From 8c8dffb60d23bf3a5666dcc251d2f15cb913d541 Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 3 Apr 2004 11:13:51 +0300 Subject: [PATCH 1/3] 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 --- mysql-test/r/union.result | 2 +- sql/item_cmpfunc.h | 7 +--- sql/item_sum.cc | 82 ++++++++++++++++++++++++++++++++------- sql/item_sum.h | 30 ++++++-------- sql/mysql_priv.h | 1 + sql/sql_base.cc | 44 +++++++++++++-------- sql/sql_parse.cc | 7 ++-- sql/sql_prepare.cc | 12 ++++-- sql/sql_select.cc | 4 +- sql/sql_union.cc | 13 ------- sql/table.h | 1 + tests/client_test.c | 47 ++++++++++++++++++++++ 12 files changed, 172 insertions(+), 78 deletions(-) diff --git a/mysql-test/r/union.result b/mysql-test/r/union.result index 8e288f9725f..91d53ce21d0 100644 --- a/mysql-test/r/union.result +++ b/mysql-test/r/union.result @@ -435,7 +435,7 @@ drop temporary table t1; create table t1 select a from t1 union select a from t2; ERROR HY000: You can't specify target table 't1' for update in FROM clause select a from t1 union select a from t2 order by t2.a; -ERROR 42S22: Unknown column 't2.a' in 'ORDER BY' +ERROR 42S02: Unknown table 't2' in order clause drop table t1,t2; select length(version()) > 1 as `*` UNION select 2; * 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 &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 &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 &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 */ diff --git a/tests/client_test.c b/tests/client_test.c index 8cd8efdcce9..49856d6d60d 100644 --- a/tests/client_test.c +++ b/tests/client_test.c @@ -8531,6 +8531,52 @@ static void test_on() } +static void test_selecttmp() +{ + MYSQL_STMT *stmt; + int rc, i; + const char *query= "select a,(select count(distinct t1.b) as sum from t1,t2 where t1.a=t2.a and t2.b > 0 and t1.a <= t3.b group by t1.a order by sum limit 1) from t3"; + + myheader("test_select_tmp"); + + rc = mysql_query(mysql, "DROP TABLE IF EXISTS t1,t2,t3"); + myquery(rc); + + rc= mysql_query(mysql,"CREATE TABLE t1 (a int , b int);"); + myquery(rc); + + rc= mysql_query(mysql,"create table t2 (a int, b int);"); + myquery(rc); + + rc= mysql_query(mysql,"create table t3 (a int, b int);"); + myquery(rc); + + rc= mysql_query(mysql, + "insert into t1 values (0,100),(1,2), (1,3), (2,2), (2,7), \ +(2,-1), (3,10);"); + myquery(rc); + rc= mysql_query(mysql, + "insert into t2 values (0,0), (1,1), (2,1), (3,1), (4,1);"); + myquery(rc); + rc= mysql_query(mysql, + "insert into t3 values (3,3), (2,2), (1,1);"); + myquery(rc); + + stmt= mysql_prepare(mysql, query, strlen(query)); + mystmt_init(stmt); + for (i= 0; i < 3; i++) + { + rc= mysql_execute(stmt); + mystmt(stmt, rc); + assert(3 == my_process_stmt_result(stmt)); + } + mysql_stmt_close(stmt); + + rc= mysql_query(mysql, "DROP TABLE t1,t2,t3"); + myquery(rc); +} + + /* Read and parse arguments and MySQL options from my.cnf */ @@ -8791,6 +8837,7 @@ int main(int argc, char **argv) test_union(); /* test union with prepared statements */ test_bug3117(); /* BUG#3117: LAST_INSERT_ID() */ test_on(); /* ... join ... on(), BUG#2794 */ + test_selecttmp(); /* temporary table used in select execution */ end_time= time((time_t *)0); From e65aed9cbd61f5fc3c7cd396d60a9d6cb1d9b218 Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 3 Apr 2004 17:23:41 +0300 Subject: [PATCH 2/3] for Item_param we have to have value set instead of fave item fixed (BUG#3353) fixed outer joins test of different joins included sql/item.cc: for Item_param we have to have value set instead of fave item fixed sql/sql_base.cc: fixed PS with outer joins tests/client_test.c: test of different types of joins --- sql/item.cc | 8 ++++---- sql/sql_base.cc | 3 +++ tests/client_test.c | 40 +++++++++++++++++++++++++++------------- 3 files changed, 34 insertions(+), 17 deletions(-) diff --git a/sql/item.cc b/sql/item.cc index 8da4990942c..1efed78799a 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -713,7 +713,7 @@ bool Item_param::get_time(TIME *res) double Item_param::val() { - DBUG_ASSERT(fixed == 1); + DBUG_ASSERT(value_is_set == 1); int err; switch (item_result_type) { case STRING_RESULT: @@ -729,7 +729,7 @@ double Item_param::val() longlong Item_param::val_int() { - DBUG_ASSERT(fixed == 1); + DBUG_ASSERT(value_is_set == 1); int err; switch (item_result_type) { case STRING_RESULT: @@ -746,7 +746,7 @@ longlong Item_param::val_int() String *Item_param::val_str(String* str) { - DBUG_ASSERT(fixed == 1); + DBUG_ASSERT(value_is_set == 1); switch (item_result_type) { case INT_RESULT: str->set(int_value, &my_charset_bin); @@ -766,7 +766,7 @@ String *Item_param::val_str(String* str) String *Item_param::query_val_str(String* str) { - DBUG_ASSERT(fixed == 1); + DBUG_ASSERT(value_is_set == 1); switch (item_result_type) { case INT_RESULT: case REAL_RESULT: diff --git a/sql/sql_base.cc b/sql/sql_base.cc index bea77c72bc0..48ba810c1a3 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -2469,6 +2469,9 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds) } thd->lex->current_select->cond_count+= cond_and->list.elements; + // to prevent natural join processing during PS re-execution + table->natural_join= 0; + if (!table->outer_join) // Not left join { *conds= and_conds(*conds, cond_and); diff --git a/tests/client_test.c b/tests/client_test.c index 49856d6d60d..0d4d84b02c7 100644 --- a/tests/client_test.c +++ b/tests/client_test.c @@ -8495,13 +8495,21 @@ static void test_bug3117() } -static void test_on() +static void jest_join() { MYSQL_STMT *stmt; - int rc, i; - const char *query= "SELECT * FROM t2 join t1 on (t1.a=t2.a)"; + int rc, i, j; + const char *query[]={"SELECT * FROM t2 join t1 on (t1.a=t2.a)", + "SELECT * FROM t2 natural join t1", + "SELECT * FROM t2 join t1 using(a)", + "SELECT * FROM t2 left join t1 on(t1.a=t2.a)", + "SELECT * FROM t2 natural left join t1", + "SELECT * FROM t2 left join t1 using(a)", + "SELECT * FROM t2 right join t1 on(t1.a=t2.a)", + "SELECT * FROM t2 natural right join t1", + "SELECT * FROM t2 right join t1 using(a)"}; - myheader("test_on"); + myheader("jest_join"); rc = mysql_query(mysql, "DROP TABLE IF EXISTS t1,t2"); myquery(rc); @@ -8513,18 +8521,24 @@ static void test_on() "insert into t1 values (1,1), (2, 2), (3,3), (4,4), (5,5);"); myquery(rc); - rc= mysql_query(mysql,"create table t2 select * from t1;"); + rc= mysql_query(mysql,"CREATE TABLE t2 (a int , c int);"); myquery(rc); - stmt= mysql_prepare(mysql, query, strlen(query)); - mystmt_init(stmt); - for (i= 0; i < 3; i++) + rc= mysql_query(mysql, + "insert into t2 values (1,1), (2, 2), (3,3), (4,4), (5,5);"); + + for (j= 0; j < 9; j++) { - rc= mysql_execute(stmt); - mystmt(stmt, rc); - assert(5 == my_process_stmt_result(stmt)); + stmt= mysql_prepare(mysql, query[j], strlen(query[j])); + mystmt_init(stmt); + for (i= 0; i < 3; i++) + { + rc= mysql_execute(stmt); + mystmt(stmt, rc); + assert(5 == my_process_stmt_result(stmt)); + } + mysql_stmt_close(stmt); } - mysql_stmt_close(stmt); rc= mysql_query(mysql, "DROP TABLE t1,t2"); myquery(rc); @@ -8836,7 +8850,7 @@ int main(int argc, char **argv) Item_field -> Item_ref */ test_union(); /* test union with prepared statements */ test_bug3117(); /* BUG#3117: LAST_INSERT_ID() */ - test_on(); /* ... join ... on(), BUG#2794 */ + jest_join(); /* different kinds of join, BUG#2794 */ test_selecttmp(); /* temporary table used in select execution */ From 3c01162f0e642d535ec5a8912f77f9f4a96ad8d9 Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 4 Apr 2004 03:05:44 +0300 Subject: [PATCH 3/3] removed old way to prevent using stack tables for caching Items in PS fixed error code in union test mysql-test/t/union.test: right code worr 4.1 error sql/log_event.cc: assign non-cachable for Item status for all stack tables for safety sql/repl_failsafe.cc: assign non-cachable for Item status for all stack tables for safety sql/slave.cc: assign non-cachable for Item status for all stack tables for safety sql/sql_acl.cc: assign non-cachable for Item status for all stack tables for safety sql/sql_base.cc: assign non-cachable for Item status for all stack tables for safety non-cachable status processing sql/sql_cache.cc: assign non-cachable for Item status for all stack tables for safety sql/sql_class.cc: removed ald way to prevent using stack tables for caching Items in PS sql/sql_class.h: removed old way to prevent using stack tables for caching Items in PS sql/sql_help.cc: assign non-cachable for Item status for all stack tables for safety sql/sql_insert.cc: assign non-cachable for Item status for all stack tables for safety removed old way to prevent using stack tables for caching Items in PS sql/table.h: non-cachable for Item status for tables --- mysql-test/t/union.test | 2 +- sql/log_event.cc | 1 + sql/repl_failsafe.cc | 1 + sql/slave.cc | 1 + sql/sql_acl.cc | 15 +++++++++++++++ sql/sql_base.cc | 8 +++++++- sql/sql_cache.cc | 1 + sql/sql_class.cc | 1 - sql/sql_class.h | 6 ------ sql/sql_help.cc | 8 ++++---- sql/sql_insert.cc | 7 ++----- sql/table.h | 1 + 12 files changed, 34 insertions(+), 18 deletions(-) diff --git a/mysql-test/t/union.test b/mysql-test/t/union.test index eaa1415d41f..9866b867427 100644 --- a/mysql-test/t/union.test +++ b/mysql-test/t/union.test @@ -251,7 +251,7 @@ create temporary table t1 select a from t1 union select a from t2; drop temporary table t1; --error 1093 create table t1 select a from t1 union select a from t2; ---error 1054 +--error 1109 select a from t1 union select a from t2 order by t2.a; drop table t1,t2; diff --git a/sql/log_event.cc b/sql/log_event.cc index 742cf6a1a82..cd0324a72ca 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -1698,6 +1698,7 @@ int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli, tables.alias = tables.real_name = (char*)table_name; tables.lock_type = TL_WRITE; tables.updating= 1; + tables.non_cachable_table= 1; // just safety for table on stack // the table will be opened in mysql_load if (table_rules_on && !tables_ok(thd, &tables)) { diff --git a/sql/repl_failsafe.cc b/sql/repl_failsafe.cc index 284444090bb..f8b0cf31621 100644 --- a/sql/repl_failsafe.cc +++ b/sql/repl_failsafe.cc @@ -736,6 +736,7 @@ static int fetch_db_tables(THD *thd, MYSQL *mysql, const char *db, table.db= (char*) db; table.real_name= (char*) table_name; table.updating= 1; + table.non_cachable_table= 1; // just safety for table on stack if (!tables_ok(thd, &table)) continue; } diff --git a/sql/slave.cc b/sql/slave.cc index be9a5795233..d8bb9359727 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -1216,6 +1216,7 @@ static int create_table_from_dump(THD* thd, MYSQL *mysql, const char* db, bzero((char*) &tables,sizeof(tables)); tables.db = (char*)db; tables.alias= tables.real_name= (char*)table_name; + tables.non_cachable_table= 1; // just safety for table on stack /* Drop the table if 'overwrite' is true */ if (overwrite && mysql_rm_table(thd,&tables,1,0)) /* drop if exists */ { diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 3add540f9a9..ee049b619ea 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -172,6 +172,9 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables) tables[1].next=tables+2; tables[0].lock_type=tables[1].lock_type=tables[2].lock_type=TL_READ; tables[0].db=tables[1].db=tables[2].db=thd->db; + // just safety for table on stack + tables[0].non_cachable_table= tables[1].non_cachable_table= + tables[2].non_cachable_table= 1; uint counter; if (open_tables(thd, tables, &counter)) @@ -1325,6 +1328,7 @@ static bool update_user_table(THD *thd, const char *host, const char *user, bzero((char*) &tables,sizeof(tables)); tables.alias=tables.real_name=(char*) "user"; tables.db=(char*) "mysql"; + tables.non_cachable_table= 1; // just safety for table on stack #ifdef HAVE_REPLICATION /* GRANT and REVOKE are applied the slave in/exclusion rules as they are @@ -1382,6 +1386,7 @@ static bool test_if_create_new_users(THD *thd) bzero((char*) &tl,sizeof(tl)); tl.db= (char*) "mysql"; tl.real_name= (char*) "user"; + tl.non_cachable_table= 1; // just safety for table on stack db_access=acl_get(thd->host, thd->ip, thd->priv_user, tl.db, 0); if (!(db_access & INSERT_ACL)) @@ -2233,6 +2238,9 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list, ? tables+2 : 0); tables[0].lock_type=tables[1].lock_type=tables[2].lock_type=TL_WRITE; tables[0].db=tables[1].db=tables[2].db=(char*) "mysql"; + // just safety for table on stack + tables[0].non_cachable_table= tables[1].non_cachable_table= + tables[2].non_cachable_table= 1; #ifdef HAVE_REPLICATION /* @@ -2407,6 +2415,8 @@ int mysql_grant(THD *thd, const char *db, List &list, tables[0].lock_type=tables[1].lock_type=TL_WRITE; tables[0].db=tables[1].db=(char*) "mysql"; tables[0].table=tables[1].table=0; + // just safety for table on stack + tables[0].non_cachable_table= tables[1].non_cachable_table= 1; #ifdef HAVE_REPLICATION /* @@ -2526,6 +2536,8 @@ my_bool grant_init(THD *org_thd) tables[0].next=tables+1; tables[0].lock_type=tables[1].lock_type=TL_READ; tables[0].db=tables[1].db=thd->db; + // just safety for table on stack + tables[0].non_cachable_table= tables[1].non_cachable_table= 1; uint counter; if (open_tables(thd, tables, &counter)) @@ -3363,6 +3375,9 @@ int open_grant_tables(THD *thd, TABLE_LIST *tables) tables->lock_type= (tables+1)->lock_type= (tables+2)->lock_type= (tables+3)->lock_type= TL_WRITE; tables->db= (tables+1)->db= (tables+2)->db= (tables+3)->db=(char*) "mysql"; + // just safety for table on stack + tables[0].non_cachable_table= tables[1].non_cachable_table= + tables[2].non_cachable_table= tables[3].non_cachable_table=1; #ifdef HAVE_REPLICATION /* diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 48ba810c1a3..f70feb8dc9c 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -156,6 +156,7 @@ OPEN_TABLE_LIST *list_open_tables(THD *thd, const char *wild) table_list.db= (char*) entry->table_cache_key; table_list.real_name= entry->real_name; table_list.grant.privilege=0; + table_list.non_cachable_table= 1; // just safety for table on stack if (check_table_access(thd,SELECT_ACL | EXTRA_ACL,&table_list,1)) continue; /* need to check if we haven't already listed it */ @@ -1332,6 +1333,7 @@ static int open_unireg_entry(THD *thd, TABLE *entry, const char *db, bzero((char*) &table_list, sizeof(table_list)); // just for safe table_list.db=(char*) db; table_list.real_name=(char*) name; + table_list.non_cachable_table= 1; // just safety for table on stack safe_mutex_assert_owner(&LOCK_open); if ((error=lock_table_name(thd,&table_list))) @@ -1886,7 +1888,7 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables, char name_buff[NAME_LEN+1]; - if (!thd->no_table_fix_fields_cache && item->cached_table) + if (item->cached_table) { /* This shortcut is used by prepared statements. We assuming that @@ -1939,6 +1941,8 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables, if (find) { (*where)= item->cached_table= tables; + if (tables->non_cachable_table) + item->cached_table= 0; if (find == WRONG_GRANT) return (Field*) 0; if (db || !thd->where) @@ -1998,6 +2002,8 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables, if (field == WRONG_GRANT) return (Field*) 0; (*where)= item->cached_table= tables; + if (tables->non_cachable_table) + item->cached_table= 0; if (found) { if (!thd->where) // Returns first found diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index 39061a6501b..985dac7d613 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -1022,6 +1022,7 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length) Query_cache_table *table = block_table->parent; table_list.db = table->db(); table_list.alias= table_list.real_name= table->table(); + table_list.non_cachable_table= 1; // just safety for table on stack #ifndef NO_EMBEDDED_ACCESS_CHECKS if (check_table_access(thd,SELECT_ACL,&table_list,1)) { diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 44d35f5c165..1b4c8bec416 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -84,7 +84,6 @@ extern "C" void free_user_var(user_var_entry *entry) ****************************************************************************/ THD::THD():user_time(0), current_statement(0), is_fatal_error(0), - no_table_fix_fields_cache(0), last_insert_id_used(0), insert_id_used(0), rand_used(0), in_lock_tables(0), global_read_lock(0), bootstrap(0) diff --git a/sql/sql_class.h b/sql/sql_class.h index 20983074eed..aa526d5e474 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -787,12 +787,6 @@ public: bool charset_is_system_charset, charset_is_collation_connection; bool slow_command; - /* - Used in prepared statement to prevent using table/field cache in - Item_idend, bacuse it can point on removed table. - */ - bool no_table_fix_fields_cache; - /* If we do a purge of binary logs, log index info of the threads that are currently reading it needs to be adjusted. To do that diff --git a/sql/sql_help.cc b/sql/sql_help.cc index 980ed4047f3..29dab51839d 100644 --- a/sql/sql_help.cc +++ b/sql/sql_help.cc @@ -659,20 +659,20 @@ int mysqld_help(THD *thd, const char *mask) bzero((gptr)tables,sizeof(tables)); tables[0].alias= tables[0].real_name= (char*) "help_topic"; tables[0].lock_type= TL_READ; - tables[0].db= (char*) "mysql"; tables[0].next= &tables[1]; tables[1].alias= tables[1].real_name= (char*) "help_category"; tables[1].lock_type= TL_READ; - tables[1].db= (char*) "mysql"; tables[1].next= &tables[2]; tables[2].alias= tables[2].real_name= (char*) "help_relation"; tables[2].lock_type= TL_READ; - tables[2].db= (char*) "mysql"; tables[2].next= &tables[3]; tables[3].alias= tables[3].real_name= (char*) "help_keyword"; tables[3].lock_type= TL_READ; - tables[3].db= (char*) "mysql"; tables[3].next= 0; + tables[0].db= tables[1].db= tables[2].db= tables[3].db= (char*) "mysql"; + // just safety for table on stack + tables[0].non_cachable_table= tables[1].non_cachable_table= + tables[2].non_cachable_table= tables[3].non_cachable_table= 1; List topics_list, categories_list, subcategories_list; String name, description, example; diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index f2764a6f1c0..3f943b3a4c6 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -82,16 +82,13 @@ check_insert_fields(THD *thd,TABLE *table,List &fields, table_list.real_name= table_list.alias= table->table_name; table_list.table=table; table_list.grant=table->grant; + table_list.non_cachable_table= 1; thd->dupp_field=0; - thd->no_table_fix_fields_cache= 1; if (setup_tables(&table_list) || setup_fields(thd, 0, &table_list,fields,1,0,0)) - { - thd->no_table_fix_fields_cache= 0; return -1; - } - thd->no_table_fix_fields_cache= 0; + if (thd->dupp_field) { my_error(ER_FIELD_SPECIFIED_TWICE,MYF(0), thd->dupp_field->field_name); diff --git a/sql/table.h b/sql/table.h index 7761f610f21..0a4cd48c79e 100644 --- a/sql/table.h +++ b/sql/table.h @@ -193,6 +193,7 @@ typedef struct st_table_list bool updating; /* for replicate-do/ignore table */ bool force_index; /* Prefer index over table scan */ bool ignore_leaves; /* Preload only non-leaf nodes */ + bool non_cachable_table; /* stop PS caching */ } TABLE_LIST; typedef struct st_changed_table_list