#pragma once // ------------------------------------------------------------------------------------------------ #include "Core/Utility.hpp" // ------------------------------------------------------------------------------------------------ #include "Library/IO/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 // ------------------------------------------------------------------------------------------------ #ifdef SQMOD_POCO_HAS_SQLITE #include #else #error Enable SQLite support in order to compile this library. #endif // ------------------------------------------------------------------------------------------------ namespace SqMod { /* ------------------------------------------------------------------------------------------------ * Forward declarations. */ class SQLiteConnection; class SQLiteStatement; class SQLiteParameter; class SQLiteColumn; class SQLiteTransaction; /* ------------------------------------------------------------------------------------------------ * 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 SQLiteConnHnd; struct SQLiteStmtHnd; /* ------------------------------------------------------------------------------------------------ * Common typedefs. */ typedef SharedPtr< SQLiteConnHnd > ConnRef; typedef SharedPtr< SQLiteStmtHnd > 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); /* ------------------------------------------------------------------------------------------------ * Tests if a certain query string is empty. */ SQMOD_NODISCARD bool IsQueryEmpty(const SQChar * str); /* ------------------------------------------------------------------------------------------------ * Retrieve the string representation of a certain status code. */ SQMOD_NODISCARD const SQChar * GetErrStr(int32_t status); /* ------------------------------------------------------------------------------------------------ * Set a specific heap limit. */ void SetSoftHeapLimit(int32_t limit); /* ------------------------------------------------------------------------------------------------ * Release the specified amount of memory. */ int32_t ReleaseMemory(int32_t bytes); /* ------------------------------------------------------------------------------------------------ * Retrieve the current memory usage. */ SQMOD_NODISCARD SQInteger GetMemoryUsage(); /* ------------------------------------------------------------------------------------------------ * Retrieve the memory high watermark. */ SQMOD_NODISCARD SQInteger GetMemoryHighwaterMark(bool reset); /* ------------------------------------------------------------------------------------------------ * Retrieve the escaped version of the specified string. */ SQMOD_NODISCARD LightObj EscapeString(StackStrF & str); /* ------------------------------------------------------------------------------------------------ * Retrieve the escaped version of the specified string using the supplied format specifier. */ SQMOD_NODISCARD LightObj EscapeStringEx(SQChar spec, StackStrF & str); /* ------------------------------------------------------------------------------------------------ * Convert the values from the specified array to a list of column names string. */ SQMOD_NODISCARD LightObj ArrayToQueryColumns(Array & arr); /* ------------------------------------------------------------------------------------------------ * Convert the keys from the specified array to a list of column names string. */ SQMOD_NODISCARD LightObj TableToQueryColumns(Table & tbl); /* ------------------------------------------------------------------------------------------------ * The structure that holds the data associated with a certain connection. */ struct SQLiteConnHnd { public: // -------------------------------------------------------------------------------------------- typedef sqlite3 Type; // The managed type. // -------------------------------------------------------------------------------------------- typedef Type * Pointer; // Pointer to the managed type. typedef const Type * SQ_UNUSED_TYPEDEF(ConstPtr); // Constant pointer to the managed type. // -------------------------------------------------------------------------------------------- typedef Type & Reference; // Reference to the managed type. typedef const Type & SQ_UNUSED_TYPEDEF(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_t mStatus; // The last status code of this connection handle. // -------------------------------------------------------------------------------------------- QueryList mQueue; // A queue of queries to be executed in groups. // -------------------------------------------------------------------------------------------- int32_t 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. */ SQLiteConnHnd(); /* -------------------------------------------------------------------------------------------- * Copy constructor. (disabled) */ SQLiteConnHnd(const SQLiteConnHnd & o) = delete; /* -------------------------------------------------------------------------------------------- * Move constructor. (disabled) */ SQLiteConnHnd(SQLiteConnHnd && o) = delete; /* -------------------------------------------------------------------------------------------- * Destructor. */ ~SQLiteConnHnd(); /* -------------------------------------------------------------------------------------------- * Copy assignment operator. (disabled) */ SQLiteConnHnd & operator = (const SQLiteConnHnd & o) = delete; /* -------------------------------------------------------------------------------------------- * Move assignment operator. (disabled) */ SQLiteConnHnd & operator = (SQLiteConnHnd && o) = delete; /* -------------------------------------------------------------------------------------------- * Create the database connection resource. */ void Create(const SQChar * name, int32_t flags, const SQChar * vfs); /* -------------------------------------------------------------------------------------------- * Execute a specific amount of queries from the queue. */ int32_t Flush(uint32_t num, Object & env, Function & func); /* -------------------------------------------------------------------------------------------- * Retrieve the message of the last received error code. */ SQMOD_NODISCARD const char * ErrStr() const { return sqlite3_errstr(sqlite3_errcode(mPtr)); } /* -------------------------------------------------------------------------------------------- * Return the last error message associated with this database connection. */ SQMOD_NODISCARD const char * ErrMsg() const { return sqlite3_errmsg(mPtr); } /* -------------------------------------------------------------------------------------------- * Return the numeric result code for the most recent failed API call (if any). */ SQMOD_NODISCARD int32_t ErrNo() const { return sqlite3_errcode(mPtr); } /* -------------------------------------------------------------------------------------------- * Return the extended numeric result code for the most recent failed API call (if any). */ SQMOD_NODISCARD int32_t ExErrNo() const { return sqlite3_extended_errcode(mPtr); } }; /* ------------------------------------------------------------------------------------------------ * The structure that holds the data associated with a certain statement. */ struct SQLiteStmtHnd { public: // -------------------------------------------------------------------------------------------- typedef sqlite3_stmt Type; // The managed type. // -------------------------------------------------------------------------------------------- typedef Type * Pointer; // Pointer to the managed type. typedef const Type * SQ_UNUSED_TYPEDEF(ConstPtr); // Constant pointer to the managed type. // -------------------------------------------------------------------------------------------- typedef Type & Reference; // Reference to the managed type. typedef const Type & SQ_UNUSED_TYPEDEF(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_t 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_t mColumns; // The amount of columns available in this statement. int32_t 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. */ explicit SQLiteStmtHnd(ConnRef conn); /* -------------------------------------------------------------------------------------------- * Copy constructor. (disabled) */ SQLiteStmtHnd(const SQLiteStmtHnd & o) = delete; /* -------------------------------------------------------------------------------------------- * Move constructor. (disabled) */ SQLiteStmtHnd(SQLiteStmtHnd && o) = delete; /* -------------------------------------------------------------------------------------------- * Destructor. */ ~SQLiteStmtHnd(); /* -------------------------------------------------------------------------------------------- * Copy assignment operator. (disabled) */ SQLiteStmtHnd & operator = (const SQLiteStmtHnd & o) = delete; /* -------------------------------------------------------------------------------------------- * Move assignment operator. (disabled) */ SQLiteStmtHnd & operator = (SQLiteStmtHnd && o) = delete; /* -------------------------------------------------------------------------------------------- * Create the database statement resource. */ void Create(const SQChar * query, SQInteger length = -1); /* -------------------------------------------------------------------------------------------- * Check whether a specific column index is in range. */ SQMOD_NODISCARD bool CheckColumn(int32_t idx) const { return (idx >= 0) && (idx < mColumns); } /* -------------------------------------------------------------------------------------------- * Check whether a specific parameter index is in range. */ SQMOD_NODISCARD bool CheckParameter(int32_t idx) const { return (idx >= 1) && (idx <= mParameters); } /* -------------------------------------------------------------------------------------------- * Retrieve the column index associated with the specified name. */ SQMOD_NODISCARD int32_t GetColumnIndex(const SQChar * name, SQInteger length = -1); /* -------------------------------------------------------------------------------------------- * Retrieve the message of the last received error code. */ SQMOD_NODISCARD const char * ErrStr() const; /* -------------------------------------------------------------------------------------------- * Return the last error message associated with this database connection. */ SQMOD_NODISCARD const char * ErrMsg() const; /* -------------------------------------------------------------------------------------------- * Return the numeric result code for the most recent failed API call (if any). */ SQMOD_NODISCARD int32_t ErrNo() const; /* -------------------------------------------------------------------------------------------- * Return the extended numeric result code for the most recent failed API call (if any). */ SQMOD_NODISCARD int32_t ExErrNo() const; }; /* ------------------------------------------------------------------------------------------------ * Used to manage and interact with a database connection. */ class SQLiteConnection { private: // -------------------------------------------------------------------------------------------- ConnRef m_Handle; // Reference to the managed connection. protected: /* -------------------------------------------------------------------------------------------- * Callback function for ActivateTracing() */ static void TraceOutput(void * ptr, const char * sql); /* -------------------------------------------------------------------------------------------- * Callback function for ActivateProfiling() */ static void ProfileOutput(void * ptr, const char * sql, sqlite3_uint64 time); /* -------------------------------------------------------------------------------------------- * Validate the managed connection handle and throw an error if invalid. */ #if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) void Validate(const char * file, int32_t 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(const char * file, int32_t 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) SQMOD_NODISCARD const ConnRef & GetValid(const char * file, int32_t line) const; #else SQMOD_NODISCARD const ConnRef & GetValid() const; #endif // _DEBUG /* -------------------------------------------------------------------------------------------- * Validate the managed connection handle and throw an error if invalid. */ #if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) SQMOD_NODISCARD const ConnRef & GetCreated(const char * file, int32_t line) const; #else SQMOD_NODISCARD const ConnRef & GetCreated() const; #endif // _DEBUG public: /* -------------------------------------------------------------------------------------------- * Attempt to open the specified database. */ SQLiteConnection() : m_Handle() { /* ... */ } /* -------------------------------------------------------------------------------------------- * Explicit constructor. */ explicit SQLiteConnection(StackStrF & name) : m_Handle(new SQLiteConnHnd()) { // 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. */ SQLiteConnection(StackStrF & name, int32_t flags) : m_Handle(new SQLiteConnHnd()) { SQMOD_GET_VALID(*this)->Create(name.mPtr, flags, nullptr); } /* -------------------------------------------------------------------------------------------- * Explicit constructor. */ SQLiteConnection(StackStrF & name, int32_t flags, StackStrF & vfs) : m_Handle(new SQLiteConnHnd()) { SQMOD_GET_VALID(*this)->Create(name.mPtr, flags, vfs.mPtr); } /* -------------------------------------------------------------------------------------------- * Direct handle constructor. */ explicit SQLiteConnection(ConnRef c) : m_Handle(std::move(c)) { /* ... */ } /* -------------------------------------------------------------------------------------------- * Copy constructor. */ SQLiteConnection(const SQLiteConnection & o) = default; /* -------------------------------------------------------------------------------------------- * Move constructor. */ SQLiteConnection(SQLiteConnection && o) = default; /* -------------------------------------------------------------------------------------------- * Copy assignment operator. */ SQLiteConnection & operator = (const SQLiteConnection & o) = default; /* -------------------------------------------------------------------------------------------- * Move assignment operator. */ SQLiteConnection & operator = (SQLiteConnection && o) = default; /* -------------------------------------------------------------------------------------------- * Perform an equality comparison between two connections. */ bool operator == (const SQLiteConnection & o) const { return (m_Handle == o.m_Handle); } /* -------------------------------------------------------------------------------------------- * Perform an inequality comparison between two connections. */ bool operator != (const SQLiteConnection & 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. */ SQMOD_NODISCARD const String & ToString() const { return m_Handle ? m_Handle->mName : NullString(); } /* -------------------------------------------------------------------------------------------- * Retrieve the associated connection handle. */ SQMOD_NODISCARD const ConnRef & GetHandle() const { return m_Handle; } /* -------------------------------------------------------------------------------------------- * See whether the managed connection handle is valid. */ SQMOD_NODISCARD bool IsValid() const { return m_Handle; } /* -------------------------------------------------------------------------------------------- * See whether the managed connection handle was connected. */ SQMOD_NODISCARD bool IsConnected() const { return m_Handle && (m_Handle->mPtr != nullptr); } /* -------------------------------------------------------------------------------------------- * Return the number of active references to this connection handle. */ SQMOD_NODISCARD uint32_t 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. */ SQMOD_NODISCARD int32_t GetStatus() const { return SQMOD_GET_VALID(*this)->mStatus; } /* -------------------------------------------------------------------------------------------- * Retrieve the flags used to create this database connection. */ SQMOD_NODISCARD int32_t GetFlags() const { return SQMOD_GET_VALID(*this)->mFlags; } /* -------------------------------------------------------------------------------------------- * Retrieve the name used to create this database connection. */ SQMOD_NODISCARD const String & GetName() const { return SQMOD_GET_VALID(*this)->mName; } /* -------------------------------------------------------------------------------------------- * Retrieve the virtual file system used to create this database connection. */ SQMOD_NODISCARD const String & GetVFS() const { return SQMOD_GET_VALID(*this)->mVFS; } /* -------------------------------------------------------------------------------------------- * Return the numeric result code for the most recent failed API call (if any). */ SQMOD_NODISCARD int32_t GetErrorCode() const { return SQMOD_GET_VALID(*this)->ErrNo(); } /* -------------------------------------------------------------------------------------------- * Return the extended numeric result code for the most recent failed API call (if any). */ SQMOD_NODISCARD int32_t GetExtendedErrorCode() const { return SQMOD_GET_VALID(*this)->ExErrNo(); } /* -------------------------------------------------------------------------------------------- * Retrieve the message of the last received error code. */ SQMOD_NODISCARD const SQChar * GetErrStr() const { return SQMOD_GET_VALID(*this)->ErrStr(); } /* -------------------------------------------------------------------------------------------- * Return the last error message associated with this database connection. */ SQMOD_NODISCARD const SQChar * 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_t flags); /* -------------------------------------------------------------------------------------------- * Attempt to open the specified database. */ void Open(StackStrF & name, int32_t flags, StackStrF & vfs); /* -------------------------------------------------------------------------------------------- * Attempt to execute the specified query. */ int32_t 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. */ SQMOD_NODISCARD bool IsReadOnly() const; /* -------------------------------------------------------------------------------------------- * Shortcut to test if a table exists. */ SQMOD_NODISCARD bool TableExists(StackStrF & name) const; /* -------------------------------------------------------------------------------------------- * See if the database connection is or is not in auto-commit mode. */ SQMOD_NODISCARD bool GetAutoCommit() const { return static_cast< bool >(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. */ SQMOD_NODISCARD SQInteger GetLastInsertRowID() const { return 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. */ SQMOD_NODISCARD int32_t 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. */ SQMOD_NODISCARD int32_t GetTotalChanges() const { return sqlite3_total_changes(SQMOD_GET_CREATED(*this)->mPtr); } /* -------------------------------------------------------------------------------------------- * See if this database connection has tracing enabled. */ SQMOD_NODISCARD 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. */ SQMOD_NODISCARD 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_t 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. */ SQMOD_NODISCARD int32_t GetInfo(int32_t operation) { return GetInfo(operation, false, false); } /* -------------------------------------------------------------------------------------------- * Returns internal runtime status information associated with the current database connection. */ SQMOD_NODISCARD int32_t GetInfo(int32_t operation, bool highwater) { return GetInfo(operation, highwater, false); } /* -------------------------------------------------------------------------------------------- * Returns internal runtime status information associated with the current database connection. */ SQMOD_NODISCARD int32_t GetInfo(int32_t operation, bool highwater, bool reset); /* -------------------------------------------------------------------------------------------- * Retrieve the number of queries in the queue. */ SQMOD_NODISCARD uint32_t QueueSize() const { return ConvTo< uint32_t >::From(SQMOD_GET_VALID(*this)->mQueue.size()); } /* -------------------------------------------------------------------------------------------- * Reserve space upfront for the specified amount of queries in the query queue. */ void ReserveQueue(uint32_t 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_t Flush(); /* -------------------------------------------------------------------------------------------- * Flush a specific amount of queries from the queue. */ int32_t Flush(SQInteger num); /* -------------------------------------------------------------------------------------------- * Flush all queries from the queue and handle errors manually. */ int32_t Flush(Object & env, Function & func); /* -------------------------------------------------------------------------------------------- * Flush a specific amount of queries from the queue and handle errors manually. */ int32_t Flush(SQInteger num, Object & env, Function & func); }; /* ------------------------------------------------------------------------------------------------ * Used to manage and interact with parameters from a database statement. */ class SQLiteParameter { // -------------------------------------------------------------------------------------------- friend class SQLiteStatement; private: // -------------------------------------------------------------------------------------------- int32_t m_Index{0}; // 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(const char * file, int32_t 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(const char * file, int32_t 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) SQMOD_NODISCARD const StmtRef & GetValid(const char * file, int32_t line) const; #else SQMOD_NODISCARD const StmtRef & GetValid() const; #endif // _DEBUG /* -------------------------------------------------------------------------------------------- * Validate the managed statement handle and throw an error if invalid. */ #if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) SQMOD_NODISCARD const StmtRef & GetCreated(const char * file, int32_t line) const; #else SQMOD_NODISCARD 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_t idx, const char * file, int32_t line) const; #else void ValidateParam(int32_t idx) const; #endif // _DEBUG /* -------------------------------------------------------------------------------------------- * Modify the index to the specified value. */ void SetIndex(int32_t idx) { // Assign the index with a failsafe to invalid on error AutoAssign< int32_t > 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(const SQChar * 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). */ SQLiteParameter() = default; /* -------------------------------------------------------------------------------------------- * No parameter constructor. */ explicit SQLiteParameter(StmtRef stmt) : m_Index(0), m_Handle(std::move(stmt)) { /* ... */ } /* -------------------------------------------------------------------------------------------- * Index constructor. */ SQLiteParameter(StmtRef stmt, int32_t idx) : m_Index(idx), m_Handle(std::move(stmt)) { SQMOD_VALIDATE_PARAM(*this, m_Index); } /* -------------------------------------------------------------------------------------------- * Name constructor. */ SQLiteParameter(const StmtRef & stmt, const SQChar * name) : m_Index(stmt ? sqlite3_bind_parameter_index(stmt->mPtr, name) : 0), m_Handle(stmt) { SQMOD_VALIDATE_PARAM(*this, m_Index); } /* -------------------------------------------------------------------------------------------- * Dynamic constructor. */ SQLiteParameter(StmtRef stmt, const Object & param) : m_Index(0), m_Handle(std::move(stmt)) { if (!m_Handle) { STHROWF("Invalid SQLite statement reference"); } // Extract the index SetIndex(param); } /* -------------------------------------------------------------------------------------------- * Copy constructor. */ SQLiteParameter(const SQLiteParameter & o) = default; /* -------------------------------------------------------------------------------------------- * Move constructor. */ SQLiteParameter(SQLiteParameter && o) = default; /* -------------------------------------------------------------------------------------------- * Copy assignment operator. */ SQLiteParameter & operator = (const SQLiteParameter & o) = default; /* -------------------------------------------------------------------------------------------- * Move assignment operator. */ SQLiteParameter & operator = (SQLiteParameter && o) = default; /* -------------------------------------------------------------------------------------------- * Perform an equality comparison between two parameter indexes. */ bool operator == (const SQLiteParameter & o) const { return (m_Index == o.m_Index); } /* -------------------------------------------------------------------------------------------- * Perform an inequality comparison between two parameter indexes. */ bool operator != (const SQLiteParameter & o) const { return (m_Index != o.m_Index); } /* -------------------------------------------------------------------------------------------- * Implicit conversion to boolean for use in boolean operations. */ operator bool () const // NOLINT(google-explicit-constructor,hicpp-explicit-conversions) { return m_Index >= 0; } /* -------------------------------------------------------------------------------------------- * Used by the script engine to convert an instance of this type to a string. */ SQMOD_NODISCARD String ToString() const { // Can we attempt to return the parameter name? if (m_Handle && m_Index) { const SQChar * val = sqlite3_bind_parameter_name(m_Handle->mPtr, m_Index); // Return the value if valid return val ? val : String{}; } else { return fmt::format("{}", m_Index); } } /* -------------------------------------------------------------------------------------------- * See whether this statement is valid. */ SQMOD_NODISCARD bool IsValid() const { return m_Handle; // An invalid statement means an invalid parameter } /* -------------------------------------------------------------------------------------------- * Return the number of active references to this statement handle. */ SQMOD_NODISCARD uint32_t GetRefCount() const { return m_Handle.Count(); } /* -------------------------------------------------------------------------------------------- * Retrieve the associated parameter index. */ SQMOD_NODISCARD int32_t GetIndex() const { return m_Index; } /* -------------------------------------------------------------------------------------------- * Retrieve the associated database statement. */ SQMOD_NODISCARD Object GetStatement() const; /* -------------------------------------------------------------------------------------------- * Retrieve the associated database connection. */ SQMOD_NODISCARD Object GetConnection() const; /* -------------------------------------------------------------------------------------------- * Retrieve the name of the referenced parameter. */ SQMOD_NODISCARD const SQChar * 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(SQInteger value); /* -------------------------------------------------------------------------------------------- * Attempt to bind an unsigned 64 bit integer value at the referenced parameter index. */ void SetUint64(SQInteger 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(const SQChar * 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 SQLiteColumn { // -------------------------------------------------------------------------------------------- friend class SQLiteStatement; private: // -------------------------------------------------------------------------------------------- int32_t m_Index{-1}; // 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(const char * file, int32_t 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(const char * file, int32_t 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) SQMOD_NODISCARD const StmtRef & GetValid(const char * file, int32_t line) const; #else SQMOD_NODISCARD const StmtRef & GetValid() const; #endif // _DEBUG /* -------------------------------------------------------------------------------------------- * Validate the managed statement handle and throw an error if invalid. */ #if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) SQMOD_NODISCARD const StmtRef & GetCreated(const char * file, int32_t line) const; #else SQMOD_NODISCARD 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_t idx, const char * file, int32_t line) const; #else void ValidateColumn(int32_t 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(const char * file, int32_t line) const; #else void ValidateRow() const; #endif // _DEBUG /* -------------------------------------------------------------------------------------------- * Modify the index to the specified value. */ void SetIndex(int32_t idx) { // Assign the index with a failsafe to invalid on error AutoAssign< int32_t > aa(m_Index, -1, idx); // Validate the obtained column index SQMOD_VALIDATE_COLUMN(*this, idx); // Don't fall back to the invalid index anymore aa.Set(idx); } /* -------------------------------------------------------------------------------------------- * Modify the index to the specified value. */ void SetIndex(const SQChar * name) { SetIndex(SQMOD_GET_CREATED(*this)->GetColumnIndex(name)); } /* -------------------------------------------------------------------------------------------- * Modify the index to the specified value. */ void SetIndex(const Object & column); public: /* -------------------------------------------------------------------------------------------- * Default constructor (null). */ SQLiteColumn() = default; /* -------------------------------------------------------------------------------------------- * No column constructor. */ explicit SQLiteColumn(StmtRef stmt) : m_Index(-1), m_Handle(std::move(stmt)) { /* ... */ } /* -------------------------------------------------------------------------------------------- * Index constructor. */ SQLiteColumn(StmtRef stmt, int32_t idx) : m_Index(idx), m_Handle(std::move(stmt)) { SQMOD_VALIDATE_COLUMN(*this, m_Index); } /* -------------------------------------------------------------------------------------------- * Name constructor. */ SQLiteColumn(const StmtRef & stmt, const SQChar * name) : m_Index(stmt ? stmt->GetColumnIndex(name) : -1), m_Handle(stmt) { SQMOD_VALIDATE_COLUMN(*this, m_Index); } /* -------------------------------------------------------------------------------------------- * Dynamic constructor. */ SQLiteColumn(StmtRef stmt, const Object & column) : m_Index(-1), m_Handle(std::move(stmt)) { if (!m_Handle) { STHROWF("Invalid SQLite statement reference"); } // Extract the index SetIndex(column); } /* -------------------------------------------------------------------------------------------- * Copy constructor. */ SQLiteColumn(const SQLiteColumn & o) = default; /* -------------------------------------------------------------------------------------------- * Move constructor. */ SQLiteColumn(SQLiteColumn && o) = default; /* -------------------------------------------------------------------------------------------- * Copy assignment operator. */ SQLiteColumn & operator = (const SQLiteColumn & o) = default; /* -------------------------------------------------------------------------------------------- * Move assignment operator. */ SQLiteColumn & operator = (SQLiteColumn && o) = default; /* -------------------------------------------------------------------------------------------- * Perform an equality comparison between two table column indexes. */ bool operator == (const SQLiteColumn & o) const { return (m_Index == o.m_Index); } /* -------------------------------------------------------------------------------------------- * Perform an inequality comparison between two table column indexes. */ bool operator != (const SQLiteColumn & o) const { return (m_Index != o.m_Index); } /* -------------------------------------------------------------------------------------------- * Implicit conversion to boolean for use in boolean operations. */ operator bool () const // NOLINT(google-explicit-constructor,hicpp-explicit-conversions) { return m_Index >= 0; } /* -------------------------------------------------------------------------------------------- * Used by the script engine to convert an instance of this type to a string. */ SQMOD_NODISCARD String ToString() const { // Can we attempt to return the parameter name? if (m_Handle && m_Index) { const SQChar * val = sqlite3_column_name(m_Handle->mPtr, m_Index); // Return the value if valid return val ? val : String{}; } else { return fmt::format("{}", m_Index); } } /* -------------------------------------------------------------------------------------------- * See whether the column is valid. */ SQMOD_NODISCARD bool IsValid() const { return m_Handle; // An invalid statement means an invalid column } /* -------------------------------------------------------------------------------------------- * Return the number of active references to the associated statement handle. */ SQMOD_NODISCARD uint32_t GetRefCount() const { return m_Handle.Count(); } /* -------------------------------------------------------------------------------------------- * Retrieve the referenced column index. */ SQMOD_NODISCARD int32_t GetIndex() const { return m_Index; } /* -------------------------------------------------------------------------------------------- * Retrieve the referenced database statement. */ SQMOD_NODISCARD Object GetStatement() const; /* -------------------------------------------------------------------------------------------- * Retrieve the referenced database connection. */ SQMOD_NODISCARD 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. */ SQMOD_NODISCARD bool IsNull() const; /* -------------------------------------------------------------------------------------------- * Retrieve the name of the referenced column index. */ SQMOD_NODISCARD const SQChar * GetName() const; /* -------------------------------------------------------------------------------------------- * Retrieve the column origin name if the library was compiled with such feature. */ SQMOD_NODISCARD const SQChar * GetOriginName() const; /* -------------------------------------------------------------------------------------------- * Retrieve the type identifier of the referenced column index. */ SQMOD_NODISCARD int32_t GetType() const; /* -------------------------------------------------------------------------------------------- * Retrieve the size in bytes of the referenced column index. */ SQMOD_NODISCARD int32_t GetBytes() const; /* -------------------------------------------------------------------------------------------- * Retrieve the value inside the referenced column as a dynamic type. */ SQMOD_NODISCARD Object GetValue() const; /* -------------------------------------------------------------------------------------------- * Retrieve the value inside the referenced column as a numeric type. */ SQMOD_NODISCARD Object GetNumber() const; /* -------------------------------------------------------------------------------------------- * Retrieve the value inside the referenced column as a native script integer. */ SQMOD_NODISCARD SQInteger GetInteger() const; /* -------------------------------------------------------------------------------------------- * Retrieve the value inside the referenced column as a native script floating point. */ SQMOD_NODISCARD SQFloat GetFloat() const; /* -------------------------------------------------------------------------------------------- * Retrieve the value inside the referenced column as a long integer. */ SQMOD_NODISCARD SQInteger GetLong() const; /* -------------------------------------------------------------------------------------------- * Retrieve the value inside the referenced column as a string. */ SQMOD_NODISCARD Object GetString() const; /* -------------------------------------------------------------------------------------------- * Retrieve the value inside the referenced column as a boolean. */ SQMOD_NODISCARD bool GetBoolean() const; /* -------------------------------------------------------------------------------------------- * Retrieve the value inside the referenced column as a character. */ SQMOD_NODISCARD SQChar GetChar() const; /* -------------------------------------------------------------------------------------------- * Retrieve the value inside the referenced column as a memory buffer. */ SQMOD_NODISCARD Object GetBuffer() const; /* -------------------------------------------------------------------------------------------- * Retrieve the value inside the referenced column as a memory blob. */ SQMOD_NODISCARD Object GetBlob() const; }; /* ------------------------------------------------------------------------------------------------ * Used to manage and interact a database statement. */ class SQLiteStatement { 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(const char * file, int32_t 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(const char * file, int32_t 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) SQMOD_NODISCARD const StmtRef & GetValid(const char * file, int32_t line) const; #else SQMOD_NODISCARD const StmtRef & GetValid() const; #endif // _DEBUG /* -------------------------------------------------------------------------------------------- * Validate the managed statement handle and throw an error if invalid. */ #if defined(_DEBUG) || defined(SQMOD_EXCEPTLOC) SQMOD_NODISCARD const StmtRef & GetCreated(const char * file, int32_t line) const; #else SQMOD_NODISCARD 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_t idx, const char * file, int32_t line) const; #else void ValidateColumn(int32_t 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_t idx, const char * file, int32_t line) const; #else void ValidateParam(int32_t 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(const char * file, int32_t line) const; #else void ValidateRow() const; #endif // _DEBUG public: /* -------------------------------------------------------------------------------------------- * Default constructor. */ SQLiteStatement() : m_Handle() { /* ... */ } /* -------------------------------------------------------------------------------------------- * Construct a statement under the specified connection using the specified string. */ SQLiteStatement(const ConnRef & connection, StackStrF & query) : m_Handle(new SQLiteStmtHnd(connection)) { SQMOD_GET_VALID(*this)->Create(query.mPtr, query.mLen); } /* -------------------------------------------------------------------------------------------- * Construct a statement under the specified connection using the specified string. */ SQLiteStatement(const SQLiteConnection & connection, StackStrF & query); /* -------------------------------------------------------------------------------------------- * Direct handle constructor. */ explicit SQLiteStatement(StmtRef s) : m_Handle(std::move(s)) { /* ... */ } /* -------------------------------------------------------------------------------------------- * Copy constructor. */ SQLiteStatement(const SQLiteStatement & o) = default; /* -------------------------------------------------------------------------------------------- * Move constructor. */ SQLiteStatement(SQLiteStatement && o) = default; /* -------------------------------------------------------------------------------------------- * Copy assignment operator. */ SQLiteStatement & operator = (const SQLiteStatement & o) = default; /* -------------------------------------------------------------------------------------------- * Move assignment operator. */ SQLiteStatement & operator = (SQLiteStatement && o) = default; /* -------------------------------------------------------------------------------------------- * Perform an equality comparison between two connections. */ bool operator == (const SQLiteStatement & o) const { return (m_Handle.Get() == o.m_Handle.Get()); } /* -------------------------------------------------------------------------------------------- * Perform an inequality comparison between two connections. */ bool operator != (const SQLiteStatement & o) const { return (m_Handle.Get() != o.m_Handle.Get()); } /* -------------------------------------------------------------------------------------------- * Implicit conversion to the raw connection handle. */ operator sqlite3_stmt * () // NOLINT(google-explicit-constructor,hicpp-explicit-conversions) { return m_Handle ? m_Handle->mPtr : nullptr; } /* -------------------------------------------------------------------------------------------- * Implicit conversion to the raw connection handle. */ operator sqlite3_stmt * () const // NOLINT(google-explicit-constructor,hicpp-explicit-conversions) { return m_Handle ? m_Handle->mPtr : nullptr; } /* -------------------------------------------------------------------------------------------- * Used by the script engine to convert an instance of this type to a string. */ SQMOD_NODISCARD const String & ToString() const { return m_Handle ? m_Handle->mQuery : NullString(); } /* -------------------------------------------------------------------------------------------- * Retrieve the associated statement handle. */ SQMOD_NODISCARD const StmtRef & GetHandle() const { return m_Handle; } /* -------------------------------------------------------------------------------------------- * See whether the managed handle is valid. */ SQMOD_NODISCARD bool IsValid() const { return m_Handle; } /* -------------------------------------------------------------------------------------------- * See whether the managed statement is valid. */ SQMOD_NODISCARD bool IsPrepared() const { return m_Handle && (m_Handle->mPtr != nullptr); } /* -------------------------------------------------------------------------------------------- * Return the number of active references to this statement handle. */ SQMOD_NODISCARD uint32_t GetReferences() const { return m_Handle.Count(); } /* -------------------------------------------------------------------------------------------- * Retrieve the associated database connection. */ SQMOD_NODISCARD Object GetConnection() const; /* -------------------------------------------------------------------------------------------- * Release the reference to the associated database statement. */ void Release() { m_Handle.Reset(); } /* -------------------------------------------------------------------------------------------- * Retrieve the last received status code. */ SQMOD_NODISCARD int32_t GetStatus() const { return SQMOD_GET_VALID(*this)->mStatus; } /* -------------------------------------------------------------------------------------------- * Return the numeric result code for the most recent failed API call (if any). */ SQMOD_NODISCARD int32_t GetErrorCode() const { return SQMOD_GET_VALID(*this)->ErrNo(); } /* -------------------------------------------------------------------------------------------- * Return the extended numeric result code for the most recent failed API call (if any). */ SQMOD_NODISCARD int32_t GetExtendedErrorCode() const { return SQMOD_GET_VALID(*this)->ExErrNo(); } /* -------------------------------------------------------------------------------------------- * Retrieve the message of the last received error code. */ SQMOD_NODISCARD const SQChar * GetErrStr() const { return SQMOD_GET_VALID(*this)->ErrStr(); } /* -------------------------------------------------------------------------------------------- * Return the last error message associated with this database connection. */ SQMOD_NODISCARD const SQChar * GetErrMsg() const { return SQMOD_GET_VALID(*this)->ErrMsg(); } /* -------------------------------------------------------------------------------------------- * Retrieve the amount of requested columns. */ SQMOD_NODISCARD int32_t GetColumns() const { return SQMOD_GET_VALID(*this)->mColumns; } /* -------------------------------------------------------------------------------------------- * Retrieve the amount of specified parameters. */ SQMOD_NODISCARD int32_t GetParameters() const { return SQMOD_GET_VALID(*this)->mParameters; } /* -------------------------------------------------------------------------------------------- * Retrieve the query string used to create this statement. */ SQMOD_NODISCARD const String & GetQuery() const { return SQMOD_GET_VALID(*this)->mQuery; } /* -------------------------------------------------------------------------------------------- * See if the last step retrieved a valid row. */ SQMOD_NODISCARD bool GetGood() const { return SQMOD_GET_CREATED(*this)->mGood; } /* -------------------------------------------------------------------------------------------- * See if there are any steps left. */ SQMOD_NODISCARD bool GetDone() const { return SQMOD_GET_CREATED(*this)->mDone; } /* -------------------------------------------------------------------------------------------- * Check whether a specific parameter index is within range. */ SQMOD_NODISCARD bool CheckParameter(int32_t idx) const { return SQMOD_GET_VALID(*this)->CheckParameter(idx); } /* -------------------------------------------------------------------------------------------- * Retrieve the parameter index associated with the specified name. */ SQMOD_NODISCARD int32_t 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. */ SQMOD_NODISCARD const SQChar * GetParameterName(int32_t idx) const { // Validate the specified index if (!idx) { STHROWF("Invalid parameter index (%d)", idx); } // Attempt to locate the name at the specified index const SQChar * 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. */ SQMOD_NODISCARD bool CheckColumn(int32_t idx) const { return SQMOD_GET_VALID(*this)->CheckColumn(idx); } /* -------------------------------------------------------------------------------------------- * Retrieve the amount of columns available in the current row. */ SQMOD_NODISCARD int32_t GetDataCount() const { return sqlite3_data_count(SQMOD_GET_VALID(*this)->mPtr); } /* -------------------------------------------------------------------------------------------- * Check whether the specified column is null. */ SQMOD_NODISCARD bool IsColumnNull(int32_t idx) const { return (sqlite3_column_type(SQMOD_GET_VALID(*this)->mPtr, idx) == SQLITE_NULL); } /* -------------------------------------------------------------------------------------------- * Retrieve the column index associated with the specified name. */ SQMOD_NODISCARD int32_t GetColumnIndex(StackStrF & name) const { return SQMOD_GET_VALID(*this)->GetColumnIndex(name.mPtr, name.mLen); } /* -------------------------------------------------------------------------------------------- * Retrieve the column name associated with the specified index. */ SQMOD_NODISCARD const SQChar * GetColumnName(int32_t 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. */ SQMOD_NODISCARD const SQChar * GetColumnOriginName(int32_t idx) const // NOLINT(readability-convert-member-functions-to-static) { #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. */ SQMOD_NODISCARD int32_t GetColumnType(int32_t 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. */ SQMOD_NODISCARD int32_t GetColumnBytes(int32_t idx) const { return sqlite3_column_bytes(SQMOD_GET_VALID(*this)->mPtr, idx); } /* -------------------------------------------------------------------------------------------- * Reset the statement back to its initial position to be stepped again. */ SQLiteStatement & Reset(); /* -------------------------------------------------------------------------------------------- * Clear any values binded to this statement. */ SQLiteStatement & Clear(); /* -------------------------------------------------------------------------------------------- * Execute this statement and don't expect any rows to be returned. */ int32_t Exec(); /* -------------------------------------------------------------------------------------------- * Step the statement and expect a row to be returned. */ bool Step(); /* -------------------------------------------------------------------------------------------- * Retrieve the parameter with the specified name or index. */ SQMOD_NODISCARD Object GetParameter(const Object & param) const { return Object(new SQLiteParameter(m_Handle, param)); } /* -------------------------------------------------------------------------------------------- * Attempt to bind a dynamic value at the specified parameter index. */ SQLiteStatement & SetValue(const Object & param, const Object & value) { SQLiteParameter(SQMOD_GET_CREATED(*this), param).SetValue(value); // Allow chaining of operations return *this; } /* -------------------------------------------------------------------------------------------- * Attempt to bind a boolean value at the specified parameter index. */ SQLiteStatement & SetBool(const Object & param, bool value) { SQLiteParameter(SQMOD_GET_CREATED(*this), param).SetBool(value); // Allow chaining of operations return *this; } /* -------------------------------------------------------------------------------------------- * Attempt to bind a character value at the specified parameter index. */ SQLiteStatement & SetChar(const Object & param, SQInteger value) { SQLiteParameter(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. */ SQLiteStatement & SetInteger(const Object & param, SQInteger value) { SQLiteParameter(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. */ SQLiteStatement & SetInt8(const Object & param, SQInteger value) { SQLiteParameter(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. */ SQLiteStatement & SetUint8(const Object & param, SQInteger value) { SQLiteParameter(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. */ SQLiteStatement & SetInt16(const Object & param, SQInteger value) { SQLiteParameter(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. */ SQLiteStatement & SetUint16(const Object & param, SQInteger value) { SQLiteParameter(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. */ SQLiteStatement & SetInt32(const Object & param, SQInteger value) { SQLiteParameter(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. */ SQLiteStatement & SetUint32(const Object & param, SQInteger value) { SQLiteParameter(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. */ SQLiteStatement & SetInt64(const Object & param, SQInteger value) { SQLiteParameter(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. */ SQLiteStatement & SetUint64(const Object & param, SQInteger value) { SQLiteParameter(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. */ SQLiteStatement & SetFloat(const Object & param, SQFloat value) { SQLiteParameter(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. */ SQLiteStatement & SetFloat32(const Object & param, SQFloat value) { SQLiteParameter(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. */ SQLiteStatement & SetFloat64(const Object & param, SQFloat value) { SQLiteParameter(SQMOD_GET_CREATED(*this), param).SetFloat64(value); // Allow chaining of operations return *this; } /* -------------------------------------------------------------------------------------------- * Attempt to bind a string value at the specified parameter index. */ SQLiteStatement & SetString(const Object & param, StackStrF & value) { SQLiteParameter(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. */ SQLiteStatement & SetZeroBlob(const Object & param, SQInteger size) { SQLiteParameter(SQMOD_GET_CREATED(*this), param).SetZeroBlob(size); // Allow chaining of operations return *this; } /* -------------------------------------------------------------------------------------------- * Attempt to bind a blob value at the specified parameter index. */ SQLiteStatement & SetBlob(const Object & param, const Object & value) { SQLiteParameter(SQMOD_GET_CREATED(*this), param).SetBlob(value); // Allow chaining of operations return *this; } /* -------------------------------------------------------------------------------------------- * Attempt to bind a buffer value at the specified parameter index. */ SQLiteStatement & SetData(const Object & param, const Object & value) { SQLiteParameter(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. */ SQLiteStatement & SetDate(const Object & param, const Object & value) { SQLiteParameter(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. */ SQLiteStatement & SetDateEx(const Object & param, SQInteger year, SQInteger month, SQInteger day) { SQLiteParameter(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. */ SQLiteStatement & SetTime(const Object & param, const Object & value) { SQLiteParameter(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. */ SQLiteStatement & SetTimeEx(const Object & param, SQInteger hour, SQInteger minute, SQInteger second) { SQLiteParameter(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. */ SQLiteStatement & SetDatetime(const Object & param, const Object & value) { SQLiteParameter(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. */ SQLiteStatement & SetDatetimeEx(const Object & param, SQInteger year, SQInteger month, SQInteger day, SQInteger hour, SQInteger minute, SQInteger second) { SQLiteParameter(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. */ SQLiteStatement & SetNow(const Object & param) { SQLiteParameter(SQMOD_GET_CREATED(*this), param).SetNow(); // Allow chaining of operations return *this; } /* -------------------------------------------------------------------------------------------- * Attempt to bind a null value at the specified parameter index. */ SQLiteStatement & SetNull(const Object & param) { SQLiteParameter(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. */ SQLiteStatement & SetArray(int32_t idx, const Array & arr); /* -------------------------------------------------------------------------------------------- * Attempt to bind the values from an associative container. */ SQLiteStatement & SetTable(const Table & tbl); /* -------------------------------------------------------------------------------------------- * Retrieve the column with the specified name or index. */ SQMOD_NODISCARD Object GetColumn(const Object & column) const { return Object(new SQLiteColumn(m_Handle, column)); } /* -------------------------------------------------------------------------------------------- * Retrieve the value inside the referenced column as a dynamic type. */ SQMOD_NODISCARD Object GetValue(const Object & column) const { return SQLiteColumn(SQMOD_GET_CREATED(*this), column).GetValue(); } /* -------------------------------------------------------------------------------------------- * Retrieve the value inside the referenced column as a numeric type. */ SQMOD_NODISCARD Object GetNumber(const Object & column) const { return SQLiteColumn(SQMOD_GET_CREATED(*this), column).GetNumber(); } /* -------------------------------------------------------------------------------------------- * Retrieve the value inside the referenced column as a native script integer. */ SQMOD_NODISCARD SQInteger GetInteger(const Object & column) const { return SQLiteColumn(SQMOD_GET_CREATED(*this), column).GetInteger(); } /* -------------------------------------------------------------------------------------------- * Retrieve the value inside the referenced column as a native script floating point. */ SQMOD_NODISCARD SQFloat GetFloat(const Object & column) const { return SQLiteColumn(SQMOD_GET_CREATED(*this), column).GetFloat(); } /* -------------------------------------------------------------------------------------------- * Retrieve the value inside the referenced column as a long integer. */ SQMOD_NODISCARD Object GetLong(const Object & column) const { return SQLiteColumn(SQMOD_GET_CREATED(*this), column).GetLong(); } /* -------------------------------------------------------------------------------------------- * Retrieve the value inside the referenced column as a string. */ SQMOD_NODISCARD Object GetString(const Object & column) const { return SQLiteColumn(SQMOD_GET_CREATED(*this), column).GetString(); } /* -------------------------------------------------------------------------------------------- * Retrieve the value inside the referenced column as a boolean. */ SQMOD_NODISCARD bool GetBoolean(const Object & column) const { return SQLiteColumn(SQMOD_GET_CREATED(*this), column).GetBoolean(); } /* -------------------------------------------------------------------------------------------- * Retrieve the value inside the referenced column as a character. */ SQMOD_NODISCARD SQChar GetChar(const Object & column) const { return SQLiteColumn(SQMOD_GET_CREATED(*this), column).GetChar(); } /* -------------------------------------------------------------------------------------------- * Retrieve the value inside the referenced column as a memory buffer. */ SQMOD_NODISCARD Object GetBuffer(const Object & column) const { return SQLiteColumn(SQMOD_GET_CREATED(*this), column).GetBuffer(); } /* -------------------------------------------------------------------------------------------- * Retrieve the value inside the referenced column as a memory blob. */ SQMOD_NODISCARD Object GetBlob(const Object & column) const { return SQLiteColumn(SQMOD_GET_CREATED(*this), column).GetBlob(); } /* -------------------------------------------------------------------------------------------- * Retrieve the row as an array container. */ SQMOD_NODISCARD Array GetArray() const { return GetArray(0, SQMOD_GET_CREATED(*this)->mColumns); } /* -------------------------------------------------------------------------------------------- * Retrieve the row as an array container. */ SQMOD_NODISCARD Array GetArray(int32_t min) const { return GetArray(min, SQMOD_GET_CREATED(*this)->mColumns); } /* -------------------------------------------------------------------------------------------- * Retrieve the row as an array container. */ SQMOD_NODISCARD Array GetArray(int32_t min, int32_t max) const; /* -------------------------------------------------------------------------------------------- * Retrieve the row as an associative container. */ SQMOD_NODISCARD 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. */ SQMOD_NODISCARD Table GetTable(int32_t 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. */ SQMOD_NODISCARD Table GetTable(int32_t min, int32_t max) const; }; /* ------------------------------------------------------------------------------------------------ * Implements the RAII pattern for database transactions. */ class SQLiteTransaction { public: /* -------------------------------------------------------------------------------------------- * Construct by taking the handle from a connection. */ explicit SQLiteTransaction(const SQLiteConnection & db); /* -------------------------------------------------------------------------------------------- * Construct using the direct connection handle. */ explicit SQLiteTransaction(ConnRef db); /* -------------------------------------------------------------------------------------------- * Copy constructor. (disabled) */ SQLiteTransaction(const SQLiteTransaction & o) = delete; /* -------------------------------------------------------------------------------------------- * Move constructor. (disabled) */ SQLiteTransaction(SQLiteTransaction && o) = delete; /* -------------------------------------------------------------------------------------------- * Destructor. */ ~SQLiteTransaction(); /* -------------------------------------------------------------------------------------------- * Copy assignment operator. (disabled) */ SQLiteTransaction & operator = (const SQLiteTransaction & o) = delete; /* -------------------------------------------------------------------------------------------- * Move assignment operator. (disabled) */ SQLiteTransaction & operator = (SQLiteTransaction && o) = delete; /* -------------------------------------------------------------------------------------------- * Used by the script engine to convert an instance of this type to a string. */ SQMOD_NODISCARD const String & ToString() const { return m_Handle ? m_Handle->mName : NullString(); } /* -------------------------------------------------------------------------------------------- * See whether the managed handle is valid. */ SQMOD_NODISCARD 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. */ SQMOD_NODISCARD bool Commited() const { return m_Committed; } private: // -------------------------------------------------------------------------------------------- ConnRef m_Handle{}; // The database connection handle where the transaction began. bool m_Committed{false}; // Whether changes were successfully committed to the database. }; } // Namespace:: SqMod