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