diff options
author | unknown <bell@sanja.is.com.ua> | 2004-04-03 11:13:51 +0300 |
---|---|---|
committer | unknown <bell@sanja.is.com.ua> | 2004-04-03 11:13:51 +0300 |
commit | 8c8dffb60d23bf3a5666dcc251d2f15cb913d541 (patch) | |
tree | c9f3e9d74cc127bb1de122f2c0d31fab4719caac /sql | |
parent | a62a5fc9c0cef8d9f1ae685b43b6dc539d6fcfc8 (diff) | |
download | mariadb-git-8c8dffb60d23bf3a5666dcc251d2f15cb913d541.tar.gz |
fixed brocken of client_test
fixed aggregate functions in PS (BUG#3360)
mysql-test/r/union.result:
4.1 more correct error
sql/item_cmpfunc.h:
and_conds do not make fix fields
sql/item_sum.cc:
storing/restoring argument of aggregate function for prepared statements
restoring order list of group_concat for safety
sql/item_sum.h:
storing/restoring argument of aggregate function for prepared statements
layout fix
sql/mysql_priv.h:
just declaration
sql/sql_base.cc:
fix_fields() have to be called with temporary memory pool active
sql/sql_parse.cc:
removed hack with item pointer storing
sql/sql_prepare.cc:
debug output added
removed hack with item pointer storing
sql/sql_select.cc:
fix_fields now should be called separately
sql/sql_union.cc:
removed wrong merged check from 4.0 (4.1 have its own protection)
sql/table.h:
removed hack with item pointer storing
tests/client_test.c:
new test fo PS
Diffstat (limited to 'sql')
-rw-r--r-- | sql/item_cmpfunc.h | 7 | ||||
-rw-r--r-- | sql/item_sum.cc | 82 | ||||
-rw-r--r-- | sql/item_sum.h | 30 | ||||
-rw-r--r-- | sql/mysql_priv.h | 1 | ||||
-rw-r--r-- | sql/sql_base.cc | 44 | ||||
-rw-r--r-- | sql/sql_parse.cc | 7 | ||||
-rw-r--r-- | sql/sql_prepare.cc | 12 | ||||
-rw-r--r-- | sql/sql_select.cc | 4 | ||||
-rw-r--r-- | sql/sql_union.cc | 13 | ||||
-rw-r--r-- | sql/table.h | 1 |
10 files changed, 124 insertions, 77 deletions
diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index cbd1e9feffa..d654bec4f4e 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -991,14 +991,11 @@ public: /* Some usefull inline functions */ -inline Item *and_conds(THD *thd, Item *a, Item *b, TABLE_LIST *tables) +inline Item *and_conds(Item *a, Item *b) { if (!b) return a; if (!a) return b; - Item *cond= new Item_cond_and(a,b); - if (cond) - cond->fix_fields(thd, tables, &cond); - return cond; + return new Item_cond_and(a, b); } Item *and_expressions(Item *a, Item *b, Item **org_item); diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 113ef0e1922..26b859c8aba 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -24,8 +24,8 @@ #include "mysql_priv.h" Item_sum::Item_sum(List<Item> &list) + :args_copy(0), arg_count(list.elements) { - arg_count=list.elements; if ((args=(Item**) sql_alloc(sizeof(Item*)*arg_count))) { uint i=0; @@ -43,18 +43,51 @@ Item_sum::Item_sum(List<Item> &list) // Constructor used in processing select with temporary tebles Item_sum::Item_sum(THD *thd, Item_sum *item): - Item_result_field(thd, item), quick_group(item->quick_group) + Item_result_field(thd, item), arg_count(item->arg_count), + quick_group(item->quick_group) { - arg_count= item->arg_count; if (arg_count <= 2) args=tmp_args; else - if (!(args=(Item**) sql_alloc(sizeof(Item*)*arg_count))) + if (!(args= (Item**) thd->alloc(sizeof(Item*)*arg_count))) return; - for (uint i= 0; i < arg_count; i++) - args[i]= item->args[i]; + memcpy(args, item->args, sizeof(Item*)*arg_count); + if (item->args_copy != 0) + save_args(thd); + else + args_copy= 0; +} + + +/* + Save copy of arguments if we are prepare prepared statement + (arguments can be rewritten in get_tmp_table_item()) + + SYNOPSIS + Item_sum::save_args_for_prepared_statements() + thd - thread handler + + RETURN + 0 - OK + 1 - Error +*/ +bool Item_sum::save_args_for_prepared_statements(THD *thd) +{ + if (thd->current_statement) + return save_args(thd->current_statement); + return 0; } + +bool Item_sum::save_args(Statement* stmt) +{ + if (!(args_copy= (Item**) stmt->alloc(sizeof(Item*)*arg_count))) + return 1; + memcpy(args_copy, args, sizeof(Item*)*arg_count); + return 0; +} + + void Item_sum::mark_as_sum_func() { current_thd->lex->current_select->with_sum_func= 1; @@ -62,6 +95,17 @@ void Item_sum::mark_as_sum_func() } +void Item_sum::cleanup() +{ + DBUG_ENTER("Item_sum::cleanup"); + Item_result_field::cleanup(); + if (args_copy != 0) + memcpy(args, args_copy, sizeof(Item*)*arg_count); + result_field=0; + DBUG_VOID_RETURN; +} + + void Item_sum::make_field(Send_field *tmp_field) { if (args[0]->type() == Item::FIELD_ITEM && keep_field_type()) @@ -165,6 +209,10 @@ bool Item_sum_num::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) { DBUG_ASSERT(fixed == 0); + + if (save_args_for_prepared_statements(thd)) + return 1; + if (!thd->allow_sum_func) { my_error(ER_INVALID_GROUP_FUNC_USE,MYF(0)); @@ -195,6 +243,10 @@ bool Item_sum_hybrid::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) { DBUG_ASSERT(fixed == 0); + + if (save_args_for_prepared_statements(thd)) + return 1; + Item *item= args[0]; if (!thd->allow_sum_func) { @@ -1131,15 +1183,6 @@ void Item_sum_count_distinct::cleanup() } -bool Item_sum_count_distinct::fix_fields(THD *thd, TABLE_LIST *tables, - Item **ref) -{ - DBUG_ASSERT(fixed == 0); - if (Item_sum_num::fix_fields(thd, tables, ref)) - return 1; - return 0; -} - /* This is used by rollup to create a separate usable copy of the function */ void Item_sum_count_distinct::make_unique() @@ -1705,6 +1748,11 @@ void Item_func_group_concat::cleanup() { DBUG_ENTER("Item_func_group_concat::cleanup"); Item_sum::cleanup(); + + /* fix order list */ + for (uint i= 0; i < arg_count_order ; i++) + order[i]->item= &order[i]->item_ptr; + /* Free table and tree if they belong to this item (if item have not pointer to original item from which was made copy => it own its objects ) @@ -1821,6 +1869,10 @@ bool Item_func_group_concat::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) { DBUG_ASSERT(fixed == 0); + + if (save_args_for_prepared_statements(thd)) + return 1; + uint i; /* for loop variable */ if (!thd->allow_sum_func) diff --git a/sql/item_sum.h b/sql/item_sum.h index 1c31f1a9b70..8a51a7e5a7c 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -32,40 +32,32 @@ public: UDF_SUM_FUNC, GROUP_CONCAT_FUNC }; - Item **args,*tmp_args[2]; + Item **args, *tmp_args[2]; + Item **args_copy; /* copy of arguments for PS */ uint arg_count; bool quick_group; /* If incremental update of fields */ void mark_as_sum_func(); - Item_sum() : arg_count(0),quick_group(1) + Item_sum() :args_copy(0), arg_count(0), quick_group(1) { mark_as_sum_func(); } - Item_sum(Item *a) :quick_group(1) + Item_sum(Item *a) + :args(tmp_args), args_copy(0), arg_count(1), quick_group(1) { - arg_count=1; - args=tmp_args; args[0]=a; mark_as_sum_func(); } - Item_sum( Item *a, Item *b ) :quick_group(1) + Item_sum( Item *a, Item *b ) + :args(tmp_args), args_copy(0), arg_count(2), quick_group(1) { - arg_count=2; - args=tmp_args; args[0]=a; args[1]=b; mark_as_sum_func(); } Item_sum(List<Item> &list); //Copy constructor, need to perform subselects with temporary tables Item_sum(THD *thd, Item_sum *item); - void cleanup() - { - DBUG_ENTER("Item_sum::cleanup"); - Item_result_field::cleanup(); - result_field=0; - DBUG_VOID_RETURN; - } - + void cleanup(); enum Type type() const { return SUM_FUNC_ITEM; } virtual enum Sumfunctype sum_func () const=0; inline bool reset() { clear(); return add(); }; @@ -100,6 +92,8 @@ public: virtual bool setup(THD *thd) {return 0;} virtual void make_unique() {} Item *get_tmp_table_item(THD *thd); + bool save_args_for_prepared_statements(THD *); + bool save_args(Statement* stmt); bool walk (Item_processor processor, byte *argument); }; @@ -190,7 +184,6 @@ class Item_sum_count_distinct :public Item_sum_int { TABLE *table; table_map used_table_cache; - bool fix_fields(THD *thd, TABLE_LIST *tables, Item **ref); uint32 *field_lengths; TMP_TABLE_PARAM *tmp_table_param; TREE tree_base; @@ -236,7 +229,8 @@ class Item_sum_count_distinct :public Item_sum_int Item_sum_count_distinct(THD *thd, Item_sum_count_distinct *item) :Item_sum_int(thd, item), table(item->table), used_table_cache(item->used_table_cache), - field_lengths(item->field_lengths), tmp_table_param(item->tmp_table_param), + field_lengths(item->field_lengths), + tmp_table_param(item->tmp_table_param), tree(item->tree), original(item), key_length(item->key_length), max_elements_in_tree(item->max_elements_in_tree), rec_offset(item->rec_offset), use_tree(item->use_tree), diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index a979ef137ae..3189cc5c88e 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -285,6 +285,7 @@ void debug_sync_point(const char* lock_name, uint lock_timeout); struct st_table; class THD; +class Statement; /* Struct to handle simple linked lists */ diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 7fc97a14ffd..38e01546a4a 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -2403,15 +2403,13 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds) { if (table->on_expr) { - if (stmt) - thd->set_n_backup_item_arena(stmt, &backup); /* Make a join an a expression */ thd->where="on clause"; if (!table->on_expr->fixed && table->on_expr->fix_fields(thd, tables, &table->on_expr) || table->on_expr->check_cols(1)) - goto err; + DBUG_RETURN(1); thd->lex->current_select->cond_count++; /* @@ -2423,12 +2421,16 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds) !(specialflag & SPECIAL_NO_NEW_FUNC))) { table->outer_join= 0; - if (!(*conds= and_conds(thd, *conds, table->on_expr, tables))) - goto err; + if (stmt) + thd->set_n_backup_item_arena(stmt, &backup); + *conds= and_conds(*conds, table->on_expr); table->on_expr=0; + if (stmt) + thd->restore_backup_item_arena(stmt, &backup); + if ((*conds) && !(*conds)->fixed && + (*conds)->fix_fields(thd, tables, conds)) + DBUG_RETURN(1); } - if (stmt) - thd->restore_backup_item_arena(stmt, &backup); } if (table->natural_join) { @@ -2467,20 +2469,28 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds) if (!table->outer_join) // Not left join { - if (!(*conds= and_conds(thd, *conds, cond_and, tables)) || - (*conds && !(*conds)->fixed && - (*conds)->fix_fields(thd, tables, conds))) - goto err; + *conds= and_conds(*conds, cond_and); + // fix_fields() should be made with temporary memory pool + if (stmt) + thd->restore_backup_item_arena(stmt, &backup); + if (*conds && !(*conds)->fixed) + { + if ((*conds)->fix_fields(thd, tables, conds)) + DBUG_RETURN(1); + } } else { - table->on_expr= and_conds(thd, table->on_expr, cond_and, tables); - if (table->on_expr && !table->on_expr->fixed && - table->on_expr->fix_fields(thd, tables, &table->on_expr)) - goto err; + table->on_expr= and_conds(table->on_expr, cond_and); + // fix_fields() should be made with temporary memory pool + if (stmt) + thd->restore_backup_item_arena(stmt, &backup); + if (table->on_expr && !table->on_expr->fixed) + { + if (table->on_expr->fix_fields(thd, tables, &table->on_expr)) + DBUG_RETURN(1); + } } - if (stmt) - thd->restore_backup_item_arena(stmt, &backup); } } diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 68ef195cdc4..b3d3af61d6d 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -4389,11 +4389,10 @@ bool add_to_list(THD *thd, SQL_LIST &list,Item *item,bool asc) ORDER *order; Item **item_ptr; DBUG_ENTER("add_to_list"); - if (!(order = (ORDER *) thd->alloc(sizeof(ORDER)+sizeof(Item*)))) + if (!(order = (ORDER *) thd->alloc(sizeof(ORDER)))) DBUG_RETURN(1); - item_ptr = (Item**) (order+1); - *item_ptr=item; - order->item= item_ptr; + order->item_ptr= item; + order->item= &order->item_ptr; order->asc = asc; order->free_me=0; order->used=0; diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 94fef4cafdc..bdbdcb28d3a 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -987,6 +987,8 @@ void mysql_stmt_prepare(THD *thd, char *packet, uint packet_length) int error; DBUG_ENTER("mysql_stmt_prepare"); + DBUG_PRINT("pquery", ("%s", packet)); + if (stmt == 0) { send_error(thd, ER_OUT_OF_RESOURCES); @@ -1076,11 +1078,11 @@ static void reset_stmt_for_execute(Prepared_statement *stmt) DBUG_ASSERT(sl->join == 0); ORDER *order; /* Fix GROUP list */ - for (order=(ORDER *)sl->group_list.first ; order ; order=order->next) - order->item= (Item **)(order+1); + for (order= (ORDER *)sl->group_list.first; order; order= order->next) + order->item= &order->item_ptr; /* Fix ORDER list */ - for (order=(ORDER *)sl->order_list.first ; order ; order=order->next) - order->item= (Item **)(order+1); + for (order= (ORDER *)sl->order_list.first; order; order= order->next) + order->item= &order->item_ptr; /* TODO: When the new table structure is ready, then have a status bit @@ -1131,6 +1133,8 @@ void mysql_stmt_execute(THD *thd, char *packet, uint packet_length) if (!(stmt= find_prepared_statement(thd, stmt_id, "execute", SEND_ERROR))) DBUG_VOID_RETURN; + DBUG_PRINT("equery:", ("%s", stmt->query)); + /* Check if we got an error when sending long data */ if (stmt->get_longdata_error) { diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 63fe8d77f1a..598b53fe7dd 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -3536,7 +3536,9 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond) { /* Join with outer join condition */ COND *orig_cond=sel->cond; - sel->cond=and_conds(join->thd, sel->cond, tab->on_expr, 0); + sel->cond= and_conds(sel->cond, tab->on_expr); + if (sel->cond && !sel->cond->fixed) + sel->cond->fix_fields(join->thd, 0, &sel->cond); if (sel->test_quick_select(join->thd, tab->keys, used_tables & ~ current_map, (join->select_options & diff --git a/sql/sql_union.cc b/sql/sql_union.cc index 907250b11c8..7265a99d6e5 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -208,19 +208,6 @@ int st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, } } - for (tmp_order= (ORDER*) global_parameters->order_list.first; - tmp_order ; - tmp_order= tmp_order->next) - { - Item *item= *tmp_order->item; - if (((item->type() == Item::FIELD_ITEM) && - ((class Item_field*) item)->table_name)) - { - my_error(ER_BAD_FIELD_ERROR,MYF(0),item->full_name(),"ORDER BY"); - DBUG_RETURN(-1); - } - } - item_list.empty(); // it is not single select if (first_select->next_select()) diff --git a/sql/table.h b/sql/table.h index 039e3ded9f3..d128038d15a 100644 --- a/sql/table.h +++ b/sql/table.h @@ -26,6 +26,7 @@ class st_select_lex_unit; typedef struct st_order { struct st_order *next; Item **item; /* Point at item in select fields */ + Item *item_ptr; /* Storage for initial item */ bool asc; /* true if ascending */ bool free_me; /* true if item isn't shared */ bool in_field_list; /* true if in select field list */ |