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 353 by tony, Sat Oct 23 14:11:37 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 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 getCharSetID: cardinal; virtual; abstract;
150 <     function Transliterate(s: string; CodePage: TSystemCodePage): RawByteString;
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 175 | 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 192 | 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 205 | 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 227 | 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 +    function GetAttachment: IAttachment; virtual; abstract;
293      function GetSQLType: cardinal; virtual; abstract;
294      function GetSubtype: integer; virtual; abstract;
295 <    function GetAliasName: string;  virtual; abstract;
296 <    function GetFieldName: string; virtual; abstract;
297 <    function GetOwnerName: string;  virtual; abstract;
298 <    function GetRelationName: string;  virtual; abstract;
295 >    function GetAliasName: AnsiString;  virtual; abstract;
296 >    function GetFieldName: AnsiString; virtual; abstract;
297 >    function GetOwnerName: AnsiString;  virtual; abstract;
298 >    function GetRelationName: AnsiString;  virtual; abstract;
299      function GetScale: integer; virtual; abstract;
300      function GetCharSetID: cardinal; virtual; abstract;
301 +    function GetCharSetWidth: integer; virtual; abstract;
302      function GetCodePage: TSystemCodePage; virtual; abstract;
303      function GetIsNull: Boolean;   virtual; abstract;
304      function GetIsNullable: boolean; virtual; abstract;
305 <    function GetSQLData: PChar;  virtual; abstract;
306 <    function GetDataLength: cardinal; virtual; abstract;
305 >    function GetSQLData: PByte;  virtual; abstract;
306 >    function GetDataLength: cardinal; virtual; abstract; {current field length}
307 >    function GetSize: cardinal; virtual; abstract; {field length as given by metadata}
308 >    function GetDefaultTextSQLType: cardinal; virtual; abstract;
309      procedure SetIsNull(Value: Boolean); virtual; abstract;
310      procedure SetIsNullable(Value: Boolean);  virtual; abstract;
311 <    procedure SetSQLData(AValue: PChar; len: cardinal); virtual; abstract;
311 >    procedure SetSQLData(AValue: PByte; len: cardinal); virtual; abstract;
312      procedure SetScale(aValue: integer); virtual; abstract;
313      procedure SetDataLength(len: cardinal); virtual; abstract;
314      procedure SetSQLType(aValue: cardinal); virtual; abstract;
315      procedure SetCharSetID(aValue: cardinal); virtual; abstract;
316 +    procedure SetMetaSize(aValue: cardinal); virtual;
317    public
318      constructor Create(aParent: TSQLDataArea; aIndex: integer);
319 <    procedure SetString(aValue: string);
319 >    procedure SetString(aValue: AnsiString);
320      procedure Changed; virtual;
321      procedure RowChange; virtual;
322      function GetAsArray(Array_ID: TISC_QUAD): IArray; virtual; abstract;
# Line 265 | Line 324 | type
324      function CreateBlob: IBlob; virtual; abstract;
325      function GetArrayMetaData: IArrayMetaData; virtual; abstract;
326      function GetBlobMetaData: IBlobMetaData; virtual; abstract;
327 +    function getColMetadata: IParamMetaData;
328      procedure Initialize; virtual;
329 +    procedure SaveMetaData;
330  
331    public
332 <    property AliasName: string read GetAliasName;
333 <    property FieldName: string read GetFieldName;
334 <    property OwnerName: string read GetOwnerName;
335 <    property RelationName: string read GetRelationName;
332 >    property AliasName: AnsiString read GetAliasName;
333 >    property FieldName: AnsiString read GetFieldName;
334 >    property OwnerName: AnsiString read GetOwnerName;
335 >    property RelationName: AnsiString read GetRelationName;
336      property Parent: TSQLDataArea read FParent;
337      property Index: integer read FIndex;
338 <    property Name: string read FName write SetName;
338 >    property Name: AnsiString read FName write SetName;
339      property CharSetID: cardinal read GetCharSetID write SetCharSetID;
340      property SQLType: cardinal read GetSQLType write SetSQLType;
341      property SQLSubtype: integer read GetSubtype;
342 <    property SQLData: PChar read GetSQLData;
342 >    property SQLData: PByte read GetSQLData;
343      property DataLength: cardinal read GetDataLength write SetDataLength;
344      property IsNull: Boolean read GetIsNull write SetIsNull;
345      property IsNullable: Boolean read GetIsNullable write SetIsNullable;
# Line 296 | Line 357 | type
357      FIBXSQLVAR: TSQLVarData;
358      FOwner: IUnknown;         {Keep reference to ensure Metadata/statement not discarded}
359      FPrepareSeqNo: integer;
299    FStatement: IStatement;
360      FChangeSeqNo: integer;
361    protected
362      procedure CheckActive; override;
363 <    function SQLData: PChar; override;
363 >    function GetAttachment: IAttachment; override;
364 >    function SQLData: PByte; override;
365      function GetDataLength: cardinal; override;
366      function GetCodePage: TSystemCodePage; override;
367  
# Line 308 | Line 369 | type
369      constructor Create(aOwner: IUnknown; aIBXSQLVAR: TSQLVarData);
370      destructor Destroy; override;
371      function GetSQLDialect: integer; override;
311    property Statement: IStatement read FStatement;
372  
373    public
374      {IColumnMetaData}
375      function GetIndex: integer;
376      function GetSQLType: cardinal; override;
377      function getSubtype: integer;
378 <    function getRelationName: string;
379 <    function getOwnerName: string;
380 <    function getSQLName: string;    {Name of the column}
381 <    function getAliasName: string;  {Alias Name of column or Column Name if not alias}
382 <    function GetName: string; override;      {Disambiguated uppercase Field Name}
378 >    function getRelationName: AnsiString;
379 >    function getOwnerName: AnsiString;
380 >    function getSQLName: AnsiString;    {Name of the column}
381 >    function getAliasName: AnsiString;  {Alias Name of column or Column Name if not alias}
382 >    function GetName: AnsiString; override;      {Disambiguated uppercase Field Name}
383      function GetScale: integer; override;
384      function getCharSetID: cardinal; override;
385      function GetIsNullable: boolean; override;
386 <    function GetSize: cardinal;
386 >    function GetSize: cardinal; override;
387 >    function GetCharSetWidth: integer; override;
388      function GetArrayMetaData: IArrayMetaData;
389      function GetBlobMetaData: IBlobMetaData;
390 <    property Name: string read GetName;
390 >    function GetStatement: IStatement;
391 >    function GetTransaction: ITransaction; virtual;
392 >    property Name: AnsiString read GetName;
393      property Size: cardinal read GetSize;
394      property CharSetID: cardinal read getCharSetID;
395      property SQLSubtype: integer read getSubtype;
396      property IsNullable: Boolean read GetIsNullable;
397 +  public
398 +    property Statement: IStatement read GetStatement;
399    end;
400  
401    { TIBSQLData }
402  
403    TIBSQLData = class(TColumnMetaData,ISQLData)
404 +  private
405 +    FTransaction: ITransaction;
406    protected
407      procedure CheckActive; override;
408    public
409 +    function GetTransaction: ITransaction; override;
410      function GetIsNull: Boolean; override;
411      function GetAsArray: IArray;
412      function GetAsBlob: IBlob; overload;
413      function GetAsBlob(BPB: IBPB): IBlob; overload;
414 <    function GetAsString: String; override;
414 >    function GetAsString: AnsiString; override;
415      property AsBlob: IBlob read GetAsBlob;
416   end;
417  
418 +  { TSQLParamMetaData }
419 +
420 +  TSQLParamMetaData = class(TFBInterfacedObject,IParamMetaData)
421 +  private
422 +    FSQLType: cardinal;
423 +    FSQLSubType: integer;
424 +    FScale: integer;
425 +    FCharSetID: cardinal;
426 +    FNullable: boolean;
427 +    FSize: cardinal;
428 +    FCodePage: TSystemCodePage;
429 +  public
430 +    constructor Create(src: TSQLVarData);
431 +    {IParamMetaData}
432 +    function GetSQLType: cardinal;
433 +    function GetSQLTypeName: AnsiString;
434 +    function getSubtype: integer;
435 +    function getScale: integer;
436 +    function getCharSetID: cardinal;
437 +    function getCodePage: TSystemCodePage;
438 +    function getIsNullable: boolean;
439 +    function GetSize: cardinal;
440 +    property SQLType: cardinal read GetSQLType;
441 +  end;
442 +
443    { TSQLParam }
444  
445 <  TSQLParam = class(TIBSQLData,ISQLParam)
445 >  TSQLParam = class(TIBSQLData,ISQLParam,ISQLData)
446    protected
447      procedure CheckActive; override;
448      procedure Changed; override;
449 <    procedure InternalSetAsString(Value: String); override;
449 >    procedure InternalSetAsString(Value: AnsiString); override;
450      procedure SetScale(aValue: integer); override;
451      procedure SetDataLength(len: cardinal); override;
452      procedure SetSQLType(aValue: cardinal); override;
453    public
454      procedure Clear;
455 +    function getColMetadata: IParamMetaData;
456      function GetModified: boolean; override;
457      function GetAsPointer: Pointer;
458 <    procedure SetName(Value: string); override;
458 >    function GetAsString: AnsiString; override;
459 >    procedure SetName(Value: AnsiString); override;
460      procedure SetIsNull(Value: Boolean);  override;
461      procedure SetIsNullable(Value: Boolean); override;
462      procedure SetAsArray(anArray: IArray);
# Line 372 | Line 467 | type
467      procedure SetAsInt64(AValue: Int64);
468      procedure SetAsDate(AValue: TDateTime);
469      procedure SetAsLong(AValue: Long);
470 <    procedure SetAsTime(AValue: TDateTime);
471 <    procedure SetAsDateTime(AValue: TDateTime);
470 >    procedure SetAsTime(AValue: TDateTime); overload;
471 >    procedure SetAsTime(aValue: TDateTime; OnDate: TDateTime; aTimeZoneID: TFBTimeZoneID); overload;
472 >    procedure SetAsTime(aValue: TDateTime; OnDate: TDateTime; aTimeZone: AnsiString); overload;
473 >    procedure SetAsTime(aValue: TDateTime; aTimeZoneID: TFBTimeZoneID); overload;
474 >    procedure SetAsTime(aValue: TDateTime; aTimeZone: AnsiString); overload;
475 >    procedure SetAsDateTime(AValue: TDateTime); overload;
476 >    procedure SetAsDateTime(aValue: TDateTime; aTimeZoneID: TFBTimeZoneID); overload;
477 >    procedure SetAsDateTime(aValue: TDateTime; aTimeZone: AnsiString); overload;
478      procedure SetAsDouble(AValue: Double);
479      procedure SetAsFloat(AValue: Float);
480      procedure SetAsPointer(AValue: Pointer);
481      procedure SetAsShort(AValue: Short);
482 <    procedure SetAsString(AValue: String); override;
482 >    procedure SetAsString(AValue: AnsiString); override;
483      procedure SetAsVariant(AValue: Variant);
484      procedure SetAsBlob(aValue: IBlob);
485      procedure SetAsQuad(AValue: TISC_QUAD);
486      procedure SetCharSetID(aValue: cardinal);
487 +    procedure SetAsBcd(aValue: tBCD);
488  
489      property AsBlob: IBlob read GetAsBlob write SetAsBlob;
490      property IsNullable: Boolean read GetIsNullable write SetIsNullable;
# Line 401 | Line 503 | type
503      destructor Destroy; override;
504    public
505      {IMetaData}
506 <    function GetUniqueRelationName: string;
506 >    function GetUniqueRelationName: AnsiString;
507      function getCount: integer;
508      function getColumnMetaData(index: integer): IColumnMetaData;
509 <    function ByName(Idx: String): IColumnMetaData;
509 >    function ByName(Idx: AnsiString): IColumnMetaData;
510    end;
511  
512    { TSQLParams }
# Line 423 | Line 525 | type
525      {ISQLParams}
526      function getCount: integer;
527      function getSQLParam(index: integer): ISQLParam;
528 <    function ByName(Idx: String): ISQLParam ;
528 >    function ByName(Idx: AnsiString): ISQLParam ;
529      function GetModified: Boolean;
530 +    function GetHasCaseSensitiveParams: Boolean;
531    end;
532  
533    { TResults }
# Line 443 | Line 546 | type
546       constructor Create(aResults: TSQLDataArea);
547        {IResults}
548       function getCount: integer;
549 <     function ByName(Idx: String): ISQLData;
549 >     function ByName(Idx: AnsiString): ISQLData;
550       function getSQLData(index: integer): ISQLData;
551 <     procedure GetData(index: integer; var IsNull:boolean; var len: short; var data: PChar);
551 >     procedure GetData(index: integer; var IsNull:boolean; var len: short; var data: PByte);
552 >     function GetStatement: IStatement;
553       function GetTransaction: ITransaction; virtual;
554       procedure SetRetainInterfaces(aValue: boolean);
555   end;
556  
557   implementation
558  
559 < uses FBMessages, FBClientAPI, variants, IBUtils, FBTransaction;
559 > uses FBMessages, variants, IBUtils, FBTransaction, DateUtils;
560 >
561 > { TSQLParamMetaData }
562 >
563 > constructor TSQLParamMetaData.Create(src: TSQLVarData);
564 > begin
565 >  inherited Create;
566 >  FSQLType := src.GetSQLType;
567 >  FSQLSubType := src.getSubtype;
568 >  FScale := src.GetScale;
569 >  FCharSetID := src.getCharSetID;
570 >  FNullable := src.GetIsNullable;
571 >  FSize := src.GetSize;
572 >  FCodePage := src.GetCodePage;
573 > end;
574 >
575 > function TSQLParamMetaData.GetSQLType: cardinal;
576 > begin
577 >  Result := FSQLType;
578 > end;
579 >
580 > function TSQLParamMetaData.GetSQLTypeName: AnsiString;
581 > begin
582 >  Result := TSQLDataItem.GetSQLTypeName(FSQLType);
583 > end;
584 >
585 > function TSQLParamMetaData.getSubtype: integer;
586 > begin
587 >  Result := FSQLSubType;
588 > end;
589 >
590 > function TSQLParamMetaData.getScale: integer;
591 > begin
592 >  Result := FScale;
593 > end;
594 >
595 > function TSQLParamMetaData.getCharSetID: cardinal;
596 > begin
597 >  Result := FCharSetID;
598 > end;
599 >
600 > function TSQLParamMetaData.getCodePage: TSystemCodePage;
601 > begin
602 >  Result :=  FCodePage;
603 > end;
604 >
605 > function TSQLParamMetaData.getIsNullable: boolean;
606 > begin
607 >  Result :=  FNullable;
608 > end;
609 >
610 > function TSQLParamMetaData.GetSize: cardinal;
611 > begin
612 >  Result := FSize;
613 > end;
614  
615   { TSQLDataArea }
616  
# Line 472 | Line 630 | procedure TSQLDataArea.SetUniqueRelation
630   var
631    i: Integer;
632    bUnique: Boolean;
633 <  RelationName: string;
633 >  RelationName: AnsiString;
634   begin
635    bUnique := True;
636    for i := 0 to ColumnsInUseCount - 1 do
# Line 503 | Line 661 | begin
661      Column[i].Initialize;
662   end;
663  
664 < procedure TSQLDataArea.PreprocessSQL(sSQL: string; GenerateParamNames: boolean;
665 <  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]);
538 <
539 <  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;
664 > procedure TSQLDataArea.PreprocessSQL(sSQL: AnsiString; GenerateParamNames: boolean;
665 >  var sProcessedSQL: AnsiString);
666  
667 <        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;
667 > var slNames: TStrings;
668  
669 <        CommentState:
670 <        begin
671 <          if (cNextChar = #0) then
672 <            IBError(ibxeSQLParseError, [SEOFInComment])
673 <          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);
669 >  procedure SetColumnNames(slNames: TStrings);
670 >  var i, j: integer;
671 >      found: boolean;
672 >  begin
673 >    found := false;
674      SetCount(slNames.Count);
675      for i := 0 to slNames.Count - 1 do
676      begin
# Line 705 | Line 691 | begin
691          Column[i].UniqueName := not found;
692        end;
693      end;
694 +  end;
695 +
696 + begin
697 +  if not IsInputDataArea then
698 +    IBError(ibxeNotPermitted,[nil]);
699 +
700 +  slNames := TStringList.Create;
701 +  try
702 +    sProcessedSQL := TSQLParamProcessor.Execute(sSQL,GenerateParamNames,slNames);
703 +    SetColumnNames(slNames);
704    finally
705      slNames.Free;
710    FreeMem(StrBuffer);
706    end;
707   end;
708  
# Line 716 | Line 711 | begin
711    Result := Count;
712   end;
713  
714 < function TSQLDataArea.ColumnByName(Idx: string): TSQLVarData;
714 > function TSQLDataArea.ColumnByName(Idx: AnsiString): TSQLVarData;
715   var
716 <  s: String;
716 >  s: AnsiString;
717    i: Integer;
718   begin
719 <  {$ifdef UseCaseInSensitiveParamName}
720 <   s := AnsiUpperCase(Idx);
721 <  {$else}
719 >  if not IsInputDataArea or not CaseSensitiveParams then
720 >   s := AnsiUpperCase(Idx)
721 >  else
722     s := Idx;
723 <  {$endif}
723 >
724    for i := 0 to Count - 1 do
725      if Column[i].Name = s then
726      begin
# Line 736 | Line 731 | begin
731   end;
732  
733   procedure TSQLDataArea.GetData(index: integer; var IsNull: boolean;
734 <  var len: short; var data: PChar);
734 >  var len: short; var data: PByte);
735   begin
736    //Do Nothing
737   end;
# Line 755 | Line 750 | begin
750    Result := FParent.Statement;
751   end;
752  
753 < procedure TSQLVarData.SetName(AValue: string);
753 > procedure TSQLVarData.SetName(AValue: AnsiString);
754   begin
755 <  if FName = AValue then Exit;
761 <  {$ifdef UseCaseInSensitiveParamName}
762 <  if Parent.IsInputDataArea then
755 >  if not Parent.IsInputDataArea or not Parent.CaseSensitiveParams then
756      FName := AnsiUpperCase(AValue)
757    else
765  {$endif}
758      FName := AValue;
759   end;
760  
761 + procedure TSQLVarData.SetMetaSize(aValue: cardinal);
762 + begin
763 +  //Ignore
764 + end;
765 +
766 + procedure TSQLVarData.SaveMetaData;
767 + begin
768 +  FColMetaData := TSQLParamMetaData.Create(self);
769 + end;
770 +
771   constructor TSQLVarData.Create(aParent: TSQLDataArea; aIndex: integer);
772   begin
773    inherited Create;
# Line 774 | Line 776 | begin
776    FUniqueName := true;
777   end;
778  
779 < procedure TSQLVarData.SetString(aValue: string);
779 > procedure TSQLVarData.SetString(aValue: AnsiString);
780   begin
781    {we take full advantage here of reference counted strings. When setting a string
782     value, a reference is kept in FVarString and a pointer to it placed in the
783 <   SQLVar. This avoids string copies. Note that PChar is guaranteed to point to
783 >   SQLVar. This avoids string copies. Note that PAnsiChar is guaranteed to point to
784     a zero byte when the string is empty, neatly avoiding a nil pointer error.}
785  
786    FVarString := aValue;
787 <  SQLType := SQL_TEXT;
788 <  SetSQLData(PChar(FVarString),Length(aValue));
787 >  if SQLType = SQL_BLOB then
788 >    SetMetaSize(GetAttachment.GetInlineBlobLimit);
789 >  SQLType := GetDefaultTextSQLType;
790 >  Scale := 0;
791 >  SetSQLData(PByte(PAnsiChar(FVarString)),Length(aValue));
792   end;
793  
794   procedure TSQLVarData.Changed;
# Line 797 | Line 802 | begin
802    FVarString := '';
803   end;
804  
805 + function TSQLVarData.getColMetadata: IParamMetaData;
806 + begin
807 +  Result := FColMetaData;
808 + end;
809 +
810   procedure TSQLVarData.Initialize;
811  
812 <  function FindVarByName(idx: string; limit: integer): TSQLVarData;
812 >  function FindVarByName(idx: AnsiString; limit: integer): TSQLVarData;
813    var
814      k: integer;
815    begin
# Line 814 | Line 824 | procedure TSQLVarData.Initialize;
824  
825   var
826    j, j_len: Integer;
827 <  st: String;
828 <  sBaseName: string;
827 >  st: AnsiString;
828 >  sBaseName: AnsiString;
829   begin
830    RowChange;
831  
# Line 897 | Line 907 | begin
907      result := Val;
908   end;
909  
910 + function TSQLDataItem.AdjustScaleToStr(Value: Int64; aScale: Integer
911 +  ): AnsiString;
912 + var Scaling : AnsiString;
913 +    i: Integer;
914 + begin
915 +  Result := IntToStr(Value);
916 +  Scaling := '';
917 +  if aScale > 0 then
918 +  begin
919 +    for i := 1 to aScale do
920 +      Result := Result + '0';
921 +  end
922 +  else
923 +  if aScale < 0 then
924 +  {$IF declared(DefaultFormatSettings)}
925 +  with DefaultFormatSettings do
926 +  {$ELSE}
927 +  {$IF declared(FormatSettings)}
928 +  with FormatSettings do
929 +  {$IFEND}
930 +  {$IFEND}
931 +  begin
932 +    if Length(Result) > -aScale then
933 +      system.Insert(DecimalSeparator,Result,Length(Result) + aScale)
934 +    else
935 +    begin
936 +      Scaling := '0' + DecimalSeparator;
937 +      for i := -1 downto aScale + Length(Result) do
938 +        Scaling := Scaling + '0';
939 +      Result := Scaling + Result;
940 +    end;
941 +  end;
942 + end;
943 +
944   function TSQLDataItem.AdjustScaleToCurrency(Value: Int64; aScale: Integer
945    ): Currency;
946   var
947    Scaling : Int64;
948    i : Integer;
949 <  FractionText, PadText, CurrText: string;
949 >  FractionText, PadText, CurrText: AnsiString;
950   begin
951    Result := 0;
952    Scaling := 1;
# Line 921 | Line 965 | begin
965        FractionText := IntToStr(abs(Value mod Scaling));
966        for i := Length(FractionText) to -aScale -1 do
967          PadText := '0' + PadText;
968 +      {$IF declared(DefaultFormatSettings)}
969 +      with DefaultFormatSettings do
970 +      {$ELSE}
971 +      {$IF declared(FormatSettings)}
972 +      with FormatSettings do
973 +      {$IFEND}
974 +      {$IFEND}
975        if Value < 0 then
976 <        CurrText := '-' + IntToStr(Abs(Value div Scaling)) + DefaultFormatSettings.DecimalSeparator + PadText + FractionText
976 >        CurrText := '-' + IntToStr(Abs(Value div Scaling)) + DecimalSeparator + PadText + FractionText
977        else
978 <        CurrText := IntToStr(Abs(Value div Scaling)) + DefaultFormatSettings.DecimalSeparator + PadText + FractionText;
978 >        CurrText := IntToStr(Abs(Value div Scaling)) + DecimalSeparator + PadText + FractionText;
979        try
980          result := StrToCurr(CurrText);
981        except
# Line 936 | Line 987 | begin
987        result := Value;
988   end;
989  
990 + function TSQLDataItem.GetDateFormatStr(IncludeTime: boolean): AnsiString;
991 + begin
992 +  {$IF declared(DefaultFormatSettings)}
993 +  with DefaultFormatSettings do
994 +  {$ELSE}
995 +  {$IF declared(FormatSettings)}
996 +  with FormatSettings do
997 +  {$IFEND}
998 +  {$IFEND}
999 +  case GetSQLDialect of
1000 +    1:
1001 +      if IncludeTime then
1002 +        result := ShortDateFormat + ' ' + LongTimeFormat
1003 +      else
1004 +        result := ShortDateFormat;
1005 +    3:
1006 +      result := ShortDateFormat;
1007 +  end;
1008 + end;
1009 +
1010 + function TSQLDataItem.GetTimeFormatStr: AnsiString;
1011 + begin
1012 +  {$IF declared(DefaultFormatSettings)}
1013 +  with DefaultFormatSettings do
1014 +  {$ELSE}
1015 +  {$IF declared(FormatSettings)}
1016 +  with FormatSettings do
1017 +  {$IFEND}
1018 +  {$IFEND}
1019 +    Result := 'hh' + TimeSeparator + 'nn' + TimeSeparator + 'ss' + '.zzzz';;
1020 + end;
1021 +
1022 + function TSQLDataItem.GetTimestampFormatStr: AnsiString;
1023 + begin
1024 +  {$IF declared(DefaultFormatSettings)}
1025 +  with DefaultFormatSettings do
1026 +  {$ELSE}
1027 +  {$IF declared(FormatSettings)}
1028 +  with FormatSettings do
1029 +  {$IFEND}
1030 +  {$IFEND}
1031 +    Result := ShortDateFormat + ' ' +  'hh' + TimeSeparator + 'nn' + TimeSeparator + 'ss' + '.zzzz';
1032 + end;
1033 +
1034   procedure TSQLDataItem.SetAsInteger(AValue: Integer);
1035   begin
1036    SetAsLong(aValue);
1037   end;
1038  
1039 + procedure TSQLDataItem.InternalGetAsDateTime(var aDateTime: TDateTime;
1040 +  var dstOffset: smallint; var aTimezone: AnsiString;
1041 +  var aTimeZoneID: TFBTimeZoneID);
1042 + begin
1043 +  CheckActive;
1044 +  aDateTime := 0;
1045 +  dstOffset := 0;
1046 +  aTimezone := '';
1047 +  aTimeZoneID := TimeZoneID_GMT;
1048 +  if not IsNull then
1049 +    with FFirebirdClientAPI do
1050 +    case SQLType of
1051 +      SQL_TEXT, SQL_VARYING:
1052 +        if not ParseDateTimeTZString(AsString,aDateTime,aTimeZone) then
1053 +          IBError(ibxeInvalidDataConversion, [nil]);
1054 +      SQL_TYPE_DATE:
1055 +        aDateTime := SQLDecodeDate(SQLData);
1056 +      SQL_TYPE_TIME:
1057 +        aDateTime := SQLDecodeTime(SQLData);
1058 +      SQL_TIMESTAMP:
1059 +        aDateTime := SQLDecodeDateTime(SQLData);
1060 +      SQL_TIMESTAMP_TZ:
1061 +        begin
1062 +          GetTimeZoneServices.DecodeTimestampTZ(SQLData,aDateTime,dstOffset,aTimeZone);
1063 +          aTimeZoneID := PISC_TIMESTAMP_TZ(SQLData)^.time_zone;
1064 +        end;
1065 +      SQL_TIMESTAMP_TZ_EX:
1066 +      begin
1067 +        GetTimeZoneServices.DecodeTimestampTZEx(SQLData,aDateTime,dstOffset,aTimeZone);
1068 +        aTimeZoneID := PISC_TIMESTAMP_TZ_EX(SQLData)^.time_zone;
1069 +      end;
1070 +      SQL_TIME_TZ:
1071 +        with GetTimeZoneServices do
1072 +        begin
1073 +          DecodeTimeTZ(SQLData,GetTimeTZDate,aDateTime,dstOffset,aTimeZone);
1074 +          aTimeZoneID := PISC_TIME_TZ(SQLData)^.time_zone;
1075 +        end;
1076 +      SQL_TIME_TZ_EX:
1077 +        with GetTimeZoneServices do
1078 +        begin
1079 +          DecodeTimeTZEx(SQLData,GetTimeTZDate,aDateTime,dstOffset,aTimeZone);
1080 +          aTimeZoneID := PISC_TIME_TZ_EX(SQLData)^.time_zone;
1081 +        end;
1082 +      else
1083 +        IBError(ibxeInvalidDataConversion, [nil]);
1084 +    end;
1085 + end;
1086 +
1087   function TSQLDataItem.AdjustScaleFromCurrency(Value: Currency; aScale: Integer
1088    ): Int64;
1089   var
# Line 989 | Line 1132 | begin
1132    end
1133    else
1134      result := trunc(Value);
1135 + //  writeln('Adjusted ',Value,' to ',Result);
1136   end;
1137  
1138   procedure TSQLDataItem.CheckActive;
# Line 996 | Line 1140 | begin
1140    //Do nothing by default
1141   end;
1142  
1143 + procedure TSQLDataItem.CheckTZSupport;
1144 + begin
1145 +  if not FFirebirdClientAPI.HasTimeZoneSupport then
1146 +    IBError(ibxeNoTimezoneSupport,[]);
1147 + end;
1148 +
1149 + function TSQLDataItem.GetTimeZoneServices: IExTimeZoneServices;
1150 + begin
1151 +  if FTimeZoneServices = nil then
1152 +  begin
1153 +    if not GetAttachment.HasTimeZoneSupport then
1154 +      IBError(ibxeNoTimezoneSupport,[]);
1155 +    GetAttachment.GetTimeZoneServices.QueryInterface(IExTimeZoneServices,FTimeZoneServices);
1156 +  end;
1157 +  Result := FTimeZoneServices;
1158 + end;
1159 +
1160   procedure TSQLDataItem.Changed;
1161   begin
1162    //Do nothing by default
# Line 1006 | Line 1167 | begin
1167    //Do nothing by default
1168   end;
1169  
1170 < procedure TSQLDataItem.InternalSetAsString(Value: String);
1170 > procedure TSQLDataItem.InternalSetAsString(Value: AnsiString);
1171   begin
1172    //Do nothing by default
1173   end;
1174  
1175 < function TSQLDataItem.Transliterate(s: string; CodePage: TSystemCodePage
1175 > function TSQLDataItem.Transliterate(s: AnsiString; CodePage: TSystemCodePage
1176    ): RawByteString;
1177   begin
1178    Result := s;
# Line 1034 | Line 1195 | begin
1195     //Do nothing by default
1196   end;
1197  
1198 < function TSQLDataItem.GetSQLTypeName: string;
1198 > constructor TSQLDataItem.Create(api: TFBClientAPI);
1199 > begin
1200 >  inherited Create;
1201 >  FFirebirdClientAPI := api;
1202 > end;
1203 >
1204 > function TSQLDataItem.GetSQLTypeName: AnsiString;
1205   begin
1206    Result := GetSQLTypeName(GetSQLType);
1207   end;
1208  
1209 < class function TSQLDataItem.GetSQLTypeName(SQLType: short): string;
1209 > class function TSQLDataItem.GetSQLTypeName(SQLType: cardinal): AnsiString;
1210   begin
1211    Result := 'Unknown';
1212    case SQLType of
# Line 1050 | Line 1217 | begin
1217    SQL_LONG:             Result := 'SQL_LONG';
1218    SQL_SHORT:            Result := 'SQL_SHORT';
1219    SQL_TIMESTAMP:        Result := 'SQL_TIMESTAMP';
1220 +  SQL_TIMESTAMP_TZ:     Result := 'SQL_TIMESTAMP_TZ';
1221 +  SQL_TIMESTAMP_TZ_EX:  Result := 'SQL_TIMESTAMP_TZ_EX';
1222    SQL_BLOB:             Result := 'SQL_BLOB';
1223    SQL_D_FLOAT:          Result := 'SQL_D_FLOAT';
1224    SQL_ARRAY:            Result := 'SQL_ARRAY';
# Line 1057 | Line 1226 | begin
1226    SQL_TYPE_TIME:        Result := 'SQL_TYPE_TIME';
1227    SQL_TYPE_DATE:        Result := 'SQL_TYPE_DATE';
1228    SQL_INT64:            Result := 'SQL_INT64';
1229 +  SQL_TIME_TZ:          Result := 'SQL_TIME_TZ';
1230 +  SQL_TIME_TZ_EX:       Result := 'SQL_TIME_TZ_EX';
1231 +  SQL_DEC_FIXED:        Result := 'SQL_DEC_FIXED';
1232 +  SQL_DEC16:            Result := 'SQL_DEC16';
1233 +  SQL_DEC34:            Result := 'SQL_DEC34';
1234 +  SQL_INT128:           Result := 'SQL_INT128';
1235 +  SQL_NULL:             Result := 'SQL_NULL';
1236 +  SQL_BOOLEAN:          Result := 'SQL_BOOLEAN';
1237    end;
1238   end;
1239  
1240 + function TSQLDataItem.GetStrDataLength: short;
1241 + begin
1242 +  with FFirebirdClientAPI do
1243 +  if SQLType = SQL_VARYING then
1244 +    Result := DecodeInteger(SQLData, 2)
1245 +  else
1246 +    Result := DataLength;
1247 + end;
1248 +
1249   function TSQLDataItem.GetAsBoolean: boolean;
1250   begin
1251    CheckActive;
# Line 1099 | Line 1285 | begin
1285            result := AdjustScaleToCurrency(PInt64(SQLData)^,
1286                                        Scale);
1287          SQL_DOUBLE, SQL_FLOAT, SQL_D_FLOAT:
1288 <          result := Trunc(AsDouble);
1288 >          result := Round(AsDouble);
1289 >
1290 >        SQL_DEC_FIXED,
1291 >        SQL_DEC16,
1292 >        SQL_DEC34,
1293 >        SQL_INT128:
1294 >          if not BCDToCurr(GetAsBCD,Result) then
1295 >            IBError(ibxeInvalidDataConversion, [nil]);
1296 >
1297          else
1298            IBError(ibxeInvalidDataConversion, [nil]);
1299        end;
# Line 1129 | Line 1323 | begin
1323          result := AdjustScaleToInt64(PInt64(SQLData)^,
1324                                      Scale);
1325        SQL_DOUBLE, SQL_FLOAT, SQL_D_FLOAT:
1326 <        result := Trunc(AsDouble);
1326 >        result := Round(AsDouble);
1327        else
1328          IBError(ibxeInvalidDataConversion, [nil]);
1329      end;
1330   end;
1331  
1332   function TSQLDataItem.GetAsDateTime: TDateTime;
1333 + var aTimezone: AnsiString;
1334 +    aTimeZoneID: TFBTimeZoneID;
1335 +    dstOffset: smallint;
1336 + begin
1337 +  InternalGetAsDateTime(Result,dstOffset,aTimeZone,aTimeZoneID);
1338 + end;
1339 +
1340 + procedure TSQLDataItem.GetAsDateTime(var aDateTime: TDateTime;
1341 +  var dstOffset: smallint; var aTimezone: AnsiString);
1342 + var aTimeZoneID: TFBTimeZoneID;
1343 + begin
1344 +  InternalGetAsDateTime(aDateTime,dstOffset,aTimeZone,aTimeZoneID);
1345 + end;
1346 +
1347 + procedure TSQLDataItem.GetAsDateTime(var aDateTime: TDateTime; var dstOffset: smallint;
1348 +  var aTimezoneID: TFBTimeZoneID);
1349 + var aTimezone: AnsiString;
1350 + begin
1351 +  InternalGetAsDateTime(aDateTime,dstOffset,aTimeZone,aTimeZoneID);
1352 + end;
1353 +
1354 + procedure TSQLDataItem.GetAsTime(var aTime: TDateTime; var dstOffset: smallint;
1355 +  var aTimezoneID: TFBTimeZoneID; OnDate: TDateTime);
1356 + var aTimeZone: AnsiString;
1357   begin
1358    CheckActive;
1359 <  result := 0;
1359 >  aTime := 0;
1360 >  dstOffset := 0;
1361    if not IsNull then
1362 <    with FirebirdClientAPI do
1362 >    with FFirebirdClientAPI do
1363      case SQLType of
1364 <      SQL_TEXT, SQL_VARYING: begin
1365 <        try
1366 <          result := StrToDate(AsString);
1367 <        except
1149 <          on E: EConvertError do IBError(ibxeInvalidDataConversion, [nil]);
1364 >      SQL_TIME_TZ:
1365 >        begin
1366 >          GetTimeZoneServices.DecodeTimeTZ(SQLData,OnDate,aTime,dstOffset,aTimeZone);
1367 >          aTimeZoneID := PISC_TIME_TZ(SQLData)^.time_zone;
1368          end;
1369 +      SQL_TIME_TZ_EX:
1370 +        begin
1371 +          GetTimeZoneServices.DecodeTimeTZEx(SQLData,OnDate,aTime,dstOffset,aTimeZone);
1372 +          aTimeZoneID := PISC_TIME_TZ_EX(SQLData)^.time_zone;
1373 +        end;
1374 +    else
1375 +      IBError(ibxeInvalidDataConversion, [nil]);
1376 +    end;
1377 + end;
1378 +
1379 + procedure TSQLDataItem.GetAsTime(var aTime: TDateTime; var dstOffset: smallint;
1380 +  var aTimezone: AnsiString; OnDate: TDateTime);
1381 + begin
1382 +  CheckActive;
1383 +  aTime := 0;
1384 +  dstOffset := 0;
1385 +  if not IsNull then
1386 +    with FFirebirdClientAPI do
1387 +    case SQLType of
1388 +      SQL_TIME_TZ:
1389 +        GetTimeZoneServices.DecodeTimeTZ(SQLData,OnDate,aTime,dstOffset,aTimeZone);
1390 +      SQL_TIME_TZ_EX:
1391 +        GetTimeZoneServices.DecodeTimeTZEx(SQLData,OnDate,aTime,dstOffset,aTimeZone);
1392 +    else
1393 +      IBError(ibxeInvalidDataConversion, [nil]);
1394 +    end;
1395 + end;
1396 +
1397 + procedure TSQLDataItem.GetAsTime(var aTime: TDateTime; var dstOffset: smallint;
1398 +  var aTimezoneID: TFBTimeZoneID);
1399 + begin
1400 +  GetAsTime(aTime,dstOffset,aTimeZoneID,GetTimeZoneServices.GetTimeTZDate);
1401 + end;
1402 +
1403 + procedure TSQLDataItem.GetAsTime(var aTime: TDateTime; var dstOffset: smallint;
1404 +  var aTimezone: AnsiString);
1405 + begin
1406 +  GetAsTime(aTime,dstOffset,aTimeZone,GetTimeZoneServices.GetTimeTZDate);
1407 + end;
1408 +
1409 + function TSQLDataItem.GetAsUTCDateTime: TDateTime;
1410 + var aTimezone: AnsiString;
1411 + begin
1412 +  CheckActive;
1413 +  result := 0;
1414 +  aTimezone := '';
1415 +  if not IsNull then
1416 +    with FFirebirdClientAPI do
1417 +    case SQLType of
1418 +      SQL_TEXT, SQL_VARYING:
1419 +      begin
1420 +        if not ParseDateTimeTZString(AsString,Result,aTimeZone) then
1421 +          IBError(ibxeInvalidDataConversion, [nil]);
1422 +        Result := GetTimeZoneServices.LocalTimeToGMT(Result,aTimeZone);
1423        end;
1424        SQL_TYPE_DATE:
1425          result := SQLDecodeDate(SQLData);
1426 <      SQL_TYPE_TIME:
1426 >      SQL_TYPE_TIME,
1427 >      SQL_TIME_TZ,
1428 >      SQL_TIME_TZ_EX:
1429          result := SQLDecodeTime(SQLData);
1430 <      SQL_TIMESTAMP:
1430 >      SQL_TIMESTAMP,
1431 >      SQL_TIMESTAMP_TZ,
1432 >      SQL_TIMESTAMP_TZ_EX:
1433          result := SQLDecodeDateTime(SQLData);
1434        else
1435          IBError(ibxeInvalidDataConversion, [nil]);
1436 <    end;
1436 >      end;
1437   end;
1438  
1439   function TSQLDataItem.GetAsDouble: Double;
# Line 1185 | Line 1461 | begin
1461          result := PFloat(SQLData)^;
1462        SQL_DOUBLE, SQL_D_FLOAT:
1463          result := PDouble(SQLData)^;
1464 +      SQL_DEC_FIXED,
1465 +      SQL_DEC16,
1466 +      SQL_DEC34,
1467 +      SQL_INT128:
1468 +        Result := BCDToDouble(GetAsBCD);
1469        else
1470          IBError(ibxeInvalidDataConversion, [nil]);
1471      end;
# Line 1221 | Line 1502 | begin
1502          end;
1503        end;
1504        SQL_SHORT:
1505 <        result := Trunc(AdjustScale(Int64(PShort(SQLData)^),
1505 >        result := Round(AdjustScale(Int64(PShort(SQLData)^),
1506                                      Scale));
1507        SQL_LONG:
1508 <        result := Trunc(AdjustScale(Int64(PLong(SQLData)^),
1508 >        result := Round(AdjustScale(Int64(PLong(SQLData)^),
1509                                      Scale));
1510        SQL_INT64:
1511 <        result := Trunc(AdjustScale(PInt64(SQLData)^, Scale));
1511 >        result := Round(AdjustScale(PInt64(SQLData)^, Scale));
1512        SQL_DOUBLE, SQL_FLOAT, SQL_D_FLOAT:
1513 <        result := Trunc(AsDouble);
1513 >        result := Round(AsDouble);
1514 >      SQL_DEC_FIXED,
1515 >      SQL_DEC16,
1516 >      SQL_DEC34,
1517 >      SQL_INT128:
1518 >        Result := BCDToInteger(GetAsBCD);
1519        else
1520 <        IBError(ibxeInvalidDataConversion, [nil]);
1520 >        IBError(ibxeInvalidDataConversion, [GetSQLTypeName]);
1521      end;
1522   end;
1523  
# Line 1269 | Line 1555 | begin
1555    end;
1556   end;
1557  
1558 + {Copied from LazUTF8}
1559 +
1560 + function UTF8CodepointSizeFull(p: PAnsiChar): integer;
1561 + const TopBitSetMask   = $80; {%10000000}
1562 +      Top2BitsSetMask = $C0; {%11000000}
1563 +      Top3BitsSetMask = $E0; {%11100000}
1564 +      Top4BitsSetMask = $F0; {%11110000}
1565 +      Top5BitsSetMask = $F8; {%11111000}
1566 + begin
1567 +  case p^ of
1568 +  #0..#191: // %11000000
1569 +    // regular single byte character (#0 is a character, this is Pascal ;)
1570 +    Result:=1;
1571 +  #192..#223: // p^ and %11100000 = %11000000
1572 +    begin
1573 +      // could be 2 byte character
1574 +      if (ord(p[1]) and Top2BitsSetMask) = TopBitSetMask then
1575 +        Result:=2
1576 +      else
1577 +        Result:=1;
1578 +    end;
1579 +  #224..#239: // p^ and %11110000 = %11100000
1580 +    begin
1581 +      // could be 3 byte character
1582 +      if ((ord(p[1]) and Top2BitsSetMask) = TopBitSetMask)
1583 +      and ((ord(p[2]) and Top2BitsSetMask) = TopBitSetMask) then
1584 +        Result:=3
1585 +      else
1586 +        Result:=1;
1587 +    end;
1588 +  #240..#247: // p^ and %11111000 = %11110000
1589 +    begin
1590 +      // could be 4 byte character
1591 +      if ((ord(p[1]) and Top2BitsSetMask) = TopBitSetMask)
1592 +      and ((ord(p[2]) and Top2BitsSetMask) = TopBitSetMask)
1593 +      and ((ord(p[3]) and Top2BitsSetMask) = TopBitSetMask) then
1594 +        Result:=4
1595 +      else
1596 +        Result:=1;
1597 +    end;
1598 +  else
1599 +    Result:=1;
1600 +  end;
1601 + end;
1602 +
1603 + {Returns the byte length of a UTF8 string with a fixed charwidth}
1604 +
1605 + function GetStrLen(p: PAnsiChar; FieldWidth, MaxDataLength: cardinal): integer;
1606 + var i: integer;
1607 +    cplen: integer;
1608 +    s: AnsiString;
1609 + begin
1610 +  Result := 0;
1611 +  s := strpas(p);
1612 +  for i := 1 to FieldWidth do
1613 +  begin
1614 +    cplen := UTF8CodepointSizeFull(p);
1615 +    Inc(p,cplen);
1616 +    Inc(Result,cplen);
1617 +    if Result >= MaxDataLength then
1618 +    begin
1619 +      Result := MaxDataLength;
1620 +      Exit;
1621 +    end;
1622 +  end;
1623 + end;
1624  
1625 < function TSQLDataItem.GetAsString: String;
1625 > function TSQLDataItem.GetAsString: AnsiString;
1626   var
1627 <  sz: PChar;
1627 >  sz: PByte;
1628    str_len: Integer;
1629    rs: RawByteString;
1630 +  aTimeZone: AnsiString;
1631 +  aDateTime: TDateTime;
1632 +  dstOffset: smallint;
1633   begin
1634    CheckActive;
1635    result := '';
1636    { Check null, if so return a default string }
1637    if not IsNull then
1638 <  with FirebirdClientAPI do
1638 >  with FFirebirdClientAPI do
1639      case SQLType of
1640        SQL_BOOLEAN:
1641          if AsBoolean then
# Line 1292 | Line 1647 | begin
1647        begin
1648          sz := SQLData;
1649          if (SQLType = SQL_TEXT) then
1650 <          str_len := DataLength
1650 >        begin
1651 >          if GetCodePage = cp_utf8 then
1652 >            str_len := GetStrLen(PAnsiChar(sz),GetSize div GetCharSetWidth,DataLength)
1653 >          else
1654 >            str_len := DataLength
1655 >        end
1656          else begin
1657 <          str_len := DecodeInteger(SQLData, 2);
1657 >          str_len := DecodeInteger(sz, 2);
1658            Inc(sz, 2);
1659          end;
1660 <        SetString(rs, sz, str_len);
1660 >        SetString(rs, PAnsiChar(sz), str_len);
1661          SetCodePage(rs,GetCodePage,false);
1662 <        if (SQLType = SQL_TEXT) and (GetCharSetID <> 1) then
1303 <          Result := TrimRight(rs)
1304 <        else
1305 <          Result := rs
1662 >        Result := rs;
1663        end;
1664 +
1665        SQL_TYPE_DATE:
1666 <        case GetSQLDialect of
1309 <          1 : result := DateTimeToStr(AsDateTime);
1310 <          3 : result := DateToStr(AsDateTime);
1311 <        end;
1312 <      SQL_TYPE_TIME :
1313 <        result := TimeToStr(AsDateTime);
1666 >        Result := DateToStr(GetAsDateTime);
1667        SQL_TIMESTAMP:
1668 <        result := FormatDateTime(FormatSettings.ShortDateFormat + ' ' +
1669 <                            FormatSettings.LongTimeFormat+'.zzz',AsDateTime);
1668 >        Result := FBFormatDateTime(GetTimestampFormatStr,GetAsDateTime);
1669 >      SQL_TYPE_TIME:
1670 >        Result := FBFormatDateTime(GetTimeFormatStr,GetAsDateTime);
1671 >      SQL_TIMESTAMP_TZ,
1672 >      SQL_TIMESTAMP_TZ_EX:
1673 >        with GetAttachment.GetTimeZoneServices do
1674 >        begin
1675 >          if GetTZTextOption = tzGMT then
1676 >            Result := FBFormatDateTime(GetTimestampFormatStr,GetAsUTCDateTime)
1677 >          else
1678 >          begin
1679 >            GetAsDateTime(aDateTime,dstOffset,aTimeZone);
1680 >            if GetTZTextOption = tzOffset then
1681 >              Result := FBFormatDateTime(GetTimestampFormatStr,aDateTime) + ' ' + FormatTimeZoneOffset(dstOffset)
1682 >            else
1683 >              Result := FBFormatDateTime(GetTimestampFormatStr,aDateTime) + ' ' + aTimeZone;
1684 >          end;
1685 >        end;
1686 >      SQL_TIME_TZ,
1687 >      SQL_TIME_TZ_EX:
1688 >        with GetAttachment.GetTimeZoneServices do
1689 >        begin
1690 >          if GetTZTextOption = tzGMT then
1691 >             Result := FBFormatDateTime(GetTimeFormatStr,GetAsUTCDateTime)
1692 >          else
1693 >          begin
1694 >            GetAsTime(aDateTime,dstOffset,aTimeZone,GetTimeTZDate);
1695 >            if GetTZTextOption = tzOffset then
1696 >              Result := FBFormatDateTime(GetTimeFormatStr,aDateTime) + ' ' + FormatTimeZoneOffset(dstOffset)
1697 >            else
1698 >              Result := FBFormatDateTime(GetTimeFormatStr,aDateTime) + ' ' + aTimeZone;
1699 >          end;
1700 >        end;
1701 >
1702        SQL_SHORT, SQL_LONG:
1703          if Scale = 0 then
1704            result := IntToStr(AsLong)
# Line 1330 | Line 1715 | begin
1715            result := FloatToStr(AsDouble);
1716        SQL_DOUBLE, SQL_FLOAT, SQL_D_FLOAT:
1717          result := FloatToStr(AsDouble);
1718 +
1719 +      SQL_DEC16,
1720 +      SQL_DEC34:
1721 +        result := BCDToStr(GetAsBCD);
1722 +
1723 +      SQL_DEC_FIXED,
1724 +      SQL_INT128:
1725 +        result := Int128ToStr(SQLData,scale);
1726 +
1727        else
1728          IBError(ibxeInvalidDataConversion, [nil]);
1729      end;
# Line 1341 | Line 1735 | begin
1735    Result := false;
1736   end;
1737  
1738 < function TSQLDataItem.getIsNullable: boolean;
1738 > function TSQLDataItem.GetIsNullable: boolean;
1739   begin
1740    CheckActive;
1741    Result := false;
1742   end;
1743  
1744   function TSQLDataItem.GetAsVariant: Variant;
1745 + var ts: TDateTime;
1746 +  dstOffset: smallint;
1747 +    timezone: AnsiString;
1748   begin
1749    CheckActive;
1750    if IsNull then
# Line 1361 | Line 1758 | begin
1758          result := AsString;
1759        SQL_TIMESTAMP, SQL_TYPE_DATE, SQL_TYPE_TIME:
1760          result := AsDateTime;
1761 +      SQL_TIMESTAMP_TZ,
1762 +      SQL_TIME_TZ,
1763 +      SQL_TIMESTAMP_TZ_EX,
1764 +      SQL_TIME_TZ_EX:
1765 +        begin
1766 +          GetAsDateTime(ts,dstOffset,timezone);
1767 +          result := VarArrayOf([ts,dstOffset,timezone]);
1768 +        end;
1769        SQL_SHORT, SQL_LONG:
1770          if Scale = 0 then
1771            result := AsLong
# Line 1379 | Line 1784 | begin
1784          result := AsDouble;
1785        SQL_BOOLEAN:
1786          result := AsBoolean;
1787 +      SQL_DEC_FIXED,
1788 +      SQL_DEC16,
1789 +      SQL_DEC34,
1790 +      SQL_INT128:
1791 +        result := VarFmtBCDCreate(GetAsBcd);
1792        else
1793          IBError(ibxeInvalidDataConversion, [nil]);
1794      end;
# Line 1389 | Line 1799 | begin
1799    Result := false;
1800   end;
1801  
1802 + function TSQLDataItem.GetDateTimeStrLength(DateTimeFormat: TIBDateTimeFormats
1803 +  ): integer;
1804 + begin
1805 +  case DateTimeFormat of
1806 +  dfTimestamp:
1807 +    Result := Length(GetTimestampFormatStr);
1808 +  dfDateTime:
1809 +    Result := Length(GetDateFormatStr(true));
1810 +  dfTime:
1811 +    Result := Length(GetTimeFormatStr);
1812 +  dfTimestampTZ:
1813 +    Result := Length(GetTimestampFormatStr) + 6; {assume time offset format}
1814 +  dfTimeTZ:
1815 +    Result := Length(GetTimeFormatStr)+ 6;
1816 +  else
1817 +    Result := 0;
1818 +  end;end;
1819 +
1820 + function TSQLDataItem.GetAsBCD: tBCD;
1821 +
1822 + begin
1823 +  CheckActive;
1824 +  if IsNull then
1825 +   with Result do
1826 +   begin
1827 +     FillChar(Result,sizeof(Result),0);
1828 +     Precision := 1;
1829 +     exit;
1830 +   end;
1831 +
1832 +  case SQLType of
1833 +  SQL_DEC16,
1834 +  SQL_DEC34:
1835 +    with FFirebirdClientAPI do
1836 +      Result := SQLDecFloatDecode(SQLType,  SQLData);
1837 +
1838 +  SQL_DEC_FIXED,
1839 +  SQL_INT128:
1840 +    with FFirebirdClientAPI do
1841 +      Result := StrToBCD(Int128ToStr(SQLData,scale));
1842 +  else
1843 +    if not CurrToBCD(GetAsCurrency,Result) then
1844 +      IBError(ibxeBadBCDConversion,[]);
1845 +  end;
1846 + end;
1847 +
1848  
1849   procedure TSQLDataItem.SetIsNull(Value: Boolean);
1850   begin
# Line 1400 | Line 1856 | begin
1856    //ignore unless overridden
1857   end;
1858  
1859 < procedure TSQLDataItem.SetName(aValue: string);
1859 > procedure TSQLDataItem.SetName(aValue: AnsiString);
1860   begin
1861    //ignore unless overridden
1862   end;
# Line 1452 | Line 1908 | begin
1908  
1909    SQLType := SQL_TYPE_DATE;
1910    DataLength := SizeOf(ISC_DATE);
1911 <  with FirebirdClientAPI do
1911 >  with FFirebirdClientAPI do
1912      SQLEncodeDate(Value,SQLData);
1913    Changed;
1914   end;
# Line 1472 | Line 1928 | begin
1928  
1929    SQLType := SQL_TYPE_TIME;
1930    DataLength := SizeOf(ISC_TIME);
1931 <  with FirebirdClientAPI do
1931 >  with FFirebirdClientAPI do
1932      SQLEncodeTime(Value,SQLData);
1933    Changed;
1934   end;
1935  
1936 + procedure TSQLDataItem.SetAsTime(aValue: TDateTime; OnDate: TDateTime; aTimeZoneID: TFBTimeZoneID);
1937 + begin
1938 +  CheckActive;
1939 +  CheckTZSupport;
1940 +  if GetSQLDialect < 3 then
1941 +  begin
1942 +    AsDateTime := aValue;
1943 +    exit;
1944 +  end;
1945 +
1946 +  Changing;
1947 +  if IsNullable then
1948 +    IsNull := False;
1949 +
1950 +  SQLType := SQL_TIME_TZ;
1951 +  DataLength := SizeOf(ISC_TIME_TZ);
1952 +  GetTimeZoneServices.EncodeTimeTZ(aValue, aTimeZoneID,OnDate,SQLData);
1953 +  Changed;
1954 + end;
1955 +
1956 + procedure TSQLDataItem.SetAsTime(aValue: TDateTime; OnDate: TDateTime; aTimeZone: AnsiString);
1957 + begin
1958 +  CheckActive;
1959 +  CheckTZSupport;
1960 +  if GetSQLDialect < 3 then
1961 +  begin
1962 +    AsDateTime := aValue;
1963 +    exit;
1964 +  end;
1965 +
1966 +  Changing;
1967 +  if IsNullable then
1968 +    IsNull := False;
1969 +
1970 +  SQLType := SQL_TIME_TZ;
1971 +  DataLength := SizeOf(ISC_TIME_TZ);
1972 +  GetTimeZoneServices.EncodeTimeTZ(aValue, aTimeZone,OnDate,SQLData);
1973 +  Changed;
1974 + end;
1975 +
1976   procedure TSQLDataItem.SetAsDateTime(Value: TDateTime);
1977   begin
1978    CheckActive;
# Line 1486 | Line 1982 | begin
1982    Changing;
1983    SQLType := SQL_TIMESTAMP;
1984    DataLength := SizeOf(ISC_TIME) + sizeof(ISC_DATE);
1985 <  with FirebirdClientAPI do
1985 >  with FFirebirdClientAPI do
1986      SQLEncodeDateTime(Value,SQLData);
1987    Changed;
1988   end;
1989  
1990 + procedure TSQLDataItem.SetAsDateTime(aValue: TDateTime;
1991 +  aTimeZoneID: TFBTimeZoneID);
1992 + begin
1993 +  CheckActive;
1994 +  CheckTZSupport;
1995 +  if IsNullable then
1996 +    IsNull := False;
1997 +
1998 +  Changing;
1999 +  SQLType := SQL_TIMESTAMP_TZ;
2000 +  DataLength := SizeOf(ISC_TIMESTAMP_TZ);
2001 +  GetTimeZoneServices.EncodeTimestampTZ(aValue,aTimeZoneID,SQLData);
2002 +  Changed;
2003 + end;
2004 +
2005 + procedure TSQLDataItem.SetAsDateTime(aValue: TDateTime; aTimeZone: AnsiString
2006 +  );
2007 + begin
2008 +  CheckActive;
2009 +  CheckTZSupport;
2010 +  if IsNullable then
2011 +    IsNull := False;
2012 +
2013 +  Changing;
2014 +  SQLType := SQL_TIMESTAMP_TZ;
2015 +  DataLength := SizeOf(ISC_TIMESTAMP_TZ);
2016 +  GetTimeZoneServices.EncodeTimestampTZ(aValue,aTimeZone,SQLData);
2017 +  Changed;
2018 + end;
2019 +
2020 + procedure TSQLDataItem.SetAsUTCDateTime(aUTCTime: TDateTime);
2021 + begin
2022 +  SetAsDateTime(aUTCTime,TimeZoneID_GMT);
2023 + end;
2024 +
2025   procedure TSQLDataItem.SetAsDouble(Value: Double);
2026   begin
2027    CheckActive;
# Line 1576 | Line 2107 | begin
2107    Changed;
2108   end;
2109  
2110 < procedure TSQLDataItem.SetAsString(Value: String);
2110 > procedure TSQLDataItem.SetAsString(Value: AnsiString);
2111   begin
2112    InternalSetAsString(Value);
2113   end;
# Line 1586 | Line 2117 | begin
2117    CheckActive;
2118    if VarIsNull(Value) then
2119      IsNull := True
2120 +  else
2121 +  if VarIsArray(Value) then {must be datetime plus timezone}
2122 +    SetAsDateTime(Value[0],AnsiString(Value[1]))
2123    else case VarType(Value) of
2124      varEmpty, varNull:
2125        IsNull := True;
# Line 1608 | Line 2142 | begin
2142        IBError(ibxeNotSupported, [nil]);
2143      varByRef, varDispatch, varError, varUnknown, varVariant:
2144        IBError(ibxeNotPermitted, [nil]);
2145 +    else
2146 +      if VarIsFmtBCD(Value) then
2147 +        SetAsBCD(VarToBCD(Value))
2148 +      else
2149 +        IBError(ibxeNotSupported, [nil]);
2150    end;
2151   end;
2152  
2153 + procedure TSQLDataItem.SetAsNumeric(Value: Int64; aScale: integer);
2154 + begin
2155 +  CheckActive;
2156 +  Changing;
2157 +  if IsNullable then
2158 +    IsNull := False;
2159 +
2160 +  SQLType := SQL_INT64;
2161 +  Scale := aScale;
2162 +  DataLength := SizeOf(Int64);
2163 +  PInt64(SQLData)^ := Value;
2164 +  Changed;
2165 + end;
2166 +
2167 + procedure TSQLDataItem.SetAsBcd(aValue: tBCD);
2168 + var C: Currency;
2169 + begin
2170 +  CheckActive;
2171 +  Changing;
2172 +  if IsNullable then
2173 +    IsNull := False;
2174 +
2175 +
2176 +  with FFirebirdClientAPI do
2177 +  if aValue.Precision <= 16 then
2178 +  begin
2179 +    if not HasDecFloatSupport then
2180 +      IBError(ibxeDecFloatNotSupported,[]);
2181 +
2182 +    SQLType := SQL_DEC16;
2183 +    DataLength := 8;
2184 +    SQLDecFloatEncode(aValue,SQLType,SQLData);
2185 +  end
2186 +  else
2187 +  if aValue.Precision <= 34 then
2188 +  begin
2189 +    if not HasDecFloatSupport then
2190 +      IBError(ibxeDecFloatNotSupported,[]);
2191 +
2192 +    SQLType := SQL_DEC34;
2193 +    DataLength := 16;
2194 +    SQLDecFloatEncode(aValue,SQLType,SQLData);
2195 +  end
2196 +  else
2197 +  if aValue.Precision <= 38 then
2198 +  begin
2199 +    if not HasInt128Support then
2200 +      IBError(ibxeInt128NotSupported,[]);
2201 +
2202 +    SQLType := SQL_INT128;
2203 +    DataLength := 16;
2204 +    StrToInt128(scale,BcdToStr(aValue),SQLData);
2205 +  end
2206 +  else
2207 +    IBError(ibxeBCDOverflow,[BCDToStr(aValue)]);
2208 +
2209 +  Changed;
2210 + end;
2211 +
2212   procedure TSQLDataItem.SetAsBoolean(AValue: boolean);
2213   begin
2214    CheckActive;
# Line 1641 | Line 2239 | begin
2239      IBError(ibxeStatementNotPrepared, [nil]);
2240   end;
2241  
2242 < function TColumnMetaData.SQLData: PChar;
2242 > function TColumnMetaData.GetAttachment: IAttachment;
2243 > begin
2244 >  Result := GetStatement.GetAttachment;
2245 > end;
2246 >
2247 > function TColumnMetaData.SQLData: PByte;
2248   begin
2249    Result := FIBXSQLVAR.SQLData;
2250   end;
# Line 1658 | Line 2261 | end;
2261  
2262   constructor TColumnMetaData.Create(aOwner: IUnknown; aIBXSQLVAR: TSQLVarData);
2263   begin
2264 <  inherited Create;
2264 >  inherited Create(aIBXSQLVAR.GetStatement.GetAttachment.getFirebirdAPI as TFBClientAPI);
2265    FIBXSQLVAR := aIBXSQLVAR;
2266    FOwner := aOwner;
2267    FPrepareSeqNo := FIBXSQLVAR.Parent.PrepareSeqNo;
# Line 1694 | Line 2297 | begin
2297    result := FIBXSQLVAR.SQLSubtype;
2298   end;
2299  
2300 < function TColumnMetaData.getRelationName: string;
2300 > function TColumnMetaData.getRelationName: AnsiString;
2301   begin
2302    CheckActive;
2303     result :=  FIBXSQLVAR.RelationName;
2304   end;
2305  
2306 < function TColumnMetaData.getOwnerName: string;
2306 > function TColumnMetaData.getOwnerName: AnsiString;
2307   begin
2308    CheckActive;
2309    result :=  FIBXSQLVAR.OwnerName;
2310   end;
2311  
2312 < function TColumnMetaData.getSQLName: string;
2312 > function TColumnMetaData.getSQLName: AnsiString;
2313   begin
2314    CheckActive;
2315    result :=  FIBXSQLVAR.FieldName;
2316   end;
2317  
2318 < function TColumnMetaData.getAliasName: string;
2318 > function TColumnMetaData.getAliasName: AnsiString;
2319   begin
2320    CheckActive;
2321    result := FIBXSQLVAR.AliasName;
2322   end;
2323  
2324 < function TColumnMetaData.GetName: string;
2324 > function TColumnMetaData.GetName: AnsiString;
2325   begin
2326    CheckActive;
2327    Result := FIBXSQLVAR. Name;
# Line 1745 | Line 2348 | end;
2348   function TColumnMetaData.GetSize: cardinal;
2349   begin
2350    CheckActive;
2351 <  result := FIBXSQLVAR.DataLength;
2351 >  result := FIBXSQLVAR.GetSize;
2352 > end;
2353 >
2354 > function TColumnMetaData.GetCharSetWidth: integer;
2355 > begin
2356 >  CheckActive;
2357 >  result := FIBXSQLVAR.GetCharSetWidth;
2358   end;
2359  
2360   function TColumnMetaData.GetArrayMetaData: IArrayMetaData;
# Line 1760 | Line 2369 | begin
2369    result := FIBXSQLVAR.GetBlobMetaData;
2370   end;
2371  
2372 + function TColumnMetaData.GetStatement: IStatement;
2373 + begin
2374 +  Result := FIBXSQLVAR.GetStatement;
2375 + end;
2376 +
2377 + function TColumnMetaData.GetTransaction: ITransaction;
2378 + begin
2379 +  Result := GetStatement.GetTransaction;
2380 + end;
2381 +
2382   { TIBSQLData }
2383  
2384   procedure TIBSQLData.CheckActive;
# Line 1779 | Line 2398 | begin
2398      IBError(ibxeBOF,[nil]);
2399   end;
2400  
2401 + function TIBSQLData.GetTransaction: ITransaction;
2402 + begin
2403 +  if FTransaction = nil then
2404 +    Result := inherited GetTransaction
2405 +  else
2406 +    Result := FTransaction;
2407 + end;
2408 +
2409   function TIBSQLData.GetIsNull: Boolean;
2410   begin
2411    CheckActive;
# Line 1803 | Line 2430 | begin
2430    result := FIBXSQLVAR.GetAsBlob(AsQuad,BPB);
2431   end;
2432  
2433 < function TIBSQLData.GetAsString: String;
2433 > function TIBSQLData.GetAsString: AnsiString;
2434   begin
2435    CheckActive;
2436    Result := '';
# Line 1821 | Line 2448 | end;
2448  
2449   { TSQLParam }
2450  
2451 < procedure TSQLParam.InternalSetAsString(Value: String);
2451 > procedure TSQLParam.InternalSetAsString(Value: AnsiString);
2452 >
2453 > procedure DoSetString;
2454 > begin
2455 >  Changing;
2456 >  FIBXSQLVar.SetString(Transliterate(Value,GetCodePage));
2457 >  Changed;
2458 > end;
2459 >
2460   var b: IBlob;
2461 +    dt: TDateTime;
2462 +    timezone: AnsiString;
2463 +    Int64Value: Int64;
2464 +    BCDValue: TBCD;
2465 +    aScale: integer;
2466   begin
2467    CheckActive;
2468    if IsNullable then
2469      IsNull := False;
2470 <  case SQLTYPE of
2470 >  with FFirebirdClientAPI do
2471 >  case getColMetaData.SQLTYPE of
2472    SQL_BOOLEAN:
2473 <    if CompareText(Value,STrue) = 0 then
2473 >    if AnsiCompareText(Value,STrue) = 0 then
2474        AsBoolean := true
2475      else
2476 <    if CompareText(Value,SFalse) = 0 then
2476 >    if AnsiCompareText(Value,SFalse) = 0 then
2477        AsBoolean := false
2478      else
2479        IBError(ibxeInvalidDataConversion,[nil]);
2480  
2481    SQL_BLOB:
2482 +    if Length(Value) < GetAttachment.GetInlineBlobLimit then
2483 +      DoSetString
2484 +    else
2485      begin
2486        Changing;
2487        b := FIBXSQLVAR.CreateBlob;
# Line 1848 | Line 2492 | begin
2492  
2493    SQL_VARYING,
2494    SQL_TEXT:
2495 <    begin
1852 <      Changing;
1853 <      FIBXSQLVar.SetString(Transliterate(Value,GetCodePage));
1854 <      Changed;
1855 <    end;
2495 >    DoSetString;
2496  
2497 <    SQL_SHORT,
2498 <    SQL_LONG,
2499 <    SQL_INT64:
2500 <      SetAsInt64(StrToInt(Value));
2501 <
2502 <    SQL_D_FLOAT,
2503 <    SQL_DOUBLE,
1864 <    SQL_FLOAT:
1865 <      SetAsDouble(StrToFloat(Value));
2497 >  SQL_SHORT,
2498 >  SQL_LONG,
2499 >  SQL_INT64:
2500 >    if TryStrToNumeric(Value,Int64Value,aScale) then
2501 >      SetAsNumeric(Int64Value,aScale)
2502 >    else
2503 >      DoSetString;
2504  
2505 <    SQL_TIMESTAMP:
2506 <      SetAsDateTime(StrToDateTime(Value));
2505 >  SQL_DEC_FIXED,
2506 >  SQL_DEC16,
2507 >  SQL_DEC34,
2508 >  SQL_INT128:
2509 >    if TryStrToBCD(Value,BCDValue) then
2510 >      SetAsBCD(BCDValue)
2511 >    else
2512 >      DoSetString;
2513  
2514 <    SQL_TYPE_DATE:
2515 <      SetAsDate(StrToDateTime(Value));
2514 >  SQL_D_FLOAT,
2515 >  SQL_DOUBLE,
2516 >  SQL_FLOAT:
2517 >    if TryStrToNumeric(Value,Int64Value,aScale) then
2518 >      SetAsDouble(NumericToDouble(Int64Value,aScale))
2519 >    else
2520 >      DoSetString;
2521  
2522 <    SQL_TYPE_TIME:
2523 <      SetAsTime(StrToDateTime(Value));
2522 >  SQL_TIMESTAMP:
2523 >      if TryStrToDateTime(Value,dt) then
2524 >        SetAsDateTime(dt)
2525 >      else
2526 >        DoSetString;
2527  
2528 <    else
2529 <      IBError(ibxeInvalidDataConversion,[nil]);
2528 >  SQL_TYPE_DATE:
2529 >      if TryStrToDateTime(Value,dt) then
2530 >        SetAsDate(dt)
2531 >      else
2532 >        DoSetString;
2533 >
2534 >  SQL_TYPE_TIME:
2535 >      if TryStrToDateTime(Value,dt) then
2536 >        SetAsTime(dt)
2537 >      else
2538 >        DoSetString;
2539 >
2540 >  SQL_TIMESTAMP_TZ,
2541 >  SQL_TIMESTAMP_TZ_EX:
2542 >      if ParseDateTimeTZString(value,dt,timezone) then
2543 >        SetAsDateTime(dt,timezone)
2544 >      else
2545 >        DoSetString;
2546 >
2547 >  SQL_TIME_TZ,
2548 >  SQL_TIME_TZ_EX:
2549 >      if ParseDateTimeTZString(value,dt,timezone,true) then
2550 >        SetAsTime(dt,GetAttachment.GetTimeZoneServices.GetTimeTZDate,timezone)
2551 >      else
2552 >        DoSetString;
2553 >
2554 >  else
2555 >    IBError(ibxeInvalidDataConversion,[GetSQLTypeName(getColMetaData.SQLTYPE)]);
2556    end;
2557   end;
2558  
# Line 1912 | Line 2590 | begin
2590    IsNull := true;
2591   end;
2592  
2593 + function TSQLParam.getColMetadata: IParamMetaData;
2594 + begin
2595 +  Result := FIBXSQLVAR.getColMetadata;
2596 + end;
2597 +
2598   function TSQLParam.GetModified: boolean;
2599   begin
2600    CheckActive;
# Line 1925 | Line 2608 | begin
2608    Result := inherited GetAsPointer;
2609   end;
2610  
2611 < procedure TSQLParam.SetName(Value: string);
2611 > function TSQLParam.GetAsString: AnsiString;
2612 > var rs: RawByteString;
2613 > begin
2614 >  Result := '';
2615 >  if (SQLType = SQL_VARYING) and not IsNull then
2616 >  {SQLData points to start of string - default is to length word}
2617 >  begin
2618 >    CheckActive;
2619 >    SetString(rs,PAnsiChar(SQLData),DataLength);
2620 >    SetCodePage(rs,GetCodePage,false);
2621 >    Result := rs;
2622 >  end
2623 >  else
2624 >    Result := inherited GetAsString;
2625 > end;
2626 >
2627 > procedure TSQLParam.SetName(Value: AnsiString);
2628   begin
2629    CheckActive;
2630    FIBXSQLVAR.Name := Value;
# Line 2116 | Line 2815 | begin
2815    end;
2816   end;
2817  
2818 + procedure TSQLParam.SetAsTime(aValue: TDateTime; OnDate: TDateTime; aTimeZoneID: TFBTimeZoneID);
2819 + var i: integer;
2820 +    OldSQLVar: TSQLVarData;
2821 + begin
2822 +  if FIBXSQLVAR.UniqueName then
2823 +    inherited SetAsTime(AValue,OnDate, aTimeZoneID)
2824 +  else
2825 +  with FIBXSQLVAR.Parent do
2826 +  begin
2827 +    for i := 0 to Count - 1 do
2828 +      if Column[i].Name = Name then
2829 +      begin
2830 +        OldSQLVar := FIBXSQLVAR;
2831 +        FIBXSQLVAR := Column[i];
2832 +        try
2833 +          inherited SetAsTime(AValue,OnDate, aTimeZoneID);
2834 +        finally
2835 +          FIBXSQLVAR := OldSQLVar;
2836 +        end;
2837 +      end;
2838 +  end;
2839 + end;
2840 +
2841 + procedure TSQLParam.SetAsTime(aValue: TDateTime; OnDate: TDateTime; aTimeZone: AnsiString);
2842 + var i: integer;
2843 +    OldSQLVar: TSQLVarData;
2844 + begin
2845 +  if FIBXSQLVAR.UniqueName then
2846 +    inherited SetAsTime(AValue,OnDate,aTimeZone)
2847 +  else
2848 +  with FIBXSQLVAR.Parent do
2849 +  begin
2850 +    for i := 0 to Count - 1 do
2851 +      if Column[i].Name = Name then
2852 +      begin
2853 +        OldSQLVar := FIBXSQLVAR;
2854 +        FIBXSQLVAR := Column[i];
2855 +        try
2856 +          inherited SetAsTime(AValue,OnDate,aTimeZone);
2857 +        finally
2858 +          FIBXSQLVAR := OldSQLVar;
2859 +        end;
2860 +      end;
2861 +  end;
2862 + end;
2863 +
2864 + procedure TSQLParam.SetAsTime(aValue: TDateTime; aTimeZoneID: TFBTimeZoneID);
2865 + begin
2866 +  SetAsTime(aValue,GetTimeZoneServices.GetTimeTZDate,aTimeZoneID);
2867 + end;
2868 +
2869 + procedure TSQLParam.SetAsTime(aValue: TDateTime; aTimeZone: AnsiString);
2870 + begin
2871 +  SetAsTime(aValue,GetTimeZoneServices.GetTimeTZDate,aTimeZone);
2872 + end;
2873 +
2874   procedure TSQLParam.SetAsDateTime(AValue: TDateTime);
2875   var i: integer;
2876      OldSQLVar: TSQLVarData;
# Line 2139 | Line 2894 | begin
2894    end;
2895   end;
2896  
2897 + procedure TSQLParam.SetAsDateTime(aValue: TDateTime; aTimeZoneID: TFBTimeZoneID
2898 +  );
2899 + var i: integer;
2900 +    OldSQLVar: TSQLVarData;
2901 + begin
2902 +  if FIBXSQLVAR.UniqueName then
2903 +    inherited SetAsDateTime(AValue,aTimeZoneID)
2904 +  else
2905 +  with FIBXSQLVAR.Parent do
2906 +  begin
2907 +    for i := 0 to Count - 1 do
2908 +      if Column[i].Name = Name then
2909 +      begin
2910 +        OldSQLVar := FIBXSQLVAR;
2911 +        FIBXSQLVAR := Column[i];
2912 +        try
2913 +          inherited SetAsDateTime(AValue,aTimeZoneID);
2914 +        finally
2915 +          FIBXSQLVAR := OldSQLVar;
2916 +        end;
2917 +      end;
2918 +  end;
2919 + end;
2920 +
2921 + procedure TSQLParam.SetAsDateTime(aValue: TDateTime; aTimeZone: AnsiString);
2922 + var i: integer;
2923 +    OldSQLVar: TSQLVarData;
2924 + begin
2925 +  if FIBXSQLVAR.UniqueName then
2926 +    inherited SetAsDateTime(AValue,aTimeZone)
2927 +  else
2928 +  with FIBXSQLVAR.Parent do
2929 +  begin
2930 +    for i := 0 to Count - 1 do
2931 +      if Column[i].Name = Name then
2932 +      begin
2933 +        OldSQLVar := FIBXSQLVAR;
2934 +        FIBXSQLVAR := Column[i];
2935 +        try
2936 +          inherited SetAsDateTime(AValue,aTimeZone);
2937 +        finally
2938 +          FIBXSQLVAR := OldSQLVar;
2939 +        end;
2940 +      end;
2941 +  end;
2942 + end;
2943 +
2944   procedure TSQLParam.SetAsDouble(AValue: Double);
2945   var i: integer;
2946      OldSQLVar: TSQLVarData;
# Line 2231 | Line 3033 | begin
3033    end;
3034   end;
3035  
3036 < procedure TSQLParam.SetAsString(AValue: String);
3036 > procedure TSQLParam.SetAsString(AValue: AnsiString);
3037   var i: integer;
3038      OldSQLVar: TSQLVarData;
3039   begin
# Line 2319 | Line 3121 | begin
3121    FIBXSQLVAR.SetCharSetID(aValue);
3122   end;
3123  
3124 + procedure TSQLParam.SetAsBcd(aValue: tBCD);
3125 + var i: integer;
3126 +    OldSQLVar: TSQLVarData;
3127 + begin
3128 +  if FIBXSQLVAR.UniqueName then
3129 +    inherited SetAsBcd(AValue)
3130 +  else
3131 +  with FIBXSQLVAR.Parent do
3132 +  begin
3133 +    for i := 0 to Count - 1 do
3134 +      if Column[i].Name = Name then
3135 +      begin
3136 +        OldSQLVar := FIBXSQLVAR;
3137 +        FIBXSQLVAR := Column[i];
3138 +        try
3139 +          inherited SetAsBcd(AValue);
3140 +        finally
3141 +          FIBXSQLVAR := OldSQLVar;
3142 +        end;
3143 +      end;
3144 +  end;
3145 + end;
3146 +
3147   { TMetaData }
3148  
3149   procedure TMetaData.CheckActive;
# Line 2344 | Line 3169 | begin
3169    inherited Destroy;
3170   end;
3171  
3172 < function TMetaData.GetUniqueRelationName: string;
3172 > function TMetaData.GetUniqueRelationName: AnsiString;
3173   begin
3174    CheckActive;
3175    Result := FMetaData.UniqueRelationName;
# Line 2372 | Line 3197 | begin
3197    end;
3198   end;
3199  
3200 < function TMetaData.ByName(Idx: String): IColumnMetaData;
3200 > function TMetaData.ByName(Idx: AnsiString): IColumnMetaData;
3201   var aIBXSQLVAR: TSQLVarData;
3202   begin
3203    CheckActive;
# Line 2432 | Line 3257 | begin
3257    end;
3258   end;
3259  
3260 < function TSQLParams.ByName(Idx: String): ISQLParam;
3260 > function TSQLParams.ByName(Idx: AnsiString): ISQLParam;
3261   var aIBXSQLVAR: TSQLVarData;
3262   begin
3263    CheckActive;
# Line 2457 | Line 3282 | begin
3282      end;
3283   end;
3284  
3285 + function TSQLParams.GetHasCaseSensitiveParams: Boolean;
3286 + begin
3287 +  Result := FSQLParams.CaseSensitiveParams;
3288 + end;
3289 +
3290   { TResults }
3291  
3292   procedure TResults.CheckActive;
# Line 2469 | Line 3299 | begin
3299    if not FResults.CheckStatementStatus(ssPrepared)  then
3300      IBError(ibxeStatementNotPrepared, [nil]);
3301  
3302 <  with GetTransaction as TFBTransaction do
3302 >  with GetTransaction do
3303    if not InTransaction or (FResults.TransactionSeqNo <> FTransactionSeqNo) then
3304      IBError(ibxeInterfaceOutofDate,[nil]);
3305   end;
3306  
3307   function TResults.GetISQLData(aIBXSQLVAR: TSQLVarData): ISQLData;
3308 + var col: TIBSQLData;
3309   begin
3310    if (aIBXSQLVAR.Index < 0) or (aIBXSQLVAR.Index >= getCount) then
3311      IBError(ibxeInvalidColumnIndex,[nil]);
3312  
3313    if not HasInterface(aIBXSQLVAR.Index) then
3314      AddInterface(aIBXSQLVAR.Index, TIBSQLData.Create(self,aIBXSQLVAR));
3315 <  Result := TIBSQLData(GetInterface(aIBXSQLVAR.Index));
3315 >  col := TIBSQLData(GetInterface(aIBXSQLVAR.Index));
3316 >  col.FTransaction := GetTransaction;
3317 >  Result := col;
3318   end;
3319  
3320   constructor TResults.Create(aResults: TSQLDataArea);
# Line 2500 | Line 3333 | begin
3333    Result := FResults.Count;
3334   end;
3335  
3336 < function TResults.ByName(Idx: String): ISQLData;
3336 > function TResults.ByName(Idx: AnsiString): ISQLData;
3337   var col: TSQLVarData;
3338   begin
3339    Result := nil;
# Line 2532 | Line 3365 | begin
3365   end;
3366  
3367   procedure TResults.GetData(index: integer; var IsNull: boolean; var len: short;
3368 <  var data: PChar);
3368 >  var data: PByte);
3369   begin
3370    CheckActive;
3371    FResults.GetData(index,IsNull, len,data);
3372   end;
3373  
3374 + function TResults.GetStatement: IStatement;
3375 + begin
3376 +  Result := FStatement;
3377 + end;
3378 +
3379   function TResults.GetTransaction: ITransaction;
3380   begin
3381    Result := FStatement.GetTransaction;
# Line 2548 | Line 3386 | begin
3386    RetainInterfaces := aValue;
3387   end;
3388  
2551
3389   end.
3390  

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines