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/query_constraints.h"
18 
19 #include <sqlite3.h>
20 #include <string>
21 
22 #include "perfetto/base/string_splitter.h"
23 
24 namespace perfetto {
25 namespace trace_processor {
26 
27 QueryConstraints::QueryConstraints() = default;
28 QueryConstraints::~QueryConstraints() = default;
29 QueryConstraints::QueryConstraints(QueryConstraints&&) noexcept = default;
30 QueryConstraints& QueryConstraints::operator=(QueryConstraints&&) = default;
31 
FreeSqliteString(char * resource)32 int QueryConstraints::FreeSqliteString(char* resource) {
33   sqlite3_free(resource);
34   return 0;
35 }
36 
operator ==(const QueryConstraints & other) const37 bool QueryConstraints::operator==(const QueryConstraints& other) const {
38   if ((other.constraints().size() != constraints().size()) ||
39       (other.order_by().size() != order_by().size())) {
40     return false;
41   }
42 
43   for (size_t i = 0; i < constraints().size(); ++i) {
44     if ((constraints()[i].iColumn != other.constraints()[i].iColumn) ||
45         (constraints()[i].op != other.constraints()[i].op)) {
46       return false;
47     }
48   }
49 
50   for (size_t i = 0; i < order_by().size(); ++i) {
51     if ((order_by()[i].iColumn != other.order_by()[i].iColumn) ||
52         (order_by()[i].desc != other.order_by()[i].desc)) {
53       return false;
54     }
55   }
56 
57   return true;
58 }
59 
AddConstraint(int column,unsigned char op)60 void QueryConstraints::AddConstraint(int column, unsigned char op) {
61   Constraint c{};
62   c.iColumn = column;
63   c.op = op;
64   constraints_.emplace_back(c);
65 }
66 
AddOrderBy(int column,unsigned char desc)67 void QueryConstraints::AddOrderBy(int column, unsigned char desc) {
68   OrderBy ob{};
69   ob.iColumn = column;
70   ob.desc = desc;
71   order_by_.emplace_back(ob);
72 }
73 
ToNewSqlite3String() const74 QueryConstraints::SqliteString QueryConstraints::ToNewSqlite3String() const {
75   std::string str_result;
76   str_result.reserve(512);
77   str_result.append("C");
78   str_result.append(std::to_string(constraints_.size()));
79   str_result.append(",");
80   for (const auto& cs : constraints_) {
81     str_result.append(std::to_string(cs.iColumn));
82     str_result.append(",");
83     str_result.append(std::to_string(cs.op));
84     str_result.append(",");
85   }
86   str_result.append("O");
87   str_result.append(std::to_string(order_by_.size()));
88   str_result.append(",");
89   for (const auto& ob : order_by_) {
90     str_result.append(std::to_string(ob.iColumn));
91     str_result.append(",");
92     str_result.append(std::to_string(ob.desc));
93     str_result.append(",");
94   }
95 
96   // The last char is a "," so overwriting with the null terminator on purpose.
97   SqliteString result(
98       static_cast<char*>(sqlite3_malloc(static_cast<int>(str_result.size()))));
99   strncpy(result.get(), str_result.c_str(), str_result.size());
100   (*result)[str_result.size() - 1] = '\0';
101 
102   return result;
103 }
104 
FromString(const char * idxStr)105 QueryConstraints QueryConstraints::FromString(const char* idxStr) {
106   QueryConstraints qc;
107 
108   base::StringSplitter splitter(std::string(idxStr), ',');
109 
110   PERFETTO_CHECK(splitter.Next() && splitter.cur_token_size() > 1);
111   // The '+ 1' skips the letter 'C' in the first token.
112   long num_constraints = strtol(splitter.cur_token() + 1, nullptr, 10);
113   for (int i = 0; i < num_constraints; ++i) {
114     PERFETTO_CHECK(splitter.Next());
115     int col = static_cast<int>(strtol(splitter.cur_token(), nullptr, 10));
116     PERFETTO_CHECK(splitter.Next());
117     unsigned char op =
118         static_cast<unsigned char>(strtol(splitter.cur_token(), nullptr, 10));
119     qc.AddConstraint(col, op);
120   }
121 
122   PERFETTO_CHECK(splitter.Next() && splitter.cur_token_size() > 1);
123   // The '+ 1' skips the letter 'O' in the current token.
124   long num_order_by = strtol(splitter.cur_token() + 1, nullptr, 10);
125   for (int i = 0; i < num_order_by; ++i) {
126     PERFETTO_CHECK(splitter.Next());
127     int col = static_cast<int>(strtol(splitter.cur_token(), nullptr, 10));
128     PERFETTO_CHECK(splitter.Next());
129     unsigned char desc =
130         static_cast<unsigned char>(strtol(splitter.cur_token(), nullptr, 10));
131     qc.AddOrderBy(col, desc);
132   }
133 
134   PERFETTO_DCHECK(!splitter.Next());
135   return qc;
136 }
137 
138 }  // namespace trace_processor
139 }  // namespace perfetto
140