ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/public/ibx/branches/udr/client/FBSQLData.pas
Revision: 371
Committed: Wed Jan 5 15:21:22 2022 UTC (2 years, 3 months ago) by tony
Content type: text/x-pascal
File size: 92624 byte(s)
Log Message:
Beta Release 0.1

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 270 function GetDateFormatStr(IncludeTime: boolean): AnsiString;
126     function GetTimeFormatStr: AnsiString;
127 tony 315 function GetTimestampFormatStr: AnsiString;
128 tony 45 procedure SetAsInteger(AValue: Integer);
129 tony 315 procedure InternalGetAsDateTime(var aDateTime: TDateTime; var dstOffset: smallint;
130     var aTimezone: AnsiString; var aTimeZoneID: TFBTimeZoneID);
131 tony 45 protected
132     procedure CheckActive; virtual;
133 tony 315 procedure CheckTZSupport;
134     function GetAttachment: IAttachment; virtual; abstract;
135 tony 371 function GetTransaction: ITransaction; virtual; abstract;
136 tony 45 function GetSQLDialect: integer; virtual; abstract;
137 tony 315 function GetTimeZoneServices: IExTimeZoneServices; virtual;
138 tony 45 procedure Changed; virtual;
139     procedure Changing; virtual;
140 tony 56 procedure InternalSetAsString(Value: AnsiString); virtual;
141     function SQLData: PByte; virtual; abstract;
142 tony 45 function GetDataLength: cardinal; virtual; abstract;
143     function GetCodePage: TSystemCodePage; virtual; abstract;
144 tony 47 function getCharSetID: cardinal; virtual; abstract;
145 tony 56 function Transliterate(s: AnsiString; CodePage: TSystemCodePage): RawByteString;
146 tony 45 procedure SetScale(aValue: integer); virtual;
147     procedure SetDataLength(len: cardinal); virtual;
148     procedure SetSQLType(aValue: cardinal); virtual;
149     property DataLength: cardinal read GetDataLength write SetDataLength;
150 tony 315 property FirebirdClientAPI: TFBClientAPI read FFirebirdClientAPI;
151 tony 45 public
152 tony 263 constructor Create(api: TFBClientAPI);
153 tony 371 function CanChangeMetaData: boolean; virtual;
154 tony 349 function GetSQLType: cardinal; virtual; abstract; {Current Field Data SQL Type}
155 tony 56 function GetSQLTypeName: AnsiString; overload;
156 tony 349 class function GetSQLTypeName(SQLType: cardinal): AnsiString; overload;
157 tony 291 function GetStrDataLength: short;
158 tony 371 function getColMetadata: IParamMetaData; virtual; abstract;
159 tony 56 function GetName: AnsiString; virtual; abstract;
160 tony 349 function GetScale: integer; virtual; abstract; {Current Field Data scale}
161 tony 45 function GetAsBoolean: boolean;
162     function GetAsCurrency: Currency;
163     function GetAsInt64: Int64;
164 tony 315 function GetAsDateTime: TDateTime; overload;
165     procedure GetAsDateTime(var aDateTime: TDateTime; var dstOffset: smallint; var aTimezone: AnsiString); overload;
166     procedure GetAsDateTime(var aDateTime: TDateTime; var dstOffset: smallint; var aTimezoneID: TFBTimeZoneID); overload;
167     procedure GetAsTime(var aTime: TDateTime; var dstOffset: smallint; var aTimezoneID: TFBTimeZoneID; OnDate: TDateTime); overload;
168     procedure GetAsTime(var aTime: TDateTime; var dstOffset: smallint; var aTimezone: AnsiString; OnDate: TDateTime); overload;
169     procedure GetAsTime(var aTime: TDateTime; var dstOffset: smallint; var aTimezoneID: TFBTimeZoneID); overload;
170     procedure GetAsTime(var aTime: TDateTime; var dstOffset: smallint; var aTimezone: AnsiString); overload;
171     function GetAsUTCDateTime: TDateTime;
172 tony 45 function GetAsDouble: Double;
173     function GetAsFloat: Float;
174     function GetAsLong: Long;
175     function GetAsPointer: Pointer;
176     function GetAsQuad: TISC_QUAD;
177     function GetAsShort: short;
178 tony 56 function GetAsString: AnsiString; virtual;
179 tony 371 function GetAsNumeric: IFBNumeric;
180 tony 45 function GetIsNull: Boolean; virtual;
181 tony 263 function GetIsNullable: boolean; virtual;
182 tony 45 function GetAsVariant: Variant;
183     function GetModified: boolean; virtual;
184 tony 270 function GetDateTimeStrLength(DateTimeFormat: TIBDateTimeFormats): integer;
185 tony 315 function GetAsBCD: tBCD;
186 tony 308 function GetSize: cardinal; virtual; abstract;
187 tony 309 function GetCharSetWidth: integer; virtual; abstract;
188 tony 45 procedure SetAsBoolean(AValue: boolean); virtual;
189     procedure SetAsCurrency(Value: Currency); virtual;
190     procedure SetAsInt64(Value: Int64); virtual;
191     procedure SetAsDate(Value: TDateTime); virtual;
192     procedure SetAsLong(Value: Long); virtual;
193 tony 315 procedure SetAsTime(Value: TDateTime); overload;
194     procedure SetAsTime(aValue: TDateTime; OnDate: TDateTime;aTimeZoneID: TFBTimeZoneID); overload;
195     procedure SetAsTime(aValue: TDateTime; OnDate: TDateTime; aTimeZone: AnsiString); overload;
196     procedure SetAsDateTime(Value: TDateTime); overload;
197     procedure SetAsDateTime(aValue: TDateTime; aTimeZoneID: TFBTimeZoneID); overload;
198     procedure SetAsDateTime(aValue: TDateTime; aTimeZone: AnsiString); overload;
199     procedure SetAsUTCDateTime(aUTCTime: TDateTime);
200 tony 45 procedure SetAsDouble(Value: Double); virtual;
201     procedure SetAsFloat(Value: Float); virtual;
202     procedure SetAsPointer(Value: Pointer);
203     procedure SetAsQuad(Value: TISC_QUAD);
204     procedure SetAsShort(Value: short); virtual;
205 tony 56 procedure SetAsString(Value: AnsiString); virtual;
206 tony 45 procedure SetAsVariant(Value: Variant);
207 tony 371 procedure SetAsNumeric(Value: IFBNumeric); virtual;
208 tony 315 procedure SetAsBcd(aValue: tBCD); virtual;
209 tony 45 procedure SetIsNull(Value: Boolean); virtual;
210     procedure SetIsNullable(Value: Boolean); virtual;
211 tony 56 procedure SetName(aValue: AnsiString); virtual;
212 tony 45 property AsDate: TDateTime read GetAsDateTime write SetAsDate;
213     property AsBoolean:boolean read GetAsBoolean write SetAsBoolean;
214     property AsTime: TDateTime read GetAsDateTime write SetAsTime;
215     property AsDateTime: TDateTime read GetAsDateTime write SetAsDateTime;
216     property AsDouble: Double read GetAsDouble write SetAsDouble;
217     property AsFloat: Float read GetAsFloat write SetAsFloat;
218     property AsCurrency: Currency read GetAsCurrency write SetAsCurrency;
219     property AsInt64: Int64 read GetAsInt64 write SetAsInt64;
220     property AsInteger: Integer read GetAsLong write SetAsInteger;
221     property AsLong: Long read GetAsLong write SetAsLong;
222     property AsPointer: Pointer read GetAsPointer write SetAsPointer;
223     property AsQuad: TISC_QUAD read GetAsQuad write SetAsQuad;
224     property AsShort: short read GetAsShort write SetAsShort;
225 tony 56 property AsString: AnsiString read GetAsString write SetAsString;
226 tony 45 property AsVariant: Variant read GetAsVariant write SetAsVariant;
227     property Modified: Boolean read getModified;
228     property IsNull: Boolean read GetIsNull write SetIsNull;
229     property IsNullable: Boolean read GetIsNullable write SetIsNullable;
230     property Scale: integer read GetScale write SetScale;
231     property SQLType: cardinal read GetSQLType write SetSQLType;
232     end;
233    
234     TSQLVarData = class;
235    
236     TStatementStatus = (ssPrepared, ssExecuteResults, ssCursorOpen, ssBOF, ssEOF);
237    
238     { TSQLDataArea }
239    
240     TSQLDataArea = class
241     private
242 tony 270 FCaseSensitiveParams: boolean;
243 tony 45 function GetColumn(index: integer): TSQLVarData;
244     function GetCount: integer;
245     protected
246 tony 56 FUniqueRelationName: AnsiString;
247 tony 45 FColumnList: array of TSQLVarData;
248     function GetStatement: IStatement; virtual; abstract;
249 tony 371 function GetAttachment: IAttachment; virtual;
250     function GetTransaction: ITransaction; virtual;
251 tony 45 function GetPrepareSeqNo: integer; virtual; abstract;
252     function GetTransactionSeqNo: integer; virtual; abstract;
253     procedure SetCount(aValue: integer); virtual; abstract;
254     procedure SetUniqueRelationName;
255     public
256     procedure Initialize; virtual;
257     function IsInputDataArea: boolean; virtual; abstract; {Input to Database}
258 tony 56 procedure PreprocessSQL(sSQL: AnsiString; GenerateParamNames: boolean;
259     var sProcessedSQL: AnsiString);
260 tony 45 function ColumnsInUseCount: integer; virtual;
261 tony 56 function ColumnByName(Idx: AnsiString): TSQLVarData;
262 tony 45 function CheckStatementStatus(Request: TStatementStatus): boolean; virtual; abstract;
263     procedure GetData(index: integer; var IsNull: boolean; var len: short;
264 tony 56 var data: PByte); virtual;
265 tony 45 procedure RowChange;
266     function StateChanged(var ChangeSeqNo: integer): boolean; virtual; abstract;
267 tony 270 property CaseSensitiveParams: boolean read FCaseSensitiveParams
268     write FCaseSensitiveParams; {Only used when IsInputDataArea true}
269 tony 345 function CanChangeMetaData: boolean; virtual; abstract;
270 tony 45 property Count: integer read GetCount;
271 tony 371 property Column[index: integer]: TSQLVarData read GetColumn; default;
272 tony 56 property UniqueRelationName: AnsiString read FUniqueRelationName;
273 tony 45 property Statement: IStatement read GetStatement;
274 tony 371 property Attachment: IAttachment read GetAttachment;
275 tony 45 property PrepareSeqNo: integer read GetPrepareSeqNo;
276 tony 371 property Transaction: ITransaction read GetTransaction;
277 tony 45 property TransactionSeqNo: integer read GetTransactionSeqNo;
278     end;
279    
280     { TSQLVarData }
281    
282     TSQLVarData = class
283     private
284     FParent: TSQLDataArea;
285 tony 56 FName: AnsiString;
286 tony 45 FIndex: integer;
287     FModified: boolean;
288     FUniqueName: boolean;
289     FVarString: RawByteString;
290 tony 349 FColMetaData: IParamMetaData;
291 tony 45 function GetStatement: IStatement;
292 tony 56 procedure SetName(AValue: AnsiString);
293 tony 45 protected
294 tony 363 FArrayIntf: IArray;
295 tony 371 function GetAttachment: IAttachment;
296     function GetTransaction: ITransaction;
297 tony 45 function GetSQLType: cardinal; virtual; abstract;
298     function GetSubtype: integer; virtual; abstract;
299 tony 56 function GetAliasName: AnsiString; virtual; abstract;
300     function GetFieldName: AnsiString; virtual; abstract;
301     function GetOwnerName: AnsiString; virtual; abstract;
302     function GetRelationName: AnsiString; virtual; abstract;
303 tony 45 function GetScale: integer; virtual; abstract;
304     function GetCharSetID: cardinal; virtual; abstract;
305 tony 371 function GetCharSetWidth: integer;
306     function GetCodePage: TSystemCodePage;
307 tony 45 function GetIsNull: Boolean; virtual; abstract;
308     function GetIsNullable: boolean; virtual; abstract;
309 tony 56 function GetSQLData: PByte; virtual; abstract;
310 tony 315 function GetDataLength: cardinal; virtual; abstract; {current field length}
311     function GetSize: cardinal; virtual; abstract; {field length as given by metadata}
312 tony 345 function GetDefaultTextSQLType: cardinal; virtual; abstract;
313 tony 371 procedure InternalSetSQLType(aValue: cardinal); virtual; abstract;
314     procedure InternalSetScale(aValue: integer); virtual; abstract;
315     procedure InternalSetDataLength(len: cardinal); virtual; abstract;
316 tony 45 procedure SetIsNull(Value: Boolean); virtual; abstract;
317     procedure SetIsNullable(Value: Boolean); virtual; abstract;
318 tony 56 procedure SetSQLData(AValue: PByte; len: cardinal); virtual; abstract;
319 tony 371 procedure SetScale(aValue: integer);
320     procedure SetDataLength(len: cardinal);
321     procedure SetSQLType(aValue: cardinal);
322 tony 45 procedure SetCharSetID(aValue: cardinal); virtual; abstract;
323 tony 345 procedure SetMetaSize(aValue: cardinal); virtual;
324 tony 45 public
325     constructor Create(aParent: TSQLDataArea; aIndex: integer);
326 tony 371 function CanChangeMetaData: boolean;
327 tony 56 procedure SetString(aValue: AnsiString);
328 tony 45 procedure Changed; virtual;
329     procedure RowChange; virtual;
330 tony 363 function GetAsArray: IArray; virtual; abstract;
331 tony 45 function GetAsBlob(Blob_ID: TISC_QUAD; BPB: IBPB): IBlob; virtual; abstract;
332     function CreateBlob: IBlob; virtual; abstract;
333     function GetArrayMetaData: IArrayMetaData; virtual; abstract;
334     function GetBlobMetaData: IBlobMetaData; virtual; abstract;
335 tony 349 function getColMetadata: IParamMetaData;
336 tony 45 procedure Initialize; virtual;
337 tony 349 procedure SaveMetaData;
338 tony 363 procedure SetArray(AValue: IArray);
339 tony 45
340     public
341 tony 56 property AliasName: AnsiString read GetAliasName;
342     property FieldName: AnsiString read GetFieldName;
343     property OwnerName: AnsiString read GetOwnerName;
344     property RelationName: AnsiString read GetRelationName;
345 tony 45 property Parent: TSQLDataArea read FParent;
346     property Index: integer read FIndex;
347 tony 56 property Name: AnsiString read FName write SetName;
348 tony 45 property CharSetID: cardinal read GetCharSetID write SetCharSetID;
349 tony 371 property CodePage: TSystemCodePage read GetCodePage;
350 tony 45 property SQLType: cardinal read GetSQLType write SetSQLType;
351     property SQLSubtype: integer read GetSubtype;
352 tony 56 property SQLData: PByte read GetSQLData;
353 tony 45 property DataLength: cardinal read GetDataLength write SetDataLength;
354     property IsNull: Boolean read GetIsNull write SetIsNull;
355     property IsNullable: Boolean read GetIsNullable write SetIsNullable;
356     property Scale: integer read GetScale write SetScale;
357     public
358     property Modified: Boolean read FModified;
359     property Statement: IStatement read GetStatement;
360     property UniqueName: boolean read FUniqueName write FUniqueName;
361     end;
362    
363     { TColumnMetaData }
364    
365 tony 371 TColumnMetaData = class(TSQLDataItem,IColumnMetaData,IParamMetaData)
366 tony 45 private
367     FIBXSQLVAR: TSQLVarData;
368     FOwner: IUnknown; {Keep reference to ensure Metadata/statement not discarded}
369     FPrepareSeqNo: integer;
370     FChangeSeqNo: integer;
371     protected
372     procedure CheckActive; override;
373 tony 56 function SQLData: PByte; override;
374 tony 45 function GetDataLength: cardinal; override;
375     function GetCodePage: TSystemCodePage; override;
376    
377     public
378     constructor Create(aOwner: IUnknown; aIBXSQLVAR: TSQLVarData);
379     destructor Destroy; override;
380     function GetSQLDialect: integer; override;
381 tony 371 function getColMetadata: IParamMetaData; override;
382 tony 45
383     public
384     {IColumnMetaData}
385     function GetIndex: integer;
386     function GetSQLType: cardinal; override;
387     function getSubtype: integer;
388 tony 56 function getRelationName: AnsiString;
389     function getOwnerName: AnsiString;
390     function getSQLName: AnsiString; {Name of the column}
391     function getAliasName: AnsiString; {Alias Name of column or Column Name if not alias}
392     function GetName: AnsiString; override; {Disambiguated uppercase Field Name}
393 tony 45 function GetScale: integer; override;
394 tony 47 function getCharSetID: cardinal; override;
395 tony 45 function GetIsNullable: boolean; override;
396 tony 308 function GetSize: cardinal; override;
397 tony 309 function GetCharSetWidth: integer; override;
398 tony 45 function GetArrayMetaData: IArrayMetaData;
399     function GetBlobMetaData: IBlobMetaData;
400 tony 291 function GetStatement: IStatement;
401 tony 371 function GetTransaction: ITransaction; override;
402     function GetAttachment: IAttachment; override;
403 tony 56 property Name: AnsiString read GetName;
404 tony 45 property Size: cardinal read GetSize;
405     property CharSetID: cardinal read getCharSetID;
406     property SQLSubtype: integer read getSubtype;
407     property IsNullable: Boolean read GetIsNullable;
408 tony 291 public
409     property Statement: IStatement read GetStatement;
410 tony 45 end;
411    
412     { TIBSQLData }
413    
414     TIBSQLData = class(TColumnMetaData,ISQLData)
415     protected
416     procedure CheckActive; override;
417     public
418     function GetIsNull: Boolean; override;
419     function GetAsArray: IArray;
420     function GetAsBlob: IBlob; overload;
421     function GetAsBlob(BPB: IBPB): IBlob; overload;
422 tony 56 function GetAsString: AnsiString; override;
423 tony 45 property AsBlob: IBlob read GetAsBlob;
424     end;
425    
426 tony 349 { TSQLParamMetaData }
427    
428     TSQLParamMetaData = class(TFBInterfacedObject,IParamMetaData)
429     private
430     FSQLType: cardinal;
431     FSQLSubType: integer;
432     FScale: integer;
433     FCharSetID: cardinal;
434     FNullable: boolean;
435     FSize: cardinal;
436     FCodePage: TSystemCodePage;
437     public
438     constructor Create(src: TSQLVarData);
439     {IParamMetaData}
440     function GetSQLType: cardinal;
441     function GetSQLTypeName: AnsiString;
442     function getSubtype: integer;
443     function getScale: integer;
444     function getCharSetID: cardinal;
445     function getCodePage: TSystemCodePage;
446     function getIsNullable: boolean;
447     function GetSize: cardinal;
448     property SQLType: cardinal read GetSQLType;
449     end;
450    
451 tony 45 { TSQLParam }
452    
453 tony 315 TSQLParam = class(TIBSQLData,ISQLParam,ISQLData)
454 tony 45 protected
455     procedure CheckActive; override;
456     procedure Changed; override;
457 tony 56 procedure InternalSetAsString(Value: AnsiString); override;
458 tony 45 procedure SetScale(aValue: integer); override;
459     procedure SetDataLength(len: cardinal); override;
460     procedure SetSQLType(aValue: cardinal); override;
461     public
462     procedure Clear;
463 tony 371 function CanChangeMetaData: boolean; override;
464     function getColMetadata: IParamMetaData; override;
465 tony 45 function GetModified: boolean; override;
466     function GetAsPointer: Pointer;
467 tony 345 function GetAsString: AnsiString; override;
468 tony 56 procedure SetName(Value: AnsiString); override;
469 tony 45 procedure SetIsNull(Value: Boolean); override;
470     procedure SetIsNullable(Value: Boolean); override;
471     procedure SetAsArray(anArray: IArray);
472    
473     {overrides}
474     procedure SetAsBoolean(AValue: boolean);
475     procedure SetAsCurrency(AValue: Currency);
476     procedure SetAsInt64(AValue: Int64);
477     procedure SetAsDate(AValue: TDateTime);
478     procedure SetAsLong(AValue: Long);
479 tony 315 procedure SetAsTime(AValue: TDateTime); overload;
480     procedure SetAsTime(aValue: TDateTime; OnDate: TDateTime; aTimeZoneID: TFBTimeZoneID); overload;
481     procedure SetAsTime(aValue: TDateTime; OnDate: TDateTime; aTimeZone: AnsiString); overload;
482     procedure SetAsTime(aValue: TDateTime; aTimeZoneID: TFBTimeZoneID); overload;
483     procedure SetAsTime(aValue: TDateTime; aTimeZone: AnsiString); overload;
484     procedure SetAsDateTime(AValue: TDateTime); overload;
485     procedure SetAsDateTime(aValue: TDateTime; aTimeZoneID: TFBTimeZoneID); overload;
486     procedure SetAsDateTime(aValue: TDateTime; aTimeZone: AnsiString); overload;
487 tony 45 procedure SetAsDouble(AValue: Double);
488     procedure SetAsFloat(AValue: Float);
489     procedure SetAsPointer(AValue: Pointer);
490     procedure SetAsShort(AValue: Short);
491 tony 56 procedure SetAsString(AValue: AnsiString); override;
492 tony 45 procedure SetAsVariant(AValue: Variant);
493     procedure SetAsBlob(aValue: IBlob);
494     procedure SetAsQuad(AValue: TISC_QUAD);
495     procedure SetCharSetID(aValue: cardinal);
496 tony 315 procedure SetAsBcd(aValue: tBCD);
497 tony 371 procedure SetAsNumeric(aValue: IFBNumeric);
498 tony 45
499     property AsBlob: IBlob read GetAsBlob write SetAsBlob;
500     property IsNullable: Boolean read GetIsNullable write SetIsNullable;
501     end;
502    
503     { TMetaData }
504    
505     TMetaData = class(TInterfaceOwner,IMetaData)
506     private
507     FPrepareSeqNo: integer;
508     FMetaData: TSQLDataArea;
509     FStatement: IStatement; {ensure FStatement not destroyed until no longer needed}
510     procedure CheckActive;
511     public
512     constructor Create(aMetaData: TSQLDataArea);
513     destructor Destroy; override;
514     public
515     {IMetaData}
516 tony 56 function GetUniqueRelationName: AnsiString;
517 tony 45 function getCount: integer;
518     function getColumnMetaData(index: integer): IColumnMetaData;
519 tony 56 function ByName(Idx: AnsiString): IColumnMetaData;
520 tony 45 end;
521    
522     { TSQLParams }
523    
524     TSQLParams = class(TInterfaceOwner,ISQLParams)
525     private
526     FPrepareSeqNo: integer;
527     FChangeSeqNo: integer;
528     FSQLParams: TSQLDataArea;
529     FStatement: IStatement; {ensure FStatement not destroyed until no longer needed}
530     procedure CheckActive;
531     public
532     constructor Create(aSQLParams: TSQLDataArea);
533     destructor Destroy; override;
534     public
535     {ISQLParams}
536     function getCount: integer;
537     function getSQLParam(index: integer): ISQLParam;
538 tony 56 function ByName(Idx: AnsiString): ISQLParam ;
539 tony 45 function GetModified: Boolean;
540 tony 287 function GetHasCaseSensitiveParams: Boolean;
541 tony 371 function GetStatement: IStatement;
542     function GetTransaction: ITransaction;
543     function GetAttachment: IAttachment;
544     procedure Clear;
545 tony 45 end;
546    
547     { TResults }
548    
549     TResults = class(TInterfaceOwner,IResults)
550     private
551     FPrepareSeqNo: integer;
552     FTransactionSeqNo: integer;
553     FChangeSeqNo: integer;
554     FResults: TSQLDataArea;
555     FStatement: IStatement; {ensure FStatement not destroyed until no longer needed}
556     function GetISQLData(aIBXSQLVAR: TSQLVarData): ISQLData;
557     protected
558     procedure CheckActive;
559     public
560     constructor Create(aResults: TSQLDataArea);
561     {IResults}
562     function getCount: integer;
563 tony 56 function ByName(Idx: AnsiString): ISQLData;
564 tony 45 function getSQLData(index: integer): ISQLData;
565 tony 56 procedure GetData(index: integer; var IsNull:boolean; var len: short; var data: PByte);
566 tony 291 function GetStatement: IStatement;
567 tony 371 function GetTransaction: ITransaction;
568     function GetAttachment: IAttachment;
569 tony 45 procedure SetRetainInterfaces(aValue: boolean);
570     end;
571    
572     implementation
573    
574 tony 371 uses FBMessages, variants, IBUtils, FBTransaction, FBNumeric, DateUtils;
575 tony 45
576 tony 349 { TSQLParamMetaData }
577    
578     constructor TSQLParamMetaData.Create(src: TSQLVarData);
579     begin
580     inherited Create;
581     FSQLType := src.GetSQLType;
582     FSQLSubType := src.getSubtype;
583     FScale := src.GetScale;
584     FCharSetID := src.getCharSetID;
585     FNullable := src.GetIsNullable;
586     FSize := src.GetSize;
587     FCodePage := src.GetCodePage;
588     end;
589    
590     function TSQLParamMetaData.GetSQLType: cardinal;
591     begin
592     Result := FSQLType;
593     end;
594    
595     function TSQLParamMetaData.GetSQLTypeName: AnsiString;
596     begin
597     Result := TSQLDataItem.GetSQLTypeName(FSQLType);
598     end;
599    
600     function TSQLParamMetaData.getSubtype: integer;
601     begin
602     Result := FSQLSubType;
603     end;
604    
605     function TSQLParamMetaData.getScale: integer;
606     begin
607     Result := FScale;
608     end;
609    
610     function TSQLParamMetaData.getCharSetID: cardinal;
611     begin
612     Result := FCharSetID;
613     end;
614    
615     function TSQLParamMetaData.getCodePage: TSystemCodePage;
616     begin
617     Result := FCodePage;
618     end;
619    
620     function TSQLParamMetaData.getIsNullable: boolean;
621     begin
622     Result := FNullable;
623     end;
624    
625     function TSQLParamMetaData.GetSize: cardinal;
626     begin
627     Result := FSize;
628     end;
629    
630 tony 45 { TSQLDataArea }
631    
632     function TSQLDataArea.GetColumn(index: integer): TSQLVarData;
633     begin
634     if (index < 0) or (index >= Count) then
635     IBError(ibxeInvalidColumnIndex,[nil]);
636     Result := FColumnList[index];
637     end;
638    
639     function TSQLDataArea.GetCount: integer;
640     begin
641     Result := Length(FColumnList);
642     end;
643    
644 tony 371 function TSQLDataArea.GetTransaction: ITransaction;
645     begin
646     Result := GetStatement.GetTransaction;
647     end;
648    
649     function TSQLDataArea.GetAttachment: IAttachment;
650     begin
651     Result := GetStatement.GetAttachment;
652     end;
653    
654 tony 45 procedure TSQLDataArea.SetUniqueRelationName;
655     var
656     i: Integer;
657     bUnique: Boolean;
658 tony 56 RelationName: AnsiString;
659 tony 45 begin
660     bUnique := True;
661     for i := 0 to ColumnsInUseCount - 1 do
662     begin
663     RelationName := Column[i].RelationName;
664    
665     {First get the unique relation name, if any}
666    
667     if bUnique and (RelationName <> '') then
668     begin
669     if FUniqueRelationName = '' then
670     FUniqueRelationName := RelationName
671     else
672     if RelationName <> FUniqueRelationName then
673     begin
674     FUniqueRelationName := '';
675     bUnique := False;
676     end;
677     end;
678     end;
679     end;
680    
681     procedure TSQLDataArea.Initialize;
682     var
683     i: Integer;
684     begin
685     for i := 0 to ColumnsInUseCount - 1 do
686     Column[i].Initialize;
687     end;
688    
689 tony 56 procedure TSQLDataArea.PreprocessSQL(sSQL: AnsiString; GenerateParamNames: boolean;
690     var sProcessedSQL: AnsiString);
691 tony 45
692 tony 263 var slNames: TStrings;
693 tony 45
694 tony 263 procedure SetColumnNames(slNames: TStrings);
695     var i, j: integer;
696     found: boolean;
697 tony 45 begin
698 tony 263 found := false;
699 tony 45 SetCount(slNames.Count);
700     for i := 0 to slNames.Count - 1 do
701     begin
702     Column[i].Name := slNames[i];
703     Column[i].UniqueName := (slNames.Objects[i] <> nil);
704     end;
705     for i := 0 to Count - 1 do
706     begin
707     if not Column[i].UniqueName then
708     begin
709     found := false;
710     for j := i + 1 to Count - 1 do
711     if Column[i].Name = Column[j].Name then
712     begin
713     found := true;
714     break;
715     end;
716     Column[i].UniqueName := not found;
717     end;
718     end;
719 tony 263 end;
720    
721     begin
722     if not IsInputDataArea then
723     IBError(ibxeNotPermitted,[nil]);
724    
725     slNames := TStringList.Create;
726     try
727     sProcessedSQL := TSQLParamProcessor.Execute(sSQL,GenerateParamNames,slNames);
728     SetColumnNames(slNames);
729 tony 45 finally
730     slNames.Free;
731     end;
732     end;
733    
734     function TSQLDataArea.ColumnsInUseCount: integer;
735     begin
736     Result := Count;
737     end;
738    
739 tony 56 function TSQLDataArea.ColumnByName(Idx: AnsiString): TSQLVarData;
740 tony 45 var
741 tony 56 s: AnsiString;
742 tony 45 i: Integer;
743     begin
744 tony 270 if not IsInputDataArea or not CaseSensitiveParams then
745     s := AnsiUpperCase(Idx)
746     else
747 tony 45 s := Idx;
748 tony 270
749 tony 45 for i := 0 to Count - 1 do
750     if Column[i].Name = s then
751     begin
752     Result := Column[i];
753     Exit;
754     end;
755     Result := nil;
756     end;
757    
758     procedure TSQLDataArea.GetData(index: integer; var IsNull: boolean;
759 tony 56 var len: short; var data: PByte);
760 tony 45 begin
761     //Do Nothing
762     end;
763    
764     procedure TSQLDataArea.RowChange;
765     var i: integer;
766     begin
767     for i := 0 to Count - 1 do
768     Column[i].RowChange;
769     end;
770    
771     {TSQLVarData}
772    
773     function TSQLVarData.GetStatement: IStatement;
774     begin
775     Result := FParent.Statement;
776     end;
777    
778 tony 56 procedure TSQLVarData.SetName(AValue: AnsiString);
779 tony 45 begin
780 tony 270 if not Parent.IsInputDataArea or not Parent.CaseSensitiveParams then
781 tony 45 FName := AnsiUpperCase(AValue)
782     else
783     FName := AValue;
784     end;
785    
786 tony 371 function TSQLVarData.GetAttachment: IAttachment;
787     begin
788     Result := Parent.Attachment;
789     end;
790    
791     function TSQLVarData.GetTransaction: ITransaction;
792     begin
793     Result := Parent.Transaction;
794     end;
795    
796     function TSQLVarData.GetCharSetWidth: integer;
797     begin
798     result := 1;
799     GetAttachment.CharSetWidth(GetCharSetID,result);
800     end;
801    
802     function TSQLVarData.GetCodePage: TSystemCodePage;
803     begin
804     result := CP_NONE;
805     GetAttachment.CharSetID2CodePage(GetCharSetID,result);
806     end;
807    
808     procedure TSQLVarData.SetScale(aValue: integer);
809     begin
810     if aValue = Scale then
811     Exit;
812     if not CanChangeMetaData then
813     IBError(ibxeScaleCannotBeChanged,[]);
814     InternalSetScale(aValue);
815     end;
816    
817     procedure TSQLVarData.SetDataLength(len: cardinal);
818     begin
819     if len = DataLength then
820     Exit;
821     InternalSetDataLength(len);
822     end;
823    
824     procedure TSQLVarData.SetSQLType(aValue: cardinal);
825     begin
826     if aValue = SQLType then
827     Exit;
828     if not CanChangeMetaData then
829     IBError(ibxeSQLTypeUnchangeable,[TSQLDataItem.GetSQLTypeName(SQLType),
830     TSQLDataItem.GetSQLTypeName(aValue)]);
831     InternalSetSQLType(aValue);
832     end;
833    
834 tony 345 procedure TSQLVarData.SetMetaSize(aValue: cardinal);
835     begin
836     //Ignore
837     end;
838    
839 tony 349 procedure TSQLVarData.SaveMetaData;
840     begin
841     FColMetaData := TSQLParamMetaData.Create(self);
842     end;
843    
844 tony 363 procedure TSQLVarData.SetArray(AValue: IArray);
845     begin
846     FArrayIntf := AValue;
847     end;
848    
849 tony 45 constructor TSQLVarData.Create(aParent: TSQLDataArea; aIndex: integer);
850     begin
851     inherited Create;
852     FParent := aParent;
853     FIndex := aIndex;
854     FUniqueName := true;
855     end;
856    
857 tony 371 function TSQLVarData.CanChangeMetaData: boolean;
858     begin
859     Result := Parent.CanChangeMetaData;
860     end;
861    
862 tony 56 procedure TSQLVarData.SetString(aValue: AnsiString);
863 tony 45 begin
864     {we take full advantage here of reference counted strings. When setting a string
865     value, a reference is kept in FVarString and a pointer to it placed in the
866 tony 56 SQLVar. This avoids string copies. Note that PAnsiChar is guaranteed to point to
867 tony 45 a zero byte when the string is empty, neatly avoiding a nil pointer error.}
868    
869     FVarString := aValue;
870 tony 345 if SQLType = SQL_BLOB then
871     SetMetaSize(GetAttachment.GetInlineBlobLimit);
872 tony 371 if CanChangeMetaData then
873     SQLType := GetDefaultTextSQLType;
874 tony 270 Scale := 0;
875 tony 371 if (SQLType <> SQL_VARYING) and (SQLType <> SQL_TEXT) then
876     IBError(ibxeUnableTosetaTextType,[Index,Name,TSQLDataItem.GetSQLTypeName(SQLType)]);
877 tony 56 SetSQLData(PByte(PAnsiChar(FVarString)),Length(aValue));
878 tony 45 end;
879    
880     procedure TSQLVarData.Changed;
881     begin
882     FModified := true;
883     end;
884    
885     procedure TSQLVarData.RowChange;
886     begin
887 tony 363 FArrayIntf := nil;
888 tony 45 FModified := false;
889     FVarString := '';
890     end;
891    
892 tony 349 function TSQLVarData.getColMetadata: IParamMetaData;
893     begin
894     Result := FColMetaData;
895     end;
896    
897 tony 45 procedure TSQLVarData.Initialize;
898    
899 tony 56 function FindVarByName(idx: AnsiString; limit: integer): TSQLVarData;
900 tony 45 var
901     k: integer;
902     begin
903     for k := 0 to limit do
904     if Parent.Column[k].Name = idx then
905     begin
906     Result := Parent.Column[k];
907     Exit;
908     end;
909     Result := nil;
910     end;
911    
912     var
913     j, j_len: Integer;
914 tony 56 st: AnsiString;
915     sBaseName: AnsiString;
916 tony 45 begin
917     RowChange;
918    
919     {If an output SQLDA then copy the aliasname to the FName. Ensure
920     that they are all upper case only and disambiguated.
921     }
922    
923     if not Parent.IsInputDataArea then
924     begin
925     st := Space2Underscore(AnsiUppercase(AliasName));
926     if st = '' then
927     begin
928     sBaseName := 'F_'; {do not localize}
929     j := 1; j_len := 1;
930     st := sBaseName + IntToStr(j);
931     end
932     else
933     begin
934     j := 0; j_len := 0;
935     sBaseName := st;
936     end;
937    
938     {Look for other columns with the same name and make unique}
939    
940     while FindVarByName(st,Index-1) <> nil do
941     begin
942     Inc(j);
943     j_len := Length(IntToStr(j));
944     if j_len + Length(sBaseName) > 31 then
945     st := system.Copy(sBaseName, 1, 31 - j_len) + IntToStr(j)
946     else
947     st := sBaseName + IntToStr(j);
948     end;
949    
950     Name := st;
951     end;
952     end;
953    
954     {TSQLDataItem}
955    
956 tony 270 function TSQLDataItem.GetDateFormatStr(IncludeTime: boolean): AnsiString;
957     begin
958     {$IF declared(DefaultFormatSettings)}
959     with DefaultFormatSettings do
960     {$ELSE}
961     {$IF declared(FormatSettings)}
962     with FormatSettings do
963     {$IFEND}
964     {$IFEND}
965     case GetSQLDialect of
966     1:
967     if IncludeTime then
968     result := ShortDateFormat + ' ' + LongTimeFormat
969     else
970     result := ShortDateFormat;
971     3:
972     result := ShortDateFormat;
973     end;
974     end;
975    
976     function TSQLDataItem.GetTimeFormatStr: AnsiString;
977     begin
978     {$IF declared(DefaultFormatSettings)}
979     with DefaultFormatSettings do
980     {$ELSE}
981     {$IF declared(FormatSettings)}
982     with FormatSettings do
983     {$IFEND}
984     {$IFEND}
985 tony 315 Result := 'hh' + TimeSeparator + 'nn' + TimeSeparator + 'ss' + '.zzzz';;
986 tony 270 end;
987    
988     function TSQLDataItem.GetTimestampFormatStr: AnsiString;
989     begin
990     {$IF declared(DefaultFormatSettings)}
991     with DefaultFormatSettings do
992     {$ELSE}
993     {$IF declared(FormatSettings)}
994     with FormatSettings do
995     {$IFEND}
996     {$IFEND}
997 tony 315 Result := ShortDateFormat + ' ' + 'hh' + TimeSeparator + 'nn' + TimeSeparator + 'ss' + '.zzzz';
998 tony 270 end;
999    
1000 tony 45 procedure TSQLDataItem.SetAsInteger(AValue: Integer);
1001     begin
1002     SetAsLong(aValue);
1003     end;
1004    
1005 tony 315 procedure TSQLDataItem.InternalGetAsDateTime(var aDateTime: TDateTime;
1006     var dstOffset: smallint; var aTimezone: AnsiString;
1007     var aTimeZoneID: TFBTimeZoneID);
1008     begin
1009     CheckActive;
1010     aDateTime := 0;
1011     dstOffset := 0;
1012     aTimezone := '';
1013     aTimeZoneID := TimeZoneID_GMT;
1014     if not IsNull then
1015     with FFirebirdClientAPI do
1016     case SQLType of
1017     SQL_TEXT, SQL_VARYING:
1018     if not ParseDateTimeTZString(AsString,aDateTime,aTimeZone) then
1019     IBError(ibxeInvalidDataConversion, [nil]);
1020     SQL_TYPE_DATE:
1021     aDateTime := SQLDecodeDate(SQLData);
1022     SQL_TYPE_TIME:
1023     aDateTime := SQLDecodeTime(SQLData);
1024     SQL_TIMESTAMP:
1025     aDateTime := SQLDecodeDateTime(SQLData);
1026     SQL_TIMESTAMP_TZ:
1027     begin
1028     GetTimeZoneServices.DecodeTimestampTZ(SQLData,aDateTime,dstOffset,aTimeZone);
1029     aTimeZoneID := PISC_TIMESTAMP_TZ(SQLData)^.time_zone;
1030     end;
1031     SQL_TIMESTAMP_TZ_EX:
1032     begin
1033     GetTimeZoneServices.DecodeTimestampTZEx(SQLData,aDateTime,dstOffset,aTimeZone);
1034     aTimeZoneID := PISC_TIMESTAMP_TZ_EX(SQLData)^.time_zone;
1035     end;
1036     SQL_TIME_TZ:
1037     with GetTimeZoneServices do
1038     begin
1039     DecodeTimeTZ(SQLData,GetTimeTZDate,aDateTime,dstOffset,aTimeZone);
1040     aTimeZoneID := PISC_TIME_TZ(SQLData)^.time_zone;
1041     end;
1042     SQL_TIME_TZ_EX:
1043     with GetTimeZoneServices do
1044     begin
1045     DecodeTimeTZEx(SQLData,GetTimeTZDate,aDateTime,dstOffset,aTimeZone);
1046     aTimeZoneID := PISC_TIME_TZ_EX(SQLData)^.time_zone;
1047     end;
1048     else
1049     IBError(ibxeInvalidDataConversion, [nil]);
1050     end;
1051     end;
1052    
1053 tony 45 procedure TSQLDataItem.CheckActive;
1054     begin
1055     //Do nothing by default
1056     end;
1057    
1058 tony 315 procedure TSQLDataItem.CheckTZSupport;
1059     begin
1060     if not FFirebirdClientAPI.HasTimeZoneSupport then
1061     IBError(ibxeNoTimezoneSupport,[]);
1062     end;
1063    
1064     function TSQLDataItem.GetTimeZoneServices: IExTimeZoneServices;
1065     begin
1066     if FTimeZoneServices = nil then
1067     begin
1068     if not GetAttachment.HasTimeZoneSupport then
1069     IBError(ibxeNoTimezoneSupport,[]);
1070     GetAttachment.GetTimeZoneServices.QueryInterface(IExTimeZoneServices,FTimeZoneServices);
1071     end;
1072     Result := FTimeZoneServices;
1073     end;
1074    
1075 tony 45 procedure TSQLDataItem.Changed;
1076     begin
1077     //Do nothing by default
1078     end;
1079    
1080     procedure TSQLDataItem.Changing;
1081     begin
1082     //Do nothing by default
1083     end;
1084    
1085 tony 56 procedure TSQLDataItem.InternalSetAsString(Value: AnsiString);
1086 tony 45 begin
1087     //Do nothing by default
1088     end;
1089    
1090 tony 56 function TSQLDataItem.Transliterate(s: AnsiString; CodePage: TSystemCodePage
1091 tony 45 ): RawByteString;
1092     begin
1093     Result := s;
1094     if StringCodePage(Result) <> CodePage then
1095     SetCodePage(Result,CodePage,CodePage <> CP_NONE);
1096     end;
1097    
1098     procedure TSQLDataItem.SetScale(aValue: integer);
1099     begin
1100     //Do nothing by default
1101     end;
1102    
1103     procedure TSQLDataItem.SetDataLength(len: cardinal);
1104     begin
1105     //Do nothing by default
1106     end;
1107    
1108     procedure TSQLDataItem.SetSQLType(aValue: cardinal);
1109     begin
1110     //Do nothing by default
1111     end;
1112    
1113 tony 263 constructor TSQLDataItem.Create(api: TFBClientAPI);
1114     begin
1115     inherited Create;
1116     FFirebirdClientAPI := api;
1117     end;
1118    
1119 tony 371 function TSQLDataItem.CanChangeMetaData: boolean;
1120     begin
1121     Result := false;
1122     end;
1123    
1124 tony 56 function TSQLDataItem.GetSQLTypeName: AnsiString;
1125 tony 45 begin
1126     Result := GetSQLTypeName(GetSQLType);
1127     end;
1128    
1129 tony 349 class function TSQLDataItem.GetSQLTypeName(SQLType: cardinal): AnsiString;
1130 tony 45 begin
1131     Result := 'Unknown';
1132     case SQLType of
1133     SQL_VARYING: Result := 'SQL_VARYING';
1134     SQL_TEXT: Result := 'SQL_TEXT';
1135     SQL_DOUBLE: Result := 'SQL_DOUBLE';
1136     SQL_FLOAT: Result := 'SQL_FLOAT';
1137     SQL_LONG: Result := 'SQL_LONG';
1138     SQL_SHORT: Result := 'SQL_SHORT';
1139     SQL_TIMESTAMP: Result := 'SQL_TIMESTAMP';
1140 tony 315 SQL_TIMESTAMP_TZ: Result := 'SQL_TIMESTAMP_TZ';
1141     SQL_TIMESTAMP_TZ_EX: Result := 'SQL_TIMESTAMP_TZ_EX';
1142 tony 45 SQL_BLOB: Result := 'SQL_BLOB';
1143     SQL_D_FLOAT: Result := 'SQL_D_FLOAT';
1144     SQL_ARRAY: Result := 'SQL_ARRAY';
1145     SQL_QUAD: Result := 'SQL_QUAD';
1146     SQL_TYPE_TIME: Result := 'SQL_TYPE_TIME';
1147     SQL_TYPE_DATE: Result := 'SQL_TYPE_DATE';
1148     SQL_INT64: Result := 'SQL_INT64';
1149 tony 315 SQL_TIME_TZ: Result := 'SQL_TIME_TZ';
1150     SQL_TIME_TZ_EX: Result := 'SQL_TIME_TZ_EX';
1151     SQL_DEC_FIXED: Result := 'SQL_DEC_FIXED';
1152     SQL_DEC16: Result := 'SQL_DEC16';
1153     SQL_DEC34: Result := 'SQL_DEC34';
1154     SQL_INT128: Result := 'SQL_INT128';
1155     SQL_NULL: Result := 'SQL_NULL';
1156     SQL_BOOLEAN: Result := 'SQL_BOOLEAN';
1157 tony 45 end;
1158     end;
1159    
1160 tony 291 function TSQLDataItem.GetStrDataLength: short;
1161     begin
1162     with FFirebirdClientAPI do
1163     if SQLType = SQL_VARYING then
1164     Result := DecodeInteger(SQLData, 2)
1165     else
1166     Result := DataLength;
1167     end;
1168    
1169 tony 45 function TSQLDataItem.GetAsBoolean: boolean;
1170     begin
1171     CheckActive;
1172     result := false;
1173     if not IsNull then
1174     begin
1175     if SQLType = SQL_BOOLEAN then
1176     result := PByte(SQLData)^ = ISC_TRUE
1177     else
1178     IBError(ibxeInvalidDataConversion, [nil]);
1179     end
1180     end;
1181    
1182     function TSQLDataItem.GetAsCurrency: Currency;
1183     begin
1184     CheckActive;
1185     result := 0;
1186     if GetSQLDialect < 3 then
1187     result := GetAsDouble
1188     else begin
1189     if not IsNull then
1190     case SQLType of
1191     SQL_TEXT, SQL_VARYING: begin
1192     try
1193     result := StrtoCurr(AsString);
1194     except
1195     on E: Exception do IBError(ibxeInvalidDataConversion, [nil]);
1196     end;
1197     end;
1198     SQL_SHORT:
1199 tony 371 result := NumericFromRawValues(Int64(PShort(SQLData)^),
1200     Scale).getAsCurrency;
1201 tony 45 SQL_LONG:
1202 tony 371 result := NumericFromRawValues(Int64(PLong(SQLData)^),
1203     Scale).getAsCurrency;
1204 tony 45 SQL_INT64:
1205 tony 371 result := NumericFromRawValues(PInt64(SQLData)^,
1206     Scale).getAsCurrency;
1207 tony 45 SQL_DOUBLE, SQL_FLOAT, SQL_D_FLOAT:
1208 tony 345 result := Round(AsDouble);
1209 tony 315
1210     SQL_DEC_FIXED,
1211     SQL_DEC16,
1212     SQL_DEC34,
1213     SQL_INT128:
1214     if not BCDToCurr(GetAsBCD,Result) then
1215     IBError(ibxeInvalidDataConversion, [nil]);
1216    
1217 tony 45 else
1218     IBError(ibxeInvalidDataConversion, [nil]);
1219     end;
1220     end;
1221     end;
1222    
1223     function TSQLDataItem.GetAsInt64: Int64;
1224     begin
1225     CheckActive;
1226     result := 0;
1227     if not IsNull then
1228     case SQLType of
1229     SQL_TEXT, SQL_VARYING: begin
1230     try
1231     result := StrToInt64(AsString);
1232     except
1233     on E: Exception do IBError(ibxeInvalidDataConversion, [nil]);
1234     end;
1235     end;
1236     SQL_SHORT:
1237 tony 371 result := NumericFromRawValues(Int64(PShort(SQLData)^),
1238     Scale).getAsInt64;
1239 tony 45 SQL_LONG:
1240 tony 371 result := NumericFromRawValues(Int64(PLong(SQLData)^),
1241     Scale).getAsInt64;
1242 tony 45 SQL_INT64:
1243 tony 371 result := NumericFromRawValues(PInt64(SQLData)^,
1244     Scale).getAsInt64;
1245 tony 45 SQL_DOUBLE, SQL_FLOAT, SQL_D_FLOAT:
1246 tony 345 result := Round(AsDouble);
1247 tony 45 else
1248     IBError(ibxeInvalidDataConversion, [nil]);
1249     end;
1250     end;
1251    
1252     function TSQLDataItem.GetAsDateTime: TDateTime;
1253 tony 315 var aTimezone: AnsiString;
1254     aTimeZoneID: TFBTimeZoneID;
1255     dstOffset: smallint;
1256 tony 45 begin
1257 tony 315 InternalGetAsDateTime(Result,dstOffset,aTimeZone,aTimeZoneID);
1258     end;
1259    
1260     procedure TSQLDataItem.GetAsDateTime(var aDateTime: TDateTime;
1261     var dstOffset: smallint; var aTimezone: AnsiString);
1262     var aTimeZoneID: TFBTimeZoneID;
1263     begin
1264     InternalGetAsDateTime(aDateTime,dstOffset,aTimeZone,aTimeZoneID);
1265     end;
1266    
1267     procedure TSQLDataItem.GetAsDateTime(var aDateTime: TDateTime; var dstOffset: smallint;
1268     var aTimezoneID: TFBTimeZoneID);
1269     var aTimezone: AnsiString;
1270     begin
1271     InternalGetAsDateTime(aDateTime,dstOffset,aTimeZone,aTimeZoneID);
1272     end;
1273    
1274     procedure TSQLDataItem.GetAsTime(var aTime: TDateTime; var dstOffset: smallint;
1275     var aTimezoneID: TFBTimeZoneID; OnDate: TDateTime);
1276     var aTimeZone: AnsiString;
1277     begin
1278 tony 45 CheckActive;
1279 tony 315 aTime := 0;
1280     dstOffset := 0;
1281     if not IsNull then
1282     with FFirebirdClientAPI do
1283     case SQLType of
1284     SQL_TIME_TZ:
1285     begin
1286     GetTimeZoneServices.DecodeTimeTZ(SQLData,OnDate,aTime,dstOffset,aTimeZone);
1287     aTimeZoneID := PISC_TIME_TZ(SQLData)^.time_zone;
1288     end;
1289     SQL_TIME_TZ_EX:
1290     begin
1291     GetTimeZoneServices.DecodeTimeTZEx(SQLData,OnDate,aTime,dstOffset,aTimeZone);
1292     aTimeZoneID := PISC_TIME_TZ_EX(SQLData)^.time_zone;
1293     end;
1294     else
1295     IBError(ibxeInvalidDataConversion, [nil]);
1296     end;
1297     end;
1298    
1299     procedure TSQLDataItem.GetAsTime(var aTime: TDateTime; var dstOffset: smallint;
1300     var aTimezone: AnsiString; OnDate: TDateTime);
1301     begin
1302     CheckActive;
1303     aTime := 0;
1304     dstOffset := 0;
1305     if not IsNull then
1306     with FFirebirdClientAPI do
1307     case SQLType of
1308     SQL_TIME_TZ:
1309     GetTimeZoneServices.DecodeTimeTZ(SQLData,OnDate,aTime,dstOffset,aTimeZone);
1310     SQL_TIME_TZ_EX:
1311     GetTimeZoneServices.DecodeTimeTZEx(SQLData,OnDate,aTime,dstOffset,aTimeZone);
1312     else
1313     IBError(ibxeInvalidDataConversion, [nil]);
1314     end;
1315     end;
1316    
1317     procedure TSQLDataItem.GetAsTime(var aTime: TDateTime; var dstOffset: smallint;
1318     var aTimezoneID: TFBTimeZoneID);
1319     begin
1320     GetAsTime(aTime,dstOffset,aTimeZoneID,GetTimeZoneServices.GetTimeTZDate);
1321     end;
1322    
1323     procedure TSQLDataItem.GetAsTime(var aTime: TDateTime; var dstOffset: smallint;
1324     var aTimezone: AnsiString);
1325     begin
1326     GetAsTime(aTime,dstOffset,aTimeZone,GetTimeZoneServices.GetTimeTZDate);
1327     end;
1328    
1329     function TSQLDataItem.GetAsUTCDateTime: TDateTime;
1330     var aTimezone: AnsiString;
1331     begin
1332     CheckActive;
1333 tony 45 result := 0;
1334 tony 315 aTimezone := '';
1335 tony 45 if not IsNull then
1336 tony 263 with FFirebirdClientAPI do
1337 tony 45 case SQLType of
1338 tony 315 SQL_TEXT, SQL_VARYING:
1339     begin
1340     if not ParseDateTimeTZString(AsString,Result,aTimeZone) then
1341     IBError(ibxeInvalidDataConversion, [nil]);
1342     Result := GetTimeZoneServices.LocalTimeToGMT(Result,aTimeZone);
1343 tony 45 end;
1344     SQL_TYPE_DATE:
1345     result := SQLDecodeDate(SQLData);
1346 tony 315 SQL_TYPE_TIME,
1347     SQL_TIME_TZ,
1348     SQL_TIME_TZ_EX:
1349 tony 45 result := SQLDecodeTime(SQLData);
1350 tony 315 SQL_TIMESTAMP,
1351     SQL_TIMESTAMP_TZ,
1352     SQL_TIMESTAMP_TZ_EX:
1353 tony 45 result := SQLDecodeDateTime(SQLData);
1354     else
1355     IBError(ibxeInvalidDataConversion, [nil]);
1356 tony 315 end;
1357 tony 45 end;
1358    
1359     function TSQLDataItem.GetAsDouble: Double;
1360     begin
1361     CheckActive;
1362     result := 0;
1363     if not IsNull then begin
1364     case SQLType of
1365     SQL_TEXT, SQL_VARYING: begin
1366     try
1367     result := StrToFloat(AsString);
1368     except
1369     on E: Exception do IBError(ibxeInvalidDataConversion, [nil]);
1370     end;
1371     end;
1372     SQL_SHORT:
1373 tony 371 result := NumericFromRawValues(Int64(PShort(SQLData)^),
1374     Scale).getAsDouble;
1375 tony 45 SQL_LONG:
1376 tony 371 result := NumericFromRawValues(Int64(PLong(SQLData)^),
1377     Scale).getAsDouble;
1378 tony 45 SQL_INT64:
1379 tony 371 result := NumericFromRawValues(PInt64(SQLData)^, Scale).getAsDouble;
1380 tony 45 SQL_FLOAT:
1381     result := PFloat(SQLData)^;
1382     SQL_DOUBLE, SQL_D_FLOAT:
1383     result := PDouble(SQLData)^;
1384 tony 315 SQL_DEC_FIXED,
1385     SQL_DEC16,
1386     SQL_DEC34,
1387     SQL_INT128:
1388     Result := BCDToDouble(GetAsBCD);
1389 tony 45 else
1390     IBError(ibxeInvalidDataConversion, [nil]);
1391     end;
1392     if Scale <> 0 then
1393     result :=
1394     StrToFloat(FloatToStrF(result, fffixed, 15,
1395     Abs(Scale) ));
1396     end;
1397     end;
1398    
1399     function TSQLDataItem.GetAsFloat: Float;
1400     begin
1401     CheckActive;
1402     result := 0;
1403     try
1404     result := AsDouble;
1405     except
1406     on E: EOverflow do
1407     IBError(ibxeInvalidDataConversion, [nil]);
1408     end;
1409     end;
1410    
1411     function TSQLDataItem.GetAsLong: Long;
1412     begin
1413     CheckActive;
1414     result := 0;
1415     if not IsNull then
1416     case SQLType of
1417     SQL_TEXT, SQL_VARYING: begin
1418     try
1419     result := StrToInt(AsString);
1420     except
1421     on E: Exception do IBError(ibxeInvalidDataConversion, [nil]);
1422     end;
1423     end;
1424     SQL_SHORT:
1425 tony 371 result := NumericFromRawValues(Int64(PShort(SQLData)^),
1426     Scale).getAsInteger;
1427 tony 45 SQL_LONG:
1428 tony 371 result := NumericFromRawValues(Int64(PLong(SQLData)^),
1429     Scale).getAsInteger;
1430 tony 45 SQL_INT64:
1431 tony 371 result := NumericFromRawValues(PInt64(SQLData)^, Scale).getAsInteger;
1432    
1433 tony 45 SQL_DOUBLE, SQL_FLOAT, SQL_D_FLOAT:
1434 tony 345 result := Round(AsDouble);
1435 tony 315 SQL_DEC_FIXED,
1436     SQL_DEC16,
1437     SQL_DEC34,
1438     SQL_INT128:
1439     Result := BCDToInteger(GetAsBCD);
1440 tony 45 else
1441 tony 315 IBError(ibxeInvalidDataConversion, [GetSQLTypeName]);
1442 tony 45 end;
1443     end;
1444    
1445     function TSQLDataItem.GetAsPointer: Pointer;
1446     begin
1447     CheckActive;
1448     if not IsNull then
1449     result := SQLData
1450     else
1451     result := nil;
1452     end;
1453    
1454     function TSQLDataItem.GetAsQuad: TISC_QUAD;
1455     begin
1456     CheckActive;
1457     result.gds_quad_high := 0;
1458     result.gds_quad_low := 0;
1459     if not IsNull then
1460     case SQLType of
1461     SQL_BLOB, SQL_ARRAY, SQL_QUAD:
1462     result := PISC_QUAD(SQLData)^;
1463     else
1464     IBError(ibxeInvalidDataConversion, [nil]);
1465     end;
1466     end;
1467    
1468     function TSQLDataItem.GetAsShort: short;
1469     begin
1470     CheckActive;
1471     result := 0;
1472     try
1473     result := AsLong;
1474     except
1475     on E: Exception do IBError(ibxeInvalidDataConversion, [nil]);
1476     end;
1477     end;
1478    
1479 tony 308 {Copied from LazUTF8}
1480 tony 45
1481 tony 308 function UTF8CodepointSizeFull(p: PAnsiChar): integer;
1482 tony 309 const TopBitSetMask = $80; {%10000000}
1483     Top2BitsSetMask = $C0; {%11000000}
1484     Top3BitsSetMask = $E0; {%11100000}
1485     Top4BitsSetMask = $F0; {%11110000}
1486     Top5BitsSetMask = $F8; {%11111000}
1487 tony 308 begin
1488     case p^ of
1489     #0..#191: // %11000000
1490     // regular single byte character (#0 is a character, this is Pascal ;)
1491     Result:=1;
1492     #192..#223: // p^ and %11100000 = %11000000
1493     begin
1494     // could be 2 byte character
1495     if (ord(p[1]) and Top2BitsSetMask) = TopBitSetMask then
1496     Result:=2
1497     else
1498     Result:=1;
1499     end;
1500     #224..#239: // p^ and %11110000 = %11100000
1501     begin
1502     // could be 3 byte character
1503     if ((ord(p[1]) and Top2BitsSetMask) = TopBitSetMask)
1504     and ((ord(p[2]) and Top2BitsSetMask) = TopBitSetMask) then
1505     Result:=3
1506     else
1507     Result:=1;
1508     end;
1509     #240..#247: // p^ and %11111000 = %11110000
1510     begin
1511     // could be 4 byte character
1512     if ((ord(p[1]) and Top2BitsSetMask) = TopBitSetMask)
1513     and ((ord(p[2]) and Top2BitsSetMask) = TopBitSetMask)
1514     and ((ord(p[3]) and Top2BitsSetMask) = TopBitSetMask) then
1515     Result:=4
1516     else
1517     Result:=1;
1518     end;
1519     else
1520     Result:=1;
1521     end;
1522     end;
1523    
1524     {Returns the byte length of a UTF8 string with a fixed charwidth}
1525    
1526 tony 315 function GetStrLen(p: PAnsiChar; FieldWidth, MaxDataLength: cardinal): integer;
1527 tony 308 var i: integer;
1528     cplen: integer;
1529     begin
1530     Result := 0;
1531 tony 315 for i := 1 to FieldWidth do
1532 tony 308 begin
1533     cplen := UTF8CodepointSizeFull(p);
1534     Inc(p,cplen);
1535     Inc(Result,cplen);
1536     if Result >= MaxDataLength then
1537     begin
1538     Result := MaxDataLength;
1539     Exit;
1540     end;
1541     end;
1542     end;
1543    
1544 tony 56 function TSQLDataItem.GetAsString: AnsiString;
1545 tony 45 var
1546 tony 56 sz: PByte;
1547 tony 45 str_len: Integer;
1548     rs: RawByteString;
1549 tony 315 aTimeZone: AnsiString;
1550     aDateTime: TDateTime;
1551     dstOffset: smallint;
1552 tony 45 begin
1553     CheckActive;
1554     result := '';
1555     { Check null, if so return a default string }
1556     if not IsNull then
1557 tony 263 with FFirebirdClientAPI do
1558 tony 45 case SQLType of
1559     SQL_BOOLEAN:
1560     if AsBoolean then
1561     Result := sTrue
1562     else
1563     Result := SFalse;
1564    
1565     SQL_TEXT, SQL_VARYING:
1566     begin
1567     sz := SQLData;
1568     if (SQLType = SQL_TEXT) then
1569 tony 308 begin
1570     if GetCodePage = cp_utf8 then
1571 tony 309 str_len := GetStrLen(PAnsiChar(sz),GetSize div GetCharSetWidth,DataLength)
1572 tony 308 else
1573     str_len := DataLength
1574     end
1575 tony 45 else begin
1576 tony 308 str_len := DecodeInteger(sz, 2);
1577 tony 45 Inc(sz, 2);
1578     end;
1579 tony 56 SetString(rs, PAnsiChar(sz), str_len);
1580 tony 45 SetCodePage(rs,GetCodePage,false);
1581 tony 308 Result := rs;
1582 tony 45 end;
1583 tony 315
1584 tony 45 SQL_TYPE_DATE:
1585 tony 315 Result := DateToStr(GetAsDateTime);
1586 tony 45 SQL_TIMESTAMP:
1587 tony 315 Result := FBFormatDateTime(GetTimestampFormatStr,GetAsDateTime);
1588     SQL_TYPE_TIME:
1589     Result := FBFormatDateTime(GetTimeFormatStr,GetAsDateTime);
1590     SQL_TIMESTAMP_TZ,
1591     SQL_TIMESTAMP_TZ_EX:
1592     with GetAttachment.GetTimeZoneServices do
1593     begin
1594     if GetTZTextOption = tzGMT then
1595     Result := FBFormatDateTime(GetTimestampFormatStr,GetAsUTCDateTime)
1596     else
1597     begin
1598     GetAsDateTime(aDateTime,dstOffset,aTimeZone);
1599     if GetTZTextOption = tzOffset then
1600     Result := FBFormatDateTime(GetTimestampFormatStr,aDateTime) + ' ' + FormatTimeZoneOffset(dstOffset)
1601     else
1602     Result := FBFormatDateTime(GetTimestampFormatStr,aDateTime) + ' ' + aTimeZone;
1603     end;
1604     end;
1605     SQL_TIME_TZ,
1606     SQL_TIME_TZ_EX:
1607     with GetAttachment.GetTimeZoneServices do
1608     begin
1609     if GetTZTextOption = tzGMT then
1610     Result := FBFormatDateTime(GetTimeFormatStr,GetAsUTCDateTime)
1611     else
1612     begin
1613     GetAsTime(aDateTime,dstOffset,aTimeZone,GetTimeTZDate);
1614     if GetTZTextOption = tzOffset then
1615     Result := FBFormatDateTime(GetTimeFormatStr,aDateTime) + ' ' + FormatTimeZoneOffset(dstOffset)
1616     else
1617     Result := FBFormatDateTime(GetTimeFormatStr,aDateTime) + ' ' + aTimeZone;
1618     end;
1619     end;
1620    
1621 tony 45 SQL_SHORT, SQL_LONG:
1622     if Scale = 0 then
1623     result := IntToStr(AsLong)
1624     else if Scale >= (-4) then
1625     result := CurrToStr(AsCurrency)
1626     else
1627     result := FloatToStr(AsDouble);
1628     SQL_INT64:
1629     if Scale = 0 then
1630     result := IntToStr(AsInt64)
1631     else if Scale >= (-4) then
1632     result := CurrToStr(AsCurrency)
1633     else
1634     result := FloatToStr(AsDouble);
1635     SQL_DOUBLE, SQL_FLOAT, SQL_D_FLOAT:
1636     result := FloatToStr(AsDouble);
1637 tony 315
1638     SQL_DEC16,
1639     SQL_DEC34:
1640     result := BCDToStr(GetAsBCD);
1641    
1642     SQL_DEC_FIXED,
1643     SQL_INT128:
1644     result := Int128ToStr(SQLData,scale);
1645    
1646 tony 45 else
1647 tony 371 IBError(ibxeInvalidDataConversion, [GetSQLTypeName]);
1648 tony 45 end;
1649     end;
1650    
1651 tony 371 function TSQLDataItem.GetAsNumeric: IFBNumeric;
1652     var aValue: Int64;
1653     begin
1654     case SQLType of
1655     SQL_TEXT, SQL_VARYING:
1656     Result := NewNumeric(GetAsString);
1657    
1658     SQL_SHORT:
1659     Result := NumericFromRawValues(PShort(SQLData)^, Scale);
1660    
1661     SQL_LONG:
1662     Result := NumericFromRawValues(PLong(SQLData)^, Scale);
1663    
1664     SQL_INT64:
1665     Result := NumericFromRawValues(PInt64(SQLData)^, Scale);
1666    
1667     SQL_DEC16,
1668     SQL_DEC34,
1669     SQL_DEC_FIXED,
1670     SQL_INT128:
1671     Result := NewNumeric(GetAsBCD);
1672    
1673     else
1674     IBError(ibxeInvalidDataConversion, [nil]);
1675     end;
1676     end;
1677    
1678 tony 45 function TSQLDataItem.GetIsNull: Boolean;
1679     begin
1680     CheckActive;
1681     Result := false;
1682     end;
1683    
1684 tony 270 function TSQLDataItem.GetIsNullable: boolean;
1685 tony 45 begin
1686     CheckActive;
1687     Result := false;
1688     end;
1689    
1690     function TSQLDataItem.GetAsVariant: Variant;
1691 tony 315 var ts: TDateTime;
1692     dstOffset: smallint;
1693     timezone: AnsiString;
1694 tony 45 begin
1695     CheckActive;
1696     if IsNull then
1697     result := NULL
1698     { Check null, if so return a default string }
1699     else case SQLType of
1700     SQL_ARRAY:
1701     result := '(Array)'; {do not localize}
1702     SQL_BLOB,
1703     SQL_TEXT, SQL_VARYING:
1704     result := AsString;
1705     SQL_TIMESTAMP, SQL_TYPE_DATE, SQL_TYPE_TIME:
1706     result := AsDateTime;
1707 tony 315 SQL_TIMESTAMP_TZ,
1708     SQL_TIME_TZ,
1709     SQL_TIMESTAMP_TZ_EX,
1710     SQL_TIME_TZ_EX:
1711     begin
1712     GetAsDateTime(ts,dstOffset,timezone);
1713     result := VarArrayOf([ts,dstOffset,timezone]);
1714     end;
1715 tony 45 SQL_SHORT, SQL_LONG:
1716     if Scale = 0 then
1717     result := AsLong
1718     else if Scale >= (-4) then
1719     result := AsCurrency
1720     else
1721     result := AsDouble;
1722     SQL_INT64:
1723     if Scale = 0 then
1724     result := AsInt64
1725     else if Scale >= (-4) then
1726     result := AsCurrency
1727     else
1728     result := AsDouble;
1729     SQL_DOUBLE, SQL_FLOAT, SQL_D_FLOAT:
1730     result := AsDouble;
1731     SQL_BOOLEAN:
1732     result := AsBoolean;
1733 tony 315 SQL_DEC_FIXED,
1734     SQL_DEC16,
1735     SQL_DEC34,
1736     SQL_INT128:
1737     result := VarFmtBCDCreate(GetAsBcd);
1738 tony 45 else
1739     IBError(ibxeInvalidDataConversion, [nil]);
1740     end;
1741     end;
1742    
1743     function TSQLDataItem.GetModified: boolean;
1744     begin
1745     Result := false;
1746     end;
1747    
1748 tony 270 function TSQLDataItem.GetDateTimeStrLength(DateTimeFormat: TIBDateTimeFormats
1749     ): integer;
1750     begin
1751     case DateTimeFormat of
1752     dfTimestamp:
1753     Result := Length(GetTimestampFormatStr);
1754     dfDateTime:
1755     Result := Length(GetDateFormatStr(true));
1756     dfTime:
1757     Result := Length(GetTimeFormatStr);
1758 tony 315 dfTimestampTZ:
1759     Result := Length(GetTimestampFormatStr) + 6; {assume time offset format}
1760     dfTimeTZ:
1761     Result := Length(GetTimeFormatStr)+ 6;
1762 tony 270 else
1763     Result := 0;
1764 tony 315 end;end;
1765    
1766     function TSQLDataItem.GetAsBCD: tBCD;
1767    
1768     begin
1769     CheckActive;
1770     if IsNull then
1771     with Result do
1772     begin
1773     FillChar(Result,sizeof(Result),0);
1774     Precision := 1;
1775     exit;
1776     end;
1777    
1778     case SQLType of
1779     SQL_DEC16,
1780     SQL_DEC34:
1781     with FFirebirdClientAPI do
1782     Result := SQLDecFloatDecode(SQLType, SQLData);
1783    
1784     SQL_DEC_FIXED,
1785     SQL_INT128:
1786     with FFirebirdClientAPI do
1787     Result := StrToBCD(Int128ToStr(SQLData,scale));
1788     else
1789     if not CurrToBCD(GetAsCurrency,Result) then
1790     IBError(ibxeBadBCDConversion,[]);
1791 tony 270 end;
1792     end;
1793 tony 45
1794 tony 270
1795 tony 45 procedure TSQLDataItem.SetIsNull(Value: Boolean);
1796     begin
1797     //ignore unless overridden
1798     end;
1799    
1800     procedure TSQLDataItem.SetIsNullable(Value: Boolean);
1801     begin
1802     //ignore unless overridden
1803     end;
1804    
1805 tony 56 procedure TSQLDataItem.SetName(aValue: AnsiString);
1806 tony 45 begin
1807     //ignore unless overridden
1808     end;
1809    
1810     procedure TSQLDataItem.SetAsCurrency(Value: Currency);
1811     begin
1812     CheckActive;
1813     if GetSQLDialect < 3 then
1814     AsDouble := Value
1815     else
1816 tony 371 if not CanChangeMetaData and ((SQLType <> SQL_INT64) or (Scale <> -4)) then
1817     SetAsNumeric(NewNumeric(Value))
1818     else
1819 tony 45 begin
1820     Changing;
1821     if IsNullable then
1822     IsNull := False;
1823     SQLType := SQL_INT64;
1824     Scale := -4;
1825     DataLength := SizeOf(Int64);
1826     PCurrency(SQLData)^ := Value;
1827     Changed;
1828     end;
1829     end;
1830    
1831     procedure TSQLDataItem.SetAsInt64(Value: Int64);
1832     begin
1833     CheckActive;
1834 tony 371 if not CanChangeMetaData and ((SQLType <> SQL_INT64) or (Scale <> 0)) then
1835     SetAsNumeric(NewNumeric(Value))
1836     else
1837     begin
1838     Changing;
1839     if IsNullable then
1840     IsNull := False;
1841 tony 45
1842 tony 371 SQLType := SQL_INT64;
1843     Scale := 0;
1844     DataLength := SizeOf(Int64);
1845     PInt64(SQLData)^ := Value;
1846     Changed;
1847     end;
1848 tony 45 end;
1849    
1850     procedure TSQLDataItem.SetAsDate(Value: TDateTime);
1851     begin
1852     CheckActive;
1853     if GetSQLDialect < 3 then
1854     begin
1855     AsDateTime := Value;
1856     exit;
1857     end;
1858    
1859     Changing;
1860     if IsNullable then
1861     IsNull := False;
1862    
1863     SQLType := SQL_TYPE_DATE;
1864     DataLength := SizeOf(ISC_DATE);
1865 tony 263 with FFirebirdClientAPI do
1866 tony 45 SQLEncodeDate(Value,SQLData);
1867     Changed;
1868     end;
1869    
1870     procedure TSQLDataItem.SetAsTime(Value: TDateTime);
1871     begin
1872     CheckActive;
1873     if GetSQLDialect < 3 then
1874     begin
1875     AsDateTime := Value;
1876     exit;
1877     end;
1878    
1879     Changing;
1880     if IsNullable then
1881     IsNull := False;
1882    
1883     SQLType := SQL_TYPE_TIME;
1884     DataLength := SizeOf(ISC_TIME);
1885 tony 263 with FFirebirdClientAPI do
1886 tony 45 SQLEncodeTime(Value,SQLData);
1887     Changed;
1888     end;
1889    
1890 tony 315 procedure TSQLDataItem.SetAsTime(aValue: TDateTime; OnDate: TDateTime; aTimeZoneID: TFBTimeZoneID);
1891     begin
1892     CheckActive;
1893     CheckTZSupport;
1894     if GetSQLDialect < 3 then
1895     begin
1896     AsDateTime := aValue;
1897     exit;
1898     end;
1899    
1900     Changing;
1901     if IsNullable then
1902     IsNull := False;
1903    
1904     SQLType := SQL_TIME_TZ;
1905     DataLength := SizeOf(ISC_TIME_TZ);
1906     GetTimeZoneServices.EncodeTimeTZ(aValue, aTimeZoneID,OnDate,SQLData);
1907     Changed;
1908     end;
1909    
1910     procedure TSQLDataItem.SetAsTime(aValue: TDateTime; OnDate: TDateTime; aTimeZone: AnsiString);
1911     begin
1912     CheckActive;
1913     CheckTZSupport;
1914     if GetSQLDialect < 3 then
1915     begin
1916     AsDateTime := aValue;
1917     exit;
1918     end;
1919    
1920     Changing;
1921     if IsNullable then
1922     IsNull := False;
1923    
1924     SQLType := SQL_TIME_TZ;
1925     DataLength := SizeOf(ISC_TIME_TZ);
1926     GetTimeZoneServices.EncodeTimeTZ(aValue, aTimeZone,OnDate,SQLData);
1927     Changed;
1928     end;
1929    
1930 tony 45 procedure TSQLDataItem.SetAsDateTime(Value: TDateTime);
1931     begin
1932     CheckActive;
1933     if IsNullable then
1934     IsNull := False;
1935    
1936     Changing;
1937     SQLType := SQL_TIMESTAMP;
1938 tony 47 DataLength := SizeOf(ISC_TIME) + sizeof(ISC_DATE);
1939 tony 263 with FFirebirdClientAPI do
1940 tony 45 SQLEncodeDateTime(Value,SQLData);
1941     Changed;
1942     end;
1943    
1944 tony 315 procedure TSQLDataItem.SetAsDateTime(aValue: TDateTime;
1945     aTimeZoneID: TFBTimeZoneID);
1946     begin
1947     CheckActive;
1948     CheckTZSupport;
1949     if IsNullable then
1950     IsNull := False;
1951    
1952     Changing;
1953     SQLType := SQL_TIMESTAMP_TZ;
1954     DataLength := SizeOf(ISC_TIMESTAMP_TZ);
1955     GetTimeZoneServices.EncodeTimestampTZ(aValue,aTimeZoneID,SQLData);
1956     Changed;
1957     end;
1958    
1959     procedure TSQLDataItem.SetAsDateTime(aValue: TDateTime; aTimeZone: AnsiString
1960     );
1961     begin
1962     CheckActive;
1963     CheckTZSupport;
1964     if IsNullable then
1965     IsNull := False;
1966    
1967     Changing;
1968     SQLType := SQL_TIMESTAMP_TZ;
1969     DataLength := SizeOf(ISC_TIMESTAMP_TZ);
1970     GetTimeZoneServices.EncodeTimestampTZ(aValue,aTimeZone,SQLData);
1971     Changed;
1972     end;
1973    
1974     procedure TSQLDataItem.SetAsUTCDateTime(aUTCTime: TDateTime);
1975     begin
1976     SetAsDateTime(aUTCTime,TimeZoneID_GMT);
1977     end;
1978    
1979 tony 45 procedure TSQLDataItem.SetAsDouble(Value: Double);
1980     begin
1981     CheckActive;
1982     if IsNullable then
1983     IsNull := False;
1984    
1985     Changing;
1986     SQLType := SQL_DOUBLE;
1987     DataLength := SizeOf(Double);
1988     Scale := 0;
1989     PDouble(SQLData)^ := Value;
1990     Changed;
1991     end;
1992    
1993     procedure TSQLDataItem.SetAsFloat(Value: Float);
1994     begin
1995     CheckActive;
1996     if IsNullable then
1997     IsNull := False;
1998    
1999     Changing;
2000     SQLType := SQL_FLOAT;
2001     DataLength := SizeOf(Float);
2002     Scale := 0;
2003     PSingle(SQLData)^ := Value;
2004     Changed;
2005     end;
2006    
2007     procedure TSQLDataItem.SetAsLong(Value: Long);
2008     begin
2009     CheckActive;
2010 tony 371 if not CanChangeMetaData and ((SQLType <> SQL_LONG) or (Scale <> 0)) then
2011     SetAsNumeric(NewNumeric(Value))
2012     else
2013     begin
2014     if IsNullable then
2015     IsNull := False;
2016 tony 45
2017 tony 371 Changing;
2018     SQLType := SQL_LONG;
2019     DataLength := SizeOf(Long);
2020     Scale := 0;
2021     PLong(SQLData)^ := Value;
2022     Changed;
2023     end;
2024 tony 45 end;
2025    
2026     procedure TSQLDataItem.SetAsPointer(Value: Pointer);
2027     begin
2028     CheckActive;
2029     Changing;
2030     if IsNullable and (Value = nil) then
2031     IsNull := True
2032     else
2033     begin
2034     IsNull := False;
2035     SQLType := SQL_TEXT;
2036     Move(Value^, SQLData^, DataLength);
2037     end;
2038     Changed;
2039     end;
2040    
2041     procedure TSQLDataItem.SetAsQuad(Value: TISC_QUAD);
2042     begin
2043     CheckActive;
2044     Changing;
2045     if IsNullable then
2046     IsNull := False;
2047     if (SQLType <> SQL_BLOB) and
2048     (SQLType <> SQL_ARRAY) then
2049     IBError(ibxeInvalidDataConversion, [nil]);
2050     DataLength := SizeOf(TISC_QUAD);
2051     PISC_QUAD(SQLData)^ := Value;
2052     Changed;
2053     end;
2054    
2055     procedure TSQLDataItem.SetAsShort(Value: short);
2056     begin
2057     CheckActive;
2058 tony 371 if not CanChangeMetaData and ((SQLType <> SQL_SHORT) or (Scale <> 0)) then
2059     SetAsNumeric(NewNumeric(Value))
2060     else
2061     begin
2062     Changing;
2063     if IsNullable then
2064     IsNull := False;
2065 tony 45
2066 tony 371 SQLType := SQL_SHORT;
2067     DataLength := SizeOf(Short);
2068     Scale := 0;
2069     PShort(SQLData)^ := Value;
2070     Changed;
2071     end;
2072 tony 45 end;
2073    
2074 tony 56 procedure TSQLDataItem.SetAsString(Value: AnsiString);
2075 tony 45 begin
2076     InternalSetAsString(Value);
2077     end;
2078    
2079     procedure TSQLDataItem.SetAsVariant(Value: Variant);
2080     begin
2081     CheckActive;
2082     if VarIsNull(Value) then
2083     IsNull := True
2084 tony 315 else
2085     if VarIsArray(Value) then {must be datetime plus timezone}
2086     SetAsDateTime(Value[0],AnsiString(Value[1]))
2087 tony 45 else case VarType(Value) of
2088     varEmpty, varNull:
2089     IsNull := True;
2090     varSmallint, varInteger, varByte,
2091 tony 371 varWord, varShortInt, varInt64:
2092     SetAsNumeric(NewNumeric(Int64(Value)));
2093 tony 45 varSingle, varDouble:
2094     AsDouble := Value;
2095     varCurrency:
2096 tony 371 SetAsNumeric(NewNumeric(Currency(Value)));
2097 tony 45 varBoolean:
2098     AsBoolean := Value;
2099     varDate:
2100     AsDateTime := Value;
2101     varOleStr, varString:
2102     AsString := Value;
2103     varArray:
2104     IBError(ibxeNotSupported, [nil]);
2105     varByRef, varDispatch, varError, varUnknown, varVariant:
2106     IBError(ibxeNotPermitted, [nil]);
2107 tony 315 else
2108     if VarIsFmtBCD(Value) then
2109     SetAsBCD(VarToBCD(Value))
2110     else
2111     IBError(ibxeNotSupported, [nil]);
2112 tony 45 end;
2113     end;
2114    
2115 tony 371 procedure TSQLDataItem.SetAsNumeric(Value: IFBNumeric);
2116 tony 59 begin
2117     CheckActive;
2118     Changing;
2119     if IsNullable then
2120     IsNull := False;
2121    
2122 tony 371 if CanChangeMetadata then
2123     begin
2124     {Restore original values}
2125     SQLType := getColMetadata.GetSQLType;
2126     Scale := getColMetadata.getScale;
2127     SetDataLength(getColMetadata.GetSize);
2128     end;
2129    
2130     with FFirebirdClientAPI do
2131     case GetSQLType of
2132     SQL_LONG:
2133     PLong(SQLData)^ := SafeInteger(Value.clone(Scale).getRawValue);
2134     SQL_SHORT:
2135     PShort(SQLData)^ := SafeSmallInt(Value.clone(Scale).getRawValue);
2136     SQL_INT64:
2137     PInt64(SQLData)^ := Value.clone(Scale).getRawValue;
2138     SQL_TEXT, SQL_VARYING:
2139     SetAsString(Value.getAsString);
2140     SQL_D_FLOAT,
2141     SQL_DOUBLE:
2142     PDouble(SQLData)^ := Value.getAsDouble;
2143     SQL_FLOAT:
2144     PSingle(SQLData)^ := Value.getAsDouble;
2145     SQL_DEC_FIXED,
2146     SQL_DEC16,
2147     SQL_DEC34:
2148     SQLDecFloatEncode(Value.getAsBCD,SQLType,SQLData);
2149     SQL_INT128:
2150     StrToInt128(Scale,Value.getAsString,SQLData);
2151     else
2152     IBError(ibxeInvalidDataConversion, [nil]);
2153     end;
2154 tony 59 Changed;
2155     end;
2156    
2157 tony 315 procedure TSQLDataItem.SetAsBcd(aValue: tBCD);
2158     begin
2159     CheckActive;
2160     Changing;
2161     if IsNullable then
2162     IsNull := False;
2163    
2164 tony 371 if not CanChangeMetaData then
2165     begin
2166     SetAsNumeric(NewNumeric(aValue));
2167     Exit;
2168     end;
2169 tony 315
2170     with FFirebirdClientAPI do
2171     if aValue.Precision <= 16 then
2172     begin
2173     if not HasDecFloatSupport then
2174     IBError(ibxeDecFloatNotSupported,[]);
2175    
2176     SQLType := SQL_DEC16;
2177     DataLength := 8;
2178     SQLDecFloatEncode(aValue,SQLType,SQLData);
2179     end
2180     else
2181     if aValue.Precision <= 34 then
2182     begin
2183     if not HasDecFloatSupport then
2184     IBError(ibxeDecFloatNotSupported,[]);
2185    
2186     SQLType := SQL_DEC34;
2187     DataLength := 16;
2188     SQLDecFloatEncode(aValue,SQLType,SQLData);
2189     end
2190     else
2191     if aValue.Precision <= 38 then
2192     begin
2193     if not HasInt128Support then
2194     IBError(ibxeInt128NotSupported,[]);
2195    
2196     SQLType := SQL_INT128;
2197     DataLength := 16;
2198     StrToInt128(scale,BcdToStr(aValue),SQLData);
2199     end
2200     else
2201     IBError(ibxeBCDOverflow,[BCDToStr(aValue)]);
2202    
2203     Changed;
2204     end;
2205    
2206 tony 45 procedure TSQLDataItem.SetAsBoolean(AValue: boolean);
2207     begin
2208     CheckActive;
2209     Changing;
2210     if IsNullable then
2211     IsNull := False;
2212    
2213     SQLType := SQL_BOOLEAN;
2214     DataLength := 1;
2215     Scale := 0;
2216     if AValue then
2217     PByte(SQLData)^ := ISC_TRUE
2218     else
2219     PByte(SQLData)^ := ISC_FALSE;
2220     Changed;
2221     end;
2222    
2223     {TColumnMetaData}
2224    
2225     procedure TColumnMetaData.CheckActive;
2226     begin
2227     if not FIBXSQLVAR.Parent.StateChanged(FChangeSeqNo) then Exit;
2228    
2229     if FPrepareSeqNo < FIBXSQLVAR.Parent.GetPrepareSeqNo then
2230     IBError(ibxeInterfaceOutofDate,[nil]);
2231    
2232     if not FIBXSQLVAR.Parent.CheckStatementStatus(ssPrepared) then
2233     IBError(ibxeStatementNotPrepared, [nil]);
2234     end;
2235    
2236 tony 315 function TColumnMetaData.GetAttachment: IAttachment;
2237     begin
2238 tony 371 Result := FIBXSQLVAR.GetAttachment;
2239 tony 315 end;
2240    
2241 tony 56 function TColumnMetaData.SQLData: PByte;
2242 tony 45 begin
2243     Result := FIBXSQLVAR.SQLData;
2244     end;
2245    
2246     function TColumnMetaData.GetDataLength: cardinal;
2247     begin
2248     Result := FIBXSQLVAR.DataLength;
2249     end;
2250    
2251     function TColumnMetaData.GetCodePage: TSystemCodePage;
2252     begin
2253     Result := FIBXSQLVAR.GetCodePage;
2254     end;
2255    
2256     constructor TColumnMetaData.Create(aOwner: IUnknown; aIBXSQLVAR: TSQLVarData);
2257     begin
2258 tony 371 inherited Create(aIBXSQLVAR.GetAttachment.getFirebirdAPI as TFBClientAPI);
2259 tony 45 FIBXSQLVAR := aIBXSQLVAR;
2260     FOwner := aOwner;
2261     FPrepareSeqNo := FIBXSQLVAR.Parent.PrepareSeqNo;
2262     FIBXSQLVAR.Parent.StateChanged(FChangeSeqNo)
2263     end;
2264    
2265     destructor TColumnMetaData.Destroy;
2266     begin
2267     (FOwner as TInterfaceOwner).Remove(self);
2268     inherited Destroy;
2269     end;
2270    
2271    
2272     function TColumnMetaData.GetSQLDialect: integer;
2273     begin
2274 tony 371 Result := FIBXSQLVAR.GetAttachment.GetSQLDialect;
2275 tony 45 end;
2276    
2277 tony 371 function TColumnMetaData.getColMetadata: IParamMetaData;
2278     begin
2279     Result := self;
2280     end;
2281    
2282 tony 45 function TColumnMetaData.GetIndex: integer;
2283     begin
2284     Result := FIBXSQLVAR.Index;
2285     end;
2286    
2287     function TColumnMetaData.GetSQLType: cardinal;
2288     begin
2289     CheckActive;
2290     result := FIBXSQLVAR.SQLType;
2291     end;
2292    
2293     function TColumnMetaData.getSubtype: integer;
2294     begin
2295     CheckActive;
2296     result := FIBXSQLVAR.SQLSubtype;
2297     end;
2298    
2299 tony 56 function TColumnMetaData.getRelationName: AnsiString;
2300 tony 45 begin
2301     CheckActive;
2302     result := FIBXSQLVAR.RelationName;
2303     end;
2304    
2305 tony 56 function TColumnMetaData.getOwnerName: AnsiString;
2306 tony 45 begin
2307     CheckActive;
2308     result := FIBXSQLVAR.OwnerName;
2309     end;
2310    
2311 tony 56 function TColumnMetaData.getSQLName: AnsiString;
2312 tony 45 begin
2313     CheckActive;
2314     result := FIBXSQLVAR.FieldName;
2315     end;
2316    
2317 tony 56 function TColumnMetaData.getAliasName: AnsiString;
2318 tony 45 begin
2319     CheckActive;
2320     result := FIBXSQLVAR.AliasName;
2321     end;
2322    
2323 tony 56 function TColumnMetaData.GetName: AnsiString;
2324 tony 45 begin
2325     CheckActive;
2326     Result := FIBXSQLVAR. Name;
2327     end;
2328    
2329     function TColumnMetaData.GetScale: integer;
2330     begin
2331     CheckActive;
2332     result := FIBXSQLVAR.Scale;
2333     end;
2334    
2335     function TColumnMetaData.getCharSetID: cardinal;
2336     begin
2337     CheckActive;
2338     Result := FIBXSQLVAR.CharSetID;
2339     end;
2340    
2341     function TColumnMetaData.GetIsNullable: boolean;
2342     begin
2343     CheckActive;
2344     result := FIBXSQLVAR.IsNullable;
2345     end;
2346    
2347     function TColumnMetaData.GetSize: cardinal;
2348     begin
2349     CheckActive;
2350 tony 315 result := FIBXSQLVAR.GetSize;
2351 tony 45 end;
2352    
2353 tony 309 function TColumnMetaData.GetCharSetWidth: integer;
2354     begin
2355     CheckActive;
2356     result := FIBXSQLVAR.GetCharSetWidth;
2357     end;
2358    
2359 tony 45 function TColumnMetaData.GetArrayMetaData: IArrayMetaData;
2360     begin
2361     CheckActive;
2362     result := FIBXSQLVAR.GetArrayMetaData;
2363     end;
2364    
2365     function TColumnMetaData.GetBlobMetaData: IBlobMetaData;
2366     begin
2367     CheckActive;
2368     result := FIBXSQLVAR.GetBlobMetaData;
2369     end;
2370    
2371 tony 291 function TColumnMetaData.GetStatement: IStatement;
2372     begin
2373     Result := FIBXSQLVAR.GetStatement;
2374     end;
2375    
2376     function TColumnMetaData.GetTransaction: ITransaction;
2377     begin
2378 tony 371 Result := FIBXSQLVAR.GetTransaction;
2379 tony 291 end;
2380    
2381 tony 45 { TIBSQLData }
2382    
2383     procedure TIBSQLData.CheckActive;
2384     begin
2385     if not FIBXSQLVAR.Parent.StateChanged(FChangeSeqNo) then Exit;
2386    
2387     inherited CheckActive;
2388    
2389     if not FIBXSQLVAR.Parent.CheckStatementStatus(ssCursorOpen) and
2390     not FIBXSQLVAR.Parent.CheckStatementStatus(ssExecuteResults) then
2391     IBError(ibxeSQLClosed, [nil]);
2392    
2393     if FIBXSQLVAR.Parent.CheckStatementStatus(ssEOF) then
2394     IBError(ibxeEOF,[nil]);
2395    
2396     if FIBXSQLVAR.Parent.CheckStatementStatus(ssBOF) then
2397     IBError(ibxeBOF,[nil]);
2398     end;
2399    
2400     function TIBSQLData.GetIsNull: Boolean;
2401     begin
2402     CheckActive;
2403     result := FIBXSQLVAR.IsNull;
2404     end;
2405    
2406     function TIBSQLData.GetAsArray: IArray;
2407     begin
2408     CheckActive;
2409 tony 363 result := FIBXSQLVAR.GetAsArray;
2410 tony 45 end;
2411    
2412     function TIBSQLData.GetAsBlob: IBlob;
2413     begin
2414     CheckActive;
2415     result := FIBXSQLVAR.GetAsBlob(AsQuad,nil);
2416     end;
2417    
2418     function TIBSQLData.GetAsBlob(BPB: IBPB): IBlob;
2419     begin
2420     CheckActive;
2421     result := FIBXSQLVAR.GetAsBlob(AsQuad,BPB);
2422     end;
2423    
2424 tony 56 function TIBSQLData.GetAsString: AnsiString;
2425 tony 45 begin
2426     CheckActive;
2427     Result := '';
2428     { Check null, if so return a default string }
2429     if not IsNull then
2430     case SQLType of
2431     SQL_ARRAY:
2432 tony 47 result := SArray;
2433 tony 45 SQL_BLOB:
2434 tony 47 Result := FIBXSQLVAR.GetAsBlob(AsQuad,nil).GetAsString;
2435 tony 45 else
2436     Result := inherited GetAsString;
2437     end;
2438     end;
2439    
2440     { TSQLParam }
2441    
2442 tony 56 procedure TSQLParam.InternalSetAsString(Value: AnsiString);
2443 tony 270
2444     procedure DoSetString;
2445     begin
2446     Changing;
2447     FIBXSQLVar.SetString(Transliterate(Value,GetCodePage));
2448     Changed;
2449     end;
2450    
2451 tony 45 var b: IBlob;
2452 tony 59 dt: TDateTime;
2453 tony 315 timezone: AnsiString;
2454 tony 349 Int64Value: Int64;
2455     BCDValue: TBCD;
2456     aScale: integer;
2457 tony 45 begin
2458     CheckActive;
2459     if IsNullable then
2460     IsNull := False;
2461 tony 315 with FFirebirdClientAPI do
2462 tony 371 case SQLTYPE of
2463 tony 45 SQL_BOOLEAN:
2464 tony 56 if AnsiCompareText(Value,STrue) = 0 then
2465 tony 45 AsBoolean := true
2466     else
2467 tony 56 if AnsiCompareText(Value,SFalse) = 0 then
2468 tony 45 AsBoolean := false
2469     else
2470     IBError(ibxeInvalidDataConversion,[nil]);
2471    
2472     SQL_BLOB:
2473 tony 345 if Length(Value) < GetAttachment.GetInlineBlobLimit then
2474     DoSetString
2475     else
2476 tony 45 begin
2477     Changing;
2478     b := FIBXSQLVAR.CreateBlob;
2479     b.SetAsString(Value);
2480     AsBlob := b;
2481     Changed;
2482     end;
2483    
2484     SQL_VARYING,
2485     SQL_TEXT:
2486 tony 270 DoSetString;
2487 tony 45
2488 tony 349 SQL_SHORT,
2489     SQL_LONG,
2490     SQL_INT64:
2491 tony 350 if TryStrToNumeric(Value,Int64Value,aScale) then
2492 tony 371 SetAsNumeric(NumericFromRawValues(Int64Value,aScale))
2493 tony 349 else
2494     DoSetString;
2495 tony 45
2496 tony 349 SQL_DEC_FIXED,
2497     SQL_DEC16,
2498     SQL_DEC34,
2499     SQL_INT128:
2500     if TryStrToBCD(Value,BCDValue) then
2501 tony 371 SetAsNumeric(NewNumeric(BCDValue))
2502 tony 349 else
2503     DoSetString;
2504    
2505     SQL_D_FLOAT,
2506     SQL_DOUBLE,
2507     SQL_FLOAT:
2508 tony 353 if TryStrToNumeric(Value,Int64Value,aScale) then
2509 tony 371 SetAsNumeric(NumericFromRawValues(Int64Value,AScale))
2510 tony 349 else
2511     DoSetString;
2512    
2513     SQL_TIMESTAMP:
2514 tony 59 if TryStrToDateTime(Value,dt) then
2515     SetAsDateTime(dt)
2516     else
2517 tony 270 DoSetString;
2518 tony 45
2519 tony 349 SQL_TYPE_DATE:
2520 tony 59 if TryStrToDateTime(Value,dt) then
2521     SetAsDate(dt)
2522     else
2523 tony 270 DoSetString;
2524 tony 45
2525 tony 349 SQL_TYPE_TIME:
2526 tony 59 if TryStrToDateTime(Value,dt) then
2527     SetAsTime(dt)
2528     else
2529 tony 270 DoSetString;
2530 tony 45
2531 tony 349 SQL_TIMESTAMP_TZ,
2532     SQL_TIMESTAMP_TZ_EX:
2533 tony 315 if ParseDateTimeTZString(value,dt,timezone) then
2534     SetAsDateTime(dt,timezone)
2535     else
2536     DoSetString;
2537    
2538 tony 349 SQL_TIME_TZ,
2539     SQL_TIME_TZ_EX:
2540 tony 315 if ParseDateTimeTZString(value,dt,timezone,true) then
2541     SetAsTime(dt,GetAttachment.GetTimeZoneServices.GetTimeTZDate,timezone)
2542     else
2543     DoSetString;
2544    
2545 tony 349 else
2546     IBError(ibxeInvalidDataConversion,[GetSQLTypeName(getColMetaData.SQLTYPE)]);
2547 tony 45 end;
2548     end;
2549    
2550     procedure TSQLParam.CheckActive;
2551     begin
2552     if not FIBXSQLVAR.Parent.StateChanged(FChangeSeqNo) then Exit;
2553    
2554     if FPrepareSeqNo < FIBXSQLVAR.Parent.GetPrepareSeqNo then
2555     IBError(ibxeInterfaceOutofDate,[nil]);
2556    
2557     if not FIBXSQLVAR.Parent.CheckStatementStatus(ssPrepared) then
2558     IBError(ibxeStatementNotPrepared, [nil]);
2559     end;
2560    
2561     procedure TSQLParam.SetScale(aValue: integer);
2562     begin
2563     CheckActive;
2564     FIBXSQLVAR.Scale := aValue;
2565     end;
2566    
2567     procedure TSQLParam.SetDataLength(len: cardinal);
2568     begin
2569     CheckActive;
2570     FIBXSQLVAR.DataLength := len;
2571     end;
2572    
2573     procedure TSQLParam.SetSQLType(aValue: cardinal);
2574     begin
2575     CheckActive;
2576     FIBXSQLVAR.SQLType := aValue;
2577     end;
2578    
2579     procedure TSQLParam.Clear;
2580     begin
2581     IsNull := true;
2582     end;
2583    
2584 tony 371 function TSQLParam.CanChangeMetaData: boolean;
2585     begin
2586     Result := FIBXSQLVAR.CanChangeMetaData;
2587     end;
2588    
2589 tony 349 function TSQLParam.getColMetadata: IParamMetaData;
2590     begin
2591     Result := FIBXSQLVAR.getColMetadata;
2592     end;
2593    
2594 tony 45 function TSQLParam.GetModified: boolean;
2595     begin
2596     CheckActive;
2597     Result := FIBXSQLVAR.Modified;
2598     end;
2599    
2600     function TSQLParam.GetAsPointer: Pointer;
2601     begin
2602     IsNull := false; {Assume that we get the pointer in order to set a value}
2603     Changed;
2604     Result := inherited GetAsPointer;
2605     end;
2606    
2607 tony 345 function TSQLParam.GetAsString: AnsiString;
2608     var rs: RawByteString;
2609     begin
2610     Result := '';
2611     if (SQLType = SQL_VARYING) and not IsNull then
2612     {SQLData points to start of string - default is to length word}
2613     begin
2614     CheckActive;
2615     SetString(rs,PAnsiChar(SQLData),DataLength);
2616     SetCodePage(rs,GetCodePage,false);
2617     Result := rs;
2618     end
2619     else
2620     Result := inherited GetAsString;
2621     end;
2622    
2623 tony 56 procedure TSQLParam.SetName(Value: AnsiString);
2624 tony 45 begin
2625     CheckActive;
2626     FIBXSQLVAR.Name := Value;
2627     end;
2628    
2629     procedure TSQLParam.SetIsNull(Value: Boolean);
2630     var i: integer;
2631     begin
2632     CheckActive;
2633     if FIBXSQLVAR.UniqueName then
2634     FIBXSQLVAR.IsNull := Value
2635     else
2636     with FIBXSQLVAR.Parent do
2637     begin
2638     for i := 0 to Count - 1 do
2639     if Column[i].Name = Name then
2640     Column[i].IsNull := Value;
2641     end
2642     end;
2643    
2644     procedure TSQLParam.SetIsNullable(Value: Boolean);
2645     var i: integer;
2646     begin
2647     CheckActive;
2648     if FIBXSQLVAR.UniqueName then
2649     FIBXSQLVAR.IsNullable := Value
2650     else
2651     with FIBXSQLVAR.Parent do
2652     begin
2653     for i := 0 to Count - 1 do
2654     if Column[i].Name = Name then
2655     Column[i].IsNullable := Value;
2656     end
2657     end;
2658    
2659     procedure TSQLParam.SetAsArray(anArray: IArray);
2660     begin
2661     CheckActive;
2662     if GetSQLType <> SQL_ARRAY then
2663     IBError(ibxeInvalidDataConversion,[nil]);
2664    
2665     if not FIBXSQLVAR.UniqueName then
2666     IBError(ibxeDuplicateParamName,[FIBXSQLVAR.Name]);
2667    
2668 tony 363 FIBXSQLVAR.SetArray(anArray); {save array interface}
2669 tony 45 SetAsQuad(AnArray.GetArrayID);
2670     end;
2671    
2672     procedure TSQLParam.Changed;
2673     begin
2674     FIBXSQLVAR.Changed;
2675     end;
2676    
2677     procedure TSQLParam.SetAsBoolean(AValue: boolean);
2678     var i: integer;
2679     OldSQLVar: TSQLVarData;
2680     begin
2681     if FIBXSQLVAR.UniqueName then
2682     inherited SetAsBoolean(AValue)
2683     else
2684     with FIBXSQLVAR.Parent do
2685     begin
2686     for i := 0 to Count - 1 do
2687     if Column[i].Name = Name then
2688     begin
2689     OldSQLVar := FIBXSQLVAR;
2690     FIBXSQLVAR := Column[i];
2691     try
2692     inherited SetAsBoolean(AValue);
2693     finally
2694     FIBXSQLVAR := OldSQLVar;
2695     end;
2696     end;
2697     end;
2698     end;
2699    
2700     procedure TSQLParam.SetAsCurrency(AValue: Currency);
2701     var i: integer;
2702     OldSQLVar: TSQLVarData;
2703     begin
2704     if FIBXSQLVAR.UniqueName then
2705     inherited SetAsCurrency(AValue)
2706     else
2707     with FIBXSQLVAR.Parent do
2708     begin
2709     for i := 0 to Count - 1 do
2710     if Column[i].Name = Name then
2711     begin
2712     OldSQLVar := FIBXSQLVAR;
2713     FIBXSQLVAR := Column[i];
2714     try
2715     inherited SetAsCurrency(AValue);
2716     finally
2717     FIBXSQLVAR := OldSQLVar;
2718     end;
2719     end;
2720     end;
2721     end;
2722    
2723     procedure TSQLParam.SetAsInt64(AValue: Int64);
2724     var i: integer;
2725     OldSQLVar: TSQLVarData;
2726     begin
2727     if FIBXSQLVAR.UniqueName then
2728     inherited SetAsInt64(AValue)
2729     else
2730     with FIBXSQLVAR.Parent do
2731     begin
2732     for i := 0 to Count - 1 do
2733     if Column[i].Name = Name then
2734     begin
2735     OldSQLVar := FIBXSQLVAR;
2736     FIBXSQLVAR := Column[i];
2737     try
2738     inherited SetAsInt64(AValue);
2739     finally
2740     FIBXSQLVAR := OldSQLVar;
2741     end;
2742     end;
2743     end;
2744     end;
2745    
2746     procedure TSQLParam.SetAsDate(AValue: TDateTime);
2747     var i: integer;
2748     OldSQLVar: TSQLVarData;
2749     begin
2750     if FIBXSQLVAR.UniqueName then
2751     inherited SetAsDate(AValue)
2752     else
2753     with FIBXSQLVAR.Parent do
2754     begin
2755     for i := 0 to Count - 1 do
2756     if Column[i].Name = Name then
2757     begin
2758     OldSQLVar := FIBXSQLVAR;
2759     FIBXSQLVAR := Column[i];
2760     try
2761     inherited SetAsDate(AValue);
2762     finally
2763     FIBXSQLVAR := OldSQLVar;
2764     end;
2765     end;
2766     end;
2767     end;
2768    
2769     procedure TSQLParam.SetAsLong(AValue: Long);
2770     var i: integer;
2771     OldSQLVar: TSQLVarData;
2772     begin
2773     if FIBXSQLVAR.UniqueName then
2774     inherited SetAsLong(AValue)
2775     else
2776     with FIBXSQLVAR.Parent do
2777     begin
2778     for i := 0 to Count - 1 do
2779     if Column[i].Name = Name then
2780     begin
2781     OldSQLVar := FIBXSQLVAR;
2782     FIBXSQLVAR := Column[i];
2783     try
2784     inherited SetAsLong(AValue);
2785     finally
2786     FIBXSQLVAR := OldSQLVar;
2787     end;
2788     end;
2789     end;
2790     end;
2791    
2792     procedure TSQLParam.SetAsTime(AValue: TDateTime);
2793     var i: integer;
2794     OldSQLVar: TSQLVarData;
2795     begin
2796     if FIBXSQLVAR.UniqueName then
2797     inherited SetAsTime(AValue)
2798     else
2799     with FIBXSQLVAR.Parent do
2800     begin
2801     for i := 0 to Count - 1 do
2802     if Column[i].Name = Name then
2803     begin
2804     OldSQLVar := FIBXSQLVAR;
2805     FIBXSQLVAR := Column[i];
2806     try
2807     inherited SetAsTime(AValue);
2808     finally
2809     FIBXSQLVAR := OldSQLVar;
2810     end;
2811     end;
2812     end;
2813     end;
2814    
2815 tony 315 procedure TSQLParam.SetAsTime(aValue: TDateTime; OnDate: TDateTime; aTimeZoneID: TFBTimeZoneID);
2816     var i: integer;
2817     OldSQLVar: TSQLVarData;
2818     begin
2819     if FIBXSQLVAR.UniqueName then
2820     inherited SetAsTime(AValue,OnDate, aTimeZoneID)
2821     else
2822     with FIBXSQLVAR.Parent do
2823     begin
2824     for i := 0 to Count - 1 do
2825     if Column[i].Name = Name then
2826     begin
2827     OldSQLVar := FIBXSQLVAR;
2828     FIBXSQLVAR := Column[i];
2829     try
2830     inherited SetAsTime(AValue,OnDate, aTimeZoneID);
2831     finally
2832     FIBXSQLVAR := OldSQLVar;
2833     end;
2834     end;
2835     end;
2836     end;
2837    
2838     procedure TSQLParam.SetAsTime(aValue: TDateTime; OnDate: TDateTime; aTimeZone: AnsiString);
2839     var i: integer;
2840     OldSQLVar: TSQLVarData;
2841     begin
2842     if FIBXSQLVAR.UniqueName then
2843     inherited SetAsTime(AValue,OnDate,aTimeZone)
2844     else
2845     with FIBXSQLVAR.Parent do
2846     begin
2847     for i := 0 to Count - 1 do
2848     if Column[i].Name = Name then
2849     begin
2850     OldSQLVar := FIBXSQLVAR;
2851     FIBXSQLVAR := Column[i];
2852     try
2853     inherited SetAsTime(AValue,OnDate,aTimeZone);
2854     finally
2855     FIBXSQLVAR := OldSQLVar;
2856     end;
2857     end;
2858     end;
2859     end;
2860    
2861     procedure TSQLParam.SetAsTime(aValue: TDateTime; aTimeZoneID: TFBTimeZoneID);
2862     begin
2863     SetAsTime(aValue,GetTimeZoneServices.GetTimeTZDate,aTimeZoneID);
2864     end;
2865    
2866     procedure TSQLParam.SetAsTime(aValue: TDateTime; aTimeZone: AnsiString);
2867     begin
2868     SetAsTime(aValue,GetTimeZoneServices.GetTimeTZDate,aTimeZone);
2869     end;
2870    
2871 tony 45 procedure TSQLParam.SetAsDateTime(AValue: TDateTime);
2872     var i: integer;
2873     OldSQLVar: TSQLVarData;
2874     begin
2875     if FIBXSQLVAR.UniqueName then
2876     inherited SetAsDateTime(AValue)
2877     else
2878     with FIBXSQLVAR.Parent do
2879     begin
2880     for i := 0 to Count - 1 do
2881     if Column[i].Name = Name then
2882     begin
2883     OldSQLVar := FIBXSQLVAR;
2884     FIBXSQLVAR := Column[i];
2885     try
2886     inherited SetAsDateTime(AValue);
2887     finally
2888     FIBXSQLVAR := OldSQLVar;
2889     end;
2890     end;
2891     end;
2892     end;
2893    
2894 tony 315 procedure TSQLParam.SetAsDateTime(aValue: TDateTime; aTimeZoneID: TFBTimeZoneID
2895     );
2896     var i: integer;
2897     OldSQLVar: TSQLVarData;
2898     begin
2899     if FIBXSQLVAR.UniqueName then
2900     inherited SetAsDateTime(AValue,aTimeZoneID)
2901     else
2902     with FIBXSQLVAR.Parent do
2903     begin
2904     for i := 0 to Count - 1 do
2905     if Column[i].Name = Name then
2906     begin
2907     OldSQLVar := FIBXSQLVAR;
2908     FIBXSQLVAR := Column[i];
2909     try
2910     inherited SetAsDateTime(AValue,aTimeZoneID);
2911     finally
2912     FIBXSQLVAR := OldSQLVar;
2913     end;
2914     end;
2915     end;
2916     end;
2917    
2918     procedure TSQLParam.SetAsDateTime(aValue: TDateTime; aTimeZone: AnsiString);
2919     var i: integer;
2920     OldSQLVar: TSQLVarData;
2921     begin
2922     if FIBXSQLVAR.UniqueName then
2923     inherited SetAsDateTime(AValue,aTimeZone)
2924     else
2925     with FIBXSQLVAR.Parent do
2926     begin
2927     for i := 0 to Count - 1 do
2928     if Column[i].Name = Name then
2929     begin
2930     OldSQLVar := FIBXSQLVAR;
2931     FIBXSQLVAR := Column[i];
2932     try
2933     inherited SetAsDateTime(AValue,aTimeZone);
2934     finally
2935     FIBXSQLVAR := OldSQLVar;
2936     end;
2937     end;
2938     end;
2939     end;
2940    
2941 tony 45 procedure TSQLParam.SetAsDouble(AValue: Double);
2942     var i: integer;
2943     OldSQLVar: TSQLVarData;
2944     begin
2945     if FIBXSQLVAR.UniqueName then
2946     inherited SetAsDouble(AValue)
2947     else
2948     with FIBXSQLVAR.Parent do
2949     begin
2950     for i := 0 to Count - 1 do
2951     if Column[i].Name = Name then
2952     begin
2953     OldSQLVar := FIBXSQLVAR;
2954     FIBXSQLVAR := Column[i];
2955     try
2956     inherited SetAsDouble(AValue);
2957     finally
2958     FIBXSQLVAR := OldSQLVar;
2959     end;
2960     end;
2961     end;
2962     end;
2963    
2964     procedure TSQLParam.SetAsFloat(AValue: Float);
2965     var i: integer;
2966     OldSQLVar: TSQLVarData;
2967     begin
2968     if FIBXSQLVAR.UniqueName then
2969     inherited SetAsFloat(AValue)
2970     else
2971     with FIBXSQLVAR.Parent do
2972     begin
2973     for i := 0 to Count - 1 do
2974     if Column[i].Name = Name then
2975     begin
2976     OldSQLVar := FIBXSQLVAR;
2977     FIBXSQLVAR := Column[i];
2978     try
2979     inherited SetAsFloat(AValue);
2980     finally
2981     FIBXSQLVAR := OldSQLVar;
2982     end;
2983     end;
2984     end;
2985     end;
2986    
2987     procedure TSQLParam.SetAsPointer(AValue: Pointer);
2988     var i: integer;
2989     OldSQLVar: TSQLVarData;
2990     begin
2991     if FIBXSQLVAR.UniqueName then
2992     inherited SetAsPointer(AValue)
2993     else
2994     with FIBXSQLVAR.Parent do
2995     begin
2996     for i := 0 to Count - 1 do
2997     if Column[i].Name = Name then
2998     begin
2999     OldSQLVar := FIBXSQLVAR;
3000     FIBXSQLVAR := Column[i];
3001     try
3002     inherited SetAsPointer(AValue);
3003     finally
3004     FIBXSQLVAR := OldSQLVar;
3005     end;
3006     end;
3007     end;
3008     end;
3009    
3010     procedure TSQLParam.SetAsShort(AValue: Short);
3011     var i: integer;
3012     OldSQLVar: TSQLVarData;
3013     begin
3014     if FIBXSQLVAR.UniqueName then
3015     inherited SetAsShort(AValue)
3016     else
3017     with FIBXSQLVAR.Parent do
3018     begin
3019     for i := 0 to Count - 1 do
3020     if Column[i].Name = Name then
3021     begin
3022     OldSQLVar := FIBXSQLVAR;
3023     FIBXSQLVAR := Column[i];
3024     try
3025     inherited SetAsShort(AValue);
3026     finally
3027     FIBXSQLVAR := OldSQLVar;
3028     end;
3029     end;
3030     end;
3031     end;
3032    
3033 tony 56 procedure TSQLParam.SetAsString(AValue: AnsiString);
3034 tony 45 var i: integer;
3035     OldSQLVar: TSQLVarData;
3036     begin
3037     if FIBXSQLVAR.UniqueName then
3038     InternalSetAsString(AValue)
3039     else
3040     with FIBXSQLVAR.Parent do
3041     begin
3042     for i := 0 to Count - 1 do
3043     if Column[i].Name = Name then
3044     begin
3045     OldSQLVar := FIBXSQLVAR;
3046     FIBXSQLVAR := Column[i];
3047     try
3048     InternalSetAsString(AValue);
3049     finally
3050     FIBXSQLVAR := OldSQLVar;
3051     end;
3052     end;
3053     end;
3054     end;
3055    
3056     procedure TSQLParam.SetAsVariant(AValue: Variant);
3057     var i: integer;
3058     OldSQLVar: TSQLVarData;
3059     begin
3060     if FIBXSQLVAR.UniqueName then
3061     inherited SetAsVariant(AValue)
3062     else
3063     with FIBXSQLVAR.Parent do
3064     begin
3065     for i := 0 to Count - 1 do
3066     if Column[i].Name = Name then
3067     begin
3068     OldSQLVar := FIBXSQLVAR;
3069     FIBXSQLVAR := Column[i];
3070     try
3071     inherited SetAsVariant(AValue);
3072     finally
3073     FIBXSQLVAR := OldSQLVar;
3074     end;
3075     end;
3076     end;
3077     end;
3078    
3079     procedure TSQLParam.SetAsBlob(aValue: IBlob);
3080     begin
3081     with FIBXSQLVAR do
3082     if not UniqueName then
3083     IBError(ibxeDuplicateParamName,[Name]);
3084     CheckActive;
3085     Changing;
3086     aValue.Close;
3087     if aValue.GetSubType <> GetSubType then
3088     IBError(ibxeIncompatibleBlob,[GetSubType,aValue.GetSubType]);
3089     AsQuad := aValue.GetBlobID;
3090     Changed;
3091     end;
3092    
3093     procedure TSQLParam.SetAsQuad(AValue: TISC_QUAD);
3094     var i: integer;
3095     OldSQLVar: TSQLVarData;
3096     begin
3097     if FIBXSQLVAR.UniqueName then
3098     inherited SetAsQuad(AValue)
3099     else
3100     with FIBXSQLVAR.Parent do
3101     begin
3102     for i := 0 to Count - 1 do
3103     if Column[i].Name = Name then
3104     begin
3105     OldSQLVar := FIBXSQLVAR;
3106     FIBXSQLVAR := Column[i];
3107     try
3108     inherited SetAsQuad(AValue);
3109     finally
3110     FIBXSQLVAR := OldSQLVar;
3111     end;
3112     end;
3113     end;
3114     end;
3115    
3116     procedure TSQLParam.SetCharSetID(aValue: cardinal);
3117     begin
3118     FIBXSQLVAR.SetCharSetID(aValue);
3119     end;
3120    
3121 tony 315 procedure TSQLParam.SetAsBcd(aValue: tBCD);
3122     var i: integer;
3123     OldSQLVar: TSQLVarData;
3124     begin
3125     if FIBXSQLVAR.UniqueName then
3126     inherited SetAsBcd(AValue)
3127     else
3128     with FIBXSQLVAR.Parent do
3129     begin
3130     for i := 0 to Count - 1 do
3131     if Column[i].Name = Name then
3132     begin
3133     OldSQLVar := FIBXSQLVAR;
3134     FIBXSQLVAR := Column[i];
3135     try
3136     inherited SetAsBcd(AValue);
3137     finally
3138     FIBXSQLVAR := OldSQLVar;
3139     end;
3140     end;
3141     end;
3142     end;
3143    
3144 tony 371 procedure TSQLParam.SetAsNumeric(aValue: IFBNumeric);
3145     var i: integer;
3146     OldSQLVar: TSQLVarData;
3147     begin
3148     if FIBXSQLVAR.UniqueName then
3149     inherited SetAsNumeric(AValue)
3150     else
3151     with FIBXSQLVAR.Parent do
3152     begin
3153     for i := 0 to Count - 1 do
3154     if Column[i].Name = Name then
3155     begin
3156     OldSQLVar := FIBXSQLVAR;
3157     FIBXSQLVAR := Column[i];
3158     try
3159     inherited SetAsNumeric(AValue);
3160     finally
3161     FIBXSQLVAR := OldSQLVar;
3162     end;
3163     end;
3164     end;
3165     end;
3166    
3167 tony 45 { TMetaData }
3168    
3169     procedure TMetaData.CheckActive;
3170     begin
3171     if FPrepareSeqNo < FMetaData.PrepareSeqNo then
3172     IBError(ibxeInterfaceOutofDate,[nil]);
3173    
3174     if not FMetaData.CheckStatementStatus(ssPrepared) then
3175     IBError(ibxeStatementNotPrepared, [nil]);
3176     end;
3177    
3178     constructor TMetaData.Create(aMetaData: TSQLDataArea);
3179     begin
3180     inherited Create(aMetaData.Count);
3181     FMetaData := aMetaData;
3182     FStatement := aMetaData.Statement;
3183     FPrepareSeqNo := aMetaData.PrepareSeqNo;
3184     end;
3185    
3186     destructor TMetaData.Destroy;
3187     begin
3188 tony 371 if FStatement <> nil then
3189     (FStatement as TInterfaceOwner).Remove(self);
3190 tony 45 inherited Destroy;
3191     end;
3192    
3193 tony 56 function TMetaData.GetUniqueRelationName: AnsiString;
3194 tony 45 begin
3195     CheckActive;
3196     Result := FMetaData.UniqueRelationName;
3197     end;
3198    
3199     function TMetaData.getCount: integer;
3200     begin
3201     CheckActive;
3202     Result := FMetaData.ColumnsInUseCount;
3203     end;
3204    
3205     function TMetaData.getColumnMetaData(index: integer): IColumnMetaData;
3206     begin
3207     CheckActive;
3208     if (index < 0) or (index >= getCount) then
3209     IBError(ibxeInvalidColumnIndex,[nil]);
3210    
3211     if FMetaData.Count = 0 then
3212     Result := nil
3213     else
3214     begin
3215     if not HasInterface(index) then
3216     AddInterface(index,TColumnMetaData.Create(self,FMetaData.Column[index]));
3217     Result := TColumnMetaData(GetInterface(index));
3218     end;
3219     end;
3220    
3221 tony 56 function TMetaData.ByName(Idx: AnsiString): IColumnMetaData;
3222 tony 45 var aIBXSQLVAR: TSQLVarData;
3223     begin
3224     CheckActive;
3225     aIBXSQLVAR := FMetaData.ColumnByName(Idx);
3226     if aIBXSQLVAR = nil then
3227     IBError(ibxeFieldNotFound,[Idx]);
3228     Result := getColumnMetaData(aIBXSQLVAR.index);
3229     end;
3230    
3231     { TSQLParams }
3232    
3233     procedure TSQLParams.CheckActive;
3234     begin
3235     if not FSQLParams.StateChanged(FChangeSeqNo) then Exit;
3236    
3237     if FPrepareSeqNo < FSQLParams.PrepareSeqNo then
3238     IBError(ibxeInterfaceOutofDate,[nil]);
3239    
3240     if not FSQLParams.CheckStatementStatus(ssPrepared) then
3241     IBError(ibxeStatementNotPrepared, [nil]);
3242     end;
3243    
3244     constructor TSQLParams.Create(aSQLParams: TSQLDataArea);
3245     begin
3246     inherited Create(aSQLParams.Count);
3247     FSQLParams := aSQLParams;
3248     FStatement := aSQLParams.Statement;
3249     FPrepareSeqNo := aSQLParams.PrepareSeqNo;
3250     FSQLParams.StateChanged(FChangeSeqNo);
3251     end;
3252    
3253     destructor TSQLParams.Destroy;
3254     begin
3255 tony 371 if FStatement <> nil then
3256     (FStatement as TInterfaceOwner).Remove(self);
3257 tony 45 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 371 function TSQLParams.GetStatement: IStatement;
3313     begin
3314     Result := FSQLParams.GetStatement;
3315     end;
3316    
3317     function TSQLParams.GetTransaction: ITransaction;
3318     begin
3319     Result := FSQLParams.GetTransaction;
3320     end;
3321    
3322     function TSQLParams.GetAttachment: IAttachment;
3323     begin
3324     Result := FSQLParams.GetAttachment;
3325     end;
3326    
3327     procedure TSQLParams.Clear;
3328     var i: integer;
3329     begin
3330     for i := 0 to getCount - 1 do
3331     getSQLParam(i).Clear;
3332     end;
3333    
3334 tony 45 { TResults }
3335    
3336     procedure TResults.CheckActive;
3337     begin
3338     if not FResults.StateChanged(FChangeSeqNo) then Exit;
3339    
3340     if FPrepareSeqNo < FResults.PrepareSeqNo then
3341     IBError(ibxeInterfaceOutofDate,[nil]);
3342    
3343     if not FResults.CheckStatementStatus(ssPrepared) then
3344     IBError(ibxeStatementNotPrepared, [nil]);
3345    
3346 tony 315 with GetTransaction do
3347 tony 45 if not InTransaction or (FResults.TransactionSeqNo <> FTransactionSeqNo) then
3348     IBError(ibxeInterfaceOutofDate,[nil]);
3349     end;
3350    
3351     function TResults.GetISQLData(aIBXSQLVAR: TSQLVarData): ISQLData;
3352 tony 291 var col: TIBSQLData;
3353 tony 45 begin
3354     if (aIBXSQLVAR.Index < 0) or (aIBXSQLVAR.Index >= getCount) then
3355     IBError(ibxeInvalidColumnIndex,[nil]);
3356    
3357     if not HasInterface(aIBXSQLVAR.Index) then
3358 tony 371 begin
3359     col := TIBSQLData.Create(self,aIBXSQLVAR);
3360     AddInterface(aIBXSQLVAR.Index, col);
3361     end
3362     else
3363     col := TIBSQLData(GetInterface(aIBXSQLVAR.Index));
3364 tony 291 Result := col;
3365 tony 45 end;
3366    
3367     constructor TResults.Create(aResults: TSQLDataArea);
3368     begin
3369     inherited Create(aResults.Count);
3370     FResults := aResults;
3371     FStatement := aResults.Statement;
3372     FPrepareSeqNo := aResults.PrepareSeqNo;
3373     FTransactionSeqNo := aResults.TransactionSeqNo;
3374     FResults.StateChanged(FChangeSeqNo);
3375     end;
3376    
3377     function TResults.getCount: integer;
3378     begin
3379     CheckActive;
3380     Result := FResults.Count;
3381     end;
3382    
3383 tony 56 function TResults.ByName(Idx: AnsiString): ISQLData;
3384 tony 45 var col: TSQLVarData;
3385     begin
3386     Result := nil;
3387     CheckActive;
3388     if FResults.CheckStatementStatus(ssBOF) then
3389     IBError(ibxeBOF,[nil]);
3390     if FResults.CheckStatementStatus(ssEOF) then
3391     IBError(ibxeEOF,[nil]);
3392    
3393     if FResults.Count > 0 then
3394     begin
3395     col := FResults.ColumnByName(Idx);
3396     if col <> nil then
3397     Result := GetISQLData(col);
3398     end;
3399     end;
3400    
3401     function TResults.getSQLData(index: integer): ISQLData;
3402     begin
3403     CheckActive;
3404     if FResults.CheckStatementStatus(ssBOF) then
3405     IBError(ibxeBOF,[nil]);
3406     if FResults.CheckStatementStatus(ssEOF) then
3407     IBError(ibxeEOF,[nil]);
3408     if (index < 0) or (index >= FResults.Count) then
3409     IBError(ibxeInvalidColumnIndex,[nil]);
3410    
3411     Result := GetISQLData(FResults.Column[index]);
3412     end;
3413    
3414     procedure TResults.GetData(index: integer; var IsNull: boolean; var len: short;
3415 tony 56 var data: PByte);
3416 tony 45 begin
3417     CheckActive;
3418     FResults.GetData(index,IsNull, len,data);
3419     end;
3420    
3421 tony 291 function TResults.GetStatement: IStatement;
3422     begin
3423     Result := FStatement;
3424     end;
3425    
3426 tony 45 function TResults.GetTransaction: ITransaction;
3427     begin
3428 tony 371 Result := FResults.GetTransaction;
3429 tony 45 end;
3430    
3431 tony 371 function TResults.GetAttachment: IAttachment;
3432     begin
3433     Result := FResults.GetAttachment;
3434     end;
3435    
3436 tony 45 procedure TResults.SetRetainInterfaces(aValue: boolean);
3437     begin
3438     RetainInterfaces := aValue;
3439     end;
3440    
3441     end.
3442