Commit 5f34513c authored by Alexander Barkov's avatar Alexander Barkov

MDEV-18813 PROCEDURE and anonymous blocks silently ignore FETCH GROUP NEXT ROW

Part#2 (final): rewritting the code to pass the correct enum_sp_aggregate_type
to the sp_head constructor, so sp_head never changes its aggregation type
later on. The grammar has been simplified and defragmented.
This allowed to check aggregate specific instructions right after
a routine body has been scanned, by calling new LEX methods:
  sp_body_finalize_{procedure|function|trigger|event}()

Moving some C++ code from *.yy to a few new helper methods in LEX.
parent a71d185a
...@@ -37,7 +37,7 @@ set x=5; ...@@ -37,7 +37,7 @@ set x=5;
fetch group next row; fetch group next row;
return x+1; return x+1;
end | end |
ERROR HY000: Non-aggregate function contains aggregate specific instructions: (FETCH GROUP NEXT ROW) ERROR HY000: Aggregate specific instruction (FETCH GROUP NEXT ROW) used in a wrong context
create aggregate function f1(x INT) returns INT create aggregate function f1(x INT) returns INT
begin begin
declare continue handler for not found return x; declare continue handler for not found return x;
...@@ -1153,3 +1153,36 @@ i sum(i) ...@@ -1153,3 +1153,36 @@ i sum(i)
NULL 8 NULL 8
drop function agg_sum; drop function agg_sum;
drop table t1; drop table t1;
#
# MDEV-18813 PROCEDURE and anonymous blocks silently ignore FETCH GROUP NEXT ROW
#
CREATE PROCEDURE p1()
BEGIN
FETCH GROUP NEXT ROW;
END;
$$
ERROR HY000: Aggregate specific instruction (FETCH GROUP NEXT ROW) used in a wrong context
BEGIN NOT ATOMIC
FETCH GROUP NEXT ROW;
END;
$$
ERROR HY000: Aggregate specific instruction (FETCH GROUP NEXT ROW) used in a wrong context
CREATE DEFINER=root@localhost FUNCTION f1() RETURNS INT
BEGIN
FETCH GROUP NEXT ROW;
RETURN 0;
END;
$$
ERROR HY000: Aggregate specific instruction (FETCH GROUP NEXT ROW) used in a wrong context
CREATE TABLE t1 (a INT);
CREATE TRIGGER tr1
AFTER INSERT ON t1 FOR EACH ROW
FETCH GROUP NEXT ROW;
ERROR HY000: Aggregate specific instruction (FETCH GROUP NEXT ROW) used in a wrong context
DROP TABLE t1;
CREATE EVENT ev1
ON SCHEDULE EVERY 1 HOUR
STARTS CURRENT_TIMESTAMP + INTERVAL 1 MONTH
ENDS CURRENT_TIMESTAMP + INTERVAL 1 MONTH + INTERVAL 1 WEEK
DO FETCH GROUP NEXT ROW;
ERROR HY000: Aggregate specific instruction (FETCH GROUP NEXT ROW) used in a wrong context
...@@ -965,3 +965,54 @@ select i, sum(i) from t1 group by i with rollup; ...@@ -965,3 +965,54 @@ select i, sum(i) from t1 group by i with rollup;
# Cleanup # Cleanup
drop function agg_sum; drop function agg_sum;
drop table t1; drop table t1;
--echo #
--echo # MDEV-18813 PROCEDURE and anonymous blocks silently ignore FETCH GROUP NEXT ROW
--echo #
DELIMITER $$;
--error ER_NOT_AGGREGATE_FUNCTION
CREATE PROCEDURE p1()
BEGIN
FETCH GROUP NEXT ROW;
END;
$$
DELIMITER ;$$
DELIMITER $$;
--error ER_NOT_AGGREGATE_FUNCTION
BEGIN NOT ATOMIC
FETCH GROUP NEXT ROW;
END;
$$
DELIMITER ;$$
DELIMITER $$;
--error ER_NOT_AGGREGATE_FUNCTION
CREATE DEFINER=root@localhost FUNCTION f1() RETURNS INT
BEGIN
FETCH GROUP NEXT ROW;
RETURN 0;
END;
$$
DELIMITER ;$$
CREATE TABLE t1 (a INT);
--error ER_NOT_AGGREGATE_FUNCTION
CREATE TRIGGER tr1
AFTER INSERT ON t1 FOR EACH ROW
FETCH GROUP NEXT ROW;
DROP TABLE t1;
--error ER_NOT_AGGREGATE_FUNCTION
CREATE EVENT ev1
ON SCHEDULE EVERY 1 HOUR
STARTS CURRENT_TIMESTAMP + INTERVAL 1 MONTH
ENDS CURRENT_TIMESTAMP + INTERVAL 1 MONTH + INTERVAL 1 WEEK
DO FETCH GROUP NEXT ROW;
...@@ -5170,7 +5170,7 @@ RETURN CONCAT(']]>, ', c1, '!'); ...@@ -5170,7 +5170,7 @@ RETURN CONCAT(']]>, ', c1, '!');
<routines> <routines>
<routine Function="straße" sql_mode="" character_set_client="utf8" collation_connection="utf8_general_ci" Database_Collation="latin1_swedish_ci"> <routine Function="straße" sql_mode="" character_set_client="utf8" collation_connection="utf8_general_ci" Database_Collation="latin1_swedish_ci">
<![CDATA[ <![CDATA[
CREATE DEFINER=`root`@`localhost` FUNCTION `straße`( c1 CHAR(20)) RETURNS char(50) CHARSET latin1 CREATE DEFINER=`root`@`localhost` FUNCTION `straße`(c1 CHAR(20)) RETURNS char(50) CHARSET latin1
DETERMINISTIC DETERMINISTIC
RETURN CONCAT(']]]]><![CDATA[>, ', c1, '!') RETURN CONCAT(']]]]><![CDATA[>, ', c1, '!')
]]> ]]>
......
...@@ -11,7 +11,7 @@ set x=5; ...@@ -11,7 +11,7 @@ set x=5;
fetch group next row; fetch group next row;
return x+1; return x+1;
end | end |
ERROR HY000: Non-aggregate function contains aggregate specific instructions: (FETCH GROUP NEXT ROW) ERROR HY000: Aggregate specific instruction (FETCH GROUP NEXT ROW) used in a wrong context
CREATE TABLE marks(stud_id INT, grade_count INT); CREATE TABLE marks(stud_id INT, grade_count INT);
INSERT INTO marks VALUES (1,6), (2,4), (3,7), (4,5), (5,8); INSERT INTO marks VALUES (1,6), (2,4), (3,7), (4,5), (5,8);
SELECT * FROM marks; SELECT * FROM marks;
...@@ -56,3 +56,81 @@ aggregate_count(stud_id) ...@@ -56,3 +56,81 @@ aggregate_count(stud_id)
5 5
DROP FUNCTION IF EXISTS aggregate_count; DROP FUNCTION IF EXISTS aggregate_count;
DROP TABLE marks; DROP TABLE marks;
#
# MDEV-18813 PROCEDURE and anonymous blocks silently ignore FETCH GROUP NEXT ROW
#
CREATE PROCEDURE p1 AS
BEGIN
FETCH GROUP NEXT ROW;
END;
$$
ERROR HY000: Aggregate specific instruction (FETCH GROUP NEXT ROW) used in a wrong context
BEGIN NOT ATOMIC
FETCH GROUP NEXT ROW;
END;
$$
ERROR HY000: Aggregate specific instruction (FETCH GROUP NEXT ROW) used in a wrong context
CREATE DEFINER=root@localhost FUNCTION f1 RETURN INT AS
BEGIN
FETCH GROUP NEXT ROW;
RETURN 0;
END;
$$
ERROR HY000: Aggregate specific instruction (FETCH GROUP NEXT ROW) used in a wrong context
CREATE TABLE t1 (a INT);
CREATE TRIGGER tr1
AFTER INSERT ON t1 FOR EACH ROW
FETCH GROUP NEXT ROW;
ERROR HY000: Aggregate specific instruction (FETCH GROUP NEXT ROW) used in a wrong context
DROP TABLE t1;
CREATE EVENT ev1
ON SCHEDULE EVERY 1 HOUR
STARTS CURRENT_TIMESTAMP + INTERVAL 1 MONTH
ENDS CURRENT_TIMESTAMP + INTERVAL 1 MONTH + INTERVAL 1 WEEK
DO FETCH GROUP NEXT ROW;
ERROR HY000: Aggregate specific instruction (FETCH GROUP NEXT ROW) used in a wrong context
CREATE PACKAGE pkg1 AS
PROCEDURE p1;
FUNCTION f1 RETURN INT;
END;
$$
CREATE PACKAGE BODY pkg1 AS
PROCEDURE p1 AS
BEGIN
FETCH GROUP NEXT ROW; -- In a package procedure
END;
FUNCTION f1 RETURN INT AS
BEGIN
RETURN 0;
END;
END;
$$
ERROR HY000: Aggregate specific instruction (FETCH GROUP NEXT ROW) used in a wrong context
CREATE PACKAGE BODY pkg1 AS
PROCEDURE p1 AS
BEGIN
NULL;
END;
FUNCTION f1 RETURN INT AS
BEGIN
FETCH GROUP NEXT ROW; -- In a package function
RETURN 0;
END;
END;
$$
ERROR HY000: Aggregate specific instruction (FETCH GROUP NEXT ROW) used in a wrong context
CREATE PACKAGE BODY pkg1 AS
PROCEDURE p1 AS
BEGIN
NULL;
END;
FUNCTION f1 RETURN INT AS
BEGIN
RETURN 0;
END;
BEGIN
FETCH GROUP NEXT ROW; -- In a package executable section
END;
$$
ERROR HY000: Aggregate specific instruction (FETCH GROUP NEXT ROW) used in a wrong context
DROP PACKAGE pkg1;
...@@ -64,3 +64,107 @@ DROP FUNCTION IF EXISTS aggregate_count; ...@@ -64,3 +64,107 @@ DROP FUNCTION IF EXISTS aggregate_count;
DROP TABLE marks; DROP TABLE marks;
--echo #
--echo # MDEV-18813 PROCEDURE and anonymous blocks silently ignore FETCH GROUP NEXT ROW
--echo #
DELIMITER $$;
--error ER_NOT_AGGREGATE_FUNCTION
CREATE PROCEDURE p1 AS
BEGIN
FETCH GROUP NEXT ROW;
END;
$$
DELIMITER ;$$
DELIMITER $$;
--error ER_NOT_AGGREGATE_FUNCTION
BEGIN NOT ATOMIC
FETCH GROUP NEXT ROW;
END;
$$
DELIMITER ;$$
DELIMITER $$;
--error ER_NOT_AGGREGATE_FUNCTION
CREATE DEFINER=root@localhost FUNCTION f1 RETURN INT AS
BEGIN
FETCH GROUP NEXT ROW;
RETURN 0;
END;
$$
DELIMITER ;$$
CREATE TABLE t1 (a INT);
--error ER_NOT_AGGREGATE_FUNCTION
CREATE TRIGGER tr1
AFTER INSERT ON t1 FOR EACH ROW
FETCH GROUP NEXT ROW;
DROP TABLE t1;
--error ER_NOT_AGGREGATE_FUNCTION
CREATE EVENT ev1
ON SCHEDULE EVERY 1 HOUR
STARTS CURRENT_TIMESTAMP + INTERVAL 1 MONTH
ENDS CURRENT_TIMESTAMP + INTERVAL 1 MONTH + INTERVAL 1 WEEK
DO FETCH GROUP NEXT ROW;
DELIMITER $$;
CREATE PACKAGE pkg1 AS
PROCEDURE p1;
FUNCTION f1 RETURN INT;
END;
$$
--error ER_NOT_AGGREGATE_FUNCTION
CREATE PACKAGE BODY pkg1 AS
PROCEDURE p1 AS
BEGIN
FETCH GROUP NEXT ROW; -- In a package procedure
END;
FUNCTION f1 RETURN INT AS
BEGIN
RETURN 0;
END;
END;
$$
--error ER_NOT_AGGREGATE_FUNCTION
CREATE PACKAGE BODY pkg1 AS
PROCEDURE p1 AS
BEGIN
NULL;
END;
FUNCTION f1 RETURN INT AS
BEGIN
FETCH GROUP NEXT ROW; -- In a package function
RETURN 0;
END;
END;
$$
--error ER_NOT_AGGREGATE_FUNCTION
CREATE PACKAGE BODY pkg1 AS
PROCEDURE p1 AS
BEGIN
NULL;
END;
FUNCTION f1 RETURN INT AS
BEGIN
RETURN 0;
END;
BEGIN
FETCH GROUP NEXT ROW; -- In a package executable section
END;
$$
DELIMITER ;$$
DROP PACKAGE pkg1;
...@@ -7811,7 +7811,7 @@ ER_ARGUMENT_OUT_OF_RANGE ...@@ -7811,7 +7811,7 @@ ER_ARGUMENT_OUT_OF_RANGE
ER_WRONG_TYPE_OF_ARGUMENT ER_WRONG_TYPE_OF_ARGUMENT
eng "%s function only accepts arguments that can be converted to numerical types" eng "%s function only accepts arguments that can be converted to numerical types"
ER_NOT_AGGREGATE_FUNCTION ER_NOT_AGGREGATE_FUNCTION
eng "Non-aggregate function contains aggregate specific instructions: (FETCH GROUP NEXT ROW)" eng "Aggregate specific instruction (FETCH GROUP NEXT ROW) used in a wrong context"
ER_INVALID_AGGREGATE_FUNCTION ER_INVALID_AGGREGATE_FUNCTION
eng "Aggregate specific instruction(FETCH GROUP NEXT ROW) missing from the aggregate function" eng "Aggregate specific instruction(FETCH GROUP NEXT ROW) missing from the aggregate function"
ER_INVALID_VALUE_TO_LIMIT ER_INVALID_VALUE_TO_LIMIT
......
...@@ -489,7 +489,8 @@ sp_head::operator delete(void *ptr, size_t size) throw() ...@@ -489,7 +489,8 @@ sp_head::operator delete(void *ptr, size_t size) throw()
} }
sp_head::sp_head(sp_package *parent, const Sp_handler *sph) sp_head::sp_head(sp_package *parent, const Sp_handler *sph,
enum_sp_aggregate_type agg_type)
:Query_arena(&main_mem_root, STMT_INITIALIZED_FOR_SP), :Query_arena(&main_mem_root, STMT_INITIALIZED_FOR_SP),
Database_qualified_name(&null_clex_str, &null_clex_str), Database_qualified_name(&null_clex_str, &null_clex_str),
m_parent(parent), m_parent(parent),
...@@ -522,6 +523,7 @@ sp_head::sp_head(sp_package *parent, const Sp_handler *sph) ...@@ -522,6 +523,7 @@ sp_head::sp_head(sp_package *parent, const Sp_handler *sph)
m_pcont(new (&main_mem_root) sp_pcontext()), m_pcont(new (&main_mem_root) sp_pcontext()),
m_cont_level(0) m_cont_level(0)
{ {
set_chistics_agg_type(agg_type);
m_first_instance= this; m_first_instance= this;
m_first_free_instance= this; m_first_free_instance= this;
m_last_cached_sp= this; m_last_cached_sp= this;
...@@ -547,7 +549,7 @@ sp_head::sp_head(sp_package *parent, const Sp_handler *sph) ...@@ -547,7 +549,7 @@ sp_head::sp_head(sp_package *parent, const Sp_handler *sph)
sp_package::sp_package(LEX *top_level_lex, sp_package::sp_package(LEX *top_level_lex,
const sp_name *name, const sp_name *name,
const Sp_handler *sph) const Sp_handler *sph)
:sp_head(NULL, sph), :sp_head(NULL, sph, DEFAULT_AGGREGATE),
m_current_routine(NULL), m_current_routine(NULL),
m_top_level_lex(top_level_lex), m_top_level_lex(top_level_lex),
m_rcontext(NULL), m_rcontext(NULL),
...@@ -2681,6 +2683,17 @@ sp_head::set_chistics(const st_sp_chistics &chistics) ...@@ -2681,6 +2683,17 @@ sp_head::set_chistics(const st_sp_chistics &chistics)
m_chistics.comment.length); m_chistics.comment.length);
} }
void
sp_head::set_c_chistics(const st_sp_chistics &chistics)
{
// Set all chistics but preserve agg_type.
enum_sp_aggregate_type save_agg_type= agg_type();
set_chistics(chistics);
set_chistics_agg_type(save_agg_type);
}
void void
sp_head::set_info(longlong created, longlong modified, sp_head::set_info(longlong created, longlong modified,
const st_sp_chistics &chistics, sql_mode_t sql_mode) const st_sp_chistics &chistics, sql_mode_t sql_mode)
...@@ -5134,6 +5147,36 @@ bool sp_head::spvar_fill_table_rowtype_reference(THD *thd, ...@@ -5134,6 +5147,36 @@ bool sp_head::spvar_fill_table_rowtype_reference(THD *thd,
} }
bool sp_head::check_group_aggregate_instructions_forbid() const
{
if (unlikely(m_flags & sp_head::HAS_AGGREGATE_INSTR))
{
my_error(ER_NOT_AGGREGATE_FUNCTION, MYF(0));
return true;
}
return false;
}
bool sp_head::check_group_aggregate_instructions_require() const
{
if (unlikely(!(m_flags & HAS_AGGREGATE_INSTR)))
{
my_error(ER_INVALID_AGGREGATE_FUNCTION, MYF(0));
return true;
}
return false;
}
bool sp_head::check_group_aggregate_instructions_function() const
{
return agg_type() == GROUP_AGGREGATE ?
check_group_aggregate_instructions_require() :
check_group_aggregate_instructions_forbid();
}
/* /*
In Oracle mode stored routines have an optional name In Oracle mode stored routines have an optional name
at the end of a declaration: at the end of a declaration:
......
...@@ -183,6 +183,11 @@ class sp_head :private Query_arena, ...@@ -183,6 +183,11 @@ class sp_head :private Query_arena,
set_chistics() makes sure this. set_chistics() makes sure this.
*/ */
Sp_chistics m_chistics; Sp_chistics m_chistics;
void set_chistics(const st_sp_chistics &chistics);
inline void set_chistics_agg_type(enum enum_sp_aggregate_type type)
{
m_chistics.agg_type= type;
}
public: public:
sql_mode_t m_sql_mode; ///< For SHOW CREATE and execution sql_mode_t m_sql_mode; ///< For SHOW CREATE and execution
bool m_explicit_name; /**< Prepend the db name? */ bool m_explicit_name; /**< Prepend the db name? */
...@@ -319,7 +324,8 @@ class sp_head :private Query_arena, ...@@ -319,7 +324,8 @@ class sp_head :private Query_arena,
static void static void
operator delete(void *ptr, size_t size) throw (); operator delete(void *ptr, size_t size) throw ();
sp_head(sp_package *parent, const Sp_handler *handler); sp_head(sp_package *parent, const Sp_handler *handler,
enum_sp_aggregate_type);
/// Initialize after we have reset mem_root /// Initialize after we have reset mem_root
void void
...@@ -413,6 +419,9 @@ class sp_head :private Query_arena, ...@@ -413,6 +419,9 @@ class sp_head :private Query_arena,
Item *val, LEX *lex); Item *val, LEX *lex);
bool check_package_routine_end_name(const LEX_CSTRING &end_name) const; bool check_package_routine_end_name(const LEX_CSTRING &end_name) const;
bool check_standalone_routine_end_name(const sp_name *end_name) const; bool check_standalone_routine_end_name(const sp_name *end_name) const;
bool check_group_aggregate_instructions_function() const;
bool check_group_aggregate_instructions_forbid() const;
bool check_group_aggregate_instructions_require() const;
private: private:
/** /**
Generate a code to set a single cursor parameter variable. Generate a code to set a single cursor parameter variable.
...@@ -730,11 +739,7 @@ class sp_head :private Query_arena, ...@@ -730,11 +739,7 @@ class sp_head :private Query_arena,
const LEX_CSTRING &db, const LEX_CSTRING &db,
const LEX_CSTRING &table); const LEX_CSTRING &table);
void set_chistics(const st_sp_chistics &chistics); void set_c_chistics(const st_sp_chistics &chistics);
inline void set_chistics_agg_type(enum enum_sp_aggregate_type type)
{
m_chistics.agg_type= type;
}
void set_info(longlong created, longlong modified, void set_info(longlong created, longlong modified,
const st_sp_chistics &chistics, sql_mode_t sql_mode); const st_sp_chistics &chistics, sql_mode_t sql_mode);
......
...@@ -35,6 +35,7 @@ ...@@ -35,6 +35,7 @@
#include "sql_admin.h" // Sql_cmd_analyze/Check..._table #include "sql_admin.h" // Sql_cmd_analyze/Check..._table
#include "sql_partition.h" #include "sql_partition.h"
#include "sql_partition_admin.h" // Sql_cmd_alter_table_*_part #include "sql_partition_admin.h" // Sql_cmd_alter_table_*_part
#include "event_parse_data.h"
void LEX::parse_error(uint err_number) void LEX::parse_error(uint err_number)
{ {
...@@ -6469,13 +6470,14 @@ sp_name *LEX::make_sp_name(THD *thd, const LEX_CSTRING *name1, ...@@ -6469,13 +6470,14 @@ sp_name *LEX::make_sp_name(THD *thd, const LEX_CSTRING *name1,
sp_head *LEX::make_sp_head(THD *thd, const sp_name *name, sp_head *LEX::make_sp_head(THD *thd, const sp_name *name,
const Sp_handler *sph) const Sp_handler *sph,
enum_sp_aggregate_type agg_type)
{ {
sp_package *package= get_sp_package(); sp_package *package= get_sp_package();
sp_head *sp; sp_head *sp;
/* Order is important here: new - reset - init */ /* Order is important here: new - reset - init */
if (likely((sp= new sp_head(package, sph)))) if (likely((sp= new sp_head(package, sph, agg_type))))
{ {
sp->reset_thd_mem_root(thd); sp->reset_thd_mem_root(thd);
sp->init(this); sp->init(this);
...@@ -6498,7 +6500,8 @@ sp_head *LEX::make_sp_head(THD *thd, const sp_name *name, ...@@ -6498,7 +6500,8 @@ sp_head *LEX::make_sp_head(THD *thd, const sp_name *name,
sp_head *LEX::make_sp_head_no_recursive(THD *thd, const sp_name *name, sp_head *LEX::make_sp_head_no_recursive(THD *thd, const sp_name *name,
const Sp_handler *sph) const Sp_handler *sph,
enum_sp_aggregate_type agg_type)
{ {
sp_package *package= thd->lex->get_sp_package(); sp_package *package= thd->lex->get_sp_package();
/* /*
...@@ -6516,13 +6519,13 @@ sp_head *LEX::make_sp_head_no_recursive(THD *thd, const sp_name *name, ...@@ -6516,13 +6519,13 @@ sp_head *LEX::make_sp_head_no_recursive(THD *thd, const sp_name *name,
(package && (package &&
(sph == &sp_handler_package_procedure || (sph == &sp_handler_package_procedure ||
sph == &sp_handler_package_function))) sph == &sp_handler_package_function)))
return make_sp_head(thd, name, sph); return make_sp_head(thd, name, sph, agg_type);
my_error(ER_SP_NO_RECURSIVE_CREATE, MYF(0), sph->type_str()); my_error(ER_SP_NO_RECURSIVE_CREATE, MYF(0), sph->type_str());
return NULL; return NULL;
} }
bool LEX::sp_body_finalize_procedure(THD *thd) bool LEX::sp_body_finalize_routine(THD *thd)
{ {
if (sphead->check_unresolved_goto()) if (sphead->check_unresolved_goto())
return true; return true;
...@@ -6532,6 +6535,13 @@ bool LEX::sp_body_finalize_procedure(THD *thd) ...@@ -6532,6 +6535,13 @@ bool LEX::sp_body_finalize_procedure(THD *thd)
} }
bool LEX::sp_body_finalize_procedure(THD *thd)
{
return sphead->check_group_aggregate_instructions_forbid() ||
sp_body_finalize_routine(thd);
}
bool LEX::sp_body_finalize_procedure_standalone(THD *thd, bool LEX::sp_body_finalize_procedure_standalone(THD *thd,
const sp_name *end_name) const sp_name *end_name)
{ {
...@@ -6542,25 +6552,41 @@ bool LEX::sp_body_finalize_procedure_standalone(THD *thd, ...@@ -6542,25 +6552,41 @@ bool LEX::sp_body_finalize_procedure_standalone(THD *thd,
bool LEX::sp_body_finalize_function(THD *thd) bool LEX::sp_body_finalize_function(THD *thd)
{ {
if (sphead->is_not_allowed_in_function("function")) if (sphead->is_not_allowed_in_function("function") ||
sphead->check_group_aggregate_instructions_function())
return true; return true;
if (!(sphead->m_flags & sp_head::HAS_RETURN)) if (!(sphead->m_flags & sp_head::HAS_RETURN))
{ {
my_error(ER_SP_NORETURN, MYF(0), ErrConvDQName(sphead).ptr()); my_error(ER_SP_NORETURN, MYF(0), ErrConvDQName(sphead).ptr());
return true; return true;
} }
if (sp_body_finalize_procedure(thd)) if (sp_body_finalize_routine(thd))
return true; return true;
(void) is_native_function_with_warn(thd, &sphead->m_name); (void) is_native_function_with_warn(thd, &sphead->m_name);
return false; return false;
} }
bool LEX::sp_body_finalize_function_standalone(THD *thd, bool LEX::sp_body_finalize_trigger(THD *thd)
const sp_name *end_name)
{ {
return sp_body_finalize_function(thd) || return sphead->is_not_allowed_in_function("trigger") ||
sphead->check_standalone_routine_end_name(end_name); sp_body_finalize_procedure(thd);
}
bool LEX::sp_body_finalize_event(THD *thd)
{
event_parse_data->body_changed= true;
return sp_body_finalize_procedure(thd);
}
bool LEX::stmt_create_stored_function_finalize_standalone(const sp_name *end_name)
{
if (sphead->check_standalone_routine_end_name(end_name))
return true;
stmt_create_routine_finalize();
return false;
} }
...@@ -6855,7 +6881,7 @@ bool LEX::maybe_start_compound_statement(THD *thd) ...@@ -6855,7 +6881,7 @@ bool LEX::maybe_start_compound_statement(THD *thd)
{ {
if (!sphead) if (!sphead)
{ {
if (!make_sp_head(thd, NULL, &sp_handler_procedure)) if (!make_sp_head(thd, NULL, &sp_handler_procedure, DEFAULT_AGGREGATE))
return true; return true;
sphead->set_suid(SP_IS_NOT_SUID); sphead->set_suid(SP_IS_NOT_SUID);
sphead->set_body_start(thd, thd->m_parser_state->m_lip.get_cpp_ptr()); sphead->set_body_start(thd, thd->m_parser_state->m_lip.get_cpp_ptr());
...@@ -8376,6 +8402,7 @@ bool LEX::create_package_finalize(THD *thd, ...@@ -8376,6 +8402,7 @@ bool LEX::create_package_finalize(THD *thd,
exp ? ErrConvDQName(name).ptr() : name->m_name.str); exp ? ErrConvDQName(name).ptr() : name->m_name.str);
return true; return true;
} }
// TODO: reuse code in LEX::create_package_finalize and sp_head::set_stmt_end
sphead->m_body.length= body_end - body_start; sphead->m_body.length= body_end - body_start;
if (unlikely(!(sphead->m_body.str= thd->strmake(body_start, if (unlikely(!(sphead->m_body.str= thd->strmake(body_start,
sphead->m_body.length)))) sphead->m_body.length))))
...@@ -8390,7 +8417,8 @@ bool LEX::create_package_finalize(THD *thd, ...@@ -8390,7 +8417,8 @@ bool LEX::create_package_finalize(THD *thd,
sphead->restore_thd_mem_root(thd); sphead->restore_thd_mem_root(thd);
sp_package *pkg= sphead->get_package(); sp_package *pkg= sphead->get_package();
DBUG_ASSERT(pkg); DBUG_ASSERT(pkg);
return pkg->validate_after_parser(thd); return sphead->check_group_aggregate_instructions_forbid() ||
pkg->validate_after_parser(thd);
} }
...@@ -10326,3 +10354,40 @@ bool LEX::stmt_purge_before(Item *item) ...@@ -10326,3 +10354,40 @@ bool LEX::stmt_purge_before(Item *item)
value_list.push_front(item, thd->mem_root); value_list.push_front(item, thd->mem_root);
return check_main_unit_semantics(); return check_main_unit_semantics();
} }
bool LEX::stmt_create_udf_function(const DDL_options_st &options,
enum_sp_aggregate_type agg_type,
const Lex_ident_sys_st &name,
Item_result return_type,
const LEX_CSTRING &soname)
{
if (stmt_create_function_start(options))
return true;
if (unlikely(is_native_function(thd, &name)))
{
my_error(ER_NATIVE_FCT_NAME_COLLISION, MYF(0), name.str);
return true;
}
sql_command= SQLCOM_CREATE_FUNCTION;
udf.name= name;
udf.returns= return_type;
udf.dl= soname.str;
udf.type= agg_type == GROUP_AGGREGATE ? UDFTYPE_AGGREGATE :
UDFTYPE_FUNCTION;
stmt_create_routine_finalize();
return false;
}
bool LEX::stmt_create_stored_function_start(const DDL_options_st &options,
enum_sp_aggregate_type agg_type,
const sp_name *spname)
{
if (stmt_create_function_start(options) ||
unlikely(!make_sp_head_no_recursive(thd, spname,
&sp_handler_function, agg_type)))
return true;
return false;
}
...@@ -241,6 +241,14 @@ enum enum_sp_suid_behaviour ...@@ -241,6 +241,14 @@ enum enum_sp_suid_behaviour
}; };
enum enum_sp_aggregate_type
{
DEFAULT_AGGREGATE= 0,
NOT_AGGREGATE,
GROUP_AGGREGATE
};
/* These may not be declared yet */ /* These may not be declared yet */
class Table_ident; class Table_ident;
class sql_exchange; class sql_exchange;
...@@ -371,13 +379,6 @@ enum enum_sp_data_access ...@@ -371,13 +379,6 @@ enum enum_sp_data_access
SP_MODIFIES_SQL_DATA SP_MODIFIES_SQL_DATA
}; };
enum enum_sp_aggregate_type
{
DEFAULT_AGGREGATE= 0,
NOT_AGGREGATE,
GROUP_AGGREGATE
};
const LEX_CSTRING sp_data_access_name[]= const LEX_CSTRING sp_data_access_name[]=
{ {
{ STRING_WITH_LEN("") }, { STRING_WITH_LEN("") },
...@@ -3734,12 +3735,16 @@ struct LEX: public Query_tables_list ...@@ -3734,12 +3735,16 @@ struct LEX: public Query_tables_list
sp_name *make_sp_name(THD *thd, const LEX_CSTRING *name1, sp_name *make_sp_name(THD *thd, const LEX_CSTRING *name1,
const LEX_CSTRING *name2); const LEX_CSTRING *name2);
sp_name *make_sp_name_package_routine(THD *thd, const LEX_CSTRING *name); sp_name *make_sp_name_package_routine(THD *thd, const LEX_CSTRING *name);
sp_head *make_sp_head(THD *thd, const sp_name *name, const Sp_handler *sph); sp_head *make_sp_head(THD *thd, const sp_name *name, const Sp_handler *sph,
enum_sp_aggregate_type agg_type);
sp_head *make_sp_head_no_recursive(THD *thd, const sp_name *name, sp_head *make_sp_head_no_recursive(THD *thd, const sp_name *name,
const Sp_handler *sph); const Sp_handler *sph,
enum_sp_aggregate_type agg_type);
bool sp_body_finalize_routine(THD *);
bool sp_body_finalize_trigger(THD *);
bool sp_body_finalize_event(THD *);
bool sp_body_finalize_function(THD *); bool sp_body_finalize_function(THD *);
bool sp_body_finalize_procedure(THD *); bool sp_body_finalize_procedure(THD *);
bool sp_body_finalize_function_standalone(THD *, const sp_name *end_name);
bool sp_body_finalize_procedure_standalone(THD *, const sp_name *end_name); bool sp_body_finalize_procedure_standalone(THD *, const sp_name *end_name);
sp_package *create_package_start(THD *thd, sp_package *create_package_start(THD *thd,
enum_sql_command command, enum_sql_command command,
...@@ -4502,6 +4507,17 @@ struct LEX: public Query_tables_list ...@@ -4502,6 +4507,17 @@ struct LEX: public Query_tables_list
{ {
pop_select(); // main select pop_select(); // main select
} }
bool stmt_create_stored_function_start(const DDL_options_st &options,
enum_sp_aggregate_type,
const sp_name *name);
bool stmt_create_stored_function_finalize_standalone(const sp_name *end_name);
bool stmt_create_udf_function(const DDL_options_st &options,
enum_sp_aggregate_type agg_type,
const Lex_ident_sys_st &name,
Item_result return_type,
const LEX_CSTRING &soname);
}; };
......
...@@ -758,6 +758,7 @@ Virtual_column_info *add_virtual_expression(THD *thd, Item *expr) ...@@ -758,6 +758,7 @@ Virtual_column_info *add_virtual_expression(THD *thd, Item *expr)
/* enums */ /* enums */
enum enum_sp_suid_behaviour sp_suid; enum enum_sp_suid_behaviour sp_suid;
enum enum_sp_aggregate_type sp_aggregate_type;
enum enum_view_suid view_suid; enum enum_view_suid view_suid;
enum Condition_information_item::Name cond_info_item_name; enum Condition_information_item::Name cond_info_item_name;
enum enum_diag_condition_item_name diag_condition_item_name; enum enum_diag_condition_item_name diag_condition_item_name;
...@@ -2061,10 +2062,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize); ...@@ -2061,10 +2062,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
sp_c_chistics sp_a_chistics sp_chistic sp_c_chistic xa sp_c_chistics sp_a_chistics sp_chistic sp_c_chistic xa
opt_field_or_var_spec fields_or_vars opt_load_data_set_spec opt_field_or_var_spec fields_or_vars opt_load_data_set_spec
view_list_opt view_list view_select view_list_opt view_list view_select
trigger_tail sp_tail sf_tail event_tail trigger_tail sp_tail event_tail
udf_tail
create_function_tail
create_aggregate_function_tail
install uninstall partition_entry binlog_base64_event install uninstall partition_entry binlog_base64_event
normal_key_options normal_key_opts all_key_opt normal_key_options normal_key_opts all_key_opt
spatial_key_options fulltext_key_options normal_key_opt spatial_key_options fulltext_key_options normal_key_opt
...@@ -2107,6 +2105,7 @@ END_OF_INPUT ...@@ -2107,6 +2105,7 @@ END_OF_INPUT
%type <plsql_cursor_attr> plsql_cursor_attr %type <plsql_cursor_attr> plsql_cursor_attr
%type <sp_suid> sp_suid %type <sp_suid> sp_suid
%type <sp_aggregate_type> opt_aggregate
%type <num> sp_decl_idents sp_decl_idents_init_vars %type <num> sp_decl_idents sp_decl_idents_init_vars
%type <num> sp_handler_type sp_hcond_list %type <num> sp_handler_type sp_hcond_list
...@@ -2860,42 +2859,37 @@ create: ...@@ -2860,42 +2859,37 @@ create:
{ {
Lex->pop_select(); //main select Lex->pop_select(); //main select
} }
| create_or_replace definer FUNCTION_SYM opt_if_not_exists | create_or_replace definer opt_aggregate FUNCTION_SYM opt_if_not_exists
sp_name '('
{ {
if (Lex->stmt_create_function_start($1 | $4)) if (Lex->stmt_create_stored_function_start($1 | $5, $3, $6))
MYSQL_YYABORT; MYSQL_YYABORT;
} }
sf_tail sp_fdparam_list ')'
{ sf_return_type
Lex->stmt_create_routine_finalize(); sf_c_chistics_and_body
}
| create_or_replace definer AGGREGATE_SYM FUNCTION_SYM opt_if_not_exists
{
if (Lex->stmt_create_function_start($1 | $5))
MYSQL_YYABORT;
}
sf_tail_aggregate
{ {
Lex->stmt_create_routine_finalize(); Lex->stmt_create_routine_finalize();
} }
| create_or_replace no_definer FUNCTION_SYM opt_if_not_exists | create_or_replace no_definer opt_aggregate FUNCTION_SYM opt_if_not_exists
sp_name '('
{ {
if (Lex->stmt_create_function_start($1 | $4)) if (Lex->stmt_create_stored_function_start($1 | $5, $3, $6))
MYSQL_YYABORT; MYSQL_YYABORT;
} }
create_function_tail sp_fdparam_list ')'
sf_return_type
sf_c_chistics_and_body
{ {
Lex->stmt_create_routine_finalize(); Lex->stmt_create_routine_finalize();
} }
| create_or_replace no_definer AGGREGATE_SYM FUNCTION_SYM opt_if_not_exists | create_or_replace no_definer opt_aggregate FUNCTION_SYM opt_if_not_exists
ident RETURNS_SYM udf_type SONAME_SYM TEXT_STRING_sys
{ {
if (Lex->stmt_create_function_start($1 | $5)) if (Lex->stmt_create_udf_function($1 | $5, $3, $6,
(Item_result) $8, $10))
MYSQL_YYABORT; MYSQL_YYABORT;
} }
create_aggregate_function_tail
{
Lex->stmt_create_routine_finalize();
}
| create_or_replace USER_SYM opt_if_not_exists clear_privileges | create_or_replace USER_SYM opt_if_not_exists clear_privileges
grant_list opt_require_clause opt_resource_options opt_account_locking opt_password_expiration grant_list opt_require_clause opt_resource_options opt_account_locking opt_password_expiration
{ {
...@@ -2923,38 +2917,6 @@ create: ...@@ -2923,38 +2917,6 @@ create:
{ } { }
; ;
sf_tail_not_aggregate:
sf_tail
{
if (unlikely(Lex->sphead->m_flags & sp_head::HAS_AGGREGATE_INSTR))
{
my_yyabort_error((ER_NOT_AGGREGATE_FUNCTION, MYF(0)));
}
Lex->sphead->set_chistics_agg_type(NOT_AGGREGATE);
}
;
sf_tail_aggregate:
sf_tail
{
if (unlikely(!(Lex->sphead->m_flags & sp_head::HAS_AGGREGATE_INSTR)))
{
my_yyabort_error((ER_INVALID_AGGREGATE_FUNCTION, MYF(0)));
}
Lex->sphead->set_chistics_agg_type(GROUP_AGGREGATE);
}
;
create_function_tail:
sf_tail_not_aggregate { }
| udf_tail { Lex->udf.type= UDFTYPE_FUNCTION; }
;
create_aggregate_function_tail:
sf_tail_aggregate { }
| udf_tail { Lex->udf.type= UDFTYPE_AGGREGATE; }
;
opt_sequence: opt_sequence:
/* empty */ { } /* empty */ { }
| sequence_defs | sequence_defs
...@@ -3275,20 +3237,17 @@ ev_sql_stmt: ...@@ -3275,20 +3237,17 @@ ev_sql_stmt:
if (unlikely(!lex->make_sp_head(thd, if (unlikely(!lex->make_sp_head(thd,
lex->event_parse_data->identifier, lex->event_parse_data->identifier,
&sp_handler_procedure))) &sp_handler_procedure,
DEFAULT_AGGREGATE)))
MYSQL_YYABORT; MYSQL_YYABORT;
lex->sphead->set_body_start(thd, lip->get_cpp_ptr()); lex->sphead->set_body_start(thd, lip->get_cpp_ptr());
} }
sp_proc_stmt sp_proc_stmt
{ {
LEX *lex= thd->lex;
/* return back to the original memory root ASAP */ /* return back to the original memory root ASAP */
lex->sphead->set_stmt_end(thd); if (Lex->sp_body_finalize_event(thd))
lex->sphead->restore_thd_mem_root(thd); MYSQL_YYABORT;
lex->event_parse_data->body_changed= TRUE;
} }
; ;
...@@ -3305,6 +3264,11 @@ clear_privileges: ...@@ -3305,6 +3264,11 @@ clear_privileges:
} }
; ;
opt_aggregate:
/* Empty */ { $$= NOT_AGGREGATE; }
| AGGREGATE_SYM { $$= GROUP_AGGREGATE; }
;
sp_name: sp_name:
ident '.' ident ident '.' ident
{ {
...@@ -3391,7 +3355,18 @@ sp_cparams: ...@@ -3391,7 +3355,18 @@ sp_cparams:
/* Stored FUNCTION parameter declaration list */ /* Stored FUNCTION parameter declaration list */
sp_fdparam_list: sp_fdparam_list:
/* Empty */ /* Empty */
| sp_fdparams {
Lex->sphead->m_param_begin= YYLIP->get_cpp_tok_start();
Lex->sphead->m_param_end= Lex->sphead->m_param_begin;
}
|
{
Lex->sphead->m_param_begin= YYLIP->get_cpp_tok_start();
}
sp_fdparams
{
Lex->sphead->m_param_end= YYLIP->get_cpp_tok_start();
}
; ;
sp_fdparams: sp_fdparams:
...@@ -3465,18 +3440,6 @@ sp_opt_inout: ...@@ -3465,18 +3440,6 @@ sp_opt_inout:
| INOUT_SYM { $$= sp_variable::MODE_INOUT; } | INOUT_SYM { $$= sp_variable::MODE_INOUT; }
; ;
sp_parenthesized_fdparam_list:
'('
{
Lex->sphead->m_param_begin= YYLIP->get_cpp_tok_start() + 1;
}
sp_fdparam_list
')'
{
Lex->sphead->m_param_end= YYLIP->get_cpp_tok_start();
}
;
sp_parenthesized_pdparam_list: sp_parenthesized_pdparam_list:
'(' '('
{ {
...@@ -17415,8 +17378,8 @@ compound_statement: ...@@ -17415,8 +17378,8 @@ compound_statement:
sp_proc_stmt_compound_ok sp_proc_stmt_compound_ok
{ {
Lex->sql_command= SQLCOM_COMPOUND; Lex->sql_command= SQLCOM_COMPOUND;
Lex->sphead->set_stmt_end(thd); if (Lex->sp_body_finalize_procedure(thd))
Lex->sphead->restore_thd_mem_root(thd); MYSQL_YYABORT;
} }
; ;
...@@ -17702,7 +17665,8 @@ trigger_tail: ...@@ -17702,7 +17665,8 @@ trigger_tail:
(*static_cast<st_trg_execution_order*>(&lex->trg_chistics))= ($17); (*static_cast<st_trg_execution_order*>(&lex->trg_chistics))= ($17);
lex->trg_chistics.ordering_clause_end= lip->get_cpp_ptr(); lex->trg_chistics.ordering_clause_end= lip->get_cpp_ptr();
if (unlikely(!lex->make_sp_head(thd, $4, &sp_handler_trigger))) if (unlikely(!lex->make_sp_head(thd, $4, &sp_handler_trigger,
DEFAULT_AGGREGATE)))
MYSQL_YYABORT; MYSQL_YYABORT;
lex->sphead->set_body_start(thd, lip->get_cpp_tok_start()); lex->sphead->set_body_start(thd, lip->get_cpp_tok_start());
...@@ -17710,13 +17674,9 @@ trigger_tail: ...@@ -17710,13 +17674,9 @@ trigger_tail:
sp_proc_stmt /* $19 */ sp_proc_stmt /* $19 */
{ /* $20 */ { /* $20 */
LEX *lex= Lex; LEX *lex= Lex;
sp_head *sp= lex->sphead;
lex->sql_command= SQLCOM_CREATE_TRIGGER; lex->sql_command= SQLCOM_CREATE_TRIGGER;
sp->set_stmt_end(thd); if (lex->sp_body_finalize_trigger(thd))
sp->restore_thd_mem_root(thd);
if (unlikely(sp->is_not_allowed_in_function("trigger")))
MYSQL_YYABORT; MYSQL_YYABORT;
/* /*
...@@ -17738,19 +17698,6 @@ trigger_tail: ...@@ -17738,19 +17698,6 @@ trigger_tail:
**************************************************************************/ **************************************************************************/
udf_tail:
ident RETURNS_SYM udf_type SONAME_SYM TEXT_STRING_sys
{
LEX *lex= thd->lex;
if (unlikely(is_native_function(thd, & $1)))
my_yyabort_error((ER_NATIVE_FCT_NAME_COLLISION, MYF(0), $1.str));
lex->sql_command= SQLCOM_CREATE_FUNCTION;
lex->udf.name= $1;
lex->udf.returns= (Item_result) $3;
lex->udf.dl= $5.str;
}
;
sf_return_type: sf_return_type:
RETURNS_SYM RETURNS_SYM
...@@ -17768,22 +17715,12 @@ sf_return_type: ...@@ -17768,22 +17715,12 @@ sf_return_type:
} }
; ;
sf_tail: sf_c_chistics_and_body:
sp_name
{
if (unlikely(!Lex->make_sp_head_no_recursive(thd, $1,
&sp_handler_function)))
MYSQL_YYABORT;
}
sp_parenthesized_fdparam_list
sf_return_type
sp_c_chistics sp_c_chistics
{ {
LEX *lex= thd->lex; LEX *lex= thd->lex;
Lex_input_stream *lip= YYLIP; lex->sphead->set_c_chistics(lex->sp_chistics);
lex->sphead->set_body_start(thd, YYLIP->get_cpp_tok_start());
lex->sphead->set_chistics(lex->sp_chistics);
lex->sphead->set_body_start(thd, lip->get_cpp_tok_start());
} }
sp_proc_stmt_in_returns_clause sp_proc_stmt_in_returns_clause
{ {
...@@ -17792,17 +17729,19 @@ sf_tail: ...@@ -17792,17 +17729,19 @@ sf_tail:
} }
; ;
sp_tail: sp_tail:
sp_name sp_name
{ {
if (unlikely(!Lex->make_sp_head_no_recursive(thd, $1, if (unlikely(!Lex->make_sp_head_no_recursive(thd, $1,
&sp_handler_procedure))) &sp_handler_procedure,
DEFAULT_AGGREGATE)))
MYSQL_YYABORT; MYSQL_YYABORT;
} }
sp_parenthesized_pdparam_list sp_parenthesized_pdparam_list
sp_c_chistics sp_c_chistics
{ {
Lex->sphead->set_chistics(Lex->sp_chistics); Lex->sphead->set_c_chistics(Lex->sp_chistics);
Lex->sphead->set_body_start(thd, YYLIP->get_cpp_tok_start()); Lex->sphead->set_body_start(thd, YYLIP->get_cpp_tok_start());
} }
sp_proc_stmt sp_proc_stmt
......
...@@ -254,6 +254,7 @@ void ORAerror(THD *thd, const char *s) ...@@ -254,6 +254,7 @@ void ORAerror(THD *thd, const char *s)
/* enums */ /* enums */
enum enum_sp_suid_behaviour sp_suid; enum enum_sp_suid_behaviour sp_suid;
enum enum_sp_aggregate_type sp_aggregate_type;
enum enum_view_suid view_suid; enum enum_view_suid view_suid;
enum Condition_information_item::Name cond_info_item_name; enum Condition_information_item::Name cond_info_item_name;
enum enum_diag_condition_item_name diag_condition_item_name; enum enum_diag_condition_item_name diag_condition_item_name;
...@@ -1565,9 +1566,6 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize); ...@@ -1565,9 +1566,6 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
opt_field_or_var_spec fields_or_vars opt_load_data_set_spec opt_field_or_var_spec fields_or_vars opt_load_data_set_spec
view_list_opt view_list view_select view_list_opt view_list view_select
trigger_tail event_tail trigger_tail event_tail
udf_tail
create_function_tail_standalone
create_aggregate_function_tail_standalone
install uninstall partition_entry binlog_base64_event install uninstall partition_entry binlog_base64_event
normal_key_options normal_key_opts all_key_opt normal_key_options normal_key_opts all_key_opt
spatial_key_options fulltext_key_options normal_key_opt spatial_key_options fulltext_key_options normal_key_opt
...@@ -1587,7 +1585,6 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize); ...@@ -1587,7 +1585,6 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
opt_delete_gtid_domain opt_delete_gtid_domain
asrow_attribute asrow_attribute
set_assign set_assign
sf_tail_standalone
sp_tail_standalone sp_tail_standalone
opt_constraint_no_id opt_constraint_no_id
END_OF_INPUT END_OF_INPUT
...@@ -1613,6 +1610,7 @@ END_OF_INPUT ...@@ -1613,6 +1610,7 @@ END_OF_INPUT
%type <plsql_cursor_attr> plsql_cursor_attr %type <plsql_cursor_attr> plsql_cursor_attr
%type <sp_suid> sp_suid %type <sp_suid> sp_suid
%type <sp_aggregate_type> opt_aggregate
%type <num> sp_decl_idents sp_decl_idents_init_vars %type <num> sp_decl_idents sp_decl_idents_init_vars
%type <num> sp_handler_type sp_hcond_list %type <num> sp_handler_type sp_hcond_list
...@@ -2381,41 +2379,66 @@ create: ...@@ -2381,41 +2379,66 @@ create:
{ {
Lex->pop_select(); //main select Lex->pop_select(); //main select
} }
| create_or_replace definer FUNCTION_SYM opt_if_not_exists | create_or_replace definer opt_aggregate FUNCTION_SYM opt_if_not_exists
sp_name RETURN_ORACLE_SYM
{ {
if (Lex->stmt_create_function_start($1 | $4)) if (Lex->stmt_create_stored_function_start($1 | $5, $3, $6))
MYSQL_YYABORT; MYSQL_YYABORT;
} }
sf_tail_standalone sf_return_type
sf_c_chistics_and_body_standalone
opt_sp_name
{ {
Lex->stmt_create_routine_finalize(); if (Lex->stmt_create_stored_function_finalize_standalone($11))
MYSQL_YYABORT;
} }
| create_or_replace definer AGGREGATE_SYM FUNCTION_SYM opt_if_not_exists | create_or_replace definer opt_aggregate FUNCTION_SYM opt_if_not_exists
sp_name '('
{ {
if (Lex->stmt_create_function_start($1 | $5)) if (Lex->stmt_create_stored_function_start($1 | $5, $3, $6))
MYSQL_YYABORT; MYSQL_YYABORT;
} }
sf_tail_aggregate_standalone sp_fdparam_list ')'
RETURN_ORACLE_SYM sf_return_type
sf_c_chistics_and_body_standalone
opt_sp_name
{ {
Lex->stmt_create_routine_finalize(); if (Lex->stmt_create_stored_function_finalize_standalone($14))
MYSQL_YYABORT;
} }
| create_or_replace no_definer FUNCTION_SYM opt_if_not_exists | create_or_replace no_definer opt_aggregate FUNCTION_SYM opt_if_not_exists
sp_name RETURN_ORACLE_SYM
{ {
if (Lex->stmt_create_function_start($1 | $4)) if (Lex->stmt_create_stored_function_start($1 | $5, $3, $6))
MYSQL_YYABORT; MYSQL_YYABORT;
} }
create_function_tail_standalone sf_return_type
sf_c_chistics_and_body_standalone
opt_sp_name
{ {
Lex->stmt_create_routine_finalize(); if (Lex->stmt_create_stored_function_finalize_standalone($11))
MYSQL_YYABORT;
} }
| create_or_replace no_definer AGGREGATE_SYM FUNCTION_SYM opt_if_not_exists | create_or_replace no_definer opt_aggregate FUNCTION_SYM opt_if_not_exists
sp_name '('
{ {
if (Lex->stmt_create_function_start($1 | $5)) if (Lex->stmt_create_stored_function_start($1 | $5, $3, $6))
MYSQL_YYABORT; MYSQL_YYABORT;
} }
create_aggregate_function_tail_standalone sp_fdparam_list ')'
RETURN_ORACLE_SYM sf_return_type
sf_c_chistics_and_body_standalone
opt_sp_name
{ {
Lex->stmt_create_routine_finalize(); if (Lex->stmt_create_stored_function_finalize_standalone($14))
MYSQL_YYABORT;
}
| create_or_replace no_definer opt_aggregate FUNCTION_SYM opt_if_not_exists
ident RETURNS_SYM udf_type SONAME_SYM TEXT_STRING_sys
{
if (Lex->stmt_create_udf_function($1 | $5, $3, $6,
(Item_result) $8, $10))
MYSQL_YYABORT;
} }
| create_or_replace USER_SYM opt_if_not_exists clear_privileges | create_or_replace USER_SYM opt_if_not_exists clear_privileges
grant_list opt_require_clause opt_resource_options opt_account_locking opt_password_expiration grant_list opt_require_clause opt_resource_options opt_account_locking opt_password_expiration
...@@ -2454,7 +2477,7 @@ create: ...@@ -2454,7 +2477,7 @@ create:
&sp_handler_package_spec, &sp_handler_package_spec,
$5, $1 | $4)))) $5, $1 | $4))))
MYSQL_YYABORT; MYSQL_YYABORT;
pkg->set_chistics(Lex->sp_chistics); pkg->set_c_chistics(Lex->sp_chistics);
} }
opt_package_specification_element_list END opt_package_specification_element_list END
remember_end_opt opt_sp_name remember_end_opt opt_sp_name
...@@ -2474,7 +2497,7 @@ create: ...@@ -2474,7 +2497,7 @@ create:
&sp_handler_package_body, &sp_handler_package_body,
$6, $1 | $5)))) $6, $1 | $5))))
MYSQL_YYABORT; MYSQL_YYABORT;
pkg->set_chistics(Lex->sp_chistics); pkg->set_c_chistics(Lex->sp_chistics);
Lex->sp_block_init(thd); Lex->sp_block_init(thd);
} }
package_implementation_declare_section package_implementation_declare_section
...@@ -2495,39 +2518,6 @@ create: ...@@ -2495,39 +2518,6 @@ create:
} }
; ;
sf_tail_not_aggregate_standalone:
sf_tail_standalone
{
if (unlikely(Lex->sphead->m_flags & sp_head::HAS_AGGREGATE_INSTR))
{
my_yyabort_error((ER_NOT_AGGREGATE_FUNCTION, MYF(0)));
}
Lex->sphead->set_chistics_agg_type(NOT_AGGREGATE);
}
;
sf_tail_aggregate_standalone:
sf_tail_standalone
{
if (unlikely(!(Lex->sphead->m_flags & sp_head::HAS_AGGREGATE_INSTR)))
{
my_yyabort_error((ER_INVALID_AGGREGATE_FUNCTION, MYF(0)));
}
Lex->sphead->set_chistics_agg_type(GROUP_AGGREGATE);
}
;
create_function_tail_standalone:
sf_tail_not_aggregate_standalone { }
| udf_tail { Lex->udf.type= UDFTYPE_FUNCTION; }
;
create_aggregate_function_tail_standalone:
sf_tail_aggregate_standalone { }
| udf_tail { Lex->udf.type= UDFTYPE_AGGREGATE; }
;
package_implementation_executable_section: package_implementation_executable_section:
END END
{ {
...@@ -2584,13 +2574,14 @@ package_specification_function: ...@@ -2584,13 +2574,14 @@ package_specification_function:
MYSQL_YYABORT; MYSQL_YYABORT;
thd->lex= $2; thd->lex= $2;
if (unlikely(!$2->make_sp_head_no_recursive(thd, spname, if (unlikely(!$2->make_sp_head_no_recursive(thd, spname,
&sp_handler_package_function))) &sp_handler_package_function,
NOT_AGGREGATE)))
MYSQL_YYABORT; MYSQL_YYABORT;
$1->sphead->get_package()->m_current_routine= $2; $1->sphead->get_package()->m_current_routine= $2;
(void) is_native_function_with_warn(thd, &$3); (void) is_native_function_with_warn(thd, &$3);
} }
opt_sp_parenthesized_fdparam_list opt_sp_parenthesized_fdparam_list
sf_return_type RETURN_ORACLE_SYM sf_return_type
sp_c_chistics sp_c_chistics
{ {
sp_head *sp= thd->lex->sphead; sp_head *sp= thd->lex->sphead;
...@@ -2610,7 +2601,8 @@ package_specification_procedure: ...@@ -2610,7 +2601,8 @@ package_specification_procedure:
MYSQL_YYABORT; MYSQL_YYABORT;
thd->lex= $2; thd->lex= $2;
if (unlikely(!$2->make_sp_head_no_recursive(thd, spname, if (unlikely(!$2->make_sp_head_no_recursive(thd, spname,
&sp_handler_package_procedure))) &sp_handler_package_procedure,
DEFAULT_AGGREGATE)))
MYSQL_YYABORT; MYSQL_YYABORT;
$1->sphead->get_package()->m_current_routine= $2; $1->sphead->get_package()->m_current_routine= $2;
} }
...@@ -2660,11 +2652,6 @@ package_implementation_function_body: ...@@ -2660,11 +2652,6 @@ package_implementation_function_body:
} }
sp_body opt_package_routine_end_name sp_body opt_package_routine_end_name
{ {
if (unlikely(Lex->sphead->m_flags & sp_head::HAS_AGGREGATE_INSTR))
{
my_yyabort_error((ER_NOT_AGGREGATE_FUNCTION, MYF(0)));
}
Lex->sphead->set_chistics_agg_type(NOT_AGGREGATE);
if (unlikely(thd->lex->sp_body_finalize_function(thd) || if (unlikely(thd->lex->sp_body_finalize_function(thd) ||
thd->lex->sphead->check_package_routine_end_name($5))) thd->lex->sphead->check_package_routine_end_name($5)))
MYSQL_YYABORT; MYSQL_YYABORT;
...@@ -2684,7 +2671,7 @@ package_implementation_procedure_body: ...@@ -2684,7 +2671,7 @@ package_implementation_procedure_body:
sp_body opt_package_routine_end_name sp_body opt_package_routine_end_name
{ {
if (unlikely(thd->lex->sp_body_finalize_procedure(thd) || if (unlikely(thd->lex->sp_body_finalize_procedure(thd) ||
thd->lex->sphead->check_package_routine_end_name($5))) thd->lex->sphead->check_package_routine_end_name($5)))
MYSQL_YYABORT; MYSQL_YYABORT;
thd->lex= $2; thd->lex= $2;
} }
...@@ -3043,20 +3030,17 @@ ev_sql_stmt: ...@@ -3043,20 +3030,17 @@ ev_sql_stmt:
if (unlikely(!lex->make_sp_head(thd, if (unlikely(!lex->make_sp_head(thd,
lex->event_parse_data->identifier, lex->event_parse_data->identifier,
&sp_handler_procedure))) &sp_handler_procedure,
DEFAULT_AGGREGATE)))
MYSQL_YYABORT; MYSQL_YYABORT;
lex->sphead->set_body_start(thd, lip->get_cpp_ptr()); lex->sphead->set_body_start(thd, lip->get_cpp_ptr());
} }
sp_proc_stmt sp_proc_stmt
{ {
LEX *lex= thd->lex;
/* return back to the original memory root ASAP */ /* return back to the original memory root ASAP */
lex->sphead->set_stmt_end(thd); if (Lex->sp_body_finalize_event(thd))
lex->sphead->restore_thd_mem_root(thd); MYSQL_YYABORT;
lex->event_parse_data->body_changed= TRUE;
} }
; ;
...@@ -3073,6 +3057,11 @@ clear_privileges: ...@@ -3073,6 +3057,11 @@ clear_privileges:
} }
; ;
opt_aggregate:
/* Empty */ { $$= NOT_AGGREGATE; }
| AGGREGATE_SYM { $$= GROUP_AGGREGATE; }
;
sp_name: sp_name:
ident '.' ident ident '.' ident
{ {
...@@ -3186,7 +3175,18 @@ sp_cparams: ...@@ -3186,7 +3175,18 @@ sp_cparams:
/* Stored FUNCTION parameter declaration list */ /* Stored FUNCTION parameter declaration list */
sp_fdparam_list: sp_fdparam_list:
/* Empty */ /* Empty */
| sp_fdparams {
Lex->sphead->m_param_begin= YYLIP->get_cpp_tok_start();
Lex->sphead->m_param_end= Lex->sphead->m_param_begin;
}
|
{
Lex->sphead->m_param_begin= YYLIP->get_cpp_tok_start();
}
sp_fdparams
{
Lex->sphead->m_param_end= YYLIP->get_cpp_tok_start();
}
; ;
sp_fdparams: sp_fdparams:
...@@ -3293,18 +3293,6 @@ sp_opt_inout: ...@@ -3293,18 +3293,6 @@ sp_opt_inout:
| IN_SYM OUT_SYM { $$= sp_variable::MODE_INOUT; } | IN_SYM OUT_SYM { $$= sp_variable::MODE_INOUT; }
; ;
sp_parenthesized_fdparam_list:
'('
{
Lex->sphead->m_param_begin= YYLIP->get_cpp_tok_start() + 1;
}
sp_fdparam_list
')'
{
Lex->sphead->m_param_end= YYLIP->get_cpp_tok_start();
}
;
sp_parenthesized_pdparam_list: sp_parenthesized_pdparam_list:
'(' '('
{ {
...@@ -3327,7 +3315,7 @@ sp_no_param: ...@@ -3327,7 +3315,7 @@ sp_no_param:
opt_sp_parenthesized_fdparam_list: opt_sp_parenthesized_fdparam_list:
sp_no_param sp_no_param
| sp_parenthesized_fdparam_list | '(' sp_fdparam_list ')'
; ;
opt_sp_parenthesized_pdparam_list: opt_sp_parenthesized_pdparam_list:
...@@ -17620,8 +17608,8 @@ compound_statement: ...@@ -17620,8 +17608,8 @@ compound_statement:
sp_proc_stmt_compound_ok sp_proc_stmt_compound_ok
{ {
Lex->sql_command= SQLCOM_COMPOUND; Lex->sql_command= SQLCOM_COMPOUND;
Lex->sphead->set_stmt_end(thd); if (Lex->sp_body_finalize_procedure(thd))
Lex->sphead->restore_thd_mem_root(thd); MYSQL_YYABORT;
} }
; ;
...@@ -17908,7 +17896,8 @@ trigger_tail: ...@@ -17908,7 +17896,8 @@ trigger_tail:
(*static_cast<st_trg_execution_order*>(&lex->trg_chistics))= ($17); (*static_cast<st_trg_execution_order*>(&lex->trg_chistics))= ($17);
lex->trg_chistics.ordering_clause_end= lip->get_cpp_ptr(); lex->trg_chistics.ordering_clause_end= lip->get_cpp_ptr();
if (unlikely(!lex->make_sp_head(thd, $4, &sp_handler_trigger))) if (unlikely(!lex->make_sp_head(thd, $4, &sp_handler_trigger,
DEFAULT_AGGREGATE)))
MYSQL_YYABORT; MYSQL_YYABORT;
lex->sphead->set_body_start(thd, lip->get_cpp_tok_start()); lex->sphead->set_body_start(thd, lip->get_cpp_tok_start());
...@@ -17916,15 +17905,9 @@ trigger_tail: ...@@ -17916,15 +17905,9 @@ trigger_tail:
sp_proc_stmt /* $19 */ sp_proc_stmt /* $19 */
{ /* $20 */ { /* $20 */
LEX *lex= Lex; LEX *lex= Lex;
sp_head *sp= lex->sphead;
if (unlikely(sp->check_unresolved_goto()))
MYSQL_YYABORT;
lex->sql_command= SQLCOM_CREATE_TRIGGER; lex->sql_command= SQLCOM_CREATE_TRIGGER;
sp->set_stmt_end(thd); if (lex->sp_body_finalize_trigger(thd))
sp->restore_thd_mem_root(thd);
if (unlikely(sp->is_not_allowed_in_function("trigger")))
MYSQL_YYABORT; MYSQL_YYABORT;
/* /*
...@@ -17946,22 +17929,7 @@ trigger_tail: ...@@ -17946,22 +17929,7 @@ trigger_tail:
**************************************************************************/ **************************************************************************/
udf_tail:
ident RETURNS_SYM udf_type SONAME_SYM TEXT_STRING_sys
{
LEX *lex= thd->lex;
if (unlikely(is_native_function(thd, & $1)))
my_yyabort_error((ER_NATIVE_FCT_NAME_COLLISION, MYF(0), $1.str));
lex->sql_command= SQLCOM_CREATE_FUNCTION;
lex->udf.name= $1;
lex->udf.returns= (Item_result) $3;
lex->udf.dl= $5.str;
}
;
sf_return_type: sf_return_type:
RETURN_ORACLE_SYM
{ {
LEX *lex= Lex; LEX *lex= Lex;
lex->init_last_field(&lex->sphead->m_return_field_def, lex->init_last_field(&lex->sphead->m_return_field_def,
...@@ -17976,28 +17944,17 @@ sf_return_type: ...@@ -17976,28 +17944,17 @@ sf_return_type:
} }
; ;
sf_tail_standalone: sf_c_chistics_and_body_standalone:
sp_name
{
if (unlikely(!Lex->make_sp_head_no_recursive(thd, $1,
&sp_handler_function)))
MYSQL_YYABORT;
}
opt_sp_parenthesized_fdparam_list
sf_return_type
sp_c_chistics sp_c_chistics
{ {
LEX *lex= thd->lex; LEX *lex= thd->lex;
Lex_input_stream *lip= YYLIP; lex->sphead->set_c_chistics(lex->sp_chistics);
lex->sphead->set_body_start(thd, YYLIP->get_cpp_tok_start());
lex->sphead->set_chistics(lex->sp_chistics);
lex->sphead->set_body_start(thd, lip->get_cpp_tok_start());
} }
sp_tail_is sp_tail_is
sp_body sp_body
opt_sp_name
{ {
if (unlikely(Lex->sp_body_finalize_function_standalone(thd, $9))) if (unlikely(Lex->sp_body_finalize_function(thd)))
MYSQL_YYABORT; MYSQL_YYABORT;
} }
; ;
...@@ -18006,13 +17963,14 @@ sp_tail_standalone: ...@@ -18006,13 +17963,14 @@ sp_tail_standalone:
sp_name sp_name
{ {
if (unlikely(!Lex->make_sp_head_no_recursive(thd, $1, if (unlikely(!Lex->make_sp_head_no_recursive(thd, $1,
&sp_handler_procedure))) &sp_handler_procedure,
DEFAULT_AGGREGATE)))
MYSQL_YYABORT; MYSQL_YYABORT;
} }
opt_sp_parenthesized_pdparam_list opt_sp_parenthesized_pdparam_list
sp_c_chistics sp_c_chistics
{ {
Lex->sphead->set_chistics(Lex->sp_chistics); Lex->sphead->set_c_chistics(Lex->sp_chistics);
Lex->sphead->set_body_start(thd, YYLIP->get_cpp_tok_start()); Lex->sphead->set_body_start(thd, YYLIP->get_cpp_tok_start());
} }
sp_tail_is sp_tail_is
......
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