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