Commit 4cb57ac0 authored by kostja@bodhi.local's avatar kostja@bodhi.local

Merge bk-internal.mysql.com:/home/bk/mysql-5.1

into  bodhi.local:/opt/local/work/mysql-5.1-runtime-merge
parents 99b572b9 85068819
...@@ -100,6 +100,8 @@ int my_TIME_to_str(const MYSQL_TIME *l_time, char *to); ...@@ -100,6 +100,8 @@ int my_TIME_to_str(const MYSQL_TIME *l_time, char *to);
/* /*
The following must be sorted so that simple intervals comes first. The following must be sorted so that simple intervals comes first.
(get_interval_value() depends on this) (get_interval_value() depends on this)
When updating this enum please update
LEX_STRING interval_type_to_name[] in sql/time.cc
*/ */
enum interval_type enum interval_type
......
...@@ -546,7 +546,103 @@ GROUP_CONCAT(Track SEPARATOR ', ') ...@@ -546,7 +546,103 @@ GROUP_CONCAT(Track SEPARATOR ', ')
CAD CAD
DEALLOCATE PREPARE STMT; DEALLOCATE PREPARE STMT;
DROP TABLE t1; DROP TABLE t1;
End of 4.1 tests DROP TABLE IF EXISTS t1;
CREATE TABLE t1 (i INT, INDEX(i));
INSERT INTO t1 VALUES (1);
PREPARE stmt FROM "SELECT (COUNT(i) = 1), COUNT(i) FROM t1 WHERE i = ?";
SET @a = 0;
EXECUTE stmt USING @a;
(COUNT(i) = 1) COUNT(i)
0 0
SET @a = 1;
EXECUTE stmt USING @a;
(COUNT(i) = 1) COUNT(i)
1 1
SET @a = 0;
EXECUTE stmt USING @a;
(COUNT(i) = 1) COUNT(i)
0 0
PREPARE stmt FROM "SELECT (AVG(i) = 1), AVG(i) FROM t1 WHERE i = ?";
SET @a = 0;
EXECUTE stmt USING @a;
(AVG(i) = 1) AVG(i)
NULL NULL
SET @a = 1;
EXECUTE stmt USING @a;
(AVG(i) = 1) AVG(i)
1 1.0000
SET @a = 0;
EXECUTE stmt USING @a;
(AVG(i) = 1) AVG(i)
NULL NULL
PREPARE stmt FROM "SELECT (VARIANCE(i) = 1), VARIANCE(i) FROM t1 WHERE i = ?";
SET @a = 0;
EXECUTE stmt USING @a;
(VARIANCE(i) = 1) VARIANCE(i)
NULL NULL
SET @a = 1;
EXECUTE stmt USING @a;
(VARIANCE(i) = 1) VARIANCE(i)
0 0.0000
SET @a = 0;
EXECUTE stmt USING @a;
(VARIANCE(i) = 1) VARIANCE(i)
NULL NULL
PREPARE stmt FROM "SELECT (STDDEV(i) = 1), STDDEV(i) FROM t1 WHERE i = ?";
SET @a = 0;
EXECUTE stmt USING @a;
(STDDEV(i) = 1) STDDEV(i)
NULL NULL
SET @a = 1;
EXECUTE stmt USING @a;
(STDDEV(i) = 1) STDDEV(i)
0 0.0000
SET @a = 0;
EXECUTE stmt USING @a;
(STDDEV(i) = 1) STDDEV(i)
NULL NULL
PREPARE stmt FROM "SELECT (BIT_OR(i) = 1), BIT_OR(i) FROM t1 WHERE i = ?";
SET @a = 0;
EXECUTE stmt USING @a;
(BIT_OR(i) = 1) BIT_OR(i)
0 0
SET @a = 1;
EXECUTE stmt USING @a;
(BIT_OR(i) = 1) BIT_OR(i)
1 1
SET @a = 0;
EXECUTE stmt USING @a;
(BIT_OR(i) = 1) BIT_OR(i)
0 0
PREPARE stmt FROM "SELECT (BIT_AND(i) = 1), BIT_AND(i) FROM t1 WHERE i = ?";
SET @a = 0;
EXECUTE stmt USING @a;
(BIT_AND(i) = 1) BIT_AND(i)
0 18446744073709551615
SET @a = 1;
EXECUTE stmt USING @a;
(BIT_AND(i) = 1) BIT_AND(i)
1 1
SET @a = 0;
EXECUTE stmt USING @a;
(BIT_AND(i) = 1) BIT_AND(i)
0 18446744073709551615
PREPARE stmt FROM "SELECT (BIT_XOR(i) = 1), BIT_XOR(i) FROM t1 WHERE i = ?";
SET @a = 0;
EXECUTE stmt USING @a;
(BIT_XOR(i) = 1) BIT_XOR(i)
0 0
SET @a = 1;
EXECUTE stmt USING @a;
(BIT_XOR(i) = 1) BIT_XOR(i)
1 1
SET @a = 0;
EXECUTE stmt USING @a;
(BIT_XOR(i) = 1) BIT_XOR(i)
0 0
DEALLOCATE PREPARE stmt;
DROP TABLE t1;
End of 4.1 tests.
create table t1 (a varchar(20)); create table t1 (a varchar(20));
insert into t1 values ('foo'); insert into t1 values ('foo');
prepare stmt FROM 'SELECT char_length (a) FROM t1'; prepare stmt FROM 'SELECT char_length (a) FROM t1';
...@@ -1360,6 +1456,7 @@ i ...@@ -1360,6 +1456,7 @@ i
1 1
DEALLOCATE PREPARE stmt; DEALLOCATE PREPARE stmt;
DROP TABLE t1, t2; DROP TABLE t1, t2;
DROP PROCEDURE IF EXISTS p1;
End of 5.0 tests. End of 5.0 tests.
create procedure proc_1() reset query cache; create procedure proc_1() reset query cache;
call proc_1(); call proc_1();
......
...@@ -1226,6 +1226,30 @@ END; ...@@ -1226,6 +1226,30 @@ END;
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 'IF NOT EXISTS bug14702() 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 'IF NOT EXISTS bug14702()
BEGIN BEGIN
END' at line 1 END' at line 1
DROP TABLE IF EXISTS t1;
CREATE TABLE t1 (i INT);
CREATE PROCEDURE bug20953() CREATE VIEW v AS SELECT 1 INTO @a;
ERROR HY000: View's SELECT contains a 'INTO' clause
CREATE PROCEDURE bug20953() CREATE VIEW v AS SELECT 1 INTO DUMPFILE "file";
ERROR HY000: View's SELECT contains a 'INTO' clause
CREATE PROCEDURE bug20953() CREATE VIEW v AS SELECT 1 INTO OUTFILE "file";
ERROR HY000: View's SELECT contains a 'INTO' clause
CREATE PROCEDURE bug20953()
CREATE VIEW v AS SELECT i FROM t1 PROCEDURE ANALYSE();
ERROR HY000: View's SELECT contains a 'PROCEDURE' clause
CREATE PROCEDURE bug20953() CREATE VIEW v AS SELECT 1 FROM (SELECT 1) AS d1;
ERROR HY000: View's SELECT contains a subquery in the FROM clause
CREATE PROCEDURE bug20953(i INT) CREATE VIEW v AS SELECT i;
ERROR HY000: View's SELECT contains a variable or parameter
CREATE PROCEDURE bug20953()
BEGIN
DECLARE i INT;
CREATE VIEW v AS SELECT i;
END |
ERROR HY000: View's SELECT contains a variable or parameter
PREPARE stmt FROM "CREATE VIEW v AS SELECT ?";
ERROR HY000: View's SELECT contains a variable or parameter
DROP TABLE t1;
End of 5.0 tests End of 5.0 tests
drop function if exists bug16164; drop function if exists bug16164;
create function bug16164() returns int create function bug16164() returns int
...@@ -1234,9 +1258,9 @@ show authors; ...@@ -1234,9 +1258,9 @@ show authors;
return 42; return 42;
end| end|
ERROR 0A000: Not allowed to return a result set from a function ERROR 0A000: Not allowed to return a result set from a function
drop function if exists bug20701| drop function if exists bug20701;
create function bug20701() returns varchar(25) binary return "test"| create function bug20701() returns varchar(25) binary return "test";
ERROR 42000: This version of MySQL doesn't yet support 'return value collation' ERROR 42000: This version of MySQL doesn't yet support 'return value collation'
create function bug20701() returns varchar(25) return "test"| create function bug20701() returns varchar(25) return "test";
drop function bug20701| drop function bug20701;
End of 5.1 tests End of 5.1 tests
...@@ -12,6 +12,9 @@ create table t1 (a int, b int); ...@@ -12,6 +12,9 @@ create table t1 (a int, b int);
insert into t1 values (1,2), (1,3), (2,4), (2,5), (3,10); insert into t1 values (1,2), (1,3), (2,4), (2,5), (3,10);
create view v1 (c,d) as select a,b+@@global.max_user_connections from t1; create view v1 (c,d) as select a,b+@@global.max_user_connections from t1;
ERROR HY000: View's SELECT contains a variable or parameter ERROR HY000: View's SELECT contains a variable or parameter
create view v1 (c,d) as select a,b from t1
where a = @@global.max_user_connections;
ERROR HY000: View's SELECT contains a variable or parameter
create view v1 (c) as select b+1 from t1; create view v1 (c) as select b+1 from t1;
select c from v1; select c from v1;
c c
...@@ -596,11 +599,6 @@ ERROR HY000: View 'test.v1' references invalid table(s) or column(s) or function ...@@ -596,11 +599,6 @@ ERROR HY000: View 'test.v1' references invalid table(s) or column(s) or function
drop view v1; drop view v1;
create view v1 (a,a) as select 'a','a'; create view v1 (a,a) as select 'a','a';
ERROR 42S21: Duplicate column name 'a' ERROR 42S21: Duplicate column name 'a'
drop procedure if exists p1;
create procedure p1 () begin declare v int; create view v1 as select v; end;//
call p1();
ERROR HY000: View's SELECT contains a variable or parameter
drop procedure p1;
create table t1 (col1 int,col2 char(22)); create table t1 (col1 int,col2 char(22));
insert into t1 values(5,'Hello, world of views'); insert into t1 values(5,'Hello, world of views');
create view v1 as select * from t1; create view v1 as select * from t1;
...@@ -886,6 +884,8 @@ ERROR HY000: View's SELECT contains a 'INTO' clause ...@@ -886,6 +884,8 @@ ERROR HY000: View's SELECT contains a 'INTO' clause
create table t1 (a int); create table t1 (a int);
create view v1 as select a from t1 procedure analyse(); create view v1 as select a from t1 procedure analyse();
ERROR HY000: View's SELECT contains a 'PROCEDURE' clause ERROR HY000: View's SELECT contains a 'PROCEDURE' clause
create view v1 as select 1 from (select 1) as d1;
ERROR HY000: View's SELECT contains a subquery in the FROM clause
drop table t1; drop table t1;
create table t1 (s1 int, primary key (s1)); create table t1 (s1 int, primary key (s1));
create view v1 as select * from t1; create view v1 as select * from t1;
...@@ -2956,6 +2956,18 @@ View Create View ...@@ -2956,6 +2956,18 @@ View Create View
v1 CREATE ALGORITHM=MERGE DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`pk` AS `pk` from (`t1` join `t2` on(((`t2`.`fk` = `t1`.`pk`) and (`t2`.`ver` = (select max(`t`.`ver`) AS `MAX(t.ver)` from `t2` `t` where (`t`.`org` = `t2`.`org`)))))) v1 CREATE ALGORITHM=MERGE DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`pk` AS `pk` from (`t1` join `t2` on(((`t2`.`fk` = `t1`.`pk`) and (`t2`.`ver` = (select max(`t`.`ver`) AS `MAX(t.ver)` from `t2` `t` where (`t`.`org` = `t2`.`org`))))))
DROP VIEW v1; DROP VIEW v1;
DROP TABLE t1, t2; DROP TABLE t1, t2;
DROP FUNCTION IF EXISTS f1;
DROP VIEW IF EXISTS v1;
DROP TABLE IF EXISTS t1;
CREATE TABLE t1 (i INT);
INSERT INTO t1 VALUES (1);
CREATE VIEW v1 AS SELECT MAX(i) FROM t1;
CREATE TRIGGER t1_bi BEFORE INSERT ON t1 FOR EACH ROW
SET NEW.i = (SELECT * FROM v1) + 1;
INSERT INTO t1 VALUES (1);
CREATE FUNCTION f1() RETURNS INT RETURN (SELECT * FROM v1);
UPDATE t1 SET i= f1();
DROP FUNCTION f1;
CREATE TABLE t1(id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, val INT UNSIGNED NOT NULL); CREATE TABLE t1(id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, val INT UNSIGNED NOT NULL);
CREATE VIEW v1 AS SELECT id, val FROM t1 WHERE val >= 1 AND val <= 5 WITH CHECK OPTION; CREATE VIEW v1 AS SELECT id, val FROM t1 WHERE val >= 1 AND val <= 5 WITH CHECK OPTION;
INSERT INTO v1 (val) VALUES (2); INSERT INTO v1 (val) VALUES (2);
......
...@@ -98,7 +98,7 @@ select ifnull(group_concat(concat(t1.id, ':', t1.name)), 'shortname') as 'withou ...@@ -98,7 +98,7 @@ select ifnull(group_concat(concat(t1.id, ':', t1.name)), 'shortname') as 'withou
select distinct ifnull(group_concat(concat(t1.id, ':', t1.name)), 'shortname') as 'with distinct: cutoff at length of shortname' from t1; select distinct ifnull(group_concat(concat(t1.id, ':', t1.name)), 'shortname') as 'with distinct: cutoff at length of shortname' from t1;
drop table t1; drop table t1;
# check zero rows # check zero rows (bug#836)
create table t1(id int); create table t1(id int);
create table t2(id int); create table t2(id int);
insert into t1 values(0),(1); insert into t1 values(0),(1);
......
...@@ -1040,7 +1040,80 @@ EXECUTE STMT USING @id,@id; ...@@ -1040,7 +1040,80 @@ EXECUTE STMT USING @id,@id;
DEALLOCATE PREPARE STMT; DEALLOCATE PREPARE STMT;
DROP TABLE t1; DROP TABLE t1;
--echo End of 4.1 tests #
# BUG#21354: (COUNT(*) = 1) not working in SELECT inside prepared
# statement
#
--disable_warnings
DROP TABLE IF EXISTS t1;
--enable_warnings
CREATE TABLE t1 (i INT, INDEX(i));
INSERT INTO t1 VALUES (1);
PREPARE stmt FROM "SELECT (COUNT(i) = 1), COUNT(i) FROM t1 WHERE i = ?";
SET @a = 0;
EXECUTE stmt USING @a;
SET @a = 1;
EXECUTE stmt USING @a;
SET @a = 0;
EXECUTE stmt USING @a;
PREPARE stmt FROM "SELECT (AVG(i) = 1), AVG(i) FROM t1 WHERE i = ?";
SET @a = 0;
EXECUTE stmt USING @a;
SET @a = 1;
EXECUTE stmt USING @a;
SET @a = 0;
EXECUTE stmt USING @a;
PREPARE stmt FROM "SELECT (VARIANCE(i) = 1), VARIANCE(i) FROM t1 WHERE i = ?";
SET @a = 0;
EXECUTE stmt USING @a;
SET @a = 1;
EXECUTE stmt USING @a;
SET @a = 0;
EXECUTE stmt USING @a;
PREPARE stmt FROM "SELECT (STDDEV(i) = 1), STDDEV(i) FROM t1 WHERE i = ?";
SET @a = 0;
EXECUTE stmt USING @a;
SET @a = 1;
EXECUTE stmt USING @a;
SET @a = 0;
EXECUTE stmt USING @a;
PREPARE stmt FROM "SELECT (BIT_OR(i) = 1), BIT_OR(i) FROM t1 WHERE i = ?";
SET @a = 0;
EXECUTE stmt USING @a;
SET @a = 1;
EXECUTE stmt USING @a;
SET @a = 0;
EXECUTE stmt USING @a;
PREPARE stmt FROM "SELECT (BIT_AND(i) = 1), BIT_AND(i) FROM t1 WHERE i = ?";
SET @a = 0;
EXECUTE stmt USING @a;
SET @a = 1;
EXECUTE stmt USING @a;
SET @a = 0;
EXECUTE stmt USING @a;
PREPARE stmt FROM "SELECT (BIT_XOR(i) = 1), BIT_XOR(i) FROM t1 WHERE i = ?";
SET @a = 0;
EXECUTE stmt USING @a;
SET @a = 1;
EXECUTE stmt USING @a;
SET @a = 0;
EXECUTE stmt USING @a;
DEALLOCATE PREPARE stmt;
DROP TABLE t1;
--echo End of 4.1 tests.
############################# 5.0 tests start ################################ ############################# 5.0 tests start ################################
# #
# #
...@@ -1437,6 +1510,26 @@ DEALLOCATE PREPARE stmt; ...@@ -1437,6 +1510,26 @@ DEALLOCATE PREPARE stmt;
DROP TABLE t1, t2; DROP TABLE t1, t2;
#
# BUG#21856: Prepared Statments: crash if bad create
#
--disable_warnings
DROP PROCEDURE IF EXISTS p1;
--enable_warnings
let $iterations= 100;
--disable_query_log
--disable_result_log
while ($iterations > 0)
{
--error ER_PARSE_ERROR
PREPARE stmt FROM "CREATE PROCEDURE p1()";
dec $iterations;
}
--enable_query_log
--enable_result_log
--echo End of 5.0 tests. --echo End of 5.0 tests.
# #
......
...@@ -1769,6 +1769,47 @@ BEGIN ...@@ -1769,6 +1769,47 @@ BEGIN
END; END;
#
# BUG#20953: create proc with a create view that uses local
# vars/params should fail to create
#
# See test case for what syntax is forbidden in a view.
#
--disable_warnings
DROP TABLE IF EXISTS t1;
--enable_warnings
CREATE TABLE t1 (i INT);
# We do not have to drop this procedure and view because they won't be
# created.
--error ER_VIEW_SELECT_CLAUSE
CREATE PROCEDURE bug20953() CREATE VIEW v AS SELECT 1 INTO @a;
--error ER_VIEW_SELECT_CLAUSE
CREATE PROCEDURE bug20953() CREATE VIEW v AS SELECT 1 INTO DUMPFILE "file";
--error ER_VIEW_SELECT_CLAUSE
CREATE PROCEDURE bug20953() CREATE VIEW v AS SELECT 1 INTO OUTFILE "file";
--error ER_VIEW_SELECT_CLAUSE
CREATE PROCEDURE bug20953()
CREATE VIEW v AS SELECT i FROM t1 PROCEDURE ANALYSE();
--error ER_VIEW_SELECT_DERIVED
CREATE PROCEDURE bug20953() CREATE VIEW v AS SELECT 1 FROM (SELECT 1) AS d1;
--error ER_VIEW_SELECT_VARIABLE
CREATE PROCEDURE bug20953(i INT) CREATE VIEW v AS SELECT i;
delimiter |;
--error ER_VIEW_SELECT_VARIABLE
CREATE PROCEDURE bug20953()
BEGIN
DECLARE i INT;
CREATE VIEW v AS SELECT i;
END |
delimiter ;|
--error ER_VIEW_SELECT_VARIABLE
PREPARE stmt FROM "CREATE VIEW v AS SELECT ?";
DROP TABLE t1;
# #
# End of 5.0 tests # End of 5.0 tests
# #
...@@ -1788,12 +1829,14 @@ begin ...@@ -1788,12 +1829,14 @@ begin
show authors; show authors;
return 42; return 42;
end| end|
delimiter ;|
# #
# BUG#20701: BINARY keyword should be forbidden in stored routines # BUG#20701: BINARY keyword should be forbidden in stored routines
# #
--disable_warnings --disable_warnings
drop function if exists bug20701| drop function if exists bug20701;
--enable_warnings --enable_warnings
# #
# This was disabled in 5.1.12. See bug #20701 # This was disabled in 5.1.12. See bug #20701
...@@ -1801,17 +1844,19 @@ drop function if exists bug20701| ...@@ -1801,17 +1844,19 @@ drop function if exists bug20701|
# be removed. # be removed.
# #
--error ER_NOT_SUPPORTED_YET --error ER_NOT_SUPPORTED_YET
create function bug20701() returns varchar(25) binary return "test"| create function bug20701() returns varchar(25) binary return "test";
create function bug20701() returns varchar(25) return "test"| create function bug20701() returns varchar(25) return "test";
drop function bug20701| drop function bug20701;
--echo End of 5.1 tests --echo End of 5.1 tests
# #
# BUG#NNNN: New bug synopsis # BUG#NNNN: New bug synopsis
# #
#--disable_warnings #--disable_warnings
#drop procedure if exists bugNNNN| #drop procedure if exists bugNNNN;
#drop function if exists bugNNNN| #drop function if exists bugNNNN;
#--enable_warnings #--enable_warnings
#create procedure bugNNNN... #create procedure bugNNNN...
#create function bugNNNN... #create function bugNNNN...
...@@ -23,8 +23,11 @@ create table t1 (a int, b int); ...@@ -23,8 +23,11 @@ create table t1 (a int, b int);
insert into t1 values (1,2), (1,3), (2,4), (2,5), (3,10); insert into t1 values (1,2), (1,3), (2,4), (2,5), (3,10);
# view with variable # view with variable
-- error 1351 -- error ER_VIEW_SELECT_VARIABLE
create view v1 (c,d) as select a,b+@@global.max_user_connections from t1; create view v1 (c,d) as select a,b+@@global.max_user_connections from t1;
-- error ER_VIEW_SELECT_VARIABLE
create view v1 (c,d) as select a,b from t1
where a = @@global.max_user_connections;
# simple view # simple view
create view v1 (c) as select b+1 from t1; create view v1 (c) as select b+1 from t1;
...@@ -486,19 +489,6 @@ drop view v1; ...@@ -486,19 +489,6 @@ drop view v1;
-- error 1060 -- error 1060
create view v1 (a,a) as select 'a','a'; create view v1 (a,a) as select 'a','a';
#
# SP variables inside view test
#
--disable_warnings
drop procedure if exists p1;
--enable_warnings
delimiter //;
create procedure p1 () begin declare v int; create view v1 as select v; end;//
delimiter ;//
-- error 1351
call p1();
drop procedure p1;
# #
# updatablity should be transitive # updatablity should be transitive
# #
...@@ -820,6 +810,8 @@ create view v1 as select 5 into outfile 'ttt'; ...@@ -820,6 +810,8 @@ create view v1 as select 5 into outfile 'ttt';
create table t1 (a int); create table t1 (a int);
-- error 1350 -- error 1350
create view v1 as select a from t1 procedure analyse(); create view v1 as select a from t1 procedure analyse();
-- error ER_VIEW_SELECT_DERIVED
create view v1 as select 1 from (select 1) as d1;
drop table t1; drop table t1;
# #
...@@ -2886,6 +2878,38 @@ DROP VIEW v1; ...@@ -2886,6 +2878,38 @@ DROP VIEW v1;
DROP TABLE t1, t2; DROP TABLE t1, t2;
# #
# Bug#19111: TRIGGERs selecting from a VIEW on the firing base table
# fail
#
# Allow to select from a view on a table being modified in a trigger
# and stored function, since plain select is allowed there.
#
--disable_warnings
DROP FUNCTION IF EXISTS f1;
DROP VIEW IF EXISTS v1;
DROP TABLE IF EXISTS t1;
--enable_warnings
CREATE TABLE t1 (i INT);
INSERT INTO t1 VALUES (1);
CREATE VIEW v1 AS SELECT MAX(i) FROM t1;
# Plain 'SET NEW.i = (SELECT MAX(i) FROM t1) + 1' works, so select
# from a view should work too.
CREATE TRIGGER t1_bi BEFORE INSERT ON t1 FOR EACH ROW
SET NEW.i = (SELECT * FROM v1) + 1;
INSERT INTO t1 VALUES (1);
# Plain 'RETURN (SELECT MAX(i) FROM t1)' works in INSERT, so select
# from a view should work too.
CREATE FUNCTION f1() RETURNS INT RETURN (SELECT * FROM v1);
UPDATE t1 SET i= f1();
DROP FUNCTION f1;
DROP VIEW v1;
DROP TABLE t1;
# Bug #16813 (WITH CHECK OPTION doesn't work with UPDATE) # Bug #16813 (WITH CHECK OPTION doesn't work with UPDATE)
# #
CREATE TABLE t1(id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, val INT UNSIGNED NOT NULL); CREATE TABLE t1(id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, val INT UNSIGNED NOT NULL);
......
...@@ -886,14 +886,29 @@ Event_queue_element::load_from_row(TABLE *table) ...@@ -886,14 +886,29 @@ Event_queue_element::load_from_row(TABLE *table)
goto error; goto error;
/* /*
In DB the values start from 1 but enum interval_type starts We load the interval type from disk as string and then map it to
from 0 an integer. This decouples the values of enum interval_type
and values actually stored on disk. Therefore the type can be
reordered without risking incompatibilities of data between versions.
*/ */
if (!table->field[ET_FIELD_TRANSIENT_INTERVAL]->is_null()) if (!table->field[ET_FIELD_TRANSIENT_INTERVAL]->is_null())
interval= (interval_type) ((ulonglong) {
table->field[ET_FIELD_TRANSIENT_INTERVAL]->val_int() - 1); int i;
else char buff[MAX_FIELD_WIDTH];
interval= (interval_type) 0; String str(buff, sizeof(buff), &my_charset_bin);
LEX_STRING tmp;
table->field[ET_FIELD_TRANSIENT_INTERVAL]->val_str(&str);
if (!(tmp.length= str.length()))
goto error;
tmp.str= str.c_ptr_safe();
i= find_string_in_array(interval_type_to_name, &tmp, system_charset_info);
if (i < 0)
goto error;
interval= (interval_type) i;
}
table->field[ET_FIELD_LAST_EXECUTED]->get_date(&last_executed, table->field[ET_FIELD_LAST_EXECUTED]->get_date(&last_executed,
TIME_NO_ZERO_DATE); TIME_NO_ZERO_DATE);
......
...@@ -188,11 +188,11 @@ mysql_event_fill_row(THD *thd, TABLE *table, Event_parse_data *et, ...@@ -188,11 +188,11 @@ mysql_event_fill_row(THD *thd, TABLE *table, Event_parse_data *et,
fields[ET_FIELD_INTERVAL_EXPR]->store((longlong)et->expression, TRUE); fields[ET_FIELD_INTERVAL_EXPR]->store((longlong)et->expression, TRUE);
fields[ET_FIELD_TRANSIENT_INTERVAL]->set_notnull(); fields[ET_FIELD_TRANSIENT_INTERVAL]->set_notnull();
/*
In the enum (C) intervals start from 0 but in mysql enum valid values fields[ET_FIELD_TRANSIENT_INTERVAL]->
start from 1. Thus +1 offset is needed! store(interval_type_to_name[et->interval].str,
*/ interval_type_to_name[et->interval].length,
fields[ET_FIELD_TRANSIENT_INTERVAL]->store((longlong)et->interval+1, TRUE); scs);
fields[ET_FIELD_EXECUTE_AT]->set_null(); fields[ET_FIELD_EXECUTE_AT]->set_null();
......
...@@ -1065,6 +1065,7 @@ longlong Item_sum_count::val_int() ...@@ -1065,6 +1065,7 @@ longlong Item_sum_count::val_int()
void Item_sum_count::cleanup() void Item_sum_count::cleanup()
{ {
DBUG_ENTER("Item_sum_count::cleanup"); DBUG_ENTER("Item_sum_count::cleanup");
clear();
Item_sum_int::cleanup(); Item_sum_int::cleanup();
used_table_cache= ~(table_map) 0; used_table_cache= ~(table_map) 0;
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
......
...@@ -260,9 +260,30 @@ class Item_sum :public Item_result_field ...@@ -260,9 +260,30 @@ class Item_sum :public Item_result_field
Item_sum(THD *thd, Item_sum *item); Item_sum(THD *thd, Item_sum *item);
enum Type type() const { return SUM_FUNC_ITEM; } enum Type type() const { return SUM_FUNC_ITEM; }
virtual enum Sumfunctype sum_func () const=0; virtual enum Sumfunctype sum_func () const=0;
/*
This method is similar to add(), but it is called when the current
aggregation group changes. Thus it performs a combination of
clear() and add().
*/
inline bool reset() { clear(); return add(); }; inline bool reset() { clear(); return add(); };
/*
Prepare this item for evaluation of an aggregate value. This is
called by reset() when a group changes, or, for correlated
subqueries, between subquery executions. E.g. for COUNT(), this
method should set count= 0;
*/
virtual void clear()= 0; virtual void clear()= 0;
/*
This method is called for the next row in the same group. Its
purpose is to aggregate the new value to the previous values in
the group (i.e. since clear() was called last time). For example,
for COUNT(), do count++.
*/
virtual bool add()=0; virtual bool add()=0;
/* /*
Called when new group is started and results are being saved in Called when new group is started and results are being saved in
a temporary table. Similar to reset(), but must also store value in a temporary table. Similar to reset(), but must also store value in
...@@ -306,7 +327,17 @@ class Item_sum :public Item_result_field ...@@ -306,7 +327,17 @@ class Item_sum :public Item_result_field
void make_field(Send_field *field); void make_field(Send_field *field);
void print(String *str); void print(String *str);
void fix_num_length_and_dec(); void fix_num_length_and_dec();
void no_rows_in_result() { reset(); }
/*
This function is called by the execution engine to assign 'NO ROWS
FOUND' value to an aggregate item, when the underlying result set
has no rows. Such value, in a general case, may be different from
the default value of the item after 'clear()': e.g. a numeric item
may be initialized to 0 by clear() and to NULL by
no_rows_in_result().
*/
void no_rows_in_result() { clear(); }
virtual bool setup(THD *thd) {return 0;} virtual bool setup(THD *thd) {return 0;}
virtual void make_unique() {} virtual void make_unique() {}
Item *get_tmp_table_item(THD *thd); Item *get_tmp_table_item(THD *thd);
...@@ -610,6 +641,11 @@ class Item_sum_avg :public Item_sum_sum ...@@ -610,6 +641,11 @@ class Item_sum_avg :public Item_sum_sum
const char *func_name() const { return "avg("; } const char *func_name() const { return "avg("; }
Item *copy_or_same(THD* thd); Item *copy_or_same(THD* thd);
Field *create_tmp_field(bool group, TABLE *table, uint convert_blob_length); Field *create_tmp_field(bool group, TABLE *table, uint convert_blob_length);
void cleanup()
{
clear();
Item_sum_num::cleanup();
}
}; };
class Item_sum_variance; class Item_sum_variance;
...@@ -689,6 +725,11 @@ class Item_sum_variance : public Item_sum_num ...@@ -689,6 +725,11 @@ class Item_sum_variance : public Item_sum_num
Item *copy_or_same(THD* thd); Item *copy_or_same(THD* thd);
Field *create_tmp_field(bool group, TABLE *table, uint convert_blob_length); Field *create_tmp_field(bool group, TABLE *table, uint convert_blob_length);
enum Item_result result_type () const { return REAL_RESULT; } enum Item_result result_type () const { return REAL_RESULT; }
void cleanup()
{
clear();
Item_sum_num::cleanup();
}
}; };
class Item_sum_std; class Item_sum_std;
...@@ -819,6 +860,11 @@ class Item_sum_bit :public Item_sum_int ...@@ -819,6 +860,11 @@ class Item_sum_bit :public Item_sum_int
void update_field(); void update_field();
void fix_length_and_dec() void fix_length_and_dec()
{ decimals= 0; max_length=21; unsigned_flag= 1; maybe_null= null_value= 0; } { decimals= 0; max_length=21; unsigned_flag= 1; maybe_null= null_value= 0; }
void cleanup()
{
clear();
Item_sum_int::cleanup();
}
}; };
......
...@@ -1485,6 +1485,8 @@ uint find_type2(TYPELIB *lib, const char *find, uint length, CHARSET_INFO *cs); ...@@ -1485,6 +1485,8 @@ uint find_type2(TYPELIB *lib, const char *find, uint length, CHARSET_INFO *cs);
void unhex_type2(TYPELIB *lib); void unhex_type2(TYPELIB *lib);
uint check_word(TYPELIB *lib, const char *val, const char *end, uint check_word(TYPELIB *lib, const char *val, const char *end,
const char **end_of_word); const char **end_of_word);
int find_string_in_array(LEX_STRING * const haystack, LEX_STRING * const needle,
CHARSET_INFO * const cs);
bool is_keyword(const char *name, uint len); bool is_keyword(const char *name, uint len);
......
...@@ -107,4 +107,20 @@ class File_parser: public Sql_alloc ...@@ -107,4 +107,20 @@ class File_parser: public Sql_alloc
bool bad_format_errors); bool bad_format_errors);
}; };
/*
Custom version of standard offsetof() macro which can be used to get
offsets of members in class for non-POD types (according to the current
version of C++ standard offsetof() macro can't be used in such cases and
attempt to do so causes warnings to be emitted, OTOH in many cases it is
still OK to assume that all instances of the class has the same offsets
for the same members).
This is temporary solution which should be removed once File_parser class
and related routines are refactored.
*/
#define my_offsetof(TYPE, MEMBER) \
((size_t)((char *)&(((TYPE *)0x10)->MEMBER) - (char*)0x10))
#endif /* _PARSE_FILE_H_ */ #endif /* _PARSE_FILE_H_ */
...@@ -1365,6 +1365,10 @@ TABLE_LIST *find_table_in_list(TABLE_LIST *table, ...@@ -1365,6 +1365,10 @@ TABLE_LIST *find_table_in_list(TABLE_LIST *table,
Also SELECT::exclude_from_table_unique_test used to exclude from check Also SELECT::exclude_from_table_unique_test used to exclude from check
tables of main SELECT of multi-delete and multi-update tables of main SELECT of multi-delete and multi-update
We also skip tables with TABLE_LIST::prelocking_placeholder set,
because we want to allow SELECTs from them, and their modification
will rise the error anyway.
TODO: when we will have table/view change detection we can do this check TODO: when we will have table/view change detection we can do this check
only once for PS/SP only once for PS/SP
...@@ -1411,12 +1415,13 @@ TABLE_LIST* unique_table(THD *thd, TABLE_LIST *table, TABLE_LIST *table_list) ...@@ -1411,12 +1415,13 @@ TABLE_LIST* unique_table(THD *thd, TABLE_LIST *table, TABLE_LIST *table_list)
if (((! (res= find_table_in_global_list(table_list, d_name, t_name))) && if (((! (res= find_table_in_global_list(table_list, d_name, t_name))) &&
(! (res= mysql_lock_have_duplicate(thd, table, table_list)))) || (! (res= mysql_lock_have_duplicate(thd, table, table_list)))) ||
((!res->table || res->table != table->table) && ((!res->table || res->table != table->table) &&
res->select_lex && !res->select_lex->exclude_from_table_unique_test)) res->select_lex && !res->select_lex->exclude_from_table_unique_test &&
!res->prelocking_placeholder))
break; break;
/* /*
If we found entry of this table or or table of SELECT which already If we found entry of this table or table of SELECT which already
processed in derived table or top select of multi-update/multi-delete processed in derived table or top select of multi-update/multi-delete
(exclude_from_table_unique_test). (exclude_from_table_unique_test) or prelocking placeholder.
*/ */
table_list= res->next_global; table_list= res->next_global;
DBUG_PRINT("info", DBUG_PRINT("info",
......
...@@ -151,7 +151,6 @@ void lex_start(THD *thd, const uchar *buf, uint length) ...@@ -151,7 +151,6 @@ void lex_start(THD *thd, const uchar *buf, uint length)
lex->safe_to_cache_query= 1; lex->safe_to_cache_query= 1;
lex->time_zone_tables_used= 0; lex->time_zone_tables_used= 0;
lex->leaf_tables_insert= 0; lex->leaf_tables_insert= 0;
lex->variables_used= 0;
lex->empty_field_list_on_rset= 0; lex->empty_field_list_on_rset= 0;
lex->select_lex.select_number= 1; lex->select_lex.select_number= 1;
lex->next_state=MY_LEX_START; lex->next_state=MY_LEX_START;
......
...@@ -867,6 +867,25 @@ class Query_tables_list ...@@ -867,6 +867,25 @@ class Query_tables_list
}; };
/*
st_parsing_options contains the flags for constructions that are
allowed in the current statement.
*/
struct st_parsing_options
{
bool allows_variable;
bool allows_select_into;
bool allows_select_procedure;
bool allows_derived;
st_parsing_options()
: allows_variable(TRUE), allows_select_into(TRUE),
allows_select_procedure(TRUE), allows_derived(TRUE)
{}
};
/* The state of the lex parsing. This is saved in the THD struct */ /* The state of the lex parsing. This is saved in the THD struct */
typedef struct st_lex : public Query_tables_list typedef struct st_lex : public Query_tables_list
...@@ -1023,7 +1042,7 @@ typedef struct st_lex : public Query_tables_list ...@@ -1023,7 +1042,7 @@ typedef struct st_lex : public Query_tables_list
bool stmt_prepare_mode; bool stmt_prepare_mode;
bool safe_to_cache_query; bool safe_to_cache_query;
bool subqueries, ignore; bool subqueries, ignore;
bool variables_used; st_parsing_options parsing_options;
ALTER_INFO alter_info; ALTER_INFO alter_info;
/* Prepared statements SQL syntax:*/ /* Prepared statements SQL syntax:*/
LEX_STRING prepared_stmt_name; /* Statement name (in all queries) */ LEX_STRING prepared_stmt_name; /* Statement name (in all queries) */
......
...@@ -6088,14 +6088,19 @@ void mysql_parse(THD *thd, char *inBuf, uint length) ...@@ -6088,14 +6088,19 @@ void mysql_parse(THD *thd, char *inBuf, uint length)
DBUG_ASSERT(thd->net.report_error); DBUG_ASSERT(thd->net.report_error);
DBUG_PRINT("info",("Command aborted. Fatal_error: %d", DBUG_PRINT("info",("Command aborted. Fatal_error: %d",
thd->is_fatal_error)); thd->is_fatal_error));
query_cache_abort(&thd->net);
lex->unit.cleanup(); /*
The first thing we do after parse error is freeing sp_head to
ensure that we have restored original memroot.
*/
if (lex->sphead) if (lex->sphead)
{ {
/* Clean up after failed stored procedure/function */ /* Clean up after failed stored procedure/function */
delete lex->sphead; delete lex->sphead;
lex->sphead= NULL; lex->sphead= NULL;
} }
query_cache_abort(&thd->net);
lex->unit.cleanup();
} }
thd->proc_info="freeing items"; thd->proc_info="freeing items";
thd->end_statement(); thd->end_statement();
......
...@@ -2811,7 +2811,19 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len) ...@@ -2811,7 +2811,19 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len)
error= MYSQLparse((void *)thd) || thd->is_fatal_error || error= MYSQLparse((void *)thd) || thd->is_fatal_error ||
thd->net.report_error || init_param_array(this); thd->net.report_error || init_param_array(this);
/*
The first thing we do after parse error is freeing sp_head to
ensure that we have restored original memroot.
*/
if (error && lex->sphead)
{
delete lex->sphead;
lex->sphead= NULL;
}
lex->safe_to_cache_query= FALSE; lex->safe_to_cache_query= FALSE;
/* /*
While doing context analysis of the query (in check_prepared_statement) While doing context analysis of the query (in check_prepared_statement)
we allocate a lot of additional memory: for open tables, JOINs, derived we allocate a lot of additional memory: for open tables, JOINs, derived
...@@ -2837,6 +2849,7 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len) ...@@ -2837,6 +2849,7 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len)
if (error == 0) if (error == 0)
error= check_prepared_statement(this, name.str != 0); error= check_prepared_statement(this, name.str != 0);
/* Free sp_head if check_prepared_statement() failed. */
if (error && lex->sphead) if (error && lex->sphead)
{ {
delete lex->sphead; delete lex->sphead;
......
...@@ -36,17 +36,17 @@ static File_option triggers_file_parameters[]= ...@@ -36,17 +36,17 @@ static File_option triggers_file_parameters[]=
{ {
{ {
{ C_STRING_WITH_LEN("triggers") }, { C_STRING_WITH_LEN("triggers") },
offsetof(class Table_triggers_list, definitions_list), my_offsetof(class Table_triggers_list, definitions_list),
FILE_OPTIONS_STRLIST FILE_OPTIONS_STRLIST
}, },
{ {
{ C_STRING_WITH_LEN("sql_modes") }, { C_STRING_WITH_LEN("sql_modes") },
offsetof(class Table_triggers_list, definition_modes_list), my_offsetof(class Table_triggers_list, definition_modes_list),
FILE_OPTIONS_ULLLIST FILE_OPTIONS_ULLLIST
}, },
{ {
{ C_STRING_WITH_LEN("definers") }, { C_STRING_WITH_LEN("definers") },
offsetof(class Table_triggers_list, definers_list), my_offsetof(class Table_triggers_list, definers_list),
FILE_OPTIONS_STRLIST FILE_OPTIONS_STRLIST
}, },
{ { 0, 0 }, 0, FILE_OPTIONS_STRING } { { 0, 0 }, 0, FILE_OPTIONS_STRING }
...@@ -55,7 +55,7 @@ static File_option triggers_file_parameters[]= ...@@ -55,7 +55,7 @@ static File_option triggers_file_parameters[]=
File_option sql_modes_parameters= File_option sql_modes_parameters=
{ {
{ C_STRING_WITH_LEN("sql_modes") }, { C_STRING_WITH_LEN("sql_modes") },
offsetof(class Table_triggers_list, definition_modes_list), my_offsetof(class Table_triggers_list, definition_modes_list),
FILE_OPTIONS_ULLLIST FILE_OPTIONS_ULLLIST
}; };
......
...@@ -236,25 +236,9 @@ bool mysql_create_view(THD *thd, ...@@ -236,25 +236,9 @@ bool mysql_create_view(THD *thd,
bool res= FALSE; bool res= FALSE;
DBUG_ENTER("mysql_create_view"); DBUG_ENTER("mysql_create_view");
if (lex->proc_list.first || /* This is ensured in the parser. */
lex->result) DBUG_ASSERT(!lex->proc_list.first && !lex->result &&
{ !lex->param_list.elements && !lex->derived_tables);
my_error(ER_VIEW_SELECT_CLAUSE, MYF(0), (lex->result ?
"INTO" :
"PROCEDURE"));
res= TRUE;
goto err;
}
if (lex->derived_tables ||
lex->variables_used || lex->param_list.elements)
{
int err= (lex->derived_tables ?
ER_VIEW_SELECT_DERIVED :
ER_VIEW_SELECT_VARIABLE);
my_message(err, ER(err), MYF(0));
res= TRUE;
goto err;
}
if (mode != VIEW_CREATE_NEW) if (mode != VIEW_CREATE_NEW)
{ {
...@@ -582,40 +566,40 @@ static const int num_view_backups= 3; ...@@ -582,40 +566,40 @@ static const int num_view_backups= 3;
*/ */
static File_option view_parameters[]= static File_option view_parameters[]=
{{{ C_STRING_WITH_LEN("query")}, {{{ C_STRING_WITH_LEN("query")},
offsetof(TABLE_LIST, query), my_offsetof(TABLE_LIST, query),
FILE_OPTIONS_ESTRING}, FILE_OPTIONS_ESTRING},
{{ C_STRING_WITH_LEN("md5")}, {{ C_STRING_WITH_LEN("md5")},
offsetof(TABLE_LIST, md5), my_offsetof(TABLE_LIST, md5),
FILE_OPTIONS_STRING}, FILE_OPTIONS_STRING},
{{ C_STRING_WITH_LEN("updatable")}, {{ C_STRING_WITH_LEN("updatable")},
offsetof(TABLE_LIST, updatable_view), my_offsetof(TABLE_LIST, updatable_view),
FILE_OPTIONS_ULONGLONG}, FILE_OPTIONS_ULONGLONG},
{{ C_STRING_WITH_LEN("algorithm")}, {{ C_STRING_WITH_LEN("algorithm")},
offsetof(TABLE_LIST, algorithm), my_offsetof(TABLE_LIST, algorithm),
FILE_OPTIONS_ULONGLONG}, FILE_OPTIONS_ULONGLONG},
{{ C_STRING_WITH_LEN("definer_user")}, {{ C_STRING_WITH_LEN("definer_user")},
offsetof(TABLE_LIST, definer.user), my_offsetof(TABLE_LIST, definer.user),
FILE_OPTIONS_STRING}, FILE_OPTIONS_STRING},
{{ C_STRING_WITH_LEN("definer_host")}, {{ C_STRING_WITH_LEN("definer_host")},
offsetof(TABLE_LIST, definer.host), my_offsetof(TABLE_LIST, definer.host),
FILE_OPTIONS_STRING}, FILE_OPTIONS_STRING},
{{ C_STRING_WITH_LEN("suid")}, {{ C_STRING_WITH_LEN("suid")},
offsetof(TABLE_LIST, view_suid), my_offsetof(TABLE_LIST, view_suid),
FILE_OPTIONS_ULONGLONG}, FILE_OPTIONS_ULONGLONG},
{{ C_STRING_WITH_LEN("with_check_option")}, {{ C_STRING_WITH_LEN("with_check_option")},
offsetof(TABLE_LIST, with_check), my_offsetof(TABLE_LIST, with_check),
FILE_OPTIONS_ULONGLONG}, FILE_OPTIONS_ULONGLONG},
{{ C_STRING_WITH_LEN("revision")}, {{ C_STRING_WITH_LEN("revision")},
offsetof(TABLE_LIST, revision), my_offsetof(TABLE_LIST, revision),
FILE_OPTIONS_REV}, FILE_OPTIONS_REV},
{{ C_STRING_WITH_LEN("timestamp")}, {{ C_STRING_WITH_LEN("timestamp")},
offsetof(TABLE_LIST, timestamp), my_offsetof(TABLE_LIST, timestamp),
FILE_OPTIONS_TIMESTAMP}, FILE_OPTIONS_TIMESTAMP},
{{ C_STRING_WITH_LEN("create-version")}, {{ C_STRING_WITH_LEN("create-version")},
offsetof(TABLE_LIST, file_version), my_offsetof(TABLE_LIST, file_version),
FILE_OPTIONS_ULONGLONG}, FILE_OPTIONS_ULONGLONG},
{{ C_STRING_WITH_LEN("source")}, {{ C_STRING_WITH_LEN("source")},
offsetof(TABLE_LIST, source), my_offsetof(TABLE_LIST, source),
FILE_OPTIONS_ESTRING}, FILE_OPTIONS_ESTRING},
{{NullS, 0}, 0, {{NullS, 0}, 0,
FILE_OPTIONS_STRING} FILE_OPTIONS_STRING}
......
...@@ -793,7 +793,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); ...@@ -793,7 +793,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%type <item> %type <item>
literal text_literal insert_ident order_ident literal text_literal insert_ident order_ident
simple_ident select_item2 expr opt_expr opt_else sum_expr in_sum_expr simple_ident select_item2 expr opt_expr opt_else sum_expr in_sum_expr
bool_term bool_factor bool_test bool_pri variable variable_aux bool_term bool_factor bool_test bool_pri
predicate bit_expr bit_term bit_factor value_expr term factor predicate bit_expr bit_term bit_factor value_expr term factor
table_wild simple_expr udf_expr table_wild simple_expr udf_expr
expr_or_default set_expr_or_default interval_expr expr_or_default set_expr_or_default interval_expr
...@@ -5953,32 +5953,7 @@ simple_expr: ...@@ -5953,32 +5953,7 @@ simple_expr:
} }
| literal | literal
| param_marker | param_marker
| '@' ident_or_text SET_VAR expr | variable
{
$$= new Item_func_set_user_var($2,$4);
LEX *lex= Lex;
lex->uncacheable(UNCACHEABLE_RAND);
lex->variables_used= 1;
}
| '@' ident_or_text
{
$$= new Item_func_get_user_var($2);
LEX *lex= Lex;
lex->uncacheable(UNCACHEABLE_RAND);
lex->variables_used= 1;
}
| '@' '@' opt_var_ident_type ident_or_text opt_component
{
if ($4.str && $5.str && check_reserved_words(&$4))
{
yyerror(ER(ER_SYNTAX_ERROR));
YYABORT;
}
if (!($$= get_system_var(YYTHD, $3, $4, $5)))
YYABORT;
Lex->variables_used= 1;
}
| sum_expr | sum_expr
| simple_expr OR_OR_SYM simple_expr | simple_expr OR_OR_SYM simple_expr
{ $$= new Item_func_concat($1, $3); } { $$= new Item_func_concat($1, $3); }
...@@ -6701,6 +6676,46 @@ sum_expr: ...@@ -6701,6 +6676,46 @@ sum_expr:
$5->empty(); $5->empty();
}; };
variable:
'@'
{
if (! Lex->parsing_options.allows_variable)
{
my_error(ER_VIEW_SELECT_VARIABLE, MYF(0));
YYABORT;
}
}
variable_aux
{
$$= $3;
}
;
variable_aux:
ident_or_text SET_VAR expr
{
$$= new Item_func_set_user_var($1, $3);
LEX *lex= Lex;
lex->uncacheable(UNCACHEABLE_RAND);
}
| ident_or_text
{
$$= new Item_func_get_user_var($1);
LEX *lex= Lex;
lex->uncacheable(UNCACHEABLE_RAND);
}
| '@' opt_var_ident_type ident_or_text opt_component
{
if ($3.str && $4.str && check_reserved_words(&$3))
{
yyerror(ER(ER_SYNTAX_ERROR));
YYABORT;
}
if (!($$= get_system_var(YYTHD, $2, $3, $4)))
YYABORT;
}
;
opt_distinct: opt_distinct:
/* empty */ { $$ = 0; } /* empty */ { $$ = 0; }
|DISTINCT { $$ = 1; }; |DISTINCT { $$ = 1; };
...@@ -7130,6 +7145,13 @@ select_derived_init: ...@@ -7130,6 +7145,13 @@ select_derived_init:
SELECT_SYM SELECT_SYM
{ {
LEX *lex= Lex; LEX *lex= Lex;
if (! lex->parsing_options.allows_derived)
{
my_error(ER_VIEW_SELECT_DERIVED, MYF(0));
YYABORT;
}
SELECT_LEX *sel= lex->current_select; SELECT_LEX *sel= lex->current_select;
TABLE_LIST *embedding; TABLE_LIST *embedding;
if (!sel->embedding || sel->end_nested_join(lex->thd)) if (!sel->embedding || sel->end_nested_join(lex->thd))
...@@ -7514,6 +7536,13 @@ procedure_clause: ...@@ -7514,6 +7536,13 @@ procedure_clause:
| PROCEDURE ident /* Procedure name */ | PROCEDURE ident /* Procedure name */
{ {
LEX *lex=Lex; LEX *lex=Lex;
if (! lex->parsing_options.allows_select_procedure)
{
my_error(ER_VIEW_SELECT_CLAUSE, MYF(0), "PROCEDURE");
YYABORT;
}
if (&lex->select_lex != lex->current_select) if (&lex->select_lex != lex->current_select)
{ {
my_error(ER_WRONG_USAGE, MYF(0), "PROCEDURE", "subquery"); my_error(ER_WRONG_USAGE, MYF(0), "PROCEDURE", "subquery");
...@@ -7613,28 +7642,40 @@ select_var_ident: ...@@ -7613,28 +7642,40 @@ select_var_ident:
; ;
into: into:
INTO OUTFILE TEXT_STRING_filesystem INTO
{
if (! Lex->parsing_options.allows_select_into)
{
my_error(ER_VIEW_SELECT_CLAUSE, MYF(0), "INTO");
YYABORT;
}
}
into_destination
;
into_destination:
OUTFILE TEXT_STRING_filesystem
{ {
LEX *lex= Lex; LEX *lex= Lex;
lex->uncacheable(UNCACHEABLE_SIDEEFFECT); lex->uncacheable(UNCACHEABLE_SIDEEFFECT);
if (!(lex->exchange= new sql_exchange($3.str, 0)) || if (!(lex->exchange= new sql_exchange($2.str, 0)) ||
!(lex->result= new select_export(lex->exchange))) !(lex->result= new select_export(lex->exchange)))
YYABORT; YYABORT;
} }
opt_field_term opt_line_term opt_field_term opt_line_term
| INTO DUMPFILE TEXT_STRING_filesystem | DUMPFILE TEXT_STRING_filesystem
{ {
LEX *lex=Lex; LEX *lex=Lex;
if (!lex->describe) if (!lex->describe)
{ {
lex->uncacheable(UNCACHEABLE_SIDEEFFECT); lex->uncacheable(UNCACHEABLE_SIDEEFFECT);
if (!(lex->exchange= new sql_exchange($3.str,1))) if (!(lex->exchange= new sql_exchange($2.str,1)))
YYABORT; YYABORT;
if (!(lex->result= new select_dump(lex->exchange))) if (!(lex->result= new select_dump(lex->exchange)))
YYABORT; YYABORT;
} }
} }
| INTO select_var_list_init | select_var_list_init
{ {
Lex->uncacheable(UNCACHEABLE_SIDEEFFECT); Lex->uncacheable(UNCACHEABLE_SIDEEFFECT);
} }
...@@ -8843,8 +8884,13 @@ param_marker: ...@@ -8843,8 +8884,13 @@ param_marker:
{ {
THD *thd=YYTHD; THD *thd=YYTHD;
LEX *lex= thd->lex; LEX *lex= thd->lex;
Item_param *item= new Item_param((uint) (lex->tok_start - Item_param *item;
(uchar *) thd->query)); if (! lex->parsing_options.allows_variable)
{
my_error(ER_VIEW_SELECT_VARIABLE, MYF(0));
YYABORT;
}
item= new Item_param((uint) (lex->tok_start - (uchar *) thd->query));
if (!($$= item) || lex->param_list.push_back(item)) if (!($$= item) || lex->param_list.push_back(item))
{ {
my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0)); my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0));
...@@ -8964,6 +9010,12 @@ simple_ident: ...@@ -8964,6 +9010,12 @@ simple_ident:
if (spc && (spv = spc->find_variable(&$1))) if (spc && (spv = spc->find_variable(&$1)))
{ {
/* We're compiling a stored procedure and found a variable */ /* We're compiling a stored procedure and found a variable */
if (! lex->parsing_options.allows_variable)
{
my_error(ER_VIEW_SELECT_VARIABLE, MYF(0));
YYABORT;
}
Item_splocal *splocal; Item_splocal *splocal;
splocal= new Item_splocal($1, spv->offset, spv->type, splocal= new Item_splocal($1, spv->offset, spv->type,
lex->tok_start_prev - lex->tok_start_prev -
...@@ -8973,7 +9025,6 @@ simple_ident: ...@@ -8973,7 +9025,6 @@ simple_ident:
splocal->m_sp= lex->sphead; splocal->m_sp= lex->sphead;
#endif #endif
$$ = (Item*) splocal; $$ = (Item*) splocal;
lex->variables_used= 1;
lex->safe_to_cache_query=0; lex->safe_to_cache_query=0;
} }
else else
...@@ -10872,6 +10923,24 @@ view_list: ...@@ -10872,6 +10923,24 @@ view_list:
; ;
view_select: view_select:
{
LEX *lex= Lex;
lex->parsing_options.allows_variable= FALSE;
lex->parsing_options.allows_select_into= FALSE;
lex->parsing_options.allows_select_procedure= FALSE;
lex->parsing_options.allows_derived= FALSE;
}
view_select_aux
{
LEX *lex= Lex;
lex->parsing_options.allows_variable= TRUE;
lex->parsing_options.allows_select_into= TRUE;
lex->parsing_options.allows_select_procedure= TRUE;
lex->parsing_options.allows_derived= TRUE;
}
;
view_select_aux:
SELECT_SYM remember_name select_init2 SELECT_SYM remember_name select_init2
{ {
THD *thd=YYTHD; THD *thd=YYTHD;
......
...@@ -312,3 +312,33 @@ uint strconvert(CHARSET_INFO *from_cs, const char *from, ...@@ -312,3 +312,33 @@ uint strconvert(CHARSET_INFO *from_cs, const char *from,
return (uint32) (to - to_start); return (uint32) (to - to_start);
} }
/*
Searches for a LEX_STRING in an LEX_STRING array.
SYNOPSIS
find_string_in_array()
heap The array
needle The string to search for
NOTE
The last LEX_STRING in the array should have str member set to NULL
RETURN VALUES
-1 Not found
>=0 Ordinal position
*/
int find_string_in_array(LEX_STRING * const haystack, LEX_STRING * const needle,
CHARSET_INFO * const cs)
{
const LEX_STRING *pos;
for (pos= haystack; pos->str; pos++)
if (!cs->coll->strnncollsp(cs, (uchar *) pos->str, pos->length,
(uchar *) needle->str, needle->length, 0))
{
return (pos - haystack);
}
return -1;
}
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