ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/public/ibx/branches/journaling/runtime/nongui/IBCustomDataSet.pas
(Generate patch)

Comparing:
ibx/trunk/runtime/nongui/IBCustomDataSet.pas (file contents), Revision 209 by tony, Wed Mar 14 12:48:51 2018 UTC vs.
ibx/branches/journaling/runtime/nongui/IBCustomDataSet.pas (file contents), Revision 362 by tony, Tue Dec 7 13:27:39 2021 UTC

# Line 49 | Line 49 | interface
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;
# Line 87 | Line 84 | type
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
# Line 107 | Line 102 | type
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)
# Line 293 | Line 243 | type
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;
# Line 310 | Line 318 | type
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);
# Line 364 | Line 372 | type
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;
# Line 374 | Line 380 | type
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;
# Line 429 | Line 499 | type
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;
# Line 463 | Line 536 | type
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  
# Line 496 | Line 573 | type
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;
# Line 580 | Line 658 | type
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;
# Line 616 | Line 693 | type
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);
# Line 639 | Line 717 | type
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;
# Line 652 | Line 734 | type
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;
# Line 705 | Line 788 | type
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;
# Line 714 | Line 798 | type
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}
# Line 762 | Line 847 | type
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;
# Line 799 | Line 888 | type
888      property AutoCommit;
889      property BufferChunks;
890      property CachedUpdates;
891 +    property CaseSensitiveParameterNames;
892      property EnableStatistics;
893      property DeleteSQL;
894      property InsertSQL;
# Line 812 | Line 902 | type
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;
# Line 880 | Line 974 | type
974      FCharacterSetName: RawByteString;
975      FCharacterSetSize: integer;
976      FCodePage: TSystemCodePage;
977 +    FHasTimeZone: boolean;
978      FIdentityColumn: boolean;
979      FRelationName: string;
980      FDataSize: integer;
# Line 892 | Line 987 | type
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 }
# Line 920 | Line 1016 | DefaultFieldClasses: array[TFieldType] o
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  
# Line 1018 | Line 1110 | type
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);
# Line 1156 | Line 1500 | begin
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;
# Line 1264 | Line 1616 | begin
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;
# Line 1307 | Line 1659 | var
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
# Line 1316 | Line 1668 | begin
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);
# Line 1332 | Line 1691 | var
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);
# Line 1409 | Line 1768 | constructor TIBDataLink.Create(ADataSet:
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  
# Line 1445 | Line 1818 | procedure TIBDataLink.RecordChanged(Fiel
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;
# Line 1479 | Line 1854 | begin
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;
# Line 1492 | Line 1867 | begin
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;
# Line 1513 | Line 1888 | begin
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;
# Line 1535 | Line 1914 | begin
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  
# Line 1619 | Line 1999 | var
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;
# Line 1637 | Line 2015 | var
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  
# Line 1656 | Line 2037 | var
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;
# Line 1687 | Line 2064 | begin
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;
# Line 1885 | Line 2260 | var
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;
# Line 1908 | Line 2283 | end;
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;
# Line 2076 | Line 2451 | begin
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
# Line 2103 | Line 2483 | begin
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);
# Line 2136 | Line 2521 | procedure TIBCustomDataSet.ColumnDataToB
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];
# Line 2155 | Line 2536 | begin
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  
# Line 2561 | Line 2940 | begin
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;
# Line 2676 | Line 3055 | begin
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
# Line 2816 | Line 3195 | end;
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;
# Line 2866 | Line 3245 | begin
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;
# Line 2899 | Line 3278 | begin
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;
# Line 2957 | Line 3351 | procedure TIBCustomDataSet.SetUniDirecti
3351   begin
3352    CheckDatasetClosed;
3353    FUniDirectional := Value;
3354 +  inherited SetUniDirectional(Value);
3355   end;
3356  
3357   procedure TIBCustomDataSet.SetUpdateRecordTypes(Value: TIBUpdateRecordTypes);
# Line 3066 | Line 3461 | end;
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
# Line 3148 | Line 3550 | end;
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
# Line 3313 | Line 3717 | end;
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  
# Line 3419 | Line 3840 | begin
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;
# Line 3541 | Line 3950 | end;
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;
# Line 3568 | Line 3978 | begin
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;
# Line 3580 | Line 3990 | begin
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;
# Line 3751 | Line 4164 | var
4164    Buff: PChar;
4165    CurRec: Integer;
4166    pda: PArrayDataArray;
4167 +  pbd: PBlobDataArray;
4168    i: integer;
4169   begin
4170    inherited InternalCancel;
# Line 3758 | Line 4172 | begin
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);
# Line 3781 | Line 4198 | begin
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;
# Line 3843 | Line 4247 | end;
4247   procedure TIBCustomDataSet.InternalFirst;
4248   begin
4249    FCurrentRecord := -1;
4250 +  if Unidirectional then GetNextRecord;
4251   end;
4252  
4253   procedure TIBCustomDataSet.InternalGotoBookmark(Bookmark: Pointer);
# Line 3868 | Line 4273 | begin
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}
# Line 3901 | Line 4306 | var
4306    aArrayDimensions: integer;
4307    aArrayBounds: TArrayBounds;
4308    ArrayMetaData: IArrayMetaData;
4309 +  FieldHasTimeZone: boolean;
4310  
4311    function Add_Node(Relation, Field : String) : TRelationNode;
4312    var
# Line 3920 | Line 4326 | 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;
# Line 4053 | Line 4459 | begin
4459          FieldDataSize := GetSize;
4460          FieldPrecision := 0;
4461          FieldNullable := IsNullable;
4462 +        FieldHasTimeZone := false;
4463          CharSetSize := 0;
4464          CharSetName := '';
4465          FieldCodePage := CP_NONE;
# Line 4101 | Line 4508 | begin
4508                FieldType := ftFloat
4509              else
4510              begin
4511 <              FieldType := ftFMTBCD;
4511 >              FieldType := ftBCD;
4512                FieldPrecision := 9;
4513                FieldSize := -getScale;
4514              end;
# Line 4123 | Line 4530 | begin
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);
# Line 4150 | Line 4569 | begin
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;
# Line 4173 | Line 4615 | begin
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);
# Line 4271 | Line 4714 | begin
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;
# Line 4287 | Line 4740 | begin
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;
# Line 4312 | Line 4767 | begin
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;
# Line 4519 | Line 4992 | end;
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);
# Line 4575 | Line 5049 | begin
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;
# Line 4719 | Line 5197 | begin
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;
# Line 4731 | Line 5239 | begin
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
# Line 5075 | Line 5588 | end;
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;
# Line 5184 | Line 5698 | end;
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;
# Line 5200 | Line 5716 | end;
5716   procedure TIBGenerator.SetDatabase(AValue: TIBDatabase);
5717   begin
5718    FQuery.Database := AValue;
5719 +  SetQuerySQL;
5720   end;
5721  
5722   procedure TIBGenerator.SetGeneratorName(AValue: string);
# Line 5244 | Line 5761 | begin
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.

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines