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