Bug 1472338: part 1) Add Chrome tests for the async Clipboard API. r=NeilDeakin
[gecko.git] / storage / mozStorageBindingParams.cpp
blobbf5198beb4b0d01439895d6be4d8a0a343b2d1fb
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::storage {
20 ////////////////////////////////////////////////////////////////////////////////
21 //// Local Helper Objects
23 namespace {
25 struct BindingColumnData {
26 BindingColumnData(sqlite3_stmt* aStmt, int aColumn)
27 : stmt(aStmt), column(aColumn) {}
28 sqlite3_stmt* stmt;
29 int column;
32 ////////////////////////////////////////////////////////////////////////////////
33 //// Variant Specialization Functions (variantToSQLiteT)
35 int sqlite3_T_int(BindingColumnData aData, int aValue) {
36 return ::sqlite3_bind_int(aData.stmt, aData.column + 1, aValue);
39 int sqlite3_T_int64(BindingColumnData aData, sqlite3_int64 aValue) {
40 return ::sqlite3_bind_int64(aData.stmt, aData.column + 1, aValue);
43 int sqlite3_T_double(BindingColumnData aData, double aValue) {
44 return ::sqlite3_bind_double(aData.stmt, aData.column + 1, aValue);
47 int sqlite3_T_text(BindingColumnData aData, const nsCString& aValue) {
48 return ::sqlite3_bind_text(aData.stmt, aData.column + 1, aValue.get(),
49 aValue.Length(), SQLITE_TRANSIENT);
52 int sqlite3_T_text16(BindingColumnData aData, const nsString& aValue) {
53 return ::sqlite3_bind_text16(
54 aData.stmt, aData.column + 1, aValue.get(),
55 aValue.Length() * sizeof(char16_t), // Length in bytes!
56 SQLITE_TRANSIENT);
59 int sqlite3_T_null(BindingColumnData aData) {
60 return ::sqlite3_bind_null(aData.stmt, aData.column + 1);
63 int sqlite3_T_blob(BindingColumnData aData, const void* aBlob, int aSize) {
64 return ::sqlite3_bind_blob(aData.stmt, aData.column + 1, aBlob, aSize, free);
67 #include "variantToSQLiteT_impl.h"
69 } // namespace
71 ////////////////////////////////////////////////////////////////////////////////
72 //// BindingParams
74 BindingParams::BindingParams(mozIStorageBindingParamsArray* aOwningArray,
75 Statement* aOwningStatement)
76 : mLocked(false),
77 mOwningArray(aOwningArray),
78 mOwningStatement(aOwningStatement),
79 mParamCount(0) {
80 (void)mOwningStatement->GetParameterCount(&mParamCount);
81 mParameters.SetCapacity(mParamCount);
84 BindingParams::BindingParams(mozIStorageBindingParamsArray* aOwningArray)
85 : mLocked(false),
86 mOwningArray(aOwningArray),
87 mOwningStatement(nullptr),
88 mParamCount(0) {}
90 AsyncBindingParams::AsyncBindingParams(
91 mozIStorageBindingParamsArray* aOwningArray)
92 : BindingParams(aOwningArray) {}
94 void BindingParams::lock() {
95 NS_ASSERTION(mLocked == false, "Parameters have already been locked!");
96 mLocked = true;
98 // We no longer need to hold a reference to our statement or our owning array.
99 // The array owns us at this point, and it will own a reference to the
100 // statement.
101 mOwningStatement = nullptr;
102 mOwningArray = nullptr;
105 void BindingParams::unlock(Statement* aOwningStatement) {
106 NS_ASSERTION(mLocked == true, "Parameters were not yet locked!");
107 mLocked = false;
108 mOwningStatement = aOwningStatement;
111 const mozIStorageBindingParamsArray* BindingParams::getOwner() const {
112 return mOwningArray;
115 ////////////////////////////////////////////////////////////////////////////////
116 //// nsISupports
118 NS_IMPL_ISUPPORTS(BindingParams, mozIStorageBindingParams,
119 IStorageBindingParamsInternal)
121 ////////////////////////////////////////////////////////////////////////////////
122 //// IStorageBindingParamsInternal
124 already_AddRefed<mozIStorageError> BindingParams::bind(
125 sqlite3_stmt* aStatement) {
126 // Iterate through all of our stored data, and bind it.
127 for (size_t i = 0; i < mParameters.Length(); i++) {
128 int rc = variantToSQLiteT(BindingColumnData(aStatement, i), mParameters[i]);
129 if (rc != SQLITE_OK) {
130 // We had an error while trying to bind. Now we need to create an error
131 // object with the right message. Note that we special case
132 // SQLITE_MISMATCH, but otherwise get the message from SQLite.
133 const char* msg = "Could not covert nsIVariant to SQLite type.";
134 if (rc != SQLITE_MISMATCH)
135 msg = ::sqlite3_errmsg(::sqlite3_db_handle(aStatement));
137 nsCOMPtr<mozIStorageError> err(new Error(rc, msg));
138 return err.forget();
142 return nullptr;
145 already_AddRefed<mozIStorageError> AsyncBindingParams::bind(
146 sqlite3_stmt* aStatement) {
147 // We should bind by index using the super-class if there is nothing in our
148 // hashtable.
149 if (!mNamedParameters.Count()) return BindingParams::bind(aStatement);
151 nsCOMPtr<mozIStorageError> err;
153 for (const auto& entry : mNamedParameters) {
154 const nsACString& key = entry.GetKey();
156 // We do not accept any forms of names other than ":name", but we need to
157 // add the colon for SQLite.
158 nsAutoCString name(":");
159 name.Append(key);
160 int oneIdx = ::sqlite3_bind_parameter_index(aStatement, name.get());
162 if (oneIdx == 0) {
163 nsAutoCString errMsg(key);
164 errMsg.AppendLiteral(" is not a valid named parameter.");
165 err = new Error(SQLITE_RANGE, errMsg.get());
166 break;
169 // XPCVariant's AddRef and Release are not thread-safe and so we must not
170 // do anything that would invoke them here on the async thread. As such we
171 // can't cram aValue into mParameters using ReplaceObjectAt so that
172 // we can freeload off of the BindingParams::Bind implementation.
173 int rc = variantToSQLiteT(BindingColumnData(aStatement, oneIdx - 1),
174 entry.GetWeak());
175 if (rc != SQLITE_OK) {
176 // We had an error while trying to bind. Now we need to create an error
177 // object with the right message. Note that we special case
178 // SQLITE_MISMATCH, but otherwise get the message from SQLite.
179 const char* msg = "Could not covert nsIVariant to SQLite type.";
180 if (rc != SQLITE_MISMATCH) {
181 msg = ::sqlite3_errmsg(::sqlite3_db_handle(aStatement));
183 err = new Error(rc, msg);
184 break;
188 return err.forget();
191 ///////////////////////////////////////////////////////////////////////////////
192 //// mozIStorageBindingParams
194 NS_IMETHODIMP
195 BindingParams::BindByName(const nsACString& aName, nsIVariant* aValue) {
196 NS_ENSURE_FALSE(mLocked, NS_ERROR_UNEXPECTED);
198 // Get the column index that we need to store this at.
199 uint32_t index;
200 nsresult rv = mOwningStatement->GetParameterIndex(aName, &index);
201 NS_ENSURE_SUCCESS(rv, rv);
203 return BindByIndex(index, aValue);
206 NS_IMETHODIMP
207 AsyncBindingParams::BindByName(const nsACString& aName, nsIVariant* aValue) {
208 NS_ENSURE_FALSE(mLocked, NS_ERROR_UNEXPECTED);
210 RefPtr<Variant_base> variant = convertVariantToStorageVariant(aValue);
211 if (!variant) return NS_ERROR_UNEXPECTED;
213 mNamedParameters.InsertOrUpdate(aName, nsCOMPtr<nsIVariant>{variant});
214 return NS_OK;
217 NS_IMETHODIMP
218 BindingParams::BindUTF8StringByName(const nsACString& aName,
219 const nsACString& aValue) {
220 nsCOMPtr<nsIVariant> value(new UTF8TextVariant(aValue));
221 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
223 return BindByName(aName, value);
226 NS_IMETHODIMP
227 BindingParams::BindStringByName(const nsACString& aName,
228 const nsAString& aValue) {
229 nsCOMPtr<nsIVariant> value(new TextVariant(aValue));
230 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
232 return BindByName(aName, value);
235 NS_IMETHODIMP
236 BindingParams::BindDoubleByName(const nsACString& aName, double aValue) {
237 nsCOMPtr<nsIVariant> value(new FloatVariant(aValue));
238 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
240 return BindByName(aName, value);
243 NS_IMETHODIMP
244 BindingParams::BindInt32ByName(const nsACString& aName, int32_t aValue) {
245 nsCOMPtr<nsIVariant> value(new IntegerVariant(aValue));
246 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
248 return BindByName(aName, value);
251 NS_IMETHODIMP
252 BindingParams::BindInt64ByName(const nsACString& aName, int64_t aValue) {
253 nsCOMPtr<nsIVariant> value(new IntegerVariant(aValue));
254 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
256 return BindByName(aName, value);
259 NS_IMETHODIMP
260 BindingParams::BindNullByName(const nsACString& aName) {
261 nsCOMPtr<nsIVariant> value(new NullVariant());
262 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
264 return BindByName(aName, value);
267 NS_IMETHODIMP
268 BindingParams::BindBlobByName(const nsACString& aName, const uint8_t* aValue,
269 uint32_t aValueSize) {
270 NS_ENSURE_ARG_MAX(aValueSize, INT_MAX);
271 std::pair<const void*, int> data(static_cast<const void*>(aValue),
272 int(aValueSize));
273 nsCOMPtr<nsIVariant> value(new BlobVariant(data));
274 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
276 return BindByName(aName, value);
279 NS_IMETHODIMP
280 BindingParams::BindBlobArrayByName(const nsACString& aName,
281 const nsTArray<uint8_t>& aValue) {
282 return BindBlobByName(aName, aValue.Elements(), aValue.Length());
285 NS_IMETHODIMP
286 BindingParams::BindStringAsBlobByName(const nsACString& aName,
287 const nsAString& aValue) {
288 return DoBindStringAsBlobByName(this, aName, aValue);
291 NS_IMETHODIMP
292 BindingParams::BindUTF8StringAsBlobByName(const nsACString& aName,
293 const nsACString& aValue) {
294 return DoBindStringAsBlobByName(this, aName, aValue);
297 NS_IMETHODIMP
298 BindingParams::BindAdoptedBlobByName(const nsACString& aName, uint8_t* aValue,
299 uint32_t aValueSize) {
300 UniqueFreePtr<uint8_t> uniqueValue(aValue);
301 NS_ENSURE_ARG_MAX(aValueSize, INT_MAX);
302 std::pair<uint8_t*, int> data(uniqueValue.release(), int(aValueSize));
303 nsCOMPtr<nsIVariant> value(new AdoptedBlobVariant(data));
305 return BindByName(aName, value);
308 NS_IMETHODIMP
309 BindingParams::BindByIndex(uint32_t aIndex, nsIVariant* aValue) {
310 NS_ENSURE_FALSE(mLocked, NS_ERROR_UNEXPECTED);
311 ENSURE_INDEX_VALUE(aIndex, mParamCount);
313 // Store the variant for later use.
314 RefPtr<Variant_base> variant = convertVariantToStorageVariant(aValue);
315 if (!variant) return NS_ERROR_UNEXPECTED;
316 if (mParameters.Length() <= aIndex) {
317 (void)mParameters.SetLength(aIndex);
318 (void)mParameters.AppendElement(variant);
319 } else {
320 mParameters.ReplaceElementAt(aIndex, variant);
322 return NS_OK;
325 NS_IMETHODIMP
326 AsyncBindingParams::BindByIndex(uint32_t aIndex, nsIVariant* aValue) {
327 NS_ENSURE_FALSE(mLocked, NS_ERROR_UNEXPECTED);
328 // In the asynchronous case we do not know how many parameters there are to
329 // bind to, so we cannot check the validity of aIndex.
331 RefPtr<Variant_base> variant = convertVariantToStorageVariant(aValue);
332 if (!variant) return NS_ERROR_UNEXPECTED;
333 if (mParameters.Length() <= aIndex) {
334 mParameters.SetLength(aIndex);
335 mParameters.AppendElement(variant);
336 } else {
337 mParameters.ReplaceElementAt(aIndex, variant);
339 return NS_OK;
342 NS_IMETHODIMP
343 BindingParams::BindUTF8StringByIndex(uint32_t aIndex,
344 const nsACString& aValue) {
345 nsCOMPtr<nsIVariant> value(new UTF8TextVariant(aValue));
346 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
348 return BindByIndex(aIndex, value);
351 NS_IMETHODIMP
352 BindingParams::BindStringByIndex(uint32_t aIndex, const nsAString& aValue) {
353 nsCOMPtr<nsIVariant> value(new TextVariant(aValue));
354 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
356 return BindByIndex(aIndex, value);
359 NS_IMETHODIMP
360 BindingParams::BindDoubleByIndex(uint32_t aIndex, double aValue) {
361 nsCOMPtr<nsIVariant> value(new FloatVariant(aValue));
362 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
364 return BindByIndex(aIndex, value);
367 NS_IMETHODIMP
368 BindingParams::BindInt32ByIndex(uint32_t aIndex, int32_t aValue) {
369 nsCOMPtr<nsIVariant> value(new IntegerVariant(aValue));
370 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
372 return BindByIndex(aIndex, value);
375 NS_IMETHODIMP
376 BindingParams::BindInt64ByIndex(uint32_t aIndex, int64_t aValue) {
377 nsCOMPtr<nsIVariant> value(new IntegerVariant(aValue));
378 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
380 return BindByIndex(aIndex, value);
383 NS_IMETHODIMP
384 BindingParams::BindNullByIndex(uint32_t aIndex) {
385 nsCOMPtr<nsIVariant> value(new NullVariant());
386 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
388 return BindByIndex(aIndex, value);
391 NS_IMETHODIMP
392 BindingParams::BindBlobByIndex(uint32_t aIndex, const uint8_t* aValue,
393 uint32_t aValueSize) {
394 NS_ENSURE_ARG_MAX(aValueSize, INT_MAX);
395 std::pair<const void*, int> data(static_cast<const void*>(aValue),
396 int(aValueSize));
397 nsCOMPtr<nsIVariant> value(new BlobVariant(data));
398 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
400 return BindByIndex(aIndex, value);
403 NS_IMETHODIMP
404 BindingParams::BindBlobArrayByIndex(uint32_t aIndex,
405 const nsTArray<uint8_t>& aValue) {
406 return BindBlobByIndex(aIndex, aValue.Elements(), aValue.Length());
409 NS_IMETHODIMP
410 BindingParams::BindStringAsBlobByIndex(uint32_t aIndex,
411 const nsAString& aValue) {
412 return DoBindStringAsBlobByIndex(this, aIndex, aValue);
415 NS_IMETHODIMP
416 BindingParams::BindUTF8StringAsBlobByIndex(uint32_t aIndex,
417 const nsACString& aValue) {
418 return DoBindStringAsBlobByIndex(this, aIndex, aValue);
421 NS_IMETHODIMP
422 BindingParams::BindAdoptedBlobByIndex(uint32_t aIndex, uint8_t* aValue,
423 uint32_t aValueSize) {
424 UniqueFreePtr<uint8_t> uniqueValue(aValue);
425 NS_ENSURE_ARG_MAX(aValueSize, INT_MAX);
426 std::pair<uint8_t*, int> data(uniqueValue.release(), int(aValueSize));
427 nsCOMPtr<nsIVariant> value(new AdoptedBlobVariant(data));
429 return BindByIndex(aIndex, value);
432 } // namespace mozilla::storage