MDEV-35854: Simplify dict_get_referenced_table()

innodb_convert_name(): Convert a schema or table name to
my_charset_filename compatible format.

dict_table_lookup(): Replaces dict_get_referenced_table().
Make the callers responsible for invoking innodb_convert_name().

innobase_casedn_str(): Remove. Let us invoke my_casedn_str() directly.

dict_table_rename_in_cache(): Do not duplicate a call to
dict_mem_foreign_table_name_lookup_set().

innobase_convert_to_filename_charset(): Defined static in the only
compilation unit that needs it.

dict_scan_id(): Remove the constant parameters
table_id=FALSE, accept_also_dot=TRUE. Invoke strconvert() directly.

innobase_convert_from_id(): Remove; only called from dict_scan_id().

innobase_convert_from_table_id(): Remove (dead code).

table_name_t::dblen(), table_name_t::basename(): In non-debug builds,
tolerate names that may miss a '/' separator.

Reviewed by: Debarun Banerjee
This commit is contained in:
Marko Mäkelä 2025-01-23 14:38:08 +02:00
parent fa74c1a40f
commit d4da659b43
11 changed files with 245 additions and 324 deletions

View file

@ -1118,5 +1118,29 @@ test.binaries check status OK
test.collections check status OK
disconnect con1;
DROP TABLE binaries, collections;
CREATE SCHEMA `#mysql50##mysql50#d-b`;
CREATE TABLE `#mysql50##mysql50#d-b`.t1 (a INT PRIMARY KEY, b INT UNIQUE) engine=InnoDB;
USE `#mysql50##mysql50#d-b`;
CREATE TABLE t2 (a INT PRIMARY KEY, b INT UNIQUE REFERENCES t1(b)) ENGINE=InnoDB;
SET STATEMENT foreign_key_checks=0 FOR
ALTER TABLE t2 ADD FOREIGN KEY (a) REFERENCES t1(a);
SHOW CREATE TABLE t2;
Table Create Table
t2 CREATE TABLE `t2` (
`a` int(11) NOT NULL,
`b` int(11) DEFAULT NULL,
PRIMARY KEY (`a`),
UNIQUE KEY `b` (`b`),
CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`b`) REFERENCES `t1` (`b`),
CONSTRAINT `t2_ibfk_2` FOREIGN KEY (`a`) REFERENCES `t1` (`a`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci
INSERT INTO t1 SET a=1;
INSERT INTO t2 SET a=1;
DELETE FROM t1;
ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`#mysql50#d-b`.`t2`, CONSTRAINT `t2_ibfk_2` FOREIGN KEY (`a`) REFERENCES `t1` (`a`))
DELETE FROM t2;
DELETE FROM t1;
DROP DATABASE `#mysql50##mysql50#d-b`;
USE test;
# End of 10.6 tests
SET GLOBAL innodb_stats_persistent = @save_stats_persistent;

View file

@ -4,6 +4,7 @@
--disable_query_log
call mtr.add_suppression("InnoDB: Transaction was aborted due to ");
call mtr.add_suppression("Invalid \\(old\\?\\) table or database name '#mysql50#d-b'");
--enable_query_log
SET GLOBAL innodb_stats_persistent = 0;
@ -1188,6 +1189,22 @@ CHECK TABLE binaries, collections EXTENDED;
# Cleanup
DROP TABLE binaries, collections;
CREATE SCHEMA `#mysql50##mysql50#d-b`;
CREATE TABLE `#mysql50##mysql50#d-b`.t1 (a INT PRIMARY KEY, b INT UNIQUE) engine=InnoDB;
USE `#mysql50##mysql50#d-b`;
CREATE TABLE t2 (a INT PRIMARY KEY, b INT UNIQUE REFERENCES t1(b)) ENGINE=InnoDB;
SET STATEMENT foreign_key_checks=0 FOR
ALTER TABLE t2 ADD FOREIGN KEY (a) REFERENCES t1(a);
SHOW CREATE TABLE t2;
INSERT INTO t1 SET a=1;
INSERT INTO t2 SET a=1;
--error ER_ROW_IS_REFERENCED_2
DELETE FROM t1;
DELETE FROM t2;
DELETE FROM t1;
DROP DATABASE `#mysql50##mysql50#d-b`;
USE test;
--echo # End of 10.6 tests
SET GLOBAL innodb_stats_persistent = @save_stats_persistent;

View file

@ -1467,6 +1467,26 @@ dict_table_t::rename_tablespace(span<const char> new_name, bool replace) const
return err;
}
/**********************************************************************
Converts an identifier from my_charset_filename to UTF-8 charset.
@return result string length, as returned by strconvert() */
static
uint
innobase_convert_to_filename_charset(
/*=================================*/
char* to, /* out: converted identifier */
const char* from, /* in: identifier to convert */
ulint len) /* in: length of 'to', in bytes */
{
uint errors;
CHARSET_INFO* cs_to = &my_charset_filename;
CHARSET_INFO* cs_from = system_charset_info;
return(static_cast<uint>(strconvert(
cs_from, from, uint(strlen(from)),
cs_to, to, static_cast<uint>(len), &errors)));
}
/**********************************************************************//**
Renames a table object.
@return TRUE if success */
@ -1599,19 +1619,20 @@ dict_table_rename_in_cache(
foreign->referenced_table->referenced_set.erase(foreign);
}
if (strlen(foreign->foreign_table_name)
< strlen(table->name.m_name)) {
const bool do_alloc = strlen(foreign->foreign_table_name)
< strlen(table->name.m_name);
if (do_alloc) {
/* Allocate a longer name buffer;
TODO: store buf len to save memory */
foreign->foreign_table_name = mem_heap_strdup(
foreign->heap, table->name.m_name);
dict_mem_foreign_table_name_lookup_set(foreign, TRUE);
} else {
strcpy(foreign->foreign_table_name,
table->name.m_name);
dict_mem_foreign_table_name_lookup_set(foreign, FALSE);
}
dict_mem_foreign_table_name_lookup_set(foreign, do_alloc);
if (strchr(foreign->id, '/')) {
/* This is a >= 4.0.18 format id */
@ -3105,20 +3126,13 @@ dict_scan_id(
mem_heap_t* heap, /*!< in: heap where to allocate the id
(NULL=id will not be allocated, but it
will point to string near ptr) */
const char** id, /*!< out,own: the id; NULL if no id was
const char** id) /*!< out,own: the id; NULL if no id was
scannable */
ibool table_id,/*!< in: TRUE=convert the allocated id
as a table name; FALSE=convert to UTF-8 */
ibool accept_also_dot)
/*!< in: TRUE if also a dot can appear in a
non-quoted id; in a quoted id it can appear
always */
{
char quote = '\0';
ulint len = 0;
const char* s;
char* str;
char* dst;
*id = NULL;
@ -3154,7 +3168,6 @@ dict_scan_id(
}
} else {
while (!my_isspace(cs, *ptr) && *ptr != '(' && *ptr != ')'
&& (accept_also_dot || *ptr != '.')
&& *ptr != ',' && *ptr != '\0') {
ptr++;
@ -3188,125 +3201,15 @@ dict_scan_id(
str = mem_heap_strdupl(heap, s, len);
}
if (!table_id) {
convert_id:
/* Convert the identifier from connection character set
to UTF-8. */
len = 3 * len + 1;
*id = dst = static_cast<char*>(mem_heap_alloc(heap, len));
innobase_convert_from_id(cs, dst, str, len);
} else if (!strncmp(str, srv_mysql50_table_name_prefix,
sizeof(srv_mysql50_table_name_prefix) - 1)) {
/* This is a pre-5.1 table name
containing chars other than [A-Za-z0-9].
Discard the prefix and use raw UTF-8 encoding. */
str += sizeof(srv_mysql50_table_name_prefix) - 1;
len -= sizeof(srv_mysql50_table_name_prefix) - 1;
goto convert_id;
} else {
/* Encode using filename-safe characters. */
len = 5 * len + 1;
*id = dst = static_cast<char*>(mem_heap_alloc(heap, len));
innobase_convert_from_table_id(cs, dst, str, len);
}
ulint dstlen = 3 * len + 1;
char *dst = static_cast<char*>(mem_heap_alloc(heap, dstlen));
*id = dst;
uint errors;
strconvert(cs, str, uint(len), system_charset_info, dst,
uint(dstlen), &errors);
return(ptr);
}
/*********************************************************************//**
Open a table from its database and table name, this is currently used by
foreign constraint parser to get the referenced table.
@return complete table name with database and table name, allocated from
heap memory passed in */
char*
dict_get_referenced_table(
const char* name, /*!< in: foreign key table name */
const char* database_name, /*!< in: table db name */
ulint database_name_len, /*!< in: db name length */
const char* table_name, /*!< in: table name */
ulint table_name_len, /*!< in: table name length */
dict_table_t** table, /*!< out: table object or NULL */
mem_heap_t* heap, /*!< in/out: heap memory */
CHARSET_INFO* from_cs) /*!< in: table name charset */
{
char* ref;
char db_name[MAX_DATABASE_NAME_LEN];
char tbl_name[MAX_TABLE_NAME_LEN];
CHARSET_INFO* to_cs = &my_charset_filename;
uint errors;
ut_ad(database_name || name);
ut_ad(table_name);
if (!strncmp(table_name, srv_mysql50_table_name_prefix,
sizeof(srv_mysql50_table_name_prefix) - 1)) {
/* This is a pre-5.1 table name
containing chars other than [A-Za-z0-9].
Discard the prefix and use raw UTF-8 encoding. */
table_name += sizeof(srv_mysql50_table_name_prefix) - 1;
table_name_len -= sizeof(srv_mysql50_table_name_prefix) - 1;
to_cs = system_charset_info;
}
table_name_len = strconvert(from_cs, table_name, table_name_len, to_cs,
tbl_name, MAX_TABLE_NAME_LEN, &errors);
table_name = tbl_name;
if (database_name) {
to_cs = &my_charset_filename;
if (!strncmp(database_name, srv_mysql50_table_name_prefix,
sizeof(srv_mysql50_table_name_prefix) - 1)) {
database_name
+= sizeof(srv_mysql50_table_name_prefix) - 1;
database_name_len
-= sizeof(srv_mysql50_table_name_prefix) - 1;
to_cs = system_charset_info;
}
database_name_len = strconvert(
from_cs, database_name, database_name_len, to_cs,
db_name, MAX_DATABASE_NAME_LEN, &errors);
database_name = db_name;
} else {
/* Use the database name of the foreign key table */
database_name = name;
database_name_len = dict_get_db_name_len(name);
}
/* Copy database_name, '/', table_name, '\0' */
const size_t len = database_name_len + table_name_len + 1;
ref = static_cast<char*>(mem_heap_alloc(heap, len + 1));
memcpy(ref, database_name, database_name_len);
ref[database_name_len] = '/';
memcpy(ref + database_name_len + 1, table_name, table_name_len + 1);
/* Values; 0 = Store and compare as given; case sensitive
1 = Store and compare in lower; case insensitive
2 = Store as given, compare in lower; case semi-sensitive */
if (lower_case_table_names == 2) {
innobase_casedn_str(ref);
*table = dict_sys.load_table({ref, len});
memcpy(ref, database_name, database_name_len);
ref[database_name_len] = '/';
memcpy(ref + database_name_len + 1, table_name, table_name_len + 1);
} else {
#ifndef _WIN32
if (lower_case_table_names == 1) {
innobase_casedn_str(ref);
}
#else
innobase_casedn_str(ref);
#endif /* !_WIN32 */
*table = dict_sys.load_table({ref, len});
}
return(ref);
}
/*********************************************************************//**
Removes MySQL comments from an SQL string. A comment is either
(a) '#' to the end of the line,
@ -3563,7 +3466,7 @@ loop:
}
}
ptr = dict_scan_id(cs, ptr, heap, &id, FALSE, TRUE);
ptr = dict_scan_id(cs, ptr, heap, &id);
if (id == NULL) {

View file

@ -816,7 +816,7 @@ void
dict_mem_foreign_table_name_lookup_set(
/*===================================*/
dict_foreign_t* foreign, /*!< in/out: foreign struct */
ibool do_alloc) /*!< in: is an alloc needed */
bool do_alloc) /*!< in: is an alloc needed */
{
if (lower_case_table_names == 2) {
if (do_alloc) {
@ -830,7 +830,8 @@ dict_mem_foreign_table_name_lookup_set(
}
strcpy(foreign->foreign_table_name_lookup,
foreign->foreign_table_name);
innobase_casedn_str(foreign->foreign_table_name_lookup);
my_casedn_str(system_charset_info,
foreign->foreign_table_name_lookup);
} else {
foreign->foreign_table_name_lookup
= foreign->foreign_table_name;
@ -860,7 +861,8 @@ dict_mem_referenced_table_name_lookup_set(
}
strcpy(foreign->referenced_table_name_lookup,
foreign->referenced_table_name);
innobase_casedn_str(foreign->referenced_table_name_lookup);
my_casedn_str(system_charset_info,
foreign->referenced_table_name_lookup);
} else {
foreign->referenced_table_name_lookup
= foreign->referenced_table_name;

View file

@ -1320,9 +1320,7 @@ static void innodb_drop_database(handlerton*, char *path)
namebuf[len] = '/';
namebuf[len + 1] = '\0';
#ifdef _WIN32
innobase_casedn_str(namebuf);
#endif /* _WIN32 */
IF_WIN(my_casedn_str(system_charset_info, namebuf),);
THD * const thd= current_thd;
trx_t *trx= innobase_trx_allocate(thd);
@ -2435,21 +2433,6 @@ dtype_get_mblen(
}
}
/******************************************************************//**
Converts an identifier to a table name. */
void
innobase_convert_from_table_id(
/*===========================*/
CHARSET_INFO* cs, /*!< in: the 'from' character set */
char* to, /*!< out: converted identifier */
const char* from, /*!< in: identifier to convert */
ulint len) /*!< in: length of 'to', in bytes */
{
uint errors;
strconvert(cs, from, FN_REFLEN, &my_charset_filename, to, (uint) len, &errors);
}
/**********************************************************************
Check if the length of the identifier exceeds the maximum allowed.
return true when length of identifier is too long. */
@ -2474,21 +2457,6 @@ innobase_check_identifier_length(
DBUG_RETURN(false);
}
/******************************************************************//**
Converts an identifier to UTF-8. */
void
innobase_convert_from_id(
/*=====================*/
CHARSET_INFO* cs, /*!< in: the 'from' character set */
char* to, /*!< out: converted identifier */
const char* from, /*!< in: identifier to convert */
ulint len) /*!< in: length of 'to', in bytes */
{
uint errors;
strconvert(cs, from, FN_REFLEN, system_charset_info, to, (uint) len, &errors);
}
/******************************************************************//**
Compares NUL-terminated UTF-8 strings case insensitively.
@return 0 if a=b, <0 if a<b, >1 if a>b */
@ -2537,16 +2505,6 @@ innobase_basename(
return((name) ? name : "null");
}
/******************************************************************//**
Makes all characters in a NUL-terminated UTF-8 string lower case. */
void
innobase_casedn_str(
/*================*/
char* a) /*!< in/out: string to put in lower case */
{
my_casedn_str(system_charset_info, a);
}
/** Determines the current SQL statement.
Thread unsafe, can only be called from the thread owning the THD.
@param[in] thd MySQL thread handle
@ -3683,13 +3641,13 @@ innobase_format_name(
ulint buflen, /*!< in: length of buf, in bytes */
const char* name) /*!< in: table name to format */
{
const char* bufend;
char* bufend;
bufend = innobase_convert_name(buf, buflen, name, strlen(name), NULL);
ut_ad((ulint) (bufend - buf) < buflen);
buf[bufend - buf] = '\0';
*bufend = '\0';
}
/**********************************************************************//**
@ -5386,7 +5344,7 @@ normalize_table_name_c_low(
memcpy(norm_name + db_len + 1, name_ptr, name_len + 1);
if (set_lower_case) {
innobase_casedn_str(norm_name);
my_casedn_str(system_charset_info, norm_name);
}
}
@ -6261,7 +6219,7 @@ ha_innobase::open_dict_table(
case name, including the partition
separator "P" */
strcpy(par_case_name, norm_name);
innobase_casedn_str(par_case_name);
my_casedn_str(system_charset_info, par_case_name);
#else
/* On Windows platfrom, check
whether there exists table name in
@ -12389,6 +12347,73 @@ public:
const char* str() { return buf; }
};
/** Construct an InnoDB table name from a schema and table name.
@param table_name buffer InnoDB table name being constructed
@param db schema name
@param name table name
@return table_name filled in */
static char *copy_name(char *table_name, LEX_CSTRING db, LEX_CSTRING name)
noexcept
{
memcpy(table_name, db.str, db.length);
table_name[db.length] = '/';
memcpy(table_name + db.length + 1, name.str, name.length + 1);
return table_name;
}
char *dict_table_lookup(LEX_CSTRING db, LEX_CSTRING name,
dict_table_t **table, mem_heap_t *heap) noexcept
{
const size_t len= db.length + name.length + 1;
char *ref= static_cast<char*>(mem_heap_alloc(heap, len + 1));
copy_name(ref, db, name);
switch (lower_case_table_names) {
case 2: /* store as given, compare in lower case */
my_casedn_str(system_charset_info, ref);
*table= dict_sys.load_table({ref, len});
return copy_name(ref, db, name);
case 0: /* store and compare as given; case sensitive */
#ifndef _WIN32 /* On Windows, InnoDB treats 0 as lower_case_table_names=1 */
break;
#endif
case 1: /* store and compare in lower case */
my_casedn_str(system_charset_info, ref);
}
*table = dict_sys.load_table({ref, len});
return ref;
}
/** Convert a schema or table name to InnoDB (and file system) format.
@param cs source character set
@param name name encoded in cs
@param buf output buffer (MAX_TABLE_NAME_LEN + 1 bytes)
@return the converted string (within buf) */
LEX_CSTRING innodb_convert_name(CHARSET_INFO *cs, LEX_CSTRING name, char *buf)
noexcept
{
CHARSET_INFO *to_cs= &my_charset_filename;
if (!strncmp(name.str, srv_mysql50_table_name_prefix,
sizeof srv_mysql50_table_name_prefix - 1))
{
/* Before MySQL 5.1 introduced my_charset_filename, schema and
table names were stored in the file system as specified by the
user, hopefully in ASCII encoding, but it could also be in ISO
8859-1 or UTF-8. Such schema or table names are distinguished by
the #mysql50# prefix.
Let us discard that prefix and convert the name to UTF-8
(system_charset_info). */
name.str+= sizeof srv_mysql50_table_name_prefix - 1;
name.length-= sizeof srv_mysql50_table_name_prefix - 1;
to_cs= system_charset_info;
}
uint errors;
return LEX_CSTRING{buf, strconvert(cs, name.str, name.length, to_cs,
buf, MAX_TABLE_NAME_LEN, &errors)};
}
/** Create InnoDB foreign keys from MySQL alter_info. Collect all
dict_foreign_t items into local_fk_set and then add into system table.
@return DB_SUCCESS or specific error code */
@ -12404,6 +12429,9 @@ create_table_info_t::create_foreign_keys()
const char* ref_column_names[MAX_COLS_PER_FK];
char create_name[MAX_DATABASE_NAME_LEN + 1 +
MAX_TABLE_NAME_LEN + 1];
char db_name[MAX_DATABASE_NAME_LEN + 1];
char t_name[MAX_TABLE_NAME_LEN + 1];
static_assert(MAX_TABLE_NAME_LEN == MAX_DATABASE_NAME_LEN, "");
dict_index_t* index = NULL;
fkerr_t index_error = FK_SUCCESS;
dict_index_t* err_index = NULL;
@ -12411,59 +12439,57 @@ create_table_info_t::create_foreign_keys()
const bool tmp_table = m_flags2 & DICT_TF2_TEMPORARY;
const CHARSET_INFO* cs = thd_charset(m_thd);
const char* operation = "Create ";
const char* name = m_table_name;
enum_sql_command sqlcom = enum_sql_command(thd_sql_command(m_thd));
LEX_CSTRING name= {m_table_name, strlen(m_table_name)};
if (sqlcom == SQLCOM_ALTER_TABLE) {
dict_table_t* table_to_alter;
mem_heap_t* heap = mem_heap_create(10000);
ulint highest_id_so_far;
char* n = dict_get_referenced_table(
name, LEX_STRING_WITH_LEN(m_form->s->db),
LEX_STRING_WITH_LEN(m_form->s->table_name),
&table_to_alter, heap, cs);
LEX_CSTRING t{innodb_convert_name(cs, m_form->s->table_name,
t_name)};
LEX_CSTRING d{innodb_convert_name(cs, m_form->s->db, db_name)};
dict_table_t* alter_table;
char* n = dict_table_lookup(d, t, &alter_table, heap);
/* Starting from 4.0.18 and 4.1.2, we generate foreign key id's
in the format databasename/tablename_ibfk_[number], where
[number] is local to the table; look for the highest [number]
for table_to_alter, so that we can assign to new constraints
for alter_table, so that we can assign to new constraints
higher numbers. */
/* If we are altering a temporary table, the table name after
ALTER TABLE does not correspond to the internal table name, and
table_to_alter is NULL. TODO: should we fix this somehow? */
alter_table=nullptr. But, we do not support FOREIGN KEY
constraints for temporary tables. */
if (table_to_alter) {
n = table_to_alter->name.m_name;
highest_id_so_far = dict_table_get_highest_foreign_id(
table_to_alter);
} else {
highest_id_so_far = 0;
if (alter_table) {
n = alter_table->name.m_name;
number = 1 + dict_table_get_highest_foreign_id(
alter_table);
}
char* bufend = innobase_convert_name(
create_name, sizeof create_name, n, strlen(n), m_thd);
create_name[bufend - create_name] = '\0';
number = highest_id_so_far + 1;
*bufend = '\0';
mem_heap_free(heap);
operation = "Alter ";
} else if (strstr(name, "#P#") || strstr(name, "#p#")) {
} else if (strstr(m_table_name, "#P#")
|| strstr(m_table_name, "#p#")) {
/* Partitioned table */
create_name[0] = '\0';
} else {
char* bufend = innobase_convert_name(create_name,
sizeof create_name,
name,
strlen(name), m_thd);
create_name[bufend - create_name] = '\0';
LEX_STRING_WITH_LEN(name),
m_thd);
*bufend = '\0';
}
Alter_info* alter_info = m_create_info->alter_info;
ut_ad(alter_info);
List_iterator_fast<Key> key_it(alter_info->key_list);
dict_table_t* table = dict_sys.find_table({name,strlen(name)});
dict_table_t* table = dict_sys.find_table({name.str, name.length});
if (!table) {
ib_foreign_warn(m_trx, DB_CANNOT_ADD_CONSTRAINT, create_name,
"%s table %s foreign key constraint"
@ -12510,27 +12536,27 @@ create_table_info_t::create_foreign_keys()
col->field_name.length);
success = find_col(table, column_names + i);
if (!success) {
key_text k(fk);
ib_foreign_warn(
m_trx, DB_CANNOT_ADD_CONSTRAINT,
create_name,
"%s table %s foreign key %s constraint"
" failed. Column %s was not found.",
operation, create_name, k.str(),
operation, create_name,
key_text(fk).str(),
column_names[i]);
dict_foreign_free(foreign);
return (DB_CANNOT_ADD_CONSTRAINT);
}
++i;
if (i >= MAX_COLS_PER_FK) {
key_text k(fk);
ib_foreign_warn(
m_trx, DB_CANNOT_ADD_CONSTRAINT,
create_name,
"%s table %s foreign key %s constraint"
" failed. Too many columns: %u (%u "
"allowed).",
operation, create_name, k.str(), i,
operation, create_name,
key_text(fk).str(), i,
MAX_COLS_PER_FK);
dict_foreign_free(foreign);
return (DB_CANNOT_ADD_CONSTRAINT);
@ -12542,9 +12568,9 @@ create_table_info_t::create_foreign_keys()
&index_error, &err_col, &err_index);
if (!index) {
key_text k(fk);
foreign_push_index_error(m_trx, operation, create_name,
k.str(), column_names,
key_text(fk).str(),
column_names,
index_error, err_col,
err_index, table);
dict_foreign_free(foreign);
@ -12610,14 +12636,12 @@ create_table_info_t::create_foreign_keys()
memcpy(foreign->foreign_col_names, column_names,
i * sizeof(void*));
foreign->referenced_table_name = dict_get_referenced_table(
name, LEX_STRING_WITH_LEN(fk->ref_db),
LEX_STRING_WITH_LEN(fk->ref_table),
&foreign->referenced_table, foreign->heap, cs);
if (!foreign->referenced_table_name) {
return (DB_OUT_OF_MEMORY);
}
LEX_CSTRING t{innodb_convert_name(cs, fk->ref_table, t_name)};
LEX_CSTRING d = fk->ref_db.str
? innodb_convert_name(cs, fk->ref_db, db_name)
: LEX_CSTRING{table->name.m_name, table->name.dblen()};
foreign->referenced_table_name = dict_table_lookup(
d, t, &foreign->referenced_table, foreign->heap);
if (!foreign->referenced_table && m_trx->check_foreigns) {
char buf[MAX_TABLE_NAME_LEN + 1] = "";
@ -12627,15 +12651,15 @@ create_table_info_t::create_foreign_keys()
buf, MAX_TABLE_NAME_LEN,
foreign->referenced_table_name,
strlen(foreign->referenced_table_name), m_thd);
buf[bufend - buf] = '\0';
key_text k(fk);
*bufend = '\0';
ib_foreign_warn(m_trx, DB_CANNOT_ADD_CONSTRAINT,
create_name,
"%s table %s with foreign key %s "
"constraint failed. Referenced table "
"%s not found in the data dictionary.",
operation, create_name, k.str(), buf);
return (DB_CANNOT_ADD_CONSTRAINT);
operation, create_name,
key_text(fk).str(), buf);
return DB_CANNOT_ADD_CONSTRAINT;
}
/* Don't allow foreign keys on partitioned tables yet. */
@ -12658,7 +12682,6 @@ create_table_info_t::create_foreign_keys()
success = find_col(foreign->referenced_table,
ref_column_names + j);
if (!success) {
key_text k(fk);
ib_foreign_warn(
m_trx,
DB_CANNOT_ADD_CONSTRAINT,
@ -12667,9 +12690,9 @@ create_table_info_t::create_foreign_keys()
"constraint failed. "
"Column %s was not found.",
operation, create_name,
k.str(), ref_column_names[j]);
return (DB_CANNOT_ADD_CONSTRAINT);
key_text(fk).str(),
ref_column_names[j]);
return DB_CANNOT_ADD_CONSTRAINT;
}
}
++j;
@ -12689,16 +12712,15 @@ create_table_info_t::create_foreign_keys()
&err_index);
if (!index) {
key_text k(fk);
foreign_push_index_error(
m_trx, operation, create_name, k.str(),
m_trx, operation, create_name,
key_text(fk).str(),
column_names, index_error, err_col,
err_index, foreign->referenced_table);
return (DB_CANNOT_ADD_CONSTRAINT);
return DB_CANNOT_ADD_CONSTRAINT;
}
} else {
ut_a(m_trx->check_foreigns == FALSE);
ut_a(!m_trx->check_foreigns);
index = NULL;
}
@ -12735,7 +12757,6 @@ create_table_info_t::create_foreign_keys()
NULL
if the column is not allowed to be
NULL! */
key_text k(fk);
ib_foreign_warn(
m_trx,
DB_CANNOT_ADD_CONSTRAINT,
@ -12746,9 +12767,9 @@ create_table_info_t::create_foreign_keys()
"but column '%s' is defined as "
"NOT NULL.",
operation, create_name,
k.str(), col_name);
key_text(fk).str(), col_name);
return (DB_CANNOT_ADD_CONSTRAINT);
return DB_CANNOT_ADD_CONSTRAINT;
}
}
}
@ -13596,7 +13617,7 @@ int ha_innobase::delete_table(const char *name)
if (!table && lower_case_table_names == 1 && is_partition(norm_name))
{
IF_WIN(normalize_table_name_c_low(norm_name, name, false),
innobase_casedn_str(norm_name));
my_casedn_str(system_charset_info, norm_name));
table= dict_sys.load_table(n, DICT_ERR_IGNORE_DROP);
}
#endif
@ -13903,7 +13924,8 @@ static dberr_t innobase_rename_table(trx_t *trx, const char *from,
case name, including the partition
separator "P" */
strcpy(par_case_name, norm_from);
innobase_casedn_str(par_case_name);
my_casedn_str(system_charset_info,
par_case_name);
#else
/* On Windows platfrom, check
whether there exists table name in
@ -20924,25 +20946,6 @@ const char* SET_TRANSACTION_MSG =
const char* INNODB_PARAMETERS_MSG =
"Please refer to https://mariadb.com/kb/en/library/innodb-system-variables/";
/**********************************************************************
Converts an identifier from my_charset_filename to UTF-8 charset.
@return result string length, as returned by strconvert() */
uint
innobase_convert_to_filename_charset(
/*=================================*/
char* to, /* out: converted identifier */
const char* from, /* in: identifier to convert */
ulint len) /* in: length of 'to', in bytes */
{
uint errors;
CHARSET_INFO* cs_to = &my_charset_filename;
CHARSET_INFO* cs_from = system_charset_info;
return(static_cast<uint>(strconvert(
cs_from, from, uint(strlen(from)),
cs_to, to, static_cast<uint>(len), &errors)));
}
/**********************************************************************
Converts an identifier from my_charset_filename to UTF-8 charset.
@return result string length, as returned by strconvert() */

View file

@ -30,6 +30,7 @@ Smart ALTER TABLE
#include <sql_class.h>
#include <sql_table.h>
#include <mysql/plugin.h>
#include <strfunc.h>
/* Include necessary InnoDB headers */
#include "btr0sea.h"
@ -3231,6 +3232,9 @@ innobase_get_foreign_key_info(
ulint num_fk = 0;
Alter_info* alter_info = ha_alter_info->alter_info;
const CHARSET_INFO* cs = thd_charset(trx->mysql_thd);
char db_name[MAX_DATABASE_NAME_LEN + 1];
char t_name[MAX_TABLE_NAME_LEN + 1];
static_assert(MAX_TABLE_NAME_LEN == MAX_DATABASE_NAME_LEN, "");
DBUG_ENTER("innobase_get_foreign_key_info");
@ -3295,14 +3299,15 @@ innobase_get_foreign_key_info(
add_fk[num_fk] = dict_mem_foreign_create();
LEX_CSTRING t = innodb_convert_name(cs, fk_key->ref_table,
t_name);
LEX_CSTRING d = fk_key->ref_db.str
? innodb_convert_name(cs, fk_key->ref_db, db_name)
: LEX_CSTRING{table->name.m_name, table->name.dblen()};
dict_sys.lock(SRW_LOCK_CALL);
referenced_table_name = dict_get_referenced_table(
table->name.m_name,
LEX_STRING_WITH_LEN(fk_key->ref_db),
LEX_STRING_WITH_LEN(fk_key->ref_table),
&referenced_table,
add_fk[num_fk]->heap, cs);
referenced_table_name = dict_table_lookup(
d, t, &referenced_table, add_fk[num_fk]->heap);
/* Test the case when referenced_table failed to
open, if trx->check_foreigns is not set, we should

View file

@ -55,22 +55,6 @@ inline size_t dict_get_db_name_len(const char *name)
}
/*********************************************************************//**
Open a table from its database and table name, this is currently used by
foreign constraint parser to get the referenced table.
@return complete table name with database and table name, allocated from
heap memory passed in */
char*
dict_get_referenced_table(
/*======================*/
const char* name, /*!< in: foreign key table name */
const char* database_name, /*!< in: table db name */
ulint database_name_len,/*!< in: db name length */
const char* table_name, /*!< in: table name */
ulint table_name_len, /*!< in: table name length */
dict_table_t** table, /*!< out: table object or NULL */
mem_heap_t* heap, /*!< in: heap memory */
CHARSET_INFO* from_cs); /*!< in: table name charset */
/*********************************************************************//**
Frees a foreign key struct. */
void

View file

@ -431,7 +431,7 @@ void
dict_mem_foreign_table_name_lookup_set(
/*===================================*/
dict_foreign_t* foreign, /*!< in/out: foreign struct */
ibool do_alloc); /*!< in: is an alloc needed */
bool do_alloc); /*!< in: is an alloc needed */
/**********************************************************************//**
Sets the referenced_table_name_lookup pointer based on the value of

View file

@ -110,7 +110,7 @@ struct table_name_t
table_name_t(char* name) : m_name(name) {}
/** @return the end of the schema name */
const char* dbend() const
const char* dbend() const noexcept
{
const char* sep = strchr(m_name, '/');
ut_ad(sep);
@ -118,11 +118,19 @@ struct table_name_t
}
/** @return the length of the schema name, in bytes */
size_t dblen() const { return size_t(dbend() - m_name); }
size_t dblen() const noexcept
{
const char *end= dbend();
return UNIV_LIKELY(end != nullptr) ? size_t(end - m_name) : 0;
}
/** Determine the filename-safe encoded table name.
@return the filename-safe encoded table name */
const char* basename() const { return dbend() + 1; }
const char* basename() const noexcept
{
const char *end= dbend();
return UNIV_LIKELY(end != nullptr) ? end + 1 : nullptr;
}
/** The start of the table basename suffix for partitioned tables */
static const char part_suffix[4];

View file

@ -40,6 +40,8 @@ class Field;
struct dict_table_t;
struct dict_foreign_t;
struct table_name_t;
struct mem_block_info_t;
typedef struct mem_block_info_t mem_heap_t;
// JAN: TODO missing features:
#undef MYSQL_FT_INIT_EXT
@ -156,33 +158,6 @@ const char*
innobase_basename(
const char* path_name);
/******************************************************************//**
Converts an identifier to a table name. */
void
innobase_convert_from_table_id(
/*===========================*/
CHARSET_INFO* cs, /*!< in: the 'from' character set */
char* to, /*!< out: converted identifier */
const char* from, /*!< in: identifier to convert */
ulint len); /*!< in: length of 'to', in bytes; should
be at least 5 * strlen(to) + 1 */
/******************************************************************//**
Converts an identifier to UTF-8. */
void
innobase_convert_from_id(
/*=====================*/
CHARSET_INFO* cs, /*!< in: the 'from' character set */
char* to, /*!< out: converted identifier */
const char* from, /*!< in: identifier to convert */
ulint len); /*!< in: length of 'to', in bytes;
should be at least 3 * strlen(to) + 1 */
/******************************************************************//**
Makes all characters in a NUL-terminated UTF-8 string lower case. */
void
innobase_casedn_str(
/*================*/
char* a); /*!< in/out: string to put in lower case */
#ifdef WITH_WSREP
ulint wsrep_innobase_mysql_sort(int mysql_type, uint charset_number,
unsigned char* str, ulint str_length,
@ -370,15 +345,6 @@ innobase_next_autoinc(
MY_ATTRIBUTE((pure, warn_unused_result));
/**********************************************************************
Converts an identifier from my_charset_filename to UTF-8 charset. */
uint
innobase_convert_to_system_charset(
/*===============================*/
char* to, /* out: converted identifier */
const char* from, /* in: identifier to convert */
ulint len, /* in: length of 'to', in bytes */
uint* errors); /* out: error return */
/**********************************************************************
Check if the length of the identifier exceeds the maximum allowed.
The input to this function is an identifier in charset my_charset_filename.
return true when length of identifier is too long. */
@ -398,14 +364,13 @@ innobase_convert_to_system_charset(
ulint len, /* in: length of 'to', in bytes */
uint* errors); /* out: error return */
/**********************************************************************
Converts an identifier from my_charset_filename to UTF-8 charset. */
uint
innobase_convert_to_filename_charset(
/*=================================*/
char* to, /* out: converted identifier */
const char* from, /* in: identifier to convert */
ulint len); /* in: length of 'to', in bytes */
/** Convert a schema or table name to InnoDB (and file system) format.
@param cs source character set
@param name name encoded in cs
@param buf output buffer (MAX_TABLE_NAME_LEN + 1 bytes)
@return the converted string (within buf) */
LEX_CSTRING innodb_convert_name(CHARSET_INFO *cs, LEX_CSTRING name, char *buf)
noexcept;
/** Report that a table cannot be decrypted.
@param thd connection context
@ -460,6 +425,16 @@ void destroy_background_thd(MYSQL_THD thd);
void
innobase_reset_background_thd(MYSQL_THD);
/** Open a table based on a database and table name.
@param db schema name
@param name table name within the schema
@param table table
@param heap memory heap for allocating a converted name
@return InnoDB format table name with database and table name,
allocated from heap */
char *dict_table_lookup(LEX_CSTRING db, LEX_CSTRING name,
dict_table_t **table, mem_heap_t *heap) noexcept;
#ifdef WITH_WSREP
/** Append table-level exclusive key.
@param thd MySQL thread handle

View file

@ -2608,7 +2608,7 @@ row_rename_table_for_mysql(
memcpy(par_case_name, old_name,
strlen(old_name));
par_case_name[strlen(old_name)] = 0;
innobase_casedn_str(par_case_name);
my_casedn_str(system_charset_info, par_case_name);
#else
/* On Windows platfrom, check
whether there exists table name in