00001 {*********************************************************}
00002 { }
00003 { Zeos Database Objects }
00004 { DBLib Resultset common functionality }
00005 { }
00006 { Originally written by Janos Fegyverneki }
00007 { }
00008 {*********************************************************}
00009
00010 {@********************************************************}
00011 { Copyright (c) 1999-2006 Zeos Development Group }
00012 { }
00013 { License Agreement: }
00014 { }
00015 { This library is distributed in the hope that it will be }
00016 { useful, but WITHOUT ANY WARRANTY; without even the }
00017 { implied warranty of MERCHANTABILITY or FITNESS FOR }
00018 { A PARTICULAR PURPOSE. See the GNU Lesser General }
00019 { Public License for more details. }
00020 { }
00021 { The source code of the ZEOS Libraries and packages are }
00022 { distributed under the Library GNU General Public }
00023 { License (see the file COPYING / COPYING.ZEOS) }
00024 { with the following modification: }
00025 { As a special exception, the copyright holders of this }
00026 { library give you permission to link this library with }
00027 { independent modules to produce an executable, }
00028 { regardless of the license terms of these independent }
00029 { modules, and to copy and distribute the resulting }
00030 { executable under terms of your choice, provided that }
00031 { you also meet, for each linked independent module, }
00032 { the terms and conditions of the license of that module. }
00033 { An independent module is a module which is not derived }
00034 { from or based on this library. If you modify this }
00035 { library, you may extend this exception to your version }
00036 { of the library, but you are not obligated to do so. }
00037 { If you do not wish to do so, delete this exception }
00038 { statement from your version. }
00039 { }
00040 { }
00041 { The project web site is located on: }
00042 { http:
00043 { http:
00044 { svn:
00045 { }
00046 { http:
00047 { http:
00048 { }
00049 { }
00050 { }
00051 { Zeos Development Group. }
00052 {********************************************************@}
00053
00054 unit ZDbcDbLibResultSet;
00055
00056 interface
00057
00058 {$I ZDbc.inc}
00059
00060 uses
00061 {$IFNDEF VER130BELOW}
00062 Types,
00063 DateUtils,
00064 {$ENDIF}
00065 Classes, SysUtils, ZSysUtils, ZDbcIntfs, ZDbcResultSet,
00066 ZCompatibility, ZDbcResultsetMetadata, ZDbcGenericResolver, ZDbcCachedResultSet,
00067 ZDbcCache, ZDbcDBLib, ZPlainDBLibDriver;
00068
00069 type
00070 {** Implements DBLib ResultSet. }
00071 TZDBLibResultSet = class(TZAbstractResultSet)
00072 private
00073 FSQL: string;
00074 FHandle: PDBPROCESS;
00075 DBLibColTypeCache: TSmallIntDynArray;
00076 DBLibColumnCount: Integer;
00077 procedure CheckColumnIndex(ColumnIndex: Integer);
00078 protected
00079 FDBLibConnection: IZDBLibConnection;
00080 FPlainDriver: IZDBLibPlainDriver;
00081 procedure Open; override;
00082 public
00083 constructor Create(Statement: IZStatement; SQL: string);
00084 destructor Destroy; override;
00085
00086 procedure Close; override;
00087
00088 function IsNull(ColumnIndex: Integer): Boolean; override;
00089 function GetString(ColumnIndex: Integer): string; override;
00090 function GetBoolean(ColumnIndex: Integer): Boolean; override;
00091 function GetByte(ColumnIndex: Integer): ShortInt; override;
00092 function GetShort(ColumnIndex: Integer): SmallInt; override;
00093 function GetInt(ColumnIndex: Integer): Integer; override;
00094 function GetLong(ColumnIndex: Integer): Int64; override;
00095 function GetFloat(ColumnIndex: Integer): Single; override;
00096 function GetDouble(ColumnIndex: Integer): Double; override;
00097 function GetBigDecimal(ColumnIndex: Integer): Extended; override;
00098 function GetBytes(ColumnIndex: Integer): TByteDynArray; override;
00099 function GetDate(ColumnIndex: Integer): TDateTime; override;
00100 function GetTime(ColumnIndex: Integer): TDateTime; override;
00101 function GetTimestamp(ColumnIndex: Integer): TDateTime; override;
00102 function GetBlob(ColumnIndex: Integer): IZBlob; override;
00103
00104 function MoveAbsolute(Row: Integer): Boolean; override;
00105 function Next: Boolean; override;
00106 end;
00107
00108 {** Implements a cached resolver with mssql and sybase specific functionality. }
00109 TZDBLibCachedResolver = class (TZGenericCachedResolver, IZCachedResolver)
00110 private
00111 FAutoColumnIndex: Integer;
00112 public
00113 constructor Create(Statement: IZStatement; Metadata: IZResultSetMetadata);
00114
00115 procedure PostUpdates(Sender: IZCachedResultSet; UpdateType: TZRowUpdateType;
00116 OldRowAccessor, NewRowAccessor: TZRowAccessor); override;
00117 end;
00118
00119 implementation
00120
00121 uses ZMessages, ZDbcLogging, ZDbcDBLibUtils;
00122
00123 { TZDBLibResultSet }
00124
00125 {**
00126 Constructs this object, assignes main properties and
00127 opens the record set.
00128 @param Statement a related SQL statement object.
00129 @param Handle a DBLib specific query handle.
00130 }
00131 constructor TZDBLibResultSet.Create(Statement: IZStatement; SQL: string);
00132 begin
00133 inherited Create(Statement, SQL, nil);
00134 Statement.GetConnection.QueryInterface(IZDBLibConnection, FDBLibConnection);
00135 FPlainDriver := FDBLibConnection.GetPlainDriver;
00136 FHandle := FDBLibConnection.GetConnectionHandle;
00137 FSQL := SQL;
00138
00139 Open;
00140 end;
00141
00142 {**
00143 Destroys this object and cleanups the memory.
00144 }
00145 destructor TZDBLibResultSet.Destroy;
00146 begin
00147 { TODO -ofjanos -cGeneral : Does it need close here? }
00148 Close;
00149 inherited Destroy;
00150 end;
00151
00152 {**
00153 Opens this recordset.
00154 }
00155 procedure TZDBLibResultSet.Open;
00156 var
00157 I: Integer;
00158 ColumnInfo: TZColumnInfo;
00159 ColName: string;
00160 ColType: Integer;
00161 begin
00162
00163 if FPlainDriver.dbCmdRow(FHandle) <> DBSUCCEED then
00164 raise EZSQLException.Create(SCanNotRetrieveResultSetData);
00165
00166 { Fills the column info }
00167 ColumnsInfo.Clear;
00168 DBLibColumnCount := FPlainDriver.dbnumcols(FHandle);
00169 SetLength(DBLibColTypeCache, DBLibColumnCount + 1);
00170 for I := 1 to DBLibColumnCount do
00171 begin
00172 ColName := FPlainDriver.dbColName(FHandle, I);
00173 ColType := FPlainDriver.dbColtype(FHandle, I);
00174 ColumnInfo := TZColumnInfo.Create;
00175
00176 ColumnInfo.ColumnLabel := ColName;
00177 ColumnInfo.ColumnName := ColName;
00178 ColumnInfo.ColumnType := ConvertDBLibToSqlType(ColType);
00179 ColumnInfo.Currency := ColType in [SQLMONEY, SQLMONEY4, SQLMONEYN];
00180 ColumnInfo.Precision := FPlainDriver.dbCollen(FHandle, I);
00181 ColumnInfo.Scale := 0;
00182 if ColType = SQLINT1 then
00183 ColumnInfo.Signed := False
00184 else
00185 ColumnInfo.Signed := True;
00186
00187 ColumnsInfo.Add(ColumnInfo);
00188
00189 DBLibColTypeCache[I] := ColType;
00190 end;
00191 inherited Open;
00192 end;
00193
00194 {**
00195 Releases this <code>ResultSet</code> object's database and
00196 JDBC resources immediately instead of waiting for
00197 this to happen when it is automatically closed.
00198
00199 <P><B>Note:</B> A <code>ResultSet</code> object
00200 is automatically closed by the
00201 <code>Statement</code> object that generated it when
00202 that <code>Statement</code> object is closed,
00203 re-executed, or is used to retrieve the next result from a
00204 sequence of multiple results. A <code>ResultSet</code> object
00205 is also automatically closed when it is garbage collected.
00206 }
00207 procedure TZDBLibResultSet.Close;
00208 begin
00209 { TODO -ofjanos -cGeneral : Maybe it needs a dbcanquery here. }
00210 // if Assigned(FHandle) then
00211 // if not FPlainDriver.dbDead(FHandle) then
00212 // if FPlainDriver.dbCanQuery(FHandle) <> DBSUCCEED then
00213 // FDBLibConnection.CheckDBLibError(lcDisconnect, 'CLOSE QUERY');
00214 FHandle := nil;
00215 SetLength(DBLibColTypeCache, 0);
00216 inherited Close;
00217 end;
00218
00219 {**
00220 Checks if the columnindex is in the proper range.
00221 An exception is generated if somthing is not ok.
00222
00223 @param columnIndex the first column is 1, the second is 2, ...
00224 }
00225 procedure TZDBLibResultSet.CheckColumnIndex(ColumnIndex: Integer);
00226 begin
00227 if (ColumnIndex > DBLibColumnCount) or (ColumnIndex < 1) then
00228 begin
00229 raise EZSQLException.Create(
00230 Format(SColumnIsNotAccessable, [ColumnIndex]));
00231 end;
00232 end;
00233
00234 {**
00235 Indicates if the value of the designated column in the current row
00236 of this <code>ResultSet</code> object is Null.
00237
00238 @param columnIndex the first column is 1, the second is 2, ...
00239 @return if the value is SQL <code>NULL</code>, the
00240 value returned is <code>true</code>. <code>false</code> otherwise.
00241 }
00242 function TZDBLibResultSet.IsNull(ColumnIndex: Integer): Boolean;
00243 begin
00244 CheckClosed;
00245 CheckColumnIndex(ColumnIndex);
00246 Result := FPlainDriver.dbData(FHandle, ColumnIndex) = nil;
00247 end;
00248
00249 {**
00250 Gets the value of the designated column in the current row
00251 of this <code>ResultSet</code> object as
00252 a <code>String</code> in the Java programming language.
00253
00254 @param columnIndex the first column is 1, the second is 2, ...
00255 @return the column value; if the value is SQL <code>NULL</code>, the
00256 value returned is <code>null</code>
00257 }
00258 function TZDBLibResultSet.GetString(ColumnIndex: Integer): string;
00259 var
00260 DL: Integer;
00261 Data: Pointer;
00262 DT: Integer;
00263 begin
00264 CheckClosed;
00265 CheckColumnIndex(ColumnIndex);
00266
00267 DL := FPlainDriver.dbDatLen(FHandle, ColumnIndex);
00268 Data := FPlainDriver.dbdata(FHandle, ColumnIndex);
00269 DT := DBLibColTypeCache[ColumnIndex];
00270 LastWasNull := Data = nil;
00271
00272 if Assigned(Data) then
00273 begin
00274 case DT of
00275 SQLCHAR, SQLTEXT:
00276 begin
00277 while (DL > 0) and (PChar(Integer(Data) + DL - 1)^ = ' ') do Dec(DL);
00278 if DL > 0 then
00279 begin
00280 SetLength(Result, DL);
00281 Move(Data^, PChar(Result)^, DL);
00282 end;
00283 end;
00284 SQLIMAGE:
00285 begin
00286 SetLength(Result, DL);
00287 Move(Data^, PChar(Result)^, DL);
00288 end;
00289 else
00290 begin
00291 SetLength(Result, 4001);
00292 DL := FPlainDriver.dbconvert(FHandle, DT, Data, DL, SQLCHAR, Pointer(PChar(Result)), Length(Result));
00293 while (DL > 0) and (Result[DL] = ' ') do Dec(DL);
00294 SetLength(Result, DL);
00295 end;
00296 end;
00297 end
00298 else
00299 Result := '';
00300 FDBLibConnection.CheckDBLibError(lcOther, 'GETSTRING');
00301 end;
00302
00303 {**
00304 Gets the value of the designated column in the current row
00305 of this <code>ResultSet</code> object as
00306 a <code>boolean</code> in the Java programming language.
00307
00308 @param columnIndex the first column is 1, the second is 2, ...
00309 @return the column value; if the value is SQL <code>NULL</code>, the
00310 value returned is <code>false</code>
00311 }
00312 function TZDBLibResultSet.GetBoolean(ColumnIndex: Integer): Boolean;
00313 var
00314 DL: Integer;
00315 Data: Pointer;
00316 DT: Integer;
00317 begin
00318 CheckClosed;
00319 CheckColumnIndex(ColumnIndex);
00320
00321 DL := FPlainDriver.dbdatlen(FHandle, ColumnIndex);
00322 Data := FPlainDriver.dbdata(FHandle, ColumnIndex);
00323 DT := DBLibColTypeCache[ColumnIndex];
00324 LastWasNull := Data = nil;
00325
00326 Result := False;
00327 if Assigned(Data) then
00328 begin
00329 if DT = SQLBIT then
00330 Result := PBoolean(Data)^
00331 else
00332 begin
00333 FPlainDriver.dbconvert(FHandle, DT, Data, DL, SQLBIT,
00334 @Result, SizeOf(Result));
00335 end;
00336 end;
00337 FDBLibConnection.CheckDBLibError(lcOther, 'GETBOOLEAN');
00338 end;
00339
00340 {**
00341 Gets the value of the designated column in the current row
00342 of this <code>ResultSet</code> object as
00343 a <code>byte</code> in the Java programming language.
00344
00345 @param columnIndex the first column is 1, the second is 2, ...
00346 @return the column value; if the value is SQL <code>NULL</code>, the
00347 value returned is <code>0</code>
00348 }
00349 function TZDBLibResultSet.GetByte(ColumnIndex: Integer): ShortInt;
00350 var
00351 DL: Integer;
00352 Data: Pointer;
00353 DT: Integer;
00354 begin
00355 CheckClosed;
00356 CheckColumnIndex(ColumnIndex);
00357
00358 DL := FPlainDriver.dbdatlen(FHandle, ColumnIndex);
00359 Data := FPlainDriver.dbdata(FHandle, ColumnIndex);
00360 DT := DBLibColTypeCache[ColumnIndex];
00361 LastWasNull := Data = nil;
00362
00363 Result := 0;
00364 if Assigned(Data) then
00365 begin
00366 if DT = SQLINT1 then
00367 Result := PShortInt(Data)^
00368 else
00369 begin
00370 FPlainDriver.dbconvert(FHandle, DT, Data, DL, SQLINT1,
00371 @Result, SizeOf(Result));
00372 end;
00373 end;
00374 FDBLibConnection.CheckDBLibError(lcOther, 'GETBYTE');
00375 end;
00376
00377 {**
00378 Gets the value of the designated column in the current row
00379 of this <code>ResultSet</code> object as
00380 a <code>short</code> in the Java programming language.
00381
00382 @param columnIndex the first column is 1, the second is 2, ...
00383 @return the column value; if the value is SQL <code>NULL</code>, the
00384 value returned is <code>0</code>
00385 }
00386 function TZDBLibResultSet.GetShort(ColumnIndex: Integer): SmallInt;
00387 var
00388 DL: Integer;
00389 Data: Pointer;
00390 DT: Integer;
00391 begin
00392 CheckClosed;
00393 CheckColumnIndex(ColumnIndex);
00394
00395 DL := FPlainDriver.dbdatlen(FHandle, ColumnIndex);
00396 Data := FPlainDriver.dbdata(FHandle, ColumnIndex);
00397 DT := DBLibColTypeCache[ColumnIndex];
00398 LastWasNull := Data = nil;
00399
00400 Result := 0;
00401 if Assigned(Data) then
00402 begin
00403 if DT = SQLINT2 then
00404 Result := PSmallInt(Data)^
00405 else
00406 begin
00407 FPlainDriver.dbconvert(FHandle, DT, Data, DL, SQLINT2,
00408 @Result, SizeOf(Result));
00409 end;
00410 end;
00411 FDBLibConnection.CheckDBLibError(lcOther, 'GETSHORT');
00412 end;
00413
00414 {**
00415 Gets the value of the designated column in the current row
00416 of this <code>ResultSet</code> object as
00417 an <code>int</code> in the Java programming language.
00418
00419 @param columnIndex the first column is 1, the second is 2, ...
00420 @return the column value; if the value is SQL <code>NULL</code>, the
00421 value returned is <code>0</code>
00422 }
00423 function TZDBLibResultSet.GetInt(ColumnIndex: Integer): Integer;
00424 var
00425 DL: Integer;
00426 Data: Pointer;
00427 DT: Integer;
00428 begin
00429 CheckClosed;
00430 CheckColumnIndex(ColumnIndex);
00431
00432 DL := FPlainDriver.dbdatlen(FHandle, ColumnIndex);
00433 Data := FPlainDriver.dbdata(FHandle, ColumnIndex);
00434 DT := DBLibColTypeCache[ColumnIndex];
00435 LastWasNull := Data = nil;
00436
00437 Result := 0;
00438 if Assigned(Data) then
00439 begin
00440 if DT = SQLINT4 then
00441 Result := PLongint(Data)^
00442 else
00443 begin
00444 FPlainDriver.dbconvert(FHandle, DT, Data, DL, SQLINT4,
00445 @Result, SizeOf(Result));
00446 end;
00447 end;
00448 FDBLibConnection.CheckDBLibError(lcOther, 'GETINT');
00449 end;
00450
00451 {**
00452 Gets the value of the designated column in the current row
00453 of this <code>ResultSet</code> object as
00454 a <code>long</code> in the Java programming language.
00455
00456 @param columnIndex the first column is 1, the second is 2, ...
00457 @return the column value; if the value is SQL <code>NULL</code>, the
00458 value returned is <code>0</code>
00459 }
00460 function TZDBLibResultSet.GetLong(ColumnIndex: Integer): Int64;
00461 begin
00462 Result := GetInt(ColumnIndex);
00463 end;
00464
00465 {**
00466 Gets the value of the designated column in the current row
00467 of this <code>ResultSet</code> object as
00468 a <code>float</code> in the Java programming language.
00469
00470 @param columnIndex the first column is 1, the second is 2, ...
00471 @return the column value; if the value is SQL <code>NULL</code>, the
00472 value returned is <code>0</code>
00473 }
00474 function TZDBLibResultSet.GetFloat(ColumnIndex: Integer): Single;
00475 var
00476 DL: Integer;
00477 Data: Pointer;
00478 DT: Integer;
00479 begin
00480 CheckClosed;
00481 CheckColumnIndex(ColumnIndex);
00482
00483 DL := FPlainDriver.dbdatlen(FHandle, ColumnIndex);
00484 Data := FPlainDriver.dbdata(FHandle, ColumnIndex);
00485 DT := DBLibColTypeCache[ColumnIndex];
00486 LastWasNull := Data = nil;
00487
00488 Result := 0;
00489 if Assigned(Data) then
00490 begin
00491 if DT = SQLFLT4 then
00492 Result := PSingle(Data)^
00493 else
00494 begin
00495 FPlainDriver.dbconvert(FHandle, DT, Data, DL, SQLFLT4,
00496 @Result, SizeOf(Result));
00497 end;
00498 end;
00499 FDBLibConnection.CheckDBLibError(lcOther, 'GETFLOAT');
00500 end;
00501
00502 {**
00503 Gets the value of the designated column in the current row
00504 of this <code>ResultSet</code> object as
00505 a <code>double</code> in the Java programming language.
00506
00507 @param columnIndex the first column is 1, the second is 2, ...
00508 @return the column value; if the value is SQL <code>NULL</code>, the
00509 value returned is <code>0</code>
00510 }
00511 function TZDBLibResultSet.GetDouble(ColumnIndex: Integer): Double;
00512 var
00513 DL: Integer;
00514 Data: Pointer;
00515 DT: Integer;
00516 begin
00517 CheckClosed;
00518 CheckColumnIndex(ColumnIndex);
00519
00520 DL := FPlainDriver.dbdatlen(FHandle, ColumnIndex);
00521 Data := FPlainDriver.dbdata(FHandle, ColumnIndex);
00522 DT := DBLibColTypeCache[ColumnIndex];
00523 LastWasNull := Data = nil;
00524
00525 Result := 0;
00526 if Assigned(Data) then
00527 begin
00528 if DT = SQLFLT8 then
00529 Result := PDouble(Data)^
00530 else
00531 begin
00532 FPlainDriver.dbconvert(FHandle, DT, Data, DL, SQLFLT8,
00533 @Result, SizeOf(Result));
00534 end;
00535 end;
00536 FDBLibConnection.CheckDBLibError(lcOther, 'GETDOUBLE');
00537 end;
00538
00539 {**
00540 Gets the value of the designated column in the current row
00541 of this <code>ResultSet</code> object as
00542 a <code>java.sql.BigDecimal</code> in the Java programming language.
00543
00544 @param columnIndex the first column is 1, the second is 2, ...
00545 @param scale the number of digits to the right of the decimal point
00546 @return the column value; if the value is SQL <code>NULL</code>, the
00547 value returned is <code>null</code>
00548 }
00549 function TZDBLibResultSet.GetBigDecimal(ColumnIndex: Integer): Extended;
00550 begin
00551 Result := GetDouble(ColumnIndex);
00552 end;
00553
00554 {**
00555 Gets the value of the designated column in the current row
00556 of this <code>ResultSet</code> object as
00557 a <code>byte</code> array in the Java programming language.
00558 The bytes represent the raw values returned by the driver.
00559
00560 @param columnIndex the first column is 1, the second is 2, ...
00561 @return the column value; if the value is SQL <code>NULL</code>, the
00562 value returned is <code>null</code>
00563 }
00564 function TZDBLibResultSet.GetBytes(ColumnIndex: Integer): TByteDynArray;
00565 var
00566 DL: Integer;
00567 Data: Pointer;
00568 begin
00569 CheckClosed;
00570 CheckColumnIndex(ColumnIndex);
00571
00572 DL := FPlainDriver.dbdatlen(FHandle, ColumnIndex);
00573 Data := FPlainDriver.dbdata(FHandle, ColumnIndex);
00574 FDBLibConnection.CheckDBLibError(lcOther, 'GETBYTES');
00575 LastWasNull := Data = nil;
00576
00577 SetLength(Result, DL);
00578 if Assigned(Data) then
00579 Move(PChar(Data)^, Result[0], DL);
00580 end;
00581
00582 {**
00583 Gets the value of the designated column in the current row
00584 of this <code>ResultSet</code> object as
00585 a <code>java.sql.Date</code> object in the Java programming language.
00586
00587 @param columnIndex the first column is 1, the second is 2, ...
00588 @return the column value; if the value is SQL <code>NULL</code>, the
00589 value returned is <code>null</code>
00590 }
00591 function TZDBLibResultSet.GetDate(ColumnIndex: Integer): TDateTime;
00592 begin
00593 Result := Int(GetTimestamp(ColumnIndex));
00594 end;
00595
00596 {**
00597 Gets the value of the designated column in the current row
00598 of this <code>ResultSet</code> object as
00599 a <code>java.sql.Time</code> object in the Java programming language.
00600
00601 @param columnIndex the first column is 1, the second is 2, ...
00602 @return the column value; if the value is SQL <code>NULL</code>, the
00603 value returned is <code>null</code>
00604 }
00605 function TZDBLibResultSet.GetTime(ColumnIndex: Integer): TDateTime;
00606 begin
00607 Result := Frac(GetTimestamp(ColumnIndex));
00608 end;
00609
00610 {**
00611 Gets the value of the designated column in the current row
00612 of this <code>ResultSet</code> object as
00613 a <code>java.sql.Timestamp</code> object in the Java programming language.
00614
00615 @param columnIndex the first column is 1, the second is 2, ...
00616 @return the column value; if the value is SQL <code>NULL</code>, the
00617 value returned is <code>null</code>
00618 @exception SQLException if a database access error occurs
00619 }
00620 function TZDBLibResultSet.GetTimestamp(ColumnIndex: Integer): TDateTime;
00621 var
00622 DL: Integer;
00623 Data: Pointer;
00624 DT: Integer;
00625 TempDate: DBDATETIME;
00626 begin
00627 CheckClosed;
00628 CheckColumnIndex(ColumnIndex);
00629
00630 DL := FPlainDriver.dbdatlen(FHandle, ColumnIndex);
00631 Data := FPlainDriver.dbdata(FHandle, ColumnIndex);
00632 DT := DBLibColTypeCache[ColumnIndex];
00633 LastWasNull := Data = nil;
00634
00635 Result := 0;
00636 if Assigned(Data) then
00637 begin
00638 if DT = SQLDATETIME then
00639 Move(Data^, TempDate, SizeOf(TempDate))
00640 else
00641 begin
00642 FPlainDriver.dbconvert(FHandle, DT, Data, DL, SQLDATETIME,
00643 @TempDate, SizeOf(TempDate));
00644 end;
00645 Result := TempDate.dtdays + 2 + (TempDate.dttime / 25920000);
00646 //Perfect conversion no need to crack and reencode the date.
00647 end;
00648 FDBLibConnection.CheckDBLibError(lcOther, 'GETTIMESTAMP');
00649 end;
00650
00651 {**
00652 Returns the value of the designated column in the current row
00653 of this <code>ResultSet</code> object as a <code>Blob</code> object
00654 in the Java programming language.
00655
00656 @param ColumnIndex the first column is 1, the second is 2, ...
00657 @return a <code>Blob</code> object representing the SQL <code>BLOB</code> value in
00658 the specified column
00659 }
00660 function TZDBLibResultSet.GetBlob(ColumnIndex: Integer): IZBlob;
00661 var
00662 DL: Integer;
00663 Data: Pointer;
00664 begin
00665 CheckClosed;
00666 CheckColumnIndex(ColumnIndex);
00667 CheckBlobColumn(ColumnIndex);
00668
00669 DL := FPlainDriver.dbdatlen(FHandle, ColumnIndex);
00670 Data := FPlainDriver.dbdata(FHandle, ColumnIndex);
00671 LastWasNull := Data = nil;
00672 Result := TZAbstractBlob.CreateWithData(Data, DL);
00673 end;
00674
00675 {**
00676 Moves the cursor to the given row number in
00677 this <code>ResultSet</code> object.
00678
00679 <p>If the row number is positive, the cursor moves to
00680 the given row number with respect to the
00681 beginning of the result set. The first row is row 1, the second
00682 is row 2, and so on.
00683
00684 <p>If the given row number is negative, the cursor moves to
00685 an absolute row position with respect to
00686 the end of the result set. For example, calling the method
00687 <code>absolute(-1)</code> positions the
00688 cursor on the last row; calling the method <code>absolute(-2)</code>
00689 moves the cursor to the next-to-last row, and so on.
00690
00691 <p>An attempt to position the cursor beyond the first/last row in
00692 the result set leaves the cursor before the first row or after
00693 the last row.
00694
00695 <p><B>Note:</B> Calling <code>absolute(1)</code> is the same
00696 as calling <code>first()</code>. Calling <code>absolute(-1)</code>
00697 is the same as calling <code>last()</code>.
00698
00699 @return <code>true</code> if the cursor is on the result set;
00700 <code>false</code> otherwise
00701 }
00702 function TZDBLibResultSet.MoveAbsolute(Row: Integer): Boolean;
00703 begin
00704 Result := False;
00705 RaiseUnsupportedException;
00706 end;
00707
00708 {**
00709 Moves the cursor down one row from its current position.
00710 A <code>ResultSet</code> cursor is initially positioned
00711 before the first row; the first call to the method
00712 <code>next</code> makes the first row the current row; the
00713 second call makes the second row the current row, and so on.
00714
00715 <P>If an input stream is open for the current row, a call
00716 to the method <code>next</code> will
00717 implicitly close it. A <code>ResultSet</code> object's
00718 warning chain is cleared when a new row is read.
00719
00720 @return <code>true</code> if the new current row is valid;
00721 <code>false</code> if there are no more rows
00722 }
00723 function TZDBLibResultSet.Next: Boolean;
00724 begin
00725 Result := False;
00726 if FPlainDriver.GetProtocol = 'mssql' then
00727 if FPlainDriver.dbDead(FHandle) then
00728 Exit;
00729
00730 case FPlainDriver.dbnextrow(FHandle) of
00731 REG_ROW: Result := True;
00732 NO_MORE_ROWS: ;
00733 DBFAIL: FDBLibConnection.CheckDBLibError(lcOther, 'NEXT');
00734 BUF_FULL: ;
00735 else
00736
00737 Result := False;
00738 end;
00739 end;
00740
00741
00742 { TZDBLibCachedResolver }
00743
00744 {**
00745 Creates a DBLib specific cached resolver object.
00746 @param PlainDriver a native DBLib plain driver.
00747 @param Handle a DBLib specific query handle.
00748 @param Statement a related SQL statement object.
00749 @param Metadata a resultset metadata reference.
00750 }
00751 constructor TZDBLibCachedResolver.Create(Statement: IZStatement;
00752 Metadata: IZResultSetMetadata);
00753 begin
00754 inherited Create(Statement, Metadata);
00755
00756 { Defines an index of autoincrement field. }
00757 FAutoColumnIndex := -1;
00758 end;
00759
00760 {**
00761 Posts updates to database.
00762 @param Sender a cached result set object.
00763 @param UpdateType a type of updates.
00764 @param OldRowAccessor an accessor object to old column values.
00765 @param NewRowAccessor an accessor object to new column values.
00766 }
00767 procedure TZDBLibCachedResolver.PostUpdates(Sender: IZCachedResultSet;
00768 UpdateType: TZRowUpdateType; OldRowAccessor, NewRowAccessor: TZRowAccessor);
00769 var
00770 Statement: IZStatement;
00771 ResultSet: IZResultSet;
00772 I: Integer;
00773 begin
00774 inherited PostUpdates(Sender, UpdateType, OldRowAccessor, NewRowAccessor);
00775
00776 { Defines an index of autoincrement field. }
00777 if FAutoColumnIndex = -1 then
00778 begin
00779 FAutoColumnIndex := 0;
00780 for I := 1 to Metadata.GetColumnCount do
00781 begin
00782 if Metadata.IsAutoIncrement(I) then
00783 begin
00784 FAutoColumnIndex := I;
00785 Break;
00786 end;
00787 end;
00788 end;
00789
00790 if (UpdateType = utInserted) and (FAutoColumnIndex > 0)
00791 and OldRowAccessor.IsNull(FAutoColumnIndex) then
00792 begin
00793 Statement := Connection.CreateStatement;
00794 ResultSet := Statement.ExecuteQuery('SELECT @@IDENTITY');
00795 try
00796 if ResultSet.Next then
00797 NewRowAccessor.SetLong(FAutoColumnIndex, ResultSet.GetLong(1));
00798 finally
00799 ResultSet.Close;
00800 Statement.Close;
00801 end;
00802 end;
00803 end;
00804
00805
00806
00807 end.