1 {*********************************************************}
3 { Zeos Database Objects }
4 { DBLib Resultset common functionality }
6 { Originally written by Janos Fegyverneki }
8 {*********************************************************}
10 {@********************************************************}
11 { Copyright (c) 1999-2012 Zeos Development Group }
13 { License Agreement: }
15 { This library is distributed in the hope that it will be }
16 { useful, but WITHOUT ANY WARRANTY; without even the }
17 { implied warranty of MERCHANTABILITY or FITNESS FOR }
18 { A PARTICULAR PURPOSE. See the GNU Lesser General }
19 { Public License for more details. }
21 { The source code of the ZEOS Libraries and packages are }
22 { distributed under the Library GNU General Public }
23 { License (see the file COPYING / COPYING.ZEOS) }
24 { with the following modification: }
25 { As a special exception, the copyright holders of this }
26 { library give you permission to link this library with }
27 { independent modules to produce an executable, }
28 { regardless of the license terms of these independent }
29 { modules, and to copy and distribute the resulting }
30 { executable under terms of your choice, provided that }
31 { you also meet, for each linked independent module, }
32 { the terms and conditions of the license of that module. }
33 { An independent module is a module which is not derived }
34 { from or based on this library. If you modify this }
35 { library, you may extend this exception to your version }
36 { of the library, but you are not obligated to do so. }
37 { If you do not wish to do so, delete this exception }
38 { statement from your version. }
41 { The project web site is located on: }
42 { http://zeos.firmos.at (FORUM) }
43 { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)}
44 { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) }
46 { http://www.sourceforge.net/projects/zeoslib. }
49 { Zeos Development Group. }
50 {********************************************************@}
52 unit ZDbcDbLibResultSet;
62 {$IFDEF WITH_TOBJECTLIST_INLINE}System.Types, System.Contnrs{$ELSE}Types{$ENDIF},
63 Classes, {$IFDEF MSEgui}mclasses,{$ENDIF} SysUtils,
64 ZDbcIntfs, ZDbcResultSet, ZCompatibility, ZDbcResultsetMetadata,
65 ZDbcGenericResolver, ZDbcCachedResultSet, ZDbcCache, ZDbcDBLib,
66 ZPlainDbLibConstants, ZPlainDBLibDriver;
69 {** Implements DBLib ResultSet. }
70 TZDBLibResultSet = class(TZAbstractResultSet)
74 DBLibColTypeCache: TSmallIntDynArray;
75 DBLibColumnCount: Integer;
76 procedure CheckColumnIndex(ColumnIndex: Integer);
78 FDBLibConnection: IZDBLibConnection;
79 FPlainDriver: IZDBLibPlainDriver;
80 procedure Open; override;
81 function InternalGetString(ColumnIndex: Integer): RawByteString; override;
83 constructor Create(Statement: IZStatement; SQL: string);
84 destructor Destroy; override;
86 procedure Close; override;
88 function IsNull(ColumnIndex: Integer): Boolean; override;
89 function GetString(ColumnIndex: Integer): String; override;
90 function GetUnicodeString(ColumnIndex: Integer): WideString; override;
91 function GetBoolean(ColumnIndex: Integer): Boolean; override;
92 function GetByte(ColumnIndex: Integer): Byte; override;
93 function GetShort(ColumnIndex: Integer): SmallInt; override;
94 function GetInt(ColumnIndex: Integer): Integer; override;
95 function GetLong(ColumnIndex: Integer): Int64; override;
96 function GetFloat(ColumnIndex: Integer): Single; override;
97 function GetDouble(ColumnIndex: Integer): Double; override;
98 function GetBigDecimal(ColumnIndex: Integer): Extended; override;
99 function GetBytes(ColumnIndex: Integer): TByteDynArray; override;
100 function GetDate(ColumnIndex: Integer): TDateTime; override;
101 function GetTime(ColumnIndex: Integer): TDateTime; override;
102 function GetTimestamp(ColumnIndex: Integer): TDateTime; override;
103 function GetBlob(ColumnIndex: Integer): IZBlob; override;
105 function MoveAbsolute(Row: Integer): Boolean; override;
106 function Next: Boolean; override;
109 {** Implements a cached resolver with mssql and sybase specific functionality. }
110 TZDBLibCachedResolver = class (TZGenericCachedResolver, IZCachedResolver)
112 FAutoColumnIndex: Integer;
114 constructor Create(Statement: IZStatement; Metadata: IZResultSetMetadata);
116 procedure PostUpdates(Sender: IZCachedResultSet; UpdateType: TZRowUpdateType;
117 OldRowAccessor, NewRowAccessor: TZRowAccessor); override;
122 uses ZMessages, ZDbcLogging, ZDbcDBLibUtils, ZEncoding
123 {$IFDEF WITH_UNITANSISTRINGS}, AnsiStrings{$ENDIF}
124 {$IFDEF WITH_WIDESTRUTILS}, WideStrUtils {$ENDIF}
130 Constructs this object, assignes main properties and
131 opens the record set.
132 @param Statement a related SQL statement object.
133 @param Handle a DBLib specific query handle.
135 constructor TZDBLibResultSet.Create(Statement: IZStatement; SQL: string);
137 inherited Create(Statement, SQL, nil, Statement.GetConnection.GetConSettings);
138 Statement.GetConnection.QueryInterface(IZDBLibConnection, FDBLibConnection);
139 FPlainDriver := FDBLibConnection.GetPlainDriver;
140 FHandle := FDBLibConnection.GetConnectionHandle;
147 Destroys this object and cleanups the memory.
149 destructor TZDBLibResultSet.Destroy;
151 { TODO -ofjanos -cGeneral : Does it need close here? }
157 Opens this recordset.
159 procedure TZDBLibResultSet.Open;
162 ColumnInfo: TZColumnInfo;
166 //Check if the current statement can return rows
167 if FPlainDriver.dbCmdRow(FHandle) <> DBSUCCEED then
168 raise EZSQLException.Create(SCanNotRetrieveResultSetData);
170 { Fills the column info }
172 DBLibColumnCount := FPlainDriver.dbnumcols(FHandle);
173 SetLength(DBLibColTypeCache, DBLibColumnCount + 1);
174 for I := 1 to DBLibColumnCount do
176 ColName := FPlainDriver.ZDbcString(FPlainDriver.dbColName(FHandle, I),
177 FDBLibConnection.GetConSettings);
178 ColType := FPlainDriver.dbColtype(FHandle, I);
179 ColumnInfo := TZColumnInfo.Create;
181 ColumnInfo.ColumnLabel := ColName;
182 ColumnInfo.ColumnName := ColName;
183 if Self.FDBLibConnection.FreeTDS then
184 ColumnInfo.ColumnType := ConvertFreeTDSToSqlType(ColType, ConSettings.CPType)
186 ColumnInfo.ColumnType := ConvertDBLibToSqlType(ColType, ConSettings.CPType);
187 ColumnInfo.Currency := (ColType = FPlainDriver.GetVariables.datatypes[Z_SQLMONEY]) or
188 (ColType = FPlainDriver.GetVariables.datatypes[Z_SQLMONEY4]) or
189 (ColType = FPlainDriver.GetVariables.datatypes[Z_SQLMONEYN]);;
190 ColumnInfo.Precision := FPlainDriver.dbCollen(FHandle, I);
191 ColumnInfo.Scale := 0;
192 if ColType = FPlainDriver.GetVariables.datatypes[Z_SQLINT1] then
193 ColumnInfo.Signed := False
195 ColumnInfo.Signed := True;
197 ColumnsInfo.Add(ColumnInfo);
199 DBLibColTypeCache[I] := ColType;
205 Releases this <code>ResultSet</code> object's database and
206 JDBC resources immediately instead of waiting for
207 this to happen when it is automatically closed.
209 <P><B>Note:</B> A <code>ResultSet</code> object
210 is automatically closed by the
211 <code>Statement</code> object that generated it when
212 that <code>Statement</code> object is closed,
213 re-executed, or is used to retrieve the next result from a
214 sequence of multiple results. A <code>ResultSet</code> object
215 is also automatically closed when it is garbage collected.
217 procedure TZDBLibResultSet.Close;
219 { TODO -ofjanos -cGeneral : Maybe it needs a dbcanquery here. }
220 // if Assigned(FHandle) then
221 // if not FPlainDriver.dbDead(FHandle) then
222 // if FPlainDriver.dbCanQuery(FHandle) <> DBSUCCEED then
223 // FDBLibConnection.CheckDBLibError(lcDisconnect, 'CLOSE QUERY');
225 SetLength(DBLibColTypeCache, 0);
230 Checks if the columnindex is in the proper range.
231 An exception is generated if somthing is not ok.
233 @param columnIndex the first column is 1, the second is 2, ...
235 procedure TZDBLibResultSet.CheckColumnIndex(ColumnIndex: Integer);
237 if (ColumnIndex > DBLibColumnCount) or (ColumnIndex < 1) then
239 raise EZSQLException.Create(
240 Format(SColumnIsNotAccessable, [ColumnIndex]));
245 Indicates if the value of the designated column in the current row
246 of this <code>ResultSet</code> object is Null.
248 @param columnIndex the first column is 1, the second is 2, ...
249 @return if the value is SQL <code>NULL</code>, the
250 value returned is <code>true</code>. <code>false</code> otherwise.
252 function TZDBLibResultSet.IsNull(ColumnIndex: Integer): Boolean;
255 CheckColumnIndex(ColumnIndex);
256 Result := FPlainDriver.dbData(FHandle, ColumnIndex) = nil;
260 Gets the value of the designated column in the current row
261 of this <code>ResultSet</code> object as
262 a <code>String</code> in the Java programming language.
264 @param columnIndex the first column is 1, the second is 2, ...
265 @return the column value; if the value is SQL <code>NULL</code>, the
266 value returned is <code>null</code>
268 function TZDBLibResultSet.GetString(ColumnIndex: Integer): String;
269 var Tmp: RawByteString;
271 if TZColumnInfo(ColumnsInfo[ColumnIndex-1]).ColumnType in [stString, stUnicodeString, stAsciiStream, stUnicodeStream] then
272 if TZColumnInfo(ColumnsInfo[ColumnIndex-1]).InternalColumnType = stUnknown then
274 Tmp := InternalGetString(ColumnIndex);
275 case DetectUTF8Encoding(Tmp) of
278 if TZColumnInfo(ColumnsInfo[ColumnIndex-1]).ColumnType in [stString, stUnicodeString] then
279 TZColumnInfo(ColumnsInfo[ColumnIndex-1]).InternalColumnType := stUnicodeString
281 TZColumnInfo(ColumnsInfo[ColumnIndex-1]).InternalColumnType := stUnicodeStream;
282 Result := ZDbcString(Tmp, zCP_UTF8)
286 if TZColumnInfo(ColumnsInfo[ColumnIndex-1]).ColumnType in [stString, stUnicodeString] then
287 TZColumnInfo(ColumnsInfo[ColumnIndex-1]).InternalColumnType := stString
289 TZColumnInfo(ColumnsInfo[ColumnIndex-1]).InternalColumnType := stAsciiStream;
290 Result := ZDbcString(tmp, ConSettings^.ClientCodePage^.CP)
293 Result := ZDbcString(tmp);
297 if TZColumnInfo(ColumnsInfo[ColumnIndex-1]).InternalColumnType in [stUnicodeString, stUnicodeStream] then
298 Result := ZDbcString(InternalGetString(ColumnIndex), zCP_UTF8)
300 Result := ZDbcString(InternalGetString(ColumnIndex), ConSettings^.ClientCodePage^.CP)
302 Result := String(InternalGetString(ColumnIndex));
306 Gets the value of the designated column in the current row
307 of this <code>ResultSet</code> object as
308 a <code>WideString</code> in the Delphi programming language.
310 @param columnIndex the first column is 1, the second is 2, ...
311 @return the column value; if the value is SQL <code>NULL</code>, the
312 value returned is <code>null</code>
314 function TZDBLibResultSet.GetUnicodeString(ColumnIndex: Integer): WideString;
315 var Tmp: RawByteString;
317 if TZColumnInfo(ColumnsInfo[ColumnIndex-1]).ColumnType in [stString, stUnicodeString, stAsciiStream, stUnicodeStream] then
318 if TZColumnInfo(ColumnsInfo[ColumnIndex-1]).InternalColumnType = stUnknown then
320 Tmp := InternalGetString(ColumnIndex);
321 case DetectUTF8Encoding(Tmp) of
324 if TZColumnInfo(ColumnsInfo[ColumnIndex-1]).ColumnType in [stString, stUnicodeString] then
325 TZColumnInfo(ColumnsInfo[ColumnIndex-1]).InternalColumnType := stUnicodeString
327 TZColumnInfo(ColumnsInfo[ColumnIndex-1]).InternalColumnType := stUnicodeStream;
328 Result := ZDbcUnicodeString(Tmp, zCP_UTF8)
332 if TZColumnInfo(ColumnsInfo[ColumnIndex-1]).ColumnType in [stString, stUnicodeString] then
333 TZColumnInfo(ColumnsInfo[ColumnIndex-1]).InternalColumnType := stString
335 TZColumnInfo(ColumnsInfo[ColumnIndex-1]).InternalColumnType := stAsciiStream;
336 Result := ZDbcUnicodeString(tmp, ConSettings^.ClientCodePage^.CP)
339 Result := ZDbcUnicodeString(tmp);
343 if TZColumnInfo(ColumnsInfo[ColumnIndex-1]).InternalColumnType in [stUnicodeString, stUnicodeStream] then
344 Result := ZDbcUnicodeString(InternalGetString(ColumnIndex), zCP_UTF8)
346 Result := ZDbcUnicodeString(InternalGetString(ColumnIndex), ConSettings^.ClientCodePage^.CP)
348 Result := WideString(InternalGetString(ColumnIndex));
352 Gets the value of the designated column in the current row
353 of this <code>ResultSet</code> object as
354 a <code>String</code> in the Java programming language.
356 @param columnIndex the first column is 1, the second is 2, ...
357 @return the column value; if the value is SQL <code>NULL</code>, the
358 value returned is <code>null</code>
360 function TZDBLibResultSet.InternalGetString(ColumnIndex: Integer): RawByteString;
367 CheckColumnIndex(ColumnIndex);
369 DL := FPlainDriver.dbDatLen(FHandle, ColumnIndex);
370 Data := FPlainDriver.dbdata(FHandle, ColumnIndex);
371 DT := DBLibColTypeCache[ColumnIndex];
372 LastWasNull := Data = nil;
375 if Assigned(Data) then
377 if (DT = FPlainDriver.GetVariables.datatypes[Z_SQLCHAR]) or
378 (DT = FPlainDriver.GetVariables.datatypes[Z_SQLTEXT]) then
380 while (DL > 0) and (PAnsiChar(NativeUint(Data) + NativeUint(DL - 1))^ = ' ') do
384 SetLength(Result, DL);
385 Move(Data^, PAnsiChar(Result)^, DL);
388 if (DT = FPlainDriver.GetVariables.datatypes[Z_SQLIMAGE]) then
390 SetLength(Result, DL);
391 Move(Data^, PAnsiChar(Result)^, DL);
394 SetLength(Result, 4001);
395 DL := FPlainDriver.dbconvert(FHandle, DT, Data, DL,
396 FPlainDriver.GetVariables.datatypes[Z_SQLCHAR], Pointer(PAnsiChar(Result)), Length(Result));
397 while (DL > 0) and (Result[DL] = ' ') do
399 SetLength(Result, DL);
404 FDBLibConnection.CheckDBLibError(lcOther, 'GETSTRING');
408 Gets the value of the designated column in the current row
409 of this <code>ResultSet</code> object as
410 a <code>boolean</code> in the Java programming language.
412 @param columnIndex the first column is 1, the second is 2, ...
413 @return the column value; if the value is SQL <code>NULL</code>, the
414 value returned is <code>false</code>
416 function TZDBLibResultSet.GetBoolean(ColumnIndex: Integer): Boolean;
423 CheckColumnIndex(ColumnIndex);
425 DL := FPlainDriver.dbdatlen(FHandle, ColumnIndex);
426 Data := FPlainDriver.dbdata(FHandle, ColumnIndex);
427 DT := DBLibColTypeCache[ColumnIndex];
428 LastWasNull := Data = nil;
431 if Assigned(Data) then
433 if DT = FPlainDriver.GetVariables.datatypes[Z_SQLBIT] then
434 Result := PBoolean(Data)^
437 FPlainDriver.dbconvert(FHandle, DT, Data, DL, FPlainDriver.GetVariables.datatypes[Z_SQLBIT],
438 @Result, SizeOf(Result));
441 FDBLibConnection.CheckDBLibError(lcOther, 'GETBOOLEAN');
445 Gets the value of the designated column in the current row
446 of this <code>ResultSet</code> object as
447 a <code>byte</code> in the Java programming language.
449 @param columnIndex the first column is 1, the second is 2, ...
450 @return the column value; if the value is SQL <code>NULL</code>, the
451 value returned is <code>0</code>
453 function TZDBLibResultSet.GetByte(ColumnIndex: Integer): Byte;
460 CheckColumnIndex(ColumnIndex);
462 DL := FPlainDriver.dbdatlen(FHandle, ColumnIndex);
463 Data := FPlainDriver.dbdata(FHandle, ColumnIndex);
464 DT := DBLibColTypeCache[ColumnIndex];
465 LastWasNull := Data = nil;
468 if Assigned(Data) then
470 if DT = FPlainDriver.GetVariables.datatypes[Z_SQLINT1] then
471 Result := PByte(Data)^
474 FPlainDriver.dbconvert(FHandle, DT, Data, DL, FPlainDriver.GetVariables.datatypes[Z_SQLINT1],
475 @Result, SizeOf(Result));
478 FDBLibConnection.CheckDBLibError(lcOther, 'GETBYTE');
482 Gets the value of the designated column in the current row
483 of this <code>ResultSet</code> object as
484 a <code>short</code> in the Java programming language.
486 @param columnIndex the first column is 1, the second is 2, ...
487 @return the column value; if the value is SQL <code>NULL</code>, the
488 value returned is <code>0</code>
490 function TZDBLibResultSet.GetShort(ColumnIndex: Integer): SmallInt;
497 CheckColumnIndex(ColumnIndex);
499 DL := FPlainDriver.dbdatlen(FHandle, ColumnIndex);
500 Data := FPlainDriver.dbdata(FHandle, ColumnIndex);
501 DT := DBLibColTypeCache[ColumnIndex];
502 LastWasNull := Data = nil;
505 if Assigned(Data) then
507 if DT = FPlainDriver.GetVariables.datatypes[Z_SQLINT2] then
508 Result := PSmallInt(Data)^
511 FPlainDriver.dbconvert(FHandle, DT, Data, DL, FPlainDriver.GetVariables.datatypes[Z_SQLINT2],
512 @Result, SizeOf(Result));
515 FDBLibConnection.CheckDBLibError(lcOther, 'GETSHORT');
519 Gets the value of the designated column in the current row
520 of this <code>ResultSet</code> object as
521 an <code>int</code> in the Java programming language.
523 @param columnIndex the first column is 1, the second is 2, ...
524 @return the column value; if the value is SQL <code>NULL</code>, the
525 value returned is <code>0</code>
527 function TZDBLibResultSet.GetInt(ColumnIndex: Integer): Integer;
534 CheckColumnIndex(ColumnIndex);
536 DL := FPlainDriver.dbdatlen(FHandle, ColumnIndex);
537 Data := FPlainDriver.dbdata(FHandle, ColumnIndex);
538 DT := DBLibColTypeCache[ColumnIndex];
539 LastWasNull := Data = nil;
542 if Assigned(Data) then
544 if DT = FPlainDriver.GetVariables.datatypes[Z_SQLINT4] then
545 Result := PLongint(Data)^
548 FPlainDriver.dbconvert(FHandle, DT, Data, DL, FPlainDriver.GetVariables.datatypes[Z_SQLINT4],
549 @Result, SizeOf(Result));
552 FDBLibConnection.CheckDBLibError(lcOther, 'GETINT');
556 Gets the value of the designated column in the current row
557 of this <code>ResultSet</code> object as
558 a <code>long</code> in the Java programming language.
560 @param columnIndex the first column is 1, the second is 2, ...
561 @return the column value; if the value is SQL <code>NULL</code>, the
562 value returned is <code>0</code>
564 function TZDBLibResultSet.GetLong(ColumnIndex: Integer): Int64;
566 Result := GetInt(ColumnIndex);
570 Gets the value of the designated column in the current row
571 of this <code>ResultSet</code> object as
572 a <code>float</code> in the Java programming language.
574 @param columnIndex the first column is 1, the second is 2, ...
575 @return the column value; if the value is SQL <code>NULL</code>, the
576 value returned is <code>0</code>
578 function TZDBLibResultSet.GetFloat(ColumnIndex: Integer): Single;
585 CheckColumnIndex(ColumnIndex);
587 DL := FPlainDriver.dbdatlen(FHandle, ColumnIndex);
588 Data := FPlainDriver.dbdata(FHandle, ColumnIndex);
589 DT := DBLibColTypeCache[ColumnIndex];
590 LastWasNull := Data = nil;
593 if Assigned(Data) then
595 if DT = FPlainDriver.GetVariables.datatypes[Z_SQLFLT4] then
596 Result := PSingle(Data)^
599 FPlainDriver.dbconvert(FHandle, DT, Data, DL, FPlainDriver.GetVariables.datatypes[Z_SQLFLT4],
600 @Result, SizeOf(Result));
603 FDBLibConnection.CheckDBLibError(lcOther, 'GETFLOAT');
607 Gets the value of the designated column in the current row
608 of this <code>ResultSet</code> object as
609 a <code>double</code> in the Java programming language.
611 @param columnIndex the first column is 1, the second is 2, ...
612 @return the column value; if the value is SQL <code>NULL</code>, the
613 value returned is <code>0</code>
615 function TZDBLibResultSet.GetDouble(ColumnIndex: Integer): Double;
622 CheckColumnIndex(ColumnIndex);
624 DL := FPlainDriver.dbdatlen(FHandle, ColumnIndex);
625 Data := FPlainDriver.dbdata(FHandle, ColumnIndex);
626 DT := DBLibColTypeCache[ColumnIndex];
627 LastWasNull := Data = nil;
630 if Assigned(Data) then
632 if DT = FPlainDriver.GetVariables.datatypes[Z_SQLFLT8] then
633 Result := PDouble(Data)^
636 FPlainDriver.dbconvert(FHandle, DT, Data, DL, FPlainDriver.GetVariables.datatypes[Z_SQLFLT8],
637 @Result, SizeOf(Result));
640 FDBLibConnection.CheckDBLibError(lcOther, 'GETDOUBLE');
644 Gets the value of the designated column in the current row
645 of this <code>ResultSet</code> object as
646 a <code>java.sql.BigDecimal</code> in the Java programming language.
648 @param columnIndex the first column is 1, the second is 2, ...
649 @param scale the number of digits to the right of the decimal point
650 @return the column value; if the value is SQL <code>NULL</code>, the
651 value returned is <code>null</code>
653 function TZDBLibResultSet.GetBigDecimal(ColumnIndex: Integer): Extended;
655 Result := GetDouble(ColumnIndex);
659 Gets the value of the designated column in the current row
660 of this <code>ResultSet</code> object as
661 a <code>byte</code> array in the Java programming language.
662 The bytes represent the raw values returned by the driver.
664 @param columnIndex the first column is 1, the second is 2, ...
665 @return the column value; if the value is SQL <code>NULL</code>, the
666 value returned is <code>null</code>
668 function TZDBLibResultSet.GetBytes(ColumnIndex: Integer): TByteDynArray;
674 CheckColumnIndex(ColumnIndex);
676 DL := FPlainDriver.dbdatlen(FHandle, ColumnIndex);
677 Data := FPlainDriver.dbdata(FHandle, ColumnIndex);
678 FDBLibConnection.CheckDBLibError(lcOther, 'GETBYTES');
679 LastWasNull := Data = nil;
681 SetLength(Result, DL);
682 if Assigned(Data) then
683 Move(PAnsiChar(Data)^, Result[0], DL);
687 Gets the value of the designated column in the current row
688 of this <code>ResultSet</code> object as
689 a <code>java.sql.Date</code> object in the Java programming language.
691 @param columnIndex the first column is 1, the second is 2, ...
692 @return the column value; if the value is SQL <code>NULL</code>, the
693 value returned is <code>null</code>
695 function TZDBLibResultSet.GetDate(ColumnIndex: Integer): TDateTime;
697 Result := System.Int(GetTimestamp(ColumnIndex));
701 Gets the value of the designated column in the current row
702 of this <code>ResultSet</code> object as
703 a <code>java.sql.Time</code> object in the Java programming language.
705 @param columnIndex the first column is 1, the second is 2, ...
706 @return the column value; if the value is SQL <code>NULL</code>, the
707 value returned is <code>null</code>
709 function TZDBLibResultSet.GetTime(ColumnIndex: Integer): TDateTime;
711 Result := Frac(GetTimestamp(ColumnIndex));
715 Gets the value of the designated column in the current row
716 of this <code>ResultSet</code> object as
717 a <code>java.sql.Timestamp</code> object in the Java programming language.
719 @param columnIndex the first column is 1, the second is 2, ...
720 @return the column value; if the value is SQL <code>NULL</code>, the
721 value returned is <code>null</code>
722 @exception SQLException if a database access error occurs
724 function TZDBLibResultSet.GetTimestamp(ColumnIndex: Integer): TDateTime;
729 TempDate: DBDATETIME;
730 tdsTempDate: TTDSDBDATETIME;
733 CheckColumnIndex(ColumnIndex);
735 DL := FPlainDriver.dbdatlen(FHandle, ColumnIndex);
736 Data := FPlainDriver.dbdata(FHandle, ColumnIndex);
737 DT := DBLibColTypeCache[ColumnIndex];
738 LastWasNull := Data = nil;
741 if Assigned(Data) then
743 if DT = FPlainDriver.GetVariables.datatypes[Z_SQLDATETIME] then
744 if FDBLibConnection.FreeTDS then //type diff
745 Result := PTDSDBDATETIME(Data)^.dtdays + 2 + (PTDSDBDATETIME(Data)^.dttime / 25920000)
747 Result := PDBDATETIME(Data)^.dtdays + 2 + (PDBDATETIME(Data)^.dttime / 25920000)
749 if FDBLibConnection.FreeTDS then //type diff
751 FPlainDriver.dbconvert(FHandle, DT, Data, DL, FPlainDriver.GetVariables.datatypes[Z_SQLDATETIME],
752 @tdsTempDate, SizeOf(tdsTempDate));
753 Result := tdsTempDate.dtdays + 2 + (tdsTempDate.dttime / 25920000);
757 FPlainDriver.dbconvert(FHandle, DT, Data, DL, FPlainDriver.GetVariables.datatypes[Z_SQLDATETIME],
758 @TempDate, SizeOf(TempDate));
759 Result := TempDate.dtdays + 2 + (TempDate.dttime / 25920000);
762 FDBLibConnection.CheckDBLibError(lcOther, 'GETTIMESTAMP');
766 Returns the value of the designated column in the current row
767 of this <code>ResultSet</code> object as a <code>Blob</code> object
768 in the Java programming language.
770 @param ColumnIndex the first column is 1, the second is 2, ...
771 @return a <code>Blob</code> object representing the SQL <code>BLOB</code> value in
774 function TZDBLibResultSet.GetBlob(ColumnIndex: Integer): IZBlob;
779 TempAnsi: RawByteString;
782 CheckColumnIndex(ColumnIndex);
783 CheckBlobColumn(ColumnIndex);
785 DL := FPlainDriver.dbdatlen(FHandle, ColumnIndex);
786 Data := FPlainDriver.dbdata(FHandle, ColumnIndex);
787 LastWasNull := Data = nil;
788 Result := TZAbstractBlob.CreateWithData(Data, DL, FDBLibConnection);
789 if (GetMetaData.GetColumnType(ColumnIndex) in [stAsciiStream, stUnicodeStream]) then
791 TempAnsi := Result.GetString;
792 if ( Length(TempAnsi) = 1) and (TempAnsi[1] = ' ') then
795 TempAnsi := {$IFDEF WITH_UNITANSISTRINGS}AnsiStrings.{$ENDIF}StringReplace(TempAnsi, #0, '', [rfReplaceAll]);
796 if (GetMetaData.GetColumnType(ColumnIndex) = stAsciiStream ) then
797 Result.SetString(ZEncoding.GetValidatedAnsiString(TempAnsi, ConSettings, True))
800 if TempAnsi = '' then
801 TempStream := TMemoryStream.Create
803 TempStream := ZEncoding.GetValidatedUnicodeStream(TempAnsi, ConSettings, True);
804 Result.SetStream(TempStream, True);
811 Moves the cursor to the given row number in
812 this <code>ResultSet</code> object.
814 <p>If the row number is positive, the cursor moves to
815 the given row number with respect to the
816 beginning of the result set. The first row is row 1, the second
819 <p>If the given row number is negative, the cursor moves to
820 an absolute row position with respect to
821 the end of the result set. For example, calling the method
822 <code>absolute(-1)</code> positions the
823 cursor on the last row; calling the method <code>absolute(-2)</code>
824 moves the cursor to the next-to-last row, and so on.
826 <p>An attempt to position the cursor beyond the first/last row in
827 the result set leaves the cursor before the first row or after
830 <p><B>Note:</B> Calling <code>absolute(1)</code> is the same
831 as calling <code>first()</code>. Calling <code>absolute(-1)</code>
832 is the same as calling <code>last()</code>.
834 @return <code>true</code> if the cursor is on the result set;
835 <code>false</code> otherwise
837 function TZDBLibResultSet.MoveAbsolute(Row: Integer): Boolean;
840 RaiseUnsupportedException;
844 Moves the cursor down one row from its current position.
845 A <code>ResultSet</code> cursor is initially positioned
846 before the first row; the first call to the method
847 <code>next</code> makes the first row the current row; the
848 second call makes the second row the current row, and so on.
850 <P>If an input stream is open for the current row, a call
851 to the method <code>next</code> will
852 implicitly close it. A <code>ResultSet</code> object's
853 warning chain is cleared when a new row is read.
855 @return <code>true</code> if the new current row is valid;
856 <code>false</code> if there are no more rows
858 function TZDBLibResultSet.Next: Boolean;
861 if FPlainDriver.GetProtocol = 'mssql' then
862 if FPlainDriver.dbDead(FHandle) then
864 //!!! maybe an error message other than dbconnection is dead should be raised
865 case FPlainDriver.dbnextrow(FHandle) of
866 REG_ROW: Result := True;
868 DBFAIL: FDBLibConnection.CheckDBLibError(lcOther, 'NEXT');
869 BUF_FULL: ;//should not happen because we are not using dblibc buffering.
871 // If a compute row is read, the computeid of the row is returned
877 { TZDBLibCachedResolver }
880 Creates a DBLib specific cached resolver object.
881 @param PlainDriver a native DBLib plain driver.
882 @param Handle a DBLib specific query handle.
883 @param Statement a related SQL statement object.
884 @param Metadata a resultset metadata reference.
886 constructor TZDBLibCachedResolver.Create(Statement: IZStatement;
887 Metadata: IZResultSetMetadata);
889 inherited Create(Statement, Metadata);
891 { Defines an index of autoincrement field. }
892 FAutoColumnIndex := -1;
896 Posts updates to database.
897 @param Sender a cached result set object.
898 @param UpdateType a type of updates.
899 @param OldRowAccessor an accessor object to old column values.
900 @param NewRowAccessor an accessor object to new column values.
902 procedure TZDBLibCachedResolver.PostUpdates(Sender: IZCachedResultSet;
903 UpdateType: TZRowUpdateType; OldRowAccessor, NewRowAccessor: TZRowAccessor);
905 Statement: IZStatement;
906 ResultSet: IZResultSet;
909 inherited PostUpdates(Sender, UpdateType, OldRowAccessor, NewRowAccessor);
911 { Defines an index of autoincrement field. }
912 if FAutoColumnIndex = -1 then
914 FAutoColumnIndex := 0;
915 for I := 1 to Metadata.GetColumnCount do
917 if Metadata.IsAutoIncrement(I) then
919 FAutoColumnIndex := I;
925 if (UpdateType = utInserted) and (FAutoColumnIndex > 0)
926 and OldRowAccessor.IsNull(FAutoColumnIndex) then
928 Statement := Connection.CreateStatement;
929 ResultSet := Statement.ExecuteQuery('SELECT @@IDENTITY');
931 if ResultSet.Next then
932 NewRowAccessor.SetLong(FAutoColumnIndex, ResultSet.GetLong(1));