mirror of
https://github.com/MariaDB/server.git
synced 2026-05-16 03:47:17 +02:00
Many files:
Merge InnoDB-4.0.13; DROP FOREIGN KEY now works innobase/buf/buf0flu.c: Merge InnoDB-4.0.13; DROP FOREIGN KEY now works innobase/dict/dict0crea.c: Merge InnoDB-4.0.13; DROP FOREIGN KEY now works innobase/dict/dict0dict.c: Merge InnoDB-4.0.13; DROP FOREIGN KEY now works innobase/dict/dict0load.c: Merge InnoDB-4.0.13; DROP FOREIGN KEY now works innobase/ibuf/ibuf0ibuf.c: Merge InnoDB-4.0.13; DROP FOREIGN KEY now works innobase/include/db0err.h: Merge InnoDB-4.0.13; DROP FOREIGN KEY now works innobase/include/dict0dict.h: Merge InnoDB-4.0.13; DROP FOREIGN KEY now works innobase/include/row0ins.h: Merge InnoDB-4.0.13; DROP FOREIGN KEY now works innobase/lock/lock0lock.c: Merge InnoDB-4.0.13; DROP FOREIGN KEY now works innobase/os/os0file.c: Merge InnoDB-4.0.13; DROP FOREIGN KEY now works innobase/row/row0ins.c: Merge InnoDB-4.0.13; DROP FOREIGN KEY now works innobase/row/row0mysql.c: Merge InnoDB-4.0.13; DROP FOREIGN KEY now works innobase/row/row0sel.c: Merge InnoDB-4.0.13; DROP FOREIGN KEY now works innobase/row/row0upd.c: Merge InnoDB-4.0.13; DROP FOREIGN KEY now works innobase/srv/srv0srv.c: Merge InnoDB-4.0.13; DROP FOREIGN KEY now works innobase/ut/ut0ut.c: Merge InnoDB-4.0.13; DROP FOREIGN KEY now works sql/ha_innodb.cc: Merge InnoDB-4.0.13; DROP FOREIGN KEY now works
This commit is contained in:
parent
07c29cc91a
commit
33ac47279b
17 changed files with 999 additions and 205 deletions
|
|
@ -106,7 +106,7 @@ buf_flush_ready_for_replace(
|
||||||
BUF_BLOCK_FILE_PAGE and in the LRU list*/
|
BUF_BLOCK_FILE_PAGE and in the LRU list*/
|
||||||
{
|
{
|
||||||
ut_ad(mutex_own(&(buf_pool->mutex)));
|
ut_ad(mutex_own(&(buf_pool->mutex)));
|
||||||
ut_ad(block->state == BUF_BLOCK_FILE_PAGE);
|
ut_a(block->state == BUF_BLOCK_FILE_PAGE);
|
||||||
|
|
||||||
if ((ut_dulint_cmp(block->oldest_modification, ut_dulint_zero) > 0)
|
if ((ut_dulint_cmp(block->oldest_modification, ut_dulint_zero) > 0)
|
||||||
|| (block->buf_fix_count != 0)
|
|| (block->buf_fix_count != 0)
|
||||||
|
|
@ -227,7 +227,9 @@ buf_flush_buffered_writes(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < trx_doublewrite->first_free; i++) {
|
for (i = 0; i < trx_doublewrite->first_free; i++) {
|
||||||
|
|
||||||
block = trx_doublewrite->buf_block_arr[i];
|
block = trx_doublewrite->buf_block_arr[i];
|
||||||
|
ut_a(block->state == BUF_BLOCK_FILE_PAGE);
|
||||||
|
|
||||||
if (block->check_index_page_at_flush
|
if (block->check_index_page_at_flush
|
||||||
&& !page_simple_validate(block->frame)) {
|
&& !page_simple_validate(block->frame)) {
|
||||||
|
|
@ -236,10 +238,12 @@ buf_flush_buffered_writes(void)
|
||||||
|
|
||||||
ut_print_timestamp(stderr);
|
ut_print_timestamp(stderr);
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
" InnoDB: Apparent corruption of an index page\n"
|
" InnoDB: Apparent corruption of an index page n:o %lu in space %lu\n"
|
||||||
"InnoDB: to be written to data file. We intentionally crash server\n"
|
"InnoDB: to be written to data file. We intentionally crash server\n"
|
||||||
"InnoDB: to prevent corrupt data from ending up in data\n"
|
"InnoDB: to prevent corrupt data from ending up in data\n"
|
||||||
"InnoDB: files.\n");
|
"InnoDB: files.\n",
|
||||||
|
block->offset, block->space);
|
||||||
|
|
||||||
ut_a(0);
|
ut_a(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -432,6 +436,8 @@ buf_flush_try_page(
|
||||||
|
|
||||||
block = buf_page_hash_get(space, offset);
|
block = buf_page_hash_get(space, offset);
|
||||||
|
|
||||||
|
ut_a(block->state == BUF_BLOCK_FILE_PAGE);
|
||||||
|
|
||||||
if (flush_type == BUF_FLUSH_LIST
|
if (flush_type == BUF_FLUSH_LIST
|
||||||
&& block && buf_flush_ready_for_flush(block, flush_type)) {
|
&& block && buf_flush_ready_for_flush(block, flush_type)) {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1173,6 +1173,7 @@ dict_create_add_foreigns_to_dictionary(
|
||||||
if (NULL == dict_table_get_low((char *) "SYS_FOREIGN")) {
|
if (NULL == dict_table_get_low((char *) "SYS_FOREIGN")) {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"InnoDB: table SYS_FOREIGN not found from internal data dictionary\n");
|
"InnoDB: table SYS_FOREIGN not found from internal data dictionary\n");
|
||||||
|
|
||||||
return(DB_ERROR);
|
return(DB_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1259,6 +1260,13 @@ loop:
|
||||||
"InnoDB: at http://www.innodb.com/ibman.html\n");
|
"InnoDB: at http://www.innodb.com/ibman.html\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mutex_enter(&dict_foreign_err_mutex);
|
||||||
|
ut_sprintf_timestamp(buf);
|
||||||
|
sprintf(buf + strlen(buf),
|
||||||
|
" Internal error in foreign key constraint creation for table %.500s.\n"
|
||||||
|
"See the MySQL .err log in the datadir for more information.\n", table->name);
|
||||||
|
mutex_exit(&dict_foreign_err_mutex);
|
||||||
|
|
||||||
return(error);
|
return(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -185,6 +185,12 @@ dict_foreign_free(
|
||||||
/*==============*/
|
/*==============*/
|
||||||
dict_foreign_t* foreign); /* in, own: foreign key struct */
|
dict_foreign_t* foreign); /* in, own: foreign key struct */
|
||||||
|
|
||||||
|
/* Buffer for storing detailed information about the latest foreig key
|
||||||
|
error */
|
||||||
|
char* dict_foreign_err_buf = NULL;
|
||||||
|
mutex_t dict_foreign_err_mutex; /* mutex protecting the buffer */
|
||||||
|
|
||||||
|
|
||||||
/************************************************************************
|
/************************************************************************
|
||||||
Checks if the database name in two table names is the same. */
|
Checks if the database name in two table names is the same. */
|
||||||
static
|
static
|
||||||
|
|
@ -573,6 +579,11 @@ dict_init(void)
|
||||||
|
|
||||||
rw_lock_create(&dict_operation_lock);
|
rw_lock_create(&dict_operation_lock);
|
||||||
rw_lock_set_level(&dict_operation_lock, SYNC_DICT_OPERATION);
|
rw_lock_set_level(&dict_operation_lock, SYNC_DICT_OPERATION);
|
||||||
|
|
||||||
|
dict_foreign_err_buf = mem_alloc(DICT_FOREIGN_ERR_BUF_LEN);
|
||||||
|
dict_foreign_err_buf[0] = '\0';
|
||||||
|
mutex_create(&dict_foreign_err_mutex);
|
||||||
|
mutex_set_level(&dict_foreign_err_mutex, SYNC_ANY_LATCH);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**************************************************************************
|
/**************************************************************************
|
||||||
|
|
@ -1818,6 +1829,7 @@ dict_foreign_add_to_cache(
|
||||||
dict_foreign_t* for_in_cache = NULL;
|
dict_foreign_t* for_in_cache = NULL;
|
||||||
dict_index_t* index;
|
dict_index_t* index;
|
||||||
ibool added_to_referenced_list = FALSE;
|
ibool added_to_referenced_list = FALSE;
|
||||||
|
char* buf = dict_foreign_err_buf;
|
||||||
|
|
||||||
ut_ad(mutex_own(&(dict_sys->mutex)));
|
ut_ad(mutex_own(&(dict_sys->mutex)));
|
||||||
|
|
||||||
|
|
@ -1850,9 +1862,29 @@ dict_foreign_add_to_cache(
|
||||||
for_in_cache->foreign_index);
|
for_in_cache->foreign_index);
|
||||||
|
|
||||||
if (index == NULL) {
|
if (index == NULL) {
|
||||||
|
mutex_enter(&dict_foreign_err_mutex);
|
||||||
|
ut_sprintf_timestamp(buf);
|
||||||
|
sprintf(buf + strlen(buf),
|
||||||
|
" Error in foreign key constraint of table %.500s:\n"
|
||||||
|
"there is no index in referenced table which would contain\n"
|
||||||
|
"the columns as the first columns, or the data types in the\n"
|
||||||
|
"referenced table do not match to the ones in table. Constraint:\n",
|
||||||
|
for_in_cache->foreign_table_name);
|
||||||
|
dict_print_info_on_foreign_key_in_create_format(
|
||||||
|
for_in_cache, buf + strlen(buf));
|
||||||
|
if (for_in_cache->foreign_index) {
|
||||||
|
sprintf(buf + strlen(buf),
|
||||||
|
"\nThe index in the foreign key in table is %.500s\n"
|
||||||
|
"See http://www.innodb.com/ibman.html about correct foreign key definition.\n",
|
||||||
|
for_in_cache->foreign_index->name);
|
||||||
|
}
|
||||||
|
ut_a(strlen(buf) < DICT_FOREIGN_ERR_BUF_LEN);
|
||||||
|
mutex_exit(&dict_foreign_err_mutex);
|
||||||
|
|
||||||
if (for_in_cache == foreign) {
|
if (for_in_cache == foreign) {
|
||||||
mem_heap_free(foreign->heap);
|
mem_heap_free(foreign->heap);
|
||||||
}
|
}
|
||||||
|
|
||||||
return(DB_CANNOT_ADD_CONSTRAINT);
|
return(DB_CANNOT_ADD_CONSTRAINT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1871,6 +1903,25 @@ dict_foreign_add_to_cache(
|
||||||
for_in_cache->referenced_index);
|
for_in_cache->referenced_index);
|
||||||
|
|
||||||
if (index == NULL) {
|
if (index == NULL) {
|
||||||
|
mutex_enter(&dict_foreign_err_mutex);
|
||||||
|
ut_sprintf_timestamp(buf);
|
||||||
|
sprintf(buf + strlen(buf),
|
||||||
|
" Error in foreign key constraint of table %.500s:\n"
|
||||||
|
"there is no index in the table which would contain\n"
|
||||||
|
"the columns as the first columns, or the data types in the\n"
|
||||||
|
"table do not match to the ones in the referenced table. Constraint:\n",
|
||||||
|
for_in_cache->foreign_table_name);
|
||||||
|
dict_print_info_on_foreign_key_in_create_format(
|
||||||
|
for_in_cache, buf + strlen(buf));
|
||||||
|
if (for_in_cache->foreign_index) {
|
||||||
|
sprintf(buf + strlen(buf),
|
||||||
|
"\nIndex of the foreign key in the referenced table is %.500s\n"
|
||||||
|
"See http://www.innodb.com/ibman.html about correct foreign key definition.\n",
|
||||||
|
for_in_cache->referenced_index->name);
|
||||||
|
}
|
||||||
|
ut_a(strlen(buf) < DICT_FOREIGN_ERR_BUF_LEN);
|
||||||
|
mutex_exit(&dict_foreign_err_mutex);
|
||||||
|
|
||||||
if (for_in_cache == foreign) {
|
if (for_in_cache == foreign) {
|
||||||
if (added_to_referenced_list) {
|
if (added_to_referenced_list) {
|
||||||
UT_LIST_REMOVE(referenced_list,
|
UT_LIST_REMOVE(referenced_list,
|
||||||
|
|
@ -2038,7 +2089,7 @@ dict_scan_col(
|
||||||
if (*ptr == '`') {
|
if (*ptr == '`') {
|
||||||
ptr++;
|
ptr++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return(ptr);
|
return(ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2141,18 +2192,21 @@ dict_scan_table_name(
|
||||||
}
|
}
|
||||||
|
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
Skips one 'word', like an id. For the lexical definition of 'word', see the
|
Scans an id. For the lexical definition of an 'id', see the code below.
|
||||||
code below. */
|
Strips backquotes from around the id. */
|
||||||
static
|
static
|
||||||
char*
|
char*
|
||||||
dict_skip_word(
|
dict_scan_id(
|
||||||
/*===========*/
|
/*=========*/
|
||||||
/* out: scanned to */
|
/* out: scanned to */
|
||||||
char* ptr, /* in: scanned to */
|
char* ptr, /* in: scanned to */
|
||||||
ibool* success)/* out: TRUE if success, FALSE if just spaces left in
|
char** start, /* out: start of the id; NULL if no id was
|
||||||
string */
|
scannable */
|
||||||
|
ulint* len) /* out: length of the id */
|
||||||
{
|
{
|
||||||
*success = FALSE;
|
ibool scanned_backquote = FALSE;
|
||||||
|
|
||||||
|
*start = NULL;
|
||||||
|
|
||||||
while (isspace(*ptr)) {
|
while (isspace(*ptr)) {
|
||||||
ptr++;
|
ptr++;
|
||||||
|
|
@ -2164,20 +2218,58 @@ dict_skip_word(
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*ptr == '`') {
|
if (*ptr == '`') {
|
||||||
|
scanned_backquote = TRUE;
|
||||||
ptr++;
|
ptr++;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (!isspace(*ptr) && *ptr != ',' && *ptr != '(' && *ptr != '`'
|
*start = ptr;
|
||||||
&& *ptr != '\0') {
|
|
||||||
|
while (!isspace(*ptr) && *ptr != ',' && *ptr != '(' && *ptr != ')'
|
||||||
|
&& *ptr != '\0' && *ptr != '`') {
|
||||||
|
|
||||||
ptr++;
|
ptr++;
|
||||||
}
|
}
|
||||||
|
|
||||||
*success = TRUE;
|
*len = (ulint) (ptr - *start);
|
||||||
|
|
||||||
|
if (scanned_backquote) {
|
||||||
|
if (*ptr == '`') {
|
||||||
|
ptr++;
|
||||||
|
} else {
|
||||||
|
/* Syntax error */
|
||||||
|
*start = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return(ptr);
|
return(ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
Skips one id. */
|
||||||
|
static
|
||||||
|
char*
|
||||||
|
dict_skip_word(
|
||||||
|
/*===========*/
|
||||||
|
/* out: scanned to */
|
||||||
|
char* ptr, /* in: scanned to */
|
||||||
|
ibool* success)/* out: TRUE if success, FALSE if just spaces left in
|
||||||
|
string or a syntax error */
|
||||||
|
{
|
||||||
|
char* start;
|
||||||
|
ulint len;
|
||||||
|
|
||||||
|
*success = FALSE;
|
||||||
|
|
||||||
|
ptr = dict_scan_id(ptr, &start, &len);
|
||||||
|
|
||||||
|
if (start) {
|
||||||
|
*success = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef currentlynotused
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
Returns the number of opening brackets '(' subtracted by the number
|
Returns the number of opening brackets '(' subtracted by the number
|
||||||
of closing brackets ')' between string and ptr. */
|
of closing brackets ')' between string and ptr. */
|
||||||
|
|
@ -2204,6 +2296,106 @@ dict_bracket_count(
|
||||||
|
|
||||||
return(count);
|
return(count);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
Removes MySQL comments from an SQL string. A comment is either
|
||||||
|
(a) '#' to the end of the line,
|
||||||
|
(b) '--<space>' to the end of the line, or
|
||||||
|
(c) '<slash><asterisk>' till the next '<asterisk><slash>' (like the familiar
|
||||||
|
C comment syntax). */
|
||||||
|
static
|
||||||
|
char*
|
||||||
|
dict_strip_comments(
|
||||||
|
/*================*/
|
||||||
|
/* out, own: SQL string stripped from
|
||||||
|
comments; the caller must free this
|
||||||
|
with mem_free()! */
|
||||||
|
char* sql_string) /* in: SQL string */
|
||||||
|
{
|
||||||
|
char* str;
|
||||||
|
char* sptr;
|
||||||
|
char* ptr;
|
||||||
|
|
||||||
|
str = mem_alloc(strlen(sql_string) + 1);
|
||||||
|
|
||||||
|
sptr = sql_string;
|
||||||
|
ptr = str;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
if (*sptr == '\0') {
|
||||||
|
*ptr = '\0';
|
||||||
|
|
||||||
|
return(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*sptr == '#'
|
||||||
|
|| (strlen(sptr) >= 3 && 0 == memcmp("-- ", sptr, 3))) {
|
||||||
|
for (;;) {
|
||||||
|
/* In Unix a newline is 0x0D while in Windows
|
||||||
|
it is 0x0A followed by 0x0D */
|
||||||
|
|
||||||
|
if (*sptr == (char)0x0A
|
||||||
|
|| *sptr == (char)0x0D
|
||||||
|
|| *sptr == '\0') {
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
sptr++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strlen(sptr) >= 2 && *sptr == '/' && *(sptr + 1) == '*') {
|
||||||
|
for (;;) {
|
||||||
|
if (strlen(sptr) >= 2
|
||||||
|
&& *sptr == '*' && *(sptr + 1) == '/') {
|
||||||
|
|
||||||
|
sptr += 2;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*sptr == '\0') {
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
sptr++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*ptr = *sptr;
|
||||||
|
|
||||||
|
ptr++;
|
||||||
|
sptr++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
Reports a simple foreign key create clause syntax error. */
|
||||||
|
static
|
||||||
|
void
|
||||||
|
dict_foreign_report_syntax_err(
|
||||||
|
/*===========================*/
|
||||||
|
char* name, /* in: table name */
|
||||||
|
char* start_of_latest_foreign,/* in: start of the foreign key clause
|
||||||
|
in the SQL string */
|
||||||
|
char* ptr) /* in: place of the syntax error */
|
||||||
|
{
|
||||||
|
char* buf = dict_foreign_err_buf;
|
||||||
|
|
||||||
|
mutex_enter(&dict_foreign_err_mutex);
|
||||||
|
|
||||||
|
ut_sprintf_timestamp(buf);
|
||||||
|
|
||||||
|
sprintf(buf + strlen(buf),
|
||||||
|
" Error in foreign key constraint of table %.500s,\n%.500s.\n"
|
||||||
|
"Syntax error close to:\n%.500s\n", name, start_of_latest_foreign, ptr);
|
||||||
|
|
||||||
|
ut_a(strlen(buf) < DICT_FOREIGN_ERR_BUF_LEN);
|
||||||
|
mutex_exit(&dict_foreign_err_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
Scans a table create SQL string and adds to the data dictionary the foreign
|
Scans a table create SQL string and adds to the data dictionary the foreign
|
||||||
|
|
@ -2211,10 +2403,10 @@ key constraints declared in the string. This function should be called after
|
||||||
the indexes for a table have been created. Each foreign key constraint must
|
the indexes for a table have been created. Each foreign key constraint must
|
||||||
be accompanied with indexes in both participating tables. The indexes are
|
be accompanied with indexes in both participating tables. The indexes are
|
||||||
allowed to contain more fields than mentioned in the constraint. */
|
allowed to contain more fields than mentioned in the constraint. */
|
||||||
|
static
|
||||||
ulint
|
ulint
|
||||||
dict_create_foreign_constraints(
|
dict_create_foreign_constraints_low(
|
||||||
/*============================*/
|
/*================================*/
|
||||||
/* out: error code or DB_SUCCESS */
|
/* out: error code or DB_SUCCESS */
|
||||||
trx_t* trx, /* in: transaction */
|
trx_t* trx, /* in: transaction */
|
||||||
char* sql_string, /* in: table create or ALTER TABLE
|
char* sql_string, /* in: table create or ALTER TABLE
|
||||||
|
|
@ -2230,7 +2422,9 @@ dict_create_foreign_constraints(
|
||||||
dict_table_t* referenced_table;
|
dict_table_t* referenced_table;
|
||||||
dict_index_t* index;
|
dict_index_t* index;
|
||||||
dict_foreign_t* foreign;
|
dict_foreign_t* foreign;
|
||||||
char* ptr = sql_string;
|
char* ptr = sql_string;
|
||||||
|
char* start_of_latest_foreign = sql_string;
|
||||||
|
char* buf = dict_foreign_err_buf;
|
||||||
ibool success;
|
ibool success;
|
||||||
ulint error;
|
ulint error;
|
||||||
ulint i;
|
ulint i;
|
||||||
|
|
@ -2248,6 +2442,15 @@ dict_create_foreign_constraints(
|
||||||
table = dict_table_get_low(name);
|
table = dict_table_get_low(name);
|
||||||
|
|
||||||
if (table == NULL) {
|
if (table == NULL) {
|
||||||
|
mutex_enter(&dict_foreign_err_mutex);
|
||||||
|
ut_sprintf_timestamp(buf);
|
||||||
|
sprintf(buf + strlen(buf),
|
||||||
|
" Error in foreign key constraint of table %.500s.\n"
|
||||||
|
"Cannot find the table from the internal data dictionary of InnoDB.\n"
|
||||||
|
"Create table statement:\n%.2000\n", name, sql_string);
|
||||||
|
ut_a(strlen(buf) < DICT_FOREIGN_ERR_BUF_LEN);
|
||||||
|
mutex_exit(&dict_foreign_err_mutex);
|
||||||
|
|
||||||
return(DB_ERROR);
|
return(DB_ERROR);
|
||||||
}
|
}
|
||||||
loop:
|
loop:
|
||||||
|
|
@ -2263,6 +2466,8 @@ loop:
|
||||||
return(error);
|
return(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
start_of_latest_foreign = ptr;
|
||||||
|
|
||||||
ptr = dict_accept(ptr, (char *) "FOREIGN", &success);
|
ptr = dict_accept(ptr, (char *) "FOREIGN", &success);
|
||||||
|
|
||||||
if (!isspace(*ptr)) {
|
if (!isspace(*ptr)) {
|
||||||
|
|
@ -2283,13 +2488,19 @@ loop:
|
||||||
ptr = dict_skip_word(ptr, &success);
|
ptr = dict_skip_word(ptr, &success);
|
||||||
|
|
||||||
if (!success) {
|
if (!success) {
|
||||||
|
dict_foreign_report_syntax_err(name,
|
||||||
|
start_of_latest_foreign, ptr);
|
||||||
|
|
||||||
return(DB_CANNOT_ADD_CONSTRAINT);
|
return(DB_CANNOT_ADD_CONSTRAINT);
|
||||||
}
|
}
|
||||||
|
|
||||||
ptr = dict_accept(ptr, (char *) "(", &success);
|
ptr = dict_accept(ptr, (char *) "(", &success);
|
||||||
|
|
||||||
if (!success) {
|
if (!success) {
|
||||||
return(DB_CANNOT_ADD_CONSTRAINT);
|
/* We do not flag a syntax error here because in an
|
||||||
|
ALTER TABLE we may also have DROP FOREIGN KEY abc */
|
||||||
|
|
||||||
|
goto loop;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2300,6 +2511,15 @@ col_loop1:
|
||||||
ptr = dict_scan_col(ptr, &success, table, columns + i,
|
ptr = dict_scan_col(ptr, &success, table, columns + i,
|
||||||
column_names + i, column_name_lens + i);
|
column_names + i, column_name_lens + i);
|
||||||
if (!success) {
|
if (!success) {
|
||||||
|
mutex_enter(&dict_foreign_err_mutex);
|
||||||
|
ut_sprintf_timestamp(buf);
|
||||||
|
sprintf(buf + strlen(buf),
|
||||||
|
" Error in foreign key constraint of table %.500s,\n%.500s.\n"
|
||||||
|
"Cannot resolve column name close to:\n%.500s\n", name,
|
||||||
|
start_of_latest_foreign, ptr);
|
||||||
|
ut_a(strlen(buf) < DICT_FOREIGN_ERR_BUF_LEN);
|
||||||
|
mutex_exit(&dict_foreign_err_mutex);
|
||||||
|
|
||||||
return(DB_CANNOT_ADD_CONSTRAINT);
|
return(DB_CANNOT_ADD_CONSTRAINT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2314,6 +2534,8 @@ col_loop1:
|
||||||
ptr = dict_accept(ptr, (char *) ")", &success);
|
ptr = dict_accept(ptr, (char *) ")", &success);
|
||||||
|
|
||||||
if (!success) {
|
if (!success) {
|
||||||
|
dict_foreign_report_syntax_err(name, start_of_latest_foreign,
|
||||||
|
ptr);
|
||||||
return(DB_CANNOT_ADD_CONSTRAINT);
|
return(DB_CANNOT_ADD_CONSTRAINT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2323,12 +2545,24 @@ col_loop1:
|
||||||
index = dict_foreign_find_index(table, column_names, i, NULL);
|
index = dict_foreign_find_index(table, column_names, i, NULL);
|
||||||
|
|
||||||
if (!index) {
|
if (!index) {
|
||||||
|
mutex_enter(&dict_foreign_err_mutex);
|
||||||
|
ut_sprintf_timestamp(buf);
|
||||||
|
sprintf(buf + strlen(buf),
|
||||||
|
" Error in foreign key constraint of table %.500s:\n"
|
||||||
|
"There is no index in the table %.500s where the columns appear\n"
|
||||||
|
"as the first columns. Constraint:\n%.500s\n"
|
||||||
|
"See http://www.innodb.com/ibman.html for correct foreign key definition.\n",
|
||||||
|
name, name, start_of_latest_foreign);
|
||||||
|
ut_a(strlen(buf) < DICT_FOREIGN_ERR_BUF_LEN);
|
||||||
|
mutex_exit(&dict_foreign_err_mutex);
|
||||||
|
|
||||||
return(DB_CANNOT_ADD_CONSTRAINT);
|
return(DB_CANNOT_ADD_CONSTRAINT);
|
||||||
}
|
}
|
||||||
|
|
||||||
ptr = dict_accept(ptr, (char *) "REFERENCES", &success);
|
ptr = dict_accept(ptr, (char *) "REFERENCES", &success);
|
||||||
|
|
||||||
if (!success || !isspace(*ptr)) {
|
if (!success || !isspace(*ptr)) {
|
||||||
|
dict_foreign_report_syntax_err(name, start_of_latest_foreign,
|
||||||
|
ptr);
|
||||||
return(DB_CANNOT_ADD_CONSTRAINT);
|
return(DB_CANNOT_ADD_CONSTRAINT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2358,6 +2592,15 @@ col_loop1:
|
||||||
if (!success || (!referenced_table && trx->check_foreigns)) {
|
if (!success || (!referenced_table && trx->check_foreigns)) {
|
||||||
dict_foreign_free(foreign);
|
dict_foreign_free(foreign);
|
||||||
|
|
||||||
|
mutex_enter(&dict_foreign_err_mutex);
|
||||||
|
ut_sprintf_timestamp(buf);
|
||||||
|
sprintf(buf + strlen(buf),
|
||||||
|
" Error in foreign key constraint of table %.500s,\n%.500s.\n"
|
||||||
|
"Cannot resolve table name close to:\n"
|
||||||
|
"%.500s\n", name, start_of_latest_foreign, ptr);
|
||||||
|
ut_a(strlen(buf) < DICT_FOREIGN_ERR_BUF_LEN);
|
||||||
|
mutex_exit(&dict_foreign_err_mutex);
|
||||||
|
|
||||||
return(DB_CANNOT_ADD_CONSTRAINT);
|
return(DB_CANNOT_ADD_CONSTRAINT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2365,7 +2608,8 @@ col_loop1:
|
||||||
|
|
||||||
if (!success) {
|
if (!success) {
|
||||||
dict_foreign_free(foreign);
|
dict_foreign_free(foreign);
|
||||||
|
dict_foreign_report_syntax_err(name, start_of_latest_foreign,
|
||||||
|
ptr);
|
||||||
return(DB_CANNOT_ADD_CONSTRAINT);
|
return(DB_CANNOT_ADD_CONSTRAINT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2380,6 +2624,15 @@ col_loop2:
|
||||||
if (!success) {
|
if (!success) {
|
||||||
dict_foreign_free(foreign);
|
dict_foreign_free(foreign);
|
||||||
|
|
||||||
|
mutex_enter(&dict_foreign_err_mutex);
|
||||||
|
ut_sprintf_timestamp(buf);
|
||||||
|
sprintf(buf + strlen(buf),
|
||||||
|
" Error in foreign key constraint of table %.500s,\n%.500s\n"
|
||||||
|
"Cannot resolve column name close to:\n"
|
||||||
|
"%.500s\n", name, start_of_latest_foreign, ptr);
|
||||||
|
ut_a(strlen(buf) < DICT_FOREIGN_ERR_BUF_LEN);
|
||||||
|
mutex_exit(&dict_foreign_err_mutex);
|
||||||
|
|
||||||
return(DB_CANNOT_ADD_CONSTRAINT);
|
return(DB_CANNOT_ADD_CONSTRAINT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2394,6 +2647,8 @@ col_loop2:
|
||||||
if (!success || foreign->n_fields != i) {
|
if (!success || foreign->n_fields != i) {
|
||||||
dict_foreign_free(foreign);
|
dict_foreign_free(foreign);
|
||||||
|
|
||||||
|
dict_foreign_report_syntax_err(name, start_of_latest_foreign,
|
||||||
|
ptr);
|
||||||
return(DB_CANNOT_ADD_CONSTRAINT);
|
return(DB_CANNOT_ADD_CONSTRAINT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2416,9 +2671,10 @@ scan_on_conditions:
|
||||||
ptr = dict_accept(ptr, "UPDATE", &success);
|
ptr = dict_accept(ptr, "UPDATE", &success);
|
||||||
|
|
||||||
if (!success) {
|
if (!success) {
|
||||||
|
|
||||||
dict_foreign_free(foreign);
|
dict_foreign_free(foreign);
|
||||||
|
|
||||||
|
dict_foreign_report_syntax_err(name,
|
||||||
|
start_of_latest_foreign, ptr);
|
||||||
return(DB_CANNOT_ADD_CONSTRAINT);
|
return(DB_CANNOT_ADD_CONSTRAINT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2454,6 +2710,8 @@ scan_on_conditions:
|
||||||
|
|
||||||
if (!success) {
|
if (!success) {
|
||||||
dict_foreign_free(foreign);
|
dict_foreign_free(foreign);
|
||||||
|
dict_foreign_report_syntax_err(name,
|
||||||
|
start_of_latest_foreign, ptr);
|
||||||
|
|
||||||
return(DB_CANNOT_ADD_CONSTRAINT);
|
return(DB_CANNOT_ADD_CONSTRAINT);
|
||||||
}
|
}
|
||||||
|
|
@ -2471,7 +2729,8 @@ scan_on_conditions:
|
||||||
|
|
||||||
if (!success) {
|
if (!success) {
|
||||||
dict_foreign_free(foreign);
|
dict_foreign_free(foreign);
|
||||||
|
dict_foreign_report_syntax_err(name, start_of_latest_foreign,
|
||||||
|
ptr);
|
||||||
return(DB_CANNOT_ADD_CONSTRAINT);
|
return(DB_CANNOT_ADD_CONSTRAINT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2479,7 +2738,8 @@ scan_on_conditions:
|
||||||
|
|
||||||
if (!success) {
|
if (!success) {
|
||||||
dict_foreign_free(foreign);
|
dict_foreign_free(foreign);
|
||||||
|
dict_foreign_report_syntax_err(name, start_of_latest_foreign,
|
||||||
|
ptr);
|
||||||
return(DB_CANNOT_ADD_CONSTRAINT);
|
return(DB_CANNOT_ADD_CONSTRAINT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2493,6 +2753,15 @@ scan_on_conditions:
|
||||||
|
|
||||||
dict_foreign_free(foreign);
|
dict_foreign_free(foreign);
|
||||||
|
|
||||||
|
mutex_enter(&dict_foreign_err_mutex);
|
||||||
|
ut_sprintf_timestamp(buf);
|
||||||
|
sprintf(buf + strlen(buf),
|
||||||
|
" Error in foreign key constraint of table %.500s,\n%.500s.\n"
|
||||||
|
"You have defined a SET NULL condition though some of the\n"
|
||||||
|
"columns is defined as NOT NULL.\n", name, start_of_latest_foreign);
|
||||||
|
ut_a(strlen(buf) < DICT_FOREIGN_ERR_BUF_LEN);
|
||||||
|
mutex_exit(&dict_foreign_err_mutex);
|
||||||
|
|
||||||
return(DB_CANNOT_ADD_CONSTRAINT);
|
return(DB_CANNOT_ADD_CONSTRAINT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2511,6 +2780,15 @@ try_find_index:
|
||||||
|
|
||||||
dict_foreign_free(foreign);
|
dict_foreign_free(foreign);
|
||||||
|
|
||||||
|
mutex_enter(&dict_foreign_err_mutex);
|
||||||
|
ut_sprintf_timestamp(buf);
|
||||||
|
sprintf(buf + strlen(buf),
|
||||||
|
" Error in foreign key constraint of table %.500s,\n%.500s.\n"
|
||||||
|
"You have twice an ON DELETE clause or twice an ON UPDATE clause.\n",
|
||||||
|
name, start_of_latest_foreign);
|
||||||
|
ut_a(strlen(buf) < DICT_FOREIGN_ERR_BUF_LEN);
|
||||||
|
mutex_exit(&dict_foreign_err_mutex);
|
||||||
|
|
||||||
return(DB_CANNOT_ADD_CONSTRAINT);
|
return(DB_CANNOT_ADD_CONSTRAINT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2524,6 +2802,18 @@ try_find_index:
|
||||||
foreign->foreign_index);
|
foreign->foreign_index);
|
||||||
if (!index) {
|
if (!index) {
|
||||||
dict_foreign_free(foreign);
|
dict_foreign_free(foreign);
|
||||||
|
mutex_enter(&dict_foreign_err_mutex);
|
||||||
|
ut_sprintf_timestamp(buf);
|
||||||
|
sprintf(buf + strlen(buf),
|
||||||
|
" Error in foreign key constraint of table %.500s:\n"
|
||||||
|
"Cannot find an index in the referenced table where the\n"
|
||||||
|
"referenced columns appear as the first columns, or column types\n"
|
||||||
|
"in the table and the referenced table do not match for constraint:\n%.500s\n"
|
||||||
|
"See http://www.innodb.com/ibman.html for correct foreign key definition.\n",
|
||||||
|
name, start_of_latest_foreign);
|
||||||
|
ut_a(strlen(buf) < DICT_FOREIGN_ERR_BUF_LEN);
|
||||||
|
mutex_exit(&dict_foreign_err_mutex);
|
||||||
|
|
||||||
return(DB_CANNOT_ADD_CONSTRAINT);
|
return(DB_CANNOT_ADD_CONSTRAINT);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -2564,6 +2854,165 @@ try_find_index:
|
||||||
goto loop;
|
goto loop;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
Scans a table create SQL string and adds to the data dictionary the foreign
|
||||||
|
key constraints declared in the string. This function should be called after
|
||||||
|
the indexes for a table have been created. Each foreign key constraint must
|
||||||
|
be accompanied with indexes in both participating tables. The indexes are
|
||||||
|
allowed to contain more fields than mentioned in the constraint. */
|
||||||
|
|
||||||
|
ulint
|
||||||
|
dict_create_foreign_constraints(
|
||||||
|
/*============================*/
|
||||||
|
/* out: error code or DB_SUCCESS */
|
||||||
|
trx_t* trx, /* in: transaction */
|
||||||
|
char* sql_string, /* in: table create or ALTER TABLE
|
||||||
|
statement where foreign keys are declared like:
|
||||||
|
FOREIGN KEY (a, b) REFERENCES table2(c, d),
|
||||||
|
table2 can be written also with the database
|
||||||
|
name before it: test.table2; the default
|
||||||
|
database id the database of parameter name */
|
||||||
|
char* name) /* in: table full name in the normalized form
|
||||||
|
database_name/table_name */
|
||||||
|
{
|
||||||
|
char* str;
|
||||||
|
ulint err;
|
||||||
|
|
||||||
|
str = dict_strip_comments(sql_string);
|
||||||
|
|
||||||
|
err = dict_create_foreign_constraints_low(trx, str, name);
|
||||||
|
|
||||||
|
mem_free(str);
|
||||||
|
|
||||||
|
return(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
Parses the CONSTRAINT id's to be dropped in an ALTER TABLE statement. */
|
||||||
|
|
||||||
|
ulint
|
||||||
|
dict_foreign_parse_drop_constraints(
|
||||||
|
/*================================*/
|
||||||
|
/* out: DB_SUCCESS or
|
||||||
|
DB_CANNOT_DROP_CONSTRAINT if
|
||||||
|
syntax error or the constraint
|
||||||
|
id does not match */
|
||||||
|
mem_heap_t* heap, /* in: heap from which we can
|
||||||
|
allocate memory */
|
||||||
|
trx_t* trx, /* in: transaction */
|
||||||
|
dict_table_t* table, /* in: table */
|
||||||
|
ulint* n, /* out: number of constraints
|
||||||
|
to drop */
|
||||||
|
char*** constraints_to_drop) /* out: id's of the
|
||||||
|
constraints to drop */
|
||||||
|
{
|
||||||
|
dict_foreign_t* foreign;
|
||||||
|
ibool success;
|
||||||
|
char* str;
|
||||||
|
char* ptr;
|
||||||
|
char* buf = dict_foreign_err_buf;
|
||||||
|
char* start;
|
||||||
|
char* id;
|
||||||
|
ulint len;
|
||||||
|
|
||||||
|
*n = 0;
|
||||||
|
|
||||||
|
*constraints_to_drop = mem_heap_alloc(heap, 1000 * sizeof(char*));
|
||||||
|
|
||||||
|
str = dict_strip_comments(*(trx->mysql_query_str));
|
||||||
|
ptr = str;
|
||||||
|
|
||||||
|
ut_ad(mutex_own(&(dict_sys->mutex)));
|
||||||
|
loop:
|
||||||
|
ptr = dict_scan_to(ptr, (char *) "DROP");
|
||||||
|
|
||||||
|
if (*ptr == '\0') {
|
||||||
|
ut_a(*n < 1000);
|
||||||
|
|
||||||
|
mem_free(str);
|
||||||
|
|
||||||
|
return(DB_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
ptr = dict_accept(ptr, (char *) "DROP", &success);
|
||||||
|
|
||||||
|
if (!isspace(*ptr)) {
|
||||||
|
|
||||||
|
goto loop;
|
||||||
|
}
|
||||||
|
|
||||||
|
ptr = dict_accept(ptr, (char *) "FOREIGN", &success);
|
||||||
|
|
||||||
|
if (!success) {
|
||||||
|
|
||||||
|
goto loop;
|
||||||
|
}
|
||||||
|
|
||||||
|
ptr = dict_accept(ptr, (char *) "KEY", &success);
|
||||||
|
|
||||||
|
if (!success) {
|
||||||
|
|
||||||
|
goto syntax_error;
|
||||||
|
}
|
||||||
|
|
||||||
|
ptr = dict_scan_id(ptr, &start, &len);
|
||||||
|
|
||||||
|
if (start == NULL) {
|
||||||
|
|
||||||
|
goto syntax_error;
|
||||||
|
}
|
||||||
|
|
||||||
|
id = mem_heap_alloc(heap, len + 1);
|
||||||
|
ut_memcpy(id, start, len);
|
||||||
|
id[len] = '\0';
|
||||||
|
(*constraints_to_drop)[*n] = id;
|
||||||
|
(*n)++;
|
||||||
|
|
||||||
|
/* Look for the given constraint id */
|
||||||
|
|
||||||
|
foreign = UT_LIST_GET_FIRST(table->foreign_list);
|
||||||
|
|
||||||
|
while (foreign != NULL) {
|
||||||
|
if (0 == ut_strcmp(foreign->id, id)) {
|
||||||
|
|
||||||
|
/* Found */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (foreign == NULL) {
|
||||||
|
mutex_enter(&dict_foreign_err_mutex);
|
||||||
|
ut_sprintf_timestamp(buf);
|
||||||
|
sprintf(buf + strlen(buf),
|
||||||
|
" Error in dropping of a foreign key constraint of table %.500s,\n"
|
||||||
|
"just before:\n%s\n in SQL command\n%s\nCannot find a constraint with the\n"
|
||||||
|
"given id %s.\n", table->name, ptr, str, id);
|
||||||
|
ut_a(strlen(buf) < DICT_FOREIGN_ERR_BUF_LEN);
|
||||||
|
mutex_exit(&dict_foreign_err_mutex);
|
||||||
|
|
||||||
|
mem_free(str);
|
||||||
|
|
||||||
|
return(DB_CANNOT_DROP_CONSTRAINT);
|
||||||
|
}
|
||||||
|
|
||||||
|
goto loop;
|
||||||
|
|
||||||
|
syntax_error:
|
||||||
|
mutex_enter(&dict_foreign_err_mutex);
|
||||||
|
ut_sprintf_timestamp(buf);
|
||||||
|
sprintf(buf + strlen(buf),
|
||||||
|
" Syntax error in dropping of a foreign key constraint of table %.500s,\n"
|
||||||
|
"close to:\n%s\n in SQL command\n%s\n", table->name, ptr, str);
|
||||||
|
ut_a(strlen(buf) < DICT_FOREIGN_ERR_BUF_LEN);
|
||||||
|
mutex_exit(&dict_foreign_err_mutex);
|
||||||
|
|
||||||
|
mem_free(str);
|
||||||
|
|
||||||
|
return(DB_CANNOT_DROP_CONSTRAINT);
|
||||||
|
}
|
||||||
|
|
||||||
/*==================== END OF FOREIGN KEY PROCESSING ====================*/
|
/*==================== END OF FOREIGN KEY PROCESSING ====================*/
|
||||||
|
|
||||||
/**************************************************************************
|
/**************************************************************************
|
||||||
|
|
@ -3285,7 +3734,6 @@ dict_index_print_low(
|
||||||
n_vals = index->stat_n_diff_key_vals[1];
|
n_vals = index->stat_n_diff_key_vals[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
printf(
|
printf(
|
||||||
" INDEX: name %s, table name %s, id %lu %lu, fields %lu/%lu, type %lu\n",
|
" INDEX: name %s, table name %s, id %lu %lu, fields %lu/%lu, type %lu\n",
|
||||||
index->name, index->table_name,
|
index->name, index->table_name,
|
||||||
|
|
@ -3326,6 +3774,99 @@ dict_field_print_low(
|
||||||
printf(" %s", field->name);
|
printf(" %s", field->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
Sprintfs to a string info on a foreign key of a table in a format suitable
|
||||||
|
for CREATE TABLE. */
|
||||||
|
|
||||||
|
char*
|
||||||
|
dict_print_info_on_foreign_key_in_create_format(
|
||||||
|
/*============================================*/
|
||||||
|
/* out: how far in buf we printed */
|
||||||
|
dict_foreign_t* foreign,/* in: foreign key constraint */
|
||||||
|
char* buf) /* in: buffer of at least 5000 bytes */
|
||||||
|
{
|
||||||
|
char* buf2 = buf;
|
||||||
|
ulint i;
|
||||||
|
|
||||||
|
buf2 += sprintf(buf2, ",\n CONSTRAINT `%s` FOREIGN KEY (",
|
||||||
|
foreign->id);
|
||||||
|
for (i = 0; i < foreign->n_fields; i++) {
|
||||||
|
if ((ulint)(buf2 - buf) >= 4000) {
|
||||||
|
|
||||||
|
goto no_space;
|
||||||
|
}
|
||||||
|
buf2 += sprintf(buf2, "`%.250s`",
|
||||||
|
foreign->foreign_col_names[i]);
|
||||||
|
|
||||||
|
if (i + 1 < foreign->n_fields) {
|
||||||
|
buf2 += sprintf(buf2, ", ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dict_tables_have_same_db(foreign->foreign_table_name,
|
||||||
|
foreign->referenced_table_name)) {
|
||||||
|
/* Do not print the database name of the referenced
|
||||||
|
table */
|
||||||
|
buf2 += sprintf(buf2, ") REFERENCES `%.500s` (",
|
||||||
|
dict_remove_db_name(
|
||||||
|
foreign->referenced_table_name));
|
||||||
|
} else {
|
||||||
|
buf2 += sprintf(buf2, ") REFERENCES `%.500s` (",
|
||||||
|
foreign->referenced_table_name);
|
||||||
|
/* Change the '/' in the table name to '.' */
|
||||||
|
|
||||||
|
for (i = ut_strlen(buf); i > 0; i--) {
|
||||||
|
if (buf[i] == '/') {
|
||||||
|
|
||||||
|
buf[i] = '.';
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < foreign->n_fields; i++) {
|
||||||
|
if ((ulint)(buf2 - buf) >= 4000) {
|
||||||
|
|
||||||
|
goto no_space;
|
||||||
|
}
|
||||||
|
buf2 += sprintf(buf2, "`%.250s`",
|
||||||
|
foreign->referenced_col_names[i]);
|
||||||
|
if (i + 1 < foreign->n_fields) {
|
||||||
|
buf2 += sprintf(buf2, ", ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
buf2 += sprintf(buf2, ")");
|
||||||
|
|
||||||
|
if (foreign->type & DICT_FOREIGN_ON_DELETE_CASCADE) {
|
||||||
|
buf2 += sprintf(buf2, " ON DELETE CASCADE");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (foreign->type & DICT_FOREIGN_ON_DELETE_SET_NULL) {
|
||||||
|
buf2 += sprintf(buf2, " ON DELETE SET NULL");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (foreign->type & DICT_FOREIGN_ON_DELETE_NO_ACTION) {
|
||||||
|
buf2 += sprintf(buf2, " ON DELETE NO ACTION");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (foreign->type & DICT_FOREIGN_ON_UPDATE_CASCADE) {
|
||||||
|
buf2 += sprintf(buf2, " ON UPDATE CASCADE");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (foreign->type & DICT_FOREIGN_ON_UPDATE_SET_NULL) {
|
||||||
|
buf2 += sprintf(buf2, " ON UPDATE SET NULL");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (foreign->type & DICT_FOREIGN_ON_UPDATE_NO_ACTION) {
|
||||||
|
buf2 += sprintf(buf2, " ON UPDATE NO ACTION");
|
||||||
|
}
|
||||||
|
|
||||||
|
no_space:
|
||||||
|
return(buf2);
|
||||||
|
}
|
||||||
|
|
||||||
/**************************************************************************
|
/**************************************************************************
|
||||||
Sprintfs to a string info on foreign keys of a table in a format suitable
|
Sprintfs to a string info on foreign keys of a table in a format suitable
|
||||||
for CREATE TABLE. */
|
for CREATE TABLE. */
|
||||||
|
|
@ -3335,13 +3876,12 @@ dict_print_info_on_foreign_keys_in_create_format(
|
||||||
/*=============================================*/
|
/*=============================================*/
|
||||||
char* buf, /* in: auxiliary buffer */
|
char* buf, /* in: auxiliary buffer */
|
||||||
char* str, /* in/out: pointer to a string */
|
char* str, /* in/out: pointer to a string */
|
||||||
ulint len, /* in: str has to be a buffer at least
|
ulint len, /* in: buf has to be a buffer of at least
|
||||||
len + 5000 bytes */
|
len + 5000 bytes; str must have at least
|
||||||
|
len + 1 bytes */
|
||||||
dict_table_t* table) /* in: table */
|
dict_table_t* table) /* in: table */
|
||||||
{
|
{
|
||||||
|
|
||||||
dict_foreign_t* foreign;
|
dict_foreign_t* foreign;
|
||||||
ulint i;
|
|
||||||
char* buf2;
|
char* buf2;
|
||||||
|
|
||||||
buf2 = buf;
|
buf2 = buf;
|
||||||
|
|
@ -3357,78 +3897,12 @@ dict_print_info_on_foreign_keys_in_create_format(
|
||||||
}
|
}
|
||||||
|
|
||||||
while (foreign != NULL) {
|
while (foreign != NULL) {
|
||||||
buf2 += sprintf(buf2, ",\n FOREIGN KEY (");
|
if ((ulint)(buf2 - buf) >= len) {
|
||||||
|
goto no_space;
|
||||||
|
}
|
||||||
|
|
||||||
for (i = 0; i < foreign->n_fields; i++) {
|
buf2 = dict_print_info_on_foreign_key_in_create_format(
|
||||||
if ((ulint)(buf2 - buf) >= len) {
|
foreign, buf2);
|
||||||
goto no_space;
|
|
||||||
}
|
|
||||||
buf2 += sprintf(buf2, "`%s`",
|
|
||||||
foreign->foreign_col_names[i]);
|
|
||||||
|
|
||||||
if (i + 1 < foreign->n_fields) {
|
|
||||||
buf2 += sprintf(buf2, ", ");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dict_tables_have_same_db(table->name,
|
|
||||||
foreign->referenced_table_name)) {
|
|
||||||
/* Do not print the database name of the referenced
|
|
||||||
table */
|
|
||||||
buf2 += sprintf(buf2, ") REFERENCES `%s` (",
|
|
||||||
dict_remove_db_name(
|
|
||||||
foreign->referenced_table_name));
|
|
||||||
} else {
|
|
||||||
buf2 += sprintf(buf2, ") REFERENCES `%s` (",
|
|
||||||
foreign->referenced_table_name);
|
|
||||||
/* Change the '/' in the table name to '.' */
|
|
||||||
|
|
||||||
for (i = ut_strlen(buf); i > 0; i--) {
|
|
||||||
if (buf[i] == '/') {
|
|
||||||
|
|
||||||
buf[i] = '.';
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < foreign->n_fields; i++) {
|
|
||||||
if ((ulint)(buf2 - buf) >= len) {
|
|
||||||
goto no_space;
|
|
||||||
}
|
|
||||||
buf2 += sprintf(buf2, "`%s`",
|
|
||||||
foreign->referenced_col_names[i]);
|
|
||||||
if (i + 1 < foreign->n_fields) {
|
|
||||||
buf2 += sprintf(buf2, ", ");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
buf2 += sprintf(buf2, ")");
|
|
||||||
|
|
||||||
if (foreign->type & DICT_FOREIGN_ON_DELETE_CASCADE) {
|
|
||||||
buf2 += sprintf(buf2, " ON DELETE CASCADE");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (foreign->type & DICT_FOREIGN_ON_DELETE_SET_NULL) {
|
|
||||||
buf2 += sprintf(buf2, " ON DELETE SET NULL");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (foreign->type & DICT_FOREIGN_ON_DELETE_NO_ACTION) {
|
|
||||||
buf2 += sprintf(buf2, " ON DELETE NO ACTION");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (foreign->type & DICT_FOREIGN_ON_UPDATE_CASCADE) {
|
|
||||||
buf2 += sprintf(buf2, " ON UPDATE CASCADE");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (foreign->type & DICT_FOREIGN_ON_UPDATE_SET_NULL) {
|
|
||||||
buf2 += sprintf(buf2, " ON UPDATE SET NULL");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (foreign->type & DICT_FOREIGN_ON_UPDATE_NO_ACTION) {
|
|
||||||
buf2 += sprintf(buf2, " ON UPDATE NO ACTION");
|
|
||||||
}
|
|
||||||
|
|
||||||
foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
|
foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
|
||||||
}
|
}
|
||||||
|
|
@ -3489,7 +3963,7 @@ dict_print_info_on_foreign_keys(
|
||||||
goto no_space;
|
goto no_space;
|
||||||
}
|
}
|
||||||
|
|
||||||
buf2 += sprintf(buf2, "%s",
|
buf2 += sprintf(buf2, "%.500s",
|
||||||
foreign->foreign_col_names[i]);
|
foreign->foreign_col_names[i]);
|
||||||
|
|
||||||
if (i + 1 < foreign->n_fields) {
|
if (i + 1 < foreign->n_fields) {
|
||||||
|
|
@ -3497,14 +3971,14 @@ dict_print_info_on_foreign_keys(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
buf2 += sprintf(buf2, ") REFER %s(",
|
buf2 += sprintf(buf2, ") REFER %.500s(",
|
||||||
foreign->referenced_table_name);
|
foreign->referenced_table_name);
|
||||||
|
|
||||||
for (i = 0; i < foreign->n_fields; i++) {
|
for (i = 0; i < foreign->n_fields; i++) {
|
||||||
if ((ulint)(buf2 - buf) >= len) {
|
if ((ulint)(buf2 - buf) >= len) {
|
||||||
goto no_space;
|
goto no_space;
|
||||||
}
|
}
|
||||||
buf2 += sprintf(buf2, "%s",
|
buf2 += sprintf(buf2, "%.500s",
|
||||||
foreign->referenced_col_names[i]);
|
foreign->referenced_col_names[i]);
|
||||||
if (i + 1 < foreign->n_fields) {
|
if (i + 1 < foreign->n_fields) {
|
||||||
buf2 += sprintf(buf2, " ");
|
buf2 += sprintf(buf2, " ");
|
||||||
|
|
|
||||||
|
|
@ -456,7 +456,7 @@ dict_load_indexes(
|
||||||
ut_ad(len == 8);
|
ut_ad(len == 8);
|
||||||
id = mach_read_from_8(field);
|
id = mach_read_from_8(field);
|
||||||
|
|
||||||
ut_a(0 == ut_strcmp("NAME",
|
ut_a(0 == ut_strcmp((char*)"NAME",
|
||||||
dict_field_get_col(
|
dict_field_get_col(
|
||||||
dict_index_get_nth_field(
|
dict_index_get_nth_field(
|
||||||
dict_table_get_first_index(sys_indexes), 4))->name));
|
dict_table_get_first_index(sys_indexes), 4))->name));
|
||||||
|
|
@ -515,7 +515,7 @@ dict_load_indexes(
|
||||||
&& ((type & DICT_CLUSTERED)
|
&& ((type & DICT_CLUSTERED)
|
||||||
|| ((table == dict_sys->sys_tables)
|
|| ((table == dict_sys->sys_tables)
|
||||||
&& (name_len == ut_strlen("ID_IND"))
|
&& (name_len == ut_strlen("ID_IND"))
|
||||||
&& (0 == ut_memcmp(name_buf, "ID_IND",
|
&& (0 == ut_memcmp(name_buf, (char*)"ID_IND",
|
||||||
name_len))))) {
|
name_len))))) {
|
||||||
|
|
||||||
/* The index was created in memory already in
|
/* The index was created in memory already in
|
||||||
|
|
@ -566,6 +566,7 @@ dict_load_table(
|
||||||
char* buf;
|
char* buf;
|
||||||
ulint space;
|
ulint space;
|
||||||
ulint n_cols;
|
ulint n_cols;
|
||||||
|
ulint err;
|
||||||
mtr_t mtr;
|
mtr_t mtr;
|
||||||
|
|
||||||
ut_ad(mutex_own(&(dict_sys->mutex)));
|
ut_ad(mutex_own(&(dict_sys->mutex)));
|
||||||
|
|
@ -674,8 +675,25 @@ dict_load_table(
|
||||||
|
|
||||||
dict_load_indexes(table, heap);
|
dict_load_indexes(table, heap);
|
||||||
|
|
||||||
ut_a(DB_SUCCESS == dict_load_foreigns(table->name));
|
err = dict_load_foreigns(table->name);
|
||||||
|
/*
|
||||||
|
if (err != DB_SUCCESS) {
|
||||||
|
|
||||||
|
mutex_enter(&dict_foreign_err_mutex);
|
||||||
|
|
||||||
|
ut_print_timestamp(stderr);
|
||||||
|
|
||||||
|
fprintf(stderr,
|
||||||
|
" InnoDB: Error: could not make a foreign key definition to match\n"
|
||||||
|
"InnoDB: the foreign key table or the referenced table!\n"
|
||||||
|
"InnoDB: The data dictionary of InnoDB is corrupt. You may need to drop\n"
|
||||||
|
"InnoDB: and recreate the foreign key table or the referenced table.\n"
|
||||||
|
"InnoDB: Send a detailed bug report to mysql@lists.mysql.com\n"
|
||||||
|
"InnoDB: Latest foreign key error printout:\n%s\n", dict_foreign_err_buf);
|
||||||
|
|
||||||
|
mutex_exit(&dict_foreign_err_mutex);
|
||||||
|
}
|
||||||
|
*/
|
||||||
mem_heap_free(heap);
|
mem_heap_free(heap);
|
||||||
|
|
||||||
return(table);
|
return(table);
|
||||||
|
|
@ -978,8 +996,8 @@ dict_load_foreign(
|
||||||
|
|
||||||
field = rec_get_nth_field(rec, 4, &len);
|
field = rec_get_nth_field(rec, 4, &len);
|
||||||
|
|
||||||
foreign->referenced_table_name = mem_heap_alloc(foreign->heap, 1 + len);
|
foreign->referenced_table_name = mem_heap_alloc(foreign->heap,
|
||||||
|
1 + len);
|
||||||
ut_memcpy(foreign->referenced_table_name, field, len);
|
ut_memcpy(foreign->referenced_table_name, field, len);
|
||||||
foreign->referenced_table_name[len] = '\0';
|
foreign->referenced_table_name[len] = '\0';
|
||||||
|
|
||||||
|
|
@ -988,10 +1006,19 @@ dict_load_foreign(
|
||||||
|
|
||||||
dict_load_foreign_cols(id, foreign);
|
dict_load_foreign_cols(id, foreign);
|
||||||
|
|
||||||
|
/* If the foreign table is not yet in the dictionary cache, we
|
||||||
|
have to load it so that we are able to make type comparisons
|
||||||
|
in the next function call. */
|
||||||
|
|
||||||
|
dict_table_get_low(foreign->foreign_table_name);
|
||||||
|
|
||||||
/* Note that there may already be a foreign constraint object in
|
/* Note that there may already be a foreign constraint object in
|
||||||
the dictionary cache for this constraint: then the following
|
the dictionary cache for this constraint: then the following
|
||||||
call only sets the pointers in it to point to the appropriate table
|
call only sets the pointers in it to point to the appropriate table
|
||||||
and index objects and frees the newly created object foreign. */
|
and index objects and frees the newly created object foreign.
|
||||||
|
Adding to the cache should always succeed since we are not creating
|
||||||
|
a new foreign key constraint but loading one from the data
|
||||||
|
dictionary. */
|
||||||
|
|
||||||
err = dict_foreign_add_to_cache(foreign);
|
err = dict_foreign_add_to_cache(foreign);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2391,7 +2391,7 @@ ibuf_delete_rec(
|
||||||
|
|
||||||
ut_ad(ibuf_inside());
|
ut_ad(ibuf_inside());
|
||||||
|
|
||||||
success = btr_cur_optimistic_delete(btr_pcur_get_btr_cur(pcur), mtr);
|
success = btr_cur_optimistic_delete(btr_pcur_get_btr_cur(pcur), mtr);
|
||||||
|
|
||||||
if (success) {
|
if (success) {
|
||||||
#ifdef UNIV_IBUF_DEBUG
|
#ifdef UNIV_IBUF_DEBUG
|
||||||
|
|
@ -2401,7 +2401,7 @@ ibuf_delete_rec(
|
||||||
return(FALSE);
|
return(FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We have to resort to a pessimistic delete from ibuf */
|
/* We have to resort to a pessimistic delete from ibuf */
|
||||||
btr_pcur_store_position(pcur, mtr);
|
btr_pcur_store_position(pcur, mtr);
|
||||||
|
|
||||||
btr_pcur_commit_specify_mtr(pcur, mtr);
|
btr_pcur_commit_specify_mtr(pcur, mtr);
|
||||||
|
|
@ -2420,17 +2420,22 @@ ibuf_delete_rec(
|
||||||
fprintf(stderr, "InnoDB: ibuf cursor restoration fails!\n");
|
fprintf(stderr, "InnoDB: ibuf cursor restoration fails!\n");
|
||||||
fprintf(stderr, "InnoDB: ibuf record inserted to page %lu\n",
|
fprintf(stderr, "InnoDB: ibuf record inserted to page %lu\n",
|
||||||
page_no);
|
page_no);
|
||||||
|
fflush(stderr);
|
||||||
|
|
||||||
rec_print(btr_pcur_get_rec(pcur));
|
rec_print(btr_pcur_get_rec(pcur));
|
||||||
rec_print(pcur->old_rec);
|
rec_print(pcur->old_rec);
|
||||||
dtuple_print(search_tuple);
|
dtuple_print(search_tuple);
|
||||||
|
|
||||||
rec_print(page_rec_get_next(btr_pcur_get_rec(pcur)));
|
rec_print(page_rec_get_next(btr_pcur_get_rec(pcur)));
|
||||||
|
fflush(stdout);
|
||||||
|
|
||||||
mtr_commit(mtr);
|
mtr_commit(mtr);
|
||||||
|
|
||||||
fprintf(stderr, "InnoDB: Validating insert buffer tree:\n");
|
fprintf(stderr, "InnoDB: Validating insert buffer tree:\n");
|
||||||
ut_a(btr_validate_tree(ibuf_data->index->tree));
|
ut_a(btr_validate_tree(ibuf_data->index->tree));
|
||||||
fprintf(stderr, "InnoDB: Ibuf tree ok\n");
|
|
||||||
|
fprintf(stderr, "InnoDB: ibuf tree ok\n");
|
||||||
|
fflush(stderr);
|
||||||
}
|
}
|
||||||
|
|
||||||
ut_a(success);
|
ut_a(success);
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,8 @@ Created 5/24/1996 Heikki Tuuri
|
||||||
#define DB_CORRUPTION 39 /* data structure corruption noticed */
|
#define DB_CORRUPTION 39 /* data structure corruption noticed */
|
||||||
#define DB_COL_APPEARS_TWICE_IN_INDEX 40 /* InnoDB cannot handle an index
|
#define DB_COL_APPEARS_TWICE_IN_INDEX 40 /* InnoDB cannot handle an index
|
||||||
where same column appears twice */
|
where same column appears twice */
|
||||||
|
#define DB_CANNOT_DROP_CONSTRAINT 40 /* dropping a foreign key constraint
|
||||||
|
from a table failed */
|
||||||
|
|
||||||
/* The following are partial failure codes */
|
/* The following are partial failure codes */
|
||||||
#define DB_FAIL 1000
|
#define DB_FAIL 1000
|
||||||
|
|
|
||||||
|
|
@ -219,6 +219,24 @@ dict_create_foreign_constraints(
|
||||||
char* name); /* in: table full name in the normalized form
|
char* name); /* in: table full name in the normalized form
|
||||||
database_name/table_name */
|
database_name/table_name */
|
||||||
/**************************************************************************
|
/**************************************************************************
|
||||||
|
Parses the CONSTRAINT id's to be dropped in an ALTER TABLE statement. */
|
||||||
|
|
||||||
|
ulint
|
||||||
|
dict_foreign_parse_drop_constraints(
|
||||||
|
/*================================*/
|
||||||
|
/* out: DB_SUCCESS or
|
||||||
|
DB_CANNOT_DROP_CONSTRAINT if
|
||||||
|
syntax error or the constraint
|
||||||
|
id does not match */
|
||||||
|
mem_heap_t* heap, /* in: heap from which we can
|
||||||
|
allocate memory */
|
||||||
|
trx_t* trx, /* in: transaction */
|
||||||
|
dict_table_t* table, /* in: table */
|
||||||
|
ulint* n, /* out: number of constraints
|
||||||
|
to drop */
|
||||||
|
char*** constraints_to_drop); /* out: id's of the
|
||||||
|
constraints to drop */
|
||||||
|
/**************************************************************************
|
||||||
Returns a table object and memoryfixes it. NOTE! This is a high-level
|
Returns a table object and memoryfixes it. NOTE! This is a high-level
|
||||||
function to be used mainly from outside the 'dict' directory. Inside this
|
function to be used mainly from outside the 'dict' directory. Inside this
|
||||||
directory dict_table_get_low is usually the appropriate function. */
|
directory dict_table_get_low is usually the appropriate function. */
|
||||||
|
|
@ -333,6 +351,16 @@ dict_print_info_on_foreign_keys(
|
||||||
char* str, /* in/out: pointer to a string */
|
char* str, /* in/out: pointer to a string */
|
||||||
ulint len, /* in: space in str available for info */
|
ulint len, /* in: space in str available for info */
|
||||||
dict_table_t* table); /* in: table */
|
dict_table_t* table); /* in: table */
|
||||||
|
/**************************************************************************
|
||||||
|
Sprintfs to a string info on a foreign key of a table in a format suitable
|
||||||
|
for CREATE TABLE. */
|
||||||
|
|
||||||
|
char*
|
||||||
|
dict_print_info_on_foreign_key_in_create_format(
|
||||||
|
/*============================================*/
|
||||||
|
/* out: how far in buf we printed */
|
||||||
|
dict_foreign_t* foreign,/* in: foreign key constraint */
|
||||||
|
char* buf); /* in: buffer of at least 5000 bytes */
|
||||||
/************************************************************************
|
/************************************************************************
|
||||||
Gets the first index on the table (the clustered index). */
|
Gets the first index on the table (the clustered index). */
|
||||||
UNIV_INLINE
|
UNIV_INLINE
|
||||||
|
|
@ -808,6 +836,13 @@ void
|
||||||
dict_mutex_exit_for_mysql(void);
|
dict_mutex_exit_for_mysql(void);
|
||||||
/*===========================*/
|
/*===========================*/
|
||||||
|
|
||||||
|
/* The following len must be at least 10000 bytes! */
|
||||||
|
#define DICT_FOREIGN_ERR_BUF_LEN 10000
|
||||||
|
|
||||||
|
/* Buffer for storing detailed information about the latest foreig key
|
||||||
|
error */
|
||||||
|
extern char* dict_foreign_err_buf;
|
||||||
|
extern mutex_t dict_foreign_err_mutex; /* mutex protecting the buffer */
|
||||||
|
|
||||||
extern dict_sys_t* dict_sys; /* the dictionary system */
|
extern dict_sys_t* dict_sys; /* the dictionary system */
|
||||||
extern rw_lock_t dict_operation_lock;
|
extern rw_lock_t dict_operation_lock;
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,6 @@ row_ins_check_foreign_constraint(
|
||||||
dictionary cache if they exist at all */
|
dictionary cache if they exist at all */
|
||||||
dict_table_t* table, /* in: if check_ref is TRUE, then the foreign
|
dict_table_t* table, /* in: if check_ref is TRUE, then the foreign
|
||||||
table, else the referenced table */
|
table, else the referenced table */
|
||||||
dict_index_t* index, /* in: index in table */
|
|
||||||
dtuple_t* entry, /* in: index entry for index */
|
dtuple_t* entry, /* in: index entry for index */
|
||||||
que_thr_t* thr); /* in: query thread */
|
que_thr_t* thr); /* in: query thread */
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
|
|
|
||||||
|
|
@ -3092,8 +3092,7 @@ lock_deadlock_recursive(
|
||||||
err_buf += strlen(err_buf);
|
err_buf += strlen(err_buf);
|
||||||
|
|
||||||
err_buf += sprintf(err_buf,
|
err_buf += sprintf(err_buf,
|
||||||
" LATEST DETECTED DEADLOCK:\n"
|
"\n*** (1) TRANSACTION:\n");
|
||||||
"*** (1) TRANSACTION:\n");
|
|
||||||
|
|
||||||
trx_print(err_buf, wait_lock->trx);
|
trx_print(err_buf, wait_lock->trx);
|
||||||
err_buf += strlen(err_buf);
|
err_buf += strlen(err_buf);
|
||||||
|
|
@ -3934,24 +3933,15 @@ lock_print_info(
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
buf += sprintf(buf, "Trx id counter %lu %lu\n",
|
|
||||||
ut_dulint_get_high(trx_sys->max_trx_id),
|
|
||||||
ut_dulint_get_low(trx_sys->max_trx_id));
|
|
||||||
|
|
||||||
buf += sprintf(buf,
|
|
||||||
"Purge done for trx's n:o < %lu %lu undo n:o < %lu %lu\n",
|
|
||||||
ut_dulint_get_high(purge_sys->purge_trx_no),
|
|
||||||
ut_dulint_get_low(purge_sys->purge_trx_no),
|
|
||||||
ut_dulint_get_high(purge_sys->purge_undo_no),
|
|
||||||
ut_dulint_get_low(purge_sys->purge_undo_no));
|
|
||||||
|
|
||||||
lock_mutex_enter_kernel();
|
lock_mutex_enter_kernel();
|
||||||
|
|
||||||
buf += sprintf(buf,
|
|
||||||
"Total number of lock structs in row lock hash table %lu\n",
|
|
||||||
lock_get_n_rec_locks());
|
|
||||||
if (lock_deadlock_found) {
|
if (lock_deadlock_found) {
|
||||||
|
|
||||||
|
buf += sprintf(buf,
|
||||||
|
"------------------------\n"
|
||||||
|
"LATEST DETECTED DEADLOCK\n"
|
||||||
|
"------------------------\n");
|
||||||
|
|
||||||
if ((ulint)(buf_end - buf)
|
if ((ulint)(buf_end - buf)
|
||||||
< 100 + strlen(lock_latest_err_buf)) {
|
< 100 + strlen(lock_latest_err_buf)) {
|
||||||
|
|
@ -3972,6 +3962,26 @@ lock_print_info(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
buf += sprintf(buf,
|
||||||
|
"------------\n"
|
||||||
|
"TRANSACTIONS\n"
|
||||||
|
"------------\n");
|
||||||
|
|
||||||
|
buf += sprintf(buf, "Trx id counter %lu %lu\n",
|
||||||
|
ut_dulint_get_high(trx_sys->max_trx_id),
|
||||||
|
ut_dulint_get_low(trx_sys->max_trx_id));
|
||||||
|
|
||||||
|
buf += sprintf(buf,
|
||||||
|
"Purge done for trx's n:o < %lu %lu undo n:o < %lu %lu\n",
|
||||||
|
ut_dulint_get_high(purge_sys->purge_trx_no),
|
||||||
|
ut_dulint_get_low(purge_sys->purge_trx_no),
|
||||||
|
ut_dulint_get_high(purge_sys->purge_undo_no),
|
||||||
|
ut_dulint_get_low(purge_sys->purge_undo_no));
|
||||||
|
|
||||||
|
buf += sprintf(buf,
|
||||||
|
"Total number of lock structs in row lock hash table %lu\n",
|
||||||
|
lock_get_n_rec_locks());
|
||||||
|
|
||||||
buf += sprintf(buf, "LIST OF TRANSACTIONS FOR EACH SESSION:\n");
|
buf += sprintf(buf, "LIST OF TRANSACTIONS FOR EACH SESSION:\n");
|
||||||
|
|
||||||
/* First print info on non-active transactions */
|
/* First print info on non-active transactions */
|
||||||
|
|
|
||||||
|
|
@ -214,9 +214,14 @@ os_file_get_last_error(void)
|
||||||
"InnoDB: the directory. It may also be you have created a subdirectory\n"
|
"InnoDB: the directory. It may also be you have created a subdirectory\n"
|
||||||
"InnoDB: of the same name as a data file.\n");
|
"InnoDB: of the same name as a data file.\n");
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr,
|
if (strerror((int)err) != NULL) {
|
||||||
"InnoDB: Look from section 13.2 at http://www.innodb.com/ibman.html\n"
|
fprintf(stderr,
|
||||||
"InnoDB: what the error number means.\n");
|
"InnoDB: Error number %lu means '%s'.\n", err, strerror((int)err));
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(stderr,
|
||||||
|
"InnoDB: See also section 13.2 at http://www.innodb.com/ibman.html\n"
|
||||||
|
"InnoDB: about operating system error numbers.\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -252,9 +257,14 @@ os_file_get_last_error(void)
|
||||||
"InnoDB: The error means mysqld does not have the access rights to\n"
|
"InnoDB: The error means mysqld does not have the access rights to\n"
|
||||||
"InnoDB: the directory.\n");
|
"InnoDB: the directory.\n");
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr,
|
if (strerror((int)err) != NULL) {
|
||||||
"InnoDB: Look from section 13.2 at http://www.innodb.com/ibman.html\n"
|
fprintf(stderr,
|
||||||
"InnoDB: what the error number means or use the perror program of MySQL.\n");
|
"InnoDB: Error number %lu means '%s'.\n", err, strerror((int)err));
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(stderr,
|
||||||
|
"InnoDB: See also section 13.2 at http://www.innodb.com/ibman.html\n"
|
||||||
|
"InnoDB: about operating system error numbers.\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -437,6 +437,111 @@ row_ins_cascade_calc_update_vec(
|
||||||
return(n_fields_updated);
|
return(n_fields_updated);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
Reports a foreign key error associated with an update or a delete of a
|
||||||
|
parent table index entry. */
|
||||||
|
static
|
||||||
|
void
|
||||||
|
row_ins_foreign_report_err(
|
||||||
|
/*=======================*/
|
||||||
|
char* errstr, /* in: error string from the viewpoint
|
||||||
|
of the parent table */
|
||||||
|
que_thr_t* thr, /* in: query thread whose run_node
|
||||||
|
is an update node */
|
||||||
|
dict_foreign_t* foreign, /* in: foreign key constraint */
|
||||||
|
rec_t* rec, /* in: a matching index record in the
|
||||||
|
child table */
|
||||||
|
dtuple_t* entry) /* in: index entry in the parent
|
||||||
|
table */
|
||||||
|
{
|
||||||
|
char* buf = dict_foreign_err_buf;
|
||||||
|
|
||||||
|
mutex_enter(&dict_foreign_err_mutex);
|
||||||
|
ut_sprintf_timestamp(buf);
|
||||||
|
sprintf(buf + strlen(buf), " Transaction:\n");
|
||||||
|
trx_print(buf + strlen(buf), thr_get_trx(thr));
|
||||||
|
|
||||||
|
sprintf(buf + strlen(buf),
|
||||||
|
"Foreign key constraint fails for table %.500s:\n",
|
||||||
|
foreign->foreign_table_name);
|
||||||
|
dict_print_info_on_foreign_key_in_create_format(
|
||||||
|
foreign, buf + strlen(buf));
|
||||||
|
sprintf(buf + strlen(buf), "\n%s", errstr);
|
||||||
|
sprintf(buf + strlen(buf),
|
||||||
|
" in parent table, in index %.500s tuple:\n",
|
||||||
|
foreign->referenced_index->name);
|
||||||
|
if (entry) {
|
||||||
|
dtuple_sprintf(buf + strlen(buf), 1000, entry);
|
||||||
|
}
|
||||||
|
sprintf(buf + strlen(buf),
|
||||||
|
"\nBut in child table %.500s, in index %.500s, there is a record:\n",
|
||||||
|
foreign->foreign_table_name, foreign->foreign_index->name);
|
||||||
|
if (rec) {
|
||||||
|
rec_sprintf(buf + strlen(buf), 1000, rec);
|
||||||
|
}
|
||||||
|
sprintf(buf + strlen(buf), "\n");
|
||||||
|
|
||||||
|
ut_a(strlen(buf) < DICT_FOREIGN_ERR_BUF_LEN);
|
||||||
|
|
||||||
|
mutex_exit(&dict_foreign_err_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
Reports a foreign key error to dict_foreign_err_buf when we are trying
|
||||||
|
to add an index entry to a child table. Note that the adding may be the result
|
||||||
|
of an update, too. */
|
||||||
|
static
|
||||||
|
void
|
||||||
|
row_ins_foreign_report_add_err(
|
||||||
|
/*===========================*/
|
||||||
|
que_thr_t* thr, /* in: query thread whose run_node
|
||||||
|
is an insert node */
|
||||||
|
dict_foreign_t* foreign, /* in: foreign key constraint */
|
||||||
|
rec_t* rec, /* in: a record in the parent table:
|
||||||
|
it does not match entry because we
|
||||||
|
have an error! */
|
||||||
|
dtuple_t* entry) /* in: index entry to insert in the
|
||||||
|
child table */
|
||||||
|
{
|
||||||
|
char* buf = dict_foreign_err_buf;
|
||||||
|
|
||||||
|
mutex_enter(&dict_foreign_err_mutex);
|
||||||
|
ut_sprintf_timestamp(buf);
|
||||||
|
sprintf(buf + strlen(buf), " Transaction:\n");
|
||||||
|
trx_print(buf + strlen(buf), thr_get_trx(thr));
|
||||||
|
sprintf(buf + strlen(buf),
|
||||||
|
"Foreign key constraint fails for table %.500s:\n",
|
||||||
|
foreign->foreign_table_name);
|
||||||
|
dict_print_info_on_foreign_key_in_create_format(
|
||||||
|
foreign, buf + strlen(buf));
|
||||||
|
sprintf(buf + strlen(buf),
|
||||||
|
"\nTrying to add in child table, in index %.500s tuple:\n",
|
||||||
|
foreign->foreign_index->name);
|
||||||
|
if (entry) {
|
||||||
|
dtuple_sprintf(buf + strlen(buf), 1000, entry);
|
||||||
|
}
|
||||||
|
sprintf(buf + strlen(buf),
|
||||||
|
"\nBut in parent table %.500s, in index %.500s,\n"
|
||||||
|
"the closest match we can find is record:\n",
|
||||||
|
foreign->referenced_table_name,
|
||||||
|
foreign->referenced_index->name);
|
||||||
|
if (rec && page_rec_is_supremum(rec)) {
|
||||||
|
/* If the cursor ended on a supremum record, it is better
|
||||||
|
to report the previous record in the error message, so that
|
||||||
|
the user gets a more descriptive error message. */
|
||||||
|
rec = page_rec_get_prev(rec);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rec) {
|
||||||
|
rec_sprintf(buf + strlen(buf), 1000, rec);
|
||||||
|
}
|
||||||
|
sprintf(buf + strlen(buf), "\n");
|
||||||
|
|
||||||
|
ut_a(strlen(buf) < DICT_FOREIGN_ERR_BUF_LEN);
|
||||||
|
|
||||||
|
mutex_exit(&dict_foreign_err_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
Perform referential actions or checks when a parent row is deleted or updated
|
Perform referential actions or checks when a parent row is deleted or updated
|
||||||
and the constraint had an ON DELETE or ON UPDATE condition which was not
|
and the constraint had an ON DELETE or ON UPDATE condition which was not
|
||||||
|
|
@ -453,6 +558,8 @@ row_ins_foreign_check_on_constraint(
|
||||||
type is != 0 */
|
type is != 0 */
|
||||||
btr_pcur_t* pcur, /* in: cursor placed on a matching
|
btr_pcur_t* pcur, /* in: cursor placed on a matching
|
||||||
index record in the child table */
|
index record in the child table */
|
||||||
|
dtuple_t* entry, /* in: index entry in the parent
|
||||||
|
table */
|
||||||
mtr_t* mtr) /* in: mtr holding the latch of pcur
|
mtr_t* mtr) /* in: mtr holding the latch of pcur
|
||||||
page */
|
page */
|
||||||
{
|
{
|
||||||
|
|
@ -506,6 +613,10 @@ row_ins_foreign_check_on_constraint(
|
||||||
return(DB_SUCCESS);
|
return(DB_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
row_ins_foreign_report_err((char*)"Trying to delete",
|
||||||
|
thr, foreign,
|
||||||
|
btr_pcur_get_rec(pcur), entry);
|
||||||
|
|
||||||
return(DB_ROW_IS_REFERENCED);
|
return(DB_ROW_IS_REFERENCED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -523,6 +634,10 @@ row_ins_foreign_check_on_constraint(
|
||||||
return(DB_SUCCESS);
|
return(DB_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
row_ins_foreign_report_err((char*)"Trying to update",
|
||||||
|
thr, foreign,
|
||||||
|
btr_pcur_get_rec(pcur), entry);
|
||||||
|
|
||||||
return(DB_ROW_IS_REFERENCED);
|
return(DB_ROW_IS_REFERENCED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -580,6 +695,10 @@ row_ins_foreign_check_on_constraint(
|
||||||
|
|
||||||
err = DB_ROW_IS_REFERENCED;
|
err = DB_ROW_IS_REFERENCED;
|
||||||
|
|
||||||
|
row_ins_foreign_report_err(
|
||||||
|
(char*)"Trying an update, possibly causing a cyclic cascaded update\n"
|
||||||
|
"in the child table,", thr, foreign, btr_pcur_get_rec(pcur), entry);
|
||||||
|
|
||||||
goto nonstandard_exit_func;
|
goto nonstandard_exit_func;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -809,11 +928,10 @@ row_ins_check_foreign_constraint(
|
||||||
dictionary cache if they exist at all */
|
dictionary cache if they exist at all */
|
||||||
dict_table_t* table, /* in: if check_ref is TRUE, then the foreign
|
dict_table_t* table, /* in: if check_ref is TRUE, then the foreign
|
||||||
table, else the referenced table */
|
table, else the referenced table */
|
||||||
dict_index_t* index __attribute__((unused)),/* in: index in table */
|
|
||||||
dtuple_t* entry, /* in: index entry for index */
|
dtuple_t* entry, /* in: index entry for index */
|
||||||
que_thr_t* thr) /* in: query thread */
|
que_thr_t* thr) /* in: query thread */
|
||||||
{
|
{
|
||||||
upd_node_t* upd_node;
|
upd_node_t* upd_node;
|
||||||
dict_table_t* check_table;
|
dict_table_t* check_table;
|
||||||
dict_index_t* check_index;
|
dict_index_t* check_index;
|
||||||
ulint n_fields_cmp;
|
ulint n_fields_cmp;
|
||||||
|
|
@ -824,6 +942,7 @@ row_ins_check_foreign_constraint(
|
||||||
int cmp;
|
int cmp;
|
||||||
ulint err;
|
ulint err;
|
||||||
ulint i;
|
ulint i;
|
||||||
|
char* buf = dict_foreign_err_buf;
|
||||||
mtr_t mtr;
|
mtr_t mtr;
|
||||||
|
|
||||||
run_again:
|
run_again:
|
||||||
|
|
@ -884,6 +1003,25 @@ run_again:
|
||||||
|
|
||||||
if (check_table == NULL) {
|
if (check_table == NULL) {
|
||||||
if (check_ref) {
|
if (check_ref) {
|
||||||
|
mutex_enter(&dict_foreign_err_mutex);
|
||||||
|
ut_sprintf_timestamp(buf);
|
||||||
|
sprintf(buf + strlen(buf), " Transaction:\n");
|
||||||
|
trx_print(buf + strlen(buf), thr_get_trx(thr));
|
||||||
|
sprintf(buf + strlen(buf),
|
||||||
|
"Foreign key constraint fails for table %.500s:\n",
|
||||||
|
foreign->foreign_table_name);
|
||||||
|
dict_print_info_on_foreign_key_in_create_format(
|
||||||
|
foreign, buf + strlen(buf));
|
||||||
|
sprintf(buf + strlen(buf),
|
||||||
|
"\nTrying to add to index %.500s tuple:\n", foreign->foreign_index->name);
|
||||||
|
dtuple_sprintf(buf + strlen(buf), 1000, entry);
|
||||||
|
sprintf(buf + strlen(buf),
|
||||||
|
"\nBut the parent table %.500s does not currently exist!\n",
|
||||||
|
foreign->referenced_table_name);
|
||||||
|
|
||||||
|
ut_a(strlen(buf) < DICT_FOREIGN_ERR_BUF_LEN);
|
||||||
|
mutex_exit(&dict_foreign_err_mutex);
|
||||||
|
|
||||||
return(DB_NO_REFERENCED_ROW);
|
return(DB_NO_REFERENCED_ROW);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -949,7 +1087,8 @@ run_again:
|
||||||
|
|
||||||
if (cmp == 0) {
|
if (cmp == 0) {
|
||||||
if (rec_get_deleted_flag(rec)) {
|
if (rec_get_deleted_flag(rec)) {
|
||||||
err = row_ins_set_shared_rec_lock(LOCK_ORDINARY,
|
err = row_ins_set_shared_rec_lock(
|
||||||
|
LOCK_ORDINARY,
|
||||||
rec, check_index, thr);
|
rec, check_index, thr);
|
||||||
if (err != DB_SUCCESS) {
|
if (err != DB_SUCCESS) {
|
||||||
|
|
||||||
|
|
@ -989,13 +1128,17 @@ run_again:
|
||||||
|
|
||||||
err =
|
err =
|
||||||
row_ins_foreign_check_on_constraint(
|
row_ins_foreign_check_on_constraint(
|
||||||
thr, foreign, &pcur, &mtr);
|
thr, foreign, &pcur, entry,
|
||||||
|
&mtr);
|
||||||
if (err != DB_SUCCESS) {
|
if (err != DB_SUCCESS) {
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
row_ins_foreign_report_err(
|
||||||
|
(char*)"Trying to delete or update",
|
||||||
|
thr, foreign, rec, entry);
|
||||||
|
|
||||||
err = DB_ROW_IS_REFERENCED;
|
err = DB_ROW_IS_REFERENCED;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -1012,6 +1155,8 @@ run_again:
|
||||||
|
|
||||||
if (check_ref) {
|
if (check_ref) {
|
||||||
err = DB_NO_REFERENCED_ROW;
|
err = DB_NO_REFERENCED_ROW;
|
||||||
|
row_ins_foreign_report_add_err(
|
||||||
|
thr, foreign, rec, entry);
|
||||||
} else {
|
} else {
|
||||||
err = DB_SUCCESS;
|
err = DB_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
@ -1025,6 +1170,9 @@ next_rec:
|
||||||
|
|
||||||
if (!moved) {
|
if (!moved) {
|
||||||
if (check_ref) {
|
if (check_ref) {
|
||||||
|
rec = btr_pcur_get_rec(&pcur);
|
||||||
|
row_ins_foreign_report_add_err(
|
||||||
|
thr, foreign, rec, entry);
|
||||||
err = DB_NO_REFERENCED_ROW;
|
err = DB_NO_REFERENCED_ROW;
|
||||||
} else {
|
} else {
|
||||||
err = DB_SUCCESS;
|
err = DB_SUCCESS;
|
||||||
|
|
@ -1100,7 +1248,7 @@ row_ins_check_foreign_constraints(
|
||||||
}
|
}
|
||||||
|
|
||||||
err = row_ins_check_foreign_constraint(TRUE, foreign,
|
err = row_ins_check_foreign_constraint(TRUE, foreign,
|
||||||
table, index, entry, thr);
|
table, entry, thr);
|
||||||
if (got_s_lock) {
|
if (got_s_lock) {
|
||||||
row_mysql_unfreeze_data_dictionary(trx);
|
row_mysql_unfreeze_data_dictionary(trx);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ Contains also create table and other data dictionary operations.
|
||||||
|
|
||||||
Created 9/17/2000 Heikki Tuuri
|
Created 9/17/2000 Heikki Tuuri
|
||||||
*******************************************************/
|
*******************************************************/
|
||||||
|
|
||||||
#include "row0mysql.h"
|
#include "row0mysql.h"
|
||||||
|
|
||||||
#ifdef UNIV_NONINL
|
#ifdef UNIV_NONINL
|
||||||
|
|
@ -1156,7 +1156,7 @@ row_mysql_recover_tmp_table(
|
||||||
return(DB_ERROR);
|
return(DB_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (0 == ut_memcmp(ptr, "/rsql", 5)) {
|
if (0 == ut_memcmp(ptr, (char*)"/rsql", 5)) {
|
||||||
ptr++;
|
ptr++;
|
||||||
*ptr = '#';
|
*ptr = '#';
|
||||||
|
|
||||||
|
|
@ -1280,10 +1280,10 @@ row_create_table_for_mysql(
|
||||||
}
|
}
|
||||||
|
|
||||||
trx->op_info = (char *) "creating table";
|
trx->op_info = (char *) "creating table";
|
||||||
|
|
||||||
if (0 == ut_strcmp(table->name, "mysql/host")
|
if (0 == ut_strcmp(table->name, (char*)"mysql/host")
|
||||||
|| 0 == ut_strcmp(table->name, "mysql/user")
|
|| 0 == ut_strcmp(table->name, (char*)"mysql/user")
|
||||||
|| 0 == ut_strcmp(table->name, "mysql/db")) {
|
|| 0 == ut_strcmp(table->name, (char*)"mysql/db")) {
|
||||||
|
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"InnoDB: Error: trying to create a MySQL system table %s of type InnoDB.\n"
|
"InnoDB: Error: trying to create a MySQL system table %s of type InnoDB.\n"
|
||||||
|
|
@ -1303,7 +1303,7 @@ row_create_table_for_mysql(
|
||||||
|
|
||||||
if (namelen >= keywordlen
|
if (namelen >= keywordlen
|
||||||
&& 0 == ut_memcmp(table->name + namelen - keywordlen,
|
&& 0 == ut_memcmp(table->name + namelen - keywordlen,
|
||||||
"_recover_innodb_tmp_table", keywordlen)) {
|
(char*)"_recover_innodb_tmp_table", keywordlen)) {
|
||||||
|
|
||||||
/* MySQL prevents accessing of tables whose name begins
|
/* MySQL prevents accessing of tables whose name begins
|
||||||
with #sql, that is temporary tables. If mysqld crashes in
|
with #sql, that is temporary tables. If mysqld crashes in
|
||||||
|
|
@ -1371,7 +1371,7 @@ row_create_table_for_mysql(
|
||||||
|
|
||||||
if (namelen >= keywordlen
|
if (namelen >= keywordlen
|
||||||
&& 0 == ut_memcmp(table->name + namelen - keywordlen,
|
&& 0 == ut_memcmp(table->name + namelen - keywordlen,
|
||||||
"innodb_mem_validate", keywordlen)) {
|
(char*)"innodb_mem_validate", keywordlen)) {
|
||||||
|
|
||||||
/* We define here a debugging feature intended for
|
/* We define here a debugging feature intended for
|
||||||
developers */
|
developers */
|
||||||
|
|
@ -1481,7 +1481,7 @@ row_create_index_for_mysql(
|
||||||
if (namelen >= keywordlen
|
if (namelen >= keywordlen
|
||||||
&& 0 == ut_memcmp(
|
&& 0 == ut_memcmp(
|
||||||
index->table_name + namelen - keywordlen,
|
index->table_name + namelen - keywordlen,
|
||||||
"_recover_innodb_tmp_table", keywordlen)) {
|
(char*)"_recover_innodb_tmp_table", keywordlen)) {
|
||||||
|
|
||||||
return(DB_SUCCESS);
|
return(DB_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
@ -1586,7 +1586,7 @@ row_table_add_foreign_constraints(
|
||||||
if (namelen >= keywordlen
|
if (namelen >= keywordlen
|
||||||
&& 0 == ut_memcmp(
|
&& 0 == ut_memcmp(
|
||||||
name + namelen - keywordlen,
|
name + namelen - keywordlen,
|
||||||
"_recover_innodb_tmp_table", keywordlen)) {
|
(char*)"_recover_innodb_tmp_table", keywordlen)) {
|
||||||
|
|
||||||
return(DB_SUCCESS);
|
return(DB_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
@ -1808,7 +1808,6 @@ row_drop_table_for_mysql(
|
||||||
ulint len;
|
ulint len;
|
||||||
ulint namelen;
|
ulint namelen;
|
||||||
ulint keywordlen;
|
ulint keywordlen;
|
||||||
ulint rounds = 0;
|
|
||||||
ibool locked_dictionary = FALSE;
|
ibool locked_dictionary = FALSE;
|
||||||
char buf[10000];
|
char buf[10000];
|
||||||
|
|
||||||
|
|
@ -2155,7 +2154,7 @@ row_is_mysql_tmp_table_name(
|
||||||
ulint i;
|
ulint i;
|
||||||
|
|
||||||
for (i = 0; i <= ut_strlen(name) - 5; i++) {
|
for (i = 0; i <= ut_strlen(name) - 5; i++) {
|
||||||
if (ut_memcmp(name + i, "/#sql", 5) == 0) {
|
if (ut_memcmp(name + i, (char*)"/#sql", 5) == 0) {
|
||||||
|
|
||||||
return(TRUE);
|
return(TRUE);
|
||||||
}
|
}
|
||||||
|
|
@ -2177,12 +2176,16 @@ row_rename_table_for_mysql(
|
||||||
{
|
{
|
||||||
dict_table_t* table;
|
dict_table_t* table;
|
||||||
que_thr_t* thr;
|
que_thr_t* thr;
|
||||||
que_t* graph;
|
que_t* graph = NULL;
|
||||||
ulint err;
|
ulint err;
|
||||||
char* str1;
|
char* str1;
|
||||||
char* str2;
|
char* str2;
|
||||||
char* str3;
|
char* str3;
|
||||||
|
mem_heap_t* heap = NULL;
|
||||||
|
char** constraints_to_drop = NULL;
|
||||||
|
ulint n_constraints_to_drop = 0;
|
||||||
ulint len;
|
ulint len;
|
||||||
|
ulint i;
|
||||||
char buf[10000];
|
char buf[10000];
|
||||||
|
|
||||||
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
|
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
|
||||||
|
|
@ -2200,10 +2203,10 @@ row_rename_table_for_mysql(
|
||||||
trx_commit_for_mysql(trx);
|
trx_commit_for_mysql(trx);
|
||||||
return(DB_ERROR);
|
return(DB_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (0 == ut_strcmp(new_name, "mysql/host")
|
if (0 == ut_strcmp(new_name, (char*)"mysql/host")
|
||||||
|| 0 == ut_strcmp(new_name, "mysql/user")
|
|| 0 == ut_strcmp(new_name, (char*)"mysql/user")
|
||||||
|| 0 == ut_strcmp(new_name, "mysql/db")) {
|
|| 0 == ut_strcmp(new_name, (char*)"mysql/db")) {
|
||||||
|
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"InnoDB: Error: trying to create a MySQL system table %s of type InnoDB.\n"
|
"InnoDB: Error: trying to create a MySQL system table %s of type InnoDB.\n"
|
||||||
|
|
@ -2217,6 +2220,19 @@ row_rename_table_for_mysql(
|
||||||
trx->op_info = (char *) "renaming table";
|
trx->op_info = (char *) "renaming table";
|
||||||
trx_start_if_not_started(trx);
|
trx_start_if_not_started(trx);
|
||||||
|
|
||||||
|
/* Serialize data dictionary operations with dictionary mutex:
|
||||||
|
no deadlocks can occur then in these operations */
|
||||||
|
|
||||||
|
row_mysql_lock_data_dictionary(trx);
|
||||||
|
|
||||||
|
table = dict_table_get_low(old_name);
|
||||||
|
|
||||||
|
if (!table) {
|
||||||
|
err = DB_TABLE_NOT_FOUND;
|
||||||
|
|
||||||
|
goto funct_exit;
|
||||||
|
}
|
||||||
|
|
||||||
str1 = (char *)
|
str1 = (char *)
|
||||||
"PROCEDURE RENAME_TABLE_PROC () IS\n"
|
"PROCEDURE RENAME_TABLE_PROC () IS\n"
|
||||||
"new_table_name CHAR;\n"
|
"new_table_name CHAR;\n"
|
||||||
|
|
@ -2229,14 +2245,43 @@ row_rename_table_for_mysql(
|
||||||
|
|
||||||
if (row_is_mysql_tmp_table_name(new_name)) {
|
if (row_is_mysql_tmp_table_name(new_name)) {
|
||||||
|
|
||||||
/* We want to preserve the original foreign key
|
/* MySQL is doing an ALTER TABLE command and it renames the
|
||||||
constraint definitions despite the name change */
|
original table to a temporary table name. We want to preserve
|
||||||
|
the original foreign key constraint definitions despite the
|
||||||
|
name change. An exception is those constraints for which
|
||||||
|
the ALTER TABLE contained DROP FOREIGN KEY <foreign key id>.*/
|
||||||
|
|
||||||
str3 = (char*)
|
heap = mem_heap_create(100);
|
||||||
"';\n"
|
|
||||||
"UPDATE SYS_TABLES SET NAME = new_table_name\n"
|
err = dict_foreign_parse_drop_constraints(heap, trx,
|
||||||
"WHERE NAME = old_table_name;\n"
|
table,
|
||||||
"END;\n";
|
&n_constraints_to_drop,
|
||||||
|
&constraints_to_drop);
|
||||||
|
if (err != DB_SUCCESS) {
|
||||||
|
|
||||||
|
goto funct_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
str3 = mem_heap_alloc(heap,
|
||||||
|
1000 + 500 * n_constraints_to_drop);
|
||||||
|
*str3 = '\0';
|
||||||
|
sprintf(str3,
|
||||||
|
"';\n"
|
||||||
|
"UPDATE SYS_TABLES SET NAME = new_table_name\n"
|
||||||
|
"WHERE NAME = old_table_name;\n");
|
||||||
|
|
||||||
|
for (i = 0; i < n_constraints_to_drop; i++) {
|
||||||
|
sprintf(str3 + strlen(str3),
|
||||||
|
"DELETE FROM SYS_FOREIGN_COLS WHERE ID = '%s';\n"
|
||||||
|
"DELETE FROM SYS_FOREIGN WHERE ID = '%s';\n",
|
||||||
|
constraints_to_drop[i],
|
||||||
|
constraints_to_drop[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
sprintf(str3 + strlen(str3),
|
||||||
|
"END;\n");
|
||||||
|
|
||||||
|
ut_a(strlen(str3) < 1000 + 500 * n_constraints_to_drop);
|
||||||
} else {
|
} else {
|
||||||
str3 = (char*)
|
str3 = (char*)
|
||||||
"';\n"
|
"';\n"
|
||||||
|
|
@ -2267,13 +2312,6 @@ row_rename_table_for_mysql(
|
||||||
|
|
||||||
ut_memcpy(buf + len, str3, ut_strlen(str3) + 1);
|
ut_memcpy(buf + len, str3, ut_strlen(str3) + 1);
|
||||||
|
|
||||||
/* Serialize data dictionary operations with dictionary mutex:
|
|
||||||
no deadlocks can occur then in these operations */
|
|
||||||
|
|
||||||
row_mysql_lock_data_dictionary(trx);
|
|
||||||
|
|
||||||
table = dict_table_get_low(old_name);
|
|
||||||
|
|
||||||
graph = pars_sql(buf);
|
graph = pars_sql(buf);
|
||||||
|
|
||||||
ut_a(graph);
|
ut_a(graph);
|
||||||
|
|
@ -2283,12 +2321,6 @@ row_rename_table_for_mysql(
|
||||||
|
|
||||||
graph->fork_type = QUE_FORK_MYSQL_INTERFACE;
|
graph->fork_type = QUE_FORK_MYSQL_INTERFACE;
|
||||||
|
|
||||||
if (!table) {
|
|
||||||
err = DB_TABLE_NOT_FOUND;
|
|
||||||
|
|
||||||
goto funct_exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
ut_a(thr = que_fork_start_command(graph, SESS_COMM_EXECUTE, 0));
|
ut_a(thr = que_fork_start_command(graph, SESS_COMM_EXECUTE, 0));
|
||||||
|
|
||||||
que_run_threads(thr);
|
que_run_threads(thr);
|
||||||
|
|
@ -2329,6 +2361,13 @@ row_rename_table_for_mysql(
|
||||||
|
|
||||||
if (row_is_mysql_tmp_table_name(old_name)) {
|
if (row_is_mysql_tmp_table_name(old_name)) {
|
||||||
|
|
||||||
|
/* MySQL is doing an ALTER TABLE command and it
|
||||||
|
renames the created temporary table to the name
|
||||||
|
of the original table. In the ALTER TABLE we maybe
|
||||||
|
created some FOREIGN KEY constraints for the temporary
|
||||||
|
table. But we want to load also the foreign key
|
||||||
|
constraint definitions for the original table name. */
|
||||||
|
|
||||||
err = dict_load_foreigns(new_name);
|
err = dict_load_foreigns(new_name);
|
||||||
|
|
||||||
if (err != DB_SUCCESS) {
|
if (err != DB_SUCCESS) {
|
||||||
|
|
@ -2354,7 +2393,13 @@ row_rename_table_for_mysql(
|
||||||
funct_exit:
|
funct_exit:
|
||||||
row_mysql_unlock_data_dictionary(trx);
|
row_mysql_unlock_data_dictionary(trx);
|
||||||
|
|
||||||
que_graph_free(graph);
|
if (graph) {
|
||||||
|
que_graph_free(graph);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (heap) {
|
||||||
|
mem_heap_free(heap);
|
||||||
|
}
|
||||||
|
|
||||||
trx_commit_for_mysql(trx);
|
trx_commit_for_mysql(trx);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2601,6 +2601,24 @@ row_search_for_mysql(
|
||||||
|
|
||||||
printf("N tables locked %lu\n", trx->mysql_n_tables_locked);
|
printf("N tables locked %lu\n", trx->mysql_n_tables_locked);
|
||||||
*/
|
*/
|
||||||
|
/*-------------------------------------------------------------*/
|
||||||
|
/* PHASE 0: Release a possible s-latch we are holding on the
|
||||||
|
adaptive hash index latch if there is someone waiting behind */
|
||||||
|
|
||||||
|
if (trx->has_search_latch
|
||||||
|
&& btr_search_latch.writer != RW_LOCK_NOT_LOCKED) {
|
||||||
|
|
||||||
|
/* There is an x-latch request on the adaptive hash index:
|
||||||
|
release the s-latch to reduce starvation and wait for
|
||||||
|
BTR_SEA_TIMEOUT rounds before trying to keep it again over
|
||||||
|
calls from MySQL */
|
||||||
|
|
||||||
|
rw_lock_s_unlock(&btr_search_latch);
|
||||||
|
trx->has_search_latch = FALSE;
|
||||||
|
|
||||||
|
trx->search_latch_timeout = BTR_SEA_TIMEOUT;
|
||||||
|
}
|
||||||
|
|
||||||
/*-------------------------------------------------------------*/
|
/*-------------------------------------------------------------*/
|
||||||
/* PHASE 1: Try to pop the row from the prefetch cache */
|
/* PHASE 1: Try to pop the row from the prefetch cache */
|
||||||
|
|
||||||
|
|
@ -2736,23 +2754,7 @@ row_search_for_mysql(
|
||||||
NOT prepared to inserts interleaved with the SELECT,
|
NOT prepared to inserts interleaved with the SELECT,
|
||||||
and if we try that, we can deadlock on the adaptive
|
and if we try that, we can deadlock on the adaptive
|
||||||
hash index semaphore! */
|
hash index semaphore! */
|
||||||
|
|
||||||
if (btr_search_latch.writer != RW_LOCK_NOT_LOCKED) {
|
|
||||||
/* There is an x-latch request: release
|
|
||||||
a possible s-latch to reduce starvation
|
|
||||||
and wait for BTR_SEA_TIMEOUT rounds before
|
|
||||||
trying to keep it again over calls from
|
|
||||||
MySQL */
|
|
||||||
|
|
||||||
if (trx->has_search_latch) {
|
|
||||||
rw_lock_s_unlock(&btr_search_latch);
|
|
||||||
trx->has_search_latch = FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
trx->search_latch_timeout = BTR_SEA_TIMEOUT;
|
|
||||||
|
|
||||||
goto no_shortcut;
|
|
||||||
}
|
|
||||||
#ifndef UNIV_SEARCH_DEBUG
|
#ifndef UNIV_SEARCH_DEBUG
|
||||||
if (!trx->has_search_latch) {
|
if (!trx->has_search_latch) {
|
||||||
rw_lock_s_lock(&btr_search_latch);
|
rw_lock_s_lock(&btr_search_latch);
|
||||||
|
|
@ -2810,7 +2812,6 @@ row_search_for_mysql(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
no_shortcut:
|
|
||||||
/*-------------------------------------------------------------*/
|
/*-------------------------------------------------------------*/
|
||||||
/* PHASE 3: Open or restore index cursor position */
|
/* PHASE 3: Open or restore index cursor position */
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -218,7 +218,7 @@ row_upd_check_references_constraints(
|
||||||
being dropped while the check is running. */
|
being dropped while the check is running. */
|
||||||
|
|
||||||
err = row_ins_check_foreign_constraint(FALSE, foreign,
|
err = row_ins_check_foreign_constraint(FALSE, foreign,
|
||||||
table, index, entry, thr);
|
table, entry, thr);
|
||||||
|
|
||||||
if (foreign->foreign_table) {
|
if (foreign->foreign_table) {
|
||||||
mutex_enter(&(dict_sys->mutex));
|
mutex_enter(&(dict_sys->mutex));
|
||||||
|
|
|
||||||
|
|
@ -1869,11 +1869,11 @@ retry:
|
||||||
/* Go to wait for the event; when a thread leaves InnoDB it will
|
/* Go to wait for the event; when a thread leaves InnoDB it will
|
||||||
release this thread */
|
release this thread */
|
||||||
|
|
||||||
trx->op_info = "waiting in InnoDB queue";
|
trx->op_info = (char*)"waiting in InnoDB queue";
|
||||||
|
|
||||||
os_event_wait(slot->event);
|
os_event_wait(slot->event);
|
||||||
|
|
||||||
trx->op_info = "";
|
trx->op_info = (char*)"";
|
||||||
|
|
||||||
os_fast_mutex_lock(&srv_conc_mutex);
|
os_fast_mutex_lock(&srv_conc_mutex);
|
||||||
|
|
||||||
|
|
@ -2346,12 +2346,22 @@ srv_sprintf_innodb_monitor(
|
||||||
buf = buf + strlen(buf);
|
buf = buf + strlen(buf);
|
||||||
ut_a(buf < buf_end + 1500);
|
ut_a(buf < buf_end + 1500);
|
||||||
|
|
||||||
buf += sprintf(buf, "------------\n"
|
if (*dict_foreign_err_buf != '\0') {
|
||||||
"TRANSACTIONS\n"
|
buf += sprintf(buf,
|
||||||
"------------\n");
|
"------------------------\n"
|
||||||
|
"LATEST FOREIGN KEY ERROR\n"
|
||||||
|
"------------------------\n");
|
||||||
|
|
||||||
|
if (buf_end - buf > 6000) {
|
||||||
|
buf+= sprintf(buf, "%.4000s", dict_foreign_err_buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ut_a(buf < buf_end + 1500);
|
||||||
|
|
||||||
lock_print_info(buf, buf_end);
|
lock_print_info(buf, buf_end);
|
||||||
buf = buf + strlen(buf);
|
buf = buf + strlen(buf);
|
||||||
|
|
||||||
buf += sprintf(buf, "--------\n"
|
buf += sprintf(buf, "--------\n"
|
||||||
"FILE I/O\n"
|
"FILE I/O\n"
|
||||||
"--------\n");
|
"--------\n");
|
||||||
|
|
|
||||||
|
|
@ -204,7 +204,7 @@ ut_get_year_month_day(
|
||||||
|
|
||||||
cal_tm_ptr = localtime(&tm);
|
cal_tm_ptr = localtime(&tm);
|
||||||
|
|
||||||
*year = (ulint)cal_tm_ptr->tm_year;
|
*year = (ulint)cal_tm_ptr->tm_year + 1900;
|
||||||
*month = (ulint)cal_tm_ptr->tm_mon + 1;
|
*month = (ulint)cal_tm_ptr->tm_mon + 1;
|
||||||
*day = (ulint)cal_tm_ptr->tm_mday;
|
*day = (ulint)cal_tm_ptr->tm_mday;
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -242,6 +242,10 @@ convert_error_code_to_mysql(
|
||||||
|
|
||||||
return(HA_ERR_CANNOT_ADD_FOREIGN);
|
return(HA_ERR_CANNOT_ADD_FOREIGN);
|
||||||
|
|
||||||
|
} else if (error == (int) DB_CANNOT_DROP_CONSTRAINT) {
|
||||||
|
|
||||||
|
return(HA_WRONG_CREATE_OPTION);
|
||||||
|
|
||||||
} else if (error == (int) DB_COL_APPEARS_TWICE_IN_INDEX) {
|
} else if (error == (int) DB_COL_APPEARS_TWICE_IN_INDEX) {
|
||||||
|
|
||||||
return(HA_ERR_CRASHED);
|
return(HA_ERR_CRASHED);
|
||||||
|
|
@ -3048,6 +3052,9 @@ ha_innobase::create(
|
||||||
trx_search_latch_release_if_reserved(parent_trx);
|
trx_search_latch_release_if_reserved(parent_trx);
|
||||||
|
|
||||||
trx = trx_allocate_for_mysql();
|
trx = trx_allocate_for_mysql();
|
||||||
|
|
||||||
|
trx->mysql_thd = thd;
|
||||||
|
trx->mysql_query_str = &((*thd).query);
|
||||||
|
|
||||||
if (thd->options & OPTION_NO_FOREIGN_KEY_CHECKS) {
|
if (thd->options & OPTION_NO_FOREIGN_KEY_CHECKS) {
|
||||||
trx->check_foreigns = FALSE;
|
trx->check_foreigns = FALSE;
|
||||||
|
|
@ -3231,6 +3238,9 @@ ha_innobase::delete_table(
|
||||||
|
|
||||||
trx = trx_allocate_for_mysql();
|
trx = trx_allocate_for_mysql();
|
||||||
|
|
||||||
|
trx->mysql_thd = current_thd;
|
||||||
|
trx->mysql_query_str = &((*current_thd).query);
|
||||||
|
|
||||||
name_len = strlen(name);
|
name_len = strlen(name);
|
||||||
|
|
||||||
assert(name_len < 1000);
|
assert(name_len < 1000);
|
||||||
|
|
@ -3309,6 +3319,8 @@ innobase_drop_database(
|
||||||
casedn_str(namebuf);
|
casedn_str(namebuf);
|
||||||
#endif
|
#endif
|
||||||
trx = trx_allocate_for_mysql();
|
trx = trx_allocate_for_mysql();
|
||||||
|
trx->mysql_thd = current_thd;
|
||||||
|
trx->mysql_query_str = &((*current_thd).query);
|
||||||
|
|
||||||
error = row_drop_database_for_mysql(namebuf, trx);
|
error = row_drop_database_for_mysql(namebuf, trx);
|
||||||
|
|
||||||
|
|
@ -3368,6 +3380,8 @@ ha_innobase::rename_table(
|
||||||
}
|
}
|
||||||
|
|
||||||
trx = trx_allocate_for_mysql();
|
trx = trx_allocate_for_mysql();
|
||||||
|
trx->mysql_thd = current_thd;
|
||||||
|
trx->mysql_query_str = &((*current_thd).query);
|
||||||
|
|
||||||
name_len1 = strlen(from);
|
name_len1 = strlen(from);
|
||||||
name_len2 = strlen(to);
|
name_len2 = strlen(to);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue