// ------------------------------------------------------------------------------------------------
#include "Library/SQLite.hpp"

// ------------------------------------------------------------------------------------------------
#include <sqratConst.h>

// ------------------------------------------------------------------------------------------------
#include <ctime>

// ------------------------------------------------------------------------------------------------
#include <sqstdblob.h>

// ------------------------------------------------------------------------------------------------
namespace SqMod {

// ------------------------------------------------------------------------------------------------
// Error message when failed to bind value to parameter index.
#define SQMOD_BINDFAILED "Unable to bind ({}) parameter ({}) because [{}]"

// ------------------------------------------------------------------------------------------------
SQMOD_DECL_TYPENAME(SQLiteConnectionTypename, _SC("SQLiteConnection"))
SQMOD_DECL_TYPENAME(SQLiteParameterTypename, _SC("SQLiteParameter"))
SQMOD_DECL_TYPENAME(SQLiteColumnTypename, _SC("SQLiteColumn"))
SQMOD_DECL_TYPENAME(SQLiteStatementTypename, _SC("SQLiteStatement"))
SQMOD_DECL_TYPENAME(SQLiteTransactionTypename, _SC("SQLiteTransaction"))

// ------------------------------------------------------------------------------------------------
static const EnumElement g_MainEnum[] = {
    {_SC("ABORT"),                                SQLITE_ABORT},
    {_SC("ABORT_ROLLBACK"),                       SQLITE_ABORT_ROLLBACK},
    {_SC("ACCESS_EXISTS"),                        SQLITE_ACCESS_EXISTS},
    {_SC("ACCESS_READ"),                          SQLITE_ACCESS_READ},
    {_SC("ACCESS_READWRITE"),                     SQLITE_ACCESS_READWRITE},
    {_SC("ALTER_TABLE"),                          SQLITE_ALTER_TABLE},
    {_SC("ANALYZE"),                              SQLITE_ANALYZE},
    {_SC("ANY"),                                  SQLITE_ANY},
    {_SC("ATTACH"),                               SQLITE_ATTACH},
    {_SC("AUTH"),                                 SQLITE_AUTH},
    {_SC("AUTH_USER"),                            SQLITE_AUTH_USER},
    {_SC("BLOB"),                                 SQLITE_BLOB},
    {_SC("BUSY"),                                 SQLITE_BUSY},
    {_SC("BUSY_RECOVERY"),                        SQLITE_BUSY_RECOVERY},
    {_SC("BUSY_SNAPSHOT"),                        SQLITE_BUSY_SNAPSHOT},
    {_SC("CANTOPEN"),                             SQLITE_CANTOPEN},
    {_SC("CANTOPEN_CONVPATH"),                    SQLITE_CANTOPEN_CONVPATH},
    {_SC("CANTOPEN_FULLPATH"),                    SQLITE_CANTOPEN_FULLPATH},
    {_SC("CANTOPEN_ISDIR"),                       SQLITE_CANTOPEN_ISDIR},
    {_SC("CANTOPEN_NOTEMPDIR"),                   SQLITE_CANTOPEN_NOTEMPDIR},
    {_SC("CHECKPOINT_FULL"),                      SQLITE_CHECKPOINT_FULL},
    {_SC("CHECKPOINT_PASSIVE"),                   SQLITE_CHECKPOINT_PASSIVE},
    {_SC("CHECKPOINT_RESTART"),                   SQLITE_CHECKPOINT_RESTART},
    {_SC("CHECKPOINT_TRUNCATE"),                  SQLITE_CHECKPOINT_TRUNCATE},
    {_SC("CONFIG_COVERING_INDEX_SCAN"),           SQLITE_CONFIG_COVERING_INDEX_SCAN},
    {_SC("CONFIG_GETMALLOC"),                     SQLITE_CONFIG_GETMALLOC},
    {_SC("CONFIG_GETMUTEX"),                      SQLITE_CONFIG_GETMUTEX},
    {_SC("CONFIG_GETPCACHE"),                     SQLITE_CONFIG_GETPCACHE},
    {_SC("CONFIG_GETPCACHE2"),                    SQLITE_CONFIG_GETPCACHE2},
    {_SC("CONFIG_HEAP"),                          SQLITE_CONFIG_HEAP},
    {_SC("CONFIG_LOG"),                           SQLITE_CONFIG_LOG},
    {_SC("CONFIG_LOOKASIDE"),                     SQLITE_CONFIG_LOOKASIDE},
    {_SC("CONFIG_MALLOC"),                        SQLITE_CONFIG_MALLOC},
    {_SC("CONFIG_MEMSTATUS"),                     SQLITE_CONFIG_MEMSTATUS},
    {_SC("CONFIG_MMAP_SIZE"),                     SQLITE_CONFIG_MMAP_SIZE},
    {_SC("CONFIG_MULTITHREAD"),                   SQLITE_CONFIG_MULTITHREAD},
    {_SC("CONFIG_MUTEX"),                         SQLITE_CONFIG_MUTEX},
    {_SC("CONFIG_PAGECACHE"),                     SQLITE_CONFIG_PAGECACHE},
    {_SC("CONFIG_PCACHE"),                        SQLITE_CONFIG_PCACHE},
    {_SC("CONFIG_PCACHE2"),                       SQLITE_CONFIG_PCACHE2},
    {_SC("CONFIG_PCACHE_HDRSZ"),                  SQLITE_CONFIG_PCACHE_HDRSZ},
    {_SC("CONFIG_PMASZ"),                         SQLITE_CONFIG_PMASZ},
    {_SC("CONFIG_SCRATCH"),                       SQLITE_CONFIG_SCRATCH},
    {_SC("CONFIG_SERIALIZED"),                    SQLITE_CONFIG_SERIALIZED},
    {_SC("CONFIG_SINGLETHREAD"),                  SQLITE_CONFIG_SINGLETHREAD},
    {_SC("CONFIG_SQLLOG"),                        SQLITE_CONFIG_SQLLOG},
    {_SC("CONFIG_URI"),                           SQLITE_CONFIG_URI},
    {_SC("CONFIG_WIN32_HEAPSIZE"),                SQLITE_CONFIG_WIN32_HEAPSIZE},
    {_SC("CONSTRAINT"),                           SQLITE_CONSTRAINT},
    {_SC("CONSTRAINT_CHECK"),                     SQLITE_CONSTRAINT_CHECK},
    {_SC("CONSTRAINT_COMMITHOOK"),                SQLITE_CONSTRAINT_COMMITHOOK},
    {_SC("CONSTRAINT_FOREIGNKEY"),                SQLITE_CONSTRAINT_FOREIGNKEY},
    {_SC("CONSTRAINT_FUNCTION"),                  SQLITE_CONSTRAINT_FUNCTION},
    {_SC("CONSTRAINT_NOTNULL"),                   SQLITE_CONSTRAINT_NOTNULL},
    {_SC("CONSTRAINT_PRIMARYKEY"),                SQLITE_CONSTRAINT_PRIMARYKEY},
    {_SC("CONSTRAINT_ROWID"),                     SQLITE_CONSTRAINT_ROWID},
    {_SC("CONSTRAINT_TRIGGER"),                   SQLITE_CONSTRAINT_TRIGGER},
    {_SC("CONSTRAINT_UNIQUE"),                    SQLITE_CONSTRAINT_UNIQUE},
    {_SC("CONSTRAINT_VTAB"),                      SQLITE_CONSTRAINT_VTAB},
    {_SC("COPY"),                                 SQLITE_COPY},
    {_SC("CORRUPT"),                              SQLITE_CORRUPT},
    {_SC("CORRUPT_VTAB"),                         SQLITE_CORRUPT_VTAB},
    {_SC("CREATE_INDEX"),                         SQLITE_CREATE_INDEX},
    {_SC("CREATE_TABLE"),                         SQLITE_CREATE_TABLE},
    {_SC("CREATE_TEMP_INDEX"),                    SQLITE_CREATE_TEMP_INDEX},
    {_SC("CREATE_TEMP_TABLE"),                    SQLITE_CREATE_TEMP_TABLE},
    {_SC("CREATE_TEMP_TRIGGER"),                  SQLITE_CREATE_TEMP_TRIGGER},
    {_SC("CREATE_TEMP_VIEW"),                     SQLITE_CREATE_TEMP_VIEW},
    {_SC("CREATE_TRIGGER"),                       SQLITE_CREATE_TRIGGER},
    {_SC("CREATE_VIEW"),                          SQLITE_CREATE_VIEW},
    {_SC("CREATE_VTABLE"),                        SQLITE_CREATE_VTABLE},
    {_SC("DBCONFIG_ENABLE_FKEY"),                 SQLITE_DBCONFIG_ENABLE_FKEY},
    {_SC("DBCONFIG_ENABLE_TRIGGER"),              SQLITE_DBCONFIG_ENABLE_TRIGGER},
    {_SC("DBCONFIG_LOOKASIDE"),                   SQLITE_DBCONFIG_LOOKASIDE},
    {_SC("DBSTATUS_CACHE_HIT"),                   SQLITE_DBSTATUS_CACHE_HIT},
    {_SC("DBSTATUS_CACHE_MISS"),                  SQLITE_DBSTATUS_CACHE_MISS},
    {_SC("DBSTATUS_CACHE_USED"),                  SQLITE_DBSTATUS_CACHE_USED},
    {_SC("DBSTATUS_CACHE_WRITE"),                 SQLITE_DBSTATUS_CACHE_WRITE},
    {_SC("DBSTATUS_DEFERRED_FKS"),                SQLITE_DBSTATUS_DEFERRED_FKS},
    {_SC("DBSTATUS_LOOKASIDE_HIT"),               SQLITE_DBSTATUS_LOOKASIDE_HIT},
    {_SC("DBSTATUS_LOOKASIDE_MISS_FULL"),         SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL},
    {_SC("DBSTATUS_LOOKASIDE_MISS_SIZE"),         SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE},
    {_SC("DBSTATUS_LOOKASIDE_USED"),              SQLITE_DBSTATUS_LOOKASIDE_USED},
    {_SC("DBSTATUS_MAX"),                         SQLITE_DBSTATUS_MAX},
    {_SC("DBSTATUS_SCHEMA_USED"),                 SQLITE_DBSTATUS_SCHEMA_USED},
    {_SC("DBSTATUS_STMT_USED"),                   SQLITE_DBSTATUS_STMT_USED},
    {_SC("DELETE"),                               SQLITE_DELETE},
    {_SC("DENY"),                                 SQLITE_DENY},
    {_SC("DETACH"),                               SQLITE_DETACH},
    {_SC("DETERMINISTIC"),                        SQLITE_DETERMINISTIC},
    {_SC("DONE"),                                 SQLITE_DONE},
    {_SC("DROP_INDEX"),                           SQLITE_DROP_INDEX},
    {_SC("DROP_TABLE"),                           SQLITE_DROP_TABLE},
    {_SC("DROP_TEMP_INDEX"),                      SQLITE_DROP_TEMP_INDEX},
    {_SC("DROP_TEMP_TABLE"),                      SQLITE_DROP_TEMP_TABLE},
    {_SC("DROP_TEMP_TRIGGER"),                    SQLITE_DROP_TEMP_TRIGGER},
    {_SC("DROP_TEMP_VIEW"),                       SQLITE_DROP_TEMP_VIEW},
    {_SC("DROP_TRIGGER"),                         SQLITE_DROP_TRIGGER},
    {_SC("DROP_VIEW"),                            SQLITE_DROP_VIEW},
    {_SC("DROP_VTABLE"),                          SQLITE_DROP_VTABLE},
    {_SC("EMPTY"),                                SQLITE_EMPTY},
    {_SC("ERROR"),                                SQLITE_ERROR},
    {_SC("FAIL"),                                 SQLITE_FAIL},
    {_SC("FCNTL_BUSYHANDLER"),                    SQLITE_FCNTL_BUSYHANDLER},
    {_SC("FCNTL_CHUNK_SIZE"),                     SQLITE_FCNTL_CHUNK_SIZE},
    {_SC("FCNTL_COMMIT_PHASETWO"),                SQLITE_FCNTL_COMMIT_PHASETWO},
    {_SC("FCNTL_FILE_POINTER"),                   SQLITE_FCNTL_FILE_POINTER},
    {_SC("FCNTL_GET_LOCKPROXYFILE"),              SQLITE_FCNTL_GET_LOCKPROXYFILE},
    {_SC("FCNTL_HAS_MOVED"),                      SQLITE_FCNTL_HAS_MOVED},
    {_SC("FCNTL_LAST_ERRNO"),                     SQLITE_FCNTL_LAST_ERRNO},
    {_SC("FCNTL_LOCKSTATE"),                      SQLITE_FCNTL_LOCKSTATE},
    {_SC("FCNTL_MMAP_SIZE"),                      SQLITE_FCNTL_MMAP_SIZE},
    {_SC("FCNTL_OVERWRITE"),                      SQLITE_FCNTL_OVERWRITE},
    {_SC("FCNTL_PERSIST_WAL"),                    SQLITE_FCNTL_PERSIST_WAL},
    {_SC("FCNTL_POWERSAFE_OVERWRITE"),            SQLITE_FCNTL_POWERSAFE_OVERWRITE},
    {_SC("FCNTL_PRAGMA"),                         SQLITE_FCNTL_PRAGMA},
    {_SC("FCNTL_RBU"),                            SQLITE_FCNTL_RBU},
    {_SC("FCNTL_SET_LOCKPROXYFILE"),              SQLITE_FCNTL_SET_LOCKPROXYFILE},
    {_SC("FCNTL_SIZE_HINT"),                      SQLITE_FCNTL_SIZE_HINT},
    {_SC("FCNTL_SYNC"),                           SQLITE_FCNTL_SYNC},
    {_SC("FCNTL_SYNC_OMITTED"),                   SQLITE_FCNTL_SYNC_OMITTED},
    {_SC("FCNTL_TEMPFILENAME"),                   SQLITE_FCNTL_TEMPFILENAME},
    {_SC("FCNTL_TRACE"),                          SQLITE_FCNTL_TRACE},
    {_SC("FCNTL_VFSNAME"),                        SQLITE_FCNTL_VFSNAME},
    {_SC("FCNTL_WAL_BLOCK"),                      SQLITE_FCNTL_WAL_BLOCK},
    {_SC("FCNTL_WIN32_AV_RETRY"),                 SQLITE_FCNTL_WIN32_AV_RETRY},
    {_SC("FCNTL_WIN32_SET_HANDLE"),               SQLITE_FCNTL_WIN32_SET_HANDLE},
    {_SC("FCNTL_ZIPVFS"),                         SQLITE_FCNTL_ZIPVFS},
    {_SC("FLOAT"),                                SQLITE_FLOAT},
    {_SC("FORMAT"),                               SQLITE_FORMAT},
    {_SC("FULL"),                                 SQLITE_FULL},
    {_SC("FUNCTION"),                             SQLITE_FUNCTION},
    {_SC("IGNORE"),                               SQLITE_IGNORE},
    {_SC("INDEX_CONSTRAINT_EQ"),                  SQLITE_INDEX_CONSTRAINT_EQ},
    {_SC("INDEX_CONSTRAINT_GE"),                  SQLITE_INDEX_CONSTRAINT_GE},
    {_SC("INDEX_CONSTRAINT_GT"),                  SQLITE_INDEX_CONSTRAINT_GT},
    {_SC("INDEX_CONSTRAINT_LE"),                  SQLITE_INDEX_CONSTRAINT_LE},
    {_SC("INDEX_CONSTRAINT_LT"),                  SQLITE_INDEX_CONSTRAINT_LT},
    {_SC("INDEX_CONSTRAINT_MATCH"),               SQLITE_INDEX_CONSTRAINT_MATCH},
    {_SC("INDEX_SCAN_UNIQUE"),                    SQLITE_INDEX_SCAN_UNIQUE},
    {_SC("INSERT"),                               SQLITE_INSERT},
    {_SC("INTEGER"),                              SQLITE_INTEGER},
    {_SC("INTERNAL"),                             SQLITE_INTERNAL},
    {_SC("INTERRUPT"),                            SQLITE_INTERRUPT},
    {_SC("IOCAP_ATOMIC"),                         SQLITE_IOCAP_ATOMIC},
    {_SC("IOCAP_ATOMIC16K"),                      SQLITE_IOCAP_ATOMIC16K},
    {_SC("IOCAP_ATOMIC1K"),                       SQLITE_IOCAP_ATOMIC1K},
    {_SC("IOCAP_ATOMIC2K"),                       SQLITE_IOCAP_ATOMIC2K},
    {_SC("IOCAP_ATOMIC32K"),                      SQLITE_IOCAP_ATOMIC32K},
    {_SC("IOCAP_ATOMIC4K"),                       SQLITE_IOCAP_ATOMIC4K},
    {_SC("IOCAP_ATOMIC512"),                      SQLITE_IOCAP_ATOMIC512},
    {_SC("IOCAP_ATOMIC64K"),                      SQLITE_IOCAP_ATOMIC64K},
    {_SC("IOCAP_ATOMIC8K"),                       SQLITE_IOCAP_ATOMIC8K},
    {_SC("IOCAP_IMMUTABLE"),                      SQLITE_IOCAP_IMMUTABLE},
    {_SC("IOCAP_POWERSAFE_OVERWRITE"),            SQLITE_IOCAP_POWERSAFE_OVERWRITE},
    {_SC("IOCAP_SAFE_APPEND"),                    SQLITE_IOCAP_SAFE_APPEND},
    {_SC("IOCAP_SEQUENTIAL"),                     SQLITE_IOCAP_SEQUENTIAL},
    {_SC("IOCAP_UNDELETABLE_WHEN_OPEN"),          SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN},
    {_SC("IOERR"),                                SQLITE_IOERR},
    {_SC("IOERR_ACCESS"),                         SQLITE_IOERR_ACCESS},
    {_SC("IOERR_BLOCKED"),                        SQLITE_IOERR_BLOCKED},
    {_SC("IOERR_CHECKRESERVEDLOCK"),              SQLITE_IOERR_CHECKRESERVEDLOCK},
    {_SC("IOERR_CLOSE"),                          SQLITE_IOERR_CLOSE},
    {_SC("IOERR_CONVPATH"),                       SQLITE_IOERR_CONVPATH},
    {_SC("IOERR_DELETE"),                         SQLITE_IOERR_DELETE},
    {_SC("IOERR_DELETE_NOENT"),                   SQLITE_IOERR_DELETE_NOENT},
    {_SC("IOERR_DIR_CLOSE"),                      SQLITE_IOERR_DIR_CLOSE},
    {_SC("IOERR_DIR_FSYNC"),                      SQLITE_IOERR_DIR_FSYNC},
    {_SC("IOERR_FSTAT"),                          SQLITE_IOERR_FSTAT},
    {_SC("IOERR_FSYNC"),                          SQLITE_IOERR_FSYNC},
    {_SC("IOERR_GETTEMPPATH"),                    SQLITE_IOERR_GETTEMPPATH},
    {_SC("IOERR_LOCK"),                           SQLITE_IOERR_LOCK},
    {_SC("IOERR_MMAP"),                           SQLITE_IOERR_MMAP},
    {_SC("IOERR_NOMEM"),                          SQLITE_IOERR_NOMEM},
    {_SC("IOERR_RDLOCK"),                         SQLITE_IOERR_RDLOCK},
    {_SC("IOERR_READ"),                           SQLITE_IOERR_READ},
    {_SC("IOERR_SEEK"),                           SQLITE_IOERR_SEEK},
    {_SC("IOERR_SHMLOCK"),                        SQLITE_IOERR_SHMLOCK},
    {_SC("IOERR_SHMMAP"),                         SQLITE_IOERR_SHMMAP},
    {_SC("IOERR_SHMOPEN"),                        SQLITE_IOERR_SHMOPEN},
    {_SC("IOERR_SHMSIZE"),                        SQLITE_IOERR_SHMSIZE},
    {_SC("IOERR_SHORT_READ"),                     SQLITE_IOERR_SHORT_READ},
    {_SC("IOERR_TRUNCATE"),                       SQLITE_IOERR_TRUNCATE},
    {_SC("IOERR_UNLOCK"),                         SQLITE_IOERR_UNLOCK},
    {_SC("IOERR_VNODE"),                          SQLITE_IOERR_VNODE},
    {_SC("IOERR_WRITE"),                          SQLITE_IOERR_WRITE},
    {_SC("LIMIT_ATTACHED"),                       SQLITE_LIMIT_ATTACHED},
    {_SC("LIMIT_COLUMN"),                         SQLITE_LIMIT_COLUMN},
    {_SC("LIMIT_COMPOUND_SELECT"),                SQLITE_LIMIT_COMPOUND_SELECT},
    {_SC("LIMIT_EXPR_DEPTH"),                     SQLITE_LIMIT_EXPR_DEPTH},
    {_SC("LIMIT_FUNCTION_ARG"),                   SQLITE_LIMIT_FUNCTION_ARG},
    {_SC("LIMIT_LENGTH"),                         SQLITE_LIMIT_LENGTH},
    {_SC("LIMIT_LIKE_PATTERN_LENGTH"),            SQLITE_LIMIT_LIKE_PATTERN_LENGTH},
    {_SC("LIMIT_SQL_LENGTH"),                     SQLITE_LIMIT_SQL_LENGTH},
    {_SC("LIMIT_TRIGGER_DEPTH"),                  SQLITE_LIMIT_TRIGGER_DEPTH},
    {_SC("LIMIT_VARIABLE_NUMBER"),                SQLITE_LIMIT_VARIABLE_NUMBER},
    {_SC("LIMIT_VDBE_OP"),                        SQLITE_LIMIT_VDBE_OP},
    {_SC("LIMIT_WORKER_THREADS"),                 SQLITE_LIMIT_WORKER_THREADS},
    {_SC("LOCKED"),                               SQLITE_LOCKED},
    {_SC("LOCKED_SHAREDCACHE"),                   SQLITE_LOCKED_SHAREDCACHE},
    {_SC("LOCK_EXCLUSIVE"),                       SQLITE_LOCK_EXCLUSIVE},
    {_SC("LOCK_NONE"),                            SQLITE_LOCK_NONE},
    {_SC("LOCK_PENDING"),                         SQLITE_LOCK_PENDING},
    {_SC("LOCK_RESERVED"),                        SQLITE_LOCK_RESERVED},
    {_SC("LOCK_SHARED"),                          SQLITE_LOCK_SHARED},
    {_SC("MISMATCH"),                             SQLITE_MISMATCH},
    {_SC("MISUSE"),                               SQLITE_MISUSE},
    {_SC("MUTEX_FAST"),                           SQLITE_MUTEX_FAST},
    {_SC("MUTEX_RECURSIVE"),                      SQLITE_MUTEX_RECURSIVE},
    {_SC("MUTEX_STATIC_APP1"),                    SQLITE_MUTEX_STATIC_APP1},
    {_SC("MUTEX_STATIC_APP2"),                    SQLITE_MUTEX_STATIC_APP2},
    {_SC("MUTEX_STATIC_APP3"),                    SQLITE_MUTEX_STATIC_APP3},
    {_SC("MUTEX_STATIC_LRU"),                     SQLITE_MUTEX_STATIC_LRU},
    {_SC("MUTEX_STATIC_LRU2"),                    SQLITE_MUTEX_STATIC_LRU2},
    {_SC("MUTEX_STATIC_MASTER"),                  SQLITE_MUTEX_STATIC_MASTER},
    {_SC("MUTEX_STATIC_MEM"),                     SQLITE_MUTEX_STATIC_MEM},
    {_SC("MUTEX_STATIC_MEM2"),                    SQLITE_MUTEX_STATIC_MEM2},
    {_SC("MUTEX_STATIC_OPEN"),                    SQLITE_MUTEX_STATIC_OPEN},
    {_SC("MUTEX_STATIC_PMEM"),                    SQLITE_MUTEX_STATIC_PMEM},
    {_SC("MUTEX_STATIC_PRNG"),                    SQLITE_MUTEX_STATIC_PRNG},
    {_SC("MUTEX_STATIC_VFS1"),                    SQLITE_MUTEX_STATIC_VFS1},
    {_SC("MUTEX_STATIC_VFS2"),                    SQLITE_MUTEX_STATIC_VFS2},
    {_SC("MUTEX_STATIC_VFS3"),                    SQLITE_MUTEX_STATIC_VFS3},
    {_SC("NOLFS"),                                SQLITE_NOLFS},
    {_SC("NOMEM"),                                SQLITE_NOMEM},
    {_SC("NOTADB"),                               SQLITE_NOTADB},
    {_SC("NOTFOUND"),                             SQLITE_NOTFOUND},
    {_SC("NOTICE"),                               SQLITE_NOTICE},
    {_SC("NOTICE_RECOVER_ROLLBACK"),              SQLITE_NOTICE_RECOVER_ROLLBACK},
    {_SC("NOTICE_RECOVER_WAL"),                   SQLITE_NOTICE_RECOVER_WAL},
    {_SC("NULL"),                                 SQLITE_NULL},
    {_SC("OK"),                                   SQLITE_OK},
    {_SC("OPEN_AUTOPROXY"),                       SQLITE_OPEN_AUTOPROXY},
    {_SC("OPEN_CREATE"),                          SQLITE_OPEN_CREATE},
    {_SC("OPEN_DELETEONCLOSE"),                   SQLITE_OPEN_DELETEONCLOSE},
    {_SC("OPEN_EXCLUSIVE"),                       SQLITE_OPEN_EXCLUSIVE},
    {_SC("OPEN_FULLMUTEX"),                       SQLITE_OPEN_FULLMUTEX},
    {_SC("OPEN_MAIN_DB"),                         SQLITE_OPEN_MAIN_DB},
    {_SC("OPEN_MAIN_JOURNAL"),                    SQLITE_OPEN_MAIN_JOURNAL},
    {_SC("OPEN_MASTER_JOURNAL"),                  SQLITE_OPEN_MASTER_JOURNAL},
    {_SC("OPEN_MEMORY"),                          SQLITE_OPEN_MEMORY},
    {_SC("OPEN_NOMUTEX"),                         SQLITE_OPEN_NOMUTEX},
    {_SC("OPEN_PRIVATECACHE"),                    SQLITE_OPEN_PRIVATECACHE},
    {_SC("OPEN_READONLY"),                        SQLITE_OPEN_READONLY},
    {_SC("OPEN_READWRITE"),                       SQLITE_OPEN_READWRITE},
    {_SC("OPEN_SHAREDCACHE"),                     SQLITE_OPEN_SHAREDCACHE},
    {_SC("OPEN_SUBJOURNAL"),                      SQLITE_OPEN_SUBJOURNAL},
    {_SC("OPEN_TEMP_DB"),                         SQLITE_OPEN_TEMP_DB},
    {_SC("OPEN_TEMP_JOURNAL"),                    SQLITE_OPEN_TEMP_JOURNAL},
    {_SC("OPEN_TRANSIENT_DB"),                    SQLITE_OPEN_TRANSIENT_DB},
    {_SC("OPEN_URI"),                             SQLITE_OPEN_URI},
    {_SC("OPEN_WAL"),                             SQLITE_OPEN_WAL},
    {_SC("PERM"),                                 SQLITE_PERM},
    {_SC("PRAGMA"),                               SQLITE_PRAGMA},
    {_SC("PROTOCOL"),                             SQLITE_PROTOCOL},
    {_SC("RANGE"),                                SQLITE_RANGE},
    {_SC("READ"),                                 SQLITE_READ},
    {_SC("READONLY"),                             SQLITE_READONLY},
    {_SC("READONLY_CANTLOCK"),                    SQLITE_READONLY_CANTLOCK},
    {_SC("READONLY_DBMOVED"),                     SQLITE_READONLY_DBMOVED},
    {_SC("READONLY_RECOVERY"),                    SQLITE_READONLY_RECOVERY},
    {_SC("READONLY_ROLLBACK"),                    SQLITE_READONLY_ROLLBACK},
    {_SC("RECURSIVE"),                            SQLITE_RECURSIVE},
    {_SC("REINDEX"),                              SQLITE_REINDEX},
    {_SC("REPLACE"),                              SQLITE_REPLACE},
    {_SC("ROLLBACK"),                             SQLITE_ROLLBACK},
    {_SC("ROW"),                                  SQLITE_ROW},
    {_SC("SAVEPOINT"),                            SQLITE_SAVEPOINT},
    {_SC("SCANSTAT_EST"),                         SQLITE_SCANSTAT_EST},
    {_SC("SCANSTAT_EXPLAIN"),                     SQLITE_SCANSTAT_EXPLAIN},
    {_SC("SCANSTAT_NAME"),                        SQLITE_SCANSTAT_NAME},
    {_SC("SCANSTAT_NLOOP"),                       SQLITE_SCANSTAT_NLOOP},
    {_SC("SCANSTAT_NVISIT"),                      SQLITE_SCANSTAT_NVISIT},
    {_SC("SCANSTAT_SELECTID"),                    SQLITE_SCANSTAT_SELECTID},
    {_SC("SCHEMA"),                               SQLITE_SCHEMA},
    {_SC("SELECT"),                               SQLITE_SELECT},
    {_SC("SHM_EXCLUSIVE"),                        SQLITE_SHM_EXCLUSIVE},
    {_SC("SHM_LOCK"),                             SQLITE_SHM_LOCK},
    {_SC("SHM_NLOCK"),                            SQLITE_SHM_NLOCK},
    {_SC("SHM_SHARED"),                           SQLITE_SHM_SHARED},
    {_SC("SHM_UNLOCK"),                           SQLITE_SHM_UNLOCK},
    {_SC("STATUS_MALLOC_COUNT"),                  SQLITE_STATUS_MALLOC_COUNT},
    {_SC("STATUS_MALLOC_SIZE"),                   SQLITE_STATUS_MALLOC_SIZE},
    {_SC("STATUS_MEMORY_USED"),                   SQLITE_STATUS_MEMORY_USED},
    {_SC("STATUS_PAGECACHE_OVERFLOW"),            SQLITE_STATUS_PAGECACHE_OVERFLOW},
    {_SC("STATUS_PAGECACHE_SIZE"),                SQLITE_STATUS_PAGECACHE_SIZE},
    {_SC("STATUS_PAGECACHE_USED"),                SQLITE_STATUS_PAGECACHE_USED},
    {_SC("STATUS_PARSER_STACK"),                  SQLITE_STATUS_PARSER_STACK},
    {_SC("STATUS_SCRATCH_OVERFLOW"),              SQLITE_STATUS_SCRATCH_OVERFLOW},
    {_SC("STATUS_SCRATCH_SIZE"),                  SQLITE_STATUS_SCRATCH_SIZE},
    {_SC("STATUS_SCRATCH_USED"),                  SQLITE_STATUS_SCRATCH_USED},
    {_SC("STMTSTATUS_AUTOINDEX"),                 SQLITE_STMTSTATUS_AUTOINDEX},
    {_SC("STMTSTATUS_FULLSCAN_STEP"),             SQLITE_STMTSTATUS_FULLSCAN_STEP},
    {_SC("STMTSTATUS_SORT"),                      SQLITE_STMTSTATUS_SORT},
    {_SC("STMTSTATUS_VM_STEP"),                   SQLITE_STMTSTATUS_VM_STEP},
    {_SC("SYNC_DATAONLY"),                        SQLITE_SYNC_DATAONLY},
    {_SC("SYNC_FULL"),                            SQLITE_SYNC_FULL},
    {_SC("SYNC_NORMAL"),                          SQLITE_SYNC_NORMAL},
    {_SC("TESTCTRL_ALWAYS"),                      SQLITE_TESTCTRL_ALWAYS},
    {_SC("TESTCTRL_ASSERT"),                      SQLITE_TESTCTRL_ASSERT},
    {_SC("TESTCTRL_BENIGN_MALLOC_HOOKS"),         SQLITE_TESTCTRL_BENIGN_MALLOC_HOOKS},
    {_SC("TESTCTRL_BITVEC_TEST"),                 SQLITE_TESTCTRL_BITVEC_TEST},
    {_SC("TESTCTRL_BYTEORDER"),                   SQLITE_TESTCTRL_BYTEORDER},
    {_SC("TESTCTRL_EXPLAIN_STMT"),                SQLITE_TESTCTRL_EXPLAIN_STMT},
    {_SC("TESTCTRL_FAULT_INSTALL"),               SQLITE_TESTCTRL_FAULT_INSTALL},
    {_SC("TESTCTRL_FIRST"),                       SQLITE_TESTCTRL_FIRST},
    {_SC("TESTCTRL_IMPOSTER"),                    SQLITE_TESTCTRL_IMPOSTER},
    {_SC("TESTCTRL_ISINIT"),                      SQLITE_TESTCTRL_ISINIT},
    {_SC("TESTCTRL_ISKEYWORD"),                   SQLITE_TESTCTRL_ISKEYWORD},
    {_SC("TESTCTRL_LAST"),                        SQLITE_TESTCTRL_LAST},
    {_SC("TESTCTRL_LOCALTIME_FAULT"),             SQLITE_TESTCTRL_LOCALTIME_FAULT},
    {_SC("TESTCTRL_NEVER_CORRUPT"),               SQLITE_TESTCTRL_NEVER_CORRUPT},
    {_SC("TESTCTRL_OPTIMIZATIONS"),               SQLITE_TESTCTRL_OPTIMIZATIONS},
    {_SC("TESTCTRL_PENDING_BYTE"),                SQLITE_TESTCTRL_PENDING_BYTE},
    {_SC("TESTCTRL_PRNG_RESET"),                  SQLITE_TESTCTRL_PRNG_RESET},
    {_SC("TESTCTRL_PRNG_RESTORE"),                SQLITE_TESTCTRL_PRNG_RESTORE},
    {_SC("TESTCTRL_PRNG_SAVE"),                   SQLITE_TESTCTRL_PRNG_SAVE},
    {_SC("TESTCTRL_RESERVE"),                     SQLITE_TESTCTRL_RESERVE},
    {_SC("TESTCTRL_SCRATCHMALLOC"),               SQLITE_TESTCTRL_SCRATCHMALLOC},
    {_SC("TESTCTRL_SORTER_MMAP"),                 SQLITE_TESTCTRL_SORTER_MMAP},
    {_SC("TESTCTRL_VDBE_COVERAGE"),               SQLITE_TESTCTRL_VDBE_COVERAGE},
    {_SC("TEXT"),                                 SQLITE_TEXT},
    {_SC("TOOBIG"),                               SQLITE_TOOBIG},
    {_SC("TRANSACTION"),                          SQLITE_TRANSACTION},
    {_SC("UPDATE"),                               SQLITE_UPDATE},
    {_SC("UTF16"),                                SQLITE_UTF16},
    {_SC("UTF16BE"),                              SQLITE_UTF16BE},
    {_SC("UTF16LE"),                              SQLITE_UTF16LE},
    {_SC("UTF16_ALIGNED"),                        SQLITE_UTF16_ALIGNED},
    {_SC("UTF8"),                                 SQLITE_UTF8},
    {_SC("VERSION_NUMBER"),                       SQLITE_VERSION_NUMBER},
    {_SC("VTAB_CONSTRAINT_SUPPORT"),              SQLITE_VTAB_CONSTRAINT_SUPPORT},
    {_SC("WARNING"),                              SQLITE_WARNING},
    {_SC("WARNING_AUTOINDEX"),                    SQLITE_WARNING_AUTOINDEX}
};

// ------------------------------------------------------------------------------------------------
static inline bool IsDigitsOnly(const SQChar * str)
{
    while (std::isdigit(*str) || std::isspace(*str))
    {
        ++str;
    }
    // Return whether we reached the end while searching
    return *str == '\0';
}

// ------------------------------------------------------------------------------------------------
Object GetConnectionObj(const ConnRef & conn)
{
    return Object(new SQLiteConnection(conn));
}

// ------------------------------------------------------------------------------------------------
Object GetStatementObj(const StmtRef & stmt)
{
    return Object(new SQLiteStatement(stmt));
}

// ------------------------------------------------------------------------------------------------
bool IsQueryEmpty(const SQChar * str)
{
    // Is the pointer valid?
    if (!str || *str == '\0')
    {
        return true;
    }
    // See if the query contains any alpha numeric characters
    while (*str != 0)
    {
        if (std::isalnum(*(str++)) != 0)
        {
            return false;
        }
    }
    // At this point we consider the query empty
    return true;
}

// ------------------------------------------------------------------------------------------------
const SQChar * GetErrStr(int32_t status)
{
    return sqlite3_errstr(status);
}

// ------------------------------------------------------------------------------------------------
void SetSoftHeapLimit(int32_t limit)
{
    sqlite3_soft_heap_limit(limit);
}

// ------------------------------------------------------------------------------------------------
int32_t ReleaseMemory(int32_t bytes)
{
    return sqlite3_release_memory(bytes);
}

// ------------------------------------------------------------------------------------------------
SQInteger GetMemoryUsage()
{
    // Obtain the initial stack size
    const StackGuard sg;
    // Push a long integer instance with the requested value on the stack
    return sqlite3_memory_used();
}

// ------------------------------------------------------------------------------------------------
SQInteger GetMemoryHighwaterMark(bool reset)
{
    // Obtain the initial stack size
    const StackGuard sg;
    // Push a long integer instance with the requested value on the stack
    return sqlite3_memory_highwater(reset);
}

// ------------------------------------------------------------------------------------------------
LightObj EscapeString(StackStrF & str)
{
    // Is there even a string to escape?
    if (str.mLen <= 0)
    {
        return LightObj(_SC(""), 0); // Default to empty string
    }
    // Allocate a memory buffer
    std::vector< SQChar > b;
    // Allocate extra space to make sure there's room for a null terminator since we need it
    // This is a f* up from SQLite devs not returning the number of written characters from snprintf
    // So we can figure out if we actually had room for the null terminator or not
    b.reserve(static_cast< size_t >(str.mLen * 2 + 1));
    // Attempt to escape the specified string
    sqlite3_snprintf(static_cast<int>(b.capacity()), b.data(), "%q", str.mPtr);
    // Return the resulted string
    LightObj o(b.data(), -1);
    return o;
}

// ------------------------------------------------------------------------------------------------
LightObj EscapeStringEx(SQChar spec, StackStrF & str)
{
    // Validate the specified format specifier
    if ((spec != 'q') && (spec != 'Q') && (spec != 'w') && (spec != 's'))
    {
        STHROWF("Unknown format specifier: '{:c}'", spec);
    }
    // Is there even a string to escape?
    else if (!str.mLen)
    {
        return LightObj(_SC(""), 0); // Default to empty string
    }
    // Utility that allows changing the format specifier temporarily
    SQChar fs[] = _SC("%q");
    // Apply the format specifier
    fs[1] = spec;
    // Allocate a memory buffer
    std::vector< SQChar > b;
    // Allocate extra space to make sure there's room for a null terminator since we need it (see above)
    b.reserve(static_cast< size_t >(str.mLen * 2 + 1));
    // Attempt to escape the specified string
    sqlite3_snprintf(static_cast<int>(b.capacity()), b.data(), fs, str.mPtr);
    // Return the resulted string
    return LightObj(b.data());
}

// ------------------------------------------------------------------------------------------------
LightObj ArrayToQueryColumns(Array & arr)
{
    // Do we even have any elements to process?
    if (arr.Length() <= 0)
    {
        return LightObj(_SC(""), 0); // Default to empty string
    }
    size_t size_estimate = 0;
    // Allocate a vector with the required amount of column names
    std::vector< String > values(static_cast< size_t >(arr.Length()));
    // Attempt to extract the array elements as strings
    arr.GetArray< String >(&values[0], static_cast<int>(values.size()));
    // Attempt to estimate the size of the buffer we'll need
    for (const auto & v : values) size_estimate += v.size();
    // Used to know the position of the next column name
    size_t offset = 0;
    // Obtain the start of the array
    auto itr = values.begin();
    // Allocate a memory buffer
    std::vector< SQChar > b;
    b.reserve(size_estimate + (size_estimate / 2));
    // Process all elements within range
    for (; itr != values.end() && offset < b.capacity(); ++itr)
    {
        // Is the name valid?
        if (itr->empty())
        {
            STHROWF("Invalid column name");
        }
        // Attempt to append the column name to the buffer
        sqlite3_snprintf(static_cast< int >(b.capacity() - offset), b.data() + offset, "[%q], ", itr->c_str());
        // Add the column name size to the offset
        offset += itr->size();
        // Also include the comma and space in the offset
        offset += 2;
    }
    // Trim the last coma and space
    if (offset >= 2)
    {
        b.data()[offset-2] = '\0'; // NOLINT(readability-simplify-subscript-expr)
    }
    else
    {
        b.data()[0] = '\0'; // NOLINT(readability-simplify-subscript-expr)
    }
    // Return the resulted string
    return LightObj(b.data());
}

// ------------------------------------------------------------------------------------------------
LightObj TableToQueryColumns(Table & tbl)
{
    auto len = tbl.GetSize();
    // Do we even have any elements to process?
    if (len <= 0)
    {
        return LightObj(_SC(""), 0); // Default to empty string
    }
    size_t size_estimate = 0;
    // Allocate a vector with the required amount of column names
    std::vector< String > values(static_cast< size_t >(len));
    // Process all elements within range
    for (Table::iterator itr; tbl.Next(itr);)
    {
        // Transform the key to string
        values.emplace_back(itr.getName());
        // Add to buffer size estimate
        size_estimate += values.back().size();
    }
    // Used to know the position of the next column name
    size_t offset = 0;
    // Obtain the start of the array
    auto itr = values.begin();
    // Allocate a memory buffer
    std::vector< SQChar > b;
    b.reserve(size_estimate + (size_estimate / 2));
    // Process all elements within range
    for (; itr != values.end() && offset < b.capacity(); ++itr)
    {
        // Is the name valid?
        if (itr->empty())
        {
            STHROWF("Invalid column name");
        }
        // Attempt to append the column name to the buffer
        sqlite3_snprintf(static_cast< int >(b.capacity() - offset), b.data() + offset, "[%q], ", itr->c_str());
        // Add the column name size to the offset
        offset += itr->size();
        // Also include the comma and space in the offset
        offset += 2;
    }
    // Trim the last coma and space
    if (offset >= 2)
    {
        b.data()[offset-2] = '\0'; // NOLINT(readability-simplify-subscript-expr)
    }
    else
    {
        b.data()[0] = '\0'; // NOLINT(readability-simplify-subscript-expr)
    }
    // Return the resulted string
    return LightObj(b.data());
}

// ------------------------------------------------------------------------------------------------
SQLiteConnHnd::SQLiteConnHnd()
    : mPtr(nullptr)
    , mStatus(SQLITE_OK)
    , mQueue()
    , mFlags(0)
    , mName()
    , mVFS()
    , mMemory(false)
    , mTrace(false)
    , mProfile(false)
{
    /* ... */
}

// ------------------------------------------------------------------------------------------------
SQLiteConnHnd::~SQLiteConnHnd()
{
    // Is there anything to close?
    if (mPtr != nullptr)
    {
        // Flush remaining queries in the queue and ignore the result
        Flush(static_cast<uint32_t>(mQueue.size()), NullObject(), NullFunction());
        // NOTE: Should we call sqlite3_interrupt(...) before closing?
        // Attempt to close the database
        if ((sqlite3_close(mPtr)) != SQLITE_OK)
        {
            LogErr("Unable to close SQLite connection [%s]", sqlite3_errmsg(mPtr));
        }
    }
}

// ------------------------------------------------------------------------------------------------
void SQLiteConnHnd::Create(const SQChar * name, int32_t flags, const SQChar * vfs)
{
    // Make sure a previous connection doesn't exist
    if (mPtr)
    {
        STHROWF("Unable to connect to database. Database already connected");
    }
    // Make sure the name is valid
    else if (!name || *name == '\0')
    {
        STHROWF("Unable to connect to database. The name is invalid");
    }
    // Attempt to create the database connection
    else if ((mStatus = sqlite3_open_v2(name, &mPtr, flags, vfs)) != SQLITE_OK)
    {
        // Grab the error message before destroying the handle
        String msg(sqlite3_errmsg(mPtr) ? sqlite3_errmsg(mPtr) : _SC("Unknown reason"));
        // Must be destroyed regardless of result
        sqlite3_close(mPtr);
        // Prevent further use of this handle
        mPtr = nullptr;
        // Now its safe to throw the error
        STHROWF("Unable to connect to database [{}]", msg.c_str());
    }
    // Let's save the specified information
    mName.assign(name);
    mFlags = flags;
    mVFS.assign(vfs ? vfs : _SC(""));
    // Optional check if database is initially stored in memory
    mMemory = (mName == _SC(":memory:"));
}

// ------------------------------------------------------------------------------------------------
int32_t SQLiteConnHnd::Flush(uint32_t num, Object & env, Function & func)
{
    // Do we even have a valid connection?
    if (!mPtr)
    {
        return -1; // No connection!
    }
    // Is there anything to flush?
    else if (!num || mQueue.empty())
    {
        return 0; // Nothing to process!
    }
    // Can we even flush that many?
    else if (num > mQueue.size())
    {
        num = static_cast<uint32_t>(mQueue.size());
    }
    // Generate the function that should be called upon error
    Function callback = Function(env.GetObj(), func.GetFunc(), env.GetVM());
    // Obtain iterators to the range of queries that should be flushed
    auto itr = mQueue.begin();
    auto end = mQueue.begin() + num;
    // Attempt to begin the flush transaction
    if ((mStatus = sqlite3_exec(mPtr, "BEGIN", nullptr, nullptr, nullptr)) != SQLITE_OK)
    {
        STHROWF("Unable to begin flush transaction [{}]", sqlite3_errmsg(mPtr));
    }
    // Process all queries within range of selection
    for (; itr != end; ++itr)
    {
        // Should we manually terminate this query?
        /*
        if (*(*itr).rbegin() != ';')
        {
            itr->push_back(';');
        }
        */
        // Attempt to execute the currently processed query string
        if ((mStatus = sqlite3_exec(mPtr, itr->c_str(), nullptr, nullptr, nullptr)) == SQLITE_OK)
        {
            continue;
        }
        // Do we have to execute any callback to resolve our issue?
        else if (!callback.IsNull())
        {
            try
            {
                // Ask the callback whether the query processing should end here
                SharedPtr< bool > ret = callback.Evaluate< bool >(mStatus, *itr);
                // Should we break here?
                if (!!ret && !(*ret))
                {
                    break;
                }
            }
            catch (const Sqrat::Exception & e)
            {
                LogErr("Squirrel error caught in flush handler [%s]", e.what());
            }
            catch (const std::exception & e)
            {
                LogErr("Program error caught in flush handler [%s]", e.what());
            }
            catch (...)
            {
                LogErr("Unknown error caught in flush handler");
            }
        }
    }
    // Erase all queries till end or till the point of failure (if any occurred)
    mQueue.erase(mQueue.begin(), itr);
    // Attempt to commit changes requested during transaction
    if ((mStatus = sqlite3_exec(mPtr, "COMMIT", nullptr, nullptr, nullptr)) == SQLITE_OK)
    {
        return sqlite3_changes(mPtr);
    }
    // Attempt to roll back erroneous changes
    else if ((mStatus = sqlite3_exec(mPtr, "ROLLBACK", nullptr, nullptr, nullptr)) != SQLITE_OK)
    {
        STHROWF("Unable to rollback flush transaction [{}]", sqlite3_errmsg(mPtr));
    }
    // The transaction failed somehow but we managed to rollback
    else
    {
        STHROWF("Unable to commit flush transaction [{}]", sqlite3_errmsg(mPtr));
    }
    // Operation failed
    return -1;
}

// ------------------------------------------------------------------------------------------------
SQLiteStmtHnd::SQLiteStmtHnd(ConnRef conn)
    : mPtr(nullptr)
    , mStatus(SQLITE_OK)
    , mConn(std::move(conn))
    , mQuery()
    , mColumns(0)
    , mParameters(0)
    , mIndexes()
    , mGood(false)
    , mDone(false)
{
    /* ... */
}

// ------------------------------------------------------------------------------------------------
SQLiteStmtHnd::~SQLiteStmtHnd()
{
    // Is there anything to finalize?
    if (mPtr != nullptr)
    {
        // Attempt to finalize the statement
        if ((sqlite3_finalize(mPtr)) != SQLITE_OK)
        {
            LogErr("Unable to finalize SQLite statement [%s]", mConn->ErrMsg());
        }
    }
}

// ------------------------------------------------------------------------------------------------
void SQLiteStmtHnd::Create(const SQChar * query, SQInteger length)
{
    // Make sure a previous statement doesn't exist
    if (mPtr)
    {
        STHROWF("Unable to prepare statement. Statement already prepared");
    }
    // Is the specified database connection is valid?
    else if (!mConn)
    {
        STHROWF("Unable to prepare statement. Invalid connection handle");
    }
    // Is the specified query string valid?
    else if (!query || !length || *query == '\0')
    {
        STHROWF("Unable to prepare statement. Invalid or empty query string");
    }
    // Save the query string
    mQuery.assign(query, static_cast< size_t >(length));
    // Attempt to prepare a statement with the specified query string
    if ((mStatus = sqlite3_prepare_v2(mConn->mPtr, mQuery.c_str(), ConvTo< int32_t >::From(mQuery.size()),
                                            &mPtr, nullptr)) != SQLITE_OK)
    {
        // Clear the query string since it failed
        mQuery.clear();
        // Explicitly make sure the handle is null
        mPtr = nullptr;
        // Now it's safe to throw the error
        STHROWF("Unable to prepare statement [{}]", mConn->ErrMsg());
    }
    else
    {
        // Obtain the number of available columns
        mColumns = sqlite3_column_count(mPtr);
        // Obtain the number of available parameters
        mParameters = sqlite3_bind_parameter_count(mPtr);
    }
}

// ------------------------------------------------------------------------------------------------
int32_t SQLiteStmtHnd::GetColumnIndex(const SQChar * name, SQInteger length)
{
    // Validate the handle
    if (!mPtr)
    {
        STHROWF("Invalid SQLite statement");
    }
    // Are the names cached?
    else if (mIndexes.empty())
    {
        for (int32_t i = 0; i < mColumns; ++i)
        {
            // Get the column name at the current index
            auto column_name = static_cast< const SQChar * >(sqlite3_column_name(mPtr, i));
            // Validate the name
            if (!column_name)
            {
                STHROWF("Unable to retrieve column name for index {}", i);
            }
            // Save it to guarantee the same lifetime as this instance
            else
            {
                mIndexes[name] = i;
            }
        }
    }
    const String str(name, length < 0 ? std::strlen(name) : length);
    // Attempt to find the specified column
    auto itr = mIndexes.find(str);
    // Was there a column with the specified name?
    if (itr != mIndexes.end())
    {
        return itr->second;
    }
    // No such column exists (expecting the invoker to validate the result)
    return -1;
}

// ------------------------------------------------------------------------------------------------
const char * SQLiteStmtHnd::ErrStr() const
{
    return mConn ? sqlite3_errstr(sqlite3_errcode(mConn->mPtr)) : _SC("");
}

// ------------------------------------------------------------------------------------------------
const char * SQLiteStmtHnd::ErrMsg() const
{
    return mConn ? sqlite3_errmsg(mConn->mPtr) : _SC("");
}

// ------------------------------------------------------------------------------------------------
int32_t SQLiteStmtHnd::ErrNo() const
{
    return mConn ? sqlite3_errcode(mConn->mPtr) : SQLITE_NOMEM;
}

// ------------------------------------------------------------------------------------------------
int32_t SQLiteStmtHnd::ExErrNo() const
{
    return mConn ? sqlite3_extended_errcode(mConn->mPtr) : SQLITE_NOMEM;
}

// ------------------------------------------------------------------------------------------------
void SQLiteConnection::TraceOutput(void * /*ptr*/, const char * sql)
{
    LogInf("SQLite Trace: %s", sql);
}

// ------------------------------------------------------------------------------------------------
void SQLiteConnection::ProfileOutput(void * /*ptr*/, const char * sql, sqlite3_uint64 time)
{
    LogInf("SQLite profile (time: %llu): %s", time, sql);
}

// ------------------------------------------------------------------------------------------------
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
void SQLiteConnection::Validate(const char * file, int32_t line) const
{
    if (!m_Handle)
    {
        SqThrowF(SQMOD_RTFMT("Invalid SQLite connection reference =>[{}:{}]"), file, line);
    }
}
#else
void SQLiteConnection::Validate() const
{
    if (!m_Handle)
    {
        SqThrowF(fmt::runtime("Invalid SQLite connection reference"));
    }
}
#endif // _DEBUG

// ------------------------------------------------------------------------------------------------
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
void SQLiteConnection::ValidateCreated(const char * file, int32_t line) const
{
    if (!m_Handle)
    {
        SqThrowF(SQMOD_RTFMT("Invalid SQLite connection reference =>[{}:{}]"), file, line);
    }
    else if (m_Handle->mPtr == nullptr)
    {
        SqThrowF(SQMOD_RTFMT("Invalid SQLite connection =>[{}:{}]"), file, line);
    }
}
#else
void SQLiteConnection::ValidateCreated() const
{
    if (!m_Handle)
    {
        SqThrowF(fmt::runtime("Invalid SQLite connection reference"));
    }
    else if (m_Handle->mPtr == nullptr)
    {
        SqThrowF(fmt::runtime("Invalid SQLite connection"));
    }
}
#endif // _DEBUG

// ------------------------------------------------------------------------------------------------
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
const ConnRef & SQLiteConnection::GetValid(const char * file, int32_t line) const
{
    Validate(file, line);
    return m_Handle;
}
#else
const ConnRef & SQLiteConnection::GetValid() const
{
    Validate();
    return m_Handle;
}
#endif // _DEBUG

// ------------------------------------------------------------------------------------------------
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
const ConnRef & SQLiteConnection::GetCreated(const char * file, int32_t line) const
{
    ValidateCreated(file, line);
    return m_Handle;
}
#else
const ConnRef & SQLiteConnection::GetCreated() const
{
    ValidateCreated();
    return m_Handle;
}
#endif // _DEBUG

// ------------------------------------------------------------------------------------------------
void SQLiteConnection::Open(StackStrF & name)
{
    // Should we create a connection handle?
    if (!m_Handle)
    {
        m_Handle = ConnRef(new SQLiteConnHnd());
    }
    // Make sure another database isn't opened
    if (SQMOD_GET_VALID(*this)->mPtr != nullptr)
    {
        STHROWF("Already referencing a valid database connection");
    }
    // Effing signed/unsigned warnings everywhere. I just need it to shut up.
    constexpr unsigned OPEN_READWRITE_F = SQLITE_OPEN_READWRITE;
    constexpr unsigned OPEN_CREATE_F = SQLITE_OPEN_CREATE;
    // Perform the requested operation
    m_Handle->Create(name.mPtr, OPEN_READWRITE_F | OPEN_CREATE_F, nullptr);
}

// ------------------------------------------------------------------------------------------------
void SQLiteConnection::Open(StackStrF & name, int32_t flags)
{
    // Should we create a connection handle?
    if (!m_Handle)
    {
        m_Handle = ConnRef(new SQLiteConnHnd());
    }
    // Make sure another database isn't opened
    if (SQMOD_GET_VALID(*this)->mPtr != nullptr)
    {
        STHROWF("Already referencing a valid database connection");
    }
    // Perform the requested operation
    m_Handle->Create(name.mPtr, flags, nullptr);
}

// ------------------------------------------------------------------------------------------------
void SQLiteConnection::Open(StackStrF & name, int32_t flags, StackStrF & vfs)
{
    // Should we create a connection handle?
    if (!m_Handle)
    {
        m_Handle = ConnRef(new SQLiteConnHnd());
    }
    // Make sure another database isn't opened
    if (SQMOD_GET_VALID(*this)->mPtr != nullptr)
    {
        STHROWF("Already referencing a valid database connection");
    }
    // Perform the requested operation
    m_Handle->Create(name.mPtr, flags, vfs.mPtr);
}

// ------------------------------------------------------------------------------------------------
int32_t SQLiteConnection::Exec(StackStrF & str)
{
    SQMOD_VALIDATE_CREATED(*this);
    // Attempt to execute the specified query
    m_Handle->mStatus = sqlite3_exec(m_Handle->mPtr, str.mPtr, nullptr, nullptr, nullptr);
    // Validate the execution result
    if (m_Handle->mStatus != SQLITE_OK)
    {
        STHROWF("Unable to execute query [{}]", m_Handle->ErrMsg());
    }
    // Return rows affected by this query
    return sqlite3_changes(m_Handle->mPtr);
}

// ------------------------------------------------------------------------------------------------
Object SQLiteConnection::Query(StackStrF & str) const
{
    SQMOD_VALIDATE_CREATED(*this);
    // Return the requested information
    return Object(new SQLiteStatement(m_Handle, str));
}

// ------------------------------------------------------------------------------------------------
void SQLiteConnection::Queue(StackStrF & str)
{
    SQMOD_VALIDATE(*this);
    // Is there a query to commit?
    if (!str.mLen || IsQueryEmpty(str.mPtr))
    {
        STHROWF("No query string to queue");
    }
    // Add the specified string to the queue
    m_Handle->mQueue.emplace_back(str.mPtr, str.mLen);
}

// ------------------------------------------------------------------------------------------------
bool SQLiteConnection::IsReadOnly() const
{
    // Request the desired information
    const int result = sqlite3_db_readonly(SQMOD_GET_CREATED(*this)->mPtr, "main");
    // Verify the result
    if (result == -1)
    {
        STHROWF("'main' is not the name of a database on connection");
    }
    // Return the requested information
    return (result != 1);
}

// ------------------------------------------------------------------------------------------------
bool SQLiteConnection::TableExists(StackStrF & name) const
{
    StackStrF query("SELECT count(*) FROM [sqlite_master] WHERE [type]='table' AND [name]=?");
    // Prepare a statement to inspect the master table
    SQLiteStatement stmt(SQMOD_GET_CREATED(*this), query);
    // Could the statement be created?
    if (stmt.IsValid())
    {
        // Bind the specified name onto the statement parameter
        SQLiteParameter(stmt.GetHandle(), 1).SetString(name);
        // Attempt to step the statement and obtain a value
        if (stmt.Step())
        {
            return (sqlite3_column_int(stmt, 0) == 1);
        }
    }
    // Assume it doesn't exist
    return false;
}

// ------------------------------------------------------------------------------------------------
void SQLiteConnection::SetTracing(bool SQ_UNUSED_ARG(toggle)) // NOLINT(readability-convert-member-functions-to-static)
{
#if defined(SQLITE_OMIT_TRACE) || defined(SQLITE_OMIT_DEPRECATED)
    STHROWF("The module was compiled without this feature");
#else
    // Check whether changes are necessary
    if (SQMOD_GET_CREATED(*this)->mTrace == toggle)
    {
        return; // No point in proceeding
    }
    // Do we have to disable it?
    else if (m_Handle->mTrace)
    {
        sqlite3_trace(m_Handle->mPtr, nullptr, nullptr);
    }
    // Go ahead and enable tracing
    else
    {
        sqlite3_trace(m_Handle->mPtr, &SQLiteConnection::TraceOutput, nullptr);
    }
#endif
}

// ------------------------------------------------------------------------------------------------
void SQLiteConnection::SetProfiling(bool SQ_UNUSED_ARG(toggle)) // NOLINT(readability-convert-member-functions-to-static)
{
#if defined(SQLITE_OMIT_TRACE) || defined(SQLITE_OMIT_DEPRECATED)
    STHROWF("The module was compiled without this feature");
#else
    // Check whether changes are necessary
    if (SQMOD_GET_CREATED(*this)->mProfile == toggle)
    {
        return; // No point in proceeding
    }
    // Do we have to disable it?
    else if (m_Handle->mProfile)
    {
        sqlite3_profile(m_Handle->mPtr, nullptr, nullptr);
    }
    // Go ahead and enable profiling
    else
    {
        sqlite3_profile(m_Handle->mPtr, &SQLiteConnection::ProfileOutput, nullptr);
    }
#endif
}

// ------------------------------------------------------------------------------------------------
void SQLiteConnection::SetBusyTimeout(int32_t millis)
{
    SQMOD_VALIDATE_CREATED(*this);
    // Apply the requested timeout
    if ((m_Handle->mStatus = sqlite3_busy_timeout(m_Handle->mPtr, millis)) != SQLITE_OK)
    {
        STHROWF("Unable to set busy timeout [{}]", m_Handle->ErrMsg());
    }
}

// ------------------------------------------------------------------------------------------------
int32_t SQLiteConnection::GetInfo(int32_t operation, bool highwater, bool reset)
{
    // Where to retrieve the information
    int32_t cur_value;
    int32_t hiwtr_value;
    // Attempt to retrieve the specified information
    if ((m_Handle->mStatus = sqlite3_db_status(SQMOD_GET_CREATED(*this)->mPtr, operation, &cur_value, &hiwtr_value, reset)) != SQLITE_OK)
    {
        STHROWF("Unable to get runtime status information", m_Handle->ErrMsg());
    }
    // Return the high-water value if requested
    else if (highwater)
    {
        return hiwtr_value;
    }
    // Return the requested information
    return cur_value;
}

// ------------------------------------------------------------------------------------------------
void SQLiteConnection::ReserveQueue(uint32_t num)
{
    SQMOD_VALIDATE(*this);
    // Perform the requested operation
    m_Handle->mQueue.reserve(m_Handle->mQueue.size() + num);
}

// ------------------------------------------------------------------------------------------------
void SQLiteConnection::PopQueue()
{
    SQMOD_VALIDATE(*this);
    // Perform the requested operation
    if (!SQMOD_GET_VALID(*this)->mQueue.empty())
    {
        m_Handle->mQueue.pop_back();
    }
}

// ------------------------------------------------------------------------------------------------
int32_t SQLiteConnection::Flush()
{
    SQMOD_VALIDATE_CREATED(*this);
    // Perform the requested operation
    return m_Handle->Flush(static_cast<uint32_t>(m_Handle->mQueue.size()), NullObject(), NullFunction());
}

// ------------------------------------------------------------------------------------------------
int32_t SQLiteConnection::Flush(SQInteger num)
{
    SQMOD_VALIDATE_CREATED(*this);
    // Perform the requested operation
    return m_Handle->Flush(ConvTo< uint32_t >::From(num), NullObject(), NullFunction());
}

// ------------------------------------------------------------------------------------------------
int32_t SQLiteConnection::Flush(Object & env, Function & func)
{
    SQMOD_VALIDATE_CREATED(*this);
    // Perform the requested operation
    return m_Handle->Flush(static_cast<uint32_t>(m_Handle->mQueue.size()), env, func);
}

// ------------------------------------------------------------------------------------------------
int32_t SQLiteConnection::Flush(SQInteger num, Object & env, Function & func)
{
    SQMOD_VALIDATE_CREATED(*this);
    // Perform the requested operation
    return m_Handle->Flush(ConvTo< uint32_t >::From(num), env, func);
}

// ------------------------------------------------------------------------------------------------
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
void SQLiteParameter::Validate(const char * file, int32_t line) const
{
    // Are we pointing to a valid index?
    if (m_Index < 0)
    {
        SqThrowF(SQMOD_RTFMT("Invalid column index: {} < 0 =>[{}:{}]"), m_Index, file, line);
    }
    // Do we have a valid statement handle?
    else if (!m_Handle)
    {
        SqThrowF(SQMOD_RTFMT("Invalid SQLite statement reference =>[{}:{}]"), file, line);
    }
}
#else
void SQLiteParameter::Validate() const
{
    // Are we pointing to a valid index?
    if (m_Index < 0)
    {
        SqThrowF(fmt::runtime("Invalid column index: {} < 0"), m_Index);
    }
    // Do we have a valid statement handle?
    else if (!m_Handle)
    {
        SqThrowF(fmt::runtime("Invalid SQLite statement reference"));
    }
}
#endif // _DEBUG

// ------------------------------------------------------------------------------------------------
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
void SQLiteParameter::ValidateCreated(const char * file, int32_t line) const
{
    // Are we pointing to a valid index?
    if (m_Index < 0)
    {
        SqThrowF(SQMOD_RTFMT("Invalid column index: {} < 0 =>[{}:{}]"), m_Index, file, line);
    }
    else if (!m_Handle)
    {
        SqThrowF(SQMOD_RTFMT("Invalid SQLite statement reference =>[{}:{}]"), file, line);
    }
    else if (m_Handle->mPtr == nullptr)
    {
        SqThrowF(SQMOD_RTFMT("Invalid SQLite statement =>[{}:{}]"), file, line);
    }
}
#else
void SQLiteParameter::ValidateCreated() const
{
    // Are we pointing to a valid index?
    if (m_Index < 0)
    {
        SqThrowF(fmt::runtime("Invalid column index: {} < 0"), m_Index);
    }
    else if (!m_Handle)
    {
        SqThrowF(fmt::runtime("Invalid SQLite statement reference"));
    }
    else if (m_Handle->mPtr == nullptr)
    {
        SqThrowF(fmt::runtime("Invalid SQLite statement"));
    }
}
#endif // _DEBUG

// ------------------------------------------------------------------------------------------------
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
const StmtRef & SQLiteParameter::GetValid(const char * file, int32_t line) const
{
    Validate(file, line);
    return m_Handle;
}
#else
const StmtRef & SQLiteParameter::GetValid() const
{
    Validate();
    return m_Handle;
}
#endif // _DEBUG

// ------------------------------------------------------------------------------------------------
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
const StmtRef & SQLiteParameter::GetCreated(const char * file, int32_t line) const
{
    ValidateCreated(file, line);
    return m_Handle;
}
#else
const StmtRef & SQLiteParameter::GetCreated() const
{
    ValidateCreated();
    return m_Handle;
}
#endif // _DEBUG

// ------------------------------------------------------------------------------------------------
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
void SQLiteParameter::ValidateParam(int32_t idx, const char * file, int32_t line) const
{
    ValidateCreated(file, line);
    // Is the specified index in range?
    if (!m_Handle->CheckParameter(idx))
    {
        SqThrowF(SQMOD_RTFMT("Parameter index is out of range ({}:{}) =>[{}:{}]"), idx, m_Handle->mParameters,
                    file, line);
    }
}
#else
void SQLiteParameter::ValidateParam(int32_t idx) const
{
    ValidateCreated();
    // Is the specified index in range?
    if (!m_Handle->CheckParameter(idx))
    {
        SqThrowF(fmt::runtime("SQLiteParameter index is out of range ({}:{})"), idx, m_Handle->mParameters);
    }
}
#endif // _DEBUG

// ------------------------------------------------------------------------------------------------
void SQLiteParameter::SetIndex(const Object & param)
{
    // Where the index will be extracted
    int32_t idx = 0;
    // Grab the object virtual machine
    HSQUIRRELVM vm = param.GetVM();
    // Remember the current stack size
    const StackGuard sg(vm);
    // Push the specified object onto the stack
    Var< const Object & >::push(vm, param);
    // Identify the type of parameter was given
    switch  (param.GetType())
    {
        // Is this a string value?
        case OT_STRING:
        {
            // Obtain the object from the stack as a string
            StackStrF val(vm, -1);
            // Validate the result
            if (SQ_FAILED(val.Proc(false)))
            {
                STHROWF("{}", LastErrorString(vm));
            }
            // Is the obtained string empty?
            else if (val.mLen <= 0)
            {
                STHROWF("Cannot use an empty parameter name");
            }
            // Attempt to find a parameter with the specified name
            idx = sqlite3_bind_parameter_index(SQMOD_GET_CREATED(*this)->mPtr, val.mPtr);
        } break;
        // Is this an integer value? (or at least can be easily converted to one)
        case OT_INTEGER:
        case OT_FLOAT:
        case OT_BOOL:
        {
            idx = ConvTo< int32_t >::From(PopStackInteger(vm, -1));
        } break;
        // Is this an instance that we can extract either a string or integer from it?
        case OT_INSTANCE:
        {
            // Obtain the object from the stack as a string
            StackStrF val(vm, -1);
            // Validate the result
            if (SQ_FAILED(val.Proc(false)))
            {
                STHROWF("{}", LastErrorString(vm));
            }
            // Is the obtained string empty?
            else if (val.mLen <= 0)
            {
                STHROWF("Cannot use an empty parameter name");
            }
            // Check if this value is made only of digits
            else if (IsDigitsOnly(val.mPtr))
            {
                idx = ConvNum< int32_t >::FromStr(val.mPtr);
            }
            // Attempt to find a parameter with the specified name
            else
            {
                idx = sqlite3_bind_parameter_index(SQMOD_GET_CREATED(*this)->mPtr, val.mPtr);
            }
        } break;
        // We don't recognize this kind of value!
        default: STHROWF("Unknown parameter index of type ({})", SqTypeName(param.GetType()));
    }
    // Assign the index with a failsafe to invalid on error
    AutoAssign< int32_t > aa(m_Index, 0, idx);
    // Validate the obtained parameter index
    SQMOD_VALIDATE_PARAM(*this, idx);
    // Don't fall back to the invalid index anymore
    aa.Set(idx);
}

// ------------------------------------------------------------------------------------------------
Object SQLiteParameter::GetStatement() const
{
    return GetStatementObj(m_Handle);
}

// ------------------------------------------------------------------------------------------------
Object SQLiteParameter::GetConnection() const
{
    return GetConnectionObj(SQMOD_GET_VALID(*this)->mConn);
}

// ------------------------------------------------------------------------------------------------
void SQLiteParameter::SetValue(const Object & value)
{
    switch (value.GetType())
    {
        case OT_NULL:
        {
            SetNull();
        } break;
        case OT_INTEGER:
        {
            SetInteger(value.Cast< SQInteger >());
        } break;
        case OT_FLOAT:
        {
            SetFloat(value.Cast< SQFloat >());
        } break;
        case OT_BOOL:
        {
            SetBool(value.Cast< bool >());
        } break;
        case OT_STRING:
        {
            SQMOD_VALIDATE_CREATED(*this);
            // Remember the current stack size
            const StackGuard sg;
            // Push the object onto the stack
            Var< Object >::push(SqVM(), value);
            // Pop the object from the stack as a string
            const Var< const SQChar * > str(SqVM(), -1);
            // Attempt to bind the specified value
            SetStringRaw(str.value, ConvTo< SQInteger >::From(str.size));
        } break;
        default: STHROWF("No known conversion for the specified value type");
    }
}

// ------------------------------------------------------------------------------------------------
void SQLiteParameter::SetBool(bool value)
{
    SQMOD_VALIDATE_CREATED(*this);
    // Attempt to bind the specified value
    m_Handle->mStatus = sqlite3_bind_int(m_Handle->mPtr, m_Index, value);
    // Validate the result
    if (m_Handle->mStatus != SQLITE_OK)
    {
        STHROWF(SQMOD_BINDFAILED, "bool", m_Index, m_Handle->ErrMsg());
    }
}

// ------------------------------------------------------------------------------------------------
void SQLiteParameter::SetChar(SQInteger value)
{
    SQMOD_VALIDATE_CREATED(*this);
    // Attempt to bind the specified value
    m_Handle->mStatus = sqlite3_bind_int(m_Handle->mPtr, m_Index, ConvTo< SQChar >::From(value));
    // Validate the result
    if (m_Handle->mStatus != SQLITE_OK)
    {
        STHROWF(SQMOD_BINDFAILED, "char", m_Index, m_Handle->ErrMsg());
    }
}

// ------------------------------------------------------------------------------------------------
void SQLiteParameter::SetInteger(SQInteger value)
{
    SQMOD_VALIDATE_CREATED(*this);
    // Attempt to bind the specified value
    m_Handle->mStatus = sqlite3_bind_integer(m_Handle->mPtr, m_Index, value);
    // Validate the result
    if (m_Handle->mStatus != SQLITE_OK)
    {
        STHROWF(SQMOD_BINDFAILED, "integer", m_Index, m_Handle->ErrMsg());
    }
}

// ------------------------------------------------------------------------------------------------
void SQLiteParameter::SetInt8(SQInteger value)
{
    SQMOD_VALIDATE_CREATED(*this);
    // Attempt to bind the specified value
    m_Handle->mStatus = sqlite3_bind_int(m_Handle->mPtr, m_Index, ConvTo< int8_t >::From(value));
    // Validate the result
    if (m_Handle->mStatus != SQLITE_OK)
    {
        STHROWF(SQMOD_BINDFAILED, "int8", m_Index, m_Handle->ErrMsg());
    }
}

// ------------------------------------------------------------------------------------------------
void SQLiteParameter::SetUint8(SQInteger value)
{
    SQMOD_VALIDATE_CREATED(*this);
    // Attempt to bind the specified value
    m_Handle->mStatus = sqlite3_bind_int(m_Handle->mPtr, m_Index, ConvTo< uint8_t >::From(value));
    // Validate the result
    if (m_Handle->mStatus != SQLITE_OK)
    {
        STHROWF(SQMOD_BINDFAILED, "uint8", m_Index, m_Handle->ErrMsg());
    }
}

// ------------------------------------------------------------------------------------------------
void SQLiteParameter::SetInt16(SQInteger value)
{
    SQMOD_VALIDATE_CREATED(*this);
    // Attempt to bind the specified value
    m_Handle->mStatus = sqlite3_bind_int(m_Handle->mPtr, m_Index, ConvTo< int16_t >::From(value));
    // Validate the result
    if (m_Handle->mStatus != SQLITE_OK)
    {
        STHROWF(SQMOD_BINDFAILED, "int16", m_Index, m_Handle->ErrMsg());
    }
}

// ------------------------------------------------------------------------------------------------
void SQLiteParameter::SetUint16(SQInteger value)
{
    SQMOD_VALIDATE_CREATED(*this);
    // Attempt to bind the specified value
    m_Handle->mStatus = sqlite3_bind_int(m_Handle->mPtr, m_Index, ConvTo< uint16_t >::From(value));
    // Validate the result
    if (m_Handle->mStatus != SQLITE_OK)
    {
        STHROWF(SQMOD_BINDFAILED, "uint16", m_Index, m_Handle->ErrMsg());
    }
}

// ------------------------------------------------------------------------------------------------
void SQLiteParameter::SetInt32(SQInteger value)
{
    SQMOD_VALIDATE_CREATED(*this);
    // Attempt to bind the specified value
    m_Handle->mStatus = sqlite3_bind_int(m_Handle->mPtr, m_Index, ConvTo< int32_t >::From(value));
    // Validate the result
    if (m_Handle->mStatus != SQLITE_OK)
    {
        STHROWF(SQMOD_BINDFAILED, "int32", m_Index, m_Handle->ErrMsg());
    }
}

// ------------------------------------------------------------------------------------------------
void SQLiteParameter::SetUint32(SQInteger value)
{
    SQMOD_VALIDATE_CREATED(*this);
    // Attempt to bind the specified value
    m_Handle->mStatus = sqlite3_bind_int(m_Handle->mPtr, m_Index, static_cast< int32_t >(ConvTo< uint32_t >::From(value)));
    // Validate the result
    if (m_Handle->mStatus != SQLITE_OK)
    {
        STHROWF(SQMOD_BINDFAILED, "uint32", m_Index, m_Handle->ErrMsg());
    }
}

// ------------------------------------------------------------------------------------------------
void SQLiteParameter::SetInt64(SQInteger value)
{
    SQMOD_VALIDATE_CREATED(*this);
    // Attempt to bind the specified value
    m_Handle->mStatus = sqlite3_bind_int64(m_Handle->mPtr, m_Index, value);
    // Validate the result
    if (m_Handle->mStatus != SQLITE_OK)
    {
        STHROWF(SQMOD_BINDFAILED, "int64", m_Index, m_Handle->ErrMsg());
    }
}

// ------------------------------------------------------------------------------------------------
void SQLiteParameter::SetUint64(SQInteger value)
{
    SQMOD_VALIDATE_CREATED(*this);
    // Attempt to bind the specified value
    m_Handle->mStatus = sqlite3_bind_int64(m_Handle->mPtr, m_Index, value);
    // Validate the result
    if (m_Handle->mStatus != SQLITE_OK)
    {
        STHROWF(SQMOD_BINDFAILED, "uint64", m_Index, m_Handle->ErrMsg());
    }
}

// ------------------------------------------------------------------------------------------------
void SQLiteParameter::SetFloat(SQFloat value)
{
    SQMOD_VALIDATE_CREATED(*this);
    // Attempt to bind the specified value
    m_Handle->mStatus = sqlite3_bind_double(m_Handle->mPtr, m_Index, value);
    // Validate the result
    if (m_Handle->mStatus != SQLITE_OK)
    {
        STHROWF(SQMOD_BINDFAILED, "float", m_Index, m_Handle->ErrMsg());
    }
}

// ------------------------------------------------------------------------------------------------
void SQLiteParameter::SetFloat32(SQFloat value)
{
    SQMOD_VALIDATE_CREATED(*this);
    // Attempt to bind the specified value
    m_Handle->mStatus = sqlite3_bind_double(m_Handle->mPtr, m_Index, ConvTo< float >::From(value));
    // Validate the result
    if (m_Handle->mStatus != SQLITE_OK)
    {
        STHROWF(SQMOD_BINDFAILED, "float32", m_Index, m_Handle->ErrMsg());
    }
}

// ------------------------------------------------------------------------------------------------
void SQLiteParameter::SetFloat64(SQFloat value)
{
    SQMOD_VALIDATE_CREATED(*this);
    // Attempt to bind the specified value
    m_Handle->mStatus = sqlite3_bind_double(m_Handle->mPtr, m_Index, value);
    // Validate the result
    if (m_Handle->mStatus != SQLITE_OK)
    {
        STHROWF(SQMOD_BINDFAILED, "float64", m_Index, m_Handle->ErrMsg());
    }
}

// ------------------------------------------------------------------------------------------------
void SQLiteParameter::SetString(StackStrF & value)
{
    SQMOD_VALIDATE_CREATED(*this);
    // Attempt to bind the specified value
    m_Handle->mStatus = sqlite3_bind_text(m_Handle->mPtr, m_Index, value.mPtr, static_cast<int>(value.mLen), SQLITE_TRANSIENT);
    // Validate the result
    if (m_Handle->mStatus != SQLITE_OK)
    {
        STHROWF(SQMOD_BINDFAILED, "string", m_Index, m_Handle->ErrMsg());
    }
}

// ------------------------------------------------------------------------------------------------
void SQLiteParameter::SetStringRaw(const SQChar * value, SQInteger length)
{
    SQMOD_VALIDATE_CREATED(*this);
    // Attempt to bind the specified value
    m_Handle->mStatus = sqlite3_bind_text(m_Handle->mPtr, m_Index, value, static_cast<int>(length), SQLITE_TRANSIENT);
    // Validate the result
    if (m_Handle->mStatus != SQLITE_OK)
    {
        STHROWF(SQMOD_BINDFAILED, "string", m_Index, m_Handle->ErrMsg());
    }
}

// ------------------------------------------------------------------------------------------------
void SQLiteParameter::SetZeroBlob(SQInteger size)
{
    SQMOD_VALIDATE_CREATED(*this);
    // Attempt to bind the specified value
    m_Handle->mStatus = sqlite3_bind_zeroblob(m_Handle->mPtr, m_Index, ConvTo< int32_t >::From(size));
    // Validate the result
    if (m_Handle->mStatus != SQLITE_OK)
    {
        STHROWF(SQMOD_BINDFAILED, "blob", m_Index, m_Handle->ErrMsg());
    }
}

// ------------------------------------------------------------------------------------------------
void SQLiteParameter::SetBlob(const Object & value)
{
    SQMOD_VALIDATE_CREATED(*this);
    // The blob data pointer and size
    SQUserPointer ptr = nullptr;
    SQInteger len;
    // Grab the associated object virtual machine
    HSQUIRRELVM vm = value.GetVM();
    // Extract the blob data from the specified object
    {
        // Remember the current stack size
        const StackGuard sg(vm);
        // Push the specified object onto the stack
        Var< const Object & >::push(vm, value);
        // Grab the blob data pointer
        if (SQ_FAILED(sqstd_getblob(vm, -1, &ptr)))
        {
            STHROWF("Unable to obtain the blob data");
        }
        // Grab the blob data size
        len = sqstd_getblobsize(vm, -1);
    }
    // Attempt to bind the specified value
    m_Handle->mStatus = sqlite3_bind_blob(m_Handle->mPtr, m_Index, ptr, static_cast<int>(len), SQLITE_TRANSIENT);
    // Validate the result
    if (m_Handle->mStatus != SQLITE_OK)
    {
        STHROWF(SQMOD_BINDFAILED, "blob", m_Index, m_Handle->ErrMsg());
    }
}
// ------------------------------------------------------------------------------------------------
void SQLiteParameter::SetData(const SqBuffer & value)
{
    // Grab the internal buffer
    Buffer & buff = *value.GetRef();
    // Attempt to bind the specified value
#ifdef _SQ64
    m_Handle->mStatus = sqlite3_bind_blob64(m_Handle->mPtr, m_Index, buff.Data(), buff.Position(), SQLITE_TRANSIENT);
#else
    m_Handle->mStatus = sqlite3_bind_blob(m_Handle->mPtr, m_Index, buff.Data(), buff.Position(), SQLITE_TRANSIENT);
#endif
    // Validate the result
    if (m_Handle->mStatus != SQLITE_OK)
    {
        STHROWF(SQMOD_BINDFAILED, "buffer", m_Index, m_Handle->ErrMsg());
    }
}

// ------------------------------------------------------------------------------------------------
void SQLiteParameter::SetDataEx(const SqBuffer & value, SQInteger offset, SQInteger length)
{
    // Grab the internal buffer
    Buffer & buff = *value.GetRef();
    // Make sure we are within range
    if (offset < 0)
    {
        STHROWF("Negative buffer offset is not allowed: {}", offset);
    }
    else if (offset < 0)
    {
        STHROWF("Negative buffer length is not allowed: {}", length);
    }
    else if (offset + length > buff.Capacity())
    {
        STHROWF("Buffer range is outside boundaries: ({}+{}) > {}", offset, length, buff.Capacity());
    }
    // Attempt to bind the specified value
#ifdef _SQ64
    m_Handle->mStatus = sqlite3_bind_blob64(m_Handle->mPtr, m_Index, (buff.Data() + offset), static_cast< sqlite3_uint64 >(offset + length), SQLITE_TRANSIENT);
#else
    m_Handle->mStatus = sqlite3_bind_blob(m_Handle->mPtr, m_Index, (buff.Data() + offset), static_cast< int >(offset + length), SQLITE_TRANSIENT);
#endif
    // Validate the result
    if (m_Handle->mStatus != SQLITE_OK)
    {
        STHROWF(SQMOD_BINDFAILED, "buffer", m_Index, m_Handle->ErrMsg());
    }
}

// ------------------------------------------------------------------------------------------------
void SQLiteParameter::SetDate(const Date & value)
{
    SQMOD_VALIDATE_CREATED(*this);
    // Attempt to generate the specified date string
    auto str = fmt::format("{} 00:00:00", value.ToString());
    // Attempt to bind the specified value
    m_Handle->mStatus = sqlite3_bind_text(m_Handle->mPtr, m_Index, str.data(), static_cast< int >(str.size()), SQLITE_TRANSIENT);
    // Validate the result
    if (m_Handle->mStatus != SQLITE_OK)
    {
        STHROWF(SQMOD_BINDFAILED, "date", m_Index, m_Handle->ErrMsg());
    }
}

// ------------------------------------------------------------------------------------------------
void SQLiteParameter::SetDateEx(SQInteger year, SQInteger month, SQInteger day)
{
    SQMOD_VALIDATE_CREATED(*this);
    // Convert the specified values within the proper ranges
    const uint16_t y = ConvTo< uint16_t >::From(year);
    const uint8_t m = ConvTo< uint8_t >::From(month), d = ConvTo< uint8_t >::From(day);
    // Validate the specified date
    if (!Chrono::ValidDate(y, m, d))
    {
        STHROWF("Invalid date ({}-{}-{})", y, m, d);
    }
    // Attempt to generate the specified date string
    auto str = fmt::format("{}-{}-{} 00:00:00", y, m, d);
    // Attempt to bind the specified value
    m_Handle->mStatus = sqlite3_bind_text(m_Handle->mPtr, m_Index, str.data(), static_cast< int >(str.size()), SQLITE_TRANSIENT);
    // Validate the result
    if (m_Handle->mStatus != SQLITE_OK)
    {
        STHROWF(SQMOD_BINDFAILED, "date", m_Index, m_Handle->ErrMsg());
    }
}

// ------------------------------------------------------------------------------------------------
void SQLiteParameter::SetTime(const Time & value)
{
    SQMOD_VALIDATE_CREATED(*this);
    // Attempt to bind the specified value
    m_Handle->mStatus = sqlite3_bind_int(m_Handle->mPtr, m_Index, static_cast<int>(value.GetTimestamp().GetSecondsI()));
    // Validate the result
    if (m_Handle->mStatus != SQLITE_OK)
    {
        STHROWF(SQMOD_BINDFAILED, "time", m_Index, m_Handle->ErrMsg());
    }
}

// ------------------------------------------------------------------------------------------------
void SQLiteParameter::SetTimeEx(SQInteger hour, SQInteger minute, SQInteger second)
{
    SQMOD_VALIDATE_CREATED(*this);
    // Convert the specified values within the proper ranges
    const uint8_t h = ConvTo< uint8_t >::From(hour)
                , m = ConvTo< uint8_t >::From(minute)
                , s = ConvTo< uint8_t >::From(second);
    // Is the specified hour within range?
    if (h >= 24)
    {
        STHROWF("Hour value is out of range: {} >= 24", h);
    }
    // Is the specified minute within range?
    else if (m >= 60)
    {
        STHROWF("Minute value is out of range: {} >= 60", m);
    }
    // Is the specified second within range?
    else if (s >= 60)
    {
        STHROWF("Second value is out of range: {} >= 60", s);
    }
    // Calculate the number of seconds in the specified time and bind the resulted value
    m_Handle->mStatus = sqlite3_bind_int(m_Handle->mPtr, m_Index, (h * (60 * 60)) + (m * 60) + s);
    // Validate the result
    if (m_Handle->mStatus != SQLITE_OK)
    {
        STHROWF(SQMOD_BINDFAILED, "time", m_Index, m_Handle->ErrMsg());
    }
}

// ------------------------------------------------------------------------------------------------
void SQLiteParameter::SetDatetime(const Datetime & value)
{
    SetDatetimeEx(value.GetYear(), value.GetMonth(), value.GetDay(), value.GetHour(), value.GetMinute(), value.GetSecond());
}

// ------------------------------------------------------------------------------------------------
void SQLiteParameter::SetDatetimeEx(SQInteger year, SQInteger month, SQInteger day, SQInteger hour, SQInteger minute, SQInteger second)
{
    SQMOD_VALIDATE_CREATED(*this);
    // Convert the specified values within the proper ranges
    const uint16_t y = ConvTo< uint16_t >::From(year);
    const uint8_t mo = ConvTo< uint8_t >::From(month)
                , d = ConvTo< uint8_t >::From(day)
                , h = ConvTo< uint8_t >::From(hour)
                , mi = ConvTo< uint8_t >::From(minute)
                , s = ConvTo< uint8_t >::From(second);
    // Validate the specified date
    if (!Chrono::ValidDate(y, mo, d))
    {
        STHROWF("Invalid date ({}-{}-{})", y, mo, d);
    }
    // Is the specified hour within range?
    else if (h >= 24)
    {
        STHROWF("Hour value is out of range: {} >= 24", h);
    }
    // Is the specified minute within range?
    else if (mi >= 60)
    {
        STHROWF("Minute value is out of range: {} >= 60", mi);
    }
    // Is the specified second within range?
    else if (s >= 60)
    {
        STHROWF("Second value is out of range: {} >= 60", s);
    }
    // Attempt to generate the specified date string
    auto str = fmt::format(_SC("{:04}-{:02}-{:02} {:02}:{:02}:{:02}"), y, mo, d, h, mi, s);
    // Attempt to bind the specified value
    m_Handle->mStatus = sqlite3_bind_text(m_Handle->mPtr, m_Index, str.data(), static_cast< int >(str.size()), SQLITE_TRANSIENT);
    // Validate the result
    if (m_Handle->mStatus != SQLITE_OK)
    {
        STHROWF(SQMOD_BINDFAILED, "date-time", m_Index, m_Handle->ErrMsg());
    }
}

// ------------------------------------------------------------------------------------------------
void SQLiteParameter::SetNow()
{
    SQMOD_VALIDATE_CREATED(*this);
    // Attempt to bind the specified value
    m_Handle->mStatus = sqlite3_bind_int(m_Handle->mPtr, m_Index,
                                            static_cast< int32_t >(std::time(nullptr)));
    // Validate the result
    if (m_Handle->mStatus != SQLITE_OK)
    {
        STHROWF(SQMOD_BINDFAILED, "time-stamp", m_Index, m_Handle->ErrMsg());
    }
}

// ------------------------------------------------------------------------------------------------
void SQLiteParameter::SetNull()
{
    SQMOD_VALIDATE_CREATED(*this);
    // Attempt to bind the specified value
    m_Handle->mStatus = sqlite3_bind_null(m_Handle->mPtr, m_Index);
    // Validate the result
    if (m_Handle->mStatus != SQLITE_OK)
    {
        STHROWF(SQMOD_BINDFAILED, "null", m_Index, m_Handle->ErrMsg());
    }
}

// ------------------------------------------------------------------------------------------------
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
void SQLiteColumn::Validate(const char * file, int32_t line) const
{
    // Are we pointing to a valid index?
    if (m_Index < 0)
    {
        SqThrowF(SQMOD_RTFMT("Invalid column index: {} < 0 =>[{}:{}]"), m_Index, file, line);
    }
    // Do we have a valid statement handle?
    else if (!m_Handle)
    {
        SqThrowF(SQMOD_RTFMT("Invalid SQLite statement reference =>[{}:{}]"), file, line);
    }
}
#else
void SQLiteColumn::Validate() const
{
    // Are we pointing to a valid index?
    if (m_Index < 0)
    {
        SqThrowF(fmt::runtime("Invalid column index: {} < 0"), m_Index);
    }
    // Do we have a valid statement handle?
    else if (!m_Handle)
    {
        SqThrowF(fmt::runtime("Invalid SQLite statement reference"));
    }
}
#endif // _DEBUG

// ------------------------------------------------------------------------------------------------
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
void SQLiteColumn::ValidateCreated(const char * file, int32_t line) const
{
    // Are we pointing to a valid index?
    if (m_Index < 0)
    {
        SqThrowF(SQMOD_RTFMT("Invalid column index: {} < 0 =>[{}:{}]"), m_Index, file, line);
    }
    else if (!m_Handle)
    {
        SqThrowF(SQMOD_RTFMT("Invalid SQLite statement reference =>[{}:{}]"), file, line);
    }
    else if (m_Handle->mPtr == nullptr)
    {
        SqThrowF(SQMOD_RTFMT("Invalid SQLite statement =>[{}:{}]"), file, line);
    }
}
#else
void SQLiteColumn::ValidateCreated() const
{
    // Are we pointing to a valid index?
    if (m_Index < 0)
    {
        SqThrowF(fmt::runtime("Invalid column index: {} < 0"), m_Index);
    }
    else if (!m_Handle)
    {
        SqThrowF(fmt::runtime("Invalid SQLite statement reference"));
    }
    else if (m_Handle->mPtr == nullptr)
    {
        SqThrowF(fmt::runtime("Invalid SQLite statement"));
    }
}
#endif // _DEBUG

// ------------------------------------------------------------------------------------------------
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
const StmtRef & SQLiteColumn::GetValid(const char * file, int32_t line) const
{
    Validate(file, line);
    return m_Handle;
}
#else
const StmtRef & SQLiteColumn::GetValid() const
{
    Validate();
    return m_Handle;
}
#endif // _DEBUG

// ------------------------------------------------------------------------------------------------
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
const StmtRef & SQLiteColumn::GetCreated(const char * file, int32_t line) const
{
    ValidateCreated(file, line);
    return m_Handle;
}
#else
const StmtRef & SQLiteColumn::GetCreated() const
{
    ValidateCreated();
    return m_Handle;
}
#endif // _DEBUG

// ------------------------------------------------------------------------------------------------
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
void SQLiteColumn::ValidateColumn(int32_t idx, const char * file, int32_t line) const
{
    ValidateCreated(file, line);
    // Is the specified index in range?
    if (!m_Handle->CheckColumn(idx))
    {
        SqThrowF(SQMOD_RTFMT("Column index is out of range: {}:{} =>[{}:{}]"), idx, m_Handle->mColumns,
                    file, line);
    }
}
#else
void SQLiteColumn::ValidateColumn(int32_t idx) const
{
    ValidateCreated();
    // Is the specified index in range?
    if (!m_Handle->CheckColumn(idx))
    {
        SqThrowF(fmt::runtime("Column index is out of range: {}:{}"), idx, m_Handle->mColumns);
    }
}
#endif // _DEBUG

// ------------------------------------------------------------------------------------------------
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
void SQLiteColumn::ValidateRow(const char * file, int32_t line) const
{
    ValidateCreated(file, line);
    // Do we have any rows available?
    if (!m_Handle->mGood)
    {
        STHROWF("No row available =>[{}:{}]", file, line);
    }
}
#else
void SQLiteColumn::ValidateRow() const
{
    ValidateCreated();
    // Do we have any rows available?
    if (!m_Handle->mGood)
    {
        STHROWF("No row available");
    }
}
#endif // _DEBUG

// ------------------------------------------------------------------------------------------------
void SQLiteColumn::SetIndex(const Object & column)
{
    // Where the index will be extracted
    int32_t idx = -1;
    // Grab the object virtual machine
    HSQUIRRELVM vm = column.GetVM();
    // Remember the current stack size
    const StackGuard sg(vm);
    // Push the specified object onto the stack
    Var< const Object & >::push(vm, column);
    // Identify the type of column was given
    switch  (column.GetType())
    {
        // Is this a string value?
        case OT_STRING:
        {
            // Obtain the object from the stack as a string
            StackStrF val(vm, -1);
            // Validate the result
            if (SQ_FAILED(val.Proc(false)))
            {
                STHROWF("{}", LastErrorString(vm));
            }
            // Is the obtained string empty?
            else if (val.mLen <= 0)
            {
                STHROWF("Cannot use an empty column name");
            }
            // Attempt to find a column with the specified name
            idx = m_Handle->GetColumnIndex(val.mPtr);
        } break;
        // Is this an integer value? (or at least can be easily converted to one)
        case OT_INTEGER:
        case OT_FLOAT:
        case OT_BOOL:
        {
            idx = ConvTo< int32_t >::From(PopStackInteger(vm, -1));
        } break;
        // Is this an instance that we can extract either a string or integer from it?
        case OT_INSTANCE:
        {
            // Obtain the object from the stack as a string
            StackStrF val(vm, -1);
            // Validate the result
            if (SQ_FAILED(val.Proc(false)))
            {
                STHROWF("{}", LastErrorString(vm));
            }
            // Is the obtained string empty?
            else if (val.mLen <= 0)
            {
                STHROWF("Cannot use an empty column name");
            }
            // Check if this value is made only of digits
            else if (IsDigitsOnly(val.mPtr))
            {
                idx = ConvNum< int32_t >::FromStr(val.mPtr);
            }
            // Attempt to find a column with the specified name
            else
            {
                idx = m_Handle->GetColumnIndex(val.mPtr);
            }
        } break;
        // We don't recognize this kind of value!
        default: STHROWF("Unknown column index of type ({})", SqTypeName(column.GetType()));
    }
    // Assign the index with a failsafe to invalid on error
    AutoAssign< int32_t > aa(m_Index, -1, idx);
    // Validate the obtained column index
    SQMOD_VALIDATE_COLUMN(*this, idx);
    // Don't fall back to the invalid index anymore
    aa.Set(idx);
}

// ------------------------------------------------------------------------------------------------
Object SQLiteColumn::GetStatement() const
{
    return GetStatementObj(m_Handle);
}

// ------------------------------------------------------------------------------------------------
Object SQLiteColumn::GetConnection() const
{
    return GetConnectionObj(SQMOD_GET_VALID(*this)->mConn);
}

// ------------------------------------------------------------------------------------------------
bool SQLiteColumn::IsNull() const
{
    return (sqlite3_column_type(SQMOD_GET_CREATED(*this)->mPtr, m_Index) == SQLITE_NULL);
}

// ------------------------------------------------------------------------------------------------
const SQChar * SQLiteColumn::GetName() const
{
    return sqlite3_column_name(SQMOD_GET_CREATED(*this)->mPtr, m_Index);
}

// ------------------------------------------------------------------------------------------------
const SQChar * SQLiteColumn::GetOriginName() const // NOLINT(readability-convert-member-functions-to-static)
{
#ifdef SQLITE_ENABLE_COLUMN_METADATA
    return sqlite3_column_origin_name(SQMOD_GET_CREATED(*this)->mPtr, m_Index);
#else
    STHROWF("The module was compiled without this feature");
    // Request failed
    return _SC("");
#endif
}

// ------------------------------------------------------------------------------------------------
int32_t SQLiteColumn::GetType() const
{
    return sqlite3_column_type(SQMOD_GET_CREATED(*this)->mPtr, m_Index);
}

// ------------------------------------------------------------------------------------------------
int32_t SQLiteColumn::GetBytes() const
{
    return sqlite3_column_bytes(SQMOD_GET_CREATED(*this)->mPtr, m_Index);
}

// ------------------------------------------------------------------------------------------------
Object SQLiteColumn::GetValue() const
{
    SQMOD_VALIDATE_ROW(*this);
    // Obtain the initial stack size
    const StackGuard sg;
    // Identify which type of value must be pushed on the stack
    switch (sqlite3_column_type(m_Handle->mPtr, m_Index))
    {
        // Is this a null value?
        case SQLITE_NULL:
        {
            sq_pushnull(SqVM());
        } break;
        // Is this an integer?
        case SQLITE_INTEGER:
        {
            sq_pushinteger(SqVM(), sqlite3_column_integer(m_Handle->mPtr, m_Index));
        } break;
        // Is this a floating point?
        case SQLITE_FLOAT:
        {
            sq_pushfloat(SqVM(),
                            ConvTo< SQFloat >::From(sqlite3_column_double(m_Handle->mPtr, m_Index)));
        } break;
        // Is this a string?
        case SQLITE_TEXT:
        {
            sq_pushstring(SqVM(),
                            reinterpret_cast< const SQChar * >(sqlite3_column_text(m_Handle->mPtr, m_Index)),
                            sqlite3_column_bytes(m_Handle->mPtr, m_Index));
        } break;
        // Is this raw data?
        case SQLITE_BLOB:
        {
            // Retrieve the size of the blob that must be allocated
            const int32_t size = sqlite3_column_bytes(m_Handle->mPtr, m_Index);
            // Retrieve the the actual blob data that must be returned
            auto data = reinterpret_cast< const char * >(sqlite3_column_blob(m_Handle->mPtr, m_Index));
            // Attempt to create a buffer with the blob data on the stack
            Var< const SqBuffer & >::push(SqVM(), SqBuffer(data, size, 0));
        } break;
        // Unknown type
        default: STHROWF("Unknown value to fetch at index: {}", m_Index);
    }
    // Obtain the object with the value from the stack and return it
    return Var< Object >(SqVM(), -1).value;
}

// ------------------------------------------------------------------------------------------------
Object SQLiteColumn::GetNumber() const
{
    SQMOD_VALIDATE_ROW(*this);
    // Obtain the initial stack size
    const StackGuard sg;
    // Identify which type of value must be pushed on the stack
    switch (sqlite3_column_type(m_Handle->mPtr, m_Index))
    {
        // Is this a null value?
        case SQLITE_NULL:
        {
            sq_pushinteger(SqVM(), 0);
        } break;
        // Is this an integer?
        case SQLITE_INTEGER:
        {
            sq_pushinteger(SqVM(), sqlite3_column_integer(m_Handle->mPtr, m_Index));
        } break;
        // Is this a floating point?
        case SQLITE_FLOAT:
        {
            sq_pushfloat(SqVM(),
                            ConvTo< SQFloat >::From(sqlite3_column_double(m_Handle->mPtr, m_Index)));
        } break;
        // Is this a string?
        case SQLITE_TEXT:
        {
            auto str = reinterpret_cast< const SQChar * >(sqlite3_column_text(m_Handle->mPtr, m_Index));
            // Is there even a string to parse?
            if (!str || *str == '\0')
            {
                sq_pushinteger(SqVM(), 0);
            }
            // Can we treat this string as a float?
            else if (!std::strchr(str, '.'))
            {
                sq_pushfloat(SqVM(),
                                ConvTo< SQFloat >::From(std::strtod(str, nullptr)));
            }
            else
            {
                sq_pushinteger(SqVM(),
                                ConvTo< SQInteger >::From(std::strtoll(str, nullptr, 10)));

            }
        } break;
        // Unknown type
        default: STHROWF("Unknown number to fetch at index: {}", m_Index);
    }
    // Obtain the object with the value from the stack and return it
    return Var< Object >(SqVM(), -1).value;
}

// ------------------------------------------------------------------------------------------------
SQInteger SQLiteColumn::GetInteger() const
{
    SQMOD_VALIDATE_ROW(*this);
    // Return the requested information
    return sqlite3_column_integer(m_Handle->mPtr, m_Index);
}

// ------------------------------------------------------------------------------------------------
SQFloat SQLiteColumn::GetFloat() const
{
    SQMOD_VALIDATE_ROW(*this);
    // Return the requested information
    return ConvTo< SQFloat >::From(sqlite3_column_double(m_Handle->mPtr, m_Index));
}

// ------------------------------------------------------------------------------------------------
SQInteger SQLiteColumn::GetLong() const
{
    SQMOD_VALIDATE_ROW(*this);
    // Return the requested information
    return sqlite3_column_int64(m_Handle->mPtr, m_Index);
}

// ------------------------------------------------------------------------------------------------
Object SQLiteColumn::GetString() const
{
    SQMOD_VALIDATE_ROW(*this);
    // Obtain the initial stack size
    const StackGuard sg;
    // Push the column text on the stack
    sq_pushstring(SqVM(), reinterpret_cast< const SQChar * >(sqlite3_column_text(m_Handle->mPtr, m_Index)),
                            sqlite3_column_bytes(m_Handle->mPtr, m_Index));
    // Get the object from the stack and return it
    return Var< Object >(SqVM(), -1).value;
}

// ------------------------------------------------------------------------------------------------
bool SQLiteColumn::GetBoolean() const
{
    SQMOD_VALIDATE_ROW(*this);
    // Return the requested information
    return sqlite3_column_int(m_Handle->mPtr, m_Index) > 0;
}

// ------------------------------------------------------------------------------------------------
SQChar SQLiteColumn::GetChar() const
{
    SQMOD_VALIDATE_ROW(*this);
    // Return the requested information
    return (SQChar)sqlite3_column_int(m_Handle->mPtr, m_Index);
}

// ------------------------------------------------------------------------------------------------
Object SQLiteColumn::GetBuffer() const
{
    SQMOD_VALIDATE_ROW(*this);
    // Remember the current stack size
    const StackGuard sg;
    // Retrieve the size of the blob that must be allocated
    const int32_t size = sqlite3_column_bytes(m_Handle->mPtr, m_Index);
    // Retrieve the the actual blob data that must be returned
    auto data = reinterpret_cast< const char * >(sqlite3_column_blob(m_Handle->mPtr, m_Index));
    // Attempt to create a buffer with the blob data on the stack
    Var< const SqBuffer & >::push(SqVM(), SqBuffer(data, size, 0));
    // Get the object from the stack and return it
    return Var< Object >(SqVM(), -1).value;
}

// ------------------------------------------------------------------------------------------------
Object SQLiteColumn::GetBlob() const
{
    SQMOD_VALIDATE_ROW(*this);
    // Obtain the initial stack size
    const StackGuard sg;
    // Obtain the size of the data
    const int32_t sz = sqlite3_column_bytes(m_Handle->mPtr, m_Index);
    // Allocate a blob of the same size
    SQUserPointer p = sqstd_createblob(SqVM(), sz);
    // Obtain a pointer to the data
    const void * b = sqlite3_column_blob(m_Handle->mPtr, m_Index);
    // Could the memory blob be allocated?
    if (!p)
    {
        STHROWF("Unable to allocate space for column blob value");
    }
    // Is there any data to read?
    else if (!b)
    {
        // Pop the memory blob from the stack
        sq_pop(SqVM(), 1);
        // Push a null value instead
        sq_pushnull(SqVM());
    }
    // Copy the data into the memory blob
    else
    {
        std::memcpy(p, b, static_cast< size_t >(sz));
    }
    // Get the object from the stack and return it
    return Var< Object >(SqVM(), -1).value;
}

// ------------------------------------------------------------------------------------------------
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
void SQLiteStatement::Validate(const char * file, int32_t line) const
{
    if (!m_Handle)
    {
        SqThrowF(SQMOD_RTFMT("Invalid SQLite statement reference =>[{}:{}]"), file, line);
    }
}
#else
void SQLiteStatement::Validate() const
{
    if (!m_Handle)
    {
        SqThrowF(fmt::runtime("Invalid SQLite statement reference"));
    }
}
#endif // _DEBUG

// ------------------------------------------------------------------------------------------------
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
void SQLiteStatement::ValidateCreated(const char * file, int32_t line) const
{
    if (!m_Handle)
    {
        SqThrowF(SQMOD_RTFMT("Invalid SQLite statement reference =>[{}:{}]"), file, line);
    }
    else if (m_Handle->mPtr == nullptr)
    {
        SqThrowF(SQMOD_RTFMT("Invalid SQLite statement =>[{}:{}]"), file, line);
    }
}
#else
void SQLiteStatement::ValidateCreated() const
{
    if (!m_Handle)
    {
        SqThrowF(fmt::runtime("Invalid SQLite statement reference"));
    }
    else if (m_Handle->mPtr == nullptr)
    {
        SqThrowF(fmt::runtime("Invalid SQLite statement"));
    }
}
#endif // _DEBUG

// ------------------------------------------------------------------------------------------------
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
const StmtRef & SQLiteStatement::GetValid(const char * file, int32_t line) const
{
    Validate(file, line);
    return m_Handle;
}
#else
const StmtRef & SQLiteStatement::GetValid() const
{
    Validate();
    return m_Handle;
}
#endif // _DEBUG

// ------------------------------------------------------------------------------------------------
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
const StmtRef & SQLiteStatement::GetCreated(const char * file, int32_t line) const
{
    ValidateCreated(file, line);
    return m_Handle;
}
#else
const StmtRef & SQLiteStatement::GetCreated() const
{
    ValidateCreated();
    return m_Handle;
}
#endif // _DEBUG

// ------------------------------------------------------------------------------------------------
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
void SQLiteStatement::ValidateColumn(int32_t idx, const char * file, int32_t line) const
{
    ValidateCreated(file, line);
    // Is the specified index in range?
    if (!m_Handle->CheckColumn(idx))
    {
        SqThrowF(SQMOD_RTFMT("Column index is out of range: {}:{} =>[{}:{}]"), idx, m_Handle->mColumns, file, line);
    }
}
#else
void SQLiteStatement::ValidateColumn(int32_t idx) const
{
    ValidateCreated();
    // Is the specified index in range?
    if (!m_Handle->CheckColumn(idx))
    {
        SqThrowF(fmt::runtime("Column index is out of range: {}:{}"), idx, m_Handle->mColumns);
    }
}
#endif // _DEBUG

// ------------------------------------------------------------------------------------------------
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
void SQLiteStatement::ValidateParam(int32_t idx, const char * file, int32_t line) const
{
    ValidateCreated(file, line);
    // Is the specified index in range?
    if (!m_Handle->CheckParameter(idx))
    {
        SqThrowF(SQMOD_RTFMT("Parameter index is out of range: {}:{} =>[{}:{}]"), idx, m_Handle->mParameters, file, line);
    }
}
#else
void SQLiteStatement::ValidateParam(int32_t idx) const
{
    ValidateCreated();
    // Is the specified index in range?
    if (!m_Handle->CheckParameter(idx))
    {
        SqThrowF(fmt::runtime("Parameter index is out of range: {}:{}"), idx, m_Handle->mParameters);
    }
}
#endif // _DEBUG

// ------------------------------------------------------------------------------------------------
#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC)
void SQLiteStatement::ValidateRow(const char * file, int32_t line) const
{
    ValidateCreated(file, line);
    // Do we have any rows available?
    if (!m_Handle->mGood)
    {
        SqThrowF(SQMOD_RTFMT("No row available =>[{}:{}]"), file, line);
    }
}
#else
void SQLiteStatement::ValidateRow() const
{
    ValidateCreated();
    // Do we have any rows available?
    if (!m_Handle->mGood)
    {
        SqThrowF(fmt::runtime("No row available"));
    }
}
#endif // _DEBUG

// ------------------------------------------------------------------------------------------------
SQLiteStatement::SQLiteStatement(const SQLiteConnection & connection, StackStrF & query)
    : m_Handle(new SQLiteStmtHnd(connection.GetHandle()))
{
    SQMOD_GET_VALID(*this)->Create(query.mPtr, query.mLen);
}

// ------------------------------------------------------------------------------------------------
Object SQLiteStatement::GetConnection() const
{
    return Object(new SQLiteConnection(SQMOD_GET_VALID(*this)->mConn));
}

// ------------------------------------------------------------------------------------------------
SQLiteStatement & SQLiteStatement::Reset()
{
    SQMOD_VALIDATE_CREATED(*this);
    // Specify that we don't have a row available and we haven't finished stepping
    m_Handle->mGood = false;
    m_Handle->mDone = false;
    // Attempt to reset the statement to it's initial state
    m_Handle->mStatus = sqlite3_reset(m_Handle->mPtr);
    // Validate the result
    if (m_Handle->mStatus != SQLITE_OK)
    {
        STHROWF("Unable to reset statement [{}]", m_Handle->ErrStr());
    }
    // Allow further chaining of operations
    return *this;
}

// ------------------------------------------------------------------------------------------------
SQLiteStatement & SQLiteStatement::Clear()
{
    SQMOD_VALIDATE_CREATED(*this);
    // Specify that we don't have a row available and we haven't finished stepping
    m_Handle->mGood = false;
    m_Handle->mDone = false;
    // Attempt to clear the statement
    m_Handle->mStatus = sqlite3_clear_bindings(m_Handle->mPtr);
    // Validate the result
    if (m_Handle->mStatus != SQLITE_OK)
    {
        STHROWF("Unable to clear statement [{}]", m_Handle->ErrStr());
    }
    // Allow further chaining of operations
    return *this;
}

// ------------------------------------------------------------------------------------------------
int32_t SQLiteStatement::Exec()
{
    SQMOD_VALIDATE_CREATED(*this);
    // Did we reset first?
    if (m_Handle->mDone)
    {
        STHROWF("Executed without resetting first");
    }
    // Attempt to step the statement
    m_Handle->mStatus = sqlite3_step(m_Handle->mPtr);
    // Have we finished stepping?
    if (m_Handle->mStatus == SQLITE_DONE)
    {
        // Specify that we don't have row available and we finished stepping
        m_Handle->mGood = false;
        m_Handle->mDone = true;
        // Return the changes made by this statement
        return sqlite3_changes(m_Handle->mConn->mPtr);
    }
    // Specify that we don't have any row and we haven't finished stepping
    m_Handle->mGood = false;
    m_Handle->mDone = false;
    // Inspect the result
    switch (m_Handle->mStatus)
    {
        // We don't expect any rows to be returned in this case!
        case SQLITE_ROW:    STHROWF("Results were found");
        // fall through
        case SQLITE_BUSY:   STHROWF("Database was busy");
        // fall through
        case SQLITE_ERROR:  STHROWF("Runtime error occurred");
        // fall through
        case SQLITE_MISUSE: STHROWF("Statement misuse");
        // fall through
        default:            STHROWF("Unknown failure [{}]", m_Handle->ErrStr());
    }
    // Operation failed (shouldn't reach this point!)
    return -1;
}

// ------------------------------------------------------------------------------------------------
bool SQLiteStatement::Step()
{
    SQMOD_VALIDATE_CREATED(*this);
    // Did we reset first?
    if (m_Handle->mDone)
    {
        STHROWF("Stepped without resetting first");
    }
    // Attempt to step the statement
    m_Handle->mStatus = sqlite3_step(m_Handle->mPtr);
    // Do we have a row available?
    if (m_Handle->mStatus == SQLITE_ROW)
    {
        // Specify that we have a row available
        return (m_Handle->mGood = true);
    }
    // Have we finished stepping?
    else if (m_Handle->mStatus == SQLITE_DONE)
    {
        // Specify that we finished stepping
        m_Handle->mDone = true;
        // Specify that we don't have a row available
        return (m_Handle->mGood = false);
    }
    // Specify that we don't have any row and we haven't finished stepping
    m_Handle->mGood = false;
    m_Handle->mDone = false;
    // Inspect the result
    switch (m_Handle->mStatus)
    {
        case SQLITE_BUSY:   STHROWF("Database was busy");
        // fall through
        case SQLITE_ERROR:  STHROWF("Runtime error occurred");
        // fall through
        case SQLITE_MISUSE: STHROWF("Statement misuse");
        // fall through
        default:            STHROWF("Unknown failure [{}]", m_Handle->ErrStr());
    }
    // Operation failed (shouldn't reach this point!)
    return false;
}

// ------------------------------------------------------------------------------------------------
SQLiteStatement & SQLiteStatement::SetArray(int32_t idx, const Array & arr)
{
    // Obtain a script iterator
    Array::iterator itr;
    // Create a parameter instance to bind the values
    SQLiteParameter param(m_Handle);
    // Process each element until _next returns null
    while (idx <= m_Handle->mParameters && arr.Next(itr))
    {
        // Update the parameter index
        param.SetIndex(idx++);
        // Bind it to the current index
        param.SetValue(Object(itr.getValue()));
    }
    // Allow further chaining of operations
    return *this;
}

// ------------------------------------------------------------------------------------------------
SQLiteStatement & SQLiteStatement::SetTable(const Table & tbl)
{
    // Is there anything to bind?
    if (tbl.GetSize() <= 0)
    {
        return *this; // Nothing to bind!
    }
    // Obtain a table iterator
    Table::iterator itr;
    // Create a parameter instance to bind the values
    SQLiteParameter param(m_Handle);
    // Process each element until _next returns null
    while (tbl.Next(itr))
    {
        // Update the parameter index
        param.SetIndex(itr.getName());
        // Bind it to the current index
        param.SetValue(Object(itr.getValue()));
    }
    // Allow further chaining of operations
    return *this;
}

// ------------------------------------------------------------------------------------------------
Array SQLiteStatement::GetArray(int32_t min, int32_t max) const
{
    SQMOD_VALIDATE_ROW(*this);
    // Is the specified minimum index valid?
    if (min < 0)
    {
        STHROWF("Minimum is bellow zero: {}", min);
    }
    // Is the minimum actually the minimum?
    else if (min > max)
    {
        STHROWF("Minimum is higher than maximum: {} > {}", min, max);
    }
    // Is the minimum in range?
    else if (!m_Handle->CheckColumn(min))
    {
        STHROWF("Minimum is out of range: {}:{}", min, m_Handle->mColumns);
    }
    // Is the maximum in range?
    else if (!m_Handle->CheckColumn(max))
    {
        STHROWF("Maximum is out of range: {}:{}", max, m_Handle->mColumns);
    }
    // Allocate an array large enough to hold the values from selected columns
    Array arr(SqVM(), max-min);
    // Create a column instance to retrieve the values
    SQLiteColumn column(m_Handle);
    // Array element counter
    int32_t elem = 0;
    // Process the range of selected columns
    while (min <= max)
    {
        // Update the column index
        column.SetIndex(min++);
        // Retrieve the column value and bind it to the array
        arr.SetValue(elem++, column.GetValue());
    }
    // Return the resulted array
    return arr;
}

// ------------------------------------------------------------------------------------------------
Table SQLiteStatement::GetTable(int32_t min, int32_t max) const
{
    SQMOD_VALIDATE_ROW(*this);
    // Is the specified minimum index valid?
    if (min < 0)
    {
        STHROWF("Minimum is bellow zero: {}", min);
    }
    // Is the minimum actually the minimum?
    else if (min > max)
    {
        STHROWF("Minimum is higher than maximum: {} > {}", min, max);
    }
    // Is the minimum in range>
    else if (!m_Handle->CheckColumn(min))
    {
        STHROWF("Minimum is out of range: {}:{}", min, m_Handle->mColumns);
    }
    // Is the maximum in range?
    else if (!m_Handle->CheckColumn(max))
    {
        STHROWF("Maximum is out of range: {}:{}", max, m_Handle->mColumns);
    }
    // Create a table to hold the selected column values
    Table tbl(SqVM());
    // Create a column instance to retrieve the values
    SQLiteColumn column(m_Handle);
    // Process the range of selected columns
    while (min <= max)
    {
        // Attempt to obtain the column name
        const SQChar * name = sqlite3_column_name(m_Handle->mPtr, min);
        // Validate the obtained name
        if (!name)
        {
            STHROWF("Unable to retrieve name of column ({})", min);
        }
        // Update the column index
        column.SetIndex(min++);
        // Retrieve the column value and bind it to the table
        tbl.SetValue(name, column.GetValue());
    }
    // Return the resulted table
    return tbl;
}

// ------------------------------------------------------------------------------------------------
SQLiteTransaction::SQLiteTransaction(const SQLiteConnection & db)
    : SQLiteTransaction(db.GetHandle())
{
    /* ... */
}

// ------------------------------------------------------------------------------------------------
SQLiteTransaction::SQLiteTransaction(ConnRef  db)
    : m_Handle(std::move(db)), m_Committed(false)
{
    // Was the specified database connection valid?
    if (!m_Handle)
    {
        STHROWF("Invalid connection handle");
    }
    // Attempt to begin transaction
    m_Handle->mStatus = sqlite3_exec(m_Handle->mPtr, "BEGIN", nullptr, nullptr, nullptr);
    // Validate the result
    if (m_Handle->mStatus != SQLITE_OK)
    {
        STHROWF("Unable to begin transaction [{}]", m_Handle->ErrMsg());
    }
}

// ------------------------------------------------------------------------------------------------
SQLiteTransaction::~SQLiteTransaction()
{
    // Was this transaction successfully committed?
    if (m_Committed)
    {
        return; // We're done here!
    }
    // Attempt to roll back changes because this failed to commit
    m_Handle->mStatus = sqlite3_exec(m_Handle->mPtr, "ROLLBACK", nullptr, nullptr, nullptr);
    // Validate the result
    if (m_Handle->mStatus != SQLITE_OK)
    {
        // We cannot throw exceptions in destructor
        LogErr("Unable to rollback transaction [%s]", m_Handle->ErrMsg());
    }
}

// ------------------------------------------------------------------------------------------------
bool SQLiteTransaction::Commit()
{
    // We shouldn't even be here if there wasn't a valid connection but let's be sure
    if (!m_Handle)
    {
        STHROWF("Invalid database connection");
    }
    // Was this transaction already committed?
    else if (m_Committed)
    {
        STHROWF("Transaction was already committed");
    }
    // Attempt to commit the change during this transaction
    m_Handle->mStatus = sqlite3_exec(m_Handle->mPtr, "COMMIT", nullptr, nullptr, nullptr);
    // Validate the result
    if (m_Handle->mStatus != SQLITE_OK)
    {
        STHROWF("Unable to commit transaction [{}]", m_Handle->ErrMsg());
    }
    else
    {
        m_Committed = true; // Everything was committed successfully
    }
    // Return the result
    return m_Committed;
}

// ================================================================================================
void Register_SQLite(HSQUIRRELVM vm)
{
    Enumeration e(vm);
    EnumElements(g_MainEnum).Bind(e);
    ConstTable(vm).Enum(_SC("SQLiteOpt"), e);

    Table sqlns(vm);

	sqlns.Func(_SC("IsQueryEmpty"), &IsQueryEmpty)
	    .Func(_SC("GetErrStr"), &GetErrStr)
	    .Func(_SC("SetSoftHeapLimit"), &SetSoftHeapLimit)
	    .Func(_SC("ReleaseMemory"), &ReleaseMemory)
	    .Func(_SC("MemoryUsage"), &GetMemoryUsage)
	    .Func(_SC("MemoryHighwaterMark"), &GetMemoryHighwaterMark)
	    .Func(_SC("ArrayToQueryColumns"), &ArrayToQueryColumns)
	    .Func(_SC("TableToQueryColumns"), &TableToQueryColumns)
	    .FmtFunc(_SC("EscapeString"), &EscapeString)
	    .FmtFunc(_SC("EscapeStringEx"), &EscapeStringEx)
	    .FmtFunc(_SC("Escape"), &EscapeString)
	    .FmtFunc(_SC("EscapeEx"), &EscapeStringEx);

    sqlns.Bind(_SC("Connection"),
        Class< SQLiteConnection >(sqlns.GetVM(), SQLiteConnectionTypename::Str)
        // Constructors
        .Ctor()
        .Ctor< StackStrF & >()
        .Ctor< StackStrF &, int32_t >()
        .Ctor< StackStrF &, int32_t, StackStrF & >()
        // Meta-methods
        .SquirrelFunc(_SC("_typename"), &SQLiteConnectionTypename::Fn)
        .Func(_SC("_tostring"), &SQLiteConnection::ToString)
        // Properties
        .Prop(_SC("IsValid"), &SQLiteConnection::IsValid)
        .Prop(_SC("Connected"), &SQLiteConnection::IsConnected)
        .Prop(_SC("References"), &SQLiteConnection::GetRefCount)
        .Prop(_SC("Status"), &SQLiteConnection::GetStatus)
        .Prop(_SC("Flags"), &SQLiteConnection::GetFlags)
        .Prop(_SC("Name"), &SQLiteConnection::GetName)
        .Prop(_SC("VFS"), &SQLiteConnection::GetVFS)
        .Prop(_SC("ErrCode"), &SQLiteConnection::GetErrorCode)
        .Prop(_SC("ExErrCode"), &SQLiteConnection::GetExtendedErrorCode)
        .Prop(_SC("ExtendedErrCode"), &SQLiteConnection::GetExtendedErrorCode)
        .Prop(_SC("ErrStr"), &SQLiteConnection::GetErrStr)
        .Prop(_SC("ErrMsg"), &SQLiteConnection::GetErrMsg)
        .Prop(_SC("ReadOnly"), &SQLiteConnection::IsReadOnly)
        .Prop(_SC("Autocommit"), &SQLiteConnection::GetAutoCommit)
        .Prop(_SC("LastInsertRowId"), &SQLiteConnection::GetLastInsertRowID)
        .Prop(_SC("Changes"), &SQLiteConnection::GetChanges)
        .Prop(_SC("TotalChanges"), &SQLiteConnection::GetTotalChanges)
        .Prop(_SC("Trace"), &SQLiteConnection::GetTracing, &SQLiteConnection::SetTracing)
        .Prop(_SC("Profile"), &SQLiteConnection::GetProfiling, &SQLiteConnection::SetProfiling)
        .Prop(_SC("QueueSize"), &SQLiteConnection::QueueSize)
        // Member Methods
        .Func(_SC("Release"), &SQLiteConnection::Release)
        .FmtFunc(_SC("Exec"), &SQLiteConnection::Exec)
        .FmtFunc(_SC("Queue"), &SQLiteConnection::Queue)
        .FmtFunc(_SC("Query"), &SQLiteConnection::Query)
        .FmtFunc(_SC("TableExists"), &SQLiteConnection::TableExists)
        .Func(_SC("InterruptOperation"), &SQLiteConnection::InterruptOperation)
        .Func(_SC("SetBusyTimeout"), &SQLiteConnection::SetBusyTimeout)
        .Func(_SC("ReleaseMemory"), &SQLiteConnection::ReleaseMemory)
        .Func(_SC("ReserveQueue"), &SQLiteConnection::ReserveQueue)
        .Func(_SC("CompactQueue"), &SQLiteConnection::CompactQueue)
        .Func(_SC("ClearQueue"), &SQLiteConnection::ClearQueue)
        .Func(_SC("PopQueue"), &SQLiteConnection::PopQueue)
        // Member Overloads
        .Overload< void (SQLiteConnection::*)(StackStrF &) >(_SC("Open"), &SQLiteConnection::Open)
        .Overload< void (SQLiteConnection::*)(StackStrF &, int32_t) >(_SC("Open"), &SQLiteConnection::Open)
        .Overload< void (SQLiteConnection::*)(StackStrF &, int32_t, StackStrF &) >(_SC("Open"), &SQLiteConnection::Open)
        .Overload< int32_t (SQLiteConnection::*)(int32_t) >(_SC("GetInfo"), &SQLiteConnection::GetInfo)
        .Overload< int32_t (SQLiteConnection::*)(int32_t, bool) >(_SC("GetInfo"), &SQLiteConnection::GetInfo)
        .Overload< int32_t (SQLiteConnection::*)(int32_t, bool, bool) >(_SC("GetInfo"), &SQLiteConnection::GetInfo)
        .Overload< int32_t (SQLiteConnection::*)(void) >(_SC("Flush"), &SQLiteConnection::Flush)
        .Overload< int32_t (SQLiteConnection::*)(SQInteger) >(_SC("Flush"), &SQLiteConnection::Flush)
        .Overload< int32_t (SQLiteConnection::*)(Object &, Function &) >(_SC("Flush"), &SQLiteConnection::Flush)
        .Overload< int32_t (SQLiteConnection::*)(SQInteger, Object &, Function &) >(_SC("Flush"), &SQLiteConnection::Flush)
    );

    sqlns.Bind(_SC("Parameter"),
        Class< SQLiteParameter >(sqlns.GetVM(), SQLiteParameterTypename::Str)
        // Constructors
        .Ctor()
        .Ctor< const SQLiteParameter & >()
        // Meta-methods
        .SquirrelFunc(_SC("_typename"), &SQLiteParameterTypename::Fn)
        .Func(_SC("_tostring"), &SQLiteParameter::ToString)
        // Properties
        .Prop(_SC("IsValid"), &SQLiteParameter::IsValid)
        .Prop(_SC("References"), &SQLiteParameter::GetRefCount)
        .Prop(_SC("Index"), &SQLiteParameter::GetIndex)
        .Prop(_SC("Statement"), &SQLiteParameter::GetStatement)
        .Prop(_SC("Connection"), &SQLiteParameter::GetConnection)
        .Prop(_SC("References"), &SQLiteParameter::GetRefCount)
        .Prop(_SC("Name"), &SQLiteParameter::GetName)
        // Member Methods
        .Func(_SC("Release"), &SQLiteParameter::Release)
        .Func(_SC("SetValue"), &SQLiteParameter::SetValue)
        .Func(_SC("SetBool"), &SQLiteParameter::SetBool)
        .Func(_SC("SetChar"), &SQLiteParameter::SetChar)
        .Func(_SC("SetInteger"), &SQLiteParameter::SetInteger)
        .Func(_SC("SetInt8"), &SQLiteParameter::SetInt8)
        .Func(_SC("SetUint8"), &SQLiteParameter::SetUint8)
        .Func(_SC("SetInt16"), &SQLiteParameter::SetInt16)
        .Func(_SC("SetUint16"), &SQLiteParameter::SetUint16)
        .Func(_SC("SetInt32"), &SQLiteParameter::SetInt32)
        .Func(_SC("SetUint32"), &SQLiteParameter::SetUint32)
        .Func(_SC("SetInt64"), &SQLiteParameter::SetInt64)
        .Func(_SC("SetUint64"), &SQLiteParameter::SetUint64)
        .Func(_SC("SetFloat"), &SQLiteParameter::SetFloat)
        .Func(_SC("SetFloat32"), &SQLiteParameter::SetFloat32)
        .Func(_SC("SetFloat64"), &SQLiteParameter::SetFloat64)
        .FmtFunc(_SC("SetString"), &SQLiteParameter::SetString)
        .Func(_SC("SetZeroBlob"), &SQLiteParameter::SetZeroBlob)
        .Func(_SC("SetBlob"), &SQLiteParameter::SetBlob)
        .Func(_SC("SetData"), &SQLiteParameter::SetData)
        .Func(_SC("SetDataEx"), &SQLiteParameter::SetDataEx)
        .Func(_SC("SetDate"), &SQLiteParameter::SetDate)
        .Func(_SC("SetDateEx"), &SQLiteParameter::SetDateEx)
        .Func(_SC("SetTime"), &SQLiteParameter::SetTime)
        .Func(_SC("SetTimeEx"), &SQLiteParameter::SetTimeEx)
        .Func(_SC("SetDatetime"), &SQLiteParameter::SetDatetime)
        .Func(_SC("SetDatetimeEx"), &SQLiteParameter::SetDatetimeEx)
        .Func(_SC("SetNow"), &SQLiteParameter::SetNow)
        .Func(_SC("SetNull"), &SQLiteParameter::SetNull)
    );

    sqlns.Bind(_SC("Column"),
        Class< SQLiteColumn >(sqlns.GetVM(), SQLiteColumnTypename::Str)
        // Constructors
        .Ctor()
        .Ctor< const SQLiteColumn & >()
        // Meta-methods
        .SquirrelFunc(_SC("_typename"), &SQLiteColumnTypename::Fn)
        .Func(_SC("_tostring"), &SQLiteColumn::ToString)
        // Properties
        .Prop(_SC("IsValid"), &SQLiteColumn::IsValid)
        .Prop(_SC("References"), &SQLiteColumn::GetRefCount)
        .Prop(_SC("Index"), &SQLiteColumn::GetIndex)
        .Prop(_SC("Statement"), &SQLiteColumn::GetStatement)
        .Prop(_SC("Connection"), &SQLiteColumn::GetConnection)
        .Prop(_SC("IsNull"), &SQLiteColumn::IsNull)
        .Prop(_SC("Name"), &SQLiteColumn::GetName)
        .Prop(_SC("OriginName"), &SQLiteColumn::GetOriginName)
        .Prop(_SC("Type"), &SQLiteColumn::GetType)
        .Prop(_SC("Bytes"), &SQLiteColumn::GetBytes)
        .Prop(_SC("Value"), &SQLiteColumn::GetValue)
        .Prop(_SC("Number"), &SQLiteColumn::GetNumber)
        .Prop(_SC("Integer"), &SQLiteColumn::GetInteger)
        .Prop(_SC("Float"), &SQLiteColumn::GetFloat)
        .Prop(_SC("Long"), &SQLiteColumn::GetLong)
        .Prop(_SC("String"), &SQLiteColumn::GetString)
        .Prop(_SC("Boolean"), &SQLiteColumn::GetBoolean)
        .Prop(_SC("Char"), &SQLiteColumn::GetChar)
        .Prop(_SC("Buffer"), &SQLiteColumn::GetBuffer)
        .Prop(_SC("Blob"), &SQLiteColumn::GetBlob)
        // Member Methods
        .Func(_SC("Release"), &SQLiteColumn::Release)
    );

    sqlns.Bind(_SC("Statement"),
        Class< SQLiteStatement >(sqlns.GetVM(), SQLiteStatementTypename::Str)
        // Constructors
        .Ctor()
        .Ctor< const SQLiteStatement & >()
        .Ctor< const SQLiteConnection &, StackStrF & >()
        // Meta-methods
        .SquirrelFunc(_SC("_typename"), &SQLiteStatementTypename::Fn)
        .Func(_SC("_tostring"), &SQLiteStatement::ToString)
        // Properties
        .Prop(_SC("IsValid"), &SQLiteStatement::IsValid)
        .Prop(_SC("Prepared"), &SQLiteStatement::IsPrepared)
        .Prop(_SC("References"), &SQLiteStatement::GetReferences)
        .Prop(_SC("Connection"), &SQLiteStatement::GetConnection)
        .Prop(_SC("Status"), &SQLiteStatement::GetStatus)
        .Prop(_SC("ErrCode"), &SQLiteStatement::GetErrorCode)
        .Prop(_SC("ExErrCode"), &SQLiteStatement::GetExtendedErrorCode)
        .Prop(_SC("ExtendedErrCode"), &SQLiteStatement::GetExtendedErrorCode)
        .Prop(_SC("ErrStr"), &SQLiteStatement::GetErrStr)
        .Prop(_SC("ErrMsg"), &SQLiteStatement::GetErrMsg)
        .Prop(_SC("Columns"), &SQLiteStatement::GetColumns)
        .Prop(_SC("Parameters"), &SQLiteStatement::GetParameters)
        .Prop(_SC("Query"), &SQLiteStatement::GetQuery)
        .Prop(_SC("Good"), &SQLiteStatement::GetGood)
        .Prop(_SC("Done"), &SQLiteStatement::GetDone)
        .Prop(_SC("DataCount"), &SQLiteStatement::GetDataCount)
        // Member Methods
        .Func(_SC("Release"), &SQLiteStatement::Release)
        .Func(_SC("CheckParameter"), &SQLiteStatement::CheckParameter)
        .FmtFunc(_SC("GetParameterIndex"), &SQLiteStatement::GetParameterIndex)
        .Func(_SC("GetParameterName"), &SQLiteStatement::GetParameterName)
        .Func(_SC("CheckColumn"), &SQLiteStatement::CheckColumn)
        .Func(_SC("IsColumnNull"), &SQLiteStatement::IsColumnNull)
        .FmtFunc(_SC("ColumnIndex"), &SQLiteStatement::GetColumnIndex)
        .Func(_SC("ColumnName"), &SQLiteStatement::GetColumnName)
        .Func(_SC("ColumnOriginName"), &SQLiteStatement::GetColumnOriginName)
        .Func(_SC("ColumnType"), &SQLiteStatement::GetColumnType)
        .Func(_SC("ColumnBytes"), &SQLiteStatement::GetColumnBytes)
        .Func(_SC("Reset"), &SQLiteStatement::Reset)
        .Func(_SC("Clear"), &SQLiteStatement::Clear)
        .Func(_SC("Exec"), &SQLiteStatement::Exec)
        .Func(_SC("Step"), &SQLiteStatement::Step)
        .Func(_SC("Param"), &SQLiteStatement::GetParameter)
        .Func(_SC("Parameter"), &SQLiteStatement::GetParameter)
        .Func(_SC("SetValue"), &SQLiteStatement::SetValue)
        .Func(_SC("SetBool"), &SQLiteStatement::SetBool)
        .Func(_SC("SetChar"), &SQLiteStatement::SetChar)
        .Func(_SC("SetInteger"), &SQLiteStatement::SetInteger)
        .Func(_SC("SetInt8"), &SQLiteStatement::SetInt8)
        .Func(_SC("SetUint8"), &SQLiteStatement::SetUint8)
        .Func(_SC("SetInt16"), &SQLiteStatement::SetInt16)
        .Func(_SC("SetUint16"), &SQLiteStatement::SetUint16)
        .Func(_SC("SetInt32"), &SQLiteStatement::SetInt32)
        .Func(_SC("SetUint32"), &SQLiteStatement::SetUint32)
        .Func(_SC("SetInt64"), &SQLiteStatement::SetInt64)
        .Func(_SC("SetUint64"), &SQLiteStatement::SetUint64)
        .Func(_SC("SetFloat"), &SQLiteStatement::SetFloat)
        .Func(_SC("SetFloat32"), &SQLiteStatement::SetFloat32)
        .Func(_SC("SetFloat64"), &SQLiteStatement::SetFloat64)
        .FmtFunc(_SC("SetString"), &SQLiteStatement::SetString)
        .Func(_SC("SetZeroBlob"), &SQLiteStatement::SetZeroBlob)
        .Func(_SC("SetBlob"), &SQLiteStatement::SetBlob)
        .Func(_SC("SetData"), &SQLiteStatement::SetData)
        .Func(_SC("SetDate"), &SQLiteStatement::SetDate)
        .Func(_SC("SetDateEx"), &SQLiteStatement::SetDateEx)
        .Func(_SC("SetTime"), &SQLiteStatement::SetTime)
        .Func(_SC("SetTimeEx"), &SQLiteStatement::SetTimeEx)
        .Func(_SC("SetDatetime"), &SQLiteStatement::SetDatetime)
        .Func(_SC("SetDatetimeEx"), &SQLiteStatement::SetDatetimeEx)
        .Func(_SC("SetNow"), &SQLiteStatement::SetNow)
        .Func(_SC("SetNull"), &SQLiteStatement::SetNull)
        .Func(_SC("SetArray"), &SQLiteStatement::SetArray)
        .Func(_SC("SetTable"), &SQLiteStatement::SetTable)
        .Func(_SC("Field"), &SQLiteStatement::GetColumn)
        .Func(_SC("Column"), &SQLiteStatement::GetColumn)
        .Func(_SC("GetValue"), &SQLiteStatement::GetValue)
        .Func(_SC("GetNumber"), &SQLiteStatement::GetNumber)
        .Func(_SC("GetInteger"), &SQLiteStatement::GetInteger)
        .Func(_SC("GetFloat"), &SQLiteStatement::GetFloat)
        .Func(_SC("GetLong"), &SQLiteStatement::GetLong)
        .Func(_SC("GetString"), &SQLiteStatement::GetString)
        .Func(_SC("GetBoolean"), &SQLiteStatement::GetBoolean)
        .Func(_SC("GetChar"), &SQLiteStatement::GetChar)
        .Func(_SC("GetBuffer"), &SQLiteStatement::GetBuffer)
        .Func(_SC("GetBlob"), &SQLiteStatement::GetBlob)
        // Member overloads
        .Overload< Array (SQLiteStatement::*)(void) const >(_SC("GetArray"), &SQLiteStatement::GetArray)
        .Overload< Array (SQLiteStatement::*)(int32_t) const >(_SC("GetArray"), &SQLiteStatement::GetArray)
        .Overload< Array (SQLiteStatement::*)(int32_t, int32_t) const >(_SC("GetArray"), &SQLiteStatement::GetArray)
        .Overload< Table (SQLiteStatement::*)(void) const >(_SC("GetTable"), &SQLiteStatement::GetTable)
        .Overload< Table (SQLiteStatement::*)(int32_t) const >(_SC("GetTable"), &SQLiteStatement::GetTable)
        .Overload< Table (SQLiteStatement::*)(int32_t, int32_t) const >(_SC("GetTable"), &SQLiteStatement::GetTable)
    );

    sqlns.Bind(_SC("Transaction"),
        Class< SQLiteTransaction, NoCopy< SQLiteTransaction > >(sqlns.GetVM(), SQLiteTransactionTypename::Str)
        // Constructors
        .Ctor< const SQLiteConnection & >()
        // Meta-methods
        .SquirrelFunc(_SC("_typename"), &SQLiteTransactionTypename::Fn)
        .Func(_SC("_tostring"), &SQLiteTransaction::ToString)
        // Properties
        .Prop(_SC("IsValid"), &SQLiteTransaction::IsValid)
        .Prop(_SC("Committed"), &SQLiteTransaction::Commited)
        // Member Methods
        .Func(_SC("Commit"), &SQLiteTransaction::Commit)
    );

    RootTable(vm).Bind(_SC("SQLite"), sqlns);
}

} // Namespace:: SqMod
