Bug 1918529 - fix some subpixel misalignment issues with gfx.webrender.svg-filter...
[gecko.git] / storage / mozStorageBindingParams.cpp
blob55ce40de3e6c33e1443067697105be9c6629cd3e
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 "Variant.h"
16 #include "sqlite3_static_ext.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 int sqlite3_T_array(BindingColumnData aData, void* aArray, int aSize,
68 int aType) {
69 // In debug builds ensure that the statement includes at least one `carray()`.
70 MOZ_ASSERT(
71 ::strstr(::sqlite3_sql(aData.stmt), "carray("),
72 "Binding arrays to SQL statements requires using the carray() function.");
74 if (aType == CARRAY_TEXT) {
75 // We don't manage the string buffers lifecycle, thus let SQLite make its
76 // own copy.
77 int srv = ::sqlite3_carray_bind(aData.stmt, aData.column + 1, aArray, aSize,
78 aType, SQLITE_TRANSIENT);
79 free(aArray);
80 return srv;
82 return ::sqlite3_carray_bind(aData.stmt, aData.column + 1, aArray, aSize,
83 aType, free);
86 #include "variantToSQLiteT_impl.h"
88 } // namespace
90 ////////////////////////////////////////////////////////////////////////////////
91 //// BindingParams
93 BindingParams::BindingParams(mozIStorageBindingParamsArray* aOwningArray,
94 Statement* aOwningStatement)
95 : mLocked(false),
96 mOwningArray(aOwningArray),
97 mOwningStatement(aOwningStatement),
98 mParamCount(0) {
99 (void)mOwningStatement->GetParameterCount(&mParamCount);
100 mParameters.SetCapacity(mParamCount);
103 BindingParams::BindingParams(mozIStorageBindingParamsArray* aOwningArray)
104 : mLocked(false),
105 mOwningArray(aOwningArray),
106 mOwningStatement(nullptr),
107 mParamCount(0) {}
109 AsyncBindingParams::AsyncBindingParams(
110 mozIStorageBindingParamsArray* aOwningArray)
111 : BindingParams(aOwningArray) {}
113 void BindingParams::lock() {
114 NS_ASSERTION(mLocked == false, "Parameters have already been locked!");
115 mLocked = true;
117 // We no longer need to hold a reference to our statement or our owning array.
118 // The array owns us at this point, and it will own a reference to the
119 // statement.
120 mOwningStatement = nullptr;
121 mOwningArray = nullptr;
124 void BindingParams::unlock(Statement* aOwningStatement) {
125 NS_ASSERTION(mLocked == true, "Parameters were not yet locked!");
126 mLocked = false;
127 mOwningStatement = aOwningStatement;
130 const mozIStorageBindingParamsArray* BindingParams::getOwner() const {
131 return mOwningArray;
134 ////////////////////////////////////////////////////////////////////////////////
135 //// nsISupports
137 NS_IMPL_ISUPPORTS(BindingParams, mozIStorageBindingParams,
138 IStorageBindingParamsInternal)
140 ////////////////////////////////////////////////////////////////////////////////
141 //// IStorageBindingParamsInternal
143 already_AddRefed<mozIStorageError> BindingParams::bind(
144 sqlite3_stmt* aStatement) {
145 // Iterate through all of our stored data, and bind it.
146 for (size_t i = 0; i < mParameters.Length(); i++) {
147 int rc = variantToSQLiteT(BindingColumnData(aStatement, i), mParameters[i]);
148 if (rc != SQLITE_OK) {
149 // We had an error while trying to bind. Now we need to create an error
150 // object with the right message. Note that we special case
151 // SQLITE_MISMATCH, but otherwise get the message from SQLite.
152 const char* msg = "Could not covert nsIVariant to SQLite type.";
153 if (rc != SQLITE_MISMATCH) {
154 msg = ::sqlite3_errmsg(::sqlite3_db_handle(aStatement));
157 nsCOMPtr<mozIStorageError> err(new Error(rc, msg));
158 return err.forget();
162 return nullptr;
165 already_AddRefed<mozIStorageError> AsyncBindingParams::bind(
166 sqlite3_stmt* aStatement) {
167 nsCOMPtr<mozIStorageError> err;
169 for (const auto& entry : mNamedParameters) {
170 const nsACString& key = entry.GetKey();
172 // We do not accept any forms of names other than ":name", but we need to
173 // add the colon for SQLite.
174 nsAutoCString name(":");
175 name.Append(key);
176 int oneIdx = ::sqlite3_bind_parameter_index(aStatement, name.get());
178 if (oneIdx == 0) {
179 nsAutoCString errMsg(key);
180 errMsg.AppendLiteral(" is not a valid named parameter.");
181 err = new Error(SQLITE_RANGE, errMsg.get());
182 return err.forget();
185 if (mParameters.Length() <= static_cast<uint32_t>(oneIdx - 1)) {
186 mParameters.SetLength(oneIdx - 1);
187 mParameters.AppendElement(entry.GetWeak());
188 } else {
189 mParameters.ReplaceElementAt(oneIdx - 1, entry.GetWeak());
193 // Now bind using the super class.
194 return BindingParams::bind(aStatement);
197 ///////////////////////////////////////////////////////////////////////////////
198 //// mozIStorageBindingParams
200 NS_IMETHODIMP
201 BindingParams::BindByName(const nsACString& aName, nsIVariant* aValue) {
202 NS_ENSURE_FALSE(mLocked, NS_ERROR_UNEXPECTED);
204 // Get the column index that we need to store this at.
205 uint32_t index;
206 nsresult rv = mOwningStatement->GetParameterIndex(aName, &index);
207 NS_ENSURE_SUCCESS(rv, rv);
209 return BindByIndex(index, aValue);
212 NS_IMETHODIMP
213 AsyncBindingParams::BindByName(const nsACString& aName, nsIVariant* aValue) {
214 NS_ENSURE_FALSE(mLocked, NS_ERROR_UNEXPECTED);
216 RefPtr<Variant_base> variant = convertVariantToStorageVariant(aValue);
217 if (!variant) return NS_ERROR_UNEXPECTED;
218 mNamedParameters.InsertOrUpdate(aName, std::move(variant));
219 return NS_OK;
222 NS_IMETHODIMP
223 BindingParams::BindUTF8StringByName(const nsACString& aName,
224 const nsACString& aValue) {
225 nsCOMPtr<nsIVariant> value(new UTF8TextVariant(aValue));
226 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
228 return BindByName(aName, value);
231 NS_IMETHODIMP
232 BindingParams::BindStringByName(const nsACString& aName,
233 const nsAString& aValue) {
234 nsCOMPtr<nsIVariant> value(new TextVariant(aValue));
235 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
237 return BindByName(aName, value);
240 NS_IMETHODIMP
241 BindingParams::BindDoubleByName(const nsACString& aName, double aValue) {
242 nsCOMPtr<nsIVariant> value(new FloatVariant(aValue));
243 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
245 return BindByName(aName, value);
248 NS_IMETHODIMP
249 BindingParams::BindInt32ByName(const nsACString& aName, int32_t aValue) {
250 nsCOMPtr<nsIVariant> value(new IntegerVariant(aValue));
251 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
253 return BindByName(aName, value);
256 NS_IMETHODIMP
257 BindingParams::BindInt64ByName(const nsACString& aName, int64_t aValue) {
258 nsCOMPtr<nsIVariant> value(new IntegerVariant(aValue));
259 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
261 return BindByName(aName, value);
264 NS_IMETHODIMP
265 BindingParams::BindNullByName(const nsACString& aName) {
266 nsCOMPtr<nsIVariant> value(new NullVariant());
267 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
269 return BindByName(aName, value);
272 NS_IMETHODIMP
273 BindingParams::BindBlobByName(const nsACString& aName, const uint8_t* aValue,
274 uint32_t aValueSize) {
275 NS_ENSURE_ARG_MAX(aValueSize, INT_MAX);
276 std::pair<const void*, int> data(static_cast<const void*>(aValue),
277 int(aValueSize));
278 nsCOMPtr<nsIVariant> value(new BlobVariant(data));
279 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
281 return BindByName(aName, value);
284 NS_IMETHODIMP
285 BindingParams::BindBlobArrayByName(const nsACString& aName,
286 const nsTArray<uint8_t>& aValue) {
287 return BindBlobByName(aName, aValue.Elements(), aValue.Length());
290 NS_IMETHODIMP
291 BindingParams::BindStringAsBlobByName(const nsACString& aName,
292 const nsAString& aValue) {
293 return DoBindStringAsBlobByName(this, aName, aValue);
296 NS_IMETHODIMP
297 BindingParams::BindUTF8StringAsBlobByName(const nsACString& aName,
298 const nsACString& aValue) {
299 return DoBindStringAsBlobByName(this, aName, aValue);
302 NS_IMETHODIMP
303 BindingParams::BindAdoptedBlobByName(const nsACString& aName, uint8_t* aValue,
304 uint32_t aValueSize) {
305 UniqueFreePtr<uint8_t> uniqueValue(aValue);
306 NS_ENSURE_ARG_MAX(aValueSize, INT_MAX);
307 std::pair<uint8_t*, int> data(uniqueValue.release(), int(aValueSize));
308 nsCOMPtr<nsIVariant> value(new AdoptedBlobVariant(data));
310 return BindByName(aName, value);
313 NS_IMETHODIMP
314 BindingParams::BindArrayOfIntegersByName(const nsACString& aName,
315 const nsTArray<int64_t>& aValue) {
316 NS_ENSURE_ARG_MAX(aValue.Length(), INT_MAX);
317 std::pair<const void*, int> data(static_cast<const void*>(aValue.Elements()),
318 int(aValue.Length()));
319 nsCOMPtr<nsIVariant> value(new ArrayOfIntegersVariant(data));
320 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
322 return BindByName(aName, value);
325 NS_IMETHODIMP
326 BindingParams::BindArrayOfDoublesByName(const nsACString& aName,
327 const nsTArray<double>& aValue) {
328 NS_ENSURE_ARG_MAX(aValue.Length(), INT_MAX);
329 std::pair<const void*, int> data(static_cast<const void*>(aValue.Elements()),
330 int(aValue.Length()));
331 nsCOMPtr<nsIVariant> value(new ArrayOfDoublesVariant(data));
332 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
334 return BindByName(aName, value);
337 NS_IMETHODIMP
338 BindingParams::BindArrayOfStringsByName(const nsACString& aName,
339 const nsTArray<nsString>& aValue) {
340 NS_ENSURE_ARG_MAX(aValue.Length(), INT_MAX);
341 nsTArray<nsCString> UTF8Strings(aValue.Length());
342 for (const nsString& str : aValue) {
343 UTF8Strings.AppendElement(NS_ConvertUTF16toUTF8(str));
345 std::pair<const void*, int> data(
346 static_cast<const void*>(UTF8Strings.Elements()),
347 int(UTF8Strings.Length()));
348 // The variant will make a copy of all the buffers.
349 nsCOMPtr<nsIVariant> value(new ArrayOfUTF8StringsVariant(data));
350 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
352 return BindByName(aName, value);
355 NS_IMETHODIMP
356 BindingParams::BindArrayOfUTF8StringsByName(const nsACString& aName,
357 const nsTArray<nsCString>& aValue) {
358 NS_ENSURE_ARG_MAX(aValue.Length(), INT_MAX);
359 std::pair<const void*, int> data(static_cast<const void*>(aValue.Elements()),
360 int(aValue.Length()));
361 // The variant will make a copy of all the buffers.
362 nsCOMPtr<nsIVariant> value(new ArrayOfUTF8StringsVariant(data));
363 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
365 return BindByName(aName, value);
368 NS_IMETHODIMP
369 BindingParams::BindByIndex(uint32_t aIndex, nsIVariant* aValue) {
370 NS_ENSURE_FALSE(mLocked, NS_ERROR_UNEXPECTED);
371 ENSURE_INDEX_VALUE(aIndex, mParamCount);
373 // Store the variant for later use.
374 RefPtr<Variant_base> variant = convertVariantToStorageVariant(aValue);
375 if (!variant) return NS_ERROR_UNEXPECTED;
376 if (mParameters.Length() <= aIndex) {
377 (void)mParameters.SetLength(aIndex);
378 (void)mParameters.AppendElement(variant);
379 } else {
380 mParameters.ReplaceElementAt(aIndex, variant);
382 return NS_OK;
385 NS_IMETHODIMP
386 AsyncBindingParams::BindByIndex(uint32_t aIndex, nsIVariant* aValue) {
387 NS_ENSURE_FALSE(mLocked, NS_ERROR_UNEXPECTED);
388 // In the asynchronous case we do not know how many parameters there are to
389 // bind to, so we cannot check the validity of aIndex.
391 RefPtr<Variant_base> variant = convertVariantToStorageVariant(aValue);
392 if (!variant) return NS_ERROR_UNEXPECTED;
393 if (mParameters.Length() <= aIndex) {
394 mParameters.SetLength(aIndex);
395 mParameters.AppendElement(variant);
396 } else {
397 mParameters.ReplaceElementAt(aIndex, variant);
399 return NS_OK;
402 NS_IMETHODIMP
403 BindingParams::BindUTF8StringByIndex(uint32_t aIndex,
404 const nsACString& aValue) {
405 nsCOMPtr<nsIVariant> value(new UTF8TextVariant(aValue));
406 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
408 return BindByIndex(aIndex, value);
411 NS_IMETHODIMP
412 BindingParams::BindStringByIndex(uint32_t aIndex, const nsAString& aValue) {
413 nsCOMPtr<nsIVariant> value(new TextVariant(aValue));
414 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
416 return BindByIndex(aIndex, value);
419 NS_IMETHODIMP
420 BindingParams::BindDoubleByIndex(uint32_t aIndex, double aValue) {
421 nsCOMPtr<nsIVariant> value(new FloatVariant(aValue));
422 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
424 return BindByIndex(aIndex, value);
427 NS_IMETHODIMP
428 BindingParams::BindInt32ByIndex(uint32_t aIndex, int32_t aValue) {
429 nsCOMPtr<nsIVariant> value(new IntegerVariant(aValue));
430 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
432 return BindByIndex(aIndex, value);
435 NS_IMETHODIMP
436 BindingParams::BindInt64ByIndex(uint32_t aIndex, int64_t aValue) {
437 nsCOMPtr<nsIVariant> value(new IntegerVariant(aValue));
438 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
440 return BindByIndex(aIndex, value);
443 NS_IMETHODIMP
444 BindingParams::BindNullByIndex(uint32_t aIndex) {
445 nsCOMPtr<nsIVariant> value(new NullVariant());
446 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
448 return BindByIndex(aIndex, value);
451 NS_IMETHODIMP
452 BindingParams::BindBlobByIndex(uint32_t aIndex, const uint8_t* aValue,
453 uint32_t aValueSize) {
454 NS_ENSURE_ARG_MAX(aValueSize, INT_MAX);
455 std::pair<const void*, int> data(static_cast<const void*>(aValue),
456 int(aValueSize));
457 nsCOMPtr<nsIVariant> value(new BlobVariant(data));
458 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
460 return BindByIndex(aIndex, value);
463 NS_IMETHODIMP
464 BindingParams::BindBlobArrayByIndex(uint32_t aIndex,
465 const nsTArray<uint8_t>& aValue) {
466 return BindBlobByIndex(aIndex, aValue.Elements(), aValue.Length());
469 NS_IMETHODIMP
470 BindingParams::BindStringAsBlobByIndex(uint32_t aIndex,
471 const nsAString& aValue) {
472 return DoBindStringAsBlobByIndex(this, aIndex, aValue);
475 NS_IMETHODIMP
476 BindingParams::BindUTF8StringAsBlobByIndex(uint32_t aIndex,
477 const nsACString& aValue) {
478 return DoBindStringAsBlobByIndex(this, aIndex, aValue);
481 NS_IMETHODIMP
482 BindingParams::BindAdoptedBlobByIndex(uint32_t aIndex, uint8_t* aValue,
483 uint32_t aValueSize) {
484 UniqueFreePtr<uint8_t> uniqueValue(aValue);
485 NS_ENSURE_ARG_MAX(aValueSize, INT_MAX);
486 std::pair<uint8_t*, int> data(uniqueValue.release(), int(aValueSize));
487 nsCOMPtr<nsIVariant> value(new AdoptedBlobVariant(data));
489 return BindByIndex(aIndex, value);
492 NS_IMETHODIMP
493 BindingParams::BindArrayOfIntegersByIndex(uint32_t aIndex,
494 const nsTArray<int64_t>& aValue) {
495 NS_ENSURE_ARG_MAX(aValue.Length(), INT_MAX);
496 std::pair<const void*, int> data(static_cast<const void*>(aValue.Elements()),
497 int(aValue.Length()));
498 nsCOMPtr<nsIVariant> value(new ArrayOfIntegersVariant(data));
499 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
501 return BindByIndex(aIndex, value);
504 NS_IMETHODIMP
505 BindingParams::BindArrayOfDoublesByIndex(uint32_t aIndex,
506 const nsTArray<double>& aValue) {
507 NS_ENSURE_ARG_MAX(aValue.Length(), INT_MAX);
508 std::pair<const void*, int> data(static_cast<const void*>(aValue.Elements()),
509 int(aValue.Length()));
510 nsCOMPtr<nsIVariant> value(new ArrayOfDoublesVariant(data));
511 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
513 return BindByIndex(aIndex, value);
516 NS_IMETHODIMP
517 BindingParams::BindArrayOfStringsByIndex(uint32_t aIndex,
518 const nsTArray<nsString>& aValue) {
519 NS_ENSURE_ARG_MAX(aValue.Length(), INT_MAX);
520 nsTArray<nsCString> UTF8Strings(aValue.Length());
521 for (const nsString& str : aValue) {
522 UTF8Strings.AppendElement(NS_ConvertUTF16toUTF8(str).get());
524 std::pair<const void*, int> data(
525 static_cast<const void*>(UTF8Strings.Elements()),
526 int(UTF8Strings.Length()));
527 // The variant will make a copy of all the buffers.
528 nsCOMPtr<nsIVariant> value(new ArrayOfUTF8StringsVariant(data));
529 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
531 return BindByIndex(aIndex, value);
534 NS_IMETHODIMP
535 BindingParams::BindArrayOfUTF8StringsByIndex(
536 uint32_t aIndex, const nsTArray<nsCString>& aValue) {
537 NS_ENSURE_ARG_MAX(aValue.Length(), INT_MAX);
538 std::pair<const void*, int> data(static_cast<const void*>(aValue.Elements()),
539 int(aValue.Length()));
540 // The variant will make a copy of all the buffers.
541 nsCOMPtr<nsIVariant> value(new ArrayOfUTF8StringsVariant(data));
542 NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
544 return BindByIndex(aIndex, value);
547 } // namespace mozilla::storage