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 "AbsPredicates"
16 #include "abs_predicates.h"
17 
18 #include <algorithm>
19 #include <initializer_list>
20 #include <variant>
21 
22 #include "logger.h"
23 #include "rdb_trace.h"
24 #include "rdb_types.h"
25 #include "sqlite_sql_builder.h"
26 #include "string_utils.h"
27 
28 namespace OHOS {
29 namespace NativeRdb {
30 using namespace OHOS::Rdb;
31 static constexpr const char* FLAG[AbsPredicates::Origin::BUTT] = { "0x02", "0x0", "0x0" };
AbsPredicates()32 AbsPredicates::AbsPredicates()
33 {
34     Initial();
35 }
36 
~AbsPredicates()37 AbsPredicates::~AbsPredicates()
38 {
39 }
40 
Clear()41 void AbsPredicates::Clear()
42 {
43     Initial();
44 }
45 
IsNeedAnd() const46 bool AbsPredicates::IsNeedAnd() const
47 {
48     return isNeedAnd;
49 }
50 
51 /**
52  * Restricts the value of the field to be greater than the specified value.
53  */
EqualTo(const std::string & field,const ValueObject & value)54 AbsPredicates *AbsPredicates::EqualTo(const std::string &field, const ValueObject &value)
55 {
56     if (!CheckParameter("equalTo", field, {})) {
57         return this;
58     }
59     hasSpecificField = hasSpecificField || IsSpecificField(field);
60     ValueObject valObj = value;
61     std::string newField = field;
62     std::string flagVal;
63     if (newField == DistributedRdb::Field::ORIGIN_FIELD) {
64         newField = LOG_ORIGIN_FIELD;
65         double location = 0;
66         valObj.GetDouble(location);
67         if (location < 0 || location > Origin::REMOTE) {
68             return this;
69         }
70         flagVal = FLAG[static_cast<int>(location)];
71         valObj = ValueObject(flagVal);
72     }
73     if (isNeedAnd) {
74         whereClause += "AND ";
75     } else {
76         isNeedAnd = true;
77     }
78     if (flagVal.empty()) {
79         whereClause += newField + " = ? ";
80         bindArgs.push_back(std::move(valObj));
81     } else {
82         whereClause += "(" + newField + " & 0x02 = " + flagVal + ")";
83     }
84     return this;
85 }
86 
87 /**
88  * Restricts the value of the field to be unequal to the specified value.
89  */
NotEqualTo(const std::string & field,const ValueObject & value)90 AbsPredicates *AbsPredicates::NotEqualTo(const std::string &field, const ValueObject &value)
91 {
92     if (!CheckParameter("notEqualTo", field, {})) {
93         return this;
94     }
95     hasSpecificField = hasSpecificField || IsSpecificField(field);
96     CheckIsNeedAnd();
97     whereClause += field + " <> ? ";
98     bindArgs.push_back(value);
99     return this;
100 }
101 
BeginWrap()102 AbsPredicates *AbsPredicates::BeginWrap()
103 {
104     if (isNeedAnd) {
105         whereClause += "AND ";
106         isNeedAnd = false;
107     }
108     whereClause += " ( ";
109     return this;
110 }
111 
EndWrap()112 AbsPredicates *AbsPredicates::EndWrap()
113 {
114     if (!isNeedAnd) {
115         LOG_WARN("Fail to add EndWrap.");
116         return this;
117     }
118     whereClause += " ) ";
119     return this;
120 }
121 
Or()122 AbsPredicates *AbsPredicates::Or()
123 {
124     if (!isNeedAnd) {
125         LOG_WARN("Fail to add Or.");
126         return this;
127     }
128     whereClause += " OR ";
129     isNeedAnd = false;
130     return this;
131 }
132 
And()133 AbsPredicates *AbsPredicates::And()
134 {
135     return this;
136 }
137 
138 /**
139  * Restricts the value of the field to contain the specified string.
140  */
Contains(const std::string & field,const std::string & value)141 AbsPredicates *AbsPredicates::Contains(const std::string &field, const std::string &value)
142 {
143     if (!CheckParameter("contains", field, { value })) {
144         return this;
145     }
146     CheckIsNeedAnd();
147     whereClause += field + " LIKE ? ";
148     bindArgs.push_back(ValueObject("%" + value + "%"));
149     return this;
150 }
151 
152 /**
153  * Restricts the value of the field to not contain the specified string.
154  */
NotContains(const std::string & field,const std::string & value)155 AbsPredicates *AbsPredicates::NotContains(const std::string &field, const std::string &value)
156 {
157     if (!CheckParameter("notContains", field, { value })) {
158         return this;
159     }
160     CheckIsNeedAnd();
161     whereClause += field + " NOT LIKE ? ";
162     bindArgs.push_back(ValueObject("%" + value + "%"));
163     return this;
164 }
165 
166 /**
167  * Restricts the field to start with the specified string.
168  */
BeginsWith(const std::string & field,const std::string & value)169 AbsPredicates *AbsPredicates::BeginsWith(const std::string &field, const std::string &value)
170 {
171     if (!CheckParameter("beginsWith", field, { value })) {
172         return this;
173     }
174     CheckIsNeedAnd();
175     whereClause += field + " LIKE ? ";
176     bindArgs.push_back(ValueObject(value + "%"));
177     return this;
178 }
179 
180 /**
181  * Restricts the field to end with the specified string.
182  */
EndsWith(const std::string & field,const std::string & value)183 AbsPredicates *AbsPredicates::EndsWith(const std::string &field, const std::string &value)
184 {
185     if (!CheckParameter("endsWith", field, { value })) {
186         return this;
187     }
188     CheckIsNeedAnd();
189     whereClause += field + " LIKE ? ";
190     bindArgs.push_back(ValueObject("%" + value));
191     return this;
192 }
193 
194 /**
195  * Restricts the value of the field to be null.
196  */
IsNull(const std::string & field)197 AbsPredicates *AbsPredicates::IsNull(const std::string &field)
198 {
199     if (!CheckParameter("isNull", field, {})) {
200         return this;
201     }
202     CheckIsNeedAnd();
203     whereClause += field + " IS NULL ";
204     return this;
205 }
206 
207 /**
208  * estricts the value of the field not to be null.
209  */
IsNotNull(const std::string & field)210 AbsPredicates *AbsPredicates::IsNotNull(const std::string &field)
211 {
212     if (!CheckParameter("isNotNull", field, {})) {
213         return this;
214     }
215     CheckIsNeedAnd();
216     whereClause += field + " IS NOT NULL ";
217     return this;
218 }
219 
220 /**
221  * Restricts the value of the field to have a pattern like field.
222  */
Like(const std::string & field,const std::string & value)223 AbsPredicates *AbsPredicates::Like(const std::string &field, const std::string &value)
224 {
225     if (!CheckParameter("like", field, { value })) {
226         return this;
227     }
228     CheckIsNeedAnd();
229     whereClause += field + " LIKE ? ";
230     bindArgs.push_back(ValueObject(value));
231     return this;
232 }
233 
234 /**
235  * Restricts the value of the field to have a pattern like field.
236  */
NotLike(const std::string & field,const std::string & value)237 AbsPredicates *AbsPredicates::NotLike(const std::string &field, const std::string &value)
238 {
239     if (!CheckParameter("notLike", field, { value })) {
240         return this;
241     }
242     CheckIsNeedAnd();
243     whereClause += field + " NOT LIKE ? ";
244     bindArgs.push_back(ValueObject(value));
245     return this;
246 }
247 
248 /**
249  * Configures to match the specified field whose data type is String and the value contains a wildcard.
250  */
Glob(const std::string & field,const std::string & value)251 AbsPredicates *AbsPredicates::Glob(const std::string &field, const std::string &value)
252 {
253     if (!CheckParameter("glob", field, { value })) {
254         return this;
255     }
256     CheckIsNeedAnd();
257     whereClause += field + " GLOB ? ";
258     bindArgs.push_back(ValueObject(value));
259     return this;
260 }
261 
262 /**
263  * Restricts the value of the field to be unequal to the specified value.
264  */
Between(const std::string & field,const ValueObject & low,const ValueObject & high)265 AbsPredicates *AbsPredicates::Between(const std::string &field, const ValueObject &low, const ValueObject &high)
266 {
267     if (!CheckParameter("between", field, { low, high })) {
268         return this;
269     }
270     hasSpecificField = hasSpecificField || IsSpecificField(field);
271     CheckIsNeedAnd();
272     whereClause += field + " BETWEEN ? AND ? ";
273     bindArgs.push_back(low);
274     bindArgs.push_back(high);
275     return this;
276 }
277 
278 /**
279  * Configures to match the specified field whose data type is String and value is out of a given range.
280  */
NotBetween(const std::string & field,const ValueObject & low,const ValueObject & high)281 AbsPredicates *AbsPredicates::NotBetween(const std::string &field, const ValueObject &low, const ValueObject &high)
282 {
283     if (!CheckParameter("notBetween", field, { low, high })) {
284         return this;
285     }
286     hasSpecificField = hasSpecificField || IsSpecificField(field);
287     CheckIsNeedAnd();
288     whereClause += field + " NOT BETWEEN ? AND ? ";
289     bindArgs.push_back(low);
290     bindArgs.push_back(high);
291     return this;
292 }
293 
294 /**
295  * Restricts the value of the field to be greater than the specified value.
296  */
GreaterThan(const std::string & field,const ValueObject & value)297 AbsPredicates *AbsPredicates::GreaterThan(const std::string &field, const ValueObject &value)
298 {
299     if (!CheckParameter("greaterThan", field, { value })) {
300         return this;
301     }
302     hasSpecificField = hasSpecificField || IsSpecificField(field);
303     CheckIsNeedAnd();
304     whereClause += field + " > ? ";
305     bindArgs.push_back(value);
306     return this;
307 }
308 
309 /**
310  * Restricts the value of the field to be smaller than the specified value.
311  */
LessThan(const std::string & field,const ValueObject & value)312 AbsPredicates *AbsPredicates::LessThan(const std::string &field, const ValueObject &value)
313 {
314     if (!CheckParameter("lessThan", field, { value })) {
315         return this;
316     }
317     hasSpecificField = hasSpecificField || IsSpecificField(field);
318     CheckIsNeedAnd();
319     whereClause += field + " < ? ";
320     bindArgs.push_back(value);
321     return this;
322 }
323 
324 /**
325  * Restricts the value of the field to be greater than or equal to the specified value.
326  */
GreaterThanOrEqualTo(const std::string & field,const ValueObject & value)327 AbsPredicates *AbsPredicates::GreaterThanOrEqualTo(const std::string &field, const ValueObject &value)
328 {
329     if (!CheckParameter("greaterThanOrEqualTo", field, { value })) {
330         return this;
331     }
332     hasSpecificField = hasSpecificField || IsSpecificField(field);
333     CheckIsNeedAnd();
334     whereClause += field + " >= ? ";
335     bindArgs.push_back(value);
336     return this;
337 }
338 
339 /**
340  * Restricts the value of the field to be smaller than or equal to the specified value.
341  */
LessThanOrEqualTo(const std::string & field,const ValueObject & value)342 AbsPredicates *AbsPredicates::LessThanOrEqualTo(const std::string &field, const ValueObject &value)
343 {
344     if (!CheckParameter("greaterThanOrEqualTo", field, { value })) {
345         return this;
346     }
347     hasSpecificField = hasSpecificField || IsSpecificField(field);
348     CheckIsNeedAnd();
349     whereClause += field + " <= ? ";
350     bindArgs.push_back(value);
351     return this;
352 }
353 
354 /**
355  * Restricts the ascending order of the return list. When there are several orders,
356  * the one close to the head has the highest priority.
357  */
OrderByAsc(const std::string & field)358 AbsPredicates *AbsPredicates::OrderByAsc(const std::string &field)
359 {
360     if (!CheckParameter("orderByAsc", field, {})) {
361         return this;
362     }
363     hasSpecificField = hasSpecificField || IsSpecificField(field);
364     if (isSorted) {
365         order += ',';
366     }
367     order += field + " ASC ";
368     isSorted = true;
369     return this;
370 }
371 
372 /**
373  * Restricts the descending order of the return list. When there are several orders,
374  * the one close to the head has the highest priority.
375  */
OrderByDesc(const std::string & field)376 AbsPredicates *AbsPredicates::OrderByDesc(const std::string &field)
377 {
378     if (!CheckParameter("orderByDesc", field, {})) {
379         return this;
380     }
381     hasSpecificField = hasSpecificField || IsSpecificField(field);
382     if (isSorted) {
383         order += ',';
384     }
385     order += field + " DESC ";
386     isSorted = true;
387     return this;
388 }
389 
Distinct()390 AbsPredicates *AbsPredicates::Distinct()
391 {
392     distinct = true;
393     return this;
394 }
395 
396 /**
397  * Restricts the max number of return records.
398  */
Limit(const int limit)399 AbsPredicates *AbsPredicates::Limit(const int limit)
400 {
401     this->limit = (limit <= 0) ? -1 : limit;
402     return this;
403 }
404 
405 /**
406  * Restricts the max number of return records.
407  */
Limit(const int offset,const int limit)408 AbsPredicates *AbsPredicates::Limit(const int offset, const int limit)
409 {
410     return this->Limit(limit)->Offset(offset);
411 }
412 
413 /**
414  * Configures to specify the start position of the returned result.
415  */
Offset(const int offset)416 AbsPredicates *AbsPredicates::Offset(const int offset)
417 {
418     this->offset = (offset < 0) ? -1 : offset;
419     return this;
420 }
421 
422 /**
423  * Configures {@code AbsPredicates} to group query results by specified columns.
424  */
GroupBy(const std::vector<std::string> & fields)425 AbsPredicates *AbsPredicates::GroupBy(const std::vector<std::string> &fields)
426 {
427     if (fields.empty()) {
428         LOG_WARN("groupBy() fails because fields can't be null.");
429         return this;
430     }
431     for (auto &field : fields) {
432         if (!CheckParameter("GroupBy", field, {})) {
433             return this;
434         }
435         group += field + ",";
436     }
437     size_t pos = group.find_last_of(",");
438     if (pos != group.npos) {
439         group.erase(pos, 1);
440     }
441     return this;
442 }
443 
444 /**
445  * Configures {@code AbsPredicates} to specify the index column.
446  */
IndexedBy(const std::string & indexName)447 AbsPredicates *AbsPredicates::IndexedBy(const std::string &indexName)
448 {
449     if (!CheckParameter("indexedBy", indexName, {})) {
450         return this;
451     }
452     index = RemoveQuotes(indexName);
453     return this;
454 }
455 
In(const std::string & field,const std::vector<std::string> & values)456 AbsPredicates *AbsPredicates::In(const std::string &field, const std::vector<std::string> &values)
457 {
458     std::vector<ValueObject> bindArgs;
459     std::for_each(values.begin(), values.end(), [&bindArgs](const auto &it) { bindArgs.push_back(ValueObject(it)); });
460     return In(field, bindArgs);
461 }
462 
463 /**
464  * Configures to match the specified field whose data type is String array and values are within a given range.
465  */
In(const std::string & field,const std::vector<ValueObject> & values)466 AbsPredicates *AbsPredicates::In(const std::string &field, const std::vector<ValueObject> &values)
467 {
468     bool chekParaFlag = CheckParameter("in", field, {});
469     if (!chekParaFlag) {
470         return this;
471     }
472 
473     CheckIsNeedAnd();
474 
475     std::vector<std::string> replaceValues(values.size(), "?");
476     bindArgs.insert(bindArgs.end(), values.begin(), values.end());
477     AppendWhereClauseWithInOrNotIn(" IN ", field, replaceValues);
478     return this;
479 }
480 
NotIn(const std::string & field,const std::vector<std::string> & values)481 AbsPredicates *AbsPredicates::NotIn(const std::string &field, const std::vector<std::string> &values)
482 {
483     std::vector<ValueObject> bindArgs;
484     std::for_each(values.begin(), values.end(), [&bindArgs](const auto &it) { bindArgs.push_back(ValueObject(it)); });
485     return NotIn(field, bindArgs);
486 }
487 
488 /**
489  * Configures to match the specified field whose data type is String array and values are out of a given range.
490  */
NotIn(const std::string & field,const std::vector<ValueObject> & values)491 AbsPredicates *AbsPredicates::NotIn(const std::string &field, const std::vector<ValueObject> &values)
492 {
493     bool chekParaFlag = CheckParameter("notIn", field, {});
494     if (!chekParaFlag) {
495         return this;
496     }
497     CheckIsNeedAnd();
498     std::vector<std::string> replaceValues(values.size(), "?");
499     bindArgs.insert(bindArgs.end(), values.begin(), values.end());
500     AppendWhereClauseWithInOrNotIn(" NOT IN ", field, replaceValues);
501     return this;
502 }
503 
Initial()504 void AbsPredicates::Initial()
505 {
506     distinct = false;
507     isNeedAnd = false;
508     isSorted = false;
509     bindArgs.clear();
510     whereClause.clear();
511     order.clear();
512     group.clear();
513     index.clear();
514     limit = INIT_LIMIT_VALUE;
515     offset = INIT_OFFSET_VALUE;
516 }
517 
518 /**
519  * Check the parameter validity.
520  */
CheckParameter(const std::string & methodName,const std::string & field,const std::initializer_list<ValueObject> & args) const521 bool AbsPredicates::CheckParameter(
522     const std::string &methodName, const std::string &field, const std::initializer_list<ValueObject> &args) const
523 {
524     if (field.empty()) {
525         LOG_WARN("%{public}s: string 'field' is empty.", methodName.c_str());
526         return false;
527     }
528     for (auto &arg : args) {
529         if (auto pval = std::get_if<std::string>(&arg.value)) {
530             if ((*pval).empty()) {
531                 LOG_WARN("%{public}s: value is empty.", methodName.c_str());
532                 return false;
533             }
534         }
535     }
536     return true;
537 }
538 
RemoveQuotes(const std::string & source) const539 std::string AbsPredicates::RemoveQuotes(const std::string &source) const
540 {
541     std::string src = source;
542     if (source.empty()) {
543         return source;
544     }
545     src.erase(std::remove(src.begin(), src.end(), '\''), src.end());
546     src.erase(std::remove(src.begin(), src.end(), '\"'), src.end());
547     src.erase(std::remove(src.begin(), src.end(), '`'), src.end());
548     return src;
549 }
550 
CheckIsNeedAnd()551 void AbsPredicates::CheckIsNeedAnd()
552 {
553     if (isNeedAnd) {
554         whereClause += " AND ";
555     } else {
556         isNeedAnd = true;
557     }
558 }
559 
AppendWhereClauseWithInOrNotIn(const std::string & methodName,const std::string & field,const std::vector<std::string> & replaceValues)560 void AbsPredicates::AppendWhereClauseWithInOrNotIn(
561     const std::string &methodName, const std::string &field, const std::vector<std::string> &replaceValues)
562 {
563     whereClause += field + StringUtils::SurroundWithFunction(methodName, ",", replaceValues);
564 }
565 
GetStatement() const566 std::string AbsPredicates::GetStatement()  const
567 {
568     return SqliteSqlBuilder::BuildSqlStringFromPredicates(*this);
569 }
570 
GetWhereClause() const571 std::string AbsPredicates::GetWhereClause() const
572 {
573     return whereClause;
574 }
575 
SetWhereClause(const std::string & whereClause)576 void AbsPredicates::SetWhereClause(const std::string &whereClause)
577 {
578     if (whereClause.empty()) {
579         return;
580     }
581     this->whereClause = whereClause;
582 }
583 
GetWhereArgs() const584 std::vector<std::string> AbsPredicates::GetWhereArgs() const
585 {
586     std::vector<std::string> whereArgs;
587     for (auto &arg : this->bindArgs) {
588         std::string temp;
589         if (!arg.GetString(temp)) {
590             LOG_DEBUG("No matching type, empty string instead.");
591         }
592         whereArgs.push_back(temp);
593     }
594     return whereArgs;
595 }
596 
SetWhereArgs(const std::vector<std::string> & whereArgs)597 void AbsPredicates::SetWhereArgs(const std::vector<std::string> &whereArgs)
598 {
599     this->bindArgs.clear();
600     std::for_each(whereArgs.begin(), whereArgs.end(), [this](const auto &it) { bindArgs.push_back(ValueObject(it)); });
601 }
602 
GetBindArgs() const603 std::vector<ValueObject> AbsPredicates::GetBindArgs() const
604 {
605     return bindArgs;
606 }
607 
SetBindArgs(const std::vector<ValueObject> & bindArgs)608 void AbsPredicates::SetBindArgs(const std::vector<ValueObject> &bindArgs)
609 {
610     this->bindArgs = bindArgs;
611 }
612 
GetOrder() const613 std::string AbsPredicates::GetOrder() const
614 {
615     return order;
616 }
617 
SetOrder(const std::string & order)618 void AbsPredicates::SetOrder(const std::string &order)
619 {
620     if (order.empty()) {
621         return;
622     }
623     this->order = order;
624 }
625 
GetLimit() const626 int AbsPredicates::GetLimit() const
627 {
628     return limit;
629 }
630 
GetOffset() const631 int AbsPredicates::GetOffset() const
632 {
633     return offset;
634 }
635 
IsDistinct() const636 bool AbsPredicates::IsDistinct() const
637 {
638     return distinct;
639 }
640 
IsSorted() const641 bool AbsPredicates::IsSorted() const
642 {
643     return isSorted;
644 }
645 
HasSpecificField() const646 bool AbsPredicates::HasSpecificField() const
647 {
648     return hasSpecificField;
649 }
650 
GetGroup() const651 std::string AbsPredicates::GetGroup() const
652 {
653     return group;
654 }
655 
GetIndex() const656 std::string AbsPredicates::GetIndex() const
657 {
658     return index;
659 }
660 } // namespace NativeRdb
661 } // namespace OHOS