Bug 1462329 [wpt PR 10991] - Server-Timing: test TAO:* for cross-origin resource...
[gecko.git] / storage / mozStorageBindingParams.cpp
blob98e11442015e8269a9ae883aabda3923d5712d13
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/. */
7 #include <limits.h>
9 #include "mozilla/UniquePtrExtensions.h"
10 #include "nsString.h"
12 #include "mozStorageError.h"
13 #include "mozStoragePrivateHelpers.h"
14 #include "mozStorageBindingParams.h"
15 #include "mozStorageBindingParamsArray.h"
16 #include "Variant.h"
18 namespace mozilla {
19 namespace storage {
21 ////////////////////////////////////////////////////////////////////////////////
22 //// Local Helper Objects
24 namespace {
26 struct BindingColumnData
28 BindingColumnData(sqlite3_stmt *aStmt,
29 int aColumn)
30 : stmt(aStmt)
31 , column(aColumn)
34 sqlite3_stmt *stmt;
35 int column;
38 ////////////////////////////////////////////////////////////////////////////////
39 //// Variant Specialization Functions (variantToSQLiteT)
41 int
42 sqlite3_T_int(BindingColumnData aData,
43 int aValue)
45 return ::sqlite3_bind_int(aData.stmt, aData.column + 1, aValue);
48 int
49 sqlite3_T_int64(BindingColumnData aData,
50 sqlite3_int64 aValue)
52 return ::sqlite3_bind_int64(aData.stmt, aData.column + 1, aValue);
55 int
56 sqlite3_T_double(BindingColumnData aData,
57 double aValue)
59 return ::sqlite3_bind_double(aData.stmt, aData.column + 1, aValue);
62 int
63 sqlite3_T_text(BindingColumnData aData,
64 const nsCString& aValue)
66 return ::sqlite3_bind_text(aData.stmt,
67 aData.column + 1,
68 aValue.get(),
69 aValue.Length(),
70 SQLITE_TRANSIENT);
73 int
74 sqlite3_T_text16(BindingColumnData aData,
75 const nsString& aValue)
77 return ::sqlite3_bind_text16(aData.stmt,
78 aData.column + 1,
79 aValue.get(),
80 aValue.Length() * 2, // Length in bytes!
81 SQLITE_TRANSIENT);
84 int
85 sqlite3_T_null(BindingColumnData aData)
87 return ::sqlite3_bind_null(aData.stmt, aData.column + 1);
90 int
91 sqlite3_T_blob(BindingColumnData aData,
92 const void *aBlob,
93 int aSize)
95 return ::sqlite3_bind_blob(aData.stmt, aData.column + 1, aBlob, aSize,
96 free);
100 #include "variantToSQLiteT_impl.h"
102 } // namespace
104 ////////////////////////////////////////////////////////////////////////////////
105 //// BindingParams
107 BindingParams::BindingParams(mozIStorageBindingParamsArray *aOwningArray,
108 Statement *aOwningStatement)
109 : mLocked(false)
110 , mOwningArray(aOwningArray)
111 , mOwningStatement(aOwningStatement)
112 , mParamCount(0)
114 (void)mOwningStatement->GetParameterCount(&mParamCount);
115 mParameters.SetCapacity(mParamCount);
118 BindingParams::BindingParams(mozIStorageBindingParamsArray *aOwningArray)
119 : mLocked(false)
120 , mOwningArray(aOwningArray)
121 , mOwningStatement(nullptr)
122 , mParamCount(0)
126 AsyncBindingParams::AsyncBindingParams(
127 mozIStorageBindingParamsArray *aOwningArray
129 : BindingParams(aOwningArray)
133 void
134 BindingParams::lock()
136 NS_ASSERTION(mLocked == false, "Parameters have already been locked!");
137 mLocked = true;
139 // We no longer need to hold a reference to our statement or our owning array.
140 // The array owns us at this point, and it will own a reference to the
141 // statement.
142 mOwningStatement = nullptr;
143 mOwningArray = nullptr;
146 void
147 BindingParams::unlock(Statement *aOwningStatement)
149 NS_ASSERTION(mLocked == true, "Parameters were not yet locked!");
150 mLocked = false;
151 mOwningStatement = aOwningStatement;
154 const mozIStorageBindingParamsArray *
155 BindingParams::getOwner() const
157 return mOwningArray;
160 ////////////////////////////////////////////////////////////////////////////////
161 //// nsISupports
163 NS_IMPL_ISUPPORTS(
164 BindingParams
165 , mozIStorageBindingParams
166 , IStorageBindingParamsInternal
170 ////////////////////////////////////////////////////////////////////////////////
171 //// IStorageBindingParamsInternal
173 already_AddRefed<mozIStorageError>
174 BindingParams::bind(sqlite3_stmt *aStatement)
176 // Iterate through all of our stored data, and bind it.
177 for (size_t i = 0; i < mParameters.Length(); i++) {
178 int rc = variantToSQLiteT(BindingColumnData(aStatement, i), mParameters[i]);
179 if (rc != SQLITE_OK) {
180 // We had an error while trying to bind. Now we need to create an error
181 // object with the right message. Note that we special case
182 // SQLITE_MISMATCH, but otherwise get the message from SQLite.
183 const char *msg = "Could not covert nsIVariant to SQLite type.";
184 if (rc != SQLITE_MISMATCH)
185 msg = ::sqlite3_errmsg(::sqlite3_db_handle(aStatement));
187 nsCOMPtr<mozIStorageError> err(new Error(rc, msg));
188 return err.forget();
192 return nullptr;
195 already_AddRefed<mozIStorageError>
196 AsyncBindingParams::bind(sqlite3_stmt * aStatement)
198 // We should bind by index using the super-class if there is nothing in our
199 // hashtable.
200 if (!mNamedParameters.Count())
201 return BindingParams::bind(aStatement);
203 nsCOMPtr<mozIStorageError> err;
205 for (auto iter = mNamedParameters.Iter(); !iter.Done(); iter.Next()) {
206 const nsACString &key = iter.Key();
208 // We do not accept any forms of names other than ":name", but we need to
209 // add the colon for SQLite.
210 nsAutoCString name(":");
211 name.Append(key);
212 int oneIdx = ::sqlite3_bind_parameter_index(aStatement, name.get());
214 if (oneIdx == 0) {
215 nsAutoCString errMsg(key);
216 errMsg.AppendLiteral(" is not a valid named parameter.");
217 err = new Error(SQLITE_RANGE, errMsg.get());
218 break;
221 // XPCVariant's AddRef and Release are not thread-safe and so we must not
222 // do anything that would invoke them here on the async thread. As such we
223 // can't cram aValue into mParameters using ReplaceObjectAt so that
224 // we can freeload off of the BindingParams::Bind implementation.
225 int rc = variantToSQLiteT(BindingColumnData(aStatement, oneIdx - 1),
226 iter.UserData());
227 if (rc != SQLITE_OK) {
228 // We had an error while trying to bind. Now we need to create an error
229 // object with the right message. Note that we special case
230 // SQLITE_MISMATCH, but otherwise get the message from SQLite.
231 const char *msg = "Could not covert nsIVariant to SQLite type.";
232 if (rc != SQLITE_MISMATCH) {
233 msg = ::sqlite3_errmsg(::sqlite3_db_handle(aStatement));
235 err = new Error(rc, msg);
236 break;
240 return err.forget();
244 ///////////////////////////////////////////////////////////////////////////////
245 //// mozIStorageBindingParams
247 NS_IMETHODIMP
248 BindingParams::BindByName(const nsACString &aName,
249 nsIVariant *aValue)
251 NS_ENSURE_FALSE(mLocked, NS_ERROR_UNEXPECTED);
253 // Get the column index that we need to store this at.
254 uint32_t index;
255 nsresult rv = mOwningStatement->GetParameterIndex(aName, &index);
256 NS_ENSURE_SUCCESS(rv, rv);
258 return BindByIndex(index, aValue);
261 NS_IMETHODIMP
262 AsyncBindingParams::BindByName(const nsACString &aName,
263 nsIVariant *aValue)
265 NS_ENSURE_FALSE(mLocked, NS_ERROR_UNEXPECTED);
267 RefPtr<Variant_base> variant = convertVariantToStorageVariant(aValue);
268 if (!variant)
269 return NS_ERROR_UNEXPECTED;
271 mNamedParameters.Put(aName, variant);
272 return NS_OK;
276 NS_IMETHODIMP
277 BindingParams::BindUTF8StringByName(const nsACString &aName,
278 const nsACString &aValue)
280 nsCOMPtr<nsIVariant> value(new UTF8TextVariant(aValue));
281 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
283 return BindByName(aName, value);
286 NS_IMETHODIMP
287 BindingParams::BindStringByName(const nsACString &aName,
288 const nsAString &aValue)
290 nsCOMPtr<nsIVariant> value(new TextVariant(aValue));
291 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
293 return BindByName(aName, value);
296 NS_IMETHODIMP
297 BindingParams::BindDoubleByName(const nsACString &aName,
298 double aValue)
300 nsCOMPtr<nsIVariant> value(new FloatVariant(aValue));
301 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
303 return BindByName(aName, value);
306 NS_IMETHODIMP
307 BindingParams::BindInt32ByName(const nsACString &aName,
308 int32_t aValue)
310 nsCOMPtr<nsIVariant> value(new IntegerVariant(aValue));
311 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
313 return BindByName(aName, value);
316 NS_IMETHODIMP
317 BindingParams::BindInt64ByName(const nsACString &aName,
318 int64_t aValue)
320 nsCOMPtr<nsIVariant> value(new IntegerVariant(aValue));
321 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
323 return BindByName(aName, value);
326 NS_IMETHODIMP
327 BindingParams::BindNullByName(const nsACString &aName)
329 nsCOMPtr<nsIVariant> value(new NullVariant());
330 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
332 return BindByName(aName, value);
335 NS_IMETHODIMP
336 BindingParams::BindBlobByName(const nsACString &aName,
337 const uint8_t *aValue,
338 uint32_t aValueSize)
340 NS_ENSURE_ARG_MAX(aValueSize, INT_MAX);
341 std::pair<const void *, int> data(
342 static_cast<const void *>(aValue),
343 int(aValueSize)
345 nsCOMPtr<nsIVariant> value(new BlobVariant(data));
346 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
348 return BindByName(aName, value);
351 NS_IMETHODIMP
352 BindingParams::BindStringAsBlobByName(const nsACString& aName,
353 const nsAString& aValue)
355 return DoBindStringAsBlobByName(this, aName, aValue);
358 NS_IMETHODIMP
359 BindingParams::BindUTF8StringAsBlobByName(const nsACString& aName,
360 const nsACString& aValue)
362 return DoBindStringAsBlobByName(this, aName, aValue);
366 NS_IMETHODIMP
367 BindingParams::BindAdoptedBlobByName(const nsACString &aName,
368 uint8_t *aValue,
369 uint32_t aValueSize)
371 UniqueFreePtr<uint8_t> uniqueValue(aValue);
372 NS_ENSURE_ARG_MAX(aValueSize, INT_MAX);
373 std::pair<uint8_t *, int> data(uniqueValue.release(), int(aValueSize));
374 nsCOMPtr<nsIVariant> value(new AdoptedBlobVariant(data));
376 return BindByName(aName, value);
379 NS_IMETHODIMP
380 BindingParams::BindByIndex(uint32_t aIndex,
381 nsIVariant *aValue)
383 NS_ENSURE_FALSE(mLocked, NS_ERROR_UNEXPECTED);
384 ENSURE_INDEX_VALUE(aIndex, mParamCount);
386 // Store the variant for later use.
387 RefPtr<Variant_base> variant = convertVariantToStorageVariant(aValue);
388 if (!variant)
389 return NS_ERROR_UNEXPECTED;
390 if (mParameters.Length() <= aIndex) {
391 (void)mParameters.SetLength(aIndex);
392 (void)mParameters.AppendElement(variant);
394 else {
395 NS_ENSURE_TRUE(mParameters.ReplaceElementAt(aIndex, variant),
396 NS_ERROR_OUT_OF_MEMORY);
398 return NS_OK;
401 NS_IMETHODIMP
402 AsyncBindingParams::BindByIndex(uint32_t aIndex,
403 nsIVariant *aValue)
405 NS_ENSURE_FALSE(mLocked, NS_ERROR_UNEXPECTED);
406 // In the asynchronous case we do not know how many parameters there are to
407 // bind to, so we cannot check the validity of aIndex.
409 RefPtr<Variant_base> variant = convertVariantToStorageVariant(aValue);
410 if (!variant)
411 return NS_ERROR_UNEXPECTED;
412 if (mParameters.Length() <= aIndex) {
413 mParameters.SetLength(aIndex);
414 mParameters.AppendElement(variant);
416 else {
417 NS_ENSURE_TRUE(mParameters.ReplaceElementAt(aIndex, variant),
418 NS_ERROR_OUT_OF_MEMORY);
420 return NS_OK;
423 NS_IMETHODIMP
424 BindingParams::BindUTF8StringByIndex(uint32_t aIndex,
425 const nsACString &aValue)
427 nsCOMPtr<nsIVariant> value(new UTF8TextVariant(aValue));
428 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
430 return BindByIndex(aIndex, value);
433 NS_IMETHODIMP
434 BindingParams::BindStringByIndex(uint32_t aIndex,
435 const nsAString &aValue)
437 nsCOMPtr<nsIVariant> value(new TextVariant(aValue));
438 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
440 return BindByIndex(aIndex, value);
443 NS_IMETHODIMP
444 BindingParams::BindDoubleByIndex(uint32_t aIndex,
445 double aValue)
447 nsCOMPtr<nsIVariant> value(new FloatVariant(aValue));
448 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
450 return BindByIndex(aIndex, value);
453 NS_IMETHODIMP
454 BindingParams::BindInt32ByIndex(uint32_t aIndex,
455 int32_t aValue)
457 nsCOMPtr<nsIVariant> value(new IntegerVariant(aValue));
458 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
460 return BindByIndex(aIndex, value);
463 NS_IMETHODIMP
464 BindingParams::BindInt64ByIndex(uint32_t aIndex,
465 int64_t aValue)
467 nsCOMPtr<nsIVariant> value(new IntegerVariant(aValue));
468 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
470 return BindByIndex(aIndex, value);
473 NS_IMETHODIMP
474 BindingParams::BindNullByIndex(uint32_t aIndex)
476 nsCOMPtr<nsIVariant> value(new NullVariant());
477 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
479 return BindByIndex(aIndex, value);
482 NS_IMETHODIMP
483 BindingParams::BindBlobByIndex(uint32_t aIndex,
484 const uint8_t *aValue,
485 uint32_t aValueSize)
487 NS_ENSURE_ARG_MAX(aValueSize, INT_MAX);
488 std::pair<const void *, int> data(
489 static_cast<const void *>(aValue),
490 int(aValueSize)
492 nsCOMPtr<nsIVariant> value(new BlobVariant(data));
493 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
495 return BindByIndex(aIndex, value);
498 NS_IMETHODIMP
499 BindingParams::BindStringAsBlobByIndex(uint32_t aIndex, const nsAString& aValue)
501 return DoBindStringAsBlobByIndex(this, aIndex, aValue);
504 NS_IMETHODIMP
505 BindingParams::BindUTF8StringAsBlobByIndex(uint32_t aIndex,
506 const nsACString& aValue)
508 return DoBindStringAsBlobByIndex(this, aIndex, aValue);
511 NS_IMETHODIMP
512 BindingParams::BindAdoptedBlobByIndex(uint32_t aIndex,
513 uint8_t *aValue,
514 uint32_t aValueSize)
516 UniqueFreePtr<uint8_t> uniqueValue(aValue);
517 NS_ENSURE_ARG_MAX(aValueSize, INT_MAX);
518 std::pair<uint8_t *, int> data(uniqueValue.release(), int(aValueSize));
519 nsCOMPtr<nsIVariant> value(new AdoptedBlobVariant(data));
521 return BindByIndex(aIndex, value);
524 } // namespace storage
525 } // namespace mozilla