1 {*********************************************************}
3 { Zeos Database Objects }
4 { Interbase Database Connectivity Classes }
6 { Originally written by Sergey Merkuriev }
8 {*********************************************************}
10 {@********************************************************}
11 { Copyright (c) 1999-2012 Zeos Development Group }
13 { License Agreement: }
15 { This library is distributed in the hope that it will be }
16 { useful, but WITHOUT ANY WARRANTY; without even the }
17 { implied warranty of MERCHANTABILITY or FITNESS FOR }
18 { A PARTICULAR PURPOSE. See the GNU Lesser General }
19 { Public License for more details. }
21 { The source code of the ZEOS Libraries and packages are }
22 { distributed under the Library GNU General Public }
23 { License (see the file COPYING / COPYING.ZEOS) }
24 { with the following modification: }
25 { As a special exception, the copyright holders of this }
26 { library give you permission to link this library with }
27 { independent modules to produce an executable, }
28 { regardless of the license terms of these independent }
29 { modules, and to copy and distribute the resulting }
30 { executable under terms of your choice, provided that }
31 { you also meet, for each linked independent module, }
32 { the terms and conditions of the license of that module. }
33 { An independent module is a module which is not derived }
34 { from or based on this library. If you modify this }
35 { library, you may extend this exception to your version }
36 { of the library, but you are not obligated to do so. }
37 { If you do not wish to do so, delete this exception }
38 { statement from your version. }
41 { The project web site is located on: }
42 { http://zeos.firmos.at (FORUM) }
43 { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)}
44 { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) }
46 { http://www.sourceforge.net/projects/zeoslib. }
49 { Zeos Development Group. }
50 {********************************************************@}
52 unit ZDbcInterbase6Utils;
59 SysUtils, Classes, {$IFDEF MSEgui}mclasses,{$ENDIF} Types,
60 ZDbcIntfs, ZDbcStatement, ZPlainFirebirdDriver, ZCompatibility,
61 ZPlainFirebirdInterbaseConstants, ZDbcCachedResultSet, ZDbcLogging, ZMessages,
65 { Interbase Statement Type }
66 TZIbSqlStatementType = (stUnknown, stSelect, stInsert, stUpdate, stDelete,
67 stDDL, stGetSegment, stPutSegment, stExecProc, stStartTrans, stCommit,
68 stRollback, stSelectForUpdate, stSetGenerator, stDisconnect);
70 { Interbase Error Class}
71 EZIBConvertError = class(Exception);
73 { Paparameter string name and it value}
78 PZIbParam = ^TZIbParam;
80 { Interbase blob Information structure
81 contain iformation about blob size in bytes,
82 segments count, segment size in bytes and blob type
83 Note: blob type can be text an binary }
91 { Base interface for sqlda }
93 ['{2D0D6029-B31C-4E39-89DC-D86D20437C35}']
94 procedure InitFields(Parameters: boolean);
95 procedure AllocateSQLDA;
96 procedure FreeParamtersValues;
98 function GetData: PXSQLDA;
99 function IsBlob(const Index: Word): boolean;
100 function IsNullable(const Index: Word): boolean;
102 function GetFieldCount: Integer;
103 function GetFieldSqlName(const Index: Word): String;
104 function GetFieldRelationName(const Index: Word): String;
105 function GetFieldOwnerName(const Index: Word): String;
106 function GetFieldAliasName(const Index: Word): String;
107 function GetFieldIndex(const Name: AnsiString): Word;
108 function GetFieldScale(const Index: Word): integer;
109 function GetFieldSqlType(const Index: Word): TZSQLType;
110 function GetFieldLength(const Index: Word): SmallInt;
111 function GetIbSqlType(const Index: Word): Smallint;
112 function GetIbSqlSubType(const Index: Word): Smallint;
113 function GetIbSqlLen(const Index: Word): Smallint;
116 { parameters interface sqlda}
117 IZParamsSQLDA = interface(IZSQLDA)
118 ['{D2C3D5E1-F3A6-4223-9A6E-3048B99A06C4}']
119 procedure WriteBlob(const Index: Integer; Stream: TStream);
120 procedure UpdateNull(const Index: Integer; Value: boolean);
121 procedure UpdateBoolean(const Index: Integer; Value: boolean);
122 procedure UpdateByte(const Index: Integer; Value: ShortInt);
123 procedure UpdateShort(const Index: Integer; Value: SmallInt);
124 procedure UpdateInt(const Index: Integer; Value: Integer);
125 procedure UpdateLong(const Index: Integer; Value: Int64);
126 procedure UpdateFloat(const Index: Integer; Value: Single);
127 procedure UpdateDouble(const Index: Integer; Value: Double);
128 procedure UpdateBigDecimal(const Index: Integer; Value: Extended);
129 procedure UpdatePChar(const Index: Integer; Value: PAnsiChar);
130 procedure UpdateString(const Index: Integer; Value: RawByteString);
131 procedure UpdateBytes(const Index: Integer; Value: TByteDynArray);
132 procedure UpdateDate(const Index: Integer; Value: TDateTime);
133 procedure UpdateTime(const Index: Integer; Value: TDateTime);
134 procedure UpdateTimestamp(const Index: Integer; Value: TDateTime);
135 procedure UpdateQuad(const Index: Word; const Value: TISC_QUAD);
138 { Result interface for sqlda}
139 IZResultSQLDA = interface(IZSQLDA)
140 ['{D2C3D5E1-F3A6-4223-9A6E-3048B99A06C4}']
141 procedure ReadBlobFromStream(const Index: Word; Stream: TStream);
142 procedure ReadBlobFromString(const Index: Word; var str: AnsiString);
143 procedure ReadBlobFromVariant(const Index: Word; var Value: Variant);
145 function IsNull(const Index: Integer): Boolean;
146 function GetPChar(const Index: Integer): PChar;
147 function GetString(const Index: Integer): RawByteString;
148 function GetBoolean(const Index: Integer): Boolean;
149 function GetByte(const Index: Integer): Byte;
150 function GetShort(const Index: Integer): SmallInt;
151 function GetInt(const Index: Integer): Integer;
152 function GetLong(const Index: Integer): Int64;
153 function GetFloat(const Index: Integer): Single;
154 function GetDouble(const Index: Integer): Double;
155 function GetBigDecimal(const Index: Integer): Extended;
156 function GetBytes(const Index: Integer): TByteDynArray;
157 function GetDate(const Index: Integer): TDateTime;
158 function GetTime(const Index: Integer): TDateTime;
159 function GetTimestamp(const Index: Integer): TDateTime;
160 function GetValue(const Index: Word): Variant;
161 function GetQuad(const Index: Integer): TISC_QUAD;
164 { Base class contain core functions to work with sqlda structure
165 Can allocate memory for sqlda structure get basic information }
166 TZSQLDA = class (TZCodePagedObject, IZSQLDA)
168 FHandle: PISC_DB_HANDLE;
169 FTransactionHandle: PISC_TR_HANDLE;
171 FPlainDriver: IZInterbasePlainDriver;
173 procedure CheckRange(const Index: Word);
174 procedure IbReAlloc(var P; OldSize, NewSize: Integer);
175 procedure SetFieldType(const Index: Word; Size: Integer; Code: Smallint;
178 constructor Create(PlainDriver: IZInterbasePlainDriver;
179 Handle: PISC_DB_HANDLE; TransactionHandle: PISC_TR_HANDLE;
180 ConSettings: PZConSettings); virtual;
181 procedure InitFields(Parameters: boolean);
182 procedure AllocateSQLDA; virtual;
183 procedure FreeParamtersValues;
185 function IsBlob(const Index: Word): boolean;
186 function IsNullable(const Index: Word): boolean;
188 function GetFieldCount: Integer;
189 function GetFieldSqlName(const Index: Word): String;
190 function GetFieldOwnerName(const Index: Word): String;
191 function GetFieldRelationName(const Index: Word): String;
192 function GetFieldAliasName(const Index: Word): String;
193 function GetFieldIndex(const Name: AnsiString): Word;
194 function GetFieldScale(const Index: Word): integer;
195 function GetFieldSqlType(const Index: Word): TZSQLType;
196 function GetFieldLength(const Index: Word): SmallInt;
197 function GetData: PXSQLDA;
199 function GetIbSqlType(const Index: Word): Smallint;
200 function GetIbSqlSubType(const Index: Word): Smallint;
201 function GetIbSqlLen(const Index: Word): Smallint;
204 { Parameters class for sqlda structure.
205 It clas can only write data to parameters/fields }
206 TZParamsSQLDA = class (TZSQLDA, IZParamsSQLDA)
208 procedure EncodeString(Code: Smallint; const Index: Word; const Str: RawByteString);
209 procedure EncodeBytes(Code: Smallint; const Index: Word; const Value: TByteDynArray);
210 procedure UpdateDateTime(const Index: Integer; Value: TDateTime);
212 destructor Destroy; override;
214 procedure WriteBlob(const Index: Integer; Stream: TStream);
216 procedure UpdateNull(const Index: Integer; Value: boolean);
217 procedure UpdateBoolean(const Index: Integer; Value: boolean);
218 procedure UpdateByte(const Index: Integer; Value: ShortInt);
219 procedure UpdateShort(const Index: Integer; Value: SmallInt);
220 procedure UpdateInt(const Index: Integer; Value: Integer);
221 procedure UpdateLong(const Index: Integer; Value: Int64);
222 procedure UpdateFloat(const Index: Integer; Value: Single);
223 procedure UpdateDouble(const Index: Integer; Value: Double);
224 procedure UpdateBigDecimal(const Index: Integer; Value: Extended);
225 procedure UpdatePChar(const Index: Integer; Value: PAnsiChar);
226 procedure UpdateString(const Index: Integer; Value: RawByteString);
227 procedure UpdateBytes(const Index: Integer; Value: TByteDynArray);
228 procedure UpdateDate(const Index: Integer; Value: TDateTime);
229 procedure UpdateTime(const Index: Integer; Value: TDateTime);
230 procedure UpdateTimestamp(const Index: Integer; Value: TDateTime);
231 procedure UpdateQuad(const Index: Word; const Value: TISC_QUAD);
234 { Resultset class for sqlda structure.
235 It class read data from sqlda fields }
236 TZResultSQLDA = class (TZSQLDA, IZResultSQLDA)
238 function DecodeString(const Code: Smallint; const Index: Word): RawByteString;
239 procedure DecodeString2(const Code: Smallint; const Index: Word; out Str: RawByteString);
241 FDefaults: array of Variant;
243 destructor Destroy; override;
245 procedure AllocateSQLDA; override;
247 procedure ReadBlobFromStream(const Index: Word; Stream: TStream);
248 procedure ReadBlobFromString(const Index: Word; var str: AnsiString);
249 procedure ReadBlobFromVariant(const Index: Word; var Value: Variant);
251 function IsNull(const Index: Integer): Boolean;
252 function GetPChar(const Index: Integer): PChar;
253 function GetString(const Index: Integer): RawByteString;
254 function GetBoolean(const Index: Integer): Boolean;
255 function GetByte(const Index: Integer): Byte;
256 function GetShort(const Index: Integer): SmallInt;
257 function GetInt(const Index: Integer): Integer;
258 function GetLong(const Index: Integer): Int64;
259 function GetFloat(const Index: Integer): Single;
260 function GetDouble(const Index: Integer): Double;
261 function GetBigDecimal(const Index: Integer): Extended;
262 function GetBytes(const Index: Integer): TByteDynArray;
263 function GetDate(const Index: Integer): TDateTime;
264 function GetTime(const Index: Integer): TDateTime;
265 function GetTimestamp(const Index: Integer): TDateTime;
266 function GetValue(const Index: Word): Variant;
267 function GetQuad(const Index: Integer): TISC_QUAD;
270 function RandomString(Len: integer): AnsiString;
271 function CreateIBResultSet(SQL: string; Statement: IZStatement;
272 NativeResultSet: IZResultSet): IZResultSet;
274 {Interbase6 Connection Functions}
275 function GenerateDPB(Info: TStrings; var FDPBLength, Dialect: Word): PAnsiChar;
276 function GenerateTPB(Params: TStrings; var Handle: TISC_DB_HANDLE): PISC_TEB;
277 function GetInterbase6DatabaseParamNumber(const Value: AnsiString): word;
278 function GetInterbase6TransactionParamNumber(const Value: AnsiString): word;
280 { Interbase6 errors functions }
281 function GetNameSqlType(Value: Word): AnsiString;
282 function CheckInterbase6Error(PlainDriver: IZInterbasePlainDriver;
283 StatusVector: TARRAY_ISC_STATUS; LoggingCategory: TZLoggingCategory = lcOther;
284 SQL: string = '') : Integer;
286 { Interbase information functions}
287 function GetVersion(PlainDriver: IZInterbasePlainDriver;
288 Handle: PISC_DB_HANDLE): AnsiString;
289 function GetDBImplementationNo(PlainDriver: IZInterbasePlainDriver;
290 Handle: PISC_DB_HANDLE): LongInt;
291 function GetDBImplementationClass(PlainDriver: IZInterbasePlainDriver;
292 Handle: PISC_DB_HANDLE): LongInt;
293 function GetLongDbInfo(PlainDriver: IZInterbasePlainDriver;
294 Handle: PISC_DB_HANDLE; DatabaseInfoCommand: Integer): LongInt;
295 function GetStringDbInfo(PlainDriver: IZInterbasePlainDriver;
296 Handle: PISC_DB_HANDLE; DatabaseInfoCommand: Integer): AnsiString;
297 function GetDBSQLDialect(PlainDriver: IZInterbasePlainDriver;
298 Handle: PISC_DB_HANDLE): Integer;
300 { Interbase statement functions}
301 function PrepareStatement(PlainDriver: IZInterbasePlainDriver;
302 Handle: PISC_DB_HANDLE; TrHandle: PISC_TR_HANDLE; Dialect: Word;
303 SQL: RawByteString; LogSQL: String;
304 var StmtHandle: TISC_STMT_HANDLE): TZIbSqlStatementType;
305 procedure PrepareResultSqlData(PlainDriver: IZInterbasePlainDriver;
306 Handle: PISC_DB_HANDLE; Dialect: Word; LogSQL: string;
307 var StmtHandle: TISC_STMT_HANDLE; SqlData: IZResultSQLDA);
308 procedure PrepareParameters(PlainDriver: IZInterbasePlainDriver; LogSQL: string;
309 Dialect: Word; var StmtHandle: TISC_STMT_HANDLE; ParamSqlData: IZParamsSQLDA);
310 procedure BindSQLDAInParameters(PlainDriver: IZInterbasePlainDriver;
311 InParamValues: TZVariantDynArray; InParamTypes: TZSQLTypeArray;
312 InParamCount: Integer; ParamSqlData: IZParamsSQLDA; ConSettings: PZConSettings);
313 procedure FreeStatement(PlainDriver: IZInterbasePlainDriver;
314 StatementHandle: TISC_STMT_HANDLE; Options : Word);
315 function GetStatementType(PlainDriver: IZInterbasePlainDriver;
316 StmtHandle: TISC_STMT_HANDLE): TZIbSqlStatementType;
317 function GetAffectedRows(PlainDriver: IZInterbasePlainDriver;
318 StmtHandle: TISC_STMT_HANDLE; StatementType: TZIbSqlStatementType): integer;
320 function ConvertInterbase6ToSqlType(SqlType, SqlSubType: Integer;
321 const CtrlsCPType: TZControlsCodePage): TZSqlType;
323 { interbase blob routines }
324 procedure GetBlobInfo(PlainDriver: IZInterbasePlainDriver;
325 BlobHandle: TISC_BLOB_HANDLE; var BlobInfo: TIbBlobInfo);
326 procedure ReadBlobBufer(PlainDriver: IZInterbasePlainDriver;
327 Handle: PISC_DB_HANDLE; TransactionHandle: PISC_TR_HANDLE;
328 BlobId: TISC_QUAD; var Size: Integer; var Buffer: Pointer);
329 function GetIBScaleDivisor(Scale: SmallInt): Int64;
333 { Default Interbase blob size for readig }
334 DefaultBlobSegmentSize = 16 * 1024;
336 IBScaleDivisor: array[-15..-1] of Int64 = (1000000000000000,100000000000000,
337 10000000000000,1000000000000,100000000000,10000000000,1000000000,100000000,
338 10000000,1000000,100000,10000,1000,100,10);
340 { count database parameters }
342 { prefix database parameters names it used in paramters scann procedure }
343 BPBPrefix = 'isc_dpb_';
344 { list database parameters and their apropriate numbers }
345 DatabaseParams: array [0..MAX_DPB_PARAMS]of TZIbParam = (
346 (Name:'isc_dpb_version1'; Number: isc_dpb_version1),
347 (Name:'isc_dpb_cdd_pathname'; Number: isc_dpb_cdd_pathname),
348 (Name:'isc_dpb_allocation'; Number: isc_dpb_allocation),
349 (Name:'isc_dpb_journal'; Number: isc_dpb_journal),
350 (Name:'isc_dpb_page_size'; Number: isc_dpb_page_size),
351 (Name:'isc_dpb_num_buffers'; Number: isc_dpb_num_buffers),
352 (Name:'isc_dpb_buffer_length'; Number: isc_dpb_buffer_length),
353 (Name:'isc_dpb_debug'; Number: isc_dpb_debug),
354 (Name:'isc_dpb_garbage_collect'; Number: isc_dpb_garbage_collect),
355 (Name:'isc_dpb_verify'; Number: isc_dpb_verify),
356 (Name:'isc_dpb_sweep'; Number: isc_dpb_sweep),
357 (Name:'isc_dpb_enable_journal'; Number: isc_dpb_enable_journal),
358 (Name:'isc_dpb_disable_journal'; Number: isc_dpb_disable_journal),
359 (Name:'isc_dpb_dbkey_scope'; Number: isc_dpb_dbkey_scope),
360 (Name:'isc_dpb_number_of_users'; Number: isc_dpb_number_of_users),
361 (Name:'isc_dpb_trace'; Number: isc_dpb_trace),
362 (Name:'isc_dpb_no_garbage_collect'; Number: isc_dpb_no_garbage_collect),
363 (Name:'isc_dpb_damaged'; Number: isc_dpb_damaged),
364 (Name:'isc_dpb_license'; Number: isc_dpb_license),
365 (Name:'isc_dpb_sys_user_name'; Number: isc_dpb_sys_user_name),
366 (Name:'isc_dpb_encrypt_key'; Number: isc_dpb_encrypt_key),
367 (Name:'isc_dpb_activate_shadow'; Number: isc_dpb_activate_shadow),
368 (Name:'isc_dpb_sweep_interval'; Number: isc_dpb_sweep_interval),
369 (Name:'isc_dpb_delete_shadow'; Number: isc_dpb_delete_shadow),
370 (Name:'isc_dpb_force_write'; Number: isc_dpb_force_write),
371 (Name:'isc_dpb_begin_log'; Number: isc_dpb_begin_log),
372 (Name:'isc_dpb_quit_log'; Number: isc_dpb_quit_log),
373 (Name:'isc_dpb_no_reserve'; Number: isc_dpb_no_reserve),
374 (Name:'isc_dpb_username'; Number: isc_dpb_user_name),
375 (Name:'isc_dpb_password'; Number: isc_dpb_password),
376 (Name:'isc_dpb_password_enc'; Number: isc_dpb_password_enc),
377 (Name:'isc_dpb_sys_user_name_enc'; Number: isc_dpb_sys_user_name_enc),
378 (Name:'isc_dpb_interp'; Number: isc_dpb_interp),
379 (Name:'isc_dpb_online_dump'; Number: isc_dpb_online_dump),
380 (Name:'isc_dpb_old_file_size'; Number: isc_dpb_old_file_size),
381 (Name:'isc_dpb_old_num_files'; Number: isc_dpb_old_num_files),
382 (Name:'isc_dpb_old_file'; Number: isc_dpb_old_file),
383 (Name:'isc_dpb_old_start_page'; Number: isc_dpb_old_start_page),
384 (Name:'isc_dpb_old_start_seqno'; Number: isc_dpb_old_start_seqno),
385 (Name:'isc_dpb_old_start_file'; Number: isc_dpb_old_start_file),
386 (Name:'isc_dpb_drop_walfile'; Number: isc_dpb_drop_walfile),
387 (Name:'isc_dpb_old_dump_id'; Number: isc_dpb_old_dump_id),
388 (Name:'isc_dpb_wal_backup_dir'; Number: isc_dpb_wal_backup_dir),
389 (Name:'isc_dpb_wal_chkptlen'; Number: isc_dpb_wal_chkptlen),
390 (Name:'isc_dpb_wal_numbufs'; Number: isc_dpb_wal_numbufs),
391 (Name:'isc_dpb_wal_bufsize'; Number: isc_dpb_wal_bufsize),
392 (Name:'isc_dpb_wal_grp_cmt_wait'; Number: isc_dpb_wal_grp_cmt_wait),
393 (Name:'isc_dpb_lc_messages'; Number: isc_dpb_lc_messages),
394 (Name:'isc_dpb_lc_ctype'; Number: isc_dpb_lc_ctype),
395 (Name:'isc_dpb_cache_manager'; Number: isc_dpb_cache_manager),
396 (Name:'isc_dpb_shutdown'; Number: isc_dpb_shutdown),
397 (Name:'isc_dpb_online'; Number: isc_dpb_online),
398 (Name:'isc_dpb_shutdown_delay'; Number: isc_dpb_shutdown_delay),
399 (Name:'isc_dpb_reserved'; Number: isc_dpb_reserved),
400 (Name:'isc_dpb_overwrite'; Number: isc_dpb_overwrite),
401 (Name:'isc_dpb_sec_attach'; Number: isc_dpb_sec_attach),
402 (Name:'isc_dpb_disable_wal'; Number: isc_dpb_disable_wal),
403 (Name:'isc_dpb_connect_timeout'; Number: isc_dpb_connect_timeout),
404 (Name:'isc_dpb_dummy_packet_interval'; Number: isc_dpb_dummy_packet_interval),
405 (Name:'isc_dpb_gbak_attach'; Number: isc_dpb_gbak_attach),
406 (Name:'isc_dpb_sql_role_name'; Number: isc_dpb_sql_role_name),
407 (Name:'isc_dpb_set_page_buffers'; Number: isc_dpb_set_page_buffers),
408 (Name:'isc_dpb_working_directory'; Number: isc_dpb_working_directory),
409 (Name:'isc_dpb_sql_dialect'; Number: isc_dpb_SQL_dialect),
410 (Name:'isc_dpb_set_db_readonly'; Number: isc_dpb_set_db_readonly),
411 (Name:'isc_dpb_set_db_sql_dialect'; Number: isc_dpb_set_db_SQL_dialect),
412 (Name:'isc_dpb_gfix_attach'; Number: isc_dpb_gfix_attach),
413 (Name:'isc_dpb_gstat_attach'; Number: isc_dpb_gstat_attach)
416 { count transaction parameters }
418 { prefix transaction parameters names it used in paramters scann procedure }
419 TPBPrefix = 'isc_tpb_';
420 { list transaction parameters and their apropriate numbers }
421 TransactionParams: array [0..MAX_TPB_PARAMS-1]of TZIbParam = (
422 (Name:'isc_tpb_version1'; Number: isc_tpb_version1),
423 (Name:'isc_tpb_version3'; Number: isc_tpb_version3),
424 (Name:'isc_tpb_consistency'; Number: isc_tpb_consistency),
425 (Name:'isc_tpb_concurrency'; Number: isc_tpb_concurrency),
426 (Name:'isc_tpb_shared'; Number: isc_tpb_shared),
427 (Name:'isc_tpb_protected'; Number: isc_tpb_protected),
428 (Name:'isc_tpb_exclusive'; Number: isc_tpb_exclusive),
429 (Name:'isc_tpb_wait'; Number: isc_tpb_wait),
430 (Name:'isc_tpb_nowait'; Number: isc_tpb_nowait),
431 (Name:'isc_tpb_read'; Number: isc_tpb_read),
432 (Name:'isc_tpb_write'; Number: isc_tpb_write),
433 (Name:'isc_tpb_lock_read'; Number: isc_tpb_lock_read),
434 (Name:'isc_tpb_lock_write'; Number: isc_tpb_lock_write),
435 (Name:'isc_tpb_verb_time'; Number: isc_tpb_verb_time),
436 (Name:'isc_tpb_commit_time'; Number: isc_tpb_commit_time),
437 (Name:'isc_tpb_ignore_limbo'; Number: isc_tpb_ignore_limbo),
438 (Name:'isc_tpb_read_committed'; Number: isc_tpb_read_committed),
439 (Name:'isc_tpb_autocommit'; Number: isc_tpb_autocommit),
440 (Name:'isc_tpb_rec_version'; Number: isc_tpb_rec_version),
441 (Name:'isc_tpb_no_rec_version'; Number: isc_tpb_no_rec_version),
442 (Name:'isc_tpb_restart_requests'; Number: isc_tpb_restart_requests),
443 (Name:'isc_tpb_no_auto_undo'; Number: isc_tpb_no_auto_undo),
444 (Name:'isc_tpb_no_savepoint'; Number: isc_tpb_no_savepoint),// Since IB75+
445 (Name:'isc_tpb_lock_timeout'; Number: isc_tpb_lock_timeout) // Since FB20+
451 Variants, ZSysUtils, Math, ZDbcInterbase6, ZEncoding
452 {$IFDEF WITH_UNITANSISTRINGS}, AnsiStrings{$ENDIF};
455 Generate specific length random string and return it
456 @param Len a length result string
457 @return random string
459 function RandomString(Len: integer): AnsiString;
462 while Length(Result) < Len do
463 Result := Result + AnsiString(IntToStr(Trunc(Random(High(Integer)))));
464 if Length(Result) > Len then
465 Result := Copy(Result, 1, Len);
469 Create CachedResultSet with using TZCachedResultSet and return it.
470 @param SQL a sql query command
471 @param Statement a zeos statement object
472 @param NativeResultSet a native result set
473 @return cached ResultSet
475 function CreateIBResultSet(SQL: string; Statement: IZStatement; NativeResultSet: IZResultSet): IZResultSet;
477 CachedResolver: TZInterbase6CachedResolver;
478 CachedResultSet: TZCachedResultSet;
480 if (Statement.GetResultSetConcurrency <> rcReadOnly)
481 or (Statement.GetResultSetType <> rtForwardOnly) then
483 CachedResolver := TZInterbase6CachedResolver.Create(Statement, NativeResultSet.GetMetadata);
484 CachedResultSet := TZCachedResultSet.Create(NativeResultSet, SQL,
485 CachedResolver, Statement.GetConnection.GetConSettings);
486 CachedResultSet.SetConcurrency(Statement.GetResultSetConcurrency);
487 Result := CachedResultSet;
490 Result := NativeResultSet;
494 Generate database connection string by connection information
495 @param DPB - a database connection string
496 @param Dialect - a sql dialect number
497 @param Info - a list connection interbase parameters
498 @return a generated string length
500 function GenerateDPB(Info: TStrings; var FDPBLength, Dialect: Word): PAnsiChar;
502 I, Pos, PValue: Integer;
505 DPB, ParamName, ParamValue: AnsiString;
508 DPB := AnsiChar(isc_dpb_version1);
510 for I := 0 to Info.Count - 1 do
512 Buffer := Info.Strings[I];
513 Pos := FirstDelimiter(' ='#9#10#13, Buffer);
514 ParamName := AnsiString(Copy(Buffer, 1, Pos - 1));
515 Delete(Buffer, 1, Pos);
516 ParamValue := AnsiString(Buffer);
517 ParamNo := GetInterbase6DatabaseParamNumber(ParamName);
521 isc_dpb_set_db_SQL_dialect:
522 Dialect := StrToIntDef(String(ParamValue), 0);
523 isc_dpb_user_name, isc_dpb_password, isc_dpb_password_enc,
524 isc_dpb_sys_user_name, isc_dpb_license, isc_dpb_encrypt_key,
525 isc_dpb_lc_messages, isc_dpb_lc_ctype, isc_dpb_sql_role_name,
526 isc_dpb_connect_timeout:
528 DPB := DPB + AnsiChar(ParamNo) + AnsiChar(Length(ParamValue)) + ParamValue;
529 Inc(FDPBLength, 2 + Length(ParamValue));
531 isc_dpb_num_buffers, isc_dpb_dbkey_scope, isc_dpb_force_write,
532 isc_dpb_no_reserve, isc_dpb_damaged, isc_dpb_verify:
534 DPB := DPB + AnsiChar(ParamNo) + #1 + AnsiChar(StrToInt(String(ParamValue)));
539 DPB := DPB + AnsiChar(ParamNo) + #1 + AnsiChar(isc_dpb_records);
542 isc_dpb_sweep_interval:
544 PValue := StrToInt(String(ParamValue));
545 DPB := DPB + AnsiChar(ParamNo) + #4 + PAnsiChar(@PValue)[0] +
546 PAnsiChar(@PValue)[1] + PAnsiChar(@PValue)[2] + PAnsiChar(@PValue)[3];
549 isc_dpb_activate_shadow, isc_dpb_delete_shadow, isc_dpb_begin_log,
552 DPB := DPB + AnsiChar(ParamNo) + #1 + #0;
559 Result := AnsiStrAlloc(FDPBLength + 1);
561 Result := StrAlloc(FDPBLength + 1);
565 {$IFDEF WITH_STRPCOPY_DEPRECATED}AnsiStrings.{$ENDIF}StrPCopy(Result, DPB);
569 Generate transaction structuer by connection information
570 @param Params - a transaction parameters list
571 @param Dialect - a database connection handle
572 @return a transaction ISC structure
574 function GenerateTPB(Params: TStrings; var Handle: TISC_DB_HANDLE): PISC_TEB;
577 TPBLength,ParamNo: Word;
578 TempStr, ParamValue: AnsiString;
580 IsolationLevel: Boolean;
584 IsolationLevel := False;
586 { Prepare transaction parameters string }
587 for I := 0 to Params.Count - 1 do
589 ParamValue := AnsiString(Params.Strings[I]);
590 ParamNo := GetInterbase6TransactionParamNumber(ParamValue);
594 isc_tpb_lock_read, isc_tpb_lock_write:
596 TempStr := TempStr + AnsiChar(ParamNo) + AnsiChar(Length(ParamValue)) + ParamValue;
597 Inc(TPBLength, Length(ParamValue) + 2);
601 TempStr := TempStr + AnsiChar(ParamNo);
606 { Check what was set use transaction isolation level }
607 if not IsolationLevel then
609 isc_tpb_concurrency, isc_tpb_consistency,
610 isc_tpb_read_committed:
611 IsolationLevel := True
613 IsolationLevel := False;
618 { Allocate transaction parameters PAnsiChar buffer
619 if temporally parameters string is empty the set null pointer for
620 default database transaction}
621 if (TPBLength > 0) and (IsolationLevel) then
624 TPB := AnsiStrAlloc(TPBLength + 1);
626 TPB := StrAlloc(TPBLength + 1);
628 TPB := {$IFDEF WITH_STRPCOPY_DEPRECATED}AnsiStrings.{$ENDIF}StrPCopy(TPB, TempStr);
634 { Allocate transaction structure }
635 Result := AllocMem(SizeOf(TISC_TEB));
638 db_handle := @Handle;
639 tpb_length := TPBLength;
645 Return interbase connection parameter number by it name
646 @param Value - a connection parameter name
647 @return - connection parameter number
649 function GetInterbase6DatabaseParamNumber(const Value: AnsiString): Word;
652 ParamName: AnsiString;
654 ParamName := {$IFDEF WITH_UNITANSISTRINGS}AnsiStrings.{$ENDIF}AnsiLowerCase(Value);
656 if System.Pos(BPBPrefix, String(ParamName)) = 1 then
657 for I := 1 to MAX_DPB_PARAMS do
659 if ParamName = DatabaseParams[I].Name then
661 Result := DatabaseParams[I].Number;
668 Return interbase transaction parameter number by it name
669 @param Value - a transaction parameter name
670 @return - transaction parameter number
672 function GetInterbase6TransactionParamNumber(const Value: AnsiString): Word;
675 ParamName: AnsiString;
677 ParamName := {$IFDEF WITH_UNITANSISTRINGS}AnsiStrings.{$ENDIF}AnsiLowerCase(Value);
679 if System.Pos(TPBPrefix, String(ParamName)) = 1 then
680 for I := 1 to MAX_TPB_PARAMS do
682 if ParamName = TransactionParams[I].Name then
684 Result := TransactionParams[I].Number;
691 Converts a Interbase6 native types into ZDBC SQL types.
692 @param the interbase type
693 @param the interbase subtype
694 @return a SQL undepended type.
696 <b>Note:</b> The interbase type and subtype get from RDB$TYPES table
698 function ConvertInterbase6ToSqlType(SqlType, SqlSubType: Integer;
699 const CtrlsCPType: TZControlsCodePage): TZSQLType;
701 Result := ZDbcIntfs.stUnknown;
704 blr_bool, blr_not_nullable: Result := stBoolean;
705 blr_varying2, blr_varying, blr_cstring, blr_cstring2, blr_domain_name,
706 blr_domain_name2, blr_column_name, blr_column_name2:
710 CS_BINARY: Result := stBytes;
714 blr_d_float: Result := stDouble;
715 blr_float: Result := stFloat;
716 blr_double: Result := stDouble;
717 blr_blob_id, blr_quad: Result := stLong;
720 RDB_NUMBERS_NONE: Result := stLong;
721 RDB_NUMBERS_NUMERIC: Result := stDouble;
722 RDB_NUMBERS_DECIMAL: Result := stBigDecimal;
727 RDB_NUMBERS_NONE: Result := stInteger;
728 RDB_NUMBERS_NUMERIC: Result := stDouble;
729 RDB_NUMBERS_DECIMAL: Result := stBigDecimal;
735 RDB_NUMBERS_NONE: Result := stShort;
736 RDB_NUMBERS_NUMERIC: Result := stDouble;
737 RDB_NUMBERS_DECIMAL: Result := stDouble;
740 blr_sql_date: Result := stDate;
741 blr_sql_time: Result := stTime;
742 blr_timestamp: Result := stTimestamp;
747 { types less than zero are reserved for customer use }
748 isc_blob_untyped: Result := stBinaryStream;
750 { internal subtypes }
751 isc_blob_text: Result := stAsciiStream;
752 isc_blob_blr: Result := stBinaryStream;
753 isc_blob_acl: Result := stAsciiStream;
754 isc_blob_ranges: Result := stBinaryStream;
755 isc_blob_summary: Result := stBinaryStream;
756 isc_blob_format: Result := stAsciiStream;
757 isc_blob_tra: Result := stAsciiStream;
758 isc_blob_extfile: Result := stAsciiStream;
759 isc_blob_debug_info: Result := stBinaryStream;
763 Result := ZDbcIntfs.stUnknown;
765 if ( CtrlsCPType = cCP_UTF16) then
767 stString: Result := stUnicodeString;
768 stAsciiStream: Result := stUnicodeStream;
773 Return Interbase SqlType by it number
774 @param Value the SqlType number
776 function GetNameSqlType(Value: Word): AnsiString;
779 SQL_VARYING: Result := 'SQL_VARYING';
780 SQL_TEXT: Result := 'SQL_TEXT';
781 SQL_DOUBLE: Result := 'SQL_DOUBLE';
782 SQL_FLOAT: Result := 'SQL_FLOAT';
783 SQL_LONG: Result := 'SQL_LONG';
784 SQL_SHORT: Result := 'SQL_SHORT';
785 SQL_TIMESTAMP: Result := 'SQL_TIMESTAMP';
786 SQL_BLOB: Result := 'SQL_BLOB';
787 SQL_D_FLOAT: Result := 'SQL_D_FLOAT';
788 SQL_ARRAY: Result := 'SQL_ARRAY';
789 SQL_QUAD: Result := 'SQL_QUAD';
790 SQL_TYPE_TIME: Result := 'SQL_TYPE_TIME';
791 SQL_TYPE_DATE: Result := 'SQL_TYPE_DATE';
792 SQL_INT64: Result := 'SQL_INT64';
793 SQL_BOOLEAN: Result := 'SQL_BOOLEAN';
800 Checks for possible sql errors.
801 @param PlainDriver a Interbase Plain drver
802 @param StatusVector a status vector. It contain information about error
803 @param Sql a sql query commend
805 @Param Integer Return is the ErrorCode that happened - for disconnecting the database
807 function CheckInterbase6Error(PlainDriver: IZInterbasePlainDriver;
808 StatusVector: TARRAY_ISC_STATUS; LoggingCategory: TZLoggingCategory = lcOther;
809 SQL: string = '') : Integer;
811 Msg: array[0..1024] of AnsiChar;
812 PStatusVector: PISC_STATUS;
813 ErrorMessage, ErrorSqlMessage: string;
817 if (StatusVector[0] = 1) and (StatusVector[1] > 0) then
820 PStatusVector := @StatusVector;
821 while PlainDriver.isc_interprete(Msg, @PStatusVector) > 0 do
822 ErrorMessage := ErrorMessage + ' ' + String(Msg);
824 ErrorCode := PlainDriver.isc_sqlcode(@StatusVector);
825 PlainDriver.isc_sql_interprete(ErrorCode, Msg, 1024);
826 ErrorSqlMessage := String(Msg);
828 {$IFDEF INTERBASE_EXTENDED_MESSAGES}
830 SQL := Format(' The SQL: %s; ', [SQL]);
833 if ErrorMessage <> '' then
835 DriverManager.LogError(LoggingCategory, PlainDriver.GetProtocol,
836 ErrorMessage, ErrorCode, ErrorSqlMessage + SQL);
838 //AVZ Ignore error codes for disconnected database -901, -902
839 if ((ErrorCode <> -901) and (ErrorCode <> -902)) then
841 {$IFDEF INTERBASE_EXTENDED_MESSAGES}
842 raise EZSQLException.CreateWithCode(ErrorCode,
843 Format('SQL Error: %s. Error Code: %d. %s',
844 [ErrorMessage, ErrorCode, ErrorSqlMessage]) + SQL);
846 raise EZSQLException.CreateWithCode(ErrorCode,
847 Format('SQL Error: %s. Error Code: %d. %s',
848 [ErrorMessage, ErrorCode, ErrorSqlMessage]));
852 begin //AVZ -- Added exception back in to help error trapping
853 raise EZSQLException.CreateWithCode(ErrorCode,
854 Format('SQL Error: %s. Error Code: %d. %s',
855 [ErrorMessage, ErrorCode, ErrorSqlMessage]));
857 Result := DISCONNECT_ERROR;
864 Prepare statement and create statement handle.
865 @param PlainDriver a interbase plain driver
866 @param Handle a interbase connection handle
867 @param TrHandle a transaction handle
868 @param Dialect a interbase sql dialect number
869 @param Sql a sql query
870 @param StmtHandle a statement handle
871 @param SqlData a interbase sql result data
872 @return sql statement type
874 function PrepareStatement(PlainDriver: IZInterbasePlainDriver;
875 Handle: PISC_DB_HANDLE; TrHandle: PISC_TR_HANDLE; Dialect: Word;
876 SQL: RawByteString; LogSQL: String; var StmtHandle: TISC_STMT_HANDLE):
877 TZIbSqlStatementType;
879 StatusVector: TARRAY_ISC_STATUS;
880 iError : Integer; //Error for disconnect
882 { Allocate an sql statement }
883 if StmtHandle = 0 then
885 PlainDriver.isc_dsql_allocate_statement(@StatusVector, Handle, @StmtHandle);
886 CheckInterbase6Error(PlainDriver, StatusVector, lcOther, LogSQL);
888 { Prepare an sql statement }
889 PlainDriver.isc_dsql_prepare(@StatusVector, TrHandle, @StmtHandle,
890 0, PAnsiChar(SQL), Dialect, nil);
892 iError := CheckInterbase6Error(PlainDriver, StatusVector, lcPrepStmt, LogSQL); //Check for disconnect AVZ
894 { Set Statement Type }
895 if (iError <> DISCONNECT_ERROR) then //AVZ
896 Result := GetStatementType(PlainDriver, StmtHandle)
898 Result := stDisconnect;
900 if Result in [stUnknown, stGetSegment, stPutSegment, stStartTrans] then
902 FreeStatement(PlainDriver, StmtHandle, DSQL_CLOSE); //AVZ
903 raise EZSQLException.Create(SStatementIsNotAllowed);
908 Describe SQLDA and allocate memory for result values.
909 @param PlainDriver a interbase plain driver
910 @param Handle a interbase connection handle
911 @param Dialect a interbase sql dialect number
912 @param Sql a sql query
913 @param StmtHandle a statement handle
914 @param SqlData a interbase sql result data
916 procedure PrepareResultSqlData(PlainDriver: IZInterbasePlainDriver;
917 Handle: PISC_DB_HANDLE; Dialect: Word; LogSQL: string;
918 var StmtHandle: TISC_STMT_HANDLE; SqlData: IZResultSQLDA);
920 StatusVector: TARRAY_ISC_STATUS;
922 { Initialise ouput param and fields }
923 PlainDriver.isc_dsql_describe(@StatusVector, @StmtHandle, Dialect,
925 CheckInterbase6Error(PlainDriver, StatusVector, lcExecute, LogSQL);
927 if SqlData.GetData^.sqld > SqlData.GetData^.sqln then
929 SqlData.AllocateSQLDA;
930 PlainDriver.isc_dsql_describe(@StatusVector, @StmtHandle,
931 Dialect, SqlData.GetData);
932 CheckInterbase6Error(PlainDriver, StatusVector, lcExecute, LogSql);
934 SqlData.InitFields(False);
938 Return interbase statement type by statement handle
939 @param PlainDriver a interbase plain driver
940 @param StmtHandle a statement handle
941 @return interbase statement type
943 function GetStatementType(PlainDriver: IZInterbasePlainDriver;
944 StmtHandle: TISC_STMT_HANDLE): TZIbSqlStatementType;
947 StatusVector: TARRAY_ISC_STATUS;
948 StatementLength: integer;
949 StatementBuffer: array[0..7] of AnsiChar;
952 TypeItem := AnsiChar(isc_info_sql_stmt_type);
954 { Get information about a prepared DSQL statement. }
955 PlainDriver.isc_dsql_sql_info(@StatusVector, @StmtHandle, 1,
956 @TypeItem, SizeOf(StatementBuffer), StatementBuffer);
957 CheckInterbase6Error(PlainDriver, StatusVector);
959 if StatementBuffer[0] = AnsiChar(isc_info_sql_stmt_type) then
961 StatementLength := PlainDriver.isc_vax_integer(
962 @StatementBuffer[1], 2);
963 Result := TZIbSqlStatementType(PlainDriver.isc_vax_integer(
964 @StatementBuffer[3], StatementLength));
969 Free interbse allocated statement and SQLDA for input and utput parameters
970 @param the interbase plain driver
971 @param the interbse statement handle
973 procedure FreeStatement(PlainDriver: IZInterbasePlainDriver; StatementHandle: TISC_STMT_HANDLE; Options: Word);
975 StatusVector: TARRAY_ISC_STATUS;
977 if StatementHandle <> 0 then
978 PlainDriver.isc_dsql_free_statement(@StatusVector, @StatementHandle, Options);
979 //CheckInterbase6Error(PlainDriver, StatusVector); //raises an unwanted exception if Connection was reopened See: http://sourceforge.net/p/zeoslib/tickets/40/
984 <i>Note:<i> it function may call after statement execution
985 @param PlainDriver a interbase plain driver
986 @param StmtHandle a statement handle
987 @param StatementType a statement type
988 @return affected rows
990 function GetAffectedRows(PlainDriver: IZInterbasePlainDriver;
991 StmtHandle: TISC_STMT_HANDLE; StatementType: TZIbSqlStatementType): Integer;
994 OutBuffer: array[0..255] of AnsiChar;
995 StatusVector: TARRAY_ISC_STATUS;
998 ReqInfo := AnsiChar(isc_info_sql_records);
1000 if PlainDriver.isc_dsql_sql_info(@StatusVector, @StmtHandle, 1,
1001 @ReqInfo, SizeOf(OutBuffer), OutBuffer) > 0 then
1003 CheckInterbase6Error(PlainDriver, StatusVector);
1004 if OutBuffer[0] = AnsiChar(isc_info_sql_records) then
1006 case StatementType of
1007 stUpdate: Result := PlainDriver.isc_vax_integer(@OutBuffer[6], 4);
1008 stDelete: Result := PlainDriver.isc_vax_integer(@OutBuffer[13], 4);
1009 stSelect: Result := PlainDriver.isc_vax_integer(@OutBuffer[20], 4);
1010 stInsert: Result := PlainDriver.isc_vax_integer(@OutBuffer[27], 4);
1018 Prepare sql statement parameters and fill parameters by values
1019 @param PlainDriver a interbase plain driver
1020 @param Dialect a interbase sql dialect number
1021 @param StmtHandle a statement handle
1022 @param SqlData a interbase sql result data
1024 procedure PrepareParameters(PlainDriver: IZInterbasePlainDriver; LogSQL: string;
1025 Dialect: Word; var StmtHandle: TISC_STMT_HANDLE; ParamSqlData: IZParamsSQLDA);
1027 StatusVector: TARRAY_ISC_STATUS;
1030 PlainDriver.isc_dsql_describe_bind(@StatusVector, @StmtHandle, Dialect,
1031 ParamSqlData.GetData);
1032 CheckInterbase6Error(PlainDriver, StatusVector, lcExecute, LogSQL);
1034 { Resize XSQLDA structure if needed }
1035 if ParamSqlData.GetData^.sqld > ParamSqlData.GetData^.sqln then
1037 ParamSqlData.AllocateSQLDA;
1038 PlainDriver.isc_dsql_describe_bind(@StatusVector, @StmtHandle, Dialect,
1039 ParamSqlData.GetData);
1040 CheckInterbase6Error(PlainDriver, StatusVector, lcExecute, LogSQL);
1043 ParamSqlData.InitFields(True);
1046 procedure BindSQLDAInParameters(PlainDriver: IZInterbasePlainDriver;
1047 InParamValues: TZVariantDynArray; InParamTypes: TZSQLTypeArray;
1048 InParamCount: Integer; ParamSqlData: IZParamsSQLDA; ConSettings: PZConSettings);
1052 TempStream: TStream;
1054 if InParamCount <> ParamSqlData.GetFieldCount then
1055 raise EZSQLException.Create(SInvalidInputParameterCount);
1058 for I := 0 to ParamSqlData.GetFieldCount - 1 do
1060 ParamSqlData.UpdateNull(I, DefVarManager.IsNull(InParamValues[I]));
1061 if DefVarManager.IsNull(InParamValues[I])then
1064 case InParamTypes[I] of
1066 ParamSqlData.UpdateBoolean(I,
1067 SoftVarManager.GetAsBoolean(InParamValues[I]));
1069 ParamSqlData.UpdateByte(I,
1070 SoftVarManager.GetAsInteger(InParamValues[I]));
1072 ParamSqlData.UpdateShort(I,
1073 SoftVarManager.GetAsInteger(InParamValues[I]));
1075 ParamSqlData.UpdateInt(I,
1076 SoftVarManager.GetAsInteger(InParamValues[I]));
1078 ParamSqlData.UpdateLong(I,
1079 SoftVarManager.GetAsInteger(InParamValues[I]));
1081 ParamSqlData.UpdateFloat(I,
1082 SoftVarManager.GetAsFloat(InParamValues[I]));
1084 ParamSqlData.UpdateDouble(I,
1085 SoftVarManager.GetAsFloat(InParamValues[I]));
1087 ParamSqlData.UpdateBigDecimal(I,
1088 SoftVarManager.GetAsFloat(InParamValues[I]));
1090 if ( ConSettings.ClientCodePage.ID = CS_NONE ) and not
1091 (ParamSqlData.GetIbSqlSubType(I) = CS_NONE) then //CharSet 'NONE' writes data 'as is'!
1092 ParamSqlData.UpdateString(I,
1093 PlainDriver.ZPlainString(SoftVarManager.GetAsString(InParamValues[I]),
1094 ConSettings, PlainDriver.ValidateCharEncoding(ParamSqlData.GetIbSqlSubType(I)).CP))
1096 ParamSqlData.UpdateString(I,
1097 PlainDriver.ZPlainString(SoftVarManager.GetAsString(InParamValues[I]), ConSettings));
1099 if ( ConSettings.ClientCodePage.ID = CS_NONE ) and not
1100 (ParamSqlData.GetIbSqlSubType(I) = CS_NONE) then //CharSet 'NONE' writes data 'as is'!
1101 ParamSqlData.UpdateString(I,
1102 PlainDriver.ZPlainString(SoftVarManager.GetAsUnicodeString(InParamValues[I]),
1103 ConSettings, PlainDriver.ValidateCharEncoding(ParamSqlData.GetIbSqlSubType(I)).CP))
1105 ParamSqlData.UpdateString(I,
1106 PlainDriver.ZPlainString(SoftVarManager.GetAsUnicodeString(InParamValues[I]), ConSettings));
1108 ParamSqlData.UpdateBytes(I, SoftVarManager.GetAsBytes(InParamValues[I]));
1110 ParamSqlData.UpdateDate(I,
1111 SoftVarManager.GetAsDateTime(InParamValues[I]));
1113 ParamSqlData.UpdateTime(I,
1114 SoftVarManager.GetAsDateTime(InParamValues[I]));
1116 ParamSqlData.UpdateTimestamp(I,
1117 SoftVarManager.GetAsDateTime(InParamValues[I]));
1122 TempBlob := DefVarManager.GetAsInterface(InParamValues[I]) as IZBlob;
1123 if not TempBlob.IsEmpty then
1125 if (ParamSqlData.GetFieldSqlType(i) in [stUnicodeStream, stAsciiStream] ) then
1126 TempStream := TStringStream.Create(GetValidatedAnsiStringFromBuffer(TempBlob.GetBuffer, TempBlob.Length,
1127 TempBlob.WasDecoded, ConSettings))
1129 TempStream := TempBlob.GetStream;
1130 if Assigned(TempStream) then
1132 ParamSqlData.WriteBlob(I, TempStream);
1138 raise EZIBConvertError.Create(SUnsupportedParameterType);
1146 Read blob information by it handle such as blob segment size, segments count,
1149 @param BlobInfo the blob information structure
1151 procedure GetBlobInfo(PlainDriver: IZInterbasePlainDriver;
1152 BlobHandle: TISC_BLOB_HANDLE; var BlobInfo: TIbBlobInfo);
1154 Items: array[0..3] of AnsiChar;
1155 Results: array[0..99] of AnsiChar;
1156 I, ItemLength: Integer;
1158 StatusVector: TARRAY_ISC_STATUS;
1161 Items[0] := AnsiChar(isc_info_blob_num_segments);
1162 Items[1] := AnsiChar(isc_info_blob_max_segment);
1163 Items[2] := AnsiChar(isc_info_blob_total_length);
1164 Items[3] := AnsiChar(isc_info_blob_type);
1166 if PlainDriver.isc_blob_info(@StatusVector, @BlobHandle, 4, @items[0],
1167 SizeOf(Results), @Results[0]) > 0 then
1168 CheckInterbase6Error(PlainDriver, StatusVector);
1170 while (I < SizeOf(Results)) and (Results[I] <> AnsiChar(isc_info_end)) do
1172 Item := Integer(Results[I]);
1174 ItemLength := PlainDriver.isc_vax_integer(@results[I], 2);
1177 isc_info_blob_num_segments:
1178 BlobInfo.NumSegments := PlainDriver.isc_vax_integer(@Results[I], ItemLength);
1179 isc_info_blob_max_segment:
1180 BlobInfo.MaxSegmentSize := PlainDriver.isc_vax_integer(@Results[I], ItemLength);
1181 isc_info_blob_total_length:
1182 BlobInfo.TotalSize := PlainDriver.isc_vax_integer(@Results[I], ItemLength);
1184 BlobInfo.BlobType := PlainDriver.isc_vax_integer(@Results[I], ItemLength);
1191 Read blob field data to stream by it ISC_QUAD value
1192 Note: DefaultBlobSegmentSize constant used for limit segment size reading
1193 @param Handle the database connection handle
1194 @param TransactionHandle the transaction handle
1195 @param BlobId the ISC_QUAD structure
1196 @param Size the result buffer size
1197 @param Buffer the pointer to result buffer
1199 Note: Buffer must be nill. Function self allocate memory for data
1202 procedure ReadBlobBufer(PlainDriver: IZInterbasePlainDriver;
1203 Handle: PISC_DB_HANDLE; TransactionHandle: PISC_TR_HANDLE;
1204 BlobId: TISC_QUAD; var Size: Integer; var Buffer: Pointer);
1206 TempBuffer: PAnsiChar;
1207 BlobInfo: TIbBlobInfo;
1208 BlobSize, CurPos: LongInt;
1209 BytesRead, SegmentLenght: UShort;
1210 BlobHandle: TISC_BLOB_HANDLE;
1211 StatusVector: TARRAY_ISC_STATUS;
1215 // SegmentLenght := UShort(DefaultBlobSegmentSize);
1218 PlainDriver.isc_open_blob2(@StatusVector, Handle,
1219 TransactionHandle, @BlobHandle, @BlobId, 0 , nil);
1220 CheckInterbase6Error(PlainDriver, StatusVector);
1223 GetBlobInfo(PlainDriver, BlobHandle, BlobInfo);
1224 BlobSize := BlobInfo.TotalSize;
1227 SegmentLenght := BlobInfo.MaxSegmentSize;
1229 { Allocates a blob buffer }
1230 Buffer := AllocMem(BlobSize);
1231 TempBuffer := Buffer;
1233 { Copies data to blob buffer }
1234 while CurPos < BlobSize do
1236 if (CurPos + SegmentLenght > BlobSize) then
1237 SegmentLenght := BlobSize - CurPos;
1238 if not(PlainDriver.isc_get_segment(@StatusVector, @BlobHandle,
1239 @BytesRead, SegmentLenght, TempBuffer) = 0) or
1240 (StatusVector[1] <> isc_segment) then
1241 CheckInterbase6Error(PlainDriver, StatusVector);
1242 Inc(CurPos, BytesRead);
1243 Inc(TempBuffer, BytesRead);
1247 { close blob handle }
1248 PlainDriver.isc_close_blob(@StatusVector, @BlobHandle);
1249 CheckInterbase6Error(PlainDriver, StatusVector);
1252 function GetIBScaleDivisor(Scale: SmallInt): Int64;
1258 for i := 1 to Scale do
1259 Result := Result * 10
1262 for i := -1 downto Scale do
1263 Result := Result * 10;
1266 Return interbase server version string
1267 @param PlainDriver a interbase plain driver
1268 @param Handle the database connection handle
1269 @return interbase version string
1271 function GetVersion(PlainDriver: IZInterbasePlainDriver;
1272 Handle: PISC_DB_HANDLE): AnsiString;
1274 DatabaseInfoCommand: AnsiChar;
1275 StatusVector: TARRAY_ISC_STATUS;
1276 Buffer: array[0..IBBigLocalBufferLength - 1] of AnsiChar;
1278 DatabaseInfoCommand := AnsiChar(isc_info_version);
1279 PlainDriver.isc_database_info(@StatusVector, Handle, 1, @DatabaseInfoCommand,
1280 IBBigLocalBufferLength, Buffer);
1281 CheckInterbase6Error(PlainDriver, StatusVector);
1282 Buffer[5 + Integer(Buffer[4])] := #0;
1283 result := AnsiString(PAnsiChar(@Buffer[5]));
1287 Return interbase database implementation
1288 @param PlainDriver a interbase plain driver
1289 @param Handle the database connection handle
1290 @return interbase database implementation
1292 function GetDBImplementationNo(PlainDriver: IZInterbasePlainDriver;
1293 Handle: PISC_DB_HANDLE): LongInt;
1295 DatabaseInfoCommand: AnsiChar;
1296 StatusVector: TARRAY_ISC_STATUS;
1297 Buffer: array[0..IBBigLocalBufferLength - 1] of AnsiChar;
1299 DatabaseInfoCommand := AnsiChar(isc_info_implementation);
1300 PlainDriver.isc_database_info(@StatusVector, Handle, 1, @DatabaseInfoCommand,
1301 IBLocalBufferLength, Buffer);
1302 CheckInterbase6Error(PlainDriver, StatusVector);
1303 result := PlainDriver.isc_vax_integer(@Buffer[3], 1);
1307 Return interbase database implementation class
1308 @param PlainDriver a interbase plain driver
1309 @param Handle the database connection handle
1310 @return interbase database implementation class
1312 function GetDBImplementationClass(PlainDriver: IZInterbasePlainDriver;
1313 Handle: PISC_DB_HANDLE): LongInt;
1315 DatabaseInfoCommand: AnsiChar;
1316 StatusVector: TARRAY_ISC_STATUS;
1317 Buffer: array[0..IBBigLocalBufferLength - 1] of AnsiChar;
1319 DatabaseInfoCommand := AnsiChar(isc_info_implementation);
1320 PlainDriver.isc_database_info(@StatusVector, Handle, 1, @DatabaseInfoCommand,
1321 IBLocalBufferLength, Buffer);
1322 CheckInterbase6Error(PlainDriver, StatusVector);
1323 result := PlainDriver.isc_vax_integer(@Buffer[4], 1);
1327 Return interbase database info
1328 @param PlainDriver a interbase plain driver
1329 @param Handle the database connection handle
1330 @param DatabaseInfoCommand a database information command
1331 @return interbase database info
1333 function GetLongDbInfo(PlainDriver: IZInterbasePlainDriver;
1334 Handle: PISC_DB_HANDLE; DatabaseInfoCommand: Integer): LongInt;
1337 DatabaseInfoCommand1: AnsiChar;
1338 StatusVector: TARRAY_ISC_STATUS;
1339 Buffer: array[0..IBBigLocalBufferLength - 1] of AnsiChar;
1341 DatabaseInfoCommand1 := AnsiChar(DatabaseInfoCommand);
1342 PlainDriver.isc_database_info(@StatusVector, Handle, 1, @DatabaseInfoCommand1,
1343 IBLocalBufferLength, Buffer);
1344 CheckInterbase6Error(PlainDriver, StatusVector);
1345 Length := PlainDriver.isc_vax_integer(@Buffer[1], 2);
1346 Result := PlainDriver.isc_vax_integer(@Buffer[4], Length);
1350 Return interbase database info string
1351 @param PlainDriver a interbase plain driver
1352 @param Handle a database connection handle
1353 @param DatabaseInfoCommand a database information command
1354 @return interbase database info string
1356 function GetStringDbInfo(PlainDriver: IZInterbasePlainDriver;
1357 Handle: PISC_DB_HANDLE; DatabaseInfoCommand: Integer): AnsiString;
1359 DatabaseInfoCommand1: AnsiChar;
1360 StatusVector: TARRAY_ISC_STATUS;
1361 Buffer: array[0..IBBigLocalBufferLength - 1] of AnsiChar;
1363 DatabaseInfoCommand1 := AnsiChar(DatabaseInfoCommand);
1364 PlainDriver.isc_database_info(@StatusVector, Handle, 1, @DatabaseInfoCommand1,
1365 IBLocalBufferLength, Buffer);
1366 CheckInterbase6Error(PlainDriver, StatusVector);
1367 Buffer[4 + Integer(Buffer[3])] := #0;
1368 Result := AnsiString(PAnsiChar(@Buffer[4]));
1372 Return interbase database dialect
1373 @param PlainDriver a interbase plain driver
1374 @param Handle the database connection handle
1375 @return interbase database dialect
1377 function GetDBSQLDialect(PlainDriver: IZInterbasePlainDriver;
1378 Handle: PISC_DB_HANDLE): Integer;
1381 DatabaseInfoCommand1: AnsiChar;
1382 StatusVector: TARRAY_ISC_STATUS;
1383 Buffer: array[0..IBBigLocalBufferLength - 1] of AnsiChar;
1385 DatabaseInfoCommand1 := AnsiChar(isc_info_db_SQL_Dialect);
1386 PlainDriver.isc_database_info(@StatusVector, Handle, 1, @DatabaseInfoCommand1,
1387 IBLocalBufferLength, Buffer);
1388 CheckInterbase6Error(PlainDriver, StatusVector);
1389 if (Buffer[0] <> AnsiChar(isc_info_db_SQL_dialect)) then
1393 Length := PlainDriver.isc_vax_integer(@Buffer[1], 2);
1394 Result := PlainDriver.isc_vax_integer(@Buffer[3], Length);
1399 constructor TZSQLDA.Create(PlainDriver: IZInterbasePlainDriver;
1400 Handle: PISC_DB_HANDLE; TransactionHandle: PISC_TR_HANDLE;
1401 ConSettings: PZConSettings);
1403 Self.ConSettings := ConSettings;
1404 FPlainDriver := PlainDriver;
1406 FTransactionHandle := TransactionHandle;
1408 GetMem(FXSQLDA, XSQLDA_LENGTH(0));
1409 FillChar(FXSQLDA^, XSQLDA_LENGTH(0), 0);
1413 FXSQLDA.version := SQLDA_VERSION1;
1416 Allocate memory for SQLVar in SQLDA structure for every
1417 fields by it length.
1419 procedure TZSQLDA.InitFields(Parameters: boolean);
1425 for I := 0 to FXSQLDA.sqld - 1 do
1427 SqlVar := @FXSQLDA.SqlVar[I];
1428 case SqlVar.sqltype and (not 1) of
1429 SQL_BOOLEAN, SQL_TEXT, SQL_TYPE_DATE, SQL_TYPE_TIME, SQL_DATE,
1430 SQL_BLOB, SQL_ARRAY, SQL_QUAD, SQL_SHORT,
1431 SQL_LONG, SQL_INT64, SQL_DOUBLE, SQL_FLOAT, SQL_D_FLOAT:
1433 if SqlVar.sqllen = 0 then
1434 IbReAlloc(SqlVar.sqldata, 0, 1)
1436 IbReAlloc(SqlVar.sqldata, 0, SqlVar.sqllen)
1439 IbReAlloc(SqlVar.sqldata, 0, SqlVar.sqllen + 2)
1442 if Parameters = True then
1444 //This code used when allocated sqlind parameter for Param SQLDA
1445 SqlVar.sqltype := SqlVar.sqltype or 1;
1446 IbReAlloc(SqlVar.sqlind, 0, SizeOf(Short))
1450 //This code used when allocated sqlind parameter for Result SQLDA
1451 if (SqlVar.sqltype and 1) <> 0 then
1452 ReallocMem(SqlVar.sqlind, SizeOf(Short))
1454 SqlVar.sqlind := nil;
1463 Clear allocated data for SQLDA paramters
1465 procedure TZSQLDA.FreeParamtersValues;
1471 for I := 0 to FXSQLDA.sqln - 1 do
1473 SqlVar := @FXSQLDA.SqlVar[I];
1474 FreeMem(SqlVar.sqldata);
1475 FreeMem(SqlVar.sqlind);
1476 SqlVar.sqldata := nil;
1477 SqlVar.sqlind := nil;
1485 Chech reange count fields. If index out of range raised exception.
1486 @param Index the index field
1488 procedure TZSQLDA.CheckRange(const Index: Word);
1490 Assert(Index < Word(FXSQLDA.sqln), 'Out of Range.');
1494 Return alias name for field
1495 @param Index the index fields
1496 @return the alias name
1498 function TZSQLDA.GetFieldAliasName(const Index: Word): String;
1502 SetString(Temp, FXSQLDA.sqlvar[Index].aliasname, FXSQLDA.sqlvar[Index].aliasname_length);
1503 Result := ZDbcString(Temp);
1510 Return pointer to SQLDA structure
1512 function TZSQLDA.GetData: PXSQLDA;
1518 Get fields count not allocated.
1519 @return fields count
1521 function TZSQLDA.GetFieldCount: Integer;
1523 Result := FXSQLDA.sqld;
1527 Return field index by it name
1528 @param Index the index fields
1529 @return the index field
1531 function TZSQLDA.GetFieldIndex(const Name: AnsiString): Word;
1534 for Result := 0 to GetFieldCount - 1 do
1535 if FXSQLDA.sqlvar[Result].aliasname_length = Length(name) then
1536 if {$IFDEF WITH_STRLICOPY_DEPRECATED}AnsiStrings.{$ENDIF}StrLIComp(@FXSQLDA.sqlvar[Result].aliasname, PAnsiChar(Name), FXSQLDA.sqlvar[Result].aliasname_length) = 0 then
1538 raise Exception.Create(Format(SFieldNotFound1, [name]));
1546 @param Index the index fields
1547 @return the field lenth
1549 function TZSQLDA.GetFieldLength(const Index: Word): SmallInt;
1552 case GetIbSqlType(Index) of
1553 SQL_TEXT: Result := GetIbSqlLen(Index);
1554 SQL_VARYING: Result := GetIbSqlLen(Index);
1555 //SQL_VARYING: Result := FPlainDriver.isc_vax_integer(GetData.sqlvar[Index].sqldata, 2); //AVZ
1557 Result := GetIbSqlLen(Index);
1566 @param Index the index fields
1567 @return the field scale
1569 function TZSQLDA.GetFieldScale(const Index: Word): integer;
1573 Result := Abs(FXSQLDA.sqlvar[Index].sqlscale);
1580 Convert Interbase sql type to SQLType
1581 @param Index the index fields
1584 function TZSQLDA.GetFieldSqlType(const Index: Word): TZSQLType;
1587 SqlSubType: Integer;
1589 SqlScale := GetFieldScale(Index);
1590 SqlSubType := GetIbSqlSubType(Index);
1592 case GetIbSqlType(Index) of
1593 SQL_VARYING, SQL_TEXT:
1595 1: {Octets} Result := stBytes;
1601 if SqlScale = 0 then
1608 if SqlScale = 0 then
1611 Result := stFloat; //Numeric with low precision
1613 SQL_FLOAT: Result := stFloat;
1614 SQL_DOUBLE: Result := stDouble;
1615 SQL_DATE: Result := stTimestamp;
1616 SQL_TYPE_TIME: Result := stTime;
1617 SQL_TYPE_DATE: Result := stDate;
1620 if SqlScale = 0 then
1622 else if Abs(SqlScale) <= 4 then
1625 Result := stBigDecimal;
1627 SQL_QUAD, SQL_ARRAY, SQL_BLOB:
1629 if SqlSubType = isc_blob_text then
1630 Result := stAsciiStream
1632 Result := stBinaryStream;
1634 //SQL_ARRAY: Result := stBytes;
1638 if ( ConSettings.CPType = cCP_UTF16 ) then
1640 stString: Result := stUnicodeString;
1641 stAsciiStream: Result := stUnicodeStream;
1646 Return own name for field
1647 @param Index the index fields
1648 @return the own name
1650 function TZSQLDA.GetFieldOwnerName(const Index: Word): String;
1654 {$IFDEF WITH_RAWBYTESTRING}
1655 SetLength(Temp, FXSQLDA.sqlvar[Index].OwnName_length);
1656 System.Move(FXSQLDA.sqlvar[Index].OwnName, PAnsiChar(Temp)^, FXSQLDA.sqlvar[Index].OwnName_length);
1658 SetString(Temp, FXSQLDA.sqlvar[Index].OwnName, FXSQLDA.sqlvar[Index].OwnName_length);
1660 Result := ZDbcString(Temp);
1667 Return real name for field
1668 @param Index the index fields
1669 @return the real name
1671 function TZSQLDA.GetFieldRelationName(const Index: Word): String;
1675 {$IFDEF WITH_RAWBYTESTRING}
1676 SetLength(Temp, FXSQLDA.sqlvar[Index].RelName_length);
1677 System.Move(FXSQLDA.sqlvar[Index].RelName, PAnsiChar(Temp)^, FXSQLDA.sqlvar[Index].RelName_length);
1679 SetString(Temp, FXSQLDA.sqlvar[Index].RelName, FXSQLDA.sqlvar[Index].RelName_length);
1681 Result := ZDbcString(Temp);
1688 Get Interbase sql fields lenth
1689 @param Index the index fields
1690 @return Interbase sql fields lenth
1692 function TZSQLDA.GetIbSqlLen(const Index: Word): Smallint;
1696 result := FXSQLDA.sqlvar[Index].sqllen;
1703 Return sql name for field
1704 @param Index the index fields
1705 @return the sql name
1707 function TZSQLDA.GetFieldSqlName(const Index: Word): String;
1711 {$IFDEF WITH_RAWBYTESTRING}
1712 SetLength(Temp, FXSQLDA.sqlvar[Index].sqlname_length);
1713 System.Move(FXSQLDA.sqlvar[Index].sqlname, PAnsiChar(Temp)^, FXSQLDA.sqlvar[Index].sqlname_length);
1715 SetString(Temp, FXSQLDA.sqlvar[Index].sqlname, FXSQLDA.sqlvar[Index].sqlname_length);
1717 Result := ZDbcString(Temp);
1724 Get Interbase subsql type
1725 @param Index the index fields
1726 @return the Interbase subsql
1728 function TZSQLDA.GetIbSqlSubType(const Index: Word): Smallint;
1732 result := FXSQLDA.sqlvar[Index].sqlsubtype;
1739 Get Interbase sql type
1740 @param Index the index fields
1741 @return the interbase sql type
1743 function TZSQLDA.GetIbSqlType(const Index: Word): Smallint;
1747 result := FXSQLDA.sqlvar[Index].sqltype and not (1);
1754 Reallocate memory and fill memory by #0
1755 @param pointer to memory block
1756 @param old size of memory block
1757 @param new size of memory block
1759 procedure TZSQLDA.IbReAlloc(var P; OldSize, NewSize: Integer);
1761 ReallocMem(Pointer(P), NewSize);
1762 if NewSize > OldSize then
1763 Fillchar((PAnsiChar(P) + OldSize)^, NewSize - OldSize, #0);
1766 procedure TZSQLDA.SetFieldType(const Index: Word; Size: Integer; Code: Smallint;
1771 with FXSQLDA.sqlvar[Index] do
1778 IbReAlloc(sqldata, 0, Size)
1792 @param Index the index fields
1793 @return true if blob field overwise false
1795 function TZSQLDA.IsBlob(const Index: Word): boolean;
1799 result := ((FXSQLDA.sqlvar[Index].sqltype and not(1)) = SQL_BLOB);
1807 @param Index the index fields
1808 @return true if field nullable overwise false
1810 function TZSQLDA.IsNullable(const Index: Word): boolean;
1814 Result := FXSQLDA.sqlvar[Index].sqltype and 1 = 1
1821 Reallocate SQLDA to fields count length
1822 @param Value the count fields
1824 procedure TZSQLDA.AllocateSQLDA;
1826 IbReAlloc(FXSQLDA, XSQLDA_LENGTH(FXSQLDA.sqln), XSQLDA_LENGTH(FXSQLDA.sqld));
1827 FXSQLDA.sqln := FXSQLDA.sqld;
1833 Free allocated memory and free object
1835 destructor TZParamsSQLDA.Destroy;
1837 FreeParamtersValues;
1843 Encode pascal string to Interbase paramter buffer
1844 @param Code the Interbase data type
1845 @param Index the index target filed
1846 @param Str the source string
1849 procedure TZParamsSQLDA.EncodeString(Code: Smallint; const Index: Word;
1850 const Str: RawByteString);
1856 with FXSQLDA.sqlvar[Index] do
1860 if (sqllen = 0) and (Str <> '') then //Manits: #0000249/pktfag
1861 GetMem(sqldata, Len)
1863 IbReAlloc(sqldata, 0, Len + 1);
1865 Move(PAnsiChar(Str)^, sqldata^, sqllen);
1870 if sqllen = 0 then //Egonhugeist: Todo: Need test case. Can't believe this line is correct! sqllen is min 2
1871 GetMem(sqldata, Len + 2)
1873 IbReAlloc(sqldata, 0, Len + 2);
1874 PISC_VARYING(sqldata).strlen := Len;
1875 Move(PAnsiChar(Str)^, PISC_VARYING(sqldata).str, PISC_VARYING(sqldata).strlen);
1884 Encode Bytes dynamic array to Interbase paramter buffer
1885 @param Code the Interbase data type
1886 @param Index the index target filed
1887 @param Value the source array
1890 procedure TZParamsSQLDA.EncodeBytes(Code: Smallint; const Index: Word;
1891 const Value: TByteDynArray);
1895 Len := Length(Value);
1897 with FXSQLDA.sqlvar[Index] do
1901 if (sqllen = 0) and ( Len <> 0 ) then //Manits: #0000249/pktfag
1902 GetMem(sqldata, Len)
1904 IbReAlloc(sqldata, 0, Len + 1);
1906 Move(Pointer(Value)^, sqldata^, sqllen);
1911 if sqllen = 0 then //Egonhugeist: Todo: Need test case. Can't believe this line is correct! sqllen is min 2
1912 GetMem(sqldata, Len + 2)
1914 IbReAlloc(sqldata, 0, Len + 2);
1915 PISC_VARYING(sqldata).strlen := Len;
1916 Move(Pointer(Value)^, PISC_VARYING(sqldata).str, PISC_VARYING(sqldata).strlen);
1925 Set up parameter BigDecimal value
1926 @param Index the target parameter index
1927 @param Value the source value
1929 procedure TZParamsSQLDA.UpdateBigDecimal(const Index: Integer; Value: Extended);
1936 with FXSQLDA.sqlvar[Index] do
1938 if (sqlind <> nil) and (sqlind^ = -1) then
1941 SQLCode := (sqltype and not(1));
1943 if (sqlscale < 0) then
1944 begin //http://code.google.com/p/fbclient/wiki/DatatypeMapping
1946 SQL_SHORT : PSmallInt(sqldata)^ := Trunc(Value * IBScaleDivisor[sqlscale]);
1947 SQL_LONG : PInteger(sqldata)^ := Trunc(Value * IBScaleDivisor[sqlscale]);
1949 SQL_QUAD : //PInt64(sqldata)^ := Trunc(Value * GetIBScaleDivisor(sqlscale)); EgonHugeist: Trunc seems to have rounding issues!
1950 //remain issues if decimal digits > scale than we've school learned rounding success randomly only
1951 //each aproach did fail: RoundTo(Value, sqlscale*-1), Round etc.
1952 //so the developer has to take
1953 PInt64(sqldata)^ := StrToInt64(FloatToStrF(RoundTo(Value, sqlscale) * GetIBScaleDivisor(sqlscale), ffFixed, 18, 0));
1954 SQL_DOUBLE : PDouble(sqldata)^ := Value; //I have tested with Query.ParamByName ().AsCurrency to check this, problem does not lie with straight SQL
1956 raise EZIBConvertError.Create(SUnsupportedDataType);
1961 SQL_DOUBLE : PDouble(sqldata)^ := Value;
1962 SQL_LONG : PInteger(sqldata)^ := Trunc(Value);
1964 SQL_FLOAT : PSingle(sqldata)^ := Value;
1965 SQL_BOOLEAN : PSmallint(sqldata)^ := Trunc(Value);
1966 SQL_SHORT : PSmallint(sqldata)^ := Trunc(Value);
1967 SQL_INT64 : PInt64(sqldata)^ := Trunc(Value);
1968 SQL_TEXT : EncodeString(SQL_TEXT, Index, AnsiString(FloatToStr(Value)));
1969 SQL_VARYING : EncodeString(SQL_VARYING, Index, AnsiString(FloatToStr(Value)));
1971 raise EZIBConvertError.Create(SUnsupportedDataType);
1973 if (sqlind <> nil) then
1974 sqlind^ := 0; // not null
1982 Set up parameter Boolean value
1983 @param Index the target parameter index
1984 @param Value the source value
1986 procedure TZParamsSQLDA.UpdateBoolean(const Index: Integer; Value: boolean);
1992 with FXSQLDA.sqlvar[Index] do
1994 if (sqlind <> nil) and (sqlind^ = -1) then
1996 SQLCode := (sqltype and not(1));
1998 if (sqlscale < 0) then
2001 SQL_SHORT : PSmallInt(sqldata)^ := ord(Value) * IBScaleDivisor[sqlscale];
2002 SQL_LONG : PInteger(sqldata)^ := ord(Value) * IBScaleDivisor[sqlscale];
2004 SQL_QUAD : PInt64(sqldata)^ := ord(Value) * IBScaleDivisor[sqlscale];
2005 SQL_DOUBLE : PDouble(sqldata)^ := ord(Value);
2007 raise EZIBConvertError.Create(SUnsupportedParameterType);
2012 SQL_DOUBLE : PDouble(sqldata)^ := ord(Value);
2013 SQL_LONG : PInteger(sqldata)^ := ord(Value);
2015 SQL_FLOAT : PSingle(sqldata)^ := ord(Value);
2016 SQL_BOOLEAN : PSmallint(sqldata)^ := ord(Value);
2017 SQL_SHORT : PSmallint(sqldata)^ := ord(Value);
2018 SQL_INT64 : PInt64(sqldata)^ := ord(Value);
2019 SQL_TEXT : EncodeString(SQL_TEXT, Index, AnsiString(IntToStr(ord(Value))));
2020 SQL_VARYING : EncodeString(SQL_VARYING, Index, AnsiString(IntToStr(ord(Value))));
2022 raise EZIBConvertError.Create(SUnsupportedParameterType);
2024 if (sqlind <> nil) then
2025 sqlind^ := 0; // not null
2033 Set up parameter Byte value
2034 @param Index the target parameter index
2035 @param Value the source value
2037 procedure TZParamsSQLDA.UpdateByte(const Index: Integer; Value: ShortInt);
2042 SetFieldType(Index, sizeof(Smallint), SQL_SHORT + 1, 0);
2044 with FXSQLDA.sqlvar[Index] do
2046 if (sqlind <> nil) and (sqlind^ = -1) then
2048 SQLCode := (sqltype and not(1));
2050 if (sqlscale < 0) then
2053 SQL_SHORT : PSmallInt(sqldata)^ := Value * IBScaleDivisor[sqlscale];
2054 SQL_LONG : PInteger(sqldata)^ := Value * IBScaleDivisor[sqlscale];
2056 SQL_QUAD : PInt64(sqldata)^ := Value * IBScaleDivisor[sqlscale];
2057 SQL_DOUBLE : PDouble(sqldata)^ := Value;
2059 raise EZIBConvertError.Create(SUnsupportedParameterType);
2064 SQL_DOUBLE : PDouble(sqldata)^ := Value;
2065 SQL_LONG : PInteger(sqldata)^ := Value;
2067 SQL_FLOAT : PSingle(sqldata)^ := Value;
2070 if FPlainDriver.GetProtocol <> 'interbase-7' then
2071 raise EZIBConvertError.Create(SUnsupportedDataType);
2072 PSmallint(sqldata)^ := Value;
2074 SQL_SHORT : PSmallint(sqldata)^ := Value;
2075 SQL_INT64 : PInt64(sqldata)^ := Value;
2076 SQL_TEXT : EncodeString(SQL_TEXT, Index, AnsiString(IntToStr(Value)));
2077 SQL_VARYING : EncodeString(SQL_VARYING, Index, AnsiString(IntToStr(Value)));
2079 raise EZIBConvertError.Create(SUnsupportedParameterType);
2081 if (sqlind <> nil) then
2082 sqlind^ := 0; // not null
2090 Set up parameter byte value
2091 @param Index the target parameter index
2092 @param Value the source value
2094 procedure TZParamsSQLDA.UpdateBytes(const Index: Integer; Value: TByteDynArray);
2101 // SetFieldType(Index, Length(Value) + 1, SQL_TEXT + 1, 0);
2103 with FXSQLDA.sqlvar[Index] do
2105 if (sqlind <> nil) and (sqlind^ = -1) then
2107 SQLCode := (sqltype and not(1));
2109 SQL_TEXT : EncodeBytes(SQL_TEXT, Index, Value);
2110 SQL_VARYING : EncodeBytes(SQL_VARYING, Index, Value);
2111 SQL_LONG : PInteger (sqldata)^ := Round(ZStrToFloat(BytesToStr(Value)) * IBScaleDivisor[sqlscale]); //AVZ
2112 SQL_SHORT : PInteger (sqldata)^ := StrToInt(String(BytesToStr(Value)));
2113 SQL_TYPE_DATE : EncodeString(SQL_DATE, Index, BytesToStr(Value));
2114 SQL_DOUBLE : PDouble (sqldata)^ := ZStrToFloat(BytesToStr(Value)) * IBScaleDivisor[sqlscale]; //AVZ
2116 SQL_FLOAT : PSingle (sqldata)^ := ZStrToFloat(BytesToStr(Value)) * IBScaleDivisor[sqlscale]; //AVZ
2117 SQL_INT64 : PInt64(sqldata)^ := Trunc(ZStrToFloat(BytesToStr(Value)) * IBScaleDivisor[sqlscale]); //AVZ - INT64 value was not recognized
2120 Stream := TMemoryStream.Create;
2122 Len := Length(Value);
2124 System.Move(Pointer(Value)^, TMemoryStream(Stream).Memory^, Len);
2125 WriteBlob(index, Stream);
2131 raise EZIBConvertError.Create(SErrorConvertion);
2133 if (sqlind <> nil) then
2134 sqlind^ := 0; // not null
2142 Set up parameter Date value
2143 @param Index the target parameter index
2144 @param Value the source value
2146 procedure TZParamsSQLDA.UpdateDate(const Index: Integer; Value: TDateTime);
2148 SetFieldType(Index, sizeof(Integer), SQL_TYPE_DATE + 1, 0);
2149 UpdateDateTime(Index, Value);
2153 Set up parameter DateTime value
2154 @param Index the target parameter index
2155 @param Value the source value
2157 procedure TZParamsSQLDA.UpdateDateTime(const Index: Integer;
2161 hr, min, sec, msec: word;
2163 TmpDate: TCTimeStructure;
2167 with FXSQLDA.sqlvar[Index] do
2169 DecodeDate(Value, y, m, d);
2170 DecodeTime(Value, hr, min, sec, msec);
2171 TmpDate.tm_year := y - 1900;
2172 TmpDate.tm_mon := m - 1;
2173 TmpDate.tm_mday := d;
2174 TmpDate.tm_hour := hr;
2175 TmpDate.tm_min := min;
2176 TmpDate.tm_sec := sec;
2177 TmpDate.tm_wday := 0;
2178 TmpDate.tm_yday := 0;
2179 TmpDate.tm_isdst := 0;
2181 if (sqlind <> nil) and (sqlind^ = -1) then
2183 SQLCode := (sqltype and not(1));
2186 SQL_TYPE_DATE : FPlainDriver.isc_encode_sql_date(@TmpDate, PISC_DATE(sqldata));
2187 SQL_TYPE_TIME : begin
2188 FPlainDriver.isc_encode_sql_time(@TmpDate, PISC_TIME(sqldata));
2189 PISC_TIME(sqldata)^ := PISC_TIME(sqldata)^ + msec*10;
2191 SQL_TIMESTAMP : begin
2192 FPlainDriver.isc_encode_timestamp(@TmpDate,PISC_TIMESTAMP(sqldata));
2193 PISC_TIMESTAMP(sqldata).timestamp_time :=PISC_TIMESTAMP(sqldata).timestamp_time + msec*10;
2196 raise EZIBConvertError.Create(SInvalidState);
2198 if (sqlind <> nil) then
2199 sqlind^ := 0; // not null
2207 Set up parameter Double value
2208 @param Index the target parameter index
2209 @param Value the source value
2211 procedure TZParamsSQLDA.UpdateDouble(const Index: Integer; Value: Double);
2216 SetFieldType(Index, sizeof(double), SQL_DOUBLE + 1, 0);
2218 with FXSQLDA.sqlvar[Index] do
2220 if (sqlind <> nil) and (sqlind^ = -1) then
2222 SQLCode := (sqltype and not(1));
2224 if (sqlscale < 0) then
2227 SQL_SHORT : PSmallInt(sqldata)^ := Trunc(Value * IBScaleDivisor[sqlscale]);
2228 SQL_LONG : PInteger(sqldata)^ := Trunc(Value * IBScaleDivisor[sqlscale]);
2230 SQL_QUAD : PInt64(sqldata)^ := Trunc(Value * IBScaleDivisor[sqlscale]);
2231 SQL_DOUBLE : PDouble(sqldata)^ := Value;
2233 raise EZIBConvertError.Create(SUnsupportedDataType);
2238 SQL_DOUBLE : PDouble(sqldata)^ := Value;
2239 SQL_LONG : PInteger(sqldata)^ := Trunc(Value);
2241 SQL_FLOAT : PSingle(sqldata)^ := Value;
2242 SQL_BOOLEAN : PSmallint(sqldata)^ := Trunc(Value);
2243 SQL_SHORT : PSmallint(sqldata)^ := Trunc(Value);
2244 SQL_INT64 : PInt64(sqldata)^ := Trunc(Value);
2245 SQL_TEXT : EncodeString(SQL_TEXT, Index, AnsiString(FloatToStr(Value)));
2246 SQL_VARYING : EncodeString(SQL_VARYING, Index, AnsiString(FloatToStr(Value)));
2248 raise EZIBConvertError.Create(SUnsupportedDataType);
2250 if (sqlind <> nil) then
2251 sqlind^ := 0; // not null
2259 Set up parameter Float value
2260 @param Index the target parameter index
2261 @param Value the source value
2263 procedure TZParamsSQLDA.UpdateFloat(const Index: Integer; Value: Single);
2268 SetFieldType(Index, sizeof(Single), SQL_FLOAT + 1, 1);
2270 with FXSQLDA.sqlvar[Index] do
2272 if (sqlind <> nil) and (sqlind^ = -1) then
2274 SQLCode := (sqltype and not(1));
2276 if (sqlscale < 0) then
2279 SQL_SHORT : PSmallInt(sqldata)^ := Trunc(Value * IBScaleDivisor[sqlscale]);
2280 SQL_LONG : PInteger(sqldata)^ := Trunc(Value * IBScaleDivisor[sqlscale]);
2282 SQL_QUAD : PInt64(sqldata)^ := Trunc(Value * IBScaleDivisor[sqlscale]);
2283 SQL_DOUBLE : PDouble(sqldata)^ := Value;
2285 SQL_FLOAT : PSingle(sqldata)^ := Value;
2287 raise EZIBConvertError.Create(SUnsupportedDataType);
2292 SQL_DOUBLE : PDouble(sqldata)^ := Value;
2293 SQL_LONG : PInteger(sqldata)^ := Trunc(Value);
2295 SQL_FLOAT : PSingle(sqldata)^ := Value;
2296 SQL_BOOLEAN : PSmallint(sqldata)^ := Trunc(Value);
2297 SQL_SHORT : PSmallint(sqldata)^ := Trunc(Value);
2298 SQL_INT64 : PInt64(sqldata)^ := Trunc(Value);
2299 SQL_TEXT : EncodeString(SQL_TEXT, Index, AnsiString(FloatToStr(Value)));
2300 SQL_VARYING : EncodeString(SQL_VARYING, Index, AnsiString(FloatToStr(Value)));
2302 raise EZIBConvertError.Create(SUnsupportedDataType);
2304 if (sqlind <> nil) then
2305 sqlind^ := 0; // not null
2313 Set up parameter integer value
2314 @param Index the target parameter index
2315 @param Value the source value
2317 procedure TZParamsSQLDA.UpdateInt(const Index: Integer; Value: Integer);
2322 SetFieldType(Index, sizeof(Integer), SQL_LONG + 1, 0);
2324 with FXSQLDA.sqlvar[Index] do
2326 if (sqlind <> nil) and (sqlind^ = -1) then
2328 SQLCode := (sqltype and not(1));
2330 if (sqlscale < 0) then
2333 SQL_SHORT : PSmallInt(sqldata)^ := Value * IBScaleDivisor[sqlscale];
2334 SQL_LONG : PInteger(sqldata)^ := Value * IBScaleDivisor[sqlscale];
2336 SQL_QUAD : PInt64(sqldata)^ := Value * IBScaleDivisor[sqlscale];
2337 SQL_DOUBLE : PDouble(sqldata)^ := Value;
2339 raise EZIBConvertError.Create(SUnsupportedDataType);
2344 SQL_DOUBLE : PDouble(sqldata)^ := Value;
2345 SQL_LONG : PInteger(sqldata)^ := Value;
2347 SQL_FLOAT : PSingle(sqldata)^ := Value;
2348 SQL_BOOLEAN : PSmallint(sqldata)^ := Value;
2349 SQL_SHORT : PSmallint(sqldata)^ := Value;
2350 SQL_INT64 : PInt64(sqldata)^ := Value;
2351 SQL_TEXT : EncodeString(SQL_TEXT, Index, AnsiString(IntToStr(Value)));
2352 SQL_VARYING : EncodeString(SQL_VARYING, Index, AnsiString(IntToStr(Value)));
2354 raise EZIBConvertError.Create(SUnsupportedDataType);
2356 if (sqlind <> nil) then
2357 sqlind^ := 0; // not null
2365 Set up parameter Long value
2366 @param Index the target parameter index
2367 @param Value the source value
2369 procedure TZParamsSQLDA.UpdateLong(const Index: integer; Value: Int64);
2374 SetFieldType(Index, sizeof(Int64), SQL_INT64 + 1, 0);
2376 with FXSQLDA.sqlvar[Index] do
2378 if (sqlind <> nil) and (sqlind^ = -1) then
2380 SQLCode := (sqltype and not(1));
2382 if (sqlscale < 0) then
2385 SQL_SHORT : PSmallInt(sqldata)^ := Value * IBScaleDivisor[sqlscale];
2386 SQL_LONG : PInteger(sqldata)^ := Value * IBScaleDivisor[sqlscale];
2388 SQL_QUAD : PInt64(sqldata)^ := Value * IBScaleDivisor[sqlscale];
2389 SQL_DOUBLE : PDouble(sqldata)^ := Value;
2391 raise EZIBConvertError.Create(SUnsupportedDataType);
2396 SQL_DOUBLE : PDouble(sqldata)^ := Value;
2397 SQL_LONG : PInteger(sqldata)^ := Value;
2399 SQL_FLOAT : PSingle(sqldata)^ := Value;
2400 SQL_BOOLEAN : PSmallint(sqldata)^ := Value;
2401 SQL_SHORT : PSmallint(sqldata)^ := Value;
2402 SQL_INT64 : PInt64(sqldata)^ := Value;
2403 SQL_TEXT : EncodeString(SQL_TEXT, Index, AnsiString(IntToStr(Value)));
2404 SQL_VARYING : EncodeString(SQL_VARYING, Index, AnsiString(IntToStr(Value)));
2406 raise EZIBConvertError.Create(SUnsupportedDataType);
2408 if (sqlind <> nil) then
2409 sqlind^ := 0; // not null
2417 Set up parameter null value
2418 @param Index the target parameter index
2419 @param Value the source value
2421 procedure TZParamsSQLDA.UpdateNull(const Index: Integer; Value: boolean);
2425 with FXSQLDA.sqlvar[Index] do
2426 if (sqlind <> nil) then
2428 True : sqlind^ := -1; //NULL
2429 False : sqlind^ := 0; //NOT NULL
2437 Set up parameter PAnsiChar value
2438 @param Index the target parameter index
2439 @param Value the source value
2441 procedure TZParamsSQLDA.UpdatePChar(const Index: Integer; Value: PAnsiChar);
2443 TempString: AnsiString;
2445 TempString := Value;
2446 UpdateString(Index, TempString);
2450 Set up parameter Interbase QUAD value
2451 @param Index the target parameter index
2452 @param Value the source value
2454 procedure TZParamsSQLDA.UpdateQuad(const Index: Word; const Value: TISC_QUAD);
2457 SetFieldType(Index, sizeof(TISC_QUAD), SQL_QUAD + 1, 0);
2459 with FXSQLDA.sqlvar[Index] do
2460 if not ((sqlind <> nil) and (sqlind^ = -1)) then
2462 case (sqltype and not(1)) of
2463 SQL_QUAD, SQL_DOUBLE, SQL_INT64, SQL_BLOB, SQL_ARRAY: PISC_QUAD(sqldata)^ := Value;
2465 raise EZIBConvertError.Create(SUnsupportedDataType);
2467 if (sqlind <> nil) then
2468 sqlind^ := 0; // not null
2471 raise EZIBConvertError.Create(SUnsupportedDataType);
2478 Set up parameter short value
2479 @param Index the target parameter index
2480 @param Value the source value
2482 procedure TZParamsSQLDA.UpdateShort(const Index: Integer; Value: SmallInt);
2487 SetFieldType(Index, sizeof(Smallint), SQL_SHORT + 1, 0);
2489 with FXSQLDA.sqlvar[Index] do
2491 if (sqlind <> nil) and (sqlind^ = -1) then
2493 SQLCode := (sqltype and not(1));
2495 if (sqlscale < 0) then
2498 SQL_SHORT : PSmallInt(sqldata)^ := Value * IBScaleDivisor[sqlscale];
2499 SQL_LONG : PInteger(sqldata)^ := Value * IBScaleDivisor[sqlscale];
2501 SQL_QUAD : PInt64(sqldata)^ := Value * IBScaleDivisor[sqlscale];
2502 SQL_DOUBLE : PDouble(sqldata)^ := Value;
2504 raise EZIBConvertError.Create(SUnsupportedDataType);
2509 SQL_DOUBLE : PDouble(sqldata)^ := Value;
2510 SQL_LONG : PInteger(sqldata)^ := Value;
2512 SQL_FLOAT : PSingle(sqldata)^ := Value;
2513 SQL_BOOLEAN : PSmallint(sqldata)^ := Value;
2514 SQL_SHORT : PSmallint(sqldata)^ := Value;
2515 SQL_INT64 : PInt64(sqldata)^ := Value;
2516 SQL_TEXT : EncodeString(SQL_TEXT, Index, AnsiString(IntToStr(Value)));
2517 SQL_VARYING : EncodeString(SQL_VARYING, Index, AnsiString(IntToStr(Value)));
2519 raise EZIBConvertError.Create(SUnsupportedDataType);
2521 if (sqlind <> nil) then
2522 sqlind^ := 0; // not null
2530 Set up parameter String value
2531 @param Index the target parameter index
2532 @param Value the source value
2535 procedure TZParamsSQLDA.UpdateString(const Index: Integer; Value: RawByteString);
2541 // SetFieldType(Index, Length(Value) + 1, SQL_TEXT + 1, 0);
2543 with FXSQLDA.sqlvar[Index] do
2545 if (sqlind <> nil) and (sqlind^ = -1) then
2547 SQLCode := (sqltype and not(1));
2549 SQL_TEXT : EncodeString(SQL_TEXT, Index, Value);
2550 SQL_VARYING : EncodeString(SQL_VARYING, Index, Value);
2551 SQL_LONG : PInteger (sqldata)^ := StrToInt(String(Value)); //AVZ
2552 SQL_SHORT : PSmallInt (sqldata)^ := StrToInt(String(Value));
2553 SQL_TYPE_DATE : EncodeString(SQL_DATE, Index, Value);
2554 SQL_DOUBLE : PDouble (sqldata)^ := ZStrToFloat(Value) * IBScaleDivisor[sqlscale]; //AVZ
2556 SQL_FLOAT : PSingle (sqldata)^ := ZStrToFloat(Value) * IBScaleDivisor[sqlscale]; //AVZ
2557 SQL_INT64 : PInt64(sqldata)^ := Trunc(ZStrToFloat(Value) * IBScaleDivisor[sqlscale]); //AVZ - INT64 value was not recognized
2560 Stream := TStringStream.Create(Value);
2562 WriteBlob(index, Stream);
2568 raise EZIBConvertError.Create(SErrorConvertion);
2570 if (sqlind <> nil) then
2571 sqlind^ := 0; // not null
2579 Set up parameter Time value
2580 @param Index the target parameter index
2581 @param Value the source value
2583 procedure TZParamsSQLDA.UpdateTime(const Index: Integer; Value: TDateTime);
2585 SetFieldType(Index, sizeof(Cardinal), SQL_TYPE_TIME + 1, 0);
2586 UpdateDateTime(Index, Value);
2590 Set up parameter Timestamp value
2591 @param Index the target parameter index
2592 @param Value the source value
2594 procedure TZParamsSQLDA.UpdateTimestamp(const Index: Integer; Value: TDateTime);
2596 SetFieldType(Index, sizeof(TISC_QUAD), SQL_TIMESTAMP + 1, 0);
2597 UpdateDateTime(Index, Value);
2601 Write stream to blob field
2602 @param Index an index field number
2603 @param Stream the souse data stream
2605 procedure TZParamsSQLDA.WriteBlob(const Index: Integer; Stream: TStream);
2609 BlobHandle: TISC_BLOB_HANDLE;
2610 StatusVector: TARRAY_ISC_STATUS;
2611 BlobSize, CurPos, SegLen: Integer;
2616 { create blob handle }
2617 FPlainDriver.isc_create_blob2(@StatusVector, FHandle, FTransactionHandle,
2618 @BlobHandle, @BlobId, 0, nil);
2619 CheckInterbase6Error(FPlainDriver, StatusVector);
2621 Stream.Position := 0;
2622 BlobSize := Stream.Size;
2623 Buffer := AllocMem(BlobSize);
2625 Stream.ReadBuffer(Buffer^, BlobSize);
2627 { put data to blob }
2629 SegLen := DefaultBlobSegmentSize;
2630 while (CurPos < BlobSize) do
2632 if (CurPos + SegLen > BlobSize) then
2633 SegLen := BlobSize - CurPos;
2634 if FPlainDriver.isc_put_segment(@StatusVector, @BlobHandle, SegLen,
2635 PAnsiChar(@Buffer[CurPos])) > 0 then
2636 CheckInterbase6Error(FPlainDriver, StatusVector);
2637 Inc(CurPos, SegLen);
2640 { close blob handle }
2641 FPlainDriver.isc_close_blob(@StatusVector, @BlobHandle);
2642 CheckInterbase6Error(FPlainDriver, StatusVector);
2645 UpdateQuad(Index, BlobId);
2654 Decode Interbase field value to pascal string
2655 @param Code the Interbase data type
2656 @param Index field index
2657 @result the field string
2659 function TZResultSQLDA.DecodeString(const Code: Smallint;
2660 const Index: Word): RawByteString;
2663 procedure SetAnsi(Ansi: PAnsiChar; Len: Longint);
2665 SetLength(Result, Len);
2666 System.Move(Ansi^, PAnsiChar(Result)^, Len);
2670 with FXSQLDA.sqlvar[Index] do
2674 SetAnsi(sqldata, sqllen);
2675 // Trim only spaces. TrimRight also removes other characters)
2677 while (l > 0) and (Result[l] = ' ') do
2680 result := copy(result, 1, l);
2682 SQL_VARYING : SetAnsi(PISC_VARYING(sqldata).str, PISC_VARYING(sqldata).strlen);
2690 Decode Interbase field value to pascal string
2691 @param Code the Interbase data type
2692 @param Index field index
2693 @param Str the field string
2695 procedure TZResultSQLDA.DecodeString2(const Code: Smallint; const Index: Word;
2696 out Str: RawByteString);
2698 Str := DecodeString(Code, Index);
2702 Return BigDecimal field value
2703 @param Index the field index
2704 @return the field BigDecimal value
2706 function TZResultSQLDA.GetBigDecimal(const Index: Integer): Extended;
2712 with FXSQLDA.sqlvar[Index] do
2715 if (sqlind <> nil) and (sqlind^ = -1) then
2717 SQLCode := (sqltype and not(1));
2719 if (sqlscale < 0) then
2722 SQL_SHORT : Result := PSmallInt(sqldata)^ / IBScaleDivisor[sqlscale];
2723 SQL_LONG : Result := PInteger(sqldata)^ / IBScaleDivisor[sqlscale];
2725 SQL_QUAD : Result := PInt64(sqldata)^ / IBScaleDivisor[sqlscale];
2726 SQL_DOUBLE : Result := PDouble(sqldata)^;
2728 raise EZIBConvertError.Create(Format(SErrorConvertionField,
2729 [GetFieldAliasName(Index), GetNameSqlType(SQLCode)]));
2734 SQL_DOUBLE : Result := PDouble(sqldata)^;
2735 SQL_LONG : Result := PInteger(sqldata)^;
2737 SQL_FLOAT : Result := PSingle(sqldata)^;
2738 SQL_BOOLEAN : Result := PSmallint(sqldata)^;
2739 SQL_SHORT : Result := PSmallint(sqldata)^;
2740 SQL_INT64 : Result := PInt64(sqldata)^;
2741 SQL_TEXT : Result := StrToFloat(String(DecodeString(SQL_TEXT, Index)));
2742 SQL_VARYING : Result := StrToFloat(String(DecodeString(SQL_VARYING, Index)));
2744 raise EZIBConvertError.Create(Format(SErrorConvertionField,
2745 [GetFieldAliasName(Index), GetNameSqlType(SQLCode)]));
2754 Return Boolean field value
2755 @param Index the field index
2756 @return the field boolean value
2758 function TZResultSQLDA.GetBoolean(const Index: Integer): Boolean;
2764 with FXSQLDA.sqlvar[Index] do
2767 if (sqlind <> nil) and (sqlind^ = -1) then
2769 SQLCode := (sqltype and not(1));
2771 if (sqlscale < 0) then
2774 SQL_SHORT : Result := PSmallInt(sqldata)^ div IBScaleDivisor[sqlscale] <> 0;
2775 SQL_LONG : Result := PInteger(sqldata)^ div IBScaleDivisor[sqlscale] <> 0;
2777 SQL_QUAD : Result := PInt64(sqldata)^ div IBScaleDivisor[sqlscale] <> 0;
2778 SQL_DOUBLE : Result := Trunc(PDouble(sqldata)^) > 0;
2780 raise EZIBConvertError.Create(Format(SErrorConvertionField,
2781 [GetFieldAliasName(Index), GetNameSqlType(SQLCode)]));
2786 SQL_DOUBLE : Result := Trunc(PDouble(sqldata)^) <> 0;
2787 SQL_LONG : Result := PInteger(sqldata)^ <> 0;
2789 SQL_FLOAT : Result := Trunc(PSingle(sqldata)^) <> 0;
2790 SQL_BOOLEAN : Result := PSmallint(sqldata)^ <> 0;
2791 SQL_SHORT : Result := PSmallint(sqldata)^ <> 0;
2792 SQL_INT64 : Result := PInt64(sqldata)^ <> 0;
2793 SQL_TEXT : Result := StrToInt(String(DecodeString(SQL_TEXT, Index))) <> 0;
2794 SQL_VARYING : Result := StrToInt(String(DecodeString(SQL_VARYING, Index))) <> 0;
2796 raise EZIBConvertError.Create(Format(SErrorConvertionField,
2797 [GetFieldAliasName(Index), GetNameSqlType(SQLCode)]));
2806 Return Byte field value
2807 @param Index the field index
2808 @return the field Byte value
2810 function TZResultSQLDA.GetByte(const Index: Integer): Byte;
2812 Result := Byte(GetShort(Index));
2816 Return Bytes field value
2817 @param Index the field index
2818 @return the field Bytes value
2820 function TZResultSQLDA.GetBytes(const Index: Integer): TByteDynArray;
2827 with FXSQLDA.sqlvar[Index] do
2829 if (sqlind <> nil) and (sqlind^ = -1) then
2831 SQLCode := (sqltype and not(1));
2834 SQL_TEXT, SQL_VARYING:
2836 SetLength(Result, sqllen);
2837 System.Move(PAnsiChar(sqldata)^, Pointer(Result)^, sqllen);
2840 raise EZIBConvertError.Create(Format(SErrorConvertionField,
2841 [GetFieldAliasName(Index), GetNameSqlType(SQLCode)]));
2850 Return Date field value
2851 @param Index the field index
2852 @return the field Date value
2854 function TZResultSQLDA.GetDate(const Index: Integer): TDateTime;
2856 Result := Trunc(GetTimestamp(Index));
2860 Return Double field value
2861 @param Index the field index
2862 @return the field Double value
2864 function TZResultSQLDA.GetDouble(const Index: Integer): Double;
2870 with FXSQLDA.sqlvar[Index] do
2873 if (sqlind <> nil) and (sqlind^ = -1) then
2875 SQLCode := (sqltype and not(1));
2877 if (sqlscale < 0) then
2880 SQL_SHORT : Result := PSmallInt(sqldata)^ / IBScaleDivisor[sqlscale];
2881 SQL_LONG : Result := PInteger(sqldata)^ / IBScaleDivisor[sqlscale];
2883 SQL_QUAD : Result := PInt64(sqldata)^ / IBScaleDivisor[sqlscale];
2884 SQL_DOUBLE : Result := PDouble(sqldata)^;
2886 raise EZIBConvertError.Create(Format(SErrorConvertionField,
2887 [GetFieldAliasName(Index), GetNameSqlType(SQLCode)]));
2892 SQL_DOUBLE : Result := PDouble(sqldata)^;
2893 SQL_LONG : Result := PInteger(sqldata)^;
2895 SQL_FLOAT : Result := PSingle(sqldata)^;
2896 SQL_BOOLEAN : Result := PSmallint(sqldata)^;
2897 SQL_SHORT : Result := PSmallint(sqldata)^;
2898 SQL_INT64 : Result := PInt64(sqldata)^;
2899 SQL_TEXT : Result := StrToFloat(String(DecodeString(SQL_TEXT, Index)));
2900 SQL_VARYING : Result := StrToFloat(String(DecodeString(SQL_VARYING, Index)));
2902 raise EZIBConvertError.Create(Format(SErrorConvertionField,
2903 [GetFieldAliasName(Index), GetNameSqlType(SQLCode)]));
2912 Return Float field value
2913 @param Index the field index
2914 @return the field Float value
2916 function TZResultSQLDA.GetFloat(const Index: Integer): Single;
2922 with FXSQLDA.sqlvar[Index] do
2925 if (sqlind <> nil) and (sqlind^ = -1) then
2927 SQLCode := (sqltype and not(1));
2929 if (sqlscale < 0) then
2932 SQL_SHORT : Result := PSmallInt(sqldata)^ / IBScaleDivisor[sqlscale];
2933 SQL_LONG : Result := PInteger(sqldata)^ / IBScaleDivisor[sqlscale];
2935 SQL_QUAD : Result := PInt64(sqldata)^ / IBScaleDivisor[sqlscale];
2936 SQL_DOUBLE : Result := PDouble(sqldata)^;
2938 raise EZIBConvertError.Create(Format(SErrorConvertionField,
2939 [GetFieldAliasName(Index), GetNameSqlType(SQLCode)]));
2944 SQL_DOUBLE : Result := PDouble(sqldata)^;
2945 SQL_LONG : Result := PInteger(sqldata)^;
2947 SQL_FLOAT : Result := PSingle(sqldata)^;
2948 SQL_BOOLEAN : Result := PSmallint(sqldata)^;
2949 SQL_SHORT : Result := PSmallint(sqldata)^;
2950 SQL_INT64 : Result := PInt64(sqldata)^;
2951 SQL_TEXT : Result := StrToFloat(String(DecodeString(SQL_TEXT, Index)));
2952 SQL_VARYING : Result := StrToFloat(String(DecodeString(SQL_VARYING, Index)));
2954 raise EZIBConvertError.Create(Format(SErrorConvertionField,
2955 [GetFieldAliasName(Index), GetNameSqlType(SQLCode)]));
2964 Return Integer field value
2965 @param Index the field index
2966 @return the field Integer value
2968 function TZResultSQLDA.GetInt(const Index: Integer): Integer;
2970 Result := Integer(GetLong(Index));
2974 Return Long field value
2975 @param Index the field index
2976 @return the field Long value
2978 function TZResultSQLDA.GetLong(const Index: Integer): Int64;
2984 with FXSQLDA.sqlvar[Index] do
2987 if (sqlind <> nil) and (sqlind^ = -1) then
2989 SQLCode := (sqltype and not(1));
2991 if (sqlscale < 0) then
2994 SQL_SHORT : Result := PSmallInt(sqldata)^ div IBScaleDivisor[sqlscale];
2995 SQL_LONG : Result := PInteger(sqldata)^ div IBScaleDivisor[sqlscale];
2997 SQL_QUAD : Result := PInt64(sqldata)^ div IBScaleDivisor[sqlscale];
2998 SQL_DOUBLE : Result := Trunc(PDouble(sqldata)^);
3000 raise EZIBConvertError.Create(Format(SErrorConvertionField,
3001 [GetFieldAliasName(Index), GetNameSqlType(SQLCode)]));
3006 SQL_DOUBLE : Result := Trunc(PDouble(sqldata)^);
3007 SQL_LONG : Result := PInteger(sqldata)^;
3009 SQL_FLOAT : Result := Trunc(PSingle(sqldata)^);
3010 SQL_BOOLEAN : Result := PSmallint(sqldata)^;
3011 SQL_SHORT : Result := PSmallint(sqldata)^;
3012 SQL_INT64 : Result := PInt64(sqldata)^;
3013 SQL_TEXT : Result := StrToInt(String(DecodeString(SQL_TEXT, Index)));
3014 SQL_VARYING : Result := StrToInt(String(DecodeString(SQL_VARYING, Index)));
3016 raise EZIBConvertError.Create(Format(SErrorConvertionField,
3017 [GetFieldAliasName(Index), GetNameSqlType(SQLCode)]));
3026 Return PAnsiChar field value
3027 @param Index the field index
3028 @return the field PAnsiChar value
3030 function TZResultSQLDA.GetPChar(const Index: Integer): PChar;
3034 TempStr := ZDbcString(GetString(Index));
3035 Result := PChar(TempStr);
3039 Return Short field value
3040 @param Index the field index
3041 @return the field Short value
3043 function TZResultSQLDA.GetShort(const Index: Integer): SmallInt;
3049 with FXSQLDA.sqlvar[Index] do
3052 if (sqlind <> nil) and (sqlind^ = -1) then
3054 SQLCode := (sqltype and not(1));
3056 if (sqlscale < 0) then
3059 SQL_SHORT : Result := PSmallInt(sqldata)^ div IBScaleDivisor[sqlscale];
3060 SQL_LONG : Result := PInteger(sqldata)^ div IBScaleDivisor[sqlscale];
3062 SQL_QUAD : Result := PInt64(sqldata)^ div IBScaleDivisor[sqlscale];
3063 SQL_DOUBLE : Result := Trunc(PDouble(sqldata)^);
3065 raise EZIBConvertError.Create(Format(SErrorConvertionField,
3066 [GetFieldAliasName(Index), GetNameSqlType(SQLCode)]));
3071 SQL_DOUBLE : Result := Trunc(PDouble(sqldata)^);
3072 SQL_LONG : Result := PInteger(sqldata)^;
3074 SQL_FLOAT : Result := Trunc(PSingle(sqldata)^);
3075 SQL_BOOLEAN : Result := PSmallint(sqldata)^;
3076 SQL_SHORT : Result := PSmallint(sqldata)^;
3077 SQL_INT64 : Result := PInt64(sqldata)^;
3078 SQL_TEXT : Result := StrToInt(String(DecodeString(SQL_TEXT, Index)));
3079 SQL_VARYING : Result := StrToInt(String(DecodeString(SQL_VARYING, Index)));
3081 raise EZIBConvertError.Create(Format(SErrorConvertionField,
3082 [GetFieldAliasName(Index), GetNameSqlType(SQLCode)]));
3091 Return String field value
3092 @param Index the field index
3093 @return the field String value
3095 function TZResultSQLDA.GetString(const Index: Integer): RawByteString;
3098 TempAnsi: AnsiString;
3103 with FXSQLDA.sqlvar[Index] do
3105 if (sqlind <> nil) and (sqlind^ = -1) then
3107 SQLCode := (sqltype and not(1));
3109 if (sqlscale < 0) then
3112 SQL_SHORT : Result := RawByteString(FloatToStr(PSmallInt(sqldata)^ / IBScaleDivisor[sqlscale]));
3113 SQL_LONG : Result := RawByteString(FloatToStr(PInteger(sqldata)^ / IBScaleDivisor[sqlscale]));
3115 SQL_QUAD : Result := RawByteString(FloatToStr(PInt64(sqldata)^ / IBScaleDivisor[sqlscale]));
3116 SQL_DOUBLE : Result := RawByteString(FloatToStr(PDouble(sqldata)^));
3118 raise EZIBConvertError.Create(Format(SErrorConvertionField,
3119 [GetFieldAliasName(Index), GetNameSqlType(SQLCode)]));
3124 SQL_DOUBLE : Result := RawByteString(FloatToStr(PDouble(sqldata)^));
3125 SQL_LONG : Result := RawByteString(IntToStr(PInteger(sqldata)^));
3127 SQL_FLOAT : Result := RawByteString(FloatToStr(PSingle(sqldata)^));
3129 if Boolean(PSmallint(sqldata)^) = True then
3133 SQL_SHORT : Result := RawByteString(IntToStr(PSmallint(sqldata)^));
3134 SQL_INT64 : Result := RawByteString(IntToStr(PInt64(sqldata)^));
3135 SQL_TEXT : DecodeString2(SQL_TEXT, Index, Result);
3136 SQL_VARYING : DecodeString2(SQL_VARYING, Index, Result);
3137 SQL_BLOB : if VarIsEmpty(FDefaults[Index]) then
3139 ReadBlobFromString(Index, TempAnsi);
3140 FDefaults[Index] := TempAnsi;
3143 Result := {$IFDEF WITH_FPC_STRING_CONVERSATION}AnsiString{$ELSE}RawByteString{$ENDIF}(FDefaults[Index]);
3146 raise EZIBConvertError.Create(Format(SErrorConvertionField,
3147 [GetFieldAliasName(Index), GetNameSqlType(SQLCode)]));
3156 Return Time field value
3157 @param Index the field index
3158 @return the field Time value
3160 function TZResultSQLDA.GetTime(const Index: Integer): TDateTime;
3162 Result := Frac(GetTimestamp(Index));
3166 Return Timestamp field value
3167 @param Index the field index
3168 @return the field Timestamp value
3170 function TZResultSQLDA.GetTimestamp(const Index: Integer): TDateTime;
3172 TempDate: TCTimeStructure;
3176 with FXSQLDA.sqlvar[Index] do
3179 if (sqlind <> nil) and (sqlind^ = -1) then
3182 case (sqltype and not(1)) of
3183 SQL_TIMESTAMP : begin
3184 FPlainDriver.isc_decode_timestamp(PISC_TIMESTAMP(sqldata), @TempDate);
3185 Result := SysUtils.EncodeDate(TempDate.tm_year + 1900,
3186 TempDate.tm_mon + 1, TempDate.tm_mday) + EncodeTime(TempDate.tm_hour,
3187 TempDate.tm_min, TempDate.tm_sec, Word((PISC_TIMESTAMP(sqldata).timestamp_time mod 10000) div 10));
3189 SQL_TYPE_DATE : begin
3190 FPlainDriver.isc_decode_sql_date(PISC_DATE(sqldata), @TempDate);
3191 Result := SysUtils.EncodeDate(Word(TempDate.tm_year + 1900),
3192 Word(TempDate.tm_mon + 1), Word(TempDate.tm_mday));
3194 SQL_TYPE_TIME : begin
3195 FPlainDriver.isc_decode_sql_time(PISC_TIME(sqldata), @TempDate);
3196 Result := SysUtils.EncodeTime(Word(TempDate.tm_hour), Word(TempDate.tm_min),
3197 Word(TempDate.tm_sec), Word((PISC_TIME(sqldata)^ mod 10000) div 10));
3200 Result := Trunc(GetDouble(Index));
3210 @param Index the field index
3211 @return true if fied value NULL overwise false
3213 function TZResultSQLDA.IsNull(const Index: Integer): Boolean;
3217 with FXSQLDA.sqlvar[Index] do
3218 Result := (sqlind <> nil) and (sqlind^ = ISC_NULL);
3225 Return Interbase QUAD field value
3226 @param Index the field index
3227 @return the field Interbase QUAD value
3229 function TZResultSQLDA.GetQuad(const Index: Integer): TISC_QUAD;
3233 with FXSQLDA.sqlvar[Index] do
3234 if not ((sqlind <> nil) and (sqlind^ = -1)) then
3235 case (sqltype and not(1)) of
3236 SQL_QUAD, SQL_DOUBLE, SQL_INT64, SQL_BLOB, SQL_ARRAY: result := PISC_QUAD(sqldata)^;
3238 raise EZIBConvertError.Create(SUnsupportedDataType + ' ' + inttostr((sqltype and not(1))));
3241 raise EZIBConvertError.Create('Invalid State.');
3248 Return Variant field value
3249 @param Index the field index
3250 @return the field Variant value
3252 function TZResultSQLDA.GetValue(const Index: Word): Variant;
3257 with FXSQLDA.sqlvar[Index] do
3260 if (sqlind <> nil) and (sqlind^ = -1) then
3262 SQLCode := (sqltype and not(1));
3264 if (sqlscale < 0) then
3267 SQL_SHORT : Result := PSmallInt(sqldata)^ / IBScaleDivisor[sqlscale];
3268 SQL_LONG : Result := PInteger(sqldata)^ / IBScaleDivisor[sqlscale];
3270 SQL_QUAD : Result := PInt64(sqldata)^ / IBScaleDivisor[sqlscale];
3271 SQL_DOUBLE : Result := PDouble(sqldata)^;
3273 raise EZIBConvertError.Create(Format(SErrorConvertionField,
3274 [GetFieldAliasName(Index), GetNameSqlType(SQLCode)]));
3279 SQL_DOUBLE : Result := PDouble(sqldata)^;
3280 SQL_TIMESTAMP : Result := GetTimestamp(Index);
3281 SQL_TYPE_DATE : Result := GetDate(Index);
3282 SQL_TYPE_TIME : Result := GetTime(Index);
3283 SQL_LONG : Result := PInteger(sqldata)^;
3285 SQL_FLOAT : Result := PSingle(sqldata)^;
3288 if FPlainDriver.GetProtocol <> 'interbase-7' then
3289 raise EZIBConvertError.Create(SUnsupportedDataType);
3290 Result := IntToStr(PSmallint(sqldata)^);
3292 SQL_SHORT : Result := PSmallint(sqldata)^;
3293 SQL_INT64 : Result := PInt64(sqldata)^;
3294 SQL_TEXT : Result := DecodeString(SQL_TEXT, Index);
3295 SQL_VARYING : Result := DecodeString(SQL_VARYING, Index);
3296 SQL_BLOB : if VarIsEmpty(FDefaults[Index]) then
3298 ReadBlobFromVariant(Index, FDefaults[Index]);
3299 Result := FDefaults[Index];
3302 Result := Double(FDefaults[Index]);
3304 raise EZIBConvertError.Create(Format(SErrorConvertionField,
3305 [GetFieldAliasName(Index), GetNameSqlType(SQLCode)]));
3310 destructor TZResultSQLDA.Destroy;
3312 FreeParamtersValues;
3318 Read blob data to string
3319 @param Index an filed index
3320 @param Str destination string
3322 procedure TZResultSQLDA.ReadBlobFromString(const Index: Word; var Str: AnsiString);
3327 ReadBlobBufer(FPlainDriver, FHandle, FTransactionHandle, GetQuad(Index),
3330 SetLength(Str, Size);
3331 SetString(Str, PAnsiChar(Buffer), Size);
3333 FreeMem(Buffer, Size);
3338 Read blob data to stream
3339 @param Index an filed index
3340 @param Stream destination stream object
3342 procedure TZResultSQLDA.ReadBlobFromStream(const Index: Word; Stream: TStream);
3347 ReadBlobBufer(FPlainDriver, FHandle, FTransactionHandle, GetQuad(Index),
3351 Stream.Write(Buffer^, Size);
3354 FreeMem(Buffer, Size);
3359 Read blob data to variant value
3360 @param Index an filed index
3361 @param Value destination variant value
3363 procedure TZResultSQLDA.ReadBlobFromVariant(const Index: Word;
3364 var Value: Variant);
3370 ReadBlobBufer(FPlainDriver, FHandle, FTransactionHandle, GetQuad(Index),
3372 Value := VarArrayCreate([0, Size-1], varByte);
3373 PData := VarArrayLock(Value);
3375 move(Buffer^, PData^, Size);
3377 VarArrayUnlock(Value);
3378 FreeMem(Buffer, Size);
3382 procedure TZResultSQLDA.AllocateSQLDA;
3384 inherited AllocateSQLDA;
3385 SetLength(FDefaults, GetFieldCount);