49 |
|
uses |
50 |
|
{$IFDEF WINDOWS } |
51 |
|
Windows, |
52 |
< |
{$ELSE} |
52 |
> |
{$ENDIF} |
53 |
> |
{$IFDEF UNIX} |
54 |
|
unix, |
55 |
|
{$ENDIF} |
56 |
< |
SysUtils, Classes, IBDatabase, IBExternals, IB, IBSQL, Db, |
57 |
< |
IBUtils, IBBlob, IBSQLParser, IBDatabaseInfo, fpTimer; |
57 |
< |
|
58 |
< |
const |
59 |
< |
BufferCacheSize = 1000; { Allocate cache in this many record chunks} |
60 |
< |
UniCache = 2; { Uni-directional cache is 2 records big } |
56 |
> |
SysUtils, Classes, IBDatabase, IBExternals, IBInternals, IB, IBSQL, Db, |
57 |
> |
IBUtils, IBBlob, IBSQLParser, IBDatabaseInfo; |
58 |
|
|
59 |
|
type |
60 |
|
TIBCustomDataSet = class; |
84 |
|
property RefreshSQL: TStrings read FRefreshSQL write SetRefreshSQL; |
85 |
|
end; |
86 |
|
|
90 |
– |
TBlobDataArray = array[0..0] of TIBBlobStream; |
91 |
– |
PBlobDataArray = ^TBlobDataArray; |
87 |
|
TIBArrayField = class; |
88 |
|
|
89 |
|
{ TIBArray } |
90 |
|
|
91 |
< |
{Wrapper class to support array cache in TIBCustomDataset and event handling} |
91 |
> |
{Wrapper class to support array cache in TIBCustomDataSet and event handling} |
92 |
|
|
93 |
|
TIBArray = class |
94 |
|
private |
102 |
|
property ArrayIntf: IArray read FArray; |
103 |
|
end; |
104 |
|
|
110 |
– |
TArrayDataArray = array [0..0] of TIBArray; |
111 |
– |
PArrayDataArray = ^TArrayDataArray; |
112 |
– |
|
113 |
– |
{ TIBCustomDataSet } |
114 |
– |
|
115 |
– |
TCachedUpdateStatus = ( |
116 |
– |
cusUnmodified, cusModified, cusInserted, |
117 |
– |
cusDeleted, cusUninserted |
118 |
– |
); |
119 |
– |
TIBDBKey = record |
120 |
– |
DBKey: array[0..7] of Byte; |
121 |
– |
end; |
122 |
– |
PIBDBKey = ^TIBDBKey; |
123 |
– |
|
124 |
– |
PFieldData = ^TFieldData; |
125 |
– |
TFieldData = record |
126 |
– |
fdIsNull: Boolean; |
127 |
– |
fdDataLength: Short; |
128 |
– |
end; |
129 |
– |
|
130 |
– |
PColumnData = ^TColumnData; |
131 |
– |
TColumnData = record |
132 |
– |
fdDataType: Short; |
133 |
– |
fdDataScale: Short; |
134 |
– |
fdNullable: Boolean; |
135 |
– |
fdDataSize: Short; |
136 |
– |
fdDataOfs: Integer; |
137 |
– |
fdCodePage: TSystemCodePage; |
138 |
– |
end; |
139 |
– |
|
140 |
– |
PFieldColumns = ^TFieldColumns; |
141 |
– |
TFieldColumns = array[1..1] of TColumnData; |
142 |
– |
|
143 |
– |
TRecordData = record |
144 |
– |
rdBookmarkFlag: TBookmarkFlag; |
145 |
– |
rdFieldCount: Short; |
146 |
– |
rdRecordNumber: Integer; |
147 |
– |
rdCachedUpdateStatus: TCachedUpdateStatus; |
148 |
– |
rdUpdateStatus: TUpdateStatus; |
149 |
– |
rdSavedOffset: DWORD; |
150 |
– |
rdDBKey: TIBDBKey; |
151 |
– |
rdFields: array[1..1] of TFieldData; |
152 |
– |
end; |
153 |
– |
PRecordData = ^TRecordData; |
154 |
– |
|
105 |
|
{ TIBArrayField } |
106 |
|
|
107 |
|
TIBArrayField = class(TField) |
243 |
|
property CodePage: TSystemCodePage read FFCodePage write FFCodePage; |
244 |
|
end; |
245 |
|
|
246 |
+ |
PIBBufferedDateTimeWithTimeZone = ^TIBBufferedDateTimeWithTimeZone; |
247 |
+ |
TIBBufferedDateTimeWithTimeZone = packed record |
248 |
+ |
Timestamp: TDateTime; |
249 |
+ |
dstOffset: smallint; |
250 |
+ |
TimeZoneID: ISC_USHORT; |
251 |
+ |
end; |
252 |
+ |
|
253 |
+ |
{ TIBDateTimeField } |
254 |
+ |
|
255 |
+ |
{It seems wrong to make this a subclass of TTimeField and not TDateTimField. |
256 |
+ |
However, the rationale is backwards compatibility for applications that |
257 |
+ |
may want to coerce a TField to a TTimeField. If this is to work then |
258 |
+ |
TIBTimeField has to descend from TTimeField. Hence the declation. As |
259 |
+ |
TTimeField also descends from TDateTimeField this should not result in any |
260 |
+ |
problems - unless someone makes a drastic change to TTimeField.} |
261 |
+ |
|
262 |
+ |
TIBDateTimeField = class(TTimeField) |
263 |
+ |
private |
264 |
+ |
FHasTimeZone: boolean; |
265 |
+ |
FTimeZoneServices: ITimeZoneServices; |
266 |
+ |
function GetTimeZoneServices: ITimeZoneServices; |
267 |
+ |
function GetDateTimeBuffer(var aBuffer: TIBBufferedDateTimeWithTimeZone): boolean; |
268 |
+ |
function GetTimeZoneID: TFBTimeZoneID; |
269 |
+ |
function GetTimeZoneName: string; |
270 |
+ |
procedure SetTimeZoneID(aValue: TFBTimeZoneID); |
271 |
+ |
procedure SetTimeZoneName(AValue: string); |
272 |
+ |
protected |
273 |
+ |
procedure Bind(Binding: Boolean); override; |
274 |
+ |
function GetAsDateTime: TDateTime; override; |
275 |
+ |
function GetAsVariant: variant; override; |
276 |
+ |
function GetDataSize: Integer; override; |
277 |
+ |
procedure GetText(var theText: string; ADisplayText: Boolean); override; |
278 |
+ |
procedure SetAsDateTime(AValue: TDateTime); override; |
279 |
+ |
procedure SetAsString(const AValue: string); override; |
280 |
+ |
procedure SetVarValue(const AValue: Variant); override; |
281 |
+ |
public |
282 |
+ |
constructor Create(AOwner: TComponent); override; |
283 |
+ |
function GetAsDateTimeTZ(var aDateTime: TDateTime; var dstOffset: smallint; |
284 |
+ |
var aTimeZoneID: TFBTimeZoneID): boolean; overload; |
285 |
+ |
function GetAsDateTimeTZ(var aDateTime: TDateTime; var dstOffset: smallint; |
286 |
+ |
var aTimeZone: string): boolean; overload; |
287 |
+ |
function GetAsUTCDateTime: TDateTime; |
288 |
+ |
procedure SetAsDateTimeTZ(aDateTime: TDateTime; aTimeZoneID: TFBTimeZoneID); overload; |
289 |
+ |
procedure SetAsDateTimeTZ(aDateTime: TDateTime; aTimeZone: string); overload; |
290 |
+ |
property TimeZoneName: string read GetTimeZoneName write SetTimeZoneName; |
291 |
+ |
property TimeZoneID: TFBTimeZoneID read GetTimeZoneID; |
292 |
+ |
published |
293 |
+ |
property HasTimeZone: boolean read FHasTimeZone; |
294 |
+ |
end; |
295 |
+ |
|
296 |
+ |
{ TIBTimeField } |
297 |
+ |
|
298 |
+ |
TIBTimeField = class(TIBDateTimeField) |
299 |
+ |
public |
300 |
+ |
constructor Create(AOwner: TComponent); override; |
301 |
+ |
end; |
302 |
+ |
|
303 |
|
{ TIBDataLink } |
304 |
|
|
305 |
|
TIBDataLink = class(TDetailDataLink) |
306 |
|
private |
307 |
|
FDataSet: TIBCustomDataSet; |
308 |
|
FDelayTimerValue: integer; |
309 |
< |
FTimer: TFPTimer; |
309 |
> |
FTimer: IIBTimerInf; |
310 |
|
procedure HandleRefreshTimer(Sender: TObject); |
311 |
+ |
procedure SetDelayTimerValue(AValue: integer); |
312 |
|
protected |
313 |
|
procedure ActiveChanged; override; |
314 |
|
procedure RecordChanged(Field: TField); override; |
318 |
|
constructor Create(ADataSet: TIBCustomDataSet); |
319 |
|
destructor Destroy; override; |
320 |
|
property DelayTimerValue: integer {in Milliseconds} |
321 |
< |
read FDelayTimerValue write FDelayTimerValue; |
321 |
> |
read FDelayTimerValue write SetDelayTimerValue; |
322 |
|
end; |
323 |
|
|
324 |
|
TIBGeneratorApplyOnEvent = (gaeOnNewRecord,gaeOnPostRecord); |
372 |
|
|
373 |
|
TIBAutoCommit = (acDisabled, acCommitRetaining); |
374 |
|
|
367 |
– |
{ TIBCustomDataSet } |
368 |
– |
|
375 |
|
TIBUpdateAction = (uaFail, uaAbort, uaSkip, uaRetry, uaApply, uaApplied); |
376 |
|
|
377 |
|
TIBUpdateErrorEvent = procedure(DataSet: TDataSet; E: EDatabaseError; |
380 |
|
TIBUpdateRecordEvent = procedure(DataSet: TDataSet; UpdateKind: TUpdateKind; |
381 |
|
var UpdateAction: TIBUpdateAction) of object; |
382 |
|
|
377 |
– |
TIBUpdateRecordTypes = set of TCachedUpdateStatus; |
378 |
– |
|
383 |
|
TDataSetCloseAction = (dcDiscardChanges, dcSaveChanges); |
384 |
|
|
385 |
|
TOnValidatePost = procedure (Sender: TObject; var CancelPost: boolean) of object; |
386 |
|
|
387 |
|
TOnDeleteReturning = procedure (Sender: TObject; QryResults: IResults) of object; |
388 |
|
|
389 |
+ |
{ TIBCustomDataSet } |
390 |
+ |
|
391 |
|
TIBCustomDataSet = class(TDataset) |
392 |
|
private |
393 |
+ |
const |
394 |
+ |
BufferCacheSize = 1000; { Allocate cache in this many record chunks} |
395 |
+ |
UniCache = 2; { Uni-directional cache is 2 records big } |
396 |
+ |
|
397 |
+ |
{Buffer cache constants for record selection} |
398 |
+ |
FILE_BEGIN = 0; |
399 |
+ |
FILE_CURRENT = 1; |
400 |
+ |
FILE_END = 2; |
401 |
+ |
|
402 |
+ |
{internal type declarations} |
403 |
+ |
type |
404 |
+ |
TArrayDataArray = array [0..0] of TIBArray; |
405 |
+ |
PArrayDataArray = ^TArrayDataArray; |
406 |
+ |
|
407 |
+ |
TBlobDataArray = array[0..0] of TIBBlobStream; |
408 |
+ |
PBlobDataArray = ^TBlobDataArray; |
409 |
+ |
|
410 |
+ |
TCachedUpdateStatus = ( |
411 |
+ |
cusUnmodified, cusModified, cusInserted, |
412 |
+ |
cusDeleted, cusUninserted |
413 |
+ |
); |
414 |
+ |
TIBUpdateRecordTypes = set of TCachedUpdateStatus; |
415 |
+ |
|
416 |
+ |
PFieldData = ^TFieldData; |
417 |
+ |
TFieldData = record |
418 |
+ |
fdIsNull: Boolean; |
419 |
+ |
fdDataLength: Short; |
420 |
+ |
end; |
421 |
+ |
|
422 |
+ |
PColumnData = ^TColumnData; |
423 |
+ |
TColumnData = record |
424 |
+ |
fdDataType: Short; |
425 |
+ |
fdDataScale: Short; |
426 |
+ |
fdNullable: Boolean; |
427 |
+ |
fdDataSize: Short; |
428 |
+ |
fdDataOfs: Integer; |
429 |
+ |
fdCodePage: TSystemCodePage; |
430 |
+ |
end; |
431 |
+ |
|
432 |
+ |
PFieldColumns = ^TFieldColumns; |
433 |
+ |
TFieldColumns = array[1..1] of TColumnData; |
434 |
+ |
|
435 |
+ |
protected |
436 |
+ |
type |
437 |
+ |
TIBDBKey = record |
438 |
+ |
DBKey: array[0..7] of Byte; |
439 |
+ |
end; |
440 |
+ |
PIBDBKey = ^TIBDBKey; |
441 |
+ |
|
442 |
+ |
TRecordData = record |
443 |
+ |
rdBookmarkFlag: TBookmarkFlag; |
444 |
+ |
rdFieldCount: Short; |
445 |
+ |
rdRecordNumber: Integer; |
446 |
+ |
rdCachedUpdateStatus: TCachedUpdateStatus; |
447 |
+ |
rdUpdateStatus: TUpdateStatus; |
448 |
+ |
rdSavedOffset: DWORD; |
449 |
+ |
rdDBKey: TIBDBKey; |
450 |
+ |
rdFields: array[1..1] of TFieldData; |
451 |
+ |
end; |
452 |
+ |
PRecordData = ^TRecordData; |
453 |
+ |
|
454 |
+ |
private |
455 |
|
FAllowAutoActivateTransaction: Boolean; |
456 |
|
FArrayFieldCount: integer; |
457 |
|
FArrayCacheOffset: integer; |
458 |
|
FAutoCommit: TIBAutoCommit; |
459 |
+ |
FCaseSensitiveParameterNames: boolean; |
460 |
+ |
FDefaultTZDate: TDateTime; |
461 |
|
FEnableStatistics: boolean; |
462 |
|
FGenerateParamNames: Boolean; |
463 |
|
FGeneratorField: TIBGenerator; |
499 |
|
FRecordCount: Integer; |
500 |
|
FRecordSize: Integer; |
501 |
|
FDataSetCloseAction: TDataSetCloseAction; |
502 |
+ |
FTZTextOption: TTZTextOptions; |
503 |
+ |
FSQLFiltered: boolean; |
504 |
+ |
FSQLFilterParams: TStrings; |
505 |
|
FUniDirectional: Boolean; |
506 |
|
FUpdateMode: TUpdateMode; |
507 |
|
FUpdateObject: TIBDataSetUpdateObject; |
536 |
|
FieldIndex: integer; Buffer: PChar); |
537 |
|
procedure InitModelBuffer(Qry: TIBSQL; Buffer: PChar); |
538 |
|
function GetSelectStmtIntf: IStatement; |
539 |
+ |
procedure SetCaseSensitiveParameterNames(AValue: boolean); |
540 |
+ |
procedure SetDefaultTZDate(AValue: TDateTime); |
541 |
+ |
procedure SetSQLFiltered(AValue: boolean); |
542 |
+ |
procedure SetSQLFilterParams(AValue: TStrings); |
543 |
|
procedure SetUpdateMode(const Value: TUpdateMode); |
544 |
|
procedure SetUpdateObject(Value: TIBDataSetUpdateObject); |
545 |
|
|
573 |
|
function GetModifySQL: TStrings; |
574 |
|
function GetTransaction: TIBTransaction; |
575 |
|
function GetParser: TSelectSQLParser; |
576 |
+ |
procedure HandleSQLFilterParamsChanged(Sender: TObject); |
577 |
|
procedure InternalDeleteRecord(Qry: TIBSQL; Buff: Pointer); virtual; |
578 |
|
function InternalLocate(const KeyFields: string; const KeyValues: Variant; |
579 |
|
Options: TLocateOptions): Boolean; virtual; |
658 |
|
procedure DoBeforeInsert; override; |
659 |
|
procedure DoAfterInsert; override; |
660 |
|
procedure DoBeforeClose; override; |
583 |
– |
procedure DoBeforeOpen; override; |
661 |
|
procedure DoBeforePost; override; |
662 |
|
procedure DoAfterPost; override; |
663 |
|
procedure FreeRecordBuffer(var Buffer: PChar); override; |
693 |
|
function IsCursorOpen: Boolean; override; |
694 |
|
procedure Loaded; override; |
695 |
|
procedure ReQuery; |
696 |
+ |
procedure ResetBufferCache; |
697 |
|
procedure SetBookmarkFlag(Buffer: PChar; Value: TBookmarkFlag); override; |
698 |
|
procedure SetBookmarkData(Buffer: PChar; Data: Pointer); override; |
699 |
|
procedure SetCachedUpdates(Value: Boolean); |
717 |
|
property QModify: TIBSQL read FQModify; |
718 |
|
property StatementType: TIBSQLStatementTypes read GetStatementType; |
719 |
|
property SelectStmtHandle: IStatement read GetSelectStmtIntf; |
720 |
+ |
property Parser: TSelectSQLParser read GetParser; |
721 |
+ |
property BaseSQLSelect: TStrings read FBaseSQLSelect; |
722 |
|
|
723 |
|
{Likely to be made published by descendant classes} |
724 |
+ |
property CaseSensitiveParameterNames: boolean read FCaseSensitiveParameterNames |
725 |
+ |
write SetCaseSensitiveParameterNames; |
726 |
|
property BufferChunks: Integer read FBufferChunks write SetBufferChunks; |
727 |
|
property CachedUpdates: Boolean read FCachedUpdates write SetCachedUpdates; |
728 |
|
property UniDirectional: Boolean read FUniDirectional write SetUniDirectional default False; |
734 |
|
property ModifySQL: TStrings read GetModifySQL write SetModifySQL; |
735 |
|
property UpdateMode: TUpdateMode read FUpdateMode write SetUpdateMode default upWhereAll; |
736 |
|
property ParamCheck: Boolean read FParamCheck write FParamCheck default True; |
737 |
< |
property Parser: TSelectSQLParser read GetParser; |
738 |
< |
property BaseSQLSelect: TStrings read FBaseSQLSelect; |
737 |
> |
property TZTextOption: TTZTextOptions read FTZTextOption write FTZTextOption; |
738 |
> |
property SQLFiltered: boolean read FSQLFiltered write SetSQLFiltered; |
739 |
> |
property SQLFilterParams: TStrings read FSQLFilterParams write SetSQLFilterParams; |
740 |
|
|
741 |
|
property BeforeDatabaseDisconnect: TNotifyEvent read FBeforeDatabaseDisconnect |
742 |
|
write FBeforeDatabaseDisconnect; |
788 |
|
function IsSequenced: Boolean; override; |
789 |
|
procedure Post; override; |
790 |
|
function ParamByName(ParamName: String): ISQLParam; |
791 |
+ |
function FindParam(ParamName: String): ISQLParam; |
792 |
|
property ArrayFieldCount: integer read FArrayFieldCount; |
793 |
|
property DatabaseInfo: TIBDatabaseInfo read FDatabaseInfo; |
794 |
|
property UpdateObject: TIBDataSetUpdateObject read FUpdateObject write SetUpdateObject; |
798 |
|
property MasterDetailDelay: integer read GetMasterDetailDelay write SetMasterDetailDelay; |
799 |
|
property DataSetCloseAction: TDataSetCloseAction |
800 |
|
read FDataSetCloseAction write FDataSetCloseAction; |
801 |
+ |
property DefaultTZDate: TDateTime read FDefaultTZDate write SetDefaultTZDate; |
802 |
|
|
803 |
|
public |
804 |
|
{Performance Statistics} |
847 |
|
write FOnDeleteReturning; |
848 |
|
end; |
849 |
|
|
850 |
+ |
{ TIBParserDataSet } |
851 |
+ |
|
852 |
|
TIBParserDataSet = class(TIBCustomDataSet) |
853 |
+ |
protected |
854 |
+ |
procedure DoBeforeOpen; override; |
855 |
|
public |
856 |
|
property Parser; |
857 |
|
end; |
888 |
|
property AutoCommit; |
889 |
|
property BufferChunks; |
890 |
|
property CachedUpdates; |
891 |
+ |
property CaseSensitiveParameterNames; |
892 |
|
property EnableStatistics; |
893 |
|
property DeleteSQL; |
894 |
|
property InsertSQL; |
902 |
|
property UniDirectional; |
903 |
|
property Filtered; |
904 |
|
property DataSetCloseAction; |
905 |
+ |
property TZTextOption; |
906 |
+ |
property DefaultTZDate; |
907 |
+ |
property SQLFiltered; |
908 |
+ |
property SQLFilterParams; |
909 |
|
|
910 |
|
property BeforeDatabaseDisconnect; |
911 |
|
property AfterDatabaseDisconnect; |
974 |
|
FCharacterSetName: RawByteString; |
975 |
|
FCharacterSetSize: integer; |
976 |
|
FCodePage: TSystemCodePage; |
977 |
+ |
FHasTimeZone: boolean; |
978 |
|
FIdentityColumn: boolean; |
979 |
|
FRelationName: string; |
980 |
|
FDataSize: integer; |
987 |
|
property ArrayDimensions: integer read FArrayDimensions write FArrayDimensions; |
988 |
|
property ArrayBounds: TArrayBounds read FArrayBounds write FArrayBounds; |
989 |
|
property IdentityColumn: boolean read FIdentityColumn write FIdentityColumn default false; |
990 |
+ |
property HasTimeZone: boolean read FHasTimeZone write FHasTimeZone default false; |
991 |
|
end; |
992 |
|
|
993 |
|
const |
994 |
< |
DefaultFieldClasses: array[TFieldType] of TFieldClass = ( |
994 |
> |
DefaultFieldClasses: array[TFieldType] of TFieldClass = ( |
995 |
|
nil, { ftUnknown } |
996 |
|
TIBStringField, { ftString } |
997 |
|
TIBSmallintField, { ftSmallint } |
998 |
< |
TIBIntegerField, { ftInteger } |
998 |
> |
TIBIntegerField, { ftInteger } |
999 |
|
TWordField, { ftWord } |
1000 |
|
TBooleanField, { ftBoolean } |
1001 |
|
TFloatField, { ftFloat } |
1002 |
|
TCurrencyField, { ftCurrency } |
1003 |
|
TIBBCDField, { ftBCD } |
1004 |
|
TDateField, { ftDate } |
1005 |
< |
TTimeField, { ftTime } |
1006 |
< |
TDateTimeField, { ftDateTime } |
1005 |
> |
TIBTimeField, { ftTime } |
1006 |
> |
TIBDateTimeField, { ftDateTime } |
1007 |
|
TBytesField, { ftBytes } |
1008 |
|
TVarBytesField, { ftVarBytes } |
1009 |
|
TAutoIncField, { ftAutoInc } |
1016 |
|
TBlobField, { ftTypedBinary } |
1017 |
|
nil, { ftCursor } |
1018 |
|
TStringField, { ftFixedChar } |
1019 |
< |
nil, { ftWideString } |
1020 |
< |
TIBLargeIntField, { ftLargeInt } |
1021 |
< |
nil, { ftADT } |
1022 |
< |
TIBArrayField, { ftArray } |
1023 |
< |
nil, { ftReference } |
1024 |
< |
nil, { ftDataSet } |
1019 |
> |
nil, { ftWideString } |
1020 |
> |
TIBLargeIntField, { ftLargeInt } |
1021 |
> |
nil, { ftADT } |
1022 |
> |
TIBArrayField, { ftArray } |
1023 |
> |
nil, { ftReference } |
1024 |
> |
nil, { ftDataSet } |
1025 |
|
TBlobField, { ftOraBlob } |
1026 |
|
TMemoField, { ftOraClob } |
1027 |
|
TVariantField, { ftVariant } |
1028 |
< |
nil, { ftInterface } |
1029 |
< |
nil, { ftIDispatch } |
1030 |
< |
TGuidField, { ftGuid } |
1031 |
< |
TDateTimeField, {ftTimestamp} |
1032 |
< |
TIBBCDField, {ftFMTBcd} |
1033 |
< |
nil, {ftFixedWideChar} |
1034 |
< |
nil); {ftWideMemo} |
1035 |
< |
(* |
1036 |
< |
TADTField, { ftADT } |
1037 |
< |
TArrayField, { ftArray } |
1038 |
< |
TReferenceField, { ftReference } |
1039 |
< |
TDataSetField, { ftDataSet } |
1040 |
< |
TBlobField, { ftOraBlob } |
1041 |
< |
TMemoField, { ftOraClob } |
1042 |
< |
TVariantField, { ftVariant } |
1043 |
< |
TInterfaceField, { ftInterface } |
1044 |
< |
TIDispatchField, { ftIDispatch } |
1045 |
< |
TGuidField); { ftGuid } *) |
1028 |
> |
nil, { ftInterface } |
1029 |
> |
nil, { ftIDispatch } |
1030 |
> |
TGuidField, { ftGuid } |
1031 |
> |
TIBDateTimeField, { ftTimestamp } |
1032 |
> |
TFmtBCDField, { ftFMTBcd } |
1033 |
> |
nil, { ftFixedWideChar } |
1034 |
> |
nil { ftWideMemo } |
1035 |
> |
{$IF declared(ftOraTimeStamp)} |
1036 |
> |
{These six extra elements were added to the FPC fixes_3_2 branch in Q3 2021} |
1037 |
> |
, |
1038 |
> |
nil, {ftOraTimeStamp} |
1039 |
> |
nil, {ftOraInterval} |
1040 |
> |
nil, {ftLongWord} |
1041 |
> |
nil, {ftShortint} |
1042 |
> |
nil, {ftByte} |
1043 |
> |
nil {ftExtended} |
1044 |
> |
{$IFEND} |
1045 |
> |
); |
1046 |
|
(*var |
1047 |
|
CreateProviderProc: function(DataSet: TIBCustomDataSet): IProvider = nil;*) |
1048 |
|
|
1049 |
|
implementation |
1050 |
|
|
1051 |
< |
uses Variants, FmtBCD, LazUTF8, FBMessages, IBQuery; |
956 |
< |
|
957 |
< |
const FILE_BEGIN = 0; |
958 |
< |
FILE_CURRENT = 1; |
959 |
< |
FILE_END = 2; |
1051 |
> |
uses Variants, FmtBCD, LazUTF8, IBMessages, IBQuery, DateUtils, dbconst; |
1052 |
|
|
1053 |
|
type |
1054 |
|
|
1110 |
|
Result := str; |
1111 |
|
end; |
1112 |
|
|
1113 |
+ |
{ TIBDateTimeField } |
1114 |
+ |
|
1115 |
+ |
function TIBDateTimeField.GetTimeZoneName: string; |
1116 |
+ |
var aBuffer: TIBBufferedDateTimeWithTimeZone; |
1117 |
+ |
begin |
1118 |
+ |
if GetDateTimeBuffer(aBuffer) then |
1119 |
+ |
Result := GetTimeZoneServices.TimeZoneID2TimeZoneName(aBuffer.TimeZoneID) |
1120 |
+ |
else |
1121 |
+ |
Result := ''; |
1122 |
+ |
end; |
1123 |
+ |
|
1124 |
+ |
function TIBDateTimeField.GetTimeZoneServices: ITimeZoneServices; |
1125 |
+ |
begin |
1126 |
+ |
if (FTimeZoneServices = nil) and |
1127 |
+ |
(DataSet <> nil) and ((DataSet as TIBCustomDataSet).Database <> nil) |
1128 |
+ |
and ((DataSet as TIBCustomDataSet).Database.attachment <> nil) then |
1129 |
+ |
FTimeZoneServices := (DataSet as TIBCustomDataSet).Database.attachment.GetTimeZoneServices; |
1130 |
+ |
Result := FTimeZoneServices; |
1131 |
+ |
end; |
1132 |
+ |
|
1133 |
+ |
function TIBDateTimeField.GetDateTimeBuffer( |
1134 |
+ |
var aBuffer: TIBBufferedDateTimeWithTimeZone): boolean; |
1135 |
+ |
begin |
1136 |
+ |
Result := HasTimeZone; |
1137 |
+ |
if Result then |
1138 |
+ |
Result := GetData(@aBuffer,False); |
1139 |
+ |
end; |
1140 |
+ |
|
1141 |
+ |
function TIBDateTimeField.GetTimeZoneID: TFBTimeZoneID; |
1142 |
+ |
var aBuffer: TIBBufferedDateTimeWithTimeZone; |
1143 |
+ |
begin |
1144 |
+ |
if GetDateTimeBuffer(aBuffer) then |
1145 |
+ |
Result := aBuffer.TimeZoneID |
1146 |
+ |
else |
1147 |
+ |
Result := TimeZoneID_GMT; |
1148 |
+ |
end; |
1149 |
+ |
|
1150 |
+ |
procedure TIBDateTimeField.SetTimeZoneID(aValue: TFBTimeZoneID); |
1151 |
+ |
var aBuffer: TIBBufferedDateTimeWithTimeZone; |
1152 |
+ |
begin |
1153 |
+ |
if GetDateTimeBuffer(aBuffer) then |
1154 |
+ |
SetAsDateTimeTZ(aBuffer.Timestamp,aValue) |
1155 |
+ |
end; |
1156 |
+ |
|
1157 |
+ |
procedure TIBDateTimeField.SetTimeZoneName(AValue: string); |
1158 |
+ |
var aBuffer: TIBBufferedDateTimeWithTimeZone; |
1159 |
+ |
begin |
1160 |
+ |
if GetDateTimeBuffer(aBuffer) then |
1161 |
+ |
SetAsDateTimeTZ(aBuffer.Timestamp,aValue) |
1162 |
+ |
end; |
1163 |
+ |
|
1164 |
+ |
procedure TIBDateTimeField.Bind(Binding: Boolean); |
1165 |
+ |
var IBFieldDef: TIBFieldDef; |
1166 |
+ |
begin |
1167 |
+ |
inherited Bind(Binding); |
1168 |
+ |
if Binding and (FieldDef <> nil) then |
1169 |
+ |
begin |
1170 |
+ |
IBFieldDef := FieldDef as TIBFieldDef; |
1171 |
+ |
FHasTimeZone := IBFieldDef.HasTimeZone; |
1172 |
+ |
end; |
1173 |
+ |
end; |
1174 |
+ |
|
1175 |
+ |
function TIBDateTimeField.GetAsDateTime: TDateTime; |
1176 |
+ |
var aBuffer: TIBBufferedDateTimeWithTimeZone; |
1177 |
+ |
begin |
1178 |
+ |
if GetDateTimeBuffer(aBuffer) then |
1179 |
+ |
Result := aBuffer.Timestamp |
1180 |
+ |
else |
1181 |
+ |
Result := inherited GetAsDateTime; |
1182 |
+ |
end; |
1183 |
+ |
|
1184 |
+ |
function TIBDateTimeField.GetAsVariant: variant; |
1185 |
+ |
var aBuffer: TIBBufferedDateTimeWithTimeZone; |
1186 |
+ |
begin |
1187 |
+ |
if GetDateTimeBuffer(aBuffer) then |
1188 |
+ |
with aBuffer do |
1189 |
+ |
Result := VarArrayOf([Timestamp,dstOffset,TimeZoneID]) |
1190 |
+ |
else |
1191 |
+ |
Result := inherited GetAsVariant; |
1192 |
+ |
end; |
1193 |
+ |
|
1194 |
+ |
function TIBDateTimeField.GetDataSize: Integer; |
1195 |
+ |
begin |
1196 |
+ |
if HasTimeZone then |
1197 |
+ |
Result := sizeof(TIBBufferedDateTimeWithTimeZone) |
1198 |
+ |
else |
1199 |
+ |
Result := inherited GetDataSize; |
1200 |
+ |
end; |
1201 |
+ |
|
1202 |
+ |
procedure TIBDateTimeField.GetText(var theText: string; ADisplayText: Boolean); |
1203 |
+ |
var aBuffer: TIBBufferedDateTimeWithTimeZone; |
1204 |
+ |
F: string; |
1205 |
+ |
begin |
1206 |
+ |
if Dataset = nil then |
1207 |
+ |
DatabaseErrorFmt(SNoDataset,[FieldName]); |
1208 |
+ |
|
1209 |
+ |
if GetDateTimeBuffer(aBuffer) then |
1210 |
+ |
{$if declared(DefaultFormatSettings)} |
1211 |
+ |
with DefaultFormatSettings do |
1212 |
+ |
{$else} |
1213 |
+ |
{$if declared(FormatSettings)} |
1214 |
+ |
with FormatSettings do |
1215 |
+ |
{$ifend} |
1216 |
+ |
{$ifend} |
1217 |
+ |
begin |
1218 |
+ |
if ADisplayText and (Length(DisplayFormat) <> 0) then |
1219 |
+ |
F := DisplayFormat |
1220 |
+ |
else |
1221 |
+ |
Case DataType of |
1222 |
+ |
ftTime : F := LongTimeFormat; |
1223 |
+ |
ftDate : F := ShortDateFormat; |
1224 |
+ |
else |
1225 |
+ |
F := ShortDateFormat + ' ' + LongTimeFormat; |
1226 |
+ |
end; |
1227 |
+ |
|
1228 |
+ |
with aBuffer do |
1229 |
+ |
case (DataSet as TIBCustomDataSet).TZTextOption of |
1230 |
+ |
tzOffset: |
1231 |
+ |
TheText := FBFormatDateTime(F,timestamp) + ' ' + FormatTimeZoneOffset(dstOffset); |
1232 |
+ |
tzGMT: |
1233 |
+ |
TheText := FBFormatDateTime(F,IncMinute(Timestamp,-dstOffset)); |
1234 |
+ |
tzOriginalID: |
1235 |
+ |
TheText := FBFormatDateTime(F,timestamp) + ' ' + GetTimeZoneServices.TimeZoneID2TimeZoneName(TimeZoneID); |
1236 |
+ |
end; |
1237 |
+ |
end |
1238 |
+ |
else |
1239 |
+ |
inherited GetText(theText, ADisplayText); |
1240 |
+ |
end; |
1241 |
+ |
|
1242 |
+ |
procedure TIBDateTimeField.SetAsDateTime(AValue: TDateTime); |
1243 |
+ |
var aBuffer: TIBBufferedDateTimeWithTimeZone; |
1244 |
+ |
begin |
1245 |
+ |
if GetDateTimeBuffer(aBuffer) then |
1246 |
+ |
SetAsDateTimeTZ(AValue,aBuffer.TimeZoneID) |
1247 |
+ |
else |
1248 |
+ |
inherited SetAsDateTime(AValue) |
1249 |
+ |
end; |
1250 |
+ |
|
1251 |
+ |
procedure TIBDateTimeField.SetAsString(const AValue: string); |
1252 |
+ |
var aDateTime: TDateTime; |
1253 |
+ |
aTimeZone: AnsiString; |
1254 |
+ |
begin |
1255 |
+ |
if AValue = '' then |
1256 |
+ |
Clear |
1257 |
+ |
else |
1258 |
+ |
if ParseDateTimeTZString(AValue,aDateTime,aTimeZone,DataType=ftTime) then |
1259 |
+ |
begin |
1260 |
+ |
if not HasTimeZone or (aTimeZone = '') then |
1261 |
+ |
SetAsDateTime(aDateTime) |
1262 |
+ |
else |
1263 |
+ |
SetAsDateTimeTZ(aDateTime,aTimeZone); |
1264 |
+ |
end |
1265 |
+ |
else |
1266 |
+ |
IBError(ibxeBadDateTimeTZString,[AValue]); |
1267 |
+ |
end; |
1268 |
+ |
|
1269 |
+ |
procedure TIBDateTimeField.SetVarValue(const AValue: Variant); |
1270 |
+ |
begin |
1271 |
+ |
if HasTimeZone and VarIsArray(AValue)then |
1272 |
+ |
SetAsDateTimeTZ(AValue[0],string(AValue[2])) |
1273 |
+ |
else |
1274 |
+ |
inherited SetVarValue(AValue); |
1275 |
+ |
end; |
1276 |
+ |
|
1277 |
+ |
constructor TIBDateTimeField.Create(AOwner: TComponent); |
1278 |
+ |
begin |
1279 |
+ |
inherited Create(AOwner); |
1280 |
+ |
SetDataType(ftDateTime); |
1281 |
+ |
end; |
1282 |
+ |
|
1283 |
+ |
function TIBDateTimeField.GetAsDateTimeTZ(var aDateTime: TDateTime; |
1284 |
+ |
var dstOffset: smallint; var aTimeZoneID: TFBTimeZoneID): boolean; |
1285 |
+ |
var aBuffer: TIBBufferedDateTimeWithTimeZone; |
1286 |
+ |
begin |
1287 |
+ |
Result := GetDateTimeBuffer(aBuffer); |
1288 |
+ |
if Result then |
1289 |
+ |
begin |
1290 |
+ |
aDateTime := aBuffer.Timestamp; |
1291 |
+ |
dstOffset := aBuffer.dstOffset; |
1292 |
+ |
aTimeZoneID := aBuffer.TimeZoneID; |
1293 |
+ |
end |
1294 |
+ |
else |
1295 |
+ |
aDateTime := inherited GetAsDateTime |
1296 |
+ |
end; |
1297 |
+ |
|
1298 |
+ |
function TIBDateTimeField.GetAsDateTimeTZ(var aDateTime: TDateTime; |
1299 |
+ |
var dstOffset: smallint; var aTimeZone: string): boolean; |
1300 |
+ |
var aTimeZoneID: TFBTimeZoneID; |
1301 |
+ |
begin |
1302 |
+ |
Result := GetAsDateTimeTZ(aDateTime,dstOffset,aTimeZoneID); |
1303 |
+ |
if Result then |
1304 |
+ |
aTimeZone := GetTimeZoneServices.TimeZoneID2TimeZoneName(aTimeZoneID); |
1305 |
+ |
end; |
1306 |
+ |
|
1307 |
+ |
function TIBDateTimeField.GetAsUTCDateTime: TDateTime; |
1308 |
+ |
var aBuffer: TIBBufferedDateTimeWithTimeZone; |
1309 |
+ |
begin |
1310 |
+ |
if GetDateTimeBuffer(aBuffer) then |
1311 |
+ |
Result := IncMinute(aBuffer.timestamp,-aBuffer.dstOffset) |
1312 |
+ |
else |
1313 |
+ |
Result := inherited GetAsDateTime; |
1314 |
+ |
end; |
1315 |
+ |
|
1316 |
+ |
procedure TIBDateTimeField.SetAsDateTimeTZ(aDateTime: TDateTime; |
1317 |
+ |
aTimeZoneID: TFBTimeZoneID); |
1318 |
+ |
var DateTimeBuffer: TIBBufferedDateTimeWithTimeZone; |
1319 |
+ |
begin |
1320 |
+ |
if HasTimeZone then |
1321 |
+ |
begin |
1322 |
+ |
DateTimeBuffer.Timestamp := aDateTime; |
1323 |
+ |
DateTimeBuffer.dstOffset := GetTimeZoneServices.GetEffectiveOffsetMins(aDateTime,aTimeZoneID); |
1324 |
+ |
DateTimeBuffer.TimeZoneID := aTimeZoneID; |
1325 |
+ |
SetData(@DateTimeBuffer,False); |
1326 |
+ |
end |
1327 |
+ |
else |
1328 |
+ |
inherited SetAsDateTime(aDateTime); |
1329 |
+ |
end; |
1330 |
+ |
|
1331 |
+ |
procedure TIBDateTimeField.SetAsDateTimeTZ(aDateTime: TDateTime; |
1332 |
+ |
aTimeZone: string); |
1333 |
+ |
begin |
1334 |
+ |
if HasTimeZone then |
1335 |
+ |
SetAsDateTimeTZ(aDateTime,GetTimeZoneServices.TimeZoneName2TimeZoneID(aTimeZone)) |
1336 |
+ |
else |
1337 |
+ |
inherited SetAsDateTime(aDateTime); |
1338 |
+ |
end; |
1339 |
+ |
|
1340 |
+ |
{ TIBTimeField } |
1341 |
+ |
|
1342 |
+ |
constructor TIBTimeField.Create(AOwner: TComponent); |
1343 |
+ |
begin |
1344 |
+ |
inherited Create(AOwner); |
1345 |
+ |
SetDataType(ftTime); |
1346 |
+ |
end; |
1347 |
+ |
|
1348 |
+ |
{ TIBParserDataSet } |
1349 |
+ |
|
1350 |
+ |
procedure TIBParserDataSet.DoBeforeOpen; |
1351 |
+ |
var i: integer; |
1352 |
+ |
begin |
1353 |
+ |
if assigned(FParser) then |
1354 |
+ |
FParser.RestoreClauseValues; |
1355 |
+ |
if SQLFiltered then |
1356 |
+ |
for i := 0 to SQLFilterParams.Count - 1 do |
1357 |
+ |
Parser.Add2WhereClause(SQLFilterParams[i]); |
1358 |
+ |
for i := 0 to FIBLinks.Count - 1 do |
1359 |
+ |
TIBControlLink(FIBLinks[i]).UpdateSQL(self); |
1360 |
+ |
inherited DoBeforeOpen; |
1361 |
+ |
for i := 0 to FIBLinks.Count - 1 do |
1362 |
+ |
TIBControlLink(FIBLinks[i]).UpdateParams(self); |
1363 |
+ |
end; |
1364 |
+ |
|
1365 |
|
{ TIBLargeIntField } |
1366 |
|
|
1367 |
|
procedure TIBLargeIntField.Bind(Binding: Boolean); |
1500 |
|
3, {Assume UNICODE_FSS is really UTF8} |
1501 |
|
4: {Include GB18030 - assuming UTF8 routines work for this codeset} |
1502 |
|
if DisplayWidth = 0 then |
1503 |
+ |
{$if declared(Utf8EscapeControlChars)} |
1504 |
+ |
Result := Utf8EscapeControlChars(TextToSingleLine(Result)) |
1505 |
+ |
{$else} |
1506 |
|
Result := ValidUTF8String(TextToSingleLine(Result)) |
1507 |
+ |
{$endif} |
1508 |
|
else |
1509 |
|
if UTF8Length(Result) > DisplayWidth then {Show truncation with elipses} |
1510 |
+ |
{$if declared(Utf8EscapeControlChars)} |
1511 |
+ |
Result := Utf8EscapeControlChars(TextToSingleLine(UTF8Copy(Result,1,DisplayWidth-3))) + '...'; |
1512 |
+ |
{$else} |
1513 |
|
Result := ValidUTF8String(TextToSingleLine(UTF8Copy(Result,1,DisplayWidth-3))) + '...'; |
1514 |
+ |
{$endif} |
1515 |
|
end; |
1516 |
|
end |
1517 |
|
end; |
1616 |
|
IBFieldDef := FieldDef as TIBFieldDef; |
1617 |
|
CharacterSetSize := IBFieldDef.CharacterSetSize; |
1618 |
|
CharacterSetName := IBFieldDef.CharacterSetName; |
1619 |
< |
FDataSize := IBFieldDef.DataSize + 1; |
1619 |
> |
FDataSize := IBFieldDef.DataSize; |
1620 |
|
if AutoFieldSize then |
1621 |
|
Size := IBFieldDef.Size; |
1622 |
|
CodePage := IBFieldDef.CodePage; |
1659 |
|
s: RawByteString; |
1660 |
|
begin |
1661 |
|
Buffer := nil; |
1662 |
< |
IBAlloc(Buffer, 0, DataSize); |
1662 |
> |
IBAlloc(Buffer, 0, DataSize + 1); {allow for trailing #0} |
1663 |
|
try |
1664 |
|
Result := GetData(Buffer); |
1665 |
|
if Result then |
1668 |
|
SetCodePage(s,CodePage,false); |
1669 |
|
if (CodePage <> CP_NONE) and (CodePage <> CP_UTF8) then |
1670 |
|
SetCodePage(s,CP_UTF8,true); {LCL only accepts UTF8} |
1671 |
< |
Value := s; |
1671 |
> |
|
1672 |
> |
if (CodePage = CP_UTF8) and (UTF8Length(s) > Size) then |
1673 |
> |
{truncate to max. number of UTF8 characters - usually a problem with |
1674 |
> |
fixed width columns right padded with white space} |
1675 |
> |
Value := UTF8Copy(s,1,Size) |
1676 |
> |
else |
1677 |
> |
Value := s; |
1678 |
> |
|
1679 |
|
// writeln(FieldName,': ', StringCodePage(Value),', ',Value); |
1680 |
|
if Transliterate and (Value <> '') then |
1681 |
|
DataSet.Translate(PChar(Value), PChar(Value), False); |
1691 |
|
s: RawByteString; |
1692 |
|
begin |
1693 |
|
Buffer := nil; |
1694 |
< |
IBAlloc(Buffer, 0, DataSize); |
1694 |
> |
IBAlloc(Buffer, 0, DataSize + 1); {allow for trailing #0} |
1695 |
|
try |
1696 |
|
s := Value; |
1697 |
|
if StringCodePage(s) <> CodePage then |
1698 |
|
SetCodePage(s,CodePage,CodePage<>CP_NONE); |
1699 |
< |
StrLCopy(Buffer, PChar(s), DataSize-1); |
1699 |
> |
StrLCopy(Buffer, PChar(s), DataSize); |
1700 |
|
if Transliterate then |
1701 |
|
DataSet.Translate(Buffer, Buffer, True); |
1702 |
|
SetData(Buffer); |
1768 |
|
begin |
1769 |
|
inherited Create; |
1770 |
|
FDataSet := ADataSet; |
1771 |
< |
FTimer := TFPTimer.Create(nil); |
1772 |
< |
FTimer.Enabled := true; |
1773 |
< |
FTimer.Interval := 0; |
1774 |
< |
FTimer.OnTimer := HandleRefreshTimer; |
1771 |
> |
if assigned(IBGUIInterface) then |
1772 |
> |
begin |
1773 |
> |
FTimer := IBGUIInterface.CreateTimer; |
1774 |
> |
if FTimer <> nil then |
1775 |
> |
begin |
1776 |
> |
FTimer.Enabled := false; |
1777 |
> |
FTimer.Interval := 0; |
1778 |
> |
FTimer.OnTimer := HandleRefreshTimer; |
1779 |
> |
end; |
1780 |
> |
end; |
1781 |
|
FDelayTimerValue := 0; |
1782 |
|
end; |
1783 |
|
|
1784 |
|
destructor TIBDataLink.Destroy; |
1785 |
|
begin |
1786 |
|
FDataSet.FDataLink := nil; |
1422 |
– |
if assigned(FTimer) then FTimer.Free; |
1787 |
|
inherited Destroy; |
1788 |
|
end; |
1789 |
|
|
1790 |
|
procedure TIBDataLink.HandleRefreshTimer(Sender: TObject); |
1791 |
|
begin |
1792 |
< |
FTimer.Interval := 0; |
1793 |
< |
FDataSet.RefreshParams; |
1792 |
> |
FTimer.Enabled := false; |
1793 |
> |
if FDataSet.Active then |
1794 |
> |
FDataSet.RefreshParams; |
1795 |
> |
end; |
1796 |
> |
|
1797 |
> |
procedure TIBDataLink.SetDelayTimerValue(AValue: integer); |
1798 |
> |
begin |
1799 |
> |
if FDelayTimerValue = AValue then Exit; |
1800 |
> |
if assigned(FTimer) then |
1801 |
> |
FTimer.Enabled := false; |
1802 |
> |
FDelayTimerValue := AValue; |
1803 |
|
end; |
1804 |
|
|
1805 |
|
procedure TIBDataLink.ActiveChanged; |
1806 |
|
begin |
1807 |
< |
if FDataSet.Active then |
1807 |
> |
if DetailDataSet.Active and DataSet.Active then |
1808 |
|
FDataSet.RefreshParams; |
1809 |
|
end; |
1810 |
|
|
1818 |
|
begin |
1819 |
|
if (Field = nil) and FDataSet.Active then |
1820 |
|
begin |
1821 |
< |
if FDelayTimerValue > 0 then |
1821 |
> |
if assigned(FTimer) and (FDelayTimerValue > 0) then |
1822 |
> |
with FTimer do |
1823 |
|
begin |
1824 |
+ |
FTimer.Enabled := false; |
1825 |
|
FTimer.Interval := FDelayTimerValue; |
1826 |
< |
FTimer.StartTimer; |
1826 |
> |
FTimer.Enabled := true; |
1827 |
|
end |
1828 |
|
else |
1829 |
|
FDataSet.RefreshParams; |
1854 |
|
FDataLink := TIBDataLink.Create(Self); |
1855 |
|
FQDelete := TIBSQL.Create(Self); |
1856 |
|
FQDelete.OnSQLChanging := SQLChanging; |
1857 |
< |
FQDelete.GoToFirstRecordOnExecute := False; |
1857 |
> |
FQDelete.GoToFirstRecordOnExecute := True; |
1858 |
|
FQInsert := TIBSQL.Create(Self); |
1859 |
|
FQInsert.OnSQLChanging := SQLChanging; |
1860 |
< |
FQInsert.GoToFirstRecordOnExecute := False; |
1860 |
> |
FQInsert.GoToFirstRecordOnExecute := true; |
1861 |
|
FQRefresh := TIBSQL.Create(Self); |
1862 |
|
FQRefresh.OnSQLChanging := SQLChanging; |
1863 |
|
FQRefresh.GoToFirstRecordOnExecute := False; |
1867 |
|
FQSelect.GoToFirstRecordOnExecute := False; |
1868 |
|
FQModify := TIBSQL.Create(Self); |
1869 |
|
FQModify.OnSQLChanging := SQLChanging; |
1870 |
< |
FQModify.GoToFirstRecordOnExecute := False; |
1870 |
> |
FQModify.GoToFirstRecordOnExecute := True; {In Firebird 5, Update..Returning returns a cursor} |
1871 |
|
FUpdateRecordTypes := [cusUnmodified, cusModified, cusInserted]; |
1872 |
|
FParamCheck := True; |
1873 |
|
FGenerateParamNames := False; |
1888 |
|
if AOwner is TIBTransaction then |
1889 |
|
Transaction := TIBTransaction(AOwner); |
1890 |
|
FBaseSQLSelect := TStringList.Create; |
1891 |
+ |
FTZTextOption := tzOffset; |
1892 |
+ |
FDefaultTZDate := EncodeDate(2020,1,1); |
1893 |
+ |
FSQLFilterParams := TStringList.Create; |
1894 |
+ |
TStringList(FSQLFilterParams).OnChange := HandleSQLFilterParamsChanged; |
1895 |
|
end; |
1896 |
|
|
1897 |
|
destructor TIBCustomDataSet.Destroy; |
1914 |
|
FMappedFieldPosition := nil; |
1915 |
|
if assigned(FBaseSQLSelect) then FBaseSQLSelect.Free; |
1916 |
|
if assigned(FParser) then FParser.Free; |
1917 |
+ |
if assigned(FSQLFilterParams) then FSQLFilterParams.Free; |
1918 |
|
inherited Destroy; |
1919 |
|
end; |
1920 |
|
|
1999 |
|
|
2000 |
|
procedure UpdateUsingOnUpdateRecord; |
2001 |
|
begin |
1622 |
– |
UpdateAction := uaFail; |
2002 |
|
try |
2003 |
|
FOnUpdateRecord(Self, UpdateKind, UpdateAction); |
2004 |
|
except |
2005 |
|
on E: Exception do |
2006 |
|
begin |
2007 |
+ |
UpdateAction := uaFail; |
2008 |
|
if (E is EDatabaseError) and Assigned(FOnUpdateError) then |
2009 |
< |
FOnUpdateError(Self, EIBError(E), UpdateKind, UpdateAction); |
1630 |
< |
if UpdateAction = uaFail then |
1631 |
< |
raise; |
2009 |
> |
FOnUpdateError(Self, EDatabaseError(E), UpdateKind, UpdateAction); |
2010 |
|
end; |
2011 |
|
end; |
2012 |
|
end; |
2015 |
|
begin |
2016 |
|
try |
2017 |
|
FUpdateObject.Apply(UpdateKind,PChar(Buffer)); |
2018 |
< |
ResetBufferUpdateStatus; |
2018 |
> |
UpdateAction := uaApplied; |
2019 |
|
except |
2020 |
|
on E: Exception do |
2021 |
+ |
begin |
2022 |
+ |
UpdateAction := uaFail; |
2023 |
|
if (E is EDatabaseError) and Assigned(FOnUpdateError) then |
2024 |
< |
FOnUpdateError(Self, EIBError(E), UpdateKind, UpdateAction); |
2024 |
> |
FOnUpdateError(Self, EDatabaseError(E), UpdateKind, UpdateAction); |
2025 |
> |
end; |
2026 |
|
end; |
2027 |
|
end; |
2028 |
|
|
2037 |
|
cusDeleted: |
2038 |
|
InternalDeleteRecord(FQDelete, Buffer); |
2039 |
|
end; |
2040 |
+ |
UpdateAction := uaApplied; |
2041 |
|
except |
2042 |
< |
on E: EIBError do begin |
2042 |
> |
on E: Exception do begin |
2043 |
|
UpdateAction := uaFail; |
2044 |
< |
if Assigned(FOnUpdateError) then |
2045 |
< |
FOnUpdateError(Self, E, UpdateKind, UpdateAction); |
1664 |
< |
case UpdateAction of |
1665 |
< |
uaFail: raise; |
1666 |
< |
uaAbort: SysUtils.Abort; |
1667 |
< |
uaSkip: bRecordsSkipped := True; |
1668 |
< |
end; |
2044 |
> |
if (E is EDatabaseError) and Assigned(FOnUpdateError) then |
2045 |
> |
FOnUpdateError(Self, EDatabaseError(E), UpdateKind, UpdateAction); |
2046 |
|
end; |
2047 |
|
end; |
2048 |
|
end; |
2064 |
|
Buffer := PRecordData(GetActiveBuf); |
2065 |
|
GetUpdateKind; |
2066 |
|
UpdateAction := uaApply; |
2067 |
< |
if Assigned(FUpdateObject) or Assigned(FOnUpdateRecord) then |
2067 |
> |
if (Assigned(FOnUpdateRecord)) then |
2068 |
> |
UpdateUsingOnUpdateRecord; |
2069 |
> |
if UpdateAction = uaApply then |
2070 |
|
begin |
2071 |
< |
if (Assigned(FOnUpdateRecord)) then |
2072 |
< |
UpdateUsingOnUpdateRecord |
2071 |
> |
if Assigned(FUpdateObject) then |
2072 |
> |
UpdateUsingUpdateObject |
2073 |
|
else |
2074 |
< |
if Assigned(FUpdateObject) then |
1696 |
< |
UpdateUsingUpdateObject; |
1697 |
< |
case UpdateAction of |
1698 |
< |
uaFail: |
1699 |
< |
IBError(ibxeUserAbort, [nil]); |
1700 |
< |
uaAbort: |
1701 |
< |
SysUtils.Abort; |
1702 |
< |
uaApplied: |
1703 |
< |
ResetBufferUpdateStatus; |
1704 |
< |
uaSkip: |
1705 |
< |
bRecordsSkipped := True; |
1706 |
< |
uaRetry: |
1707 |
< |
Continue; |
1708 |
< |
end; |
2074 |
> |
UpdateUsingInternalquery; |
2075 |
|
end; |
2076 |
< |
if (not Assigned(FUpdateObject)) and (UpdateAction = UaApply) then |
2077 |
< |
begin |
2078 |
< |
UpdateUsingInternalquery; |
2079 |
< |
UpdateAction := uaApplied; |
2076 |
> |
|
2077 |
> |
case UpdateAction of |
2078 |
> |
uaFail: |
2079 |
> |
IBError(ibxeUserAbort, [nil]); |
2080 |
> |
uaAbort: |
2081 |
> |
SysUtils.Abort; |
2082 |
> |
uaApplied: |
2083 |
> |
ResetBufferUpdateStatus; |
2084 |
> |
uaSkip: |
2085 |
> |
bRecordsSkipped := True; |
2086 |
> |
uaRetry: |
2087 |
> |
Continue; |
2088 |
|
end; |
2089 |
+ |
|
2090 |
|
Next; |
2091 |
|
end; |
2092 |
|
FUpdatesPending := bRecordsSkipped; |
2260 |
|
Buff: PRecordData; |
2261 |
|
begin |
2262 |
|
Buff := PRecordData(GetActiveBuf); |
2263 |
< |
result := (FQModify.SQL.Text <> '') or |
2264 |
< |
(Assigned(FUpdateObject) and (FUpdateObject.GetSQL(ukModify).Text <> '')) or |
2263 |
> |
result := (Trim(FQModify.SQL.Text) <> '') or |
2264 |
> |
(Assigned(FUpdateObject) and (Trim(FUpdateObject.GetSQL(ukModify).Text) <> '')) or |
2265 |
|
((Buff <> nil) and (Buff^.rdCachedUpdateStatus = cusInserted) and |
2266 |
|
(FCachedUpdates)); |
2267 |
|
end; |
2268 |
|
|
2269 |
|
function TIBCustomDataSet.CanInsert: Boolean; |
2270 |
|
begin |
2271 |
< |
result := (FQInsert.SQL.Text <> '') or |
2272 |
< |
(Assigned(FUpdateObject) and (FUpdateObject.GetSQL(ukInsert).Text <> '')); |
2271 |
> |
result := (Trim(FQInsert.SQL.Text) <> '') or |
2272 |
> |
(Assigned(FUpdateObject) and (Trim(FUpdateObject.GetSQL(ukInsert).Text) <> '')); |
2273 |
|
end; |
2274 |
|
|
2275 |
|
function TIBCustomDataSet.CanDelete: Boolean; |
2276 |
|
begin |
2277 |
< |
if (FQDelete.SQL.Text <> '') or |
2278 |
< |
(Assigned(FUpdateObject) and (FUpdateObject.GetSQL(ukDelete).Text <> '')) then |
2277 |
> |
if (Trim(FQDelete.SQL.Text) <> '') or |
2278 |
> |
(Assigned(FUpdateObject) and (Trim(FUpdateObject.GetSQL(ukDelete).Text) <> '')) then |
2279 |
|
result := True |
2280 |
|
else |
2281 |
|
result := False; |
2283 |
|
|
2284 |
|
function TIBCustomDataSet.CanRefresh: Boolean; |
2285 |
|
begin |
2286 |
< |
result := (FQRefresh.SQL.Text <> '') or |
2287 |
< |
(Assigned(FUpdateObject) and (FUpdateObject.RefreshSQL.Text <> '')); |
2286 |
> |
result := (Trim(FQRefresh.SQL.Text) <> '') or |
2287 |
> |
(Assigned(FUpdateObject) and (Trim(FUpdateObject.RefreshSQL.Text) <> '')); |
2288 |
|
end; |
2289 |
|
|
2290 |
|
procedure TIBCustomDataSet.CheckEditState; |
2451 |
|
SQL_TYPE_DATE, |
2452 |
|
SQL_TYPE_TIME: |
2453 |
|
fdDataSize := SizeOf(TDateTime); |
2454 |
+ |
SQL_TIMESTAMP_TZ, |
2455 |
+ |
SQL_TIMESTAMP_TZ_EX, |
2456 |
+ |
SQL_TIME_TZ, |
2457 |
+ |
SQL_TIME_TZ_EX: |
2458 |
+ |
fdDataSize := SizeOf(TIBBufferedDateTimeWithTimeZone); |
2459 |
|
SQL_SHORT, SQL_LONG: |
2460 |
|
begin |
2461 |
|
if (fdDataScale = 0) then |
2483 |
|
SQL_VARYING, |
2484 |
|
SQL_TEXT, |
2485 |
|
SQL_BLOB: |
2486 |
< |
fdCodePage := Qry.Metadata[i].getCodePage; |
2486 |
> |
fdCodePage := colMetadata.getCodePage; |
2487 |
> |
SQL_DEC16, |
2488 |
> |
SQL_DEC34, |
2489 |
> |
SQL_DEC_FIXED, |
2490 |
> |
SQL_INT128: |
2491 |
> |
fdDataSize := sizeof(tBCD); |
2492 |
|
end; |
2493 |
|
fdDataOfs := FRecordSize; |
2494 |
|
Inc(FRecordSize, fdDataSize); |
2521 |
|
ColumnIndex, FieldIndex: integer; Buffer: PChar); |
2522 |
|
var |
2523 |
|
LocalData: PByte; |
2524 |
< |
LocalDate: TDateTime; |
2140 |
< |
LocalDouble: Double; |
2141 |
< |
LocalInt: Integer; |
2142 |
< |
LocalBool: wordBool; |
2143 |
< |
LocalInt64: Int64; |
2144 |
< |
LocalCurrency: Currency; |
2524 |
> |
BufPtr: PByte; |
2525 |
|
ColData: ISQLData; |
2526 |
|
begin |
2527 |
|
LocalData := nil; |
2528 |
|
with PRecordData(Buffer)^.rdFields[FieldIndex], FFieldColumns^[FieldIndex] do |
2529 |
|
begin |
2530 |
|
QryResults.GetData(ColumnIndex,fdIsNull,fdDataLength,LocalData); |
2531 |
+ |
BufPtr := PByte(Buffer + fdDataOfs); |
2532 |
|
if not fdIsNull then |
2533 |
|
begin |
2534 |
|
ColData := QryResults[ColumnIndex]; |
2536 |
|
SQL_TYPE_DATE, |
2537 |
|
SQL_TYPE_TIME, |
2538 |
|
SQL_TIMESTAMP: |
2158 |
– |
begin |
2539 |
|
{This is an IBX native format and not the TDataset approach. See also GetFieldData} |
2540 |
< |
LocalDate := ColData.AsDateTime; |
2541 |
< |
LocalData := PByte(@LocalDate); |
2540 |
> |
PDateTime(BufPtr)^ := ColData.AsDateTime; |
2541 |
> |
|
2542 |
> |
SQL_TIMESTAMP_TZ, |
2543 |
> |
SQL_TIMESTAMP_TZ_EX: |
2544 |
> |
begin |
2545 |
> |
with PIBBufferedDateTimeWithTimeZone(Bufptr)^ do |
2546 |
> |
ColData.GetAsDateTime(Timestamp,dstOffset,TimeZoneID); |
2547 |
> |
end; |
2548 |
> |
|
2549 |
> |
SQL_TIME_TZ, |
2550 |
> |
SQL_TIME_TZ_EX: |
2551 |
> |
begin |
2552 |
> |
with PIBBufferedDateTimeWithTimeZone(Bufptr)^ do |
2553 |
> |
ColData.GetAsTime(Timestamp, dstOffset,TimeZoneID, DefaultTZDate); |
2554 |
|
end; |
2555 |
|
SQL_SHORT, SQL_LONG: |
2556 |
|
begin |
2557 |
|
if (fdDataScale = 0) then |
2558 |
< |
begin |
2167 |
< |
LocalInt := ColData.AsLong; |
2168 |
< |
LocalData := PByte(@LocalInt); |
2169 |
< |
end |
2558 |
> |
PInteger(BufPtr)^ := ColData.AsLong |
2559 |
|
else |
2560 |
|
if (fdDataScale >= (-4)) then |
2561 |
< |
begin |
2173 |
< |
LocalCurrency := ColData.AsCurrency; |
2174 |
< |
LocalData := PByte(@LocalCurrency); |
2175 |
< |
end |
2561 |
> |
PCurrency(BufPtr)^ := ColData.AsCurrency |
2562 |
|
else |
2563 |
< |
begin |
2178 |
< |
LocalDouble := ColData.AsDouble; |
2179 |
< |
LocalData := PByte(@LocalDouble); |
2180 |
< |
end; |
2563 |
> |
PDouble(BufPtr)^ := ColData.AsDouble; |
2564 |
|
end; |
2565 |
|
SQL_INT64: |
2566 |
|
begin |
2567 |
|
if (fdDataScale = 0) then |
2568 |
< |
begin |
2186 |
< |
LocalInt64 := ColData.AsInt64; |
2187 |
< |
LocalData := PByte(@LocalInt64); |
2188 |
< |
end |
2568 |
> |
PInt64(BufPtr)^ := ColData.AsInt64 |
2569 |
|
else |
2570 |
|
if (fdDataScale >= (-4)) then |
2571 |
< |
begin |
2572 |
< |
LocalCurrency := ColData.AsCurrency; |
2573 |
< |
LocalData := PByte(@LocalCurrency); |
2194 |
< |
end |
2195 |
< |
else |
2196 |
< |
begin |
2197 |
< |
LocalDouble := ColData.AsDouble; |
2198 |
< |
LocalData := PByte(@LocalDouble); |
2199 |
< |
end |
2571 |
> |
PCurrency(BufPtr)^ := ColData.AsCurrency |
2572 |
> |
else |
2573 |
> |
PDouble(BufPtr)^ := ColData.AsDouble; |
2574 |
|
end; |
2575 |
+ |
|
2576 |
|
SQL_DOUBLE, SQL_FLOAT, SQL_D_FLOAT: |
2577 |
< |
begin |
2578 |
< |
LocalDouble := ColData.AsDouble; |
2204 |
< |
LocalData := PByte(@LocalDouble); |
2205 |
< |
end; |
2577 |
> |
PDouble(BufPtr)^ := ColData.AsDouble; |
2578 |
> |
|
2579 |
|
SQL_BOOLEAN: |
2580 |
< |
begin |
2581 |
< |
LocalBool := ColData.AsBoolean; |
2582 |
< |
LocalData := PByte(@LocalBool); |
2583 |
< |
end; |
2584 |
< |
end; |
2580 |
> |
system.PBoolean(BufPtr)^ := ColData.AsBoolean; |
2581 |
> |
|
2582 |
> |
SQL_DEC16, |
2583 |
> |
SQL_DEC34, |
2584 |
> |
SQL_DEC_FIXED, |
2585 |
> |
SQL_INT128: |
2586 |
> |
pBCD(BufPtr)^ := ColData.GetAsBCD; |
2587 |
|
|
2213 |
– |
if fdDataType = SQL_VARYING then |
2214 |
– |
Move(LocalData^, Buffer[fdDataOfs], fdDataLength) |
2588 |
|
else |
2589 |
< |
Move(LocalData^, Buffer[fdDataOfs], fdDataSize) |
2589 |
> |
begin |
2590 |
> |
if fdDataType = SQL_VARYING then |
2591 |
> |
Move(LocalData^, BufPtr^, fdDataLength) |
2592 |
> |
else |
2593 |
> |
Move(LocalData^, BufPtr^, fdDataSize) |
2594 |
> |
end; |
2595 |
> |
end; {case} |
2596 |
|
end |
2597 |
|
else {Null column} |
2598 |
|
if fdDataType = SQL_VARYING then |
2599 |
< |
FillChar(Buffer[fdDataOfs],fdDataLength,0) |
2599 |
> |
FillChar(BufPtr^,fdDataLength,0) |
2600 |
|
else |
2601 |
< |
FillChar(Buffer[fdDataOfs],fdDataSize,0); |
2601 |
> |
FillChar(BufPtr^,fdDataSize,0); |
2602 |
|
end; |
2603 |
|
end; |
2604 |
|
|
2940 |
|
begin |
2941 |
|
if Buff <> nil then |
2942 |
|
begin |
2943 |
< |
if (Assigned(FUpdateObject) and (FUpdateObject.RefreshSQL.Text <> '')) then |
2943 |
> |
if (Assigned(FUpdateObject) and (Trim(FUpdateObject.RefreshSQL.Text) <> '')) then |
2944 |
|
begin |
2945 |
|
Qry := TIBSQL.Create(self); |
2946 |
|
Qry.Database := Database; |
3055 |
|
ActivateTransaction; |
3056 |
|
FBase.CheckDatabase; |
3057 |
|
FBase.CheckTransaction; |
3058 |
< |
if HasParser and (FParser.SQLText <> FQSelect.SQL.Text) then |
3058 |
> |
if HasParser and not FParser.NotaSelectStmt and (FParser.SQLText <> FQSelect.SQL.Text) then |
3059 |
|
begin |
3060 |
|
FQSelect.OnSQLChanged := nil; {Do not react to change} |
3061 |
|
try |
3195 |
|
procedure TIBCustomDataSet.SetInternalSQLParams(Params: ISQLParams; Buffer: Pointer); |
3196 |
|
var |
3197 |
|
i, j: Integer; |
3198 |
< |
cr, data: PChar; |
3198 |
> |
cr, data: PByte; |
3199 |
|
fn: string; |
3200 |
|
st: RawByteString; |
3201 |
|
OldBuffer: Pointer; |
3245 |
|
case fdDataType of |
3246 |
|
SQL_TEXT, SQL_VARYING: |
3247 |
|
begin |
3248 |
< |
SetString(st, data, fdDataLength); |
3248 |
> |
SetString(st, PAnsiChar(data), fdDataLength); |
3249 |
|
SetCodePage(st,fdCodePage,false); |
3250 |
|
Param.AsString := st; |
3251 |
|
end; |
3278 |
|
SQL_TIMESTAMP: |
3279 |
|
{This is an IBX native format and not the TDataset approach. See also SetFieldData} |
3280 |
|
Param.AsDateTime := PDateTime(data)^; |
3281 |
+ |
SQL_TIMESTAMP_TZ_EX, |
3282 |
+ |
SQL_TIMESTAMP_TZ: |
3283 |
+ |
with PIBBufferedDateTimeWithTimeZone(data)^ do |
3284 |
+ |
Param.SetAsDateTime(Timestamp,TimeZoneID); |
3285 |
+ |
SQL_TIME_TZ_EX, |
3286 |
+ |
SQL_TIME_TZ: |
3287 |
+ |
with PIBBufferedDateTimeWithTimeZone(data)^ do |
3288 |
+ |
Param.SetAsTime(Timestamp,DefaultTZDate,TimeZoneID); |
3289 |
|
SQL_BOOLEAN: |
3290 |
|
Param.AsBoolean := PWordBool(data)^; |
3291 |
+ |
SQL_DEC16, |
3292 |
+ |
SQL_DEC34, |
3293 |
+ |
SQL_DEC_FIXED, |
3294 |
+ |
SQL_INT128: |
3295 |
+ |
Param.AsBCD := pBCD(data)^; |
3296 |
+ |
else |
3297 |
+ |
IBError(ibxeUnknownSQLType,[fdDataType]); |
3298 |
|
end; |
3299 |
|
end; |
3300 |
|
end; |
3351 |
|
begin |
3352 |
|
CheckDatasetClosed; |
3353 |
|
FUniDirectional := Value; |
3354 |
+ |
inherited SetUniDirectional(Value); |
3355 |
|
end; |
3356 |
|
|
3357 |
|
procedure TIBCustomDataSet.SetUpdateRecordTypes(Value: TIBUpdateRecordTypes); |
3461 |
|
|
3462 |
|
function TIBCustomDataSet.ParamByName(ParamName: String): ISQLParam; |
3463 |
|
begin |
3464 |
+ |
Result := FindParam(ParamName); |
3465 |
+ |
if Result = nil then |
3466 |
+ |
IBError(ibxeParameterNameNotFound,[ParamName]); |
3467 |
+ |
end; |
3468 |
+ |
|
3469 |
+ |
function TIBCustomDataSet.FindParam(ParamName: String): ISQLParam; |
3470 |
+ |
begin |
3471 |
|
ActivateConnection; |
3472 |
|
ActivateTransaction; |
3473 |
|
if not FInternalPrepared then |
3550 |
|
procedure TIBCustomDataSet.ReadRecordCache(RecordNumber: Integer; Buffer: PChar; |
3551 |
|
ReadOldBuffer: Boolean); |
3552 |
|
begin |
3553 |
+ |
if RecordNumber = -1 then |
3554 |
+ |
Exit; {nothing to do} |
3555 |
|
if FUniDirectional then |
3556 |
|
RecordNumber := RecordNumber mod UniCache; |
3557 |
|
if (ReadOldBuffer) then |
3717 |
|
procedure TIBCustomDataSet.SetArrayIntf(AnArray: IArray; Field: TIBArrayField); |
3718 |
|
var Buff: PChar; |
3719 |
|
pda: PArrayDataArray; |
3720 |
+ |
MappedFieldPos: integer; |
3721 |
|
begin |
3722 |
|
if (Field = nil) or (Field.DataSet <> self) then |
3723 |
|
IBError(ibxFieldNotinDataSet,[Field.Name,Name]); |
3724 |
|
Buff := GetActiveBuf; |
3725 |
|
if Buff <> nil then |
3726 |
+ |
with PRecordData(Buff)^ do |
3727 |
|
begin |
3728 |
|
AdjustRecordOnInsert(Buff); |
3729 |
< |
pda := PArrayDataArray(Buff + FArrayCacheOffset); |
3730 |
< |
pda^[Field.FCacheOffset].FArray := AnArray; |
3731 |
< |
WriteRecordCache(PRecordData(Buff)^.rdRecordNumber, Pointer(Buff)); |
3729 |
> |
MappedFieldPos := FMappedFieldPosition[Field.FieldNo - 1]; |
3730 |
> |
if (MappedFieldPos > 0) and |
3731 |
> |
(MappedFieldPos <= rdFieldCount) then |
3732 |
> |
begin |
3733 |
> |
rdFields[MappedFieldPos].fdIsNull := AnArray = nil; |
3734 |
> |
pda := PArrayDataArray(Buff + FArrayCacheOffset); |
3735 |
> |
if pda^[Field.FCacheOffset] = nil then |
3736 |
> |
begin |
3737 |
> |
if not rdFields[MappedFieldPos].fdIsNull then |
3738 |
> |
begin |
3739 |
> |
pda^[Field.FCacheOffset] := TIBArray.Create(Field,AnArray); |
3740 |
> |
FArrayList.Add(pda^[Field.FCacheOffset]); |
3741 |
> |
end |
3742 |
> |
end |
3743 |
> |
else |
3744 |
> |
pda^[Field.FCacheOffset].FArray := AnArray; |
3745 |
> |
WriteRecordCache(PRecordData(Buff)^.rdRecordNumber, Pointer(Buff)); |
3746 |
> |
end; |
3747 |
|
end; |
3748 |
|
end; |
3749 |
|
|
3840 |
|
ApplyUpdates; |
3841 |
|
end; |
3842 |
|
|
3422 |
– |
procedure TIBCustomDataSet.DoBeforeOpen; |
3423 |
– |
var i: integer; |
3424 |
– |
begin |
3425 |
– |
if assigned(FParser) then |
3426 |
– |
FParser.Reset; |
3427 |
– |
for i := 0 to FIBLinks.Count - 1 do |
3428 |
– |
TIBControlLink(FIBLinks[i]).UpdateSQL(self); |
3429 |
– |
inherited DoBeforeOpen; |
3430 |
– |
for i := 0 to FIBLinks.Count - 1 do |
3431 |
– |
TIBControlLink(FIBLinks[i]).UpdateParams(self); |
3432 |
– |
end; |
3433 |
– |
|
3843 |
|
procedure TIBCustomDataSet.DoBeforePost; |
3844 |
|
begin |
3845 |
|
inherited DoBeforePost; |
3950 |
|
|
3951 |
|
function TIBCustomDataSet.InternalGetFieldData(Field: TField; Buffer: Pointer): Boolean; |
3952 |
|
var |
3953 |
< |
Buff, Data: PChar; |
3953 |
> |
Buff: PChar; |
3954 |
> |
Data: PByte; |
3955 |
|
CurrentRecord: PRecordData; |
3956 |
|
begin |
3957 |
|
result := False; |
3978 |
|
result := not fdIsNull; |
3979 |
|
if result and (Buffer <> nil) then |
3980 |
|
begin |
3981 |
< |
Data := Buff + fdDataOfs; |
3981 |
> |
Data := PByte(Buff) + fdDataOfs; |
3982 |
|
if (fdDataType = SQL_VARYING) or (fdDataType = SQL_TEXT) then |
3983 |
|
begin |
3984 |
< |
if fdDataLength < Field.DataSize then |
3984 |
> |
if fdDataLength <= Field.DataSize then |
3985 |
|
begin |
3986 |
|
Move(Data^, Buffer^, fdDataLength); |
3987 |
|
PChar(Buffer)[fdDataLength] := #0; |
3990 |
|
IBError(ibxeFieldSizeError,[Field.FieldName]) |
3991 |
|
end |
3992 |
|
else |
3993 |
< |
Move(Data^, Buffer^, Field.DataSize); |
3993 |
> |
if fdDataLength <= Field.DataSize then |
3994 |
> |
Move(Data^, Buffer^, Field.DataSize) |
3995 |
> |
else |
3996 |
> |
IBError(ibxeFieldSizeError,[Field.FieldName,Field.DataSize,fdDataLength]) |
3997 |
|
end; |
3998 |
|
end; |
3999 |
|
end; |
4164 |
|
Buff: PChar; |
4165 |
|
CurRec: Integer; |
4166 |
|
pda: PArrayDataArray; |
4167 |
+ |
pbd: PBlobDataArray; |
4168 |
|
i: integer; |
4169 |
|
begin |
4170 |
|
inherited InternalCancel; |
4172 |
|
if Buff <> nil then |
4173 |
|
begin |
4174 |
|
pda := PArrayDataArray(Buff + FArrayCacheOffset); |
4175 |
+ |
pbd := PBlobDataArray(Buff + FBlobCacheOffset); |
4176 |
|
for i := 0 to ArrayFieldCount - 1 do |
4177 |
|
pda^[i].ArrayIntf.CancelChanges; |
4178 |
|
CurRec := FCurrentRecord; |
4179 |
|
AdjustRecordOnInsert(Buff); |
4180 |
|
if (State = dsEdit) then begin |
4181 |
|
CopyRecordBuffer(FOldBuffer, Buff); |
4182 |
+ |
for i := 0 to BlobFieldCount - 1 do |
4183 |
+ |
pbd^[i] := nil; |
4184 |
|
WriteRecordCache(PRecordData(Buff)^.rdRecordNumber, Buff); |
4185 |
|
end else begin |
4186 |
|
CopyRecordBuffer(FModelBuffer, Buff); |
4198 |
|
if FDidActivate then |
4199 |
|
DeactivateTransaction; |
4200 |
|
FQSelect.Close; |
4201 |
< |
ClearBlobCache; |
3785 |
< |
ClearArrayCache; |
4201 |
> |
ResetBufferCache; |
4202 |
|
FreeRecordBuffer(FModelBuffer); |
4203 |
|
FreeRecordBuffer(FOldBuffer); |
4204 |
|
FCurrentRecord := -1; |
4205 |
|
FOpen := False; |
3790 |
– |
FRecordCount := 0; |
3791 |
– |
FDeletedRecords := 0; |
4206 |
|
FRecordSize := 0; |
3793 |
– |
FBPos := 0; |
3794 |
– |
FOBPos := 0; |
3795 |
– |
FCacheSize := 0; |
3796 |
– |
FOldCacheSize := 0; |
3797 |
– |
FBEnd := 0; |
3798 |
– |
FOBEnd := 0; |
3799 |
– |
FreeMem(FBufferCache); |
3800 |
– |
FBufferCache := nil; |
4207 |
|
FreeMem(FFieldColumns); |
4208 |
|
FFieldColumns := nil; |
3803 |
– |
FreeMem(FOldBufferCache); |
3804 |
– |
FOldBufferCache := nil; |
4209 |
|
BindFields(False); |
4210 |
|
ResetParser; |
4211 |
|
if DefaultFields then DestroyFields; |
4247 |
|
procedure TIBCustomDataSet.InternalFirst; |
4248 |
|
begin |
4249 |
|
FCurrentRecord := -1; |
4250 |
+ |
if Unidirectional then GetNextRecord; |
4251 |
|
end; |
4252 |
|
|
4253 |
|
procedure TIBCustomDataSet.InternalGotoBookmark(Bookmark: Pointer); |
4273 |
|
procedure TIBCustomDataSet.FieldDefsFromQuery(SourceQuery: TIBSQL); |
4274 |
|
const |
4275 |
|
DefaultSQL = 'Select F.RDB$COMPUTED_BLR, ' + {do not localize} |
4276 |
< |
'F.RDB$DEFAULT_VALUE, R.RDB$FIELD_NAME ' + {do not localize} |
4276 |
> |
'F.RDB$DEFAULT_VALUE, R.RDB$FIELD_NAME ' + {do not localize} |
4277 |
|
'from RDB$RELATION_FIELDS R, RDB$FIELDS F ' + {do not localize} |
4278 |
|
'where R.RDB$RELATION_NAME = :RELATION ' + {do not localize} |
4279 |
|
'and R.RDB$FIELD_SOURCE = F.RDB$FIELD_NAME '+ {do not localize} |
4306 |
|
aArrayDimensions: integer; |
4307 |
|
aArrayBounds: TArrayBounds; |
4308 |
|
ArrayMetaData: IArrayMetaData; |
4309 |
+ |
FieldHasTimeZone: boolean; |
4310 |
|
|
4311 |
|
function Add_Node(Relation, Field : String) : TRelationNode; |
4312 |
|
var |
4326 |
|
while not Query.Eof do |
4327 |
|
begin |
4328 |
|
FField := TFieldNode.Create; |
4329 |
< |
FField.FieldName := Query.Fields[2].AsString; |
4329 |
> |
FField.FieldName := TrimRight(Query.Fields[2].AsString); |
4330 |
|
FField.DEFAULT_VALUE := not Query.Fields[1].IsNull; |
4331 |
|
FField.COMPUTED_BLR := not Query.Fields[0].IsNull; |
4332 |
|
FField.IDENTITY_COLUMN := (Query.FieldCount > 3) and not Query.Fields[3].IsNull; |
4459 |
|
FieldDataSize := GetSize; |
4460 |
|
FieldPrecision := 0; |
4461 |
|
FieldNullable := IsNullable; |
4462 |
+ |
FieldHasTimeZone := false; |
4463 |
|
CharSetSize := 0; |
4464 |
|
CharSetName := ''; |
4465 |
|
FieldCodePage := CP_NONE; |
4508 |
|
FieldType := ftFloat |
4509 |
|
else |
4510 |
|
begin |
4511 |
< |
FieldType := ftFMTBCD; |
4511 |
> |
FieldType := ftBCD; |
4512 |
|
FieldPrecision := 9; |
4513 |
|
FieldSize := -getScale; |
4514 |
|
end; |
4530 |
|
SQL_TIMESTAMP: FieldType := ftDateTime; |
4531 |
|
SQL_TYPE_TIME: FieldType := ftTime; |
4532 |
|
SQL_TYPE_DATE: FieldType := ftDate; |
4533 |
+ |
SQL_TIMESTAMP_TZ, |
4534 |
+ |
SQL_TIMESTAMP_TZ_EX: |
4535 |
+ |
begin |
4536 |
+ |
FieldType := ftDateTime; |
4537 |
+ |
FieldHasTimeZone := true; |
4538 |
+ |
end; |
4539 |
+ |
SQL_TIME_TZ, |
4540 |
+ |
SQL_TIME_TZ_EX: |
4541 |
+ |
begin |
4542 |
+ |
FieldType := ftTime; |
4543 |
+ |
FieldHasTimeZone := true; |
4544 |
+ |
end; |
4545 |
|
SQL_BLOB: |
4546 |
|
begin |
4547 |
|
FieldSize := sizeof (TISC_QUAD); |
4569 |
|
end; |
4570 |
|
SQL_BOOLEAN: |
4571 |
|
FieldType:= ftBoolean; |
4572 |
+ |
|
4573 |
+ |
SQL_DEC16: |
4574 |
+ |
begin |
4575 |
+ |
FieldType := ftFmtBCD; |
4576 |
+ |
FieldPrecision := 16; |
4577 |
+ |
FieldSize := 4; {For conversions from currency type} |
4578 |
+ |
end; |
4579 |
+ |
|
4580 |
+ |
SQL_DEC34: |
4581 |
+ |
begin |
4582 |
+ |
FieldType := ftFmtBCD; |
4583 |
+ |
FieldPrecision := 34; |
4584 |
+ |
FieldSize := 4; {For conversions from currency type} |
4585 |
+ |
end; |
4586 |
+ |
|
4587 |
+ |
SQL_DEC_FIXED, |
4588 |
+ |
SQL_INT128: |
4589 |
+ |
begin |
4590 |
+ |
FieldType := ftFmtBCD; |
4591 |
+ |
FieldPrecision := 38; |
4592 |
+ |
FieldSize := -getScale; {For conversions from currency type} |
4593 |
+ |
end; |
4594 |
+ |
|
4595 |
|
else |
4596 |
|
FieldType := ftUnknown; |
4597 |
|
end; |
4615 |
|
CodePage := FieldCodePage; |
4616 |
|
ArrayDimensions := aArrayDimensions; |
4617 |
|
ArrayBounds := aArrayBounds; |
4618 |
+ |
HasTimezone := FieldHasTimeZone; |
4619 |
|
if (FieldName <> '') and (RelationName <> '') then |
4620 |
|
begin |
4621 |
|
IdentityColumn := Is_IDENTITY_COLUMN(RelationName, FieldName); |
4714 |
|
ftDate: |
4715 |
|
cur_param.AsDate := cur_field.AsDateTime; |
4716 |
|
ftTime: |
4717 |
< |
cur_param.AsTime := cur_field.AsDateTime; |
4717 |
> |
if (cur_field is TIBDateTimeField) and TIBDateTimeField(cur_field).HasTimeZone |
4718 |
> |
and (cur_param.GetSQLType = SQL_TIME_TZ) then |
4719 |
> |
cur_param.SetAsTime(cur_Field.asDateTime,DefaultTZDate,TIBDateTimeField(cur_field).TimeZoneID) |
4720 |
> |
else |
4721 |
> |
cur_param.AsTime := cur_field.AsDateTime; |
4722 |
|
ftDateTime: |
4723 |
< |
cur_param.AsDateTime := cur_field.AsDateTime; |
4723 |
> |
begin |
4724 |
> |
if (cur_field is TIBDateTimeField) and TIBDateTimeField(cur_field).HasTimeZone |
4725 |
> |
and (cur_param.GetSQLType = SQL_TIMESTAMP_TZ) then |
4726 |
> |
cur_param.SetAsDateTime(cur_field.AsDateTime,TIBDateTimeField(cur_field).TimeZoneID) |
4727 |
> |
else |
4728 |
> |
cur_param.AsDateTime := cur_field.AsDateTime; |
4729 |
> |
end; |
4730 |
|
ftBlob, ftMemo: |
4731 |
|
begin |
4732 |
|
s := nil; |
4740 |
|
end; |
4741 |
|
ftArray: |
4742 |
|
cur_param.AsArray := TIBArrayField(cur_field).ArrayIntf; |
4743 |
+ |
ftFmtBCD: |
4744 |
+ |
cur_param.AsBCD := TFmtBCDField(cur_field).AsBCD; |
4745 |
|
else |
4746 |
|
IBError(ibxeNotSupported, [nil]); |
4747 |
|
end; |
4767 |
|
First; |
4768 |
|
end; |
4769 |
|
|
4770 |
+ |
procedure TIBCustomDataSet.ResetBufferCache; |
4771 |
+ |
begin |
4772 |
+ |
ClearBlobCache; |
4773 |
+ |
ClearArrayCache; |
4774 |
+ |
FRecordCount := 0; |
4775 |
+ |
FDeletedRecords := 0; |
4776 |
+ |
FBPos := 0; |
4777 |
+ |
FOBPos := 0; |
4778 |
+ |
FCacheSize := 0; |
4779 |
+ |
FOldCacheSize := 0; |
4780 |
+ |
FBEnd := 0; |
4781 |
+ |
FOBEnd := 0; |
4782 |
+ |
FreeMem(FBufferCache); |
4783 |
+ |
FBufferCache := nil; |
4784 |
+ |
FreeMem(FOldBufferCache); |
4785 |
+ |
FOldBufferCache := nil; |
4786 |
+ |
end; |
4787 |
+ |
|
4788 |
|
procedure TIBCustomDataSet.InternalOpen; |
4789 |
|
|
4790 |
|
function RecordDataLength(n: Integer): Long; |
4992 |
|
|
4993 |
|
procedure TIBCustomDataSet.SetBookmarkData(Buffer: PChar; Data: Pointer); |
4994 |
|
begin |
4995 |
< |
PRecordData(Buffer)^.rdRecordNumber := PInteger(Data)^; |
4995 |
> |
if Data <> nil then |
4996 |
> |
PRecordData(Buffer)^.rdRecordNumber := PInteger(Data)^; |
4997 |
|
end; |
4998 |
|
|
4999 |
|
procedure TIBCustomDataSet.SetBookmarkFlag(Buffer: PChar; Value: TBookmarkFlag); |
5049 |
|
fdIsNull := True |
5050 |
|
else |
5051 |
|
begin |
5052 |
< |
Move(Buffer^, Buff[fdDataOfs],fdDataSize); |
5052 |
> |
if fdDataSize >= Field.DataSize then |
5053 |
> |
Move(Buffer^, Buff[fdDataOfs],fdDataSize) |
5054 |
> |
else |
5055 |
> |
IBError(ibxeDBBufferTooSmall,[fdDataSize,Field.FieldName,Field.DataSize]); |
5056 |
> |
|
5057 |
|
if (fdDataType = SQL_TEXT) or (fdDataType = SQL_VARYING) then |
5058 |
|
fdDataLength := StrLen(PChar(Buffer)); |
5059 |
|
fdIsNull := False; |
5197 |
|
Result := FQSelect.Statement; |
5198 |
|
end; |
5199 |
|
|
5200 |
+ |
procedure TIBCustomDataSet.SetCaseSensitiveParameterNames(AValue: boolean); |
5201 |
+ |
begin |
5202 |
+ |
if FCaseSensitiveParameterNames = AValue then Exit; |
5203 |
+ |
FCaseSensitiveParameterNames := AValue; |
5204 |
+ |
if assigned(FQSelect) then |
5205 |
+ |
FQSelect.CaseSensitiveParameterNames := AValue; |
5206 |
+ |
end; |
5207 |
+ |
|
5208 |
+ |
procedure TIBCustomDataSet.SetDefaultTZDate(AValue: TDateTime); |
5209 |
+ |
begin |
5210 |
+ |
FDefaultTZDate := DateOf(AValue); |
5211 |
+ |
end; |
5212 |
+ |
|
5213 |
+ |
procedure TIBCustomDataSet.SetSQLFiltered(AValue: boolean); |
5214 |
+ |
begin |
5215 |
+ |
if FSQLFiltered = AValue then Exit; |
5216 |
+ |
FSQLFiltered := AValue; |
5217 |
+ |
if Active then |
5218 |
+ |
begin |
5219 |
+ |
Active := false; |
5220 |
+ |
Active := true; |
5221 |
+ |
end; |
5222 |
+ |
end; |
5223 |
+ |
|
5224 |
+ |
procedure TIBCustomDataSet.SetSQLFilterParams(AValue: TStrings); |
5225 |
+ |
begin |
5226 |
+ |
if FSQLFilterParams = AValue then Exit; |
5227 |
+ |
FSQLFilterParams.Assign(AValue); |
5228 |
+ |
end; |
5229 |
+ |
|
5230 |
|
procedure TIBCustomDataSet.SetMasterDetailDelay(AValue: integer); |
5231 |
|
begin |
5232 |
|
FDataLink.DelayTimerValue := AValue; |
5239 |
|
Result := FParser |
5240 |
|
end; |
5241 |
|
|
5242 |
+ |
procedure TIBCustomDataSet.HandleSQLFilterParamsChanged(Sender: TObject); |
5243 |
+ |
begin |
5244 |
+ |
Active := false; |
5245 |
+ |
end; |
5246 |
+ |
|
5247 |
|
procedure TIBCustomDataSet.ResetParser; |
5248 |
|
begin |
5249 |
|
if assigned(FParser) then |
5588 |
|
function TIBDataSetUpdateObject.GetRowsAffected( |
5589 |
|
var SelectCount, InsertCount, UpdateCount, DeleteCount: integer): boolean; |
5590 |
|
begin |
5591 |
+ |
Result := true; |
5592 |
|
SelectCount := 0; |
5593 |
|
InsertCount := 0; |
5594 |
|
UpdateCount := 0; |
5698 |
|
|
5699 |
|
procedure TIBGenerator.SetQuerySQL; |
5700 |
|
begin |
5701 |
< |
FQuery.SQL.Text := Format('Select Gen_ID(%s,%d) From RDB$Database',[FGeneratorName,Increment]); |
5701 |
> |
if (Database <> nil) and (FGeneratorName <> '') then |
5702 |
> |
FQuery.SQL.Text := Format('Select Gen_ID(%s,%d) From RDB$Database', |
5703 |
> |
[QuoteIdentifierIfNeeded(Database.SQLDialect,FGeneratorName),Increment]); |
5704 |
|
end; |
5705 |
|
|
5706 |
|
function TIBGenerator.GetDatabase: TIBDatabase; |
5716 |
|
procedure TIBGenerator.SetDatabase(AValue: TIBDatabase); |
5717 |
|
begin |
5718 |
|
FQuery.Database := AValue; |
5719 |
+ |
SetQuerySQL; |
5720 |
|
end; |
5721 |
|
|
5722 |
|
procedure TIBGenerator.SetGeneratorName(AValue: string); |
5761 |
|
Owner.FieldByName(FFieldName).AsInteger := GetNextValue; |
5762 |
|
end; |
5763 |
|
|
5764 |
+ |
initialization |
5765 |
+ |
RegisterClasses([TIBArrayField,TIBStringField,TIBBCDField, |
5766 |
+ |
TIBSmallintField,TIBIntegerField,TIBLargeIntField, |
5767 |
+ |
TIBMemoField, TIBDateTimeField, TIBTimeField]); |
5768 |
+ |
|
5769 |
|
|
5770 |
|
end. |