• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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