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