Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/storage/mozStorageBindingParams.cpp
Line
Count
Source (jump to first uncovered line)
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/. */
6
7
#include <limits.h>
8
9
#include "mozilla/UniquePtrExtensions.h"
10
#include "nsString.h"
11
12
#include "mozStorageError.h"
13
#include "mozStoragePrivateHelpers.h"
14
#include "mozStorageBindingParams.h"
15
#include "mozStorageBindingParamsArray.h"
16
#include "Variant.h"
17
18
namespace mozilla {
19
namespace storage {
20
21
////////////////////////////////////////////////////////////////////////////////
22
//// Local Helper Objects
23
24
namespace {
25
26
struct BindingColumnData
27
{
28
  BindingColumnData(sqlite3_stmt *aStmt,
29
                    int aColumn)
30
  : stmt(aStmt)
31
  , column(aColumn)
32
0
  {
33
0
  }
34
  sqlite3_stmt *stmt;
35
  int column;
36
};
37
38
////////////////////////////////////////////////////////////////////////////////
39
//// Variant Specialization Functions (variantToSQLiteT)
40
41
int
42
sqlite3_T_int(BindingColumnData aData,
43
              int aValue)
44
0
{
45
0
  return ::sqlite3_bind_int(aData.stmt, aData.column + 1, aValue);
46
0
}
47
48
int
49
sqlite3_T_int64(BindingColumnData aData,
50
                sqlite3_int64 aValue)
51
0
{
52
0
  return ::sqlite3_bind_int64(aData.stmt, aData.column + 1, aValue);
53
0
}
54
55
int
56
sqlite3_T_double(BindingColumnData aData,
57
                 double aValue)
58
0
{
59
0
  return ::sqlite3_bind_double(aData.stmt, aData.column + 1, aValue);
60
0
}
61
62
int
63
sqlite3_T_text(BindingColumnData aData,
64
               const nsCString& aValue)
65
0
{
66
0
  return ::sqlite3_bind_text(aData.stmt,
67
0
                             aData.column + 1,
68
0
                             aValue.get(),
69
0
                             aValue.Length(),
70
0
                             SQLITE_TRANSIENT);
71
0
}
72
73
int
74
sqlite3_T_text16(BindingColumnData aData,
75
                 const nsString& aValue)
76
0
{
77
0
  return ::sqlite3_bind_text16(aData.stmt,
78
0
                               aData.column + 1,
79
0
                               aValue.get(),
80
0
                               aValue.Length() * 2, // Length in bytes!
81
0
                               SQLITE_TRANSIENT);
82
0
}
83
84
int
85
sqlite3_T_null(BindingColumnData aData)
86
0
{
87
0
  return ::sqlite3_bind_null(aData.stmt, aData.column + 1);
88
0
}
89
90
int
91
sqlite3_T_blob(BindingColumnData aData,
92
               const void *aBlob,
93
               int aSize)
94
0
{
95
0
  return ::sqlite3_bind_blob(aData.stmt, aData.column + 1, aBlob, aSize,
96
0
                             free);
97
0
98
0
}
99
100
#include "variantToSQLiteT_impl.h"
101
102
} // namespace
103
104
////////////////////////////////////////////////////////////////////////////////
105
//// BindingParams
106
107
BindingParams::BindingParams(mozIStorageBindingParamsArray *aOwningArray,
108
                             Statement *aOwningStatement)
109
: mLocked(false)
110
, mOwningArray(aOwningArray)
111
, mOwningStatement(aOwningStatement)
112
, mParamCount(0)
113
0
{
114
0
  (void)mOwningStatement->GetParameterCount(&mParamCount);
115
0
  mParameters.SetCapacity(mParamCount);
116
0
}
117
118
BindingParams::BindingParams(mozIStorageBindingParamsArray *aOwningArray)
119
: mLocked(false)
120
, mOwningArray(aOwningArray)
121
, mOwningStatement(nullptr)
122
, mParamCount(0)
123
0
{
124
0
}
125
126
AsyncBindingParams::AsyncBindingParams(
127
  mozIStorageBindingParamsArray *aOwningArray
128
)
129
: BindingParams(aOwningArray)
130
0
{
131
0
}
132
133
void
134
BindingParams::lock()
135
0
{
136
0
  NS_ASSERTION(mLocked == false, "Parameters have already been locked!");
137
0
  mLocked = true;
138
0
139
0
  // We no longer need to hold a reference to our statement or our owning array.
140
0
  // The array owns us at this point, and it will own a reference to the
141
0
  // statement.
142
0
  mOwningStatement = nullptr;
143
0
  mOwningArray = nullptr;
144
0
}
145
146
void
147
BindingParams::unlock(Statement *aOwningStatement)
148
0
{
149
0
  NS_ASSERTION(mLocked == true, "Parameters were not yet locked!");
150
0
  mLocked = false;
151
0
  mOwningStatement = aOwningStatement;
152
0
}
153
154
const mozIStorageBindingParamsArray *
155
BindingParams::getOwner() const
156
0
{
157
0
  return mOwningArray;
158
0
}
159
160
////////////////////////////////////////////////////////////////////////////////
161
//// nsISupports
162
163
NS_IMPL_ISUPPORTS(
164
  BindingParams
165
, mozIStorageBindingParams
166
, IStorageBindingParamsInternal
167
)
168
169
170
////////////////////////////////////////////////////////////////////////////////
171
//// IStorageBindingParamsInternal
172
173
already_AddRefed<mozIStorageError>
174
BindingParams::bind(sqlite3_stmt *aStatement)
175
0
{
176
0
  // Iterate through all of our stored data, and bind it.
177
0
  for (size_t i = 0; i < mParameters.Length(); i++) {
178
0
    int rc = variantToSQLiteT(BindingColumnData(aStatement, i), mParameters[i]);
179
0
    if (rc != SQLITE_OK) {
180
0
      // We had an error while trying to bind.  Now we need to create an error
181
0
      // object with the right message.  Note that we special case
182
0
      // SQLITE_MISMATCH, but otherwise get the message from SQLite.
183
0
      const char *msg = "Could not covert nsIVariant to SQLite type.";
184
0
      if (rc != SQLITE_MISMATCH)
185
0
        msg = ::sqlite3_errmsg(::sqlite3_db_handle(aStatement));
186
0
187
0
      nsCOMPtr<mozIStorageError> err(new Error(rc, msg));
188
0
      return err.forget();
189
0
    }
190
0
  }
191
0
192
0
  return nullptr;
193
0
}
194
195
already_AddRefed<mozIStorageError>
196
AsyncBindingParams::bind(sqlite3_stmt * aStatement)
197
0
{
198
0
  // We should bind by index using the super-class if there is nothing in our
199
0
  // hashtable.
200
0
  if (!mNamedParameters.Count())
201
0
    return BindingParams::bind(aStatement);
202
0
203
0
  nsCOMPtr<mozIStorageError> err;
204
0
205
0
  for (auto iter = mNamedParameters.Iter(); !iter.Done(); iter.Next()) {
206
0
    const nsACString &key = iter.Key();
207
0
208
0
    // We do not accept any forms of names other than ":name", but we need to
209
0
    // add the colon for SQLite.
210
0
    nsAutoCString name(":");
211
0
    name.Append(key);
212
0
    int oneIdx = ::sqlite3_bind_parameter_index(aStatement, name.get());
213
0
214
0
    if (oneIdx == 0) {
215
0
      nsAutoCString errMsg(key);
216
0
      errMsg.AppendLiteral(" is not a valid named parameter.");
217
0
      err = new Error(SQLITE_RANGE, errMsg.get());
218
0
      break;
219
0
    }
220
0
221
0
    // XPCVariant's AddRef and Release are not thread-safe and so we must not
222
0
    // do anything that would invoke them here on the async thread.  As such we
223
0
    // can't cram aValue into mParameters using ReplaceObjectAt so that
224
0
    // we can freeload off of the BindingParams::Bind implementation.
225
0
    int rc = variantToSQLiteT(BindingColumnData(aStatement, oneIdx - 1),
226
0
                              iter.UserData());
227
0
    if (rc != SQLITE_OK) {
228
0
      // We had an error while trying to bind.  Now we need to create an error
229
0
      // object with the right message.  Note that we special case
230
0
      // SQLITE_MISMATCH, but otherwise get the message from SQLite.
231
0
      const char *msg = "Could not covert nsIVariant to SQLite type.";
232
0
      if (rc != SQLITE_MISMATCH) {
233
0
        msg = ::sqlite3_errmsg(::sqlite3_db_handle(aStatement));
234
0
      }
235
0
      err = new Error(rc, msg);
236
0
      break;
237
0
    }
238
0
  }
239
0
240
0
  return err.forget();
241
0
}
242
243
244
///////////////////////////////////////////////////////////////////////////////
245
//// mozIStorageBindingParams
246
247
NS_IMETHODIMP
248
BindingParams::BindByName(const nsACString &aName,
249
                          nsIVariant *aValue)
250
0
{
251
0
  NS_ENSURE_FALSE(mLocked, NS_ERROR_UNEXPECTED);
252
0
253
0
  // Get the column index that we need to store this at.
254
0
  uint32_t index;
255
0
  nsresult rv = mOwningStatement->GetParameterIndex(aName, &index);
256
0
  NS_ENSURE_SUCCESS(rv, rv);
257
0
258
0
  return BindByIndex(index, aValue);
259
0
}
260
261
NS_IMETHODIMP
262
AsyncBindingParams::BindByName(const nsACString &aName,
263
                               nsIVariant *aValue)
264
0
{
265
0
  NS_ENSURE_FALSE(mLocked, NS_ERROR_UNEXPECTED);
266
0
267
0
  RefPtr<Variant_base> variant = convertVariantToStorageVariant(aValue);
268
0
  if (!variant)
269
0
    return NS_ERROR_UNEXPECTED;
270
0
271
0
  mNamedParameters.Put(aName, variant);
272
0
  return NS_OK;
273
0
}
274
275
276
NS_IMETHODIMP
277
BindingParams::BindUTF8StringByName(const nsACString &aName,
278
                                    const nsACString &aValue)
279
0
{
280
0
  nsCOMPtr<nsIVariant> value(new UTF8TextVariant(aValue));
281
0
  NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
282
0
283
0
  return BindByName(aName, value);
284
0
}
285
286
NS_IMETHODIMP
287
BindingParams::BindStringByName(const nsACString &aName,
288
                                const nsAString &aValue)
289
0
{
290
0
  nsCOMPtr<nsIVariant> value(new TextVariant(aValue));
291
0
  NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
292
0
293
0
  return BindByName(aName, value);
294
0
}
295
296
NS_IMETHODIMP
297
BindingParams::BindDoubleByName(const nsACString &aName,
298
                                double aValue)
299
0
{
300
0
  nsCOMPtr<nsIVariant> value(new FloatVariant(aValue));
301
0
  NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
302
0
303
0
  return BindByName(aName, value);
304
0
}
305
306
NS_IMETHODIMP
307
BindingParams::BindInt32ByName(const nsACString &aName,
308
                               int32_t aValue)
309
0
{
310
0
  nsCOMPtr<nsIVariant> value(new IntegerVariant(aValue));
311
0
  NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
312
0
313
0
  return BindByName(aName, value);
314
0
}
315
316
NS_IMETHODIMP
317
BindingParams::BindInt64ByName(const nsACString &aName,
318
                               int64_t aValue)
319
0
{
320
0
  nsCOMPtr<nsIVariant> value(new IntegerVariant(aValue));
321
0
  NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
322
0
323
0
  return BindByName(aName, value);
324
0
}
325
326
NS_IMETHODIMP
327
BindingParams::BindNullByName(const nsACString &aName)
328
0
{
329
0
  nsCOMPtr<nsIVariant> value(new NullVariant());
330
0
  NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
331
0
332
0
  return BindByName(aName, value);
333
0
}
334
335
NS_IMETHODIMP
336
BindingParams::BindBlobByName(const nsACString &aName,
337
                              const uint8_t *aValue,
338
                              uint32_t aValueSize)
339
0
{
340
0
  NS_ENSURE_ARG_MAX(aValueSize, INT_MAX);
341
0
  std::pair<const void *, int> data(
342
0
    static_cast<const void *>(aValue),
343
0
    int(aValueSize)
344
0
  );
345
0
  nsCOMPtr<nsIVariant> value(new BlobVariant(data));
346
0
  NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
347
0
348
0
  return BindByName(aName, value);
349
0
}
350
351
NS_IMETHODIMP
352
BindingParams::BindStringAsBlobByName(const nsACString& aName,
353
                                      const nsAString& aValue)
354
0
{
355
0
  return DoBindStringAsBlobByName(this, aName, aValue);
356
0
}
357
358
NS_IMETHODIMP
359
BindingParams::BindUTF8StringAsBlobByName(const nsACString& aName,
360
                                          const nsACString& aValue)
361
0
{
362
0
  return DoBindStringAsBlobByName(this, aName, aValue);
363
0
}
364
365
366
NS_IMETHODIMP
367
BindingParams::BindAdoptedBlobByName(const nsACString &aName,
368
                                     uint8_t *aValue,
369
                                     uint32_t aValueSize)
370
0
{
371
0
  UniqueFreePtr<uint8_t> uniqueValue(aValue);
372
0
  NS_ENSURE_ARG_MAX(aValueSize, INT_MAX);
373
0
  std::pair<uint8_t *, int> data(uniqueValue.release(), int(aValueSize));
374
0
  nsCOMPtr<nsIVariant> value(new AdoptedBlobVariant(data));
375
0
376
0
  return BindByName(aName, value);
377
0
}
378
379
NS_IMETHODIMP
380
BindingParams::BindByIndex(uint32_t aIndex,
381
                           nsIVariant *aValue)
382
0
{
383
0
  NS_ENSURE_FALSE(mLocked, NS_ERROR_UNEXPECTED);
384
0
  ENSURE_INDEX_VALUE(aIndex, mParamCount);
385
0
386
0
  // Store the variant for later use.
387
0
  RefPtr<Variant_base> variant = convertVariantToStorageVariant(aValue);
388
0
  if (!variant)
389
0
    return NS_ERROR_UNEXPECTED;
390
0
  if (mParameters.Length() <= aIndex) {
391
0
    (void)mParameters.SetLength(aIndex);
392
0
    (void)mParameters.AppendElement(variant);
393
0
  }
394
0
  else {
395
0
    NS_ENSURE_TRUE(mParameters.ReplaceElementAt(aIndex, variant),
396
0
                   NS_ERROR_OUT_OF_MEMORY);
397
0
  }
398
0
  return NS_OK;
399
0
}
400
401
NS_IMETHODIMP
402
AsyncBindingParams::BindByIndex(uint32_t aIndex,
403
                                nsIVariant *aValue)
404
0
{
405
0
  NS_ENSURE_FALSE(mLocked, NS_ERROR_UNEXPECTED);
406
0
  // In the asynchronous case we do not know how many parameters there are to
407
0
  // bind to, so we cannot check the validity of aIndex.
408
0
409
0
  RefPtr<Variant_base> variant = convertVariantToStorageVariant(aValue);
410
0
  if (!variant)
411
0
    return NS_ERROR_UNEXPECTED;
412
0
  if (mParameters.Length() <= aIndex) {
413
0
    mParameters.SetLength(aIndex);
414
0
    mParameters.AppendElement(variant);
415
0
  }
416
0
  else {
417
0
    NS_ENSURE_TRUE(mParameters.ReplaceElementAt(aIndex, variant),
418
0
                   NS_ERROR_OUT_OF_MEMORY);
419
0
  }
420
0
  return NS_OK;
421
0
}
422
423
NS_IMETHODIMP
424
BindingParams::BindUTF8StringByIndex(uint32_t aIndex,
425
                                     const nsACString &aValue)
426
0
{
427
0
  nsCOMPtr<nsIVariant> value(new UTF8TextVariant(aValue));
428
0
  NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
429
0
430
0
  return BindByIndex(aIndex, value);
431
0
}
432
433
NS_IMETHODIMP
434
BindingParams::BindStringByIndex(uint32_t aIndex,
435
                                 const nsAString &aValue)
436
0
{
437
0
  nsCOMPtr<nsIVariant> value(new TextVariant(aValue));
438
0
  NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
439
0
440
0
  return BindByIndex(aIndex, value);
441
0
}
442
443
NS_IMETHODIMP
444
BindingParams::BindDoubleByIndex(uint32_t aIndex,
445
                                 double aValue)
446
0
{
447
0
  nsCOMPtr<nsIVariant> value(new FloatVariant(aValue));
448
0
  NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
449
0
450
0
  return BindByIndex(aIndex, value);
451
0
}
452
453
NS_IMETHODIMP
454
BindingParams::BindInt32ByIndex(uint32_t aIndex,
455
                                int32_t aValue)
456
0
{
457
0
  nsCOMPtr<nsIVariant> value(new IntegerVariant(aValue));
458
0
  NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
459
0
460
0
  return BindByIndex(aIndex, value);
461
0
}
462
463
NS_IMETHODIMP
464
BindingParams::BindInt64ByIndex(uint32_t aIndex,
465
                                int64_t aValue)
466
0
{
467
0
  nsCOMPtr<nsIVariant> value(new IntegerVariant(aValue));
468
0
  NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
469
0
470
0
  return BindByIndex(aIndex, value);
471
0
}
472
473
NS_IMETHODIMP
474
BindingParams::BindNullByIndex(uint32_t aIndex)
475
0
{
476
0
  nsCOMPtr<nsIVariant> value(new NullVariant());
477
0
  NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
478
0
479
0
  return BindByIndex(aIndex, value);
480
0
}
481
482
NS_IMETHODIMP
483
BindingParams::BindBlobByIndex(uint32_t aIndex,
484
                               const uint8_t *aValue,
485
                               uint32_t aValueSize)
486
0
{
487
0
  NS_ENSURE_ARG_MAX(aValueSize, INT_MAX);
488
0
  std::pair<const void *, int> data(
489
0
    static_cast<const void *>(aValue),
490
0
    int(aValueSize)
491
0
  );
492
0
  nsCOMPtr<nsIVariant> value(new BlobVariant(data));
493
0
  NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY);
494
0
495
0
  return BindByIndex(aIndex, value);
496
0
}
497
498
NS_IMETHODIMP
499
BindingParams::BindStringAsBlobByIndex(uint32_t aIndex, const nsAString& aValue)
500
0
{
501
0
  return DoBindStringAsBlobByIndex(this, aIndex, aValue);
502
0
}
503
504
NS_IMETHODIMP
505
BindingParams::BindUTF8StringAsBlobByIndex(uint32_t aIndex,
506
                                           const nsACString& aValue)
507
0
{
508
0
  return DoBindStringAsBlobByIndex(this, aIndex, aValue);
509
0
}
510
511
NS_IMETHODIMP
512
BindingParams::BindAdoptedBlobByIndex(uint32_t aIndex,
513
                                      uint8_t *aValue,
514
                                      uint32_t aValueSize)
515
0
{
516
0
  UniqueFreePtr<uint8_t> uniqueValue(aValue);
517
0
  NS_ENSURE_ARG_MAX(aValueSize, INT_MAX);
518
0
  std::pair<uint8_t *, int> data(uniqueValue.release(), int(aValueSize));
519
0
  nsCOMPtr<nsIVariant> value(new AdoptedBlobVariant(data));
520
0
521
0
  return BindByIndex(aIndex, value);
522
0
}
523
524
} // namespace storage
525
} // namespace mozilla