zeoslib  UNKNOWN
 All Files
ZDbcCachedResultSet.pas
Go to the documentation of this file.
1 {*********************************************************}
2 { }
3 { Zeos Database Objects }
4 { Caching Classes and Interfaces }
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 ZDbcCachedResultSet;
53 
54 interface
55 
56 {$I ZDbc.inc}
57 
58 uses
59  Types, Classes, {$IFDEF MSEgui}mclasses,{$ENDIF} SysUtils, Contnrs,
60  ZClasses, ZDbcIntfs, ZDbcResultSet, ZDbcCache, ZCompatibility;
61 
62 type
63  // Forward declarations.
64  IZCachedResultSet = interface;
65 
66  {** Resolver to post updates. }
67  IZCachedResolver = interface (IZInterface)
68  ['{546ED716-BB88-468C-8CCE-D7111CF5E1EF}']
69 
70  procedure CalculateDefaults(Sender: IZCachedResultSet;
71  RowAccessor: TZRowAccessor);
72  procedure PostUpdates(Sender: IZCachedResultSet; UpdateType: TZRowUpdateType;
73  OldRowAccessor, NewRowAccessor: TZRowAccessor);
74  {BEGIN of PATCH [1185969]: Do tasks after posting updates. ie: Updating AutoInc fields in MySQL }
75  procedure UpdateAutoIncrementFields(Sender: IZCachedResultSet; UpdateType: TZRowUpdateType;
76  OldRowAccessor, NewRowAccessor: TZRowAccessor; Resolver: IZCachedResolver);
77  {END of PATCH [1185969]: Do tasks after posting updates. ie: Updating AutoInc fields in MySQL }
78  procedure RefreshCurrentRow(Sender: IZCachedResultSet;RowAccessor: TZRowAccessor); //FOS+ 07112006
79  end;
80 
81  {** Represents a cached result set. }
82  IZCachedResultSet = interface (IZResultSet)
83  ['{BAF24A92-C8CE-4AB4-AEBC-3D4A9BCB0946}']
84 
85  function GetResolver: IZCachedResolver;
86  procedure SetResolver(Resolver: IZCachedResolver);
87 
88  {BEGIN PATCH [1214009] Calc Defaults in TZUpdateSQL and Added Methods to GET and SET the database Native Resolver
89  will help to implemented feature to Calculate default values in TZUpdateSQL
90  comment: add this properties to get the original Resolver
91  this will be useful whn using TZUpdateSQL //added by fduenas
92  }
93  function GetNativeResolver: IZCachedResolver;
94  {END PATCH [1214009] CalcDefaults in TZUpdateSQL and Added Methods to GET the DB NativeResolver}
95 
96  function IsCachedUpdates: Boolean;
97  procedure SetCachedUpdates(Value: Boolean);
98  function IsPendingUpdates: Boolean;
99 
100  procedure PostUpdates;
101  procedure CancelUpdates;
102  procedure PostUpdatesCached;
103  procedure DisposeCachedUpdates;
104  procedure RevertRecord;
105  procedure MoveToInitialRow;
106  procedure RefreshRow; // FOS+ 071106
107  end;
108 
109  {** Implements cached ResultSet. }
110  TZAbstractCachedResultSet = class (TZAbstractResultSet, IZCachedResultSet)
111  private
112  FCachedUpdates: Boolean;
113  FRowsList: TList;
114  FInitialRowsList: TList;
115  FCurrentRowsList: TList;
116  FSelectedRow: PZRowBuffer;
117  FUpdatedRow: PZRowBuffer;
118  FInsertedRow: PZRowBuffer;
119  FRowAccessor: TZRowAccessor;
120  FNewRowAccessor: TZRowAccessor;
121  FOldRowAccessor: TZRowAccessor;
122  FNextRowIndex: Integer;
123  FResolver: IZCachedResolver;
124  {BEGIN PATCH [1214009] CalcDefaults in TZUpdateSQL and Added Methods to GET the DB NativeResolver}
125  FNativeResolver: IZCachedResolver;
126  {END PATCH [1214009] CalcDefaults in TZUpdateSQL and Added Methods to GET the DB NativeResolver}
127  protected
128  procedure CheckAvailable;
129  procedure CheckUpdatable;
130  procedure Open; override;
131  function GetNextRowIndex: Integer;
132 
133  procedure CalculateRowDefaults(RowAccessor: TZRowAccessor); virtual;
134  procedure PostRowUpdates(OldRowAccessor,
135  NewRowAccessor: TZRowAccessor); virtual;
136  function LocateRow(RowsList: TList; RowIndex: Integer): Integer;
137  function AppendRow(Row: PZRowBuffer): PZRowBuffer;
138  procedure PrepareRowForUpdates;
139 
140  property CachedUpdates: Boolean read FCachedUpdates write FCachedUpdates;
141  property RowsList: TList read FRowsList write FRowsList;
142  property InitialRowsList: TList read FInitialRowsList
143  write FInitialRowsList;
144  property CurrentRowsList: TList read FCurrentRowsList
145  write FCurrentRowsList;
146  property SelectedRow: PZRowBuffer read FSelectedRow write FSelectedRow;
147  property UpdatedRow: PZRowBuffer read FUpdatedRow write FUpdatedRow;
148  property InsertedRow: PZRowBuffer read FInsertedRow write FInsertedRow;
149  property RowAccessor: TZRowAccessor read FRowAccessor write FRowAccessor;
150  property OldRowAccessor: TZRowAccessor read FOldRowAccessor
151  write FOldRowAccessor;
152  property NewRowAccessor: TZRowAccessor read FNewRowAccessor
153  write FNewRowAccessor;
154  property NextRowIndex: Integer read FNextRowIndex write FNextRowIndex;
155  property Resolver: IZCachedResolver read FResolver write FResolver;
156  {BEGIN PATCH [1214009] CalcDefaults in TZUpdateSQL and Added Methods to GET the DB NativeResolver}
157  property NativeResolver: IZCachedResolver read FNativeResolver;
158  {END PATCH [1214009] CalcDefaults in TZUpdateSQL and Added Methods to GET the DB NativeResolver}
159  public
160  constructor CreateWithStatement(SQL: string; Statement: IZStatement;
161  ConSettings: PZConSettings);
162  constructor CreateWithColumns(ColumnsInfo: TObjectList; SQL: string;
163  ConSettings: PZConSettings);
164  destructor Destroy; override;
165 
166  procedure Close; override;
167 
168  //======================================================================
169  // Methods for accessing results by column index
170  //======================================================================
171 
172  function IsNull(ColumnIndex: Integer): Boolean; override;
173  function GetPChar(ColumnIndex: Integer): PChar; override;
174  function GetString(ColumnIndex: Integer): String; override;
175  function GetUnicodeString(ColumnIndex: Integer): Widestring; override;
176  function GetBoolean(ColumnIndex: Integer): Boolean; override;
177  function GetByte(ColumnIndex: Integer): Byte; override;
178  function GetShort(ColumnIndex: Integer): SmallInt; override;
179  function GetInt(ColumnIndex: Integer): Integer; override;
180  function GetLong(ColumnIndex: Integer): Int64; override;
181  function GetFloat(ColumnIndex: Integer): Single; override;
182  function GetDouble(ColumnIndex: Integer): Double; override;
183  function GetBigDecimal(ColumnIndex: Integer): Extended; override;
184  function GetBytes(ColumnIndex: Integer): TByteDynArray; override;
185  function GetDate(ColumnIndex: Integer): TDateTime; override;
186  function GetTime(ColumnIndex: Integer): TDateTime; override;
187  function GetTimestamp(ColumnIndex: Integer): TDateTime; override;
188  function GetBlob(ColumnIndex: Integer): IZBlob; override;
189  function GetDefaultExpression(ColumnIndex: Integer): string; override;
190 
191  //---------------------------------------------------------------------
192  // Traversal/Positioning
193  //---------------------------------------------------------------------
194 
195  function MoveAbsolute(Row: Integer): Boolean; override;
196 
197  //---------------------------------------------------------------------
198  // Updates
199  //---------------------------------------------------------------------
200 
201  function RowUpdated: Boolean; override;
202  function RowInserted: Boolean; override;
203  function RowDeleted: Boolean; override;
204 
205  procedure UpdateNull(ColumnIndex: Integer); override;
206  procedure UpdateBoolean(ColumnIndex: Integer; Value: Boolean); override;
207  procedure UpdateByte(ColumnIndex: Integer; Value: ShortInt); override;
208  procedure UpdateShort(ColumnIndex: Integer; Value: SmallInt); override;
209  procedure UpdateInt(ColumnIndex: Integer; Value: Integer); override;
210  procedure UpdateLong(ColumnIndex: Integer; Value: Int64); override;
211  procedure UpdateFloat(ColumnIndex: Integer; Value: Single); override;
212  procedure UpdateDouble(ColumnIndex: Integer; Value: Double); override;
213  procedure UpdateBigDecimal(ColumnIndex: Integer; Value: Extended); override;
214  procedure UpdatePChar(ColumnIndex: Integer; Value: PChar); override;
215  procedure UpdateString(ColumnIndex: Integer; const Value: String); override;
216  procedure UpdateUnicodeString(ColumnIndex: Integer; const Value: WideString); override;
217  procedure UpdateBytes(ColumnIndex: Integer; const Value: TByteDynArray); override;
218  procedure UpdateDate(ColumnIndex: Integer; Value: TDateTime); override;
219  procedure UpdateTime(ColumnIndex: Integer; Value: TDateTime); override;
220  procedure UpdateTimestamp(ColumnIndex: Integer; Value: TDateTime); override;
221  procedure UpdateAsciiStream(ColumnIndex: Integer; Value: TStream); override;
222  procedure UpdateUnicodeStream(ColumnIndex: Integer; Value: TStream); override;
223  procedure UpdateBinaryStream(ColumnIndex: Integer; Value: TStream); override;
224  procedure UpdateDefaultExpression(ColumnIndex: Integer; const Value: string); override;
225 
226  procedure InsertRow; override;
227  procedure UpdateRow; override;
228  procedure DeleteRow; override;
229  procedure CancelRowUpdates; override;
230  procedure RefreshRow;override;// FOS+ 071106
231 
232 
233  procedure MoveToInsertRow; override;
234  procedure MoveToCurrentRow; override;
235 
236  function CompareRows(Row1, Row2: Integer; const ColumnIndices: TIntegerDynArray;
237  const ColumnDirs: TBooleanDynArray): Integer; override;
238 
239  //---------------------------------------------------------------------
240  // Cached Updates
241  //---------------------------------------------------------------------
242 
243  function GetResolver: IZCachedResolver;
244  procedure SetResolver(Resolver: IZCachedResolver);
245  {BEGIN PATCH [1214009] CalcDefaults in TZUpdateSQL and Added Methods to GET the DB NativeResolver}
246  function GetNativeResolver: IZCachedResolver;
247  {END PATCH [1214009] CalcDefaults in TZUpdateSQL and Added Methods to GET the DB NativeResolver}
248  function IsCachedUpdates: Boolean;
249  procedure SetCachedUpdates(Value: Boolean);
250  function IsPendingUpdates: Boolean; virtual;
251 
252  procedure PostUpdates; virtual;
253  procedure CancelUpdates; virtual;
254  procedure RevertRecord; virtual;
255  procedure MoveToInitialRow; virtual;
256  procedure PostUpdatesCached; virtual;
257  procedure DisposeCachedUpdates; virtual;
258  end;
259 
260  {**
261  Implements Abstract cached ResultSet. This class should be extended
262  with database specific logic to form SQL data manipulation statements.
263  }
264  TZCachedResultSet = class(TZAbstractCachedResultSet)
265  private
266  FResultSet: IZResultSet;
267  protected
268  procedure Open; override;
269  function Fetch: Boolean; virtual;
270  procedure FetchAll; virtual;
271 
272  property ResultSet: IZResultSet read FResultSet write FResultSet;
273  public
274  constructor Create(ResultSet: IZResultSet; SQL: string;
275  Resolver: IZCachedResolver; ConSettings: PZConSettings);
276  destructor Destroy; override;
277 
278  procedure Close; override;
279  function GetMetaData: IZResultSetMetaData; override;
280 
281  function IsAfterLast: Boolean; override;
282  function IsLast: Boolean; override;
283  procedure AfterLast; override;
284  function Last: Boolean; override;
285  function MoveAbsolute(Row: Integer): Boolean; override;
286  end;
287 
288 implementation
289 
290 uses ZMessages, ZDbcResultSetMetadata, ZDbcGenericResolver, ZDbcUtils, ZEncoding;
291 
292 { TZAbstractCachedResultSet }
293 
294 {**
295  Creates this object and assignes the main properties.
296  @param Statement an SQL statement object.
297  @param SQL an SQL query.
298 }
299 constructor TZAbstractCachedResultSet.CreateWithStatement(SQL: string;
300  Statement: IZStatement; ConSettings: PZConSettings);
301 begin
302  inherited Create(Statement, SQL, nil, ConSettings);
303  FCachedUpdates := False;
304 end;
305 
306 {**
307  Creates this object and assignes the main properties.
308  @param SQL an SQL query.
309  @param ColumnsInfo a columns info for cached rows.
310 }
311 constructor TZAbstractCachedResultSet.CreateWithColumns(
312  ColumnsInfo: TObjectList; SQL: string; ConSettings: PZConSettings);
313 begin
314  inherited Create(nil, SQL, nil, ConSettings);
315 
316  CopyColumnsInfo(ColumnsInfo, Self.ColumnsInfo);
317  FCachedUpdates := False;
318  Open;
319 end;
320 
321 {**
322  Destroys this object and cleanups the memory.
323 }
324 destructor TZAbstractCachedResultSet.Destroy;
325 begin
326  FResolver := nil;
327  {BEGIN PATCH [1214009] CalcDefaults in TZUpdateSQL and Added Methods to GET the DB NativeResolver}
328  FNativeResolver := nil;
329  {END PATCH [1214009] CalcDefaults in TZUpdateSQL and Added Methods to GET the DB NativeResolver}
330  inherited Destroy;
331 end;
332 
333 {**
334  Checks for availability of the cached buffer.
335 }
336 procedure TZAbstractCachedResultSet.CheckAvailable;
337 begin
338  CheckClosed;
339  if (FRowAccessor = nil) or (FRowAccessor.RowBuffer = nil) then
340  raise EZSQLException.Create(SRowDataIsNotAvailable);
341 end;
342 
343 {**
344  Checks is the cached buffer updatable.
345 }
346 procedure TZAbstractCachedResultSet.CheckUpdatable;
347 begin
348  CheckAvailable;
349  if ResultSetConcurrency <> rcUpdatable then
350  RaiseReadOnlyException;
351 end;
352 
353 {**
354  Generates the next row index value.
355  @return the new generated row index.
356 }
357 function TZAbstractCachedResultSet.GetNextRowIndex: Integer;
358 begin
359  Result := FNextRowIndex;
360  Inc(FNextRowIndex);
361 end;
362 
363 {**
364  Finds a row with specified index among list of rows.
365  @param RowsList a list of rows.
366  @param Index a row index.
367  @return a found row buffer of <code>null</code> otherwise.
368 }
369 function TZAbstractCachedResultSet.LocateRow(RowsList: TList;
370  RowIndex: Integer): Integer;
371 var
372  I: Integer;
373 begin
374  Result := -1;
375  for I := 0 to RowsList.Count - 1 do
376  begin
377  if PZRowBuffer(RowsList[I]).Index = RowIndex then
378  begin
379  Result := I;
380  Break;
381  end;
382  end;
383 end;
384 
385 {**
386  Appends a row to the list of rows if such row is not exist.
387  @param Row a row buffer.
388  @return an appended row buffer.
389 }
390 function TZAbstractCachedResultSet.AppendRow(Row: PZRowBuffer): PZRowBuffer;
391 begin
392  if LocateRow(FInitialRowsList, Row.Index) < 0 then
393  begin
394  FRowAccessor.AllocBuffer(Result);
395  FRowAccessor.CopyBuffer(Row, Result);
396  FInitialRowsList.Add(Result);
397  FCurrentRowsList.Add(Row);
398  end
399  else
400  Result := nil;
401 end;
402 
403 {**
404  Prepares the current selected row for updates.
405 }
406 procedure TZAbstractCachedResultSet.PrepareRowForUpdates;
407 begin
408  if (RowAccessor.RowBuffer = FSelectedRow) and (FSelectedRow <> FUpdatedRow) then
409  begin
410  FSelectedRow := FUpdatedRow;
411  RowAccessor.RowBuffer := FSelectedRow;
412  RowAccessor.CloneFrom(PZRowBuffer(FRowsList[RowNo - 1]));
413  end;
414 end;
415 
416 {**
417  Calculates column default values..
418  @param RowAccessor a row accessor which contains new column values.
419 }
420 procedure TZAbstractCachedResultSet.CalculateRowDefaults(
421  RowAccessor: TZRowAccessor);
422 begin
423 {$IFNDEF DISABLE_CHECKING}
424  if Resolver = nil then
425  raise EZSQLException.Create(SResolverIsNotSpecified);
426 {$ENDIF}
427  Resolver.CalculateDefaults(Self, RowAccessor);
428 end;
429 
430 {**
431  Post changes to database server.
432  @param OldRowAccessor a row accessor which contains old column values.
433  @param NewRowAccessor a row accessor which contains new or updated
434  column values.
435 }
436 procedure TZAbstractCachedResultSet.PostRowUpdates(OldRowAccessor,
437  NewRowAccessor: TZRowAccessor);
438 begin
439 {$IFNDEF DISABLE_CHECKING}
440  if Resolver = nil then
441  raise EZSQLException.Create(SResolverIsNotSpecified);
442 {$ENDIF}
443  Resolver.PostUpdates(Self, NewRowAccessor.RowBuffer.UpdateType,
444  OldRowAccessor, NewRowAccessor);
445 end;
446 
447 {**
448  Gets a cached updates resolver object.
449  @return a cached updates resolver object.
450 }
451 function TZAbstractCachedResultSet.GetResolver: IZCachedResolver;
452 begin
453  Result := FResolver;
454 end;
455 
456 {**
457  Sets a new cached updates resolver object.
458  @param Resolver a cached updates resolver object.
459 }
460 procedure TZAbstractCachedResultSet.SetResolver(Resolver: IZCachedResolver);
461 begin
462  FResolver := Resolver;
463 {BEGIN PATCH [1214009] CalcDefaults in TZUpdateSQL and Added Methods to GET the DB NativeResolver}
464  if FNativeResolver = nil then
465  FNativeResolver := Resolver;
466 {END PATCH [1214009] CalcDefaults in TZUpdateSQL and Added Methods to GET the DB NativeResolver}
467 end;
468 {BEGIN PATCH [1214009] CalcDefaults in TZUpdateSQL and Added Methods to GET the DB NativeResolver}
469 {**
470  Gets a Native cached updates resolver object.
471  @return a Native cached updates resolver object.
472 }
473 function TZAbstractCachedResultSet.GetNativeResolver: IZCachedResolver;
474 begin
475  Result := FNativeResolver;
476 end;
477 {END PATCH [1214009] CalcDefaults in TZUpdateSQL and Added Methods to GET the DB NativeResolver}
478 
479 {**
480  Checks is the cached updates mode turned on.
481  @return <code>True</code> if the cached updates mode turned on.
482 }
483 function TZAbstractCachedResultSet.IsCachedUpdates: Boolean;
484 begin
485  Result := FCachedUpdates;
486 end;
487 
488 {**
489  Switched the cached updates mode.
490  @param Value boolean flag which turns on/off the cached updates mode.
491 }
492 procedure TZAbstractCachedResultSet.SetCachedUpdates(Value: Boolean);
493 begin
494  if FCachedUpdates <> Value then
495  begin
496  FCachedUpdates := Value;
497  if not FCachedUpdates then
498  PostUpdates;
499  end;
500 end;
501 
502 {**
503  Checks is cached updates pending.
504  @return <code>True</code> if the cached updates pending.
505 }
506 function TZAbstractCachedResultSet.IsPendingUpdates: Boolean;
507 begin
508  Result := FInitialRowsList.Count > 0;
509 end;
510 
511 {**
512  Moves to the current row with initial column values.
513 }
514 procedure TZAbstractCachedResultSet.MoveToInitialRow;
515 var
516  Index: Integer;
517 begin
518  CheckClosed;
519  if (RowNo >= 1) and (RowNo <= LastRowNo) and (FSelectedRow <> nil) then
520  begin
521  Index := LocateRow(FInitialRowsList, FSelectedRow.Index);
522  if Index >= 0 then
523  begin
524  FSelectedRow := FInitialRowsList[Index];
525  FRowAccessor.RowBuffer := FSelectedRow;
526  end;
527  end
528  else
529  FRowAccessor.RowBuffer := nil;
530 end;
531 
532 {**
533  Posts all saved updates to the server.
534 }
535 procedure TZAbstractCachedResultSet.PostUpdates;
536 begin
537  CheckClosed;
538  if FInitialRowsList.Count > 0 then
539  begin
540  while FInitialRowsList.Count > 0 do
541  begin
542  OldRowAccessor.RowBuffer := PZRowBuffer(FInitialRowsList[0]);
543  NewRowAccessor.RowBuffer := PZRowBuffer(FCurrentRowsList[0]);
544 
545  { Updates default field values. }
546  if NewRowAccessor.RowBuffer.UpdateType = utInserted then
547  CalculateRowDefaults(NewRowAccessor);
548 
549  { Posts row updates and processes the exceptions. }
550  PostRowUpdates(OldRowAccessor, NewRowAccessor);
551 
552  { If post was Ok - update the row update type. }
553  if NewRowAccessor.RowBuffer.UpdateType <> utDeleted then
554  begin
555  NewRowAccessor.RowBuffer.UpdateType := utUnmodified;
556  if (FSelectedRow <> nil)
557  and (FSelectedRow.Index = NewRowAccessor.RowBuffer.Index) then
558  FSelectedRow.UpdateType := utUnmodified;
559  end;
560 
561  { Removes cached rows. }
562  OldRowAccessor.Dispose;
563  FInitialRowsList.Delete(0);
564  FCurrentRowsList.Delete(0);
565  end;
566  end;
567 end;
568 
569 {**
570  Posts all saved updates to the server but keeps them cached.
571 }
572 procedure TZAbstractCachedResultSet.PostUpdatesCached;
573 var
574  i: Integer;
575 begin
576  CheckClosed;
577  if FInitialRowsList.Count > 0 then
578  begin
579  i := 0;
580  while i < FInitialRowsList.Count do
581  begin
582  OldRowAccessor.RowBuffer := PZRowBuffer(FInitialRowsList[i]);
583  NewRowAccessor.RowBuffer := PZRowBuffer(FCurrentRowsList[i]);
584  Inc(i);
585 
586  { Updates default field values. }
587  if NewRowAccessor.RowBuffer.UpdateType = utInserted then
588  CalculateRowDefaults(NewRowAccessor);
589 
590  { Posts row updates. }
591  PostRowUpdates(OldRowAccessor, NewRowAccessor);
592  end;
593  end;
594 end;
595 
596 {**
597  Frees the updates and marks records as unmodified. Complements
598  PostUpdatesCached.
599 }
600 procedure TZAbstractCachedResultSet.DisposeCachedUpdates;
601 begin
602  while FInitialRowsList.Count > 0 do
603  begin
604  OldRowAccessor.RowBuffer := PZRowBuffer(FInitialRowsList[0]);
605  NewRowAccessor.RowBuffer := PZRowBuffer(FCurrentRowsList[0]);
606 
607  if NewRowAccessor.RowBuffer.UpdateType <> utDeleted then
608  begin
609  NewRowAccessor.RowBuffer.UpdateType := utUnmodified;
610  if (FSelectedRow <> nil)
611  and (FSelectedRow.Index = NewRowAccessor.RowBuffer.Index) then
612  FSelectedRow.UpdateType := utUnmodified;
613  end;
614 
615  { Remove cached rows. }
616  OldRowAccessor.Dispose;
617  FInitialRowsList.Delete(0);
618  FCurrentRowsList.Delete(0);
619  end;
620 end;
621 
622 {**
623  Cancels updates for all rows.
624 }
625 procedure TZAbstractCachedResultSet.CancelUpdates;
626 var
627  InitialRow, CurrentRow: PZRowBuffer;
628 begin
629  CheckClosed;
630  while FInitialRowsList.Count > 0 do
631  begin
632  InitialRow := PZRowBuffer(FInitialRowsList[0]);
633  CurrentRow := PZRowBuffer(FCurrentRowsList[0]);
634 
635  if CurrentRow.UpdateType = utInserted then
636  InitialRow.UpdateType := utDeleted;
637 
638  FRowAccessor.CopyBuffer(InitialRow, CurrentRow);
639  if (FSelectedRow = FUpdatedRow)
640  and (FSelectedRow.Index = InitialRow.Index) then
641  FRowAccessor.CopyBuffer(InitialRow, FSelectedRow);
642 
643  FRowAccessor.DisposeBuffer(InitialRow);
644  FInitialRowsList.Delete(0);
645  FCurrentRowsList.Delete(0);
646  end;
647 end;
648 
649 {**
650  Cancels updates for the current row.
651 }
652 procedure TZAbstractCachedResultSet.RefreshRow;
653 begin
654  if Resolver = nil then
655  raise EZSQLException.Create(SResolverIsNotSpecified);
656  Resolver.RefreshCurrentRow(Self,RowAccessor);
657 end;
658 
659 procedure TZAbstractCachedResultSet.RevertRecord;
660 var
661  Index: Integer;
662  InitialRow, CurrentRow: PZRowBuffer;
663 begin
664  CheckClosed;
665  if (RowNo >= 1) and (RowNo <= LastRowNo) then
666  begin
667  Index := LocateRow(FInitialRowsList, FSelectedRow.Index);
668  if Index >= 0 then
669  begin
670  InitialRow := PZRowBuffer(FInitialRowsList[Index]);
671  CurrentRow := PZRowBuffer(FRowsList[RowNo - 1]);
672 
673  if CurrentRow.UpdateType = utInserted then
674  InitialRow.UpdateType := utDeleted;
675  FRowAccessor.CopyBuffer(InitialRow, CurrentRow);
676  if (FSelectedRow = FUpdatedRow) then
677  FRowAccessor.CopyBuffer(InitialRow, FSelectedRow);
678 
679  FRowAccessor.DisposeBuffer(InitialRow);
680  FInitialRowsList.Delete(Index);
681  FCurrentRowsList.Delete(Index);
682  end;
683  end;
684 end;
685 
686 {**
687  Opens this recordset.
688 }
689 procedure TZAbstractCachedResultSet.Open;
690 begin
691  if not Closed then
692  raise EZSQLException.Create(SResultsetIsAlreadyOpened);
693 
694  FRowsList := TList.Create;
695  FInitialRowsList := TList.Create;
696  FCurrentRowsList := TList.Create;
697 
698  FRowAccessor := TZRowAccessor.Create(ColumnsInfo, ConSettings);
699  FOldRowAccessor := TZRowAccessor.Create(ColumnsInfo, ConSettings);
700  FNewRowAccessor := TZRowAccessor.Create(ColumnsInfo, ConSettings);
701 
702  FRowAccessor.AllocBuffer(FUpdatedRow);
703  FRowAccessor.AllocBuffer(FInsertedRow);
704  FSelectedRow := nil;
705 
706  FNextRowIndex := 0;
707 
708  if (Resolver = nil) and (GetConcurrency = rcUpdatable) then
709  Resolver := TZGenericCachedResolver.Create(GetStatement, GetMetadata);
710 
711  inherited Open;
712 end;
713 
714 {**
715  Releases this <code>ResultSet</code> object's database and
716  JDBC resources immediately instead of waiting for
717  this to happen when it is automatically closed.
718 
719  <P><B>Note:</B> A <code>ResultSet</code> object
720  is automatically closed by the
721  <code>Statement</code> object that generated it when
722  that <code>Statement</code> object is closed,
723  re-executed, or is used to retrieve the next result from a
724  sequence of multiple results. A <code>ResultSet</code> object
725  is also automatically closed when it is garbage collected.
726 }
727 procedure TZAbstractCachedResultSet.Close;
728 var
729  I: Integer;
730 begin
731  inherited Close;
732 
733  if Assigned(FRowAccessor) then
734  begin
735  for I := 0 to FRowsList.Count - 1 do
736  FRowAccessor.DisposeBuffer(PZRowBuffer(FRowsList[I]));
737  for I := 0 to FInitialRowsList.Count - 1 do
738  FRowAccessor.DisposeBuffer(PZRowBuffer(FInitialRowsList[I]));
739 
740  FRowAccessor.DisposeBuffer(FUpdatedRow);
741  FUpdatedRow := nil;
742  FRowAccessor.DisposeBuffer(FInsertedRow);
743  FInsertedRow := nil;
744  FSelectedRow := nil;
745 
746  FreeAndNil(FRowsList);
747  FreeAndNil(FInitialRowsList);
748  FreeAndNil(FCurrentRowsList);
749 
750  FreeAndNil(FRowAccessor);
751  FreeAndNil(FOldRowAccessor);
752  FreeAndNil(FNewRowAccessor);
753  end;
754 end;
755 
756 //======================================================================
757 // Methods for accessing results by column index
758 //======================================================================
759 
760 {**
761  Indicates if the value of the designated column in the current row
762  of this <code>ResultSet</code> object is Null.
763 
764  @param columnIndex the first column is 1, the second is 2, ...
765  @return if the value is SQL <code>NULL</code>, the
766  value returned is <code>true</code>. <code>false</code> otherwise.
767 }
768 function TZAbstractCachedResultSet.IsNull(ColumnIndex: Integer): Boolean;
769 begin
770 {$IFNDEF DISABLE_CHECKING}
771  CheckAvailable;
772 {$ENDIF}
773  Result := FRowAccessor.IsNull(ColumnIndex);
774 end;
775 
776 {**
777  Gets the value of the designated column in the current row
778  of this <code>ResultSet</code> object as
779  a <code>PAnsiChar</code> in the Delphi programming language.
780 
781  @param columnIndex the first column is 1, the second is 2, ...
782  @return the column value; if the value is SQL <code>NULL</code>, the
783  value returned is <code>null</code>
784 }
785 function TZAbstractCachedResultSet.GetPChar(ColumnIndex: Integer): PChar;
786 begin
787 {$IFNDEF DISABLE_CHECKING}
788  CheckAvailable;
789 {$ENDIF}
790  Result := FRowAccessor.GetPChar(ColumnIndex, LastWasNull);
791 end;
792 
793 {**
794  Gets the value of the designated column in the current row
795  of this <code>ResultSet</code> object as
796  a <code>String</code> in the Java programming language.
797 
798  @param columnIndex the first column is 1, the second is 2, ...
799  @return the column value; if the value is SQL <code>NULL</code>, the
800  value returned is <code>null</code>
801 }
802 function TZAbstractCachedResultSet.GetString(ColumnIndex: Integer): String;
803 begin
804 {$IFNDEF DISABLE_CHECKING}
805  CheckAvailable;
806 {$ENDIF}
807  Result := FRowAccessor.GetString(ColumnIndex, LastWasNull);
808 end;
809 
810 {**
811  Gets the value of the designated column in the current row
812  of this <code>ResultSet</code> object as
813  a <code>Widestring</code> in the Java programming language.
814 
815  @param columnIndex the first column is 1, the second is 2, ...
816  @return the column value; if the value is SQL <code>NULL</code>, the
817  value returned is <code>null</code>
818 }
819 function TZAbstractCachedResultSet.GetUnicodeString(ColumnIndex: Integer): Widestring;
820 begin
821 {$IFNDEF DISABLE_CHECKING}
822  CheckAvailable;
823 {$ENDIF}
824  Result := FRowAccessor.GetUnicodeString(ColumnIndex, LastWasNull);
825 end;
826 
827 {**
828  Gets the value of the designated column in the current row
829  of this <code>ResultSet</code> object as
830  a <code>boolean</code> in the Java programming language.
831 
832  @param columnIndex the first column is 1, the second is 2, ...
833  @return the column value; if the value is SQL <code>NULL</code>, the
834  value returned is <code>false</code>
835 }
836 function TZAbstractCachedResultSet.GetBoolean(ColumnIndex: Integer): Boolean;
837 begin
838 {$IFNDEF DISABLE_CHECKING}
839  CheckAvailable;
840 {$ENDIF}
841  Result := FRowAccessor.GetBoolean(ColumnIndex, LastWasNull);
842 end;
843 
844 {**
845  Gets the value of the designated column in the current row
846  of this <code>ResultSet</code> object as
847  a <code>byte</code> in the Java programming language.
848 
849  @param columnIndex the first column is 1, the second is 2, ...
850  @return the column value; if the value is SQL <code>NULL</code>, the
851  value returned is <code>0</code>
852 }
853 function TZAbstractCachedResultSet.GetByte(ColumnIndex: Integer): Byte;
854 begin
855 {$IFNDEF DISABLE_CHECKING}
856  CheckAvailable;
857 {$ENDIF}
858  Result := FRowAccessor.GetByte(ColumnIndex, LastWasNull);
859 end;
860 
861 {**
862  Gets the value of the designated column in the current row
863  of this <code>ResultSet</code> object as
864  a <code>short</code> in the Java programming language.
865 
866  @param columnIndex the first column is 1, the second is 2, ...
867  @return the column value; if the value is SQL <code>NULL</code>, the
868  value returned is <code>0</code>
869 }
870 function TZAbstractCachedResultSet.GetShort(ColumnIndex: Integer): SmallInt;
871 begin
872 {$IFNDEF DISABLE_CHECKING}
873  CheckAvailable;
874 {$ENDIF}
875  Result := FRowAccessor.GetShort(ColumnIndex, LastWasNull);
876 end;
877 
878 {**
879  Gets the value of the designated column in the current row
880  of this <code>ResultSet</code> object as
881  an <code>int</code> in the Java programming language.
882 
883  @param columnIndex the first column is 1, the second is 2, ...
884  @return the column value; if the value is SQL <code>NULL</code>, the
885  value returned is <code>0</code>
886 }
887 function TZAbstractCachedResultSet.GetInt(ColumnIndex: Integer): Integer;
888 begin
889 {$IFNDEF DISABLE_CHECKING}
890  CheckAvailable;
891 {$ENDIF}
892  Result := FRowAccessor.GetInt(ColumnIndex, LastWasNull);
893 end;
894 
895 {**
896  Gets the value of the designated column in the current row
897  of this <code>ResultSet</code> object as
898  a <code>long</code> in the Java programming language.
899 
900  @param columnIndex the first column is 1, the second is 2, ...
901  @return the column value; if the value is SQL <code>NULL</code>, the
902  value returned is <code>0</code>
903 }
904 function TZAbstractCachedResultSet.GetLong(ColumnIndex: Integer): Int64;
905 begin
906 {$IFNDEF DISABLE_CHECKING}
907  CheckAvailable;
908 {$ENDIF}
909  Result := FRowAccessor.GetLong(ColumnIndex, LastWasNull);
910 end;
911 
912 {**
913  Gets the value of the designated column in the current row
914  of this <code>ResultSet</code> object as
915  a <code>float</code> in the Java programming language.
916 
917  @param columnIndex the first column is 1, the second is 2, ...
918  @return the column value; if the value is SQL <code>NULL</code>, the
919  value returned is <code>0</code>
920 }
921 function TZAbstractCachedResultSet.GetFloat(ColumnIndex: Integer): Single;
922 begin
923 {$IFNDEF DISABLE_CHECKING}
924  CheckAvailable;
925 {$ENDIF}
926  Result := FRowAccessor.GetFloat(ColumnIndex, LastWasNull);
927 end;
928 
929 {**
930  Gets the value of the designated column in the current row
931  of this <code>ResultSet</code> object as
932  a <code>double</code> in the Java programming language.
933 
934  @param columnIndex the first column is 1, the second is 2, ...
935  @return the column value; if the value is SQL <code>NULL</code>, the
936  value returned is <code>0</code>
937 }
938 function TZAbstractCachedResultSet.GetDouble(ColumnIndex: Integer): Double;
939 begin
940 {$IFNDEF DISABLE_CHECKING}
941  CheckAvailable;
942 {$ENDIF}
943  Result := FRowAccessor.GetDouble(ColumnIndex, LastWasNull);
944 end;
945 
946 {**
947  Gets the value of the designated column in the current row
948  of this <code>ResultSet</code> object as
949  a <code>java.sql.BigDecimal</code> in the Java programming language.
950 
951  @param columnIndex the first column is 1, the second is 2, ...
952  @param scale the number of digits to the right of the decimal point
953  @return the column value; if the value is SQL <code>NULL</code>, the
954  value returned is <code>null</code>
955 }
956 function TZAbstractCachedResultSet.GetBigDecimal(ColumnIndex: Integer): Extended;
957 begin
958 {$IFNDEF DISABLE_CHECKING}
959  CheckAvailable;
960 {$ENDIF}
961  Result := FRowAccessor.GetBigDecimal(ColumnIndex, LastWasNull);
962 end;
963 
964 {**
965  Gets the value of the designated column in the current row
966  of this <code>ResultSet</code> object as
967  a <code>byte</code> array in the Java programming language.
968  The bytes represent the raw values returned by the driver.
969 
970  @param columnIndex the first column is 1, the second is 2, ...
971  @return the column value; if the value is SQL <code>NULL</code>, the
972  value returned is <code>null</code>
973 }
974 function TZAbstractCachedResultSet.GetBytes(ColumnIndex: Integer): TByteDynArray;
975 begin
976 {$IFNDEF DISABLE_CHECKING}
977  CheckAvailable;
978 {$ENDIF}
979  Result := FRowAccessor.GetBytes(ColumnIndex, LastWasNull);
980 end;
981 
982 {**
983  Gets the value of the designated column in the current row
984  of this <code>ResultSet</code> object as
985  a <code>java.sql.Date</code> object in the Java programming language.
986 
987  @param columnIndex the first column is 1, the second is 2, ...
988  @return the column value; if the value is SQL <code>NULL</code>, the
989  value returned is <code>null</code>
990 }
991 function TZAbstractCachedResultSet.GetDate(ColumnIndex: Integer): TDateTime;
992 begin
993 {$IFNDEF DISABLE_CHECKING}
994  CheckAvailable;
995 {$ENDIF}
996  Result := FRowAccessor.GetDate(ColumnIndex, LastWasNull);
997 end;
998 
999 {**
1000  Gets the value of the designated column in the current row
1001  of this <code>ResultSet</code> object as
1002  a <code>java.sql.Time</code> object in the Java programming language.
1003 
1004  @param columnIndex the first column is 1, the second is 2, ...
1005  @return the column value; if the value is SQL <code>NULL</code>, the
1006  value returned is <code>null</code>
1007 }
1008 function TZAbstractCachedResultSet.GetTime(ColumnIndex: Integer): TDateTime;
1009 begin
1010 {$IFNDEF DISABLE_CHECKING}
1011  CheckAvailable;
1012 {$ENDIF}
1013  Result := FRowAccessor.GetTime(ColumnIndex, LastWasNull);
1014 end;
1015 
1016 {**
1017  Gets the value of the designated column in the current row
1018  of this <code>ResultSet</code> object as
1019  a <code>java.sql.Timestamp</code> object in the Java programming language.
1020 
1021  @param columnIndex the first column is 1, the second is 2, ...
1022  @return the column value; if the value is SQL <code>NULL</code>, the
1023  value returned is <code>null</code>
1024  @exception SQLException if a database access error occurs
1025 }
1026 function TZAbstractCachedResultSet.GetTimestamp(ColumnIndex: Integer): TDateTime;
1027 begin
1028 {$IFNDEF DISABLE_CHECKING}
1029  CheckAvailable;
1030 {$ENDIF}
1031  Result := FRowAccessor.GetTimestamp(ColumnIndex, LastWasNull);
1032 end;
1033 
1034 {**
1035  Returns the value of the designated column in the current row
1036  of this <code>ResultSet</code> object as a <code>Blob</code> object
1037  in the Java programming language.
1038 
1039  @param ColumnIndex the first column is 1, the second is 2, ...
1040  @return a <code>Blob</code> object representing the SQL <code>BLOB</code> value in
1041  the specified column
1042 }
1043 function TZAbstractCachedResultSet.GetBlob(ColumnIndex: Integer): IZBlob;
1044 begin
1045 {$IFNDEF DISABLE_CHECKING}
1046  CheckAvailable;
1047 {$ENDIF}
1048  Result := FRowAccessor.GetBlob(ColumnIndex, LastWasNull);
1049 end;
1050 
1051 {**
1052  Gets the DefaultExpression value of the designated column in the current row
1053  of this <code>ResultSet</code> object as
1054  a <code>String</code>.
1055 
1056  @param columnIndex the first column is 1, the second is 2, ...
1057  @return the DefaultExpression value
1058 }
1059 function TZAbstractCachedResultSet.GetDefaultExpression(ColumnIndex: Integer): string;
1060 begin
1061 {$IFNDEF DISABLE_CHECKING}
1062  CheckAvailable;
1063 {$ENDIF}
1064  Result := FRowAccessor.GetColumnDefaultExpression(ColumnIndex);
1065 end;
1066 
1067 //---------------------------------------------------------------------
1068 // Updates
1069 //---------------------------------------------------------------------
1070 
1071 {**
1072  Gives a nullable column a null value.
1073 
1074  The <code>updateXXX</code> methods are used to update column values in the
1075  current row or the insert row. The <code>updateXXX</code> methods do not
1076  update the underlying database; instead the <code>updateRow</code>
1077  or <code>insertRow</code> methods are called to update the database.
1078 
1079  @param columnIndex the first column is 1, the second is 2, ...
1080 }
1081 procedure TZAbstractCachedResultSet.UpdateNull(ColumnIndex: Integer);
1082 begin
1083 {$IFNDEF DISABLE_CHECKING}
1084  CheckUpdatable;
1085 {$ENDIF}
1086  PrepareRowForUpdates;
1087  FRowAccessor.SetNull(ColumnIndex);
1088 end;
1089 
1090 {**
1091  Updates the designated column with a <code>boolean</code> value.
1092  The <code>updateXXX</code> methods are used to update column values in the
1093  current row or the insert row. The <code>updateXXX</code> methods do not
1094  update the underlying database; instead the <code>updateRow</code> or
1095  <code>insertRow</code> methods are called to update the database.
1096 
1097  @param columnIndex the first column is 1, the second is 2, ...
1098  @param x the new column value
1099 }
1100 procedure TZAbstractCachedResultSet.UpdateBoolean(ColumnIndex: Integer;
1101  Value: Boolean);
1102 begin
1103 {$IFNDEF DISABLE_CHECKING}
1104  CheckUpdatable;
1105 {$ENDIF}
1106  PrepareRowForUpdates;
1107  FRowAccessor.SetBoolean(ColumnIndex, Value);
1108 end;
1109 
1110 {**
1111  Updates the designated column with a <code>byte</code> value.
1112  The <code>updateXXX</code> methods are used to update column values in the
1113  current row or the insert row. The <code>updateXXX</code> methods do not
1114  update the underlying database; instead the <code>updateRow</code> or
1115  <code>insertRow</code> methods are called to update the database.
1116 
1117  @param columnIndex the first column is 1, the second is 2, ...
1118  @param x the new column value
1119 }
1120 procedure TZAbstractCachedResultSet.UpdateByte(ColumnIndex: Integer;
1121  Value: ShortInt);
1122 begin
1123 {$IFNDEF DISABLE_CHECKING}
1124  CheckUpdatable;
1125 {$ENDIF}
1126  PrepareRowForUpdates;
1127  FRowAccessor.SetByte(ColumnIndex, Value);
1128 end;
1129 
1130 {**
1131  Updates the designated column with a <code>short</code> value.
1132  The <code>updateXXX</code> methods are used to update column values in the
1133  current row or the insert row. The <code>updateXXX</code> methods do not
1134  update the underlying database; instead the <code>updateRow</code> or
1135  <code>insertRow</code> methods are called to update the database.
1136 
1137  @param columnIndex the first column is 1, the second is 2, ...
1138  @param x the new column value
1139 }
1140 procedure TZAbstractCachedResultSet.UpdateShort(ColumnIndex: Integer;
1141  Value: SmallInt);
1142 begin
1143 {$IFNDEF DISABLE_CHECKING}
1144  CheckUpdatable;
1145 {$ENDIF}
1146  PrepareRowForUpdates;
1147  FRowAccessor.SetShort(ColumnIndex, Value);
1148 end;
1149 
1150 {**
1151  Updates the designated column with an <code>int</code> value.
1152  The <code>updateXXX</code> methods are used to update column values in the
1153  current row or the insert row. The <code>updateXXX</code> methods do not
1154  update the underlying database; instead the <code>updateRow</code> or
1155  <code>insertRow</code> methods are called to update the database.
1156 
1157  @param columnIndex the first column is 1, the second is 2, ...
1158  @param x the new column value
1159 }
1160 procedure TZAbstractCachedResultSet.UpdateInt(ColumnIndex, Value: Integer);
1161 begin
1162 {$IFNDEF DISABLE_CHECKING}
1163  CheckUpdatable;
1164 {$ENDIF}
1165  PrepareRowForUpdates;
1166  FRowAccessor.SetInt(ColumnIndex, Value);
1167 end;
1168 
1169 {**
1170  Updates the designated column with a <code>long</code> value.
1171  The <code>updateXXX</code> methods are used to update column values in the
1172  current row or the insert row. The <code>updateXXX</code> methods do not
1173  update the underlying database; instead the <code>updateRow</code> or
1174  <code>insertRow</code> methods are called to update the database.
1175 
1176  @param columnIndex the first column is 1, the second is 2, ...
1177  @param x the new column value
1178 }
1179 procedure TZAbstractCachedResultSet.UpdateLong(ColumnIndex: Integer;
1180  Value: Int64);
1181 begin
1182 {$IFNDEF DISABLE_CHECKING}
1183  CheckUpdatable;
1184 {$ENDIF}
1185  PrepareRowForUpdates;
1186  FRowAccessor.SetLong(ColumnIndex, Value);
1187 end;
1188 
1189 {**
1190  Updates the designated column with a <code>float</code> value.
1191  The <code>updateXXX</code> methods are used to update column values in the
1192  current row or the insert row. The <code>updateXXX</code> methods do not
1193  update the underlying database; instead the <code>updateRow</code> or
1194  <code>insertRow</code> methods are called to update the database.
1195 
1196  @param columnIndex the first column is 1, the second is 2, ...
1197  @param x the new column value
1198 }
1199 procedure TZAbstractCachedResultSet.UpdateFloat(ColumnIndex: Integer;
1200  Value: Single);
1201 begin
1202 {$IFNDEF DISABLE_CHECKING}
1203  CheckUpdatable;
1204 {$ENDIF}
1205  PrepareRowForUpdates;
1206  FRowAccessor.SetFloat(ColumnIndex, Value);
1207 end;
1208 
1209 {**
1210  Updates the designated column with a <code>double</code> value.
1211  The <code>updateXXX</code> methods are used to update column values in the
1212  current row or the insert row. The <code>updateXXX</code> methods do not
1213  update the underlying database; instead the <code>updateRow</code> or
1214  <code>insertRow</code> methods are called to update the database.
1215 
1216  @param columnIndex the first column is 1, the second is 2, ...
1217  @param x the new column value
1218 }
1219 procedure TZAbstractCachedResultSet.UpdateDouble(ColumnIndex: Integer;
1220  Value: Double);
1221 begin
1222 {$IFNDEF DISABLE_CHECKING}
1223  CheckUpdatable;
1224 {$ENDIF}
1225  PrepareRowForUpdates;
1226  FRowAccessor.SetDouble(ColumnIndex, Value);
1227 end;
1228 
1229 {**
1230  Updates the designated column with a <code>java.math.BigDecimal</code>
1231  value.
1232  The <code>updateXXX</code> methods are used to update column values in the
1233  current row or the insert row. The <code>updateXXX</code> methods do not
1234  update the underlying database; instead the <code>updateRow</code> or
1235  <code>insertRow</code> methods are called to update the database.
1236 
1237  @param columnIndex the first column is 1, the second is 2, ...
1238  @param x the new column value
1239 }
1240 procedure TZAbstractCachedResultSet.UpdateBigDecimal(ColumnIndex: Integer;
1241  Value: Extended);
1242 begin
1243 {$IFNDEF DISABLE_CHECKING}
1244  CheckUpdatable;
1245 {$ENDIF}
1246  PrepareRowForUpdates;
1247  FRowAccessor.SetBigDecimal(ColumnIndex, Value);
1248 end;
1249 
1250 {**
1251  Updates the designated column with a <code>String</code> value.
1252  The <code>updateXXX</code> methods are used to update column values in the
1253  current row or the insert row. The <code>updateXXX</code> methods do not
1254  update the underlying database; instead the <code>updateRow</code> or
1255  <code>insertRow</code> methods are called to update the database.
1256 
1257  @param columnIndex the first column is 1, the second is 2, ...
1258  @param x the new column value
1259 }
1260 procedure TZAbstractCachedResultSet.UpdatePChar(ColumnIndex: Integer;
1261  Value: PChar);
1262 begin
1263 {$IFNDEF DISABLE_CHECKING}
1264  CheckUpdatable;
1265 {$ENDIF}
1266  PrepareRowForUpdates;
1267  FRowAccessor.SetPChar(ColumnIndex, Value);
1268 end;
1269 
1270 {**
1271  Updates the designated column with a <code>String</code> value.
1272  The <code>updateXXX</code> methods are used to update column values in the
1273  current row or the insert row. The <code>updateXXX</code> methods do not
1274  update the underlying database; instead the <code>updateRow</code> or
1275  <code>insertRow</code> methods are called to update the database.
1276 
1277  @param columnIndex the first column is 1, the second is 2, ...
1278  @param x the new column value
1279 }
1280 procedure TZAbstractCachedResultSet.UpdateString(ColumnIndex: Integer;
1281  const Value: String);
1282 begin
1283 {$IFNDEF DISABLE_CHECKING}
1284  CheckUpdatable;
1285 {$ENDIF}
1286  PrepareRowForUpdates;
1287  FRowAccessor.SetString(ColumnIndex, Value);
1288 end;
1289 
1290 {**
1291  Updates the designated column with a <code>Widestring</code> value.
1292  The <code>updateXXX</code> methods are used to update column values in the
1293  current row or the insert row. The <code>updateXXX</code> methods do not
1294  update the underlying database; instead the <code>updateRow</code> or
1295  <code>insertRow</code> methods are called to update the database.
1296 
1297  @param columnIndex the first column is 1, the second is 2, ...
1298  @param x the new column value
1299 }
1300 procedure TZAbstractCachedResultSet.UpdateUnicodeString(ColumnIndex: Integer;
1301  const Value: WideString);
1302 begin
1303 {$IFNDEF DISABLE_CHECKING}
1304  CheckUpdatable;
1305 {$ENDIF}
1306  PrepareRowForUpdates;
1307  FRowAccessor.SetUnicodeString(ColumnIndex, Value);
1308 end;
1309 
1310 {**
1311  Updates the designated column with a <code>byte</code> array value.
1312  The <code>updateXXX</code> methods are used to update column values in the
1313  current row or the insert row. The <code>updateXXX</code> methods do not
1314  update the underlying database; instead the <code>updateRow</code> or
1315  <code>insertRow</code> methods are called to update the database.
1316 
1317  @param columnIndex the first column is 1, the second is 2, ...
1318  @param x the new column value
1319 }
1320 procedure TZAbstractCachedResultSet.UpdateBytes(ColumnIndex: Integer;
1321  const Value: TByteDynArray);
1322 begin
1323 {$IFNDEF DISABLE_CHECKING}
1324  CheckUpdatable;
1325 {$ENDIF}
1326  PrepareRowForUpdates;
1327  FRowAccessor.SetBytes(ColumnIndex, Value);
1328 end;
1329 
1330 {**
1331  Updates the designated column with a <code>java.sql.Date</code> value.
1332  The <code>updateXXX</code> methods are used to update column values in the
1333  current row or the insert row. The <code>updateXXX</code> methods do not
1334  update the underlying database; instead the <code>updateRow</code> or
1335  <code>insertRow</code> methods are called to update the database.
1336 
1337  @param columnIndex the first column is 1, the second is 2, ...
1338  @param x the new column value
1339 }
1340 procedure TZAbstractCachedResultSet.UpdateDate(ColumnIndex: Integer;
1341  Value: TDateTime);
1342 begin
1343 {$IFNDEF DISABLE_CHECKING}
1344  CheckUpdatable;
1345 {$ENDIF}
1346  PrepareRowForUpdates;
1347  FRowAccessor.SetDate(ColumnIndex, Value);
1348 end;
1349 
1350 {**
1351  Updates the designated column with a <code>java.sql.Time</code> value.
1352  The <code>updateXXX</code> methods are used to update column values in the
1353  current row or the insert row. The <code>updateXXX</code> methods do not
1354  update the underlying database; instead the <code>updateRow</code> or
1355  <code>insertRow</code> methods are called to update the database.
1356 
1357  @param columnIndex the first column is 1, the second is 2, ...
1358  @param x the new column value
1359 }
1360 procedure TZAbstractCachedResultSet.UpdateTime(ColumnIndex: Integer;
1361  Value: TDateTime);
1362 begin
1363 {$IFNDEF DISABLE_CHECKING}
1364  CheckUpdatable;
1365 {$ENDIF}
1366  PrepareRowForUpdates;
1367  FRowAccessor.SetTime(ColumnIndex, Value);
1368 end;
1369 
1370 {**
1371  Updates the designated column with a <code>java.sql.Timestamp</code>
1372  value.
1373  The <code>updateXXX</code> methods are used to update column values in the
1374  current row or the insert row. The <code>updateXXX</code> methods do not
1375  update the underlying database; instead the <code>updateRow</code> or
1376  <code>insertRow</code> methods are called to update the database.
1377 
1378  @param columnIndex the first column is 1, the second is 2, ...
1379  @param x the new column value
1380 }
1381 procedure TZAbstractCachedResultSet.UpdateTimestamp(ColumnIndex: Integer;
1382  Value: TDateTime);
1383 begin
1384 {$IFNDEF DISABLE_CHECKING}
1385  CheckUpdatable;
1386 {$ENDIF}
1387  PrepareRowForUpdates;
1388  FRowAccessor.SetTimestamp(ColumnIndex, Value);
1389 end;
1390 
1391 {**
1392  Updates the designated column with an ascii stream value.
1393  The <code>updateXXX</code> methods are used to update column values in the
1394  current row or the insert row. The <code>updateXXX</code> methods do not
1395  update the underlying database; instead the <code>updateRow</code> or
1396  <code>insertRow</code> methods are called to update the database.
1397 
1398  @param columnIndex the first column is 1, the second is 2, ...
1399  @param x the new column value
1400 }
1401 procedure TZAbstractCachedResultSet.UpdateAsciiStream(ColumnIndex: Integer;
1402  Value: TStream);
1403 begin
1404 {$IFNDEF DISABLE_CHECKING}
1405  CheckUpdatable;
1406 {$ENDIF}
1407  PrepareRowForUpdates;
1408  FRowAccessor.SetAsciiStream(ColumnIndex, Value);
1409 end;
1410 
1411 {**
1412  Updates the designated column with a binary stream value.
1413  The <code>updateXXX</code> methods are used to update column values in the
1414  current row or the insert row. The <code>updateXXX</code> methods do not
1415  update the underlying database; instead the <code>updateRow</code> or
1416  <code>insertRow</code> methods are called to update the database.
1417 
1418  @param columnIndex the first column is 1, the second is 2, ...
1419  @param x the new column value
1420  @param length the length of the stream
1421 }
1422 procedure TZAbstractCachedResultSet.UpdateBinaryStream(
1423  ColumnIndex: Integer; Value: TStream);
1424 begin
1425 {$IFNDEF DISABLE_CHECKING}
1426  CheckUpdatable;
1427 {$ENDIF}
1428  PrepareRowForUpdates;
1429  FRowAccessor.SetBinaryStream(ColumnIndex, Value);
1430 end;
1431 
1432 {**
1433  Updates the designated column with a character stream value.
1434  The <code>updateXXX</code> methods are used to update column values in the
1435  current row or the insert row. The <code>updateXXX</code> methods do not
1436  update the underlying database; instead the <code>updateRow</code> or
1437  <code>insertRow</code> methods are called to update the database.
1438 
1439  @param columnIndex the first column is 1, the second is 2, ...
1440  @param x the new column value
1441 }
1442 procedure TZAbstractCachedResultSet.UpdateUnicodeStream(
1443  ColumnIndex: Integer; Value: TStream);
1444 var
1445  TempStream: TStream;
1446 begin
1447 {$IFNDEF DISABLE_CHECKING}
1448  CheckUpdatable;
1449 {$ENDIF}
1450  PrepareRowForUpdates;
1451  {EgonHugeist:
1452  Findout, wat's comming in! To avoid User-Bugs
1453  it is possible that a PAnsiChar OR a PWideChar was written into
1454  the Stream!!! And these chars could be trunced with changing the
1455  Stream.Size.}
1456  if Assigned(Value) then
1457  begin
1458  TempStream := GetValidatedUnicodeStream(TMemoryStream(Value).Memory, Value.Size, ConSettings, False);
1459  FRowAccessor.SetUnicodeStream(ColumnIndex, TempStream);
1460  TempStream.Free;
1461  end
1462  else
1463  FRowAccessor.SetUnicodeStream(ColumnIndex, nil);
1464 end;
1465 
1466 {**
1467  Updates the DefaultExpression of the designated column with a <code>String</code> value.
1468  This changes the behaviour of the RowAccessor used by the Resultset
1469  @param columnIndex the first column is 1, the second is 2, ...
1470  @param x the new DefaultExpression value for the column
1471 }
1472 procedure TZAbstractCachedResultSet.UpdateDefaultExpression(ColumnIndex: Integer;
1473  const Value: string);
1474 begin
1475  FNewRowAccessor.SetColumnDefaultExpression(ColumnIndex, Value);
1476 end;
1477 
1478 //---------------------------------------------------------------------
1479 // Processing methods
1480 //---------------------------------------------------------------------
1481 
1482 {**
1483  Moves the cursor to the given row number in
1484  this <code>ResultSet</code> object.
1485 
1486  <p>If the row number is positive, the cursor moves to
1487  the given row number with respect to the
1488  beginning of the result set. The first row is row 1, the second
1489  is row 2, and so on.
1490 
1491  <p>If the given row number is negative, the cursor moves to
1492  an absolute row position with respect to
1493  the end of the result set. For example, calling the method
1494  <code>absolute(-1)</code> positions the
1495  cursor on the last row; calling the method <code>absolute(-2)</code>
1496  moves the cursor to the next-to-last row, and so on.
1497 
1498  <p>An attempt to position the cursor beyond the first/last row in
1499  the result set leaves the cursor before the first row or after
1500  the last row.
1501 
1502  <p><B>Note:</B> Calling <code>absolute(1)</code> is the same
1503  as calling <code>first()</code>. Calling <code>absolute(-1)</code>
1504  is the same as calling <code>last()</code>.
1505 
1506  @return <code>true</code> if the cursor is on the result set;
1507  <code>false</code> otherwise
1508 }
1509 function TZAbstractCachedResultSet.MoveAbsolute(Row: Integer): Boolean;
1510 begin
1511 {$IFNDEF DISABLE_CHECKING}
1512  CheckClosed;
1513  if (ResultSetType = rtForwardOnly) and (Row < RowNo) then
1514  RaiseForwardOnlyException;
1515 {$ENDIF}
1516 
1517  if (Row >= 0) and (Row <= LastRowNo + 1) then
1518  begin
1519  RowNo := Row;
1520  if (Row >= 1) and (Row <= LastRowNo) then
1521  begin
1522  Result := True;
1523  FSelectedRow := PZRowBuffer(FRowsList[Row - 1]);
1524  RowAccessor.RowBuffer := FSelectedRow;
1525  end
1526  else
1527  begin
1528  Result := False;
1529  FSelectedRow := nil;
1530  RowAccessor.RowBuffer := FSelectedRow;
1531  end;
1532  end
1533  else
1534  Result := False;
1535 end;
1536 
1537 {**
1538  Indicates whether the current row has been updated. The value returned
1539  depends on whether or not the result set can detect updates.
1540 
1541  @return <code>true</code> if the row has been visibly updated
1542  by the owner or another, and updates are detected
1543 }
1544 function TZAbstractCachedResultSet.RowUpdated: Boolean;
1545 var
1546  CurrentRow: PZRowBuffer;
1547 begin
1548  if (RowNo >= 1) and (RowNo <= LastRowNo) then
1549  begin
1550  CurrentRow := PZRowBuffer(FRowsList[RowNo - 1]);
1551  Result := CurrentRow^.UpdateType = utModified;
1552  end
1553  else
1554  Result := False;
1555 end;
1556 
1557 {**
1558  Indicates whether the current row has had an insertion.
1559  The value returned depends on whether or not this
1560  <code>ResultSet</code> object can detect visible inserts.
1561 
1562  @return <code>true</code> if a row has had an insertion
1563  and insertions are detected; <code>false</code> otherwise
1564 }
1565 function TZAbstractCachedResultSet.RowInserted: Boolean;
1566 var
1567  CurrentRow: PZRowBuffer;
1568 begin
1569  if (RowNo >= 1) and (RowNo <= LastRowNo) then
1570  begin
1571  CurrentRow := PZRowBuffer(FRowsList[RowNo - 1]);
1572  Result := CurrentRow^.UpdateType = utInserted;
1573  end
1574  else
1575  Result := False;
1576 end;
1577 
1578 {**
1579  Indicates whether a row has been deleted. A deleted row may leave
1580  a visible "hole" in a result set. This method can be used to
1581  detect holes in a result set. The value returned depends on whether
1582  or not this <code>ResultSet</code> object can detect deletions.
1583 
1584  @return <code>true</code> if a row was deleted and deletions are detected;
1585  <code>false</code> otherwise
1586 }
1587 function TZAbstractCachedResultSet.RowDeleted: Boolean;
1588 var
1589  UpdateType: TZRowUpdateType;
1590 begin
1591  if (RowNo >= 1) and (RowNo <= LastRowNo) then
1592  begin
1593  UpdateType := PZRowBuffer(FRowsList[RowNo - 1])^.UpdateType;
1594  Result := UpdateType = utDeleted;
1595  end
1596  else
1597  Result := False;
1598 end;
1599 
1600 {**
1601  Inserts the contents of the insert row into this
1602  <code>ResultSet</code> object and into the database.
1603  The cursor must be on the insert row when this method is called.
1604 }
1605 procedure TZAbstractCachedResultSet.InsertRow;
1606 var
1607  TempRow: PZRowBuffer;
1608 begin
1609  CheckClosed;
1610 
1611  { Creates a new row. }
1612  TempRow := FRowAccessor.RowBuffer;
1613  FRowAccessor.Alloc;
1614  FRowAccessor.MoveFrom(FInsertedRow);
1615  FRowAccessor.RowBuffer^.UpdateType := utInserted;
1616  FRowAccessor.RowBuffer^.Index := GetNextRowIndex;
1617 
1618  AppendRow(FRowAccessor.RowBuffer);
1619 
1620  { Posts non-cached updates. }
1621  if not FCachedUpdates then
1622  begin
1623  try
1624  PostUpdates;
1625  except
1626  on E: Exception do
1627  begin
1628  { Restore the previous state. }
1629  FRowAccessor.DisposeBuffer(FInitialRowsList[FInitialRowsList.Count - 1]);
1630  FInitialRowsList.Delete(FInitialRowsList.Count - 1);
1631  FRowAccessor.DisposeBuffer(FCurrentRowsList[FCurrentRowsList.Count - 1]);
1632  FCurrentRowsList.Delete(FCurrentRowsList.Count - 1);
1633  FRowAccessor.RowBuffer := TempRow;
1634 
1635  { Reraises the exception. }
1636  RaiseSQLException(E);
1637  end;
1638  end;
1639  end;
1640 
1641  FRowsList.Add(FRowAccessor.RowBuffer);
1642  LastRowNo := FRowsList.Count;
1643  MoveAbsolute(LastRowNo);
1644 end;
1645 
1646 {**
1647  Updates the underlying database with the new contents of the
1648  current row of this <code>ResultSet</code> object.
1649  This method cannot be called when the cursor is on the insert row.
1650 }
1651 procedure TZAbstractCachedResultSet.UpdateRow;
1652 begin
1653  CheckUpdatable;
1654  if (RowNo < 1) or (RowNo > LastRowNo) then
1655  raise EZSQLException.Create(SCanNotUpdateEmptyRow);
1656 
1657  if PZRowBuffer(FRowsList[RowNo - 1]).UpdateType = utDeleted then
1658  raise EZSQLException.Create(SCanNotUpdateDeletedRow);
1659 
1660  if FSelectedRow <> FUpdatedRow then
1661  Exit;
1662 
1663  AppendRow(FRowsList[RowNo - 1]);
1664 
1665  FSelectedRow := PZRowBuffer(FRowsList[RowNo - 1]);
1666  FRowAccessor.CopyBuffer(FUpdatedRow, FSelectedRow);
1667  FRowAccessor.RowBuffer := FSelectedRow;
1668  if FSelectedRow.UpdateType = utUnmodified then
1669  FSelectedRow.UpdateType := utModified;
1670 
1671  { Posts non-cached updates. }
1672  if not FCachedUpdates then
1673  begin
1674  try
1675  PostUpdates;
1676  except
1677  on E: Exception do
1678  begin
1679  { Restore the previous state. }
1680  FRowAccessor.DisposeBuffer(FRowsList[RowNo - 1]);
1681  FRowsList[RowNo - 1] := FInitialRowsList[FInitialRowsList.Count - 1];
1682  FInitialRowsList.Delete(FInitialRowsList.Count - 1);
1683  FCurrentRowsList.Delete(FCurrentRowsList.Count - 1);
1684 
1685  FSelectedRow := PZRowBuffer(FRowsList[RowNo - 1]);
1686  FRowAccessor.RowBuffer := FSelectedRow;
1687 
1688  { Reraises the exception. }
1689  RaiseSQLException(E);
1690  end;
1691  end;
1692  end;
1693 end;
1694 
1695 {**
1696  Deletes the current row from this <code>ResultSet</code> object
1697  and from the underlying database. This method cannot be called when
1698  the cursor is on the insert row.
1699 }
1700 procedure TZAbstractCachedResultSet.DeleteRow;
1701 begin
1702  CheckUpdatable;
1703  if (RowNo < 1) or (RowNo > LastRowNo) or (FSelectedRow = nil) then
1704  raise EZSQLException.Create(SCanNotDeleteEmptyRow);
1705 
1706  if FSelectedRow^.UpdateType = utInserted then
1707  RevertRecord
1708  else
1709  begin
1710  AppendRow(FRowsList[RowNo - 1]);
1711 
1712  FSelectedRow^.UpdateType := utDeleted;
1713  if FSelectedRow = FUpdatedRow then
1714  FRowAccessor.CopyBuffer(FUpdatedRow, FRowsList[RowNo - 1]);
1715 
1716  { Posts non-cached updates. }
1717  if not FCachedUpdates then
1718  begin
1719  try
1720  PostUpdates;
1721  except
1722  on E: Exception do
1723  begin
1724  { Restores the previous state. }
1725  FRowAccessor.DisposeBuffer(FRowsList[RowNo - 1]);
1726  FRowsList[RowNo - 1] := FInitialRowsList[FInitialRowsList.Count - 1];
1727  FSelectedRow := FRowsList[RowNo - 1];
1728  FInitialRowsList.Delete(FInitialRowsList.Count - 1);
1729  FCurrentRowsList.Delete(FCurrentRowsList.Count - 1);
1730 
1731  { Rethrows the exception. }
1732  RaiseSQLException(E);
1733  end;
1734  end;
1735  end;
1736  end;
1737 end;
1738 
1739 {**
1740  Cancels the updates made to the current row in this
1741  <code>ResultSet</code> object.
1742  This method may be called after calling an
1743  <code>updateXXX</code> method(s) and before calling
1744  the method <code>updateRow</code> to roll back
1745  the updates made to a row. If no updates have been made or
1746  <code>updateRow</code> has already been called, this method has no
1747  effect.
1748 }
1749 procedure TZAbstractCachedResultSet.CancelRowUpdates;
1750 begin
1751  MoveAbsolute(RowNo);
1752 end;
1753 
1754 {**
1755  Moves the cursor to the insert row. The current cursor position is
1756  remembered while the cursor is positioned on the insert row.
1757 
1758  The insert row is a special row associated with an updatable
1759  result set. It is essentially a buffer where a new row may
1760  be constructed by calling the <code>updateXXX</code> methods prior to
1761  inserting the row into the result set.
1762 
1763  Only the <code>updateXXX</code>, <code>getXXX</code>,
1764  and <code>insertRow</code> methods may be
1765  called when the cursor is on the insert row. All of the columns in
1766  a result set must be given a value each time this method is
1767  called before calling <code>insertRow</code>.
1768  An <code>updateXXX</code> method must be called before a
1769  <code>getXXX</code> method can be called on a column value.
1770 }
1771 procedure TZAbstractCachedResultSet.MoveToInsertRow;
1772 begin
1773  CheckClosed;
1774  FRowAccessor.RowBuffer := FInsertedRow;
1775 end;
1776 
1777 {**
1778  Moves the cursor to the remembered cursor position, usually the
1779  current row. This method has no effect if the cursor is not on
1780  the insert row.
1781 }
1782 procedure TZAbstractCachedResultSet.MoveToCurrentRow;
1783 begin
1784  CheckClosed;
1785  if (RowNo >= 1) and (RowNo <= LastRowNo) then
1786  FRowAccessor.RowBuffer := FSelectedRow
1787  else
1788  FRowAccessor.RowBuffer := nil;
1789 end;
1790 
1791 {**
1792  Compares fields from two row buffers.
1793  @param Row1 the first row buffer to compare.
1794  @param Row2 the second row buffer to compare.
1795  @param ColumnIndices column indices to compare.
1796  @param ColumnDirs compare direction for each columns.
1797 }
1798 function TZAbstractCachedResultSet.CompareRows(Row1, Row2: Integer;
1799  const ColumnIndices: TIntegerDynArray; const ColumnDirs: TBooleanDynArray): Integer;
1800 var
1801  RowBuffer1, RowBuffer2: PZRowBuffer;
1802 begin
1803 {$IFNDEF DISABLE_CHECKING}
1804  if ResultSetType = rtForwardOnly then
1805  RaiseForwardOnlyException;
1806 {$ENDIF}
1807  RowBuffer1 := PZRowBuffer(FRowsList[Row1 - 1]);
1808  RowBuffer2 := PZRowBuffer(FRowsList[Row2 - 1]);
1809  Result := FRowAccessor.CompareBuffers(RowBuffer1, RowBuffer2,
1810  ColumnIndices, ColumnDirs);
1811 end;
1812 
1813 { TZCachedResultSet }
1814 
1815 {**
1816  Creates this object and assignes the main properties.
1817  @param ResultSet a wrapped resultset object.
1818  @param Resolver a cached updates resolver object.
1819 }
1820 constructor TZCachedResultSet.Create(ResultSet: IZResultSet; SQL: string;
1821  Resolver: IZCachedResolver; ConSettings: PZConSettings);
1822 begin
1823  inherited Create(ResultSet.GetStatement, SQL, nil, ConSettings);
1824  FResultSet := ResultSet;
1825  FResolver := Resolver;
1826  {BEGIN PATCH [1214009] CalcDefaults in TZUpdateSQL and Added Methods to GET the DB NativeResolver}
1827  FNativeResolver := Resolver;
1828  {END PATCH [1214009] CalcDefaults in TZUpdateSQL and Added Methods to GET the DB NativeResolver}
1829  Open;
1830 end;
1831 
1832 {**
1833  Destroys this object and cleanups the memory.
1834 }
1835 destructor TZCachedResultSet.Destroy;
1836 begin
1837  inherited Destroy;
1838 end;
1839 
1840 {**
1841  Fetches one row from the wrapped result set object.
1842  @return <code>True</code> if row was successfuly fetched
1843  or <code>False</code> otherwise.
1844 }
1845 function TZCachedResultSet.Fetch: Boolean;
1846 var
1847  I: Integer;
1848  TempRow: PZRowBuffer;
1849 begin
1850  Result := FResultSet.Next;
1851  if not Result or ((MaxRows > 0) and (LastRowNo >= MaxRows)) then
1852  Exit;
1853 
1854  TempRow := RowAccessor.RowBuffer;
1855  try
1856  RowAccessor.Alloc;
1857  RowAccessor.RowBuffer.Index := GetNextRowIndex;
1858  RowAccessor.RowBuffer.UpdateType := utUnmodified;
1859 
1860  for I := 1 to ColumnsInfo.Count do
1861  begin
1862  case TZColumnInfo(ColumnsInfo[I - 1]).ColumnType of
1863  stBoolean: RowAccessor.SetBoolean(I, ResultSet.GetBoolean(I));
1864  stByte: RowAccessor.SetByte(I, ResultSet.GetByte(I));
1865  stShort: RowAccessor.SetShort(I, ResultSet.GetShort(I));
1866  stInteger: RowAccessor.SetInt(I, ResultSet.GetInt(I));
1867  stLong: RowAccessor.SetLong(I, ResultSet.GetLong(I));
1868  stFloat: RowAccessor.SetFloat(I, ResultSet.GetFloat(I));
1869  stDouble: RowAccessor.SetDouble(I, ResultSet.GetDouble(I));
1870  stBigDecimal: RowAccessor.SetBigDecimal(I, ResultSet.GetBigDecimal(I));
1871  stString: RowAccessor.SetString(I, ResultSet.GetString(I));
1872  stUnicodeString: RowAccessor.SetUnicodeString(I,
1873  ResultSet.GetUnicodeString(I));
1874  stBytes,stGUID: RowAccessor.SetBytes(I, ResultSet.GetBytes(I));
1875  stDate: RowAccessor.SetDate(I, ResultSet.GetDate(I));
1876  stTime: RowAccessor.SetTime(I, ResultSet.GetTime(I));
1877  stTimestamp: RowAccessor.SetTimestamp(I, ResultSet.GetTimestamp(I));
1878  stAsciiStream, stBinaryStream, stUnicodeStream:
1879  RowAccessor.SetBlob(I, ResultSet.GetBlob(I));
1880  stDataSet: RowAccessor.SetDataSet(i, ResultSet.GetDataSet(I));
1881 
1882  end;
1883  if ResultSet.WasNull then
1884  RowAccessor.SetNull(I);
1885  end;
1886 
1887  RowsList.Add(RowAccessor.RowBuffer);
1888  LastRowNo := RowsList.Count;
1889  finally
1890  RowAccessor.RowBuffer := TempRow;
1891  end;
1892 end;
1893 
1894 {**
1895  Fetches all of the rest rows from the wrapped result set.
1896 }
1897 procedure TZCachedResultSet.FetchAll;
1898 begin
1899  while Fetch do;
1900 end;
1901 
1902 {**
1903  Opens this recordset.
1904 }
1905 procedure TZCachedResultSet.Open;
1906 var
1907  I: Integer;
1908  ColumnInfo: TZColumnInfo;
1909  MetaData : IZResultSetMetaData;
1910 begin
1911  ColumnsInfo.Clear;
1912  MetaData := FResultSet.GetMetadata;
1913  for I := 1 to Metadata.GetColumnCount do
1914  begin
1915  ColumnInfo := TZColumnInfo.Create;
1916  with ColumnInfo do
1917  begin
1918  Currency := Metadata.IsCurrency(I);
1919  Signed := Metadata.IsSigned(I);
1920  ColumnDisplaySize := Metadata.GetColumnDisplaySize(I);
1921  ColumnLabel := Metadata.GetColumnLabel(I);
1922  Precision := Metadata.GetPrecision(I);
1923  Scale := Metadata.GetScale(I);
1924  ColumnType := Metadata.GetColumnType(I);
1925  end;
1926  ColumnsInfo.Add(ColumnInfo);
1927  end;
1928 
1929  inherited Open;
1930 end;
1931 
1932 {**
1933  Releases this <code>ResultSet</code> object's database and
1934  JDBC resources immediately instead of waiting for
1935  this to happen when it is automatically closed.
1936 
1937  <P><B>Note:</B> A <code>ResultSet</code> object
1938  is automatically closed by the
1939  <code>Statement</code> object that generated it when
1940  that <code>Statement</code> object is closed,
1941  re-executed, or is used to retrieve the next result from a
1942  sequence of multiple results. A <code>ResultSet</code> object
1943  is also automatically closed when it is garbage collected.
1944 }
1945 procedure TZCachedResultSet.Close;
1946 begin
1947  inherited Close;
1948  ColumnsInfo.Clear;
1949  If Assigned(FResultset) then
1950  FResultset.Close;
1951  FResultSet := nil;
1952 end;
1953 
1954 {**
1955  Retrieves the number, types and properties of
1956  this <code>ResultSet</code> object's columns.
1957  @return the description of this <code>ResultSet</code> object's columns
1958 }
1959 function TZCachedResultSet.GetMetadata: IZResultSetMetadata;
1960 begin
1961  Result := ResultSet.GetMetadata;
1962 end;
1963 
1964 {**
1965  Indicates whether the cursor is after the last row in
1966  this <code>ResultSet</code> object.
1967 
1968  @return <code>true</code> if the cursor is after the last row;
1969  <code>false</code> if the cursor is at any other position or the
1970  result set contains no rows
1971 }
1972 function TZCachedResultSet.IsAfterLast: Boolean;
1973 begin
1974  FetchAll;
1975  Result := inherited IsAfterLast;
1976 end;
1977 
1978 {**
1979  Moves the cursor to the end of
1980  this <code>ResultSet</code> object, just after the
1981  last row. This method has no effect if the result set contains no rows.
1982 }
1983 procedure TZCachedResultSet.AfterLast;
1984 begin
1985  FetchAll;
1986  inherited AfterLast;
1987 end;
1988 
1989 {**
1990  Indicates whether the cursor is on the last row of
1991  this <code>ResultSet</code> object.
1992  Note: Calling the method <code>isLast</code> may be expensive
1993  because the JDBC driver
1994  might need to fetch ahead one row in order to determine
1995  whether the current row is the last row in the result set.
1996 
1997  @return <code>true</code> if the cursor is on the last row;
1998  <code>false</code> otherwise
1999 }
2000 function TZCachedResultSet.IsLast: Boolean;
2001 begin
2002  FetchAll;
2003  Result := inherited IsLast;
2004 end;
2005 
2006 {**
2007  Moves the cursor to the last row in
2008  this <code>ResultSet</code> object.
2009 
2010  @return <code>true</code> if the cursor is on a valid row;
2011  <code>false</code> if there are no rows in the result set
2012 }
2013 function TZCachedResultSet.Last: Boolean;
2014 begin
2015  FetchAll;
2016  Result := inherited Last;
2017 end;
2018 
2019 {**
2020  Moves the cursor to the given row number in
2021  this <code>ResultSet</code> object.
2022 
2023  <p>If the row number is positive, the cursor moves to
2024  the given row number with respect to the
2025  beginning of the result set. The first row is row 1, the second
2026  is row 2, and so on.
2027 
2028  <p>If the given row number is negative, the cursor moves to
2029  an absolute row position with respect to
2030  the end of the result set. For example, calling the method
2031  <code>absolute(-1)</code> positions the
2032  cursor on the last row; calling the method <code>absolute(-2)</code>
2033  moves the cursor to the next-to-last row, and so on.
2034 
2035  <p>An attempt to position the cursor beyond the first/last row in
2036  the result set leaves the cursor before the first row or after
2037  the last row.
2038 
2039  <p><B>Note:</B> Calling <code>absolute(1)</code> is the same
2040  as calling <code>first()</code>. Calling <code>absolute(-1)</code>
2041  is the same as calling <code>last()</code>.
2042 
2043  @return <code>true</code> if the cursor is on the result set;
2044  <code>false</code> otherwise
2045 }
2046 function TZCachedResultSet.MoveAbsolute(Row: Integer): Boolean;
2047 begin
2048  { Checks for maximum row. }
2049  Result := False;
2050  if (MaxRows > 0) and (Row > MaxRows) then
2051  Exit;
2052 
2053  { Processes negative rows }
2054  if Row < 0 then
2055  begin
2056  FetchAll;
2057  Row := LastRowNo - Row + 1;
2058  if Row < 0 then
2059  Row := 0;
2060  end
2061  else
2062  { Processes moving after last row }
2063  while (LastRowNo < Row) and Fetch do;
2064 
2065  Result := inherited MoveAbsolute(Row);
2066 end;
2067 
2068 end.
2069