Below is the list of changes that have just been committed into a local
5.0 repository of davi. When davi does a push these changes will
be propagated to the main repository and, within 24 hours after the
push, to the public repository.
For information on how to access the public repository
see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html
ChangeSet@stripped, 2007-09-13 13:13:14-03:00, davi@stripped +8 -0
Bug#28318 CREATE FUNCTION (UDF) requires a schema
Bug#29816 Syntactically wrong query fails with misleading error message
The core problem is that an SQL-invoked function name can be a <schema
qualified routine name> that contains no <schema name>, but the mysql
parser insists that all stored procedures (function, procedures and
triggers) must have a <schema name>, which is not true for functions.
This problem is especially visible when trying to create a function
or when a query contains a syntax error after a function call (in the
same query), both will fail with a "No database selected" message if
the session is not attached to a particular schema, but the first
one should succeed and the second fail with a "syntax error" message.
Part of the fix is to revamp the sp name handling so that a schema
name may be omitted for functions -- this means that the internal
function name representation may not have a dot, which represents
that the function doesn't have a schema name. The other part is
to place schema checks after the type (function, trigger or procedure)
of the routine is known.
mysql-test/r/sp-error.result@stripped, 2007-09-13 13:13:10-03:00, davi@stripped +13 -0
Add test case result for Bug#29816
mysql-test/r/udf.result@stripped, 2007-09-13 13:13:10-03:00, davi@stripped +7 -0
Add test case result for Bug#28318
mysql-test/t/sp-error.test@stripped, 2007-09-13 13:13:10-03:00, davi@stripped +20 -0
Add test case for Bug#29816
mysql-test/t/udf.test@stripped, 2007-09-13 13:13:10-03:00, davi@stripped +14 -0
Add test case for Bug#28318
sql/sp.cc@stripped, 2007-09-13 13:13:11-03:00, davi@stripped +3 -10
Copy the (last) nul byte of the stored routine key and move name parsing
code to the sp_name class constructor.
sql/sp_head.cc@stripped, 2007-09-13 13:13:11-03:00, davi@stripped +28 -3
Revamp routine name parsing for when no schema is specified and
omit dot from the qualified name if the routine is not associated
with a scheme name.
sql/sp_head.h@stripped, 2007-09-13 13:13:11-03:00, davi@stripped +1 -10
Name parsing got bigger, uninline by moving to a single unit -- the sp_head.cc
file.
sql/sql_yacc.yy@stripped, 2007-09-13 13:13:11-03:00, davi@stripped +26 -5
Only copy the schema name if one is actually set and check for schema
name presence only where it's necessary.
diff -Nrup a/mysql-test/r/sp-error.result b/mysql-test/r/sp-error.result
--- a/mysql-test/r/sp-error.result 2007-06-22 06:55:46 -03:00
+++ b/mysql-test/r/sp-error.result 2007-09-13 13:13:10 -03:00
@@ -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 -Nrup a/mysql-test/r/udf.result b/mysql-test/r/udf.result
--- a/mysql-test/r/udf.result 2007-06-18 18:55:07 -03:00
+++ b/mysql-test/r/udf.result 2007-09-13 13:13:10 -03:00
@@ -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 -Nrup a/mysql-test/t/sp-error.test b/mysql-test/t/sp-error.test
--- a/mysql-test/t/sp-error.test 2007-06-22 06:55:46 -03:00
+++ b/mysql-test/t/sp-error.test 2007-09-13 13:13:10 -03:00
@@ -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 -Nrup a/mysql-test/t/udf.test b/mysql-test/t/udf.test
--- a/mysql-test/t/udf.test 2007-06-18 18:55:07 -03:00
+++ b/mysql-test/t/udf.test 2007-09-13 13:13:10 -03:00
@@ -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 -Nrup a/sql/sp.cc b/sql/sp.cc
--- a/sql/sp.cc 2007-07-25 11:38:48 -03:00
+++ b/sql/sp.cc 2007-09-13 13:13:11 -03:00
@@ -1405,12 +1405,12 @@ static bool add_used_routine(LEX *lex, Q
{
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
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->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 -Nrup a/sql/sp_head.cc b/sql/sp_head.cc
--- a/sql/sp_head.cc 2007-07-31 09:23:23 -03:00
+++ b/sql/sp_head.cc 2007-09-13 13:13:11 -03:00
@@ -369,17 +369,42 @@ sp_eval_expr(THD *thd, Field *result_fie
*
*/
+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 -Nrup a/sql/sp_head.h b/sql/sp_head.h
--- a/sql/sp_head.h 2007-07-12 15:26:38 -03:00
+++ b/sql/sp_head.h 2007-09-13 13:13:11 -03:00
@@ -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 -Nrup a/sql/sql_yacc.yy b/sql/sql_yacc.yy
--- a/sql/sql_yacc.yy 2007-08-28 14:16:02 -03:00
+++ b/sql/sql_yacc.yy 2007-09-13 13:13:11 -03:00
@@ -1569,13 +1569,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 && lex->copy_db_to(&db.str, &db.length))
MYSQL_YYABORT;
$$= new sp_name(db, $1, false);
if ($$)
@@ -1625,6 +1627,13 @@ create_function_tail:
my_error(ER_SP_NO_RECURSIVE_CREATE, MYF(0), "FUNCTION");
MYSQL_YYABORT;
}
+
+ if (!lex->spname->m_db.str || !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);
@@ -5194,8 +5203,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 && lex->copy_db_to(&db.str, &db.length))
MYSQL_YYABORT;
sp_name *name= new sp_name(db, $1, false);
if (name)
@@ -9730,7 +9739,13 @@ trigger_tail:
my_error(ER_SP_NO_RECURSIVE_CREATE, MYF(0), "TRIGGER");
MYSQL_YYABORT;
}
-
+
+ if (!$3->m_db.str || !$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);
@@ -9810,6 +9825,12 @@ sp_tail:
if (lex->sphead)
{
my_error(ER_SP_NO_RECURSIVE_CREATE, MYF(0), "PROCEDURE");
+ MYSQL_YYABORT;
+ }
+
+ if (!$3->m_db.str || !$3->m_db.length)
+ {
+ my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0));
MYSQL_YYABORT;
}