MDEV-31606 Refactor check_db_name() to get a const argument
Problem: Under terms of MDEV-27490, we'll update Unicode version used to compare identifiers to 14.0.0. Unlike in the old Unicode version, in the new version a string can grow during lower-case. We cannot perform check_db_name() inplace any more. Change summary: - Allocate memory to store lower-cased identifiers in memory root - Removing check_db_name() performing both in-place lower-casing and validation at the same time. Splitting it into two separate stages: * creating a memory-root lower-cased copy of an identifier (using new MEM_ROOT functions and Query_arena wrapper methods) * performing validation on a constant string (using Lex_ident_fs methods) Implementation details: - Adding a mysys helper function to allocate lower-cased strings on MEM_ROOT: lex_string_casedn_root() and a Query_arena wrappers for it: make_ident_casedn() make_ident_opt_casedn() - Adding a Query_arena method to perform both MEM_ROOT lower-casing and database name validation at the same time: to_ident_db_internal_with_error() This method is very close to the old (pre-11.3) check_db_name(), but performs lower-casing to a newly allocated MEM_ROOT memory (instead of performing lower-casing the original string in-place). - Adding a Table_ident method which additionally handles derived table names: to_ident_db_internal_with_error() - Removing the old check_db_name()
This commit is contained in:
parent
e987b9350c
commit
f5aae71661
@ -908,6 +908,20 @@ static inline char *safe_strdup_root(MEM_ROOT *root, const char *str)
|
||||
extern char *strmake_root(MEM_ROOT *root,const char *str,size_t len);
|
||||
extern void *memdup_root(MEM_ROOT *root,const void *str, size_t len);
|
||||
extern LEX_CSTRING safe_lexcstrdup_root(MEM_ROOT *root, const LEX_CSTRING str);
|
||||
|
||||
static inline LEX_STRING lex_string_strmake_root(MEM_ROOT *mem_root,
|
||||
const char *str, size_t length)
|
||||
{
|
||||
LEX_STRING tmp;
|
||||
tmp.str= strmake_root(mem_root, str, length);
|
||||
tmp.length= tmp.str ? length : 0;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
extern LEX_STRING lex_string_casedn_root(MEM_ROOT *root,
|
||||
CHARSET_INFO *cs,
|
||||
const char *str, size_t length);
|
||||
|
||||
extern my_bool my_compress(uchar *, size_t *, size_t *);
|
||||
extern my_bool my_uncompress(uchar *, size_t , size_t *);
|
||||
extern uchar *my_compress_alloc(const uchar *packet, size_t *len,
|
||||
|
@ -623,3 +623,16 @@ LEX_CSTRING safe_lexcstrdup_root(MEM_ROOT *root, const LEX_CSTRING str)
|
||||
res.length= str.length;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
LEX_STRING lex_string_casedn_root(MEM_ROOT *root, CHARSET_INFO *cs,
|
||||
const char *str, size_t length)
|
||||
{
|
||||
size_t nbytes= length * cs->cset->casedn_multiply(cs);
|
||||
LEX_STRING res= {NULL, 0};
|
||||
if (!(res.str= alloc_root(root, nbytes + 1)))
|
||||
return res;
|
||||
res.length= cs->cset->casedn(cs, str, length, res.str, nbytes);
|
||||
res.str[res.length]= '\0';
|
||||
return res;
|
||||
}
|
||||
|
@ -42,6 +42,7 @@ public:
|
||||
bool check_db_name() const;
|
||||
bool check_db_name_with_error() const;
|
||||
#ifndef DBUG_OFF
|
||||
bool is_in_lower_case() const;
|
||||
bool ok_for_lower_case_names() const;
|
||||
#endif
|
||||
};
|
||||
@ -55,6 +56,11 @@ public:
|
||||
*/
|
||||
class Lex_ident_db: public Lex_ident_fs
|
||||
{
|
||||
// {empty_c_string,0} is used by derived tables
|
||||
bool is_empty() const
|
||||
{
|
||||
return length == 0 && str != NULL;
|
||||
}
|
||||
public:
|
||||
Lex_ident_db()
|
||||
:Lex_ident_fs(NULL, 0)
|
||||
@ -62,7 +68,7 @@ public:
|
||||
Lex_ident_db(const char *str, size_t length)
|
||||
:Lex_ident_fs(str, length)
|
||||
{
|
||||
DBUG_SLOW_ASSERT(!check_db_name());
|
||||
DBUG_SLOW_ASSERT(is_empty() || !check_db_name());
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -2620,9 +2620,9 @@ bool Sp_handler::
|
||||
pkgstr, name->m_name, type()))
|
||||
{
|
||||
DBUG_ASSERT(ret == SP_OK);
|
||||
pkgname->copy(thd->mem_root, caller->m_db, pkgstr);
|
||||
*pkg_routine_handler= package_routine_handler();
|
||||
if (name->make_package_routine_name(thd->mem_root, pkgstr, name->m_name))
|
||||
if (pkgname->copy_sp_name_internal(thd->mem_root, caller->m_db, pkgstr) ||
|
||||
name->make_package_routine_name(thd->mem_root, pkgstr, name->m_name))
|
||||
return true;
|
||||
}
|
||||
return ret != SP_OK;
|
||||
|
@ -810,7 +810,7 @@ sp_head::init(LEX *lex)
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
bool
|
||||
sp_head::init_sp_name(const sp_name *spname)
|
||||
{
|
||||
DBUG_ENTER("sp_head::init_sp_name");
|
||||
@ -819,10 +819,10 @@ sp_head::init_sp_name(const sp_name *spname)
|
||||
|
||||
DBUG_ASSERT(spname && spname->m_db.str && spname->m_db.length);
|
||||
|
||||
/* We have to copy strings to get them into the right memroot. */
|
||||
Database_qualified_name::copy(&main_mem_root, spname->m_db, spname->m_name);
|
||||
m_explicit_name= spname->m_explicit_name;
|
||||
DBUG_VOID_RETURN;
|
||||
/* We have to copy strings to get them into the right memroot. */
|
||||
DBUG_RETURN(copy_sp_name_internal(&main_mem_root,
|
||||
spname->m_db, spname->m_name));
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -339,7 +339,7 @@ public:
|
||||
init(LEX *lex);
|
||||
|
||||
/** Copy sp name from parser. */
|
||||
void
|
||||
bool
|
||||
init_sp_name(const sp_name *spname);
|
||||
|
||||
/** Set the body-definition start position. */
|
||||
|
@ -3975,6 +3975,49 @@ Query_arena::Type Statement::type() const
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Return an internal database name:
|
||||
- validated with Lex_ident_db::check_db_name()
|
||||
- optionally converted to lower-case when lower_case_table_names==1
|
||||
|
||||
The lower-cased copy is made on mem_root when needed.
|
||||
An error is raised in case of EOM or a bad database name.
|
||||
|
||||
@param src - the database name
|
||||
@returns - {NULL,0} on EOM or a bad database name,
|
||||
or a good database name otherwise
|
||||
*/
|
||||
|
||||
Lex_ident_db
|
||||
Query_arena::to_ident_db_internal_with_error(const LEX_CSTRING &src)
|
||||
{
|
||||
DBUG_ASSERT(src.str);
|
||||
if (src.str == any_db.str) // e.g. JSON table
|
||||
return any_db; // preserve any_db - it has a special meaning
|
||||
|
||||
bool casedn= lower_case_table_names == 1;
|
||||
const LEX_CSTRING tmp= casedn ? make_ident_casedn(src) : src;
|
||||
if (!tmp.str /*EOM*/ ||
|
||||
Lex_ident_fs(tmp).check_db_name_with_error())
|
||||
return Lex_ident_db();
|
||||
|
||||
return Lex_ident_db(tmp.str, tmp.length);
|
||||
}
|
||||
|
||||
|
||||
Lex_ident_db
|
||||
Table_ident::to_ident_db_internal_with_error(Query_arena *arena) const
|
||||
{
|
||||
if (is_derived_table())
|
||||
{
|
||||
DBUG_ASSERT(db.str == empty_c_string && db.length == 0);
|
||||
return Lex_ident_db(empty_c_string, 0);
|
||||
}
|
||||
// Normal table or JSON table
|
||||
return arena->to_ident_db_internal_with_error(db);
|
||||
}
|
||||
|
||||
|
||||
void Statement::set_statement(Statement *stmt)
|
||||
{
|
||||
id= stmt->id;
|
||||
@ -8168,14 +8211,18 @@ void AUTHID::parse(const char *str, size_t length)
|
||||
}
|
||||
|
||||
|
||||
void Database_qualified_name::copy(MEM_ROOT *mem_root,
|
||||
const LEX_CSTRING &db,
|
||||
const LEX_CSTRING &name)
|
||||
bool Database_qualified_name::copy_sp_name_internal(MEM_ROOT *mem_root,
|
||||
const LEX_CSTRING &db,
|
||||
const LEX_CSTRING &name)
|
||||
{
|
||||
m_db.length= db.length;
|
||||
m_db.str= strmake_root(mem_root, db.str, db.length);
|
||||
m_name.length= name.length;
|
||||
m_name.str= strmake_root(mem_root, name.str, name.length);
|
||||
DBUG_ASSERT(db.str);
|
||||
DBUG_ASSERT(name.str);
|
||||
m_db= lower_case_table_names == 1 ?
|
||||
lex_string_casedn_root(mem_root, &my_charset_utf8mb3_general_ci,
|
||||
db.str, db.length) :
|
||||
lex_string_strmake_root(mem_root, db.str, db.length);
|
||||
m_name= lex_string_strmake_root(mem_root, name.str, name.length);
|
||||
return m_db.str == NULL || m_name.str == NULL; // check if EOM
|
||||
}
|
||||
|
||||
|
||||
|
@ -1355,6 +1355,45 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
Make a lower-cased copy of an identifier on mem_root.
|
||||
|
||||
@param src - The original identifier (usually coming from the parser)
|
||||
@return - {NULL,0} in case of EOM, or a non-NULL LEX_STRING
|
||||
with the lower-cased identifier copy.
|
||||
*/
|
||||
LEX_STRING make_ident_casedn(const LEX_CSTRING &src)
|
||||
{
|
||||
return lex_string_casedn_root(mem_root, &my_charset_utf8mb3_general_ci,
|
||||
src.str, src.length);
|
||||
}
|
||||
|
||||
/*
|
||||
Make an exact copy or a lower-cased copy of an identifier on mem_root.
|
||||
|
||||
@param src - The original identifier (usually coming from the parser)
|
||||
@param casedn - If the name should be converted to lower case
|
||||
@return - {NULL,0} in case of EOM,
|
||||
or a non-NULL LEX_STRING with the identifier copy.
|
||||
*/
|
||||
LEX_STRING make_ident_opt_casedn(const LEX_CSTRING &src, bool casedn)
|
||||
{
|
||||
return casedn ? make_ident_casedn(src) :
|
||||
lex_string_strmake_root(mem_root, src.str, src.length);
|
||||
}
|
||||
|
||||
/*
|
||||
Convert a LEX_CSTRING to a valid internal database name:
|
||||
- validated with Lex_ident_fs::check_db_name()
|
||||
- optionally lower-cased when lower_case_table_names==1
|
||||
The lower-cased copy is created on Query_arena::mem_root, when needed.
|
||||
|
||||
@param name - The name to normalize. Must not be {NULL,0}.
|
||||
@return - {NULL,0} on EOM or a bad database name
|
||||
(with an errror is raised,
|
||||
or a good database name otherwise.
|
||||
*/
|
||||
Lex_ident_db to_ident_db_internal_with_error(const LEX_CSTRING &name);
|
||||
|
||||
void set_query_arena(Query_arena *set);
|
||||
|
||||
@ -7051,6 +7090,16 @@ public:
|
||||
}
|
||||
bool resolve_table_rowtype_ref(THD *thd, Row_definition_list &defs);
|
||||
bool append_to(THD *thd, String *to) const;
|
||||
/*
|
||||
Convert Table_ident::m_db to a valid internal database name:
|
||||
- validated with Lex_ident_fs::check_db_name()
|
||||
- optionally lower-cased when lower_case_table_names==1
|
||||
|
||||
@param arena - the arena to allocate the lower-cased copy on, when needed.
|
||||
@return {NULL,0} in case of EOM or invalid database name,
|
||||
or a good identifier otherwise.
|
||||
*/
|
||||
Lex_ident_db to_ident_db_internal_with_error(Query_arena *arena) const;
|
||||
};
|
||||
|
||||
|
||||
@ -7865,8 +7914,13 @@ public:
|
||||
!cs->strnncoll(m_name.str, m_name.length,
|
||||
other->m_name.str, other->m_name.length);
|
||||
}
|
||||
void copy(MEM_ROOT *mem_root, const LEX_CSTRING &db,
|
||||
const LEX_CSTRING &name);
|
||||
/*
|
||||
Make copies of "db" and "name" on the memory root in internal format:
|
||||
- Lower-case "db" if lower-case-table-names==1.
|
||||
- Preserve "name" as is.
|
||||
*/
|
||||
bool copy_sp_name_internal(MEM_ROOT *mem_root, const LEX_CSTRING &db,
|
||||
const LEX_CSTRING &name);
|
||||
|
||||
// Export db and name as a qualified name string: 'db.name'
|
||||
size_t make_qname(char *dst, size_t dstlen) const
|
||||
|
@ -7389,14 +7389,9 @@ sp_name *LEX::make_sp_name(THD *thd, const Lex_ident_sys_st &name1,
|
||||
{
|
||||
DBUG_ASSERT(name1.str);
|
||||
sp_name *res;
|
||||
LEX_CSTRING norm_name1;
|
||||
if (unlikely(!thd->make_lex_string(&norm_name1, name1.str, name1.length)) ||
|
||||
unlikely(check_db_name((LEX_STRING *) &norm_name1)))
|
||||
{
|
||||
my_error(ER_WRONG_DB_NAME, MYF(0), name1.str);
|
||||
return NULL;
|
||||
}
|
||||
if (unlikely(check_routine_name(&name2)) ||
|
||||
const Lex_ident_db norm_name1= thd->to_ident_db_internal_with_error(name1);
|
||||
if (unlikely(!norm_name1.str) ||
|
||||
unlikely(check_routine_name(&name2)) ||
|
||||
unlikely(!(res= new (thd->mem_root) sp_name(&norm_name1, &name2, true))))
|
||||
return NULL;
|
||||
return res;
|
||||
@ -9309,20 +9304,16 @@ bool LEX::call_statement_start(THD *thd,
|
||||
const Lex_ident_sys_st *pkg,
|
||||
const Lex_ident_sys_st *proc)
|
||||
{
|
||||
DBUG_ASSERT(db->str);
|
||||
Database_qualified_name q_db_pkg(db, pkg);
|
||||
Identifier_chain2 q_pkg_proc(*pkg, *proc);
|
||||
sp_name *spname;
|
||||
|
||||
sql_command= SQLCOM_CALL;
|
||||
|
||||
if (check_db_name(reinterpret_cast<LEX_STRING*>
|
||||
(const_cast<LEX_CSTRING*>
|
||||
(static_cast<const LEX_CSTRING*>(db)))))
|
||||
{
|
||||
my_error(ER_WRONG_DB_NAME, MYF(0), db->str);
|
||||
return true;
|
||||
}
|
||||
if (check_routine_name(pkg) ||
|
||||
const Lex_ident_db db_int= thd->to_ident_db_internal_with_error(*db);
|
||||
if (!db_int.str ||
|
||||
check_routine_name(pkg) ||
|
||||
check_routine_name(proc))
|
||||
return true;
|
||||
|
||||
@ -9330,7 +9321,7 @@ bool LEX::call_statement_start(THD *thd,
|
||||
LEX_CSTRING pkg_dot_proc;
|
||||
if (q_pkg_proc.make_qname(thd->mem_root, &pkg_dot_proc) ||
|
||||
check_ident_length(&pkg_dot_proc) ||
|
||||
!(spname= new (thd->mem_root) sp_name(db, &pkg_dot_proc, true)))
|
||||
!(spname= new (thd->mem_root) sp_name(&db_int, &pkg_dot_proc, true)))
|
||||
return true;
|
||||
|
||||
sp_handler_package_function.add_used_routine(thd->lex, thd, spname);
|
||||
@ -9575,17 +9566,13 @@ Item *LEX::make_item_func_call_generic(THD *thd, Lex_ident_cli_st *cdb,
|
||||
version() (a vendor can specify any schema).
|
||||
*/
|
||||
|
||||
if (!name.str || check_db_name((LEX_STRING*) static_cast<LEX_CSTRING*>(&db)))
|
||||
{
|
||||
my_error(ER_WRONG_DB_NAME, MYF(0), db.str);
|
||||
return NULL;
|
||||
}
|
||||
if (check_routine_name(&name))
|
||||
const Lex_ident_db db_int= thd->to_ident_db_internal_with_error(db);
|
||||
if (!db_int.str || check_routine_name(&name))
|
||||
return NULL;
|
||||
|
||||
Create_qfunc *builder= find_qualified_function_builder(thd);
|
||||
DBUG_ASSERT(builder);
|
||||
return builder->create_with_db(thd, &db, &name, true, args);
|
||||
return builder->create_with_db(thd, &db_int, &name, true, args);
|
||||
}
|
||||
|
||||
|
||||
@ -9609,12 +9596,9 @@ Item *LEX::make_item_func_call_generic(THD *thd,
|
||||
if (db.is_null() || pkg.is_null() || func.is_null())
|
||||
return NULL; // EOM
|
||||
|
||||
if (check_db_name((LEX_STRING*) static_cast<LEX_CSTRING*>(&db)))
|
||||
{
|
||||
my_error(ER_WRONG_DB_NAME, MYF(0), db.str);
|
||||
return NULL;
|
||||
}
|
||||
if (check_routine_name(&pkg) ||
|
||||
const Lex_ident_db db_int= thd->to_ident_db_internal_with_error(db);
|
||||
if (!db_int.str ||
|
||||
check_routine_name(&pkg) ||
|
||||
check_routine_name(&func))
|
||||
return NULL;
|
||||
|
||||
@ -9622,7 +9606,7 @@ Item *LEX::make_item_func_call_generic(THD *thd,
|
||||
LEX_CSTRING pkg_dot_func;
|
||||
if (q_pkg_func.make_qname(thd->mem_root, &pkg_dot_func) ||
|
||||
check_ident_length(&pkg_dot_func) ||
|
||||
!(qname= new (thd->mem_root) sp_name(&db, &pkg_dot_func, true)))
|
||||
!(qname= new (thd->mem_root) sp_name(&db_int, &pkg_dot_func, true)))
|
||||
return NULL;
|
||||
|
||||
sp_handler_package_function.add_used_routine(thd->lex, thd, qname);
|
||||
@ -11427,13 +11411,18 @@ bool LEX::stmt_alter_table_exchange_partition(Table_ident *table)
|
||||
bool LEX::stmt_alter_table(Table_ident *table)
|
||||
{
|
||||
DBUG_ASSERT(sql_command == SQLCOM_ALTER_TABLE);
|
||||
first_select_lex()->db= table->db;
|
||||
if (first_select_lex()->db.str == NULL &&
|
||||
copy_db_to(&first_select_lex()->db))
|
||||
|
||||
if (table->db.str)
|
||||
{
|
||||
const Lex_ident_db db_int= thd->to_ident_db_internal_with_error(table->db);
|
||||
if (!db_int.str)
|
||||
return true;
|
||||
first_select_lex()->db= db_int;
|
||||
}
|
||||
else if (copy_db_to(&first_select_lex()->db))
|
||||
return true;
|
||||
if (unlikely(check_table_name(table->table.str, table->table.length,
|
||||
false)) ||
|
||||
(table->db.str && unlikely(check_db_name((LEX_STRING*) &table->db))))
|
||||
false)))
|
||||
{
|
||||
my_error(ER_WRONG_TABLE_NAME, MYF(0), table->table.str);
|
||||
return true;
|
||||
@ -11502,18 +11491,19 @@ bool LEX::stmt_drop_function(const DDL_options_st &options,
|
||||
const Lex_ident_sys_st &db,
|
||||
const Lex_ident_sys_st &name)
|
||||
{
|
||||
if (unlikely(db.str && check_db_name((LEX_STRING*) &db)))
|
||||
{
|
||||
my_error(ER_WRONG_DB_NAME, MYF(0), db.str);
|
||||
DBUG_ASSERT(db.str);
|
||||
DBUG_ASSERT(name.str);
|
||||
const Lex_ident_db db_int= thd->to_ident_db_internal_with_error(db);
|
||||
if (unlikely(!db_int.str))
|
||||
return true;
|
||||
}
|
||||
|
||||
if (unlikely(sphead))
|
||||
{
|
||||
my_error(ER_SP_NO_DROP_SP, MYF(0), "FUNCTION");
|
||||
return true;
|
||||
}
|
||||
set_command(SQLCOM_DROP_FUNCTION, options);
|
||||
spname= new (thd->mem_root) sp_name(&db, &name, true);
|
||||
spname= new (thd->mem_root) sp_name(&db_int, &name, true);
|
||||
return spname == NULL;
|
||||
}
|
||||
|
||||
|
@ -1424,8 +1424,8 @@ public:
|
||||
bool add_ftfunc_to_list(THD *thd, Item_func_match *func);
|
||||
bool add_order_to_list(THD *thd, Item *item, bool asc);
|
||||
bool add_gorder_to_list(THD *thd, Item *item, bool asc);
|
||||
TABLE_LIST* add_table_to_list(THD *thd, Table_ident *table,
|
||||
LEX_CSTRING *alias,
|
||||
TABLE_LIST* add_table_to_list(THD *thd, const Table_ident *table,
|
||||
const LEX_CSTRING *alias,
|
||||
ulong table_options,
|
||||
thr_lock_type flags= TL_UNLOCK,
|
||||
enum_mdl_type mdl_type= MDL_SHARED_READ,
|
||||
|
115
sql/sql_parse.cc
115
sql/sql_parse.cc
@ -2623,18 +2623,11 @@ int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident,
|
||||
schema_select_lex= new (thd->mem_root) SELECT_LEX();
|
||||
schema_select_lex->table_list.first= NULL;
|
||||
if (lower_case_table_names == 1)
|
||||
lex->first_select_lex()->db.str=
|
||||
thd->strdup(lex->first_select_lex()->db.str);
|
||||
lex->first_select_lex()->db=
|
||||
thd->make_ident_casedn(lex->first_select_lex()->db);
|
||||
schema_select_lex->db= lex->first_select_lex()->db;
|
||||
/*
|
||||
check_db_name() may change db.str if lower_case_table_names == 1,
|
||||
but that's ok as the db is allocted above in this case.
|
||||
*/
|
||||
if (check_db_name((LEX_STRING*) &lex->first_select_lex()->db))
|
||||
{
|
||||
my_error(ER_WRONG_DB_NAME, MYF(0), lex->first_select_lex()->db.str);
|
||||
if (Lex_ident_fs(lex->first_select_lex()->db).check_db_name_with_error())
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
@ -3045,15 +3038,11 @@ mysql_create_routine(THD *thd, LEX *lex)
|
||||
{
|
||||
DBUG_ASSERT(lex->sphead != 0);
|
||||
DBUG_ASSERT(lex->sphead->m_db.str); /* Must be initialized in the parser */
|
||||
/*
|
||||
Verify that the database name is allowed, optionally
|
||||
lowercase it.
|
||||
*/
|
||||
if (check_db_name((LEX_STRING*) &lex->sphead->m_db))
|
||||
{
|
||||
my_error(ER_WRONG_DB_NAME, MYF(0), lex->sphead->m_db.str);
|
||||
DBUG_ASSERT(lower_case_table_names != 1 ||
|
||||
Lex_ident_fs(lex->sphead->m_db).is_in_lower_case());
|
||||
|
||||
if (Lex_ident_fs(lex->sphead->m_db).check_db_name_with_error())
|
||||
return true;
|
||||
}
|
||||
|
||||
if (check_access(thd, CREATE_PROC_ACL, lex->sphead->m_db.str,
|
||||
NULL, NULL, 0, 0))
|
||||
@ -7056,7 +7045,7 @@ bool check_global_access(THD *thd, privilege_t want_access, bool no_errors)
|
||||
bool check_fk_parent_table_access(THD *thd,
|
||||
HA_CREATE_INFO *create_info,
|
||||
Alter_info *alter_info,
|
||||
const char* create_db)
|
||||
const LEX_CSTRING &create_db)
|
||||
{
|
||||
Key *key;
|
||||
List_iterator<Key> key_iterator(alter_info->key_list);
|
||||
@ -7079,54 +7068,37 @@ bool check_fk_parent_table_access(THD *thd,
|
||||
my_error(ER_WRONG_TABLE_NAME, MYF(0), table_name.str);
|
||||
return true;
|
||||
}
|
||||
// if lower_case_table_names is set then convert tablename to lower case.
|
||||
if (lower_case_table_names &&
|
||||
!(table_name= thd->make_ident_casedn(fk_key->ref_table)).str)
|
||||
return true;
|
||||
|
||||
if (fk_key->ref_db.str)
|
||||
{
|
||||
if (!(db_name.str= (char *) thd->memdup(fk_key->ref_db.str,
|
||||
fk_key->ref_db.length+1)))
|
||||
if (Lex_ident_fs(fk_key->ref_db).check_db_name_with_error() ||
|
||||
!(db_name= thd->make_ident_opt_casedn(fk_key->ref_db,
|
||||
lower_case_table_names)).str)
|
||||
return true;
|
||||
db_name.length= fk_key->ref_db.length;
|
||||
|
||||
// Check if database name is valid or not.
|
||||
if (check_db_name((LEX_STRING*) &db_name))
|
||||
{
|
||||
my_error(ER_WRONG_DB_NAME, MYF(0), db_name.str);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!thd->db.str)
|
||||
{
|
||||
DBUG_ASSERT(create_db);
|
||||
db_name.length= strlen(create_db);
|
||||
if (!(db_name.str= (char *) thd->memdup(create_db,
|
||||
db_name.length+1)))
|
||||
DBUG_ASSERT(create_db.str);
|
||||
if (Lex_ident_fs(create_db).check_db_name_with_error() ||
|
||||
!(db_name= thd->make_ident_opt_casedn(create_db,
|
||||
lower_case_table_names)).str)
|
||||
return true;
|
||||
|
||||
if (check_db_name((LEX_STRING*) &db_name))
|
||||
{
|
||||
my_error(ER_WRONG_DB_NAME, MYF(0), db_name.str);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (thd->lex->copy_db_to(&db_name))
|
||||
if (thd->lex->copy_db_to(&db_name) ||
|
||||
(lower_case_table_names &&
|
||||
!(db_name= thd->make_ident_casedn(db_name)).str))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// if lower_case_table_names is set then convert tablename to lower case.
|
||||
if (lower_case_table_names)
|
||||
{
|
||||
char *name;
|
||||
table_name.str= name= (char *) thd->memdup(fk_key->ref_table.str,
|
||||
fk_key->ref_table.length+1);
|
||||
table_name.length= my_casedn_str(files_charset_info, name);
|
||||
db_name.length= my_casedn_str(files_charset_info, (char*) db_name.str);
|
||||
}
|
||||
|
||||
parent_table.init_one_table(&db_name, &table_name, 0, TL_IGNORE);
|
||||
|
||||
/*
|
||||
@ -7892,11 +7864,30 @@ bool add_to_list(THD *thd, SQL_I_List<ORDER> &list, Item *item,bool asc)
|
||||
0 Error
|
||||
@retval
|
||||
\# Pointer to TABLE_LIST element added to the total table list
|
||||
|
||||
|
||||
This method can be called in contexts when the "table" argument has a longer
|
||||
life cycle than TABLE_LIST and belongs to a different MEM_ROOT than
|
||||
the current THD::mem_root.
|
||||
|
||||
For example, it's called from Table_ident::resolve_table_rowtype_ref()
|
||||
during sp_head::rcontext_create() during a CALL statement.
|
||||
"table" in this case belongs to sp_pcontext, which must stay valid
|
||||
(inside its SP cache sp_head entry) after the end of the current statement.
|
||||
|
||||
Let's allocate normalized copies of table.db and table.table on the current
|
||||
THD::mem_root and store them in the TABLE_LIST.
|
||||
|
||||
We should not touch "table" and replace table.db and table.table to their
|
||||
normalized copies allocated on the current THD::mem_root, because it'll be
|
||||
freed at the end of the current statement, while table.db and table.table
|
||||
should stay valid. Let's keep them in the original state.
|
||||
|
||||
*/
|
||||
|
||||
TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
|
||||
Table_ident *table,
|
||||
LEX_CSTRING *alias,
|
||||
const Table_ident *table,
|
||||
const LEX_CSTRING *alias,
|
||||
ulong table_options,
|
||||
thr_lock_type lock_type,
|
||||
enum_mdl_type mdl_type,
|
||||
@ -7928,11 +7919,8 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
|
||||
|
||||
if (unlikely(table->is_derived_table() == FALSE && table->db.str &&
|
||||
!(table_options & TL_OPTION_TABLE_FUNCTION) &&
|
||||
check_db_name((LEX_STRING*) &table->db)))
|
||||
{
|
||||
my_error(ER_WRONG_DB_NAME, MYF(0), table->db.str);
|
||||
Lex_ident_fs(table->db).check_db_name_with_error()))
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
if (!alias) /* Alias is case sensitive */
|
||||
{
|
||||
@ -7960,16 +7948,17 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
|
||||
|
||||
ptr->alias= alias_str;
|
||||
ptr->is_alias= alias ? TRUE : FALSE;
|
||||
ptr->table_name= table->table;
|
||||
|
||||
if (lower_case_table_names)
|
||||
{
|
||||
if (table->table.length)
|
||||
table->table.length= my_casedn_str(files_charset_info,
|
||||
(char*) table->table.str);
|
||||
if (ptr->db.length && ptr->db.str != any_db.str)
|
||||
ptr->db.length= my_casedn_str(files_charset_info, (char*) ptr->db.str);
|
||||
if (!(ptr->table_name= thd->make_ident_casedn(ptr->table_name)).str)
|
||||
DBUG_RETURN(0);
|
||||
if (ptr->db.length && ptr->db.str != any_db.str &&
|
||||
!(ptr->db= thd->make_ident_casedn(ptr->db)).str)
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
ptr->table_name= table->table;
|
||||
ptr->lock_type= lock_type;
|
||||
ptr->mdl_type= mdl_type;
|
||||
ptr->table_options= table_options;
|
||||
@ -9693,7 +9682,7 @@ bool create_table_precheck(THD *thd, TABLE_LIST *tables,
|
||||
}
|
||||
|
||||
if (check_fk_parent_table_access(thd, &lex->create_info, &lex->alter_info,
|
||||
create_table->db.str))
|
||||
create_table->db))
|
||||
goto err;
|
||||
|
||||
error= FALSE;
|
||||
|
@ -50,7 +50,7 @@ bool create_table_precheck(THD *thd, TABLE_LIST *tables,
|
||||
bool check_fk_parent_table_access(THD *thd,
|
||||
HA_CREATE_INFO *create_info,
|
||||
Alter_info *alter_info,
|
||||
const char* create_db);
|
||||
const LEX_CSTRING &create_db);
|
||||
|
||||
bool parse_sql(THD *thd, Parser_state *parser_state,
|
||||
Object_creation_ctx *creation_ctx, bool do_pfs_digest=false);
|
||||
|
@ -10409,7 +10409,7 @@ bool mysql_alter_table(THD *thd, const LEX_CSTRING *new_db,
|
||||
till this point for the alter operation.
|
||||
*/
|
||||
if ((alter_info->flags & ALTER_ADD_FOREIGN_KEY) &&
|
||||
check_fk_parent_table_access(thd, create_info, alter_info, new_db->str))
|
||||
check_fk_parent_table_access(thd, create_info, alter_info, *new_db))
|
||||
DBUG_RETURN(true);
|
||||
|
||||
/*
|
||||
|
53
sql/table.cc
53
sql/table.cc
@ -5146,57 +5146,16 @@ uint calculate_key_len(TABLE *table, uint key, const uchar *buf,
|
||||
*/
|
||||
bool Lex_ident_fs::ok_for_lower_case_names() const
|
||||
{
|
||||
if (!lower_case_table_names || !str)
|
||||
return true;
|
||||
DBNameBuffer buf(*this, lower_case_table_names);
|
||||
return !lower_case_table_names || !str || is_in_lower_case();
|
||||
}
|
||||
|
||||
bool Lex_ident_fs::is_in_lower_case() const
|
||||
{
|
||||
DBNameBuffer buf(*this, true);
|
||||
return cmp(*this, buf.to_lex_cstring()) == 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
Check if database name is valid
|
||||
|
||||
SYNPOSIS
|
||||
check_db_name()
|
||||
org_name Name of database
|
||||
|
||||
NOTES
|
||||
If lower_case_table_names is set to 1 then database name is converted
|
||||
to lower case
|
||||
|
||||
RETURN
|
||||
0 ok
|
||||
1 error
|
||||
*/
|
||||
|
||||
bool check_db_name(LEX_STRING *org_name)
|
||||
{
|
||||
char *name= org_name->str;
|
||||
size_t name_length= org_name->length;
|
||||
bool disallow_path_chars;
|
||||
|
||||
if ((disallow_path_chars= check_mysql50_prefix(name)))
|
||||
{
|
||||
name+= MYSQL50_TABLE_NAME_PREFIX_LENGTH;
|
||||
name_length-= MYSQL50_TABLE_NAME_PREFIX_LENGTH;
|
||||
}
|
||||
|
||||
if (!name_length || name_length > NAME_LEN)
|
||||
return 1;
|
||||
|
||||
if (lower_case_table_names == 1 && name != any_db.str)
|
||||
{
|
||||
org_name->length= name_length= my_casedn_str(files_charset_info, name);
|
||||
if (disallow_path_chars)
|
||||
org_name->length+= MYSQL50_TABLE_NAME_PREFIX_LENGTH;
|
||||
}
|
||||
if (db_name_is_in_ignore_db_dirs_list(name))
|
||||
return 1;
|
||||
|
||||
return check_table_name(name, name_length, disallow_path_chars);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Allow anything as a table name, as long as it doesn't contain an
|
||||
' ' at the end
|
||||
|
@ -3398,7 +3398,7 @@ enum open_frm_error open_table_def(THD *thd, TABLE_SHARE *share,
|
||||
void open_table_error(TABLE_SHARE *share, enum open_frm_error error,
|
||||
int db_errno);
|
||||
void update_create_info_from_table(HA_CREATE_INFO *info, TABLE *form);
|
||||
bool check_db_name(LEX_STRING *db);
|
||||
|
||||
bool check_column_name(const char *name);
|
||||
bool check_period_name(const char *name);
|
||||
bool check_table_name(const char *name, size_t length, bool check_for_path_chars);
|
||||
|
Loading…
x
Reference in New Issue
Block a user