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