1 
2 /*
3  * Copyright (C) 2019 The Android Open Source Project
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 #include "src/trace_processor/sqlite/db_sqlite_table.h"
19 
20 #include "test/gtest_and_gmock.h"
21 
22 namespace perfetto {
23 namespace trace_processor {
24 namespace {
25 
CreateSchema()26 Table::Schema CreateSchema() {
27   Table::Schema schema;
28   schema.columns.push_back({"id", SqlValue::Type::kLong, true /* is_id */,
29                             true /* is_sorted */, false /* is_hidden */});
30   schema.columns.push_back({"type", SqlValue::Type::kLong, false /* is_id */,
31                             false /* is_sorted */, false /* is_hidden */});
32   schema.columns.push_back({"test1", SqlValue::Type::kLong, false /* is_id */,
33                             true /* is_sorted */, false /* is_hidden */});
34   schema.columns.push_back({"test2", SqlValue::Type::kLong, false /* is_id */,
35                             false /* is_sorted */, false /* is_hidden */});
36   schema.columns.push_back({"test3", SqlValue::Type::kLong, false /* is_id */,
37                             false /* is_sorted */, false /* is_hidden */});
38   return schema;
39 }
40 
TEST(DbSqliteTable,IdEqCheaperThanOtherEq)41 TEST(DbSqliteTable, IdEqCheaperThanOtherEq) {
42   auto schema = CreateSchema();
43   constexpr uint32_t kRowCount = 1234;
44 
45   QueryConstraints id_eq;
46   id_eq.AddConstraint(0u, SQLITE_INDEX_CONSTRAINT_EQ, 0u);
47 
48   auto id_cost = DbSqliteTable::EstimateCost(schema, kRowCount, id_eq);
49 
50   QueryConstraints a_eq;
51   a_eq.AddConstraint(1u, SQLITE_INDEX_CONSTRAINT_EQ, 1u);
52 
53   auto a_cost = DbSqliteTable::EstimateCost(schema, kRowCount, a_eq);
54 
55   ASSERT_LT(id_cost.cost, a_cost.cost);
56   ASSERT_LT(id_cost.rows, a_cost.rows);
57 }
58 
TEST(DbSqliteTable,IdEqCheaperThatOtherConstraint)59 TEST(DbSqliteTable, IdEqCheaperThatOtherConstraint) {
60   auto schema = CreateSchema();
61   constexpr uint32_t kRowCount = 1234;
62 
63   QueryConstraints id_eq;
64   id_eq.AddConstraint(0u, SQLITE_INDEX_CONSTRAINT_EQ, 0u);
65 
66   auto id_cost = DbSqliteTable::EstimateCost(schema, kRowCount, id_eq);
67 
68   QueryConstraints a_eq;
69   a_eq.AddConstraint(1u, SQLITE_INDEX_CONSTRAINT_LT, 1u);
70 
71   auto a_cost = DbSqliteTable::EstimateCost(schema, kRowCount, a_eq);
72 
73   ASSERT_LT(id_cost.cost, a_cost.cost);
74   ASSERT_LT(id_cost.rows, a_cost.rows);
75 }
76 
TEST(DbSqliteTable,SingleEqCheaperThanMultipleConstraint)77 TEST(DbSqliteTable, SingleEqCheaperThanMultipleConstraint) {
78   auto schema = CreateSchema();
79   constexpr uint32_t kRowCount = 1234;
80 
81   QueryConstraints single_eq;
82   single_eq.AddConstraint(1u, SQLITE_INDEX_CONSTRAINT_EQ, 0u);
83 
84   auto single_cost = DbSqliteTable::EstimateCost(schema, kRowCount, single_eq);
85 
86   QueryConstraints multi_eq;
87   multi_eq.AddConstraint(1u, SQLITE_INDEX_CONSTRAINT_EQ, 0u);
88   multi_eq.AddConstraint(2u, SQLITE_INDEX_CONSTRAINT_EQ, 1u);
89 
90   auto multi_cost = DbSqliteTable::EstimateCost(schema, kRowCount, multi_eq);
91 
92   // The cost of the single filter should be cheaper (because of our special
93   // handling of single equality). But the number of rows should be greater.
94   ASSERT_LT(single_cost.cost, multi_cost.cost);
95   ASSERT_GT(single_cost.rows, multi_cost.rows);
96 }
97 
TEST(DbSqliteTable,MultiSortedEqCheaperThanMultiUnsortedEq)98 TEST(DbSqliteTable, MultiSortedEqCheaperThanMultiUnsortedEq) {
99   auto schema = CreateSchema();
100   constexpr uint32_t kRowCount = 1234;
101 
102   QueryConstraints sorted_eq;
103   sorted_eq.AddConstraint(2u, SQLITE_INDEX_CONSTRAINT_EQ, 0u);
104   sorted_eq.AddConstraint(3u, SQLITE_INDEX_CONSTRAINT_EQ, 0u);
105 
106   auto sorted_cost = DbSqliteTable::EstimateCost(schema, kRowCount, sorted_eq);
107 
108   QueryConstraints unsorted_eq;
109   unsorted_eq.AddConstraint(3u, SQLITE_INDEX_CONSTRAINT_EQ, 0u);
110   unsorted_eq.AddConstraint(4u, SQLITE_INDEX_CONSTRAINT_EQ, 0u);
111 
112   auto unsorted_cost =
113       DbSqliteTable::EstimateCost(schema, kRowCount, unsorted_eq);
114 
115   // The number of rows should be the same but the cost of the sorted
116   // query should be less.
117   ASSERT_LT(sorted_cost.cost, unsorted_cost.cost);
118   ASSERT_EQ(sorted_cost.rows, unsorted_cost.rows);
119 }
120 
TEST(DbSqliteTable,EmptyTableCosting)121 TEST(DbSqliteTable, EmptyTableCosting) {
122   auto schema = CreateSchema();
123 
124   QueryConstraints id_eq;
125   id_eq.AddConstraint(0u, SQLITE_INDEX_CONSTRAINT_EQ, 0u);
126 
127   auto id_cost = DbSqliteTable::EstimateCost(schema, 0, id_eq);
128 
129   QueryConstraints a_eq;
130   a_eq.AddConstraint(1u, SQLITE_INDEX_CONSTRAINT_LT, 1u);
131 
132   auto a_cost = DbSqliteTable::EstimateCost(schema, 0, a_eq);
133 
134   ASSERT_DOUBLE_EQ(id_cost.cost, a_cost.cost);
135   ASSERT_EQ(id_cost.rows, a_cost.rows);
136 }
137 
TEST(DbSqliteTable,OrderByOnSortedCheaper)138 TEST(DbSqliteTable, OrderByOnSortedCheaper) {
139   auto schema = CreateSchema();
140   constexpr uint32_t kRowCount = 1234;
141 
142   QueryConstraints a_qc;
143   a_qc.AddOrderBy(1u, false);
144 
145   auto a_cost = DbSqliteTable::EstimateCost(schema, kRowCount, a_qc);
146 
147   // On an ordered column, the constraint for sorting would get pruned so
148   // we would end up with an empty constraint set.
149   QueryConstraints sorted_qc;
150   auto sorted_cost = DbSqliteTable::EstimateCost(schema, kRowCount, sorted_qc);
151 
152   ASSERT_LT(sorted_cost.cost, a_cost.cost);
153   ASSERT_EQ(sorted_cost.rows, a_cost.rows);
154 }
155 
156 }  // namespace
157 }  // namespace trace_processor
158 }  // namespace perfetto
159