5128 Jorgen Loland 2012-11-29
WL#5894: Unit-test SEL_ARG
Batch #1, which contains:
* Introduction of utility functions to be used when adding unit
tests for SEL_ARG.
* First batch of unit tests
* Some cleanup of gunit mock classes as proposed by Didrik.
modified:
sql/opt_range.cc
unittest/gunit/fake_table.h
unittest/gunit/field-t.cc
unittest/gunit/field_date-t.cc
unittest/gunit/field_datetime-t.cc
unittest/gunit/field_long-t.cc
unittest/gunit/field_newdecimal-t.cc
unittest/gunit/item-t.cc
unittest/gunit/mock_field_timestamp.h
unittest/gunit/opt_range-t.cc
unittest/gunit/test_utils.h
5127 Venkatesh Duggirala 2012-11-30 [merge]
BUG#15888454: SLAVE CRASHES WHEN DML REQUIRES CONVERSION & TABLE HAS
LESS COLUMNS THAN MASTER
Null merge from mysql-5.6
=== modified file 'sql/opt_range.cc'
--- a/sql/opt_range.cc 2012-11-23 11:17:38 +0000
+++ b/sql/opt_range.cc 2012-11-29 15:23:48 +0000
@@ -904,6 +904,11 @@ static inline void dbug_print_tree(const
SEL_TREE *tree,
const RANGE_OPT_PARAM *param);
+static inline void print_tree(String *out,
+ const char *tree_name,
+ SEL_TREE *tree,
+ const RANGE_OPT_PARAM *param);
+
void append_range(String *out,
const KEY_PART_INFO *key_parts,
const uchar *min_key, const uchar *max_key,
@@ -13621,8 +13626,6 @@ static void trace_range_all_keyparts(Opt
#endif //OPTIMIZER_TRACE
-#ifndef DBUG_OFF
-
/**
Traverse an R-B tree of range conditions and append all ranges for
this keypart and consecutive keyparts to a String. See description
@@ -13701,8 +13704,6 @@ static void print_range_all_keyparts(Str
}
}
-#endif // DBUG_OFF
-
/**
Print the ranges in a SEL_TREE to debug log.
@@ -13715,53 +13716,107 @@ static inline void dbug_print_tree(const
const RANGE_OPT_PARAM *param)
{
#ifndef DBUG_OFF
+ print_tree(NULL, tree_name, tree, param);
+#endif
+}
+
+static inline void print_tree(String *out,
+ const char *tree_name,
+ SEL_TREE *tree,
+ const RANGE_OPT_PARAM *param)
+{
if (!param->using_real_indexes)
{
- DBUG_PRINT("info",
- ("sel_tree: "
- "%s uses a partitioned index and cannot be printed",
- tree_name));
+ if (out)
+ {
+ out->append(tree_name);
+ out->append(" uses a partitioned index and cannot be printed");
+ }
+ else
+ DBUG_PRINT("info",
+ ("sel_tree: "
+ "%s uses a partitioned index and cannot be printed",
+ tree_name));
return;
}
if (!tree)
{
- DBUG_PRINT("info", ("sel_tree: %s is NULL", tree_name));
+ if (out)
+ {
+ out->append(tree_name);
+ out->append(" is NULL");
+ }
+ else
+ DBUG_PRINT("info", ("sel_tree: %s is NULL", tree_name));
return;
}
if (tree->type == SEL_TREE::IMPOSSIBLE)
{
- DBUG_PRINT("info", ("sel_tree: %s is IMPOSSIBLE", tree_name));
+ if (out)
+ {
+ out->append(tree_name);
+ out->append(" is IMPOSSIBLE");
+ }
+ else
+ DBUG_PRINT("info", ("sel_tree: %s is IMPOSSIBLE", tree_name));
return;
}
if (tree->type == SEL_TREE::ALWAYS)
{
- DBUG_PRINT("info", ("sel_tree: %s is ALWAYS", tree_name));
+ if (out)
+ {
+ out->append(tree_name);
+ out->append(" is ALWAYS");
+ }
+ else
+ DBUG_PRINT("info", ("sel_tree: %s is ALWAYS", tree_name));
return;
}
if (tree->type == SEL_TREE::MAYBE)
{
- DBUG_PRINT("info", ("sel_tree: %s is MAYBE", tree_name));
+ if (out)
+ {
+ out->append(tree_name);
+ out->append(" is MAYBE");
+ }
+ else
+ DBUG_PRINT("info", ("sel_tree: %s is MAYBE", tree_name));
return;
}
if (!tree->merges.is_empty())
{
- DBUG_PRINT("info",
- ("sel_tree: "
- "%s contains the following merges", tree_name));
+ if (out)
+ {
+ out->append(tree_name);
+ out->append(" contains the following merges\n");
+ }
+ else
+ DBUG_PRINT("info",
+ ("sel_tree: "
+ "%s contains the following merges", tree_name));
List_iterator<SEL_IMERGE> it(tree->merges);
- int i= 0;
+ int i= 1;
for (SEL_IMERGE *el= it++; el; el= it++, i++)
{
+ if (out)
+ {
+ out->append(tree_name);
+ out->append(" --- alternative ");
+ out->append(i);
+ out->append(" ---\n");
+ }
+ else
+ DBUG_PRINT("info", ("sel_tree: --- alternative %d ---",i));
for (SEL_TREE** current= el->trees;
current != el->trees_next;
current++)
- dbug_print_tree(" merge_tree", *current, param);
+ print_tree(out, " merge_tree", *current, param);
}
}
@@ -13794,11 +13849,24 @@ static inline void dbug_print_tree(const
print_range_all_keyparts(&range_result, &range_so_far,
tree->keys[i], key_part);
- DBUG_PRINT("info",
- ("sel_tree: %s->keys[%d(real_keynr: %d)]: %s",
- tree_name, i, real_key_nr, range_result.ptr()));
+ if (out)
+ {
+ char istr[22];
+ if (i>0)
+ out->append("\n");
+
+ out->append(tree_name);
+ out->append(" keys[");
+ out->append(llstr(i, istr));
+ out->append("]: ");
+ out->append(range_result.ptr());
+ }
+ else
+ DBUG_PRINT("info",
+ ("sel_tree: %p, type=%d, %s->keys[%u(%u)]: %s",
+ tree->keys[i], tree->keys[i]->type, tree_name, i,
+ real_key_nr, range_result.ptr()));
}
-#endif
}
/*****************************************************************************
=== modified file 'unittest/gunit/fake_table.h'
--- a/unittest/gunit/fake_table.h 2012-09-07 14:07:26 +0000
+++ b/unittest/gunit/fake_table.h 2012-11-29 15:23:48 +0000
@@ -23,6 +23,8 @@
*/
class Fake_TABLE_SHARE : public TABLE_SHARE
{
+ uint32 all_set_buf;
+
public:
Fake_TABLE_SHARE(uint number_of_columns)
{
@@ -34,6 +36,9 @@ public:
db_low_byte_first= true;
path.str= const_cast<char*>(fakepath);
path.length= strlen(path.str);
+
+ EXPECT_EQ(0, bitmap_init(&all_set, &all_set_buf, fields, false));
+ bitmap_set_above(&all_set, 0, 1);
}
~Fake_TABLE_SHARE() {}
};
@@ -44,10 +49,18 @@ public:
*/
class Fake_TABLE: public TABLE
{
+ // make room for 8 indexes (mysql permits 64)
+ static const int max_keys= 8;
+ KEY m_keys[max_keys];
+ // make room for up to 8 keyparts per index
+ KEY_PART_INFO m_key_part_infos[max_keys][8];
+
Fake_TABLE_SHARE table_share;
MY_BITMAP write_set_struct;
uint32 write_set_buf;
- Field *field_array[32];
+ MY_BITMAP read_set_struct;
+ uint32 read_set_buf;
+ Field *m_field_array[32];
void inititalize()
{
@@ -55,11 +68,12 @@ class Fake_TABLE: public TABLE
file= NULL;
in_use= current_thd;
null_row= '\0';
+ read_set= &read_set_struct;
write_set= &write_set_struct;
- read_set= NULL;
next_number_field= NULL; // No autoinc column
EXPECT_EQ(0, bitmap_init(write_set, &write_set_buf, s->fields, false));
+ EXPECT_EQ(0, bitmap_init(read_set, &read_set_buf, s->fields, false));
static const char *table_name= "Fake";
for (uint i= 0; i < s->fields; ++i)
@@ -70,19 +84,36 @@ class Fake_TABLE: public TABLE
}
const_table= true;
maybe_null= 0;
+ this->TABLE::map= 1; /* ID bit of table */
+ this->TABLE::key_info= &m_keys[0];
+ for (int i= 0; i < max_keys; i++)
+ key_info[i].key_part= m_key_part_infos[i];
}
public:
+ Fake_TABLE(List<Field> fields)
+ : table_share(fields.elements)
+ {
+ field= m_field_array;
+
+ List_iterator<Field> it(fields);
+ int nbr_fields= 0;
+ for (Field *cur_field= it++; cur_field; cur_field= it++)
+ field[nbr_fields++]= cur_field;
+
+ inititalize();
+ }
+
Fake_TABLE(Field *column1) : table_share(1)
{
- field= field_array;
+ field= m_field_array;
field[0]= column1;
inititalize();
}
Fake_TABLE(Field *column1, Field *column2) : table_share(2)
{
- field= field_array;
+ field= m_field_array;
field[0]= column1;
field[1]= column2;
inititalize();
=== modified file 'unittest/gunit/field-t.cc'
--- a/unittest/gunit/field-t.cc 2012-10-30 14:40:02 +0000
+++ b/unittest/gunit/field-t.cc 2012-11-29 15:23:48 +0000
@@ -390,6 +390,7 @@ TEST_F(FieldTest, CopyFieldSet)
Field_set *f_from= create_field_set(&tl4);
bitmap_set_all(f_from->table->write_set);
+ bitmap_set_all(f_from->table->read_set);
uchar from_fieldval= static_cast<uchar>(typeset);
f_from->ptr= &from_fieldval;
=== modified file 'unittest/gunit/field_date-t.cc'
--- a/unittest/gunit/field_date-t.cc 2012-05-07 12:05:48 +0000
+++ b/unittest/gunit/field_date-t.cc 2012-11-29 15:23:48 +0000
@@ -90,6 +90,7 @@ public:
}
void make_writable() { bitmap_set_bit(table->write_set, field_index); }
+ void make_readable() { bitmap_set_bit(table->read_set, field_index); }
};
@@ -99,6 +100,7 @@ TEST_F(FieldDateTest, StoreLegalStringVa
Fake_TABLE table(&field_date);
table.in_use= thd();
field_date.make_writable();
+ field_date.make_readable();
{
SCOPED_TRACE("");
@@ -123,6 +125,7 @@ TEST_F(FieldDateTest, StoreIllegalString
Fake_TABLE table(&field_date);
table.in_use= thd();
field_date.make_writable();
+ field_date.make_readable();
thd()->count_cuted_fields= CHECK_FIELD_WARN;
// Truncates time
@@ -178,6 +181,7 @@ TEST_F(FieldDateTest, StoreZeroDateSqlMo
Fake_TABLE table(&field_date);
table.in_use= thd();
field_date.make_writable();
+ field_date.make_readable();
thd()->count_cuted_fields= CHECK_FIELD_WARN;
for (int i= 0; i < no_modes; i++)
@@ -225,6 +229,7 @@ TEST_F(FieldDateTest, StoreZeroDateSqlMo
Fake_TABLE table(&field_date);
table.in_use= thd();
field_date.make_writable();
+ field_date.make_readable();
thd()->count_cuted_fields= CHECK_FIELD_WARN;
// With "MODE_NO_ZERO_DATE" set - Errors if date is all null
@@ -286,6 +291,7 @@ TEST_F(FieldDateTest, StoreZeroDateSqlMo
Fake_TABLE table(&field_date);
table.in_use= thd();
field_date.make_writable();
+ field_date.make_readable();
thd()->count_cuted_fields= CHECK_FIELD_WARN;
// With "MODE_NO_ZERO_IN_DATE" set - Entire date zero is ok
=== modified file 'unittest/gunit/field_datetime-t.cc'
--- a/unittest/gunit/field_datetime-t.cc 2012-05-07 12:05:48 +0000
+++ b/unittest/gunit/field_datetime-t.cc 2012-11-29 15:23:48 +0000
@@ -69,6 +69,7 @@ public:
}
void make_writable() { bitmap_set_bit(table->write_set, field_index); }
+ void make_readable() { bitmap_set_bit(table->read_set, field_index); }
};
@@ -82,6 +83,7 @@ TEST_F(FieldDatetimeTest, StoreLegalStri
Fake_TABLE table(&field_dt);
table.in_use= thd();
field_dt.make_writable();
+ field_dt.make_readable();
thd()->count_cuted_fields= CHECK_FIELD_WARN;
{
@@ -108,6 +110,7 @@ TEST_F(FieldDatetimeTest, StoreIllegalSt
Fake_TABLE table(&field_dt);
table.in_use= thd();
field_dt.make_writable();
+ field_dt.make_readable();
thd()->count_cuted_fields= CHECK_FIELD_WARN;
// Bad year
@@ -191,6 +194,7 @@ TEST_F(FieldDatetimeTest, StoreZeroDateS
Fake_TABLE table(&field_dt);
table.in_use= thd();
field_dt.make_writable();
+ field_dt.make_readable();
thd()->count_cuted_fields= CHECK_FIELD_WARN;
for (int i= 0; i < no_modes; i++)
@@ -252,6 +256,7 @@ TEST_F(FieldDatetimeTest, StoreZeroDateS
Fake_TABLE table(&field_dt);
table.in_use= thd();
field_dt.make_writable();
+ field_dt.make_readable();
thd()->count_cuted_fields= CHECK_FIELD_WARN;
// With "MODE_NO_ZERO_DATE" set - Errors if date is all null
@@ -313,6 +318,7 @@ TEST_F(FieldDatetimeTest, StoreZeroDateS
Fake_TABLE table(&field_dt);
table.in_use= thd();
field_dt.make_writable();
+ field_dt.make_readable();
thd()->count_cuted_fields= CHECK_FIELD_WARN;
// With "MODE_NO_ZERO_IN_DATE" set - Entire date zero is ok
=== modified file 'unittest/gunit/field_long-t.cc'
--- a/unittest/gunit/field_long-t.cc 2012-06-24 07:07:58 +0000
+++ b/unittest/gunit/field_long-t.cc 2012-11-29 15:23:48 +0000
@@ -66,6 +66,7 @@ public:
}
void make_writable() { bitmap_set_bit(table->write_set, field_index); }
+ void make_readable() { bitmap_set_bit(table->read_set, field_index); }
};
@@ -105,6 +106,7 @@ TEST_F(FieldLongTest, StoreLegalIntValue
Fake_TABLE table(&field_long);
table.in_use= thd();
field_long.make_writable();
+ field_long.make_readable();
thd()->count_cuted_fields= CHECK_FIELD_WARN;
SCOPED_TRACE(""); test_store_long(&field_long, 0, 0, 0, TYPE_OK);
@@ -145,6 +147,7 @@ TEST_F(FieldLongTest, StoreOutOfRangeInt
Fake_TABLE table(&field_long);
table.in_use= thd();
field_long.make_writable();
+ field_long.make_readable();
thd()->count_cuted_fields= CHECK_FIELD_WARN;
@@ -188,6 +191,7 @@ TEST_F(FieldLongTest, StoreLegalStringVa
Fake_TABLE table(&field_long);
table.in_use= thd();
field_long.make_writable();
+ field_long.make_readable();
thd()->count_cuted_fields= CHECK_FIELD_WARN;
const char min_int[]= "-2147483648";
@@ -242,6 +246,7 @@ TEST_F(FieldLongTest, StoreIllegalString
Fake_TABLE table(&field_long);
table.in_use= thd();
field_long.make_writable();
+ field_long.make_readable();
thd()->count_cuted_fields= CHECK_FIELD_WARN;
const char max_int_plus1[]= "2147483648";
@@ -330,6 +335,7 @@ TEST_F(FieldLongTest, StoreNullValue)
Fake_TABLE table(&field_long);
table.in_use= thd();
field_long.make_writable();
+ field_long.make_readable();
thd()->count_cuted_fields= CHECK_FIELD_WARN;
type_conversion_status err;
=== modified file 'unittest/gunit/field_newdecimal-t.cc'
--- a/unittest/gunit/field_newdecimal-t.cc 2012-05-07 12:05:48 +0000
+++ b/unittest/gunit/field_newdecimal-t.cc 2012-11-29 15:23:48 +0000
@@ -72,6 +72,7 @@ public:
}
void make_writable() { bitmap_set_bit(table->write_set, field_index); }
+ void make_readable() { bitmap_set_bit(table->read_set, field_index); }
void test_store_string(const char *store_value, const int length,
const char *expected_string_result,
@@ -87,6 +88,7 @@ public:
Mock_error_handler error_handler(table->in_use, expected_error_no);
type_conversion_status err= store(store_value, length, &my_charset_latin1);
val_str(&str, &unused);
+
EXPECT_STREQ(expected_string_result, str.ptr());
EXPECT_EQ(expected_int_result, val_int());
EXPECT_EQ(expected_real_result, val_real());
@@ -106,6 +108,7 @@ TEST_F(FieldNewDecimalTest, StoreLegalSt
Fake_TABLE table(&field_dec);
table.in_use= thd();
field_dec.make_writable();
+ field_dec.make_readable();
thd()->count_cuted_fields= CHECK_FIELD_WARN;
{
@@ -128,6 +131,7 @@ TEST_F(FieldNewDecimalTest, StoreIllegal
Fake_TABLE table(&field_dec);
table.in_use= thd();
field_dec.make_writable();
+ field_dec.make_readable();
thd()->count_cuted_fields= CHECK_FIELD_WARN;
// Truncated (precision beyond 3 decimals is lost)
@@ -206,6 +210,7 @@ TEST_F(FieldNewDecimalTest, storeInterna
Fake_TABLE table(&field_dec);
table.in_use= thd();
field_dec.make_writable();
+ field_dec.make_readable();
thd()->count_cuted_fields= CHECK_FIELD_WARN;
my_decimal d10_01;
@@ -261,6 +266,7 @@ TEST_F(FieldNewDecimalTest, storeInterna
Fake_TABLE table(&field_dec);
table.in_use= thd();
field_dec.make_writable();
+ field_dec.make_readable();
thd()->count_cuted_fields= CHECK_FIELD_WARN;
my_decimal dTooHigh;
@@ -300,6 +306,7 @@ TEST_F(FieldNewDecimalTest, storeInterna
Fake_TABLE table(&field_dec);
table.in_use= thd();
field_dec.make_writable();
+ field_dec.make_readable();
thd()->count_cuted_fields= CHECK_FIELD_WARN;
my_decimal d10_01;
@@ -370,6 +377,7 @@ TEST_F(FieldNewDecimalTest, storeInterna
Fake_TABLE table(&field_dec);
table.in_use= thd();
field_dec.make_writable();
+ field_dec.make_readable();
thd()->count_cuted_fields= CHECK_FIELD_WARN;
my_decimal d10_01;
@@ -438,6 +446,7 @@ TEST_F(FieldNewDecimalTest, storeInterna
Fake_TABLE table(&field_dec);
table.in_use= thd();
field_dec.make_writable();
+ field_dec.make_readable();
thd()->count_cuted_fields= CHECK_FIELD_WARN;
my_decimal d10_01;
=== modified file 'unittest/gunit/item-t.cc'
--- a/unittest/gunit/item-t.cc 2012-11-23 09:02:13 +0000
+++ b/unittest/gunit/item-t.cc 2012-11-29 15:23:48 +0000
@@ -134,6 +134,7 @@ TEST_F(ItemTest, ItemEqual)
{
// Bug#13720201 VALGRIND: VARIOUS BLOCKS OF BYTES DEFINITELY LOST
Mock_field_timestamp mft;
+ mft.make_readable();
// foo is longer than STRING_BUFFER_USUAL_SIZE used by cmp_item_sort_string.
const char foo[]=
"0123456789012345678901234567890123456789"
@@ -142,6 +143,7 @@ TEST_F(ItemTest, ItemEqual)
Item_equal *item_equal=
new Item_equal(new Item_string(STRING_WITH_LEN(foo), &my_charset_bin),
new Item_field(&mft));
+
EXPECT_FALSE(item_equal->fix_fields(thd(), NULL));
EXPECT_EQ(0, item_equal->val_int());
}
=== modified file 'unittest/gunit/mock_field_timestamp.h'
--- a/unittest/gunit/mock_field_timestamp.h 2012-01-31 15:16:16 +0000
+++ b/unittest/gunit/mock_field_timestamp.h 2012-11-29 15:23:48 +0000
@@ -73,6 +73,7 @@ public:
/* Averts ASSERT_COLUMN_MARKED_FOR_WRITE assertion. */
void make_writable() { bitmap_set_bit(table->write_set, field_index); }
+ void make_readable() { bitmap_set_bit(table->read_set, field_index); }
void store_timestamp(const timeval *tm)
{
=== modified file 'unittest/gunit/opt_range-t.cc'
--- a/unittest/gunit/opt_range-t.cc 2012-05-07 12:05:48 +0000
+++ b/unittest/gunit/opt_range-t.cc 2012-11-29 15:23:48 +0000
@@ -17,6 +17,10 @@
#include "my_config.h"
#include <gtest/gtest.h>
+#include <vector>
+
+#include "handler-t.h"
+#include "fake_table.h"
#include "test_utils.h"
#include "opt_range.cc"
@@ -24,35 +28,191 @@
namespace {
using my_testing::Server_initializer;
+using my_testing::delete_container_pointers;
+using ::testing::Return;
+using ::testing::NiceMock;
+using ::testing::_;
+
+class Fake_RANGE_OPT_PARAM : public RANGE_OPT_PARAM
+{
+ KEY_PART m_key_parts[64];
+ Mem_root_array<KEY_PART_INFO, true> m_kpis;
+
+public:
+
+ Fake_RANGE_OPT_PARAM(THD *thd_arg, MEM_ROOT *alloc_arg, TABLE *table_arg)
+ : m_kpis(alloc_arg)
+ {
+ m_kpis.reserve(64);
+
+ thd= thd_arg;
+ mem_root= alloc_arg;
+ current_table= 1<<0;
+ table= table_arg;
+
+ alloced_sel_args= 0;
+ using_real_indexes= true;
+ key_parts= m_key_parts;
+ key_parts_end= m_key_parts;
+ keys= 0;
+ }
+
+ void add_key(List<Field> fields_in_index)
+ {
+ List_iterator<Field> it(fields_in_index);
+ int cur_kp= 0;
+
+ table->key_info[keys].actual_key_parts= 0;
+ for (Field *cur_field= it++; cur_field; cur_field= it++, cur_kp++)
+ {
+ KEY_PART_INFO *kpi= m_kpis.end(); // Points past the end.
+ m_kpis.push_back(KEY_PART_INFO()); // kpi now points to a new element
+ kpi->init_from_field(cur_field);
+
+ key_parts_end->key= keys;
+ key_parts_end->part= cur_kp;
+ key_parts_end->length= kpi->store_length;
+ key_parts_end->store_length= kpi->store_length;
+ key_parts_end->field= kpi->field;
+ key_parts_end->null_bit= kpi->null_bit;
+ key_parts_end->image_type = Field::itRAW;
+
+ key_parts_end++;
+ table->key_info[keys].key_part[cur_kp]= *kpi;
+ table->key_info[keys].actual_key_parts++;
+ }
+ table->key_info[keys].user_defined_key_parts=
+ table->key_info[keys].actual_key_parts;
+ real_keynr[keys]= keys;
+ keys++;
+ }
+
+ ~Fake_RANGE_OPT_PARAM()
+ {
+ for (uint i= 0; i < keys; i++)
+ {
+ table->key_info[i].actual_key_parts= 0;
+ table->key_info[i].user_defined_key_parts= 0;
+ }
+ }
+
+};
+
+class Mock_field_long : public Field_long
+{
+private:
+ Fake_TABLE *m_fake_tbl;
+
+public:
+ Mock_field_long(THD *thd, Item *item, const char *name, bool create_table)
+ : Field_long(0, // ptr_arg
+ 8, // len_arg
+ NULL, // null_ptr_arg
+ 0, // null_bit_arg
+ Field::NONE, // unireg_check_arg
+ name ? name : "field_name", // field_name_arg
+ false, // zero_arg
+ false) // unsigned_arg
+ {
+ if (create_table)
+ m_fake_tbl= new Fake_TABLE(this);
+ else
+ m_fake_tbl= NULL;
+
+ this->ptr= (uchar*) alloc_root((thd->mem_root), KEY_LENGTH);
+ if (item)
+ item->save_in_field_no_warnings(this, true);
+ }
+
+ ~Mock_field_long()
+ {
+ delete m_fake_tbl;
+ m_fake_tbl= NULL;
+ }
+
+ // #bytes to store the value - see Field_long::key_lenght()
+ static const int KEY_LENGTH= 4;
+};
+
class SelArgTest : public ::testing::Test
{
protected:
- SelArgTest()
+ SelArgTest() : m_ftable(NULL), m_opt_param(NULL), m_mock_handler(NULL)
{
- memset(&m_opt_param, 0, sizeof(m_opt_param));
}
virtual void SetUp()
{
initializer.SetUp();
- m_opt_param.thd= thd();
- m_opt_param.mem_root= &m_alloc;
- m_opt_param.current_table= 1<<0;
init_sql_alloc(&m_alloc, thd()->variables.range_alloc_block_size, 0);
}
virtual void TearDown()
{
+ delete_container_pointers(m_table_fields);
+ delete m_mock_handler;
+ delete m_opt_param;
+ delete m_ftable;
+
initializer.TearDown();
free_root(&m_alloc, MYF(0));
}
THD *thd() { return initializer.thd(); }
+ void create_table(List<char*> field_names_arg)
+ {
+ List_iterator<char*> fld_name_it(field_names_arg);
+ for (char **cur_name= fld_name_it++; *cur_name; cur_name= fld_name_it++)
+ m_field_list.push_back(new Mock_field_long(thd(), NULL,
+ *cur_name, false));
+
+ create_table_common();
+ }
+
+ void create_table(const char *field_name)
+ {
+ m_field_list.push_back(new Mock_field_long(thd(), NULL,
+ field_name, false));
+ create_table_common();
+ }
+
+ void create_table(const char *field_name1, const char *field_name2)
+ {
+ m_field_list.push_back(new Mock_field_long(thd(), NULL,
+ field_name1, false));
+ m_field_list.push_back(new Mock_field_long(thd(), NULL,
+ field_name2, false));
+ create_table_common();
+ }
+
Server_initializer initializer;
MEM_ROOT m_alloc;
- RANGE_OPT_PARAM m_opt_param;
+
+ List<Field> m_field_list;
+ Fake_TABLE *m_ftable;
+ Fake_RANGE_OPT_PARAM *m_opt_param;
+ Mock_HANDLER *m_mock_handler;
+ std::vector<Mock_field_long*> m_table_fields;
+
+private:
+ void create_table_common()
+ {
+ m_ftable= new Fake_TABLE(m_field_list);
+ m_opt_param= new Fake_RANGE_OPT_PARAM(thd(), &m_alloc, m_ftable);
+ handlerton *hton= NULL;
+ m_mock_handler=
+ new NiceMock<Mock_HANDLER>(hton, m_ftable->get_share());
+ m_ftable->set_handler(m_mock_handler);
+
+ List_iterator<Field> it(m_field_list);
+ for (Field *cur_field= it++; cur_field; cur_field= it++)
+ m_table_fields.push_back(static_cast<Mock_field_long*>(cur_field));
+
+ ON_CALL(*m_mock_handler, index_flags(_, _, true))
+ .WillByDefault(Return(HA_READ_RANGE));
+ }
};
/*
@@ -91,64 +251,6 @@ const SEL_TREE *null_tree= NULL;
const SEL_ARG *null_arg= NULL;
-class Mock_field_long : public Field_long
-{
-public:
- Mock_field_long(THD *thd, Item *item)
- : Field_long(0, // ptr_arg
- 8, // len_arg
- NULL, // null_ptr_arg
- 0, // null_bit_arg
- Field::NONE, // unireg_check_arg
- "field_name", // field_name_arg
- false, // zero_arg
- false) // unsigned_arg
- {
- m_table_name= "mock_table";
- memset(&m_share, 0, sizeof(m_share));
- const char *foo= "mock_db";
- m_share.db.str= const_cast<char*>(foo);
- m_share.db.length= strlen(m_share.db.str);
-
- bitmap_init(&share_allset, 0, sizeof(my_bitmap_map), 0);
- bitmap_set_above(&share_allset, 0, 1); //all bits 1
- m_share.all_set= share_allset;
-
- memset(&m_table, 0, sizeof(m_table));
- m_table.s= &m_share;
-
- bitmap_init(&tbl_readset, 0, sizeof(my_bitmap_map), 0);
- m_table.read_set= &tbl_readset;
-
- bitmap_init(&tbl_writeset, 0, sizeof(my_bitmap_map), 0);
- m_table.write_set= &tbl_writeset;
-
- m_table.map= 1<<0;
- m_table.in_use= thd;
- this->table_name= &m_table_name;
- this->table= &m_table;
- this->ptr= (uchar*) alloc_root((thd->mem_root), KEY_LENGTH);
- if (item)
- item->save_in_field_no_warnings(this, true);
- }
- ~Mock_field_long()
- {
- bitmap_free(&share_allset);
- bitmap_free(&tbl_readset);
- bitmap_free(&tbl_writeset);
- }
-
- // #bytes to store the value - see Field_long::key_lenght()
- static const int KEY_LENGTH= 4;
- const char *m_table_name;
- TABLE_SHARE m_share;
- TABLE m_table;
- MY_BITMAP share_allset;
- MY_BITMAP tbl_readset;
- MY_BITMAP tbl_writeset;
-};
-
-
static void print_selarg_ranges(String *s, SEL_ARG *sel_arg,
const KEY_PART_INFO *kpi)
{
@@ -170,30 +272,216 @@ static void print_selarg_ranges(String *
TEST_F(SelArgTest, SimpleCond)
{
- EXPECT_NE(null_tree, get_mm_tree(&m_opt_param, new Item_int(42)));
+ Fake_RANGE_OPT_PARAM opt_param(thd(), &m_alloc, NULL);
+ EXPECT_NE(null_tree, get_mm_tree(&opt_param, new Item_int(42)));
}
/*
- TODO: Here we try to build a range, but a lot of mocking remains
- before it works as intended. Currently get_mm_tree() returns NULL
- because m_opt_param.key_parts and m_opt_param.key_parts_end have not
- been setup.
+ Exercise range optimizer without adding indexes
*/
-TEST_F(SelArgTest, EqualCond)
+TEST_F(SelArgTest, EqualCondNoIndexes)
{
- Mock_field_long field_long(thd(), NULL);
- m_opt_param.table= &field_long.m_table;
- SEL_TREE *tree= get_mm_tree(&m_opt_param,
+ Mock_field_long field_long(thd(), NULL, NULL, true);
+ Fake_RANGE_OPT_PARAM opt_param(thd(), &m_alloc, field_long.table);
+ SEL_TREE *tree= get_mm_tree(&opt_param,
new Item_equal(new Item_int(42),
new Item_field(&field_long)));
EXPECT_EQ(null_tree, tree);
}
+/*
+ Exercise range optimizer with single column index
+*/
+TEST_F(SelArgTest, GetMMTreeSingleColIndex)
+{
+ create_table(NULL);
+
+ Mock_field_long *field_long= m_table_fields[0];
+
+ List<Field> index_list;
+ index_list.push_back(field_long);
+ m_opt_param->add_key(index_list);
+
+ char buff[512];
+ String range_string(buff, sizeof(buff), system_charset_info);
+ range_string.set_charset(system_charset_info);
+
+ // Expected result of next test:
+ const char expected[]= "result keys[0]: (42 <= field_name <= 42)";
+ SEL_TREE *tree= get_mm_tree(m_opt_param,
+ new Item_equal(new Item_int(42),
+ new Item_field(field_long)));
+ range_string.length(0);
+ print_tree(&range_string, "result", tree, m_opt_param);
+ EXPECT_STREQ(expected, range_string.c_ptr());
+
+
+ // Expected result of next test:
+ const char expected2[]=
+ "result keys[0]: (42 <= field_name <= 42) OR (43 <= field_name <= 43)";
+ tree= get_mm_tree(m_opt_param,
+ new Item_cond_or(new Item_equal(new Item_int(42),
+ new Item_field(field_long)),
+ new Item_equal(new Item_int(43),
+ new Item_field(field_long)))
+ );
+ range_string.length(0);
+ print_tree(&range_string, "result", tree, m_opt_param);
+ EXPECT_STREQ(expected2, range_string.c_ptr());
+
+
+ // Expected result of next test:
+ const char expected3[]=
+ "result keys[0]: "
+ "(1 <= field_name <= 1) OR (2 <= field_name <= 2) OR "
+ "(3 <= field_name <= 3) OR (4 <= field_name <= 4) OR "
+ "(5 <= field_name <= 5) OR (6 <= field_name <= 6) OR "
+ "(7 <= field_name <= 7) OR (8 <= field_name <= 8)";
+ List<Item> or_list1;
+ or_list1.push_back(new Item_equal(new Item_int(1),
+ new Item_field(field_long)));
+ or_list1.push_back(new Item_equal(new Item_int(2),
+ new Item_field(field_long)));
+ or_list1.push_back(new Item_equal(new Item_int(3),
+ new Item_field(field_long)));
+ or_list1.push_back(new Item_equal(new Item_int(4),
+ new Item_field(field_long)));
+ or_list1.push_back(new Item_equal(new Item_int(5),
+ new Item_field(field_long)));
+ or_list1.push_back(new Item_equal(new Item_int(6),
+ new Item_field(field_long)));
+ or_list1.push_back(new Item_equal(new Item_int(7),
+ new Item_field(field_long)));
+ or_list1.push_back(new Item_equal(new Item_int(8),
+ new Item_field(field_long)));
+ tree= get_mm_tree(m_opt_param, new Item_cond_or(or_list1));
+ range_string.length(0);
+ print_tree(&range_string, "result", tree, m_opt_param);
+ EXPECT_STREQ(expected3, range_string.c_ptr());
+
+
+ // Expected result of next test:
+ const char expected4[]= "result keys[0]: (7 <= field_name <= 7)";
+ Item_equal *eq7= new Item_equal(new Item_int(7),
+ new Item_field(field_long));
+ tree= get_mm_tree(m_opt_param,
+ new Item_cond_and(new Item_cond_or(or_list1), eq7));
+ range_string.length(0);
+ print_tree(&range_string, "result", tree, m_opt_param);
+ EXPECT_STREQ(expected4, range_string.c_ptr());
+
+
+ // Expected result of next test:
+ const char expected5[]=
+ "result keys[0]: "
+ "(1 <= field_name <= 1) OR (3 <= field_name <= 3) OR "
+ "(5 <= field_name <= 5) OR (7 <= field_name <= 7)";
+ List<Item> or_list2;
+ or_list2.push_back(new Item_equal(new Item_int(1),
+ new Item_field(field_long)));
+ or_list2.push_back(new Item_equal(new Item_int(3),
+ new Item_field(field_long)));
+ or_list2.push_back(new Item_equal(new Item_int(5),
+ new Item_field(field_long)));
+ or_list2.push_back(new Item_equal(new Item_int(7),
+ new Item_field(field_long)));
+ or_list2.push_back(new Item_equal(new Item_int(9),
+ new Item_field(field_long)));
+ tree= get_mm_tree(m_opt_param,
+ new Item_cond_and(new Item_cond_or(or_list1),
+ new Item_cond_or(or_list2)));
+ range_string.length(0);
+ print_tree(&range_string, "result", tree, m_opt_param);
+ EXPECT_STREQ(expected5, range_string.c_ptr());
+}
+
+
+/*
+ Exercise range optimizer with multiple column index
+*/
+TEST_F(SelArgTest, GetMMTreeMultipleSingleColIndex)
+{
+ create_table(NULL);
+
+ Mock_field_long *field_long= m_table_fields[0];
+
+ List<Field> index_list;
+ index_list.push_back(field_long);
+ m_opt_param->add_key(index_list);
+ m_opt_param->add_key(index_list);
+
+ char buff[512];
+ String range_string(buff, sizeof(buff), system_charset_info);
+ range_string.set_charset(system_charset_info);
+
+ // Expected result of next test:
+ const char expected[]=
+ "result keys[0]: (42 <= field_name <= 42)\n"
+ "result keys[1]: (42 <= field_name <= 42)";
+ SEL_TREE *tree= get_mm_tree(m_opt_param,
+ new Item_equal(new Item_int(42),
+ new Item_field(field_long)));
+ range_string.length(0);
+ print_tree(&range_string, "result", tree, m_opt_param);
+ EXPECT_STREQ(expected, range_string.c_ptr());
+}
+
+
+/*
+ Exercise range optimizer with multiple single column indexes
+*/
+TEST_F(SelArgTest, GetMMTreeSingleMultiColIndex)
+{
+ create_table("field_1", "field_2");
+
+ Mock_field_long *field_long1= m_table_fields[0];
+ Mock_field_long *field_long2= m_table_fields[1];
+
+ List<Field> index_list;
+ index_list.push_back(field_long1);
+ index_list.push_back(field_long2);
+ m_opt_param->add_key(index_list);
+
+ char buff[512];
+ String range_string(buff, sizeof(buff), system_charset_info);
+ range_string.set_charset(system_charset_info);
+
+ // Expected result of next test:
+ const char expected[]= "result keys[0]: (42 <= field_1 <= 42)";
+ SEL_TREE *tree= get_mm_tree(m_opt_param,
+ new Item_equal(new Item_int(42),
+ new Item_field(field_long1)));
+ range_string.length(0);
+ print_tree(&range_string, "result", tree, m_opt_param);
+ EXPECT_STREQ(expected, range_string.c_ptr());
+
+
+ // Expected result of next test:
+ const char expected3[]= "result keys[0]: "
+ "(42 <= field_1 <= 42 AND 10 <= field_2 <= 10)";
+
+ tree= get_mm_tree(m_opt_param,
+ new
+ Item_cond_and(new Item_equal(new Item_int(42),
+ new Item_field(field_long1)),
+ new Item_equal(new Item_int(10),
+ new Item_field(field_long2)))
+ );
+
+ range_string.length(0);
+ print_tree(&range_string, "result", tree, m_opt_param);
+ EXPECT_STREQ(expected3, range_string.c_ptr());
+}
+
+
+/*
+ Create SelArg with various single valued predicate
+*/
TEST_F(SelArgTest, SelArgOnevalue)
{
- Mock_field_long field_long7(thd(), new Item_int(7));
+ Mock_field_long field_long7(thd(), new Item_int(7), NULL, true);
KEY_PART_INFO kpi;
kpi.init_from_field(&field_long7);
@@ -234,10 +522,13 @@ TEST_F(SelArgTest, SelArgOnevalue)
}
+/*
+ Create SelArg with a between predicate
+*/
TEST_F(SelArgTest, SelArgBetween)
{
- Mock_field_long field_long3(thd(), new Item_int(3));
- Mock_field_long field_long5(thd(), new Item_int(5));
+ Mock_field_long field_long3(thd(), new Item_int(3), NULL, true);
+ Mock_field_long field_long5(thd(), new Item_int(5), NULL, true);
KEY_PART_INFO kpi;
kpi.init_from_field(&field_long3);
@@ -288,10 +579,13 @@ TEST_F(SelArgTest, SelArgBetween)
EXPECT_STREQ(expected6, range_string.c_ptr());
}
+/*
+ Test SelArg::CopyMax
+*/
TEST_F(SelArgTest, CopyMax)
{
- Mock_field_long field_long3(thd(), new Item_int(3));
- Mock_field_long field_long5(thd(), new Item_int(5));
+ Mock_field_long field_long3(thd(), new Item_int(3), NULL, true);
+ Mock_field_long field_long5(thd(), new Item_int(5), NULL, true);
KEY_PART_INFO kpi;
kpi.init_from_field(&field_long3);
@@ -358,10 +652,13 @@ TEST_F(SelArgTest, CopyMax)
EXPECT_STREQ(expected5, range_string.c_ptr());
}
+/*
+ Test SelArg::CopyMin
+*/
TEST_F(SelArgTest, CopyMin)
{
- Mock_field_long field_long3(thd(), new Item_int(3));
- Mock_field_long field_long5(thd(), new Item_int(5));
+ Mock_field_long field_long3(thd(), new Item_int(3), NULL, true);
+ Mock_field_long field_long5(thd(), new Item_int(5), NULL, true);
KEY_PART_INFO kpi;
kpi.init_from_field(&field_long3);
@@ -429,10 +726,13 @@ TEST_F(SelArgTest, CopyMin)
}
+/*
+ Test SelArg::KeyOr
+*/
TEST_F(SelArgTest, KeyOr1)
{
- Mock_field_long field_long3(thd(), new Item_int(3));
- Mock_field_long field_long4(thd(), new Item_int(4));
+ Mock_field_long field_long3(thd(), new Item_int(3), NULL, true);
+ Mock_field_long field_long4(thd(), new Item_int(4), NULL, true);
KEY_PART_INFO kpi;
kpi.init_from_field(&field_long3);
=== modified file 'unittest/gunit/test_utils.h'
--- a/unittest/gunit/test_utils.h 2012-10-25 13:34:04 +0000
+++ b/unittest/gunit/test_utils.h 2012-11-29 15:23:48 +0000
@@ -23,6 +23,18 @@
namespace my_testing {
+template<typename Container_type>
+void delete_container_pointers(Container_type &container)
+{
+ typename Container_type::iterator it1= container.begin();
+ typename Container_type::iterator it2= container.end();
+ for (; it1 != it2; ++it1)
+ {
+ delete (*it1);
+ }
+ container.clear();
+}
+
void setup_server_for_unit_tests();
void teardown_server_for_unit_tests();
No bundle (reason: useless for push emails).
| Thread |
|---|
| • bzr push into mysql-trunk branch (jorgen.loland:5127 to 5128) WL#5894 | Jorgen Loland | 30 Nov |