#ifndef _LIBRARY_SQLITE_SHARED_HPP_ #define _LIBRARY_SQLITE_SHARED_HPP_ // ------------------------------------------------------------------------------------------------ #include "Common.hpp" #include "Library/LongInt.hpp" // ------------------------------------------------------------------------------------------------ #include // ------------------------------------------------------------------------------------------------ #include // ------------------------------------------------------------------------------------------------ namespace SqMod { namespace SQLite { // ------------------------------------------------------------------------------------------------ class Connection; class Statement; class Result; /* ------------------------------------------------------------------------------------------------ * A managed handle to a shared SQLite connection. */ class ConnectionHandle { // -------------------------------------------------------------------------------------------- friend class Connection; protected: /* -------------------------------------------------------------------------------------------- * Helper class responsible for managing the handle to an SQLite connection resource. */ struct Handle { friend class ConnectionHandle; /* ---------------------------------------------------------------------------------------- * The type of container used to queue queries for group execution. */ typedef std::queue< String > QueryList; /* ---------------------------------------------------------------------------------------- * The amount of references to this handle instance. */ mutable SQUint32 Ref; /* ---------------------------------------------------------------------------------------- * The handle to the managed SQLite connection resource. */ sqlite3* Ptr; /* ---------------------------------------------------------------------------------------- * The flags used to create the SQLite connection handle. */ SQInt32 Flags; /* ---------------------------------------------------------------------------------------- * The specified path to be used as the database file. */ String Path; /* ---------------------------------------------------------------------------------------- * The specified virtual file system. */ String VFS; /* ---------------------------------------------------------------------------------------- * The last status code of this connection handle. */ SQInt32 Status; /* ---------------------------------------------------------------------------------------- * A queue of queries to be executed in groups in order to reduce lag. */ QueryList Queue; /* ---------------------------------------------------------------------------------------- * The global tag associated with this resource. */ SqTag Tag; /* ---------------------------------------------------------------------------------------- * The global data associated with this resource. */ SqObj Data; /* ---------------------------------------------------------------------------------------- * Whether the database exists in memory and not disk. */ bool Memory; /* ---------------------------------------------------------------------------------------- * Whether tracing was activated on the database. */ bool Trace; /* ---------------------------------------------------------------------------------------- * Whether profiling was activated on the database. */ bool Profile; private: /* ---------------------------------------------------------------------------------------- * Handle constructor. */ Handle(const String & path, SQInt32 flags, const String & vfs) : Ref(1), Ptr(NULL), Flags(flags), Path(path), VFS(vfs) , Status(SQLITE_OK), Queue(), Tag(), Data() , Memory(path == ":memory:"), Trace(false), Profile(false) { /* ... */ } /* ---------------------------------------------------------------------------------------- * Copy constructor (disabled) */ Handle(const Handle &) = delete; /* ---------------------------------------------------------------------------------------- * Move constructor (disabled) */ Handle(Handle &&) = delete; /* ---------------------------------------------------------------------------------------- * Handle destructor. */ ~Handle() { // If a valid handle exists then attempt to release it if (Ptr != NULL && (Status = sqlite3_close(Ptr)) != SQLITE_OK) { LogErr("Unable to because : %s", sqlite3_errmsg(Ptr)); } } /* ---------------------------------------------------------------------------------------- * Copy assignment operator (disabled) */ Handle & operator = (const Handle &) = delete; /* ---------------------------------------------------------------------------------------- * Move assignment operator (disabled) */ Handle & operator = (Handle &&) = delete; }; /* -------------------------------------------------------------------------------------------- * Acquire a strong reference to the resource handle. */ void Grab() { // If a valid handle exists then grab a reference to it if (Hnd != nullptr) { ++(Hnd->Ref); } } /* -------------------------------------------------------------------------------------------- * Release the handle reference and therefore the handle it self if no more references exist. */ void Drop() { // If a valid handle exists then delete it if this is the last released reference if (Hnd != nullptr && --(Hnd->Ref) == 0) { delete Hnd; } // Explicitly make sure the handle is null Hnd = nullptr; } public: /* -------------------------------------------------------------------------------------------- * The handle instance that manages the SQLite resource. */ Handle * Hnd; /* -------------------------------------------------------------------------------------------- * Default constructor (invalid). */ ConnectionHandle(); /* -------------------------------------------------------------------------------------------- * Open a connection to a database using the specified path, flags and vfs. */ ConnectionHandle(const SQChar * path, SQInt32 flags, const SQChar * vfs); /* -------------------------------------------------------------------------------------------- * Copy constructor. */ ConnectionHandle(const ConnectionHandle & o); /* -------------------------------------------------------------------------------------------- * Move constructor. */ ConnectionHandle(ConnectionHandle && o); /* -------------------------------------------------------------------------------------------- * Destructor. */ ~ConnectionHandle(); /* -------------------------------------------------------------------------------------------- * Copy assignment operator. */ ConnectionHandle & operator = (const ConnectionHandle & o); /* -------------------------------------------------------------------------------------------- * Move assignment operator. */ ConnectionHandle & operator = (ConnectionHandle && o); /* -------------------------------------------------------------------------------------------- * Implicit conversion to boolean. */ operator bool () const { return (Hnd != nullptr) && (Hnd->Ptr != NULL); } /* -------------------------------------------------------------------------------------------- * Negation operator. */ operator ! () const { return (Hnd == nullptr) || (Hnd->Ptr == NULL); } /* -------------------------------------------------------------------------------------------- * Implicit conversion to raw SQLite connection handle. */ operator sqlite3 * () const { return (Hnd != nullptr) ? Hnd->Ptr : NULL; } /* -------------------------------------------------------------------------------------------- * Implicit conversion to integer status code. */ operator SQInt32 () const { return (Hnd != nullptr) ? Hnd->Status : 0; } /* -------------------------------------------------------------------------------------------- * Member of pointer operator. */ Handle * operator -> () const { return Hnd; } /* -------------------------------------------------------------------------------------------- * Indirection operator. */ Handle & operator * () const { return *Hnd; } /* -------------------------------------------------------------------------------------------- * Equality operator. */ bool operator == (const ConnectionHandle & o) const { return (Hnd == o.Hnd); } /* -------------------------------------------------------------------------------------------- * Inequality operator. */ bool operator != (const ConnectionHandle & o) const { return (Hnd != o.Hnd); } /* -------------------------------------------------------------------------------------------- * Reset this handle and release the internal reference. */ void Release() { Drop(); } /* -------------------------------------------------------------------------------------------- * Retrieve the number of active references to this handle. */ SQUint32 Count() const { return (Hnd != nullptr) ? Hnd->Ref : 0; } /* -------------------------------------------------------------------------------------------- * Retrieve the error message associated with the value in status. */ const SQChar * ErrStr() const { return sqlite3_errstr(Hnd->Status); } /* -------------------------------------------------------------------------------------------- * Retrieve the error message associated with the connection. */ const SQChar * ErrMsg() const { return sqlite3_errmsg(Hnd->Ptr); } /* -------------------------------------------------------------------------------------------- * Retrieve the error code associated with the connection. */ SQInt32 ErrNo() const { return sqlite3_errcode(Hnd->Ptr); } }; /* ------------------------------------------------------------------------------------------------ * RAII encapsulation of a SQLite Transaction. */ class Transaction { public: /* -------------------------------------------------------------------------------------------- * Default constructor. */ Transaction(const Connection & db); /* -------------------------------------------------------------------------------------------- * Copy constructor (disabled). */ Transaction(const Transaction & o) = delete; /* -------------------------------------------------------------------------------------------- * Move constructor (disabled). */ Transaction(Transaction && o) = delete; /* -------------------------------------------------------------------------------------------- * Destructor. */ ~Transaction(); /* -------------------------------------------------------------------------------------------- * Copy assignment operator (disabled). */ Transaction & operator = (const Transaction & o) = delete; /* -------------------------------------------------------------------------------------------- * Move assignment operator (disabled). */ Transaction & operator = (Transaction && o) = delete; /* -------------------------------------------------------------------------------------------- * Commit the transaction. */ void Commit(); /* -------------------------------------------------------------------------------------------- * See whether the transaction was committed. */ bool Commited() const { return m_Commited; } protected: // -------------------------------------------------------------------------------------------- private: /* -------------------------------------------------------------------------------------------- * The SQLite connection associated with this transaction. */ ConnectionHandle m_Connection; /* -------------------------------------------------------------------------------------------- * Whether the changes were committed. */ bool m_Commited; }; /* ------------------------------------------------------------------------------------------------ * Places a "soft" limit on the amount of heap memory that may be allocated by SQLite. */ void SetSoftHeapLimit(SQInt32 limit); /* ------------------------------------------------------------------------------------------------ * Attempts to free N bytes of heap memory by deallocating non-essential memory allocations * held by the database library. */ SQInt32 ReleaseMemory(SQInt32 bytes); /* ------------------------------------------------------------------------------------------------ * Returns the number of bytes of memory currently outstanding (malloced but not freed). */ SLongInt GetMemoryUsage(); /* ------------------------------------------------------------------------------------------------ * Returns the maximum value of used bytes since the high-water mark was last reset. */ SLongInt GetMemoryHighwaterMark(bool reset); } // Namespace:: SQLite } // Namespace:: SqMod #endif // _LIBRARY_SQLITE_SHARED_HPP_