mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-12-03 20:57:22 +01:00
fcl-db:
- base: added new TDataSetState: dsRefreshFields used in refreshing field between local TBufDataSet and remote DB during process of applying updates. - mssql: implemented RefreshLastInsertID + test git-svn-id: trunk@29443 -
This commit is contained in:
parent
8ae9752530
commit
9fba59b3bc
@ -2106,6 +2106,7 @@ begin
|
||||
case State of
|
||||
dsFilter: Result := FFilterBuffer;
|
||||
dsCalcFields: Result := CalcBuffer;
|
||||
dsRefreshFields: Result := FCurrentIndex.CurrentBuffer
|
||||
else Result := ActiveBuffer;
|
||||
end;
|
||||
end;
|
||||
@ -2155,7 +2156,7 @@ begin
|
||||
begin
|
||||
Inc(CurrBuff, GetRecordSize + Field.Offset);
|
||||
Result := Boolean(CurrBuff^);
|
||||
if result and assigned(Buffer) then
|
||||
if Result and assigned(Buffer) then
|
||||
begin
|
||||
inc(CurrBuff);
|
||||
Move(CurrBuff^, Buffer^, Field.DataSize);
|
||||
@ -2180,7 +2181,7 @@ begin
|
||||
CurrBuff := GetCurrentBuffer;
|
||||
If Field.FieldNo > 0 then // If =-1, then calculated/lookup field or =0 unbound field
|
||||
begin
|
||||
if Field.ReadOnly and not (State in [dsSetKey, dsFilter]) then
|
||||
if Field.ReadOnly and not (State in [dsSetKey, dsFilter, dsRefreshFields]) then
|
||||
DatabaseErrorFmt(SReadOnlyField, [Field.DisplayName]);
|
||||
if State in [dsEdit, dsInsert, dsNewValue] then
|
||||
Field.Validate(Buffer);
|
||||
|
||||
@ -48,7 +48,7 @@ type
|
||||
|
||||
TDataSetState = (dsInactive, dsBrowse, dsEdit, dsInsert, dsSetKey,
|
||||
dsCalcFields, dsFilter, dsNewValue, dsOldValue, dsCurValue, dsBlockRead,
|
||||
dsInternalCalc, dsOpening);
|
||||
dsInternalCalc, dsOpening, dsRefreshFields);
|
||||
|
||||
TDataEvent = (deFieldChange, deRecordChange, deDataSetChange,
|
||||
deDataSetScroll, deLayoutChange, deUpdateRecord, deUpdateState,
|
||||
@ -2157,7 +2157,7 @@ const
|
||||
|
||||
dsEditModes = [dsEdit, dsInsert, dsSetKey];
|
||||
dsWriteModes = [dsEdit, dsInsert, dsSetKey, dsCalcFields, dsFilter,
|
||||
dsNewValue, dsInternalCalc];
|
||||
dsNewValue, dsInternalCalc, dsRefreshFields];
|
||||
// Correct list of all field types that are BLOB types.
|
||||
// Please use this instead of checking TBlobType which will give
|
||||
// incorrect results
|
||||
|
||||
@ -96,6 +96,7 @@ type
|
||||
// - Statement execution
|
||||
procedure Execute(cursor:TSQLCursor; ATransaction:TSQLTransaction; AParams:TParams); override;
|
||||
function RowsAffected(cursor: TSQLCursor): TRowsCount; override;
|
||||
function RefreshLastInsertID(Query : TCustomSQLQuery; Field : TField): boolean; override;
|
||||
// - Result retrieving
|
||||
procedure AddFieldDefs(cursor:TSQLCursor; FieldDefs:TFieldDefs); override;
|
||||
function Fetch(cursor:TSQLCursor):boolean; override;
|
||||
@ -315,7 +316,7 @@ end;
|
||||
constructor TMSSQLConnection.Create(AOwner: TComponent);
|
||||
begin
|
||||
inherited Create(AOwner);
|
||||
FConnOptions := FConnOptions + [sqSupportEmptyDatabaseName, sqEscapeRepeat];
|
||||
FConnOptions := [sqSupportEmptyDatabaseName, sqEscapeRepeat, sqImplicitTransaction, sqLastInsertID];
|
||||
//FieldNameQuoteChars:=DoubleQuotes; //default
|
||||
Ftds := DBTDS_UNKNOWN;
|
||||
end;
|
||||
@ -659,6 +660,21 @@ begin
|
||||
Result := inherited RowsAffected(cursor);
|
||||
end;
|
||||
|
||||
function TMSSQLConnection.RefreshLastInsertID(Query: TCustomSQLQuery; Field: TField): boolean;
|
||||
var Identity: int64;
|
||||
begin
|
||||
// global variable @@IDENTITY is NUMERIC(38,0)
|
||||
Result:=False;
|
||||
if dbcmd(FDBProc, 'SELECT @@IDENTITY') = FAIL then Exit;
|
||||
if dbsqlexec(FDBProc) = FAIL then Exit;
|
||||
if dbresults(FDBProc) = FAIL then Exit;
|
||||
if dbnextrow(FDBProc) = FAIL then Exit;
|
||||
if dbconvert(FDBProc, dbcoltype(FDBProc,1), dbdata(FDBProc,1), -1, SYBINT8, @Identity, sizeof(Identity)) = -1 then Exit;
|
||||
// by default identity columns are ReadOnly
|
||||
Field.AsLargeInt := Identity;
|
||||
Result:=True;
|
||||
end;
|
||||
|
||||
function TMSSQLConnection.TranslateFldType(SQLDataType: integer): TFieldType;
|
||||
begin
|
||||
case SQLDataType of
|
||||
|
||||
@ -2644,7 +2644,9 @@ begin
|
||||
DoRefresh:=(UpdateKind in [ukModify,ukInsert]) and NeedRefreshRecord(UpdateKind);
|
||||
if assigned(LastIDField) or DoRefresh then
|
||||
begin
|
||||
S:=SetTempState(dsNewValue);
|
||||
// updates fields directly in record buffer of TBufDataSet
|
||||
// TDataSet buffers are resynchronized at end of ApplyUpdates process
|
||||
S:=SetTempState(dsRefreshFields);
|
||||
try
|
||||
RecordRefreshed:=False;
|
||||
if assigned(LastIDField) then
|
||||
@ -2656,7 +2658,7 @@ begin
|
||||
end;
|
||||
if RecordRefreshed then
|
||||
// Active buffer is updated, move to record.
|
||||
ActiveBufferToRecord;
|
||||
//ActiveBufferToRecord;
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
@ -574,6 +574,8 @@ begin
|
||||
case SQLServerType of
|
||||
ssMySQL:
|
||||
datatype := 'integer auto_increment';
|
||||
ssMSSQL, ssSybase:
|
||||
datatype := 'integer identity';
|
||||
ssSQLite:
|
||||
datatype := 'integer';
|
||||
else
|
||||
@ -590,18 +592,18 @@ begin
|
||||
Open;
|
||||
Insert;
|
||||
FieldByName('f').AsString:='a';
|
||||
Post;
|
||||
Post; // #1 record
|
||||
Append;
|
||||
FieldByName('f').AsString:='b';
|
||||
Post;
|
||||
Post; // #2 record
|
||||
AssertTrue('ID field is not null after Post', FieldByName('id').IsNull);
|
||||
First;
|
||||
First; // #1 record
|
||||
ApplyUpdates(0);
|
||||
AssertTrue('ID field is still null after ApplyUpdates', Not FieldByName('id').IsNull);
|
||||
// Should be 1 after the table was created, but this is not guaranteed... So we just test positive values.
|
||||
id := FieldByName('id').AsLargeInt;
|
||||
AssertTrue('ID field has not positive value', id>0);
|
||||
Next;
|
||||
Next; // #2 record
|
||||
AssertTrue('Next ID value is not greater than previous', FieldByName('id').AsLargeInt>id);
|
||||
end;
|
||||
end;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user