|
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 "nsMemory.h" |
|
8 #include "nsString.h" |
|
9 |
|
10 #include "jsapi.h" |
|
11 |
|
12 #include "mozStoragePrivateHelpers.h" |
|
13 #include "mozStorageStatementParams.h" |
|
14 #include "mozIStorageStatement.h" |
|
15 |
|
16 namespace mozilla { |
|
17 namespace storage { |
|
18 |
|
19 //////////////////////////////////////////////////////////////////////////////// |
|
20 //// StatementParams |
|
21 |
|
22 StatementParams::StatementParams(mozIStorageStatement *aStatement) : |
|
23 mStatement(aStatement) |
|
24 { |
|
25 NS_ASSERTION(mStatement != nullptr, "mStatement is null"); |
|
26 (void)mStatement->GetParameterCount(&mParamCount); |
|
27 } |
|
28 |
|
29 NS_IMPL_ISUPPORTS( |
|
30 StatementParams, |
|
31 mozIStorageStatementParams, |
|
32 nsIXPCScriptable |
|
33 ) |
|
34 |
|
35 //////////////////////////////////////////////////////////////////////////////// |
|
36 //// nsIXPCScriptable |
|
37 |
|
38 #define XPC_MAP_CLASSNAME StatementParams |
|
39 #define XPC_MAP_QUOTED_CLASSNAME "StatementParams" |
|
40 #define XPC_MAP_WANT_SETPROPERTY |
|
41 #define XPC_MAP_WANT_NEWENUMERATE |
|
42 #define XPC_MAP_WANT_NEWRESOLVE |
|
43 #define XPC_MAP_FLAGS nsIXPCScriptable::ALLOW_PROP_MODS_DURING_RESOLVE |
|
44 #include "xpc_map_end.h" |
|
45 |
|
46 NS_IMETHODIMP |
|
47 StatementParams::SetProperty(nsIXPConnectWrappedNative *aWrapper, |
|
48 JSContext *aCtx, |
|
49 JSObject *aScopeObj, |
|
50 jsid aId, |
|
51 JS::Value *_vp, |
|
52 bool *_retval) |
|
53 { |
|
54 NS_ENSURE_TRUE(mStatement, NS_ERROR_NOT_INITIALIZED); |
|
55 |
|
56 if (JSID_IS_INT(aId)) { |
|
57 int idx = JSID_TO_INT(aId); |
|
58 |
|
59 nsCOMPtr<nsIVariant> variant(convertJSValToVariant(aCtx, *_vp)); |
|
60 NS_ENSURE_TRUE(variant, NS_ERROR_UNEXPECTED); |
|
61 nsresult rv = mStatement->BindByIndex(idx, variant); |
|
62 NS_ENSURE_SUCCESS(rv, rv); |
|
63 } |
|
64 else if (JSID_IS_STRING(aId)) { |
|
65 JSString *str = JSID_TO_STRING(aId); |
|
66 size_t length; |
|
67 const jschar *chars = JS_GetStringCharsAndLength(aCtx, str, &length); |
|
68 NS_ENSURE_TRUE(chars, NS_ERROR_UNEXPECTED); |
|
69 NS_ConvertUTF16toUTF8 name(chars, length); |
|
70 |
|
71 // check to see if there's a parameter with this name |
|
72 nsCOMPtr<nsIVariant> variant(convertJSValToVariant(aCtx, *_vp)); |
|
73 NS_ENSURE_TRUE(variant, NS_ERROR_UNEXPECTED); |
|
74 nsresult rv = mStatement->BindByName(name, variant); |
|
75 NS_ENSURE_SUCCESS(rv, rv); |
|
76 } |
|
77 else { |
|
78 return NS_ERROR_INVALID_ARG; |
|
79 } |
|
80 |
|
81 *_retval = true; |
|
82 return NS_OK; |
|
83 } |
|
84 |
|
85 NS_IMETHODIMP |
|
86 StatementParams::NewEnumerate(nsIXPConnectWrappedNative *aWrapper, |
|
87 JSContext *aCtx, |
|
88 JSObject *aScopeObj, |
|
89 uint32_t aEnumOp, |
|
90 jsval *_statep, |
|
91 jsid *_idp, |
|
92 bool *_retval) |
|
93 { |
|
94 NS_ENSURE_TRUE(mStatement, NS_ERROR_NOT_INITIALIZED); |
|
95 |
|
96 switch (aEnumOp) { |
|
97 case JSENUMERATE_INIT: |
|
98 case JSENUMERATE_INIT_ALL: |
|
99 { |
|
100 // Start our internal index at zero. |
|
101 *_statep = JSVAL_ZERO; |
|
102 |
|
103 // And set our length, if needed. |
|
104 if (_idp) |
|
105 *_idp = INT_TO_JSID(mParamCount); |
|
106 |
|
107 break; |
|
108 } |
|
109 case JSENUMERATE_NEXT: |
|
110 { |
|
111 NS_ASSERTION(*_statep != JSVAL_NULL, "Internal state is null!"); |
|
112 |
|
113 // Make sure we are in range first. |
|
114 uint32_t index = static_cast<uint32_t>(JSVAL_TO_INT(*_statep)); |
|
115 if (index >= mParamCount) { |
|
116 *_statep = JSVAL_NULL; |
|
117 return NS_OK; |
|
118 } |
|
119 |
|
120 // Get the name of our parameter. |
|
121 nsAutoCString name; |
|
122 nsresult rv = mStatement->GetParameterName(index, name); |
|
123 NS_ENSURE_SUCCESS(rv, rv); |
|
124 |
|
125 // But drop the first character, which is going to be a ':'. |
|
126 JS::RootedString jsname(aCtx, ::JS_NewStringCopyN(aCtx, &(name.get()[1]), |
|
127 name.Length() - 1)); |
|
128 NS_ENSURE_TRUE(jsname, NS_ERROR_OUT_OF_MEMORY); |
|
129 |
|
130 // Set our name. |
|
131 JS::Rooted<jsid> id(aCtx); |
|
132 if (!::JS_StringToId(aCtx, jsname, &id)) { |
|
133 *_retval = false; |
|
134 return NS_OK; |
|
135 } |
|
136 *_idp = id; |
|
137 |
|
138 // And increment our index. |
|
139 *_statep = INT_TO_JSVAL(++index); |
|
140 |
|
141 break; |
|
142 } |
|
143 case JSENUMERATE_DESTROY: |
|
144 { |
|
145 // Clear our state. |
|
146 *_statep = JSVAL_NULL; |
|
147 |
|
148 break; |
|
149 } |
|
150 } |
|
151 |
|
152 return NS_OK; |
|
153 } |
|
154 |
|
155 NS_IMETHODIMP |
|
156 StatementParams::NewResolve(nsIXPConnectWrappedNative *aWrapper, |
|
157 JSContext *aCtx, |
|
158 JSObject *aScopeObj, |
|
159 jsid aId, |
|
160 JSObject **_objp, |
|
161 bool *_retval) |
|
162 { |
|
163 NS_ENSURE_TRUE(mStatement, NS_ERROR_NOT_INITIALIZED); |
|
164 // We do not throw at any point after this unless our index is out of range |
|
165 // because we want to allow the prototype chain to be checked for the |
|
166 // property. |
|
167 |
|
168 JS::RootedObject scope(aCtx, aScopeObj); |
|
169 JS::RootedId id(aCtx, aId); |
|
170 bool resolved = false; |
|
171 bool ok = true; |
|
172 if (JSID_IS_INT(id)) { |
|
173 uint32_t idx = JSID_TO_INT(id); |
|
174 |
|
175 // Ensure that our index is within range. We do not care about the |
|
176 // prototype chain being checked here. |
|
177 if (idx >= mParamCount) |
|
178 return NS_ERROR_INVALID_ARG; |
|
179 |
|
180 ok = ::JS_DefineElement(aCtx, scope, idx, JSVAL_VOID, nullptr, |
|
181 nullptr, JSPROP_ENUMERATE); |
|
182 resolved = true; |
|
183 } |
|
184 else if (JSID_IS_STRING(id)) { |
|
185 JSString *str = JSID_TO_STRING(id); |
|
186 size_t nameLength; |
|
187 const jschar *nameChars = JS_GetStringCharsAndLength(aCtx, str, &nameLength); |
|
188 NS_ENSURE_TRUE(nameChars, NS_ERROR_UNEXPECTED); |
|
189 |
|
190 // Check to see if there's a parameter with this name, and if not, let |
|
191 // the rest of the prototype chain be checked. |
|
192 NS_ConvertUTF16toUTF8 name(nameChars, nameLength); |
|
193 uint32_t idx; |
|
194 nsresult rv = mStatement->GetParameterIndex(name, &idx); |
|
195 if (NS_SUCCEEDED(rv)) { |
|
196 ok = ::JS_DefinePropertyById(aCtx, scope, id, JSVAL_VOID, nullptr, |
|
197 nullptr, JSPROP_ENUMERATE); |
|
198 resolved = true; |
|
199 } |
|
200 } |
|
201 |
|
202 *_retval = ok; |
|
203 *_objp = resolved && ok ? scope.get() : nullptr; |
|
204 return NS_OK; |
|
205 } |
|
206 |
|
207 } // namespace storage |
|
208 } // namespace mozilla |