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
28 BindingColumnData(sqlite3_stmt
*aStmt
,
38 ////////////////////////////////////////////////////////////////////////////////
39 //// Variant Specialization Functions (variantToSQLiteT)
42 sqlite3_T_int(BindingColumnData aData
,
45 return ::sqlite3_bind_int(aData
.stmt
, aData
.column
+ 1, aValue
);
49 sqlite3_T_int64(BindingColumnData aData
,
52 return ::sqlite3_bind_int64(aData
.stmt
, aData
.column
+ 1, aValue
);
56 sqlite3_T_double(BindingColumnData aData
,
59 return ::sqlite3_bind_double(aData
.stmt
, aData
.column
+ 1, aValue
);
63 sqlite3_T_text(BindingColumnData aData
,
64 const nsCString
& aValue
)
66 return ::sqlite3_bind_text(aData
.stmt
,
74 sqlite3_T_text16(BindingColumnData aData
,
75 const nsString
& aValue
)
77 return ::sqlite3_bind_text16(aData
.stmt
,
80 aValue
.Length() * 2, // Length in bytes!
85 sqlite3_T_null(BindingColumnData aData
)
87 return ::sqlite3_bind_null(aData
.stmt
, aData
.column
+ 1);
91 sqlite3_T_blob(BindingColumnData aData
,
95 return ::sqlite3_bind_blob(aData
.stmt
, aData
.column
+ 1, aBlob
, aSize
,
100 #include "variantToSQLiteT_impl.h"
104 ////////////////////////////////////////////////////////////////////////////////
107 BindingParams::BindingParams(mozIStorageBindingParamsArray
*aOwningArray
,
108 Statement
*aOwningStatement
)
110 , mOwningArray(aOwningArray
)
111 , mOwningStatement(aOwningStatement
)
114 (void)mOwningStatement
->GetParameterCount(&mParamCount
);
115 mParameters
.SetCapacity(mParamCount
);
118 BindingParams::BindingParams(mozIStorageBindingParamsArray
*aOwningArray
)
120 , mOwningArray(aOwningArray
)
121 , mOwningStatement(nullptr)
126 AsyncBindingParams::AsyncBindingParams(
127 mozIStorageBindingParamsArray
*aOwningArray
129 : BindingParams(aOwningArray
)
134 BindingParams::lock()
136 NS_ASSERTION(mLocked
== false, "Parameters have already been locked!");
139 // We no longer need to hold a reference to our statement or our owning array.
140 // The array owns us at this point, and it will own a reference to the
142 mOwningStatement
= nullptr;
143 mOwningArray
= nullptr;
147 BindingParams::unlock(Statement
*aOwningStatement
)
149 NS_ASSERTION(mLocked
== true, "Parameters were not yet locked!");
151 mOwningStatement
= aOwningStatement
;
154 const mozIStorageBindingParamsArray
*
155 BindingParams::getOwner() const
160 ////////////////////////////////////////////////////////////////////////////////
165 , mozIStorageBindingParams
166 , IStorageBindingParamsInternal
170 ////////////////////////////////////////////////////////////////////////////////
171 //// IStorageBindingParamsInternal
173 already_AddRefed
<mozIStorageError
>
174 BindingParams::bind(sqlite3_stmt
*aStatement
)
176 // Iterate through all of our stored data, and bind it.
177 for (size_t i
= 0; i
< mParameters
.Length(); i
++) {
178 int rc
= variantToSQLiteT(BindingColumnData(aStatement
, i
), mParameters
[i
]);
179 if (rc
!= SQLITE_OK
) {
180 // We had an error while trying to bind. Now we need to create an error
181 // object with the right message. Note that we special case
182 // SQLITE_MISMATCH, but otherwise get the message from SQLite.
183 const char *msg
= "Could not covert nsIVariant to SQLite type.";
184 if (rc
!= SQLITE_MISMATCH
)
185 msg
= ::sqlite3_errmsg(::sqlite3_db_handle(aStatement
));
187 nsCOMPtr
<mozIStorageError
> err(new Error(rc
, msg
));
195 already_AddRefed
<mozIStorageError
>
196 AsyncBindingParams::bind(sqlite3_stmt
* aStatement
)
198 // We should bind by index using the super-class if there is nothing in our
200 if (!mNamedParameters
.Count())
201 return BindingParams::bind(aStatement
);
203 nsCOMPtr
<mozIStorageError
> err
;
205 for (auto iter
= mNamedParameters
.Iter(); !iter
.Done(); iter
.Next()) {
206 const nsACString
&key
= iter
.Key();
208 // We do not accept any forms of names other than ":name", but we need to
209 // add the colon for SQLite.
210 nsAutoCString
name(":");
212 int oneIdx
= ::sqlite3_bind_parameter_index(aStatement
, name
.get());
215 nsAutoCString
errMsg(key
);
216 errMsg
.AppendLiteral(" is not a valid named parameter.");
217 err
= new Error(SQLITE_RANGE
, errMsg
.get());
221 // XPCVariant's AddRef and Release are not thread-safe and so we must not
222 // do anything that would invoke them here on the async thread. As such we
223 // can't cram aValue into mParameters using ReplaceObjectAt so that
224 // we can freeload off of the BindingParams::Bind implementation.
225 int rc
= variantToSQLiteT(BindingColumnData(aStatement
, oneIdx
- 1),
227 if (rc
!= SQLITE_OK
) {
228 // We had an error while trying to bind. Now we need to create an error
229 // object with the right message. Note that we special case
230 // SQLITE_MISMATCH, but otherwise get the message from SQLite.
231 const char *msg
= "Could not covert nsIVariant to SQLite type.";
232 if (rc
!= SQLITE_MISMATCH
) {
233 msg
= ::sqlite3_errmsg(::sqlite3_db_handle(aStatement
));
235 err
= new Error(rc
, msg
);
244 ///////////////////////////////////////////////////////////////////////////////
245 //// mozIStorageBindingParams
248 BindingParams::BindByName(const nsACString
&aName
,
251 NS_ENSURE_FALSE(mLocked
, NS_ERROR_UNEXPECTED
);
253 // Get the column index that we need to store this at.
255 nsresult rv
= mOwningStatement
->GetParameterIndex(aName
, &index
);
256 NS_ENSURE_SUCCESS(rv
, rv
);
258 return BindByIndex(index
, aValue
);
262 AsyncBindingParams::BindByName(const nsACString
&aName
,
265 NS_ENSURE_FALSE(mLocked
, NS_ERROR_UNEXPECTED
);
267 RefPtr
<Variant_base
> variant
= convertVariantToStorageVariant(aValue
);
269 return NS_ERROR_UNEXPECTED
;
271 mNamedParameters
.Put(aName
, variant
);
277 BindingParams::BindUTF8StringByName(const nsACString
&aName
,
278 const nsACString
&aValue
)
280 nsCOMPtr
<nsIVariant
> value(new UTF8TextVariant(aValue
));
281 NS_ENSURE_TRUE(value
, NS_ERROR_OUT_OF_MEMORY
);
283 return BindByName(aName
, value
);
287 BindingParams::BindStringByName(const nsACString
&aName
,
288 const nsAString
&aValue
)
290 nsCOMPtr
<nsIVariant
> value(new TextVariant(aValue
));
291 NS_ENSURE_TRUE(value
, NS_ERROR_OUT_OF_MEMORY
);
293 return BindByName(aName
, value
);
297 BindingParams::BindDoubleByName(const nsACString
&aName
,
300 nsCOMPtr
<nsIVariant
> value(new FloatVariant(aValue
));
301 NS_ENSURE_TRUE(value
, NS_ERROR_OUT_OF_MEMORY
);
303 return BindByName(aName
, value
);
307 BindingParams::BindInt32ByName(const nsACString
&aName
,
310 nsCOMPtr
<nsIVariant
> value(new IntegerVariant(aValue
));
311 NS_ENSURE_TRUE(value
, NS_ERROR_OUT_OF_MEMORY
);
313 return BindByName(aName
, value
);
317 BindingParams::BindInt64ByName(const nsACString
&aName
,
320 nsCOMPtr
<nsIVariant
> value(new IntegerVariant(aValue
));
321 NS_ENSURE_TRUE(value
, NS_ERROR_OUT_OF_MEMORY
);
323 return BindByName(aName
, value
);
327 BindingParams::BindNullByName(const nsACString
&aName
)
329 nsCOMPtr
<nsIVariant
> value(new NullVariant());
330 NS_ENSURE_TRUE(value
, NS_ERROR_OUT_OF_MEMORY
);
332 return BindByName(aName
, value
);
336 BindingParams::BindBlobByName(const nsACString
&aName
,
337 const uint8_t *aValue
,
340 NS_ENSURE_ARG_MAX(aValueSize
, INT_MAX
);
341 std::pair
<const void *, int> data(
342 static_cast<const void *>(aValue
),
345 nsCOMPtr
<nsIVariant
> value(new BlobVariant(data
));
346 NS_ENSURE_TRUE(value
, NS_ERROR_OUT_OF_MEMORY
);
348 return BindByName(aName
, value
);
352 BindingParams::BindStringAsBlobByName(const nsACString
& aName
,
353 const nsAString
& aValue
)
355 return DoBindStringAsBlobByName(this, aName
, aValue
);
359 BindingParams::BindUTF8StringAsBlobByName(const nsACString
& aName
,
360 const nsACString
& aValue
)
362 return DoBindStringAsBlobByName(this, aName
, aValue
);
367 BindingParams::BindAdoptedBlobByName(const nsACString
&aName
,
371 UniqueFreePtr
<uint8_t> uniqueValue(aValue
);
372 NS_ENSURE_ARG_MAX(aValueSize
, INT_MAX
);
373 std::pair
<uint8_t *, int> data(uniqueValue
.release(), int(aValueSize
));
374 nsCOMPtr
<nsIVariant
> value(new AdoptedBlobVariant(data
));
376 return BindByName(aName
, value
);
380 BindingParams::BindByIndex(uint32_t aIndex
,
383 NS_ENSURE_FALSE(mLocked
, NS_ERROR_UNEXPECTED
);
384 ENSURE_INDEX_VALUE(aIndex
, mParamCount
);
386 // Store the variant for later use.
387 RefPtr
<Variant_base
> variant
= convertVariantToStorageVariant(aValue
);
389 return NS_ERROR_UNEXPECTED
;
390 if (mParameters
.Length() <= aIndex
) {
391 (void)mParameters
.SetLength(aIndex
);
392 (void)mParameters
.AppendElement(variant
);
395 NS_ENSURE_TRUE(mParameters
.ReplaceElementAt(aIndex
, variant
),
396 NS_ERROR_OUT_OF_MEMORY
);
402 AsyncBindingParams::BindByIndex(uint32_t aIndex
,
405 NS_ENSURE_FALSE(mLocked
, NS_ERROR_UNEXPECTED
);
406 // In the asynchronous case we do not know how many parameters there are to
407 // bind to, so we cannot check the validity of aIndex.
409 RefPtr
<Variant_base
> variant
= convertVariantToStorageVariant(aValue
);
411 return NS_ERROR_UNEXPECTED
;
412 if (mParameters
.Length() <= aIndex
) {
413 mParameters
.SetLength(aIndex
);
414 mParameters
.AppendElement(variant
);
417 NS_ENSURE_TRUE(mParameters
.ReplaceElementAt(aIndex
, variant
),
418 NS_ERROR_OUT_OF_MEMORY
);
424 BindingParams::BindUTF8StringByIndex(uint32_t aIndex
,
425 const nsACString
&aValue
)
427 nsCOMPtr
<nsIVariant
> value(new UTF8TextVariant(aValue
));
428 NS_ENSURE_TRUE(value
, NS_ERROR_OUT_OF_MEMORY
);
430 return BindByIndex(aIndex
, value
);
434 BindingParams::BindStringByIndex(uint32_t aIndex
,
435 const nsAString
&aValue
)
437 nsCOMPtr
<nsIVariant
> value(new TextVariant(aValue
));
438 NS_ENSURE_TRUE(value
, NS_ERROR_OUT_OF_MEMORY
);
440 return BindByIndex(aIndex
, value
);
444 BindingParams::BindDoubleByIndex(uint32_t aIndex
,
447 nsCOMPtr
<nsIVariant
> value(new FloatVariant(aValue
));
448 NS_ENSURE_TRUE(value
, NS_ERROR_OUT_OF_MEMORY
);
450 return BindByIndex(aIndex
, value
);
454 BindingParams::BindInt32ByIndex(uint32_t aIndex
,
457 nsCOMPtr
<nsIVariant
> value(new IntegerVariant(aValue
));
458 NS_ENSURE_TRUE(value
, NS_ERROR_OUT_OF_MEMORY
);
460 return BindByIndex(aIndex
, value
);
464 BindingParams::BindInt64ByIndex(uint32_t aIndex
,
467 nsCOMPtr
<nsIVariant
> value(new IntegerVariant(aValue
));
468 NS_ENSURE_TRUE(value
, NS_ERROR_OUT_OF_MEMORY
);
470 return BindByIndex(aIndex
, value
);
474 BindingParams::BindNullByIndex(uint32_t aIndex
)
476 nsCOMPtr
<nsIVariant
> value(new NullVariant());
477 NS_ENSURE_TRUE(value
, NS_ERROR_OUT_OF_MEMORY
);
479 return BindByIndex(aIndex
, value
);
483 BindingParams::BindBlobByIndex(uint32_t aIndex
,
484 const uint8_t *aValue
,
487 NS_ENSURE_ARG_MAX(aValueSize
, INT_MAX
);
488 std::pair
<const void *, int> data(
489 static_cast<const void *>(aValue
),
492 nsCOMPtr
<nsIVariant
> value(new BlobVariant(data
));
493 NS_ENSURE_TRUE(value
, NS_ERROR_OUT_OF_MEMORY
);
495 return BindByIndex(aIndex
, value
);
499 BindingParams::BindStringAsBlobByIndex(uint32_t aIndex
, const nsAString
& aValue
)
501 return DoBindStringAsBlobByIndex(this, aIndex
, aValue
);
505 BindingParams::BindUTF8StringAsBlobByIndex(uint32_t aIndex
,
506 const nsACString
& aValue
)
508 return DoBindStringAsBlobByIndex(this, aIndex
, aValue
);
512 BindingParams::BindAdoptedBlobByIndex(uint32_t aIndex
,
516 UniqueFreePtr
<uint8_t> uniqueValue(aValue
);
517 NS_ENSURE_ARG_MAX(aValueSize
, INT_MAX
);
518 std::pair
<uint8_t *, int> data(uniqueValue
.release(), int(aValueSize
));
519 nsCOMPtr
<nsIVariant
> value(new AdoptedBlobVariant(data
));
521 return BindByIndex(aIndex
, value
);
524 } // namespace storage
525 } // namespace mozilla