diff --git a/module/CMakeLists.txt b/module/CMakeLists.txt index d2dc4a4a..8b95de67 100644 --- a/module/CMakeLists.txt +++ b/module/CMakeLists.txt @@ -46,14 +46,6 @@ add_library(SqModule MODULE Library/Numeric/Math.cpp Library/Numeric/Math.hpp Library/Numeric/Random.cpp Library/Numeric/Random.hpp Library/SQLite.cpp Library/SQLite.hpp - Library/SQLite/Constants.cpp - Library/SQLite/Column.cpp Library/SQLite/Column.hpp - Library/SQLite/Common.cpp Library/SQLite/Common.hpp - Library/SQLite/Connection.cpp Library/SQLite/Connection.hpp - Library/SQLite/Handle.cpp Library/SQLite/Handle.hpp - Library/SQLite/Parameter.cpp Library/SQLite/Parameter.hpp - Library/SQLite/Statement.cpp Library/SQLite/Statement.hpp - Library/SQLite/Transaction.cpp Library/SQLite/Transaction.hpp Library/String.cpp Library/String.hpp Library/System.cpp Library/System.hpp Library/System/Dir.cpp Library/System/Dir.hpp diff --git a/module/Library/SQLite.cpp b/module/Library/SQLite.cpp index c03de0e1..de899a98 100644 --- a/module/Library/SQLite.cpp +++ b/module/Library/SQLite.cpp @@ -1,30 +1,3136 @@ // ------------------------------------------------------------------------------------------------ #include "Library/SQLite.hpp" +// ------------------------------------------------------------------------------------------------ +#include + +// ------------------------------------------------------------------------------------------------ +#include + // ------------------------------------------------------------------------------------------------ namespace SqMod { // ------------------------------------------------------------------------------------------------ -extern void Register_Constants(Table & sqlns); -extern void Register_Common(Table & sqlns); -extern void Register_Connection(Table & sqlns); -extern void Register_Statement(Table & sqlns); -extern void Register_Parameter(Table & sqlns); -extern void Register_Column(Table & sqlns); -extern void Register_Transaction(Table & sqlns); +// Error message when failed to bind value to parameter index. +#define SQMOD_BINDFAILED "Unable to bind (%s) parameter (%d) because [%s]" + +// ------------------------------------------------------------------------------------------------ +SQMODE_DECL_TYPENAME(SQLiteConnectionTypename, _SC("SQLiteConnection")) +SQMODE_DECL_TYPENAME(SQLiteParameterTypename, _SC("SQLiteParameter")) +SQMODE_DECL_TYPENAME(SQLiteColumnTypename, _SC("SQLiteColumn")) +SQMODE_DECL_TYPENAME(SQLiteStatementTypename, _SC("SQLiteStatement")) +SQMODE_DECL_TYPENAME(SQLiteTransactionTypename, _SC("SQLiteTransaction")) + +/* ------------------------------------------------------------------------------------------------ + * Helper class that represents an integral enumeration value. Used to reduce compilation times. +*/ +struct SEnumElement +{ + CSStr Name; + Int32 Value; +}; + +// ------------------------------------------------------------------------------------------------ +static const SEnumElement 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(CSStr 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 Connection(conn)); +} + +// ------------------------------------------------------------------------------------------------ +Object GetStatementObj(const StmtRef & stmt) +{ + return Object(new Statement(stmt)); +} + +// ------------------------------------------------------------------------------------------------ +bool IsQueryEmpty(CSStr str) +{ + // Is the pointer valid? + if (!str || *str == '\0') + { + return true; + } + // Currently processed character + SQChar c = 0; + // See if the query contains any alpha numeric characters + while ((c = *str) != 0) + { + if (std::isalnum(c) != 0) + { + return false; + } + ++str; + } + // At this point we consider the query empty + return true; +} + +// ------------------------------------------------------------------------------------------------ +CSStr GetErrStr(Int32 status) +{ + return sqlite3_errstr(status); +} + +// ------------------------------------------------------------------------------------------------ +void SetSoftHeapLimit(Int32 limit) +{ + sqlite3_soft_heap_limit(limit); +} + +// ------------------------------------------------------------------------------------------------ +Int32 ReleaseMemory(Int32 bytes) +{ + return sqlite3_release_memory(bytes); +} + +// ------------------------------------------------------------------------------------------------ +Object GetMemoryUsage() +{ + // Obtain the initial stack size + const StackGuard sg; + // Push a long integer instance with the requested value on the stack + return Object(new SLongInt(sqlite3_memory_used())); +} + +// ------------------------------------------------------------------------------------------------ +Object GetMemoryHighwaterMark(bool reset) +{ + // Obtain the initial stack size + const StackGuard sg; + // Push a long integer instance with the requested value on the stack + return Object(new SLongInt(sqlite3_memory_highwater(reset))); +} + +// ------------------------------------------------------------------------------------------------ +CSStr EscapeString(StackStrF & str) +{ + // Is there even a string to escape? + if (str.mLen <= 0) + { + return _SC(""); // Default to empty string + } + // Attempt to escape the specified string + sqlite3_snprintf(GetTempBuffSize(), GetTempBuff(), "%q", str.mPtr); + // Return the resulted string + return GetTempBuff(); +} + +// ------------------------------------------------------------------------------------------------ +CCStr EscapeStringEx(SQChar spec, StackStrF & str) +{ + // Utility that allows changing the format specifier temporarily + static SQChar fs[] = _SC("%q"); + // 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 _SC(""); // Default to empty string + } + // Apply the format specifier + fs[1] = spec; + // Attempt to escape the specified string + sqlite3_snprintf(GetTempBuffSize(), GetTempBuff(), fs, str.mPtr); + // Restore the format specifier + fs[1] = 'q'; + // Return the resulted string + return GetTempBuff(); +} + +// ------------------------------------------------------------------------------------------------ +CCStr ArrayToQueryColumns(Array & arr) +{ + // Do we even have any elements to process? + if (arr.Length() <= 0) + { + return _SC(""); // Default to empty string + } + // Allocate a vector with the required amount of column names + std::vector< String > values(arr.Length()); + // Attempt to extract the array elements as strings + arr.GetArray< String >(&values[0], values.size()); + // Used to know the position of the next column name + Uint32 offset = 0; + // Obtain the start of the array + auto itr = values.begin(); + // Process all elements within range + for (; itr != values.end() && offset < GetTempBuffSize(); ++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 >(GetTempBuffSize() - offset), GetTempBuff() + 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) + { + GetTempBuff()[offset-2] = '\0'; + } + else + { + GetTempBuff()[0] = '\0'; + } + // Return the resulted string + return GetTempBuff(); +} + +// ------------------------------------------------------------------------------------------------ +CCStr TableToQueryColumns(Table & tbl) +{ + // Used to know the position of the next column name + Uint32 offset = 0; + // Used to obtain the column name temporarily + String name; + // Obtain the start of the table + Table::iterator itr; + // Process all elements within range + while (tbl.Next(itr)) + { + // Use the element key as the column name + name.assign(itr.getName()); + // Is the name valid? + if (name.empty()) + { + STHROWF("Invalid or empty column name"); + } + // Attempt to append the column name to the buffer + sqlite3_snprintf(static_cast< int >(GetTempBuffSize() - offset), GetTempBuff() + offset, "[%q], ", name.c_str()); + // Add the column name size to the offset + offset += name.size(); + // Also include the comma and space in the offset + offset += 2; + } + // Trim the last coma and space + if (offset >= 2) + { + GetTempBuff()[offset-2] = '\0'; + } + else + { + GetTempBuff()[0] = '\0'; + } + // Return the resulted string + return GetTempBuff(); +} + +// ------------------------------------------------------------------------------------------------ +ConnHnd::ConnHnd() + : mPtr(nullptr) + , mStatus(SQLITE_OK) + , mQueue() + , mFlags(0) + , mName() + , mVFS() + , mMemory(false) + , mTrace(false) + , mProfile(false) +{ + /* ... */ +} + +// ------------------------------------------------------------------------------------------------ +ConnHnd::~ConnHnd() +{ + // Is there anything to close? + if (mPtr != nullptr) + { + // Flush remaining queries in the queue and ignore the result + Flush(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 ConnHnd::Create(CSStr name, Int32 flags, CSStr 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 [%s]", 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 ConnHnd::Flush(Uint32 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 = mQueue.size(); + } + // Generate the function that should be called upon error + Function callback = Function(env.GetVM(), env.GetObject(), func.GetFunc()); + // 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 [%s]", 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 [%s]", sqlite3_errmsg(mPtr)); + } + // The transaction failed somehow but we managed to rollback + else + { + STHROWF("Unable to commit flush transaction [%s]", sqlite3_errmsg(mPtr)); + } + // Operation failed + return -1; +} + +// ------------------------------------------------------------------------------------------------ +StmtHnd::StmtHnd(ConnRef conn) + : mPtr(nullptr) + , mStatus(SQLITE_OK) + , mConn(std::move(conn)) + , mQuery() + , mColumns(0) + , mParameters(0) + , mIndexes() + , mGood(false) + , mDone(false) +{ + /* ... */ +} + +// ------------------------------------------------------------------------------------------------ +StmtHnd::~StmtHnd() +{ + // 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 StmtHnd::Create(CSStr 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, length); + // Attempt to prepare a statement with the specified query string + if ((mStatus = sqlite3_prepare_v2(mConn->mPtr, mQuery.c_str(), ConvTo< Int32 >::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 [%s]", 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 StmtHnd::GetColumnIndex(CSStr name, SQInteger length) +{ + // Validate the handle + if (!mPtr) + { + STHROWF("Invalid SQLite statement"); + } + // Are the names cached? + else if (mIndexes.empty()) + { + for (Int32 i = 0; i < mColumns; ++i) + { + // Get the column name at the current index + auto column_name = static_cast< CSStr >(sqlite3_column_name(mPtr, i)); + // Validate the name + if (!column_name) + { + STHROWF("Unable to retrieve column name for index (%d)", 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 + const Indexes::iterator 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; +} + +// ------------------------------------------------------------------------------------------------ +CCStr StmtHnd::ErrStr() const +{ + return mConn ? sqlite3_errstr(sqlite3_errcode(mConn->mPtr)) : _SC(""); +} + +// ------------------------------------------------------------------------------------------------ +CCStr StmtHnd::ErrMsg() const +{ + return mConn ? sqlite3_errmsg(mConn->mPtr) : _SC(""); +} + +// ------------------------------------------------------------------------------------------------ +Int32 StmtHnd::ErrNo() const +{ + return mConn ? sqlite3_errcode(mConn->mPtr) : SQLITE_NOMEM; +} + +// ------------------------------------------------------------------------------------------------ +Int32 StmtHnd::ExErrNo() const +{ + return mConn ? sqlite3_extended_errcode(mConn->mPtr) : SQLITE_NOMEM; +} + +// ------------------------------------------------------------------------------------------------ +void Connection::TraceOutput(void * /*ptr*/, CCStr sql) +{ + LogInf("SQLite Trace: %s", sql); +} + +// ------------------------------------------------------------------------------------------------ +void Connection::ProfileOutput(void * /*ptr*/, CCStr sql, sqlite3_uint64 time) +{ + LogInf("SQLite profile (time: %llu): %s", time, sql); +} + +// ------------------------------------------------------------------------------------------------ +#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) +void Connection::Validate(CCStr file, Int32 line) const +{ + if (!m_Handle) + { + SqThrowF("Invalid SQLite connection reference =>[%s:%d]", file, line); + } +} +#else +void Connection::Validate() const +{ + if (!m_Handle) + { + SqThrowF("Invalid SQLite connection reference"); + } +} +#endif // _DEBUG + +// ------------------------------------------------------------------------------------------------ +#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) +void Connection::ValidateCreated(CCStr file, Int32 line) const +{ + if (!m_Handle) + { + SqThrowF("Invalid SQLite connection reference =>[%s:%d]", file, line); + } + else if (m_Handle->mPtr == nullptr) + { + SqThrowF("Invalid SQLite connection =>[%s:%d]", file, line); + } +} +#else +void Connection::ValidateCreated() const +{ + if (!m_Handle) + { + SqThrowF("Invalid SQLite connection reference"); + } + else if (m_Handle->mPtr == nullptr) + { + SqThrowF("Invalid SQLite connection"); + } +} +#endif // _DEBUG + +// ------------------------------------------------------------------------------------------------ +#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) +const ConnRef & Connection::GetValid(CCStr file, Int32 line) const +{ + Validate(file, line); + return m_Handle; +} +#else +const ConnRef & Connection::GetValid() const +{ + Validate(); + return m_Handle; +} +#endif // _DEBUG + +// ------------------------------------------------------------------------------------------------ +#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) +const ConnRef & Connection::GetCreated(CCStr file, Int32 line) const +{ + ValidateCreated(file, line); + return m_Handle; +} +#else +const ConnRef & Connection::GetCreated() const +{ + ValidateCreated(); + return m_Handle; +} +#endif // _DEBUG + +// ------------------------------------------------------------------------------------------------ +void Connection::Open(StackStrF & name) +{ + // Should we create a connection handle? + if (!m_Handle) + { + m_Handle = ConnRef(new ConnHnd()); + } + // 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 Connection::Open(StackStrF & name, Int32 flags) +{ + // Should we create a connection handle? + if (!m_Handle) + { + m_Handle = ConnRef(new ConnHnd()); + } + // 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 Connection::Open(StackStrF & name, Int32 flags, StackStrF & vfs) +{ + // Should we create a connection handle? + if (!m_Handle) + { + m_Handle = ConnRef(new ConnHnd()); + } + // 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 Connection::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 [%s]", m_Handle->ErrMsg()); + } + // Return rows affected by this query + return sqlite3_changes(m_Handle->mPtr); +} + +// ------------------------------------------------------------------------------------------------ +Object Connection::Query(StackStrF & str) const +{ + SQMOD_VALIDATE_CREATED(*this); + // Return the requested information + return Object(new Statement(m_Handle, str)); +} + +// ------------------------------------------------------------------------------------------------ +void Connection::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 Connection::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 Connection::TableExists(StackStrF & name) const +{ + StackStrF query("SELECT count(*) FROM [sqlite_master] WHERE [type]='table' AND [name]=?"); + // Prepare a statement to inspect the master table + Statement stmt(SQMOD_GET_CREATED(*this), query); + // Could the statement be created? + if (stmt.IsValid()) + { + // Bind the specified name onto the statement parameter + Parameter(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 Connection::SetTracing(bool toggle) +{ + // 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, &Connection::TraceOutput, nullptr); + } +} + +// ------------------------------------------------------------------------------------------------ +void Connection::SetProfiling(bool toggle) +{ + // 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, &Connection::ProfileOutput, nullptr); + } +} + +// ------------------------------------------------------------------------------------------------ +void Connection::SetBusyTimeout(Int32 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 [%s]", m_Handle->ErrMsg()); + } +} + +// ------------------------------------------------------------------------------------------------ +Int32 Connection::GetInfo(Int32 operation, bool highwater, bool reset) +{ + // Where to retrieve the information + Int32 cur_value; + Int32 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 Connection::ReserveQueue(Uint32 num) +{ + SQMOD_VALIDATE(*this); + // Perform the requested operation + m_Handle->mQueue.reserve(m_Handle->mQueue.size() + num); +} + +// ------------------------------------------------------------------------------------------------ +void Connection::PopQueue() +{ + SQMOD_VALIDATE(*this); + // Perform the requested operation + if (!SQMOD_GET_VALID(*this)->mQueue.empty()) + { + m_Handle->mQueue.pop_back(); + } +} + +// ------------------------------------------------------------------------------------------------ +Int32 Connection::Flush() +{ + SQMOD_VALIDATE_CREATED(*this); + // Perform the requested operation + return m_Handle->Flush(m_Handle->mQueue.size(), NullObject(), NullFunction()); +} + +// ------------------------------------------------------------------------------------------------ +Int32 Connection::Flush(SQInteger num) +{ + SQMOD_VALIDATE_CREATED(*this); + // Perform the requested operation + return m_Handle->Flush(ConvTo< Uint32 >::From(num), NullObject(), NullFunction()); +} + +// ------------------------------------------------------------------------------------------------ +Int32 Connection::Flush(Object & env, Function & func) +{ + SQMOD_VALIDATE_CREATED(*this); + // Perform the requested operation + return m_Handle->Flush(m_Handle->mQueue.size(), env, func); +} + +// ------------------------------------------------------------------------------------------------ +Int32 Connection::Flush(SQInteger num, Object & env, Function & func) +{ + SQMOD_VALIDATE_CREATED(*this); + // Perform the requested operation + return m_Handle->Flush(ConvTo< Uint32 >::From(num), env, func); +} + +// ------------------------------------------------------------------------------------------------ +#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) +void Parameter::Validate(CCStr file, Int32 line) const +{ + // Are we pointing to a valid index? + if (m_Index < 0) + { + SqThrowF("Invalid column index: %d < 0 =>[%s:%d]", m_Index, file, line); + } + // Do we have a valid statement handle? + else if (!m_Handle) + { + SqThrowF("Invalid SQLite statement reference =>[%s:%d]", file, line); + } +} +#else +void Parameter::Validate() const +{ + // Are we pointing to a valid index? + if (m_Index < 0) + { + SqThrowF("Invalid column index: %d < 0", m_Index); + } + // Do we have a valid statement handle? + else if (!m_Handle) + { + SqThrowF("Invalid SQLite statement reference"); + } +} +#endif // _DEBUG + +// ------------------------------------------------------------------------------------------------ +#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) +void Parameter::ValidateCreated(CCStr file, Int32 line) const +{ + // Are we pointing to a valid index? + if (m_Index < 0) + { + SqThrowF("Invalid column index: %d < 0 =>[%s:%d]", m_Index, file, line); + } + else if (!m_Handle) + { + SqThrowF("Invalid SQLite statement reference =>[%s:%d]", file, line); + } + else if (m_Handle->mPtr == nullptr) + { + SqThrowF("Invalid SQLite statement =>[%s:%d]", file, line); + } +} +#else +void Parameter::ValidateCreated() const +{ + // Are we pointing to a valid index? + if (m_Index < 0) + { + SqThrowF("Invalid column index: %d < 0", m_Index); + } + else if (!m_Handle) + { + SqThrowF("Invalid SQLite statement reference"); + } + else if (m_Handle->mPtr == nullptr) + { + SqThrowF("Invalid SQLite statement"); + } +} +#endif // _DEBUG + +// ------------------------------------------------------------------------------------------------ +#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) +const StmtRef & Parameter::GetValid(CCStr file, Int32 line) const +{ + Validate(file, line); + return m_Handle; +} +#else +const StmtRef & Parameter::GetValid() const +{ + Validate(); + return m_Handle; +} +#endif // _DEBUG + +// ------------------------------------------------------------------------------------------------ +#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) +const StmtRef & Parameter::GetCreated(CCStr file, Int32 line) const +{ + ValidateCreated(file, line); + return m_Handle; +} +#else +const StmtRef & Parameter::GetCreated() const +{ + ValidateCreated(); + return m_Handle; +} +#endif // _DEBUG + +// ------------------------------------------------------------------------------------------------ +#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) +void Parameter::ValidateParam(Int32 idx, CCStr file, Int32 line) const +{ + ValidateCreated(file, line); + // Is the specified index in range? + if (!m_Handle->CheckParameter(idx)) + { + SqThrowF("Parameter index is out of range (%d:%d) =>[%s:%d]", idx, m_Handle->mParameters, + file, line); + } +} +#else +void Parameter::ValidateParam(Int32 idx) const +{ + ValidateCreated(); + // Is the specified index in range? + if (!m_Handle->CheckParameter(idx)) + { + SqThrowF("Parameter index is out of range (%d:%d)", idx, m_Handle->mParameters); + } +} +#endif // _DEBUG + +// ------------------------------------------------------------------------------------------------ +void Parameter::SetIndex(const Object & param) +{ + // Where the index will be extracted + Int32 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("%s", LastErrorString(vm).c_str()); + } + // 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 >::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("%s", LastErrorString(vm).c_str()); + } + // 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 >::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 (%s)", SqTypeName(param.GetType())); + } + // Assign the index with a failsafe to invalid on error + AutoAssign< Int32 > 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 Parameter::GetStatement() const +{ + return GetStatementObj(m_Handle); +} + +// ------------------------------------------------------------------------------------------------ +Object Parameter::GetConnection() const +{ + return GetConnectionObj(SQMOD_GET_VALID(*this)->mConn); +} + +// ------------------------------------------------------------------------------------------------ +void Parameter::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(DefaultVM::Get(), value); + // Pop the object from the stack as a string + const Var< CSStr > str(DefaultVM::Get(), -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 Parameter::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 Parameter::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 Parameter::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 Parameter::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 >::From(value)); + // Validate the result + if (m_Handle->mStatus != SQLITE_OK) + { + STHROWF(SQMOD_BINDFAILED, "int8", m_Index, m_Handle->ErrMsg()); + } +} + +// ------------------------------------------------------------------------------------------------ +void Parameter::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 >::From(value)); + // Validate the result + if (m_Handle->mStatus != SQLITE_OK) + { + STHROWF(SQMOD_BINDFAILED, "uint8", m_Index, m_Handle->ErrMsg()); + } +} + +// ------------------------------------------------------------------------------------------------ +void Parameter::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 >::From(value)); + // Validate the result + if (m_Handle->mStatus != SQLITE_OK) + { + STHROWF(SQMOD_BINDFAILED, "int16", m_Index, m_Handle->ErrMsg()); + } +} + +// ------------------------------------------------------------------------------------------------ +void Parameter::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 >::From(value)); + // Validate the result + if (m_Handle->mStatus != SQLITE_OK) + { + STHROWF(SQMOD_BINDFAILED, "uint16", m_Index, m_Handle->ErrMsg()); + } +} + +// ------------------------------------------------------------------------------------------------ +void Parameter::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 >::From(value)); + // Validate the result + if (m_Handle->mStatus != SQLITE_OK) + { + STHROWF(SQMOD_BINDFAILED, "int32", m_Index, m_Handle->ErrMsg()); + } +} + +// ------------------------------------------------------------------------------------------------ +void Parameter::SetUint32(SQInteger value) +{ + SQMOD_VALIDATE_CREATED(*this); + // Attempt to bind the specified value + m_Handle->mStatus = sqlite3_bind_int(m_Handle->mPtr, m_Index, ConvTo< Uint32 >::From(value)); + // Validate the result + if (m_Handle->mStatus != SQLITE_OK) + { + STHROWF(SQMOD_BINDFAILED, "uint32", m_Index, m_Handle->ErrMsg()); + } +} + +// ------------------------------------------------------------------------------------------------ +void Parameter::SetInt64(const Object & value) +{ + SQMOD_VALIDATE_CREATED(*this); + // Attempt to bind the specified value + m_Handle->mStatus = sqlite3_bind_int64(m_Handle->mPtr, m_Index, value.Cast< const SLongInt & >().GetNum()); + // Validate the result + if (m_Handle->mStatus != SQLITE_OK) + { + STHROWF(SQMOD_BINDFAILED, "int64", m_Index, m_Handle->ErrMsg()); + } +} + +// ------------------------------------------------------------------------------------------------ +void Parameter::SetUint64(const Object & value) +{ + SQMOD_VALIDATE_CREATED(*this); + // Attempt to bind the specified value + m_Handle->mStatus = sqlite3_bind_int64(m_Handle->mPtr, m_Index, value.Cast< const ULongInt & >().GetNum()); + // Validate the result + if (m_Handle->mStatus != SQLITE_OK) + { + STHROWF(SQMOD_BINDFAILED, "uint64", m_Index, m_Handle->ErrMsg()); + } +} + +// ------------------------------------------------------------------------------------------------ +void Parameter::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 Parameter::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< Float32 >::From(value)); + // Validate the result + if (m_Handle->mStatus != SQLITE_OK) + { + STHROWF(SQMOD_BINDFAILED, "float32", m_Index, m_Handle->ErrMsg()); + } +} + +// ------------------------------------------------------------------------------------------------ +void Parameter::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 Parameter::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, value.mLen, SQLITE_TRANSIENT); + // Validate the result + if (m_Handle->mStatus != SQLITE_OK) + { + STHROWF(SQMOD_BINDFAILED, "string", m_Index, m_Handle->ErrMsg()); + } +} + +// ------------------------------------------------------------------------------------------------ +void Parameter::SetStringRaw(CSStr 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, length, SQLITE_TRANSIENT); + // Validate the result + if (m_Handle->mStatus != SQLITE_OK) + { + STHROWF(SQMOD_BINDFAILED, "string", m_Index, m_Handle->ErrMsg()); + } +} + +// ------------------------------------------------------------------------------------------------ +void Parameter::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 >::From(size)); + // Validate the result + if (m_Handle->mStatus != SQLITE_OK) + { + STHROWF(SQMOD_BINDFAILED, "blob", m_Index, m_Handle->ErrMsg()); + } +} + +// ------------------------------------------------------------------------------------------------ +void Parameter::SetBlob(const Object & value) +{ + SQMOD_VALIDATE_CREATED(*this); + // The blob data pointer and size + SQUserPointer ptr = nullptr; + SQInteger len = 0; + // 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, len, SQLITE_TRANSIENT); + // Validate the result + if (m_Handle->mStatus != SQLITE_OK) + { + STHROWF(SQMOD_BINDFAILED, "blob", m_Index, m_Handle->ErrMsg()); + } +} +// ------------------------------------------------------------------------------------------------ +void Parameter::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 Parameter::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: %d", offset); + } + else if (offset < 0) + { + STHROWF("Negative buffer length is not allowed: %d", length); + } + else if (offset + length > buff.Capacity()) + { + STHROWF("Buffer range is outside boundaries: (%d+%d) > %u", 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< int >(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 Parameter::SetDate(const Date & value) +{ + SQMOD_VALIDATE_CREATED(*this); + // Attempt to generate the specified date string + CSStr ptr = FmtStr(_SC("%s 00:00:00"), value.ToString()); + // Attempt to bind the specified value + m_Handle->mStatus = sqlite3_bind_text(m_Handle->mPtr, m_Index, ptr, -1, SQLITE_TRANSIENT); + // Validate the result + if (m_Handle->mStatus != SQLITE_OK) + { + STHROWF(SQMOD_BINDFAILED, "date", m_Index, m_Handle->ErrMsg()); + } +} + +// ------------------------------------------------------------------------------------------------ +void Parameter::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 (%u-%u-%u)", y, m, d); + } + // Attempt to generate the specified date string + CSStr ptr = FmtStr(_SC("%u-%u-%u 00:00:00"), y, m, d); + // Attempt to bind the specified value + m_Handle->mStatus = sqlite3_bind_text(m_Handle->mPtr, m_Index, ptr, -1, SQLITE_TRANSIENT); + // Validate the result + if (m_Handle->mStatus != SQLITE_OK) + { + STHROWF(SQMOD_BINDFAILED, "date", m_Index, m_Handle->ErrMsg()); + } +} + +// ------------------------------------------------------------------------------------------------ +void Parameter::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, value.GetTimestamp().GetSecondsI()); + // Validate the result + if (m_Handle->mStatus != SQLITE_OK) + { + STHROWF(SQMOD_BINDFAILED, "time", m_Index, m_Handle->ErrMsg()); + } +} + +// ------------------------------------------------------------------------------------------------ +void Parameter::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: %u >= 24", h); + } + // Is the specified minute within range? + else if (m >= 60) + { + STHROWF("Minute value is out of range: %u >= 60", m); + } + // Is the specified second within range? + else if (s >= 60) + { + STHROWF("Second value is out of range: %u >= 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 Parameter::SetDatetime(const Datetime & value) +{ + SetDatetimeEx(value.GetYear(), value.GetMonth(), value.GetDay(), value.GetHour(), value.GetMinute(), value.GetSecond()); +} + +// ------------------------------------------------------------------------------------------------ +void Parameter::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 (%u-%u-%u)", y, mo, d); + } + // Is the specified hour within range? + else if (h >= 24) + { + STHROWF("Hour value is out of range: %u >= 24", h); + } + // Is the specified minute within range? + else if (mi >= 60) + { + STHROWF("Minute value is out of range: %u >= 60", mi); + } + // Is the specified second within range? + else if (s >= 60) + { + STHROWF("Second value is out of range: %u >= 60", s); + } + // Attempt to generate the specified date string + CSStr ptr = FmtStr(_SC("%04u-%02u-%02u %02u:%02u:%02u"), y, mo, d, h, mi, s); + // Attempt to bind the specified value + m_Handle->mStatus = sqlite3_bind_text(m_Handle->mPtr, m_Index, ptr, -1, SQLITE_TRANSIENT); + // Validate the result + if (m_Handle->mStatus != SQLITE_OK) + { + STHROWF(SQMOD_BINDFAILED, "date-time", m_Index, m_Handle->ErrMsg()); + } +} + +// ------------------------------------------------------------------------------------------------ +void Parameter::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 >(std::time(nullptr))); + // Validate the result + if (m_Handle->mStatus != SQLITE_OK) + { + STHROWF(SQMOD_BINDFAILED, "time-stamp", m_Index, m_Handle->ErrMsg()); + } +} + +// ------------------------------------------------------------------------------------------------ +void Parameter::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 Column::Validate(CCStr file, Int32 line) const +{ + // Are we pointing to a valid index? + if (m_Index < 0) + { + SqThrowF("Invalid column index: %d < 0 =>[%s:%d]", m_Index, file, line); + } + // Do we have a valid statement handle? + else if (!m_Handle) + { + SqThrowF("Invalid SQLite statement reference =>[%s:%d]", file, line); + } +} +#else +void Column::Validate() const +{ + // Are we pointing to a valid index? + if (m_Index < 0) + { + SqThrowF("Invalid column index: %d < 0", m_Index); + } + // Do we have a valid statement handle? + else if (!m_Handle) + { + SqThrowF("Invalid SQLite statement reference"); + } +} +#endif // _DEBUG + +// ------------------------------------------------------------------------------------------------ +#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) +void Column::ValidateCreated(CCStr file, Int32 line) const +{ + // Are we pointing to a valid index? + if (m_Index < 0) + { + SqThrowF("Invalid column index: %d < 0 =>[%s:%d]", m_Index, file, line); + } + else if (!m_Handle) + { + SqThrowF("Invalid SQLite statement reference =>[%s:%d]", file, line); + } + else if (m_Handle->mPtr == nullptr) + { + SqThrowF("Invalid SQLite statement =>[%s:%d]", file, line); + } +} +#else +void Column::ValidateCreated() const +{ + // Are we pointing to a valid index? + if (m_Index < 0) + { + SqThrowF("Invalid column index: %d < 0", m_Index); + } + else if (!m_Handle) + { + SqThrowF("Invalid SQLite statement reference"); + } + else if (m_Handle->mPtr == nullptr) + { + SqThrowF("Invalid SQLite statement"); + } +} +#endif // _DEBUG + +// ------------------------------------------------------------------------------------------------ +#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) +const StmtRef & Column::GetValid(CCStr file, Int32 line) const +{ + Validate(file, line); + return m_Handle; +} +#else +const StmtRef & Column::GetValid() const +{ + Validate(); + return m_Handle; +} +#endif // _DEBUG + +// ------------------------------------------------------------------------------------------------ +#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) +const StmtRef & Column::GetCreated(CCStr file, Int32 line) const +{ + ValidateCreated(file, line); + return m_Handle; +} +#else +const StmtRef & Column::GetCreated() const +{ + ValidateCreated(); + return m_Handle; +} +#endif // _DEBUG + +// ------------------------------------------------------------------------------------------------ +#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) +void Column::ValidateColumn(Int32 idx, CCStr file, Int32 line) const +{ + ValidateCreated(file, line); + // Is the specified index in range? + if (!m_Handle->CheckColumn(idx)) + { + SqThrowF("Column index is out of range: %d:%d =>[%s:%d]", idx, m_Handle->mColumns, + file, line); + } +} +#else +void Column::ValidateColumn(Int32 idx) const +{ + ValidateCreated(); + // Is the specified index in range? + if (!m_Handle->CheckColumn(idx)) + { + SqThrowF("Column index is out of range: %d:%d", idx, m_Handle->mColumns); + } +} +#endif // _DEBUG + +// ------------------------------------------------------------------------------------------------ +#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) +void Column::ValidateRow(CCStr file, Int32 line) const +{ + ValidateCreated(file, line); + // Do we have any rows available? + if (!m_Handle->mGood) + { + STHROWF("No row available =>[%s:%d]", file, line); + } +} +#else +void Column::ValidateRow() const +{ + ValidateCreated(); + // Do we have any rows available? + if (!m_Handle->mGood) + { + STHROWF("No row available"); + } +} +#endif // _DEBUG + +// ------------------------------------------------------------------------------------------------ +void Column::SetIndex(const Object & column) +{ + // Where the index will be extracted + Int32 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("%s", LastErrorString(vm).c_str()); + } + // 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 >::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("%s", LastErrorString(vm).c_str()); + } + // 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 >::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 (%s)", SqTypeName(column.GetType())); + } + // Assign the index with a failsafe to invalid on error + AutoAssign< Int32 > 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 Column::GetStatement() const +{ + return GetStatementObj(m_Handle); +} + +// ------------------------------------------------------------------------------------------------ +Object Column::GetConnection() const +{ + return GetConnectionObj(SQMOD_GET_VALID(*this)->mConn); +} + +// ------------------------------------------------------------------------------------------------ +bool Column::IsNull() const +{ + return (sqlite3_column_type(SQMOD_GET_CREATED(*this)->mPtr, m_Index) == SQLITE_NULL); +} + +// ------------------------------------------------------------------------------------------------ +CSStr Column::GetName() const +{ + return sqlite3_column_name(SQMOD_GET_CREATED(*this)->mPtr, m_Index); +} + +// ------------------------------------------------------------------------------------------------ +CSStr Column::GetOriginName() const +{ +#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 Column::GetType() const +{ + return sqlite3_column_type(SQMOD_GET_CREATED(*this)->mPtr, m_Index); +} + +// ------------------------------------------------------------------------------------------------ +Int32 Column::GetBytes() const +{ + return sqlite3_column_bytes(SQMOD_GET_CREATED(*this)->mPtr, m_Index); +} + +// ------------------------------------------------------------------------------------------------ +Object Column::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(DefaultVM::Get()); + } break; + // Is this an integer? + case SQLITE_INTEGER: + { + sq_pushinteger(DefaultVM::Get(), sqlite3_column_integer(m_Handle->mPtr, m_Index)); + } break; + // Is this a floating point? + case SQLITE_FLOAT: + { + sq_pushfloat(DefaultVM::Get(), + ConvTo< SQFloat >::From(sqlite3_column_double(m_Handle->mPtr, m_Index))); + } break; + // Is this a string? + case SQLITE_TEXT: + { + sq_pushstring(DefaultVM::Get(), + reinterpret_cast< CSStr >(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 size = sqlite3_column_bytes(m_Handle->mPtr, m_Index); + // Retrieve the the actual blob data that must be returned + auto data = reinterpret_cast< CCStr >(sqlite3_column_blob(m_Handle->mPtr, m_Index)); + // Attempt to create a buffer with the blob data on the stack + Var< const SqBuffer & >::push(DefaultVM::Get(), SqBuffer(data, size, 0)); + } break; + // Unknown type + default: STHROWF("Unknown value to fetch at index: %d", m_Index); + } + // Obtain the object with the value from the stack and return it + return Var< Object >(DefaultVM::Get(), -1).value; +} + +// ------------------------------------------------------------------------------------------------ +Object Column::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(DefaultVM::Get(), 0); + } break; + // Is this an integer? + case SQLITE_INTEGER: + { + sq_pushinteger(DefaultVM::Get(), sqlite3_column_integer(m_Handle->mPtr, m_Index)); + } break; + // Is this a floating point? + case SQLITE_FLOAT: + { + sq_pushfloat(DefaultVM::Get(), + ConvTo< SQFloat >::From(sqlite3_column_double(m_Handle->mPtr, m_Index))); + } break; + // Is this a string? + case SQLITE_TEXT: + { + auto str = reinterpret_cast< CSStr >(sqlite3_column_text(m_Handle->mPtr, m_Index)); + // Is there even a string to parse? + if (!str || *str == '\0') + { + sq_pushinteger(DefaultVM::Get(), 0); + } + // Can we treat this string as a float? + else if (!std::strchr(str, '.')) + { + sq_pushfloat(DefaultVM::Get(), + ConvTo< SQFloat >::From(std::strtod(str, nullptr))); + } + else + { + sq_pushinteger(DefaultVM::Get(), + ConvTo< SQInteger >::From(std::strtoll(str, nullptr, 10))); + + } + } break; + // Unknown type + default: STHROWF("Unknown number to fetch at index: %d", m_Index); + } + // Obtain the object with the value from the stack and return it + return Var< Object >(DefaultVM::Get(), -1).value; +} + +// ------------------------------------------------------------------------------------------------ +SQInteger Column::GetInteger() const +{ + SQMOD_VALIDATE_ROW(*this); + // Return the requested information + return sqlite3_column_integer(m_Handle->mPtr, m_Index); +} + +// ------------------------------------------------------------------------------------------------ +SQFloat Column::GetFloat() const +{ + SQMOD_VALIDATE_ROW(*this); + // Return the requested information + return ConvTo< SQFloat >::From(sqlite3_column_double(m_Handle->mPtr, m_Index)); +} + +// ------------------------------------------------------------------------------------------------ +Object Column::GetLong() const +{ + SQMOD_VALIDATE_ROW(*this); + // Return the requested information + return Object(new SLongInt(sqlite3_column_int64(m_Handle->mPtr, m_Index))); +} + +// ------------------------------------------------------------------------------------------------ +Object Column::GetString() const +{ + SQMOD_VALIDATE_ROW(*this); + // Obtain the initial stack size + const StackGuard sg; + // Push the column text on the stack + sq_pushstring(DefaultVM::Get(), reinterpret_cast< CSStr >(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 >(DefaultVM::Get(), -1).value; +} + +// ------------------------------------------------------------------------------------------------ +bool Column::GetBoolean() const +{ + SQMOD_VALIDATE_ROW(*this); + // Return the requested information + return sqlite3_column_int(m_Handle->mPtr, m_Index) > 0; +} + +// ------------------------------------------------------------------------------------------------ +SQChar Column::GetChar() const +{ + SQMOD_VALIDATE_ROW(*this); + // Return the requested information + return (SQChar)sqlite3_column_int(m_Handle->mPtr, m_Index); +} + +// ------------------------------------------------------------------------------------------------ +Object Column::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 size = sqlite3_column_bytes(m_Handle->mPtr, m_Index); + // Retrieve the the actual blob data that must be returned + auto data = reinterpret_cast< CCStr >(sqlite3_column_blob(m_Handle->mPtr, m_Index)); + // Attempt to create a buffer with the blob data on the stack + Var< const SqBuffer & >::push(DefaultVM::Get(), SqBuffer(data, size, 0)); + // Get the object from the stack and return it + return Var< Object >(DefaultVM::Get(), -1).value; +} + +// ------------------------------------------------------------------------------------------------ +Object Column::GetBlob() const +{ + SQMOD_VALIDATE_ROW(*this); + // Obtain the initial stack size + const StackGuard sg; + // Obtain the size of the data + const Int32 sz = sqlite3_column_bytes(m_Handle->mPtr, m_Index); + // Allocate a blob of the same size + SQUserPointer p = sqstd_createblob(DefaultVM::Get(), 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(DefaultVM::Get(), 1); + // Push a null value instead + sq_pushnull(DefaultVM::Get()); + } + // Copy the data into the memory blob + else + { + std::memcpy(p, b, sz); + } + // Get the object from the stack and return it + return Var< Object >(DefaultVM::Get(), -1).value; +} + +// ------------------------------------------------------------------------------------------------ +#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) +void Statement::Validate(CCStr file, Int32 line) const +{ + if (!m_Handle) + { + SqThrowF("Invalid SQLite statement reference =>[%s:%d]", file, line); + } +} +#else +void Statement::Validate() const +{ + if (!m_Handle) + { + SqThrowF("Invalid SQLite statement reference"); + } +} +#endif // _DEBUG + +// ------------------------------------------------------------------------------------------------ +#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) +void Statement::ValidateCreated(CCStr file, Int32 line) const +{ + if (!m_Handle) + { + SqThrowF("Invalid SQLite statement reference =>[%s:%d]", file, line); + } + else if (m_Handle->mPtr == nullptr) + { + SqThrowF("Invalid SQLite statement =>[%s:%d]", file, line); + } +} +#else +void Statement::ValidateCreated() const +{ + if (!m_Handle) + { + SqThrowF("Invalid SQLite statement reference"); + } + else if (m_Handle->mPtr == nullptr) + { + SqThrowF("Invalid SQLite statement"); + } +} +#endif // _DEBUG + +// ------------------------------------------------------------------------------------------------ +#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) +const StmtRef & Statement::GetValid(CCStr file, Int32 line) const +{ + Validate(file, line); + return m_Handle; +} +#else +const StmtRef & Statement::GetValid() const +{ + Validate(); + return m_Handle; +} +#endif // _DEBUG + +// ------------------------------------------------------------------------------------------------ +#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) +const StmtRef & Statement::GetCreated(CCStr file, Int32 line) const +{ + ValidateCreated(file, line); + return m_Handle; +} +#else +const StmtRef & Statement::GetCreated() const +{ + ValidateCreated(); + return m_Handle; +} +#endif // _DEBUG + +// ------------------------------------------------------------------------------------------------ +#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) +void Statement::ValidateColumn(Int32 idx, CCStr file, Int32 line) const +{ + ValidateCreated(file, line); + // Is the specified index in range? + if (!m_Handle->CheckColumn(idx)) + { + SqThrowF("Column index is out of range: %d:%d =>[%s:%d]", idx, m_Handle->mColumns, + file, line); + } +} +#else +void Statement::ValidateColumn(Int32 idx) const +{ + ValidateCreated(); + // Is the specified index in range? + if (!m_Handle->CheckColumn(idx)) + { + SqThrowF("Column index is out of range: %d:%d", idx, m_Handle->mColumns); + } +} +#endif // _DEBUG + +// ------------------------------------------------------------------------------------------------ +#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) +void Statement::ValidateParam(Int32 idx, CCStr file, Int32 line) const +{ + ValidateCreated(file, line); + // Is the specified index in range? + if (!m_Handle->CheckParameter(idx)) + { + SqThrowF("Parameter index is out of range: %d:%d =>[%s:%d]", idx, m_Handle->mParameters, + file, line); + } +} +#else +void Statement::ValidateParam(Int32 idx) const +{ + ValidateCreated(); + // Is the specified index in range? + if (!m_Handle->CheckParameter(idx)) + { + SqThrowF("Parameter index is out of range: %d:%d", idx, m_Handle->mParameters); + } +} +#endif // _DEBUG + +// ------------------------------------------------------------------------------------------------ +#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) +void Statement::ValidateRow(CCStr file, Int32 line) const +{ + ValidateCreated(file, line); + // Do we have any rows available? + if (!m_Handle->mGood) + { + SqThrowF("No row available =>[%s:%d]", file, line); + } +} +#else +void Statement::ValidateRow() const +{ + ValidateCreated(); + // Do we have any rows available? + if (!m_Handle->mGood) + { + SqThrowF("No row available"); + } +} +#endif // _DEBUG + +// ------------------------------------------------------------------------------------------------ +Statement::Statement(const Connection & connection, StackStrF & query) + : m_Handle(new StmtHnd(connection.GetHandle())) +{ + SQMOD_GET_VALID(*this)->Create(query.mPtr, query.mLen); +} + +// ------------------------------------------------------------------------------------------------ +Object Statement::GetConnection() const +{ + return Object(new Connection(SQMOD_GET_VALID(*this)->mConn)); +} + +// ------------------------------------------------------------------------------------------------ +Statement & Statement::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 [%s]", m_Handle->ErrStr()); + } + // Allow further chaining of operations + return *this; +} + +// ------------------------------------------------------------------------------------------------ +Statement & Statement::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 [%s]", m_Handle->ErrStr()); + } + // Allow further chaining of operations + return *this; +} + +// ------------------------------------------------------------------------------------------------ +Int32 Statement::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 [%s]", m_Handle->ErrStr()); + } + // Operation failed (shouldn't reach this point!) + return -1; +} + +// ------------------------------------------------------------------------------------------------ +bool Statement::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 [%s]", m_Handle->ErrStr()); + } + // Operation failed (shouldn't reach this point!) + return false; +} + +// ------------------------------------------------------------------------------------------------ +Statement & Statement::SetArray(Int32 idx, const Array & arr) +{ + // Obtain a script iterator + Array::iterator itr; + // Create a parameter instance to bind the values + Parameter 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; +} + +// ------------------------------------------------------------------------------------------------ +Statement & Statement::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 + Parameter 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 Statement::GetArray(Int32 min, Int32 max) const +{ + SQMOD_VALIDATE_ROW(*this); + // Is the specified minimum index valid? + if (min < 0) + { + STHROWF("Minimum is bellow zero: %d", min); + } + // Is the minimum actually the minimum? + else if (min > max) + { + STHROWF("Minimum is higher than maximum: %d > %d", min, max); + } + // Is the minimum in range? + else if (!m_Handle->CheckColumn(min)) + { + STHROWF("Minimum is out of range: %d:%d", min, m_Handle->mColumns); + } + // Is the maximum in range? + else if (!m_Handle->CheckColumn(max)) + { + STHROWF("Maximum is out of range: %d:%d", max, m_Handle->mColumns); + } + // Allocate an array large enough to hold the values from selected columns + Array arr(DefaultVM::Get(), max-min); + // Create a column instance to retrieve the values + Column column(m_Handle); + // Array element counter + Int32 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 Statement::GetTable(Int32 min, Int32 max) const +{ + SQMOD_VALIDATE_ROW(*this); + // Is the specified minimum index valid? + if (min < 0) + { + STHROWF("Minimum is bellow zero: %d", min); + } + // Is the minimum actually the minimum? + else if (min > max) + { + STHROWF("Minimum is higher than maximum: %d > %d", min, max); + } + // Is the minimum in range> + else if (!m_Handle->CheckColumn(min)) + { + STHROWF("Minimum is out of range: %d:%d", min, m_Handle->mColumns); + } + // Is the maximum in range? + else if (!m_Handle->CheckColumn(max)) + { + STHROWF("Maximum is out of range: %d:%d", max, m_Handle->mColumns); + } + // Create a table to hold the selected column values + Table tbl(DefaultVM::Get()); + // Create a column instance to retrieve the values + Column column(m_Handle); + // Process the range of selected columns + while (min <= max) + { + // Attempt to obtain the column name + CSStr name = sqlite3_column_name(m_Handle->mPtr, min); + // Validate the obtained name + if (!name) + { + STHROWF("Unable to retrieve name of column (%d)", 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; +} + +// ------------------------------------------------------------------------------------------------ +Transaction::Transaction(const Connection & db) + : Transaction(db.GetHandle()) +{ + /* ... */ +} + +// ------------------------------------------------------------------------------------------------ +Transaction::Transaction(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 [%s]", m_Handle->ErrMsg()); + } +} + +// ------------------------------------------------------------------------------------------------ +Transaction::~Transaction() +{ + // 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 Transaction::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 [%s]", 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); + + for (Uint32 n = 0; n < (sizeof(g_MainEnum) / sizeof(EnumElement)); ++n) + { + e.Const(g_MainEnum[n].Name, g_MainEnum[n].Value); + } + + ConstTable(vm).Enum(_SC("SQLiteOpt"), e); + Table sqlns(vm); - Register_Constants(sqlns); - Register_Common(sqlns); - Register_Connection(sqlns); - Register_Statement(sqlns); - Register_Parameter(sqlns); - Register_Column(sqlns); - Register_Transaction(sqlns); + 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< Connection >(sqlns.GetVM(), SQLiteConnectionTypename::Str) + // Constructors + .Ctor() + .Ctor< StackStrF & >() + .Ctor< StackStrF &, Int32 >() + .Ctor< StackStrF &, Int32, StackStrF & >() + // Meta-methods + .SquirrelFunc(_SC("_typename"), &SQLiteConnectionTypename::Fn) + .Func(_SC("_tostring"), &Connection::ToString) + // Properties + .Prop(_SC("IsValid"), &Connection::IsValid) + .Prop(_SC("Connected"), &Connection::IsConnected) + .Prop(_SC("References"), &Connection::GetRefCount) + .Prop(_SC("Status"), &Connection::GetStatus) + .Prop(_SC("Flags"), &Connection::GetFlags) + .Prop(_SC("Name"), &Connection::GetName) + .Prop(_SC("VFS"), &Connection::GetVFS) + .Prop(_SC("ErrCode"), &Connection::GetErrorCode) + .Prop(_SC("ExErrCode"), &Connection::GetExtendedErrorCode) + .Prop(_SC("ExtendedErrCode"), &Connection::GetExtendedErrorCode) + .Prop(_SC("ErrStr"), &Connection::GetErrStr) + .Prop(_SC("ErrMsg"), &Connection::GetErrMsg) + .Prop(_SC("ReadOnly"), &Connection::IsReadOnly) + .Prop(_SC("Autocommit"), &Connection::GetAutoCommit) + .Prop(_SC("LastInsertRowId"), &Connection::GetLastInsertRowID) + .Prop(_SC("Changes"), &Connection::GetChanges) + .Prop(_SC("TotalChanges"), &Connection::GetTotalChanges) + .Prop(_SC("Trace"), &Connection::GetTracing, &Connection::SetTracing) + .Prop(_SC("Profile"), &Connection::GetProfiling, &Connection::SetProfiling) + .Prop(_SC("QueueSize"), &Connection::QueueSize) + // Member Methods + .Func(_SC("Release"), &Connection::Release) + .FmtFunc(_SC("Exec"), &Connection::Exec) + .FmtFunc(_SC("Queue"), &Connection::Queue) + .FmtFunc(_SC("Query"), &Connection::Query) + .FmtFunc(_SC("TableExists"), &Connection::TableExists) + .Func(_SC("InterruptOperation"), &Connection::InterruptOperation) + .Func(_SC("SetBusyTimeout"), &Connection::SetBusyTimeout) + .Func(_SC("ReleaseMemory"), &Connection::ReleaseMemory) + .Func(_SC("ReserveQueue"), &Connection::ReserveQueue) + .Func(_SC("CompactQueue"), &Connection::CompactQueue) + .Func(_SC("ClearQueue"), &Connection::ClearQueue) + .Func(_SC("PopQueue"), &Connection::PopQueue) + // Member Overloads + .Overload< void (Connection::*)(StackStrF &) >(_SC("Open"), &Connection::Open) + .Overload< void (Connection::*)(StackStrF &, Int32) >(_SC("Open"), &Connection::Open) + .Overload< void (Connection::*)(StackStrF &, Int32, StackStrF &) >(_SC("Open"), &Connection::Open) + .Overload< Int32 (Connection::*)(Int32) >(_SC("GetInfo"), &Connection::GetInfo) + .Overload< Int32 (Connection::*)(Int32, bool) >(_SC("GetInfo"), &Connection::GetInfo) + .Overload< Int32 (Connection::*)(Int32, bool, bool) >(_SC("GetInfo"), &Connection::GetInfo) + .Overload< Int32 (Connection::*)(void) >(_SC("Flush"), &Connection::Flush) + .Overload< Int32 (Connection::*)(SQInteger) >(_SC("Flush"), &Connection::Flush) + .Overload< Int32 (Connection::*)(Object &, Function &) >(_SC("Flush"), &Connection::Flush) + .Overload< Int32 (Connection::*)(SQInteger, Object &, Function &) >(_SC("Flush"), &Connection::Flush) + ); + + sqlns.Bind(_SC("Parameter"), + Class< Parameter >(sqlns.GetVM(), SQLiteParameterTypename::Str) + // Constructors + .Ctor() + .Ctor< const Parameter & >() + // Meta-methods + .SquirrelFunc(_SC("_typename"), &SQLiteParameterTypename::Fn) + .Func(_SC("_tostring"), &Parameter::ToString) + // Properties + .Prop(_SC("IsValid"), &Parameter::IsValid) + .Prop(_SC("References"), &Parameter::GetRefCount) + .Prop(_SC("Index"), &Parameter::GetIndex) + .Prop(_SC("Statement"), &Parameter::GetStatement) + .Prop(_SC("Connection"), &Parameter::GetConnection) + .Prop(_SC("References"), &Parameter::GetRefCount) + .Prop(_SC("Name"), &Parameter::GetName) + // Member Methods + .Func(_SC("Release"), &Parameter::Release) + .Func(_SC("SetValue"), &Parameter::SetValue) + .Func(_SC("SetBool"), &Parameter::SetBool) + .Func(_SC("SetChar"), &Parameter::SetChar) + .Func(_SC("SetInteger"), &Parameter::SetInteger) + .Func(_SC("SetInt8"), &Parameter::SetInt8) + .Func(_SC("SetUint8"), &Parameter::SetUint8) + .Func(_SC("SetInt16"), &Parameter::SetInt16) + .Func(_SC("SetUint16"), &Parameter::SetUint16) + .Func(_SC("SetInt32"), &Parameter::SetInt32) + .Func(_SC("SetUint32"), &Parameter::SetUint32) + .Func(_SC("SetInt64"), &Parameter::SetInt64) + .Func(_SC("SetUint64"), &Parameter::SetUint64) + .Func(_SC("SetFloat"), &Parameter::SetFloat) + .Func(_SC("SetFloat32"), &Parameter::SetFloat32) + .Func(_SC("SetFloat64"), &Parameter::SetFloat64) + .FmtFunc(_SC("SetString"), &Parameter::SetString) + .Func(_SC("SetZeroBlob"), &Parameter::SetZeroBlob) + .Func(_SC("SetBlob"), &Parameter::SetBlob) + .Func(_SC("SetData"), &Parameter::SetData) + .Func(_SC("SetDataEx"), &Parameter::SetDataEx) + .Func(_SC("SetDate"), &Parameter::SetDate) + .Func(_SC("SetDateEx"), &Parameter::SetDateEx) + .Func(_SC("SetTime"), &Parameter::SetTime) + .Func(_SC("SetTimeEx"), &Parameter::SetTimeEx) + .Func(_SC("SetDatetime"), &Parameter::SetDatetime) + .Func(_SC("SetDatetimeEx"), &Parameter::SetDatetimeEx) + .Func(_SC("SetNow"), &Parameter::SetNow) + .Func(_SC("SetNull"), &Parameter::SetNull) + ); + + sqlns.Bind(_SC("Column"), + Class< Column >(sqlns.GetVM(), SQLiteColumnTypename::Str) + // Constructors + .Ctor() + .Ctor< const Column & >() + // Meta-methods + .SquirrelFunc(_SC("_typename"), &SQLiteColumnTypename::Fn) + .Func(_SC("_tostring"), &Column::ToString) + // Properties + .Prop(_SC("IsValid"), &Column::IsValid) + .Prop(_SC("References"), &Column::GetRefCount) + .Prop(_SC("Index"), &Column::GetIndex) + .Prop(_SC("Statement"), &Column::GetStatement) + .Prop(_SC("Connection"), &Column::GetConnection) + .Prop(_SC("IsNull"), &Column::IsNull) + .Prop(_SC("Name"), &Column::GetName) + .Prop(_SC("OriginName"), &Column::GetOriginName) + .Prop(_SC("Type"), &Column::GetType) + .Prop(_SC("Bytes"), &Column::GetBytes) + .Prop(_SC("Value"), &Column::GetValue) + .Prop(_SC("Number"), &Column::GetNumber) + .Prop(_SC("Integer"), &Column::GetInteger) + .Prop(_SC("Float"), &Column::GetFloat) + .Prop(_SC("Long"), &Column::GetLong) + .Prop(_SC("String"), &Column::GetString) + .Prop(_SC("Boolean"), &Column::GetBoolean) + .Prop(_SC("Char"), &Column::GetChar) + .Prop(_SC("Buffer"), &Column::GetBuffer) + .Prop(_SC("Blob"), &Column::GetBlob) + // Member Methods + .Func(_SC("Release"), &Column::Release) + ); + + sqlns.Bind(_SC("Statement"), + Class< Statement >(sqlns.GetVM(), SQLiteStatementTypename::Str) + // Constructors + .Ctor() + .Ctor< const Statement & >() + .Ctor< const Connection &, StackStrF & >() + // Meta-methods + .SquirrelFunc(_SC("_typename"), &SQLiteStatementTypename::Fn) + .Func(_SC("_tostring"), &Statement::ToString) + // Properties + .Prop(_SC("IsValid"), &Statement::IsValid) + .Prop(_SC("Prepared"), &Statement::IsPrepared) + .Prop(_SC("References"), &Statement::GetReferences) + .Prop(_SC("Connection"), &Statement::GetConnection) + .Prop(_SC("Status"), &Statement::GetStatus) + .Prop(_SC("ErrCode"), &Statement::GetErrorCode) + .Prop(_SC("ExErrCode"), &Statement::GetExtendedErrorCode) + .Prop(_SC("ExtendedErrCode"), &Statement::GetExtendedErrorCode) + .Prop(_SC("ErrStr"), &Statement::GetErrStr) + .Prop(_SC("ErrMsg"), &Statement::GetErrMsg) + .Prop(_SC("Columns"), &Statement::GetColumns) + .Prop(_SC("Parameters"), &Statement::GetParameters) + .Prop(_SC("Query"), &Statement::GetQuery) + .Prop(_SC("Good"), &Statement::GetGood) + .Prop(_SC("Done"), &Statement::GetDone) + .Prop(_SC("DataCount"), &Statement::GetDataCount) + // Member Methods + .Func(_SC("Release"), &Statement::Release) + .Func(_SC("CheckParameter"), &Statement::CheckParameter) + .FmtFunc(_SC("GetParameterIndex"), &Statement::GetParameterIndex) + .Func(_SC("GetParameterName"), &Statement::GetParameterName) + .Func(_SC("CheckColumn"), &Statement::CheckColumn) + .Func(_SC("IsColumnNull"), &Statement::IsColumnNull) + .FmtFunc(_SC("ColumnIndex"), &Statement::GetColumnIndex) + .Func(_SC("ColumnName"), &Statement::GetColumnName) + .Func(_SC("ColumnOriginName"), &Statement::GetColumnOriginName) + .Func(_SC("ColumnType"), &Statement::GetColumnType) + .Func(_SC("ColumnBytes"), &Statement::GetColumnBytes) + .Func(_SC("Reset"), &Statement::Reset) + .Func(_SC("Clear"), &Statement::Clear) + .Func(_SC("Exec"), &Statement::Exec) + .Func(_SC("Step"), &Statement::Step) + .Func(_SC("Param"), &Statement::GetParameter) + .Func(_SC("Parameter"), &Statement::GetParameter) + .Func(_SC("SetValue"), &Statement::SetValue) + .Func(_SC("SetBool"), &Statement::SetBool) + .Func(_SC("SetChar"), &Statement::SetChar) + .Func(_SC("SetInteger"), &Statement::SetInteger) + .Func(_SC("SetInt8"), &Statement::SetInt8) + .Func(_SC("SetUint8"), &Statement::SetUint8) + .Func(_SC("SetInt16"), &Statement::SetInt16) + .Func(_SC("SetUint16"), &Statement::SetUint16) + .Func(_SC("SetInt32"), &Statement::SetInt32) + .Func(_SC("SetUint32"), &Statement::SetUint32) + .Func(_SC("SetInt64"), &Statement::SetInt64) + .Func(_SC("SetUint64"), &Statement::SetUint64) + .Func(_SC("SetFloat"), &Statement::SetFloat) + .Func(_SC("SetFloat32"), &Statement::SetFloat32) + .Func(_SC("SetFloat64"), &Statement::SetFloat64) + .FmtFunc(_SC("SetString"), &Statement::SetString) + .Func(_SC("SetZeroBlob"), &Statement::SetZeroBlob) + .Func(_SC("SetBlob"), &Statement::SetBlob) + .Func(_SC("SetData"), &Statement::SetData) + .Func(_SC("SetDate"), &Statement::SetDate) + .Func(_SC("SetDateEx"), &Statement::SetDateEx) + .Func(_SC("SetTime"), &Statement::SetTime) + .Func(_SC("SetTimeEx"), &Statement::SetTimeEx) + .Func(_SC("SetDatetime"), &Statement::SetDatetime) + .Func(_SC("SetDatetimeEx"), &Statement::SetDatetimeEx) + .Func(_SC("SetNow"), &Statement::SetNow) + .Func(_SC("SetNull"), &Statement::SetNull) + .Func(_SC("SetArray"), &Statement::SetArray) + .Func(_SC("SetTable"), &Statement::SetTable) + .Func(_SC("Field"), &Statement::GetColumn) + .Func(_SC("Column"), &Statement::GetColumn) + .Func(_SC("GetValue"), &Statement::GetValue) + .Func(_SC("GetNumber"), &Statement::GetNumber) + .Func(_SC("GetInteger"), &Statement::GetInteger) + .Func(_SC("GetFloat"), &Statement::GetFloat) + .Func(_SC("GetLong"), &Statement::GetLong) + .Func(_SC("GetString"), &Statement::GetString) + .Func(_SC("GetBoolean"), &Statement::GetBoolean) + .Func(_SC("GetChar"), &Statement::GetChar) + .Func(_SC("GetBuffer"), &Statement::GetBuffer) + .Func(_SC("GetBlob"), &Statement::GetBlob) + // Member overloads + .Overload< Array (Statement::*)(void) const >(_SC("GetArray"), &Statement::GetArray) + .Overload< Array (Statement::*)(Int32) const >(_SC("GetArray"), &Statement::GetArray) + .Overload< Array (Statement::*)(Int32, Int32) const >(_SC("GetArray"), &Statement::GetArray) + .Overload< Table (Statement::*)(void) const >(_SC("GetTable"), &Statement::GetTable) + .Overload< Table (Statement::*)(Int32) const >(_SC("GetTable"), &Statement::GetTable) + .Overload< Table (Statement::*)(Int32, Int32) const >(_SC("GetTable"), &Statement::GetTable) + ); + + sqlns.Bind(_SC("Transaction"), + Class< Transaction, NoCopy< Transaction > >(sqlns.GetVM(), SQLiteTransactionTypename::Str) + // Constructors + .Ctor< const Connection & >() + // Meta-methods + .SquirrelFunc(_SC("_typename"), &SQLiteTransactionTypename::Fn) + .Func(_SC("_tostring"), &Transaction::ToString) + // Properties + .Prop(_SC("IsValid"), &Transaction::IsValid) + .Prop(_SC("Committed"), &Transaction::Commited) + // Member Methods + .Func(_SC("Commit"), &Transaction::Commit) + ); RootTable(vm).Bind(_SC("SQLite"), sqlns); } diff --git a/module/Library/SQLite.hpp b/module/Library/SQLite.hpp index 09f68b1f..60bb4402 100644 --- a/module/Library/SQLite.hpp +++ b/module/Library/SQLite.hpp @@ -3,9 +3,2518 @@ // ------------------------------------------------------------------------------------------------ #include "Base/Shared.hpp" +// ------------------------------------------------------------------------------------------------ +#include "Library/Numeric/LongInt.hpp" +#include "Library/Utils/Buffer.hpp" +#include "Library/Chrono/Date.hpp" +#include "Library/Chrono/Datetime.hpp" +#include "Library/Chrono/Time.hpp" +#include "Library/Chrono/Timestamp.hpp" + +// ------------------------------------------------------------------------------------------------ +#include +#include + +// ------------------------------------------------------------------------------------------------ +#include + // ------------------------------------------------------------------------------------------------ namespace SqMod { +/* ------------------------------------------------------------------------------------------------ + * Forward declarations. +*/ +class Connection; +class Statement; +class Column; +class Transaction; +/* ------------------------------------------------------------------------------------------------ + * Handle validation. +*/ +#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) + #define SQMOD_THROW_CURRENT(x, a) (x).ThrowCurrent(a, __FILE__, __LINE__) + #define SQMOD_VALIDATE(x) (x).Validate(__FILE__, __LINE__) + #define SQMOD_VALIDATE_CREATED(x) (x).ValidateCreated(__FILE__, __LINE__) + #define SQMOD_VALIDATE_PARAM(x, i) (x).ValidateParam((i), __FILE__, __LINE__) + #define SQMOD_VALIDATE_COLUMN(x, i) (x).ValidateColumn((i), __FILE__, __LINE__) + #define SQMOD_VALIDATE_ROW(x) (x).ValidateRow(__FILE__, __LINE__) + #define SQMOD_GET_VALID(x) (x).GetValid(__FILE__, __LINE__) + #define SQMOD_GET_CREATED(x) (x).GetCreated(__FILE__, __LINE__) +#else + #define SQMOD_THROW_CURRENT(x, a) (x).ThrowCurrent(a) + #define SQMOD_VALIDATE(x) (x).Validate() + #define SQMOD_VALIDATE_CREATED(x) (x).ValidateCreated() + #define SQMOD_VALIDATE_PARAM(x, i) (x).ValidateParam((i)) + #define SQMOD_VALIDATE_COLUMN(x, i) (x).ValidateColumn((i)) + #define SQMOD_VALIDATE_ROW(x) (x).ValidateRow() + #define SQMOD_GET_VALID(x) (x).GetValid() + #define SQMOD_GET_CREATED(x) (x).GetCreated() +#endif // _DEBUG + +/* ------------------------------------------------------------------------------------------------ + * Helper macros for architecture differences. +*/ + +#ifdef _SQ64 + #define sqlite3_bind_integer sqlite3_bind_int64 + #define sqlite3_column_integer sqlite3_column_int64 +#else + #define sqlite3_bind_integer sqlite3_bind_int + #define sqlite3_column_integer sqlite3_column_int +#endif + +/* ------------------------------------------------------------------------------------------------ + * Forward declarations. +*/ +struct ConnHnd; +struct StmtHnd; + +/* ------------------------------------------------------------------------------------------------ + * Common typedefs. +*/ +typedef SharedPtr< ConnHnd > ConnRef; +typedef SharedPtr< StmtHnd > StmtRef; + +/* ------------------------------------------------------------------------------------------------ + * Obtain a script object from a connection handle. (meant to avoid having to include the header) +*/ +Object GetConnectionObj(const ConnRef & conn); + +/* ------------------------------------------------------------------------------------------------ + * Obtain a script object from a statement handle. (meant to avoid having to include the header) +*/ +Object GetStatementObj(const StmtRef & stmt); + +/* ------------------------------------------------------------------------------------------------ + * Generate a formatted query. +*/ +CSStr QFmtStr(CSStr str, ...); + +/* ------------------------------------------------------------------------------------------------ + * Tests if a certain query string is empty. +*/ +bool IsQueryEmpty(CSStr str); + +/* ------------------------------------------------------------------------------------------------ + * Retrieve the string representation of a certain status code. +*/ +CSStr GetErrStr(Int32 status); + +/* ------------------------------------------------------------------------------------------------ + * Set a specific heap limit. +*/ +void SetSoftHeapLimit(Int32 limit); + +/* ------------------------------------------------------------------------------------------------ + * Release the specified amount of memory. +*/ +Int32 ReleaseMemory(Int32 bytes); + +/* ------------------------------------------------------------------------------------------------ + * Retrieve the current memory usage. +*/ +Object GetMemoryUsage(); + +/* ------------------------------------------------------------------------------------------------ + * Retrieve the memory high watermark. +*/ +Object GetMemoryHighwaterMark(bool reset); + +/* ------------------------------------------------------------------------------------------------ + * Retrieve the escaped version of the specified string. +*/ +CSStr EscapeString(StackStrF & str); + +/* ------------------------------------------------------------------------------------------------ + * Retrieve the escaped version of the specified string using the supplied format specifier. +*/ +CCStr EscapeStringEx(SQChar spec, StackStrF & str); + +/* ------------------------------------------------------------------------------------------------ + * Convert the values from the specified array to a list of column names string. +*/ +CCStr ArrayToQueryColumns(Array & arr); + +/* ------------------------------------------------------------------------------------------------ + * Convert the keys from the specified array to a list of column names string. +*/ +CCStr TableToQueryColumns(Table & tbl); + +/* ------------------------------------------------------------------------------------------------ + * The structure that holds the data associated with a certain connection. +*/ +struct ConnHnd +{ +public: + + // -------------------------------------------------------------------------------------------- + typedef sqlite3 Type; // The managed type. + + // -------------------------------------------------------------------------------------------- + typedef Type* Pointer; // Pointer to the managed type. + typedef const Type* ConstPtr; // Constant pointer to the managed type. + + // -------------------------------------------------------------------------------------------- + typedef Type& Reference; // Reference to the managed type. + typedef const Type& ConstRef; // Constant reference to the managed type. + + // -------------------------------------------------------------------------------------------- + typedef std::vector< String > QueryList; // Container used to queue queries. + +public: + + // -------------------------------------------------------------------------------------------- + Pointer mPtr; // The connection handle resource. + + // -------------------------------------------------------------------------------------------- + Int32 mStatus; // The last status code of this connection handle. + + // -------------------------------------------------------------------------------------------- + QueryList mQueue; // A queue of queries to be executed in groups. + + // -------------------------------------------------------------------------------------------- + Int32 mFlags; // The flags used to create the database connection handle. + String mName; // The specified name to be used as the database file. + String mVFS; // The specified virtual file system. + + // -------------------------------------------------------------------------------------------- + bool mMemory; // Whether the database exists in memory and not disk. + bool mTrace; // Whether tracing was activated on the database. + bool mProfile; // Whether profiling was activated on the database. + + /* -------------------------------------------------------------------------------------------- + * Default constructor. + */ + ConnHnd(); + + /* -------------------------------------------------------------------------------------------- + * Copy constructor. (disabled) + */ + ConnHnd(const ConnHnd & o) = delete; + + /* -------------------------------------------------------------------------------------------- + * Move constructor. (disabled) + */ + ConnHnd(ConnHnd && o) = delete; + + /* -------------------------------------------------------------------------------------------- + * Destructor. + */ + ~ConnHnd(); + + /* -------------------------------------------------------------------------------------------- + * Copy assignment operator. (disabled) + */ + ConnHnd & operator = (const ConnHnd & o) = delete; + + /* -------------------------------------------------------------------------------------------- + * Move assignment operator. (disabled) + */ + ConnHnd & operator = (ConnHnd && o) = delete; + + /* -------------------------------------------------------------------------------------------- + * Create the database connection resource. + */ + void Create(CSStr name, Int32 flags, CSStr vfs); + + /* -------------------------------------------------------------------------------------------- + * Execute a specific amount of queries from the queue. + */ + Int32 Flush(Uint32 num, Object & env, Function & func); + + /* -------------------------------------------------------------------------------------------- + * Retrieve the message of the last received error code. + */ + CCStr ErrStr() const + { + return sqlite3_errstr(sqlite3_errcode(mPtr)); + } + + /* -------------------------------------------------------------------------------------------- + * Return the last error message associated with this database connection. + */ + CCStr ErrMsg() const + { + return sqlite3_errmsg(mPtr); + } + + /* -------------------------------------------------------------------------------------------- + * Return the numeric result code for the most recent failed API call (if any). + */ + Int32 ErrNo() const + { + return sqlite3_errcode(mPtr); + } + + /* -------------------------------------------------------------------------------------------- + * Return the extended numeric result code for the most recent failed API call (if any). + */ + Int32 ExErrNo() const + { + return sqlite3_extended_errcode(mPtr); + } +}; + +/* ------------------------------------------------------------------------------------------------ + * The structure that holds the data associated with a certain statement. +*/ +struct StmtHnd +{ +public: + + // -------------------------------------------------------------------------------------------- + typedef sqlite3_stmt Type; // The managed type. + + // -------------------------------------------------------------------------------------------- + typedef Type* Pointer; // Pointer to the managed type. + typedef const Type* ConstPtr; // Constant pointer to the managed type. + + // -------------------------------------------------------------------------------------------- + typedef Type& Reference; // Reference to the managed type. + typedef const Type& ConstRef; // Constant reference to the managed type. + + // -------------------------------------------------------------------------------------------- + typedef std::map< String, int > Indexes; // Container used to identify column indexes. + +public: + + // -------------------------------------------------------------------------------------------- + Pointer mPtr; // The statement handle resource. + + // -------------------------------------------------------------------------------------------- + Int32 mStatus; // The last status code of this connection handle. + + // -------------------------------------------------------------------------------------------- + ConnRef mConn; // The handle to the associated database connection. + + // -------------------------------------------------------------------------------------------- + String mQuery; // The query string used to create this statement. + + // -------------------------------------------------------------------------------------------- + Int32 mColumns; // The amount of columns available in this statement. + Int32 mParameters; // The amount of parameters available in this statement. + Indexes mIndexes; // An associative container with column names and their index. + + // -------------------------------------------------------------------------------------------- + bool mGood; // True when a row has been fetched with step. + bool mDone; // True when the last step had no more rows to fetch. + + /* -------------------------------------------------------------------------------------------- + * Default constructor. + */ + StmtHnd(ConnRef conn); + + /* -------------------------------------------------------------------------------------------- + * Copy constructor. (disabled) + */ + StmtHnd(const StmtHnd & o) = delete; + + /* -------------------------------------------------------------------------------------------- + * Move constructor. (disabled) + */ + StmtHnd(StmtHnd && o) = delete; + + /* -------------------------------------------------------------------------------------------- + * Destructor. + */ + ~StmtHnd(); + + /* -------------------------------------------------------------------------------------------- + * Copy assignment operator. (disabled) + */ + StmtHnd & operator = (const StmtHnd & o) = delete; + + /* -------------------------------------------------------------------------------------------- + * Move assignment operator. (disabled) + */ + StmtHnd & operator = (StmtHnd && o) = delete; + + /* -------------------------------------------------------------------------------------------- + * Create the database statement resource. + */ + void Create(CSStr query, SQInteger length = -1); + + /* -------------------------------------------------------------------------------------------- + * Check whether a specific column index is in range. + */ + bool CheckColumn(Int32 idx) const + { + return (idx >= 0) && (idx < mColumns); + } + + /* -------------------------------------------------------------------------------------------- + * Check whether a specific parameter index is in range. + */ + bool CheckParameter(Int32 idx) const + { + return (idx >= 1) && (idx <= mParameters); + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve the column index associated with the specified name. + */ + Int32 GetColumnIndex(CSStr name, SQInteger length = -1); + + /* -------------------------------------------------------------------------------------------- + * Retrieve the message of the last received error code. + */ + CCStr ErrStr() const; + + /* -------------------------------------------------------------------------------------------- + * Return the last error message associated with this database connection. + */ + CCStr ErrMsg() const; + + /* -------------------------------------------------------------------------------------------- + * Return the numeric result code for the most recent failed API call (if any). + */ + Int32 ErrNo() const; + + /* -------------------------------------------------------------------------------------------- + * Return the extended numeric result code for the most recent failed API call (if any). + */ + Int32 ExErrNo() const; +}; + +/* ------------------------------------------------------------------------------------------------ + * Used to manage and interact with a database connection. +*/ +class Connection +{ +private: + + // -------------------------------------------------------------------------------------------- + ConnRef m_Handle; // Reference to the managed connection. + +protected: + + /* -------------------------------------------------------------------------------------------- + * Callback function for ActivateTracing() + */ + static void TraceOutput(void * ptr, CCStr sql); + + /* -------------------------------------------------------------------------------------------- + * Callback function for ActivateProfiling() + */ + static void ProfileOutput(void * ptr, CCStr sql, sqlite3_uint64 time); + + /* -------------------------------------------------------------------------------------------- + * Validate the managed connection handle and throw an error if invalid. + */ +#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) + void Validate(CCStr file, Int32 line) const; +#else + void Validate() const; +#endif // _DEBUG + + /* -------------------------------------------------------------------------------------------- + * Validate the managed connection handle and throw an error if invalid. + */ +#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) + void ValidateCreated(CCStr file, Int32 line) const; +#else + void ValidateCreated() const; +#endif // _DEBUG + + /* -------------------------------------------------------------------------------------------- + * Validate the managed connection handle and throw an error if invalid. + */ +#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) + const ConnRef & GetValid(CCStr file, Int32 line) const; +#else + const ConnRef & GetValid() const; +#endif // _DEBUG + + /* -------------------------------------------------------------------------------------------- + * Validate the managed connection handle and throw an error if invalid. + */ +#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) + const ConnRef & GetCreated(CCStr file, Int32 line) const; +#else + const ConnRef & GetCreated() const; +#endif // _DEBUG + +public: + + /* -------------------------------------------------------------------------------------------- + * Attempt to open the specified database. + */ + Connection() + : m_Handle() + { + /* ... */ + } + + /* -------------------------------------------------------------------------------------------- + * Explicit constructor. + */ + explicit Connection(StackStrF & name) + : m_Handle(new ConnHnd()) + { + // 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; + SQMOD_GET_VALID(*this)->Create(name.mPtr, OPEN_READWRITE_F | OPEN_CREATE_F, nullptr); + } + + /* -------------------------------------------------------------------------------------------- + * Explicit constructor. + */ + Connection(StackStrF & name, Int32 flags) + : m_Handle(new ConnHnd()) + { + SQMOD_GET_VALID(*this)->Create(name.mPtr, flags, nullptr); + } + + /* -------------------------------------------------------------------------------------------- + * Explicit constructor. + */ + Connection(StackStrF & name, Int32 flags, StackStrF & vfs) + : m_Handle(new ConnHnd()) + { + SQMOD_GET_VALID(*this)->Create(name.mPtr, flags, vfs.mPtr); + } + + /* -------------------------------------------------------------------------------------------- + * Direct handle constructor. + */ + explicit Connection(ConnRef c) + : m_Handle(std::move(c)) + { + /* ... */ + } + + /* -------------------------------------------------------------------------------------------- + * Copy constructor. + */ + Connection(const Connection & o) = default; + + /* -------------------------------------------------------------------------------------------- + * Move constructor. + */ + Connection(Connection && o) = default; + + /* -------------------------------------------------------------------------------------------- + * Copy assignment operator. + */ + Connection & operator = (const Connection & o) = default; + + /* -------------------------------------------------------------------------------------------- + * Move assignment operator. + */ + Connection & operator = (Connection && o) = default; + + /* -------------------------------------------------------------------------------------------- + * Perform an equality comparison between two connections. + */ + bool operator == (const Connection & o) const + { + return (m_Handle == o.m_Handle); + } + + /* -------------------------------------------------------------------------------------------- + * Perform an inequality comparison between two connections. + */ + bool operator != (const Connection & o) const + { + return (m_Handle != o.m_Handle); + } + + /* -------------------------------------------------------------------------------------------- + * Implicit conversion to the raw connection handle. + */ + operator sqlite3 * () //NOLINT (intentionally implicit) + { + return m_Handle ? m_Handle->mPtr : nullptr; + } + + /* -------------------------------------------------------------------------------------------- + * Implicit conversion to the raw connection handle. + */ + operator sqlite3 * () const //NOLINT (intentionally implicit) + { + return m_Handle ? m_Handle->mPtr : nullptr; + } + + /* -------------------------------------------------------------------------------------------- + * Used by the script engine to convert an instance of this type to a string. + */ + const String & ToString() const + { + return m_Handle ? m_Handle->mName : NullString(); + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve the associated connection handle. + */ + const ConnRef & GetHandle() const + { + return m_Handle; + } + + /* -------------------------------------------------------------------------------------------- + * See whether the managed connection handle is valid. + */ + bool IsValid() const + { + return m_Handle; + } + + /* -------------------------------------------------------------------------------------------- + * See whether the managed connection handle was connected. + */ + bool IsConnected() const + { + return m_Handle && (m_Handle->mPtr != nullptr); + } + + /* -------------------------------------------------------------------------------------------- + * Return the number of active references to this connection handle. + */ + Uint32 GetRefCount() const + { + return m_Handle.Count(); + } + + /* -------------------------------------------------------------------------------------------- + * Release the reference to the associated database connection. + */ + void Release() + { + m_Handle.Reset(); + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve the last received status code. + */ + Int32 GetStatus() const + { + return SQMOD_GET_VALID(*this)->mStatus; + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve the flags used to create this database connection. + */ + Int32 GetFlags() const + { + return SQMOD_GET_VALID(*this)->mFlags; + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve the name used to create this database connection. + */ + const String & GetName() const + { + return SQMOD_GET_VALID(*this)->mName; + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve the virtual file system used to create this database connection. + */ + const String & GetVFS() const + { + return SQMOD_GET_VALID(*this)->mVFS; + } + + /* -------------------------------------------------------------------------------------------- + * Return the numeric result code for the most recent failed API call (if any). + */ + Int32 GetErrorCode() const + { + return SQMOD_GET_VALID(*this)->ErrNo(); + } + + /* -------------------------------------------------------------------------------------------- + * Return the extended numeric result code for the most recent failed API call (if any). + */ + Int32 GetExtendedErrorCode() const + { + return SQMOD_GET_VALID(*this)->ExErrNo(); + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve the message of the last received error code. + */ + CSStr GetErrStr() const + { + return SQMOD_GET_VALID(*this)->ErrStr(); + } + + /* -------------------------------------------------------------------------------------------- + * Return the last error message associated with this database connection. + */ + CSStr GetErrMsg() const + { + return SQMOD_GET_VALID(*this)->ErrMsg(); + } + + /* -------------------------------------------------------------------------------------------- + * Attempt to open the specified database. + */ + void Open(StackStrF & name); + + /* -------------------------------------------------------------------------------------------- + * Attempt to open the specified database. + */ + void Open(StackStrF & name, Int32 flags); + + /* -------------------------------------------------------------------------------------------- + * Attempt to open the specified database. + */ + void Open(StackStrF & name, Int32 flags, StackStrF & vfs); + + /* -------------------------------------------------------------------------------------------- + * Attempt to execute the specified query. + */ + Int32 Exec(StackStrF & str); + + /* -------------------------------------------------------------------------------------------- + * Attempt to queue the specified query. + */ + void Queue(StackStrF & str); + + /* -------------------------------------------------------------------------------------------- + * Attempt to create a statement from the specified query. + */ + Object Query(StackStrF & str) const; + + /* -------------------------------------------------------------------------------------------- + * See if the database connection was opened in read-only mode. + */ + bool IsReadOnly() const; + + /* -------------------------------------------------------------------------------------------- + * Shortcut to test if a table exists. + */ + bool TableExists(StackStrF & name) const; + + /* -------------------------------------------------------------------------------------------- + * See if the database connection is or is not in auto-commit mode. + */ + bool GetAutoCommit() const + { + return sqlite3_get_autocommit(SQMOD_GET_CREATED(*this)->mPtr); + } + + /* -------------------------------------------------------------------------------------------- + * Get the row-id of the most recent successful INSERT into the database from the current connection. + */ + Object GetLastInsertRowID() const + { + return Object(new SLongInt(sqlite3_last_insert_rowid(SQMOD_GET_CREATED(*this)->mPtr))); + } + + /* -------------------------------------------------------------------------------------------- + * Returns the number of database rows that were changed, inserted or deleted + * by the most recently completed SQL statement. + */ + Int32 GetChanges() const + { + return sqlite3_changes(SQMOD_GET_CREATED(*this)->mPtr); + } + + /* -------------------------------------------------------------------------------------------- + * Returns the total number of row changes caused by INSERT, UPDATE or DELETE statements + * since the database connection was opened. + */ + Int32 GetTotalChanges() const + { + return sqlite3_total_changes(SQMOD_GET_CREATED(*this)->mPtr); + } + + /* -------------------------------------------------------------------------------------------- + * See if this database connection has tracing enabled. + */ + bool GetTracing() const + { + return SQMOD_GET_VALID(*this)->mTrace; + } + + /* -------------------------------------------------------------------------------------------- + * Activate or deactivate tracing on this database connection. + */ + void SetTracing(bool toggle); + + /* -------------------------------------------------------------------------------------------- + * See if this database connection has profiling enabled. + */ + bool GetProfiling() const + { + return SQMOD_GET_VALID(*this)->mProfile; + } + + /* -------------------------------------------------------------------------------------------- + * Activate or deactivate profiling on this database connection. + */ + void SetProfiling(bool toggle); + + /* -------------------------------------------------------------------------------------------- + * Set a busy handler that sleeps for a specified amount of time when a table is locked. + */ + void SetBusyTimeout(Int32 millis); + + /* -------------------------------------------------------------------------------------------- + * Causes any pending database operation to abort and return at its earliest opportunity. + */ + void InterruptOperation() const + { + sqlite3_interrupt(SQMOD_GET_CREATED(*this)->mPtr); + } + + /* -------------------------------------------------------------------------------------------- + * Attempts to free as much heap memory as possible from the database connection. + */ + void ReleaseMemory() const + { + sqlite3_db_release_memory(SQMOD_GET_CREATED(*this)->mPtr); + } + + /* -------------------------------------------------------------------------------------------- + * Returns internal runtime status information associated with the current database connection. + */ + Int32 GetInfo(Int32 operation) + { + return GetInfo(operation, false, false); + } + + /* -------------------------------------------------------------------------------------------- + * Returns internal runtime status information associated with the current database connection. + */ + Int32 GetInfo(Int32 operation, bool highwater) + { + return GetInfo(operation, highwater, false); + } + + /* -------------------------------------------------------------------------------------------- + * Returns internal runtime status information associated with the current database connection. + */ + Int32 GetInfo(Int32 operation, bool highwater, bool reset); + + /* -------------------------------------------------------------------------------------------- + * Retrieve the number of queries in the queue. + */ + Uint32 QueueSize() const + { + return ConvTo< Uint32 >::From(SQMOD_GET_VALID(*this)->mQueue.size()); + } + + /* -------------------------------------------------------------------------------------------- + * Reserve space upfront for the specified amount of queries in the query queue. + */ + void ReserveQueue(Uint32 num); + + /* -------------------------------------------------------------------------------------------- + * Release memory that is not occupied from the query queue. + */ + void CompactQueue() + { + SQMOD_GET_VALID(*this)->mQueue.shrink_to_fit(); + } + + /* -------------------------------------------------------------------------------------------- + * Remove all queries from the queue without executing them. + */ + void ClearQueue() + { + SQMOD_GET_VALID(*this)->mQueue.clear(); + } + + /* -------------------------------------------------------------------------------------------- + * Remove the last query from the queue. + */ + void PopQueue(); + + /* -------------------------------------------------------------------------------------------- + * Flush all queries from the queue. + */ + Int32 Flush(); + + /* -------------------------------------------------------------------------------------------- + * Flush a specific amount of queries from the queue. + */ + Int32 Flush(SQInteger num); + + /* -------------------------------------------------------------------------------------------- + * Flush all queries from the queue and handle errors manually. + */ + Int32 Flush(Object & env, Function & func); + + /* -------------------------------------------------------------------------------------------- + * Flush a specific amount of queries from the queue and handle errors manually. + */ + Int32 Flush(SQInteger num, Object & env, Function & func); +}; + +/* ------------------------------------------------------------------------------------------------ + * Used to manage and interact with parameters from a database statement. +*/ +class Parameter +{ + // -------------------------------------------------------------------------------------------- + friend class Statement; + +private: + + // -------------------------------------------------------------------------------------------- + Int32 m_Index; // The index of the managed parameter. + StmtRef m_Handle; // Reference to the managed statement. + +protected: + + /* -------------------------------------------------------------------------------------------- + * Validate the managed statement handle and throw an error if invalid. + */ +#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) + void Validate(CCStr file, Int32 line) const; +#else + void Validate() const; +#endif // _DEBUG + + /* -------------------------------------------------------------------------------------------- + * Validate the managed statement handle and throw an error if invalid. + */ +#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) + void ValidateCreated(CCStr file, Int32 line) const; +#else + void ValidateCreated() const; +#endif // _DEBUG + + /* -------------------------------------------------------------------------------------------- + * Validate the managed statement handle and throw an error if invalid. + */ +#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) + const StmtRef & GetValid(CCStr file, Int32 line) const; +#else + const StmtRef & GetValid() const; +#endif // _DEBUG + + /* -------------------------------------------------------------------------------------------- + * Validate the managed statement handle and throw an error if invalid. + */ +#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) + const StmtRef & GetCreated(CCStr file, Int32 line) const; +#else + const StmtRef & GetCreated() const; +#endif // _DEBUG + + /* -------------------------------------------------------------------------------------------- + * Validate the statement reference and parameter index, and throw an error if they're invalid. + */ +#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) + void ValidateParam(Int32 idx, CCStr file, Int32 line) const; +#else + void ValidateParam(Int32 idx) const; +#endif // _DEBUG + + /* -------------------------------------------------------------------------------------------- + * Modify the index to the specified value. + */ + void SetIndex(Int32 idx) + { + // Assign the index with a failsafe to invalid on error + AutoAssign< Int32 > aa(m_Index, -1, idx); + // Validate the obtained parameter index + SQMOD_VALIDATE_PARAM(*this, idx); + // Don't fall back to the invalid index anymore + aa.Set(idx); + } + + /* -------------------------------------------------------------------------------------------- + * Modify the index to the specified value. + */ + void SetIndex(CSStr name) + { + SetIndex(sqlite3_bind_parameter_index(SQMOD_GET_CREATED(*this)->mPtr, name)); + } + + /* -------------------------------------------------------------------------------------------- + * Modify the index to the specified value. + */ + void SetIndex(const Object & param); + +public: + + /* -------------------------------------------------------------------------------------------- + * Default constructor (null). + */ + Parameter() + : m_Index(0), m_Handle() + { + /* ... */ + } + + /* -------------------------------------------------------------------------------------------- + * No parameter constructor. + */ + Parameter(const StmtRef & stmt) + : m_Index(0), m_Handle(stmt) + { + /* ... */ + } + + /* -------------------------------------------------------------------------------------------- + * Index constructor. + */ + Parameter(const StmtRef & stmt, Int32 idx) + : m_Index(idx), m_Handle(stmt) + { + SQMOD_VALIDATE_PARAM(*this, m_Index); + } + + /* -------------------------------------------------------------------------------------------- + * Name constructor. + */ + Parameter(const StmtRef & stmt, CSStr name) + : m_Index(stmt ? sqlite3_bind_parameter_index(stmt->mPtr, name) : 0), m_Handle(stmt) + { + SQMOD_VALIDATE_PARAM(*this, m_Index); + } + + /* -------------------------------------------------------------------------------------------- + * Dynamic constructor. + */ + Parameter(const StmtRef & stmt, const Object & param) + : m_Index(0), m_Handle(stmt) + { + if (!m_Handle) + { + STHROWF("Invalid SQLite statement reference"); + } + // Extract the index + SetIndex(param); + } + + /* -------------------------------------------------------------------------------------------- + * Copy constructor. + */ + Parameter(const Parameter & o) = default; + + /* -------------------------------------------------------------------------------------------- + * Move constructor. + */ + Parameter(Parameter && o) = default; + + /* -------------------------------------------------------------------------------------------- + * Copy assignment operator. + */ + Parameter & operator = (const Parameter & o) = default; + + /* -------------------------------------------------------------------------------------------- + * Move assignment operator. + */ + Parameter & operator = (Parameter && o) = default; + + /* -------------------------------------------------------------------------------------------- + * Perform an equality comparison between two parameter indexes. + */ + bool operator == (const Parameter & o) const + { + return (m_Index == o.m_Index); + } + + /* -------------------------------------------------------------------------------------------- + * Perform an inequality comparison between two parameter indexes. + */ + bool operator != (const Parameter & o) const + { + return (m_Index != o.m_Index); + } + + /* -------------------------------------------------------------------------------------------- + * Implicit conversion to boolean for use in boolean operations. + */ + operator bool () const + { + return m_Index >= 0; + } + + /* -------------------------------------------------------------------------------------------- + * Used by the script engine to convert an instance of this type to a string. + */ + CSStr ToString() const + { + CSStr val = nullptr; + // Can we attempt to return the parameter name? + if (m_Handle && m_Index) + { + val = sqlite3_bind_parameter_name(m_Handle->mPtr, m_Index); + } + else + { + val = ToStrF(_SC("%d"), m_Index); + } + // Return the value if valid + return val ? val : _SC(""); + } + + /* -------------------------------------------------------------------------------------------- + * See whether this statement is valid. + */ + bool IsValid() const + { + return m_Handle; // An invalid statement means an invalid parameter + } + + /* -------------------------------------------------------------------------------------------- + * Return the number of active references to this statement handle. + */ + Uint32 GetRefCount() const + { + return m_Handle.Count(); + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve the associated parameter index. + */ + Int32 GetIndex() const + { + return m_Index; + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve the associated database statement. + */ + Object GetStatement() const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the associated database connection. + */ + Object GetConnection() const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the name of the referenced parameter. + */ + CSStr GetName() const + { + return sqlite3_bind_parameter_name(SQMOD_GET_CREATED(*this)->mPtr, m_Index); + } + + /* -------------------------------------------------------------------------------------------- + * Release the reference to the associated database statement and parameter index. + */ + void Release() + { + m_Handle.Reset(); + m_Index = 0; + } + + /* -------------------------------------------------------------------------------------------- + * Attempt to bind a dynamic value at the referenced parameter index. + */ + void SetValue(const Object & value); + + /* -------------------------------------------------------------------------------------------- + * Attempt to bind a boolean value at the referenced parameter index. + */ + void SetBool(bool value); + + /* -------------------------------------------------------------------------------------------- + * Attempt to bind a character value at the referenced parameter index. + */ + void SetChar(SQInteger value); + + /* -------------------------------------------------------------------------------------------- + * Attempt to bind a native integer value at the referenced parameter index. + */ + void SetInteger(SQInteger value); + + /* -------------------------------------------------------------------------------------------- + * Attempt to bind a signed 8 bit integer value at the referenced parameter index. + */ + void SetInt8(SQInteger value); + + /* -------------------------------------------------------------------------------------------- + * Attempt to bind an unsigned 8 bit integer value at the referenced parameter index. + */ + void SetUint8(SQInteger value); + + /* -------------------------------------------------------------------------------------------- + * Attempt to bind a signed 16 bit integer value at the referenced parameter index. + */ + void SetInt16(SQInteger value); + + /* -------------------------------------------------------------------------------------------- + * Attempt to bind an unsigned 16 bit integer value at the referenced parameter index. + */ + void SetUint16(SQInteger value); + + /* -------------------------------------------------------------------------------------------- + * Attempt to bind a signed 32 bit integer value at the referenced parameter index. + */ + void SetInt32(SQInteger value); + + /* -------------------------------------------------------------------------------------------- + * Attempt to bind an unsigned 32 bit integer value at the referenced parameter index. + */ + void SetUint32(SQInteger value); + + /* -------------------------------------------------------------------------------------------- + * Attempt to bind a signed 64 bit integer value at the referenced parameter index. + */ + void SetInt64(const Object & value); + + /* -------------------------------------------------------------------------------------------- + * Attempt to bind an unsigned 64 bit integer value at the referenced parameter index. + */ + void SetUint64(const Object & value); + + /* -------------------------------------------------------------------------------------------- + * Attempt to bind a native floating point value at the referenced parameter index. + */ + void SetFloat(SQFloat value); + + /* -------------------------------------------------------------------------------------------- + * Attempt to bind a 32 bit floating point value at the referenced parameter index. + */ + void SetFloat32(SQFloat value); + + /* -------------------------------------------------------------------------------------------- + * Attempt to bind a 64 bit floating point value at the referenced parameter index. + */ + void SetFloat64(SQFloat value); + + /* -------------------------------------------------------------------------------------------- + * Attempt to bind a string value at the referenced parameter index. + */ + void SetString(StackStrF & value); + + /* -------------------------------------------------------------------------------------------- + * Attempt to bind a string value at the referenced parameter index. + */ + void SetStringRaw(CSStr value, SQInteger length = -1); + + /* -------------------------------------------------------------------------------------------- + * Attempt to bind a zeroed blob value at the referenced parameter index. + */ + void SetZeroBlob(SQInteger size); + + /* -------------------------------------------------------------------------------------------- + * Attempt to bind a blob value at the referenced parameter index. + */ + void SetBlob(const Object & value); + + /* -------------------------------------------------------------------------------------------- + * Attempt to bind a buffer value at the referenced parameter index. + */ + void SetData(const SqBuffer & value); + + /* -------------------------------------------------------------------------------------------- + * Attempt to bind a buffer value at the referenced parameter index. + */ + void SetDataEx(const SqBuffer & value, SQInteger offset, SQInteger length); + + /* -------------------------------------------------------------------------------------------- + * Attempt to bind a date value at the referenced parameter index. + */ + void SetDate(const Date & value); + + /* -------------------------------------------------------------------------------------------- + * Attempt to bind a date value at the referenced parameter index. + */ + void SetDateEx(SQInteger year, SQInteger month, SQInteger day); + + /* -------------------------------------------------------------------------------------------- + * Attempt to bind a time value at the referenced parameter index. + */ + void SetTime(const Time & value); + + /* -------------------------------------------------------------------------------------------- + * Attempt to bind a time value at the referenced parameter index. + */ + void SetTimeEx(SQInteger hour, SQInteger minute, SQInteger second); + + /* -------------------------------------------------------------------------------------------- + * Attempt to bind a date-time value at the referenced parameter index. + */ + void SetDatetime(const Datetime & value); + + /* -------------------------------------------------------------------------------------------- + * Attempt to bind a date-time value at the referenced parameter index. + */ + void SetDatetimeEx(SQInteger year, SQInteger month, SQInteger day, SQInteger hour, SQInteger minute, SQInteger second); + + /* -------------------------------------------------------------------------------------------- + * Attempt to bind the current timestamp at the referenced parameter index. + */ + void SetNow(); + + /* -------------------------------------------------------------------------------------------- + * Attempt to bind a null value at the referenced parameter index. + */ + void SetNull(); +}; + +/* ------------------------------------------------------------------------------------------------ + * Used to manage and interact with statement columns. +*/ +class Column +{ + // -------------------------------------------------------------------------------------------- + friend class Statement; + +private: + + // -------------------------------------------------------------------------------------------- + Int32 m_Index; // The index of the managed column. + StmtRef m_Handle; // The statement where the column exist. + +protected: + + /* -------------------------------------------------------------------------------------------- + * Validate the managed statement handle and throw an error if invalid. + */ +#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) + void Validate(CCStr file, Int32 line) const; +#else + void Validate() const; +#endif // _DEBUG + + /* -------------------------------------------------------------------------------------------- + * Validate the managed statement handle and throw an error if invalid. + */ +#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) + void ValidateCreated(CCStr file, Int32 line) const; +#else + void ValidateCreated() const; +#endif // _DEBUG + + /* -------------------------------------------------------------------------------------------- + * Validate the managed statement handle and throw an error if invalid. + */ +#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) + const StmtRef & GetValid(CCStr file, Int32 line) const; +#else + const StmtRef & GetValid() const; +#endif // _DEBUG + + /* -------------------------------------------------------------------------------------------- + * Validate the managed statement handle and throw an error if invalid. + */ +#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) + const StmtRef & GetCreated(CCStr file, Int32 line) const; +#else + const StmtRef & GetCreated() const; +#endif // _DEBUG + + /* -------------------------------------------------------------------------------------------- + * Validate the statement reference and column index, and throw an error if they're invalid. + */ +#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) + void ValidateColumn(Int32 idx, CCStr file, Int32 line) const; +#else + void ValidateColumn(Int32 idx) const; +#endif // _DEBUG + + /* -------------------------------------------------------------------------------------------- + * Validate the statement reference and row, and throw an error if they're invalid. + */ +#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) + void ValidateRow(CCStr file, Int32 line) const; +#else + void ValidateRow() const; +#endif // _DEBUG + + /* -------------------------------------------------------------------------------------------- + * Modify the index to the specified value. + */ + void SetIndex(Int32 idx) + { + // Assign the index with a failsafe to invalid on error + AutoAssign< Int32 > 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); + } + + /* -------------------------------------------------------------------------------------------- + * Modify the index to the specified value. + */ + void SetIndex(CSStr name) + { + SetIndex(SQMOD_GET_CREATED(*this)->GetColumnIndex(name)); + } + + /* -------------------------------------------------------------------------------------------- + * Modify the index to the specified value. + */ + void SetIndex(const Object & column); + +public: + + /* -------------------------------------------------------------------------------------------- + * Default constructor (null). + */ + Column() + : m_Index(-1), m_Handle() + { + /* ... */ + } + + /* -------------------------------------------------------------------------------------------- + * No column constructor. + */ + Column(const StmtRef & stmt) + : m_Index(-1), m_Handle(stmt) + { + /* ... */ + } + + /* -------------------------------------------------------------------------------------------- + * Index constructor. + */ + Column(const StmtRef & stmt, Int32 idx) + : m_Index(idx), m_Handle(stmt) + { + SQMOD_VALIDATE_COLUMN(*this, m_Index); + } + + /* -------------------------------------------------------------------------------------------- + * Name constructor. + */ + Column(const StmtRef & stmt, CSStr name) + : m_Index(stmt ? stmt->GetColumnIndex(name) : -1), m_Handle(stmt) + { + SQMOD_VALIDATE_COLUMN(*this, m_Index); + } + + /* -------------------------------------------------------------------------------------------- + * Dynamic constructor. + */ + Column(const StmtRef & stmt, const Object & column) + : m_Index(-1), m_Handle(stmt) + { + if (!m_Handle) + { + STHROWF("Invalid SQLite statement reference"); + } + // Extract the index + SetIndex(column); + } + + /* -------------------------------------------------------------------------------------------- + * Copy constructor. + */ + Column(const Column & o) = default; + + /* -------------------------------------------------------------------------------------------- + * Move constructor. + */ + Column(Column && o) = default; + + /* -------------------------------------------------------------------------------------------- + * Copy assignment operator. + */ + Column & operator = (const Column & o) = default; + + /* -------------------------------------------------------------------------------------------- + * Move assignment operator. + */ + Column & operator = (Column && o) = default; + + /* -------------------------------------------------------------------------------------------- + * Perform an equality comparison between two table column indexes. + */ + bool operator == (const Column & o) const + { + return (m_Index == o.m_Index); + } + + /* -------------------------------------------------------------------------------------------- + * Perform an inequality comparison between two table column indexes. + */ + bool operator != (const Column & o) const + { + return (m_Index != o.m_Index); + } + + /* -------------------------------------------------------------------------------------------- + * Implicit conversion to boolean for use in boolean operations. + */ + operator bool () const + { + return m_Index >= 0; + } + + /* -------------------------------------------------------------------------------------------- + * Used by the script engine to convert an instance of this type to a string. + */ + CSStr ToString() const + { + CSStr val = nullptr; + // Can we attempt to return the parameter name? + if (m_Handle && m_Index) + { + val = sqlite3_column_name(m_Handle->mPtr, m_Index); + } + else + { + val = ToStrF(_SC("%d"), m_Index); + } + // Return the value if valid + return val ? val : _SC(""); + } + + /* -------------------------------------------------------------------------------------------- + * See whether the column is valid. + */ + bool IsValid() const + { + return m_Handle; // An invalid statement means an invalid column + } + + /* -------------------------------------------------------------------------------------------- + * Return the number of active references to the associated statement handle. + */ + Uint32 GetRefCount() const + { + return m_Handle.Count(); + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve the referenced column index. + */ + Int32 GetIndex() const + { + return m_Index; + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve the referenced database statement. + */ + Object GetStatement() const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the referenced database connection. + */ + Object GetConnection() const; + + /* -------------------------------------------------------------------------------------------- + * Release the reference to the referenced database statement and column index. + */ + void Release() + { + m_Handle.Reset(); + m_Index = -1; + } + + /* -------------------------------------------------------------------------------------------- + * Check whether the referenced column is null. + */ + bool IsNull() const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the name of the referenced column index. + */ + CSStr GetName() const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the column origin name if the library was compiled with such feature. + */ + CSStr GetOriginName() const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the type identifier of the referenced column index. + */ + Int32 GetType() const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the size in bytes of the referenced column index. + */ + Int32 GetBytes() const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the value inside the referenced column as a dynamic type. + */ + Object GetValue() const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the value inside the referenced column as a numeric type. + */ + Object GetNumber() const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the value inside the referenced column as a native script integer. + */ + SQInteger GetInteger() const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the value inside the referenced column as a native script floating point. + */ + SQFloat GetFloat() const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the value inside the referenced column as a long integer. + */ + Object GetLong() const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the value inside the referenced column as a string. + */ + Object GetString() const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the value inside the referenced column as a boolean. + */ + bool GetBoolean() const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the value inside the referenced column as a character. + */ + SQChar GetChar() const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the value inside the referenced column as a memory buffer. + */ + Object GetBuffer() const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the value inside the referenced column as a memory blob. + */ + Object GetBlob() const; +}; + +/* ------------------------------------------------------------------------------------------------ + * Used to manage and interact a database statement. +*/ +class Statement +{ +private: + + // -------------------------------------------------------------------------------------------- + StmtRef m_Handle; // Reference to the managed statement. + +protected: + + /* -------------------------------------------------------------------------------------------- + * Validate the managed statement handle and throw an error if invalid. + */ +#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) + void Validate(CCStr file, Int32 line) const; +#else + void Validate() const; +#endif // _DEBUG + + /* -------------------------------------------------------------------------------------------- + * Validate the managed statement handle and throw an error if invalid. + */ +#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) + void ValidateCreated(CCStr file, Int32 line) const; +#else + void ValidateCreated() const; +#endif // _DEBUG + + /* -------------------------------------------------------------------------------------------- + * Validate the managed statement handle and throw an error if invalid. + */ +#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) + const StmtRef & GetValid(CCStr file, Int32 line) const; +#else + const StmtRef & GetValid() const; +#endif // _DEBUG + + /* -------------------------------------------------------------------------------------------- + * Validate the managed statement handle and throw an error if invalid. + */ +#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) + const StmtRef & GetCreated(CCStr file, Int32 line) const; +#else + const StmtRef & GetCreated() const; +#endif // _DEBUG + + /* -------------------------------------------------------------------------------------------- + * Validate the statement reference and column index, and throw an error if they're invalid. + */ +#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) + void ValidateColumn(Int32 idx, CCStr file, Int32 line) const; +#else + void ValidateColumn(Int32 idx) const; +#endif // _DEBUG + + /* -------------------------------------------------------------------------------------------- + * Validate the statement reference and parameter index, and throw an error if they're invalid. + */ +#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) + void ValidateParam(Int32 idx, CCStr file, Int32 line) const; +#else + void ValidateParam(Int32 idx) const; +#endif // _DEBUG + + /* -------------------------------------------------------------------------------------------- + * Validate the statement reference and row, and throw an error if they're invalid. + */ +#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) + void ValidateRow(CCStr file, Int32 line) const; +#else + void ValidateRow() const; +#endif // _DEBUG + +public: + + /* -------------------------------------------------------------------------------------------- + * Default constructor. + */ + Statement() + : m_Handle() + { + /* ... */ + } + + /* -------------------------------------------------------------------------------------------- + * Construct a statement under the specified connection using the specified string. + */ + Statement(const ConnRef & connection, StackStrF & query) + : m_Handle(new StmtHnd(connection)) + { + SQMOD_GET_VALID(*this)->Create(query.mPtr, query.mLen); + } + + /* -------------------------------------------------------------------------------------------- + * Construct a statement under the specified connection using the specified string. + */ + Statement(const Connection & connection, StackStrF & query); + + /* -------------------------------------------------------------------------------------------- + * Direct handle constructor. + */ + Statement(const StmtRef & s) + : m_Handle(s) + { + /* ... */ + } + + /* -------------------------------------------------------------------------------------------- + * Copy constructor. + */ + Statement(const Statement & o) = default; + + /* -------------------------------------------------------------------------------------------- + * Move constructor. + */ + Statement(Statement && o) = default; + + /* -------------------------------------------------------------------------------------------- + * Copy assignment operator. + */ + Statement & operator = (const Statement & o) = default; + + /* -------------------------------------------------------------------------------------------- + * Move assignment operator. + */ + Statement & operator = (Statement && o) = default; + + /* -------------------------------------------------------------------------------------------- + * Perform an equality comparison between two connections. + */ + bool operator == (const Statement & o) const + { + return (m_Handle.Get() == o.m_Handle.Get()); + } + + /* -------------------------------------------------------------------------------------------- + * Perform an inequality comparison between two connections. + */ + bool operator != (const Statement & o) const + { + return (m_Handle.Get() != o.m_Handle.Get()); + } + + /* -------------------------------------------------------------------------------------------- + * Implicit conversion to the raw connection handle. + */ + operator sqlite3_stmt * () + { + return m_Handle ? m_Handle->mPtr : nullptr; + } + + /* -------------------------------------------------------------------------------------------- + * Implicit conversion to the raw connection handle. + */ + operator sqlite3_stmt * () const + { + return m_Handle ? m_Handle->mPtr : nullptr; + } + + /* -------------------------------------------------------------------------------------------- + * Used by the script engine to convert an instance of this type to a string. + */ + const String & ToString() const + { + return m_Handle ? m_Handle->mQuery : NullString(); + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve the associated statement handle. + */ + const StmtRef & GetHandle() const + { + return m_Handle; + } + + /* -------------------------------------------------------------------------------------------- + * See whether the managed handle is valid. + */ + bool IsValid() const + { + return m_Handle; + } + + /* -------------------------------------------------------------------------------------------- + * See whether the managed statement is valid. + */ + bool IsPrepared() const + { + return m_Handle && (m_Handle->mPtr != nullptr); + } + + /* -------------------------------------------------------------------------------------------- + * Return the number of active references to this statement handle. + */ + Uint32 GetReferences() const + { + return m_Handle.Count(); + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve the associated database connection. + */ + Object GetConnection() const; + + /* -------------------------------------------------------------------------------------------- + * Release the reference to the associated database statement. + */ + void Release() + { + m_Handle.Reset(); + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve the last received status code. + */ + Int32 GetStatus() const + { + return SQMOD_GET_VALID(*this)->mStatus; + } + + /* -------------------------------------------------------------------------------------------- + * Return the numeric result code for the most recent failed API call (if any). + */ + Int32 GetErrorCode() const + { + return SQMOD_GET_VALID(*this)->ErrNo(); + } + + /* -------------------------------------------------------------------------------------------- + * Return the extended numeric result code for the most recent failed API call (if any). + */ + Int32 GetExtendedErrorCode() const + { + return SQMOD_GET_VALID(*this)->ExErrNo(); + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve the message of the last received error code. + */ + CSStr GetErrStr() const + { + return SQMOD_GET_VALID(*this)->ErrStr(); + } + + /* -------------------------------------------------------------------------------------------- + * Return the last error message associated with this database connection. + */ + CSStr GetErrMsg() const + { + return SQMOD_GET_VALID(*this)->ErrMsg(); + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve the amount of requested columns. + */ + Int32 GetColumns() const + { + return SQMOD_GET_VALID(*this)->mColumns; + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve the amount of specified parameters. + */ + Int32 GetParameters() const + { + return SQMOD_GET_VALID(*this)->mParameters; + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve the query string used to create this statement. + */ + const String & GetQuery() const + { + return SQMOD_GET_VALID(*this)->mQuery; + } + + /* -------------------------------------------------------------------------------------------- + * See if the last step retrieved a valid row. + */ + bool GetGood() const + { + return SQMOD_GET_CREATED(*this)->mGood; + } + + /* -------------------------------------------------------------------------------------------- + * See if there are any steps left. + */ + bool GetDone() const + { + return SQMOD_GET_CREATED(*this)->mDone; + } + + /* -------------------------------------------------------------------------------------------- + * Check whether a specific parameter index is within range. + */ + bool CheckParameter(Int32 idx) const + { + return SQMOD_GET_VALID(*this)->CheckParameter(idx); + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve the parameter index associated with the specified name. + */ + Int32 GetParameterIndex(StackStrF & name) const + { + return sqlite3_bind_parameter_index(SQMOD_GET_VALID(*this)->mPtr, name.mPtr); + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve the parameter name associated with the specified index. + */ + CSStr GetParameterName(Int32 idx) const + { + // Validate the specified index + if (!idx) + { + STHROWF("Invalid parameter index (%d)", idx); + } + // Attempt to locate the name at the specified index + CSStr name = sqlite3_bind_parameter_name(SQMOD_GET_VALID(*this)->mPtr, idx); + // Validate the obtained string + if (!name) + { + STHROWF("No such parameter exists (%d)", idx); + } + // Return the obtained string + return name; + } + + /* -------------------------------------------------------------------------------------------- + * Check whether a specific column index is within range. + */ + bool CheckColumn(Int32 idx) const + { + return SQMOD_GET_VALID(*this)->CheckColumn(idx); + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve the amount of columns available in the current row. + */ + Int32 GetDataCount() const + { + return sqlite3_data_count(SQMOD_GET_VALID(*this)->mPtr); + } + + /* -------------------------------------------------------------------------------------------- + * Check whether the specified column is null. + */ + bool IsColumnNull(Int32 idx) const + { + return (sqlite3_column_type(SQMOD_GET_VALID(*this)->mPtr, idx) == SQLITE_NULL); + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve the column index associated with the specified name. + */ + Int32 GetColumnIndex(StackStrF & name) const + { + return SQMOD_GET_VALID(*this)->GetColumnIndex(name.mPtr, name.mLen); + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve the column name associated with the specified index. + */ + CSStr GetColumnName(Int32 idx) const + { + return sqlite3_column_name(SQMOD_GET_VALID(*this)->mPtr, idx); + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve the column origin name if the library was compiled with such feature. + */ + CSStr GetColumnOriginName(Int32 idx) const + { +#ifdef SQLITE_ENABLE_COLUMN_METADATA + return sqlite3_column_origin_name(SQMOD_GET_VALID(*this)->mPtr, idx); +#else + // The compiler moans when extra warnings are enabled + SQMOD_UNUSED_VAR(idx); + // Stop the execution here! + STHROWF("The module was compiled without this feature"); + // We have to return something + return _SC(""); +#endif + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve the type identifier of the column associated with the specified index. + */ + Int32 GetColumnType(Int32 idx) const + { + return sqlite3_column_type(SQMOD_GET_VALID(*this)->mPtr, idx); + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve the size in bytes of the column associated with the specified index. + */ + Int32 GetColumnBytes(Int32 idx) const + { + return sqlite3_column_bytes(SQMOD_GET_VALID(*this)->mPtr, idx); + } + + /* -------------------------------------------------------------------------------------------- + * Reset the statement back to its initial position to be stepped again. + */ + Statement & Reset(); + + /* -------------------------------------------------------------------------------------------- + * Clear any values binded to this statement. + */ + Statement & Clear(); + + /* -------------------------------------------------------------------------------------------- + * Execute this statement and don't expect any rows to be returned. + */ + Int32 Exec(); + + /* -------------------------------------------------------------------------------------------- + * Step the statement and expect a row to be returned. + */ + bool Step(); + + /* -------------------------------------------------------------------------------------------- + * Retrieve the parameter with the specified name or index. + */ + Object GetParameter(const Object & param) const + { + return Object(new Parameter(m_Handle, param)); + } + + /* -------------------------------------------------------------------------------------------- + * Attempt to bind a dynamic value at the specified parameter index. + */ + Statement & SetValue(const Object & param, const Object & value) + { + Parameter(SQMOD_GET_CREATED(*this), param).SetValue(value); + // Allow chaining of operations + return *this; + } + + /* -------------------------------------------------------------------------------------------- + * Attempt to bind a boolean value at the specified parameter index. + */ + Statement & SetBool(const Object & param, bool value) + { + Parameter(SQMOD_GET_CREATED(*this), param).SetBool(value); + // Allow chaining of operations + return *this; + } + + /* -------------------------------------------------------------------------------------------- + * Attempt to bind a character value at the specified parameter index. + */ + Statement & SetChar(const Object & param, SQInteger value) + { + Parameter(SQMOD_GET_CREATED(*this), param).SetChar(value); + // Allow chaining of operations + return *this; + } + + /* -------------------------------------------------------------------------------------------- + * Attempt to bind a native integer value at the specified parameter index. + */ + Statement & SetInteger(const Object & param, SQInteger value) + { + Parameter(SQMOD_GET_CREATED(*this), param).SetInteger(value); + // Allow chaining of operations + return *this; + } + + /* -------------------------------------------------------------------------------------------- + * Attempt to bind a signed 8 bit integer value at the specified parameter index. + */ + Statement & SetInt8(const Object & param, SQInteger value) + { + Parameter(SQMOD_GET_CREATED(*this), param).SetInt8(value); + // Allow chaining of operations + return *this; + } + + /* -------------------------------------------------------------------------------------------- + * Attempt to bind an unsigned 8 bit integer value at the specified parameter index. + */ + Statement & SetUint8(const Object & param, SQInteger value) + { + Parameter(SQMOD_GET_CREATED(*this), param).SetUint8(value); + // Allow chaining of operations + return *this; + } + + /* -------------------------------------------------------------------------------------------- + * Attempt to bind a signed 16 bit integer value at the specified parameter index. + */ + Statement & SetInt16(const Object & param, SQInteger value) + { + Parameter(SQMOD_GET_CREATED(*this), param).SetInt16(value); + // Allow chaining of operations + return *this; + } + + /* -------------------------------------------------------------------------------------------- + * Attempt to bind an unsigned 16 bit integer value at the specified parameter index. + */ + Statement & SetUint16(const Object & param, SQInteger value) + { + Parameter(SQMOD_GET_CREATED(*this), param).SetUint16(value); + // Allow chaining of operations + return *this; + } + + /* -------------------------------------------------------------------------------------------- + * Attempt to bind a signed 32 bit integer value at the specified parameter index. + */ + Statement & SetInt32(const Object & param, SQInteger value) + { + Parameter(SQMOD_GET_CREATED(*this), param).SetInt32(value); + // Allow chaining of operations + return *this; + } + + /* -------------------------------------------------------------------------------------------- + * Attempt to bind an unsigned 32 bit integer value at the specified parameter index. + */ + Statement & SetUint32(const Object & param, SQInteger value) + { + Parameter(SQMOD_GET_CREATED(*this), param).SetUint32(value); + // Allow chaining of operations + return *this; + } + + /* -------------------------------------------------------------------------------------------- + * Attempt to bind a signed 64 bit integer value at the specified parameter index. + */ + Statement & SetInt64(const Object & param, const Object & value) + { + Parameter(SQMOD_GET_CREATED(*this), param).SetInt64(value); + // Allow chaining of operations + return *this; + } + + /* -------------------------------------------------------------------------------------------- + * Attempt to bind an unsigned 64 bit integer value at the specified parameter index. + */ + Statement & SetUint64(const Object & param, const Object & value) + { + Parameter(SQMOD_GET_CREATED(*this), param).SetUint64(value); + // Allow chaining of operations + return *this; + } + + /* -------------------------------------------------------------------------------------------- + * Attempt to bind a native floating point value at the specified parameter index. + */ + Statement & SetFloat(const Object & param, SQFloat value) + { + Parameter(SQMOD_GET_CREATED(*this), param).SetFloat(value); + // Allow chaining of operations + return *this; + } + + /* -------------------------------------------------------------------------------------------- + * Attempt to bind a 32 bit floating point value at the specified parameter index. + */ + Statement & SetFloat32(const Object & param, SQFloat value) + { + Parameter(SQMOD_GET_CREATED(*this), param).SetFloat32(value); + // Allow chaining of operations + return *this; + } + + /* -------------------------------------------------------------------------------------------- + * Attempt to bind a 64 bit floating point value at the specified parameter index. + */ + Statement & SetFloat64(const Object & param, SQFloat value) + { + Parameter(SQMOD_GET_CREATED(*this), param).SetFloat64(value); + // Allow chaining of operations + return *this; + } + + /* -------------------------------------------------------------------------------------------- + * Attempt to bind a string value at the specified parameter index. + */ + Statement & SetString(const Object & param, StackStrF & value) + { + Parameter(SQMOD_GET_CREATED(*this), param).SetString(value); + // Allow chaining of operations + return *this; + } + + /* -------------------------------------------------------------------------------------------- + * Attempt to bind a zeroed blob value at the specified parameter index. + */ + Statement & SetZeroBlob(const Object & param, SQInteger size) + { + Parameter(SQMOD_GET_CREATED(*this), param).SetZeroBlob(size); + // Allow chaining of operations + return *this; + } + + /* -------------------------------------------------------------------------------------------- + * Attempt to bind a blob value at the specified parameter index. + */ + Statement & SetBlob(const Object & param, const Object & value) + { + Parameter(SQMOD_GET_CREATED(*this), param).SetBlob(value); + // Allow chaining of operations + return *this; + } + + /* -------------------------------------------------------------------------------------------- + * Attempt to bind a buffer value at the specified parameter index. + */ + Statement & SetData(const Object & param, const Object & value) + { + Parameter(SQMOD_GET_CREATED(*this), param).SetData(value.Cast< const SqBuffer & >()); + // Allow chaining of operations + return *this; + } + + /* -------------------------------------------------------------------------------------------- + * Attempt to bind a date value at the specified parameter index. + */ + Statement & SetDate(const Object & param, const Object & value) + { + Parameter(SQMOD_GET_CREATED(*this), param).SetDate(value.Cast< const Date & >()); + // Allow chaining of operations + return *this; + } + + /* -------------------------------------------------------------------------------------------- + * Attempt to bind a date value at the specified parameter index. + */ + Statement & SetDateEx(const Object & param, SQInteger year, SQInteger month, SQInteger day) + { + Parameter(SQMOD_GET_CREATED(*this), param).SetDateEx(year, month, day); + // Allow chaining of operations + return *this; + } + + /* -------------------------------------------------------------------------------------------- + * Attempt to bind a time value at the specified parameter index. + */ + Statement & SetTime(const Object & param, const Object & value) + { + Parameter(SQMOD_GET_CREATED(*this), param).SetTime(value.Cast< const Time & >()); + // Allow chaining of operations + return *this; + } + + /* -------------------------------------------------------------------------------------------- + * Attempt to bind a time value at the specified parameter index. + */ + Statement & SetTimeEx(const Object & param, SQInteger hour, SQInteger minute, SQInteger second) + { + Parameter(SQMOD_GET_CREATED(*this), param).SetTimeEx(hour, minute, second); + // Allow chaining of operations + return *this; + } + + /* -------------------------------------------------------------------------------------------- + * Attempt to bind a date-time value at the specified parameter index. + */ + Statement & SetDatetime(const Object & param, const Object & value) + { + Parameter(SQMOD_GET_CREATED(*this), param).SetDatetime(value.Cast< const Datetime & >()); + // Allow chaining of operations + return *this; + } + + /* -------------------------------------------------------------------------------------------- + * Attempt to bind a date-time value at the specified parameter index. + */ + Statement & SetDatetimeEx(const Object & param, SQInteger year, SQInteger month, SQInteger day, + SQInteger hour, SQInteger minute, SQInteger second) + { + Parameter(SQMOD_GET_CREATED(*this), param).SetDatetimeEx(year, month, day, hour, minute, second); + // Allow chaining of operations + return *this; + } + + /* -------------------------------------------------------------------------------------------- + * Attempt to bind the current timestamp at the specified parameter index. + */ + Statement & SetNow(const Object & param) + { + Parameter(SQMOD_GET_CREATED(*this), param).SetNow(); + // Allow chaining of operations + return *this; + } + + /* -------------------------------------------------------------------------------------------- + * Attempt to bind a null value at the specified parameter index. + */ + Statement & SetNull(const Object & param) + { + Parameter(SQMOD_GET_CREATED(*this), param).SetNull(); + // Allow chaining of operations + return *this; + } + + /* -------------------------------------------------------------------------------------------- + * Attempt to bind the values from an array starting at the specified index. + */ + Statement & SetArray(Int32 idx, const Array & arr); + + /* -------------------------------------------------------------------------------------------- + * Attempt to bind the values from an associative container. + */ + Statement & SetTable(const Table & tbl); + + /* -------------------------------------------------------------------------------------------- + * Retrieve the column with the specified name or index. + */ + Object GetColumn(const Object & column) const + { + return Object(new Column(m_Handle, column)); + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve the value inside the referenced column as a dynamic type. + */ + Object GetValue(const Object & column) const + { + return Column(SQMOD_GET_CREATED(*this), column).GetValue(); + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve the value inside the referenced column as a numeric type. + */ + Object GetNumber(const Object & column) const + { + return Column(SQMOD_GET_CREATED(*this), column).GetNumber(); + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve the value inside the referenced column as a native script integer. + */ + SQInteger GetInteger(const Object & column) const + { + return Column(SQMOD_GET_CREATED(*this), column).GetInteger(); + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve the value inside the referenced column as a native script floating point. + */ + SQFloat GetFloat(const Object & column) const + { + return Column(SQMOD_GET_CREATED(*this), column).GetFloat(); + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve the value inside the referenced column as a long integer. + */ + Object GetLong(const Object & column) const + { + return Column(SQMOD_GET_CREATED(*this), column).GetLong(); + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve the value inside the referenced column as a string. + */ + Object GetString(const Object & column) const + { + return Column(SQMOD_GET_CREATED(*this), column).GetString(); + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve the value inside the referenced column as a boolean. + */ + bool GetBoolean(const Object & column) const + { + return Column(SQMOD_GET_CREATED(*this), column).GetBoolean(); + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve the value inside the referenced column as a character. + */ + SQChar GetChar(const Object & column) const + { + return Column(SQMOD_GET_CREATED(*this), column).GetChar(); + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve the value inside the referenced column as a memory buffer. + */ + Object GetBuffer(const Object & column) const + { + return Column(SQMOD_GET_CREATED(*this), column).GetBuffer(); + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve the value inside the referenced column as a memory blob. + */ + Object GetBlob(const Object & column) const + { + return Column(SQMOD_GET_CREATED(*this), column).GetBlob(); + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve the row as an array container. + */ + Array GetArray() const + { + return GetArray(0, SQMOD_GET_CREATED(*this)->mColumns); + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve the row as an array container. + */ + Array GetArray(Int32 min) const + { + return GetArray(min, SQMOD_GET_CREATED(*this)->mColumns); + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve the row as an array container. + */ + Array GetArray(Int32 min, Int32 max) const; + + /* -------------------------------------------------------------------------------------------- + * Retrieve the row as an associative container. + */ + Table GetTable() const + { + // Is there something to return? + if (SQMOD_GET_CREATED(*this)->mColumns > 0) + { + return GetTable(0, m_Handle->mColumns - 1); + } + // Fallback to empty table + return NullTable(); + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve the row as an associative container. + */ + Table GetTable(Int32 min) const + { + // Is there something to return? + if (SQMOD_GET_CREATED(*this)->mColumns > 0) + { + return GetTable(min, m_Handle->mColumns - 1); + } + // Fallback to empty table + return NullTable(); + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve the row as an associative container. + */ + Table GetTable(Int32 min, Int32 max) const; +}; + +/* ------------------------------------------------------------------------------------------------ + * Implements the RAII pattern for database transactions. +*/ +class Transaction +{ +public: + + /* -------------------------------------------------------------------------------------------- + * Construct by taking the handle from a connection. + */ + Transaction(const Connection & db); + + /* -------------------------------------------------------------------------------------------- + * Construct using the direct connection handle. + */ + Transaction(ConnRef db); + + /* -------------------------------------------------------------------------------------------- + * Copy constructor. (disabled) + */ + Transaction(const Transaction & o) = delete; + + /* -------------------------------------------------------------------------------------------- + * Move constructor. (disabled) + */ + Transaction(Transaction && o) = delete; + + /* -------------------------------------------------------------------------------------------- + * Destructor. + */ + ~Transaction(); + + /* -------------------------------------------------------------------------------------------- + * Copy assignment operator. (disabled) + */ + Transaction & operator = (const Transaction & o) = delete; + + /* -------------------------------------------------------------------------------------------- + * Move assignment operator. (disabled) + */ + Transaction & operator = (Transaction && o) = delete; + + /* -------------------------------------------------------------------------------------------- + * Used by the script engine to convert an instance of this type to a string. + */ + const String & ToString() const + { + return m_Handle ? m_Handle->mName : NullString(); + } + + /* -------------------------------------------------------------------------------------------- + * Retrieve the associated statement handle. + */ + const ConnRef & GetHandle() const + { + return m_Handle; + } + + /* -------------------------------------------------------------------------------------------- + * See whether the managed handle is valid. + */ + bool IsValid() const + { + return m_Handle; + } + + /* -------------------------------------------------------------------------------------------- + * Attempt to commit changes to the database. + */ + bool Commit(); + + /* -------------------------------------------------------------------------------------------- + * See whether the change during this transaction were successfully committed. + */ + bool Commited() const + { + return m_Committed; + } + +private: + + // -------------------------------------------------------------------------------------------- + ConnRef m_Handle; // The database connection handle where the transaction began. + bool m_Committed; // Whether changes were successfully committed to the database. +}; } // Namespace:: SqMod diff --git a/module/Library/SQLite/Column.cpp b/module/Library/SQLite/Column.cpp deleted file mode 100644 index 7e282167..00000000 --- a/module/Library/SQLite/Column.cpp +++ /dev/null @@ -1,540 +0,0 @@ -// ------------------------------------------------------------------------------------------------ -#include "Library/SQLite/Column.hpp" - -// ------------------------------------------------------------------------------------------------ -#include -#include - -// ------------------------------------------------------------------------------------------------ -#include - -// ------------------------------------------------------------------------------------------------ -namespace SqMod { - -// ------------------------------------------------------------------------------------------------ -SQMODE_DECL_TYPENAME(Typename, _SC("SqLiteColumn")) - -// ------------------------------------------------------------------------------------------------ -static inline bool IsDigitsOnly(CSStr str) -{ - while (std::isdigit(*str) || std::isspace(*str)) - { - ++str; - } - // Return whether we reached the end while searching - return *str == '\0'; -} - -// ------------------------------------------------------------------------------------------------ -#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) -void Column::Validate(CCStr file, Int32 line) const -{ - // Are we pointing to a valid index? - if (m_Index < 0) - { - SqThrowF("Invalid column index: %d < 0 =>[%s:%d]", m_Index, file, line); - } - // Do we have a valid statement handle? - else if (!m_Handle) - { - SqThrowF("Invalid SQLite statement reference =>[%s:%d]", file, line); - } -} -#else -void Column::Validate() const -{ - // Are we pointing to a valid index? - if (m_Index < 0) - { - SqThrowF("Invalid column index: %d < 0", m_Index); - } - // Do we have a valid statement handle? - else if (!m_Handle) - { - SqThrowF("Invalid SQLite statement reference"); - } -} -#endif // _DEBUG - -// ------------------------------------------------------------------------------------------------ -#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) -void Column::ValidateCreated(CCStr file, Int32 line) const -{ - // Are we pointing to a valid index? - if (m_Index < 0) - { - SqThrowF("Invalid column index: %d < 0 =>[%s:%d]", m_Index, file, line); - } - else if (!m_Handle) - { - SqThrowF("Invalid SQLite statement reference =>[%s:%d]", file, line); - } - else if (m_Handle->mPtr == nullptr) - { - SqThrowF("Invalid SQLite statement =>[%s:%d]", file, line); - } -} -#else -void Column::ValidateCreated() const -{ - // Are we pointing to a valid index? - if (m_Index < 0) - { - SqThrowF("Invalid column index: %d < 0", m_Index); - } - else if (!m_Handle) - { - SqThrowF("Invalid SQLite statement reference"); - } - else if (m_Handle->mPtr == nullptr) - { - SqThrowF("Invalid SQLite statement"); - } -} -#endif // _DEBUG - -// ------------------------------------------------------------------------------------------------ -#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) -const StmtRef & Column::GetValid(CCStr file, Int32 line) const -{ - Validate(file, line); - return m_Handle; -} -#else -const StmtRef & Column::GetValid() const -{ - Validate(); - return m_Handle; -} -#endif // _DEBUG - -// ------------------------------------------------------------------------------------------------ -#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) -const StmtRef & Column::GetCreated(CCStr file, Int32 line) const -{ - ValidateCreated(file, line); - return m_Handle; -} -#else -const StmtRef & Column::GetCreated() const -{ - ValidateCreated(); - return m_Handle; -} -#endif // _DEBUG - -// ------------------------------------------------------------------------------------------------ -#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) -void Column::ValidateColumn(Int32 idx, CCStr file, Int32 line) const -{ - ValidateCreated(file, line); - // Is the specified index in range? - if (!m_Handle->CheckColumn(idx)) - { - SqThrowF("Column index is out of range: %d:%d =>[%s:%d]", idx, m_Handle->mColumns, - file, line); - } -} -#else -void Column::ValidateColumn(Int32 idx) const -{ - ValidateCreated(); - // Is the specified index in range? - if (!m_Handle->CheckColumn(idx)) - { - SqThrowF("Column index is out of range: %d:%d", idx, m_Handle->mColumns); - } -} -#endif // _DEBUG - -// ------------------------------------------------------------------------------------------------ -#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) -void Column::ValidateRow(CCStr file, Int32 line) const -{ - ValidateCreated(file, line); - // Do we have any rows available? - if (!m_Handle->mGood) - { - STHROWF("No row available =>[%s:%d]", file, line); - } -} -#else -void Column::ValidateRow() const -{ - ValidateCreated(); - // Do we have any rows available? - if (!m_Handle->mGood) - { - STHROWF("No row available"); - } -} -#endif // _DEBUG - -// ------------------------------------------------------------------------------------------------ -void Column::SetIndex(const Object & column) -{ - // Where the index will be extracted - Int32 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("%s", LastErrorString(vm).c_str()); - } - // 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 >::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("%s", LastErrorString(vm).c_str()); - } - // 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 >::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 (%s)", SqTypeName(column.GetType())); - } - // Assign the index with a failsafe to invalid on error - AutoAssign< Int32 > 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 Column::GetStatement() const -{ - return GetStatementObj(m_Handle); -} - -// ------------------------------------------------------------------------------------------------ -Object Column::GetConnection() const -{ - return GetConnectionObj(SQMOD_GET_VALID(*this)->mConn); -} - -// ------------------------------------------------------------------------------------------------ -bool Column::IsNull() const -{ - return (sqlite3_column_type(SQMOD_GET_CREATED(*this)->mPtr, m_Index) == SQLITE_NULL); -} - -// ------------------------------------------------------------------------------------------------ -CSStr Column::GetName() const -{ - return sqlite3_column_name(SQMOD_GET_CREATED(*this)->mPtr, m_Index); -} - -// ------------------------------------------------------------------------------------------------ -CSStr Column::GetOriginName() const -{ -#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 Column::GetType() const -{ - return sqlite3_column_type(SQMOD_GET_CREATED(*this)->mPtr, m_Index); -} - -// ------------------------------------------------------------------------------------------------ -Int32 Column::GetBytes() const -{ - return sqlite3_column_bytes(SQMOD_GET_CREATED(*this)->mPtr, m_Index); -} - -// ------------------------------------------------------------------------------------------------ -Object Column::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(DefaultVM::Get()); - } break; - // Is this an integer? - case SQLITE_INTEGER: - { - sq_pushinteger(DefaultVM::Get(), sqlite3_column_integer(m_Handle->mPtr, m_Index)); - } break; - // Is this a floating point? - case SQLITE_FLOAT: - { - sq_pushfloat(DefaultVM::Get(), - ConvTo< SQFloat >::From(sqlite3_column_double(m_Handle->mPtr, m_Index))); - } break; - // Is this a string? - case SQLITE_TEXT: - { - sq_pushstring(DefaultVM::Get(), - reinterpret_cast< CSStr >(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 size = sqlite3_column_bytes(m_Handle->mPtr, m_Index); - // Retrieve the the actual blob data that must be returned - auto data = reinterpret_cast< CCStr >(sqlite3_column_blob(m_Handle->mPtr, m_Index)); - // Attempt to create a buffer with the blob data on the stack - Var< const SqBuffer & >::push(DefaultVM::Get(), SqBuffer(data, size, 0)); - } break; - // Unknown type - default: STHROWF("Unknown value to fetch at index: %d", m_Index); - } - // Obtain the object with the value from the stack and return it - return Var< Object >(DefaultVM::Get(), -1).value; -} - -// ------------------------------------------------------------------------------------------------ -Object Column::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(DefaultVM::Get(), 0); - } break; - // Is this an integer? - case SQLITE_INTEGER: - { - sq_pushinteger(DefaultVM::Get(), sqlite3_column_integer(m_Handle->mPtr, m_Index)); - } break; - // Is this a floating point? - case SQLITE_FLOAT: - { - sq_pushfloat(DefaultVM::Get(), - ConvTo< SQFloat >::From(sqlite3_column_double(m_Handle->mPtr, m_Index))); - } break; - // Is this a string? - case SQLITE_TEXT: - { - auto str = reinterpret_cast< CSStr >(sqlite3_column_text(m_Handle->mPtr, m_Index)); - // Is there even a string to parse? - if (!str || *str == '\0') - { - sq_pushinteger(DefaultVM::Get(), 0); - } - // Can we treat this string as a float? - else if (!std::strchr(str, '.')) - { - sq_pushfloat(DefaultVM::Get(), - ConvTo< SQFloat >::From(std::strtod(str, nullptr))); - } - else - { - sq_pushinteger(DefaultVM::Get(), - ConvTo< SQInteger >::From(std::strtoll(str, nullptr, 10))); - - } - } break; - // Unknown type - default: STHROWF("Unknown number to fetch at index: %d", m_Index); - } - // Obtain the object with the value from the stack and return it - return Var< Object >(DefaultVM::Get(), -1).value; -} - -// ------------------------------------------------------------------------------------------------ -SQInteger Column::GetInteger() const -{ - SQMOD_VALIDATE_ROW(*this); - // Return the requested information - return sqlite3_column_integer(m_Handle->mPtr, m_Index); -} - -// ------------------------------------------------------------------------------------------------ -SQFloat Column::GetFloat() const -{ - SQMOD_VALIDATE_ROW(*this); - // Return the requested information - return ConvTo< SQFloat >::From(sqlite3_column_double(m_Handle->mPtr, m_Index)); -} - -// ------------------------------------------------------------------------------------------------ -Object Column::GetLong() const -{ - SQMOD_VALIDATE_ROW(*this); - // Return the requested information - return Object(new SLongInt(sqlite3_column_int64(m_Handle->mPtr, m_Index))); -} - -// ------------------------------------------------------------------------------------------------ -Object Column::GetString() const -{ - SQMOD_VALIDATE_ROW(*this); - // Obtain the initial stack size - const StackGuard sg; - // Push the column text on the stack - sq_pushstring(DefaultVM::Get(), reinterpret_cast< CSStr >(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 >(DefaultVM::Get(), -1).value; -} - -// ------------------------------------------------------------------------------------------------ -bool Column::GetBoolean() const -{ - SQMOD_VALIDATE_ROW(*this); - // Return the requested information - return sqlite3_column_int(m_Handle->mPtr, m_Index) > 0; -} - -// ------------------------------------------------------------------------------------------------ -SQChar Column::GetChar() const -{ - SQMOD_VALIDATE_ROW(*this); - // Return the requested information - return (SQChar)sqlite3_column_int(m_Handle->mPtr, m_Index); -} - -// ------------------------------------------------------------------------------------------------ -Object Column::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 size = sqlite3_column_bytes(m_Handle->mPtr, m_Index); - // Retrieve the the actual blob data that must be returned - auto data = reinterpret_cast< CCStr >(sqlite3_column_blob(m_Handle->mPtr, m_Index)); - // Attempt to create a buffer with the blob data on the stack - Var< const SqBuffer & >::push(DefaultVM::Get(), SqBuffer(data, size, 0)); - // Get the object from the stack and return it - return Var< Object >(DefaultVM::Get(), -1).value; -} - -// ------------------------------------------------------------------------------------------------ -Object Column::GetBlob() const -{ - SQMOD_VALIDATE_ROW(*this); - // Obtain the initial stack size - const StackGuard sg; - // Obtain the size of the data - const Int32 sz = sqlite3_column_bytes(m_Handle->mPtr, m_Index); - // Allocate a blob of the same size - SQUserPointer p = sqstd_createblob(DefaultVM::Get(), 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(DefaultVM::Get(), 1); - // Push a null value instead - sq_pushnull(DefaultVM::Get()); - } - // Copy the data into the memory blob - else - { - std::memcpy(p, b, sz); - } - // Get the object from the stack and return it - return Var< Object >(DefaultVM::Get(), -1).value; -} - -// ================================================================================================ -void Register_Column(Table & sqlns) -{ - sqlns.Bind(_SC("Column"), - Class< Column >(sqlns.GetVM(), Typename::Str) - // Constructors - .Ctor() - .Ctor< const Column & >() - // Meta-methods - .SquirrelFunc(_SC("_typename"), &Typename::Fn) - .Func(_SC("_tostring"), &Column::ToString) - // Properties - .Prop(_SC("IsValid"), &Column::IsValid) - .Prop(_SC("References"), &Column::GetRefCount) - .Prop(_SC("Index"), &Column::GetIndex) - .Prop(_SC("Statement"), &Column::GetStatement) - .Prop(_SC("Connection"), &Column::GetConnection) - .Prop(_SC("IsNull"), &Column::IsNull) - .Prop(_SC("Name"), &Column::GetName) - .Prop(_SC("OriginName"), &Column::GetOriginName) - .Prop(_SC("Type"), &Column::GetType) - .Prop(_SC("Bytes"), &Column::GetBytes) - .Prop(_SC("Value"), &Column::GetValue) - .Prop(_SC("Number"), &Column::GetNumber) - .Prop(_SC("Integer"), &Column::GetInteger) - .Prop(_SC("Float"), &Column::GetFloat) - .Prop(_SC("Long"), &Column::GetLong) - .Prop(_SC("String"), &Column::GetString) - .Prop(_SC("Boolean"), &Column::GetBoolean) - .Prop(_SC("Char"), &Column::GetChar) - .Prop(_SC("Buffer"), &Column::GetBuffer) - .Prop(_SC("Blob"), &Column::GetBlob) - // Member Methods - .Func(_SC("Release"), &Column::Release) - ); -} - -} // Namespace:: SqMod diff --git a/module/Library/SQLite/Column.hpp b/module/Library/SQLite/Column.hpp deleted file mode 100644 index 083bf4c9..00000000 --- a/module/Library/SQLite/Column.hpp +++ /dev/null @@ -1,339 +0,0 @@ -#pragma once - -// ------------------------------------------------------------------------------------------------ -#include "Library/SQLite/Handle.hpp" - -// ------------------------------------------------------------------------------------------------ -namespace SqMod { - -/* ------------------------------------------------------------------------------------------------ - * Used to manage and interact with statement columns. -*/ -class Column -{ - // -------------------------------------------------------------------------------------------- - friend class Statement; - -private: - - // -------------------------------------------------------------------------------------------- - Int32 m_Index; // The index of the managed column. - StmtRef m_Handle; // The statement where the column exist. - -protected: - - /* -------------------------------------------------------------------------------------------- - * Validate the managed statement handle and throw an error if invalid. - */ -#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) - void Validate(CCStr file, Int32 line) const; -#else - void Validate() const; -#endif // _DEBUG - - /* -------------------------------------------------------------------------------------------- - * Validate the managed statement handle and throw an error if invalid. - */ -#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) - void ValidateCreated(CCStr file, Int32 line) const; -#else - void ValidateCreated() const; -#endif // _DEBUG - - /* -------------------------------------------------------------------------------------------- - * Validate the managed statement handle and throw an error if invalid. - */ -#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) - const StmtRef & GetValid(CCStr file, Int32 line) const; -#else - const StmtRef & GetValid() const; -#endif // _DEBUG - - /* -------------------------------------------------------------------------------------------- - * Validate the managed statement handle and throw an error if invalid. - */ -#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) - const StmtRef & GetCreated(CCStr file, Int32 line) const; -#else - const StmtRef & GetCreated() const; -#endif // _DEBUG - - /* -------------------------------------------------------------------------------------------- - * Validate the statement reference and column index, and throw an error if they're invalid. - */ -#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) - void ValidateColumn(Int32 idx, CCStr file, Int32 line) const; -#else - void ValidateColumn(Int32 idx) const; -#endif // _DEBUG - - /* -------------------------------------------------------------------------------------------- - * Validate the statement reference and row, and throw an error if they're invalid. - */ -#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) - void ValidateRow(CCStr file, Int32 line) const; -#else - void ValidateRow() const; -#endif // _DEBUG - - /* -------------------------------------------------------------------------------------------- - * Modify the index to the specified value. - */ - void SetIndex(Int32 idx) - { - // Assign the index with a failsafe to invalid on error - AutoAssign< Int32 > 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); - } - - /* -------------------------------------------------------------------------------------------- - * Modify the index to the specified value. - */ - void SetIndex(CSStr name) - { - SetIndex(SQMOD_GET_CREATED(*this)->GetColumnIndex(name)); - } - - /* -------------------------------------------------------------------------------------------- - * Modify the index to the specified value. - */ - void SetIndex(const Object & column); - -public: - - /* -------------------------------------------------------------------------------------------- - * Default constructor (null). - */ - Column() - : m_Index(-1), m_Handle() - { - /* ... */ - } - - /* -------------------------------------------------------------------------------------------- - * No column constructor. - */ - Column(const StmtRef & stmt) - : m_Index(-1), m_Handle(stmt) - { - /* ... */ - } - - /* -------------------------------------------------------------------------------------------- - * Index constructor. - */ - Column(const StmtRef & stmt, Int32 idx) - : m_Index(idx), m_Handle(stmt) - { - SQMOD_VALIDATE_COLUMN(*this, m_Index); - } - - /* -------------------------------------------------------------------------------------------- - * Name constructor. - */ - Column(const StmtRef & stmt, CSStr name) - : m_Index(stmt ? stmt->GetColumnIndex(name) : -1), m_Handle(stmt) - { - SQMOD_VALIDATE_COLUMN(*this, m_Index); - } - - /* -------------------------------------------------------------------------------------------- - * Dynamic constructor. - */ - Column(const StmtRef & stmt, const Object & column) - : m_Index(-1), m_Handle(stmt) - { - if (!m_Handle) - { - STHROWF("Invalid SQLite statement reference"); - } - // Extract the index - SetIndex(column); - } - - /* -------------------------------------------------------------------------------------------- - * Copy constructor. - */ - Column(const Column & o) = default; - - /* -------------------------------------------------------------------------------------------- - * Move constructor. - */ - Column(Column && o) = default; - - /* -------------------------------------------------------------------------------------------- - * Copy assignment operator. - */ - Column & operator = (const Column & o) = default; - - /* -------------------------------------------------------------------------------------------- - * Move assignment operator. - */ - Column & operator = (Column && o) = default; - - /* -------------------------------------------------------------------------------------------- - * Perform an equality comparison between two table column indexes. - */ - bool operator == (const Column & o) const - { - return (m_Index == o.m_Index); - } - - /* -------------------------------------------------------------------------------------------- - * Perform an inequality comparison between two table column indexes. - */ - bool operator != (const Column & o) const - { - return (m_Index != o.m_Index); - } - - /* -------------------------------------------------------------------------------------------- - * Implicit conversion to boolean for use in boolean operations. - */ - operator bool () const - { - return m_Index >= 0; - } - - /* -------------------------------------------------------------------------------------------- - * Used by the script engine to convert an instance of this type to a string. - */ - CSStr ToString() const - { - CSStr val = nullptr; - // Can we attempt to return the parameter name? - if (m_Handle && m_Index) - { - val = sqlite3_column_name(m_Handle->mPtr, m_Index); - } - else - { - val = ToStrF(_SC("%d"), m_Index); - } - // Return the value if valid - return val ? val : _SC(""); - } - - /* -------------------------------------------------------------------------------------------- - * See whether the column is valid. - */ - bool IsValid() const - { - return m_Handle; // An invalid statement means an invalid column - } - - /* -------------------------------------------------------------------------------------------- - * Return the number of active references to the associated statement handle. - */ - Uint32 GetRefCount() const - { - return m_Handle.Count(); - } - - /* -------------------------------------------------------------------------------------------- - * Retrieve the referenced column index. - */ - Int32 GetIndex() const - { - return m_Index; - } - - /* -------------------------------------------------------------------------------------------- - * Retrieve the referenced database statement. - */ - Object GetStatement() const; - - /* -------------------------------------------------------------------------------------------- - * Retrieve the referenced database connection. - */ - Object GetConnection() const; - - /* -------------------------------------------------------------------------------------------- - * Release the reference to the referenced database statement and column index. - */ - void Release() - { - m_Handle.Reset(); - m_Index = -1; - } - - /* -------------------------------------------------------------------------------------------- - * Check whether the referenced column is null. - */ - bool IsNull() const; - - /* -------------------------------------------------------------------------------------------- - * Retrieve the name of the referenced column index. - */ - CSStr GetName() const; - - /* -------------------------------------------------------------------------------------------- - * Retrieve the column origin name if the library was compiled with such feature. - */ - CSStr GetOriginName() const; - - /* -------------------------------------------------------------------------------------------- - * Retrieve the type identifier of the referenced column index. - */ - Int32 GetType() const; - - /* -------------------------------------------------------------------------------------------- - * Retrieve the size in bytes of the referenced column index. - */ - Int32 GetBytes() const; - - /* -------------------------------------------------------------------------------------------- - * Retrieve the value inside the referenced column as a dynamic type. - */ - Object GetValue() const; - - /* -------------------------------------------------------------------------------------------- - * Retrieve the value inside the referenced column as a numeric type. - */ - Object GetNumber() const; - - /* -------------------------------------------------------------------------------------------- - * Retrieve the value inside the referenced column as a native script integer. - */ - SQInteger GetInteger() const; - - /* -------------------------------------------------------------------------------------------- - * Retrieve the value inside the referenced column as a native script floating point. - */ - SQFloat GetFloat() const; - - /* -------------------------------------------------------------------------------------------- - * Retrieve the value inside the referenced column as a long integer. - */ - Object GetLong() const; - - /* -------------------------------------------------------------------------------------------- - * Retrieve the value inside the referenced column as a string. - */ - Object GetString() const; - - /* -------------------------------------------------------------------------------------------- - * Retrieve the value inside the referenced column as a boolean. - */ - bool GetBoolean() const; - - /* -------------------------------------------------------------------------------------------- - * Retrieve the value inside the referenced column as a character. - */ - SQChar GetChar() const; - - /* -------------------------------------------------------------------------------------------- - * Retrieve the value inside the referenced column as a memory buffer. - */ - Object GetBuffer() const; - - /* -------------------------------------------------------------------------------------------- - * Retrieve the value inside the referenced column as a memory blob. - */ - Object GetBlob() const; -}; - -} // Namespace:: SqMod diff --git a/module/Library/SQLite/Common.cpp b/module/Library/SQLite/Common.cpp deleted file mode 100644 index 0567c319..00000000 --- a/module/Library/SQLite/Common.cpp +++ /dev/null @@ -1,219 +0,0 @@ -// ------------------------------------------------------------------------------------------------ -#include "Library/SQLite/Common.hpp" -#include "Library/SQLite/Connection.hpp" -#include "Library/SQLite/Statement.hpp" - -// ------------------------------------------------------------------------------------------------ -namespace SqMod { - -// ------------------------------------------------------------------------------------------------ -Object GetConnectionObj(const ConnRef & conn) -{ - return Object(new Connection(conn)); -} - -// ------------------------------------------------------------------------------------------------ -Object GetStatementObj(const StmtRef & stmt) -{ - return Object(new Statement(stmt)); -} - -// ------------------------------------------------------------------------------------------------ -bool IsQueryEmpty(CSStr str) -{ - // Is the pointer valid? - if (!str || *str == '\0') - { - return true; - } - // Currently processed character - SQChar c = 0; - // See if the query contains any alpha numeric characters - while ((c = *str) != 0) - { - if (std::isalnum(c) != 0) - { - return false; - } - ++str; - } - // At this point we consider the query empty - return true; -} - -// ------------------------------------------------------------------------------------------------ -CSStr GetErrStr(Int32 status) -{ - return sqlite3_errstr(status); -} - -// ------------------------------------------------------------------------------------------------ -void SetSoftHeapLimit(Int32 limit) -{ - sqlite3_soft_heap_limit(limit); -} - -// ------------------------------------------------------------------------------------------------ -Int32 ReleaseMemory(Int32 bytes) -{ - return sqlite3_release_memory(bytes); -} - -// ------------------------------------------------------------------------------------------------ -Object GetMemoryUsage() -{ - // Obtain the initial stack size - const StackGuard sg; - // Push a long integer instance with the requested value on the stack - return Object(new SLongInt(sqlite3_memory_used())); -} - -// ------------------------------------------------------------------------------------------------ -Object GetMemoryHighwaterMark(bool reset) -{ - // Obtain the initial stack size - const StackGuard sg; - // Push a long integer instance with the requested value on the stack - return Object(new SLongInt(sqlite3_memory_highwater(reset))); -} - -// ------------------------------------------------------------------------------------------------ -CSStr EscapeString(StackStrF & str) -{ - // Is there even a string to escape? - if (str.mLen <= 0) - { - return _SC(""); // Default to empty string - } - // Attempt to escape the specified string - sqlite3_snprintf(GetTempBuffSize(), GetTempBuff(), "%q", str.mPtr); - // Return the resulted string - return GetTempBuff(); -} - -// ------------------------------------------------------------------------------------------------ -CCStr EscapeStringEx(SQChar spec, StackStrF & str) -{ - // Utility that allows changing the format specifier temporarily - static SQChar fs[] = _SC("%q"); - // 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 _SC(""); // Default to empty string - } - // Apply the format specifier - fs[1] = spec; - // Attempt to escape the specified string - sqlite3_snprintf(GetTempBuffSize(), GetTempBuff(), fs, str.mPtr); - // Restore the format specifier - fs[1] = 'q'; - // Return the resulted string - return GetTempBuff(); -} - -// ------------------------------------------------------------------------------------------------ -CCStr ArrayToQueryColumns(Array & arr) -{ - // Do we even have any elements to process? - if (arr.Length() <= 0) - { - return _SC(""); // Default to empty string - } - // Allocate a vector with the required amount of column names - std::vector< String > values(arr.Length()); - // Attempt to extract the array elements as strings - arr.GetArray< String >(&values[0], values.size()); - // Used to know the position of the next column name - Uint32 offset = 0; - // Obtain the start of the array - auto itr = values.begin(); - // Process all elements within range - for (; itr != values.end() && offset < GetTempBuffSize(); ++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 >(GetTempBuffSize() - offset), GetTempBuff() + 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) - { - GetTempBuff()[offset-2] = '\0'; - } - else - { - GetTempBuff()[0] = '\0'; - } - // Return the resulted string - return GetTempBuff(); -} - -// ------------------------------------------------------------------------------------------------ -CCStr TableToQueryColumns(Table & tbl) -{ - // Used to know the position of the next column name - Uint32 offset = 0; - // Used to obtain the column name temporarily - String name; - // Obtain the start of the table - Table::iterator itr; - // Process all elements within range - while (tbl.Next(itr)) - { - // Use the element key as the column name - name.assign(itr.getName()); - // Is the name valid? - if (name.empty()) - { - STHROWF("Invalid or empty column name"); - } - // Attempt to append the column name to the buffer - sqlite3_snprintf(static_cast< int >(GetTempBuffSize() - offset), GetTempBuff() + offset, "[%q], ", name.c_str()); - // Add the column name size to the offset - offset += name.size(); - // Also include the comma and space in the offset - offset += 2; - } - // Trim the last coma and space - if (offset >= 2) - { - GetTempBuff()[offset-2] = '\0'; - } - else - { - GetTempBuff()[0] = '\0'; - } - // Return the resulted string - return GetTempBuff(); -} - -// ================================================================================================ -void Register_Common(Table & sqlns) -{ - 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); -} - -} // Namespace:: SqMod diff --git a/module/Library/SQLite/Common.hpp b/module/Library/SQLite/Common.hpp deleted file mode 100644 index aa94ef69..00000000 --- a/module/Library/SQLite/Common.hpp +++ /dev/null @@ -1,153 +0,0 @@ -#pragma once - -// ------------------------------------------------------------------------------------------------ -#include "Base/Shared.hpp" - -// ------------------------------------------------------------------------------------------------ -#include "Library/Numeric/LongInt.hpp" -#include "Library/Utils/Buffer.hpp" -#include "Library/Chrono/Date.hpp" -#include "Library/Chrono/Datetime.hpp" -#include "Library/Chrono/Time.hpp" -#include "Library/Chrono/Timestamp.hpp" - -// ------------------------------------------------------------------------------------------------ -#include - -// ------------------------------------------------------------------------------------------------ -namespace SqMod { - -/* ------------------------------------------------------------------------------------------------ - * Forward declarations. -*/ -class Connection; -class Statement; -class Column; -class Transaction; - -/* ------------------------------------------------------------------------------------------------ - * SOFTWARE INFORMATION -*/ -#define SQSQLITE_NAME "Squirrel SQLite Module" -#define SQSQLITE_AUTHOR "Sandu Liviu Catalin (S.L.C)" -#define SQSQLITE_COPYRIGHT "Copyright (C) 2018 Sandu Liviu Catalin" -#define SQSQLITE_HOST_NAME "SqModSQLiteHost" -#define SQSQLITE_VERSION 001 -#define SQSQLITE_VERSION_STR "0.0.1" -#define SQSQLITE_VERSION_MAJOR 0 -#define SQSQLITE_VERSION_MINOR 0 -#define SQSQLITE_VERSION_PATCH 1 - -/* ------------------------------------------------------------------------------------------------ - * Handle validation. -*/ -#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) - #define SQMOD_THROW_CURRENT(x, a) (x).ThrowCurrent(a, __FILE__, __LINE__) - #define SQMOD_VALIDATE(x) (x).Validate(__FILE__, __LINE__) - #define SQMOD_VALIDATE_CREATED(x) (x).ValidateCreated(__FILE__, __LINE__) - #define SQMOD_VALIDATE_PARAM(x, i) (x).ValidateParam((i), __FILE__, __LINE__) - #define SQMOD_VALIDATE_COLUMN(x, i) (x).ValidateColumn((i), __FILE__, __LINE__) - #define SQMOD_VALIDATE_ROW(x) (x).ValidateRow(__FILE__, __LINE__) - #define SQMOD_GET_VALID(x) (x).GetValid(__FILE__, __LINE__) - #define SQMOD_GET_CREATED(x) (x).GetCreated(__FILE__, __LINE__) -#else - #define SQMOD_THROW_CURRENT(x, a) (x).ThrowCurrent(a) - #define SQMOD_VALIDATE(x) (x).Validate() - #define SQMOD_VALIDATE_CREATED(x) (x).ValidateCreated() - #define SQMOD_VALIDATE_PARAM(x, i) (x).ValidateParam((i)) - #define SQMOD_VALIDATE_COLUMN(x, i) (x).ValidateColumn((i)) - #define SQMOD_VALIDATE_ROW(x) (x).ValidateRow() - #define SQMOD_GET_VALID(x) (x).GetValid() - #define SQMOD_GET_CREATED(x) (x).GetCreated() -#endif // _DEBUG - -/* ------------------------------------------------------------------------------------------------ - * Helper macros for architecture differences. -*/ - -#ifdef _SQ64 - #define sqlite3_bind_integer sqlite3_bind_int64 - #define sqlite3_column_integer sqlite3_column_int64 -#else - #define sqlite3_bind_integer sqlite3_bind_int - #define sqlite3_column_integer sqlite3_column_int -#endif - -/* ------------------------------------------------------------------------------------------------ - * Forward declarations. -*/ -struct ConnHnd; -struct StmtHnd; - -/* ------------------------------------------------------------------------------------------------ - * Common typedefs. -*/ -typedef SharedPtr< ConnHnd > ConnRef; -typedef SharedPtr< StmtHnd > StmtRef; - -/* ------------------------------------------------------------------------------------------------ - * Obtain a script object from a connection handle. (meant to avoid having to include the header) -*/ -Object GetConnectionObj(const ConnRef & conn); - -/* ------------------------------------------------------------------------------------------------ - * Obtain a script object from a statement handle. (meant to avoid having to include the header) -*/ -Object GetStatementObj(const StmtRef & stmt); - -/* ------------------------------------------------------------------------------------------------ - * Generate a formatted query. -*/ -CSStr QFmtStr(CSStr str, ...); - -/* ------------------------------------------------------------------------------------------------ - * Tests if a certain query string is empty. -*/ -bool IsQueryEmpty(CSStr str); - -/* ------------------------------------------------------------------------------------------------ - * Retrieve the string representation of a certain status code. -*/ -CSStr GetErrStr(Int32 status); - -/* ------------------------------------------------------------------------------------------------ - * Set a specific heap limit. -*/ -void SetSoftHeapLimit(Int32 limit); - -/* ------------------------------------------------------------------------------------------------ - * Release the specified amount of memory. -*/ -Int32 ReleaseMemory(Int32 bytes); - -/* ------------------------------------------------------------------------------------------------ - * Retrieve the current memory usage. -*/ -Object GetMemoryUsage(); - -/* ------------------------------------------------------------------------------------------------ - * Retrieve the memory high watermark. -*/ -Object GetMemoryHighwaterMark(bool reset); - -/* ------------------------------------------------------------------------------------------------ - * Retrieve the escaped version of the specified string. -*/ -CSStr EscapeString(StackStrF & str); - -/* ------------------------------------------------------------------------------------------------ - * Retrieve the escaped version of the specified string using the supplied format specifier. -*/ -CCStr EscapeStringEx(SQChar spec, StackStrF & str); - -/* ------------------------------------------------------------------------------------------------ - * Convert the values from the specified array to a list of column names string. -*/ -CCStr ArrayToQueryColumns(Array & arr); - -/* ------------------------------------------------------------------------------------------------ - * Convert the keys from the specified array to a list of column names string. -*/ -CCStr TableToQueryColumns(Table & tbl); - -} // Namespace:: SqMod diff --git a/module/Library/SQLite/Connection.cpp b/module/Library/SQLite/Connection.cpp deleted file mode 100644 index f087aaac..00000000 --- a/module/Library/SQLite/Connection.cpp +++ /dev/null @@ -1,407 +0,0 @@ -// ------------------------------------------------------------------------------------------------ -#include "Library/SQLite/Connection.hpp" -#include "Library/SQLite/Statement.hpp" - -// ------------------------------------------------------------------------------------------------ -namespace SqMod { - -// ------------------------------------------------------------------------------------------------ -SQMODE_DECL_TYPENAME(Typename, _SC("SqLiteConnection")) - -// ------------------------------------------------------------------------------------------------ -void Connection::TraceOutput(void * /*ptr*/, CCStr sql) -{ - LogInf("SQLite Trace: %s", sql); -} - -// ------------------------------------------------------------------------------------------------ -void Connection::ProfileOutput(void * /*ptr*/, CCStr sql, sqlite3_uint64 time) -{ - LogInf("SQLite profile (time: %llu): %s", time, sql); -} - -// ------------------------------------------------------------------------------------------------ -#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) -void Connection::Validate(CCStr file, Int32 line) const -{ - if (!m_Handle) - { - SqThrowF("Invalid SQLite connection reference =>[%s:%d]", file, line); - } -} -#else -void Connection::Validate() const -{ - if (!m_Handle) - { - SqThrowF("Invalid SQLite connection reference"); - } -} -#endif // _DEBUG - -// ------------------------------------------------------------------------------------------------ -#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) -void Connection::ValidateCreated(CCStr file, Int32 line) const -{ - if (!m_Handle) - { - SqThrowF("Invalid SQLite connection reference =>[%s:%d]", file, line); - } - else if (m_Handle->mPtr == nullptr) - { - SqThrowF("Invalid SQLite connection =>[%s:%d]", file, line); - } -} -#else -void Connection::ValidateCreated() const -{ - if (!m_Handle) - { - SqThrowF("Invalid SQLite connection reference"); - } - else if (m_Handle->mPtr == nullptr) - { - SqThrowF("Invalid SQLite connection"); - } -} -#endif // _DEBUG - -// ------------------------------------------------------------------------------------------------ -#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) -const ConnRef & Connection::GetValid(CCStr file, Int32 line) const -{ - Validate(file, line); - return m_Handle; -} -#else -const ConnRef & Connection::GetValid() const -{ - Validate(); - return m_Handle; -} -#endif // _DEBUG - -// ------------------------------------------------------------------------------------------------ -#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) -const ConnRef & Connection::GetCreated(CCStr file, Int32 line) const -{ - ValidateCreated(file, line); - return m_Handle; -} -#else -const ConnRef & Connection::GetCreated() const -{ - ValidateCreated(); - return m_Handle; -} -#endif // _DEBUG - -// ------------------------------------------------------------------------------------------------ -void Connection::Open(StackStrF & name) -{ - // Should we create a connection handle? - if (!m_Handle) - { - m_Handle = ConnRef(new ConnHnd()); - } - // 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 Connection::Open(StackStrF & name, Int32 flags) -{ - // Should we create a connection handle? - if (!m_Handle) - { - m_Handle = ConnRef(new ConnHnd()); - } - // 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 Connection::Open(StackStrF & name, Int32 flags, StackStrF & vfs) -{ - // Should we create a connection handle? - if (!m_Handle) - { - m_Handle = ConnRef(new ConnHnd()); - } - // 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 Connection::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 [%s]", m_Handle->ErrMsg()); - } - // Return rows affected by this query - return sqlite3_changes(m_Handle->mPtr); -} - -// ------------------------------------------------------------------------------------------------ -Object Connection::Query(StackStrF & str) const -{ - SQMOD_VALIDATE_CREATED(*this); - // Return the requested information - return Object(new Statement(m_Handle, str)); -} - -// ------------------------------------------------------------------------------------------------ -void Connection::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 Connection::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 Connection::TableExists(StackStrF & name) const -{ - StackStrF query("SELECT count(*) FROM [sqlite_master] WHERE [type]='table' AND [name]=?"); - // Prepare a statement to inspect the master table - Statement stmt(SQMOD_GET_CREATED(*this), query); - // Could the statement be created? - if (stmt.IsValid()) - { - // Bind the specified name onto the statement parameter - Parameter(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 Connection::SetTracing(bool toggle) -{ - // 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, &Connection::TraceOutput, nullptr); - } -} - -// ------------------------------------------------------------------------------------------------ -void Connection::SetProfiling(bool toggle) -{ - // 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, &Connection::ProfileOutput, nullptr); - } -} - -// ------------------------------------------------------------------------------------------------ -void Connection::SetBusyTimeout(Int32 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 [%s]", m_Handle->ErrMsg()); - } -} - -// ------------------------------------------------------------------------------------------------ -Int32 Connection::GetInfo(Int32 operation, bool highwater, bool reset) -{ - // Where to retrieve the information - Int32 cur_value; - Int32 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 Connection::ReserveQueue(Uint32 num) -{ - SQMOD_VALIDATE(*this); - // Perform the requested operation - m_Handle->mQueue.reserve(m_Handle->mQueue.size() + num); -} - -// ------------------------------------------------------------------------------------------------ -void Connection::PopQueue() -{ - SQMOD_VALIDATE(*this); - // Perform the requested operation - if (!SQMOD_GET_VALID(*this)->mQueue.empty()) - { - m_Handle->mQueue.pop_back(); - } -} - -// ------------------------------------------------------------------------------------------------ -Int32 Connection::Flush() -{ - SQMOD_VALIDATE_CREATED(*this); - // Perform the requested operation - return m_Handle->Flush(m_Handle->mQueue.size(), NullObject(), NullFunction()); -} - -// ------------------------------------------------------------------------------------------------ -Int32 Connection::Flush(SQInteger num) -{ - SQMOD_VALIDATE_CREATED(*this); - // Perform the requested operation - return m_Handle->Flush(ConvTo< Uint32 >::From(num), NullObject(), NullFunction()); -} - -// ------------------------------------------------------------------------------------------------ -Int32 Connection::Flush(Object & env, Function & func) -{ - SQMOD_VALIDATE_CREATED(*this); - // Perform the requested operation - return m_Handle->Flush(m_Handle->mQueue.size(), env, func); -} - -// ------------------------------------------------------------------------------------------------ -Int32 Connection::Flush(SQInteger num, Object & env, Function & func) -{ - SQMOD_VALIDATE_CREATED(*this); - // Perform the requested operation - return m_Handle->Flush(ConvTo< Uint32 >::From(num), env, func); -} - -// ================================================================================================ -void Register_Connection(Table & sqlns) -{ - sqlns.Bind(_SC("Connection"), - Class< Connection >(sqlns.GetVM(), Typename::Str) - // Constructors - .Ctor() - .Ctor< StackStrF & >() - .Ctor< StackStrF &, Int32 >() - .Ctor< StackStrF &, Int32, StackStrF & >() - // Meta-methods - .SquirrelFunc(_SC("_typename"), &Typename::Fn) - .Func(_SC("_tostring"), &Connection::ToString) - // Properties - .Prop(_SC("IsValid"), &Connection::IsValid) - .Prop(_SC("Connected"), &Connection::IsConnected) - .Prop(_SC("References"), &Connection::GetRefCount) - .Prop(_SC("Status"), &Connection::GetStatus) - .Prop(_SC("Flags"), &Connection::GetFlags) - .Prop(_SC("Name"), &Connection::GetName) - .Prop(_SC("VFS"), &Connection::GetVFS) - .Prop(_SC("ErrCode"), &Connection::GetErrorCode) - .Prop(_SC("ExErrCode"), &Connection::GetExtendedErrorCode) - .Prop(_SC("ExtendedErrCode"), &Connection::GetExtendedErrorCode) - .Prop(_SC("ErrStr"), &Connection::GetErrStr) - .Prop(_SC("ErrMsg"), &Connection::GetErrMsg) - .Prop(_SC("ReadOnly"), &Connection::IsReadOnly) - .Prop(_SC("Autocommit"), &Connection::GetAutoCommit) - .Prop(_SC("LastInsertRowId"), &Connection::GetLastInsertRowID) - .Prop(_SC("Changes"), &Connection::GetChanges) - .Prop(_SC("TotalChanges"), &Connection::GetTotalChanges) - .Prop(_SC("Trace"), &Connection::GetTracing, &Connection::SetTracing) - .Prop(_SC("Profile"), &Connection::GetProfiling, &Connection::SetProfiling) - .Prop(_SC("QueueSize"), &Connection::QueueSize) - // Member Methods - .Func(_SC("Release"), &Connection::Release) - .FmtFunc(_SC("Exec"), &Connection::Exec) - .FmtFunc(_SC("Queue"), &Connection::Queue) - .FmtFunc(_SC("Query"), &Connection::Query) - .FmtFunc(_SC("TableExists"), &Connection::TableExists) - .Func(_SC("InterruptOperation"), &Connection::InterruptOperation) - .Func(_SC("SetBusyTimeout"), &Connection::SetBusyTimeout) - .Func(_SC("ReleaseMemory"), &Connection::ReleaseMemory) - .Func(_SC("ReserveQueue"), &Connection::ReserveQueue) - .Func(_SC("CompactQueue"), &Connection::CompactQueue) - .Func(_SC("ClearQueue"), &Connection::ClearQueue) - .Func(_SC("PopQueue"), &Connection::PopQueue) - // Member Overloads - .Overload< void (Connection::*)(StackStrF &) >(_SC("Open"), &Connection::Open) - .Overload< void (Connection::*)(StackStrF &, Int32) >(_SC("Open"), &Connection::Open) - .Overload< void (Connection::*)(StackStrF &, Int32, StackStrF &) >(_SC("Open"), &Connection::Open) - .Overload< Int32 (Connection::*)(Int32) >(_SC("GetInfo"), &Connection::GetInfo) - .Overload< Int32 (Connection::*)(Int32, bool) >(_SC("GetInfo"), &Connection::GetInfo) - .Overload< Int32 (Connection::*)(Int32, bool, bool) >(_SC("GetInfo"), &Connection::GetInfo) - .Overload< Int32 (Connection::*)(void) >(_SC("Flush"), &Connection::Flush) - .Overload< Int32 (Connection::*)(SQInteger) >(_SC("Flush"), &Connection::Flush) - .Overload< Int32 (Connection::*)(Object &, Function &) >(_SC("Flush"), &Connection::Flush) - .Overload< Int32 (Connection::*)(SQInteger, Object &, Function &) >(_SC("Flush"), &Connection::Flush) - ); -} - -} // Namespace:: SqMod diff --git a/module/Library/SQLite/Connection.hpp b/module/Library/SQLite/Connection.hpp deleted file mode 100644 index 79cfc8b8..00000000 --- a/module/Library/SQLite/Connection.hpp +++ /dev/null @@ -1,481 +0,0 @@ -#pragma once - -// ------------------------------------------------------------------------------------------------ -#include "Library/SQLite/Handle.hpp" - -// ------------------------------------------------------------------------------------------------ -#include - -// ------------------------------------------------------------------------------------------------ -namespace SqMod { - -/* ------------------------------------------------------------------------------------------------ - * Used to manage and interact with a database connection. -*/ -class Connection -{ -private: - - // -------------------------------------------------------------------------------------------- - ConnRef m_Handle; // Reference to the managed connection. - -protected: - - /* -------------------------------------------------------------------------------------------- - * Callback function for ActivateTracing() - */ - static void TraceOutput(void * ptr, CCStr sql); - - /* -------------------------------------------------------------------------------------------- - * Callback function for ActivateProfiling() - */ - static void ProfileOutput(void * ptr, CCStr sql, sqlite3_uint64 time); - - /* -------------------------------------------------------------------------------------------- - * Validate the managed connection handle and throw an error if invalid. - */ -#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) - void Validate(CCStr file, Int32 line) const; -#else - void Validate() const; -#endif // _DEBUG - - /* -------------------------------------------------------------------------------------------- - * Validate the managed connection handle and throw an error if invalid. - */ -#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) - void ValidateCreated(CCStr file, Int32 line) const; -#else - void ValidateCreated() const; -#endif // _DEBUG - - /* -------------------------------------------------------------------------------------------- - * Validate the managed connection handle and throw an error if invalid. - */ -#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) - const ConnRef & GetValid(CCStr file, Int32 line) const; -#else - const ConnRef & GetValid() const; -#endif // _DEBUG - - /* -------------------------------------------------------------------------------------------- - * Validate the managed connection handle and throw an error if invalid. - */ -#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) - const ConnRef & GetCreated(CCStr file, Int32 line) const; -#else - const ConnRef & GetCreated() const; -#endif // _DEBUG - -public: - - /* -------------------------------------------------------------------------------------------- - * Attempt to open the specified database. - */ - Connection() - : m_Handle() - { - /* ... */ - } - - /* -------------------------------------------------------------------------------------------- - * Explicit constructor. - */ - explicit Connection(StackStrF & name) - : m_Handle(new ConnHnd()) - { - // 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; - SQMOD_GET_VALID(*this)->Create(name.mPtr, OPEN_READWRITE_F | OPEN_CREATE_F, nullptr); - } - - /* -------------------------------------------------------------------------------------------- - * Explicit constructor. - */ - Connection(StackStrF & name, Int32 flags) - : m_Handle(new ConnHnd()) - { - SQMOD_GET_VALID(*this)->Create(name.mPtr, flags, nullptr); - } - - /* -------------------------------------------------------------------------------------------- - * Explicit constructor. - */ - Connection(StackStrF & name, Int32 flags, StackStrF & vfs) - : m_Handle(new ConnHnd()) - { - SQMOD_GET_VALID(*this)->Create(name.mPtr, flags, vfs.mPtr); - } - - /* -------------------------------------------------------------------------------------------- - * Direct handle constructor. - */ - explicit Connection(ConnRef c) - : m_Handle(std::move(c)) - { - /* ... */ - } - - /* -------------------------------------------------------------------------------------------- - * Copy constructor. - */ - Connection(const Connection & o) = default; - - /* -------------------------------------------------------------------------------------------- - * Move constructor. - */ - Connection(Connection && o) = default; - - /* -------------------------------------------------------------------------------------------- - * Copy assignment operator. - */ - Connection & operator = (const Connection & o) = default; - - /* -------------------------------------------------------------------------------------------- - * Move assignment operator. - */ - Connection & operator = (Connection && o) = default; - - /* -------------------------------------------------------------------------------------------- - * Perform an equality comparison between two connections. - */ - bool operator == (const Connection & o) const - { - return (m_Handle == o.m_Handle); - } - - /* -------------------------------------------------------------------------------------------- - * Perform an inequality comparison between two connections. - */ - bool operator != (const Connection & o) const - { - return (m_Handle != o.m_Handle); - } - - /* -------------------------------------------------------------------------------------------- - * Implicit conversion to the raw connection handle. - */ - operator sqlite3 * () //NOLINT (intentionally implicit) - { - return m_Handle ? m_Handle->mPtr : nullptr; - } - - /* -------------------------------------------------------------------------------------------- - * Implicit conversion to the raw connection handle. - */ - operator sqlite3 * () const //NOLINT (intentionally implicit) - { - return m_Handle ? m_Handle->mPtr : nullptr; - } - - /* -------------------------------------------------------------------------------------------- - * Used by the script engine to convert an instance of this type to a string. - */ - const String & ToString() const - { - return m_Handle ? m_Handle->mName : NullString(); - } - - /* -------------------------------------------------------------------------------------------- - * Retrieve the associated connection handle. - */ - const ConnRef & GetHandle() const - { - return m_Handle; - } - - /* -------------------------------------------------------------------------------------------- - * See whether the managed connection handle is valid. - */ - bool IsValid() const - { - return m_Handle; - } - - /* -------------------------------------------------------------------------------------------- - * See whether the managed connection handle was connected. - */ - bool IsConnected() const - { - return m_Handle && (m_Handle->mPtr != nullptr); - } - - /* -------------------------------------------------------------------------------------------- - * Return the number of active references to this connection handle. - */ - Uint32 GetRefCount() const - { - return m_Handle.Count(); - } - - /* -------------------------------------------------------------------------------------------- - * Release the reference to the associated database connection. - */ - void Release() - { - m_Handle.Reset(); - } - - /* -------------------------------------------------------------------------------------------- - * Retrieve the last received status code. - */ - Int32 GetStatus() const - { - return SQMOD_GET_VALID(*this)->mStatus; - } - - /* -------------------------------------------------------------------------------------------- - * Retrieve the flags used to create this database connection. - */ - Int32 GetFlags() const - { - return SQMOD_GET_VALID(*this)->mFlags; - } - - /* -------------------------------------------------------------------------------------------- - * Retrieve the name used to create this database connection. - */ - const String & GetName() const - { - return SQMOD_GET_VALID(*this)->mName; - } - - /* -------------------------------------------------------------------------------------------- - * Retrieve the virtual file system used to create this database connection. - */ - const String & GetVFS() const - { - return SQMOD_GET_VALID(*this)->mVFS; - } - - /* -------------------------------------------------------------------------------------------- - * Return the numeric result code for the most recent failed API call (if any). - */ - Int32 GetErrorCode() const - { - return SQMOD_GET_VALID(*this)->ErrNo(); - } - - /* -------------------------------------------------------------------------------------------- - * Return the extended numeric result code for the most recent failed API call (if any). - */ - Int32 GetExtendedErrorCode() const - { - return SQMOD_GET_VALID(*this)->ExErrNo(); - } - - /* -------------------------------------------------------------------------------------------- - * Retrieve the message of the last received error code. - */ - CSStr GetErrStr() const - { - return SQMOD_GET_VALID(*this)->ErrStr(); - } - - /* -------------------------------------------------------------------------------------------- - * Return the last error message associated with this database connection. - */ - CSStr GetErrMsg() const - { - return SQMOD_GET_VALID(*this)->ErrMsg(); - } - - /* -------------------------------------------------------------------------------------------- - * Attempt to open the specified database. - */ - void Open(StackStrF & name); - - /* -------------------------------------------------------------------------------------------- - * Attempt to open the specified database. - */ - void Open(StackStrF & name, Int32 flags); - - /* -------------------------------------------------------------------------------------------- - * Attempt to open the specified database. - */ - void Open(StackStrF & name, Int32 flags, StackStrF & vfs); - - /* -------------------------------------------------------------------------------------------- - * Attempt to execute the specified query. - */ - Int32 Exec(StackStrF & str); - - /* -------------------------------------------------------------------------------------------- - * Attempt to queue the specified query. - */ - void Queue(StackStrF & str); - - /* -------------------------------------------------------------------------------------------- - * Attempt to create a statement from the specified query. - */ - Object Query(StackStrF & str) const; - - /* -------------------------------------------------------------------------------------------- - * See if the database connection was opened in read-only mode. - */ - bool IsReadOnly() const; - - /* -------------------------------------------------------------------------------------------- - * Shortcut to test if a table exists. - */ - bool TableExists(StackStrF & name) const; - - /* -------------------------------------------------------------------------------------------- - * See if the database connection is or is not in auto-commit mode. - */ - bool GetAutoCommit() const - { - return sqlite3_get_autocommit(SQMOD_GET_CREATED(*this)->mPtr); - } - - /* -------------------------------------------------------------------------------------------- - * Get the row-id of the most recent successful INSERT into the database from the current connection. - */ - Object GetLastInsertRowID() const - { - return Object(new SLongInt(sqlite3_last_insert_rowid(SQMOD_GET_CREATED(*this)->mPtr))); - } - - /* -------------------------------------------------------------------------------------------- - * Returns the number of database rows that were changed, inserted or deleted - * by the most recently completed SQL statement. - */ - Int32 GetChanges() const - { - return sqlite3_changes(SQMOD_GET_CREATED(*this)->mPtr); - } - - /* -------------------------------------------------------------------------------------------- - * Returns the total number of row changes caused by INSERT, UPDATE or DELETE statements - * since the database connection was opened. - */ - Int32 GetTotalChanges() const - { - return sqlite3_total_changes(SQMOD_GET_CREATED(*this)->mPtr); - } - - /* -------------------------------------------------------------------------------------------- - * See if this database connection has tracing enabled. - */ - bool GetTracing() const - { - return SQMOD_GET_VALID(*this)->mTrace; - } - - /* -------------------------------------------------------------------------------------------- - * Activate or deactivate tracing on this database connection. - */ - void SetTracing(bool toggle); - - /* -------------------------------------------------------------------------------------------- - * See if this database connection has profiling enabled. - */ - bool GetProfiling() const - { - return SQMOD_GET_VALID(*this)->mProfile; - } - - /* -------------------------------------------------------------------------------------------- - * Activate or deactivate profiling on this database connection. - */ - void SetProfiling(bool toggle); - - /* -------------------------------------------------------------------------------------------- - * Set a busy handler that sleeps for a specified amount of time when a table is locked. - */ - void SetBusyTimeout(Int32 millis); - - /* -------------------------------------------------------------------------------------------- - * Causes any pending database operation to abort and return at its earliest opportunity. - */ - void InterruptOperation() const - { - sqlite3_interrupt(SQMOD_GET_CREATED(*this)->mPtr); - } - - /* -------------------------------------------------------------------------------------------- - * Attempts to free as much heap memory as possible from the database connection. - */ - void ReleaseMemory() const - { - sqlite3_db_release_memory(SQMOD_GET_CREATED(*this)->mPtr); - } - - /* -------------------------------------------------------------------------------------------- - * Returns internal runtime status information associated with the current database connection. - */ - Int32 GetInfo(Int32 operation) - { - return GetInfo(operation, false, false); - } - - /* -------------------------------------------------------------------------------------------- - * Returns internal runtime status information associated with the current database connection. - */ - Int32 GetInfo(Int32 operation, bool highwater) - { - return GetInfo(operation, highwater, false); - } - - /* -------------------------------------------------------------------------------------------- - * Returns internal runtime status information associated with the current database connection. - */ - Int32 GetInfo(Int32 operation, bool highwater, bool reset); - - /* -------------------------------------------------------------------------------------------- - * Retrieve the number of queries in the queue. - */ - Uint32 QueueSize() const - { - return ConvTo< Uint32 >::From(SQMOD_GET_VALID(*this)->mQueue.size()); - } - - /* -------------------------------------------------------------------------------------------- - * Reserve space upfront for the specified amount of queries in the query queue. - */ - void ReserveQueue(Uint32 num); - - /* -------------------------------------------------------------------------------------------- - * Release memory that is not occupied from the query queue. - */ - void CompactQueue() - { - SQMOD_GET_VALID(*this)->mQueue.shrink_to_fit(); - } - - /* -------------------------------------------------------------------------------------------- - * Remove all queries from the queue without executing them. - */ - void ClearQueue() - { - SQMOD_GET_VALID(*this)->mQueue.clear(); - } - - /* -------------------------------------------------------------------------------------------- - * Remove the last query from the queue. - */ - void PopQueue(); - - /* -------------------------------------------------------------------------------------------- - * Flush all queries from the queue. - */ - Int32 Flush(); - - /* -------------------------------------------------------------------------------------------- - * Flush a specific amount of queries from the queue. - */ - Int32 Flush(SQInteger num); - - /* -------------------------------------------------------------------------------------------- - * Flush all queries from the queue and handle errors manually. - */ - Int32 Flush(Object & env, Function & func); - - /* -------------------------------------------------------------------------------------------- - * Flush a specific amount of queries from the queue and handle errors manually. - */ - Int32 Flush(SQInteger num, Object & env, Function & func); -}; - -} // Namespace:: SqMod diff --git a/module/Library/SQLite/Constants.cpp b/module/Library/SQLite/Constants.cpp deleted file mode 100644 index acac5897..00000000 --- a/module/Library/SQLite/Constants.cpp +++ /dev/null @@ -1,367 +0,0 @@ -// ------------------------------------------------------------------------------------------------ -#include "Library/SQLite/Common.hpp" - -// ------------------------------------------------------------------------------------------------ -namespace SqMod { - -/* ------------------------------------------------------------------------------------------------ - * Helper class that represents an integral enumeration value. Used to reduce compilation times. -*/ -struct EnumElement -{ - CSStr Name; - Int32 Value; -}; - -// ------------------------------------------------------------------------------------------------ -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} -}; - -// ================================================================================================ -void Register_Constants(Table & sqlns) -{ - Enumeration e(sqlns.GetVM()); - - for (Uint32 n = 0; n < (sizeof(g_MainEnum) / sizeof(EnumElement)); ++n) - { - e.Const(g_MainEnum[n].Name, g_MainEnum[n].Value); - } - - ConstTable(sqlns.GetVM()).Enum(_SC("ESQLite"), e); -} - -} // Namespace:: SqMod \ No newline at end of file diff --git a/module/Library/SQLite/Handle.cpp b/module/Library/SQLite/Handle.cpp deleted file mode 100644 index 04f7b073..00000000 --- a/module/Library/SQLite/Handle.cpp +++ /dev/null @@ -1,297 +0,0 @@ -// ------------------------------------------------------------------------------------------------ -#include "Library/SQLite/Handle.hpp" - -#include - -// ------------------------------------------------------------------------------------------------ -namespace SqMod { - -// ------------------------------------------------------------------------------------------------ -ConnHnd::ConnHnd() - : mPtr(nullptr) - , mStatus(SQLITE_OK) - , mQueue() - , mFlags(0) - , mName() - , mVFS() - , mMemory(false) - , mTrace(false) - , mProfile(false) -{ - /* ... */ -} - -// ------------------------------------------------------------------------------------------------ -ConnHnd::~ConnHnd() -{ - // Is there anything to close? - if (mPtr != nullptr) - { - // Flush remaining queries in the queue and ignore the result - Flush(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 ConnHnd::Create(CSStr name, Int32 flags, CSStr 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 [%s]", 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 ConnHnd::Flush(Uint32 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 = mQueue.size(); - } - // Generate the function that should be called upon error - Function callback = Function(env.GetVM(), env.GetObject(), func.GetFunc()); - // 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 [%s]", 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 [%s]", sqlite3_errmsg(mPtr)); - } - // The transaction failed somehow but we managed to rollback - else - { - STHROWF("Unable to commit flush transaction [%s]", sqlite3_errmsg(mPtr)); - } - // Operation failed - return -1; -} - -// ------------------------------------------------------------------------------------------------ -StmtHnd::StmtHnd(ConnRef conn) - : mPtr(nullptr) - , mStatus(SQLITE_OK) - , mConn(std::move(conn)) - , mQuery() - , mColumns(0) - , mParameters(0) - , mIndexes() - , mGood(false) - , mDone(false) -{ - /* ... */ -} - -// ------------------------------------------------------------------------------------------------ -StmtHnd::~StmtHnd() -{ - // 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 StmtHnd::Create(CSStr 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, length); - // Attempt to prepare a statement with the specified query string - if ((mStatus = sqlite3_prepare_v2(mConn->mPtr, mQuery.c_str(), ConvTo< Int32 >::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 [%s]", 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 StmtHnd::GetColumnIndex(CSStr name, SQInteger length) -{ - // Validate the handle - if (!mPtr) - { - STHROWF("Invalid SQLite statement"); - } - // Are the names cached? - else if (mIndexes.empty()) - { - for (Int32 i = 0; i < mColumns; ++i) - { - // Get the column name at the current index - auto column_name = static_cast< CSStr >(sqlite3_column_name(mPtr, i)); - // Validate the name - if (!column_name) - { - STHROWF("Unable to retrieve column name for index (%d)", 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 - const Indexes::iterator 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; -} - -// ------------------------------------------------------------------------------------------------ -CCStr StmtHnd::ErrStr() const -{ - return mConn ? sqlite3_errstr(sqlite3_errcode(mConn->mPtr)) : _SC(""); -} - -// ------------------------------------------------------------------------------------------------ -CCStr StmtHnd::ErrMsg() const -{ - return mConn ? sqlite3_errmsg(mConn->mPtr) : _SC(""); -} - -// ------------------------------------------------------------------------------------------------ -Int32 StmtHnd::ErrNo() const -{ - return mConn ? sqlite3_errcode(mConn->mPtr) : SQLITE_NOMEM; -} - -// ------------------------------------------------------------------------------------------------ -Int32 StmtHnd::ExErrNo() const -{ - return mConn ? sqlite3_extended_errcode(mConn->mPtr) : SQLITE_NOMEM; -} - -} // Namespace:: SqMod diff --git a/module/Library/SQLite/Handle.hpp b/module/Library/SQLite/Handle.hpp deleted file mode 100644 index 011ca77d..00000000 --- a/module/Library/SQLite/Handle.hpp +++ /dev/null @@ -1,249 +0,0 @@ -#pragma once - -// ------------------------------------------------------------------------------------------------ -#include "Library/SQLite/Common.hpp" - -// ------------------------------------------------------------------------------------------------ -#include -#include - -// ------------------------------------------------------------------------------------------------ -namespace SqMod { - -/* ------------------------------------------------------------------------------------------------ - * The structure that holds the data associated with a certain connection. -*/ -struct ConnHnd -{ -public: - - // -------------------------------------------------------------------------------------------- - typedef sqlite3 Type; // The managed type. - - // -------------------------------------------------------------------------------------------- - typedef Type* Pointer; // Pointer to the managed type. - typedef const Type* ConstPtr; // Constant pointer to the managed type. - - // -------------------------------------------------------------------------------------------- - typedef Type& Reference; // Reference to the managed type. - typedef const Type& ConstRef; // Constant reference to the managed type. - - // -------------------------------------------------------------------------------------------- - typedef std::vector< String > QueryList; // Container used to queue queries. - -public: - - // -------------------------------------------------------------------------------------------- - Pointer mPtr; // The connection handle resource. - - // -------------------------------------------------------------------------------------------- - Int32 mStatus; // The last status code of this connection handle. - - // -------------------------------------------------------------------------------------------- - QueryList mQueue; // A queue of queries to be executed in groups. - - // -------------------------------------------------------------------------------------------- - Int32 mFlags; // The flags used to create the database connection handle. - String mName; // The specified name to be used as the database file. - String mVFS; // The specified virtual file system. - - // -------------------------------------------------------------------------------------------- - bool mMemory; // Whether the database exists in memory and not disk. - bool mTrace; // Whether tracing was activated on the database. - bool mProfile; // Whether profiling was activated on the database. - - /* -------------------------------------------------------------------------------------------- - * Default constructor. - */ - ConnHnd(); - - /* -------------------------------------------------------------------------------------------- - * Copy constructor. (disabled) - */ - ConnHnd(const ConnHnd & o) = delete; - - /* -------------------------------------------------------------------------------------------- - * Move constructor. (disabled) - */ - ConnHnd(ConnHnd && o) = delete; - - /* -------------------------------------------------------------------------------------------- - * Destructor. - */ - ~ConnHnd(); - - /* -------------------------------------------------------------------------------------------- - * Copy assignment operator. (disabled) - */ - ConnHnd & operator = (const ConnHnd & o) = delete; - - /* -------------------------------------------------------------------------------------------- - * Move assignment operator. (disabled) - */ - ConnHnd & operator = (ConnHnd && o) = delete; - - /* -------------------------------------------------------------------------------------------- - * Create the database connection resource. - */ - void Create(CSStr name, Int32 flags, CSStr vfs); - - /* -------------------------------------------------------------------------------------------- - * Execute a specific amount of queries from the queue. - */ - Int32 Flush(Uint32 num, Object & env, Function & func); - - /* -------------------------------------------------------------------------------------------- - * Retrieve the message of the last received error code. - */ - CCStr ErrStr() const - { - return sqlite3_errstr(sqlite3_errcode(mPtr)); - } - - /* -------------------------------------------------------------------------------------------- - * Return the last error message associated with this database connection. - */ - CCStr ErrMsg() const - { - return sqlite3_errmsg(mPtr); - } - - /* -------------------------------------------------------------------------------------------- - * Return the numeric result code for the most recent failed API call (if any). - */ - Int32 ErrNo() const - { - return sqlite3_errcode(mPtr); - } - - /* -------------------------------------------------------------------------------------------- - * Return the extended numeric result code for the most recent failed API call (if any). - */ - Int32 ExErrNo() const - { - return sqlite3_extended_errcode(mPtr); - } -}; - -/* ------------------------------------------------------------------------------------------------ - * The structure that holds the data associated with a certain statement. -*/ -struct StmtHnd -{ -public: - - // -------------------------------------------------------------------------------------------- - typedef sqlite3_stmt Type; // The managed type. - - // -------------------------------------------------------------------------------------------- - typedef Type* Pointer; // Pointer to the managed type. - typedef const Type* ConstPtr; // Constant pointer to the managed type. - - // -------------------------------------------------------------------------------------------- - typedef Type& Reference; // Reference to the managed type. - typedef const Type& ConstRef; // Constant reference to the managed type. - - // -------------------------------------------------------------------------------------------- - typedef std::map< String, int > Indexes; // Container used to identify column indexes. - -public: - - // -------------------------------------------------------------------------------------------- - Pointer mPtr; // The statement handle resource. - - // -------------------------------------------------------------------------------------------- - Int32 mStatus; // The last status code of this connection handle. - - // -------------------------------------------------------------------------------------------- - ConnRef mConn; // The handle to the associated database connection. - - // -------------------------------------------------------------------------------------------- - String mQuery; // The query string used to create this statement. - - // -------------------------------------------------------------------------------------------- - Int32 mColumns; // The amount of columns available in this statement. - Int32 mParameters; // The amount of parameters available in this statement. - Indexes mIndexes; // An associative container with column names and their index. - - // -------------------------------------------------------------------------------------------- - bool mGood; // True when a row has been fetched with step. - bool mDone; // True when the last step had no more rows to fetch. - - /* -------------------------------------------------------------------------------------------- - * Default constructor. - */ - StmtHnd(ConnRef conn); - - /* -------------------------------------------------------------------------------------------- - * Copy constructor. (disabled) - */ - StmtHnd(const StmtHnd & o) = delete; - - /* -------------------------------------------------------------------------------------------- - * Move constructor. (disabled) - */ - StmtHnd(StmtHnd && o) = delete; - - /* -------------------------------------------------------------------------------------------- - * Destructor. - */ - ~StmtHnd(); - - /* -------------------------------------------------------------------------------------------- - * Copy assignment operator. (disabled) - */ - StmtHnd & operator = (const StmtHnd & o) = delete; - - /* -------------------------------------------------------------------------------------------- - * Move assignment operator. (disabled) - */ - StmtHnd & operator = (StmtHnd && o) = delete; - - /* -------------------------------------------------------------------------------------------- - * Create the database statement resource. - */ - void Create(CSStr query, SQInteger length = -1); - - /* -------------------------------------------------------------------------------------------- - * Check whether a specific column index is in range. - */ - bool CheckColumn(Int32 idx) const - { - return (idx >= 0) && (idx < mColumns); - } - - /* -------------------------------------------------------------------------------------------- - * Check whether a specific parameter index is in range. - */ - bool CheckParameter(Int32 idx) const - { - return (idx >= 1) && (idx <= mParameters); - } - - /* -------------------------------------------------------------------------------------------- - * Retrieve the column index associated with the specified name. - */ - Int32 GetColumnIndex(CSStr name, SQInteger length = -1); - - /* -------------------------------------------------------------------------------------------- - * Retrieve the message of the last received error code. - */ - CCStr ErrStr() const; - - /* -------------------------------------------------------------------------------------------- - * Return the last error message associated with this database connection. - */ - CCStr ErrMsg() const; - - /* -------------------------------------------------------------------------------------------- - * Return the numeric result code for the most recent failed API call (if any). - */ - Int32 ErrNo() const; - - /* -------------------------------------------------------------------------------------------- - * Return the extended numeric result code for the most recent failed API call (if any). - */ - Int32 ExErrNo() const; -}; - -} // Namespace:: SqMod diff --git a/module/Library/SQLite/Parameter.cpp b/module/Library/SQLite/Parameter.cpp deleted file mode 100644 index 0288bb71..00000000 --- a/module/Library/SQLite/Parameter.cpp +++ /dev/null @@ -1,789 +0,0 @@ -// ------------------------------------------------------------------------------------------------ -#include "Library/SQLite/Parameter.hpp" - -// ------------------------------------------------------------------------------------------------ -#include - -// ------------------------------------------------------------------------------------------------ -#include - -// ------------------------------------------------------------------------------------------------ -namespace SqMod { - -// ------------------------------------------------------------------------------------------------ -// Error message when failed to bind value to parameter index. -#define SQMOD_BINDFAILED "Unable to bind (%s) parameter (%d) because [%s]" - -// ------------------------------------------------------------------------------------------------ -SQMODE_DECL_TYPENAME(Typename, _SC("SqLiteParameter")) - -// ------------------------------------------------------------------------------------------------ -static inline bool IsDigitsOnly(CSStr str) -{ - while (std::isdigit(*str) || std::isspace(*str)) - { - ++str; - } - // Return whether we reached the end while searching - return *str == '\0'; -} - -// ------------------------------------------------------------------------------------------------ -#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) -void Parameter::Validate(CCStr file, Int32 line) const -{ - // Are we pointing to a valid index? - if (m_Index < 0) - { - SqThrowF("Invalid column index: %d < 0 =>[%s:%d]", m_Index, file, line); - } - // Do we have a valid statement handle? - else if (!m_Handle) - { - SqThrowF("Invalid SQLite statement reference =>[%s:%d]", file, line); - } -} -#else -void Parameter::Validate() const -{ - // Are we pointing to a valid index? - if (m_Index < 0) - { - SqThrowF("Invalid column index: %d < 0", m_Index); - } - // Do we have a valid statement handle? - else if (!m_Handle) - { - SqThrowF("Invalid SQLite statement reference"); - } -} -#endif // _DEBUG - -// ------------------------------------------------------------------------------------------------ -#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) -void Parameter::ValidateCreated(CCStr file, Int32 line) const -{ - // Are we pointing to a valid index? - if (m_Index < 0) - { - SqThrowF("Invalid column index: %d < 0 =>[%s:%d]", m_Index, file, line); - } - else if (!m_Handle) - { - SqThrowF("Invalid SQLite statement reference =>[%s:%d]", file, line); - } - else if (m_Handle->mPtr == nullptr) - { - SqThrowF("Invalid SQLite statement =>[%s:%d]", file, line); - } -} -#else -void Parameter::ValidateCreated() const -{ - // Are we pointing to a valid index? - if (m_Index < 0) - { - SqThrowF("Invalid column index: %d < 0", m_Index); - } - else if (!m_Handle) - { - SqThrowF("Invalid SQLite statement reference"); - } - else if (m_Handle->mPtr == nullptr) - { - SqThrowF("Invalid SQLite statement"); - } -} -#endif // _DEBUG - -// ------------------------------------------------------------------------------------------------ -#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) -const StmtRef & Parameter::GetValid(CCStr file, Int32 line) const -{ - Validate(file, line); - return m_Handle; -} -#else -const StmtRef & Parameter::GetValid() const -{ - Validate(); - return m_Handle; -} -#endif // _DEBUG - -// ------------------------------------------------------------------------------------------------ -#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) -const StmtRef & Parameter::GetCreated(CCStr file, Int32 line) const -{ - ValidateCreated(file, line); - return m_Handle; -} -#else -const StmtRef & Parameter::GetCreated() const -{ - ValidateCreated(); - return m_Handle; -} -#endif // _DEBUG - -// ------------------------------------------------------------------------------------------------ -#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) -void Parameter::ValidateParam(Int32 idx, CCStr file, Int32 line) const -{ - ValidateCreated(file, line); - // Is the specified index in range? - if (!m_Handle->CheckParameter(idx)) - { - SqThrowF("Parameter index is out of range (%d:%d) =>[%s:%d]", idx, m_Handle->mParameters, - file, line); - } -} -#else -void Parameter::ValidateParam(Int32 idx) const -{ - ValidateCreated(); - // Is the specified index in range? - if (!m_Handle->CheckParameter(idx)) - { - SqThrowF("Parameter index is out of range (%d:%d)", idx, m_Handle->mParameters); - } -} -#endif // _DEBUG - -// ------------------------------------------------------------------------------------------------ -void Parameter::SetIndex(const Object & param) -{ - // Where the index will be extracted - Int32 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("%s", LastErrorString(vm).c_str()); - } - // 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 >::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("%s", LastErrorString(vm).c_str()); - } - // 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 >::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 (%s)", SqTypeName(param.GetType())); - } - // Assign the index with a failsafe to invalid on error - AutoAssign< Int32 > 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 Parameter::GetStatement() const -{ - return GetStatementObj(m_Handle); -} - -// ------------------------------------------------------------------------------------------------ -Object Parameter::GetConnection() const -{ - return GetConnectionObj(SQMOD_GET_VALID(*this)->mConn); -} - -// ------------------------------------------------------------------------------------------------ -void Parameter::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(DefaultVM::Get(), value); - // Pop the object from the stack as a string - const Var< CSStr > str(DefaultVM::Get(), -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 Parameter::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 Parameter::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 Parameter::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 Parameter::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 >::From(value)); - // Validate the result - if (m_Handle->mStatus != SQLITE_OK) - { - STHROWF(SQMOD_BINDFAILED, "int8", m_Index, m_Handle->ErrMsg()); - } -} - -// ------------------------------------------------------------------------------------------------ -void Parameter::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 >::From(value)); - // Validate the result - if (m_Handle->mStatus != SQLITE_OK) - { - STHROWF(SQMOD_BINDFAILED, "uint8", m_Index, m_Handle->ErrMsg()); - } -} - -// ------------------------------------------------------------------------------------------------ -void Parameter::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 >::From(value)); - // Validate the result - if (m_Handle->mStatus != SQLITE_OK) - { - STHROWF(SQMOD_BINDFAILED, "int16", m_Index, m_Handle->ErrMsg()); - } -} - -// ------------------------------------------------------------------------------------------------ -void Parameter::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 >::From(value)); - // Validate the result - if (m_Handle->mStatus != SQLITE_OK) - { - STHROWF(SQMOD_BINDFAILED, "uint16", m_Index, m_Handle->ErrMsg()); - } -} - -// ------------------------------------------------------------------------------------------------ -void Parameter::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 >::From(value)); - // Validate the result - if (m_Handle->mStatus != SQLITE_OK) - { - STHROWF(SQMOD_BINDFAILED, "int32", m_Index, m_Handle->ErrMsg()); - } -} - -// ------------------------------------------------------------------------------------------------ -void Parameter::SetUint32(SQInteger value) -{ - SQMOD_VALIDATE_CREATED(*this); - // Attempt to bind the specified value - m_Handle->mStatus = sqlite3_bind_int(m_Handle->mPtr, m_Index, ConvTo< Uint32 >::From(value)); - // Validate the result - if (m_Handle->mStatus != SQLITE_OK) - { - STHROWF(SQMOD_BINDFAILED, "uint32", m_Index, m_Handle->ErrMsg()); - } -} - -// ------------------------------------------------------------------------------------------------ -void Parameter::SetInt64(const Object & value) -{ - SQMOD_VALIDATE_CREATED(*this); - // Attempt to bind the specified value - m_Handle->mStatus = sqlite3_bind_int64(m_Handle->mPtr, m_Index, value.Cast< const SLongInt & >().GetNum()); - // Validate the result - if (m_Handle->mStatus != SQLITE_OK) - { - STHROWF(SQMOD_BINDFAILED, "int64", m_Index, m_Handle->ErrMsg()); - } -} - -// ------------------------------------------------------------------------------------------------ -void Parameter::SetUint64(const Object & value) -{ - SQMOD_VALIDATE_CREATED(*this); - // Attempt to bind the specified value - m_Handle->mStatus = sqlite3_bind_int64(m_Handle->mPtr, m_Index, value.Cast< const ULongInt & >().GetNum()); - // Validate the result - if (m_Handle->mStatus != SQLITE_OK) - { - STHROWF(SQMOD_BINDFAILED, "uint64", m_Index, m_Handle->ErrMsg()); - } -} - -// ------------------------------------------------------------------------------------------------ -void Parameter::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 Parameter::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< Float32 >::From(value)); - // Validate the result - if (m_Handle->mStatus != SQLITE_OK) - { - STHROWF(SQMOD_BINDFAILED, "float32", m_Index, m_Handle->ErrMsg()); - } -} - -// ------------------------------------------------------------------------------------------------ -void Parameter::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 Parameter::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, value.mLen, SQLITE_TRANSIENT); - // Validate the result - if (m_Handle->mStatus != SQLITE_OK) - { - STHROWF(SQMOD_BINDFAILED, "string", m_Index, m_Handle->ErrMsg()); - } -} - -// ------------------------------------------------------------------------------------------------ -void Parameter::SetStringRaw(CSStr 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, length, SQLITE_TRANSIENT); - // Validate the result - if (m_Handle->mStatus != SQLITE_OK) - { - STHROWF(SQMOD_BINDFAILED, "string", m_Index, m_Handle->ErrMsg()); - } -} - -// ------------------------------------------------------------------------------------------------ -void Parameter::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 >::From(size)); - // Validate the result - if (m_Handle->mStatus != SQLITE_OK) - { - STHROWF(SQMOD_BINDFAILED, "blob", m_Index, m_Handle->ErrMsg()); - } -} - -// ------------------------------------------------------------------------------------------------ -void Parameter::SetBlob(const Object & value) -{ - SQMOD_VALIDATE_CREATED(*this); - // The blob data pointer and size - SQUserPointer ptr = nullptr; - SQInteger len = 0; - // 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, len, SQLITE_TRANSIENT); - // Validate the result - if (m_Handle->mStatus != SQLITE_OK) - { - STHROWF(SQMOD_BINDFAILED, "blob", m_Index, m_Handle->ErrMsg()); - } -} -// ------------------------------------------------------------------------------------------------ -void Parameter::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 Parameter::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: %d", offset); - } - else if (offset < 0) - { - STHROWF("Negative buffer length is not allowed: %d", length); - } - else if (offset + length > buff.Capacity()) - { - STHROWF("Buffer range is outside boundaries: (%d+%d) > %u", 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< int >(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 Parameter::SetDate(const Date & value) -{ - SQMOD_VALIDATE_CREATED(*this); - // Attempt to generate the specified date string - CSStr ptr = FmtStr(_SC("%s 00:00:00"), value.ToString()); - // Attempt to bind the specified value - m_Handle->mStatus = sqlite3_bind_text(m_Handle->mPtr, m_Index, ptr, -1, SQLITE_TRANSIENT); - // Validate the result - if (m_Handle->mStatus != SQLITE_OK) - { - STHROWF(SQMOD_BINDFAILED, "date", m_Index, m_Handle->ErrMsg()); - } -} - -// ------------------------------------------------------------------------------------------------ -void Parameter::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 (%u-%u-%u)", y, m, d); - } - // Attempt to generate the specified date string - CSStr ptr = FmtStr(_SC("%u-%u-%u 00:00:00"), y, m, d); - // Attempt to bind the specified value - m_Handle->mStatus = sqlite3_bind_text(m_Handle->mPtr, m_Index, ptr, -1, SQLITE_TRANSIENT); - // Validate the result - if (m_Handle->mStatus != SQLITE_OK) - { - STHROWF(SQMOD_BINDFAILED, "date", m_Index, m_Handle->ErrMsg()); - } -} - -// ------------------------------------------------------------------------------------------------ -void Parameter::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, value.GetTimestamp().GetSecondsI()); - // Validate the result - if (m_Handle->mStatus != SQLITE_OK) - { - STHROWF(SQMOD_BINDFAILED, "time", m_Index, m_Handle->ErrMsg()); - } -} - -// ------------------------------------------------------------------------------------------------ -void Parameter::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: %u >= 24", h); - } - // Is the specified minute within range? - else if (m >= 60) - { - STHROWF("Minute value is out of range: %u >= 60", m); - } - // Is the specified second within range? - else if (s >= 60) - { - STHROWF("Second value is out of range: %u >= 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 Parameter::SetDatetime(const Datetime & value) -{ - SetDatetimeEx(value.GetYear(), value.GetMonth(), value.GetDay(), value.GetHour(), value.GetMinute(), value.GetSecond()); -} - -// ------------------------------------------------------------------------------------------------ -void Parameter::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 (%u-%u-%u)", y, mo, d); - } - // Is the specified hour within range? - else if (h >= 24) - { - STHROWF("Hour value is out of range: %u >= 24", h); - } - // Is the specified minute within range? - else if (mi >= 60) - { - STHROWF("Minute value is out of range: %u >= 60", mi); - } - // Is the specified second within range? - else if (s >= 60) - { - STHROWF("Second value is out of range: %u >= 60", s); - } - // Attempt to generate the specified date string - CSStr ptr = FmtStr(_SC("%04u-%02u-%02u %02u:%02u:%02u"), y, mo, d, h, mi, s); - // Attempt to bind the specified value - m_Handle->mStatus = sqlite3_bind_text(m_Handle->mPtr, m_Index, ptr, -1, SQLITE_TRANSIENT); - // Validate the result - if (m_Handle->mStatus != SQLITE_OK) - { - STHROWF(SQMOD_BINDFAILED, "date-time", m_Index, m_Handle->ErrMsg()); - } -} - -// ------------------------------------------------------------------------------------------------ -void Parameter::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 >(std::time(nullptr))); - // Validate the result - if (m_Handle->mStatus != SQLITE_OK) - { - STHROWF(SQMOD_BINDFAILED, "time-stamp", m_Index, m_Handle->ErrMsg()); - } -} - -// ------------------------------------------------------------------------------------------------ -void Parameter::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()); - } -} - -// ================================================================================================ -void Register_Parameter(Table & sqlns) -{ - sqlns.Bind(_SC("Parameter"), - Class< Parameter >(sqlns.GetVM(), Typename::Str) - // Constructors - .Ctor() - .Ctor< const Parameter & >() - // Meta-methods - .SquirrelFunc(_SC("_typename"), &Typename::Fn) - .Func(_SC("_tostring"), &Parameter::ToString) - // Properties - .Prop(_SC("IsValid"), &Parameter::IsValid) - .Prop(_SC("References"), &Parameter::GetRefCount) - .Prop(_SC("Index"), &Parameter::GetIndex) - .Prop(_SC("Statement"), &Parameter::GetStatement) - .Prop(_SC("Connection"), &Parameter::GetConnection) - .Prop(_SC("References"), &Parameter::GetRefCount) - .Prop(_SC("Name"), &Parameter::GetName) - // Member Methods - .Func(_SC("Release"), &Parameter::Release) - .Func(_SC("SetValue"), &Parameter::SetValue) - .Func(_SC("SetBool"), &Parameter::SetBool) - .Func(_SC("SetChar"), &Parameter::SetChar) - .Func(_SC("SetInteger"), &Parameter::SetInteger) - .Func(_SC("SetInt8"), &Parameter::SetInt8) - .Func(_SC("SetUint8"), &Parameter::SetUint8) - .Func(_SC("SetInt16"), &Parameter::SetInt16) - .Func(_SC("SetUint16"), &Parameter::SetUint16) - .Func(_SC("SetInt32"), &Parameter::SetInt32) - .Func(_SC("SetUint32"), &Parameter::SetUint32) - .Func(_SC("SetInt64"), &Parameter::SetInt64) - .Func(_SC("SetUint64"), &Parameter::SetUint64) - .Func(_SC("SetFloat"), &Parameter::SetFloat) - .Func(_SC("SetFloat32"), &Parameter::SetFloat32) - .Func(_SC("SetFloat64"), &Parameter::SetFloat64) - .FmtFunc(_SC("SetString"), &Parameter::SetString) - .Func(_SC("SetZeroBlob"), &Parameter::SetZeroBlob) - .Func(_SC("SetBlob"), &Parameter::SetBlob) - .Func(_SC("SetData"), &Parameter::SetData) - .Func(_SC("SetDataEx"), &Parameter::SetDataEx) - .Func(_SC("SetDate"), &Parameter::SetDate) - .Func(_SC("SetDateEx"), &Parameter::SetDateEx) - .Func(_SC("SetTime"), &Parameter::SetTime) - .Func(_SC("SetTimeEx"), &Parameter::SetTimeEx) - .Func(_SC("SetDatetime"), &Parameter::SetDatetime) - .Func(_SC("SetDatetimeEx"), &Parameter::SetDatetimeEx) - .Func(_SC("SetNow"), &Parameter::SetNow) - .Func(_SC("SetNull"), &Parameter::SetNull) - ); -} - -} // Namespace:: SqMod diff --git a/module/Library/SQLite/Parameter.hpp b/module/Library/SQLite/Parameter.hpp deleted file mode 100644 index dc759ffe..00000000 --- a/module/Library/SQLite/Parameter.hpp +++ /dev/null @@ -1,411 +0,0 @@ -#pragma once - -// ------------------------------------------------------------------------------------------------ -#include "Library/SQLite/Handle.hpp" - -// ------------------------------------------------------------------------------------------------ -#include - -// ------------------------------------------------------------------------------------------------ -namespace SqMod { - -/* ------------------------------------------------------------------------------------------------ - * Used to manage and interact with parameters from a database statement. -*/ -class Parameter -{ - // -------------------------------------------------------------------------------------------- - friend class Statement; - -private: - - // -------------------------------------------------------------------------------------------- - Int32 m_Index; // The index of the managed parameter. - StmtRef m_Handle; // Reference to the managed statement. - -protected: - - /* -------------------------------------------------------------------------------------------- - * Validate the managed statement handle and throw an error if invalid. - */ -#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) - void Validate(CCStr file, Int32 line) const; -#else - void Validate() const; -#endif // _DEBUG - - /* -------------------------------------------------------------------------------------------- - * Validate the managed statement handle and throw an error if invalid. - */ -#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) - void ValidateCreated(CCStr file, Int32 line) const; -#else - void ValidateCreated() const; -#endif // _DEBUG - - /* -------------------------------------------------------------------------------------------- - * Validate the managed statement handle and throw an error if invalid. - */ -#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) - const StmtRef & GetValid(CCStr file, Int32 line) const; -#else - const StmtRef & GetValid() const; -#endif // _DEBUG - - /* -------------------------------------------------------------------------------------------- - * Validate the managed statement handle and throw an error if invalid. - */ -#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) - const StmtRef & GetCreated(CCStr file, Int32 line) const; -#else - const StmtRef & GetCreated() const; -#endif // _DEBUG - - /* -------------------------------------------------------------------------------------------- - * Validate the statement reference and parameter index, and throw an error if they're invalid. - */ -#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) - void ValidateParam(Int32 idx, CCStr file, Int32 line) const; -#else - void ValidateParam(Int32 idx) const; -#endif // _DEBUG - - /* -------------------------------------------------------------------------------------------- - * Modify the index to the specified value. - */ - void SetIndex(Int32 idx) - { - // Assign the index with a failsafe to invalid on error - AutoAssign< Int32 > aa(m_Index, -1, idx); - // Validate the obtained parameter index - SQMOD_VALIDATE_PARAM(*this, idx); - // Don't fall back to the invalid index anymore - aa.Set(idx); - } - - /* -------------------------------------------------------------------------------------------- - * Modify the index to the specified value. - */ - void SetIndex(CSStr name) - { - SetIndex(sqlite3_bind_parameter_index(SQMOD_GET_CREATED(*this)->mPtr, name)); - } - - /* -------------------------------------------------------------------------------------------- - * Modify the index to the specified value. - */ - void SetIndex(const Object & param); - -public: - - /* -------------------------------------------------------------------------------------------- - * Default constructor (null). - */ - Parameter() - : m_Index(0), m_Handle() - { - /* ... */ - } - - /* -------------------------------------------------------------------------------------------- - * No parameter constructor. - */ - Parameter(const StmtRef & stmt) - : m_Index(0), m_Handle(stmt) - { - /* ... */ - } - - /* -------------------------------------------------------------------------------------------- - * Index constructor. - */ - Parameter(const StmtRef & stmt, Int32 idx) - : m_Index(idx), m_Handle(stmt) - { - SQMOD_VALIDATE_PARAM(*this, m_Index); - } - - /* -------------------------------------------------------------------------------------------- - * Name constructor. - */ - Parameter(const StmtRef & stmt, CSStr name) - : m_Index(stmt ? sqlite3_bind_parameter_index(stmt->mPtr, name) : 0), m_Handle(stmt) - { - SQMOD_VALIDATE_PARAM(*this, m_Index); - } - - /* -------------------------------------------------------------------------------------------- - * Dynamic constructor. - */ - Parameter(const StmtRef & stmt, const Object & param) - : m_Index(0), m_Handle(stmt) - { - if (!m_Handle) - { - STHROWF("Invalid SQLite statement reference"); - } - // Extract the index - SetIndex(param); - } - - /* -------------------------------------------------------------------------------------------- - * Copy constructor. - */ - Parameter(const Parameter & o) = default; - - /* -------------------------------------------------------------------------------------------- - * Move constructor. - */ - Parameter(Parameter && o) = default; - - /* -------------------------------------------------------------------------------------------- - * Copy assignment operator. - */ - Parameter & operator = (const Parameter & o) = default; - - /* -------------------------------------------------------------------------------------------- - * Move assignment operator. - */ - Parameter & operator = (Parameter && o) = default; - - /* -------------------------------------------------------------------------------------------- - * Perform an equality comparison between two parameter indexes. - */ - bool operator == (const Parameter & o) const - { - return (m_Index == o.m_Index); - } - - /* -------------------------------------------------------------------------------------------- - * Perform an inequality comparison between two parameter indexes. - */ - bool operator != (const Parameter & o) const - { - return (m_Index != o.m_Index); - } - - /* -------------------------------------------------------------------------------------------- - * Implicit conversion to boolean for use in boolean operations. - */ - operator bool () const - { - return m_Index >= 0; - } - - /* -------------------------------------------------------------------------------------------- - * Used by the script engine to convert an instance of this type to a string. - */ - CSStr ToString() const - { - CSStr val = nullptr; - // Can we attempt to return the parameter name? - if (m_Handle && m_Index) - { - val = sqlite3_bind_parameter_name(m_Handle->mPtr, m_Index); - } - else - { - val = ToStrF(_SC("%d"), m_Index); - } - // Return the value if valid - return val ? val : _SC(""); - } - - /* -------------------------------------------------------------------------------------------- - * See whether this statement is valid. - */ - bool IsValid() const - { - return m_Handle; // An invalid statement means an invalid parameter - } - - /* -------------------------------------------------------------------------------------------- - * Return the number of active references to this statement handle. - */ - Uint32 GetRefCount() const - { - return m_Handle.Count(); - } - - /* -------------------------------------------------------------------------------------------- - * Retrieve the associated parameter index. - */ - Int32 GetIndex() const - { - return m_Index; - } - - /* -------------------------------------------------------------------------------------------- - * Retrieve the associated database statement. - */ - Object GetStatement() const; - - /* -------------------------------------------------------------------------------------------- - * Retrieve the associated database connection. - */ - Object GetConnection() const; - - /* -------------------------------------------------------------------------------------------- - * Retrieve the name of the referenced parameter. - */ - CSStr GetName() const - { - return sqlite3_bind_parameter_name(SQMOD_GET_CREATED(*this)->mPtr, m_Index); - } - - /* -------------------------------------------------------------------------------------------- - * Release the reference to the associated database statement and parameter index. - */ - void Release() - { - m_Handle.Reset(); - m_Index = 0; - } - - /* -------------------------------------------------------------------------------------------- - * Attempt to bind a dynamic value at the referenced parameter index. - */ - void SetValue(const Object & value); - - /* -------------------------------------------------------------------------------------------- - * Attempt to bind a boolean value at the referenced parameter index. - */ - void SetBool(bool value); - - /* -------------------------------------------------------------------------------------------- - * Attempt to bind a character value at the referenced parameter index. - */ - void SetChar(SQInteger value); - - /* -------------------------------------------------------------------------------------------- - * Attempt to bind a native integer value at the referenced parameter index. - */ - void SetInteger(SQInteger value); - - /* -------------------------------------------------------------------------------------------- - * Attempt to bind a signed 8 bit integer value at the referenced parameter index. - */ - void SetInt8(SQInteger value); - - /* -------------------------------------------------------------------------------------------- - * Attempt to bind an unsigned 8 bit integer value at the referenced parameter index. - */ - void SetUint8(SQInteger value); - - /* -------------------------------------------------------------------------------------------- - * Attempt to bind a signed 16 bit integer value at the referenced parameter index. - */ - void SetInt16(SQInteger value); - - /* -------------------------------------------------------------------------------------------- - * Attempt to bind an unsigned 16 bit integer value at the referenced parameter index. - */ - void SetUint16(SQInteger value); - - /* -------------------------------------------------------------------------------------------- - * Attempt to bind a signed 32 bit integer value at the referenced parameter index. - */ - void SetInt32(SQInteger value); - - /* -------------------------------------------------------------------------------------------- - * Attempt to bind an unsigned 32 bit integer value at the referenced parameter index. - */ - void SetUint32(SQInteger value); - - /* -------------------------------------------------------------------------------------------- - * Attempt to bind a signed 64 bit integer value at the referenced parameter index. - */ - void SetInt64(const Object & value); - - /* -------------------------------------------------------------------------------------------- - * Attempt to bind an unsigned 64 bit integer value at the referenced parameter index. - */ - void SetUint64(const Object & value); - - /* -------------------------------------------------------------------------------------------- - * Attempt to bind a native floating point value at the referenced parameter index. - */ - void SetFloat(SQFloat value); - - /* -------------------------------------------------------------------------------------------- - * Attempt to bind a 32 bit floating point value at the referenced parameter index. - */ - void SetFloat32(SQFloat value); - - /* -------------------------------------------------------------------------------------------- - * Attempt to bind a 64 bit floating point value at the referenced parameter index. - */ - void SetFloat64(SQFloat value); - - /* -------------------------------------------------------------------------------------------- - * Attempt to bind a string value at the referenced parameter index. - */ - void SetString(StackStrF & value); - - /* -------------------------------------------------------------------------------------------- - * Attempt to bind a string value at the referenced parameter index. - */ - void SetStringRaw(CSStr value, SQInteger length = -1); - - /* -------------------------------------------------------------------------------------------- - * Attempt to bind a zeroed blob value at the referenced parameter index. - */ - void SetZeroBlob(SQInteger size); - - /* -------------------------------------------------------------------------------------------- - * Attempt to bind a blob value at the referenced parameter index. - */ - void SetBlob(const Object & value); - - /* -------------------------------------------------------------------------------------------- - * Attempt to bind a buffer value at the referenced parameter index. - */ - void SetData(const SqBuffer & value); - - /* -------------------------------------------------------------------------------------------- - * Attempt to bind a buffer value at the referenced parameter index. - */ - void SetDataEx(const SqBuffer & value, SQInteger offset, SQInteger length); - - /* -------------------------------------------------------------------------------------------- - * Attempt to bind a date value at the referenced parameter index. - */ - void SetDate(const Date & value); - - /* -------------------------------------------------------------------------------------------- - * Attempt to bind a date value at the referenced parameter index. - */ - void SetDateEx(SQInteger year, SQInteger month, SQInteger day); - - /* -------------------------------------------------------------------------------------------- - * Attempt to bind a time value at the referenced parameter index. - */ - void SetTime(const Time & value); - - /* -------------------------------------------------------------------------------------------- - * Attempt to bind a time value at the referenced parameter index. - */ - void SetTimeEx(SQInteger hour, SQInteger minute, SQInteger second); - - /* -------------------------------------------------------------------------------------------- - * Attempt to bind a date-time value at the referenced parameter index. - */ - void SetDatetime(const Datetime & value); - - /* -------------------------------------------------------------------------------------------- - * Attempt to bind a date-time value at the referenced parameter index. - */ - void SetDatetimeEx(SQInteger year, SQInteger month, SQInteger day, SQInteger hour, SQInteger minute, SQInteger second); - - /* -------------------------------------------------------------------------------------------- - * Attempt to bind the current timestamp at the referenced parameter index. - */ - void SetNow(); - - /* -------------------------------------------------------------------------------------------- - * Attempt to bind a null value at the referenced parameter index. - */ - void SetNull(); -}; - -} // Namespace:: SqMod diff --git a/module/Library/SQLite/Statement.cpp b/module/Library/SQLite/Statement.cpp deleted file mode 100644 index 4c2f168f..00000000 --- a/module/Library/SQLite/Statement.cpp +++ /dev/null @@ -1,525 +0,0 @@ -// ------------------------------------------------------------------------------------------------ -#include "Library/SQLite/Statement.hpp" -#include "Library/SQLite/Connection.hpp" -#include "Library/SQLite/Column.hpp" - -// ------------------------------------------------------------------------------------------------ -#include - -// ------------------------------------------------------------------------------------------------ -namespace SqMod { - -// ------------------------------------------------------------------------------------------------ -SQMODE_DECL_TYPENAME(Typename, _SC("SqLiteStatement")) - -// ------------------------------------------------------------------------------------------------ -#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) -void Statement::Validate(CCStr file, Int32 line) const -{ - if (!m_Handle) - { - SqThrowF("Invalid SQLite statement reference =>[%s:%d]", file, line); - } -} -#else -void Statement::Validate() const -{ - if (!m_Handle) - { - SqThrowF("Invalid SQLite statement reference"); - } -} -#endif // _DEBUG - -// ------------------------------------------------------------------------------------------------ -#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) -void Statement::ValidateCreated(CCStr file, Int32 line) const -{ - if (!m_Handle) - { - SqThrowF("Invalid SQLite statement reference =>[%s:%d]", file, line); - } - else if (m_Handle->mPtr == nullptr) - { - SqThrowF("Invalid SQLite statement =>[%s:%d]", file, line); - } -} -#else -void Statement::ValidateCreated() const -{ - if (!m_Handle) - { - SqThrowF("Invalid SQLite statement reference"); - } - else if (m_Handle->mPtr == nullptr) - { - SqThrowF("Invalid SQLite statement"); - } -} -#endif // _DEBUG - -// ------------------------------------------------------------------------------------------------ -#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) -const StmtRef & Statement::GetValid(CCStr file, Int32 line) const -{ - Validate(file, line); - return m_Handle; -} -#else -const StmtRef & Statement::GetValid() const -{ - Validate(); - return m_Handle; -} -#endif // _DEBUG - -// ------------------------------------------------------------------------------------------------ -#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) -const StmtRef & Statement::GetCreated(CCStr file, Int32 line) const -{ - ValidateCreated(file, line); - return m_Handle; -} -#else -const StmtRef & Statement::GetCreated() const -{ - ValidateCreated(); - return m_Handle; -} -#endif // _DEBUG - -// ------------------------------------------------------------------------------------------------ -#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) -void Statement::ValidateColumn(Int32 idx, CCStr file, Int32 line) const -{ - ValidateCreated(file, line); - // Is the specified index in range? - if (!m_Handle->CheckColumn(idx)) - { - SqThrowF("Column index is out of range: %d:%d =>[%s:%d]", idx, m_Handle->mColumns, - file, line); - } -} -#else -void Statement::ValidateColumn(Int32 idx) const -{ - ValidateCreated(); - // Is the specified index in range? - if (!m_Handle->CheckColumn(idx)) - { - SqThrowF("Column index is out of range: %d:%d", idx, m_Handle->mColumns); - } -} -#endif // _DEBUG - -// ------------------------------------------------------------------------------------------------ -#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) -void Statement::ValidateParam(Int32 idx, CCStr file, Int32 line) const -{ - ValidateCreated(file, line); - // Is the specified index in range? - if (!m_Handle->CheckParameter(idx)) - { - SqThrowF("Parameter index is out of range: %d:%d =>[%s:%d]", idx, m_Handle->mParameters, - file, line); - } -} -#else -void Statement::ValidateParam(Int32 idx) const -{ - ValidateCreated(); - // Is the specified index in range? - if (!m_Handle->CheckParameter(idx)) - { - SqThrowF("Parameter index is out of range: %d:%d", idx, m_Handle->mParameters); - } -} -#endif // _DEBUG - -// ------------------------------------------------------------------------------------------------ -#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) -void Statement::ValidateRow(CCStr file, Int32 line) const -{ - ValidateCreated(file, line); - // Do we have any rows available? - if (!m_Handle->mGood) - { - SqThrowF("No row available =>[%s:%d]", file, line); - } -} -#else -void Statement::ValidateRow() const -{ - ValidateCreated(); - // Do we have any rows available? - if (!m_Handle->mGood) - { - SqThrowF("No row available"); - } -} -#endif // _DEBUG - -// ------------------------------------------------------------------------------------------------ -Statement::Statement(const Connection & connection, StackStrF & query) - : m_Handle(new StmtHnd(connection.GetHandle())) -{ - SQMOD_GET_VALID(*this)->Create(query.mPtr, query.mLen); -} - -// ------------------------------------------------------------------------------------------------ -Object Statement::GetConnection() const -{ - return Object(new Connection(SQMOD_GET_VALID(*this)->mConn)); -} - -// ------------------------------------------------------------------------------------------------ -Statement & Statement::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 [%s]", m_Handle->ErrStr()); - } - // Allow further chaining of operations - return *this; -} - -// ------------------------------------------------------------------------------------------------ -Statement & Statement::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 [%s]", m_Handle->ErrStr()); - } - // Allow further chaining of operations - return *this; -} - -// ------------------------------------------------------------------------------------------------ -Int32 Statement::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 [%s]", m_Handle->ErrStr()); - } - // Operation failed (shouldn't reach this point!) - return -1; -} - -// ------------------------------------------------------------------------------------------------ -bool Statement::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 [%s]", m_Handle->ErrStr()); - } - // Operation failed (shouldn't reach this point!) - return false; -} - -// ------------------------------------------------------------------------------------------------ -Statement & Statement::SetArray(Int32 idx, const Array & arr) -{ - // Obtain a script iterator - Array::iterator itr; - // Create a parameter instance to bind the values - Parameter 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; -} - -// ------------------------------------------------------------------------------------------------ -Statement & Statement::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 - Parameter 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 Statement::GetArray(Int32 min, Int32 max) const -{ - SQMOD_VALIDATE_ROW(*this); - // Is the specified minimum index valid? - if (min < 0) - { - STHROWF("Minimum is bellow zero: %d", min); - } - // Is the minimum actually the minimum? - else if (min > max) - { - STHROWF("Minimum is higher than maximum: %d > %d", min, max); - } - // Is the minimum in range? - else if (!m_Handle->CheckColumn(min)) - { - STHROWF("Minimum is out of range: %d:%d", min, m_Handle->mColumns); - } - // Is the maximum in range? - else if (!m_Handle->CheckColumn(max)) - { - STHROWF("Maximum is out of range: %d:%d", max, m_Handle->mColumns); - } - // Allocate an array large enough to hold the values from selected columns - Array arr(DefaultVM::Get(), max-min); - // Create a column instance to retrieve the values - Column column(m_Handle); - // Array element counter - Int32 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 Statement::GetTable(Int32 min, Int32 max) const -{ - SQMOD_VALIDATE_ROW(*this); - // Is the specified minimum index valid? - if (min < 0) - { - STHROWF("Minimum is bellow zero: %d", min); - } - // Is the minimum actually the minimum? - else if (min > max) - { - STHROWF("Minimum is higher than maximum: %d > %d", min, max); - } - // Is the minimum in range> - else if (!m_Handle->CheckColumn(min)) - { - STHROWF("Minimum is out of range: %d:%d", min, m_Handle->mColumns); - } - // Is the maximum in range? - else if (!m_Handle->CheckColumn(max)) - { - STHROWF("Maximum is out of range: %d:%d", max, m_Handle->mColumns); - } - // Create a table to hold the selected column values - Table tbl(DefaultVM::Get()); - // Create a column instance to retrieve the values - Column column(m_Handle); - // Process the range of selected columns - while (min <= max) - { - // Attempt to obtain the column name - CSStr name = sqlite3_column_name(m_Handle->mPtr, min); - // Validate the obtained name - if (!name) - { - STHROWF("Unable to retrieve name of column (%d)", 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; -} - -// ================================================================================================ -void Register_Statement(Table & sqlns) -{ - sqlns.Bind(_SC("Statement"), - Class< Statement >(sqlns.GetVM(), Typename::Str) - // Constructors - .Ctor() - .Ctor< const Statement & >() - .Ctor< const Connection &, StackStrF & >() - // Meta-methods - .SquirrelFunc(_SC("_typename"), &Typename::Fn) - .Func(_SC("_tostring"), &Statement::ToString) - // Properties - .Prop(_SC("IsValid"), &Statement::IsValid) - .Prop(_SC("Prepared"), &Statement::IsPrepared) - .Prop(_SC("References"), &Statement::GetReferences) - .Prop(_SC("Connection"), &Statement::GetConnection) - .Prop(_SC("Status"), &Statement::GetStatus) - .Prop(_SC("ErrCode"), &Statement::GetErrorCode) - .Prop(_SC("ExErrCode"), &Statement::GetExtendedErrorCode) - .Prop(_SC("ExtendedErrCode"), &Statement::GetExtendedErrorCode) - .Prop(_SC("ErrStr"), &Statement::GetErrStr) - .Prop(_SC("ErrMsg"), &Statement::GetErrMsg) - .Prop(_SC("Columns"), &Statement::GetColumns) - .Prop(_SC("Parameters"), &Statement::GetParameters) - .Prop(_SC("Query"), &Statement::GetQuery) - .Prop(_SC("Good"), &Statement::GetGood) - .Prop(_SC("Done"), &Statement::GetDone) - .Prop(_SC("DataCount"), &Statement::GetDataCount) - // Member Methods - .Func(_SC("Release"), &Statement::Release) - .Func(_SC("CheckParameter"), &Statement::CheckParameter) - .FmtFunc(_SC("GetParameterIndex"), &Statement::GetParameterIndex) - .Func(_SC("GetParameterName"), &Statement::GetParameterName) - .Func(_SC("CheckColumn"), &Statement::CheckColumn) - .Func(_SC("IsColumnNull"), &Statement::IsColumnNull) - .FmtFunc(_SC("ColumnIndex"), &Statement::GetColumnIndex) - .Func(_SC("ColumnName"), &Statement::GetColumnName) - .Func(_SC("ColumnOriginName"), &Statement::GetColumnOriginName) - .Func(_SC("ColumnType"), &Statement::GetColumnType) - .Func(_SC("ColumnBytes"), &Statement::GetColumnBytes) - .Func(_SC("Reset"), &Statement::Reset) - .Func(_SC("Clear"), &Statement::Clear) - .Func(_SC("Exec"), &Statement::Exec) - .Func(_SC("Step"), &Statement::Step) - .Func(_SC("Param"), &Statement::GetParameter) - .Func(_SC("Parameter"), &Statement::GetParameter) - .Func(_SC("SetValue"), &Statement::SetValue) - .Func(_SC("SetBool"), &Statement::SetBool) - .Func(_SC("SetChar"), &Statement::SetChar) - .Func(_SC("SetInteger"), &Statement::SetInteger) - .Func(_SC("SetInt8"), &Statement::SetInt8) - .Func(_SC("SetUint8"), &Statement::SetUint8) - .Func(_SC("SetInt16"), &Statement::SetInt16) - .Func(_SC("SetUint16"), &Statement::SetUint16) - .Func(_SC("SetInt32"), &Statement::SetInt32) - .Func(_SC("SetUint32"), &Statement::SetUint32) - .Func(_SC("SetInt64"), &Statement::SetInt64) - .Func(_SC("SetUint64"), &Statement::SetUint64) - .Func(_SC("SetFloat"), &Statement::SetFloat) - .Func(_SC("SetFloat32"), &Statement::SetFloat32) - .Func(_SC("SetFloat64"), &Statement::SetFloat64) - .FmtFunc(_SC("SetString"), &Statement::SetString) - .Func(_SC("SetZeroBlob"), &Statement::SetZeroBlob) - .Func(_SC("SetBlob"), &Statement::SetBlob) - .Func(_SC("SetData"), &Statement::SetData) - .Func(_SC("SetDate"), &Statement::SetDate) - .Func(_SC("SetDateEx"), &Statement::SetDateEx) - .Func(_SC("SetTime"), &Statement::SetTime) - .Func(_SC("SetTimeEx"), &Statement::SetTimeEx) - .Func(_SC("SetDatetime"), &Statement::SetDatetime) - .Func(_SC("SetDatetimeEx"), &Statement::SetDatetimeEx) - .Func(_SC("SetNow"), &Statement::SetNow) - .Func(_SC("SetNull"), &Statement::SetNull) - .Func(_SC("SetArray"), &Statement::SetArray) - .Func(_SC("SetTable"), &Statement::SetTable) - .Func(_SC("Field"), &Statement::GetColumn) - .Func(_SC("Column"), &Statement::GetColumn) - .Func(_SC("GetValue"), &Statement::GetValue) - .Func(_SC("GetNumber"), &Statement::GetNumber) - .Func(_SC("GetInteger"), &Statement::GetInteger) - .Func(_SC("GetFloat"), &Statement::GetFloat) - .Func(_SC("GetLong"), &Statement::GetLong) - .Func(_SC("GetString"), &Statement::GetString) - .Func(_SC("GetBoolean"), &Statement::GetBoolean) - .Func(_SC("GetChar"), &Statement::GetChar) - .Func(_SC("GetBuffer"), &Statement::GetBuffer) - .Func(_SC("GetBlob"), &Statement::GetBlob) - // Member overloads - .Overload< Array (Statement::*)(void) const >(_SC("GetArray"), &Statement::GetArray) - .Overload< Array (Statement::*)(Int32) const >(_SC("GetArray"), &Statement::GetArray) - .Overload< Array (Statement::*)(Int32, Int32) const >(_SC("GetArray"), &Statement::GetArray) - .Overload< Table (Statement::*)(void) const >(_SC("GetTable"), &Statement::GetTable) - .Overload< Table (Statement::*)(Int32) const >(_SC("GetTable"), &Statement::GetTable) - .Overload< Table (Statement::*)(Int32, Int32) const >(_SC("GetTable"), &Statement::GetTable) - ); -} - -} // Namespace:: SqMod diff --git a/module/Library/SQLite/Statement.hpp b/module/Library/SQLite/Statement.hpp deleted file mode 100644 index 04565873..00000000 --- a/module/Library/SQLite/Statement.hpp +++ /dev/null @@ -1,868 +0,0 @@ -#pragma once - -// ------------------------------------------------------------------------------------------------ -#include "Library/SQLite/Handle.hpp" -#include "Library/SQLite/Parameter.hpp" -#include "Library/SQLite/Column.hpp" -#include "Library/Utils/Buffer.hpp" - -// ------------------------------------------------------------------------------------------------ -namespace SqMod { - -/* ------------------------------------------------------------------------------------------------ - * Used to manage and interact a database statement. -*/ -class Statement -{ -private: - - // -------------------------------------------------------------------------------------------- - StmtRef m_Handle; // Reference to the managed statement. - -protected: - - /* -------------------------------------------------------------------------------------------- - * Validate the managed statement handle and throw an error if invalid. - */ -#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) - void Validate(CCStr file, Int32 line) const; -#else - void Validate() const; -#endif // _DEBUG - - /* -------------------------------------------------------------------------------------------- - * Validate the managed statement handle and throw an error if invalid. - */ -#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) - void ValidateCreated(CCStr file, Int32 line) const; -#else - void ValidateCreated() const; -#endif // _DEBUG - - /* -------------------------------------------------------------------------------------------- - * Validate the managed statement handle and throw an error if invalid. - */ -#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) - const StmtRef & GetValid(CCStr file, Int32 line) const; -#else - const StmtRef & GetValid() const; -#endif // _DEBUG - - /* -------------------------------------------------------------------------------------------- - * Validate the managed statement handle and throw an error if invalid. - */ -#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) - const StmtRef & GetCreated(CCStr file, Int32 line) const; -#else - const StmtRef & GetCreated() const; -#endif // _DEBUG - - /* -------------------------------------------------------------------------------------------- - * Validate the statement reference and column index, and throw an error if they're invalid. - */ -#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) - void ValidateColumn(Int32 idx, CCStr file, Int32 line) const; -#else - void ValidateColumn(Int32 idx) const; -#endif // _DEBUG - - /* -------------------------------------------------------------------------------------------- - * Validate the statement reference and parameter index, and throw an error if they're invalid. - */ -#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) - void ValidateParam(Int32 idx, CCStr file, Int32 line) const; -#else - void ValidateParam(Int32 idx) const; -#endif // _DEBUG - - /* -------------------------------------------------------------------------------------------- - * Validate the statement reference and row, and throw an error if they're invalid. - */ -#if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) - void ValidateRow(CCStr file, Int32 line) const; -#else - void ValidateRow() const; -#endif // _DEBUG - -public: - - /* -------------------------------------------------------------------------------------------- - * Default constructor. - */ - Statement() - : m_Handle() - { - /* ... */ - } - - /* -------------------------------------------------------------------------------------------- - * Construct a statement under the specified connection using the specified string. - */ - Statement(const ConnRef & connection, StackStrF & query) - : m_Handle(new StmtHnd(connection)) - { - SQMOD_GET_VALID(*this)->Create(query.mPtr, query.mLen); - } - - /* -------------------------------------------------------------------------------------------- - * Construct a statement under the specified connection using the specified string. - */ - Statement(const Connection & connection, StackStrF & query); - - /* -------------------------------------------------------------------------------------------- - * Direct handle constructor. - */ - Statement(const StmtRef & s) - : m_Handle(s) - { - /* ... */ - } - - /* -------------------------------------------------------------------------------------------- - * Copy constructor. - */ - Statement(const Statement & o) = default; - - /* -------------------------------------------------------------------------------------------- - * Move constructor. - */ - Statement(Statement && o) = default; - - /* -------------------------------------------------------------------------------------------- - * Copy assignment operator. - */ - Statement & operator = (const Statement & o) = default; - - /* -------------------------------------------------------------------------------------------- - * Move assignment operator. - */ - Statement & operator = (Statement && o) = default; - - /* -------------------------------------------------------------------------------------------- - * Perform an equality comparison between two connections. - */ - bool operator == (const Statement & o) const - { - return (m_Handle.Get() == o.m_Handle.Get()); - } - - /* -------------------------------------------------------------------------------------------- - * Perform an inequality comparison between two connections. - */ - bool operator != (const Statement & o) const - { - return (m_Handle.Get() != o.m_Handle.Get()); - } - - /* -------------------------------------------------------------------------------------------- - * Implicit conversion to the raw connection handle. - */ - operator sqlite3_stmt * () - { - return m_Handle ? m_Handle->mPtr : nullptr; - } - - /* -------------------------------------------------------------------------------------------- - * Implicit conversion to the raw connection handle. - */ - operator sqlite3_stmt * () const - { - return m_Handle ? m_Handle->mPtr : nullptr; - } - - /* -------------------------------------------------------------------------------------------- - * Used by the script engine to convert an instance of this type to a string. - */ - const String & ToString() const - { - return m_Handle ? m_Handle->mQuery : NullString(); - } - - /* -------------------------------------------------------------------------------------------- - * Retrieve the associated statement handle. - */ - const StmtRef & GetHandle() const - { - return m_Handle; - } - - /* -------------------------------------------------------------------------------------------- - * See whether the managed handle is valid. - */ - bool IsValid() const - { - return m_Handle; - } - - /* -------------------------------------------------------------------------------------------- - * See whether the managed statement is valid. - */ - bool IsPrepared() const - { - return m_Handle && (m_Handle->mPtr != nullptr); - } - - /* -------------------------------------------------------------------------------------------- - * Return the number of active references to this statement handle. - */ - Uint32 GetReferences() const - { - return m_Handle.Count(); - } - - /* -------------------------------------------------------------------------------------------- - * Retrieve the associated database connection. - */ - Object GetConnection() const; - - /* -------------------------------------------------------------------------------------------- - * Release the reference to the associated database statement. - */ - void Release() - { - m_Handle.Reset(); - } - - /* -------------------------------------------------------------------------------------------- - * Retrieve the last received status code. - */ - Int32 GetStatus() const - { - return SQMOD_GET_VALID(*this)->mStatus; - } - - /* -------------------------------------------------------------------------------------------- - * Return the numeric result code for the most recent failed API call (if any). - */ - Int32 GetErrorCode() const - { - return SQMOD_GET_VALID(*this)->ErrNo(); - } - - /* -------------------------------------------------------------------------------------------- - * Return the extended numeric result code for the most recent failed API call (if any). - */ - Int32 GetExtendedErrorCode() const - { - return SQMOD_GET_VALID(*this)->ExErrNo(); - } - - /* -------------------------------------------------------------------------------------------- - * Retrieve the message of the last received error code. - */ - CSStr GetErrStr() const - { - return SQMOD_GET_VALID(*this)->ErrStr(); - } - - /* -------------------------------------------------------------------------------------------- - * Return the last error message associated with this database connection. - */ - CSStr GetErrMsg() const - { - return SQMOD_GET_VALID(*this)->ErrMsg(); - } - - /* -------------------------------------------------------------------------------------------- - * Retrieve the amount of requested columns. - */ - Int32 GetColumns() const - { - return SQMOD_GET_VALID(*this)->mColumns; - } - - /* -------------------------------------------------------------------------------------------- - * Retrieve the amount of specified parameters. - */ - Int32 GetParameters() const - { - return SQMOD_GET_VALID(*this)->mParameters; - } - - /* -------------------------------------------------------------------------------------------- - * Retrieve the query string used to create this statement. - */ - const String & GetQuery() const - { - return SQMOD_GET_VALID(*this)->mQuery; - } - - /* -------------------------------------------------------------------------------------------- - * See if the last step retrieved a valid row. - */ - bool GetGood() const - { - return SQMOD_GET_CREATED(*this)->mGood; - } - - /* -------------------------------------------------------------------------------------------- - * See if there are any steps left. - */ - bool GetDone() const - { - return SQMOD_GET_CREATED(*this)->mDone; - } - - /* -------------------------------------------------------------------------------------------- - * Check whether a specific parameter index is within range. - */ - bool CheckParameter(Int32 idx) const - { - return SQMOD_GET_VALID(*this)->CheckParameter(idx); - } - - /* -------------------------------------------------------------------------------------------- - * Retrieve the parameter index associated with the specified name. - */ - Int32 GetParameterIndex(StackStrF & name) const - { - return sqlite3_bind_parameter_index(SQMOD_GET_VALID(*this)->mPtr, name.mPtr); - } - - /* -------------------------------------------------------------------------------------------- - * Retrieve the parameter name associated with the specified index. - */ - CSStr GetParameterName(Int32 idx) const - { - // Validate the specified index - if (!idx) - { - STHROWF("Invalid parameter index (%d)", idx); - } - // Attempt to locate the name at the specified index - CSStr name = sqlite3_bind_parameter_name(SQMOD_GET_VALID(*this)->mPtr, idx); - // Validate the obtained string - if (!name) - { - STHROWF("No such parameter exists (%d)", idx); - } - // Return the obtained string - return name; - } - - /* -------------------------------------------------------------------------------------------- - * Check whether a specific column index is within range. - */ - bool CheckColumn(Int32 idx) const - { - return SQMOD_GET_VALID(*this)->CheckColumn(idx); - } - - /* -------------------------------------------------------------------------------------------- - * Retrieve the amount of columns available in the current row. - */ - Int32 GetDataCount() const - { - return sqlite3_data_count(SQMOD_GET_VALID(*this)->mPtr); - } - - /* -------------------------------------------------------------------------------------------- - * Check whether the specified column is null. - */ - bool IsColumnNull(Int32 idx) const - { - return (sqlite3_column_type(SQMOD_GET_VALID(*this)->mPtr, idx) == SQLITE_NULL); - } - - /* -------------------------------------------------------------------------------------------- - * Retrieve the column index associated with the specified name. - */ - Int32 GetColumnIndex(StackStrF & name) const - { - return SQMOD_GET_VALID(*this)->GetColumnIndex(name.mPtr, name.mLen); - } - - /* -------------------------------------------------------------------------------------------- - * Retrieve the column name associated with the specified index. - */ - CSStr GetColumnName(Int32 idx) const - { - return sqlite3_column_name(SQMOD_GET_VALID(*this)->mPtr, idx); - } - - /* -------------------------------------------------------------------------------------------- - * Retrieve the column origin name if the library was compiled with such feature. - */ - CSStr GetColumnOriginName(Int32 idx) const - { -#ifdef SQLITE_ENABLE_COLUMN_METADATA - return sqlite3_column_origin_name(SQMOD_GET_VALID(*this)->mPtr, idx); -#else - // The compiler moans when extra warnings are enabled - SQMOD_UNUSED_VAR(idx); - // Stop the execution here! - STHROWF("The module was compiled without this feature"); - // We have to return something - return _SC(""); -#endif - } - - /* -------------------------------------------------------------------------------------------- - * Retrieve the type identifier of the column associated with the specified index. - */ - Int32 GetColumnType(Int32 idx) const - { - return sqlite3_column_type(SQMOD_GET_VALID(*this)->mPtr, idx); - } - - /* -------------------------------------------------------------------------------------------- - * Retrieve the size in bytes of the column associated with the specified index. - */ - Int32 GetColumnBytes(Int32 idx) const - { - return sqlite3_column_bytes(SQMOD_GET_VALID(*this)->mPtr, idx); - } - - /* -------------------------------------------------------------------------------------------- - * Reset the statement back to its initial position to be stepped again. - */ - Statement & Reset(); - - /* -------------------------------------------------------------------------------------------- - * Clear any values binded to this statement. - */ - Statement & Clear(); - - /* -------------------------------------------------------------------------------------------- - * Execute this statement and don't expect any rows to be returned. - */ - Int32 Exec(); - - /* -------------------------------------------------------------------------------------------- - * Step the statement and expect a row to be returned. - */ - bool Step(); - - /* -------------------------------------------------------------------------------------------- - * Retrieve the parameter with the specified name or index. - */ - Object GetParameter(const Object & param) const - { - return Object(new Parameter(m_Handle, param)); - } - - /* -------------------------------------------------------------------------------------------- - * Attempt to bind a dynamic value at the specified parameter index. - */ - Statement & SetValue(const Object & param, const Object & value) - { - Parameter(SQMOD_GET_CREATED(*this), param).SetValue(value); - // Allow chaining of operations - return *this; - } - - /* -------------------------------------------------------------------------------------------- - * Attempt to bind a boolean value at the specified parameter index. - */ - Statement & SetBool(const Object & param, bool value) - { - Parameter(SQMOD_GET_CREATED(*this), param).SetBool(value); - // Allow chaining of operations - return *this; - } - - /* -------------------------------------------------------------------------------------------- - * Attempt to bind a character value at the specified parameter index. - */ - Statement & SetChar(const Object & param, SQInteger value) - { - Parameter(SQMOD_GET_CREATED(*this), param).SetChar(value); - // Allow chaining of operations - return *this; - } - - /* -------------------------------------------------------------------------------------------- - * Attempt to bind a native integer value at the specified parameter index. - */ - Statement & SetInteger(const Object & param, SQInteger value) - { - Parameter(SQMOD_GET_CREATED(*this), param).SetInteger(value); - // Allow chaining of operations - return *this; - } - - /* -------------------------------------------------------------------------------------------- - * Attempt to bind a signed 8 bit integer value at the specified parameter index. - */ - Statement & SetInt8(const Object & param, SQInteger value) - { - Parameter(SQMOD_GET_CREATED(*this), param).SetInt8(value); - // Allow chaining of operations - return *this; - } - - /* -------------------------------------------------------------------------------------------- - * Attempt to bind an unsigned 8 bit integer value at the specified parameter index. - */ - Statement & SetUint8(const Object & param, SQInteger value) - { - Parameter(SQMOD_GET_CREATED(*this), param).SetUint8(value); - // Allow chaining of operations - return *this; - } - - /* -------------------------------------------------------------------------------------------- - * Attempt to bind a signed 16 bit integer value at the specified parameter index. - */ - Statement & SetInt16(const Object & param, SQInteger value) - { - Parameter(SQMOD_GET_CREATED(*this), param).SetInt16(value); - // Allow chaining of operations - return *this; - } - - /* -------------------------------------------------------------------------------------------- - * Attempt to bind an unsigned 16 bit integer value at the specified parameter index. - */ - Statement & SetUint16(const Object & param, SQInteger value) - { - Parameter(SQMOD_GET_CREATED(*this), param).SetUint16(value); - // Allow chaining of operations - return *this; - } - - /* -------------------------------------------------------------------------------------------- - * Attempt to bind a signed 32 bit integer value at the specified parameter index. - */ - Statement & SetInt32(const Object & param, SQInteger value) - { - Parameter(SQMOD_GET_CREATED(*this), param).SetInt32(value); - // Allow chaining of operations - return *this; - } - - /* -------------------------------------------------------------------------------------------- - * Attempt to bind an unsigned 32 bit integer value at the specified parameter index. - */ - Statement & SetUint32(const Object & param, SQInteger value) - { - Parameter(SQMOD_GET_CREATED(*this), param).SetUint32(value); - // Allow chaining of operations - return *this; - } - - /* -------------------------------------------------------------------------------------------- - * Attempt to bind a signed 64 bit integer value at the specified parameter index. - */ - Statement & SetInt64(const Object & param, const Object & value) - { - Parameter(SQMOD_GET_CREATED(*this), param).SetInt64(value); - // Allow chaining of operations - return *this; - } - - /* -------------------------------------------------------------------------------------------- - * Attempt to bind an unsigned 64 bit integer value at the specified parameter index. - */ - Statement & SetUint64(const Object & param, const Object & value) - { - Parameter(SQMOD_GET_CREATED(*this), param).SetUint64(value); - // Allow chaining of operations - return *this; - } - - /* -------------------------------------------------------------------------------------------- - * Attempt to bind a native floating point value at the specified parameter index. - */ - Statement & SetFloat(const Object & param, SQFloat value) - { - Parameter(SQMOD_GET_CREATED(*this), param).SetFloat(value); - // Allow chaining of operations - return *this; - } - - /* -------------------------------------------------------------------------------------------- - * Attempt to bind a 32 bit floating point value at the specified parameter index. - */ - Statement & SetFloat32(const Object & param, SQFloat value) - { - Parameter(SQMOD_GET_CREATED(*this), param).SetFloat32(value); - // Allow chaining of operations - return *this; - } - - /* -------------------------------------------------------------------------------------------- - * Attempt to bind a 64 bit floating point value at the specified parameter index. - */ - Statement & SetFloat64(const Object & param, SQFloat value) - { - Parameter(SQMOD_GET_CREATED(*this), param).SetFloat64(value); - // Allow chaining of operations - return *this; - } - - /* -------------------------------------------------------------------------------------------- - * Attempt to bind a string value at the specified parameter index. - */ - Statement & SetString(const Object & param, StackStrF & value) - { - Parameter(SQMOD_GET_CREATED(*this), param).SetString(value); - // Allow chaining of operations - return *this; - } - - /* -------------------------------------------------------------------------------------------- - * Attempt to bind a zeroed blob value at the specified parameter index. - */ - Statement & SetZeroBlob(const Object & param, SQInteger size) - { - Parameter(SQMOD_GET_CREATED(*this), param).SetZeroBlob(size); - // Allow chaining of operations - return *this; - } - - /* -------------------------------------------------------------------------------------------- - * Attempt to bind a blob value at the specified parameter index. - */ - Statement & SetBlob(const Object & param, const Object & value) - { - Parameter(SQMOD_GET_CREATED(*this), param).SetBlob(value); - // Allow chaining of operations - return *this; - } - - /* -------------------------------------------------------------------------------------------- - * Attempt to bind a buffer value at the specified parameter index. - */ - Statement & SetData(const Object & param, const Object & value) - { - Parameter(SQMOD_GET_CREATED(*this), param).SetData(value.Cast< const SqBuffer & >()); - // Allow chaining of operations - return *this; - } - - /* -------------------------------------------------------------------------------------------- - * Attempt to bind a date value at the specified parameter index. - */ - Statement & SetDate(const Object & param, const Object & value) - { - Parameter(SQMOD_GET_CREATED(*this), param).SetDate(value.Cast< const Date & >()); - // Allow chaining of operations - return *this; - } - - /* -------------------------------------------------------------------------------------------- - * Attempt to bind a date value at the specified parameter index. - */ - Statement & SetDateEx(const Object & param, SQInteger year, SQInteger month, SQInteger day) - { - Parameter(SQMOD_GET_CREATED(*this), param).SetDateEx(year, month, day); - // Allow chaining of operations - return *this; - } - - /* -------------------------------------------------------------------------------------------- - * Attempt to bind a time value at the specified parameter index. - */ - Statement & SetTime(const Object & param, const Object & value) - { - Parameter(SQMOD_GET_CREATED(*this), param).SetTime(value.Cast< const Time & >()); - // Allow chaining of operations - return *this; - } - - /* -------------------------------------------------------------------------------------------- - * Attempt to bind a time value at the specified parameter index. - */ - Statement & SetTimeEx(const Object & param, SQInteger hour, SQInteger minute, SQInteger second) - { - Parameter(SQMOD_GET_CREATED(*this), param).SetTimeEx(hour, minute, second); - // Allow chaining of operations - return *this; - } - - /* -------------------------------------------------------------------------------------------- - * Attempt to bind a date-time value at the specified parameter index. - */ - Statement & SetDatetime(const Object & param, const Object & value) - { - Parameter(SQMOD_GET_CREATED(*this), param).SetDatetime(value.Cast< const Datetime & >()); - // Allow chaining of operations - return *this; - } - - /* -------------------------------------------------------------------------------------------- - * Attempt to bind a date-time value at the specified parameter index. - */ - Statement & SetDatetimeEx(const Object & param, SQInteger year, SQInteger month, SQInteger day, - SQInteger hour, SQInteger minute, SQInteger second) - { - Parameter(SQMOD_GET_CREATED(*this), param).SetDatetimeEx(year, month, day, hour, minute, second); - // Allow chaining of operations - return *this; - } - - /* -------------------------------------------------------------------------------------------- - * Attempt to bind the current timestamp at the specified parameter index. - */ - Statement & SetNow(const Object & param) - { - Parameter(SQMOD_GET_CREATED(*this), param).SetNow(); - // Allow chaining of operations - return *this; - } - - /* -------------------------------------------------------------------------------------------- - * Attempt to bind a null value at the specified parameter index. - */ - Statement & SetNull(const Object & param) - { - Parameter(SQMOD_GET_CREATED(*this), param).SetNull(); - // Allow chaining of operations - return *this; - } - - /* -------------------------------------------------------------------------------------------- - * Attempt to bind the values from an array starting at the specified index. - */ - Statement & SetArray(Int32 idx, const Array & arr); - - /* -------------------------------------------------------------------------------------------- - * Attempt to bind the values from an associative container. - */ - Statement & SetTable(const Table & tbl); - - /* -------------------------------------------------------------------------------------------- - * Retrieve the column with the specified name or index. - */ - Object GetColumn(const Object & column) const - { - return Object(new Column(m_Handle, column)); - } - - /* -------------------------------------------------------------------------------------------- - * Retrieve the value inside the referenced column as a dynamic type. - */ - Object GetValue(const Object & column) const - { - return Column(SQMOD_GET_CREATED(*this), column).GetValue(); - } - - /* -------------------------------------------------------------------------------------------- - * Retrieve the value inside the referenced column as a numeric type. - */ - Object GetNumber(const Object & column) const - { - return Column(SQMOD_GET_CREATED(*this), column).GetNumber(); - } - - /* -------------------------------------------------------------------------------------------- - * Retrieve the value inside the referenced column as a native script integer. - */ - SQInteger GetInteger(const Object & column) const - { - return Column(SQMOD_GET_CREATED(*this), column).GetInteger(); - } - - /* -------------------------------------------------------------------------------------------- - * Retrieve the value inside the referenced column as a native script floating point. - */ - SQFloat GetFloat(const Object & column) const - { - return Column(SQMOD_GET_CREATED(*this), column).GetFloat(); - } - - /* -------------------------------------------------------------------------------------------- - * Retrieve the value inside the referenced column as a long integer. - */ - Object GetLong(const Object & column) const - { - return Column(SQMOD_GET_CREATED(*this), column).GetLong(); - } - - /* -------------------------------------------------------------------------------------------- - * Retrieve the value inside the referenced column as a string. - */ - Object GetString(const Object & column) const - { - return Column(SQMOD_GET_CREATED(*this), column).GetString(); - } - - /* -------------------------------------------------------------------------------------------- - * Retrieve the value inside the referenced column as a boolean. - */ - bool GetBoolean(const Object & column) const - { - return Column(SQMOD_GET_CREATED(*this), column).GetBoolean(); - } - - /* -------------------------------------------------------------------------------------------- - * Retrieve the value inside the referenced column as a character. - */ - SQChar GetChar(const Object & column) const - { - return Column(SQMOD_GET_CREATED(*this), column).GetChar(); - } - - /* -------------------------------------------------------------------------------------------- - * Retrieve the value inside the referenced column as a memory buffer. - */ - Object GetBuffer(const Object & column) const - { - return Column(SQMOD_GET_CREATED(*this), column).GetBuffer(); - } - - /* -------------------------------------------------------------------------------------------- - * Retrieve the value inside the referenced column as a memory blob. - */ - Object GetBlob(const Object & column) const - { - return Column(SQMOD_GET_CREATED(*this), column).GetBlob(); - } - - /* -------------------------------------------------------------------------------------------- - * Retrieve the row as an array container. - */ - Array GetArray() const - { - return GetArray(0, SQMOD_GET_CREATED(*this)->mColumns); - } - - /* -------------------------------------------------------------------------------------------- - * Retrieve the row as an array container. - */ - Array GetArray(Int32 min) const - { - return GetArray(min, SQMOD_GET_CREATED(*this)->mColumns); - } - - /* -------------------------------------------------------------------------------------------- - * Retrieve the row as an array container. - */ - Array GetArray(Int32 min, Int32 max) const; - - /* -------------------------------------------------------------------------------------------- - * Retrieve the row as an associative container. - */ - Table GetTable() const - { - // Is there something to return? - if (SQMOD_GET_CREATED(*this)->mColumns > 0) - { - return GetTable(0, m_Handle->mColumns - 1); - } - // Fallback to empty table - return NullTable(); - } - - /* -------------------------------------------------------------------------------------------- - * Retrieve the row as an associative container. - */ - Table GetTable(Int32 min) const - { - // Is there something to return? - if (SQMOD_GET_CREATED(*this)->mColumns > 0) - { - return GetTable(min, m_Handle->mColumns - 1); - } - // Fallback to empty table - return NullTable(); - } - - /* -------------------------------------------------------------------------------------------- - * Retrieve the row as an associative container. - */ - Table GetTable(Int32 min, Int32 max) const; -}; - -} // Namespace:: SqMod diff --git a/module/Library/SQLite/Transaction.cpp b/module/Library/SQLite/Transaction.cpp deleted file mode 100644 index 8f4ff0b2..00000000 --- a/module/Library/SQLite/Transaction.cpp +++ /dev/null @@ -1,102 +0,0 @@ -// ------------------------------------------------------------------------------------------------ -#include "Library/SQLite/Transaction.hpp" - -#include -#include "Library/SQLite/Connection.hpp" - -// ------------------------------------------------------------------------------------------------ -namespace SqMod { - -// ------------------------------------------------------------------------------------------------ -SQMODE_DECL_TYPENAME(Typename, _SC("SqLiteTransaction")) - -// ------------------------------------------------------------------------------------------------ -Transaction::Transaction(const Connection & db) - : Transaction(db.GetHandle()) -{ - /* ... */ -} - -// ------------------------------------------------------------------------------------------------ -Transaction::Transaction(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 [%s]", m_Handle->ErrMsg()); - } -} - -// ------------------------------------------------------------------------------------------------ -Transaction::~Transaction() -{ - // 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 Transaction::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 [%s]", m_Handle->ErrMsg()); - } - else - { - m_Committed = true; // Everything was committed successfully - } - // Return the result - return m_Committed; -} - -// ================================================================================================ -void Register_Transaction(Table & sqlns) -{ - sqlns.Bind(_SC("Transaction"), - Class< Transaction, NoCopy< Transaction > >(sqlns.GetVM(), Typename::Str) - // Constructors - .Ctor< const Connection & >() - // Meta-methods - .SquirrelFunc(_SC("_typename"), &Typename::Fn) - .Func(_SC("_tostring"), &Transaction::ToString) - // Properties - .Prop(_SC("IsValid"), &Transaction::IsValid) - .Prop(_SC("Committed"), &Transaction::Commited) - // Member Methods - .Func(_SC("Commit"), &Transaction::Commit) - ); -} - -} // Namespace:: SqMod diff --git a/module/Library/SQLite/Transaction.hpp b/module/Library/SQLite/Transaction.hpp deleted file mode 100644 index 6497f974..00000000 --- a/module/Library/SQLite/Transaction.hpp +++ /dev/null @@ -1,95 +0,0 @@ -#pragma once - -// ------------------------------------------------------------------------------------------------ -#include "Library/SQLite/Handle.hpp" - -// ------------------------------------------------------------------------------------------------ -namespace SqMod { - -/* ------------------------------------------------------------------------------------------------ - * Implements the RAII pattern for database transactions. -*/ -class Transaction -{ -public: - - /* -------------------------------------------------------------------------------------------- - * Construct by taking the handle from a connection. - */ - Transaction(const Connection & db); - - /* -------------------------------------------------------------------------------------------- - * Construct using the direct connection handle. - */ - Transaction(ConnRef db); - - /* -------------------------------------------------------------------------------------------- - * Copy constructor. (disabled) - */ - Transaction(const Transaction & o) = delete; - - /* -------------------------------------------------------------------------------------------- - * Move constructor. (disabled) - */ - Transaction(Transaction && o) = delete; - - /* -------------------------------------------------------------------------------------------- - * Destructor. - */ - ~Transaction(); - - /* -------------------------------------------------------------------------------------------- - * Copy assignment operator. (disabled) - */ - Transaction & operator = (const Transaction & o) = delete; - - /* -------------------------------------------------------------------------------------------- - * Move assignment operator. (disabled) - */ - Transaction & operator = (Transaction && o) = delete; - - /* -------------------------------------------------------------------------------------------- - * Used by the script engine to convert an instance of this type to a string. - */ - const String & ToString() const - { - return m_Handle ? m_Handle->mName : NullString(); - } - - /* -------------------------------------------------------------------------------------------- - * Retrieve the associated statement handle. - */ - const ConnRef & GetHandle() const - { - return m_Handle; - } - - /* -------------------------------------------------------------------------------------------- - * See whether the managed handle is valid. - */ - bool IsValid() const - { - return m_Handle; - } - - /* -------------------------------------------------------------------------------------------- - * Attempt to commit changes to the database. - */ - bool Commit(); - - /* -------------------------------------------------------------------------------------------- - * See whether the change during this transaction were successfully committed. - */ - bool Commited() const - { - return m_Committed; - } - -private: - - // -------------------------------------------------------------------------------------------- - ConnRef m_Handle; // The database connection handle where the transaction began. - bool m_Committed; // Whether changes were successfully committed to the database. -}; - -} // Namespace:: SqMod