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 "string_utils.h"
24 #include "anonymous.h"
25
26 namespace OHOS {
27 namespace NativeRdb {
28 std::vector<std::string> g_onConflictClause = {
29 "", " OR ROLLBACK", " OR ABORT", " OR FAIL", " OR IGNORE", " OR REPLACE"
30 };
SqliteSqlBuilder()31 SqliteSqlBuilder::SqliteSqlBuilder() {}
~SqliteSqlBuilder()32 SqliteSqlBuilder::~SqliteSqlBuilder() {}
33
34 /**
35 * Build a delete SQL string using the given condition for SQLite.
36 */
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)37 std::string SqliteSqlBuilder::BuildDeleteString(const std::string &tableName, const std::string &index,
38 const std::string &whereClause, const std::string &group, const std::string &order, int limit, int offset)
39 {
40 std::string sql;
41 sql.append("Delete ").append("FROM ").append(tableName).append(
42 BuildSqlStringFromPredicates(index, whereClause, group, order, limit, offset));
43 return sql;
44 }
45
46 /**
47 * Build a count SQL string using the given condition for SQLite.
48 */
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)49 std::string SqliteSqlBuilder::BuildUpdateString(const ValuesBucket &values, const std::string &tableName,
50 const std::vector<std::string> &whereArgs, const std::string &index, const std::string &whereClause,
51 const std::string &group, const std::string &order, int limit, int offset, std::vector<ValueObject> &bindArgs,
52 ConflictResolution conflictResolution)
53 {
54 std::string sql;
55
56 sql.append("UPDATE")
57 .append(g_onConflictClause[static_cast<int>(conflictResolution)])
58 .append(" ")
59 .append(tableName)
60 .append(" SET ");
61 std::map<std::string, ValueObject> valuesMap;
62 values.GetAll(valuesMap);
63 for (auto iter = valuesMap.begin(); iter != valuesMap.end(); iter++) {
64 sql.append((iter == valuesMap.begin()) ? "" : ",");
65 sql.append(iter->first).append("=?");
66 bindArgs.push_back(iter->second);
67 }
68
69 if (!whereArgs.empty()) {
70 for (size_t i = 0; i < whereArgs.size(); i++) {
71 bindArgs.push_back(ValueObject(whereArgs[i]));
72 }
73 }
74 sql.append(BuildSqlStringFromPredicates(index, whereClause, group, order, limit, offset));
75 return sql;
76 }
77
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)78 std::string SqliteSqlBuilder::BuildUpdateStringOnlyWhere(const ValuesBucket &values, const std::string &tableName,
79 const std::vector<std::string> &whereArgs, const std::string &index, const std::string &whereClause,
80 const std::string &group, const std::string &order, int limit, int offset, std::vector<ValueObject> &bindArgs,
81 ConflictResolution conflictResolution)
82 {
83 std::string sql;
84
85 sql.append("UPDATE")
86 .append(g_onConflictClause[static_cast<int>(conflictResolution)])
87 .append(" ")
88 .append(tableName)
89 .append(" SET ");
90
91 if (!whereArgs.empty()) {
92 for (size_t i = 0; i < whereArgs.size(); i++) {
93 bindArgs.push_back(ValueObject(whereArgs[i]));
94 }
95 }
96
97 sql.append(BuildSqlStringFromPredicates(index, whereClause, group, order, limit, offset));
98 return sql;
99 }
100
101 /**
102 * Build a query SQL string using the given condition for SQLite.
103 */
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)104 int SqliteSqlBuilder::BuildQueryString(bool distinct, const std::string &table, const std::vector<std::string> &columns,
105 const std::string &where, const std::string &groupBy, const std::string &having, const std::string &orderBy,
106 const std::string &limit, const std::string &offset, std::string &outSql)
107 {
108 if (table.empty()) {
109 return E_EMPTY_TABLE_NAME;
110 }
111
112 std::string sql;
113 sql.append("SELECT ");
114 if (distinct) {
115 sql.append("DISTINCT ");
116 }
117 int errorCode = 0;
118 if (columns.size() != 0) {
119 AppendColumns(sql, columns, errorCode);
120 } else {
121 sql.append("* ");
122 }
123 int climit = std::stoi(limit);
124 int coffset = std::stoi(offset);
125 sql.append("FROM ").append(table).append(
126 BuildSqlStringFromPredicates(having, where, groupBy, orderBy, climit, coffset));
127 outSql = sql;
128
129 return errorCode;
130 }
131
132 /**
133 * Build a query SQL string using the given condition for SQLite.
134 */
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)135 std::string SqliteSqlBuilder::BuildQueryStringWithExpr(const std::string &tableName, bool distinct,
136 const std::string &index, const std::string &whereClause, const std::string &group, const std::string &order,
137 int limit, int offset, std::vector<std::string> &expr)
138 {
139 std::string sql;
140
141 sql.append("SELECT ");
142 if (distinct) {
143 sql.append("DISTINCT ");
144 }
145 if (expr.size() != 0) {
146 AppendExpr(sql, expr);
147 } else {
148 sql.append("* ");
149 }
150 sql.append("FROM ").append(tableName).append(
151 BuildSqlStringFromPredicates(index, whereClause, group, order, limit, offset));
152
153 return sql;
154 }
155
156 /**
157 * Build a count SQL string using the given condition for SQLite.
158 */
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)159 std::string SqliteSqlBuilder::BuildCountString(const std::string &tableName, const std::string &index,
160 const std::string &whereClause, const std::string &group, const std::string &order, int limit, int offset)
161 {
162 std::string sql;
163 sql.append("SELECT COUNT(*) FROM ")
164 .append(tableName)
165 .append(BuildSqlStringFromPredicates(index, whereClause, group, order, limit, offset));
166 return sql;
167 }
168
BuildSqlStringFromPredicates(const std::string & index,const std::string & whereClause,const std::string & group,const std::string & order,int limit,int offset)169 std::string SqliteSqlBuilder::BuildSqlStringFromPredicates(const std::string &index, const std::string &whereClause,
170 const std::string &group, const std::string &order, int limit, int offset)
171 {
172 std::string sqlString;
173
174 std::string limitStr = (limit == -1) ? "" : std::to_string(limit);
175 std::string offsetStr = (offset == -1) ? "" : std::to_string(offset);
176
177 AppendClause(sqlString, " INDEXED BY ", index);
178 AppendClause(sqlString, " WHERE ", whereClause);
179 AppendClause(sqlString, " GROUP BY ", group);
180 AppendClause(sqlString, " ORDER BY ", order);
181 AppendClause(sqlString, " LIMIT ", limitStr);
182 AppendClause(sqlString, " OFFSET ", offsetStr);
183
184 return sqlString;
185 }
186
BuildSqlStringFromPredicates(const AbsRdbPredicates & predicates)187 std::string SqliteSqlBuilder::BuildSqlStringFromPredicates(const AbsRdbPredicates &predicates)
188 {
189 std::string sqlString;
190
191 std::string limitStr = (predicates.GetLimit() == -1) ? "" : std::to_string(predicates.GetLimit());
192 std::string offsetStr = (predicates.GetOffset() == -1) ? "" : std::to_string(predicates.GetOffset());
193
194 AppendClause(sqlString, " INDEXED BY ", predicates.GetIndex());
195 AppendClause(sqlString, " WHERE ", predicates.GetWhereClause());
196 AppendClause(sqlString, " GROUP BY ", predicates.GetGroup());
197 AppendClause(sqlString, " ORDER BY ", predicates.GetOrder());
198 AppendClause(sqlString, " LIMIT ", limitStr);
199 AppendClause(sqlString, " OFFSET ", offsetStr);
200
201 return sqlString;
202 }
203
BuildSqlStringFromPredicatesNoWhere(const std::string & index,const std::string & whereClause,const std::string & group,const std::string & order,int limit,int offset)204 std::string SqliteSqlBuilder::BuildSqlStringFromPredicatesNoWhere(const std::string &index,
205 const std::string &whereClause, const std::string &group, const std::string &order, int limit, int offset)
206 {
207 std::string sqlString;
208 std::string limitStr = (limit == -1) ? "" : std::to_string(limit);
209 std::string offsetStr = (offset == -1) ? "" : std::to_string(offset);
210
211 AppendClause(sqlString, " INDEXED BY ", index);
212 AppendClause(sqlString, " ", whereClause);
213 AppendClause(sqlString, " GROUP BY ", group);
214 AppendClause(sqlString, " ORDER BY ", order);
215 AppendClause(sqlString, " LIMIT ", limitStr);
216 AppendClause(sqlString, " OFFSET ", offsetStr);
217
218 return sqlString;
219 }
220
AppendClause(std::string & builder,const std::string & name,const std::string & clause)221 void SqliteSqlBuilder::AppendClause(std::string &builder, const std::string &name, const std::string &clause)
222 {
223 if (clause.empty()) {
224 return;
225 }
226 builder.append(name);
227 builder.append(clause);
228 }
229
230 /**
231 * Add the names that are non-null in columns to s, separating them with commas.
232 */
AppendColumns(std::string & builder,const std::vector<std::string> & columns,int & errorCode)233 void SqliteSqlBuilder::AppendColumns(std::string &builder, const std::vector<std::string> &columns, int &errorCode)
234 {
235 size_t length = columns.size();
236 for (size_t i = 0; i < length; i++) {
237 std::string column = columns[i];
238
239 if (column.size() != 0) {
240 if (i > 0) {
241 builder.append(", ");
242 }
243 builder.append(Normalize(column, errorCode));
244 }
245 }
246
247 builder += ' ';
248 }
249
AppendExpr(std::string & builder,std::vector<std::string> & exprs)250 void SqliteSqlBuilder::AppendExpr(std::string &builder, std::vector<std::string> &exprs)
251 {
252 size_t length = exprs.size();
253
254 for (size_t i = 0; i < length; i++) {
255 std::string expr = exprs[i];
256
257 if (expr.size() != 0) {
258 if (i > 0) {
259 builder.append(", ");
260 }
261 builder.append(expr);
262 }
263 }
264
265 builder += ' ';
266 }
267
IsNotEmptyString(const std::string & str)268 bool SqliteSqlBuilder::IsNotEmptyString(const std::string &str)
269 {
270 return (!str.empty());
271 }
272
BuildQueryString(const AbsRdbPredicates & predicates,const std::vector<std::string> & columns)273 std::string SqliteSqlBuilder::BuildQueryString(const AbsRdbPredicates &predicates,
274 const std::vector<std::string> &columns)
275 {
276 bool distinct = predicates.IsDistinct();
277 std::string tableNameStr = predicates.GetTableName();
278 std::string whereClauseStr = predicates.GetWhereClause();
279 std::string groupStr = predicates.GetGroup();
280 std::string indexStr = predicates.GetIndex();
281 std::string orderStr = predicates.GetOrder();
282 std::string limitStr = std::to_string(predicates.GetLimit());
283 std::string offsetStr = std::to_string(predicates.GetOffset());
284 std::string sqlStr;
285 BuildQueryString(distinct, tableNameStr, columns, whereClauseStr, groupStr, indexStr, orderStr, limitStr,
286 offsetStr, sqlStr);
287 LOG_DEBUG("sqlStr:%{public}s", Anonymous::Change(sqlStr).c_str());
288 return sqlStr;
289 }
290
BuildCountString(const AbsRdbPredicates & predicates)291 std::string SqliteSqlBuilder::BuildCountString(const AbsRdbPredicates &predicates)
292 {
293 std::string tableName = predicates.GetTableName();
294 return "SELECT COUNT(*) FROM " + tableName + BuildSqlStringFromPredicates(predicates);
295 }
296
Normalize(const std::string & source,int & errorCode)297 std::string SqliteSqlBuilder::Normalize(const std::string &source, int &errorCode)
298 {
299 if (StringUtils::IsEmpty(source)) {
300 return "";
301 }
302 // Input source is like "address"
303 std::regex pattern("^(\\w+)$");
304 std::smatch result;
305 auto wordMatcher = std::regex_match(source, result, pattern);
306 if (wordMatcher) {
307 return StringUtils::SurroundWithQuote(source, "`");
308 }
309 // Input source is like "*"
310 std::string obj = "*";
311 if (obj == source) {
312 return "*";
313 }
314
315 // Input source is like "`address name`"
316 std::regex apattern("^(['\"`])?([^`\"']+)\\1$");
317 std::smatch aresult;
318 auto matcher = std::regex_match(source, aresult, apattern);
319 if (matcher) {
320 return source;
321 }
322 return NormalizeComplexPattern(source, errorCode);
323 }
324
NormalizeComplexPattern(const std::string & source,int & errorCode)325 std::string SqliteSqlBuilder::NormalizeComplexPattern(const std::string &source, int &errorCode)
326 {
327 // Remove quotations
328 std::regex quotePattern("['\"`]");
329 std::string replaceResult = regex_replace(source, quotePattern, "");
330 replaceResult.erase(0, replaceResult.find_first_not_of(" "));
331 replaceResult.erase(replaceResult.find_last_not_of(" ") + 1);
332 std::regex pattern2("^(\\w+|\\*)\\s*([.]\\s*(\\w+|\\*))?\\s*(AS|as)?\\s*(\\w+)?$");
333 std::smatch result;
334 bool columnMatcher = std::regex_match(replaceResult, result, pattern2);
335 if (!columnMatcher) {
336 return StringUtils::SurroundWithQuote(replaceResult, "`");
337 }
338
339 // If group 3 is not empty, group 3 is column name.
340 const int three = 3;
341 // Group 5 is alias.
342 const int five = 5;
343 // If group 3 is empty, group 1 is column name, else group 1 is table name.
344 std::string firstName = result[1];
345 std::string lastName = result[three];
346 std::string alias = result[five];
347 if (StringUtils::IsEmpty(firstName)) {
348 return StringUtils::SurroundWithQuote(replaceResult, "`");
349 }
350 std::string aresult(StringUtils::SurroundWithQuote(firstName, "`"));
351 if (!StringUtils::IsEmpty(lastName)) {
352 std::string obj = "*";
353 if (obj == lastName) {
354 // table.*
355 aresult.append(".").append(lastName);
356 } else {
357 // table.column
358 aresult.append(".").append(StringUtils::SurroundWithQuote(lastName, "`"));
359 }
360 }
361 if (!StringUtils::IsEmpty(alias)) {
362 std::string obj = "*";
363
364 if (obj != lastName) {
365 // (table.)column as alias
366 aresult.append(" as ").append(StringUtils::SurroundWithQuote(alias, "`"));
367 } else {
368 // Illegal pattern: table.* as alias
369 errorCode = E_SQLITE_SQL_BUILDER_NORMALIZE_FAIL;
370 return aresult;
371 }
372 }
373 return aresult;
374 }
375 } // namespace NativeRdb
376 } // namespace OHOS
377