Browse Source

* Close dataset on SQL change. Fixes issue #39610

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

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

@@ -368,6 +368,7 @@ type
   Private
   Private
     FCursor : TSQLCursor;
     FCursor : TSQLCursor;
     FDatabase: TSQLConnection;
     FDatabase: TSQLConnection;
+    FOnSQLChanged: TNotifyEvent;
     FParamCheck: Boolean;
     FParamCheck: Boolean;
     FParams: TParams;
     FParams: TParams;
     FMacroCheck: Boolean;
     FMacroCheck: Boolean;
@@ -428,6 +429,7 @@ type
     Property ParamCheck : Boolean Read FParamCheck Write FParamCheck default true;
     Property ParamCheck : Boolean Read FParamCheck Write FParamCheck default true;
     Property MacroCheck : Boolean Read FMacroCheck Write SetMacroCheck default false;
     Property MacroCheck : Boolean Read FMacroCheck Write SetMacroCheck default false;
     Property InfoQuery : Boolean Read FInfoQuery Write FInfoQuery;
     Property InfoQuery : Boolean Read FInfoQuery Write FInfoQuery;
+    Property OnSQLChanged : TNotifyEvent Read FOnSQLChanged Write FOnSQLChanged;
   Public
   Public
     constructor Create(AOwner : TComponent); override;
     constructor Create(AOwner : TComponent); override;
     destructor Destroy; override;
     destructor Destroy; override;
@@ -479,7 +481,7 @@ type
 
 
   { TCustomSQLQuery }
   { TCustomSQLQuery }
 
 
-  TSQLQueryOption = (sqoKeepOpenOnCommit, sqoAutoApplyUpdates, sqoAutoCommit, sqoCancelUpdatesOnRefresh, sqoRefreshUsingSelect);
+  TSQLQueryOption = (sqoKeepOpenOnCommit, sqoAutoApplyUpdates, sqoAutoCommit, sqoCancelUpdatesOnRefresh, sqoRefreshUsingSelect, sqoNoCloseOnSQLChange);
   TSQLQueryOptions = Set of TSQLQueryOption;
   TSQLQueryOptions = Set of TSQLQueryOption;
 
 
   TCustomSQLQuery = class (TCustomBufDataset)
   TCustomSQLQuery = class (TCustomBufDataset)
@@ -529,6 +531,7 @@ type
     function HasMacros: Boolean;
     function HasMacros: Boolean;
     Function HasParams : Boolean;
     Function HasParams : Boolean;
     Function NeedLastInsertID: TField;
     Function NeedLastInsertID: TField;
+    procedure OnChangeSelectSQL(Sender: TObject);
     procedure SetMacroChar(AValue: AnsiChar);
     procedure SetMacroChar(AValue: AnsiChar);
     procedure SetOptions(AValue: TSQLQueryOptions);
     procedure SetOptions(AValue: TSQLQueryOptions);
     procedure SetParamCheck(AValue: Boolean);
     procedure SetParamCheck(AValue: Boolean);
@@ -942,6 +945,8 @@ var
   NewParams: TSQLDBParams;
   NewParams: TSQLDBParams;
 
 
 begin
 begin
+  if Assigned(FOnSQLChanged) then
+    FOnSQLChanged(Self);
   UnPrepare;
   UnPrepare;
   RecreateMacros;
   RecreateMacros;
   if not ParamCheck then
   if not ParamCheck then
@@ -2724,6 +2729,7 @@ begin
   If ParamCheck and Assigned(FDataLink) then
   If ParamCheck and Assigned(FDataLink) then
     (FDataLink as TMasterParamsDataLink).RefreshParamNames;
     (FDataLink as TMasterParamsDataLink).RefreshParamNames;
   FQuery.ServerIndexDefs.Updated:=false;
   FQuery.ServerIndexDefs.Updated:=false;
+
 end;
 end;
 
 
 { TCustomSQLQuery }
 { TCustomSQLQuery }
@@ -2740,6 +2746,7 @@ constructor TCustomSQLQuery.Create(AOwner : TComponent);
 begin
 begin
   inherited Create(AOwner);
   inherited Create(AOwner);
   FStatement:=CreateSQLStatement(Self);
   FStatement:=CreateSQLStatement(Self);
+  FStatement.OnSQLChanged:=@OnChangeSelectSQL;
 
 
   FInsertSQL := TStringList.Create;
   FInsertSQL := TStringList.Create;
   FInsertSQL.OnChange := @OnChangeModifySQL;
   FInsertSQL.OnChange := @OnChangeModifySQL;
@@ -3352,6 +3359,13 @@ begin
     end
     end
 end;
 end;
 
 
+procedure TCustomSQLQuery.OnChangeSelectSQL(Sender: TObject);
+begin
+  if (sqoNoCloseOnSQLChange in Options) then
+    exit;
+  Close;
+end;
+
 procedure TCustomSQLQuery.SetMacroChar(AValue: AnsiChar);
 procedure TCustomSQLQuery.SetMacroChar(AValue: AnsiChar);
 begin
 begin
   FStatement.MacroChar:=AValue;
   FStatement.MacroChar:=AValue;

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

@@ -63,6 +63,8 @@ type
     Procedure TestPrepareCount;
     Procedure TestPrepareCount;
     Procedure TestPrepareCount2;
     Procedure TestPrepareCount2;
     Procedure TestNullTypeParam;
     Procedure TestNullTypeParam;
+    procedure TestChangeSQLCloseUnprepare;
+    procedure TestChangeSQLCloseUnprepareDisabled;
   end;
   end;
 
 
   { TTestTSQLConnection }
   { TTestTSQLConnection }
@@ -863,6 +865,38 @@ begin
     SQLDBConnector.Connection.OnLog:=Nil;
     SQLDBConnector.Connection.OnLog:=Nil;
   end;
   end;
 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 }
 { TTestTSQLConnection }