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 422900 : BindingColumnData(sqlite3_stmt *aStmt,
62 : int aColumn)
63 : : stmt(aStmt)
64 422900 : , column(aColumn)
65 : {
66 422900 : }
67 : sqlite3_stmt *stmt;
68 : int column;
69 : };
70 :
71 : ////////////////////////////////////////////////////////////////////////////////
72 : //// Variant Specialization Functions (variantToSQLiteT)
73 :
74 : int
75 1127 : sqlite3_T_int(BindingColumnData aData,
76 : int aValue)
77 : {
78 1127 : return ::sqlite3_bind_int(aData.stmt, aData.column + 1, aValue);
79 : }
80 :
81 : int
82 229427 : sqlite3_T_int64(BindingColumnData aData,
83 : sqlite3_int64 aValue)
84 : {
85 229427 : return ::sqlite3_bind_int64(aData.stmt, aData.column + 1, aValue);
86 : }
87 :
88 : int
89 12768 : sqlite3_T_double(BindingColumnData aData,
90 : double aValue)
91 : {
92 12768 : return ::sqlite3_bind_double(aData.stmt, aData.column + 1, aValue);
93 : }
94 :
95 : int
96 103404 : 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 103404 : aValue.Length(),
103 103404 : SQLITE_TRANSIENT);
104 : }
105 :
106 : int
107 41781 : sqlite3_T_text16(BindingColumnData aData,
108 : const nsString& aValue)
109 : {
110 : return ::sqlite3_bind_text16(aData.stmt,
111 : aData.column + 1,
112 41781 : aValue.get(),
113 41781 : aValue.Length() * 2, // Length in bytes!
114 83562 : SQLITE_TRANSIENT);
115 : }
116 :
117 : int
118 26340 : sqlite3_T_null(BindingColumnData aData)
119 : {
120 26340 : return ::sqlite3_bind_null(aData.stmt, aData.column + 1);
121 : }
122 :
123 : int
124 8044 : 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 8044 : NS_Free);
130 :
131 : }
132 :
133 : #include "variantToSQLiteT_impl.h"
134 :
135 : } // anonymous namespace
136 :
137 : ////////////////////////////////////////////////////////////////////////////////
138 : //// BindingParams
139 :
140 88723 : BindingParams::BindingParams(mozIStorageBindingParamsArray *aOwningArray,
141 : Statement *aOwningStatement)
142 : : mLocked(false)
143 : , mOwningArray(aOwningArray)
144 88723 : , mOwningStatement(aOwningStatement)
145 : {
146 88723 : (void)mOwningStatement->GetParameterCount(&mParamCount);
147 88723 : (void)mParameters.SetCapacity(mParamCount);
148 88723 : }
149 :
150 33194 : BindingParams::BindingParams(mozIStorageBindingParamsArray *aOwningArray)
151 : : mLocked(false)
152 : , mOwningArray(aOwningArray)
153 : , mOwningStatement(nsnull)
154 33194 : , mParamCount(0)
155 : {
156 33194 : }
157 :
158 33194 : AsyncBindingParams::AsyncBindingParams(
159 : mozIStorageBindingParamsArray *aOwningArray
160 : )
161 33194 : : BindingParams(aOwningArray)
162 : {
163 33194 : mNamedParameters.Init();
164 33194 : }
165 :
166 : void
167 121911 : BindingParams::lock()
168 : {
169 121911 : NS_ASSERTION(mLocked == false, "Parameters have already been locked!");
170 121911 : 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 121911 : mOwningStatement = nsnull;
176 121911 : mOwningArray = nsnull;
177 121911 : }
178 :
179 : void
180 105756 : BindingParams::unlock(Statement *aOwningStatement)
181 : {
182 105756 : NS_ASSERTION(mLocked == true, "Parameters were not yet locked!");
183 105756 : mLocked = false;
184 105756 : mOwningStatement = aOwningStatement;
185 105756 : }
186 :
187 : const mozIStorageBindingParamsArray *
188 121913 : BindingParams::getOwner() const
189 : {
190 121913 : return mOwningArray;
191 : }
192 :
193 : PLDHashOperator
194 185019 : AsyncBindingParams::iterateOverNamedParameters(const nsACString &aName,
195 : nsIVariant *aValue,
196 : void *voidClosureThunk)
197 : {
198 : NamedParameterIterationClosureThunk *closureThunk =
199 185019 : 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 370038 : nsCAutoString name(":");
204 185019 : name.Append(aName);
205 : int oneIdx = ::sqlite3_bind_parameter_index(closureThunk->statement,
206 185019 : name.get());
207 :
208 185019 : 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 185018 : aValue);
222 185018 : 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 185017 : return PL_DHASH_NEXT;
234 : }
235 :
236 : ////////////////////////////////////////////////////////////////////////////////
237 : //// nsISupports
238 :
239 1366671 : NS_IMPL_THREADSAFE_ISUPPORTS2(
240 : BindingParams
241 : , mozIStorageBindingParams
242 : , IStorageBindingParamsInternal
243 : )
244 :
245 :
246 : ////////////////////////////////////////////////////////////////////////////////
247 : //// IStorageBindingParamsInternal
248 :
249 : already_AddRefed<mozIStorageError>
250 89072 : BindingParams::bind(sqlite3_stmt *aStatement)
251 : {
252 : // Iterate through all of our stored data, and bind it.
253 326951 : for (PRInt32 i = 0; i < mParameters.Count(); i++) {
254 237883 : int rc = variantToSQLiteT(BindingColumnData(aStatement, i), mParameters[i]);
255 237883 : 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 89068 : return nsnull;
269 : }
270 :
271 : already_AddRefed<mozIStorageError>
272 33188 : 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 33188 : if (!mNamedParameters.Count())
277 361 : 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 65654 : NamedParameterIterationClosureThunk closureThunk = {this, aStatement, nsnull};
282 : (void)mNamedParameters.EnumerateRead(iterateOverNamedParameters,
283 32827 : (void *)&closureThunk);
284 :
285 32827 : 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 185026 : AsyncBindingParams::BindByName(const nsACString &aName,
308 : nsIVariant *aValue)
309 : {
310 185026 : NS_ENSURE_FALSE(mLocked, NS_ERROR_UNEXPECTED);
311 :
312 185025 : if (!mNamedParameters.Put(aName, aValue))
313 0 : return NS_ERROR_OUT_OF_MEMORY;
314 185025 : return NS_OK;
315 : }
316 :
317 :
318 : NS_IMETHODIMP
319 101194 : BindingParams::BindUTF8StringByName(const nsACString &aName,
320 : const nsACString &aValue)
321 : {
322 202388 : nsCOMPtr<nsIVariant> value(new UTF8TextVariant(aValue));
323 101194 : NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
324 :
325 101194 : return BindByName(aName, value);
326 : }
327 :
328 : NS_IMETHODIMP
329 4285 : BindingParams::BindStringByName(const nsACString &aName,
330 : const nsAString &aValue)
331 : {
332 8570 : nsCOMPtr<nsIVariant> value(new TextVariant(aValue));
333 4285 : NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
334 :
335 4285 : 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 54124 : BindingParams::BindInt32ByName(const nsACString &aName,
350 : PRInt32 aValue)
351 : {
352 108248 : nsCOMPtr<nsIVariant> value(new IntegerVariant(aValue));
353 54124 : NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
354 :
355 54124 : return BindByName(aName, value);
356 : }
357 :
358 : NS_IMETHODIMP
359 122363 : BindingParams::BindInt64ByName(const nsACString &aName,
360 : PRInt64 aValue)
361 : {
362 244726 : nsCOMPtr<nsIVariant> value(new IntegerVariant(aValue));
363 122363 : NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
364 :
365 122363 : return BindByName(aName, value);
366 : }
367 :
368 : NS_IMETHODIMP
369 7700 : BindingParams::BindNullByName(const nsACString &aName)
370 : {
371 15400 : nsCOMPtr<nsIVariant> value(new NullVariant());
372 7700 : NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
373 :
374 7700 : return BindByName(aName, value);
375 : }
376 :
377 : NS_IMETHODIMP
378 7381 : BindingParams::BindBlobByName(const nsACString &aName,
379 : const PRUint8 *aValue,
380 : PRUint32 aValueSize)
381 : {
382 7381 : NS_ENSURE_ARG_MAX(aValueSize, INT_MAX);
383 : std::pair<const void *, int> data(
384 : static_cast<const void *>(aValue),
385 : int(aValueSize)
386 7381 : );
387 14762 : nsCOMPtr<nsIVariant> value(new BlobVariant(data));
388 7381 : NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
389 :
390 7381 : return BindByName(aName, value);
391 : }
392 :
393 : NS_IMETHODIMP
394 237506 : BindingParams::BindByIndex(PRUint32 aIndex,
395 : nsIVariant *aValue)
396 : {
397 237506 : NS_ENSURE_FALSE(mLocked, NS_ERROR_UNEXPECTED);
398 237506 : ENSURE_INDEX_VALUE(aIndex, mParamCount);
399 :
400 : // Store the variant for later use.
401 237504 : NS_ENSURE_TRUE(mParameters.ReplaceObjectAt(aValue, aIndex),
402 : NS_ERROR_OUT_OF_MEMORY);
403 237504 : return NS_OK;
404 : }
405 :
406 : NS_IMETHODIMP
407 395 : AsyncBindingParams::BindByIndex(PRUint32 aIndex,
408 : nsIVariant *aValue)
409 : {
410 395 : 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 395 : NS_ENSURE_TRUE(mParameters.ReplaceObjectAt(aValue, aIndex),
416 : NS_ERROR_OUT_OF_MEMORY);
417 395 : return NS_OK;
418 : }
419 :
420 : NS_IMETHODIMP
421 2210 : BindingParams::BindUTF8StringByIndex(PRUint32 aIndex,
422 : const nsACString &aValue)
423 : {
424 4420 : nsCOMPtr<nsIVariant> value(new UTF8TextVariant(aValue));
425 2210 : NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
426 :
427 2210 : return BindByIndex(aIndex, value);
428 : }
429 :
430 : NS_IMETHODIMP
431 103 : BindingParams::BindStringByIndex(PRUint32 aIndex,
432 : const nsAString &aValue)
433 : {
434 206 : nsCOMPtr<nsIVariant> value(new TextVariant(aValue));
435 103 : NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
436 :
437 103 : 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 2441 : BindingParams::BindInt32ByIndex(PRUint32 aIndex,
452 : PRInt32 aValue)
453 : {
454 4882 : nsCOMPtr<nsIVariant> value(new IntegerVariant(aValue));
455 2441 : NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
456 :
457 2441 : return BindByIndex(aIndex, value);
458 : }
459 :
460 : NS_IMETHODIMP
461 1156 : BindingParams::BindInt64ByIndex(PRUint32 aIndex,
462 : PRInt64 aValue)
463 : {
464 2312 : nsCOMPtr<nsIVariant> value(new IntegerVariant(aValue));
465 1156 : NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
466 :
467 1156 : return BindByIndex(aIndex, value);
468 : }
469 :
470 : NS_IMETHODIMP
471 331 : BindingParams::BindNullByIndex(PRUint32 aIndex)
472 : {
473 662 : nsCOMPtr<nsIVariant> value(new NullVariant());
474 331 : NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
475 :
476 331 : return BindByIndex(aIndex, value);
477 : }
478 :
479 : NS_IMETHODIMP
480 665 : BindingParams::BindBlobByIndex(PRUint32 aIndex,
481 : const PRUint8 *aValue,
482 : PRUint32 aValueSize)
483 : {
484 665 : NS_ENSURE_ARG_MAX(aValueSize, INT_MAX);
485 : std::pair<const void *, int> data(
486 : static_cast<const void *>(aValue),
487 : int(aValueSize)
488 665 : );
489 1330 : nsCOMPtr<nsIVariant> value(new BlobVariant(data));
490 665 : NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
491 :
492 665 : return BindByIndex(aIndex, value);
493 : }
494 :
495 : } // namespace storage
496 : } // namespace mozilla
|