Commit 40ea2b48 authored by unknown's avatar unknown

Manual merge of 5.0-runtime to 5.1-runtime


mysql-test/r/sp-error.result:
  Manual merge
mysql-test/r/sp.result:
  Manual merge
mysql-test/r/udf.result:
  Manual merge
mysql-test/t/sp.test:
  Manual merge
mysql-test/t/udf.test:
  Manual merge
sql/item_create.cc:
  Manual merge
sql/sp_head.cc:
  Manual merge
sql/sql_yacc.yy:
  Manual merge
parent 4466dec3
......@@ -1226,7 +1226,7 @@ ERROR 42S02: Unknown table 'c' in field list
drop procedure bug15091;
drop function if exists bug16896;
create aggregate function bug16896() returns int return 1;
ERROR 42000: AGGREGATE is not supported for stored functions
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '() returns int return 1' at line 1
DROP PROCEDURE IF EXISTS bug14702;
CREATE IF NOT EXISTS PROCEDURE bug14702()
BEGIN
......@@ -1510,3 +1510,16 @@ FETCH cur1 INTO c;
select c;
CLOSE cur1;
END' at line 4
DROP DATABASE IF EXISTS mysqltest;
CREATE DATABASE mysqltest;
USE mysqltest;
DROP DATABASE mysqltest;
SELECT inexistent(), 1 + ,;
ERROR 42000: FUNCTION inexistent does not exist
SELECT inexistent();
ERROR 42000: FUNCTION inexistent does not exist
SELECT .inexistent();
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '()' at line 1
SELECT ..inexistent();
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '.inexistent()' at line 1
USE test;
......@@ -6796,6 +6796,22 @@ f1()
DROP TABLE t1;
DROP FUNCTION f1;
DROP PROCEDURE IF EXISTS db28318_a.t1;
DROP PROCEDURE IF EXISTS db28318_b.t2;
DROP DATABASE IF EXISTS db28318_a;
DROP DATABASE IF EXISTS db28318_b;
CREATE DATABASE db28318_a;
CREATE DATABASE db28318_b;
CREATE PROCEDURE db28318_a.t1() SELECT "db28318_a.t1";
CREATE PROCEDURE db28318_b.t2() CALL t1();
use db28318_a;
CALL db28318_b.t2();
ERROR 42000: PROCEDURE db28318_b.t1 does not exist
DROP PROCEDURE db28318_a.t1;
DROP PROCEDURE db28318_b.t2;
DROP DATABASE db28318_a;
DROP DATABASE db28318_b;
use test;
End of 5.0 tests
#
......
......@@ -95,10 +95,10 @@ FR
DROP TABLE bug19904;
CREATE DEFINER=CURRENT_USER() FUNCTION should_not_parse
RETURNS STRING SONAME "should_not_parse.so";
ERROR HY000: Incorrect usage of SONAME and DEFINER
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'RETURNS STRING SONAME "should_not_parse.so"' at line 2
CREATE DEFINER=someone@somewhere FUNCTION should_not_parse
RETURNS STRING SONAME "should_not_parse.so";
ERROR HY000: Incorrect usage of SONAME and DEFINER
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'RETURNS STRING SONAME "should_not_parse.so"' at line 2
create table t1(f1 int);
insert into t1 values(1),(2);
explain select myfunc_int(f1) from t1 order by 1;
......@@ -214,7 +214,7 @@ DROP FUNCTION IF EXISTS metaphon;
CREATE FUNCTION metaphon(a int) RETURNS int
return 0;
CREATE FUNCTION metaphon RETURNS STRING SONAME "UDF_EXAMPLE_LIB";
ERROR HY000: Function 'metaphon' already exists
DROP FUNCTION metaphon;
DROP FUNCTION metaphon;
CREATE FUNCTION metaphon RETURNS STRING SONAME "UDF_EXAMPLE_LIB";
CREATE FUNCTION metaphon(a int) RETURNS int
......@@ -334,6 +334,13 @@ Qcache_queries_in_cache 0
drop table t1;
drop function metaphon;
set GLOBAL query_cache_size=default;
DROP DATABASE IF EXISTS mysqltest;
CREATE DATABASE mysqltest;
USE mysqltest;
DROP DATABASE mysqltest;
CREATE FUNCTION metaphon RETURNS STRING SONAME "UDF_EXAMPLE_LIB";
DROP FUNCTION metaphon;
USE test;
CREATE TABLE const_len_bug (
str_const varchar(4000),
result1 varchar(4000),
......
......@@ -7871,6 +7871,37 @@ DROP FUNCTION f1;
###########################################################################
#
# Bug#28318 (CREATE FUNCTION (UDF) requires a schema)
#
--disable_warnings
DROP PROCEDURE IF EXISTS db28318_a.t1;
DROP PROCEDURE IF EXISTS db28318_b.t2;
DROP DATABASE IF EXISTS db28318_a;
DROP DATABASE IF EXISTS db28318_b;
--enable_warnings
CREATE DATABASE db28318_a;
CREATE DATABASE db28318_b;
CREATE PROCEDURE db28318_a.t1() SELECT "db28318_a.t1";
CREATE PROCEDURE db28318_b.t2() CALL t1();
use db28318_a;
# In db28318_b.t2, t1 refers to db28318_b.t1
--error ER_SP_DOES_NOT_EXIST
CALL db28318_b.t2();
DROP PROCEDURE db28318_a.t1;
DROP PROCEDURE db28318_b.t2;
DROP DATABASE db28318_a;
DROP DATABASE db28318_b;
use test;
###########################################################################
--echo End of 5.0 tests
###########################################################################
......
......@@ -206,10 +206,11 @@ DROP FUNCTION IF EXISTS metaphon;
CREATE FUNCTION metaphon(a int) RETURNS int
return 0;
# this currently passes, and eclipse the stored function
--replace_result $UDF_EXAMPLE_LIB UDF_EXAMPLE_LIB
--error ER_UDF_EXISTS
eval CREATE FUNCTION metaphon RETURNS STRING SONAME "$UDF_EXAMPLE_LIB";
DROP FUNCTION metaphon;
DROP FUNCTION metaphon;
--replace_result $UDF_EXAMPLE_LIB UDF_EXAMPLE_LIB
......
......@@ -2326,6 +2326,25 @@ Item*
Create_qfunc::create(THD *thd, LEX_STRING name, List<Item> *item_list)
{
LEX_STRING db;
if (! thd->db && ! thd->lex->sphead)
{
/*
The proper error message should be in the lines of:
Can't resolve <name>() to a function call,
because this function:
- is not a native function,
- is not a user defined function,
- can not match a qualified (read: stored) function
since no database is selected.
Reusing ER_SP_DOES_NOT_EXIST have a message consistent with
the case when a default database exist, see Create_sp_func::create().
*/
my_error(ER_SP_DOES_NOT_EXIST, MYF(0),
"FUNCTION", name.str);
return NULL;
}
if (thd->lex->copy_db_to(&db.str, &db.length))
return NULL;
......
......@@ -386,17 +386,43 @@ sp_eval_expr(THD *thd, Field *result_field, Item **expr_item_ptr)
*
*/
sp_name::sp_name(THD *thd, char *key, uint key_len)
{
m_sroutines_key.str= key;
m_sroutines_key.length= key_len;
m_qname.str= ++key;
m_qname.length= key_len - 1;
if ((m_name.str= strchr(m_qname.str, '.')))
{
m_db.length= m_name.str - key;
m_db.str= strmake_root(thd->mem_root, key, m_db.length);
m_name.str++;
m_name.length= m_qname.length - m_db.length - 1;
}
else
{
m_name.str= m_qname.str;
m_name.length= m_qname.length;
m_db.str= 0;
m_db.length= 0;
}
m_explicit_name= false;
}
void
sp_name::init_qname(THD *thd)
{
m_sroutines_key.length= m_db.length + m_name.length + 2;
const uint dot= !!m_db.length;
/* m_sroutines format: m_type + [database + dot] + name + nul */
m_sroutines_key.length= 1 + m_db.length + dot + m_name.length;
if (!(m_sroutines_key.str= (char*) thd->alloc(m_sroutines_key.length + 1)))
return;
m_qname.length= m_sroutines_key.length - 1;
m_qname.str= m_sroutines_key.str + 1;
sprintf(m_qname.str, "%.*s.%.*s",
(int) m_db.length, (m_db.length ? m_db.str : ""),
(int) m_name.length, m_name.str);
sprintf(m_qname.str, "%.*s%.*s%.*s",
(int) m_db.length, (m_db.length ? m_db.str : ""),
dot, ".",
(int) m_name.length, m_name.str);
}
......
......@@ -1211,8 +1211,6 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%type <cast_type> cast_type
%type <udf_type> udf_func_type
%type <symbol> keyword keyword_sp
%type <lex_user> user grant_user
......@@ -1254,7 +1252,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
ref_list opt_on_delete opt_on_delete_list opt_on_delete_item use
opt_delete_options opt_delete_option varchar nchar nvarchar
opt_outer table_list table_name table_alias_ref_list table_alias_ref
opt_option opt_place
opt_option opt_place
opt_attribute opt_attribute_list attribute column_list column_list_id
opt_column_list grant_privileges grant_ident grant_list grant_option
object_privilege object_privilege_list user_list rename_list
......@@ -1272,14 +1270,15 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
statement sp_suid
sp_c_chistics sp_a_chistics sp_chistic sp_c_chistic xa
load_data opt_field_or_var_spec fields_or_vars opt_load_data_set_spec
definer view_replace_or_algorithm view_replace
view_replace_or_algorithm view_replace
view_algorithm view_or_trigger_or_sp_or_event
view_or_trigger_or_sp_or_event_tail
definer_tail no_definer_tail
view_suid view_tail view_list_opt view_list view_select
view_check_option trigger_tail sp_tail
view_check_option trigger_tail sp_tail sf_tail udf_tail event_tail
install uninstall partition_entry binlog_base64_event
init_key_options key_options key_opts key_opt key_using_alg
server_def server_options_list server_option
definer_opt no_definer definer
END_OF_INPUT
%type <NONE> call sp_proc_stmts sp_proc_stmts1 sp_proc_stmt
......@@ -2002,181 +2001,6 @@ sp_name:
}
;
create_function_tail:
RETURNS_SYM udf_type SONAME_SYM TEXT_STRING_sys
{
THD *thd= YYTHD;
LEX *lex= thd->lex;
if (lex->definer != NULL)
{
/*
DEFINER is a concept meaningful when interpreting SQL code.
UDF functions are compiled.
Using DEFINER with UDF has therefore no semantic,
and is considered a parsing error.
*/
my_error(ER_WRONG_USAGE, MYF(0), "SONAME", "DEFINER");
MYSQL_YYABORT;
}
if (is_native_function(thd, & lex->spname->m_name))
{
my_error(ER_NATIVE_FCT_NAME_COLLISION, MYF(0),
lex->spname->m_name.str);
MYSQL_YYABORT;
}
lex->sql_command = SQLCOM_CREATE_FUNCTION;
lex->udf.name = lex->spname->m_name;
lex->udf.returns=(Item_result) $2;
lex->udf.dl=$4.str;
}
| '('
{
THD *thd= YYTHD;
LEX *lex= thd->lex;
Lex_input_stream *lip= thd->m_lip;
sp_head *sp;
const char* tmp_param_begin;
/*
First check if AGGREGATE was used, in that case it's a
syntax error.
*/
if (lex->udf.type == UDFTYPE_AGGREGATE)
{
my_error(ER_SP_NO_AGGREGATE, MYF(0));
MYSQL_YYABORT;
}
if (lex->sphead)
{
my_error(ER_SP_NO_RECURSIVE_CREATE, MYF(0), "FUNCTION");
MYSQL_YYABORT;
}
/* Order is important here: new - reset - init */
sp= new sp_head();
sp->reset_thd_mem_root(thd);
sp->init(lex);
sp->init_sp_name(thd, lex->spname);
sp->m_type= TYPE_ENUM_FUNCTION;
lex->sphead= sp;
/*
We have to turn off CLIENT_MULTI_QUERIES while parsing a
stored procedure, otherwise yylex will chop it into pieces
at each ';'.
*/
$<ulong_num>$= thd->client_capabilities & CLIENT_MULTI_QUERIES;
thd->client_capabilities &= ~CLIENT_MULTI_QUERIES;
tmp_param_begin= lip->get_cpp_tok_start();
tmp_param_begin++;
lex->sphead->m_param_begin= tmp_param_begin;
}
sp_fdparam_list ')'
{
THD *thd= YYTHD;
LEX *lex= thd->lex;
Lex_input_stream *lip= thd->m_lip;
lex->sphead->m_param_end= lip->get_cpp_tok_start();
}
RETURNS_SYM
{
LEX *lex= Lex;
lex->charset= NULL;
lex->length= lex->dec= NULL;
lex->interval_list.empty();
lex->type= 0;
}
type
{
LEX *lex= Lex;
sp_head *sp= lex->sphead;
/*
This was disabled in 5.1.12. See bug #20701
When collation support in SP is implemented, then this test
should be removed.
*/
if (($8 == MYSQL_TYPE_STRING || $8 == MYSQL_TYPE_VARCHAR)
&& (lex->type & BINCMP_FLAG))
{
my_error(ER_NOT_SUPPORTED_YET, MYF(0), "return value collation");
MYSQL_YYABORT;
}
if (sp->fill_field_definition(YYTHD, lex,
(enum enum_field_types) $8,
&sp->m_return_field_def))
MYSQL_YYABORT;
bzero((char *)&lex->sp_chistics, sizeof(st_sp_chistics));
}
sp_c_chistics
{
THD *thd= YYTHD;
LEX *lex= thd->lex;
Lex_input_stream *lip= thd->m_lip;
lex->sphead->m_chistics= &lex->sp_chistics;
lex->sphead->set_body_start(thd, lip->get_cpp_tok_start());
}
sp_proc_stmt
{
THD *thd= YYTHD;
LEX *lex= thd->lex;
sp_head *sp= lex->sphead;
if (sp->is_not_allowed_in_function("function"))
MYSQL_YYABORT;
lex->sql_command= SQLCOM_CREATE_SPFUNCTION;
sp->set_stmt_end(thd);
if (!(sp->m_flags & sp_head::HAS_RETURN))
{
my_error(ER_SP_NORETURN, MYF(0), sp->m_qname.str);
MYSQL_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 */
thd->client_capabilities |= $<ulong_num>2;
sp->restore_thd_mem_root(thd);
}
;
sp_a_chistics:
/* Empty */ {}
| sp_a_chistics sp_chistic {}
......@@ -4489,11 +4313,10 @@ create_table_option:
}
| TRANSACTIONAL_SYM opt_equal ulong_num
{
Lex->create_info.used_fields|= HA_CREATE_USED_TRANSACTIONAL;
Lex->create_info.used_fields|= HA_CREATE_USED_TRANSACTIONAL;
Lex->create_info.transactional= ($3 != 0 ? HA_CHOICE_YES :
HA_CHOICE_NO);
HA_CHOICE_NO);
}
;
default_charset:
......@@ -4575,7 +4398,7 @@ row_types:
| COMPRESSED_SYM { $$= ROW_TYPE_COMPRESSED; }
| REDUNDANT_SYM { $$= ROW_TYPE_REDUNDANT; }
| COMPACT_SYM { $$= ROW_TYPE_COMPACT; }
| PAGE_SYM { $$= ROW_TYPE_PAGE; }
| PAGE_SYM { $$= ROW_TYPE_PAGE; }
;
merge_insert_types:
......@@ -4589,10 +4412,6 @@ opt_select_from:
| select_from select_lock_type
;
udf_func_type:
/* empty */ { $$ = UDFTYPE_FUNCTION; }
| AGGREGATE_SYM { $$ = UDFTYPE_AGGREGATE; };
udf_type:
STRING_SYM {$$ = (int) STRING_RESULT; }
| REAL {$$ = (int) REAL_RESULT; }
......@@ -5437,7 +5256,7 @@ alter:
lex->sql_command= SQLCOM_ALTER_FUNCTION;
lex->spname= $3;
}
| ALTER view_algorithm definer
| ALTER view_algorithm definer_opt
{
LEX *lex= Lex;
......@@ -5450,7 +5269,7 @@ alter:
}
view_tail
{}
| ALTER definer
| ALTER definer_opt
/*
We have two separate rules for ALTER VIEW rather that
optional view_algorithm above, to resolve the ambiguity
......@@ -5469,7 +5288,7 @@ alter:
}
view_tail
{}
| ALTER definer EVENT_SYM sp_name
| ALTER definer_opt EVENT_SYM sp_name
/*
BE CAREFUL when you add a new rule to update the block where
YYTHD->client_capabilities is set back to original value
......@@ -5505,7 +5324,7 @@ alter:
{
/*
$1 - ALTER
$2 - definer
$2 - definer_opt
$3 - EVENT_SYM
$4 - sp_name
$5 - the block above
......@@ -8559,9 +8378,11 @@ drop:
lex->drop_if_exists=$3;
lex->name= $4;
}
| DROP FUNCTION_SYM if_exists sp_name
| DROP FUNCTION_SYM if_exists ident '.' ident
{
LEX *lex=Lex;
THD *thd= YYTHD;
LEX *lex= thd->lex;
sp_name *spname;
if (lex->sphead)
{
my_error(ER_SP_NO_DROP_SP, MYF(0), "FUNCTION");
......@@ -8569,7 +8390,28 @@ drop:
}
lex->sql_command = SQLCOM_DROP_FUNCTION;
lex->drop_if_exists= $3;
lex->spname= $4;
spname= new sp_name($4, $6, true);
spname->init_qname(thd);
lex->spname= spname;
}
| DROP FUNCTION_SYM if_exists ident
{
THD *thd= YYTHD;
LEX *lex= thd->lex;
LEX_STRING db= {0, 0};
sp_name *spname;
if (lex->sphead)
{
my_error(ER_SP_NO_DROP_SP, MYF(0), "FUNCTION");
MYSQL_YYABORT;
}
if (thd->db && lex->copy_db_to(&db.str, &db.length))
MYSQL_YYABORT;
lex->sql_command = SQLCOM_DROP_FUNCTION;
lex->drop_if_exists= $3;
spname= new sp_name(db, $4, false);
spname->init_qname(thd);
lex->spname= spname;
}
| DROP PROCEDURE if_exists sp_name
{
......@@ -8639,18 +8481,19 @@ table_name:
;
table_alias_ref_list:
table_alias_ref
| table_alias_ref_list ',' table_alias_ref;
table_alias_ref
| table_alias_ref_list ',' table_alias_ref
;
table_alias_ref:
table_ident
{
if (!Select->add_table_to_list(YYTHD, $1, NULL,
TL_OPTION_UPDATING | TL_OPTION_ALIAS,
Lex->lock_option ))
MYSQL_YYABORT;
}
;
table_ident
{
if (!Select->add_table_to_list(YYTHD, $1, NULL,
TL_OPTION_UPDATING | TL_OPTION_ALIAS,
Lex->lock_option ))
MYSQL_YYABORT;
}
;
if_exists:
/* empty */ { $$= 0; }
......@@ -10625,7 +10468,7 @@ keyword_sp:
| TEXT_SYM {}
| THAN_SYM {}
| TRANSACTION_SYM {}
| TRANSACTIONAL_SYM {}
| TRANSACTIONAL_SYM {}
| TRIGGERS_SYM {}
| TIMESTAMP {}
| TIMESTAMP_ADD {}
......@@ -11855,21 +11698,29 @@ subselect_end:
**************************************************************************/
view_or_trigger_or_sp_or_event:
definer view_or_trigger_or_sp_or_event_tail
definer definer_tail
{}
| no_definer no_definer_tail
{}
| view_replace_or_algorithm definer view_tail
| view_replace_or_algorithm definer_opt view_tail
{}
;
view_or_trigger_or_sp_or_event_tail:
definer_tail:
view_tail
{}
| trigger_tail
{}
| sp_tail
{}
| sf_tail
| event_tail
;
no_definer_tail:
view_tail
| trigger_tail
| sp_tail
| sf_tail
| udf_tail
| event_tail
{}
;
/**************************************************************************
......@@ -11878,7 +11729,12 @@ view_or_trigger_or_sp_or_event_tail:
**************************************************************************/
definer:
definer_opt:
no_definer
| definer
;
no_definer:
/* empty */
{
/*
......@@ -11890,7 +11746,10 @@ definer:
*/
YYTHD->lex->definer= 0;
}
| DEFINER_SYM EQ user
;
definer:
DEFINER_SYM EQ user
{
YYTHD->lex->definer= get_current_user(YYTHD, $3);
}
......@@ -12127,17 +11986,193 @@ trigger_tail:
**************************************************************************/
sp_tail:
udf_func_type remember_name FUNCTION_SYM sp_name
udf_tail:
AGGREGATE_SYM remember_name FUNCTION_SYM ident
RETURNS_SYM udf_type SONAME_SYM TEXT_STRING_sys
{
LEX *lex=Lex;
lex->udf.type= $1;
THD *thd= YYTHD;
LEX *lex= thd->lex;
if (is_native_function(thd, & $4))
{
my_error(ER_NATIVE_FCT_NAME_COLLISION, MYF(0),
$4.str);
MYSQL_YYABORT;
}
lex->sql_command = SQLCOM_CREATE_FUNCTION;
lex->udf.type= UDFTYPE_AGGREGATE;
lex->stmt_definition_begin= $2;
lex->spname= $4;
lex->udf.name = $4;
lex->udf.returns=(Item_result) $6;
lex->udf.dl=$8.str;
}
create_function_tail
{}
| PROCEDURE remember_name sp_name
| remember_name FUNCTION_SYM ident
RETURNS_SYM udf_type SONAME_SYM TEXT_STRING_sys
{
THD *thd= YYTHD;
LEX *lex= thd->lex;
if (is_native_function(thd, & $3))
{
my_error(ER_NATIVE_FCT_NAME_COLLISION, MYF(0),
$3.str);
MYSQL_YYABORT;
}
lex->sql_command = SQLCOM_CREATE_FUNCTION;
lex->udf.type= UDFTYPE_FUNCTION;
lex->stmt_definition_begin= $1;
lex->udf.name = $3;
lex->udf.returns=(Item_result) $5;
lex->udf.dl=$7.str;
}
;
sf_tail:
remember_name /* $1 */
FUNCTION_SYM /* $2 */
sp_name /* $3 */
'(' /* $4 */
{ /* $5 */
THD *thd= YYTHD;
LEX *lex= thd->lex;
Lex_input_stream *lip= thd->m_lip;
sp_head *sp;
const char* tmp_param_begin;
lex->stmt_definition_begin= $1;
lex->spname= $3;
if (lex->sphead)
{
my_error(ER_SP_NO_RECURSIVE_CREATE, MYF(0), "FUNCTION");
MYSQL_YYABORT;
}
/* Order is important here: new - reset - init */
sp= new sp_head();
sp->reset_thd_mem_root(thd);
sp->init(lex);
sp->init_sp_name(thd, lex->spname);
sp->m_type= TYPE_ENUM_FUNCTION;
lex->sphead= sp;
/*
We have to turn off CLIENT_MULTI_QUERIES while parsing a
stored procedure, otherwise yylex will chop it into pieces
at each ';'.
*/
$<ulong_num>$= thd->client_capabilities & CLIENT_MULTI_QUERIES;
thd->client_capabilities &= ~CLIENT_MULTI_QUERIES;
tmp_param_begin= lip->get_cpp_tok_start();
tmp_param_begin++;
lex->sphead->m_param_begin= tmp_param_begin;
}
sp_fdparam_list /* $6 */
')' /* $7 */
{ /* $8 */
THD *thd= YYTHD;
LEX *lex= thd->lex;
Lex_input_stream *lip= thd->m_lip;
lex->sphead->m_param_end= lip->get_cpp_tok_start();
}
RETURNS_SYM /* $9 */
{ /* $10 */
LEX *lex= Lex;
lex->charset= NULL;
lex->length= lex->dec= NULL;
lex->interval_list.empty();
lex->type= 0;
}
type /* $11 */
{ /* $12 */
LEX *lex= Lex;
sp_head *sp= lex->sphead;
/*
This was disabled in 5.1.12. See bug #20701
When collation support in SP is implemented, then this test
should be removed.
*/
if (($11 == MYSQL_TYPE_STRING || $11 == MYSQL_TYPE_VARCHAR)
&& (lex->type & BINCMP_FLAG))
{
my_error(ER_NOT_SUPPORTED_YET, MYF(0), "return value collation");
MYSQL_YYABORT;
}
if (sp->fill_field_definition(YYTHD, lex,
(enum enum_field_types) $11,
&sp->m_return_field_def))
MYSQL_YYABORT;
bzero((char *)&lex->sp_chistics, sizeof(st_sp_chistics));
}
sp_c_chistics /* $13 */
{ /* $14 */
THD *thd= YYTHD;
LEX *lex= thd->lex;
Lex_input_stream *lip= thd->m_lip;
lex->sphead->m_chistics= &lex->sp_chistics;
lex->sphead->set_body_start(thd, lip->get_cpp_tok_start());
}
sp_proc_stmt /* $15 */
{
THD *thd= YYTHD;
LEX *lex= thd->lex;
sp_head *sp= lex->sphead;
if (sp->is_not_allowed_in_function("function"))
MYSQL_YYABORT;
lex->sql_command= SQLCOM_CREATE_SPFUNCTION;
sp->set_stmt_end(thd);
if (!(sp->m_flags & sp_head::HAS_RETURN))
{
my_error(ER_SP_NORETURN, MYF(0), sp->m_qname.str);
MYSQL_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 */
thd->client_capabilities |= $<ulong_num>5;
sp->restore_thd_mem_root(thd);
}
;
sp_tail:
PROCEDURE remember_name sp_name
{
LEX *lex= Lex;
sp_head *sp;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment