1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/storage/src/StorageBaseStatementInternal.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,340 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- 1.5 + * vim: sw=2 ts=2 sts=2 expandtab 1.6 + * This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#ifndef mozilla_storage_StorageBaseStatementInternal_h_ 1.11 +#define mozilla_storage_StorageBaseStatementInternal_h_ 1.12 + 1.13 +#include "nsISupports.h" 1.14 +#include "nsCOMPtr.h" 1.15 +#include "nsAutoPtr.h" 1.16 + 1.17 +struct sqlite3; 1.18 +struct sqlite3_stmt; 1.19 +class mozIStorageError; 1.20 +class mozIStorageBindingParamsArray; 1.21 +class mozIStorageBindingParams; 1.22 +class mozIStorageStatementCallback; 1.23 +class mozIStoragePendingStatement; 1.24 + 1.25 +namespace mozilla { 1.26 +namespace storage { 1.27 + 1.28 +#define STORAGEBASESTATEMENTINTERNAL_IID \ 1.29 + {0xd18856c9, 0xbf07, 0x4ae2, {0x94, 0x5b, 0x1a, 0xdd, 0x49, 0x19, 0x55, 0x2a}} 1.30 + 1.31 +class Connection; 1.32 +class StatementData; 1.33 + 1.34 +class AsyncStatementFinalizer; 1.35 + 1.36 +/** 1.37 + * Implementation-only interface and shared logix mix-in corresponding to 1.38 + * mozIStorageBaseStatement. Both Statement and AsyncStatement inherit from 1.39 + * this. The interface aspect makes them look the same to implementation innards 1.40 + * that aren't publicly accessible. The mix-in avoids code duplication in 1.41 + * common implementations of mozIStorageBaseStatement, albeit with some minor 1.42 + * performance/space overhead because we have to use defines to officially 1.43 + * implement the methods on Statement/AsyncStatement (and proxy to this base 1.44 + * class.) 1.45 + */ 1.46 +class StorageBaseStatementInternal : public nsISupports 1.47 +{ 1.48 +public: 1.49 + NS_DECLARE_STATIC_IID_ACCESSOR(STORAGEBASESTATEMENTINTERNAL_IID) 1.50 + 1.51 + /** 1.52 + * @return the connection that this statement belongs to. 1.53 + */ 1.54 + Connection *getOwner() 1.55 + { 1.56 + return mDBConnection; 1.57 + } 1.58 + 1.59 + /** 1.60 + * Return the asynchronous statement, creating it if required. 1.61 + * 1.62 + * This is for use by the asynchronous execution code for StatementData 1.63 + * created by AsyncStatements. Statement internally uses this method to 1.64 + * prepopulate StatementData with the sqlite3_stmt. 1.65 + * 1.66 + * @param[out] stmt 1.67 + * The sqlite3_stmt for asynchronous use. 1.68 + * @return The SQLite result code for creating the statement if created, 1.69 + * SQLITE_OK if creation was not required. 1.70 + */ 1.71 + virtual int getAsyncStatement(sqlite3_stmt **_stmt) = 0; 1.72 + 1.73 + /** 1.74 + * Obtains the StatementData needed for asynchronous execution. 1.75 + * 1.76 + * This is for use by Connection to retrieve StatementData from statements 1.77 + * when executeAsync is invoked. 1.78 + * 1.79 + * @param[out] _data 1.80 + * A reference to a StatementData object that will be populated 1.81 + * upon successful execution of this method. 1.82 + * @return NS_OK if we were able to assemble the data, failure otherwise. 1.83 + */ 1.84 + virtual nsresult getAsynchronousStatementData(StatementData &_data) = 0; 1.85 + 1.86 + /** 1.87 + * Construct a new BindingParams to be owned by the provided binding params 1.88 + * array. This method exists so that BindingParamsArray does not need 1.89 + * factory logic to determine what type of BindingParams to instantiate. 1.90 + * 1.91 + * @param aOwner 1.92 + * The binding params array to own the newly created binding params. 1.93 + * @return The new mozIStorageBindingParams instance appropriate to the 1.94 + * underlying statement type. 1.95 + */ 1.96 + virtual already_AddRefed<mozIStorageBindingParams> newBindingParams( 1.97 + mozIStorageBindingParamsArray *aOwner 1.98 + ) = 0; 1.99 + 1.100 +protected: // mix-in bits are protected 1.101 + StorageBaseStatementInternal(); 1.102 + 1.103 + nsRefPtr<Connection> mDBConnection; 1.104 + sqlite3 *mNativeConnection; 1.105 + 1.106 + /** 1.107 + * Our asynchronous statement. 1.108 + * 1.109 + * For Statement this is populated by the first invocation to 1.110 + * getAsyncStatement. 1.111 + * 1.112 + * For AsyncStatement, this is null at creation time and initialized by the 1.113 + * async thread when it calls getAsyncStatement the first time the statement 1.114 + * is executed. (Or in the event of badly formed SQL, every time.) 1.115 + */ 1.116 + sqlite3_stmt *mAsyncStatement; 1.117 + 1.118 + /** 1.119 + * Initiate asynchronous finalization by dispatching an event to the 1.120 + * asynchronous thread to finalize mAsyncStatement. This acquires a reference 1.121 + * to this statement and proxies it back to the connection's owning thread 1.122 + * for release purposes. 1.123 + * 1.124 + * In the event the asynchronous thread is already gone or we otherwise fail 1.125 + * to dispatch an event to it we failover to invoking internalAsyncFinalize 1.126 + * directly. (That's what the asynchronous finalizer would have called.) 1.127 + * 1.128 + * @note You must not call this method from your destructor because its 1.129 + * operation assumes we are still alive. Call internalAsyncFinalize 1.130 + * directly in that case. 1.131 + */ 1.132 + void asyncFinalize(); 1.133 + 1.134 + /** 1.135 + * Cleanup the async sqlite3_stmt stored in mAsyncStatement if it exists by 1.136 + * attempting to dispatch to the asynchronous thread if available, finalizing 1.137 + * on this thread if it is not. 1.138 + * 1.139 + * @note Call this from your destructor, call asyncFinalize otherwise. 1.140 + */ 1.141 + void destructorAsyncFinalize(); 1.142 + 1.143 + NS_IMETHOD NewBindingParamsArray(mozIStorageBindingParamsArray **_array); 1.144 + NS_IMETHOD ExecuteAsync(mozIStorageStatementCallback *aCallback, 1.145 + mozIStoragePendingStatement **_stmt); 1.146 + NS_IMETHOD EscapeStringForLIKE(const nsAString &aValue, 1.147 + const char16_t aEscapeChar, 1.148 + nsAString &_escapedString); 1.149 + 1.150 + // Needs access to internalAsyncFinalize 1.151 + friend class AsyncStatementFinalizer; 1.152 +}; 1.153 + 1.154 +NS_DEFINE_STATIC_IID_ACCESSOR(StorageBaseStatementInternal, 1.155 + STORAGEBASESTATEMENTINTERNAL_IID) 1.156 + 1.157 +#define NS_DECL_STORAGEBASESTATEMENTINTERNAL \ 1.158 + virtual Connection *getOwner(); \ 1.159 + virtual int getAsyncStatement(sqlite3_stmt **_stmt); \ 1.160 + virtual nsresult getAsynchronousStatementData(StatementData &_data); \ 1.161 + virtual already_AddRefed<mozIStorageBindingParams> newBindingParams( \ 1.162 + mozIStorageBindingParamsArray *aOwner); 1.163 + 1.164 +/** 1.165 + * Helper macro to implement the proxying implementations. Because we are 1.166 + * implementing methods that are part of mozIStorageBaseStatement and the 1.167 + * implementation classes already use NS_DECL_MOZISTORAGEBASESTATEMENT we don't 1.168 + * need to provide declaration support. 1.169 + */ 1.170 +#define MIX_IMPL(_class, _optionalGuard, _method, _declArgs, _invokeArgs) \ 1.171 + NS_IMETHODIMP _class::_method _declArgs \ 1.172 + { \ 1.173 + _optionalGuard \ 1.174 + return StorageBaseStatementInternal::_method _invokeArgs; \ 1.175 + } 1.176 + 1.177 + 1.178 +/** 1.179 + * Define proxying implementation for the given _class. If a state invariant 1.180 + * needs to be checked and an early return possibly performed, pass the clause 1.181 + * to use as _optionalGuard. 1.182 + */ 1.183 +#define MIXIN_IMPL_STORAGEBASESTATEMENTINTERNAL(_class, _optionalGuard) \ 1.184 + MIX_IMPL(_class, _optionalGuard, \ 1.185 + NewBindingParamsArray, \ 1.186 + (mozIStorageBindingParamsArray **_array), \ 1.187 + (_array)) \ 1.188 + MIX_IMPL(_class, _optionalGuard, \ 1.189 + ExecuteAsync, \ 1.190 + (mozIStorageStatementCallback *aCallback, \ 1.191 + mozIStoragePendingStatement **_stmt), \ 1.192 + (aCallback, _stmt)) \ 1.193 + MIX_IMPL(_class, _optionalGuard, \ 1.194 + EscapeStringForLIKE, \ 1.195 + (const nsAString &aValue, const char16_t aEscapeChar, \ 1.196 + nsAString &_escapedString), \ 1.197 + (aValue, aEscapeChar, _escapedString)) 1.198 + 1.199 +/** 1.200 + * Name-building helper for BIND_GEN_IMPL. 1.201 + */ 1.202 +#define BIND_NAME_CONCAT(_nameBit, _concatBit) \ 1.203 + Bind##_nameBit##_concatBit 1.204 + 1.205 +/** 1.206 + * We have type-specific convenience methods for C++ implementations in 1.207 + * 3 different forms; 2 by index, 1 by name. The following macro allows 1.208 + * us to avoid having to define repetitive things by hand. 1.209 + * 1.210 + * Because of limitations of macros and our desire to avoid requiring special 1.211 + * permutations for the null and blob cases (whose argument count varies), 1.212 + * we require that the argument declarations and corresponding invocation 1.213 + * usages are passed in. 1.214 + * 1.215 + * @param _class 1.216 + * The class name. 1.217 + * @param _guard 1.218 + * The guard clause to inject. 1.219 + * @param _declName 1.220 + * The argument list (with parens) for the ByName variants. 1.221 + * @param _declIndex 1.222 + * The argument list (with parens) for the index variants. 1.223 + * @param _invArgs 1.224 + * The invocation argumment list. 1.225 + */ 1.226 +#define BIND_GEN_IMPL(_class, _guard, _name, _declName, _declIndex, _invArgs) \ 1.227 + NS_IMETHODIMP _class::BIND_NAME_CONCAT(_name, ByName) _declName \ 1.228 + { \ 1.229 + _guard \ 1.230 + mozIStorageBindingParams *params = getParams(); \ 1.231 + NS_ENSURE_TRUE(params, NS_ERROR_OUT_OF_MEMORY); \ 1.232 + return params->BIND_NAME_CONCAT(_name, ByName) _invArgs; \ 1.233 + } \ 1.234 + NS_IMETHODIMP _class::BIND_NAME_CONCAT(_name, ByIndex) _declIndex \ 1.235 + { \ 1.236 + _guard \ 1.237 + mozIStorageBindingParams *params = getParams(); \ 1.238 + NS_ENSURE_TRUE(params, NS_ERROR_OUT_OF_MEMORY); \ 1.239 + return params->BIND_NAME_CONCAT(_name, ByIndex) _invArgs; \ 1.240 + } \ 1.241 + NS_IMETHODIMP _class::BIND_NAME_CONCAT(_name, Parameter) _declIndex \ 1.242 + { \ 1.243 + _guard \ 1.244 + mozIStorageBindingParams *params = getParams(); \ 1.245 + NS_ENSURE_TRUE(params, NS_ERROR_OUT_OF_MEMORY); \ 1.246 + return params->BIND_NAME_CONCAT(_name, ByIndex) _invArgs; \ 1.247 + } 1.248 + 1.249 +/** 1.250 + * Implement BindByName/BindByIndex for the given class. 1.251 + * 1.252 + * @param _class The class name. 1.253 + * @param _optionalGuard The guard clause to inject. 1.254 + */ 1.255 +#define BIND_BASE_IMPLS(_class, _optionalGuard) \ 1.256 + NS_IMETHODIMP _class::BindByName(const nsACString &aName, \ 1.257 + nsIVariant *aValue) \ 1.258 + { \ 1.259 + _optionalGuard \ 1.260 + mozIStorageBindingParams *params = getParams(); \ 1.261 + NS_ENSURE_TRUE(params, NS_ERROR_OUT_OF_MEMORY); \ 1.262 + return params->BindByName(aName, aValue); \ 1.263 + } \ 1.264 + NS_IMETHODIMP _class::BindByIndex(uint32_t aIndex, \ 1.265 + nsIVariant *aValue) \ 1.266 + { \ 1.267 + _optionalGuard \ 1.268 + mozIStorageBindingParams *params = getParams(); \ 1.269 + NS_ENSURE_TRUE(params, NS_ERROR_OUT_OF_MEMORY); \ 1.270 + return params->BindByIndex(aIndex, aValue); \ 1.271 + } 1.272 + 1.273 +/** 1.274 + * Define the various Bind*Parameter, Bind*ByIndex, Bind*ByName stubs that just 1.275 + * end up proxying to the params object. 1.276 + */ 1.277 +#define BOILERPLATE_BIND_PROXIES(_class, _optionalGuard) \ 1.278 + BIND_BASE_IMPLS(_class, _optionalGuard) \ 1.279 + BIND_GEN_IMPL(_class, _optionalGuard, \ 1.280 + UTF8String, \ 1.281 + (const nsACString &aWhere, \ 1.282 + const nsACString &aValue), \ 1.283 + (uint32_t aWhere, \ 1.284 + const nsACString &aValue), \ 1.285 + (aWhere, aValue)) \ 1.286 + BIND_GEN_IMPL(_class, _optionalGuard, \ 1.287 + String, \ 1.288 + (const nsACString &aWhere, \ 1.289 + const nsAString &aValue), \ 1.290 + (uint32_t aWhere, \ 1.291 + const nsAString &aValue), \ 1.292 + (aWhere, aValue)) \ 1.293 + BIND_GEN_IMPL(_class, _optionalGuard, \ 1.294 + Double, \ 1.295 + (const nsACString &aWhere, \ 1.296 + double aValue), \ 1.297 + (uint32_t aWhere, \ 1.298 + double aValue), \ 1.299 + (aWhere, aValue)) \ 1.300 + BIND_GEN_IMPL(_class, _optionalGuard, \ 1.301 + Int32, \ 1.302 + (const nsACString &aWhere, \ 1.303 + int32_t aValue), \ 1.304 + (uint32_t aWhere, \ 1.305 + int32_t aValue), \ 1.306 + (aWhere, aValue)) \ 1.307 + BIND_GEN_IMPL(_class, _optionalGuard, \ 1.308 + Int64, \ 1.309 + (const nsACString &aWhere, \ 1.310 + int64_t aValue), \ 1.311 + (uint32_t aWhere, \ 1.312 + int64_t aValue), \ 1.313 + (aWhere, aValue)) \ 1.314 + BIND_GEN_IMPL(_class, _optionalGuard, \ 1.315 + Null, \ 1.316 + (const nsACString &aWhere), \ 1.317 + (uint32_t aWhere), \ 1.318 + (aWhere)) \ 1.319 + BIND_GEN_IMPL(_class, _optionalGuard, \ 1.320 + Blob, \ 1.321 + (const nsACString &aWhere, \ 1.322 + const uint8_t *aValue, \ 1.323 + uint32_t aValueSize), \ 1.324 + (uint32_t aWhere, \ 1.325 + const uint8_t *aValue, \ 1.326 + uint32_t aValueSize), \ 1.327 + (aWhere, aValue, aValueSize)) \ 1.328 + BIND_GEN_IMPL(_class, _optionalGuard, \ 1.329 + AdoptedBlob, \ 1.330 + (const nsACString &aWhere, \ 1.331 + uint8_t *aValue, \ 1.332 + uint32_t aValueSize), \ 1.333 + (uint32_t aWhere, \ 1.334 + uint8_t *aValue, \ 1.335 + uint32_t aValueSize), \ 1.336 + (aWhere, aValue, aValueSize)) 1.337 + 1.338 + 1.339 + 1.340 +} // storage 1.341 +} // mozilla 1.342 + 1.343 +#endif // mozilla_storage_StorageBaseStatementInternal_h_