From 1ba91d5a0e1df7419a561f6dcf16a0839509a5e7 Mon Sep 17 00:00:00 2001
From: k-m_schindler <k-m_schindler@b956fd51-792f-4845-bead-9b4dfca2ff2c>
Date: Wed, 27 Aug 2008 13:28:57 +0000
Subject: Reordering of the directories[1]: moving Game/Code to src

git-svn-id: svn://svn.code.sf.net/p/ultrastardx/svn/trunk@1302 b956fd51-792f-4845-bead-9b4dfca2ff2c
---
 src/lib/SQLite/SQLite3.pas             |  255 ++++++
 src/lib/SQLite/SQLiteTable3.pas        | 1446 ++++++++++++++++++++++++++++++++
 src/lib/SQLite/example/Sunset.jpg      |  Bin 0 -> 71189 bytes
 src/lib/SQLite/example/TestSqlite.dpr  |   15 +
 src/lib/SQLite/example/TestSqlite.res  |  Bin 0 -> 876 bytes
 src/lib/SQLite/example/uTestSqlite.dfm |  110 +++
 src/lib/SQLite/example/uTestSqlite.pas |  233 +++++
 src/lib/SQLite/readme.txt              |   93 ++
 8 files changed, 2152 insertions(+)
 create mode 100644 src/lib/SQLite/SQLite3.pas
 create mode 100644 src/lib/SQLite/SQLiteTable3.pas
 create mode 100644 src/lib/SQLite/example/Sunset.jpg
 create mode 100644 src/lib/SQLite/example/TestSqlite.dpr
 create mode 100644 src/lib/SQLite/example/TestSqlite.res
 create mode 100644 src/lib/SQLite/example/uTestSqlite.dfm
 create mode 100644 src/lib/SQLite/example/uTestSqlite.pas
 create mode 100644 src/lib/SQLite/readme.txt

(limited to 'src/lib/SQLite')

diff --git a/src/lib/SQLite/SQLite3.pas b/src/lib/SQLite/SQLite3.pas
new file mode 100644
index 00000000..c702554a
--- /dev/null
+++ b/src/lib/SQLite/SQLite3.pas
@@ -0,0 +1,255 @@
+unit SQLite3;
+
+{
+  Simplified interface for SQLite.
+  Updated for Sqlite 3 by Tim Anderson (tim@itwriting.com)
+  Note: NOT COMPLETE for version 3, just minimal functionality
+  Adapted from file created by Pablo Pissanetzky (pablo@myhtpc.net)
+  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
+{$IFDEF MSWINDOWS}
+  SQLiteDLL = 'sqlite3.dll';
+{$ENDIF}
+{$IFDEF LINUX}
+  SQLiteDLL = 'sqlite3.so';
+{$ENDIF}
+{$IFDEF DARWIN}
+  SQLiteDLL = 'libsqlite3.dylib';
+  {$linklib libsqlite3}
+{$ENDIF}
+
+// Return values for sqlite3_exec() and sqlite3_step()
+
+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_UTF8     = 1;
+  SQLITE_UTF16    = 2;
+  SQLITE_UTF16BE  = 3;
+  SQLITE_UTF16LE  = 4;
+  SQLITE_ANY      = 5;
+
+  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(UserData: pointer; Buf1Len: integer; Buf1: pointer;
+    Buf2Len: integer; Buf2: pointer): integer; cdecl;
+    
+
+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: 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';
+procedure SQlite3_Free(P: PChar); cdecl; external SQLiteDLL name 'sqlite3_free';
+function SQLite3_GetTable(db: TSQLiteDB; SQLStatement: PChar; var ResultPtr: TSQLiteResult; var RowCount: Cardinal; var ColCount: Cardinal; var ErrMsg: PChar): integer; cdecl; external SQLiteDLL name 'sqlite3_get_table';
+procedure SQLite3_FreeTable(Table: TSQLiteResult); cdecl; external SQLiteDLL name 'sqlite3_free_table';
+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: 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_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_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
+//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.
+// 
+
+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_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;
+  cdecl; external SQLiteDLL name 'sqlite3_bind_null';
+
+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';
+
+//user collate definiton
+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;
+
+implementation
+
+uses
+  SysUtils;
+
+function SQLiteFieldType(SQLiteFieldTypeCode: Integer): AnsiString;
+begin
+  case SQLiteFieldTypeCode of
+    SQLITE_INTEGER: Result := 'Integer';
+    SQLITE_FLOAT: Result := 'Float';
+    SQLITE_TEXT: Result := 'Text';
+    SQLITE_BLOB: Result := 'Blob';
+    SQLITE_NULL: Result := 'Null';
+  else
+    Result := 'Unknown SQLite Field Type Code "' + IntToStr(SQLiteFieldTypeCode) + '"';
+  end;
+end;
+
+function SQLiteErrorStr(SQLiteErrorCode: Integer): AnsiString;
+begin
+  case SQLiteErrorCode of
+    SQLITE_OK: Result := 'Successful result';
+    SQLITE_ERROR: Result := 'SQL error or missing database';
+    SQLITE_INTERNAL: Result := 'An internal logic error in SQLite';
+    SQLITE_PERM: Result := 'Access permission denied';
+    SQLITE_ABORT: Result := 'Callback routine requested an abort';
+    SQLITE_BUSY: Result := 'The database file is locked';
+    SQLITE_LOCKED: Result := 'A table in the database is locked';
+    SQLITE_NOMEM: Result := 'A malloc() failed';
+    SQLITE_READONLY: Result := 'Attempt to write a readonly database';
+    SQLITE_INTERRUPT: Result := 'Operation terminated by sqlite3_interrupt()';
+    SQLITE_IOERR: Result := 'Some kind of disk I/O error occurred';
+    SQLITE_CORRUPT: Result := 'The database disk image is malformed';
+    SQLITE_NOTFOUND: Result := '(Internal Only) Table or record not found';
+    SQLITE_FULL: Result := 'Insertion failed because database is full';
+    SQLITE_CANTOPEN: Result := 'Unable to open the database file';
+    SQLITE_PROTOCOL: Result := 'Database lock protocol error';
+    SQLITE_EMPTY: Result := 'Database is empty';
+    SQLITE_SCHEMA: Result := 'The database schema changed';
+    SQLITE_TOOBIG: Result := 'Too much data for one row of a table';
+    SQLITE_CONSTRAINT: Result := 'Abort due to contraint violation';
+    SQLITE_MISMATCH: Result := 'Data type mismatch';
+    SQLITE_MISUSE: Result := 'Library used incorrectly';
+    SQLITE_NOLFS: Result := 'Uses OS features not supported on host';
+    SQLITE_AUTH: Result := 'Authorization denied';
+    SQLITE_FORMAT: Result := 'Auxiliary database format error';
+    SQLITE_RANGE: Result := '2nd parameter to sqlite3_bind out of range';
+    SQLITE_NOTADB: Result := 'File opened that is not a database file';
+    SQLITE_ROW: Result := 'sqlite3_step() has another row ready';
+    SQLITE_DONE: Result := 'sqlite3_step() has finished executing';
+  else
+    Result := 'Unknown SQLite Error Code "' + IntToStr(SQLiteErrorCode) + '"';
+  end;
+end;
+
+function ColValueToStr(Value: PChar): AnsiString;
+begin
+  if (Value = nil) then
+    Result := 'NULL'
+  else
+    Result := Value;
+end;
+
+
+end.
+
diff --git a/src/lib/SQLite/SQLiteTable3.pas b/src/lib/SQLite/SQLiteTable3.pas
new file mode 100644
index 00000000..8f33b115
--- /dev/null
+++ b/src/lib/SQLite/SQLiteTable3.pas
@@ -0,0 +1,1446 @@
+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 execution of SQL query.
+  It run query and read all returned rows to internal buffer.
+  It allows accessing fields by name as well as index and can move through a
+  result set forward and backwards, or randomly to any row.
+
+  TSQLiteUniTable wraps execution of SQL query.
+  It run query as TSQLiteTable, but reading just first row only!
+  You can step to next row (until not EOF) by 'Next' method.
+  You cannot step backwards! (So, it is called as UniDirectional result set.)
+  It not using any internal buffering, this class is very close to Sqlite API.
+  It allows accessing fields by name as well as index on actual row only.
+  Very good and fast for sequentional scanning of large result sets with minimal
+    memory footprint.
+
+  Warning! Do not close TSQLiteDatabase before any TSQLiteUniTable,
+    because query is closed on TSQLiteUniTable destructor and database connection
+    is used during TSQLiteUniTable live!
+
+  SQL parameter usage:
+    You can add named parameter values by call set of AddParam* methods.
+    Parameters will be used for first next SQL statement only.
+    Parameter name must be prefixed by ':', '$' or '@' and same prefix must be
+    used in SQL statement!
+    Sample:
+      table.AddParamText(':str', 'some value');
+      s := table.GetTableString('SELECT value FROM sometable WHERE id=:str');
+
+   Notes from Andrew Retmanski on prepared queries
+   The changes are as follows:
+
+   SQLiteTable3.pas
+   - Added new boolean property Synchronised (this controls the SYNCHRONOUS pragma as I found that turning this OFF increased the write performance in my application)
+   - Added new type TSQLiteQuery (this is just a simple record wrapper around the SQL string and a TSQLiteStmt pointer)
+   - Added PrepareSQL method to prepare SQL query - returns TSQLiteQuery
+   - Added ReleaseSQL method to release previously prepared query
+   - Added overloaded BindSQL methods for Integer and String types - these set new values for the prepared query parameters
+   - Added overloaded ExecSQL method to execute a prepared TSQLiteQuery
+
+   Usage of the new methods should be self explanatory but the process is in essence:
+
+   1. Call PrepareSQL to return TSQLiteQuery 2. Call BindSQL for each parameter in the prepared query 3. Call ExecSQL to run the prepared query 4. Repeat steps 2 & 3 as required 5. Call ReleaseSQL to free SQLite resources
+
+   One other point - the Synchronised property throws an error if used inside a transaction.
+
+   Acknowledments
+   Adapted by Tim Anderson (tim@itwriting.com)
+   Originally created by Pablo Pissanetzky (pablo@myhtpc.net)
+   Modified and enhanced by Lukas Gebauer
+}
+
+interface
+
+{$IFDEF FPC}
+  {$MODE Delphi}{$H+}
+{$ENDIF}
+
+uses
+  {$IFDEF WIN32}
+  Windows,
+  {$ENDIF}
+  SQLite3, Classes, SysUtils;
+
+const
+
+  dtInt = 1;
+  dtNumeric = 2;
+  dtStr = 3;
+  dtBlob = 4;
+  dtNull = 5;
+
+type
+
+  ESQLiteException = class(Exception)
+  end;
+
+  TSQliteParam = class
+  public
+    name: string;
+    valuetype: integer;
+    valueinteger: int64;
+    valuefloat: double;
+    valuedata: string;
+  end;
+
+  TSQLiteQuery = record
+    SQL: String;
+    Statement: TSQLiteStmt;
+  end;
+
+
+  TSQLiteTable = class;
+  TSQLiteUniTable = class;
+
+  TSQLiteDatabase = class
+  private
+    fDB: TSQLiteDB;
+    fInTrans: boolean;
+    fSync: boolean;
+    fParams: TList;
+    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);
+  public
+    constructor Create(const FileName: string);
+    destructor Destroy; override;
+    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; 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 UpdateBlob(const SQL: string; BlobData: TStream);
+    procedure BeginTransaction;
+    procedure Commit;
+    procedure Rollback;
+    function TableExists(TableName: string): boolean;
+    function GetLastInsertRowID: int64;
+    function GetLastChangedRows: int64;
+    procedure SetTimeout(Value: integer);
+    function Version: string;
+    procedure AddCustomCollate(name: string; xCompare: TCollateXCompare);
+    //adds collate named SYSTEM for correct data sorting by user's locale
+    Procedure AddSystemCollate;
+    procedure ParamsClear;
+    procedure AddParamInt(name: string; value: int64);
+    procedure AddParamFloat(name: string; value: double);
+    procedure AddParamText(name: string; value: string);
+    procedure AddParamNull(name: string);
+    property DB: TSQLiteDB read fDB;
+  published
+    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;
+
+  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); 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 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;
+    function MoveTo(position:Integer): 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.
+    property CountResult: integer read GetCountResult;
+  end;
+
+  TSQLiteUniTable = class
+  private
+    fColCount: cardinal;
+    fCols: TStringList;
+    fRow: cardinal;
+    fEOF: boolean;
+    fStmt: TSQLiteStmt;
+    fDB: TSQLiteDatabase;
+    fSQL: string;
+    function GetFields(I: cardinal): string;
+    function GetColumns(I: integer): string;
+    function GetFieldByName(FieldName: string): string;
+    function GetFieldIndex(FieldName: string): integer;
+  public
+    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;
+    function FieldAsDouble(I: cardinal): double;
+    function Next: boolean;
+    property EOF: boolean read FEOF;
+    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 Row: cardinal read fRow;
+  end;
+
+procedure DisposePointer(ptr: pointer); cdecl;
+
+{$IFDEF WIN32}
+function SystemCollate(Userdta: pointer; Buf1Len: integer; Buf1: pointer;
+    Buf2Len: integer; Buf2: pointer): integer; cdecl;
+{$ENDIF}
+
+implementation
+
+procedure DisposePointer(ptr: pointer); cdecl;
+begin
+  if assigned(ptr) then
+    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
+//------------------------------------------------------------------------------
+
+constructor TSQLiteDatabase.Create(const FileName: string);
+var
+  Msg: pchar;
+  iResult: integer;
+  utf8FileName: string;
+begin
+  inherited Create;
+  fParams := TList.Create;
+
+  self.fInTrans := False;
+
+  Msg := nil;
+  try
+    utf8FileName := AnsiToUtf8(FileName);
+    iResult := SQLite3_Open(PChar(utf8FileName), 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]);
+
+//set a few configs
+//L.G. Do not call it here. Because busy handler is not setted here,
+// any share violation causing exception!
+
+//    self.ExecSQL('PRAGMA SYNCHRONOUS=NORMAL;');
+//    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.Rollback;  //assume rollback
+  if Assigned(fDB) then
+    SQLite3_Close(fDB);
+  ParamsClear;    
+  fParams.Free;
+  inherited;
+end;
+
+function TSQLiteDatabase.GetLastInsertRowID: int64;
+begin
+  Result := Sqlite3_LastInsertRowID(self.fDB);
+end;
+
+function TSQLiteDatabase.GetLastChangedRows: int64;
+begin
+  Result := SQLite3_TotalChanges(self.fDB);
+end;
+
+//..............................................................................
+
+procedure TSQLiteDatabase.RaiseError(s: string; SQL: string);
+//look up last error and raise an exception with an appropriate message
+var
+  Msg: PChar;
+  ret : integer;
+begin
+
+  Msg := nil;
+
+  ret := sqlite3_errcode(self.fDB);
+  if ret <> SQLITE_OK then
+    Msg := sqlite3_errmsg(self.fDB);
+
+  if Msg <> nil then
+    raise ESqliteException.CreateFmt(s +'.'#13'Error [%d]: %s.'#13'"%s": %s', [ret, SQLiteErrorStr(ret),SQL, Msg])
+  else
+    raise ESqliteException.CreateFmt(s, [SQL, 'No message']);
+
+end;
+
+procedure TSQLiteDatabase.SetSynchronised(Value: boolean);
+begin
+  if Value <> fSync then
+  begin
+    if Value then
+      ExecSQL('PRAGMA synchronous = ON;')
+    else
+      ExecSQL('PRAGMA synchronous = OFF;');
+    fSync := Value;
+  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;
+  iStepResult: integer;
+begin
+  try
+    if Sqlite3_Prepare_v2(self.fDB, PChar(SQL), -1, Stmt, NextSQLStatement) <>
+      SQLITE_OK then
+      RaiseError('Error executing SQL', SQL);
+    if (Stmt = nil) then
+      RaiseError('Could not prepare SQL statement', SQL);
+
+    SetParams(Stmt);
+    BindData(Stmt, Bindings);
+
+    iStepResult := Sqlite3_step(Stmt);
+    if (iStepResult <> SQLITE_DONE) then
+      begin
+      SQLite3_reset(stmt);
+      RaiseError('Error executing SQL statement', SQL);
+      end;
+  finally
+    if Assigned(Stmt) then
+      Sqlite3_Finalize(stmt);
+  end;
+end;
+
+{$WARNINGS OFF}
+procedure TSQLiteDatabase.ExecSQL(Query: TSQLiteQuery);
+var
+  iStepResult: integer;
+begin
+  if Assigned(Query.Statement) then
+  begin
+    iStepResult := Sqlite3_step(Query.Statement);
+
+    if (iStepResult <> SQLITE_DONE) then
+      begin
+      SQLite3_reset(Query.Statement);
+      RaiseError('Error executing prepared SQL statement', Query.SQL);
+      end;
+    Sqlite3_Reset(Query.Statement);
+  end;
+end;
+{$WARNINGS ON}
+
+{$WARNINGS OFF}
+function TSQLiteDatabase.PrepareSQL(const SQL: string): TSQLiteQuery;
+var
+  Stmt: TSQLiteStmt;
+  NextSQLStatement: Pchar;
+begin
+  Result.SQL := SQL;
+  Result.Statement := nil;
+
+  if Sqlite3_Prepare(self.fDB, PChar(SQL), -1, Stmt, NextSQLStatement) <>
+    SQLITE_OK then
+    RaiseError('Error executing SQL', SQL)
+  else
+    Result.Statement := Stmt;
+
+  if (Result.Statement = nil) then
+    RaiseError('Could not prepare SQL statement', SQL);
+end;
+{$WARNINGS ON}
+
+{$WARNINGS OFF}
+procedure TSQLiteDatabase.BindSQL(Query: TSQLiteQuery; const Index: Integer; const Value: Integer);
+begin
+  if Assigned(Query.Statement) then
+    sqlite3_Bind_Int(Query.Statement, Index, Value)
+  else
+    RaiseError('Could not bind integer to prepared SQL statement', Query.SQL);
+end;
+{$WARNINGS ON}
+
+{$WARNINGS OFF}
+procedure TSQLiteDatabase.BindSQL(Query: TSQLiteQuery; const Index: Integer; const Value: String);
+begin
+  if Assigned(Query.Statement) then
+    Sqlite3_Bind_Text(Query.Statement, Index, PChar(Value), Length(Value), Pointer(SQLITE_STATIC))
+  else
+    RaiseError('Could not bind string to prepared SQL statement', Query.SQL);
+end;
+{$WARNINGS ON}
+
+{$WARNINGS OFF}
+procedure TSQLiteDatabase.ReleaseSQL(Query: TSQLiteQuery);
+begin
+  if Assigned(Query.Statement) then
+  begin
+    Sqlite3_Finalize(Query.Statement);
+    Query.Statement := nil;
+  end
+  else
+    RaiseError('Could not release prepared SQL statement', Query.SQL);
+end;
+{$WARNINGS ON}
+
+procedure TSQLiteDatabase.UpdateBlob(const SQL: string; BlobData: TStream);
+var
+  iSize: integer;
+  ptr: pointer;
+  Stmt: TSQLiteStmt;
+  Msg: Pchar;
+  NextSQLStatement: Pchar;
+  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_v2(self.fDB, PChar(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
+      begin
+      SQLite3_reset(stmt);
+      RaiseError('Error executing SQL statement', SQL);
+      end;
+
+  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.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, Bindings);
+  try
+    if not Table.EOF then
+      Result := Table.FieldAsInteger(0);
+  finally
+    Table.Free;
+  end;
+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, Bindings);
+  try
+    if not Table.EOF then
+      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_BusyTimeout(self.fDB, Value);
+end;
+
+function TSQLiteDatabase.Version: string;
+begin
+  Result := SQLite3_Version;
+end;
+
+procedure TSQLiteDatabase.AddCustomCollate(name: string;
+  xCompare: TCollateXCompare);
+begin
+  sqlite3_create_collation(fdb, PChar(name), SQLITE_UTF8, nil, xCompare);
+end;
+
+procedure TSQLiteDatabase.AddSystemCollate;
+begin
+  {$IFDEF WIN32}
+  sqlite3_create_collation(fdb, 'SYSTEM', SQLITE_UTF16LE, nil, @SystemCollate);
+  {$ENDIF}
+end;
+
+procedure TSQLiteDatabase.ParamsClear;
+var
+  n: integer;
+begin
+  for n := fParams.Count - 1 downto 0 do
+    TSQliteParam(fparams[n]).free;
+  fParams.Clear;
+end;
+
+procedure TSQLiteDatabase.AddParamInt(name: string; value: int64);
+var
+  par: TSQliteParam;
+begin
+  par := TSQliteParam.Create;
+  par.name := name;
+  par.valuetype := SQLITE_INTEGER;
+  par.valueinteger := value;
+  fParams.Add(par);
+end;
+
+procedure TSQLiteDatabase.AddParamFloat(name: string; value: double);
+var
+  par: TSQliteParam;
+begin
+  par := TSQliteParam.Create;
+  par.name := name;
+  par.valuetype := SQLITE_FLOAT;
+  par.valuefloat := value;
+  fParams.Add(par);
+end;
+
+procedure TSQLiteDatabase.AddParamText(name: string; value: string);
+var
+  par: TSQliteParam;
+begin
+  par := TSQliteParam.Create;
+  par.name := name;
+  par.valuetype := SQLITE_TEXT;
+  par.valuedata := value;
+  fParams.Add(par);
+end;
+
+procedure TSQLiteDatabase.AddParamNull(name: string);
+var
+  par: TSQliteParam;
+begin
+  par := TSQliteParam.Create;
+  par.name := name;
+  par.valuetype := SQLITE_NULL;
+  fParams.Add(par);
+end;
+
+procedure TSQLiteDatabase.SetParams(Stmt: TSQLiteStmt);
+var
+  n: integer;
+  i: integer;
+  par: TSQliteParam;
+begin
+  try
+    for n := 0 to fParams.Count - 1 do
+    begin
+      par := TSQliteParam(fParams[n]);
+      i := sqlite3_bind_parameter_index(Stmt, PChar(par.name));
+      if i > 0 then
+      begin
+        case par.valuetype of
+          SQLITE_INTEGER:
+            sqlite3_bind_int64(Stmt, i, par.valueinteger);
+          SQLITE_FLOAT:
+            sqlite3_bind_double(Stmt, i, par.valuefloat);
+          SQLITE_TEXT:
+            sqlite3_bind_text(Stmt, i, pchar(par.valuedata),
+              length(par.valuedata), SQLITE_TRANSIENT);
+          SQLITE_NULL:
+            sqlite3_bind_null(Stmt, i);
+        end;
+      end;
+    end;
+  finally
+    ParamsClear;
+  end;
+end;
+
+//database rows that were changed (or inserted or deleted) by the most recent SQL statement
+function TSQLiteDatabase.GetRowsChanged: integer;
+begin
+ Result := SQLite3_Changes(self.fDB);
+end;
+
+//------------------------------------------------------------------------------
+// TSQLiteTable
+//------------------------------------------------------------------------------
+
+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;
+  iStepResult: integer;
+  ptr: pointer;
+  iNumBytes: integer;
+  thisBlobValue: TMemoryStream;
+  thisStringValue: pstring;
+  thisDoubleValue: pDouble;
+  thisIntValue: pInt64;
+  thisColType: pInteger;
+  i: integer;
+  DeclaredColType: Pchar;
+  ActualColType: integer;
+  ptrValue: Pchar;
+begin
+  inherited create;
+  try
+    self.fRowCount := 0;
+    self.fColCount := 0;
+    //if there are several SQL statements in SQL, NextSQLStatment points to the
+    //beginning of the next one. Prepare only prepares the first SQL statement.
+    if Sqlite3_Prepare_v2(DB.fDB, PChar(SQL), -1, Stmt, NextSQLStatement) <> SQLITE_OK then
+      DB.RaiseError('Error executing SQL', SQL);
+    if (Stmt = nil) then
+      DB.RaiseError('Could not prepare SQL statement', SQL);
+
+    DB.SetParams(Stmt);
+    DB.BindData(Stmt, Bindings);
+
+    iStepResult := Sqlite3_step(Stmt);
+    while (iStepResult <> SQLITE_DONE) do
+    begin
+      case iStepResult of
+        SQLITE_ROW:
+          begin
+            Inc(fRowCount);
+            if (fRowCount = 1) then
+            begin
+            //get data types
+              fCols := TStringList.Create;
+              fColTypes := TList.Create;
+              fColCount := SQLite3_ColumnCount(stmt);
+              for i := 0 to Pred(fColCount) do
+                fCols.Add(AnsiUpperCase(Sqlite3_ColumnName(stmt, i)));
+              for i := 0 to Pred(fColCount) do
+              begin
+                new(thisColType);
+                DeclaredColType := Sqlite3_ColumnDeclType(stmt, i);
+                if DeclaredColType = nil then
+                  thisColType^ := Sqlite3_ColumnType(stmt, 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;
+              fResults := TList.Create;
+            end;
+
+          //get column values
+            for i := 0 to Pred(ColCount) do
+            begin
+              ActualColType := Sqlite3_ColumnType(stmt, i);
+              if (ActualColType = SQLITE_NULL) then
+                fResults.Add(nil)
+              else
+                if pInteger(fColTypes[i])^ = dtInt then
+                begin
+                  new(thisintvalue);
+                  thisintvalue^ := Sqlite3_ColumnInt64(stmt, i);
+                  fResults.Add(thisintvalue);
+                end
+                else
+                  if pInteger(fColTypes[i])^ = dtNumeric then
+                  begin
+                    new(thisdoublevalue);
+                    thisdoublevalue^ := Sqlite3_ColumnDouble(stmt, i);
+                    fResults.Add(thisdoublevalue);
+                  end
+                  else
+                    if pInteger(fColTypes[i])^ = dtBlob then
+                    begin
+                      iNumBytes := Sqlite3_ColumnBytes(stmt, i);
+                      if iNumBytes = 0 then
+                        thisblobvalue := nil
+                      else
+                      begin
+                        thisblobvalue := TMemoryStream.Create;
+                        thisblobvalue.position := 0;
+                        ptr := Sqlite3_ColumnBlob(stmt, i);
+                        thisblobvalue.writebuffer(ptr^, iNumBytes);
+                      end;
+                      fResults.Add(thisblobvalue);
+                    end
+                    else
+                    begin
+                      new(thisstringvalue);
+                      ptrValue := Sqlite3_ColumnText(stmt, i);
+                      setstring(thisstringvalue^, ptrvalue, strlen(ptrvalue));
+                      fResults.Add(thisstringvalue);
+                    end;
+            end;
+          end;
+        SQLITE_BUSY:
+          raise ESqliteException.CreateFmt('Could not prepare SQL statement',
+            [SQL, 'SQLite is Busy']);
+      else
+        begin
+        SQLite3_reset(stmt);
+        DB.RaiseError('Could not retrieve data', SQL);
+        end;
+      end;
+      iStepResult := Sqlite3_step(Stmt);
+    end;
+    fRow := 0;
+  finally
+    if Assigned(Stmt) then
+      Sqlite3_Finalize(stmt);
+  end;
+end;
+
+//..............................................................................
+
+destructor TSQLiteTable.Destroy;
+var
+  i: cardinal;
+  iColNo: integer;
+begin
+  if Assigned(fResults) then
+  begin
+    for i := 0 to fResults.Count - 1 do
+    begin
+      //check for blob type
+      iColNo := (i mod fColCount);
+      case pInteger(self.fColTypes[iColNo])^ of
+        dtBlob:
+          TMemoryStream(fResults[i]).Free;
+        dtStr:
+          if fResults[i] <> nil then
+          begin
+            setstring(string(fResults[i]^), nil, 0);
+            dispose(fResults[i]);
+          end;
+      else
+        dispose(fResults[i]);
+      end;
+    end;
+    fResults.Free;
+  end;
+  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;
+
+//..............................................................................
+
+function TSQLiteTable.GetColumns(I: integer): string;
+begin
+  Result := fCols[I];
+end;
+
+//..............................................................................
+
+function TSQLiteTable.GetCountResult: integer;
+begin
+  if not EOF then
+    Result := StrToInt(Fields[0])
+  else
+    Result := 0;
+end;
+
+function TSQLiteTable.GetCount: integer;
+begin
+  Result := FRowCount;
+end;
+
+//..............................................................................
+
+function TSQLiteTable.GetEOF: boolean;
+begin
+  Result := fRow >= fRowCount;
+end;
+
+function TSQLiteTable.GetBOF: boolean;
+begin
+  Result := fRow <= 0;
+end;
+
+//..............................................................................
+
+function TSQLiteTable.GetFieldByName(FieldName: string): string;
+begin
+  Result := GetFields(self.GetFieldIndex(FieldName));
+end;
+
+function TSQLiteTable.GetFieldIndex(FieldName: string): integer;
+begin
+  if (fCols = nil) then
+  begin
+    raise ESqliteException.Create('Field ' + fieldname + ' Not found. Empty dataset');
+    exit;
+  end;
+
+  if (fCols.count = 0) then
+  begin
+    raise ESqliteException.Create('Field ' + fieldname + ' Not found. Empty dataset');
+    exit;
+  end;
+
+  Result := fCols.IndexOf(AnsiUpperCase(FieldName));
+
+  if (result < 0) then
+  begin
+    raise ESqliteException.Create('Field not found in dataset: ' + fieldname)
+  end;
+end;
+
+//..............................................................................
+
+function TSQLiteTable.GetFields(I: cardinal): string;
+var
+  thisvalue: pstring;
+  thistype: integer;
+begin
+  Result := '';
+  if EOF then
+    raise ESqliteException.Create('Table is at End of File');
+  //integer types are not stored in the resultset
+  //as strings, so they should be retrieved using the type-specific
+  //methods
+  thistype := pInteger(self.fColTypes[I])^;
+
+  case thistype of
+    dtStr:
+      begin
+        thisvalue := self.fResults[(self.frow * self.fColCount) + I];
+        if (thisvalue <> nil) then
+          Result := thisvalue^
+        else
+          Result := '';
+      end;
+    dtInt:
+      Result := IntToStr(self.FieldAsInteger(I));
+    dtNumeric:
+      Result := FloatToStr(self.FieldAsDouble(I));
+    dtBlob:
+      Result := self.FieldAsBlobText(I);
+  else
+    Result := '';
+  end;
+end;
+
+function TSqliteTable.FieldAsBlob(I: cardinal): TMemoryStream;
+begin
+  if EOF then
+    raise ESqliteException.Create('Table is at End of File');
+  if (self.fResults[(self.frow * self.fColCount) + I] = nil) then
+    Result := nil
+  else
+    if pInteger(self.fColTypes[I])^ = dtBlob then
+      Result := TMemoryStream(self.fResults[(self.frow * self.fColCount) + I])
+    else
+      raise ESqliteException.Create('Not a Blob field');
+end;
+
+function TSqliteTable.FieldAsBlobText(I: cardinal): string;
+var
+  MemStream: TMemoryStream;
+  Buffer: PChar;
+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;
+end;
+
+
+function TSqliteTable.FieldAsInteger(I: cardinal): int64;
+begin
+  if EOF then
+    raise ESqliteException.Create('Table is at End of File');
+  if (self.fResults[(self.frow * self.fColCount) + I] = nil) then
+    Result := 0
+  else
+    if pInteger(self.fColTypes[I])^ = dtInt then
+      Result := pInt64(self.fResults[(self.frow * self.fColCount) + I])^
+    else
+      if pInteger(self.fColTypes[I])^ = dtNumeric then
+        Result := trunc(strtofloat(pString(self.fResults[(self.frow * self.fColCount) + I])^))
+      else
+        raise ESqliteException.Create('Not an integer or numeric field');
+end;
+
+function TSqliteTable.FieldAsDouble(I: cardinal): double;
+begin
+  if EOF then
+    raise ESqliteException.Create('Table is at End of File');
+  if (self.fResults[(self.frow * self.fColCount) + I] = nil) then
+    Result := 0
+  else
+    if pInteger(self.fColTypes[I])^ = dtInt then
+      Result := pInt64(self.fResults[(self.frow * self.fColCount) + I])^
+    else
+      if pInteger(self.fColTypes[I])^ = dtNumeric then
+        Result := pDouble(self.fResults[(self.frow * self.fColCount) + I])^
+      else
+        raise ESqliteException.Create('Not an integer or numeric field');
+end;
+
+function TSqliteTable.FieldAsString(I: cardinal): string;
+begin
+  if EOF then
+    raise ESqliteException.Create('Table is at End of File');
+  if (self.fResults[(self.frow * self.fColCount) + I] = nil) then
+    Result := ''
+  else
+    Result := self.GetFields(I);
+end;
+
+function TSqliteTable.FieldIsNull(I: cardinal): boolean;
+var
+  thisvalue: pointer;
+begin
+  if EOF then
+    raise ESqliteException.Create('Table is at End of File');
+  thisvalue := self.fResults[(self.frow * self.fColCount) + I];
+  Result := (thisvalue = nil);
+end;
+
+//..............................................................................
+
+function TSQLiteTable.Next: boolean;
+begin
+  Result := False;
+  if not EOF then
+  begin
+    Inc(fRow);
+    Result := True;
+  end;
+end;
+
+function TSQLiteTable.Previous: boolean;
+begin
+  Result := False;
+  if not BOF then
+  begin
+    Dec(fRow);
+    Result := True;
+  end;
+end;
+
+function TSQLiteTable.MoveFirst: boolean;
+begin
+  Result := False;
+  if self.fRowCount > 0 then
+  begin
+    fRow := 0;
+    Result := True;
+  end;
+end;
+
+function TSQLiteTable.MoveLast: boolean;
+begin
+  Result := False;
+  if self.fRowCount > 0 then
+  begin
+    fRow := fRowCount - 1;
+    Result := True;
+  end;
+end;
+
+{$WARNINGS OFF}
+function TSQLiteTable.MoveTo(position: Integer): boolean;
+begin
+  Result := False;
+  if (self.fRowCount > 0) and (self.fRowCount > position) then
+  begin
+    fRow := position;
+    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;
+  i: integer;
+  DeclaredColType: Pchar;
+begin
+  inherited create;
+  self.fDB := db;
+  self.fEOF := false;
+  self.fRow := 0;
+  self.fColCount := 0;
+  self.fSQL := SQL;
+  if Sqlite3_Prepare_v2(DB.fDB, PChar(SQL), -1, fStmt, NextSQLStatement) <> SQLITE_OK then
+    DB.RaiseError('Error executing SQL', SQL);
+  if (fStmt = nil) then
+    DB.RaiseError('Could not prepare SQL statement', SQL);
+
+  DB.SetParams(fStmt);
+  DB.BindData(fStmt, Bindings);
+
+  //get data types
+  fCols := TStringList.Create;
+  fColCount := SQLite3_ColumnCount(fstmt);
+  for i := 0 to Pred(fColCount) do
+    fCols.Add(AnsiUpperCase(Sqlite3_ColumnName(fstmt, i)));
+
+  Next;
+end;
+
+destructor TSQLiteUniTable.Destroy;
+var
+  i: integer;
+begin
+  if Assigned(fStmt) then
+    Sqlite3_Finalize(fstmt);
+  if Assigned(fCols) then
+    fCols.Free;
+  inherited;
+end;
+
+function TSQLiteUniTable.FieldAsBlob(I: cardinal): TMemoryStream;
+var
+  iNumBytes: integer;
+  ptr: pointer;
+begin
+  Result := TMemoryStream.Create;
+  iNumBytes := Sqlite3_ColumnBytes(fstmt, i);
+  if iNumBytes > 0 then
+  begin
+    ptr := Sqlite3_ColumnBlob(fstmt, i);
+    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;
+var
+  MemStream: TMemoryStream;
+  Buffer: PChar;
+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;
+end;
+
+function TSQLiteUniTable.FieldAsDouble(I: cardinal): double;
+begin
+  Result := Sqlite3_ColumnDouble(fstmt, i);
+end;
+
+function TSQLiteUniTable.FieldAsInteger(I: cardinal): int64;
+begin
+  Result := Sqlite3_ColumnInt64(fstmt, i);
+end;
+
+function TSQLiteUniTable.FieldAsString(I: cardinal): string;
+begin
+  Result := self.GetFields(I);
+end;
+
+function TSQLiteUniTable.FieldIsNull(I: cardinal): boolean;
+begin
+  Result := Sqlite3_ColumnText(fstmt, i) = nil;
+end;
+
+function TSQLiteUniTable.GetColumns(I: integer): string;
+begin
+  Result := fCols[I];
+end;
+
+function TSQLiteUniTable.GetFieldByName(FieldName: string): string;
+begin
+  Result := GetFields(self.GetFieldIndex(FieldName));
+end;
+
+function TSQLiteUniTable.GetFieldIndex(FieldName: string): integer;
+begin
+  if (fCols = nil) then
+  begin
+    raise ESqliteException.Create('Field ' + fieldname + ' Not found. Empty dataset');
+    exit;
+  end;
+
+  if (fCols.count = 0) then
+  begin
+    raise ESqliteException.Create('Field ' + fieldname + ' Not found. Empty dataset');
+    exit;
+  end;
+
+  Result := fCols.IndexOf(AnsiUpperCase(FieldName));
+
+  if (result < 0) then
+  begin
+    raise ESqliteException.Create('Field not found in dataset: ' + fieldname)
+  end;
+end;
+
+function TSQLiteUniTable.GetFields(I: cardinal): string;
+begin
+  Result := Sqlite3_ColumnText(fstmt, i);
+end;
+
+function TSQLiteUniTable.Next: boolean;
+var
+  iStepResult: integer;
+begin
+  fEOF := true;
+  iStepResult := Sqlite3_step(fStmt);
+  case iStepResult of
+    SQLITE_ROW:
+      begin
+        fEOF := false;
+        inc(fRow);
+      end;
+    SQLITE_DONE:
+      // we are on the end of dataset
+      // return EOF=true only
+      ;
+  else
+    begin
+    SQLite3_reset(fStmt);
+    fDB.RaiseError('Could not retrieve data', fSQL);
+    end;
+  end;
+  Result := not fEOF;
+end;
+
+end.
+
diff --git a/src/lib/SQLite/example/Sunset.jpg b/src/lib/SQLite/example/Sunset.jpg
new file mode 100644
index 00000000..860f6eec
Binary files /dev/null and b/src/lib/SQLite/example/Sunset.jpg differ
diff --git a/src/lib/SQLite/example/TestSqlite.dpr b/src/lib/SQLite/example/TestSqlite.dpr
new file mode 100644
index 00000000..596a3a04
--- /dev/null
+++ b/src/lib/SQLite/example/TestSqlite.dpr
@@ -0,0 +1,15 @@
+program TestSqlite;
+
+uses
+  Forms,
+  uTestSqlite in 'uTestSqlite.pas' {Form1},
+  SQLiteTable3 in 'SQLiteTable3.pas',
+  SQLite3 in 'SQLite3.pas';
+
+{$R *.res}
+
+begin
+  Application.Initialize;
+  Application.CreateForm(TForm1, Form1);
+  Application.Run;
+end.
diff --git a/src/lib/SQLite/example/TestSqlite.res b/src/lib/SQLite/example/TestSqlite.res
new file mode 100644
index 00000000..4bdd5e2e
Binary files /dev/null and b/src/lib/SQLite/example/TestSqlite.res differ
diff --git a/src/lib/SQLite/example/uTestSqlite.dfm b/src/lib/SQLite/example/uTestSqlite.dfm
new file mode 100644
index 00000000..6b4a2aaf
--- /dev/null
+++ b/src/lib/SQLite/example/uTestSqlite.dfm
@@ -0,0 +1,110 @@
+object Form1: TForm1
+  Left = 199
+  Top = 280
+  Width = 541
+  Height = 308
+  Caption = 'Test SQLite 3'
+  Color = clBtnFace
+  Font.Charset = DEFAULT_CHARSET
+  Font.Color = clWindowText
+  Font.Height = -11
+  Font.Name = 'MS Sans Serif'
+  Font.Style = []
+  OldCreateOrder = False
+  PixelsPerInch = 96
+  TextHeight = 13
+  object Label1: TLabel
+    Left = 24
+    Top = 104
+    Width = 28
+    Height = 13
+    Caption = 'Notes'
+  end
+  object Label2: TLabel
+    Left = 24
+    Top = 44
+    Width = 28
+    Height = 13
+    Caption = 'Name'
+  end
+  object Label3: TLabel
+    Left = 24
+    Top = 72
+    Width = 40
+    Height = 13
+    Caption = 'Number:'
+  end
+  object Label4: TLabel
+    Left = 24
+    Top = 12
+    Width = 11
+    Height = 13
+    Caption = 'ID'
+  end
+  object Image1: TImage
+    Left = 272
+    Top = 12
+    Width = 241
+    Height = 165
+    Proportional = True
+    Stretch = True
+  end
+  object btnTest: TButton
+    Left = 24
+    Top = 224
+    Width = 161
+    Height = 37
+    Caption = 'Test SQLite 3'
+    TabOrder = 0
+    OnClick = btnTestClick
+  end
+  object memNotes: TMemo
+    Left = 24
+    Top = 124
+    Width = 185
+    Height = 89
+    Lines.Strings = (
+      '')
+    ScrollBars = ssVertical
+    TabOrder = 1
+  end
+  object ebName: TEdit
+    Left = 72
+    Top = 40
+    Width = 173
+    Height = 21
+    TabOrder = 2
+  end
+  object ebNumber: TEdit
+    Left = 72
+    Top = 68
+    Width = 173
+    Height = 21
+    TabOrder = 3
+  end
+  object ebID: TEdit
+    Left = 72
+    Top = 12
+    Width = 173
+    Height = 21
+    TabOrder = 4
+  end
+  object btnLoadImage: TButton
+    Left = 192
+    Top = 224
+    Width = 157
+    Height = 37
+    Caption = 'Load image'
+    TabOrder = 5
+    OnClick = btnLoadImageClick
+  end
+  object btnDisplayImage: TButton
+    Left = 360
+    Top = 224
+    Width = 157
+    Height = 37
+    Caption = 'Display image'
+    TabOrder = 6
+    OnClick = btnDisplayImageClick
+  end
+end
diff --git a/src/lib/SQLite/example/uTestSqlite.pas b/src/lib/SQLite/example/uTestSqlite.pas
new file mode 100644
index 00000000..484be71c
--- /dev/null
+++ b/src/lib/SQLite/example/uTestSqlite.pas
@@ -0,0 +1,233 @@
+unit uTestSqlite;
+
+interface
+
+uses
+  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
+  Dialogs, StdCtrls,SQLiteTable3, ExtCtrls, jpeg;
+
+type
+  TForm1 = class(TForm)
+    btnTest: TButton;
+    memNotes: TMemo;
+    Label1: TLabel;
+    Label2: TLabel;
+    ebName: TEdit;
+    Label3: TLabel;
+    ebNumber: TEdit;
+    Label4: TLabel;
+    ebID: TEdit;
+    Image1: TImage;
+    btnLoadImage: TButton;
+    btnDisplayImage: TButton;
+    procedure btnTestClick(Sender: TObject);
+    procedure btnLoadImageClick(Sender: TObject);
+    procedure btnDisplayImageClick(Sender: TObject);
+  private
+    { Private declarations }
+  public
+    { Public declarations }
+  end;
+
+var
+  Form1: TForm1;
+
+implementation
+
+{$R *.dfm}
+
+procedure TForm1.btnTestClick(Sender: TObject);
+var
+slDBpath: string;
+sldb: TSQLiteDatabase;
+sltb: TSQLIteTable;
+sSQL: String;
+Notes: String;
+
+begin
+
+slDBPath := ExtractFilepath(application.exename)
++ 'test.db';
+
+sldb := TSQLiteDatabase.Create(slDBPath);
+try
+
+if sldb.TableExists('testTable') then begin
+sSQL := 'DROP TABLE testtable';
+sldb.execsql(sSQL);
+end;
+
+sSQL := 'CREATE TABLE testtable ([ID] INTEGER PRIMARY KEY,[OtherID] INTEGER NULL,';
+sSQL := sSQL + '[Name] VARCHAR (255),[Number] FLOAT, [notes] BLOB, [picture] BLOB COLLATE NOCASE);';
+
+sldb.execsql(sSQL);
+
+sldb.execsql('CREATE INDEX TestTableName ON [testtable]([Name]);');
+
+//begin a transaction
+sldb.BeginTransaction;
+
+sSQL := 'INSERT INTO testtable(Name,OtherID,Number,Notes) VALUES ("Some Name",4,587.6594,"Here are some notes");';
+//do the insert
+sldb.ExecSQL(sSQL);
+
+sSQL := 'INSERT INTO testtable(Name,OtherID,Number,Notes) VALUES ("Another Name",12,4758.3265,"More notes");';
+//do the insert
+sldb.ExecSQL(sSQL);
+
+//end the transaction
+sldb.Commit;
+
+//query the data
+sltb := slDb.GetTable('SELECT * FROM testtable');
+try
+
+if sltb.Count > 0 then
+begin
+//display first row
+
+ebName.Text := sltb.FieldAsString(sltb.FieldIndex['Name']);
+ebID.Text := inttostr(sltb.FieldAsInteger(sltb.FieldIndex['ID']));
+ebNumber.Text := floattostr( sltb.FieldAsDouble(sltb.FieldIndex['Number']));
+Notes :=  sltb.FieldAsBlobText(sltb.FieldIndex['Notes']);
+memNotes.Text := notes;
+
+end;
+
+finally
+sltb.Free;
+end;
+
+finally
+sldb.Free;
+
+end;
+
+end;
+
+procedure TForm1.btnLoadImageClick(Sender: TObject);
+var
+slDBpath: string;
+sldb: TSQLiteDatabase;
+sltb: TSQLIteTable;
+iID: integer;
+fs: TFileStream;
+
+begin
+
+slDBPath := ExtractFilepath(application.exename)
++ 'test.db';
+
+if not FileExists(slDBPath) then begin
+MessageDLg('Test.db does not exist. Click Test Sqlite 3 to create it.',mtInformation,[mbOK],0);
+exit;
+end;
+
+sldb := TSQLiteDatabase.Create(slDBPath);
+try
+
+//get an ID
+//query the data
+sltb := slDb.GetTable('SELECT ID FROM testtable');
+try
+
+if sltb.Count = 0 then begin
+MessageDLg('There are no rows in the database. Click Test Sqlite 3 to insert a row.',mtInformation,[mbOK],0);
+exit;
+end;
+
+iID := sltb.FieldAsInteger(sltb.FieldIndex['ID']);
+
+finally
+sltb.Free;
+end;
+
+//load an image
+fs := TFileStream.Create(ExtractFileDir(application.ExeName) + '\sunset.jpg',fmOpenRead);
+try
+
+//insert the image into the db
+sldb.UpdateBlob('UPDATE testtable set picture = ? WHERE ID = ' + inttostr(iID),fs);
+
+finally
+fs.Free;
+end;
+
+finally
+sldb.Free;
+
+end;
+
+end;
+
+procedure TForm1.btnDisplayImageClick(Sender: TObject);
+var
+slDBpath: string;
+sldb: TSQLiteDatabase;
+sltb: TSQLIteTable;
+iID: integer;
+ms: TMemoryStream;
+pic: TJPegImage;
+
+begin
+
+slDBPath := ExtractFilepath(application.exename)
++ 'test.db';
+
+if not FileExists(slDBPath) then begin
+MessageDLg('Test.db does not exist. Click Test Sqlite 3 to create it, then Load image to load an image.',mtInformation,[mbOK],0);
+exit;
+end;
+
+sldb := TSQLiteDatabase.Create(slDBPath);
+try
+
+//get an ID
+//query the data
+sltb := slDb.GetTable('SELECT ID FROM testtable');
+try
+
+if not sltb.Count = 0 then begin
+MessageDLg('No rows in the test database. Click Test Sqlite 3 to insert a row, then Load image to load an image.',mtInformation,[mbOK],0);
+exit;
+end;
+
+iID := sltb.FieldAsInteger(sltb.FieldIndex['ID']);
+
+finally
+sltb.Free;
+end;
+
+sltb := sldb.GetTable('SELECT picture FROM testtable where ID = ' + inttostr(iID));
+try
+
+ms := sltb.FieldAsBlob(sltb.FieldIndex['picture']);
+//note that the memory stream is freed when the TSqliteTable is destroyed.
+
+if (ms = nil) then begin
+MessageDLg('No image in the test database. Click Load image to load an image.',mtInformation,[mbOK],0);
+exit;
+end;
+
+ms.Position := 0;
+
+pic := TJPEGImage.Create;
+pic.LoadFromStream(ms);
+
+self.Image1.Picture.Graphic := pic;
+
+pic.Free;
+
+finally
+sltb.Free;
+end;
+
+finally
+sldb.Free;
+
+end;
+
+
+end;
+
+end.
diff --git a/src/lib/SQLite/readme.txt b/src/lib/SQLite/readme.txt
new file mode 100644
index 00000000..7998d17f
--- /dev/null
+++ b/src/lib/SQLite/readme.txt
@@ -0,0 +1,93 @@
+5 June 2008
+Updated DLL to version 3.5.9 (built with MSVC 6.0)
+Added code from Andrew Retmanski to support prepared queries (see comments in SQLIteTable3.pas
+Lukas added support for named parameters - see comments in code
+User nebula enhanced error message; also modified code to call sqlite3_reset before checking error message
+
+
+27 Aug 2007
+Amended TSQLiteDatabase constructor to convert filename to UTF8,for compatibility with latest SQLite3 DLL.
+
+Updated DLL to version 3.4.2 (built with MSVC 6.0).
+
+14 Aug 2005
+
+The following changes were made by Lukas Gebauer (geby@volny.cz). In addition, some changes from a previous D5-compatible version were merged, and the supplied sqlite3.dll is updated to version 3.2.2
+
+Notes from Lukas:
+
+- added support for delphi 4+
+
+- datatype constants matches SQlite datatypes contants. (otherwise in some situations you got bad column datatype!)
+
+- removed dependency on strutils
+
+- code is reformatted to better look (official borland formatting rules)
+
+- added some pragma's after database is open (temp is in memory)
+
+- TSQLiteDatabase.GetTableValue(const SQL: string): int64 for easy call of SQL commands what returning one number only. (like select
+count(*)...)
+
+- TSQLiteDatabase.GetTableString(const SQL: string): String for easy call of SQL commands what returning one string only. (like PRAGMA
+integrity_check)
+
+- TSQLiteDatabase.SetTimeout(Value: integer); you can set timeout for accessing to some table. Good for database sharing!
+
+- TSQLiteDatabase.version: string; returns SQLITE version string
+
+- removed bool fieldtype (it is not natural SQLite3 type)
+
+- fild type detection by Sqite3_columnType knows REAL too.
+
+- integer filedtype is based on Int64
+
+- GetFields can get data from any supported fieldtype
+
+- changed some integers to cardinal for avoid signed and unsigned mismatch
+
+- TSqliteTable.FieldAsInteger(I: cardinal): int64; returns int64
+
+
+3 May 2005 Fixed bug where strupper called on column type before checking for nil
+
+2 May 2005 Add extra check for nil in TSqliteTable.Destroy, thanks to Tim Maddrell
+
+22 Apr 2005 Revise TSqliteTable.Destroy to fix memory leak with dtStr type (thanks to
+Jose Brito)
+
+21 Apr 2005 Quick revision to fix case sensitivity in detecting column type,
+and remove PRAGMA full_column_names = 1 which is deprecated. Warning: may break code. Fix your SQL code so that all column names in a result set are unique.
+
+21 Feb 2005 Sqlite DLL now 3.1.3 
+
+19 Feb 2005 Revised for Sqlite 3.1.2 
+
+21 Dec 2004 First public release 
+
+The following notice appears in the Sqlite source code:
+
+*
+** 2001 September 15
+**
+** 
+** The author disclaims copyright to this source code.  In place of
+
+** a legal notice, here is a blessing:
+
+**
+ May you do good and not evil.
+
+** May you find forgiveness for yourself and forgive others.
+
+** May you share freely, never taking more than you give.
+
+
+For more information about SQLite, see http://www.sqlite.org
+
+For more information about this simple wrapper, see http://www.itwriting.com/sqlitesimple.php
+
+
+
+
+
-- 
cgit v1.2.3