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/. */
11 #include "mozStorageError.h"
12 #include "mozStoragePrivateHelpers.h"
13 #include "mozStorageBindingParams.h"
14 #include "mozStorageBindingParamsArray.h"
20 ////////////////////////////////////////////////////////////////////////////////
21 //// Local Helper Objects
25 struct BindingColumnData
27 BindingColumnData(sqlite3_stmt
*aStmt
,
37 ////////////////////////////////////////////////////////////////////////////////
38 //// Variant Specialization Functions (variantToSQLiteT)
41 sqlite3_T_int(BindingColumnData aData
,
44 return ::sqlite3_bind_int(aData
.stmt
, aData
.column
+ 1, aValue
);
48 sqlite3_T_int64(BindingColumnData aData
,
51 return ::sqlite3_bind_int64(aData
.stmt
, aData
.column
+ 1, aValue
);
55 sqlite3_T_double(BindingColumnData aData
,
58 return ::sqlite3_bind_double(aData
.stmt
, aData
.column
+ 1, aValue
);
62 sqlite3_T_text(BindingColumnData aData
,
63 const nsCString
& aValue
)
65 return ::sqlite3_bind_text(aData
.stmt
,
73 sqlite3_T_text16(BindingColumnData aData
,
74 const nsString
& aValue
)
76 return ::sqlite3_bind_text16(aData
.stmt
,
79 aValue
.Length() * 2, // Length in bytes!
84 sqlite3_T_null(BindingColumnData aData
)
86 return ::sqlite3_bind_null(aData
.stmt
, aData
.column
+ 1);
90 sqlite3_T_blob(BindingColumnData aData
,
94 return ::sqlite3_bind_blob(aData
.stmt
, aData
.column
+ 1, aBlob
, aSize
,
99 #include "variantToSQLiteT_impl.h"
101 } // anonymous namespace
103 ////////////////////////////////////////////////////////////////////////////////
106 BindingParams::BindingParams(mozIStorageBindingParamsArray
*aOwningArray
,
107 Statement
*aOwningStatement
)
109 , mOwningArray(aOwningArray
)
110 , mOwningStatement(aOwningStatement
)
112 (void)mOwningStatement
->GetParameterCount(&mParamCount
);
113 (void)mParameters
.SetCapacity(mParamCount
);
116 BindingParams::BindingParams(mozIStorageBindingParamsArray
*aOwningArray
)
118 , mOwningArray(aOwningArray
)
119 , mOwningStatement(nullptr)
124 AsyncBindingParams::AsyncBindingParams(
125 mozIStorageBindingParamsArray
*aOwningArray
127 : BindingParams(aOwningArray
)
129 mNamedParameters
.Init();
133 BindingParams::lock()
135 NS_ASSERTION(mLocked
== false, "Parameters have already been locked!");
138 // We no longer need to hold a reference to our statement or our owning array.
139 // The array owns us at this point, and it will own a reference to the
141 mOwningStatement
= nullptr;
142 mOwningArray
= nullptr;
146 BindingParams::unlock(Statement
*aOwningStatement
)
148 NS_ASSERTION(mLocked
== true, "Parameters were not yet locked!");
150 mOwningStatement
= aOwningStatement
;
153 const mozIStorageBindingParamsArray
*
154 BindingParams::getOwner() const
160 AsyncBindingParams::iterateOverNamedParameters(const nsACString
&aName
,
162 void *voidClosureThunk
)
164 NamedParameterIterationClosureThunk
*closureThunk
=
165 static_cast<NamedParameterIterationClosureThunk
*>(voidClosureThunk
);
167 // We do not accept any forms of names other than ":name", but we need to add
168 // the colon for SQLite.
169 nsAutoCString
name(":");
171 int oneIdx
= ::sqlite3_bind_parameter_index(closureThunk
->statement
,
175 nsAutoCString
errMsg(aName
);
176 errMsg
.Append(NS_LITERAL_CSTRING(" is not a valid named parameter."));
177 closureThunk
->err
= new Error(SQLITE_RANGE
, errMsg
.get());
178 return PL_DHASH_STOP
;
181 // XPCVariant's AddRef and Release are not thread-safe and so we must not do
182 // anything that would invoke them here on the async thread. As such we can't
183 // cram aValue into self->mParameters using ReplaceObjectAt so that we can
184 // freeload off of the BindingParams::Bind implementation.
185 int rc
= variantToSQLiteT(BindingColumnData(closureThunk
->statement
,
188 if (rc
!= SQLITE_OK
) {
189 // We had an error while trying to bind. Now we need to create an error
190 // object with the right message. Note that we special case
191 // SQLITE_MISMATCH, but otherwise get the message from SQLite.
192 const char *msg
= "Could not covert nsIVariant to SQLite type.";
193 if (rc
!= SQLITE_MISMATCH
)
194 msg
= ::sqlite3_errmsg(::sqlite3_db_handle(closureThunk
->statement
));
196 closureThunk
->err
= new Error(rc
, msg
);
197 return PL_DHASH_STOP
;
199 return PL_DHASH_NEXT
;
202 ////////////////////////////////////////////////////////////////////////////////
207 , mozIStorageBindingParams
208 , IStorageBindingParamsInternal
212 ////////////////////////////////////////////////////////////////////////////////
213 //// IStorageBindingParamsInternal
215 already_AddRefed
<mozIStorageError
>
216 BindingParams::bind(sqlite3_stmt
*aStatement
)
218 // Iterate through all of our stored data, and bind it.
219 for (int32_t i
= 0; i
< mParameters
.Count(); i
++) {
220 int rc
= variantToSQLiteT(BindingColumnData(aStatement
, i
), mParameters
[i
]);
221 if (rc
!= SQLITE_OK
) {
222 // We had an error while trying to bind. Now we need to create an error
223 // object with the right message. Note that we special case
224 // SQLITE_MISMATCH, but otherwise get the message from SQLite.
225 const char *msg
= "Could not covert nsIVariant to SQLite type.";
226 if (rc
!= SQLITE_MISMATCH
)
227 msg
= ::sqlite3_errmsg(::sqlite3_db_handle(aStatement
));
229 nsCOMPtr
<mozIStorageError
> err(new Error(rc
, msg
));
237 already_AddRefed
<mozIStorageError
>
238 AsyncBindingParams::bind(sqlite3_stmt
* aStatement
)
240 // We should bind by index using the super-class if there is nothing in our
242 if (!mNamedParameters
.Count())
243 return BindingParams::bind(aStatement
);
245 // Enumerate over everyone in the map, propagating them into mParameters if
246 // we can and creating an error immediately when we cannot.
247 NamedParameterIterationClosureThunk closureThunk
= {this, aStatement
, nullptr};
248 (void)mNamedParameters
.EnumerateRead(iterateOverNamedParameters
,
249 (void *)&closureThunk
);
251 return closureThunk
.err
.forget();
255 ///////////////////////////////////////////////////////////////////////////////
256 //// mozIStorageBindingParams
259 BindingParams::BindByName(const nsACString
&aName
,
262 NS_ENSURE_FALSE(mLocked
, NS_ERROR_UNEXPECTED
);
264 // Get the column index that we need to store this at.
266 nsresult rv
= mOwningStatement
->GetParameterIndex(aName
, &index
);
267 NS_ENSURE_SUCCESS(rv
, rv
);
269 return BindByIndex(index
, aValue
);
273 AsyncBindingParams::BindByName(const nsACString
&aName
,
276 NS_ENSURE_FALSE(mLocked
, NS_ERROR_UNEXPECTED
);
278 mNamedParameters
.Put(aName
, aValue
);
284 BindingParams::BindUTF8StringByName(const nsACString
&aName
,
285 const nsACString
&aValue
)
287 nsCOMPtr
<nsIVariant
> value(new UTF8TextVariant(aValue
));
288 NS_ENSURE_TRUE(value
, NS_ERROR_OUT_OF_MEMORY
);
290 return BindByName(aName
, value
);
294 BindingParams::BindStringByName(const nsACString
&aName
,
295 const nsAString
&aValue
)
297 nsCOMPtr
<nsIVariant
> value(new TextVariant(aValue
));
298 NS_ENSURE_TRUE(value
, NS_ERROR_OUT_OF_MEMORY
);
300 return BindByName(aName
, value
);
304 BindingParams::BindDoubleByName(const nsACString
&aName
,
307 nsCOMPtr
<nsIVariant
> value(new FloatVariant(aValue
));
308 NS_ENSURE_TRUE(value
, NS_ERROR_OUT_OF_MEMORY
);
310 return BindByName(aName
, value
);
314 BindingParams::BindInt32ByName(const nsACString
&aName
,
317 nsCOMPtr
<nsIVariant
> value(new IntegerVariant(aValue
));
318 NS_ENSURE_TRUE(value
, NS_ERROR_OUT_OF_MEMORY
);
320 return BindByName(aName
, value
);
324 BindingParams::BindInt64ByName(const nsACString
&aName
,
327 nsCOMPtr
<nsIVariant
> value(new IntegerVariant(aValue
));
328 NS_ENSURE_TRUE(value
, NS_ERROR_OUT_OF_MEMORY
);
330 return BindByName(aName
, value
);
334 BindingParams::BindNullByName(const nsACString
&aName
)
336 nsCOMPtr
<nsIVariant
> value(new NullVariant());
337 NS_ENSURE_TRUE(value
, NS_ERROR_OUT_OF_MEMORY
);
339 return BindByName(aName
, value
);
343 BindingParams::BindBlobByName(const nsACString
&aName
,
344 const uint8_t *aValue
,
347 NS_ENSURE_ARG_MAX(aValueSize
, INT_MAX
);
348 std::pair
<const void *, int> data(
349 static_cast<const void *>(aValue
),
352 nsCOMPtr
<nsIVariant
> value(new BlobVariant(data
));
353 NS_ENSURE_TRUE(value
, NS_ERROR_OUT_OF_MEMORY
);
355 return BindByName(aName
, value
);
359 BindingParams::BindByIndex(uint32_t aIndex
,
362 NS_ENSURE_FALSE(mLocked
, NS_ERROR_UNEXPECTED
);
363 ENSURE_INDEX_VALUE(aIndex
, mParamCount
);
365 // Store the variant for later use.
366 NS_ENSURE_TRUE(mParameters
.ReplaceObjectAt(aValue
, aIndex
),
367 NS_ERROR_OUT_OF_MEMORY
);
372 AsyncBindingParams::BindByIndex(uint32_t aIndex
,
375 NS_ENSURE_FALSE(mLocked
, NS_ERROR_UNEXPECTED
);
376 // In the asynchronous case we do not know how many parameters there are to
377 // bind to, so we cannot check the validity of aIndex.
379 // Store the variant for later use.
380 NS_ENSURE_TRUE(mParameters
.ReplaceObjectAt(aValue
, aIndex
),
381 NS_ERROR_OUT_OF_MEMORY
);
386 BindingParams::BindUTF8StringByIndex(uint32_t aIndex
,
387 const nsACString
&aValue
)
389 nsCOMPtr
<nsIVariant
> value(new UTF8TextVariant(aValue
));
390 NS_ENSURE_TRUE(value
, NS_ERROR_OUT_OF_MEMORY
);
392 return BindByIndex(aIndex
, value
);
396 BindingParams::BindStringByIndex(uint32_t aIndex
,
397 const nsAString
&aValue
)
399 nsCOMPtr
<nsIVariant
> value(new TextVariant(aValue
));
400 NS_ENSURE_TRUE(value
, NS_ERROR_OUT_OF_MEMORY
);
402 return BindByIndex(aIndex
, value
);
406 BindingParams::BindDoubleByIndex(uint32_t aIndex
,
409 nsCOMPtr
<nsIVariant
> value(new FloatVariant(aValue
));
410 NS_ENSURE_TRUE(value
, NS_ERROR_OUT_OF_MEMORY
);
412 return BindByIndex(aIndex
, value
);
416 BindingParams::BindInt32ByIndex(uint32_t aIndex
,
419 nsCOMPtr
<nsIVariant
> value(new IntegerVariant(aValue
));
420 NS_ENSURE_TRUE(value
, NS_ERROR_OUT_OF_MEMORY
);
422 return BindByIndex(aIndex
, value
);
426 BindingParams::BindInt64ByIndex(uint32_t aIndex
,
429 nsCOMPtr
<nsIVariant
> value(new IntegerVariant(aValue
));
430 NS_ENSURE_TRUE(value
, NS_ERROR_OUT_OF_MEMORY
);
432 return BindByIndex(aIndex
, value
);
436 BindingParams::BindNullByIndex(uint32_t aIndex
)
438 nsCOMPtr
<nsIVariant
> value(new NullVariant());
439 NS_ENSURE_TRUE(value
, NS_ERROR_OUT_OF_MEMORY
);
441 return BindByIndex(aIndex
, value
);
445 BindingParams::BindBlobByIndex(uint32_t aIndex
,
446 const uint8_t *aValue
,
449 NS_ENSURE_ARG_MAX(aValueSize
, INT_MAX
);
450 std::pair
<const void *, int> data(
451 static_cast<const void *>(aValue
),
454 nsCOMPtr
<nsIVariant
> value(new BlobVariant(data
));
455 NS_ENSURE_TRUE(value
, NS_ERROR_OUT_OF_MEMORY
);
457 return BindByIndex(aIndex
, value
);
460 } // namespace storage
461 } // namespace mozilla