{-------------------------------------------------------------------------------
 
 Copyright (c) 1999-2009 Ralf Junker, The Delphi Inspiration
 Internet: http://www.yunqa.de/delphi/
 E-Mail:   delphi@yunqa.de

-------------------------------------------------------------------------------}

unit DISQLite3Database;

{$I DI.inc}
{$I DISQLite3.inc}

interface

uses
  DISystemCompat, Classes, DISQLite3Api;

type
  TDISQLite3Statement = class;

  TDISQLite3StatementClass = class of TDISQLite3Statement;

  TDISQLite3TransactionType = (
    ttDeferred,
    ttImmediate,
    ttExclusive);

  TDISQLite3Database = class(TComponent)
  private
    FAfterConnect: TNotifyEvent;
    FAfterCreateDatabase: TNotifyEvent;
    FAfterDisconnect: TNotifyEvent;
    FBeforeConnect: TNotifyEvent;
    FBeforeCreateDatabase: TNotifyEvent;
    FBeforeDisconnect: TNotifyEvent;
    FDataBaseName: UnicodeString;
    FHandle: sqlite3;
    FInitDatabase: TNotifyEvent;
    {$IFDEF SQLITE_HAS_CODEC}
    FPassword: RawByteString;
    {$ENDIF SQLITE_HAS_CODEC}
    FStatements: TList;
    FStreamedConnected: Boolean;
    FTransactionCount: Integer;

    procedure CheckActive;
    procedure CheckDatabaseName(const ADatabaseName: UnicodeString);

    procedure CheckInactive;

    function GetAutoVacuum: Boolean;
    procedure SetAutoVacuum(const AValue: Boolean);

    function GetCacheSize: Integer;
    procedure SetCacheSize(const AValue: Integer);

    procedure SetCaseSensitiveLike(const AValue: Boolean);

    function GetConnected: Boolean;
    procedure SetConnected(const AValue: Boolean);

    function GetCountChanges: Boolean;
    procedure SetCountChanges(const AValue: Boolean);

    function GetEmptyResultCallbacks: Boolean;
    procedure SetEmptyResultCallbacks(const AValue: Boolean);

    function GetEncoding: UnicodeString;
    procedure SetEncoding(const AValue: UnicodeString);

    function GetInTransaction: Boolean;

    function GetSQLiteVersion: UnicodeString;
    procedure SetSQLiteVersion(const Value: UnicodeString);

    function GetDefaultCacheSize: Integer;
    procedure SetDefaultCacheSize(const AValue: Integer);

    procedure SetDatabaseName(const AValue: UnicodeString);

    function GetPageSize: Integer;
    procedure SetPageSize(const AValue: Integer);

    {$IFDEF SQLITE_HAS_CODEC}
    procedure SetPassword(const AValue: RawByteString);
    {$ENDIF SQLITE_HAS_CODEC}

    function IsMemoryDatabaseName(const ADatabaseName: UnicodeString): Boolean;

  protected

    procedure CloseStatements;

    procedure DoAfterConnect; dynamic;

    procedure DoAfterCreateDatabase; dynamic;

    procedure DoAfterDisconnect; dynamic;

    procedure DoBeforeConnect; dynamic;

    procedure DoBeforeCreateDatabase; dynamic;

    procedure DoBeforeDisconnect; dynamic;

    procedure DoConnect;

    procedure DoDisconnect;

    procedure DoInitDatabase; dynamic;

    function GetStatementClass: TDISQLite3StatementClass; virtual;

    procedure Loaded; override;

    procedure RegisterStatement(const AStatement: TDISQLite3Statement);

    procedure UnRegisterStatement(const AStatement: TDISQLite3Statement);

    property StreamedConnected: Boolean read FStreamedConnected write FStreamedConnected;

  public

    constructor Create(AOwner: TComponent); override;

    destructor Destroy; override;

    procedure AttachDataBase16(
      const ADatabaseName: UnicodeString;
      ADataBaseAlias: UnicodeString{$IFDEF SUPPORTS_DEFAULTPARAMS} = ''{$ENDIF});

    function Changes: Integer;

    function Check(const AErrorCode: Integer): Integer;

    procedure Close;

    procedure CreateDatabase; dynamic;

    procedure Commit;

    procedure DetachDatabase(const ADataBaseAlias: Utf8String);

    procedure DetachDatabase16(const ADataBaseAlias: UnicodeString);

    procedure Execute(const ASql: Utf8String);

    procedure Execute16(const ASql: UnicodeString);

    function IntegrityCheck: Integer;

    procedure Interrupt;

    function LastInsertRowID: Int64;

    procedure Open;

    function Prepare(const ASql8: Utf8String): TDISQLite3Statement;

    function Prepare16(const ASQL16: UnicodeString): TDISQLite3Statement;

    {$IFDEF SQLITE_HAS_CODEC}

    procedure ReKey(const ANewPassword: RawByteString);

    {$ENDIF SQLITE_HAS_CODEC}

    procedure Rollback;

    procedure StartTransaction(const ATransactionType: TDISQLite3TransactionType{$IFDEF SUPPORTS_DEFAULTPARAMS} = ttDeferred{$ENDIF});

    function TotalChanges: Integer;

    procedure Vacuum;

    property AutoVacuum: Boolean read GetAutoVacuum write SetAutoVacuum;

    property CacheSize: Integer read GetCacheSize write SetCacheSize;

    property CaseSensitiveLike: Boolean write SetCaseSensitiveLike;

    property DefaultCacheSize: Integer read GetDefaultCacheSize write SetDefaultCacheSize;

    property CountChanges: Boolean read GetCountChanges write SetCountChanges;

    property EmptyResultCallbacks: Boolean read GetEmptyResultCallbacks write SetEmptyResultCallbacks;

    property Encoding: UnicodeString read GetEncoding write SetEncoding;

    property Handle: sqlite3 read FHandle;

    property InTransaction: Boolean read GetInTransaction;

    property PageSize: Integer read GetPageSize write SetPageSize;

  published

    property Connected: Boolean read GetConnected write SetConnected default False;

    property DatabaseName: UnicodeString read FDataBaseName write SetDatabaseName;

    {$IFDEF SQLITE_HAS_CODEC}

    property Password: RawByteString read FPassword write SetPassword;

    {$ENDIF SQLITE_HAS_CODEC}

    property SQLiteVersion: UnicodeString read GetSQLiteVersion write SetSQLiteVersion stored False;

    property AfterConnect: TNotifyEvent read FAfterConnect write FAfterConnect;

    property AfterCreateDatabase: TNotifyEvent read FAfterCreateDatabase write FAfterCreateDatabase;

    property AfterDisconnect: TNotifyEvent read FAfterDisconnect write FAfterDisconnect;

    property BeforeConnect: TNotifyEvent read FBeforeConnect write FBeforeConnect;

    property BeforeCreateDatabase: TNotifyEvent read FBeforeCreateDatabase write FBeforeCreateDatabase;

    property BeforeDisconnect: TNotifyEvent read FBeforeDisconnect write FBeforeDisconnect;

    property InitDatabase: TNotifyEvent read FInitDatabase write FInitDatabase;

  end;

  TDISQLite3Cell8 = packed record
    CellType: Byte;
    case Byte of
      1: (CellInteger: Int64);
      2: (CellFloat: Double);
      3: (CellText: packed record l: Integer; p: PUtf8Char; end);
      4: (CellBlob: packed record l: Integer; p: Pointer; end);
  end;

  TDISQLite3Cell16 = packed record
    CellType: Byte;
    case Byte of
      1: (CellInteger: Int64);
      2: (CellFloat: Double);
      3: (CellText: packed record l: Integer; p: PWideChar; end);
      4: (CellBlob: packed record l: Integer; p: Pointer; end);
  end;

  TDISQLite3Statement = class
  private
    FAfterClose: TNotifyEvent;
    FAfterOpen: TNotifyEvent;
    FBeforeClose: TNotifyEvent;
    FBeforeOpen: TNotifyEvent;
    FHandle: sqlite3_stmt;
    FDatabase: TDISQLite3Database;
    FSql8: Utf8String;
    function GetActive: Boolean;

    function GetSql16: UnicodeString;

    procedure SetActive(const AValue: Boolean);

    procedure SetDatabase(const AValue: TDISQLite3Database);

    procedure SetSql8(const AValue: Utf8String);

    procedure SetSql16(const AValue: UnicodeString);

  protected

    function Check(const AErrorCode: Integer): Integer;

    procedure CheckActive;

    procedure CheckInactive;

    procedure DoAfterClose;

    procedure DoAfterOpen;

    procedure DoBeforeClose;

    procedure DoBeforeOpen;

  public

    destructor Destroy; override;

    procedure Assign(const ASource: TDISQLite3Statement);

    procedure Bind_Blob(
      const AParamIdx: Integer;
      const ABlobData: Pointer;
      const ABlobSize: Integer;
      const ADestroy: TSQLite_Bind_Destructor);

    procedure bind_Blob_By_Name(
      const AParamName: Utf8String;
      const ABlobData: Pointer;
      const ABlobSize: Integer;
      const ADestroy: TSQLite_Bind_Destructor);

    procedure bind_Blob_By_Name16(
      const AParamName: UnicodeString;
      const ABlobData: Pointer;
      const ABlobSize: Integer;
      const ADestroy: TSQLite_Bind_Destructor);

    procedure Bind_Double(
      const AParamIdx: Integer;
      const AValue: Double);

    procedure Bind_Double_By_Name(
      const AParamName: Utf8String;
      const AValue: Double);

    procedure Bind_Double_By_Name16(
      const AParamName: UnicodeString;
      const AValue: Double);

    procedure Bind_Int(
      const AParamIdx: Integer;
      const AValue: Integer);

    procedure Bind_Int_By_Name(
      const AParamName: Utf8String;
      const AValue: Integer);

    procedure Bind_Int_By_Name16(
      const AParamName: UnicodeString;
      const AValue: Integer);

    procedure Bind_Int64(
      const AParamIdx: Integer;
      const AValue: Int64);

    procedure Bind_Int64_By_Name(
      const AParamName: Utf8String;
      const AValue: Int64);

    procedure Bind_Int64_By_Name16(
      const AParamName: UnicodeString;
      const AValue: Int64);

    procedure Bind_Null(
      const AParamIdx: Integer);

    procedure Bind_Null_By_Name(
      const AParamName: Utf8String);

    procedure Bind_Null_By_Name16(
      const AParamName: UnicodeString);

    function Bind_Parameter_Count: Integer;

    function Bind_Parameter_Index(
      const AParamName: Utf8String): Integer;

    function Bind_Parameter_Index16(
      const AParamName: UnicodeString): Integer;

    function bind_Parameter_Name(
      const AParamIdx: Integer): Utf8String;

    function Bind_Parameter_Name16(
      const AParamIdx: Integer): UnicodeString;

    procedure Bind_Str(
      const AParamIdx: Integer;
      const AValue: Utf8String);

    procedure Bind_Str_By_Name(
      const AParamName: Utf8String;
      const AValue: Utf8String);

    procedure Bind_Str_By_Name16(
      const AParamName: UnicodeString;
      const AValue: Utf8String);

    procedure Bind_Str16(
      const AParamIdx: Integer;
      const AValue: UnicodeString);

    procedure Bind_Str16_By_Name(
      const AParamName: Utf8String;
      const AValue: UnicodeString);

    procedure Bind_Str16_By_Name16(
      const AParamName: UnicodeString;
      const AValue: UnicodeString);

    procedure Bind_Text(
      const AParamIdx: Integer;
      const AValue: PUtf8Char;
      const AValueLen: Integer;
      const xDestroy: TSQLite_Bind_Destructor);

    procedure Bind_Text_By_Name(
      const AParamName: Utf8String;
      const AValue: PUtf8Char;
      const AValueLen: Integer;
      const xDestroy: TSQLite_Bind_Destructor);

    procedure Bind_Text_By_Name16(
      const AParamName: UnicodeString;
      const AValue: PUtf8Char;
      const AValueLen: Integer;
      const xDestroy: TSQLite_Bind_Destructor);

    {$IFNDEF SQLITE_OMIT_UTF16}

    procedure Bind_Text16(
      const AParamIdx: Integer;
      const AValue: PWideChar;
      const AValueLen: Integer;
      const xDestroy: TSQLite_Bind_Destructor);
    {$ENDIF SQLITE_OMIT_UTF16}

    {$IFNDEF SQLITE_OMIT_UTF16}

    procedure Bind_Text16_By_Name(
      const AParamName: Utf8String;
      const AValue: PWideChar;
      const AValueLen: Integer;
      const xDestroy: TSQLite_Bind_Destructor);
    {$ENDIF SQLITE_OMIT_UTF16}

    {$IFNDEF SQLITE_OMIT_UTF16}

    procedure Bind_Text16_By_Name16(
      const AParamName: UnicodeString;
      const AValue: PWideChar;
      const AValueLen: Integer;
      const xDestroy: TSQLite_Bind_Destructor);
    {$ENDIF SQLITE_OMIT_UTF16}

    procedure Bind_Variant(
      const AParamIdx: Integer;
      const AValue: Variant);

    procedure Bind_Variant_By_Name(
      const AParamName: Utf8String;
      const AValue: Variant);

    procedure Bind_Variant_By_Name16(
      const AParamName: UnicodeString;
      const AValue: Variant);

    procedure Bind_ZeroBlob(
      const AParamIdx: Integer;
      const ABlobSize: Integer);

    procedure Clear_Bindings;

    procedure Close;

    function Column_Blob(
      const AColumnIdx: Integer): Pointer;

    function Column_Bytes(
      const AColumnIdx: Integer): Integer;

    {$IFNDEF SQLITE_OMIT_UTF16}

    function Column_Bytes16(
      const AColumnIdx: Integer): Integer;
    {$ENDIF !SQLITE_OMIT_UTF16}

    function Column_Cell8(
      const AColumnIdx: Integer): TDISQLite3Cell8;

    procedure Column_Cell16(
      const AColumnIdx: Integer;
      out ACell: TDISQLite3Cell16);

    function Column_Count: Integer;

    {$IFDEF SQLITE_ENABLE_COLUMN_METADATA}

    function Column_Database_Name(
      const AColumnIdx: Integer): Utf8String;
    {$ENDIF SQLITE_ENABLE_COLUMN_METADATA}

    {$IFDEF SQLITE_ENABLE_COLUMN_METADATA}

    function Column_Database_Name16(
      const AColumnIdx: Integer): UnicodeString;
    {$ENDIF SQLITE_ENABLE_COLUMN_METADATA}

    {$IFNDEF SQLITE_OMIT_DECLTYPE}

    function Column_DeclType(
      const AColumnIdx: Integer): Utf8String;
    {$ENDIF !SQLITE_OMIT_DECLTYPE}

    {$IFNDEF SQLITE_OMIT_DECLTYPE}

    function Column_DeclType16(
      const AColumnIdx: Integer): UnicodeString;
    {$ENDIF !SQLITE_OMIT_DECLTYPE}

    function Column_Double(
      const AColumnIdx: Integer): Double;

    function Column_Int(
      const AColumnIdx: Integer): Integer;

    function Column_Int64(
      const AColumnIdx: Integer): Int64;

    function Column_Name(
      const AColumnIdx: Integer): Utf8String;

    function Column_Name16(
      const AColumnIdx: Integer): UnicodeString;

    {$IFDEF SQLITE_ENABLE_COLUMN_METADATA}

    function Column_Origin_Name(
      const AColumnIdx: Integer): Utf8String;
    {$ENDIF SQLITE_ENABLE_COLUMN_METADATA}

    {$IFDEF SQLITE_ENABLE_COLUMN_METADATA}

    function Column_Origin_Name16(
      const AColumnIdx: Integer): UnicodeString;
    {$ENDIF SQLITE_ENABLE_COLUMN_METADATA}

    function Column_Str(
      const AColumnIdx: Integer): Utf8String;

    function Column_Str16(
      const AColumnIdx: Integer): UnicodeString;

    {$IFDEF SQLITE_ENABLE_COLUMN_METADATA}

    function Column_Table_Name(
      const AColumnIdx: Integer): Utf8String;
    {$ENDIF SQLITE_ENABLE_COLUMN_METADATA}

    {$IFDEF SQLITE_ENABLE_COLUMN_METADATA}

    function Column_Table_Name16(
      const AColumnIdx: Integer): UnicodeString;
    {$ENDIF SQLITE_ENABLE_COLUMN_METADATA}

    function Column_Text(
      const AColumnIdx: Integer): PUtf8Char;

    {$IFNDEF SQLITE_OMIT_UTF16}

    function Column_Text16(
      const AColumnIdx: Integer): PWideChar;
    {$ENDIF !SQLITE_OMIT_UTF16}

    function Column_Type(
      const AColumnIdx: Integer): Integer;

    procedure Open;

    function Step: Integer;

    function StepAndReset: Integer;

    {$IFDEF SQLITE_ENABLE_COLUMN_METADATA}

    function TableName(const AQuoteChar: AnsiChar{$IFDEF SUPPORTS_DEFAULTPARAMS} = SQLITE3_IDENTIFIER_QUOTE_CHAR{$ENDIF}): Utf8String;

    {$ENDIF SQLITE_ENABLE_COLUMN_METADATA}

    {$IFDEF SQLITE_ENABLE_COLUMN_METADATA}

    function TableName16(const AQuoteChar: WideChar{$IFDEF SUPPORTS_DEFAULTPARAMS} = SQLITE3_IDENTIFIER_QUOTE_CHAR{$ENDIF}): UnicodeString;

    {$ENDIF SQLITE_ENABLE_COLUMN_METADATA}

    function Reset: Integer;

    property Active: Boolean read GetActive write SetActive default False;

    property Database: TDISQLite3Database read FDatabase write SetDatabase;

    property Handle: sqlite3_stmt read FHandle;

    property SQL8: Utf8String read FSql8 write SetSql8;

    property SQL16: UnicodeString read GetSql16 write SetSql16 stored False;

    property AfterClose: TNotifyEvent read FAfterClose write FAfterClose;

    property AfterOpen: TNotifyEvent read FAfterOpen write FAfterOpen;

    property BeforeClose: TNotifyEvent read FBeforeClose write FBeforeClose;

    property BeforeOpen: TNotifyEvent read FBeforeOpen write FBeforeOpen;

  end;

  {$IFNDEF SQLITE_OMIT_INCRBLOB}

  TDISQLite3IncrBlobStream = class(TStream)
  private
    FBlobHandle: TDISQLite3BlobHandle;
    FFlags: Integer;
    FOffset: Integer;
  protected
    procedure SetSize(NewSize: Integer); override;
  public

    constructor Create(
      const ADBHandle: sqlite3;
      const ADatabaseName: UnicodeString;
      const ATableName: UnicodeString;
      const AColumnName: UnicodeString;
      const ARowID: Int64;
      const AFlags: Integer); {$IFDEF SUPPORTS_OVERLOAD} overload; {$ENDIF}

    constructor{$IFDEF SUPPORTS_OVERLOAD}Create{$ELSE}CreateDB{$ENDIF}(
      const ADb: TDISQLite3Database;
      const ADatabaseName: UnicodeString;
      const ATableName: UnicodeString;
      const AColumnName: UnicodeString;
      const ARowID: Int64;
      const AFlags: Integer); {$IFDEF SUPPORTS_OVERLOAD} overload; {$ENDIF}
    destructor Destroy; override;
    function Read(var Buffer; Count: Integer): Integer; override;
    function Seek(Offset: Integer; Origin: Word): Integer; override;
    function Write(const Buffer; Count: Integer): Integer; override;
  end;

  {$ENDIF !SQLITE_OMIT_INCRBLOB}

  TDISQLite3_Callback_ = function(
    const AStmt: sqlite3_stmt;
    const AUserData: Pointer): Boolean;

procedure DatabaseError(
  const AResStrRec: PResStringRec;
  const AObject: TObject{$IFDEF SUPPORTS_DEFAULTPARAMS} = nil{$ENDIF});

procedure DatabaseErrorFmt(
  const AResStrRec: PResStringRec;
  const AArgs: array of const;
  const AObject: TObject{$IFDEF SUPPORTS_DEFAULTPARAMS} = nil{$ENDIF});

function DateToJulianDate(
  const ADate: TDateTime): TDIJulianDate; {$IFDEF SUPPORTS_DEPRECATED}deprecated; {$ENDIF}

function DateTimeToJulianDate(
  const ADateTime: TDateTime): TDIJulianDate; {$IFDEF SUPPORTS_DEPRECATED}deprecated; {$ENDIF}

function HmsToJulianDate(
  const AHour, AMinute, ASecond: Integer): TDIJulianDate; {$IFDEF SUPPORTS_DEPRECATED}deprecated; {$ENDIF}

function JulianDateToDate(
  const AJulianDate: TDIJulianDate): TDateTime; {$IFDEF SUPPORTS_DEPRECATED}deprecated; {$ENDIF}

procedure JulianDateToHms(
  const AJulianDate: TDIJulianDate;
  out AHour, AMinute, ASecond: Integer); {$IFDEF SUPPORTS_DEPRECATED}deprecated; {$ENDIF}

function JulianDateToTime(
  const AJulianDate: TDIJulianDate): TDateTime; {$IFDEF SUPPORTS_DEPRECATED}deprecated; {$ENDIF}

procedure JulianDateToYmd(
  const AJulianDate: TDIJulianDate;
  out AYear, AMonth, ADay: Integer); {$IFDEF SUPPORTS_DEPRECATED}deprecated; {$ENDIF}

function JulianDateToDateTime(
  const AJulianDate: TDIJulianDate): TDateTime; {$IFDEF SUPPORTS_DEPRECATED}deprecated; {$ENDIF}

function sqlite3_cell16_as_ansistring(const ACell: TDISQLite3Cell16): AnsiString;

function sqlite3_cell16_as_date(const ACell: TDISQLite3Cell16): TDateTime;

function sqlite3_cell16_as_datetime(const ACell: TDISQLite3Cell16): TDateTime;

function sqlite3_cell16_as_float(const ACell: TDISQLite3Cell16): Double;

function sqlite3_cell16_as_integer(const ACell: TDISQLite3Cell16): Integer;

function sqlite3_cell16_as_int64(const ACell: TDISQLite3Cell16): Int64;

function sqlite3_cell16_as_time(const ACell: TDISQLite3Cell16): TDateTime;

function sqlite3_cell16_as_widestring(const ACell: TDISQLite3Cell16): UnicodeString;

function sqlite3_exec_with_callback(
  const ADBHandle: sqlite3;
  const ASql: Utf8String;
  const ACallback: TDISQLite3_Callback_{$IFDEF SUPPORTS_DEFAULTPARAMS} = nil{$ENDIF};
  const AUserData: Pointer{$IFDEF SUPPORTS_DEFAULTPARAMS} = nil{$ENDIF}): Integer;

function sqlite3_exec_with_callback16(
  const ADBHandle: sqlite3;
  const ASql: UnicodeString;
  const ACallback: TDISQLite3_Callback_;
  const AUserData: Pointer): Integer;

function sqlite3_get_boolean(
  const ADb: sqlite3;
  const ASql: Utf8String;
  out ABoolean: Boolean): Integer;

function sqlite3_get_boolean16(
  const ADb: sqlite3;
  const ASql: UnicodeString;
  out ABoolean: Boolean): Integer;

function sqlite3_get_int(
  const ADb: sqlite3;
  const ASql: Utf8String;
  out AInteger: Integer): Integer;

function sqlite3_get_int16(
  const ADb: sqlite3;
  const ASql: UnicodeString;
  out AInteger: Integer): Integer;

function sqlite3_get_str(
  const ADb: sqlite3;
  const ASql: Utf8String;
  out AValue: Utf8String): Integer;

function sqlite3_get_str16(
  const ADb: sqlite3;
  const ASql: UnicodeString;
  out AValue: UnicodeString): Integer;

procedure sqlite3_init_cell8(
  out ACell: TDISQLite3Cell8);

procedure sqlite3_init_cell16(
  out ACell: TDISQLite3Cell16);

function sqlite3_integrity_check(
  const ADb: sqlite3;
  const ADatabaseName: Utf8String{$IFDEF SUPPORTS_DEFAULTPARAMS} = ''{$ENDIF}): Integer;

{$IFNDEF SQLITE_OMIT_UTF16}
function sqlite3_integrity_check16(
  const ADb: sqlite3;
  const ADatabaseName: UnicodeString{$IFDEF SUPPORTS_DEFAULTPARAMS} = ''{$ENDIF}): Integer;
{$ENDIF !SQLITE_OMIT_UTF16}

procedure sqlite3_finalize_cell8(
  var ACell: TDISQLite3Cell8);

procedure sqlite3_finalize_cell16(
  var ACell: TDISQLite3Cell16);

function sqlite3_pragma_database(
  const ADataBase: Utf8String): Utf8String;

function sqlite3_pragma_database16(
  const ADataBase: UnicodeString): UnicodeString;

function sqlite3_pragma_get_encoding(
  const ADb: sqlite3;
  out AEncoding: Utf8String;
  const ADatabaseName: Utf8String{$IFDEF SUPPORTS_DEFAULTPARAMS} = ''{$ENDIF}): Integer;

function strcmp(l, r: PAnsiChar): Integer; {$IFDEF SUPPORTS_DEPRECATED}deprecated; {$ENDIF}

function TimeToJulianDate(const ATime: TDateTime): TDIJulianDate; {$IFDEF SUPPORTS_DEPRECATED}deprecated; {$ENDIF}

type

  TDITextLineBreakStyle = (tlbsLF, tlbsCRLF, tlbsCR);

function WideAdjustLineBreaks(
  const s: UnicodeString;
  const Style: TDITextLineBreakStyle{$IFDEF SUPPORTS_DEFAULTPARAMS} = tlbsCRLF{$ENDIF}): UnicodeString;

function WideDeleteFile(const AFileName: UnicodeString): Boolean;

function WideExtractFileName(const FileName: UnicodeString): UnicodeString;

function WideStrCmp(l, r: PWideChar): Integer;

function YmdToJulianDate(const AYear, AMonth, ADay: Integer): TDIJulianDate; {$IFDEF SUPPORTS_DEPRECATED}deprecated; {$ENDIF}

const

  SQLITE3_AFFINITY_TO_TYPE: array[TDISQLite3Affinity] of Integer = (
    SQLITE_INTEGER,
    SQLITE_TEXT,
    SQLITE_BLOB,
    SQLITE_FLOAT,
    SQLITE_FLOAT);

type

  TJulianDate = DISQLite3Api.TDIJulianDate;

resourcestring

  SCannotWriteStreamError = 'Cannot write to a read-only stream';
  SDatabaseClosed = 'Cannot perform this operation on a closed database';
  SDatabaseNameMissing = 'Database name missing';
  SDatabaseOpen = 'Cannot perform this operation on an open database';
  SEmptySQLStatement = 'Empty SQL Statement';
  SMissingDatabase = 'Missing dabatase';
  SMissingDataSet = 'Missing dataset';
  SStatementClosed = 'Cannot perform this operation on a closed statement';
  SStatementOpen = 'Cannot perform this operation on an open statement';

  {$IFNDEF COMPILER_6_UP}
  SStreamSetSize = 'Error setting stream size';
  {$ENDIF !COMPILER_6_UP}

implementation

uses
  Windows, {$IFDEF COMPILER_6_UP}RTLConsts{$ELSE}Consts{$ENDIF}, SysUtils
  ;

const
  BOOLEAN_TO_ANSICHAR: array[Boolean] of AnsiChar = ('0', '1');
  BOOLEAN_TO_WIDECHAR: array[Boolean] of WideChar = ('0', '1');

  WC_SPACE = WideChar(#$0020);

  WC_FULL_STOP = WideChar(#$002E);

  WC_SOLIDUS = WideChar(#$002F);

  WC_COLON = WideChar(#$003A);

  WC_REVERSE_SOLIDUS = WideChar(#$005C);

  WC_REPLACEMENT_CHARACTER = WideChar(#$FFFD);

  WC_DRIVE_DELIMITER: WideChar = WideChar(WC_COLON);

  WC_DOS_PATH_DELIMITER = WC_REVERSE_SOLIDUS;
  WC_UNIX_PATH_DELIMITER = WC_SOLIDUS;
  WC_PATH_DELIMITER =
    {$IFDEF MSWINDOWS}WC_DOS_PATH_DELIMITER{$ENDIF}
  {$IFDEF CLR}WC_DOS_PATH_DELIMITER{$ENDIF}
  {$IFDEF LINUX}WC_UNIX_PATH_DELIMITER{$ENDIF};

  WideLineSeparator = WideChar($2028);

var
  IsUnicode: Boolean;

function DateToJulianDate(const ADate: TDateTime): TDIJulianDate;
begin
  Result := DISQLite3Api.DateToJulianDate(ADate);
end;

function DateTimeToJulianDate(const ADateTime: TDateTime): TDIJulianDate;
begin
  Result := DISQLite3Api.DateTimeToJulianDate(ADateTime);
end;

function HmsToJulianDate(const AHour, AMinute, ASecond: Integer): TDIJulianDate;
begin
  Result := DISQLite3Api.HmsToJulianDate(AHour, AMinute, ASecond);
end;

function JulianDateToDate(const AJulianDate: TDIJulianDate): TDateTime;
begin
  Result := DISQLite3Api.JulianDateToDate(AJulianDate);
end;

function JulianDateToDateTime(const AJulianDate: TDIJulianDate): TDateTime;
begin
  Result := DISQLite3Api.JulianDateToDateTime(AJulianDate);
end;

function JulianDateToTime(const AJulianDate: TDIJulianDate): TDateTime;
begin
  Result := DISQLite3Api.JulianDateToTime(AJulianDate);
end;

procedure JulianDateToHms(const AJulianDate: TDIJulianDate; out AHour, AMinute, ASecond: Integer);
begin
  DISQLite3Api.JulianDateToHms(AJulianDate, AHour, AMinute, ASecond);
end;

procedure JulianDateToYmd(const AJulianDate: TDIJulianDate; out AYear, AMonth, ADay: Integer);
begin
  DISQLite3Api.JulianDateToYmd(AJulianDate, AYear, AMonth, ADay);
end;

function strcmp(l, r: PAnsiChar): Integer;
begin
  Result := DISQLite3Api.strcmp(l, r);
end;

function TimeToJulianDate(const ATime: TDateTime): TDIJulianDate;
begin
  Result := DISQLite3Api.TimeToJulianDate(ATime);
end;

function WideAdjustLineBreaksLength(
  const s: UnicodeString;
  const Style: TDITextLineBreakStyle{$IFDEF SUPPORTS_DEFAULTPARAMS} = tlbsCRLF{$ENDIF}): Cardinal;
var
  l: Cardinal;
  Source: PWideChar;
begin
  Source := Pointer(s);
  Result := Length(s);
  l := Result;
  while l > 0 do
    begin
      case Source^ of
        #10, WideLineSeparator:
          if Style = tlbsCRLF then
            Inc(Result);
        #13:
          if (l > 1) and (Source[1] = #10) then
            begin
              Inc(Source); Dec(l);
              if Style <> tlbsCRLF then
                Dec(Result)
            end
          else
            if Style = tlbsCRLF then
              Inc(Result);
      end;
      Inc(Source); Dec(l);
    end;
end;

function WideAdjustLineBreaks(
  const s: UnicodeString;
  const Style: TDITextLineBreakStyle{$IFDEF SUPPORTS_DEFAULTPARAMS} = tlbsCRLF{$ENDIF}): UnicodeString;
label
  OutputLineBreak;
var
  l: Integer;
  Source, Dest: PWideChar;
begin
  SetString(Result, nil, WideAdjustLineBreaksLength(s, Style));
  Dest := Pointer(Result);

  Source := Pointer(s);
  l := Length(s);
  while l > 0 do
    begin
      case Source^ of
        #10, WideLineSeparator:
          begin
            goto OutputLineBreak;
          end;
        #13:
          begin
            if (l > 1) and (Source[1] = #10) then
              begin
                Inc(Source); Dec(l);
              end;
            OutputLineBreak:
            if Style in [tlbsCRLF, tlbsCR] then
              begin
                Dest^ := #13;
                Inc(Dest);
              end;
            if Style in [tlbsCRLF, tlbsLF] then
              begin
                Dest^ := #10;
                Inc(Dest);
              end;
          end;
      else
        Dest^ := Source^;
        Inc(Dest);
      end;
      Inc(Source); Dec(l);
    end;
end;

function WideStrCmp(l, r: PWideChar): Integer;
begin
  if l = r then
    Result := 0
  else
    if not Assigned(l) then
      Result := -1
    else
      if not Assigned(r) then
        Result := 1
      else
        begin
          repeat
            if l[0] = r[0] then
              begin
                if l[0] = #0 then Break;
                if l[1] = r[1] then
                  begin
                    if l[1] = #0 then Break;
                    if l[2] = r[2] then
                      begin
                        if l[2] = #0 then Break;
                        if l[3] = r[3] then
                          begin
                            if l[3] = #0 then Break;
                            Inc(l, 4); Inc(r, 4);
                          end
                        else
                          begin
                            Result := Ord(l[3]) - Ord(r[3]);
                            Exit;
                          end;
                      end
                    else
                      begin
                        Result := Ord(l[2]) - Ord(r[2]);
                        Exit;
                      end;
                  end
                else
                  begin
                    Result := Ord(l[1]) - Ord(r[1]);
                    Exit;
                  end;
              end
            else
              begin
                Result := Ord(l[0]) - Ord(r[0]);
                Exit;
              end;
          until False;
          Result := 0;
        end;
end;

function WideChangeFileExt(const FileName, Extension: UnicodeString): UnicodeString;
label
  NoExtension;
var
  p: PWideChar;
  i, l: Cardinal;
begin
  l := Length(FileName);
  if l > 0 then
    begin
      i := l;
      p := Pointer(FileName);
      Inc(p, i);
      repeat
        Dec(i);
        Dec(p);
        if p^ = WC_FULL_STOP then Break;
        if i = 0 then goto NoExtension;
        if p^ = WC_PATH_DELIMITER then goto NoExtension;
        if p^ = WC_DRIVE_DELIMITER then goto NoExtension;
      until False;
      Result := Copy(FileName, 1, i) + Extension;
      Exit;
    end;

  NoExtension:
  Result := FileName + Extension;
end;

function WideDeleteFile(const AFileName: UnicodeString): Boolean;
begin
  if IsUnicode then
    Result := DeleteFileW(PWideChar(AFileName))
  else
    Result := SysUtils.DeleteFile(AFileName);
end;

function WideExtractFileName(const FileName: UnicodeString): UnicodeString;
var
  l, Start: Cardinal;
begin
  l := Length(FileName);
  if l > 0 then
    begin
      Start := l;
      while (Start > 0) and (FileName[Start] <> WC_PATH_DELIMITER) and (FileName[Start] <> WC_COLON) do
        Dec(Start);
      SetString(Result, PWideChar(Pointer(FileName)) + Start, l - Start);
    end
  else
    Result := '';
end;

function WideFileExists(const AFileName: UnicodeString): Boolean;
var
  Code: Cardinal;
begin
  if IsUnicode then
    begin
      Code := GetFileAttributesW(Pointer(AFileName));
      Result := (Code <> $FFFFFFFF) and (Code and FILE_ATTRIBUTE_DIRECTORY = 0);
    end
  else
    Result := FileExists(AFileName);
end;

function WideExpandFileName(const AFileName: UnicodeString): UnicodeString;
var
  Required: Cardinal;
begin
  if IsUnicode then
    begin
      Required := GetFullPathNameW(Pointer(AFileName), 0, nil, PWideChar(nil^));
      SetString(Result, nil, Required - 1);
      GetFullPathNameW(Pointer(AFileName), Required, Pointer(Result), PWideChar(nil^));
      SetLength(Result, DISQLite3Api.StrLen16(PWideChar(Result)));
    end
  else
    Result := ExpandFileName(AFileName);
end;

function YmdToJulianDate(const AYear, AMonth, ADay: Integer): TDIJulianDate;
begin
  Result := DISQLite3Api.YmdToJulianDate(AYear, AMonth, ADay);
end;

function sqlite3_cell16_as_ansistring(const ACell: TDISQLite3Cell16): AnsiString;
var
  l: Integer;
begin
  with ACell do
    case CellType of
      SQLITE_INTEGER:
        Result := AnsiString({$IFDEF SUPPORTS_INT64}IntToStr(CellInteger){$ELSE}FloatToSqlStr(CellInteger, '.', 15, 0){$ENDIF});
      SQLITE_FLOAT:
        Result := AnsiString(FloatToSqlStr(CellFloat{$IFNDEF SUPPORTS_DEFAULTPARAMS}, '.', 15, 9999{$ENDIF}));
      SQLITE_TEXT:
        begin
          l := WideCharToMultiByte(CP_ACP, 0, CellText.p, CellText.l, nil, 0, nil, nil);
          SetLength(Result, l);
          WideCharToMultiByte(CP_ACP, 0, CellText.p, CellText.l, PAnsiChar(Result), l, nil, nil);
        end;
    else
      Result := '';
    end;
end;

function sqlite3_cell16_as_date(const ACell: TDISQLite3Cell16): TDateTime;
begin
  Result := DISQLite3Api.JulianDateToDate(sqlite3_cell16_as_float(ACell));
end;

function sqlite3_cell16_as_datetime(const ACell: TDISQLite3Cell16): TDateTime;
begin
  Result := DISQLite3Api.JulianDateToDateTime(sqlite3_cell16_as_float(ACell));
end;

function sqlite3_cell16_as_float(const ACell: TDISQLite3Cell16): Double;
begin
  with ACell do
    case CellType of
      SQLITE_INTEGER:
        Result := CellInteger;
      SQLITE_FLOAT:
        Result := CellFloat;
      SQLITE_TEXT:
        Result := SqlBufToFloatDef16(CellText.p, CellText.l, 0{$IFNDEF SUPPORTS_DEFAULTPARAMS}, '.'{$ENDIF});
    else
      Result := 0;
    end;
end;

function sqlite3_cell16_as_integer(const ACell: TDISQLite3Cell16): Integer;
begin
  with ACell do
    case CellType of
      SQLITE_INTEGER:
        Result := {$IFDEF SUPPORTS_INT64}CellInteger{$ELSE}Trunc(CellInteger){$ENDIF};
      SQLITE_FLOAT:
        Result := Trunc(CellFloat);
      SQLITE_TEXT:
        Result := StrToIntDef(CellText.p, 0);
    else
      Result := 0;
    end;
end;

function sqlite3_cell16_as_int64(const ACell: TDISQLite3Cell16): Int64;
begin
  with ACell do
    case CellType of
      SQLITE_INTEGER:
        Result := CellInteger;
      SQLITE_FLOAT:
        Result := Trunc(CellFloat);
      SQLITE_TEXT:
        Result := {$IFDEF SUPPORTS_INT64}StrToInt64Def(CellText.p, 0){$ELSE}SqlBufToFloatDef16(CellText.p, CellText.l, 0, '.'){$ENDIF};
    else
      Result := 0;
    end;
end;

function sqlite3_cell16_as_time(const ACell: TDISQLite3Cell16): TDateTime;
begin
  Result := DISQLite3Api.JulianDateToTime(sqlite3_cell16_as_float(ACell));
end;

function sqlite3_cell16_as_widestring(const ACell: TDISQLite3Cell16): UnicodeString;
begin
  with ACell do
    case CellType of
      SQLITE_INTEGER:
        Result := {$IFDEF SUPPORTS_INT64}IntToStr(CellInteger){$ELSE}FloatToSqlStr(CellInteger, '.', 15, 0){$ENDIF};
      SQLITE_FLOAT:
        Result := sqlite3_decode_utf8(FloatToSqlStr(CellFloat{$IFNDEF SUPPORTS_DEFAULTPARAMS}, '.', 15, 9999{$ENDIF}));
      SQLITE_TEXT:
        SetString(Result, CellText.p, CellText.l);
    else
      Result := '';
    end;
end;

function sqlite3_pragma_database(const ADataBase: Utf8String): Utf8String;
begin
  Result := 'PRAGMA ';
  if sqlite3_database_type(ADataBase) <> dtMain then
    Result := Result + DISQLite3Api.QuotedStr(ADataBase{$IFNDEF SUPPORTS_DEFAULTPARAMS}, SQLITE3_IDENTIFIER_QUOTE_CHAR{$ENDIF}) + '.';
end;

function sqlite3_pragma_database16(const ADataBase: UnicodeString): UnicodeString;
begin
  Result := 'PRAGMA ';
  if sqlite3_database_type16(ADataBase) <> dtMain then
    Result := Result + DISQLite3Api.QuotedStr16(ADataBase{$IFNDEF SUPPORTS_DEFAULTPARAMS}, SQLITE3_IDENTIFIER_QUOTE_CHAR{$ENDIF}) + '.';
end;

function sqlite3_exec_with_callback(
  const ADBHandle: sqlite3;
  const ASql: Utf8String;
  const ACallback: TDISQLite3_Callback_{$IFDEF SUPPORTS_DEFAULTPARAMS} = nil{$ENDIF};
  const AUserData: Pointer{$IFDEF SUPPORTS_DEFAULTPARAMS} = nil{$ENDIF}): Integer;
var
  CallbackResult: Boolean;
  SqlStart, SqlTail: PUtf8Char;
  SqlLength: Integer;
  Stmt: sqlite3_stmt;
begin
  if Assigned(ADBHandle) then
    begin
      SqlStart := Pointer(ASql);
      SqlLength := Length(ASql);
      repeat
        CallbackResult := True;

        Result := sqlite3_prepare_v2(ADBHandle, SqlStart, SqlLength, @Stmt, @SqlTail);
        if Result <> SQLITE_OK then
          Exit;

        if Assigned(Stmt) then
          begin
            Result := sqlite3_step(Stmt);
            if (Result and $FF = SQLITE_ROW) and Assigned(ACallback) then

              repeat
                CallbackResult := ACallback(Stmt, AUserData);
                if not CallbackResult then
                  Break;
                Result := sqlite3_step(Stmt);
              until Result and $FF <> SQLITE_ROW;
            Result := sqlite3_finalize(Stmt);
          end;

        if not CallbackResult then
          begin
            Result := SQLITE_ABORT;
            Break;
          end;
        Dec(SqlLength, SqlTail - SqlStart);
        if SqlLength = 0 then
          Break;
        SqlStart := SqlTail;
      until False;
    end
  else
    Result := SQLITE_MISUSE;
end;

function sqlite3_exec_with_callback16(
  const ADBHandle: sqlite3;
  const ASql: UnicodeString;
  const ACallback: TDISQLite3_Callback_;
  const AUserData: Pointer): Integer;
begin
  Result := sqlite3_exec_with_callback(
    ADBHandle,
    sqlite3_encode_utf8(ASql),
    ACallback,
    AUserData);
end;

function sqlite3_exec_once(
  const ADb: sqlite3;
  const ASql: Utf8String): Integer;
var
  e: Integer;
  Stmt: sqlite3_stmt;
begin
  if Assigned(ADb) then
    begin
      Result := sqlite3_prepare_v2(ADb, Pointer(ASql), Length(ASql), @Stmt, nil);
      if Result = SQLITE_OK then
        begin
          Result := sqlite3_step(Stmt);
          case Result and $FF of
            SQLITE_ROW, SQLITE_DONE:
              Result := SQLITE_OK;
          end;
          e := sqlite3_finalize(Stmt);
          if e <> SQLITE_OK then
            Result := e;
        end;
    end
  else
    Result := SQLITE_MISUSE;
end;

{$IFNDEF SQLITE_OMIT_UTF16}

function sqlite3_exec_once16(
  const ADb: sqlite3;
  const ASql: UnicodeString): Integer;
var
  e: Integer;
  Stmt: sqlite3_stmt;
begin
  if Assigned(ADb) then
    begin
      Result := sqlite3_prepare16_v2(ADb, Pointer(ASql), Length(ASql) * 2, @Stmt, nil);
      if Result = SQLITE_OK then
        begin
          Result := sqlite3_step(Stmt);
          case Result and $FF of
            SQLITE_ROW, SQLITE_DONE:
              Result := SQLITE_OK;
          end;
          e := sqlite3_finalize(Stmt);
          if e <> SQLITE_OK then
            Result := e;
        end;
    end
  else
    Result := SQLITE_MISUSE;
end;

{$ENDIF !SQLITE_OMIT_UTF16}

procedure sqlite3_init_cell8(out ACell: TDISQLite3Cell8);
begin
  FillChar(ACell, SizeOf(ACell), 0);
end;

procedure sqlite3_init_cell16(out ACell: TDISQLite3Cell16);
begin
  with ACell do
    begin
      CellType := 0;
      CellInteger := 0;
    end;
end;

procedure sqlite3_finalize_cell8(var ACell: TDISQLite3Cell8);
begin
  with ACell do
    begin

      case CellType of
        SQLITE_BLOB:
          FreeMem(CellBlob.p);
        SQLITE_TEXT:
          FreeMem(CellText.p);
      end;

      CellType := 0;
      CellInteger := 0;
    end;
end;

procedure sqlite3_finalize_cell16(var ACell: TDISQLite3Cell16);
begin
  with ACell do
    begin

      case CellType of
        SQLITE_BLOB:
          FreeMem(CellBlob.p);
        SQLITE_TEXT:
          FreeMem(CellText.p);
      end;

      CellType := 0;
      CellInteger := 0;
    end;
end;

function sqlite3_get_boolean_callback(
  const AStmt: sqlite3_stmt;
  const AUserData: Pointer): Boolean;
{$IFNDEF COMPILER_6_UP}type PBoolean = ^Boolean; {$ENDIF}
begin
  PBoolean(AUserData)^ := sqlite3_column_int(AStmt, 0) <> 0;
  Result := False;
end;

function sqlite3_get_boolean(
  const ADb: sqlite3;
  const ASql: Utf8String;
  out ABoolean: Boolean): Integer;
begin
  Result := sqlite3_exec_with_callback(ADb, ASql, sqlite3_get_boolean_callback, @ABoolean);
  if Result and $FF = SQLITE_ABORT then
    Result := SQLITE_OK
  else
    Result := SQLITE_NOTFOUND;
end;

function sqlite3_get_boolean16(
  const ADb: sqlite3;
  const ASql: UnicodeString;
  out ABoolean: Boolean): Integer;
begin
  Result := sqlite3_exec_with_callback16(ADb, ASql, sqlite3_get_boolean_callback, @ABoolean);
  if Result and $FF = SQLITE_ABORT then
    Result := SQLITE_OK
  else
    Result := SQLITE_NOTFOUND;
end;

function sqlite3_get_int_callback(
  const AStmt: sqlite3_stmt;
  const AUserData: Pointer): Boolean;
begin
  PInteger(AUserData)^ := sqlite3_column_int(AStmt, 0);
  Result := False;
end;

function sqlite3_get_int(
  const ADb: sqlite3;
  const ASql: Utf8String;
  out AInteger: Integer): Integer;
begin
  Result := sqlite3_exec_with_callback(ADb, ASql, sqlite3_get_int_callback, @AInteger);
  if Result and $FF = SQLITE_ABORT then
    Result := SQLITE_OK
  else
    Result := SQLITE_NOTFOUND;
end;

function sqlite3_get_int16(
  const ADb: sqlite3;
  const ASql: UnicodeString;
  out AInteger: Integer): Integer;
begin
  Result := sqlite3_exec_with_callback16(ADb, ASql, sqlite3_get_int_callback, @AInteger);
  if Result and $FF = SQLITE_ABORT then
    Result := SQLITE_OK
  else
    Result := SQLITE_NOTFOUND;
end;

function sqlite3_get_str_callback(
  const AStmt: sqlite3_stmt;
  const AUserData: Pointer): Boolean;
begin
  PUtf8String(AUserData)^ := sqlite3_column_str(AStmt, 0);
  Result := False;
end;

function sqlite3_get_str(
  const ADb: sqlite3;
  const ASql: Utf8String;
  out AValue: Utf8String): Integer;
begin
  Result := sqlite3_exec_with_callback(ADb, ASql, sqlite3_get_str_callback, @AValue);
  if Result and $FF = SQLITE_ABORT then
    Result := SQLITE_OK
  else
    Result := SQLITE_NOTFOUND;
end;

function sqlite3_get_str16_callback(
  const AStmt: sqlite3_stmt;
  const AUserData: Pointer): Boolean;
begin
  {$IFDEF SQLITE_OMIT_UTF16}
  PUnicodeString(AUserData)^ := sqlite3_decode_utf8(sqlite3_column_str(AStmt, 0));
  {$ELSE SQLITE_OMIT_UTF16}
  PUnicodeString(AUserData)^ := sqlite3_column_str16(AStmt, 0);
  {$ENDIF SQLITE_OMIT_UTF16}
  Result := False;
end;

function sqlite3_get_str16(
  const ADb: sqlite3;
  const ASql: UnicodeString;
  out AValue: UnicodeString): Integer;
begin
  Result := sqlite3_exec_with_callback16(ADb, ASql, sqlite3_get_str16_callback, @AValue);
  if Result and $FF = SQLITE_ABORT then
    Result := SQLITE_OK
  else
    Result := SQLITE_NOTFOUND;
end;

function sqlite3_get_pragma_boolean(
  const ADb: sqlite3;
  const APragma: Utf8String;
  out APragmaValue: Boolean;
  const ADatabaseName: Utf8String{$IFDEF SUPPORTS_DEFAULTPARAMS} = ''{$ENDIF}): Integer;
begin
  Result := sqlite3_get_boolean(ADb, sqlite3_pragma_database(ADatabaseName) + APragma + ';', APragmaValue);
end;

{$IFNDEF SQLITE_OMIT_UTF16}

function sqlite3_get_pragma_boolean16(
  const ADb: sqlite3;
  const APragma: UnicodeString;
  out APragmaValue: Boolean;
  const ADatabaseName: UnicodeString{$IFDEF SUPPORTS_DEFAULTPARAMS} = ''{$ENDIF}): Integer;
begin
  Result := sqlite3_get_boolean16(ADb, sqlite3_pragma_database16(ADatabaseName) + APragma + ';', APragmaValue);
end;

{$ENDIF !SQLITE_OMIT_UTF16}

function sqlite3_set_pragma_boolean(
  const ADb: sqlite3;
  const APragma: Utf8String;
  const APragmaValue: Boolean;
  const ADatabaseName: Utf8String{$IFDEF SUPPORTS_DEFAULTPARAMS} = ''{$ENDIF}): Integer;
const
  BOOLEAN_TO_UTF8STRING: array[Boolean] of Utf8String = ('0', '1');
begin
  Result := sqlite3_exec_with_callback(ADb, sqlite3_pragma_database(ADatabaseName) + APragma + '=' + BOOLEAN_TO_UTF8STRING[APragmaValue] + ';'{$IFNDEF SUPPORTS_DEFAULTPARAMS}, nil, nil{$ENDIF});
end;

{$IFNDEF SQLITE_OMIT_UTF16}

function sqlite3_set_pragma_boolean16(
  const ADb: sqlite3;
  const APragma: UnicodeString;
  const APragmaValue: Boolean;
  const ADatabaseName: UnicodeString{$IFDEF SUPPORTS_DEFAULTPARAMS} = ''{$ENDIF}): Integer;
begin
  Result := sqlite3_exec_once16(ADb, sqlite3_pragma_database16(ADatabaseName) + APragma + UnicodeString('=') + UnicodeString(BOOLEAN_TO_WIDECHAR[APragmaValue]) + ';');
end;
{$ENDIF !SQLITE_OMIT_UTF16}

function sqlite3_get_pragma_int(
  const ADb: sqlite3;
  const APragma: Utf8String;
  out APragmaValue: Integer;
  const ADatabaseName: Utf8String{$IFDEF SUPPORTS_DEFAULTPARAMS} = ''{$ENDIF}): Integer;
begin
  Result := sqlite3_get_int(ADb, sqlite3_pragma_database(ADatabaseName) + APragma + ';', APragmaValue);
end;

{$IFNDEF SQLITE_OMIT_UTF16}

function sqlite3_get_pragma_int16(
  const ADb: sqlite3;
  const APragma: UnicodeString;
  out APragmaValue: Integer;
  const ADatabaseName: UnicodeString{$IFDEF SUPPORTS_DEFAULTPARAMS} = ''{$ENDIF}): Integer;
begin
  Result := sqlite3_get_int16(ADb, sqlite3_pragma_database16(ADatabaseName) + APragma + ';', APragmaValue);
end;

{$ENDIF !SQLITE_OMIT_UTF16}

function sqlite3_set_pragma_int(
  const ADb: sqlite3;
  const APragma: Utf8String;
  const APragmaValue: Integer;
  const ADatabaseName: Utf8String{$IFDEF SUPPORTS_DEFAULTPARAMS} = ''{$ENDIF}): Integer;
begin
  Result := sqlite3_exec_once(ADb, sqlite3_pragma_database(ADatabaseName) + APragma + '=' + Utf8String(IntToStr(APragmaValue)) + ';');
end;

{$IFNDEF SQLITE_OMIT_UTF16}

function sqlite3_set_pragma_int16(
  const ADb: sqlite3;
  const APragma: UnicodeString;
  const APragmaValue: Integer;
  const ADatabaseName: UnicodeString{$IFDEF SUPPORTS_DEFAULTPARAMS} = ''{$ENDIF}): Integer;
begin
  Result := sqlite3_exec_once16(ADb, sqlite3_pragma_database16(ADatabaseName) + APragma + '=' + IntToStr(APragmaValue) + ';');
end;

{$ENDIF !SQLITE_OMIT_UTF16}

function sqlite3_get_pragma_str(
  const ADb: sqlite3;
  const APragma: Utf8String;
  out APragmaValue: Utf8String;
  const ADatabaseName: Utf8String{$IFDEF SUPPORTS_DEFAULTPARAMS} = ''{$ENDIF}): Integer;
begin
  Result := sqlite3_get_str(ADb, sqlite3_pragma_database(ADatabaseName) + APragma + ';', APragmaValue);
end;

{$IFNDEF SQLITE_OMIT_UTF16}

function sqlite3_get_pragma_str16(
  const ADb: sqlite3;
  const APragma: UnicodeString;
  out APragmaValue: UnicodeString;
  const ADatabaseName: UnicodeString{$IFDEF SUPPORTS_DEFAULTPARAMS} = ''{$ENDIF}): Integer;
begin
  Result := sqlite3_get_str16(ADb, sqlite3_pragma_database16(ADatabaseName) + APragma + ';', APragmaValue);
end;

{$ENDIF !SQLITE_OMIT_UTF16}

function sqlite3_set_pragma_str(
  const ADb: sqlite3;
  const APragma: Utf8String;
  const APragmaValue: Utf8String;
  const ADatabaseName: Utf8String{$IFDEF SUPPORTS_DEFAULTPARAMS} = ''{$ENDIF}): Integer;
begin
  Result := sqlite3_exec_with_callback(ADb, sqlite3_pragma_database(ADatabaseName) + APragma + '=' + DISQLite3Api.QuotedStr(APragmaValue, '''') + ';'{$IFNDEF SUPPORTS_DEFAULTPARAMS}, nil, nil{$ENDIF});
end;

{$IFNDEF SQLITE_OMIT_UTF16}

function sqlite3_pragma_set_str16(
  const ADb: sqlite3;
  const APragma: UnicodeString;
  const APragmaValue: UnicodeString;
  const ADatabaseName: UnicodeString{$IFDEF SUPPORTS_DEFAULTPARAMS} = ''{$ENDIF}): Integer;
begin
  Result := sqlite3_exec_once16(ADb, sqlite3_pragma_database16(ADatabaseName) + APragma + '=' + DISQLite3Api.QuotedStr16(APragmaValue, '''') + ';');
end;

{$ENDIF !SQLITE_OMIT_UTF16}

function sqlite3_get_default_cache_size(
  const ADb: sqlite3;
  out ADefaultCacheSize: Integer;
  const ADatabaseName: Utf8String{$IFDEF SUPPORTS_DEFAULTPARAMS} = ''{$ENDIF}): Integer;
begin
  Result := sqlite3_get_pragma_int(ADb, 'default_cache_size', ADefaultCacheSize, ADatabaseName);
end;

{$IFNDEF SQLITE_OMIT_UTF16}

function sqlite3_get_default_cache_size16(
  const ADb: sqlite3;
  out ADefaultCacheSize: Integer;
  const ADatabaseName: UnicodeString{$IFDEF SUPPORTS_DEFAULTPARAMS} = ''{$ENDIF}): Integer;
begin
  Result := sqlite3_get_pragma_int16(ADb, 'default_cache_size', ADefaultCacheSize, ADatabaseName);
end;

{$ENDIF !SQLITE_OMIT_UTF16}

function sqlite3_set_default_cache_size(
  const ADb: sqlite3;
  const ADefaultCacheSize: Integer;
  const ADatabaseName: Utf8String{$IFDEF SUPPORTS_DEFAULTPARAMS} = ''{$ENDIF}): Integer;
begin
  Result := sqlite3_set_pragma_int(ADb, 'default_cache_size', ADefaultCacheSize, ADatabaseName);
end;

{$IFNDEF SQLITE_OMIT_UTF16}

function sqlite3_set_default_cache_size16(
  const ADb: sqlite3;
  const ADefaultCacheSize: Integer;
  const ADatabaseName: UnicodeString{$IFDEF SUPPORTS_DEFAULTPARAMS} = ''{$ENDIF}): Integer;
begin
  Result := sqlite3_set_pragma_int16(ADb, 'default_cache_size', ADefaultCacheSize, ADatabaseName);
end;

{$ENDIF !SQLITE_OMIT_UTF16}

function sqlite3_get_empty_result_callbacks(
  const ADb: sqlite3;
  out AEmptyResultCallbacks: Boolean): Integer;
begin
  Result := sqlite3_get_pragma_boolean(ADb, 'empty_result_callbacks', AEmptyResultCallbacks{$IFNDEF SUPPORTS_DEFAULTPARAMS}, ''{$ENDIF});
end;

function sqlite3_set_empty_result_callbacks(
  const ADb: sqlite3;
  const AEmptyResultCallbacks: Boolean): Integer;
begin
  Result := sqlite3_set_pragma_boolean(ADb, 'empty_result_callbacks', AEmptyResultCallbacks{$IFNDEF SUPPORTS_DEFAULTPARAMS}, ''{$ENDIF});
end;

function sqlite3_pragma_get_encoding(
  const ADb: sqlite3;
  out AEncoding: Utf8String;
  const ADatabaseName: Utf8String{$IFDEF SUPPORTS_DEFAULTPARAMS} = ''{$ENDIF}): Integer;
begin
  Result := sqlite3_get_pragma_str(ADb, 'encoding', AEncoding, ADatabaseName);
end;

{$IFNDEF SQLITE_OMIT_UTF16}

function sqlite3_pragma_get_encoding16(
  const ADb: sqlite3;
  out AEncoding: UnicodeString;
  const ADatabaseName: UnicodeString{$IFDEF SUPPORTS_DEFAULTPARAMS} = ''{$ENDIF}): Integer;
begin
  Result := sqlite3_get_pragma_str16(ADb, 'encoding', AEncoding, ADatabaseName);
end;

{$ENDIF !SQLITE_OMIT_UTF16}

function sqlite3_set_encoding(
  const ADb: sqlite3;
  const AEncoding: Utf8String;
  const ADatabaseName: Utf8String{$IFDEF SUPPORTS_DEFAULTPARAMS} = ''{$ENDIF}): Integer;
begin
  Result := sqlite3_set_pragma_str(ADb, 'encoding', AEncoding, ADatabaseName);
end;

{$IFNDEF SQLITE_OMIT_UTF16}

function sqlite3_set_encoding16(
  const ADb: sqlite3;
  const AEncoding: UnicodeString;
  const ADatabaseName: UnicodeString{$IFDEF SUPPORTS_DEFAULTPARAMS} = ''{$ENDIF}): Integer;
begin
  Result := sqlite3_pragma_set_str16(ADb, 'encoding', AEncoding, ADatabaseName);
end;

{$ENDIF !SQLITE_OMIT_UTF16}

function sqlite3_get_schema_version(
  const ADb: sqlite3;
  out ASchemaVersion: Integer;
  const ADatabaseName: Utf8String{$IFDEF SUPPORTS_DEFAULTPARAMS} = ''{$ENDIF}): Integer;
begin
  Result := sqlite3_get_pragma_int(ADb, 'schema_version', ASchemaVersion, ADatabaseName);
end;

{$IFNDEF SQLITE_OMIT_UTF16}

function sqlite3_get_schema_version16(
  const ADb: sqlite3;
  out ASchemaVersion: Integer;
  const ADatabaseName: UnicodeString{$IFDEF SUPPORTS_DEFAULTPARAMS} = ''{$ENDIF}): Integer;
begin
  Result := sqlite3_get_pragma_int16(ADb, 'schema_version', ASchemaVersion, ADatabaseName);
end;

{$ENDIF !SQLITE_OMIT_UTF16}

function sqlite3_set_schema_version(
  const ADb: sqlite3;
  const ASchemaVersion: Integer;
  const ADatabaseName: Utf8String{$IFDEF SUPPORTS_DEFAULTPARAMS} = ''{$ENDIF}): Integer;
begin
  Result := sqlite3_set_pragma_int(ADb, 'schema_version', ASchemaVersion, ADatabaseName);
end;

{$IFNDEF SQLITE_OMIT_UTF16}

function sqlite3_set_schema_version16(
  const ADb: sqlite3;
  const ASchemaVersion: Integer;
  const ADatabaseName: UnicodeString{$IFDEF SUPPORTS_DEFAULTPARAMS} = ''{$ENDIF}): Integer;
begin
  Result := sqlite3_set_pragma_int16(ADb, 'schema_version', ASchemaVersion, ADatabaseName);
end;

{$ENDIF !SQLITE_OMIT_UTF16}

function sqlite3_get_user_version(
  const ADb: sqlite3;
  out AUserVersion: Integer;
  const ADatabaseName: Utf8String{$IFDEF SUPPORTS_DEFAULTPARAMS} = ''{$ENDIF}): Integer;
begin
  Result := sqlite3_get_pragma_int(ADb, 'user_version', AUserVersion, ADatabaseName);
end;

{$IFNDEF SQLITE_OMIT_UTF16}

function sqlite3_get_user_version16(
  const ADb: sqlite3;
  out AUserVersion: Integer;
  const ADatabaseName: UnicodeString{$IFDEF SUPPORTS_DEFAULTPARAMS} = ''{$ENDIF}): Integer;
begin
  Result := sqlite3_get_pragma_int16(ADb, 'user_version', AUserVersion, ADatabaseName);
end;

{$ENDIF !SQLITE_OMIT_UTF16}

function sqlite3_set_user_version(
  const ADb: sqlite3;
  const AUserVersion: Integer;
  const ADatabaseName: Utf8String{$IFDEF SUPPORTS_DEFAULTPARAMS} = ''{$ENDIF}): Integer;
begin
  Result := sqlite3_set_pragma_int(ADb, 'user_version', AUserVersion, ADatabaseName);
end;

{$IFNDEF SQLITE_OMIT_UTF16}

function sqlite3_pragma_set_user_version16(
  const ADb: sqlite3;
  const AUserVersion: Integer;
  const ADatabaseName: UnicodeString{$IFDEF SUPPORTS_DEFAULTPARAMS} = ''{$ENDIF}): Integer;
begin
  Result := sqlite3_set_pragma_int16(ADb, 'user_version', AUserVersion, ADatabaseName);
end;

{$ENDIF !SQLITE_OMIT_UTF16}

function sqlite3_get_auto_vacuum(
  const ADb: sqlite3;
  out AAutoVacuum: Boolean;
  const ADatabaseName: Utf8String{$IFDEF SUPPORTS_DEFAULTPARAMS} = ''{$ENDIF}): Integer;
begin
  Result := sqlite3_get_pragma_boolean(ADb, 'auto_vacuum', AAutoVacuum, ADatabaseName);
end;

{$IFNDEF SQLITE_OMIT_UTF16}

function sqlite3_get_auto_vacuum16(
  const ADb: sqlite3;
  out AAutoVacuum: Boolean;
  const ADatabaseName: UnicodeString{$IFDEF SUPPORTS_DEFAULTPARAMS} = ''{$ENDIF}): Integer;
begin
  Result := sqlite3_get_pragma_boolean16(ADb, 'auto_vacuum', AAutoVacuum, ADatabaseName);
end;

{$ENDIF !SQLITE_OMIT_UTF16}

function sqlite3_set_auto_vacuum(
  const ADb: sqlite3;
  const AAutoVacuum: Boolean;
  const ADatabaseName: Utf8String{$IFDEF SUPPORTS_DEFAULTPARAMS} = ''{$ENDIF}): Integer;
begin
  Result := sqlite3_set_pragma_boolean(ADb, 'auto_vacuum', AAutoVacuum, ADatabaseName);
end;

{$IFNDEF SQLITE_OMIT_UTF16}

function sqlite3_set_auto_vacuum16(
  const ADb: sqlite3;
  const AAutoVacuum: Boolean;
  const ADatabaseName: UnicodeString{$IFDEF SUPPORTS_DEFAULTPARAMS} = ''{$ENDIF}): Integer;
begin
  Result := sqlite3_set_pragma_boolean16(ADb, 'auto_vacuum', AAutoVacuum, ADatabaseName);
end;

{$ENDIF !SQLITE_OMIT_UTF16}

function sqlite3_get_cache_size(
  const ADb: sqlite3;
  out ACacheSize: Integer;
  const ADatabaseName: Utf8String{$IFDEF SUPPORTS_DEFAULTPARAMS} = ''{$ENDIF}): Integer;
begin
  Result := sqlite3_get_pragma_int(ADb, 'cache_size', ACacheSize, ADatabaseName);
end;

{$IFNDEF SQLITE_OMIT_UTF16}

function sqlite3_get_cache_size16(
  const ADb: sqlite3;
  out ACacheSize: Integer;
  const ADatabaseName: UnicodeString{$IFDEF SUPPORTS_DEFAULTPARAMS} = ''{$ENDIF}): Integer;
begin
  Result := sqlite3_get_pragma_int16(ADb, 'cache_size', ACacheSize, ADatabaseName);
end;

{$ENDIF !SQLITE_OMIT_UTF16}

function sqlite3_pragma_set_cache_size(
  const ADb: sqlite3;
  const ACacheSize: Integer;
  const ADatabaseName: Utf8String{$IFDEF SUPPORTS_DEFAULTPARAMS} = ''{$ENDIF}): Integer;
begin
  Result := sqlite3_set_pragma_int(ADb, 'cache_size', ACacheSize, ADatabaseName);
end;

{$IFNDEF SQLITE_OMIT_UTF16}

function sqlite3_pragma_set_cache_size16(
  const ADb: sqlite3;
  const ACacheSize: Integer;
  const ADatabaseName: UnicodeString{$IFDEF SUPPORTS_DEFAULTPARAMS} = ''{$ENDIF}): Integer;
begin
  Result := sqlite3_set_pragma_int16(ADb, 'cache_size', ACacheSize, ADatabaseName);
end;

{$ENDIF !SQLITE_OMIT_UTF16}

function sqlite3_pragma_get_case_sensitive_like(
  const ADb: sqlite3;
  out ACaseSensitiveLike: Boolean): Integer;
begin
  Result := sqlite3_get_pragma_boolean(ADb, 'case_sensitive_like', ACaseSensitiveLike{$IFNDEF SUPPORTS_DEFAULTPARAMS}, ''{$ENDIF});
end;

function sqlite3_pragma_set_case_sensitive_like(
  const ADb: sqlite3;
  const ACaseSensitiveLike: Boolean): Integer;
begin
  Result := sqlite3_set_pragma_boolean(ADb, 'case_sensitive_like', ACaseSensitiveLike{$IFNDEF SUPPORTS_DEFAULTPARAMS}, ''{$ENDIF});
end;

function sqlite3_pragma_get_count_changes(
  const ADb: sqlite3;
  out ACountChanges: Boolean): Integer;
begin
  Result := sqlite3_get_pragma_boolean(ADb, 'count_changes', ACountChanges{$IFNDEF SUPPORTS_DEFAULTPARAMS}, ''{$ENDIF});
end;

function sqlite3_pragma_set_count_changes(
  const ADb: sqlite3;
  const ACountChanges: Boolean): Integer;
begin
  Result := sqlite3_set_pragma_boolean(ADb, 'count_changes', ACountChanges{$IFNDEF SUPPORTS_DEFAULTPARAMS}, ''{$ENDIF});
end;

function sqlite3_integrity_check(
  const ADb: sqlite3;
  const ADatabaseName: Utf8String{$IFDEF SUPPORTS_DEFAULTPARAMS} = ''{$ENDIF}): Integer;
var
  s: Utf8String;
begin
  Result := sqlite3_get_pragma_str(ADb, 'integrity_check', s, ADatabaseName);
  if (Result = SQLITE_OK) and (s <> 'ok') then
    Result := SQLITE_ERROR;
end;

{$IFNDEF SQLITE_OMIT_UTF16}
function sqlite3_integrity_check16(
  const ADb: sqlite3;
  const ADatabaseName: UnicodeString{$IFDEF SUPPORTS_DEFAULTPARAMS} = ''{$ENDIF}): Integer;
var
  s: UnicodeString;
begin
  Result := sqlite3_get_pragma_str16(ADb, 'integrity_check', s, ADatabaseName);
  if (Result = SQLITE_OK) and (s <> 'ok') then
    Result := SQLITE_ERROR;
end;

{$ENDIF !SQLITE_OMIT_UTF16}

procedure DatabaseError(const AResStrRec: PResStringRec; const AObject: TObject{$IFDEF SUPPORTS_DEFAULTPARAMS} = nil{$ENDIF});
begin
  if AObject is TComponent then
    with AObject as TComponent do
      if Name <> '' then
        begin
          raise ESQLite3.Create({$IFNDEF SUPPORTS_DEFAULTPARAMS}SQLITE_ERROR, {$ENDIF}Format('%s: %s', [Name, LoadResString(AResStrRec)]));
          Exit;
        end;
  {$IFDEF COMPILER_5_UP}
  raise ESQLite3.CreateRes(AResStrRec);
  {$ELSE}
  raise ESQLite3.Create({$IFNDEF SUPPORTS_DEFAULTPARAMS}SQLITE_ERROR, {$ENDIF}LoadResString(AResStrRec));
  {$ENDIF}
end;

procedure DatabaseErrorFmt(const AResStrRec: PResStringRec; const AArgs: array of const; const AObject: TObject{$IFDEF SUPPORTS_DEFAULTPARAMS} = nil{$ENDIF});
begin
  if AObject is TComponent then
    with AObject as TComponent do
      if Name <> '' then
        begin
          raise ESQLite3.Create({$IFNDEF SUPPORTS_DEFAULTPARAMS}SQLITE_ERROR, {$ENDIF}Format('%s: %s', [Name, Format(LoadResString(AResStrRec), AArgs)]));
          Exit;
        end;
  {$IFDEF COMPILER_5_UP}
  raise ESQLite3.CreateResFmt(AResStrRec, AArgs);
  {$ELSE}
  raise ESQLite3.CreateFmt(LoadResString(AResStrRec), AArgs);
  {$ENDIF}
end;

constructor TDISQLite3Database.Create(AOwner: TComponent);
begin
  inherited;
  FStatements := TList.Create;
end;

destructor TDISQLite3Database.Destroy;
var
  i: Integer;
  Stmt: TDISQLite3Statement;
begin

  i := FStatements.Count - 1;
  while i >= 0 do
    begin
      Stmt := TDISQLite3Statement(FStatements[i]);
      Stmt.Active := False;
      Stmt.Database := nil;
      Dec(i);
    end;

  Connected := False;
  FStatements.Free;
  inherited;
end;

procedure TDISQLite3Database.AttachDataBase16(const ADatabaseName: UnicodeString; ADataBaseAlias: UnicodeString{$IFDEF SUPPORTS_DEFAULTPARAMS} = ''{$ENDIF});
var
  Stmt: TDISQLite3Statement;
begin
  CheckActive;
  CheckDatabaseName(ADatabaseName);

  if IsMemoryDatabaseName(ADatabaseName) and not WideFileExists(ADatabaseName) then
    raise EFOpenError.CreateFmt(SFOpenError, [WideExpandFileName(ADatabaseName)]);

  if ADataBaseAlias = '' then
    ADataBaseAlias := WideChangeFileExt(WideExtractFileName(ADatabaseName), '');

  Stmt := Prepare('ATTACH ? AS ?');
  try
    Stmt.Bind_Str16(1, ADatabaseName);
    Stmt.Bind_Str16(2, ADataBaseAlias);
    Stmt.Step;
  finally
    Stmt.Free;
  end;
end;

function TDISQLite3Database.Changes: Integer;
begin
  CheckActive;
  Result := sqlite3_changes(FHandle);
end;

function TDISQLite3Database.Check(const AErrorCode: Integer): Integer;
begin
  Result := AErrorCode;
  if Result <> SQLITE_OK then
    sqlite3_raise_exception(Result, FHandle);
end;

procedure TDISQLite3Database.CheckActive;
begin
  if not Assigned(FHandle) then
    DatabaseError(PResStringRec(@SDatabaseClosed), Self);
end;

procedure TDISQLite3Database.CheckDatabaseName(const ADatabaseName: UnicodeString);
var
  l: Integer;
  p: PWideChar;
begin
  l := Length(ADatabaseName);
  if l > 0 then
    begin
      p := Pointer(ADatabaseName);
      repeat
        if p^ > WC_SPACE then Exit;
        Inc(p); Dec(l);
      until l = 0;
    end;
  DatabaseError(PResStringRec(@SDatabaseNameMissing), Self);
end;

procedure TDISQLite3Database.CheckInactive;
begin
  if Assigned(FHandle) then
    DatabaseError(PResStringRec(@SDatabaseOpen), Self);
end;

procedure TDISQLite3Database.Close;
begin
  SetConnected(False);
end;

procedure TDISQLite3Database.CloseStatements;
var
  i: Integer;
  Stmt: TDISQLite3Statement;
begin
  for i := 0 to FStatements.Count - 1 do
    begin
      Stmt := TDISQLite3Statement(FStatements[i]);
      Stmt.Active := False;
    end;
end;

procedure TDISQLite3Database.Commit;
begin
  if InTransaction then
    begin
      if FTransactionCount = 1 then
        begin
          CheckActive;
          Check(sqlite3_exec_with_callback(FHandle, 'COMMIT TRANSACTION;'{$IFNDEF SUPPORTS_DEFAULTPARAMS}, nil, nil{$ENDIF}));
        end;
      Dec(FTransactionCount);
    end;
end;

procedure TDISQLite3Database.DetachDatabase(const ADataBaseAlias: Utf8String);
begin
  CheckActive;
  with Prepare('DETACH ?') do
    try
      Bind_Str(1, ADataBaseAlias);
      Step;
    finally
      Free;
    end;
end;

procedure TDISQLite3Database.DetachDatabase16(const ADataBaseAlias: UnicodeString);
begin
  DetachDatabase(sqlite3_encode_utf8(ADataBaseAlias));
end;

procedure TDISQLite3Database.DoAfterConnect;
begin
  if Assigned(FAfterConnect) then
    FAfterConnect(Self);
end;

procedure TDISQLite3Database.DoAfterCreateDatabase;
begin
  if Assigned(FAfterCreateDatabase) then
    FAfterCreateDatabase(Self);
end;

procedure TDISQLite3Database.DoAfterDisconnect;
begin
  if Assigned(FAfterDisconnect) then
    FAfterDisconnect(Self);
end;

procedure TDISQLite3Database.DoBeforeCreateDatabase;
begin
  if Assigned(FBeforeCreateDatabase) then
    FBeforeCreateDatabase(Self);
end;

procedure TDISQLite3Database.DoBeforeConnect;
begin
  if Assigned(FBeforeConnect) then
    FBeforeConnect(Self);
end;

procedure TDISQLite3Database.DoBeforeDisconnect;
begin
  if Assigned(FBeforeDisconnect) then
    FBeforeDisconnect(Self);
end;

procedure TDISQLite3Database.DoConnect;
var
  h: sqlite3;
  s8: Utf8String;
begin
  if not Assigned(FHandle) then
    begin
      CheckDatabaseName(FDataBaseName);
      s8 := sqlite3_encode_utf8(FDataBaseName);
      try
        Check(sqlite3_open_v2(PUtf8Char(s8), @FHandle, SQLITE_OPEN_READWRITE, nil));
      except

        on e: ESQLite3 do
          begin
            h := FHandle; FHandle := nil; sqlite3_close(h);
            if e.ErrorCode and $FF = SQLITE_CANTOPEN then
              raise EFOpenError.CreateFmt(SFOpenError, [WideExpandFileName(FDataBaseName)])
            else
              raise;
          end;
      else
        h := FHandle; FHandle := nil; sqlite3_close(h);
        raise;
      end;

      {$IFDEF SQLITE_HAS_CODEC}
      if FPassword <> '' then
        Check(sqlite3_key(FHandle, Pointer(FPassword), Length(FPassword)));
      {$ENDIF SQLITE_HAS_CODEC}
    end;
end;

procedure TDISQLite3Database.DoDisconnect;
var
  h: sqlite3;
begin
  if Assigned(FHandle) then
    begin
      CloseStatements;
      h := FHandle;
      FHandle := nil;
      Check(sqlite3_close(h));
    end;
end;

procedure TDISQLite3Database.DoInitDatabase;
begin
  if Assigned(FInitDatabase) then
    FInitDatabase(Self);
end;

function TDISQLite3Database.GetAutoVacuum: Boolean;
begin
  CheckActive;
  Check(sqlite3_get_auto_vacuum(FHandle, Result{$IFNDEF SUPPORTS_DEFAULTPARAMS}, ''{$ENDIF}))
end;

procedure TDISQLite3Database.SetAutoVacuum(const AValue: Boolean);
begin
  CheckActive;
  Check(sqlite3_set_auto_vacuum(FHandle, AValue{$IFNDEF SUPPORTS_DEFAULTPARAMS}, ''{$ENDIF}));
end;

function TDISQLite3Database.GetCacheSize: Integer;
begin
  CheckActive;
  Check(sqlite3_get_cache_size(FHandle, Result{$IFNDEF SUPPORTS_DEFAULTPARAMS}, ''{$ENDIF}));
end;

procedure TDISQLite3Database.SetCacheSize(const AValue: Integer);
begin
  CheckActive;
  Check(sqlite3_pragma_set_cache_size(FHandle, AValue{$IFNDEF SUPPORTS_DEFAULTPARAMS}, ''{$ENDIF}));
end;

procedure TDISQLite3Database.SetCaseSensitiveLike(const AValue: Boolean);
begin
  CheckActive;
  Check(sqlite3_pragma_set_case_sensitive_like(FHandle, AValue));
end;

function TDISQLite3Database.GetConnected: Boolean;
begin
  Result := Assigned(FHandle);
end;

function TDISQLite3Database.GetCountChanges: Boolean;
begin
  CheckActive;
  Check(sqlite3_pragma_get_count_changes(FHandle, Result))
end;

procedure TDISQLite3Database.SetCountChanges(const AValue: Boolean);
begin
  CheckActive;
  Check(sqlite3_pragma_set_count_changes(FHandle, AValue));
end;

function TDISQLite3Database.GetDefaultCacheSize: Integer;
begin
  CheckActive;
  Check(sqlite3_get_default_cache_size(FHandle, Result{$IFNDEF SUPPORTS_DEFAULTPARAMS}, ''{$ENDIF}))
end;

procedure TDISQLite3Database.SetDefaultCacheSize(const AValue: Integer);
begin
  CheckActive;
  Check(sqlite3_set_default_cache_size(FHandle, AValue{$IFNDEF SUPPORTS_DEFAULTPARAMS}, ''{$ENDIF}));
end;

function TDISQLite3Database.GetEmptyResultCallbacks: Boolean;
begin
  CheckActive;
  Check(sqlite3_get_empty_result_callbacks(FHandle, Result))
end;

procedure TDISQLite3Database.SetEmptyResultCallbacks(const AValue: Boolean);
begin
  CheckActive;
  Check(sqlite3_set_empty_result_callbacks(FHandle, AValue));
end;

function TDISQLite3Database.GetEncoding: UnicodeString;
{$IFDEF SQLITE_OMIT_UTF16}
var
  s8: Utf8String;
  {$ENDIF SQLITE_OMIT_UTF16}
begin
  CheckActive;
  {$IFDEF SQLITE_OMIT_UTF16}
  Check(sqlite3_pragma_get_encoding(FHandle, s8));
  Result := sqlite3_decode_utf8(s8);
  {$ELSE  SQLITE_OMIT_UTF16}
  Check(sqlite3_pragma_get_encoding16(FHandle, Result{$IFNDEF SUPPORTS_DEFAULTPARAMS}, ''{$ENDIF}));
  {$ENDIF  SQLITE_OMIT_UTF16}
end;

procedure TDISQLite3Database.SetEncoding(const AValue: UnicodeString);
begin
  CheckActive;
  {$IFDEF SQLITE_OMIT_UTF16}
  Check(sqlite3_set_encoding(FHandle, sqlite3_encode_utf8(AValue)));
  {$ELSE  SQLITE_OMIT_UTF16}
  Check(sqlite3_set_encoding16(FHandle, AValue{$IFNDEF SUPPORTS_DEFAULTPARAMS}, ''{$ENDIF}));
  {$ENDIF  SQLITE_OMIT_UTF16}
end;

function TDISQLite3Database.GetInTransaction: Boolean;
begin
  Result := FTransactionCount > 0;
end;

function TDISQLite3Database.GetPageSize: Integer;
begin
  CheckActive;
  Check(sqlite3_get_pragma_int(Handle, 'page_size', Result{$IFNDEF SUPPORTS_DEFAULTPARAMS}, ''{$ENDIF}));
end;

procedure TDISQLite3Database.SetPageSize(const AValue: Integer);
begin
  CheckActive;
  Check(sqlite3_set_pragma_int(Handle, 'page_size', AValue{$IFNDEF SUPPORTS_DEFAULTPARAMS}, ''{$ENDIF}));
end;

function TDISQLite3Database.GetStatementClass: TDISQLite3StatementClass;
begin
  Result := TDISQLite3Statement;
end;

function TDISQLite3Database.GetSQLiteVersion: UnicodeString;
begin
  Result := sqlite3_decode_utf8(sqlite3_libversion);
end;

procedure TDISQLite3Database.CreateDatabase;
var
  h: sqlite3;
  s8: Utf8String;
begin
  CheckInactive;
  CheckDatabaseName(FDataBaseName);
  if WideFileExists(FDataBaseName) and not WideDeleteFile(FDataBaseName) then
    raise EFCreateError.CreateFmt(SFCreateError, [WideExpandFileName(FDataBaseName)]);

  DoBeforeConnect;
  DoBeforeCreateDatabase;

  s8 := sqlite3_encode_utf8(FDataBaseName);
  try
    Check(sqlite3_open_v2(PUtf8Char(s8), @FHandle, SQLITE_OPEN_READWRITE or SQLITE_OPEN_CREATE, nil));
  except

    h := FHandle; FHandle := nil; sqlite3_close(h);
    raise;
  end;

  {$IFDEF SQLITE_HAS_CODEC}
  if FPassword <> '' then
    Check(sqlite3_key(FHandle, Pointer(FPassword), Length(FPassword)));
  {$ENDIF SQLITE_HAS_CODEC}

  DoInitDatabase;

  DoAfterCreateDatabase;
  DoAfterConnect;
end;

procedure TDISQLite3Database.Execute(const ASql: Utf8String);
begin
  CheckActive;
  Check(sqlite3_exec_with_callback(FHandle, ASql{$IFNDEF SUPPORTS_DEFAULTPARAMS}, nil, nil{$ENDIF}));
end;

procedure TDISQLite3Database.Execute16(const ASql: UnicodeString);
begin
  CheckActive;
  Check(sqlite3_exec_with_callback(FHandle, sqlite3_encode_utf8(ASql){$IFNDEF SUPPORTS_DEFAULTPARAMS}, nil, nil{$ENDIF}));
end;

function TDISQLite3Database.IntegrityCheck: Integer;
begin
  CheckActive;
  Result := sqlite3_integrity_check(FHandle{$IFNDEF SUPPORTS_DEFAULTPARAMS}, ''{$ENDIF});
end;

procedure TDISQLite3Database.Interrupt;
begin
  CheckActive;
  sqlite3_interrupt(FHandle);
end;

function TDISQLite3Database.IsMemoryDatabaseName(const ADatabaseName: UnicodeString): Boolean;
begin
  Result := (Length(ADatabaseName) = 8) and
    (ADatabaseName[1] = ':') and
    ((ADatabaseName[2] = 'M') or (ADatabaseName[2] = 'm')) and
    ((ADatabaseName[3] = 'E') or (ADatabaseName[3] = 'e')) and
    ((ADatabaseName[4] = 'M') or (ADatabaseName[4] = 'm')) and
    ((ADatabaseName[5] = 'O') or (ADatabaseName[5] = 'o')) and
    ((ADatabaseName[6] = 'R') or (ADatabaseName[6] = 'r')) and
    ((ADatabaseName[7] = 'Y') or (ADatabaseName[7] = 'y')) and
    (ADatabaseName[8] = ':');
end;

function TDISQLite3Database.LastInsertRowID: Int64;
begin
  CheckActive;
  Result := sqlite3_last_insert_rowid(FHandle);
end;

procedure TDISQLite3Database.Loaded;
begin
  inherited;
  try
    if FStreamedConnected then
      SetConnected(True);
  except
    if csDesigning in ComponentState then
      {$IFDEF COMPILER_6_UP}
      if Assigned(Classes.ApplicationHandleException) then
        Classes.ApplicationHandleException(ExceptObject)
      else
        {$ENDIF}
        ShowException(ExceptObject, ExceptAddr)
    else
      raise;
  end;
end;

procedure TDISQLite3Database.Open;
begin
  SetConnected(True);
end;

function TDISQLite3Database.Prepare(const ASql8: Utf8String): TDISQLite3Statement;
begin
  Result := GetStatementClass.Create;
  Result.Database := Self;
  Result.SQL8 := ASql8;
  try
    Result.Open;
  except
    Result.Free;
    raise;
  end;
end;

function TDISQLite3Database.Prepare16(const ASQL16: UnicodeString): TDISQLite3Statement;
begin
  Result := GetStatementClass.Create;
  Result.Database := Self;
  Result.SQL16 := ASQL16;
  try
    Result.Open;
  except
    Result.Free;
    raise;
  end;
end;

procedure TDISQLite3Database.RegisterStatement(const AStatement: TDISQLite3Statement);
begin
  if Assigned(AStatement) then
    FStatements.Add(AStatement);
end;

{$IFDEF SQLITE_HAS_CODEC}

procedure TDISQLite3Database.ReKey(const ANewPassword: RawByteString);
begin
  CheckActive;
  Check(sqlite3_rekey(FHandle, Pointer(ANewPassword), Length(ANewPassword)));
  FPassword := ANewPassword;
end;

{$ENDIF SQLITE_HAS_CODEC}

procedure TDISQLite3Database.Rollback;
begin
  if InTransaction then
    begin
      if FTransactionCount = 1 then
        begin
          CheckActive;
          Check(sqlite3_exec_with_callback(FHandle, 'ROLLBACK TRANSACTION;'{$IFNDEF SUPPORTS_DEFAULTPARAMS}, nil, nil{$ENDIF}));
        end;
      Dec(FTransactionCount);
    end;
end;

procedure TDISQLite3Database.SetConnected(const AValue: Boolean);
begin
  if (csReading in ComponentState) and AValue then
    FStreamedConnected := True
  else
    if AValue <> GetConnected then
      if AValue then
        begin
          DoBeforeConnect;
          DoConnect;
          DoInitDatabase;
          DoAfterConnect;
        end
      else
        begin
          DoBeforeDisconnect;
          DoDisconnect;
          DoAfterDisconnect;
        end;
end;

procedure TDISQLite3Database.SetDatabaseName(const AValue: UnicodeString);
begin
  CheckInactive;
  FDataBaseName := AValue;
end;

{$IFDEF SQLITE_HAS_CODEC}

procedure TDISQLite3Database.SetPassword(const AValue: RawByteString);
begin
  if Connected then
    begin
      Check(sqlite3_key(FHandle, Pointer(AValue), Length(AValue)));
    end;
  FPassword := AValue;
end;

{$ENDIF SQLITE_HAS_CODEC}

procedure TDISQLite3Database.SetSQLiteVersion(const Value: UnicodeString);
begin

end;

procedure TDISQLite3Database.StartTransaction(const ATransactionType: TDISQLite3TransactionType{$IFDEF SUPPORTS_DEFAULTPARAMS} = ttDeferred{$ENDIF});
const
  tt: array[TDISQLite3TransactionType] of Utf8String = ('DEFERRED', 'IMMEDIATE', 'EXCLUSIVE');
begin
  if not InTransaction then
    begin
      CheckActive;
      Check(sqlite3_exec_with_callback(FHandle, 'BEGIN ' + tt[ATransactionType] + ' TRANSACTION;'{$IFNDEF SUPPORTS_DEFAULTPARAMS}, nil, nil{$ENDIF}));
    end;
  Inc(FTransactionCount);
end;

function TDISQLite3Database.TotalChanges: Integer;
begin
  CheckActive;
  Result := sqlite3_total_changes(FHandle);
end;

procedure TDISQLite3Database.UnRegisterStatement(const AStatement: TDISQLite3Statement);
begin
  if Assigned(AStatement) then
    FStatements.Remove(AStatement);
end;

procedure TDISQLite3Database.Vacuum;
begin
  CheckActive;
  Check(sqlite3_exec_with_callback(FHandle, 'VACUUM;'{$IFNDEF SUPPORTS_DEFAULTPARAMS}, nil, nil{$ENDIF}));
end;

destructor TDISQLite3Statement.Destroy;
begin

  if Assigned(FHandle) then
    begin
      DoBeforeClose;

      sqlite3_finalize(FHandle);
      DoAfterClose;
    end;

  if Assigned(FDatabase) then
    FDatabase.UnRegisterStatement(Self);

  inherited;
end;

procedure TDISQLite3Statement.Assign(const ASource: TDISQLite3Statement);
begin
  Database := ASource.Database;
  SQL8 := ASource.SQL8;
end;

procedure TDISQLite3Statement.Bind_Blob(const AParamIdx: Integer; const ABlobData: Pointer; const ABlobSize: Integer; const ADestroy: TSQLite_Bind_Destructor);
begin
  CheckActive;
  Check(sqlite3_bind_blob(FHandle, AParamIdx, ABlobData, ABlobSize, ADestroy));
end;

procedure TDISQLite3Statement.bind_Blob_By_Name(const AParamName: Utf8String; const ABlobData: Pointer; const ABlobSize: Integer; const ADestroy: TSQLite_Bind_Destructor);
begin
  CheckActive;
  Check(sqlite3_bind_blob(FHandle, sqlite3_bind_parameter_index(FHandle, PUtf8Char(AParamName)), ABlobData, ABlobSize, ADestroy));
end;

procedure TDISQLite3Statement.bind_Blob_By_Name16(const AParamName: UnicodeString; const ABlobData: Pointer; const ABlobSize: Integer; const ADestroy: TSQLite_Bind_Destructor);
begin
  CheckActive;
  Check(sqlite3_bind_blob(FHandle, sqlite3_bind_parameter_index(FHandle, PUtf8Char(sqlite3_encode_utf8(AParamName))), ABlobData, ABlobSize, ADestroy));
end;

procedure TDISQLite3Statement.Bind_Double(const AParamIdx: Integer; const AValue: Double);
begin
  CheckActive;
  Check(sqlite3_bind_double(FHandle, AParamIdx, AValue));
end;

procedure TDISQLite3Statement.Bind_Double_By_Name(const AParamName: Utf8String; const AValue: Double);
begin
  CheckActive;
  Check(sqlite3_bind_double(FHandle, sqlite3_bind_parameter_index(FHandle, PUtf8Char(AParamName)), AValue));
end;

procedure TDISQLite3Statement.Bind_Double_By_Name16(const AParamName: UnicodeString; const AValue: Double);
begin
  CheckActive;
  Check(sqlite3_bind_double(FHandle, sqlite3_bind_parameter_index(FHandle, PUtf8Char(sqlite3_encode_utf8(AParamName))), AValue));
end;

procedure TDISQLite3Statement.Bind_Int(const AParamIdx: Integer; const AValue: Integer);
begin
  CheckActive;
  Check(sqlite3_bind_int(FHandle, AParamIdx, AValue));
end;

procedure TDISQLite3Statement.Bind_Int_By_Name(const AParamName: Utf8String; const AValue: Integer);
begin
  CheckActive;
  Check(sqlite3_bind_int(FHandle, sqlite3_bind_parameter_index(FHandle, PUtf8Char(AParamName)), AValue));
end;

procedure TDISQLite3Statement.Bind_Int_By_Name16(const AParamName: UnicodeString; const AValue: Integer);
begin
  CheckActive;
  Check(sqlite3_bind_int(FHandle, sqlite3_bind_parameter_index(FHandle, PUtf8Char(sqlite3_encode_utf8(AParamName))), AValue));
end;

procedure TDISQLite3Statement.Bind_Int64(const AParamIdx: Integer; const AValue: Int64);
begin
  CheckActive;
  Check(sqlite3_bind_int64(FHandle, AParamIdx, AValue));
end;

procedure TDISQLite3Statement.Bind_Int64_By_Name(const AParamName: Utf8String; const AValue: Int64);
begin
  CheckActive;
  Check(sqlite3_bind_int64(FHandle, sqlite3_bind_parameter_index(FHandle, PUtf8Char(AParamName)), AValue));
end;

procedure TDISQLite3Statement.Bind_Int64_By_Name16(const AParamName: UnicodeString; const AValue: Int64);
begin
  CheckActive;
  Check(sqlite3_bind_int64(FHandle, sqlite3_bind_parameter_index(FHandle, PUtf8Char(sqlite3_encode_utf8(AParamName))), AValue));
end;

procedure TDISQLite3Statement.Bind_Null(const AParamIdx: Integer);
begin
  CheckActive;
  Check(sqlite3_bind_null(FHandle, AParamIdx));
end;

procedure TDISQLite3Statement.Bind_Null_By_Name(const AParamName: Utf8String);
begin
  CheckActive;
  Check(sqlite3_bind_null(FHandle, sqlite3_bind_parameter_index(FHandle, PUtf8Char(AParamName))));
end;

procedure TDISQLite3Statement.Bind_Null_By_Name16(const AParamName: UnicodeString);
begin
  CheckActive;
  Check(sqlite3_bind_null(FHandle, sqlite3_bind_parameter_index(FHandle, PUtf8Char(sqlite3_encode_utf8(AParamName)))));
end;

function TDISQLite3Statement.Bind_Parameter_Count: Integer;
begin
  CheckActive;
  Result := sqlite3_bind_parameter_count(FHandle);
end;

function TDISQLite3Statement.bind_Parameter_Name(const AParamIdx: Integer): Utf8String;
begin
  CheckActive;
  Result := sqlite3_bind_parameter_name(FHandle, AParamIdx);
end;

function TDISQLite3Statement.Bind_Parameter_Name16(const AParamIdx: Integer): UnicodeString;
begin
  CheckActive;
  Result := sqlite3_decode_utf8(sqlite3_bind_parameter_name(FHandle, AParamIdx));
end;

function TDISQLite3Statement.Bind_Parameter_Index(const AParamName: Utf8String): Integer;
begin
  CheckActive;
  Result := sqlite3_bind_parameter_index(FHandle, PUtf8Char(AParamName));
end;

function TDISQLite3Statement.Bind_Parameter_Index16(const AParamName: UnicodeString): Integer;
begin
  CheckActive;
  Result := sqlite3_bind_parameter_index(FHandle, PUtf8Char(sqlite3_encode_utf8(AParamName)));
end;

procedure TDISQLite3Statement.Bind_Str(const AParamIdx: Integer; const AValue: Utf8String);
begin
  CheckActive;
  Check(sqlite3_bind_str(FHandle, AParamIdx, AValue));
end;

procedure TDISQLite3Statement.Bind_Str_By_Name(const AParamName: Utf8String; const AValue: Utf8String);
begin
  CheckActive;
  Check(sqlite3_bind_str(FHandle, Bind_Parameter_Index(AParamName), AValue));
end;

procedure TDISQLite3Statement.Bind_Str_By_Name16(const AParamName: UnicodeString; const AValue: Utf8String);
begin
  CheckActive;
  Check(sqlite3_bind_str(FHandle, sqlite3_bind_parameter_index(FHandle, PUtf8Char(sqlite3_encode_utf8(AParamName))), AValue));
end;

procedure TDISQLite3Statement.Bind_Str16(const AParamIdx: Integer; const AValue: UnicodeString);
begin
  CheckActive;
  {$IFDEF SQLITE_OMIT_UTF16}
  Check(sqlite3_bind_str(FHandle, AParamIdx, sqlite3_encode_utf8(AValue)));
  {$ELSE SQLITE_OMIT_UTF16}
  Check(sqlite3_bind_str16(FHandle, AParamIdx, AValue));
  {$ENDIF SQLITE_OMIT_UTF16}
end;

procedure TDISQLite3Statement.Bind_Str16_By_Name(const AParamName: Utf8String; const AValue: UnicodeString);
begin
  CheckActive;
  {$IFDEF SQLITE_OMIT_UTF16}
  Check(sqlite3_bind_str(FHandle, sqlite3_bind_parameter_index(FHandle, PUtf8Char(AParamName)), sqlite3_encode_utf8(AValue)));
  {$ELSE SQLITE_OMIT_UTF16}
  Check(sqlite3_bind_str16(FHandle, sqlite3_bind_parameter_index(FHandle, PUtf8Char(AParamName)), AValue));
  {$ENDIF SQLITE_OMIT_UTF16}
end;

procedure TDISQLite3Statement.Bind_Str16_By_Name16(const AParamName: UnicodeString; const AValue: UnicodeString);
begin
  CheckActive;
  {$IFDEF SQLITE_OMIT_UTF16}
  Check(sqlite3_bind_str(FHandle, sqlite3_bind_parameter_index(FHandle, PUtf8Char(sqlite3_encode_utf8(AParamName))), sqlite3_encode_utf8(AValue)));
  {$ELSE SQLITE_OMIT_UTF16}
  Check(sqlite3_bind_str16(FHandle, sqlite3_bind_parameter_index(FHandle, PUtf8Char(sqlite3_encode_utf8(AParamName))), AValue));
  {$ENDIF SQLITE_OMIT_UTF16}
end;

procedure TDISQLite3Statement.Bind_Text(
  const AParamIdx: Integer;
  const AValue: PUtf8Char;
  const AValueLen: Integer;
  const xDestroy: TSQLite_Bind_Destructor);
begin
  CheckActive;
  Check(sqlite3_bind_text(FHandle, AParamIdx, AValue, AValueLen, xDestroy));
end;

procedure TDISQLite3Statement.Bind_Text_By_Name(
  const AParamName: Utf8String;
  const AValue: PUtf8Char;
  const AValueLen: Integer;
  const xDestroy: TSQLite_Bind_Destructor);
begin
  CheckActive;
  Check(sqlite3_bind_text(FHandle, sqlite3_bind_parameter_index(FHandle, PUtf8Char(AParamName)), AValue, AValueLen, xDestroy));
end;

procedure TDISQLite3Statement.Bind_Text_By_Name16(
  const AParamName: UnicodeString;
  const AValue: PUtf8Char;
  const AValueLen: Integer;
  const xDestroy: TSQLite_Bind_Destructor);
begin
  CheckActive;
  Check(sqlite3_bind_text(FHandle, sqlite3_bind_parameter_index(FHandle, PUtf8Char(sqlite3_encode_utf8(AParamName))), AValue, AValueLen, xDestroy));
end;

{$IFNDEF SQLITE_OMIT_UTF16}
procedure TDISQLite3Statement.Bind_Text16(
  const AParamIdx: Integer;
  const AValue: PWideChar;
  const AValueLen: Integer;
  const xDestroy: TSQLite_Bind_Destructor);
begin
  CheckActive;
  Check(sqlite3_bind_text16(FHandle, AParamIdx, AValue, AValueLen, xDestroy));
end;
{$ENDIF SQLITE_OMIT_UTF16}

{$IFNDEF SQLITE_OMIT_UTF16}
procedure TDISQLite3Statement.Bind_Text16_By_Name(
  const AParamName: Utf8String;
  const AValue: PWideChar;
  const AValueLen: Integer;
  const xDestroy: TSQLite_Bind_Destructor);
begin
  CheckActive;
  Check(sqlite3_bind_text16(FHandle, sqlite3_bind_parameter_index(FHandle, PUtf8Char(AParamName)), AValue, AValueLen, xDestroy));
end;
{$ENDIF SQLITE_OMIT_UTF16}

{$IFNDEF SQLITE_OMIT_UTF16}
procedure TDISQLite3Statement.Bind_Text16_By_Name16(
  const AParamName: UnicodeString;
  const AValue: PWideChar;
  const AValueLen: Integer;
  const xDestroy: TSQLite_Bind_Destructor);
begin
  CheckActive;
  Check(sqlite3_bind_text16(FHandle, sqlite3_bind_parameter_index(FHandle, PUtf8Char(sqlite3_encode_utf8(AParamName))), AValue, AValueLen, xDestroy));
end;
{$ENDIF SQLITE_OMIT_UTF16}

procedure TDISQLite3Statement.Bind_Variant(const AParamIdx: Integer; const AValue: Variant);
begin
  CheckActive;
  Check(sqlite3_bind_variant(FHandle, AParamIdx, AValue));
end;

procedure TDISQLite3Statement.Bind_Variant_By_Name(const AParamName: Utf8String; const AValue: Variant);
begin
  CheckActive;
  Check(sqlite3_bind_variant(FHandle, sqlite3_bind_parameter_index(FHandle, PUtf8Char(AParamName)), AValue));
end;

procedure TDISQLite3Statement.Bind_Variant_By_Name16(const AParamName: UnicodeString; const AValue: Variant);
begin
  CheckActive;
  Check(sqlite3_bind_variant(FHandle, sqlite3_bind_parameter_index(FHandle, PUtf8Char(sqlite3_encode_utf8(AParamName))), AValue));
end;

procedure TDISQLite3Statement.Bind_ZeroBlob(const AParamIdx: Integer; const ABlobSize: Integer);
begin
  CheckActive;
  Check(sqlite3_bind_zeroblob(FHandle, AParamIdx, ABlobSize));
end;

function TDISQLite3Statement.Check(const AErrorCode: Integer): Integer;
begin
  Result := AErrorCode;
  if Result <> SQLITE_OK then
    sqlite3_raise_exception(Result, FDatabase.Handle);
end;

procedure TDISQLite3Statement.CheckActive;
begin
  if not Assigned(FHandle) then
    DatabaseError(PResStringRec(@SStatementClosed), Self)
end;

procedure TDISQLite3Statement.CheckInactive;
begin
  if Assigned(FHandle) then
    DatabaseError(PResStringRec(@SStatementOpen), Self);
end;

procedure TDISQLite3Statement.Clear_Bindings;
begin
  CheckActive;
  Check(sqlite3_clear_bindings(FHandle));
end;

procedure TDISQLite3Statement.Close;
begin
  SetActive(False);
end;

function TDISQLite3Statement.Column_Blob(
  const AColumnIdx: Integer): Pointer;
begin
  CheckActive;
  Result := sqlite3_column_blob(FHandle, AColumnIdx);
end;

function TDISQLite3Statement.Column_Bytes(
  const AColumnIdx: Integer): Integer;
begin
  CheckActive;
  Result := sqlite3_column_bytes(FHandle, AColumnIdx);
end;

{$IFNDEF SQLITE_OMIT_UTF16}

function TDISQLite3Statement.Column_Bytes16(
  const AColumnIdx: Integer): Integer;
begin
  CheckActive;
  Result := sqlite3_column_bytes16(FHandle, AColumnIdx);
end;

{$ENDIF !SQLITE_OMIT_UTF16}

function TDISQLite3Statement.Column_Cell8(const AColumnIdx: Integer): TDISQLite3Cell8;
var
  ColLen: Integer;
  ColPtr: Pointer;
begin
  CheckActive;

  Result.CellType := sqlite3_column_type(FHandle, AColumnIdx);
  case Result.CellType of

    SQLITE_INTEGER:
      begin
        Result.CellInteger := sqlite3_column_int64(FHandle, AColumnIdx);
      end;

    SQLITE_FLOAT:
      begin
        Result.CellFloat := sqlite3_column_double(FHandle, AColumnIdx);
      end;

    SQLITE_TEXT:
      begin
        ColPtr := sqlite3_column_text(FHandle, AColumnIdx);
        ColLen := sqlite3_column_bytes(FHandle, AColumnIdx);
        Result.CellText.l := ColLen;
        GetMem(Result.CellText.p, ColLen);
        Move(ColPtr^, Result.CellText.p^, ColLen);
      end;

    SQLITE_BLOB:
      begin
        ColPtr := sqlite3_column_blob(FHandle, AColumnIdx);
        ColLen := sqlite3_column_bytes(FHandle, AColumnIdx);
        Result.CellBlob.l := ColLen;
        GetMem(Result.CellBlob.p, ColLen);
        Move(ColPtr^, Result.CellBlob.p^, ColLen);
      end;

    SQLITE_NULL:
      begin
        Result.CellInteger := 0;
      end;
  else
    sqlite3_init_cell8(Result);
  end;
end;

procedure TDISQLite3Statement.Column_Cell16(const AColumnIdx: Integer; out ACell: TDISQLite3Cell16);
var
  ColLen: Integer;
  ColPtr: Pointer;
  {$IFDEF SQLITE_OMIT_UTF16}
  s: UnicodeString;
  {$ENDIF SQLITE_OMIT_UTF16}
begin
  CheckActive;

  with ACell do
    begin
      CellType := sqlite3_column_type(FHandle, AColumnIdx);
      case CellType of

        SQLITE_INTEGER:
          begin
            CellInteger := sqlite3_column_int64(FHandle, AColumnIdx);
          end;

        SQLITE_FLOAT:
          begin
            CellFloat := sqlite3_column_double(FHandle, AColumnIdx);
          end;

        SQLITE_TEXT:
          begin
            {$IFDEF SQLITE_OMIT_UTF16}
            s := sqlite3_column_str16(FHandle, AColumnIdx);
            ColLen := Length(s);
            CellText.l := ColLen;
            ColLen := ColLen shl 1;
            GetMem(CellText.p, ColLen);
            Move(Pointer(s)^, CellText.p^, ColLen);
            {$ELSE SQLITE_OMIT_UTF16}
            ColPtr := sqlite3_column_text16(FHandle, AColumnIdx);
            ColLen := sqlite3_column_bytes16(FHandle, AColumnIdx);
            CellText.l := ColLen shr 1;
            GetMem(CellText.p, ColLen);
            Move(ColPtr^, CellText.p^, ColLen);
            {$ENDIF SQLITE_OMIT_UTF16}
          end;

        SQLITE_BLOB:
          begin
            ColPtr := sqlite3_column_blob(FHandle, AColumnIdx);
            ColLen := sqlite3_column_bytes(FHandle, AColumnIdx);
            CellBlob.l := ColLen;
            GetMem(CellBlob.p, ColLen);
            Move(ColPtr^, CellBlob.p^, ColLen);
          end;

        SQLITE_NULL:
          begin
            CellInteger := 0;
          end;
      else
        sqlite3_init_cell16(ACell);
      end;
    end;
end;

function TDISQLite3Statement.Column_Count: Integer;
begin
  CheckActive;
  Result := sqlite3_column_count(FHandle);
end;

{$IFDEF SQLITE_ENABLE_COLUMN_METADATA}

function TDISQLite3Statement.Column_Database_Name(
  const AColumnIdx: Integer): Utf8String;
begin
  CheckActive;
  Result := sqlite3_column_database_name(FHandle, AColumnIdx);
end;

{$ENDIF SQLITE_ENABLE_COLUMN_METADATA}

{$IFDEF SQLITE_ENABLE_COLUMN_METADATA}

function TDISQLite3Statement.Column_Database_Name16(
  const AColumnIdx: Integer): UnicodeString;
begin
  {$IFDEF SQLITE_OMIT_UTF16}
  Result := sqlite3_decode_utf8(Column_Database_Name(AColumnIdx));
  {$ELSE SQLITE_OMIT_UTF16}
  CheckActive;
  Result := sqlite3_column_database_name16(FHandle, AColumnIdx);
  {$ENDIF SQLITE_OMIT_UTF16}
end;

{$ENDIF SQLITE_ENABLE_COLUMN_METADATA}

{$IFNDEF SQLITE_OMIT_DECLTYPE}
function TDISQLite3Statement.Column_DeclType(const AColumnIdx: Integer): Utf8String;
begin
  Result := sqlite3_column_decltype(FHandle, AColumnIdx);
end;
{$ENDIF !SQLITE_OMIT_DECLTYPE}

{$IFNDEF SQLITE_OMIT_DECLTYPE}
function TDISQLite3Statement.Column_DeclType16(const AColumnIdx: Integer): UnicodeString;
begin
  {$IFDEF SQLITE_OMIT_UTF16}
  Result := sqlite3_decode_utf8(Column_DeclType(AColumnIdx));
  {$ELSE SQLITE_OMIT_UTF16}
  CheckActive;
  Result := sqlite3_column_decltype16(FHandle, AColumnIdx);
  {$ENDIF SQLITE_OMIT_UTF16}
end;
{$ENDIF !SQLITE_OMIT_DECLTYPE}

function TDISQLite3Statement.Column_Double(
  const AColumnIdx: Integer): Double;
begin
  CheckActive;
  Result := sqlite3_column_double(FHandle, AColumnIdx);
end;

function TDISQLite3Statement.Column_Int(
  const AColumnIdx: Integer): Integer;
begin
  CheckActive;
  Result := sqlite3_column_int(FHandle, AColumnIdx);
end;

function TDISQLite3Statement.Column_Int64(
  const AColumnIdx: Integer): Int64;
begin
  CheckActive;
  Result := sqlite3_column_int64(FHandle, AColumnIdx);
end;

function TDISQLite3Statement.Column_Name(
  const AColumnIdx: Integer): Utf8String;
begin
  CheckActive;
  Result := sqlite3_column_name(FHandle, AColumnIdx);
end;

function TDISQLite3Statement.Column_Name16(
  const AColumnIdx: Integer): UnicodeString;
begin
  {$IFDEF SQLITE_OMIT_UTF16}
  Result := sqlite3_decode_utf8(Column_Name(AColumnIdx));
  {$ELSE SQLITE_OMIT_UTF16}
  CheckActive;
  Result := sqlite3_column_name16(FHandle, AColumnIdx);
  {$ENDIF SQLITE_OMIT_UTF16}
end;

{$IFDEF SQLITE_ENABLE_COLUMN_METADATA}

function TDISQLite3Statement.Column_Origin_Name(
  const AColumnIdx: Integer): Utf8String;
begin
  CheckActive;
  Result := sqlite3_column_origin_name(FHandle, AColumnIdx);
end;
{$ENDIF SQLITE_ENABLE_COLUMN_METADATA}

{$IFDEF SQLITE_ENABLE_COLUMN_METADATA}

function TDISQLite3Statement.Column_Origin_Name16(
  const AColumnIdx: Integer): UnicodeString;
begin
  {$IFDEF SQLITE_OMIT_UTF16}
  Result := sqlite3_decode_utf8(Column_Origin_Name(AColumnIdx));
  {$ELSE SQLITE_OMIT_UTF16}
  CheckActive;
  Result := sqlite3_column_origin_name16(FHandle, AColumnIdx);
  {$ENDIF SQLITE_OMIT_UTF16}
end;

{$ENDIF SQLITE_ENABLE_COLUMN_METADATA}

function TDISQLite3Statement.Column_Str(
  const AColumnIdx: Integer): Utf8String;
begin
  CheckActive;
  Result := sqlite3_column_str(FHandle, AColumnIdx);
end;

function TDISQLite3Statement.Column_Str16(
  const AColumnIdx: Integer): UnicodeString;
begin
  CheckActive;
  Result := sqlite3_column_str16(FHandle, AColumnIdx);
end;

{$IFDEF SQLITE_ENABLE_COLUMN_METADATA}

function TDISQLite3Statement.Column_Table_Name(
  const AColumnIdx: Integer): Utf8String;
begin
  CheckActive;
  Result := sqlite3_column_table_name(FHandle, AColumnIdx);
end;
{$ENDIF SQLITE_ENABLE_COLUMN_METADATA}

{$IFDEF SQLITE_ENABLE_COLUMN_METADATA}

function TDISQLite3Statement.Column_Table_Name16(
  const AColumnIdx: Integer): UnicodeString;
begin
  {$IFDEF SQLITE_OMIT_UTF16}
  Result := sqlite3_decode_utf8(Column_Table_Name(AColumnIdx));
  {$ELSE SQLITE_OMIT_UTF16}
  CheckActive;
  Result := sqlite3_column_table_name16(FHandle, AColumnIdx);
  {$ENDIF SQLITE_OMIT_UTF16}
end;

{$ENDIF SQLITE_ENABLE_COLUMN_METADATA}

function TDISQLite3Statement.Column_Text(
  const AColumnIdx: Integer): PUtf8Char;
begin
  CheckActive;
  Result := sqlite3_column_text(FHandle, AColumnIdx);
end;

{$IFNDEF SQLITE_OMIT_UTF16}

function TDISQLite3Statement.Column_Text16(
  const AColumnIdx: Integer): PWideChar;
begin
  CheckActive;
  Result := sqlite3_column_text16(FHandle, AColumnIdx);
end;

{$ENDIF !SQLITE_OMIT_UTF16}

function TDISQLite3Statement.Column_Type(
  const AColumnIdx: Integer): Integer;
begin
  CheckActive;
  Result := sqlite3_column_type(FHandle, AColumnIdx);
end;

procedure TDISQLite3Statement.DoAfterClose;
begin
  if Assigned(FAfterClose) then
    FAfterClose(Self);
end;

procedure TDISQLite3Statement.DoAfterOpen;
begin
  if Assigned(FAfterOpen) then
    FAfterOpen(Self);
end;

procedure TDISQLite3Statement.DoBeforeClose;
begin
  if Assigned(FBeforeClose) then
    FBeforeClose(Self);
end;

procedure TDISQLite3Statement.DoBeforeOpen;
begin
  if Assigned(FBeforeOpen) then
    FBeforeOpen(Self);
end;

function TDISQLite3Statement.GetActive: Boolean;
begin
  Result := Assigned(FHandle);
end;

function TDISQLite3Statement.GetSql16: UnicodeString;
begin
  Result := sqlite3_decode_utf8(FSql8);
end;

{$IFDEF SQLITE_ENABLE_COLUMN_METADATA}

function TDISQLite3Statement.TableName(const AQuoteChar: AnsiChar{$IFDEF SUPPORTS_DEFAULTPARAMS} = SQLITE3_IDENTIFIER_QUOTE_CHAR{$ENDIF}): Utf8String;
var
  c, i: Integer;
  d, t: Utf8String;
begin
  Result := '';
  CheckActive;

  c := sqlite3_column_count(FHandle);
  if c > 0 then
    begin
      i := 0;
      d := sqlite3_column_database_name(FHandle, i);
      t := sqlite3_column_table_name(FHandle, i);

      Inc(i);
      while i < c do
        begin
          if d <> Utf8String(sqlite3_column_database_name(FHandle, i)) then
            Break;
          if t <> Utf8String(sqlite3_column_table_name(FHandle, i)) then
            Break;

          Inc(i);
        end;

      if i = c then
        begin
          if sqlite3_database_type(d) <> dtMain then
            Result := DISQLite3Api.QuotedStr(d{$IFNDEF SUPPORTS_DEFAULTPARAMS}, SQLITE3_IDENTIFIER_QUOTE_CHAR{$ENDIF}) + '.'
          else
            Result := '';
          Result := Result + DISQLite3Api.QuotedStr(t{$IFNDEF SUPPORTS_DEFAULTPARAMS}, SQLITE3_IDENTIFIER_QUOTE_CHAR{$ENDIF});
        end;
    end;
end;

{$ENDIF SQLITE_ENABLE_COLUMN_METADATA}

{$IFDEF SQLITE_ENABLE_COLUMN_METADATA}

function TDISQLite3Statement.TableName16(const AQuoteChar: WideChar{$IFDEF SUPPORTS_DEFAULTPARAMS} = SQLITE3_IDENTIFIER_QUOTE_CHAR{$ENDIF}): UnicodeString;
{$IFNDEF SQLITE_OMIT_UTF16}
var
  c, i: Integer;
  d, t: UnicodeString;
  {$ENDIF SQLITE_OMIT_UTF16}
begin
  {$IFDEF SQLITE_OMIT_UTF16}
  Result := sqlite3_decode_utf8(TableName(AnsiChar(AQuoteChar)));
  {$ELSE  SQLITE_OMIT_UTF16}
  Result := '';
  CheckActive;

  c := sqlite3_column_count(FHandle);
  if c > 0 then
    begin
      i := 0;
      d := sqlite3_column_database_name16(FHandle, i);
      t := sqlite3_column_table_name16(FHandle, i);

      Inc(i);
      while i < c do
        begin
          if d <> UnicodeString(sqlite3_column_database_name16(FHandle, i)) then
            Break;
          if t <> UnicodeString(sqlite3_column_table_name16(FHandle, i)) then
            Break;

          Inc(i);
        end;

      if i = c then
        begin
          if sqlite3_database_type16(d) <> dtMain then
            Result := DISQLite3Api.QuotedStr16(d{$IFNDEF SUPPORTS_DEFAULTPARAMS}, SQLITE3_IDENTIFIER_QUOTE_CHAR{$ENDIF}) + '.'
          else
            Result := '';
          Result := Result + DISQLite3Api.QuotedStr16(t{$IFNDEF SUPPORTS_DEFAULTPARAMS}, SQLITE3_IDENTIFIER_QUOTE_CHAR{$ENDIF});
        end;
    end;
  {$ENDIF SQLITE_OMIT_UTF16}
end;

{$ENDIF SQLITE_ENABLE_COLUMN_METADATA}

procedure TDISQLite3Statement.Open;
begin
  SetActive(True);
end;

function TDISQLite3Statement.Reset: Integer;
begin
  CheckActive;

  Result := sqlite3_reset(FHandle);
end;

procedure TDISQLite3Statement.SetActive(const AValue: Boolean);
var
  h: sqlite3_stmt;
begin
  if AValue <> Assigned(FHandle) then
    if AValue then
      begin
        if not Assigned(FDatabase) then
          DatabaseError(PResStringRec(@SMissingDatabase){$IFNDEF SUPPORTS_DEFAULTPARAMS}, nil{$ENDIF});
        FDatabase.Connected := True;
        DoBeforeOpen;
        Check(sqlite3_prepare_v2(FDatabase.Handle, PUtf8Char(FSql8), Length(FSql8), @FHandle, nil));
        if not Assigned(FHandle) then
          DatabaseError(PResStringRec(@SEmptySQLStatement), Self);
        DoAfterOpen;
      end
    else
      begin

        DoBeforeClose;
        h := FHandle;
        FHandle := nil;

        sqlite3_finalize(h);
        DoAfterClose;
      end;
end;

procedure TDISQLite3Statement.SetDatabase(const AValue: TDISQLite3Database);
begin
  CheckInactive;
  if Assigned(FDatabase) then
    FDatabase.UnRegisterStatement(Self);
  FDatabase := AValue;
  if Assigned(AValue) then
    AValue.RegisterStatement(Self);
end;

procedure TDISQLite3Statement.SetSql8(const AValue: Utf8String);
begin
  CheckInactive;
  FSql8 := AValue;
end;

procedure TDISQLite3Statement.SetSql16(const AValue: UnicodeString);
begin
  SetSql8(sqlite3_encode_utf8(AValue));
end;

function TDISQLite3Statement.Step: Integer;
var
  l: Integer;
begin
  CheckActive;

  l := 8;
  repeat
    Result := sqlite3_step(FHandle);
    case Result and $FF of
      SQLITE_OK, SQLITE_ROW, SQLITE_DONE:
        Exit;
      SQLITE_BUSY:
        Sleep(10);
    else
      Break;
    end;
    Dec(l);
  until l = 0;

  sqlite3_raise_exception(Result, FDatabase.Handle);
end;

function TDISQLite3Statement.StepAndReset: Integer;
var
  eReset, l: Integer;
begin
  CheckActive;

  l := 8;
  repeat
    Result := sqlite3_step(FHandle);
    if Result and $FF <> SQLITE_BUSY then
      Break;
    Sleep(10);
    Dec(l);
  until l = 0;

  eReset := sqlite3_reset(FHandle);

  if (Result and $FF in [SQLITE_OK, SQLITE_ERROR])
    and (eReset <> SQLITE_OK) then
    Result := eReset;

  case Result and $FF of
    SQLITE_OK, SQLITE_ROW, SQLITE_DONE:
      ;
  else
    sqlite3_raise_exception(Result, FDatabase.Handle);
  end;
end;

{$IFNDEF SQLITE_OMIT_INCRBLOB}

constructor TDISQLite3IncrBlobStream.Create(
  const ADBHandle: sqlite3;
  const ADatabaseName: UnicodeString;
  const ATableName: UnicodeString;
  const AColumnName: UnicodeString;
  const ARowID: Int64;
  const AFlags: Integer);
begin
  inherited Create;
  sqlite3_check(sqlite3_blob_open(
    ADBHandle,
    PUtf8Char(sqlite3_encode_utf8(ADatabaseName)),
    PUtf8Char(sqlite3_encode_utf8(ATableName)),
    PUtf8Char(sqlite3_encode_utf8(AColumnName)),
    ARowID,
    AFlags,
    @FBlobHandle), ADBHandle);
  FFlags := AFlags;
end;

constructor TDISQLite3IncrBlobStream.{$IFDEF SUPPORTS_OVERLOAD}Create{$ELSE}CreateDB{$ENDIF}(
  const ADb: TDISQLite3Database;
  const ADatabaseName: UnicodeString;
  const ATableName: UnicodeString;
  const AColumnName: UnicodeString;
  const ARowID: Int64;
  const AFlags: Integer);
begin
  Create(ADb.Handle, ADatabaseName, ATableName, AColumnName, ARowID, AFlags);
end;

destructor TDISQLite3IncrBlobStream.Destroy;
begin

  sqlite3_blob_close(FBlobHandle);
  inherited;
end;

function TDISQLite3IncrBlobStream.Read(var Buffer; Count: Integer): Integer;
var
  BlobSize: Integer;
begin
  Result := Count;
  BlobSize := sqlite3_blob_bytes(FBlobHandle);
  if Result + FOffset > BlobSize then
    Result := BlobSize - FOffset;
  if (Count > 0) and (sqlite3_blob_read(FBlobHandle, @Buffer, Count, FOffset) = SQLITE_OK) then
    Inc(FOffset, Result)
  else
    Result := 0;
end;

function TDISQLite3IncrBlobStream.Seek(Offset: Integer; Origin: Word): Integer;
begin
  case Origin of
    soFromBeginning: FOffset := Offset;
    soFromCurrent: Inc(FOffset, Offset);
    soFromEnd: FOffset := sqlite3_blob_bytes(FBlobHandle) + Offset;
  end;
  Result := FOffset;
end;

procedure TDISQLite3IncrBlobStream.SetSize(NewSize: Integer);
begin
  {$IFDEF COMPILER_5_UP}
  raise EStreamError.CreateRes(PResStringRec(@SStreamSetSize));
  {$ELSE COMPILER_5_UP}
  raise EStreamError.Create(SStreamSetSize);
  {$ENDIF COMPILER_5_UP}
end;

function TDISQLite3IncrBlobStream.Write(const Buffer; Count: Integer): Integer;
var
  BlobSize: Integer;
begin
  if FFlags <> 0 then
    begin
      Result := Count;
      BlobSize := sqlite3_blob_bytes(FBlobHandle);
      if FOffset + Result > BlobSize then
        Result := BlobSize - FOffset;
      if (Result > 0) and (sqlite3_blob_write(FBlobHandle, @Buffer, Result, FOffset) = SQLITE_OK) then
        Inc(FOffset, Result)
      else
        Result := 0;
    end
  else
    begin
      {$IFDEF COMPILER_5_UP}
      raise EStreamError.CreateRes(PResStringRec(@SCannotWriteStreamError));
      {$ELSE COMPILER_5_UP}
      raise EStreamError.Create(SCannotWriteStreamError);
      {$ENDIF COMPILER_5_UP}
    end;
end;

{$ENDIF !SQLITE_OMIT_INCRBLOB}

procedure Init;
var
  OSVersionInfo: TOSVersionInfo;
begin
  OSVersionInfo.dwOSVersionInfoSize := SizeOf(OSVersionInfo);
  IsUnicode := GetVersionEx(OSVersionInfo) and (OSVersionInfo.dwPlatformId = VER_PLATFORM_WIN32_NT);
end;

initialization
  Init;

end.

