|
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 "nsThreadUtils.h" |
|
17 #include "nsJSUtils.h" |
|
18 |
|
19 #include "Variant.h" |
|
20 #include "mozStoragePrivateHelpers.h" |
|
21 #include "mozIStorageStatement.h" |
|
22 #include "mozIStorageCompletionCallback.h" |
|
23 #include "mozIStorageBindingParams.h" |
|
24 |
|
25 #include "prlog.h" |
|
26 #ifdef PR_LOGGING |
|
27 extern PRLogModuleInfo* gStorageLog; |
|
28 #endif |
|
29 |
|
30 namespace mozilla { |
|
31 namespace storage { |
|
32 |
|
33 nsresult |
|
34 convertResultCode(int aSQLiteResultCode) |
|
35 { |
|
36 // Drop off the extended result bits of the result code. |
|
37 int rc = aSQLiteResultCode & 0xFF; |
|
38 |
|
39 switch (rc) { |
|
40 case SQLITE_OK: |
|
41 case SQLITE_ROW: |
|
42 case SQLITE_DONE: |
|
43 return NS_OK; |
|
44 case SQLITE_CORRUPT: |
|
45 case SQLITE_NOTADB: |
|
46 return NS_ERROR_FILE_CORRUPTED; |
|
47 case SQLITE_PERM: |
|
48 case SQLITE_CANTOPEN: |
|
49 return NS_ERROR_FILE_ACCESS_DENIED; |
|
50 case SQLITE_BUSY: |
|
51 return NS_ERROR_STORAGE_BUSY; |
|
52 case SQLITE_LOCKED: |
|
53 return NS_ERROR_FILE_IS_LOCKED; |
|
54 case SQLITE_READONLY: |
|
55 return NS_ERROR_FILE_READ_ONLY; |
|
56 case SQLITE_IOERR: |
|
57 return NS_ERROR_STORAGE_IOERR; |
|
58 case SQLITE_FULL: |
|
59 case SQLITE_TOOBIG: |
|
60 return NS_ERROR_FILE_NO_DEVICE_SPACE; |
|
61 case SQLITE_NOMEM: |
|
62 return NS_ERROR_OUT_OF_MEMORY; |
|
63 case SQLITE_MISUSE: |
|
64 return NS_ERROR_UNEXPECTED; |
|
65 case SQLITE_ABORT: |
|
66 case SQLITE_INTERRUPT: |
|
67 return NS_ERROR_ABORT; |
|
68 case SQLITE_CONSTRAINT: |
|
69 return NS_ERROR_STORAGE_CONSTRAINT; |
|
70 } |
|
71 |
|
72 // generic error |
|
73 #ifdef DEBUG |
|
74 nsAutoCString message; |
|
75 message.AppendLiteral("SQLite returned error code "); |
|
76 message.AppendInt(rc); |
|
77 message.AppendLiteral(" , Storage will convert it to NS_ERROR_FAILURE"); |
|
78 NS_WARNING(message.get()); |
|
79 #endif |
|
80 return NS_ERROR_FAILURE; |
|
81 } |
|
82 |
|
83 void |
|
84 checkAndLogStatementPerformance(sqlite3_stmt *aStatement) |
|
85 { |
|
86 // Check to see if the query performed sorting operations or not. If it |
|
87 // did, it may need to be optimized! |
|
88 int count = ::sqlite3_stmt_status(aStatement, SQLITE_STMTSTATUS_SORT, 1); |
|
89 if (count <= 0) |
|
90 return; |
|
91 |
|
92 const char *sql = ::sqlite3_sql(aStatement); |
|
93 |
|
94 // Check to see if this is marked to not warn |
|
95 if (::strstr(sql, "/* do not warn (bug ")) |
|
96 return; |
|
97 |
|
98 nsAutoCString message; |
|
99 message.AppendInt(count); |
|
100 if (count == 1) |
|
101 message.Append(" sort operation has "); |
|
102 else |
|
103 message.Append(" sort operations have "); |
|
104 message.Append("occurred for the SQL statement '"); |
|
105 nsPrintfCString address("0x%p", aStatement); |
|
106 message.Append(address); |
|
107 message.Append("'. See https://developer.mozilla.org/En/Storage/Warnings " |
|
108 "details."); |
|
109 NS_WARNING(message.get()); |
|
110 } |
|
111 |
|
112 nsIVariant * |
|
113 convertJSValToVariant( |
|
114 JSContext *aCtx, |
|
115 JS::Value aValue) |
|
116 { |
|
117 if (aValue.isInt32()) |
|
118 return new IntegerVariant(aValue.toInt32()); |
|
119 |
|
120 if (aValue.isDouble()) |
|
121 return new FloatVariant(aValue.toDouble()); |
|
122 |
|
123 if (aValue.isString()) { |
|
124 nsDependentJSString value; |
|
125 if (!value.init(aCtx, aValue)) |
|
126 return nullptr; |
|
127 return new TextVariant(value); |
|
128 } |
|
129 |
|
130 if (aValue.isBoolean()) |
|
131 return new IntegerVariant(aValue.isTrue() ? 1 : 0); |
|
132 |
|
133 if (aValue.isNull()) |
|
134 return new NullVariant(); |
|
135 |
|
136 if (aValue.isObject()) { |
|
137 JSObject* obj = &aValue.toObject(); |
|
138 // We only support Date instances, all others fail. |
|
139 if (!::js_DateIsValid(obj)) |
|
140 return nullptr; |
|
141 |
|
142 double msecd = ::js_DateGetMsecSinceEpoch(obj); |
|
143 msecd *= 1000.0; |
|
144 int64_t msec = msecd; |
|
145 |
|
146 return new IntegerVariant(msec); |
|
147 } |
|
148 |
|
149 return nullptr; |
|
150 } |
|
151 |
|
152 namespace { |
|
153 class CallbackEvent : public nsRunnable |
|
154 { |
|
155 public: |
|
156 CallbackEvent(mozIStorageCompletionCallback *aCallback) |
|
157 : mCallback(aCallback) |
|
158 { |
|
159 } |
|
160 |
|
161 NS_IMETHOD Run() |
|
162 { |
|
163 (void)mCallback->Complete(NS_OK, nullptr); |
|
164 return NS_OK; |
|
165 } |
|
166 private: |
|
167 nsCOMPtr<mozIStorageCompletionCallback> mCallback; |
|
168 }; |
|
169 } // anonymous namespace |
|
170 already_AddRefed<nsIRunnable> |
|
171 newCompletionEvent(mozIStorageCompletionCallback *aCallback) |
|
172 { |
|
173 NS_ASSERTION(aCallback, "Passing a null callback is a no-no!"); |
|
174 nsCOMPtr<nsIRunnable> event = new CallbackEvent(aCallback); |
|
175 return event.forget(); |
|
176 } |
|
177 |
|
178 |
|
179 |
|
180 } // namespace storage |
|
181 } // namespace mozilla |