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