unit SQLite3Lib;
{ *******************************************************

  SQLite 3 Dynamic Library wrapper for Delphi

  2012 Ángel Fernández Pineda. Madrid. Spain.

  This work is licensed under the Creative Commons
  Attribution-ShareAlike 3.0 Unported License. To
  view a copy of this license,
  visit http://creativecommons.org/licenses/by-sa/3.0/
  or send a letter to Creative Commons,
  444 Castro Street, Suite 900,
  Mountain View, California, 94041, USA.

  *******************************************************

  Files: SQLite3Constants, SQLite3Lib

  *******************************************************

  This wrapper should include sqlite3.dll as a Windows
  Resource. If sqlite3.dll is not found, it will
  be extracted to a temporary folder, then loaded.
  So there is no need to distribute that DLL along
  with an aplication.  As a result, it may be used
  as a statically linked library.

  *******************************************************

  CHANGE LOG:

  - 2012-03-22: First implementation

  TO DO:

  - Some procedures are linked but not exported
  - 64bit implementation not tested

  ******************************************************* }

interface

function isAvailable: boolean;

type
  PSQLite3 = type Pointer;
  PSQLite3_backup = type Pointer;
  Psqlite3_blob = type Pointer;
  Psqlite3_context = type Pointer;
  Psqlite3_file = type Pointer;
  psqlite3_io_methods = type Pointer;
  Psqlite3_index_info = type Pointer;
  Psqlite3_int64 = type Pointer;
  Psqlite3_uint64 = type Pointer;
  Psqlite_int64 = type Pointer;
  Psqlite_uint64 = type Pointer;
  Psqlite3_mem_methods = type Pointer;
  Psqlite3_module = type Pointer;
  Psqlite3_mutex = type Pointer;
  Psqlite3_mutex_methods = type Pointer;
  Psqlite3_pcache = type Pointer;
  Psqlite3_pcache_methods2 = type Pointer;
  Psqlite3_pcache_page = type Pointer;
  Psqlite3_stmt = type Pointer;
  Psqlite3_temp_directory = type Pointer;
  Psqlite3_value = type Pointer;
  Psqlite3_vfs = type Pointer;
  Psqlite3_vtab = type Pointer;
  Psqlite3_vtab_cursor = type Pointer;

  PUTF8Char = PAnsiChar;
  PUTF8CharArray = array of PUTF8Char;
  TSQLite3Destructor = procedure(Data: Pointer); cdecl;
  TSQLiteExecCallback = function(UserData: Pointer; NumCols: integer;
    ColValues: PUTF8CharArray; ColNames: PUTF8CharArray): integer; cdecl;

  // Open and close
function sqlite3_open(const filename: UTF8String; out db: PSQLite3): integer;
function sqlite3_open16(const filename: UnicodeString;
  out db: PSQLite3): integer;
function sqlite3_open_v2(const filename: UTF8String; out db: PSQLite3;
  flags: integer; zVfs: PAnsiString): integer;
function sqlite3_close(db: PSQLite3): integer;

// Statements
function sqlite3_prepare(db: PSQLite3; const zSql: UTF8String; nByte: integer;
  out ppStmt: Psqlite3_stmt; out pzTail: PUTF8Char): integer;
function sqlite3_prepare_v2(db: PSQLite3; const zSql: UTF8String;
  nByte: integer; out ppStmt: Psqlite3_stmt; out pzTail: PUTF8Char): integer;
function sqlite3_prepare16(db: PSQLite3; const zSql: UnicodeString;
  nByte: integer; out ppStmt: Psqlite3_stmt;
  out pzTail: PUnicodeString): integer;
function sqlite3_prepare16_v2(db: PSQLite3; const zSql: UnicodeString;
  nByte: integer; out ppStmt: Psqlite3_stmt;
  out pzTail: PUnicodeString): integer;
function sqlite3_finalize(pStmt: Psqlite3_stmt): integer;
function sqlite3_step(pStmt: Psqlite3_stmt): integer;
function sqlite3_reset(pStmt: Psqlite3_stmt): integer;
function sqlite3_stmt_readonly(pStmt: Psqlite3_stmt): integer;

// Bindings
function sqlite3_bind_blob(pStmt: Psqlite3_stmt; index: integer; value: Pointer;
  nBytes: integer; pDestructor: TSQLite3Destructor): integer;
function sqlite3_bind_double(pStmt: Psqlite3_stmt; index: integer;
  value: double): integer;
function sqlite3_bind_int(pStmt: Psqlite3_stmt; index: integer;
  value: integer): integer;
function sqlite3_bind_int64(pStmt: Psqlite3_stmt; index: integer;
  value: int64): integer;
function sqlite3_bind_null(pStmt: Psqlite3_stmt; index: integer): integer;
function sqlite3_bind_text(pStmt: Psqlite3_stmt; index: integer;
  const value: AnsiString; nBytes: integer;
  pDestructor: TSQLite3Destructor): integer;
function sqlite3_bind_text16(pStmt: Psqlite3_stmt; index: integer;
  const value: UnicodeString; nBytes: integer;
  pDestructor: TSQLite3Destructor): integer;
function sqlite3_bind_value(pStmt: Psqlite3_stmt; index: integer;
  value: Psqlite3_value): integer;
function sqlite3_bind_zeroblob(pStmt: Psqlite3_stmt; index: integer;
  nBytes: integer): integer;
function sqlite3_clear_bindings(pStmt: Psqlite3_stmt): integer;

// Bindings metadata
function sqlite3_bind_parameter_count(pStmt: Psqlite3_stmt): integer;
function sqlite3_bind_parameter_index(pStmt: Psqlite3_stmt;
  const zName: UTF8String): integer;
function sqlite3_bind_parameter_name(pStmt: Psqlite3_stmt; index: integer)
  : PUTF8Char;

// Result sets
function sqlite3_column_blob(pStmt: Psqlite3_stmt; iCol: integer): Pointer;
function sqlite3_column_bytes(pStmt: Psqlite3_stmt; iCol: integer): integer;
function sqlite3_column_bytes16(pStmt: Psqlite3_stmt; iCol: integer): integer;
function sqlite3_column_double(pStmt: Psqlite3_stmt; iCol: integer): double;
function sqlite3_column_int(pStmt: Psqlite3_stmt; iCol: integer): integer;
function sqlite3_column_int64(pStmt: Psqlite3_stmt; iCol: integer): int64;
function sqlite3_column_text(pStmt: Psqlite3_stmt; iCol: integer): PUTF8Char;
function sqlite3_column_text16(pStmt: Psqlite3_stmt; iCol: integer): PWideChar;
function sqlite3_column_type(pStmt: Psqlite3_stmt; iCol: integer): integer;
function sqlite3_column_value(pStmt: Psqlite3_stmt; iCol: integer)
  : Psqlite3_value;
function sqlite3_column_count(pStmt: Psqlite3_stmt): integer;
function sqlite3_data_count(pStmt: Psqlite3_stmt): integer;

// Result sets metadata
function sqlite3_column_database_name(pStmt: Psqlite3_stmt; index: integer)
  : PUTF8Char;
function sqlite3_column_database_name16(pStmt: Psqlite3_stmt; index: integer)
  : PWideChar;
function sqlite3_column_table_name(pStmt: Psqlite3_stmt; index: integer)
  : PUTF8Char;
function sqlite3_column_table_name16(pStmt: Psqlite3_stmt; index: integer)
  : PWideChar;
function sqlite3_column_origin_name(pStmt: Psqlite3_stmt; index: integer)
  : PUTF8Char;
function sqlite3_column_origin_name16(pStmt: Psqlite3_stmt; index: integer)
  : PWideChar;
function sqlite3_column_decltype(pStmt: Psqlite3_stmt; index: integer)
  : PUTF8Char;
function sqlite3_column_decltype16(pStmt: Psqlite3_stmt; index: integer)
  : PUTF8Char;
function sqlite3_column_name(pStmt: Psqlite3_stmt; index: integer): PUTF8Char;
function sqlite3_column_name16(pStmt: Psqlite3_stmt; index: integer): PWideChar;

// Blobs
function sqlite3_blob_bytes(pBlob: Psqlite3_blob): integer;
function sqlite3_blob_close(pBlob: Psqlite3_blob): integer;
function sqlite3_blob_open(db: PSQLite3; const zDb: UTF8String;
  const zTable: UTF8String; const zColumn: UTF8String; iRow: int64;
  flags: integer; out ppBlob: Psqlite3_blob): integer;
function sqlite3_blob_read(pBlob: Psqlite3_blob; buffer: Pointer;
  nBytes: integer; iOffset: integer): integer;
function sqlite3_blob_reopen(pBlob: Psqlite3_blob; iRow: int64): integer;
function sqlite3_blob_write(pBlob: Psqlite3_blob; buffer: Pointer;
  nBytes: integer; iOffset: integer): integer;

// Run-Time Library Version Numbers
function sqlite3_libversion: PAnsiChar;
function sqlite3_sourceid: PAnsiChar;
function sqlite3_libversion_number: integer;

// Test To See If The Library Is Threadsafe
function sqlite3_threadsafe: integer;

// Test For Auto-Commit Mode
function sqlite3_get_autocommit(db: PSQLite3): integer;

// Error Codes And Messages
function sqlite3_errcode(db: PSQLite3): integer;
function sqlite3_extended_errcode(db: PSQLite3): integer;
function sqlite3_errmsg(db: PSQLite3): PUTF8Char;
function sqlite3_errmsg16(db: PSQLite3): PWideChar;

// Enable Or Disable Extended Result Codes
function sqlite3_extended_result_codes(db: PSQLite3; onoff: integer): integer;

// Affected rows
function sqlite3_changes(db: PSQLite3): integer;
function sqlite3_total_changes(db: PSQLite3): integer;

// One-Step Query Execution Interface
function sqlite3_exec(db: PSQLite3; const sql: UTF8String;
  callback: TSQLiteExecCallback; UserData: Pointer;
  var errmsg: PUTF8Char): integer;

// Memory Allocation Subsystem
function sqlite3_malloc(nBytes: integer): Pointer;
function sqlite3_realloc(buffer: Pointer; nBytes: integer): Pointer;
procedure sqlite3_free(buffer: Pointer);

// Run-time Limits
function sqlite3_limit(db: PSQLite3; id: integer; newVal: integer): integer;

// Extract Metadata About A Column Of A Table
function sqlite3_table_column_metadata(db: PSQLite3; const zDbName: UTF8String;
  const zTableName: UTF8String; const zColumnName: UTF8String;
  out pzDataType: PUTF8Char; out pzCollSeq: PUTF8Char; out pNotNull: integer;
  out pPrimaryKey: integer; out pAutoinc: integer): integer;

// Last Insert Rowid
function sqlite3_last_insert_rowid(db: PSQLite3): int64;


function sqlite3_db_readonly(db : PSQlite3; const zDBName : string) : integer;

implementation

{$IFDEF WIN64}
{$R SQLite3Dll64.RES}
{$ELSE}
{$R SQLite3Dll32.RES}
{$ENDIF}

uses WinApi.Windows, Classes, System.SysUtils, IOUtils, UnitMisc, Dialogs
  ;

const
  SQLITERESID = 'SQLITE3DLL';
  EXCPT_MSG = 'SQLite3 function not implemented';

var
  // Global library variables
  TempDLLFile: string = '';
  dllHandler: THandle = 0;

type
  // Dynamically linked prototypes
  Tsqlite3_open = function(const filename: UTF8String; sqlite3: PSQLite3)
    : integer; cdecl;
  Tsqlite3_open16 = function(const filename: UnicodeString;
    out sqlite3: PSQLite3): integer; cdecl;
  Tsqlite3_open_v2 = function(const filename: UTF8String; out sqlite3: PSQLite3;
    flags: integer; zVfs: PAnsiString): integer; cdecl;
  Tsqlite3_close = function(sqlite3: PSQLite3): integer; cdecl;

  Tsqlite3_prepare = function(db: PSQLite3; const zSql: UTF8String;
    nByte: integer; out ppStmt: Psqlite3_stmt; out pzTail: PUTF8Char)
    : integer; cdecl;
  Tsqlite3_prepare_v2 = function(db: PSQLite3; const zSql: UTF8String;
    nByte: integer; out ppStmt: Psqlite3_stmt; out pzTail: PUTF8Char)
    : integer; cdecl;
  Tsqlite3_prepare16 = function(db: PSQLite3; const zSql: UnicodeString;
    nByte: integer; out ppStmt: Psqlite3_stmt; out pzTail: PUnicodeString)
    : integer; cdecl;
  Tsqlite3_prepare16_v2 = function(db: PSQLite3; const zSql: UnicodeString;
    nByte: integer; out ppStmt: Psqlite3_stmt; out pzTail: PUnicodeString)
    : integer; cdecl;
  Tsqlite3_finalize = function(pStmt: Psqlite3_stmt): integer; cdecl;
  Tsqlite3_step = function(pStmt: Psqlite3_stmt): integer; cdecl;
  Tsqlite3_reset = function(pStmt: Psqlite3_stmt): integer; cdecl;
  Tsqlite3_stmt_readonly = function(pStmt: Psqlite3_stmt): integer; cdecl;

  Tsqlite3_bind_blob = function(pStmt: Psqlite3_stmt; index: integer;
    value: Pointer; nBytes: integer; pDestructor: TSQLite3Destructor)
    : integer; cdecl;
  Tsqlite3_bind_double = function(pStmt: Psqlite3_stmt; index: integer;
    value: double): integer; cdecl;
  Tsqlite3_bind_int = function(pStmt: Psqlite3_stmt; index: integer;
    value: integer): integer; cdecl;
  Tsqlite3_bind_int64 = function(pStmt: Psqlite3_stmt; index: integer;
    value: int64): integer; cdecl;
  Tsqlite3_bind_null = function(pStmt: Psqlite3_stmt; index: integer)
    : integer; cdecl;
  Tsqlite3_bind_text = function(pStmt: Psqlite3_stmt; index: integer;
    const value: AnsiString; nBytes: integer; pDestructor: TSQLite3Destructor)
    : integer; cdecl;
  Tsqlite3_bind_text16 = function(pStmt: Psqlite3_stmt; index: integer;
    const value: UnicodeString; nBytes: integer;
    pDestructor: TSQLite3Destructor): integer; cdecl;
  Tsqlite3_bind_value = function(pStmt: Psqlite3_stmt; index: integer;
    value: Psqlite3_value): integer; cdecl;
  Tsqlite3_bind_zeroblob = function(pStmt: Psqlite3_stmt; index: integer;
    nBytes: integer): integer; cdecl;
  Tsqlite3_clear_bindings = function(pStmt: Psqlite3_stmt): integer; cdecl;

  Tsqlite3_bind_parameter_count = function(pStmt: Psqlite3_stmt)
    : integer; cdecl;
  Tsqlite3_bind_parameter_index = function(pStmt: Psqlite3_stmt;
    const zName: UTF8String): integer; cdecl;
  Tsqlite3_bind_parameter_name = function(pStmt: Psqlite3_stmt; index: integer)
    : PUTF8Char; cdecl;

  Tsqlite3_column_blob = function(pStmt: Psqlite3_stmt; iCol: integer)
    : Pointer; cdecl;
  Tsqlite3_column_bytes = function(pStmt: Psqlite3_stmt; iCol: integer)
    : integer; cdecl;
  Tsqlite3_column_bytes16 = function(pStmt: Psqlite3_stmt; iCol: integer)
    : integer; cdecl;
  Tsqlite3_column_double = function(pStmt: Psqlite3_stmt;
    iCol: integer): double;
  Tsqlite3_column_int = function(pStmt: Psqlite3_stmt; iCol: integer)
    : integer; cdecl;
  Tsqlite3_column_int64 = function(pStmt: Psqlite3_stmt; iCol: integer)
    : int64; cdecl;
  Tsqlite3_column_text = function(pStmt: Psqlite3_stmt; iCol: integer)
    : PUTF8Char; cdecl;
  Tsqlite3_column_text16 = function(pStmt: Psqlite3_stmt; iCol: integer)
    : PWideChar; cdecl;
  Tsqlite3_column_type = function(pStmt: Psqlite3_stmt; iCol: integer)
    : integer; cdecl;
  Tsqlite3_column_value = function(pStmt: Psqlite3_stmt; iCol: integer)
    : Psqlite3_value; cdecl;
  Tsqlite3_column_count = function(pStmt: Psqlite3_stmt): integer; cdecl;
  Tsqlite3_data_count = function(pStmt: Psqlite3_stmt): integer; cdecl;
  Tsqlite3_column_database_name = function(pStmt: Psqlite3_stmt; index: integer)
    : PUTF8Char; cdecl;
  Tsqlite3_column_database_name16 = function(pStmt: Psqlite3_stmt;
    index: integer): PWideChar; cdecl;
  Tsqlite3_column_table_name = function(pStmt: Psqlite3_stmt; index: integer)
    : PUTF8Char; cdecl;
  Tsqlite3_column_table_name16 = function(pStmt: Psqlite3_stmt; index: integer)
    : PWideChar; cdecl;
  Tsqlite3_column_origin_name = function(pStmt: Psqlite3_stmt; index: integer)
    : PUTF8Char; cdecl;
  Tsqlite3_column_origin_name16 = function(pStmt: Psqlite3_stmt; index: integer)
    : PWideChar;
  Tsqlite3_column_decltype = function(pStmt: Psqlite3_stmt; index: integer)
    : PUTF8Char; cdecl;
  Tsqlite3_column_decltype16 = function(pStmt: Psqlite3_stmt; index: integer)
    : PUTF8Char; cdecl;
  Tsqlite3_column_name = function(pStmt: Psqlite3_stmt; index: integer)
    : PUTF8Char; cdecl;
  Tsqlite3_column_name16 = function(pStmt: Psqlite3_stmt; index: integer)
    : PWideChar; cdecl;

  Tsqlite3_blob_bytes = function(pBlob: Psqlite3_blob): integer; cdecl;
  Tsqlite3_blob_close = function(pBlob: Psqlite3_blob): integer; cdecl;
  Tsqlite3_blob_open = function(db: PSQLite3; const zDb: UTF8String;
    const zTable: UTF8String; const zColumn: UTF8String; iRow: int64;
    flags: integer; out ppBlob: Psqlite3_blob): integer; cdecl;
  Tsqlite3_blob_read = function(pBlob: Psqlite3_blob; buffer: Pointer;
    nBytes: integer; iOffset: integer): integer; cdecl;
  Tsqlite3_blob_reopen = function(pBlob: Psqlite3_blob; iRow: int64)
    : integer; cdecl;
  Tsqlite3_blob_write = function(pBlob: Psqlite3_blob; buffer: Pointer;
    nBytes: integer; iOffset: integer): integer; cdecl;

  Tsqlite3_libversion = function: PAnsiChar; cdecl;
  Tsqlite3_sourceid = function: PAnsiChar; cdecl;
  Tsqlite3_libversion_number = function: integer; cdecl;

  Tsqlite3_threadsafe = function: integer; cdecl;

  Tsqlite3_get_autocommit = function(db: PSQLite3): integer; cdecl;

  Tsqlite3_errcode = function(db: PSQLite3): integer; cdecl;
  Tsqlite3_extended_errcode = function(db: PSQLite3): integer; cdecl;
  Tsqlite3_errmsg = function(db: PSQLite3): PUTF8Char; cdecl;
  Tsqlite3_errmsg16 = function(db: PSQLite3): PWideChar; cdecl;

  Tsqlite3_extended_result_codes = function(db: PSQLite3; onoff: integer)
    : integer; cdecl;

  Tsqlite3_changes = function(db: PSQLite3): integer; cdecl;
  Tsqlite3_total_changes = function(db: PSQLite3): integer; cdecl;

  Tsqlite3_exec = function(db: PSQLite3; const sql: UTF8String;
    callback: TSQLiteExecCallback; UserData: Pointer; var errmsg: PUTF8Char)
    : integer; cdecl;

  Tsqlite3_malloc = function(nBytes: integer): Pointer; cdecl;
  Tsqlite3_realloc = function(buffer: Pointer; nBytes: integer): Pointer; cdecl;
  Tsqlite3_free = procedure(buffer: Pointer); cdecl;

  Tsqlite3_limit = function(db: PSQLite3; id: integer; newVal: integer)
    : integer; cdecl;

  Tsqlite3_table_column_metadata = function(db: PSQLite3;
    const zDbName: UTF8String; const zTableName: UTF8String;
    const zColumnName: UTF8String; out pzDataType: PUTF8Char;
    out pzCollSeq: PUTF8Char; out pNotNull: integer; out pPrimaryKey: integer;
    out pAutoinc: integer): integer; cdecl;

  Tsqlite3_last_insert_rowid = function(db: PSQLite3): int64;



    Tsqlite3_db_readonly = function(db : PSQlite3; const zDbName : UTF8String) : integer; cdecl;
var
  // Dinamically linked procedures
  psqlite3_aggregate_context: FARPROC = nil;
  psqlite3_auto_extension: FARPROC = nil;
  psqlite3_backup_finish: FARPROC = nil;
  psqlite3_backup_init: FARPROC = nil;
  psqlite3_backup_pagecount: FARPROC = nil;
  psqlite3_backup_remaining: FARPROC = nil;
  psqlite3_backup_step: FARPROC = nil;
  psqlite3_bind_blob: FARPROC = nil;
  psqlite3_bind_double: FARPROC = nil;
  psqlite3_bind_int: FARPROC = nil;
  psqlite3_bind_int64: FARPROC = nil;
  psqlite3_bind_null: FARPROC = nil;
  psqlite3_bind_parameter_count: FARPROC = nil;
  psqlite3_bind_parameter_index: FARPROC = nil;
  psqlite3_bind_parameter_name: FARPROC = nil;
  psqlite3_bind_text: FARPROC = nil;
  psqlite3_bind_text16: FARPROC = nil;
  psqlite3_bind_value: FARPROC = nil;
  psqlite3_bind_zeroblob: FARPROC = nil;
  psqlite3_blob_bytes: FARPROC = nil;
  psqlite3_blob_close: FARPROC = nil;
  psqlite3_blob_open: FARPROC = nil;
  psqlite3_blob_read: FARPROC = nil;
  psqlite3_blob_reopen: FARPROC = nil;
  psqlite3_blob_write: FARPROC = nil;
  psqlite3_busy_handler: FARPROC = nil;
  psqlite3_busy_timeout: FARPROC = nil;
  psqlite3_changes: FARPROC = nil;
  psqlite3_clear_bindings: FARPROC = nil;
  psqlite3_close: FARPROC = nil;
  psqlite3_collation_needed: FARPROC = nil;
  psqlite3_collation_needed16: FARPROC = nil;
  psqlite3_column_blob: FARPROC = nil;
  psqlite3_column_bytes: FARPROC = nil;
  psqlite3_column_bytes16: FARPROC = nil;
  psqlite3_column_count: FARPROC = nil;
  psqlite3_column_database_name: FARPROC = nil;
  psqlite3_column_database_name16: FARPROC = nil;
  psqlite3_column_decltype: FARPROC = nil;
  psqlite3_column_decltype16: FARPROC = nil;
  psqlite3_column_double: FARPROC = nil;
  psqlite3_column_int: FARPROC = nil;
  psqlite3_column_int64: FARPROC = nil;
  psqlite3_column_name: FARPROC = nil;
  psqlite3_column_name16: FARPROC = nil;
  psqlite3_column_origin_name: FARPROC = nil;
  psqlite3_column_origin_name16: FARPROC = nil;
  psqlite3_column_table_name: FARPROC = nil;
  psqlite3_column_table_name16: FARPROC = nil;
  psqlite3_column_text: FARPROC = nil;
  psqlite3_column_text16: FARPROC = nil;
  psqlite3_column_type: FARPROC = nil;
  psqlite3_column_value: FARPROC = nil;
  psqlite3_commit_hook: FARPROC = nil;
  psqlite3_compileoption_get: FARPROC = nil;
  psqlite3_compileoption_used: FARPROC = nil;
  psqlite3_complete: FARPROC = nil;
  psqlite3_complete16: FARPROC = nil;
  psqlite3_config: FARPROC = nil;
  psqlite3_context_db_handle: FARPROC = nil;
  psqlite3_create_collation: FARPROC = nil;
  psqlite3_create_collation16: FARPROC = nil;
  psqlite3_create_collation_v2: FARPROC = nil;
  psqlite3_create_function: FARPROC = nil;
  psqlite3_create_function16: FARPROC = nil;
  psqlite3_create_function_v2: FARPROC = nil;
  psqlite3_create_module: FARPROC = nil;
  psqlite3_create_module_v2: FARPROC = nil;
  psqlite3_data_count: FARPROC = nil;
  psqlite3_db_config: FARPROC = nil;
  psqlite3_db_filename: FARPROC = nil;
  psqlite3_db_handle: FARPROC = nil;
  psqlite3_db_mutex: FARPROC = nil;
  psqlite3_db_readonly: FARPROC = nil;
  psqlite3_db_release_memory: FARPROC = nil;
  psqlite3_db_status: FARPROC = nil;
  psqlite3_declare_vtab: FARPROC = nil;
  psqlite3_enable_load_extension: FARPROC = nil;
  psqlite3_enable_shared_cache: FARPROC = nil;
  psqlite3_errcode: FARPROC = nil;
  psqlite3_errmsg: FARPROC = nil;
  psqlite3_errmsg16: FARPROC = nil;
  psqlite3_exec: FARPROC = nil;
  psqlite3_extended_errcode: FARPROC = nil;
  psqlite3_extended_result_codes: FARPROC = nil;
  psqlite3_file_control: FARPROC = nil;
  psqlite3_finalize: FARPROC = nil;
  psqlite3_free: FARPROC = nil;
  psqlite3_free_table: FARPROC = nil;
  psqlite3_get_autocommit: FARPROC = nil;
  psqlite3_get_auxdata: FARPROC = nil;
  psqlite3_get_table: FARPROC = nil;
  psqlite3_initialize: FARPROC = nil;
  psqlite3_interrupt: FARPROC = nil;
  psqlite3_last_insert_rowid: FARPROC = nil;
  psqlite3_libversion: FARPROC = nil;
  psqlite3_libversion_number: FARPROC = nil;
  psqlite3_limit: FARPROC = nil;
  psqlite3_load_extension: FARPROC = nil;
  psqlite3_log: FARPROC = nil;
  psqlite3_malloc: FARPROC = nil;
  psqlite3_memory_highwater: FARPROC = nil;
  psqlite3_memory_used: FARPROC = nil;
  psqlite3_mprintf: FARPROC = nil;
  psqlite3_mutex_alloc: FARPROC = nil;
  psqlite3_mutex_enter: FARPROC = nil;
  psqlite3_mutex_free: FARPROC = nil;
  psqlite3_mutex_held: FARPROC = nil;
  psqlite3_mutex_leave: FARPROC = nil;
  psqlite3_mutex_notheld: FARPROC = nil;
  psqlite3_mutex_try: FARPROC = nil;
  psqlite3_next_stmt: FARPROC = nil;
  psqlite3_open: FARPROC = nil;
  psqlite3_open16: FARPROC = nil;
  psqlite3_open_v2: FARPROC = nil;
  psqlite3_os_end: FARPROC = nil;
  psqlite3_os_init: FARPROC = nil;
  psqlite3_overload_function: FARPROC = nil;
  psqlite3_prepare: FARPROC = nil;
  psqlite3_prepare16: FARPROC = nil;
  psqlite3_prepare16_v2: FARPROC = nil;
  psqlite3_prepare_v2: FARPROC = nil;
  psqlite3_profile: FARPROC = nil;
  psqlite3_progress_handler: FARPROC = nil;
  psqlite3_randomness: FARPROC = nil;
  psqlite3_realloc: FARPROC = nil;
  psqlite3_release_memory: FARPROC = nil;
  psqlite3_reset: FARPROC = nil;
  psqlite3_reset_auto_extension: FARPROC = nil;
  psqlite3_result_blob: FARPROC = nil;
  psqlite3_result_double: FARPROC = nil;
  psqlite3_result_error: FARPROC = nil;
  psqlite3_result_error16: FARPROC = nil;
  psqlite3_result_error_code: FARPROC = nil;
  psqlite3_result_error_nomem: FARPROC = nil;
  psqlite3_result_error_toobig: FARPROC = nil;
  psqlite3_result_int: FARPROC = nil;
  psqlite3_result_int64: FARPROC = nil;
  psqlite3_result_null: FARPROC = nil;
  psqlite3_result_text: FARPROC = nil;
  psqlite3_result_text16: FARPROC = nil;
  psqlite3_result_text16be: FARPROC = nil;
  psqlite3_result_text16le: FARPROC = nil;
  psqlite3_result_value: FARPROC = nil;
  psqlite3_result_zeroblob: FARPROC = nil;
  psqlite3_rollback_hook: FARPROC = nil;
  psqlite3_set_authorizer: FARPROC = nil;
  psqlite3_set_auxdata: FARPROC = nil;
  psqlite3_shutdown: FARPROC = nil;
  psqlite3_sleep: FARPROC = nil;
  psqlite3_snprintf: FARPROC = nil;
  psqlite3_soft_heap_limit64: FARPROC = nil;
  psqlite3_sourceid: FARPROC = nil;
  psqlite3_sql: FARPROC = nil;
  psqlite3_status: FARPROC = nil;
  psqlite3_step: FARPROC = nil;
  psqlite3_stmt_busy: FARPROC = nil;
  psqlite3_stmt_readonly: FARPROC = nil;
  psqlite3_stmt_status: FARPROC = nil;
  psqlite3_stricmp: FARPROC = nil;
  psqlite3_strnicmp: FARPROC = nil;
  psqlite3_table_column_metadata: FARPROC = nil;
  psqlite3_test_control: FARPROC = nil;
  psqlite3_threadsafe: FARPROC = nil;
  psqlite3_total_changes: FARPROC = nil;
  psqlite3_trace: FARPROC = nil;
  psqlite3_unlock_notify: FARPROC = nil;
  psqlite3_update_hook: FARPROC = nil;
  psqlite3_uri_boolean: FARPROC = nil;
  psqlite3_uri_int64: FARPROC = nil;
  psqlite3_uri_parameter: FARPROC = nil;
  psqlite3_user_data: FARPROC = nil;
  psqlite3_value_blob: FARPROC = nil;
  psqlite3_value_bytes: FARPROC = nil;
  psqlite3_value_bytes16: FARPROC = nil;
  psqlite3_value_double: FARPROC = nil;
  psqlite3_value_int: FARPROC = nil;
  psqlite3_value_int64: FARPROC = nil;
  psqlite3_value_numeric_type: FARPROC = nil;
  psqlite3_value_text: FARPROC = nil;
  psqlite3_value_text16: FARPROC = nil;
  psqlite3_value_text16be: FARPROC = nil;
  psqlite3_value_text16le: FARPROC = nil;
  psqlite3_value_type: FARPROC = nil;
  psqlite3_version: FARPROC = nil;
  psqlite3_vfs_find: FARPROC = nil;
  psqlite3_vfs_register: FARPROC = nil;
  psqlite3_vfs_unregister: FARPROC = nil;
  psqlite3_vmprintf: FARPROC = nil;
  psqlite3_vsnprintf: FARPROC = nil;
  psqlite3_vtab_config: FARPROC = nil;
  psqlite3_vtab_on_conflict: FARPROC = nil;
  psqlite3_wal_autocheckpoint: FARPROC = nil;
  psqlite3_wal_checkpoint: FARPROC = nil;
  psqlite3_wal_checkpoint_v2: FARPROC = nil;
  psqlite3_wal_hook: FARPROC = nil;

  // ------------------------------------
  // Delphi Implementation
  // ------------------------------------

function isAvailable: boolean;
begin
  Result := (dllHandler <> 0);
end;

// Open/close

function sqlite3_open(const filename: UTF8String; out db: PSQLite3): integer;
begin
  if assigned(psqlite3_open) then
    Result := Tsqlite3_open(psqlite3_open)(filename, db)
  else
    raise ENotImplemented.Create(EXCPT_MSG);
end;

function sqlite3_open16(const filename: UnicodeString;
  out db: PSQLite3): integer;
begin
  if assigned(psqlite3_open16) then
    Result := Tsqlite3_open16(psqlite3_open16)(filename, db)
  else
    raise ENotImplemented.Create(EXCPT_MSG);
end;

function sqlite3_open_v2(const filename: UTF8String; out db: PSQLite3;
  flags: integer; zVfs: PAnsiString): integer;
begin
  if assigned(psqlite3_open_v2) then
    Result := Tsqlite3_open_v2(psqlite3_open_v2)(filename, db, flags, zVfs)
  else
    raise ENotImplemented.Create(EXCPT_MSG);
end;

function sqlite3_close(db: PSQLite3): integer;
begin
  if assigned(psqlite3_close) then
    Result := Tsqlite3_close(psqlite3_close)(db)
  else
    raise ENotImplemented.Create(EXCPT_MSG);
end;

// Statements

function sqlite3_prepare(db: PSQLite3; const zSql: UTF8String; nByte: integer;
  out ppStmt: Psqlite3_stmt; out pzTail: PUTF8Char): integer;
begin
  if assigned(psqlite3_prepare) then
    Result := Tsqlite3_prepare(psqlite3_prepare)
      (db, zSql, nByte, ppStmt, pzTail)
  else
    raise ENotImplemented.Create(EXCPT_MSG);
end;

function sqlite3_prepare_v2(db: PSQLite3; const zSql: UTF8String;
  nByte: integer; out ppStmt: Psqlite3_stmt; out pzTail: PUTF8Char): integer;
begin
  if assigned(psqlite3_prepare_v2) then
    Result := Tsqlite3_prepare_v2(psqlite3_prepare_v2)
      (db, zSql, nByte, ppStmt, pzTail)
  else
    raise ENotImplemented.Create(EXCPT_MSG);
end;

function sqlite3_prepare16(db: PSQLite3; const zSql: UnicodeString;
  nByte: integer; out ppStmt: Psqlite3_stmt;
  out pzTail: PUnicodeString): integer;
begin
  if assigned(psqlite3_prepare16) then
    Result := Tsqlite3_prepare16(psqlite3_prepare16)
      (db, zSql, nByte, ppStmt, pzTail)
  else
    raise ENotImplemented.Create(EXCPT_MSG);
end;

function sqlite3_prepare16_v2(db: PSQLite3; const zSql: UnicodeString;
  nByte: integer; out ppStmt: Psqlite3_stmt;
  out pzTail: PUnicodeString): integer;
begin
  if assigned(psqlite3_prepare16_v2) then
    Result := Tsqlite3_prepare16_v2(psqlite3_prepare16_v2)
      (db, zSql, nByte, ppStmt, pzTail)
  else
    raise ENotImplemented.Create(EXCPT_MSG);
end;

function sqlite3_finalize(pStmt: Psqlite3_stmt): integer;
begin
  if assigned(psqlite3_finalize) then
    Result := Tsqlite3_finalize(psqlite3_finalize)(pStmt)
  else
    raise ENotImplemented.Create(EXCPT_MSG);
end;

function sqlite3_step(pStmt: Psqlite3_stmt): integer;
begin
  if assigned(psqlite3_step) then
    Result := Tsqlite3_step(psqlite3_step)(pStmt)
  else
    raise ENotImplemented.Create(EXCPT_MSG);
end;

function sqlite3_reset(pStmt: Psqlite3_stmt): integer;
begin
  if assigned(psqlite3_reset) then
    Result := Tsqlite3_reset(psqlite3_reset)(pStmt)
  else
    raise ENotImplemented.Create(EXCPT_MSG);
end;

function sqlite3_stmt_readonly(pStmt: Psqlite3_stmt): integer;
begin
  if assigned(psqlite3_stmt_readonly) then
    Result := Tsqlite3_stmt_readonly(psqlite3_stmt_readonly)(pStmt)
  else
    raise ENotImplemented.Create(EXCPT_MSG);
end;

// Bindings

function sqlite3_bind_blob(pStmt: Psqlite3_stmt; index: integer; value: Pointer;
  nBytes: integer; pDestructor: TSQLite3Destructor): integer;
begin
  if assigned(psqlite3_bind_blob) then
    Result := Tsqlite3_bind_blob(psqlite3_bind_blob)(pStmt, index, value,
      nBytes, pDestructor)
  else
    raise ENotImplemented.Create(EXCPT_MSG);
end;

function sqlite3_bind_double(pStmt: Psqlite3_stmt; index: integer;
  value: double): integer;
begin
  if assigned(psqlite3_bind_double) then
    Result := Tsqlite3_bind_double(psqlite3_bind_double)(pStmt, index, value)
  else
    raise ENotImplemented.Create(EXCPT_MSG);
end;

function sqlite3_bind_int(pStmt: Psqlite3_stmt; index: integer;
  value: integer): integer;
begin
  if assigned(psqlite3_bind_int) then
    Result := Tsqlite3_bind_int(psqlite3_bind_int)(pStmt, index, value)
  else
    raise ENotImplemented.Create(EXCPT_MSG);
end;

function sqlite3_bind_int64(pStmt: Psqlite3_stmt; index: integer;
  value: int64): integer;
begin
  if assigned(psqlite3_bind_int64) then
    Result := Tsqlite3_bind_int64(psqlite3_bind_int64)(pStmt, index, value)
  else
    raise ENotImplemented.Create(EXCPT_MSG);
end;

function sqlite3_bind_null(pStmt: Psqlite3_stmt; index: integer): integer;
begin
  if assigned(psqlite3_bind_null) then
    Result := Tsqlite3_bind_null(psqlite3_bind_null)(pStmt, index)
  else
    raise ENotImplemented.Create(EXCPT_MSG);
end;

function sqlite3_bind_text(pStmt: Psqlite3_stmt; index: integer;
  const value: AnsiString; nBytes: integer;
  pDestructor: TSQLite3Destructor): integer;
begin
  if assigned(psqlite3_bind_text) then
    Result := Tsqlite3_bind_text(psqlite3_bind_text)(pStmt, index, value,
      nBytes, pDestructor)
  else
    raise ENotImplemented.Create(EXCPT_MSG);
end;

function sqlite3_bind_text16(pStmt: Psqlite3_stmt; index: integer;
  const value: UnicodeString; nBytes: integer;
  pDestructor: TSQLite3Destructor): integer;
begin
  if assigned(psqlite3_bind_text16) then
    Result := Tsqlite3_bind_text16(psqlite3_bind_text16)
      (pStmt, index, value, nBytes, pDestructor)
  else
    raise ENotImplemented.Create(EXCPT_MSG);
end;

function sqlite3_bind_value(pStmt: Psqlite3_stmt; index: integer;
  value: Psqlite3_value): integer;
begin
  if assigned(psqlite3_bind_value) then
    Result := Tsqlite3_bind_value(psqlite3_bind_value)(pStmt, index, value)
  else
    raise ENotImplemented.Create(EXCPT_MSG);
end;

function sqlite3_bind_zeroblob(pStmt: Psqlite3_stmt; index: integer;
  nBytes: integer): integer;
begin
  if assigned(psqlite3_bind_zeroblob) then
    Result := Tsqlite3_bind_zeroblob(psqlite3_bind_zeroblob)
      (pStmt, index, nBytes)
  else
    raise ENotImplemented.Create(EXCPT_MSG);
end;

function sqlite3_clear_bindings(pStmt: Psqlite3_stmt): integer;
begin
  if assigned(psqlite3_clear_bindings) then
    Result := Tsqlite3_clear_bindings(psqlite3_clear_bindings)(pStmt)
  else
    raise ENotImplemented.Create(EXCPT_MSG);
end;

// Bindings metadata

function sqlite3_bind_parameter_count(pStmt: Psqlite3_stmt): integer;
begin
  if assigned(psqlite3_bind_parameter_count) then
    Result := Tsqlite3_bind_parameter_count
      (psqlite3_bind_parameter_count)(pStmt)
  else
    raise ENotImplemented.Create(EXCPT_MSG);
end;

function sqlite3_bind_parameter_index(pStmt: Psqlite3_stmt;
  const zName: UTF8String): integer;
begin
  if assigned(psqlite3_bind_parameter_index) then
    Result := Tsqlite3_bind_parameter_index(psqlite3_bind_parameter_index)
      (pStmt, zName)
  else
    raise ENotImplemented.Create(EXCPT_MSG);
end;

function sqlite3_bind_parameter_name(pStmt: Psqlite3_stmt; index: integer)
  : PUTF8Char;
begin
  if assigned(psqlite3_bind_parameter_name) then
    Result := Tsqlite3_bind_parameter_name(psqlite3_bind_parameter_name)
      (pStmt, index)
  else
    raise ENotImplemented.Create(EXCPT_MSG);
end;


// Result sets

function sqlite3_column_blob(pStmt: Psqlite3_stmt; iCol: integer): Pointer;
begin
  if assigned(psqlite3_column_blob) then
    Result := Tsqlite3_column_blob(psqlite3_column_blob)(pStmt, iCol)
  else
    raise ENotImplemented.Create(EXCPT_MSG);
end;

function sqlite3_column_bytes(pStmt: Psqlite3_stmt; iCol: integer): integer;
begin
  if assigned(psqlite3_column_bytes) then
    Result := Tsqlite3_column_bytes(psqlite3_column_bytes)(pStmt, iCol)
  else
    raise ENotImplemented.Create(EXCPT_MSG);
end;

function sqlite3_column_bytes16(pStmt: Psqlite3_stmt; iCol: integer): integer;
begin
  if assigned(psqlite3_column_bytes16) then
    Result := Tsqlite3_column_bytes16(psqlite3_column_bytes16)(pStmt, iCol)
  else
    raise ENotImplemented.Create(EXCPT_MSG);
end;

function sqlite3_column_double(pStmt: Psqlite3_stmt; iCol: integer): double;
begin
  if assigned(psqlite3_column_double) then
    Result := Tsqlite3_column_double(psqlite3_column_double)(pStmt, iCol)
  else
    raise ENotImplemented.Create(EXCPT_MSG);
end;

function sqlite3_column_int(pStmt: Psqlite3_stmt; iCol: integer): integer;
begin
  if assigned(psqlite3_column_int) then
    Result := Tsqlite3_column_int(psqlite3_column_int)(pStmt, iCol)
  else
    raise ENotImplemented.Create(EXCPT_MSG);
end;

function sqlite3_column_int64(pStmt: Psqlite3_stmt; iCol: integer): int64;
begin
  if assigned(psqlite3_column_int64) then
    Result := Tsqlite3_column_int64(psqlite3_column_int64)(pStmt, iCol)
  else
    raise ENotImplemented.Create(EXCPT_MSG);
end;

function sqlite3_column_text(pStmt: Psqlite3_stmt; iCol: integer): PUTF8Char;
begin
  if assigned(psqlite3_column_text) then
    Result := Tsqlite3_column_text(psqlite3_column_text)(pStmt, iCol)
  else
    raise ENotImplemented.Create(EXCPT_MSG);
end;

function sqlite3_column_text16(pStmt: Psqlite3_stmt; iCol: integer): PWideChar;
begin
  if assigned(psqlite3_column_text16) then
    Result := Tsqlite3_column_text16(psqlite3_column_text16)(pStmt, iCol)
  else
    raise ENotImplemented.Create(EXCPT_MSG);
end;

function sqlite3_column_type(pStmt: Psqlite3_stmt; iCol: integer): integer;
begin
  if assigned(psqlite3_column_type) then
    Result := Tsqlite3_column_type(psqlite3_column_type)(pStmt, iCol)
  else
    raise ENotImplemented.Create(EXCPT_MSG);
end;

function sqlite3_column_value(pStmt: Psqlite3_stmt; iCol: integer)
  : Psqlite3_value;
begin
  if assigned(psqlite3_column_value) then
    Result := Tsqlite3_column_value(psqlite3_column_value)(pStmt, iCol)
  else
    raise ENotImplemented.Create(EXCPT_MSG);
end;

function sqlite3_column_count(pStmt: Psqlite3_stmt): integer;
begin
  if assigned(psqlite3_column_count) then
    Result := Tsqlite3_column_count(psqlite3_column_count)(pStmt)
  else
    raise ENotImplemented.Create(EXCPT_MSG);
end;

function sqlite3_data_count(pStmt: Psqlite3_stmt): integer;
begin
  if assigned(psqlite3_data_count) then
    Result := Tsqlite3_data_count(psqlite3_data_count)(pStmt)
  else
    raise ENotImplemented.Create(EXCPT_MSG);
end;

// Result sets metadata

function sqlite3_column_database_name(pStmt: Psqlite3_stmt; index: integer)
  : PUTF8Char;
begin
  if assigned(psqlite3_column_database_name) then
    Result := Tsqlite3_column_database_name(psqlite3_column_database_name)
      (pStmt, index)
  else
    raise ENotImplemented.Create(EXCPT_MSG);
end;

function sqlite3_column_database_name16(pStmt: Psqlite3_stmt; index: integer)
  : PWideChar;
begin
  if assigned(psqlite3_column_database_name16) then
    Result := Tsqlite3_column_database_name16(psqlite3_column_database_name16)
      (pStmt, index)
  else
    raise ENotImplemented.Create(EXCPT_MSG);
end;

function sqlite3_column_table_name(pStmt: Psqlite3_stmt; index: integer)
  : PUTF8Char;
begin
  if assigned(psqlite3_column_table_name) then
    Result := Tsqlite3_column_table_name(psqlite3_column_table_name)
      (pStmt, index)
  else
    raise ENotImplemented.Create(EXCPT_MSG);
end;

function sqlite3_column_table_name16(pStmt: Psqlite3_stmt; index: integer)
  : PWideChar;
begin
  if assigned(psqlite3_column_table_name16) then
    Result := Tsqlite3_column_table_name16(psqlite3_column_table_name16)
      (pStmt, index)
  else
    raise ENotImplemented.Create(EXCPT_MSG);
end;

function sqlite3_column_origin_name(pStmt: Psqlite3_stmt; index: integer)
  : PUTF8Char;
begin
  if assigned(psqlite3_column_origin_name) then
    Result := Tsqlite3_column_origin_name(psqlite3_column_origin_name)
      (pStmt, index)
  else
    raise ENotImplemented.Create(EXCPT_MSG);
end;

function sqlite3_column_origin_name16(pStmt: Psqlite3_stmt; index: integer)
  : PWideChar;
begin
  if assigned(psqlite3_column_origin_name16) then
    Result := Tsqlite3_column_origin_name16(psqlite3_column_origin_name16)
      (pStmt, index)
  else
    raise ENotImplemented.Create(EXCPT_MSG);
end;

function sqlite3_column_decltype(pStmt: Psqlite3_stmt; index: integer)
  : PUTF8Char;
begin
  if assigned(psqlite3_column_decltype) then
    Result := Tsqlite3_column_decltype(psqlite3_column_decltype)(pStmt, index)
  else
    raise ENotImplemented.Create(EXCPT_MSG);
end;

function sqlite3_column_decltype16(pStmt: Psqlite3_stmt; index: integer)
  : PUTF8Char;
begin
  if assigned(psqlite3_column_decltype16) then
    Result := Tsqlite3_column_decltype16(psqlite3_column_decltype16)
      (pStmt, index)
  else
    raise ENotImplemented.Create(EXCPT_MSG);
end;

function sqlite3_column_name(pStmt: Psqlite3_stmt; index: integer): PUTF8Char;
begin
  if assigned(psqlite3_column_name) then
    Result := Tsqlite3_column_name(psqlite3_column_name)(pStmt, index)
  else
    raise ENotImplemented.Create(EXCPT_MSG);
end;

function sqlite3_column_name16(pStmt: Psqlite3_stmt; index: integer): PWideChar;
begin
  if assigned(psqlite3_column_name16) then
    Result := Tsqlite3_column_name16(psqlite3_column_name16)(pStmt, index)
  else
    raise ENotImplemented.Create(EXCPT_MSG);
end;

// Blobs

function sqlite3_blob_bytes(pBlob: Psqlite3_blob): integer;
begin
  if assigned(psqlite3_blob_bytes) then
    Result := Tsqlite3_blob_bytes(psqlite3_blob_bytes)(pBlob)
  else
    raise ENotImplemented.Create(EXCPT_MSG);
end;

function sqlite3_blob_close(pBlob: Psqlite3_blob): integer;
begin
  if assigned(psqlite3_blob_close) then
    Result := Tsqlite3_blob_close(psqlite3_blob_close)(pBlob)
  else
    raise ENotImplemented.Create(EXCPT_MSG);
end;

function sqlite3_blob_open(db: PSQLite3; const zDb: UTF8String;
  const zTable: UTF8String; const zColumn: UTF8String; iRow: int64;
  flags: integer; out ppBlob: Psqlite3_blob): integer;
begin
  if assigned(psqlite3_blob_open) then
    Result := Tsqlite3_blob_open(psqlite3_blob_open)(db, zDb, zTable, zColumn,
      iRow, flags, ppBlob)
  else
    raise ENotImplemented.Create(EXCPT_MSG);
end;

function sqlite3_blob_read(pBlob: Psqlite3_blob; buffer: Pointer;
  nBytes: integer; iOffset: integer): integer;
begin
  if assigned(psqlite3_blob_read) then
    Result := Tsqlite3_blob_read(psqlite3_blob_read)
      (pBlob, buffer, nBytes, iOffset)
  else
    raise ENotImplemented.Create(EXCPT_MSG);
end;

function sqlite3_blob_reopen(pBlob: Psqlite3_blob; iRow: int64): integer;
begin
  if assigned(psqlite3_blob_reopen) then
    Result := Tsqlite3_blob_reopen(psqlite3_blob_reopen)(pBlob, iRow)
  else
    raise ENotImplemented.Create(EXCPT_MSG);
end;

function sqlite3_blob_write(pBlob: Psqlite3_blob; buffer: Pointer;
  nBytes: integer; iOffset: integer): integer;
begin
  if assigned(psqlite3_blob_write) then
    Result := Tsqlite3_blob_write(psqlite3_blob_write)
      (pBlob, buffer, nBytes, iOffset)
  else
    raise ENotImplemented.Create(EXCPT_MSG);
end;

// Run-Time Library Version Numbers

function sqlite3_libversion: PAnsiChar;
begin
  if assigned(psqlite3_libversion) then
    Result := Tsqlite3_libversion(psqlite3_libversion)()
  else
    raise ENotImplemented.Create(EXCPT_MSG);
end;

function sqlite3_sourceid: PAnsiChar;
begin
  if assigned(psqlite3_sourceid) then
    Result := Tsqlite3_sourceid(psqlite3_sourceid)()
  else
    raise ENotImplemented.Create(EXCPT_MSG);
end;

function sqlite3_libversion_number: integer;
begin
  if assigned(psqlite3_libversion_number) then
    Result := Tsqlite3_libversion_number(psqlite3_libversion_number)()
  else
    raise ENotImplemented.Create(EXCPT_MSG);
end;

// Test To See If The Library Is Threadsafe

function sqlite3_threadsafe: integer;
begin
  if assigned(psqlite3_threadsafe) then
    Result := Tsqlite3_threadsafe(psqlite3_threadsafe)()
  else
    raise ENotImplemented.Create(EXCPT_MSG);
end;

// Test For Auto-Commit Mode

function sqlite3_get_autocommit(db: PSQLite3): integer;
begin
  if assigned(psqlite3_get_autocommit) then
    Result := Tsqlite3_get_autocommit(psqlite3_get_autocommit)(db)
  else
    raise ENotImplemented.Create(EXCPT_MSG);
end;

// Error Codes And Messages

function sqlite3_errcode(db: PSQLite3): integer;
begin
  if assigned(psqlite3_errcode) then
    Result := Tsqlite3_errcode(psqlite3_errcode)(db)
  else
    raise ENotImplemented.Create(EXCPT_MSG);
end;

function sqlite3_extended_errcode(db: PSQLite3): integer;
begin
  if assigned(psqlite3_extended_errcode) then
    Result := Tsqlite3_extended_errcode(psqlite3_extended_errcode)(db)
  else
    raise ENotImplemented.Create(EXCPT_MSG);
end;

function sqlite3_errmsg(db: PSQLite3): PUTF8Char;
begin
  if assigned(psqlite3_errmsg) then
    Result := Tsqlite3_errmsg(psqlite3_errmsg)(db)
  else
    raise ENotImplemented.Create(EXCPT_MSG);
end;

function sqlite3_errmsg16(db: PSQLite3): PWideChar;
begin
  if assigned(psqlite3_errmsg16) then
    Result := Tsqlite3_errmsg16(psqlite3_errmsg16)(db)
  else
    raise ENotImplemented.Create(EXCPT_MSG);
end;

// Enable Or Disable Extended Result Codes

function sqlite3_extended_result_codes(db: PSQLite3; onoff: integer): integer;
begin
  if assigned(psqlite3_extended_result_codes) then
    Result := Tsqlite3_extended_result_codes(psqlite3_extended_result_codes)
      (db, onoff)
  else
    raise ENotImplemented.Create(EXCPT_MSG);
end;

// Affected rows

function sqlite3_changes(db: PSQLite3): integer;
begin
  if assigned(psqlite3_changes) then
    Result := Tsqlite3_changes(psqlite3_changes)(db)
  else
    raise ENotImplemented.Create(EXCPT_MSG);
end;

function sqlite3_total_changes(db: PSQLite3): integer;
begin
  if assigned(psqlite3_total_changes) then
    Result := Tsqlite3_total_changes(psqlite3_total_changes)(db)
  else
    raise ENotImplemented.Create(EXCPT_MSG);
end;

// One-Step Query Execution Interface

function sqlite3_exec(db: PSQLite3; const sql: UTF8String;
  callback: TSQLiteExecCallback; UserData: Pointer;
  var errmsg: PUTF8Char): integer;
begin
  if assigned(psqlite3_exec) then
    Result := Tsqlite3_exec(psqlite3_exec)(db, sql, callback, UserData, errmsg)
  else
    raise ENotImplemented.Create(EXCPT_MSG);
end;

// Memory Allocation Subsystem

function sqlite3_malloc(nBytes: integer): Pointer;
begin
  if assigned(psqlite3_malloc) then
    Result := Tsqlite3_malloc(psqlite3_malloc)(nBytes)
  else
    raise ENotImplemented.Create(EXCPT_MSG);
end;

function sqlite3_realloc(buffer: Pointer; nBytes: integer): Pointer;
begin
  if assigned(psqlite3_realloc) then
    Result := Tsqlite3_realloc(psqlite3_realloc)(buffer, nBytes)
  else
    raise ENotImplemented.Create(EXCPT_MSG);
end;

procedure sqlite3_free(buffer: Pointer);
begin
  if assigned(psqlite3_free) then
    Tsqlite3_free(psqlite3_free)(buffer)
  else
    raise ENotImplemented.Create(EXCPT_MSG);
end;



function sqlite3_db_readonly(db : PSQlite3; const zDBName : string) : integer;
begin

    if assigned(psqlite3_db_readonly) then

        result := Tsqlite3_db_readonly(Psqlite3_db_readonly)(db, UTF8String(PAnsiChar(nil)))
    else
        raise ENotImplemented.Create(EXCPT_MSG);
end;

// Run-time Limits

function sqlite3_limit(db: PSQLite3; id: integer; newVal: integer): integer;
begin
  if assigned(psqlite3_limit) then
    Result := Tsqlite3_limit(psqlite3_limit)(db, id, newVal)
  else
    raise ENotImplemented.Create(EXCPT_MSG);
end;


// Extract Metadata About A Column Of A Table

function sqlite3_table_column_metadata(db: PSQLite3; const zDbName: UTF8String;
  const zTableName: UTF8String; const zColumnName: UTF8String;
  out pzDataType: PUTF8Char; out pzCollSeq: PUTF8Char; out pNotNull: integer;
  out pPrimaryKey: integer; out pAutoinc: integer): integer;
begin
  if assigned(psqlite3_table_column_metadata) then
    Result := Tsqlite3_table_column_metadata(psqlite3_table_column_metadata)
      (db, zDbName, zTableName, zColumnName, pzDataType, pzCollSeq, pNotNull,
      pPrimaryKey, pAutoinc)
  else
    raise ENotImplemented.Create(EXCPT_MSG);
end;

// Last Insert Rowid

function sqlite3_last_insert_rowid(db: PSQLite3): int64;
begin
  if assigned(psqlite3_last_insert_rowid) then
    Result := Tsqlite3_last_insert_rowid(psqlite3_last_insert_rowid)(db)
  else
    raise ENotImplemented.Create(EXCPT_MSG);
end;




// ------------------------------------
// Unit initalization and finalization
// ------------------------------------

function DoLink : boolean;
var issue : boolean;
    function get(functionName : PWideChar) : Pointer;
    begin
        result := GetProcAddress(dllHandler, functionName);
        if result = nil then begin
            issue := true;
        end;
    end;
begin
    issue := false;
    psqlite3_aggregate_context := get(     'sqlite3_aggregate_context');
    psqlite3_auto_extension := get(        'sqlite3_auto_extension');
    psqlite3_backup_finish := get( 'sqlite3_backup_finish');
    psqlite3_backup_init := get( 'sqlite3_backup_init');
    psqlite3_backup_pagecount := get(      'sqlite3_backup_pagecount');
    psqlite3_backup_remaining := get(      'sqlite3_backup_remaining');
    psqlite3_backup_step := get( 'sqlite3_backup_step');
    psqlite3_bind_blob := get( 'sqlite3_bind_blob');
    psqlite3_bind_double := get( 'sqlite3_bind_double');
    psqlite3_bind_int := get( 'sqlite3_bind_int');
    psqlite3_bind_int64 := get( 'sqlite3_bind_int64');
    psqlite3_bind_null := get( 'sqlite3_bind_null');
    psqlite3_bind_parameter_count := get(    'sqlite3_bind_parameter_count');
    psqlite3_bind_parameter_index := get(    'sqlite3_bind_parameter_index');
    psqlite3_bind_parameter_name := get(     'sqlite3_bind_parameter_name');
    psqlite3_bind_text := get( 'sqlite3_bind_text');
    psqlite3_bind_text16 := get( 'sqlite3_bind_text16');
    psqlite3_bind_value := get( 'sqlite3_bind_value');
    psqlite3_bind_zeroblob := get( 'sqlite3_bind_zeroblob');
    psqlite3_blob_bytes := get( 'sqlite3_blob_bytes');
    psqlite3_blob_close := get( 'sqlite3_blob_close');
    psqlite3_blob_open := get( 'sqlite3_blob_open');
    psqlite3_blob_read := get( 'sqlite3_blob_read');
    psqlite3_blob_reopen := get( 'sqlite3_blob_reopen');
    psqlite3_blob_write := get( 'sqlite3_blob_write');
    psqlite3_busy_handler := get( 'sqlite3_busy_handler');
    psqlite3_busy_timeout := get( 'sqlite3_busy_timeout');
    psqlite3_changes := get( 'sqlite3_changes');
    psqlite3_clear_bindings := get(          'sqlite3_clear_bindings');
    psqlite3_close := get( 'sqlite3_close');
    psqlite3_collation_needed := get(        'sqlite3_collation_needed');
    psqlite3_collation_needed16 := get(      'sqlite3_collation_needed16');
    psqlite3_column_blob := get( 'sqlite3_column_blob');
    psqlite3_column_bytes := get( 'sqlite3_column_bytes');
    psqlite3_column_bytes16 := get(          'sqlite3_column_bytes16');
    psqlite3_column_count := get( 'sqlite3_column_count');
    psqlite3_column_database_name := get(    'sqlite3_column_database_name');
    psqlite3_column_database_name16 := get(    'sqlite3_column_database_name16');
    psqlite3_column_decltype := get(           'sqlite3_column_decltype');
    psqlite3_column_decltype16 := get(         'sqlite3_column_decltype16');
    psqlite3_column_double := get( 'sqlite3_column_double');
    psqlite3_column_int := get( 'sqlite3_column_int');
    psqlite3_column_int64 := get( 'sqlite3_column_int64');
    psqlite3_column_name := get( 'sqlite3_column_name');
    psqlite3_column_name16 := get( 'sqlite3_column_name16');
    psqlite3_column_origin_name := get(        'sqlite3_column_origin_name');
    psqlite3_column_origin_name16 := get(      'sqlite3_column_origin_name16');
    psqlite3_column_table_name := get(         'sqlite3_column_table_name');
    psqlite3_column_table_name16 := get(       'sqlite3_column_table_name16');
    psqlite3_column_text := get( 'sqlite3_column_text');
    psqlite3_column_text16 := get( 'sqlite3_column_text16');
    psqlite3_column_type := get( 'sqlite3_column_type');
    psqlite3_column_value := get( 'sqlite3_column_value');
    psqlite3_commit_hook := get( 'sqlite3_commit_hook');
    psqlite3_compileoption_get := get(         'sqlite3_compileoption_get');
    psqlite3_compileoption_used := get(        'sqlite3_compileoption_used');
    psqlite3_complete := get( 'sqlite3_complete');
    psqlite3_complete16 := get( 'sqlite3_complete16');
    psqlite3_config := get( 'sqlite3_config');
    psqlite3_context_db_handle := get(         'sqlite3_context_db_handle');
    psqlite3_create_collation := get(          'sqlite3_create_collation');
    psqlite3_create_collation16 := get(        'sqlite3_create_collation16');
    psqlite3_create_collation_v2 := get(       'sqlite3_create_collation_v2');
    psqlite3_create_function := get(           'sqlite3_create_function');
    psqlite3_create_function16 := get(         'sqlite3_create_function16');
    psqlite3_create_function_v2 := get(        'sqlite3_create_function_v2');
    psqlite3_create_module := get( 'sqlite3_create_module');
    psqlite3_create_module_v2 := get(          'sqlite3_create_module_v2');
    psqlite3_data_count := get( 'sqlite3_data_count');
    psqlite3_db_config := get( 'sqlite3_db_config');
    psqlite3_db_filename := get( 'sqlite3_db_filename');
    psqlite3_db_handle := get( 'sqlite3_db_handle');
    psqlite3_db_mutex := get( 'sqlite3_db_mutex');
    psqlite3_db_readonly := get( 'sqlite3_db_readonly');
    psqlite3_db_release_memory := get(         'sqlite3_db_release_memory');
    psqlite3_db_status := get( 'sqlite3_db_status');
    psqlite3_declare_vtab := get( 'sqlite3_declare_vtab');
    psqlite3_enable_load_extension := get(     'sqlite3_enable_load_extension');
    psqlite3_enable_shared_cache := get(       'sqlite3_enable_shared_cache');
    psqlite3_errcode := get( 'sqlite3_errcode');
    psqlite3_errmsg := get( 'sqlite3_errmsg');
    psqlite3_errmsg16 := get( 'sqlite3_errmsg16');
    psqlite3_exec := get( 'sqlite3_exec');
    psqlite3_extended_errcode := get(          'sqlite3_extended_errcode');
    psqlite3_extended_result_codes := get(     'sqlite3_extended_result_codes');
    psqlite3_file_control := get( 'sqlite3_file_control');
    psqlite3_finalize := get( 'sqlite3_finalize');
    psqlite3_free := get( 'sqlite3_free');
    psqlite3_free_table := get( 'sqlite3_free_table');
    psqlite3_get_autocommit := get(         'sqlite3_get_autocommit');
    psqlite3_get_auxdata := get( 'sqlite3_get_auxdata');
    psqlite3_get_table := get( 'sqlite3_get_table');
    psqlite3_initialize := get( 'sqlite3_initialize');
    psqlite3_interrupt := get( 'sqlite3_interrupt');
    psqlite3_last_insert_rowid := get(      'sqlite3_last_insert_rowid');
    psqlite3_libversion := get( 'sqlite3_libversion');
    psqlite3_libversion_number := get(      'sqlite3_libversion_number');
    psqlite3_limit := get( 'sqlite3_limit');
    psqlite3_load_extension := get(         'sqlite3_load_extension');
    psqlite3_log := get( 'sqlite3_log');
    psqlite3_malloc := get( 'sqlite3_malloc');
    psqlite3_memory_highwater := get(       'sqlite3_memory_highwater');
    psqlite3_memory_used := get( 'sqlite3_memory_used');
    psqlite3_mprintf := get( 'sqlite3_mprintf');
    psqlite3_mutex_alloc := get( 'sqlite3_mutex_alloc');
    psqlite3_mutex_enter := get( 'sqlite3_mutex_enter');
    psqlite3_mutex_free := get( 'sqlite3_mutex_free');
    psqlite3_mutex_held := get( 'sqlite3_mutex_held');
    psqlite3_mutex_leave := get( 'sqlite3_mutex_leave');
    psqlite3_mutex_notheld := get( 'sqlite3_mutex_notheld');
    psqlite3_mutex_try := get( 'sqlite3_mutex_try');
    psqlite3_next_stmt := get( 'sqlite3_next_stmt');
    psqlite3_open := get( 'sqlite3_open');
    psqlite3_open16 := get( 'sqlite3_open16');
    psqlite3_open_v2 := get( 'sqlite3_open_v2');
    psqlite3_os_end := get( 'sqlite3_os_end');
    psqlite3_os_init := get( 'sqlite3_os_init');
    psqlite3_overload_function := get(      'sqlite3_overload_function');
    psqlite3_prepare := get( 'sqlite3_prepare');
    psqlite3_prepare16 := get( 'sqlite3_prepare16');
    psqlite3_prepare16_v2 := get( 'sqlite3_prepare16_v2');
    psqlite3_prepare_v2 := get( 'sqlite3_prepare_v2');
    psqlite3_profile := get( 'sqlite3_profile');
    psqlite3_progress_handler := get(       'sqlite3_progress_handler');
    psqlite3_randomness := get( 'sqlite3_randomness');
    psqlite3_realloc := get( 'sqlite3_realloc');
    psqlite3_release_memory := get(         'sqlite3_release_memory');
    psqlite3_reset := get( 'sqlite3_reset');
    psqlite3_reset_auto_extension := get(    'sqlite3_reset_auto_extension');
    psqlite3_result_blob := get( 'sqlite3_result_blob');
    psqlite3_result_double := get( 'sqlite3_result_double');
    psqlite3_result_error := get( 'sqlite3_result_error');
    psqlite3_result_error16 := get(    'sqlite3_result_error16');
    psqlite3_result_error_code := get(    'sqlite3_result_error_code');
    psqlite3_result_error_nomem := get(    'sqlite3_result_error_nomem');
    psqlite3_result_error_toobig := get(    'sqlite3_result_error_toobig');
    psqlite3_result_int := get( 'sqlite3_result_int');
    psqlite3_result_int64 := get( 'sqlite3_result_int64');
    psqlite3_result_null := get( 'sqlite3_result_null');
    psqlite3_result_text := get( 'sqlite3_result_text');
    psqlite3_result_text16 := get( 'sqlite3_result_text16');
    psqlite3_result_text16be := get(        'sqlite3_result_text16be');
    psqlite3_result_text16le := get(        'sqlite3_result_text16le');
    psqlite3_result_value := get( 'sqlite3_result_value');
    psqlite3_result_zeroblob := get(        'sqlite3_result_zeroblob');
    psqlite3_rollback_hook := get( 'sqlite3_rollback_hook');
    psqlite3_set_authorizer := get(         'sqlite3_set_authorizer');
    psqlite3_set_auxdata := get( 'sqlite3_set_auxdata');
    psqlite3_shutdown := get( 'sqlite3_shutdown');
    psqlite3_sleep := get( 'sqlite3_sleep');
    psqlite3_snprintf := get( 'sqlite3_snprintf');
    psqlite3_soft_heap_limit64 := get(      'sqlite3_soft_heap_limit64');
    psqlite3_sourceid := get( 'sqlite3_sourceid');
    psqlite3_sql := get( 'sqlite3_sql');
    psqlite3_status := get( 'sqlite3_status');
    psqlite3_step := get( 'sqlite3_step');
    psqlite3_stmt_busy := get( 'sqlite3_stmt_busy');
    psqlite3_stmt_readonly := get( 'sqlite3_stmt_readonly');
    psqlite3_stmt_status := get( 'sqlite3_stmt_status');
    psqlite3_stricmp := get( 'sqlite3_stricmp');
    psqlite3_strnicmp := get( 'sqlite3_strnicmp');
    psqlite3_table_column_metadata := get(    'sqlite3_table_column_metadata');
    psqlite3_test_control := get( 'sqlite3_test_control');
    psqlite3_threadsafe := get( 'sqlite3_threadsafe');
    psqlite3_total_changes := get( 'sqlite3_total_changes');
    psqlite3_trace := get( 'sqlite3_trace');
    psqlite3_unlock_notify := get( 'sqlite3_unlock_notify');
    psqlite3_update_hook := get( 'sqlite3_update_hook');
    psqlite3_uri_boolean := get( 'sqlite3_uri_boolean');
    psqlite3_uri_int64 := get( 'sqlite3_uri_int64');
    psqlite3_uri_parameter := get( 'sqlite3_uri_parameter');
    psqlite3_user_data := get( 'sqlite3_user_data');
    psqlite3_value_blob := get( 'sqlite3_value_blob');
    psqlite3_value_bytes := get( 'sqlite3_value_bytes');
    psqlite3_value_bytes16 := get( 'sqlite3_value_bytes16');
    psqlite3_value_double := get( 'sqlite3_value_double');
    psqlite3_value_int := get( 'sqlite3_value_int');
    psqlite3_value_int64 := get( 'sqlite3_value_int64');
    psqlite3_value_numeric_type := get(       'sqlite3_value_numeric_type');
    psqlite3_value_text := get( 'sqlite3_value_text');
    psqlite3_value_text16 := get( 'sqlite3_value_text16');
    psqlite3_value_text16be := get(           'sqlite3_value_text16be');
    psqlite3_value_text16le := get(           'sqlite3_value_text16le');
    psqlite3_value_type := get( 'sqlite3_value_type');
    psqlite3_version := get( 'sqlite3_version');
    psqlite3_vfs_find := get( 'sqlite3_vfs_find');
    psqlite3_vfs_register := get( 'sqlite3_vfs_register');
    psqlite3_vfs_unregister := get(           'sqlite3_vfs_unregister');
    psqlite3_vmprintf := get( 'sqlite3_vmprintf');
    psqlite3_vsnprintf := get( 'sqlite3_vsnprintf');
    psqlite3_vtab_config := get( 'sqlite3_vtab_config');
    psqlite3_vtab_on_conflict := get(         'sqlite3_vtab_on_conflict');
    psqlite3_wal_autocheckpoint := get(       'sqlite3_wal_autocheckpoint');
    psqlite3_wal_checkpoint := get(           'sqlite3_wal_checkpoint');
    psqlite3_wal_checkpoint_v2 := get(        'sqlite3_wal_checkpoint_v2');
    psqlite3_wal_hook := get( 'sqlite3_wal_hook');

    result := issue;
end;

procedure DoInitialize;
var
    errmode: cardinal;


    function extractDLL(fullname : string) : boolean;
    var
        rs: TResourceStream;
    begin
        try
            result := false;
            if not FileExists(fullname) then begin
                rs := TResourceStream.Create(GetModuleHandle(nil), SQLITERESID, RT_RCDATA);
                rs.SaveToFile(TempDLLFile);
                rs.Free;
                result := true;
            end;
        except
            result := false;
        end;
    end;

    function loadDLL(fullname : string) : integer;
    begin
        result := 0;
        if (FileExists(fullname)) then begin
            result := LoadLibrary(PChar(fullname));
        end else begin
            if extractDLL(fullname) then
                result := LoadLibrary(PChar(fullname));
        end;
    end;

const
    SQL_DLL_NAME = 'sqlite3-a.dll';
begin
  // Note: no exceptions are raised.
  // In case of error, isAvailable will return false
  // so applications have a chance to deal with the error

    try
        errmode := SetErrorMode(SEM_FAILCRITICALERRORS);
        dllHandler := 0;
        TempDLLFile := '';

        //dllHandler := LoadLibrary('sqlite3.dll');

        if (dllHandler = 0) then begin
            TempDLLFile := UnitMisc.GetAppPath + SQL_DLL_NAME;
            dllHandler := loadDLL(TempDLLFile);

            TempDLLFile := '';
        end;

        if (dllHandler = 0) then begin
            TempDLLFile := IncludeTrailingPathDelimiter(TPath.GetTempPath) + SQL_DLL_NAME;
            dllHandler := loadDLL(TempDLLFile);
        end;

        if (dllHandler = 0) or (not DoLink) then begin
            ShowMessage('Unable to connect to ' + SQL_DLL_NAME);
            ExitProcess(1);
        end;


        SetErrorMode(errmode);
        SetLastError(NO_ERROR);
    except on E : Exception do
        begin
            ShowMessage(e.ToString);
        end;
    end;
end;

procedure DoFinalize;
begin
    if (dllHandler <> 0) then FreeLibrary(dllHandler);
    if (TempDLLFile <> '') then begin
        if FileExists(TempDLLFile) then DeleteFile(TempDLLFile);
    end;
end;

initialization
begin
    DoInitialize;
end;

finalization
begin
    DoFinalize;
end;

end.
