mirror of
https://github.com/MariaDB/server.git
synced 2025-08-01 03:47:19 +03:00
Merge sinisa@bk-internal.mysql.com:/home/bk/mysql-4.0
into sinisa.nasamreza.org:/mnt/work/mysql-4.0
This commit is contained in:
@ -19,6 +19,11 @@
|
||||
#ifndef _global_h
|
||||
#define _global_h
|
||||
|
||||
#ifndef EMBEDDED_LIBRARY
|
||||
#define HAVE_REPLICATION
|
||||
#define HAVE_EXTERNAL_CLIENT
|
||||
#endif
|
||||
|
||||
#if defined( __EMX__) && !defined( MYSQL_SERVER)
|
||||
/* moved here to use below VOID macro redefinition */
|
||||
#define INCL_BASE
|
||||
|
@ -106,7 +106,7 @@ buf_flush_ready_for_replace(
|
||||
BUF_BLOCK_FILE_PAGE and in the LRU list*/
|
||||
{
|
||||
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)
|
||||
|| (block->buf_fix_count != 0)
|
||||
@ -227,7 +227,9 @@ buf_flush_buffered_writes(void)
|
||||
}
|
||||
|
||||
for (i = 0; i < trx_doublewrite->first_free; i++) {
|
||||
|
||||
block = trx_doublewrite->buf_block_arr[i];
|
||||
ut_a(block->state == BUF_BLOCK_FILE_PAGE);
|
||||
|
||||
if (block->check_index_page_at_flush
|
||||
&& !page_simple_validate(block->frame)) {
|
||||
@ -236,10 +238,12 @@ buf_flush_buffered_writes(void)
|
||||
|
||||
ut_print_timestamp(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 prevent corrupt data from ending up in data\n"
|
||||
"InnoDB: files.\n");
|
||||
"InnoDB: files.\n",
|
||||
block->offset, block->space);
|
||||
|
||||
ut_a(0);
|
||||
}
|
||||
}
|
||||
@ -432,6 +436,8 @@ buf_flush_try_page(
|
||||
|
||||
block = buf_page_hash_get(space, offset);
|
||||
|
||||
ut_a(block->state == BUF_BLOCK_FILE_PAGE);
|
||||
|
||||
if (flush_type == BUF_FLUSH_LIST
|
||||
&& 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")) {
|
||||
fprintf(stderr,
|
||||
"InnoDB: table SYS_FOREIGN not found from internal data dictionary\n");
|
||||
|
||||
return(DB_ERROR);
|
||||
}
|
||||
|
||||
@ -1259,6 +1260,13 @@ loop:
|
||||
"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);
|
||||
}
|
||||
|
||||
|
@ -185,6 +185,12 @@ dict_foreign_free(
|
||||
/*==============*/
|
||||
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. */
|
||||
static
|
||||
@ -573,6 +579,11 @@ dict_init(void)
|
||||
|
||||
rw_lock_create(&dict_operation_lock);
|
||||
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_index_t* index;
|
||||
ibool added_to_referenced_list = FALSE;
|
||||
char* buf = dict_foreign_err_buf;
|
||||
|
||||
ut_ad(mutex_own(&(dict_sys->mutex)));
|
||||
|
||||
@ -1850,9 +1862,29 @@ dict_foreign_add_to_cache(
|
||||
for_in_cache->foreign_index);
|
||||
|
||||
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) {
|
||||
mem_heap_free(foreign->heap);
|
||||
}
|
||||
|
||||
return(DB_CANNOT_ADD_CONSTRAINT);
|
||||
}
|
||||
|
||||
@ -1871,6 +1903,25 @@ dict_foreign_add_to_cache(
|
||||
for_in_cache->referenced_index);
|
||||
|
||||
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 (added_to_referenced_list) {
|
||||
UT_LIST_REMOVE(referenced_list,
|
||||
@ -2141,18 +2192,21 @@ dict_scan_table_name(
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
Skips one 'word', like an id. For the lexical definition of 'word', see the
|
||||
code below. */
|
||||
Scans an id. For the lexical definition of an 'id', see the code below.
|
||||
Strips backquotes from around the id. */
|
||||
static
|
||||
char*
|
||||
dict_skip_word(
|
||||
/*===========*/
|
||||
dict_scan_id(
|
||||
/*=========*/
|
||||
/* out: scanned to */
|
||||
char* ptr, /* in: scanned to */
|
||||
ibool* success)/* out: TRUE if success, FALSE if just spaces left in
|
||||
string */
|
||||
char** start, /* out: start of the id; NULL if no id was
|
||||
scannable */
|
||||
ulint* len) /* out: length of the id */
|
||||
{
|
||||
*success = FALSE;
|
||||
ibool scanned_backquote = FALSE;
|
||||
|
||||
*start = NULL;
|
||||
|
||||
while (isspace(*ptr)) {
|
||||
ptr++;
|
||||
@ -2164,20 +2218,58 @@ dict_skip_word(
|
||||
}
|
||||
|
||||
if (*ptr == '`') {
|
||||
scanned_backquote = TRUE;
|
||||
ptr++;
|
||||
}
|
||||
|
||||
while (!isspace(*ptr) && *ptr != ',' && *ptr != '(' && *ptr != '`'
|
||||
&& *ptr != '\0') {
|
||||
*start = ptr;
|
||||
|
||||
while (!isspace(*ptr) && *ptr != ',' && *ptr != '(' && *ptr != ')'
|
||||
&& *ptr != '\0' && *ptr != '`') {
|
||||
|
||||
ptr++;
|
||||
}
|
||||
|
||||
*success = TRUE;
|
||||
*len = (ulint) (ptr - *start);
|
||||
|
||||
if (scanned_backquote) {
|
||||
if (*ptr == '`') {
|
||||
ptr++;
|
||||
} else {
|
||||
/* Syntax error */
|
||||
*start = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
of closing brackets ')' between string and ptr. */
|
||||
@ -2204,6 +2296,106 @@ dict_bracket_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
|
||||
@ -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
|
||||
be accompanied with indexes in both participating tables. The indexes are
|
||||
allowed to contain more fields than mentioned in the constraint. */
|
||||
|
||||
static
|
||||
ulint
|
||||
dict_create_foreign_constraints(
|
||||
/*============================*/
|
||||
dict_create_foreign_constraints_low(
|
||||
/*================================*/
|
||||
/* out: error code or DB_SUCCESS */
|
||||
trx_t* trx, /* in: transaction */
|
||||
char* sql_string, /* in: table create or ALTER TABLE
|
||||
@ -2231,6 +2423,8 @@ dict_create_foreign_constraints(
|
||||
dict_index_t* index;
|
||||
dict_foreign_t* foreign;
|
||||
char* ptr = sql_string;
|
||||
char* start_of_latest_foreign = sql_string;
|
||||
char* buf = dict_foreign_err_buf;
|
||||
ibool success;
|
||||
ulint error;
|
||||
ulint i;
|
||||
@ -2248,6 +2442,15 @@ dict_create_foreign_constraints(
|
||||
table = dict_table_get_low(name);
|
||||
|
||||
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);
|
||||
}
|
||||
loop:
|
||||
@ -2263,6 +2466,8 @@ loop:
|
||||
return(error);
|
||||
}
|
||||
|
||||
start_of_latest_foreign = ptr;
|
||||
|
||||
ptr = dict_accept(ptr, (char *) "FOREIGN", &success);
|
||||
|
||||
if (!isspace(*ptr)) {
|
||||
@ -2283,13 +2488,19 @@ loop:
|
||||
ptr = dict_skip_word(ptr, &success);
|
||||
|
||||
if (!success) {
|
||||
dict_foreign_report_syntax_err(name,
|
||||
start_of_latest_foreign, ptr);
|
||||
|
||||
return(DB_CANNOT_ADD_CONSTRAINT);
|
||||
}
|
||||
|
||||
ptr = dict_accept(ptr, (char *) "(", &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,
|
||||
column_names + i, column_name_lens + i);
|
||||
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);
|
||||
}
|
||||
|
||||
@ -2314,6 +2534,8 @@ col_loop1:
|
||||
ptr = dict_accept(ptr, (char *) ")", &success);
|
||||
|
||||
if (!success) {
|
||||
dict_foreign_report_syntax_err(name, start_of_latest_foreign,
|
||||
ptr);
|
||||
return(DB_CANNOT_ADD_CONSTRAINT);
|
||||
}
|
||||
|
||||
@ -2323,12 +2545,24 @@ col_loop1:
|
||||
index = dict_foreign_find_index(table, column_names, i, NULL);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
ptr = dict_accept(ptr, (char *) "REFERENCES", &success);
|
||||
|
||||
if (!success || !isspace(*ptr)) {
|
||||
dict_foreign_report_syntax_err(name, start_of_latest_foreign,
|
||||
ptr);
|
||||
return(DB_CANNOT_ADD_CONSTRAINT);
|
||||
}
|
||||
|
||||
@ -2358,6 +2592,15 @@ col_loop1:
|
||||
if (!success || (!referenced_table && trx->check_foreigns)) {
|
||||
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);
|
||||
}
|
||||
|
||||
@ -2365,7 +2608,8 @@ col_loop1:
|
||||
|
||||
if (!success) {
|
||||
dict_foreign_free(foreign);
|
||||
|
||||
dict_foreign_report_syntax_err(name, start_of_latest_foreign,
|
||||
ptr);
|
||||
return(DB_CANNOT_ADD_CONSTRAINT);
|
||||
}
|
||||
|
||||
@ -2380,6 +2624,15 @@ col_loop2:
|
||||
if (!success) {
|
||||
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);
|
||||
}
|
||||
|
||||
@ -2394,6 +2647,8 @@ col_loop2:
|
||||
if (!success || foreign->n_fields != i) {
|
||||
dict_foreign_free(foreign);
|
||||
|
||||
dict_foreign_report_syntax_err(name, start_of_latest_foreign,
|
||||
ptr);
|
||||
return(DB_CANNOT_ADD_CONSTRAINT);
|
||||
}
|
||||
|
||||
@ -2416,9 +2671,10 @@ scan_on_conditions:
|
||||
ptr = dict_accept(ptr, "UPDATE", &success);
|
||||
|
||||
if (!success) {
|
||||
|
||||
dict_foreign_free(foreign);
|
||||
|
||||
dict_foreign_report_syntax_err(name,
|
||||
start_of_latest_foreign, ptr);
|
||||
return(DB_CANNOT_ADD_CONSTRAINT);
|
||||
}
|
||||
|
||||
@ -2454,6 +2710,8 @@ scan_on_conditions:
|
||||
|
||||
if (!success) {
|
||||
dict_foreign_free(foreign);
|
||||
dict_foreign_report_syntax_err(name,
|
||||
start_of_latest_foreign, ptr);
|
||||
|
||||
return(DB_CANNOT_ADD_CONSTRAINT);
|
||||
}
|
||||
@ -2471,7 +2729,8 @@ scan_on_conditions:
|
||||
|
||||
if (!success) {
|
||||
dict_foreign_free(foreign);
|
||||
|
||||
dict_foreign_report_syntax_err(name, start_of_latest_foreign,
|
||||
ptr);
|
||||
return(DB_CANNOT_ADD_CONSTRAINT);
|
||||
}
|
||||
|
||||
@ -2479,7 +2738,8 @@ scan_on_conditions:
|
||||
|
||||
if (!success) {
|
||||
dict_foreign_free(foreign);
|
||||
|
||||
dict_foreign_report_syntax_err(name, start_of_latest_foreign,
|
||||
ptr);
|
||||
return(DB_CANNOT_ADD_CONSTRAINT);
|
||||
}
|
||||
|
||||
@ -2493,6 +2753,15 @@ scan_on_conditions:
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
@ -2511,6 +2780,15 @@ try_find_index:
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@ -2524,6 +2802,18 @@ try_find_index:
|
||||
foreign->foreign_index);
|
||||
if (!index) {
|
||||
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);
|
||||
}
|
||||
} else {
|
||||
@ -2564,6 +2854,165 @@ try_find_index:
|
||||
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 ====================*/
|
||||
|
||||
/**************************************************************************
|
||||
@ -3285,7 +3734,6 @@ dict_index_print_low(
|
||||
n_vals = index->stat_n_diff_key_vals[1];
|
||||
}
|
||||
|
||||
|
||||
printf(
|
||||
" INDEX: name %s, table name %s, id %lu %lu, fields %lu/%lu, type %lu\n",
|
||||
index->name, index->table_name,
|
||||
@ -3327,43 +3775,27 @@ dict_field_print_low(
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
Sprintfs to a string info on foreign keys of a table in a format suitable
|
||||
Sprintfs to a string info on a foreign key of a table in a format suitable
|
||||
for CREATE TABLE. */
|
||||
static
|
||||
void
|
||||
dict_print_info_on_foreign_keys_in_create_format(
|
||||
/*=============================================*/
|
||||
char* buf, /* in: auxiliary buffer */
|
||||
char* str, /* in/out: pointer to a string */
|
||||
ulint len, /* in: str has to be a buffer at least
|
||||
len + 5000 bytes */
|
||||
dict_table_t* table) /* in: 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 */
|
||||
{
|
||||
|
||||
dict_foreign_t* foreign;
|
||||
char* buf2 = buf;
|
||||
ulint i;
|
||||
char* buf2;
|
||||
|
||||
buf2 = buf;
|
||||
|
||||
mutex_enter(&(dict_sys->mutex));
|
||||
|
||||
foreign = UT_LIST_GET_FIRST(table->foreign_list);
|
||||
|
||||
if (foreign == NULL) {
|
||||
mutex_exit(&(dict_sys->mutex));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
while (foreign != NULL) {
|
||||
buf2 += sprintf(buf2, ",\n FOREIGN KEY (");
|
||||
|
||||
buf2 += sprintf(buf2, ",\n CONSTRAINT `%s` FOREIGN KEY (",
|
||||
foreign->id);
|
||||
for (i = 0; i < foreign->n_fields; i++) {
|
||||
if ((ulint)(buf2 - buf) >= len) {
|
||||
if ((ulint)(buf2 - buf) >= 4000) {
|
||||
|
||||
goto no_space;
|
||||
}
|
||||
buf2 += sprintf(buf2, "`%s`",
|
||||
buf2 += sprintf(buf2, "`%.250s`",
|
||||
foreign->foreign_col_names[i]);
|
||||
|
||||
if (i + 1 < foreign->n_fields) {
|
||||
@ -3371,15 +3803,15 @@ dict_print_info_on_foreign_keys_in_create_format(
|
||||
}
|
||||
}
|
||||
|
||||
if (dict_tables_have_same_db(table->name,
|
||||
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 `%s` (",
|
||||
buf2 += sprintf(buf2, ") REFERENCES `%.500s` (",
|
||||
dict_remove_db_name(
|
||||
foreign->referenced_table_name));
|
||||
} else {
|
||||
buf2 += sprintf(buf2, ") REFERENCES `%s` (",
|
||||
buf2 += sprintf(buf2, ") REFERENCES `%.500s` (",
|
||||
foreign->referenced_table_name);
|
||||
/* Change the '/' in the table name to '.' */
|
||||
|
||||
@ -3394,10 +3826,11 @@ dict_print_info_on_foreign_keys_in_create_format(
|
||||
}
|
||||
|
||||
for (i = 0; i < foreign->n_fields; i++) {
|
||||
if ((ulint)(buf2 - buf) >= len) {
|
||||
if ((ulint)(buf2 - buf) >= 4000) {
|
||||
|
||||
goto no_space;
|
||||
}
|
||||
buf2 += sprintf(buf2, "`%s`",
|
||||
buf2 += sprintf(buf2, "`%.250s`",
|
||||
foreign->referenced_col_names[i]);
|
||||
if (i + 1 < foreign->n_fields) {
|
||||
buf2 += sprintf(buf2, ", ");
|
||||
@ -3430,6 +3863,47 @@ dict_print_info_on_foreign_keys_in_create_format(
|
||||
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
|
||||
for CREATE TABLE. */
|
||||
static
|
||||
void
|
||||
dict_print_info_on_foreign_keys_in_create_format(
|
||||
/*=============================================*/
|
||||
char* buf, /* in: auxiliary buffer */
|
||||
char* str, /* in/out: pointer to a string */
|
||||
ulint len, /* in: buf has to be a buffer of at least
|
||||
len + 5000 bytes; str must have at least
|
||||
len + 1 bytes */
|
||||
dict_table_t* table) /* in: table */
|
||||
{
|
||||
dict_foreign_t* foreign;
|
||||
char* buf2;
|
||||
|
||||
buf2 = buf;
|
||||
|
||||
mutex_enter(&(dict_sys->mutex));
|
||||
|
||||
foreign = UT_LIST_GET_FIRST(table->foreign_list);
|
||||
|
||||
if (foreign == NULL) {
|
||||
mutex_exit(&(dict_sys->mutex));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
while (foreign != NULL) {
|
||||
if ((ulint)(buf2 - buf) >= len) {
|
||||
goto no_space;
|
||||
}
|
||||
|
||||
buf2 = dict_print_info_on_foreign_key_in_create_format(
|
||||
foreign, buf2);
|
||||
|
||||
foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
|
||||
}
|
||||
no_space:
|
||||
@ -3489,7 +3963,7 @@ dict_print_info_on_foreign_keys(
|
||||
goto no_space;
|
||||
}
|
||||
|
||||
buf2 += sprintf(buf2, "%s",
|
||||
buf2 += sprintf(buf2, "%.500s",
|
||||
foreign->foreign_col_names[i]);
|
||||
|
||||
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);
|
||||
|
||||
for (i = 0; i < foreign->n_fields; i++) {
|
||||
if ((ulint)(buf2 - buf) >= len) {
|
||||
goto no_space;
|
||||
}
|
||||
buf2 += sprintf(buf2, "%s",
|
||||
buf2 += sprintf(buf2, "%.500s",
|
||||
foreign->referenced_col_names[i]);
|
||||
if (i + 1 < foreign->n_fields) {
|
||||
buf2 += sprintf(buf2, " ");
|
||||
|
@ -456,7 +456,7 @@ dict_load_indexes(
|
||||
ut_ad(len == 8);
|
||||
id = mach_read_from_8(field);
|
||||
|
||||
ut_a(0 == ut_strcmp("NAME",
|
||||
ut_a(0 == ut_strcmp((char*)"NAME",
|
||||
dict_field_get_col(
|
||||
dict_index_get_nth_field(
|
||||
dict_table_get_first_index(sys_indexes), 4))->name));
|
||||
@ -515,7 +515,7 @@ dict_load_indexes(
|
||||
&& ((type & DICT_CLUSTERED)
|
||||
|| ((table == dict_sys->sys_tables)
|
||||
&& (name_len == ut_strlen("ID_IND"))
|
||||
&& (0 == ut_memcmp(name_buf, "ID_IND",
|
||||
&& (0 == ut_memcmp(name_buf, (char*)"ID_IND",
|
||||
name_len))))) {
|
||||
|
||||
/* The index was created in memory already in
|
||||
@ -566,6 +566,7 @@ dict_load_table(
|
||||
char* buf;
|
||||
ulint space;
|
||||
ulint n_cols;
|
||||
ulint err;
|
||||
mtr_t mtr;
|
||||
|
||||
ut_ad(mutex_own(&(dict_sys->mutex)));
|
||||
@ -674,8 +675,25 @@ dict_load_table(
|
||||
|
||||
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);
|
||||
|
||||
return(table);
|
||||
@ -978,8 +996,8 @@ dict_load_foreign(
|
||||
|
||||
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);
|
||||
foreign->referenced_table_name[len] = '\0';
|
||||
|
||||
@ -988,10 +1006,19 @@ dict_load_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
|
||||
the dictionary cache for this constraint: then the following
|
||||
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);
|
||||
|
||||
|
@ -2420,17 +2420,22 @@ ibuf_delete_rec(
|
||||
fprintf(stderr, "InnoDB: ibuf cursor restoration fails!\n");
|
||||
fprintf(stderr, "InnoDB: ibuf record inserted to page %lu\n",
|
||||
page_no);
|
||||
fflush(stderr);
|
||||
|
||||
rec_print(btr_pcur_get_rec(pcur));
|
||||
rec_print(pcur->old_rec);
|
||||
dtuple_print(search_tuple);
|
||||
|
||||
rec_print(page_rec_get_next(btr_pcur_get_rec(pcur)));
|
||||
fflush(stdout);
|
||||
|
||||
mtr_commit(mtr);
|
||||
|
||||
fprintf(stderr, "InnoDB: Validating insert buffer tree:\n");
|
||||
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);
|
||||
|
@ -44,6 +44,8 @@ Created 5/24/1996 Heikki Tuuri
|
||||
#define DB_CORRUPTION 39 /* data structure corruption noticed */
|
||||
#define DB_COL_APPEARS_TWICE_IN_INDEX 40 /* InnoDB cannot handle an index
|
||||
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 */
|
||||
#define DB_FAIL 1000
|
||||
|
@ -219,6 +219,24 @@ dict_create_foreign_constraints(
|
||||
char* name); /* in: table full name in the normalized form
|
||||
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
|
||||
function to be used mainly from outside the 'dict' directory. Inside this
|
||||
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 */
|
||||
ulint len, /* in: space in str available for info */
|
||||
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). */
|
||||
UNIV_INLINE
|
||||
@ -808,6 +836,13 @@ 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 rw_lock_t dict_operation_lock;
|
||||
|
@ -35,7 +35,6 @@ row_ins_check_foreign_constraint(
|
||||
dictionary cache if they exist at all */
|
||||
dict_table_t* table, /* in: if check_ref is TRUE, then the foreign
|
||||
table, else the referenced table */
|
||||
dict_index_t* index, /* in: index in table */
|
||||
dtuple_t* entry, /* in: index entry for index */
|
||||
que_thr_t* thr); /* in: query thread */
|
||||
/*************************************************************************
|
||||
|
@ -3092,8 +3092,7 @@ lock_deadlock_recursive(
|
||||
err_buf += strlen(err_buf);
|
||||
|
||||
err_buf += sprintf(err_buf,
|
||||
" LATEST DETECTED DEADLOCK:\n"
|
||||
"*** (1) TRANSACTION:\n");
|
||||
"\n*** (1) TRANSACTION:\n");
|
||||
|
||||
trx_print(err_buf, wait_lock->trx);
|
||||
err_buf += strlen(err_buf);
|
||||
@ -3935,24 +3934,15 @@ lock_print_info(
|
||||
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();
|
||||
|
||||
buf += sprintf(buf,
|
||||
"Total number of lock structs in row lock hash table %lu\n",
|
||||
lock_get_n_rec_locks());
|
||||
if (lock_deadlock_found) {
|
||||
|
||||
buf += sprintf(buf,
|
||||
"------------------------\n"
|
||||
"LATEST DETECTED DEADLOCK\n"
|
||||
"------------------------\n");
|
||||
|
||||
if ((ulint)(buf_end - buf)
|
||||
< 100 + strlen(lock_latest_err_buf)) {
|
||||
|
||||
@ -3972,6 +3962,26 @@ lock_print_info(
|
||||
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");
|
||||
|
||||
/* 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: of the same name as a data file.\n");
|
||||
} else {
|
||||
if (strerror((int)err) != NULL) {
|
||||
fprintf(stderr,
|
||||
"InnoDB: Look from section 13.2 at http://www.innodb.com/ibman.html\n"
|
||||
"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 directory.\n");
|
||||
} else {
|
||||
if (strerror((int)err) != NULL) {
|
||||
fprintf(stderr,
|
||||
"InnoDB: Look from section 13.2 at http://www.innodb.com/ibman.html\n"
|
||||
"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);
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
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
|
||||
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 */
|
||||
btr_pcur_t* pcur, /* in: cursor placed on a matching
|
||||
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
|
||||
page */
|
||||
{
|
||||
@ -506,6 +613,10 @@ row_ins_foreign_check_on_constraint(
|
||||
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);
|
||||
}
|
||||
|
||||
@ -523,6 +634,10 @@ row_ins_foreign_check_on_constraint(
|
||||
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);
|
||||
}
|
||||
|
||||
@ -580,6 +695,10 @@ row_ins_foreign_check_on_constraint(
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@ -809,7 +928,6 @@ row_ins_check_foreign_constraint(
|
||||
dictionary cache if they exist at all */
|
||||
dict_table_t* table, /* in: if check_ref is TRUE, then the foreign
|
||||
table, else the referenced table */
|
||||
dict_index_t* index __attribute__((unused)),/* in: index in table */
|
||||
dtuple_t* entry, /* in: index entry for index */
|
||||
que_thr_t* thr) /* in: query thread */
|
||||
{
|
||||
@ -824,6 +942,7 @@ row_ins_check_foreign_constraint(
|
||||
int cmp;
|
||||
ulint err;
|
||||
ulint i;
|
||||
char* buf = dict_foreign_err_buf;
|
||||
mtr_t mtr;
|
||||
|
||||
run_again:
|
||||
@ -884,6 +1003,25 @@ run_again:
|
||||
|
||||
if (check_table == NULL) {
|
||||
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);
|
||||
}
|
||||
|
||||
@ -949,7 +1087,8 @@ run_again:
|
||||
|
||||
if (cmp == 0) {
|
||||
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);
|
||||
if (err != DB_SUCCESS) {
|
||||
|
||||
@ -989,13 +1128,17 @@ run_again:
|
||||
|
||||
err =
|
||||
row_ins_foreign_check_on_constraint(
|
||||
thr, foreign, &pcur, &mtr);
|
||||
|
||||
thr, foreign, &pcur, entry,
|
||||
&mtr);
|
||||
if (err != DB_SUCCESS) {
|
||||
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
row_ins_foreign_report_err(
|
||||
(char*)"Trying to delete or update",
|
||||
thr, foreign, rec, entry);
|
||||
|
||||
err = DB_ROW_IS_REFERENCED;
|
||||
break;
|
||||
}
|
||||
@ -1012,6 +1155,8 @@ run_again:
|
||||
|
||||
if (check_ref) {
|
||||
err = DB_NO_REFERENCED_ROW;
|
||||
row_ins_foreign_report_add_err(
|
||||
thr, foreign, rec, entry);
|
||||
} else {
|
||||
err = DB_SUCCESS;
|
||||
}
|
||||
@ -1025,6 +1170,9 @@ next_rec:
|
||||
|
||||
if (!moved) {
|
||||
if (check_ref) {
|
||||
rec = btr_pcur_get_rec(&pcur);
|
||||
row_ins_foreign_report_add_err(
|
||||
thr, foreign, rec, entry);
|
||||
err = DB_NO_REFERENCED_ROW;
|
||||
} else {
|
||||
err = DB_SUCCESS;
|
||||
@ -1100,7 +1248,7 @@ row_ins_check_foreign_constraints(
|
||||
}
|
||||
|
||||
err = row_ins_check_foreign_constraint(TRUE, foreign,
|
||||
table, index, entry, thr);
|
||||
table, entry, thr);
|
||||
if (got_s_lock) {
|
||||
row_mysql_unfreeze_data_dictionary(trx);
|
||||
}
|
||||
|
@ -1156,7 +1156,7 @@ row_mysql_recover_tmp_table(
|
||||
return(DB_ERROR);
|
||||
}
|
||||
|
||||
if (0 == ut_memcmp(ptr, "/rsql", 5)) {
|
||||
if (0 == ut_memcmp(ptr, (char*)"/rsql", 5)) {
|
||||
ptr++;
|
||||
*ptr = '#';
|
||||
|
||||
@ -1281,9 +1281,9 @@ row_create_table_for_mysql(
|
||||
|
||||
trx->op_info = (char *) "creating table";
|
||||
|
||||
if (0 == ut_strcmp(table->name, "mysql/host")
|
||||
|| 0 == ut_strcmp(table->name, "mysql/user")
|
||||
|| 0 == ut_strcmp(table->name, "mysql/db")) {
|
||||
if (0 == ut_strcmp(table->name, (char*)"mysql/host")
|
||||
|| 0 == ut_strcmp(table->name, (char*)"mysql/user")
|
||||
|| 0 == ut_strcmp(table->name, (char*)"mysql/db")) {
|
||||
|
||||
fprintf(stderr,
|
||||
"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
|
||||
&& 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
|
||||
with #sql, that is temporary tables. If mysqld crashes in
|
||||
@ -1371,7 +1371,7 @@ row_create_table_for_mysql(
|
||||
|
||||
if (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
|
||||
developers */
|
||||
@ -1481,7 +1481,7 @@ row_create_index_for_mysql(
|
||||
if (namelen >= keywordlen
|
||||
&& 0 == ut_memcmp(
|
||||
index->table_name + namelen - keywordlen,
|
||||
"_recover_innodb_tmp_table", keywordlen)) {
|
||||
(char*)"_recover_innodb_tmp_table", keywordlen)) {
|
||||
|
||||
return(DB_SUCCESS);
|
||||
}
|
||||
@ -1586,7 +1586,7 @@ row_table_add_foreign_constraints(
|
||||
if (namelen >= keywordlen
|
||||
&& 0 == ut_memcmp(
|
||||
name + namelen - keywordlen,
|
||||
"_recover_innodb_tmp_table", keywordlen)) {
|
||||
(char*)"_recover_innodb_tmp_table", keywordlen)) {
|
||||
|
||||
return(DB_SUCCESS);
|
||||
}
|
||||
@ -1808,7 +1808,6 @@ row_drop_table_for_mysql(
|
||||
ulint len;
|
||||
ulint namelen;
|
||||
ulint keywordlen;
|
||||
ulint rounds = 0;
|
||||
ibool locked_dictionary = FALSE;
|
||||
char buf[10000];
|
||||
|
||||
@ -2155,7 +2154,7 @@ row_is_mysql_tmp_table_name(
|
||||
ulint 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);
|
||||
}
|
||||
@ -2177,12 +2176,16 @@ row_rename_table_for_mysql(
|
||||
{
|
||||
dict_table_t* table;
|
||||
que_thr_t* thr;
|
||||
que_t* graph;
|
||||
que_t* graph = NULL;
|
||||
ulint err;
|
||||
char* str1;
|
||||
char* str2;
|
||||
char* str3;
|
||||
mem_heap_t* heap = NULL;
|
||||
char** constraints_to_drop = NULL;
|
||||
ulint n_constraints_to_drop = 0;
|
||||
ulint len;
|
||||
ulint i;
|
||||
char buf[10000];
|
||||
|
||||
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
|
||||
@ -2201,9 +2204,9 @@ row_rename_table_for_mysql(
|
||||
return(DB_ERROR);
|
||||
}
|
||||
|
||||
if (0 == ut_strcmp(new_name, "mysql/host")
|
||||
|| 0 == ut_strcmp(new_name, "mysql/user")
|
||||
|| 0 == ut_strcmp(new_name, "mysql/db")) {
|
||||
if (0 == ut_strcmp(new_name, (char*)"mysql/host")
|
||||
|| 0 == ut_strcmp(new_name, (char*)"mysql/user")
|
||||
|| 0 == ut_strcmp(new_name, (char*)"mysql/db")) {
|
||||
|
||||
fprintf(stderr,
|
||||
"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_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 *)
|
||||
"PROCEDURE RENAME_TABLE_PROC () IS\n"
|
||||
"new_table_name CHAR;\n"
|
||||
@ -2229,14 +2245,43 @@ row_rename_table_for_mysql(
|
||||
|
||||
if (row_is_mysql_tmp_table_name(new_name)) {
|
||||
|
||||
/* We want to preserve the original foreign key
|
||||
constraint definitions despite the name change */
|
||||
/* MySQL is doing an ALTER TABLE command and it renames the
|
||||
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);
|
||||
|
||||
err = dict_foreign_parse_drop_constraints(heap, trx,
|
||||
table,
|
||||
&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"
|
||||
"END;\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 {
|
||||
str3 = (char*)
|
||||
"';\n"
|
||||
@ -2267,13 +2312,6 @@ row_rename_table_for_mysql(
|
||||
|
||||
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);
|
||||
|
||||
ut_a(graph);
|
||||
@ -2283,12 +2321,6 @@ row_rename_table_for_mysql(
|
||||
|
||||
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));
|
||||
|
||||
que_run_threads(thr);
|
||||
@ -2329,6 +2361,13 @@ row_rename_table_for_mysql(
|
||||
|
||||
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);
|
||||
|
||||
if (err != DB_SUCCESS) {
|
||||
@ -2354,7 +2393,13 @@ row_rename_table_for_mysql(
|
||||
funct_exit:
|
||||
row_mysql_unlock_data_dictionary(trx);
|
||||
|
||||
if (graph) {
|
||||
que_graph_free(graph);
|
||||
}
|
||||
|
||||
if (heap) {
|
||||
mem_heap_free(heap);
|
||||
}
|
||||
|
||||
trx_commit_for_mysql(trx);
|
||||
|
||||
|
@ -2601,6 +2601,24 @@ row_search_for_mysql(
|
||||
|
||||
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 */
|
||||
|
||||
@ -2737,22 +2755,6 @@ row_search_for_mysql(
|
||||
and if we try that, we can deadlock on the adaptive
|
||||
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
|
||||
if (!trx->has_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 */
|
||||
|
||||
|
@ -218,7 +218,7 @@ row_upd_check_references_constraints(
|
||||
being dropped while the check is running. */
|
||||
|
||||
err = row_ins_check_foreign_constraint(FALSE, foreign,
|
||||
table, index, entry, thr);
|
||||
table, entry, thr);
|
||||
|
||||
if (foreign->foreign_table) {
|
||||
mutex_enter(&(dict_sys->mutex));
|
||||
|
@ -1869,11 +1869,11 @@ retry:
|
||||
/* Go to wait for the event; when a thread leaves InnoDB it will
|
||||
release this thread */
|
||||
|
||||
trx->op_info = "waiting in InnoDB queue";
|
||||
trx->op_info = (char*)"waiting in InnoDB queue";
|
||||
|
||||
os_event_wait(slot->event);
|
||||
|
||||
trx->op_info = "";
|
||||
trx->op_info = (char*)"";
|
||||
|
||||
os_fast_mutex_lock(&srv_conc_mutex);
|
||||
|
||||
@ -2346,9 +2346,19 @@ srv_sprintf_innodb_monitor(
|
||||
buf = buf + strlen(buf);
|
||||
ut_a(buf < buf_end + 1500);
|
||||
|
||||
buf += sprintf(buf, "------------\n"
|
||||
"TRANSACTIONS\n"
|
||||
"------------\n");
|
||||
if (*dict_foreign_err_buf != '\0') {
|
||||
buf += sprintf(buf,
|
||||
"------------------------\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);
|
||||
buf = buf + strlen(buf);
|
||||
|
||||
|
@ -204,7 +204,7 @@ ut_get_year_month_day(
|
||||
|
||||
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;
|
||||
*day = (ulint)cal_tm_ptr->tm_mday;
|
||||
#endif
|
||||
|
@ -47,7 +47,7 @@ sum(all a) count(all a) avg(all a) std(all a) bit_or(all a) bit_and(all a) min(a
|
||||
21 6 3.5000 1.7078 7 0 1 6 E
|
||||
select grp, sum(a),count(a),avg(a),std(a),bit_or(a),bit_and(a),min(a),max(a),min(c),max(c) from t1 group by grp;
|
||||
grp sum(a) count(a) avg(a) std(a) bit_or(a) bit_and(a) min(a) max(a) min(c) max(c)
|
||||
NULL 0 0 NULL NULL 0 0 NULL NULL
|
||||
NULL NULL 0 NULL NULL 0 0 NULL NULL
|
||||
1 1 1 1.0000 0.0000 1 1 1 1 a a
|
||||
2 5 2 2.5000 0.5000 3 2 2 3 b c
|
||||
3 15 3 5.0000 0.8165 7 4 4 6 C E
|
||||
@ -204,3 +204,44 @@ select max(t2.a1) from t1 left outer join t2 on t1.a2=t2.a1 and 1=0 where t2.a1=
|
||||
max(t2.a1)
|
||||
NULL
|
||||
drop table t1,t2;
|
||||
CREATE TABLE t1 (a int, b int);
|
||||
select count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b) from t1;
|
||||
count(b) sum(b) avg(b) std(b) min(b) max(b) bit_and(b) bit_or(b)
|
||||
0 NULL NULL NULL NULL NULL -1 0
|
||||
select a,count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b) from t1 group by a;
|
||||
a count(b) sum(b) avg(b) std(b) min(b) max(b) bit_and(b) bit_or(b)
|
||||
insert into t1 values (1,null);
|
||||
select a,count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b) from t1 group by a;
|
||||
a count(b) sum(b) avg(b) std(b) min(b) max(b) bit_and(b) bit_or(b)
|
||||
1 0 NULL NULL NULL NULL NULL -1 0
|
||||
insert into t1 values (1,null);
|
||||
insert into t1 values (2,null);
|
||||
select a,count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b) from t1 group by a;
|
||||
a count(b) sum(b) avg(b) std(b) min(b) max(b) bit_and(b) bit_or(b)
|
||||
1 0 NULL NULL NULL NULL NULL 0 0
|
||||
2 0 NULL NULL NULL NULL NULL 0 0
|
||||
select SQL_BIG_RESULT a,count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b) from t1 group by a;
|
||||
a count(b) sum(b) avg(b) std(b) min(b) max(b) bit_and(b) bit_or(b)
|
||||
1 0 NULL NULL NULL NULL NULL -1 0
|
||||
2 0 NULL NULL NULL NULL NULL -1 0
|
||||
insert into t1 values (2,1);
|
||||
select a,count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b) from t1 group by a;
|
||||
a count(b) sum(b) avg(b) std(b) min(b) max(b) bit_and(b) bit_or(b)
|
||||
1 0 NULL NULL NULL NULL NULL 0 0
|
||||
2 1 1 1.0000 0.0000 1 1 0 1
|
||||
select SQL_BIG_RESULT a,count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b) from t1 group by a;
|
||||
a count(b) sum(b) avg(b) std(b) min(b) max(b) bit_and(b) bit_or(b)
|
||||
1 0 NULL NULL NULL NULL NULL -1 0
|
||||
2 1 1 1.0000 0.0000 1 1 1 1
|
||||
insert into t1 values (3,1);
|
||||
select a,count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b) from t1 group by a;
|
||||
a count(b) sum(b) avg(b) std(b) min(b) max(b) bit_and(b) bit_or(b)
|
||||
1 0 NULL NULL NULL NULL NULL 0 0
|
||||
2 1 1 1.0000 0.0000 1 1 0 1
|
||||
3 1 1 1.0000 0.0000 1 1 1 1
|
||||
select SQL_BIG_RESULT a,count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b) from t1 group by a;
|
||||
a count(b) sum(b) avg(b) std(b) min(b) max(b) bit_and(b) bit_or(b)
|
||||
1 0 NULL NULL NULL NULL NULL -1 0
|
||||
2 1 1 1.0000 0.0000 1 1 1 1
|
||||
3 1 1 1.0000 0.0000 1 1 1 1
|
||||
drop table t1;
|
||||
|
@ -126,3 +126,24 @@ select max(t1.a2) from t1 left outer join t2 on t1.a1=10 where t1.a1=20;
|
||||
select max(t1.a2) from t1 left outer join t2 on t1.a1=10 where t1.a1=10;
|
||||
select max(t2.a1) from t1 left outer join t2 on t1.a2=t2.a1 and 1=0 where t2.a1='AAA';
|
||||
drop table t1,t2;
|
||||
|
||||
#
|
||||
# Test of group function and NULL values
|
||||
#
|
||||
|
||||
CREATE TABLE t1 (a int, b int);
|
||||
select count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b) from t1;
|
||||
select a,count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b) from t1 group by a;
|
||||
insert into t1 values (1,null);
|
||||
select a,count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b) from t1 group by a;
|
||||
insert into t1 values (1,null);
|
||||
insert into t1 values (2,null);
|
||||
select a,count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b) from t1 group by a;
|
||||
select SQL_BIG_RESULT a,count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b) from t1 group by a;
|
||||
insert into t1 values (2,1);
|
||||
select a,count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b) from t1 group by a;
|
||||
select SQL_BIG_RESULT a,count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b) from t1 group by a;
|
||||
insert into t1 values (3,1);
|
||||
select a,count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b) from t1 group by a;
|
||||
select SQL_BIG_RESULT a,count(b), sum(b), avg(b), std(b), min(b), max(b), bit_and(b), bit_or(b) from t1 group by a;
|
||||
drop table t1;
|
||||
|
@ -224,7 +224,7 @@ then
|
||||
if test -n "$open_files"
|
||||
then
|
||||
ulimit -n $open_files
|
||||
args="open-files-limit=$open_files $args"
|
||||
args="--open-files-limit=$open_files $args"
|
||||
fi
|
||||
if test -n "$core_file_size"
|
||||
then
|
||||
|
@ -242,6 +242,10 @@ convert_error_code_to_mysql(
|
||||
|
||||
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) {
|
||||
|
||||
return(HA_ERR_CRASHED);
|
||||
@ -3049,6 +3053,9 @@ ha_innobase::create(
|
||||
|
||||
trx = trx_allocate_for_mysql();
|
||||
|
||||
trx->mysql_thd = thd;
|
||||
trx->mysql_query_str = &((*thd).query);
|
||||
|
||||
if (thd->options & OPTION_NO_FOREIGN_KEY_CHECKS) {
|
||||
trx->check_foreigns = FALSE;
|
||||
}
|
||||
@ -3231,6 +3238,9 @@ ha_innobase::delete_table(
|
||||
|
||||
trx = trx_allocate_for_mysql();
|
||||
|
||||
trx->mysql_thd = current_thd;
|
||||
trx->mysql_query_str = &((*current_thd).query);
|
||||
|
||||
name_len = strlen(name);
|
||||
|
||||
assert(name_len < 1000);
|
||||
@ -3309,6 +3319,8 @@ innobase_drop_database(
|
||||
casedn_str(namebuf);
|
||||
#endif
|
||||
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);
|
||||
|
||||
@ -3368,6 +3380,8 @@ ha_innobase::rename_table(
|
||||
}
|
||||
|
||||
trx = trx_allocate_for_mysql();
|
||||
trx->mysql_thd = current_thd;
|
||||
trx->mysql_query_str = &((*current_thd).query);
|
||||
|
||||
name_len1 = strlen(from);
|
||||
name_len2 = strlen(to);
|
||||
|
@ -175,12 +175,14 @@ Item_sum_hybrid::fix_fields(THD *thd,TABLE_LIST *tables)
|
||||
|
||||
void Item_sum_sum::reset()
|
||||
{
|
||||
null_value=0; sum=0.0; Item_sum_sum::add();
|
||||
null_value=1; sum=0.0; Item_sum_sum::add();
|
||||
}
|
||||
|
||||
bool Item_sum_sum::add()
|
||||
{
|
||||
sum+=args[0]->val();
|
||||
if (!args[0]->null_value)
|
||||
null_value= 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -566,7 +568,9 @@ void Item_sum_sum::reset_field()
|
||||
{
|
||||
double nr=args[0]->val(); // Nulls also return 0
|
||||
float8store(result_field->ptr,nr);
|
||||
null_value=0;
|
||||
if (args[0]->null_value)
|
||||
result_field->set_null();
|
||||
else
|
||||
result_field->set_notnull();
|
||||
}
|
||||
|
||||
@ -623,7 +627,10 @@ void Item_sum_sum::update_field(int offset)
|
||||
float8get(old_nr,res+offset);
|
||||
nr=args[0]->val();
|
||||
if (!args[0]->null_value)
|
||||
{
|
||||
old_nr+=nr;
|
||||
result_field->set_notnull();
|
||||
}
|
||||
float8store(res,old_nr);
|
||||
}
|
||||
|
||||
|
@ -92,9 +92,6 @@ public:
|
||||
|
||||
class Item_sum_int :public Item_sum_num
|
||||
{
|
||||
void fix_length_and_dec()
|
||||
{ decimals=0; max_length=21; maybe_null=null_value=0; }
|
||||
|
||||
public:
|
||||
Item_sum_int(Item *item_par) :Item_sum_num(item_par) {}
|
||||
Item_sum_int(List<Item> &list) :Item_sum_num(list) {}
|
||||
@ -102,6 +99,8 @@ public:
|
||||
String *val_str(String*str);
|
||||
enum Item_result result_type () const { return INT_RESULT; }
|
||||
unsigned int size_of() { return sizeof(*this);}
|
||||
void fix_length_and_dec()
|
||||
{ decimals=0; max_length=21; maybe_null=null_value=0; }
|
||||
};
|
||||
|
||||
|
||||
@ -118,6 +117,7 @@ class Item_sum_sum :public Item_sum_num
|
||||
double val();
|
||||
void reset_field();
|
||||
void update_field(int offset);
|
||||
void no_rows_in_result() {}
|
||||
const char *func_name() const { return "sum"; }
|
||||
unsigned int size_of() { return sizeof(*this);}
|
||||
};
|
||||
@ -361,6 +361,8 @@ class Item_sum_bit :public Item_sum_int
|
||||
longlong val_int();
|
||||
void reset_field();
|
||||
unsigned int size_of() { return sizeof(*this);}
|
||||
void fix_length_and_dec()
|
||||
{ decimals=0; max_length=21; unsigned_flag=1; maybe_null=null_value=0; }
|
||||
};
|
||||
|
||||
|
||||
|
@ -921,6 +921,8 @@ void clean_up(bool print_message)
|
||||
free_max_user_conn();
|
||||
end_slave_list();
|
||||
#ifdef HAVE_OPENSSL
|
||||
if (ssl_acceptor_fd)
|
||||
my_free((gptr) ssl_acceptor_fd, MYF(MY_ALLOW_ZERO_PTR));
|
||||
free_des_key_file();
|
||||
#endif /* HAVE_OPENSSL */
|
||||
#ifdef USE_REGEX
|
||||
@ -3562,7 +3564,7 @@ relay logs",
|
||||
{"skip-stack-trace", OPT_SKIP_STACK_TRACE,
|
||||
"Don't print a stack trace on failure", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0,
|
||||
0, 0, 0, 0},
|
||||
{"skip-symlink", OPT_SKIP_SYMLINKS, "Don't allow symlinking of tables",
|
||||
{"skip-symlink", OPT_SKIP_SYMLINKS, "Don't allow symlinking of tables. Depricated option. Use --skip-symbolic-links instead",
|
||||
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
|
||||
{"skip-thread-priority", OPT_SKIP_PRIOR,
|
||||
"Don't give threads different priorities.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0,
|
||||
@ -3606,11 +3608,12 @@ replicating a LOAD DATA INFILE command",
|
||||
{"external-locking", OPT_USE_LOCKING, "Use system (external) locking. With this option enabled you can run myisamchk to test (not repair) tables while the MySQL server is running",
|
||||
(gptr*) &opt_external_locking, (gptr*) &opt_external_locking,
|
||||
0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
|
||||
#ifdef USE_SYMDIR
|
||||
{"use-symbolic-links", 's', "Enable symbolic link support",
|
||||
{"use-symbolic-links", 's', "Enable symbolic link support. Depricated option; Use --symbolic-links instead",
|
||||
(gptr*) &my_use_symdir, (gptr*) &my_use_symdir, 0, GET_BOOL, NO_ARG,
|
||||
IF_PURIFY(0,1), 0, 0, 0, 0, 0},
|
||||
{"--symbolic-links", 's', "Enable symbolic link support",
|
||||
(gptr*) &my_use_symdir, (gptr*) &my_use_symdir, 0, GET_BOOL, NO_ARG,
|
||||
IF_PURIFY(0,1), 0, 0, 0, 0, 0},
|
||||
#endif
|
||||
{"user", 'u', "Run mysqld daemon as user", 0, 0, 0, GET_STR, REQUIRED_ARG,
|
||||
0, 0, 0, 0, 0, 0},
|
||||
{"version", 'V', "Output version information and exit", 0, 0, 0, GET_NO_ARG,
|
||||
@ -4424,9 +4427,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
|
||||
delay_key_write_options= (uint) DELAY_KEY_WRITE_NONE;
|
||||
myisam_concurrent_insert=0;
|
||||
myisam_recover_options= HA_RECOVER_NONE;
|
||||
my_disable_symlinks=1;
|
||||
my_use_symdir=0;
|
||||
have_symlink=SHOW_OPTION_DISABLED;
|
||||
ha_open_options&= ~(HA_OPEN_ABORT_IF_CRASHED | HA_OPEN_DELAY_KEY_WRITE);
|
||||
#ifdef HAVE_QUERY_CACHE
|
||||
query_cache_size=0;
|
||||
@ -4473,9 +4474,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
|
||||
test_flags|=TEST_NO_STACKTRACE;
|
||||
break;
|
||||
case (int) OPT_SKIP_SYMLINKS:
|
||||
my_disable_symlinks=1;
|
||||
my_use_symdir=0;
|
||||
have_symlink=SHOW_OPTION_DISABLED;
|
||||
break;
|
||||
case (int) OPT_BIND_ADDRESS:
|
||||
if (argument && isdigit(argument[0]))
|
||||
|
@ -47,13 +47,6 @@
|
||||
can't normally do this the client should have a bigger max_allowed_packet.
|
||||
*/
|
||||
|
||||
#ifdef MYSQL_SERVER
|
||||
#define USE_QUERY_CACHE
|
||||
extern uint test_flags;
|
||||
extern void query_cache_insert(NET *net, const char *packet, ulong length);
|
||||
#else
|
||||
#endif
|
||||
|
||||
#if defined(__WIN__) || !defined(MYSQL_SERVER)
|
||||
/* The following is because alarms doesn't work on windows. */
|
||||
#define NO_ALARM
|
||||
@ -62,15 +55,22 @@ extern void query_cache_insert(NET *net, const char *packet, ulong length);
|
||||
#ifndef NO_ALARM
|
||||
#include "my_pthread.h"
|
||||
void sql_print_error(const char *format,...);
|
||||
#else
|
||||
#define DONT_USE_THR_ALARM
|
||||
#endif /* NO_ALARM */
|
||||
|
||||
#include "thr_alarm.h"
|
||||
|
||||
#ifdef MYSQL_SERVER
|
||||
#define USE_QUERY_CACHE
|
||||
extern uint test_flags;
|
||||
extern void query_cache_insert(NET *net, const char *packet, ulong length);
|
||||
extern ulong bytes_sent, bytes_received;
|
||||
extern pthread_mutex_t LOCK_bytes_sent , LOCK_bytes_received;
|
||||
#else
|
||||
#undef statistic_add
|
||||
#define statistic_add(A,B,C)
|
||||
#define DONT_USE_THR_ALARM
|
||||
#endif /* NO_ALARM */
|
||||
|
||||
#include "thr_alarm.h"
|
||||
#endif
|
||||
|
||||
#define TEST_BLOCKING 8
|
||||
#define MAX_PACKET_LENGTH (256L*256L*256L-1)
|
||||
|
@ -542,19 +542,19 @@ ulong acl_getroot(THD *thd, const char *host, const char *ip, const char *user,
|
||||
break;
|
||||
case SSL_TYPE_X509: /* Client should have any valid certificate. */
|
||||
/*
|
||||
Connections with non-valid certificates are dropped already
|
||||
in sslaccept() anyway, so we do not check validity here.
|
||||
We need to check for absence of SSL because without SSL
|
||||
we should reject connection.
|
||||
*/
|
||||
if (SSL_get_peer_certificate(vio->ssl_))
|
||||
if (vio_type(vio) == VIO_TYPE_SSL && SSL_get_peer_certificate(vio->ssl_))
|
||||
user_access=acl_user->access;
|
||||
break;
|
||||
case SSL_TYPE_SPECIFIED: /* Client should have specified attrib */
|
||||
/*
|
||||
We do not check for absence of SSL because without SSL it does
|
||||
not pass all checks here anyway.
|
||||
If cipher name is specified, we compare it to actual cipher in
|
||||
use.
|
||||
We need to check for absence of SSL because without SSL
|
||||
we should reject connection.
|
||||
*/
|
||||
if (vio_type(vio) == VIO_TYPE_SSL)
|
||||
{
|
||||
if (acl_user->ssl_cipher)
|
||||
{
|
||||
DBUG_PRINT("info",("comparing ciphers: '%s' and '%s'",
|
||||
@ -564,6 +564,10 @@ ulong acl_getroot(THD *thd, const char *host, const char *ip, const char *user,
|
||||
user_access=acl_user->access;
|
||||
else
|
||||
{
|
||||
if (global_system_variables.log_warnings)
|
||||
sql_print_error("X509 ciphers mismatch: should be '%s' but is '%s'",
|
||||
acl_user->ssl_cipher,
|
||||
SSL_get_cipher(vio->ssl_));
|
||||
user_access=NO_ACCESS;
|
||||
break;
|
||||
}
|
||||
@ -581,6 +585,9 @@ ulong acl_getroot(THD *thd, const char *host, const char *ip, const char *user,
|
||||
acl_user->x509_issuer, ptr));
|
||||
if (strcmp(acl_user->x509_issuer, ptr))
|
||||
{
|
||||
if (global_system_variables.log_warnings)
|
||||
sql_print_error("X509 issuer mismatch: should be '%s' but is '%s'",
|
||||
acl_user->x509_issuer, ptr);
|
||||
user_access=NO_ACCESS;
|
||||
free(ptr);
|
||||
break;
|
||||
@ -596,13 +603,19 @@ ulong acl_getroot(THD *thd, const char *host, const char *ip, const char *user,
|
||||
DBUG_PRINT("info",("comparing subjects: '%s' and '%s'",
|
||||
acl_user->x509_subject, ptr));
|
||||
if (strcmp(acl_user->x509_subject,ptr))
|
||||
{
|
||||
if (global_system_variables.log_warnings)
|
||||
sql_print_error("X509 subject mismatch: '%s' vs '%s'",
|
||||
acl_user->x509_subject, ptr);
|
||||
user_access=NO_ACCESS;
|
||||
}
|
||||
else
|
||||
user_access=acl_user->access;
|
||||
free(ptr);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
#else /* HAVE_OPENSSL */
|
||||
user_access=acl_user->access;
|
||||
#endif /* HAVE_OPENSSL */
|
||||
|
@ -1228,7 +1228,7 @@ int mysqld_show(THD *thd, const char *wild, show_var_st *variables,
|
||||
case SHOW_RPL_STATUS:
|
||||
net_store_data(&packet2, rpl_status_type[(int)rpl_status]);
|
||||
break;
|
||||
#ifndef EMBEDDED_LIBRARY
|
||||
#ifdef HAVE_REPLICATION
|
||||
case SHOW_SLAVE_RUNNING:
|
||||
{
|
||||
LOCK_ACTIVE_MI;
|
||||
|
@ -29,8 +29,8 @@ skip-locking
|
||||
set-variable = key_buffer=384M
|
||||
set-variable = max_allowed_packet=1M
|
||||
set-variable = table_cache=512
|
||||
set-variable = sort_buffer=2M
|
||||
set-variable = record_buffer=2M
|
||||
set-variable = sort_buffer_size=2M
|
||||
set-variable = read_buffer_size=2M
|
||||
set-variable = myisam_sort_buffer_size=64M
|
||||
set-variable = thread_cache=8
|
||||
# Try number of CPU's*2 for thread_concurrency
|
||||
@ -53,7 +53,36 @@ log-bin
|
||||
# but will not function as a master if omitted
|
||||
server-id = 1
|
||||
|
||||
# Replication Slave Server (comment out master section to use this)
|
||||
# Replication Slave (comment out master section to use this)
|
||||
#
|
||||
# To configure this host as a replication slave, you can choose between
|
||||
# two methods :
|
||||
#
|
||||
# 1) Use the CHANGE MASTER TO command (fully described in our manual) -
|
||||
# the syntax is:
|
||||
#
|
||||
# CHANGE MASTER TO MASTER_HOST=<host>, MASTER_PORT=<port>,
|
||||
# MASTER_USER=<user>, MASTER_PASSWORD=<password> ;
|
||||
#
|
||||
# where you replace <host>, <user>, <password> by quoted strings and
|
||||
# <port> by the master's port number (3306 by default).
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# CHANGE MASTER TO MASTER_HOST='125.564.12.1', MASTER_PORT=3306,
|
||||
# MASTER_USER='joe', MASTER_PASSWORD='secret';
|
||||
#
|
||||
# OR
|
||||
#
|
||||
# 2) Set the variables below. However, in case you choose this method, then
|
||||
# start replication for the first time (even unsuccessfully, for example
|
||||
# if you mistyped the password in master-password and the slave fails to
|
||||
# connect), the slave will create a master.info file, and any later
|
||||
# change in this file to the variables' values below will be ignored and
|
||||
# overridden by the content of the master.info file, unless you shutdown
|
||||
# the slave server, delete master.info and restart the slaver server.
|
||||
# For that reason, you may want to leave the lines below untouched
|
||||
# (commented) and instead use CHANGE MASTER TO (see above)
|
||||
#
|
||||
# required unique id between 2 and 2^32 - 1
|
||||
# (and different from the master)
|
||||
@ -113,13 +142,13 @@ no-auto-rehash
|
||||
|
||||
[isamchk]
|
||||
set-variable = key_buffer=256M
|
||||
set-variable = sort_buffer=256M
|
||||
set-variable = sort_buffer_size=256M
|
||||
set-variable = read_buffer=2M
|
||||
set-variable = write_buffer=2M
|
||||
|
||||
[myisamchk]
|
||||
set-variable = key_buffer=256M
|
||||
set-variable = sort_buffer=256M
|
||||
set-variable = sort_buffer_size=256M
|
||||
set-variable = read_buffer=2M
|
||||
set-variable = write_buffer=2M
|
||||
|
||||
|
@ -29,8 +29,8 @@ skip-locking
|
||||
set-variable = key_buffer=256M
|
||||
set-variable = max_allowed_packet=1M
|
||||
set-variable = table_cache=256
|
||||
set-variable = sort_buffer=1M
|
||||
set-variable = record_buffer=1M
|
||||
set-variable = sort_buffer_size=1M
|
||||
set-variable = read_buffer_size=1M
|
||||
set-variable = myisam_sort_buffer_size=64M
|
||||
set-variable = thread_cache=8
|
||||
# Try number of CPU's*2 for thread_concurrency
|
||||
@ -53,7 +53,36 @@ log-bin
|
||||
# but will not function as a master if omitted
|
||||
server-id = 1
|
||||
|
||||
# Replication Slave Server (comment out master section to use this)
|
||||
# Replication Slave (comment out master section to use this)
|
||||
#
|
||||
# To configure this host as a replication slave, you can choose between
|
||||
# two methods :
|
||||
#
|
||||
# 1) Use the CHANGE MASTER TO command (fully described in our manual) -
|
||||
# the syntax is:
|
||||
#
|
||||
# CHANGE MASTER TO MASTER_HOST=<host>, MASTER_PORT=<port>,
|
||||
# MASTER_USER=<user>, MASTER_PASSWORD=<password> ;
|
||||
#
|
||||
# where you replace <host>, <user>, <password> by quoted strings and
|
||||
# <port> by the master's port number (3306 by default).
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# CHANGE MASTER TO MASTER_HOST='125.564.12.1', MASTER_PORT=3306,
|
||||
# MASTER_USER='joe', MASTER_PASSWORD='secret';
|
||||
#
|
||||
# OR
|
||||
#
|
||||
# 2) Set the variables below. However, in case you choose this method, then
|
||||
# start replication for the first time (even unsuccessfully, for example
|
||||
# if you mistyped the password in master-password and the slave fails to
|
||||
# connect), the slave will create a master.info file, and any later
|
||||
# change in this file to the variables' values below will be ignored and
|
||||
# overridden by the content of the master.info file, unless you shutdown
|
||||
# the slave server, delete master.info and restart the slaver server.
|
||||
# For that reason, you may want to leave the lines below untouched
|
||||
# (commented) and instead use CHANGE MASTER TO (see above)
|
||||
#
|
||||
# required unique id between 2 and 2^32 - 1
|
||||
# (and different from the master)
|
||||
@ -113,13 +142,13 @@ no-auto-rehash
|
||||
|
||||
[isamchk]
|
||||
set-variable = key_buffer=128M
|
||||
set-variable = sort_buffer=128M
|
||||
set-variable = sort_buffer_size=128M
|
||||
set-variable = read_buffer=2M
|
||||
set-variable = write_buffer=2M
|
||||
|
||||
[myisamchk]
|
||||
set-variable = key_buffer=128M
|
||||
set-variable = sort_buffer=128M
|
||||
set-variable = sort_buffer_size=128M
|
||||
set-variable = read_buffer=2M
|
||||
set-variable = write_buffer=2M
|
||||
|
||||
|
@ -30,7 +30,7 @@ skip-locking
|
||||
set-variable = key_buffer=16M
|
||||
set-variable = max_allowed_packet=1M
|
||||
set-variable = table_cache=64
|
||||
set-variable = sort_buffer=512K
|
||||
set-variable = sort_buffer_size=512K
|
||||
set-variable = net_buffer_length=8K
|
||||
set-variable = myisam_sort_buffer_size=8M
|
||||
|
||||
@ -51,7 +51,36 @@ log-bin
|
||||
# but will not function as a master if omitted
|
||||
server-id = 1
|
||||
|
||||
# Replication Slave Server (comment out master section to use this)
|
||||
# Replication Slave (comment out master section to use this)
|
||||
#
|
||||
# To configure this host as a replication slave, you can choose between
|
||||
# two methods :
|
||||
#
|
||||
# 1) Use the CHANGE MASTER TO command (fully described in our manual) -
|
||||
# the syntax is:
|
||||
#
|
||||
# CHANGE MASTER TO MASTER_HOST=<host>, MASTER_PORT=<port>,
|
||||
# MASTER_USER=<user>, MASTER_PASSWORD=<password> ;
|
||||
#
|
||||
# where you replace <host>, <user>, <password> by quoted strings and
|
||||
# <port> by the master's port number (3306 by default).
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# CHANGE MASTER TO MASTER_HOST='125.564.12.1', MASTER_PORT=3306,
|
||||
# MASTER_USER='joe', MASTER_PASSWORD='secret';
|
||||
#
|
||||
# OR
|
||||
#
|
||||
# 2) Set the variables below. However, in case you choose this method, then
|
||||
# start replication for the first time (even unsuccessfully, for example
|
||||
# if you mistyped the password in master-password and the slave fails to
|
||||
# connect), the slave will create a master.info file, and any later
|
||||
# change in this file to the variables' values below will be ignored and
|
||||
# overridden by the content of the master.info file, unless you shutdown
|
||||
# the slave server, delete master.info and restart the slaver server.
|
||||
# For that reason, you may want to leave the lines below untouched
|
||||
# (commented) and instead use CHANGE MASTER TO (see above)
|
||||
#
|
||||
# required unique id between 2 and 2^32 - 1
|
||||
# (and different from the master)
|
||||
@ -111,13 +140,13 @@ no-auto-rehash
|
||||
|
||||
[isamchk]
|
||||
set-variable = key_buffer=20M
|
||||
set-variable = sort_buffer=20M
|
||||
set-variable = sort_buffer_size=20M
|
||||
set-variable = read_buffer=2M
|
||||
set-variable = write_buffer=2M
|
||||
|
||||
[myisamchk]
|
||||
set-variable = key_buffer=20M
|
||||
set-variable = sort_buffer=20M
|
||||
set-variable = sort_buffer_size=20M
|
||||
set-variable = read_buffer=2M
|
||||
set-variable = write_buffer=2M
|
||||
|
||||
|
@ -29,10 +29,18 @@ socket = @MYSQL_UNIX_ADDR@
|
||||
skip-locking
|
||||
set-variable = key_buffer=16K
|
||||
set-variable = max_allowed_packet=1M
|
||||
set-variable = thread_stack=64K
|
||||
set-variable = table_cache=4
|
||||
set-variable = sort_buffer=64K
|
||||
set-variable = sort_buffer_size=64K
|
||||
set-variable = net_buffer_length=2K
|
||||
set-variable = thread_stack=64K
|
||||
|
||||
# Don't listen on a TCP/IP port at all. This can be a security enhancement,
|
||||
# if all processes that need to connect to mysqld run on the same host.
|
||||
# All interaction with mysqld must be made via Unix sockets or named pipes.
|
||||
# Note that using this option without enabling named pipes on Windows
|
||||
# (via the "pipe" option) will render mysqld useless!
|
||||
#
|
||||
#skip-networking
|
||||
server-id = 1
|
||||
|
||||
# Uncomment the following if you want to log updates
|
||||
@ -67,11 +75,11 @@ no-auto-rehash
|
||||
|
||||
[isamchk]
|
||||
set-variable = key_buffer=8M
|
||||
set-variable = sort_buffer=8M
|
||||
set-variable = sort_buffer_size=8M
|
||||
|
||||
[myisamchk]
|
||||
set-variable = key_buffer=8M
|
||||
set-variable = sort_buffer=8M
|
||||
set-variable = sort_buffer_size=8M
|
||||
|
||||
[mysqlhotcopy]
|
||||
interactive-timeout
|
||||
|
@ -281,7 +281,8 @@ int sslaccept(struct st_VioSSLAcceptorFd* ptr, Vio* vio, long timeout)
|
||||
SSL_SESSION_set_timeout(SSL_get_session(vio->ssl_), timeout);
|
||||
SSL_set_fd(vio->ssl_,vio->sd);
|
||||
SSL_set_accept_state(vio->ssl_);
|
||||
if (SSL_do_handshake(vio->ssl_) < 1)
|
||||
if (SSL_do_handshake(vio->ssl_) < 1 ||
|
||||
SSL_get_verify_result(vio->ssl_) != X509_V_OK)
|
||||
{
|
||||
DBUG_PRINT("error", ("SSL_do_handshake failure"));
|
||||
report_errors();
|
||||
@ -354,7 +355,8 @@ int sslconnect(struct st_VioSSLConnectorFd* ptr, Vio* vio, long timeout)
|
||||
SSL_SESSION_set_timeout(SSL_get_session(vio->ssl_), timeout);
|
||||
SSL_set_fd (vio->ssl_, vio->sd);
|
||||
SSL_set_connect_state(vio->ssl_);
|
||||
if (SSL_do_handshake(vio->ssl_) < 1)
|
||||
if (SSL_do_handshake(vio->ssl_) < 1 ||
|
||||
SSL_get_verify_result(vio->ssl_) != X509_V_OK)
|
||||
{
|
||||
DBUG_PRINT("error", ("SSL_do_handshake failure"));
|
||||
report_errors();
|
||||
|
Reference in New Issue
Block a user