zeoslib  UNKNOWN
 All Files
ZDbcStatement.pas
Go to the documentation of this file.
1 {*********************************************************}
2 { }
3 { Zeos Database Objects }
4 { Abstract Database Connectivity Classes }
5 { }
6 { Originally written by Sergey Seroukhov }
7 { }
8 {*********************************************************}
9 
10 {@********************************************************}
11 { Copyright (c) 1999-2012 Zeos Development Group }
12 { }
13 { License Agreement: }
14 { }
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. }
20 { }
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. }
39 { }
40 { }
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) }
45 { }
46 { http://www.sourceforge.net/projects/zeoslib. }
47 { }
48 { }
49 { Zeos Development Group. }
50 {********************************************************@}
51 
52 unit ZDbcStatement;
53 
54 interface
55 
56 {$I ZDbc.inc}
57 
58 uses
59  Types, Classes, {$IFDEF MSEgui}mclasses,{$ENDIF} SysUtils,
60  ZDbcIntfs, ZTokenizer, ZCompatibility, ZVariant, ZDbcLogging, ZClasses,
61  ZPlainDriver;
62 
63 type
64  TZSQLTypeArray = array of TZSQLType;
65 
66  {** Implements Abstract Generic SQL Statement. }
67 
68  { TZAbstractStatement }
69 
70  TZAbstractStatement = class(TZCodePagedObject, IZStatement)
71  private
72  FMaxFieldSize: Integer;
73  FMaxRows: Integer;
74  FEscapeProcessing: Boolean;
75  FQueryTimeout: Integer;
76  FLastUpdateCount: Integer;
77  FLastResultSet: IZResultSet;
78  FFetchDirection: TZFetchDirection;
79  FFetchSize: Integer;
80  FResultSetConcurrency: TZResultSetConcurrency;
81  FResultSetType: TZResultSetType;
82  FPostUpdates: TZPostUpdatesMode;
83  FLocateUpdates: TZLocateUpdatesMode;
84  FCursorName: AnsiString;
85  FBatchQueries: TStrings;
86  FConnection: IZConnection;
87  FInfo: TStrings;
88  FChunkSize: Integer; //size of buffer chunks for large lob's related to network settings
89  FClosed: Boolean;
90  FWSQL: ZWideString;
91  FaSQL: RawByteString;
92  FIsAnsiDriver: Boolean;
93  procedure SetLastResultSet(ResultSet: IZResultSet); virtual;
94  protected
95  procedure SetASQL(const Value: RawByteString); virtual;
96  procedure SetWSQL(const Value: ZWideString); virtual;
97  class function GetNextStatementId : integer;
98  procedure RaiseUnsupportedException;
99 
100  property MaxFieldSize: Integer read FMaxFieldSize write FMaxFieldSize;
101  property MaxRows: Integer read FMaxRows write FMaxRows;
102  property EscapeProcessing: Boolean
103  read FEscapeProcessing write FEscapeProcessing;
104  property QueryTimeout: Integer read FQueryTimeout write FQueryTimeout;
105  property LastUpdateCount: Integer
106  read FLastUpdateCount write FLastUpdateCount;
107  property LastResultSet: IZResultSet
108  read FLastResultSet write SetLastResultSet;
109  property FetchDirection: TZFetchDirection
110  read FFetchDirection write FFetchDirection;
111  property FetchSize: Integer read FFetchSize write FFetchSize;
112  property ResultSetConcurrency: TZResultSetConcurrency
113  read FResultSetConcurrency write FResultSetConcurrency;
114  property ResultSetType: TZResultSetType
115  read FResultSetType write FResultSetType;
116  property CursorName: AnsiString read FCursorName write FCursorName;
117  property BatchQueries: TStrings read FBatchQueries;
118  property Connection: IZConnection read FConnection;
119  property Info: TStrings read FInfo;
120  property Closed: Boolean read FClosed write FClosed;
121 
122  {EgonHugeist SSQL only because of compatibility to the old code available}
123  property SSQL: {$IF defined(FPC) and defined(WITH_RAWBYTESTRING)}RawByteString{$ELSE}String{$IFEND} read {$IFDEF UNICODE}FWSQL{$ELSE}FaSQL{$ENDIF} write {$IFDEF UNICODE}SetWSQL{$ELSE}SetASQL{$ENDIF};
124  property WSQL: ZWideString read FWSQL write SetWSQL;
125  property ASQL: RawByteString read FaSQL write SetASQL;
126  property LogSQL: String read {$IFDEF UNICODE}FWSQL{$ELSE}FaSQL{$ENDIF};
127  property ChunkSize: Integer read FChunkSize;
128  property IsAnsiDriver: Boolean read FIsAnsiDriver;
129  public
130  constructor Create(Connection: IZConnection; Info: TStrings);
131  destructor Destroy; override;
132 
133  function ExecuteQuery(const SQL: ZWideString): IZResultSet; overload; virtual;
134  function ExecuteUpdate(const SQL: ZWideString): Integer; overload; virtual;
135  function Execute(const SQL: ZWideString): Boolean; overload; virtual;
136 
137  function ExecuteQuery(const SQL: RawByteString): IZResultSet; overload; virtual;
138  function ExecuteUpdate(const SQL: RawByteString): Integer; overload; virtual;
139  function Execute(const SQL: RawByteString): Boolean; overload; virtual;
140 
141  procedure Close; virtual;
142 
143  function GetMaxFieldSize: Integer; virtual;
144  procedure SetMaxFieldSize(Value: Integer); virtual;
145  function GetMaxRows: Integer; virtual;
146  procedure SetMaxRows(Value: Integer); virtual;
147  procedure SetEscapeProcessing(Value: Boolean); virtual;
148  function GetQueryTimeout: Integer; virtual;
149  procedure SetQueryTimeout(Value: Integer); virtual;
150  procedure Cancel; virtual;
151  procedure SetCursorName(const Value: AnsiString); virtual;
152 
153  function GetResultSet: IZResultSet; virtual;
154  function GetUpdateCount: Integer; virtual;
155  function GetMoreResults: Boolean; virtual;
156 
157  procedure SetFetchDirection(Value: TZFetchDirection); virtual;
158  function GetFetchDirection: TZFetchDirection; virtual;
159  procedure SetFetchSize(Value: Integer); virtual;
160  function GetFetchSize: Integer; virtual;
161 
162  procedure SetResultSetConcurrency(Value: TZResultSetConcurrency); virtual;
163  function GetResultSetConcurrency: TZResultSetConcurrency; virtual;
164  procedure SetResultSetType(Value: TZResultSetType); virtual;
165  function GetResultSetType: TZResultSetType; virtual;
166 
167  procedure SetPostUpdates(Value: TZPostUpdatesMode);
168  function GetPostUpdates: TZPostUpdatesMode;
169  procedure SetLocateUpdates(Value: TZLocateUpdatesMode);
170  function GetLocateUpdates: TZLocateUpdatesMode;
171 
172  procedure AddBatch(const SQL: string); virtual;
173  procedure ClearBatch; virtual;
174  function ExecuteBatch: TIntegerDynArray; virtual;
175 
176  function GetConnection: IZConnection;
177  function GetParameters: TStrings;
178  function GetChunkSize: Integer;
179 
180  function GetWarnings: EZSQLWarning; virtual;
181  procedure ClearWarnings; virtual;
182  function GetEncodedSQL(const SQL: {$IF defined(FPC) and defined(WITH_RAWBYTESTRING)}RawByteString{$ELSE}String{$IFEND}): RawByteString; virtual;
183  end;
184 
185  {** Implements Abstract Prepared SQL Statement. }
186 
187  { TZAbstractPreparedStatement }
188 
189  TZAbstractPreparedStatement = class(TZAbstractStatement, IZPreparedStatement)
190  private
191  FSQL: string;
192  FInParamValues: TZVariantDynArray;
193  FInParamTypes: TZSQLTypeArray;
194  FInParamDefaultValues: TStringDynArray;
195  FInParamCount: Integer;
196  FPrepared : Boolean;
197  FExecCount: Integer;
198  protected
199  FStatementId : Integer;
200  procedure PrepareInParameters; virtual;
201  procedure BindInParameters; virtual;
202  procedure UnPrepareInParameters; virtual;
203 
204  procedure SetInParamCount(NewParamCount: Integer); virtual;
205  procedure SetInParam(ParameterIndex: Integer; SQLType: TZSQLType;
206  const Value: TZVariant); virtual;
207  procedure LogPrepStmtMessage(Category: TZLoggingCategory; const Msg: string = '');
208  function GetInParamLogValue(Value: TZVariant): String;
209 
210  property ExecCount: Integer read FExecCount;
211  property SQL: string read FSQL write FSQL;
212  property InParamValues: TZVariantDynArray
213  read FInParamValues write FInParamValues;
214  property InParamTypes: TZSQLTypeArray
215  read FInParamTypes write FInParamTypes;
216  property InParamDefaultValues: TStringDynArray
217  read FInParamDefaultValues write FInParamDefaultValues;
218  property InParamCount: Integer read FInParamCount write FInParamCount;
219  public
220  constructor Create(Connection: IZConnection; const SQL: string; Info: TStrings);
221  destructor Destroy; override;
222 
223  function ExecuteQuery(const SQL: ZWideString): IZResultSet; override;
224  function ExecuteUpdate(const SQL: ZWideString): Integer; override;
225  function Execute(const SQL: ZWideString): Boolean; override;
226 
227  function ExecuteQuery(const SQL: RawByteString): IZResultSet; override;
228  function ExecuteUpdate(const SQL: RawByteString): Integer; override;
229  function Execute(const SQL: RawByteString): Boolean; override;
230 
231  function ExecuteQueryPrepared: IZResultSet; virtual;
232  function ExecuteUpdatePrepared: Integer; virtual;
233  function ExecutePrepared: Boolean; virtual;
234 
235  function GetSQL : String;
236  procedure Prepare; virtual;
237  procedure Unprepare; virtual;
238  function IsPrepared: Boolean; virtual;
239  property Prepared: Boolean read IsPrepared;
240 
241  procedure SetDefaultValue(ParameterIndex: Integer; const Value: string);
242 
243  procedure SetNull(ParameterIndex: Integer; SQLType: TZSQLType); virtual;
244  procedure SetBoolean(ParameterIndex: Integer; Value: Boolean); virtual;
245  procedure SetByte(ParameterIndex: Integer; Value: Byte); virtual;
246  procedure SetShort(ParameterIndex: Integer; Value: SmallInt); virtual;
247  procedure SetInt(ParameterIndex: Integer; Value: Integer); virtual;
248  procedure SetLong(ParameterIndex: Integer; Value: Int64); virtual;
249  procedure SetFloat(ParameterIndex: Integer; Value: Single); virtual;
250  procedure SetDouble(ParameterIndex: Integer; Value: Double); virtual;
251  procedure SetBigDecimal(ParameterIndex: Integer; Value: Extended); virtual;
252  procedure SetPChar(ParameterIndex: Integer; Value: PChar); virtual;
253  procedure SetString(ParameterIndex: Integer; const Value: String); virtual;
254  procedure SetUnicodeString(ParameterIndex: Integer; const Value: ZWideString); virtual; //AVZ
255  procedure SetBytes(ParameterIndex: Integer; const Value: TByteDynArray); virtual;
256  procedure SetDate(ParameterIndex: Integer; Value: TDateTime); virtual;
257  procedure SetTime(ParameterIndex: Integer; Value: TDateTime); virtual;
258  procedure SetTimestamp(ParameterIndex: Integer; Value: TDateTime); virtual;
259  procedure SetAsciiStream(ParameterIndex: Integer; Value: TStream); virtual;
260  procedure SetUnicodeStream(ParameterIndex: Integer; Value: TStream); virtual;
261  procedure SetBinaryStream(ParameterIndex: Integer; Value: TStream); virtual;
262  procedure SetBlob(ParameterIndex: Integer; SQLType: TZSQLType; Value: IZBlob); virtual;
263  procedure SetValue(ParameterIndex: Integer; const Value: TZVariant); virtual;
264 
265  procedure ClearParameters; virtual;
266 
267  procedure AddBatchPrepared; virtual;
268  function GetMetaData: IZResultSetMetaData; virtual;
269  end;
270 
271  {** Implements Abstract Callable SQL statement. }
272  TZAbstractCallableStatement = class(TZAbstractPreparedStatement,
273  IZCallableStatement)
274  private
275  FOutParamValues: TZVariantDynArray;
276  FOutParamTypes: TZSQLTypeArray;
277  FOutParamCount: Integer;
278  FLastWasNull: Boolean;
279  FTemp: String;
280  FProcSql: String;
281  FIsFunction: Boolean;
282  FHasOutParameter: Boolean;
283  protected
284  FResultSets: IZCollection;
285  FActiveResultset: Integer;
286  FDBParamTypes: array of ShortInt;
287  procedure ClearResultSets; virtual;
288  procedure TrimInParameters; virtual;
289  procedure SetOutParamCount(NewParamCount: Integer); virtual;
290  function GetOutParam(ParameterIndex: Integer): TZVariant; virtual;
291  procedure SetProcSQL(const Value: String); virtual;
292 
293  property OutParamValues: TZVariantDynArray
294  read FOutParamValues write FOutParamValues;
295  property OutParamTypes: TZSQLTypeArray
296  read FOutParamTypes write FOutParamTypes;
297  property OutParamCount: Integer read FOutParamCount write FOutParamCount;
298  property LastWasNull: Boolean read FLastWasNull write FLastWasNull;
299  property ProcSql: String read FProcSQL write SetProcSQL;
300  public
301  constructor Create(Connection: IZConnection; SQL: string; Info: TStrings);
302  procedure ClearParameters; override;
303  procedure Close; override;
304 
305  function IsFunction: Boolean;
306  function HasOutParameter: Boolean;
307  function HasMoreResultSets: Boolean; virtual;
308  function GetFirstResultSet: IZResultSet; virtual;
309  function GetPreviousResultSet: IZResultSet; virtual;
310  function GetNextResultSet: IZResultSet; virtual;
311  function GetLastResultSet: IZResultSet; virtual;
312  function BOR: Boolean; virtual;
313  function EOR: Boolean; virtual;
314  function GetResultSetByIndex(const Index: Integer): IZResultSet; virtual;
315  function GetResultSetCount: Integer; virtual;
316 
317  procedure RegisterOutParameter(ParameterIndex: Integer;
318  SQLType: Integer); virtual;
319  procedure RegisterParamType(ParameterIndex:integer;ParamType:Integer);virtual;
320  function WasNull: Boolean; virtual;
321 
322  function IsNull(ParameterIndex: Integer): Boolean; virtual;
323  function GetPChar(ParameterIndex: Integer): PChar; virtual;
324  function GetString(ParameterIndex: Integer): String; virtual;
325  function GetUnicodeString(ParameterIndex: Integer): WideString; virtual;
326  function GetBoolean(ParameterIndex: Integer): Boolean; virtual;
327  function GetByte(ParameterIndex: Integer): Byte; virtual;
328  function GetShort(ParameterIndex: Integer): SmallInt; virtual;
329  function GetInt(ParameterIndex: Integer): Integer; virtual;
330  function GetLong(ParameterIndex: Integer): Int64; virtual;
331  function GetFloat(ParameterIndex: Integer): Single; virtual;
332  function GetDouble(ParameterIndex: Integer): Double; virtual;
333  function GetBigDecimal(ParameterIndex: Integer): Extended; virtual;
334  function GetBytes(ParameterIndex: Integer): TByteDynArray; virtual;
335  function GetDate(ParameterIndex: Integer): TDateTime; virtual;
336  function GetTime(ParameterIndex: Integer): TDateTime; virtual;
337  function GetTimestamp(ParameterIndex: Integer): TDateTime; virtual;
338  function GetValue(ParameterIndex: Integer): TZVariant; virtual;
339  end;
340 
341  {** Implements a real Prepared Callable SQL Statement. }
342  TZAbstractPreparedCallableStatement = CLass(TZAbstractCallableStatement)
343  protected
344  procedure SetProcSQL(const Value: String); override;
345  public
346  function ExecuteQuery(const SQL: ZWideString): IZResultSet; override;
347  function ExecuteQuery(const SQL: RawByteString): IZResultSet; override;
348  function ExecuteUpdate(const SQL: ZWideString): Integer; override;
349  function ExecuteUpdate(const SQL: RawByteString): Integer; override;
350  function Execute(const SQL: ZWideString): Boolean; override;
351  function Execute(const SQL: RawByteString): Boolean; override;
352  end;
353 
354  {** Implements an Emulated Prepared SQL Statement. }
355  TZEmulatedPreparedStatement = class(TZAbstractPreparedStatement)
356  private
357  FExecStatement: IZStatement;
358  FCachedQuery: TStrings;
359  FLastStatement: IZStatement;
360  procedure SetLastStatement(LastStatement: IZStatement);
361  protected
362  FNeedNCharDetection: Boolean;
363  property ExecStatement: IZStatement read FExecStatement write FExecStatement;
364  property CachedQuery: TStrings read FCachedQuery write FCachedQuery;
365  property LastStatement: IZStatement read FLastStatement write SetLastStatement;
366 
367  function CreateExecStatement: IZStatement; virtual; abstract;
368  function PrepareWideSQLParam(ParamIndex: Integer): ZWideString; virtual;
369  function PrepareAnsiSQLParam(ParamIndex: Integer): RawByteString; virtual;
370  function GetExecStatement: IZStatement;
371  function TokenizeSQLQuery: TStrings;
372  function PrepareWideSQLQuery: ZWideString; virtual;
373  function PrepareAnsiSQLQuery: RawByteString; virtual;
374  public
375  destructor Destroy; override;
376 
377  procedure Close; override;
378 
379  function ExecuteQuery(const SQL: ZWideString): IZResultSet; override;
380  function ExecuteQuery(const SQL: RawByteString): IZResultSet; override;
381  function ExecuteUpdate(const SQL: ZWideString): Integer; override;
382  function ExecuteUpdate(const SQL: RawByteString): Integer; override;
383  function Execute(const SQL: ZWideString): Boolean; override;
384  function Execute(const SQL: RawByteString): Boolean; override;
385 
386  function ExecuteQueryPrepared: IZResultSet; override;
387  function ExecuteUpdatePrepared: Integer; override;
388  function ExecutePrepared: Boolean; override;
389  end;
390 
391 implementation
392 
393 uses ZSysUtils, ZMessages, ZDbcResultSet, ZCollections;
394 
395 var
396 {**
397  Holds the value of the last assigned statement ID.
398  Only Accessible using TZAbstractStatement.GetNextStatementId.
399 }
400  GlobalStatementIdCounter : integer;
401 
402 { TZAbstractStatement }
403 
404 {**
405  Constructs this class and defines the main properties.
406  @param Connection a database connection object.
407  @param Info a statement parameters;
408 }
409 constructor TZAbstractStatement.Create(Connection: IZConnection; Info: TStrings);
410 begin
411  { Sets the default properties. }
412  inherited Create;
413  ConSettings := Connection.GetConSettings;
414  FMaxFieldSize := 0;
415  FMaxRows := 0;
416  FEscapeProcessing := False;
417  FQueryTimeout := 0;
418  FLastUpdateCount := -1;
419  FLastResultSet := nil;
420  FFetchDirection := fdForward;
421  FFetchSize := 0;
422  FResultSetConcurrency := rcReadOnly;
423  FResultSetType := rtForwardOnly;
424  FCursorName := '';
425 
426  FConnection := Connection;
427  FBatchQueries := TStringList.Create;
428 
429  FInfo := TStringList.Create;
430  if Info <> nil then
431  FInfo.AddStrings(Info);
432  if FInfo.Values['chunk_size'] = '' then
433  FChunkSize := StrToIntDef(Connection.GetParameters.Values['chunk_size'], 4096)
434  else
435  FChunkSize := StrToIntDef(FInfo.Values['chunk_size'], 4096);
436 
437  FIsAnsiDriver := Connection.GetIZPlainDriver.IsAnsiDriver;
438 end;
439 
440 {**
441  Destroys this object and cleanups the memory.
442 }
443 destructor TZAbstractStatement.Destroy;
444 begin
445  Close;
446  if Assigned(FBatchQueries) then
447  FreeAndNil(FBatchQueries);
448  FConnection := nil;
449  FreeAndNil(FInfo);
450  FLastResultSet := nil;
451  inherited Destroy;
452 end;
453 
454 {**
455  Sets the preprepared SQL-Statement in an String and AnsiStringForm.
456  @param Value: the SQL-String which has to be optional preprepared
457 }
458 procedure TZAbstractStatement.SetWSQL(const Value: ZWideString);
459 begin
460  if FWSQL <> Value then
461  begin
462  {$IFDEF UNICODE}
463  FaSQL := GetEncodedSQL(Value);
464  {$ELSE}
465  FaSQL := ZPlainString(Value);
466  {$ENDIF}
467  FWSQL := ZDbcUnicodeString(FASQL, ConSettings^.ClientCodePage^.CP);;
468  end;
469 end;
470 
471 procedure TZAbstractStatement.SetASQL(const Value: RawByteString);
472 begin
473  if FASQL <> Value then
474  begin
475  {$IFNDEF UNICODE}
476  FASQL := GetEncodedSQL(Value);
477  FWSQL := ZDbcUnicodeString(FASQL, ConSettings^.ClientCodePage^.CP);
478  {$else}
479  FASQL := Value;
480  FWSQL := ZDbcString(Value);
481  {$ENDIF}
482  end;
483 end;
484 
485 {**
486  Raises unsupported operation exception.
487 }
488 procedure TZAbstractStatement.RaiseUnsupportedException;
489 begin
490  raise EZSQLException.Create(SUnsupportedOperation);
491 end;
492 
493 {**
494  Sets a last result set to avoid problems with reference counting.
495  @param ResultSet the lastest executed result set.
496 }
497 procedure TZAbstractStatement.SetLastResultSet(ResultSet: IZResultSet);
498 begin
499  if (FLastResultSet <> nil) then
500  FLastResultSet.Close;
501 
502  FLastResultSet := ResultSet;
503 end;
504 
505 class function TZAbstractStatement.GetNextStatementId: integer;
506 begin
507  Inc(GlobalStatementIdCounter);
508  Result := GlobalStatementIdCounter;
509 end;
510 
511 {**
512  Executes an SQL statement that returns a single <code>ResultSet</code> object.
513  @param sql typically this is a static SQL <code>SELECT</code> statement
514  @return a <code>ResultSet</code> object that contains the data produced by the
515  given query; never <code>null</code>
516 }
517 function TZAbstractStatement.ExecuteQuery(const SQL: ZWideString): IZResultSet;
518 begin
519  WSQL := SQL;
520  Result := ExecuteQuery(ASQL);
521 end;
522 
523 function TZAbstractStatement.ExecuteQuery(const SQL: RawByteString): IZResultSet;
524 begin
525  Result := nil;
526  RaiseUnsupportedException;
527 end;
528 
529 {**
530  Executes an SQL <code>INSERT</code>, <code>UPDATE</code> or
531  <code>DELETE</code> statement. In addition,
532  SQL statements that return nothing, such as SQL DDL statements,
533  can be executed.
534 
535  @param sql an SQL <code>INSERT</code>, <code>UPDATE</code> or
536  <code>DELETE</code> statement or an SQL statement that returns nothing
537  @return either the row count for <code>INSERT</code>, <code>UPDATE</code>
538  or <code>DELETE</code> statements, or 0 for SQL statements that return nothing
539 }
540 function TZAbstractStatement.ExecuteUpdate(const SQL: ZWideString): Integer;
541 begin
542  WSQL := SQL;
543  Result := ExecuteUpdate(ASQL);
544 end;
545 
546 function TZAbstractStatement.ExecuteUpdate(const SQL: RawByteString): Integer;
547 begin
548  Result := 0;
549  RaiseUnsupportedException;
550 end;
551 
552 {**
553  Releases this <code>Statement</code> object's database
554  and JDBC resources immediately instead of waiting for
555  this to happen when it is automatically closed.
556  It is generally good practice to release resources as soon as
557  you are finished with them to avoid tying up database
558  resources.
559  <P><B>Note:</B> A <code>Statement</code> object is automatically closed when it is
560  garbage collected. When a <code>Statement</code> object is closed, its current
561  <code>ResultSet</code> object, if one exists, is also closed.
562 }
563 procedure TZAbstractStatement.Close;
564 begin
565  if LastResultSet <> nil then
566  begin
567  LastResultSet.Close;
568  LastResultSet := nil;
569  end;
570  FClosed := True;
571 end;
572 
573 {**
574  Returns the maximum number of bytes allowed
575  for any column value.
576  This limit is the maximum number of bytes that can be
577  returned for any column value.
578  The limit applies only to <code>BINARY</code>,
579  <code>VARBINARY</code>, <code>LONGVARBINARY</code>, <code>CHAR</code>, <code>VARCHAR</code>, and <code>LONGVARCHAR</code>
580  columns. If the limit is exceeded, the excess data is silently
581  discarded.
582  @return the current max column size limit; zero means unlimited
583 }
584 function TZAbstractStatement.GetMaxFieldSize: Integer;
585 begin
586  Result := FMaxFieldSize;
587 end;
588 
589 {**
590  Sets the limit for the maximum number of bytes in a column to
591  the given number of bytes. This is the maximum number of bytes
592  that can be returned for any column value. This limit applies
593  only to <code>BINARY</code>, <code>VARBINARY</code>,
594  <code>LONGVARBINARY</code>, <code>CHAR</code>, <code>VARCHAR</code>, and
595  <code>LONGVARCHAR</code> fields. If the limit is exceeded, the excess data
596  is silently discarded. For maximum portability, use values
597  greater than 256.
598 
599  @param max the new max column size limit; zero means unlimited
600 }
601 procedure TZAbstractStatement.SetMaxFieldSize(Value: Integer);
602 begin
603  FMaxFieldSize := Value;
604 end;
605 
606 {**
607  Retrieves the maximum number of rows that a
608  <code>ResultSet</code> object can contain. If the limit is exceeded, the excess
609  rows are silently dropped.
610 
611  @return the current max row limit; zero means unlimited
612 }
613 function TZAbstractStatement.GetMaxRows: Integer;
614 begin
615  Result := FMaxRows;
616 end;
617 
618 {**
619  Sets the limit for the maximum number of rows that any
620  <code>ResultSet</code> object can contain to the given number.
621  If the limit is exceeded, the excess rows are silently dropped.
622 
623  @param max the new max rows limit; zero means unlimited
624 }
625 procedure TZAbstractStatement.SetMaxRows(Value: Integer);
626 begin
627  FMaxRows := Value;
628 end;
629 
630 {**
631  Sets escape processing on or off.
632  If escape scanning is on (the default), the driver will do
633  escape substitution before sending the SQL to the database.
634 
635  Note: Since prepared statements have usually been parsed prior
636  to making this call, disabling escape processing for prepared
637  statements will have no effect.
638 
639  @param enable <code>true</code> to enable; <code>false</code> to disable
640 }
641 procedure TZAbstractStatement.SetEscapeProcessing(Value: Boolean);
642 begin
643  FEscapeProcessing := Value;
644 end;
645 
646 {**
647  Retrieves the number of seconds the driver will
648  wait for a <code>Statement</code> object to execute. If the limit is exceeded, a
649  <code>SQLException</code> is thrown.
650 
651  @return the current query timeout limit in seconds; zero means unlimited
652 }
653 function TZAbstractStatement.GetQueryTimeout: Integer;
654 begin
655  Result := FQueryTimeout;
656 end;
657 
658 {**
659  Sets the number of seconds the driver will
660  wait for a <code>Statement</code> object to execute to the given number of seconds.
661  If the limit is exceeded, an <code>SQLException</code> is thrown.
662 
663  @param seconds the new query timeout limit in seconds; zero means unlimited
664 }
665 procedure TZAbstractStatement.SetQueryTimeout(Value: Integer);
666 begin
667  FQueryTimeout := Value;
668 end;
669 
670 {**
671  Cancels this <code>Statement</code> object if both the DBMS and
672  driver support aborting an SQL statement.
673  This method can be used by one thread to cancel a statement that
674  is being executed by another thread.
675 }
676 procedure TZAbstractStatement.Cancel;
677 begin
678  RaiseUnsupportedException;
679 end;
680 
681 {**
682  Retrieves the first warning reported by calls on this <code>Statement</code> object.
683  Subsequent <code>Statement</code> object warnings will be chained to this
684  <code>SQLWarning</code> object.
685 
686  <p>The warning chain is automatically cleared each time
687  a statement is (re)executed.
688 
689  <P><B>Note:</B> If you are processing a <code>ResultSet</code> object, any
690  warnings associated with reads on that <code>ResultSet</code> object
691  will be chained on it.
692 
693  @return the first <code>SQLWarning</code> object or <code>null</code>
694 }
695 function TZAbstractStatement.GetWarnings: EZSQLWarning;
696 begin
697  Result := nil;
698 end;
699 
700 {**
701  Clears all the warnings reported on this <code>Statement</code>
702  object. After a call to this method,
703  the method <code>getWarnings</code> will return
704  <code>null</code> until a new warning is reported for this
705  <code>Statement</code> object.
706 }
707 procedure TZAbstractStatement.ClearWarnings;
708 begin
709 end;
710 
711 function TZAbstractStatement.GetEncodedSQL(const SQL: {$IF defined(FPC) and defined(WITH_RAWBYTESTRING)}RawByteString{$ELSE}String{$IFEND}): RawByteString;
712 var
713  SQLTokens: TZTokenDynArray;
714  i: Integer;
715 begin
716  if GetConnection.AutoEncodeStrings then
717  begin
718  Result := ''; //init for FPC
719  SQLTokens := GetConnection.GetDriver.GetTokenizer.TokenizeBuffer(SQL, [toSkipEOF]); //Disassembles the Query
720  for i := Low(SQLTokens) to high(SQLTokens) do //Assembles the Query
721  begin
722  case (SQLTokens[i].TokenType) of
723  ttEscape:
724  Result := Result + {$IFDEF UNICODE}ZPlainString{$ENDIF}(SQLTokens[i].Value);
725  ttQuoted, ttComment,
726  ttWord, ttQuotedIdentifier, ttKeyword:
727  Result := Result + ZPlainString(SQLTokens[i].Value);
728  else
729  Result := Result + RawByteString(SQLTokens[i].Value);
730  end;
731  end;
732  end
733  else
734  {$IFDEF UNICODE}
735  Result := ZPlainString(SQL);
736  {$ELSE}
737  Result := SQL;
738  {$ENDIF}
739 end;
740 
741 {**
742  Defines the SQL cursor name that will be used by
743  subsequent <code>Statement</code> object <code>execute</code> methods.
744  This name can then be
745  used in SQL positioned update/delete statements to identify the
746  current row in the <code>ResultSet</code> object generated by this statement. If
747  the database doesn't support positioned update/delete, this
748  method is a noop. To insure that a cursor has the proper isolation
749  level to support updates, the cursor's <code>SELECT</code> statement should be
750  of the form 'select for update ...'. If the 'for update' phrase is
751  omitted, positioned updates may fail.
752 
753  <P><B>Note:</B> By definition, positioned update/delete
754  execution must be done by a different <code>Statement</code> object than the one
755  which generated the <code>ResultSet</code> object being used for positioning. Also,
756  cursor names must be unique within a connection.
757 
758  @param name the new cursor name, which must be unique within a connection
759 }
760 procedure TZAbstractStatement.SetCursorName(const Value: AnsiString);
761 begin
762  FCursorName := Value;
763 end;
764 
765 {**
766  Executes an SQL statement that may return multiple results.
767  Under some (uncommon) situations a single SQL statement may return
768  multiple result sets and/or update counts. Normally you can ignore
769  this unless you are (1) executing a stored procedure that you know may
770  return multiple results or (2) you are dynamically executing an
771  unknown SQL string. The methods <code>execute</code>,
772  <code>getMoreResults</code>, <code>getResultSet</code>,
773  and <code>getUpdateCount</code> let you navigate through multiple results.
774 
775  The <code>execute</code> method executes an SQL statement and indicates the
776  form of the first result. You can then use the methods
777  <code>getResultSet</code> or <code>getUpdateCount</code>
778  to retrieve the result, and <code>getMoreResults</code> to
779  move to any subsequent result(s).
780 
781  @param sql any SQL statement
782  @return <code>true</code> if the next result is a <code>ResultSet</code> object;
783  <code>false</code> if it is an update count or there are no more results
784  @see #getResultSet
785  @see #getUpdateCount
786  @see #getMoreResults
787 }
788 function TZAbstractStatement.Execute(const SQL: ZWideString): Boolean;
789 begin
790  WSQL := SQL;
791  Result := Execute(ASQL);
792 end;
793 
794 function TZAbstractStatement.Execute(const SQL: RawByteString): Boolean;
795 begin
796  Result := False;
797  LastResultSet := nil;
798  LastUpdateCount := -1;
799 end;
800 
801 {**
802  Returns the current result as a <code>ResultSet</code> object.
803  This method should be called only once per result.
804 
805  @return the current result as a <code>ResultSet</code> object;
806  <code>null</code> if the result is an update count or there are no more results
807  @see #execute
808 }
809 function TZAbstractStatement.GetResultSet: IZResultSet;
810 begin
811  Result := LastResultSet;
812 end;
813 
814 {**
815  Returns the current result as an update count;
816  if the result is a <code>ResultSet</code> object or there are no more results, -1
817  is returned. This method should be called only once per result.
818 
819  @return the current result as an update count; -1 if the current result is a
820  <code>ResultSet</code> object or there are no more results
821  @see #execute
822 }
823 function TZAbstractStatement.GetUpdateCount: Integer;
824 begin
825  Result := FLastUpdateCount;
826 end;
827 
828 {**
829  Moves to a <code>Statement</code> object's next result. It returns
830  <code>true</code> if this result is a <code>ResultSet</code> object.
831  This method also implicitly closes any current <code>ResultSet</code>
832  object obtained with the method <code>getResultSet</code>.
833 
834  <P>There are no more results when the following is true:
835  <PRE>
836  <code>(!getMoreResults() && (getUpdateCount() == -1)</code>
837  </PRE>
838 
839  @return <code>true</code> if the next result is a <code>ResultSet</code> object;
840  <code>false</code> if it is an update count or there are no more results
841  @see #execute
842 }
843 function TZAbstractStatement.GetMoreResults: Boolean;
844 begin
845  Result := False;
846 end;
847 
848 {**
849  Retrieves the direction for fetching rows from
850  database tables that is the default for result sets
851  generated from this <code>Statement</code> object.
852  If this <code>Statement</code> object has not set
853  a fetch direction by calling the method <code>setFetchDirection</code>,
854  the return value is implementation-specific.
855 
856  @return the default fetch direction for result sets generated
857  from this <code>Statement</code> object
858 }
859 function TZAbstractStatement.GetFetchDirection: TZFetchDirection;
860 begin
861  Result := FFetchDirection;
862 end;
863 
864 {**
865  Gives the driver a hint as to the direction in which
866  the rows in a result set
867  will be processed. The hint applies only to result sets created
868  using this <code>Statement</code> object. The default value is
869  <code>ResultSet.FETCH_FORWARD</code>.
870  <p>Note that this method sets the default fetch direction for
871  result sets generated by this <code>Statement</code> object.
872  Each result set has its own methods for getting and setting
873  its own fetch direction.
874  @param direction the initial direction for processing rows
875 }
876 procedure TZAbstractStatement.SetFetchDirection(Value: TZFetchDirection);
877 begin
878  FFetchDirection := Value;
879 end;
880 
881 {**
882  Retrieves the number of result set rows that is the default
883  fetch size for result sets
884  generated from this <code>Statement</code> object.
885  If this <code>Statement</code> object has not set
886  a fetch size by calling the method <code>setFetchSize</code>,
887  the return value is implementation-specific.
888  @return the default fetch size for result sets generated
889  from this <code>Statement</code> object
890 }
891 function TZAbstractStatement.GetFetchSize: Integer;
892 begin
893  Result := FFetchSize;
894 end;
895 
896 {**
897  Gives the JDBC driver a hint as to the number of rows that should
898  be fetched from the database when more rows are needed. The number
899  of rows specified affects only result sets created using this
900  statement. If the value specified is zero, then the hint is ignored.
901  The default value is zero.
902 
903  @param rows the number of rows to fetch
904 }
905 procedure TZAbstractStatement.SetFetchSize(Value: Integer);
906 begin
907  FFetchSize := Value;
908 end;
909 
910 {**
911  Sets a result set concurrency for <code>ResultSet</code> objects
912  generated by this <code>Statement</code> object.
913 
914  @param Concurrency either <code>ResultSet.CONCUR_READ_ONLY</code> or
915  <code>ResultSet.CONCUR_UPDATABLE</code>
916 }
917 procedure TZAbstractStatement.SetResultSetConcurrency(
918  Value: TZResultSetConcurrency);
919 begin
920  FResultSetConcurrency := Value;
921 end;
922 
923 {**
924  Retrieves the result set concurrency for <code>ResultSet</code> objects
925  generated by this <code>Statement</code> object.
926 
927  @return either <code>ResultSet.CONCUR_READ_ONLY</code> or
928  <code>ResultSet.CONCUR_UPDATABLE</code>
929 }
930 function TZAbstractStatement.GetResultSetConcurrency: TZResultSetConcurrency;
931 begin
932  Result := FResultSetConcurrency;
933 end;
934 
935 {**
936  Sets a result set type for <code>ResultSet</code> objects
937  generated by this <code>Statement</code> object.
938 
939  @param ResultSetType one of <code>ResultSet.TYPE_FORWARD_ONLY</code>,
940  <code>ResultSet.TYPE_SCROLL_INSENSITIVE</code>, or
941  <code>ResultSet.TYPE_SCROLL_SENSITIVE</code>
942 }
943 procedure TZAbstractStatement.SetResultSetType(Value: TZResultSetType);
944 begin
945  FResultSetType := Value;
946 end;
947 
948 {**
949  Retrieves the result set type for <code>ResultSet</code> objects
950  generated by this <code>Statement</code> object.
951 
952  @return one of <code>ResultSet.TYPE_FORWARD_ONLY</code>,
953  <code>ResultSet.TYPE_SCROLL_INSENSITIVE</code>, or
954  <code>ResultSet.TYPE_SCROLL_SENSITIVE</code>
955 }
956 function TZAbstractStatement.GetResultSetType: TZResultSetType;
957 begin
958  Result := FResultSetType;
959 end;
960 
961 {**
962  Gets the current value for locate updates.
963  @returns the current value for locate updates.
964 }
965 function TZAbstractStatement.GetLocateUpdates: TZLocateUpdatesMode;
966 begin
967  Result := FLocateUpdates;
968 end;
969 
970 {**
971  Sets a new value for locate updates.
972  @param Value a new value for locate updates.
973 }
974 procedure TZAbstractStatement.SetLocateUpdates(Value: TZLocateUpdatesMode);
975 begin
976  FLocateUpdates := Value;
977 end;
978 
979 {**
980  Gets the current value for post updates.
981  @returns the current value for post updates.
982 }
983 function TZAbstractStatement.GetPostUpdates: TZPostUpdatesMode;
984 begin
985  Result := FPostUpdates;
986 end;
987 
988 {**
989  Sets a new value for post updates.
990  @param Value a new value for post updates.
991 }
992 procedure TZAbstractStatement.SetPostUpdates(Value: TZPostUpdatesMode);
993 begin
994  FPostUpdates := Value;
995 end;
996 
997 {**
998  Adds an SQL command to the current batch of commmands for this
999  <code>Statement</code> object. This method is optional.
1000 
1001  @param sql typically this is a static SQL <code>INSERT</code> or
1002  <code>UPDATE</code> statement
1003 }
1004 procedure TZAbstractStatement.AddBatch(const SQL: string);
1005 begin
1006  FBatchQueries.Add(SQL);
1007 end;
1008 
1009 {**
1010  Makes the set of commands in the current batch empty.
1011  This method is optional.
1012 }
1013 procedure TZAbstractStatement.ClearBatch;
1014 begin
1015  FBatchQueries.Clear;
1016 end;
1017 
1018 {**
1019  Submits a batch of commands to the database for execution and
1020  if all commands execute successfully, returns an array of update counts.
1021  The <code>int</code> elements of the array that is returned are ordered
1022  to correspond to the commands in the batch, which are ordered
1023  according to the order in which they were added to the batch.
1024  The elements in the array returned by the method <code>executeBatch</code>
1025  may be one of the following:
1026  <OL>
1027  <LI>A number greater than or equal to zero -- indicates that the
1028  command was processed successfully and is an update count giving the
1029  number of rows in the database that were affected by the command's
1030  execution
1031  <LI>A value of <code>-2</code> -- indicates that the command was
1032  processed successfully but that the number of rows affected is
1033  unknown
1034  <P>
1035  If one of the commands in a batch update fails to execute properly,
1036  this method throws a <code>BatchUpdateException</code>, and a JDBC
1037  driver may or may not continue to process the remaining commands in
1038  the batch. However, the driver's behavior must be consistent with a
1039  particular DBMS, either always continuing to process commands or never
1040  continuing to process commands. If the driver continues processing
1041  after a failure, the array returned by the method
1042  <code>BatchUpdateException.getUpdateCounts</code>
1043  will contain as many elements as there are commands in the batch, and
1044  at least one of the elements will be the following:
1045  <P>
1046  <LI>A value of <code>-3</code> -- indicates that the command failed
1047  to execute successfully and occurs only if a driver continues to
1048  process commands after a command fails
1049  </OL>
1050  <P>
1051  A driver is not required to implement this method.
1052  The possible implementations and return values have been modified in
1053  the Java 2 SDK, Standard Edition, version 1.3 to
1054  accommodate the option of continuing to proccess commands in a batch
1055  update after a <code>BatchUpdateException</code> obejct has been thrown.
1056 
1057  @return an array of update counts containing one element for each
1058  command in the batch. The elements of the array are ordered according
1059  to the order in which commands were added to the batch.
1060 }
1061 function TZAbstractStatement.ExecuteBatch: TIntegerDynArray;
1062 var
1063  I: Integer;
1064 begin
1065  SetLength(Result, FBatchQueries.Count);
1066  for I := 0 to FBatchQueries.Count -1 do
1067  Result[I] := ExecuteUpdate(FBatchQueries[I]);
1068  ClearBatch;
1069 end;
1070 
1071 {**
1072  Returns the <code>Connection</code> object
1073  that produced this <code>Statement</code> object.
1074  @return the connection that produced this statement
1075 }
1076 function TZAbstractStatement.GetConnection: IZConnection;
1077 begin
1078  Result := FConnection;
1079 end;
1080 
1081 {**
1082  Gets statement parameters.
1083  @returns a list with statement parameters.
1084 }
1085 function TZAbstractStatement.GetParameters: TStrings;
1086 begin
1087  Result := FInfo;
1088 end;
1089 
1090 {**
1091  Returns the ChunkSize for reading/writing large lobs
1092  @returns the chunksize in bytes.
1093 }
1094 function TZAbstractStatement.GetChunkSize: Integer;
1095 begin
1096  Result := FChunkSize;
1097 end;
1098 
1099 { TZAbstractPreparedStatement }
1100 
1101 {**
1102  Constructs this object and assigns main properties.
1103  @param Connection a database connection object.
1104  @param Sql a prepared Sql statement.
1105  @param Info a statement parameters.
1106 }
1107 constructor TZAbstractPreparedStatement.Create(Connection: IZConnection;
1108  const SQL: string; Info: TStrings);
1109 begin
1110  inherited Create(Connection, Info);
1111  FSQL := SQL;
1112  {$IFDEF UNICODE}WSQL{$ELSE}ASQL{$ENDIF} := SQL;
1113  FInParamCount := 0;
1114  SetInParamCount(0);
1115  FPrepared := False;
1116  FExecCount := 0;
1117  FStatementId := Self.GetNextStatementId;
1118 end;
1119 
1120 {**
1121  Destroys this object and cleanups the memory.
1122 }
1123 destructor TZAbstractPreparedStatement.Destroy;
1124 begin
1125  Unprepare;
1126  inherited Destroy;
1127  ClearParameters;
1128 end;
1129 
1130 {**
1131  Executes an SQL statement that returns a single <code>ResultSet</code> object.
1132  @param sql typically this is a static SQL <code>SELECT</code> statement
1133  @return a <code>ResultSet</code> object that contains the data produced by the
1134  given query; never <code>null</code>
1135 }
1136 function TZAbstractPreparedStatement.ExecuteQuery(const SQL: ZWideString): IZResultSet;
1137 begin
1138  WSQL := SQL;
1139  Result := ExecuteQueryPrepared;
1140 end;
1141 
1142 {**
1143  Executes an SQL <code>INSERT</code>, <code>UPDATE</code> or
1144  <code>DELETE</code> statement. In addition,
1145  SQL statements that return nothing, such as SQL DDL statements,
1146  can be executed.
1147 
1148  @param sql an SQL <code>INSERT</code>, <code>UPDATE</code> or
1149  <code>DELETE</code> statement or an SQL statement that returns nothing
1150  @return either the row count for <code>INSERT</code>, <code>UPDATE</code>
1151  or <code>DELETE</code> statements, or 0 for SQL statements that return nothing
1152 }
1153 function TZAbstractPreparedStatement.ExecuteUpdate(const SQL: ZWideString): Integer;
1154 begin
1155  WSQL := SQL;
1156  Result := ExecuteUpdatePrepared;
1157 end;
1158 
1159 {**
1160  Executes an SQL statement that may return multiple results.
1161  Under some (uncommon) situations a single SQL statement may return
1162  multiple result sets and/or update counts. Normally you can ignore
1163  this unless you are (1) executing a stored procedure that you know may
1164  return multiple results or (2) you are dynamically executing an
1165  unknown SQL string. The methods <code>execute</code>,
1166  <code>getMoreResults</code>, <code>getResultSet</code>,
1167  and <code>getUpdateCount</code> let you navigate through multiple results.
1168 
1169  The <code>execute</code> method executes an SQL statement and indicates the
1170  form of the first result. You can then use the methods
1171  <code>getResultSet</code> or <code>getUpdateCount</code>
1172  to retrieve the result, and <code>getMoreResults</code> to
1173  move to any subsequent result(s).
1174 
1175  @param sql any SQL statement
1176  @return <code>true</code> if the next result is a <code>ResultSet</code> object;
1177  <code>false</code> if it is an update count or there are no more results
1178  @see #getResultSet
1179  @see #getUpdateCount
1180  @see #getMoreResults
1181 }
1182 function TZAbstractPreparedStatement.Execute(const SQL: ZWideString): Boolean;
1183 begin
1184  WSQL := SQL;
1185  Result := ExecutePrepared;
1186 end;
1187 
1188 {**
1189  Executes an SQL statement that returns a single <code>ResultSet</code> object.
1190  @param sql typically this is a static SQL <code>SELECT</code> statement
1191  @return a <code>ResultSet</code> object that contains the data produced by the
1192  given query; never <code>null</code>
1193 }
1194 function TZAbstractPreparedStatement.ExecuteQuery(const SQL: RawByteString): IZResultSet;
1195 begin
1196  ASQL := SQL;
1197  Result := ExecuteQueryPrepared;
1198 end;
1199 
1200 {**
1201  Executes an SQL <code>INSERT</code>, <code>UPDATE</code> or
1202  <code>DELETE</code> statement. In addition,
1203  SQL statements that return nothing, such as SQL DDL statements,
1204  can be executed.
1205 
1206  @param sql an SQL <code>INSERT</code>, <code>UPDATE</code> or
1207  <code>DELETE</code> statement or an SQL statement that returns nothing
1208  @return either the row count for <code>INSERT</code>, <code>UPDATE</code>
1209  or <code>DELETE</code> statements, or 0 for SQL statements that return nothing
1210 }
1211 function TZAbstractPreparedStatement.ExecuteUpdate(const SQL: RawByteString): Integer;
1212 begin
1213  ASQL := SQL;
1214  Result := ExecuteUpdatePrepared;
1215 end;
1216 
1217 {**
1218  Executes an SQL statement that may return multiple results.
1219  Under some (uncommon) situations a single SQL statement may return
1220  multiple result sets and/or update counts. Normally you can ignore
1221  this unless you are (1) executing a stored procedure that you know may
1222  return multiple results or (2) you are dynamically executing an
1223  unknown SQL string. The methods <code>execute</code>,
1224  <code>getMoreResults</code>, <code>getResultSet</code>,
1225  and <code>getUpdateCount</code> let you navigate through multiple results.
1226 
1227  The <code>execute</code> method executes an SQL statement and indicates the
1228  form of the first result. You can then use the methods
1229  <code>getResultSet</code> or <code>getUpdateCount</code>
1230  to retrieve the result, and <code>getMoreResults</code> to
1231  move to any subsequent result(s).
1232 
1233  @param sql any SQL statement
1234  @return <code>true</code> if the next result is a <code>ResultSet</code> object;
1235  <code>false</code> if it is an update count or there are no more results
1236  @see #getResultSet
1237  @see #getUpdateCount
1238  @see #getMoreResults
1239 }
1240 function TZAbstractPreparedStatement.Execute(const SQL: RawByteString): Boolean;
1241 begin
1242  ASQL := SQL;
1243  Result := ExecutePrepared;
1244 end;
1245 
1246 
1247 {**
1248  Prepares eventual structures for binding input parameters.
1249 }
1250 procedure TZAbstractPreparedStatement.PrepareInParameters;
1251 begin
1252 end;
1253 
1254 {**
1255  Binds the input parameters
1256 }
1257 procedure TZAbstractPreparedStatement.BindInParameters;
1258 var
1259  I : integer;
1260  LogString : String;
1261 begin
1262  LogString := ''; //init for FPC
1263  if InParamCount = 0 then
1264  exit;
1265  { Prepare Log Output}
1266  For I := 0 to InParamCount - 1 do
1267  begin
1268  LogString := LogString + GetInParamLogValue(InParamValues[I])+',';
1269  end;
1270  LogPrepStmtMessage(lcBindPrepStmt, LogString);
1271 end;
1272 
1273 {**
1274  Removes eventual structures for binding input parameters.
1275 }
1276 procedure TZAbstractPreparedStatement.UnPrepareInParameters;
1277 begin
1278 end;
1279 
1280 {**
1281  Sets a new parameter count and initializes the buffers.
1282  @param NewParamCount a new parameters count.
1283 }
1284 procedure TZAbstractPreparedStatement.SetInParamCount(NewParamCount: Integer);
1285 var
1286  I: Integer;
1287 begin
1288  SetLength(FInParamValues, NewParamCount);
1289  SetLength(FInParamTypes, NewParamCount);
1290  SetLength(FInParamDefaultValues, NewParamCount);
1291  for I := FInParamCount to NewParamCount - 1 do
1292  begin
1293  FInParamValues[I] := NullVariant;
1294  FInParamTypes[I] := stUnknown;
1295 
1296  FInParamDefaultValues[I] := '';
1297  end;
1298  FInParamCount := NewParamCount;
1299 end;
1300 
1301 {**
1302  Sets a variant value into specified parameter.
1303  @param ParameterIndex a index of the parameter.
1304  @param SqlType a parameter SQL type.
1305  @paran Value a new parameter value.
1306 }
1307 procedure TZAbstractPreparedStatement.SetInParam(ParameterIndex: Integer;
1308  SQLType: TZSQLType; const Value: TZVariant);
1309 begin
1310  if ParameterIndex >= FInParamCount then
1311  SetInParamCount(ParameterIndex);
1312 
1313  FInParamTypes[ParameterIndex - 1] := SQLType;
1314  FInParamValues[ParameterIndex - 1] := Value;
1315 end;
1316 
1317 {**
1318  Logs a message about prepared statement event with normal result code.
1319  @param Category a category of the message.
1320  @param Protocol a name of the protocol.
1321  @param Msg a description message.
1322 }
1323 procedure TZAbstractPreparedStatement.LogPrepStmtMessage(Category: TZLoggingCategory;
1324  const Msg: string = '');
1325 begin
1326  if msg <> '' then
1327  DriverManager.LogMessage(Category, Connection.GetIZPlainDriver.GetProtocol, Format('Statement %d : %s', [FStatementId, Msg]))
1328  else
1329  DriverManager.LogMessage(Category, Connection.GetIZPlainDriver.GetProtocol, Format('Statement %d', [FStatementId]));
1330 end;
1331 
1332 
1333 function TZAbstractPreparedStatement.GetInParamLogValue(Value: TZVariant): String;
1334 begin
1335  With Value do
1336  case VType of
1337  vtNull : result := '(NULL)';
1338  vtBoolean : If VBoolean then result := '(TRUE)' else result := '(FALSE)';
1339  vtInteger : result := IntToStr(VInteger);
1340  vtFloat : result := FloatToStr(VFloat);
1341  vtString : result := '''' + VString + '''';
1342  vtUnicodeString : result := '''' + VUnicodeString + '''';
1343  vtDateTime : result := DateTimeToStr(VDateTime);
1344  vtPointer : result := '(POINTER)';
1345  vtInterface : result := '(INTERFACE)';
1346  else
1347  result := '(UNKNOWN TYPE)'
1348  end;
1349 end;
1350 
1351 {**
1352  Executes the SQL query in this <code>PreparedStatement</code> object
1353  and returns the result set generated by the query.
1354 
1355  @return a <code>ResultSet</code> object that contains the data produced by the
1356  query; never <code>null</code>
1357 }
1358 {$WARNINGS OFF}
1359 function TZAbstractPreparedStatement.ExecuteQueryPrepared: IZResultSet;
1360 begin
1361  { Logging Execution }
1362  LogPrepStmtMessage(lcExecPrepStmt);
1363  Inc(FExecCount);
1364 end;
1365 {$WARNINGS ON}
1366 {**
1367  Executes the SQL INSERT, UPDATE or DELETE statement
1368  in this <code>PreparedStatement</code> object.
1369  In addition,
1370  SQL statements that return nothing, such as SQL DDL statements,
1371  can be executed.
1372 
1373  @return either the row count for INSERT, UPDATE or DELETE statements;
1374  or 0 for SQL statements that return nothing
1375 }
1376 {$WARNINGS OFF}
1377 function TZAbstractPreparedStatement.ExecuteUpdatePrepared: Integer;
1378 begin
1379  { Logging Execution }
1380  LogPrepStmtMessage(lcExecPrepStmt);
1381  Inc(FExecCount);
1382 end;
1383 {$WARNINGS ON}
1384 {**
1385  Sets the designated parameter the default SQL value.
1386  <P><B>Note:</B> You must specify the default value.
1387 
1388  @param parameterIndex the first parameter is 1, the second is 2, ...
1389  @param Value the default value normally defined in the field's DML SQL statement
1390 }
1391 procedure TZAbstractPreparedStatement.SetDefaultValue(
1392  ParameterIndex: Integer; const Value: string);
1393 begin
1394  if ParameterIndex >= FInParamCount then
1395  SetInParamCount(ParameterIndex);
1396 
1397  FInParamDefaultValues[ParameterIndex - 1] := Value;
1398 end;
1399 
1400 {**
1401  Sets the designated parameter to SQL <code>NULL</code>.
1402  <P><B>Note:</B> You must specify the parameter's SQL type.
1403 
1404  @param parameterIndex the first parameter is 1, the second is 2, ...
1405  @param sqlType the SQL type code defined in <code>java.sql.Types</code>
1406 }
1407 procedure TZAbstractPreparedStatement.SetNull(ParameterIndex: Integer;
1408  SQLType: TZSQLType);
1409 begin
1410  SetInParam(ParameterIndex, SQLType, NullVariant);
1411 end;
1412 
1413 {**
1414  Sets the designated parameter to a Java <code>boolean</code> value.
1415  The driver converts this
1416  to an SQL <code>BIT</code> value when it sends it to the database.
1417 
1418  @param parameterIndex the first parameter is 1, the second is 2, ...
1419  @param x the parameter value
1420 }
1421 procedure TZAbstractPreparedStatement.SetBoolean(ParameterIndex: Integer;
1422  Value: Boolean);
1423 var
1424  Temp: TZVariant;
1425 begin
1426  DefVarManager.SetAsBoolean(Temp, Value);
1427  SetInParam(ParameterIndex, stBoolean, Temp);
1428 end;
1429 
1430 {**
1431  Sets the designated parameter to a Java <code>byte</code> value.
1432  The driver converts this
1433  to an SQL <code>TINYINT</code> value when it sends it to the database.
1434 
1435  @param parameterIndex the first parameter is 1, the second is 2, ...
1436  @param x the parameter value
1437 }
1438 procedure TZAbstractPreparedStatement.SetByte(ParameterIndex: Integer;
1439  Value: Byte);
1440 var
1441  Temp: TZVariant;
1442 begin
1443  DefVarManager.SetAsInteger(Temp, Value);
1444  SetInParam(ParameterIndex, stByte, Temp);
1445 end;
1446 
1447 {**
1448  Sets the designated parameter to a Java <code>short</code> value.
1449  The driver converts this
1450  to an SQL <code>SMALLINT</code> value when it sends it to the database.
1451 
1452  @param parameterIndex the first parameter is 1, the second is 2, ...
1453  @param x the parameter value
1454 }
1455 procedure TZAbstractPreparedStatement.SetShort(ParameterIndex: Integer;
1456  Value: SmallInt);
1457 var
1458  Temp: TZVariant;
1459 begin
1460  DefVarManager.SetAsInteger(Temp, Value);
1461  SetInParam(ParameterIndex, stShort, Temp);
1462 end;
1463 
1464 {**
1465  Sets the designated parameter to a Java <code>int</code> value.
1466  The driver converts this
1467  to an SQL <code>INTEGER</code> value when it sends it to the database.
1468 
1469  @param parameterIndex the first parameter is 1, the second is 2, ...
1470  @param x the parameter value
1471 }
1472 procedure TZAbstractPreparedStatement.SetInt(ParameterIndex: Integer;
1473  Value: Integer);
1474 var
1475  Temp: TZVariant;
1476 begin
1477  DefVarManager.SetAsInteger(Temp, Value);
1478  SetInParam(ParameterIndex, stInteger, Temp);
1479 end;
1480 
1481 {**
1482  Sets the designated parameter to a Java <code>long</code> value.
1483  The driver converts this
1484  to an SQL <code>BIGINT</code> value when it sends it to the database.
1485 
1486  @param parameterIndex the first parameter is 1, the second is 2, ...
1487  @param x the parameter value
1488 }
1489 procedure TZAbstractPreparedStatement.SetLong(ParameterIndex: Integer;
1490  Value: Int64);
1491 var
1492  Temp: TZVariant;
1493 begin
1494  DefVarManager.SetAsInteger(Temp, Value);
1495  SetInParam(ParameterIndex, stLong, Temp);
1496 end;
1497 
1498 {**
1499  Sets the designated parameter to a Java <code>float</code> value.
1500  The driver converts this
1501  to an SQL <code>FLOAT</code> value when it sends it to the database.
1502 
1503  @param parameterIndex the first parameter is 1, the second is 2, ...
1504  @param x the parameter value
1505 }
1506 procedure TZAbstractPreparedStatement.SetFloat(ParameterIndex: Integer;
1507  Value: Single);
1508 var
1509  Temp: TZVariant;
1510 begin
1511  DefVarManager.SetAsFloat(Temp, Value);
1512  SetInParam(ParameterIndex, stFloat, Temp);
1513 end;
1514 
1515 {**
1516  Sets the designated parameter to a Java <code>double</code> value.
1517  The driver converts this
1518  to an SQL <code>DOUBLE</code> value when it sends it to the database.
1519 
1520  @param parameterIndex the first parameter is 1, the second is 2, ...
1521  @param x the parameter value
1522 }
1523 procedure TZAbstractPreparedStatement.SetDouble(ParameterIndex: Integer;
1524  Value: Double);
1525 var
1526  Temp: TZVariant;
1527 begin
1528  DefVarManager.SetAsFloat(Temp, Value);
1529  SetInParam(ParameterIndex, stDouble, Temp);
1530 end;
1531 
1532 {**
1533  Sets the designated parameter to a <code>java.math.BigDecimal</code> value.
1534  The driver converts this to an SQL <code>NUMERIC</code> value when
1535  it sends it to the database.
1536 
1537  @param parameterIndex the first parameter is 1, the second is 2, ...
1538  @param x the parameter value
1539 }
1540 procedure TZAbstractPreparedStatement.SetBigDecimal(
1541  ParameterIndex: Integer; Value: Extended);
1542 var
1543  Temp: TZVariant;
1544 begin
1545  DefVarManager.SetAsFloat(Temp, Value);
1546  SetInParam(ParameterIndex, stBigDecimal, Temp);
1547 end;
1548 
1549 {**
1550  Sets the designated parameter to a Java <code>String</code> value.
1551  The driver converts this
1552  to an SQL <code>VARCHAR</code> or <code>LONGVARCHAR</code> value
1553  (depending on the argument's
1554  size relative to the driver's limits on <code>VARCHAR</code> values)
1555  when it sends it to the database.
1556 
1557  @param parameterIndex the first parameter is 1, the second is 2, ...
1558  @param x the parameter value
1559 }
1560 procedure TZAbstractPreparedStatement.SetPChar(ParameterIndex: Integer;
1561  Value: PChar);
1562 var
1563  Temp: TZVariant;
1564 begin
1565  DefVarManager.SetAsString(Temp, Value);
1566  SetInParam(ParameterIndex, stString, Temp);
1567 end;
1568 
1569 {**
1570  Sets the designated parameter to a Java <code>String</code> value.
1571  The driver converts this
1572  to an SQL <code>VARCHAR</code> or <code>LONGVARCHAR</code> value
1573  (depending on the argument's
1574  size relative to the driver's limits on <code>VARCHAR</code> values)
1575  when it sends it to the database.
1576 
1577  @param parameterIndex the first parameter is 1, the second is 2, ...
1578  @param x the parameter value
1579 }
1580 procedure TZAbstractPreparedStatement.SetString(ParameterIndex: Integer;
1581  const Value: String);
1582 var
1583  Temp: TZVariant;
1584 begin
1585  DefVarManager.SetAsString(Temp, Value);
1586  SetInParam(ParameterIndex, stString, Temp);
1587 end;
1588 
1589 {**
1590  Sets the designated parameter to a Object Pascal <code>WideString</code>
1591  value. The driver converts this
1592  to an SQL <code>VARCHAR</code> or <code>LONGVARCHAR</code> value
1593  (depending on the argument's
1594  size relative to the driver's limits on <code>VARCHAR</code> values)
1595  when it sends it to the database.
1596 
1597  @param parameterIndex the first parameter is 1, the second is 2, ...
1598  @param x the parameter value
1599 }
1600 
1601 procedure TZAbstractPreparedStatement.SetUnicodeString(ParameterIndex: Integer;
1602  const Value: ZWideString);
1603 var
1604  Temp: TZVariant;
1605 begin
1606  DefVarManager.SetAsUnicodeString(Temp, Value);
1607  SetInParam(ParameterIndex, stUnicodeString, Temp);
1608 end;
1609 
1610 {**
1611  Sets the designated parameter to a Java array of bytes. The driver converts
1612  this to an SQL <code>VARBINARY</code> or <code>LONGVARBINARY</code>
1613  (depending on the argument's size relative to the driver's limits on
1614  <code>VARBINARY</code> values) when it sends it to the database.
1615 
1616  @param parameterIndex the first parameter is 1, the second is 2, ...
1617  @param x the parameter value
1618 }
1619 procedure TZAbstractPreparedStatement.SetBytes(ParameterIndex: Integer;
1620  const Value: TByteDynArray);
1621 var
1622  Temp: TZVariant;
1623 begin
1624  DefVarManager.SetAsBytes(Temp, Value);
1625  SetInParam(ParameterIndex, stBytes, Temp);
1626 end;
1627 
1628 {**
1629  Sets the designated parameter to a <code<java.sql.Date</code> value.
1630  The driver converts this to an SQL <code>DATE</code>
1631  value when it sends it to the database.
1632 
1633  @param parameterIndex the first parameter is 1, the second is 2, ...
1634  @param x the parameter value
1635 }
1636 procedure TZAbstractPreparedStatement.SetDate(ParameterIndex: Integer;
1637  Value: TDateTime);
1638 var
1639  Temp: TZVariant;
1640 begin
1641  DefVarManager.SetAsDateTime(Temp, Value);
1642  SetInParam(ParameterIndex, stDate, Temp);
1643 end;
1644 
1645 {**
1646  Sets the designated parameter to a <code>java.sql.Time</code> value.
1647  The driver converts this to an SQL <code>TIME</code> value
1648  when it sends it to the database.
1649 
1650  @param parameterIndex the first parameter is 1, the second is 2, ...
1651  @param x the parameter value
1652 }
1653 procedure TZAbstractPreparedStatement.SetTime(ParameterIndex: Integer;
1654  Value: TDateTime);
1655 var
1656  Temp: TZVariant;
1657 begin
1658  DefVarManager.SetAsDateTime(Temp, Value);
1659  SetInParam(ParameterIndex, stTime, Temp);
1660 end;
1661 
1662 {**
1663  Sets the designated parameter to a <code>java.sql.Timestamp</code> value.
1664  The driver converts this to an SQL <code>TIMESTAMP</code> value
1665  when it sends it to the database.
1666 
1667  @param parameterIndex the first parameter is 1, the second is 2, ...
1668  @param x the parameter value
1669 }
1670 procedure TZAbstractPreparedStatement.SetTimestamp(ParameterIndex: Integer;
1671  Value: TDateTime);
1672 var
1673  Temp: TZVariant;
1674 begin
1675  DefVarManager.SetAsDateTime(Temp, Value);
1676  SetInParam(ParameterIndex, stTimestamp, Temp);
1677 end;
1678 
1679 {**
1680  Sets the designated parameter to the given input stream, which will have
1681  the specified number of bytes.
1682  When a very large ASCII value is input to a <code>LONGVARCHAR</code>
1683  parameter, it may be more practical to send it via a
1684  <code>java.io.InputStream</code>. Data will be read from the stream
1685  as needed until end-of-file is reached. The JDBC driver will
1686  do any necessary conversion from ASCII to the database char format.
1687 
1688  <P><B>Note:</B> This stream object can either be a standard
1689  Java stream object or your own subclass that implements the
1690  standard interface.
1691 
1692  @param parameterIndex the first parameter is 1, the second is 2, ...
1693  @param x the Java input stream that contains the ASCII parameter value
1694  @param length the number of bytes in the stream
1695 }
1696 procedure TZAbstractPreparedStatement.SetAsciiStream(
1697  ParameterIndex: Integer; Value: TStream);
1698 begin
1699  SetBlob(ParameterIndex, stAsciiStream, TZAbstractBlob.CreateWithStream(Value, GetConnection));
1700 end;
1701 
1702 {**
1703  Sets the designated parameter to the given input stream, which will have
1704  the specified number of bytes.
1705  When a very large UNICODE value is input to a <code>LONGVARCHAR</code>
1706  parameter, it may be more practical to send it via a
1707  <code>java.io.InputStream</code> object. The data will be read from the stream
1708  as needed until end-of-file is reached. The JDBC driver will
1709  do any necessary conversion from UNICODE to the database char format.
1710  The byte format of the Unicode stream must be Java UTF-8, as
1711  defined in the Java Virtual Machine Specification.
1712 
1713  <P><B>Note:</B> This stream object can either be a standard
1714  Java stream object or your own subclass that implements the
1715  standard interface.
1716 
1717  @param parameterIndex the first parameter is 1, the second is 2, ...
1718  @param x the java input stream which contains the UNICODE parameter value
1719 }
1720 procedure TZAbstractPreparedStatement.SetUnicodeStream(
1721  ParameterIndex: Integer; Value: TStream);
1722 begin
1723  SetBlob(ParameterIndex, stUnicodeStream, TZAbstractBlob.CreateWithStream(Value, GetConnection));
1724 end;
1725 
1726 {**
1727  Sets the designated parameter to the given input stream, which will have
1728  the specified number of bytes.
1729  When a very large binary value is input to a <code>LONGVARBINARY</code>
1730  parameter, it may be more practical to send it via a
1731  <code>java.io.InputStream</code> object. The data will be read from the stream
1732  as needed until end-of-file is reached.
1733 
1734  <P><B>Note:</B> This stream object can either be a standard
1735  Java stream object or your own subclass that implements the
1736  standard interface.
1737 
1738  @param parameterIndex the first parameter is 1, the second is 2, ...
1739  @param x the java input stream which contains the binary parameter value
1740 }
1741 procedure TZAbstractPreparedStatement.SetBinaryStream(
1742  ParameterIndex: Integer; Value: TStream);
1743 begin
1744  SetBlob(ParameterIndex, stBinaryStream, TZAbstractBlob.CreateWithStream(Value, GetConnection));
1745 end;
1746 
1747 {**
1748  Sets a blob object for the specified parameter.
1749  @param ParameterIndex the first parameter is 1, the second is 2, ...
1750  @param Value the java blob object.
1751 }
1752 procedure TZAbstractPreparedStatement.SetBlob(ParameterIndex: Integer;
1753  SQLType: TZSQLType; Value: IZBlob);
1754 var
1755  Temp: TZVariant;
1756 begin
1757  if not (SQLType in [stAsciiStream, stUnicodeStream, stBinaryStream]) then
1758  raise EZSQLException.Create(SWrongTypeForBlobParameter);
1759  DefVarManager.SetAsInterface(Temp, Value);
1760  SetInParam(ParameterIndex, SQLType, Temp);
1761 end;
1762 
1763 {**
1764  Sets a variant value for the specified parameter.
1765  @param ParameterIndex the first parameter is 1, the second is 2, ...
1766  @param Value the variant value.
1767 }
1768 procedure TZAbstractPreparedStatement.SetValue(ParameterIndex: Integer;
1769  const Value: TZVariant);
1770 var
1771  SQLType: TZSQLType;
1772 begin
1773  case Value.VType of
1774  vtBoolean: SQLType := stBoolean;
1775  vtInteger: SQLType := stLong;
1776  vtFloat: SQLType := stBigDecimal;
1777  vtUnicodeString: SQLType := stUnicodeString;
1778  vtDateTime: SQLType := stTimestamp;
1779  else
1780  SQLType := stString;
1781  end;
1782  SetInParam(ParameterIndex, SQLType, Value);
1783 end;
1784 
1785 {**
1786  Clears the current parameter values immediately.
1787  <P>In general, parameter values remain in force for repeated use of a
1788  statement. Setting a parameter value automatically clears its
1789  previous value. However, in some cases it is useful to immediately
1790  release the resources used by the current parameter values; this can
1791  be done by calling the method <code>clearParameters</code>.
1792 }
1793 procedure TZAbstractPreparedStatement.ClearParameters;
1794 var
1795  I: Integer;
1796 begin
1797  for I := 1 to FInParamCount do
1798  begin
1799  SetInParam(I, stUnknown, NullVariant);
1800  SetDefaultValue(I, '');
1801  end;
1802  SetInParamCount(0);
1803 end;
1804 
1805 {**
1806  Executes any kind of SQL statement.
1807  Some prepared statements return multiple results; the <code>execute</code>
1808  method handles these complex statements as well as the simpler
1809  form of statements handled by the methods <code>executeQuery</code>
1810  and <code>executeUpdate</code>.
1811  @see Statement#execute
1812 }
1813 {$WARNINGS OFF}
1814 function TZAbstractPreparedStatement.ExecutePrepared: Boolean;
1815 begin
1816  { Logging Execution }
1817  LogPrepStmtMessage(lcExecPrepStmt, '');
1818  Inc(FExecCount);
1819 end;
1820 {$WARNINGS ON}
1821 
1822 function TZAbstractPreparedStatement.GetSQL: String;
1823 begin
1824  Result := FSQL;
1825 end;
1826 
1827 procedure TZAbstractPreparedStatement.Prepare;
1828 begin
1829  PrepareInParameters;
1830  FPrepared := True;
1831 end;
1832 
1833 procedure TZAbstractPreparedStatement.Unprepare;
1834 begin
1835  UnPrepareInParameters;
1836  FPrepared := False;
1837 end;
1838 
1839 function TZAbstractPreparedStatement.IsPrepared: Boolean;
1840 begin
1841  Result := FPrepared;
1842 end;
1843 
1844 {**
1845  Adds a set of parameters to this <code>PreparedStatement</code>
1846  object's batch of commands.
1847  @see Statement#addBatch
1848 }
1849 procedure TZAbstractPreparedStatement.AddBatchPrepared;
1850 begin
1851 end;
1852 
1853 {**
1854  Gets the number, types and properties of a <code>ResultSet</code>
1855  object's columns.
1856  @return the description of a <code>ResultSet</code> object's columns
1857 }
1858 function TZAbstractPreparedStatement.GetMetaData: IZResultSetMetaData;
1859 begin
1860  Result := nil;
1861  RaiseUnsupportedException;
1862 end;
1863 
1864 { TZAbstractCallableStatement }
1865 
1866 {**
1867  Constructs this object and assigns main properties.
1868  @param Connection a database connection object.
1869  @param Sql a prepared Sql statement.
1870  @param Info a statement parameters.
1871 }
1872 constructor TZAbstractCallableStatement.Create(Connection: IZConnection;
1873  SQL: string; Info: TStrings);
1874 begin
1875  inherited Create(Connection, SQL, Info);
1876  FOutParamCount := 0;
1877  SetOutParamCount(0);
1878  FProcSql := ''; //Init -> FPC
1879  FLastWasNull := True;
1880  FResultSets := TZCollection.Create;
1881  FIsFunction := False;
1882 end;
1883 
1884 {**
1885  Close and release a list of returned resultsets.
1886 }
1887 procedure TZAbstractCallableStatement.ClearResultSets;
1888 var
1889  I: Integer;
1890  RS: IZResultSet;
1891 begin
1892  for i := 0 to FResultSets.Count -1 do
1893  if Supports(FResultSets[i], IZResultSet, RS) then //possible IZUpdateCount e.g. DBLib, ASA
1894  RS.Close;
1895  FResultSets.Clear;
1896  LastResultSet := nil;
1897 end;
1898 
1899 {**
1900  Function remove stUnknown and ptResult, ptOutput paramters from
1901  InParamTypes and InParamValues because the out-params are added after
1902  fetching.
1903 }
1904 procedure TZAbstractCallableStatement.TrimInParameters;
1905 var
1906  I: integer;
1907  ParamValues: TZVariantDynArray;
1908  ParamTypes: TZSQLTypeArray;
1909  ParamCount: Integer;
1910 begin
1911  ParamCount := 0;
1912  SetLength(ParamValues, InParamCount);
1913  SetLength(ParamTypes, InParamCount);
1914 
1915  {Need for dbc access, where no metadata is used to register the ParamTypes}
1916  if Length(FDBParamTypes) < InParamCount then
1917  SetLength(FDBParamTypes, InParamCount);
1918  {end for dbc access}
1919 
1920  for I := 0 to High(InParamTypes) do
1921  begin
1922  if ( InParamTypes[I] = ZDbcIntfs.stUnknown ) then
1923  Continue;
1924  if (FDBParamTypes[i] in [2, 4]) then //[ptResult, ptOutput]
1925  continue; //EgonHugeist: Ignore known OutParams! else StatmentInparamCount <> expect ProcedureParamCount
1926  ParamTypes[ParamCount] := InParamTypes[I];
1927  ParamValues[ParamCount] := InParamValues[I];
1928  Inc(ParamCount);
1929  end;
1930  if ParamCount = InParamCount then
1931  Exit;
1932  InParamTypes := ParamTypes;
1933  InParamValues := ParamValues;
1934  SetInParamCount(ParamCount); //AVZ
1935 end;
1936 
1937 {**
1938  Sets a new parameter count and initializes the buffers.
1939  @param NewParamCount a new parameters count.
1940 }
1941 procedure TZAbstractCallableStatement.SetOutParamCount(NewParamCount: Integer);
1942 var
1943  I: Integer;
1944 begin
1945  SetLength(FOutParamValues, NewParamCount);
1946  SetLength(FOutParamTypes, NewParamCount);
1947  for I := FOutParamCount to NewParamCount - 1 do
1948  begin
1949  FOutParamValues[I] := NullVariant;
1950  FOutParamTypes[I] := stUnknown;
1951  end;
1952  FOutParamCount := NewParamCount;
1953 end;
1954 
1955 {**
1956  Clears the current parameter values immediately.
1957  <P>In general, parameter values remain in force for repeated use of a
1958  statement. Setting a parameter value automatically clears its
1959  previous value. However, in some cases it is useful to immediately
1960  release the resources used by the current parameter values; this can
1961  be done by calling the method <code>clearParameters</code>.
1962 }
1963 procedure TZAbstractCallableStatement.ClearParameters;
1964 var
1965  I: Integer;
1966 begin
1967  inherited;
1968  for I := 1 to FOutParamCount do
1969  begin
1970  OutParamValues[I - 1] := NullVariant;
1971  OutParamTypes[I - 1] := stUnknown;
1972  end;
1973  SetOutParamCount(0);
1974 end;
1975 
1976 {**
1977  Releases this <code>Statement</code> object's database
1978  and JDBC resources immediately instead of waiting for
1979  this to happen when it is automatically closed.
1980  It is generally good practice to release resources as soon as
1981  you are finished with them to avoid tying up database
1982  resources.
1983  <P><B>Note:</B> A <code>Statement</code> object is automatically closed when it is
1984  garbage collected. When a <code>Statement</code> object is closed, its current
1985  <code>ResultSet</code> object, if one exists, is also closed.
1986 }
1987 procedure TZAbstractCallableStatement.Close;
1988 begin
1989  ClearResultSets;
1990  inherited Close;
1991 end;
1992 
1993 
1994 {**
1995  Do we call a function or a procedure?
1996  @result Returns <code>True</code> if we call a function
1997 }
1998 function TZAbstractCallableStatement.IsFunction: Boolean;
1999 begin
2000  Result := FIsFunction;
2001 end;
2002 
2003 {**
2004  Do we have ptInputOutput or ptOutput paramets in a function or procedure?
2005  @result Returns <code>True</code> if ptInputOutput or ptOutput is available
2006 }
2007 function TZAbstractCallableStatement.HasOutParameter: Boolean;
2008 begin
2009  Result := FHasOutParameter;
2010 end;
2011 
2012 {**
2013  Are more resultsets retrieved?
2014  @result Returns <code>True</code> if more resultsets are retrieved
2015 }
2016 function TZAbstractCallableStatement.HasMoreResultSets: Boolean;
2017 begin
2018  Result := False;
2019 end;
2020 
2021 {**
2022  Get the first resultset..
2023  @result <code>IZResultSet</code> if supported
2024 }
2025 function TZAbstractCallableStatement.GetFirstResultSet: IZResultSet;
2026 begin
2027  Result := nil;
2028 end;
2029 
2030 {**
2031  Get the previous resultset..
2032  @result <code>IZResultSet</code> if supported
2033 }
2034 function TZAbstractCallableStatement.GetPreviousResultSet: IZResultSet;
2035 begin
2036  Result := nil;
2037 end;
2038 
2039 {**
2040  Get the next resultset..
2041  @result <code>IZResultSet</code> if supported
2042 }
2043 function TZAbstractCallableStatement.GetNextResultSet: IZResultSet;
2044 begin
2045  Result := nil;
2046 end;
2047 
2048 {**
2049  Get the last resultset..
2050  @result <code>IZResultSet</code> if supported
2051 }
2052 function TZAbstractCallableStatement.GetLastResultSet: IZResultSet;
2053 begin
2054  Result := nil;
2055 end;
2056 
2057 {**
2058  First ResultSet?
2059  @result <code>True</code> if first ResultSet
2060 }
2061 function TZAbstractCallableStatement.BOR: Boolean;
2062 begin
2063  Result := True;
2064 end;
2065 
2066 {**
2067  Last ResultSet?
2068  @result <code>True</code> if Last ResultSet
2069 }
2070 function TZAbstractCallableStatement.EOR: Boolean;
2071 begin
2072  Result := True;
2073 end;
2074 
2075 {**
2076  Retrieves a ResultSet by his index.
2077  @param Index the index of the Resultset
2078  @result <code>IZResultSet</code> of the Index or nil.
2079 }
2080 function TZAbstractCallableStatement.GetResultSetByIndex(const Index: Integer): IZResultSet;
2081 begin
2082  Result := nil;
2083 end;
2084 
2085 {**
2086  Returns the Count of retrived ResultSets.
2087  @result <code>Integer</code> Count
2088 }
2089 function TZAbstractCallableStatement.GetResultSetCount: Integer;
2090 begin
2091  Result := 0;
2092 end;
2093 
2094 {**
2095  Registers the OUT parameter in ordinal position
2096  <code>parameterIndex</code> to the JDBC type
2097  <code>sqlType</code>. All OUT parameters must be registered
2098  before a stored procedure is executed.
2099  <p>
2100  The JDBC type specified by <code>sqlType</code> for an OUT
2101  parameter determines the Java type that must be used
2102  in the <code>get</code> method to read the value of that parameter.
2103  <p>
2104  If the JDBC type expected to be returned to this output parameter
2105  is specific to this particular database, <code>sqlType</code>
2106  should be <code>java.sql.Types.OTHER</code>. The method retrieves the value.
2107  @param parameterIndex the first parameter is 1, the second is 2,
2108  and so on
2109  @param sqlType the JDBC type code defined by <code>java.sql.Types</code>.
2110  If the parameter is of JDBC type <code>NUMERIC</code>
2111  or <code>DECIMAL</code>, the version of
2112  <code>registerOutParameter</code> that accepts a scale value should be used.
2113 }
2114 procedure TZAbstractCallableStatement.RegisterOutParameter(ParameterIndex,
2115  SQLType: Integer);
2116 begin
2117  SetOutParamCount(ParameterIndex);
2118  OutParamTypes[ParameterIndex - 1] := TZSQLType(SQLType);
2119 end;
2120 
2121 procedure TZAbstractCallableStatement.RegisterParamType(ParameterIndex,
2122  ParamType: Integer);
2123 begin
2124  if (Length(FDBParamTypes) < ParameterIndex) then
2125  SetLength(FDBParamTypes, ParameterIndex);
2126 
2127  FDBParamTypes[ParameterIndex - 1] := ParamType;
2128  if not FIsFunction then FIsFunction := ParamType = 4; //ptResult
2129  if not FHasOutParameter then FHasOutParameter := ParamType in [2,3]; //ptOutput, ptInputOutput
2130 end;
2131 
2132 {**
2133  Gets a output parameter value by it's index.
2134  @param ParameterIndex a parameter index.
2135  @returns a parameter value.
2136 }
2137 function TZAbstractCallableStatement.GetOutParam(
2138  ParameterIndex: Integer): TZVariant;
2139 begin
2140  if Assigned(OutParamValues) then
2141  begin
2142  Result := OutParamValues[ParameterIndex - 1];
2143  FLastWasNull := DefVarManager.IsNull(Result);
2144  end
2145  else
2146  begin
2147  Result:=NullVariant;
2148  FLastWasNull:=True;
2149  end;
2150 end;
2151 
2152 procedure TZAbstractCallableStatement.SetProcSQL(const Value: String);
2153 begin
2154  FProcSql := Value;
2155 end;
2156 
2157 {**
2158  Indicates whether or not the last OUT parameter read had the value of
2159  SQL <code>NULL</code>. Note that this method should be called only after
2160  calling a <code>getXXX</code> method; otherwise, there is no value to use in
2161  determining whether it is <code>null</code> or not.
2162  @return <code>true</code> if the last parameter read was SQL
2163  <code>NULL</code>; <code>false</code> otherwise
2164 }
2165 function TZAbstractCallableStatement.WasNull: Boolean;
2166 begin
2167  Result := FLastWasNull;
2168 end;
2169 
2170 {**
2171  Indicates whether or not the specified OUT parameter read had the value of
2172  SQL <code>NULL</code>.
2173  @return <code>true</code> if the parameter read was SQL
2174  <code>NULL</code>; <code>false</code> otherwise
2175 }
2176 function TZAbstractCallableStatement.IsNull(ParameterIndex: Integer): Boolean;
2177 begin
2178  GetOutParam(ParameterIndex);
2179  Result := FLastWasNull;
2180 end;
2181 
2182 {**
2183  Retrieves the value of a JDBC <code>CHAR</code>, <code>VARCHAR</code>,
2184  or <code>LONGVARCHAR</code> parameter as a <code>String</code> in
2185  the Java programming language.
2186  <p>
2187  For the fixed-length type JDBC <code>CHAR</code>,
2188  the <code>String</code> object
2189  returned has exactly the same value the JDBC
2190  <code>CHAR</code> value had in the
2191  database, including any padding added by the database.
2192  @param parameterIndex the first parameter is 1, the second is 2,
2193  and so on
2194  @return the parameter value. If the value is SQL <code>NULL</code>, the result
2195  is <code>null</code>.
2196  @exception SQLException if a database access error occurs
2197 }
2198 function TZAbstractCallableStatement.GetPChar(ParameterIndex: Integer): PChar;
2199 begin
2200  FTemp := GetString(ParameterIndex);
2201  Result := PChar(FTemp);
2202 end;
2203 
2204 {**
2205  Retrieves the value of a JDBC <code>CHAR</code>, <code>VARCHAR</code>,
2206  or <code>LONGVARCHAR</code> parameter as a <code>String</code> in
2207  the Java programming language.
2208  <p>
2209  For the fixed-length type JDBC <code>CHAR</code>,
2210  the <code>String</code> object
2211  returned has exactly the same value the JDBC
2212  <code>CHAR</code> value had in the
2213  database, including any padding added by the database.
2214  @param parameterIndex the first parameter is 1, the second is 2,
2215  and so on
2216  @return the parameter value. If the value is SQL <code>NULL</code>, the result
2217  is <code>null</code>.
2218  @exception SQLException if a database access error occurs
2219 }
2220 function TZAbstractCallableStatement.GetString(ParameterIndex: Integer): String;
2221 begin
2222  Result := SoftVarManager.GetAsString(GetOutParam(ParameterIndex));
2223 end;
2224 
2225 {**
2226  Retrieves the value of a JDBC <code>CHAR</code>, <code>VARCHAR</code>,
2227  or <code>LONGVARCHAR</code> parameter as a <code>String</code> in
2228  the Java programming language.
2229  <p>
2230  For the fixed-length type JDBC <code>CHAR</code>,
2231  the <code>WideString</code> object
2232  returned has exactly the same value the JDBC
2233  <code>CHAR</code> value had in the
2234  database, including any padding added by the database.
2235  @param parameterIndex the first parameter is 1, the second is 2,
2236  and so on
2237  @return the parameter value. If the value is SQL <code>NULL</code>, the result
2238  is <code>null</code>.
2239  @exception SQLException if a database access error occurs
2240 }
2241 function TZAbstractCallableStatement.GetUnicodeString(
2242  ParameterIndex: Integer): WideString;
2243 begin
2244  Result := SoftVarManager.GetAsUnicodeString(GetOutParam(ParameterIndex));
2245 end;
2246 
2247 {**
2248  Gets the value of a JDBC <code>BIT</code> parameter as a <code>boolean</code>
2249  in the Java programming language.
2250  @param parameterIndex the first parameter is 1, the second is 2,
2251  and so on
2252  @return the parameter value. If the value is SQL <code>NULL</code>, the result
2253  is <code>false</code>.
2254 }
2255 function TZAbstractCallableStatement.GetBoolean(ParameterIndex: Integer): Boolean;
2256 begin
2257  Result := SoftvarManager.GetAsBoolean(GetOutParam(ParameterIndex));
2258 end;
2259 
2260 {**
2261  Gets the value of a JDBC <code>TINYINT</code> parameter as a <code>byte</code>
2262  in the Java programming language.
2263  @param parameterIndex the first parameter is 1, the second is 2,
2264  and so on
2265  @return the parameter value. If the value is SQL <code>NULL</code>, the result
2266  is 0.
2267 }
2268 function TZAbstractCallableStatement.GetByte(ParameterIndex: Integer): Byte;
2269 begin
2270  Result := Byte(SoftVarManager.GetAsInteger(GetOutParam(ParameterIndex)));
2271 end;
2272 
2273 {**
2274  Gets the value of a JDBC <code>SMALLINT</code> parameter as a <code>short</code>
2275  in the Java programming language.
2276  @param parameterIndex the first parameter is 1, the second is 2,
2277  and so on
2278  @return the parameter value. If the value is SQL <code>NULL</code>, the result
2279  is 0.
2280 }
2281 function TZAbstractCallableStatement.GetShort(ParameterIndex: Integer): SmallInt;
2282 begin
2283  Result := SmallInt(SoftVarManager.GetAsInteger(GetOutParam(ParameterIndex)));
2284 end;
2285 
2286 {**
2287  Gets the value of a JDBC <code>INTEGER</code> parameter as an <code>int</code>
2288  in the Java programming language.
2289  @param parameterIndex the first parameter is 1, the second is 2,
2290  and so on
2291  @return the parameter value. If the value is SQL <code>NULL</code>, the result
2292  is 0.
2293 }
2294 function TZAbstractCallableStatement.GetInt(ParameterIndex: Integer): Integer;
2295 begin
2296  Result := Integer(SoftVarManager.GetAsInteger(GetOutParam(ParameterIndex)));
2297 end;
2298 
2299 {**
2300  Gets the value of a JDBC <code>BIGINT</code> parameter as a <code>long</code>
2301  in the Java programming language.
2302  @param parameterIndex the first parameter is 1, the second is 2,
2303  and so on
2304  @return the parameter value. If the value is SQL <code>NULL</code>, the result
2305  is 0.
2306 }
2307 function TZAbstractCallableStatement.GetLong(ParameterIndex: Integer): Int64;
2308 begin
2309  Result := SoftVarManager.GetAsInteger(GetOutParam(ParameterIndex));
2310 end;
2311 
2312 {**
2313  Gets the value of a JDBC <code>FLOAT</code> parameter as a <code>float</code>
2314  in the Java programming language.
2315  @param parameterIndex the first parameter is 1, the second is 2,
2316  and so on
2317  @return the parameter value. If the value is SQL <code>NULL</code>, the result
2318  is 0.
2319 }
2320 function TZAbstractCallableStatement.GetFloat(ParameterIndex: Integer): Single;
2321 begin
2322  Result := SoftVarManager.GetAsFloat(GetOutParam(ParameterIndex));
2323 end;
2324 
2325 {**
2326  Gets the value of a JDBC <code>DOUBLE</code> parameter as a <code>double</code>
2327  in the Java programming language.
2328  @param parameterIndex the first parameter is 1, the second is 2,
2329  and so on
2330  @return the parameter value. If the value is SQL <code>NULL</code>, the result
2331  is 0.
2332 }
2333 function TZAbstractCallableStatement.GetDouble(ParameterIndex: Integer): Double;
2334 begin
2335  Result := SoftVarManager.GetAsFloat(GetOutParam(ParameterIndex));
2336 end;
2337 
2338 {**
2339  Gets the value of a JDBC <code>NUMERIC</code> parameter as a
2340  <code>java.math.BigDecimal</code> object with scale digits to
2341  the right of the decimal point.
2342  @param parameterIndex the first parameter is 1, the second is 2,
2343  and so on
2344  @return the parameter value. If the value is SQL <code>NULL</code>, the result is
2345  <code>null</code>.
2346 }
2347 function TZAbstractCallableStatement.GetBigDecimal(ParameterIndex: Integer):
2348  Extended;
2349 begin
2350  Result := SoftVarManager.GetAsFloat(GetOutParam(ParameterIndex));
2351 end;
2352 
2353 {**
2354  Gets the value of a JDBC <code>BINARY</code> or <code>VARBINARY</code>
2355  parameter as an array of <code>byte</code> values in the Java
2356  programming language.
2357  @param parameterIndex the first parameter is 1, the second is 2,
2358  and so on
2359  @return the parameter value. If the value is SQL <code>NULL</code>, the result is
2360  <code>null</code>.
2361 }
2362 function TZAbstractCallableStatement.GetBytes(ParameterIndex: Integer):
2363  TByteDynArray;
2364 begin
2365  Result := SoftVarManager.GetAsBytes(GetOutParam(ParameterIndex));
2366 end;
2367 
2368 {**
2369  Gets the value of a JDBC <code>DATE</code> parameter as a
2370  <code>java.sql.Date</code> object.
2371  @param parameterIndex the first parameter is 1, the second is 2,
2372  and so on
2373  @return the parameter value. If the value is SQL <code>NULL</code>, the result
2374  is <code>null</code>.
2375 }
2376 function TZAbstractCallableStatement.GetDate(ParameterIndex: Integer):
2377  TDateTime;
2378 begin
2379  Result := SoftVarManager.GetAsDateTime(GetOutParam(ParameterIndex));
2380 end;
2381 
2382 {**
2383  Get the value of a JDBC <code>TIME</code> parameter as a
2384  <code>java.sql.Time</code> object.
2385  @param parameterIndex the first parameter is 1, the second is 2,
2386  and so on
2387  @return the parameter value. If the value is SQL <code>NULL</code>, the result
2388  is <code>null</code>.
2389 }
2390 function TZAbstractCallableStatement.GetTime(ParameterIndex: Integer):
2391  TDateTime;
2392 begin
2393  Result := SoftVarManager.GetAsDateTime(GetOutParam(ParameterIndex));
2394 end;
2395 
2396 {**
2397  Gets the value of a JDBC <code>TIMESTAMP</code> parameter as a
2398  <code>java.sql.Timestamp</code> object.
2399  @param parameterIndex the first parameter is 1, the second is 2,
2400  and so on
2401  @return the parameter value. If the value is SQL <code>NULL</code>, the result
2402  is <code>null</code>.
2403 }
2404 function TZAbstractCallableStatement.GetTimestamp(ParameterIndex: Integer):
2405  TDateTime;
2406 begin
2407  Result := SoftVarManager.GetAsDateTime(GetOutParam(ParameterIndex));
2408 end;
2409 
2410 {**
2411  Gets the value of a JDBC <code>Variant</code> parameter value.
2412  @param parameterIndex the first parameter is 1, the second is 2,
2413  and so on
2414  @return the parameter value. If the value is SQL <code>NULL</code>,
2415  the result is <code>null</code>.
2416 }
2417 function TZAbstractCallableStatement.GetValue(ParameterIndex: Integer):
2418  TZVariant;
2419 begin
2420  Result := GetOutParam(ParameterIndex);
2421 end;
2422 
2423 { TZAbstractPreparedCallableStatement }
2424 
2425 procedure TZAbstractPreparedCallableStatement.SetProcSQL(const Value: String);
2426 begin
2427  if Value <> ProcSQL then Unprepare;
2428  inherited SetProcSQL(Value);
2429  if (Value <> '') and ( not Prepared ) then Prepare;
2430 end;
2431 
2432 {**
2433  Executes an SQL statement that returns a single <code>ResultSet</code> object.
2434  @param sql typically this is a static SQL <code>SELECT</code> statement
2435  @return a <code>ResultSet</code> object that contains the data produced by the
2436  given query; never <code>null</code>
2437 }
2438 function TZAbstractPreparedCallableStatement.ExecuteQuery(const SQL: ZWideString): IZResultSet;
2439 begin
2440  if (SQL <> Self.WSQL) and (Prepared) then Unprepare;
2441  WSQL := SQL;
2442  Result := ExecuteQueryPrepared;
2443 end;
2444 
2445 function TZAbstractPreparedCallableStatement.ExecuteQuery(const SQL: RawByteString): IZResultSet;
2446 begin
2447  if (SQL <> Self.ASQL) and (Prepared) then Unprepare;
2448  Self.ASQL := SQL;
2449  Result := ExecuteQueryPrepared;
2450 end;
2451 
2452 {**
2453  Executes an SQL <code>INSERT</code>, <code>UPDATE</code> or
2454  <code>DELETE</code> statement. In addition,
2455  SQL statements that return nothing, such as SQL DDL statements,
2456  can be executed.
2457 
2458  @param sql an SQL <code>INSERT</code>, <code>UPDATE</code> or
2459  <code>DELETE</code> statement or an SQL statement that returns nothing
2460  @return either the row count for <code>INSERT</code>, <code>UPDATE</code>
2461  or <code>DELETE</code> statements, or 0 for SQL statements that return nothing
2462 }
2463 function TZAbstractPreparedCallableStatement.ExecuteUpdate(const SQL: ZWideString): Integer;
2464 begin
2465  if (SQL <> WSQL) and (Prepared) then Unprepare;
2466  WSQL := SQL;
2467  Result := ExecuteUpdatePrepared;
2468 end;
2469 
2470 function TZAbstractPreparedCallableStatement.ExecuteUpdate(const SQL: RawByteString): Integer;
2471 begin
2472  if (SQL <> ASQL) and (Prepared) then Unprepare;
2473  ASQL := SQL;
2474  Result := ExecuteUpdatePrepared;
2475 end;
2476 
2477 {**
2478  Executes an SQL statement that may return multiple results.
2479  Under some (uncommon) situations a single SQL statement may return
2480  multiple result sets and/or update counts. Normally you can ignore
2481  this unless you are (1) executing a stored procedure that you know may
2482  return multiple results or (2) you are dynamically executing an
2483  unknown SQL string. The methods <code>execute</code>,
2484  <code>getMoreResults</code>, <code>getResultSet</code>,
2485  and <code>getUpdateCount</code> let you navigate through multiple results.
2486 
2487  The <code>execute</code> method executes an SQL statement and indicates the
2488  form of the first result. You can then use the methods
2489  <code>getResultSet</code> or <code>getUpdateCount</code>
2490  to retrieve the result, and <code>getMoreResults</code> to
2491  move to any subsequent result(s).
2492 
2493  @param sql any SQL statement
2494  @return <code>true</code> if the next result is a <code>ResultSet</code> object;
2495  <code>false</code> if it is an update count or there are no more results
2496  @see #getResultSet
2497  @see #getUpdateCount
2498  @see #getMoreResults
2499 }
2500 
2501 function TZAbstractPreparedCallableStatement.Execute(const SQL: ZWideString): Boolean;
2502 begin
2503  if (SQL <> WSQL) and (Prepared) then Unprepare;
2504  WSQL := SQL;
2505  Result := ExecutePrepared;
2506 end;
2507 
2508 function TZAbstractPreparedCallableStatement.Execute(const SQL: RawByteString): Boolean;
2509 begin
2510  if (SQL <> ASQL) and (Prepared) then Unprepare;
2511  ASQL := SQL;
2512  Result := ExecutePrepared;
2513 end;
2514 
2515 { TZEmulatedPreparedStatement }
2516 
2517 {**
2518  Destroys this object and cleanups the memory.
2519 }
2520 destructor TZEmulatedPreparedStatement.Destroy;
2521 begin
2522  if FCachedQuery <> nil then
2523  FCachedQuery.Free;
2524  inherited Destroy;
2525 end;
2526 
2527 {**
2528  Sets a reference to the last statement.
2529  @param LastStatement the last statement interface.
2530 }
2531 procedure TZEmulatedPreparedStatement.SetLastStatement(
2532  LastStatement: IZStatement);
2533 begin
2534  if FLastStatement <> nil then
2535  FLastStatement.Close;
2536  FLastStatement := LastStatement;
2537 end;
2538 
2539 function TZEmulatedPreparedStatement.PrepareWideSQLParam(ParamIndex: Integer): ZWideString;
2540 begin
2541  Result := '';
2542 end;
2543 
2544 function TZEmulatedPreparedStatement.PrepareAnsiSQLParam(ParamIndex: Integer): RawByteString;
2545 begin
2546  Result := '';
2547 end;
2548 
2549 {**
2550  Creates a temporary statement which executes queries.
2551  @param Info a statement parameters.
2552  @return a created statement object.
2553 }
2554 function TZEmulatedPreparedStatement.GetExecStatement: IZStatement;
2555 begin
2556  if ExecStatement = nil then
2557  begin
2558  ExecStatement := CreateExecStatement;
2559 
2560  ExecStatement.SetMaxFieldSize(GetMaxFieldSize);
2561  ExecStatement.SetMaxRows(GetMaxRows);
2562  ExecStatement.SetEscapeProcessing(EscapeProcessing);
2563  ExecStatement.SetQueryTimeout(GetQueryTimeout);
2564  ExecStatement.SetCursorName(CursorName);
2565 
2566  ExecStatement.SetFetchDirection(GetFetchDirection);
2567  ExecStatement.SetFetchSize(GetFetchSize);
2568  ExecStatement.SetResultSetConcurrency(GetResultSetConcurrency);
2569  ExecStatement.SetResultSetType(GetResultSetType);
2570  end;
2571  Result := ExecStatement;
2572 end;
2573 
2574 {**
2575  Splits a SQL query into a list of sections.
2576  @returns a list of splitted sections.
2577 }
2578 function TZEmulatedPreparedStatement.TokenizeSQLQuery: TStrings;
2579 var
2580  I: Integer;
2581  Tokens: TStrings;
2582  Temp: string;
2583 begin
2584  if FCachedQuery = nil then
2585  begin
2586  FCachedQuery := TStringList.Create;
2587  if Pos('?', SSQL) > 0 then
2588  begin
2589  Tokens := Connection.GetDriver.GetTokenizer.TokenizeBufferToList(SSQL, [toUnifyWhitespaces]);
2590  try
2591  Temp := '';
2592  for I := 0 to Tokens.Count - 1 do
2593  begin
2594  if Tokens[I] = '?' then
2595  begin
2596  if FNeedNCharDetection and not (Temp = '') then
2597  FCachedQuery.Add(Temp)
2598  else
2599  FCachedQuery.Add(Temp);
2600  FCachedQuery.AddObject('?', Self);
2601  Temp := '';
2602  end
2603  else
2604  if FNeedNCharDetection and (Tokens[I] = 'N') and (Tokens.Count > i) and (Tokens[i+1] = '?') then
2605  begin
2606  FCachedQuery.Add(Temp);
2607  FCachedQuery.Add(Tokens[i]);
2608  Temp := '';
2609  end
2610  else
2611  Temp := Temp + Tokens[I];
2612  end;
2613  if Temp <> '' then
2614  FCachedQuery.Add(Temp);
2615  finally
2616  Tokens.Free;
2617  end;
2618  end
2619  else
2620  FCachedQuery.Add(SSQL);
2621  end;
2622  Result := FCachedQuery;
2623 end;
2624 
2625 {**
2626  Prepares an SQL statement and inserts all data values.
2627  @return a prepared SQL statement.
2628 }
2629 function TZEmulatedPreparedStatement.PrepareWideSQLQuery: ZWideString;
2630 var
2631  I: Integer;
2632  ParamIndex: Integer;
2633  Tokens: TStrings;
2634 begin
2635  ParamIndex := 0;
2636  Result := '';
2637  Tokens := TokenizeSQLQuery;
2638 
2639  for I := 0 to Tokens.Count - 1 do
2640  begin
2641  if Tokens[I] = '?' then
2642  begin
2643  Result := Result + PrepareWideSQLParam(ParamIndex);
2644  Inc(ParamIndex);
2645  end
2646  else
2647  Result := Result + ZPlainUnicodeString(Tokens[I]);
2648  end;
2649 end;
2650 
2651 {**
2652  Prepares an SQL statement and inserts all data values.
2653  @return a prepared SQL statement.
2654 }
2655 function TZEmulatedPreparedStatement.PrepareAnsiSQLQuery: RawByteString;
2656 var
2657  I: Integer;
2658  ParamIndex: Integer;
2659  Tokens: TStrings;
2660 begin
2661  ParamIndex := 0;
2662  Result := '';
2663  Tokens := TokenizeSQLQuery;
2664 
2665  for I := 0 to Tokens.Count - 1 do
2666  begin
2667  if Tokens[I] = '?' then
2668  begin
2669  Result := Result + PrepareAnsiSQLParam(ParamIndex);
2670  Inc(ParamIndex);
2671  end
2672  else
2673  Result := Result + ZPlainString(Tokens[I]);
2674  end;
2675  {$IFNDEF UNICODE}
2676  if GetConnection.AutoEncodeStrings then
2677  Result := GetConnection.GetDriver.GetTokenizer.GetEscapeString(Result);
2678  {$ENDIF}
2679 end;
2680 
2681 {**
2682  Closes this statement and frees all resources.
2683 }
2684 procedure TZEmulatedPreparedStatement.Close;
2685 begin
2686  inherited Close;
2687  if LastStatement <> nil then
2688  begin
2689  FLastStatement.Close;
2690  FLastStatement := nil;
2691  end;
2692 end;
2693 
2694 {**
2695  Executes an SQL statement that may return multiple results.
2696  Under some (uncommon) situations a single SQL statement may return
2697  multiple result sets and/or update counts. Normally you can ignore
2698  this unless you are (1) executing a stored procedure that you know may
2699  return multiple results or (2) you are dynamically executing an
2700  unknown SQL string. The methods <code>execute</code>,
2701  <code>getMoreResults</code>, <code>getResultSet</code>,
2702  and <code>getUpdateCount</code> let you navigate through multiple results.
2703 
2704  The <code>execute</code> method executes an SQL statement and indicates the
2705  form of the first result. You can then use the methods
2706  <code>getResultSet</code> or <code>getUpdateCount</code>
2707  to retrieve the result, and <code>getMoreResults</code> to
2708  move to any subsequent result(s).
2709 
2710  @param sql any SQL statement
2711  @return <code>true</code> if the next result is a <code>ResultSet</code> object;
2712  <code>false</code> if it is an update count or there are no more results
2713 }
2714 function TZEmulatedPreparedStatement.Execute(const SQL: ZWideString): Boolean;
2715 begin
2716  LastStatement := GetExecStatement;
2717  Result := LastStatement.Execute(SQL);
2718  if Result then
2719  LastResultSet := LastStatement.GetResultSet
2720  else
2721  LastUpdateCount := LastStatement.GetUpdateCount;
2722 end;
2723 
2724 {**
2725  Executes an SQL statement that may return multiple results.
2726  Under some (uncommon) situations a single SQL statement may return
2727  multiple result sets and/or update counts. Normally you can ignore
2728  this unless you are (1) executing a stored procedure that you know may
2729  return multiple results or (2) you are dynamically executing an
2730  unknown SQL string. The methods <code>execute</code>,
2731  <code>getMoreResults</code>, <code>getResultSet</code>,
2732  and <code>getUpdateCount</code> let you navigate through multiple results.
2733 
2734  The <code>execute</code> method executes an SQL statement and indicates the
2735  form of the first result. You can then use the methods
2736  <code>getResultSet</code> or <code>getUpdateCount</code>
2737  to retrieve the result, and <code>getMoreResults</code> to
2738  move to any subsequent result(s).
2739 
2740  @param sql any SQL statement
2741  @return <code>true</code> if the next result is a <code>ResultSet</code> object;
2742  <code>false</code> if it is an update count or there are no more results
2743 }
2744 function TZEmulatedPreparedStatement.Execute(const SQL: RawByteString): Boolean;
2745 begin
2746  LastStatement := GetExecStatement;
2747  Result := LastStatement.Execute(SQL);
2748  if Result then
2749  LastResultSet := LastStatement.GetResultSet
2750  else
2751  LastUpdateCount := LastStatement.GetUpdateCount;
2752 end;
2753 
2754 {**
2755  Executes an SQL statement that returns a single <code>ResultSet</code> object.
2756  @param sql typically this is a static SQL <code>SELECT</code> statement
2757  @return a <code>ResultSet</code> object that contains the data produced by the
2758  given query; never <code>null</code>
2759 }
2760 function TZEmulatedPreparedStatement.ExecuteQuery(const SQL: ZWideString): IZResultSet;
2761 begin
2762  Result := GetExecStatement.ExecuteQuery(SQL);
2763 end;
2764 
2765 {**
2766  Executes an SQL statement that returns a single <code>ResultSet</code> object.
2767  @param sql typically this is a static SQL <code>SELECT</code> statement
2768  @return a <code>ResultSet</code> object that contains the data produced by the
2769  given query; never <code>null</code>
2770 }
2771 function TZEmulatedPreparedStatement.ExecuteQuery(const SQL: RawByteString): IZResultSet;
2772 begin
2773  Result := GetExecStatement.ExecuteQuery(SQL);
2774 end;
2775 
2776 {**
2777  Executes an SQL <code>INSERT</code>, <code>UPDATE</code> or
2778  <code>DELETE</code> statement. In addition,
2779  SQL statements that return nothing, such as SQL DDL statements,
2780  can be executed.
2781 
2782  @param sql an SQL <code>INSERT</code>, <code>UPDATE</code> or
2783  <code>DELETE</code> statement or an SQL statement that returns nothing
2784  @return either the row count for <code>INSERT</code>, <code>UPDATE</code>
2785  or <code>DELETE</code> statements, or 0 for SQL statements that return nothing
2786 }
2787 function TZEmulatedPreparedStatement.ExecuteUpdate(const SQL: ZWideString): Integer;
2788 begin
2789  Result := GetExecStatement.ExecuteUpdate(SQL);
2790  LastUpdateCount := Result;
2791 end;
2792 
2793 {**
2794  Executes an SQL <code>INSERT</code>, <code>UPDATE</code> or
2795  <code>DELETE</code> statement. In addition,
2796  SQL statements that return nothing, such as SQL DDL statements,
2797  can be executed.
2798 
2799  @param sql an SQL <code>INSERT</code>, <code>UPDATE</code> or
2800  <code>DELETE</code> statement or an SQL statement that returns nothing
2801  @return either the row count for <code>INSERT</code>, <code>UPDATE</code>
2802  or <code>DELETE</code> statements, or 0 for SQL statements that return nothing
2803 }
2804 function TZEmulatedPreparedStatement.ExecuteUpdate(const SQL: RawByteString): Integer;
2805 begin
2806  Result := GetExecStatement.ExecuteUpdate(SQL);
2807  LastUpdateCount := Result;
2808 end;
2809 
2810 {**
2811  Executes the SQL query in this <code>PreparedStatement</code> object
2812  and returns the result set generated by the query.
2813 
2814  @return a <code>ResultSet</code> object that contains the data produced by the
2815  query; never <code>null</code>
2816 }
2817 function TZEmulatedPreparedStatement.ExecutePrepared: Boolean;
2818 begin
2819  if IsAnsiDriver then
2820  Result := Execute(PrepareAnsiSQLQuery)
2821  else
2822  Result := Execute(PrepareWideSQLQuery);
2823 end;
2824 
2825 {**
2826  Executes the SQL query in this <code>PreparedStatement</code> object
2827  and returns the result set generated by the query.
2828 
2829  @return a <code>ResultSet</code> object that contains the data produced by the
2830  query; never <code>null</code>
2831 }
2832 function TZEmulatedPreparedStatement.ExecuteQueryPrepared: IZResultSet;
2833 begin
2834  if IsAnsiDriver then
2835  Result := ExecuteQuery(PrepareAnsiSQLQuery)
2836  else
2837  Result := ExecuteQuery(PrepareWideSQLQuery);
2838 end;
2839 
2840 {**
2841  Executes the SQL INSERT, UPDATE or DELETE statement
2842  in this <code>PreparedStatement</code> object.
2843  In addition,
2844  SQL statements that return nothing, such as SQL DDL statements,
2845  can be executed.
2846 
2847  @return either the row count for INSERT, UPDATE or DELETE statements;
2848  or 0 for SQL statements that return nothing
2849 }
2850 function TZEmulatedPreparedStatement.ExecuteUpdatePrepared: Integer;
2851 begin
2852  if IsAnsiDriver then
2853  Result := ExecuteUpdate(PrepareAnsiSQLQuery)
2854  else
2855  Result := ExecuteUpdate(PrepareWideSQLQuery);
2856 end;
2857 
2858 end.
2859