mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-09-13 21:11:23 +02:00
* Implemented RETURNING clause as a way of updating fields
git-svn-id: trunk@30463 -
This commit is contained in:
parent
1427d94933
commit
9a807bdfe3
@ -122,6 +122,7 @@ Resourcestring
|
|||||||
SErrRefreshNotSingleton = 'Refresh SQL resulted in multiple records: %d.';
|
SErrRefreshNotSingleton = 'Refresh SQL resulted in multiple records: %d.';
|
||||||
SErrRefreshEmptyResult = 'Refresh SQL resulted in empty result set.';
|
SErrRefreshEmptyResult = 'Refresh SQL resulted in empty result set.';
|
||||||
SErrNoKeyFieldForRefreshClause = 'No key field found to construct refresh SQL WHERE clause';
|
SErrNoKeyFieldForRefreshClause = 'No key field found to construct refresh SQL WHERE clause';
|
||||||
|
SErrFailedToFetchReturningResult = 'Failed to fetch returning result';
|
||||||
|
|
||||||
Implementation
|
Implementation
|
||||||
|
|
||||||
|
@ -180,7 +180,7 @@ constructor TIBConnection.Create(AOwner : TComponent);
|
|||||||
|
|
||||||
begin
|
begin
|
||||||
inherited;
|
inherited;
|
||||||
FConnOptions := FConnOptions + [sqSupportParams] + [sqEscapeRepeat];
|
FConnOptions := FConnOptions + [sqSupportParams, sqEscapeRepeat, sqSupportReturning];
|
||||||
FBlobSegmentSize := 65535; //Shows we're using the maximum segment size
|
FBlobSegmentSize := 65535; //Shows we're using the maximum segment size
|
||||||
FDialect := INVALID_DATA;
|
FDialect := INVALID_DATA;
|
||||||
ResetDatabaseInfo;
|
ResetDatabaseInfo;
|
||||||
|
@ -274,7 +274,7 @@ constructor TPQConnection.Create(AOwner : TComponent);
|
|||||||
|
|
||||||
begin
|
begin
|
||||||
inherited;
|
inherited;
|
||||||
FConnOptions := FConnOptions + [sqSupportParams, sqSupportEmptyDatabaseName, sqEscapeRepeat, sqEscapeSlash, sqImplicitTransaction];
|
FConnOptions := FConnOptions + [sqSupportParams, sqSupportEmptyDatabaseName, sqEscapeRepeat, sqEscapeSlash, sqImplicitTransaction,sqSupportReturning];
|
||||||
FieldNameQuoteChars:=DoubleQuotes;
|
FieldNameQuoteChars:=DoubleQuotes;
|
||||||
VerboseErrors:=True;
|
VerboseErrors:=True;
|
||||||
FConnectionPool:=TThreadlist.Create;
|
FConnectionPool:=TThreadlist.Create;
|
||||||
|
@ -138,7 +138,7 @@ type
|
|||||||
|
|
||||||
{ TSQLConnection }
|
{ TSQLConnection }
|
||||||
|
|
||||||
TConnOption = (sqSupportParams, sqSupportEmptyDatabaseName, sqEscapeSlash, sqEscapeRepeat, sqImplicitTransaction, sqLastInsertID);
|
TConnOption = (sqSupportParams, sqSupportEmptyDatabaseName, sqEscapeSlash, sqEscapeRepeat, sqImplicitTransaction, sqLastInsertID, sqSupportReturning);
|
||||||
TConnOptions= set of TConnOption;
|
TConnOptions= set of TConnOption;
|
||||||
|
|
||||||
TSQLConnectionOption = (scoExplicitConnect, scoApplyUpdatesChecksRowsAffected);
|
TSQLConnectionOption = (scoExplicitConnect, scoApplyUpdatesChecksRowsAffected);
|
||||||
@ -172,11 +172,11 @@ type
|
|||||||
// One day, this may be factored out to a TSQLResolver class.
|
// One day, this may be factored out to a TSQLResolver class.
|
||||||
// The following allow construction of update queries. They can be adapted as needed by descendents to fit the DB engine.
|
// The following allow construction of update queries. They can be adapted as needed by descendents to fit the DB engine.
|
||||||
procedure AddFieldToUpdateWherePart(var sql_where: string; UpdateMode : TUpdateMode; F: TField); virtual;
|
procedure AddFieldToUpdateWherePart(var sql_where: string; UpdateMode : TUpdateMode; F: TField); virtual;
|
||||||
function ConstructInsertSQL(Query: TCustomSQLQuery): string; virtual;
|
function ConstructInsertSQL(Query: TCustomSQLQuery; Var ReturningClause : Boolean): string; virtual;
|
||||||
function ConstructUpdateSQL(Query: TCustomSQLQuery): string; virtual;
|
function ConstructUpdateSQL(Query: TCustomSQLQuery; Var ReturningClause : Boolean): string; virtual;
|
||||||
function ConstructDeleteSQL(Query: TCustomSQLQuery): string; virtual;
|
function ConstructDeleteSQL(Query: TCustomSQLQuery): string; virtual;
|
||||||
function ConstructRefreshSQL(Query: TCustomSQLQuery; UpdateKind : TUpdateKind): string; virtual;
|
function ConstructRefreshSQL(Query: TCustomSQLQuery; UpdateKind : TUpdateKind): string; virtual;
|
||||||
function InitialiseUpdateStatement(Query: TCustomSQLQuery; var qry: TCustomSQLStatement): TCustomSQLStatement;
|
function InitialiseUpdateStatement(Query: TCustomSQLQuery; var qry: TCustomSQLQuery): TCustomSQLQuery;
|
||||||
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;
|
||||||
@ -402,7 +402,7 @@ type
|
|||||||
|
|
||||||
{ TCustomSQLQuery }
|
{ TCustomSQLQuery }
|
||||||
|
|
||||||
TSQLQueryOption = (sqoKeepOpenOnCommit, sqoAutoApplyUpdates, sqoAutoCommit, sqoCancelUpdatesOnRefresh);
|
TSQLQueryOption = (sqoKeepOpenOnCommit, sqoAutoApplyUpdates, sqoAutoCommit, sqoCancelUpdatesOnRefresh, sqoPreferRefresh);
|
||||||
TSQLQueryOptions = Set of TSQLQueryOption;
|
TSQLQueryOptions = Set of TSQLQueryOption;
|
||||||
|
|
||||||
TCustomSQLQuery = class (TCustomBufDataset)
|
TCustomSQLQuery = class (TCustomBufDataset)
|
||||||
@ -433,7 +433,7 @@ type
|
|||||||
|
|
||||||
FInsertQry,
|
FInsertQry,
|
||||||
FUpdateQry,
|
FUpdateQry,
|
||||||
FDeleteQry : TCustomSQLStatement;
|
FDeleteQry : TCustomSQLQuery;
|
||||||
FSequence : TSQLSequence;
|
FSequence : TSQLSequence;
|
||||||
procedure FreeFldBuffers;
|
procedure FreeFldBuffers;
|
||||||
function GetParamCheck: Boolean;
|
function GetParamCheck: Boolean;
|
||||||
@ -466,6 +466,7 @@ type
|
|||||||
Function RefreshLastInsertID(Field: TField): Boolean; virtual;
|
Function RefreshLastInsertID(Field: TField): Boolean; virtual;
|
||||||
Function NeedRefreshRecord (UpdateKind: TUpdateKind): Boolean; virtual;
|
Function NeedRefreshRecord (UpdateKind: TUpdateKind): Boolean; virtual;
|
||||||
Function RefreshRecord (UpdateKind: TUpdateKind) : Boolean; virtual;
|
Function RefreshRecord (UpdateKind: TUpdateKind) : Boolean; virtual;
|
||||||
|
Procedure ApplyReturningResult(Q : TCustomSQLQuery; UpdateKind : TUpdateKind);
|
||||||
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;
|
||||||
@ -1587,15 +1588,18 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
function TSQLConnection.InitialiseUpdateStatement(Query : TCustomSQLQuery; var qry : TCustomSQLStatement): TCustomSQLStatement;
|
function TSQLConnection.InitialiseUpdateStatement(Query : TCustomSQLQuery; var qry : TCustomSQLQuery): TCustomSQLQuery;
|
||||||
|
|
||||||
begin
|
begin
|
||||||
if not assigned(qry) then
|
if not assigned(qry) then
|
||||||
begin
|
begin
|
||||||
qry := TCustomSQLStatement.Create(nil);
|
qry := TCustomSQLQuery.Create(nil);
|
||||||
qry.ParseSQL := False;
|
qry.ParseSQL := False;
|
||||||
qry.DataBase := Self;
|
qry.DataBase := Self;
|
||||||
qry.Transaction := Query.SQLTransaction;
|
qry.Transaction := Query.SQLTransaction;
|
||||||
|
qry.Unidirectional:=True;
|
||||||
|
qry.UsePrimaryKeyAsKey:=False;
|
||||||
|
qry.PacketRecords:=1;
|
||||||
end;
|
end;
|
||||||
Result:=qry;
|
Result:=qry;
|
||||||
end;
|
end;
|
||||||
@ -1620,16 +1624,19 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
function TSQLConnection.ConstructInsertSQL(Query : TCustomSQLQuery) : string;
|
function TSQLConnection.ConstructInsertSQL(Query : TCustomSQLQuery; Var ReturningClause : Boolean) : string;
|
||||||
|
|
||||||
var x : integer;
|
var x : integer;
|
||||||
sql_fields : string;
|
sql_fields : string;
|
||||||
sql_values : string;
|
sql_values : string;
|
||||||
|
returning_fields : String;
|
||||||
F : TField;
|
F : TField;
|
||||||
|
|
||||||
|
|
||||||
begin
|
begin
|
||||||
sql_fields := '';
|
sql_fields := '';
|
||||||
sql_values := '';
|
sql_values := '';
|
||||||
|
returning_fields :='';
|
||||||
for x := 0 to Query.Fields.Count -1 do
|
for x := 0 to Query.Fields.Count -1 do
|
||||||
begin
|
begin
|
||||||
F:=Query.Fields[x];
|
F:=Query.Fields[x];
|
||||||
@ -1638,37 +1645,60 @@ begin
|
|||||||
sql_fields := sql_fields + FieldNameQuoteChars[0] + F.FieldName + FieldNameQuoteChars[1] + ',';
|
sql_fields := sql_fields + FieldNameQuoteChars[0] + F.FieldName + FieldNameQuoteChars[1] + ',';
|
||||||
sql_values := sql_values + ':"' + F.FieldName + '",';
|
sql_values := sql_values + ':"' + F.FieldName + '",';
|
||||||
end;
|
end;
|
||||||
|
if ReturningClause and (pfRefreshOnInsert in F.ProviderFlags) then
|
||||||
|
returning_fields :=returning_fields+FieldNameQuoteChars[0] + F.FieldName + FieldNameQuoteChars[1] + ',';
|
||||||
end;
|
end;
|
||||||
if length(sql_fields) = 0 then
|
if length(sql_fields) = 0 then
|
||||||
DatabaseErrorFmt(sNoUpdateFields,['insert'],self);
|
DatabaseErrorFmt(sNoUpdateFields,['insert'],self);
|
||||||
setlength(sql_fields,length(sql_fields)-1);
|
setlength(sql_fields,length(sql_fields)-1);
|
||||||
setlength(sql_values,length(sql_values)-1);
|
setlength(sql_values,length(sql_values)-1);
|
||||||
|
|
||||||
result := 'insert into ' + Query.FTableName + ' (' + sql_fields + ') values (' + sql_values + ')';
|
result := 'insert into ' + Query.FTableName + ' (' + sql_fields + ') values (' + sql_values + ')';
|
||||||
|
if ReturningClause then
|
||||||
|
begin
|
||||||
|
ReturningClause:=length(returning_fields) <> 0 ;
|
||||||
|
if ReturningClause then
|
||||||
|
begin
|
||||||
|
setlength(returning_fields,length(returning_fields)-1);
|
||||||
|
result:=Result+' returning '+returning_fields;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
function TSQLConnection.ConstructUpdateSQL(Query: TCustomSQLQuery): string;
|
function TSQLConnection.ConstructUpdateSQL(Query: TCustomSQLQuery; Var ReturningClause : Boolean): string;
|
||||||
|
|
||||||
var x : integer;
|
var x : integer;
|
||||||
F : TField;
|
F : TField;
|
||||||
sql_set : string;
|
sql_set : string;
|
||||||
sql_where : string;
|
sql_where : string;
|
||||||
|
returning_fields : String;
|
||||||
|
|
||||||
begin
|
begin
|
||||||
sql_set := '';
|
sql_set := '';
|
||||||
sql_where := '';
|
sql_where := '';
|
||||||
|
returning_fields :='';
|
||||||
for x := 0 to Query.Fields.Count -1 do
|
for x := 0 to Query.Fields.Count -1 do
|
||||||
begin
|
begin
|
||||||
F:=Query.Fields[x];
|
F:=Query.Fields[x];
|
||||||
AddFieldToUpdateWherePart(sql_where,Query.UpdateMode,F);
|
AddFieldToUpdateWherePart(sql_where,Query.UpdateMode,F);
|
||||||
if (pfInUpdate in F.ProviderFlags) and (not F.ReadOnly) then
|
if (pfInUpdate in F.ProviderFlags) and (not F.ReadOnly) then
|
||||||
sql_set := sql_set +FieldNameQuoteChars[0] + F.FieldName + FieldNameQuoteChars[1] +'=:"' + F.FieldName + '",';
|
sql_set := sql_set +FieldNameQuoteChars[0] + F.FieldName + FieldNameQuoteChars[1] +'=:"' + F.FieldName + '",';
|
||||||
|
if ReturningClause and (pfRefreshOnUpdate in F.ProviderFlags) then
|
||||||
|
returning_fields :=returning_fields+FieldNameQuoteChars[0] + F.FieldName + FieldNameQuoteChars[1] + ',';
|
||||||
end;
|
end;
|
||||||
if length(sql_set) = 0 then DatabaseErrorFmt(sNoUpdateFields,['update'],self);
|
if length(sql_set) = 0 then DatabaseErrorFmt(sNoUpdateFields,['update'],self);
|
||||||
setlength(sql_set,length(sql_set)-1);
|
setlength(sql_set,length(sql_set)-1);
|
||||||
if length(sql_where) = 0 then DatabaseErrorFmt(sNoWhereFields,['update'],self);
|
if length(sql_where) = 0 then DatabaseErrorFmt(sNoWhereFields,['update'],self);
|
||||||
result := 'update ' + Query.FTableName + ' set ' + sql_set + ' where ' + sql_where;
|
result := 'update ' + Query.FTableName + ' set ' + sql_set + ' where ' + sql_where;
|
||||||
|
if ReturningClause then
|
||||||
|
begin
|
||||||
|
ReturningClause:=length(returning_fields) <> 0 ;
|
||||||
|
if ReturningClause then
|
||||||
|
begin
|
||||||
|
setlength(returning_fields,length(returning_fields)-1);
|
||||||
|
result:=Result+' returning '+returning_fields;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
@ -1737,24 +1767,27 @@ end;
|
|||||||
procedure TSQLConnection.ApplyRecUpdate(Query: TCustomSQLQuery; UpdateKind: TUpdateKind);
|
procedure TSQLConnection.ApplyRecUpdate(Query: TCustomSQLQuery; UpdateKind: TUpdateKind);
|
||||||
|
|
||||||
var
|
var
|
||||||
qry : TCustomSQLStatement;
|
qry : TCustomSQLQuery;
|
||||||
s : string;
|
s : string;
|
||||||
x : integer;
|
x : integer;
|
||||||
Fld : TField;
|
Fld : TField;
|
||||||
P : TParam;
|
P : TParam;
|
||||||
B : Boolean;
|
B,ReturningClause : Boolean;
|
||||||
|
|
||||||
begin
|
begin
|
||||||
|
qry:=Nil;
|
||||||
|
ReturningClause:=(sqSupportReturning in Connoptions) and not (sqoPreferRefresh in Query.Options);
|
||||||
case UpdateKind of
|
case UpdateKind of
|
||||||
ukInsert : begin
|
ukInsert : begin
|
||||||
s := trim(Query.FInsertSQL.Text);
|
s := trim(Query.FInsertSQL.Text);
|
||||||
if s = '' then s := ConstructInsertSQL(Query);
|
if s = '' then
|
||||||
|
s := ConstructInsertSQL(Query,ReturningClause);
|
||||||
qry := InitialiseUpdateStatement(Query,Query.FInsertQry);
|
qry := InitialiseUpdateStatement(Query,Query.FInsertQry);
|
||||||
end;
|
end;
|
||||||
ukModify : begin
|
ukModify : begin
|
||||||
s := trim(Query.FUpdateSQL.Text);
|
s := trim(Query.FUpdateSQL.Text);
|
||||||
if (s='') and (not assigned(Query.FUpdateQry) or (Query.UpdateMode<>upWhereKeyOnly)) then //first time or dynamic where part
|
if (s='') and (not assigned(Query.FUpdateQry) or (Query.UpdateMode<>upWhereKeyOnly)) then //first time or dynamic where part
|
||||||
s := ConstructUpdateSQL(Query);
|
s := ConstructUpdateSQL(Query,ReturningClause);
|
||||||
qry := InitialiseUpdateStatement(Query,Query.FUpdateQry);
|
qry := InitialiseUpdateStatement(Query,Query.FUpdateQry);
|
||||||
end;
|
end;
|
||||||
ukDelete : begin
|
ukDelete : begin
|
||||||
@ -1762,11 +1795,12 @@ begin
|
|||||||
if (s='') and (not assigned(Query.FDeleteQry) or (Query.UpdateMode<>upWhereKeyOnly)) then
|
if (s='') and (not assigned(Query.FDeleteQry) or (Query.UpdateMode<>upWhereKeyOnly)) then
|
||||||
s := ConstructDeleteSQL(Query);
|
s := ConstructDeleteSQL(Query);
|
||||||
qry := InitialiseUpdateStatement(Query,Query.FDeleteQry);
|
qry := InitialiseUpdateStatement(Query,Query.FDeleteQry);
|
||||||
|
ReturningClause:=False;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
if (s<>'') and (qry.SQL.Text<>s) then
|
if (s<>'') and (qry.SQL.Text<>s) then
|
||||||
qry.SQL.Text:=s; //assign only when changed, to avoid UnPrepare/Prepare
|
qry.SQL.Text:=s; //assign only when changed, to avoid UnPrepare/Prepare
|
||||||
assert(qry.sql.Text<>'');
|
Assert(qry.sql.Text<>'');
|
||||||
for x:=0 to Qry.Params.Count-1 do
|
for x:=0 to Qry.Params.Count-1 do
|
||||||
begin
|
begin
|
||||||
P:=Qry.Params[x];
|
P:=Qry.Params[x];
|
||||||
@ -1777,9 +1811,18 @@ begin
|
|||||||
Fld:=Query.FieldByName(S);
|
Fld:=Query.FieldByName(S);
|
||||||
ApplyFieldUpdate(Query.Cursor,P as TSQLDBParam,Fld,B);
|
ApplyFieldUpdate(Query.Cursor,P as TSQLDBParam,Fld,B);
|
||||||
end;
|
end;
|
||||||
|
if ReturningClause then
|
||||||
|
Qry.Open
|
||||||
|
else
|
||||||
Qry.Execute;
|
Qry.Execute;
|
||||||
if (scoApplyUpdatesChecksRowsAffected in Options) and (Qry.RowsAffected<>1) then
|
if (scoApplyUpdatesChecksRowsAffected in Options) and (Qry.RowsAffected<>1) then
|
||||||
|
begin
|
||||||
|
if ReturningClause then
|
||||||
|
Qry.Close;
|
||||||
DatabaseErrorFmt(SErrFailedToUpdateRecord, [Qry.RowsAffected], Query);
|
DatabaseErrorFmt(SErrFailedToUpdateRecord, [Qry.RowsAffected], Query);
|
||||||
|
end;
|
||||||
|
if ReturningClause then
|
||||||
|
Query.ApplyReturningResult(Qry,UpdateKind);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TSQLConnection.RefreshLastInsertID(Query: TCustomSQLQuery; Field: TField): Boolean;
|
function TSQLConnection.RefreshLastInsertID(Query: TCustomSQLQuery; Field: TField): Boolean;
|
||||||
@ -2310,9 +2353,12 @@ function TCustomSQLQuery.NeedRefreshRecord(UpdateKind: TUpdateKind): Boolean;
|
|||||||
Var
|
Var
|
||||||
PF : TProviderFlag;
|
PF : TProviderFlag;
|
||||||
I : Integer;
|
I : Integer;
|
||||||
|
DoReturning : Boolean;
|
||||||
|
|
||||||
begin
|
begin
|
||||||
Result:=(FRefreshSQL.Count<>0);
|
Result:=(FRefreshSQL.Count<>0);
|
||||||
if Not Result then
|
DoReturning:=(sqSupportReturning in SQLConnection.ConnOptions) and not (sqoPreferRefresh in Options);
|
||||||
|
if Not (Result or DoReturning) then
|
||||||
begin
|
begin
|
||||||
PF:=RefreshFlags[UpdateKind];
|
PF:=RefreshFlags[UpdateKind];
|
||||||
I:=0;
|
I:=0;
|
||||||
@ -2374,6 +2420,25 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TCustomSQLQuery.ApplyReturningResult(Q: TCustomSQLQuery; UpdateKind : TUpdateKind);
|
||||||
|
|
||||||
|
Var
|
||||||
|
S : TDataSetState;
|
||||||
|
refreshFlag : TProviderFlag;
|
||||||
|
F : TField;
|
||||||
|
|
||||||
|
begin
|
||||||
|
RefreshFlag:=RefreshFlags[UpdateKind];
|
||||||
|
S:=SetTempState(dsRefreshFields);
|
||||||
|
try
|
||||||
|
For F in Fields do
|
||||||
|
if RefreshFlag in F.ProviderFlags then
|
||||||
|
F.Assign(Q.FieldByName(F.FieldName));
|
||||||
|
finally
|
||||||
|
RestoreState(S);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TCustomSQLQuery.ApplyFilter;
|
procedure TCustomSQLQuery.ApplyFilter;
|
||||||
|
|
||||||
begin
|
begin
|
||||||
|
@ -54,6 +54,8 @@ type
|
|||||||
Procedure TestRefreshSQLNoRecords;
|
Procedure TestRefreshSQLNoRecords;
|
||||||
Procedure TestFetchAutoInc;
|
Procedure TestFetchAutoInc;
|
||||||
procedure TestSequence;
|
procedure TestSequence;
|
||||||
|
procedure TestReturningInsert;
|
||||||
|
procedure TestReturningUpdate;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{ TTestTSQLConnection }
|
{ TTestTSQLConnection }
|
||||||
@ -198,7 +200,7 @@ begin
|
|||||||
|
|
||||||
Q := SQLDBConnector.Query;
|
Q := SQLDBConnector.Query;
|
||||||
Q.SQL.Text:='select * from FPDEV2';
|
Q.SQL.Text:='select * from FPDEV2';
|
||||||
Q.Options:=[sqoKeepOpenOnCommit];
|
Q.Options:=[sqoKeepOpenOnCommit,sqoPreferRefresh];
|
||||||
AssertEquals('PacketRecords forced to -1',-1,Q.PacketRecords);
|
AssertEquals('PacketRecords forced to -1',-1,Q.PacketRecords);
|
||||||
Q.Open;
|
Q.Open;
|
||||||
AssertEquals('Got all records',20,Q.RecordCount);
|
AssertEquals('Got all records',20,Q.RecordCount);
|
||||||
@ -402,6 +404,7 @@ begin
|
|||||||
Transaction.Commit;
|
Transaction.Commit;
|
||||||
end;
|
end;
|
||||||
Q:=SQLDBConnector.Query;
|
Q:=SQLDBConnector.Query;
|
||||||
|
Q.OPtions:=Q.OPtions+[sqoPreferRefresh];
|
||||||
Q.SQL.Text:='select * from FPDEV2';
|
Q.SQL.Text:='select * from FPDEV2';
|
||||||
Q.InsertSQL.Text:='insert into FPDEV2 (id) values (:id)';
|
Q.InsertSQL.Text:='insert into FPDEV2 (id) values (:id)';
|
||||||
Q.RefreshSQL.Text:='SELECT a,b FROM FPDEV2 WHERE (id=:id)';
|
Q.RefreshSQL.Text:='SELECT a,b FROM FPDEV2 WHERE (id=:id)';
|
||||||
@ -440,6 +443,7 @@ begin
|
|||||||
Q:=SQLDBConnector.Query;
|
Q:=SQLDBConnector.Query;
|
||||||
Q.SQL.Text:='select * from FPDEV2';
|
Q.SQL.Text:='select * from FPDEV2';
|
||||||
Q.InsertSQL.Text:='insert into FPDEV2 (id) values (:id)';
|
Q.InsertSQL.Text:='insert into FPDEV2 (id) values (:id)';
|
||||||
|
Q.OPtions:=Q.OPtions+[sqoPreferRefresh];
|
||||||
Q.Open;
|
Q.Open;
|
||||||
With Q.FieldByName('id') do
|
With Q.FieldByName('id') do
|
||||||
ProviderFlags:=ProviderFlags+[pfInKey];
|
ProviderFlags:=ProviderFlags+[pfInKey];
|
||||||
@ -471,6 +475,7 @@ begin
|
|||||||
Q:=SQLDBConnector.Query;
|
Q:=SQLDBConnector.Query;
|
||||||
Q.SQL.Text:='select * from FPDEV2';
|
Q.SQL.Text:='select * from FPDEV2';
|
||||||
Q.InsertSQL.Text:='insert into FPDEV2 (id) values (:id)';
|
Q.InsertSQL.Text:='insert into FPDEV2 (id) values (:id)';
|
||||||
|
Q.OPtions:=Q.OPtions+[sqoPreferRefresh];
|
||||||
Q.Open;
|
Q.Open;
|
||||||
With Q.FieldByName('id') do
|
With Q.FieldByName('id') do
|
||||||
ProviderFlags:=ProviderFlags+[pfInKey];
|
ProviderFlags:=ProviderFlags+[pfInKey];
|
||||||
@ -497,6 +502,7 @@ begin
|
|||||||
FMyQ:=SQLDBConnector.Query;
|
FMyQ:=SQLDBConnector.Query;
|
||||||
FMyQ.SQL.Text:='select * from FPDEV2';
|
FMyQ.SQL.Text:='select * from FPDEV2';
|
||||||
FMyQ.InsertSQL.Text:='insert into FPDEV2 (id) values (:id)';
|
FMyQ.InsertSQL.Text:='insert into FPDEV2 (id) values (:id)';
|
||||||
|
FMyQ.OPtions:=FMyQ.OPtions+[sqoPreferRefresh];
|
||||||
FMyQ.Open;
|
FMyQ.Open;
|
||||||
With FMyQ.FieldByName('id') do
|
With FMyQ.FieldByName('id') do
|
||||||
ProviderFlags:=ProviderFlags-[pfInKey];
|
ProviderFlags:=ProviderFlags-[pfInKey];
|
||||||
@ -521,6 +527,7 @@ begin
|
|||||||
Transaction.Commit;
|
Transaction.Commit;
|
||||||
end;
|
end;
|
||||||
FMyQ:=SQLDBConnector.Query;
|
FMyQ:=SQLDBConnector.Query;
|
||||||
|
FMyQ.OPtions:=FMyQ.OPtions+[sqoPreferRefresh];
|
||||||
FMyQ.SQL.Text:='select * from FPDEV2';
|
FMyQ.SQL.Text:='select * from FPDEV2';
|
||||||
FMyQ.InsertSQL.Text:='insert into FPDEV2 (id) values (:id)';
|
FMyQ.InsertSQL.Text:='insert into FPDEV2 (id) values (:id)';
|
||||||
FMyQ.RefreshSQL.Text:='select * from FPDEV2';
|
FMyQ.RefreshSQL.Text:='select * from FPDEV2';
|
||||||
@ -547,6 +554,7 @@ begin
|
|||||||
Transaction.Commit;
|
Transaction.Commit;
|
||||||
end;
|
end;
|
||||||
FMyQ:=SQLDBConnector.Query;
|
FMyQ:=SQLDBConnector.Query;
|
||||||
|
FMyQ.OPtions:=FMyQ.OPtions+[sqoPreferRefresh];
|
||||||
FMyQ.SQL.Text:='select * from FPDEV2';
|
FMyQ.SQL.Text:='select * from FPDEV2';
|
||||||
FMyQ.InsertSQL.Text:='insert into FPDEV2 (id) values (:id)';
|
FMyQ.InsertSQL.Text:='insert into FPDEV2 (id) values (:id)';
|
||||||
FMyQ.RefreshSQL.Text:='select * from FPDEV2 where 1=2';
|
FMyQ.RefreshSQL.Text:='select * from FPDEV2 where 1=2';
|
||||||
@ -647,6 +655,68 @@ begin
|
|||||||
SQLDBConnector.CommitDDL;
|
SQLDBConnector.CommitDDL;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TTestTSQLQuery.TestReturningInsert;
|
||||||
|
|
||||||
|
begin
|
||||||
|
with SQLDBConnector do
|
||||||
|
begin
|
||||||
|
if not (sqSupportReturning in Connection.ConnOptions) then
|
||||||
|
Ignore(STestNotApplicable);
|
||||||
|
ExecuteDirect('create table FPDEV2 (id integer not null, a varchar(10) default ''abcde'', b varchar(5) default ''fgh'', constraint PK_FPDEV2 primary key(id))');
|
||||||
|
if Transaction.Active then
|
||||||
|
Transaction.Commit;
|
||||||
|
ExecuteDirect('insert into FPDEV2 (id) values (123)');
|
||||||
|
if Transaction.Active then
|
||||||
|
Transaction.Commit;
|
||||||
|
end;
|
||||||
|
FMyQ:=SQLDBConnector.Query;
|
||||||
|
FMyQ.SQL.Text:='select * from FPDEV2';
|
||||||
|
// FMyQ.InsertSQL.Text:='insert into FPDEV2 (id) values (:id)';
|
||||||
|
FMyQ.Open;
|
||||||
|
With FMyQ.FieldByName('id') do
|
||||||
|
ProviderFlags:=ProviderFlags+[pfInKey];
|
||||||
|
With FMyQ.FieldByName('a') do
|
||||||
|
ProviderFlags:=ProviderFlags+[pfRefreshOnInsert];
|
||||||
|
With FMyQ.FieldByName('b') do
|
||||||
|
ProviderFlags:=[];
|
||||||
|
FMyQ.Insert;
|
||||||
|
FMyQ.FieldByName('id').AsInteger:=1;
|
||||||
|
FMyQ.Post;
|
||||||
|
FMyQ.ApplyUpdates;
|
||||||
|
AssertEquals('a updated','abcde',FMyQ.FieldByName('a').AsString);
|
||||||
|
AssertEquals('b not updated','',FMyQ.FieldByName('b').AsString);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TTestTSQLQuery.TestReturningUpdate;
|
||||||
|
|
||||||
|
begin
|
||||||
|
with SQLDBConnector do
|
||||||
|
begin
|
||||||
|
if not (sqSupportReturning in Connection.ConnOptions) then
|
||||||
|
Ignore(STestNotApplicable);
|
||||||
|
ExecuteDirect('create table FPDEV2 (id integer not null, a varchar(10) default ''abcde'', b varchar(5) default ''fgh'', constraint PK_FPDEV2 primary key(id))');
|
||||||
|
if Transaction.Active then
|
||||||
|
Transaction.Commit;
|
||||||
|
ExecuteDirect('insert into FPDEV2 (id) values (123)');
|
||||||
|
if Transaction.Active then
|
||||||
|
Transaction.Commit;
|
||||||
|
end;
|
||||||
|
FMyQ:=SQLDBConnector.Query;
|
||||||
|
FMyQ.SQL.Text:='select * from FPDEV2';
|
||||||
|
FMyQ.Open;
|
||||||
|
With FMyQ.FieldByName('id') do
|
||||||
|
ProviderFlags:=ProviderFlags+[pfInKey];
|
||||||
|
With FMyQ.FieldByName('b') do
|
||||||
|
ProviderFlags:=[pfRefreshOnUpdate]; // Do not update, just fetch new value
|
||||||
|
FMyQ.Edit;
|
||||||
|
FMyQ.FieldByName('a').AsString:='ccc';
|
||||||
|
FMyQ.Post;
|
||||||
|
SQLDBConnector.ExecuteDirect('update FPDEV2 set b=''123'' where id=123');
|
||||||
|
FMyQ.ApplyUpdates;
|
||||||
|
AssertEquals('a updated','ccc',FMyQ.FieldByName('a').AsString);
|
||||||
|
AssertEquals('b updated','123',FMyQ.FieldByName('b').AsString);
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
{ TTestTSQLConnection }
|
{ TTestTSQLConnection }
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user