?? sqlitetable3.pas
字號:
Unit SQLiteTable3;
{
Simple classes for using SQLite's exec and get_table.
TSQLiteDatabase wraps the calls to open and close an SQLite database.
It also wraps SQLite_exec for queries that do not return a result set
TSQLiteTable wraps sqlite_get_table.
It allows accessing fields by name as well as index and can step through a
result set with the Next procedure.
Adapted by Tim Anderson (tim@itwriting.com)
Originally created by Pablo Pissanetzky (pablo@myhtpc.net)
Modified and enhanced by Lukas Gebauer
}
{$I Sqlite.inc}
Interface
Uses
Windows, SQLite3Lib, SQLite3Types, Classes, SysUtils;
Type
ESQLiteException = Class(Exception)
End;
TSQLiteTable = Class;
TSQLiteDatabase = Class
Private
fPassWord, fOldPassWord: String;
fDB: TSQLiteDB;
fInTrans: boolean;
Procedure RaiseError(s: String; SQL: String);
Public
Constructor Create(Const FileName: String; Const PassWord: String = '');
Destructor Destroy; Override;
Function GetTable(Const SQL: String): TSQLiteTable;
Procedure ExecSQL(Const SQL: String);
Function GetTableValue(Const SQL: String): int64;
Function GetTableString(Const SQL: String): String;
Procedure UpdateBlob(Const SQL: String; BlobData: TStream);
Procedure BeginTransaction;
Procedure Commit;
Procedure Rollback;
Function TableExists(TableName: String): boolean;
Function GetLastInsertRowID: int64;
Procedure SetTimeout(Value: integer);
Function version: String;
Published
Property isTransactionOpen: boolean Read fInTrans;
Property PassWord: String Read fPassWord Write fPassWord;
End;
TSQLiteTable = Class
Private
fResults: TList;
fRowCount: cardinal;
fColCount: cardinal;
fCols: TStringList;
fColTypes: TList;
fRow: cardinal;
Function GetFields(I: cardinal): String;
Function GetEOF: boolean;
Function GetBOF: boolean;
Function GetColumns(I: integer): String;
Function GetFieldByName(FieldName: String): String;
Function GetFieldIndex(FieldName: String): integer;
Function GetCount: integer;
Function GetCountResult: integer;
Public
Constructor Create(DB: TSQLiteDatabase; Const SQL: String);
Destructor Destroy; Override;
Function FieldAsInteger(I: cardinal): int64;
Function FieldAsBlob(I: cardinal): TMemoryStream;
Function FieldAsBlobText(I: cardinal): String;
Function FieldIsNull(I: cardinal): boolean;
Function FieldAsString(I: cardinal): String;
Function FieldAsDouble(I: cardinal): double;
Function Next: boolean;
Function Previous: boolean;
Property Eof: boolean Read GetEOF;
Property BOF: boolean Read GetBOF;
Property Fields[I: cardinal]: String Read GetFields;
Property FieldByName[FieldName: String]: String Read GetFieldByName;
Property FieldIndex[FieldName: String]: integer Read GetFieldIndex;
Property Columns[I: integer]: String Read GetColumns;
Property ColCount: cardinal Read fColCount;
Property RowCount: cardinal Read fRowCount;
Property Row: cardinal Read fRow;
Function MoveFirst: boolean;
Function MoveLast: boolean;
Property Count: integer Read GetCount;
// The property CountResult is used when you execute count(*) queries.
// It returns 0 if the result set is empty or the value of the
// first field as an integer.
End;
Procedure DisposePointer(ptr: pointer); cdecl;
Implementation
Procedure DisposePointer(ptr: pointer); Cdecl;
Begin
If Assigned(ptr) Then
FreeMem(ptr);
End;
//------------------------------------------------------------------------------
// TSQLiteDatabase
//------------------------------------------------------------------------------
Constructor TSQLiteDatabase.Create(Const FileName: String; Const PassWord: String = '');
Var
Msg: PAnsiChar;
iResult: integer;
Begin
Inherited Create;
SQLite3LoadLibrary;
self.fInTrans := False;
Msg := Nil;
Try
iResult := SQLite3_Open(PAnsiChar(AnsiToUtf8(FileName)), fDB);
If iResult <> SQLITE_OK Then
If Assigned(fDB) Then
Begin
Msg := Sqlite3_ErrMsg(fDB);
Raise ESQLiteException.CreateFmt('Failed to open database "%s" : %s',
[FileName, Msg]);
End
Else
Raise ESQLiteException.CreateFmt('Failed to open database "%s" : unknown error',
[FileName]);
If PassWord <> '' Then
Begin
fPassWord := PassWord;
fOldPassWord := fPassWord;
{$IFDEF UseSQLiteCrypt}
If Assigned(SqLite3_Key) Then
SqLite3_Key(fDB, PAnsiChar(fPassWord), Length(fPassWord));
{$ENDIF}
End;
//set a few configs
self.ExecSQL('PRAGMA SYNCHRONOUS=NORMAL;');
// self.ExecSQL('PRAGMA full_column_names = 1;');
self.ExecSQL('PRAGMA temp_store = MEMORY;');
Finally
If Assigned(Msg) Then
SQLite3_Free(Msg);
End;
End;
//..............................................................................
Destructor TSQLiteDatabase.Destroy;
Begin
If self.fInTrans Then
self.ExecSQL('ROLLBACK;'); //assume rollback
If fPassWord <> fOldPassWord Then
Begin
{$IFDEF UseSQLiteCrypt}
If Assigned(SqLite3_Rekey) Then
SqLite3_Rekey(fDB, PAnsiChar(fPassWord), Length(fPassWord));
{$ENDIF}
End;
If Assigned(fDB) Then
SQLite3_Close(fDB);
SQLite3FreeLibrary;
Inherited;
End;
Function TSQLiteDatabase.GetLastInsertRowID: int64;
Begin
Result := SQLite3_Last_Insert_RowID(self.fDB);
End;
//..............................................................................
Procedure TSQLiteDatabase.RaiseError(s: String; SQL: String);
//look up last error and raise an exception with an appropriate message
Var
Msg: PAnsiChar;
Begin
Msg := Nil;
If sqlite3_errcode(self.fDB) <> SQLITE_OK Then
Msg := Sqlite3_ErrMsg(self.fDB);
If Msg <> Nil Then
Raise ESQLiteException.CreateFmt(s + ' "%s" : %s', [SQL, Msg])
Else
Raise ESQLiteException.CreateFmt(s, [SQL, 'No message']);
End;
Procedure TSQLiteDatabase.ExecSQL(Const SQL: String);
Var
Stmt: TSQLiteStmt;
NextSQLStatement: PAnsiChar;
iStepResult: integer;
Begin
Try
If Sqlite3_Prepare(self.fDB, PAnsiChar(SQL), -1, Stmt, NextSQLStatement) <>
SQLITE_OK Then
RaiseError('Error executing SQL', SQL);
If (Stmt = Nil) Then
RaiseError('Could not prepare SQL statement', SQL);
iStepResult := Sqlite3_step(Stmt);
If (iStepResult <> SQLITE_DONE) Then
RaiseError('Error executing SQL statement', SQL);
Finally
If Assigned(Stmt) Then
Sqlite3_Finalize(Stmt);
End;
End;
Procedure TSQLiteDatabase.UpdateBlob(Const SQL: String; BlobData: TStream);
Var
iSize: integer;
ptr: pointer;
Stmt: TSQLiteStmt;
Msg: PAnsiChar;
NextSQLStatement: PAnsiChar;
iStepResult: integer;
iBindResult: integer;
Begin
//expects SQL of the form 'UPDATE MYTABLE SET MYFIELD = ? WHERE MYKEY = 1'
If Pos('?', SQL) = 0 Then
RaiseError('SQL must include a ? parameter', SQL);
Msg := Nil;
Try
If Sqlite3_Prepare(self.fDB, PAnsiChar(SQL), -1, Stmt, NextSQLStatement) <>
SQLITE_OK Then
RaiseError('Could not prepare SQL statement', SQL);
If (Stmt = Nil) Then
RaiseError('Could not prepare SQL statement', SQL);
//now bind the blob data
iSize := BlobData.size;
GetMem(ptr, iSize);
If (ptr = Nil) Then
Raise ESQLiteException.CreateFmt('Error getting memory to save blob',
[SQL, 'Error']);
BlobData.position := 0;
BlobData.Read(ptr^, iSize);
iBindResult := SQLite3_Bind_Blob(Stmt, 1, ptr, iSize, @DisposePointer);
If iBindResult <> SQLITE_OK Then
RaiseError('Error binding blob to database', SQL);
iStepResult := Sqlite3_step(Stmt);
If (iStepResult <> SQLITE_DONE) Then
RaiseError('Error executing SQL statement', SQL);
Finally
If Assigned(Stmt) Then
Sqlite3_Finalize(Stmt);
If Assigned(Msg) Then
SQLite3_Free(Msg);
End;
End;
//..............................................................................
Function TSQLiteDatabase.GetTable(Const SQL: String): TSQLiteTable;
Begin
Result := TSQLiteTable.Create(self, SQL);
End;
Function TSQLiteDatabase.GetTableValue(Const SQL: String): int64;
Var
Table: TSQLiteTable;
Begin
Table := self.GetTable(SQL);
Try
Result := Table.FieldAsInteger(0);
Finally
Table.Free;
End;
End;
Function TSQLiteDatabase.GetTableString(Const SQL: String): String;
Var
Table: TSQLiteTable;
Begin
Table := self.GetTable(SQL);
Try
Result := Table.FieldAsString(0);
Finally
Table.Free;
End;
End;
Procedure TSQLiteDatabase.BeginTransaction;
Begin
If Not self.fInTrans Then
Begin
self.ExecSQL('BEGIN TRANSACTION;');
self.fInTrans := True;
End
Else
Raise ESQLiteException.Create('Transaction already open');
End;
Procedure TSQLiteDatabase.Commit;
Begin
self.ExecSQL('COMMIT;');
self.fInTrans := False;
End;
Procedure TSQLiteDatabase.Rollback;
Begin
self.ExecSQL('ROLLBACK;');
self.fInTrans := False;
End;
Function TSQLiteDatabase.TableExists(TableName: String): boolean;
Var
SQL: String;
ds: TSQLiteTable;
Begin
//returns true if table exists in the database
SQL := 'select [sql] from sqlite_master where [type] = ''table'' and lower(name) = ''' +
LowerCase(TableName) + ''' ';
ds := self.GetTable(SQL);
Try
Result := (ds.Count > 0);
Finally
ds.Free;
End;
End;
Procedure TSQLiteDatabase.SetTimeout(Value: integer);
Begin
SQLite3_Busy_Timeout(self.fDB, Value);
End;
Function TSQLiteDatabase.version: String;
Begin
Result := SQLite3_LibVersion;
End;
//------------------------------------------------------------------------------
// TSQLiteTable
//------------------------------------------------------------------------------
Constructor TSQLiteTable.Create(DB: TSQLiteDatabase; Const SQL: String);
Var
Stmt: TSQLiteStmt;
NextSQLStatement: PAnsiChar;
iStepResult: integer;
ptr: pointer;
iNumBytes: integer;
thisBlobValue: TMemoryStream;
thisStringValue: pstring;
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -