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"
15 #include "mozStorageBindingParamsArray.h"
21 ////////////////////////////////////////////////////////////////////////////////
22 //// Local Helper Objects
26 struct BindingColumnData
{
27 BindingColumnData(sqlite3_stmt
* aStmt
, int aColumn
)
28 : stmt(aStmt
), column(aColumn
) {}
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!
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"
72 ////////////////////////////////////////////////////////////////////////////////
75 BindingParams::BindingParams(mozIStorageBindingParamsArray
* aOwningArray
,
76 Statement
* aOwningStatement
)
78 mOwningArray(aOwningArray
),
79 mOwningStatement(aOwningStatement
),
81 (void)mOwningStatement
->GetParameterCount(&mParamCount
);
82 mParameters
.SetCapacity(mParamCount
);
85 BindingParams::BindingParams(mozIStorageBindingParamsArray
* aOwningArray
)
87 mOwningArray(aOwningArray
),
88 mOwningStatement(nullptr),
91 AsyncBindingParams::AsyncBindingParams(
92 mozIStorageBindingParamsArray
* aOwningArray
)
93 : BindingParams(aOwningArray
) {}
95 void BindingParams::lock() {
96 NS_ASSERTION(mLocked
== false, "Parameters have already been locked!");
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
102 mOwningStatement
= nullptr;
103 mOwningArray
= nullptr;
106 void BindingParams::unlock(Statement
* aOwningStatement
) {
107 NS_ASSERTION(mLocked
== true, "Parameters were not yet locked!");
109 mOwningStatement
= aOwningStatement
;
112 const mozIStorageBindingParamsArray
* BindingParams::getOwner() const {
116 ////////////////////////////////////////////////////////////////////////////////
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
));
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
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(":");
161 int oneIdx
= ::sqlite3_bind_parameter_index(aStatement
, name
.get());
164 nsAutoCString
errMsg(key
);
165 errMsg
.AppendLiteral(" is not a valid named parameter.");
166 err
= new Error(SQLITE_RANGE
, errMsg
.get());
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),
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
);
192 ///////////////////////////////////////////////////////////////////////////////
193 //// mozIStorageBindingParams
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.
201 nsresult rv
= mOwningStatement
->GetParameterIndex(aName
, &index
);
202 NS_ENSURE_SUCCESS(rv
, rv
);
204 return BindByIndex(index
, aValue
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
),
274 nsCOMPtr
<nsIVariant
> value(new BlobVariant(data
));
275 NS_ENSURE_TRUE(value
, NS_ERROR_OUT_OF_MEMORY
);
277 return BindByName(aName
, value
);
281 BindingParams::BindBlobArrayByName(const nsACString
& aName
,
282 const nsTArray
<uint8_t>& aValue
) {
283 return BindBlobByName(aName
, aValue
.Elements(), aValue
.Length());
287 BindingParams::BindStringAsBlobByName(const nsACString
& aName
,
288 const nsAString
& aValue
) {
289 return DoBindStringAsBlobByName(this, aName
, aValue
);
293 BindingParams::BindUTF8StringAsBlobByName(const nsACString
& aName
,
294 const nsACString
& aValue
) {
295 return DoBindStringAsBlobByName(this, aName
, aValue
);
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
);
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
);
321 NS_ENSURE_TRUE(mParameters
.ReplaceElementAt(aIndex
, variant
),
322 NS_ERROR_OUT_OF_MEMORY
);
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
);
339 NS_ENSURE_TRUE(mParameters
.ReplaceElementAt(aIndex
, variant
),
340 NS_ERROR_OUT_OF_MEMORY
);
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
);
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
);
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
);
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
);
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
);
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
);
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
),
400 nsCOMPtr
<nsIVariant
> value(new BlobVariant(data
));
401 NS_ENSURE_TRUE(value
, NS_ERROR_OUT_OF_MEMORY
);
403 return BindByIndex(aIndex
, value
);
407 BindingParams::BindBlobArrayByIndex(uint32_t aIndex
,
408 const nsTArray
<uint8_t>& aValue
) {
409 return BindBlobByIndex(aIndex
, aValue
.Elements(), aValue
.Length());
413 BindingParams::BindStringAsBlobByIndex(uint32_t aIndex
,
414 const nsAString
& aValue
) {
415 return DoBindStringAsBlobByIndex(this, aIndex
, aValue
);
419 BindingParams::BindUTF8StringAsBlobByIndex(uint32_t aIndex
,
420 const nsACString
& aValue
) {
421 return DoBindStringAsBlobByIndex(this, aIndex
, aValue
);
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