Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/storage/mozStoragePrivateHelpers.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 "sqlite3.h"
8
9
#include "jsfriendapi.h"
10
11
#include "nsPrintfCString.h"
12
#include "nsString.h"
13
#include "nsError.h"
14
#include "mozilla/Mutex.h"
15
#include "mozilla/CondVar.h"
16
#include "nsQueryObject.h"
17
#include "nsThreadUtils.h"
18
#include "nsJSUtils.h"
19
20
#include "Variant.h"
21
#include "mozStoragePrivateHelpers.h"
22
#include "mozIStorageStatement.h"
23
#include "mozIStorageCompletionCallback.h"
24
#include "mozIStorageBindingParams.h"
25
26
#include "mozilla/Logging.h"
27
extern mozilla::LazyLogModule gStorageLog;
28
29
namespace mozilla {
30
namespace storage {
31
32
nsresult
33
convertResultCode(int aSQLiteResultCode)
34
0
{
35
0
  // Drop off the extended result bits of the result code.
36
0
  int rc = aSQLiteResultCode & 0xFF;
37
0
38
0
  switch (rc) {
39
0
    case SQLITE_OK:
40
0
    case SQLITE_ROW:
41
0
    case SQLITE_DONE:
42
0
      return NS_OK;
43
0
    case SQLITE_CORRUPT:
44
0
    case SQLITE_NOTADB:
45
0
      return NS_ERROR_FILE_CORRUPTED;
46
0
    case SQLITE_PERM:
47
0
    case SQLITE_CANTOPEN:
48
0
      return NS_ERROR_FILE_ACCESS_DENIED;
49
0
    case SQLITE_BUSY:
50
0
      return NS_ERROR_STORAGE_BUSY;
51
0
    case SQLITE_LOCKED:
52
0
      return NS_ERROR_FILE_IS_LOCKED;
53
0
    case SQLITE_READONLY:
54
0
      return NS_ERROR_FILE_READ_ONLY;
55
0
    case SQLITE_IOERR:
56
0
      return NS_ERROR_STORAGE_IOERR;
57
0
    case SQLITE_FULL:
58
0
    case SQLITE_TOOBIG:
59
0
      return NS_ERROR_FILE_NO_DEVICE_SPACE;
60
0
    case SQLITE_NOMEM:
61
0
      return NS_ERROR_OUT_OF_MEMORY;
62
0
    case SQLITE_MISUSE:
63
0
      return NS_ERROR_UNEXPECTED;
64
0
    case SQLITE_ABORT:
65
0
    case SQLITE_INTERRUPT:
66
0
      return NS_ERROR_ABORT;
67
0
    case SQLITE_CONSTRAINT:
68
0
      return NS_ERROR_STORAGE_CONSTRAINT;
69
0
  }
70
0
71
0
  // generic error
72
#ifdef DEBUG
73
  nsAutoCString message;
74
  message.AppendLiteral("SQLite returned error code ");
75
  message.AppendInt(rc);
76
  message.AppendLiteral(" , Storage will convert it to NS_ERROR_FAILURE");
77
  NS_WARNING_ASSERTION(rc == SQLITE_ERROR, message.get());
78
#endif
79
0
  return NS_ERROR_FAILURE;
80
0
}
81
82
void
83
checkAndLogStatementPerformance(sqlite3_stmt *aStatement)
84
0
{
85
0
  // Check to see if the query performed sorting operations or not.  If it
86
0
  // did, it may need to be optimized!
87
0
  int count = ::sqlite3_stmt_status(aStatement, SQLITE_STMTSTATUS_SORT, 1);
88
0
  if (count <= 0)
89
0
    return;
90
0
91
0
  const char *sql = ::sqlite3_sql(aStatement);
92
0
93
0
  // Check to see if this is marked to not warn
94
0
  if (::strstr(sql, "/* do not warn (bug "))
95
0
    return;
96
0
97
0
  // CREATE INDEX always sorts (sorting is a necessary step in creating
98
0
  // an index).  So ignore the warning there.
99
0
  if (::strstr(sql, "CREATE INDEX") || ::strstr(sql, "CREATE UNIQUE INDEX"))
100
0
    return;
101
0
102
0
  nsAutoCString message("Suboptimal indexes for the SQL statement ");
103
#ifdef MOZ_STORAGE_SORTWARNING_SQL_DUMP
104
  message.Append('`');
105
  message.Append(sql);
106
  message.AppendLiteral("` [");
107
  message.AppendInt(count);
108
  message.AppendLiteral(" sort operation(s)]");
109
#else
110
  nsPrintfCString address("0x%p", aStatement);
111
0
  message.Append(address);
112
0
#endif
113
0
  message.AppendLiteral(" (http://mzl.la/1FuID0j).");
114
0
  NS_WARNING(message.get());
115
0
}
116
117
nsIVariant *
118
convertJSValToVariant(
119
  JSContext *aCtx,
120
  const JS::Value& aValue)
121
0
{
122
0
  if (aValue.isInt32())
123
0
    return new IntegerVariant(aValue.toInt32());
124
0
125
0
  if (aValue.isDouble())
126
0
    return new FloatVariant(aValue.toDouble());
127
0
128
0
  if (aValue.isString()) {
129
0
    nsAutoJSString value;
130
0
    if (!value.init(aCtx, aValue.toString()))
131
0
        return nullptr;
132
0
    return new TextVariant(value);
133
0
  }
134
0
135
0
  if (aValue.isBoolean())
136
0
    return new IntegerVariant(aValue.isTrue() ? 1 : 0);
137
0
138
0
  if (aValue.isNull())
139
0
    return new NullVariant();
140
0
141
0
  if (aValue.isObject()) {
142
0
    JS::Rooted<JSObject*> obj(aCtx, &aValue.toObject());
143
0
    // We only support Date instances, all others fail.
144
0
    bool valid;
145
0
    if (!js::DateIsValid(aCtx, obj, &valid) || !valid)
146
0
      return nullptr;
147
0
148
0
    double msecd;
149
0
    if (!js::DateGetMsecSinceEpoch(aCtx, obj, &msecd))
150
0
      return nullptr;
151
0
152
0
    msecd *= 1000.0;
153
0
    int64_t msec = msecd;
154
0
155
0
    return new IntegerVariant(msec);
156
0
  }
157
0
158
0
  return nullptr;
159
0
}
160
161
Variant_base *
162
convertVariantToStorageVariant(nsIVariant* aVariant)
163
0
{
164
0
  RefPtr<Variant_base> variant = do_QueryObject(aVariant);
165
0
  if (variant) {
166
0
    // JS helpers already convert the JS representation to a Storage Variant,
167
0
    // in such a case there's nothing left to do here, so just pass-through.
168
0
    return variant;
169
0
  }
170
0
171
0
  if (!aVariant)
172
0
    return new NullVariant();
173
0
174
0
  uint16_t dataType;
175
0
  nsresult rv = aVariant->GetDataType(&dataType);
176
0
  NS_ENSURE_SUCCESS(rv, nullptr);
177
0
178
0
  switch (dataType) {
179
0
    case nsIDataType::VTYPE_BOOL:
180
0
    case nsIDataType::VTYPE_INT8:
181
0
    case nsIDataType::VTYPE_INT16:
182
0
    case nsIDataType::VTYPE_INT32:
183
0
    case nsIDataType::VTYPE_UINT8:
184
0
    case nsIDataType::VTYPE_UINT16:
185
0
    case nsIDataType::VTYPE_UINT32:
186
0
    case nsIDataType::VTYPE_INT64:
187
0
    case nsIDataType::VTYPE_UINT64: {
188
0
      int64_t v;
189
0
      rv = aVariant->GetAsInt64(&v);
190
0
      NS_ENSURE_SUCCESS(rv, nullptr);
191
0
      return new IntegerVariant(v);
192
0
    }
193
0
    case nsIDataType::VTYPE_FLOAT:
194
0
    case nsIDataType::VTYPE_DOUBLE: {
195
0
      double v;
196
0
      rv = aVariant->GetAsDouble(&v);
197
0
      NS_ENSURE_SUCCESS(rv, nullptr);
198
0
      return new FloatVariant(v);
199
0
    }
200
0
    case nsIDataType::VTYPE_CHAR:
201
0
    case nsIDataType::VTYPE_CHAR_STR:
202
0
    case nsIDataType::VTYPE_STRING_SIZE_IS:
203
0
    case nsIDataType::VTYPE_UTF8STRING:
204
0
    case nsIDataType::VTYPE_CSTRING: {
205
0
      nsCString v;
206
0
      rv = aVariant->GetAsAUTF8String(v);
207
0
      NS_ENSURE_SUCCESS(rv, nullptr);
208
0
      return new UTF8TextVariant(v);
209
0
    }
210
0
    case nsIDataType::VTYPE_WCHAR:
211
0
    case nsIDataType::VTYPE_DOMSTRING:
212
0
    case nsIDataType::VTYPE_WCHAR_STR:
213
0
    case nsIDataType::VTYPE_WSTRING_SIZE_IS:
214
0
    case nsIDataType::VTYPE_ASTRING: {
215
0
      nsString v;
216
0
      rv = aVariant->GetAsAString(v);
217
0
      NS_ENSURE_SUCCESS(rv, nullptr);
218
0
      return new TextVariant(v);
219
0
    }
220
0
    case nsIDataType::VTYPE_ARRAY: {
221
0
      uint16_t type;
222
0
      nsIID iid;
223
0
      uint32_t len;
224
0
      void *rawArray;
225
0
      // Note this copies the array data.
226
0
      rv = aVariant->GetAsArray(&type, &iid, &len, &rawArray);
227
0
      NS_ENSURE_SUCCESS(rv, nullptr);
228
0
      if (type == nsIDataType::VTYPE_UINT8) {
229
0
        std::pair<uint8_t *, int> v(static_cast<uint8_t *>(rawArray), len);
230
0
        // Take ownership of the data avoiding a further copy.
231
0
        return new AdoptedBlobVariant(v);
232
0
      }
233
0
      MOZ_FALLTHROUGH;
234
0
    }
235
0
    case nsIDataType::VTYPE_EMPTY:
236
0
    case nsIDataType::VTYPE_EMPTY_ARRAY:
237
0
    case nsIDataType::VTYPE_VOID:
238
0
      return new NullVariant();
239
0
    case nsIDataType::VTYPE_ID:
240
0
    case nsIDataType::VTYPE_INTERFACE:
241
0
    case nsIDataType::VTYPE_INTERFACE_IS:
242
0
    default:
243
0
      NS_WARNING("Unsupported variant type");
244
0
      return nullptr;
245
0
  }
246
0
247
0
  return nullptr;
248
0
}
249
250
namespace {
251
class CallbackEvent : public Runnable
252
{
253
public:
254
  explicit CallbackEvent(mozIStorageCompletionCallback* aCallback)
255
    : Runnable("storage::CallbackEvent")
256
    , mCallback(aCallback)
257
0
  {
258
0
  }
259
260
  NS_IMETHOD Run() override
261
0
  {
262
0
    (void)mCallback->Complete(NS_OK, nullptr);
263
0
    return NS_OK;
264
0
  }
265
private:
266
  nsCOMPtr<mozIStorageCompletionCallback> mCallback;
267
};
268
} // namespace
269
already_AddRefed<nsIRunnable>
270
newCompletionEvent(mozIStorageCompletionCallback *aCallback)
271
0
{
272
0
  NS_ASSERTION(aCallback, "Passing a null callback is a no-no!");
273
0
  nsCOMPtr<nsIRunnable> event = new CallbackEvent(aCallback);
274
0
  return event.forget();
275
0
}
276
277
} // namespace storage
278
} // namespace mozilla