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
5 : *
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/
10 : *
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
14 : * License.
15 : *
16 : * The Original Code is mozilla.org code.
17 : *
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.
22 : *
23 : * Contributor(s):
24 : * Shawn Wilsher <me@shawnwilsher.com> (Original Author)
25 : * Andrew Sutherland <asutherland@asutherland.org>
26 : *
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.
38 : *
39 : * ***** END LICENSE BLOCK ***** */
40 :
41 : #include <limits.h>
42 :
43 : #include "nsString.h"
44 :
45 : #include "mozStorageError.h"
46 : #include "mozStoragePrivateHelpers.h"
47 : #include "mozStorageBindingParams.h"
48 : #include "mozStorageBindingParamsArray.h"
49 : #include "Variant.h"
50 :
51 : namespace mozilla {
52 : namespace storage {
53 :
54 : ////////////////////////////////////////////////////////////////////////////////
55 : //// Local Helper Objects
56 :
57 : namespace {
58 :
59 : struct BindingColumnData
60 : {
61 420266 : BindingColumnData(sqlite3_stmt *aStmt,
62 : int aColumn)
63 : : stmt(aStmt)
64 420266 : , column(aColumn)
65 : {
66 420266 : }
67 : sqlite3_stmt *stmt;
68 : int column;
69 : };
70 :
71 : ////////////////////////////////////////////////////////////////////////////////
72 : //// Variant Specialization Functions (variantToSQLiteT)
73 :
74 : int
75 1123 : sqlite3_T_int(BindingColumnData aData,
76 : int aValue)
77 : {
78 1123 : return ::sqlite3_bind_int(aData.stmt, aData.column + 1, aValue);
79 : }
80 :
81 : int
82 228022 : sqlite3_T_int64(BindingColumnData aData,
83 : sqlite3_int64 aValue)
84 : {
85 228022 : return ::sqlite3_bind_int64(aData.stmt, aData.column + 1, aValue);
86 : }
87 :
88 : int
89 12764 : sqlite3_T_double(BindingColumnData aData,
90 : double aValue)
91 : {
92 12764 : return ::sqlite3_bind_double(aData.stmt, aData.column + 1, aValue);
93 : }
94 :
95 : int
96 102975 : sqlite3_T_text(BindingColumnData aData,
97 : const nsCString& aValue)
98 : {
99 : return ::sqlite3_bind_text(aData.stmt,
100 : aData.column + 1,
101 : aValue.get(),
102 102975 : aValue.Length(),
103 102975 : SQLITE_TRANSIENT);
104 : }
105 :
106 : int
107 41749 : sqlite3_T_text16(BindingColumnData aData,
108 : const nsString& aValue)
109 : {
110 : return ::sqlite3_bind_text16(aData.stmt,
111 : aData.column + 1,
112 41749 : aValue.get(),
113 41749 : aValue.Length() * 2, // Length in bytes!
114 83498 : SQLITE_TRANSIENT);
115 : }
116 :
117 : int
118 25996 : sqlite3_T_null(BindingColumnData aData)
119 : {
120 25996 : return ::sqlite3_bind_null(aData.stmt, aData.column + 1);
121 : }
122 :
123 : int
124 7633 : sqlite3_T_blob(BindingColumnData aData,
125 : const void *aBlob,
126 : int aSize)
127 : {
128 : return ::sqlite3_bind_blob(aData.stmt, aData.column + 1, aBlob, aSize,
129 7633 : NS_Free);
130 :
131 : }
132 :
133 : #include "variantToSQLiteT_impl.h"
134 :
135 : } // anonymous namespace
136 :
137 : ////////////////////////////////////////////////////////////////////////////////
138 : //// BindingParams
139 :
140 87644 : BindingParams::BindingParams(mozIStorageBindingParamsArray *aOwningArray,
141 : Statement *aOwningStatement)
142 : : mLocked(false)
143 : , mOwningArray(aOwningArray)
144 87644 : , mOwningStatement(aOwningStatement)
145 : {
146 87644 : (void)mOwningStatement->GetParameterCount(&mParamCount);
147 87644 : (void)mParameters.SetCapacity(mParamCount);
148 87644 : }
149 :
150 33153 : BindingParams::BindingParams(mozIStorageBindingParamsArray *aOwningArray)
151 : : mLocked(false)
152 : , mOwningArray(aOwningArray)
153 : , mOwningStatement(nsnull)
154 33153 : , mParamCount(0)
155 : {
156 33153 : }
157 :
158 33153 : AsyncBindingParams::AsyncBindingParams(
159 : mozIStorageBindingParamsArray *aOwningArray
160 : )
161 33153 : : BindingParams(aOwningArray)
162 : {
163 33153 : mNamedParameters.Init();
164 33153 : }
165 :
166 : void
167 120791 : BindingParams::lock()
168 : {
169 120791 : NS_ASSERTION(mLocked == false, "Parameters have already been locked!");
170 120791 : mLocked = true;
171 :
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
174 : // statement.
175 120791 : mOwningStatement = nsnull;
176 120791 : mOwningArray = nsnull;
177 120791 : }
178 :
179 : void
180 104645 : BindingParams::unlock(Statement *aOwningStatement)
181 : {
182 104645 : NS_ASSERTION(mLocked == true, "Parameters were not yet locked!");
183 104645 : mLocked = false;
184 104645 : mOwningStatement = aOwningStatement;
185 104645 : }
186 :
187 : const mozIStorageBindingParamsArray *
188 120793 : BindingParams::getOwner() const
189 : {
190 120793 : return mOwningArray;
191 : }
192 :
193 : PLDHashOperator
194 184985 : AsyncBindingParams::iterateOverNamedParameters(const nsACString &aName,
195 : nsIVariant *aValue,
196 : void *voidClosureThunk)
197 : {
198 : NamedParameterIterationClosureThunk *closureThunk =
199 184985 : static_cast<NamedParameterIterationClosureThunk *>(voidClosureThunk);
200 :
201 : // We do not accept any forms of names other than ":name", but we need to add
202 : // the colon for SQLite.
203 369970 : nsCAutoString name(":");
204 184985 : name.Append(aName);
205 : int oneIdx = ::sqlite3_bind_parameter_index(closureThunk->statement,
206 184985 : name.get());
207 :
208 184985 : if (oneIdx == 0) {
209 2 : nsCAutoString errMsg(aName);
210 1 : errMsg.Append(NS_LITERAL_CSTRING(" is not a valid named parameter."));
211 2 : closureThunk->err = new Error(SQLITE_RANGE, errMsg.get());
212 1 : return PL_DHASH_STOP;
213 : }
214 :
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,
220 : oneIdx - 1),
221 184984 : aValue);
222 184984 : 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 1 : const char *msg = "Could not covert nsIVariant to SQLite type.";
227 1 : if (rc != SQLITE_MISMATCH)
228 0 : msg = ::sqlite3_errmsg(::sqlite3_db_handle(closureThunk->statement));
229 :
230 1 : closureThunk->err = new Error(rc, msg);
231 1 : return PL_DHASH_STOP;
232 : }
233 184983 : return PL_DHASH_NEXT;
234 : }
235 :
236 : ////////////////////////////////////////////////////////////////////////////////
237 : //// nsISupports
238 :
239 1355378 : NS_IMPL_THREADSAFE_ISUPPORTS2(
240 : BindingParams
241 : , mozIStorageBindingParams
242 : , IStorageBindingParamsInternal
243 : )
244 :
245 :
246 : ////////////////////////////////////////////////////////////////////////////////
247 : //// IStorageBindingParamsInternal
248 :
249 : already_AddRefed<mozIStorageError>
250 87978 : BindingParams::bind(sqlite3_stmt *aStatement)
251 : {
252 : // Iterate through all of our stored data, and bind it.
253 323256 : for (PRInt32 i = 0; i < mParameters.Count(); i++) {
254 235282 : int rc = variantToSQLiteT(BindingColumnData(aStatement, i), mParameters[i]);
255 235282 : 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 4 : const char *msg = "Could not covert nsIVariant to SQLite type.";
260 4 : if (rc != SQLITE_MISMATCH)
261 1 : msg = ::sqlite3_errmsg(::sqlite3_db_handle(aStatement));
262 :
263 8 : nsCOMPtr<mozIStorageError> err(new Error(rc, msg));
264 4 : return err.forget();
265 : }
266 : }
267 :
268 87974 : return nsnull;
269 : }
270 :
271 : already_AddRefed<mozIStorageError>
272 33144 : AsyncBindingParams::bind(sqlite3_stmt * aStatement)
273 : {
274 : // We should bind by index using the super-class if there is nothing in our
275 : // hashtable.
276 33144 : if (!mNamedParameters.Count())
277 348 : return BindingParams::bind(aStatement);
278 :
279 : // Enumerate over everyone in the map, propagating them into mParameters if
280 : // we can and creating an error immediately when we cannot.
281 65592 : NamedParameterIterationClosureThunk closureThunk = {this, aStatement, nsnull};
282 : (void)mNamedParameters.EnumerateRead(iterateOverNamedParameters,
283 32796 : (void *)&closureThunk);
284 :
285 32796 : return closureThunk.err.forget();
286 : }
287 :
288 :
289 : ///////////////////////////////////////////////////////////////////////////////
290 : //// mozIStorageBindingParams
291 :
292 : NS_IMETHODIMP
293 230240 : BindingParams::BindByName(const nsACString &aName,
294 : nsIVariant *aValue)
295 : {
296 230240 : NS_ENSURE_FALSE(mLocked, NS_ERROR_UNEXPECTED);
297 :
298 : // Get the column index that we need to store this at.
299 : PRUint32 index;
300 230239 : nsresult rv = mOwningStatement->GetParameterIndex(aName, &index);
301 230239 : NS_ENSURE_SUCCESS(rv, rv);
302 :
303 230237 : return BindByIndex(index, aValue);
304 : }
305 :
306 : NS_IMETHODIMP
307 184995 : AsyncBindingParams::BindByName(const nsACString &aName,
308 : nsIVariant *aValue)
309 : {
310 184995 : NS_ENSURE_FALSE(mLocked, NS_ERROR_UNEXPECTED);
311 :
312 184994 : if (!mNamedParameters.Put(aName, aValue))
313 0 : return NS_ERROR_OUT_OF_MEMORY;
314 184994 : return NS_OK;
315 : }
316 :
317 :
318 : NS_IMETHODIMP
319 101122 : BindingParams::BindUTF8StringByName(const nsACString &aName,
320 : const nsACString &aValue)
321 : {
322 202244 : nsCOMPtr<nsIVariant> value(new UTF8TextVariant(aValue));
323 101122 : NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
324 :
325 101122 : return BindByName(aName, value);
326 : }
327 :
328 : NS_IMETHODIMP
329 4272 : BindingParams::BindStringByName(const nsACString &aName,
330 : const nsAString &aValue)
331 : {
332 8544 : nsCOMPtr<nsIVariant> value(new TextVariant(aValue));
333 4272 : NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
334 :
335 4272 : return BindByName(aName, value);
336 : }
337 :
338 : NS_IMETHODIMP
339 10 : BindingParams::BindDoubleByName(const nsACString &aName,
340 : double aValue)
341 : {
342 20 : nsCOMPtr<nsIVariant> value(new FloatVariant(aValue));
343 10 : NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
344 :
345 10 : return BindByName(aName, value);
346 : }
347 :
348 : NS_IMETHODIMP
349 54047 : BindingParams::BindInt32ByName(const nsACString &aName,
350 : PRInt32 aValue)
351 : {
352 108094 : nsCOMPtr<nsIVariant> value(new IntegerVariant(aValue));
353 54047 : NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
354 :
355 54047 : return BindByName(aName, value);
356 : }
357 :
358 : NS_IMETHODIMP
359 122348 : BindingParams::BindInt64ByName(const nsACString &aName,
360 : PRInt64 aValue)
361 : {
362 244696 : nsCOMPtr<nsIVariant> value(new IntegerVariant(aValue));
363 122348 : NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
364 :
365 122348 : return BindByName(aName, value);
366 : }
367 :
368 : NS_IMETHODIMP
369 7686 : BindingParams::BindNullByName(const nsACString &aName)
370 : {
371 15372 : nsCOMPtr<nsIVariant> value(new NullVariant());
372 7686 : NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
373 :
374 7686 : return BindByName(aName, value);
375 : }
376 :
377 : NS_IMETHODIMP
378 7560 : BindingParams::BindBlobByName(const nsACString &aName,
379 : const PRUint8 *aValue,
380 : PRUint32 aValueSize)
381 : {
382 7560 : NS_ENSURE_ARG_MAX(aValueSize, INT_MAX);
383 : std::pair<const void *, int> data(
384 : static_cast<const void *>(aValue),
385 : int(aValueSize)
386 7560 : );
387 15120 : nsCOMPtr<nsIVariant> value(new BlobVariant(data));
388 7560 : NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
389 :
390 7560 : return BindByName(aName, value);
391 : }
392 :
393 : NS_IMETHODIMP
394 234920 : BindingParams::BindByIndex(PRUint32 aIndex,
395 : nsIVariant *aValue)
396 : {
397 234920 : NS_ENSURE_FALSE(mLocked, NS_ERROR_UNEXPECTED);
398 234920 : ENSURE_INDEX_VALUE(aIndex, mParamCount);
399 :
400 : // Store the variant for later use.
401 234918 : NS_ENSURE_TRUE(mParameters.ReplaceObjectAt(aValue, aIndex),
402 : NS_ERROR_OUT_OF_MEMORY);
403 234918 : return NS_OK;
404 : }
405 :
406 : NS_IMETHODIMP
407 384 : AsyncBindingParams::BindByIndex(PRUint32 aIndex,
408 : nsIVariant *aValue)
409 : {
410 384 : 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.
413 :
414 : // Store the variant for later use.
415 384 : NS_ENSURE_TRUE(mParameters.ReplaceObjectAt(aValue, aIndex),
416 : NS_ERROR_OUT_OF_MEMORY);
417 384 : return NS_OK;
418 : }
419 :
420 : NS_IMETHODIMP
421 1853 : BindingParams::BindUTF8StringByIndex(PRUint32 aIndex,
422 : const nsACString &aValue)
423 : {
424 3706 : nsCOMPtr<nsIVariant> value(new UTF8TextVariant(aValue));
425 1853 : NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
426 :
427 1853 : return BindByIndex(aIndex, value);
428 : }
429 :
430 : NS_IMETHODIMP
431 102 : BindingParams::BindStringByIndex(PRUint32 aIndex,
432 : const nsAString &aValue)
433 : {
434 204 : nsCOMPtr<nsIVariant> value(new TextVariant(aValue));
435 102 : NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
436 :
437 102 : return BindByIndex(aIndex, value);
438 : }
439 :
440 : NS_IMETHODIMP
441 0 : BindingParams::BindDoubleByIndex(PRUint32 aIndex,
442 : double aValue)
443 : {
444 0 : nsCOMPtr<nsIVariant> value(new FloatVariant(aValue));
445 0 : NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
446 :
447 0 : return BindByIndex(aIndex, value);
448 : }
449 :
450 : NS_IMETHODIMP
451 1239 : BindingParams::BindInt32ByIndex(PRUint32 aIndex,
452 : PRInt32 aValue)
453 : {
454 2478 : nsCOMPtr<nsIVariant> value(new IntegerVariant(aValue));
455 1239 : NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
456 :
457 1239 : return BindByIndex(aIndex, value);
458 : }
459 :
460 : NS_IMETHODIMP
461 1040 : BindingParams::BindInt64ByIndex(PRUint32 aIndex,
462 : PRInt64 aValue)
463 : {
464 2080 : nsCOMPtr<nsIVariant> value(new IntegerVariant(aValue));
465 1040 : NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
466 :
467 1040 : return BindByIndex(aIndex, value);
468 : }
469 :
470 : NS_IMETHODIMP
471 0 : BindingParams::BindNullByIndex(PRUint32 aIndex)
472 : {
473 0 : nsCOMPtr<nsIVariant> value(new NullVariant());
474 0 : NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
475 :
476 0 : return BindByIndex(aIndex, value);
477 : }
478 :
479 : NS_IMETHODIMP
480 75 : BindingParams::BindBlobByIndex(PRUint32 aIndex,
481 : const PRUint8 *aValue,
482 : PRUint32 aValueSize)
483 : {
484 75 : NS_ENSURE_ARG_MAX(aValueSize, INT_MAX);
485 : std::pair<const void *, int> data(
486 : static_cast<const void *>(aValue),
487 : int(aValueSize)
488 75 : );
489 150 : nsCOMPtr<nsIVariant> value(new BlobVariant(data));
490 75 : NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
491 :
492 75 : return BindByIndex(aIndex, value);
493 : }
494 :
495 : } // namespace storage
496 : } // namespace mozilla
|