summaryrefslogtreecommitdiffstats
path: root/storage/StorageBaseStatementInternal.h
blob: 685f0f79d0004228e03012ee9476b2f757dc4d14 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
 * vim: sw=2 ts=2 sts=2 expandtab
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef mozilla_storage_StorageBaseStatementInternal_h_
#define mozilla_storage_StorageBaseStatementInternal_h_

#include "nsISupports.h"
#include "nsCOMPtr.h"
#include "mozStorageHelper.h"

struct sqlite3;
struct sqlite3_stmt;
class mozIStorageBindingParamsArray;
class mozIStorageBindingParams;
class mozIStorageStatementCallback;
class mozIStoragePendingStatement;

namespace mozilla {
namespace storage {

#define STORAGEBASESTATEMENTINTERNAL_IID             \
  {                                                  \
    0xd18856c9, 0xbf07, 0x4ae2, {                    \
      0x94, 0x5b, 0x1a, 0xdd, 0x49, 0x19, 0x55, 0x2a \
    }                                                \
  }

class Connection;
class StatementData;

class AsyncStatementFinalizer;

/**
 * Implementation-only interface and shared logix mix-in corresponding to
 * mozIStorageBaseStatement.  Both Statement and AsyncStatement inherit from
 * this. The interface aspect makes them look the same to implementation innards
 * that aren't publicly accessible.  The mix-in avoids code duplication in
 * common implementations of mozIStorageBaseStatement, albeit with some minor
 * performance/space overhead because we have to use defines to officially
 * implement the methods on Statement/AsyncStatement (and proxy to this base
 * class.)
 */
class StorageBaseStatementInternal : public nsISupports {
 public:
  NS_DECLARE_STATIC_IID_ACCESSOR(STORAGEBASESTATEMENTINTERNAL_IID)

  /**
   * @return the connection that this statement belongs to.
   */
  Connection* getOwner() { return mDBConnection; }

  /**
   * Return the asynchronous statement, creating it if required.
   *
   * This is for use by the asynchronous execution code for StatementData
   * created by AsyncStatements.  Statement internally uses this method to
   * prepopulate StatementData with the sqlite3_stmt.
   *
   * @param[out] stmt
   *             The sqlite3_stmt for asynchronous use.
   * @return The SQLite result code for creating the statement if created,
   *         SQLITE_OK if creation was not required.
   */
  virtual int getAsyncStatement(sqlite3_stmt** _stmt) = 0;

  /**
   * Obtains the StatementData needed for asynchronous execution.
   *
   * This is for use by Connection to retrieve StatementData from statements
   * when executeAsync is invoked.
   *
   * @param[out] _data
   *             A reference to a StatementData object that will be populated
   *             upon successful execution of this method.
   * @return NS_OK if we were able to assemble the data, failure otherwise.
   */
  virtual nsresult getAsynchronousStatementData(StatementData& _data) = 0;

  /**
   * Construct a new BindingParams to be owned by the provided binding params
   * array.  This method exists so that BindingParamsArray does not need
   * factory logic to determine what type of BindingParams to instantiate.
   *
   * @param aOwner
   *        The binding params array to own the newly created binding params.
   * @return The new mozIStorageBindingParams instance appropriate to the
   *         underlying statement type.
   */
  virtual already_AddRefed<mozIStorageBindingParams> newBindingParams(
      mozIStorageBindingParamsArray* aOwner) = 0;

 protected:  // mix-in bits are protected
  StorageBaseStatementInternal();

  RefPtr<Connection> mDBConnection;
  sqlite3* mNativeConnection;

  /**
   * Our asynchronous statement.
   *
   * For Statement this is populated by the first invocation to
   * getAsyncStatement.
   *
   * For AsyncStatement, this is null at creation time and initialized by the
   * async thread when it calls getAsyncStatement the first time the statement
   * is executed.  (Or in the event of badly formed SQL, every time.)
   */
  sqlite3_stmt* mAsyncStatement;

  /**
   * Initiate asynchronous finalization by dispatching an event to the
   * asynchronous thread to finalize mAsyncStatement.  This acquires a reference
   * to this statement and proxies it back to the connection's owning thread
   * for release purposes.
   *
   * In the event the asynchronous thread is already gone or we otherwise fail
   * to dispatch an event to it we failover to invoking internalAsyncFinalize
   * directly.  (That's what the asynchronous finalizer would have called.)
   *
   * @note You must not call this method from your destructor because its
   *       operation assumes we are still alive.  Call internalAsyncFinalize
   *       directly in that case.
   */
  void asyncFinalize();

  /**
   * Cleanup the async sqlite3_stmt stored in mAsyncStatement if it exists by
   * attempting to dispatch to the asynchronous thread if available, finalizing
   * on this thread if it is not.
   *
   * @note Call this from your destructor, call asyncFinalize otherwise.
   */
  void destructorAsyncFinalize();

  NS_IMETHOD NewBindingParamsArray(mozIStorageBindingParamsArray** _array);
  NS_IMETHOD ExecuteAsync(mozIStorageStatementCallback* aCallback,
                          mozIStoragePendingStatement** _stmt);
  NS_IMETHOD EscapeStringForLIKE(const nsAString& aValue, char16_t aEscapeChar,
                                 nsAString& _escapedString);
  NS_IMETHOD EscapeUTF8StringForLIKE(const nsACString& aValue, char aEscapeChar,
                                     nsACString& _escapedString);

  // Needs access to internalAsyncFinalize
  friend class AsyncStatementFinalizer;
};

NS_DEFINE_STATIC_IID_ACCESSOR(StorageBaseStatementInternal,
                              STORAGEBASESTATEMENTINTERNAL_IID)

#define NS_DECL_STORAGEBASESTATEMENTINTERNAL                           \
  virtual Connection* getOwner();                                      \
  virtual int getAsyncStatement(sqlite3_stmt** _stmt) override;        \
  virtual nsresult getAsynchronousStatementData(StatementData& _data)  \
      override;                                                        \
  virtual already_AddRefed<mozIStorageBindingParams> newBindingParams( \
      mozIStorageBindingParamsArray* aOwner) override;

/**
 * Helper macro to implement the proxying implementations.  Because we are
 * implementing methods that are part of mozIStorageBaseStatement and the
 * implementation classes already use NS_DECL_MOZISTORAGEBASESTATEMENT we don't
 * need to provide declaration support.
 */
#define MIX_IMPL(_class, _optionalGuard, _method, _declArgs, _invokeArgs)    \
  NS_IMETHODIMP _class::_method _declArgs {                                  \
    _optionalGuard return StorageBaseStatementInternal::_method _invokeArgs; \
  }

/**
 * Define proxying implementation for the given _class.  If a state invariant
 * needs to be checked and an early return possibly performed, pass the clause
 * to use as _optionalGuard.
 */
#define MIXIN_IMPL_STORAGEBASESTATEMENTINTERNAL(_class, _optionalGuard) \
  MIX_IMPL(_class, _optionalGuard, NewBindingParamsArray,               \
           (mozIStorageBindingParamsArray * *_array), (_array))         \
  MIX_IMPL(_class, _optionalGuard, ExecuteAsync,                        \
           (mozIStorageStatementCallback * aCallback,                   \
            mozIStoragePendingStatement * *_stmt),                      \
           (aCallback, _stmt))                                          \
  MIX_IMPL(_class, _optionalGuard, EscapeStringForLIKE,                 \
           (const nsAString& aValue, char16_t aEscapeChar,              \
            nsAString& _escapedString),                                 \
           (aValue, aEscapeChar, _escapedString))                       \
  MIX_IMPL(_class, _optionalGuard, EscapeUTF8StringForLIKE,             \
           (const nsACString& aValue, char aEscapeChar,                 \
            nsACString& _escapedString),                                \
           (aValue, aEscapeChar, _escapedString))

/**
 * Name-building helper for BIND_GEN_IMPL.
 */
#define BIND_NAME_CONCAT(_nameBit, _concatBit) Bind##_nameBit##_concatBit

/**
 * We have type-specific convenience methods for C++ implementations in
 * two different forms; by index and by name.  The following macro allows
 * us to avoid having to define repetitive things by hand.
 *
 * Because of limitations of macros and our desire to avoid requiring special
 * permutations for the null and blob cases (whose argument count varies),
 * we require that the argument declarations and corresponding invocation
 * usages are passed in.
 *
 * @param _class
 *        The class name.
 * @param _guard
 *        The guard clause to inject.
 * @param _declName
 *        The argument list (with parens) for the ByName variants.
 * @param _declIndex
 *        The argument list (with parens) for the ByIndex variants.
 * @param _invArgs
 *        The invocation argumment list.
 */
#define BIND_GEN_IMPL(_class, _guard, _name, _declName, _declIndex, _invArgs) \
  NS_IMETHODIMP _class::BIND_NAME_CONCAT(_name, ByName) _declName {           \
    _guard mozIStorageBindingParams* params = getParams();                    \
    NS_ENSURE_TRUE(params, NS_ERROR_OUT_OF_MEMORY);                           \
    return params->BIND_NAME_CONCAT(_name, ByName) _invArgs;                  \
  }                                                                           \
  NS_IMETHODIMP _class::BIND_NAME_CONCAT(_name, ByIndex) _declIndex {         \
    _guard mozIStorageBindingParams* params = getParams();                    \
    NS_ENSURE_TRUE(params, NS_ERROR_OUT_OF_MEMORY);                           \
    return params->BIND_NAME_CONCAT(_name, ByIndex) _invArgs;                 \
  }

/**
 * Implement BindByName/BindByIndex for the given class.
 *
 * @param _class The class name.
 * @param _optionalGuard The guard clause to inject.
 */
#define BIND_BASE_IMPLS(_class, _optionalGuard)                            \
  NS_IMETHODIMP _class::BindByName(const nsACString& aName,                \
                                   nsIVariant* aValue) {                   \
    _optionalGuard mozIStorageBindingParams* params = getParams();         \
    NS_ENSURE_TRUE(params, NS_ERROR_OUT_OF_MEMORY);                        \
    return params->BindByName(aName, aValue);                              \
  }                                                                        \
  NS_IMETHODIMP _class::BindByIndex(uint32_t aIndex, nsIVariant* aValue) { \
    _optionalGuard mozIStorageBindingParams* params = getParams();         \
    NS_ENSURE_TRUE(params, NS_ERROR_OUT_OF_MEMORY);                        \
    return params->BindByIndex(aIndex, aValue);                            \
  }

/**
 * Define the various Bind*ByIndex, Bind*ByName stubs that just end up proxying
 * to the params object.
 */
#define BOILERPLATE_BIND_PROXIES(_class, _optionalGuard)                       \
  BIND_BASE_IMPLS(_class, _optionalGuard)                                      \
  BIND_GEN_IMPL(_class, _optionalGuard, UTF8String,                            \
                (const nsACString& aWhere, const nsACString& aValue),          \
                (uint32_t aWhere, const nsACString& aValue), (aWhere, aValue)) \
  BIND_GEN_IMPL(_class, _optionalGuard, String,                                \
                (const nsACString& aWhere, const nsAString& aValue),           \
                (uint32_t aWhere, const nsAString& aValue), (aWhere, aValue))  \
  BIND_GEN_IMPL(_class, _optionalGuard, Double,                                \
                (const nsACString& aWhere, double aValue),                     \
                (uint32_t aWhere, double aValue), (aWhere, aValue))            \
  BIND_GEN_IMPL(_class, _optionalGuard, Int32,                                 \
                (const nsACString& aWhere, int32_t aValue),                    \
                (uint32_t aWhere, int32_t aValue), (aWhere, aValue))           \
  BIND_GEN_IMPL(_class, _optionalGuard, Int64,                                 \
                (const nsACString& aWhere, int64_t aValue),                    \
                (uint32_t aWhere, int64_t aValue), (aWhere, aValue))           \
  BIND_GEN_IMPL(_class, _optionalGuard, Null, (const nsACString& aWhere),      \
                (uint32_t aWhere), (aWhere))                                   \
  BIND_GEN_IMPL(                                                               \
      _class, _optionalGuard, Blob,                                            \
      (const nsACString& aWhere, const uint8_t* aValue, uint32_t aValueSize),  \
      (uint32_t aWhere, const uint8_t* aValue, uint32_t aValueSize),           \
      (aWhere, aValue, aValueSize))                                            \
  BIND_GEN_IMPL(_class, _optionalGuard, BlobArray,                             \
                (const nsACString& aWhere, const nsTArray<uint8_t>& aValue),   \
                (uint32_t aWhere, const nsTArray<uint8_t>& aValue),            \
                (aWhere, aValue))                                              \
  BIND_GEN_IMPL(_class, _optionalGuard, StringAsBlob,                          \
                (const nsACString& aWhere, const nsAString& aValue),           \
                (uint32_t aWhere, const nsAString& aValue), (aWhere, aValue))  \
  BIND_GEN_IMPL(_class, _optionalGuard, UTF8StringAsBlob,                      \
                (const nsACString& aWhere, const nsACString& aValue),          \
                (uint32_t aWhere, const nsACString& aValue), (aWhere, aValue)) \
  BIND_GEN_IMPL(                                                               \
      _class, _optionalGuard, AdoptedBlob,                                     \
      (const nsACString& aWhere, uint8_t* aValue, uint32_t aValueSize),        \
      (uint32_t aWhere, uint8_t * aValue, uint32_t aValueSize),                \
      (aWhere, aValue, aValueSize))

}  // namespace storage
}  // namespace mozilla

#endif  // mozilla_storage_StorageBaseStatementInternal_h_