ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/public/ibx/branches/udr/client/FBSQLData.pas
Revision: 372
Committed: Wed Jan 5 16:20:22 2022 UTC (2 years, 3 months ago) by tony
Content type: text/x-pascal
File size: 92729 byte(s)
Log Message:
string overflow fix

File Contents

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