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