summaryrefslogtreecommitdiff
path: root/sql/sql_yacc.yy
diff options
context:
space:
mode:
Diffstat (limited to 'sql/sql_yacc.yy')
-rw-r--r--sql/sql_yacc.yy146
1 files changed, 104 insertions, 42 deletions
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 6a829171125..704c505ded9 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -97,6 +97,17 @@ void turn_parser_debug_on()
}
#endif
+static bool is_native_function(THD *thd, const LEX_STRING *name)
+{
+ if (find_native_function_builder(thd, *name))
+ return true;
+
+ if (is_lex_native_function(name))
+ return true;
+
+ return false;
+}
+
%}
%union {
int num;
@@ -735,7 +746,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
LEX_HOSTNAME ULONGLONG_NUM field_ident select_alias ident ident_or_text
UNDERSCORE_CHARSET IDENT_sys TEXT_STRING_sys TEXT_STRING_literal
NCHAR_STRING opt_component key_cache_name
- sp_opt_label BIN_NUM label_ident TEXT_STRING_filesystem
+ sp_opt_label BIN_NUM label_ident TEXT_STRING_filesystem ident_or_empty
%type <lex_str_ptr>
opt_table_alias
@@ -745,7 +756,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%type <simple_string>
remember_name remember_end opt_ident opt_db text_or_password
- opt_constraint constraint ident_or_empty
+ opt_constraint constraint
%type <string>
text_string opt_gconcat_separator
@@ -797,8 +808,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%type <item_list>
expr_list udf_expr_list udf_expr_list2 when_list
- ident_list ident_list_arg
- expr_list_opt
+ ident_list ident_list_arg opt_expr_list
%type <var_type>
option_type opt_var_type opt_var_ident_type
@@ -1229,7 +1239,8 @@ create:
lex->create_info.options=$2 | $4;
lex->create_info.db_type= lex->thd->variables.table_type;
lex->create_info.default_table_charset= NULL;
- lex->name= 0;
+ lex->name.str= 0;
+ lex->name.length= 0;
lex->like_name= 0;
}
create2
@@ -1269,7 +1280,7 @@ create:
{
LEX *lex=Lex;
lex->sql_command=SQLCOM_CREATE_DB;
- lex->name=$4.str;
+ lex->name= $4;
lex->create_info.options=$3;
}
| CREATE
@@ -1504,7 +1515,7 @@ clear_privileges:
sp_name:
ident '.' ident
{
- if (!$1.str || check_db_name($1.str))
+ if (!$1.str || check_db_name(&$1))
{
my_error(ER_WRONG_DB_NAME, MYF(0), $1.str);
YYABORT;
@@ -1537,6 +1548,7 @@ sp_name:
create_function_tail:
RETURNS_SYM udf_type SONAME_SYM TEXT_STRING_sys
{
+ THD *thd= YYTHD;
LEX *lex=Lex;
if (lex->definer != NULL)
{
@@ -1549,6 +1561,12 @@ create_function_tail:
my_error(ER_WRONG_USAGE, MYF(0), "SONAME", "DEFINER");
YYABORT;
}
+ if (is_native_function(thd, & lex->spname->m_name))
+ {
+ my_error(ER_NATIVE_FCT_NAME_COLLISION, MYF(0),
+ lex->spname->m_name.str);
+ YYABORT;
+ }
lex->sql_command = SQLCOM_CREATE_FUNCTION;
lex->udf.name = lex->spname->m_name;
lex->udf.returns=(Item_result) $2;
@@ -1637,6 +1655,7 @@ create_function_tail:
}
sp_proc_stmt
{
+ THD *thd= YYTHD;
LEX *lex= Lex;
sp_head *sp= lex->sphead;
@@ -1644,15 +1663,50 @@ create_function_tail:
YYABORT;
lex->sql_command= SQLCOM_CREATE_SPFUNCTION;
- sp->init_strings(YYTHD, lex);
+ sp->init_strings(thd, lex);
if (!(sp->m_flags & sp_head::HAS_RETURN))
{
my_error(ER_SP_NORETURN, MYF(0), sp->m_qname.str);
YYABORT;
}
+ if (is_native_function(thd, & sp->m_name))
+ {
+ /*
+ This warning will be printed when
+ [1] A client query is parsed,
+ [2] A stored function is loaded by db_load_routine.
+ Printing the warning for [2] is intentional, to cover the
+ following scenario:
+ - A user define a SF 'foo' using MySQL 5.N
+ - An application uses select foo(), and works.
+ - MySQL 5.{N+1} defines a new native function 'foo', as
+ part of a new feature.
+ - MySQL 5.{N+1} documentation is updated, and should mention
+ that there is a potential incompatible change in case of
+ existing stored function named 'foo'.
+ - The user deploys 5.{N+1}. At this point, 'select foo()'
+ means something different, and the user code is most likely
+ broken (it's only safe if the code is 'select db.foo()').
+ With a warning printed when the SF is loaded (which has to occur
+ before the call), the warning will provide a hint explaining
+ the root cause of a later failure of 'select foo()'.
+ With no warning printed, the user code will fail with no
+ apparent reason.
+ Printing a warning each time db_load_routine is executed for
+ an ambiguous function is annoying, since that can happen a lot,
+ but in practice should not happen unless there *are* name
+ collisions.
+ If a collision exists, it should not be silenced but fixed.
+ */
+ push_warning_printf(thd,
+ MYSQL_ERROR::WARN_LEVEL_NOTE,
+ ER_NATIVE_FCT_NAME_COLLISION,
+ ER(ER_NATIVE_FCT_NAME_COLLISION),
+ sp->m_name.str);
+ }
/* Restore flag if it was cleared above */
- YYTHD->client_capabilities |= $<ulong_num>2;
- sp->restore_thd_mem_root(YYTHD);
+ thd->client_capabilities |= $<ulong_num>2;
+ sp->restore_thd_mem_root(thd);
}
;
@@ -1894,7 +1948,6 @@ sp_decl:
uint num_vars= pctx->context_var_count();
enum enum_field_types var_type= (enum enum_field_types) $4;
Item *dflt_value_item= $5;
- create_field *create_field_op;
if (!dflt_value_item)
{
@@ -3090,11 +3143,11 @@ size_number:
real_ulong_num { $$= $1;}
| IDENT
{
- ulonglong number, test_number;
+ ulonglong number;
uint text_shift_number= 0;
longlong prefix_number;
char *start_ptr= $1.str;
- uint str_len= strlen(start_ptr);
+ uint str_len= $1.length;
char *end_ptr= start_ptr + str_len;
int error;
prefix_number= my_strtoll10(start_ptr, &end_ptr, &error);
@@ -3599,11 +3652,9 @@ part_bit_expr:
bit_expr
{
Item *part_expr= $1;
- bool not_corr_func;
int part_expression_ok= 1;
LEX *lex= Lex;
THD *thd= YYTHD;
- longlong item_value;
Name_resolution_context *context= &lex->current_select->context;
TABLE_LIST *save_list= context->table_list;
const char *save_where= thd->where;
@@ -3744,11 +3795,11 @@ opt_part_option:
lex->part_info->default_engine_type= $4;
}
| NODEGROUP_SYM opt_equal real_ulong_num
- { Lex->part_info->curr_part_elem->nodegroup_id= $3; }
+ { Lex->part_info->curr_part_elem->nodegroup_id= (uint16) $3; }
| MAX_ROWS opt_equal real_ulonglong_num
- { Lex->part_info->curr_part_elem->part_max_rows= $3; }
+ { Lex->part_info->curr_part_elem->part_max_rows= (ha_rows) $3; }
| MIN_ROWS opt_equal real_ulonglong_num
- { Lex->part_info->curr_part_elem->part_min_rows= $3; }
+ { Lex->part_info->curr_part_elem->part_min_rows= (ha_rows) $3; }
| DATA_SYM DIRECTORY_SYM opt_equal TEXT_STRING_sys
{ Lex->part_info->curr_part_elem->data_file_name= $4.str; }
| INDEX_SYM DIRECTORY_SYM opt_equal TEXT_STRING_sys
@@ -4618,7 +4669,8 @@ alter:
{
THD *thd= YYTHD;
LEX *lex= thd->lex;
- lex->name= 0;
+ lex->name.str= 0;
+ lex->name.length= 0;
lex->sql_command= SQLCOM_ALTER_TABLE;
lex->duplicates= DUP_ERROR;
if (!lex->select_lex.add_table_to_list(thd, $4, NULL,
@@ -4628,7 +4680,6 @@ alter:
lex->key_list.empty();
lex->col_list.empty();
lex->select_lex.init_order();
- lex->name= 0;
lex->like_name= 0;
lex->select_lex.db=
((TABLE_LIST*) lex->select_lex.table_list.first)->db;
@@ -4653,7 +4704,8 @@ alter:
THD *thd= Lex->thd;
lex->sql_command=SQLCOM_ALTER_DB;
lex->name= $3;
- if (lex->name == NULL && thd->copy_db_to(&lex->name, NULL))
+ if (lex->name.str == NULL &&
+ thd->copy_db_to(&lex->name.str, &lex->name.length))
YYABORT;
}
| ALTER PROCEDURE sp_name
@@ -4803,8 +4855,8 @@ opt_ev_sql_stmt: /* empty*/ { $$= 0;}
ident_or_empty:
- /* empty */ { $$= 0; }
- | ident { $$= $1.str; };
+ /* empty */ { $$.str= 0; $$.length= 0; }
+ | ident { $$= $1; };
alter_commands:
| DISCARD TABLESPACE { Lex->alter_info.tablespace_op= DISCARD_TABLESPACE; }
@@ -4816,7 +4868,7 @@ alter_commands:
| remove_partitioning
| partitioning
/*
- This part was added for release 5.1 by Mikael Ronström.
+ This part was added for release 5.1 by Mikael Ronström.
From here we insert a number of commands to manage the partitions of a
partitioned table such as adding partitions, dropping partitions,
reorganising partitions in various manners. In future releases the list
@@ -5082,19 +5134,20 @@ alter_list_item:
{
LEX *lex=Lex;
THD *thd= lex->thd;
+ uint dummy;
lex->select_lex.db=$3->db.str;
if (lex->select_lex.db == NULL &&
- thd->copy_db_to(&lex->select_lex.db, NULL))
+ thd->copy_db_to(&lex->select_lex.db, &dummy))
{
YYABORT;
}
if (check_table_name($3->table.str,$3->table.length) ||
- $3->db.str && check_db_name($3->db.str))
+ $3->db.str && check_db_name(&$3->db))
{
my_error(ER_WRONG_TABLE_NAME, MYF(0), $3->table.str);
YYABORT;
}
- lex->name= $3->table.str;
+ lex->name= $3->table;
lex->alter_info.flags|= ALTER_RENAME;
}
| CONVERT_SYM TO_SYM charset charset_name_or_default opt_collate
@@ -6361,11 +6414,11 @@ function_call_generic:
{
#ifdef HAVE_DLOPEN
udf_func *udf= 0;
+ LEX *lex= Lex;
if (using_udf_functions &&
(udf= find_udf($1.str, $1.length)) &&
udf->type == UDFTYPE_AGGREGATE)
{
- LEX *lex= Lex;
if (lex->current_select->inc_in_sum_expr())
{
yyerror(ER(ER_SYNTAX_ERROR));
@@ -6376,7 +6429,7 @@ function_call_generic:
$<udf>$= udf;
#endif
}
- expr_list_opt ')'
+ udf_expr_list ')'
{
THD *thd= YYTHD;
LEX *lex= Lex;
@@ -6402,6 +6455,7 @@ function_call_generic:
#ifdef HAVE_DLOPEN
/* Retrieving the result of find_udf */
udf_func *udf= $<udf>3;
+ LEX *lex= Lex;
if (udf)
{
@@ -6426,7 +6480,7 @@ function_call_generic:
YYABORT;
}
}
- | ident '.' ident '(' udf_expr_list ')'
+ | ident '.' ident '(' opt_expr_list ')'
{
THD *thd= YYTHD;
Create_qfunc *builder;
@@ -6499,6 +6553,12 @@ udf_expr_list3:
udf_expr:
remember_name expr remember_end select_alias
{
+ /*
+ Use Item::name as a storage for the attribute value of user
+ defined function argument. It is safe to use Item::name
+ because the syntax will not allow having an explicit name here.
+ See WL#1017 re. udf attributes.
+ */
if ($4.str)
{
$2->is_autogenerated_name= FALSE;
@@ -6665,12 +6725,10 @@ cast_type:
| DECIMAL_SYM float_options { $$=ITEM_CAST_DECIMAL; Lex->charset= NULL; }
;
-expr_list_opt:
- /* empty */
- { $$ = NULL; }
- | expr_list
- { $$ = $1;}
- ;
+opt_expr_list:
+ /* empty */ { $$= NULL; }
+ | expr_list { $$= $1;}
+ ;
expr_list:
{ Select->expr_list.push_front(new List<Item>); }
@@ -7627,7 +7685,7 @@ drop:
LEX *lex=Lex;
lex->sql_command= SQLCOM_DROP_DB;
lex->drop_if_exists=$3;
- lex->name=$4.str;
+ lex->name= $4;
}
| DROP FUNCTION_SYM if_exists sp_name
{
@@ -7669,11 +7727,12 @@ drop:
Lex->spname= $4;
Lex->sql_command = SQLCOM_DROP_EVENT;
}
- | DROP TRIGGER_SYM sp_name
+ | DROP TRIGGER_SYM if_exists sp_name
{
LEX *lex= Lex;
lex->sql_command= SQLCOM_DROP_TRIGGER;
- lex->spname= $3;
+ lex->drop_if_exists= $3;
+ lex->spname= $4;
}
| DROP TABLESPACE tablespace_name opt_ts_engine opt_ts_wait
{
@@ -7684,7 +7743,7 @@ drop:
{
LEX *lex= Lex;
lex->alter_tablespace_info->ts_cmd_type= DROP_LOGFILE_GROUP;
- }
+ }
;
table_list:
@@ -8274,7 +8333,7 @@ show_param:
{
Lex->sql_command=SQLCOM_SHOW_CREATE_DB;
Lex->create_info.options=$3;
- Lex->name=$4.str;
+ Lex->name= $4;
}
| CREATE TABLE_SYM table_ident
{
@@ -8640,6 +8699,8 @@ load_data_lock:
Ignore this option in SP to avoid problem with query cache
*/
if (Lex->sphead != 0)
+ $$= YYTHD->update_lock_default;
+ else
#endif
$$= TL_WRITE_CONCURRENT_INSERT;
}
@@ -10279,7 +10340,8 @@ grant_ident:
{
LEX *lex= Lex;
THD *thd= lex->thd;
- if (thd->copy_db_to(&lex->current_select->db, NULL))
+ uint dummy;
+ if (thd->copy_db_to(&lex->current_select->db, &dummy))
YYABORT;
if (lex->grant == GLOBAL_ACLS)
lex->grant = DB_ACLS & ~GRANT_ACL;