27 |
|
{ IBX For Lazarus (Firebird Express) } |
28 |
|
{ Contributor: Tony Whyman, MWA Software http://www.mwasoftware.co.uk } |
29 |
|
{ Portions created by MWA Software are copyright McCallum Whyman } |
30 |
< |
{ Associates Ltd 2011 - 2015 } |
30 |
> |
{ Associates Ltd 2011 - 2015 } |
31 |
|
{ } |
32 |
|
{************************************************************************} |
33 |
|
|
53 |
|
unix, |
54 |
|
{$ENDIF} |
55 |
|
SysUtils, Classes, IBDatabase, IBExternals, IB, IBSQL, Db, |
56 |
< |
IBUtils, IBBlob, IBSQLParser; |
56 |
> |
IBUtils, IBBlob, IBSQLParser, IBDatabaseInfo; |
57 |
|
|
58 |
|
const |
59 |
|
BufferCacheSize = 1000; { Allocate cache in this many record chunks} |
74 |
|
procedure SetDataSet(ADataSet: TIBCustomDataSet); virtual; abstract; |
75 |
|
procedure Apply(UpdateKind: TUpdateKind; buff: PChar); virtual; abstract; |
76 |
|
function GetSQL(UpdateKind: TUpdateKind): TStrings; virtual; abstract; |
77 |
< |
procedure InternalSetParams(Query: TIBSQL; buff: PChar); |
77 |
> |
procedure InternalSetParams(Params: ISQLParams; buff: PChar); overload; |
78 |
> |
procedure InternalSetParams(Query: TIBSQL; buff: PChar); overload; |
79 |
> |
procedure UpdateRecordFromQuery(UpdateKind: TUpdateKind; QryResults: IResults; Buffer: PChar); |
80 |
|
property DataSet: TIBCustomDataSet read GetDataSet write SetDataSet; |
81 |
|
public |
82 |
|
constructor Create(AOwner: TComponent); override; |
183 |
|
FCharacterSetSize: integer; |
184 |
|
FAutoFieldSize: boolean; |
185 |
|
FCodePage: TSystemCodePage; |
186 |
+ |
FDataSize: integer; |
187 |
|
protected |
188 |
|
procedure Bind(Binding: Boolean); override; |
189 |
|
function GetDataSize: Integer; override; |
209 |
|
Note: y > 4 will default to Floats |
210 |
|
} |
211 |
|
TIBBCDField = class(TBCDField) |
212 |
+ |
private |
213 |
+ |
FIdentityColumn: boolean; |
214 |
|
protected |
215 |
+ |
procedure Bind(Binding: Boolean); override; |
216 |
|
class procedure CheckTypeSize(Value: Integer); override; |
217 |
|
function GetAsCurrency: Currency; override; |
218 |
|
function GetAsString: string; override; |
220 |
|
function GetDataSize: Integer; override; |
221 |
|
public |
222 |
|
constructor Create(AOwner: TComponent); override; |
223 |
+ |
property IdentityColumn: boolean read FIdentityColumn; |
224 |
|
published |
225 |
|
property Size default 8; |
226 |
|
end; |
227 |
|
|
228 |
+ |
{The following integer field types extend the built in versions to enable IBX appplications |
229 |
+ |
to check for an Identity column} |
230 |
+ |
|
231 |
+ |
{ TIBSmallintField } |
232 |
+ |
|
233 |
+ |
TIBSmallintField = class(TSmallintField) |
234 |
+ |
private |
235 |
+ |
FIdentityColumn: boolean; |
236 |
+ |
protected |
237 |
+ |
procedure Bind(Binding: Boolean); override; |
238 |
+ |
public |
239 |
+ |
property IdentityColumn: boolean read FIdentityColumn; |
240 |
+ |
end; |
241 |
+ |
|
242 |
+ |
{ TIBIntegerField } |
243 |
+ |
|
244 |
+ |
TIBIntegerField = class(TIntegerField) |
245 |
+ |
private |
246 |
+ |
FIdentityColumn: boolean; |
247 |
+ |
protected |
248 |
+ |
procedure Bind(Binding: Boolean); override; |
249 |
+ |
public |
250 |
+ |
property IdentityColumn: boolean read FIdentityColumn; |
251 |
+ |
end; |
252 |
+ |
|
253 |
+ |
{ TIBLargeIntField } |
254 |
+ |
|
255 |
+ |
TIBLargeIntField = class(TLargeIntField) |
256 |
+ |
private |
257 |
+ |
FIdentityColumn: boolean; |
258 |
+ |
protected |
259 |
+ |
procedure Bind(Binding: Boolean); override; |
260 |
+ |
public |
261 |
+ |
property IdentityColumn: boolean read FIdentityColumn; |
262 |
+ |
end; |
263 |
+ |
|
264 |
|
{TIBMemoField} |
265 |
|
{Allows us to show truncated text in DBGrids and anything else that uses |
266 |
|
DisplayText} |
315 |
|
FFieldName: string; |
316 |
|
FGeneratorName: string; |
317 |
|
FIncrement: integer; |
318 |
+ |
FQuery: TIBSQL; |
319 |
+ |
function GetDatabase: TIBDatabase; |
320 |
+ |
function GetTransaction: TIBTransaction; |
321 |
+ |
procedure SetDatabase(AValue: TIBDatabase); |
322 |
+ |
procedure SetGeneratorName(AValue: string); |
323 |
|
procedure SetIncrement(const AValue: integer); |
324 |
+ |
procedure SetTransaction(AValue: TIBTransaction); |
325 |
+ |
procedure SetQuerySQL; |
326 |
|
protected |
327 |
< |
function GetNextValue(ADatabase: TIBDatabase; ATransaction: TIBTransaction): integer; |
327 |
> |
function GetNextValue: integer; |
328 |
|
public |
329 |
|
constructor Create(Owner: TIBCustomDataSet); |
330 |
+ |
destructor Destroy; override; |
331 |
|
procedure Apply; |
332 |
|
property Owner: TIBCustomDataSet read FOwner; |
333 |
+ |
property Database: TIBDatabase read GetDatabase write SetDatabase; |
334 |
+ |
property Transaction: TIBTransaction read GetTransaction write SetTransaction; |
335 |
|
published |
336 |
< |
property Generator: string read FGeneratorName write FGeneratorName; |
336 |
> |
property Generator: string read FGeneratorName write SetGeneratorName; |
337 |
|
property Field: string read FFieldName write FFieldName; |
338 |
|
property Increment: integer read FIncrement write SetIncrement default 1; |
339 |
|
property ApplyOnEvent: TIBGeneratorApplyOnEvent read FApplyOnEvent write FApplyOnEvent; |
371 |
|
|
372 |
|
TOnValidatePost = procedure (Sender: TObject; var CancelPost: boolean) of object; |
373 |
|
|
374 |
+ |
TOnDeleteReturning = procedure (Sender: TObject; QryResults: IResults) of object; |
375 |
+ |
|
376 |
|
TIBCustomDataSet = class(TDataset) |
377 |
|
private |
378 |
|
FAllowAutoActivateTransaction: Boolean; |
405 |
|
FDeletedRecords: Long; |
406 |
|
FModelBuffer, |
407 |
|
FOldBuffer: PChar; |
408 |
+ |
FOnDeleteReturning: TOnDeleteReturning; |
409 |
|
FOnValidatePost: TOnValidatePost; |
410 |
|
FOpen: Boolean; |
411 |
|
FInternalPrepared: Boolean; |
414 |
|
FQRefresh, |
415 |
|
FQSelect, |
416 |
|
FQModify: TIBSQL; |
417 |
+ |
FDatabaseInfo: TIBDatabaseInfo; |
418 |
|
FRecordBufferSize: Integer; |
419 |
|
FRecordCount: Integer; |
420 |
|
FRecordSize: Integer; |
444 |
|
FInTransactionEnd: boolean; |
445 |
|
FIBLinks: TList; |
446 |
|
FFieldColumns: PFieldColumns; |
447 |
+ |
FBufferUpdatedOnQryReturn: boolean; |
448 |
+ |
procedure ColumnDataToBuffer(QryResults: IResults; ColumnIndex, |
449 |
+ |
FieldIndex: integer; Buffer: PChar); |
450 |
|
procedure InitModelBuffer(Qry: TIBSQL; Buffer: PChar); |
451 |
|
function GetSelectStmtIntf: IStatement; |
452 |
|
procedure SetUpdateMode(const Value: TUpdateMode); |
469 |
|
procedure DoBeforeTransactionEnd(Sender: TObject; Action: TTransactionAction); |
470 |
|
procedure DoAfterTransactionEnd(Sender: TObject); |
471 |
|
procedure DoTransactionFree(Sender: TObject); |
472 |
+ |
procedure DoDeleteReturning(QryResults: IResults); |
473 |
|
procedure FetchCurrentRecordToBuffer(Qry: TIBSQL; RecordNumber: Integer; |
474 |
|
Buffer: PChar); |
475 |
|
function GetDatabase: TIBDatabase; |
495 |
|
procedure SetDatabase(Value: TIBDatabase); |
496 |
|
procedure SetDeleteSQL(Value: TStrings); |
497 |
|
procedure SetInsertSQL(Value: TStrings); |
498 |
< |
procedure SetInternalSQLParams(Qry: TIBSQL; Buffer: Pointer); |
498 |
> |
procedure SetInternalSQLParams(Params: ISQLParams; Buffer: Pointer); |
499 |
|
procedure SetRefreshSQL(Value: TStrings); |
500 |
|
procedure SetSelectSQL(Value: TStrings); |
501 |
|
procedure SetModifySQL(Value: TStrings); |
502 |
|
procedure SetTransaction(Value: TIBTransaction); |
503 |
|
procedure SetUpdateRecordTypes(Value: TIBUpdateRecordTypes); |
504 |
|
procedure SetUniDirectional(Value: Boolean); |
505 |
+ |
procedure UpdateRecordFromQuery(QryResults: IResults; Buffer: PChar); |
506 |
|
procedure RefreshParams; |
507 |
|
function AdjustPosition(FCache: PChar; Offset: DWORD; |
508 |
|
Origin: Integer): DWORD; |
690 |
|
procedure Post; override; |
691 |
|
function ParamByName(ParamName: String): ISQLParam; |
692 |
|
property ArrayFieldCount: integer read FArrayFieldCount; |
693 |
+ |
property DatabaseInfo: TIBDatabaseInfo read FDatabaseInfo; |
694 |
|
property UpdateObject: TIBDataSetUpdateObject read FUpdateObject write SetUpdateObject; |
695 |
|
property UpdatesPending: Boolean read FUpdatesPending; |
696 |
|
property UpdateRecordTypes: TIBUpdateRecordTypes read FUpdateRecordTypes |
735 |
|
write FOnUpdateError; |
736 |
|
property OnUpdateRecord: TIBUpdateRecordEvent read FOnUpdateRecord |
737 |
|
write FOnUpdateRecord; |
738 |
+ |
property OnDeleteReturning: TOnDeleteReturning read FOnDeleteReturning |
739 |
+ |
write FOnDeleteReturning; |
740 |
|
end; |
741 |
|
|
742 |
|
TIBParserDataSet = class(TIBCustomDataSet) |
823 |
|
property OnNewRecord; |
824 |
|
property OnPostError; |
825 |
|
property OnValidatePost; |
826 |
+ |
property OnDeleteReturning; |
827 |
|
end; |
828 |
|
|
829 |
|
{ TIBDSBlobStream } |
855 |
|
FCharacterSetName: RawByteString; |
856 |
|
FCharacterSetSize: integer; |
857 |
|
FCodePage: TSystemCodePage; |
858 |
+ |
FIdentityColumn: boolean; |
859 |
|
FRelationName: string; |
860 |
+ |
FDataSize: integer; |
861 |
|
published |
862 |
|
property CharacterSetName: RawByteString read FCharacterSetName write FCharacterSetName; |
863 |
|
property CharacterSetSize: integer read FCharacterSetSize write FCharacterSetSize; |
864 |
|
property CodePage: TSystemCodePage read FCodePage write FCodePage; |
865 |
+ |
property DataSize: integer read FDataSize write FDataSize; |
866 |
|
property RelationName: string read FRelationName write FRelationName; |
867 |
|
property ArrayDimensions: integer read FArrayDimensions write FArrayDimensions; |
868 |
|
property ArrayBounds: TArrayBounds read FArrayBounds write FArrayBounds; |
869 |
+ |
property IdentityColumn: boolean read FIdentityColumn write FIdentityColumn default false; |
870 |
|
end; |
871 |
|
|
872 |
|
const |
873 |
|
DefaultFieldClasses: array[TFieldType] of TFieldClass = ( |
874 |
|
nil, { ftUnknown } |
875 |
|
TIBStringField, { ftString } |
876 |
< |
TSmallintField, { ftSmallint } |
877 |
< |
TIntegerField, { ftInteger } |
876 |
> |
TIBSmallintField, { ftSmallint } |
877 |
> |
TIBIntegerField, { ftInteger } |
878 |
|
TWordField, { ftWord } |
879 |
|
TBooleanField, { ftBoolean } |
880 |
|
TFloatField, { ftFloat } |
896 |
|
nil, { ftCursor } |
897 |
|
TStringField, { ftFixedChar } |
898 |
|
nil, { ftWideString } |
899 |
< |
TLargeIntField, { ftLargeInt } |
899 |
> |
TIBLargeIntField, { ftLargeInt } |
900 |
|
nil, { ftADT } |
901 |
|
TIBArrayField, { ftArray } |
902 |
|
nil, { ftReference } |
940 |
|
FieldName : String; |
941 |
|
COMPUTED_BLR : Boolean; |
942 |
|
DEFAULT_VALUE : boolean; |
943 |
+ |
IDENTITY_COLUMN : boolean; |
944 |
|
NextField : TFieldNode; |
945 |
|
end; |
946 |
|
|
993 |
|
Result := str; |
994 |
|
end; |
995 |
|
|
996 |
+ |
{ TIBLargeIntField } |
997 |
+ |
|
998 |
+ |
procedure TIBLargeIntField.Bind(Binding: Boolean); |
999 |
+ |
begin |
1000 |
+ |
inherited Bind(Binding); |
1001 |
+ |
if Binding and (FieldDef <> nil) then |
1002 |
+ |
FIdentityColumn := (FieldDef as TIBFieldDef).IdentityColumn; |
1003 |
+ |
end; |
1004 |
+ |
|
1005 |
+ |
{ TIBIntegerField } |
1006 |
+ |
|
1007 |
+ |
procedure TIBIntegerField.Bind(Binding: Boolean); |
1008 |
+ |
begin |
1009 |
+ |
inherited Bind(Binding); |
1010 |
+ |
if Binding and (FieldDef <> nil) then |
1011 |
+ |
FIdentityColumn := (FieldDef as TIBFieldDef).IdentityColumn; |
1012 |
+ |
end; |
1013 |
+ |
|
1014 |
+ |
{ TIBSmallintField } |
1015 |
+ |
|
1016 |
+ |
procedure TIBSmallintField.Bind(Binding: Boolean); |
1017 |
+ |
begin |
1018 |
+ |
inherited Bind(Binding); |
1019 |
+ |
if Binding and (FieldDef <> nil) then |
1020 |
+ |
FIdentityColumn := (FieldDef as TIBFieldDef).IdentityColumn; |
1021 |
+ |
end; |
1022 |
+ |
|
1023 |
|
{ TIBArray } |
1024 |
|
|
1025 |
|
procedure TIBArray.EventHandler(Sender: IArray; Reason: TArrayEventReason); |
1129 |
|
{2: case 2 ignored. This should be handled by TIBWideMemo} |
1130 |
|
|
1131 |
|
3, {Assume UNICODE_FSS is really UTF8} |
1132 |
< |
4: {Include GB18030 - assuming UTF8 routine work for this codeset} |
1132 |
> |
4: {Include GB18030 - assuming UTF8 routines work for this codeset} |
1133 |
|
if DisplayWidth = 0 then |
1134 |
|
Result := ValidUTF8String(TextToSingleLine(Result)) |
1135 |
|
else |
1187 |
|
var s: RawByteString; |
1188 |
|
begin |
1189 |
|
s := AValue; |
1190 |
< |
if StringCodePage(Value) <> CodePage then |
1190 |
> |
if StringCodePage(s) <> CodePage then |
1191 |
|
SetCodePage(s,CodePage,CodePage<>CP_NONE); |
1192 |
|
inherited SetAsString(s); |
1193 |
|
end; |
1239 |
|
IBFieldDef := FieldDef as TIBFieldDef; |
1240 |
|
CharacterSetSize := IBFieldDef.CharacterSetSize; |
1241 |
|
CharacterSetName := IBFieldDef.CharacterSetName; |
1242 |
+ |
FDataSize := IBFieldDef.DataSize + 1; |
1243 |
|
if AutoFieldSize then |
1244 |
|
Size := IBFieldDef.Size; |
1245 |
|
CodePage := IBFieldDef.CodePage; |
1248 |
|
|
1249 |
|
function TIBStringField.GetDataSize: Integer; |
1250 |
|
begin |
1251 |
< |
Result := Size * CharacterSetSize + 1; |
1251 |
> |
Result := FDataSize; |
1252 |
|
end; |
1253 |
|
|
1254 |
|
constructor TIBStringField.Create(aOwner: TComponent); |
1307 |
|
s: RawByteString; |
1308 |
|
begin |
1309 |
|
Buffer := nil; |
1310 |
< |
IBAlloc(Buffer, 0, Size + 1); |
1310 |
> |
IBAlloc(Buffer, 0, DataSize); |
1311 |
|
try |
1312 |
|
s := Value; |
1313 |
|
if StringCodePage(s) <> CodePage then |
1314 |
|
SetCodePage(s,CodePage,CodePage<>CP_NONE); |
1315 |
< |
StrLCopy(Buffer, PChar(s), Size); |
1315 |
> |
StrLCopy(Buffer, PChar(s), DataSize-1); |
1316 |
|
if Transliterate then |
1317 |
|
DataSet.Translate(Buffer, Buffer, True); |
1318 |
|
SetData(Buffer); |
1331 |
|
Size := 8; |
1332 |
|
end; |
1333 |
|
|
1334 |
+ |
procedure TIBBCDField.Bind(Binding: Boolean); |
1335 |
+ |
begin |
1336 |
+ |
inherited Bind(Binding); |
1337 |
+ |
if Binding and (FieldDef <> nil) then |
1338 |
+ |
FIdentityColumn := (FieldDef as TIBFieldDef).IdentityColumn; |
1339 |
+ |
end; |
1340 |
+ |
|
1341 |
|
class procedure TIBBCDField.CheckTypeSize(Value: Integer); |
1342 |
|
begin |
1343 |
|
{ No need to check as the base type is currency, not BCD } |
1423 |
|
begin |
1424 |
|
inherited Create(AOwner); |
1425 |
|
FBase := TIBBase.Create(Self); |
1426 |
+ |
FDatabaseInfo := TIBDatabaseInfo.Create(self); |
1427 |
|
FIBLinks := TList.Create; |
1428 |
|
FCurrentRecord := -1; |
1429 |
|
FDeletedRecords := 0; |
1973 |
|
FTransactionFree(Sender); |
1974 |
|
end; |
1975 |
|
|
1976 |
+ |
procedure TIBCustomDataSet.DoDeleteReturning(QryResults: IResults); |
1977 |
+ |
begin |
1978 |
+ |
if assigned(FOnDeleteReturning) then |
1979 |
+ |
OnDeleteReturning(self,QryResults); |
1980 |
+ |
end; |
1981 |
+ |
|
1982 |
|
procedure TIBCustomDataSet.InitModelBuffer(Qry: TIBSQL; Buffer: PChar); |
1983 |
|
var i, j: Integer; |
1984 |
|
FieldsLoaded: integer; |
2068 |
|
end; |
2069 |
|
end; |
2070 |
|
|
2071 |
+ |
{Update Buffer Fields from Query Results} |
2072 |
+ |
|
2073 |
+ |
procedure TIBCustomDataSet.UpdateRecordFromQuery(QryResults: IResults; |
2074 |
+ |
Buffer: PChar); |
2075 |
+ |
var i, j: integer; |
2076 |
+ |
begin |
2077 |
+ |
for i := 0 to QryResults.Count - 1 do |
2078 |
+ |
begin |
2079 |
+ |
j := GetFieldPosition(QryResults[i].GetAliasName); |
2080 |
+ |
if j > 0 then |
2081 |
+ |
begin |
2082 |
+ |
ColumnDataToBuffer(QryResults,i,j,Buffer); |
2083 |
+ |
FBufferUpdatedOnQryReturn := true; |
2084 |
+ |
end; |
2085 |
+ |
end; |
2086 |
+ |
end; |
2087 |
+ |
|
2088 |
+ |
|
2089 |
+ |
{Move column data returned from query to row buffer} |
2090 |
+ |
|
2091 |
+ |
procedure TIBCustomDataSet.ColumnDataToBuffer(QryResults: IResults; |
2092 |
+ |
ColumnIndex, FieldIndex: integer; Buffer: PChar); |
2093 |
+ |
var |
2094 |
+ |
LocalData: PByte; |
2095 |
+ |
LocalDate: TDateTime; |
2096 |
+ |
LocalDouble: Double; |
2097 |
+ |
LocalInt: Integer; |
2098 |
+ |
LocalBool: wordBool; |
2099 |
+ |
LocalInt64: Int64; |
2100 |
+ |
LocalCurrency: Currency; |
2101 |
+ |
ColData: ISQLData; |
2102 |
+ |
begin |
2103 |
+ |
LocalData := nil; |
2104 |
+ |
with PRecordData(Buffer)^.rdFields[FieldIndex], FFieldColumns^[FieldIndex] do |
2105 |
+ |
begin |
2106 |
+ |
QryResults.GetData(ColumnIndex,fdIsNull,fdDataLength,LocalData); |
2107 |
+ |
if not fdIsNull then |
2108 |
+ |
begin |
2109 |
+ |
ColData := QryResults[ColumnIndex]; |
2110 |
+ |
case fdDataType of {Get Formatted data for column types that need formatting} |
2111 |
+ |
SQL_TYPE_DATE, |
2112 |
+ |
SQL_TYPE_TIME, |
2113 |
+ |
SQL_TIMESTAMP: |
2114 |
+ |
begin |
2115 |
+ |
{This is an IBX native format and not the TDataset approach. See also GetFieldData} |
2116 |
+ |
LocalDate := ColData.AsDateTime; |
2117 |
+ |
LocalData := PByte(@LocalDate); |
2118 |
+ |
end; |
2119 |
+ |
SQL_SHORT, SQL_LONG: |
2120 |
+ |
begin |
2121 |
+ |
if (fdDataScale = 0) then |
2122 |
+ |
begin |
2123 |
+ |
LocalInt := ColData.AsLong; |
2124 |
+ |
LocalData := PByte(@LocalInt); |
2125 |
+ |
end |
2126 |
+ |
else |
2127 |
+ |
if (fdDataScale >= (-4)) then |
2128 |
+ |
begin |
2129 |
+ |
LocalCurrency := ColData.AsCurrency; |
2130 |
+ |
LocalData := PByte(@LocalCurrency); |
2131 |
+ |
end |
2132 |
+ |
else |
2133 |
+ |
begin |
2134 |
+ |
LocalDouble := ColData.AsDouble; |
2135 |
+ |
LocalData := PByte(@LocalDouble); |
2136 |
+ |
end; |
2137 |
+ |
end; |
2138 |
+ |
SQL_INT64: |
2139 |
+ |
begin |
2140 |
+ |
if (fdDataScale = 0) then |
2141 |
+ |
begin |
2142 |
+ |
LocalInt64 := ColData.AsInt64; |
2143 |
+ |
LocalData := PByte(@LocalInt64); |
2144 |
+ |
end |
2145 |
+ |
else |
2146 |
+ |
if (fdDataScale >= (-4)) then |
2147 |
+ |
begin |
2148 |
+ |
LocalCurrency := ColData.AsCurrency; |
2149 |
+ |
LocalData := PByte(@LocalCurrency); |
2150 |
+ |
end |
2151 |
+ |
else |
2152 |
+ |
begin |
2153 |
+ |
LocalDouble := ColData.AsDouble; |
2154 |
+ |
LocalData := PByte(@LocalDouble); |
2155 |
+ |
end |
2156 |
+ |
end; |
2157 |
+ |
SQL_DOUBLE, SQL_FLOAT, SQL_D_FLOAT: |
2158 |
+ |
begin |
2159 |
+ |
LocalDouble := ColData.AsDouble; |
2160 |
+ |
LocalData := PByte(@LocalDouble); |
2161 |
+ |
end; |
2162 |
+ |
SQL_BOOLEAN: |
2163 |
+ |
begin |
2164 |
+ |
LocalBool := ColData.AsBoolean; |
2165 |
+ |
LocalData := PByte(@LocalBool); |
2166 |
+ |
end; |
2167 |
+ |
end; |
2168 |
+ |
|
2169 |
+ |
if fdDataType = SQL_VARYING then |
2170 |
+ |
Move(LocalData^, Buffer[fdDataOfs], fdDataLength) |
2171 |
+ |
else |
2172 |
+ |
Move(LocalData^, Buffer[fdDataOfs], fdDataSize) |
2173 |
+ |
end |
2174 |
+ |
else {Null column} |
2175 |
+ |
if fdDataType = SQL_VARYING then |
2176 |
+ |
FillChar(Buffer[fdDataOfs],fdDataLength,0) |
2177 |
+ |
else |
2178 |
+ |
FillChar(Buffer[fdDataOfs],fdDataSize,0); |
2179 |
+ |
end; |
2180 |
+ |
end; |
2181 |
+ |
|
2182 |
|
{ Read the record from FQSelect.Current into the record buffer |
2183 |
|
Then write the buffer to in memory cache } |
2184 |
|
procedure TIBCustomDataSet.FetchCurrentRecordToBuffer(Qry: TIBSQL; |
2187 |
|
pbd: PBlobDataArray; |
2188 |
|
pda: PArrayDataArray; |
2189 |
|
i, j: Integer; |
1966 |
– |
LocalData: PChar; |
1967 |
– |
LocalDate, LocalDouble: Double; |
1968 |
– |
LocalInt: Integer; |
1969 |
– |
LocalBool: wordBool; |
1970 |
– |
LocalInt64: Int64; |
1971 |
– |
LocalCurrency: Currency; |
2190 |
|
FieldsLoaded: Integer; |
2191 |
|
p: PRecordData; |
2192 |
|
begin |
2237 |
|
continue; |
2238 |
|
end; |
2239 |
|
if j > 0 then |
2240 |
< |
begin |
2023 |
< |
LocalData := nil; |
2024 |
< |
with p^.rdFields[j], FFieldColumns^[j] do |
2025 |
< |
begin |
2026 |
< |
Qry.Current.GetData(i,fdIsNull,fdDataLength,LocalData); |
2027 |
< |
if not fdIsNull then |
2028 |
< |
begin |
2029 |
< |
case fdDataType of {Get Formatted data for column types that need formatting} |
2030 |
< |
SQL_TIMESTAMP: |
2031 |
< |
begin |
2032 |
< |
LocalDate := TimeStampToMSecs(DateTimeToTimeStamp(Qry[i].AsDateTime)); |
2033 |
< |
LocalData := PChar(@LocalDate); |
2034 |
< |
end; |
2035 |
< |
SQL_TYPE_DATE: |
2036 |
< |
begin |
2037 |
< |
LocalInt := DateTimeToTimeStamp(Qry[i].AsDateTime).Date; |
2038 |
< |
LocalData := PChar(@LocalInt); |
2039 |
< |
end; |
2040 |
< |
SQL_TYPE_TIME: |
2041 |
< |
begin |
2042 |
< |
LocalInt := DateTimeToTimeStamp(Qry[i].AsDateTime).Time; |
2043 |
< |
LocalData := PChar(@LocalInt); |
2044 |
< |
end; |
2045 |
< |
SQL_SHORT, SQL_LONG: |
2046 |
< |
begin |
2047 |
< |
if (fdDataScale = 0) then |
2048 |
< |
begin |
2049 |
< |
LocalInt := Qry[i].AsLong; |
2050 |
< |
LocalData := PChar(@LocalInt); |
2051 |
< |
end |
2052 |
< |
else |
2053 |
< |
if (fdDataScale >= (-4)) then |
2054 |
< |
begin |
2055 |
< |
LocalCurrency := Qry[i].AsCurrency; |
2056 |
< |
LocalData := PChar(@LocalCurrency); |
2057 |
< |
end |
2058 |
< |
else |
2059 |
< |
begin |
2060 |
< |
LocalDouble := Qry[i].AsDouble; |
2061 |
< |
LocalData := PChar(@LocalDouble); |
2062 |
< |
end; |
2063 |
< |
end; |
2064 |
< |
SQL_INT64: |
2065 |
< |
begin |
2066 |
< |
if (fdDataScale = 0) then |
2067 |
< |
begin |
2068 |
< |
LocalInt64 := Qry[i].AsInt64; |
2069 |
< |
LocalData := PChar(@LocalInt64); |
2070 |
< |
end |
2071 |
< |
else |
2072 |
< |
if (fdDataScale >= (-4)) then |
2073 |
< |
begin |
2074 |
< |
LocalCurrency := Qry[i].AsCurrency; |
2075 |
< |
LocalData := PChar(@LocalCurrency); |
2076 |
< |
end |
2077 |
< |
else |
2078 |
< |
begin |
2079 |
< |
LocalDouble := Qry[i].AsDouble; |
2080 |
< |
LocalData := PChar(@LocalDouble); |
2081 |
< |
end |
2082 |
< |
end; |
2083 |
< |
SQL_DOUBLE, SQL_FLOAT, SQL_D_FLOAT: |
2084 |
< |
begin |
2085 |
< |
LocalDouble := Qry[i].AsDouble; |
2086 |
< |
LocalData := PChar(@LocalDouble); |
2087 |
< |
end; |
2088 |
< |
SQL_BOOLEAN: |
2089 |
< |
begin |
2090 |
< |
LocalBool := Qry[i].AsBoolean; |
2091 |
< |
LocalData := PChar(@LocalBool); |
2092 |
< |
end; |
2093 |
< |
end; |
2094 |
< |
|
2095 |
< |
if fdDataType = SQL_VARYING then |
2096 |
< |
Move(LocalData^, Buffer[fdDataOfs], fdDataLength) |
2097 |
< |
else |
2098 |
< |
Move(LocalData^, Buffer[fdDataOfs], fdDataSize) |
2099 |
< |
end |
2100 |
< |
else {Null column} |
2101 |
< |
if fdDataType = SQL_VARYING then |
2102 |
< |
FillChar(Buffer[fdDataOfs],fdDataLength,0) |
2103 |
< |
else |
2104 |
< |
FillChar(Buffer[fdDataOfs],fdDataSize,0); |
2105 |
< |
end; |
2106 |
< |
end; |
2240 |
> |
ColumnDataToBuffer(Qry.Current,i,j,Buffer); |
2241 |
|
end; |
2242 |
|
WriteRecordCache(RecordNumber, Buffer); |
2243 |
|
end; |
2332 |
|
FUpdateObject.Apply(ukDelete,Buff) |
2333 |
|
else |
2334 |
|
begin |
2335 |
< |
SetInternalSQLParams(FQDelete, Buff); |
2335 |
> |
SetInternalSQLParams(FQDelete.Params, Buff); |
2336 |
|
FQDelete.ExecQuery; |
2337 |
+ |
if (FQDelete.FieldCount > 0) then |
2338 |
+ |
DoDeleteReturning(FQDelete.Current); |
2339 |
|
end; |
2340 |
|
with PRecordData(Buff)^ do |
2341 |
|
begin |
2473 |
|
end; |
2474 |
|
Inc(arr); |
2475 |
|
end; |
2476 |
+ |
FBufferUpdatedOnQryReturn := false; |
2477 |
|
if Assigned(FUpdateObject) then |
2478 |
|
begin |
2479 |
|
if (Qry = FQDelete) then |
2484 |
|
FUpdateObject.Apply(ukModify,Buff); |
2485 |
|
end |
2486 |
|
else begin |
2487 |
< |
SetInternalSQLParams(Qry, Buff); |
2487 |
> |
SetInternalSQLParams(Qry.Params, Buff); |
2488 |
|
Qry.ExecQuery; |
2489 |
+ |
if Qry.FieldCount > 0 then {Has RETURNING Clause} |
2490 |
+ |
UpdateRecordFromQuery(Qry.Current,Buff); |
2491 |
|
end; |
2492 |
|
PRecordData(Buff)^.rdUpdateStatus := usUnmodified; |
2493 |
|
PRecordData(Buff)^.rdCachedUpdateStatus := cusUnmodified; |
2494 |
|
SetModified(False); |
2495 |
|
WriteRecordCache(PRecordData(Buff)^.rdRecordNumber, Buff); |
2496 |
< |
if (FForcedRefresh or FNeedsRefresh) and CanRefresh then |
2496 |
> |
if (FForcedRefresh or (FNeedsRefresh and not FBufferUpdatedOnQryReturn)) and CanRefresh then |
2497 |
|
InternalRefreshRow; |
2498 |
|
end; |
2499 |
|
|
2520 |
|
end |
2521 |
|
else |
2522 |
|
Qry := FQRefresh; |
2523 |
< |
SetInternalSQLParams(Qry, Buff); |
2523 |
> |
SetInternalSQLParams(Qry.Params, Buff); |
2524 |
|
Qry.ExecQuery; |
2525 |
|
try |
2526 |
|
if (Qry.SQLStatementType = SQLExecProcedure) or Qry.Next then |
2729 |
|
|
2730 |
|
procedure TIBCustomDataSet.SetDatabase(Value: TIBDatabase); |
2731 |
|
begin |
2732 |
< |
if (FBase.Database <> Value) then |
2732 |
> |
if (csLoading in ComponentState) or (FBase.Database <> Value) then |
2733 |
|
begin |
2734 |
|
CheckDatasetClosed; |
2735 |
+ |
InternalUnPrepare; |
2736 |
|
FBase.Database := Value; |
2737 |
|
FQDelete.Database := Value; |
2738 |
|
FQInsert.Database := Value; |
2739 |
|
FQRefresh.Database := Value; |
2740 |
|
FQSelect.Database := Value; |
2741 |
|
FQModify.Database := Value; |
2742 |
+ |
FDatabaseInfo.Database := Value; |
2743 |
+ |
FGeneratorField.Database := Value; |
2744 |
|
end; |
2745 |
|
end; |
2746 |
|
|
2762 |
|
end; |
2763 |
|
end; |
2764 |
|
|
2765 |
< |
procedure TIBCustomDataSet.SetInternalSQLParams(Qry: TIBSQL; Buffer: Pointer); |
2765 |
> |
procedure TIBCustomDataSet.SetInternalSQLParams(Params: ISQLParams; Buffer: Pointer); |
2766 |
|
var |
2767 |
|
i, j: Integer; |
2768 |
|
cr, data: PChar; |
2778 |
|
InternalPrepare; |
2779 |
|
OldBuffer := nil; |
2780 |
|
try |
2781 |
< |
for i := 0 to Qry.Params.GetCount - 1 do |
2781 |
> |
for i := 0 to Params.GetCount - 1 do |
2782 |
|
begin |
2783 |
< |
Param := Qry.Params[i]; |
2783 |
> |
Param := Params[i]; |
2784 |
|
fn := Param.Name; |
2785 |
|
if (Pos('OLD_', fn) = 1) then {mbcs ok} |
2786 |
|
begin |
2844 |
|
end; |
2845 |
|
SQL_BLOB, SQL_ARRAY, SQL_QUAD: |
2846 |
|
Param.AsQuad := PISC_QUAD(data)^; |
2847 |
< |
SQL_TYPE_DATE: |
2848 |
< |
begin |
2707 |
< |
ts.Date := PInt(data)^; |
2708 |
< |
ts.Time := 0; |
2709 |
< |
Param.AsDate := TimeStampToDateTime(ts); |
2710 |
< |
end; |
2711 |
< |
SQL_TYPE_TIME: |
2712 |
< |
begin |
2713 |
< |
ts.Date := 0; |
2714 |
< |
ts.Time := PInt(data)^; |
2715 |
< |
Param.AsTime := TimeStampToDateTime(ts); |
2716 |
< |
end; |
2847 |
> |
SQL_TYPE_DATE, |
2848 |
> |
SQL_TYPE_TIME, |
2849 |
|
SQL_TIMESTAMP: |
2850 |
< |
Param.AsDateTime := |
2851 |
< |
TimeStampToDateTime(MSecsToTimeStamp(trunc(PDouble(data)^))); |
2850 |
> |
{This is an IBX native format and not the TDataset approach. See also SetFieldData} |
2851 |
> |
Param.AsDateTime := PDateTime(data)^; |
2852 |
|
SQL_BOOLEAN: |
2853 |
|
Param.AsBoolean := PWordBool(data)^; |
2854 |
|
end; |
2899 |
|
FQRefresh.Transaction := Value; |
2900 |
|
FQSelect.Transaction := Value; |
2901 |
|
FQModify.Transaction := Value; |
2902 |
+ |
FGeneratorField.Transaction := Value; |
2903 |
|
end; |
2904 |
|
end; |
2905 |
|
|
3801 |
|
'and R.RDB$FIELD_SOURCE = F.RDB$FIELD_NAME '+ {do not localize} |
3802 |
|
'and ((not F.RDB$COMPUTED_BLR is NULL) or ' + {do not localize} |
3803 |
|
' (not F.RDB$DEFAULT_VALUE is NULL)) '; {do not localize} |
3804 |
+ |
|
3805 |
+ |
DefaultSQLODS12 = 'Select F.RDB$COMPUTED_BLR, ' + {do not localize} |
3806 |
+ |
'F.RDB$DEFAULT_VALUE, R.RDB$FIELD_NAME, R.RDB$IDENTITY_TYPE ' + {do not localize} |
3807 |
+ |
'from RDB$RELATION_FIELDS R, RDB$FIELDS F ' + {do not localize} |
3808 |
+ |
'where R.RDB$RELATION_NAME = :RELATION ' + {do not localize} |
3809 |
+ |
'and R.RDB$FIELD_SOURCE = F.RDB$FIELD_NAME '+ {do not localize} |
3810 |
+ |
'and ((not F.RDB$COMPUTED_BLR is NULL) or ' + {do not localize} |
3811 |
+ |
' (not F.RDB$DEFAULT_VALUE is NULL) or ' + {do not localize} |
3812 |
+ |
' ( not R.RDB$IDENTITY_TYPE is NULL))' ; {do not localize} |
3813 |
+ |
|
3814 |
|
var |
3815 |
|
FieldType: TFieldType; |
3816 |
|
FieldSize: Word; |
3817 |
+ |
FieldDataSize: integer; |
3818 |
|
charSetID: short; |
3819 |
|
CharSetSize: integer; |
3820 |
|
CharSetName: RawByteString; |
3851 |
|
FField.FieldName := Query.Fields[2].AsString; |
3852 |
|
FField.DEFAULT_VALUE := not Query.Fields[1].IsNull; |
3853 |
|
FField.COMPUTED_BLR := not Query.Fields[0].IsNull; |
3854 |
+ |
FField.IDENTITY_COLUMN := (Query.FieldCount > 3) and not Query.Fields[3].IsNull; |
3855 |
|
FField.NextField := Result.FieldNodes; |
3856 |
|
Result.FieldNodes := FField; |
3857 |
|
Query.Next; |
3905 |
|
FField := Ffield.NextField; |
3906 |
|
end; |
3907 |
|
|
3908 |
+ |
function Is_IDENTITY_COLUMN(Relation, Field : String) : Boolean; |
3909 |
+ |
var |
3910 |
+ |
FRelation : TRelationNode; |
3911 |
+ |
FField : TFieldNode; |
3912 |
+ |
begin |
3913 |
+ |
FRelation := FRelationNodes; |
3914 |
+ |
while Assigned(FRelation) and |
3915 |
+ |
(FRelation.RelationName <> Relation) do |
3916 |
+ |
FRelation := FRelation.NextRelation; |
3917 |
+ |
if not Assigned(FRelation) then |
3918 |
+ |
FRelation := Add_Node(Relation, Field); |
3919 |
+ |
Result := false; |
3920 |
+ |
FField := FRelation.FieldNodes; |
3921 |
+ |
while Assigned(FField) do |
3922 |
+ |
if FField.FieldName = Field then |
3923 |
+ |
begin |
3924 |
+ |
Result := Ffield.IDENTITY_COLUMN; |
3925 |
+ |
Exit; |
3926 |
+ |
end |
3927 |
+ |
else |
3928 |
+ |
FField := Ffield.NextField; |
3929 |
+ |
end; |
3930 |
+ |
|
3931 |
|
Procedure FreeNodes; |
3932 |
|
var |
3933 |
|
FRelation : TRelationNode; |
3961 |
|
FieldIndex := 0; |
3962 |
|
if (Length(FMappedFieldPosition) < SourceQuery.MetaData.Count) then |
3963 |
|
SetLength(FMappedFieldPosition, SourceQuery.MetaData.Count); |
3964 |
< |
Query.SQL.Text := DefaultSQL; |
3964 |
> |
if FDatabaseInfo.ODSMajorVersion >= 12 then |
3965 |
> |
Query.SQL.Text := DefaultSQLODS12 |
3966 |
> |
else |
3967 |
> |
Query.SQL.Text := DefaultSQL; |
3968 |
|
Query.Prepare; |
3969 |
|
SetLength(FAliasNameMap, SourceQuery.MetaData.Count); |
3970 |
|
SetLength(FAliasNameList, SourceQuery.MetaData.Count); |
3978 |
|
FieldName := getSQLName; |
3979 |
|
FAliasNameList[i] := DBAliasName; |
3980 |
|
FieldSize := 0; |
3981 |
+ |
FieldDataSize := GetSize; |
3982 |
|
FieldPrecision := 0; |
3983 |
|
FieldNullable := IsNullable; |
3984 |
|
CharSetSize := 0; |
3991 |
|
their values } |
3992 |
|
SQL_VARYING, SQL_TEXT: |
3993 |
|
begin |
3994 |
< |
FirebirdAPI.CharSetWidth(getCharSetID,CharSetSize); |
3995 |
< |
CharSetName := FirebirdAPI.GetCharsetName(getCharSetID); |
3996 |
< |
FirebirdAPI.CharSetID2CodePage(getCharSetID,FieldCodePage); |
3997 |
< |
FieldSize := GetSize div CharSetSize; |
3994 |
> |
if not Database.Attachment.CharSetWidth(getCharSetID,CharSetSize) then |
3995 |
> |
CharSetSize := 1; |
3996 |
> |
CharSetName := Database.Attachment.GetCharsetName(getCharSetID); |
3997 |
> |
Database.Attachment.CharSetID2CodePage(getCharSetID,FieldCodePage); |
3998 |
> |
FieldSize := FieldDataSize div CharSetSize; |
3999 |
|
FieldType := ftString; |
4000 |
|
end; |
4001 |
|
{ All Doubles/Floats should be cast to doubles } |
4046 |
|
FieldSize := -getScale; |
4047 |
|
end |
4048 |
|
else |
4049 |
< |
FieldType := ftFloat |
4049 |
> |
FieldType := ftFloat; |
4050 |
|
end; |
4051 |
|
SQL_TIMESTAMP: FieldType := ftDateTime; |
4052 |
|
SQL_TYPE_TIME: FieldType := ftTime; |
4056 |
|
FieldSize := sizeof (TISC_QUAD); |
4057 |
|
if (getSubtype = 1) then |
4058 |
|
begin |
4059 |
< |
FirebirdAPI.CharSetWidth(getCharSetID,CharSetSize); |
4060 |
< |
CharSetName := FirebirdAPI.GetCharsetName(getCharSetID); |
4061 |
< |
FirebirdAPI.CharSetID2CodePage(getCharSetID,FieldCodePage); |
4059 |
> |
if not Database.Attachment.CharSetWidth(getCharSetID,CharSetSize) then |
4060 |
> |
CharSetSize := 1; |
4061 |
> |
CharSetName := Database.Attachment.GetCharsetName(getCharSetID); |
4062 |
> |
Database.Attachment.CharSetID2CodePage(getCharSetID,FieldCodePage); |
4063 |
|
FieldType := ftMemo; |
4064 |
|
end |
4065 |
|
else |
4091 |
|
Name := FieldAliasName; |
4092 |
|
FAliasNameMap[FieldNo-1] := DBAliasName; |
4093 |
|
Size := FieldSize; |
4094 |
+ |
DataSize := FieldDataSize; |
4095 |
|
Precision := FieldPrecision; |
4096 |
|
Required := not FieldNullable; |
4097 |
|
RelationName := aRelationName; |
4103 |
|
ArrayBounds := aArrayBounds; |
4104 |
|
if (FieldName <> '') and (RelationName <> '') then |
4105 |
|
begin |
4106 |
+ |
IdentityColumn := Is_IDENTITY_COLUMN(RelationName, FieldName); |
4107 |
|
if Has_COMPUTED_BLR(RelationName, FieldName) then |
4108 |
|
begin |
4109 |
|
Attributes := [faReadOnly]; |
4175 |
|
for i := 0 to SQLParams.GetCount - 1 do |
4176 |
|
begin |
4177 |
|
cur_field := DataSource.DataSet.FindField(SQLParams[i].Name); |
4178 |
< |
cur_param := SQLParams[i]; |
4179 |
< |
if (cur_field <> nil) then begin |
4178 |
> |
if (cur_field <> nil) then |
4179 |
> |
begin |
4180 |
> |
cur_param := SQLParams[i]; |
4181 |
|
if (cur_field.IsNull) then |
4182 |
|
cur_param.IsNull := True |
4183 |
< |
else case cur_field.DataType of |
4183 |
> |
else |
4184 |
> |
case cur_field.DataType of |
4185 |
|
ftString: |
4186 |
|
cur_param.AsString := cur_field.AsString; |
4187 |
|
ftBoolean: |
4191 |
|
ftInteger: |
4192 |
|
cur_param.AsLong := cur_field.AsInteger; |
4193 |
|
ftLargeInt: |
4194 |
< |
cur_param.AsInt64 := TLargeIntField(cur_field).AsLargeInt; |
4194 |
> |
cur_param.AsInt64 := cur_field.AsLargeInt; |
4195 |
|
ftFloat, ftCurrency: |
4196 |
|
cur_param.AsDouble := cur_field.AsFloat; |
4197 |
|
ftBCD: |
4850 |
|
Transaction.StartTransaction; |
4851 |
|
end; |
4852 |
|
|
4853 |
< |
function TIBCustomDataSet.PSGetTableName: string; |
4853 |
> |
function TIBCustomDataSet.PsGetTableName: string; |
4854 |
|
begin |
4855 |
|
// if not FInternalPrepared then |
4856 |
|
// InternalPrepare; |
4945 |
|
function TIBCustomDataSet.GetFieldData(Field: TField; Buffer: Pointer; |
4946 |
|
NativeFormat: Boolean): Boolean; |
4947 |
|
begin |
4948 |
< |
if (Field.DataType = ftBCD) and not NativeFormat then |
4948 |
> |
{These datatypes use IBX conventions and not TDataset conventions} |
4949 |
> |
if (Field.DataType in [ftBCD,ftDateTime,ftDate,ftTime]) and not NativeFormat then |
4950 |
|
Result := InternalGetFieldData(Field, Buffer) |
4951 |
|
else |
4952 |
|
Result := inherited GetFieldData(Field, Buffer, NativeFormat); |
4972 |
|
procedure TIBCustomDataSet.SetFieldData(Field: TField; Buffer: Pointer; |
4973 |
|
NativeFormat: Boolean); |
4974 |
|
begin |
4975 |
< |
if (not NativeFormat) and (Field.DataType = ftBCD) then |
4975 |
> |
{These datatypes use IBX conventions and not TDataset conventions} |
4976 |
> |
if (not NativeFormat) and (Field.DataType in [ftBCD,ftDateTime,ftDate,ftTime]) then |
4977 |
|
InternalSetfieldData(Field, Buffer) |
4978 |
|
else |
4979 |
|
inherited SetFieldData(Field, buffer, NativeFormat); |
4993 |
|
inherited Destroy; |
4994 |
|
end; |
4995 |
|
|
4996 |
< |
procedure TIBDataSetUpdateObject.SetRefreshSQL(Value: TStrings); |
4996 |
> |
procedure TIBDataSetUpdateObject.SetRefreshSQL(value: TStrings); |
4997 |
|
begin |
4998 |
|
FRefreshSQL.Assign(Value); |
4999 |
|
end; |
5000 |
|
|
5001 |
+ |
procedure TIBDataSetUpdateObject.InternalSetParams(Params: ISQLParams; |
5002 |
+ |
buff: PChar); |
5003 |
+ |
begin |
5004 |
+ |
if not Assigned(DataSet) then Exit; |
5005 |
+ |
DataSet.SetInternalSQLParams(Params, buff); |
5006 |
+ |
end; |
5007 |
+ |
|
5008 |
|
procedure TIBDataSetUpdateObject.InternalSetParams(Query: TIBSQL; buff: PChar); |
5009 |
|
begin |
5010 |
+ |
InternalSetParams(Query.Params,buff); |
5011 |
+ |
end; |
5012 |
+ |
|
5013 |
+ |
procedure TIBDataSetUpdateObject.UpdateRecordFromQuery(UpdateKind: TUpdateKind; |
5014 |
+ |
QryResults: IResults; Buffer: PChar); |
5015 |
+ |
begin |
5016 |
|
if not Assigned(DataSet) then Exit; |
5017 |
< |
DataSet.SetInternalSQLParams(Query, buff); |
5017 |
> |
case UpdateKind of |
5018 |
> |
ukModify, ukInsert: |
5019 |
> |
DataSet.UpdateRecordFromQuery(QryResults, Buffer); |
5020 |
> |
ukDelete: |
5021 |
> |
DataSet.DoDeleteReturning(QryResults); |
5022 |
> |
end; |
5023 |
|
end; |
5024 |
|
|
5025 |
|
function TIBDSBlobStream.GetSize: Int64; |
5082 |
|
|
5083 |
|
procedure TIBGenerator.SetIncrement(const AValue: integer); |
5084 |
|
begin |
5085 |
+ |
if FIncrement = AValue then Exit; |
5086 |
|
if AValue < 0 then |
5087 |
< |
raise Exception.Create('A Generator Increment cannot be negative'); |
5088 |
< |
FIncrement := AValue |
5087 |
> |
IBError(ibxeNegativeGenerator,[]); |
5088 |
> |
FIncrement := AValue; |
5089 |
> |
SetQuerySQL; |
5090 |
|
end; |
5091 |
|
|
5092 |
< |
function TIBGenerator.GetNextValue(ADatabase: TIBDatabase; |
4893 |
< |
ATransaction: TIBTransaction): integer; |
5092 |
> |
procedure TIBGenerator.SetTransaction(AValue: TIBTransaction); |
5093 |
|
begin |
5094 |
< |
with TIBSQL.Create(nil) do |
5095 |
< |
try |
5096 |
< |
Database := ADatabase; |
5097 |
< |
Transaction := ATransaction; |
5098 |
< |
if not assigned(Database) then |
5099 |
< |
IBError(ibxeCannotSetDatabase,[]); |
5100 |
< |
if not assigned(Transaction) then |
5101 |
< |
IBError(ibxeCannotSetTransaction,[]); |
5102 |
< |
with Transaction do |
5103 |
< |
if not InTransaction then StartTransaction; |
5104 |
< |
SQL.Text := Format('Select Gen_ID(%s,%d) as ID From RDB$Database',[FGeneratorName,Increment]); |
5105 |
< |
Prepare; |
5094 |
> |
FQuery.Transaction := AValue; |
5095 |
> |
end; |
5096 |
> |
|
5097 |
> |
procedure TIBGenerator.SetQuerySQL; |
5098 |
> |
begin |
5099 |
> |
FQuery.SQL.Text := Format('Select Gen_ID(%s,%d) From RDB$Database',[FGeneratorName,Increment]); |
5100 |
> |
end; |
5101 |
> |
|
5102 |
> |
function TIBGenerator.GetDatabase: TIBDatabase; |
5103 |
> |
begin |
5104 |
> |
Result := FQuery.Database; |
5105 |
> |
end; |
5106 |
> |
|
5107 |
> |
function TIBGenerator.GetTransaction: TIBTransaction; |
5108 |
> |
begin |
5109 |
> |
Result := FQuery.Transaction; |
5110 |
> |
end; |
5111 |
> |
|
5112 |
> |
procedure TIBGenerator.SetDatabase(AValue: TIBDatabase); |
5113 |
> |
begin |
5114 |
> |
FQuery.Database := AValue; |
5115 |
> |
end; |
5116 |
> |
|
5117 |
> |
procedure TIBGenerator.SetGeneratorName(AValue: string); |
5118 |
> |
begin |
5119 |
> |
if FGeneratorName = AValue then Exit; |
5120 |
> |
FGeneratorName := AValue; |
5121 |
> |
SetQuerySQL; |
5122 |
> |
end; |
5123 |
> |
|
5124 |
> |
function TIBGenerator.GetNextValue: integer; |
5125 |
> |
begin |
5126 |
> |
with FQuery do |
5127 |
> |
begin |
5128 |
> |
Transaction.Active := true; |
5129 |
|
ExecQuery; |
5130 |
|
try |
5131 |
< |
Result := FieldByName('ID').AsInteger |
5131 |
> |
Result := Fields[0].AsInteger |
5132 |
|
finally |
5133 |
|
Close |
5134 |
|
end; |
4913 |
– |
finally |
4914 |
– |
Free |
5135 |
|
end; |
5136 |
|
end; |
5137 |
|
|
5139 |
|
begin |
5140 |
|
FOwner := Owner; |
5141 |
|
FIncrement := 1; |
5142 |
+ |
FQuery := TIBSQL.Create(nil); |
5143 |
+ |
end; |
5144 |
+ |
|
5145 |
+ |
destructor TIBGenerator.Destroy; |
5146 |
+ |
begin |
5147 |
+ |
if assigned(FQuery) then FQuery.Free; |
5148 |
+ |
inherited Destroy; |
5149 |
|
end; |
5150 |
|
|
5151 |
|
|
5152 |
|
procedure TIBGenerator.Apply; |
5153 |
|
begin |
5154 |
< |
if (FGeneratorName <> '') and (FFieldName <> '') and Owner.FieldByName(FFieldName).IsNull then |
5155 |
< |
Owner.FieldByName(FFieldName).AsInteger := GetNextValue(Owner.Database,Owner.Transaction); |
5154 |
> |
if assigned(Database) and assigned(Transaction) and |
5155 |
> |
(FGeneratorName <> '') and (FFieldName <> '') and Owner.FieldByName(FFieldName).IsNull then |
5156 |
> |
Owner.FieldByName(FFieldName).AsInteger := GetNextValue; |
5157 |
|
end; |
5158 |
|
|
5159 |
|
|