ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/public/ibx/branches/udr/client/FBSQLData.pas
Revision: 391
Committed: Thu Jan 27 16:34:24 2022 UTC (2 years, 9 months ago) by tony
Content type: text/x-pascal
File size: 93459 byte(s)
Log Message:
Fix issues with a select procedure returning an empty dataset

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

Properties

Name Value
svn:eol-style native