zeoslib  UNKNOWN
 All Files
ZDbcInterbase6ResultSet.pas
Go to the documentation of this file.
1 {*********************************************************}
2 { }
3 { Zeos Database Objects }
4 { Interbase Database Connectivity Classes }
5 { }
6 { Originally written by Sergey Merkuriev }
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 ZDbcInterbase6ResultSet;
53 
54 interface
55 
56 {$I ZDbc.inc}
57 
58 uses
59  {$IFDEF WITH_TOBJECTLIST_INLINE}System.Types, System.Contnrs{$ELSE}Types{$ENDIF},
60  Classes, {$IFDEF MSEgui}mclasses,{$ENDIF}
61  ZDbcIntfs, ZDbcResultSet, ZDbcInterbase6, ZPlainFirebirdInterbaseConstants,
62  ZPlainFirebirdDriver, ZCompatibility, ZDbcResultSetMetadata, ZMessages,
63  ZDbcInterbase6Utils;
64 
65 type
66 
67  {** Implements Interbase ResultSet. }
68  TZInterbase6ResultSet = class(TZAbstractResultSet)
69  private
70  FCachedBlob: boolean;
71  FFetchStat: Integer;
72  FCursorName: AnsiString;
73  FStmtHandle: TISC_STMT_HANDLE;
74  FSqlData: IZResultSQLDA;
75  FIBConnection: IZInterbase6Connection;
76  protected
77  procedure Open; override;
78  function GetFieldValue(ColumnIndex: Integer): Variant;
79  function InternalGetString(ColumnIndex: Integer): RawByteString; override;
80  public
81  constructor Create(Statement: IZStatement; SQL: string;
82  var StatementHandle: TISC_STMT_HANDLE; CursorName: AnsiString;
83  SqlData: IZResultSQLDA; CachedBlob: boolean);
84  destructor Destroy; override;
85 
86  procedure Close; override;
87 
88  function GetCursorName: AnsiString; override;
89 
90  function IsNull(ColumnIndex: Integer): Boolean; override;
91  function GetString(ColumnIndex: Integer): String; override;
92  function GetUnicodeString(ColumnIndex: Integer): WideString; override;
93  function GetBoolean(ColumnIndex: Integer): Boolean; override;
94  function GetByte(ColumnIndex: Integer): Byte; override;
95  function GetShort(ColumnIndex: Integer): SmallInt; override;
96  function GetInt(ColumnIndex: Integer): Integer; override;
97  function GetLong(ColumnIndex: Integer): Int64; override;
98  function GetFloat(ColumnIndex: Integer): Single; override;
99  function GetDouble(ColumnIndex: Integer): Double; override;
100  function GetBigDecimal(ColumnIndex: Integer): Extended; override;
101  function GetBytes(ColumnIndex: Integer): TByteDynArray; override;
102  function GetDate(ColumnIndex: Integer): TDateTime; override;
103  function GetTime(ColumnIndex: Integer): TDateTime; override;
104  function GetTimestamp(ColumnIndex: Integer): TDateTime; override;
105  function GetBlob(ColumnIndex: Integer): IZBlob; override;
106 
107  function MoveAbsolute(Row: Integer): Boolean; override;
108  function Next: Boolean; override;
109  end;
110 
111  {** Implements external blob wrapper object for Intebase/Firbird. }
112  TZInterbase6Blob = class(TZAbstractBlob)
113  private
114  FBlobId: TISC_QUAD;
115  FBlobRead: Boolean;
116  FIBConnection: IZInterbase6Connection;
117  protected
118  procedure ReadBlob;
119  public
120  constructor Create(IBConnection: IZInterbase6Connection;
121  var BlobId: TISC_QUAD);
122 
123  function IsEmpty: Boolean; override;
124  function Clone: IZBlob; override;
125  function GetStream: TStream; override;
126  function GetString: RawByteString; override;
127  function GetUnicodeString: WideString; override;
128  function GetBytes: TByteDynArray; override;
129  end;
130 
131 implementation
132 
133 uses
134 {$IFNDEF FPC}
135  Variants,
136 {$ENDIF}
137  SysUtils, ZDbcUtils, ZEncoding, ZDbcLogging;
138 
139 { TZInterbase6ResultSet }
140 
141 {**
142  Releases this <code>ResultSet</code> object's database and
143  JDBC resources immediately instead of waiting for
144  this to happen when it is automatically closed.
145 
146  <P><B>Note:</B> A <code>ResultSet</code> object
147  is automatically closed by the
148  <code>Statement</code> object that generated it when
149  that <code>Statement</code> object is closed,
150  re-executed, or is used to retrieve the next result from a
151  sequence of multiple results. A <code>ResultSet</code> object
152  is also automatically closed when it is garbage collected.
153 }
154 procedure TZInterbase6ResultSet.Close;
155 begin
156  if FStmtHandle <> 0 then
157  begin
158  { Free output allocated memory }
159  FSqlData := nil;
160  { Free allocate sql statement }
161  FreeStatement(FIBConnection.GetPlainDriver, FStmtHandle, DSQL_CLOSE); //AVZ
162  end;
163  inherited Close;
164 end;
165 
166 {**
167  Constructs this object, assignes main properties and
168  opens the record set.
169  @param Statement a related SQL statement object.
170  @param handle a Interbase6 database connect handle.
171  @param the statement previously prepared
172  @param the sql out data previously allocated
173  @param the Interbase sql dialect
174 }
175 constructor TZInterbase6ResultSet.Create(Statement: IZStatement; SQL: string;
176  var StatementHandle: TISC_STMT_HANDLE; CursorName: AnsiString;
177  SqlData: IZResultSQLDA; CachedBlob: boolean);
178 begin
179  inherited Create(Statement, SQL, nil,
180  Statement.GetConnection.GetConSettings);
181 
182  FFetchStat := 0;
183  FSqlData := SqlData;
184  FCursorName := CursorName;
185  FCachedBlob := CachedBlob;
186  FIBConnection := Statement.GetConnection as IZInterbase6Connection;
187 
188  FStmtHandle := StatementHandle;
189  ResultSetType := rtForwardOnly;
190  ResultSetConcurrency := rcReadOnly;
191 
192  Open;
193 end;
194 
195 {**
196  Free memory and destriy component
197 }
198 destructor TZInterbase6ResultSet.Destroy;
199 begin
200  if not Closed then
201  Close;
202  inherited Destroy;
203 end;
204 
205 {**
206  Return field value by it index
207  @param the index column 0 first, 1 second ...
208  @return the field value as variant type
209 }
210 function TZInterbase6ResultSet.GetFieldValue(ColumnIndex: Integer): Variant;
211 begin
212  CheckClosed;
213  Result := FSqlData.GetValue(ColumnIndex);
214 end;
215 
216 {**
217  Gets the value of the designated column in the current row
218  of this <code>ResultSet</code> object as
219  a <code>java.sql.BigDecimal</code> in the Java programming language.
220 
221  @param columnIndex the first column is 1, the second is 2, ...
222  @param scale the number of digits to the right of the decimal point
223  @return the column value; if the value is SQL <code>NULL</code>, the
224  value returned is <code>null</code>
225 }
226 function TZInterbase6ResultSet.GetBigDecimal(ColumnIndex: Integer): Extended;
227 begin
228  CheckClosed;
229 {$IFNDEF DISABLE_CHECKING}
230  CheckColumnConvertion(ColumnIndex, stBigDecimal);
231 {$ENDIF}
232  Result := FSqlData.GetBigDecimal(ColumnIndex - 1);
233  LastWasNull := IsNull(ColumnIndex);
234 end;
235 
236 {**
237  Returns the value of the designated column in the current row
238  of this <code>ResultSet</code> object as a <code>Blob</code> object
239  in the Java programming language.
240 
241  @param ColumnIndex the first column is 1, the second is 2, ...
242  @return a <code>Blob</code> object representing the SQL <code>BLOB</code> value in
243  the specified column
244 }
245 {$IFDEF FPC}
246  {$HINTS OFF}
247 {$ENDIF}
248 function TZInterbase6ResultSet.GetBlob(ColumnIndex: Integer): IZBlob;
249 var
250  Size: Integer;
251  Buffer: Pointer;
252  BlobId: TISC_QUAD;
253  TempStream: TStream;
254 begin
255  Result := nil;
256  CheckClosed;
257  CheckBlobColumn(ColumnIndex);
258 
259  LastWasNull := IsNull(ColumnIndex);
260  if LastWasNull then
261  Exit;
262  TempStream := nil;
263  if FCachedBlob then
264  begin
265  try
266  BlobId := FSqlData.GetQuad(ColumnIndex - 1);
267  with FIBConnection do
268  ReadBlobBufer(GetPlainDriver, GetDBHandle, GetTrHandle,
269  BlobId, Size, Buffer);
270 
271  if Size = 0 then
272  begin
273  TempStream := TMemoryStream.Create;
274  Result := TZAbstractBlob.CreateWithStream(TempStream, FIBConnection, GetMetaData.GetColumnType(ColumnIndex) = stUnicodeStream);
275  end
276  else
277  case GetMetaData.GetColumnType(ColumnIndex) of
278  stBinaryStream:
279  Result := TZAbstractBlob.CreateWithData(Buffer, Size, FIBConnection);
280  stAsciiStream:
281  begin
282  Result := TZAbstractBlob.CreateWithData(Buffer, Size, FIBConnection);
283  TempStream := TStringStream.Create(GetValidatedAnsiString(Result.GetString, Consettings, True));
284  Result.SetStream(TempStream);
285  end;
286  else
287  begin
288  TempStream := GetValidatedUnicodeStream(Buffer, Size, ConSettings, True);
289  Result := TZAbstractBlob.CreateWithStream(TempStream, FIBConnection, True);
290  end;
291  end;
292  finally
293  if Assigned(TempStream) then FreeAndNil(TempStream);
294  FreeMem(Buffer, Size);
295  end;
296  end
297  else
298  begin
299  BlobId := FSqlData.GetQuad(ColumnIndex - 1);
300  Result := TZInterbase6Blob.Create(FIBConnection, BlobId);
301  end;
302 end;
303 {$IFDEF FPC}
304  {$HINTS ON}
305 {$ENDIF}
306 
307 {**
308  Gets the value of the designated column in the current row
309  of this <code>ResultSet</code> object as
310  a <code>boolean</code> in the Java programming language.
311 
312  @param columnIndex the first column is 1, the second is 2, ...
313  @return the column value; if the value is SQL <code>NULL</code>, the
314  value returned is <code>false</code>
315 }
316 function TZInterbase6ResultSet.GetBoolean(ColumnIndex: Integer): Boolean;
317 begin
318  CheckClosed;
319 {$IFNDEF DISABLE_CHECKING}
320  CheckColumnConvertion(ColumnIndex, stBoolean);
321 {$ENDIF}
322  Result := FSqlData.GetBoolean(ColumnIndex - 1);
323  LastWasNull := IsNull(ColumnIndex);
324 end;
325 
326 {**
327  Gets the value of the designated column in the current row
328  of this <code>ResultSet</code> object as
329  a <code>byte</code> in the Java programming language.
330 
331  @param columnIndex the first column is 1, the second is 2, ...
332  @return the column value; if the value is SQL <code>NULL</code>, the
333  value returned is <code>0</code>
334 }
335 function TZInterbase6ResultSet.GetByte(ColumnIndex: Integer): Byte;
336 begin
337  CheckClosed;
338 {$IFNDEF DISABLE_CHECKING}
339  CheckColumnConvertion(ColumnIndex, stByte);
340 {$ENDIF}
341  Result := FSqlData.GetByte(ColumnIndex - 1);
342  LastWasNull := IsNull(ColumnIndex);
343 end;
344 
345 {**
346  Gets the value of the designated column in the current row
347  of this <code>ResultSet</code> object as
348  a <code>byte</code> array in the Java programming language.
349  The bytes represent the raw values returned by the driver.
350 
351  @param columnIndex the first column is 1, the second is 2, ...
352  @return the column value; if the value is SQL <code>NULL</code>, the
353  value returned is <code>null</code>
354 }
355 function TZInterbase6ResultSet.GetBytes(ColumnIndex: Integer): TByteDynArray;
356 begin
357  CheckClosed;
358 {$IFNDEF DISABLE_CHECKING}
359  CheckColumnConvertion(ColumnIndex, stBytes);
360 {$ENDIF}
361  Result := FSqlData.GetBytes(ColumnIndex - 1);
362  LastWasNull := IsNull(ColumnIndex);
363 end;
364 
365 {**
366  Gets the value of the designated column in the current row
367  of this <code>ResultSet</code> object as
368  a <code>java.sql.Date</code> object in the Java programming language.
369 
370  @param columnIndex the first column is 1, the second is 2, ...
371  @return the column value; if the value is SQL <code>NULL</code>, the
372  value returned is <code>null</code>
373 }
374 function TZInterbase6ResultSet.GetDate(ColumnIndex: Integer): TDateTime;
375 begin
376  CheckClosed;
377 {$IFNDEF DISABLE_CHECKING}
378  CheckColumnConvertion(ColumnIndex, stDate);
379 {$ENDIF}
380  Result := FSqlData.GetDate(ColumnIndex - 1);
381  LastWasNull := IsNull(ColumnIndex);
382 end;
383 
384 {**
385  Gets the value of the designated column in the current row
386  of this <code>ResultSet</code> object as
387  a <code>double</code> in the Java programming language.
388 
389  @param columnIndex the first column is 1, the second is 2, ...
390  @return the column value; if the value is SQL <code>NULL</code>, the
391  value returned is <code>0</code>
392 }
393 function TZInterbase6ResultSet.GetDouble(ColumnIndex: Integer): Double;
394 begin
395  CheckClosed;
396 {$IFNDEF DISABLE_CHECKING}
397  CheckColumnConvertion(ColumnIndex, stDouble);
398 {$ENDIF}
399  Result := FSqlData.GetDouble(ColumnIndex - 1);
400  LastWasNull := IsNull(ColumnIndex);
401 end;
402 
403 {**
404  Gets the value of the designated column in the current row
405  of this <code>ResultSet</code> object as
406  a <code>float</code> in the Java programming language.
407 
408  @param columnIndex the first column is 1, the second is 2, ...
409  @return the column value; if the value is SQL <code>NULL</code>, the
410  value returned is <code>0</code>
411 }
412 function TZInterbase6ResultSet.GetFloat(ColumnIndex: Integer): Single;
413 begin
414  CheckClosed;
415 {$IFNDEF DISABLE_CHECKING}
416  CheckColumnConvertion(ColumnIndex, stFloat);
417 {$ENDIF}
418  Result := FSqlData.GetFloat(ColumnIndex - 1);
419  LastWasNull := IsNull(ColumnIndex);
420 end;
421 
422 {**
423  Gets the value of the designated column in the current row
424  of this <code>ResultSet</code> object as
425  an <code>int</code> in the Java programming language.
426 
427  @param columnIndex the first column is 1, the second is 2, ...
428  @return the column value; if the value is SQL <code>NULL</code>, the
429  value returned is <code>0</code>
430 }
431 function TZInterbase6ResultSet.GetInt(ColumnIndex: Integer): Integer;
432 begin
433  CheckClosed;
434 {$IFNDEF DISABLE_CHECKING}
435  CheckColumnConvertion(ColumnIndex, stInteger);
436 {$ENDIF}
437  Result := FSqlData.GetInt(ColumnIndex - 1);
438  LastWasNull := IsNull(ColumnIndex);
439 end;
440 
441 {**
442  Gets the value of the designated column in the current row
443  of this <code>ResultSet</code> object as
444  a <code>long</code> in the Java programming language.
445 
446  @param columnIndex the first column is 1, the second is 2, ...
447  @return the column value; if the value is SQL <code>NULL</code>, the
448  value returned is <code>0</code>
449 }
450 function TZInterbase6ResultSet.GetLong(ColumnIndex: Integer): Int64;
451 begin
452  CheckClosed;
453 {$IFNDEF DISABLE_CHECKING}
454  CheckColumnConvertion(ColumnIndex, stLong);
455 {$ENDIF}
456  Result := FSqlData.GetLong(ColumnIndex - 1);
457  LastWasNull := IsNull(ColumnIndex);
458 end;
459 
460 {**
461  Gets the value of the designated column in the current row
462  of this <code>ResultSet</code> object as
463  a <code>short</code> in the Java programming language.
464 
465  @param columnIndex the first column is 1, the second is 2, ...
466  @return the column value; if the value is SQL <code>NULL</code>, the
467  value returned is <code>0</code>
468 }
469 function TZInterbase6ResultSet.GetShort(ColumnIndex: Integer): SmallInt;
470 begin
471  CheckClosed;
472 {$IFNDEF DISABLE_CHECKING}
473  CheckColumnConvertion(ColumnIndex, stShort);
474 {$ENDIF}
475  Result := FSqlData.GetShort(ColumnIndex - 1);
476  LastWasNull := IsNull(ColumnIndex);
477 end;
478 
479 {**
480  Gets the value of the designated column in the current row
481  of this <code>ResultSet</code> object as
482  a <code>String</code> in the Java programming language.
483 
484  @param columnIndex the first column is 1, the second is 2, ...
485  @return the column value; if the value is SQL <code>NULL</code>, the
486  value returned is <code>null</code>
487 }
488 function TZInterbase6ResultSet.InternalGetString(ColumnIndex: Integer): RawByteString;
489 begin
490  CheckClosed;
491 {$IFNDEF DISABLE_CHECKING}
492  CheckColumnConvertion(ColumnIndex, stString);
493 {$ENDIF}
494  LastWasNull := IsNull(ColumnIndex);
495  Result := FSqlData.GetString(ColumnIndex - 1);
496 end;
497 
498 {**
499  Gets the value of the designated column in the current row
500  of this <code>ResultSet</code> object as
501  a <code>java.sql.Time</code> object in the Java programming language.
502 
503  @param columnIndex the first column is 1, the second is 2, ...
504  @return the column value; if the value is SQL <code>NULL</code>, the
505  value returned is <code>null</code>
506 }
507 function TZInterbase6ResultSet.GetTime(ColumnIndex: Integer): TDateTime;
508 begin
509  CheckClosed;
510 {$IFNDEF DISABLE_CHECKING}
511  CheckColumnConvertion(ColumnIndex, stTime);
512 {$ENDIF}
513  Result := FSqlData.GetTime(ColumnIndex - 1);
514  LastWasNull := IsNull(ColumnIndex);
515 end;
516 
517 {**
518  Gets the value of the designated column in the current row
519  of this <code>ResultSet</code> object as
520  a <code>java.sql.Timestamp</code> object in the Java programming language.
521 
522  @param columnIndex the first column is 1, the second is 2, ...
523  @return the column value; if the value is SQL <code>NULL</code>, the
524  value returned is <code>null</code>
525  @exception SQLException if a database access error occurs
526 }
527 function TZInterbase6ResultSet.GetTimestamp(ColumnIndex: Integer): TDateTime;
528 begin
529  CheckClosed;
530 {$IFNDEF DISABLE_CHECKING}
531  CheckColumnConvertion(ColumnIndex, stTimestamp);
532 {$ENDIF}
533  Result := FSqlData.GetTimestamp(ColumnIndex - 1);
534  LastWasNull := IsNull(ColumnIndex);
535 end;
536 
537 {**
538  Indicates if the value of the designated column in the current row
539  of this <code>ResultSet</code> object is Null.
540 
541  @param columnIndex the first column is 1, the second is 2, ...
542  @return if the value is SQL <code>NULL</code>, the
543  value returned is <code>true</code>. <code>false</code> otherwise.
544 }
545 function TZInterbase6ResultSet.IsNull(ColumnIndex: Integer): Boolean;
546 begin
547  CheckClosed;
548  Result := FSqlData.IsNull(ColumnIndex - 1);
549 end;
550 
551 {**
552  Gets the value of the designated column in the current row
553  of this <code>ResultSet</code> object as
554  a <code>String</code> in the Java programming language.
555 
556  @param columnIndex the first column is 1, the second is 2, ...
557  @return the column value; if the value is SQL <code>NULL</code>, the
558  value returned is <code>null</code>
559 }
560 function TZInterbase6ResultSet.GetString(ColumnIndex: Integer): String;
561 begin
562  CheckClosed;
563 {$IFNDEF DISABLE_CHECKING}
564  CheckColumnConvertion(ColumnIndex, stString);
565 {$ENDIF}
566  LastWasNull := IsNull(ColumnIndex);
567  if ( ConSettings.ClientCodePage.ID = CS_NONE ) then //CharacterSet 'NONE' doesn't convert anything! Data as is!
568  case FSqlData.GetIbSqlType(ColumnIndex -1) of
569  SQL_VARYING, SQL_TEXT:
570  if FSqlData.GetIbSqlSubType(ColumnIndex -1) = CS_NONE then
571  Result := ZDbcString(FSqlData.GetString(ColumnIndex - 1))
572  else
573  Result := ZDbcString(FSqlData.GetString(ColumnIndex - 1),
574  FIBConnection.GetPlainDriver.ValidateCharEncoding(FSqlData.GetIbSqlSubType(ColumnIndex -1)).CP);
575  else
576  Result := ZDbcString(FSqlData.GetString(ColumnIndex - 1));
577  end
578  else
579  Result := ZDbcString(FSqlData.GetString(ColumnIndex - 1));
580 end;
581 
582 {**
583  Gets the value of the designated column in the current row
584  of this <code>ResultSet</code> object as
585  a <code>WideString</code> in the Delphi programming language.
586 
587  @param columnIndex the first column is 1, the second is 2, ...
588  @return the column value; if the value is SQL <code>NULL</code>, the
589  value returned is <code>null</code>
590 }
591 function TZInterbase6ResultSet.GetUnicodeString(ColumnIndex: Integer): WideString;
592 begin
593  CheckClosed;
594 {$IFNDEF DISABLE_CHECKING}
595  CheckColumnConvertion(ColumnIndex, stString);
596 {$ENDIF}
597  LastWasNull := IsNull(ColumnIndex);
598  if ( ConSettings.ClientCodePage.ID = CS_NONE ) then //CharacterSet 'NONE' doesn't convert anything! Data as is!
599  case FSqlData.GetIbSqlType(ColumnIndex -1) of
600  SQL_VARYING, SQL_TEXT:
601  if FSqlData.GetIbSqlSubType(ColumnIndex -1) = CS_NONE then
602  Result := ZDbcUnicodeString(FSqlData.GetString(ColumnIndex - 1))
603  else
604  Result := ZDbcUnicodeString(FSqlData.GetString(ColumnIndex - 1),
605  FIBConnection.GetPlainDriver.ValidateCharEncoding(FSqlData.GetIbSqlSubType(ColumnIndex -1)).CP);
606  else
607  Result := ZDbcUnicodeString(FSqlData.GetString(ColumnIndex - 1));
608  end
609  else
610  Result := ZDbcUnicodeString(FSqlData.GetString(ColumnIndex - 1));
611 end;
612 
613 {**
614  Moves the cursor to the given row number in
615  this <code>ResultSet</code> object.
616 
617  <p>If the row number is positive, the cursor moves to
618  the given row number with respect to the
619  beginning of the result set. The first row is row 1, the second
620  is row 2, and so on.
621 
622  <p>If the given row number is negative, the cursor moves to
623  an absolute row position with respect to
624  the end of the result set. For example, calling the method
625  <code>absolute(-1)</code> positions the
626  cursor on the last row; calling the method <code>absolute(-2)</code>
627  moves the cursor to the next-to-last row, and so on.
628 
629  <p>An attempt to position the cursor beyond the first/last row in
630  the result set leaves the cursor before the first row or after
631  the last row.
632 
633  <p><B>Note:</B> Calling <code>absolute(1)</code> is the same
634  as calling <code>first()</code>. Calling <code>absolute(-1)</code>
635  is the same as calling <code>last()</code>.
636 
637  @return <code>true</code> if the cursor is on the result set;
638  <code>false</code> otherwise
639 }
640 function TZInterbase6ResultSet.MoveAbsolute(Row: Integer): Boolean;
641 begin
642  Result := False;
643  RaiseForwardOnlyException;
644 end;
645 
646 {**
647  Moves the cursor down one row from its current position.
648  A <code>ResultSet</code> cursor is initially positioned
649  before the first row; the first call to the method
650  <code>next</code> makes the first row the current row; the
651  second call makes the second row the current row, and so on.
652 
653  <P>If an input stream is open for the current row, a call
654  to the method <code>next</code> will
655  implicitly close it. A <code>ResultSet</code> object's
656  warning chain is cleared when a new row is read.
657 
658  @return <code>true</code> if the new current row is valid;
659  <code>false</code> if there are no more rows
660 }
661 function TZInterbase6ResultSet.Next: Boolean;
662 var
663  StatusVector: TARRAY_ISC_STATUS;
664 begin
665  { Checks for maximum row. }
666  Result := False;
667  if (MaxRows > 0) and (LastRowNo >= MaxRows) then
668  Exit;
669 
670  { Fetch row. }
671  if (ResultSetType = rtForwardOnly) and (FFetchStat = 0) then
672  begin
673  with FIBConnection do
674  begin
675  if (FCursorName = '') then //AVZ - Test for ExecProc - this is for multiple rows
676  begin
677  FFetchStat := GetPlainDriver.isc_dsql_fetch(@StatusVector,
678  @FStmtHandle, GetDialect, FSqlData.GetData);
679  end
680  else
681  begin
682  FFetchStat := 1;
683  Result := True;
684  end;
685  end;
686 
687  if FFetchStat = 0 then
688  begin
689  RowNo := RowNo + 1;
690  LastRowNo := RowNo;
691  Result := True;
692  end
693  else
694  if not Result then
695  CheckInterbase6Error(FIBConnection.GetPlainDriver, StatusVector, lcOther);
696  end;
697 end;
698 
699 {**
700  Opens this recordset.
701 }
702 procedure TZInterbase6ResultSet.Open;
703 var
704  I: Integer;
705  FieldSqlType: TZSQLType;
706  ColumnInfo: TZColumnInfo;
707  ZCodePageInfo: PZCodePage;
708 begin
709  if FStmtHandle=0 then
710  raise EZSQLException.Create(SCanNotRetrieveResultSetData);
711 
712  ColumnsInfo.Clear;
713  for I := 0 to FSqlData.GetFieldCount - 1 do
714  begin
715  ColumnInfo := TZColumnInfo.Create;
716  with ColumnInfo, FSqlData do
717  begin
718  ColumnName := GetFieldSqlName(I);
719  TableName := GetFieldRelationName(I);
720  ColumnLabel := GetFieldAliasName(I);
721  FieldSqlType := GetFieldSqlType(I);
722  ColumnType := FieldSqlType;
723 
724  if FieldSqlType in [stString, stUnicodeString] then
725  begin
726  ZCodePageInfo := FIBConnection.GetPlainDriver.ValidateCharEncoding(GetIbSqlSubType(I)); //get column CodePage info
727  Precision := GetFieldSize(ColumnType, ConSettings, GetIbSqlLen(I),
728  ZCodePageInfo^.CharWidth, @ColumnDisplaySize, True);
729  end;
730  if FieldSQLType = stBytes then
731  Precision := GetIbSqlLen(I);
732 
733  ReadOnly := (TableName = '') or (ColumnName = '') or
734  (ColumnName = 'RDB$DB_KEY') or (FieldSqlType = ZDbcIntfs.stUnknown);
735 
736  if IsNullable(I) then
737  Nullable := ntNullable
738  else
739  Nullable := ntNoNulls;
740 
741  Scale := GetFieldScale(I);
742  CaseSensitive := UpperCase(ColumnName) <> ColumnName; //non quoted fields are uppercased by default
743  end;
744  ColumnsInfo.Add(ColumnInfo);
745  end;
746  inherited Open;
747 end;
748 
749 function TZInterbase6ResultSet.GetCursorName: AnsiString;
750 begin
751  Result := FCursorName;
752 end;
753 
754 { TZInterbase6Blob }
755 
756 function TZInterbase6Blob.Clone: IZBlob;
757 begin
758  Result := TZInterbase6Blob.Create(FIBConnection, FBlobId);
759 end;
760 
761 {**
762  Reads the blob information by blob handle.
763  @param handle a Interbase6 database connect handle.
764  @param the statement previously prepared
765 }
766 constructor TZInterbase6Blob.Create(IBConnection: IZInterbase6Connection;
767  var BlobId: TISC_QUAD);
768 begin
769  FBlobId := BlobId;
770  FBlobRead := False;
771  FIBConnection := IBConnection;
772 end;
773 
774 function TZInterbase6Blob.GetBytes: TByteDynArray;
775 begin
776  ReadBlob;
777  Result := inherited GetBytes;
778 end;
779 
780 function TZInterbase6Blob.GetStream: TStream;
781 begin
782  ReadBlob;
783  Result := inherited GetStream;
784 end;
785 
786 function TZInterbase6Blob.GetString: RawByteString;
787 begin
788  ReadBlob;
789  Result := inherited GetString;
790 end;
791 
792 function TZInterbase6Blob.GetUnicodeString: WideString;
793 begin
794  ReadBlob;
795  Result := inherited GetUnicodeString;
796 end;
797 
798 function TZInterbase6Blob.IsEmpty: Boolean;
799 begin
800  ReadBlob;
801  Result := inherited IsEmpty;
802 end;
803 
804 {$IFDEF FPC}
805  {$HINTS OFF}
806 {$ENDIF}
807 procedure TZInterbase6Blob.ReadBlob;
808 var
809  Size: Integer;
810  Buffer: Pointer;
811 begin
812  if FBlobRead then
813  Exit;
814 
815  with FIBConnection do
816  ReadBlobBufer(GetPlainDriver, GetDBHandle, GetTrHandle, FBlobId, Size, Buffer);
817  BlobSize := Size;
818  BlobData := Buffer;
819  FBlobRead := True;
820 end;
821 {$IFDEF FPC}
822  {$HINTS ON}
823 {$ENDIF}
824 
825 end.