1 /*
2 * Copyright (c) 2021 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 #define LOG_TAG "SqliteSqlBuilder"
16 #include "sqlite_sql_builder.h"
17
18 #include <list>
19 #include <regex>
20
21 #include "logger.h"
22 #include "rdb_errno.h"
23 #include "rdb_trace.h"
24 #include "string_utils.h"
25 #include "sqlite_utils.h"
26 #include "traits.h"
27 namespace OHOS {
28 namespace NativeRdb {
29 using namespace OHOS::Rdb;
30 std::vector<std::string> g_onConflictClause = {
31 "", " OR ROLLBACK", " OR ABORT", " OR FAIL", " OR IGNORE", " OR REPLACE"
32 };
33 ValueObject SqliteSqlBuilder::nullObject_;
34 std::reference_wrapper<ValueObject> SqliteSqlBuilder::nullRef_ = SqliteSqlBuilder::nullObject_;
35
SqliteSqlBuilder()36 SqliteSqlBuilder::SqliteSqlBuilder() {}
~SqliteSqlBuilder()37 SqliteSqlBuilder::~SqliteSqlBuilder() {}
38
39 /**
40 * Build a delete SQL string using the given condition for SQLite.
41 */
BuildDeleteString(const std::string & tableName,const std::string & index,const std::string & whereClause,const std::string & group,const std::string & order,int limit,int offset)42 std::string SqliteSqlBuilder::BuildDeleteString(const std::string &tableName, const std::string &index,
43 const std::string &whereClause, const std::string &group, const std::string &order, int limit, int offset)
44 {
45 std::string sql;
46 sql.append("Delete ").append("FROM ").append(tableName).append(
47 BuildSqlStringFromPredicates(index, "", whereClause, group, order, limit, offset));
48 return sql;
49 }
50
51 /**
52 * Build a count SQL string using the given condition for SQLite.
53 */
BuildUpdateString(const ValuesBucket & values,const std::string & tableName,const std::vector<std::string> & whereArgs,const std::string & index,const std::string & whereClause,const std::string & group,const std::string & order,int limit,int offset,std::vector<ValueObject> & bindArgs,ConflictResolution conflictResolution)54 std::string SqliteSqlBuilder::BuildUpdateString(const ValuesBucket &values, const std::string &tableName,
55 const std::vector<std::string> &whereArgs, const std::string &index, const std::string &whereClause,
56 const std::string &group, const std::string &order, int limit, int offset, std::vector<ValueObject> &bindArgs,
57 ConflictResolution conflictResolution)
58 {
59 std::string sql;
60
61 sql.append("UPDATE")
62 .append(g_onConflictClause[static_cast<int>(conflictResolution)])
63 .append(" ")
64 .append(tableName)
65 .append(" SET ");
66 const char *split = "";
67 for (auto &[key, val] : values.values_) {
68 sql.append(split);
69 sql.append(key).append("=?");
70 bindArgs.push_back(val);
71 split = ",";
72 }
73
74 if (!whereArgs.empty()) {
75 for (size_t i = 0; i < whereArgs.size(); i++) {
76 bindArgs.push_back(ValueObject(whereArgs[i]));
77 }
78 }
79 sql.append(BuildSqlStringFromPredicates(index, "", whereClause, group, order, limit, offset));
80 return sql;
81 }
82
83 /**
84 * Build a query SQL string using the given condition for SQLite.
85 */
BuildQueryString(bool distinct,const std::string & table,const std::string & joinClause,const std::vector<std::string> & columns,const std::string & whereClause,const std::string & groupBy,const std::string & indexName,const std::string & orderBy,const int & limit,const int & offset,std::string & outSql)86 int SqliteSqlBuilder::BuildQueryString(bool distinct, const std::string &table, const std::string &joinClause,
87 const std::vector<std::string> &columns, const std::string &whereClause, const std::string &groupBy,
88 const std::string &indexName, const std::string &orderBy, const int &limit, const int &offset, std::string &outSql)
89 {
90 if (table.empty()) {
91 return E_EMPTY_TABLE_NAME;
92 }
93
94 std::string sql;
95 sql.append("SELECT ");
96 if (distinct) {
97 sql.append("DISTINCT ");
98 }
99 if (columns.size() != 0) {
100 AppendColumns(sql, columns);
101 } else {
102 sql.append("* ");
103 }
104 sql.append("FROM ").append(table).append(
105 BuildSqlStringFromPredicates(indexName, joinClause, whereClause, groupBy, orderBy, limit, offset));
106 outSql = sql;
107
108 return E_OK;
109 }
110
111 /**
112 * Build a count SQL string using the given condition for SQLite.
113 */
BuildCountString(const std::string & tableName,const std::string & index,const std::string & whereClause,const std::string & group,const std::string & order,int limit,int offset)114 std::string SqliteSqlBuilder::BuildCountString(const std::string &tableName, const std::string &index,
115 const std::string &whereClause, const std::string &group, const std::string &order, int limit, int offset)
116 {
117 std::string sql;
118 sql.append("SELECT COUNT(*) FROM ")
119 .append(tableName)
120 .append(BuildSqlStringFromPredicates(index, "", whereClause, group, order, limit, offset));
121 return sql;
122 }
123
BuildSqlStringFromPredicates(const std::string & index,const std::string & joinClause,const std::string & whereClause,const std::string & group,const std::string & order,int limit,int offset)124 std::string SqliteSqlBuilder::BuildSqlStringFromPredicates(const std::string &index, const std::string &joinClause,
125 const std::string &whereClause, const std::string &group, const std::string &order, int limit, int offset)
126 {
127 std::string sqlString;
128
129 std::string limitStr = (limit == AbsPredicates::INIT_LIMIT_VALUE) ? "" : std::to_string(limit);
130 std::string offsetStr = (offset == AbsPredicates::INIT_OFFSET_VALUE) ? "" : std::to_string(offset);
131
132 AppendClause(sqlString, " INDEXED BY ", index);
133 AppendClause(sqlString, " ", joinClause);
134 AppendClause(sqlString, " WHERE ", whereClause);
135 AppendClause(sqlString, " GROUP BY ", group);
136 AppendClause(sqlString, " ORDER BY ", order);
137 AppendClause(sqlString, " LIMIT ", limitStr);
138 AppendClause(sqlString, " OFFSET ", offsetStr);
139
140 return sqlString;
141 }
142
BuildSqlStringFromPredicates(const AbsPredicates & predicates)143 std::string SqliteSqlBuilder::BuildSqlStringFromPredicates(const AbsPredicates &predicates)
144 {
145 std::string limitStr =
146 (predicates.GetLimit() == AbsPredicates::INIT_LIMIT_VALUE) ? "" : std::to_string(predicates.GetLimit());
147 std::string offsetStr =
148 (predicates.GetOffset() == AbsPredicates::INIT_OFFSET_VALUE) ? "" : std::to_string(predicates.GetOffset());
149
150 std::string sqlString;
151 AppendClause(sqlString, " INDEXED BY ", predicates.GetIndex());
152 AppendClause(sqlString, " WHERE ", predicates.GetWhereClause());
153 AppendClause(sqlString, " GROUP BY ", predicates.GetGroup());
154 AppendClause(sqlString, " ORDER BY ", predicates.GetOrder());
155 AppendClause(sqlString, " LIMIT ", limitStr);
156 AppendClause(sqlString, " OFFSET ", offsetStr);
157
158 return sqlString;
159 }
160
BuildSqlStringFromPredicatesNoWhere(const std::string & index,const std::string & whereClause,const std::string & group,const std::string & order,int limit,int offset)161 std::string SqliteSqlBuilder::BuildSqlStringFromPredicatesNoWhere(const std::string &index,
162 const std::string &whereClause, const std::string &group, const std::string &order, int limit, int offset)
163 {
164 std::string limitStr = (limit == AbsPredicates::INIT_LIMIT_VALUE) ? "" : std::to_string(limit);
165 std::string offsetStr = (offset == AbsPredicates::INIT_OFFSET_VALUE) ? "" : std::to_string(offset);
166
167 std::string sqlString;
168 AppendClause(sqlString, " INDEXED BY ", index);
169 AppendClause(sqlString, " ", whereClause);
170 AppendClause(sqlString, " GROUP BY ", group);
171 AppendClause(sqlString, " ORDER BY ", order);
172 AppendClause(sqlString, " LIMIT ", limitStr);
173 AppendClause(sqlString, " OFFSET ", offsetStr);
174
175 return sqlString;
176 }
177
AppendClause(std::string & builder,const std::string & name,const std::string & clause,const std::string & table)178 void SqliteSqlBuilder::AppendClause(std::string &builder, const std::string &name,
179 const std::string &clause, const std::string &table)
180 {
181 if (clause.empty()) {
182 return;
183 }
184 builder.append(name);
185 if (!table.empty()) {
186 builder.append(table).append(".");
187 }
188 builder.append(clause);
189 }
190
191 /**
192 * Add the names that are non-null in columns to s, separating them with commas.
193 */
AppendColumns(std::string & builder,const std::vector<std::string> & columns,const std::string & table)194 void SqliteSqlBuilder::AppendColumns(
195 std::string &builder, const std::vector<std::string> &columns, const std::string &table)
196 {
197 for (size_t i = 0; i < columns.size(); i++) {
198 const auto &col = columns[i];
199 if (col.empty()) {
200 continue;
201 }
202 if (i > 0 && !(columns[i - 1].empty())) {
203 builder.append(", ");
204 }
205 if (!table.empty()) {
206 builder.append(table).append(".");
207 }
208 builder.append(col);
209 }
210 if (table.empty()) {
211 builder += ' ';
212 }
213 }
214
BuildQueryString(const AbsRdbPredicates & predicates,const std::vector<std::string> & columns)215 std::string SqliteSqlBuilder::BuildQueryString(
216 const AbsRdbPredicates &predicates, const std::vector<std::string> &columns)
217 {
218 bool distinct = predicates.IsDistinct();
219 std::string tableName = predicates.GetTableName();
220 std::string joinClauseStr = predicates.GetJoinClause();
221 std::string whereClauseStr = predicates.GetWhereClause();
222 std::string groupStr = predicates.GetGroup();
223 std::string indexStr = predicates.GetIndex();
224 std::string orderStr = predicates.GetOrder();
225 int limit = predicates.GetLimit();
226 int offset = predicates.GetOffset();
227 std::string sqlStr;
228 BuildQueryString(distinct, tableName, joinClauseStr, columns, whereClauseStr,
229 groupStr, indexStr, orderStr, limit, offset, sqlStr);
230 return sqlStr;
231 }
232
BuildCountString(const AbsRdbPredicates & predicates)233 std::string SqliteSqlBuilder::BuildCountString(const AbsRdbPredicates &predicates)
234 {
235 std::string tableName = predicates.GetTableName();
236 return "SELECT COUNT(*) FROM " + tableName + BuildSqlStringFromPredicates(predicates);
237 }
238
BuildCursorQueryString(const AbsRdbPredicates & predicates,const std::vector<std::string> & columns,const std::string & logTable,const std::pair<bool,bool> & queryStatus)239 std::string SqliteSqlBuilder::BuildCursorQueryString(const AbsRdbPredicates &predicates,
240 const std::vector<std::string> &columns, const std::string &logTable, const std::pair<bool, bool> &queryStatus)
241 {
242 std::string sql;
243 std::string table = predicates.GetTableName();
244 if (table.empty() || logTable.empty()) {
245 return sql;
246 }
247 sql.append("SELECT ");
248 if (predicates.IsDistinct()) {
249 sql.append("DISTINCT ");
250 }
251 if (!columns.empty()) {
252 AppendColumns(sql, columns, table);
253 } else {
254 sql.append(table + ".*");
255 }
256 if (queryStatus.first) {
257 std::string field = DistributedRdb::Field::SHARING_RESOURCE_FIELD;
258 SqliteUtils::Replace(field, SqliteUtils::REP, "");
259 SqliteUtils::Replace(sql, table + "." + DistributedRdb::Field::SHARING_RESOURCE_FIELD,
260 logTable + "." + SHARING_RESOURCE + " AS " + field);
261 }
262 if (queryStatus.second) {
263 sql.append(", " + logTable + ".cursor");
264 sql.append(", CASE WHEN ").append(logTable).append(".")
265 .append("flag & 0x8 = 0x8 THEN true ELSE false END AS deleted_flag");
266 sql.append(", CASE WHEN ").append(logTable).append(".");
267 sql.append("flag & 0x808 = 0x808 THEN 3 WHEN ").append(logTable).append(".flag & 0x800 = 0x800 THEN 1 WHEN ")
268 .append(logTable).append(".flag & 0x8 = 0x8 THEN 2 ELSE 0 END AS data_status");
269 }
270 sql.append(" FROM ").append(table);
271 AppendClause(sql, " INDEXED BY ", predicates.GetIndex());
272 sql.append(" INNER JOIN ").append(logTable).append(" ON ").append(table)
273 .append(".ROWID = ").append(logTable).append(".data_key");
274 auto whereClause = predicates.GetWhereClause();
275 SqliteUtils::Replace(whereClause, SqliteUtils::REP, logTable + ".");
276 AppendClause(sql, " WHERE ", whereClause);
277 AppendClause(sql, " GROUP BY ", predicates.GetGroup(), table);
278 auto order = predicates.GetOrder();
279 SqliteUtils::Replace(order, SqliteUtils::REP, logTable + ".");
280 AppendClause(sql, " ORDER BY ", order);
281 int limit = predicates.GetLimit();
282 auto limitClause = (limit == AbsPredicates::INIT_LIMIT_VALUE) ? "" : std::to_string(limit);
283 int offset = predicates.GetOffset();
284 auto offsetClause = (offset == AbsPredicates::INIT_OFFSET_VALUE) ? "" : std::to_string(offset);
285 AppendClause(sql, " LIMIT ", limitClause);
286 AppendClause(sql, " OFFSET ", offsetClause);
287 return sql;
288 }
289
BuildLockRowQueryString(const AbsRdbPredicates & predicates,const std::vector<std::string> & columns,const std::string & logTable)290 std::string SqliteSqlBuilder::BuildLockRowQueryString(
291 const AbsRdbPredicates &predicates, const std::vector<std::string> &columns, const std::string &logTable)
292 {
293 std::string sql;
294 std::string table = predicates.GetTableName();
295 if (table.empty() || logTable.empty()) {
296 return sql;
297 }
298 sql.append("SELECT ");
299 if (predicates.IsDistinct()) {
300 sql.append("DISTINCT ");
301 }
302 if (!columns.empty()) {
303 AppendColumns(sql, columns, table);
304 } else {
305 sql.append(table + ".*");
306 }
307 sql.append(" FROM ").append(table);
308 AppendClause(sql, " INDEXED BY ", predicates.GetIndex());
309 sql.append(" INNER JOIN ").append(logTable).append(" ON ");
310 sql.append(table).append(".ROWID = ").append(logTable).append(".data_key");
311 auto whereClause = predicates.GetWhereClause();
312 if (whereClause.empty()) {
313 sql.append(" WHERE ").append(logTable).append(".status = 2 OR ").append(logTable).append(".status = 3 ");
314 } else {
315 SqliteUtils::Replace(whereClause, SqliteUtils::REP, logTable + ".");
316 AppendClause(sql, " WHERE ", whereClause);
317 }
318 AppendClause(sql, " GROUP BY ", predicates.GetGroup(), table);
319 auto order = predicates.GetOrder();
320 SqliteUtils::Replace(order, SqliteUtils::REP, logTable + ".");
321 AppendClause(sql, " ORDER BY ", order);
322 int limit = predicates.GetLimit();
323 auto limitClause = (limit == AbsPredicates::INIT_LIMIT_VALUE) ? "" : std::to_string(limit);
324 int offset = predicates.GetOffset();
325 auto offsetClause = (offset == AbsPredicates::INIT_OFFSET_VALUE) ? "" : std::to_string(offset);
326 AppendClause(sql, " LIMIT ", limitClause);
327 AppendClause(sql, " OFFSET ", offsetClause);
328 return sql;
329 }
330
GetSqlArgs(size_t size)331 std::string SqliteSqlBuilder::GetSqlArgs(size_t size)
332 {
333 std::string args((size << 1) - 1, '?');
334 for (size_t i = 1; i < size; ++i) {
335 args[(i << 1) - 1] = ',';
336 }
337 return args;
338 }
339
GenerateSqls(const std::string & table,const ValuesBuckets & buckets,int limit)340 SqliteSqlBuilder::BatchRefSqls SqliteSqlBuilder::GenerateSqls(const std::string &table, const ValuesBuckets &buckets,
341 int limit)
342 {
343 auto [fields, values] = buckets.GetFieldsAndValues();
344 auto columnSize = fields->size();
345 auto rowSize = buckets.RowSize();
346 std::vector<std::reference_wrapper<ValueObject>> args(columnSize * rowSize, nullRef_);
347 std::string sql = "INSERT OR REPLACE INTO " + table + " (";
348 size_t columnIndex = 0;
349 for (auto &field : *fields) {
350 for (size_t row = 0; row < rowSize; ++row) {
351 auto [errorCode, value] = buckets.Get(row, std::ref(field));
352 if (errorCode != E_OK) {
353 continue;
354 }
355 SqliteSqlBuilder::UpdateAssetStatus(value.get(), AssetValue::STATUS_INSERT);
356 args[columnIndex + row * columnSize] = value;
357 }
358 columnIndex++;
359 sql.append(field).append(",");
360 }
361 sql.pop_back();
362 sql.append(") VALUES ");
363 return SqliteSqlBuilder::MakeExecuteSqls(sql, args, columnSize, limit);
364 }
365
MakeExecuteSqls(const std::string & sql,const std::vector<RefValue> & args,int fieldSize,int limit)366 SqliteSqlBuilder::BatchRefSqls SqliteSqlBuilder::MakeExecuteSqls(const std::string &sql,
367 const std::vector<RefValue> &args, int fieldSize, int limit)
368 {
369 if (fieldSize == 0) {
370 return BatchRefSqls();
371 }
372 size_t rowNumbers = args.size() / static_cast<size_t>(fieldSize);
373 size_t maxRowNumbersOneTimes = static_cast<size_t>(limit / fieldSize);
374 if (maxRowNumbersOneTimes == 0) {
375 return BatchRefSqls();
376 }
377 size_t executeTimes = rowNumbers / maxRowNumbersOneTimes;
378 size_t remainingRows = rowNumbers % maxRowNumbersOneTimes;
379 std::string singleRowSqlArgs = "(" + SqliteSqlBuilder::GetSqlArgs(fieldSize) + ")";
380 auto appendAgsSql = [&singleRowSqlArgs, &sql] (size_t rowNumber) {
381 std::string sqlStr = sql;
382 for (size_t i = 0; i < rowNumber; ++i) {
383 sqlStr.append(singleRowSqlArgs).append(",");
384 }
385 sqlStr.pop_back();
386 return sqlStr;
387 };
388 std::string executeSql;
389 BatchRefSqls executeSqls;
390 auto start = args.begin();
391 if (executeTimes != 0) {
392 executeSql = appendAgsSql(maxRowNumbersOneTimes);
393 std::vector<std::vector<RefValue>> sqlArgs;
394 size_t maxVariableNumbers = maxRowNumbersOneTimes * static_cast<size_t>(fieldSize);
395 for (size_t i = 0; i < executeTimes; ++i) {
396 std::vector<RefValue> bindValueArgs(start, start + maxVariableNumbers);
397 sqlArgs.emplace_back(std::move(bindValueArgs));
398 start += maxVariableNumbers;
399 }
400 executeSqls.emplace_back(std::make_pair(executeSql, std::move(sqlArgs)));
401 }
402
403 if (remainingRows != 0) {
404 executeSql = appendAgsSql(remainingRows);
405 std::vector<std::vector<RefValue>> sqlArgs(1, std::vector<RefValue>(start, args.end()));
406 executeSqls.emplace_back(std::make_pair(executeSql, std::move(sqlArgs)));
407 }
408 return executeSqls;
409 }
410
HandleTable(const std::string & tableName)411 std::string SqliteSqlBuilder::HandleTable(const std::string &tableName)
412 {
413 if (tableName.empty()) {
414 return tableName;
415 }
416 std::regex validName("^([a-zA-Z_][a-zA-Z0-9_\\.\\ ]*)$");
417 if (std::regex_match(tableName, validName)) {
418 return tableName;
419 }
420 return "'" + tableName + "'";
421 }
422
UpdateAssetStatus(const ValueObject & val,int32_t status)423 void SqliteSqlBuilder::UpdateAssetStatus(const ValueObject &val, int32_t status)
424 {
425 if (val.GetType() == ValueObject::TYPE_ASSET) {
426 auto *asset = Traits::get_if<ValueObject::Asset>(&val.value);
427 if (asset != nullptr) {
428 asset->status = static_cast<AssetValue::Status>(status);
429 }
430 }
431 if (val.GetType() == ValueObject::TYPE_ASSETS) {
432 auto *assets = Traits::get_if<ValueObject::Assets>(&val.value);
433 if (assets != nullptr) {
434 for (auto &asset : *assets) {
435 asset.status = static_cast<AssetValue::Status>(status);
436 }
437 }
438 }
439 }
440 } // namespace NativeRdb
441 } // namespace OHOS
442