source: oup/releases/0.20a/SQLiteTable3.pas@ 438

Last change on this file since 438 was 21, checked in by alloc, 18 years ago
File size: 22.9 KB
Line 
1unit SQLiteTable3;
2
3{
4 Simple classes for using SQLite's exec and get_table.
5
6 TSQLiteDatabase wraps the calls to open and close an SQLite database.
7 It also wraps SQLite_exec for queries that do not return a result set
8
9 TSQLiteTable wraps sqlite_get_table.
10 It allows accessing fields by name as well as index and can step through a
11 result set with the Next procedure.
12
13 Adapted by Tim Anderson (tim@itwriting.com)
14 Originally created by Pablo Pissanetzky (pablo@myhtpc.net)
15}
16
17interface
18
19uses
20 Windows, SQLite3, Classes, Sysutils;
21
22const
23 dtStr = 0;
24 dtInt = 1;
25 dtBool = 2;
26 dtNumeric = 3;
27 dtBlob = 4;
28
29type
30
31 ESQLiteException = class(Exception)
32 private
33 public
34 end;
35
36 TSQLiteTable = class;
37
38 TSQLiteDatabase = class
39 private
40 fDB: TSQLiteDB;
41 fInTrans: Boolean;
42 procedure RaiseError(s: string; SQL: string);
43
44 public
45 constructor Create(const FileName: string);
46 destructor Destroy; override;
47 function GetTable(const SQL: string): TSQLiteTable;
48 procedure ExecSQL(const SQL: string);
49 procedure UpdateBlob(const SQL: string; BlobData: TStream);
50 procedure BeginTransaction;
51 procedure Commit;
52 procedure Rollback;
53 function TableExists(TableName: string): boolean;
54 function GetLastInsertRowID: int64;
55
56 published
57 property isTransactionOpen: boolean read fInTrans;
58
59 end;
60
61 TSQLiteTable = class
62 private
63 fResults: TList;
64 fRowCount: Cardinal;
65 fColCount: Cardinal;
66 fCols: TStringList;
67 fColTypes: TList;
68 fRow: Cardinal;
69
70 function GetFields(I: Integer): string;
71 function GetEOF: Boolean;
72 function GetBOF: Boolean;
73 function GetColumns(I: Integer): string;
74 function GetFieldByName(FieldName: string): string;
75 function GetFieldIndex(FieldName: string): integer;
76 function GetCount: Integer;
77 function GetCountResult: Integer;
78
79
80 public
81 constructor Create(DB: TSQLiteDatabase; const SQL: string);
82 destructor Destroy; override;
83 function FieldAsInteger(FieldName: string): integer;
84 function FieldAsBool(FieldName: string): boolean;
85 function FieldAsBlob(FieldName: string): TMemoryStream;
86 function FieldAsBlobText(FieldName: string): string;
87 function FieldIsNull(FieldName: string): boolean;
88 function FieldAsString(FieldName: string): string;
89 function FieldAsDouble(FieldName: string): double;
90{ function FieldAsInteger(I: integer): integer;
91 function FieldAsBool(I: integer): boolean;
92 function FieldAsBlob(I: Integer): TMemoryStream;
93 function FieldAsBlobText(I: Integer): string;
94 function FieldIsNull(I: integer): boolean;
95 function FieldAsString(I: Integer): string;
96 function FieldAsDouble(I: Integer): double;
97} function Next: Boolean;
98 function Previous: Boolean;
99 property EOF: Boolean read GetEOF;
100 property BOF: Boolean read GetBOF;
101 property Fields[I: Integer]: string read GetFields;
102 property FieldByName[FieldName: string]: string read GetFieldByName;
103 property FieldIndex[FieldName: string]: integer read GetFieldIndex;
104 property Columns[I: Integer]: string read GetColumns;
105 property ColCount: Cardinal read fColCount;
106 property RowCount: Cardinal read fRowCount;
107 property Row: Cardinal read fRow;
108 function MoveFirst: boolean;
109 function MoveLast: boolean;
110
111
112 property Count: Integer read GetCount;
113
114 // The property CountResult is used when you execute count(*) queries.
115 // It returns 0 if the result set is empty or the value of the
116 // first field as an integer.
117 property CountResult: Integer read GetCountResult;
118 end;
119
120
121procedure DisposePointer(ptr: pointer); cdecl;
122
123implementation
124
125uses
126 strutils;
127
128
129procedure DisposePointer(ptr: pointer); cdecl;
130begin
131
132 if assigned(ptr) then
133 begin freemem(ptr) end;
134
135end;
136
137//------------------------------------------------------------------------------
138// TSQLiteDatabase
139//------------------------------------------------------------------------------
140
141constructor TSQLiteDatabase.Create(const FileName: string);
142var
143 Msg: pchar;
144 iResult: integer;
145begin
146 inherited Create;
147
148 self.fInTrans := false;
149
150 Msg := nil;
151 try
152 iResult := SQLite3_Open(PChar(FileName), Fdb);
153
154 if iResult <> SQLITE_OK then
155 begin
156 if Assigned(Fdb) then
157 begin
158 Msg := Sqlite3_ErrMsg(Fdb);
159 raise ESqliteException.CreateFmt('Failed to open database "%s" : %s', [FileName, Msg]);
160 end
161 else
162 begin raise ESqliteException.CreateFmt('Failed to open database "%s" : unknown error', [FileName]) end;
163 end;
164
165 //set a few configs
166 self.ExecSQL('PRAGMA SYNCHRONOUS=NORMAL;');
167
168 //this pragma not recommended and may disappear in future
169 //sqlite versions
170 //self.ExecSQL('PRAGMA full_column_names = 1;');
171
172 finally
173 if Assigned(Msg) then
174 begin SQLite3_Free(Msg) end;
175 end;
176
177
178end;
179
180
181//..............................................................................
182
183destructor TSQLiteDatabase.Destroy;
184begin
185
186 if self.fInTrans then
187 begin self.ExecSQL('ROLLBACK;') end; //assume rollback
188
189 if Assigned(fDB) then
190 begin SQLite3_Close(fDB) end;
191
192 inherited;
193end;
194
195function TSQLiteDatabase.GetLastInsertRowID: int64;
196begin
197 result := Sqlite3_LastInsertRowID(self.fDB);
198end;
199
200//..............................................................................
201
202procedure TSQLiteDatabase.RaiseError(s: string; SQL: string);
203//look up last error and raise and exception with an appropriate message
204var
205 Msg: PChar;
206begin
207
208 Msg := nil;
209
210 if sqlite3_errcode(self.fDB) <> SQLITE_OK then
211 Msg := sqlite3_errmsg(self.fDB);
212
213 IF Pos('DROP TABLE ',SQL)>0 THEN Exit;
214
215 if Msg <> nil then
216 raise ESqliteException.CreateFmt(s + ' "%s" : %s', [SQL, Msg])
217 else
218 raise ESqliteException.CreateFmt(s, [SQL, 'No message']);
219
220end;
221
222procedure TSQLiteDatabase.ExecSQL(const SQL: string);
223var
224 Stmt: TSQLiteStmt;
225 NextSQLStatement: Pchar;
226 iStepResult: integer;
227begin
228 try
229
230 if Sqlite3_Prepare(self.fDB, PChar(SQL), -1, Stmt, NextSQLStatement) <> SQLITE_OK then
231 begin RaiseError('Error executing SQL', SQL) end;
232
233 if (Stmt = nil) then
234 begin RaiseError('Could not prepare SQL statement', SQL) end;
235
236 iStepResult := Sqlite3_step(Stmt);
237
238 if (iStepResult <> SQLITE_DONE) then
239 begin RaiseError('Error executing SQL statement', SQL) end;
240
241 finally
242
243 if Assigned(Stmt) then
244 begin Sqlite3_Finalize(stmt) end;
245
246 end;
247end;
248
249procedure TSQLiteDatabase.UpdateBlob(const SQL: string; BlobData: TStream);
250var
251 iSize: integer;
252 ptr: pointer;
253 Stmt: TSQLiteStmt;
254 Msg: Pchar;
255 NextSQLStatement: Pchar;
256 iStepResult: integer;
257 iBindResult: integer;
258begin
259//expects SQL of the form 'UPDATE MYTABLE SET MYFIELD = ? WHERE MYKEY = 1'
260
261 if pos('?', SQL) = 0 then
262 begin RaiseError('SQL must include a ? parameter', SQL) end;
263
264 Msg := nil;
265 try
266
267 if Sqlite3_Prepare(self.fDB, PChar(SQL), -1, Stmt, NextSQLStatement) <> SQLITE_OK then
268 begin RaiseError('Could not prepare SQL statement', SQL) end;
269
270 if (Stmt = nil) then
271 begin RaiseError('Could not prepare SQL statement', SQL) end;
272
273//now bind the blob data
274 iSize := BlobData.size;
275
276 GetMem(ptr, iSize);
277
278 if (ptr = nil) then
279 begin raise ESqliteException.CreateFmt('Error getting memory to save blob', [SQL, 'Error']) end;
280
281 BlobData.position := 0;
282 BlobData.Read(ptr^, iSize);
283
284 iBindResult := SQLite3_BindBlob(stmt, 1, ptr, iSize, @DisposePointer);
285
286 if iBindResult <> SQLITE_OK then
287 begin RaiseError('Error binding blob to database', SQL) end;
288
289 iStepResult := Sqlite3_step(Stmt);
290
291 if (iStepResult <> SQLITE_DONE) then
292 begin RaiseError('Error executing SQL statement', SQL) end;
293
294 finally
295
296 if Assigned(Stmt) then
297 begin Sqlite3_Finalize(stmt) end;
298
299 if Assigned(Msg) then
300 begin SQLite3_Free(Msg) end;
301 end;
302
303end;
304
305//..............................................................................
306
307function TSQLiteDatabase.GetTable(const SQL: string): TSQLiteTable;
308begin
309 Result := TSQLiteTable.Create(Self, SQL);
310end;
311
312procedure TSQLiteDatabase.BeginTransaction;
313begin
314 if not self.fInTrans then
315 begin
316 self.ExecSQL('BEGIN TRANSACTION;');
317 self.fInTrans := true;
318 end
319 else
320 begin raise ESqliteException.Create('Transaction already open') end;
321end;
322
323procedure TSQLiteDatabase.Commit;
324begin
325 self.ExecSQL('COMMIT;');
326 self.fInTrans := false;
327end;
328
329procedure TSQLiteDatabase.Rollback;
330begin
331 self.ExecSQL('ROLLBACK;');
332 self.fInTrans := false;
333end;
334
335function TSQLiteDatabase.TableExists(TableName: string): boolean;
336var
337 sql: string;
338 ds: TSqliteTable;
339begin
340//returns true if table exists in the database
341 sql := 'select [sql] from sqlite_master where [type] = ''table'' and lower(name) = ''' + lowercase(TableName) + ''' ';
342
343 try
344
345 ds := self.GetTable(sql);
346
347 result := (ds.Count > 0);
348
349 finally
350
351 freeandnil(ds);
352
353 end;
354
355end;
356
357
358//------------------------------------------------------------------------------
359// TSQLiteTable
360//------------------------------------------------------------------------------
361
362constructor TSQLiteTable.Create(DB: TSQLiteDatabase; const SQL: string);
363var
364 Stmt: TSQLiteStmt;
365 NextSQLStatement: Pchar;
366 iStepResult: integer;
367
368 ptr: pointer;
369 iNumBytes: integer;
370 thisBlobValue: TMemoryStream;
371 thisStringValue: pstring;
372 thisBoolValue: pBoolean;
373 thisDoubleValue: pDouble;
374 thisIntValue: pInteger;
375 thisColType: pInteger;
376 i: integer;
377 DeclaredColType: Pchar;
378 ActualColType: integer;
379 ptrValue: Pchar;
380
381begin
382
383 try
384
385 self.fRowCount := 0;
386 self.fColCount := 0;
387
388//if there are several SQL statements in SQL, NextSQLStatment points to the
389//beginning of the next one. Prepare only prepares the first SQL statement.
390
391 if Sqlite3_Prepare(Db.fDB, PChar(SQL), -1, Stmt, NextSQLStatement) <> SQLITE_OK then
392 begin Db.RaiseError('Error executing SQL', SQL) end;
393
394 if (Stmt = nil) then
395 begin Db.RaiseError('Could not prepare SQL statement', SQL) end;
396
397 iStepResult := Sqlite3_step(Stmt);
398
399 while (iStepResult <> SQLITE_DONE) do
400 begin
401
402 case iStepResult of
403 SQLITE_ROW:
404 begin
405
406 inc(fRowCount);
407
408 if (fRowCount = 1) then
409 begin
410 //get data types
411 fCols := TStringList.Create;
412 fCols.CaseSensitive := False;
413 fColTypes := TList.Create;
414
415 fColCount := SQLite3_ColumnCount(stmt);
416
417 for i := 0 to Pred(fColCount) do
418 begin
419 fCols.Add(Sqlite3_ColumnName(stmt, i));
420 end;
421
422 for i := 0 to Pred(fColCount) do
423 begin
424
425 new(thisColType);
426 DeclaredColType := Sqlite3_ColumnDeclType(stmt, i);
427
428 if DeclaredColType = nil then begin
429 //use the actual column type instead
430 //seems to be needed for last_insert_rowid
431 thisColType^ := Sqlite3_ColumnType(stmt, i);
432 end else begin
433 DeclaredColType := strupper(DeclaredColType);
434
435 if DeclaredColType = 'INTEGER' then
436 begin thisColType^ := dtInt end
437 else
438 if DeclaredColType = 'BOOLEAN' then
439 begin thisColType^ := dtBool end
440 else
441 if (DeclaredColType = 'NUMERIC') or (DeclaredColType = 'FLOAT') or (DeclaredColType = 'DOUBLE') then
442 begin thisColType^ := dtNumeric end
443 else
444 if DeclaredColType = 'BLOB' then
445 begin thisColType^ := dtBlob end
446 else
447 begin thisColType^ := dtStr end;
448 end;
449
450 fColTypes.Add(thiscoltype);
451 end;
452
453 fResults := TList.Create;
454
455 end;
456
457 //get column values
458 for i := 0 to Pred(ColCount) do
459 begin
460
461 ActualColType := Sqlite3_ColumnType(stmt, i);
462 if (ActualColType = SQLITE_NULL) then
463 begin fResults.Add(nil) end
464 else
465 begin
466 if pInteger(fColTypes[i])^ = dtInt then
467 begin
468 new(thisintvalue);
469 thisintvalue^ := Sqlite3_ColumnInt(stmt, i);
470 fResults.Add(thisintvalue);
471 end
472 else
473 if pInteger(fColTypes[i])^ = dtBool then
474 begin
475 new(thisboolvalue);
476 thisboolvalue^ := not (Sqlite3_ColumnInt(stmt, i) = 0);
477 fResults.Add(thisboolvalue);
478 end
479 else
480 if pInteger(fColTypes[i])^ = dtNumeric then
481 begin
482 new(thisdoublevalue);
483 thisdoublevalue^ := Sqlite3_ColumnDouble(stmt, i);
484 fResults.Add(thisdoublevalue);
485 end
486 else
487 if pInteger(fColTypes[i])^ = dtBlob then
488 begin
489 iNumBytes := Sqlite3_ColumnBytes(stmt, i);
490
491 if iNumBytes = 0 then
492 begin thisblobvalue := nil end
493 else
494 begin
495 thisblobvalue := TMemoryStream.Create;
496 thisblobvalue.position := 0;
497 ptr := Sqlite3_ColumnBlob(stmt, i);
498 thisblobvalue.writebuffer(ptr^, iNumBytes);
499 end;
500 fResults.Add(thisblobvalue);
501
502 end
503 else
504 begin
505 new(thisstringvalue);
506 ptrValue := Sqlite3_ColumnText(stmt, i);
507 setstring(thisstringvalue^, ptrvalue, strlen(ptrvalue));
508 fResults.Add(thisstringvalue);
509 end;
510 end;
511
512 end;
513
514
515
516 end;
517
518 SQLITE_BUSY:
519 begin raise ESqliteException.CreateFmt('Could not prepare SQL statement', [SQL, 'SQLite is Busy']) end;
520 else
521 begin Db.RaiseError('Could not retrieve data', SQL) end;
522 end;
523
524 iStepResult := Sqlite3_step(Stmt);
525
526 end;
527
528 fRow := 0;
529
530 finally
531 if Assigned(Stmt) then
532 begin Sqlite3_Finalize(stmt) end;
533 end;
534
535end;
536
537//..............................................................................
538
539destructor TSQLiteTable.Destroy;
540var i: integer;
541 iColNo: integer;
542begin
543
544
545 if Assigned(fResults) then
546 begin for i := 0 to fResults.Count - 1 do
547 begin
548 //check for blob type
549 iColNo := (i mod fColCount);
550 case pInteger(self.fColTypes[iColNo])^ of
551 dtBlob:
552 begin
553 TMemoryStream(fResults[i]).free;
554 end;
555 dtStr:
556 begin
557 if fResults[i] <> nil then
558 begin
559 setstring(string(fResults[i]^), nil, 0);
560 dispose(fResults[i]);
561 end;
562 end;
563 else
564 begin
565 dispose(fResults[i])
566 end;
567 end;
568 end;
569 fResults.Free;
570 end;
571
572 if Assigned(fCols) then
573 begin fCols.Free end;
574
575 if Assigned(fColTypes) then
576 begin for i := 0 to fColTypes.Count - 1 do
577 begin
578 dispose(fColTypes[i]);
579 end end;
580 fColTypes.Free;
581 inherited;
582 end;
583
584//..............................................................................
585
586function TSQLiteTable.GetColumns(I: Integer): string;
587begin
588 Result := fCols[I];
589end;
590
591//..............................................................................
592
593function TSQLiteTable.GetCountResult: Integer;
594begin
595 if not EOF then
596 begin Result := StrToInt(Fields[0]) end
597 else
598 begin Result := 0 end;
599end;
600
601function TSQLiteTable.GetCount: Integer;
602begin
603 Result := FRowCount;
604end;
605
606//..............................................................................
607
608function TSQLiteTable.GetEOF: Boolean;
609begin
610 Result := fRow >= fRowCount;
611end;
612
613function TSQLiteTable.GetBOF: Boolean;
614begin
615 Result := fRow <= 0;
616end;
617
618//..............................................................................
619
620function TSQLiteTable.GetFieldByName(FieldName: string): string;
621begin
622 Result := GetFields(self.GetFieldIndex(FieldName));
623end;
624
625function TSQLiteTable.GetFieldIndex(FieldName: string): integer;
626begin
627
628 if (fCols = nil) then
629 begin
630 raise ESqliteException.Create('Field ' + fieldname + ' Not found. Empty dataset');
631 exit;
632 end;
633
634 if (fCols.count = 0) then
635 begin
636 raise ESqliteException.Create('Field ' + fieldname + ' Not found. Empty dataset');
637 exit;
638 end;
639
640 result := fCols.IndexOf(FieldName);
641
642 if (result < 0) then
643 begin raise ESqliteException.Create('Field not found in dataset: ' + fieldname) end;
644
645end;
646
647//..............................................................................
648
649function TSQLiteTable.GetFields(I: Integer): string;
650var
651 thisvalue: pstring;
652 ptr: pointer;
653 thisboolvalue: pBoolean;
654 thistype: integer;
655begin
656 Result := '';
657
658 if EOF then
659 begin raise ESqliteException.Create('Table is at End of File') end;
660
661//integer and boolean types are not stored in the resultset
662//as strings, so they should be retrieved using the type-specific
663//methods
664
665 thistype := pInteger(self.fColTypes[I])^;
666
667 if (thistype = dtInt) or (thistype = dtNumeric) or (thistype = dtBlob) then
668 begin
669 ptr := self.fResults[(self.frow * self.fColCount) + I];
670
671 if ptr <> nil then
672 begin
673 raise ESqliteException.Create('Use the specific methods for integer, numeric or blob fields');
674 end;
675
676 end
677 else
678 if pInteger(self.fColTypes[I])^ = dtBool then
679 begin
680 thisboolvalue := self.fResults[(self.frow * self.fColCount) + I];
681 if thisboolvalue <> nil then
682 begin if thisboolvalue^ then
683 begin result := '1' end
684 else
685 begin result := '0' end end;
686 end
687
688 else
689
690 begin
691
692 thisvalue := self.fResults[(self.frow * self.fColCount) + I];
693 if (thisvalue <> nil) then
694 begin Result := thisvalue^ end
695 else
696 begin Result := '' end; //return empty string
697 end;
698
699end;
700
701function TSqliteTable.FieldAsBlob(FieldName: string): TMemoryStream;
702var
703 i: Integer;
704begin
705
706 if EOF then
707 begin raise ESqliteException.Create('Table is at End of File') end;
708
709 i:=Self.FieldIndex[FieldName];
710
711 if (self.fResults[(self.frow * self.fColCount) + I] = nil) then
712 begin result := nil end
713 else
714 if pInteger(self.fColTypes[I])^ = dtBlob then
715 begin result := TMemoryStream(self.fResults[(self.frow * self.fColCount) + I]) end
716 else
717 begin raise ESqliteException.Create('Not a Blob field') end;
718end;
719
720function TSqliteTable.FieldAsBlobText(FieldName: string): string;
721var
722 MemStream: TMemoryStream;
723 Buffer: PChar;
724begin
725 result := '';
726
727 MemStream := self.FieldAsBlob(FieldName);
728
729 if MemStream <> nil then
730 begin if MemStream.Size > 0 then
731 begin
732 MemStream.position := 0;
733
734 Buffer := stralloc(MemStream.Size + 1);
735 MemStream.readbuffer(Buffer[0], MemStream.Size);
736 (Buffer + MemStream.Size)^ := chr(0);
737 SetString(Result, Buffer, MemStream.size);
738 strdispose(Buffer);
739 end end;
740
741end;
742
743
744function TSqliteTable.FieldAsInteger(FieldName: string): integer;
745var
746 i: Integer;
747begin
748
749 if EOF then
750 begin raise ESqliteException.Create('Table is at End of File') end;
751
752 i:=Self.FieldIndex[FieldName];
753
754 if (self.fResults[(self.frow * self.fColCount) + I] = nil) then
755 begin result := 0 end
756 else
757 if pInteger(self.fColTypes[I])^ = dtInt then
758 begin result := pInteger(self.fResults[(self.frow * self.fColCount) + I])^ end
759 else
760 if pInteger(self.fColTypes[I])^ = dtNumeric then
761 begin result := trunc(strtofloat(pString(self.fResults[(self.frow * self.fColCount) + I])^)) end
762 else
763 begin raise ESqliteException.Create('Not an integer or numeric field') end;
764
765end;
766
767function TSqliteTable.FieldAsDouble(FieldName: string): double;
768var
769 i: Integer;
770begin
771
772 if EOF then
773 begin raise ESqliteException.Create('Table is at End of File') end;
774
775 i:=Self.FieldIndex[FieldName];
776
777 if (self.fResults[(self.frow * self.fColCount) + I] = nil) then
778 begin result := 0 end
779 else
780 if pInteger(self.fColTypes[I])^ = dtInt then
781 begin result := pInteger(self.fResults[(self.frow * self.fColCount) + I])^ end
782 else
783 if pInteger(self.fColTypes[I])^ = dtNumeric then
784 begin result := pDouble(self.fResults[(self.frow * self.fColCount) + I])^ end
785 else
786 begin raise ESqliteException.Create('Not an integer or numeric field') end;
787
788end;
789
790function TSqliteTable.FieldAsBool(FieldName: string): boolean;
791var
792 i: Integer;
793begin
794
795 if EOF then
796 begin raise ESqliteException.Create('Table is at End of File') end;
797
798 i:=Self.FieldIndex[FieldName];
799
800 if (self.fResults[(self.frow * self.fColCount) + I] = nil) then
801 begin result := false end
802 else
803 if pInteger(self.fColTypes[I])^ = dtBool then
804 begin result := pBoolean(self.fResults[(self.frow * self.fColCount) + I])^ end
805 else
806 begin raise ESqliteException.Create('Not a boolean field') end;
807end;
808
809function TSqliteTable.FieldAsString(FieldName: string): string;
810var
811 i: Integer;
812begin
813
814 if EOF then
815 begin raise ESqliteException.Create('Table is at End of File') end;
816
817 i:=Self.FieldIndex[FieldName];
818
819 if (self.fResults[(self.frow * self.fColCount) + I] = nil) then
820 begin result := '' end
821 else
822 begin result := self.GetFields(I) end;
823
824end;
825
826function TSqliteTable.FieldIsNull(FieldName: string): boolean;
827var
828 thisvalue: pointer;
829 i: Integer;
830begin
831
832 if EOF then
833 begin raise ESqliteException.Create('Table is at End of File') end;
834
835 i:=Self.FieldIndex[FieldName];
836
837 thisvalue := self.fResults[(self.frow * self.fColCount) + I];
838 result := (thisvalue = nil);
839end;
840
841//..............................................................................
842
843function TSQLiteTable.Next: boolean;
844begin
845 result := false;
846 if not EOF then
847 begin
848 Inc(fRow);
849 result := true;
850 end;
851end;
852
853function TSQLiteTable.Previous: boolean;
854begin
855 result := false;
856 if not BOF then
857 begin
858 Dec(fRow);
859 result := true;
860 end;
861end;
862
863function TSQLiteTable.MoveFirst: boolean;
864begin
865 result := false;
866 if self.fRowCount > 0 then
867 begin
868 fRow := 0;
869 result := true;
870 end;
871end;
872
873function TSQLiteTable.MoveLast: boolean;
874begin
875 result := false;
876 if self.fRowCount > 0 then
877 begin
878 fRow := fRowCount - 1;
879 result := true;
880 end;
881end;
882
883
884end.
885
Note: See TracBrowser for help on using the repository browser.