1 /* Copyright (c) 2013, 2021, Oracle and/or its affiliates.
2
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License, version 2.0,
5 as published by the Free Software Foundation.
6
7 This program is also distributed with certain software (including
8 but not limited to OpenSSL) that is licensed under separate terms,
9 as designated in a particular file or component or in included license
10 documentation. The authors of MySQL hereby grant you an additional
11 permission to link the program and your derivative works with the
12 separately licensed software that they have included with MySQL.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License, version 2.0, for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software Foundation,
21 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
22
23 // First include (the generated) my_config.h, to get correct platform defines.
24 #include "my_config.h"
25 #include <gtest/gtest.h>
26
27 #include "test_utils.h"
28
29 #include "fake_table.h"
30 #include "mock_field_long.h"
31 #include "sql_optimizer.cc"
32 #include "parse_tree_helpers.h"
33
34
35 // Unit tests of the ref optimizer.
36 namespace opt_ref_unittest {
37
38 using my_testing::Server_initializer;
39
40 bool scrap_bool; // Needed by Key_field CTOR.
41
42 /*
43 Class for easy creation of an array of Key_field's. Must be the same
44 size as Key_field.
45 */
46 class Fake_key_field: public Key_field {
47
48 public:
Fake_key_field()49 Fake_key_field() : Key_field(NULL, NULL, 0, 0, false, false, &scrap_bool, 0)
50 {}
51 };
52
53
54 /*
55 Class that tests the ref optimizer. The class creates the fake table
56 definitions:
57
58 t1(a int, b int, key(a, b))
59 t2(a int, b int)
60 */
61 class OptRefTest : public ::testing::Test
62 {
63 public:
64
OptRefTest()65 OptRefTest() :
66 field_t1_a("field1", true),
67 field_t1_b("field2", true),
68 field_t2_a("field3", true),
69 field_t2_b("field4", true),
70 t1(&field_t1_a, &field_t1_b),
71 t2(&field_t2_a, &field_t2_b),
72 t1_key_fields(&t1_key_field_arr[0])
73 {
74 index_over_t1ab_id= t1.create_index(&field_t1_a, &field_t1_b);
75 indexes.set_bit(index_over_t1ab_id);
76
77 t1_join_tab.set_qs(&t1_qep_shared);
78 t1_join_tab.set_table(&t1);
79 t1.pos_in_table_list= &t1_table_list;
80
81 t1_table_list.table= &t1;
82 t1_table_list.embedding= NULL;
83 t1_table_list.derived_keys_ready= true;
84 t1_table_list.set_tableno(0);
85 }
86
SetUp()87 virtual void SetUp()
88 {
89 // We do some pointer arithmetic on these
90 compile_time_assert(sizeof(Fake_key_field) == sizeof(Key_field));
91 initializer.SetUp();
92
93 item_zero= new Item_int(0);
94 item_one= new Item_int(1);
95
96 item_field_t1_a= new Item_field(&field_t1_a);
97 item_field_t1_b= new Item_field(&field_t1_b);
98
99 item_field_t2_a= new Item_field(&field_t2_a);
100 item_field_t2_b= new Item_field(&field_t2_b);
101 }
102
TearDown()103 virtual void TearDown() { initializer.TearDown(); }
104
thd()105 THD *thd() { return initializer.thd(); }
106
107 key_map indexes;
108
109 Mock_field_long field_t1_a, field_t1_b;
110 Mock_field_long field_t2_a, field_t2_b;
111
112 Fake_TABLE t1;
113 Fake_TABLE t2;
114 TABLE_LIST t1_table_list;
115 TABLE_LIST t2_table_list;
116
117 JOIN_TAB t1_join_tab;
118 QEP_shared t1_qep_shared;
119 Fake_key_field t1_key_field_arr[10];
120 Key_field *t1_key_fields;
121
122 Item_int *item_zero;
123 Item_int *item_one;
124
125 Item_field *item_field_t1_a, *item_field_t1_b;
126 Item_field *item_field_t2_a, *item_field_t2_b;
127
128 int index_over_t1ab_id;
129
call_add_key_fields(Item * cond)130 void call_add_key_fields(Item *cond)
131 {
132 uint and_level= 0;
133 add_key_fields(NULL /* join */, &t1_key_fields, &and_level, cond, ~0ULL,
134 NULL);
135 }
136
137 private:
138
139 Server_initializer initializer;
140 };
141
142
make_item_row(Item * a,Item * b)143 Item_row *make_item_row(Item *a, Item *b)
144 {
145 /*
146 The Item_row CTOR doesn't store the reference to the list, hence
147 it can live on the stack.
148 */
149 List<Item> items;
150 items.push_front(b);
151 return new Item_row(POS(), a, items);
152 }
153
TEST_F(OptRefTest,addKeyFieldsFromInOneRow)154 TEST_F(OptRefTest, addKeyFieldsFromInOneRow)
155 {
156 /*
157 We simulate the where condition (a, b) IN ((0, 0)). Note that this
158 can't happen in practice since the parser is hacked to parse such
159 an expression in to (a, b) = (0, 0), which gets rewritten into a =
160 0 AND b = 0 before the ref optimizer runs.
161 */
162 PT_item_list *all_args=
163 new (current_thd->mem_root) PT_item_list;
164 all_args->push_front(make_item_row(item_zero, item_zero));
165 all_args->push_front(make_item_row(item_field_t1_a, item_field_t1_b));
166 Item *cond= new Item_func_in(POS(), all_args, false);
167 Parse_context pc(thd(), thd()->lex->current_select());
168 EXPECT_FALSE(cond->itemize(&pc, &cond));
169
170 call_add_key_fields(cond);
171
172 // We expect the key_fields pointer not to be incremented.
173 EXPECT_EQ(0, t1_key_fields - static_cast<Key_field*>(&t1_key_field_arr[0]));
174 EXPECT_EQ(indexes, t1_join_tab.const_keys)
175 << "SARGable index not present in const_keys";
176 EXPECT_EQ(indexes, t1_join_tab.keys());
177 EXPECT_EQ(0U, t1_key_field_arr[0].level);
178 EXPECT_EQ(0U, t1_key_field_arr[1].level);
179 }
180
TEST_F(OptRefTest,addKeyFieldsFromInTwoRows)181 TEST_F(OptRefTest, addKeyFieldsFromInTwoRows)
182 {
183 // We simulate the where condition (col_a, col_b) IN ((0, 0), (1, 1))
184 PT_item_list *all_args=
185 new (current_thd->mem_root) PT_item_list;
186 all_args->push_front(make_item_row(item_one, item_one));
187 all_args->push_front(make_item_row(item_zero, item_zero));
188 all_args->push_front(make_item_row(item_field_t1_a, item_field_t1_b));
189 Item *cond= new Item_func_in(POS(), all_args, false);
190 Parse_context pc(thd(), thd()->lex->current_select());
191 EXPECT_FALSE(cond->itemize(&pc, &cond));
192
193 call_add_key_fields(cond);
194
195 // We expect the key_fields pointer not to be incremented.
196 EXPECT_EQ(0, t1_key_fields - static_cast<Key_field*>(&t1_key_field_arr[0]));
197 EXPECT_EQ(indexes, t1_join_tab.const_keys)
198 << "SARGable index not present in const_keys";
199 EXPECT_EQ(indexes, t1_join_tab.keys());
200 }
201
TEST_F(OptRefTest,addKeyFieldsFromInOneRowWithCols)202 TEST_F(OptRefTest, addKeyFieldsFromInOneRowWithCols)
203 {
204 // We simulate the where condition (t1.a, t1.b) IN ((t2.a, t2.b))
205 PT_item_list *all_args=
206 new (current_thd->mem_root) PT_item_list;
207 all_args->push_front(make_item_row(item_field_t2_a, item_field_t2_b));
208 all_args->push_front(make_item_row(item_field_t1_a, item_field_t1_b));
209 Item *cond= new Item_func_in(POS(), all_args, false);
210 Parse_context pc(thd(), thd()->lex->current_select());
211 EXPECT_FALSE(cond->itemize(&pc, &cond));
212
213 call_add_key_fields(cond);
214
215 // We expect the key_fields pointer not to be incremented.
216 EXPECT_EQ(0, t1_key_fields - static_cast<Key_field*>(&t1_key_field_arr[0]));
217 EXPECT_EQ(key_map(0), t1_join_tab.const_keys);
218 EXPECT_EQ(indexes, t1_join_tab.keys());
219
220 EXPECT_EQ(t2.pos_in_table_list->map(), t1_join_tab.key_dependent);
221 }
222
TEST_F(OptRefTest,addKeyFieldsFromEq)223 TEST_F(OptRefTest, addKeyFieldsFromEq)
224 {
225 // We simulate the where condition a = 0 AND b = 0
226 Item_func_eq *eq1= new Item_func_eq(item_field_t1_a, item_zero);
227 Item_func_eq *eq2= new Item_func_eq(item_field_t1_b, item_zero);
228 Item_cond_and *cond= new Item_cond_and(eq1, eq2);
229
230 call_add_key_fields(cond);
231
232 /*
233 We expect 2 Key_field's to be written. Actually they're always
234 written, but we expect the pointer to be incremented.
235 */
236 EXPECT_EQ(2, t1_key_fields - static_cast<Key_field*>(&t1_key_field_arr[0]));
237 EXPECT_EQ(indexes, t1_join_tab.const_keys)
238 << "SARGable index not present in const_keys";
239 EXPECT_EQ(indexes, t1_join_tab.keys());
240
241 EXPECT_EQ(0U, t1_join_tab.key_dependent);
242
243 EXPECT_EQ(0U, t1_key_field_arr[0].level);
244 EXPECT_EQ(0U, t1_key_field_arr[1].level);
245 }
246
247 }
248