From dc2616a471905229cebc6225c98264c737161825 Mon Sep 17 00:00:00 2001 From: tobigun Date: Mon, 13 Oct 2008 12:04:24 +0000 Subject: SQLiteTable3 update to current trunk (http://www.itwriting.com/repos/sqlitewrapper/trunk) git-svn-id: svn://svn.code.sf.net/p/ultrastardx/svn/trunk@1445 b956fd51-792f-4845-bead-9b4dfca2ff2c --- src/lib/SQLite/SQLite3.patch | 252 ++++++++++++++++++++ src/lib/SQLite/SQLiteTable3.pas | 86 +++++-- src/lib/SQLite/SQLiteTable3.patch | 472 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 786 insertions(+), 24 deletions(-) create mode 100644 src/lib/SQLite/SQLite3.patch create mode 100644 src/lib/SQLite/SQLiteTable3.patch (limited to 'src/lib/SQLite') diff --git a/src/lib/SQLite/SQLite3.patch b/src/lib/SQLite/SQLite3.patch new file mode 100644 index 00000000..6fb38db2 --- /dev/null +++ b/src/lib/SQLite/SQLite3.patch @@ -0,0 +1,252 @@ +--- D:/daten/SQLite3.pas Mon Oct 13 12:38:56 2008 ++++ D:/daten/Projekte/ultrastardx/linuxtrunk/src/lib/SQLite/SQLite3.pas Mon Oct 13 13:31:18 2008 +@@ -8,49 +8,66 @@ + which was based on SQLite.pas by Ben Hochstrasser (bhoc@surfeu.ch) + } + ++{$IFDEF FPC} ++ {$MODE DELPHI} ++ {$H+} (* use AnsiString *) ++ {$PACKENUM 4} (* use 4-byte enums *) ++ {$PACKRECORDS C} (* C/C++-compatible record packing *) ++{$ELSE} ++ {$MINENUMSIZE 4} (* use 4-byte enums *) ++{$ENDIF} ++ + interface + + const +- ++{$IF Defined(MSWINDOWS)} + SQLiteDLL = 'sqlite3.dll'; ++{$ELSEIF Defined(DARWIN)} ++ SQLiteDLL = 'libsqlite3.dylib'; ++ {$linklib libsqlite3} ++{$ELSEIF Defined(UNIX)} ++ SQLiteDLL = 'sqlite3.so'; ++{$IFEND} + + // Return values for sqlite3_exec() and sqlite3_step() + +- SQLITE_OK = 0; // Successful result +- SQLITE_ERROR = 1; // SQL error or missing database +- SQLITE_INTERNAL = 2; // An internal logic error in SQLite +- SQLITE_PERM = 3; // Access permission denied +- SQLITE_ABORT = 4; // Callback routine requested an abort +- SQLITE_BUSY = 5; // The database file is locked +- SQLITE_LOCKED = 6; // A table in the database is locked +- SQLITE_NOMEM = 7; // A malloc() failed +- SQLITE_READONLY = 8; // Attempt to write a readonly database +- SQLITE_INTERRUPT = 9; // Operation terminated by sqlite3_interrupt() +- SQLITE_IOERR = 10; // Some kind of disk I/O error occurred +- SQLITE_CORRUPT = 11; // The database disk image is malformed +- SQLITE_NOTFOUND = 12; // (Internal Only) Table or record not found +- SQLITE_FULL = 13; // Insertion failed because database is full +- SQLITE_CANTOPEN = 14; // Unable to open the database file +- SQLITE_PROTOCOL = 15; // Database lock protocol error +- SQLITE_EMPTY = 16; // Database is empty +- SQLITE_SCHEMA = 17; // The database schema changed +- SQLITE_TOOBIG = 18; // Too much data for one row of a table +- SQLITE_CONSTRAINT = 19; // Abort due to contraint violation +- SQLITE_MISMATCH = 20; // Data type mismatch +- SQLITE_MISUSE = 21; // Library used incorrectly +- SQLITE_NOLFS = 22; // Uses OS features not supported on host +- SQLITE_AUTH = 23; // Authorization denied +- SQLITE_FORMAT = 24; // Auxiliary database format error +- SQLITE_RANGE = 25; // 2nd parameter to sqlite3_bind out of range +- SQLITE_NOTADB = 26; // File opened that is not a database file +- SQLITE_ROW = 100; // sqlite3_step() has another row ready +- SQLITE_DONE = 101; // sqlite3_step() has finished executing ++const ++ SQLITE_OK = 0; // Successful result ++ (* beginning-of-error-codes *) ++ SQLITE_ERROR = 1; // SQL error or missing database ++ SQLITE_INTERNAL = 2; // An internal logic error in SQLite ++ SQLITE_PERM = 3; // Access permission denied ++ SQLITE_ABORT = 4; // Callback routine requested an abort ++ SQLITE_BUSY = 5; // The database file is locked ++ SQLITE_LOCKED = 6; // A table in the database is locked ++ SQLITE_NOMEM = 7; // A malloc() failed ++ SQLITE_READONLY = 8; // Attempt to write a readonly database ++ SQLITE_INTERRUPT = 9; // Operation terminated by sqlite3_interrupt() ++ SQLITE_IOERR = 10; // Some kind of disk I/O error occurred ++ SQLITE_CORRUPT = 11; // The database disk image is malformed ++ SQLITE_NOTFOUND = 12; // (Internal Only) Table or record not found ++ SQLITE_FULL = 13; // Insertion failed because database is full ++ SQLITE_CANTOPEN = 14; // Unable to open the database file ++ SQLITE_PROTOCOL = 15; // Database lock protocol error ++ SQLITE_EMPTY = 16; // Database is empty ++ SQLITE_SCHEMA = 17; // The database schema changed ++ SQLITE_TOOBIG = 18; // Too much data for one row of a table ++ SQLITE_CONSTRAINT = 19; // Abort due to contraint violation ++ SQLITE_MISMATCH = 20; // Data type mismatch ++ SQLITE_MISUSE = 21; // Library used incorrectly ++ SQLITE_NOLFS = 22; // Uses OS features not supported on host ++ SQLITE_AUTH = 23; // Authorization denied ++ SQLITE_FORMAT = 24; // Auxiliary database format error ++ SQLITE_RANGE = 25; // 2nd parameter to sqlite3_bind out of range ++ SQLITE_NOTADB = 26; // File opened that is not a database file ++ SQLITE_ROW = 100; // sqlite3_step() has another row ready ++ SQLITE_DONE = 101; // sqlite3_step() has finished executing + + SQLITE_INTEGER = 1; +- SQLITE_FLOAT = 2; +- SQLITE_TEXT = 3; +- SQLITE_BLOB = 4; +- SQLITE_NULL = 5; ++ SQLITE_FLOAT = 2; ++ SQLITE_TEXT = 3; ++ SQLITE_BLOB = 4; ++ SQLITE_NULL = 5; + + SQLITE_UTF8 = 1; + SQLITE_UTF16 = 2; +@@ -58,21 +75,31 @@ + SQLITE_UTF16LE = 4; + SQLITE_ANY = 5; + +- SQLITE_TRANSIENT = pointer(-1); +- SQLITE_STATIC = pointer(0); ++ SQLITE_STATIC {: TSQLite3Destructor} = Pointer(0); ++ SQLITE_TRANSIENT {: TSQLite3Destructor} = Pointer(-1); + + type + TSQLiteDB = Pointer; + TSQLiteResult = ^PChar; + TSQLiteStmt = Pointer; + ++type ++ PPCharArray = ^TPCharArray; ++ TPCharArray = array[0 .. (MaxInt div SizeOf(PChar))-1] of PChar; ++ ++type ++ TSQLiteExecCallback = function(UserData: Pointer; NumCols: integer; ColValues: ++ PPCharArray; ColNames: PPCharArray): integer; cdecl; ++ TSQLiteBusyHandlerCallback = function(UserData: Pointer; P2: integer): integer; cdecl; ++ + //function prototype for define own collate +- TCollateXCompare = function(Userdta: pointer; Buf1Len: integer; Buf1: pointer; ++ TCollateXCompare = function(UserData: pointer; Buf1Len: integer; Buf1: pointer; + Buf2Len: integer; Buf2: pointer): integer; cdecl; ++ + +-function SQLite3_Open(dbname: PChar; var db: TSqliteDB): integer; cdecl; external SQLiteDLL name 'sqlite3_open'; ++function SQLite3_Open(filename: PChar; var db: TSQLiteDB): integer; cdecl; external SQLiteDLL name 'sqlite3_open'; + function SQLite3_Close(db: TSQLiteDB): integer; cdecl; external SQLiteDLL name 'sqlite3_close'; +-function SQLite3_Exec(db: TSQLiteDB; SQLStatement: PChar; CallbackPtr: Pointer; Sender: TObject; var ErrMsg: PChar): integer; cdecl; external SQLiteDLL name 'sqlite3_exec'; ++function SQLite3_Exec(db: TSQLiteDB; SQLStatement: PChar; CallbackPtr: TSQLiteExecCallback; UserData: Pointer; var ErrMsg: PChar): integer; cdecl; external SQLiteDLL name 'sqlite3_exec'; + function SQLite3_Version(): PChar; cdecl; external SQLiteDLL name 'sqlite3_libversion'; + function SQLite3_ErrMsg(db: TSQLiteDB): PChar; cdecl; external SQLiteDLL name 'sqlite3_errmsg'; + function SQLite3_ErrCode(db: TSQLiteDB): integer; cdecl; external SQLiteDLL name 'sqlite3_errcode'; +@@ -82,76 +109,78 @@ + function SQLite3_Complete(P: PChar): boolean; cdecl; external SQLiteDLL name 'sqlite3_complete'; + function SQLite3_LastInsertRowID(db: TSQLiteDB): int64; cdecl; external SQLiteDLL name 'sqlite3_last_insert_rowid'; + procedure SQLite3_Interrupt(db: TSQLiteDB); cdecl; external SQLiteDLL name 'sqlite3_interrupt'; +-procedure SQLite3_BusyHandler(db: TSQLiteDB; CallbackPtr: Pointer; Sender: TObject); cdecl; external SQLiteDLL name 'sqlite3_busy_handler'; ++procedure SQLite3_BusyHandler(db: TSQLiteDB; CallbackPtr: TSQLiteBusyHandlerCallback; UserData: Pointer); cdecl; external SQLiteDLL name 'sqlite3_busy_handler'; + procedure SQLite3_BusyTimeout(db: TSQLiteDB; TimeOut: integer); cdecl; external SQLiteDLL name 'sqlite3_busy_timeout'; + function SQLite3_Changes(db: TSQLiteDB): integer; cdecl; external SQLiteDLL name 'sqlite3_changes'; + function SQLite3_TotalChanges(db: TSQLiteDB): integer; cdecl; external SQLiteDLL name 'sqlite3_total_changes'; + function SQLite3_Prepare(db: TSQLiteDB; SQLStatement: PChar; nBytes: integer; var hStmt: TSqliteStmt; var pzTail: PChar): integer; cdecl; external SQLiteDLL name 'sqlite3_prepare'; + function SQLite3_Prepare_v2(db: TSQLiteDB; SQLStatement: PChar; nBytes: integer; var hStmt: TSqliteStmt; var pzTail: PChar): integer; cdecl; external SQLiteDLL name 'sqlite3_prepare_v2'; + function SQLite3_ColumnCount(hStmt: TSqliteStmt): integer; cdecl; external SQLiteDLL name 'sqlite3_column_count'; +-function Sqlite3_ColumnName(hStmt: TSqliteStmt; ColNum: integer): pchar; cdecl; external SQLiteDLL name 'sqlite3_column_name'; +-function Sqlite3_ColumnDeclType(hStmt: TSqliteStmt; ColNum: integer): pchar; cdecl; external SQLiteDLL name 'sqlite3_column_decltype'; +-function Sqlite3_Step(hStmt: TSqliteStmt): integer; cdecl; external SQLiteDLL name 'sqlite3_step'; ++function SQLite3_ColumnName(hStmt: TSqliteStmt; ColNum: integer): pchar; cdecl; external SQLiteDLL name 'sqlite3_column_name'; ++function SQLite3_ColumnDeclType(hStmt: TSqliteStmt; ColNum: integer): pchar; cdecl; external SQLiteDLL name 'sqlite3_column_decltype'; ++function SQLite3_Step(hStmt: TSqliteStmt): integer; cdecl; external SQLiteDLL name 'sqlite3_step'; + function SQLite3_DataCount(hStmt: TSqliteStmt): integer; cdecl; external SQLiteDLL name 'sqlite3_data_count'; + +-function Sqlite3_ColumnBlob(hStmt: TSqliteStmt; ColNum: integer): pointer; cdecl; external SQLiteDLL name 'sqlite3_column_blob'; +-function Sqlite3_ColumnBytes(hStmt: TSqliteStmt; ColNum: integer): integer; cdecl; external SQLiteDLL name 'sqlite3_column_bytes'; +-function Sqlite3_ColumnDouble(hStmt: TSqliteStmt; ColNum: integer): double; cdecl; external SQLiteDLL name 'sqlite3_column_double'; +-function Sqlite3_ColumnInt(hStmt: TSqliteStmt; ColNum: integer): integer; cdecl; external SQLiteDLL name 'sqlite3_column_int'; +-function Sqlite3_ColumnText(hStmt: TSqliteStmt; ColNum: integer): pchar; cdecl; external SQLiteDLL name 'sqlite3_column_text'; +-function Sqlite3_ColumnType(hStmt: TSqliteStmt; ColNum: integer): integer; cdecl; external SQLiteDLL name 'sqlite3_column_type'; +-function Sqlite3_ColumnInt64(hStmt: TSqliteStmt; ColNum: integer): Int64; cdecl; external SQLiteDLL name 'sqlite3_column_int64'; ++function SQLite3_ColumnBlob(hStmt: TSqliteStmt; ColNum: integer): pointer; cdecl; external SQLiteDLL name 'sqlite3_column_blob'; ++function SQLite3_ColumnBytes(hStmt: TSqliteStmt; ColNum: integer): integer; cdecl; external SQLiteDLL name 'sqlite3_column_bytes'; ++function SQLite3_ColumnDouble(hStmt: TSqliteStmt; ColNum: integer): double; cdecl; external SQLiteDLL name 'sqlite3_column_double'; ++function SQLite3_ColumnInt(hStmt: TSqliteStmt; ColNum: integer): integer; cdecl; external SQLiteDLL name 'sqlite3_column_int'; ++function SQLite3_ColumnText(hStmt: TSqliteStmt; ColNum: integer): pchar; cdecl; external SQLiteDLL name 'sqlite3_column_text'; ++function SQLite3_ColumnType(hStmt: TSqliteStmt; ColNum: integer): integer; cdecl; external SQLiteDLL name 'sqlite3_column_type'; ++function SQLite3_ColumnInt64(hStmt: TSqliteStmt; ColNum: integer): Int64; cdecl; external SQLiteDLL name 'sqlite3_column_int64'; + function SQLite3_Finalize(hStmt: TSqliteStmt): integer; cdecl; external SQLiteDLL name 'sqlite3_finalize'; + function SQLite3_Reset(hStmt: TSqliteStmt): integer; cdecl; external SQLiteDLL name 'sqlite3_reset'; + +-// ++// + // In the SQL strings input to sqlite3_prepare() and sqlite3_prepare16(), + // one or more literals can be replace by a wildcard "?" or ":N:" where + // N is an integer. These value of these wildcard literals can be set + // using the routines listed below. +-// ++// + // In every case, the first parameter is a pointer to the sqlite3_stmt + // structure returned from sqlite3_prepare(). The second parameter is the + // index of the wildcard. The first "?" has an index of 1. ":N:" wildcards + // use the index N. +-// +- // The fifth parameter to sqlite3_bind_blob(), sqlite3_bind_text(), and +- //sqlite3_bind_text16() is a destructor used to dispose of the BLOB or ++// ++// The fifth parameter to sqlite3_bind_blob(), sqlite3_bind_text(), and ++//sqlite3_bind_text16() is a destructor used to dispose of the BLOB or + //text after SQLite has finished with it. If the fifth argument is the + // special value SQLITE_STATIC, then the library assumes that the information + // is in static, unmanaged space and does not need to be freed. If the + // fifth argument has the value SQLITE_TRANSIENT, then SQLite makes its + // own private copy of the data. +-// ++// + // The sqlite3_bind_* routine must be called before sqlite3_step() after + // an sqlite3_prepare() or sqlite3_reset(). Unbound wildcards are interpreted + // as NULL. +-// ++// + +-function SQLite3_Bind_Blob(hStmt: TSqliteStmt; ParamNum: integer; +- ptrData: pointer; numBytes: integer; ptrDestructor: pointer): integer; +- cdecl; external SQLiteDLL name 'sqlite3_bind_blob'; +-function SQLite3_Bind_Double(hStmt: TSqliteStmt; ParamNum: integer; Data: Double): integer; ++type ++ TSQLite3Destructor = procedure(Ptr: Pointer); cdecl; ++ ++function sqlite3_bind_blob(hStmt: TSqliteStmt; ParamNum: integer; ++ ptrData: pointer; numBytes: integer; ptrDestructor: TSQLite3Destructor): integer; ++cdecl; external SQLiteDLL name 'sqlite3_bind_blob'; ++function sqlite3_bind_text(hStmt: TSqliteStmt; ParamNum: integer; ++ Text: PChar; numBytes: integer; ptrDestructor: TSQLite3Destructor): integer; ++cdecl; external SQLiteDLL name 'sqlite3_bind_text'; ++function sqlite3_bind_double(hStmt: TSqliteStmt; ParamNum: integer; Data: Double): integer; + cdecl; external SQLiteDLL name 'sqlite3_bind_double'; +-function SQLite3_BindInt(hStmt: TSqLiteStmt; ParamNum: integer; intData: integer): integer; +- cdecl; external 'sqlite3.dll' name 'sqlite3_bind_int'; +-function SQLite3_Bind_int64(hStmt: TSqliteStmt; ParamNum: integer; Data: int64): integer; ++function sqlite3_bind_int(hStmt: TSqLiteStmt; ParamNum: integer; Data: integer): integer; ++ cdecl; external SQLiteDLL name 'sqlite3_bind_int'; ++function sqlite3_bind_int64(hStmt: TSqliteStmt; ParamNum: integer; Data: int64): integer; + cdecl; external SQLiteDLL name 'sqlite3_bind_int64'; +-function SQLite3_Bind_null(hStmt: TSqliteStmt; ParamNum: integer): integer; ++function sqlite3_bind_null(hStmt: TSqliteStmt; ParamNum: integer): integer; + cdecl; external SQLiteDLL name 'sqlite3_bind_null'; +-function SQLite3_Bind_text(hStmt: TSqliteStmt; ParamNum: integer; +- Data: PChar; numBytes: integer; ptrDestructor: pointer): integer; +- cdecl; external SQLiteDLL name 'sqlite3_bind_text'; + +-function SQLite3_Bind_Parameter_Index(hStmt: TSqliteStmt; zName: PChar): integer; ++function sqlite3_bind_parameter_index(hStmt: TSqliteStmt; zName: PChar): integer; + cdecl; external SQLiteDLL name 'sqlite3_bind_parameter_index'; + +-function sqlite3_enable_shared_cache(value: integer): integer; cdecl; external SQLiteDLL name 'sqlite3_enable_shared_cache'; ++function sqlite3_enable_shared_cache(Value: integer): integer; cdecl; external SQLiteDLL name 'sqlite3_enable_shared_cache'; + + //user collate definiton +-function sqlite3_create_collation(db: TSQLiteDB; Name: Pchar; eTextRep: integer; ++function SQLite3_create_collation(db: TSQLiteDB; Name: Pchar; eTextRep: integer; + UserData: pointer; xCompare: TCollateXCompare): integer; cdecl; external SQLiteDLL name 'sqlite3_create_collation'; +- + + function SQLiteFieldType(SQLiteFieldTypeCode: Integer): AnsiString; + function SQLiteErrorStr(SQLiteErrorCode: Integer): AnsiString; diff --git a/src/lib/SQLite/SQLiteTable3.pas b/src/lib/SQLite/SQLiteTable3.pas index 8f33b115..ab465ef8 100644 --- a/src/lib/SQLite/SQLiteTable3.pas +++ b/src/lib/SQLite/SQLiteTable3.pas @@ -54,6 +54,7 @@ unit SQLiteTable3; Adapted by Tim Anderson (tim@itwriting.com) Originally created by Pablo Pissanetzky (pablo@myhtpc.net) Modified and enhanced by Lukas Gebauer + Modified and enhanced by Tobias Gunkel } interface @@ -90,12 +91,13 @@ type valuedata: string; end; + THookQuery = procedure(Sender: TObject; SQL: String) of object; + TSQLiteQuery = record SQL: String; Statement: TSQLiteStmt; end; - TSQLiteTable = class; TSQLiteUniTable = class; @@ -105,12 +107,14 @@ type fInTrans: boolean; fSync: boolean; fParams: TList; + FOnQuery: THookQuery; procedure RaiseError(s: string; SQL: string); procedure SetParams(Stmt: TSQLiteStmt); procedure BindData(Stmt: TSQLiteStmt; const Bindings: array of const); function GetRowsChanged: integer; protected procedure SetSynchronised(Value: boolean); + procedure DoQuery(value: string); public constructor Create(const FileName: string); destructor Destroy; override; @@ -129,6 +133,7 @@ type function GetTableValue(const SQL: string; const Bindings: array of const): int64; overload; function GetTableString(const SQL: string): string; overload; function GetTableString(const SQL: string; const Bindings: array of const): string; overload; + procedure GetTableStrings(const SQL: string; const Value: TStrings); procedure UpdateBlob(const SQL: string; BlobData: TStream); procedure BeginTransaction; procedure Commit; @@ -152,7 +157,7 @@ type //database rows that were changed (or inserted or deleted) by the most recent SQL statement property RowsChanged : integer read getRowsChanged; property Synchronised: boolean read FSync write SetSynchronised; - + property OnQuery: THookQuery read FOnQuery write FOnQuery; end; TSQLiteTable = class @@ -194,7 +199,7 @@ type property Row: cardinal read fRow; function MoveFirst: boolean; function MoveLast: boolean; - function MoveTo(position:Integer): boolean; + function MoveTo(position: cardinal): 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 @@ -493,7 +498,7 @@ begin RaiseError('Error executing SQL', SQL); if (Stmt = nil) then RaiseError('Could not prepare SQL statement', SQL); - + DoQuery(SQL); SetParams(Stmt); BindData(Stmt, Bindings); @@ -545,6 +550,7 @@ begin if (Result.Statement = nil) then RaiseError('Could not prepare SQL statement', SQL); + DoQuery(SQL); end; {$WARNINGS ON} @@ -604,6 +610,7 @@ begin if (Stmt = nil) then RaiseError('Could not prepare SQL statement', SQL); + DoQuery(SQL); //now bind the blob data iSize := BlobData.size; @@ -701,6 +708,23 @@ begin end; end; +procedure TSQLiteDatabase.GetTableStrings(const SQL: string; + const Value: TStrings); +var + Table: TSQLiteUniTable; +begin + Value.Clear; + Table := self.GetUniTable(SQL); + try + while not table.EOF do + begin + Value.Add(Table.FieldAsString(0)); + table.Next; + end; + finally + Table.Free; + end; +end; procedure TSQLiteDatabase.BeginTransaction; begin @@ -853,6 +877,12 @@ begin Result := SQLite3_Changes(self.fDB); end; +procedure TSQLiteDatabase.DoQuery(value: string); +begin + if assigned(OnQuery) then + OnQuery(Self, Value); +end; + //------------------------------------------------------------------------------ // TSQLiteTable //------------------------------------------------------------------------------ @@ -889,7 +919,7 @@ begin DB.RaiseError('Error executing SQL', SQL); if (Stmt = nil) then DB.RaiseError('Could not prepare SQL statement', SQL); - + DB.DoQuery(SQL); DB.SetParams(Stmt); DB.BindData(Stmt, Bindings); @@ -1152,15 +1182,19 @@ begin Result := ''; MemStream := self.FieldAsBlob(I); if MemStream <> nil then - if MemStream.Size > 0 then - begin - MemStream.position := 0; - Buffer := stralloc(MemStream.Size + 1); - MemStream.readbuffer(Buffer[0], MemStream.Size); - (Buffer + MemStream.Size)^ := chr(0); - SetString(Result, Buffer, MemStream.size); - strdispose(Buffer); - end; + try + if MemStream.Size > 0 then + begin + MemStream.position := 0; + Buffer := stralloc(MemStream.Size + 1); + MemStream.readbuffer(Buffer[0], MemStream.Size); + (Buffer + MemStream.Size)^ := chr(0); + SetString(Result, Buffer, MemStream.size); + strdispose(Buffer); + end; + finally + MemStream.free; + end; end; @@ -1259,7 +1293,7 @@ begin end; {$WARNINGS OFF} -function TSQLiteTable.MoveTo(position: Integer): boolean; +function TSQLiteTable.MoveTo(position: cardinal): boolean; begin Result := False; if (self.fRowCount > 0) and (self.fRowCount > position) then @@ -1296,7 +1330,7 @@ begin DB.RaiseError('Error executing SQL', SQL); if (fStmt = nil) then DB.RaiseError('Could not prepare SQL statement', SQL); - + DB.DoQuery(SQL); DB.SetParams(fStmt); DB.BindData(fStmt, Bindings); @@ -1349,14 +1383,18 @@ begin Result := ''; MemStream := self.FieldAsBlob(I); if MemStream <> nil then - if MemStream.Size > 0 then - begin - MemStream.position := 0; - Buffer := stralloc(MemStream.Size + 1); - MemStream.readbuffer(Buffer[0], MemStream.Size); - (Buffer + MemStream.Size)^ := chr(0); - SetString(Result, Buffer, MemStream.size); - strdispose(Buffer); + try + if MemStream.Size > 0 then + begin + MemStream.position := 0; + Buffer := stralloc(MemStream.Size + 1); + MemStream.readbuffer(Buffer[0], MemStream.Size); + (Buffer + MemStream.Size)^ := chr(0); + SetString(Result, Buffer, MemStream.size); + strdispose(Buffer); + end; + finally + MemStream.Free; end; end; diff --git a/src/lib/SQLite/SQLiteTable3.patch b/src/lib/SQLite/SQLiteTable3.patch new file mode 100644 index 00000000..bee8f498 --- /dev/null +++ b/src/lib/SQLite/SQLiteTable3.patch @@ -0,0 +1,472 @@ +--- D:/daten/SQLiteTable3.pas Mon Oct 13 12:38:52 2008 ++++ D:/daten/Projekte/ultrastardx/linuxtrunk/src/lib/SQLite/SQLiteTable3.pas Mon Oct 13 12:56:30 2008 +@@ -54,12 +54,20 @@ + Adapted by Tim Anderson (tim@itwriting.com) + Originally created by Pablo Pissanetzky (pablo@myhtpc.net) + Modified and enhanced by Lukas Gebauer ++ Modified and enhanced by Tobias Gunkel + } + + interface + ++{$IFDEF FPC} ++ {$MODE Delphi}{$H+} ++{$ENDIF} ++ + uses +- Windows, SQLite3, Classes, SysUtils; ++ {$IFDEF WIN32} ++ Windows, ++ {$ENDIF} ++ SQLite3, Classes, SysUtils; + + const + +@@ -102,23 +110,29 @@ + FOnQuery: THookQuery; + procedure RaiseError(s: string; SQL: string); + procedure SetParams(Stmt: TSQLiteStmt); +- function getRowsChanged: integer; ++ procedure BindData(Stmt: TSQLiteStmt; const Bindings: array of const); ++ function GetRowsChanged: integer; + protected + procedure SetSynchronised(Value: boolean); + procedure DoQuery(value: string); + public + constructor Create(const FileName: string); + destructor Destroy; override; +- function GetTable(const SQL: string): TSQLiteTable; ++ function GetTable(const SQL: string): TSQLiteTable; overload; ++ function GetTable(const SQL: string; const Bindings: array of const): TSQLiteTable; overload; + procedure ExecSQL(const SQL: string); overload; ++ procedure ExecSQL(const SQL: string; const Bindings: array of const); overload; + procedure ExecSQL(Query: TSQLiteQuery); overload; + function PrepareSQL(const SQL: string): TSQLiteQuery; + procedure BindSQL(Query: TSQLiteQuery; const Index: Integer; const Value: Integer); overload; + procedure BindSQL(Query: TSQLiteQuery; const Index: Integer; const Value: String); overload; + procedure ReleaseSQL(Query: TSQLiteQuery); +- function GetUniTable(const SQL: string): TSQLiteUniTable; +- function GetTableValue(const SQL: string): int64; +- function GetTableString(const SQL: string): string; ++ function GetUniTable(const SQL: string): TSQLiteUniTable; overload; ++ function GetUniTable(const SQL: string; const Bindings: array of const): TSQLiteUniTable; overload; ++ function GetTableValue(const SQL: string): int64; overload; ++ function GetTableValue(const SQL: string; const Bindings: array of const): int64; overload; ++ function GetTableString(const SQL: string): string; overload; ++ function GetTableString(const SQL: string; const Bindings: array of const): string; overload; + procedure GetTableStrings(const SQL: string; const Value: TStrings); + procedure UpdateBlob(const SQL: string; BlobData: TStream); + procedure BeginTransaction; +@@ -128,7 +142,7 @@ + function GetLastInsertRowID: int64; + function GetLastChangedRows: int64; + procedure SetTimeout(Value: integer); +- function version: string; ++ function Version: string; + procedure AddCustomCollate(name: string; xCompare: TCollateXCompare); + //adds collate named SYSTEM for correct data sorting by user's locale + Procedure AddSystemCollate; +@@ -139,7 +153,7 @@ + procedure AddParamNull(name: string); + property DB: TSQLiteDB read fDB; + published +- property isTransactionOpen: boolean read fInTrans; ++ property IsTransactionOpen: boolean read fInTrans; + //database rows that were changed (or inserted or deleted) by the most recent SQL statement + property RowsChanged : integer read getRowsChanged; + property Synchronised: boolean read FSync write SetSynchronised; +@@ -163,7 +177,8 @@ + function GetCount: integer; + function GetCountResult: integer; + public +- constructor Create(DB: TSQLiteDatabase; const SQL: string); ++ constructor Create(DB: TSQLiteDatabase; const SQL: string); overload; ++ constructor Create(DB: TSQLiteDatabase; const SQL: string; const Bindings: array of const); overload; + destructor Destroy; override; + function FieldAsInteger(I: cardinal): int64; + function FieldAsBlob(I: cardinal): TMemoryStream; +@@ -196,7 +211,6 @@ + private + fColCount: cardinal; + fCols: TStringList; +- fColTypes: TList; + fRow: cardinal; + fEOF: boolean; + fStmt: TSQLiteStmt; +@@ -207,10 +221,12 @@ + function GetFieldByName(FieldName: string): string; + function GetFieldIndex(FieldName: string): integer; + public +- constructor Create(DB: TSQLiteDatabase; const SQL: string); ++ constructor Create(DB: TSQLiteDatabase; const SQL: string); overload; ++ constructor Create(DB: TSQLiteDatabase; const SQL: string; const Bindings: array of const); overload; + destructor Destroy; override; + function FieldAsInteger(I: cardinal): int64; + function FieldAsBlob(I: cardinal): TMemoryStream; ++ function FieldAsBlobPtr(I: cardinal; out iNumBytes: integer): Pointer; + function FieldAsBlobText(I: cardinal): string; + function FieldIsNull(I: cardinal): boolean; + function FieldAsString(I: cardinal): string; +@@ -227,8 +243,10 @@ + + procedure DisposePointer(ptr: pointer); cdecl; + ++{$IFDEF WIN32} + function SystemCollate(Userdta: pointer; Buf1Len: integer; Buf1: pointer; + Buf2Len: integer; Buf2: pointer): integer; cdecl; ++{$ENDIF} + + implementation + +@@ -238,12 +256,14 @@ + freemem(ptr); + end; + ++{$IFDEF WIN32} + function SystemCollate(Userdta: pointer; Buf1Len: integer; Buf1: pointer; + Buf2Len: integer; Buf2: pointer): integer; cdecl; + begin + Result := CompareStringW(LOCALE_USER_DEFAULT, 0, PWideChar(Buf1), Buf1Len, + PWideChar(Buf2), Buf2Len) - 2; + end; ++{$ENDIF} + + //------------------------------------------------------------------------------ + // TSQLiteDatabase +@@ -347,7 +367,126 @@ + end; + end; + ++procedure TSQLiteDatabase.BindData(Stmt: TSQLiteStmt; const Bindings: array of const); ++var ++ BlobMemStream: TCustomMemoryStream; ++ BlobStdStream: TStream; ++ DataPtr: Pointer; ++ DataSize: integer; ++ AnsiStr: AnsiString; ++ AnsiStrPtr: PAnsiString; ++ I: integer; ++begin ++ for I := 0 to High(Bindings) do ++ begin ++ case Bindings[I].VType of ++ vtString, ++ vtAnsiString, vtPChar, ++ vtWideString, vtPWideChar, ++ vtChar, vtWideChar: ++ begin ++ case Bindings[I].VType of ++ vtString: begin // ShortString ++ AnsiStr := Bindings[I].VString^; ++ DataPtr := PChar(AnsiStr); ++ DataSize := Length(AnsiStr)+1; ++ end; ++ vtPChar: begin ++ DataPtr := Bindings[I].VPChar; ++ DataSize := -1; ++ end; ++ vtAnsiString: begin ++ AnsiStrPtr := PString(@Bindings[I].VAnsiString); ++ DataPtr := PChar(AnsiStrPtr^); ++ DataSize := Length(AnsiStrPtr^)+1; ++ end; ++ vtPWideChar: begin ++ DataPtr := PChar(UTF8Encode(WideString(Bindings[I].VPWideChar))); ++ DataSize := -1; ++ end; ++ vtWideString: begin ++ DataPtr := PChar(UTF8Encode(PWideString(@Bindings[I].VWideString)^)); ++ DataSize := -1; ++ end; ++ vtChar: begin ++ DataPtr := PChar(String(Bindings[I].VChar)); ++ DataSize := 2; ++ end; ++ vtWideChar: begin ++ DataPtr := PChar(UTF8Encode(WideString(Bindings[I].VWideChar))); ++ DataSize := -1; ++ end; ++ else ++ raise ESqliteException.Create('Unknown string-type'); ++ end; ++ if (sqlite3_bind_text(Stmt, I+1, DataPtr, DataSize, SQLITE_STATIC) <> SQLITE_OK) then ++ RaiseError('Could not bind text', 'BindData'); ++ end; ++ vtInteger: ++ if (sqlite3_bind_int(Stmt, I+1, Bindings[I].VInteger) <> SQLITE_OK) then ++ RaiseError('Could not bind integer', 'BindData'); ++ vtInt64: ++ if (sqlite3_bind_int64(Stmt, I+1, Bindings[I].VInt64^) <> SQLITE_OK) then ++ RaiseError('Could not bind int64', 'BindData'); ++ vtExtended: ++ if (sqlite3_bind_double(Stmt, I+1, Bindings[I].VExtended^) <> SQLITE_OK) then ++ RaiseError('Could not bind extended', 'BindData'); ++ vtBoolean: ++ if (sqlite3_bind_int(Stmt, I+1, Integer(Bindings[I].VBoolean)) <> SQLITE_OK) then ++ RaiseError('Could not bind boolean', 'BindData'); ++ vtPointer: ++ begin ++ if (Bindings[I].VPointer = nil) then ++ begin ++ if (sqlite3_bind_null(Stmt, I+1) <> SQLITE_OK) then ++ RaiseError('Could not bind null', 'BindData'); ++ end ++ else ++ raise ESqliteException.Create('Unhandled pointer (<> nil)'); ++ end; ++ vtObject: ++ begin ++ if (Bindings[I].VObject is TCustomMemoryStream) then ++ begin ++ BlobMemStream := TCustomMemoryStream(Bindings[I].VObject); ++ if (sqlite3_bind_blob(Stmt, I+1, @PChar(BlobMemStream.Memory)[BlobMemStream.Position], ++ BlobMemStream.Size-BlobMemStream.Position, SQLITE_STATIC) <> SQLITE_OK) then ++ begin ++ RaiseError('Could not bind BLOB', 'BindData'); ++ end; ++ end ++ else if (Bindings[I].VObject is TStream) then ++ begin ++ BlobStdStream := TStream(Bindings[I].VObject); ++ DataSize := BlobStdStream.Size; ++ ++ GetMem(DataPtr, DataSize); ++ if (DataPtr = nil) then ++ raise ESqliteException.Create('Error getting memory to save blob'); ++ ++ BlobStdStream.Position := 0; ++ BlobStdStream.Read(DataPtr^, DataSize); ++ ++ if (sqlite3_bind_blob(stmt, I+1, DataPtr, DataSize, @DisposePointer) <> SQLITE_OK) then ++ RaiseError('Could not bind BLOB', 'BindData'); ++ end ++ else ++ raise ESqliteException.Create('Unhandled object-type in binding'); ++ end ++ else ++ begin ++ raise ESqliteException.Create('Unhandled binding'); ++ end; ++ end; ++ end; ++end; ++ + procedure TSQLiteDatabase.ExecSQL(const SQL: string); ++begin ++ ExecSQL(SQL, []); ++end; ++ ++procedure TSQLiteDatabase.ExecSQL(const SQL: string; const Bindings: array of const); + var + Stmt: TSQLiteStmt; + NextSQLStatement: Pchar; +@@ -361,6 +500,8 @@ + RaiseError('Could not prepare SQL statement', SQL); + DoQuery(SQL); + SetParams(Stmt); ++ BindData(Stmt, Bindings); ++ + iStepResult := Sqlite3_step(Stmt); + if (iStepResult <> SQLITE_DONE) then + begin +@@ -417,7 +558,7 @@ + procedure TSQLiteDatabase.BindSQL(Query: TSQLiteQuery; const Index: Integer; const Value: Integer); + begin + if Assigned(Query.Statement) then +- Sqlite3_BindInt(Query.Statement, Index, Value) ++ sqlite3_Bind_Int(Query.Statement, Index, Value) + else + RaiseError('Could not bind integer to prepared SQL statement', Query.SQL); + end; +@@ -514,17 +655,32 @@ + Result := TSQLiteTable.Create(Self, SQL); + end; + ++function TSQLiteDatabase.GetTable(const SQL: string; const Bindings: array of const): TSQLiteTable; ++begin ++ Result := TSQLiteTable.Create(Self, SQL, Bindings); ++end; ++ + function TSQLiteDatabase.GetUniTable(const SQL: string): TSQLiteUniTable; + begin + Result := TSQLiteUniTable.Create(Self, SQL); + end; + ++function TSQLiteDatabase.GetUniTable(const SQL: string; const Bindings: array of const): TSQLiteUniTable; ++begin ++ Result := TSQLiteUniTable.Create(Self, SQL, Bindings); ++end; ++ + function TSQLiteDatabase.GetTableValue(const SQL: string): int64; ++begin ++ Result := GetTableValue(SQL, []); ++end; ++ ++function TSQLiteDatabase.GetTableValue(const SQL: string; const Bindings: array of const): int64; + var + Table: TSQLiteUniTable; + begin + Result := 0; +- Table := self.GetUniTable(SQL); ++ Table := self.GetUniTable(SQL, Bindings); + try + if not Table.EOF then + Result := Table.FieldAsInteger(0); +@@ -534,11 +690,16 @@ + end; + + function TSQLiteDatabase.GetTableString(const SQL: string): String; ++begin ++ Result := GetTableString(SQL, []); ++end; ++ ++function TSQLiteDatabase.GetTableString(const SQL: string; const Bindings: array of const): String; + var + Table: TSQLiteUniTable; + begin + Result := ''; +- Table := self.GetUniTable(SQL); ++ Table := self.GetUniTable(SQL, Bindings); + try + if not Table.EOF then + Result := Table.FieldAsString(0); +@@ -609,7 +770,7 @@ + SQLite3_BusyTimeout(self.fDB, Value); + end; + +-function TSQLiteDatabase.version: string; ++function TSQLiteDatabase.Version: string; + begin + Result := SQLite3_Version; + end; +@@ -622,7 +783,9 @@ + + procedure TSQLiteDatabase.AddSystemCollate; + begin ++ {$IFDEF WIN32} + sqlite3_create_collation(fdb, 'SYSTEM', SQLITE_UTF16LE, nil, @SystemCollate); ++ {$ENDIF} + end; + + procedure TSQLiteDatabase.ParamsClear; +@@ -709,7 +872,7 @@ + end; + + //database rows that were changed (or inserted or deleted) by the most recent SQL statement +-function TSQLiteDatabase.getRowsChanged: integer; ++function TSQLiteDatabase.GetRowsChanged: integer; + begin + Result := SQLite3_Changes(self.fDB); + end; +@@ -725,6 +888,11 @@ + //------------------------------------------------------------------------------ + + constructor TSQLiteTable.Create(DB: TSQLiteDatabase; const SQL: string); ++begin ++ Create(DB, SQL, []); ++end; ++ ++constructor TSQLiteTable.Create(DB: TSQLiteDatabase; const SQL: string; const Bindings: array of const); + var + Stmt: TSQLiteStmt; + NextSQLStatement: Pchar; +@@ -753,6 +921,8 @@ + DB.RaiseError('Could not prepare SQL statement', SQL); + DB.DoQuery(SQL); + DB.SetParams(Stmt); ++ DB.BindData(Stmt, Bindings); ++ + iStepResult := Sqlite3_step(Stmt); + while (iStepResult <> SQLITE_DONE) do + begin +@@ -1122,6 +1292,7 @@ + end; + end; + ++{$WARNINGS OFF} + function TSQLiteTable.MoveTo(position: cardinal): boolean; + begin + Result := False; +@@ -1131,13 +1302,18 @@ + Result := True; + end; + end; +- ++{$WARNINGS ON} + + + + { TSQLiteUniTable } + + constructor TSQLiteUniTable.Create(DB: TSQLiteDatabase; const SQL: string); ++begin ++ Create(DB, SQL, []); ++end; ++ ++constructor TSQLiteUniTable.Create(DB: TSQLiteDatabase; const SQL: string; const Bindings: array of const); + var + NextSQLStatement: Pchar; + thisColType: pInteger; +@@ -1156,36 +1332,14 @@ + DB.RaiseError('Could not prepare SQL statement', SQL); + DB.DoQuery(SQL); + DB.SetParams(fStmt); ++ DB.BindData(fStmt, Bindings); + + //get data types + fCols := TStringList.Create; +- fColTypes := TList.Create; + fColCount := SQLite3_ColumnCount(fstmt); + for i := 0 to Pred(fColCount) do + fCols.Add(AnsiUpperCase(Sqlite3_ColumnName(fstmt, i))); +- for i := 0 to Pred(fColCount) do +- begin +- new(thisColType); +- DeclaredColType := Sqlite3_ColumnDeclType(fstmt, i); +- if DeclaredColType = nil then +- thisColType^ := Sqlite3_ColumnType(fstmt, i) //use the actual column type instead +- //seems to be needed for last_insert_rowid +- else +- if (DeclaredColType = 'INTEGER') or (DeclaredColType = 'BOOLEAN') then +- thisColType^ := dtInt +- else +- if (DeclaredColType = 'NUMERIC') or +- (DeclaredColType = 'FLOAT') or +- (DeclaredColType = 'DOUBLE') or +- (DeclaredColType = 'REAL') then +- thisColType^ := dtNumeric +- else +- if DeclaredColType = 'BLOB' then +- thisColType^ := dtBlob +- else +- thisColType^ := dtStr; +- fColTypes.Add(thiscoltype); +- end; ++ + Next; + end; + +@@ -1197,10 +1351,6 @@ + Sqlite3_Finalize(fstmt); + if Assigned(fCols) then + fCols.Free; +- if Assigned(fColTypes) then +- for i := 0 to fColTypes.Count - 1 do +- dispose(fColTypes[i]); +- fColTypes.Free; + inherited; + end; + +@@ -1217,6 +1367,12 @@ + Result.writebuffer(ptr^, iNumBytes); + Result.Position := 0; + end; ++end; ++ ++function TSQLiteUniTable.FieldAsBlobPtr(I: cardinal; out iNumBytes: integer): Pointer; ++begin ++ iNumBytes := Sqlite3_ColumnBytes(fstmt, i); ++ Result := Sqlite3_ColumnBlob(fstmt, i); + end; + + function TSQLiteUniTable.FieldAsBlobText(I: cardinal): string; -- cgit v1.2.3