Forum > Database

prepared statements on postgresql

(1/1)

rgh:
I'm playing with a little application to talk to a postgresql server, using pqconnection & sqldb.

Using TSQLQuery, the abilty to prepare statements doesn't really seem to work in a useful way. I've posted the full code of my test program below, but the essential details are like this:

In postgresql, you can see what statements have been prepared in the current session by from pg_prepared_statements.

--- Code: SQL  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---SELECT * FROM pg_prepared_statementsSo, to test that, I create a TSQLQuery, and set its SQL.text

--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---query.SQL.Text := 'select * from employee where salary>:sal;';then prepare it. Selecting from  pg_prepared_statements at this point, shows the prepared statement on the server. Then I set the query :sal parameter to a particular value, open it & print out the records.

Now I look again at pg_prepared_statements. The previously prepared statement has gone! So, if I want to run the query again with a different salary parameter value, it will have to be prepared again.

Kind of defeats the point of preparing the query in the first place.

Is this some aspect of TSQLQuery behaviour I can have control over? Maybe by hooking up the transaction component differently? Or can I use the methods of TPQConnection directly in such as way as to have this level of control?


--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---Program prepare_test0; {$MODE DELPHI}{$H+} uses  pqconnection, sqldb, sysutils, db;   var     connection  : TPQConnection;  transaction : TSQLTransaction;  query       : TSQLQuery; function getConnection: TPQConnection;begin  result := TPQConnection.Create(nil);  result.Hostname := '10.1.100.110';  result.Params.Add('port=5432');              result.DatabaseName := 'test';  result.UserName := 'user1';  result.Password := 'user1';end; procedure listPreparedStatements(connection:TPQConnection);var  query       : TSQLQuery;begin  try    query := TSQLQuery.Create(nil);    query.Database := connection;    query.SQL.Text := 'select * from pg_prepared_statements';    query.Open;    Writeln('Prepared statements:');    while not query.Eof do      begin        Writeln(Format('  name: %s statement: %s', [query.FieldByName('name').AsString, query.FieldByName('statement').AsString]));        query.Next();      end;    query.Close;    query.Free;  except    on e:Exception do Writeln('Error in listPreparedStatements: ' + e.Message);  end;end; procedure listStaff(query:TSQLQuery; sal:integer);begin  Writeln(Format('Listing staff with salary > %d :', [sal]));  try    query.Params.ParamByName('sal').AsInteger := sal;    query.Open;    while not query.Eof do      begin        Writeln(Format('  Surname: %-10s Forename: %-8s',[Query.FieldByName('last_name').AsString, Query.FieldByName('first_name').AsString]));        query.Next;      end;    query.Close;  except    on e:Exception do Writeln('Error in listStaff: ' + e.Message);  end;end; begin  connection := getConnection;  transaction := TSQLTransaction.Create(nil);  connection.Transaction := transaction;  connection.Open;  if connection.Connected then    begin      writeln('connected ok!');      query := TSQLQuery.Create(nil);      query.Database := connection;      query.SQL.Text := 'select * from employee where salary>:sal;';      query.Prepare;      listPreparedStatements(connection);   // prepared statement exists on the server at this point      listStaff(query, 5000);         listPreparedStatements(connection);   // prepared statement has gone!      listStaff(query, 7000);              listPreparedStatements(connection);                    query.Unprepare;      query.Free;    end;  transaction.Free;  connection.Close;  connection.Free;end. 
output:


--- Code: Text  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---connected ok!Prepared statements:  name: prepst0 statement: prepare prepst0 ( unknown ) as select * from employee where salary>$1;  name: prepst1 statement: prepare prepst1  as select * from pg_prepared_statementsListing staff with salary > 5000 :  Surname: Waters     Forename: David     Surname: Thomas     Forename: Sarah     Surname: Deer       Forename: Robert    Surname: Fowler     Forename: Mary      Surname: Johnson    Forename: Lisa      Surname: Brown      Forename: Bill      Surname: Akin       Forename: Seth    Prepared statements:  name: prepst4 statement: prepare prepst4  as select * from pg_prepared_statementsListing staff with salary > 7000 :  Surname: Waters     Forename: David     Surname: Thomas     Forename: Sarah     Surname: Akin       Forename: Seth    Prepared statements:  name: prepst8 statement: prepare prepst8  as select * from pg_prepared_statements  

sky_khan:
I dont have Postgresql server to check but did you try controlling transaction manually ?


--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---transaction := TSQLTransaction.Create(nil);transaction.Action=caNone;transaction.StartTransaction; ...

--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---transaction.Commit;transaction.free; 

rgh:

--- Quote from: SkyKhan on May 21, 2017, 07:04:06 pm ---did you try controlling transaction manually ?
--- End quote ---

Yes, I tried both putting the two calls to listStaff inside a manually invoke transaction:

--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---begin  connection := getConnection;  transaction := TSQLTransaction.Create(nil);  transaction.Options := [stoExplicitStart];   connection.Transaction := transaction;  connection.Open;  if connection.Connected then    begin      writeln('connected ok!');      query := TSQLQuery.Create(nil);      query.Database := connection;      transaction.StartTransaction;      query.SQL.Text := 'select * from employee where salary>:sal;';      query.Prepare;      listPreparedStatements(connection);                         // prepared statement exists on the server at this point      listStaff(query, 5000);         listPreparedStatements(connection);                         // prepared statement has gone!      listStaff(query, 7000);                   query.Unprepare;      transaction.Commit;      query.Free;    end;  transaction.Free;  connection.Close;  connection.Free;end.which make no difference. By the time the program gets to line 17, after listStaff as been called the first time, the previously prepared statement has gone.

The other database interaction that could be within a transaction, is the query that  selects from pg_prepared_statements. Putting that in a transaction


--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---procedure listPreparedStatementsIndependentTransaction(connection:TPQConnection);var  query       : TSQLQuery;  transaction : TSQLTransaction;begin  Writeln('Prepared statements from independent transaction:');  try    query := TSQLQuery.Create(nil);    transaction := TSQLTransaction.Create(nil);    transaction.Database := connection;    transaction.Options := [stoExplicitStart];    query.SQLTransaction := transaction;     transaction.StartTransaction;    query.SQL.Text := 'select * from pg_prepared_statements';    query.Open;    while not query.Eof do      begin        Writeln(Format('  name: %s statement: %s', [query.FieldByName('name').AsString, query.FieldByName('statement').AsString]));        query.Next();      end;    query.Close;    transaction.Commit;    transaction.Free;    query.Free;  except    on e:Exception do Writeln('Error in listPreparedStatementsIndependentTransaction: ' + e.Message);  end;end;  results in the prepared statement not being visible at all, not even at the first attempt, after

--- Code: SQL  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---'select * from employee where salary>:sal;';has been initially prepared but the query hasn't been opened.

So I'm supposing that  TSQLQuery doesn't have the granularity to interact with postgresql at this level of detail.

Navigation

[0] Message Index

Go to full version