mirror of
https://github.com/MariaDB/server.git
synced 2026-05-16 03:47:17 +02:00
Bug#55222 - RB://517 - Approved by Sunny
InnoDB does not attempt to handle lower_case_table_names == 2 when looking up foreign table names and referenced table name. It turned that server variable into a boolean and ignored the possibility of it being '2'. The setting lower_case_table_names == 2 means that it should be stored and displayed in mixed case as given, but compared internally in lower case. Normally the server deals with this since it stores table names. But InnoDB stores referential constraints for the server, so it needs to keep track of both lower case and given names. This solution creates two table name pointers for each foreign and referenced table name. One to display the name, and one to look it up. Both pointers point to the same allocated string unless this setting is 2. So the overhead added is not too much. Two functions are created in dict0mem.c to populate the ..._lookup versions of these pointers. Both dict_mem_foreign_table_name_lookup_set() and dict_mem_referenced_table_name_lookup_set() are called 5 times each.
This commit is contained in:
parent
54840ede9f
commit
2dde698e0e
14 changed files with 331 additions and 75 deletions
|
|
@ -52,8 +52,9 @@ UNIV_INTERN dict_index_t* dict_ind_compact;
|
|||
#include "que0que.h"
|
||||
#include "rem0cmp.h"
|
||||
#include "row0merge.h"
|
||||
#include "srv0srv.h" /* srv_lower_case_table_names */
|
||||
#include "m_ctype.h" /* my_isspace() */
|
||||
#include "ha_prototypes.h" /* innobase_strcasecmp() */
|
||||
#include "ha_prototypes.h" /* innobase_strcasecmp(), innobase_casedn_str()*/
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
|
|
@ -1080,13 +1081,13 @@ dict_table_rename_in_cache(
|
|||
/* Allocate a longer name buffer;
|
||||
TODO: store buf len to save memory */
|
||||
|
||||
foreign->foreign_table_name
|
||||
= mem_heap_alloc(foreign->heap,
|
||||
ut_strlen(table->name) + 1);
|
||||
foreign->foreign_table_name = mem_heap_strdup(
|
||||
foreign->heap, table->name);
|
||||
dict_mem_foreign_table_name_lookup_set(foreign, TRUE);
|
||||
} else {
|
||||
strcpy(foreign->foreign_table_name, table->name);
|
||||
dict_mem_foreign_table_name_lookup_set(foreign, FALSE);
|
||||
}
|
||||
|
||||
strcpy(foreign->foreign_table_name, table->name);
|
||||
|
||||
if (strchr(foreign->id, '/')) {
|
||||
ulint db_len;
|
||||
char* old_id;
|
||||
|
|
@ -1152,12 +1153,14 @@ dict_table_rename_in_cache(
|
|||
/* Allocate a longer name buffer;
|
||||
TODO: store buf len to save memory */
|
||||
|
||||
foreign->referenced_table_name = mem_heap_alloc(
|
||||
foreign->heap, strlen(table->name) + 1);
|
||||
foreign->referenced_table_name = mem_heap_strdup(
|
||||
foreign->heap, table->name);
|
||||
dict_mem_referenced_table_name_lookup_set(foreign, TRUE);
|
||||
} else {
|
||||
/* Use the same buffer */
|
||||
strcpy(foreign->referenced_table_name, table->name);
|
||||
dict_mem_referenced_table_name_lookup_set(foreign, FALSE);
|
||||
}
|
||||
|
||||
strcpy(foreign->referenced_table_name, table->name);
|
||||
|
||||
foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
|
||||
}
|
||||
|
||||
|
|
@ -2583,10 +2586,10 @@ dict_foreign_add_to_cache(
|
|||
ut_ad(mutex_own(&(dict_sys->mutex)));
|
||||
|
||||
for_table = dict_table_check_if_in_cache_low(
|
||||
foreign->foreign_table_name);
|
||||
foreign->foreign_table_name_lookup);
|
||||
|
||||
ref_table = dict_table_check_if_in_cache_low(
|
||||
foreign->referenced_table_name);
|
||||
foreign->referenced_table_name_lookup);
|
||||
ut_a(for_table || ref_table);
|
||||
|
||||
if (for_table) {
|
||||
|
|
@ -3015,19 +3018,25 @@ dict_scan_table_name(
|
|||
memcpy(ref, database_name, database_name_len);
|
||||
ref[database_name_len] = '/';
|
||||
memcpy(ref + database_name_len + 1, table_name, table_name_len + 1);
|
||||
#ifndef __WIN__
|
||||
if (srv_lower_case_table_names) {
|
||||
#endif /* !__WIN__ */
|
||||
/* The table name is always put to lower case on Windows. */
|
||||
|
||||
/* 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 (srv_lower_case_table_names == 2) {
|
||||
innobase_casedn_str(ref);
|
||||
#ifndef __WIN__
|
||||
*table = dict_table_get_low(ref);
|
||||
memcpy(ref, database_name, database_name_len);
|
||||
ref[database_name_len] = '/';
|
||||
memcpy(ref + database_name_len + 1, table_name, table_name_len + 1);
|
||||
} else {
|
||||
if (srv_lower_case_table_names == 1) {
|
||||
innobase_casedn_str(ref);
|
||||
}
|
||||
*table = dict_table_get_low(ref);
|
||||
}
|
||||
#endif /* !__WIN__ */
|
||||
|
||||
*success = TRUE;
|
||||
*ref_name = ref;
|
||||
*table = dict_table_get_low(ref);
|
||||
|
||||
return(ptr);
|
||||
}
|
||||
|
||||
|
|
@ -3516,8 +3525,10 @@ col_loop1:
|
|||
}
|
||||
|
||||
foreign->foreign_table = table;
|
||||
foreign->foreign_table_name = mem_heap_strdup(foreign->heap,
|
||||
table->name);
|
||||
foreign->foreign_table_name = mem_heap_strdup(
|
||||
foreign->heap, table->name);
|
||||
dict_mem_foreign_table_name_lookup_set(foreign, TRUE);
|
||||
|
||||
foreign->foreign_index = index;
|
||||
foreign->n_fields = (unsigned int) i;
|
||||
foreign->foreign_col_names = mem_heap_alloc(foreign->heap,
|
||||
|
|
@ -3774,8 +3785,9 @@ try_find_index:
|
|||
foreign->referenced_index = index;
|
||||
foreign->referenced_table = referenced_table;
|
||||
|
||||
foreign->referenced_table_name
|
||||
= mem_heap_strdup(foreign->heap, referenced_table_name);
|
||||
foreign->referenced_table_name = mem_heap_strdup(
|
||||
foreign->heap, referenced_table_name);
|
||||
dict_mem_referenced_table_name_lookup_set(foreign, TRUE);
|
||||
|
||||
foreign->referenced_col_names = mem_heap_alloc(foreign->heap,
|
||||
i * sizeof(void*));
|
||||
|
|
@ -4586,8 +4598,8 @@ dict_print_info_on_foreign_key_in_create_format(
|
|||
|
||||
fputs(") REFERENCES ", file);
|
||||
|
||||
if (dict_tables_have_same_db(foreign->foreign_table_name,
|
||||
foreign->referenced_table_name)) {
|
||||
if (dict_tables_have_same_db(foreign->foreign_table_name_lookup,
|
||||
foreign->referenced_table_name_lookup)) {
|
||||
/* Do not print the database name of the referenced table */
|
||||
ut_print_name(file, trx, TRUE,
|
||||
dict_remove_db_name(
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ Created 4/24/1996 Heikki Tuuri
|
|||
#include "rem0cmp.h"
|
||||
#include "srv0start.h"
|
||||
#include "srv0srv.h"
|
||||
#include "ha_prototypes.h" /* innobase_casedn_str() */
|
||||
|
||||
|
||||
/** Following are six InnoDB system tables */
|
||||
|
|
@ -435,6 +436,8 @@ dict_process_sys_fields_rec(
|
|||
return(err_msg);
|
||||
|
||||
}
|
||||
|
||||
#ifdef FOREIGN_NOT_USED
|
||||
/********************************************************************//**
|
||||
This function parses a SYS_FOREIGN record and populate a dict_foreign_t
|
||||
structure with the information from the record. For detail information
|
||||
|
|
@ -483,13 +486,16 @@ err_len:
|
|||
}
|
||||
foreign->foreign_table_name = mem_heap_strdupl(
|
||||
heap, (const char*) field, len);
|
||||
dict_mem_foreign_table_name_lookup_set(foreign, TRUE);
|
||||
|
||||
field = rec_get_nth_field_old(rec, 4/*REF_NAME*/, &len);
|
||||
if (UNIV_UNLIKELY(len < 1 || len == UNIV_SQL_NULL)) {
|
||||
goto err_len;
|
||||
}
|
||||
|
||||
foreign->referenced_table_name = mem_heap_strdupl(
|
||||
heap, (const char*) field, len);
|
||||
dict_mem_referenced_table_name_lookup_set(foreign, TRUE);
|
||||
|
||||
field = rec_get_nth_field_old(rec, 5/*N_COLS*/, &len);
|
||||
if (UNIV_UNLIKELY(len != 4)) {
|
||||
|
|
@ -502,6 +508,9 @@ err_len:
|
|||
|
||||
return(NULL);
|
||||
}
|
||||
#endif /* FOREIGN_NOT_USED */
|
||||
|
||||
#ifdef FOREIGN_NOT_USED
|
||||
/********************************************************************//**
|
||||
This function parses a SYS_FOREIGN_COLS record and extract necessary
|
||||
information from the record and return to caller.
|
||||
|
|
@ -565,6 +574,8 @@ err_len:
|
|||
|
||||
return(NULL);
|
||||
}
|
||||
#endif /* FOREIGN_NOT_USED */
|
||||
|
||||
/********************************************************************//**
|
||||
Determine the flags of a table described in SYS_TABLES.
|
||||
@return compressed page size in kilobytes; or 0 if the tablespace is
|
||||
|
|
@ -2057,12 +2068,15 @@ dict_load_foreign(
|
|||
foreign->id = mem_heap_strdup(foreign->heap, id);
|
||||
|
||||
field = rec_get_nth_field_old(rec, 3, &len);
|
||||
|
||||
foreign->foreign_table_name = mem_heap_strdupl(
|
||||
foreign->heap, (char*) field, len);
|
||||
dict_mem_foreign_table_name_lookup_set(foreign, TRUE);
|
||||
|
||||
field = rec_get_nth_field_old(rec, 4, &len);
|
||||
foreign->referenced_table_name = mem_heap_strdupl(
|
||||
foreign->heap, (char*) field, len);
|
||||
dict_mem_referenced_table_name_lookup_set(foreign, TRUE);
|
||||
|
||||
btr_pcur_close(&pcur);
|
||||
mtr_commit(&mtr);
|
||||
|
|
@ -2070,7 +2084,7 @@ dict_load_foreign(
|
|||
dict_load_foreign_cols(id, foreign);
|
||||
|
||||
ref_table = dict_table_check_if_in_cache_low(
|
||||
foreign->referenced_table_name);
|
||||
foreign->referenced_table_name_lookup);
|
||||
|
||||
/* We could possibly wind up in a deep recursive calls if
|
||||
we call dict_table_get_low() again here if there
|
||||
|
|
@ -2103,7 +2117,7 @@ dict_load_foreign(
|
|||
have to load it so that we are able to make type comparisons
|
||||
in the next function call. */
|
||||
|
||||
for_table = dict_table_get_low(foreign->foreign_table_name);
|
||||
for_table = dict_table_get_low(foreign->foreign_table_name_lookup);
|
||||
|
||||
if (for_table && ref_table && check_recursive) {
|
||||
/* This is to record the longest chain of ancesters
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ Created 1/8/1996 Heikki Tuuri
|
|||
#include "data0type.h"
|
||||
#include "mach0data.h"
|
||||
#include "dict0dict.h"
|
||||
#include "srv0srv.h" /* srv_lower_case_table_names */
|
||||
#ifndef UNIV_HOTBACKUP
|
||||
# include "lock0lock.h"
|
||||
#endif /* !UNIV_HOTBACKUP */
|
||||
|
|
@ -287,6 +288,60 @@ dict_mem_foreign_create(void)
|
|||
return(foreign);
|
||||
}
|
||||
|
||||
/**********************************************************************//**
|
||||
Sets the foreign_table_name_lookup pointer based on the value of
|
||||
srv_lower_case_table_names. If that is 0 or 1, foreign_table_name_lookup
|
||||
will point to foreign_table_name. If 2, then another string is allocated
|
||||
of the heap and set to lower case. */
|
||||
UNIV_INLINE
|
||||
void
|
||||
dict_mem_foreign_table_name_lookup_set(
|
||||
/*===================================*/
|
||||
dict_foreign_t* foreign, /*!< in/out: foreign struct */
|
||||
ibool do_alloc) /*!< in: is an alloc needed */
|
||||
{
|
||||
if (srv_lower_case_table_names == 2) {
|
||||
if (do_alloc) {
|
||||
foreign->foreign_table_name_lookup = mem_heap_alloc(
|
||||
foreign->heap,
|
||||
strlen(foreign->foreign_table_name) + 1);
|
||||
}
|
||||
strcpy(foreign->foreign_table_name_lookup,
|
||||
foreign->foreign_table_name);
|
||||
innobase_casedn_str(foreign->foreign_table_name_lookup);
|
||||
} else {
|
||||
foreign->foreign_table_name_lookup
|
||||
= foreign->foreign_table_name;
|
||||
}
|
||||
}
|
||||
|
||||
/**********************************************************************//**
|
||||
Sets the referenced_table_name_lookup pointer based on the value of
|
||||
srv_lower_case_table_names. If that is 0 or 1,
|
||||
referenced_table_name_lookup will point to referenced_table_name. If 2,
|
||||
then another string is allocated of the heap and set to lower case. */
|
||||
UNIV_INLINE
|
||||
void
|
||||
dict_mem_referenced_table_name_lookup_set(
|
||||
/*======================================*/
|
||||
dict_foreign_t* foreign, /*!< in/out: foreign struct */
|
||||
ibool do_alloc) /*!< in: is an alloc needed */
|
||||
{
|
||||
if (srv_lower_case_table_names == 2) {
|
||||
if (do_alloc) {
|
||||
foreign->referenced_table_name_lookup = mem_heap_alloc(
|
||||
foreign->heap,
|
||||
strlen(foreign->referenced_table_name) + 1);
|
||||
}
|
||||
strcpy(foreign->referenced_table_name_lookup,
|
||||
foreign->referenced_table_name);
|
||||
innobase_casedn_str(foreign->referenced_table_name_lookup);
|
||||
} else {
|
||||
foreign->referenced_table_name_lookup
|
||||
= foreign->referenced_table_name;
|
||||
}
|
||||
}
|
||||
|
||||
/**********************************************************************//**
|
||||
Adds a field definition to an index. NOTE: does not take a copy
|
||||
of the column name if the field is a column. The memory occupied
|
||||
|
|
|
|||
|
|
@ -3639,6 +3639,7 @@ ha_innobase::open(
|
|||
UT_NOT_USED(test_if_locked);
|
||||
|
||||
thd = ha_thd();
|
||||
srv_lower_case_table_names = lower_case_table_names;
|
||||
|
||||
/* Under some cases MySQL seems to call this function while
|
||||
holding btr_search_latch. This breaks the latching order as
|
||||
|
|
@ -6750,11 +6751,7 @@ ha_innobase::create(
|
|||
|
||||
trx = innobase_trx_allocate(thd);
|
||||
|
||||
if (lower_case_table_names) {
|
||||
srv_lower_case_table_names = TRUE;
|
||||
} else {
|
||||
srv_lower_case_table_names = FALSE;
|
||||
}
|
||||
srv_lower_case_table_names = lower_case_table_names;
|
||||
|
||||
strcpy(name2, name);
|
||||
|
||||
|
|
@ -7179,11 +7176,7 @@ ha_innobase::delete_table(
|
|||
|
||||
trx = innobase_trx_allocate(thd);
|
||||
|
||||
if (lower_case_table_names) {
|
||||
srv_lower_case_table_names = TRUE;
|
||||
} else {
|
||||
srv_lower_case_table_names = FALSE;
|
||||
}
|
||||
srv_lower_case_table_names = lower_case_table_names;
|
||||
|
||||
name_len = strlen(name);
|
||||
|
||||
|
|
@ -7306,11 +7299,7 @@ innobase_rename_table(
|
|||
char* norm_to;
|
||||
char* norm_from;
|
||||
|
||||
if (lower_case_table_names) {
|
||||
srv_lower_case_table_names = TRUE;
|
||||
} else {
|
||||
srv_lower_case_table_names = FALSE;
|
||||
}
|
||||
srv_lower_case_table_names = lower_case_table_names;
|
||||
|
||||
// Magic number 64 arbitrary
|
||||
norm_to = (char*) my_malloc(strlen(to) + 64, MYF(0));
|
||||
|
|
|
|||
|
|
@ -238,6 +238,26 @@ dict_foreign_t*
|
|||
dict_mem_foreign_create(void);
|
||||
/*=========================*/
|
||||
|
||||
/**********************************************************************//**
|
||||
Sets the foreign_table_name_lookup pointer based on the value of
|
||||
srv_lower_case_table_names. */
|
||||
UNIV_INTERN
|
||||
void
|
||||
dict_mem_foreign_table_name_lookup_set(
|
||||
/*===================================*/
|
||||
dict_foreign_t* foreign, /*!< in/out: foreign struct */
|
||||
ibool do_alloc); /*!< in: is an alloc needed */
|
||||
|
||||
/**********************************************************************//**
|
||||
Sets the reference_table_name_lookup pointer based on the value of
|
||||
srv_lower_case_table_names. */
|
||||
UNIV_INTERN
|
||||
void
|
||||
dict_mem_referenced_table_name_lookup_set(
|
||||
/*======================================*/
|
||||
dict_foreign_t* foreign, /*!< in/out: foreign struct */
|
||||
ibool do_alloc); /*!< in: is an alloc needed */
|
||||
|
||||
/** Data structure for a column in a table */
|
||||
struct dict_col_struct{
|
||||
/*----------------------*/
|
||||
|
|
@ -393,10 +413,14 @@ struct dict_foreign_struct{
|
|||
unsigned type:6; /*!< 0 or DICT_FOREIGN_ON_DELETE_CASCADE
|
||||
or DICT_FOREIGN_ON_DELETE_SET_NULL */
|
||||
char* foreign_table_name;/*!< foreign table name */
|
||||
char* foreign_table_name_lookup;
|
||||
/*!< foreign table name used for dict lookup */
|
||||
dict_table_t* foreign_table; /*!< table where the foreign key is */
|
||||
const char** foreign_col_names;/*!< names of the columns in the
|
||||
foreign key */
|
||||
char* referenced_table_name;/*!< referenced table name */
|
||||
char* referenced_table_name_lookup;
|
||||
/*!< referenced table name for dict lookup*/
|
||||
dict_table_t* referenced_table;/*!< table where the referenced key
|
||||
is */
|
||||
const char** referenced_col_names;/*!< names of the referenced
|
||||
|
|
|
|||
|
|
@ -71,8 +71,8 @@ at a time */
|
|||
#define SRV_AUTO_EXTEND_INCREMENT \
|
||||
(srv_auto_extend_increment * ((1024 * 1024) / UNIV_PAGE_SIZE))
|
||||
|
||||
/* This is set to TRUE if the MySQL user has set it in MySQL */
|
||||
extern ibool srv_lower_case_table_names;
|
||||
/* This is set to the MySQL server value for this variable. */
|
||||
extern uint srv_lower_case_table_names;
|
||||
|
||||
/* Mutex for locking srv_monitor_file */
|
||||
extern mutex_t srv_monitor_file_mutex;
|
||||
|
|
|
|||
|
|
@ -1525,7 +1525,7 @@ row_ins_check_foreign_constraints(
|
|||
if (foreign->foreign_index == index) {
|
||||
|
||||
if (foreign->referenced_table == NULL) {
|
||||
dict_table_get(foreign->referenced_table_name,
|
||||
dict_table_get(foreign->referenced_table_name_lookup,
|
||||
FALSE);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3163,7 +3163,7 @@ check_next_foreign:
|
|||
|
||||
if (foreign && trx->check_foreigns
|
||||
&& !(drop_db && dict_tables_have_same_db(
|
||||
name, foreign->foreign_table_name))) {
|
||||
name, foreign->foreign_table_name_lookup))) {
|
||||
FILE* ef = dict_foreign_err_file;
|
||||
|
||||
/* We only allow dropping a referenced table if
|
||||
|
|
|
|||
|
|
@ -238,7 +238,7 @@ row_upd_check_references_constraints(
|
|||
foreign->n_fields))) {
|
||||
|
||||
if (foreign->foreign_table == NULL) {
|
||||
dict_table_get(foreign->foreign_table_name,
|
||||
dict_table_get(foreign->foreign_table_name_lookup,
|
||||
FALSE);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -87,9 +87,11 @@ Created 10/8/1995 Heikki Tuuri
|
|||
#include "mysql/plugin.h"
|
||||
#include "mysql/service_thd_wait.h"
|
||||
|
||||
/* This is set to TRUE if the MySQL user has set it in MySQL; currently
|
||||
affects only FOREIGN KEY definition parsing */
|
||||
UNIV_INTERN ibool srv_lower_case_table_names = FALSE;
|
||||
/* This is set to the MySQL server value for this variable. It is only
|
||||
needed for FOREIGN KEY definition parsing since FOREIGN KEY names are not
|
||||
stored in the server metadata. The server stores and enforces it for
|
||||
regular database and table names.*/
|
||||
UNIV_INTERN uint srv_lower_case_table_names = 0;
|
||||
|
||||
/* The following counter is incremented whenever there is some user activity
|
||||
in the server */
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue