241 lines
7.1 KiB
C++

/* Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software Foundation,
51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
// First include (the generated) my_config.h, to get correct platform defines.
#include "my_config.h"
#include <gtest/gtest.h>
#include "test_utils.h"
#include "fake_table.h"
#include "mock_field_long.h"
#include "sql_optimizer.cc"
#include "parse_tree_helpers.h"
// Unit tests of the ref optimizer.
namespace opt_ref_unittest {
using my_testing::Server_initializer;
bool scrap_bool; // Needed by Key_field CTOR.
/*
Class for easy creation of an array of Key_field's. Must be the same
size as Key_field.
*/
class Fake_key_field: public Key_field {
public:
Fake_key_field() : Key_field(NULL, NULL, 0, 0, false, false, &scrap_bool, 0)
{}
};
/*
Class that tests the ref optimizer. The class creates the fake table
definitions:
t1(a int, b int, key(a, b))
t2(a int, b int)
*/
class OptRefTest : public ::testing::Test
{
public:
OptRefTest() :
field_t1_a("field1", true),
field_t1_b("field2", true),
field_t2_a("field3", true),
field_t2_b("field4", true),
t1(&field_t1_a, &field_t1_b),
t2(&field_t2_a, &field_t2_b),
t1_key_fields(&t1_key_field_arr[0])
{
index_over_t1ab_id= t1.create_index(&field_t1_a, &field_t1_b);
indexes.set_bit(index_over_t1ab_id);
t1_join_tab.set_qs(&t1_qep_shared);
t1_join_tab.set_table(&t1);
t1.pos_in_table_list= &t1_table_list;
t1_table_list.table= &t1;
t1_table_list.embedding= NULL;
t1_table_list.derived_keys_ready= true;
t1_table_list.set_tableno(0);
}
virtual void SetUp()
{
// We do some pointer arithmetic on these
compile_time_assert(sizeof(Fake_key_field) == sizeof(Key_field));
initializer.SetUp();
item_zero= new Item_int(0);
item_one= new Item_int(1);
item_field_t1_a= new Item_field(&field_t1_a);
item_field_t1_b= new Item_field(&field_t1_b);
item_field_t2_a= new Item_field(&field_t2_a);
item_field_t2_b= new Item_field(&field_t2_b);
}
virtual void TearDown() { initializer.TearDown(); }
THD *thd() { return initializer.thd(); }
key_map indexes;
Mock_field_long field_t1_a, field_t1_b;
Mock_field_long field_t2_a, field_t2_b;
Fake_TABLE t1;
Fake_TABLE t2;
TABLE_LIST t1_table_list;
TABLE_LIST t2_table_list;
JOIN_TAB t1_join_tab;
QEP_shared t1_qep_shared;
Fake_key_field t1_key_field_arr[10];
Key_field *t1_key_fields;
Item_int *item_zero;
Item_int *item_one;
Item_field *item_field_t1_a, *item_field_t1_b;
Item_field *item_field_t2_a, *item_field_t2_b;
int index_over_t1ab_id;
void call_add_key_fields(Item *cond)
{
uint and_level= 0;
add_key_fields(NULL /* join */, &t1_key_fields, &and_level, cond, ~0ULL,
NULL);
}
private:
Server_initializer initializer;
};
Item_row *make_item_row(Item *a, Item *b)
{
/*
The Item_row CTOR doesn't store the reference to the list, hence
it can live on the stack.
*/
List<Item> items;
items.push_front(b);
return new Item_row(POS(), a, items);
}
TEST_F(OptRefTest, addKeyFieldsFromInOneRow)
{
/*
We simulate the where condition (a, b) IN ((0, 0)). Note that this
can't happen in practice since the parser is hacked to parse such
an expression in to (a, b) = (0, 0), which gets rewritten into a =
0 AND b = 0 before the ref optimizer runs.
*/
PT_item_list *all_args=
new (current_thd->mem_root) PT_item_list;
all_args->push_front(make_item_row(item_zero, item_zero));
all_args->push_front(make_item_row(item_field_t1_a, item_field_t1_b));
Item *cond= new Item_func_in(POS(), all_args, false);
Parse_context pc(thd(), thd()->lex->current_select());
EXPECT_FALSE(cond->itemize(&pc, &cond));
call_add_key_fields(cond);
// We expect the key_fields pointer not to be incremented.
EXPECT_EQ(0, t1_key_fields - static_cast<Key_field*>(&t1_key_field_arr[0]));
EXPECT_EQ(indexes, t1_join_tab.const_keys)
<< "SARGable index not present in const_keys";
EXPECT_EQ(indexes, t1_join_tab.keys());
EXPECT_EQ(0U, t1_key_field_arr[0].level);
EXPECT_EQ(0U, t1_key_field_arr[1].level);
}
TEST_F(OptRefTest, addKeyFieldsFromInTwoRows)
{
// We simulate the where condition (col_a, col_b) IN ((0, 0), (1, 1))
PT_item_list *all_args=
new (current_thd->mem_root) PT_item_list;
all_args->push_front(make_item_row(item_one, item_one));
all_args->push_front(make_item_row(item_zero, item_zero));
all_args->push_front(make_item_row(item_field_t1_a, item_field_t1_b));
Item *cond= new Item_func_in(POS(), all_args, false);
Parse_context pc(thd(), thd()->lex->current_select());
EXPECT_FALSE(cond->itemize(&pc, &cond));
call_add_key_fields(cond);
// We expect the key_fields pointer not to be incremented.
EXPECT_EQ(0, t1_key_fields - static_cast<Key_field*>(&t1_key_field_arr[0]));
EXPECT_EQ(indexes, t1_join_tab.const_keys)
<< "SARGable index not present in const_keys";
EXPECT_EQ(indexes, t1_join_tab.keys());
}
TEST_F(OptRefTest, addKeyFieldsFromInOneRowWithCols)
{
// We simulate the where condition (t1.a, t1.b) IN ((t2.a, t2.b))
PT_item_list *all_args=
new (current_thd->mem_root) PT_item_list;
all_args->push_front(make_item_row(item_field_t2_a, item_field_t2_b));
all_args->push_front(make_item_row(item_field_t1_a, item_field_t1_b));
Item *cond= new Item_func_in(POS(), all_args, false);
Parse_context pc(thd(), thd()->lex->current_select());
EXPECT_FALSE(cond->itemize(&pc, &cond));
call_add_key_fields(cond);
// We expect the key_fields pointer not to be incremented.
EXPECT_EQ(0, t1_key_fields - static_cast<Key_field*>(&t1_key_field_arr[0]));
EXPECT_EQ(key_map(0), t1_join_tab.const_keys);
EXPECT_EQ(indexes, t1_join_tab.keys());
EXPECT_EQ(t2.pos_in_table_list->map(), t1_join_tab.key_dependent);
}
TEST_F(OptRefTest, addKeyFieldsFromEq)
{
// We simulate the where condition a = 0 AND b = 0
Item_func_eq *eq1= new Item_func_eq(item_field_t1_a, item_zero);
Item_func_eq *eq2= new Item_func_eq(item_field_t1_b, item_zero);
Item_cond_and *cond= new Item_cond_and(eq1, eq2);
call_add_key_fields(cond);
/*
We expect 2 Key_field's to be written. Actually they're always
written, but we expect the pointer to be incremented.
*/
EXPECT_EQ(2, t1_key_fields - static_cast<Key_field*>(&t1_key_field_arr[0]));
EXPECT_EQ(indexes, t1_join_tab.const_keys)
<< "SARGable index not present in const_keys";
EXPECT_EQ(indexes, t1_join_tab.keys());
EXPECT_EQ(0U, t1_join_tab.key_dependent);
EXPECT_EQ(0U, t1_key_field_arr[0].level);
EXPECT_EQ(0U, t1_key_field_arr[1].level);
}
}