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 * ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
16 * The Original Code is mozilla.org code.
18 * The Initial Developer of the Original Code is
19 * Mozilla Corporation.
20 * Portions created by the Initial Developer are Copyright (C) 2009
21 * the Initial Developer. All Rights Reserved.
24 * Shawn Wilsher <me@shawnwilsher.com> (Original Author)
25 * Andrew Sutherland <asutherland@asutherland.org>
27 * Alternatively, the contents of this file may be used under the terms of
28 * either the GNU General Public License Version 2 or later (the "GPL"), or
29 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 * in which case the provisions of the GPL or the LGPL are applicable instead
31 * of those above. If you wish to allow use of your version of this file only
32 * under the terms of either the GPL or the LGPL, and not to allow others to
33 * use your version of this file under the terms of the MPL, indicate your
34 * decision by deleting the provisions above and replace them with the notice
35 * and other provisions required by the GPL or the LGPL. If you do not delete
36 * the provisions above, a recipient may use your version of this file under
37 * the terms of any one of the MPL, the GPL or the LGPL.
39 * ***** END LICENSE BLOCK ***** */
45 #include "mozStorageError.h"
46 #include "mozStoragePrivateHelpers.h"
47 #include "mozStorageBindingParams.h"
48 #include "mozStorageBindingParamsArray.h"
54 ////////////////////////////////////////////////////////////////////////////////
55 //// Local Helper Objects
59 struct BindingColumnData
61 BindingColumnData(sqlite3_stmt
*aStmt
,
71 ////////////////////////////////////////////////////////////////////////////////
72 //// Variant Specialization Functions (variantToSQLiteT)
75 sqlite3_T_int(BindingColumnData aData
,
78 return ::sqlite3_bind_int(aData
.stmt
, aData
.column
+ 1, aValue
);
82 sqlite3_T_int64(BindingColumnData aData
,
85 return ::sqlite3_bind_int64(aData
.stmt
, aData
.column
+ 1, aValue
);
89 sqlite3_T_double(BindingColumnData aData
,
92 return ::sqlite3_bind_double(aData
.stmt
, aData
.column
+ 1, aValue
);
96 sqlite3_T_text(BindingColumnData aData
,
97 const nsCString
& aValue
)
99 return ::sqlite3_bind_text(aData
.stmt
,
107 sqlite3_T_text16(BindingColumnData aData
,
108 const nsString
& aValue
)
110 return ::sqlite3_bind_text16(aData
.stmt
,
113 aValue
.Length() * 2, // Length in bytes!
118 sqlite3_T_null(BindingColumnData aData
)
120 return ::sqlite3_bind_null(aData
.stmt
, aData
.column
+ 1);
124 sqlite3_T_blob(BindingColumnData aData
,
128 return ::sqlite3_bind_blob(aData
.stmt
, aData
.column
+ 1, aBlob
, aSize
,
133 #include "variantToSQLiteT_impl.h"
135 } // anonymous namespace
137 ////////////////////////////////////////////////////////////////////////////////
140 BindingParams::BindingParams(mozIStorageBindingParamsArray
*aOwningArray
,
141 Statement
*aOwningStatement
)
143 , mOwningArray(aOwningArray
)
144 , mOwningStatement(aOwningStatement
)
146 (void)mOwningStatement
->GetParameterCount(&mParamCount
);
147 (void)mParameters
.SetCapacity(mParamCount
);
150 BindingParams::BindingParams(mozIStorageBindingParamsArray
*aOwningArray
)
152 , mOwningArray(aOwningArray
)
153 , mOwningStatement(nsnull
)
158 AsyncBindingParams::AsyncBindingParams(
159 mozIStorageBindingParamsArray
*aOwningArray
161 : BindingParams(aOwningArray
)
163 mNamedParameters
.Init();
167 BindingParams::lock()
169 NS_ASSERTION(mLocked
== false, "Parameters have already been locked!");
172 // We no longer need to hold a reference to our statement or our owning array.
173 // The array owns us at this point, and it will own a reference to the
175 mOwningStatement
= nsnull
;
176 mOwningArray
= nsnull
;
180 BindingParams::unlock(Statement
*aOwningStatement
)
182 NS_ASSERTION(mLocked
== true, "Parameters were not yet locked!");
184 mOwningStatement
= aOwningStatement
;
187 const mozIStorageBindingParamsArray
*
188 BindingParams::getOwner() const
194 AsyncBindingParams::iterateOverNamedParameters(const nsACString
&aName
,
196 void *voidClosureThunk
)
198 NamedParameterIterationClosureThunk
*closureThunk
=
199 static_cast<NamedParameterIterationClosureThunk
*>(voidClosureThunk
);
201 // We do not accept any forms of names other than ":name", but we need to add
202 // the colon for SQLite.
203 nsCAutoString
name(":");
205 int oneIdx
= ::sqlite3_bind_parameter_index(closureThunk
->statement
,
209 nsCAutoString
errMsg(aName
);
210 errMsg
.Append(NS_LITERAL_CSTRING(" is not a valid named parameter."));
211 closureThunk
->err
= new Error(SQLITE_RANGE
, errMsg
.get());
212 return PL_DHASH_STOP
;
215 // XPCVariant's AddRef and Release are not thread-safe and so we must not do
216 // anything that would invoke them here on the async thread. As such we can't
217 // cram aValue into self->mParameters using ReplaceObjectAt so that we can
218 // freeload off of the BindingParams::Bind implementation.
219 int rc
= variantToSQLiteT(BindingColumnData(closureThunk
->statement
,
222 if (rc
!= SQLITE_OK
) {
223 // We had an error while trying to bind. Now we need to create an error
224 // object with the right message. Note that we special case
225 // SQLITE_MISMATCH, but otherwise get the message from SQLite.
226 const char *msg
= "Could not covert nsIVariant to SQLite type.";
227 if (rc
!= SQLITE_MISMATCH
)
228 msg
= ::sqlite3_errmsg(::sqlite3_db_handle(closureThunk
->statement
));
230 closureThunk
->err
= new Error(rc
, msg
);
231 return PL_DHASH_STOP
;
233 return PL_DHASH_NEXT
;
236 ////////////////////////////////////////////////////////////////////////////////
239 NS_IMPL_THREADSAFE_ISUPPORTS2(
241 , mozIStorageBindingParams
242 , IStorageBindingParamsInternal
246 ////////////////////////////////////////////////////////////////////////////////
247 //// IStorageBindingParamsInternal
249 already_AddRefed
<mozIStorageError
>
250 BindingParams::bind(sqlite3_stmt
*aStatement
)
252 // Iterate through all of our stored data, and bind it.
253 for (PRInt32 i
= 0; i
< mParameters
.Count(); i
++) {
254 int rc
= variantToSQLiteT(BindingColumnData(aStatement
, i
), mParameters
[i
]);
255 if (rc
!= SQLITE_OK
) {
256 // We had an error while trying to bind. Now we need to create an error
257 // object with the right message. Note that we special case
258 // SQLITE_MISMATCH, but otherwise get the message from SQLite.
259 const char *msg
= "Could not covert nsIVariant to SQLite type.";
260 if (rc
!= SQLITE_MISMATCH
)
261 msg
= ::sqlite3_errmsg(::sqlite3_db_handle(aStatement
));
263 nsCOMPtr
<mozIStorageError
> err(new Error(rc
, msg
));
271 already_AddRefed
<mozIStorageError
>
272 AsyncBindingParams::bind(sqlite3_stmt
* aStatement
)
274 // We should bind by index using the super-class if there is nothing in our
276 if (!mNamedParameters
.Count())
277 return BindingParams::bind(aStatement
);
279 // Enumerate over everyone in the map, propagating them into mParameters if
280 // we can and creating an error immediately when we cannot.
281 NamedParameterIterationClosureThunk closureThunk
= {this, aStatement
, nsnull
};
282 (void)mNamedParameters
.EnumerateRead(iterateOverNamedParameters
,
283 (void *)&closureThunk
);
285 return closureThunk
.err
.forget();
289 ///////////////////////////////////////////////////////////////////////////////
290 //// mozIStorageBindingParams
293 BindingParams::BindByName(const nsACString
&aName
,
296 NS_ENSURE_FALSE(mLocked
, NS_ERROR_UNEXPECTED
);
298 // Get the column index that we need to store this at.
300 nsresult rv
= mOwningStatement
->GetParameterIndex(aName
, &index
);
301 NS_ENSURE_SUCCESS(rv
, rv
);
303 return BindByIndex(index
, aValue
);
307 AsyncBindingParams::BindByName(const nsACString
&aName
,
310 NS_ENSURE_FALSE(mLocked
, NS_ERROR_UNEXPECTED
);
312 if (!mNamedParameters
.Put(aName
, aValue
))
313 return NS_ERROR_OUT_OF_MEMORY
;
319 BindingParams::BindUTF8StringByName(const nsACString
&aName
,
320 const nsACString
&aValue
)
322 nsCOMPtr
<nsIVariant
> value(new UTF8TextVariant(aValue
));
323 NS_ENSURE_TRUE(value
, NS_ERROR_OUT_OF_MEMORY
);
325 return BindByName(aName
, value
);
329 BindingParams::BindStringByName(const nsACString
&aName
,
330 const nsAString
&aValue
)
332 nsCOMPtr
<nsIVariant
> value(new TextVariant(aValue
));
333 NS_ENSURE_TRUE(value
, NS_ERROR_OUT_OF_MEMORY
);
335 return BindByName(aName
, value
);
339 BindingParams::BindDoubleByName(const nsACString
&aName
,
342 nsCOMPtr
<nsIVariant
> value(new FloatVariant(aValue
));
343 NS_ENSURE_TRUE(value
, NS_ERROR_OUT_OF_MEMORY
);
345 return BindByName(aName
, value
);
349 BindingParams::BindInt32ByName(const nsACString
&aName
,
352 nsCOMPtr
<nsIVariant
> value(new IntegerVariant(aValue
));
353 NS_ENSURE_TRUE(value
, NS_ERROR_OUT_OF_MEMORY
);
355 return BindByName(aName
, value
);
359 BindingParams::BindInt64ByName(const nsACString
&aName
,
362 nsCOMPtr
<nsIVariant
> value(new IntegerVariant(aValue
));
363 NS_ENSURE_TRUE(value
, NS_ERROR_OUT_OF_MEMORY
);
365 return BindByName(aName
, value
);
369 BindingParams::BindNullByName(const nsACString
&aName
)
371 nsCOMPtr
<nsIVariant
> value(new NullVariant());
372 NS_ENSURE_TRUE(value
, NS_ERROR_OUT_OF_MEMORY
);
374 return BindByName(aName
, value
);
378 BindingParams::BindBlobByName(const nsACString
&aName
,
379 const PRUint8
*aValue
,
382 NS_ENSURE_ARG_MAX(aValueSize
, INT_MAX
);
383 std::pair
<const void *, int> data(
384 static_cast<const void *>(aValue
),
387 nsCOMPtr
<nsIVariant
> value(new BlobVariant(data
));
388 NS_ENSURE_TRUE(value
, NS_ERROR_OUT_OF_MEMORY
);
390 return BindByName(aName
, value
);
394 BindingParams::BindByIndex(PRUint32 aIndex
,
397 NS_ENSURE_FALSE(mLocked
, NS_ERROR_UNEXPECTED
);
398 ENSURE_INDEX_VALUE(aIndex
, mParamCount
);
400 // Store the variant for later use.
401 NS_ENSURE_TRUE(mParameters
.ReplaceObjectAt(aValue
, aIndex
),
402 NS_ERROR_OUT_OF_MEMORY
);
407 AsyncBindingParams::BindByIndex(PRUint32 aIndex
,
410 NS_ENSURE_FALSE(mLocked
, NS_ERROR_UNEXPECTED
);
411 // In the asynchronous case we do not know how many parameters there are to
412 // bind to, so we cannot check the validity of aIndex.
414 // Store the variant for later use.
415 NS_ENSURE_TRUE(mParameters
.ReplaceObjectAt(aValue
, aIndex
),
416 NS_ERROR_OUT_OF_MEMORY
);
421 BindingParams::BindUTF8StringByIndex(PRUint32 aIndex
,
422 const nsACString
&aValue
)
424 nsCOMPtr
<nsIVariant
> value(new UTF8TextVariant(aValue
));
425 NS_ENSURE_TRUE(value
, NS_ERROR_OUT_OF_MEMORY
);
427 return BindByIndex(aIndex
, value
);
431 BindingParams::BindStringByIndex(PRUint32 aIndex
,
432 const nsAString
&aValue
)
434 nsCOMPtr
<nsIVariant
> value(new TextVariant(aValue
));
435 NS_ENSURE_TRUE(value
, NS_ERROR_OUT_OF_MEMORY
);
437 return BindByIndex(aIndex
, value
);
441 BindingParams::BindDoubleByIndex(PRUint32 aIndex
,
444 nsCOMPtr
<nsIVariant
> value(new FloatVariant(aValue
));
445 NS_ENSURE_TRUE(value
, NS_ERROR_OUT_OF_MEMORY
);
447 return BindByIndex(aIndex
, value
);
451 BindingParams::BindInt32ByIndex(PRUint32 aIndex
,
454 nsCOMPtr
<nsIVariant
> value(new IntegerVariant(aValue
));
455 NS_ENSURE_TRUE(value
, NS_ERROR_OUT_OF_MEMORY
);
457 return BindByIndex(aIndex
, value
);
461 BindingParams::BindInt64ByIndex(PRUint32 aIndex
,
464 nsCOMPtr
<nsIVariant
> value(new IntegerVariant(aValue
));
465 NS_ENSURE_TRUE(value
, NS_ERROR_OUT_OF_MEMORY
);
467 return BindByIndex(aIndex
, value
);
471 BindingParams::BindNullByIndex(PRUint32 aIndex
)
473 nsCOMPtr
<nsIVariant
> value(new NullVariant());
474 NS_ENSURE_TRUE(value
, NS_ERROR_OUT_OF_MEMORY
);
476 return BindByIndex(aIndex
, value
);
480 BindingParams::BindBlobByIndex(PRUint32 aIndex
,
481 const PRUint8
*aValue
,
484 NS_ENSURE_ARG_MAX(aValueSize
, INT_MAX
);
485 std::pair
<const void *, int> data(
486 static_cast<const void *>(aValue
),
489 nsCOMPtr
<nsIVariant
> value(new BlobVariant(data
));
490 NS_ENSURE_TRUE(value
, NS_ERROR_OUT_OF_MEMORY
);
492 return BindByIndex(aIndex
, value
);
495 } // namespace storage
496 } // namespace mozilla