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/args_table.h"
18 
19 #include "src/trace_processor/sqlite_utils.h"
20 
21 namespace perfetto {
22 namespace trace_processor {
23 
ArgsTable(sqlite3 *,const TraceStorage * storage)24 ArgsTable::ArgsTable(sqlite3*, const TraceStorage* storage)
25     : storage_(storage) {}
26 
RegisterTable(sqlite3 * db,const TraceStorage * storage)27 void ArgsTable::RegisterTable(sqlite3* db, const TraceStorage* storage) {
28   Table::Register<ArgsTable>(db, storage, "args");
29 }
30 
CreateStorageSchema()31 StorageSchema ArgsTable::CreateStorageSchema() {
32   const auto& args = storage_->args();
33   return StorageSchema::Builder()
34       .AddNumericColumn("arg_set_id", &args.set_ids())
35       .AddStringColumn("flat_key", &args.flat_keys(), &storage_->string_pool())
36       .AddStringColumn("key", &args.keys(), &storage_->string_pool())
37       .AddColumn<ValueColumn>("int_value", VariadicType::kInt, storage_)
38       .AddColumn<ValueColumn>("string_value", VariadicType::kString, storage_)
39       .AddColumn<ValueColumn>("real_value", VariadicType::kReal, storage_)
40       .Build({"arg_set_id", "key"});
41 }
42 
RowCount()43 uint32_t ArgsTable::RowCount() {
44   return static_cast<uint32_t>(storage_->args().args_count());
45 }
46 
BestIndex(const QueryConstraints & qc,BestIndexInfo * info)47 int ArgsTable::BestIndex(const QueryConstraints& qc, BestIndexInfo* info) {
48   // In the case of an id equality filter, we can do a very efficient lookup.
49   if (qc.constraints().size() == 1) {
50     auto id = static_cast<int>(schema().ColumnIndexFromName("arg_set_id"));
51     const auto& cs = qc.constraints().back();
52     if (cs.iColumn == id && sqlite_utils::IsOpEq(cs.op)) {
53       info->estimated_cost = 1;
54       return SQLITE_OK;
55     }
56   }
57 
58   // Otherwise, just give the worst case scenario.
59   info->estimated_cost = static_cast<uint32_t>(storage_->args().args_count());
60   return SQLITE_OK;
61 }
62 
ValueColumn(std::string col_name,VariadicType type,const TraceStorage * storage)63 ArgsTable::ValueColumn::ValueColumn(std::string col_name,
64                                     VariadicType type,
65                                     const TraceStorage* storage)
66     : StorageColumn(col_name, false /* hidden */),
67       type_(type),
68       storage_(storage) {}
69 
ReportResult(sqlite3_context * ctx,uint32_t row) const70 void ArgsTable::ValueColumn::ReportResult(sqlite3_context* ctx,
71                                           uint32_t row) const {
72   const auto& value = storage_->args().arg_values()[row];
73   if (value.type != type_) {
74     sqlite3_result_null(ctx);
75     return;
76   }
77 
78   switch (type_) {
79     case VariadicType::kInt:
80       sqlite_utils::ReportSqliteResult(ctx, value.int_value);
81       break;
82     case VariadicType::kReal:
83       sqlite_utils::ReportSqliteResult(ctx, value.real_value);
84       break;
85     case VariadicType::kString: {
86       const char* str = storage_->GetString(value.string_value).c_str();
87       sqlite3_result_text(ctx, str, -1, sqlite_utils::kSqliteStatic);
88       break;
89     }
90   }
91 }
92 
BoundFilter(int,sqlite3_value *) const93 ArgsTable::ValueColumn::Bounds ArgsTable::ValueColumn::BoundFilter(
94     int,
95     sqlite3_value*) const {
96   return Bounds{};
97 }
98 
Filter(int op,sqlite3_value * value,FilteredRowIndex * index) const99 void ArgsTable::ValueColumn::Filter(int op,
100                                     sqlite3_value* value,
101                                     FilteredRowIndex* index) const {
102   switch (type_) {
103     case VariadicType::kInt: {
104       bool op_is_null = sqlite_utils::IsOpIsNull(op);
105       auto predicate = sqlite_utils::CreateNumericPredicate<int64_t>(op, value);
106       index->FilterRows(
107           [this, predicate, op_is_null](uint32_t row) PERFETTO_ALWAYS_INLINE {
108             const auto& arg = storage_->args().arg_values()[row];
109             return arg.type == type_ ? predicate(arg.int_value) : op_is_null;
110           });
111       break;
112     }
113     case VariadicType::kReal: {
114       bool op_is_null = sqlite_utils::IsOpIsNull(op);
115       auto predicate = sqlite_utils::CreateNumericPredicate<double>(op, value);
116       index->FilterRows(
117           [this, predicate, op_is_null](uint32_t row) PERFETTO_ALWAYS_INLINE {
118             const auto& arg = storage_->args().arg_values()[row];
119             return arg.type == type_ ? predicate(arg.real_value) : op_is_null;
120           });
121       break;
122     }
123     case VariadicType::kString: {
124       auto predicate = sqlite_utils::CreateStringPredicate(op, value);
125       index->FilterRows([this,
126                          &predicate](uint32_t row) PERFETTO_ALWAYS_INLINE {
127         const auto& arg = storage_->args().arg_values()[row];
128         return arg.type == type_
129                    ? predicate(storage_->GetString(arg.string_value).c_str())
130                    : predicate(nullptr);
131       });
132       break;
133     }
134   }
135 }
136 
Sort(const QueryConstraints::OrderBy & ob) const137 ArgsTable::ValueColumn::Comparator ArgsTable::ValueColumn::Sort(
138     const QueryConstraints::OrderBy& ob) const {
139   if (ob.desc) {
140     return [this](uint32_t f, uint32_t s) { return -CompareRefsAsc(f, s); };
141   }
142   return [this](uint32_t f, uint32_t s) { return CompareRefsAsc(f, s); };
143 }
144 
CompareRefsAsc(uint32_t f,uint32_t s) const145 int ArgsTable::ValueColumn::CompareRefsAsc(uint32_t f, uint32_t s) const {
146   const auto& arg_f = storage_->args().arg_values()[f];
147   const auto& arg_s = storage_->args().arg_values()[s];
148 
149   if (arg_f.type == type_ && arg_s.type == type_) {
150     switch (type_) {
151       case VariadicType::kInt:
152         return sqlite_utils::CompareValuesAsc(arg_f.int_value, arg_s.int_value);
153       case VariadicType::kReal:
154         return sqlite_utils::CompareValuesAsc(arg_f.real_value,
155                                               arg_s.real_value);
156       case VariadicType::kString: {
157         const auto& f_str = storage_->GetString(arg_f.string_value);
158         const auto& s_str = storage_->GetString(arg_s.string_value);
159         return sqlite_utils::CompareValuesAsc(f_str, s_str);
160       }
161     }
162   } else if (arg_s.type == type_) {
163     return -1;
164   } else if (arg_f.type == type_) {
165     return 1;
166   }
167   return 0;
168 }
169 
170 }  // namespace trace_processor
171 }  // namespace perfetto
172