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 #include "sg_sqlite_helper.h"
17 #include "security_guard_log.h"
18 #include "security_guard_define.h"
19 #include <sstream>
20 #include <string>
21
22 namespace OHOS::Security::SecurityGuard {
SgSqliteHelper(const std::string & dbName,const std::string & dbPath,int version,const std::vector<std::string> & createSqls)23 SgSqliteHelper::SgSqliteHelper(const std::string &dbName, const std::string &dbPath, int version,
24 const std::vector<std::string> &createSqls) : SqliteHelper(dbName, dbPath, version), createSqls_(createSqls)
25 {
26 Open();
27 }
28
OnCreate()29 void SgSqliteHelper::OnCreate()
30 {
31 SGLOGI("db create");
32 int32_t ret = FAILED;
33 size_t size = createSqls_.size();
34 if (size == 0) {
35 return;
36 }
37 for (size_t i = 0; i < size; i++) {
38 ret = ExecuteSql(createSqls_[i]);
39 if (ret == 0) {
40 return;
41 }
42 }
43 return;
44 }
45
OnUpdate()46 void SgSqliteHelper::OnUpdate()
47 {
48 return;
49 }
50
Insert(int64_t & outRowId,const std::string & table,const GenericValues & values)51 int SgSqliteHelper::Insert(int64_t &outRowId, const std::string &table, const GenericValues &values)
52 {
53 if (table.empty() || values.GetAllKeys().empty()) {
54 SGLOGE("invalid param");
55 return FAILED;
56 }
57
58 OHOS::Utils::UniqueWriteGuard<OHOS::Utils::RWLock> lock(rwLock_);
59 std::string sql = BuildInsertSql(table, values);
60 if (sql.empty()) {
61 return FAILED;
62 }
63
64 Statement stmt = Prepare(sql);
65 std::vector<std::string> keys = values.GetAllKeys();
66 for (const auto &key : keys) {
67 VariantValue val = values.Get(key);
68 if (val.GetType() == ValueType::TYPE_NULL) {
69 continue;
70 }
71 stmt.Bind(key, val);
72 }
73
74 Statement::State execRet = stmt.Step();
75 if (execRet != Statement::DONE) {
76 SGLOGE("insert fail");
77 return FAILED;
78 }
79
80 outRowId = sqlite3_last_insert_rowid(GetDb());
81 return SUCCESS;
82 }
83
BatchInsert(int64_t & outInsertNum,const std::string & table,const std::vector<GenericValues> & initialBatchValues)84 int SgSqliteHelper::BatchInsert(int64_t &outInsertNum, const std::string &table,
85 const std::vector<GenericValues> &initialBatchValues)
86 {
87 (void)outInsertNum;
88 (void)table;
89 (void)initialBatchValues;
90 return SUCCESS;
91 }
92
Update(int & changedRows,const std::string & table,const GenericValues & value)93 int SgSqliteHelper::Update(int &changedRows, const std::string &table, const GenericValues &value)
94 {
95 (void)changedRows;
96 (void)table;
97 (void)value;
98 return SUCCESS;
99 }
100
Delete(int & deletedRows,const std::string & table,const GenericValues & conditions)101 int SgSqliteHelper::Delete(int &deletedRows, const std::string &table, const GenericValues &conditions)
102 {
103 OHOS::Utils::UniqueWriteGuard<OHOS::Utils::RWLock> lock(rwLock_);
104 Statement stmt = PrepareDeleteStmt(table, conditions);
105 if (stmt.Step() == Statement::DONE) {
106 deletedRows = sqlite3_changes(GetDb());
107 return SUCCESS;
108 }
109 return FAILED;
110 }
111
Attach(const std::string & alias,const std::string & pathName,const std::vector<uint8_t> destEncryptKey)112 int SgSqliteHelper::Attach(const std::string &alias, const std::string &pathName,
113 const std::vector<uint8_t> destEncryptKey)
114 {
115 (void)alias;
116 (void)pathName;
117 (void)destEncryptKey;
118 return SUCCESS;
119 }
120
ExecuteSql(const std::string & sql)121 int SgSqliteHelper::ExecuteSql(const std::string &sql)
122 {
123 OHOS::Utils::UniqueWriteGuard<OHOS::Utils::RWLock> lock(rwLock_);
124 return SqliteHelper::ExecuteSql(sql);
125 }
126
ExecuteAndGetLong(int64_t & outValue,const std::string & sql,const std::vector<std::string> & bindArgs)127 int SgSqliteHelper::ExecuteAndGetLong(int64_t &outValue, const std::string &sql,
128 const std::vector<std::string> &bindArgs)
129 {
130 OHOS::Utils::UniqueWriteGuard<OHOS::Utils::RWLock> lock(rwLock_);
131 Statement stmt = Prepare(sql);
132 for (size_t i = 0; i < bindArgs.size(); ++i) {
133 stmt.Bind(i + 1, bindArgs[i]);
134 }
135
136 if (stmt.Step() == Statement::ROW) {
137 outValue = stmt.GetColumnInt64(0);
138 return SUCCESS;
139 }
140 return FAILED;
141 }
142
Count(int64_t & outValue,const std::string & table,const GenericValues & conditions,const QueryOptions & options)143 int SgSqliteHelper::Count(int64_t &outValue, const std::string &table, const GenericValues &conditions,
144 const QueryOptions &options)
145 {
146 OHOS::Utils::UniqueWriteGuard<OHOS::Utils::RWLock> lock(rwLock_);
147 Statement stmt = PrepareCountStmt(table, conditions, options);
148 if (stmt.Step() == Statement::ROW) {
149 outValue = stmt.GetColumnInt64(0);
150 return SUCCESS;
151 }
152 return FAILED;
153 }
154
ExecuteRowData(Statement & stmt)155 GenericValues SgSqliteHelper::ExecuteRowData(Statement &stmt)
156 {
157 GenericValues row;
158 const int columnCount = stmt.GetColumnCount();
159 for (int i = 0; i < columnCount; ++i) {
160 VariantValue value = stmt.GetValue(i, true);
161 const std::string columnName = stmt.GetColumnName(i);
162 switch (value.GetType()) {
163 case ValueType::TYPE_INT:
164 row.Put(columnName, value.GetInt());
165 break;
166 case ValueType::TYPE_INT64:
167 row.Put(columnName, value.GetInt64());
168 break;
169 case ValueType::TYPE_STRING:
170 row.Put(columnName, value.GetString());
171 break;
172 default:
173 row.Put(columnName, "");
174 break;
175 }
176 }
177
178 return row;
179 }
180
Query(const std::string & table,const GenericValues & conditions,std::vector<GenericValues> & results,const QueryOptions & options)181 int SgSqliteHelper::Query(const std::string &table, const GenericValues &conditions,
182 std::vector<GenericValues> &results, const QueryOptions &options)
183 {
184 OHOS::Utils::UniqueWriteGuard<OHOS::Utils::RWLock> lock(rwLock_);
185 std::string sql = BuildSelectSql(table, conditions, options);
186 if (sql.empty()) {
187 SGLOGE("BuildSelectSql fail");
188 return FAILED;
189 }
190
191 Statement stmt = PrepareBoundStateStmt(sql, conditions);
192 while (stmt.Step() == Statement::ROW) {
193 results.emplace_back(ExecuteRowData(stmt));
194 }
195 return SUCCESS;
196 }
197
BuildInsertSql(const std::string & table,const GenericValues & values)198 std::string SgSqliteHelper::BuildInsertSql(const std::string &table, const GenericValues &values)
199 {
200 std::vector<std::string> keys = values.GetAllKeys();
201 if (keys.empty()) {
202 SGLOGE("invalid param");
203 return "";
204 }
205
206 std::ostringstream oss;
207 oss << " INSERT INTO " << table << " (";
208 for (size_t i = 0; i < keys.size(); ++i) {
209 oss << keys[i];
210 if (i != keys.size() - 1) {
211 oss << ",";
212 }
213 }
214
215 oss << ") VALUES (";
216 for (size_t i = 0; i < keys.size(); ++i) {
217 oss << ":" << keys[i];
218 if (i != keys.size() - 1) {
219 oss << ",";
220 }
221 }
222 oss << ")";
223
224 return oss.str();
225 }
226
BuildUpdateSql(const std::string & table,const GenericValues & values,const std::string & where)227 std::string SgSqliteHelper::BuildUpdateSql(const std::string &table, const GenericValues &values,
228 const std::string &where)
229 {
230 auto keys = values.GetAllKeys();
231 if (keys.empty()) {
232 SGLOGE("update values is empty");
233 return "";
234 }
235
236 std::string setClause;
237 for (size_t i = 0; i < keys.size(); ++i) {
238 setClause += keys[i] + "=?";
239 if (i != keys.size() - 1) {
240 setClause += ",";
241 }
242 }
243 std::string sql = "UPDATE " + table + " SET " + setClause;
244 if (!where.empty()) {
245 sql += " WHERE " + where;
246 }
247 return sql;
248 }
249
BuildSelectSql(const std::string & table,const GenericValues & conditions,const QueryOptions & options)250 std::string SgSqliteHelper::BuildSelectSql(const std::string &table, const GenericValues &conditions,
251 const QueryOptions &options)
252 {
253 std::string columns = options.columns.empty() ? "*" : Join(options.columns, ", ");
254 std::string sql = "SELECT " + columns + " FROM " + table;
255 std::string whereClause = BuildWhereClause(conditions);
256 if (!whereClause.empty()) {
257 sql += " WHERE " + whereClause;
258 }
259 if (!options.orderBy.empty()) {
260 sql += " ORDER BY " + options.orderBy;
261 }
262 if (options.limit > 0) {
263 sql += " LIMIT " + std::to_string(options.limit);
264 }
265
266 return sql;
267 }
268
BuildInPlaceholders(const std::string & key,const std::string & values)269 std::string SgSqliteHelper::BuildInPlaceholders(const std::string &key, const std::string &values)
270 {
271 auto items = Split(values, ',');
272 std::vector<std::string> placeholders;
273 for (size_t i = 0; i < items.size(); ++i) {
274 placeholders.push_back(":" + key + "_" + std::to_string(i));
275 }
276
277 return Join(placeholders, ",");
278 }
279
Split(const std::string & s,char delimiter)280 std::vector<std::string> SgSqliteHelper::Split(const std::string &s, char delimiter)
281 {
282 std::vector<std::string> tokens;
283 std::string token;
284 std::istringstream tokenSteam(s);
285 while (std::getline(tokenSteam, token, delimiter)) {
286 tokens.push_back(token);
287 }
288 return tokens;
289 }
290
PrepareBoundStateStmt(const std::string & sql,const GenericValues & conditions)291 Statement SgSqliteHelper::PrepareBoundStateStmt(const std::string &sql, const GenericValues &conditions)
292 {
293 Statement stmt = Prepare(sql);
294 auto keys = conditions.GetAllKeys();
295 for (const auto& key: keys) {
296 VariantValue value = conditions.Get(key);
297 if (key.find("_IN") != std::string::npos) {
298 auto items = Split(value.GetString(), ',');
299 for (size_t i = 0; i < items.size(); ++i) {
300 const std::string paramName = key + "_" + std::to_string(i);
301 stmt.Bind(paramName, VariantValue(items[i]));
302 }
303 continue;
304 }
305
306 if (value.GetType() == ValueType::TYPE_INT) {
307 stmt.Bind(key, VariantValue(value.GetInt()));
308 } else if (value.GetType() == ValueType::TYPE_INT64) {
309 stmt.Bind(key, VariantValue(value.GetInt64()));
310 } else if (value.GetType() == ValueType::TYPE_STRING) {
311 stmt.Bind(key, VariantValue(value.GetString()));
312 }
313 }
314 return stmt;
315 }
316
EndWith(const std::string & str,const std::string & suffix) const317 bool SgSqliteHelper::EndWith(const std::string &str, const std::string &suffix) const
318 {
319 if (str.length() < suffix.length()) {
320 return false;
321 }
322
323 return str.compare(str.length() - suffix.length(), suffix.length(), suffix) == 0;
324 }
325
BuildWhereClause(const GenericValues & conditions)326 std::string SgSqliteHelper::BuildWhereClause(const GenericValues &conditions)
327 {
328 std::vector<std::string> clauses;
329 std::vector<std::string> ops = {"_IN", "_GE", "_LT", "_LIKE"};
330
331 auto keys = conditions.GetAllKeys();
332 for (const auto& key : keys) {
333 std::string opFound;
334 std::string field = key;
335
336 for (const auto& op: ops) {
337 if (EndWith(key, op)) {
338 opFound = op.substr(1);
339 field = key.substr(0, key.size() - op.size());
340 break;
341 }
342 }
343
344 if (opFound.empty()) {
345 clauses.push_back(key + " = :" + key);
346 continue;
347 }
348
349 if (opFound == "IN") {
350 std::string placeholders = BuildInPlaceholders(key, conditions.Get(key).GetString());
351 clauses.push_back(field + " IN (" + placeholders + ")");
352 } else if (opFound == "GE") {
353 clauses.push_back(field + " >= :" + key);
354 } else if (opFound == "LT") {
355 clauses.push_back(field + " < :" + key);
356 } else if (opFound == "LIKE") {
357 clauses.push_back(field + " LIKE :" + key);
358 }
359 }
360
361 return clauses.empty() ? "" : Join(clauses, " AND ");
362 }
363
PrepareCountStmt(const std::string & table,const GenericValues & conditions,const QueryOptions & options)364 Statement SgSqliteHelper::PrepareCountStmt(const std::string &table, const GenericValues &conditions,
365 const QueryOptions &options)
366 {
367 std::string sql = "SELECT COUNT(*) FROM " + table;
368 std::string where = BuildWhereClause(conditions);
369 if (!where.empty()) {
370 sql += " WHERE " + where;
371 }
372
373 return PrepareBoundStateStmt(sql, conditions);
374 }
375
PrepareDeleteStmt(const std::string & table,const GenericValues & conditions)376 Statement SgSqliteHelper::PrepareDeleteStmt(const std::string &table, const GenericValues &conditions)
377 {
378 std::string sql = "DELETE FROM " + table;
379 std::string where = BuildWhereClause(conditions);
380 if (!where.empty()) {
381 sql += " WHERE " + where;
382 }
383
384 return PrepareBoundStateStmt(sql, conditions);
385 }
386
Join(const std::vector<std::string> & items,const std::string & delimiter)387 std::string SgSqliteHelper::Join(const std::vector<std::string> &items, const std::string &delimiter)
388 {
389 if (items.empty()) {
390 return "";
391 }
392
393 std::string result;
394 bool isFirst = true;
395 for (const auto &str : items) {
396 if (!isFirst) {
397 result += delimiter;
398 }
399
400 result += str;
401 isFirst = false;
402 }
403
404 return result;
405 }
406 }
407