storage/src/mozStorageBindingParams.cpp

branch
TOR_BUG_9701
changeset 8
97036ab72558
equal deleted inserted replaced
-1:000000000000 0:6c578797d49f
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: sw=2 ts=2 et lcs=trail\:.,tab\:>~ :
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 #include <limits.h>
8
9 #include "nsString.h"
10
11 #include "mozStorageError.h"
12 #include "mozStoragePrivateHelpers.h"
13 #include "mozStorageBindingParams.h"
14 #include "mozStorageBindingParamsArray.h"
15 #include "Variant.h"
16
17 namespace mozilla {
18 namespace storage {
19
20 ////////////////////////////////////////////////////////////////////////////////
21 //// Local Helper Objects
22
23 namespace {
24
25 struct BindingColumnData
26 {
27 BindingColumnData(sqlite3_stmt *aStmt,
28 int aColumn)
29 : stmt(aStmt)
30 , column(aColumn)
31 {
32 }
33 sqlite3_stmt *stmt;
34 int column;
35 };
36
37 ////////////////////////////////////////////////////////////////////////////////
38 //// Variant Specialization Functions (variantToSQLiteT)
39
40 int
41 sqlite3_T_int(BindingColumnData aData,
42 int aValue)
43 {
44 return ::sqlite3_bind_int(aData.stmt, aData.column + 1, aValue);
45 }
46
47 int
48 sqlite3_T_int64(BindingColumnData aData,
49 sqlite3_int64 aValue)
50 {
51 return ::sqlite3_bind_int64(aData.stmt, aData.column + 1, aValue);
52 }
53
54 int
55 sqlite3_T_double(BindingColumnData aData,
56 double aValue)
57 {
58 return ::sqlite3_bind_double(aData.stmt, aData.column + 1, aValue);
59 }
60
61 int
62 sqlite3_T_text(BindingColumnData aData,
63 const nsCString& aValue)
64 {
65 return ::sqlite3_bind_text(aData.stmt,
66 aData.column + 1,
67 aValue.get(),
68 aValue.Length(),
69 SQLITE_TRANSIENT);
70 }
71
72 int
73 sqlite3_T_text16(BindingColumnData aData,
74 const nsString& aValue)
75 {
76 return ::sqlite3_bind_text16(aData.stmt,
77 aData.column + 1,
78 aValue.get(),
79 aValue.Length() * 2, // Length in bytes!
80 SQLITE_TRANSIENT);
81 }
82
83 int
84 sqlite3_T_null(BindingColumnData aData)
85 {
86 return ::sqlite3_bind_null(aData.stmt, aData.column + 1);
87 }
88
89 int
90 sqlite3_T_blob(BindingColumnData aData,
91 const void *aBlob,
92 int aSize)
93 {
94 return ::sqlite3_bind_blob(aData.stmt, aData.column + 1, aBlob, aSize,
95 NS_Free);
96
97 }
98
99 #include "variantToSQLiteT_impl.h"
100
101 } // anonymous namespace
102
103 ////////////////////////////////////////////////////////////////////////////////
104 //// BindingParams
105
106 BindingParams::BindingParams(mozIStorageBindingParamsArray *aOwningArray,
107 Statement *aOwningStatement)
108 : mLocked(false)
109 , mOwningArray(aOwningArray)
110 , mOwningStatement(aOwningStatement)
111 {
112 (void)mOwningStatement->GetParameterCount(&mParamCount);
113 (void)mParameters.SetCapacity(mParamCount);
114 }
115
116 BindingParams::BindingParams(mozIStorageBindingParamsArray *aOwningArray)
117 : mLocked(false)
118 , mOwningArray(aOwningArray)
119 , mOwningStatement(nullptr)
120 , mParamCount(0)
121 {
122 }
123
124 AsyncBindingParams::AsyncBindingParams(
125 mozIStorageBindingParamsArray *aOwningArray
126 )
127 : BindingParams(aOwningArray)
128 {
129 }
130
131 void
132 BindingParams::lock()
133 {
134 NS_ASSERTION(mLocked == false, "Parameters have already been locked!");
135 mLocked = true;
136
137 // We no longer need to hold a reference to our statement or our owning array.
138 // The array owns us at this point, and it will own a reference to the
139 // statement.
140 mOwningStatement = nullptr;
141 mOwningArray = nullptr;
142 }
143
144 void
145 BindingParams::unlock(Statement *aOwningStatement)
146 {
147 NS_ASSERTION(mLocked == true, "Parameters were not yet locked!");
148 mLocked = false;
149 mOwningStatement = aOwningStatement;
150 }
151
152 const mozIStorageBindingParamsArray *
153 BindingParams::getOwner() const
154 {
155 return mOwningArray;
156 }
157
158 PLDHashOperator
159 AsyncBindingParams::iterateOverNamedParameters(const nsACString &aName,
160 nsIVariant *aValue,
161 void *voidClosureThunk)
162 {
163 NamedParameterIterationClosureThunk *closureThunk =
164 static_cast<NamedParameterIterationClosureThunk *>(voidClosureThunk);
165
166 // We do not accept any forms of names other than ":name", but we need to add
167 // the colon for SQLite.
168 nsAutoCString name(":");
169 name.Append(aName);
170 int oneIdx = ::sqlite3_bind_parameter_index(closureThunk->statement,
171 name.get());
172
173 if (oneIdx == 0) {
174 nsAutoCString errMsg(aName);
175 errMsg.Append(NS_LITERAL_CSTRING(" is not a valid named parameter."));
176 closureThunk->err = new Error(SQLITE_RANGE, errMsg.get());
177 return PL_DHASH_STOP;
178 }
179
180 // XPCVariant's AddRef and Release are not thread-safe and so we must not do
181 // anything that would invoke them here on the async thread. As such we can't
182 // cram aValue into self->mParameters using ReplaceObjectAt so that we can
183 // freeload off of the BindingParams::Bind implementation.
184 int rc = variantToSQLiteT(BindingColumnData(closureThunk->statement,
185 oneIdx - 1),
186 aValue);
187 if (rc != SQLITE_OK) {
188 // We had an error while trying to bind. Now we need to create an error
189 // object with the right message. Note that we special case
190 // SQLITE_MISMATCH, but otherwise get the message from SQLite.
191 const char *msg = "Could not covert nsIVariant to SQLite type.";
192 if (rc != SQLITE_MISMATCH)
193 msg = ::sqlite3_errmsg(::sqlite3_db_handle(closureThunk->statement));
194
195 closureThunk->err = new Error(rc, msg);
196 return PL_DHASH_STOP;
197 }
198 return PL_DHASH_NEXT;
199 }
200
201 ////////////////////////////////////////////////////////////////////////////////
202 //// nsISupports
203
204 NS_IMPL_ISUPPORTS(
205 BindingParams
206 , mozIStorageBindingParams
207 , IStorageBindingParamsInternal
208 )
209
210
211 ////////////////////////////////////////////////////////////////////////////////
212 //// IStorageBindingParamsInternal
213
214 already_AddRefed<mozIStorageError>
215 BindingParams::bind(sqlite3_stmt *aStatement)
216 {
217 // Iterate through all of our stored data, and bind it.
218 for (int32_t i = 0; i < mParameters.Count(); i++) {
219 int rc = variantToSQLiteT(BindingColumnData(aStatement, i), mParameters[i]);
220 if (rc != SQLITE_OK) {
221 // We had an error while trying to bind. Now we need to create an error
222 // object with the right message. Note that we special case
223 // SQLITE_MISMATCH, but otherwise get the message from SQLite.
224 const char *msg = "Could not covert nsIVariant to SQLite type.";
225 if (rc != SQLITE_MISMATCH)
226 msg = ::sqlite3_errmsg(::sqlite3_db_handle(aStatement));
227
228 nsCOMPtr<mozIStorageError> err(new Error(rc, msg));
229 return err.forget();
230 }
231 }
232
233 return nullptr;
234 }
235
236 already_AddRefed<mozIStorageError>
237 AsyncBindingParams::bind(sqlite3_stmt * aStatement)
238 {
239 // We should bind by index using the super-class if there is nothing in our
240 // hashtable.
241 if (!mNamedParameters.Count())
242 return BindingParams::bind(aStatement);
243
244 // Enumerate over everyone in the map, propagating them into mParameters if
245 // we can and creating an error immediately when we cannot.
246 NamedParameterIterationClosureThunk closureThunk = {this, aStatement, nullptr};
247 (void)mNamedParameters.EnumerateRead(iterateOverNamedParameters,
248 (void *)&closureThunk);
249
250 return closureThunk.err.forget();
251 }
252
253
254 ///////////////////////////////////////////////////////////////////////////////
255 //// mozIStorageBindingParams
256
257 NS_IMETHODIMP
258 BindingParams::BindByName(const nsACString &aName,
259 nsIVariant *aValue)
260 {
261 NS_ENSURE_FALSE(mLocked, NS_ERROR_UNEXPECTED);
262
263 // Get the column index that we need to store this at.
264 uint32_t index;
265 nsresult rv = mOwningStatement->GetParameterIndex(aName, &index);
266 NS_ENSURE_SUCCESS(rv, rv);
267
268 return BindByIndex(index, aValue);
269 }
270
271 NS_IMETHODIMP
272 AsyncBindingParams::BindByName(const nsACString &aName,
273 nsIVariant *aValue)
274 {
275 NS_ENSURE_FALSE(mLocked, NS_ERROR_UNEXPECTED);
276
277 mNamedParameters.Put(aName, aValue);
278 return NS_OK;
279 }
280
281
282 NS_IMETHODIMP
283 BindingParams::BindUTF8StringByName(const nsACString &aName,
284 const nsACString &aValue)
285 {
286 nsCOMPtr<nsIVariant> value(new UTF8TextVariant(aValue));
287 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
288
289 return BindByName(aName, value);
290 }
291
292 NS_IMETHODIMP
293 BindingParams::BindStringByName(const nsACString &aName,
294 const nsAString &aValue)
295 {
296 nsCOMPtr<nsIVariant> value(new TextVariant(aValue));
297 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
298
299 return BindByName(aName, value);
300 }
301
302 NS_IMETHODIMP
303 BindingParams::BindDoubleByName(const nsACString &aName,
304 double aValue)
305 {
306 nsCOMPtr<nsIVariant> value(new FloatVariant(aValue));
307 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
308
309 return BindByName(aName, value);
310 }
311
312 NS_IMETHODIMP
313 BindingParams::BindInt32ByName(const nsACString &aName,
314 int32_t aValue)
315 {
316 nsCOMPtr<nsIVariant> value(new IntegerVariant(aValue));
317 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
318
319 return BindByName(aName, value);
320 }
321
322 NS_IMETHODIMP
323 BindingParams::BindInt64ByName(const nsACString &aName,
324 int64_t aValue)
325 {
326 nsCOMPtr<nsIVariant> value(new IntegerVariant(aValue));
327 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
328
329 return BindByName(aName, value);
330 }
331
332 NS_IMETHODIMP
333 BindingParams::BindNullByName(const nsACString &aName)
334 {
335 nsCOMPtr<nsIVariant> value(new NullVariant());
336 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
337
338 return BindByName(aName, value);
339 }
340
341 NS_IMETHODIMP
342 BindingParams::BindBlobByName(const nsACString &aName,
343 const uint8_t *aValue,
344 uint32_t aValueSize)
345 {
346 NS_ENSURE_ARG_MAX(aValueSize, INT_MAX);
347 std::pair<const void *, int> data(
348 static_cast<const void *>(aValue),
349 int(aValueSize)
350 );
351 nsCOMPtr<nsIVariant> value(new BlobVariant(data));
352 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
353
354 return BindByName(aName, value);
355 }
356
357
358 NS_IMETHODIMP
359 BindingParams::BindAdoptedBlobByName(const nsACString &aName,
360 uint8_t *aValue,
361 uint32_t aValueSize)
362 {
363 NS_ENSURE_ARG_MAX(aValueSize, INT_MAX);
364 std::pair<uint8_t *, int> data(
365 aValue,
366 int(aValueSize)
367 );
368 nsCOMPtr<nsIVariant> value(new AdoptedBlobVariant(data));
369
370 return BindByName(aName, value);
371 }
372
373 NS_IMETHODIMP
374 BindingParams::BindByIndex(uint32_t aIndex,
375 nsIVariant *aValue)
376 {
377 NS_ENSURE_FALSE(mLocked, NS_ERROR_UNEXPECTED);
378 ENSURE_INDEX_VALUE(aIndex, mParamCount);
379
380 // Store the variant for later use.
381 NS_ENSURE_TRUE(mParameters.ReplaceObjectAt(aValue, aIndex),
382 NS_ERROR_OUT_OF_MEMORY);
383 return NS_OK;
384 }
385
386 NS_IMETHODIMP
387 AsyncBindingParams::BindByIndex(uint32_t aIndex,
388 nsIVariant *aValue)
389 {
390 NS_ENSURE_FALSE(mLocked, NS_ERROR_UNEXPECTED);
391 // In the asynchronous case we do not know how many parameters there are to
392 // bind to, so we cannot check the validity of aIndex.
393
394 // Store the variant for later use.
395 NS_ENSURE_TRUE(mParameters.ReplaceObjectAt(aValue, aIndex),
396 NS_ERROR_OUT_OF_MEMORY);
397 return NS_OK;
398 }
399
400 NS_IMETHODIMP
401 BindingParams::BindUTF8StringByIndex(uint32_t aIndex,
402 const nsACString &aValue)
403 {
404 nsCOMPtr<nsIVariant> value(new UTF8TextVariant(aValue));
405 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
406
407 return BindByIndex(aIndex, value);
408 }
409
410 NS_IMETHODIMP
411 BindingParams::BindStringByIndex(uint32_t aIndex,
412 const nsAString &aValue)
413 {
414 nsCOMPtr<nsIVariant> value(new TextVariant(aValue));
415 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
416
417 return BindByIndex(aIndex, value);
418 }
419
420 NS_IMETHODIMP
421 BindingParams::BindDoubleByIndex(uint32_t aIndex,
422 double aValue)
423 {
424 nsCOMPtr<nsIVariant> value(new FloatVariant(aValue));
425 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
426
427 return BindByIndex(aIndex, value);
428 }
429
430 NS_IMETHODIMP
431 BindingParams::BindInt32ByIndex(uint32_t aIndex,
432 int32_t aValue)
433 {
434 nsCOMPtr<nsIVariant> value(new IntegerVariant(aValue));
435 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
436
437 return BindByIndex(aIndex, value);
438 }
439
440 NS_IMETHODIMP
441 BindingParams::BindInt64ByIndex(uint32_t aIndex,
442 int64_t aValue)
443 {
444 nsCOMPtr<nsIVariant> value(new IntegerVariant(aValue));
445 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
446
447 return BindByIndex(aIndex, value);
448 }
449
450 NS_IMETHODIMP
451 BindingParams::BindNullByIndex(uint32_t aIndex)
452 {
453 nsCOMPtr<nsIVariant> value(new NullVariant());
454 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
455
456 return BindByIndex(aIndex, value);
457 }
458
459 NS_IMETHODIMP
460 BindingParams::BindBlobByIndex(uint32_t aIndex,
461 const uint8_t *aValue,
462 uint32_t aValueSize)
463 {
464 NS_ENSURE_ARG_MAX(aValueSize, INT_MAX);
465 std::pair<const void *, int> data(
466 static_cast<const void *>(aValue),
467 int(aValueSize)
468 );
469 nsCOMPtr<nsIVariant> value(new BlobVariant(data));
470 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
471
472 return BindByIndex(aIndex, value);
473 }
474
475 NS_IMETHODIMP
476 BindingParams::BindAdoptedBlobByIndex(uint32_t aIndex,
477 uint8_t *aValue,
478 uint32_t aValueSize)
479 {
480 NS_ENSURE_ARG_MAX(aValueSize, INT_MAX);
481 std::pair<uint8_t *, int> data(
482 static_cast<uint8_t *>(aValue),
483 int(aValueSize)
484 );
485 nsCOMPtr<nsIVariant> value(new AdoptedBlobVariant(data));
486
487 return BindByIndex(aIndex, value);
488 }
489
490 } // namespace storage
491 } // namespace mozilla

mercurial