Skip to content
Permalink
Browse files
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.
  • Loading branch information
abarkov committed Mar 7, 2019
1 parent a71d185 commit 5f34513
Show file tree
Hide file tree
Showing 12 changed files with 567 additions and 275 deletions.
@@ -37,7 +37,7 @@ set x=5;
fetch group next row;
return x+1;
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
begin
declare continue handler for not found return x;
@@ -1153,3 +1153,36 @@ i sum(i)
NULL 8
drop function agg_sum;
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;
# Cleanup
drop function agg_sum;
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, '!');
<routines>
<routine Function="straße" sql_mode="" character_set_client="utf8" collation_connection="utf8_general_ci" Database_Collation="latin1_swedish_ci">
<![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
RETURN CONCAT(']]]]><![CDATA[>, ', c1, '!')
]]>
@@ -11,7 +11,7 @@ set x=5;
fetch group next row;
return x+1;
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);
INSERT INTO marks VALUES (1,6), (2,4), (3,7), (4,5), (5,8);
SELECT * FROM marks;
@@ -56,3 +56,81 @@ aggregate_count(stud_id)
5
DROP FUNCTION IF EXISTS aggregate_count;
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;


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
ER_WRONG_TYPE_OF_ARGUMENT
eng "%s function only accepts arguments that can be converted to numerical types"
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
eng "Aggregate specific instruction(FETCH GROUP NEXT ROW) missing from the aggregate function"
ER_INVALID_VALUE_TO_LIMIT
@@ -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),
Database_qualified_name(&null_clex_str, &null_clex_str),
m_parent(parent),
@@ -522,6 +523,7 @@ sp_head::sp_head(sp_package *parent, const Sp_handler *sph)
m_pcont(new (&main_mem_root) sp_pcontext()),
m_cont_level(0)
{
set_chistics_agg_type(agg_type);
m_first_instance= this;
m_first_free_instance= this;
m_last_cached_sp= this;
@@ -547,7 +549,7 @@ sp_head::sp_head(sp_package *parent, const Sp_handler *sph)
sp_package::sp_package(LEX *top_level_lex,
const sp_name *name,
const Sp_handler *sph)
:sp_head(NULL, sph),
:sp_head(NULL, sph, DEFAULT_AGGREGATE),
m_current_routine(NULL),
m_top_level_lex(top_level_lex),
m_rcontext(NULL),
@@ -2681,6 +2683,17 @@ sp_head::set_chistics(const st_sp_chistics &chistics)
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
sp_head::set_info(longlong created, longlong modified,
const st_sp_chistics &chistics, sql_mode_t sql_mode)
@@ -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
at the end of a declaration:

0 comments on commit 5f34513

Please sign in to comment.