From b2957b92f48b0c707c972e2d6ec3a4d7ff4a39f0 Mon Sep 17 00:00:00 2001 From: michael Date: Fri, 20 Dec 2019 16:28:42 +0000 Subject: [PATCH] * Fix bug #0036461, parameters not correctly refreshed in Mysql git-svn-id: trunk@43702 - --- packages/fcl-db/src/sqldb/mysql/mysqlconn.inc | 23 ++++--- packages/fcl-db/tests/testsqldb.pas | 64 +++++++++++++++---- 2 files changed, 67 insertions(+), 20 deletions(-) diff --git a/packages/fcl-db/src/sqldb/mysql/mysqlconn.inc b/packages/fcl-db/src/sqldb/mysql/mysqlconn.inc index 9fcbf4da66..2447eb831d 100644 --- a/packages/fcl-db/src/sqldb/mysql/mysqlconn.inc +++ b/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) diff --git a/packages/fcl-db/tests/testsqldb.pas b/packages/fcl-db/tests/testsqldb.pas index 753427af74..ec26512940 100644 --- a/packages/fcl-db/tests/testsqldb.pas +++ b/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; - Prepare; + AssertFalse('Not 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; + AssertFalse('Still not 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); + 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',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',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;