Browse Source

* Close dataset on SQL change. Fixes issue #39610
(manually merged)
(cherry picked from commit a61d60664309bc3a49446bf78a319c96aac94229)

Michaël Van Canneyt 1 year ago
parent
commit
075e978367
2 changed files with 50 additions and 1 deletions
  1. 16 1
      packages/fcl-db/src/sqldb/sqldb.pp
  2. 34 0
      packages/fcl-db/tests/testsqldb.pas

+ 16 - 1
packages/fcl-db/src/sqldb/sqldb.pp

@@ -365,6 +365,7 @@ type
   Private
     FCursor : TSQLCursor;
     FDatabase: TSQLConnection;
+    FOnSQLChanged: TNotifyEvent;
     FParamCheck: Boolean;
     FParams: TParams;
     FMacroCheck: Boolean;
@@ -423,6 +424,8 @@ type
     Property ParseSQL : Boolean Read FParseSQL Write FParseSQL;
     Property ParamCheck : Boolean Read FParamCheck Write FParamCheck default true;
     Property MacroCheck : Boolean Read FMacroCheck Write SetMacroCheck default false;
+    Property InfoQuery : Boolean Read FInfoQuery Write FInfoQuery;
+    Property OnSQLChanged : TNotifyEvent Read FOnSQLChanged Write FOnSQLChanged;
   Public
     constructor Create(AOwner : TComponent); override;
     destructor Destroy; override;
@@ -474,7 +477,7 @@ type
 
   { TCustomSQLQuery }
 
-  TSQLQueryOption = (sqoKeepOpenOnCommit, sqoAutoApplyUpdates, sqoAutoCommit, sqoCancelUpdatesOnRefresh, sqoRefreshUsingSelect);
+  TSQLQueryOption = (sqoKeepOpenOnCommit, sqoAutoApplyUpdates, sqoAutoCommit, sqoCancelUpdatesOnRefresh, sqoRefreshUsingSelect, sqoNoCloseOnSQLChange);
   TSQLQueryOptions = Set of TSQLQueryOption;
 
   TCustomSQLQuery = class (TCustomBufDataset)
@@ -524,6 +527,7 @@ type
     function HasMacros: Boolean;
     Function HasParams : Boolean;
     Function NeedLastInsertID: TField;
+    procedure OnChangeSelectSQL(Sender: TObject);
     procedure SetMacroChar(AValue: Char);
     procedure SetOptions(AValue: TSQLQueryOptions);
     procedure SetParamCheck(AValue: Boolean);
@@ -933,6 +937,8 @@ var
   NewParams: TSQLDBParams;
 
 begin
+  if Assigned(FOnSQLChanged) then
+    FOnSQLChanged(Self);
   UnPrepare;
   RecreateMacros;
   if not ParamCheck then
@@ -2785,6 +2791,7 @@ begin
   If ParamCheck and Assigned(FDataLink) then
     (FDataLink as TMasterParamsDataLink).RefreshParamNames;
   FQuery.ServerIndexDefs.Updated:=false;
+
 end;
 
 { TCustomSQLQuery }
@@ -2801,6 +2808,7 @@ constructor TCustomSQLQuery.Create(AOwner : TComponent);
 begin
   inherited Create(AOwner);
   FStatement:=CreateSQLStatement(Self);
+  FStatement.OnSQLChanged:=@OnChangeSelectSQL;
 
   FInsertSQL := TStringList.Create;
   FInsertSQL.OnChange := @OnChangeModifySQL;
@@ -3408,6 +3416,13 @@ begin
     end
 end;
 
+procedure TCustomSQLQuery.OnChangeSelectSQL(Sender: TObject);
+begin
+  if (sqoNoCloseOnSQLChange in Options) then
+    exit;
+  Close;
+end;
+
 procedure TCustomSQLQuery.SetMacroChar(AValue: Char);
 begin
   FStatement.MacroChar:=AValue;

+ 34 - 0
packages/fcl-db/tests/testsqldb.pas

@@ -61,6 +61,8 @@ type
     procedure TestMacros;
     Procedure TestPrepareCount;
     Procedure TestNullTypeParam;
+    procedure TestChangeSQLCloseUnprepare;
+    procedure TestChangeSQLCloseUnprepareDisabled;
   end;
 
   { TTestTSQLConnection }
@@ -824,6 +826,38 @@ begin
     SQLDBConnector.Connection.OnLog:=Nil;
   end;
 end;
+procedure TTestTSQLQuery.TestChangeSQLCloseUnprepare;
+begin
+  with SQLDBConnector.GetNDataset(10) as TSQLQuery do
+    begin
+    Open;
+    AssertTrue('Prepared after open', Prepared);
+    SQL.Text := 'SELECT * FROM FPDEV WHERE ID<0';
+    // statement must be unprepared when SQL is changed
+    AssertFalse('Prepared after SQL changed', Prepared);
+    // dataset remained active in FPC <= 3.2.2
+    AssertFalse('Active after SQL changed', Active);
+    SQL.Text := 'UPDATE FPDEV SET NAME=''Test'' WHERE ID>100';
+    ExecSQL;
+    end;
+end;
+procedure TTestTSQLQuery.TestChangeSQLCloseUnprepareDisabled;
+begin
+  with SQLDBConnector.GetNDataset(10) as TSQLQuery do
+    begin
+    OPtions:=OPtions+[sqoNoCloseOnSQLChange];
+    Open;
+    AssertTrue('Prepared after open', Prepared);
+    SQL.Text := 'SELECT * FROM FPDEV WHERE ID<0';
+    // statement must be unprepared when SQL is changed
+    AssertFalse('Prepared after SQL changed', Prepared);
+    // dataset remained active in FPC <= 3.2.2
+    AssertTrue('Active after SQL changed', Active);
+    Close;
+    SQL.Text := 'UPDATE FPDEV SET NAME=''Test'' WHERE ID>100';
+    ExecSQL;
+    end;
+end;
 
 
 { TTestTSQLConnection }