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

Comparing ibx/trunk/fbintf/client/FBSQLData.pas (file contents):
Revision 45 by tony, Tue Dec 6 10:33:46 2016 UTC vs.
Revision 350 by tony, Wed Oct 20 14:58:56 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 Transliterate(s: string; CodePage: TSystemCodePage): RawByteString;
148 >     function getCharSetID: cardinal; virtual; abstract;
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 174 | 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 191 | 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 204 | 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 226 | 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 264 | 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 295 | Line 356 | type
356      FIBXSQLVAR: TSQLVarData;
357      FOwner: IUnknown;         {Keep reference to ensure Metadata/statement not discarded}
358      FPrepareSeqNo: integer;
298    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 307 | Line 368 | type
368      constructor Create(aOwner: IUnknown; aIBXSQLVAR: TSQLVarData);
369      destructor Destroy; override;
370      function GetSQLDialect: integer; override;
310    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;
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 371 | 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 400 | 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 422 | 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 442 | 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 471 | 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 502 | Line 660 | begin
660      Column[i].Initialize;
661   end;
662  
663 < procedure TSQLDataArea.PreprocessSQL(sSQL: string; GenerateParamNames: boolean;
664 <  var sProcessedSQL: string);
507 < var
508 <  cCurChar, cNextChar, cQuoteChar: Char;
509 <  sParamName: String;
510 <  j, i, iLenSQL, iSQLPos: Integer;
511 <  iCurState {$ifdef ALLOWDIALECT3PARAMNAMES}, iCurParamState {$endif}: Integer;
512 <  iParamSuffix: Integer;
513 <  slNames: TStrings;
514 <  StrBuffer: PChar;
515 <  found: boolean;
516 <
517 < const
518 <  DefaultState = 0;
519 <  CommentState = 1;
520 <  QuoteState = 2;
521 <  ParamState = 3;
522 < {$ifdef ALLOWDIALECT3PARAMNAMES}
523 <  ParamDefaultState = 0;
524 <  ParamQuoteState = 1;
525 <  {$endif}
526 <
527 <  procedure AddToProcessedSQL(cChar: Char);
528 <  begin
529 <    StrBuffer[iSQLPos] := cChar;
530 <    Inc(iSQLPos);
531 <  end;
663 > procedure TSQLDataArea.PreprocessSQL(sSQL: AnsiString; GenerateParamNames: boolean;
664 >  var sProcessedSQL: AnsiString);
665  
666 < begin
534 <  if not IsInputDataArea then
535 <    IBError(ibxeNotPermitted,[nil]);
666 > var slNames: TStrings;
667  
668 <  sParamName := '';
669 <  iLenSQL := Length(sSQL);
670 <  GetMem(StrBuffer,iLenSQL + 1);
671 <  slNames := TStringList.Create;
672 <  try
542 <    { Do some initializations of variables }
543 <    iParamSuffix := 0;
544 <    cQuoteChar := '''';
545 <    i := 1;
546 <    iSQLPos := 0;
547 <    iCurState := DefaultState;
548 <    {$ifdef ALLOWDIALECT3PARAMNAMES}
549 <    iCurParamState := ParamDefaultState;
550 <    {$endif}
551 <    { Now, traverse through the SQL string, character by character,
552 <     picking out the parameters and formatting correctly for InterBase }
553 <    while (i <= iLenSQL) do begin
554 <      { Get the current token and a look-ahead }
555 <      cCurChar := sSQL[i];
556 <      if i = iLenSQL then
557 <        cNextChar := #0
558 <      else
559 <        cNextChar := sSQL[i + 1];
560 <      { Now act based on the current state }
561 <      case iCurState of
562 <        DefaultState: begin
563 <          case cCurChar of
564 <            '''', '"': begin
565 <              cQuoteChar := cCurChar;
566 <              iCurState := QuoteState;
567 <            end;
568 <            '?', ':': begin
569 <              iCurState := ParamState;
570 <              AddToProcessedSQL('?');
571 <            end;
572 <            '/': if (cNextChar = '*') then begin
573 <              AddToProcessedSQL(cCurChar);
574 <              Inc(i);
575 <              iCurState := CommentState;
576 <            end;
577 <          end;
578 <        end;
579 <        CommentState: begin
580 <          if (cNextChar = #0) then
581 <            IBError(ibxeSQLParseError, [SEOFInComment])
582 <          else if (cCurChar = '*') then begin
583 <            if (cNextChar = '/') then
584 <              iCurState := DefaultState;
585 <          end;
586 <        end;
587 <        QuoteState: begin
588 <          if cNextChar = #0 then
589 <            IBError(ibxeSQLParseError, [SEOFInString])
590 <          else if (cCurChar = cQuoteChar) then begin
591 <            if (cNextChar = cQuoteChar) then begin
592 <              AddToProcessedSQL(cCurChar);
593 <              Inc(i);
594 <            end else
595 <              iCurState := DefaultState;
596 <          end;
597 <        end;
598 <        ParamState:
599 <        begin
600 <          { collect the name of the parameter }
601 <          {$ifdef ALLOWDIALECT3PARAMNAMES}
602 <          if iCurParamState = ParamDefaultState then
603 <          begin
604 <            if cCurChar = '"' then
605 <              iCurParamState := ParamQuoteState
606 <            else
607 <            {$endif}
608 <            if (cCurChar in ['A'..'Z', 'a'..'z', '0'..'9', '_', '$']) then
609 <                sParamName := sParamName + cCurChar
610 <            else if GenerateParamNames then
611 <            begin
612 <              sParamName := 'IBXParam' + IntToStr(iParamSuffix); {do not localize}
613 <              Inc(iParamSuffix);
614 <              iCurState := DefaultState;
615 <              slNames.AddObject(sParamName,self); //Note local convention
616 <                                                  //add pointer to self to mark entry
617 <              sParamName := '';
618 <            end
619 <            else
620 <              IBError(ibxeSQLParseError, [SParamNameExpected]);
621 <          {$ifdef ALLOWDIALECT3PARAMNAMES}
622 <          end
623 <          else begin
624 <            { determine if Quoted parameter name is finished }
625 <            if cCurChar = '"' then
626 <            begin
627 <              Inc(i);
628 <              slNames.Add(sParamName);
629 <              SParamName := '';
630 <              iCurParamState := ParamDefaultState;
631 <              iCurState := DefaultState;
632 <            end
633 <            else
634 <              sParamName := sParamName + cCurChar
635 <          end;
636 <          {$endif}
637 <          { determine if the unquoted parameter name is finished }
638 <          if {$ifdef ALLOWDIALECT3PARAMNAMES}(iCurParamState <> ParamQuoteState) and {$endif}
639 <            (iCurState <> DefaultState) then
640 <          begin
641 <            if not (cNextChar in ['A'..'Z', 'a'..'z',
642 <                                  '0'..'9', '_', '$']) then begin
643 <              Inc(i);
644 <              iCurState := DefaultState;
645 <              slNames.Add(sParamName);
646 <              sParamName := '';
647 <            end;
648 <          end;
649 <        end;
650 <      end;
651 <      if (iCurState <> ParamState) and (i <= iLenSQL) then
652 <        AddToProcessedSQL(sSQL[i]);
653 <      Inc(i);
654 <    end;
655 <    AddToProcessedSQL(#0);
656 <    sProcessedSQL := strpas(StrBuffer);
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 674 | 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;
679    FreeMem(StrBuffer);
705    end;
706   end;
707  
# Line 685 | 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 705 | 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 724 | 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;
730 <  {$ifdef UseCaseInSensitiveParamName}
731 <  if Parent.IsInputDataArea then
754 >  if not Parent.IsInputDataArea or not Parent.CaseSensitiveParams then
755      FName := AnsiUpperCase(AValue)
756    else
734  {$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 743 | 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 766 | 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 783 | 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 871 | 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 890 | 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 905 | 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 958 | 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 965 | 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 975 | 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 1003 | 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 1019 | 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 1026 | 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 1068 | 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 1098 | 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 1154 | 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 1190 | 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 1238 | Line 1520 | begin
1520    end;
1521   end;
1522  
1523 + {Copied from LazUTF8}
1524 +
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 TSQLDataItem.GetAsString: String;
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 1261 | 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 <        Result := Trim(rs);
1627 >        Result := rs;
1628        end;
1629 +
1630        SQL_TYPE_DATE:
1631 <        case GetSQLDialect of
1275 <          1 : result := DateTimeToStr(AsDateTime);
1276 <          3 : result := DateToStr(AsDateTime);
1277 <        end;
1278 <      SQL_TYPE_TIME :
1279 <        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 1296 | 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 1307 | 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 1327 | 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 1345 | 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 1355 | 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 1366 | 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 1418 | 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 1438 | 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 1451 | Line 1946 | begin
1946  
1947    Changing;
1948    SQLType := SQL_TIMESTAMP;
1949 <  DataLength := SizeOf(TISC_QUAD);
1950 <  with FirebirdClientAPI do
1949 >  DataLength := SizeOf(ISC_TIME) + sizeof(ISC_DATE);
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 1542 | 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 1552 | 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 1574 | 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 1607 | 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 1624 | 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 1660 | 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 1711 | 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 1726 | 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 1745 | 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 1769 | 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 1777 | Line 2403 | begin
2403    if not IsNull then
2404    case SQLType of
2405      SQL_ARRAY:
2406 <      result := '(Array)'; {do not localize}
2406 >      result := SArray;
2407      SQL_BLOB:
2408 <      Result := Trim(FIBXSQLVAR.GetAsBlob(AsQuad,nil).GetAsString);
2408 >      Result := FIBXSQLVAR.GetAsBlob(AsQuad,nil).GetAsString;
2409      else
2410        Result := inherited GetAsString;
2411    end;
# Line 1787 | 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 > function TryStrToNumeric(S: Ansistring; out Value: int64; out scale: integer): boolean;
2426 > var i: integer;
2427 >    ds: integer;
2428 > begin
2429 >  Result := false;
2430 >  ds := 0;
2431 >  S := Trim(S);
2432 >  {$IF declared(DefaultFormatSettings)}
2433 >  with DefaultFormatSettings do
2434 >  {$ELSE}
2435 >  {$IF declared(FormatSettings)}
2436 >  with FormatSettings do
2437 >  {$IFEND}
2438 >  {$IFEND}
2439 >  begin
2440 >    {ThousandSeparator not allowed as by Delphi specs}
2441 >    if (ThousandSeparator <> DecimalSeparator) and
2442 >       (Pos(ThousandSeparator, S) <> 0) then
2443 >        Exit;
2444 >
2445 >    for i := length(S) downto 1 do
2446 >    begin
2447 >      if S[i] = AnsiChar(DecimalSeparator) then
2448 >      begin
2449 >          if ds <> 0 then Exit; {only one allowed}
2450 >          ds := i-1;
2451 >          system.Delete(S,i,1);
2452 >      end
2453 >      else
2454 >      if (i > 1) and (S[i] in ['+','-']) then
2455 >        Exit
2456 >      else
2457 >      if not (S[i] in ['0'..'9']) then
2458 >          Exit; {bad character}
2459 >
2460 >    end;
2461 >    if ds = 0 then
2462 >      scale := 0
2463 >    else
2464 >      scale := ds - Length(S);
2465 >    Result := TryStrToInt64(S,Value);
2466 >  end;
2467 > end;
2468 >
2469   var b: IBlob;
2470 +    dt: TDateTime;
2471 +    timezone: AnsiString;
2472 +    {$ifdef FPC_HAS_TYPE_EXTENDED}
2473 +    FloatValue: Extended;
2474 +    {$else}
2475 +    FloatValue: Double;
2476 +    {$endif}
2477 +    Int64Value: Int64;
2478 +    BCDValue: TBCD;
2479 +    aScale: integer;
2480   begin
2481    CheckActive;
2482    if IsNullable then
2483      IsNull := False;
2484 <  case SQLTYPE of
2484 >  with FFirebirdClientAPI do
2485 >  case getColMetaData.SQLTYPE of
2486    SQL_BOOLEAN:
2487 <    if CompareText(Value,STrue) = 0 then
2487 >    if AnsiCompareText(Value,STrue) = 0 then
2488        AsBoolean := true
2489      else
2490 <    if CompareText(Value,SFalse) = 0 then
2490 >    if AnsiCompareText(Value,SFalse) = 0 then
2491        AsBoolean := false
2492      else
2493        IBError(ibxeInvalidDataConversion,[nil]);
2494  
2495    SQL_BLOB:
2496 +    if Length(Value) < GetAttachment.GetInlineBlobLimit then
2497 +      DoSetString
2498 +    else
2499      begin
2500        Changing;
2501        b := FIBXSQLVAR.CreateBlob;
# Line 1814 | Line 2506 | begin
2506  
2507    SQL_VARYING,
2508    SQL_TEXT:
2509 +    DoSetString;
2510 +
2511 +  SQL_SHORT,
2512 +  SQL_LONG,
2513 +  SQL_INT64:
2514 +    if TryStrToNumeric(Value,Int64Value,aScale) then
2515      begin
2516 <      Changing;
2517 <      FIBXSQLVar.SetString(Transliterate(Value,GetCodePage));
2518 <      Changed;
2519 <    end;
2516 >      if aScale = 0 then
2517 >        SetAsInt64(Int64Value)
2518 >      else
2519 >        SetAsNumeric(Int64Value,aScale);
2520 >    end
2521 >    else
2522 >    if TryStrToFloat(Value,FloatValue) then
2523 >      SetAsDouble(FloatValue)
2524 >    else
2525 >      DoSetString;
2526  
2527 <    SQL_SHORT,
2528 <    SQL_LONG,
2529 <    SQL_INT64:
2530 <      SetAsInt64(StrToInt(Value));
2531 <
2532 <    SQL_D_FLOAT,
2533 <    SQL_DOUBLE,
2534 <    SQL_FLOAT:
1831 <      SetAsDouble(StrToFloat(Value));
2527 >  SQL_DEC_FIXED,
2528 >  SQL_DEC16,
2529 >  SQL_DEC34,
2530 >  SQL_INT128:
2531 >    if TryStrToBCD(Value,BCDValue) then
2532 >      SetAsBCD(BCDValue)
2533 >    else
2534 >      DoSetString;
2535  
2536 <    SQL_TIMESTAMP:
2537 <      SetAsDateTime(StrToDateTime(Value));
2536 >  SQL_D_FLOAT,
2537 >  SQL_DOUBLE,
2538 >  SQL_FLOAT:
2539 >    if TryStrToFloat(Value,FloatValue) then
2540 >      SetAsDouble(FloatValue)
2541 >    else
2542 >      DoSetString;
2543  
2544 <    SQL_TYPE_DATE:
2545 <      SetAsDate(StrToDateTime(Value));
2544 >  SQL_TIMESTAMP:
2545 >      if TryStrToDateTime(Value,dt) then
2546 >        SetAsDateTime(dt)
2547 >      else
2548 >        DoSetString;
2549  
2550 <    SQL_TYPE_TIME:
2551 <      SetAsTime(StrToDateTime(Value));
2550 >  SQL_TYPE_DATE:
2551 >      if TryStrToDateTime(Value,dt) then
2552 >        SetAsDate(dt)
2553 >      else
2554 >        DoSetString;
2555  
2556 <    else
2557 <      IBError(ibxeInvalidDataConversion,[nil]);
2556 >  SQL_TYPE_TIME:
2557 >      if TryStrToDateTime(Value,dt) then
2558 >        SetAsTime(dt)
2559 >      else
2560 >        DoSetString;
2561 >
2562 >  SQL_TIMESTAMP_TZ,
2563 >  SQL_TIMESTAMP_TZ_EX:
2564 >      if ParseDateTimeTZString(value,dt,timezone) then
2565 >        SetAsDateTime(dt,timezone)
2566 >      else
2567 >        DoSetString;
2568 >
2569 >  SQL_TIME_TZ,
2570 >  SQL_TIME_TZ_EX:
2571 >      if ParseDateTimeTZString(value,dt,timezone,true) then
2572 >        SetAsTime(dt,GetAttachment.GetTimeZoneServices.GetTimeTZDate,timezone)
2573 >      else
2574 >        DoSetString;
2575 >
2576 >  else
2577 >    IBError(ibxeInvalidDataConversion,[GetSQLTypeName(getColMetaData.SQLTYPE)]);
2578    end;
2579   end;
2580  
# Line 1878 | Line 2612 | begin
2612    IsNull := true;
2613   end;
2614  
2615 + function TSQLParam.getColMetadata: IParamMetaData;
2616 + begin
2617 +  Result := FIBXSQLVAR.getColMetadata;
2618 + end;
2619 +
2620   function TSQLParam.GetModified: boolean;
2621   begin
2622    CheckActive;
# Line 1891 | Line 2630 | begin
2630    Result := inherited GetAsPointer;
2631   end;
2632  
2633 < procedure TSQLParam.SetName(Value: string);
2633 > function TSQLParam.GetAsString: AnsiString;
2634 > var rs: RawByteString;
2635 > begin
2636 >  Result := '';
2637 >  if (SQLType = SQL_VARYING) and not IsNull then
2638 >  {SQLData points to start of string - default is to length word}
2639 >  begin
2640 >    CheckActive;
2641 >    SetString(rs,PAnsiChar(SQLData),DataLength);
2642 >    SetCodePage(rs,GetCodePage,false);
2643 >    Result := rs;
2644 >  end
2645 >  else
2646 >    Result := inherited GetAsString;
2647 > end;
2648 >
2649 > procedure TSQLParam.SetName(Value: AnsiString);
2650   begin
2651    CheckActive;
2652    FIBXSQLVAR.Name := Value;
# Line 2082 | Line 2837 | begin
2837    end;
2838   end;
2839  
2840 + procedure TSQLParam.SetAsTime(aValue: TDateTime; OnDate: TDateTime; aTimeZoneID: TFBTimeZoneID);
2841 + var i: integer;
2842 +    OldSQLVar: TSQLVarData;
2843 + begin
2844 +  if FIBXSQLVAR.UniqueName then
2845 +    inherited SetAsTime(AValue,OnDate, aTimeZoneID)
2846 +  else
2847 +  with FIBXSQLVAR.Parent do
2848 +  begin
2849 +    for i := 0 to Count - 1 do
2850 +      if Column[i].Name = Name then
2851 +      begin
2852 +        OldSQLVar := FIBXSQLVAR;
2853 +        FIBXSQLVAR := Column[i];
2854 +        try
2855 +          inherited SetAsTime(AValue,OnDate, aTimeZoneID);
2856 +        finally
2857 +          FIBXSQLVAR := OldSQLVar;
2858 +        end;
2859 +      end;
2860 +  end;
2861 + end;
2862 +
2863 + procedure TSQLParam.SetAsTime(aValue: TDateTime; OnDate: TDateTime; aTimeZone: AnsiString);
2864 + var i: integer;
2865 +    OldSQLVar: TSQLVarData;
2866 + begin
2867 +  if FIBXSQLVAR.UniqueName then
2868 +    inherited SetAsTime(AValue,OnDate,aTimeZone)
2869 +  else
2870 +  with FIBXSQLVAR.Parent do
2871 +  begin
2872 +    for i := 0 to Count - 1 do
2873 +      if Column[i].Name = Name then
2874 +      begin
2875 +        OldSQLVar := FIBXSQLVAR;
2876 +        FIBXSQLVAR := Column[i];
2877 +        try
2878 +          inherited SetAsTime(AValue,OnDate,aTimeZone);
2879 +        finally
2880 +          FIBXSQLVAR := OldSQLVar;
2881 +        end;
2882 +      end;
2883 +  end;
2884 + end;
2885 +
2886 + procedure TSQLParam.SetAsTime(aValue: TDateTime; aTimeZoneID: TFBTimeZoneID);
2887 + begin
2888 +  SetAsTime(aValue,GetTimeZoneServices.GetTimeTZDate,aTimeZoneID);
2889 + end;
2890 +
2891 + procedure TSQLParam.SetAsTime(aValue: TDateTime; aTimeZone: AnsiString);
2892 + begin
2893 +  SetAsTime(aValue,GetTimeZoneServices.GetTimeTZDate,aTimeZone);
2894 + end;
2895 +
2896   procedure TSQLParam.SetAsDateTime(AValue: TDateTime);
2897   var i: integer;
2898      OldSQLVar: TSQLVarData;
# Line 2105 | Line 2916 | begin
2916    end;
2917   end;
2918  
2919 + procedure TSQLParam.SetAsDateTime(aValue: TDateTime; aTimeZoneID: TFBTimeZoneID
2920 +  );
2921 + var i: integer;
2922 +    OldSQLVar: TSQLVarData;
2923 + begin
2924 +  if FIBXSQLVAR.UniqueName then
2925 +    inherited SetAsDateTime(AValue,aTimeZoneID)
2926 +  else
2927 +  with FIBXSQLVAR.Parent do
2928 +  begin
2929 +    for i := 0 to Count - 1 do
2930 +      if Column[i].Name = Name then
2931 +      begin
2932 +        OldSQLVar := FIBXSQLVAR;
2933 +        FIBXSQLVAR := Column[i];
2934 +        try
2935 +          inherited SetAsDateTime(AValue,aTimeZoneID);
2936 +        finally
2937 +          FIBXSQLVAR := OldSQLVar;
2938 +        end;
2939 +      end;
2940 +  end;
2941 + end;
2942 +
2943 + procedure TSQLParam.SetAsDateTime(aValue: TDateTime; aTimeZone: AnsiString);
2944 + var i: integer;
2945 +    OldSQLVar: TSQLVarData;
2946 + begin
2947 +  if FIBXSQLVAR.UniqueName then
2948 +    inherited SetAsDateTime(AValue,aTimeZone)
2949 +  else
2950 +  with FIBXSQLVAR.Parent do
2951 +  begin
2952 +    for i := 0 to Count - 1 do
2953 +      if Column[i].Name = Name then
2954 +      begin
2955 +        OldSQLVar := FIBXSQLVAR;
2956 +        FIBXSQLVAR := Column[i];
2957 +        try
2958 +          inherited SetAsDateTime(AValue,aTimeZone);
2959 +        finally
2960 +          FIBXSQLVAR := OldSQLVar;
2961 +        end;
2962 +      end;
2963 +  end;
2964 + end;
2965 +
2966   procedure TSQLParam.SetAsDouble(AValue: Double);
2967   var i: integer;
2968      OldSQLVar: TSQLVarData;
# Line 2197 | Line 3055 | begin
3055    end;
3056   end;
3057  
3058 < procedure TSQLParam.SetAsString(AValue: String);
3058 > procedure TSQLParam.SetAsString(AValue: AnsiString);
3059   var i: integer;
3060      OldSQLVar: TSQLVarData;
3061   begin
# Line 2285 | Line 3143 | begin
3143    FIBXSQLVAR.SetCharSetID(aValue);
3144   end;
3145  
3146 + procedure TSQLParam.SetAsBcd(aValue: tBCD);
3147 + var i: integer;
3148 +    OldSQLVar: TSQLVarData;
3149 + begin
3150 +  if FIBXSQLVAR.UniqueName then
3151 +    inherited SetAsBcd(AValue)
3152 +  else
3153 +  with FIBXSQLVAR.Parent do
3154 +  begin
3155 +    for i := 0 to Count - 1 do
3156 +      if Column[i].Name = Name then
3157 +      begin
3158 +        OldSQLVar := FIBXSQLVAR;
3159 +        FIBXSQLVAR := Column[i];
3160 +        try
3161 +          inherited SetAsBcd(AValue);
3162 +        finally
3163 +          FIBXSQLVAR := OldSQLVar;
3164 +        end;
3165 +      end;
3166 +  end;
3167 + end;
3168 +
3169   { TMetaData }
3170  
3171   procedure TMetaData.CheckActive;
# Line 2310 | Line 3191 | begin
3191    inherited Destroy;
3192   end;
3193  
3194 < function TMetaData.GetUniqueRelationName: string;
3194 > function TMetaData.GetUniqueRelationName: AnsiString;
3195   begin
3196    CheckActive;
3197    Result := FMetaData.UniqueRelationName;
# Line 2338 | Line 3219 | begin
3219    end;
3220   end;
3221  
3222 < function TMetaData.ByName(Idx: String): IColumnMetaData;
3222 > function TMetaData.ByName(Idx: AnsiString): IColumnMetaData;
3223   var aIBXSQLVAR: TSQLVarData;
3224   begin
3225    CheckActive;
# Line 2398 | Line 3279 | begin
3279    end;
3280   end;
3281  
3282 < function TSQLParams.ByName(Idx: String): ISQLParam;
3282 > function TSQLParams.ByName(Idx: AnsiString): ISQLParam;
3283   var aIBXSQLVAR: TSQLVarData;
3284   begin
3285    CheckActive;
# Line 2423 | Line 3304 | begin
3304      end;
3305   end;
3306  
3307 + function TSQLParams.GetHasCaseSensitiveParams: Boolean;
3308 + begin
3309 +  Result := FSQLParams.CaseSensitiveParams;
3310 + end;
3311 +
3312   { TResults }
3313  
3314   procedure TResults.CheckActive;
# Line 2435 | Line 3321 | begin
3321    if not FResults.CheckStatementStatus(ssPrepared)  then
3322      IBError(ibxeStatementNotPrepared, [nil]);
3323  
3324 <  with GetTransaction as TFBTransaction do
3324 >  with GetTransaction do
3325    if not InTransaction or (FResults.TransactionSeqNo <> FTransactionSeqNo) then
3326      IBError(ibxeInterfaceOutofDate,[nil]);
3327   end;
3328  
3329   function TResults.GetISQLData(aIBXSQLVAR: TSQLVarData): ISQLData;
3330 + var col: TIBSQLData;
3331   begin
3332    if (aIBXSQLVAR.Index < 0) or (aIBXSQLVAR.Index >= getCount) then
3333      IBError(ibxeInvalidColumnIndex,[nil]);
3334  
3335    if not HasInterface(aIBXSQLVAR.Index) then
3336      AddInterface(aIBXSQLVAR.Index, TIBSQLData.Create(self,aIBXSQLVAR));
3337 <  Result := TIBSQLData(GetInterface(aIBXSQLVAR.Index));
3337 >  col := TIBSQLData(GetInterface(aIBXSQLVAR.Index));
3338 >  col.FTransaction := GetTransaction;
3339 >  Result := col;
3340   end;
3341  
3342   constructor TResults.Create(aResults: TSQLDataArea);
# Line 2466 | Line 3355 | begin
3355    Result := FResults.Count;
3356   end;
3357  
3358 < function TResults.ByName(Idx: String): ISQLData;
3358 > function TResults.ByName(Idx: AnsiString): ISQLData;
3359   var col: TSQLVarData;
3360   begin
3361    Result := nil;
# Line 2498 | Line 3387 | begin
3387   end;
3388  
3389   procedure TResults.GetData(index: integer; var IsNull: boolean; var len: short;
3390 <  var data: PChar);
3390 >  var data: PByte);
3391   begin
3392    CheckActive;
3393    FResults.GetData(index,IsNull, len,data);
3394   end;
3395  
3396 + function TResults.GetStatement: IStatement;
3397 + begin
3398 +  Result := FStatement;
3399 + end;
3400 +
3401   function TResults.GetTransaction: ITransaction;
3402   begin
3403    Result := FStatement.GetTransaction;
# Line 2514 | Line 3408 | begin
3408    RetainInterfaces := aValue;
3409   end;
3410  
2517
3411   end.
3412  

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines