From 39689634ac14024aabc6636fd8f5584f7edc349c Mon Sep 17 00:00:00 2001 From: "bell@sanja.is.com.ua" <> Date: Thu, 1 Dec 2005 12:01:38 +0200 Subject: [PATCH 1/5] We should not skip temptable view along with other derived tables during query tables registration. (BUG#15119) --- mysql-test/r/view_query_cache.result | 61 ++++++++++++++++++++++++++++ mysql-test/t/view_query_cache.test | 31 ++++++++++++++ sql/sql_cache.cc | 2 +- 3 files changed, 93 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/view_query_cache.result b/mysql-test/r/view_query_cache.result index 944e1db34c9..03430bd504b 100644 --- a/mysql-test/r/view_query_cache.result +++ b/mysql-test/r/view_query_cache.result @@ -132,4 +132,65 @@ unlock tables; set query_cache_wlock_invalidate=default; drop view v1; drop table t1; +flush status; +create table t1 (a int, b int); +create algorithm=temptable view v1 as select * from t1; +select * from v1; +a b +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 0 +select * from v1; +a b +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 1 +insert into t1 values (1,1); +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 0 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 1 +select * from v1; +a b +1 1 +select * from v1; +a b +1 1 +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 2 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 2 +drop view v1; +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 0 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 2 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 2 +drop table t1; set GLOBAL query_cache_size=default; diff --git a/mysql-test/t/view_query_cache.test b/mysql-test/t/view_query_cache.test index 81994407641..d4ebe45b7ac 100644 --- a/mysql-test/t/view_query_cache.test +++ b/mysql-test/t/view_query_cache.test @@ -96,4 +96,35 @@ unlock tables; set query_cache_wlock_invalidate=default; drop view v1; drop table t1; + +# +# BUG#15119: returning temptable view from the query cache. +# +flush status; +create table t1 (a int, b int); +create algorithm=temptable view v1 as select * from t1; +select * from v1; +show status like "Qcache_queries_in_cache"; +show status like "Qcache_inserts"; +show status like "Qcache_hits"; +select * from v1; +show status like "Qcache_queries_in_cache"; +show status like "Qcache_inserts"; +show status like "Qcache_hits"; +insert into t1 values (1,1); +show status like "Qcache_queries_in_cache"; +show status like "Qcache_inserts"; +show status like "Qcache_hits"; +select * from v1; +select * from v1; +show status like "Qcache_queries_in_cache"; +show status like "Qcache_inserts"; +show status like "Qcache_hits"; +drop view v1; +show status like "Qcache_queries_in_cache"; +show status like "Qcache_inserts"; +show status like "Qcache_hits"; +drop table t1; + +# Reset default environment. set GLOBAL query_cache_size=default; diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index 3965079988b..24ab27c587d 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -2184,7 +2184,7 @@ Query_cache::register_tables_from_list(TABLE_LIST *tables_used, tables_used; tables_used= tables_used->next_global, n++, block_table++) { - if (tables_used->derived) + if (tables_used->derived && !tables_used->view) { DBUG_PRINT("qcache", ("derived table skipped")); n--; From 2ff98e05867ba02dad0b3bd8d27b814afbb54a59 Mon Sep 17 00:00:00 2001 From: "bell@sanja.is.com.ua" <> Date: Thu, 1 Dec 2005 12:15:48 +0200 Subject: [PATCH 2/5] View creation code fixed to expect empty TABLE_LIST::table pointer (BUG#15096). --- mysql-test/r/view.result | 15 +++++++++++++++ mysql-test/t/view.test | 21 +++++++++++++++++++++ sql/sql_view.cc | 35 ++++++++++++++++++++++------------- 3 files changed, 58 insertions(+), 13 deletions(-) diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index ebb2c190eb1..16ed023fdac 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -2424,3 +2424,18 @@ f1 sum(f2) NULL 12 drop view v1; drop table t1; +CREATE VIEW v1 AS SELECT 42 AS Meaning; +DROP FUNCTION IF EXISTS f1; +CREATE FUNCTION f1() RETURNS INTEGER +BEGIN +DECLARE retn INTEGER; +SELECT Meaning FROM v1 INTO retn; +RETURN retn; +END +// +CREATE VIEW v2 AS SELECT f1(); +select * from v2; +f1() +42 +drop view v2,v1; +drop function f1; diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index ac103278f08..8a19b9fce08 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -2280,3 +2280,24 @@ create view v1 as select * from t1; select f1, sum(f2) from v1 group by f1; drop view v1; drop table t1; + +# +# BUG#15096: using function with view for view creation +# +CREATE VIEW v1 AS SELECT 42 AS Meaning; +--disable_warnings +DROP FUNCTION IF EXISTS f1; +--enable_warnings +DELIMITER //; +CREATE FUNCTION f1() RETURNS INTEGER +BEGIN + DECLARE retn INTEGER; + SELECT Meaning FROM v1 INTO retn; + RETURN retn; +END +// +DELIMITER ;// +CREATE VIEW v2 AS SELECT f1(); +select * from v2; +drop view v2,v1; +drop function f1; diff --git a/sql/sql_view.cc b/sql/sql_view.cc index e03d3b22b89..31c5e5fed0a 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -350,15 +350,6 @@ bool mysql_create_view(THD *thd, */ for (tbl= lex->query_tables; tbl; tbl= tbl->next_global) { - /* is this table temporary and is not view? */ - if (tbl->table->s->tmp_table != NO_TMP_TABLE && !tbl->view && - !tbl->schema_table) - { - my_error(ER_VIEW_SELECT_TMPTABLE, MYF(0), tbl->alias); - res= TRUE; - goto err; - } - /* is this table view and the same view which we creates now? */ if (tbl->view && strcmp(tbl->view_db.str, view->db) == 0 && @@ -370,11 +361,29 @@ bool mysql_create_view(THD *thd, } /* - Copy the privileges of the underlying VIEWs which were filled by - fill_effective_table_privileges - (they were not copied at derived tables processing) + tbl->table can be NULL when tbl is a placeholder for a view + that is indirectly referenced via a stored function from the + view being created. We don't check these indirectly + referenced views in CREATE VIEW so they don't have table + object. */ - tbl->table->grant.privilege= tbl->grant.privilege; + if (tbl->table) + { + /* is this table temporary and is not view? */ + if (tbl->table->s->tmp_table != NO_TMP_TABLE && !tbl->view && + !tbl->schema_table) + { + my_error(ER_VIEW_SELECT_TMPTABLE, MYF(0), tbl->alias); + res= TRUE; + goto err; + } + /* + Copy the privileges of the underlying VIEWs which were filled by + fill_effective_table_privileges + (they were not copied at derived tables processing) + */ + tbl->table->grant.privilege= tbl->grant.privilege; + } } /* prepare select to resolve all fields */ From ac26e14e99beffc6d7bacaf4f996d4ff2bd3da19 Mon Sep 17 00:00:00 2001 From: "bell@sanja.is.com.ua" <> Date: Thu, 1 Dec 2005 17:13:54 +0200 Subject: [PATCH 3/5] postmerge fix --- mysql-test/r/query_cache.result | 50 ++++++++++++++++----------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/mysql-test/r/query_cache.result b/mysql-test/r/query_cache.result index c4521b4a71e..405669e95f8 100644 --- a/mysql-test/r/query_cache.result +++ b/mysql-test/r/query_cache.result @@ -850,31 +850,6 @@ group_concat(a) set group_concat_max_len=default; drop table t1; create table t1 (a int); -flush status; -(select a from t1) union (select a from t1); -a -show status like "Qcache_queries_in_cache"; -Variable_name Value -Qcache_queries_in_cache 1 -show status like "Qcache_inserts"; -Variable_name Value -Qcache_inserts 1 -show status like "Qcache_hits"; -Variable_name Value -Qcache_hits 0 -(select a from t1) union (select a from t1); -a -show status like "Qcache_queries_in_cache"; -Variable_name Value -Qcache_queries_in_cache 1 -show status like "Qcache_inserts"; -Variable_name Value -Qcache_inserts 1 -show status like "Qcache_hits"; -Variable_name Value -Qcache_hits 1 -drop table t1; -create table t1 (a int); show status like "Qcache_queries_in_cache"; Variable_name Value Qcache_queries_in_cache 0 @@ -1047,6 +1022,31 @@ Variable_name Value Qcache_hits 1 drop table t1; create table t1 (a int); +flush status; +(select a from t1) union (select a from t1); +a +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 0 +(select a from t1) union (select a from t1); +a +show status like "Qcache_queries_in_cache"; +Variable_name Value +Qcache_queries_in_cache 1 +show status like "Qcache_inserts"; +Variable_name Value +Qcache_inserts 1 +show status like "Qcache_hits"; +Variable_name Value +Qcache_hits 1 +drop table t1; +create table t1 (a int); insert into t1 values (1),(2); CREATE PROCEDURE `p1`() begin From 45e59f3d7674144fdea9aa23fd978f36b015ff30 Mon Sep 17 00:00:00 2001 From: "bell@sanja.is.com.ua" <> Date: Fri, 2 Dec 2005 21:18:12 +0200 Subject: [PATCH 4/5] Now we shall store only position (index of first character) of SELECT from query begining, to be independet of query buffer allocation. Correct procedure used to find beginning of the current statement during parsing (BUG#14885). --- mysql-test/r/view.result | 12 ++++++++++++ mysql-test/t/view.test | 19 +++++++++++++++++++ sql/sp_head.cc | 8 ++++++-- sql/sql_lex.h | 4 ++-- sql/sql_view.cc | 5 ++--- sql/sql_yacc.yy | 16 ++++++++++++---- 6 files changed, 53 insertions(+), 11 deletions(-) diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index ebb2c190eb1..5da6a4f95fd 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -2424,3 +2424,15 @@ f1 sum(f2) NULL 12 drop view v1; drop table t1; +drop procedure if exists p1; +create procedure p1 () deterministic +begin +create view v1 as select 1; +end; +// +call p1(); +show create view v1; +View Create View +v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select 1 AS `1` +drop view v1; +drop procedure p1; diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index ac103278f08..be4fb571320 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -2280,3 +2280,22 @@ create view v1 as select * from t1; select f1, sum(f2) from v1 group by f1; drop view v1; drop table t1; + +# +# BUG#14885: incorrect SOURCE in view created in a procedure +# TODO: here SOURCE string must be shown when it will be possible +# +--disable_warnings +drop procedure if exists p1; +--enable_warnings +delimiter //; +create procedure p1 () deterministic +begin +create view v1 as select 1; +end; +// +delimiter ;// +call p1(); +show create view v1; +drop view v1; +drop procedure p1; diff --git a/sql/sp_head.cc b/sql/sp_head.cc index a6e88c08789..179eebc0caf 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -954,8 +954,12 @@ int sp_head::execute(THD *thd) m_first_instance->m_first_free_instance= m_next_cached_sp; DBUG_PRINT("info", ("first free for 0x%lx ++: 0x%lx->0x%lx, level: %lu, flags %x", (ulong)m_first_instance, this, m_next_cached_sp, - m_next_cached_sp->m_recursion_level, - m_next_cached_sp->m_flags)); + (m_next_cached_sp ? + m_next_cached_sp->m_recursion_level : + 0), + (m_next_cached_sp ? + m_next_cached_sp->m_flags : + 0))); /* Check that if there are not any instances after this one then pointer to the last instance points on this instance or if there are diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 372bbc5576b..c3198beb4e9 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -738,8 +738,8 @@ typedef struct st_lex TABLE_LIST **query_tables_last; /* store original leaf_tables for INSERT SELECT and PS/SP */ TABLE_LIST *leaf_tables_insert; - char *create_view_start; - char *create_view_select_start; + /* Position (first character index) of SELECT of CREATE VIEW statement */ + uint create_view_select_start; /* The definer of the object being created (view, trigger, stored routine). diff --git a/sql/sql_view.cc b/sql/sql_view.cc index e03d3b22b89..3ca592dfd44 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -641,10 +641,9 @@ static int mysql_register_view(THD *thd, TABLE_LIST *view, /* fill structure */ view->query.str= (char*)str.ptr(); view->query.length= str.length()-1; // we do not need last \0 - view->source.str= thd->lex->create_view_select_start; + view->source.str= thd->query + thd->lex->create_view_select_start; view->source.length= (thd->query_length - - (thd->lex->create_view_select_start - - thd->lex->create_view_start)); + thd->lex->create_view_select_start); view->file_version= 1; view->calc_md5(md5); view->md5.str= md5; diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 671e2b1740d..88cc224308c 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -3374,7 +3374,6 @@ alter: THD *thd= YYTHD; LEX *lex= thd->lex; lex->sql_command= SQLCOM_CREATE_VIEW; - lex->create_view_start= thd->query; lex->create_view_mode= VIEW_ALTER; /* first table in list is target VIEW name */ lex->select_lex.add_table_to_list(thd, $6, NULL, 0); @@ -8978,7 +8977,6 @@ view_tail: THD *thd= YYTHD; LEX *lex= thd->lex; lex->sql_command= SQLCOM_CREATE_VIEW; - lex->create_view_start= thd->query; /* first table in list is target VIEW name */ if (!lex->select_lex.add_table_to_list(thd, $3, NULL, 0)) YYABORT; @@ -9009,11 +9007,21 @@ view_list: view_select: SELECT_SYM remember_name select_init2 { - Lex->create_view_select_start= $2; + THD *thd=YYTHD; + LEX *lex= thd->lex; + char *stmt_beg= (lex->sphead ? + (char *)lex->sphead->m_tmp_query : + thd->query); + lex->create_view_select_start= $2 - stmt_beg; } | '(' remember_name select_paren ')' union_opt { - Lex->create_view_select_start= $2; + THD *thd=YYTHD; + LEX *lex= thd->lex; + char *stmt_beg= (lex->sphead ? + (char *)lex->sphead->m_tmp_query : + thd->query); + lex->create_view_select_start= $2 - stmt_beg; } ; From 6f63650d721404b7fb0146a1764d4231d772b0f2 Mon Sep 17 00:00:00 2001 From: "konstantin@mysql.com" <> Date: Fri, 2 Dec 2005 22:43:56 +0300 Subject: [PATCH 5/5] Add a test case for Bug#5967 "Stored procedure declared variable used instead of column", the bug is to be fixed later. --- mysql-test/r/sp.result | 54 ++++++++++++++++++++++++++++++++++++++++++ mysql-test/t/sp.test | 45 +++++++++++++++++++++++++++++++++++ 2 files changed, 99 insertions(+) diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result index 9ea43e5aeb3..6f0a8623a4c 100644 --- a/mysql-test/r/sp.result +++ b/mysql-test/r/sp.result @@ -4099,4 +4099,58 @@ call bug14376(4711)| x 4711 drop procedure bug14376| +drop procedure if exists p1| +Warnings: +Note 1305 PROCEDURE p1 does not exist +drop table if exists t1| +create table t1 (a varchar(255))| +insert into t1 (a) values ("a - table column")| +create procedure p1(a varchar(255)) +begin +declare i varchar(255); +declare c cursor for select a from t1; +select a; +select a from t1 into i; +select i as 'Parameter takes precedence over table column'; open c; +fetch c into i; +close c; +select i as 'Parameter takes precedence over table column in cursors'; +begin +declare a varchar(255) default 'a - local variable'; +declare c1 cursor for select a from t1; +select a as 'A local variable takes precedence over parameter'; +open c1; +fetch c1 into i; +close c1; +select i as 'A local variable takes precedence over parameter in cursors'; +begin +declare a varchar(255) default 'a - local variable in a nested compound statement'; +declare c2 cursor for select a from t1; +select a as 'A local variable in a nested compound statement takes precedence over a local variable in the outer statement'; +select a from t1 into i; +select i as 'A local variable in a nested compound statement takes precedence over table column'; +open c2; +fetch c2 into i; +close c2; +select i as 'A local variable in a nested compound statement takes precedence over table column in cursors'; +end; +end; +end| +call p1("a - stored procedure parameter")| +a +a - stored procedure parameter +Parameter takes precedence over table column +a - stored procedure parameter +Parameter takes precedence over table column in cursors +a - stored procedure parameter +A local variable takes precedence over parameter +a - local variable +A local variable takes precedence over parameter in cursors +a - local variable +A local variable in a nested compound statement takes precedence over a local variable in the outer statement +a - local variable in a nested compound statement +A local variable in a nested compound statement takes precedence over table column +a - local variable in a nested compound statement +A local variable in a nested compound statement takes precedence over table column in cursors +a - local variable in a nested compound statement drop table t1,t2; diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test index 0563835de09..760110b0a64 100644 --- a/mysql-test/t/sp.test +++ b/mysql-test/t/sp.test @@ -4898,7 +4898,52 @@ call bug14376(4711)| drop procedure bug14376| +# +# Bug#5967 "Stored procedure declared variable used instead of column" +# The bug should be fixed later. +# Test precedence of names of parameters, variable declarations, +# variable declarations in nested compound statements, table columns, +# table columns in cursor declarations. +# According to the standard, table columns take precedence over +# variable declarations. In MySQL 5.0 it's vice versa. +# +drop procedure if exists p1| +drop table if exists t1| +create table t1 (a varchar(255))| +insert into t1 (a) values ("a - table column")| +create procedure p1(a varchar(255)) +begin + declare i varchar(255); + declare c cursor for select a from t1; + select a; + select a from t1 into i; + select i as 'Parameter takes precedence over table column'; open c; + fetch c into i; + close c; + select i as 'Parameter takes precedence over table column in cursors'; + begin + declare a varchar(255) default 'a - local variable'; + declare c1 cursor for select a from t1; + select a as 'A local variable takes precedence over parameter'; + open c1; + fetch c1 into i; + close c1; + select i as 'A local variable takes precedence over parameter in cursors'; + begin + declare a varchar(255) default 'a - local variable in a nested compound statement'; + declare c2 cursor for select a from t1; + select a as 'A local variable in a nested compound statement takes precedence over a local variable in the outer statement'; + select a from t1 into i; + select i as 'A local variable in a nested compound statement takes precedence over table column'; + open c2; + fetch c2 into i; + close c2; + select i as 'A local variable in a nested compound statement takes precedence over table column in cursors'; + end; + end; +end| +call p1("a - stored procedure parameter")| # # BUG#NNNN: New bug synopsis