From: Tor Didriksen Date: June 23 2011 10:08am Subject: bzr commit into mysql-trunk branch (tor.didriksen:3232) Bug#12590211 List-Archive: http://lists.mysql.com/commits/139720 X-Bug: 12590211 Message-Id: <20110623100823.322E82FD@atum07.norway.sun.com> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="===============5565954311287343554==" --===============5565954311287343554== MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Content-Disposition: inline #At file:///export/home/didrik/repo/trunk-bug11765255-arraycheck/ based on revid:vasil.dimov@stripped 3232 Tor Didriksen 2011-06-23 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/item.cc Introduce Ref_ptr_array for split_sum_funcN functions. @ sql/item.h Introduce Ref_ptr_array for split_sum_funcN functions. @ sql/item_cmpfunc.cc Introduce Ref_ptr_array for split_sum_funcN functions. @ sql/item_cmpfunc.h Introduce Ref_ptr_array for split_sum_funcN functions. @ sql/item_func.cc Introduce Ref_ptr_array for split_sum_funcN functions. @ sql/item_func.h Introduce Ref_ptr_array for split_sum_funcN functions. @ sql/item_row.cc Introduce Ref_ptr_array for split_sum_funcN functions. @ sql/item_row.h Introduce Ref_ptr_array for split_sum_funcN functions. @ sql/item_strfunc.cc Introduce Ref_ptr_array for split_sum_funcN functions. @ sql/item_strfunc.h Introduce Ref_ptr_array for split_sum_funcN functions. @ sql/item_subselect.cc Don't use select_lex->ref_pointer_array, use the "slice" owned by the JOIN instance instead. @ sql/sql_array.h New, templatized, array class. @ sql/sql_derived.cc Remove ref_pointer_array from mysql_select() function signature. @ sql/sql_lex.cc In setup_ref_array(), add sanity check that that the size of ref_pointer_array does not change. @ sql/sql_parse.cc Remove ref_pointer_array from mysql_select() function signature. @ sql/sql_select.cc Changed several functions from xx_(.. Item ** ..) to xx_(.. Ref_ptr_array ..) Remove ref_pointer_array from mysql_select() function signature. @ sql/sql_select.h Document usage of ref_pointer_array. Change from Item** to Ref_ptr_array. Re-wrote setter functions. @ sql/sql_union.cc For UNION, the 'n_sum_items' are accumulated in the "global_parameters" select_lex. This number must be propagated to setup_ref_array() When preparing a 'fake_select_lex' we need to use global_parameters->order_list rather than fake_select_lex->order_list (see comments inside st_select_lex_unit::cleanup) @ sql/sql_yacc.yy Reset parsing_place when done parsing 'SHOW' and 'DESCRIBE' @ unittest/gunit/bounds_checked_array-t.cc New unit test. added: unittest/gunit/bounds_checked_array-t.cc modified: sql/item.cc sql/item.h sql/item_cmpfunc.cc sql/item_cmpfunc.h sql/item_func.cc sql/item_func.h sql/item_row.cc sql/item_row.h sql/item_strfunc.cc sql/item_strfunc.h sql/item_subselect.cc sql/item_sum.cc sql/sql_array.h sql/sql_base.cc sql/sql_base.h sql/sql_derived.cc sql/sql_do.cc sql/sql_insert.cc sql/sql_lex.cc sql/sql_lex.h sql/sql_load.cc sql/sql_parse.cc sql/sql_prepare.cc sql/sql_select.cc sql/sql_select.h sql/sql_union.cc sql/sql_update.cc sql/sql_yacc.yy unittest/gunit/CMakeLists.txt === modified file 'sql/item.cc' --- a/sql/item.cc 2011-06-06 12:49:55 +0000 +++ b/sql/item.cc 2011-06-23 10:08:08 +0000 @@ -1489,7 +1489,7 @@ public: thd->fatal_error() may be called if we are out of memory */ -void Item::split_sum_func2(THD *thd, Item **ref_pointer_array, +void Item::split_sum_func2(THD *thd, Ref_ptr_array ref_pointer_array, List &fields, Item **ref, bool skip_registered) { @@ -1526,7 +1526,7 @@ void Item::split_sum_func2(THD *thd, Ite ref_pointer_array[el]= real_itm; if (!(item_ref= new Item_aggregate_ref(&thd->lex->current_select->context, - ref_pointer_array + el, 0, name))) + &ref_pointer_array[el], 0, name))) return; // fatal_error is set if (type() == SUM_FUNC_ITEM) item_ref->depended_from= ((Item_sum *) this)->depended_from(); @@ -4345,7 +4345,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; @@ -6233,13 +6233,13 @@ Item *Item_field::update_value_transform type() != Item::TRIGGER_FIELD_ITEM) { List *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.h' --- a/sql/item.h 2011-06-10 15:29:04 +0000 +++ b/sql/item.h 2011-06-23 10:08:08 +0000 @@ -23,6 +23,7 @@ #include "unireg.h" // REQUIRED: for other includes #include "thr_malloc.h" /* sql_calloc */ #include "field.h" /* Derivation */ +#include "sql_array.h" class Protocol; struct TABLE_LIST; @@ -30,6 +31,7 @@ void item_init(void); /* Init item fun class Item_field; class user_var_entry; +typedef Bounds_checked_array Ref_ptr_array; static inline uint32 char_to_byte_length_safe(uint32 char_length_arg, uint32 mbmaxlen_arg) @@ -932,10 +934,11 @@ public: void print_item_w_name(String *, enum_query_type query_type); virtual void update_used_tables() {} - virtual void split_sum_func(THD *thd, Item **ref_pointer_array, + virtual void split_sum_func(THD *thd, Ref_ptr_array ref_pointer_array, List &fields) {} /* Called for items that really have to be split */ - void split_sum_func2(THD *thd, Item **ref_pointer_array, List &fields, + void split_sum_func2(THD *thd, Ref_ptr_array ref_pointer_array, + List &fields, Item **ref, bool skip_registered); virtual bool get_date(MYSQL_TIME *ltime,uint fuzzydate); virtual bool get_time(MYSQL_TIME *ltime); === modified file 'sql/item_cmpfunc.cc' --- a/sql/item_cmpfunc.cc 2011-06-09 06:22:39 +0000 +++ b/sql/item_cmpfunc.cc 2011-06-23 10:08:08 +0000 @@ -4591,7 +4591,7 @@ void Item_cond::traverse_cond(Cond_trave that have or refer (HAVING) to a SUM expression. */ -void Item_cond::split_sum_func(THD *thd, Item **ref_pointer_array, +void Item_cond::split_sum_func(THD *thd, Ref_ptr_array ref_pointer_array, List &fields) { List_iterator li(list); === modified file 'sql/item_cmpfunc.h' --- a/sql/item_cmpfunc.h 2011-06-09 06:22:39 +0000 +++ b/sql/item_cmpfunc.h 2011-06-23 10:08:08 +0000 @@ -1540,7 +1540,8 @@ public: table_map used_tables() const; void update_used_tables(); virtual void print(String *str, enum_query_type query_type); - void split_sum_func(THD *thd, Item **ref_pointer_array, List &fields); + void split_sum_func(THD *thd, Ref_ptr_array ref_pointer_array, + List &fields); friend int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves, Item **conds); void top_level_item() { abort_on_null=1; } === modified file 'sql/item_func.cc' --- a/sql/item_func.cc 2011-06-09 06:22:39 +0000 +++ b/sql/item_func.cc 2011-06-23 10:08:08 +0000 @@ -392,7 +392,7 @@ Item *Item_func::compile(Item_analyzer a See comments in Item_cmp_func::split_sum_func() */ -void Item_func::split_sum_func(THD *thd, Item **ref_pointer_array, +void Item_func::split_sum_func(THD *thd, Ref_ptr_array ref_pointer_array, List &fields) { Item **arg, **arg_end; === modified file 'sql/item_func.h' --- a/sql/item_func.h 2011-05-05 07:41:53 +0000 +++ b/sql/item_func.h 2011-06-23 10:08:08 +0000 @@ -135,7 +135,8 @@ public: void set_arguments(List &list); inline uint argument_count() const { return arg_count; } inline void remove_arguments() { arg_count=0; } - void split_sum_func(THD *thd, Item **ref_pointer_array, List &fields); + void split_sum_func(THD *thd, Ref_ptr_array ref_pointer_array, + List &fields); virtual void print(String *str, enum_query_type query_type); void print_op(String *str, enum_query_type query_type); void print_args(String *str, uint from, enum_query_type query_type); === modified file 'sql/item_row.cc' --- a/sql/item_row.cc 2011-06-09 06:22:39 +0000 +++ b/sql/item_row.cc 2011-06-23 10:08:08 +0000 @@ -1,4 +1,4 @@ -/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2000, 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 @@ -113,7 +113,7 @@ void Item_row::cleanup() } -void Item_row::split_sum_func(THD *thd, Item **ref_pointer_array, +void Item_row::split_sum_func(THD *thd, Ref_ptr_array ref_pointer_array, List &fields) { Item **arg, **arg_end; === modified file 'sql/item_row.h' --- a/sql/item_row.h 2010-10-15 10:32:50 +0000 +++ b/sql/item_row.h 2011-06-23 10:08:08 +0000 @@ -66,7 +66,8 @@ public: void fix_after_pullout(st_select_lex *parent_select, st_select_lex *removed_select, Item **ref); void cleanup(); - void split_sum_func(THD *thd, Item **ref_pointer_array, List &fields); + void split_sum_func(THD *thd, Ref_ptr_array ref_pointer_array, + List &fields); table_map used_tables() const { return used_tables_cache; }; bool const_item() const { return const_item_cache; }; enum Item_result result_type() const { return ROW_RESULT; } === modified file 'sql/item_strfunc.cc' --- a/sql/item_strfunc.cc 2011-06-09 06:22:39 +0000 +++ b/sql/item_strfunc.cc 2011-06-23 10:08:08 +0000 @@ -2540,7 +2540,8 @@ String *Item_func_elt::val_str(String *s } -void Item_func_make_set::split_sum_func(THD *thd, Item **ref_pointer_array, +void Item_func_make_set::split_sum_func(THD *thd, + Ref_ptr_array ref_pointer_array, List &fields) { item->split_sum_func2(thd, ref_pointer_array, fields, &item, TRUE); === modified file 'sql/item_strfunc.h' --- a/sql/item_strfunc.h 2011-04-15 09:04:21 +0000 +++ b/sql/item_strfunc.h 2011-06-23 10:08:08 +0000 @@ -556,7 +556,8 @@ public: item->check_cols(1) || Item_func::fix_fields(thd, ref)); } - void split_sum_func(THD *thd, Item **ref_pointer_array, List &fields); + void split_sum_func(THD *thd, Ref_ptr_array ref_pointer_array, + List &fields); void fix_length_and_dec(); void update_used_tables(); const char *func_name() const { return "make_set"; } === modified file 'sql/item_subselect.cc' --- a/sql/item_subselect.cc 2011-05-24 09:36:11 +0000 +++ b/sql/item_subselect.cc 2011-06-23 10:08:08 +0000 @@ -1,4 +1,4 @@ -/* Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2002, 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 @@ -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(join->ref_ptrs[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(join->ref_ptrs[0]); } if (upper_item) upper_item->set_sum_test(item); - *select_lex->ref_pointer_array= item; + join->ref_ptrs[0]= item; { List_iterator 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,7 @@ 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, + &join->ref_ptrs[0], (char *)"", this->full_name())); if (!abort_on_null && left_expr->maybe_null) @@ -1318,7 +1318,7 @@ Item_in_subselect::single_value_in_to_ex select_lex->item_list.push_back(new Item_int("Not_used", (longlong) 1, MY_INT64_NUM_DECIMAL_DIGITS)); - select_lex->ref_pointer_array[0]= select_lex->item_list.head(); + join->ref_ptrs[0]= select_lex->item_list.head(); item= func->create(expr, item); if (!abort_on_null && orig_item->maybe_null) @@ -1393,7 +1393,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, + &join->ref_ptrs[0], (char *)"", (char *)"")); if (!abort_on_null && left_expr->maybe_null) @@ -1553,13 +1553,12 @@ Item_in_subselect::row_value_in_to_exist Item *item_having_part2= 0; for (uint i= 0; i < cols_num; i++) { - DBUG_ASSERT((left_expr->fixed && - select_lex->ref_pointer_array[i]->fixed) || - (select_lex->ref_pointer_array[i]->type() == REF_ITEM && - ((Item_ref*)(select_lex->ref_pointer_array[i]))->ref_type() == - Item_ref::OUTER_REF)); - if (select_lex->ref_pointer_array[i]-> - check_cols(left_expr->element_index(i)->cols())) + Item *item_i= join->ref_ptrs[i]; + Item **pitem_i= &join->ref_ptrs[i]; + DBUG_ASSERT((left_expr->fixed && item_i->fixed) || + (item_i->type() == REF_ITEM && + ((Item_ref*)(item_i))->ref_type() == Item_ref::OUTER_REF)); + if (item_i-> check_cols(left_expr->element_index(i)->cols())) DBUG_RETURN(RES_ERROR); Item *item_eq= new Item_func_eq(new @@ -1570,14 +1569,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, + pitem_i, (char *)"", (char *)"") ); Item *item_isnull= new Item_func_isnull(new Item_ref(&select_lex->context, - select_lex->ref_pointer_array+i, + pitem_i, (char *)"", (char *)"") ); @@ -1592,8 +1591,7 @@ 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, + pitem_i, (char *)"", (char *)"")); if (!abort_on_null && left_expr->element_index(i)->maybe_null) @@ -1630,16 +1628,14 @@ Item_in_subselect::row_value_in_to_exist Item *where_item= 0; for (uint i= 0; i < cols_num; i++) { - Item *item, *item_isnull; - DBUG_ASSERT((left_expr->fixed && - select_lex->ref_pointer_array[i]->fixed) || - (select_lex->ref_pointer_array[i]->type() == REF_ITEM && - ((Item_ref*)(select_lex->ref_pointer_array[i]))->ref_type() == - Item_ref::OUTER_REF)); - if (select_lex->ref_pointer_array[i]-> - check_cols(left_expr->element_index(i)->cols())) + Item *item_i= join->ref_ptrs[i]; + Item **pitem_i= &join->ref_ptrs[i]; + DBUG_ASSERT((left_expr->fixed && item_i->fixed) || + (item_i->type() == REF_ITEM && + ((Item_ref*)(item_i))->ref_type() == Item_ref::OUTER_REF)); + if (item_i->check_cols(left_expr->element_index(i)->cols())) DBUG_RETURN(RES_ERROR); - item= + Item *item= new Item_func_eq(new Item_direct_ref(&select_lex->context, (*optimizer->get_cache())-> @@ -1648,8 +1644,7 @@ 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, + pitem_i, (char *)"", (char *)"") ); @@ -1659,16 +1654,15 @@ 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, + pitem_i, (char *)"", (char *)"")); - item_isnull= new + Item *item_isnull= new Item_func_isnull(new Item_direct_ref(&select_lex->context, - select_lex-> - ref_pointer_array+i, + pitem_i, (char *)"", (char *)"") ); @@ -2155,8 +2149,7 @@ bool subselect_single_select_engine::pre prepared= 1; SELECT_LEX *save_select= thd->lex->current_select; thd->lex->current_select= select_lex; - if (join->prepare(&select_lex->ref_pointer_array, - select_lex->table_list.first, + if (join->prepare(select_lex->table_list.first, select_lex->with_wild, select_lex->where, select_lex->order_list.elements + === modified file 'sql/item_sum.cc' --- a/sql/item_sum.cc 2011-06-09 06:22:39 +0000 +++ b/sql/item_sum.cc 2011-06-23 10:08:08 +0000 @@ -3308,7 +3308,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-06-23 10:08:08 +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 +/** + 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 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; } + + bool is_empty() 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-06-15 22:31:43 +0000 +++ b/sql/sql_base.cc 2011-06-23 10:08:08 +0000 @@ -8025,7 +8025,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 &fields, enum_mark_columns mark_used_columns, List *sum_func_list, bool allow_sum_func) { @@ -8055,8 +8055,11 @@ bool setup_fields(THD *thd, Item **ref_p TODO: remove it when (if) we made one list for allfields and ref_pointer_array */ - if (ref_pointer_array) - memset(ref_pointer_array, 0, sizeof(Item *) * fields.elements); + if (!ref_pointer_array.is_empty()) + { + 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 @@ -8074,7 +8077,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++)) { @@ -8087,8 +8090,11 @@ bool setup_fields(THD *thd, Item **ref_p DBUG_PRINT("info", ("thd->mark_used_columns: %d", thd->mark_used_columns)); DBUG_RETURN(TRUE); /* purecov: inspected */ } - if (ref) - *(ref++)= item; + if (!ref.is_empty()) + { + 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); === modified file 'sql/sql_base.h' --- a/sql/sql_base.h 2011-05-04 07:51:15 +0000 +++ b/sql/sql_base.h 2011-06-23 10:08:08 +0000 @@ -1,4 +1,4 @@ -/* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2006, 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 @@ -184,7 +184,7 @@ bool insert_fields(THD *thd, Name_resolu List_iterator *it, bool any_privileges); int setup_wild(THD *thd, TABLE_LIST *tables, List &fields, List *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, enum_mark_columns mark_used_columns, List *sum_func_list, bool allow_sum_func); bool fill_record(THD *thd, Field **field, List &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, enum_mark_columns mark_used_columns, List *sum_func_list, === modified file 'sql/sql_derived.cc' --- a/sql/sql_derived.cc 2011-06-09 08:58:41 +0000 +++ b/sql/sql_derived.cc 2011-06-23 10:08:08 +0000 @@ -286,7 +286,7 @@ bool mysql_derived_filling(THD *thd, LEX first_select->options&= ~OPTION_FOUND_ROWS; lex->current_select= first_select; - res= mysql_select(thd, &first_select->ref_pointer_array, + res= mysql_select(thd, first_select->table_list.first, first_select->with_wild, first_select->item_list, first_select->where, === modified file 'sql/sql_do.cc' --- a/sql/sql_do.cc 2010-07-27 15:01:56 +0000 +++ b/sql/sql_do.cc 2011-06-23 10:08:08 +0000 @@ -1,4 +1,4 @@ -/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2000, 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 @@ -28,7 +28,7 @@ bool mysql_do(THD *thd, List &valu List_iterator 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-06-10 16:57:01 +0000 +++ b/sql/sql_insert.cc 2011-06-23 10:08:08 +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) { @@ -3234,7 +3237,7 @@ select_insert::prepare(List &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)); @@ -3282,7 +3285,7 @@ select_insert::prepare(List &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-06-10 09:52:57 +0000 +++ b/sql/sql_lex.cc 2011-06-23 10:08:08 +0000 @@ -1759,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; @@ -2136,20 +2136,42 @@ ulong st_select_lex::get_table_join_opti bool st_select_lex::setup_ref_array(THD *thd, uint order_group_num) { - if (ref_pointer_array) - return 0; +#ifdef DBUG_OFF + if (!ref_pointer_array.is_empty()) + return false; +#endif + + // find_order_in_list() may need some extra space, so multiply by two. + order_group_num*= 2; /* 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; + const 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 this %p %4u : %4u %4u %4u %4u %4u %4u", + this, + n_elems, // : + n_sum_items, + n_child_sum_items, + item_list.elements, + select_n_having_items, + select_n_where_fields, + order_group_num)); + if (!ref_pointer_array.is_empty()) + { + DBUG_ASSERT(ref_pointer_array.size() == n_elems); + return false; + } + Item **array= static_cast(arena->alloc(sizeof(Item*) * n_elems)); + ref_pointer_array= Ref_ptr_array(array, n_elems); + + return array == NULL; } === modified file 'sql/sql_lex.h' --- a/sql/sql_lex.h 2011-06-10 09:52:57 +0000 +++ b/sql/sql_lex.h 2011-06-23 10:08:08 +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" #include "mem_root_array.h" /* YACC and LEX Definitions */ @@ -604,6 +605,7 @@ public: }; typedef class st_select_lex_unit SELECT_LEX_UNIT; +typedef Bounds_checked_array Ref_ptr_array; /* SELECT_LEX - store information of parsed SELECT statment @@ -666,8 +668,9 @@ public: SQL_I_List order_list; /* ORDER clause */ SQL_I_List *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 @@ -677,7 +680,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-06-10 16:57:01 +0000 +++ b/sql/sql_load.cc 2011-06-23 10:08:08 +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_parse.cc' --- a/sql/sql_parse.cc 2011-06-21 07:57:31 +0000 +++ b/sql/sql_parse.cc 2011-06-23 10:08:08 +0000 @@ -3151,7 +3151,7 @@ end_with_restore_list: if (!thd->is_fatal_error && (del_result= new multi_delete(aux_tables, lex->table_count))) { - res= mysql_select(thd, &select_lex->ref_pointer_array, + res= mysql_select(thd, select_lex->get_table_list(), select_lex->with_wild, select_lex->item_list, === modified file 'sql/sql_prepare.cc' --- a/sql/sql_prepare.cc 2011-06-10 16:57:01 +0000 +++ b/sql/sql_prepare.cc 2011-06-23 10:08:08 +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-06-10 16:57:01 +0000 +++ b/sql/sql_select.cc 2011-06-23 10:08:08 +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 &fields, List &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 &fields, List &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 &new_list1, List &new_list2, uint elements, List &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 &new_list1, List &new_list2, uint elements, List &items); @@ -384,7 +384,7 @@ bool handle_select(THD *thd, LEX *lex, s every PS/SP execution new, we will not need reset this flag if setup_tables_done_option changed for next rexecution */ - res= mysql_select(thd, &select_lex->ref_pointer_array, + res= mysql_select(thd, select_lex->table_list.first, select_lex->with_wild, select_lex->item_list, select_lex->where, @@ -460,7 +460,7 @@ bool handle_select(THD *thd, LEX *lex, s bool fix_inner_refs(THD *thd, List &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; @@ -477,7 +477,7 @@ fix_inner_refs(THD *thd, List &all existing one. The change will lead to less operations for copying fields, smaller temporary tables and less data passed through filesort. */ - if (ref_pointer_array && !ref->found_in_select_list) + if (!ref_pointer_array.is_empty() && !ref->found_in_select_list) { int el= all_fields.elements; ref_pointer_array[el]= item; @@ -487,7 +487,7 @@ fix_inner_refs(THD *thd, List &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 &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 &fields, @@ -600,8 +600,7 @@ inline int setup_without_group(THD *thd, 0 on success */ int -JOIN::prepare(Item ***rref_pointer_array, - TABLE_LIST *tables_init, +JOIN::prepare(TABLE_LIST *tables_init, uint wild_num, Item *conds_init, uint og_num, ORDER *order_init, ORDER *group_init, Item *having_init, @@ -647,18 +646,31 @@ 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, + /* + 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. + */ + DBUG_ASSERT(select_lex->parsing_place == NO_MATTER); + select_lex->parsing_place= NO_MATTER; + + if (setup_wild(thd, tables_list, fields_list, &all_fields, wild_num)) + DBUG_RETURN(-1); + if (select_lex->setup_ref_array(thd, og_num)) + DBUG_RETURN(-1); + + ref_ptrs= ref_ptr_array_slice(0); + + if (setup_fields(thd, ref_ptrs, fields_list, MARK_COLUMNS_READ, + &all_fields, 1)) + DBUG_RETURN(-1); + if (setup_without_group(thd, ref_ptrs, 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; - if (having) { nesting_map save_allow_sum_func= thd->lex->allow_sum_func; @@ -712,15 +724,15 @@ 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_ptrs, all_fields); } if (!real_order) order= NULL; } if (having && having->with_sum_func) - having->split_sum_func2(thd, ref_pointer_array, all_fields, - &having, TRUE); + having->split_sum_func2(thd, ref_ptrs, + all_fields, &having, TRUE); if (select_lex->inner_sum_func_list) { Item_sum *end=select_lex->inner_sum_func_list; @@ -728,13 +740,13 @@ 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_ptrs, all_fields, item_sum->ref_by, FALSE); } while (item_sum != end); } if (select_lex->inner_refs_list.elements && - fix_inner_refs(thd, all_fields, select_lex, ref_pointer_array, + fix_inner_refs(thd, all_fields, select_lex, ref_ptrs, group_list)) DBUG_RETURN(-1); @@ -753,9 +765,9 @@ JOIN::prepare(Item ***rref_pointer_array { Item_field *field= new Item_field(thd, *(Item_field**)ord->item); int el= all_fields.elements; - ref_pointer_array[el]= field; + ref_ptrs[el]= field; all_fields.push_front(field); - ord->item= ref_pointer_array + el; + ord->item= &ref_ptrs[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; @@ -2247,7 +2258,7 @@ JOIN::optimize() if (order) skip_sort_order= test_if_skip_sort_order(tab, order, m_select_limit, 1, &tab->table->keys_in_use_for_order_by); - if ((group_list=create_distinct_group(thd, select_lex->ref_pointer_array, + if ((group_list=create_distinct_group(thd, ref_ptrs, order, fields_list, all_fields, &all_order_fields_used))) { @@ -2750,7 +2761,7 @@ void JOIN::reset() filesort_free_buffers(exec_tmp_table2,0); } clear_sj_tmp_tables(this); - if (items0) + if (!items0.is_empty()) set_items_ref_array(items0); if (join_tab_save) @@ -3032,9 +3043,9 @@ JOIN::exec() /* Change sum_fields reference to calculated fields in tmp_table */ if (curr_join != this) curr_join->all_fields= *curr_all_fields; - if (!items1) + if (items1.is_empty()) { - items1= items0 + all_fields.elements; + items1= ref_ptr_array_slice(2); if (sort_and_group || curr_tmp_table->group || tmp_table_param.precomputed_group_by) { @@ -3197,9 +3208,9 @@ JOIN::exec() curr_join->join_tab[0].table= 0; // Table is freed // No sum funcs anymore - if (!items2) + if (items2.is_empty()) { - items2= items1 + all_fields.elements; + items2= ref_ptr_array_slice(3); if (change_to_use_tmp_fields(thd, items2, tmp_fields_list2, tmp_all_fields2, fields_list.elements, tmp_all_fields1)) @@ -3252,11 +3263,11 @@ JOIN::exec() { DBUG_VOID_RETURN; } - if (!items3) + if (items3.is_empty()) { - if (!items0) + if (items0.is_empty()) init_items_ref_array(); - items3= ref_pointer_array + (all_fields.elements*4); + items3= ref_ptr_array_slice(4); setup_copy_fields(thd, &curr_join->tmp_table_param, items3, tmp_fields_list3, tmp_all_fields3, curr_fields_list->elements, *curr_all_fields); @@ -3486,7 +3497,7 @@ JOIN::exec() We also need to do this when we have temp table(s). Otherwise we would not be able to print the query correctly. */ - if (items0 && (thd->lex->describe & DESCRIBE_EXTENDED) && + if (!items0.is_empty() && (thd->lex->describe & DESCRIBE_EXTENDED) && (select_lex->linkage == DERIVED_TABLE_TYPE || exec_tmp_table1 || exec_tmp_table2)) set_items_ref_array(items0); @@ -3568,7 +3579,6 @@ void JOIN::cleanup_item_list(List An entry point to single-unit select (a select without UNION). @param thd thread handler - @param rref_pointer_array a reference to ref_pointer_array of the top-level select_lex for this query @param tables list of all tables used in this query. The tables have been pre-opened. @@ -3609,7 +3619,7 @@ void JOIN::cleanup_item_list(List */ bool -mysql_select(THD *thd, Item ***rref_pointer_array, +mysql_select(THD *thd, TABLE_LIST *tables, uint wild_num, List &fields, Item *conds, uint og_num, ORDER *order, ORDER *group, Item *having, ORDER *proc_param, ulonglong select_options, @@ -3649,7 +3659,7 @@ mysql_select(THD *thd, Item ***rref_poin } else { - err= join->prepare(rref_pointer_array, tables, wild_num, + err= join->prepare(tables, wild_num, conds, og_num, order, group, having, proc_param, select_lex, unit); if (err) @@ -3667,7 +3677,7 @@ mysql_select(THD *thd, Item ***rref_poin DBUG_RETURN(TRUE); /* purecov: inspected */ THD_STAGE_INFO(thd, stage_init); thd->used_tables=0; // Updated by setup_fields - err= join->prepare(rref_pointer_array, tables, wild_num, + err= join->prepare(tables, wild_num, conds, og_num, order, group, having, proc_param, select_lex, unit); if (err) @@ -21129,7 +21139,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 &fields, List &all_fields, bool is_group_field) { @@ -21153,7 +21163,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; @@ -21214,7 +21224,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; } @@ -21272,7 +21282,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; } @@ -21284,7 +21294,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 &fields, List &all_fields, ORDER *order) { thd->where="order clause"; @@ -21325,7 +21335,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 &fields, List &all_fields, ORDER *order, bool *hidden_group_fields) { @@ -21456,13 +21466,14 @@ setup_new_fields(THD *thd, List &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 &fields, List &all_fields, bool *all_order_by_fields_used) { List_iterator 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; @@ -21516,7 +21527,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 { @@ -21525,14 +21536,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; @@ -21847,7 +21858,7 @@ int test_if_item_cache_changed(List &res_selected_fields, List &res_all_fields, uint elements, List &all_fields) { @@ -22128,7 +22139,7 @@ bool JOIN::make_sum_func_list(List */ 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 &res_selected_fields, List &res_all_fields, uint elements, List &all_fields) @@ -22219,7 +22230,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 &res_selected_fields, List &res_all_fields, uint elements, List &all_fields) @@ -22594,15 +22605,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) + - ref_pointer_array_size) - * send_group_parts ))) - return 1; - - rollup.fields= (List*) (rollup.null_items + send_group_parts); - rollup.ref_pointer_arrays= (Item***) (rollup.fields + send_group_parts); + Item_null_result **null_items= + static_cast(thd->alloc(sizeof(Item*)*send_group_parts)); + + rollup.null_items= Item_null_array(null_items, send_group_parts); + rollup.ref_pointer_arrays= + static_cast + (thd->alloc((sizeof(Ref_ptr_array) + + all_fields.elements * sizeof(Item*)) * send_group_parts)); + rollup.fields= + static_cast*>(thd->alloc(sizeof(List) * send_group_parts)); + + if (!null_items || !rollup.ref_pointer_arrays || !rollup.fields) + return true; + ref_array= (Item**) (rollup.ref_pointer_arrays+send_group_parts); /* @@ -22614,7 +22630,7 @@ bool JOIN::rollup_init() rollup.null_items[i]= new (thd->mem_root) Item_null_result(); List *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++) @@ -22760,11 +22776,11 @@ bool JOIN::rollup_make_fields(List bool real_fields= 0; Item *item; List_iterator 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; + uint ref_array_ix= fields_arg.elements-1; /* Remember where the sum functions ends for the previous level */ sum_funcs_end[pos+1]= *func; @@ -22781,7 +22797,7 @@ bool JOIN::rollup_make_fields(List if (item == first_field) { real_fields= 1; // End of hidden fields - ref_array= ref_array_start; + ref_array_ix= 0; } if (item->type() == Item::SUM_FUNC_ITEM && !item->const_item() && @@ -22825,15 +22841,15 @@ bool JOIN::rollup_make_fields(List } } } - *ref_array= item; + ref_array_start[ref_array_ix]= item; if (real_fields) { (void) new_it++; // Point to next item new_it.replace(item); // Replace previous - ref_array++; + ref_array_ix++; } else - ref_array--; + ref_array_ix--; } } sum_funcs_end[0]= *func; // Point to last function @@ -22865,9 +22881,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_ptrs, rollup.ref_pointer_arrays[i]); if ((!having || having->val_int())) { if (send_records < unit->select_limit_cnt && do_send_rows && @@ -22877,7 +22891,7 @@ int JOIN::rollup_send_data(uint idx) } } /* Restore ref_pointer_array */ - set_items_ref_array(current_ref_pointer_array); + set_items_ref_array(current_ref_ptrs); return 0; } @@ -22907,9 +22921,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_ptrs, rollup.ref_pointer_arrays[i]); if ((!having || having->val_int())) { int write_error; @@ -22932,7 +22944,7 @@ int JOIN::rollup_write_data(uint idx, TA } } /* Restore ref_pointer_array */ - set_items_ref_array(current_ref_pointer_array); + set_items_ref_array(current_ref_ptrs); return 0; } @@ -23573,7 +23585,7 @@ bool mysql_explain_union(THD *thd, SELEC { thd->lex->current_select= first; unit->set_limit(unit->global_parameters); - res= mysql_select(thd, &first->ref_pointer_array, + res= mysql_select(thd, first->table_list.first, first->with_wild, first->item_list, first->where, === modified file 'sql/sql_select.h' --- a/sql/sql_select.h 2011-05-26 15:20:09 +0000 +++ b/sql/sql_select.h 2011-06-23 10:08:08 +0000 @@ -1598,12 +1598,14 @@ typedef struct st_position : public Sql_ } POSITION; +typedef Bounds_checked_array 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 *fields; } ROLLUP; @@ -1879,10 +1881,19 @@ public: FirstMatch strategy. */ JOIN_TAB *return_tab; - Item **ref_pointer_array; ///ref_pointer_array contains five "slices" of the same length: + |========|========|========|========|========| + ref_ptrs items0 items1 items2 items3 + */ + Ref_ptr_array ref_ptrs; + // 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_ptrs after overwriting it. + Ref_ptr_array current_ref_ptrs; + 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_ptrs.reset(); + items0.reset(); + items1.reset(); + items2.reset(); + items3.reset(); zero_result_cause= 0; optimized= 0; cond_equal= 0; @@ -1979,7 +1993,7 @@ public: first_select= sub_select; } - int prepare(Item ***rref_pointer_array, TABLE_LIST *tables, uint wind_num, + int prepare(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,16 +2008,42 @@ public: bool make_sum_func_list(List &all_fields, List &send_fields, bool before_group_by, bool recompute= FALSE); - inline void set_items_ref_array(Item **ptr) + /// Initialzes a slice, see comments for ref_ptrs above. + Ref_ptr_array ref_ptr_array_slice(size_t slice_num) + { + size_t slice_sz= select_lex->ref_pointer_array.size() / 5U; + DBUG_ASSERT(select_lex->ref_pointer_array.size() % 5 == 0); + DBUG_ASSERT(slice_num < 5U); + return Ref_ptr_array(&select_lex->ref_pointer_array[slice_num * slice_sz], + slice_sz); + } + + /** + Overwrites one slice with the contents of another slice. + In the normal case, dst and src have the same size(). + However: the rollup slices may have smaller size than slice_sz. + */ + 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()); + } + + /// Overwrites 'ref_ptrs' and remembers the the source as 'current'. + void set_items_ref_array(Ref_ptr_array src_arr) { - memcpy((char*) ref_pointer_array, (char*) ptr, ref_pointer_array_size); - current_ref_pointer_array= ptr; + copy_ref_ptr_array(ref_ptrs, src_arr); + current_ref_ptrs= src_arr; } - inline void init_items_ref_array() + + /// Initializes 'items0' and remembers that it is 'current'. + void init_items_ref_array() { - items0= ref_pointer_array + all_fields.elements; - memcpy(items0, ref_pointer_array, ref_pointer_array_size); - current_ref_pointer_array= items0; + items0= ref_ptr_array_slice(1); + copy_ref_ptr_array(items0, ref_ptrs); + current_ref_ptrs= items0; } bool rollup_init(); @@ -2074,7 +2114,7 @@ void free_tmp_table(THD *thd, TABLE *ent void count_field_types(SELECT_LEX *select_lex, TMP_TABLE_PARAM *param, List &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 &new_list1, List &new_list2, uint elements, List &fields); void copy_fields(TMP_TABLE_PARAM *param); @@ -2263,17 +2303,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 &fields, List &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 &fields, List &all_fields, ORDER *order, bool *hidden_group_fields); bool fix_inner_refs(THD *thd, List &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, TABLE_LIST *tables, uint wild_num, List &list, Item *conds, uint og_num, ORDER *order, ORDER *group, Item *having, ORDER *proc_param, ulonglong select_type, === modified file 'sql/sql_union.cc' --- a/sql/sql_union.cc 2011-05-26 15:20:09 +0000 +++ b/sql/sql_union.cc 2011-06-23 10:08:08 +0000 @@ -1,4 +1,4 @@ -/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2000, 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 @@ -10,9 +10,8 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ - + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02111-1307 USA */ /* UNION of select's @@ -270,8 +269,7 @@ bool st_select_lex_unit::prepare(THD *th can_skip_order_by= is_union_select && !(sl->braces && sl->explicit_limit); - saved_error= join->prepare(&sl->ref_pointer_array, - sl->table_list.first, + saved_error= join->prepare(sl->table_list.first, sl->with_wild, sl->where, (can_skip_order_by ? 0 : @@ -419,23 +417,38 @@ bool st_select_lex_unit::prepare(THD *th init_prepare_fake_select_lex(thd); /* Should be done only once (the only item_list per statement) */ DBUG_ASSERT(fake_select_lex->join == 0); - if (!(fake_select_lex->join= new JOIN(thd, item_list, thd->variables.option_bits, - result))) + if (!(fake_select_lex->join= + new JOIN(thd, item_list, thd->variables.option_bits, result))) { fake_select_lex->table_list.empty(); DBUG_RETURN(TRUE); } + + /* + Fake st_select_lex should have item list for correct ref_array + allocation. + */ fake_select_lex->item_list= item_list; - thd_arg->lex->current_select= fake_select_lex; + thd_arg->lex->current_select= fake_select_lex; + + /* + We need to add up n_sum_items in order to make the correct + allocation in setup_ref_array(). + */ + fake_select_lex->n_child_sum_items+= global_parameters->n_sum_items; + saved_error= fake_select_lex->join-> - prepare(&fake_select_lex->ref_pointer_array, - fake_select_lex->table_list.first, - 0, 0, - fake_select_lex->order_list.elements, - fake_select_lex->order_list.first, - NULL, NULL, NULL, - fake_select_lex, this); + prepare(fake_select_lex->table_list.first, // tables_init + 0, // wild_num + 0, // conds_init + global_parameters->order_list.elements, // og_num + global_parameters->order_list.first, // order + NULL, // group_init + NULL, // having_init + NULL, // proc_param_init + fake_select_lex, // select_lex_arg + this); // unit_arg fake_select_lex->table_list.empty(); } } @@ -607,18 +620,35 @@ bool st_select_lex_unit::exec() fake_select_lex->join->no_const_tables= true; /* - Fake st_select_lex should have item list for correctref_array + Fake st_select_lex should have item list for correct ref_array allocation. */ fake_select_lex->item_list= item_list; - saved_error= mysql_select(thd, &fake_select_lex->ref_pointer_array, - &result_table_list, - 0, item_list, NULL, - global_parameters->order_list.elements, - global_parameters->order_list.first, - NULL, NULL, NULL, - fake_select_lex->options | SELECT_NO_UNLOCK, - result, this, fake_select_lex); + + /* + We need to add up n_sum_items in order to make the correct + allocation in setup_ref_array(). + Don't add more sum_items if we have already done JOIN::prepare + for this (with a different join object) + */ + if (fake_select_lex->ref_pointer_array.is_empty()) + fake_select_lex->n_child_sum_items+= global_parameters->n_sum_items; + + saved_error= + mysql_select(thd, + &result_table_list, // tables + 0, // wild_num + item_list, // fields + NULL, // conds + global_parameters->order_list.elements, // og_num + global_parameters->order_list.first, // order + NULL, // group + NULL, // having + NULL, // proc_param + fake_select_lex->options | SELECT_NO_UNLOCK, + result, // result + this, // unit + fake_select_lex); // select_lex } else { @@ -634,7 +664,7 @@ bool st_select_lex_unit::exec() to reset them back, we re-do all of the actions (yes it is ugly): */ join->init(thd, item_list, fake_select_lex->options, result); - saved_error= mysql_select(thd, &fake_select_lex->ref_pointer_array, + saved_error= mysql_select(thd, &result_table_list, 0, item_list, NULL, global_parameters->order_list.elements, === modified file 'sql/sql_update.cc' --- a/sql/sql_update.cc 2011-06-16 06:30:16 +0000 +++ b/sql/sql_update.cc 2011-06-23 10:08:08 +0000 @@ -1,4 +1,4 @@ -/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2000, 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 @@ -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 */ @@ -1158,7 +1159,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) @@ -1347,7 +1349,7 @@ bool mysql_multi_update(THD *thd, List total_list; - res= mysql_select(thd, &select_lex->ref_pointer_array, + res= mysql_select(thd, table_list, select_lex->with_wild, total_list, conds, 0, (ORDER *) NULL, (ORDER *)NULL, (Item *) NULL, @@ -1432,7 +1434,8 @@ int multi_update::prepare(List &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 'sql/sql_yacc.yy' --- a/sql/sql_yacc.yy 2011-06-09 18:18:22 +0000 +++ b/sql/sql_yacc.yy 2011-06-23 10:08:08 +0000 @@ -11033,7 +11033,10 @@ show: memset(&lex->create_info, 0, sizeof(lex->create_info)); } show_param - {} + { + LEX *lex= Lex; + lex->current_select->parsing_place= NO_MATTER; + } ; show_param: @@ -11375,7 +11378,11 @@ describe: if (prepare_schema_table(YYTHD, lex, $2, SCH_COLUMNS)) MYSQL_YYABORT; } - opt_describe_column {} + opt_describe_column + { + LEX *lex= Lex; + lex->current_select->parsing_place= NO_MATTER; + } | describe_command opt_extended_describe { Lex->describe|= DESCRIBE_NORMAL; } select === modified file 'unittest/gunit/CMakeLists.txt' --- a/unittest/gunit/CMakeLists.txt 2011-05-18 08:29:46 +0000 +++ b/unittest/gunit/CMakeLists.txt 2011-06-23 10:08:08 +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-06-23 10:08:08 +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 + +#include "sql_array.h" + +namespace { + +typedef Bounds_checked_array 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()); + EXPECT_TRUE(int_array.is_empty()); + 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()); + EXPECT_FALSE(int_array.is_empty()); + int_array.reset(); + int *pi= NULL; + EXPECT_EQ(pi, int_array.array()); + EXPECT_TRUE(int_array.is_empty()); +} + + +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 --===============5565954311287343554== MIME-Version: 1.0 Content-Type: text/bzr-bundle; charset="us-ascii"; name="bzr/tor.didriksen@stripped" Content-Transfer-Encoding: 7bit Content-Disposition: inline # Bazaar merge directive format 2 (Bazaar 0.90) # revision_id: tor.didriksen@stripped\ # qwsnq8un1w1zfg26 # target_branch: file:///export/home/didrik/repo/trunk-bug11765255-\ # arraycheck/ # testament_sha1: 2a59a47dc7cf924f223c053998f55b4c4f2f4c5e # timestamp: 2011-06-23 12:08:22 +0200 # source_branch: bzr+ssh://bk-internal.mysql.com/bzrroot/server/mysql-\ # trunk/ # base_revision_id: vasil.dimov@stripped\ # cdjl7c0kg3z4b8vo # # Begin bundle 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 cIajPyJFaG5mjjGf/i7kinChITHSU6w= --===============5565954311287343554==--