/src/mozilla-central/storage/mozStorageStatementJSHelper.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 "nsIXPConnect.h" |
8 | | #include "mozStorageStatement.h" |
9 | | #include "mozStorageService.h" |
10 | | |
11 | | #include "nsMemory.h" |
12 | | #include "nsString.h" |
13 | | #include "nsServiceManagerUtils.h" |
14 | | |
15 | | #include "mozStorageStatementJSHelper.h" |
16 | | |
17 | | #include "mozStorageStatementRow.h" |
18 | | #include "mozStorageStatementParams.h" |
19 | | |
20 | | #include "jsapi.h" |
21 | | |
22 | | #include "xpc_make_class.h" |
23 | | |
24 | | #include "mozilla/Services.h" |
25 | | |
26 | | namespace mozilla { |
27 | | namespace storage { |
28 | | |
29 | | //////////////////////////////////////////////////////////////////////////////// |
30 | | //// Global Functions |
31 | | |
32 | | static |
33 | | bool |
34 | | stepFunc(JSContext *aCtx, uint32_t argc, JS::Value *_vp) |
35 | 0 | { |
36 | 0 | JS::CallArgs args = CallArgsFromVp(argc, _vp); |
37 | 0 |
|
38 | 0 | nsCOMPtr<nsIXPConnect> xpc(nsIXPConnect::XPConnect()); |
39 | 0 | nsCOMPtr<nsIXPConnectWrappedNative> wrapper; |
40 | 0 |
|
41 | 0 | if (!args.thisv().isObject()) { |
42 | 0 | ::JS_ReportErrorASCII(aCtx, "mozIStorageStatement::step() requires object"); |
43 | 0 | return false; |
44 | 0 | } |
45 | 0 | |
46 | 0 | JSObject *obj = &args.thisv().toObject(); |
47 | 0 | nsresult rv = |
48 | 0 | xpc->GetWrappedNativeOfJSObject(aCtx, obj, getter_AddRefs(wrapper)); |
49 | 0 | if (NS_FAILED(rv)) { |
50 | 0 | ::JS_ReportErrorASCII(aCtx, "mozIStorageStatement::step() could not obtain native statement"); |
51 | 0 | return false; |
52 | 0 | } |
53 | 0 | |
54 | | #ifdef DEBUG |
55 | | { |
56 | | nsCOMPtr<mozIStorageStatement> isStatement( |
57 | | do_QueryInterface(wrapper->Native()) |
58 | | ); |
59 | | NS_ASSERTION(isStatement, "How is this not a statement?!"); |
60 | | } |
61 | | #endif |
62 | | |
63 | 0 | Statement *stmt = static_cast<Statement *>( |
64 | 0 | static_cast<mozIStorageStatement *>(wrapper->Native()) |
65 | 0 | ); |
66 | 0 |
|
67 | 0 | bool hasMore = false; |
68 | 0 | rv = stmt->ExecuteStep(&hasMore); |
69 | 0 | if (NS_SUCCEEDED(rv) && !hasMore) { |
70 | 0 | args.rval().setBoolean(false); |
71 | 0 | (void)stmt->Reset(); |
72 | 0 | return true; |
73 | 0 | } |
74 | 0 | |
75 | 0 | if (NS_FAILED(rv)) { |
76 | 0 | ::JS_ReportErrorASCII(aCtx, "mozIStorageStatement::step() returned an error"); |
77 | 0 | return false; |
78 | 0 | } |
79 | 0 | |
80 | 0 | args.rval().setBoolean(hasMore); |
81 | 0 | return true; |
82 | 0 | } |
83 | | |
84 | | //////////////////////////////////////////////////////////////////////////////// |
85 | | //// StatementJSHelper |
86 | | |
87 | | nsresult |
88 | | StatementJSHelper::getRow(Statement *aStatement, |
89 | | JSContext *aCtx, |
90 | | JSObject *aScopeObj, |
91 | | JS::Value *_row) |
92 | 0 | { |
93 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
94 | 0 |
|
95 | | #ifdef DEBUG |
96 | | int32_t state; |
97 | | (void)aStatement->GetState(&state); |
98 | | NS_ASSERTION(state == mozIStorageStatement::MOZ_STORAGE_STATEMENT_EXECUTING, |
99 | | "Invalid state to get the row object - all calls will fail!"); |
100 | | #endif |
101 | |
|
102 | 0 | JS::RootedObject scope(aCtx, aScopeObj); |
103 | 0 |
|
104 | 0 | if (!aStatement->mStatementRowHolder) { |
105 | 0 | dom::GlobalObject global(aCtx, scope); |
106 | 0 | if (global.Failed()) { |
107 | 0 | return NS_ERROR_UNEXPECTED; |
108 | 0 | } |
109 | 0 | |
110 | 0 | nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(global.GetAsSupports()); |
111 | 0 |
|
112 | 0 | RefPtr<StatementRow> row(new StatementRow(window, aStatement)); |
113 | 0 | NS_ENSURE_TRUE(row, NS_ERROR_OUT_OF_MEMORY); |
114 | 0 |
|
115 | 0 | RefPtr<StatementRowHolder> rowHolder = new StatementRowHolder(row); |
116 | 0 | NS_ENSURE_TRUE(rowHolder, NS_ERROR_OUT_OF_MEMORY); |
117 | 0 |
|
118 | 0 | aStatement->mStatementRowHolder = |
119 | 0 | new nsMainThreadPtrHolder<StatementRowHolder>( |
120 | 0 | "Statement::mStatementRowHolder", rowHolder); |
121 | 0 | } |
122 | 0 |
|
123 | 0 | RefPtr<StatementRow> row(aStatement->mStatementRowHolder->Get()); |
124 | 0 | JSObject* obj = row->WrapObject(aCtx, nullptr); |
125 | 0 | if (!obj) { |
126 | 0 | return NS_ERROR_UNEXPECTED; |
127 | 0 | } |
128 | 0 | |
129 | 0 | _row->setObject(*obj); |
130 | 0 | return NS_OK; |
131 | 0 | } |
132 | | |
133 | | nsresult |
134 | | StatementJSHelper::getParams(Statement *aStatement, |
135 | | JSContext *aCtx, |
136 | | JSObject *aScopeObj, |
137 | | JS::Value *_params) |
138 | 0 | { |
139 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
140 | 0 |
|
141 | | #ifdef DEBUG |
142 | | int32_t state; |
143 | | (void)aStatement->GetState(&state); |
144 | | NS_ASSERTION(state == mozIStorageStatement::MOZ_STORAGE_STATEMENT_READY, |
145 | | "Invalid state to get the params object - all calls will fail!"); |
146 | | #endif |
147 | |
|
148 | 0 | JS::RootedObject scope(aCtx, aScopeObj); |
149 | 0 |
|
150 | 0 | if (!aStatement->mStatementParamsHolder) { |
151 | 0 | dom::GlobalObject global(aCtx, scope); |
152 | 0 | if (global.Failed()) { |
153 | 0 | return NS_ERROR_UNEXPECTED; |
154 | 0 | } |
155 | 0 | |
156 | 0 | nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(global.GetAsSupports()); |
157 | 0 |
|
158 | 0 | RefPtr<StatementParams> params(new StatementParams(window, aStatement)); |
159 | 0 | NS_ENSURE_TRUE(params, NS_ERROR_OUT_OF_MEMORY); |
160 | 0 |
|
161 | 0 | RefPtr<StatementParamsHolder> paramsHolder = new StatementParamsHolder(params); |
162 | 0 | NS_ENSURE_TRUE(paramsHolder, NS_ERROR_OUT_OF_MEMORY); |
163 | 0 |
|
164 | 0 | aStatement->mStatementParamsHolder = |
165 | 0 | new nsMainThreadPtrHolder<StatementParamsHolder>( |
166 | 0 | "Statement::mStatementParamsHolder", paramsHolder); |
167 | 0 | } |
168 | 0 |
|
169 | 0 | RefPtr<StatementParams> params(aStatement->mStatementParamsHolder->Get()); |
170 | 0 | JSObject* obj = params->WrapObject(aCtx, nullptr); |
171 | 0 | if (!obj) { |
172 | 0 | return NS_ERROR_UNEXPECTED; |
173 | 0 | } |
174 | 0 | |
175 | 0 | _params->setObject(*obj); |
176 | 0 | return NS_OK; |
177 | 0 | } |
178 | | |
179 | 0 | NS_IMETHODIMP_(MozExternalRefCountType) StatementJSHelper::AddRef() { return 2; } |
180 | 0 | NS_IMETHODIMP_(MozExternalRefCountType) StatementJSHelper::Release() { return 1; } |
181 | 0 | NS_INTERFACE_MAP_BEGIN(StatementJSHelper) |
182 | 0 | NS_INTERFACE_MAP_ENTRY(nsIXPCScriptable) |
183 | 0 | NS_INTERFACE_MAP_ENTRY(nsISupports) |
184 | 0 | NS_INTERFACE_MAP_END |
185 | | |
186 | | //////////////////////////////////////////////////////////////////////////////// |
187 | | //// nsIXPCScriptable |
188 | | |
189 | | #define XPC_MAP_CLASSNAME StatementJSHelper |
190 | 0 | #define XPC_MAP_QUOTED_CLASSNAME "StatementJSHelper" |
191 | 0 | #define XPC_MAP_FLAGS (XPC_SCRIPTABLE_WANT_RESOLVE | \ |
192 | 0 | XPC_SCRIPTABLE_ALLOW_PROP_MODS_DURING_RESOLVE) |
193 | | #include "xpc_map_end.h" |
194 | | |
195 | | NS_IMETHODIMP |
196 | | StatementJSHelper::Resolve(nsIXPConnectWrappedNative *aWrapper, |
197 | | JSContext *aCtx, JSObject *aScopeObj, |
198 | | jsid aId, bool *aResolvedp, |
199 | | bool *_retval) |
200 | 0 | { |
201 | 0 | if (!JSID_IS_STRING(aId)) |
202 | 0 | return NS_OK; |
203 | 0 | |
204 | 0 | JS::Rooted<JSObject*> scope(aCtx, aScopeObj); |
205 | 0 | JS::Rooted<jsid> id(aCtx, aId); |
206 | 0 |
|
207 | | #ifdef DEBUG |
208 | | { |
209 | | nsCOMPtr<mozIStorageStatement> isStatement( |
210 | | do_QueryInterface(aWrapper->Native())); |
211 | | NS_ASSERTION(isStatement, "How is this not a statement?!"); |
212 | | } |
213 | | #endif |
214 | |
|
215 | 0 | Statement *stmt = static_cast<Statement *>( |
216 | 0 | static_cast<mozIStorageStatement *>(aWrapper->Native()) |
217 | 0 | ); |
218 | 0 |
|
219 | 0 | JSFlatString* str = JSID_TO_FLAT_STRING(id); |
220 | 0 | if (::JS_FlatStringEqualsAscii(str, "step")) { |
221 | 0 | *_retval = ::JS_DefineFunction(aCtx, scope, "step", stepFunc, |
222 | 0 | 0, JSPROP_RESOLVING) != nullptr; |
223 | 0 | *aResolvedp = true; |
224 | 0 | return NS_OK; |
225 | 0 | } |
226 | 0 | |
227 | 0 | JS::RootedValue val(aCtx); |
228 | 0 |
|
229 | 0 | if (::JS_FlatStringEqualsAscii(str, "row")) { |
230 | 0 | nsresult rv = getRow(stmt, aCtx, scope, val.address()); |
231 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
232 | 0 | *_retval = ::JS_DefinePropertyById(aCtx, scope, id, val, JSPROP_RESOLVING); |
233 | 0 | *aResolvedp = true; |
234 | 0 | return NS_OK; |
235 | 0 | } |
236 | 0 | |
237 | 0 | if (::JS_FlatStringEqualsAscii(str, "params")) { |
238 | 0 | nsresult rv = getParams(stmt, aCtx, scope, val.address()); |
239 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
240 | 0 | *_retval = ::JS_DefinePropertyById(aCtx, scope, id, val, JSPROP_RESOLVING); |
241 | 0 | *aResolvedp = true; |
242 | 0 | return NS_OK; |
243 | 0 | } |
244 | 0 | |
245 | 0 | return NS_OK; |
246 | 0 | } |
247 | | |
248 | | NS_IMPL_ISUPPORTS0(StatementParamsHolder); |
249 | | |
250 | | StatementParamsHolder::~StatementParamsHolder() |
251 | 0 | { |
252 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
253 | 0 | // We are considered dead at this point, so any wrappers for row or params |
254 | 0 | // need to lose their reference to the statement. |
255 | 0 | mParams->mStatement = nullptr; |
256 | 0 | } |
257 | | |
258 | | NS_IMPL_ISUPPORTS0(StatementRowHolder); |
259 | | |
260 | | StatementRowHolder::~StatementRowHolder() |
261 | 0 | { |
262 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
263 | 0 | // We are considered dead at this point, so any wrappers for row or params |
264 | 0 | // need to lose their reference to the statement. |
265 | 0 | mRow->mStatement = nullptr; |
266 | 0 | } |
267 | | |
268 | | } // namespace storage |
269 | | } // namespace mozilla |