1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- 2 * vim: sw=2 ts=2 sts=2 expandtab 3 * This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef mozilla_storage_StorageBaseStatementInternal_h_ 8 #define mozilla_storage_StorageBaseStatementInternal_h_ 9 10 #include "nsISupports.h" 11 #include "nsCOMPtr.h" 12 #include "mozStorageHelper.h" 13 14 struct sqlite3; 15 struct sqlite3_stmt; 16 class mozIStorageBindingParamsArray; 17 class mozIStorageBindingParams; 18 class mozIStorageStatementCallback; 19 class mozIStoragePendingStatement; 20 21 namespace mozilla { 22 namespace storage { 23 24 #define STORAGEBASESTATEMENTINTERNAL_IID \ 25 { \ 26 0xd18856c9, 0xbf07, 0x4ae2, { \ 27 0x94, 0x5b, 0x1a, 0xdd, 0x49, 0x19, 0x55, 0x2a \ 28 } \ 29 } 30 31 class Connection; 32 class StatementData; 33 34 class AsyncStatementFinalizer; 35 36 /** 37 * Implementation-only interface and shared logix mix-in corresponding to 38 * mozIStorageBaseStatement. Both Statement and AsyncStatement inherit from 39 * this. The interface aspect makes them look the same to implementation innards 40 * that aren't publicly accessible. The mix-in avoids code duplication in 41 * common implementations of mozIStorageBaseStatement, albeit with some minor 42 * performance/space overhead because we have to use defines to officially 43 * implement the methods on Statement/AsyncStatement (and proxy to this base 44 * class.) 45 */ 46 class StorageBaseStatementInternal : public nsISupports { 47 public: NS_DECLARE_STATIC_IID_ACCESSOR(STORAGEBASESTATEMENTINTERNAL_IID)48 NS_DECLARE_STATIC_IID_ACCESSOR(STORAGEBASESTATEMENTINTERNAL_IID) 49 50 /** 51 * @return the connection that this statement belongs to. 52 */ 53 Connection* getOwner() { return mDBConnection; } 54 55 /** 56 * Return the asynchronous statement, creating it if required. 57 * 58 * This is for use by the asynchronous execution code for StatementData 59 * created by AsyncStatements. Statement internally uses this method to 60 * prepopulate StatementData with the sqlite3_stmt. 61 * 62 * @param[out] stmt 63 * The sqlite3_stmt for asynchronous use. 64 * @return The SQLite result code for creating the statement if created, 65 * SQLITE_OK if creation was not required. 66 */ 67 virtual int getAsyncStatement(sqlite3_stmt** _stmt) = 0; 68 69 /** 70 * Obtains the StatementData needed for asynchronous execution. 71 * 72 * This is for use by Connection to retrieve StatementData from statements 73 * when executeAsync is invoked. 74 * 75 * @param[out] _data 76 * A reference to a StatementData object that will be populated 77 * upon successful execution of this method. 78 * @return NS_OK if we were able to assemble the data, failure otherwise. 79 */ 80 virtual nsresult getAsynchronousStatementData(StatementData& _data) = 0; 81 82 /** 83 * Construct a new BindingParams to be owned by the provided binding params 84 * array. This method exists so that BindingParamsArray does not need 85 * factory logic to determine what type of BindingParams to instantiate. 86 * 87 * @param aOwner 88 * The binding params array to own the newly created binding params. 89 * @return The new mozIStorageBindingParams instance appropriate to the 90 * underlying statement type. 91 */ 92 virtual already_AddRefed<mozIStorageBindingParams> newBindingParams( 93 mozIStorageBindingParamsArray* aOwner) = 0; 94 95 protected: // mix-in bits are protected 96 StorageBaseStatementInternal(); 97 98 RefPtr<Connection> mDBConnection; 99 sqlite3* mNativeConnection; 100 101 /** 102 * Our asynchronous statement. 103 * 104 * For Statement this is populated by the first invocation to 105 * getAsyncStatement. 106 * 107 * For AsyncStatement, this is null at creation time and initialized by the 108 * async thread when it calls getAsyncStatement the first time the statement 109 * is executed. (Or in the event of badly formed SQL, every time.) 110 */ 111 sqlite3_stmt* mAsyncStatement; 112 113 /** 114 * Initiate asynchronous finalization by dispatching an event to the 115 * asynchronous thread to finalize mAsyncStatement. This acquires a reference 116 * to this statement and proxies it back to the connection's owning thread 117 * for release purposes. 118 * 119 * In the event the asynchronous thread is already gone or we otherwise fail 120 * to dispatch an event to it we failover to invoking internalAsyncFinalize 121 * directly. (That's what the asynchronous finalizer would have called.) 122 * 123 * @note You must not call this method from your destructor because its 124 * operation assumes we are still alive. Call internalAsyncFinalize 125 * directly in that case. 126 */ 127 void asyncFinalize(); 128 129 /** 130 * Cleanup the async sqlite3_stmt stored in mAsyncStatement if it exists by 131 * attempting to dispatch to the asynchronous thread if available, finalizing 132 * on this thread if it is not. 133 * 134 * @note Call this from your destructor, call asyncFinalize otherwise. 135 */ 136 void destructorAsyncFinalize(); 137 138 NS_IMETHOD NewBindingParamsArray(mozIStorageBindingParamsArray** _array); 139 NS_IMETHOD ExecuteAsync(mozIStorageStatementCallback* aCallback, 140 mozIStoragePendingStatement** _stmt); 141 NS_IMETHOD EscapeStringForLIKE(const nsAString& aValue, char16_t aEscapeChar, 142 nsAString& _escapedString); 143 NS_IMETHOD EscapeUTF8StringForLIKE(const nsACString& aValue, char aEscapeChar, 144 nsACString& _escapedString); 145 146 // Needs access to internalAsyncFinalize 147 friend class AsyncStatementFinalizer; 148 }; 149 150 NS_DEFINE_STATIC_IID_ACCESSOR(StorageBaseStatementInternal, 151 STORAGEBASESTATEMENTINTERNAL_IID) 152 153 #define NS_DECL_STORAGEBASESTATEMENTINTERNAL \ 154 virtual Connection* getOwner(); \ 155 virtual int getAsyncStatement(sqlite3_stmt** _stmt) override; \ 156 virtual nsresult getAsynchronousStatementData(StatementData& _data) \ 157 override; \ 158 virtual already_AddRefed<mozIStorageBindingParams> newBindingParams( \ 159 mozIStorageBindingParamsArray* aOwner) override; 160 161 /** 162 * Helper macro to implement the proxying implementations. Because we are 163 * implementing methods that are part of mozIStorageBaseStatement and the 164 * implementation classes already use NS_DECL_MOZISTORAGEBASESTATEMENT we don't 165 * need to provide declaration support. 166 */ 167 #define MIX_IMPL(_class, _optionalGuard, _method, _declArgs, _invokeArgs) \ 168 NS_IMETHODIMP _class::_method _declArgs { \ 169 _optionalGuard return StorageBaseStatementInternal::_method _invokeArgs; \ 170 } 171 172 /** 173 * Define proxying implementation for the given _class. If a state invariant 174 * needs to be checked and an early return possibly performed, pass the clause 175 * to use as _optionalGuard. 176 */ 177 #define MIXIN_IMPL_STORAGEBASESTATEMENTINTERNAL(_class, _optionalGuard) \ 178 MIX_IMPL(_class, _optionalGuard, NewBindingParamsArray, \ 179 (mozIStorageBindingParamsArray * *_array), (_array)) \ 180 MIX_IMPL(_class, _optionalGuard, ExecuteAsync, \ 181 (mozIStorageStatementCallback * aCallback, \ 182 mozIStoragePendingStatement * *_stmt), \ 183 (aCallback, _stmt)) \ 184 MIX_IMPL(_class, _optionalGuard, EscapeStringForLIKE, \ 185 (const nsAString& aValue, char16_t aEscapeChar, \ 186 nsAString& _escapedString), \ 187 (aValue, aEscapeChar, _escapedString)) \ 188 MIX_IMPL(_class, _optionalGuard, EscapeUTF8StringForLIKE, \ 189 (const nsACString& aValue, char aEscapeChar, \ 190 nsACString& _escapedString), \ 191 (aValue, aEscapeChar, _escapedString)) 192 193 /** 194 * Name-building helper for BIND_GEN_IMPL. 195 */ 196 #define BIND_NAME_CONCAT(_nameBit, _concatBit) Bind##_nameBit##_concatBit 197 198 /** 199 * We have type-specific convenience methods for C++ implementations in 200 * two different forms; by index and by name. The following macro allows 201 * us to avoid having to define repetitive things by hand. 202 * 203 * Because of limitations of macros and our desire to avoid requiring special 204 * permutations for the null and blob cases (whose argument count varies), 205 * we require that the argument declarations and corresponding invocation 206 * usages are passed in. 207 * 208 * @param _class 209 * The class name. 210 * @param _guard 211 * The guard clause to inject. 212 * @param _declName 213 * The argument list (with parens) for the ByName variants. 214 * @param _declIndex 215 * The argument list (with parens) for the ByIndex variants. 216 * @param _invArgs 217 * The invocation argumment list. 218 */ 219 #define BIND_GEN_IMPL(_class, _guard, _name, _declName, _declIndex, _invArgs) \ 220 NS_IMETHODIMP _class::BIND_NAME_CONCAT(_name, ByName) _declName { \ 221 _guard mozIStorageBindingParams* params = getParams(); \ 222 NS_ENSURE_TRUE(params, NS_ERROR_OUT_OF_MEMORY); \ 223 return params->BIND_NAME_CONCAT(_name, ByName) _invArgs; \ 224 } \ 225 NS_IMETHODIMP _class::BIND_NAME_CONCAT(_name, ByIndex) _declIndex { \ 226 _guard mozIStorageBindingParams* params = getParams(); \ 227 NS_ENSURE_TRUE(params, NS_ERROR_OUT_OF_MEMORY); \ 228 return params->BIND_NAME_CONCAT(_name, ByIndex) _invArgs; \ 229 } 230 231 /** 232 * Implement BindByName/BindByIndex for the given class. 233 * 234 * @param _class The class name. 235 * @param _optionalGuard The guard clause to inject. 236 */ 237 #define BIND_BASE_IMPLS(_class, _optionalGuard) \ 238 NS_IMETHODIMP _class::BindByName(const nsACString& aName, \ 239 nsIVariant* aValue) { \ 240 _optionalGuard mozIStorageBindingParams* params = getParams(); \ 241 NS_ENSURE_TRUE(params, NS_ERROR_OUT_OF_MEMORY); \ 242 return params->BindByName(aName, aValue); \ 243 } \ 244 NS_IMETHODIMP _class::BindByIndex(uint32_t aIndex, nsIVariant* aValue) { \ 245 _optionalGuard mozIStorageBindingParams* params = getParams(); \ 246 NS_ENSURE_TRUE(params, NS_ERROR_OUT_OF_MEMORY); \ 247 return params->BindByIndex(aIndex, aValue); \ 248 } 249 250 /** 251 * Define the various Bind*ByIndex, Bind*ByName stubs that just end up proxying 252 * to the params object. 253 */ 254 #define BOILERPLATE_BIND_PROXIES(_class, _optionalGuard) \ 255 BIND_BASE_IMPLS(_class, _optionalGuard) \ 256 BIND_GEN_IMPL(_class, _optionalGuard, UTF8String, \ 257 (const nsACString& aWhere, const nsACString& aValue), \ 258 (uint32_t aWhere, const nsACString& aValue), (aWhere, aValue)) \ 259 BIND_GEN_IMPL(_class, _optionalGuard, String, \ 260 (const nsACString& aWhere, const nsAString& aValue), \ 261 (uint32_t aWhere, const nsAString& aValue), (aWhere, aValue)) \ 262 BIND_GEN_IMPL(_class, _optionalGuard, Double, \ 263 (const nsACString& aWhere, double aValue), \ 264 (uint32_t aWhere, double aValue), (aWhere, aValue)) \ 265 BIND_GEN_IMPL(_class, _optionalGuard, Int32, \ 266 (const nsACString& aWhere, int32_t aValue), \ 267 (uint32_t aWhere, int32_t aValue), (aWhere, aValue)) \ 268 BIND_GEN_IMPL(_class, _optionalGuard, Int64, \ 269 (const nsACString& aWhere, int64_t aValue), \ 270 (uint32_t aWhere, int64_t aValue), (aWhere, aValue)) \ 271 BIND_GEN_IMPL(_class, _optionalGuard, Null, (const nsACString& aWhere), \ 272 (uint32_t aWhere), (aWhere)) \ 273 BIND_GEN_IMPL( \ 274 _class, _optionalGuard, Blob, \ 275 (const nsACString& aWhere, const uint8_t* aValue, uint32_t aValueSize), \ 276 (uint32_t aWhere, const uint8_t* aValue, uint32_t aValueSize), \ 277 (aWhere, aValue, aValueSize)) \ 278 BIND_GEN_IMPL(_class, _optionalGuard, BlobArray, \ 279 (const nsACString& aWhere, const nsTArray<uint8_t>& aValue), \ 280 (uint32_t aWhere, const nsTArray<uint8_t>& aValue), \ 281 (aWhere, aValue)) \ 282 BIND_GEN_IMPL(_class, _optionalGuard, StringAsBlob, \ 283 (const nsACString& aWhere, const nsAString& aValue), \ 284 (uint32_t aWhere, const nsAString& aValue), (aWhere, aValue)) \ 285 BIND_GEN_IMPL(_class, _optionalGuard, UTF8StringAsBlob, \ 286 (const nsACString& aWhere, const nsACString& aValue), \ 287 (uint32_t aWhere, const nsACString& aValue), (aWhere, aValue)) \ 288 BIND_GEN_IMPL( \ 289 _class, _optionalGuard, AdoptedBlob, \ 290 (const nsACString& aWhere, uint8_t* aValue, uint32_t aValueSize), \ 291 (uint32_t aWhere, uint8_t * aValue, uint32_t aValueSize), \ 292 (aWhere, aValue, aValueSize)) 293 294 } // namespace storage 295 } // namespace mozilla 296 297 #endif // mozilla_storage_StorageBaseStatementInternal_h_ 298