* QueryOptions for disconnected mode and autoapplyupdates

git-svn-id: trunk@29088 -
This commit is contained in:
michael 2014-11-17 12:24:46 +00:00
parent 475a9e1617
commit a53fca1b67
6 changed files with 295 additions and 38 deletions

View File

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

View File

@ -379,15 +379,27 @@ begin
DatabaseError(SErrNoDatabaseAvailable,Self) DatabaseError(SErrNoDatabaseAvailable,Self)
end; end;
Function TDBTransaction.AllowClose(DS : TDBDataset) : Boolean;
begin
Result:=Assigned(DS);
end;
procedure TDBTransaction.CloseDataSets; procedure TDBTransaction.CloseDataSets;
Var I : longint; Var
I : longint;
DS : TDBDataset;
begin begin
If Assigned(FDatasets) then If Assigned(FDatasets) then
begin begin
For I:=FDatasets.Count-1 downto 0 do 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;
end; end;

View File

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

View File

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

View File

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

View File

@ -9,7 +9,7 @@ unit TestSQLDB;
interface interface
uses uses
Classes, SysUtils, fpcunit, testregistry, Classes, sqldb, SysUtils, fpcunit, testregistry,
db; db;
type type
@ -25,10 +25,20 @@ type
{ TTestTSQLQuery } { TTestTSQLQuery }
TTestTSQLQuery = class(TSQLDBTestCase) TTestTSQLQuery = class(TSQLDBTestCase)
procedure DoAfterPost(DataSet: TDataSet);
private private
FMyQ: TSQLQuery;
Procedure Allow;
Procedure SetQueryOPtions;
Procedure TrySetPacketRecords;
published published
procedure TestMasterDetail; procedure TestMasterDetail;
procedure TestUpdateServerIndexDefs; procedure TestUpdateServerIndexDefs;
Procedure TestDisconnected;
Procedure TestDisconnectedPacketRecords;
Procedure TestCheckSettingsOnlyWhenInactive;
Procedure TestAutoApplyUpdatesPost;
Procedure TestAutoApplyUpdatesDelete;
end; end;
{ TTestTSQLConnection } { TTestTSQLConnection }
@ -50,11 +60,21 @@ type
implementation implementation
uses sqldbtoolsunit, toolsunit, sqldb; uses sqldbtoolsunit, toolsunit;
{ TTestTSQLQuery } { 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; procedure TTestTSQLQuery.TestMasterDetail;
var MasterQuery, DetailQuery: TSQLQuery; var MasterQuery, DetailQuery: TSQLQuery;
MasterSource: TDataSource; MasterSource: TDataSource;
@ -141,6 +161,168 @@ begin
end; end;
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 } { TTestTSQLConnection }
procedure TTestTSQLConnection.ReplaceMe; procedure TTestTSQLConnection.ReplaceMe;