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/. */
9 #include "mozilla/UniquePtrExtensions.h"
12 #include "mozStorageError.h"
13 #include "mozStoragePrivateHelpers.h"
14 #include "mozStorageBindingParams.h"
16 #include "sqlite3_static_ext.h"
18 namespace mozilla::storage
{
20 ////////////////////////////////////////////////////////////////////////////////
21 //// Local Helper Objects
25 struct BindingColumnData
{
26 BindingColumnData(sqlite3_stmt
* aStmt
, int aColumn
)
27 : stmt(aStmt
), column(aColumn
) {}
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!
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
,
69 // In debug builds ensure that the statement includes at least one `carray()`.
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
77 int srv
= ::sqlite3_carray_bind(aData
.stmt
, aData
.column
+ 1, aArray
, aSize
,
78 aType
, SQLITE_TRANSIENT
);
82 return ::sqlite3_carray_bind(aData
.stmt
, aData
.column
+ 1, aArray
, aSize
,
86 #include "variantToSQLiteT_impl.h"
90 ////////////////////////////////////////////////////////////////////////////////
93 BindingParams::BindingParams(mozIStorageBindingParamsArray
* aOwningArray
,
94 Statement
* aOwningStatement
)
96 mOwningArray(aOwningArray
),
97 mOwningStatement(aOwningStatement
),
99 (void)mOwningStatement
->GetParameterCount(&mParamCount
);
100 mParameters
.SetCapacity(mParamCount
);
103 BindingParams::BindingParams(mozIStorageBindingParamsArray
* aOwningArray
)
105 mOwningArray(aOwningArray
),
106 mOwningStatement(nullptr),
109 AsyncBindingParams::AsyncBindingParams(
110 mozIStorageBindingParamsArray
* aOwningArray
)
111 : BindingParams(aOwningArray
) {}
113 void BindingParams::lock() {
114 NS_ASSERTION(mLocked
== false, "Parameters have already been locked!");
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
120 mOwningStatement
= nullptr;
121 mOwningArray
= nullptr;
124 void BindingParams::unlock(Statement
* aOwningStatement
) {
125 NS_ASSERTION(mLocked
== true, "Parameters were not yet locked!");
127 mOwningStatement
= aOwningStatement
;
130 const mozIStorageBindingParamsArray
* BindingParams::getOwner() const {
134 ////////////////////////////////////////////////////////////////////////////////
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
));
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(":");
176 int oneIdx
= ::sqlite3_bind_parameter_index(aStatement
, name
.get());
179 nsAutoCString
errMsg(key
);
180 errMsg
.AppendLiteral(" is not a valid named parameter.");
181 err
= new Error(SQLITE_RANGE
, errMsg
.get());
185 if (mParameters
.Length() <= static_cast<uint32_t>(oneIdx
- 1)) {
186 mParameters
.SetLength(oneIdx
- 1);
187 mParameters
.AppendElement(entry
.GetWeak());
189 mParameters
.ReplaceElementAt(oneIdx
- 1, entry
.GetWeak());
193 // Now bind using the super class.
194 return BindingParams::bind(aStatement
);
197 ///////////////////////////////////////////////////////////////////////////////
198 //// mozIStorageBindingParams
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.
206 nsresult rv
= mOwningStatement
->GetParameterIndex(aName
, &index
);
207 NS_ENSURE_SUCCESS(rv
, rv
);
209 return BindByIndex(index
, aValue
);
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
));
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
);
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
);
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
);
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
);
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
);
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
);
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
),
278 nsCOMPtr
<nsIVariant
> value(new BlobVariant(data
));
279 NS_ENSURE_TRUE(value
, NS_ERROR_OUT_OF_MEMORY
);
281 return BindByName(aName
, value
);
285 BindingParams::BindBlobArrayByName(const nsACString
& aName
,
286 const nsTArray
<uint8_t>& aValue
) {
287 return BindBlobByName(aName
, aValue
.Elements(), aValue
.Length());
291 BindingParams::BindStringAsBlobByName(const nsACString
& aName
,
292 const nsAString
& aValue
) {
293 return DoBindStringAsBlobByName(this, aName
, aValue
);
297 BindingParams::BindUTF8StringAsBlobByName(const nsACString
& aName
,
298 const nsACString
& aValue
) {
299 return DoBindStringAsBlobByName(this, aName
, aValue
);
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
);
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
);
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
);
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
);
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
);
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
);
380 mParameters
.ReplaceElementAt(aIndex
, variant
);
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
);
397 mParameters
.ReplaceElementAt(aIndex
, variant
);
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
);
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
);
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
);
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
);
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
);
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
);
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
),
457 nsCOMPtr
<nsIVariant
> value(new BlobVariant(data
));
458 NS_ENSURE_TRUE(value
, NS_ERROR_OUT_OF_MEMORY
);
460 return BindByIndex(aIndex
, value
);
464 BindingParams::BindBlobArrayByIndex(uint32_t aIndex
,
465 const nsTArray
<uint8_t>& aValue
) {
466 return BindBlobByIndex(aIndex
, aValue
.Elements(), aValue
.Length());
470 BindingParams::BindStringAsBlobByIndex(uint32_t aIndex
,
471 const nsAString
& aValue
) {
472 return DoBindStringAsBlobByIndex(this, aIndex
, aValue
);
476 BindingParams::BindUTF8StringAsBlobByIndex(uint32_t aIndex
,
477 const nsACString
& aValue
) {
478 return DoBindStringAsBlobByIndex(this, aIndex
, aValue
);
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
);
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
);
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
);
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
);
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