diff options
author | monty@mysql.com <> | 2004-10-26 19:30:01 +0300 |
---|---|---|
committer | monty@mysql.com <> | 2004-10-26 19:30:01 +0300 |
commit | 6fbc869d183b777576670f37edaa293f16c1fa68 (patch) | |
tree | 355a805ce6da2de5e852c4f9b8372d612070cd6d /sql | |
parent | 8b6839e6446fde2931583d4d8b74bb531add5062 (diff) | |
download | mariadb-git-6fbc869d183b777576670f37edaa293f16c1fa68.tar.gz |
A lot of fixes for prepared statements (PS):
New mysqltest that can run mysqltest with PS
Added support for ZEROFILL in PS
Fixed crash when one called mysql_stmt_store_result() without a preceding mysql_stmt_bind_result()
Updated test cases to support --ps-protocol
(Some tests are still run using old protocol)
Fixed crash in PS when using SELECT * FROM t1 NATURAL JOIN t2...
Fixed crash in PS when using sub queries
Create table didn't signal when table was created. This could cause a "DROP TABLE created_table" in another thread to wait "forever"
Fixed wrong permissions check in PS and multi-table updates (one could get permission denied for legal quries)
Fix for PS and SELECT ... PROCEDURE
Reset all warnings when executing a new PS query
group_concat(...ORDER BY) didn't work with PS
Fixed problem with test suite when not using innodb
Diffstat (limited to 'sql')
-rw-r--r-- | sql/field.cc | 4 | ||||
-rw-r--r-- | sql/item_cmpfunc.cc | 8 | ||||
-rw-r--r-- | sql/item_subselect.cc | 4 | ||||
-rw-r--r-- | sql/item_sum.cc | 36 | ||||
-rw-r--r-- | sql/item_sum.h | 1 | ||||
-rw-r--r-- | sql/protocol.cc | 7 | ||||
-rw-r--r-- | sql/set_var.cc | 3 | ||||
-rw-r--r-- | sql/sql_base.cc | 63 | ||||
-rw-r--r-- | sql/sql_class.cc | 3 | ||||
-rw-r--r-- | sql/sql_error.cc | 3 | ||||
-rw-r--r-- | sql/sql_insert.cc | 8 | ||||
-rw-r--r-- | sql/sql_lex.h | 2 | ||||
-rw-r--r-- | sql/sql_parse.cc | 21 | ||||
-rw-r--r-- | sql/sql_prepare.cc | 11 | ||||
-rw-r--r-- | sql/sql_union.cc | 9 |
15 files changed, 110 insertions, 73 deletions
diff --git a/sql/field.cc b/sql/field.cc index aae507cd0ec..55351ad9a87 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -3508,8 +3508,8 @@ bool Field_time::send_binary(Protocol *protocol) { TIME tm; Field_time::get_time(&tm); - tm.day= tm.hour/3600; // Move hours to days - tm.hour-= tm.day*3600; + tm.day= tm.hour/24; // Move hours to days + tm.hour-= tm.day*24; return protocol->store_time(&tm); } diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index f6730c84979..c9396aaa67c 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -1760,6 +1760,7 @@ void Item_func_in::fix_length_and_dec() { Item **arg, **arg_end; uint const_itm= 1; + THD *thd= current_thd; agg_cmp_type(&cmp_type, args, arg_count); @@ -1797,6 +1798,9 @@ void Item_func_in::fix_length_and_dec() Conversion is possible: All IN arguments are constants. */ + Item_arena *arena= thd->current_arena, backup; + if (arena->is_stmt_prepare()) + thd->set_n_backup_item_arena(arena, &backup); for (arg= args+1, arg_end= args+arg_count; arg < arg_end; arg++) { if (!my_charset_same(cmp_collation.collation, @@ -1812,6 +1816,8 @@ void Item_func_in::fix_length_and_dec() arg[0]= conv; } } + if (arena->is_stmt_prepare()) + thd->restore_backup_item_arena(arena, &backup); } } @@ -1839,7 +1845,7 @@ void Item_func_in::fix_length_and_dec() DBUG_ASSERT(0); return; } - if (array && !(current_thd->is_fatal_error)) // If not EOM + if (array && !(thd->is_fatal_error)) // If not EOM { uint j=0; for (uint i=1 ; i < arg_count ; i++) diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index dfcc5789ea4..a869e2d24fb 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -365,9 +365,9 @@ Item_singlerow_subselect::select_transformer(JOIN *join) if (!(substitution= new Item_func_if(cond, substitution, new Item_null()))) goto err; + if (arena->is_stmt_prepare()) + thd->restore_backup_item_arena(arena, &backup); } - if (arena->is_stmt_prepare()) - thd->restore_backup_item_arena(arena, &backup); return RES_REDUCE; } return RES_OK; diff --git a/sql/item_sum.cc b/sql/item_sum.cc index fc3cf9d4aa9..e6c96dd6a9a 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -1693,8 +1693,7 @@ Item_func_group_concat::Item_func_group_concat(bool is_distinct, SQL_LIST *is_order, String *is_separator) :Item_sum(), tmp_table_param(0), max_elements_in_tree(0), warning(0), - warning_available(0), key_length(0), - tree_mode(0), distinct(is_distinct), warning_for_row(0), + key_length(0), tree_mode(0), distinct(is_distinct), warning_for_row(0), separator(is_separator), tree(&tree_base), table(0), order(0), tables_list(0), arg_count_order(0), arg_count_field(0), @@ -1752,7 +1751,6 @@ Item_func_group_concat::Item_func_group_concat(THD *thd, tmp_table_param(item->tmp_table_param), max_elements_in_tree(item->max_elements_in_tree), warning(item->warning), - warning_available(item->warning_available), key_length(item->key_length), tree_mode(item->tree_mode), distinct(item->distinct), @@ -1779,10 +1777,6 @@ 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 ) @@ -1802,6 +1796,13 @@ void Item_func_group_concat::cleanup() tree_mode= 0; delete_tree(tree); } + if (warning) + { + char warn_buff[MYSQL_ERRMSG_SIZE]; + sprintf(warn_buff, ER(ER_CUT_VALUE_GROUP_CONCAT), count_cut_values); + warning->set_msg(thd, warn_buff); + warning= 0; + } } DBUG_VOID_RETURN; } @@ -1809,19 +1810,6 @@ void Item_func_group_concat::cleanup() Item_func_group_concat::~Item_func_group_concat() { - /* - 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 ) - */ - if (!original) - { - if (warning_available) - { - char warn_buff[MYSQL_ERRMSG_SIZE]; - sprintf(warn_buff, ER(ER_CUT_VALUE_GROUP_CONCAT), count_cut_values); - warning->set_msg(current_thd, warn_buff); - } - } } @@ -2072,12 +2060,10 @@ String* Item_func_group_concat::val_str(String* str) DBUG_ASSERT(fixed == 1); if (null_value) return 0; - if (count_cut_values && !warning_available) - { - warning_available= TRUE; + if (count_cut_values && !warning) warning= push_warning(item_thd, MYSQL_ERROR::WARN_LEVEL_WARN, - ER_CUT_VALUE_GROUP_CONCAT, NULL); - } + ER_CUT_VALUE_GROUP_CONCAT, + ER(ER_CUT_VALUE_GROUP_CONCAT)); if (result.length()) return &result; if (tree_mode) diff --git a/sql/item_sum.h b/sql/item_sum.h index 2e85ba87468..5aa0d37190b 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -674,7 +674,6 @@ class Item_func_group_concat : public Item_sum TMP_TABLE_PARAM *tmp_table_param; uint max_elements_in_tree; MYSQL_ERROR *warning; - bool warning_available; uint key_length; bool tree_mode; bool distinct; diff --git a/sql/protocol.cc b/sql/protocol.cc index 060dc14be10..887177c0a19 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -1141,6 +1141,13 @@ bool Protocol_prep::store_time(TIME *tm) field_pos++; pos= buff+1; pos[0]= tm->neg ? 1 : 0; + if (tm->hour >= 24) + { + /* Fix if we come from Item::send */ + uint days= tm->hour/24; + tm->hour-= days*24; + tm->day+= days; + } int4store(pos+1, tm->day); pos[5]= (uchar) tm->hour; pos[6]= (uchar) tm->minute; diff --git a/sql/set_var.cc b/sql/set_var.cc index b5e479b9985..b16676de80e 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -2959,7 +2959,8 @@ void sys_var_thd_table_type::warn_deprecated(THD *thd) { push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DEPRECATED_SYNTAX, - ER(ER_WARN_DEPRECATED_SYNTAX), "table_type", "storage_engine"); + ER(ER_WARN_DEPRECATED_SYNTAX), "table_type", + "storage_engine"); } void sys_var_thd_table_type::set_default(THD *thd, enum_var_type type) diff --git a/sql/sql_base.cc b/sql/sql_base.cc index cd7b643e146..9313f8e2c1b 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -363,6 +363,7 @@ bool close_cached_tables(THD *thd, bool if_wait_for_refresh, void close_thread_tables(THD *thd, bool lock_in_use, bool skip_derived) { + bool found_old_table; DBUG_ENTER("close_thread_tables"); if (thd->derived_tables && !skip_derived) @@ -385,8 +386,6 @@ void close_thread_tables(THD *thd, bool lock_in_use, bool skip_derived) DBUG_VOID_RETURN; // LOCK TABLES in use } - bool found_old_table=0; - if (thd->lock) { mysql_unlock_tables(thd, thd->lock); @@ -399,6 +398,7 @@ void close_thread_tables(THD *thd, bool lock_in_use, bool skip_derived) DBUG_PRINT("info", ("thd->open_tables=%p", thd->open_tables)); + found_old_table= 0; while (thd->open_tables) found_old_table|=close_thread_table(thd, &thd->open_tables); thd->some_tables_deleted=0; @@ -2305,22 +2305,26 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields, List<Item> *sum_func_list, uint wild_num) { + bool is_stmt_prepare; + DBUG_ENTER("setup_wild"); if (!wild_num) - return 0; + DBUG_RETURN(0); + Item_arena *arena= thd->current_arena, backup; /* If we are in preparing prepared statement phase then we have change temporary mem_root to statement mem root to save changes of SELECT list */ - if (arena->is_stmt_prepare()) + if ((is_stmt_prepare= arena->is_stmt_prepare())) thd->set_n_backup_item_arena(arena, &backup); reg2 Item *item; List_iterator<Item> it(fields); while ( wild_num && (item= it++)) { - if (item->type() == Item::FIELD_ITEM && ((Item_field*) item)->field_name && + if (item->type() == Item::FIELD_ITEM && + ((Item_field*) item)->field_name && ((Item_field*) item)->field_name[0] == '*' && !((Item_field*) item)->field) { @@ -2339,9 +2343,9 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields, else if (insert_fields(thd,tables,((Item_field*) item)->db_name, ((Item_field*) item)->table_name, &it)) { - if (arena->is_stmt_prepare()) + if (is_stmt_prepare) thd->restore_backup_item_arena(arena, &backup); - return (-1); + DBUG_RETURN(-1); } if (sum_func_list) { @@ -2355,9 +2359,9 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields, wild_num--; } } - if (arena->is_stmt_prepare()) - thd->restore_backup_item_arena(arena, &backup); - return 0; + if (is_stmt_prepare) + thd->restore_backup_item_arena(arena, &backup); + DBUG_RETURN(0); } /**************************************************************************** @@ -2398,19 +2402,20 @@ int setup_fields(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables, SYNOPSIS setup_tables() - tables - tables list + tables table list - RETURN - 0 ok; In this case *map will includes the choosed index - 1 error - NOTE - Remap table numbers if INSERT ... SELECT - Check also that the 'used keys' and 'ignored keys' exists and set up the - table structure accordingly + NOTE + Remap table numbers if INSERT ... SELECT + Check also that the 'used keys' and 'ignored keys' exists and set up the + table structure accordingly + + This has to be called for all tables that are used by items, as otherwise + table->map is not set and all Item_field will be regarded as const items. - This has to be called for all tables that are used by items, as otherwise - table->map is not set and all Item_field will be regarded as const items. + RETURN + 0 ok; In this case *map will includes the choosed index + 1 error */ bool setup_tables(TABLE_LIST *tables) @@ -2584,7 +2589,7 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds) { table_map not_null_tables= 0; Item_arena *arena= thd->current_arena, backup; - + bool is_stmt_prepare= arena->is_stmt_prepare(); DBUG_ENTER("setup_conds"); thd->set_query_id=1; @@ -2622,11 +2627,11 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds) !(specialflag & SPECIAL_NO_NEW_FUNC))) { table->outer_join= 0; - if (arena->is_stmt_prepare()) + if (is_stmt_prepare) thd->set_n_backup_item_arena(arena, &backup); *conds= and_conds(*conds, table->on_expr); table->on_expr=0; - if (arena->is_stmt_prepare()) + if (is_stmt_prepare) thd->restore_backup_item_arena(arena, &backup); if ((*conds) && !(*conds)->fixed && (*conds)->fix_fields(thd, tables, conds)) @@ -2635,7 +2640,7 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds) } if (table->natural_join) { - if (arena->is_stmt_prepare()) + if (is_stmt_prepare) thd->set_n_backup_item_arena(arena, &backup); /* Make a join of all fields with have the same name */ TABLE *t1= table->table; @@ -2677,7 +2682,7 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds) { *conds= and_conds(*conds, cond_and); // fix_fields() should be made with temporary memory pool - if (arena->is_stmt_prepare()) + if (is_stmt_prepare) thd->restore_backup_item_arena(arena, &backup); if (*conds && !(*conds)->fixed) { @@ -2689,7 +2694,7 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds) { table->on_expr= and_conds(table->on_expr, cond_and); // fix_fields() should be made with temporary memory pool - if (arena->is_stmt_prepare()) + if (is_stmt_prepare) thd->restore_backup_item_arena(arena, &backup); if (table->on_expr && !table->on_expr->fixed) { @@ -2698,10 +2703,12 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds) } } } + else if (is_stmt_prepare) + thd->restore_backup_item_arena(arena, &backup); } } - if (arena->is_stmt_prepare()) + if (is_stmt_prepare) { /* We are in prepared statement preparation code => we should store @@ -2714,7 +2721,7 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds) DBUG_RETURN(test(thd->net.report_error)); err: - if (arena->is_stmt_prepare()) + if (is_stmt_prepare) thd->restore_backup_item_arena(arena, &backup); DBUG_RETURN(1); } diff --git a/sql/sql_class.cc b/sql/sql_class.cc index f1c75a3b365..aa9d96e8b2a 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -841,7 +841,8 @@ bool select_send::send_eof() /* Unlock tables before sending packet to gain some speed */ if (thd->lock) { - mysql_unlock_tables(thd, thd->lock); thd->lock=0; + mysql_unlock_tables(thd, thd->lock); + thd->lock=0; } if (!thd->net.report_error) { diff --git a/sql/sql_error.cc b/sql/sql_error.cc index c94d5e52bcf..87644300535 100644 --- a/sql/sql_error.cc +++ b/sql/sql_error.cc @@ -102,12 +102,11 @@ void mysql_reset_errors(THD *thd) MYSQL_ERROR *push_warning(THD *thd, MYSQL_ERROR::enum_warning_level level, uint code, const char *msg) { + MYSQL_ERROR *err= 0; DBUG_ENTER("push_warning"); if (thd->query_id != thd->warn_id) mysql_reset_errors(thd); - MYSQL_ERROR *err= NULL; - if (thd->warn_list.elements < thd->variables.max_error_count) { /* diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index a0496a04bb2..2c48d1dca8f 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -1680,7 +1680,12 @@ bool select_create::send_eof() We should be able to just keep the table in the table cache. */ if (!table->tmp_table) + { hash_delete(&open_cache,(byte*) table); + /* Tell threads waiting for refresh that something has happened */ + if (table->version != refresh_version) + VOID(pthread_cond_broadcast(&COND_refresh)); + } lock=0; table=0; VOID(pthread_mutex_unlock(&LOCK_open)); @@ -1705,6 +1710,9 @@ void select_create::abort() hash_delete(&open_cache,(byte*) table); if (!create_info->table_existed) quick_rm_table(table_type, db, name); + /* Tell threads waiting for refresh that something has happened */ + if (table->version != refresh_version) + VOID(pthread_cond_broadcast(&COND_refresh)); } else if (!create_info->table_existed) close_temporary_table(thd, db, name); diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 040a52ae30e..268198f74a2 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -290,6 +290,7 @@ class THD; class select_result; class JOIN; class select_union; +class Procedure; class st_select_lex_unit: public st_select_lex_node { protected: TABLE_LIST result_table_list; @@ -336,6 +337,7 @@ public: st_select_lex *union_distinct; /* pointer to the last UNION DISTINCT */ bool describe; /* union exec() called for EXPLAIN */ + Procedure *last_procedure; /* Pointer to procedure, if such exists */ void init_query(); bool create_total_list(THD *thd, st_lex *lex, TABLE_LIST **result); diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index a01b8c895c3..e727eced38f 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -3590,8 +3590,8 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv, bool dont_check_global_grants, bool no_errors) { DBUG_ENTER("check_access"); - DBUG_PRINT("enter",("want_access: %lu master_access: %lu", want_access, - thd->master_access)); + DBUG_PRINT("enter",("db: '%s' want_access: %lu master_access: %lu", + db ? db : "", want_access, thd->master_access)); #ifndef NO_EMBEDDED_ACCESS_CHECKS ulong db_access; #endif @@ -3645,7 +3645,8 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv, thd->priv_user, db, test(want_access & GRANT_ACL)); else db_access=thd->db_access; - // Remove SHOW attribute and access rights we already have + DBUG_PRINT("info",("db_access: %lu", db_access)); + /* Remove SHOW attribute and access rights we already have */ want_access &= ~(thd->master_access | EXTRA_ACL); db_access= ((*save_priv=(db_access | thd->master_access)) & want_access); @@ -4617,6 +4618,8 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd, ptr->db= empty_c_string; ptr->db_length= 0; } + if (thd->current_arena->is_stmt_prepare()) + ptr->db= thd->strdup(ptr->db); ptr->alias= alias_str; if (lower_case_table_names && table->table.length) @@ -5142,9 +5145,12 @@ int multi_update_precheck(THD *thd, TABLE_LIST *tables) */ for (table= update_list; table; table= table->next) { - if ((check_access(thd, UPDATE_ACL, table->db, - &table->grant.privilege, 0, 1) || - grant_option && check_grant(thd, UPDATE_ACL, table, 0, 1, 1)) && + if (table->derived) + table->grant.privilege= SELECT_ACL; + else if ((check_access(thd, UPDATE_ACL, table->db, + &table->grant.privilege, 0, 1) || + grant_option && + check_grant(thd, UPDATE_ACL, table, 0, 1, 1)) && (check_access(thd, SELECT_ACL, table->db, &table->grant.privilege, 0, 0) || grant_option && check_grant(thd, SELECT_ACL, table, 0, 1, 0))) @@ -5162,6 +5168,7 @@ int multi_update_precheck(THD *thd, TABLE_LIST *tables) */ if (&lex->select_lex != lex->all_selects_list) { + DBUG_PRINT("info",("Checking sub query list")); for (table= tables; table; table= table->next) { if (table->table_in_update_from_clause) @@ -5174,7 +5181,7 @@ int multi_update_precheck(THD *thd, TABLE_LIST *tables) if (table->table_list) table->grant= table->table_list->grant; } - else + else if (!table->derived) { if (check_access(thd, SELECT_ACL, table->db, &table->grant.privilege, 0, 0) || diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 0e939498925..5a311eefacd 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -1093,7 +1093,14 @@ static int mysql_test_select(Prepared_statement *stmt, } else { - List<Item> &fields= lex->select_lex.item_list; + /* Make copy of item list, as change_columns may change it */ + List<Item> fields(lex->select_lex.item_list); + + /* Change columns if a procedure like analyse() */ + if (unit->last_procedure && + unit->last_procedure->change_columns(fields)) + goto err_prep; + /* We can use lex->result as it should've been prepared in unit->prepare call above. @@ -1596,6 +1603,8 @@ int mysql_stmt_prepare(THD *thd, char *packet, uint packet_length, thd->current_arena= stmt; mysql_init_query(thd, (uchar *) thd->query, thd->query_length); + /* Reset warnings from previous command */ + mysql_reset_errors(thd); lex= thd->lex; lex->safe_to_cache_query= 0; diff --git a/sql/sql_union.cc b/sql/sql_union.cc index f9a1908355b..0be554f58a2 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -229,8 +229,12 @@ int st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, (ORDER*) 0 : (ORDER *)sl->order_list.first, (ORDER*) sl->group_list.first, sl->having, - (ORDER*) NULL, + (is_union ? (ORDER*) 0 : + (ORDER*) thd_arg->lex->proc_list.first), sl, this); + /* There are no * in the statement anymore (for PS) */ + sl->with_wild= 0; + last_procedure= join->procedure; if (res || thd_arg->is_fatal_error) goto err; if (sl == first_select) @@ -344,7 +348,8 @@ int st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, 0, 0, fake_select_lex->order_list.elements, (ORDER*) fake_select_lex->order_list.first, - (ORDER*) NULL, NULL, (ORDER*) NULL, + (ORDER*) NULL, NULL, + (ORDER*) NULL, fake_select_lex, this); fake_select_lex->table_list.empty(); } |