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