MDEV-35854 dict_get_referenced_table() got too many parameters

dict_get_referenced_table(): Make the callers responsible for
converting the database and table names.
This commit is contained in:
Marko Mäkelä 2025-01-15 15:21:30 +02:00
parent d5a417b9d5
commit 301ee7bccb
4 changed files with 180 additions and 133 deletions

View file

@ -3222,66 +3222,17 @@ foreign constraint parser to get the referenced table.
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 */
LEX_CSTRING database_name, /*!< in: table db name */
LEX_CSTRING table_name, /*!< in: table name */
dict_table_t** table, /*!< out: table object or NULL */
mem_heap_t* heap) noexcept /*!< in/out: heap memory */
{
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);
const size_t len = database_name.length + table_name.length + 1;
char* ref = static_cast<char*>(mem_heap_alloc(heap, len + 1));
memcpy(ref, database_name.str, database_name.length);
ref[database_name.length] = '/';
memcpy(ref + database_name.length + 1, table_name.str,
table_name.length + 1);
/* Values; 0 = Store and compare as given; case sensitive
1 = Store and compare in lower; case insensitive
@ -3289,10 +3240,10 @@ dict_get_referenced_table(
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);
memcpy(ref, database_name.str, database_name.length);
ref[database_name.length] = '/';
memcpy(ref + database_name.length + 1,
table_name.str, table_name.length + 1);
} else {
#ifndef _WIN32
if (lower_case_table_names == 1) {

View file

@ -12404,6 +12404,8 @@ 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];
dict_index_t* index = NULL;
fkerr_t index_error = FK_SUCCESS;
dict_index_t* err_index = NULL;
@ -12411,59 +12413,84 @@ 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 table_name = m_form->s->table_name;
CHARSET_INFO* to_cs = &my_charset_filename;
if (!strncmp(table_name.str, srv_mysql50_table_name_prefix,
sizeof srv_mysql50_table_name_prefix - 1)) {
table_name.str
+= sizeof srv_mysql50_table_name_prefix - 1;
table_name.length
-= sizeof srv_mysql50_table_name_prefix - 1;
to_cs = system_charset_info;
}
uint errors;
LEX_CSTRING t;
t.str = t_name;
t.length = strconvert(cs, LEX_STRING_WITH_LEN(table_name),
to_cs, t_name, MAX_TABLE_NAME_LEN,
&errors);
LEX_CSTRING d = m_form->s->db;
if (!strncmp(d.str, srv_mysql50_table_name_prefix,
sizeof srv_mysql50_table_name_prefix - 1)) {
d.str += sizeof srv_mysql50_table_name_prefix - 1;
d.length -= sizeof srv_mysql50_table_name_prefix - 1;
to_cs = system_charset_info;
} else {
to_cs = &my_charset_filename;
}
d.length = strconvert(cs, LEX_STRING_WITH_LEN(d), to_cs,
db_name, MAX_DATABASE_NAME_LEN,
&errors);
d.str = db_name;
dict_table_t* alter_table;
char* n = dict_get_referenced_table(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;
*innobase_convert_name(create_name, sizeof create_name,
n, strlen(n), m_thd) = '\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';
*innobase_convert_name(create_name, sizeof create_name,
LEX_STRING_WITH_LEN(name), m_thd)= '\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 +12537,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 +12569,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,32 +12637,68 @@ 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);
LEX_CSTRING table_name = fk->ref_table;
CHARSET_INFO* to_cs = &my_charset_filename;
uint errors;
LEX_CSTRING t = table_name;
LEX_CSTRING d = fk->ref_db;
if (!foreign->referenced_table_name) {
return (DB_OUT_OF_MEMORY);
if (!d.str) {
d = {table->name.m_name, table->name.dblen()};
}
if (!strncmp(table_name.str, srv_mysql50_table_name_prefix,
sizeof srv_mysql50_table_name_prefix - 1)) {
table_name.str
+= sizeof srv_mysql50_table_name_prefix - 1;
table_name.length
-= sizeof srv_mysql50_table_name_prefix - 1;
to_cs = system_charset_info;
}
t.str = t_name;
t.length = strconvert(cs, LEX_STRING_WITH_LEN(table_name),
to_cs, t_name,
MAX_TABLE_NAME_LEN, &errors);
if (!strncmp(d.str, srv_mysql50_table_name_prefix,
sizeof srv_mysql50_table_name_prefix - 1)) {
d.str += sizeof srv_mysql50_table_name_prefix - 1;
d.length -= sizeof srv_mysql50_table_name_prefix - 1;
to_cs = system_charset_info;
} else if (d.str == table->name.m_name) {
goto name_converted;
} else {
to_cs = &my_charset_filename;
}
if (d.str != table->name.m_name) {
d.length = strconvert(cs, LEX_STRING_WITH_LEN(d),
to_cs, db_name,
MAX_DATABASE_NAME_LEN,
&errors);
d.str = db_name;
}
name_converted:
foreign->referenced_table_name = dict_get_referenced_table(
d, t, &foreign->referenced_table, foreign->heap);
if (!foreign->referenced_table && m_trx->check_foreigns) {
char buf[MAX_TABLE_NAME_LEN + 1] = "";
char* bufend;
bufend = innobase_convert_name(
*innobase_convert_name(
buf, MAX_TABLE_NAME_LEN,
foreign->referenced_table_name,
strlen(foreign->referenced_table_name), m_thd);
buf[bufend - buf] = '\0';
key_text k(fk);
strlen(foreign->referenced_table_name), m_thd)
= '\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 +12721,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 +12729,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 +12751,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 +12796,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 +12806,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;
}
}
}

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,8 @@ 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];
DBUG_ENTER("innobase_get_foreign_key_info");
@ -3295,14 +3298,51 @@ innobase_get_foreign_key_info(
add_fk[num_fk] = dict_mem_foreign_create();
LEX_CSTRING table_name = fk_key->ref_table;
CHARSET_INFO* to_cs = &my_charset_filename;
if (!strncmp(table_name.str, srv_mysql50_table_name_prefix,
sizeof srv_mysql50_table_name_prefix - 1)) {
table_name.str
+= sizeof srv_mysql50_table_name_prefix - 1;
table_name.length
-= sizeof srv_mysql50_table_name_prefix - 1;
to_cs = system_charset_info;
}
uint errors;
LEX_CSTRING t;
t.str = t_name;
t.length = strconvert(cs, LEX_STRING_WITH_LEN(table_name),
to_cs, t_name, MAX_TABLE_NAME_LEN,
&errors);
LEX_CSTRING d = fk_key->ref_db;
if (!d.str) {
d.str = table->name.m_name;
d.length = table->name.dblen();
}
if (!strncmp(d.str, srv_mysql50_table_name_prefix,
sizeof srv_mysql50_table_name_prefix - 1)) {
d.str += sizeof srv_mysql50_table_name_prefix - 1;
d.length -= sizeof srv_mysql50_table_name_prefix - 1;
to_cs = system_charset_info;
} else if (d.str == table->name.m_name) {
goto name_converted;
} else {
to_cs = &my_charset_filename;
}
d.length = strconvert(cs, LEX_STRING_WITH_LEN(d), to_cs,
db_name, MAX_DATABASE_NAME_LEN,
&errors);
d.str = db_name;
name_converted:
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);
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

@ -62,15 +62,11 @@ foreign constraint parser to get the referenced table.
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 */
LEX_CSTRING database_name, /*!< in: table db name */
LEX_CSTRING table_name, /*!< in: table name */
dict_table_t** table, /*!< out: table object or NULL */
mem_heap_t* heap, /*!< in: heap memory */
CHARSET_INFO* from_cs); /*!< in: table name charset */
mem_heap_t* heap) /*!< in/out: heap memory */
noexcept MY_ATTRIBUTE((nonnull));
/*********************************************************************//**
Frees a foreign key struct. */
void