Bug 1572132 - fix URL generation in fetch-content r=glandium
[gecko.git] / storage / mozStorageBindingParams.cpp
blobd7ea5ad2a44512ab74d441e9bed02d09d2364a89
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 {
27 BindingColumnData(sqlite3_stmt* aStmt, int aColumn)
28 : stmt(aStmt), column(aColumn) {}
29 sqlite3_stmt* stmt;
30 int column;
33 ////////////////////////////////////////////////////////////////////////////////
34 //// Variant Specialization Functions (variantToSQLiteT)
36 int sqlite3_T_int(BindingColumnData aData, int aValue) {
37 return ::sqlite3_bind_int(aData.stmt, aData.column + 1, aValue);
40 int sqlite3_T_int64(BindingColumnData aData, sqlite3_int64 aValue) {
41 return ::sqlite3_bind_int64(aData.stmt, aData.column + 1, aValue);
44 int sqlite3_T_double(BindingColumnData aData, double aValue) {
45 return ::sqlite3_bind_double(aData.stmt, aData.column + 1, aValue);
48 int sqlite3_T_text(BindingColumnData aData, const nsCString& aValue) {
49 return ::sqlite3_bind_text(aData.stmt, aData.column + 1, aValue.get(),
50 aValue.Length(), SQLITE_TRANSIENT);
53 int sqlite3_T_text16(BindingColumnData aData, const nsString& aValue) {
54 return ::sqlite3_bind_text16(
55 aData.stmt, aData.column + 1, aValue.get(),
56 aValue.Length() * sizeof(char16_t), // Length in bytes!
57 SQLITE_TRANSIENT);
60 int sqlite3_T_null(BindingColumnData aData) {
61 return ::sqlite3_bind_null(aData.stmt, aData.column + 1);
64 int sqlite3_T_blob(BindingColumnData aData, const void* aBlob, int aSize) {
65 return ::sqlite3_bind_blob(aData.stmt, aData.column + 1, aBlob, aSize, free);
68 #include "variantToSQLiteT_impl.h"
70 } // namespace
72 ////////////////////////////////////////////////////////////////////////////////
73 //// BindingParams
75 BindingParams::BindingParams(mozIStorageBindingParamsArray* aOwningArray,
76 Statement* aOwningStatement)
77 : mLocked(false),
78 mOwningArray(aOwningArray),
79 mOwningStatement(aOwningStatement),
80 mParamCount(0) {
81 (void)mOwningStatement->GetParameterCount(&mParamCount);
82 mParameters.SetCapacity(mParamCount);
85 BindingParams::BindingParams(mozIStorageBindingParamsArray* aOwningArray)
86 : mLocked(false),
87 mOwningArray(aOwningArray),
88 mOwningStatement(nullptr),
89 mParamCount(0) {}
91 AsyncBindingParams::AsyncBindingParams(
92 mozIStorageBindingParamsArray* aOwningArray)
93 : BindingParams(aOwningArray) {}
95 void BindingParams::lock() {
96 NS_ASSERTION(mLocked == false, "Parameters have already been locked!");
97 mLocked = true;
99 // We no longer need to hold a reference to our statement or our owning array.
100 // The array owns us at this point, and it will own a reference to the
101 // statement.
102 mOwningStatement = nullptr;
103 mOwningArray = nullptr;
106 void BindingParams::unlock(Statement* aOwningStatement) {
107 NS_ASSERTION(mLocked == true, "Parameters were not yet locked!");
108 mLocked = false;
109 mOwningStatement = aOwningStatement;
112 const mozIStorageBindingParamsArray* BindingParams::getOwner() const {
113 return mOwningArray;
116 ////////////////////////////////////////////////////////////////////////////////
117 //// nsISupports
119 NS_IMPL_ISUPPORTS(BindingParams, mozIStorageBindingParams,
120 IStorageBindingParamsInternal)
122 ////////////////////////////////////////////////////////////////////////////////
123 //// IStorageBindingParamsInternal
125 already_AddRefed<mozIStorageError> BindingParams::bind(
126 sqlite3_stmt* aStatement) {
127 // Iterate through all of our stored data, and bind it.
128 for (size_t i = 0; i < mParameters.Length(); i++) {
129 int rc = variantToSQLiteT(BindingColumnData(aStatement, i), mParameters[i]);
130 if (rc != SQLITE_OK) {
131 // We had an error while trying to bind. Now we need to create an error
132 // object with the right message. Note that we special case
133 // SQLITE_MISMATCH, but otherwise get the message from SQLite.
134 const char* msg = "Could not covert nsIVariant to SQLite type.";
135 if (rc != SQLITE_MISMATCH)
136 msg = ::sqlite3_errmsg(::sqlite3_db_handle(aStatement));
138 nsCOMPtr<mozIStorageError> err(new Error(rc, msg));
139 return err.forget();
143 return nullptr;
146 already_AddRefed<mozIStorageError> AsyncBindingParams::bind(
147 sqlite3_stmt* aStatement) {
148 // We should bind by index using the super-class if there is nothing in our
149 // hashtable.
150 if (!mNamedParameters.Count()) return BindingParams::bind(aStatement);
152 nsCOMPtr<mozIStorageError> err;
154 for (auto iter = mNamedParameters.Iter(); !iter.Done(); iter.Next()) {
155 const nsACString& key = iter.Key();
157 // We do not accept any forms of names other than ":name", but we need to
158 // add the colon for SQLite.
159 nsAutoCString name(":");
160 name.Append(key);
161 int oneIdx = ::sqlite3_bind_parameter_index(aStatement, name.get());
163 if (oneIdx == 0) {
164 nsAutoCString errMsg(key);
165 errMsg.AppendLiteral(" is not a valid named parameter.");
166 err = new Error(SQLITE_RANGE, errMsg.get());
167 break;
170 // XPCVariant's AddRef and Release are not thread-safe and so we must not
171 // do anything that would invoke them here on the async thread. As such we
172 // can't cram aValue into mParameters using ReplaceObjectAt so that
173 // we can freeload off of the BindingParams::Bind implementation.
174 int rc = variantToSQLiteT(BindingColumnData(aStatement, oneIdx - 1),
175 iter.UserData());
176 if (rc != SQLITE_OK) {
177 // We had an error while trying to bind. Now we need to create an error
178 // object with the right message. Note that we special case
179 // SQLITE_MISMATCH, but otherwise get the message from SQLite.
180 const char* msg = "Could not covert nsIVariant to SQLite type.";
181 if (rc != SQLITE_MISMATCH) {
182 msg = ::sqlite3_errmsg(::sqlite3_db_handle(aStatement));
184 err = new Error(rc, msg);
185 break;
189 return err.forget();
192 ///////////////////////////////////////////////////////////////////////////////
193 //// mozIStorageBindingParams
195 NS_IMETHODIMP
196 BindingParams::BindByName(const nsACString& aName, nsIVariant* aValue) {
197 NS_ENSURE_FALSE(mLocked, NS_ERROR_UNEXPECTED);
199 // Get the column index that we need to store this at.
200 uint32_t index;
201 nsresult rv = mOwningStatement->GetParameterIndex(aName, &index);
202 NS_ENSURE_SUCCESS(rv, rv);
204 return BindByIndex(index, aValue);
207 NS_IMETHODIMP
208 AsyncBindingParams::BindByName(const nsACString& aName, nsIVariant* aValue) {
209 NS_ENSURE_FALSE(mLocked, NS_ERROR_UNEXPECTED);
211 RefPtr<Variant_base> variant = convertVariantToStorageVariant(aValue);
212 if (!variant) return NS_ERROR_UNEXPECTED;
214 mNamedParameters.Put(aName, variant);
215 return NS_OK;
218 NS_IMETHODIMP
219 BindingParams::BindUTF8StringByName(const nsACString& aName,
220 const nsACString& aValue) {
221 nsCOMPtr<nsIVariant> value(new UTF8TextVariant(aValue));
222 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
224 return BindByName(aName, value);
227 NS_IMETHODIMP
228 BindingParams::BindStringByName(const nsACString& aName,
229 const nsAString& aValue) {
230 nsCOMPtr<nsIVariant> value(new TextVariant(aValue));
231 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
233 return BindByName(aName, value);
236 NS_IMETHODIMP
237 BindingParams::BindDoubleByName(const nsACString& aName, double aValue) {
238 nsCOMPtr<nsIVariant> value(new FloatVariant(aValue));
239 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
241 return BindByName(aName, value);
244 NS_IMETHODIMP
245 BindingParams::BindInt32ByName(const nsACString& aName, int32_t aValue) {
246 nsCOMPtr<nsIVariant> value(new IntegerVariant(aValue));
247 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
249 return BindByName(aName, value);
252 NS_IMETHODIMP
253 BindingParams::BindInt64ByName(const nsACString& aName, int64_t aValue) {
254 nsCOMPtr<nsIVariant> value(new IntegerVariant(aValue));
255 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
257 return BindByName(aName, value);
260 NS_IMETHODIMP
261 BindingParams::BindNullByName(const nsACString& aName) {
262 nsCOMPtr<nsIVariant> value(new NullVariant());
263 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
265 return BindByName(aName, value);
268 NS_IMETHODIMP
269 BindingParams::BindBlobByName(const nsACString& aName, const uint8_t* aValue,
270 uint32_t aValueSize) {
271 NS_ENSURE_ARG_MAX(aValueSize, INT_MAX);
272 std::pair<const void*, int> data(static_cast<const void*>(aValue),
273 int(aValueSize));
274 nsCOMPtr<nsIVariant> value(new BlobVariant(data));
275 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
277 return BindByName(aName, value);
280 NS_IMETHODIMP
281 BindingParams::BindBlobArrayByName(const nsACString& aName,
282 const nsTArray<uint8_t>& aValue) {
283 return BindBlobByName(aName, aValue.Elements(), aValue.Length());
286 NS_IMETHODIMP
287 BindingParams::BindStringAsBlobByName(const nsACString& aName,
288 const nsAString& aValue) {
289 return DoBindStringAsBlobByName(this, aName, aValue);
292 NS_IMETHODIMP
293 BindingParams::BindUTF8StringAsBlobByName(const nsACString& aName,
294 const nsACString& aValue) {
295 return DoBindStringAsBlobByName(this, aName, aValue);
298 NS_IMETHODIMP
299 BindingParams::BindAdoptedBlobByName(const nsACString& aName, uint8_t* aValue,
300 uint32_t aValueSize) {
301 UniqueFreePtr<uint8_t> uniqueValue(aValue);
302 NS_ENSURE_ARG_MAX(aValueSize, INT_MAX);
303 std::pair<uint8_t*, int> data(uniqueValue.release(), int(aValueSize));
304 nsCOMPtr<nsIVariant> value(new AdoptedBlobVariant(data));
306 return BindByName(aName, value);
309 NS_IMETHODIMP
310 BindingParams::BindByIndex(uint32_t aIndex, nsIVariant* aValue) {
311 NS_ENSURE_FALSE(mLocked, NS_ERROR_UNEXPECTED);
312 ENSURE_INDEX_VALUE(aIndex, mParamCount);
314 // Store the variant for later use.
315 RefPtr<Variant_base> variant = convertVariantToStorageVariant(aValue);
316 if (!variant) return NS_ERROR_UNEXPECTED;
317 if (mParameters.Length() <= aIndex) {
318 (void)mParameters.SetLength(aIndex);
319 (void)mParameters.AppendElement(variant);
320 } else {
321 NS_ENSURE_TRUE(mParameters.ReplaceElementAt(aIndex, variant),
322 NS_ERROR_OUT_OF_MEMORY);
324 return NS_OK;
327 NS_IMETHODIMP
328 AsyncBindingParams::BindByIndex(uint32_t aIndex, nsIVariant* aValue) {
329 NS_ENSURE_FALSE(mLocked, NS_ERROR_UNEXPECTED);
330 // In the asynchronous case we do not know how many parameters there are to
331 // bind to, so we cannot check the validity of aIndex.
333 RefPtr<Variant_base> variant = convertVariantToStorageVariant(aValue);
334 if (!variant) return NS_ERROR_UNEXPECTED;
335 if (mParameters.Length() <= aIndex) {
336 mParameters.SetLength(aIndex);
337 mParameters.AppendElement(variant);
338 } else {
339 NS_ENSURE_TRUE(mParameters.ReplaceElementAt(aIndex, variant),
340 NS_ERROR_OUT_OF_MEMORY);
342 return NS_OK;
345 NS_IMETHODIMP
346 BindingParams::BindUTF8StringByIndex(uint32_t aIndex,
347 const nsACString& aValue) {
348 nsCOMPtr<nsIVariant> value(new UTF8TextVariant(aValue));
349 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
351 return BindByIndex(aIndex, value);
354 NS_IMETHODIMP
355 BindingParams::BindStringByIndex(uint32_t aIndex, const nsAString& aValue) {
356 nsCOMPtr<nsIVariant> value(new TextVariant(aValue));
357 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
359 return BindByIndex(aIndex, value);
362 NS_IMETHODIMP
363 BindingParams::BindDoubleByIndex(uint32_t aIndex, double aValue) {
364 nsCOMPtr<nsIVariant> value(new FloatVariant(aValue));
365 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
367 return BindByIndex(aIndex, value);
370 NS_IMETHODIMP
371 BindingParams::BindInt32ByIndex(uint32_t aIndex, int32_t aValue) {
372 nsCOMPtr<nsIVariant> value(new IntegerVariant(aValue));
373 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
375 return BindByIndex(aIndex, value);
378 NS_IMETHODIMP
379 BindingParams::BindInt64ByIndex(uint32_t aIndex, int64_t aValue) {
380 nsCOMPtr<nsIVariant> value(new IntegerVariant(aValue));
381 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
383 return BindByIndex(aIndex, value);
386 NS_IMETHODIMP
387 BindingParams::BindNullByIndex(uint32_t aIndex) {
388 nsCOMPtr<nsIVariant> value(new NullVariant());
389 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
391 return BindByIndex(aIndex, value);
394 NS_IMETHODIMP
395 BindingParams::BindBlobByIndex(uint32_t aIndex, const uint8_t* aValue,
396 uint32_t aValueSize) {
397 NS_ENSURE_ARG_MAX(aValueSize, INT_MAX);
398 std::pair<const void*, int> data(static_cast<const void*>(aValue),
399 int(aValueSize));
400 nsCOMPtr<nsIVariant> value(new BlobVariant(data));
401 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
403 return BindByIndex(aIndex, value);
406 NS_IMETHODIMP
407 BindingParams::BindBlobArrayByIndex(uint32_t aIndex,
408 const nsTArray<uint8_t>& aValue) {
409 return BindBlobByIndex(aIndex, aValue.Elements(), aValue.Length());
412 NS_IMETHODIMP
413 BindingParams::BindStringAsBlobByIndex(uint32_t aIndex,
414 const nsAString& aValue) {
415 return DoBindStringAsBlobByIndex(this, aIndex, aValue);
418 NS_IMETHODIMP
419 BindingParams::BindUTF8StringAsBlobByIndex(uint32_t aIndex,
420 const nsACString& aValue) {
421 return DoBindStringAsBlobByIndex(this, aIndex, aValue);
424 NS_IMETHODIMP
425 BindingParams::BindAdoptedBlobByIndex(uint32_t aIndex, uint8_t* aValue,
426 uint32_t aValueSize) {
427 UniqueFreePtr<uint8_t> uniqueValue(aValue);
428 NS_ENSURE_ARG_MAX(aValueSize, INT_MAX);
429 std::pair<uint8_t*, int> data(uniqueValue.release(), int(aValueSize));
430 nsCOMPtr<nsIVariant> value(new AdoptedBlobVariant(data));
432 return BindByIndex(aIndex, value);
435 } // namespace storage
436 } // namespace mozilla