Browse Source

* Fix bug #0036461, parameters not correctly refreshed in Mysql

git-svn-id: trunk@43702 -
michael 5 years ago
parent
commit
b2957b92f4
2 changed files with 66 additions and 19 deletions
  1. 14 9
      packages/fcl-db/src/sqldb/mysql/mysqlconn.inc
  2. 52 10
      packages/fcl-db/tests/testsqldb.pas

+ 14 - 9
packages/fcl-db/src/sqldb/mysql/mysqlconn.inc

@@ -92,7 +92,10 @@ Type
   TCursorName = Class(TSQLCursor)
   protected
     FRes: PMYSQL_RES;                   { Record pointer }
-    FStatement : String;
+    // Statement with param placeholders $1 $2 etc.
+    FPreparedStatement : String;
+    // Statement with param placeholders replaced with actual values.
+    FActualStatement : String;
     Row : MYSQL_ROW;
     Lengths : pculong;                  { Lengths of the columns of the current row }
     RowsAffected : QWord;
@@ -589,9 +592,9 @@ begin
 //    DatabaseError('Parameters (not) yet supported for the MySQL SqlDB connection.',self);
   With Cursor as TCursorName do
     begin
-    FStatement:=Buf;
+    FPreparedStatement:=Buf;
     if assigned(AParams) and (AParams.count > 0) then
-      FStatement := AParams.ParseSQL(FStatement,false,sqEscapeSlash in ConnOptions, sqEscapeRepeat in ConnOptions,psSimulated,paramBinding,ParamReplaceString);
+      FPreparedStatement := AParams.ParseSQL(FPreparedStatement,false,sqEscapeSlash in ConnOptions, sqEscapeRepeat in ConnOptions,psSimulated,paramBinding,ParamReplaceString);
     FPrepared:=True;
     end
 end;
@@ -621,6 +624,7 @@ begin
     mysql_free_result(C.FRes);
     C.FRes:=Nil;
     end;
+  C.FInitFieldDef:=True;
   SetLength(c.MapDSRowToMSQLRow,0);
   inherited;
 end;
@@ -648,18 +652,19 @@ begin
         ParamNames[AParams.count-i-1] := C.ParamReplaceString+inttostr(AParams[i].Index+1);
         ParamValues[AParams.count-i-1] := GetAsSQLText(AParams[i]);
         end;
-      // paramreplacestring kan een probleem geven bij postgres als hij niet meer gewoon $ is?
-      C.FStatement := stringsreplace(C.FStatement,ParamNames,ParamValues,[rfReplaceAll]);
-      end;
+      C.FActualStatement := stringsreplace(C.FPreparedStatement,ParamNames,ParamValues,[rfReplaceAll]);
+      end
+    else
+      C.FActualStatement:=C.FPreparedStatement;
 
     if LogEvent(detParamValue) then
       LogParams(AParams);
     if LogEvent(detExecute) then
-      Log(detExecute, C.FStatement);
+      Log(detExecute, C.FPreparedStatement);
     if LogEvent(detActualSQL) then
-      Log(detActualSQL,C.FStatement);
+      Log(detActualSQL,C.FActualStatement);
 
-    if mysql_query(FMySQL,Pchar(C.FStatement))<>0 then
+    if mysql_query(FMySQL,Pchar(C.FActualStatement))<>0 then
       begin
       if not ForcedClose then
         MySQLError(FMYSQL,SErrExecuting,Self)

+ 52 - 10
packages/fcl-db/tests/testsqldb.pas

@@ -31,6 +31,7 @@ type
   private
     FMyQ: TSQLQuery;
     FPrepareCount:Integer;
+    procedure CreateAndFillIDField;
     procedure DoAfterPost(DataSet: TDataSet);
     Procedure DoApplyUpdates;
     procedure DoCount(Sender: TSQLConnection; EventType: TDBEventType; const Msg: String);
@@ -60,6 +61,7 @@ type
     procedure TestReturningUpdate;
     procedure TestMacros;
     Procedure TestPrepareCount;
+    Procedure TestPrepareCount2;
   end;
 
   { TTestTSQLConnection }
@@ -761,40 +763,80 @@ begin
     end;
 end;
 
-procedure TTestTSQLQuery.TestPrepareCount;
+procedure TTestTSQLQuery.CreateAndFillIDField;
+
+Var
+  I : Integer;
 
 begin
   with SQLDBConnector do
     begin
+    TryDropIfExist('FPDEV2');
     ExecuteDirect('create table FPDEV2 (id integer not null, constraint PK_FPDEV2 primary key(id))');
     CommitDDL;
-    ExecuteDirect('insert into FPDEV2 (id) values (1)');
-    ExecuteDirect('insert into FPDEV2 (id) values (2)');
+    for I:=1 to 10 do
+      ExecuteDirect('insert into FPDEV2 (id) values ('+IntToStr(I)+')');
     Connection.OnLog:=@DoCount;
     Connection.LogEvents:=[detPrepare];
     end;
+end;
+
+procedure TTestTSQLQuery.TestPrepareCount;
+
+begin
+  CreateAndFillIDField;
   try
     With SQLDBConnector.Query do
       begin
-      Unidirectional:=True; // Disable server index defs etc
-      UsePrimaryKeyAsKey:=False; // Idem
-      SQL.Text:='Select ID from FPDEV2 where (ID=:ID)';
+      UsePrimaryKeyAsKey:=False; // Disable server index defs etc
+      SQL.Text:='Select ID from FPDEV2 where (ID>=:ID) order by ID';
+      ParamByname('ID').AsInteger:=1;
+      AssertFalse('Not Prepared',SQLDBConnector.Query.Prepared);
+      Open;
+      AssertEquals('Correct record count param 1',10,RecordCount);
+      AssertEquals('Correct SQL executed, correct parameter: ',1,Fields[0].AsInteger);
+      Close;
+      AssertFalse('Still not prepared',SQLDBConnector.Query.Prepared);
+      ParamByname('ID').AsInteger:=2;
+      Open;
+      AssertEquals('Correct record count param 2',9,RecordCount);
+      AssertEquals('Correct SQL executed, macro value changed: ',2,Fields[0].AsInteger);
+      Close;
+      AssertFalse('Still not prepared',SQLDBConnector.Query.Prepared);
+      end;
+    AssertEquals('Prepare called only once ',2,FPrepareCount);
+  finally
+    SQLDBConnector.Connection.OnLog:=Nil;
+  end;
+
+end;
+
+procedure TTestTSQLQuery.TestPrepareCount2;
+
+begin
+  CreateAndFillIDField;
+  try
+    With SQLDBConnector.Query do
+      begin
+      UsePrimaryKeyAsKey:=False; // Disable server index defs etc
+      SQL.Text:='Select ID from FPDEV2 where (ID>=:ID) order by ID';
       ParamByname('ID').AsInteger:=1;
       Prepare;
+      AssertTrue('Prepared',SQLDBConnector.Query.Prepared);
       Open;
-      AssertEquals('Correct record count param 1',1,RecordCount);
-      AssertEquals('Correct SQL executed, correct paramete: ',1,Fields[0].AsInteger);
+      AssertEquals('Correct record count param 1',10,RecordCount);
+      AssertEquals('Correct SQL executed, correct parameter: ',1,Fields[0].AsInteger);
       Close;
+      AssertTrue('Still prepared',SQLDBConnector.Query.Prepared);
       ParamByname('ID').AsInteger:=2;
       Open;
-      AssertEquals('Correct record count param 2',1,RecordCount);
+      AssertEquals('Correct record count param 2',9,RecordCount);
       AssertEquals('Correct SQL executed, macro value changed: ',2,Fields[0].AsInteger);
       end;
     AssertEquals('Prepare called only once ',1,FPrepareCount);
   finally
     SQLDBConnector.Connection.OnLog:=Nil;
   end;
-
 end;