1 /*
2 * Copyright (c) 2025 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #define LOG_TAG "AniRdbStore"
17 #include <ani.h>
18 #include <iostream>
19 #include <string>
20
21 #include "logger.h"
22 #include "rdb_errno.h"
23 #include "ani_utils.h"
24 #include "ani_result_set.h"
25 #include "ani_rdb_error.h"
26 #include "ani_rdb_store_helper.h"
27 #include "ani_rdb_predicates.h"
28 #include "rdb_utils.h"
29
30 namespace OHOS {
31 namespace RelationalStoreAniKit {
32
33 using namespace OHOS::NativeRdb;
34 using namespace OHOS::Rdb;
35
ConvertBindArgs(ani_env * env,ani_object args,std::vector<ValueObject> & bindArgs,bool isOptional)36 bool ConvertBindArgs(ani_env *env, ani_object args, std::vector<ValueObject> &bindArgs, bool isOptional)
37 {
38 if (env == nullptr) {
39 LOG_ERROR("env is nullptr.");
40 return false;
41 }
42 if (isOptional) {
43 ani_boolean isUndefined = true;
44 env->Reference_IsUndefined(args, &isUndefined);
45 if (isUndefined) {
46 bindArgs.clear();
47 return true;
48 }
49 }
50 std::vector<ani_ref> valRefs;
51 UnionAccessor array2Ref(env, args);
52 bool convertArrayOk = array2Ref.TryConvert(valRefs);
53 if (!convertArrayOk) {
54 LOG_ERROR("conver array fail");
55 return false;
56 }
57 for (const auto& ref : valRefs) {
58 ani_object valObject = static_cast<ani_object>(ref);
59 ValueObject valueObject;
60 UnionAccessor unionAccessor(env, valObject);
61 bool convertOk = false;
62 convertOk = unionAccessor.TryConvertVariant(valueObject.value);
63 if (convertOk) {
64 bindArgs.push_back(std::move(valueObject));
65 } else {
66 LOG_ERROR("conver ValueObject fail");
67 return false;
68 }
69 }
70 return true;
71 }
72
ExecuteSqlSync(ani_env * env,ani_object object,ani_string sql,ani_object args)73 void ExecuteSqlSync(ani_env *env, ani_object object, ani_string sql, ani_object args)
74 {
75 if (env == nullptr) {
76 LOG_ERROR("env is nullptr.");
77 return;
78 }
79
80 std::vector<ValueObject> bindArgs;
81
82 bool convertOk = ConvertBindArgs(env, args, bindArgs, true);
83 if (!convertOk) {
84 LOG_ERROR("args conver fail");
85 ThrowBusinessError(env, E_PARAM_ERROR, "Unknown parameters.");
86 return;
87 }
88
89 auto proxy = AniObjectUtils::Unwrap<RdbStoreProxy>(env, object);
90 if (proxy == nullptr || proxy->nativeRdb == nullptr) {
91 LOG_ERROR("RdbStore should be initialized properly.");
92 ThrowBusinessError(env, E_INNER_ERROR, "RdbStore uninitialized.");
93 return;
94 }
95 auto sqlStr = AniStringUtils::ToStd(env, sql);
96 auto status = proxy->nativeRdb->ExecuteSql(sqlStr, bindArgs);
97 ThrowBusinessError(env, status);
98 }
99
BeginTransaction(ani_env * env,ani_object object)100 void BeginTransaction(ani_env *env, ani_object object)
101 {
102 if (env == nullptr) {
103 LOG_ERROR("env is nullptr.");
104 return;
105 }
106 auto proxy = AniObjectUtils::Unwrap<RdbStoreProxy>(env, object);
107 if (proxy == nullptr || proxy->nativeRdb == nullptr) {
108 LOG_ERROR("RdbStore should be initialized properly.");
109 ThrowBusinessError(env, E_INNER_ERROR, "RdbStore uninitialized.");
110 return;
111 }
112 auto status = proxy->nativeRdb->BeginTransaction();
113 ThrowBusinessError(env, status);
114 }
115
Commit(ani_env * env,ani_object object)116 void Commit(ani_env *env, ani_object object)
117 {
118 if (env == nullptr) {
119 LOG_ERROR("env is nullptr.");
120 return;
121 }
122 auto proxy = AniObjectUtils::Unwrap<RdbStoreProxy>(env, object);
123 if (proxy == nullptr || proxy->nativeRdb == nullptr) {
124 LOG_ERROR("RdbStore should be initialized properly.");
125 ThrowBusinessError(env, E_INNER_ERROR, "RdbStore uninitialized.");
126 return;
127 }
128 auto status = proxy->nativeRdb->Commit();
129 ThrowBusinessError(env, status);
130 }
131
RollBack(ani_env * env,ani_object object)132 void RollBack(ani_env *env, ani_object object)
133 {
134 if (env == nullptr) {
135 LOG_ERROR("env is nullptr.");
136 return;
137 }
138 auto proxy = AniObjectUtils::Unwrap<RdbStoreProxy>(env, object);
139 if (proxy == nullptr || proxy->nativeRdb == nullptr) {
140 LOG_ERROR("RdbStore should be initialized properly.");
141 ThrowBusinessError(env, E_INNER_ERROR, "RdbStore uninitialized.");
142 return;
143 }
144 auto status = proxy->nativeRdb->RollBack();
145 ThrowBusinessError(env, status);
146 }
147
BatchInsert(ani_env * env,ani_object object,ani_string tableName,ani_object values)148 ani_double BatchInsert(ani_env *env, ani_object object, ani_string tableName, ani_object values)
149 {
150 if (env == nullptr) {
151 LOG_ERROR("env is nullptr.");
152 return 0;
153 }
154 auto proxy = AniObjectUtils::Unwrap<RdbStoreProxy>(env, object);
155 if (proxy == nullptr || proxy->nativeRdb == nullptr) {
156 LOG_ERROR("RdbStore should be initialized properly.");
157 ThrowBusinessError(env, E_INNER_ERROR, "RdbStore uninitialized.");
158 return 0;
159 }
160 auto name = AniStringUtils::ToStd(env, tableName);
161 std::vector<ani_ref> valRefs;
162 UnionAccessor array2Ref(env, values);
163 array2Ref.TryConvert(valRefs);
164 ValuesBuckets vbs;
165 for (const auto& ref : valRefs) {
166 ani_object recordObj = static_cast<ani_object>(ref);
167 UnionAccessor recordAccessor(env, recordObj);
168 ValuesBucket valuesBucket;
169 recordAccessor.TryConvert(valuesBucket);
170 vbs.Put(valuesBucket);
171 }
172 auto [status, ret] = proxy->nativeRdb->BatchInsert(name, vbs);
173 ThrowBusinessError(env, status);
174 return ret;
175 }
176
DeleteSync(ani_env * env,ani_object object,ani_object predicates)177 ani_double DeleteSync(ani_env *env, ani_object object, ani_object predicates)
178 {
179 if (env == nullptr) {
180 LOG_ERROR("env is nullptr.");
181 return 0;
182 }
183 auto proxy = AniObjectUtils::Unwrap<RdbStoreProxy>(env, object);
184 if (proxy == nullptr || proxy->nativeRdb == nullptr) {
185 LOG_ERROR("RdbStore should be initialized properly.");
186 ThrowBusinessError(env, E_INNER_ERROR, "RdbStore uninitialized.");
187 return 0;
188 }
189 auto nativePredicates = AniObjectUtils::Unwrap<PredicatesProxy>(env, predicates);
190 if (nativePredicates == nullptr || nativePredicates->predicates == nullptr) {
191 LOG_ERROR("Predicates should be initialized properly.");
192 ThrowBusinessError(env, E_INNER_ERROR, "Predicates uninitialized.");
193 return 0;
194 }
195 int rows = 0;
196 auto status = proxy->nativeRdb->Delete(rows, *(nativePredicates->predicates));
197 ThrowBusinessError(env, status);
198 return rows;
199 }
200
DeleteShareSync(ani_env * env,ani_object object,ani_string tableName,ani_object dataSharePredicates)201 ani_double DeleteShareSync(ani_env *env, ani_object object, ani_string tableName, ani_object dataSharePredicates)
202 {
203 if (env == nullptr) {
204 LOG_ERROR("env is nullptr.");
205 return 0;
206 }
207 auto proxy = AniObjectUtils::Unwrap<RdbStoreProxy>(env, object);
208 if (proxy == nullptr || proxy->nativeRdb == nullptr) {
209 LOG_ERROR("RdbStore should be initialized properly.");
210 ThrowBusinessError(env, E_INNER_ERROR, "RdbStore uninitialized.");
211 return 0;
212 }
213
214 std::string name = AniStringUtils::ToStd(env, tableName);
215
216 auto cppDataSharePredicates = AniObjectUtils::Unwrap<DataShare::DataShareAbsPredicates>(env, dataSharePredicates);
217 if (cppDataSharePredicates == nullptr) {
218 LOG_ERROR("Predicates should be initialized properly.");
219 ThrowBusinessError(env, E_INNER_ERROR, "Predicates uninitialized.");
220 return 0;
221 }
222 RdbPredicates rdbPredicates = RdbDataShareAdapter::RdbUtils::ToPredicates(*cppDataSharePredicates, name);
223 int rows = 0;
224 auto status = proxy->nativeRdb->Delete(rows, rdbPredicates);
225 ThrowBusinessError(env, status);
226 return rows;
227 }
228
QuerySqlSync(ani_env * env,ani_object object,ani_string sql,ani_object args)229 ani_object QuerySqlSync(ani_env *env, ani_object object, ani_string sql, ani_object args)
230 {
231 if (env == nullptr) {
232 LOG_ERROR("env is nullptr.");
233 return nullptr;
234 }
235 std::vector<ValueObject> bindArgs;
236 auto sqlStr = AniStringUtils::ToStd(env, sql);
237
238 if (!ConvertBindArgs(env, args, bindArgs, true)) {
239 LOG_ERROR("args conver fail");
240 return nullptr;
241 }
242 auto proxy = AniObjectUtils::Unwrap<RdbStoreProxy>(env, object);
243 if (proxy == nullptr || proxy->nativeRdb == nullptr) {
244 ThrowBusinessError(env, E_INNER_ERROR, "RdbStore uninitialized.");
245 return nullptr;
246 }
247 auto resultsetProxy = new ResultSetProxy();
248 if (resultsetProxy == nullptr) {
249 ThrowBusinessError(env, E_INNER_ERROR, "Proxy is nullptr.");
250 return nullptr;
251 }
252 resultsetProxy->resultset = proxy->nativeRdb->QueryByStep(sqlStr, bindArgs);
253 if (resultsetProxy->resultset == nullptr) {
254 delete resultsetProxy;
255 ThrowBusinessError(env, E_INNER_ERROR, "QueryByStep returned nullptr.");
256 return nullptr;
257 }
258
259 static const char *namespaceName = "L@ohos/data/relationalStore/relationalStore;";
260 static const char *className = "LResultSetInner;";
261 static const char *initFinalizer = "initFinalizer";
262 ani_object obj = AniObjectUtils::Create(env, namespaceName, className);
263 if (nullptr == obj) {
264 delete resultsetProxy;
265 ThrowBusinessError(env, E_INNER_ERROR, "Create ResultSet failed.class: LResultSetInner;");
266 return nullptr;
267 }
268 ani_status status = AniObjectUtils::Wrap(env, obj, resultsetProxy);
269 if (ANI_OK != status) {
270 delete resultsetProxy;
271 ThrowBusinessError(env, E_INNER_ERROR, "Wrap ResultSet failed.class: LResultSetInner;");
272 return nullptr;
273 }
274 status = AniObjectUtils::CallObjMethod(env, namespaceName, className, initFinalizer, obj);
275 if (ANI_OK != status) {
276 ThrowBusinessError(env, E_INNER_ERROR, "init ResultSet finalizer failed.class: LResultSetInner;");
277 return nullptr;
278 }
279 return obj;
280 }
281
RdbStoreInit(ani_env * env)282 ani_status RdbStoreInit(ani_env *env)
283 {
284 if (env == nullptr) {
285 LOG_ERROR("env is nullptr.");
286 return ANI_ERROR;
287 }
288 static const char *namespaceName = "L@ohos/data/relationalStore/relationalStore;";
289 ani_namespace ns;
290 if (ANI_OK != env->FindNamespace(namespaceName, &ns)) {
291 LOG_ERROR("Not found '%{public}s'", namespaceName);
292 return ANI_ERROR;
293 }
294
295 static const char *clsName = "LRdbStoreInner;";
296 ani_class cls;
297 if (ANI_OK != env->Namespace_FindClass(ns, clsName, &cls)) {
298 LOG_ERROR("Not found '%{public}s'", clsName);
299 return ANI_ERROR;
300 }
301
302 std::array methods = {
303 ani_native_function {"batchInsertSync", nullptr, reinterpret_cast<void *>(BatchInsert)},
304 ani_native_function {"beginTransaction", nullptr, reinterpret_cast<void *>(BeginTransaction)},
305 ani_native_function {"commit", ":V", reinterpret_cast<void *>(Commit)},
306 ani_native_function {"rollBack", nullptr, reinterpret_cast<void *>(RollBack)},
307 ani_native_function {"executeSqlSync", nullptr, reinterpret_cast<void *>(ExecuteSqlSync)},
308 ani_native_function {"deleteSync", nullptr, reinterpret_cast<void *>(DeleteSync)},
309 ani_native_function {"deleteShareSync", nullptr, reinterpret_cast<void *>(DeleteShareSync)},
310 ani_native_function {"querySqlSync", nullptr, reinterpret_cast<void *>(QuerySqlSync)},
311 };
312 if (ANI_OK != env->Class_BindNativeMethods(cls, methods.data(), methods.size())) {
313 LOG_ERROR("Cannot bind native methods to '%{public}s'", clsName);
314 return ANI_ERROR;
315 }
316 return ANI_OK;
317 }
318
319
320 } // namespace RelationalStoreAniKit
321 } // namespace OHOS
322
323