#ifndef _SQSQLITE_STATEMENT_HPP #define _SQSQLITE_STATEMENT_HPP // ------------------------------------------------------------------------------------------------ #include "Handle/Statement.hpp" #include "Parameter.hpp" #include "Column.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); // 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); // 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); // 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); // 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 #endif // _SQSQLITE_STATEMENT_HPP