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 "mozStorageAsyncStatement.h"
9 #include "mozStorageService.h"
10 
11 #include "nsMemory.h"
12 #include "nsString.h"
13 #include "nsServiceManagerUtils.h"
14 
15 #include "mozStorageAsyncStatementJSHelper.h"
16 
17 #include "mozStorageAsyncStatementParams.h"
18 
19 #include "jsapi.h"
20 #include "js/PropertyAndElement.h"  // JS_DefineProperty, JS_DefinePropertyById
21 
22 #include "xpc_make_class.h"
23 
24 namespace mozilla {
25 namespace storage {
26 
27 ////////////////////////////////////////////////////////////////////////////////
28 //// AsyncStatementJSHelper
29 
getParams(AsyncStatement * aStatement,JSContext * aCtx,JSObject * aScopeObj,JS::Value * _params)30 nsresult AsyncStatementJSHelper::getParams(AsyncStatement* aStatement,
31                                            JSContext* aCtx, JSObject* aScopeObj,
32                                            JS::Value* _params) {
33   MOZ_ASSERT(NS_IsMainThread());
34 
35 #ifdef DEBUG
36   int32_t state;
37   (void)aStatement->GetState(&state);
38   NS_ASSERTION(state == mozIStorageAsyncStatement::MOZ_STORAGE_STATEMENT_READY,
39                "Invalid state to get the params object - all calls will fail!");
40 #endif
41 
42   JS::RootedObject scope(aCtx, aScopeObj);
43 
44   if (!aStatement->mStatementParamsHolder) {
45     dom::GlobalObject global(aCtx, scope);
46     if (global.Failed()) {
47       return NS_ERROR_UNEXPECTED;
48     }
49 
50     nsCOMPtr<nsPIDOMWindowInner> window =
51         do_QueryInterface(global.GetAsSupports());
52 
53     RefPtr<AsyncStatementParams> params(
54         new AsyncStatementParams(window, aStatement));
55     NS_ENSURE_TRUE(params, NS_ERROR_OUT_OF_MEMORY);
56 
57     RefPtr<AsyncStatementParamsHolder> paramsHolder =
58         new AsyncStatementParamsHolder(params);
59     NS_ENSURE_TRUE(paramsHolder, NS_ERROR_OUT_OF_MEMORY);
60 
61     aStatement->mStatementParamsHolder =
62         new nsMainThreadPtrHolder<AsyncStatementParamsHolder>(
63             "Statement::mStatementParamsHolder", paramsHolder);
64   }
65 
66   RefPtr<AsyncStatementParams> params(
67       aStatement->mStatementParamsHolder->Get());
68   JSObject* obj = params->WrapObject(aCtx, nullptr);
69   if (!obj) {
70     return NS_ERROR_UNEXPECTED;
71   }
72 
73   _params->setObject(*obj);
74   return NS_OK;
75 }
76 
NS_IMETHODIMP_(MozExternalRefCountType)77 NS_IMETHODIMP_(MozExternalRefCountType) AsyncStatementJSHelper::AddRef() {
78   return 2;
79 }
NS_IMETHODIMP_(MozExternalRefCountType)80 NS_IMETHODIMP_(MozExternalRefCountType) AsyncStatementJSHelper::Release() {
81   return 1;
82 }
83 NS_INTERFACE_MAP_BEGIN(AsyncStatementJSHelper)
NS_INTERFACE_MAP_ENTRY(nsIXPCScriptable)84   NS_INTERFACE_MAP_ENTRY(nsIXPCScriptable)
85   NS_INTERFACE_MAP_ENTRY(nsISupports)
86 NS_INTERFACE_MAP_END
87 
88 ////////////////////////////////////////////////////////////////////////////////
89 //// nsIXPCScriptable
90 
91 #define XPC_MAP_CLASSNAME AsyncStatementJSHelper
92 #define XPC_MAP_QUOTED_CLASSNAME "AsyncStatementJSHelper"
93 #define XPC_MAP_FLAGS \
94   (XPC_SCRIPTABLE_WANT_RESOLVE | XPC_SCRIPTABLE_ALLOW_PROP_MODS_DURING_RESOLVE)
95 #include "xpc_map_end.h"
96 
97 NS_IMETHODIMP
98 AsyncStatementJSHelper::Resolve(nsIXPConnectWrappedNative* aWrapper,
99                                 JSContext* aCtx, JSObject* aScopeObj, jsid aId,
100                                 bool* resolvedp, bool* _retval) {
101   if (!aId.isString()) return NS_OK;
102 
103   // Cast to async via mozI* since direct from nsISupports is ambiguous.
104   JS::RootedObject scope(aCtx, aScopeObj);
105   JS::RootedId id(aCtx, aId);
106   mozIStorageAsyncStatement* iAsyncStmt =
107       static_cast<mozIStorageAsyncStatement*>(aWrapper->Native());
108   AsyncStatement* stmt = static_cast<AsyncStatement*>(iAsyncStmt);
109 
110 #ifdef DEBUG
111   {
112     nsISupports* supp = aWrapper->Native();
113     nsCOMPtr<mozIStorageAsyncStatement> isStatement(do_QueryInterface(supp));
114     NS_ASSERTION(isStatement, "How is this not an async statement?!");
115   }
116 #endif
117 
118   if (::JS_LinearStringEqualsLiteral(id.toLinearString(), "params")) {
119     JS::RootedValue val(aCtx);
120     nsresult rv = getParams(stmt, aCtx, scope, val.address());
121     NS_ENSURE_SUCCESS(rv, rv);
122     *_retval = ::JS_DefinePropertyById(aCtx, scope, id, val, JSPROP_RESOLVING);
123     *resolvedp = true;
124     return NS_OK;
125   }
126 
127   return NS_OK;
128 }
129 
130 ////////////////////////////////////////////////////////////////////////////////
131 //// AsyncStatementParamsHolder
132 
133 NS_IMPL_ISUPPORTS0(AsyncStatementParamsHolder);
134 
~AsyncStatementParamsHolder()135 AsyncStatementParamsHolder::~AsyncStatementParamsHolder() {
136   MOZ_ASSERT(NS_IsMainThread());
137   // We are considered dead at this point, so any wrappers for row or params
138   // need to lose their reference to the statement.
139   mParams->mStatement = nullptr;
140 }
141 
142 }  // namespace storage
143 }  // namespace mozilla
144