• 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 
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