mirror of
https://github.com/MariaDB/server.git
synced 2025-07-29 05:21:33 +03:00
Fix for BUG#16211: Stored function return type for strings is ignored.
Fix for BUG#16676: Database CHARSET not used for stored procedures The problem in BUG#16211 is that CHARSET-clause of the return type for stored functions is just ignored. The problem in BUG#16676 is that if character set is not explicitly specified for sp-variable, the server character set is used instead of the database one. The fix has two parts: - always store CHARSET-clause of the return type along with the type definition in mysql.proc.returns column. "Always" means that CHARSET-clause is appended even if it has not been explicitly specified in CREATE FUNCTION statement (this affects BUG#16211 only). Storing CHARSET-clause if it is not specified is essential to avoid changing character set if the database character set is altered in the future. NOTE: this change is not backward compatible with the previous releases. - use database default character set if CHARSET-clause is not explicitly specified (this affects both BUG#16211 and BUG#16676). NOTE: this also breaks backward compatibility. mysql-test/r/mysqldump.result: Updated result file. mysql-test/r/sp.result: Updated result file. mysql-test/t/sp.test: Provided test cases for BUG#16211, BUG#16676. sql/mysql_priv.h: Added two convenient functions for work with databases. sql/sp.cc: 1. Add CHARSET-clause to CREATE-statement if it has been explicitly specified. 2. Polishing -- provided some comments. sql/sp_head.cc: Use database charset as default charset of sp-variable. sql/sp_head.h: Move init_sp_name() out of init_strings(). sql/sql_db.cc: Two new functions created: - load_db_opt_by_name(); - check_db_dir_existence(); sql/sql_show.cc: Eliminate duplicated code by using check_db_dir_existence() and load_db_opt_by_name() sql/sql_table.cc: Eliminate duplicated code by using check_db_dir_existence() and load_db_opt_by_name() sql/sql_yacc.yy: Call sp_head::init_sp_name() to initialize stored routine name.
This commit is contained in:
@ -2248,7 +2248,7 @@ RETURN a+b */;;
|
||||
/*!50003 SET SESSION SQL_MODE=@OLD_SQL_MODE*/;;
|
||||
/*!50003 DROP FUNCTION IF EXISTS `bug9056_func2` */;;
|
||||
/*!50003 SET SESSION SQL_MODE=""*/;;
|
||||
/*!50003 CREATE*/ /*!50020 DEFINER=`root`@`localhost`*/ /*!50003 FUNCTION `bug9056_func2`(f1 char binary) RETURNS char(1)
|
||||
/*!50003 CREATE*/ /*!50020 DEFINER=`root`@`localhost`*/ /*!50003 FUNCTION `bug9056_func2`(f1 char binary) RETURNS char(1) CHARSET latin1
|
||||
begin
|
||||
set f1= concat( 'hello', f1 );
|
||||
return f1;
|
||||
|
@ -5069,4 +5069,157 @@ END |
|
||||
SET @a = _latin2"aaaaaaaaaa" |
|
||||
CALL bug21013(10) |
|
||||
DROP PROCEDURE bug21013 |
|
||||
DROP DATABASE IF EXISTS mysqltest1|
|
||||
DROP DATABASE IF EXISTS mysqltest2|
|
||||
CREATE DATABASE mysqltest1 DEFAULT CHARACTER SET utf8|
|
||||
CREATE DATABASE mysqltest2 DEFAULT CHARACTER SET utf8|
|
||||
use mysqltest1|
|
||||
CREATE FUNCTION bug16211_f1() RETURNS CHAR(10)
|
||||
RETURN ""|
|
||||
CREATE FUNCTION bug16211_f2() RETURNS CHAR(10) CHARSET koi8r
|
||||
RETURN ""|
|
||||
CREATE FUNCTION mysqltest2.bug16211_f3() RETURNS CHAR(10)
|
||||
RETURN ""|
|
||||
CREATE FUNCTION mysqltest2.bug16211_f4() RETURNS CHAR(10) CHARSET koi8r
|
||||
RETURN ""|
|
||||
SHOW CREATE FUNCTION bug16211_f1|
|
||||
Function sql_mode Create Function
|
||||
bug16211_f1 CREATE DEFINER=`root`@`localhost` FUNCTION `bug16211_f1`() RETURNS char(10) CHARSET utf8
|
||||
RETURN ""
|
||||
SHOW CREATE FUNCTION bug16211_f2|
|
||||
Function sql_mode Create Function
|
||||
bug16211_f2 CREATE DEFINER=`root`@`localhost` FUNCTION `bug16211_f2`() RETURNS char(10) CHARSET koi8r
|
||||
RETURN ""
|
||||
SHOW CREATE FUNCTION mysqltest2.bug16211_f3|
|
||||
Function sql_mode Create Function
|
||||
bug16211_f3 CREATE DEFINER=`root`@`localhost` FUNCTION `bug16211_f3`() RETURNS char(10) CHARSET utf8
|
||||
RETURN ""
|
||||
SHOW CREATE FUNCTION mysqltest2.bug16211_f4|
|
||||
Function sql_mode Create Function
|
||||
bug16211_f4 CREATE DEFINER=`root`@`localhost` FUNCTION `bug16211_f4`() RETURNS char(10) CHARSET koi8r
|
||||
RETURN ""
|
||||
SELECT dtd_identifier
|
||||
FROM INFORMATION_SCHEMA.ROUTINES
|
||||
WHERE ROUTINE_SCHEMA = "mysqltest1" AND ROUTINE_NAME = "bug16211_f1"|
|
||||
dtd_identifier
|
||||
char(10) CHARSET utf8
|
||||
SELECT dtd_identifier
|
||||
FROM INFORMATION_SCHEMA.ROUTINES
|
||||
WHERE ROUTINE_SCHEMA = "mysqltest1" AND ROUTINE_NAME = "bug16211_f2"|
|
||||
dtd_identifier
|
||||
char(10) CHARSET koi8r
|
||||
SELECT dtd_identifier
|
||||
FROM INFORMATION_SCHEMA.ROUTINES
|
||||
WHERE ROUTINE_SCHEMA = "mysqltest2" AND ROUTINE_NAME = "bug16211_f3"|
|
||||
dtd_identifier
|
||||
char(10) CHARSET utf8
|
||||
SELECT dtd_identifier
|
||||
FROM INFORMATION_SCHEMA.ROUTINES
|
||||
WHERE ROUTINE_SCHEMA = "mysqltest2" AND ROUTINE_NAME = "bug16211_f4"|
|
||||
dtd_identifier
|
||||
char(10) CHARSET koi8r
|
||||
SELECT CHARSET(bug16211_f1())|
|
||||
CHARSET(bug16211_f1())
|
||||
utf8
|
||||
SELECT CHARSET(bug16211_f2())|
|
||||
CHARSET(bug16211_f2())
|
||||
koi8r
|
||||
SELECT CHARSET(mysqltest2.bug16211_f3())|
|
||||
CHARSET(mysqltest2.bug16211_f3())
|
||||
utf8
|
||||
SELECT CHARSET(mysqltest2.bug16211_f4())|
|
||||
CHARSET(mysqltest2.bug16211_f4())
|
||||
koi8r
|
||||
ALTER DATABASE mysqltest1 CHARACTER SET cp1251|
|
||||
ALTER DATABASE mysqltest2 CHARACTER SET cp1251|
|
||||
SHOW CREATE FUNCTION bug16211_f1|
|
||||
Function sql_mode Create Function
|
||||
bug16211_f1 CREATE DEFINER=`root`@`localhost` FUNCTION `bug16211_f1`() RETURNS char(10) CHARSET utf8
|
||||
RETURN ""
|
||||
SHOW CREATE FUNCTION bug16211_f2|
|
||||
Function sql_mode Create Function
|
||||
bug16211_f2 CREATE DEFINER=`root`@`localhost` FUNCTION `bug16211_f2`() RETURNS char(10) CHARSET koi8r
|
||||
RETURN ""
|
||||
SHOW CREATE FUNCTION mysqltest2.bug16211_f3|
|
||||
Function sql_mode Create Function
|
||||
bug16211_f3 CREATE DEFINER=`root`@`localhost` FUNCTION `bug16211_f3`() RETURNS char(10) CHARSET utf8
|
||||
RETURN ""
|
||||
SHOW CREATE FUNCTION mysqltest2.bug16211_f4|
|
||||
Function sql_mode Create Function
|
||||
bug16211_f4 CREATE DEFINER=`root`@`localhost` FUNCTION `bug16211_f4`() RETURNS char(10) CHARSET koi8r
|
||||
RETURN ""
|
||||
SELECT dtd_identifier
|
||||
FROM INFORMATION_SCHEMA.ROUTINES
|
||||
WHERE ROUTINE_SCHEMA = "mysqltest1" AND ROUTINE_NAME = "bug16211_f1"|
|
||||
dtd_identifier
|
||||
char(10) CHARSET utf8
|
||||
SELECT dtd_identifier
|
||||
FROM INFORMATION_SCHEMA.ROUTINES
|
||||
WHERE ROUTINE_SCHEMA = "mysqltest1" AND ROUTINE_NAME = "bug16211_f2"|
|
||||
dtd_identifier
|
||||
char(10) CHARSET koi8r
|
||||
SELECT dtd_identifier
|
||||
FROM INFORMATION_SCHEMA.ROUTINES
|
||||
WHERE ROUTINE_SCHEMA = "mysqltest2" AND ROUTINE_NAME = "bug16211_f3"|
|
||||
dtd_identifier
|
||||
char(10) CHARSET utf8
|
||||
SELECT dtd_identifier
|
||||
FROM INFORMATION_SCHEMA.ROUTINES
|
||||
WHERE ROUTINE_SCHEMA = "mysqltest2" AND ROUTINE_NAME = "bug16211_f4"|
|
||||
dtd_identifier
|
||||
char(10) CHARSET koi8r
|
||||
SELECT CHARSET(bug16211_f1())|
|
||||
CHARSET(bug16211_f1())
|
||||
utf8
|
||||
SELECT CHARSET(bug16211_f2())|
|
||||
CHARSET(bug16211_f2())
|
||||
koi8r
|
||||
SELECT CHARSET(mysqltest2.bug16211_f3())|
|
||||
CHARSET(mysqltest2.bug16211_f3())
|
||||
utf8
|
||||
SELECT CHARSET(mysqltest2.bug16211_f4())|
|
||||
CHARSET(mysqltest2.bug16211_f4())
|
||||
koi8r
|
||||
use test|
|
||||
DROP DATABASE mysqltest1|
|
||||
DROP DATABASE mysqltest2|
|
||||
DROP DATABASE IF EXISTS mysqltest1|
|
||||
CREATE DATABASE mysqltest1 DEFAULT CHARACTER SET utf8|
|
||||
use mysqltest1|
|
||||
CREATE PROCEDURE bug16676_p1(
|
||||
IN p1 CHAR(10),
|
||||
INOUT p2 CHAR(10),
|
||||
OUT p3 CHAR(10))
|
||||
BEGIN
|
||||
SELECT CHARSET(p1), COLLATION(p1);
|
||||
SELECT CHARSET(p2), COLLATION(p2);
|
||||
SELECT CHARSET(p3), COLLATION(p3);
|
||||
END|
|
||||
CREATE PROCEDURE bug16676_p2(
|
||||
IN p1 CHAR(10) CHARSET koi8r,
|
||||
INOUT p2 CHAR(10) CHARSET cp1251,
|
||||
OUT p3 CHAR(10) CHARSET greek)
|
||||
BEGIN
|
||||
SELECT CHARSET(p1), COLLATION(p1);
|
||||
SELECT CHARSET(p2), COLLATION(p2);
|
||||
SELECT CHARSET(p3), COLLATION(p3);
|
||||
END|
|
||||
SET @v2 = 'b'|
|
||||
SET @v3 = 'c'|
|
||||
CALL bug16676_p1('a', @v2, @v3)|
|
||||
CHARSET(p1) COLLATION(p1)
|
||||
utf8 utf8_general_ci
|
||||
CHARSET(p2) COLLATION(p2)
|
||||
utf8 utf8_general_ci
|
||||
CHARSET(p3) COLLATION(p3)
|
||||
utf8 utf8_general_ci
|
||||
CALL bug16676_p2('a', @v2, @v3)|
|
||||
CHARSET(p1) COLLATION(p1)
|
||||
koi8r koi8r_general_ci
|
||||
CHARSET(p2) COLLATION(p2)
|
||||
cp1251 cp1251_general_ci
|
||||
CHARSET(p3) COLLATION(p3)
|
||||
greek greek_general_ci
|
||||
use test|
|
||||
DROP DATABASE mysqltest1|
|
||||
drop table t1,t2;
|
||||
|
@ -5989,6 +5989,164 @@ CALL bug21013(10) |
|
||||
DROP PROCEDURE bug21013 |
|
||||
|
||||
|
||||
#
|
||||
# BUG#16211: Stored function return type for strings is ignored
|
||||
#
|
||||
|
||||
# Prepare: create database with fixed, pre-defined character set.
|
||||
|
||||
--disable_warnings
|
||||
DROP DATABASE IF EXISTS mysqltest1|
|
||||
DROP DATABASE IF EXISTS mysqltest2|
|
||||
--enable_warnings
|
||||
|
||||
CREATE DATABASE mysqltest1 DEFAULT CHARACTER SET utf8|
|
||||
CREATE DATABASE mysqltest2 DEFAULT CHARACTER SET utf8|
|
||||
|
||||
# Test case:
|
||||
|
||||
use mysqltest1|
|
||||
|
||||
# - Create two stored functions -- with and without explicit CHARSET-clause
|
||||
# for return value;
|
||||
|
||||
CREATE FUNCTION bug16211_f1() RETURNS CHAR(10)
|
||||
RETURN ""|
|
||||
|
||||
CREATE FUNCTION bug16211_f2() RETURNS CHAR(10) CHARSET koi8r
|
||||
RETURN ""|
|
||||
|
||||
CREATE FUNCTION mysqltest2.bug16211_f3() RETURNS CHAR(10)
|
||||
RETURN ""|
|
||||
|
||||
CREATE FUNCTION mysqltest2.bug16211_f4() RETURNS CHAR(10) CHARSET koi8r
|
||||
RETURN ""|
|
||||
|
||||
# - Check that CHARSET-clause is specified for the second function;
|
||||
|
||||
SHOW CREATE FUNCTION bug16211_f1|
|
||||
SHOW CREATE FUNCTION bug16211_f2|
|
||||
|
||||
SHOW CREATE FUNCTION mysqltest2.bug16211_f3|
|
||||
SHOW CREATE FUNCTION mysqltest2.bug16211_f4|
|
||||
|
||||
SELECT dtd_identifier
|
||||
FROM INFORMATION_SCHEMA.ROUTINES
|
||||
WHERE ROUTINE_SCHEMA = "mysqltest1" AND ROUTINE_NAME = "bug16211_f1"|
|
||||
|
||||
SELECT dtd_identifier
|
||||
FROM INFORMATION_SCHEMA.ROUTINES
|
||||
WHERE ROUTINE_SCHEMA = "mysqltest1" AND ROUTINE_NAME = "bug16211_f2"|
|
||||
|
||||
SELECT dtd_identifier
|
||||
FROM INFORMATION_SCHEMA.ROUTINES
|
||||
WHERE ROUTINE_SCHEMA = "mysqltest2" AND ROUTINE_NAME = "bug16211_f3"|
|
||||
|
||||
SELECT dtd_identifier
|
||||
FROM INFORMATION_SCHEMA.ROUTINES
|
||||
WHERE ROUTINE_SCHEMA = "mysqltest2" AND ROUTINE_NAME = "bug16211_f4"|
|
||||
|
||||
SELECT CHARSET(bug16211_f1())|
|
||||
SELECT CHARSET(bug16211_f2())|
|
||||
|
||||
SELECT CHARSET(mysqltest2.bug16211_f3())|
|
||||
SELECT CHARSET(mysqltest2.bug16211_f4())|
|
||||
|
||||
# - Alter database character set.
|
||||
|
||||
ALTER DATABASE mysqltest1 CHARACTER SET cp1251|
|
||||
ALTER DATABASE mysqltest2 CHARACTER SET cp1251|
|
||||
|
||||
# - Check that CHARSET-clause has not changed.
|
||||
|
||||
SHOW CREATE FUNCTION bug16211_f1|
|
||||
SHOW CREATE FUNCTION bug16211_f2|
|
||||
|
||||
SHOW CREATE FUNCTION mysqltest2.bug16211_f3|
|
||||
SHOW CREATE FUNCTION mysqltest2.bug16211_f4|
|
||||
|
||||
SELECT dtd_identifier
|
||||
FROM INFORMATION_SCHEMA.ROUTINES
|
||||
WHERE ROUTINE_SCHEMA = "mysqltest1" AND ROUTINE_NAME = "bug16211_f1"|
|
||||
|
||||
SELECT dtd_identifier
|
||||
FROM INFORMATION_SCHEMA.ROUTINES
|
||||
WHERE ROUTINE_SCHEMA = "mysqltest1" AND ROUTINE_NAME = "bug16211_f2"|
|
||||
|
||||
SELECT dtd_identifier
|
||||
FROM INFORMATION_SCHEMA.ROUTINES
|
||||
WHERE ROUTINE_SCHEMA = "mysqltest2" AND ROUTINE_NAME = "bug16211_f3"|
|
||||
|
||||
SELECT dtd_identifier
|
||||
FROM INFORMATION_SCHEMA.ROUTINES
|
||||
WHERE ROUTINE_SCHEMA = "mysqltest2" AND ROUTINE_NAME = "bug16211_f4"|
|
||||
|
||||
SELECT CHARSET(bug16211_f1())|
|
||||
SELECT CHARSET(bug16211_f2())|
|
||||
|
||||
SELECT CHARSET(mysqltest2.bug16211_f3())|
|
||||
SELECT CHARSET(mysqltest2.bug16211_f4())|
|
||||
|
||||
# Cleanup.
|
||||
|
||||
use test|
|
||||
|
||||
DROP DATABASE mysqltest1|
|
||||
DROP DATABASE mysqltest2|
|
||||
|
||||
|
||||
#
|
||||
# BUG#16676: Database CHARSET not used for stored procedures
|
||||
#
|
||||
|
||||
# Prepare: create database with fixed, pre-defined character set.
|
||||
|
||||
--disable_warnings
|
||||
DROP DATABASE IF EXISTS mysqltest1|
|
||||
--enable_warnings
|
||||
|
||||
CREATE DATABASE mysqltest1 DEFAULT CHARACTER SET utf8|
|
||||
|
||||
# Test case:
|
||||
|
||||
use mysqltest1|
|
||||
|
||||
# - Create two stored procedures -- with and without explicit CHARSET-clause;
|
||||
|
||||
CREATE PROCEDURE bug16676_p1(
|
||||
IN p1 CHAR(10),
|
||||
INOUT p2 CHAR(10),
|
||||
OUT p3 CHAR(10))
|
||||
BEGIN
|
||||
SELECT CHARSET(p1), COLLATION(p1);
|
||||
SELECT CHARSET(p2), COLLATION(p2);
|
||||
SELECT CHARSET(p3), COLLATION(p3);
|
||||
END|
|
||||
|
||||
CREATE PROCEDURE bug16676_p2(
|
||||
IN p1 CHAR(10) CHARSET koi8r,
|
||||
INOUT p2 CHAR(10) CHARSET cp1251,
|
||||
OUT p3 CHAR(10) CHARSET greek)
|
||||
BEGIN
|
||||
SELECT CHARSET(p1), COLLATION(p1);
|
||||
SELECT CHARSET(p2), COLLATION(p2);
|
||||
SELECT CHARSET(p3), COLLATION(p3);
|
||||
END|
|
||||
|
||||
# - Call procedures.
|
||||
|
||||
SET @v2 = 'b'|
|
||||
SET @v3 = 'c'|
|
||||
|
||||
CALL bug16676_p1('a', @v2, @v3)|
|
||||
CALL bug16676_p2('a', @v2, @v3)|
|
||||
|
||||
# Cleanup.
|
||||
|
||||
use test|
|
||||
|
||||
DROP DATABASE mysqltest1|
|
||||
|
||||
#
|
||||
# BUG#NNNN: New bug synopsis
|
||||
#
|
||||
|
@ -1138,7 +1138,10 @@ uint check_word(TYPELIB *lib, const char *val, const char *end,
|
||||
bool is_keyword(const char *name, uint len);
|
||||
|
||||
#define MY_DB_OPT_FILE "db.opt"
|
||||
bool check_db_dir_existence(const char *db_name);
|
||||
bool load_db_opt(THD *thd, const char *path, HA_CREATE_INFO *create);
|
||||
bool load_db_opt_by_name(THD *thd, const char *db_name,
|
||||
HA_CREATE_INFO *db_create_info);
|
||||
bool my_dbopt_init(void);
|
||||
void my_dbopt_cleanup(void);
|
||||
void my_dbopt_free(void);
|
||||
|
12
sql/sp.cc
12
sql/sp.cc
@ -495,6 +495,13 @@ sp_returns_type(THD *thd, String &result, sp_head *sp)
|
||||
table.s = &table.share_not_to_be_used;
|
||||
field= sp->create_result_field(0, 0, &table);
|
||||
field->sql_type(result);
|
||||
|
||||
if (field->has_charset())
|
||||
{
|
||||
result.append(STRING_WITH_LEN(" CHARSET "));
|
||||
result.append(field->charset()->csname);
|
||||
}
|
||||
|
||||
delete field;
|
||||
}
|
||||
|
||||
@ -974,6 +981,11 @@ sp_find_routine(THD *thd, int type, sp_name *name, sp_cache **cp,
|
||||
sp_head *new_sp;
|
||||
const char *returns= "";
|
||||
char definer[USER_HOST_BUFF_SIZE];
|
||||
|
||||
/*
|
||||
String buffer for RETURNS data type must have system charset;
|
||||
64 -- size of "returns" column of mysql.proc.
|
||||
*/
|
||||
String retstr(64);
|
||||
|
||||
DBUG_PRINT("info", ("found: 0x%lx", (ulong)sp));
|
||||
|
@ -478,29 +478,42 @@ sp_head::init(LEX *lex)
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
sp_head::init_strings(THD *thd, LEX *lex, sp_name *name)
|
||||
sp_head::init_sp_name(THD *thd, sp_name *spname)
|
||||
{
|
||||
DBUG_ENTER("sp_head::init_sp_name");
|
||||
|
||||
/* Must be initialized in the parser. */
|
||||
|
||||
DBUG_ASSERT(spname && spname->m_db.str && spname->m_db.length);
|
||||
|
||||
/* We have to copy strings to get them into the right memroot. */
|
||||
|
||||
m_db.length= spname->m_db.length;
|
||||
m_db.str= strmake_root(thd->mem_root, spname->m_db.str, spname->m_db.length);
|
||||
|
||||
m_name.length= spname->m_name.length;
|
||||
m_name.str= strmake_root(thd->mem_root, spname->m_name.str,
|
||||
spname->m_name.length);
|
||||
|
||||
if (spname->m_qname.length == 0)
|
||||
spname->init_qname(thd);
|
||||
|
||||
m_qname.length= spname->m_qname.length;
|
||||
m_qname.str= strmake_root(thd->mem_root, spname->m_qname.str,
|
||||
m_qname.length);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
sp_head::init_strings(THD *thd, LEX *lex)
|
||||
{
|
||||
DBUG_ENTER("sp_head::init_strings");
|
||||
uchar *endp; /* Used to trim the end */
|
||||
/* During parsing, we must use thd->mem_root */
|
||||
MEM_ROOT *root= thd->mem_root;
|
||||
|
||||
DBUG_ASSERT(name);
|
||||
/* Must be initialized in the parser */
|
||||
DBUG_ASSERT(name->m_db.str && name->m_db.length);
|
||||
|
||||
/* We have to copy strings to get them into the right memroot */
|
||||
m_db.length= name->m_db.length;
|
||||
m_db.str= strmake_root(root, name->m_db.str, name->m_db.length);
|
||||
m_name.length= name->m_name.length;
|
||||
m_name.str= strmake_root(root, name->m_name.str, name->m_name.length);
|
||||
|
||||
if (name->m_qname.length == 0)
|
||||
name->init_qname(thd);
|
||||
m_qname.length= name->m_qname.length;
|
||||
m_qname.str= strmake_root(root, name->m_qname.str, m_qname.length);
|
||||
|
||||
if (m_param_begin && m_param_end)
|
||||
{
|
||||
m_params.length= m_param_end - m_param_begin;
|
||||
@ -1856,14 +1869,18 @@ sp_head::fill_field_definition(THD *thd, LEX *lex,
|
||||
enum enum_field_types field_type,
|
||||
create_field *field_def)
|
||||
{
|
||||
HA_CREATE_INFO sp_db_info;
|
||||
LEX_STRING cmt = { 0, 0 };
|
||||
uint unused1= 0;
|
||||
int unused2= 0;
|
||||
|
||||
load_db_opt_by_name(thd, m_db.str, &sp_db_info);
|
||||
|
||||
if (field_def->init(thd, (char*) "", field_type, lex->length, lex->dec,
|
||||
lex->type, (Item*) 0, (Item*) 0, &cmt, 0,
|
||||
&lex->interval_list,
|
||||
(lex->charset ? lex->charset : default_charset_info),
|
||||
(lex->charset ? lex->charset :
|
||||
sp_db_info.default_table_charset),
|
||||
lex->uint_geom_type))
|
||||
return TRUE;
|
||||
|
||||
|
@ -193,9 +193,13 @@ public:
|
||||
void
|
||||
init(LEX *lex);
|
||||
|
||||
/* Copy sp name from parser. */
|
||||
void
|
||||
init_sp_name(THD *thd, sp_name *spname);
|
||||
|
||||
// Initialize strings after parsing header
|
||||
void
|
||||
init_strings(THD *thd, LEX *lex, sp_name *name);
|
||||
init_strings(THD *thd, LEX *lex);
|
||||
|
||||
int
|
||||
create(THD *thd);
|
||||
|
@ -295,7 +295,6 @@ static bool write_db_opt(THD *thd, const char *path, HA_CREATE_INFO *create)
|
||||
create Where to store the read options
|
||||
|
||||
DESCRIPTION
|
||||
For now, only default-character-set is read.
|
||||
|
||||
RETURN VALUES
|
||||
0 File found
|
||||
@ -383,6 +382,50 @@ err1:
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Retrieve database options by name. Load database options file or fetch from
|
||||
cache.
|
||||
|
||||
SYNOPSIS
|
||||
load_db_opt_by_name()
|
||||
db_name Database name
|
||||
db_create_info Where to store the database options
|
||||
|
||||
DESCRIPTION
|
||||
load_db_opt_by_name() is a shortcut for load_db_opt().
|
||||
|
||||
NOTE
|
||||
Although load_db_opt_by_name() (and load_db_opt()) returns status of
|
||||
the operation, it is useless usually and should be ignored. The problem
|
||||
is that there are 1) system databases ("mysql") and 2) virtual
|
||||
databases ("information_schema"), which do not contain options file.
|
||||
So, load_db_opt[_by_name]() returns FALSE for these databases, but this
|
||||
is not an error.
|
||||
|
||||
load_db_opt[_by_name]() clears db_create_info structure in any case, so
|
||||
even on failure it contains valid data. So, common use case is just
|
||||
call load_db_opt[_by_name]() without checking return value and use
|
||||
db_create_info right after that.
|
||||
|
||||
RETURN VALUES (read NOTE!)
|
||||
FALSE Success
|
||||
TRUE Failed to retrieve options
|
||||
*/
|
||||
|
||||
bool load_db_opt_by_name(THD *thd, const char *db_name,
|
||||
HA_CREATE_INFO *db_create_info)
|
||||
{
|
||||
char db_opt_path[FN_REFLEN];
|
||||
|
||||
strxnmov(db_opt_path, sizeof (db_opt_path) - 1, mysql_data_home, "/",
|
||||
db_name, "/", MY_DB_OPT_FILE, NullS);
|
||||
|
||||
unpack_filename(db_opt_path, db_opt_path);
|
||||
|
||||
return load_db_opt(thd, db_opt_path, db_create_info);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Create a database
|
||||
|
||||
@ -1126,8 +1169,6 @@ bool mysql_change_db(THD *thd, const char *name, bool no_access_check)
|
||||
{
|
||||
int path_length, db_length;
|
||||
char *db_name;
|
||||
char path[FN_REFLEN];
|
||||
HA_CREATE_INFO create;
|
||||
bool system_db= 0;
|
||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||
ulong db_access;
|
||||
@ -1196,16 +1237,14 @@ bool mysql_change_db(THD *thd, const char *name, bool no_access_check)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
(void) sprintf(path,"%s/%s", mysql_data_home, db_name);
|
||||
path_length= unpack_dirname(path, path); // Convert if not UNIX
|
||||
if (path_length && path[path_length-1] == FN_LIBCHAR)
|
||||
path[path_length-1]= '\0'; // remove ending '\'
|
||||
if (my_access(path,F_OK))
|
||||
|
||||
if (check_db_dir_existence(db_name))
|
||||
{
|
||||
my_error(ER_BAD_DB_ERROR, MYF(0), db_name);
|
||||
my_free(db_name, MYF(0));
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
|
||||
end:
|
||||
x_free(thd->db);
|
||||
DBUG_ASSERT(db_name == NULL || db_name[0] != '\0');
|
||||
@ -1221,8 +1260,10 @@ end:
|
||||
}
|
||||
else
|
||||
{
|
||||
strmov(path+unpack_dirname(path,path), MY_DB_OPT_FILE);
|
||||
load_db_opt(thd, path, &create);
|
||||
HA_CREATE_INFO create;
|
||||
|
||||
load_db_opt_by_name(thd, db_name, &create);
|
||||
|
||||
thd->db_charset= create.default_table_charset ?
|
||||
create.default_table_charset :
|
||||
thd->variables.collation_server;
|
||||
@ -1230,3 +1271,36 @@ end:
|
||||
}
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Check if there is directory for the database name.
|
||||
|
||||
SYNOPSIS
|
||||
check_db_dir_existence()
|
||||
db_name database name
|
||||
|
||||
RETURN VALUES
|
||||
FALSE There is directory for the specified database name.
|
||||
TRUE The directory does not exist.
|
||||
*/
|
||||
|
||||
bool check_db_dir_existence(const char *db_name)
|
||||
{
|
||||
char db_dir_path[FN_REFLEN];
|
||||
uint db_dir_path_len;
|
||||
|
||||
strxnmov(db_dir_path, sizeof (db_dir_path) - 1, mysql_data_home, "/",
|
||||
db_name, NullS);
|
||||
|
||||
db_dir_path_len= unpack_dirname(db_dir_path, db_dir_path);
|
||||
|
||||
/* Remove trailing '/' or '\' if exists. */
|
||||
|
||||
if (db_dir_path_len && db_dir_path[db_dir_path_len - 1] == FN_LIBCHAR)
|
||||
db_dir_path[db_dir_path_len - 1]= 0;
|
||||
|
||||
/* Check access. */
|
||||
|
||||
return my_access(db_dir_path, F_OK);
|
||||
}
|
||||
|
@ -439,13 +439,11 @@ bool mysqld_show_create_db(THD *thd, char *dbname,
|
||||
{
|
||||
Security_context *sctx= thd->security_ctx;
|
||||
int length;
|
||||
char path[FN_REFLEN];
|
||||
char buff[2048];
|
||||
String buffer(buff, sizeof(buff), system_charset_info);
|
||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||
uint db_access;
|
||||
#endif
|
||||
bool found_libchar;
|
||||
HA_CREATE_INFO create;
|
||||
uint create_options = create_info ? create_info->options : 0;
|
||||
Protocol *protocol=thd->protocol;
|
||||
@ -480,23 +478,13 @@ bool mysqld_show_create_db(THD *thd, char *dbname,
|
||||
}
|
||||
else
|
||||
{
|
||||
(void) sprintf(path,"%s/%s",mysql_data_home, dbname);
|
||||
length=unpack_dirname(path,path); // Convert if not unix
|
||||
found_libchar= 0;
|
||||
if (length && path[length-1] == FN_LIBCHAR)
|
||||
{
|
||||
found_libchar= 1;
|
||||
path[length-1]=0; // remove ending '\'
|
||||
}
|
||||
if (access(path,F_OK))
|
||||
if (check_db_dir_existence(dbname))
|
||||
{
|
||||
my_error(ER_BAD_DB_ERROR, MYF(0), dbname);
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
if (found_libchar)
|
||||
path[length-1]= FN_LIBCHAR;
|
||||
strmov(path+length, MY_DB_OPT_FILE);
|
||||
load_db_opt(thd, path, &create);
|
||||
|
||||
load_db_opt_by_name(thd, dbname, &create);
|
||||
}
|
||||
List<Item> field_list;
|
||||
field_list.push_back(new Item_empty_string("Database",NAME_LEN));
|
||||
@ -2319,8 +2307,11 @@ bool store_schema_shemata(THD* thd, TABLE *table, const char *db_name,
|
||||
|
||||
int fill_schema_shemata(THD *thd, TABLE_LIST *tables, COND *cond)
|
||||
{
|
||||
char path[FN_REFLEN];
|
||||
bool found_libchar;
|
||||
/*
|
||||
TODO: fill_schema_shemata() is called when new client is connected.
|
||||
Returning error status in this case leads to client hangup.
|
||||
*/
|
||||
|
||||
INDEX_FIELD_VALUES idx_field_vals;
|
||||
List<char> files;
|
||||
char *file_name;
|
||||
@ -2352,19 +2343,8 @@ int fill_schema_shemata(THD *thd, TABLE_LIST *tables, COND *cond)
|
||||
(grant_option && !check_grant_db(thd, file_name)))
|
||||
#endif
|
||||
{
|
||||
strxmov(path, mysql_data_home, "/", file_name, NullS);
|
||||
length=unpack_dirname(path,path); // Convert if not unix
|
||||
found_libchar= 0;
|
||||
if (length && path[length-1] == FN_LIBCHAR)
|
||||
{
|
||||
found_libchar= 1;
|
||||
path[length-1]=0; // remove ending '\'
|
||||
}
|
||||
load_db_opt_by_name(thd, file_name, &create);
|
||||
|
||||
if (found_libchar)
|
||||
path[length-1]= FN_LIBCHAR;
|
||||
strmov(path+length, MY_DB_OPT_FILE);
|
||||
load_db_opt(thd, path, &create);
|
||||
if (store_schema_shemata(thd, table, file_name,
|
||||
create.default_table_charset))
|
||||
DBUG_RETURN(1);
|
||||
|
@ -1631,10 +1631,9 @@ bool mysql_create_table(THD *thd,const char *db, const char *table_name,
|
||||
if (!create_info->default_table_charset)
|
||||
{
|
||||
HA_CREATE_INFO db_info;
|
||||
char path[FN_REFLEN];
|
||||
/* Abuse build_table_path() to build the path to the db.opt file */
|
||||
build_table_path(path, sizeof(path), db, MY_DB_OPT_FILE, "");
|
||||
load_db_opt(thd, path, &db_info);
|
||||
|
||||
load_db_opt_by_name(thd, db, &db_info);
|
||||
|
||||
create_info->default_table_charset= db_info.default_table_charset;
|
||||
}
|
||||
|
||||
|
@ -1285,6 +1285,7 @@ create_function_tail:
|
||||
sp= new sp_head();
|
||||
sp->reset_thd_mem_root(YYTHD);
|
||||
sp->init(lex);
|
||||
sp->init_sp_name(YYTHD, lex->spname);
|
||||
|
||||
sp->m_type= TYPE_ENUM_FUNCTION;
|
||||
lex->sphead= sp;
|
||||
@ -1339,7 +1340,7 @@ create_function_tail:
|
||||
YYABORT;
|
||||
|
||||
lex->sql_command= SQLCOM_CREATE_SPFUNCTION;
|
||||
sp->init_strings(YYTHD, lex, lex->spname);
|
||||
sp->init_strings(YYTHD, lex);
|
||||
if (!(sp->m_flags & sp_head::HAS_RETURN))
|
||||
{
|
||||
my_error(ER_SP_NORETURN, MYF(0), sp->m_qname.str);
|
||||
@ -9100,6 +9101,7 @@ trigger_tail:
|
||||
YYABORT;
|
||||
sp->reset_thd_mem_root(YYTHD);
|
||||
sp->init(lex);
|
||||
sp->init_sp_name(YYTHD, $3);
|
||||
|
||||
lex->stmt_definition_begin= $2;
|
||||
lex->ident.str= $7;
|
||||
@ -9128,7 +9130,7 @@ trigger_tail:
|
||||
sp_head *sp= lex->sphead;
|
||||
|
||||
lex->sql_command= SQLCOM_CREATE_TRIGGER;
|
||||
sp->init_strings(YYTHD, lex, $3);
|
||||
sp->init_strings(YYTHD, lex);
|
||||
/* Restore flag if it was cleared above */
|
||||
if (sp->m_old_cmq)
|
||||
YYTHD->client_capabilities |= CLIENT_MULTI_QUERIES;
|
||||
@ -9183,6 +9185,7 @@ sp_tail:
|
||||
sp= new sp_head();
|
||||
sp->reset_thd_mem_root(YYTHD);
|
||||
sp->init(lex);
|
||||
sp->init_sp_name(YYTHD, $3);
|
||||
|
||||
sp->m_type= TYPE_ENUM_PROCEDURE;
|
||||
lex->sphead= sp;
|
||||
@ -9220,7 +9223,7 @@ sp_tail:
|
||||
LEX *lex= Lex;
|
||||
sp_head *sp= lex->sphead;
|
||||
|
||||
sp->init_strings(YYTHD, lex, $3);
|
||||
sp->init_strings(YYTHD, lex);
|
||||
lex->sql_command= SQLCOM_CREATE_PROCEDURE;
|
||||
/* Restore flag if it was cleared above */
|
||||
if (sp->m_old_cmq)
|
||||
|
Reference in New Issue
Block a user