diff options
author | msvensson@neptunus.(none) <> | 2006-12-04 19:11:55 +0100 |
---|---|---|
committer | msvensson@neptunus.(none) <> | 2006-12-04 19:11:55 +0100 |
commit | 971c783f7dd3a136693722f20a815b7171bbbcd8 (patch) | |
tree | ac382a3e694ccbe7ed5a481331e35e4f055fdcae /sql | |
parent | 6072b7a4c4b786604b4584058c6c62a339b6d3ba (diff) | |
parent | b70d2b9341ae804fbd5147500a4d29bd86e2a5d6 (diff) | |
download | mariadb-git-971c783f7dd3a136693722f20a815b7171bbbcd8.tar.gz |
Merge neptunus.(none):/home/msvensson/mysql/mysql-5.1
into neptunus.(none):/home/msvensson/mysql/mysql-5.1-maint
Diffstat (limited to 'sql')
-rw-r--r-- | sql/field_conv.cc | 24 | ||||
-rw-r--r-- | sql/ha_ndbcluster.cc | 3 | ||||
-rw-r--r-- | sql/handler.cc | 4 | ||||
-rw-r--r-- | sql/item.cc | 1 | ||||
-rw-r--r-- | sql/item_create.cc | 278 | ||||
-rw-r--r-- | sql/item_func.cc | 78 | ||||
-rw-r--r-- | sql/item_func.h | 8 | ||||
-rw-r--r-- | sql/item_timefunc.cc | 18 | ||||
-rw-r--r-- | sql/mysql_priv.h | 1 | ||||
-rw-r--r-- | sql/mysqld.cc | 36 | ||||
-rw-r--r-- | sql/share/errmsg.txt | 2 | ||||
-rw-r--r-- | sql/sp.cc | 9 | ||||
-rw-r--r-- | sql/sql_base.cc | 7 | ||||
-rw-r--r-- | sql/sql_handler.cc | 38 | ||||
-rw-r--r-- | sql/sql_lex.cc | 2 | ||||
-rw-r--r-- | sql/sql_lex.h | 2 | ||||
-rw-r--r-- | sql/sql_parse.cc | 151 | ||||
-rw-r--r-- | sql/sql_table.cc | 122 | ||||
-rw-r--r-- | sql/sql_yacc.yy | 19 | ||||
-rw-r--r-- | sql/udf_example.c | 31 | ||||
-rw-r--r-- | sql/udf_example.def | 2 |
21 files changed, 581 insertions, 255 deletions
diff --git a/sql/field_conv.cc b/sql/field_conv.cc index 01b5306f5a4..5fde5ecb2e8 100644 --- a/sql/field_conv.cc +++ b/sql/field_conv.cc @@ -308,6 +308,21 @@ static void do_field_string(Copy_field *copy) } +static void do_field_varbinary_pre50(Copy_field *copy) +{ + char buff[MAX_FIELD_WIDTH]; + copy->tmp.set_quick(buff,sizeof(buff),copy->tmp.charset()); + copy->from_field->val_str(©->tmp); + + /* Use the same function as in 4.1 to trim trailing spaces */ + uint length= my_lengthsp_8bit(&my_charset_bin, copy->tmp.c_ptr_quick(), + copy->from_field->field_length); + + copy->to_field->store(copy->tmp.c_ptr_quick(), length, + copy->tmp.charset()); +} + + static void do_field_int(Copy_field *copy) { longlong value= copy->from_field->val_int(); @@ -570,6 +585,15 @@ void (*Copy_field::get_copy_func(Field *to,Field *from))(Copy_field*) if (from->result_type() == STRING_RESULT) { /* + Detect copy from pre 5.0 varbinary to varbinary as of 5.0 and + use special copy function that removes trailing spaces and thus + repairs data. + */ + if (from->type() == MYSQL_TYPE_VAR_STRING && !from->has_charset() && + to->type() == MYSQL_TYPE_VARCHAR && !to->has_charset()) + return do_field_varbinary_pre50; + + /* If we are copying date or datetime's we have to check the dates if we don't allow 'all' dates. */ diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index fa69c113a69..0362b8bf215 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -7325,6 +7325,8 @@ static void print_ndbcluster_open_tables() DBUG_UNLOCK_FILE; } +#endif + #define dbug_print_open_tables() \ DBUG_EXECUTE("info", \ @@ -7336,7 +7338,6 @@ static void print_ndbcluster_open_tables() print_share((t), (s));); \ DBUG_UNLOCK_FILE; -#endif #ifdef HAVE_NDB_BINLOG /* diff --git a/sql/handler.cc b/sql/handler.cc index b134814db1e..ce9dc342713 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -2304,6 +2304,10 @@ int handler::check_old_types() { return HA_ADMIN_NEEDS_ALTER; } + if ((*field)->type() == MYSQL_TYPE_VAR_STRING) + { + return HA_ADMIN_NEEDS_ALTER; + } } } return 0; diff --git a/sql/item.cc b/sql/item.cc index b310c81af5c..e2ab28dd452 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -5574,6 +5574,7 @@ int Item_default_value::save_in_field(Field *field_arg, bool no_conversions) ER(ER_NO_DEFAULT_FOR_FIELD), field_arg->field_name); } + field_arg->set_default(); return 1; } field_arg->set_default(); diff --git a/sql/item_create.cc b/sql/item_create.cc index da8954910c8..80b5e946ae7 100644 --- a/sql/item_create.cc +++ b/sql/item_create.cc @@ -28,6 +28,37 @@ */ /** + Adapter for native functions with a variable number of arguments. + The main use of this class is to discard the following calls: + <code>foo(expr1 AS name1, expr2 AS name2, ...)</code> + which are syntactically correct (the syntax can refer to a UDF), + but semantically invalid for native functions. +*/ + +class Create_native_func : public Create_func +{ +public: + virtual Item* create(THD *thd, LEX_STRING name, List<Item> *item_list); + + /** + Builder method, with no arguments. + @param thd The current thread + @param name The native function name + @param item_list The function parameters, none of which are named + @return An item representing the function call + */ + virtual Item* create_native(THD *thd, LEX_STRING name, + List<Item> *item_list) = 0; + +protected: + /** Constructor. */ + Create_native_func() {} + /** Destructor. */ + virtual ~Create_native_func() {} +}; + + +/** Adapter for functions that takes exactly zero arguments. */ @@ -302,10 +333,10 @@ protected: }; -class Create_func_atan : public Create_func +class Create_func_atan : public Create_native_func { public: - virtual Item* create(THD *thd, LEX_STRING name, List<Item> *item_list); + virtual Item* create_native(THD *thd, LEX_STRING name, List<Item> *item_list); static Create_func_atan s_singleton; @@ -434,10 +465,10 @@ protected: }; -class Create_func_concat : public Create_func +class Create_func_concat : public Create_native_func { public: - virtual Item* create(THD *thd, LEX_STRING name, List<Item> *item_list); + virtual Item* create_native(THD *thd, LEX_STRING name, List<Item> *item_list); static Create_func_concat s_singleton; @@ -447,10 +478,10 @@ protected: }; -class Create_func_concat_ws : public Create_func +class Create_func_concat_ws : public Create_native_func { public: - virtual Item* create(THD *thd, LEX_STRING name, List<Item> *item_list); + virtual Item* create_native(THD *thd, LEX_STRING name, List<Item> *item_list); static Create_func_concat_ws s_singleton; @@ -672,10 +703,10 @@ protected: }; -class Create_func_des_decrypt : public Create_func +class Create_func_des_decrypt : public Create_native_func { public: - virtual Item* create(THD *thd, LEX_STRING name, List<Item> *item_list); + virtual Item* create_native(THD *thd, LEX_STRING name, List<Item> *item_list); static Create_func_des_decrypt s_singleton; @@ -685,10 +716,10 @@ protected: }; -class Create_func_des_encrypt : public Create_func +class Create_func_des_encrypt : public Create_native_func { public: - virtual Item* create(THD *thd, LEX_STRING name, List<Item> *item_list); + virtual Item* create_native(THD *thd, LEX_STRING name, List<Item> *item_list); static Create_func_des_encrypt s_singleton; @@ -728,10 +759,10 @@ protected: #endif -class Create_func_elt : public Create_func +class Create_func_elt : public Create_native_func { public: - virtual Item* create(THD *thd, LEX_STRING name, List<Item> *item_list); + virtual Item* create_native(THD *thd, LEX_STRING name, List<Item> *item_list); static Create_func_elt s_singleton; @@ -754,10 +785,10 @@ protected: }; -class Create_func_encrypt : public Create_func +class Create_func_encrypt : public Create_native_func { public: - virtual Item* create(THD *thd, LEX_STRING name, List<Item> *item_list); + virtual Item* create_native(THD *thd, LEX_STRING name, List<Item> *item_list); static Create_func_encrypt s_singleton; @@ -825,10 +856,10 @@ protected: }; -class Create_func_export_set : public Create_func +class Create_func_export_set : public Create_native_func { public: - virtual Item* create(THD *thd, LEX_STRING name, List<Item> *item_list); + virtual Item* create_native(THD *thd, LEX_STRING name, List<Item> *item_list); static Create_func_export_set s_singleton; @@ -853,10 +884,10 @@ protected: #endif -class Create_func_field : public Create_func +class Create_func_field : public Create_native_func { public: - virtual Item* create(THD *thd, LEX_STRING name, List<Item> *item_list); + virtual Item* create_native(THD *thd, LEX_STRING name, List<Item> *item_list); static Create_func_field s_singleton; @@ -931,10 +962,10 @@ protected: }; -class Create_func_from_unixtime : public Create_func +class Create_func_from_unixtime : public Create_native_func { public: - virtual Item* create(THD *thd, LEX_STRING name, List<Item> *item_list); + virtual Item* create_native(THD *thd, LEX_STRING name, List<Item> *item_list); static Create_func_from_unixtime s_singleton; @@ -945,10 +976,10 @@ protected: #ifdef HAVE_SPATIAL -class Create_func_geometry_from_text : public Create_func +class Create_func_geometry_from_text : public Create_native_func { public: - virtual Item* create(THD *thd, LEX_STRING name, List<Item> *item_list); + virtual Item* create_native(THD *thd, LEX_STRING name, List<Item> *item_list); static Create_func_geometry_from_text s_singleton; @@ -960,10 +991,10 @@ protected: #ifdef HAVE_SPATIAL -class Create_func_geometry_from_wkb : public Create_func +class Create_func_geometry_from_wkb : public Create_native_func { public: - virtual Item* create(THD *thd, LEX_STRING name, List<Item> *item_list); + virtual Item* create_native(THD *thd, LEX_STRING name, List<Item> *item_list); static Create_func_geometry_from_wkb s_singleton; @@ -1032,10 +1063,10 @@ protected: #endif -class Create_func_greatest : public Create_func +class Create_func_greatest : public Create_native_func { public: - virtual Item* create(THD *thd, LEX_STRING name, List<Item> *item_list); + virtual Item* create_native(THD *thd, LEX_STRING name, List<Item> *item_list); static Create_func_greatest s_singleton; @@ -1237,10 +1268,10 @@ protected: }; -class Create_func_last_insert_id : public Create_func +class Create_func_last_insert_id : public Create_native_func { public: - virtual Item* create(THD *thd, LEX_STRING name, List<Item> *item_list); + virtual Item* create_native(THD *thd, LEX_STRING name, List<Item> *item_list); static Create_func_last_insert_id s_singleton; @@ -1263,10 +1294,10 @@ protected: }; -class Create_func_least : public Create_func +class Create_func_least : public Create_native_func { public: - virtual Item* create(THD *thd, LEX_STRING name, List<Item> *item_list); + virtual Item* create_native(THD *thd, LEX_STRING name, List<Item> *item_list); static Create_func_least s_singleton; @@ -1315,10 +1346,10 @@ protected: }; -class Create_func_locate : public Create_func +class Create_func_locate : public Create_native_func { public: - virtual Item* create(THD *thd, LEX_STRING name, List<Item> *item_list); + virtual Item* create_native(THD *thd, LEX_STRING name, List<Item> *item_list); static Create_func_locate s_singleton; @@ -1328,10 +1359,10 @@ protected: }; -class Create_func_log : public Create_func +class Create_func_log : public Create_native_func { public: - virtual Item* create(THD *thd, LEX_STRING name, List<Item> *item_list); + virtual Item* create_native(THD *thd, LEX_STRING name, List<Item> *item_list); static Create_func_log s_singleton; @@ -1419,10 +1450,10 @@ protected: }; -class Create_func_make_set : public Create_func +class Create_func_make_set : public Create_native_func { public: - virtual Item* create(THD *thd, LEX_STRING name, List<Item> *item_list); + virtual Item* create_native(THD *thd, LEX_STRING name, List<Item> *item_list); static Create_func_make_set s_singleton; @@ -1432,10 +1463,10 @@ protected: }; -class Create_func_master_pos_wait : public Create_func +class Create_func_master_pos_wait : public Create_native_func { public: - virtual Item* create(THD *thd, LEX_STRING name, List<Item> *item_list); + virtual Item* create_native(THD *thd, LEX_STRING name, List<Item> *item_list); static Create_func_master_pos_wait s_singleton; @@ -1676,10 +1707,10 @@ protected: }; -class Create_func_rand : public Create_func +class Create_func_rand : public Create_native_func { public: - virtual Item* create(THD *thd, LEX_STRING name, List<Item> *item_list); + virtual Item* create_native(THD *thd, LEX_STRING name, List<Item> *item_list); static Create_func_rand s_singleton; @@ -1715,10 +1746,10 @@ protected: }; -class Create_func_round : public Create_func +class Create_func_round : public Create_native_func { public: - virtual Item* create(THD *thd, LEX_STRING name, List<Item> *item_list); + virtual Item* create_native(THD *thd, LEX_STRING name, List<Item> *item_list); static Create_func_round s_singleton; @@ -2085,10 +2116,10 @@ protected: }; -class Create_func_unix_timestamp : public Create_func +class Create_func_unix_timestamp : public Create_native_func { public: - virtual Item* create(THD *thd, LEX_STRING name, List<Item> *item_list); + virtual Item* create_native(THD *thd, LEX_STRING name, List<Item> *item_list); static Create_func_unix_timestamp s_singleton; @@ -2221,10 +2252,10 @@ protected: #endif -class Create_func_year_week : public Create_func +class Create_func_year_week : public Create_native_func { public: - virtual Item* create(THD *thd, LEX_STRING name, List<Item> *item_list); + virtual Item* create_native(THD *thd, LEX_STRING name, List<Item> *item_list); static Create_func_year_week s_singleton; @@ -2240,6 +2271,29 @@ protected: ============================================================================= */ +/** + Checks if there are named parameters in a parameter list. + The syntax to name parameters in a function call is as follow: + <code>foo(expr AS named, expr named, expr AS "named", expr "named")</code> + @param params The parameter list, can be null + @return true if one or more parameter is named +*/ +static bool has_named_parameters(List<Item> *params) +{ + if (params) + { + Item *param; + List_iterator<Item> it(*params); + while ((param= it++)) + { + if (! param->is_autogenerated_name) + return true; + } + } + + return false; +} + #ifndef HAVE_SPATIAL Create_func_no_geom Create_func_no_geom::s_singleton; @@ -2387,11 +2441,27 @@ Create_sp_func::create(THD *thd, LEX_STRING db, LEX_STRING name, int arg_count= 0; Item *func= NULL; LEX *lex= thd->lex; - sp_name *qname= new (thd->mem_root) sp_name(db, name); + sp_name *qname; + + if (has_named_parameters(item_list)) + { + /* + The syntax "db.foo(expr AS p1, expr AS p2, ...) is invalid, + and has been rejected during syntactic parsing already, + because a stored function call may not have named parameters. + + The syntax "foo(expr AS p1, expr AS p2, ...)" is correct, + because it can refer to a User Defined Function call. + For a Stored Function however, this has no semantic. + */ + my_error(ER_WRONG_PARAMETERS_TO_STORED_FCT, MYF(0), name.str); + return NULL; + } if (item_list != NULL) arg_count= item_list->elements; + qname= new (thd->mem_root) sp_name(db, name); qname->init_qname(thd); sp_add_used_routine(lex, thd, qname, TYPE_ENUM_FUNCTION); @@ -2407,6 +2477,19 @@ Create_sp_func::create(THD *thd, LEX_STRING db, LEX_STRING name, Item* +Create_native_func::create(THD *thd, LEX_STRING name, List<Item> *item_list) +{ + if (has_named_parameters(item_list)) + { + my_error(ER_WRONG_PARAMETERS_TO_NATIVE_FCT, MYF(0), name.str); + return NULL; + } + + return create_native(thd, name, item_list); +} + + +Item* Create_func_arg0::create(THD *thd, LEX_STRING name, List<Item> *item_list) { int arg_count= 0; @@ -2439,6 +2522,13 @@ Create_func_arg1::create(THD *thd, LEX_STRING name, List<Item> *item_list) } Item *param_1= item_list->pop(); + + if (! param_1->is_autogenerated_name) + { + my_error(ER_WRONG_PARAMETERS_TO_NATIVE_FCT, MYF(0), name.str); + return NULL; + } + return create(thd, param_1); } @@ -2459,6 +2549,14 @@ Create_func_arg2::create(THD *thd, LEX_STRING name, List<Item> *item_list) Item *param_1= item_list->pop(); Item *param_2= item_list->pop(); + + if ( (! param_1->is_autogenerated_name) + || (! param_2->is_autogenerated_name)) + { + my_error(ER_WRONG_PARAMETERS_TO_NATIVE_FCT, MYF(0), name.str); + return NULL; + } + return create(thd, param_1, param_2); } @@ -2480,6 +2578,15 @@ Create_func_arg3::create(THD *thd, LEX_STRING name, List<Item> *item_list) Item *param_1= item_list->pop(); Item *param_2= item_list->pop(); Item *param_3= item_list->pop(); + + if ( (! param_1->is_autogenerated_name) + || (! param_2->is_autogenerated_name) + || (! param_3->is_autogenerated_name)) + { + my_error(ER_WRONG_PARAMETERS_TO_NATIVE_FCT, MYF(0), name.str); + return NULL; + } + return create(thd, param_1, param_2, param_3); } @@ -2574,7 +2681,8 @@ Create_func_asin::create(THD *thd, Item *arg1) Create_func_atan Create_func_atan::s_singleton; Item* -Create_func_atan::create(THD *thd, LEX_STRING name, List<Item> *item_list) +Create_func_atan::create_native(THD *thd, LEX_STRING name, + List<Item> *item_list) { Item* func= NULL; int arg_count= 0; @@ -2687,7 +2795,8 @@ Create_func_coercibility::create(THD *thd, Item *arg1) Create_func_concat Create_func_concat::s_singleton; Item* -Create_func_concat::create(THD *thd, LEX_STRING name, List<Item> *item_list) +Create_func_concat::create_native(THD *thd, LEX_STRING name, + List<Item> *item_list) { int arg_count= 0; @@ -2707,7 +2816,8 @@ Create_func_concat::create(THD *thd, LEX_STRING name, List<Item> *item_list) Create_func_concat_ws Create_func_concat_ws::s_singleton; Item* -Create_func_concat_ws::create(THD *thd, LEX_STRING name, List<Item> *item_list) +Create_func_concat_ws::create_native(THD *thd, LEX_STRING name, + List<Item> *item_list) { int arg_count= 0; @@ -2897,8 +3007,8 @@ Create_func_degrees::create(THD *thd, Item *arg1) Create_func_des_decrypt Create_func_des_decrypt::s_singleton; Item* -Create_func_des_decrypt::create(THD *thd, LEX_STRING name, - List<Item> *item_list) +Create_func_des_decrypt::create_native(THD *thd, LEX_STRING name, + List<Item> *item_list) { Item *func= NULL; int arg_count= 0; @@ -2934,8 +3044,8 @@ Create_func_des_decrypt::create(THD *thd, LEX_STRING name, Create_func_des_encrypt Create_func_des_encrypt::s_singleton; Item* -Create_func_des_encrypt::create(THD *thd, LEX_STRING name, - List<Item> *item_list) +Create_func_des_encrypt::create_native(THD *thd, LEX_STRING name, + List<Item> *item_list) { Item *func= NULL; int arg_count= 0; @@ -2994,7 +3104,8 @@ Create_func_disjoint::create(THD *thd, Item *arg1, Item *arg2) Create_func_elt Create_func_elt::s_singleton; Item* -Create_func_elt::create(THD *thd, LEX_STRING name, List<Item> *item_list) +Create_func_elt::create_native(THD *thd, LEX_STRING name, + List<Item> *item_list) { int arg_count= 0; @@ -3023,7 +3134,8 @@ Create_func_encode::create(THD *thd, Item *arg1, Item *arg2) Create_func_encrypt Create_func_encrypt::s_singleton; Item* -Create_func_encrypt::create(THD *thd, LEX_STRING name, List<Item> *item_list) +Create_func_encrypt::create_native(THD *thd, LEX_STRING name, + List<Item> *item_list) { Item *func= NULL; int arg_count= 0; @@ -3104,7 +3216,8 @@ Create_func_exp::create(THD *thd, Item *arg1) Create_func_export_set Create_func_export_set::s_singleton; Item* -Create_func_export_set::create(THD *thd, LEX_STRING name, List<Item> *item_list) +Create_func_export_set::create_native(THD *thd, LEX_STRING name, + List<Item> *item_list) { Item *func= NULL; int arg_count= 0; @@ -3168,7 +3281,8 @@ Create_func_exteriorring::create(THD *thd, Item *arg1) Create_func_field Create_func_field::s_singleton; Item* -Create_func_field::create(THD *thd, LEX_STRING name, List<Item> *item_list) +Create_func_field::create_native(THD *thd, LEX_STRING name, + List<Item> *item_list) { int arg_count= 0; @@ -3234,8 +3348,8 @@ Create_func_from_days::create(THD *thd, Item *arg1) Create_func_from_unixtime Create_func_from_unixtime::s_singleton; Item* -Create_func_from_unixtime::create(THD *thd, LEX_STRING name, - List<Item> *item_list) +Create_func_from_unixtime::create_native(THD *thd, LEX_STRING name, + List<Item> *item_list) { Item *func= NULL; int arg_count= 0; @@ -3273,8 +3387,8 @@ Create_func_from_unixtime::create(THD *thd, LEX_STRING name, Create_func_geometry_from_text Create_func_geometry_from_text::s_singleton; Item* -Create_func_geometry_from_text::create(THD *thd, LEX_STRING name, - List<Item> *item_list) +Create_func_geometry_from_text::create_native(THD *thd, LEX_STRING name, + List<Item> *item_list) { Item *func= NULL; int arg_count= 0; @@ -3313,8 +3427,8 @@ Create_func_geometry_from_text::create(THD *thd, LEX_STRING name, Create_func_geometry_from_wkb Create_func_geometry_from_wkb::s_singleton; Item* -Create_func_geometry_from_wkb::create(THD *thd, LEX_STRING name, - List<Item> *item_list) +Create_func_geometry_from_wkb::create_native(THD *thd, LEX_STRING name, + List<Item> *item_list) { Item *func= NULL; int arg_count= 0; @@ -3396,7 +3510,8 @@ Create_func_glength::create(THD *thd, Item *arg1) Create_func_greatest Create_func_greatest::s_singleton; Item* -Create_func_greatest::create(THD *thd, LEX_STRING name, List<Item> *item_list) +Create_func_greatest::create_native(THD *thd, LEX_STRING name, + List<Item> *item_list) { int arg_count= 0; @@ -3556,8 +3671,8 @@ Create_func_last_day::create(THD *thd, Item *arg1) Create_func_last_insert_id Create_func_last_insert_id::s_singleton; Item* -Create_func_last_insert_id::create(THD *thd, LEX_STRING name, - List<Item> *item_list) +Create_func_last_insert_id::create_native(THD *thd, LEX_STRING name, + List<Item> *item_list) { Item *func= NULL; int arg_count= 0; @@ -3602,7 +3717,8 @@ Create_func_lcase::create(THD *thd, Item *arg1) Create_func_least Create_func_least::s_singleton; Item* -Create_func_least::create(THD *thd, LEX_STRING name, List<Item> *item_list) +Create_func_least::create_native(THD *thd, LEX_STRING name, + List<Item> *item_list) { int arg_count= 0; @@ -3650,7 +3766,8 @@ Create_func_load_file::create(THD *thd, Item *arg1) Create_func_locate Create_func_locate::s_singleton; Item* -Create_func_locate::create(THD *thd, LEX_STRING name, List<Item> *item_list) +Create_func_locate::create_native(THD *thd, LEX_STRING name, + List<Item> *item_list) { Item *func= NULL; int arg_count= 0; @@ -3690,7 +3807,8 @@ Create_func_locate::create(THD *thd, LEX_STRING name, List<Item> *item_list) Create_func_log Create_func_log::s_singleton; Item* -Create_func_log::create(THD *thd, LEX_STRING name, List<Item> *item_list) +Create_func_log::create_native(THD *thd, LEX_STRING name, + List<Item> *item_list) { Item *func= NULL; int arg_count= 0; @@ -3780,7 +3898,8 @@ Create_func_maketime::create(THD *thd, Item *arg1, Item *arg2, Item *arg3) Create_func_make_set Create_func_make_set::s_singleton; Item* -Create_func_make_set::create(THD *thd, LEX_STRING name, List<Item> *item_list) +Create_func_make_set::create_native(THD *thd, LEX_STRING name, + List<Item> *item_list) { int arg_count= 0; @@ -3801,8 +3920,8 @@ Create_func_make_set::create(THD *thd, LEX_STRING name, List<Item> *item_list) Create_func_master_pos_wait Create_func_master_pos_wait::s_singleton; Item* -Create_func_master_pos_wait::create(THD *thd, LEX_STRING name, - List<Item> *item_list) +Create_func_master_pos_wait::create_native(THD *thd, LEX_STRING name, + List<Item> *item_list) { Item *func= NULL; int arg_count= 0; @@ -4010,7 +4129,8 @@ Create_func_radians::create(THD *thd, Item *arg1) Create_func_rand Create_func_rand::s_singleton; Item* -Create_func_rand::create(THD *thd, LEX_STRING name, List<Item> *item_list) +Create_func_rand::create_native(THD *thd, LEX_STRING name, + List<Item> *item_list) { Item *func= NULL; int arg_count= 0; @@ -4065,7 +4185,8 @@ Create_func_reverse::create(THD *thd, Item *arg1) Create_func_round Create_func_round::s_singleton; Item* -Create_func_round::create(THD *thd, LEX_STRING name, List<Item> *item_list) +Create_func_round::create_native(THD *thd, LEX_STRING name, + List<Item> *item_list) { Item *func= NULL; int arg_count= 0; @@ -4374,8 +4495,8 @@ Create_func_unhex::create(THD *thd, Item *arg1) Create_func_unix_timestamp Create_func_unix_timestamp::s_singleton; Item* -Create_func_unix_timestamp::create(THD *thd, LEX_STRING name, - List<Item> *item_list) +Create_func_unix_timestamp::create_native(THD *thd, LEX_STRING name, + List<Item> *item_list) { Item *func= NULL; int arg_count= 0; @@ -4506,7 +4627,8 @@ Create_func_y::create(THD *thd, Item *arg1) Create_func_year_week Create_func_year_week::s_singleton; Item* -Create_func_year_week::create(THD *thd, LEX_STRING name, List<Item> *item_list) +Create_func_year_week::create_native(THD *thd, LEX_STRING name, + List<Item> *item_list) { Item *func= NULL; int arg_count= 0; diff --git a/sql/item_func.cc b/sql/item_func.cc index 08e417d8322..0f5faf93cc3 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -1362,6 +1362,10 @@ longlong Item_func_mod::int_op() signal_divide_by_null(); return 0; } + + if (args[0]->unsigned_flag) + return ((ulonglong) value) % val2; + return value % val2; } @@ -2730,39 +2734,47 @@ udf_handler::fix_fields(THD *thd, Item_result_field *func, char *to=num_buffer; for (uint i=0; i < arg_count; i++) { - f_args.args[i]=0; + /* + For a constant argument i, args->args[i] points to the argument value. + For non-constant, args->args[i] is NULL. + */ + f_args.args[i]= NULL; /* Non-const unless updated below. */ + f_args.lengths[i]= arguments[i]->max_length; f_args.maybe_null[i]= (char) arguments[i]->maybe_null; f_args.attributes[i]= arguments[i]->name; f_args.attribute_lengths[i]= arguments[i]->name_length; - switch(arguments[i]->type()) { - case Item::STRING_ITEM: // Constant string ! + if (arguments[i]->const_item()) { - String *res=arguments[i]->val_str(&buffers[i]); - if (arguments[i]->null_value) - continue; - f_args.args[i]= (char*) res->ptr(); - break; - } - case Item::INT_ITEM: - *((longlong*) to) = arguments[i]->val_int(); - if (!arguments[i]->null_value) - { - f_args.args[i]=to; - to+= ALIGN_SIZE(sizeof(longlong)); - } - break; - case Item::REAL_ITEM: - *((double*) to)= arguments[i]->val_real(); - if (!arguments[i]->null_value) - { - f_args.args[i]=to; - to+= ALIGN_SIZE(sizeof(double)); - } - break; - default: // Skip these - break; + if (arguments[i]->null_value) + continue; + + switch (arguments[i]->result_type()) + { + case STRING_RESULT: + case DECIMAL_RESULT: + { + String *res= arguments[i]->val_str(&buffers[i]); + f_args.args[i]= (char*) res->ptr(); + break; + } + case INT_RESULT: + *((longlong*) to)= arguments[i]->val_int(); + f_args.args[i]= to; + to+= ALIGN_SIZE(sizeof(longlong)); + break; + case REAL_RESULT: + *((double*) to)= arguments[i]->val_real(); + f_args.args[i]= to; + to+= ALIGN_SIZE(sizeof(double)); + break; + case ROW_RESULT: + default: + // This case should never be chosen + DBUG_ASSERT(0); + break; + } } } thd->net.last_error[0]=0; @@ -5025,6 +5037,18 @@ Item_func_sp::execute_impl(THD *thd, Field *return_value_fld) goto error; /* + Throw an error if a non-deterministic function is called while + statement-based replication (SBR) is active. + */ + if (!m_sp->m_chistics->detistic && !trust_function_creators && + (mysql_bin_log.is_open() && + thd->variables.binlog_format == BINLOG_FORMAT_STMT)) + { + my_error(ER_BINLOG_ROW_RBR_TO_SBR, MYF(0)); + goto error; + } + + /* Disable the binlogging if this is not a SELECT statement. If this is a SELECT, leave binlogging on, so execute_function() code writes the function call into binlog. diff --git a/sql/item_func.h b/sql/item_func.h index 9139e30483d..9130ef0a0c4 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -1315,10 +1315,10 @@ public: class Item_func_inet_aton : public Item_int_func { public: - Item_func_inet_aton(Item *a) :Item_int_func(a) {} - longlong val_int(); - const char *func_name() const { return "inet_aton"; } - void fix_length_and_dec() { decimals = 0; max_length = 21; maybe_null=1;} + Item_func_inet_aton(Item *a) :Item_int_func(a) {} + longlong val_int(); + const char *func_name() const { return "inet_aton"; } + void fix_length_and_dec() { decimals= 0; max_length= 21; maybe_null= 1; unsigned_flag= 1;} bool check_partition_func_processor(byte *int_arg) {return FALSE;} }; diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index 76ab70cca96..ff688e15307 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -289,15 +289,16 @@ static bool extract_date_time(DATE_TIME_FORMAT *format, for (; ptr != end && val != val_end; ptr++) { + /* Skip pre-space between each argument */ + while (val != val_end && my_isspace(cs, *val)) + val++; + if (*ptr == '%' && ptr+1 != end) { int val_len; char *tmp; error= 0; - /* Skip pre-space between each argument */ - while (val != val_end && my_isspace(cs, *val)) - val++; val_len= (uint) (val_end - val); switch (*++ptr) { @@ -3193,7 +3194,9 @@ bool Item_func_str_to_date::get_date(TIME *ltime, uint fuzzy_date) date_time_format.format.str= (char*) format->ptr(); date_time_format.format.length= format->length(); if (extract_date_time(&date_time_format, val->ptr(), val->length(), - ltime, cached_timestamp_type, 0, "datetime")) + ltime, cached_timestamp_type, 0, "datetime") || + ((fuzzy_date & TIME_NO_ZERO_DATE) && + (ltime->year == 0 || ltime->month == 0 || ltime->day == 0))) goto null_date; if (cached_timestamp_type == MYSQL_TIMESTAMP_TIME && ltime->day) { @@ -3230,8 +3233,13 @@ String *Item_func_str_to_date::val_str(String *str) bool Item_func_last_day::get_date(TIME *ltime, uint fuzzy_date) { - if (get_arg0_date(ltime, fuzzy_date & ~TIME_FUZZY_DATE)) + if (get_arg0_date(ltime, fuzzy_date & ~TIME_FUZZY_DATE) || + (ltime->month == 0)) + { + null_value= 1; return 1; + } + null_value= 0; uint month_idx= ltime->month-1; ltime->day= days_in_month[month_idx]; if ( month_idx == 1 && calc_days_in_year(ltime->year) == 366) diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index a75f204ae33..58e38362544 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1112,6 +1112,7 @@ bool mysql_ha_read(THD *, TABLE_LIST *,enum enum_ha_read_modes,char *, List<Item> *,enum ha_rkey_function,Item *,ha_rows,ha_rows); int mysql_ha_flush(THD *thd, TABLE_LIST *tables, uint mode_flags, bool is_locked); +void mysql_ha_mark_tables_for_reopen(THD *thd, TABLE *table); /* mysql_ha_flush mode_flags bits */ #define MYSQL_HA_CLOSE_FINAL 0x00 #define MYSQL_HA_REOPEN_ON_USAGE 0x01 diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 6921fe3e6d8..ee64a247e5a 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -346,7 +346,7 @@ bool opt_error_log= IF_WIN(1,0); bool opt_disable_networking=0, opt_skip_show_db=0; my_bool opt_character_set_client_handshake= 1; bool server_id_supplied = 0; -bool opt_endinfo,using_udf_functions; +bool opt_endinfo, using_udf_functions; my_bool locked_in_memory; bool opt_using_transactions, using_update_log; bool volatile abort_loop; @@ -2155,13 +2155,24 @@ later when used with nscd), disable LDAP in your nsswitch.conf, or use a\n\ mysqld that is not statically linked.\n"); #endif - if (test_flags & TEST_CORE_ON_SIGNAL) - { - fprintf(stderr, "Writing a core file\n"); - fflush(stderr); - write_core(sig); - } - exit(1); + if (locked_in_memory) + { + fprintf(stderr, "\n\ +The \"--memlock\" argument, which was enabled, uses system calls that are\n\ +unreliable and unstable on some operating systems and operating-system\n\ +versions (notably, some versions of Linux). This crash could be due to use\n\ +of those buggy OS calls. You should consider whether you really need the\n\ +\"--memlock\" parameter and/or consult the OS distributer about \"mlockall\"\n\ +bugs.\n"); + } + + if (test_flags & TEST_CORE_ON_SIGNAL) + { + fprintf(stderr, "Writing a core file\n"); + fflush(stderr); + write_core(sig); + } + exit(1); } #ifndef SA_RESETHAND @@ -2784,13 +2795,13 @@ static int init_common_variables(const char *conf_file_name, int argc, !(log_output_options & LOG_NONE)) sql_print_warning("Although a path was specified for the " "--log option, log tables are used. " - "To enable logging to file use the --log-output option."); + "To enable logging to files use the --log-output option."); if (opt_slow_log && opt_slow_logname && !(log_output_options & LOG_FILE) && !(log_output_options & LOG_NONE)) sql_print_warning("Although a path was specified for the " "--log-slow-queries option, log tables are used. " - "To enable logging to file use the --log-output option."); + "To enable logging to files use the --log-output option."); if (!opt_logname) opt_logname= make_default_log_name(buff, ".log"); @@ -5932,9 +5943,11 @@ The minimum value for this variable is 4096.", "If there is more than this number of interrupted connections from a host this host will be blocked from further connections.", (gptr*) &max_connect_errors, (gptr*) &max_connect_errors, 0, GET_ULONG, REQUIRED_ARG, MAX_CONNECT_ERRORS, 1, ~0L, 0, 1, 0}, + // Default max_connections of 151 is larger than Apache's default max + // children, to avoid "too many connections" error in a common setup {"max_connections", OPT_MAX_CONNECTIONS, "The number of simultaneous clients allowed.", (gptr*) &max_connections, - (gptr*) &max_connections, 0, GET_ULONG, REQUIRED_ARG, 100, 1, 16384, 0, 1, + (gptr*) &max_connections, 0, GET_ULONG, REQUIRED_ARG, 151, 1, 16384, 0, 1, 0}, {"max_delayed_threads", OPT_MAX_DELAYED_THREADS, "Don't start more than this number of threads to handle INSERT DELAYED statements. If set to zero, which means INSERT DELAYED is not used.", @@ -6624,6 +6637,7 @@ SHOW_VAR status_vars[]= { {"Com_create_function", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_CREATE_FUNCTION]), SHOW_LONG_STATUS}, {"Com_create_index", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_CREATE_INDEX]), SHOW_LONG_STATUS}, {"Com_create_table", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_CREATE_TABLE]), SHOW_LONG_STATUS}, + {"Com_create_user", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_CREATE_USER]), SHOW_LONG_STATUS}, {"Com_dealloc_sql", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_DEALLOCATE_PREPARE]), SHOW_LONG_STATUS}, {"Com_delete", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_DELETE]), SHOW_LONG_STATUS}, {"Com_delete_multi", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_DELETE_MULTI]), SHOW_LONG_STATUS}, diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index cfeca697692..c64f4da045e 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -6010,6 +6010,8 @@ ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT 42000 eng "Incorrect parameter count in the call to native function '%-.64s'" ER_WRONG_PARAMETERS_TO_NATIVE_FCT 42000 eng "Incorrect parameters in the call to native function '%-.64s'" +ER_WRONG_PARAMETERS_TO_STORED_FCT 42000 + eng "Incorrect parameters in the call to stored function '%-.64s'" ER_NATIVE_FCT_NAME_COLLISION eng "This function '%-.64s' has the same name as a native function." ER_BINLOG_PURGE_EMFILE diff --git a/sql/sp.cc b/sql/sp.cc index 45a177d3e7a..9e53aff742e 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -497,17 +497,10 @@ db_create_routine(THD *thd, int type, sp_head *sp) char definer[USER_HOST_BUFF_SIZE]; char old_db_buf[NAME_LEN+1]; LEX_STRING old_db= { old_db_buf, sizeof(old_db_buf) }; - bool dbchanged; DBUG_ENTER("db_create_routine"); DBUG_PRINT("enter", ("type: %d name: %.*s",type,sp->m_name.length, sp->m_name.str)); - if ((ret= sp_use_new_db(thd, sp->m_db, &old_db, 0, &dbchanged))) - { - ret= SP_NO_DB_ERROR; - goto done; - } - if (!(table= open_proc_table_for_update(thd))) ret= SP_OPEN_TABLE_FAILED; else @@ -631,8 +624,6 @@ db_create_routine(THD *thd, int type, sp_head *sp) done: close_thread_tables(thd); - if (dbchanged) - (void) mysql_change_db(thd, old_db.str, 1); DBUG_RETURN(ret); } diff --git a/sql/sql_base.cc b/sql/sql_base.cc index db6baac8681..3fd09d909a4 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -1089,6 +1089,13 @@ void close_thread_tables(THD *thd, bool lock_in_use, bool skip_derived) DBUG_PRINT("info", ("thd->open_tables: 0x%lx", (long) thd->open_tables)); + /* + End open index scans and table scans and remove references to the tables + from the handler tables hash. After this preparation it is safe to close + the tables. + */ + mysql_ha_mark_tables_for_reopen(thd, thd->open_tables); + found_old_table= 0; while (thd->open_tables) found_old_table|= close_thread_table(thd, &thd->open_tables); diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc index c448be04ac5..5951acdcc40 100644 --- a/sql/sql_handler.cc +++ b/sql/sql_handler.cc @@ -757,3 +757,41 @@ static int mysql_ha_flush_table(THD *thd, TABLE **table_ptr, uint mode_flags) DBUG_RETURN(0); } + + +/* + Mark tables for reopen. + + SYNOPSIS + mysql_ha_mark_tables_for_reopen() + thd Thread identifier. + table Table list to mark for reopen. + + DESCRIPTION + For each table found in the handler hash mark it as closed + (ready for reopen) and end all index/table scans. + + NOTE + The caller must lock LOCK_open. +*/ + +void mysql_ha_mark_tables_for_reopen(THD *thd, TABLE *table) +{ + DBUG_ENTER("mysql_ha_mark_tables_for_reopen"); + + safe_mutex_assert_owner(&LOCK_open); + for (; table; table= table->next) + { + TABLE_LIST *hash_tables; + if ((hash_tables= (TABLE_LIST*) hash_search(&thd->handler_tables_hash, + (byte*) table->alias, + strlen(table->alias) + 1))) + { + /* Mark table as ready for reopen. */ + hash_tables->table= NULL; + /* End open index/table scans. */ + table->file->ha_index_or_rnd_end(); + } + } + DBUG_VOID_RETURN; +} diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 47704570720..d156973a790 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -164,7 +164,6 @@ void lex_start(THD *thd, const uchar *buf, uint length) lex->select_lex.ftfunc_list= &lex->select_lex.ftfunc_list_alloc; lex->select_lex.group_list.empty(); lex->select_lex.order_list.empty(); - lex->select_lex.udf_list.empty(); lex->ignore_space=test(thd->variables.sql_mode & MODE_IGNORE_SPACE); lex->sql_command= SQLCOM_END; lex->duplicates= DUP_ERROR; @@ -1182,7 +1181,6 @@ void st_select_lex::init_select() braces= 0; when_list.empty(); expr_list.empty(); - udf_list.empty(); interval_list.empty(); use_index.empty(); ftfunc_list_alloc.empty(); diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 4af767b25db..7fd60cbfa58 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -609,8 +609,6 @@ public: /* exclude this select from check of unique_table() */ bool exclude_from_table_unique_test; - List<udf_func> udf_list; /* udf function calls stack */ - void init_query(); void init_select(); st_select_lex_unit* master_unit(); diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 401285c2f8b..3f06c0680e2 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -57,10 +57,6 @@ (LP)->sql_command == SQLCOM_DROP_FUNCTION ? \ "FUNCTION" : "PROCEDURE") -#ifdef SOLARIS -extern "C" int gethostname(char *name, int namelen); -#endif - static void time_out_user_resource_limits(THD *thd, USER_CONN *uc); #ifndef NO_EMBEDDED_ACCESS_CHECKS static int check_for_max_user_connections(THD *thd, USER_CONN *uc); @@ -2631,10 +2627,11 @@ mysql_execute_command(THD *thd) if (opt_readonly && !(thd->security_ctx->master_access & SUPER_ACL) && (sql_command_flags[lex->sql_command] & CF_CHANGES_DATA) && - !((lex->sql_command == SQLCOM_CREATE_TABLE) && - (lex->create_info.options & HA_LEX_CREATE_TMP_TABLE)) && - ((lex->sql_command != SQLCOM_UPDATE_MULTI) && - some_non_temp_table_to_be_updated(thd, all_tables))) + !((lex->sql_command == SQLCOM_CREATE_TABLE) && + (lex->create_info.options & HA_LEX_CREATE_TMP_TABLE)) && + !((lex->sql_command == SQLCOM_DROP_TABLE) && lex->drop_temporary) && + ((lex->sql_command != SQLCOM_UPDATE_MULTI) && + some_non_temp_table_to_be_updated(thd, all_tables))) { my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--read-only"); DBUG_RETURN(-1); @@ -4229,6 +4226,7 @@ end_with_restore_list: bool write_to_binlog; if (check_global_access(thd,RELOAD_ACL)) goto error; + /* reload_acl_and_cache() will tell us if we are allowed to write to the binlog or not. @@ -4249,7 +4247,8 @@ end_with_restore_list: } } send_ok(thd); - } + } + break; } case SQLCOM_KILL: @@ -4434,26 +4433,38 @@ end_with_restore_list: { uint namelen; char *name; - int result; + int result= SP_INTERNAL_ERROR; DBUG_ASSERT(lex->sphead != 0); DBUG_ASSERT(lex->sphead->m_db.str); /* Must be initialized in the parser */ - - if (check_access(thd, CREATE_PROC_ACL, lex->sphead->m_db.str, 0, 0, 0, - is_schema_db(lex->sphead->m_db.str))) + /* + Verify that the database name is allowed, optionally + lowercase it. + */ + if (check_db_name(&lex->sphead->m_db)) { - delete lex->sphead; - lex->sphead= 0; - goto error; + my_error(ER_WRONG_DB_NAME, MYF(0), lex->sphead->m_db.str); + goto create_sp_error; } - if (end_active_trans(thd)) + /* + Check that a database directory with this name + exists. Design note: This won't work on virtual databases + like information_schema. + */ + if (check_db_dir_existence(lex->sphead->m_db.str)) { - delete lex->sphead; - lex->sphead= 0; - goto error; + my_error(ER_BAD_DB_ERROR, MYF(0), lex->sphead->m_db.str); + goto create_sp_error; } + if (check_access(thd, CREATE_PROC_ACL, lex->sphead->m_db.str, 0, 0, 0, + is_schema_db(lex->sphead->m_db.str))) + goto create_sp_error; + + if (end_active_trans(thd)) + goto create_sp_error; + name= lex->sphead->name(&namelen); #ifdef HAVE_DLOPEN if (lex->sphead->m_type == TYPE_ENUM_FUNCTION) @@ -4462,10 +4473,8 @@ end_with_restore_list: if (udf) { - my_error(ER_UDF_EXISTS, MYF(0), name); - delete lex->sphead; - lex->sphead= 0; - goto error; + my_error(ER_UDF_EXISTS, MYF(0), name); + goto create_sp_error; } } #endif @@ -4473,7 +4482,7 @@ end_with_restore_list: /* If the definer is not specified, this means that CREATE-statement missed DEFINER-clause. DEFINER-clause can be missed in two cases: - + - The user submitted a statement w/o the clause. This is a normal case, we should assign CURRENT_USER as definer. @@ -4482,7 +4491,7 @@ end_with_restore_list: CURRENT_USER as definer here, but also we should mark this routine as NON-SUID. This is essential for the sake of backward compatibility. - + The problem is the slave thread is running under "special" user (@), that actually does not exist. In the older versions we do not fail execution of a stored routine if its definer does not exist and @@ -4507,13 +4516,9 @@ end_with_restore_list: if (ps_arena) thd->restore_active_arena(ps_arena, &original_arena); + /* Error has been already reported. */ if (res) - { - /* Error has been already reported. */ - delete lex->sphead; - lex->sphead= 0; - goto error; - } + goto create_sp_error; if (thd->slave_thread) lex->sphead->m_chistics->suid= SP_IS_NOT_SUID; @@ -4524,7 +4529,7 @@ end_with_restore_list: that the current user has SUPER privilege (in order to create a stored routine under another user one must have SUPER privilege). */ - + else if (strcmp(lex->definer->user.str, thd->security_ctx->priv_user) || my_strcasecmp(system_charset_info, lex->definer->host.str, @@ -4533,9 +4538,7 @@ end_with_restore_list: if (check_global_access(thd, SUPER_ACL)) { my_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, MYF(0), "SUPER"); - delete lex->sphead; - lex->sphead= 0; - goto error; + goto create_sp_error; } } @@ -4555,54 +4558,51 @@ end_with_restore_list: #endif /* NO_EMBEDDED_ACCESS_CHECKS */ res= (result= lex->sphead->create(thd)); - if (result == SP_OK) - { + switch (result) { + case SP_OK: #ifndef NO_EMBEDDED_ACCESS_CHECKS /* only add privileges if really neccessary */ if (sp_automatic_privileges && !opt_noacl && check_routine_access(thd, DEFAULT_CREATE_PROC_ACLS, - lex->sphead->m_db.str, name, + lex->sphead->m_db.str, name, lex->sql_command == SQLCOM_CREATE_PROCEDURE, 1)) { if (sp_grant_privileges(thd, lex->sphead->m_db.str, name, lex->sql_command == SQLCOM_CREATE_PROCEDURE)) - push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, - ER_PROC_AUTO_GRANT_FAIL, - ER(ER_PROC_AUTO_GRANT_FAIL)); + push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_PROC_AUTO_GRANT_FAIL, + ER(ER_PROC_AUTO_GRANT_FAIL)); close_thread_tables(thd); } #endif - lex->unit.cleanup(); - delete lex->sphead; - lex->sphead= 0; - send_ok(thd); - } - else - { - switch (result) { - case SP_WRITE_ROW_FAILED: - my_error(ER_SP_ALREADY_EXISTS, MYF(0), SP_TYPE_STRING(lex), name); - break; - case SP_NO_DB_ERROR: - my_error(ER_BAD_DB_ERROR, MYF(0), lex->sphead->m_db.str); - break; - case SP_BAD_IDENTIFIER: - my_error(ER_TOO_LONG_IDENT, MYF(0), name); - break; - case SP_BODY_TOO_LONG: - my_error(ER_TOO_LONG_BODY, MYF(0), name); - break; - default: - my_error(ER_SP_STORE_FAILED, MYF(0), SP_TYPE_STRING(lex), name); - break; - } - lex->unit.cleanup(); - delete lex->sphead; - lex->sphead= 0; - goto error; - } break; - } + case SP_WRITE_ROW_FAILED: + my_error(ER_SP_ALREADY_EXISTS, MYF(0), SP_TYPE_STRING(lex), name); + break; + case SP_BAD_IDENTIFIER: + my_error(ER_TOO_LONG_IDENT, MYF(0), name); + break; + case SP_BODY_TOO_LONG: + my_error(ER_TOO_LONG_BODY, MYF(0), name); + break; + default: + my_error(ER_SP_STORE_FAILED, MYF(0), SP_TYPE_STRING(lex), name); + break; + } /* end switch */ + + /* + Capture all errors within this CASE and + clean up the environment. + */ +create_sp_error: + lex->unit.cleanup(); + delete lex->sphead; + lex->sphead= 0; + if (result != SP_OK ) + goto error; + send_ok(thd); + break; /* break super switch */ + } /* end case group bracket */ case SQLCOM_CALL: { sp_head *sp; @@ -4678,8 +4678,6 @@ end_with_restore_list: select_limit= thd->variables.select_limit; thd->variables.select_limit= HA_POS_ERROR; - thd->row_count_func= 0; - /* We never write CALL statements into binlog: - If the mode is non-prelocked, each statement will be logged @@ -6974,7 +6972,10 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables, than it would help them) */ tmp_write_to_binlog= 0; - mysql_bin_log.rotate_and_purge(RP_FORCE_ROTATE); + if( mysql_bin_log.is_open() ) + { + mysql_bin_log.rotate_and_purge(RP_FORCE_ROTATE); + } #ifdef HAVE_REPLICATION pthread_mutex_lock(&LOCK_active_mi); rotate_relay_log(active_mi); diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 75d7f4c9fbf..165a82e4b27 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -37,7 +37,9 @@ static char *make_unique_key_name(const char *field_name,KEY *start,KEY *end); static int copy_data_between_tables(TABLE *from,TABLE *to, List<create_field> &create, bool ignore, uint order_num, ORDER *order, - ha_rows *copied,ha_rows *deleted); + ha_rows *copied,ha_rows *deleted, + enum enum_enable_or_disable keys_onoff); + static bool prepare_blob_field(THD *thd, create_field *sql_field); static bool check_engine(THD *thd, const char *table_name, HA_CREATE_INFO *create_info); @@ -5196,6 +5198,54 @@ static uint compare_tables(TABLE *table, List<create_field> *create_list, /* + Manages enabling/disabling of indexes for ALTER TABLE + + SYNOPSIS + alter_table_manage_keys() + table Target table + indexes_were_disabled Whether the indexes of the from table + were disabled + keys_onoff ENABLE | DISABLE | LEAVE_AS_IS + + RETURN VALUES + FALSE OK + TRUE Error +*/ + +static +bool alter_table_manage_keys(TABLE *table, int indexes_were_disabled, + enum enum_enable_or_disable keys_onoff) +{ + int error= 0; + DBUG_ENTER("alter_table_manage_keys"); + DBUG_PRINT("enter", ("table=%p were_disabled=%d on_off=%d", + table, indexes_were_disabled, keys_onoff)); + + switch (keys_onoff) { + case ENABLE: + error= table->file->enable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE); + break; + case LEAVE_AS_IS: + if (!indexes_were_disabled) + break; + /* fall-through: disabled indexes */ + case DISABLE: + error= table->file->disable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE); + } + + if (error == HA_ERR_WRONG_COMMAND) + { + push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_NOTE, + ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA), table->s->table_name); + error= 0; + } else if (error) + table->file->print_error(error, MYF(0)); + + DBUG_RETURN(error); +} + + +/* Alter table */ @@ -5443,13 +5493,35 @@ view_err: if (!(alter_info->flags & ~(ALTER_RENAME | ALTER_KEYS_ONOFF)) && !table->s->tmp_table) // no need to touch frm { - error=0; VOID(pthread_mutex_lock(&LOCK_open)); - if (new_name != table_name || new_db != db) + + switch (alter_info->keys_onoff) { + case LEAVE_AS_IS: + error= 0; + break; + case ENABLE: + wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN); + error= table->file->enable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE); + /* COND_refresh will be signaled in close_thread_tables() */ + break; + case DISABLE: + wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN); + error=table->file->disable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE); + /* COND_refresh will be signaled in close_thread_tables() */ + break; + } + if (error == HA_ERR_WRONG_COMMAND) + { + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, + ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA), + table->alias); + error= 0; + } + + if (!error && (new_name != table_name || new_db != db)) { thd->proc_info="rename"; /* Then do a 'simple' rename of the table */ - error=0; if (!access(new_name_buff,F_OK)) { my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_name); @@ -5472,31 +5544,14 @@ view_err: } } - if (!error) - { - switch (alter_info->keys_onoff) { - case LEAVE_AS_IS: - break; - case ENABLE: - wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN); - error= table->file->enable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE); - /* COND_refresh will be signaled in close_thread_tables() */ - break; - case DISABLE: - wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN); - error=table->file->disable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE); - /* COND_refresh will be signaled in close_thread_tables() */ - break; - } - } - if (error == HA_ERR_WRONG_COMMAND) { push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA), table->alias); - error=0; + error= 0; } + if (!error) { write_bin_log(thd, TRUE, thd->query, thd->query_length); @@ -5509,7 +5564,7 @@ view_err: error= -1; } VOID(pthread_mutex_unlock(&LOCK_open)); - table_list->table=0; // For query cache + table_list->table= NULL; // For query cache query_cache_invalidate3(thd, table_list, 0); DBUG_RETURN(error); } @@ -6112,7 +6167,18 @@ view_err: new_table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET; new_table->next_number_field=new_table->found_next_number_field; error=copy_data_between_tables(table, new_table, create_list, ignore, - order_num, order, &copied, &deleted); + order_num, order, &copied, &deleted, + alter_info->keys_onoff); + } + else + { + VOID(pthread_mutex_lock(&LOCK_open)); + wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN); + table->file->ha_external_lock(thd, F_WRLCK); + alter_table_manage_keys(table, table->file->indexes_are_disabled(), + alter_info->keys_onoff); + table->file->ha_external_lock(thd, F_UNLCK); + VOID(pthread_mutex_unlock(&LOCK_open)); } thd->count_cuted_fields= CHECK_FIELD_IGNORE; @@ -6529,7 +6595,8 @@ copy_data_between_tables(TABLE *from,TABLE *to, bool ignore, uint order_num, ORDER *order, ha_rows *copied, - ha_rows *deleted) + ha_rows *deleted, + enum enum_enable_or_disable keys_onoff) { int error; Copy_field *copy,*copy_end; @@ -6563,6 +6630,9 @@ copy_data_between_tables(TABLE *from,TABLE *to, if (to->file->ha_external_lock(thd, F_WRLCK)) DBUG_RETURN(-1); + /* We need external lock before we can disable/enable keys */ + alter_table_manage_keys(to, from->file->indexes_are_disabled(), keys_onoff); + /* We can abort alter table for any table type */ thd->no_trans_update= 0; thd->abort_on_warning= !ignore && test(thd->variables.sql_mode & diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index fcac7eb8e05..434cd0e4cd5 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -6426,7 +6426,7 @@ function_call_generic: } } /* Temporary placing the result of find_udf in $3 */ - lex->current_select->udf_list.push_front(udf); + $<udf>$= udf; #endif } udf_expr_list ')' @@ -6454,10 +6454,10 @@ function_call_generic: { #ifdef HAVE_DLOPEN /* Retrieving the result of find_udf */ - udf_func *udf; + udf_func *udf= $<udf>3; LEX *lex= Lex; - if (NULL != (udf= lex->current_select->udf_list.pop())) + if (udf) { if (udf->type == UDFTYPE_AGGREGATE) { @@ -6553,7 +6553,6 @@ udf_expr_list3: udf_expr: remember_name expr remember_end select_alias { - udf_func *udf= Select->udf_list.head(); /* Use Item::name as a storage for the attribute value of user defined function argument. It is safe to use Item::name @@ -6562,20 +6561,10 @@ udf_expr: */ if ($4.str) { - if (!udf) - { - /* - Disallow using AS to specify explicit names for the arguments - of stored routine calls - */ - yyerror(ER(ER_SYNTAX_ERROR)); - YYABORT; - } - $2->is_autogenerated_name= FALSE; $2->set_name($4.str, $4.length, system_charset_info); } - else if (udf) + else $2->set_name($1, (uint) ($3 - $1), YYTHD->charset()); $$= $2; } diff --git a/sql/udf_example.c b/sql/udf_example.c index 2fa7474eb16..bbab47e253d 100644 --- a/sql/udf_example.c +++ b/sql/udf_example.c @@ -165,6 +165,9 @@ void avgcost_reset( UDF_INIT* initid, UDF_ARGS* args, char* is_null, char *error void avgcost_clear( UDF_INIT* initid, char* is_null, char *error ); void avgcost_add( UDF_INIT* initid, UDF_ARGS* args, char* is_null, char *error ); double avgcost( UDF_INIT* initid, UDF_ARGS* args, char* is_null, char *error ); +my_bool is_const_init(UDF_INIT *initid, UDF_ARGS *args, char *message); +char *is_const(UDF_INIT *initid, UDF_ARGS *args, char *result, unsigned long + *length, char *is_null, char *error); /************************************************************************* @@ -1075,4 +1078,32 @@ char *myfunc_argument_name(UDF_INIT *initid __attribute__((unused)), return result; } + + +my_bool is_const_init(UDF_INIT *initid, UDF_ARGS *args, char *message) +{ + if (args->arg_count != 1) + { + strmov(message, "IS_CONST accepts only one argument"); + return 1; + } + initid->ptr= (char*)((args->args[0] != NULL) ? 1 : 0); + return 0; +} + +char * is_const(UDF_INIT *initid, UDF_ARGS *args __attribute__((unused)), + char *result, unsigned long *length, + char *is_null, char *error __attribute__((unused))) +{ + if (initid->ptr != 0) { + sprintf(result, "const"); + } else { + sprintf(result, "not const"); + } + *is_null= 0; + *length= strlen(result); + return result; +} + + #endif /* HAVE_DLOPEN */ diff --git a/sql/udf_example.def b/sql/udf_example.def index d3081ca7768..ee107d58e51 100644 --- a/sql/udf_example.def +++ b/sql/udf_example.def @@ -22,3 +22,5 @@ EXPORTS avgcost_add avgcost_clear avgcost + is_const + is_const_init |