Ver Fonte

* QueryOptions for disconnected mode and autoapplyupdates

git-svn-id: trunk@29088 -
michael há 10 anos atrás
pai
commit
a53fca1b67

+ 1 - 1
packages/fcl-db/src/base/bufdataset.pas

@@ -504,7 +504,6 @@ type
     procedure SetIndexFieldNames(const AValue: String);
     procedure SetIndexName(AValue: String);
     procedure SetMaxIndexesCount(const AValue: Integer);
-    procedure SetPacketRecords(aValue : integer);
     procedure SetBufUniDirectional(const AValue: boolean);
     // indexes handling
     procedure InitDefaultIndexes;
@@ -513,6 +512,7 @@ type
     procedure RemoveRecordFromIndexes(const ABookmark : TBufBookmark);
   protected
     // abstract & virtual methods of TDataset
+    procedure SetPacketRecords(aValue : integer); virtual;
     procedure UpdateIndexDefs; override;
     procedure SetRecNo(Value: Longint); override;
     function  GetRecNo: Longint; override;

+ 14 - 2
packages/fcl-db/src/base/database.inc

@@ -379,15 +379,27 @@ begin
     DatabaseError(SErrNoDatabaseAvailable,Self)
 end;
 
+Function TDBTransaction.AllowClose(DS : TDBDataset) : Boolean;
+
+begin
+  Result:=Assigned(DS);
+end;
+
 procedure TDBTransaction.CloseDataSets;
 
-Var I : longint;
+Var
+  I : longint;
+  DS : TDBDataset;
 
 begin
   If Assigned(FDatasets) then
     begin
     For I:=FDatasets.Count-1 downto 0 do
-      TDBDataset(FDatasets[i]).Close;
+      begin
+      DS:=TDBDataset(FDatasets[i]);
+      If AllowClose(DS) then
+        DS.Close;
+      end;
     end;
 end;
 

+ 2 - 1
packages/fcl-db/src/base/db.pas

@@ -1607,7 +1607,7 @@ type
     function CreateBlobStream(Field: TField; Mode: TBlobStreamMode): TStream; virtual;
     procedure CursorPosChanged;
     procedure DataConvert(aField: TField; aSource, aDest: Pointer; aToNative: Boolean); virtual;
-    procedure Delete;
+    procedure Delete; virtual;
     procedure DisableControls;
     procedure Edit;
     procedure EnableControls;
@@ -1878,6 +1878,7 @@ type
     procedure RemoveDataSets;
     procedure SetActive(Value : boolean);
   Protected
+    Function AllowClose(DS: TDBDataset): Boolean; virtual;
     Procedure SetDatabase (Value : TDatabase); virtual;
     procedure CloseTrans;
     procedure openTrans;

+ 1 - 0
packages/fcl-db/src/base/dbconst.pas

@@ -112,6 +112,7 @@ Resourcestring
   SErrNoFieldsDefined      = 'Can not create a dataset when there are no fielddefinitions or fields defined';
   SErrApplyUpdBeforeRefresh= 'Must apply updates before refreshing data';
   SErrNoDataset            = 'Missing (compatible) underlying dataset, can not open';
+  SErrDisconnectedPacketRecords = 'For disconnected TSQLQuery instances, packetrecords must be -1';
 
 Implementation
 

+ 93 - 32
packages/fcl-db/src/sqldb/sqldb.pp

@@ -24,8 +24,9 @@ uses SysUtils, Classes, DB, bufdataset, sqlscript;
 
 type
   TSchemaType = (stNoSchema, stTables, stSysTables, stProcedures, stColumns, stProcedureParams, stIndexes, stPackages, stSchemata);
-  TConnOption = (sqSupportParams, sqSupportEmptyDatabaseName, sqEscapeSlash, sqEscapeRepeat);
+  TConnOption = (sqSupportParams, sqSupportEmptyDatabaseName, sqEscapeSlash, sqEscapeRepeat, sqImplicitTransaction);
   TConnOptions= set of TConnOption;
+
   TConnInfoType=(citAll=-1, citServerType, citServerVersion, citServerVersionString, citClientName, citClientVersion);
   TStatementType = (stUnknown, stSelect, stInsert, stUpdate, stDelete,
     stDDL, stGetSegment, stPutSegment, stExecProcedure,
@@ -56,6 +57,9 @@ type
   TDBEventTypes = set of TDBEventType;
   TDBLogNotifyEvent = Procedure (Sender : TSQLConnection; EventType : TDBEventType; Const Msg : String) of object;
 
+  TSQLQueryOption = (sqoDisconnected, sqoAutoApplyUpdates);
+  TSQLQueryOptions = Set of TSQLQueryOption;
+
   TSQLHandle = Class(TObject)
   end;
 
@@ -153,11 +157,13 @@ type
     FStatements          : TFPList;
     FLogEvents: TDBEventTypes;
     FOnLog: TDBLogNotifyEvent;
+    FInternalTransaction : TSQLTransaction;
     function GetPort: cardinal;
     procedure SetPort(const AValue: cardinal);
   protected
     FConnOptions         : TConnOptions;
     FSQLFormatSettings   : TFormatSettings;
+
     // Updating of DB records is moved out of TSQLQuery.
     // It is done here, so descendents can override it and implement DB-specific.
     // One day, this may be factored out to a TSQLResolver class.
@@ -170,7 +176,6 @@ type
     procedure ApplyFieldUpdate(C : TSQLCursor; P: TSQLDBParam; F: TField; UseOldValue: Boolean); virtual;
     // This is the call that updates a record, it used to be in TSQLQuery.
     procedure ApplyRecUpdate(Query : TCustomSQLQuery; UpdateKind : TUpdateKind); virtual;
-    //
     procedure GetDBInfo(const ASchemaType : TSchemaType; const ASchemaObjectName, AReturnField : string; AList: TStrings);
     procedure SetTransaction(Value : TSQLTransaction); virtual;
     procedure DoInternalConnect; override;
@@ -182,7 +187,6 @@ type
     Procedure Log(EventType : TDBEventType; Const Msg : String); virtual;
     Procedure RegisterStatement(S : TCustomSQLStatement);
     Procedure UnRegisterStatement(S : TCustomSQLStatement);
-
     Function AllocateCursorHandle : TSQLCursor; virtual; abstract;
     Procedure DeAllocateCursorHandle(var cursor : TSQLCursor); virtual; abstract;
     function StrToStatementType(s : string) : TStatementType; virtual;
@@ -258,6 +262,7 @@ type
     procedure SetParams(const AValue: TStringList);
     procedure SetSQLConnection(AValue: TSQLConnection);
   protected
+    Function AllowClose(DS: TDBDataset): Boolean; override;
     function GetHandle : Pointer; virtual;
     Procedure SetDatabase (Value : TDatabase); override;
     Function LogEvent(EventType : TDBEventType) : Boolean;
@@ -279,6 +284,8 @@ type
     property Params : TStringList read FParams write SetParams;
   end;
 
+
+
   { TCustomSQLStatement }
 
   TCustomSQLStatement = Class(TComponent)
@@ -352,6 +359,7 @@ type
 
   TCustomSQLQuery = class (TCustomBufDataset)
   private
+    FQueryOptions: TSQLQueryOptions;
     FSchemaType          : TSchemaType;
     FUpdateable          : boolean;
     FTableName           : string;
@@ -387,6 +395,7 @@ type
     function GetSQLTransaction: TSQLTransaction;
     function GetStatementType : TStatementType;
     procedure SetParamCheck(AValue: Boolean);
+    procedure SetQueryOptions(AValue: TSQLQueryOptions);
     procedure SetSQLConnection(AValue: TSQLConnection);
     procedure SetSQLTransaction(AValue: TSQLTransaction);
     procedure SetUpdateSQL(const AValue: TStringlist);
@@ -402,6 +411,7 @@ type
     procedure ApplyFilter;
     Function AddFilter(SQLstr : string) : string;
   protected
+    procedure SetPacketRecords(aValue : integer); override;
     Function Cursor : TSQLCursor;
     Function LogEvent(EventType : TDBEventType) : Boolean;
     Procedure Log(EventType : TDBEventType; Const Msg : String); virtual;
@@ -439,6 +449,8 @@ type
     procedure Prepare; virtual;
     procedure UnPrepare; virtual;
     procedure ExecSQL; virtual;
+    Procedure Post; override;
+    Procedure Delete; override;
     procedure SetSchemaInfo( ASchemaType : TSchemaType; ASchemaObjectName, ASchemaPattern : string); virtual;
     function RowsAffected: TRowsCount; virtual;
     function ParamByName(Const AParamName : String) : TParam;
@@ -475,6 +487,7 @@ type
     property AutoCalcFields;
     property Database;
   // protected
+    Property QueryOptions : TSQLQueryOptions Read FQueryOptions Write SetQueryOptions;
     property SchemaType : TSchemaType read FSchemaType default stNoSchema;
     property Transaction;
     property SQL : TStringlist read GetSQL write SetSQL;
@@ -530,6 +543,7 @@ type
     Property OnPostError;
 
     //    property SchemaInfo default stNoSchema;
+    Property QueryOptions;
     property Database;
     property Transaction;
     property ReadOnly;
@@ -729,6 +743,9 @@ begin
   SQLState  := ASQLState;
 end;
 
+Type
+  TInternalTransaction = Class(TSQLTransaction);
+
 { TCustomSQLStatement }
 
 procedure TCustomSQLStatement.OnChangeSQL(Sender: TObject);
@@ -784,7 +801,7 @@ begin
   FDataLink.DataSource:=AValue;
 end;
 
-procedure TCustomSQLStatement.CopyParamsFromMaster(CopyBound : Boolean);
+Procedure TCustomSQLStatement.CopyParamsFromMaster(CopyBound: Boolean);
 begin
   if Assigned(DataSource) and Assigned(DataSource.Dataset) then
     FParams.CopyParamValuesFromDataset(DataSource.Dataset,CopyBound);
@@ -817,7 +834,7 @@ begin
     end;
 end;
 
-procedure TCustomSQLStatement.DoExecute;
+Procedure TCustomSQLStatement.DoExecute;
 begin
   If (FParams.Count>0) and Assigned(DataSource) then
     CopyParamsFromMaster(False);
@@ -826,27 +843,27 @@ begin
   Database.Execute(FCursor,Transaction, FParams);
 end;
 
-function TCustomSQLStatement.GetPrepared: Boolean;
+Function TCustomSQLStatement.GetPrepared: Boolean;
 begin
   Result := Assigned(FCursor) and FCursor.FPrepared;
 end;
 
-function TCustomSQLStatement.CreateDataLink: TDataLink;
+Function TCustomSQLStatement.CreateDataLink: TDataLink;
 begin
   Result:=TDataLink.Create;
 end;
 
-function TCustomSQLStatement.CreateParams: TSQLDBParams;
+Function TCustomSQLStatement.CreateParams: TSQLDBParams;
 begin
   Result:=TSQLDBParams.Create(Nil);
 end;
 
-function TCustomSQLStatement.LogEvent(EventType: TDBEventType): Boolean;
+Function TCustomSQLStatement.LogEvent(EventType: TDBEventType): Boolean;
 begin
   Result:=Assigned(Database) and Database.LogEvent(EventType);
 end;
 
-procedure TCustomSQLStatement.Log(EventType: TDBEventType; const Msg: String);
+Procedure TCustomSQLStatement.Log(EventType: TDBEventType; Const Msg: String);
 Var
   M : String;
 
@@ -897,28 +914,29 @@ begin
   inherited Destroy;
 end;
 
-function TCustomSQLStatement.GetSchemaType: TSchemaType;
+Function TCustomSQLStatement.GetSchemaType: TSchemaType;
 
 begin
   Result:=stNoSchema
 end;
 
-function TCustomSQLStatement.GetSchemaObjectName: String;
+Function TCustomSQLStatement.GetSchemaObjectName: String;
 begin
   Result:='';
 end;
 
-function TCustomSQLStatement.GetSchemaPattern: String;
+Function TCustomSQLStatement.GetSchemaPattern: String;
 begin
   Result:='';
 end;
 
-function TCustomSQLStatement.IsSelectable: Boolean;
+Function TCustomSQLStatement.IsSelectable: Boolean;
 begin
   Result:=False;
 end;
 
 
+
 procedure TCustomSQLStatement.GetStatementInfo(var ASQL: String; out Info: TSQLStatementInfo);
 
 begin
@@ -961,7 +979,7 @@ begin
   Database.PrepareStatement(FCursor,Transaction,FServerSQL,FParams);
 end;
 
-procedure TCustomSQLStatement.Prepare;
+Procedure TCustomSQLStatement.Prepare;
 
 begin
   if Prepared then exit;
@@ -981,7 +999,7 @@ begin
   end;
 end;
 
-procedure TCustomSQLStatement.Execute;
+Procedure TCustomSQLStatement.Execute;
 begin
   Prepare;
   DoExecute;
@@ -1008,7 +1026,7 @@ begin
     Result:=Nil;
 end;
 
-procedure TCustomSQLStatement.Unprepare;
+Procedure TCustomSQLStatement.Unprepare;
 begin
   // Some SQLConnections does not support statement [un]preparation, but they have allocated local cursor(s)
   //  so let them do cleanup f.e. cancel pending queries and/or free resultset
@@ -1017,7 +1035,7 @@ begin
     DoUnprepare;
 end;
 
-function TCustomSQLStatement.ParamByName(const AParamName: String): TParam;
+function TCustomSQLStatement.ParamByName(Const AParamName: String): TParam;
 begin
   Result:=FParams.ParamByName(AParamName);
 end;
@@ -1072,6 +1090,7 @@ begin
     end;
 end;
 
+
 procedure TSQLConnection.UpdateIndexDefs(IndexDefs : TIndexDefs; TableName : string);
 begin
   // Empty abstract
@@ -1152,6 +1171,7 @@ begin
   result := StrToIntDef(Params.Values['Port'],0);
 end;
 
+
 procedure TSQLConnection.SetPort(const AValue: cardinal);
 begin
   if AValue<>0 then
@@ -1440,12 +1460,12 @@ begin
   Result := nil;
 end;
 
-function TSQLConnection.LogEvent(EventType: TDBEventType): Boolean;
+Function TSQLConnection.LogEvent(EventType: TDBEventType): Boolean;
 begin
   Result:=(Assigned(FOnLog) or Assigned(GlobalDBLogHook)) and (EventType in LogEvents);
 end;
 
-procedure TSQLConnection.Log(EventType: TDBEventType; const Msg: String);
+Procedure TSQLConnection.Log(EventType: TDBEventType; Const Msg: String);
 
 Var
   M : String;
@@ -1466,18 +1486,19 @@ begin
     end;
 end;
 
-procedure TSQLConnection.RegisterStatement(S: TCustomSQLStatement);
+Procedure TSQLConnection.RegisterStatement(S: TCustomSQLStatement);
 begin
   if FStatements.IndexOf(S)=-1 then
     FStatements.Add(S);
 end;
 
-procedure TSQLConnection.UnRegisterStatement(S: TCustomSQLStatement);
+Procedure TSQLConnection.UnRegisterStatement(S: TCustomSQLStatement);
 begin
   if Assigned(FStatements) then // Can be nil, when we are destroying and datasets are uncoupled.
     FStatements.Remove(S);
 end;
 
+
 function TSQLConnection.InitialiseUpdateStatement(Query : TCustomSQLQuery; var qry : TCustomSQLStatement): TCustomSQLStatement;
 
 begin
@@ -1692,6 +1713,14 @@ begin
   Result := SQLConnection.GetTransactionHandle(FTrans);
 end;
 
+Function TSQLTransaction.AllowClose(DS: TDBDataset): Boolean;
+begin
+  if (DS is TSQLQuery) then
+    Result:=not (sqoDisconnected in TSQLQuery(DS).QueryOptions)
+  else
+    Result:=Inherited AllowClose(DS);
+end;
+
 procedure TSQLTransaction.Commit;
 begin
   if Active then
@@ -1943,7 +1972,7 @@ begin
   inherited Destroy;
 end;
 
-function TCustomSQLQuery.ParamByName(const AParamName: String): TParam;
+function TCustomSQLQuery.ParamByName(Const AParamName: String): TParam;
 
 begin
   Result:=Params.ParamByName(AParamName);
@@ -1955,7 +1984,7 @@ begin
   CheckInactive;
 end;
 
-procedure TCustomSQLQuery.SetTransaction(Value: TDBTransaction);
+Procedure TCustomSQLQuery.SetTransaction(Value: TDBTransaction);
 
 begin
   UnPrepare;
@@ -1985,7 +2014,7 @@ begin
     end;
 end;
 
-function TCustomSQLQuery.IsPrepared: Boolean;
+Function TCustomSQLQuery.IsPrepared: Boolean;
 
 begin
   if Assigned(Fstatement) then
@@ -1994,7 +2023,7 @@ begin
     Result := False;
 end;
 
-function TCustomSQLQuery.AddFilter(SQLstr: string): string;
+Function TCustomSQLQuery.AddFilter(SQLstr: string): string;
 
 begin
   if (FWhereStartPos > 0) and (FWhereStopPos > 0) then
@@ -2025,7 +2054,7 @@ begin
   First;
 end;
 
-procedure TCustomSQLQuery.SetActive(Value: Boolean);
+Procedure TCustomSQLQuery.SetActive(Value: Boolean);
 
 begin
   inherited SetActive(Value);
@@ -2056,6 +2085,7 @@ begin
     end;
 end;
 
+
 procedure TCustomSQLQuery.Prepare;
 
 begin
@@ -2114,7 +2144,15 @@ begin
   Result:=Transaction as TSQLTransaction;
 end;
 
-function TCustomSQLQuery.Cursor: TSQLCursor;
+procedure TCustomSQLQuery.SetPacketRecords(aValue: integer);
+begin
+  if (AValue=PacketRecords) then exit;
+  if (AValue<>-1) and (sqoDisconnected in QueryOptions) then
+    DatabaseError(SErrDisconnectedPacketRecords);
+  Inherited SetPacketRecords(aValue);
+end;
+
+Function TCustomSQLQuery.Cursor: TSQLCursor;
 begin
   Result:=FStatement.Cursor;
 end;
@@ -2276,6 +2314,20 @@ begin
   end;
 end;
 
+Procedure TCustomSQLQuery.Post;
+begin
+  inherited Post;
+  If (sqoAutoApplyUpdates in QueryOptions) then
+    ApplyUpdates;
+end;
+
+Procedure TCustomSQLQuery.Delete;
+begin
+  inherited Delete;
+  If (sqoAutoApplyUpdates in QueryOptions) then
+    ApplyUpdates;
+end;
+
 procedure TCustomSQLQuery.SetReadOnly(AValue : Boolean);
 
 begin
@@ -2364,12 +2416,12 @@ begin
     UnPrepareStatement(Cursor);
 end;
 
-function TCustomSQLQuery.LogEvent(EventType: TDBEventType): Boolean;
+Function TCustomSQLQuery.LogEvent(EventType: TDBEventType): Boolean;
 begin
   Result:=Assigned(Database) and SQLConnection.LogEvent(EventType);
 end;
 
-procedure TCustomSQLQuery.Log(EventType: TDBEventType; const Msg: String);
+Procedure TCustomSQLQuery.Log(EventType: TDBEventType; Const Msg: String);
 
 Var
   M : String;
@@ -2403,6 +2455,15 @@ begin
   FStatement.ParamCheck:=AValue;
 end;
 
+procedure TCustomSQLQuery.SetQueryOptions(AValue: TSQLQueryOptions);
+begin
+  if FQueryOptions=AValue then Exit;
+  CheckInactive;
+  FQueryOptions:=AValue;
+  if sqoDisconnected in FQueryOptions then
+    PacketRecords:=-1;
+end;
+
 procedure TCustomSQLQuery.SetSQLConnection(AValue: TSQLConnection);
 begin
   Database:=AValue;
@@ -2428,7 +2489,7 @@ begin
   FStatement.Params.Assign(AValue);
 end;
 
-procedure TCustomSQLQuery.SetDataSource(AValue: TDataSource);
+Procedure TCustomSQLQuery.SetDataSource(AValue: TDataSource);
 
 Var
   DS : TDataSource;
@@ -2445,7 +2506,7 @@ begin
     end;
 end;
 
-function TCustomSQLQuery.GetDataSource: TDataSource;
+Function TCustomSQLQuery.GetDataSource: TDataSource;
 
 begin
   If Assigned(FStatement) then

+ 184 - 2
packages/fcl-db/tests/testsqldb.pas

@@ -9,7 +9,7 @@ unit TestSQLDB;
 interface
 
 uses
-  Classes, SysUtils, fpcunit, testregistry,
+  Classes, sqldb, SysUtils, fpcunit, testregistry,
   db;
 
 type
@@ -25,10 +25,20 @@ type
   { TTestTSQLQuery }
 
   TTestTSQLQuery = class(TSQLDBTestCase)
+    procedure DoAfterPost(DataSet: TDataSet);
   private
+    FMyQ: TSQLQuery;
+    Procedure Allow;
+    Procedure SetQueryOPtions;
+    Procedure TrySetPacketRecords;
   published
     procedure TestMasterDetail;
     procedure TestUpdateServerIndexDefs;
+    Procedure TestDisconnected;
+    Procedure TestDisconnectedPacketRecords;
+    Procedure TestCheckSettingsOnlyWhenInactive;
+    Procedure TestAutoApplyUpdatesPost;
+    Procedure TestAutoApplyUpdatesDelete;
   end;
 
   { TTestTSQLConnection }
@@ -50,11 +60,21 @@ type
 
 implementation
 
-uses sqldbtoolsunit, toolsunit, sqldb;
+uses sqldbtoolsunit, toolsunit;
 
 
 { TTestTSQLQuery }
 
+procedure TTestTSQLQuery.DoAfterPost(DataSet: TDataSet);
+begin
+  AssertTrue('Have modifications in after post',FMyq.UpdateStatus=usModified)
+end;
+
+Procedure TTestTSQLQuery.Allow;
+begin
+
+end;
+
 procedure TTestTSQLQuery.TestMasterDetail;
 var MasterQuery, DetailQuery: TSQLQuery;
     MasterSource: TDataSource;
@@ -141,6 +161,168 @@ begin
   end;
 end;
 
+Procedure TTestTSQLQuery.TestDisconnected;
+var Q: TSQLQuery;
+    I, J : Integer;
+begin
+  // Test that for a disconnected SQL query, calling commit does not close the dataset.
+  // Test also that an edit still works.
+  with TSQLDBConnector(DBConnector) do
+    begin
+    try
+      ExecuteDirect('DROP table testdiscon');
+    except
+      // Ignore
+    end;
+    ExecuteDirect('create table testdiscon (id integer not null, a varchar(10), constraint pk_testdiscon primary key(id))');
+    Transaction.COmmit;
+    for I:=1 to 20 do
+      ExecuteDirect(Format('INSERT INTO testdiscon values (%d,''%.6d'')',[i,i]));
+    Transaction.COmmit;
+    Q := TSQLDBConnector(DBConnector).Query;
+    Q.SQL.Text:='select * from testdiscon';
+    Q.QueryOptions:=[sqoDisconnected];
+    AssertEquals('PacketRecords forced to -1',-1,Q.PacketRecords);
+    Q.Open;
+    AssertEquals('Got all records',20,Q.RecordCount);
+    Q.SQLTransaction.Commit;
+    AssertTrue('Still open after transaction',Q.Active);
+    // Now check editing
+    Q.Locate('id',20,[]);
+    Q.Edit;
+    Q.FieldByName('a').AsString:='abc';
+    Q.Post;
+    AssertTrue('Have updates pending',Q.UpdateStatus=usModified);
+    Q.ApplyUpdates;
+    AssertTrue('Have no more updates pending',Q.UpdateStatus=usUnmodified);
+    Q.Close;
+    Q.SQL.Text:='select * from testdiscon where (id=20) and (a=''abc'')';
+    Q.Open;
+    AssertTrue('Have modified data record in database',not (Q.EOF AND Q.BOF));
+    end;
+
+end;
+
+Procedure TTestTSQLQuery.TrySetPacketRecords;
+
+begin
+  FMyQ.PacketRecords:=10;
+end;
+
+Procedure TTestTSQLQuery.TestDisconnectedPacketRecords;
+begin
+  with TSQLDBConnector(DBConnector) do
+    begin
+    FMyQ := TSQLDBConnector(DBConnector).Query;
+    FMyQ.QueryOptions:=[sqoDisconnected];
+    AssertException('Cannot set packetrecords when sqoDisconnected is active',EDatabaseError,@TrySetPacketRecords);
+    end;
+end;
+
+Procedure TTestTSQLQuery.SetQueryOPtions;
+
+begin
+  FMyQ.QueryOptions:=[sqoDisconnected];
+end;
+
+Procedure TTestTSQLQuery.TestCheckSettingsOnlyWhenInactive;
+begin
+  // Check that we can only set QueryOptions when the query is inactive.
+  with TSQLDBConnector(DBConnector) do
+    begin
+    try
+      ExecuteDirect('DROP table testdiscon');
+    except
+      // Ignore
+    end;
+    ExecuteDirect('create table testdiscon (id integer not null, a varchar(10), constraint pk_testdiscon primary key(id))');
+    Transaction.COmmit;
+     ExecuteDirect(Format('INSERT INTO testdiscon values (%d,''%.6d'')',[1,1]));
+    Transaction.COmmit;
+    FMyQ := TSQLDBConnector(DBConnector).Query;
+    FMyQ.SQL.Text:='select * from testdiscon';
+    FMyQ := TSQLDBConnector(DBConnector).Query;
+    FMyQ.OPen;
+    AssertException('Cannot set packetrecords when sqoDisconnected is active',EDatabaseError,@SetQueryOptions);
+    end;
+end;
+
+Procedure TTestTSQLQuery.TestAutoApplyUpdatesPost;
+var Q: TSQLQuery;
+    I, J : Integer;
+begin
+  // Test that if sqoAutoApplyUpdates is in QueryOptions, then POST automatically does an ApplyUpdates
+  // Test also that POST afterpost event is backwards compatible.
+  with TSQLDBConnector(DBConnector) do
+    begin
+    try
+      ExecuteDirect('DROP table testdiscon');
+    except
+      // Ignore
+    end;
+    ExecuteDirect('create table testdiscon (id integer not null, a varchar(10), constraint pk_testdiscon primary key(id))');
+    Transaction.COmmit;
+    for I:=1 to 2 do
+      ExecuteDirect(Format('INSERT INTO testdiscon values (%d,''%.6d'')',[i,i]));
+    Transaction.COmmit;
+    Q := TSQLDBConnector(DBConnector).Query;
+    FMyQ:=Q; // so th event handler can reach it.
+    Q.SQL.Text:='select * from testdiscon';
+    Q.QueryOptions:=[  sqoAutoApplyUpdates];
+    // We must test that in AfterPost, the modification is still there, for backwards compatibilty
+    Q.AfterPost:=@DoAfterPost;
+    Q.Open;
+    AssertEquals('Got all records',2,Q.RecordCount);
+    // Now check editing
+    Q.Locate('id',2,[]);
+    Q.Edit;
+    Q.FieldByName('a').AsString:='abc';
+    Q.Post;
+    AssertTrue('Have no more updates pending',Q.UpdateStatus=usUnmodified);
+    Q.Close;
+    Q.SQL.Text:='select * from testdiscon where (id=2) and (a=''abc'')';
+    Q.Open;
+    AssertTrue('Have modified data record in database',not (Q.EOF AND Q.BOF));
+    end;
+
+end;
+
+Procedure TTestTSQLQuery.TestAutoApplyUpdatesDelete;
+var Q: TSQLQuery;
+    I, J : Integer;
+begin
+  // Test that if sqoAutoApplyUpdates is in QueryOptions, then Delete automatically does an ApplyUpdates
+  with TSQLDBConnector(DBConnector) do
+    begin
+    try
+      ExecuteDirect('DROP table testdiscon');
+    except
+      // Ignore
+    end;
+    ExecuteDirect('create table testdiscon (id integer not null, a varchar(10), constraint pk_testdiscon primary key(id))');
+    Transaction.COmmit;
+    for I:=1 to 2 do
+      ExecuteDirect(Format('INSERT INTO testdiscon values (%d,''%.6d'')',[i,i]));
+    Transaction.COmmit;
+    Q := TSQLDBConnector(DBConnector).Query;
+    FMyQ:=Q; // so th event handler can reach it.
+    Q.SQL.Text:='select * from testdiscon';
+    Q.QueryOptions:=[  sqoAutoApplyUpdates];
+    // We must test that in AfterPost, the modification is still there, for backwards compatibilty
+    Q.AfterPost:=@DoAfterPost;
+    Q.Open;
+    AssertEquals('Got all records',2,Q.RecordCount);
+    // Now check editing
+    Q.Locate('id',2,[]);
+    Q.Delete;
+    AssertTrue('Have no more updates pending',Q.UpdateStatus=usUnmodified);
+    Q.Close;
+    Q.SQL.Text:='select * from testdiscon where (id=2)';
+    Q.Open;
+    AssertTrue('Data record is deleted in database', (Q.EOF AND Q.BOF));
+    end;
+end;
+
 { TTestTSQLConnection }
 
 procedure TTestTSQLConnection.ReplaceMe;