summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorunknown <dkatz@damien-katzs-computer.local>2007-10-10 14:46:30 -0400
committerunknown <dkatz@damien-katzs-computer.local>2007-10-10 14:46:30 -0400
commitf9759397d251b06a08a86c343ee5912650af2f0c (patch)
tree34fc19150b115d38b54ac8187d732744d868ba81
parentc986d919c639a16feaa138ef6d3f8b7cf7e75baa (diff)
parent77c50858822197afd1b50e34c65954fd9bf6931b (diff)
downloadmariadb-git-f9759397d251b06a08a86c343ee5912650af2f0c.tar.gz
Merge bk-internal.mysql.com:/home/bk/mysql-5.0-runtime
into damien-katzs-computer.local:/Users/dkatz/mysql-5.0-runtime
-rw-r--r--mysql-test/r/sp-error.result13
-rw-r--r--mysql-test/r/sp.result6
-rw-r--r--mysql-test/r/udf.result7
-rw-r--r--mysql-test/t/sp-error.test20
-rw-r--r--mysql-test/t/sp.test10
-rw-r--r--mysql-test/t/udf.test14
-rw-r--r--sql/sp.cc13
-rw-r--r--sql/sp_head.cc31
-rw-r--r--sql/sp_head.h11
-rw-r--r--sql/sql_base.cc12
-rw-r--r--sql/sql_handler.cc47
-rw-r--r--sql/sql_yacc.yy31
12 files changed, 157 insertions, 58 deletions
diff --git a/mysql-test/r/sp-error.result b/mysql-test/r/sp-error.result
index bd0640b2b14..cc217ecd093 100644
--- a/mysql-test/r/sp-error.result
+++ b/mysql-test/r/sp-error.result
@@ -1452,3 +1452,16 @@ end
until true end repeat retry;
end//
ERROR 42000: LEAVE with no matching label: retry
+DROP DATABASE IF EXISTS mysqltest;
+CREATE DATABASE mysqltest;
+USE mysqltest;
+DROP DATABASE mysqltest;
+SELECT inexistent(), 1 + ,;
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '' at line 1
+SELECT inexistent();
+ERROR 42000: FUNCTION inexistent does not exist
+SELECT .inexistent();
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '()' at line 1
+SELECT ..inexistent();
+ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '.inexistent()' at line 1
+USE test;
diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result
index b1120a22dfd..ef173b9661f 100644
--- a/mysql-test/r/sp.result
+++ b/mysql-test/r/sp.result
@@ -5667,7 +5667,6 @@ t3_id_1 t3_id_2 t4_id
DROP PROCEDURE p1|
DROP VIEW v1, v2|
DROP TABLE t3, t4|
-End of 5.0 tests
DROP TABLE IF EXISTS bug23760|
DROP TABLE IF EXISTS bug23760_log|
DROP PROCEDURE IF EXISTS bug23760_update_log|
@@ -6145,7 +6144,6 @@ Procedure sql_mode Create Procedure
proc_21513 CREATE DEFINER=`root`@`localhost` PROCEDURE `proc_21513`()
`my_label`:BEGIN END
drop procedure proc_21513|
-End of 5.0 tests.
drop table t1,t2;
CREATE TABLE t1 (a int auto_increment primary key) engine=MyISAM;
CREATE TABLE t2 (a int auto_increment primary key, b int) engine=innodb;
@@ -6565,4 +6563,6 @@ f1()
DROP TABLE t1;
DROP FUNCTION f1;
-End of 5.0 tests
+# ------------------------------------------------------------------
+# -- End of 5.0 tests
+# ------------------------------------------------------------------
diff --git a/mysql-test/r/udf.result b/mysql-test/r/udf.result
index 2e9cf217ed6..3e29c780ca8 100644
--- a/mysql-test/r/udf.result
+++ b/mysql-test/r/udf.result
@@ -296,4 +296,11 @@ Qcache_queries_in_cache 0
drop table t1;
drop function metaphon;
set GLOBAL query_cache_size=default;
+DROP DATABASE IF EXISTS mysqltest;
+CREATE DATABASE mysqltest;
+USE mysqltest;
+DROP DATABASE mysqltest;
+CREATE FUNCTION metaphon RETURNS STRING SONAME "UDF_EXAMPLE_LIB";
+DROP FUNCTION metaphon;
+USE test;
End of 5.0 tests.
diff --git a/mysql-test/t/sp-error.test b/mysql-test/t/sp-error.test
index 240cda67edc..a1abf4852b0 100644
--- a/mysql-test/t/sp-error.test
+++ b/mysql-test/t/sp-error.test
@@ -2090,6 +2090,26 @@ end//
delimiter ;//
#
+# Bug#29816 Syntactically wrong query fails with misleading error message
+#
+
+--disable_warnings
+DROP DATABASE IF EXISTS mysqltest;
+--enable_warnings
+CREATE DATABASE mysqltest;
+USE mysqltest;
+DROP DATABASE mysqltest;
+--error ER_PARSE_ERROR
+SELECT inexistent(), 1 + ,;
+--error ER_SP_DOES_NOT_EXIST
+SELECT inexistent();
+--error ER_PARSE_ERROR
+SELECT .inexistent();
+--error ER_PARSE_ERROR
+SELECT ..inexistent();
+USE test;
+
+#
# BUG#NNNN: New bug synopsis
#
#--disable_warnings
diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test
index 465585a693e..501d96c842a 100644
--- a/mysql-test/t/sp.test
+++ b/mysql-test/t/sp.test
@@ -6642,9 +6642,6 @@ DROP VIEW v1, v2|
DROP TABLE t3, t4|
---echo End of 5.0 tests
-
-
#
# BUG#23760: ROW_COUNT() and store procedure not owrking together
#
@@ -7076,9 +7073,6 @@ show create procedure proc_21513|
drop procedure proc_21513|
-###
---echo End of 5.0 tests.
-
#
# BUG#NNNN: New bug synopsis
#
@@ -7677,4 +7671,6 @@ DROP FUNCTION f1;
###########################################################################
---echo End of 5.0 tests
+--echo # ------------------------------------------------------------------
+--echo # -- End of 5.0 tests
+--echo # ------------------------------------------------------------------
diff --git a/mysql-test/t/udf.test b/mysql-test/t/udf.test
index 75af1f4be4b..6a516a29534 100644
--- a/mysql-test/t/udf.test
+++ b/mysql-test/t/udf.test
@@ -311,5 +311,19 @@ drop table t1;
drop function metaphon;
set GLOBAL query_cache_size=default;
+#
+# Bug#28318 CREATE FUNCTION (UDF) requires a schema
+#
+
+--disable_warnings
+DROP DATABASE IF EXISTS mysqltest;
+--enable_warnings
+CREATE DATABASE mysqltest;
+USE mysqltest;
+DROP DATABASE mysqltest;
+--replace_result $UDF_EXAMPLE_LIB UDF_EXAMPLE_LIB
+eval CREATE FUNCTION metaphon RETURNS STRING SONAME "$UDF_EXAMPLE_LIB";
+DROP FUNCTION metaphon;
+USE test;
--echo End of 5.0 tests.
diff --git a/sql/sp.cc b/sql/sp.cc
index 75d6fa4618f..0b84e1ad07f 100644
--- a/sql/sp.cc
+++ b/sql/sp.cc
@@ -1405,12 +1405,12 @@ static bool add_used_routine(LEX *lex, Query_arena *arena,
{
Sroutine_hash_entry *rn=
(Sroutine_hash_entry *)arena->alloc(sizeof(Sroutine_hash_entry) +
- key->length);
+ key->length + 1);
if (!rn) // OOM. Error will be reported using fatal_error().
return FALSE;
rn->key.length= key->length;
rn->key.str= (char *)rn + sizeof(Sroutine_hash_entry);
- memcpy(rn->key.str, key->str, key->length);
+ memcpy(rn->key.str, key->str, key->length + 1);
my_hash_insert(&lex->sroutines, (byte *)rn);
lex->sroutines_list.link_in_list((byte *)rn, (byte **)&rn->next);
rn->belong_to_view= belong_to_view;
@@ -1595,7 +1595,7 @@ sp_cache_routines_and_add_tables_aux(THD *thd, LEX *lex,
for (Sroutine_hash_entry *rt= start; rt; rt= rt->next)
{
- sp_name name(rt->key.str, rt->key.length);
+ sp_name name(thd, rt->key.str, rt->key.length);
int type= rt->key.str[0];
sp_head *sp;
@@ -1603,13 +1603,6 @@ sp_cache_routines_and_add_tables_aux(THD *thd, LEX *lex,
&thd->sp_func_cache : &thd->sp_proc_cache),
&name)))
{
- name.m_name.str= strchr(name.m_qname.str, '.');
- name.m_db.length= name.m_name.str - name.m_qname.str;
- name.m_db.str= strmake_root(thd->mem_root, name.m_qname.str,
- name.m_db.length);
- name.m_name.str+= 1;
- name.m_name.length= name.m_qname.length - name.m_db.length - 1;
-
switch ((ret= db_find_routine(thd, type, &name, &sp)))
{
case SP_OK:
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index 5ad6625efb8..69dda9ec1e8 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -369,17 +369,42 @@ sp_eval_expr(THD *thd, Field *result_field, Item **expr_item_ptr)
*
*/
+sp_name::sp_name(THD *thd, char *key, uint key_len)
+{
+ m_sroutines_key.str= key;
+ m_sroutines_key.length= key_len;
+ m_qname.str= ++key;
+ m_qname.length= key_len - 1;
+ if ((m_name.str= strchr(m_qname.str, '.')))
+ {
+ m_db.length= m_name.str - key;
+ m_db.str= strmake_root(thd->mem_root, key, m_db.length);
+ m_name.str++;
+ m_name.length= m_qname.length - m_db.length - 1;
+ }
+ else
+ {
+ m_name.str= m_qname.str;
+ m_name.length= m_qname.length;
+ m_db.str= 0;
+ m_db.length= 0;
+ }
+ m_explicit_name= false;
+}
+
void
sp_name::init_qname(THD *thd)
{
- m_sroutines_key.length= m_db.length + m_name.length + 2;
+ const uint dot= !!m_db.length;
+ /* m_sroutines format: m_type + [database + dot] + name + nul */
+ m_sroutines_key.length= 1 + m_db.length + dot + m_name.length;
if (!(m_sroutines_key.str= thd->alloc(m_sroutines_key.length + 1)))
return;
m_qname.length= m_sroutines_key.length - 1;
m_qname.str= m_sroutines_key.str + 1;
- sprintf(m_qname.str, "%.*s.%.*s",
+ sprintf(m_qname.str, "%.*s%.*s%.*s",
m_db.length, (m_db.length ? m_db.str : ""),
- m_name.length, m_name.str);
+ dot, ".", m_name.length, m_name.str);
}
diff --git a/sql/sp_head.h b/sql/sp_head.h
index ebe40ce9c87..7d042367985 100644
--- a/sql/sp_head.h
+++ b/sql/sp_head.h
@@ -72,16 +72,7 @@ public:
Creates temporary sp_name object from key, used mainly
for SP-cache lookups.
*/
- sp_name(char *key, uint key_len)
- {
- m_sroutines_key.str= key;
- m_sroutines_key.length= key_len;
- m_name.str= m_qname.str= key + 1;
- m_name.length= m_qname.length= key_len - 1;
- m_db.str= 0;
- m_db.length= 0;
- m_explicit_name= false;
- }
+ sp_name(THD *thd, char *key, uint key_len);
// Init. the qualified name from the db and name.
void init_qname(THD *thd); // thd for memroot allocation
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 289924ff418..905190cb9cd 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -1745,7 +1745,13 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
DBUG_RETURN(0);
}
- /* close handler tables which are marked for flush */
+ /*
+ In order for the back off and re-start process to work properly,
+ handler tables having old versions (due to FLUSH TABLES or pending
+ name-lock) MUST be closed. This is specially important if a name-lock
+ is pending for any table of the handler_tables list, otherwise a
+ deadlock may occur.
+ */
if (thd->handler_tables)
mysql_ha_flush(thd, (TABLE_LIST*) NULL, MYSQL_HA_REOPEN_ON_USAGE, TRUE);
@@ -1810,6 +1816,10 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
table->db_stat == 0 signals wait_for_locked_table_names
that the tables in question are not used any more. See
table_is_used call for details.
+
+ Notice that HANDLER tables were already taken care of by
+ the earlier call to mysql_ha_flush() in this same critical
+ section.
*/
close_old_data_files(thd,thd->open_tables,0,0);
/*
diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc
index 89090c9fa63..e87381dd49c 100644
--- a/sql/sql_handler.cc
+++ b/sql/sql_handler.cc
@@ -182,7 +182,7 @@ bool mysql_ha_open(THD *thd, TABLE_LIST *tables, bool reopen)
char *db, *name, *alias;
uint dblen, namelen, aliaslen, counter;
int error;
- TABLE *backup_open_tables, *backup_handler_tables;
+ TABLE *backup_open_tables;
DBUG_ENTER("mysql_ha_open");
DBUG_PRINT("enter",("'%s'.'%s' as '%s' reopen: %d",
tables->db, tables->table_name, tables->alias,
@@ -211,14 +211,20 @@ bool mysql_ha_open(THD *thd, TABLE_LIST *tables, bool reopen)
}
}
- /* save open_ and handler_ tables state */
- backup_open_tables= thd->open_tables;
- backup_handler_tables= thd->handler_tables;
+ /*
+ Save and reset the open_tables list so that open_tables() won't
+ be able to access (or know about) the previous list. And on return
+ from open_tables(), thd->open_tables will contain only the opened
+ table.
+
+ The thd->handler_tables list is kept as-is to avoid deadlocks if
+ open_table(), called by open_tables(), needs to back-off because
+ of a pending name-lock on the table being opened.
- /* no pre-opened tables */
+ See open_table() back-off comments for more details.
+ */
+ backup_open_tables= thd->open_tables;
thd->open_tables= NULL;
- /* to avoid flushes */
- thd->handler_tables= NULL;
/*
open_tables() will set 'tables->table' if successful.
@@ -231,9 +237,12 @@ bool mysql_ha_open(THD *thd, TABLE_LIST *tables, bool reopen)
error= open_tables(thd, &tables, &counter, 0);
/* restore the state and merge the opened table into handler_tables list */
- thd->handler_tables= thd->open_tables ?
- thd->open_tables->next= backup_handler_tables,
- thd->open_tables : backup_handler_tables;
+ if (thd->open_tables)
+ {
+ thd->open_tables->next= thd->handler_tables;
+ thd->handler_tables= thd->open_tables;
+ }
+
thd->open_tables= backup_open_tables;
if (error)
@@ -360,7 +369,7 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables,
ha_rows select_limit_cnt, ha_rows offset_limit_cnt)
{
TABLE_LIST *hash_tables;
- TABLE *table, *backup_open_tables, *backup_handler_tables;
+ TABLE *table, *backup_open_tables;
MYSQL_LOCK *lock;
List<Item> list;
Protocol *protocol= thd->protocol;
@@ -437,20 +446,20 @@ retry:
}
tables->table=table;
- /* save open_ and handler_ tables state */
+ /* save open_tables state */
backup_open_tables= thd->open_tables;
- backup_handler_tables= thd->handler_tables;
-
- /* no pre-opened tables */
- thd->open_tables= NULL;
- /* to avoid flushes */
- thd->handler_tables= NULL;
+ /*
+ mysql_lock_tables() needs thd->open_tables to be set correctly to
+ be able to handle aborts properly. When the abort happens, it's
+ safe to not protect thd->handler_tables because it won't close any
+ tables.
+ */
+ thd->open_tables= thd->handler_tables;
lock= mysql_lock_tables(thd, &tables->table, 1,
MYSQL_LOCK_NOTIFY_IF_NEED_REOPEN, &need_reopen);
/* restore previous context */
- thd->handler_tables= backup_handler_tables;
thd->open_tables= backup_open_tables;
if (need_reopen)
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 553cc6d24d5..9c07add98d4 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -1570,13 +1570,15 @@ sp_name:
| ident
{
LEX *lex= Lex;
- LEX_STRING db;
+ LEX_STRING db= {0,0};
+ THD *thd= YYTHD;
+
if (check_routine_name($1))
{
my_error(ER_SP_WRONG_NAME, MYF(0), $1.str);
MYSQL_YYABORT;
}
- if (lex->copy_db_to(&db.str, &db.length))
+ if (thd->db && thd->copy_db_to(&db.str, &db.length))
MYSQL_YYABORT;
$$= new sp_name(db, $1, false);
if ($$)
@@ -1626,6 +1628,13 @@ create_function_tail:
my_error(ER_SP_NO_RECURSIVE_CREATE, MYF(0), "FUNCTION");
MYSQL_YYABORT;
}
+
+ if (!lex->spname->m_db.length)
+ {
+ my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0));
+ MYSQL_YYABORT;
+ }
+
/* Order is important here: new - reset - init */
sp= new sp_head();
sp->reset_thd_mem_root(thd);
@@ -5195,8 +5204,8 @@ simple_expr:
#endif /* HAVE_DLOPEN */
{
THD *thd= lex->thd;
- LEX_STRING db;
- if (lex->copy_db_to(&db.str, &db.length))
+ LEX_STRING db= {0,0};
+ if (thd->db && thd->copy_db_to(&db.str, &db.length))
MYSQL_YYABORT;
sp_name *name= new sp_name(db, $1, false);
if (name)
@@ -9745,7 +9754,13 @@ trigger_tail:
my_error(ER_SP_NO_RECURSIVE_CREATE, MYF(0), "TRIGGER");
MYSQL_YYABORT;
}
-
+
+ if (!$3->m_db.length)
+ {
+ my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0));
+ MYSQL_YYABORT;
+ }
+
if (!(sp= new sp_head()))
MYSQL_YYABORT;
sp->reset_thd_mem_root(thd);
@@ -9828,6 +9843,12 @@ sp_tail:
MYSQL_YYABORT;
}
+ if (!$3->m_db.length)
+ {
+ my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0));
+ MYSQL_YYABORT;
+ }
+
lex->stmt_definition_begin= $2;
/* Order is important here: new - reset - init */