List:Commits« Previous MessageNext Message »
From:Tor Didriksen Date:May 30 2011 10:44am
Subject:bzr commit into mysql-trunk branch (tor.didriksen:3128) Bug#12590211
View as plain text  
#At file:///export/home/didrik/repo/trunk-bug11765255-arraycheck/ based on revid:alexander.nozdrin@stripped

 3128 Tor Didriksen	2011-05-30
      Bug#12590211 - ADD BOUNDS CHECK ON REF_POINTER_ARRAY AND FRIENDS
      
      Cleanup the Item** and Item*** code for ref_pointer_array.
      Wrap the array(s) in a container, so we can do bounds checks.
     @ sql/sql_array.h
        New, templatized, array class.
     @ sql/sql_lex.cc
        In setup_ref_array(), add sanity check that that the size of ref_pointer_array 
        does not change.
     @ sql/sql_select.cc
        Changed several functions from
        xx_(.. Item ** ..)   to   xx_(.. Ref_ptr_array ..)
     @ sql/sql_select.h
        Document usage of ref_pointer_array.
        Change from Item** to Ref_ptr_array.
        Re-wrote setter functions.
     @ unittest/gunit/bounds_checked_array-t.cc
        New unit test.

    added:
      unittest/gunit/bounds_checked_array-t.cc
    modified:
      sql/item.cc
      sql/item_subselect.cc
      sql/item_sum.cc
      sql/sql_array.h
      sql/sql_base.cc
      sql/sql_base.h
      sql/sql_do.cc
      sql/sql_insert.cc
      sql/sql_lex.cc
      sql/sql_lex.h
      sql/sql_load.cc
      sql/sql_prepare.cc
      sql/sql_select.cc
      sql/sql_select.h
      sql/sql_update.cc
      unittest/gunit/CMakeLists.txt
=== modified file 'sql/item.cc'
--- a/sql/item.cc	2011-05-26 15:20:09 +0000
+++ b/sql/item.cc	2011-05-30 10:44:01 +0000
@@ -4346,7 +4346,7 @@ resolve_ref_in_select_and_group(THD *thd
         return NULL;
       }
       DBUG_ASSERT((*select_ref)->fixed);
-      return (select->ref_pointer_array + counter);
+      return &select->ref_pointer_array[counter];
     }
     if (group_by_ref)
       return group_by_ref;
@@ -6234,13 +6234,13 @@ Item *Item_field::update_value_transform
       type() != Item::TRIGGER_FIELD_ITEM)
   {
     List<Item> *all_fields= &select->join->all_fields;
-    Item **ref_pointer_array= select->ref_pointer_array;
+    Ref_ptr_array &ref_pointer_array= select->ref_pointer_array;
     int el= all_fields->elements;
     Item_ref *ref;
 
     ref_pointer_array[el]= (Item*)this;
     all_fields->push_front((Item*)this);
-    ref= new Item_ref(&select->context, ref_pointer_array + el,
+    ref= new Item_ref(&select->context, &ref_pointer_array[el],
                       table_name, field_name);
     return ref;
   }

=== modified file 'sql/item_subselect.cc'
--- a/sql/item_subselect.cc	2011-05-24 09:36:11 +0000
+++ b/sql/item_subselect.cc	2011-05-30 10:44:01 +0000
@@ -1126,7 +1126,7 @@ Item_in_subselect::single_value_transfor
 	  (ALL && (> || =>)) || (ANY && (< || =<))
 	  for ALL condition is inverted
 	*/
-	item= new Item_sum_max(*select_lex->ref_pointer_array);
+	item= new Item_sum_max(select_lex->ref_pointer_array[0]);
       }
       else
       {
@@ -1134,11 +1134,11 @@ Item_in_subselect::single_value_transfor
 	  (ALL && (< || =<)) || (ANY && (> || =>))
 	  for ALL condition is inverted
 	*/
-	item= new Item_sum_min(*select_lex->ref_pointer_array);
+	item= new Item_sum_min(select_lex->ref_pointer_array[0]);
       }
       if (upper_item)
         upper_item->set_sum_test(item);
-      *select_lex->ref_pointer_array= item;
+      select_lex->ref_pointer_array[0]= item;
       {
 	List_iterator<Item> it(select_lex->item_list);
 	it++;
@@ -1220,7 +1220,8 @@ Item_in_subselect::single_value_transfor
     DBUG_RETURN(RES_OK);
 
   /* Perform the IN=>EXISTS transformation. */
-  DBUG_RETURN(single_value_in_to_exists_transformer(join, func));
+  const trans_res retval= single_value_in_to_exists_transformer(join, func);
+  DBUG_RETURN(retval);
 }
 
 
@@ -1274,8 +1275,8 @@ Item_in_subselect::single_value_in_to_ex
     Item *item= func->create(expr,
                              new Item_ref_null_helper(&select_lex->context,
                                                       this,
-                                                      select_lex->
-                                                      ref_pointer_array,
+                                                      &select_lex->
+                                                      ref_pointer_array[0],
                                                       (char *)"<ref>",
                                                       this->full_name()));
     if (!abort_on_null && left_expr->maybe_null)
@@ -1393,7 +1394,7 @@ Item_in_subselect::single_value_in_to_ex
         Item *new_having=
           func->create(expr,
                        new Item_ref_null_helper(&select_lex->context, this,
-                                            select_lex->ref_pointer_array,
+                                            &select_lex->ref_pointer_array[0],
                                             (char *)"<no matter>",
                                             (char *)"<result>"));
         if (!abort_on_null && left_expr->maybe_null)
@@ -1570,14 +1571,14 @@ Item_in_subselect::row_value_in_to_exist
                                   (char *)in_left_expr_name),
                          new
                          Item_ref(&select_lex->context,
-                                  select_lex->ref_pointer_array + i,
+                                  &select_lex->ref_pointer_array[i],
                                   (char *)"<no matter>",
                                   (char *)"<list ref>")
                         );
       Item *item_isnull=
         new Item_func_isnull(new
                              Item_ref(&select_lex->context,
-                                      select_lex->ref_pointer_array+i,
+                                      &select_lex->ref_pointer_array[i],
                                       (char *)"<no matter>",
                                       (char *)"<list ref>")
                             );
@@ -1592,8 +1593,8 @@ Item_in_subselect::row_value_in_to_exist
       Item *item_nnull_test= 
          new Item_is_not_null_test(this,
                                    new Item_ref(&select_lex->context,
-                                                select_lex->
-                                                ref_pointer_array + i,
+                                                &select_lex->
+                                                ref_pointer_array[i],
                                                 (char *)"<no matter>",
                                                 (char *)"<list ref>"));
       if (!abort_on_null && left_expr->element_index(i)->maybe_null)
@@ -1648,8 +1649,8 @@ Item_in_subselect::row_value_in_to_exist
                                          (char *)in_left_expr_name),
                          new
                          Item_direct_ref(&select_lex->context,
-                                         select_lex->
-                                         ref_pointer_array+i,
+                                         &select_lex->
+                                         ref_pointer_array[i],
                                          (char *)"<no matter>",
                                          (char *)"<list ref>")
                         );
@@ -1659,7 +1660,7 @@ Item_in_subselect::row_value_in_to_exist
           new Item_is_not_null_test(this,
                                     new
                                     Item_ref(&select_lex->context, 
-                                             select_lex->ref_pointer_array + i,
+                                             &select_lex->ref_pointer_array[i],
                                              (char *)"<no matter>",
                                              (char *)"<list ref>"));
         
@@ -1667,8 +1668,8 @@ Item_in_subselect::row_value_in_to_exist
         item_isnull= new
           Item_func_isnull(new
                            Item_direct_ref(&select_lex->context,
-                                           select_lex->
-                                           ref_pointer_array+i,
+                                           &select_lex->
+                                           ref_pointer_array[i],
                                            (char *)"<no matter>",
                                            (char *)"<list ref>")
                           );

=== modified file 'sql/item_sum.cc'
--- a/sql/item_sum.cc	2011-05-26 15:20:09 +0000
+++ b/sql/item_sum.cc	2011-05-30 10:44:01 +0000
@@ -3306,7 +3306,8 @@ bool Item_func_group_concat::setup(THD *
     tmp table columns.
   */
   if (arg_count_order &&
-      setup_order(thd, args, context->table_list, list, all_fields, *order))
+      setup_order(thd, Ref_ptr_array(args, arg_count),
+                  context->table_list, list, all_fields, *order))
     DBUG_RETURN(TRUE);
 
   count_field_types(select_lex, tmp_table_param, all_fields, 0);

=== modified file 'sql/sql_array.h'
--- a/sql/sql_array.h	2011-05-18 13:12:02 +0000
+++ b/sql/sql_array.h	2011-05-30 10:44:01 +0000
@@ -1,7 +1,7 @@
 #ifndef SQL_ARRAY_INCLUDED
 #define SQL_ARRAY_INCLUDED
 
-/* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2003, 2011, 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
@@ -18,6 +18,60 @@
 
 #include <my_sys.h>
 
+/**
+   A wrapper class which provides array bounds checking.
+   We do *not* own the array, we simply have a pointer to the first element,
+   and a length.
+
+   @remark
+   We want the compiler-generated versions of:
+   - the copy CTOR (memberwise initialization)
+   - the assignment operator (memberwise assignment)
+
+   @param Element_type The type of the elements of the container.
+ */
+template <typename Element_type> class Bounds_checked_array
+{
+public:
+  Bounds_checked_array() : m_array(NULL), m_size(0) {}
+
+  Bounds_checked_array(Element_type *el, size_t size)
+    : m_array(el), m_size(size)
+  {}
+
+  void reset() { m_array= NULL; m_size= 0; }
+
+  Element_type &operator[](size_t n)
+  {
+    DBUG_ASSERT(n < m_size);
+    return m_array[n];
+  }
+
+  const Element_type &operator[](size_t n) const
+  {
+    DBUG_ASSERT(n < m_size);
+    return m_array[n];
+  }
+
+  size_t element_size() const { return sizeof(Element_type); }
+  size_t size() const         { return m_size; }
+
+  operator bool() const { return m_array != NULL; }
+
+  void pop_front()
+  {
+    DBUG_ASSERT(m_size > 0);
+    m_array+= 1;
+    m_size-= 1;
+  }
+
+  Element_type *array() const { return m_array; }
+
+private:
+  Element_type *m_array;
+  size_t        m_size;
+};
+
 /*
   A typesafe wrapper around DYNAMIC_ARRAY
 */

=== modified file 'sql/sql_base.cc'
--- a/sql/sql_base.cc	2011-05-26 15:20:09 +0000
+++ b/sql/sql_base.cc	2011-05-30 10:44:01 +0000
@@ -8022,7 +8022,7 @@ int setup_wild(THD *thd, TABLE_LIST *tab
 ** Check that all given fields exists and fill struct with current data
 ****************************************************************************/
 
-bool setup_fields(THD *thd, Item **ref_pointer_array,
+bool setup_fields(THD *thd, Ref_ptr_array ref_pointer_array,
                   List<Item> &fields, enum_mark_columns mark_used_columns,
                   List<Item> *sum_func_list, bool allow_sum_func)
 {
@@ -8053,7 +8053,10 @@ bool setup_fields(THD *thd, Item **ref_p
     ref_pointer_array
   */
   if (ref_pointer_array)
-    memset(ref_pointer_array, 0, sizeof(Item *) * fields.elements);
+  {
+    DBUG_ASSERT(ref_pointer_array.size() >= fields.elements);
+    memset(ref_pointer_array.array(), 0, sizeof(Item *) * fields.elements);
+  }
 
   /*
     We call set_entry() there (before fix_fields() of the whole list of field
@@ -8071,7 +8074,7 @@ bool setup_fields(THD *thd, Item **ref_p
   while ((var= li++))
     var->set_entry(thd, FALSE);
 
-  Item **ref= ref_pointer_array;
+  Ref_ptr_array ref= ref_pointer_array;
   thd->lex->current_select->cur_pos_in_select_list= 0;
   while ((item= it++))
   {
@@ -8085,10 +8088,13 @@ bool setup_fields(THD *thd, Item **ref_p
       DBUG_RETURN(TRUE); /* purecov: inspected */
     }
     if (ref)
-      *(ref++)= item;
+    {
+      ref[0]= item;
+      ref.pop_front();
+    }
     if (item->with_sum_func && item->type() != Item::SUM_FUNC_ITEM &&
 	sum_func_list)
-      item->split_sum_func(thd, ref_pointer_array, *sum_func_list);
+      item->split_sum_func(thd, ref_pointer_array.array(), *sum_func_list);
     thd->used_tables|= item->used_tables();
     thd->lex->current_select->cur_pos_in_select_list++;
   }

=== modified file 'sql/sql_base.h'
--- a/sql/sql_base.h	2011-05-04 07:51:15 +0000
+++ b/sql/sql_base.h	2011-05-30 10:44:01 +0000
@@ -184,7 +184,7 @@ bool insert_fields(THD *thd, Name_resolu
                    List_iterator<Item> *it, bool any_privileges);
 int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields,
 	       List<Item> *sum_func_list, uint wild_num);
-bool setup_fields(THD *thd, Item** ref_pointer_array,
+bool setup_fields(THD *thd, Ref_ptr_array ref_pointer_array,
                   List<Item> &item, enum_mark_columns mark_used_columns,
                   List<Item> *sum_func_list, bool allow_sum_func);
 bool fill_record(THD *thd, Field **field, List<Item> &values,
@@ -350,7 +350,7 @@ inline TABLE_LIST *find_table_in_local_l
 }
 
 
-inline bool setup_fields_with_no_wrap(THD *thd, Item **ref_pointer_array,
+inline bool setup_fields_with_no_wrap(THD *thd, Ref_ptr_array ref_pointer_array,
                                       List<Item> &item,
                                       enum_mark_columns mark_used_columns,
                                       List<Item> *sum_func_list,

=== modified file 'sql/sql_do.cc'
--- a/sql/sql_do.cc	2010-07-27 15:01:56 +0000
+++ b/sql/sql_do.cc	2011-05-30 10:44:01 +0000
@@ -28,7 +28,7 @@ bool mysql_do(THD *thd, List<Item> &valu
   List_iterator<Item> li(values);
   Item *value;
   DBUG_ENTER("mysql_do");
-  if (setup_fields(thd, 0, values, MARK_COLUMNS_NONE, 0, 0))
+  if (setup_fields(thd, Ref_ptr_array(), values, MARK_COLUMNS_NONE, 0, 0))
     DBUG_RETURN(TRUE);
   while ((value = li++))
     value->val_int();

=== modified file 'sql/sql_insert.cc'
--- a/sql/sql_insert.cc	2011-05-30 06:25:47 +0000
+++ b/sql/sql_insert.cc	2011-05-30 10:44:01 +0000
@@ -256,7 +256,7 @@ static int check_insert_fields(THD *thd,
     */
     table_list->next_local= 0;
     context->resolve_in_table_list_only(table_list);
-    res= setup_fields(thd, 0, fields, MARK_COLUMNS_WRITE, 0, 0);
+    res= setup_fields(thd, Ref_ptr_array(), fields, MARK_COLUMNS_WRITE, 0, 0);
 
     /* Restore the current context. */
     ctx_state.restore_state(context, table_list);
@@ -347,7 +347,8 @@ static int check_update_fields(THD *thd,
   }
 
   /* Check the fields we are going to modify */
-  if (setup_fields(thd, 0, update_fields, MARK_COLUMNS_WRITE, 0, 0))
+  if (setup_fields(thd, Ref_ptr_array(),
+                   update_fields, MARK_COLUMNS_WRITE, 0, 0))
     return -1;
 
   if (insert_table_list->effective_algorithm == VIEW_ALGORITHM_MERGE &&
@@ -762,7 +763,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *t
       my_error(ER_WRONG_VALUE_COUNT_ON_ROW, MYF(0), counter);
       goto abort;
     }
-    if (setup_fields(thd, 0, *values, MARK_COLUMNS_READ, 0, 0))
+    if (setup_fields(thd, Ref_ptr_array(), *values, MARK_COLUMNS_READ, 0, 0))
       goto abort;
   }
   its.rewind ();
@@ -1377,7 +1378,8 @@ bool mysql_prepare_insert(THD *thd, TABL
     table_list->next_local= 0;
     context->resolve_in_table_list_only(table_list);
 
-    res= (setup_fields(thd, 0, *values, MARK_COLUMNS_READ, 0, 0) ||
+    res= (setup_fields(thd, Ref_ptr_array(),
+                       *values, MARK_COLUMNS_READ, 0, 0) ||
           check_insert_fields(thd, context->table_list, fields, *values,
                               !insert_into_view, 0, &map));
 
@@ -1393,7 +1395,8 @@ bool mysql_prepare_insert(THD *thd, TABL
     }
 
    if (!res)
-     res= setup_fields(thd, 0, update_values, MARK_COLUMNS_READ, 0, 0);
+     res= setup_fields(thd, Ref_ptr_array(),
+                       update_values, MARK_COLUMNS_READ, 0, 0);
 
     if (!res && duplic == DUP_UPDATE)
     {
@@ -3231,7 +3234,7 @@ select_insert::prepare(List<Item> &value
 
   /* Errors during check_insert_fields() should not be ignored. */
   lex->current_select->no_error= FALSE;
-  res= (setup_fields(thd, 0, values, MARK_COLUMNS_READ, 0, 0) ||
+  res= (setup_fields(thd, Ref_ptr_array(), values, MARK_COLUMNS_READ, 0, 0) ||
         check_insert_fields(thd, table_list, *fields, values,
                             !insert_into_view, 1, &map));
 
@@ -3279,7 +3282,7 @@ select_insert::prepare(List<Item> &value
       table_list->next_name_resolution_table= 
         ctx_state.get_first_name_resolution_table();
 
-    res= res || setup_fields(thd, 0, *info.update_values,
+    res= res || setup_fields(thd, Ref_ptr_array(), *info.update_values,
                              MARK_COLUMNS_READ, 0, 0);
     if (!res)
     {

=== modified file 'sql/sql_lex.cc'
--- a/sql/sql_lex.cc	2011-05-26 15:20:09 +0000
+++ b/sql/sql_lex.cc	2011-05-30 10:44:01 +0000
@@ -1732,6 +1732,8 @@ void st_select_lex_unit::init_query()
 
 void st_select_lex::init_query()
 {
+  DBUG_ENTER("st_select_lex::init_query");
+  DBUG_PRINT("info", ("this %p", this));
   st_select_lex_node::init_query();
   table_list.empty();
   top_join_list.empty();
@@ -1757,7 +1759,7 @@ void st_select_lex::init_query()
   parent_lex->push_context(&context);
   cond_count= between_count= with_wild= 0;
   max_equal_elems= 0;
-  ref_pointer_array= 0;
+  ref_pointer_array.reset();
   select_n_where_fields= 0;
   select_n_having_items= 0;
   subquery_in_having= explicit_limit= 0;
@@ -1769,10 +1771,13 @@ void st_select_lex::init_query()
   exclude_from_table_unique_test= no_wrap_view_item= FALSE;
   nest_level= 0;
   link_next= 0;
+  DBUG_VOID_RETURN;
 }
 
 void st_select_lex::init_select()
 {
+  DBUG_ENTER("st_select_lex::init_select");
+  DBUG_PRINT("info", ("this %p", this));
   st_select_lex_node::init_select();
   sj_nests.empty();
   group_list.empty();
@@ -1800,6 +1805,7 @@ void st_select_lex::init_select()
   cond_value= having_value= Item::COND_UNDEF;
   inner_refs_list.empty();
   full_group_by_flag= 0;
+  DBUG_VOID_RETURN;
 }
 
 /*
@@ -2132,20 +2138,38 @@ ulong st_select_lex::get_table_join_opti
 
 bool st_select_lex::setup_ref_array(THD *thd, uint order_group_num)
 {
+#ifdef DBUG_OFF
   if (ref_pointer_array)
     return 0;
+#endif
+
+  DBUG_ENTER("st_select_lex::setup_ref_array");
 
   /*
     We have to create array in prepared statement memory if it is
     prepared statement
   */
   Query_arena *arena= thd->stmt_arena;
-  return (ref_pointer_array=
-          (Item **)arena->alloc(sizeof(Item*) * (n_child_sum_items +
-                                                 item_list.elements +
-                                                 select_n_having_items +
-                                                 select_n_where_fields +
-                                                 order_group_num)*5)) == 0;
+  uint n_elems= (n_child_sum_items +
+                 item_list.elements +
+                 select_n_having_items +
+                 select_n_where_fields +
+                 order_group_num) * 5;
+  DBUG_PRINT("info", ("setup_ref_array %4u : %4u %4u %4u %4u %4u",
+                      n_elems,
+                      n_child_sum_items,
+                      item_list.elements,
+                      select_n_having_items,
+                      select_n_where_fields,
+                      order_group_num));
+  if (ref_pointer_array) {
+    DBUG_ASSERT(ref_pointer_array.size() == n_elems);
+    DBUG_RETURN(0);
+  }
+  Item **array= (Item **)arena->alloc(sizeof(Item*) * n_elems);
+  ref_pointer_array= Ref_ptr_array(array, n_elems);
+
+  DBUG_RETURN(array == NULL);
 }
 
 

=== modified file 'sql/sql_lex.h'
--- a/sql/sql_lex.h	2011-05-12 17:29:19 +0000
+++ b/sql/sql_lex.h	2011-05-30 10:44:01 +0000
@@ -24,6 +24,7 @@
 #include "sql_trigger.h"
 #include "item.h"               /* From item_subselect.h: subselect_union_engine */
 #include "thr_lock.h"                  /* thr_lock_type, TL_UNLOCK */
+#include "sql_array.h"
 
 /* YACC and LEX Definitions */
 
@@ -602,6 +603,7 @@ public:
 };
 
 typedef class st_select_lex_unit SELECT_LEX_UNIT;
+typedef Bounds_checked_array<Item*> Ref_ptr_array;
 
 /*
   SELECT_LEX - store information of parsed SELECT statment
@@ -655,8 +657,9 @@ public:
   SQL_I_List<ORDER> order_list;   /* ORDER clause */
   SQL_I_List<ORDER> *gorder_list;
   Item *select_limit, *offset_limit;  /* LIMIT clause parameters */
-  // Arrays of pointers to top elements of all_fields list
-  Item **ref_pointer_array;
+
+  // Array of pointers to top elements of all_fields list
+  Ref_ptr_array ref_pointer_array;
 
   /*
     number of items in select_list and HAVING clause used to get number
@@ -666,7 +669,7 @@ public:
   uint select_n_having_items;
   uint cond_count;    /* number of arguments of and/or/xor in where/having/on */
   uint between_count; /* number of between predicates in where/having/on      */
-  uint max_equal_elems; /* maximal number of elements in multiple equalities  */   
+  uint max_equal_elems; /* maximal number of elements in multiple equalities  */
   /*
     Number of fields used in select list or where clause of current select
     and all inner subselects.

=== modified file 'sql/sql_load.cc'
--- a/sql/sql_load.cc	2011-05-26 15:20:09 +0000
+++ b/sql/sql_load.cc	2011-05-30 10:44:01 +0000
@@ -268,15 +268,18 @@ int mysql_load(THD *thd,sql_exchange *ex
       Let us also prepare SET clause, altough it is probably empty
       in this case.
     */
-    if (setup_fields(thd, 0, set_fields, MARK_COLUMNS_WRITE, 0, 0) ||
-        setup_fields(thd, 0, set_values, MARK_COLUMNS_READ, 0, 0))
+    if (setup_fields(thd, Ref_ptr_array(),
+                     set_fields, MARK_COLUMNS_WRITE, 0, 0) ||
+        setup_fields(thd, Ref_ptr_array(), set_values, MARK_COLUMNS_READ, 0, 0))
       DBUG_RETURN(TRUE);
   }
   else
   {						// Part field list
     /* TODO: use this conds for 'WITH CHECK OPTIONS' */
-    if (setup_fields(thd, 0, fields_vars, MARK_COLUMNS_WRITE, 0, 0) ||
-        setup_fields(thd, 0, set_fields, MARK_COLUMNS_WRITE, 0, 0) ||
+    if (setup_fields(thd, Ref_ptr_array(),
+                     fields_vars, MARK_COLUMNS_WRITE, 0, 0) ||
+        setup_fields(thd, Ref_ptr_array(),
+                     set_fields, MARK_COLUMNS_WRITE, 0, 0) ||
         check_that_all_fields_are_given_values(thd, table, table_list))
       DBUG_RETURN(TRUE);
     /*
@@ -295,7 +298,7 @@ int mysql_load(THD *thd,sql_exchange *ex
       }
     }
     /* Fix the expressions in SET clause */
-    if (setup_fields(thd, 0, set_values, MARK_COLUMNS_READ, 0, 0))
+    if (setup_fields(thd, Ref_ptr_array(), set_values, MARK_COLUMNS_READ, 0, 0))
       DBUG_RETURN(TRUE);
   }
 

=== modified file 'sql/sql_prepare.cc'
--- a/sql/sql_prepare.cc	2011-05-26 15:20:09 +0000
+++ b/sql/sql_prepare.cc	2011-05-30 10:44:01 +0000
@@ -1294,7 +1294,7 @@ static bool mysql_test_insert(Prepared_s
         my_error(ER_WRONG_VALUE_COUNT_ON_ROW, MYF(0), counter);
         goto error;
       }
-      if (setup_fields(thd, 0, *values, MARK_COLUMNS_NONE, 0, 0))
+      if (setup_fields(thd, Ref_ptr_array(), *values, MARK_COLUMNS_NONE, 0, 0))
         goto error;
     }
   }
@@ -1373,7 +1373,8 @@ static int mysql_test_update(Prepared_st
   table_list->register_want_access(want_privilege);
 #endif
   thd->lex->select_lex.no_wrap_view_item= TRUE;
-  res= setup_fields(thd, 0, select->item_list, MARK_COLUMNS_READ, 0, 0);
+  res= setup_fields(thd, Ref_ptr_array(),
+                    select->item_list, MARK_COLUMNS_READ, 0, 0);
   thd->lex->select_lex.no_wrap_view_item= FALSE;
   if (res)
     goto error;
@@ -1384,7 +1385,8 @@ static int mysql_test_update(Prepared_st
     (SELECT_ACL & ~table_list->table->grant.privilege);
   table_list->register_want_access(SELECT_ACL);
 #endif
-  if (setup_fields(thd, 0, stmt->lex->value_list, MARK_COLUMNS_NONE, 0, 0))
+  if (setup_fields(thd, Ref_ptr_array(),
+                   stmt->lex->value_list, MARK_COLUMNS_NONE, 0, 0))
     goto error;
   /* TODO: here we should send types of placeholders to the client. */
   DBUG_RETURN(0);
@@ -1530,7 +1532,8 @@ static bool mysql_test_do_fields(Prepare
 
   if (open_normal_and_derived_tables(thd, tables, MYSQL_OPEN_FORCE_SHARED_MDL))
     DBUG_RETURN(TRUE);
-  DBUG_RETURN(setup_fields(thd, 0, *values, MARK_COLUMNS_NONE, 0, 0));
+  DBUG_RETURN(setup_fields(thd, Ref_ptr_array(),
+                           *values, MARK_COLUMNS_NONE, 0, 0));
 }
 
 

=== modified file 'sql/sql_select.cc'
--- a/sql/sql_select.cc	2011-05-26 15:20:09 +0000
+++ b/sql/sql_select.cc	2011-05-30 10:44:01 +0000
@@ -203,7 +203,7 @@ static int remove_dup_with_hash_index(TH
 static bool cmp_buffer_with_ref(THD *thd, TABLE *table, TABLE_REF *tab_ref);
 static bool setup_new_fields(THD *thd, List<Item> &fields,
 			     List<Item> &all_fields, ORDER *new_order);
-static ORDER *create_distinct_group(THD *thd, Item **ref_pointer_array,
+static ORDER *create_distinct_group(THD *thd, Ref_ptr_array ref_pointer_array,
                                     ORDER *order, List<Item> &fields,
                                     List<Item> &all_fields,
 				    bool *all_order_by_fields_used);
@@ -213,12 +213,12 @@ static void calc_group_buffer(JOIN *join
 static bool make_group_fields(JOIN *main_join, JOIN *curr_join);
 static bool alloc_group_fields(JOIN *join,ORDER *group);
 // Create list for using with tempory table
-static bool change_to_use_tmp_fields(THD *thd, Item **ref_pointer_array,
+static bool change_to_use_tmp_fields(THD *thd, Ref_ptr_array ref_pointer_array,
 				     List<Item> &new_list1,
 				     List<Item> &new_list2,
 				     uint elements, List<Item> &items);
 // Create list for using with tempory table
-static bool change_refs_to_tmp_fields(THD *thd, Item **ref_pointer_array,
+static bool change_refs_to_tmp_fields(THD *thd, Ref_ptr_array ref_pointer_array,
 				      List<Item> &new_list1,
 				      List<Item> &new_list2,
 				      uint elements, List<Item> &items);
@@ -460,7 +460,7 @@ bool handle_select(THD *thd, LEX *lex, s
 
 bool
 fix_inner_refs(THD *thd, List<Item> &all_fields, SELECT_LEX *select,
-                 Item **ref_pointer_array, ORDER *group_list)
+               Ref_ptr_array ref_pointer_array, ORDER *group_list)
 {
   Item_outer_ref *ref;
 
@@ -487,7 +487,7 @@ fix_inner_refs(THD *thd, List<Item> &all
         If it's needed reset each Item_ref item that refers this field with
         a new reference taken from ref_pointer_array.
       */
-      item_ref= ref_pointer_array + el;
+      item_ref= &ref_pointer_array[el];
     }
 
     if (ref->in_sum_func)
@@ -546,7 +546,7 @@ fix_inner_refs(THD *thd, List<Item> &all
 /**
   Function to setup clauses without sum functions.
 */
-inline int setup_without_group(THD *thd, Item **ref_pointer_array,
+inline int setup_without_group(THD *thd, Ref_ptr_array ref_pointer_array,
 			       TABLE_LIST *tables,
 			       TABLE_LIST *leaves,
 			       List<Item> &fields,
@@ -600,7 +600,7 @@ inline int setup_without_group(THD *thd,
     0   on success
 */
 int
-JOIN::prepare(Item ***rref_pointer_array,
+JOIN::prepare(Ref_ptr_array *rref_pointer_array,
 	      TABLE_LIST *tables_init,
 	      uint wild_num, Item *conds_init, uint og_num,
 	      ORDER *order_init, ORDER *group_init,
@@ -647,15 +647,27 @@ JOIN::prepare(Item ***rref_pointer_array
        table_ptr= table_ptr->next_leaf)
     tables++;
 
-  if (setup_wild(thd, tables_list, fields_list, &all_fields, wild_num) ||
-      select_lex->setup_ref_array(thd, og_num) ||
-      setup_fields(thd, (*rref_pointer_array), fields_list, MARK_COLUMNS_READ,
-		   &all_fields, 1) ||
-      setup_without_group(thd, (*rref_pointer_array), tables_list,
+  if (setup_wild(thd, tables_list, fields_list, &all_fields, wild_num))
+    DBUG_RETURN(-1);
+  // find_order_in_list() may need some extra space, so multiply og_num by two.
+  if (select_lex->setup_ref_array(thd, og_num * 2))
+    DBUG_RETURN(-1);
+  /*
+    Item and Item_field CTORs will both increment some counters
+    in current_select, based on the current parsing context.
+    We are not parsing anymore: any new Items created now are due to
+    query rewriting, so stop incrementing counters.
+   */
+  select_lex->parsing_place= NO_MATTER;
+
+  if (setup_fields(thd, *rref_pointer_array, fields_list, MARK_COLUMNS_READ,
+		   &all_fields, 1))
+    DBUG_RETURN(-1);
+  if (setup_without_group(thd, (*rref_pointer_array), tables_list,
 			  select_lex->leaf_tables, fields_list,
 			  all_fields, &conds, order, group_list,
 			  &hidden_group_fields))
-    DBUG_RETURN(-1);				/* purecov: inspected */
+    DBUG_RETURN(-1);
 
   ref_pointer_array= *rref_pointer_array;
   
@@ -712,14 +724,14 @@ JOIN::prepare(Item ***rref_pointer_array
         real_order= TRUE;
 
       if (item->with_sum_func && item->type() != Item::SUM_FUNC_ITEM)
-        item->split_sum_func(thd, ref_pointer_array, all_fields);
+        item->split_sum_func(thd, ref_pointer_array.array(), all_fields);
     }
     if (!real_order)
       order= NULL;
   }
 
   if (having && having->with_sum_func)
-    having->split_sum_func2(thd, ref_pointer_array, all_fields,
+    having->split_sum_func2(thd, ref_pointer_array.array(), all_fields,
                             &having, TRUE);
   if (select_lex->inner_sum_func_list)
   {
@@ -728,7 +740,7 @@ JOIN::prepare(Item ***rref_pointer_array
     do
     { 
       item_sum= item_sum->next;
-      item_sum->split_sum_func2(thd, ref_pointer_array,
+      item_sum->split_sum_func2(thd, ref_pointer_array.array(),
                                 all_fields, item_sum->ref_by, FALSE);
     } while (item_sum != end);
   }
@@ -755,7 +767,7 @@ JOIN::prepare(Item ***rref_pointer_array
         int el= all_fields.elements;
         ref_pointer_array[el]= field;
         all_fields.push_front(field);
-        ord->item= ref_pointer_array + el;
+        ord->item= &ref_pointer_array[el];
       }
     }
   }
@@ -824,7 +836,6 @@ JOIN::prepare(Item ***rref_pointer_array
 
   /* Init join struct */
   count_field_types(select_lex, &tmp_table_param, all_fields, 0);
-  ref_pointer_array_size= all_fields.elements*sizeof(Item*);
   this->group= group_list != 0;
   unit= unit_arg;
 
@@ -3040,7 +3051,8 @@ JOIN::exec()
       curr_join->all_fields= *curr_all_fields;
     if (!items1)
     {
-      items1= items0 + all_fields.elements;
+      items1= Ref_ptr_array(&ref_pointer_array[2 * all_fields.elements],
+                            all_fields.elements);
       if (sort_and_group || curr_tmp_table->group ||
           tmp_table_param.precomputed_group_by)
       {
@@ -3205,7 +3217,8 @@ JOIN::exec()
       // No sum funcs anymore
       if (!items2)
       {
-	items2= items1 + all_fields.elements;
+        items2= Ref_ptr_array(&ref_pointer_array[3 * all_fields.elements],
+                              all_fields.elements);
 	if (change_to_use_tmp_fields(thd, items2,
 				     tmp_fields_list2, tmp_all_fields2, 
 				     fields_list.elements, tmp_all_fields1))
@@ -3262,7 +3275,8 @@ JOIN::exec()
     {
       if (!items0)
 	init_items_ref_array();
-      items3= ref_pointer_array + (all_fields.elements*4);
+      items3= Ref_ptr_array(&ref_pointer_array[4 * all_fields.elements],
+                            all_fields.elements);
       setup_copy_fields(thd, &curr_join->tmp_table_param,
 			items3, tmp_fields_list3, tmp_all_fields3,
 			curr_fields_list->elements, *curr_all_fields);
@@ -3615,7 +3629,7 @@ void JOIN::cleanup_item_list(List<Item> 
 */
 
 bool
-mysql_select(THD *thd, Item ***rref_pointer_array,
+mysql_select(THD *thd, Ref_ptr_array *rref_pointer_array,
 	     TABLE_LIST *tables, uint wild_num, List<Item> &fields,
 	     Item *conds, uint og_num,  ORDER *order, ORDER *group,
 	     Item *having, ORDER *proc_param, ulonglong select_options,
@@ -21122,7 +21136,7 @@ cp_buffer_from_ref(THD *thd, TABLE *tabl
 */
 
 static bool
-find_order_in_list(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
+find_order_in_list(THD *thd, Ref_ptr_array ref_pointer_array, TABLE_LIST *tables,
                    ORDER *order, List<Item> &fields, List<Item> &all_fields,
                    bool is_group_field)
 {
@@ -21146,7 +21160,7 @@ find_order_in_list(THD *thd, Item **ref_
                order_item->full_name(), thd->where);
       return TRUE;
     }
-    order->item= ref_pointer_array + count - 1;
+    order->item= &ref_pointer_array[count - 1];
     order->in_field_list= 1;
     order->counter= count;
     order->counter_used= 1;
@@ -21207,7 +21221,7 @@ find_order_in_list(THD *thd, Item **ref_
         'shadowed' a table field with the same name, the table field will be
         chosen over the derived field.
       */
-      order->item= ref_pointer_array + counter;
+      order->item= &ref_pointer_array[counter];
       order->in_field_list=1;
       return FALSE;
     }
@@ -21265,7 +21279,7 @@ find_order_in_list(THD *thd, Item **ref_
   uint el= all_fields.elements;
   all_fields.push_front(order_item); /* Add new field to field list. */
   ref_pointer_array[el]= order_item;
-  order->item= ref_pointer_array + el;
+  order->item= &ref_pointer_array[el];
   return FALSE;
 }
 
@@ -21277,7 +21291,7 @@ find_order_in_list(THD *thd, Item **ref_
   the field list.
 */
 
-int setup_order(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
+int setup_order(THD *thd, Ref_ptr_array ref_pointer_array, TABLE_LIST *tables,
 		List<Item> &fields, List<Item> &all_fields, ORDER *order)
 {
   thd->where="order clause";
@@ -21318,7 +21332,7 @@ int setup_order(THD *thd, Item **ref_poi
 */
 
 int
-setup_group(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
+setup_group(THD *thd, Ref_ptr_array ref_pointer_array, TABLE_LIST *tables,
 	    List<Item> &fields, List<Item> &all_fields, ORDER *order,
 	    bool *hidden_group_fields)
 {
@@ -21449,13 +21463,14 @@ setup_new_fields(THD *thd, List<Item> &f
 */
 
 ORDER *
-create_distinct_group(THD *thd, Item **ref_pointer_array,
+create_distinct_group(THD *thd, Ref_ptr_array ref_pointer_array,
                       ORDER *order_list, List<Item> &fields,
                       List<Item> &all_fields,
 		      bool *all_order_by_fields_used)
 {
   List_iterator<Item> li(fields);
-  Item *item, **orig_ref_pointer_array= ref_pointer_array;
+  Item *item;
+  Ref_ptr_array orig_ref_pointer_array= ref_pointer_array;
   ORDER *order,*group,**prev;
 
   *all_order_by_fields_used= 1;
@@ -21509,7 +21524,7 @@ create_distinct_group(THD *thd, Item **r
         int el= all_fields.elements;
         orig_ref_pointer_array[el]= new_item;
         all_fields.push_front(new_item);
-        ord->item= orig_ref_pointer_array + el;
+        ord->item= &orig_ref_pointer_array[el];
       }
       else
       {
@@ -21518,14 +21533,14 @@ create_distinct_group(THD *thd, Item **r
           simple indexing of ref_pointer_array (order in the array and in the
           list are same)
         */
-        ord->item= ref_pointer_array;
+        ord->item= &ref_pointer_array[0];
       }
       ord->direction= ORDER::ORDER_ASC;
       *prev=ord;
       prev= &ord->next;
     }
 next_item:
-    ref_pointer_array++;
+    ref_pointer_array.pop_front();
   }
   *prev=0;
   return group;
@@ -21840,7 +21855,7 @@ int test_if_item_cache_changed(List<Cach
 
 bool
 setup_copy_fields(THD *thd, TMP_TABLE_PARAM *param,
-		  Item **ref_pointer_array,
+		  Ref_ptr_array ref_pointer_array,
 		  List<Item> &res_selected_fields, List<Item> &res_all_fields,
 		  uint elements, List<Item> &all_fields)
 {
@@ -22121,7 +22136,7 @@ bool JOIN::make_sum_func_list(List<Item>
 */
 
 static bool
-change_to_use_tmp_fields(THD *thd, Item **ref_pointer_array,
+change_to_use_tmp_fields(THD *thd, Ref_ptr_array ref_pointer_array,
 			 List<Item> &res_selected_fields,
 			 List<Item> &res_all_fields,
 			 uint elements, List<Item> &all_fields)
@@ -22212,7 +22227,7 @@ change_to_use_tmp_fields(THD *thd, Item 
 */
 
 static bool
-change_refs_to_tmp_fields(THD *thd, Item **ref_pointer_array,
+change_refs_to_tmp_fields(THD *thd, Ref_ptr_array ref_pointer_array,
 			  List<Item> &res_selected_fields,
 			  List<Item> &res_all_fields, uint elements,
 			  List<Item> &all_fields)
@@ -22587,15 +22602,20 @@ bool JOIN::rollup_init()
   */
   tmp_table_param.group_parts= send_group_parts;
 
-  if (!(rollup.null_items= (Item_null_result**) thd->alloc((sizeof(Item*) +
-                                                sizeof(Item**) +
-                                                sizeof(List<Item>) +
-				                ref_pointer_array_size)
-				                * send_group_parts )))
-    return 1;
-  
-  rollup.fields= (List<Item>*) (rollup.null_items + send_group_parts);
-  rollup.ref_pointer_arrays= (Item***) (rollup.fields + send_group_parts);
+  Item_null_result **null_items=
+    static_cast<Item_null_result**>(thd->alloc(sizeof(Item*)*send_group_parts));
+
+  rollup.null_items=Item_null_array(null_items, send_group_parts);
+  rollup.ref_pointer_arrays=
+    static_cast<Ref_ptr_array*>
+    (thd->alloc((sizeof(Ref_ptr_array) +
+                 all_fields.elements * sizeof(Item*)) * send_group_parts));
+  rollup.fields=
+    static_cast<List<Item>*>(thd->alloc(sizeof(List<Item>) * send_group_parts));
+
+  if (!rollup.null_items || !rollup.ref_pointer_arrays || !rollup.fields)
+    return true;
+
   ref_array= (Item**) (rollup.ref_pointer_arrays+send_group_parts);
 
   /*
@@ -22607,7 +22627,7 @@ bool JOIN::rollup_init()
     rollup.null_items[i]= new (thd->mem_root) Item_null_result();
     List<Item> *rollup_fields= &rollup.fields[i];
     rollup_fields->empty();
-    rollup.ref_pointer_arrays[i]= ref_array;
+    rollup.ref_pointer_arrays[i]= Ref_ptr_array(ref_array, all_fields.elements);
     ref_array+= all_fields.elements;
   }
   for (i= 0 ; i < send_group_parts; i++)
@@ -22753,11 +22773,11 @@ bool JOIN::rollup_make_fields(List<Item>
     bool real_fields= 0;
     Item *item;
     List_iterator<Item> new_it(rollup.fields[pos]);
-    Item **ref_array_start= rollup.ref_pointer_arrays[pos];
+    Ref_ptr_array ref_array_start= rollup.ref_pointer_arrays[pos];
     ORDER *start_group;
 
     /* Point to first hidden field */
-    Item **ref_array= ref_array_start + fields_arg.elements-1;
+    Item **ref_array= &ref_array_start[fields_arg.elements-1];
 
     /* Remember where the sum functions ends for the previous level */
     sum_funcs_end[pos+1]= *func;
@@ -22774,7 +22794,7 @@ bool JOIN::rollup_make_fields(List<Item>
       if (item == first_field)
       {
 	real_fields= 1;				// End of hidden fields
-	ref_array= ref_array_start;
+	ref_array= &ref_array_start[0];
       }
 
       if (item->type() == Item::SUM_FUNC_ITEM && !item->const_item() &&
@@ -22858,9 +22878,7 @@ int JOIN::rollup_send_data(uint idx)
   for (i= send_group_parts ; i-- > idx ; )
   {
     /* Get reference pointers to sum functions in place */
-    memcpy((char*) ref_pointer_array,
-	   (char*) rollup.ref_pointer_arrays[i],
-	   ref_pointer_array_size);
+    copy_ref_ptr_array(ref_pointer_array, rollup.ref_pointer_arrays[i]);
     if ((!having || having->val_int()))
     {
       if (send_records < unit->select_limit_cnt && do_send_rows &&
@@ -22900,9 +22918,7 @@ int JOIN::rollup_write_data(uint idx, TA
   for (i= send_group_parts ; i-- > idx ; )
   {
     /* Get reference pointers to sum functions in place */
-    memcpy((char*) ref_pointer_array,
-	   (char*) rollup.ref_pointer_arrays[i],
-	   ref_pointer_array_size);
+    copy_ref_ptr_array(ref_pointer_array, rollup.ref_pointer_arrays[i]);
     if ((!having || having->val_int()))
     {
       int write_error;

=== modified file 'sql/sql_select.h'
--- a/sql/sql_select.h	2011-05-26 15:20:09 +0000
+++ b/sql/sql_select.h	2011-05-30 10:44:01 +0000
@@ -1598,12 +1598,14 @@ typedef struct st_position : public Sql_
 } POSITION;
 
 
+typedef Bounds_checked_array<Item_null_result*> Item_null_array;
+
 typedef struct st_rollup
 {
   enum State { STATE_NONE, STATE_INITED, STATE_READY };
   State state;
-  Item_null_result **null_items;
-  Item ***ref_pointer_arrays;
+  Item_null_array null_items;
+  Ref_ptr_array *ref_pointer_arrays;
   List<Item> *fields;
 } ROLLUP;
 
@@ -1879,10 +1881,19 @@ public:
     FirstMatch strategy.
   */
   JOIN_TAB *return_tab;
-  Item **ref_pointer_array; ///<used pointer reference for this select
-  // Copy of above to be used with different lists
-  Item **items0, **items1, **items2, **items3, **current_ref_pointer_array;
-  uint ref_pointer_array_size; ///< size of above in bytes
+
+  /*
+    Used pointer reference for this select.
+    Actually contains five "slices", used by items0..items3 below.
+    |=======|=======|=======|=======|=======|
+             items0  items1  items2  items3
+   */
+  Ref_ptr_array ref_pointer_array;
+  // Copy of the initial slice above, to be used with different lists
+  Ref_ptr_array items0, items1, items2, items3;
+  // Used by rollup, to restore ref_pointer_array after overwriting it.
+  Ref_ptr_array current_ref_pointer_array;
+
   const char *zero_result_cause; ///< not 0 if exec must return zero result
   
   bool union_part; ///< this subselect is part of union 
@@ -1958,8 +1969,11 @@ public:
     hidden_group_fields= 0; /*safety*/
     error= 0;
     return_tab= 0;
-    ref_pointer_array= items0= items1= items2= items3= 0;
-    ref_pointer_array_size= 0;
+    ref_pointer_array.reset();
+    items0.reset();
+    items1.reset();
+    items2.reset();
+    items3.reset();
     zero_result_cause= 0;
     optimized= 0;
     cond_equal= 0;
@@ -1979,7 +1993,8 @@ public:
     first_select= sub_select;
   }
 
-  int prepare(Item ***rref_pointer_array, TABLE_LIST *tables, uint wind_num,
+  int prepare(Ref_ptr_array *rref_pointer_array,
+              TABLE_LIST *tables, uint wind_num,
 	      Item *conds, uint og_num, ORDER *order, ORDER *group,
 	      Item *having, ORDER *proc_param, SELECT_LEX *select,
 	      SELECT_LEX_UNIT *unit);
@@ -1994,15 +2009,24 @@ public:
   bool make_sum_func_list(List<Item> &all_fields, List<Item> &send_fields,
 			  bool before_group_by, bool recompute= FALSE);
 
-  inline void set_items_ref_array(Item **ptr)
+  void copy_ref_ptr_array(Ref_ptr_array dst_arr, Ref_ptr_array src_arr)
+  {
+    DBUG_ASSERT(dst_arr.size() >= src_arr.size());
+    void *dest= dst_arr.array();
+    const void *src= src_arr.array();
+    memcpy(dest, src, src_arr.size() * src_arr.element_size());
+  }
+  void set_items_ref_array(Ref_ptr_array ptr)
   {
-    memcpy((char*) ref_pointer_array, (char*) ptr, ref_pointer_array_size);
+    copy_ref_ptr_array(ref_pointer_array, ptr);
     current_ref_pointer_array= ptr;
   }
-  inline void init_items_ref_array()
+  void init_items_ref_array()
   {
-    items0= ref_pointer_array + all_fields.elements;
-    memcpy(items0, ref_pointer_array, ref_pointer_array_size);
+    items0= Ref_ptr_array(&ref_pointer_array[all_fields.elements],
+                          all_fields.elements);
+    copy_ref_ptr_array(items0, Ref_ptr_array(&ref_pointer_array[0],
+                                             all_fields.elements));
     current_ref_pointer_array= items0;
   }
 
@@ -2074,7 +2098,7 @@ void free_tmp_table(THD *thd, TABLE *ent
 void count_field_types(SELECT_LEX *select_lex, TMP_TABLE_PARAM *param, 
                        List<Item> &fields, bool reset_with_sum_func);
 bool setup_copy_fields(THD *thd, TMP_TABLE_PARAM *param,
-		       Item **ref_pointer_array,
+		       Ref_ptr_array ref_pointer_array,
 		       List<Item> &new_list1, List<Item> &new_list2,
 		       uint elements, List<Item> &fields);
 void copy_fields(TMP_TABLE_PARAM *param);
@@ -2263,17 +2287,17 @@ Item *remove_eq_conds(THD *thd, Item *co
 int get_quick_record(SQL_SELECT *select);
 SORT_FIELD * make_unireg_sortorder(ORDER *order, uint *length,
                                   SORT_FIELD *sortorder);
-int setup_order(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
+int setup_order(THD *thd, Ref_ptr_array ref_pointer_array, TABLE_LIST *tables,
 		List<Item> &fields, List <Item> &all_fields, ORDER *order);
-int setup_group(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
+int setup_group(THD *thd, Ref_ptr_array ref_pointer_array, TABLE_LIST *tables,
 		List<Item> &fields, List<Item> &all_fields, ORDER *order,
 		bool *hidden_group_fields);
 bool fix_inner_refs(THD *thd, List<Item> &all_fields, SELECT_LEX *select,
-                   Item **ref_pointer_array, ORDER *group_list= NULL);
+                   Ref_ptr_array ref_pointer_array, ORDER *group_list= NULL);
 
 bool handle_select(THD *thd, LEX *lex, select_result *result,
                    ulong setup_tables_done_option);
-bool mysql_select(THD *thd, Item ***rref_pointer_array,
+bool mysql_select(THD *thd, Ref_ptr_array *rref_pointer_array,
                   TABLE_LIST *tables, uint wild_num,  List<Item> &list,
                   Item *conds, uint og_num, ORDER *order, ORDER *group,
                   Item *having, ORDER *proc_param, ulonglong select_type, 

=== modified file 'sql/sql_update.cc'
--- a/sql/sql_update.cc	2011-05-26 15:20:09 +0000
+++ b/sql/sql_update.cc	2011-05-30 10:44:01 +0000
@@ -328,7 +328,8 @@ int mysql_update(THD *thd,
   table_list->grant.want_privilege= table->grant.want_privilege= want_privilege;
   table_list->register_want_access(want_privilege);
 #endif
-  if (setup_fields_with_no_wrap(thd, 0, fields, MARK_COLUMNS_WRITE, 0, 0))
+  if (setup_fields_with_no_wrap(thd, Ref_ptr_array(),
+                                fields, MARK_COLUMNS_WRITE, 0, 0))
     DBUG_RETURN(1);                     /* purecov: inspected */
   if (table_list->view && check_fields(thd, fields))
   {
@@ -359,7 +360,7 @@ int mysql_update(THD *thd,
   table_list->grant.want_privilege= table->grant.want_privilege=
     (SELECT_ACL & ~table->grant.privilege);
 #endif
-  if (setup_fields(thd, 0, values, MARK_COLUMNS_READ, 0, 0))
+  if (setup_fields(thd, Ref_ptr_array(), values, MARK_COLUMNS_READ, 0, 0))
   {
     free_underlaid_joins(thd, select_lex);
     DBUG_RETURN(1);				/* purecov: inspected */
@@ -1148,7 +1149,8 @@ int mysql_multi_update_prepare(THD *thd)
                                     UPDATE_ACL, SELECT_ACL))
     DBUG_RETURN(TRUE);
 
-  if (setup_fields_with_no_wrap(thd, 0, *fields, MARK_COLUMNS_WRITE, 0, 0))
+  if (setup_fields_with_no_wrap(thd, Ref_ptr_array(),
+                                *fields, MARK_COLUMNS_WRITE, 0, 0))
     DBUG_RETURN(TRUE);
 
   for (tl= table_list; tl ; tl= tl->next_local)
@@ -1422,7 +1424,8 @@ int multi_update::prepare(List<Item> &no
     reference tables
   */
 
-  int error= setup_fields(thd, 0, *values, MARK_COLUMNS_READ, 0, 0);
+  int error= setup_fields(thd, Ref_ptr_array(),
+                          *values, MARK_COLUMNS_READ, 0, 0);
 
   for (table_ref= leaves; table_ref; table_ref= table_ref->next_leaf)
   {

=== modified file 'unittest/gunit/CMakeLists.txt'
--- a/unittest/gunit/CMakeLists.txt	2011-05-18 08:29:46 +0000
+++ b/unittest/gunit/CMakeLists.txt	2011-05-30 10:44:01 +0000
@@ -205,6 +205,7 @@ ENDIF()
 # Add tests (link them with gunit library) 
 SET(TESTS
   bounded_queue
+  bounds_checked_array
   dbug
   dynarray
   mdl

=== added file 'unittest/gunit/bounds_checked_array-t.cc'
--- a/unittest/gunit/bounds_checked_array-t.cc	1970-01-01 00:00:00 +0000
+++ b/unittest/gunit/bounds_checked_array-t.cc	2011-05-30 10:44:01 +0000
@@ -0,0 +1,117 @@
+/* Copyright (c) 2011, 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, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+
+// First include (the generated) my_config.h, to get correct platform defines,
+// then gtest.h (before any other MySQL headers), to avoid min() macros etc ...
+#include "my_config.h"
+#include <gtest/gtest.h>
+
+#include "sql_array.h"
+
+namespace {
+
+typedef Bounds_checked_array<int> Int_array;
+
+class BoundsCheckedArray : public ::testing::Test
+{
+public:
+  BoundsCheckedArray() : some_integer(0) {}
+
+  virtual void SetUp()
+  {
+    for (int ix= 0; ix < c_array_size; ++ix)
+      c_array[ix]= ix;
+  }
+
+  static const int c_array_size= 5;
+  int c_array[c_array_size];
+
+  int some_integer;
+  Int_array int_array;
+};
+
+TEST_F(BoundsCheckedArray, Empty)
+{
+  EXPECT_EQ(sizeof(int), int_array.element_size());
+  EXPECT_EQ(0U, int_array.size());
+  if (int_array) ADD_FAILURE() << "operator bool() should have returned false";
+  int *pi= NULL;
+  EXPECT_EQ(pi, int_array.array());
+}
+
+#if !defined(DBUG_OFF)
+
+// Google Test recommends DeathTest suffix for classes used in death tests.
+typedef BoundsCheckedArray BoundsCheckedArrayDeathTest;
+
+TEST_F(BoundsCheckedArrayDeathTest, BoundsCheckRead)
+{
+  ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+  int_array= Int_array(c_array, 2);
+  EXPECT_DEATH_IF_SUPPORTED(some_integer= int_array[5],
+                            ".*Assertion .*n < m_size.*");
+}
+
+TEST_F(BoundsCheckedArrayDeathTest, BoundsCheckAssign)
+{
+  ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+  int_array= Int_array(c_array, 2);
+  EXPECT_DEATH_IF_SUPPORTED(int_array[5]= some_integer,
+                            ".*Assertion .*n < m_size.*");
+}
+
+TEST_F(BoundsCheckedArrayDeathTest, BoundsCheckPopFront)
+{
+  ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+  int_array= Int_array(c_array, 1);
+  int_array.pop_front();
+  EXPECT_DEATH_IF_SUPPORTED(int_array.pop_front(),
+                            ".*Assertion .*m_size > 0.*");
+}
+
+#endif  // !defined(DBUG_OFF)
+
+TEST_F(BoundsCheckedArray, Indexing)
+{
+  int_array= Int_array(c_array, c_array_size);
+  EXPECT_EQ(0, int_array[0]);
+  int_array[0]= 42;
+  EXPECT_EQ(42, int_array[0]);
+}
+
+
+TEST_F(BoundsCheckedArray, Reset)
+{
+  int_array= Int_array(c_array, c_array_size);
+  EXPECT_EQ(c_array, int_array.array());
+  if (!int_array) ADD_FAILURE() << "operator bool() should have returned true";
+  int_array.reset();
+  int *pi= NULL;
+  EXPECT_EQ(pi, int_array.array());
+  if (int_array) ADD_FAILURE() << "operator bool() should have returned false";
+}
+
+
+TEST_F(BoundsCheckedArray, PopFront)
+{
+  int_array= Int_array(c_array, c_array_size);
+  for (int ix= 0; ix < c_array_size; ++ix)
+  {
+    EXPECT_EQ(ix, int_array[0]);
+    int_array.pop_front();
+  }
+}
+
+}  // namespace


Attachment: [text/bzr-bundle] bzr/tor.didriksen@oracle.com-20110530104401-hogb7z5uw44k55y0.bundle
Thread
bzr commit into mysql-trunk branch (tor.didriksen:3128) Bug#12590211Tor Didriksen31 May