• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "perfetto/ext/base/string_utils.h"
25 
26 namespace perfetto {
27 namespace trace_processor {
28 
QueryConstraints(uint64_t cols_used)29 QueryConstraints::QueryConstraints(uint64_t cols_used)
30     : cols_used_(cols_used) {}
31 QueryConstraints::~QueryConstraints() = default;
32 QueryConstraints::QueryConstraints(QueryConstraints&&) noexcept = default;
33 QueryConstraints& QueryConstraints::operator=(QueryConstraints&&) noexcept =
34     default;
35 
FreeSqliteString(char * resource)36 int QueryConstraints::FreeSqliteString(char* resource) {
37   sqlite3_free(resource);
38   return 0;
39 }
40 
operator ==(const QueryConstraints & other) const41 bool QueryConstraints::operator==(const QueryConstraints& other) const {
42   if ((other.constraints().size() != constraints().size()) ||
43       (other.order_by().size() != order_by().size()) ||
44       other.cols_used() != cols_used()) {
45     return false;
46   }
47 
48   for (size_t i = 0; i < constraints().size(); ++i) {
49     if ((constraints()[i].column != other.constraints()[i].column) ||
50         (constraints()[i].op != other.constraints()[i].op)) {
51       return false;
52     }
53   }
54 
55   for (size_t i = 0; i < order_by().size(); ++i) {
56     if ((order_by()[i].iColumn != other.order_by()[i].iColumn) ||
57         (order_by()[i].desc != other.order_by()[i].desc)) {
58       return false;
59     }
60   }
61 
62   return true;
63 }
64 
AddConstraint(int column,unsigned char op,int aconstraint_idx)65 void QueryConstraints::AddConstraint(int column,
66                                      unsigned char op,
67                                      int aconstraint_idx) {
68   Constraint c{};
69   c.column = column;
70   c.op = op;
71   c.a_constraint_idx = aconstraint_idx;
72   constraints_.emplace_back(c);
73 }
74 
AddOrderBy(int column,unsigned char desc)75 void QueryConstraints::AddOrderBy(int column, unsigned char desc) {
76   OrderBy ob{};
77   ob.iColumn = column;
78   ob.desc = desc;
79   order_by_.emplace_back(ob);
80 }
81 
ToNewSqlite3String() const82 QueryConstraints::SqliteString QueryConstraints::ToNewSqlite3String() const {
83   std::string str_result;
84   str_result.reserve(512);
85 
86   // Add all the constraints.
87   str_result.append("C");
88   str_result.append(std::to_string(constraints_.size()));
89   str_result.append(",");
90   for (const auto& cs : constraints_) {
91     str_result.append(std::to_string(cs.column));
92     str_result.append(",");
93     str_result.append(std::to_string(cs.op));
94     str_result.append(",");
95   }
96   str_result.back() = ';';
97 
98   // Add all the clauses.
99   str_result.append("O");
100   str_result.append(std::to_string(order_by_.size()));
101   str_result.append(",");
102   for (const auto& ob : order_by_) {
103     str_result.append(std::to_string(ob.iColumn));
104     str_result.append(",");
105     str_result.append(std::to_string(ob.desc));
106     str_result.append(",");
107   }
108   str_result.back() = ';';
109 
110   // Add the columns used.
111   str_result.append("U");
112   str_result.append(std::to_string(cols_used_));
113 
114   SqliteString result(static_cast<char*>(
115       sqlite3_malloc(static_cast<int>(str_result.size() + 1))));
116   base::StringCopy(result.get(), str_result.c_str(), str_result.size() + 1);
117   return result;
118 }
119 
FromString(const char * idxStr)120 QueryConstraints QueryConstraints::FromString(const char* idxStr) {
121   QueryConstraints qc;
122 
123   base::StringSplitter outer_splitter(std::string(idxStr), ';');
124 
125   // Handle the CONSTRAINT section of the string.
126   PERFETTO_CHECK(outer_splitter.Next() && outer_splitter.cur_token_size() > 1);
127   {
128     base::StringSplitter splitter(&outer_splitter, ',');
129     PERFETTO_CHECK(splitter.Next() && splitter.cur_token_size() > 1);
130 
131     // The '[1]' skips the letter 'C' in the first token.
132     int64_t num_constraints = *base::CStringToInt64(&splitter.cur_token()[1]);
133     for (int i = 0; i < num_constraints; ++i) {
134       PERFETTO_CHECK(splitter.Next());
135       int col = static_cast<int>(*base::CStringToInt32(splitter.cur_token()));
136       PERFETTO_CHECK(splitter.Next());
137       unsigned char op = static_cast<unsigned char>(
138           *base::CStringToUInt32(splitter.cur_token()));
139       qc.AddConstraint(col, op, 0);
140     }
141   }
142 
143   // Handle the ORDER BY section of the string.
144   PERFETTO_CHECK(outer_splitter.Next() && outer_splitter.cur_token_size() > 1);
145   {
146     base::StringSplitter splitter(&outer_splitter, ',');
147     PERFETTO_CHECK(splitter.Next() && splitter.cur_token_size() > 1);
148 
149     // The '[1]' skips the letter 'O' in the current token.
150     int64_t num_order_by = *base::CStringToInt64(&splitter.cur_token()[1]);
151     for (int i = 0; i < num_order_by; ++i) {
152       PERFETTO_CHECK(splitter.Next());
153       int col = static_cast<int>(*base::CStringToInt32(splitter.cur_token()));
154       PERFETTO_CHECK(splitter.Next());
155       unsigned char desc = static_cast<unsigned char>(
156           *base::CStringToUInt32(splitter.cur_token()));
157       qc.AddOrderBy(col, desc);
158     }
159   }
160 
161   // Handle the COLS USED section of the string.
162   PERFETTO_CHECK(outer_splitter.Next() && outer_splitter.cur_token_size() > 1);
163   {
164     // The '[1]' skips the letter 'U' in the current token.
165     qc.cols_used_ = *base::CStringToUInt64(&outer_splitter.cur_token()[1]);
166   }
167 
168   PERFETTO_DCHECK(!outer_splitter.Next());
169   return qc;
170 }
171 
172 }  // namespace trace_processor
173 }  // namespace perfetto
174