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 "nsAutoPtr.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   {0xd18856c9, 0xbf07, 0x4ae2, {0x94, 0x5b, 0x1a, 0xdd, 0x49, 0x19, 0x55, 0x2a}}
26 
27 class Connection;
28 class StatementData;
29 
30 class AsyncStatementFinalizer;
31 
32 /**
33  * Implementation-only interface and shared logix mix-in corresponding to
34  * mozIStorageBaseStatement.  Both Statement and AsyncStatement inherit from
35  * this. The interface aspect makes them look the same to implementation innards
36  * that aren't publicly accessible.  The mix-in avoids code duplication in
37  * common implementations of mozIStorageBaseStatement, albeit with some minor
38  * performance/space overhead because we have to use defines to officially
39  * implement the methods on Statement/AsyncStatement (and proxy to this base
40  * class.)
41  */
42 class StorageBaseStatementInternal : public nsISupports
43 {
44 public:
NS_DECLARE_STATIC_IID_ACCESSOR(STORAGEBASESTATEMENTINTERNAL_IID)45   NS_DECLARE_STATIC_IID_ACCESSOR(STORAGEBASESTATEMENTINTERNAL_IID)
46 
47   /**
48    * @return the connection that this statement belongs to.
49    */
50   Connection *getOwner()
51   {
52     return mDBConnection;
53   }
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
94   ) = 0;
95 
96 protected: // mix-in bits are protected
97   StorageBaseStatementInternal();
98 
99   RefPtr<Connection> mDBConnection;
100   sqlite3 *mNativeConnection;
101 
102   /**
103    * Our asynchronous statement.
104    *
105    * For Statement this is populated by the first invocation to
106    * getAsyncStatement.
107    *
108    * For AsyncStatement, this is null at creation time and initialized by the
109    * async thread when it calls getAsyncStatement the first time the statement
110    * is executed.  (Or in the event of badly formed SQL, every time.)
111    */
112   sqlite3_stmt *mAsyncStatement;
113 
114   /**
115    * Initiate asynchronous finalization by dispatching an event to the
116    * asynchronous thread to finalize mAsyncStatement.  This acquires a reference
117    * to this statement and proxies it back to the connection's owning thread
118    * for release purposes.
119    *
120    * In the event the asynchronous thread is already gone or we otherwise fail
121    * to dispatch an event to it we failover to invoking internalAsyncFinalize
122    * directly.  (That's what the asynchronous finalizer would have called.)
123    *
124    * @note You must not call this method from your destructor because its
125    *       operation assumes we are still alive.  Call internalAsyncFinalize
126    *       directly in that case.
127    */
128   void asyncFinalize();
129 
130   /**
131    * Cleanup the async sqlite3_stmt stored in mAsyncStatement if it exists by
132    * attempting to dispatch to the asynchronous thread if available, finalizing
133    * on this thread if it is not.
134    *
135    * @note Call this from your destructor, call asyncFinalize otherwise.
136    */
137   void destructorAsyncFinalize();
138 
139   NS_IMETHOD NewBindingParamsArray(mozIStorageBindingParamsArray **_array);
140   NS_IMETHOD ExecuteAsync(mozIStorageStatementCallback *aCallback,
141                           mozIStoragePendingStatement **_stmt);
142   NS_IMETHOD EscapeStringForLIKE(const nsAString &aValue,
143                                  char16_t aEscapeChar,
144                                  nsAString &_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) override; \
157   virtual already_AddRefed<mozIStorageBindingParams> newBindingParams( \
158     mozIStorageBindingParamsArray *aOwner) override;
159 
160 /**
161  * Helper macro to implement the proxying implementations.  Because we are
162  * implementing methods that are part of mozIStorageBaseStatement and the
163  * implementation classes already use NS_DECL_MOZISTORAGEBASESTATEMENT we don't
164  * need to provide declaration support.
165  */
166 #define MIX_IMPL(_class, _optionalGuard, _method, _declArgs, _invokeArgs) \
167   NS_IMETHODIMP _class::_method _declArgs                                 \
168   {                                                                       \
169     _optionalGuard                                                        \
170     return StorageBaseStatementInternal::_method _invokeArgs;             \
171   }
172 
173 
174 /**
175  * Define proxying implementation for the given _class.  If a state invariant
176  * needs to be checked and an early return possibly performed, pass the clause
177  * to use as _optionalGuard.
178  */
179 #define MIXIN_IMPL_STORAGEBASESTATEMENTINTERNAL(_class, _optionalGuard) \
180   MIX_IMPL(_class, _optionalGuard,                                      \
181            NewBindingParamsArray,                                       \
182            (mozIStorageBindingParamsArray **_array),                    \
183            (_array))                                                    \
184   MIX_IMPL(_class, _optionalGuard,                                      \
185            ExecuteAsync,                                                \
186            (mozIStorageStatementCallback *aCallback,                    \
187             mozIStoragePendingStatement **_stmt),                       \
188            (aCallback, _stmt))                                          \
189   MIX_IMPL(_class, _optionalGuard,                                      \
190            EscapeStringForLIKE,                                         \
191            (const nsAString &aValue, char16_t aEscapeChar,              \
192             nsAString &_escapedString),                                 \
193            (aValue, aEscapeChar, _escapedString))
194 
195 /**
196  * Name-building helper for BIND_GEN_IMPL.
197  */
198 #define BIND_NAME_CONCAT(_nameBit, _concatBit) \
199   Bind##_nameBit##_concatBit
200 
201 /**
202  * We have type-specific convenience methods for C++ implementations in
203  * 3 different forms; 2 by index, 1 by name.  The following macro allows
204  * us to avoid having to define repetitive things by hand.
205  *
206  * Because of limitations of macros and our desire to avoid requiring special
207  * permutations for the null and blob cases (whose argument count varies),
208  * we require that the argument declarations and corresponding invocation
209  * usages are passed in.
210  *
211  * @param _class
212  *        The class name.
213  * @param _guard
214  *        The guard clause to inject.
215  * @param _declName
216  *        The argument list (with parens) for the ByName variants.
217  * @param _declIndex
218  *        The argument list (with parens) for the index variants.
219  * @param _invArgs
220  *        The invocation argumment list.
221  */
222 #define BIND_GEN_IMPL(_class, _guard, _name, _declName, _declIndex, _invArgs) \
223   NS_IMETHODIMP _class::BIND_NAME_CONCAT(_name, ByName) _declName             \
224   {                                                                           \
225     _guard                                                                    \
226     mozIStorageBindingParams *params = getParams();                           \
227     NS_ENSURE_TRUE(params, NS_ERROR_OUT_OF_MEMORY);                           \
228     return params->BIND_NAME_CONCAT(_name, ByName) _invArgs;                  \
229   }                                                                           \
230   NS_IMETHODIMP _class::BIND_NAME_CONCAT(_name, ByIndex) _declIndex           \
231   {                                                                           \
232     _guard                                                                    \
233     mozIStorageBindingParams *params = getParams();                           \
234     NS_ENSURE_TRUE(params, NS_ERROR_OUT_OF_MEMORY);                           \
235     return params->BIND_NAME_CONCAT(_name, ByIndex) _invArgs;                 \
236   }                                                                           \
237   NS_IMETHODIMP _class::BIND_NAME_CONCAT(_name, Parameter) _declIndex         \
238   {                                                                           \
239     _guard                                                                    \
240     mozIStorageBindingParams *params = getParams();                           \
241     NS_ENSURE_TRUE(params, NS_ERROR_OUT_OF_MEMORY);                           \
242     return params->BIND_NAME_CONCAT(_name, ByIndex) _invArgs;                 \
243   }
244 
245 /**
246  * Implement BindByName/BindByIndex for the given class.
247  *
248  * @param _class The class name.
249  * @param _optionalGuard The guard clause to inject.
250  */
251 #define BIND_BASE_IMPLS(_class, _optionalGuard)             \
252   NS_IMETHODIMP _class::BindByName(const nsACString &aName, \
253                                    nsIVariant *aValue)      \
254   {                                                         \
255     _optionalGuard                                          \
256     mozIStorageBindingParams *params = getParams();         \
257     NS_ENSURE_TRUE(params, NS_ERROR_OUT_OF_MEMORY);         \
258     return params->BindByName(aName, aValue);               \
259   }                                                         \
260   NS_IMETHODIMP _class::BindByIndex(uint32_t aIndex,        \
261                                     nsIVariant *aValue)     \
262   {                                                         \
263     _optionalGuard                                          \
264     mozIStorageBindingParams *params = getParams();         \
265     NS_ENSURE_TRUE(params, NS_ERROR_OUT_OF_MEMORY);         \
266     return params->BindByIndex(aIndex, aValue);             \
267   }
268 
269 /**
270  * Define the various Bind*Parameter, Bind*ByIndex, Bind*ByName stubs that just
271  * end up proxying to the params object.
272  */
273 #define BOILERPLATE_BIND_PROXIES(_class, _optionalGuard) \
274   BIND_BASE_IMPLS(_class, _optionalGuard)                \
275   BIND_GEN_IMPL(_class, _optionalGuard,                  \
276                 UTF8String,                              \
277                 (const nsACString &aWhere,               \
278                  const nsACString &aValue),              \
279                 (uint32_t aWhere,                        \
280                  const nsACString &aValue),              \
281                 (aWhere, aValue))                        \
282   BIND_GEN_IMPL(_class, _optionalGuard,                  \
283                 String,                                  \
284                 (const nsACString &aWhere,               \
285                  const nsAString  &aValue),              \
286                 (uint32_t aWhere,                        \
287                  const nsAString  &aValue),              \
288                 (aWhere, aValue))                        \
289   BIND_GEN_IMPL(_class, _optionalGuard,                  \
290                 Double,                                  \
291                 (const nsACString &aWhere,               \
292                  double aValue),                         \
293                 (uint32_t aWhere,                        \
294                  double aValue),                         \
295                 (aWhere, aValue))                        \
296   BIND_GEN_IMPL(_class, _optionalGuard,                  \
297                 Int32,                                   \
298                 (const nsACString &aWhere,               \
299                  int32_t aValue),                        \
300                 (uint32_t aWhere,                        \
301                  int32_t aValue),                        \
302                 (aWhere, aValue))                        \
303   BIND_GEN_IMPL(_class, _optionalGuard,                  \
304                 Int64,                                   \
305                 (const nsACString &aWhere,               \
306                  int64_t aValue),                        \
307                 (uint32_t aWhere,                        \
308                  int64_t aValue),                        \
309                 (aWhere, aValue))                        \
310   BIND_GEN_IMPL(_class, _optionalGuard,                  \
311                 Null,                                    \
312                 (const nsACString &aWhere),              \
313                 (uint32_t aWhere),                       \
314                 (aWhere))                                \
315   BIND_GEN_IMPL(_class, _optionalGuard,                  \
316                 Blob,                                    \
317                 (const nsACString &aWhere,               \
318                  const uint8_t *aValue,                  \
319                  uint32_t aValueSize),                   \
320                 (uint32_t aWhere,                        \
321                  const uint8_t *aValue,                  \
322                  uint32_t aValueSize),                   \
323                 (aWhere, aValue, aValueSize))            \
324   BIND_GEN_IMPL(_class, _optionalGuard,                  \
325                 StringAsBlob,                            \
326                 (const nsACString &aWhere,               \
327                  const nsAString& aValue),               \
328                 (uint32_t aWhere,                        \
329                  const nsAString& aValue),               \
330                 (aWhere, aValue))                        \
331   BIND_GEN_IMPL(_class, _optionalGuard,                  \
332                 UTF8StringAsBlob,                        \
333                 (const nsACString &aWhere,               \
334                  const nsACString& aValue),              \
335                 (uint32_t aWhere,                        \
336                  const nsACString& aValue),              \
337                 (aWhere, aValue))                        \
338   BIND_GEN_IMPL(_class, _optionalGuard,                  \
339                 AdoptedBlob,                             \
340                 (const nsACString &aWhere,               \
341                  uint8_t *aValue,                        \
342                  uint32_t aValueSize),                   \
343                 (uint32_t aWhere,                        \
344                  uint8_t *aValue,                        \
345                  uint32_t aValueSize),                   \
346                 (aWhere, aValue, aValueSize))
347 
348 
349 
350 } // namespace storage
351 } // namespace mozilla
352 
353 #endif // mozilla_storage_StorageBaseStatementInternal_h_
354