List:Commits« Previous MessageNext Message »
From:Jorgen Loland Date:November 30 2012 6:44am
Subject:bzr push into mysql-trunk branch (jorgen.loland:5127 to 5128) WL#5894
View as plain text  
 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#5894Jorgen Loland30 Nov