ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/public/ibx/branches/udr/client/FBSQLData.pas
(Generate patch)

Comparing:
ibx/trunk/fbintf/client/FBSQLData.pas (file contents), Revision 45 by tony, Tue Dec 6 10:33:46 2016 UTC vs.
ibx/branches/udr/client/FBSQLData.pas (file contents), Revision 370 by tony, Wed Jan 5 14:59:15 2022 UTC

# Line 60 | Line 60
60   {                                                                        }
61   {************************************************************************}
62   unit FBSQLData;
63 + {$IFDEF MSWINDOWS}
64 + {$DEFINE WINDOWS}
65 + {$ENDIF}
66  
67   {$IFDEF FPC}
68 < {$mode objfpc}{$H+}
68 > {$mode delphi}
69   {$codepage UTF8}
70   {$interfaces COM}
71   {$ENDIF}
# Line 73 | Line 76 | unit FBSQLData;
76    methods are needed for SQL parameters only. The string getters and setters
77    are virtual as SQLVar and Array encodings of string data is different.}
78  
76 { $define ALLOWDIALECT3PARAMNAMES}
77
78 {$ifndef ALLOWDIALECT3PARAMNAMES}
79
80 { Note on SQL Dialects and SQL Parameter Names
81  --------------------------------------------
82
83  Even when dialect 3 quoted format parameter names are not supported, IBX still processes
84  parameter names case insensitive. This does result in some additional overhead
85  due to a call to "AnsiUpperCase". This can be avoided by undefining
86  "UseCaseInSensitiveParamName" below.
87
88  Note: do not define "UseCaseSensitiveParamName" when "ALLOWDIALECT3PARAMNAMES"
89  is defined. This will not give a useful result.
90 }
91 {$define UseCaseInSensitiveParamName}
92 {$endif}
79  
80   interface
81  
82   uses
83 <  Classes, SysUtils, IBExternals, IBHeader, IB,  FBActivityMonitor;
83 >  Classes, SysUtils, IBExternals, {$IFDEF WINDOWS} Windows, {$ENDIF} IB,  FBActivityMonitor, FBClientAPI,
84 >  FmtBCD;
85  
86   type
87  
88 <  { TSQLDataItem }
88 >   {The IExTimeZoneServices is only available in FB4 and onwards}
89 >
90 >   IExTimeZoneServices = interface(ITimeZoneServices)
91 >   ['{789c2eeb-c4a7-4fed-837e-0cbdef775904}']
92 >   {encode/decode - used to encode/decode the wire protocol}
93 >   procedure EncodeTimestampTZ(timestamp: TDateTime; timezoneID: TFBTimeZoneID;
94 >     bufptr: PByte); overload;
95 >   procedure EncodeTimestampTZ(timestamp: TDateTime; timezone: AnsiString;
96 >       bufptr: PByte); overload;
97 >   procedure EncodeTimeTZ(time: TDateTime; timezoneID: TFBTimeZoneID; OnDate: TDateTime;
98 >     bufptr: PByte); overload;
99 >   procedure EncodeTimeTZ(time: TDateTime; timezone: AnsiString; OnDate: TDateTime;
100 >     bufptr: PByte); overload;
101 >   procedure DecodeTimestampTZ(bufptr: PByte; var timestamp: TDateTime;
102 >     var dstOffset: smallint; var timezoneID: TFBTimeZoneID); overload;
103 >   procedure DecodeTimestampTZ(bufptr: PByte; var timestamp: TDateTime;
104 >     var dstOffset: smallint; var timezone: AnsiString); overload;
105 >   procedure DecodeTimestampTZEx(bufptr: PByte; var timestamp: TDateTime;
106 >     var dstOffset: smallint; var timezoneID: TFBTimeZoneID); overload;
107 >   procedure DecodeTimestampTZEx(bufptr: PByte; var timestamp: TDateTime;
108 >     var dstOffset: smallint; var timezone: AnsiString); overload;
109 >   procedure DecodeTimeTZ(bufptr: PByte; OnDate: TDateTime; var time: TDateTime;
110 >     var dstOffset: smallint; var timezoneID: TFBTimeZoneID); overload;
111 >   procedure DecodeTimeTZ(bufptr: PByte; OnDate: TDateTime; var time: TDateTime;
112 >     var dstOffset: smallint; var timezone: AnsiString); overload;
113 >   procedure DecodeTimeTZEx(bufptr: PByte; OnDate: TDateTime; var time: TDateTime;
114 >     var dstOffset: smallint; var timezoneID: TFBTimeZoneID); overload;
115 >   procedure DecodeTimeTZEx(bufptr: PByte; OnDate: TDateTime; var time: TDateTime;
116 >     var dstOffset: smallint; var timezone: AnsiString); overload;
117 >   end;
118 >
119 >   { TSQLDataItem }
120  
121    TSQLDataItem = class(TFBInterfacedObject)
122    private
123 +     FFirebirdClientAPI: TFBClientAPI;
124 +     FTimeZoneServices: IExTimeZoneServices;
125 +     function GetDateFormatStr(IncludeTime: boolean): AnsiString;
126 +     function GetTimeFormatStr: AnsiString;
127 +     function GetTimestampFormatStr: AnsiString;
128 +     procedure SetAsInteger(AValue: Integer);
129 +     procedure InternalGetAsDateTime(var aDateTime: TDateTime; var dstOffset: smallint;
130 +       var aTimezone: AnsiString; var aTimeZoneID: TFBTimeZoneID);
131 +  protected
132       function AdjustScale(Value: Int64; aScale: Integer): Double;
133       function AdjustScaleToInt64(Value: Int64; aScale: Integer): Int64;
134 +     function AdjustScaleToStr(Value: Int64; aScale: Integer): AnsiString;
135       function AdjustScaleToCurrency(Value: Int64; aScale: Integer): Currency;
108     procedure SetAsInteger(AValue: Integer);
109  protected
136       function AdjustScaleFromCurrency(Value: Currency; aScale: Integer): Int64;
137       function AdjustScaleFromDouble(Value: Double; aScale: Integer): Int64;
138       procedure CheckActive; virtual;
139 +     procedure CheckTZSupport;
140 +     function GetAttachment: IAttachment; virtual; abstract;
141       function GetSQLDialect: integer; virtual; abstract;
142 +     function GetTimeZoneServices: IExTimeZoneServices; virtual;
143       procedure Changed; virtual;
144       procedure Changing; virtual;
145 <     procedure InternalSetAsString(Value: String); virtual;
146 <     function SQLData: PChar; virtual; abstract;
145 >     procedure InternalSetAsString(Value: AnsiString); virtual;
146 >     function SQLData: PByte; virtual; abstract;
147       function GetDataLength: cardinal; virtual; abstract;
148       function GetCodePage: TSystemCodePage; virtual; abstract;
149 <     function Transliterate(s: string; CodePage: TSystemCodePage): RawByteString;
149 >     function getCharSetID: cardinal; virtual; abstract;
150 >     function Transliterate(s: AnsiString; CodePage: TSystemCodePage): RawByteString;
151       procedure SetScale(aValue: integer); virtual;
152       procedure SetDataLength(len: cardinal); virtual;
153       procedure SetSQLType(aValue: cardinal); virtual;
154       property DataLength: cardinal read GetDataLength write SetDataLength;
155 <
155 >     property FirebirdClientAPI: TFBClientAPI read FFirebirdClientAPI;
156    public
157 <     function GetSQLType: cardinal; virtual; abstract;
158 <     function GetSQLTypeName: string; overload;
159 <     class function GetSQLTypeName(SQLType: short): string; overload;
160 <     function GetName: string; virtual; abstract;
161 <     function GetScale: integer; virtual; abstract;
157 >     constructor Create(api: TFBClientAPI);
158 >     function GetSQLType: cardinal; virtual; abstract; {Current Field Data SQL Type}
159 >     function GetSQLTypeName: AnsiString; overload;
160 >     class function GetSQLTypeName(SQLType: cardinal): AnsiString; overload;
161 >     function GetStrDataLength: short;
162 >     function GetName: AnsiString; virtual; abstract;
163 >     function GetScale: integer; virtual; abstract; {Current Field Data scale}
164       function GetAsBoolean: boolean;
165       function GetAsCurrency: Currency;
166       function GetAsInt64: Int64;
167 <     function GetAsDateTime: TDateTime;
167 >     function GetAsDateTime: TDateTime; overload;
168 >     procedure GetAsDateTime(var aDateTime: TDateTime; var dstOffset: smallint; var aTimezone: AnsiString); overload;
169 >     procedure GetAsDateTime(var aDateTime: TDateTime; var dstOffset: smallint; var aTimezoneID: TFBTimeZoneID); overload;
170 >     procedure GetAsTime(var aTime: TDateTime; var dstOffset: smallint; var aTimezoneID: TFBTimeZoneID; OnDate: TDateTime); overload;
171 >     procedure GetAsTime(var aTime: TDateTime; var dstOffset: smallint; var aTimezone: AnsiString; OnDate: TDateTime); overload;
172 >     procedure GetAsTime(var aTime: TDateTime; var dstOffset: smallint; var aTimezoneID: TFBTimeZoneID); overload;
173 >     procedure GetAsTime(var aTime: TDateTime; var dstOffset: smallint; var aTimezone: AnsiString); overload;
174 >     function GetAsUTCDateTime: TDateTime;
175       function GetAsDouble: Double;
176       function GetAsFloat: Float;
177       function GetAsLong: Long;
178       function GetAsPointer: Pointer;
179       function GetAsQuad: TISC_QUAD;
180       function GetAsShort: short;
181 <     function GetAsString: String; virtual;
181 >     function GetAsString: AnsiString; virtual;
182       function GetIsNull: Boolean; virtual;
183 <     function getIsNullable: boolean; virtual;
183 >     function GetIsNullable: boolean; virtual;
184       function GetAsVariant: Variant;
185       function GetModified: boolean; virtual;
186 +     function GetDateTimeStrLength(DateTimeFormat: TIBDateTimeFormats): integer;
187 +     function GetAsBCD: tBCD;
188 +     function GetSize: cardinal; virtual; abstract;
189 +     function GetCharSetWidth: integer; virtual; abstract;
190       procedure SetAsBoolean(AValue: boolean); virtual;
191       procedure SetAsCurrency(Value: Currency); virtual;
192       procedure SetAsInt64(Value: Int64); virtual;
193       procedure SetAsDate(Value: TDateTime); virtual;
194       procedure SetAsLong(Value: Long); virtual;
195 <     procedure SetAsTime(Value: TDateTime); virtual;
196 <     procedure SetAsDateTime(Value: TDateTime);
195 >     procedure SetAsTime(Value: TDateTime); overload;
196 >     procedure SetAsTime(aValue: TDateTime; OnDate: TDateTime;aTimeZoneID: TFBTimeZoneID); overload;
197 >     procedure SetAsTime(aValue: TDateTime; OnDate: TDateTime; aTimeZone: AnsiString); overload;
198 >     procedure SetAsDateTime(Value: TDateTime); overload;
199 >     procedure SetAsDateTime(aValue: TDateTime; aTimeZoneID: TFBTimeZoneID); overload;
200 >     procedure SetAsDateTime(aValue: TDateTime; aTimeZone: AnsiString); overload;
201 >     procedure SetAsUTCDateTime(aUTCTime: TDateTime);
202       procedure SetAsDouble(Value: Double); virtual;
203       procedure SetAsFloat(Value: Float); virtual;
204       procedure SetAsPointer(Value: Pointer);
205       procedure SetAsQuad(Value: TISC_QUAD);
206       procedure SetAsShort(Value: short); virtual;
207 <     procedure SetAsString(Value: String); virtual;
207 >     procedure SetAsString(Value: AnsiString); virtual;
208       procedure SetAsVariant(Value: Variant);
209 +     procedure SetAsNumeric(Value: Int64; aScale: integer); virtual;
210 +     procedure SetAsBcd(aValue: tBCD); virtual;
211       procedure SetIsNull(Value: Boolean); virtual;
212       procedure SetIsNullable(Value: Boolean); virtual;
213 <     procedure SetName(aValue: string); virtual;
213 >     procedure SetName(aValue: AnsiString); virtual;
214       property AsDate: TDateTime read GetAsDateTime write SetAsDate;
215       property AsBoolean:boolean read GetAsBoolean write SetAsBoolean;
216       property AsTime: TDateTime read GetAsDateTime write SetAsTime;
# Line 174 | Line 224 | type
224       property AsPointer: Pointer read GetAsPointer write SetAsPointer;
225       property AsQuad: TISC_QUAD read GetAsQuad write SetAsQuad;
226       property AsShort: short read GetAsShort write SetAsShort;
227 <     property AsString: String read GetAsString write SetAsString;
227 >     property AsString: AnsiString read GetAsString write SetAsString;
228       property AsVariant: Variant read GetAsVariant write SetAsVariant;
229       property Modified: Boolean read getModified;
230       property IsNull: Boolean read GetIsNull write SetIsNull;
# Line 191 | Line 241 | type
241  
242    TSQLDataArea = class
243    private
244 +    FCaseSensitiveParams: boolean;
245      function GetColumn(index: integer): TSQLVarData;
246      function GetCount: integer;
247    protected
248 <    FUniqueRelationName: string;
248 >    FUniqueRelationName: AnsiString;
249      FColumnList: array of TSQLVarData;
250      function GetStatement: IStatement; virtual; abstract;
251      function GetPrepareSeqNo: integer; virtual; abstract;
# Line 204 | Line 255 | type
255    public
256      procedure Initialize; virtual;
257      function IsInputDataArea: boolean; virtual; abstract; {Input to Database}
258 <    procedure PreprocessSQL(sSQL: string; GenerateParamNames: boolean;
259 <      var sProcessedSQL: string);
258 >    procedure PreprocessSQL(sSQL: AnsiString; GenerateParamNames: boolean;
259 >      var sProcessedSQL: AnsiString);
260      function ColumnsInUseCount: integer; virtual;
261 <    function ColumnByName(Idx: string): TSQLVarData;
261 >    function ColumnByName(Idx: AnsiString): TSQLVarData;
262      function CheckStatementStatus(Request: TStatementStatus): boolean; virtual; abstract;
263      procedure GetData(index: integer; var IsNull: boolean; var len: short;
264 <      var data: PChar); virtual;
264 >      var data: PByte); virtual;
265      procedure RowChange;
266      function StateChanged(var ChangeSeqNo: integer): boolean; virtual; abstract;
267 +    property CaseSensitiveParams: boolean read FCaseSensitiveParams
268 +                                            write FCaseSensitiveParams; {Only used when IsInputDataArea true}
269 +    function CanChangeMetaData: boolean; virtual; abstract;
270      property Count: integer read GetCount;
271      property Column[index: integer]: TSQLVarData read GetColumn;
272 <    property UniqueRelationName: string read FUniqueRelationName;
272 >    property UniqueRelationName: AnsiString read FUniqueRelationName;
273      property Statement: IStatement read GetStatement;
274      property PrepareSeqNo: integer read GetPrepareSeqNo;
275      property TransactionSeqNo: integer read GetTransactionSeqNo;
# Line 226 | Line 280 | type
280    TSQLVarData = class
281    private
282      FParent: TSQLDataArea;
283 <    FName: string;
283 >    FName: AnsiString;
284      FIndex: integer;
285      FModified: boolean;
286      FUniqueName: boolean;
287      FVarString: RawByteString;
288 +    FColMetaData: IParamMetaData;
289      function GetStatement: IStatement;
290 <    procedure SetName(AValue: string);
290 >    procedure SetName(AValue: AnsiString);
291    protected
292 +    FArrayIntf: IArray;
293 +    function GetAttachment: IAttachment; virtual; abstract;
294      function GetSQLType: cardinal; virtual; abstract;
295      function GetSubtype: integer; virtual; abstract;
296 <    function GetAliasName: string;  virtual; abstract;
297 <    function GetFieldName: string; virtual; abstract;
298 <    function GetOwnerName: string;  virtual; abstract;
299 <    function GetRelationName: string;  virtual; abstract;
296 >    function GetAliasName: AnsiString;  virtual; abstract;
297 >    function GetFieldName: AnsiString; virtual; abstract;
298 >    function GetOwnerName: AnsiString;  virtual; abstract;
299 >    function GetRelationName: AnsiString;  virtual; abstract;
300      function GetScale: integer; virtual; abstract;
301      function GetCharSetID: cardinal; virtual; abstract;
302 +    function GetCharSetWidth: integer; virtual; abstract;
303      function GetCodePage: TSystemCodePage; virtual; abstract;
304      function GetIsNull: Boolean;   virtual; abstract;
305      function GetIsNullable: boolean; virtual; abstract;
306 <    function GetSQLData: PChar;  virtual; abstract;
307 <    function GetDataLength: cardinal; virtual; abstract;
306 >    function GetSQLData: PByte;  virtual; abstract;
307 >    function GetDataLength: cardinal; virtual; abstract; {current field length}
308 >    function GetSize: cardinal; virtual; abstract; {field length as given by metadata}
309 >    function GetDefaultTextSQLType: cardinal; virtual; abstract;
310      procedure SetIsNull(Value: Boolean); virtual; abstract;
311      procedure SetIsNullable(Value: Boolean);  virtual; abstract;
312 <    procedure SetSQLData(AValue: PChar; len: cardinal); virtual; abstract;
312 >    procedure SetSQLData(AValue: PByte; len: cardinal); virtual; abstract;
313      procedure SetScale(aValue: integer); virtual; abstract;
314      procedure SetDataLength(len: cardinal); virtual; abstract;
315      procedure SetSQLType(aValue: cardinal); virtual; abstract;
316      procedure SetCharSetID(aValue: cardinal); virtual; abstract;
317 +    procedure SetMetaSize(aValue: cardinal); virtual;
318    public
319      constructor Create(aParent: TSQLDataArea; aIndex: integer);
320 <    procedure SetString(aValue: string);
320 >    procedure SetString(aValue: AnsiString);
321      procedure Changed; virtual;
322      procedure RowChange; virtual;
323 <    function GetAsArray(Array_ID: TISC_QUAD): IArray; virtual; abstract;
323 >    function GetAsArray: IArray; virtual; abstract;
324      function GetAsBlob(Blob_ID: TISC_QUAD; BPB: IBPB): IBlob; virtual; abstract;
325      function CreateBlob: IBlob; virtual; abstract;
326      function GetArrayMetaData: IArrayMetaData; virtual; abstract;
327      function GetBlobMetaData: IBlobMetaData; virtual; abstract;
328 +    function getColMetadata: IParamMetaData;
329      procedure Initialize; virtual;
330 +    procedure SaveMetaData;
331 +    procedure SetArray(AValue: IArray);
332  
333    public
334 <    property AliasName: string read GetAliasName;
335 <    property FieldName: string read GetFieldName;
336 <    property OwnerName: string read GetOwnerName;
337 <    property RelationName: string read GetRelationName;
334 >    property AliasName: AnsiString read GetAliasName;
335 >    property FieldName: AnsiString read GetFieldName;
336 >    property OwnerName: AnsiString read GetOwnerName;
337 >    property RelationName: AnsiString read GetRelationName;
338      property Parent: TSQLDataArea read FParent;
339      property Index: integer read FIndex;
340 <    property Name: string read FName write SetName;
340 >    property Name: AnsiString read FName write SetName;
341      property CharSetID: cardinal read GetCharSetID write SetCharSetID;
342      property SQLType: cardinal read GetSQLType write SetSQLType;
343      property SQLSubtype: integer read GetSubtype;
344 <    property SQLData: PChar read GetSQLData;
344 >    property SQLData: PByte read GetSQLData;
345      property DataLength: cardinal read GetDataLength write SetDataLength;
346      property IsNull: Boolean read GetIsNull write SetIsNull;
347      property IsNullable: Boolean read GetIsNullable write SetIsNullable;
# Line 295 | Line 359 | type
359      FIBXSQLVAR: TSQLVarData;
360      FOwner: IUnknown;         {Keep reference to ensure Metadata/statement not discarded}
361      FPrepareSeqNo: integer;
298    FStatement: IStatement;
362      FChangeSeqNo: integer;
363    protected
364      procedure CheckActive; override;
365 <    function SQLData: PChar; override;
365 >    function GetAttachment: IAttachment; override;
366 >    function SQLData: PByte; override;
367      function GetDataLength: cardinal; override;
368      function GetCodePage: TSystemCodePage; override;
369  
# Line 307 | Line 371 | type
371      constructor Create(aOwner: IUnknown; aIBXSQLVAR: TSQLVarData);
372      destructor Destroy; override;
373      function GetSQLDialect: integer; override;
310    property Statement: IStatement read FStatement;
374  
375    public
376      {IColumnMetaData}
377      function GetIndex: integer;
378      function GetSQLType: cardinal; override;
379      function getSubtype: integer;
380 <    function getRelationName: string;
381 <    function getOwnerName: string;
382 <    function getSQLName: string;    {Name of the column}
383 <    function getAliasName: string;  {Alias Name of column or Column Name if not alias}
384 <    function GetName: string; override;      {Disambiguated uppercase Field Name}
380 >    function getRelationName: AnsiString;
381 >    function getOwnerName: AnsiString;
382 >    function getSQLName: AnsiString;    {Name of the column}
383 >    function getAliasName: AnsiString;  {Alias Name of column or Column Name if not alias}
384 >    function GetName: AnsiString; override;      {Disambiguated uppercase Field Name}
385      function GetScale: integer; override;
386 <    function getCharSetID: cardinal;
386 >    function getCharSetID: cardinal; override;
387      function GetIsNullable: boolean; override;
388 <    function GetSize: cardinal;
388 >    function GetSize: cardinal; override;
389 >    function GetCharSetWidth: integer; override;
390      function GetArrayMetaData: IArrayMetaData;
391      function GetBlobMetaData: IBlobMetaData;
392 <    property Name: string read GetName;
392 >    function GetStatement: IStatement;
393 >    function GetTransaction: ITransaction; virtual;
394 >    property Name: AnsiString read GetName;
395      property Size: cardinal read GetSize;
396      property CharSetID: cardinal read getCharSetID;
397      property SQLSubtype: integer read getSubtype;
398      property IsNullable: Boolean read GetIsNullable;
399 +  public
400 +    property Statement: IStatement read GetStatement;
401    end;
402  
403    { TIBSQLData }
404  
405    TIBSQLData = class(TColumnMetaData,ISQLData)
406 +  private
407 +    FTransaction: ITransaction;
408    protected
409      procedure CheckActive; override;
410    public
411 +    function GetTransaction: ITransaction; override;
412      function GetIsNull: Boolean; override;
413      function GetAsArray: IArray;
414      function GetAsBlob: IBlob; overload;
415      function GetAsBlob(BPB: IBPB): IBlob; overload;
416 <    function GetAsString: String; override;
416 >    function GetAsString: AnsiString; override;
417      property AsBlob: IBlob read GetAsBlob;
418   end;
419  
420 +  { TSQLParamMetaData }
421 +
422 +  TSQLParamMetaData = class(TFBInterfacedObject,IParamMetaData)
423 +  private
424 +    FSQLType: cardinal;
425 +    FSQLSubType: integer;
426 +    FScale: integer;
427 +    FCharSetID: cardinal;
428 +    FNullable: boolean;
429 +    FSize: cardinal;
430 +    FCodePage: TSystemCodePage;
431 +  public
432 +    constructor Create(src: TSQLVarData);
433 +    {IParamMetaData}
434 +    function GetSQLType: cardinal;
435 +    function GetSQLTypeName: AnsiString;
436 +    function getSubtype: integer;
437 +    function getScale: integer;
438 +    function getCharSetID: cardinal;
439 +    function getCodePage: TSystemCodePage;
440 +    function getIsNullable: boolean;
441 +    function GetSize: cardinal;
442 +    property SQLType: cardinal read GetSQLType;
443 +  end;
444 +
445    { TSQLParam }
446  
447 <  TSQLParam = class(TIBSQLData,ISQLParam)
447 >  TSQLParam = class(TIBSQLData,ISQLParam,ISQLData)
448    protected
449      procedure CheckActive; override;
450      procedure Changed; override;
451 <    procedure InternalSetAsString(Value: String); override;
451 >    procedure InternalSetAsString(Value: AnsiString); override;
452      procedure SetScale(aValue: integer); override;
453      procedure SetDataLength(len: cardinal); override;
454      procedure SetSQLType(aValue: cardinal); override;
455    public
456      procedure Clear;
457 +    function getColMetadata: IParamMetaData;
458      function GetModified: boolean; override;
459      function GetAsPointer: Pointer;
460 <    procedure SetName(Value: string); override;
460 >    function GetAsString: AnsiString; override;
461 >    procedure SetName(Value: AnsiString); override;
462      procedure SetIsNull(Value: Boolean);  override;
463      procedure SetIsNullable(Value: Boolean); override;
464      procedure SetAsArray(anArray: IArray);
# Line 371 | Line 469 | type
469      procedure SetAsInt64(AValue: Int64);
470      procedure SetAsDate(AValue: TDateTime);
471      procedure SetAsLong(AValue: Long);
472 <    procedure SetAsTime(AValue: TDateTime);
473 <    procedure SetAsDateTime(AValue: TDateTime);
472 >    procedure SetAsTime(AValue: TDateTime); overload;
473 >    procedure SetAsTime(aValue: TDateTime; OnDate: TDateTime; aTimeZoneID: TFBTimeZoneID); overload;
474 >    procedure SetAsTime(aValue: TDateTime; OnDate: TDateTime; aTimeZone: AnsiString); overload;
475 >    procedure SetAsTime(aValue: TDateTime; aTimeZoneID: TFBTimeZoneID); overload;
476 >    procedure SetAsTime(aValue: TDateTime; aTimeZone: AnsiString); overload;
477 >    procedure SetAsDateTime(AValue: TDateTime); overload;
478 >    procedure SetAsDateTime(aValue: TDateTime; aTimeZoneID: TFBTimeZoneID); overload;
479 >    procedure SetAsDateTime(aValue: TDateTime; aTimeZone: AnsiString); overload;
480      procedure SetAsDouble(AValue: Double);
481      procedure SetAsFloat(AValue: Float);
482      procedure SetAsPointer(AValue: Pointer);
483      procedure SetAsShort(AValue: Short);
484 <    procedure SetAsString(AValue: String); override;
484 >    procedure SetAsString(AValue: AnsiString); override;
485      procedure SetAsVariant(AValue: Variant);
486      procedure SetAsBlob(aValue: IBlob);
487      procedure SetAsQuad(AValue: TISC_QUAD);
488      procedure SetCharSetID(aValue: cardinal);
489 +    procedure SetAsBcd(aValue: tBCD);
490  
491      property AsBlob: IBlob read GetAsBlob write SetAsBlob;
492      property IsNullable: Boolean read GetIsNullable write SetIsNullable;
# Line 400 | Line 505 | type
505      destructor Destroy; override;
506    public
507      {IMetaData}
508 <    function GetUniqueRelationName: string;
508 >    function GetUniqueRelationName: AnsiString;
509      function getCount: integer;
510      function getColumnMetaData(index: integer): IColumnMetaData;
511 <    function ByName(Idx: String): IColumnMetaData;
511 >    function ByName(Idx: AnsiString): IColumnMetaData;
512    end;
513  
514    { TSQLParams }
# Line 422 | Line 527 | type
527      {ISQLParams}
528      function getCount: integer;
529      function getSQLParam(index: integer): ISQLParam;
530 <    function ByName(Idx: String): ISQLParam ;
530 >    function ByName(Idx: AnsiString): ISQLParam ;
531      function GetModified: Boolean;
532 +    function GetHasCaseSensitiveParams: Boolean;
533    end;
534  
535    { TResults }
# Line 442 | Line 548 | type
548       constructor Create(aResults: TSQLDataArea);
549        {IResults}
550       function getCount: integer;
551 <     function ByName(Idx: String): ISQLData;
551 >     function ByName(Idx: AnsiString): ISQLData;
552       function getSQLData(index: integer): ISQLData;
553 <     procedure GetData(index: integer; var IsNull:boolean; var len: short; var data: PChar);
553 >     procedure GetData(index: integer; var IsNull:boolean; var len: short; var data: PByte);
554 >     function GetStatement: IStatement;
555       function GetTransaction: ITransaction; virtual;
556       procedure SetRetainInterfaces(aValue: boolean);
557   end;
558  
559   implementation
560  
561 < uses FBMessages, FBClientAPI, variants, IBUtils, FBTransaction;
561 > uses FBMessages, variants, IBUtils, FBTransaction, DateUtils;
562 >
563 > { TSQLParamMetaData }
564 >
565 > constructor TSQLParamMetaData.Create(src: TSQLVarData);
566 > begin
567 >  inherited Create;
568 >  FSQLType := src.GetSQLType;
569 >  FSQLSubType := src.getSubtype;
570 >  FScale := src.GetScale;
571 >  FCharSetID := src.getCharSetID;
572 >  FNullable := src.GetIsNullable;
573 >  FSize := src.GetSize;
574 >  FCodePage := src.GetCodePage;
575 > end;
576 >
577 > function TSQLParamMetaData.GetSQLType: cardinal;
578 > begin
579 >  Result := FSQLType;
580 > end;
581 >
582 > function TSQLParamMetaData.GetSQLTypeName: AnsiString;
583 > begin
584 >  Result := TSQLDataItem.GetSQLTypeName(FSQLType);
585 > end;
586 >
587 > function TSQLParamMetaData.getSubtype: integer;
588 > begin
589 >  Result := FSQLSubType;
590 > end;
591 >
592 > function TSQLParamMetaData.getScale: integer;
593 > begin
594 >  Result := FScale;
595 > end;
596 >
597 > function TSQLParamMetaData.getCharSetID: cardinal;
598 > begin
599 >  Result := FCharSetID;
600 > end;
601 >
602 > function TSQLParamMetaData.getCodePage: TSystemCodePage;
603 > begin
604 >  Result :=  FCodePage;
605 > end;
606 >
607 > function TSQLParamMetaData.getIsNullable: boolean;
608 > begin
609 >  Result :=  FNullable;
610 > end;
611 >
612 > function TSQLParamMetaData.GetSize: cardinal;
613 > begin
614 >  Result := FSize;
615 > end;
616  
617   { TSQLDataArea }
618  
# Line 471 | Line 632 | procedure TSQLDataArea.SetUniqueRelation
632   var
633    i: Integer;
634    bUnique: Boolean;
635 <  RelationName: string;
635 >  RelationName: AnsiString;
636   begin
637    bUnique := True;
638    for i := 0 to ColumnsInUseCount - 1 do
# Line 502 | Line 663 | begin
663      Column[i].Initialize;
664   end;
665  
666 < procedure TSQLDataArea.PreprocessSQL(sSQL: string; GenerateParamNames: boolean;
667 <  var sProcessedSQL: string);
507 < var
508 <  cCurChar, cNextChar, cQuoteChar: Char;
509 <  sParamName: String;
510 <  j, i, iLenSQL, iSQLPos: Integer;
511 <  iCurState {$ifdef ALLOWDIALECT3PARAMNAMES}, iCurParamState {$endif}: Integer;
512 <  iParamSuffix: Integer;
513 <  slNames: TStrings;
514 <  StrBuffer: PChar;
515 <  found: boolean;
516 <
517 < const
518 <  DefaultState = 0;
519 <  CommentState = 1;
520 <  QuoteState = 2;
521 <  ParamState = 3;
522 < {$ifdef ALLOWDIALECT3PARAMNAMES}
523 <  ParamDefaultState = 0;
524 <  ParamQuoteState = 1;
525 <  {$endif}
526 <
527 <  procedure AddToProcessedSQL(cChar: Char);
528 <  begin
529 <    StrBuffer[iSQLPos] := cChar;
530 <    Inc(iSQLPos);
531 <  end;
666 > procedure TSQLDataArea.PreprocessSQL(sSQL: AnsiString; GenerateParamNames: boolean;
667 >  var sProcessedSQL: AnsiString);
668  
669 < begin
534 <  if not IsInputDataArea then
535 <    IBError(ibxeNotPermitted,[nil]);
669 > var slNames: TStrings;
670  
671 <  sParamName := '';
672 <  iLenSQL := Length(sSQL);
673 <  GetMem(StrBuffer,iLenSQL + 1);
674 <  slNames := TStringList.Create;
675 <  try
542 <    { Do some initializations of variables }
543 <    iParamSuffix := 0;
544 <    cQuoteChar := '''';
545 <    i := 1;
546 <    iSQLPos := 0;
547 <    iCurState := DefaultState;
548 <    {$ifdef ALLOWDIALECT3PARAMNAMES}
549 <    iCurParamState := ParamDefaultState;
550 <    {$endif}
551 <    { Now, traverse through the SQL string, character by character,
552 <     picking out the parameters and formatting correctly for InterBase }
553 <    while (i <= iLenSQL) do begin
554 <      { Get the current token and a look-ahead }
555 <      cCurChar := sSQL[i];
556 <      if i = iLenSQL then
557 <        cNextChar := #0
558 <      else
559 <        cNextChar := sSQL[i + 1];
560 <      { Now act based on the current state }
561 <      case iCurState of
562 <        DefaultState: begin
563 <          case cCurChar of
564 <            '''', '"': begin
565 <              cQuoteChar := cCurChar;
566 <              iCurState := QuoteState;
567 <            end;
568 <            '?', ':': begin
569 <              iCurState := ParamState;
570 <              AddToProcessedSQL('?');
571 <            end;
572 <            '/': if (cNextChar = '*') then begin
573 <              AddToProcessedSQL(cCurChar);
574 <              Inc(i);
575 <              iCurState := CommentState;
576 <            end;
577 <          end;
578 <        end;
579 <        CommentState: begin
580 <          if (cNextChar = #0) then
581 <            IBError(ibxeSQLParseError, [SEOFInComment])
582 <          else if (cCurChar = '*') then begin
583 <            if (cNextChar = '/') then
584 <              iCurState := DefaultState;
585 <          end;
586 <        end;
587 <        QuoteState: begin
588 <          if cNextChar = #0 then
589 <            IBError(ibxeSQLParseError, [SEOFInString])
590 <          else if (cCurChar = cQuoteChar) then begin
591 <            if (cNextChar = cQuoteChar) then begin
592 <              AddToProcessedSQL(cCurChar);
593 <              Inc(i);
594 <            end else
595 <              iCurState := DefaultState;
596 <          end;
597 <        end;
598 <        ParamState:
599 <        begin
600 <          { collect the name of the parameter }
601 <          {$ifdef ALLOWDIALECT3PARAMNAMES}
602 <          if iCurParamState = ParamDefaultState then
603 <          begin
604 <            if cCurChar = '"' then
605 <              iCurParamState := ParamQuoteState
606 <            else
607 <            {$endif}
608 <            if (cCurChar in ['A'..'Z', 'a'..'z', '0'..'9', '_', '$']) then
609 <                sParamName := sParamName + cCurChar
610 <            else if GenerateParamNames then
611 <            begin
612 <              sParamName := 'IBXParam' + IntToStr(iParamSuffix); {do not localize}
613 <              Inc(iParamSuffix);
614 <              iCurState := DefaultState;
615 <              slNames.AddObject(sParamName,self); //Note local convention
616 <                                                  //add pointer to self to mark entry
617 <              sParamName := '';
618 <            end
619 <            else
620 <              IBError(ibxeSQLParseError, [SParamNameExpected]);
621 <          {$ifdef ALLOWDIALECT3PARAMNAMES}
622 <          end
623 <          else begin
624 <            { determine if Quoted parameter name is finished }
625 <            if cCurChar = '"' then
626 <            begin
627 <              Inc(i);
628 <              slNames.Add(sParamName);
629 <              SParamName := '';
630 <              iCurParamState := ParamDefaultState;
631 <              iCurState := DefaultState;
632 <            end
633 <            else
634 <              sParamName := sParamName + cCurChar
635 <          end;
636 <          {$endif}
637 <          { determine if the unquoted parameter name is finished }
638 <          if {$ifdef ALLOWDIALECT3PARAMNAMES}(iCurParamState <> ParamQuoteState) and {$endif}
639 <            (iCurState <> DefaultState) then
640 <          begin
641 <            if not (cNextChar in ['A'..'Z', 'a'..'z',
642 <                                  '0'..'9', '_', '$']) then begin
643 <              Inc(i);
644 <              iCurState := DefaultState;
645 <              slNames.Add(sParamName);
646 <              sParamName := '';
647 <            end;
648 <          end;
649 <        end;
650 <      end;
651 <      if (iCurState <> ParamState) and (i <= iLenSQL) then
652 <        AddToProcessedSQL(sSQL[i]);
653 <      Inc(i);
654 <    end;
655 <    AddToProcessedSQL(#0);
656 <    sProcessedSQL := strpas(StrBuffer);
671 >  procedure SetColumnNames(slNames: TStrings);
672 >  var i, j: integer;
673 >      found: boolean;
674 >  begin
675 >    found := false;
676      SetCount(slNames.Count);
677      for i := 0 to slNames.Count - 1 do
678      begin
# Line 674 | Line 693 | begin
693          Column[i].UniqueName := not found;
694        end;
695      end;
696 +  end;
697 +
698 + begin
699 +  if not IsInputDataArea then
700 +    IBError(ibxeNotPermitted,[nil]);
701 +
702 +  slNames := TStringList.Create;
703 +  try
704 +    sProcessedSQL := TSQLParamProcessor.Execute(sSQL,GenerateParamNames,slNames);
705 +    SetColumnNames(slNames);
706    finally
707      slNames.Free;
679    FreeMem(StrBuffer);
708    end;
709   end;
710  
# Line 685 | Line 713 | begin
713    Result := Count;
714   end;
715  
716 < function TSQLDataArea.ColumnByName(Idx: string): TSQLVarData;
716 > function TSQLDataArea.ColumnByName(Idx: AnsiString): TSQLVarData;
717   var
718 <  s: String;
718 >  s: AnsiString;
719    i: Integer;
720   begin
721 <  {$ifdef UseCaseInSensitiveParamName}
722 <   s := AnsiUpperCase(Idx);
723 <  {$else}
721 >  if not IsInputDataArea or not CaseSensitiveParams then
722 >   s := AnsiUpperCase(Idx)
723 >  else
724     s := Idx;
725 <  {$endif}
725 >
726    for i := 0 to Count - 1 do
727      if Column[i].Name = s then
728      begin
# Line 705 | Line 733 | begin
733   end;
734  
735   procedure TSQLDataArea.GetData(index: integer; var IsNull: boolean;
736 <  var len: short; var data: PChar);
736 >  var len: short; var data: PByte);
737   begin
738    //Do Nothing
739   end;
# Line 724 | Line 752 | begin
752    Result := FParent.Statement;
753   end;
754  
755 < procedure TSQLVarData.SetName(AValue: string);
755 > procedure TSQLVarData.SetName(AValue: AnsiString);
756   begin
757 <  if FName = AValue then Exit;
730 <  {$ifdef UseCaseInSensitiveParamName}
731 <  if Parent.IsInputDataArea then
757 >  if not Parent.IsInputDataArea or not Parent.CaseSensitiveParams then
758      FName := AnsiUpperCase(AValue)
759    else
734  {$endif}
760      FName := AValue;
761   end;
762  
763 + procedure TSQLVarData.SetMetaSize(aValue: cardinal);
764 + begin
765 +  //Ignore
766 + end;
767 +
768 + procedure TSQLVarData.SaveMetaData;
769 + begin
770 +  FColMetaData := TSQLParamMetaData.Create(self);
771 + end;
772 +
773 + procedure TSQLVarData.SetArray(AValue: IArray);
774 + begin
775 +  FArrayIntf := AValue;
776 + end;
777 +
778   constructor TSQLVarData.Create(aParent: TSQLDataArea; aIndex: integer);
779   begin
780    inherited Create;
# Line 743 | Line 783 | begin
783    FUniqueName := true;
784   end;
785  
786 < procedure TSQLVarData.SetString(aValue: string);
786 > procedure TSQLVarData.SetString(aValue: AnsiString);
787   begin
788    {we take full advantage here of reference counted strings. When setting a string
789     value, a reference is kept in FVarString and a pointer to it placed in the
790 <   SQLVar. This avoids string copies. Note that PChar is guaranteed to point to
790 >   SQLVar. This avoids string copies. Note that PAnsiChar is guaranteed to point to
791     a zero byte when the string is empty, neatly avoiding a nil pointer error.}
792  
793    FVarString := aValue;
794 <  SQLType := SQL_TEXT;
795 <  SetSQLData(PChar(FVarString),Length(aValue));
794 >  if SQLType = SQL_BLOB then
795 >    SetMetaSize(GetAttachment.GetInlineBlobLimit);
796 >  SQLType := GetDefaultTextSQLType;
797 >  Scale := 0;
798 >  SetSQLData(PByte(PAnsiChar(FVarString)),Length(aValue));
799   end;
800  
801   procedure TSQLVarData.Changed;
# Line 762 | Line 805 | end;
805  
806   procedure TSQLVarData.RowChange;
807   begin
808 +  FArrayIntf := nil;
809    FModified := false;
810    FVarString := '';
811   end;
812  
813 + function TSQLVarData.getColMetadata: IParamMetaData;
814 + begin
815 +  Result := FColMetaData;
816 + end;
817 +
818   procedure TSQLVarData.Initialize;
819  
820 <  function FindVarByName(idx: string; limit: integer): TSQLVarData;
820 >  function FindVarByName(idx: AnsiString; limit: integer): TSQLVarData;
821    var
822      k: integer;
823    begin
# Line 783 | Line 832 | procedure TSQLVarData.Initialize;
832  
833   var
834    j, j_len: Integer;
835 <  st: String;
836 <  sBaseName: string;
835 >  st: AnsiString;
836 >  sBaseName: AnsiString;
837   begin
838    RowChange;
839  
# Line 866 | Line 915 | begin
915      result := Val;
916   end;
917  
918 + function TSQLDataItem.AdjustScaleToStr(Value: Int64; aScale: Integer
919 +  ): AnsiString;
920 + var Scaling : AnsiString;
921 +    i: Integer;
922 + begin
923 +  Result := IntToStr(Value);
924 +  Scaling := '';
925 +  if aScale > 0 then
926 +  begin
927 +    for i := 1 to aScale do
928 +      Result := Result + '0';
929 +  end
930 +  else
931 +  if aScale < 0 then
932 +  {$IF declared(DefaultFormatSettings)}
933 +  with DefaultFormatSettings do
934 +  {$ELSE}
935 +  {$IF declared(FormatSettings)}
936 +  with FormatSettings do
937 +  {$IFEND}
938 +  {$IFEND}
939 +  begin
940 +    if Length(Result) > -aScale then
941 +      system.Insert(DecimalSeparator,Result,Length(Result) + aScale)
942 +    else
943 +    begin
944 +      Scaling := '0' + DecimalSeparator;
945 +      for i := -1 downto aScale + Length(Result) do
946 +        Scaling := Scaling + '0';
947 +      Result := Scaling + Result;
948 +    end;
949 +  end;
950 + end;
951 +
952   function TSQLDataItem.AdjustScaleToCurrency(Value: Int64; aScale: Integer
953    ): Currency;
954   var
955    Scaling : Int64;
956    i : Integer;
957 <  FractionText, PadText, CurrText: string;
957 >  FractionText, PadText, CurrText: AnsiString;
958   begin
959    Result := 0;
960    Scaling := 1;
# Line 890 | Line 973 | begin
973        FractionText := IntToStr(abs(Value mod Scaling));
974        for i := Length(FractionText) to -aScale -1 do
975          PadText := '0' + PadText;
976 +      {$IF declared(DefaultFormatSettings)}
977 +      with DefaultFormatSettings do
978 +      {$ELSE}
979 +      {$IF declared(FormatSettings)}
980 +      with FormatSettings do
981 +      {$IFEND}
982 +      {$IFEND}
983        if Value < 0 then
984 <        CurrText := '-' + IntToStr(Abs(Value div Scaling)) + DefaultFormatSettings.DecimalSeparator + PadText + FractionText
984 >        CurrText := '-' + IntToStr(Abs(Value div Scaling)) + DecimalSeparator + PadText + FractionText
985        else
986 <        CurrText := IntToStr(Abs(Value div Scaling)) + DefaultFormatSettings.DecimalSeparator + PadText + FractionText;
986 >        CurrText := IntToStr(Abs(Value div Scaling)) + DecimalSeparator + PadText + FractionText;
987        try
988          result := StrToCurr(CurrText);
989        except
# Line 905 | Line 995 | begin
995        result := Value;
996   end;
997  
998 + function TSQLDataItem.GetDateFormatStr(IncludeTime: boolean): AnsiString;
999 + begin
1000 +  {$IF declared(DefaultFormatSettings)}
1001 +  with DefaultFormatSettings do
1002 +  {$ELSE}
1003 +  {$IF declared(FormatSettings)}
1004 +  with FormatSettings do
1005 +  {$IFEND}
1006 +  {$IFEND}
1007 +  case GetSQLDialect of
1008 +    1:
1009 +      if IncludeTime then
1010 +        result := ShortDateFormat + ' ' + LongTimeFormat
1011 +      else
1012 +        result := ShortDateFormat;
1013 +    3:
1014 +      result := ShortDateFormat;
1015 +  end;
1016 + end;
1017 +
1018 + function TSQLDataItem.GetTimeFormatStr: AnsiString;
1019 + begin
1020 +  {$IF declared(DefaultFormatSettings)}
1021 +  with DefaultFormatSettings do
1022 +  {$ELSE}
1023 +  {$IF declared(FormatSettings)}
1024 +  with FormatSettings do
1025 +  {$IFEND}
1026 +  {$IFEND}
1027 +    Result := 'hh' + TimeSeparator + 'nn' + TimeSeparator + 'ss' + '.zzzz';;
1028 + end;
1029 +
1030 + function TSQLDataItem.GetTimestampFormatStr: AnsiString;
1031 + begin
1032 +  {$IF declared(DefaultFormatSettings)}
1033 +  with DefaultFormatSettings do
1034 +  {$ELSE}
1035 +  {$IF declared(FormatSettings)}
1036 +  with FormatSettings do
1037 +  {$IFEND}
1038 +  {$IFEND}
1039 +    Result := ShortDateFormat + ' ' +  'hh' + TimeSeparator + 'nn' + TimeSeparator + 'ss' + '.zzzz';
1040 + end;
1041 +
1042   procedure TSQLDataItem.SetAsInteger(AValue: Integer);
1043   begin
1044    SetAsLong(aValue);
1045   end;
1046  
1047 + procedure TSQLDataItem.InternalGetAsDateTime(var aDateTime: TDateTime;
1048 +  var dstOffset: smallint; var aTimezone: AnsiString;
1049 +  var aTimeZoneID: TFBTimeZoneID);
1050 + begin
1051 +  CheckActive;
1052 +  aDateTime := 0;
1053 +  dstOffset := 0;
1054 +  aTimezone := '';
1055 +  aTimeZoneID := TimeZoneID_GMT;
1056 +  if not IsNull then
1057 +    with FFirebirdClientAPI do
1058 +    case SQLType of
1059 +      SQL_TEXT, SQL_VARYING:
1060 +        if not ParseDateTimeTZString(AsString,aDateTime,aTimeZone) then
1061 +          IBError(ibxeInvalidDataConversion, [nil]);
1062 +      SQL_TYPE_DATE:
1063 +        aDateTime := SQLDecodeDate(SQLData);
1064 +      SQL_TYPE_TIME:
1065 +        aDateTime := SQLDecodeTime(SQLData);
1066 +      SQL_TIMESTAMP:
1067 +        aDateTime := SQLDecodeDateTime(SQLData);
1068 +      SQL_TIMESTAMP_TZ:
1069 +        begin
1070 +          GetTimeZoneServices.DecodeTimestampTZ(SQLData,aDateTime,dstOffset,aTimeZone);
1071 +          aTimeZoneID := PISC_TIMESTAMP_TZ(SQLData)^.time_zone;
1072 +        end;
1073 +      SQL_TIMESTAMP_TZ_EX:
1074 +      begin
1075 +        GetTimeZoneServices.DecodeTimestampTZEx(SQLData,aDateTime,dstOffset,aTimeZone);
1076 +        aTimeZoneID := PISC_TIMESTAMP_TZ_EX(SQLData)^.time_zone;
1077 +      end;
1078 +      SQL_TIME_TZ:
1079 +        with GetTimeZoneServices do
1080 +        begin
1081 +          DecodeTimeTZ(SQLData,GetTimeTZDate,aDateTime,dstOffset,aTimeZone);
1082 +          aTimeZoneID := PISC_TIME_TZ(SQLData)^.time_zone;
1083 +        end;
1084 +      SQL_TIME_TZ_EX:
1085 +        with GetTimeZoneServices do
1086 +        begin
1087 +          DecodeTimeTZEx(SQLData,GetTimeTZDate,aDateTime,dstOffset,aTimeZone);
1088 +          aTimeZoneID := PISC_TIME_TZ_EX(SQLData)^.time_zone;
1089 +        end;
1090 +      else
1091 +        IBError(ibxeInvalidDataConversion, [nil]);
1092 +    end;
1093 + end;
1094 +
1095   function TSQLDataItem.AdjustScaleFromCurrency(Value: Currency; aScale: Integer
1096    ): Int64;
1097   var
# Line 958 | Line 1140 | begin
1140    end
1141    else
1142      result := trunc(Value);
1143 + //  writeln('Adjusted ',Value,' to ',Result);
1144   end;
1145  
1146   procedure TSQLDataItem.CheckActive;
# Line 965 | Line 1148 | begin
1148    //Do nothing by default
1149   end;
1150  
1151 + procedure TSQLDataItem.CheckTZSupport;
1152 + begin
1153 +  if not FFirebirdClientAPI.HasTimeZoneSupport then
1154 +    IBError(ibxeNoTimezoneSupport,[]);
1155 + end;
1156 +
1157 + function TSQLDataItem.GetTimeZoneServices: IExTimeZoneServices;
1158 + begin
1159 +  if FTimeZoneServices = nil then
1160 +  begin
1161 +    if not GetAttachment.HasTimeZoneSupport then
1162 +      IBError(ibxeNoTimezoneSupport,[]);
1163 +    GetAttachment.GetTimeZoneServices.QueryInterface(IExTimeZoneServices,FTimeZoneServices);
1164 +  end;
1165 +  Result := FTimeZoneServices;
1166 + end;
1167 +
1168   procedure TSQLDataItem.Changed;
1169   begin
1170    //Do nothing by default
# Line 975 | Line 1175 | begin
1175    //Do nothing by default
1176   end;
1177  
1178 < procedure TSQLDataItem.InternalSetAsString(Value: String);
1178 > procedure TSQLDataItem.InternalSetAsString(Value: AnsiString);
1179   begin
1180    //Do nothing by default
1181   end;
1182  
1183 < function TSQLDataItem.Transliterate(s: string; CodePage: TSystemCodePage
1183 > function TSQLDataItem.Transliterate(s: AnsiString; CodePage: TSystemCodePage
1184    ): RawByteString;
1185   begin
1186    Result := s;
# Line 1003 | Line 1203 | begin
1203     //Do nothing by default
1204   end;
1205  
1206 < function TSQLDataItem.GetSQLTypeName: string;
1206 > constructor TSQLDataItem.Create(api: TFBClientAPI);
1207 > begin
1208 >  inherited Create;
1209 >  FFirebirdClientAPI := api;
1210 > end;
1211 >
1212 > function TSQLDataItem.GetSQLTypeName: AnsiString;
1213   begin
1214    Result := GetSQLTypeName(GetSQLType);
1215   end;
1216  
1217 < class function TSQLDataItem.GetSQLTypeName(SQLType: short): string;
1217 > class function TSQLDataItem.GetSQLTypeName(SQLType: cardinal): AnsiString;
1218   begin
1219    Result := 'Unknown';
1220    case SQLType of
# Line 1019 | Line 1225 | begin
1225    SQL_LONG:             Result := 'SQL_LONG';
1226    SQL_SHORT:            Result := 'SQL_SHORT';
1227    SQL_TIMESTAMP:        Result := 'SQL_TIMESTAMP';
1228 +  SQL_TIMESTAMP_TZ:     Result := 'SQL_TIMESTAMP_TZ';
1229 +  SQL_TIMESTAMP_TZ_EX:  Result := 'SQL_TIMESTAMP_TZ_EX';
1230    SQL_BLOB:             Result := 'SQL_BLOB';
1231    SQL_D_FLOAT:          Result := 'SQL_D_FLOAT';
1232    SQL_ARRAY:            Result := 'SQL_ARRAY';
# Line 1026 | Line 1234 | begin
1234    SQL_TYPE_TIME:        Result := 'SQL_TYPE_TIME';
1235    SQL_TYPE_DATE:        Result := 'SQL_TYPE_DATE';
1236    SQL_INT64:            Result := 'SQL_INT64';
1237 +  SQL_TIME_TZ:          Result := 'SQL_TIME_TZ';
1238 +  SQL_TIME_TZ_EX:       Result := 'SQL_TIME_TZ_EX';
1239 +  SQL_DEC_FIXED:        Result := 'SQL_DEC_FIXED';
1240 +  SQL_DEC16:            Result := 'SQL_DEC16';
1241 +  SQL_DEC34:            Result := 'SQL_DEC34';
1242 +  SQL_INT128:           Result := 'SQL_INT128';
1243 +  SQL_NULL:             Result := 'SQL_NULL';
1244 +  SQL_BOOLEAN:          Result := 'SQL_BOOLEAN';
1245    end;
1246   end;
1247  
1248 + function TSQLDataItem.GetStrDataLength: short;
1249 + begin
1250 +  with FFirebirdClientAPI do
1251 +  if SQLType = SQL_VARYING then
1252 +    Result := DecodeInteger(SQLData, 2)
1253 +  else
1254 +    Result := DataLength;
1255 + end;
1256 +
1257   function TSQLDataItem.GetAsBoolean: boolean;
1258   begin
1259    CheckActive;
# Line 1068 | Line 1293 | begin
1293            result := AdjustScaleToCurrency(PInt64(SQLData)^,
1294                                        Scale);
1295          SQL_DOUBLE, SQL_FLOAT, SQL_D_FLOAT:
1296 <          result := Trunc(AsDouble);
1296 >          result := Round(AsDouble);
1297 >
1298 >        SQL_DEC_FIXED,
1299 >        SQL_DEC16,
1300 >        SQL_DEC34,
1301 >        SQL_INT128:
1302 >          if not BCDToCurr(GetAsBCD,Result) then
1303 >            IBError(ibxeInvalidDataConversion, [nil]);
1304 >
1305          else
1306            IBError(ibxeInvalidDataConversion, [nil]);
1307        end;
# Line 1098 | Line 1331 | begin
1331          result := AdjustScaleToInt64(PInt64(SQLData)^,
1332                                      Scale);
1333        SQL_DOUBLE, SQL_FLOAT, SQL_D_FLOAT:
1334 <        result := Trunc(AsDouble);
1334 >        result := Round(AsDouble);
1335        else
1336          IBError(ibxeInvalidDataConversion, [nil]);
1337      end;
1338   end;
1339  
1340   function TSQLDataItem.GetAsDateTime: TDateTime;
1341 + var aTimezone: AnsiString;
1342 +    aTimeZoneID: TFBTimeZoneID;
1343 +    dstOffset: smallint;
1344 + begin
1345 +  InternalGetAsDateTime(Result,dstOffset,aTimeZone,aTimeZoneID);
1346 + end;
1347 +
1348 + procedure TSQLDataItem.GetAsDateTime(var aDateTime: TDateTime;
1349 +  var dstOffset: smallint; var aTimezone: AnsiString);
1350 + var aTimeZoneID: TFBTimeZoneID;
1351 + begin
1352 +  InternalGetAsDateTime(aDateTime,dstOffset,aTimeZone,aTimeZoneID);
1353 + end;
1354 +
1355 + procedure TSQLDataItem.GetAsDateTime(var aDateTime: TDateTime; var dstOffset: smallint;
1356 +  var aTimezoneID: TFBTimeZoneID);
1357 + var aTimezone: AnsiString;
1358 + begin
1359 +  InternalGetAsDateTime(aDateTime,dstOffset,aTimeZone,aTimeZoneID);
1360 + end;
1361 +
1362 + procedure TSQLDataItem.GetAsTime(var aTime: TDateTime; var dstOffset: smallint;
1363 +  var aTimezoneID: TFBTimeZoneID; OnDate: TDateTime);
1364 + var aTimeZone: AnsiString;
1365   begin
1366    CheckActive;
1367 <  result := 0;
1367 >  aTime := 0;
1368 >  dstOffset := 0;
1369    if not IsNull then
1370 <    with FirebirdClientAPI do
1370 >    with FFirebirdClientAPI do
1371      case SQLType of
1372 <      SQL_TEXT, SQL_VARYING: begin
1373 <        try
1374 <          result := StrToDate(AsString);
1375 <        except
1376 <          on E: EConvertError do IBError(ibxeInvalidDataConversion, [nil]);
1372 >      SQL_TIME_TZ:
1373 >        begin
1374 >          GetTimeZoneServices.DecodeTimeTZ(SQLData,OnDate,aTime,dstOffset,aTimeZone);
1375 >          aTimeZoneID := PISC_TIME_TZ(SQLData)^.time_zone;
1376 >        end;
1377 >      SQL_TIME_TZ_EX:
1378 >        begin
1379 >          GetTimeZoneServices.DecodeTimeTZEx(SQLData,OnDate,aTime,dstOffset,aTimeZone);
1380 >          aTimeZoneID := PISC_TIME_TZ_EX(SQLData)^.time_zone;
1381          end;
1382 +    else
1383 +      IBError(ibxeInvalidDataConversion, [nil]);
1384 +    end;
1385 + end;
1386 +
1387 + procedure TSQLDataItem.GetAsTime(var aTime: TDateTime; var dstOffset: smallint;
1388 +  var aTimezone: AnsiString; OnDate: TDateTime);
1389 + begin
1390 +  CheckActive;
1391 +  aTime := 0;
1392 +  dstOffset := 0;
1393 +  if not IsNull then
1394 +    with FFirebirdClientAPI do
1395 +    case SQLType of
1396 +      SQL_TIME_TZ:
1397 +        GetTimeZoneServices.DecodeTimeTZ(SQLData,OnDate,aTime,dstOffset,aTimeZone);
1398 +      SQL_TIME_TZ_EX:
1399 +        GetTimeZoneServices.DecodeTimeTZEx(SQLData,OnDate,aTime,dstOffset,aTimeZone);
1400 +    else
1401 +      IBError(ibxeInvalidDataConversion, [nil]);
1402 +    end;
1403 + end;
1404 +
1405 + procedure TSQLDataItem.GetAsTime(var aTime: TDateTime; var dstOffset: smallint;
1406 +  var aTimezoneID: TFBTimeZoneID);
1407 + begin
1408 +  GetAsTime(aTime,dstOffset,aTimeZoneID,GetTimeZoneServices.GetTimeTZDate);
1409 + end;
1410 +
1411 + procedure TSQLDataItem.GetAsTime(var aTime: TDateTime; var dstOffset: smallint;
1412 +  var aTimezone: AnsiString);
1413 + begin
1414 +  GetAsTime(aTime,dstOffset,aTimeZone,GetTimeZoneServices.GetTimeTZDate);
1415 + end;
1416 +
1417 + function TSQLDataItem.GetAsUTCDateTime: TDateTime;
1418 + var aTimezone: AnsiString;
1419 + begin
1420 +  CheckActive;
1421 +  result := 0;
1422 +  aTimezone := '';
1423 +  if not IsNull then
1424 +    with FFirebirdClientAPI do
1425 +    case SQLType of
1426 +      SQL_TEXT, SQL_VARYING:
1427 +      begin
1428 +        if not ParseDateTimeTZString(AsString,Result,aTimeZone) then
1429 +          IBError(ibxeInvalidDataConversion, [nil]);
1430 +        Result := GetTimeZoneServices.LocalTimeToGMT(Result,aTimeZone);
1431        end;
1432        SQL_TYPE_DATE:
1433          result := SQLDecodeDate(SQLData);
1434 <      SQL_TYPE_TIME:
1434 >      SQL_TYPE_TIME,
1435 >      SQL_TIME_TZ,
1436 >      SQL_TIME_TZ_EX:
1437          result := SQLDecodeTime(SQLData);
1438 <      SQL_TIMESTAMP:
1438 >      SQL_TIMESTAMP,
1439 >      SQL_TIMESTAMP_TZ,
1440 >      SQL_TIMESTAMP_TZ_EX:
1441          result := SQLDecodeDateTime(SQLData);
1442        else
1443          IBError(ibxeInvalidDataConversion, [nil]);
1444 <    end;
1444 >      end;
1445   end;
1446  
1447   function TSQLDataItem.GetAsDouble: Double;
# Line 1154 | Line 1469 | begin
1469          result := PFloat(SQLData)^;
1470        SQL_DOUBLE, SQL_D_FLOAT:
1471          result := PDouble(SQLData)^;
1472 +      SQL_DEC_FIXED,
1473 +      SQL_DEC16,
1474 +      SQL_DEC34,
1475 +      SQL_INT128:
1476 +        Result := BCDToDouble(GetAsBCD);
1477        else
1478          IBError(ibxeInvalidDataConversion, [nil]);
1479      end;
# Line 1190 | Line 1510 | begin
1510          end;
1511        end;
1512        SQL_SHORT:
1513 <        result := Trunc(AdjustScale(Int64(PShort(SQLData)^),
1513 >        result := Round(AdjustScale(Int64(PShort(SQLData)^),
1514                                      Scale));
1515        SQL_LONG:
1516 <        result := Trunc(AdjustScale(Int64(PLong(SQLData)^),
1516 >        result := Round(AdjustScale(Int64(PLong(SQLData)^),
1517                                      Scale));
1518        SQL_INT64:
1519 <        result := Trunc(AdjustScale(PInt64(SQLData)^, Scale));
1519 >        result := Round(AdjustScale(PInt64(SQLData)^, Scale));
1520        SQL_DOUBLE, SQL_FLOAT, SQL_D_FLOAT:
1521 <        result := Trunc(AsDouble);
1521 >        result := Round(AsDouble);
1522 >      SQL_DEC_FIXED,
1523 >      SQL_DEC16,
1524 >      SQL_DEC34,
1525 >      SQL_INT128:
1526 >        Result := BCDToInteger(GetAsBCD);
1527        else
1528 <        IBError(ibxeInvalidDataConversion, [nil]);
1528 >        IBError(ibxeInvalidDataConversion, [GetSQLTypeName]);
1529      end;
1530   end;
1531  
# Line 1238 | Line 1563 | begin
1563    end;
1564   end;
1565  
1566 + {Copied from LazUTF8}
1567 +
1568 + function UTF8CodepointSizeFull(p: PAnsiChar): integer;
1569 + const TopBitSetMask   = $80; {%10000000}
1570 +      Top2BitsSetMask = $C0; {%11000000}
1571 +      Top3BitsSetMask = $E0; {%11100000}
1572 +      Top4BitsSetMask = $F0; {%11110000}
1573 +      Top5BitsSetMask = $F8; {%11111000}
1574 + begin
1575 +  case p^ of
1576 +  #0..#191: // %11000000
1577 +    // regular single byte character (#0 is a character, this is Pascal ;)
1578 +    Result:=1;
1579 +  #192..#223: // p^ and %11100000 = %11000000
1580 +    begin
1581 +      // could be 2 byte character
1582 +      if (ord(p[1]) and Top2BitsSetMask) = TopBitSetMask then
1583 +        Result:=2
1584 +      else
1585 +        Result:=1;
1586 +    end;
1587 +  #224..#239: // p^ and %11110000 = %11100000
1588 +    begin
1589 +      // could be 3 byte character
1590 +      if ((ord(p[1]) and Top2BitsSetMask) = TopBitSetMask)
1591 +      and ((ord(p[2]) and Top2BitsSetMask) = TopBitSetMask) then
1592 +        Result:=3
1593 +      else
1594 +        Result:=1;
1595 +    end;
1596 +  #240..#247: // p^ and %11111000 = %11110000
1597 +    begin
1598 +      // could be 4 byte character
1599 +      if ((ord(p[1]) and Top2BitsSetMask) = TopBitSetMask)
1600 +      and ((ord(p[2]) and Top2BitsSetMask) = TopBitSetMask)
1601 +      and ((ord(p[3]) and Top2BitsSetMask) = TopBitSetMask) then
1602 +        Result:=4
1603 +      else
1604 +        Result:=1;
1605 +    end;
1606 +  else
1607 +    Result:=1;
1608 +  end;
1609 + end;
1610 +
1611 + {Returns the byte length of a UTF8 string with a fixed charwidth}
1612 +
1613 + function GetStrLen(p: PAnsiChar; FieldWidth, MaxDataLength: cardinal): integer;
1614 + var i: integer;
1615 +    cplen: integer;
1616 + begin
1617 +  Result := 0;
1618 +  for i := 1 to FieldWidth do
1619 +  begin
1620 +    cplen := UTF8CodepointSizeFull(p);
1621 +    Inc(p,cplen);
1622 +    Inc(Result,cplen);
1623 +    if Result >= MaxDataLength then
1624 +    begin
1625 +      Result := MaxDataLength;
1626 +      Exit;
1627 +    end;
1628 +  end;
1629 + end;
1630  
1631 < function TSQLDataItem.GetAsString: String;
1631 > function TSQLDataItem.GetAsString: AnsiString;
1632   var
1633 <  sz: PChar;
1633 >  sz: PByte;
1634    str_len: Integer;
1635    rs: RawByteString;
1636 +  aTimeZone: AnsiString;
1637 +  aDateTime: TDateTime;
1638 +  dstOffset: smallint;
1639   begin
1640    CheckActive;
1641    result := '';
1642    { Check null, if so return a default string }
1643    if not IsNull then
1644 <  with FirebirdClientAPI do
1644 >  with FFirebirdClientAPI do
1645      case SQLType of
1646        SQL_BOOLEAN:
1647          if AsBoolean then
# Line 1261 | Line 1653 | begin
1653        begin
1654          sz := SQLData;
1655          if (SQLType = SQL_TEXT) then
1656 <          str_len := DataLength
1656 >        begin
1657 >          if GetCodePage = cp_utf8 then
1658 >            str_len := GetStrLen(PAnsiChar(sz),GetSize div GetCharSetWidth,DataLength)
1659 >          else
1660 >            str_len := DataLength
1661 >        end
1662          else begin
1663 <          str_len := DecodeInteger(SQLData, 2);
1663 >          str_len := DecodeInteger(sz, 2);
1664            Inc(sz, 2);
1665          end;
1666 <        SetString(rs, sz, str_len);
1666 >        SetString(rs, PAnsiChar(sz), str_len);
1667          SetCodePage(rs,GetCodePage,false);
1668 <        Result := Trim(rs);
1668 >        Result := rs;
1669        end;
1670 +
1671        SQL_TYPE_DATE:
1672 <        case GetSQLDialect of
1275 <          1 : result := DateTimeToStr(AsDateTime);
1276 <          3 : result := DateToStr(AsDateTime);
1277 <        end;
1278 <      SQL_TYPE_TIME :
1279 <        result := TimeToStr(AsDateTime);
1672 >        Result := DateToStr(GetAsDateTime);
1673        SQL_TIMESTAMP:
1674 <        result := FormatDateTime(FormatSettings.ShortDateFormat + ' ' +
1675 <                            FormatSettings.LongTimeFormat+'.zzz',AsDateTime);
1674 >        Result := FBFormatDateTime(GetTimestampFormatStr,GetAsDateTime);
1675 >      SQL_TYPE_TIME:
1676 >        Result := FBFormatDateTime(GetTimeFormatStr,GetAsDateTime);
1677 >      SQL_TIMESTAMP_TZ,
1678 >      SQL_TIMESTAMP_TZ_EX:
1679 >        with GetAttachment.GetTimeZoneServices do
1680 >        begin
1681 >          if GetTZTextOption = tzGMT then
1682 >            Result := FBFormatDateTime(GetTimestampFormatStr,GetAsUTCDateTime)
1683 >          else
1684 >          begin
1685 >            GetAsDateTime(aDateTime,dstOffset,aTimeZone);
1686 >            if GetTZTextOption = tzOffset then
1687 >              Result := FBFormatDateTime(GetTimestampFormatStr,aDateTime) + ' ' + FormatTimeZoneOffset(dstOffset)
1688 >            else
1689 >              Result := FBFormatDateTime(GetTimestampFormatStr,aDateTime) + ' ' + aTimeZone;
1690 >          end;
1691 >        end;
1692 >      SQL_TIME_TZ,
1693 >      SQL_TIME_TZ_EX:
1694 >        with GetAttachment.GetTimeZoneServices do
1695 >        begin
1696 >          if GetTZTextOption = tzGMT then
1697 >             Result := FBFormatDateTime(GetTimeFormatStr,GetAsUTCDateTime)
1698 >          else
1699 >          begin
1700 >            GetAsTime(aDateTime,dstOffset,aTimeZone,GetTimeTZDate);
1701 >            if GetTZTextOption = tzOffset then
1702 >              Result := FBFormatDateTime(GetTimeFormatStr,aDateTime) + ' ' + FormatTimeZoneOffset(dstOffset)
1703 >            else
1704 >              Result := FBFormatDateTime(GetTimeFormatStr,aDateTime) + ' ' + aTimeZone;
1705 >          end;
1706 >        end;
1707 >
1708        SQL_SHORT, SQL_LONG:
1709          if Scale = 0 then
1710            result := IntToStr(AsLong)
# Line 1296 | Line 1721 | begin
1721            result := FloatToStr(AsDouble);
1722        SQL_DOUBLE, SQL_FLOAT, SQL_D_FLOAT:
1723          result := FloatToStr(AsDouble);
1724 +
1725 +      SQL_DEC16,
1726 +      SQL_DEC34:
1727 +        result := BCDToStr(GetAsBCD);
1728 +
1729 +      SQL_DEC_FIXED,
1730 +      SQL_INT128:
1731 +        result := Int128ToStr(SQLData,scale);
1732 +
1733        else
1734          IBError(ibxeInvalidDataConversion, [nil]);
1735      end;
# Line 1307 | Line 1741 | begin
1741    Result := false;
1742   end;
1743  
1744 < function TSQLDataItem.getIsNullable: boolean;
1744 > function TSQLDataItem.GetIsNullable: boolean;
1745   begin
1746    CheckActive;
1747    Result := false;
1748   end;
1749  
1750   function TSQLDataItem.GetAsVariant: Variant;
1751 + var ts: TDateTime;
1752 +  dstOffset: smallint;
1753 +    timezone: AnsiString;
1754   begin
1755    CheckActive;
1756    if IsNull then
# Line 1327 | Line 1764 | begin
1764          result := AsString;
1765        SQL_TIMESTAMP, SQL_TYPE_DATE, SQL_TYPE_TIME:
1766          result := AsDateTime;
1767 +      SQL_TIMESTAMP_TZ,
1768 +      SQL_TIME_TZ,
1769 +      SQL_TIMESTAMP_TZ_EX,
1770 +      SQL_TIME_TZ_EX:
1771 +        begin
1772 +          GetAsDateTime(ts,dstOffset,timezone);
1773 +          result := VarArrayOf([ts,dstOffset,timezone]);
1774 +        end;
1775        SQL_SHORT, SQL_LONG:
1776          if Scale = 0 then
1777            result := AsLong
# Line 1345 | Line 1790 | begin
1790          result := AsDouble;
1791        SQL_BOOLEAN:
1792          result := AsBoolean;
1793 +      SQL_DEC_FIXED,
1794 +      SQL_DEC16,
1795 +      SQL_DEC34,
1796 +      SQL_INT128:
1797 +        result := VarFmtBCDCreate(GetAsBcd);
1798        else
1799          IBError(ibxeInvalidDataConversion, [nil]);
1800      end;
# Line 1355 | Line 1805 | begin
1805    Result := false;
1806   end;
1807  
1808 + function TSQLDataItem.GetDateTimeStrLength(DateTimeFormat: TIBDateTimeFormats
1809 +  ): integer;
1810 + begin
1811 +  case DateTimeFormat of
1812 +  dfTimestamp:
1813 +    Result := Length(GetTimestampFormatStr);
1814 +  dfDateTime:
1815 +    Result := Length(GetDateFormatStr(true));
1816 +  dfTime:
1817 +    Result := Length(GetTimeFormatStr);
1818 +  dfTimestampTZ:
1819 +    Result := Length(GetTimestampFormatStr) + 6; {assume time offset format}
1820 +  dfTimeTZ:
1821 +    Result := Length(GetTimeFormatStr)+ 6;
1822 +  else
1823 +    Result := 0;
1824 +  end;end;
1825 +
1826 + function TSQLDataItem.GetAsBCD: tBCD;
1827 +
1828 + begin
1829 +  CheckActive;
1830 +  if IsNull then
1831 +   with Result do
1832 +   begin
1833 +     FillChar(Result,sizeof(Result),0);
1834 +     Precision := 1;
1835 +     exit;
1836 +   end;
1837 +
1838 +  case SQLType of
1839 +  SQL_DEC16,
1840 +  SQL_DEC34:
1841 +    with FFirebirdClientAPI do
1842 +      Result := SQLDecFloatDecode(SQLType,  SQLData);
1843 +
1844 +  SQL_DEC_FIXED,
1845 +  SQL_INT128:
1846 +    with FFirebirdClientAPI do
1847 +      Result := StrToBCD(Int128ToStr(SQLData,scale));
1848 +  else
1849 +    if not CurrToBCD(GetAsCurrency,Result) then
1850 +      IBError(ibxeBadBCDConversion,[]);
1851 +  end;
1852 + end;
1853 +
1854  
1855   procedure TSQLDataItem.SetIsNull(Value: Boolean);
1856   begin
# Line 1366 | Line 1862 | begin
1862    //ignore unless overridden
1863   end;
1864  
1865 < procedure TSQLDataItem.SetName(aValue: string);
1865 > procedure TSQLDataItem.SetName(aValue: AnsiString);
1866   begin
1867    //ignore unless overridden
1868   end;
# Line 1418 | Line 1914 | begin
1914  
1915    SQLType := SQL_TYPE_DATE;
1916    DataLength := SizeOf(ISC_DATE);
1917 <  with FirebirdClientAPI do
1917 >  with FFirebirdClientAPI do
1918      SQLEncodeDate(Value,SQLData);
1919    Changed;
1920   end;
# Line 1438 | Line 1934 | begin
1934  
1935    SQLType := SQL_TYPE_TIME;
1936    DataLength := SizeOf(ISC_TIME);
1937 <  with FirebirdClientAPI do
1937 >  with FFirebirdClientAPI do
1938      SQLEncodeTime(Value,SQLData);
1939    Changed;
1940   end;
1941  
1942 + procedure TSQLDataItem.SetAsTime(aValue: TDateTime; OnDate: TDateTime; aTimeZoneID: TFBTimeZoneID);
1943 + begin
1944 +  CheckActive;
1945 +  CheckTZSupport;
1946 +  if GetSQLDialect < 3 then
1947 +  begin
1948 +    AsDateTime := aValue;
1949 +    exit;
1950 +  end;
1951 +
1952 +  Changing;
1953 +  if IsNullable then
1954 +    IsNull := False;
1955 +
1956 +  SQLType := SQL_TIME_TZ;
1957 +  DataLength := SizeOf(ISC_TIME_TZ);
1958 +  GetTimeZoneServices.EncodeTimeTZ(aValue, aTimeZoneID,OnDate,SQLData);
1959 +  Changed;
1960 + end;
1961 +
1962 + procedure TSQLDataItem.SetAsTime(aValue: TDateTime; OnDate: TDateTime; aTimeZone: AnsiString);
1963 + begin
1964 +  CheckActive;
1965 +  CheckTZSupport;
1966 +  if GetSQLDialect < 3 then
1967 +  begin
1968 +    AsDateTime := aValue;
1969 +    exit;
1970 +  end;
1971 +
1972 +  Changing;
1973 +  if IsNullable then
1974 +    IsNull := False;
1975 +
1976 +  SQLType := SQL_TIME_TZ;
1977 +  DataLength := SizeOf(ISC_TIME_TZ);
1978 +  GetTimeZoneServices.EncodeTimeTZ(aValue, aTimeZone,OnDate,SQLData);
1979 +  Changed;
1980 + end;
1981 +
1982   procedure TSQLDataItem.SetAsDateTime(Value: TDateTime);
1983   begin
1984    CheckActive;
# Line 1451 | Line 1987 | begin
1987  
1988    Changing;
1989    SQLType := SQL_TIMESTAMP;
1990 <  DataLength := SizeOf(TISC_QUAD);
1991 <  with FirebirdClientAPI do
1990 >  DataLength := SizeOf(ISC_TIME) + sizeof(ISC_DATE);
1991 >  with FFirebirdClientAPI do
1992      SQLEncodeDateTime(Value,SQLData);
1993    Changed;
1994   end;
1995  
1996 + procedure TSQLDataItem.SetAsDateTime(aValue: TDateTime;
1997 +  aTimeZoneID: TFBTimeZoneID);
1998 + begin
1999 +  CheckActive;
2000 +  CheckTZSupport;
2001 +  if IsNullable then
2002 +    IsNull := False;
2003 +
2004 +  Changing;
2005 +  SQLType := SQL_TIMESTAMP_TZ;
2006 +  DataLength := SizeOf(ISC_TIMESTAMP_TZ);
2007 +  GetTimeZoneServices.EncodeTimestampTZ(aValue,aTimeZoneID,SQLData);
2008 +  Changed;
2009 + end;
2010 +
2011 + procedure TSQLDataItem.SetAsDateTime(aValue: TDateTime; aTimeZone: AnsiString
2012 +  );
2013 + begin
2014 +  CheckActive;
2015 +  CheckTZSupport;
2016 +  if IsNullable then
2017 +    IsNull := False;
2018 +
2019 +  Changing;
2020 +  SQLType := SQL_TIMESTAMP_TZ;
2021 +  DataLength := SizeOf(ISC_TIMESTAMP_TZ);
2022 +  GetTimeZoneServices.EncodeTimestampTZ(aValue,aTimeZone,SQLData);
2023 +  Changed;
2024 + end;
2025 +
2026 + procedure TSQLDataItem.SetAsUTCDateTime(aUTCTime: TDateTime);
2027 + begin
2028 +  SetAsDateTime(aUTCTime,TimeZoneID_GMT);
2029 + end;
2030 +
2031   procedure TSQLDataItem.SetAsDouble(Value: Double);
2032   begin
2033    CheckActive;
# Line 1542 | Line 2113 | begin
2113    Changed;
2114   end;
2115  
2116 < procedure TSQLDataItem.SetAsString(Value: String);
2116 > procedure TSQLDataItem.SetAsString(Value: AnsiString);
2117   begin
2118    InternalSetAsString(Value);
2119   end;
# Line 1552 | Line 2123 | begin
2123    CheckActive;
2124    if VarIsNull(Value) then
2125      IsNull := True
2126 +  else
2127 +  if VarIsArray(Value) then {must be datetime plus timezone}
2128 +    SetAsDateTime(Value[0],AnsiString(Value[1]))
2129    else case VarType(Value) of
2130      varEmpty, varNull:
2131        IsNull := True;
# Line 1574 | Line 2148 | begin
2148        IBError(ibxeNotSupported, [nil]);
2149      varByRef, varDispatch, varError, varUnknown, varVariant:
2150        IBError(ibxeNotPermitted, [nil]);
2151 +    else
2152 +      if VarIsFmtBCD(Value) then
2153 +        SetAsBCD(VarToBCD(Value))
2154 +      else
2155 +        IBError(ibxeNotSupported, [nil]);
2156    end;
2157   end;
2158  
2159 + procedure TSQLDataItem.SetAsNumeric(Value: Int64; aScale: integer);
2160 + begin
2161 +  CheckActive;
2162 +  Changing;
2163 +  if IsNullable then
2164 +    IsNull := False;
2165 +
2166 +  SQLType := SQL_INT64;
2167 +  Scale := aScale;
2168 +  DataLength := SizeOf(Int64);
2169 +  PInt64(SQLData)^ := Value;
2170 +  Changed;
2171 + end;
2172 +
2173 + procedure TSQLDataItem.SetAsBcd(aValue: tBCD);
2174 + begin
2175 +  CheckActive;
2176 +  Changing;
2177 +  if IsNullable then
2178 +    IsNull := False;
2179 +
2180 +
2181 +  with FFirebirdClientAPI do
2182 +  if aValue.Precision <= 16 then
2183 +  begin
2184 +    if not HasDecFloatSupport then
2185 +      IBError(ibxeDecFloatNotSupported,[]);
2186 +
2187 +    SQLType := SQL_DEC16;
2188 +    DataLength := 8;
2189 +    SQLDecFloatEncode(aValue,SQLType,SQLData);
2190 +  end
2191 +  else
2192 +  if aValue.Precision <= 34 then
2193 +  begin
2194 +    if not HasDecFloatSupport then
2195 +      IBError(ibxeDecFloatNotSupported,[]);
2196 +
2197 +    SQLType := SQL_DEC34;
2198 +    DataLength := 16;
2199 +    SQLDecFloatEncode(aValue,SQLType,SQLData);
2200 +  end
2201 +  else
2202 +  if aValue.Precision <= 38 then
2203 +  begin
2204 +    if not HasInt128Support then
2205 +      IBError(ibxeInt128NotSupported,[]);
2206 +
2207 +    SQLType := SQL_INT128;
2208 +    DataLength := 16;
2209 +    StrToInt128(scale,BcdToStr(aValue),SQLData);
2210 +  end
2211 +  else
2212 +    IBError(ibxeBCDOverflow,[BCDToStr(aValue)]);
2213 +
2214 +  Changed;
2215 + end;
2216 +
2217   procedure TSQLDataItem.SetAsBoolean(AValue: boolean);
2218   begin
2219    CheckActive;
# Line 1607 | Line 2244 | begin
2244      IBError(ibxeStatementNotPrepared, [nil]);
2245   end;
2246  
2247 < function TColumnMetaData.SQLData: PChar;
2247 > function TColumnMetaData.GetAttachment: IAttachment;
2248 > begin
2249 >  Result := GetStatement.GetAttachment;
2250 > end;
2251 >
2252 > function TColumnMetaData.SQLData: PByte;
2253   begin
2254    Result := FIBXSQLVAR.SQLData;
2255   end;
# Line 1624 | Line 2266 | end;
2266  
2267   constructor TColumnMetaData.Create(aOwner: IUnknown; aIBXSQLVAR: TSQLVarData);
2268   begin
2269 <  inherited Create;
2269 >  inherited Create(aIBXSQLVAR.GetStatement.GetAttachment.getFirebirdAPI as TFBClientAPI);
2270    FIBXSQLVAR := aIBXSQLVAR;
2271    FOwner := aOwner;
2272    FPrepareSeqNo := FIBXSQLVAR.Parent.PrepareSeqNo;
# Line 1660 | Line 2302 | begin
2302    result := FIBXSQLVAR.SQLSubtype;
2303   end;
2304  
2305 < function TColumnMetaData.getRelationName: string;
2305 > function TColumnMetaData.getRelationName: AnsiString;
2306   begin
2307    CheckActive;
2308     result :=  FIBXSQLVAR.RelationName;
2309   end;
2310  
2311 < function TColumnMetaData.getOwnerName: string;
2311 > function TColumnMetaData.getOwnerName: AnsiString;
2312   begin
2313    CheckActive;
2314    result :=  FIBXSQLVAR.OwnerName;
2315   end;
2316  
2317 < function TColumnMetaData.getSQLName: string;
2317 > function TColumnMetaData.getSQLName: AnsiString;
2318   begin
2319    CheckActive;
2320    result :=  FIBXSQLVAR.FieldName;
2321   end;
2322  
2323 < function TColumnMetaData.getAliasName: string;
2323 > function TColumnMetaData.getAliasName: AnsiString;
2324   begin
2325    CheckActive;
2326    result := FIBXSQLVAR.AliasName;
2327   end;
2328  
2329 < function TColumnMetaData.GetName: string;
2329 > function TColumnMetaData.GetName: AnsiString;
2330   begin
2331    CheckActive;
2332    Result := FIBXSQLVAR. Name;
# Line 1711 | Line 2353 | end;
2353   function TColumnMetaData.GetSize: cardinal;
2354   begin
2355    CheckActive;
2356 <  result := FIBXSQLVAR.DataLength;
2356 >  result := FIBXSQLVAR.GetSize;
2357 > end;
2358 >
2359 > function TColumnMetaData.GetCharSetWidth: integer;
2360 > begin
2361 >  CheckActive;
2362 >  result := FIBXSQLVAR.GetCharSetWidth;
2363   end;
2364  
2365   function TColumnMetaData.GetArrayMetaData: IArrayMetaData;
# Line 1726 | Line 2374 | begin
2374    result := FIBXSQLVAR.GetBlobMetaData;
2375   end;
2376  
2377 + function TColumnMetaData.GetStatement: IStatement;
2378 + begin
2379 +  Result := FIBXSQLVAR.GetStatement;
2380 + end;
2381 +
2382 + function TColumnMetaData.GetTransaction: ITransaction;
2383 + begin
2384 +  Result := GetStatement.GetTransaction;
2385 + end;
2386 +
2387   { TIBSQLData }
2388  
2389   procedure TIBSQLData.CheckActive;
# Line 1745 | Line 2403 | begin
2403      IBError(ibxeBOF,[nil]);
2404   end;
2405  
2406 + function TIBSQLData.GetTransaction: ITransaction;
2407 + begin
2408 +  if FTransaction = nil then
2409 +    Result := inherited GetTransaction
2410 +  else
2411 +    Result := FTransaction;
2412 + end;
2413 +
2414   function TIBSQLData.GetIsNull: Boolean;
2415   begin
2416    CheckActive;
# Line 1754 | Line 2420 | end;
2420   function TIBSQLData.GetAsArray: IArray;
2421   begin
2422    CheckActive;
2423 <  result := FIBXSQLVAR.GetAsArray(AsQuad);
2423 >  result := FIBXSQLVAR.GetAsArray;
2424   end;
2425  
2426   function TIBSQLData.GetAsBlob: IBlob;
# Line 1769 | Line 2435 | begin
2435    result := FIBXSQLVAR.GetAsBlob(AsQuad,BPB);
2436   end;
2437  
2438 < function TIBSQLData.GetAsString: String;
2438 > function TIBSQLData.GetAsString: AnsiString;
2439   begin
2440    CheckActive;
2441    Result := '';
# Line 1777 | Line 2443 | begin
2443    if not IsNull then
2444    case SQLType of
2445      SQL_ARRAY:
2446 <      result := '(Array)'; {do not localize}
2446 >      result := SArray;
2447      SQL_BLOB:
2448 <      Result := Trim(FIBXSQLVAR.GetAsBlob(AsQuad,nil).GetAsString);
2448 >      Result := FIBXSQLVAR.GetAsBlob(AsQuad,nil).GetAsString;
2449      else
2450        Result := inherited GetAsString;
2451    end;
# Line 1787 | Line 2453 | end;
2453  
2454   { TSQLParam }
2455  
2456 < procedure TSQLParam.InternalSetAsString(Value: String);
2456 > procedure TSQLParam.InternalSetAsString(Value: AnsiString);
2457 >
2458 > procedure DoSetString;
2459 > begin
2460 >  Changing;
2461 >  FIBXSQLVar.SetString(Transliterate(Value,GetCodePage));
2462 >  Changed;
2463 > end;
2464 >
2465   var b: IBlob;
2466 +    dt: TDateTime;
2467 +    timezone: AnsiString;
2468 +    Int64Value: Int64;
2469 +    BCDValue: TBCD;
2470 +    aScale: integer;
2471   begin
2472    CheckActive;
2473    if IsNullable then
2474      IsNull := False;
2475 <  case SQLTYPE of
2475 >  with FFirebirdClientAPI do
2476 >  case getColMetaData.SQLTYPE of
2477    SQL_BOOLEAN:
2478 <    if CompareText(Value,STrue) = 0 then
2478 >    if AnsiCompareText(Value,STrue) = 0 then
2479        AsBoolean := true
2480      else
2481 <    if CompareText(Value,SFalse) = 0 then
2481 >    if AnsiCompareText(Value,SFalse) = 0 then
2482        AsBoolean := false
2483      else
2484        IBError(ibxeInvalidDataConversion,[nil]);
2485  
2486    SQL_BLOB:
2487 +    if Length(Value) < GetAttachment.GetInlineBlobLimit then
2488 +      DoSetString
2489 +    else
2490      begin
2491        Changing;
2492        b := FIBXSQLVAR.CreateBlob;
# Line 1814 | Line 2497 | begin
2497  
2498    SQL_VARYING,
2499    SQL_TEXT:
2500 <    begin
1818 <      Changing;
1819 <      FIBXSQLVar.SetString(Transliterate(Value,GetCodePage));
1820 <      Changed;
1821 <    end;
2500 >    DoSetString;
2501  
2502 <    SQL_SHORT,
2503 <    SQL_LONG,
2504 <    SQL_INT64:
2505 <      SetAsInt64(StrToInt(Value));
2506 <
2507 <    SQL_D_FLOAT,
2508 <    SQL_DOUBLE,
1830 <    SQL_FLOAT:
1831 <      SetAsDouble(StrToFloat(Value));
2502 >  SQL_SHORT,
2503 >  SQL_LONG,
2504 >  SQL_INT64:
2505 >    if TryStrToNumeric(Value,Int64Value,aScale) then
2506 >      SetAsNumeric(Int64Value,aScale)
2507 >    else
2508 >      DoSetString;
2509  
2510 <    SQL_TIMESTAMP:
2511 <      SetAsDateTime(StrToDateTime(Value));
2510 >  SQL_DEC_FIXED,
2511 >  SQL_DEC16,
2512 >  SQL_DEC34,
2513 >  SQL_INT128:
2514 >    if TryStrToBCD(Value,BCDValue) then
2515 >      SetAsBCD(BCDValue)
2516 >    else
2517 >      DoSetString;
2518  
2519 <    SQL_TYPE_DATE:
2520 <      SetAsDate(StrToDateTime(Value));
2519 >  SQL_D_FLOAT,
2520 >  SQL_DOUBLE,
2521 >  SQL_FLOAT:
2522 >    if TryStrToNumeric(Value,Int64Value,aScale) then
2523 >      SetAsDouble(NumericToDouble(Int64Value,aScale))
2524 >    else
2525 >      DoSetString;
2526  
2527 <    SQL_TYPE_TIME:
2528 <      SetAsTime(StrToDateTime(Value));
2527 >  SQL_TIMESTAMP:
2528 >      if TryStrToDateTime(Value,dt) then
2529 >        SetAsDateTime(dt)
2530 >      else
2531 >        DoSetString;
2532  
2533 <    else
2534 <      IBError(ibxeInvalidDataConversion,[nil]);
2533 >  SQL_TYPE_DATE:
2534 >      if TryStrToDateTime(Value,dt) then
2535 >        SetAsDate(dt)
2536 >      else
2537 >        DoSetString;
2538 >
2539 >  SQL_TYPE_TIME:
2540 >      if TryStrToDateTime(Value,dt) then
2541 >        SetAsTime(dt)
2542 >      else
2543 >        DoSetString;
2544 >
2545 >  SQL_TIMESTAMP_TZ,
2546 >  SQL_TIMESTAMP_TZ_EX:
2547 >      if ParseDateTimeTZString(value,dt,timezone) then
2548 >        SetAsDateTime(dt,timezone)
2549 >      else
2550 >        DoSetString;
2551 >
2552 >  SQL_TIME_TZ,
2553 >  SQL_TIME_TZ_EX:
2554 >      if ParseDateTimeTZString(value,dt,timezone,true) then
2555 >        SetAsTime(dt,GetAttachment.GetTimeZoneServices.GetTimeTZDate,timezone)
2556 >      else
2557 >        DoSetString;
2558 >
2559 >  else
2560 >    IBError(ibxeInvalidDataConversion,[GetSQLTypeName(getColMetaData.SQLTYPE)]);
2561    end;
2562   end;
2563  
# Line 1878 | Line 2595 | begin
2595    IsNull := true;
2596   end;
2597  
2598 + function TSQLParam.getColMetadata: IParamMetaData;
2599 + begin
2600 +  Result := FIBXSQLVAR.getColMetadata;
2601 + end;
2602 +
2603   function TSQLParam.GetModified: boolean;
2604   begin
2605    CheckActive;
# Line 1891 | Line 2613 | begin
2613    Result := inherited GetAsPointer;
2614   end;
2615  
2616 < procedure TSQLParam.SetName(Value: string);
2616 > function TSQLParam.GetAsString: AnsiString;
2617 > var rs: RawByteString;
2618 > begin
2619 >  Result := '';
2620 >  if (SQLType = SQL_VARYING) and not IsNull then
2621 >  {SQLData points to start of string - default is to length word}
2622 >  begin
2623 >    CheckActive;
2624 >    SetString(rs,PAnsiChar(SQLData),DataLength);
2625 >    SetCodePage(rs,GetCodePage,false);
2626 >    Result := rs;
2627 >  end
2628 >  else
2629 >    Result := inherited GetAsString;
2630 > end;
2631 >
2632 > procedure TSQLParam.SetName(Value: AnsiString);
2633   begin
2634    CheckActive;
2635    FIBXSQLVAR.Name := Value;
# Line 1936 | Line 2674 | begin
2674    if not FIBXSQLVAR.UniqueName then
2675      IBError(ibxeDuplicateParamName,[FIBXSQLVAR.Name]);
2676  
2677 +  FIBXSQLVAR.SetArray(anArray); {save array interface}
2678    SetAsQuad(AnArray.GetArrayID);
2679   end;
2680  
# Line 2082 | Line 2821 | begin
2821    end;
2822   end;
2823  
2824 + procedure TSQLParam.SetAsTime(aValue: TDateTime; OnDate: TDateTime; aTimeZoneID: TFBTimeZoneID);
2825 + var i: integer;
2826 +    OldSQLVar: TSQLVarData;
2827 + begin
2828 +  if FIBXSQLVAR.UniqueName then
2829 +    inherited SetAsTime(AValue,OnDate, aTimeZoneID)
2830 +  else
2831 +  with FIBXSQLVAR.Parent do
2832 +  begin
2833 +    for i := 0 to Count - 1 do
2834 +      if Column[i].Name = Name then
2835 +      begin
2836 +        OldSQLVar := FIBXSQLVAR;
2837 +        FIBXSQLVAR := Column[i];
2838 +        try
2839 +          inherited SetAsTime(AValue,OnDate, aTimeZoneID);
2840 +        finally
2841 +          FIBXSQLVAR := OldSQLVar;
2842 +        end;
2843 +      end;
2844 +  end;
2845 + end;
2846 +
2847 + procedure TSQLParam.SetAsTime(aValue: TDateTime; OnDate: TDateTime; aTimeZone: AnsiString);
2848 + var i: integer;
2849 +    OldSQLVar: TSQLVarData;
2850 + begin
2851 +  if FIBXSQLVAR.UniqueName then
2852 +    inherited SetAsTime(AValue,OnDate,aTimeZone)
2853 +  else
2854 +  with FIBXSQLVAR.Parent do
2855 +  begin
2856 +    for i := 0 to Count - 1 do
2857 +      if Column[i].Name = Name then
2858 +      begin
2859 +        OldSQLVar := FIBXSQLVAR;
2860 +        FIBXSQLVAR := Column[i];
2861 +        try
2862 +          inherited SetAsTime(AValue,OnDate,aTimeZone);
2863 +        finally
2864 +          FIBXSQLVAR := OldSQLVar;
2865 +        end;
2866 +      end;
2867 +  end;
2868 + end;
2869 +
2870 + procedure TSQLParam.SetAsTime(aValue: TDateTime; aTimeZoneID: TFBTimeZoneID);
2871 + begin
2872 +  SetAsTime(aValue,GetTimeZoneServices.GetTimeTZDate,aTimeZoneID);
2873 + end;
2874 +
2875 + procedure TSQLParam.SetAsTime(aValue: TDateTime; aTimeZone: AnsiString);
2876 + begin
2877 +  SetAsTime(aValue,GetTimeZoneServices.GetTimeTZDate,aTimeZone);
2878 + end;
2879 +
2880   procedure TSQLParam.SetAsDateTime(AValue: TDateTime);
2881   var i: integer;
2882      OldSQLVar: TSQLVarData;
# Line 2105 | Line 2900 | begin
2900    end;
2901   end;
2902  
2903 + procedure TSQLParam.SetAsDateTime(aValue: TDateTime; aTimeZoneID: TFBTimeZoneID
2904 +  );
2905 + var i: integer;
2906 +    OldSQLVar: TSQLVarData;
2907 + begin
2908 +  if FIBXSQLVAR.UniqueName then
2909 +    inherited SetAsDateTime(AValue,aTimeZoneID)
2910 +  else
2911 +  with FIBXSQLVAR.Parent do
2912 +  begin
2913 +    for i := 0 to Count - 1 do
2914 +      if Column[i].Name = Name then
2915 +      begin
2916 +        OldSQLVar := FIBXSQLVAR;
2917 +        FIBXSQLVAR := Column[i];
2918 +        try
2919 +          inherited SetAsDateTime(AValue,aTimeZoneID);
2920 +        finally
2921 +          FIBXSQLVAR := OldSQLVar;
2922 +        end;
2923 +      end;
2924 +  end;
2925 + end;
2926 +
2927 + procedure TSQLParam.SetAsDateTime(aValue: TDateTime; aTimeZone: AnsiString);
2928 + var i: integer;
2929 +    OldSQLVar: TSQLVarData;
2930 + begin
2931 +  if FIBXSQLVAR.UniqueName then
2932 +    inherited SetAsDateTime(AValue,aTimeZone)
2933 +  else
2934 +  with FIBXSQLVAR.Parent do
2935 +  begin
2936 +    for i := 0 to Count - 1 do
2937 +      if Column[i].Name = Name then
2938 +      begin
2939 +        OldSQLVar := FIBXSQLVAR;
2940 +        FIBXSQLVAR := Column[i];
2941 +        try
2942 +          inherited SetAsDateTime(AValue,aTimeZone);
2943 +        finally
2944 +          FIBXSQLVAR := OldSQLVar;
2945 +        end;
2946 +      end;
2947 +  end;
2948 + end;
2949 +
2950   procedure TSQLParam.SetAsDouble(AValue: Double);
2951   var i: integer;
2952      OldSQLVar: TSQLVarData;
# Line 2197 | Line 3039 | begin
3039    end;
3040   end;
3041  
3042 < procedure TSQLParam.SetAsString(AValue: String);
3042 > procedure TSQLParam.SetAsString(AValue: AnsiString);
3043   var i: integer;
3044      OldSQLVar: TSQLVarData;
3045   begin
# Line 2285 | Line 3127 | begin
3127    FIBXSQLVAR.SetCharSetID(aValue);
3128   end;
3129  
3130 + procedure TSQLParam.SetAsBcd(aValue: tBCD);
3131 + var i: integer;
3132 +    OldSQLVar: TSQLVarData;
3133 + begin
3134 +  if FIBXSQLVAR.UniqueName then
3135 +    inherited SetAsBcd(AValue)
3136 +  else
3137 +  with FIBXSQLVAR.Parent do
3138 +  begin
3139 +    for i := 0 to Count - 1 do
3140 +      if Column[i].Name = Name then
3141 +      begin
3142 +        OldSQLVar := FIBXSQLVAR;
3143 +        FIBXSQLVAR := Column[i];
3144 +        try
3145 +          inherited SetAsBcd(AValue);
3146 +        finally
3147 +          FIBXSQLVAR := OldSQLVar;
3148 +        end;
3149 +      end;
3150 +  end;
3151 + end;
3152 +
3153   { TMetaData }
3154  
3155   procedure TMetaData.CheckActive;
# Line 2310 | Line 3175 | begin
3175    inherited Destroy;
3176   end;
3177  
3178 < function TMetaData.GetUniqueRelationName: string;
3178 > function TMetaData.GetUniqueRelationName: AnsiString;
3179   begin
3180    CheckActive;
3181    Result := FMetaData.UniqueRelationName;
# Line 2338 | Line 3203 | begin
3203    end;
3204   end;
3205  
3206 < function TMetaData.ByName(Idx: String): IColumnMetaData;
3206 > function TMetaData.ByName(Idx: AnsiString): IColumnMetaData;
3207   var aIBXSQLVAR: TSQLVarData;
3208   begin
3209    CheckActive;
# Line 2398 | Line 3263 | begin
3263    end;
3264   end;
3265  
3266 < function TSQLParams.ByName(Idx: String): ISQLParam;
3266 > function TSQLParams.ByName(Idx: AnsiString): ISQLParam;
3267   var aIBXSQLVAR: TSQLVarData;
3268   begin
3269    CheckActive;
# Line 2423 | Line 3288 | begin
3288      end;
3289   end;
3290  
3291 + function TSQLParams.GetHasCaseSensitiveParams: Boolean;
3292 + begin
3293 +  Result := FSQLParams.CaseSensitiveParams;
3294 + end;
3295 +
3296   { TResults }
3297  
3298   procedure TResults.CheckActive;
# Line 2435 | Line 3305 | begin
3305    if not FResults.CheckStatementStatus(ssPrepared)  then
3306      IBError(ibxeStatementNotPrepared, [nil]);
3307  
3308 <  with GetTransaction as TFBTransaction do
3308 >  with GetTransaction do
3309    if not InTransaction or (FResults.TransactionSeqNo <> FTransactionSeqNo) then
3310      IBError(ibxeInterfaceOutofDate,[nil]);
3311   end;
3312  
3313   function TResults.GetISQLData(aIBXSQLVAR: TSQLVarData): ISQLData;
3314 + var col: TIBSQLData;
3315   begin
3316    if (aIBXSQLVAR.Index < 0) or (aIBXSQLVAR.Index >= getCount) then
3317      IBError(ibxeInvalidColumnIndex,[nil]);
3318  
3319    if not HasInterface(aIBXSQLVAR.Index) then
3320      AddInterface(aIBXSQLVAR.Index, TIBSQLData.Create(self,aIBXSQLVAR));
3321 <  Result := TIBSQLData(GetInterface(aIBXSQLVAR.Index));
3321 >  col := TIBSQLData(GetInterface(aIBXSQLVAR.Index));
3322 >  col.FTransaction := GetTransaction;
3323 >  Result := col;
3324   end;
3325  
3326   constructor TResults.Create(aResults: TSQLDataArea);
# Line 2466 | Line 3339 | begin
3339    Result := FResults.Count;
3340   end;
3341  
3342 < function TResults.ByName(Idx: String): ISQLData;
3342 > function TResults.ByName(Idx: AnsiString): ISQLData;
3343   var col: TSQLVarData;
3344   begin
3345    Result := nil;
# Line 2498 | Line 3371 | begin
3371   end;
3372  
3373   procedure TResults.GetData(index: integer; var IsNull: boolean; var len: short;
3374 <  var data: PChar);
3374 >  var data: PByte);
3375   begin
3376    CheckActive;
3377    FResults.GetData(index,IsNull, len,data);
3378   end;
3379  
3380 + function TResults.GetStatement: IStatement;
3381 + begin
3382 +  Result := FStatement;
3383 + end;
3384 +
3385   function TResults.GetTransaction: ITransaction;
3386   begin
3387    Result := FStatement.GetTransaction;
# Line 2514 | Line 3392 | begin
3392    RetainInterfaces := aValue;
3393   end;
3394  
2517
3395   end.
3396  

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines