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 47 by tony, Mon Jan 9 15:31:51 2017 UTC vs.
Revision 349 by tony, Mon Oct 18 08:39:40 2021 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 AdjustScale(Value: Int64; aScale: Integer): Double;
126       function AdjustScaleToInt64(Value: Int64; aScale: Integer): Int64;
127       function AdjustScaleToCurrency(Value: Int64; aScale: Integer): Currency;
128 +     function GetDateFormatStr(IncludeTime: boolean): AnsiString;
129 +     function GetTimeFormatStr: AnsiString;
130 +     function GetTimestampFormatStr: AnsiString;
131       procedure SetAsInteger(AValue: Integer);
132 +     procedure InternalGetAsDateTime(var aDateTime: TDateTime; var dstOffset: smallint;
133 +       var aTimezone: AnsiString; var aTimeZoneID: TFBTimeZoneID);
134    protected
135       function AdjustScaleFromCurrency(Value: Currency; aScale: Integer): Int64;
136       function AdjustScaleFromDouble(Value: Double; aScale: Integer): Int64;
137       procedure CheckActive; virtual;
138 +     procedure CheckTZSupport;
139 +     function GetAttachment: IAttachment; virtual; abstract;
140       function GetSQLDialect: integer; virtual; abstract;
141 +     function GetTimeZoneServices: IExTimeZoneServices; virtual;
142       procedure Changed; virtual;
143       procedure Changing; virtual;
144 <     procedure InternalSetAsString(Value: String); virtual;
145 <     function SQLData: PChar; virtual; abstract;
144 >     procedure InternalSetAsString(Value: AnsiString); virtual;
145 >     function SQLData: PByte; virtual; abstract;
146       function GetDataLength: cardinal; virtual; abstract;
147       function GetCodePage: TSystemCodePage; virtual; abstract;
148       function getCharSetID: cardinal; virtual; abstract;
149 <     function Transliterate(s: string; CodePage: TSystemCodePage): RawByteString;
149 >     function Transliterate(s: AnsiString; CodePage: TSystemCodePage): RawByteString;
150       procedure SetScale(aValue: integer); virtual;
151       procedure SetDataLength(len: cardinal); virtual;
152       procedure SetSQLType(aValue: cardinal); virtual;
153       property DataLength: cardinal read GetDataLength write SetDataLength;
154 <
154 >     property FirebirdClientAPI: TFBClientAPI read FFirebirdClientAPI;
155    public
156 <     function GetSQLType: cardinal; virtual; abstract;
157 <     function GetSQLTypeName: string; overload;
158 <     class function GetSQLTypeName(SQLType: short): string; overload;
159 <     function GetName: string; virtual; abstract;
160 <     function GetScale: integer; virtual; abstract;
156 >     constructor Create(api: TFBClientAPI);
157 >     function GetSQLType: cardinal; virtual; abstract; {Current Field Data SQL Type}
158 >     function GetSQLTypeName: AnsiString; overload;
159 >     class function GetSQLTypeName(SQLType: cardinal): AnsiString; overload;
160 >     function GetStrDataLength: short;
161 >     function GetName: AnsiString; virtual; abstract;
162 >     function GetScale: integer; virtual; abstract; {Current Field Data scale}
163       function GetAsBoolean: boolean;
164       function GetAsCurrency: Currency;
165       function GetAsInt64: Int64;
166 <     function GetAsDateTime: TDateTime;
166 >     function GetAsDateTime: TDateTime; overload;
167 >     procedure GetAsDateTime(var aDateTime: TDateTime; var dstOffset: smallint; var aTimezone: AnsiString); overload;
168 >     procedure GetAsDateTime(var aDateTime: TDateTime; var dstOffset: smallint; var aTimezoneID: TFBTimeZoneID); overload;
169 >     procedure GetAsTime(var aTime: TDateTime; var dstOffset: smallint; var aTimezoneID: TFBTimeZoneID; OnDate: TDateTime); overload;
170 >     procedure GetAsTime(var aTime: TDateTime; var dstOffset: smallint; var aTimezone: AnsiString; OnDate: TDateTime); overload;
171 >     procedure GetAsTime(var aTime: TDateTime; var dstOffset: smallint; var aTimezoneID: TFBTimeZoneID); overload;
172 >     procedure GetAsTime(var aTime: TDateTime; var dstOffset: smallint; var aTimezone: AnsiString); overload;
173 >     function GetAsUTCDateTime: TDateTime;
174       function GetAsDouble: Double;
175       function GetAsFloat: Float;
176       function GetAsLong: Long;
177       function GetAsPointer: Pointer;
178       function GetAsQuad: TISC_QUAD;
179       function GetAsShort: short;
180 <     function GetAsString: String; virtual;
180 >     function GetAsString: AnsiString; virtual;
181       function GetIsNull: Boolean; virtual;
182 <     function getIsNullable: boolean; virtual;
182 >     function GetIsNullable: boolean; virtual;
183       function GetAsVariant: Variant;
184       function GetModified: boolean; virtual;
185 +     function GetDateTimeStrLength(DateTimeFormat: TIBDateTimeFormats): integer;
186 +     function GetAsBCD: tBCD;
187 +     function GetSize: cardinal; virtual; abstract;
188 +     function GetCharSetWidth: integer; virtual; abstract;
189       procedure SetAsBoolean(AValue: boolean); virtual;
190       procedure SetAsCurrency(Value: Currency); virtual;
191       procedure SetAsInt64(Value: Int64); virtual;
192       procedure SetAsDate(Value: TDateTime); virtual;
193       procedure SetAsLong(Value: Long); virtual;
194 <     procedure SetAsTime(Value: TDateTime); virtual;
195 <     procedure SetAsDateTime(Value: TDateTime);
194 >     procedure SetAsTime(Value: TDateTime); overload;
195 >     procedure SetAsTime(aValue: TDateTime; OnDate: TDateTime;aTimeZoneID: TFBTimeZoneID); overload;
196 >     procedure SetAsTime(aValue: TDateTime; OnDate: TDateTime; aTimeZone: AnsiString); overload;
197 >     procedure SetAsDateTime(Value: TDateTime); overload;
198 >     procedure SetAsDateTime(aValue: TDateTime; aTimeZoneID: TFBTimeZoneID); overload;
199 >     procedure SetAsDateTime(aValue: TDateTime; aTimeZone: AnsiString); overload;
200 >     procedure SetAsUTCDateTime(aUTCTime: TDateTime);
201       procedure SetAsDouble(Value: Double); virtual;
202       procedure SetAsFloat(Value: Float); virtual;
203       procedure SetAsPointer(Value: Pointer);
204       procedure SetAsQuad(Value: TISC_QUAD);
205       procedure SetAsShort(Value: short); virtual;
206 <     procedure SetAsString(Value: String); virtual;
206 >     procedure SetAsString(Value: AnsiString); virtual;
207       procedure SetAsVariant(Value: Variant);
208 +     procedure SetAsNumeric(Value: Int64; aScale: integer);
209 +     procedure SetAsBcd(aValue: tBCD); virtual;
210       procedure SetIsNull(Value: Boolean); virtual;
211       procedure SetIsNullable(Value: Boolean); virtual;
212 <     procedure SetName(aValue: string); virtual;
212 >     procedure SetName(aValue: AnsiString); virtual;
213       property AsDate: TDateTime read GetAsDateTime write SetAsDate;
214       property AsBoolean:boolean read GetAsBoolean write SetAsBoolean;
215       property AsTime: TDateTime read GetAsDateTime write SetAsTime;
# Line 175 | Line 223 | type
223       property AsPointer: Pointer read GetAsPointer write SetAsPointer;
224       property AsQuad: TISC_QUAD read GetAsQuad write SetAsQuad;
225       property AsShort: short read GetAsShort write SetAsShort;
226 <     property AsString: String read GetAsString write SetAsString;
226 >     property AsString: AnsiString read GetAsString write SetAsString;
227       property AsVariant: Variant read GetAsVariant write SetAsVariant;
228       property Modified: Boolean read getModified;
229       property IsNull: Boolean read GetIsNull write SetIsNull;
# Line 192 | Line 240 | type
240  
241    TSQLDataArea = class
242    private
243 +    FCaseSensitiveParams: boolean;
244      function GetColumn(index: integer): TSQLVarData;
245      function GetCount: integer;
246    protected
247 <    FUniqueRelationName: string;
247 >    FUniqueRelationName: AnsiString;
248      FColumnList: array of TSQLVarData;
249      function GetStatement: IStatement; virtual; abstract;
250      function GetPrepareSeqNo: integer; virtual; abstract;
# Line 205 | Line 254 | type
254    public
255      procedure Initialize; virtual;
256      function IsInputDataArea: boolean; virtual; abstract; {Input to Database}
257 <    procedure PreprocessSQL(sSQL: string; GenerateParamNames: boolean;
258 <      var sProcessedSQL: string);
257 >    procedure PreprocessSQL(sSQL: AnsiString; GenerateParamNames: boolean;
258 >      var sProcessedSQL: AnsiString);
259      function ColumnsInUseCount: integer; virtual;
260 <    function ColumnByName(Idx: string): TSQLVarData;
260 >    function ColumnByName(Idx: AnsiString): TSQLVarData;
261      function CheckStatementStatus(Request: TStatementStatus): boolean; virtual; abstract;
262      procedure GetData(index: integer; var IsNull: boolean; var len: short;
263 <      var data: PChar); virtual;
263 >      var data: PByte); virtual;
264      procedure RowChange;
265      function StateChanged(var ChangeSeqNo: integer): boolean; virtual; abstract;
266 +    property CaseSensitiveParams: boolean read FCaseSensitiveParams
267 +                                            write FCaseSensitiveParams; {Only used when IsInputDataArea true}
268 +    function CanChangeMetaData: boolean; virtual; abstract;
269      property Count: integer read GetCount;
270      property Column[index: integer]: TSQLVarData read GetColumn;
271 <    property UniqueRelationName: string read FUniqueRelationName;
271 >    property UniqueRelationName: AnsiString read FUniqueRelationName;
272      property Statement: IStatement read GetStatement;
273      property PrepareSeqNo: integer read GetPrepareSeqNo;
274      property TransactionSeqNo: integer read GetTransactionSeqNo;
# Line 227 | Line 279 | type
279    TSQLVarData = class
280    private
281      FParent: TSQLDataArea;
282 <    FName: string;
282 >    FName: AnsiString;
283      FIndex: integer;
284      FModified: boolean;
285      FUniqueName: boolean;
286      FVarString: RawByteString;
287 +    FColMetaData: IParamMetaData;
288      function GetStatement: IStatement;
289 <    procedure SetName(AValue: string);
289 >    procedure SetName(AValue: AnsiString);
290    protected
291 +    function GetAttachment: IAttachment; virtual; abstract;
292      function GetSQLType: cardinal; virtual; abstract;
293      function GetSubtype: integer; virtual; abstract;
294 <    function GetAliasName: string;  virtual; abstract;
295 <    function GetFieldName: string; virtual; abstract;
296 <    function GetOwnerName: string;  virtual; abstract;
297 <    function GetRelationName: string;  virtual; abstract;
294 >    function GetAliasName: AnsiString;  virtual; abstract;
295 >    function GetFieldName: AnsiString; virtual; abstract;
296 >    function GetOwnerName: AnsiString;  virtual; abstract;
297 >    function GetRelationName: AnsiString;  virtual; abstract;
298      function GetScale: integer; virtual; abstract;
299      function GetCharSetID: cardinal; virtual; abstract;
300 +    function GetCharSetWidth: integer; virtual; abstract;
301      function GetCodePage: TSystemCodePage; virtual; abstract;
302      function GetIsNull: Boolean;   virtual; abstract;
303      function GetIsNullable: boolean; virtual; abstract;
304 <    function GetSQLData: PChar;  virtual; abstract;
305 <    function GetDataLength: cardinal; virtual; abstract;
304 >    function GetSQLData: PByte;  virtual; abstract;
305 >    function GetDataLength: cardinal; virtual; abstract; {current field length}
306 >    function GetSize: cardinal; virtual; abstract; {field length as given by metadata}
307 >    function GetDefaultTextSQLType: cardinal; virtual; abstract;
308      procedure SetIsNull(Value: Boolean); virtual; abstract;
309      procedure SetIsNullable(Value: Boolean);  virtual; abstract;
310 <    procedure SetSQLData(AValue: PChar; len: cardinal); virtual; abstract;
310 >    procedure SetSQLData(AValue: PByte; len: cardinal); virtual; abstract;
311      procedure SetScale(aValue: integer); virtual; abstract;
312      procedure SetDataLength(len: cardinal); virtual; abstract;
313      procedure SetSQLType(aValue: cardinal); virtual; abstract;
314      procedure SetCharSetID(aValue: cardinal); virtual; abstract;
315 +    procedure SetMetaSize(aValue: cardinal); virtual;
316    public
317      constructor Create(aParent: TSQLDataArea; aIndex: integer);
318 <    procedure SetString(aValue: string);
318 >    procedure SetString(aValue: AnsiString);
319      procedure Changed; virtual;
320      procedure RowChange; virtual;
321      function GetAsArray(Array_ID: TISC_QUAD): IArray; virtual; abstract;
# Line 265 | Line 323 | type
323      function CreateBlob: IBlob; virtual; abstract;
324      function GetArrayMetaData: IArrayMetaData; virtual; abstract;
325      function GetBlobMetaData: IBlobMetaData; virtual; abstract;
326 +    function getColMetadata: IParamMetaData;
327      procedure Initialize; virtual;
328 +    procedure SaveMetaData;
329  
330    public
331 <    property AliasName: string read GetAliasName;
332 <    property FieldName: string read GetFieldName;
333 <    property OwnerName: string read GetOwnerName;
334 <    property RelationName: string read GetRelationName;
331 >    property AliasName: AnsiString read GetAliasName;
332 >    property FieldName: AnsiString read GetFieldName;
333 >    property OwnerName: AnsiString read GetOwnerName;
334 >    property RelationName: AnsiString read GetRelationName;
335      property Parent: TSQLDataArea read FParent;
336      property Index: integer read FIndex;
337 <    property Name: string read FName write SetName;
337 >    property Name: AnsiString read FName write SetName;
338      property CharSetID: cardinal read GetCharSetID write SetCharSetID;
339      property SQLType: cardinal read GetSQLType write SetSQLType;
340      property SQLSubtype: integer read GetSubtype;
341 <    property SQLData: PChar read GetSQLData;
341 >    property SQLData: PByte read GetSQLData;
342      property DataLength: cardinal read GetDataLength write SetDataLength;
343      property IsNull: Boolean read GetIsNull write SetIsNull;
344      property IsNullable: Boolean read GetIsNullable write SetIsNullable;
# Line 296 | Line 356 | type
356      FIBXSQLVAR: TSQLVarData;
357      FOwner: IUnknown;         {Keep reference to ensure Metadata/statement not discarded}
358      FPrepareSeqNo: integer;
299    FStatement: IStatement;
359      FChangeSeqNo: integer;
360    protected
361      procedure CheckActive; override;
362 <    function SQLData: PChar; override;
362 >    function GetAttachment: IAttachment; override;
363 >    function SQLData: PByte; override;
364      function GetDataLength: cardinal; override;
365      function GetCodePage: TSystemCodePage; override;
366  
# Line 308 | Line 368 | type
368      constructor Create(aOwner: IUnknown; aIBXSQLVAR: TSQLVarData);
369      destructor Destroy; override;
370      function GetSQLDialect: integer; override;
311    property Statement: IStatement read FStatement;
371  
372    public
373      {IColumnMetaData}
374      function GetIndex: integer;
375      function GetSQLType: cardinal; override;
376      function getSubtype: integer;
377 <    function getRelationName: string;
378 <    function getOwnerName: string;
379 <    function getSQLName: string;    {Name of the column}
380 <    function getAliasName: string;  {Alias Name of column or Column Name if not alias}
381 <    function GetName: string; override;      {Disambiguated uppercase Field Name}
377 >    function getRelationName: AnsiString;
378 >    function getOwnerName: AnsiString;
379 >    function getSQLName: AnsiString;    {Name of the column}
380 >    function getAliasName: AnsiString;  {Alias Name of column or Column Name if not alias}
381 >    function GetName: AnsiString; override;      {Disambiguated uppercase Field Name}
382      function GetScale: integer; override;
383      function getCharSetID: cardinal; override;
384      function GetIsNullable: boolean; override;
385 <    function GetSize: cardinal;
385 >    function GetSize: cardinal; override;
386 >    function GetCharSetWidth: integer; override;
387      function GetArrayMetaData: IArrayMetaData;
388      function GetBlobMetaData: IBlobMetaData;
389 <    property Name: string read GetName;
389 >    function GetStatement: IStatement;
390 >    function GetTransaction: ITransaction; virtual;
391 >    property Name: AnsiString read GetName;
392      property Size: cardinal read GetSize;
393      property CharSetID: cardinal read getCharSetID;
394      property SQLSubtype: integer read getSubtype;
395      property IsNullable: Boolean read GetIsNullable;
396 +  public
397 +    property Statement: IStatement read GetStatement;
398    end;
399  
400    { TIBSQLData }
401  
402    TIBSQLData = class(TColumnMetaData,ISQLData)
403 +  private
404 +    FTransaction: ITransaction;
405    protected
406      procedure CheckActive; override;
407    public
408 +    function GetTransaction: ITransaction; override;
409      function GetIsNull: Boolean; override;
410      function GetAsArray: IArray;
411      function GetAsBlob: IBlob; overload;
412      function GetAsBlob(BPB: IBPB): IBlob; overload;
413 <    function GetAsString: String; override;
413 >    function GetAsString: AnsiString; override;
414      property AsBlob: IBlob read GetAsBlob;
415   end;
416  
417 +  { TSQLParamMetaData }
418 +
419 +  TSQLParamMetaData = class(TFBInterfacedObject,IParamMetaData)
420 +  private
421 +    FSQLType: cardinal;
422 +    FSQLSubType: integer;
423 +    FScale: integer;
424 +    FCharSetID: cardinal;
425 +    FNullable: boolean;
426 +    FSize: cardinal;
427 +    FCodePage: TSystemCodePage;
428 +  public
429 +    constructor Create(src: TSQLVarData);
430 +    {IParamMetaData}
431 +    function GetSQLType: cardinal;
432 +    function GetSQLTypeName: AnsiString;
433 +    function getSubtype: integer;
434 +    function getScale: integer;
435 +    function getCharSetID: cardinal;
436 +    function getCodePage: TSystemCodePage;
437 +    function getIsNullable: boolean;
438 +    function GetSize: cardinal;
439 +    property SQLType: cardinal read GetSQLType;
440 +  end;
441 +
442    { TSQLParam }
443  
444 <  TSQLParam = class(TIBSQLData,ISQLParam)
444 >  TSQLParam = class(TIBSQLData,ISQLParam,ISQLData)
445    protected
446      procedure CheckActive; override;
447      procedure Changed; override;
448 <    procedure InternalSetAsString(Value: String); override;
448 >    procedure InternalSetAsString(Value: AnsiString); override;
449      procedure SetScale(aValue: integer); override;
450      procedure SetDataLength(len: cardinal); override;
451      procedure SetSQLType(aValue: cardinal); override;
452    public
453      procedure Clear;
454 +    function getColMetadata: IParamMetaData;
455      function GetModified: boolean; override;
456      function GetAsPointer: Pointer;
457 <    procedure SetName(Value: string); override;
457 >    function GetAsString: AnsiString; override;
458 >    procedure SetName(Value: AnsiString); override;
459      procedure SetIsNull(Value: Boolean);  override;
460      procedure SetIsNullable(Value: Boolean); override;
461      procedure SetAsArray(anArray: IArray);
# Line 372 | Line 466 | type
466      procedure SetAsInt64(AValue: Int64);
467      procedure SetAsDate(AValue: TDateTime);
468      procedure SetAsLong(AValue: Long);
469 <    procedure SetAsTime(AValue: TDateTime);
470 <    procedure SetAsDateTime(AValue: TDateTime);
469 >    procedure SetAsTime(AValue: TDateTime); overload;
470 >    procedure SetAsTime(aValue: TDateTime; OnDate: TDateTime; aTimeZoneID: TFBTimeZoneID); overload;
471 >    procedure SetAsTime(aValue: TDateTime; OnDate: TDateTime; aTimeZone: AnsiString); overload;
472 >    procedure SetAsTime(aValue: TDateTime; aTimeZoneID: TFBTimeZoneID); overload;
473 >    procedure SetAsTime(aValue: TDateTime; aTimeZone: AnsiString); overload;
474 >    procedure SetAsDateTime(AValue: TDateTime); overload;
475 >    procedure SetAsDateTime(aValue: TDateTime; aTimeZoneID: TFBTimeZoneID); overload;
476 >    procedure SetAsDateTime(aValue: TDateTime; aTimeZone: AnsiString); overload;
477      procedure SetAsDouble(AValue: Double);
478      procedure SetAsFloat(AValue: Float);
479      procedure SetAsPointer(AValue: Pointer);
480      procedure SetAsShort(AValue: Short);
481 <    procedure SetAsString(AValue: String); override;
481 >    procedure SetAsString(AValue: AnsiString); override;
482      procedure SetAsVariant(AValue: Variant);
483      procedure SetAsBlob(aValue: IBlob);
484      procedure SetAsQuad(AValue: TISC_QUAD);
485      procedure SetCharSetID(aValue: cardinal);
486 +    procedure SetAsBcd(aValue: tBCD);
487  
488      property AsBlob: IBlob read GetAsBlob write SetAsBlob;
489      property IsNullable: Boolean read GetIsNullable write SetIsNullable;
# Line 401 | Line 502 | type
502      destructor Destroy; override;
503    public
504      {IMetaData}
505 <    function GetUniqueRelationName: string;
505 >    function GetUniqueRelationName: AnsiString;
506      function getCount: integer;
507      function getColumnMetaData(index: integer): IColumnMetaData;
508 <    function ByName(Idx: String): IColumnMetaData;
508 >    function ByName(Idx: AnsiString): IColumnMetaData;
509    end;
510  
511    { TSQLParams }
# Line 423 | Line 524 | type
524      {ISQLParams}
525      function getCount: integer;
526      function getSQLParam(index: integer): ISQLParam;
527 <    function ByName(Idx: String): ISQLParam ;
527 >    function ByName(Idx: AnsiString): ISQLParam ;
528      function GetModified: Boolean;
529 +    function GetHasCaseSensitiveParams: Boolean;
530    end;
531  
532    { TResults }
# Line 443 | Line 545 | type
545       constructor Create(aResults: TSQLDataArea);
546        {IResults}
547       function getCount: integer;
548 <     function ByName(Idx: String): ISQLData;
548 >     function ByName(Idx: AnsiString): ISQLData;
549       function getSQLData(index: integer): ISQLData;
550 <     procedure GetData(index: integer; var IsNull:boolean; var len: short; var data: PChar);
550 >     procedure GetData(index: integer; var IsNull:boolean; var len: short; var data: PByte);
551 >     function GetStatement: IStatement;
552       function GetTransaction: ITransaction; virtual;
553       procedure SetRetainInterfaces(aValue: boolean);
554   end;
555  
556   implementation
557  
558 < uses FBMessages, FBClientAPI, variants, IBUtils, FBTransaction;
558 > uses FBMessages, variants, IBUtils, FBTransaction, DateUtils;
559 >
560 > { TSQLParamMetaData }
561 >
562 > constructor TSQLParamMetaData.Create(src: TSQLVarData);
563 > begin
564 >  inherited Create;
565 >  FSQLType := src.GetSQLType;
566 >  FSQLSubType := src.getSubtype;
567 >  FScale := src.GetScale;
568 >  FCharSetID := src.getCharSetID;
569 >  FNullable := src.GetIsNullable;
570 >  FSize := src.GetSize;
571 >  FCodePage := src.GetCodePage;
572 > end;
573 >
574 > function TSQLParamMetaData.GetSQLType: cardinal;
575 > begin
576 >  Result := FSQLType;
577 > end;
578 >
579 > function TSQLParamMetaData.GetSQLTypeName: AnsiString;
580 > begin
581 >  Result := TSQLDataItem.GetSQLTypeName(FSQLType);
582 > end;
583 >
584 > function TSQLParamMetaData.getSubtype: integer;
585 > begin
586 >  Result := FSQLSubType;
587 > end;
588 >
589 > function TSQLParamMetaData.getScale: integer;
590 > begin
591 >  Result := FScale;
592 > end;
593 >
594 > function TSQLParamMetaData.getCharSetID: cardinal;
595 > begin
596 >  Result := FCharSetID;
597 > end;
598 >
599 > function TSQLParamMetaData.getCodePage: TSystemCodePage;
600 > begin
601 >  Result :=  FCodePage;
602 > end;
603 >
604 > function TSQLParamMetaData.getIsNullable: boolean;
605 > begin
606 >  Result :=  FNullable;
607 > end;
608 >
609 > function TSQLParamMetaData.GetSize: cardinal;
610 > begin
611 >  Result := FSize;
612 > end;
613  
614   { TSQLDataArea }
615  
# Line 472 | Line 629 | procedure TSQLDataArea.SetUniqueRelation
629   var
630    i: Integer;
631    bUnique: Boolean;
632 <  RelationName: string;
632 >  RelationName: AnsiString;
633   begin
634    bUnique := True;
635    for i := 0 to ColumnsInUseCount - 1 do
# Line 503 | Line 660 | begin
660      Column[i].Initialize;
661   end;
662  
663 < procedure TSQLDataArea.PreprocessSQL(sSQL: string; GenerateParamNames: boolean;
664 <  var sProcessedSQL: string);
508 < var
509 <  cCurChar, cNextChar, cQuoteChar: Char;
510 <  sParamName: String;
511 <  j, i, iLenSQL, iSQLPos: Integer;
512 <  iCurState {$ifdef ALLOWDIALECT3PARAMNAMES}, iCurParamState {$endif}: Integer;
513 <  iParamSuffix: Integer;
514 <  slNames: TStrings;
515 <  StrBuffer: PChar;
516 <  found: boolean;
517 <
518 < const
519 <  DefaultState = 0;
520 <  CommentState = 1;
521 <  QuoteState = 2;
522 <  ParamState = 3;
523 <  ArrayDimState = 4;
524 < {$ifdef ALLOWDIALECT3PARAMNAMES}
525 <  ParamDefaultState = 0;
526 <  ParamQuoteState = 1;
527 <  {$endif}
528 <
529 <  procedure AddToProcessedSQL(cChar: Char);
530 <  begin
531 <    StrBuffer[iSQLPos] := cChar;
532 <    Inc(iSQLPos);
533 <  end;
534 <
535 < begin
536 <  if not IsInputDataArea then
537 <    IBError(ibxeNotPermitted,[nil]);
663 > procedure TSQLDataArea.PreprocessSQL(sSQL: AnsiString; GenerateParamNames: boolean;
664 >  var sProcessedSQL: AnsiString);
665  
666 <  sParamName := '';
540 <  iLenSQL := Length(sSQL);
541 <  GetMem(StrBuffer,iLenSQL + 1);
542 <  slNames := TStringList.Create;
543 <  try
544 <    { Do some initializations of variables }
545 <    iParamSuffix := 0;
546 <    cQuoteChar := '''';
547 <    i := 1;
548 <    iSQLPos := 0;
549 <    iCurState := DefaultState;
550 <    {$ifdef ALLOWDIALECT3PARAMNAMES}
551 <    iCurParamState := ParamDefaultState;
552 <    {$endif}
553 <    { Now, traverse through the SQL string, character by character,
554 <     picking out the parameters and formatting correctly for InterBase }
555 <    while (i <= iLenSQL) do begin
556 <      { Get the current token and a look-ahead }
557 <      cCurChar := sSQL[i];
558 <      if i = iLenSQL then
559 <        cNextChar := #0
560 <      else
561 <        cNextChar := sSQL[i + 1];
562 <      { Now act based on the current state }
563 <      case iCurState of
564 <        DefaultState:
565 <        begin
566 <          case cCurChar of
567 <            '''', '"':
568 <            begin
569 <              cQuoteChar := cCurChar;
570 <              iCurState := QuoteState;
571 <            end;
572 <            '?', ':':
573 <            begin
574 <              iCurState := ParamState;
575 <              AddToProcessedSQL('?');
576 <            end;
577 <            '/': if (cNextChar = '*') then
578 <            begin
579 <              AddToProcessedSQL(cCurChar);
580 <              Inc(i);
581 <              iCurState := CommentState;
582 <            end;
583 <            '[':
584 <            begin
585 <              AddToProcessedSQL(cCurChar);
586 <              Inc(i);
587 <              iCurState := ArrayDimState;
588 <            end;
589 <          end;
590 <        end;
591 <
592 <        ArrayDimState:
593 <        begin
594 <          case cCurChar of
595 <          ':',',','0'..'9',' ',#9,#10,#13:
596 <            begin
597 <              AddToProcessedSQL(cCurChar);
598 <              Inc(i);
599 <            end;
600 <          else
601 <            begin
602 <              AddToProcessedSQL(cCurChar);
603 <              Inc(i);
604 <              iCurState := DefaultState;
605 <            end;
606 <          end;
607 <        end;
666 > var slNames: TStrings;
667  
668 <        CommentState:
669 <        begin
670 <          if (cNextChar = #0) then
671 <            IBError(ibxeSQLParseError, [SEOFInComment])
672 <          else if (cCurChar = '*') then begin
614 <            if (cNextChar = '/') then
615 <              iCurState := DefaultState;
616 <          end;
617 <        end;
618 <        QuoteState: begin
619 <          if cNextChar = #0 then
620 <            IBError(ibxeSQLParseError, [SEOFInString])
621 <          else if (cCurChar = cQuoteChar) then begin
622 <            if (cNextChar = cQuoteChar) then begin
623 <              AddToProcessedSQL(cCurChar);
624 <              Inc(i);
625 <            end else
626 <              iCurState := DefaultState;
627 <          end;
628 <        end;
629 <        ParamState:
630 <        begin
631 <          { collect the name of the parameter }
632 <          {$ifdef ALLOWDIALECT3PARAMNAMES}
633 <          if iCurParamState = ParamDefaultState then
634 <          begin
635 <            if cCurChar = '"' then
636 <              iCurParamState := ParamQuoteState
637 <            else
638 <            {$endif}
639 <            if (cCurChar in ['A'..'Z', 'a'..'z', '0'..'9', '_', '$']) then
640 <                sParamName := sParamName + cCurChar
641 <            else if GenerateParamNames then
642 <            begin
643 <              sParamName := 'IBXParam' + IntToStr(iParamSuffix); {do not localize}
644 <              Inc(iParamSuffix);
645 <              iCurState := DefaultState;
646 <              slNames.AddObject(sParamName,self); //Note local convention
647 <                                                  //add pointer to self to mark entry
648 <              sParamName := '';
649 <            end
650 <            else
651 <              IBError(ibxeSQLParseError, [SParamNameExpected]);
652 <          {$ifdef ALLOWDIALECT3PARAMNAMES}
653 <          end
654 <          else begin
655 <            { determine if Quoted parameter name is finished }
656 <            if cCurChar = '"' then
657 <            begin
658 <              Inc(i);
659 <              slNames.Add(sParamName);
660 <              SParamName := '';
661 <              iCurParamState := ParamDefaultState;
662 <              iCurState := DefaultState;
663 <            end
664 <            else
665 <              sParamName := sParamName + cCurChar
666 <          end;
667 <          {$endif}
668 <          { determine if the unquoted parameter name is finished }
669 <          if {$ifdef ALLOWDIALECT3PARAMNAMES}(iCurParamState <> ParamQuoteState) and {$endif}
670 <            (iCurState <> DefaultState) then
671 <          begin
672 <            if not (cNextChar in ['A'..'Z', 'a'..'z',
673 <                                  '0'..'9', '_', '$']) then begin
674 <              Inc(i);
675 <              iCurState := DefaultState;
676 <              slNames.Add(sParamName);
677 <              sParamName := '';
678 <            end;
679 <          end;
680 <        end;
681 <      end;
682 <      if (iCurState <> ParamState) and (i <= iLenSQL) then
683 <        AddToProcessedSQL(sSQL[i]);
684 <      Inc(i);
685 <    end;
686 <    AddToProcessedSQL(#0);
687 <    sProcessedSQL := strpas(StrBuffer);
668 >  procedure SetColumnNames(slNames: TStrings);
669 >  var i, j: integer;
670 >      found: boolean;
671 >  begin
672 >    found := false;
673      SetCount(slNames.Count);
674      for i := 0 to slNames.Count - 1 do
675      begin
# Line 705 | Line 690 | begin
690          Column[i].UniqueName := not found;
691        end;
692      end;
693 +  end;
694 +
695 + begin
696 +  if not IsInputDataArea then
697 +    IBError(ibxeNotPermitted,[nil]);
698 +
699 +  slNames := TStringList.Create;
700 +  try
701 +    sProcessedSQL := TSQLParamProcessor.Execute(sSQL,GenerateParamNames,slNames);
702 +    SetColumnNames(slNames);
703    finally
704      slNames.Free;
710    FreeMem(StrBuffer);
705    end;
706   end;
707  
# Line 716 | Line 710 | begin
710    Result := Count;
711   end;
712  
713 < function TSQLDataArea.ColumnByName(Idx: string): TSQLVarData;
713 > function TSQLDataArea.ColumnByName(Idx: AnsiString): TSQLVarData;
714   var
715 <  s: String;
715 >  s: AnsiString;
716    i: Integer;
717   begin
718 <  {$ifdef UseCaseInSensitiveParamName}
719 <   s := AnsiUpperCase(Idx);
720 <  {$else}
718 >  if not IsInputDataArea or not CaseSensitiveParams then
719 >   s := AnsiUpperCase(Idx)
720 >  else
721     s := Idx;
722 <  {$endif}
722 >
723    for i := 0 to Count - 1 do
724      if Column[i].Name = s then
725      begin
# Line 736 | Line 730 | begin
730   end;
731  
732   procedure TSQLDataArea.GetData(index: integer; var IsNull: boolean;
733 <  var len: short; var data: PChar);
733 >  var len: short; var data: PByte);
734   begin
735    //Do Nothing
736   end;
# Line 755 | Line 749 | begin
749    Result := FParent.Statement;
750   end;
751  
752 < procedure TSQLVarData.SetName(AValue: string);
752 > procedure TSQLVarData.SetName(AValue: AnsiString);
753   begin
754 <  if FName = AValue then Exit;
761 <  {$ifdef UseCaseInSensitiveParamName}
762 <  if Parent.IsInputDataArea then
754 >  if not Parent.IsInputDataArea or not Parent.CaseSensitiveParams then
755      FName := AnsiUpperCase(AValue)
756    else
765  {$endif}
757      FName := AValue;
758   end;
759  
760 + procedure TSQLVarData.SetMetaSize(aValue: cardinal);
761 + begin
762 +  //Ignore
763 + end;
764 +
765 + procedure TSQLVarData.SaveMetaData;
766 + begin
767 +  FColMetaData := TSQLParamMetaData.Create(self);
768 + end;
769 +
770   constructor TSQLVarData.Create(aParent: TSQLDataArea; aIndex: integer);
771   begin
772    inherited Create;
# Line 774 | Line 775 | begin
775    FUniqueName := true;
776   end;
777  
778 < procedure TSQLVarData.SetString(aValue: string);
778 > procedure TSQLVarData.SetString(aValue: AnsiString);
779   begin
780    {we take full advantage here of reference counted strings. When setting a string
781     value, a reference is kept in FVarString and a pointer to it placed in the
782 <   SQLVar. This avoids string copies. Note that PChar is guaranteed to point to
782 >   SQLVar. This avoids string copies. Note that PAnsiChar is guaranteed to point to
783     a zero byte when the string is empty, neatly avoiding a nil pointer error.}
784  
785    FVarString := aValue;
786 <  SQLType := SQL_TEXT;
787 <  SetSQLData(PChar(FVarString),Length(aValue));
786 >  if SQLType = SQL_BLOB then
787 >    SetMetaSize(GetAttachment.GetInlineBlobLimit);
788 >  SQLType := GetDefaultTextSQLType;
789 >  Scale := 0;
790 >  SetSQLData(PByte(PAnsiChar(FVarString)),Length(aValue));
791   end;
792  
793   procedure TSQLVarData.Changed;
# Line 797 | Line 801 | begin
801    FVarString := '';
802   end;
803  
804 + function TSQLVarData.getColMetadata: IParamMetaData;
805 + begin
806 +  Result := FColMetaData;
807 + end;
808 +
809   procedure TSQLVarData.Initialize;
810  
811 <  function FindVarByName(idx: string; limit: integer): TSQLVarData;
811 >  function FindVarByName(idx: AnsiString; limit: integer): TSQLVarData;
812    var
813      k: integer;
814    begin
# Line 814 | Line 823 | procedure TSQLVarData.Initialize;
823  
824   var
825    j, j_len: Integer;
826 <  st: String;
827 <  sBaseName: string;
826 >  st: AnsiString;
827 >  sBaseName: AnsiString;
828   begin
829    RowChange;
830  
# Line 902 | Line 911 | function TSQLDataItem.AdjustScaleToCurre
911   var
912    Scaling : Int64;
913    i : Integer;
914 <  FractionText, PadText, CurrText: string;
914 >  FractionText, PadText, CurrText: AnsiString;
915   begin
916    Result := 0;
917    Scaling := 1;
# Line 921 | Line 930 | begin
930        FractionText := IntToStr(abs(Value mod Scaling));
931        for i := Length(FractionText) to -aScale -1 do
932          PadText := '0' + PadText;
933 +      {$IF declared(DefaultFormatSettings)}
934 +      with DefaultFormatSettings do
935 +      {$ELSE}
936 +      {$IF declared(FormatSettings)}
937 +      with FormatSettings do
938 +      {$IFEND}
939 +      {$IFEND}
940        if Value < 0 then
941 <        CurrText := '-' + IntToStr(Abs(Value div Scaling)) + DefaultFormatSettings.DecimalSeparator + PadText + FractionText
941 >        CurrText := '-' + IntToStr(Abs(Value div Scaling)) + DecimalSeparator + PadText + FractionText
942        else
943 <        CurrText := IntToStr(Abs(Value div Scaling)) + DefaultFormatSettings.DecimalSeparator + PadText + FractionText;
943 >        CurrText := IntToStr(Abs(Value div Scaling)) + DecimalSeparator + PadText + FractionText;
944        try
945          result := StrToCurr(CurrText);
946        except
# Line 936 | Line 952 | begin
952        result := Value;
953   end;
954  
955 + function TSQLDataItem.GetDateFormatStr(IncludeTime: boolean): AnsiString;
956 + begin
957 +  {$IF declared(DefaultFormatSettings)}
958 +  with DefaultFormatSettings do
959 +  {$ELSE}
960 +  {$IF declared(FormatSettings)}
961 +  with FormatSettings do
962 +  {$IFEND}
963 +  {$IFEND}
964 +  case GetSQLDialect of
965 +    1:
966 +      if IncludeTime then
967 +        result := ShortDateFormat + ' ' + LongTimeFormat
968 +      else
969 +        result := ShortDateFormat;
970 +    3:
971 +      result := ShortDateFormat;
972 +  end;
973 + end;
974 +
975 + function TSQLDataItem.GetTimeFormatStr: AnsiString;
976 + begin
977 +  {$IF declared(DefaultFormatSettings)}
978 +  with DefaultFormatSettings do
979 +  {$ELSE}
980 +  {$IF declared(FormatSettings)}
981 +  with FormatSettings do
982 +  {$IFEND}
983 +  {$IFEND}
984 +    Result := 'hh' + TimeSeparator + 'nn' + TimeSeparator + 'ss' + '.zzzz';;
985 + end;
986 +
987 + function TSQLDataItem.GetTimestampFormatStr: AnsiString;
988 + begin
989 +  {$IF declared(DefaultFormatSettings)}
990 +  with DefaultFormatSettings do
991 +  {$ELSE}
992 +  {$IF declared(FormatSettings)}
993 +  with FormatSettings do
994 +  {$IFEND}
995 +  {$IFEND}
996 +    Result := ShortDateFormat + ' ' +  'hh' + TimeSeparator + 'nn' + TimeSeparator + 'ss' + '.zzzz';
997 + end;
998 +
999   procedure TSQLDataItem.SetAsInteger(AValue: Integer);
1000   begin
1001    SetAsLong(aValue);
1002   end;
1003  
1004 + procedure TSQLDataItem.InternalGetAsDateTime(var aDateTime: TDateTime;
1005 +  var dstOffset: smallint; var aTimezone: AnsiString;
1006 +  var aTimeZoneID: TFBTimeZoneID);
1007 + begin
1008 +  CheckActive;
1009 +  aDateTime := 0;
1010 +  dstOffset := 0;
1011 +  aTimezone := '';
1012 +  aTimeZoneID := TimeZoneID_GMT;
1013 +  if not IsNull then
1014 +    with FFirebirdClientAPI do
1015 +    case SQLType of
1016 +      SQL_TEXT, SQL_VARYING:
1017 +        if not ParseDateTimeTZString(AsString,aDateTime,aTimeZone) then
1018 +          IBError(ibxeInvalidDataConversion, [nil]);
1019 +      SQL_TYPE_DATE:
1020 +        aDateTime := SQLDecodeDate(SQLData);
1021 +      SQL_TYPE_TIME:
1022 +        aDateTime := SQLDecodeTime(SQLData);
1023 +      SQL_TIMESTAMP:
1024 +        aDateTime := SQLDecodeDateTime(SQLData);
1025 +      SQL_TIMESTAMP_TZ:
1026 +        begin
1027 +          GetTimeZoneServices.DecodeTimestampTZ(SQLData,aDateTime,dstOffset,aTimeZone);
1028 +          aTimeZoneID := PISC_TIMESTAMP_TZ(SQLData)^.time_zone;
1029 +        end;
1030 +      SQL_TIMESTAMP_TZ_EX:
1031 +      begin
1032 +        GetTimeZoneServices.DecodeTimestampTZEx(SQLData,aDateTime,dstOffset,aTimeZone);
1033 +        aTimeZoneID := PISC_TIMESTAMP_TZ_EX(SQLData)^.time_zone;
1034 +      end;
1035 +      SQL_TIME_TZ:
1036 +        with GetTimeZoneServices do
1037 +        begin
1038 +          DecodeTimeTZ(SQLData,GetTimeTZDate,aDateTime,dstOffset,aTimeZone);
1039 +          aTimeZoneID := PISC_TIME_TZ(SQLData)^.time_zone;
1040 +        end;
1041 +      SQL_TIME_TZ_EX:
1042 +        with GetTimeZoneServices do
1043 +        begin
1044 +          DecodeTimeTZEx(SQLData,GetTimeTZDate,aDateTime,dstOffset,aTimeZone);
1045 +          aTimeZoneID := PISC_TIME_TZ_EX(SQLData)^.time_zone;
1046 +        end;
1047 +      else
1048 +        IBError(ibxeInvalidDataConversion, [nil]);
1049 +    end;
1050 + end;
1051 +
1052   function TSQLDataItem.AdjustScaleFromCurrency(Value: Currency; aScale: Integer
1053    ): Int64;
1054   var
# Line 989 | Line 1097 | begin
1097    end
1098    else
1099      result := trunc(Value);
1100 + //  writeln('Adjusted ',Value,' to ',Result);
1101   end;
1102  
1103   procedure TSQLDataItem.CheckActive;
# Line 996 | Line 1105 | begin
1105    //Do nothing by default
1106   end;
1107  
1108 + procedure TSQLDataItem.CheckTZSupport;
1109 + begin
1110 +  if not FFirebirdClientAPI.HasTimeZoneSupport then
1111 +    IBError(ibxeNoTimezoneSupport,[]);
1112 + end;
1113 +
1114 + function TSQLDataItem.GetTimeZoneServices: IExTimeZoneServices;
1115 + begin
1116 +  if FTimeZoneServices = nil then
1117 +  begin
1118 +    if not GetAttachment.HasTimeZoneSupport then
1119 +      IBError(ibxeNoTimezoneSupport,[]);
1120 +    GetAttachment.GetTimeZoneServices.QueryInterface(IExTimeZoneServices,FTimeZoneServices);
1121 +  end;
1122 +  Result := FTimeZoneServices;
1123 + end;
1124 +
1125   procedure TSQLDataItem.Changed;
1126   begin
1127    //Do nothing by default
# Line 1006 | Line 1132 | begin
1132    //Do nothing by default
1133   end;
1134  
1135 < procedure TSQLDataItem.InternalSetAsString(Value: String);
1135 > procedure TSQLDataItem.InternalSetAsString(Value: AnsiString);
1136   begin
1137    //Do nothing by default
1138   end;
1139  
1140 < function TSQLDataItem.Transliterate(s: string; CodePage: TSystemCodePage
1140 > function TSQLDataItem.Transliterate(s: AnsiString; CodePage: TSystemCodePage
1141    ): RawByteString;
1142   begin
1143    Result := s;
# Line 1034 | Line 1160 | begin
1160     //Do nothing by default
1161   end;
1162  
1163 < function TSQLDataItem.GetSQLTypeName: string;
1163 > constructor TSQLDataItem.Create(api: TFBClientAPI);
1164 > begin
1165 >  inherited Create;
1166 >  FFirebirdClientAPI := api;
1167 > end;
1168 >
1169 > function TSQLDataItem.GetSQLTypeName: AnsiString;
1170   begin
1171    Result := GetSQLTypeName(GetSQLType);
1172   end;
1173  
1174 < class function TSQLDataItem.GetSQLTypeName(SQLType: short): string;
1174 > class function TSQLDataItem.GetSQLTypeName(SQLType: cardinal): AnsiString;
1175   begin
1176    Result := 'Unknown';
1177    case SQLType of
# Line 1050 | Line 1182 | begin
1182    SQL_LONG:             Result := 'SQL_LONG';
1183    SQL_SHORT:            Result := 'SQL_SHORT';
1184    SQL_TIMESTAMP:        Result := 'SQL_TIMESTAMP';
1185 +  SQL_TIMESTAMP_TZ:     Result := 'SQL_TIMESTAMP_TZ';
1186 +  SQL_TIMESTAMP_TZ_EX:  Result := 'SQL_TIMESTAMP_TZ_EX';
1187    SQL_BLOB:             Result := 'SQL_BLOB';
1188    SQL_D_FLOAT:          Result := 'SQL_D_FLOAT';
1189    SQL_ARRAY:            Result := 'SQL_ARRAY';
# Line 1057 | Line 1191 | begin
1191    SQL_TYPE_TIME:        Result := 'SQL_TYPE_TIME';
1192    SQL_TYPE_DATE:        Result := 'SQL_TYPE_DATE';
1193    SQL_INT64:            Result := 'SQL_INT64';
1194 +  SQL_TIME_TZ:          Result := 'SQL_TIME_TZ';
1195 +  SQL_TIME_TZ_EX:       Result := 'SQL_TIME_TZ_EX';
1196 +  SQL_DEC_FIXED:        Result := 'SQL_DEC_FIXED';
1197 +  SQL_DEC16:            Result := 'SQL_DEC16';
1198 +  SQL_DEC34:            Result := 'SQL_DEC34';
1199 +  SQL_INT128:           Result := 'SQL_INT128';
1200 +  SQL_NULL:             Result := 'SQL_NULL';
1201 +  SQL_BOOLEAN:          Result := 'SQL_BOOLEAN';
1202    end;
1203   end;
1204  
1205 + function TSQLDataItem.GetStrDataLength: short;
1206 + begin
1207 +  with FFirebirdClientAPI do
1208 +  if SQLType = SQL_VARYING then
1209 +    Result := DecodeInteger(SQLData, 2)
1210 +  else
1211 +    Result := DataLength;
1212 + end;
1213 +
1214   function TSQLDataItem.GetAsBoolean: boolean;
1215   begin
1216    CheckActive;
# Line 1099 | Line 1250 | begin
1250            result := AdjustScaleToCurrency(PInt64(SQLData)^,
1251                                        Scale);
1252          SQL_DOUBLE, SQL_FLOAT, SQL_D_FLOAT:
1253 <          result := Trunc(AsDouble);
1253 >          result := Round(AsDouble);
1254 >
1255 >        SQL_DEC_FIXED,
1256 >        SQL_DEC16,
1257 >        SQL_DEC34,
1258 >        SQL_INT128:
1259 >          if not BCDToCurr(GetAsBCD,Result) then
1260 >            IBError(ibxeInvalidDataConversion, [nil]);
1261 >
1262          else
1263            IBError(ibxeInvalidDataConversion, [nil]);
1264        end;
# Line 1129 | Line 1288 | begin
1288          result := AdjustScaleToInt64(PInt64(SQLData)^,
1289                                      Scale);
1290        SQL_DOUBLE, SQL_FLOAT, SQL_D_FLOAT:
1291 <        result := Trunc(AsDouble);
1291 >        result := Round(AsDouble);
1292        else
1293          IBError(ibxeInvalidDataConversion, [nil]);
1294      end;
1295   end;
1296  
1297   function TSQLDataItem.GetAsDateTime: TDateTime;
1298 + var aTimezone: AnsiString;
1299 +    aTimeZoneID: TFBTimeZoneID;
1300 +    dstOffset: smallint;
1301 + begin
1302 +  InternalGetAsDateTime(Result,dstOffset,aTimeZone,aTimeZoneID);
1303 + end;
1304 +
1305 + procedure TSQLDataItem.GetAsDateTime(var aDateTime: TDateTime;
1306 +  var dstOffset: smallint; var aTimezone: AnsiString);
1307 + var aTimeZoneID: TFBTimeZoneID;
1308 + begin
1309 +  InternalGetAsDateTime(aDateTime,dstOffset,aTimeZone,aTimeZoneID);
1310 + end;
1311 +
1312 + procedure TSQLDataItem.GetAsDateTime(var aDateTime: TDateTime; var dstOffset: smallint;
1313 +  var aTimezoneID: TFBTimeZoneID);
1314 + var aTimezone: AnsiString;
1315 + begin
1316 +  InternalGetAsDateTime(aDateTime,dstOffset,aTimeZone,aTimeZoneID);
1317 + end;
1318 +
1319 + procedure TSQLDataItem.GetAsTime(var aTime: TDateTime; var dstOffset: smallint;
1320 +  var aTimezoneID: TFBTimeZoneID; OnDate: TDateTime);
1321 + var aTimeZone: AnsiString;
1322   begin
1323    CheckActive;
1324 <  result := 0;
1324 >  aTime := 0;
1325 >  dstOffset := 0;
1326    if not IsNull then
1327 <    with FirebirdClientAPI do
1327 >    with FFirebirdClientAPI do
1328      case SQLType of
1329 <      SQL_TEXT, SQL_VARYING: begin
1330 <        try
1331 <          result := StrToDate(AsString);
1332 <        except
1333 <          on E: EConvertError do IBError(ibxeInvalidDataConversion, [nil]);
1329 >      SQL_TIME_TZ:
1330 >        begin
1331 >          GetTimeZoneServices.DecodeTimeTZ(SQLData,OnDate,aTime,dstOffset,aTimeZone);
1332 >          aTimeZoneID := PISC_TIME_TZ(SQLData)^.time_zone;
1333 >        end;
1334 >      SQL_TIME_TZ_EX:
1335 >        begin
1336 >          GetTimeZoneServices.DecodeTimeTZEx(SQLData,OnDate,aTime,dstOffset,aTimeZone);
1337 >          aTimeZoneID := PISC_TIME_TZ_EX(SQLData)^.time_zone;
1338          end;
1339 +    else
1340 +      IBError(ibxeInvalidDataConversion, [nil]);
1341 +    end;
1342 + end;
1343 +
1344 + procedure TSQLDataItem.GetAsTime(var aTime: TDateTime; var dstOffset: smallint;
1345 +  var aTimezone: AnsiString; OnDate: TDateTime);
1346 + begin
1347 +  CheckActive;
1348 +  aTime := 0;
1349 +  dstOffset := 0;
1350 +  if not IsNull then
1351 +    with FFirebirdClientAPI do
1352 +    case SQLType of
1353 +      SQL_TIME_TZ:
1354 +        GetTimeZoneServices.DecodeTimeTZ(SQLData,OnDate,aTime,dstOffset,aTimeZone);
1355 +      SQL_TIME_TZ_EX:
1356 +        GetTimeZoneServices.DecodeTimeTZEx(SQLData,OnDate,aTime,dstOffset,aTimeZone);
1357 +    else
1358 +      IBError(ibxeInvalidDataConversion, [nil]);
1359 +    end;
1360 + end;
1361 +
1362 + procedure TSQLDataItem.GetAsTime(var aTime: TDateTime; var dstOffset: smallint;
1363 +  var aTimezoneID: TFBTimeZoneID);
1364 + begin
1365 +  GetAsTime(aTime,dstOffset,aTimeZoneID,GetTimeZoneServices.GetTimeTZDate);
1366 + end;
1367 +
1368 + procedure TSQLDataItem.GetAsTime(var aTime: TDateTime; var dstOffset: smallint;
1369 +  var aTimezone: AnsiString);
1370 + begin
1371 +  GetAsTime(aTime,dstOffset,aTimeZone,GetTimeZoneServices.GetTimeTZDate);
1372 + end;
1373 +
1374 + function TSQLDataItem.GetAsUTCDateTime: TDateTime;
1375 + var aTimezone: AnsiString;
1376 + begin
1377 +  CheckActive;
1378 +  result := 0;
1379 +  aTimezone := '';
1380 +  if not IsNull then
1381 +    with FFirebirdClientAPI do
1382 +    case SQLType of
1383 +      SQL_TEXT, SQL_VARYING:
1384 +      begin
1385 +        if not ParseDateTimeTZString(AsString,Result,aTimeZone) then
1386 +          IBError(ibxeInvalidDataConversion, [nil]);
1387 +        Result := GetTimeZoneServices.LocalTimeToGMT(Result,aTimeZone);
1388        end;
1389        SQL_TYPE_DATE:
1390          result := SQLDecodeDate(SQLData);
1391 <      SQL_TYPE_TIME:
1391 >      SQL_TYPE_TIME,
1392 >      SQL_TIME_TZ,
1393 >      SQL_TIME_TZ_EX:
1394          result := SQLDecodeTime(SQLData);
1395 <      SQL_TIMESTAMP:
1395 >      SQL_TIMESTAMP,
1396 >      SQL_TIMESTAMP_TZ,
1397 >      SQL_TIMESTAMP_TZ_EX:
1398          result := SQLDecodeDateTime(SQLData);
1399        else
1400          IBError(ibxeInvalidDataConversion, [nil]);
1401 <    end;
1401 >      end;
1402   end;
1403  
1404   function TSQLDataItem.GetAsDouble: Double;
# Line 1185 | Line 1426 | begin
1426          result := PFloat(SQLData)^;
1427        SQL_DOUBLE, SQL_D_FLOAT:
1428          result := PDouble(SQLData)^;
1429 +      SQL_DEC_FIXED,
1430 +      SQL_DEC16,
1431 +      SQL_DEC34,
1432 +      SQL_INT128:
1433 +        Result := BCDToDouble(GetAsBCD);
1434        else
1435          IBError(ibxeInvalidDataConversion, [nil]);
1436      end;
# Line 1221 | Line 1467 | begin
1467          end;
1468        end;
1469        SQL_SHORT:
1470 <        result := Trunc(AdjustScale(Int64(PShort(SQLData)^),
1470 >        result := Round(AdjustScale(Int64(PShort(SQLData)^),
1471                                      Scale));
1472        SQL_LONG:
1473 <        result := Trunc(AdjustScale(Int64(PLong(SQLData)^),
1473 >        result := Round(AdjustScale(Int64(PLong(SQLData)^),
1474                                      Scale));
1475        SQL_INT64:
1476 <        result := Trunc(AdjustScale(PInt64(SQLData)^, Scale));
1476 >        result := Round(AdjustScale(PInt64(SQLData)^, Scale));
1477        SQL_DOUBLE, SQL_FLOAT, SQL_D_FLOAT:
1478 <        result := Trunc(AsDouble);
1478 >        result := Round(AsDouble);
1479 >      SQL_DEC_FIXED,
1480 >      SQL_DEC16,
1481 >      SQL_DEC34,
1482 >      SQL_INT128:
1483 >        Result := BCDToInteger(GetAsBCD);
1484        else
1485 <        IBError(ibxeInvalidDataConversion, [nil]);
1485 >        IBError(ibxeInvalidDataConversion, [GetSQLTypeName]);
1486      end;
1487   end;
1488  
# Line 1269 | Line 1520 | begin
1520    end;
1521   end;
1522  
1523 + {Copied from LazUTF8}
1524  
1525 < function TSQLDataItem.GetAsString: String;
1525 > function UTF8CodepointSizeFull(p: PAnsiChar): integer;
1526 > const TopBitSetMask   = $80; {%10000000}
1527 >      Top2BitsSetMask = $C0; {%11000000}
1528 >      Top3BitsSetMask = $E0; {%11100000}
1529 >      Top4BitsSetMask = $F0; {%11110000}
1530 >      Top5BitsSetMask = $F8; {%11111000}
1531 > begin
1532 >  case p^ of
1533 >  #0..#191: // %11000000
1534 >    // regular single byte character (#0 is a character, this is Pascal ;)
1535 >    Result:=1;
1536 >  #192..#223: // p^ and %11100000 = %11000000
1537 >    begin
1538 >      // could be 2 byte character
1539 >      if (ord(p[1]) and Top2BitsSetMask) = TopBitSetMask then
1540 >        Result:=2
1541 >      else
1542 >        Result:=1;
1543 >    end;
1544 >  #224..#239: // p^ and %11110000 = %11100000
1545 >    begin
1546 >      // could be 3 byte character
1547 >      if ((ord(p[1]) and Top2BitsSetMask) = TopBitSetMask)
1548 >      and ((ord(p[2]) and Top2BitsSetMask) = TopBitSetMask) then
1549 >        Result:=3
1550 >      else
1551 >        Result:=1;
1552 >    end;
1553 >  #240..#247: // p^ and %11111000 = %11110000
1554 >    begin
1555 >      // could be 4 byte character
1556 >      if ((ord(p[1]) and Top2BitsSetMask) = TopBitSetMask)
1557 >      and ((ord(p[2]) and Top2BitsSetMask) = TopBitSetMask)
1558 >      and ((ord(p[3]) and Top2BitsSetMask) = TopBitSetMask) then
1559 >        Result:=4
1560 >      else
1561 >        Result:=1;
1562 >    end;
1563 >  else
1564 >    Result:=1;
1565 >  end;
1566 > end;
1567 >
1568 > {Returns the byte length of a UTF8 string with a fixed charwidth}
1569 >
1570 > function GetStrLen(p: PAnsiChar; FieldWidth, MaxDataLength: cardinal): integer;
1571 > var i: integer;
1572 >    cplen: integer;
1573 >    s: AnsiString;
1574 > begin
1575 >  Result := 0;
1576 >  s := strpas(p);
1577 >  for i := 1 to FieldWidth do
1578 >  begin
1579 >    cplen := UTF8CodepointSizeFull(p);
1580 >    Inc(p,cplen);
1581 >    Inc(Result,cplen);
1582 >    if Result >= MaxDataLength then
1583 >    begin
1584 >      Result := MaxDataLength;
1585 >      Exit;
1586 >    end;
1587 >  end;
1588 > end;
1589 >
1590 > function TSQLDataItem.GetAsString: AnsiString;
1591   var
1592 <  sz: PChar;
1592 >  sz: PByte;
1593    str_len: Integer;
1594    rs: RawByteString;
1595 +  aTimeZone: AnsiString;
1596 +  aDateTime: TDateTime;
1597 +  dstOffset: smallint;
1598   begin
1599    CheckActive;
1600    result := '';
1601    { Check null, if so return a default string }
1602    if not IsNull then
1603 <  with FirebirdClientAPI do
1603 >  with FFirebirdClientAPI do
1604      case SQLType of
1605        SQL_BOOLEAN:
1606          if AsBoolean then
# Line 1292 | Line 1612 | begin
1612        begin
1613          sz := SQLData;
1614          if (SQLType = SQL_TEXT) then
1615 <          str_len := DataLength
1615 >        begin
1616 >          if GetCodePage = cp_utf8 then
1617 >            str_len := GetStrLen(PAnsiChar(sz),GetSize div GetCharSetWidth,DataLength)
1618 >          else
1619 >            str_len := DataLength
1620 >        end
1621          else begin
1622 <          str_len := DecodeInteger(SQLData, 2);
1622 >          str_len := DecodeInteger(sz, 2);
1623            Inc(sz, 2);
1624          end;
1625 <        SetString(rs, sz, str_len);
1625 >        SetString(rs, PAnsiChar(sz), str_len);
1626          SetCodePage(rs,GetCodePage,false);
1627 <        if (SQLType = SQL_TEXT) and (GetCharSetID <> 1) then
1303 <          Result := TrimRight(rs)
1304 <        else
1305 <          Result := rs
1627 >        Result := rs;
1628        end;
1629 +
1630        SQL_TYPE_DATE:
1631 <        case GetSQLDialect of
1309 <          1 : result := DateTimeToStr(AsDateTime);
1310 <          3 : result := DateToStr(AsDateTime);
1311 <        end;
1312 <      SQL_TYPE_TIME :
1313 <        result := TimeToStr(AsDateTime);
1631 >        Result := DateToStr(GetAsDateTime);
1632        SQL_TIMESTAMP:
1633 <        result := FormatDateTime(FormatSettings.ShortDateFormat + ' ' +
1634 <                            FormatSettings.LongTimeFormat+'.zzz',AsDateTime);
1633 >        Result := FBFormatDateTime(GetTimestampFormatStr,GetAsDateTime);
1634 >      SQL_TYPE_TIME:
1635 >        Result := FBFormatDateTime(GetTimeFormatStr,GetAsDateTime);
1636 >      SQL_TIMESTAMP_TZ,
1637 >      SQL_TIMESTAMP_TZ_EX:
1638 >        with GetAttachment.GetTimeZoneServices do
1639 >        begin
1640 >          if GetTZTextOption = tzGMT then
1641 >            Result := FBFormatDateTime(GetTimestampFormatStr,GetAsUTCDateTime)
1642 >          else
1643 >          begin
1644 >            GetAsDateTime(aDateTime,dstOffset,aTimeZone);
1645 >            if GetTZTextOption = tzOffset then
1646 >              Result := FBFormatDateTime(GetTimestampFormatStr,aDateTime) + ' ' + FormatTimeZoneOffset(dstOffset)
1647 >            else
1648 >              Result := FBFormatDateTime(GetTimestampFormatStr,aDateTime) + ' ' + aTimeZone;
1649 >          end;
1650 >        end;
1651 >      SQL_TIME_TZ,
1652 >      SQL_TIME_TZ_EX:
1653 >        with GetAttachment.GetTimeZoneServices do
1654 >        begin
1655 >          if GetTZTextOption = tzGMT then
1656 >             Result := FBFormatDateTime(GetTimeFormatStr,GetAsUTCDateTime)
1657 >          else
1658 >          begin
1659 >            GetAsTime(aDateTime,dstOffset,aTimeZone,GetTimeTZDate);
1660 >            if GetTZTextOption = tzOffset then
1661 >              Result := FBFormatDateTime(GetTimeFormatStr,aDateTime) + ' ' + FormatTimeZoneOffset(dstOffset)
1662 >            else
1663 >              Result := FBFormatDateTime(GetTimeFormatStr,aDateTime) + ' ' + aTimeZone;
1664 >          end;
1665 >        end;
1666 >
1667        SQL_SHORT, SQL_LONG:
1668          if Scale = 0 then
1669            result := IntToStr(AsLong)
# Line 1330 | Line 1680 | begin
1680            result := FloatToStr(AsDouble);
1681        SQL_DOUBLE, SQL_FLOAT, SQL_D_FLOAT:
1682          result := FloatToStr(AsDouble);
1683 +
1684 +      SQL_DEC16,
1685 +      SQL_DEC34:
1686 +        result := BCDToStr(GetAsBCD);
1687 +
1688 +      SQL_DEC_FIXED,
1689 +      SQL_INT128:
1690 +        result := Int128ToStr(SQLData,scale);
1691 +
1692        else
1693          IBError(ibxeInvalidDataConversion, [nil]);
1694      end;
# Line 1341 | Line 1700 | begin
1700    Result := false;
1701   end;
1702  
1703 < function TSQLDataItem.getIsNullable: boolean;
1703 > function TSQLDataItem.GetIsNullable: boolean;
1704   begin
1705    CheckActive;
1706    Result := false;
1707   end;
1708  
1709   function TSQLDataItem.GetAsVariant: Variant;
1710 + var ts: TDateTime;
1711 +  dstOffset: smallint;
1712 +    timezone: AnsiString;
1713   begin
1714    CheckActive;
1715    if IsNull then
# Line 1361 | Line 1723 | begin
1723          result := AsString;
1724        SQL_TIMESTAMP, SQL_TYPE_DATE, SQL_TYPE_TIME:
1725          result := AsDateTime;
1726 +      SQL_TIMESTAMP_TZ,
1727 +      SQL_TIME_TZ,
1728 +      SQL_TIMESTAMP_TZ_EX,
1729 +      SQL_TIME_TZ_EX:
1730 +        begin
1731 +          GetAsDateTime(ts,dstOffset,timezone);
1732 +          result := VarArrayOf([ts,dstOffset,timezone]);
1733 +        end;
1734        SQL_SHORT, SQL_LONG:
1735          if Scale = 0 then
1736            result := AsLong
# Line 1379 | Line 1749 | begin
1749          result := AsDouble;
1750        SQL_BOOLEAN:
1751          result := AsBoolean;
1752 +      SQL_DEC_FIXED,
1753 +      SQL_DEC16,
1754 +      SQL_DEC34,
1755 +      SQL_INT128:
1756 +        result := VarFmtBCDCreate(GetAsBcd);
1757        else
1758          IBError(ibxeInvalidDataConversion, [nil]);
1759      end;
# Line 1389 | Line 1764 | begin
1764    Result := false;
1765   end;
1766  
1767 + function TSQLDataItem.GetDateTimeStrLength(DateTimeFormat: TIBDateTimeFormats
1768 +  ): integer;
1769 + begin
1770 +  case DateTimeFormat of
1771 +  dfTimestamp:
1772 +    Result := Length(GetTimestampFormatStr);
1773 +  dfDateTime:
1774 +    Result := Length(GetDateFormatStr(true));
1775 +  dfTime:
1776 +    Result := Length(GetTimeFormatStr);
1777 +  dfTimestampTZ:
1778 +    Result := Length(GetTimestampFormatStr) + 6; {assume time offset format}
1779 +  dfTimeTZ:
1780 +    Result := Length(GetTimeFormatStr)+ 6;
1781 +  else
1782 +    Result := 0;
1783 +  end;end;
1784 +
1785 + function TSQLDataItem.GetAsBCD: tBCD;
1786 +
1787 + begin
1788 +  CheckActive;
1789 +  if IsNull then
1790 +   with Result do
1791 +   begin
1792 +     FillChar(Result,sizeof(Result),0);
1793 +     Precision := 1;
1794 +     exit;
1795 +   end;
1796 +
1797 +  case SQLType of
1798 +  SQL_DEC16,
1799 +  SQL_DEC34:
1800 +    with FFirebirdClientAPI do
1801 +      Result := SQLDecFloatDecode(SQLType,  SQLData);
1802 +
1803 +  SQL_DEC_FIXED,
1804 +  SQL_INT128:
1805 +    with FFirebirdClientAPI do
1806 +      Result := StrToBCD(Int128ToStr(SQLData,scale));
1807 +  else
1808 +    if not CurrToBCD(GetAsCurrency,Result) then
1809 +      IBError(ibxeBadBCDConversion,[]);
1810 +  end;
1811 + end;
1812 +
1813  
1814   procedure TSQLDataItem.SetIsNull(Value: Boolean);
1815   begin
# Line 1400 | Line 1821 | begin
1821    //ignore unless overridden
1822   end;
1823  
1824 < procedure TSQLDataItem.SetName(aValue: string);
1824 > procedure TSQLDataItem.SetName(aValue: AnsiString);
1825   begin
1826    //ignore unless overridden
1827   end;
# Line 1452 | Line 1873 | begin
1873  
1874    SQLType := SQL_TYPE_DATE;
1875    DataLength := SizeOf(ISC_DATE);
1876 <  with FirebirdClientAPI do
1876 >  with FFirebirdClientAPI do
1877      SQLEncodeDate(Value,SQLData);
1878    Changed;
1879   end;
# Line 1472 | Line 1893 | begin
1893  
1894    SQLType := SQL_TYPE_TIME;
1895    DataLength := SizeOf(ISC_TIME);
1896 <  with FirebirdClientAPI do
1896 >  with FFirebirdClientAPI do
1897      SQLEncodeTime(Value,SQLData);
1898    Changed;
1899   end;
1900  
1901 + procedure TSQLDataItem.SetAsTime(aValue: TDateTime; OnDate: TDateTime; aTimeZoneID: TFBTimeZoneID);
1902 + begin
1903 +  CheckActive;
1904 +  CheckTZSupport;
1905 +  if GetSQLDialect < 3 then
1906 +  begin
1907 +    AsDateTime := aValue;
1908 +    exit;
1909 +  end;
1910 +
1911 +  Changing;
1912 +  if IsNullable then
1913 +    IsNull := False;
1914 +
1915 +  SQLType := SQL_TIME_TZ;
1916 +  DataLength := SizeOf(ISC_TIME_TZ);
1917 +  GetTimeZoneServices.EncodeTimeTZ(aValue, aTimeZoneID,OnDate,SQLData);
1918 +  Changed;
1919 + end;
1920 +
1921 + procedure TSQLDataItem.SetAsTime(aValue: TDateTime; OnDate: TDateTime; aTimeZone: AnsiString);
1922 + begin
1923 +  CheckActive;
1924 +  CheckTZSupport;
1925 +  if GetSQLDialect < 3 then
1926 +  begin
1927 +    AsDateTime := aValue;
1928 +    exit;
1929 +  end;
1930 +
1931 +  Changing;
1932 +  if IsNullable then
1933 +    IsNull := False;
1934 +
1935 +  SQLType := SQL_TIME_TZ;
1936 +  DataLength := SizeOf(ISC_TIME_TZ);
1937 +  GetTimeZoneServices.EncodeTimeTZ(aValue, aTimeZone,OnDate,SQLData);
1938 +  Changed;
1939 + end;
1940 +
1941   procedure TSQLDataItem.SetAsDateTime(Value: TDateTime);
1942   begin
1943    CheckActive;
# Line 1486 | Line 1947 | begin
1947    Changing;
1948    SQLType := SQL_TIMESTAMP;
1949    DataLength := SizeOf(ISC_TIME) + sizeof(ISC_DATE);
1950 <  with FirebirdClientAPI do
1950 >  with FFirebirdClientAPI do
1951      SQLEncodeDateTime(Value,SQLData);
1952    Changed;
1953   end;
1954  
1955 + procedure TSQLDataItem.SetAsDateTime(aValue: TDateTime;
1956 +  aTimeZoneID: TFBTimeZoneID);
1957 + begin
1958 +  CheckActive;
1959 +  CheckTZSupport;
1960 +  if IsNullable then
1961 +    IsNull := False;
1962 +
1963 +  Changing;
1964 +  SQLType := SQL_TIMESTAMP_TZ;
1965 +  DataLength := SizeOf(ISC_TIMESTAMP_TZ);
1966 +  GetTimeZoneServices.EncodeTimestampTZ(aValue,aTimeZoneID,SQLData);
1967 +  Changed;
1968 + end;
1969 +
1970 + procedure TSQLDataItem.SetAsDateTime(aValue: TDateTime; aTimeZone: AnsiString
1971 +  );
1972 + begin
1973 +  CheckActive;
1974 +  CheckTZSupport;
1975 +  if IsNullable then
1976 +    IsNull := False;
1977 +
1978 +  Changing;
1979 +  SQLType := SQL_TIMESTAMP_TZ;
1980 +  DataLength := SizeOf(ISC_TIMESTAMP_TZ);
1981 +  GetTimeZoneServices.EncodeTimestampTZ(aValue,aTimeZone,SQLData);
1982 +  Changed;
1983 + end;
1984 +
1985 + procedure TSQLDataItem.SetAsUTCDateTime(aUTCTime: TDateTime);
1986 + begin
1987 +  SetAsDateTime(aUTCTime,TimeZoneID_GMT);
1988 + end;
1989 +
1990   procedure TSQLDataItem.SetAsDouble(Value: Double);
1991   begin
1992    CheckActive;
# Line 1576 | Line 2072 | begin
2072    Changed;
2073   end;
2074  
2075 < procedure TSQLDataItem.SetAsString(Value: String);
2075 > procedure TSQLDataItem.SetAsString(Value: AnsiString);
2076   begin
2077    InternalSetAsString(Value);
2078   end;
# Line 1586 | Line 2082 | begin
2082    CheckActive;
2083    if VarIsNull(Value) then
2084      IsNull := True
2085 +  else
2086 +  if VarIsArray(Value) then {must be datetime plus timezone}
2087 +    SetAsDateTime(Value[0],AnsiString(Value[1]))
2088    else case VarType(Value) of
2089      varEmpty, varNull:
2090        IsNull := True;
# Line 1608 | Line 2107 | begin
2107        IBError(ibxeNotSupported, [nil]);
2108      varByRef, varDispatch, varError, varUnknown, varVariant:
2109        IBError(ibxeNotPermitted, [nil]);
2110 +    else
2111 +      if VarIsFmtBCD(Value) then
2112 +        SetAsBCD(VarToBCD(Value))
2113 +      else
2114 +        IBError(ibxeNotSupported, [nil]);
2115    end;
2116   end;
2117  
2118 + procedure TSQLDataItem.SetAsNumeric(Value: Int64; aScale: integer);
2119 + begin
2120 +  CheckActive;
2121 +  Changing;
2122 +  if IsNullable then
2123 +    IsNull := False;
2124 +
2125 +  SQLType := SQL_INT64;
2126 +  Scale := aScale;
2127 +  DataLength := SizeOf(Int64);
2128 +  PInt64(SQLData)^ := Value;
2129 +  Changed;
2130 + end;
2131 +
2132 + procedure TSQLDataItem.SetAsBcd(aValue: tBCD);
2133 + var C: Currency;
2134 + begin
2135 +  CheckActive;
2136 +  Changing;
2137 +  if IsNullable then
2138 +    IsNull := False;
2139 +
2140 +
2141 +  with FFirebirdClientAPI do
2142 +  if aValue.Precision <= 16 then
2143 +  begin
2144 +    if not HasDecFloatSupport then
2145 +      IBError(ibxeDecFloatNotSupported,[]);
2146 +
2147 +    SQLType := SQL_DEC16;
2148 +    DataLength := 8;
2149 +    SQLDecFloatEncode(aValue,SQLType,SQLData);
2150 +  end
2151 +  else
2152 +  if aValue.Precision <= 34 then
2153 +  begin
2154 +    if not HasDecFloatSupport then
2155 +      IBError(ibxeDecFloatNotSupported,[]);
2156 +
2157 +    SQLType := SQL_DEC34;
2158 +    DataLength := 16;
2159 +    SQLDecFloatEncode(aValue,SQLType,SQLData);
2160 +  end
2161 +  else
2162 +  if aValue.Precision <= 38 then
2163 +  begin
2164 +    if not HasInt128Support then
2165 +      IBError(ibxeInt128NotSupported,[]);
2166 +
2167 +    SQLType := SQL_INT128;
2168 +    DataLength := 16;
2169 +    StrToInt128(scale,BcdToStr(aValue),SQLData);
2170 +  end
2171 +  else
2172 +    IBError(ibxeBCDOverflow,[BCDToStr(aValue)]);
2173 +
2174 +  Changed;
2175 + end;
2176 +
2177   procedure TSQLDataItem.SetAsBoolean(AValue: boolean);
2178   begin
2179    CheckActive;
# Line 1641 | Line 2204 | begin
2204      IBError(ibxeStatementNotPrepared, [nil]);
2205   end;
2206  
2207 < function TColumnMetaData.SQLData: PChar;
2207 > function TColumnMetaData.GetAttachment: IAttachment;
2208 > begin
2209 >  Result := GetStatement.GetAttachment;
2210 > end;
2211 >
2212 > function TColumnMetaData.SQLData: PByte;
2213   begin
2214    Result := FIBXSQLVAR.SQLData;
2215   end;
# Line 1658 | Line 2226 | end;
2226  
2227   constructor TColumnMetaData.Create(aOwner: IUnknown; aIBXSQLVAR: TSQLVarData);
2228   begin
2229 <  inherited Create;
2229 >  inherited Create(aIBXSQLVAR.GetStatement.GetAttachment.getFirebirdAPI as TFBClientAPI);
2230    FIBXSQLVAR := aIBXSQLVAR;
2231    FOwner := aOwner;
2232    FPrepareSeqNo := FIBXSQLVAR.Parent.PrepareSeqNo;
# Line 1694 | Line 2262 | begin
2262    result := FIBXSQLVAR.SQLSubtype;
2263   end;
2264  
2265 < function TColumnMetaData.getRelationName: string;
2265 > function TColumnMetaData.getRelationName: AnsiString;
2266   begin
2267    CheckActive;
2268     result :=  FIBXSQLVAR.RelationName;
2269   end;
2270  
2271 < function TColumnMetaData.getOwnerName: string;
2271 > function TColumnMetaData.getOwnerName: AnsiString;
2272   begin
2273    CheckActive;
2274    result :=  FIBXSQLVAR.OwnerName;
2275   end;
2276  
2277 < function TColumnMetaData.getSQLName: string;
2277 > function TColumnMetaData.getSQLName: AnsiString;
2278   begin
2279    CheckActive;
2280    result :=  FIBXSQLVAR.FieldName;
2281   end;
2282  
2283 < function TColumnMetaData.getAliasName: string;
2283 > function TColumnMetaData.getAliasName: AnsiString;
2284   begin
2285    CheckActive;
2286    result := FIBXSQLVAR.AliasName;
2287   end;
2288  
2289 < function TColumnMetaData.GetName: string;
2289 > function TColumnMetaData.GetName: AnsiString;
2290   begin
2291    CheckActive;
2292    Result := FIBXSQLVAR. Name;
# Line 1745 | Line 2313 | end;
2313   function TColumnMetaData.GetSize: cardinal;
2314   begin
2315    CheckActive;
2316 <  result := FIBXSQLVAR.DataLength;
2316 >  result := FIBXSQLVAR.GetSize;
2317 > end;
2318 >
2319 > function TColumnMetaData.GetCharSetWidth: integer;
2320 > begin
2321 >  CheckActive;
2322 >  result := FIBXSQLVAR.GetCharSetWidth;
2323   end;
2324  
2325   function TColumnMetaData.GetArrayMetaData: IArrayMetaData;
# Line 1760 | Line 2334 | begin
2334    result := FIBXSQLVAR.GetBlobMetaData;
2335   end;
2336  
2337 + function TColumnMetaData.GetStatement: IStatement;
2338 + begin
2339 +  Result := FIBXSQLVAR.GetStatement;
2340 + end;
2341 +
2342 + function TColumnMetaData.GetTransaction: ITransaction;
2343 + begin
2344 +  Result := GetStatement.GetTransaction;
2345 + end;
2346 +
2347   { TIBSQLData }
2348  
2349   procedure TIBSQLData.CheckActive;
# Line 1779 | Line 2363 | begin
2363      IBError(ibxeBOF,[nil]);
2364   end;
2365  
2366 + function TIBSQLData.GetTransaction: ITransaction;
2367 + begin
2368 +  if FTransaction = nil then
2369 +    Result := inherited GetTransaction
2370 +  else
2371 +    Result := FTransaction;
2372 + end;
2373 +
2374   function TIBSQLData.GetIsNull: Boolean;
2375   begin
2376    CheckActive;
# Line 1803 | Line 2395 | begin
2395    result := FIBXSQLVAR.GetAsBlob(AsQuad,BPB);
2396   end;
2397  
2398 < function TIBSQLData.GetAsString: String;
2398 > function TIBSQLData.GetAsString: AnsiString;
2399   begin
2400    CheckActive;
2401    Result := '';
# Line 1821 | Line 2413 | end;
2413  
2414   { TSQLParam }
2415  
2416 < procedure TSQLParam.InternalSetAsString(Value: String);
2416 > procedure TSQLParam.InternalSetAsString(Value: AnsiString);
2417 >
2418 > procedure DoSetString;
2419 > begin
2420 >  Changing;
2421 >  FIBXSQLVar.SetString(Transliterate(Value,GetCodePage));
2422 >  Changed;
2423 > end;
2424 >
2425   var b: IBlob;
2426 +    dt: TDateTime;
2427 +    timezone: AnsiString;
2428 +    FloatValue: Double;
2429 +    Int64Value: Int64;
2430 +    BCDValue: TBCD;
2431 +    aScale: integer;
2432   begin
2433    CheckActive;
2434    if IsNullable then
2435      IsNull := False;
2436 <  case SQLTYPE of
2436 >  with FFirebirdClientAPI do
2437 >  case getColMetaData.SQLTYPE of
2438    SQL_BOOLEAN:
2439 <    if CompareText(Value,STrue) = 0 then
2439 >    if AnsiCompareText(Value,STrue) = 0 then
2440        AsBoolean := true
2441      else
2442 <    if CompareText(Value,SFalse) = 0 then
2442 >    if AnsiCompareText(Value,SFalse) = 0 then
2443        AsBoolean := false
2444      else
2445        IBError(ibxeInvalidDataConversion,[nil]);
2446  
2447    SQL_BLOB:
2448 +    if Length(Value) < GetAttachment.GetInlineBlobLimit then
2449 +      DoSetString
2450 +    else
2451      begin
2452        Changing;
2453        b := FIBXSQLVAR.CreateBlob;
# Line 1848 | Line 2458 | begin
2458  
2459    SQL_VARYING,
2460    SQL_TEXT:
2461 +    DoSetString;
2462 +
2463 +  SQL_SHORT,
2464 +  SQL_LONG,
2465 +  SQL_INT64:
2466 +    {If the string contains an integer then convert and set directly}
2467 +    if TryStrToInt64(Value,Int64Value) then
2468 +      SetAsInt64(Int64Value)
2469 +    else
2470 +    if getColMetaData.getScale = 0 then {integer expected but non-integer string}
2471      begin
2472 <      Changing;
2473 <      FIBXSQLVar.SetString(Transliterate(Value,GetCodePage));
2474 <      Changed;
2475 <    end;
2472 >      if TryStrToFloat(Value,FloatValue) then
2473 >        {truncate it if the column is limited to an integer}
2474 >        SetAsInt64(Trunc(FloatValue))
2475 >      else
2476 >        DoSetString;
2477 >    end
2478 >    else
2479 >    if TryStrToFloat(Value,FloatValue) then
2480 >    begin
2481 >      aScale := getColMetaData.getScale;
2482 >      {Set as int64 with adjusted scale}
2483 >      SetAsNumeric(AdjustScaleFromDouble(FloatValue,aScale),aScale)
2484 >    end
2485 >    else
2486 >      DoSetString;
2487  
2488 <    SQL_SHORT,
2489 <    SQL_LONG,
2490 <    SQL_INT64:
2491 <      SetAsInt64(StrToInt(Value));
2492 <
2493 <    SQL_D_FLOAT,
2494 <    SQL_DOUBLE,
2495 <    SQL_FLOAT:
1865 <      SetAsDouble(StrToFloat(Value));
2488 >  SQL_DEC_FIXED,
2489 >  SQL_DEC16,
2490 >  SQL_DEC34,
2491 >  SQL_INT128:
2492 >    if TryStrToBCD(Value,BCDValue) then
2493 >      SetAsBCD(BCDValue)
2494 >    else
2495 >      DoSetString;
2496  
2497 <    SQL_TIMESTAMP:
2498 <      SetAsDateTime(StrToDateTime(Value));
2497 >  SQL_D_FLOAT,
2498 >  SQL_DOUBLE,
2499 >  SQL_FLOAT:
2500 >    if TryStrToFloat(Value,FloatValue) then
2501 >      SetAsDouble(FloatValue)
2502 >    else
2503 >      DoSetString;
2504  
2505 <    SQL_TYPE_DATE:
2506 <      SetAsDate(StrToDateTime(Value));
2505 >  SQL_TIMESTAMP:
2506 >      if TryStrToDateTime(Value,dt) then
2507 >        SetAsDateTime(dt)
2508 >      else
2509 >        DoSetString;
2510  
2511 <    SQL_TYPE_TIME:
2512 <      SetAsTime(StrToDateTime(Value));
2511 >  SQL_TYPE_DATE:
2512 >      if TryStrToDateTime(Value,dt) then
2513 >        SetAsDate(dt)
2514 >      else
2515 >        DoSetString;
2516  
2517 <    else
2518 <      IBError(ibxeInvalidDataConversion,[nil]);
2517 >  SQL_TYPE_TIME:
2518 >      if TryStrToDateTime(Value,dt) then
2519 >        SetAsTime(dt)
2520 >      else
2521 >        DoSetString;
2522 >
2523 >  SQL_TIMESTAMP_TZ,
2524 >  SQL_TIMESTAMP_TZ_EX:
2525 >      if ParseDateTimeTZString(value,dt,timezone) then
2526 >        SetAsDateTime(dt,timezone)
2527 >      else
2528 >        DoSetString;
2529 >
2530 >  SQL_TIME_TZ,
2531 >  SQL_TIME_TZ_EX:
2532 >      if ParseDateTimeTZString(value,dt,timezone,true) then
2533 >        SetAsTime(dt,GetAttachment.GetTimeZoneServices.GetTimeTZDate,timezone)
2534 >      else
2535 >        DoSetString;
2536 >
2537 >  else
2538 >    IBError(ibxeInvalidDataConversion,[GetSQLTypeName(getColMetaData.SQLTYPE)]);
2539    end;
2540   end;
2541  
# Line 1912 | Line 2573 | begin
2573    IsNull := true;
2574   end;
2575  
2576 + function TSQLParam.getColMetadata: IParamMetaData;
2577 + begin
2578 +  Result := FIBXSQLVAR.getColMetadata;
2579 + end;
2580 +
2581   function TSQLParam.GetModified: boolean;
2582   begin
2583    CheckActive;
# Line 1925 | Line 2591 | begin
2591    Result := inherited GetAsPointer;
2592   end;
2593  
2594 < procedure TSQLParam.SetName(Value: string);
2594 > function TSQLParam.GetAsString: AnsiString;
2595 > var rs: RawByteString;
2596 > begin
2597 >  Result := '';
2598 >  if (SQLType = SQL_VARYING) and not IsNull then
2599 >  {SQLData points to start of string - default is to length word}
2600 >  begin
2601 >    CheckActive;
2602 >    SetString(rs,PAnsiChar(SQLData),DataLength);
2603 >    SetCodePage(rs,GetCodePage,false);
2604 >    Result := rs;
2605 >  end
2606 >  else
2607 >    Result := inherited GetAsString;
2608 > end;
2609 >
2610 > procedure TSQLParam.SetName(Value: AnsiString);
2611   begin
2612    CheckActive;
2613    FIBXSQLVAR.Name := Value;
# Line 2116 | Line 2798 | begin
2798    end;
2799   end;
2800  
2801 + procedure TSQLParam.SetAsTime(aValue: TDateTime; OnDate: TDateTime; aTimeZoneID: TFBTimeZoneID);
2802 + var i: integer;
2803 +    OldSQLVar: TSQLVarData;
2804 + begin
2805 +  if FIBXSQLVAR.UniqueName then
2806 +    inherited SetAsTime(AValue,OnDate, aTimeZoneID)
2807 +  else
2808 +  with FIBXSQLVAR.Parent do
2809 +  begin
2810 +    for i := 0 to Count - 1 do
2811 +      if Column[i].Name = Name then
2812 +      begin
2813 +        OldSQLVar := FIBXSQLVAR;
2814 +        FIBXSQLVAR := Column[i];
2815 +        try
2816 +          inherited SetAsTime(AValue,OnDate, aTimeZoneID);
2817 +        finally
2818 +          FIBXSQLVAR := OldSQLVar;
2819 +        end;
2820 +      end;
2821 +  end;
2822 + end;
2823 +
2824 + procedure TSQLParam.SetAsTime(aValue: TDateTime; OnDate: TDateTime; aTimeZone: AnsiString);
2825 + var i: integer;
2826 +    OldSQLVar: TSQLVarData;
2827 + begin
2828 +  if FIBXSQLVAR.UniqueName then
2829 +    inherited SetAsTime(AValue,OnDate,aTimeZone)
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,aTimeZone);
2840 +        finally
2841 +          FIBXSQLVAR := OldSQLVar;
2842 +        end;
2843 +      end;
2844 +  end;
2845 + end;
2846 +
2847 + procedure TSQLParam.SetAsTime(aValue: TDateTime; aTimeZoneID: TFBTimeZoneID);
2848 + begin
2849 +  SetAsTime(aValue,GetTimeZoneServices.GetTimeTZDate,aTimeZoneID);
2850 + end;
2851 +
2852 + procedure TSQLParam.SetAsTime(aValue: TDateTime; aTimeZone: AnsiString);
2853 + begin
2854 +  SetAsTime(aValue,GetTimeZoneServices.GetTimeTZDate,aTimeZone);
2855 + end;
2856 +
2857   procedure TSQLParam.SetAsDateTime(AValue: TDateTime);
2858   var i: integer;
2859      OldSQLVar: TSQLVarData;
# Line 2139 | Line 2877 | begin
2877    end;
2878   end;
2879  
2880 + procedure TSQLParam.SetAsDateTime(aValue: TDateTime; aTimeZoneID: TFBTimeZoneID
2881 +  );
2882 + var i: integer;
2883 +    OldSQLVar: TSQLVarData;
2884 + begin
2885 +  if FIBXSQLVAR.UniqueName then
2886 +    inherited SetAsDateTime(AValue,aTimeZoneID)
2887 +  else
2888 +  with FIBXSQLVAR.Parent do
2889 +  begin
2890 +    for i := 0 to Count - 1 do
2891 +      if Column[i].Name = Name then
2892 +      begin
2893 +        OldSQLVar := FIBXSQLVAR;
2894 +        FIBXSQLVAR := Column[i];
2895 +        try
2896 +          inherited SetAsDateTime(AValue,aTimeZoneID);
2897 +        finally
2898 +          FIBXSQLVAR := OldSQLVar;
2899 +        end;
2900 +      end;
2901 +  end;
2902 + end;
2903 +
2904 + procedure TSQLParam.SetAsDateTime(aValue: TDateTime; aTimeZone: AnsiString);
2905 + var i: integer;
2906 +    OldSQLVar: TSQLVarData;
2907 + begin
2908 +  if FIBXSQLVAR.UniqueName then
2909 +    inherited SetAsDateTime(AValue,aTimeZone)
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,aTimeZone);
2920 +        finally
2921 +          FIBXSQLVAR := OldSQLVar;
2922 +        end;
2923 +      end;
2924 +  end;
2925 + end;
2926 +
2927   procedure TSQLParam.SetAsDouble(AValue: Double);
2928   var i: integer;
2929      OldSQLVar: TSQLVarData;
# Line 2231 | Line 3016 | begin
3016    end;
3017   end;
3018  
3019 < procedure TSQLParam.SetAsString(AValue: String);
3019 > procedure TSQLParam.SetAsString(AValue: AnsiString);
3020   var i: integer;
3021      OldSQLVar: TSQLVarData;
3022   begin
# Line 2319 | Line 3104 | begin
3104    FIBXSQLVAR.SetCharSetID(aValue);
3105   end;
3106  
3107 + procedure TSQLParam.SetAsBcd(aValue: tBCD);
3108 + var i: integer;
3109 +    OldSQLVar: TSQLVarData;
3110 + begin
3111 +  if FIBXSQLVAR.UniqueName then
3112 +    inherited SetAsBcd(AValue)
3113 +  else
3114 +  with FIBXSQLVAR.Parent do
3115 +  begin
3116 +    for i := 0 to Count - 1 do
3117 +      if Column[i].Name = Name then
3118 +      begin
3119 +        OldSQLVar := FIBXSQLVAR;
3120 +        FIBXSQLVAR := Column[i];
3121 +        try
3122 +          inherited SetAsBcd(AValue);
3123 +        finally
3124 +          FIBXSQLVAR := OldSQLVar;
3125 +        end;
3126 +      end;
3127 +  end;
3128 + end;
3129 +
3130   { TMetaData }
3131  
3132   procedure TMetaData.CheckActive;
# Line 2344 | Line 3152 | begin
3152    inherited Destroy;
3153   end;
3154  
3155 < function TMetaData.GetUniqueRelationName: string;
3155 > function TMetaData.GetUniqueRelationName: AnsiString;
3156   begin
3157    CheckActive;
3158    Result := FMetaData.UniqueRelationName;
# Line 2372 | Line 3180 | begin
3180    end;
3181   end;
3182  
3183 < function TMetaData.ByName(Idx: String): IColumnMetaData;
3183 > function TMetaData.ByName(Idx: AnsiString): IColumnMetaData;
3184   var aIBXSQLVAR: TSQLVarData;
3185   begin
3186    CheckActive;
# Line 2432 | Line 3240 | begin
3240    end;
3241   end;
3242  
3243 < function TSQLParams.ByName(Idx: String): ISQLParam;
3243 > function TSQLParams.ByName(Idx: AnsiString): ISQLParam;
3244   var aIBXSQLVAR: TSQLVarData;
3245   begin
3246    CheckActive;
# Line 2457 | Line 3265 | begin
3265      end;
3266   end;
3267  
3268 + function TSQLParams.GetHasCaseSensitiveParams: Boolean;
3269 + begin
3270 +  Result := FSQLParams.CaseSensitiveParams;
3271 + end;
3272 +
3273   { TResults }
3274  
3275   procedure TResults.CheckActive;
# Line 2469 | Line 3282 | begin
3282    if not FResults.CheckStatementStatus(ssPrepared)  then
3283      IBError(ibxeStatementNotPrepared, [nil]);
3284  
3285 <  with GetTransaction as TFBTransaction do
3285 >  with GetTransaction do
3286    if not InTransaction or (FResults.TransactionSeqNo <> FTransactionSeqNo) then
3287      IBError(ibxeInterfaceOutofDate,[nil]);
3288   end;
3289  
3290   function TResults.GetISQLData(aIBXSQLVAR: TSQLVarData): ISQLData;
3291 + var col: TIBSQLData;
3292   begin
3293    if (aIBXSQLVAR.Index < 0) or (aIBXSQLVAR.Index >= getCount) then
3294      IBError(ibxeInvalidColumnIndex,[nil]);
3295  
3296    if not HasInterface(aIBXSQLVAR.Index) then
3297      AddInterface(aIBXSQLVAR.Index, TIBSQLData.Create(self,aIBXSQLVAR));
3298 <  Result := TIBSQLData(GetInterface(aIBXSQLVAR.Index));
3298 >  col := TIBSQLData(GetInterface(aIBXSQLVAR.Index));
3299 >  col.FTransaction := GetTransaction;
3300 >  Result := col;
3301   end;
3302  
3303   constructor TResults.Create(aResults: TSQLDataArea);
# Line 2500 | Line 3316 | begin
3316    Result := FResults.Count;
3317   end;
3318  
3319 < function TResults.ByName(Idx: String): ISQLData;
3319 > function TResults.ByName(Idx: AnsiString): ISQLData;
3320   var col: TSQLVarData;
3321   begin
3322    Result := nil;
# Line 2532 | Line 3348 | begin
3348   end;
3349  
3350   procedure TResults.GetData(index: integer; var IsNull: boolean; var len: short;
3351 <  var data: PChar);
3351 >  var data: PByte);
3352   begin
3353    CheckActive;
3354    FResults.GetData(index,IsNull, len,data);
3355   end;
3356  
3357 + function TResults.GetStatement: IStatement;
3358 + begin
3359 +  Result := FStatement;
3360 + end;
3361 +
3362   function TResults.GetTransaction: ITransaction;
3363   begin
3364    Result := FStatement.GetTransaction;
# Line 2548 | Line 3369 | begin
3369    RetainInterfaces := aValue;
3370   end;
3371  
2551
3372   end.
3373  

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines