1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "src/trace_processor/sqlite/query_constraints.h"
18 
19 #include <sqlite3.h>
20 
21 #include <string>
22 
23 #include "perfetto/ext/base/string_splitter.h"
24 
25 namespace perfetto {
26 namespace trace_processor {
27 
28 QueryConstraints::QueryConstraints() = default;
29 QueryConstraints::~QueryConstraints() = default;
30 QueryConstraints::QueryConstraints(QueryConstraints&&) noexcept = default;
31 QueryConstraints& QueryConstraints::operator=(QueryConstraints&&) = default;
32 
FreeSqliteString(char * resource)33 int QueryConstraints::FreeSqliteString(char* resource) {
34   sqlite3_free(resource);
35   return 0;
36 }
37 
operator ==(const QueryConstraints & other) const38 bool QueryConstraints::operator==(const QueryConstraints& other) const {
39   if ((other.constraints().size() != constraints().size()) ||
40       (other.order_by().size() != order_by().size())) {
41     return false;
42   }
43 
44   for (size_t i = 0; i < constraints().size(); ++i) {
45     if ((constraints()[i].column != other.constraints()[i].column) ||
46         (constraints()[i].op != other.constraints()[i].op)) {
47       return false;
48     }
49   }
50 
51   for (size_t i = 0; i < order_by().size(); ++i) {
52     if ((order_by()[i].iColumn != other.order_by()[i].iColumn) ||
53         (order_by()[i].desc != other.order_by()[i].desc)) {
54       return false;
55     }
56   }
57 
58   return true;
59 }
60 
AddConstraint(int column,unsigned char op,int aconstraint_idx)61 void QueryConstraints::AddConstraint(int column,
62                                      unsigned char op,
63                                      int aconstraint_idx) {
64   Constraint c{};
65   c.column = column;
66   c.op = op;
67   c.a_constraint_idx = aconstraint_idx;
68   constraints_.emplace_back(c);
69 }
70 
AddOrderBy(int column,unsigned char desc)71 void QueryConstraints::AddOrderBy(int column, unsigned char desc) {
72   OrderBy ob{};
73   ob.iColumn = column;
74   ob.desc = desc;
75   order_by_.emplace_back(ob);
76 }
77 
ToNewSqlite3String() const78 QueryConstraints::SqliteString QueryConstraints::ToNewSqlite3String() const {
79   std::string str_result;
80   str_result.reserve(512);
81   str_result.append("C");
82   str_result.append(std::to_string(constraints_.size()));
83   str_result.append(",");
84   for (const auto& cs : constraints_) {
85     str_result.append(std::to_string(cs.column));
86     str_result.append(",");
87     str_result.append(std::to_string(cs.op));
88     str_result.append(",");
89   }
90   str_result.append("O");
91   str_result.append(std::to_string(order_by_.size()));
92   str_result.append(",");
93   for (const auto& ob : order_by_) {
94     str_result.append(std::to_string(ob.iColumn));
95     str_result.append(",");
96     str_result.append(std::to_string(ob.desc));
97     str_result.append(",");
98   }
99 
100   // The last char is a "," so overwriting with the null terminator on purpose.
101   SqliteString result(
102       static_cast<char*>(sqlite3_malloc(static_cast<int>(str_result.size()))));
103   strncpy(result.get(), str_result.c_str(), str_result.size());
104   (*result)[str_result.size() - 1] = '\0';
105 
106   return result;
107 }
108 
FromString(const char * idxStr)109 QueryConstraints QueryConstraints::FromString(const char* idxStr) {
110   QueryConstraints qc;
111 
112   base::StringSplitter splitter(std::string(idxStr), ',');
113 
114   PERFETTO_CHECK(splitter.Next() && splitter.cur_token_size() > 1);
115   // The '+ 1' skips the letter 'C' in the first token.
116   long num_constraints = strtol(splitter.cur_token() + 1, nullptr, 10);
117   for (int i = 0; i < num_constraints; ++i) {
118     PERFETTO_CHECK(splitter.Next());
119     int col = static_cast<int>(strtol(splitter.cur_token(), nullptr, 10));
120     PERFETTO_CHECK(splitter.Next());
121     unsigned char op =
122         static_cast<unsigned char>(strtol(splitter.cur_token(), nullptr, 10));
123     qc.AddConstraint(col, op, 0);
124   }
125 
126   PERFETTO_CHECK(splitter.Next() && splitter.cur_token_size() > 1);
127   // The '+ 1' skips the letter 'O' in the current token.
128   long num_order_by = strtol(splitter.cur_token() + 1, nullptr, 10);
129   for (int i = 0; i < num_order_by; ++i) {
130     PERFETTO_CHECK(splitter.Next());
131     int col = static_cast<int>(strtol(splitter.cur_token(), nullptr, 10));
132     PERFETTO_CHECK(splitter.Next());
133     unsigned char desc =
134         static_cast<unsigned char>(strtol(splitter.cur_token(), nullptr, 10));
135     qc.AddOrderBy(col, desc);
136   }
137 
138   PERFETTO_DCHECK(!splitter.Next());
139   return qc;
140 }
141 
142 }  // namespace trace_processor
143 }  // namespace perfetto
144