michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- michael@0: * vim: sw=2 ts=2 sts=2 expandtab michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef mozilla_storage_StorageBaseStatementInternal_h_ michael@0: #define mozilla_storage_StorageBaseStatementInternal_h_ michael@0: michael@0: #include "nsISupports.h" michael@0: #include "nsCOMPtr.h" michael@0: #include "nsAutoPtr.h" michael@0: michael@0: struct sqlite3; michael@0: struct sqlite3_stmt; michael@0: class mozIStorageError; michael@0: class mozIStorageBindingParamsArray; michael@0: class mozIStorageBindingParams; michael@0: class mozIStorageStatementCallback; michael@0: class mozIStoragePendingStatement; michael@0: michael@0: namespace mozilla { michael@0: namespace storage { michael@0: michael@0: #define STORAGEBASESTATEMENTINTERNAL_IID \ michael@0: {0xd18856c9, 0xbf07, 0x4ae2, {0x94, 0x5b, 0x1a, 0xdd, 0x49, 0x19, 0x55, 0x2a}} michael@0: michael@0: class Connection; michael@0: class StatementData; michael@0: michael@0: class AsyncStatementFinalizer; michael@0: michael@0: /** michael@0: * Implementation-only interface and shared logix mix-in corresponding to michael@0: * mozIStorageBaseStatement. Both Statement and AsyncStatement inherit from michael@0: * this. The interface aspect makes them look the same to implementation innards michael@0: * that aren't publicly accessible. The mix-in avoids code duplication in michael@0: * common implementations of mozIStorageBaseStatement, albeit with some minor michael@0: * performance/space overhead because we have to use defines to officially michael@0: * implement the methods on Statement/AsyncStatement (and proxy to this base michael@0: * class.) michael@0: */ michael@0: class StorageBaseStatementInternal : public nsISupports michael@0: { michael@0: public: michael@0: NS_DECLARE_STATIC_IID_ACCESSOR(STORAGEBASESTATEMENTINTERNAL_IID) michael@0: michael@0: /** michael@0: * @return the connection that this statement belongs to. michael@0: */ michael@0: Connection *getOwner() michael@0: { michael@0: return mDBConnection; michael@0: } michael@0: michael@0: /** michael@0: * Return the asynchronous statement, creating it if required. michael@0: * michael@0: * This is for use by the asynchronous execution code for StatementData michael@0: * created by AsyncStatements. Statement internally uses this method to michael@0: * prepopulate StatementData with the sqlite3_stmt. michael@0: * michael@0: * @param[out] stmt michael@0: * The sqlite3_stmt for asynchronous use. michael@0: * @return The SQLite result code for creating the statement if created, michael@0: * SQLITE_OK if creation was not required. michael@0: */ michael@0: virtual int getAsyncStatement(sqlite3_stmt **_stmt) = 0; michael@0: michael@0: /** michael@0: * Obtains the StatementData needed for asynchronous execution. michael@0: * michael@0: * This is for use by Connection to retrieve StatementData from statements michael@0: * when executeAsync is invoked. michael@0: * michael@0: * @param[out] _data michael@0: * A reference to a StatementData object that will be populated michael@0: * upon successful execution of this method. michael@0: * @return NS_OK if we were able to assemble the data, failure otherwise. michael@0: */ michael@0: virtual nsresult getAsynchronousStatementData(StatementData &_data) = 0; michael@0: michael@0: /** michael@0: * Construct a new BindingParams to be owned by the provided binding params michael@0: * array. This method exists so that BindingParamsArray does not need michael@0: * factory logic to determine what type of BindingParams to instantiate. michael@0: * michael@0: * @param aOwner michael@0: * The binding params array to own the newly created binding params. michael@0: * @return The new mozIStorageBindingParams instance appropriate to the michael@0: * underlying statement type. michael@0: */ michael@0: virtual already_AddRefed newBindingParams( michael@0: mozIStorageBindingParamsArray *aOwner michael@0: ) = 0; michael@0: michael@0: protected: // mix-in bits are protected michael@0: StorageBaseStatementInternal(); michael@0: michael@0: nsRefPtr mDBConnection; michael@0: sqlite3 *mNativeConnection; michael@0: michael@0: /** michael@0: * Our asynchronous statement. michael@0: * michael@0: * For Statement this is populated by the first invocation to michael@0: * getAsyncStatement. michael@0: * michael@0: * For AsyncStatement, this is null at creation time and initialized by the michael@0: * async thread when it calls getAsyncStatement the first time the statement michael@0: * is executed. (Or in the event of badly formed SQL, every time.) michael@0: */ michael@0: sqlite3_stmt *mAsyncStatement; michael@0: michael@0: /** michael@0: * Initiate asynchronous finalization by dispatching an event to the michael@0: * asynchronous thread to finalize mAsyncStatement. This acquires a reference michael@0: * to this statement and proxies it back to the connection's owning thread michael@0: * for release purposes. michael@0: * michael@0: * In the event the asynchronous thread is already gone or we otherwise fail michael@0: * to dispatch an event to it we failover to invoking internalAsyncFinalize michael@0: * directly. (That's what the asynchronous finalizer would have called.) michael@0: * michael@0: * @note You must not call this method from your destructor because its michael@0: * operation assumes we are still alive. Call internalAsyncFinalize michael@0: * directly in that case. michael@0: */ michael@0: void asyncFinalize(); michael@0: michael@0: /** michael@0: * Cleanup the async sqlite3_stmt stored in mAsyncStatement if it exists by michael@0: * attempting to dispatch to the asynchronous thread if available, finalizing michael@0: * on this thread if it is not. michael@0: * michael@0: * @note Call this from your destructor, call asyncFinalize otherwise. michael@0: */ michael@0: void destructorAsyncFinalize(); michael@0: michael@0: NS_IMETHOD NewBindingParamsArray(mozIStorageBindingParamsArray **_array); michael@0: NS_IMETHOD ExecuteAsync(mozIStorageStatementCallback *aCallback, michael@0: mozIStoragePendingStatement **_stmt); michael@0: NS_IMETHOD EscapeStringForLIKE(const nsAString &aValue, michael@0: const char16_t aEscapeChar, michael@0: nsAString &_escapedString); michael@0: michael@0: // Needs access to internalAsyncFinalize michael@0: friend class AsyncStatementFinalizer; michael@0: }; michael@0: michael@0: NS_DEFINE_STATIC_IID_ACCESSOR(StorageBaseStatementInternal, michael@0: STORAGEBASESTATEMENTINTERNAL_IID) michael@0: michael@0: #define NS_DECL_STORAGEBASESTATEMENTINTERNAL \ michael@0: virtual Connection *getOwner(); \ michael@0: virtual int getAsyncStatement(sqlite3_stmt **_stmt); \ michael@0: virtual nsresult getAsynchronousStatementData(StatementData &_data); \ michael@0: virtual already_AddRefed newBindingParams( \ michael@0: mozIStorageBindingParamsArray *aOwner); michael@0: michael@0: /** michael@0: * Helper macro to implement the proxying implementations. Because we are michael@0: * implementing methods that are part of mozIStorageBaseStatement and the michael@0: * implementation classes already use NS_DECL_MOZISTORAGEBASESTATEMENT we don't michael@0: * need to provide declaration support. michael@0: */ michael@0: #define MIX_IMPL(_class, _optionalGuard, _method, _declArgs, _invokeArgs) \ michael@0: NS_IMETHODIMP _class::_method _declArgs \ michael@0: { \ michael@0: _optionalGuard \ michael@0: return StorageBaseStatementInternal::_method _invokeArgs; \ michael@0: } michael@0: michael@0: michael@0: /** michael@0: * Define proxying implementation for the given _class. If a state invariant michael@0: * needs to be checked and an early return possibly performed, pass the clause michael@0: * to use as _optionalGuard. michael@0: */ michael@0: #define MIXIN_IMPL_STORAGEBASESTATEMENTINTERNAL(_class, _optionalGuard) \ michael@0: MIX_IMPL(_class, _optionalGuard, \ michael@0: NewBindingParamsArray, \ michael@0: (mozIStorageBindingParamsArray **_array), \ michael@0: (_array)) \ michael@0: MIX_IMPL(_class, _optionalGuard, \ michael@0: ExecuteAsync, \ michael@0: (mozIStorageStatementCallback *aCallback, \ michael@0: mozIStoragePendingStatement **_stmt), \ michael@0: (aCallback, _stmt)) \ michael@0: MIX_IMPL(_class, _optionalGuard, \ michael@0: EscapeStringForLIKE, \ michael@0: (const nsAString &aValue, const char16_t aEscapeChar, \ michael@0: nsAString &_escapedString), \ michael@0: (aValue, aEscapeChar, _escapedString)) michael@0: michael@0: /** michael@0: * Name-building helper for BIND_GEN_IMPL. michael@0: */ michael@0: #define BIND_NAME_CONCAT(_nameBit, _concatBit) \ michael@0: Bind##_nameBit##_concatBit michael@0: michael@0: /** michael@0: * We have type-specific convenience methods for C++ implementations in michael@0: * 3 different forms; 2 by index, 1 by name. The following macro allows michael@0: * us to avoid having to define repetitive things by hand. michael@0: * michael@0: * Because of limitations of macros and our desire to avoid requiring special michael@0: * permutations for the null and blob cases (whose argument count varies), michael@0: * we require that the argument declarations and corresponding invocation michael@0: * usages are passed in. michael@0: * michael@0: * @param _class michael@0: * The class name. michael@0: * @param _guard michael@0: * The guard clause to inject. michael@0: * @param _declName michael@0: * The argument list (with parens) for the ByName variants. michael@0: * @param _declIndex michael@0: * The argument list (with parens) for the index variants. michael@0: * @param _invArgs michael@0: * The invocation argumment list. michael@0: */ michael@0: #define BIND_GEN_IMPL(_class, _guard, _name, _declName, _declIndex, _invArgs) \ michael@0: NS_IMETHODIMP _class::BIND_NAME_CONCAT(_name, ByName) _declName \ michael@0: { \ michael@0: _guard \ michael@0: mozIStorageBindingParams *params = getParams(); \ michael@0: NS_ENSURE_TRUE(params, NS_ERROR_OUT_OF_MEMORY); \ michael@0: return params->BIND_NAME_CONCAT(_name, ByName) _invArgs; \ michael@0: } \ michael@0: NS_IMETHODIMP _class::BIND_NAME_CONCAT(_name, ByIndex) _declIndex \ michael@0: { \ michael@0: _guard \ michael@0: mozIStorageBindingParams *params = getParams(); \ michael@0: NS_ENSURE_TRUE(params, NS_ERROR_OUT_OF_MEMORY); \ michael@0: return params->BIND_NAME_CONCAT(_name, ByIndex) _invArgs; \ michael@0: } \ michael@0: NS_IMETHODIMP _class::BIND_NAME_CONCAT(_name, Parameter) _declIndex \ michael@0: { \ michael@0: _guard \ michael@0: mozIStorageBindingParams *params = getParams(); \ michael@0: NS_ENSURE_TRUE(params, NS_ERROR_OUT_OF_MEMORY); \ michael@0: return params->BIND_NAME_CONCAT(_name, ByIndex) _invArgs; \ michael@0: } michael@0: michael@0: /** michael@0: * Implement BindByName/BindByIndex for the given class. michael@0: * michael@0: * @param _class The class name. michael@0: * @param _optionalGuard The guard clause to inject. michael@0: */ michael@0: #define BIND_BASE_IMPLS(_class, _optionalGuard) \ michael@0: NS_IMETHODIMP _class::BindByName(const nsACString &aName, \ michael@0: nsIVariant *aValue) \ michael@0: { \ michael@0: _optionalGuard \ michael@0: mozIStorageBindingParams *params = getParams(); \ michael@0: NS_ENSURE_TRUE(params, NS_ERROR_OUT_OF_MEMORY); \ michael@0: return params->BindByName(aName, aValue); \ michael@0: } \ michael@0: NS_IMETHODIMP _class::BindByIndex(uint32_t aIndex, \ michael@0: nsIVariant *aValue) \ michael@0: { \ michael@0: _optionalGuard \ michael@0: mozIStorageBindingParams *params = getParams(); \ michael@0: NS_ENSURE_TRUE(params, NS_ERROR_OUT_OF_MEMORY); \ michael@0: return params->BindByIndex(aIndex, aValue); \ michael@0: } michael@0: michael@0: /** michael@0: * Define the various Bind*Parameter, Bind*ByIndex, Bind*ByName stubs that just michael@0: * end up proxying to the params object. michael@0: */ michael@0: #define BOILERPLATE_BIND_PROXIES(_class, _optionalGuard) \ michael@0: BIND_BASE_IMPLS(_class, _optionalGuard) \ michael@0: BIND_GEN_IMPL(_class, _optionalGuard, \ michael@0: UTF8String, \ michael@0: (const nsACString &aWhere, \ michael@0: const nsACString &aValue), \ michael@0: (uint32_t aWhere, \ michael@0: const nsACString &aValue), \ michael@0: (aWhere, aValue)) \ michael@0: BIND_GEN_IMPL(_class, _optionalGuard, \ michael@0: String, \ michael@0: (const nsACString &aWhere, \ michael@0: const nsAString &aValue), \ michael@0: (uint32_t aWhere, \ michael@0: const nsAString &aValue), \ michael@0: (aWhere, aValue)) \ michael@0: BIND_GEN_IMPL(_class, _optionalGuard, \ michael@0: Double, \ michael@0: (const nsACString &aWhere, \ michael@0: double aValue), \ michael@0: (uint32_t aWhere, \ michael@0: double aValue), \ michael@0: (aWhere, aValue)) \ michael@0: BIND_GEN_IMPL(_class, _optionalGuard, \ michael@0: Int32, \ michael@0: (const nsACString &aWhere, \ michael@0: int32_t aValue), \ michael@0: (uint32_t aWhere, \ michael@0: int32_t aValue), \ michael@0: (aWhere, aValue)) \ michael@0: BIND_GEN_IMPL(_class, _optionalGuard, \ michael@0: Int64, \ michael@0: (const nsACString &aWhere, \ michael@0: int64_t aValue), \ michael@0: (uint32_t aWhere, \ michael@0: int64_t aValue), \ michael@0: (aWhere, aValue)) \ michael@0: BIND_GEN_IMPL(_class, _optionalGuard, \ michael@0: Null, \ michael@0: (const nsACString &aWhere), \ michael@0: (uint32_t aWhere), \ michael@0: (aWhere)) \ michael@0: BIND_GEN_IMPL(_class, _optionalGuard, \ michael@0: Blob, \ michael@0: (const nsACString &aWhere, \ michael@0: const uint8_t *aValue, \ michael@0: uint32_t aValueSize), \ michael@0: (uint32_t aWhere, \ michael@0: const uint8_t *aValue, \ michael@0: uint32_t aValueSize), \ michael@0: (aWhere, aValue, aValueSize)) \ michael@0: BIND_GEN_IMPL(_class, _optionalGuard, \ michael@0: AdoptedBlob, \ michael@0: (const nsACString &aWhere, \ michael@0: uint8_t *aValue, \ michael@0: uint32_t aValueSize), \ michael@0: (uint32_t aWhere, \ michael@0: uint8_t *aValue, \ michael@0: uint32_t aValueSize), \ michael@0: (aWhere, aValue, aValueSize)) michael@0: michael@0: michael@0: michael@0: } // storage michael@0: } // mozilla michael@0: michael@0: #endif // mozilla_storage_StorageBaseStatementInternal_h_