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
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
26 namespace OHOS {
27 namespace NativeRdb {
28
29 const std::string SqliteSqlBuilder::patternWords_ = "['\"`]?(\\w+)['\"`]?|['\"`]([^`\"']+)['\"`]";
30 const std::string SqliteSqlBuilder::patternTableColumn_ = "(" + patternWords_ + ")[.](" + patternWords_ + "|\\*)";
31
32 std::vector<std::string> g_onConflictClause = {
33 "", " OR ROLLBACK", " OR ABORT", " OR FAIL", " OR IGNORE", " OR REPLACE"
34 };
SqliteSqlBuilder()35 SqliteSqlBuilder::SqliteSqlBuilder() {}
~SqliteSqlBuilder()36 SqliteSqlBuilder::~SqliteSqlBuilder() {}
37
38 /**
39 * Build a delete SQL string using the given condition for SQLite.
40 */
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)41 std::string SqliteSqlBuilder::BuildDeleteString(const std::string &tableName, const std::string &index,
42 const std::string &whereClause, const std::string &group, const std::string &order, int limit, int offset)
43 {
44 std::string sql;
45 sql.append("Delete ").append("FROM ").append(tableName).append(
46 BuildSqlStringFromPredicates(index, whereClause, group, order, limit, offset));
47 return sql;
48 }
49
50 /**
51 * Build a count SQL string using the given condition for SQLite.
52 */
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)53 std::string SqliteSqlBuilder::BuildUpdateString(const ValuesBucket &values, const std::string &tableName,
54 const std::vector<std::string> &whereArgs, const std::string &index, const std::string &whereClause,
55 const std::string &group, const std::string &order, int limit, int offset, std::vector<ValueObject> &bindArgs,
56 ConflictResolution conflictResolution)
57 {
58 std::string sql;
59
60 sql.append("UPDATE")
61 .append(g_onConflictClause[static_cast<int>(conflictResolution)])
62 .append(" ")
63 .append(tableName)
64 .append(" SET ");
65 std::map<std::string, ValueObject> valuesMap;
66 values.GetAll(valuesMap);
67 for (auto iter = valuesMap.begin(); iter != valuesMap.end(); iter++) {
68 sql.append((iter == valuesMap.begin()) ? "" : ",");
69 sql.append(iter->first).append("=?");
70 bindArgs.push_back(iter->second);
71 }
72
73 if (!whereArgs.empty()) {
74 for (size_t i = 0; i < whereArgs.size(); i++) {
75 bindArgs.push_back(ValueObject(whereArgs[i]));
76 }
77 }
78 sql.append(BuildSqlStringFromPredicates(index, whereClause, group, order, limit, offset));
79 return sql;
80 }
81
BuildUpdateStringOnlyWhere(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)82 std::string SqliteSqlBuilder::BuildUpdateStringOnlyWhere(const ValuesBucket &values, const std::string &tableName,
83 const std::vector<std::string> &whereArgs, const std::string &index, const std::string &whereClause,
84 const std::string &group, const std::string &order, int limit, int offset, std::vector<ValueObject> &bindArgs,
85 ConflictResolution conflictResolution)
86 {
87 std::string sql;
88
89 sql.append("UPDATE")
90 .append(g_onConflictClause[static_cast<int>(conflictResolution)])
91 .append(" ")
92 .append(tableName)
93 .append(" SET ");
94
95 if (!whereArgs.empty()) {
96 for (size_t i = 0; i < whereArgs.size(); i++) {
97 bindArgs.push_back(ValueObject(whereArgs[i]));
98 }
99 }
100
101 sql.append(BuildSqlStringFromPredicates(index, whereClause, group, order, limit, offset));
102 return sql;
103 }
104
105 /**
106 * Build a query SQL string using the given condition for SQLite.
107 */
BuildQueryString(bool distinct,const std::string & table,const std::vector<std::string> & columns,const std::string & where,const std::string & groupBy,const std::string & having,const std::string & orderBy,const std::string & limit,const std::string & offset,std::string & outSql)108 int SqliteSqlBuilder::BuildQueryString(bool distinct, const std::string &table, const std::vector<std::string> &columns,
109 const std::string &where, const std::string &groupBy, const std::string &having, const std::string &orderBy,
110 const std::string &limit, const std::string &offset, std::string &outSql)
111 {
112 if (table.empty()) {
113 return E_EMPTY_TABLE_NAME;
114 }
115
116 std::string sql;
117 sql.append("SELECT ");
118 if (distinct) {
119 sql.append("DISTINCT ");
120 }
121 int errorCode = 0;
122 if (columns.size() != 0) {
123 AppendColumns(sql, columns, errorCode);
124 } else {
125 sql.append("* ");
126 }
127 int climit = std::stoi(limit);
128 int coffset = std::stoi(offset);
129 sql.append("FROM ").append(table).append(
130 BuildSqlStringFromPredicates(having, where, groupBy, orderBy, climit, coffset));
131 outSql = sql;
132
133 return errorCode;
134 }
135
136 /**
137 * Build a query SQL string using the given condition for SQLite.
138 */
BuildQueryStringWithExpr(const std::string & tableName,bool distinct,const std::string & index,const std::string & whereClause,const std::string & group,const std::string & order,int limit,int offset,std::vector<std::string> & expr)139 std::string SqliteSqlBuilder::BuildQueryStringWithExpr(const std::string &tableName, bool distinct,
140 const std::string &index, const std::string &whereClause, const std::string &group, const std::string &order,
141 int limit, int offset, std::vector<std::string> &expr)
142 {
143 std::string sql;
144
145 sql.append("SELECT ");
146 if (distinct) {
147 sql.append("DISTINCT ");
148 }
149 if (expr.size() != 0) {
150 AppendExpr(sql, expr);
151 } else {
152 sql.append("* ");
153 }
154 sql.append("FROM ").append(tableName).append(
155 BuildSqlStringFromPredicates(index, whereClause, group, order, limit, offset));
156
157 return sql;
158 }
159
160 /**
161 * Build a count SQL string using the given condition for SQLite.
162 */
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)163 std::string SqliteSqlBuilder::BuildCountString(const std::string &tableName, const std::string &index,
164 const std::string &whereClause, const std::string &group, const std::string &order, int limit, int offset)
165 {
166 std::string sql;
167 sql.append("SELECT COUNT(*) FROM ")
168 .append(tableName)
169 .append(BuildSqlStringFromPredicates(index, whereClause, group, order, limit, offset));
170 return sql;
171 }
172
BuildSqlStringFromPredicates(const std::string & index,const std::string & whereClause,const std::string & group,const std::string & order,int limit,int offset)173 std::string SqliteSqlBuilder::BuildSqlStringFromPredicates(const std::string &index, const std::string &whereClause,
174 const std::string &group, const std::string &order, int limit, int offset)
175 {
176 std::string sqlString;
177
178 std::string limitStr = (limit == -1) ? "" : std::to_string(limit);
179 std::string offsetStr = (offset == -1) ? "" : std::to_string(offset);
180
181 AppendClause(sqlString, " INDEXED BY ", index);
182 AppendClause(sqlString, " WHERE ", whereClause);
183 AppendClause(sqlString, " GROUP BY ", group);
184 AppendClause(sqlString, " ORDER BY ", order);
185 AppendClause(sqlString, " LIMIT ", limitStr);
186 AppendClause(sqlString, " OFFSET ", offsetStr);
187
188 return sqlString;
189 }
190
BuildSqlStringFromPredicates(const AbsRdbPredicates & predicates)191 std::string SqliteSqlBuilder::BuildSqlStringFromPredicates(const AbsRdbPredicates &predicates)
192 {
193 std::string sqlString;
194
195 std::string limitStr = (predicates.GetLimit() == -1) ? "" : std::to_string(predicates.GetLimit());
196 std::string offsetStr = (predicates.GetOffset() == -1) ? "" : std::to_string(predicates.GetOffset());
197
198 AppendClause(sqlString, " INDEXED BY ", predicates.GetIndex());
199 AppendClause(sqlString, " WHERE ", predicates.GetWhereClause());
200 AppendClause(sqlString, " GROUP BY ", predicates.GetGroup());
201 AppendClause(sqlString, " ORDER BY ", predicates.GetOrder());
202 AppendClause(sqlString, " LIMIT ", limitStr);
203 AppendClause(sqlString, " OFFSET ", offsetStr);
204
205 return sqlString;
206 }
207
BuildSqlStringFromPredicatesNoWhere(const std::string & index,const std::string & whereClause,const std::string & group,const std::string & order,int limit,int offset)208 std::string SqliteSqlBuilder::BuildSqlStringFromPredicatesNoWhere(const std::string &index,
209 const std::string &whereClause, const std::string &group, const std::string &order, int limit, int offset)
210 {
211 std::string sqlString;
212 std::string limitStr = (limit == -1) ? "" : std::to_string(limit);
213 std::string offsetStr = (offset == -1) ? "" : std::to_string(offset);
214
215 AppendClause(sqlString, " INDEXED BY ", index);
216 AppendClause(sqlString, " ", whereClause);
217 AppendClause(sqlString, " GROUP BY ", group);
218 AppendClause(sqlString, " ORDER BY ", order);
219 AppendClause(sqlString, " LIMIT ", limitStr);
220 AppendClause(sqlString, " OFFSET ", offsetStr);
221
222 return sqlString;
223 }
224
AppendClause(std::string & builder,const std::string & name,const std::string & clause)225 void SqliteSqlBuilder::AppendClause(std::string &builder, const std::string &name, const std::string &clause)
226 {
227 if (clause.empty()) {
228 return;
229 }
230 builder.append(name);
231 builder.append(clause);
232 }
233
234 /**
235 * Add the names that are non-null in columns to s, separating them with commas.
236 */
AppendColumns(std::string & builder,const std::vector<std::string> & columns,int & errorCode)237 void SqliteSqlBuilder::AppendColumns(std::string &builder, const std::vector<std::string> &columns, int &errorCode)
238 {
239 size_t length = columns.size();
240 for (size_t i = 0; i < length; i++) {
241 std::string column = columns[i];
242
243 if (column.size() != 0) {
244 if (i > 0) {
245 builder.append(", ");
246 }
247 builder.append(NormalizeAlias(column, errorCode));
248 }
249 }
250
251 builder += ' ';
252 }
253
AppendExpr(std::string & builder,std::vector<std::string> & exprs)254 void SqliteSqlBuilder::AppendExpr(std::string &builder, std::vector<std::string> &exprs)
255 {
256 size_t length = exprs.size();
257
258 for (size_t i = 0; i < length; i++) {
259 std::string expr = exprs[i];
260
261 if (expr.size() != 0) {
262 if (i > 0) {
263 builder.append(", ");
264 }
265 builder.append(expr);
266 }
267 }
268
269 builder += ' ';
270 }
271
IsNotEmptyString(const std::string & str)272 bool SqliteSqlBuilder::IsNotEmptyString(const std::string &str)
273 {
274 return (!str.empty());
275 }
276
BuildQueryString(const AbsRdbPredicates & predicates,const std::vector<std::string> & columns)277 std::string SqliteSqlBuilder::BuildQueryString(
278 const AbsRdbPredicates &predicates, const std::vector<std::string> &columns)
279 {
280 bool distinct = predicates.IsDistinct();
281 std::string tableNameStr = predicates.GetJoinClause();
282 std::string whereClauseStr = predicates.GetWhereClause();
283 std::string groupStr = predicates.GetGroup();
284 std::string indexStr = predicates.GetIndex();
285 std::string orderStr = predicates.GetOrder();
286 std::string limitStr = std::to_string(predicates.GetLimit());
287 std::string offsetStr = std::to_string(predicates.GetOffset());
288 std::string sqlStr;
289 BuildQueryString(
290 distinct, tableNameStr, columns, whereClauseStr, groupStr, indexStr, orderStr, limitStr, offsetStr, sqlStr);
291 return sqlStr;
292 }
293
BuildCountString(const AbsRdbPredicates & predicates)294 std::string SqliteSqlBuilder::BuildCountString(const AbsRdbPredicates &predicates)
295 {
296 std::string tableName = predicates.GetTableName();
297 return "SELECT COUNT(*) FROM " + tableName + BuildSqlStringFromPredicates(predicates);
298 }
299
PredicatesNormalize(const std::string & source,int & errorCode)300 std::string SqliteSqlBuilder::PredicatesNormalize(const std::string &source, int &errorCode)
301 {
302 errorCode = 0;
303 if (StringUtils::IsEmpty(source)) {
304 LOG_ERROR("Input param is empty.");
305 return "";
306 }
307
308 auto index = source.rfind("(*");
309 if (index != -1) {
310 return source;
311 }
312
313 index = source.rfind(".");
314 if (index == -1) {
315 return StringUtils::SurroundWithQuote(source, "`");
316 }
317
318 auto fIndex = source.find(".");
319 if (index != fIndex) {
320 LOG_ERROR("More than one '.' exists in source");
321 errorCode = -1;
322 return "";
323 }
324
325 std::string retStr1 = StringUtils::SurroundWithQuote(source.substr(0, index), "`");
326 std::string source2 = StringUtils::Trim(source.substr(index + 1));
327 std::string retStr2 = source2 == "*" ? source2 : StringUtils::SurroundWithQuote(source2, "`");
328
329 return retStr1 + "." + retStr2;
330 }
331
NormalizeWords(const std::string & source,int & errorCode)332 std::string SqliteSqlBuilder::NormalizeWords(const std::string &source, int &errorCode)
333 {
334 DISTRIBUTED_DATA_HITRACE("SqliteSqlBuilder::NormalizeWords");
335 errorCode = 0;
336 if (StringUtils::IsEmpty(source)) {
337 return "";
338 }
339 std::string strTrimed = StringUtils::Trim(source);
340 std::string obj = "*";
341 if (obj == strTrimed) {
342 return "*";
343 }
344 std::regex pattern("^(" + patternWords_ + ")$");
345 std::smatch result;
346 auto wordMatcher = std::regex_match(strTrimed, result, pattern);
347 if (!wordMatcher) {
348 return "";
349 }
350 std::string words = StringUtils::IsEmpty(result[2]) ? result[3] : result[2];
351 return StringUtils::SurroundWithQuote(words, "`");
352 }
353
NormalizeTableColumn(const std::string & source,int & errorCode)354 std::string SqliteSqlBuilder::NormalizeTableColumn(const std::string &source, int &errorCode)
355 {
356 DISTRIBUTED_DATA_HITRACE("SqliteSqlBuilder::NormalizeTableColumn");
357 errorCode = 0;
358 if (StringUtils::IsEmpty(source)) {
359 return "";
360 }
361 std::string strTrimed = StringUtils::Trim(source);
362 std::regex pattern_table("^(" + patternWords_ + ")[.](" + patternWords_ + "|\\*)$");
363 std::smatch result;
364 bool columnMatcher = std::regex_match(strTrimed, result, pattern_table);
365 if (!columnMatcher) {
366 return "";
367 }
368 std::string firstName = StringUtils::IsEmpty(result[2]) ? StringUtils::Trim(result[3])
369 : StringUtils::Trim(result[2]);
370 std::string lastName = StringUtils::IsEmpty(result[5]) ? StringUtils::Trim(result[6])
371 : StringUtils::Trim(result[5]);
372 lastName = StringUtils::IsEmpty(lastName) ? StringUtils::Trim(result[4]) : lastName;
373 std::string aresult(StringUtils::SurroundWithQuote(firstName, "`"));
374 std::string obj = "*";
375 if (obj == lastName) {
376 aresult.append(".").append(lastName);
377 } else {
378 aresult.append(".").append(StringUtils::SurroundWithQuote(lastName, "`"));
379 }
380 return aresult;
381 }
382
NormalizeMethodPattern(const std::string & source,int & errorCode)383 std::string SqliteSqlBuilder::NormalizeMethodPattern(const std::string &source, int &errorCode)
384 {
385 DISTRIBUTED_DATA_HITRACE("SqliteSqlBuilder::NormalizeMethodPattern");
386 errorCode = 0;
387 if (StringUtils::IsEmpty(source)) {
388 return "";
389 }
390 std::string strTrimed = StringUtils::Trim(source);
391 std::regex pattern("^(\\w+)(\\()(.*)(\\))$");
392 std::smatch result;
393 bool columnMatcher = std::regex_match(strTrimed, result, pattern);
394 if (!columnMatcher) {
395 return StringUtils::SurroundWithQuote(strTrimed, "`");
396 }
397 std::string methodName = StringUtils::Trim(result[1]);
398 std::string methodParams = StringUtils::Trim(result[3]);
399 if (StringUtils::IsEmpty(methodParams)) {
400 return methodName.append("()");
401 }
402 return methodName.append("(").append(methodParams).append(")");
403 }
404
Normalize(const std::string & words,int & errorCode)405 std::string SqliteSqlBuilder::Normalize(const std::string &words, int &errorCode)
406 {
407 DISTRIBUTED_DATA_HITRACE("SqliteSqlBuilder::Normalize");
408 errorCode = 0;
409 std::string aresult = NormalizeWords(words, errorCode);
410 if (!StringUtils::IsEmpty(aresult)) {
411 return aresult;
412 }
413 aresult = NormalizeTableColumn(words, errorCode);
414 if (!StringUtils::IsEmpty(aresult)) {
415 return aresult;
416 }
417 aresult = NormalizeMethodPattern(words, errorCode);
418 if (!StringUtils::IsEmpty(aresult)) {
419 return aresult;
420 }
421 return "";
422 }
423
NormalizeAlias(const std::string & source,int & errorCode)424 std::string SqliteSqlBuilder::NormalizeAlias(const std::string &source, int &errorCode)
425 {
426 errorCode = 0;
427 if (StringUtils::IsEmpty(source)) {
428 return "";
429 }
430 std::string strTrimed = StringUtils::Trim(source);
431 std::regex pattern("^(.+)\\s+(AS|as)\\s+(" + patternWords_ + ")$");
432 std::smatch result;
433 bool columnMatcher = std::regex_match(strTrimed, result, pattern);
434 if (!columnMatcher) {
435 return Normalize(strTrimed, errorCode);
436 }
437 std::string words = StringUtils::Trim(result[1]);
438 if (StringUtils::IsEmpty(words)) {
439 errorCode = E_SQLITE_SQL_BUILDER_NORMALIZE_FAIL;
440 return "";
441 }
442 std::string aresult = Normalize(words, errorCode);
443 if (StringUtils::IsEmpty(aresult)) {
444 LOG_DEBUG("NormalizeAlias words no match Normalize %{public}s", words.c_str());
445 return "";
446 }
447
448 std::string alias = result[3];
449 if (StringUtils::IsEmpty(alias)) {
450 LOG_DEBUG("NormalizeAlias alias is empty");
451 return aresult;
452 }
453 std::string obj = aresult.substr(aresult.length() - 1, 1);
454 if ("*" == obj) {
455 errorCode = E_SQLITE_SQL_BUILDER_NORMALIZE_FAIL;
456 return "";
457 }
458 std::string presult = NormalizeWords(alias, errorCode);
459 if (!StringUtils::IsEmpty(presult)) {
460 LOG_DEBUG("NormalizeAlias alias no match NormalizeWords %{public}s", alias.c_str());
461 aresult.append(" as ").append(presult);
462 }
463 return aresult;
464 }
465 } // namespace NativeRdb
466 } // namespace OHOS
467