ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/public/ibx/trunk/fbintf/client/FBSQLData.pas
Revision: 350
Committed: Wed Oct 20 14:58:56 2021 UTC (3 years, 1 month ago) by tony
Content type: text/x-pascal
File size: 91319 byte(s)
Log Message:
Fixed Merged

File Contents

# User Rev Content
1 tony 45 (*
2     * Firebird Interface (fbintf). The fbintf components provide a set of
3     * Pascal language bindings for the Firebird API. Although predominantly
4     * a new development they include source code taken from IBX and may be
5     * considered a derived product. This software thus also includes the copyright
6     * notice and license conditions from IBX.
7     *
8     * Except for those parts dervied from IBX, contents of this file are subject
9     * to the Initial Developer's Public License Version 1.0 (the "License"); you
10     * may not use this file except in compliance with the License. You may obtain a
11     * copy of the License here:
12     *
13     * http://www.firebirdsql.org/index.php?op=doc&id=idpl
14     *
15     * Software distributed under the License is distributed on an "AS
16     * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
17     * implied. See the License for the specific language governing rights
18     * and limitations under the License.
19     *
20     * The Initial Developer of the Original Code is Tony Whyman.
21     *
22     * The Original Code is (C) 2016 Tony Whyman, MWA Software
23     * (http://www.mwasoftware.co.uk).
24     *
25     * All Rights Reserved.
26     *
27     * Contributor(s): ______________________________________.
28     *
29     *)
30     {************************************************************************}
31     { }
32     { Borland Delphi Visual Component Library }
33     { InterBase Express core components }
34     { }
35     { Copyright (c) 1998-2000 Inprise Corporation }
36     { }
37     { InterBase Express is based in part on the product }
38     { Free IB Components, written by Gregory H. Deatz for }
39     { Hoagland, Longo, Moran, Dunst & Doukas Company. }
40     { Free IB Components is used under license. }
41     { }
42     { The contents of this file are subject to the InterBase }
43     { Public License Version 1.0 (the "License"); you may not }
44     { use this file except in compliance with the License. You }
45     { may obtain a copy of the License at http://www.Inprise.com/IPL.html }
46     { Software distributed under the License is distributed on }
47     { an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either }
48     { express or implied. See the License for the specific language }
49     { governing rights and limitations under the License. }
50     { The Original Code was created by InterBase Software Corporation }
51     { and its successors. }
52     { Portions created by Inprise Corporation are Copyright (C) Inprise }
53     { Corporation. All Rights Reserved. }
54     { Contributor(s): Jeff Overcash }
55     { }
56     { IBX For Lazarus (Firebird Express) }
57     { Contributor: Tony Whyman, MWA Software http://www.mwasoftware.co.uk }
58     { Portions created by MWA Software are copyright McCallum Whyman }
59     { Associates Ltd 2011 - 2015 }
60     { }
61     {************************************************************************}
62     unit FBSQLData;
63 tony 56 {$IFDEF MSWINDOWS}
64     {$DEFINE WINDOWS}
65     {$ENDIF}
66 tony 45
67     {$IFDEF FPC}
68 tony 56 {$mode delphi}
69 tony 45 {$codepage UTF8}
70     {$interfaces COM}
71     {$ENDIF}
72    
73     { This Unit was hacked out of the IBSQL unit and defines a class used as the
74     base for interfaces accessing SQLDAVar data and Array Elements. The abstract
75     methods are used to customise for an SQLDAVar or Array Element. The empty
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    
79    
80     interface
81    
82     uses
83 tony 315 Classes, SysUtils, IBExternals, {$IFDEF WINDOWS} Windows, {$ENDIF} IB, FBActivityMonitor, FBClientAPI,
84     FmtBCD;
85 tony 45
86     type
87    
88 tony 315 {The IExTimeZoneServices is only available in FB4 and onwards}
89 tony 45
90 tony 315 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 tony 45 TSQLDataItem = class(TFBInterfacedObject)
122     private
123 tony 263 FFirebirdClientAPI: TFBClientAPI;
124 tony 315 FTimeZoneServices: IExTimeZoneServices;
125 tony 45 function AdjustScale(Value: Int64; aScale: Integer): Double;
126     function AdjustScaleToInt64(Value: Int64; aScale: Integer): Int64;
127     function AdjustScaleToCurrency(Value: Int64; aScale: Integer): Currency;
128 tony 270 function GetDateFormatStr(IncludeTime: boolean): AnsiString;
129     function GetTimeFormatStr: AnsiString;
130 tony 315 function GetTimestampFormatStr: AnsiString;
131 tony 45 procedure SetAsInteger(AValue: Integer);
132 tony 315 procedure InternalGetAsDateTime(var aDateTime: TDateTime; var dstOffset: smallint;
133     var aTimezone: AnsiString; var aTimeZoneID: TFBTimeZoneID);
134 tony 45 protected
135     function AdjustScaleFromCurrency(Value: Currency; aScale: Integer): Int64;
136     function AdjustScaleFromDouble(Value: Double; aScale: Integer): Int64;
137     procedure CheckActive; virtual;
138 tony 315 procedure CheckTZSupport;
139     function GetAttachment: IAttachment; virtual; abstract;
140 tony 45 function GetSQLDialect: integer; virtual; abstract;
141 tony 315 function GetTimeZoneServices: IExTimeZoneServices; virtual;
142 tony 45 procedure Changed; virtual;
143     procedure Changing; virtual;
144 tony 56 procedure InternalSetAsString(Value: AnsiString); virtual;
145     function SQLData: PByte; virtual; abstract;
146 tony 45 function GetDataLength: cardinal; virtual; abstract;
147     function GetCodePage: TSystemCodePage; virtual; abstract;
148 tony 47 function getCharSetID: cardinal; virtual; abstract;
149 tony 56 function Transliterate(s: AnsiString; CodePage: TSystemCodePage): RawByteString;
150 tony 45 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 tony 315 property FirebirdClientAPI: TFBClientAPI read FFirebirdClientAPI;
155 tony 45 public
156 tony 263 constructor Create(api: TFBClientAPI);
157 tony 349 function GetSQLType: cardinal; virtual; abstract; {Current Field Data SQL Type}
158 tony 56 function GetSQLTypeName: AnsiString; overload;
159 tony 349 class function GetSQLTypeName(SQLType: cardinal): AnsiString; overload;
160 tony 291 function GetStrDataLength: short;
161 tony 56 function GetName: AnsiString; virtual; abstract;
162 tony 349 function GetScale: integer; virtual; abstract; {Current Field Data scale}
163 tony 45 function GetAsBoolean: boolean;
164     function GetAsCurrency: Currency;
165     function GetAsInt64: Int64;
166 tony 315 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 tony 45 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 tony 56 function GetAsString: AnsiString; virtual;
181 tony 45 function GetIsNull: Boolean; virtual;
182 tony 263 function GetIsNullable: boolean; virtual;
183 tony 45 function GetAsVariant: Variant;
184     function GetModified: boolean; virtual;
185 tony 270 function GetDateTimeStrLength(DateTimeFormat: TIBDateTimeFormats): integer;
186 tony 315 function GetAsBCD: tBCD;
187 tony 308 function GetSize: cardinal; virtual; abstract;
188 tony 309 function GetCharSetWidth: integer; virtual; abstract;
189 tony 45 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 tony 315 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 tony 45 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 tony 56 procedure SetAsString(Value: AnsiString); virtual;
207 tony 45 procedure SetAsVariant(Value: Variant);
208 tony 59 procedure SetAsNumeric(Value: Int64; aScale: integer);
209 tony 315 procedure SetAsBcd(aValue: tBCD); virtual;
210 tony 45 procedure SetIsNull(Value: Boolean); virtual;
211     procedure SetIsNullable(Value: Boolean); virtual;
212 tony 56 procedure SetName(aValue: AnsiString); virtual;
213 tony 45 property AsDate: TDateTime read GetAsDateTime write SetAsDate;
214     property AsBoolean:boolean read GetAsBoolean write SetAsBoolean;
215     property AsTime: TDateTime read GetAsDateTime write SetAsTime;
216     property AsDateTime: TDateTime read GetAsDateTime write SetAsDateTime;
217     property AsDouble: Double read GetAsDouble write SetAsDouble;
218     property AsFloat: Float read GetAsFloat write SetAsFloat;
219     property AsCurrency: Currency read GetAsCurrency write SetAsCurrency;
220     property AsInt64: Int64 read GetAsInt64 write SetAsInt64;
221     property AsInteger: Integer read GetAsLong write SetAsInteger;
222     property AsLong: Long read GetAsLong write SetAsLong;
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 tony 56 property AsString: AnsiString read GetAsString write SetAsString;
227 tony 45 property AsVariant: Variant read GetAsVariant write SetAsVariant;
228     property Modified: Boolean read getModified;
229     property IsNull: Boolean read GetIsNull write SetIsNull;
230     property IsNullable: Boolean read GetIsNullable write SetIsNullable;
231     property Scale: integer read GetScale write SetScale;
232     property SQLType: cardinal read GetSQLType write SetSQLType;
233     end;
234    
235     TSQLVarData = class;
236    
237     TStatementStatus = (ssPrepared, ssExecuteResults, ssCursorOpen, ssBOF, ssEOF);
238    
239     { TSQLDataArea }
240    
241     TSQLDataArea = class
242     private
243 tony 270 FCaseSensitiveParams: boolean;
244 tony 45 function GetColumn(index: integer): TSQLVarData;
245     function GetCount: integer;
246     protected
247 tony 56 FUniqueRelationName: AnsiString;
248 tony 45 FColumnList: array of TSQLVarData;
249     function GetStatement: IStatement; virtual; abstract;
250     function GetPrepareSeqNo: integer; virtual; abstract;
251     function GetTransactionSeqNo: integer; virtual; abstract;
252     procedure SetCount(aValue: integer); virtual; abstract;
253     procedure SetUniqueRelationName;
254     public
255     procedure Initialize; virtual;
256     function IsInputDataArea: boolean; virtual; abstract; {Input to Database}
257 tony 56 procedure PreprocessSQL(sSQL: AnsiString; GenerateParamNames: boolean;
258     var sProcessedSQL: AnsiString);
259 tony 45 function ColumnsInUseCount: integer; virtual;
260 tony 56 function ColumnByName(Idx: AnsiString): TSQLVarData;
261 tony 45 function CheckStatementStatus(Request: TStatementStatus): boolean; virtual; abstract;
262     procedure GetData(index: integer; var IsNull: boolean; var len: short;
263 tony 56 var data: PByte); virtual;
264 tony 45 procedure RowChange;
265     function StateChanged(var ChangeSeqNo: integer): boolean; virtual; abstract;
266 tony 270 property CaseSensitiveParams: boolean read FCaseSensitiveParams
267     write FCaseSensitiveParams; {Only used when IsInputDataArea true}
268 tony 345 function CanChangeMetaData: boolean; virtual; abstract;
269 tony 45 property Count: integer read GetCount;
270     property Column[index: integer]: TSQLVarData read GetColumn;
271 tony 56 property UniqueRelationName: AnsiString read FUniqueRelationName;
272 tony 45 property Statement: IStatement read GetStatement;
273     property PrepareSeqNo: integer read GetPrepareSeqNo;
274     property TransactionSeqNo: integer read GetTransactionSeqNo;
275     end;
276    
277     { TSQLVarData }
278    
279     TSQLVarData = class
280     private
281     FParent: TSQLDataArea;
282 tony 56 FName: AnsiString;
283 tony 45 FIndex: integer;
284     FModified: boolean;
285     FUniqueName: boolean;
286     FVarString: RawByteString;
287 tony 349 FColMetaData: IParamMetaData;
288 tony 45 function GetStatement: IStatement;
289 tony 56 procedure SetName(AValue: AnsiString);
290 tony 45 protected
291 tony 345 function GetAttachment: IAttachment; virtual; abstract;
292 tony 45 function GetSQLType: cardinal; virtual; abstract;
293     function GetSubtype: integer; virtual; abstract;
294 tony 56 function GetAliasName: AnsiString; virtual; abstract;
295     function GetFieldName: AnsiString; virtual; abstract;
296     function GetOwnerName: AnsiString; virtual; abstract;
297     function GetRelationName: AnsiString; virtual; abstract;
298 tony 45 function GetScale: integer; virtual; abstract;
299     function GetCharSetID: cardinal; virtual; abstract;
300 tony 309 function GetCharSetWidth: integer; virtual; abstract;
301 tony 45 function GetCodePage: TSystemCodePage; virtual; abstract;
302     function GetIsNull: Boolean; virtual; abstract;
303     function GetIsNullable: boolean; virtual; abstract;
304 tony 56 function GetSQLData: PByte; virtual; abstract;
305 tony 315 function GetDataLength: cardinal; virtual; abstract; {current field length}
306     function GetSize: cardinal; virtual; abstract; {field length as given by metadata}
307 tony 345 function GetDefaultTextSQLType: cardinal; virtual; abstract;
308 tony 45 procedure SetIsNull(Value: Boolean); virtual; abstract;
309     procedure SetIsNullable(Value: Boolean); virtual; abstract;
310 tony 56 procedure SetSQLData(AValue: PByte; len: cardinal); virtual; abstract;
311 tony 45 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 tony 345 procedure SetMetaSize(aValue: cardinal); virtual;
316 tony 45 public
317     constructor Create(aParent: TSQLDataArea; aIndex: integer);
318 tony 56 procedure SetString(aValue: AnsiString);
319 tony 45 procedure Changed; virtual;
320     procedure RowChange; virtual;
321     function GetAsArray(Array_ID: TISC_QUAD): IArray; virtual; abstract;
322     function GetAsBlob(Blob_ID: TISC_QUAD; BPB: IBPB): IBlob; virtual; abstract;
323     function CreateBlob: IBlob; virtual; abstract;
324     function GetArrayMetaData: IArrayMetaData; virtual; abstract;
325     function GetBlobMetaData: IBlobMetaData; virtual; abstract;
326 tony 349 function getColMetadata: IParamMetaData;
327 tony 45 procedure Initialize; virtual;
328 tony 349 procedure SaveMetaData;
329 tony 45
330     public
331 tony 56 property AliasName: AnsiString read GetAliasName;
332     property FieldName: AnsiString read GetFieldName;
333     property OwnerName: AnsiString read GetOwnerName;
334     property RelationName: AnsiString read GetRelationName;
335 tony 45 property Parent: TSQLDataArea read FParent;
336     property Index: integer read FIndex;
337 tony 56 property Name: AnsiString read FName write SetName;
338 tony 45 property CharSetID: cardinal read GetCharSetID write SetCharSetID;
339     property SQLType: cardinal read GetSQLType write SetSQLType;
340     property SQLSubtype: integer read GetSubtype;
341 tony 56 property SQLData: PByte read GetSQLData;
342 tony 45 property DataLength: cardinal read GetDataLength write SetDataLength;
343     property IsNull: Boolean read GetIsNull write SetIsNull;
344     property IsNullable: Boolean read GetIsNullable write SetIsNullable;
345     property Scale: integer read GetScale write SetScale;
346     public
347     property Modified: Boolean read FModified;
348     property Statement: IStatement read GetStatement;
349     property UniqueName: boolean read FUniqueName write FUniqueName;
350     end;
351    
352     { TColumnMetaData }
353    
354     TColumnMetaData = class(TSQLDataItem,IColumnMetaData)
355     private
356     FIBXSQLVAR: TSQLVarData;
357     FOwner: IUnknown; {Keep reference to ensure Metadata/statement not discarded}
358     FPrepareSeqNo: integer;
359     FChangeSeqNo: integer;
360     protected
361     procedure CheckActive; override;
362 tony 315 function GetAttachment: IAttachment; override;
363 tony 56 function SQLData: PByte; override;
364 tony 45 function GetDataLength: cardinal; override;
365     function GetCodePage: TSystemCodePage; override;
366    
367     public
368     constructor Create(aOwner: IUnknown; aIBXSQLVAR: TSQLVarData);
369     destructor Destroy; override;
370     function GetSQLDialect: integer; override;
371    
372     public
373     {IColumnMetaData}
374     function GetIndex: integer;
375     function GetSQLType: cardinal; override;
376     function getSubtype: integer;
377 tony 56 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 tony 45 function GetScale: integer; override;
383 tony 47 function getCharSetID: cardinal; override;
384 tony 45 function GetIsNullable: boolean; override;
385 tony 308 function GetSize: cardinal; override;
386 tony 309 function GetCharSetWidth: integer; override;
387 tony 45 function GetArrayMetaData: IArrayMetaData;
388     function GetBlobMetaData: IBlobMetaData;
389 tony 291 function GetStatement: IStatement;
390     function GetTransaction: ITransaction; virtual;
391 tony 56 property Name: AnsiString read GetName;
392 tony 45 property Size: cardinal read GetSize;
393     property CharSetID: cardinal read getCharSetID;
394     property SQLSubtype: integer read getSubtype;
395     property IsNullable: Boolean read GetIsNullable;
396 tony 291 public
397     property Statement: IStatement read GetStatement;
398 tony 45 end;
399    
400     { TIBSQLData }
401    
402     TIBSQLData = class(TColumnMetaData,ISQLData)
403 tony 291 private
404     FTransaction: ITransaction;
405 tony 45 protected
406     procedure CheckActive; override;
407     public
408 tony 291 function GetTransaction: ITransaction; override;
409 tony 45 function GetIsNull: Boolean; override;
410     function GetAsArray: IArray;
411     function GetAsBlob: IBlob; overload;
412     function GetAsBlob(BPB: IBPB): IBlob; overload;
413 tony 56 function GetAsString: AnsiString; override;
414 tony 45 property AsBlob: IBlob read GetAsBlob;
415     end;
416    
417 tony 349 { 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 tony 45 { TSQLParam }
443    
444 tony 315 TSQLParam = class(TIBSQLData,ISQLParam,ISQLData)
445 tony 45 protected
446     procedure CheckActive; override;
447     procedure Changed; override;
448 tony 56 procedure InternalSetAsString(Value: AnsiString); override;
449 tony 45 procedure SetScale(aValue: integer); override;
450     procedure SetDataLength(len: cardinal); override;
451     procedure SetSQLType(aValue: cardinal); override;
452     public
453     procedure Clear;
454 tony 349 function getColMetadata: IParamMetaData;
455 tony 45 function GetModified: boolean; override;
456     function GetAsPointer: Pointer;
457 tony 345 function GetAsString: AnsiString; override;
458 tony 56 procedure SetName(Value: AnsiString); override;
459 tony 45 procedure SetIsNull(Value: Boolean); override;
460     procedure SetIsNullable(Value: Boolean); override;
461     procedure SetAsArray(anArray: IArray);
462    
463     {overrides}
464     procedure SetAsBoolean(AValue: boolean);
465     procedure SetAsCurrency(AValue: Currency);
466     procedure SetAsInt64(AValue: Int64);
467     procedure SetAsDate(AValue: TDateTime);
468     procedure SetAsLong(AValue: Long);
469 tony 315 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 tony 45 procedure SetAsDouble(AValue: Double);
478     procedure SetAsFloat(AValue: Float);
479     procedure SetAsPointer(AValue: Pointer);
480     procedure SetAsShort(AValue: Short);
481 tony 56 procedure SetAsString(AValue: AnsiString); override;
482 tony 45 procedure SetAsVariant(AValue: Variant);
483     procedure SetAsBlob(aValue: IBlob);
484     procedure SetAsQuad(AValue: TISC_QUAD);
485     procedure SetCharSetID(aValue: cardinal);
486 tony 315 procedure SetAsBcd(aValue: tBCD);
487 tony 45
488     property AsBlob: IBlob read GetAsBlob write SetAsBlob;
489     property IsNullable: Boolean read GetIsNullable write SetIsNullable;
490     end;
491    
492     { TMetaData }
493    
494     TMetaData = class(TInterfaceOwner,IMetaData)
495     private
496     FPrepareSeqNo: integer;
497     FMetaData: TSQLDataArea;
498     FStatement: IStatement; {ensure FStatement not destroyed until no longer needed}
499     procedure CheckActive;
500     public
501     constructor Create(aMetaData: TSQLDataArea);
502     destructor Destroy; override;
503     public
504     {IMetaData}
505 tony 56 function GetUniqueRelationName: AnsiString;
506 tony 45 function getCount: integer;
507     function getColumnMetaData(index: integer): IColumnMetaData;
508 tony 56 function ByName(Idx: AnsiString): IColumnMetaData;
509 tony 45 end;
510    
511     { TSQLParams }
512    
513     TSQLParams = class(TInterfaceOwner,ISQLParams)
514     private
515     FPrepareSeqNo: integer;
516     FChangeSeqNo: integer;
517     FSQLParams: TSQLDataArea;
518     FStatement: IStatement; {ensure FStatement not destroyed until no longer needed}
519     procedure CheckActive;
520     public
521     constructor Create(aSQLParams: TSQLDataArea);
522     destructor Destroy; override;
523     public
524     {ISQLParams}
525     function getCount: integer;
526     function getSQLParam(index: integer): ISQLParam;
527 tony 56 function ByName(Idx: AnsiString): ISQLParam ;
528 tony 45 function GetModified: Boolean;
529 tony 287 function GetHasCaseSensitiveParams: Boolean;
530 tony 45 end;
531    
532     { TResults }
533    
534     TResults = class(TInterfaceOwner,IResults)
535     private
536     FPrepareSeqNo: integer;
537     FTransactionSeqNo: integer;
538     FChangeSeqNo: integer;
539     FResults: TSQLDataArea;
540     FStatement: IStatement; {ensure FStatement not destroyed until no longer needed}
541     function GetISQLData(aIBXSQLVAR: TSQLVarData): ISQLData;
542     protected
543     procedure CheckActive;
544     public
545     constructor Create(aResults: TSQLDataArea);
546     {IResults}
547     function getCount: integer;
548 tony 56 function ByName(Idx: AnsiString): ISQLData;
549 tony 45 function getSQLData(index: integer): ISQLData;
550 tony 56 procedure GetData(index: integer; var IsNull:boolean; var len: short; var data: PByte);
551 tony 291 function GetStatement: IStatement;
552 tony 45 function GetTransaction: ITransaction; virtual;
553     procedure SetRetainInterfaces(aValue: boolean);
554     end;
555    
556     implementation
557    
558 tony 270 uses FBMessages, variants, IBUtils, FBTransaction, DateUtils;
559 tony 45
560 tony 349 { 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 tony 45 { TSQLDataArea }
615    
616     function TSQLDataArea.GetColumn(index: integer): TSQLVarData;
617     begin
618     if (index < 0) or (index >= Count) then
619     IBError(ibxeInvalidColumnIndex,[nil]);
620     Result := FColumnList[index];
621     end;
622    
623     function TSQLDataArea.GetCount: integer;
624     begin
625     Result := Length(FColumnList);
626     end;
627    
628     procedure TSQLDataArea.SetUniqueRelationName;
629     var
630     i: Integer;
631     bUnique: Boolean;
632 tony 56 RelationName: AnsiString;
633 tony 45 begin
634     bUnique := True;
635     for i := 0 to ColumnsInUseCount - 1 do
636     begin
637     RelationName := Column[i].RelationName;
638    
639     {First get the unique relation name, if any}
640    
641     if bUnique and (RelationName <> '') then
642     begin
643     if FUniqueRelationName = '' then
644     FUniqueRelationName := RelationName
645     else
646     if RelationName <> FUniqueRelationName then
647     begin
648     FUniqueRelationName := '';
649     bUnique := False;
650     end;
651     end;
652     end;
653     end;
654    
655     procedure TSQLDataArea.Initialize;
656     var
657     i: Integer;
658     begin
659     for i := 0 to ColumnsInUseCount - 1 do
660     Column[i].Initialize;
661     end;
662    
663 tony 56 procedure TSQLDataArea.PreprocessSQL(sSQL: AnsiString; GenerateParamNames: boolean;
664     var sProcessedSQL: AnsiString);
665 tony 45
666 tony 263 var slNames: TStrings;
667 tony 45
668 tony 263 procedure SetColumnNames(slNames: TStrings);
669     var i, j: integer;
670     found: boolean;
671 tony 45 begin
672 tony 263 found := false;
673 tony 45 SetCount(slNames.Count);
674     for i := 0 to slNames.Count - 1 do
675     begin
676     Column[i].Name := slNames[i];
677     Column[i].UniqueName := (slNames.Objects[i] <> nil);
678     end;
679     for i := 0 to Count - 1 do
680     begin
681     if not Column[i].UniqueName then
682     begin
683     found := false;
684     for j := i + 1 to Count - 1 do
685     if Column[i].Name = Column[j].Name then
686     begin
687     found := true;
688     break;
689     end;
690     Column[i].UniqueName := not found;
691     end;
692     end;
693 tony 263 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 tony 45 finally
704     slNames.Free;
705     end;
706     end;
707    
708     function TSQLDataArea.ColumnsInUseCount: integer;
709     begin
710     Result := Count;
711     end;
712    
713 tony 56 function TSQLDataArea.ColumnByName(Idx: AnsiString): TSQLVarData;
714 tony 45 var
715 tony 56 s: AnsiString;
716 tony 45 i: Integer;
717     begin
718 tony 270 if not IsInputDataArea or not CaseSensitiveParams then
719     s := AnsiUpperCase(Idx)
720     else
721 tony 45 s := Idx;
722 tony 270
723 tony 45 for i := 0 to Count - 1 do
724     if Column[i].Name = s then
725     begin
726     Result := Column[i];
727     Exit;
728     end;
729     Result := nil;
730     end;
731    
732     procedure TSQLDataArea.GetData(index: integer; var IsNull: boolean;
733 tony 56 var len: short; var data: PByte);
734 tony 45 begin
735     //Do Nothing
736     end;
737    
738     procedure TSQLDataArea.RowChange;
739     var i: integer;
740     begin
741     for i := 0 to Count - 1 do
742     Column[i].RowChange;
743     end;
744    
745     {TSQLVarData}
746    
747     function TSQLVarData.GetStatement: IStatement;
748     begin
749     Result := FParent.Statement;
750     end;
751    
752 tony 56 procedure TSQLVarData.SetName(AValue: AnsiString);
753 tony 45 begin
754 tony 270 if not Parent.IsInputDataArea or not Parent.CaseSensitiveParams then
755 tony 45 FName := AnsiUpperCase(AValue)
756     else
757     FName := AValue;
758     end;
759    
760 tony 345 procedure TSQLVarData.SetMetaSize(aValue: cardinal);
761     begin
762     //Ignore
763     end;
764    
765 tony 349 procedure TSQLVarData.SaveMetaData;
766     begin
767     FColMetaData := TSQLParamMetaData.Create(self);
768     end;
769    
770 tony 45 constructor TSQLVarData.Create(aParent: TSQLDataArea; aIndex: integer);
771     begin
772     inherited Create;
773     FParent := aParent;
774     FIndex := aIndex;
775     FUniqueName := true;
776     end;
777    
778 tony 56 procedure TSQLVarData.SetString(aValue: AnsiString);
779 tony 45 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 tony 56 SQLVar. This avoids string copies. Note that PAnsiChar is guaranteed to point to
783 tony 45 a zero byte when the string is empty, neatly avoiding a nil pointer error.}
784    
785     FVarString := aValue;
786 tony 345 if SQLType = SQL_BLOB then
787     SetMetaSize(GetAttachment.GetInlineBlobLimit);
788     SQLType := GetDefaultTextSQLType;
789 tony 270 Scale := 0;
790 tony 56 SetSQLData(PByte(PAnsiChar(FVarString)),Length(aValue));
791 tony 45 end;
792    
793     procedure TSQLVarData.Changed;
794     begin
795     FModified := true;
796     end;
797    
798     procedure TSQLVarData.RowChange;
799     begin
800     FModified := false;
801     FVarString := '';
802     end;
803    
804 tony 349 function TSQLVarData.getColMetadata: IParamMetaData;
805     begin
806     Result := FColMetaData;
807     end;
808    
809 tony 45 procedure TSQLVarData.Initialize;
810    
811 tony 56 function FindVarByName(idx: AnsiString; limit: integer): TSQLVarData;
812 tony 45 var
813     k: integer;
814     begin
815     for k := 0 to limit do
816     if Parent.Column[k].Name = idx then
817     begin
818     Result := Parent.Column[k];
819     Exit;
820     end;
821     Result := nil;
822     end;
823    
824     var
825     j, j_len: Integer;
826 tony 56 st: AnsiString;
827     sBaseName: AnsiString;
828 tony 45 begin
829     RowChange;
830    
831     {If an output SQLDA then copy the aliasname to the FName. Ensure
832     that they are all upper case only and disambiguated.
833     }
834    
835     if not Parent.IsInputDataArea then
836     begin
837     st := Space2Underscore(AnsiUppercase(AliasName));
838     if st = '' then
839     begin
840     sBaseName := 'F_'; {do not localize}
841     j := 1; j_len := 1;
842     st := sBaseName + IntToStr(j);
843     end
844     else
845     begin
846     j := 0; j_len := 0;
847     sBaseName := st;
848     end;
849    
850     {Look for other columns with the same name and make unique}
851    
852     while FindVarByName(st,Index-1) <> nil do
853     begin
854     Inc(j);
855     j_len := Length(IntToStr(j));
856     if j_len + Length(sBaseName) > 31 then
857     st := system.Copy(sBaseName, 1, 31 - j_len) + IntToStr(j)
858     else
859     st := sBaseName + IntToStr(j);
860     end;
861    
862     Name := st;
863     end;
864     end;
865    
866     {TSQLDataItem}
867    
868     function TSQLDataItem.AdjustScale(Value: Int64; aScale: Integer): Double;
869     var
870     Scaling : Int64;
871     i: Integer;
872     Val: Double;
873     begin
874     Scaling := 1; Val := Value;
875     if aScale > 0 then
876     begin
877     for i := 1 to aScale do
878     Scaling := Scaling * 10;
879     result := Val * Scaling;
880     end
881     else
882     if aScale < 0 then
883     begin
884     for i := -1 downto aScale do
885     Scaling := Scaling * 10;
886     result := Val / Scaling;
887     end
888     else
889     result := Val;
890     end;
891    
892     function TSQLDataItem.AdjustScaleToInt64(Value: Int64; aScale: Integer): Int64;
893     var
894     Scaling : Int64;
895     i: Integer;
896     Val: Int64;
897     begin
898     Scaling := 1; Val := Value;
899     if aScale > 0 then begin
900     for i := 1 to aScale do Scaling := Scaling * 10;
901     result := Val * Scaling;
902     end else if aScale < 0 then begin
903     for i := -1 downto aScale do Scaling := Scaling * 10;
904     result := Val div Scaling;
905     end else
906     result := Val;
907     end;
908    
909     function TSQLDataItem.AdjustScaleToCurrency(Value: Int64; aScale: Integer
910     ): Currency;
911     var
912     Scaling : Int64;
913     i : Integer;
914 tony 56 FractionText, PadText, CurrText: AnsiString;
915 tony 45 begin
916     Result := 0;
917     Scaling := 1;
918     PadText := '';
919     if aScale > 0 then
920     begin
921     for i := 1 to aScale do
922     Scaling := Scaling * 10;
923     result := Value * Scaling;
924     end
925     else
926     if aScale < 0 then
927     begin
928     for i := -1 downto aScale do
929     Scaling := Scaling * 10;
930     FractionText := IntToStr(abs(Value mod Scaling));
931     for i := Length(FractionText) to -aScale -1 do
932     PadText := '0' + PadText;
933 tony 56 {$IF declared(DefaultFormatSettings)}
934     with DefaultFormatSettings do
935     {$ELSE}
936     {$IF declared(FormatSettings)}
937     with FormatSettings do
938     {$IFEND}
939     {$IFEND}
940 tony 45 if Value < 0 then
941 tony 56 CurrText := '-' + IntToStr(Abs(Value div Scaling)) + DecimalSeparator + PadText + FractionText
942 tony 45 else
943 tony 56 CurrText := IntToStr(Abs(Value div Scaling)) + DecimalSeparator + PadText + FractionText;
944 tony 45 try
945     result := StrToCurr(CurrText);
946     except
947     on E: Exception do
948     IBError(ibxeInvalidDataConversion, [nil]);
949     end;
950     end
951     else
952     result := Value;
953     end;
954    
955 tony 270 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 tony 315 Result := 'hh' + TimeSeparator + 'nn' + TimeSeparator + 'ss' + '.zzzz';;
985 tony 270 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 tony 315 Result := ShortDateFormat + ' ' + 'hh' + TimeSeparator + 'nn' + TimeSeparator + 'ss' + '.zzzz';
997 tony 270 end;
998    
999 tony 45 procedure TSQLDataItem.SetAsInteger(AValue: Integer);
1000     begin
1001     SetAsLong(aValue);
1002     end;
1003    
1004 tony 315 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 tony 45 function TSQLDataItem.AdjustScaleFromCurrency(Value: Currency; aScale: Integer
1053     ): Int64;
1054     var
1055     Scaling : Int64;
1056     i : Integer;
1057     begin
1058     Result := 0;
1059     Scaling := 1;
1060     if aScale < 0 then
1061     begin
1062     for i := -1 downto aScale do
1063     Scaling := Scaling * 10;
1064     result := trunc(Value * Scaling);
1065     end
1066     else
1067     if aScale > 0 then
1068     begin
1069     for i := 1 to aScale do
1070     Scaling := Scaling * 10;
1071     result := trunc(Value / Scaling);
1072     end
1073     else
1074     result := trunc(Value);
1075     end;
1076    
1077     function TSQLDataItem.AdjustScaleFromDouble(Value: Double; aScale: Integer
1078     ): Int64;
1079     var
1080     Scaling : Int64;
1081     i : Integer;
1082     begin
1083     Result := 0;
1084     Scaling := 1;
1085     if aScale < 0 then
1086     begin
1087     for i := -1 downto aScale do
1088     Scaling := Scaling * 10;
1089     result := trunc(Value * Scaling);
1090     end
1091     else
1092     if aScale > 0 then
1093     begin
1094     for i := 1 to aScale do
1095     Scaling := Scaling * 10;
1096     result := trunc(Value / Scaling);
1097     end
1098     else
1099     result := trunc(Value);
1100 tony 349 // writeln('Adjusted ',Value,' to ',Result);
1101 tony 45 end;
1102    
1103     procedure TSQLDataItem.CheckActive;
1104     begin
1105     //Do nothing by default
1106     end;
1107    
1108 tony 315 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 tony 45 procedure TSQLDataItem.Changed;
1126     begin
1127     //Do nothing by default
1128     end;
1129    
1130     procedure TSQLDataItem.Changing;
1131     begin
1132     //Do nothing by default
1133     end;
1134    
1135 tony 56 procedure TSQLDataItem.InternalSetAsString(Value: AnsiString);
1136 tony 45 begin
1137     //Do nothing by default
1138     end;
1139    
1140 tony 56 function TSQLDataItem.Transliterate(s: AnsiString; CodePage: TSystemCodePage
1141 tony 45 ): RawByteString;
1142     begin
1143     Result := s;
1144     if StringCodePage(Result) <> CodePage then
1145     SetCodePage(Result,CodePage,CodePage <> CP_NONE);
1146     end;
1147    
1148     procedure TSQLDataItem.SetScale(aValue: integer);
1149     begin
1150     //Do nothing by default
1151     end;
1152    
1153     procedure TSQLDataItem.SetDataLength(len: cardinal);
1154     begin
1155     //Do nothing by default
1156     end;
1157    
1158     procedure TSQLDataItem.SetSQLType(aValue: cardinal);
1159     begin
1160     //Do nothing by default
1161     end;
1162    
1163 tony 263 constructor TSQLDataItem.Create(api: TFBClientAPI);
1164     begin
1165     inherited Create;
1166     FFirebirdClientAPI := api;
1167     end;
1168    
1169 tony 56 function TSQLDataItem.GetSQLTypeName: AnsiString;
1170 tony 45 begin
1171     Result := GetSQLTypeName(GetSQLType);
1172     end;
1173    
1174 tony 349 class function TSQLDataItem.GetSQLTypeName(SQLType: cardinal): AnsiString;
1175 tony 45 begin
1176     Result := 'Unknown';
1177     case SQLType of
1178     SQL_VARYING: Result := 'SQL_VARYING';
1179     SQL_TEXT: Result := 'SQL_TEXT';
1180     SQL_DOUBLE: Result := 'SQL_DOUBLE';
1181     SQL_FLOAT: Result := 'SQL_FLOAT';
1182     SQL_LONG: Result := 'SQL_LONG';
1183     SQL_SHORT: Result := 'SQL_SHORT';
1184     SQL_TIMESTAMP: Result := 'SQL_TIMESTAMP';
1185 tony 315 SQL_TIMESTAMP_TZ: Result := 'SQL_TIMESTAMP_TZ';
1186     SQL_TIMESTAMP_TZ_EX: Result := 'SQL_TIMESTAMP_TZ_EX';
1187 tony 45 SQL_BLOB: Result := 'SQL_BLOB';
1188     SQL_D_FLOAT: Result := 'SQL_D_FLOAT';
1189     SQL_ARRAY: Result := 'SQL_ARRAY';
1190     SQL_QUAD: Result := 'SQL_QUAD';
1191     SQL_TYPE_TIME: Result := 'SQL_TYPE_TIME';
1192     SQL_TYPE_DATE: Result := 'SQL_TYPE_DATE';
1193     SQL_INT64: Result := 'SQL_INT64';
1194 tony 315 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 tony 45 end;
1203     end;
1204    
1205 tony 291 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 tony 45 function TSQLDataItem.GetAsBoolean: boolean;
1215     begin
1216     CheckActive;
1217     result := false;
1218     if not IsNull then
1219     begin
1220     if SQLType = SQL_BOOLEAN then
1221     result := PByte(SQLData)^ = ISC_TRUE
1222     else
1223     IBError(ibxeInvalidDataConversion, [nil]);
1224     end
1225     end;
1226    
1227     function TSQLDataItem.GetAsCurrency: Currency;
1228     begin
1229     CheckActive;
1230     result := 0;
1231     if GetSQLDialect < 3 then
1232     result := GetAsDouble
1233     else begin
1234     if not IsNull then
1235     case SQLType of
1236     SQL_TEXT, SQL_VARYING: begin
1237     try
1238     result := StrtoCurr(AsString);
1239     except
1240     on E: Exception do IBError(ibxeInvalidDataConversion, [nil]);
1241     end;
1242     end;
1243     SQL_SHORT:
1244     result := AdjustScaleToCurrency(Int64(PShort(SQLData)^),
1245     Scale);
1246     SQL_LONG:
1247     result := AdjustScaleToCurrency(Int64(PLong(SQLData)^),
1248     Scale);
1249     SQL_INT64:
1250     result := AdjustScaleToCurrency(PInt64(SQLData)^,
1251     Scale);
1252     SQL_DOUBLE, SQL_FLOAT, SQL_D_FLOAT:
1253 tony 345 result := Round(AsDouble);
1254 tony 315
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 tony 45 else
1263     IBError(ibxeInvalidDataConversion, [nil]);
1264     end;
1265     end;
1266     end;
1267    
1268     function TSQLDataItem.GetAsInt64: Int64;
1269     begin
1270     CheckActive;
1271     result := 0;
1272     if not IsNull then
1273     case SQLType of
1274     SQL_TEXT, SQL_VARYING: begin
1275     try
1276     result := StrToInt64(AsString);
1277     except
1278     on E: Exception do IBError(ibxeInvalidDataConversion, [nil]);
1279     end;
1280     end;
1281     SQL_SHORT:
1282     result := AdjustScaleToInt64(Int64(PShort(SQLData)^),
1283     Scale);
1284     SQL_LONG:
1285     result := AdjustScaleToInt64(Int64(PLong(SQLData)^),
1286     Scale);
1287     SQL_INT64:
1288     result := AdjustScaleToInt64(PInt64(SQLData)^,
1289     Scale);
1290     SQL_DOUBLE, SQL_FLOAT, SQL_D_FLOAT:
1291 tony 345 result := Round(AsDouble);
1292 tony 45 else
1293     IBError(ibxeInvalidDataConversion, [nil]);
1294     end;
1295     end;
1296    
1297     function TSQLDataItem.GetAsDateTime: TDateTime;
1298 tony 315 var aTimezone: AnsiString;
1299     aTimeZoneID: TFBTimeZoneID;
1300     dstOffset: smallint;
1301 tony 45 begin
1302 tony 315 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 tony 45 CheckActive;
1324 tony 315 aTime := 0;
1325     dstOffset := 0;
1326     if not IsNull then
1327     with FFirebirdClientAPI do
1328     case SQLType of
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 tony 45 result := 0;
1379 tony 315 aTimezone := '';
1380 tony 45 if not IsNull then
1381 tony 263 with FFirebirdClientAPI do
1382 tony 45 case SQLType of
1383 tony 315 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 tony 45 end;
1389     SQL_TYPE_DATE:
1390     result := SQLDecodeDate(SQLData);
1391 tony 315 SQL_TYPE_TIME,
1392     SQL_TIME_TZ,
1393     SQL_TIME_TZ_EX:
1394 tony 45 result := SQLDecodeTime(SQLData);
1395 tony 315 SQL_TIMESTAMP,
1396     SQL_TIMESTAMP_TZ,
1397     SQL_TIMESTAMP_TZ_EX:
1398 tony 45 result := SQLDecodeDateTime(SQLData);
1399     else
1400     IBError(ibxeInvalidDataConversion, [nil]);
1401 tony 315 end;
1402 tony 45 end;
1403    
1404     function TSQLDataItem.GetAsDouble: Double;
1405     begin
1406     CheckActive;
1407     result := 0;
1408     if not IsNull then begin
1409     case SQLType of
1410     SQL_TEXT, SQL_VARYING: begin
1411     try
1412     result := StrToFloat(AsString);
1413     except
1414     on E: Exception do IBError(ibxeInvalidDataConversion, [nil]);
1415     end;
1416     end;
1417     SQL_SHORT:
1418     result := AdjustScale(Int64(PShort(SQLData)^),
1419     Scale);
1420     SQL_LONG:
1421     result := AdjustScale(Int64(PLong(SQLData)^),
1422     Scale);
1423     SQL_INT64:
1424     result := AdjustScale(PInt64(SQLData)^, Scale);
1425     SQL_FLOAT:
1426     result := PFloat(SQLData)^;
1427     SQL_DOUBLE, SQL_D_FLOAT:
1428     result := PDouble(SQLData)^;
1429 tony 315 SQL_DEC_FIXED,
1430     SQL_DEC16,
1431     SQL_DEC34,
1432     SQL_INT128:
1433     Result := BCDToDouble(GetAsBCD);
1434 tony 45 else
1435     IBError(ibxeInvalidDataConversion, [nil]);
1436     end;
1437     if Scale <> 0 then
1438     result :=
1439     StrToFloat(FloatToStrF(result, fffixed, 15,
1440     Abs(Scale) ));
1441     end;
1442     end;
1443    
1444     function TSQLDataItem.GetAsFloat: Float;
1445     begin
1446     CheckActive;
1447     result := 0;
1448     try
1449     result := AsDouble;
1450     except
1451     on E: EOverflow do
1452     IBError(ibxeInvalidDataConversion, [nil]);
1453     end;
1454     end;
1455    
1456     function TSQLDataItem.GetAsLong: Long;
1457     begin
1458     CheckActive;
1459     result := 0;
1460     if not IsNull then
1461     case SQLType of
1462     SQL_TEXT, SQL_VARYING: begin
1463     try
1464     result := StrToInt(AsString);
1465     except
1466     on E: Exception do IBError(ibxeInvalidDataConversion, [nil]);
1467     end;
1468     end;
1469     SQL_SHORT:
1470 tony 345 result := Round(AdjustScale(Int64(PShort(SQLData)^),
1471 tony 45 Scale));
1472     SQL_LONG:
1473 tony 345 result := Round(AdjustScale(Int64(PLong(SQLData)^),
1474 tony 45 Scale));
1475     SQL_INT64:
1476 tony 345 result := Round(AdjustScale(PInt64(SQLData)^, Scale));
1477 tony 45 SQL_DOUBLE, SQL_FLOAT, SQL_D_FLOAT:
1478 tony 345 result := Round(AsDouble);
1479 tony 315 SQL_DEC_FIXED,
1480     SQL_DEC16,
1481     SQL_DEC34,
1482     SQL_INT128:
1483     Result := BCDToInteger(GetAsBCD);
1484 tony 45 else
1485 tony 315 IBError(ibxeInvalidDataConversion, [GetSQLTypeName]);
1486 tony 45 end;
1487     end;
1488    
1489     function TSQLDataItem.GetAsPointer: Pointer;
1490     begin
1491     CheckActive;
1492     if not IsNull then
1493     result := SQLData
1494     else
1495     result := nil;
1496     end;
1497    
1498     function TSQLDataItem.GetAsQuad: TISC_QUAD;
1499     begin
1500     CheckActive;
1501     result.gds_quad_high := 0;
1502     result.gds_quad_low := 0;
1503     if not IsNull then
1504     case SQLType of
1505     SQL_BLOB, SQL_ARRAY, SQL_QUAD:
1506     result := PISC_QUAD(SQLData)^;
1507     else
1508     IBError(ibxeInvalidDataConversion, [nil]);
1509     end;
1510     end;
1511    
1512     function TSQLDataItem.GetAsShort: short;
1513     begin
1514     CheckActive;
1515     result := 0;
1516     try
1517     result := AsLong;
1518     except
1519     on E: Exception do IBError(ibxeInvalidDataConversion, [nil]);
1520     end;
1521     end;
1522    
1523 tony 308 {Copied from LazUTF8}
1524 tony 45
1525 tony 308 function UTF8CodepointSizeFull(p: PAnsiChar): integer;
1526 tony 309 const TopBitSetMask = $80; {%10000000}
1527     Top2BitsSetMask = $C0; {%11000000}
1528     Top3BitsSetMask = $E0; {%11100000}
1529     Top4BitsSetMask = $F0; {%11110000}
1530     Top5BitsSetMask = $F8; {%11111000}
1531 tony 308 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 tony 315 function GetStrLen(p: PAnsiChar; FieldWidth, MaxDataLength: cardinal): integer;
1571 tony 308 var i: integer;
1572     cplen: integer;
1573 tony 309 s: AnsiString;
1574 tony 308 begin
1575     Result := 0;
1576 tony 309 s := strpas(p);
1577 tony 315 for i := 1 to FieldWidth do
1578 tony 308 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 tony 56 function TSQLDataItem.GetAsString: AnsiString;
1591 tony 45 var
1592 tony 56 sz: PByte;
1593 tony 45 str_len: Integer;
1594     rs: RawByteString;
1595 tony 315 aTimeZone: AnsiString;
1596     aDateTime: TDateTime;
1597     dstOffset: smallint;
1598 tony 45 begin
1599     CheckActive;
1600     result := '';
1601     { Check null, if so return a default string }
1602     if not IsNull then
1603 tony 263 with FFirebirdClientAPI do
1604 tony 45 case SQLType of
1605     SQL_BOOLEAN:
1606     if AsBoolean then
1607     Result := sTrue
1608     else
1609     Result := SFalse;
1610    
1611     SQL_TEXT, SQL_VARYING:
1612     begin
1613     sz := SQLData;
1614     if (SQLType = SQL_TEXT) then
1615 tony 308 begin
1616     if GetCodePage = cp_utf8 then
1617 tony 309 str_len := GetStrLen(PAnsiChar(sz),GetSize div GetCharSetWidth,DataLength)
1618 tony 308 else
1619     str_len := DataLength
1620     end
1621 tony 45 else begin
1622 tony 308 str_len := DecodeInteger(sz, 2);
1623 tony 45 Inc(sz, 2);
1624     end;
1625 tony 56 SetString(rs, PAnsiChar(sz), str_len);
1626 tony 45 SetCodePage(rs,GetCodePage,false);
1627 tony 308 Result := rs;
1628 tony 45 end;
1629 tony 315
1630 tony 45 SQL_TYPE_DATE:
1631 tony 315 Result := DateToStr(GetAsDateTime);
1632 tony 45 SQL_TIMESTAMP:
1633 tony 315 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 tony 45 SQL_SHORT, SQL_LONG:
1668     if Scale = 0 then
1669     result := IntToStr(AsLong)
1670     else if Scale >= (-4) then
1671     result := CurrToStr(AsCurrency)
1672     else
1673     result := FloatToStr(AsDouble);
1674     SQL_INT64:
1675     if Scale = 0 then
1676     result := IntToStr(AsInt64)
1677     else if Scale >= (-4) then
1678     result := CurrToStr(AsCurrency)
1679     else
1680     result := FloatToStr(AsDouble);
1681     SQL_DOUBLE, SQL_FLOAT, SQL_D_FLOAT:
1682     result := FloatToStr(AsDouble);
1683 tony 315
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 tony 45 else
1693     IBError(ibxeInvalidDataConversion, [nil]);
1694     end;
1695     end;
1696    
1697     function TSQLDataItem.GetIsNull: Boolean;
1698     begin
1699     CheckActive;
1700     Result := false;
1701     end;
1702    
1703 tony 270 function TSQLDataItem.GetIsNullable: boolean;
1704 tony 45 begin
1705     CheckActive;
1706     Result := false;
1707     end;
1708    
1709     function TSQLDataItem.GetAsVariant: Variant;
1710 tony 315 var ts: TDateTime;
1711     dstOffset: smallint;
1712     timezone: AnsiString;
1713 tony 45 begin
1714     CheckActive;
1715     if IsNull then
1716     result := NULL
1717     { Check null, if so return a default string }
1718     else case SQLType of
1719     SQL_ARRAY:
1720     result := '(Array)'; {do not localize}
1721     SQL_BLOB,
1722     SQL_TEXT, SQL_VARYING:
1723     result := AsString;
1724     SQL_TIMESTAMP, SQL_TYPE_DATE, SQL_TYPE_TIME:
1725     result := AsDateTime;
1726 tony 315 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 tony 45 SQL_SHORT, SQL_LONG:
1735     if Scale = 0 then
1736     result := AsLong
1737     else if Scale >= (-4) then
1738     result := AsCurrency
1739     else
1740     result := AsDouble;
1741     SQL_INT64:
1742     if Scale = 0 then
1743     result := AsInt64
1744     else if Scale >= (-4) then
1745     result := AsCurrency
1746     else
1747     result := AsDouble;
1748     SQL_DOUBLE, SQL_FLOAT, SQL_D_FLOAT:
1749     result := AsDouble;
1750     SQL_BOOLEAN:
1751     result := AsBoolean;
1752 tony 315 SQL_DEC_FIXED,
1753     SQL_DEC16,
1754     SQL_DEC34,
1755     SQL_INT128:
1756     result := VarFmtBCDCreate(GetAsBcd);
1757 tony 45 else
1758     IBError(ibxeInvalidDataConversion, [nil]);
1759     end;
1760     end;
1761    
1762     function TSQLDataItem.GetModified: boolean;
1763     begin
1764     Result := false;
1765     end;
1766    
1767 tony 270 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 tony 315 dfTimestampTZ:
1778     Result := Length(GetTimestampFormatStr) + 6; {assume time offset format}
1779     dfTimeTZ:
1780     Result := Length(GetTimeFormatStr)+ 6;
1781 tony 270 else
1782     Result := 0;
1783 tony 315 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 tony 270 end;
1811     end;
1812 tony 45
1813 tony 270
1814 tony 45 procedure TSQLDataItem.SetIsNull(Value: Boolean);
1815     begin
1816     //ignore unless overridden
1817     end;
1818    
1819     procedure TSQLDataItem.SetIsNullable(Value: Boolean);
1820     begin
1821     //ignore unless overridden
1822     end;
1823    
1824 tony 56 procedure TSQLDataItem.SetName(aValue: AnsiString);
1825 tony 45 begin
1826     //ignore unless overridden
1827     end;
1828    
1829     procedure TSQLDataItem.SetAsCurrency(Value: Currency);
1830     begin
1831     CheckActive;
1832     if GetSQLDialect < 3 then
1833     AsDouble := Value
1834     else
1835     begin
1836     Changing;
1837     if IsNullable then
1838     IsNull := False;
1839     SQLType := SQL_INT64;
1840     Scale := -4;
1841     DataLength := SizeOf(Int64);
1842     PCurrency(SQLData)^ := Value;
1843     Changed;
1844     end;
1845     end;
1846    
1847     procedure TSQLDataItem.SetAsInt64(Value: Int64);
1848     begin
1849     CheckActive;
1850     Changing;
1851     if IsNullable then
1852     IsNull := False;
1853    
1854     SQLType := SQL_INT64;
1855     Scale := 0;
1856     DataLength := SizeOf(Int64);
1857     PInt64(SQLData)^ := Value;
1858     Changed;
1859     end;
1860    
1861     procedure TSQLDataItem.SetAsDate(Value: TDateTime);
1862     begin
1863     CheckActive;
1864     if GetSQLDialect < 3 then
1865     begin
1866     AsDateTime := Value;
1867     exit;
1868     end;
1869    
1870     Changing;
1871     if IsNullable then
1872     IsNull := False;
1873    
1874     SQLType := SQL_TYPE_DATE;
1875     DataLength := SizeOf(ISC_DATE);
1876 tony 263 with FFirebirdClientAPI do
1877 tony 45 SQLEncodeDate(Value,SQLData);
1878     Changed;
1879     end;
1880    
1881     procedure TSQLDataItem.SetAsTime(Value: TDateTime);
1882     begin
1883     CheckActive;
1884     if GetSQLDialect < 3 then
1885     begin
1886     AsDateTime := Value;
1887     exit;
1888     end;
1889    
1890     Changing;
1891     if IsNullable then
1892     IsNull := False;
1893    
1894     SQLType := SQL_TYPE_TIME;
1895     DataLength := SizeOf(ISC_TIME);
1896 tony 263 with FFirebirdClientAPI do
1897 tony 45 SQLEncodeTime(Value,SQLData);
1898     Changed;
1899     end;
1900    
1901 tony 315 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 tony 45 procedure TSQLDataItem.SetAsDateTime(Value: TDateTime);
1942     begin
1943     CheckActive;
1944     if IsNullable then
1945     IsNull := False;
1946    
1947     Changing;
1948     SQLType := SQL_TIMESTAMP;
1949 tony 47 DataLength := SizeOf(ISC_TIME) + sizeof(ISC_DATE);
1950 tony 263 with FFirebirdClientAPI do
1951 tony 45 SQLEncodeDateTime(Value,SQLData);
1952     Changed;
1953     end;
1954    
1955 tony 315 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 tony 45 procedure TSQLDataItem.SetAsDouble(Value: Double);
1991     begin
1992     CheckActive;
1993     if IsNullable then
1994     IsNull := False;
1995    
1996     Changing;
1997     SQLType := SQL_DOUBLE;
1998     DataLength := SizeOf(Double);
1999     Scale := 0;
2000     PDouble(SQLData)^ := Value;
2001     Changed;
2002     end;
2003    
2004     procedure TSQLDataItem.SetAsFloat(Value: Float);
2005     begin
2006     CheckActive;
2007     if IsNullable then
2008     IsNull := False;
2009    
2010     Changing;
2011     SQLType := SQL_FLOAT;
2012     DataLength := SizeOf(Float);
2013     Scale := 0;
2014     PSingle(SQLData)^ := Value;
2015     Changed;
2016     end;
2017    
2018     procedure TSQLDataItem.SetAsLong(Value: Long);
2019     begin
2020     CheckActive;
2021     if IsNullable then
2022     IsNull := False;
2023    
2024     Changing;
2025     SQLType := SQL_LONG;
2026     DataLength := SizeOf(Long);
2027     Scale := 0;
2028     PLong(SQLData)^ := Value;
2029     Changed;
2030     end;
2031    
2032     procedure TSQLDataItem.SetAsPointer(Value: Pointer);
2033     begin
2034     CheckActive;
2035     Changing;
2036     if IsNullable and (Value = nil) then
2037     IsNull := True
2038     else
2039     begin
2040     IsNull := False;
2041     SQLType := SQL_TEXT;
2042     Move(Value^, SQLData^, DataLength);
2043     end;
2044     Changed;
2045     end;
2046    
2047     procedure TSQLDataItem.SetAsQuad(Value: TISC_QUAD);
2048     begin
2049     CheckActive;
2050     Changing;
2051     if IsNullable then
2052     IsNull := False;
2053     if (SQLType <> SQL_BLOB) and
2054     (SQLType <> SQL_ARRAY) then
2055     IBError(ibxeInvalidDataConversion, [nil]);
2056     DataLength := SizeOf(TISC_QUAD);
2057     PISC_QUAD(SQLData)^ := Value;
2058     Changed;
2059     end;
2060    
2061     procedure TSQLDataItem.SetAsShort(Value: short);
2062     begin
2063     CheckActive;
2064     Changing;
2065     if IsNullable then
2066     IsNull := False;
2067    
2068     SQLType := SQL_SHORT;
2069     DataLength := SizeOf(Short);
2070     Scale := 0;
2071     PShort(SQLData)^ := Value;
2072     Changed;
2073     end;
2074    
2075 tony 56 procedure TSQLDataItem.SetAsString(Value: AnsiString);
2076 tony 45 begin
2077     InternalSetAsString(Value);
2078     end;
2079    
2080     procedure TSQLDataItem.SetAsVariant(Value: Variant);
2081     begin
2082     CheckActive;
2083     if VarIsNull(Value) then
2084     IsNull := True
2085 tony 315 else
2086     if VarIsArray(Value) then {must be datetime plus timezone}
2087     SetAsDateTime(Value[0],AnsiString(Value[1]))
2088 tony 45 else case VarType(Value) of
2089     varEmpty, varNull:
2090     IsNull := True;
2091     varSmallint, varInteger, varByte,
2092     varWord, varShortInt:
2093     AsLong := Value;
2094     varInt64:
2095     AsInt64 := Value;
2096     varSingle, varDouble:
2097     AsDouble := Value;
2098     varCurrency:
2099     AsCurrency := Value;
2100     varBoolean:
2101     AsBoolean := Value;
2102     varDate:
2103     AsDateTime := Value;
2104     varOleStr, varString:
2105     AsString := Value;
2106     varArray:
2107     IBError(ibxeNotSupported, [nil]);
2108     varByRef, varDispatch, varError, varUnknown, varVariant:
2109     IBError(ibxeNotPermitted, [nil]);
2110 tony 315 else
2111     if VarIsFmtBCD(Value) then
2112     SetAsBCD(VarToBCD(Value))
2113     else
2114     IBError(ibxeNotSupported, [nil]);
2115 tony 45 end;
2116     end;
2117    
2118 tony 59 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 tony 315 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 tony 45 procedure TSQLDataItem.SetAsBoolean(AValue: boolean);
2178     begin
2179     CheckActive;
2180     Changing;
2181     if IsNullable then
2182     IsNull := False;
2183    
2184     SQLType := SQL_BOOLEAN;
2185     DataLength := 1;
2186     Scale := 0;
2187     if AValue then
2188     PByte(SQLData)^ := ISC_TRUE
2189     else
2190     PByte(SQLData)^ := ISC_FALSE;
2191     Changed;
2192     end;
2193    
2194     {TColumnMetaData}
2195    
2196     procedure TColumnMetaData.CheckActive;
2197     begin
2198     if not FIBXSQLVAR.Parent.StateChanged(FChangeSeqNo) then Exit;
2199    
2200     if FPrepareSeqNo < FIBXSQLVAR.Parent.GetPrepareSeqNo then
2201     IBError(ibxeInterfaceOutofDate,[nil]);
2202    
2203     if not FIBXSQLVAR.Parent.CheckStatementStatus(ssPrepared) then
2204     IBError(ibxeStatementNotPrepared, [nil]);
2205     end;
2206    
2207 tony 315 function TColumnMetaData.GetAttachment: IAttachment;
2208     begin
2209     Result := GetStatement.GetAttachment;
2210     end;
2211    
2212 tony 56 function TColumnMetaData.SQLData: PByte;
2213 tony 45 begin
2214     Result := FIBXSQLVAR.SQLData;
2215     end;
2216    
2217     function TColumnMetaData.GetDataLength: cardinal;
2218     begin
2219     Result := FIBXSQLVAR.DataLength;
2220     end;
2221    
2222     function TColumnMetaData.GetCodePage: TSystemCodePage;
2223     begin
2224     Result := FIBXSQLVAR.GetCodePage;
2225     end;
2226    
2227     constructor TColumnMetaData.Create(aOwner: IUnknown; aIBXSQLVAR: TSQLVarData);
2228     begin
2229 tony 263 inherited Create(aIBXSQLVAR.GetStatement.GetAttachment.getFirebirdAPI as TFBClientAPI);
2230 tony 45 FIBXSQLVAR := aIBXSQLVAR;
2231     FOwner := aOwner;
2232     FPrepareSeqNo := FIBXSQLVAR.Parent.PrepareSeqNo;
2233     FIBXSQLVAR.Parent.StateChanged(FChangeSeqNo)
2234     end;
2235    
2236     destructor TColumnMetaData.Destroy;
2237     begin
2238     (FOwner as TInterfaceOwner).Remove(self);
2239     inherited Destroy;
2240     end;
2241    
2242    
2243     function TColumnMetaData.GetSQLDialect: integer;
2244     begin
2245     Result := FIBXSQLVAR.Statement.GetSQLDialect;
2246     end;
2247    
2248     function TColumnMetaData.GetIndex: integer;
2249     begin
2250     Result := FIBXSQLVAR.Index;
2251     end;
2252    
2253     function TColumnMetaData.GetSQLType: cardinal;
2254     begin
2255     CheckActive;
2256     result := FIBXSQLVAR.SQLType;
2257     end;
2258    
2259     function TColumnMetaData.getSubtype: integer;
2260     begin
2261     CheckActive;
2262     result := FIBXSQLVAR.SQLSubtype;
2263     end;
2264    
2265 tony 56 function TColumnMetaData.getRelationName: AnsiString;
2266 tony 45 begin
2267     CheckActive;
2268     result := FIBXSQLVAR.RelationName;
2269     end;
2270    
2271 tony 56 function TColumnMetaData.getOwnerName: AnsiString;
2272 tony 45 begin
2273     CheckActive;
2274     result := FIBXSQLVAR.OwnerName;
2275     end;
2276    
2277 tony 56 function TColumnMetaData.getSQLName: AnsiString;
2278 tony 45 begin
2279     CheckActive;
2280     result := FIBXSQLVAR.FieldName;
2281     end;
2282    
2283 tony 56 function TColumnMetaData.getAliasName: AnsiString;
2284 tony 45 begin
2285     CheckActive;
2286     result := FIBXSQLVAR.AliasName;
2287     end;
2288    
2289 tony 56 function TColumnMetaData.GetName: AnsiString;
2290 tony 45 begin
2291     CheckActive;
2292     Result := FIBXSQLVAR. Name;
2293     end;
2294    
2295     function TColumnMetaData.GetScale: integer;
2296     begin
2297     CheckActive;
2298     result := FIBXSQLVAR.Scale;
2299     end;
2300    
2301     function TColumnMetaData.getCharSetID: cardinal;
2302     begin
2303     CheckActive;
2304     Result := FIBXSQLVAR.CharSetID;
2305     end;
2306    
2307     function TColumnMetaData.GetIsNullable: boolean;
2308     begin
2309     CheckActive;
2310     result := FIBXSQLVAR.IsNullable;
2311     end;
2312    
2313     function TColumnMetaData.GetSize: cardinal;
2314     begin
2315     CheckActive;
2316 tony 315 result := FIBXSQLVAR.GetSize;
2317 tony 45 end;
2318    
2319 tony 309 function TColumnMetaData.GetCharSetWidth: integer;
2320     begin
2321     CheckActive;
2322     result := FIBXSQLVAR.GetCharSetWidth;
2323     end;
2324    
2325 tony 45 function TColumnMetaData.GetArrayMetaData: IArrayMetaData;
2326     begin
2327     CheckActive;
2328     result := FIBXSQLVAR.GetArrayMetaData;
2329     end;
2330    
2331     function TColumnMetaData.GetBlobMetaData: IBlobMetaData;
2332     begin
2333     CheckActive;
2334     result := FIBXSQLVAR.GetBlobMetaData;
2335     end;
2336    
2337 tony 291 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 tony 45 { TIBSQLData }
2348    
2349     procedure TIBSQLData.CheckActive;
2350     begin
2351     if not FIBXSQLVAR.Parent.StateChanged(FChangeSeqNo) then Exit;
2352    
2353     inherited CheckActive;
2354    
2355     if not FIBXSQLVAR.Parent.CheckStatementStatus(ssCursorOpen) and
2356     not FIBXSQLVAR.Parent.CheckStatementStatus(ssExecuteResults) then
2357     IBError(ibxeSQLClosed, [nil]);
2358    
2359     if FIBXSQLVAR.Parent.CheckStatementStatus(ssEOF) then
2360     IBError(ibxeEOF,[nil]);
2361    
2362     if FIBXSQLVAR.Parent.CheckStatementStatus(ssBOF) then
2363     IBError(ibxeBOF,[nil]);
2364     end;
2365    
2366 tony 291 function TIBSQLData.GetTransaction: ITransaction;
2367     begin
2368     if FTransaction = nil then
2369     Result := inherited GetTransaction
2370     else
2371     Result := FTransaction;
2372     end;
2373    
2374 tony 45 function TIBSQLData.GetIsNull: Boolean;
2375     begin
2376     CheckActive;
2377     result := FIBXSQLVAR.IsNull;
2378     end;
2379    
2380     function TIBSQLData.GetAsArray: IArray;
2381     begin
2382     CheckActive;
2383     result := FIBXSQLVAR.GetAsArray(AsQuad);
2384     end;
2385    
2386     function TIBSQLData.GetAsBlob: IBlob;
2387     begin
2388     CheckActive;
2389     result := FIBXSQLVAR.GetAsBlob(AsQuad,nil);
2390     end;
2391    
2392     function TIBSQLData.GetAsBlob(BPB: IBPB): IBlob;
2393     begin
2394     CheckActive;
2395     result := FIBXSQLVAR.GetAsBlob(AsQuad,BPB);
2396     end;
2397    
2398 tony 56 function TIBSQLData.GetAsString: AnsiString;
2399 tony 45 begin
2400     CheckActive;
2401     Result := '';
2402     { Check null, if so return a default string }
2403     if not IsNull then
2404     case SQLType of
2405     SQL_ARRAY:
2406 tony 47 result := SArray;
2407 tony 45 SQL_BLOB:
2408 tony 47 Result := FIBXSQLVAR.GetAsBlob(AsQuad,nil).GetAsString;
2409 tony 45 else
2410     Result := inherited GetAsString;
2411     end;
2412     end;
2413    
2414     { TSQLParam }
2415    
2416 tony 56 procedure TSQLParam.InternalSetAsString(Value: AnsiString);
2417 tony 270
2418     procedure DoSetString;
2419     begin
2420     Changing;
2421     FIBXSQLVar.SetString(Transliterate(Value,GetCodePage));
2422     Changed;
2423     end;
2424    
2425 tony 350 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 tony 45 var b: IBlob;
2470 tony 59 dt: TDateTime;
2471 tony 315 timezone: AnsiString;
2472 tony 350 {$ifdef FPC_HAS_TYPE_EXTENDED}
2473     FloatValue: Extended;
2474     {$else}
2475 tony 349 FloatValue: Double;
2476 tony 350 {$endif}
2477 tony 349 Int64Value: Int64;
2478     BCDValue: TBCD;
2479     aScale: integer;
2480 tony 45 begin
2481     CheckActive;
2482     if IsNullable then
2483     IsNull := False;
2484 tony 315 with FFirebirdClientAPI do
2485 tony 349 case getColMetaData.SQLTYPE of
2486 tony 45 SQL_BOOLEAN:
2487 tony 56 if AnsiCompareText(Value,STrue) = 0 then
2488 tony 45 AsBoolean := true
2489     else
2490 tony 56 if AnsiCompareText(Value,SFalse) = 0 then
2491 tony 45 AsBoolean := false
2492     else
2493     IBError(ibxeInvalidDataConversion,[nil]);
2494    
2495     SQL_BLOB:
2496 tony 345 if Length(Value) < GetAttachment.GetInlineBlobLimit then
2497     DoSetString
2498     else
2499 tony 45 begin
2500     Changing;
2501     b := FIBXSQLVAR.CreateBlob;
2502     b.SetAsString(Value);
2503     AsBlob := b;
2504     Changed;
2505     end;
2506    
2507     SQL_VARYING,
2508     SQL_TEXT:
2509 tony 270 DoSetString;
2510 tony 45
2511 tony 349 SQL_SHORT,
2512     SQL_LONG,
2513     SQL_INT64:
2514 tony 350 if TryStrToNumeric(Value,Int64Value,aScale) then
2515 tony 349 begin
2516 tony 350 if aScale = 0 then
2517     SetAsInt64(Int64Value)
2518 tony 270 else
2519 tony 350 SetAsNumeric(Int64Value,aScale);
2520 tony 349 end
2521     else
2522     if TryStrToFloat(Value,FloatValue) then
2523 tony 350 SetAsDouble(FloatValue)
2524 tony 349 else
2525     DoSetString;
2526 tony 45
2527 tony 349 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_D_FLOAT,
2537     SQL_DOUBLE,
2538     SQL_FLOAT:
2539     if TryStrToFloat(Value,FloatValue) then
2540     SetAsDouble(FloatValue)
2541     else
2542     DoSetString;
2543    
2544     SQL_TIMESTAMP:
2545 tony 59 if TryStrToDateTime(Value,dt) then
2546     SetAsDateTime(dt)
2547     else
2548 tony 270 DoSetString;
2549 tony 45
2550 tony 349 SQL_TYPE_DATE:
2551 tony 59 if TryStrToDateTime(Value,dt) then
2552     SetAsDate(dt)
2553     else
2554 tony 270 DoSetString;
2555 tony 45
2556 tony 349 SQL_TYPE_TIME:
2557 tony 59 if TryStrToDateTime(Value,dt) then
2558     SetAsTime(dt)
2559     else
2560 tony 270 DoSetString;
2561 tony 45
2562 tony 349 SQL_TIMESTAMP_TZ,
2563     SQL_TIMESTAMP_TZ_EX:
2564 tony 315 if ParseDateTimeTZString(value,dt,timezone) then
2565     SetAsDateTime(dt,timezone)
2566     else
2567     DoSetString;
2568    
2569 tony 349 SQL_TIME_TZ,
2570     SQL_TIME_TZ_EX:
2571 tony 315 if ParseDateTimeTZString(value,dt,timezone,true) then
2572     SetAsTime(dt,GetAttachment.GetTimeZoneServices.GetTimeTZDate,timezone)
2573     else
2574     DoSetString;
2575    
2576 tony 349 else
2577     IBError(ibxeInvalidDataConversion,[GetSQLTypeName(getColMetaData.SQLTYPE)]);
2578 tony 45 end;
2579     end;
2580    
2581     procedure TSQLParam.CheckActive;
2582     begin
2583     if not FIBXSQLVAR.Parent.StateChanged(FChangeSeqNo) then Exit;
2584    
2585     if FPrepareSeqNo < FIBXSQLVAR.Parent.GetPrepareSeqNo then
2586     IBError(ibxeInterfaceOutofDate,[nil]);
2587    
2588     if not FIBXSQLVAR.Parent.CheckStatementStatus(ssPrepared) then
2589     IBError(ibxeStatementNotPrepared, [nil]);
2590     end;
2591    
2592     procedure TSQLParam.SetScale(aValue: integer);
2593     begin
2594     CheckActive;
2595     FIBXSQLVAR.Scale := aValue;
2596     end;
2597    
2598     procedure TSQLParam.SetDataLength(len: cardinal);
2599     begin
2600     CheckActive;
2601     FIBXSQLVAR.DataLength := len;
2602     end;
2603    
2604     procedure TSQLParam.SetSQLType(aValue: cardinal);
2605     begin
2606     CheckActive;
2607     FIBXSQLVAR.SQLType := aValue;
2608     end;
2609    
2610     procedure TSQLParam.Clear;
2611     begin
2612     IsNull := true;
2613     end;
2614    
2615 tony 349 function TSQLParam.getColMetadata: IParamMetaData;
2616     begin
2617     Result := FIBXSQLVAR.getColMetadata;
2618     end;
2619    
2620 tony 45 function TSQLParam.GetModified: boolean;
2621     begin
2622     CheckActive;
2623     Result := FIBXSQLVAR.Modified;
2624     end;
2625    
2626     function TSQLParam.GetAsPointer: Pointer;
2627     begin
2628     IsNull := false; {Assume that we get the pointer in order to set a value}
2629     Changed;
2630     Result := inherited GetAsPointer;
2631     end;
2632    
2633 tony 345 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 tony 56 procedure TSQLParam.SetName(Value: AnsiString);
2650 tony 45 begin
2651     CheckActive;
2652     FIBXSQLVAR.Name := Value;
2653     end;
2654    
2655     procedure TSQLParam.SetIsNull(Value: Boolean);
2656     var i: integer;
2657     begin
2658     CheckActive;
2659     if FIBXSQLVAR.UniqueName then
2660     FIBXSQLVAR.IsNull := Value
2661     else
2662     with FIBXSQLVAR.Parent do
2663     begin
2664     for i := 0 to Count - 1 do
2665     if Column[i].Name = Name then
2666     Column[i].IsNull := Value;
2667     end
2668     end;
2669    
2670     procedure TSQLParam.SetIsNullable(Value: Boolean);
2671     var i: integer;
2672     begin
2673     CheckActive;
2674     if FIBXSQLVAR.UniqueName then
2675     FIBXSQLVAR.IsNullable := Value
2676     else
2677     with FIBXSQLVAR.Parent do
2678     begin
2679     for i := 0 to Count - 1 do
2680     if Column[i].Name = Name then
2681     Column[i].IsNullable := Value;
2682     end
2683     end;
2684    
2685     procedure TSQLParam.SetAsArray(anArray: IArray);
2686     begin
2687     CheckActive;
2688     if GetSQLType <> SQL_ARRAY then
2689     IBError(ibxeInvalidDataConversion,[nil]);
2690    
2691     if not FIBXSQLVAR.UniqueName then
2692     IBError(ibxeDuplicateParamName,[FIBXSQLVAR.Name]);
2693    
2694     SetAsQuad(AnArray.GetArrayID);
2695     end;
2696    
2697     procedure TSQLParam.Changed;
2698     begin
2699     FIBXSQLVAR.Changed;
2700     end;
2701    
2702     procedure TSQLParam.SetAsBoolean(AValue: boolean);
2703     var i: integer;
2704     OldSQLVar: TSQLVarData;
2705     begin
2706     if FIBXSQLVAR.UniqueName then
2707     inherited SetAsBoolean(AValue)
2708     else
2709     with FIBXSQLVAR.Parent do
2710     begin
2711     for i := 0 to Count - 1 do
2712     if Column[i].Name = Name then
2713     begin
2714     OldSQLVar := FIBXSQLVAR;
2715     FIBXSQLVAR := Column[i];
2716     try
2717     inherited SetAsBoolean(AValue);
2718     finally
2719     FIBXSQLVAR := OldSQLVar;
2720     end;
2721     end;
2722     end;
2723     end;
2724    
2725     procedure TSQLParam.SetAsCurrency(AValue: Currency);
2726     var i: integer;
2727     OldSQLVar: TSQLVarData;
2728     begin
2729     if FIBXSQLVAR.UniqueName then
2730     inherited SetAsCurrency(AValue)
2731     else
2732     with FIBXSQLVAR.Parent do
2733     begin
2734     for i := 0 to Count - 1 do
2735     if Column[i].Name = Name then
2736     begin
2737     OldSQLVar := FIBXSQLVAR;
2738     FIBXSQLVAR := Column[i];
2739     try
2740     inherited SetAsCurrency(AValue);
2741     finally
2742     FIBXSQLVAR := OldSQLVar;
2743     end;
2744     end;
2745     end;
2746     end;
2747    
2748     procedure TSQLParam.SetAsInt64(AValue: Int64);
2749     var i: integer;
2750     OldSQLVar: TSQLVarData;
2751     begin
2752     if FIBXSQLVAR.UniqueName then
2753     inherited SetAsInt64(AValue)
2754     else
2755     with FIBXSQLVAR.Parent do
2756     begin
2757     for i := 0 to Count - 1 do
2758     if Column[i].Name = Name then
2759     begin
2760     OldSQLVar := FIBXSQLVAR;
2761     FIBXSQLVAR := Column[i];
2762     try
2763     inherited SetAsInt64(AValue);
2764     finally
2765     FIBXSQLVAR := OldSQLVar;
2766     end;
2767     end;
2768     end;
2769     end;
2770    
2771     procedure TSQLParam.SetAsDate(AValue: TDateTime);
2772     var i: integer;
2773     OldSQLVar: TSQLVarData;
2774     begin
2775     if FIBXSQLVAR.UniqueName then
2776     inherited SetAsDate(AValue)
2777     else
2778     with FIBXSQLVAR.Parent do
2779     begin
2780     for i := 0 to Count - 1 do
2781     if Column[i].Name = Name then
2782     begin
2783     OldSQLVar := FIBXSQLVAR;
2784     FIBXSQLVAR := Column[i];
2785     try
2786     inherited SetAsDate(AValue);
2787     finally
2788     FIBXSQLVAR := OldSQLVar;
2789     end;
2790     end;
2791     end;
2792     end;
2793    
2794     procedure TSQLParam.SetAsLong(AValue: Long);
2795     var i: integer;
2796     OldSQLVar: TSQLVarData;
2797     begin
2798     if FIBXSQLVAR.UniqueName then
2799     inherited SetAsLong(AValue)
2800     else
2801     with FIBXSQLVAR.Parent do
2802     begin
2803     for i := 0 to Count - 1 do
2804     if Column[i].Name = Name then
2805     begin
2806     OldSQLVar := FIBXSQLVAR;
2807     FIBXSQLVAR := Column[i];
2808     try
2809     inherited SetAsLong(AValue);
2810     finally
2811     FIBXSQLVAR := OldSQLVar;
2812     end;
2813     end;
2814     end;
2815     end;
2816    
2817     procedure TSQLParam.SetAsTime(AValue: TDateTime);
2818     var i: integer;
2819     OldSQLVar: TSQLVarData;
2820     begin
2821     if FIBXSQLVAR.UniqueName then
2822     inherited SetAsTime(AValue)
2823     else
2824     with FIBXSQLVAR.Parent do
2825     begin
2826     for i := 0 to Count - 1 do
2827     if Column[i].Name = Name then
2828     begin
2829     OldSQLVar := FIBXSQLVAR;
2830     FIBXSQLVAR := Column[i];
2831     try
2832     inherited SetAsTime(AValue);
2833     finally
2834     FIBXSQLVAR := OldSQLVar;
2835     end;
2836     end;
2837     end;
2838     end;
2839    
2840 tony 315 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 tony 45 procedure TSQLParam.SetAsDateTime(AValue: TDateTime);
2897     var i: integer;
2898     OldSQLVar: TSQLVarData;
2899     begin
2900     if FIBXSQLVAR.UniqueName then
2901     inherited SetAsDateTime(AValue)
2902     else
2903     with FIBXSQLVAR.Parent do
2904     begin
2905     for i := 0 to Count - 1 do
2906     if Column[i].Name = Name then
2907     begin
2908     OldSQLVar := FIBXSQLVAR;
2909     FIBXSQLVAR := Column[i];
2910     try
2911     inherited SetAsDateTime(AValue);
2912     finally
2913     FIBXSQLVAR := OldSQLVar;
2914     end;
2915     end;
2916     end;
2917     end;
2918    
2919 tony 315 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 tony 45 procedure TSQLParam.SetAsDouble(AValue: Double);
2967     var i: integer;
2968     OldSQLVar: TSQLVarData;
2969     begin
2970     if FIBXSQLVAR.UniqueName then
2971     inherited SetAsDouble(AValue)
2972     else
2973     with FIBXSQLVAR.Parent do
2974     begin
2975     for i := 0 to Count - 1 do
2976     if Column[i].Name = Name then
2977     begin
2978     OldSQLVar := FIBXSQLVAR;
2979     FIBXSQLVAR := Column[i];
2980     try
2981     inherited SetAsDouble(AValue);
2982     finally
2983     FIBXSQLVAR := OldSQLVar;
2984     end;
2985     end;
2986     end;
2987     end;
2988    
2989     procedure TSQLParam.SetAsFloat(AValue: Float);
2990     var i: integer;
2991     OldSQLVar: TSQLVarData;
2992     begin
2993     if FIBXSQLVAR.UniqueName then
2994     inherited SetAsFloat(AValue)
2995     else
2996     with FIBXSQLVAR.Parent do
2997     begin
2998     for i := 0 to Count - 1 do
2999     if Column[i].Name = Name then
3000     begin
3001     OldSQLVar := FIBXSQLVAR;
3002     FIBXSQLVAR := Column[i];
3003     try
3004     inherited SetAsFloat(AValue);
3005     finally
3006     FIBXSQLVAR := OldSQLVar;
3007     end;
3008     end;
3009     end;
3010     end;
3011    
3012     procedure TSQLParam.SetAsPointer(AValue: Pointer);
3013     var i: integer;
3014     OldSQLVar: TSQLVarData;
3015     begin
3016     if FIBXSQLVAR.UniqueName then
3017     inherited SetAsPointer(AValue)
3018     else
3019     with FIBXSQLVAR.Parent do
3020     begin
3021     for i := 0 to Count - 1 do
3022     if Column[i].Name = Name then
3023     begin
3024     OldSQLVar := FIBXSQLVAR;
3025     FIBXSQLVAR := Column[i];
3026     try
3027     inherited SetAsPointer(AValue);
3028     finally
3029     FIBXSQLVAR := OldSQLVar;
3030     end;
3031     end;
3032     end;
3033     end;
3034    
3035     procedure TSQLParam.SetAsShort(AValue: Short);
3036     var i: integer;
3037     OldSQLVar: TSQLVarData;
3038     begin
3039     if FIBXSQLVAR.UniqueName then
3040     inherited SetAsShort(AValue)
3041     else
3042     with FIBXSQLVAR.Parent do
3043     begin
3044     for i := 0 to Count - 1 do
3045     if Column[i].Name = Name then
3046     begin
3047     OldSQLVar := FIBXSQLVAR;
3048     FIBXSQLVAR := Column[i];
3049     try
3050     inherited SetAsShort(AValue);
3051     finally
3052     FIBXSQLVAR := OldSQLVar;
3053     end;
3054     end;
3055     end;
3056     end;
3057    
3058 tony 56 procedure TSQLParam.SetAsString(AValue: AnsiString);
3059 tony 45 var i: integer;
3060     OldSQLVar: TSQLVarData;
3061     begin
3062     if FIBXSQLVAR.UniqueName then
3063     InternalSetAsString(AValue)
3064     else
3065     with FIBXSQLVAR.Parent do
3066     begin
3067     for i := 0 to Count - 1 do
3068     if Column[i].Name = Name then
3069     begin
3070     OldSQLVar := FIBXSQLVAR;
3071     FIBXSQLVAR := Column[i];
3072     try
3073     InternalSetAsString(AValue);
3074     finally
3075     FIBXSQLVAR := OldSQLVar;
3076     end;
3077     end;
3078     end;
3079     end;
3080    
3081     procedure TSQLParam.SetAsVariant(AValue: Variant);
3082     var i: integer;
3083     OldSQLVar: TSQLVarData;
3084     begin
3085     if FIBXSQLVAR.UniqueName then
3086     inherited SetAsVariant(AValue)
3087     else
3088     with FIBXSQLVAR.Parent do
3089     begin
3090     for i := 0 to Count - 1 do
3091     if Column[i].Name = Name then
3092     begin
3093     OldSQLVar := FIBXSQLVAR;
3094     FIBXSQLVAR := Column[i];
3095     try
3096     inherited SetAsVariant(AValue);
3097     finally
3098     FIBXSQLVAR := OldSQLVar;
3099     end;
3100     end;
3101     end;
3102     end;
3103    
3104     procedure TSQLParam.SetAsBlob(aValue: IBlob);
3105     begin
3106     with FIBXSQLVAR do
3107     if not UniqueName then
3108     IBError(ibxeDuplicateParamName,[Name]);
3109     CheckActive;
3110     Changing;
3111     aValue.Close;
3112     if aValue.GetSubType <> GetSubType then
3113     IBError(ibxeIncompatibleBlob,[GetSubType,aValue.GetSubType]);
3114     AsQuad := aValue.GetBlobID;
3115     Changed;
3116     end;
3117    
3118     procedure TSQLParam.SetAsQuad(AValue: TISC_QUAD);
3119     var i: integer;
3120     OldSQLVar: TSQLVarData;
3121     begin
3122     if FIBXSQLVAR.UniqueName then
3123     inherited SetAsQuad(AValue)
3124     else
3125     with FIBXSQLVAR.Parent do
3126     begin
3127     for i := 0 to Count - 1 do
3128     if Column[i].Name = Name then
3129     begin
3130     OldSQLVar := FIBXSQLVAR;
3131     FIBXSQLVAR := Column[i];
3132     try
3133     inherited SetAsQuad(AValue);
3134     finally
3135     FIBXSQLVAR := OldSQLVar;
3136     end;
3137     end;
3138     end;
3139     end;
3140    
3141     procedure TSQLParam.SetCharSetID(aValue: cardinal);
3142     begin
3143     FIBXSQLVAR.SetCharSetID(aValue);
3144     end;
3145    
3146 tony 315 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 tony 45 { TMetaData }
3170    
3171     procedure TMetaData.CheckActive;
3172     begin
3173     if FPrepareSeqNo < FMetaData.PrepareSeqNo then
3174     IBError(ibxeInterfaceOutofDate,[nil]);
3175    
3176     if not FMetaData.CheckStatementStatus(ssPrepared) then
3177     IBError(ibxeStatementNotPrepared, [nil]);
3178     end;
3179    
3180     constructor TMetaData.Create(aMetaData: TSQLDataArea);
3181     begin
3182     inherited Create(aMetaData.Count);
3183     FMetaData := aMetaData;
3184     FStatement := aMetaData.Statement;
3185     FPrepareSeqNo := aMetaData.PrepareSeqNo;
3186     end;
3187    
3188     destructor TMetaData.Destroy;
3189     begin
3190     (FStatement as TInterfaceOwner).Remove(self);
3191     inherited Destroy;
3192     end;
3193    
3194 tony 56 function TMetaData.GetUniqueRelationName: AnsiString;
3195 tony 45 begin
3196     CheckActive;
3197     Result := FMetaData.UniqueRelationName;
3198     end;
3199    
3200     function TMetaData.getCount: integer;
3201     begin
3202     CheckActive;
3203     Result := FMetaData.ColumnsInUseCount;
3204     end;
3205    
3206     function TMetaData.getColumnMetaData(index: integer): IColumnMetaData;
3207     begin
3208     CheckActive;
3209     if (index < 0) or (index >= getCount) then
3210     IBError(ibxeInvalidColumnIndex,[nil]);
3211    
3212     if FMetaData.Count = 0 then
3213     Result := nil
3214     else
3215     begin
3216     if not HasInterface(index) then
3217     AddInterface(index,TColumnMetaData.Create(self,FMetaData.Column[index]));
3218     Result := TColumnMetaData(GetInterface(index));
3219     end;
3220     end;
3221    
3222 tony 56 function TMetaData.ByName(Idx: AnsiString): IColumnMetaData;
3223 tony 45 var aIBXSQLVAR: TSQLVarData;
3224     begin
3225     CheckActive;
3226     aIBXSQLVAR := FMetaData.ColumnByName(Idx);
3227     if aIBXSQLVAR = nil then
3228     IBError(ibxeFieldNotFound,[Idx]);
3229     Result := getColumnMetaData(aIBXSQLVAR.index);
3230     end;
3231    
3232     { TSQLParams }
3233    
3234     procedure TSQLParams.CheckActive;
3235     begin
3236     if not FSQLParams.StateChanged(FChangeSeqNo) then Exit;
3237    
3238     if FPrepareSeqNo < FSQLParams.PrepareSeqNo then
3239     IBError(ibxeInterfaceOutofDate,[nil]);
3240    
3241     if not FSQLParams.CheckStatementStatus(ssPrepared) then
3242     IBError(ibxeStatementNotPrepared, [nil]);
3243     end;
3244    
3245     constructor TSQLParams.Create(aSQLParams: TSQLDataArea);
3246     begin
3247     inherited Create(aSQLParams.Count);
3248     FSQLParams := aSQLParams;
3249     FStatement := aSQLParams.Statement;
3250     FPrepareSeqNo := aSQLParams.PrepareSeqNo;
3251     FSQLParams.StateChanged(FChangeSeqNo);
3252     end;
3253    
3254     destructor TSQLParams.Destroy;
3255     begin
3256     (FStatement as TInterfaceOwner).Remove(self);
3257     inherited Destroy;
3258     end;
3259    
3260     function TSQLParams.getCount: integer;
3261     begin
3262     CheckActive;
3263     Result := FSQLParams.ColumnsInUseCount;
3264     end;
3265    
3266     function TSQLParams.getSQLParam(index: integer): ISQLParam;
3267     begin
3268     CheckActive;
3269     if (index < 0) or (index >= getCount) then
3270     IBError(ibxeInvalidColumnIndex,[nil]);
3271    
3272     if getCount = 0 then
3273     Result := nil
3274     else
3275     begin
3276     if not HasInterface(index) then
3277     AddInterface(index, TSQLParam.Create(self,FSQLParams.Column[index]));
3278     Result := TSQLParam(GetInterface(index));
3279     end;
3280     end;
3281    
3282 tony 56 function TSQLParams.ByName(Idx: AnsiString): ISQLParam;
3283 tony 45 var aIBXSQLVAR: TSQLVarData;
3284     begin
3285     CheckActive;
3286     aIBXSQLVAR := FSQLParams.ColumnByName(Idx);
3287     if aIBXSQLVAR = nil then
3288     IBError(ibxeFieldNotFound,[Idx]);
3289     Result := getSQLParam(aIBXSQLVAR.index);
3290     end;
3291    
3292     function TSQLParams.GetModified: Boolean;
3293     var
3294     i: Integer;
3295     begin
3296     CheckActive;
3297     result := False;
3298     with FSQLParams do
3299     for i := 0 to Count - 1 do
3300     if Column[i].Modified then
3301     begin
3302     result := True;
3303     exit;
3304     end;
3305     end;
3306    
3307 tony 287 function TSQLParams.GetHasCaseSensitiveParams: Boolean;
3308     begin
3309     Result := FSQLParams.CaseSensitiveParams;
3310     end;
3311    
3312 tony 45 { TResults }
3313    
3314     procedure TResults.CheckActive;
3315     begin
3316     if not FResults.StateChanged(FChangeSeqNo) then Exit;
3317    
3318     if FPrepareSeqNo < FResults.PrepareSeqNo then
3319     IBError(ibxeInterfaceOutofDate,[nil]);
3320    
3321     if not FResults.CheckStatementStatus(ssPrepared) then
3322     IBError(ibxeStatementNotPrepared, [nil]);
3323    
3324 tony 315 with GetTransaction do
3325 tony 45 if not InTransaction or (FResults.TransactionSeqNo <> FTransactionSeqNo) then
3326     IBError(ibxeInterfaceOutofDate,[nil]);
3327     end;
3328    
3329     function TResults.GetISQLData(aIBXSQLVAR: TSQLVarData): ISQLData;
3330 tony 291 var col: TIBSQLData;
3331 tony 45 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 tony 291 col := TIBSQLData(GetInterface(aIBXSQLVAR.Index));
3338     col.FTransaction := GetTransaction;
3339     Result := col;
3340 tony 45 end;
3341    
3342     constructor TResults.Create(aResults: TSQLDataArea);
3343     begin
3344     inherited Create(aResults.Count);
3345     FResults := aResults;
3346     FStatement := aResults.Statement;
3347     FPrepareSeqNo := aResults.PrepareSeqNo;
3348     FTransactionSeqNo := aResults.TransactionSeqNo;
3349     FResults.StateChanged(FChangeSeqNo);
3350     end;
3351    
3352     function TResults.getCount: integer;
3353     begin
3354     CheckActive;
3355     Result := FResults.Count;
3356     end;
3357    
3358 tony 56 function TResults.ByName(Idx: AnsiString): ISQLData;
3359 tony 45 var col: TSQLVarData;
3360     begin
3361     Result := nil;
3362     CheckActive;
3363     if FResults.CheckStatementStatus(ssBOF) then
3364     IBError(ibxeBOF,[nil]);
3365     if FResults.CheckStatementStatus(ssEOF) then
3366     IBError(ibxeEOF,[nil]);
3367    
3368     if FResults.Count > 0 then
3369     begin
3370     col := FResults.ColumnByName(Idx);
3371     if col <> nil then
3372     Result := GetISQLData(col);
3373     end;
3374     end;
3375    
3376     function TResults.getSQLData(index: integer): ISQLData;
3377     begin
3378     CheckActive;
3379     if FResults.CheckStatementStatus(ssBOF) then
3380     IBError(ibxeBOF,[nil]);
3381     if FResults.CheckStatementStatus(ssEOF) then
3382     IBError(ibxeEOF,[nil]);
3383     if (index < 0) or (index >= FResults.Count) then
3384     IBError(ibxeInvalidColumnIndex,[nil]);
3385    
3386     Result := GetISQLData(FResults.Column[index]);
3387     end;
3388    
3389     procedure TResults.GetData(index: integer; var IsNull: boolean; var len: short;
3390 tony 56 var data: PByte);
3391 tony 45 begin
3392     CheckActive;
3393     FResults.GetData(index,IsNull, len,data);
3394     end;
3395    
3396 tony 291 function TResults.GetStatement: IStatement;
3397     begin
3398     Result := FStatement;
3399     end;
3400    
3401 tony 45 function TResults.GetTransaction: ITransaction;
3402     begin
3403     Result := FStatement.GetTransaction;
3404     end;
3405    
3406     procedure TResults.SetRetainInterfaces(aValue: boolean);
3407     begin
3408     RetainInterfaces := aValue;
3409     end;
3410    
3411     end.
3412