mirror of
https://github.com/MariaDB/server.git
synced 2025-07-29 05:21:33 +03:00
Many files:
Implement ON DELETE CASCADE and facilitate switching off of UNIQUE constraints and foreign keys innobase/btr/btr0cur.c: Implement ON DELETE CASCADE and facilitate switching off of UNIQUE constraints and foreign keys innobase/dict/dict0crea.c: Implement ON DELETE CASCADE and facilitate switching off of UNIQUE constraints and foreign keys innobase/dict/dict0dict.c: Implement ON DELETE CASCADE and facilitate switching off of UNIQUE constraints and foreign keys innobase/dict/dict0load.c: Implement ON DELETE CASCADE and facilitate switching off of UNIQUE constraints and foreign keys innobase/dict/dict0mem.c: Implement ON DELETE CASCADE and facilitate switching off of UNIQUE constraints and foreign keys innobase/include/btr0btr.h: Implement ON DELETE CASCADE and facilitate switching off of UNIQUE constraints and foreign keys innobase/include/dict0mem.h: Implement ON DELETE CASCADE and facilitate switching off of UNIQUE constraints and foreign keys innobase/include/ibuf0ibuf.h: Implement ON DELETE CASCADE and facilitate switching off of UNIQUE constraints and foreign keys innobase/include/os0file.h: Implement ON DELETE CASCADE and facilitate switching off of UNIQUE constraints and foreign keys innobase/include/os0sync.h: Implement ON DELETE CASCADE and facilitate switching off of UNIQUE constraints and foreign keys innobase/include/row0mysql.h: Implement ON DELETE CASCADE and facilitate switching off of UNIQUE constraints and foreign keys innobase/include/row0upd.h: Implement ON DELETE CASCADE and facilitate switching off of UNIQUE constraints and foreign keys innobase/include/sync0sync.h: Implement ON DELETE CASCADE and facilitate switching off of UNIQUE constraints and foreign keys innobase/include/trx0sys.h: Implement ON DELETE CASCADE and facilitate switching off of UNIQUE constraints and foreign keys innobase/include/trx0trx.h: Implement ON DELETE CASCADE and facilitate switching off of UNIQUE constraints and foreign keys innobase/include/ibuf0ibuf.ic: Implement ON DELETE CASCADE and facilitate switching off of UNIQUE constraints and foreign keys innobase/include/os0sync.ic: Implement ON DELETE CASCADE and facilitate switching off of UNIQUE constraints and foreign keys innobase/include/sync0sync.ic: Implement ON DELETE CASCADE and facilitate switching off of UNIQUE constraints and foreign keys innobase/include/trx0sys.ic: Implement ON DELETE CASCADE and facilitate switching off of UNIQUE constraints and foreign keys innobase/lock/lock0lock.c: Implement ON DELETE CASCADE and facilitate switching off of UNIQUE constraints and foreign keys innobase/pars/pars0opt.c: Implement ON DELETE CASCADE and facilitate switching off of UNIQUE constraints and foreign keys innobase/que/que0que.c: Implement ON DELETE CASCADE and facilitate switching off of UNIQUE constraints and foreign keys innobase/row/row0ins.c: Implement ON DELETE CASCADE and facilitate switching off of UNIQUE constraints and foreign keys innobase/row/row0mysql.c: Implement ON DELETE CASCADE and facilitate switching off of UNIQUE constraints and foreign keys innobase/row/row0sel.c: Implement ON DELETE CASCADE and facilitate switching off of UNIQUE constraints and foreign keys innobase/row/row0upd.c: Implement ON DELETE CASCADE and facilitate switching off of UNIQUE constraints and foreign keys innobase/srv/srv0srv.c: Implement ON DELETE CASCADE and facilitate switching off of UNIQUE constraints and foreign keys innobase/sync/sync0sync.c: Implement ON DELETE CASCADE and facilitate switching off of UNIQUE constraints and foreign keys innobase/trx/trx0sys.c: Implement ON DELETE CASCADE and facilitate switching off of UNIQUE constraints and foreign keys innobase/trx/trx0trx.c: Implement ON DELETE CASCADE and facilitate switching off of UNIQUE constraints and foreign keys
This commit is contained in:
@ -228,6 +228,7 @@ btr_cur_search_to_nth_level(
|
|||||||
ulint insert_planned;
|
ulint insert_planned;
|
||||||
ulint buf_mode;
|
ulint buf_mode;
|
||||||
ulint estimate;
|
ulint estimate;
|
||||||
|
ulint ignore_sec_unique;
|
||||||
ulint root_height;
|
ulint root_height;
|
||||||
#ifdef BTR_CUR_ADAPT
|
#ifdef BTR_CUR_ADAPT
|
||||||
btr_search_t* info;
|
btr_search_t* info;
|
||||||
@ -246,7 +247,9 @@ btr_cur_search_to_nth_level(
|
|||||||
#endif
|
#endif
|
||||||
insert_planned = latch_mode & BTR_INSERT;
|
insert_planned = latch_mode & BTR_INSERT;
|
||||||
estimate = latch_mode & BTR_ESTIMATE;
|
estimate = latch_mode & BTR_ESTIMATE;
|
||||||
latch_mode = latch_mode & ~(BTR_INSERT | BTR_ESTIMATE);
|
ignore_sec_unique = latch_mode & BTR_IGNORE_SEC_UNIQUE;
|
||||||
|
latch_mode = latch_mode & ~(BTR_INSERT | BTR_ESTIMATE
|
||||||
|
| BTR_IGNORE_SEC_UNIQUE);
|
||||||
|
|
||||||
ut_ad(!insert_planned || (mode == PAGE_CUR_LE));
|
ut_ad(!insert_planned || (mode == PAGE_CUR_LE));
|
||||||
|
|
||||||
@ -343,7 +346,8 @@ btr_cur_search_to_nth_level(
|
|||||||
|
|
||||||
rw_latch = latch_mode;
|
rw_latch = latch_mode;
|
||||||
|
|
||||||
if (insert_planned && ibuf_should_try(index)) {
|
if (insert_planned && ibuf_should_try(index,
|
||||||
|
ignore_sec_unique)) {
|
||||||
|
|
||||||
/* Try insert to the insert buffer if the
|
/* Try insert to the insert buffer if the
|
||||||
page is not in the buffer pool */
|
page is not in the buffer pool */
|
||||||
@ -356,7 +360,6 @@ retry_page_get:
|
|||||||
buf_mode,
|
buf_mode,
|
||||||
IB__FILE__, __LINE__,
|
IB__FILE__, __LINE__,
|
||||||
mtr);
|
mtr);
|
||||||
|
|
||||||
if (page == NULL) {
|
if (page == NULL) {
|
||||||
/* This must be a search to perform an insert;
|
/* This must be a search to perform an insert;
|
||||||
try insert to the insert buffer */
|
try insert to the insert buffer */
|
||||||
@ -365,7 +368,7 @@ retry_page_get:
|
|||||||
ut_ad(insert_planned);
|
ut_ad(insert_planned);
|
||||||
ut_ad(cursor->thr);
|
ut_ad(cursor->thr);
|
||||||
|
|
||||||
if (ibuf_should_try(index) &&
|
if (ibuf_should_try(index, ignore_sec_unique) &&
|
||||||
ibuf_insert(tuple, index, space, page_no,
|
ibuf_insert(tuple, index, space, page_no,
|
||||||
cursor->thr)) {
|
cursor->thr)) {
|
||||||
/* Insertion to the insert buffer succeeded */
|
/* Insertion to the insert buffer succeeded */
|
||||||
|
@ -1201,7 +1201,8 @@ loop:
|
|||||||
ut_dulint_get_low(id),
|
ut_dulint_get_low(id),
|
||||||
table->name,
|
table->name,
|
||||||
foreign->referenced_table_name,
|
foreign->referenced_table_name,
|
||||||
foreign->n_fields);
|
foreign->n_fields
|
||||||
|
+ (foreign->type << 24));
|
||||||
|
|
||||||
for (i = 0; i < foreign->n_fields; i++) {
|
for (i = 0; i < foreign->n_fields; i++) {
|
||||||
|
|
||||||
|
@ -1648,7 +1648,7 @@ dict_foreign_find_index(
|
|||||||
->col->name;
|
->col->name;
|
||||||
if (ut_strlen(columns[i]) !=
|
if (ut_strlen(columns[i]) !=
|
||||||
ut_strlen(col_name)
|
ut_strlen(col_name)
|
||||||
|| 0 != ut_memcmp(columns[i],
|
|| 0 != ut_cmp_in_lower_case(columns[i],
|
||||||
col_name,
|
col_name,
|
||||||
ut_strlen(col_name))) {
|
ut_strlen(col_name))) {
|
||||||
break;
|
break;
|
||||||
@ -1853,8 +1853,9 @@ dict_scan_col(
|
|||||||
ibool* success,/* out: TRUE if success */
|
ibool* success,/* out: TRUE if success */
|
||||||
dict_table_t* table, /* in: table in which the column is */
|
dict_table_t* table, /* in: table in which the column is */
|
||||||
dict_col_t** column, /* out: pointer to column if success */
|
dict_col_t** column, /* out: pointer to column if success */
|
||||||
char** column_name)/* out: pointer to column->name if
|
char** column_name,/* out: pointer to column->name if
|
||||||
success */
|
success */
|
||||||
|
ulint* column_name_len)/* out: column name length */
|
||||||
{
|
{
|
||||||
dict_col_t* col;
|
dict_col_t* col;
|
||||||
char* old_ptr;
|
char* old_ptr;
|
||||||
@ -1882,6 +1883,13 @@ dict_scan_col(
|
|||||||
ptr++;
|
ptr++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*column_name_len = (ulint)(ptr - old_ptr);
|
||||||
|
|
||||||
|
if (table == NULL) {
|
||||||
|
*success = TRUE;
|
||||||
|
*column = NULL;
|
||||||
|
*column_name = old_ptr;
|
||||||
|
} else {
|
||||||
for (i = 0; i < dict_table_get_n_cols(table); i++) {
|
for (i = 0; i < dict_table_get_n_cols(table); i++) {
|
||||||
|
|
||||||
col = dict_table_get_nth_col(table, i);
|
col = dict_table_get_nth_col(table, i);
|
||||||
@ -1898,6 +1906,7 @@ dict_scan_col(
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (*ptr == '`') {
|
if (*ptr == '`') {
|
||||||
ptr++;
|
ptr++;
|
||||||
@ -1914,14 +1923,18 @@ dict_scan_table_name(
|
|||||||
/*=================*/
|
/*=================*/
|
||||||
/* out: scanned to */
|
/* out: scanned to */
|
||||||
char* ptr, /* in: scanned to */
|
char* ptr, /* in: scanned to */
|
||||||
dict_table_t** table, /* out: table object or NULL if error */
|
dict_table_t** table, /* out: table object or NULL */
|
||||||
char* name) /* in: foreign key table name */
|
char* name, /* in: foreign key table name */
|
||||||
|
ibool* success,/* out: TRUE if ok name found */
|
||||||
|
char* second_table_name)/* in/out: buffer where to store
|
||||||
|
the referenced table name; must be at least
|
||||||
|
2500 bytes */
|
||||||
{
|
{
|
||||||
char* dot_ptr = NULL;
|
char* dot_ptr = NULL;
|
||||||
char* old_ptr;
|
char* old_ptr;
|
||||||
ulint i;
|
ulint i;
|
||||||
char second_table_name[10000];
|
|
||||||
|
|
||||||
|
*success = FALSE;
|
||||||
*table = NULL;
|
*table = NULL;
|
||||||
|
|
||||||
while (isspace(*ptr)) {
|
while (isspace(*ptr)) {
|
||||||
@ -1947,7 +1960,7 @@ dict_scan_table_name(
|
|||||||
ptr++;
|
ptr++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ptr - old_ptr > 9000) {
|
if (ptr - old_ptr > 2000) {
|
||||||
return(old_ptr);
|
return(old_ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1978,6 +1991,8 @@ dict_scan_table_name(
|
|||||||
second_table_name[ptr - old_ptr] = '\0';
|
second_table_name[ptr - old_ptr] = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*success = TRUE;
|
||||||
|
|
||||||
*table = dict_table_get_low(second_table_name);
|
*table = dict_table_get_low(second_table_name);
|
||||||
|
|
||||||
if (*ptr == '`') {
|
if (*ptr == '`') {
|
||||||
@ -2043,8 +2058,11 @@ dict_create_foreign_constraints(
|
|||||||
ibool success;
|
ibool success;
|
||||||
ulint error;
|
ulint error;
|
||||||
ulint i;
|
ulint i;
|
||||||
dict_col_t* columns[1000];
|
ulint j;
|
||||||
char* column_names[1000];
|
dict_col_t* columns[500];
|
||||||
|
char* column_names[500];
|
||||||
|
ulint column_name_lens[500];
|
||||||
|
char referenced_table_name[2500];
|
||||||
|
|
||||||
ut_ad(mutex_own(&(dict_sys->mutex)));
|
ut_ad(mutex_own(&(dict_sys->mutex)));
|
||||||
|
|
||||||
@ -2090,7 +2108,7 @@ loop:
|
|||||||
/* Scan the columns in the first list */
|
/* Scan the columns in the first list */
|
||||||
col_loop1:
|
col_loop1:
|
||||||
ptr = dict_scan_col(ptr, &success, table, columns + i,
|
ptr = dict_scan_col(ptr, &success, table, columns + i,
|
||||||
column_names + i);
|
column_names + i, column_name_lens + i);
|
||||||
if (!success) {
|
if (!success) {
|
||||||
return(DB_CANNOT_ADD_CONSTRAINT);
|
return(DB_CANNOT_ADD_CONSTRAINT);
|
||||||
}
|
}
|
||||||
@ -2141,9 +2159,13 @@ col_loop1:
|
|||||||
1 + ut_strlen(columns[i]->name));
|
1 + ut_strlen(columns[i]->name));
|
||||||
}
|
}
|
||||||
|
|
||||||
ptr = dict_scan_table_name(ptr, &referenced_table, name);
|
ptr = dict_scan_table_name(ptr, &referenced_table, name,
|
||||||
|
&success, referenced_table_name);
|
||||||
|
|
||||||
if (!referenced_table) {
|
/* Note that referenced_table can be NULL if the user has suppressed
|
||||||
|
checking of foreign key constraints! */
|
||||||
|
|
||||||
|
if (!success || (!referenced_table && trx->check_foreigns)) {
|
||||||
dict_foreign_free(foreign);
|
dict_foreign_free(foreign);
|
||||||
|
|
||||||
return(DB_CANNOT_ADD_CONSTRAINT);
|
return(DB_CANNOT_ADD_CONSTRAINT);
|
||||||
@ -2161,7 +2183,7 @@ col_loop1:
|
|||||||
|
|
||||||
col_loop2:
|
col_loop2:
|
||||||
ptr = dict_scan_col(ptr, &success, referenced_table, columns + i,
|
ptr = dict_scan_col(ptr, &success, referenced_table, columns + i,
|
||||||
column_names + i);
|
column_names + i, column_name_lens + i);
|
||||||
i++;
|
i++;
|
||||||
|
|
||||||
if (!success) {
|
if (!success) {
|
||||||
@ -2183,43 +2205,104 @@ col_loop2:
|
|||||||
return(DB_CANNOT_ADD_CONSTRAINT);
|
return(DB_CANNOT_ADD_CONSTRAINT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ptr = dict_accept(ptr, "ON", &success);
|
||||||
|
|
||||||
|
if (!success) {
|
||||||
|
|
||||||
|
goto try_find_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
ptr = dict_accept(ptr, "DELETE", &success);
|
||||||
|
|
||||||
|
if (!success) {
|
||||||
|
|
||||||
|
goto try_find_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
ptr = dict_accept(ptr, "CASCADE", &success);
|
||||||
|
|
||||||
|
if (success) {
|
||||||
|
|
||||||
|
foreign->type = DICT_FOREIGN_ON_DELETE_CASCADE;
|
||||||
|
|
||||||
|
goto try_find_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
ptr = dict_accept(ptr, "SET", &success);
|
||||||
|
|
||||||
|
if (!success) {
|
||||||
|
|
||||||
|
goto try_find_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
ptr = dict_accept(ptr, "NULL", &success);
|
||||||
|
|
||||||
|
if (success) {
|
||||||
|
for (j = 0; j < foreign->n_fields; j++) {
|
||||||
|
if ((dict_index_get_nth_type(
|
||||||
|
foreign->foreign_index, j)->prtype)
|
||||||
|
& DATA_NOT_NULL) {
|
||||||
|
|
||||||
|
/* It is not sensible to define SET NULL
|
||||||
|
if the column is not allowed to be NULL! */
|
||||||
|
|
||||||
|
dict_foreign_free(foreign);
|
||||||
|
return(DB_CANNOT_ADD_CONSTRAINT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreign->type = DICT_FOREIGN_ON_DELETE_SET_NULL;
|
||||||
|
|
||||||
|
goto try_find_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
try_find_index:
|
||||||
/* Try to find an index which contains the columns as the first fields
|
/* Try to find an index which contains the columns as the first fields
|
||||||
and in the right order, and the types are the same as in
|
and in the right order, and the types are the same as in
|
||||||
foreign->foreign_index */
|
foreign->foreign_index */
|
||||||
|
|
||||||
index = dict_foreign_find_index(referenced_table, column_names, i,
|
if (referenced_table) {
|
||||||
|
index = dict_foreign_find_index(referenced_table,
|
||||||
|
column_names, i,
|
||||||
foreign->foreign_index);
|
foreign->foreign_index);
|
||||||
|
|
||||||
if (!index) {
|
if (!index) {
|
||||||
dict_foreign_free(foreign);
|
dict_foreign_free(foreign);
|
||||||
return(DB_CANNOT_ADD_CONSTRAINT);
|
return(DB_CANNOT_ADD_CONSTRAINT);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
ut_a(trx->check_foreigns == FALSE);
|
||||||
|
index = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
foreign->referenced_index = index;
|
foreign->referenced_index = index;
|
||||||
foreign->referenced_table = referenced_table;
|
foreign->referenced_table = referenced_table;
|
||||||
|
|
||||||
foreign->referenced_table_name = mem_heap_alloc(foreign->heap,
|
foreign->referenced_table_name = mem_heap_alloc(foreign->heap,
|
||||||
1 + ut_strlen(referenced_table->name));
|
1 + ut_strlen(referenced_table_name));
|
||||||
|
|
||||||
ut_memcpy(foreign->referenced_table_name, referenced_table->name,
|
ut_memcpy(foreign->referenced_table_name, referenced_table_name,
|
||||||
1 + ut_strlen(referenced_table->name));
|
1 + ut_strlen(referenced_table_name));
|
||||||
|
|
||||||
foreign->referenced_col_names = mem_heap_alloc(foreign->heap,
|
foreign->referenced_col_names = mem_heap_alloc(foreign->heap,
|
||||||
i * sizeof(void*));
|
i * sizeof(void*));
|
||||||
for (i = 0; i < foreign->n_fields; i++) {
|
for (i = 0; i < foreign->n_fields; i++) {
|
||||||
foreign->referenced_col_names[i]
|
foreign->referenced_col_names[i]
|
||||||
= mem_heap_alloc(foreign->heap,
|
= mem_heap_alloc(foreign->heap,
|
||||||
1 + ut_strlen(columns[i]->name));
|
1 + column_name_lens[i]);
|
||||||
ut_memcpy(
|
ut_memcpy(foreign->referenced_col_names[i], column_names[i],
|
||||||
foreign->referenced_col_names[i], columns[i]->name,
|
column_name_lens[i]);
|
||||||
1 + ut_strlen(columns[i]->name));
|
(foreign->referenced_col_names[i])[column_name_lens[i]] = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We found an ok constraint definition: add to the lists */
|
/* We found an ok constraint definition: add to the lists */
|
||||||
|
|
||||||
UT_LIST_ADD_LAST(foreign_list, table->foreign_list, foreign);
|
UT_LIST_ADD_LAST(foreign_list, table->foreign_list, foreign);
|
||||||
UT_LIST_ADD_LAST(referenced_list, referenced_table->referenced_list,
|
|
||||||
|
if (referenced_table) {
|
||||||
|
UT_LIST_ADD_LAST(referenced_list,
|
||||||
|
referenced_table->referenced_list,
|
||||||
foreign);
|
foreign);
|
||||||
|
}
|
||||||
goto loop;
|
goto loop;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3034,6 +3117,14 @@ dict_print_info_on_foreign_keys_in_create_format(
|
|||||||
|
|
||||||
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");
|
||||||
|
}
|
||||||
|
|
||||||
foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
|
foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -947,6 +947,11 @@ dict_load_foreign(
|
|||||||
|
|
||||||
ut_a(len == 4);
|
ut_a(len == 4);
|
||||||
|
|
||||||
|
/* We store the type to the bits 24-31 of n_fields */
|
||||||
|
|
||||||
|
foreign->type = foreign->n_fields >> 24;
|
||||||
|
foreign->n_fields = foreign->n_fields & 0xFFFFFF;
|
||||||
|
|
||||||
foreign->id = mem_heap_alloc(foreign->heap, ut_strlen(id) + 1);
|
foreign->id = mem_heap_alloc(foreign->heap, ut_strlen(id) + 1);
|
||||||
|
|
||||||
ut_memcpy(foreign->id, id, ut_strlen(id) + 1);
|
ut_memcpy(foreign->id, id, ut_strlen(id) + 1);
|
||||||
|
@ -61,6 +61,7 @@ dict_mem_table_create(
|
|||||||
table->mem_fix = 0;
|
table->mem_fix = 0;
|
||||||
|
|
||||||
table->n_mysql_handles_opened = 0;
|
table->n_mysql_handles_opened = 0;
|
||||||
|
table->n_foreign_key_checks_running = 0;
|
||||||
|
|
||||||
table->cached = FALSE;
|
table->cached = FALSE;
|
||||||
|
|
||||||
@ -235,6 +236,7 @@ dict_mem_foreign_create(void)
|
|||||||
|
|
||||||
foreign->id = NULL;
|
foreign->id = NULL;
|
||||||
|
|
||||||
|
foreign->type = 0;
|
||||||
foreign->foreign_table_name = NULL;
|
foreign->foreign_table_name = NULL;
|
||||||
foreign->foreign_table = NULL;
|
foreign->foreign_table = NULL;
|
||||||
foreign->foreign_col_names = NULL;
|
foreign->foreign_col_names = NULL;
|
||||||
|
@ -49,6 +49,12 @@ inserted to the index, at the searched position */
|
|||||||
/* This flag ORed to latch mode says that we do the search in query
|
/* This flag ORed to latch mode says that we do the search in query
|
||||||
optimization */
|
optimization */
|
||||||
#define BTR_ESTIMATE 1024
|
#define BTR_ESTIMATE 1024
|
||||||
|
|
||||||
|
/* This flag ORed to latch mode says that we can ignore possible
|
||||||
|
UNIQUE definition on secondary indexes when we decide if we can use the
|
||||||
|
insert buffer to speed up inserts */
|
||||||
|
#define BTR_IGNORE_SEC_UNIQUE 2048
|
||||||
|
|
||||||
/******************************************************************
|
/******************************************************************
|
||||||
Gets a buffer page and declares its latching order level. */
|
Gets a buffer page and declares its latching order level. */
|
||||||
UNIV_INLINE
|
UNIV_INLINE
|
||||||
|
@ -249,6 +249,8 @@ struct dict_foreign_struct{
|
|||||||
this memory heap */
|
this memory heap */
|
||||||
char* id; /* id of the constraint as a
|
char* id; /* id of the constraint as a
|
||||||
null-terminated string */
|
null-terminated string */
|
||||||
|
ulint type; /* 0 or DICT_FOREIGN_ON_DELETE_CASCADE
|
||||||
|
or DICT_FOREIGN_ON_DELETE_SET_NULL */
|
||||||
char* foreign_table_name;/* foreign table name */
|
char* foreign_table_name;/* foreign table name */
|
||||||
dict_table_t* foreign_table; /* table where the foreign key is */
|
dict_table_t* foreign_table; /* table where the foreign key is */
|
||||||
char** foreign_col_names;/* names of the columns in the
|
char** foreign_col_names;/* names of the columns in the
|
||||||
@ -278,6 +280,9 @@ struct dict_foreign_struct{
|
|||||||
table */
|
table */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define DICT_FOREIGN_ON_DELETE_CASCADE 1
|
||||||
|
#define DICT_FOREIGN_ON_DELETE_SET_NULL 2
|
||||||
|
|
||||||
#define DICT_INDEX_MAGIC_N 76789786
|
#define DICT_INDEX_MAGIC_N 76789786
|
||||||
|
|
||||||
/* Data structure for a database table */
|
/* Data structure for a database table */
|
||||||
@ -313,6 +318,12 @@ struct dict_table_struct{
|
|||||||
NOT allowed until this count gets to zero;
|
NOT allowed until this count gets to zero;
|
||||||
MySQL does NOT itself check the number of
|
MySQL does NOT itself check the number of
|
||||||
open handles at drop */
|
open handles at drop */
|
||||||
|
ulint n_foreign_key_checks_running;
|
||||||
|
/* count of how many foreign key check
|
||||||
|
operations are currently being performed
|
||||||
|
on the table: we cannot drop the table while
|
||||||
|
there are foreign key checks running on
|
||||||
|
it! */
|
||||||
ibool cached; /* TRUE if the table object has been added
|
ibool cached; /* TRUE if the table object has been added
|
||||||
to the dictionary cache */
|
to the dictionary cache */
|
||||||
lock_t* auto_inc_lock;/* a buffer for an auto-inc lock
|
lock_t* auto_inc_lock;/* a buffer for an auto-inc lock
|
||||||
@ -359,17 +370,16 @@ struct dict_table_struct{
|
|||||||
after database startup or table creation */
|
after database startup or table creation */
|
||||||
ulint stat_modified_counter;
|
ulint stat_modified_counter;
|
||||||
/* when a row is inserted, updated, or deleted,
|
/* when a row is inserted, updated, or deleted,
|
||||||
we add the row length to this number; we
|
we add 1 to this number; we calculate new
|
||||||
calculate new estimates for the stat_...
|
estimates for the stat_... values for the
|
||||||
values for the table and the indexes at an
|
table and the indexes at an interval of 2 GB
|
||||||
interval of 2 GB or when about 1 / 16 of table
|
or when about 1 / 16 of table has been
|
||||||
has been modified; also
|
modified; also when the estimate operation is
|
||||||
when the estimate operation is called
|
called for MySQL SHOW TABLE STATUS; the
|
||||||
for MySQL SHOW TABLE STATUS; the counter is
|
counter is reset to zero at statistics
|
||||||
reset to zero at statistics calculation;
|
calculation; this counter is not protected by
|
||||||
this counter
|
any latch, because this is only used for
|
||||||
is not protected by any latch, because this
|
heuristics */
|
||||||
is only used for heuristics */
|
|
||||||
/*----------------------*/
|
/*----------------------*/
|
||||||
mutex_t autoinc_mutex;
|
mutex_t autoinc_mutex;
|
||||||
/* mutex protecting the autoincrement
|
/* mutex protecting the autoincrement
|
||||||
|
@ -127,7 +127,11 @@ UNIV_INLINE
|
|||||||
ibool
|
ibool
|
||||||
ibuf_should_try(
|
ibuf_should_try(
|
||||||
/*============*/
|
/*============*/
|
||||||
dict_index_t* index); /* in: index where to insert */
|
dict_index_t* index, /* in: index where to insert */
|
||||||
|
ulint ignore_sec_unique); /* in: if != 0, we should
|
||||||
|
ignore UNIQUE constraint on
|
||||||
|
a secondary index when we
|
||||||
|
decide */
|
||||||
/**********************************************************************
|
/**********************************************************************
|
||||||
Returns TRUE if the current OS thread is performing an insert buffer
|
Returns TRUE if the current OS thread is performing an insert buffer
|
||||||
routine. */
|
routine. */
|
||||||
|
@ -81,10 +81,16 @@ UNIV_INLINE
|
|||||||
ibool
|
ibool
|
||||||
ibuf_should_try(
|
ibuf_should_try(
|
||||||
/*============*/
|
/*============*/
|
||||||
dict_index_t* index) /* in: index where to insert */
|
dict_index_t* index, /* in: index where to insert */
|
||||||
|
ulint ignore_sec_unique) /* in: if != 0, we should
|
||||||
|
ignore UNIQUE constraint on
|
||||||
|
a secondary index when we
|
||||||
|
decide */
|
||||||
{
|
{
|
||||||
if (!(index->type & (DICT_CLUSTERED | DICT_UNIQUE))
|
if (!(index->type & DICT_CLUSTERED)
|
||||||
|
&& (ignore_sec_unique || !(index->type & DICT_UNIQUE))
|
||||||
&& ibuf->meter > IBUF_THRESHOLD) {
|
&& ibuf->meter > IBUF_THRESHOLD) {
|
||||||
|
|
||||||
ibuf_flush_count++;
|
ibuf_flush_count++;
|
||||||
|
|
||||||
if (ibuf_flush_count % 8 == 0) {
|
if (ibuf_flush_count % 8 == 0) {
|
||||||
|
@ -341,6 +341,8 @@ os_aio_windows_handle(
|
|||||||
void** message2,
|
void** message2,
|
||||||
ulint* type); /* out: OS_FILE_WRITE or ..._READ */
|
ulint* type); /* out: OS_FILE_WRITE or ..._READ */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Currently we do not use Posix async i/o */
|
||||||
#ifdef POSIX_ASYNC_IO
|
#ifdef POSIX_ASYNC_IO
|
||||||
/**************************************************************************
|
/**************************************************************************
|
||||||
This function is only used in Posix asynchronous i/o. Waits for an aio
|
This function is only used in Posix asynchronous i/o. Waits for an aio
|
||||||
|
@ -149,9 +149,9 @@ void
|
|||||||
os_mutex_free(
|
os_mutex_free(
|
||||||
/*==========*/
|
/*==========*/
|
||||||
os_mutex_t mutex); /* in: mutex to free */
|
os_mutex_t mutex); /* in: mutex to free */
|
||||||
#ifndef _WIN32
|
|
||||||
/**************************************************************
|
/**************************************************************
|
||||||
Acquires ownership of a fast mutex. */
|
Acquires ownership of a fast mutex. Currently in Windows this is the same
|
||||||
|
as os_fast_mutex_lock! */
|
||||||
UNIV_INLINE
|
UNIV_INLINE
|
||||||
ulint
|
ulint
|
||||||
os_fast_mutex_trylock(
|
os_fast_mutex_trylock(
|
||||||
@ -160,7 +160,6 @@ os_fast_mutex_trylock(
|
|||||||
was reserved by another
|
was reserved by another
|
||||||
thread */
|
thread */
|
||||||
os_fast_mutex_t* fast_mutex); /* in: mutex to acquire */
|
os_fast_mutex_t* fast_mutex); /* in: mutex to acquire */
|
||||||
#endif
|
|
||||||
/**************************************************************
|
/**************************************************************
|
||||||
Releases ownership of a fast mutex. */
|
Releases ownership of a fast mutex. */
|
||||||
|
|
||||||
|
@ -10,9 +10,9 @@ Created 9/6/1995 Heikki Tuuri
|
|||||||
#include <winbase.h>
|
#include <winbase.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef _WIN32
|
|
||||||
/**************************************************************
|
/**************************************************************
|
||||||
Acquires ownership of a fast mutex. */
|
Acquires ownership of a fast mutex. Currently in Windows this is the same
|
||||||
|
as os_fast_mutex_lock! */
|
||||||
UNIV_INLINE
|
UNIV_INLINE
|
||||||
ulint
|
ulint
|
||||||
os_fast_mutex_trylock(
|
os_fast_mutex_trylock(
|
||||||
@ -23,20 +23,11 @@ os_fast_mutex_trylock(
|
|||||||
os_fast_mutex_t* fast_mutex) /* in: mutex to acquire */
|
os_fast_mutex_t* fast_mutex) /* in: mutex to acquire */
|
||||||
{
|
{
|
||||||
#ifdef __WIN__
|
#ifdef __WIN__
|
||||||
int ret;
|
EnterCriticalSection(fast_mutex);
|
||||||
|
|
||||||
/* TODO: TryEnterCriticalSection is probably not found from
|
|
||||||
NT versions < 4! */
|
|
||||||
ret = TryEnterCriticalSection(fast_mutex);
|
|
||||||
|
|
||||||
if (ret) {
|
|
||||||
return(0);
|
return(0);
|
||||||
}
|
|
||||||
|
|
||||||
return(1);
|
|
||||||
#else
|
#else
|
||||||
return((ulint) pthread_mutex_trylock(fast_mutex));
|
return((ulint) pthread_mutex_trylock(fast_mutex));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
|
@ -209,6 +209,27 @@ row_update_for_mysql(
|
|||||||
row_prebuilt_t* prebuilt); /* in: prebuilt struct in MySQL
|
row_prebuilt_t* prebuilt); /* in: prebuilt struct in MySQL
|
||||||
handle */
|
handle */
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
|
Creates an query graph node of 'update' type to be used in the MySQL
|
||||||
|
interface. */
|
||||||
|
|
||||||
|
upd_node_t*
|
||||||
|
row_create_update_node_for_mysql(
|
||||||
|
/*=============================*/
|
||||||
|
/* out, own: update node */
|
||||||
|
dict_table_t* table, /* in: table to update */
|
||||||
|
mem_heap_t* heap); /* in: mem heap from which allocated */
|
||||||
|
/**************************************************************************
|
||||||
|
Does a cascaded delete or set null in a foreign key operation. */
|
||||||
|
|
||||||
|
ulint
|
||||||
|
row_update_cascade_for_mysql(
|
||||||
|
/*=========================*/
|
||||||
|
/* out: error code or DB_SUCCESS */
|
||||||
|
que_thr_t* thr, /* in: query thread */
|
||||||
|
upd_node_t* node, /* in: update node used in the cascade
|
||||||
|
or set null operation */
|
||||||
|
dict_table_t* table); /* in: table where we do the operation */
|
||||||
|
/*************************************************************************
|
||||||
Does a table creation operation for MySQL. If the name of the created
|
Does a table creation operation for MySQL. If the name of the created
|
||||||
table ends to characters INNODB_MONITOR, then this also starts
|
table ends to characters INNODB_MONITOR, then this also starts
|
||||||
printing of monitor output by the master thread. */
|
printing of monitor output by the master thread. */
|
||||||
|
@ -312,6 +312,11 @@ struct upd_node_struct{
|
|||||||
ibool in_mysql_interface;
|
ibool in_mysql_interface;
|
||||||
/* TRUE if the update node was created
|
/* TRUE if the update node was created
|
||||||
for the MySQL interface */
|
for the MySQL interface */
|
||||||
|
upd_node_t* cascade_node;/* NULL or an update node template which
|
||||||
|
is used to implement ON DELETE CASCADE
|
||||||
|
or ... SET NULL for foreign keys */
|
||||||
|
mem_heap_t* cascade_heap;/* NULL or a mem heap where the cascade
|
||||||
|
node is created */
|
||||||
sel_node_t* select; /* query graph subtree implementing a base
|
sel_node_t* select; /* query graph subtree implementing a base
|
||||||
table cursor: the rows returned will be
|
table cursor: the rows returned will be
|
||||||
updated */
|
updated */
|
||||||
@ -322,6 +327,11 @@ struct upd_node_struct{
|
|||||||
of the MySQL interface */
|
of the MySQL interface */
|
||||||
dict_table_t* table; /* table where updated */
|
dict_table_t* table; /* table where updated */
|
||||||
upd_t* update; /* update vector for the row */
|
upd_t* update; /* update vector for the row */
|
||||||
|
ulint update_n_fields;
|
||||||
|
/* when this struct is used to implement
|
||||||
|
a cascade operation for foreign keys, we store
|
||||||
|
here the size of the buffer allocated for use
|
||||||
|
as the update vector */
|
||||||
sym_node_list_t columns;/* symbol table nodes for the columns
|
sym_node_list_t columns;/* symbol table nodes for the columns
|
||||||
to retrieve from the table */
|
to retrieve from the table */
|
||||||
ibool has_clust_rec_x_lock;
|
ibool has_clust_rec_x_lock;
|
||||||
|
@ -359,12 +359,17 @@ V
|
|||||||
Memory pool mutex */
|
Memory pool mutex */
|
||||||
|
|
||||||
/* Latching order levels */
|
/* Latching order levels */
|
||||||
|
|
||||||
|
/* User transaction locks are higher than any of the latch levels below:
|
||||||
|
no latches are allowed when a thread goes to wait for a normal table
|
||||||
|
or row lock! */
|
||||||
|
#define SYNC_USER_TRX_LOCK 9999
|
||||||
#define SYNC_NO_ORDER_CHECK 3000 /* this can be used to suppress
|
#define SYNC_NO_ORDER_CHECK 3000 /* this can be used to suppress
|
||||||
latching order checking */
|
latching order checking */
|
||||||
#define SYNC_LEVEL_NONE 2000 /* default: level not defined */
|
#define SYNC_LEVEL_NONE 2000 /* default: level not defined */
|
||||||
|
#define SYNC_FOREIGN_KEY_CHECK 1001
|
||||||
#define SYNC_DICT 1000
|
#define SYNC_DICT 1000
|
||||||
#define SYNC_DICT_AUTOINC_MUTEX 999
|
#define SYNC_DICT_AUTOINC_MUTEX 999
|
||||||
#define SYNC_FOREIGN_KEY_CHECK 998
|
|
||||||
#define SYNC_PURGE_IS_RUNNING 997
|
#define SYNC_PURGE_IS_RUNNING 997
|
||||||
#define SYNC_DICT_HEADER 995
|
#define SYNC_DICT_HEADER 995
|
||||||
#define SYNC_IBUF_HEADER 914
|
#define SYNC_IBUF_HEADER 914
|
||||||
@ -429,7 +434,7 @@ implementation of a mutual exclusion semaphore. */
|
|||||||
struct mutex_struct {
|
struct mutex_struct {
|
||||||
ulint lock_word; /* This ulint is the target of the atomic
|
ulint lock_word; /* This ulint is the target of the atomic
|
||||||
test-and-set instruction in Win32 */
|
test-and-set instruction in Win32 */
|
||||||
#ifndef _WIN32
|
#if !defined(_WIN32) || !defined(UNIV_CAN_USE_X86_ASSEMBLER)
|
||||||
os_fast_mutex_t
|
os_fast_mutex_t
|
||||||
os_fast_mutex; /* In other systems we use this OS mutex
|
os_fast_mutex; /* In other systems we use this OS mutex
|
||||||
in place of lock_word */
|
in place of lock_word */
|
||||||
|
@ -53,7 +53,7 @@ mutex_test_and_set(
|
|||||||
1 */
|
1 */
|
||||||
mutex_t* mutex) /* in: mutex */
|
mutex_t* mutex) /* in: mutex */
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
#if defined(_WIN32) && defined(UNIV_CAN_USE_X86_ASSEMBLER)
|
||||||
ulint res;
|
ulint res;
|
||||||
ulint* lw; /* assembler code is used to ensure that
|
ulint* lw; /* assembler code is used to ensure that
|
||||||
lock_word is loaded from memory */
|
lock_word is loaded from memory */
|
||||||
@ -120,7 +120,7 @@ mutex_reset_lock_word(
|
|||||||
/*==================*/
|
/*==================*/
|
||||||
mutex_t* mutex) /* in: mutex */
|
mutex_t* mutex) /* in: mutex */
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
#if defined(_WIN32) && defined(UNIV_CAN_USE_X86_ASSEMBLER)
|
||||||
ulint* lw; /* assembler code is used to ensure that
|
ulint* lw; /* assembler code is used to ensure that
|
||||||
lock_word is loaded from memory */
|
lock_word is loaded from memory */
|
||||||
ut_ad(mutex);
|
ut_ad(mutex);
|
||||||
|
@ -259,7 +259,7 @@ therefore 256 */
|
|||||||
/* The offset of the transaction system header on the page */
|
/* The offset of the transaction system header on the page */
|
||||||
#define TRX_SYS FSEG_PAGE_DATA
|
#define TRX_SYS FSEG_PAGE_DATA
|
||||||
|
|
||||||
/* Transaction system header; protected by trx_sys->mutex */
|
/* Transaction system header */
|
||||||
/*-------------------------------------------------------------*/
|
/*-------------------------------------------------------------*/
|
||||||
#define TRX_SYS_TRX_ID_STORE 0 /* the maximum trx id or trx number
|
#define TRX_SYS_TRX_ID_STORE 0 /* the maximum trx id or trx number
|
||||||
modulo TRX_SYS_TRX_ID_UPDATE_MARGIN
|
modulo TRX_SYS_TRX_ID_UPDATE_MARGIN
|
||||||
|
@ -93,7 +93,6 @@ trx_sysf_get(
|
|||||||
{
|
{
|
||||||
trx_sysf_t* header;
|
trx_sysf_t* header;
|
||||||
|
|
||||||
ut_ad(mutex_own(&(kernel_mutex)));
|
|
||||||
ut_ad(mtr);
|
ut_ad(mtr);
|
||||||
|
|
||||||
header = TRX_SYS + buf_page_get(TRX_SYS_SPACE, TRX_SYS_PAGE_NO,
|
header = TRX_SYS + buf_page_get(TRX_SYS_SPACE, TRX_SYS_PAGE_NO,
|
||||||
|
@ -298,6 +298,17 @@ struct trx_struct{
|
|||||||
of view of concurrency control:
|
of view of concurrency control:
|
||||||
TRX_ACTIVE, TRX_COMMITTED_IN_MEMORY,
|
TRX_ACTIVE, TRX_COMMITTED_IN_MEMORY,
|
||||||
... */
|
... */
|
||||||
|
ibool check_foreigns; /* normally TRUE, but if the user
|
||||||
|
wants to suppress foreign key checks,
|
||||||
|
(in table imports, for example) we
|
||||||
|
set this FALSE */
|
||||||
|
ibool check_unique_secondary;
|
||||||
|
/* normally TRUE, but if the user
|
||||||
|
wants to speed up inserts by
|
||||||
|
suppressing unique key checks
|
||||||
|
for secondary indexes when we decide
|
||||||
|
if we can use the insert buffer for
|
||||||
|
them, we set this FALSE */
|
||||||
dulint id; /* transaction id */
|
dulint id; /* transaction id */
|
||||||
dulint no; /* transaction serialization number ==
|
dulint no; /* transaction serialization number ==
|
||||||
max trx id when the transaction is
|
max trx id when the transaction is
|
||||||
@ -328,6 +339,9 @@ struct trx_struct{
|
|||||||
/* how many tables the current SQL
|
/* how many tables the current SQL
|
||||||
statement uses, except those
|
statement uses, except those
|
||||||
in consistent read */
|
in consistent read */
|
||||||
|
ibool has_dict_foreign_key_check_lock;
|
||||||
|
/* TRUE if the trx currently holds
|
||||||
|
an s-lock on dict_foreign_... */
|
||||||
ibool has_search_latch;
|
ibool has_search_latch;
|
||||||
/* TRUE if this trx has latched the
|
/* TRUE if this trx has latched the
|
||||||
search system latch in S-mode */
|
search system latch in S-mode */
|
||||||
|
@ -1534,6 +1534,8 @@ lock_rec_enqueue_waiting(
|
|||||||
|
|
||||||
if (que_thr_stop(thr)) {
|
if (que_thr_stop(thr)) {
|
||||||
|
|
||||||
|
ut_a(0);
|
||||||
|
|
||||||
return(DB_QUE_THR_SUSPENDED);
|
return(DB_QUE_THR_SUSPENDED);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2918,6 +2920,7 @@ lock_table_enqueue_waiting(
|
|||||||
stopped anyway */
|
stopped anyway */
|
||||||
|
|
||||||
if (que_thr_stop(thr)) {
|
if (que_thr_stop(thr)) {
|
||||||
|
ut_a(0);
|
||||||
|
|
||||||
return(DB_QUE_THR_SUSPENDED);
|
return(DB_QUE_THR_SUSPENDED);
|
||||||
}
|
}
|
||||||
|
@ -526,7 +526,8 @@ opt_search_plan_for_table(
|
|||||||
dict_index_t* best_index;
|
dict_index_t* best_index;
|
||||||
ulint n_fields;
|
ulint n_fields;
|
||||||
ulint goodness;
|
ulint goodness;
|
||||||
ulint last_op;
|
ulint last_op = 75946965; /* Eliminate a Purify
|
||||||
|
warning */
|
||||||
ulint best_goodness;
|
ulint best_goodness;
|
||||||
ulint best_last_op;
|
ulint best_last_op;
|
||||||
ulint mix_id_pos;
|
ulint mix_id_pos;
|
||||||
|
@ -555,6 +555,12 @@ que_graph_free_recursive(
|
|||||||
btr_pcur_free_for_mysql(upd->pcur);
|
btr_pcur_free_for_mysql(upd->pcur);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
que_graph_free_recursive(upd->cascade_node);
|
||||||
|
|
||||||
|
if (upd->cascade_heap) {
|
||||||
|
mem_heap_free(upd->cascade_heap);
|
||||||
|
}
|
||||||
|
|
||||||
que_graph_free_recursive(upd->select);
|
que_graph_free_recursive(upd->select);
|
||||||
|
|
||||||
mem_heap_free(upd->heap);
|
mem_heap_free(upd->heap);
|
||||||
@ -1110,9 +1116,6 @@ que_thr_move_to_run_state_for_mysql(
|
|||||||
trx->n_active_thrs++;
|
trx->n_active_thrs++;
|
||||||
|
|
||||||
thr->is_active = TRUE;
|
thr->is_active = TRUE;
|
||||||
|
|
||||||
ut_ad((thr->graph)->n_active_thrs == 1);
|
|
||||||
ut_ad(trx->n_active_thrs == 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
thr->state = QUE_THR_RUNNING;
|
thr->state = QUE_THR_RUNNING;
|
||||||
|
@ -355,6 +355,223 @@ row_ins_dupl_error_with_rec(
|
|||||||
return(FALSE);
|
return(FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
Either deletes or sets the referencing columns SQL NULL in a child row.
|
||||||
|
Used in ON DELETE ... clause for foreign keys when a parent row is
|
||||||
|
deleted. */
|
||||||
|
static
|
||||||
|
ulint
|
||||||
|
row_ins_foreign_delete_or_set_null(
|
||||||
|
/*===============================*/
|
||||||
|
/* out: DB_SUCCESS, DB_LOCK_WAIT,
|
||||||
|
or error code */
|
||||||
|
que_thr_t* thr, /* in: query thread whose run_node
|
||||||
|
is an update node */
|
||||||
|
dict_foreign_t* foreign, /* in: foreign key constraint whose
|
||||||
|
type is != 0 */
|
||||||
|
btr_pcur_t* pcur, /* in: cursor placed on a matching
|
||||||
|
index record in the child table */
|
||||||
|
mtr_t* mtr) /* in: mtr holding the latch of pcur
|
||||||
|
page */
|
||||||
|
{
|
||||||
|
upd_node_t* node;
|
||||||
|
upd_node_t* cascade;
|
||||||
|
dict_table_t* table = foreign->foreign_table;
|
||||||
|
dict_index_t* index;
|
||||||
|
dict_index_t* clust_index;
|
||||||
|
dtuple_t* ref;
|
||||||
|
mem_heap_t* tmp_heap;
|
||||||
|
rec_t* rec;
|
||||||
|
rec_t* clust_rec;
|
||||||
|
upd_t* update;
|
||||||
|
ulint err;
|
||||||
|
ulint i;
|
||||||
|
char err_buf[1000];
|
||||||
|
|
||||||
|
ut_a(thr && foreign && pcur && mtr);
|
||||||
|
|
||||||
|
node = thr->run_node;
|
||||||
|
|
||||||
|
if (node->cascade_node == NULL) {
|
||||||
|
/* Extend our query graph by creating a child to current
|
||||||
|
update node. The child is used in the cascade or set null
|
||||||
|
operation. */
|
||||||
|
|
||||||
|
node->cascade_heap = mem_heap_create(128);
|
||||||
|
node->cascade_node = row_create_update_node_for_mysql(
|
||||||
|
table, node->cascade_heap);
|
||||||
|
que_node_set_parent(node->cascade_node, node);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialize cascade_node to do the operation we want. Note that we
|
||||||
|
use the SAME cascade node to do all foreign key operations of the
|
||||||
|
SQL DELETE: the table of the cascade node may change if there are
|
||||||
|
several child tables to the table where the delete is done! */
|
||||||
|
|
||||||
|
cascade = node->cascade_node;
|
||||||
|
|
||||||
|
cascade->table = table;
|
||||||
|
|
||||||
|
if (foreign->type == DICT_FOREIGN_ON_DELETE_CASCADE ) {
|
||||||
|
cascade->is_delete = TRUE;
|
||||||
|
} else {
|
||||||
|
cascade->is_delete = FALSE;
|
||||||
|
|
||||||
|
if (foreign->n_fields > cascade->update_n_fields) {
|
||||||
|
/* We have to make the update vector longer */
|
||||||
|
|
||||||
|
cascade->update = upd_create(foreign->n_fields,
|
||||||
|
node->cascade_heap);
|
||||||
|
cascade->update_n_fields = foreign->n_fields;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
index = btr_pcur_get_btr_cur(pcur)->index;
|
||||||
|
|
||||||
|
rec = btr_pcur_get_rec(pcur);
|
||||||
|
|
||||||
|
if (index->type & DICT_CLUSTERED) {
|
||||||
|
/* pcur is already positioned in the clustered index of
|
||||||
|
the child table */
|
||||||
|
|
||||||
|
clust_index = index;
|
||||||
|
clust_rec = rec;
|
||||||
|
} else {
|
||||||
|
/* We have to look for the record in the clustered index
|
||||||
|
in the child table */
|
||||||
|
|
||||||
|
clust_index = dict_table_get_first_index(table);
|
||||||
|
|
||||||
|
tmp_heap = mem_heap_create(256);
|
||||||
|
|
||||||
|
ref = row_build_row_ref(ROW_COPY_POINTERS, index, rec,
|
||||||
|
tmp_heap);
|
||||||
|
btr_pcur_open_with_no_init(clust_index, ref,
|
||||||
|
PAGE_CUR_LE, BTR_SEARCH_LEAF,
|
||||||
|
cascade->pcur, 0, mtr);
|
||||||
|
|
||||||
|
mem_heap_free(tmp_heap);
|
||||||
|
|
||||||
|
clust_rec = btr_pcur_get_rec(cascade->pcur);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!page_rec_is_user_rec(clust_rec)) {
|
||||||
|
fprintf(stderr, "InnoDB: error in cascade of a foreign key op\n"
|
||||||
|
"InnoDB: index %s table %s\n", index->name,
|
||||||
|
index->table->name);
|
||||||
|
|
||||||
|
rec_sprintf(err_buf, 900, rec);
|
||||||
|
fprintf(stderr, "InnoDB: record %s\n", err_buf);
|
||||||
|
|
||||||
|
rec_sprintf(err_buf, 900, clust_rec);
|
||||||
|
fprintf(stderr, "InnoDB: clustered record %s\n", err_buf);
|
||||||
|
|
||||||
|
fprintf(stderr,
|
||||||
|
"InnoDB: Make a detailed bug report and send it\n");
|
||||||
|
fprintf(stderr, "InnoDB: to mysql@lists.mysql.com\n");
|
||||||
|
|
||||||
|
err = DB_SUCCESS;
|
||||||
|
|
||||||
|
goto nonstandard_exit_func;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set an X-lock on the row to delete or update in the child table */
|
||||||
|
|
||||||
|
err = lock_table(0, table, LOCK_IX, thr);
|
||||||
|
|
||||||
|
if (err == DB_SUCCESS) {
|
||||||
|
err = lock_clust_rec_read_check_and_lock(0, clust_rec,
|
||||||
|
clust_index, LOCK_X, thr);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (err != DB_SUCCESS) {
|
||||||
|
|
||||||
|
goto nonstandard_exit_func;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rec_get_deleted_flag(clust_rec)) {
|
||||||
|
/* This should never happen since we already have an S-lock
|
||||||
|
on non-delete-marked clust_rec or secondary index record! */
|
||||||
|
|
||||||
|
fprintf(stderr,
|
||||||
|
"InnoDB: error 2 in cascade of a foreign key op\n"
|
||||||
|
"InnoDB: index %s table %s\n", index->name,
|
||||||
|
index->table->name);
|
||||||
|
|
||||||
|
rec_sprintf(err_buf, 900, rec);
|
||||||
|
fprintf(stderr, "InnoDB: record %s\n", err_buf);
|
||||||
|
|
||||||
|
rec_sprintf(err_buf, 900, clust_rec);
|
||||||
|
fprintf(stderr, "InnoDB: clustered record %s\n", err_buf);
|
||||||
|
|
||||||
|
fprintf(stderr,
|
||||||
|
"InnoDB: Make a detailed bug report and send it\n");
|
||||||
|
fprintf(stderr, "InnoDB: to mysql@lists.mysql.com\n");
|
||||||
|
|
||||||
|
ut_a(0);
|
||||||
|
|
||||||
|
goto nonstandard_exit_func;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (foreign->type == DICT_FOREIGN_ON_DELETE_SET_NULL) {
|
||||||
|
/* Build the appropriate update vector which sets
|
||||||
|
foreign->n_fields first fields in rec to SQL NULL */
|
||||||
|
|
||||||
|
update = cascade->update;
|
||||||
|
|
||||||
|
update->info_bits = 0;
|
||||||
|
update->n_fields = foreign->n_fields;
|
||||||
|
|
||||||
|
for (i = 0; i < foreign->n_fields; i++) {
|
||||||
|
(update->fields + i)->field_no
|
||||||
|
= dict_table_get_nth_col_pos(table,
|
||||||
|
dict_index_get_nth_col_no(index, i));
|
||||||
|
(update->fields + i)->exp = NULL;
|
||||||
|
(update->fields + i)->new_val.len = UNIV_SQL_NULL;
|
||||||
|
(update->fields + i)->new_val.data = NULL;
|
||||||
|
(update->fields + i)->extern_storage = FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Store pcur position and initialize or store the cascade node
|
||||||
|
pcur stored position */
|
||||||
|
|
||||||
|
btr_pcur_store_position(pcur, mtr);
|
||||||
|
|
||||||
|
if (index == clust_index) {
|
||||||
|
btr_pcur_copy_stored_position(cascade->pcur, pcur);
|
||||||
|
} else {
|
||||||
|
btr_pcur_store_position(cascade->pcur, mtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
mtr_commit(mtr);
|
||||||
|
|
||||||
|
ut_a(cascade->pcur->rel_pos == BTR_PCUR_ON);
|
||||||
|
|
||||||
|
cascade->state = UPD_NODE_UPDATE_CLUSTERED;
|
||||||
|
|
||||||
|
err = row_update_cascade_for_mysql(thr, cascade,
|
||||||
|
foreign->foreign_table);
|
||||||
|
mtr_start(mtr);
|
||||||
|
|
||||||
|
/* Restore pcur position */
|
||||||
|
|
||||||
|
btr_pcur_restore_position(BTR_SEARCH_LEAF, pcur, mtr);
|
||||||
|
|
||||||
|
return(err);
|
||||||
|
|
||||||
|
nonstandard_exit_func:
|
||||||
|
|
||||||
|
btr_pcur_store_position(pcur, mtr);
|
||||||
|
|
||||||
|
mtr_commit(mtr);
|
||||||
|
mtr_start(mtr);
|
||||||
|
|
||||||
|
btr_pcur_restore_position(BTR_SEARCH_LEAF, pcur, mtr);
|
||||||
|
|
||||||
|
return(err);
|
||||||
|
}
|
||||||
|
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
Sets a shared lock on a record. Used in locking possible duplicate key
|
Sets a shared lock on a record. Used in locking possible duplicate key
|
||||||
records. */
|
records. */
|
||||||
@ -416,6 +633,13 @@ row_ins_check_foreign_constraint(
|
|||||||
|
|
||||||
ut_ad(rw_lock_own(&dict_foreign_key_check_lock, RW_LOCK_SHARED));
|
ut_ad(rw_lock_own(&dict_foreign_key_check_lock, RW_LOCK_SHARED));
|
||||||
|
|
||||||
|
if (thr_get_trx(thr)->check_foreigns == FALSE) {
|
||||||
|
/* The user has suppressed foreign key checks currently for
|
||||||
|
this session */
|
||||||
|
|
||||||
|
return(DB_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
/* If any of the foreign key fields in entry is SQL NULL, we
|
/* If any of the foreign key fields in entry is SQL NULL, we
|
||||||
suppress the foreign key check: this is compatible with Oracle,
|
suppress the foreign key check: this is compatible with Oracle,
|
||||||
for example */
|
for example */
|
||||||
@ -501,11 +725,21 @@ row_ins_check_foreign_constraint(
|
|||||||
|
|
||||||
if (check_ref) {
|
if (check_ref) {
|
||||||
err = DB_SUCCESS;
|
err = DB_SUCCESS;
|
||||||
} else {
|
|
||||||
err = DB_ROW_IS_REFERENCED;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
} else if (foreign->type != 0) {
|
||||||
|
err =
|
||||||
|
row_ins_foreign_delete_or_set_null(
|
||||||
|
thr, foreign, &pcur, &mtr);
|
||||||
|
|
||||||
|
if (err != DB_SUCCESS) {
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
err = DB_ROW_IS_REFERENCED;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -534,6 +768,8 @@ next_rec:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
btr_pcur_close(&pcur);
|
||||||
|
|
||||||
mtr_commit(&mtr);
|
mtr_commit(&mtr);
|
||||||
|
|
||||||
/* Restore old value */
|
/* Restore old value */
|
||||||
@ -561,6 +797,10 @@ row_ins_check_foreign_constraints(
|
|||||||
{
|
{
|
||||||
dict_foreign_t* foreign;
|
dict_foreign_t* foreign;
|
||||||
ulint err;
|
ulint err;
|
||||||
|
trx_t* trx;
|
||||||
|
ibool got_s_lock = FALSE;
|
||||||
|
|
||||||
|
trx = thr_get_trx(thr);
|
||||||
|
|
||||||
foreign = UT_LIST_GET_FIRST(table->foreign_list);
|
foreign = UT_LIST_GET_FIRST(table->foreign_list);
|
||||||
|
|
||||||
@ -569,16 +809,26 @@ row_ins_check_foreign_constraints(
|
|||||||
|
|
||||||
if (foreign->referenced_table == NULL) {
|
if (foreign->referenced_table == NULL) {
|
||||||
dict_table_get(foreign->referenced_table_name,
|
dict_table_get(foreign->referenced_table_name,
|
||||||
thr_get_trx(thr));
|
trx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!trx->has_dict_foreign_key_check_lock) {
|
||||||
|
got_s_lock = TRUE;
|
||||||
|
|
||||||
rw_lock_s_lock(&dict_foreign_key_check_lock);
|
rw_lock_s_lock(&dict_foreign_key_check_lock);
|
||||||
|
|
||||||
|
trx->has_dict_foreign_key_check_lock = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
err = row_ins_check_foreign_constraint(TRUE, foreign,
|
err = row_ins_check_foreign_constraint(TRUE, foreign,
|
||||||
table, index, entry, thr);
|
table, index, entry, thr);
|
||||||
|
if (got_s_lock) {
|
||||||
|
|
||||||
rw_lock_s_unlock(&dict_foreign_key_check_lock);
|
rw_lock_s_unlock(&dict_foreign_key_check_lock);
|
||||||
|
|
||||||
|
trx->has_dict_foreign_key_check_lock = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
if (err != DB_SUCCESS) {
|
if (err != DB_SUCCESS) {
|
||||||
return(err);
|
return(err);
|
||||||
}
|
}
|
||||||
@ -869,6 +1119,7 @@ row_ins_index_entry_low(
|
|||||||
que_thr_t* thr) /* in: query thread */
|
que_thr_t* thr) /* in: query thread */
|
||||||
{
|
{
|
||||||
btr_cur_t cursor;
|
btr_cur_t cursor;
|
||||||
|
ulint ignore_sec_unique = 0;
|
||||||
ulint modify;
|
ulint modify;
|
||||||
rec_t* insert_rec;
|
rec_t* insert_rec;
|
||||||
rec_t* rec;
|
rec_t* rec;
|
||||||
@ -887,8 +1138,13 @@ row_ins_index_entry_low(
|
|||||||
the function will return in both low_match and up_match of the
|
the function will return in both low_match and up_match of the
|
||||||
cursor sensible values */
|
cursor sensible values */
|
||||||
|
|
||||||
|
if (!(thr_get_trx(thr)->check_unique_secondary)) {
|
||||||
|
ignore_sec_unique = BTR_IGNORE_SEC_UNIQUE;
|
||||||
|
}
|
||||||
|
|
||||||
btr_cur_search_to_nth_level(index, 0, entry, PAGE_CUR_LE,
|
btr_cur_search_to_nth_level(index, 0, entry, PAGE_CUR_LE,
|
||||||
mode | BTR_INSERT, &cursor, 0, &mtr);
|
mode | BTR_INSERT | ignore_sec_unique,
|
||||||
|
&cursor, 0, &mtr);
|
||||||
|
|
||||||
if (cursor.flag == BTR_CUR_INSERT_TO_IBUF) {
|
if (cursor.flag == BTR_CUR_INSERT_TO_IBUF) {
|
||||||
/* The insertion was made to the insert buffer already during
|
/* The insertion was made to the insert buffer already during
|
||||||
|
@ -499,29 +499,24 @@ UNIV_INLINE
|
|||||||
void
|
void
|
||||||
row_update_statistics_if_needed(
|
row_update_statistics_if_needed(
|
||||||
/*============================*/
|
/*============================*/
|
||||||
row_prebuilt_t* prebuilt) /* in: prebuilt struct */
|
dict_table_t* table) /* in: table */
|
||||||
{
|
{
|
||||||
ulint counter;
|
ulint counter;
|
||||||
|
|
||||||
counter = prebuilt->table->stat_modified_counter;
|
counter = table->stat_modified_counter;
|
||||||
|
|
||||||
/* Since the physical size of an InnoDB row is bigger than the
|
table->stat_modified_counter = counter + 1;
|
||||||
MySQL row len, we put a safety factor 2 below */
|
|
||||||
|
|
||||||
counter += 2 * prebuilt->mysql_row_len;
|
|
||||||
|
|
||||||
prebuilt->table->stat_modified_counter = counter;
|
|
||||||
|
|
||||||
/* Calculate new statistics if 1 / 16 of table has been modified
|
/* Calculate new statistics if 1 / 16 of table has been modified
|
||||||
since the last time a statistics batch was run, or if
|
since the last time a statistics batch was run, or if
|
||||||
stat_modified_counter > 2 000 000 000 (to avoid wrap-around) */
|
stat_modified_counter > 2 000 000 000 (to avoid wrap-around).
|
||||||
|
We calculate statistics at most every 16th round, since we may have
|
||||||
|
a counter table which is very small and updated very often. */
|
||||||
|
|
||||||
if (counter > 2000000000
|
if (counter > 2000000000
|
||||||
|| ((ib_longlong)counter >
|
|| ((ib_longlong)counter > 16 + table->stat_n_rows / 16)) {
|
||||||
(UNIV_PAGE_SIZE * prebuilt->table->stat_clustered_index_size)
|
|
||||||
/ 16)) {
|
|
||||||
|
|
||||||
dict_update_statistics(prebuilt->table);
|
dict_update_statistics(table);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -712,7 +707,7 @@ run_again:
|
|||||||
prebuilt->table->stat_n_rows--;
|
prebuilt->table->stat_n_rows--;
|
||||||
}
|
}
|
||||||
|
|
||||||
row_update_statistics_if_needed(prebuilt);
|
row_update_statistics_if_needed(prebuilt->table);
|
||||||
trx->op_info = "";
|
trx->op_info = "";
|
||||||
|
|
||||||
return((int) err);
|
return((int) err);
|
||||||
@ -745,6 +740,43 @@ row_prebuild_sel_graph(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
Creates an query graph node of 'update' type to be used in the MySQL
|
||||||
|
interface. */
|
||||||
|
|
||||||
|
upd_node_t*
|
||||||
|
row_create_update_node_for_mysql(
|
||||||
|
/*=============================*/
|
||||||
|
/* out, own: update node */
|
||||||
|
dict_table_t* table, /* in: table to update */
|
||||||
|
mem_heap_t* heap) /* in: mem heap from which allocated */
|
||||||
|
{
|
||||||
|
upd_node_t* node;
|
||||||
|
|
||||||
|
node = upd_node_create(heap);
|
||||||
|
|
||||||
|
node->in_mysql_interface = TRUE;
|
||||||
|
node->is_delete = FALSE;
|
||||||
|
node->searched_update = FALSE;
|
||||||
|
node->select_will_do_update = FALSE;
|
||||||
|
node->select = NULL;
|
||||||
|
node->pcur = btr_pcur_create_for_mysql();
|
||||||
|
node->table = table;
|
||||||
|
|
||||||
|
node->update = upd_create(dict_table_get_n_cols(table), heap);
|
||||||
|
|
||||||
|
node->update_n_fields = dict_table_get_n_cols(table);
|
||||||
|
|
||||||
|
UT_LIST_INIT(node->columns);
|
||||||
|
node->has_clust_rec_x_lock = TRUE;
|
||||||
|
node->cmpl_info = 0;
|
||||||
|
|
||||||
|
node->table_sym = NULL;
|
||||||
|
node->col_assign_list = NULL;
|
||||||
|
|
||||||
|
return(node);
|
||||||
|
}
|
||||||
|
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
Gets pointer to a prebuilt update vector used in updates. If the update
|
Gets pointer to a prebuilt update vector used in updates. If the update
|
||||||
graph has not yet been built in the prebuilt struct, then this function
|
graph has not yet been built in the prebuilt struct, then this function
|
||||||
@ -767,27 +799,10 @@ row_get_prebuilt_update_vector(
|
|||||||
/* Not called before for this handle: create an update node
|
/* Not called before for this handle: create an update node
|
||||||
and query graph to the prebuilt struct */
|
and query graph to the prebuilt struct */
|
||||||
|
|
||||||
node = upd_node_create(prebuilt->heap);
|
node = row_create_update_node_for_mysql(table, prebuilt->heap);
|
||||||
|
|
||||||
prebuilt->upd_node = node;
|
prebuilt->upd_node = node;
|
||||||
|
|
||||||
node->in_mysql_interface = TRUE;
|
|
||||||
node->is_delete = FALSE;
|
|
||||||
node->searched_update = FALSE;
|
|
||||||
node->select_will_do_update = FALSE;
|
|
||||||
node->select = NULL;
|
|
||||||
node->pcur = btr_pcur_create_for_mysql();
|
|
||||||
node->table = table;
|
|
||||||
|
|
||||||
node->update = upd_create(dict_table_get_n_cols(table),
|
|
||||||
prebuilt->heap);
|
|
||||||
UT_LIST_INIT(node->columns);
|
|
||||||
node->has_clust_rec_x_lock = TRUE;
|
|
||||||
node->cmpl_info = 0;
|
|
||||||
|
|
||||||
node->table_sym = NULL;
|
|
||||||
node->col_assign_list = NULL;
|
|
||||||
|
|
||||||
prebuilt->upd_graph =
|
prebuilt->upd_graph =
|
||||||
que_node_get_parent(
|
que_node_get_parent(
|
||||||
pars_complete_graph_for_exec(node,
|
pars_complete_graph_for_exec(node,
|
||||||
@ -914,7 +929,7 @@ run_again:
|
|||||||
|
|
||||||
que_thr_stop_for_mysql_no_error(thr, trx);
|
que_thr_stop_for_mysql_no_error(thr, trx);
|
||||||
|
|
||||||
if (prebuilt->upd_node->is_delete) {
|
if (node->is_delete) {
|
||||||
if (prebuilt->table->stat_n_rows > 0) {
|
if (prebuilt->table->stat_n_rows > 0) {
|
||||||
prebuilt->table->stat_n_rows--;
|
prebuilt->table->stat_n_rows--;
|
||||||
}
|
}
|
||||||
@ -924,13 +939,66 @@ run_again:
|
|||||||
srv_n_rows_updated++;
|
srv_n_rows_updated++;
|
||||||
}
|
}
|
||||||
|
|
||||||
row_update_statistics_if_needed(prebuilt);
|
row_update_statistics_if_needed(prebuilt->table);
|
||||||
|
|
||||||
trx->op_info = "";
|
trx->op_info = "";
|
||||||
|
|
||||||
return((int) err);
|
return((int) err);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
Does a cascaded delete or set null in a foreign key operation. */
|
||||||
|
|
||||||
|
ulint
|
||||||
|
row_update_cascade_for_mysql(
|
||||||
|
/*=========================*/
|
||||||
|
/* out: error code or DB_SUCCESS */
|
||||||
|
que_thr_t* thr, /* in: query thread */
|
||||||
|
upd_node_t* node, /* in: update node used in the cascade
|
||||||
|
or set null operation */
|
||||||
|
dict_table_t* table) /* in: table where we do the operation */
|
||||||
|
{
|
||||||
|
ulint err;
|
||||||
|
trx_t* trx;
|
||||||
|
|
||||||
|
trx = thr_get_trx(thr);
|
||||||
|
|
||||||
|
run_again:
|
||||||
|
thr->run_node = node;
|
||||||
|
thr->prev_node = node;
|
||||||
|
|
||||||
|
row_upd_step(thr);
|
||||||
|
|
||||||
|
err = trx->error_state;
|
||||||
|
|
||||||
|
if (err == DB_LOCK_WAIT) {
|
||||||
|
que_thr_stop_for_mysql(thr);
|
||||||
|
|
||||||
|
row_mysql_handle_errors(&err, trx, thr, NULL);
|
||||||
|
|
||||||
|
goto run_again;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (err != DB_SUCCESS) {
|
||||||
|
|
||||||
|
return(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node->is_delete) {
|
||||||
|
if (table->stat_n_rows > 0) {
|
||||||
|
table->stat_n_rows--;
|
||||||
|
}
|
||||||
|
|
||||||
|
srv_n_rows_deleted++;
|
||||||
|
} else {
|
||||||
|
srv_n_rows_updated++;
|
||||||
|
}
|
||||||
|
|
||||||
|
row_update_statistics_if_needed(table);
|
||||||
|
|
||||||
|
return(err);
|
||||||
|
}
|
||||||
|
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
Checks if a table is such that we automatically created a clustered
|
Checks if a table is such that we automatically created a clustered
|
||||||
index on it (on row id). */
|
index on it (on row id). */
|
||||||
@ -1169,6 +1237,7 @@ row_create_table_for_mysql(
|
|||||||
/* Serialize data dictionary operations with dictionary mutex:
|
/* Serialize data dictionary operations with dictionary mutex:
|
||||||
no deadlocks can occur then in these operations */
|
no deadlocks can occur then in these operations */
|
||||||
|
|
||||||
|
rw_lock_x_lock(&(dict_foreign_key_check_lock));
|
||||||
mutex_enter(&(dict_sys->mutex));
|
mutex_enter(&(dict_sys->mutex));
|
||||||
|
|
||||||
heap = mem_heap_create(512);
|
heap = mem_heap_create(512);
|
||||||
@ -1221,6 +1290,8 @@ row_create_table_for_mysql(
|
|||||||
}
|
}
|
||||||
|
|
||||||
mutex_exit(&(dict_sys->mutex));
|
mutex_exit(&(dict_sys->mutex));
|
||||||
|
rw_lock_x_unlock(&(dict_foreign_key_check_lock));
|
||||||
|
|
||||||
que_graph_free((que_t*) que_node_get_parent(thr));
|
que_graph_free((que_t*) que_node_get_parent(thr));
|
||||||
|
|
||||||
trx->op_info = "";
|
trx->op_info = "";
|
||||||
@ -1268,6 +1339,7 @@ row_create_index_for_mysql(
|
|||||||
/* Serialize data dictionary operations with dictionary mutex:
|
/* Serialize data dictionary operations with dictionary mutex:
|
||||||
no deadlocks can occur then in these operations */
|
no deadlocks can occur then in these operations */
|
||||||
|
|
||||||
|
rw_lock_x_lock(&(dict_foreign_key_check_lock));
|
||||||
mutex_enter(&(dict_sys->mutex));
|
mutex_enter(&(dict_sys->mutex));
|
||||||
|
|
||||||
heap = mem_heap_create(512);
|
heap = mem_heap_create(512);
|
||||||
@ -1298,6 +1370,7 @@ row_create_index_for_mysql(
|
|||||||
}
|
}
|
||||||
|
|
||||||
mutex_exit(&(dict_sys->mutex));
|
mutex_exit(&(dict_sys->mutex));
|
||||||
|
rw_lock_x_unlock(&(dict_foreign_key_check_lock));
|
||||||
|
|
||||||
que_graph_free((que_t*) que_node_get_parent(thr));
|
que_graph_free((que_t*) que_node_get_parent(thr));
|
||||||
|
|
||||||
@ -1353,6 +1426,7 @@ row_table_add_foreign_constraints(
|
|||||||
/* Serialize data dictionary operations with dictionary mutex:
|
/* Serialize data dictionary operations with dictionary mutex:
|
||||||
no deadlocks can occur then in these operations */
|
no deadlocks can occur then in these operations */
|
||||||
|
|
||||||
|
rw_lock_x_lock(&(dict_foreign_key_check_lock));
|
||||||
mutex_enter(&(dict_sys->mutex));
|
mutex_enter(&(dict_sys->mutex));
|
||||||
|
|
||||||
trx->dict_operation = TRUE;
|
trx->dict_operation = TRUE;
|
||||||
@ -1377,6 +1451,7 @@ row_table_add_foreign_constraints(
|
|||||||
}
|
}
|
||||||
|
|
||||||
mutex_exit(&(dict_sys->mutex));
|
mutex_exit(&(dict_sys->mutex));
|
||||||
|
rw_lock_x_unlock(&(dict_foreign_key_check_lock));
|
||||||
|
|
||||||
return((int) err);
|
return((int) err);
|
||||||
}
|
}
|
||||||
@ -1471,7 +1546,8 @@ loop:
|
|||||||
goto already_dropped;
|
goto already_dropped;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (table->n_mysql_handles_opened > 0) {
|
if (table->n_mysql_handles_opened > 0
|
||||||
|
|| table->n_foreign_key_checks_running > 0) {
|
||||||
|
|
||||||
return(n_tables + n_tables_dropped);
|
return(n_tables + n_tables_dropped);
|
||||||
}
|
}
|
||||||
@ -1717,6 +1793,9 @@ row_drop_table_for_mysql(
|
|||||||
no deadlocks can occur then in these operations */
|
no deadlocks can occur then in these operations */
|
||||||
|
|
||||||
if (!has_dict_mutex) {
|
if (!has_dict_mutex) {
|
||||||
|
/* Prevent foreign key checks while we are dropping the table */
|
||||||
|
rw_lock_x_lock(&(dict_foreign_key_check_lock));
|
||||||
|
|
||||||
mutex_enter(&(dict_sys->mutex));
|
mutex_enter(&(dict_sys->mutex));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1729,9 +1808,6 @@ row_drop_table_for_mysql(
|
|||||||
|
|
||||||
graph->fork_type = QUE_FORK_MYSQL_INTERFACE;
|
graph->fork_type = QUE_FORK_MYSQL_INTERFACE;
|
||||||
|
|
||||||
/* Prevent foreign key checks while we are dropping the table */
|
|
||||||
rw_lock_x_lock(&(dict_foreign_key_check_lock));
|
|
||||||
|
|
||||||
/* Prevent purge from running while we are dropping the table */
|
/* Prevent purge from running while we are dropping the table */
|
||||||
rw_lock_s_lock(&(purge_sys->purge_is_running));
|
rw_lock_s_lock(&(purge_sys->purge_is_running));
|
||||||
|
|
||||||
@ -1766,6 +1842,22 @@ row_drop_table_for_mysql(
|
|||||||
goto funct_exit;
|
goto funct_exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (table->n_foreign_key_checks_running > 0) {
|
||||||
|
|
||||||
|
ut_print_timestamp(stderr);
|
||||||
|
fprintf(stderr,
|
||||||
|
" InnoDB: You are trying to drop table %s\n"
|
||||||
|
"InnoDB: though there are foreign key check running on it.\n"
|
||||||
|
"InnoDB: Adding the table to the background drop queue.\n",
|
||||||
|
table->name);
|
||||||
|
|
||||||
|
row_add_table_to_background_drop_list(table);
|
||||||
|
|
||||||
|
err = DB_SUCCESS;
|
||||||
|
|
||||||
|
goto funct_exit;
|
||||||
|
}
|
||||||
|
|
||||||
/* Remove any locks there are on the table or its records */
|
/* Remove any locks there are on the table or its records */
|
||||||
|
|
||||||
lock_reset_all_on_table(table);
|
lock_reset_all_on_table(table);
|
||||||
@ -1793,10 +1885,9 @@ row_drop_table_for_mysql(
|
|||||||
funct_exit:
|
funct_exit:
|
||||||
rw_lock_s_unlock(&(purge_sys->purge_is_running));
|
rw_lock_s_unlock(&(purge_sys->purge_is_running));
|
||||||
|
|
||||||
rw_lock_x_unlock(&(dict_foreign_key_check_lock));
|
|
||||||
|
|
||||||
if (!has_dict_mutex) {
|
if (!has_dict_mutex) {
|
||||||
mutex_exit(&(dict_sys->mutex));
|
mutex_exit(&(dict_sys->mutex));
|
||||||
|
rw_lock_x_unlock(&(dict_foreign_key_check_lock));
|
||||||
}
|
}
|
||||||
|
|
||||||
que_graph_free(graph);
|
que_graph_free(graph);
|
||||||
@ -1832,6 +1923,7 @@ row_drop_database_for_mysql(
|
|||||||
|
|
||||||
trx_start_if_not_started(trx);
|
trx_start_if_not_started(trx);
|
||||||
loop:
|
loop:
|
||||||
|
rw_lock_x_lock(&(dict_foreign_key_check_lock));
|
||||||
mutex_enter(&(dict_sys->mutex));
|
mutex_enter(&(dict_sys->mutex));
|
||||||
|
|
||||||
while (table_name = dict_get_first_table_name_in_db(name)) {
|
while (table_name = dict_get_first_table_name_in_db(name)) {
|
||||||
@ -1873,6 +1965,7 @@ loop:
|
|||||||
}
|
}
|
||||||
|
|
||||||
mutex_exit(&(dict_sys->mutex));
|
mutex_exit(&(dict_sys->mutex));
|
||||||
|
rw_lock_x_unlock(&(dict_foreign_key_check_lock));
|
||||||
|
|
||||||
trx_commit_for_mysql(trx);
|
trx_commit_for_mysql(trx);
|
||||||
|
|
||||||
@ -2009,6 +2102,7 @@ row_rename_table_for_mysql(
|
|||||||
/* Serialize data dictionary operations with dictionary mutex:
|
/* Serialize data dictionary operations with dictionary mutex:
|
||||||
no deadlocks can occur then in these operations */
|
no deadlocks can occur then in these operations */
|
||||||
|
|
||||||
|
rw_lock_x_lock(&(dict_foreign_key_check_lock));
|
||||||
mutex_enter(&(dict_sys->mutex));
|
mutex_enter(&(dict_sys->mutex));
|
||||||
|
|
||||||
table = dict_table_get_low(old_name);
|
table = dict_table_get_low(old_name);
|
||||||
@ -2090,6 +2184,7 @@ row_rename_table_for_mysql(
|
|||||||
}
|
}
|
||||||
funct_exit:
|
funct_exit:
|
||||||
mutex_exit(&(dict_sys->mutex));
|
mutex_exit(&(dict_sys->mutex));
|
||||||
|
rw_lock_x_unlock(&(dict_foreign_key_check_lock));
|
||||||
|
|
||||||
que_graph_free(graph);
|
que_graph_free(graph);
|
||||||
|
|
||||||
|
@ -2114,11 +2114,17 @@ row_sel_store_mysql_rec(
|
|||||||
mem_heap_free(extern_field_heap);
|
mem_heap_free(extern_field_heap);
|
||||||
extern_field_heap = NULL;
|
extern_field_heap = NULL;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
if (!templ->mysql_null_bit_mask) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"InnoDB: Error: trying to return an SQL NULL field in a non-null\n"
|
||||||
|
"innoDB: column! Table name %s\n", prebuilt->table->name);
|
||||||
} else {
|
} else {
|
||||||
mysql_rec[templ->mysql_null_byte_offset] |=
|
mysql_rec[templ->mysql_null_byte_offset] |=
|
||||||
(byte) (templ->mysql_null_bit_mask);
|
(byte) (templ->mysql_null_bit_mask);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
|
@ -73,8 +73,7 @@ steps of query graph execution. */
|
|||||||
|
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
Checks if index currently is mentioned as a referenced index in a foreign
|
Checks if index currently is mentioned as a referenced index in a foreign
|
||||||
key constraint. This function also loads into the dictionary cache the
|
key constraint. */
|
||||||
possible referencing table. */
|
|
||||||
static
|
static
|
||||||
ibool
|
ibool
|
||||||
row_upd_index_is_referenced(
|
row_upd_index_is_referenced(
|
||||||
@ -85,44 +84,28 @@ row_upd_index_is_referenced(
|
|||||||
the referencing table has been dropped when
|
the referencing table has been dropped when
|
||||||
we leave this function: this function is only
|
we leave this function: this function is only
|
||||||
for heuristic use! */
|
for heuristic use! */
|
||||||
dict_index_t* index) /* in: index */
|
dict_index_t* index, /* in: index */
|
||||||
|
trx_t* trx) /* in: transaction */
|
||||||
{
|
{
|
||||||
dict_table_t* table = index->table;
|
dict_table_t* table = index->table;
|
||||||
dict_foreign_t* foreign;
|
dict_foreign_t* foreign;
|
||||||
ulint phase = 1;
|
|
||||||
|
|
||||||
try_again:
|
|
||||||
if (!UT_LIST_GET_FIRST(table->referenced_list)) {
|
if (!UT_LIST_GET_FIRST(table->referenced_list)) {
|
||||||
|
|
||||||
return(FALSE);
|
return(FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (phase == 2) {
|
if (!trx->has_dict_foreign_key_check_lock) {
|
||||||
mutex_enter(&(dict_sys->mutex));
|
|
||||||
}
|
|
||||||
|
|
||||||
rw_lock_s_lock(&dict_foreign_key_check_lock);
|
rw_lock_s_lock(&dict_foreign_key_check_lock);
|
||||||
|
}
|
||||||
|
|
||||||
foreign = UT_LIST_GET_FIRST(table->referenced_list);
|
foreign = UT_LIST_GET_FIRST(table->referenced_list);
|
||||||
|
|
||||||
while (foreign) {
|
while (foreign) {
|
||||||
if (foreign->referenced_index == index) {
|
if (foreign->referenced_index == index) {
|
||||||
if (foreign->foreign_table == NULL) {
|
|
||||||
if (phase == 2) {
|
|
||||||
dict_table_get_low(foreign->
|
|
||||||
foreign_table_name);
|
|
||||||
} else {
|
|
||||||
phase = 2;
|
|
||||||
rw_lock_s_unlock(
|
|
||||||
&dict_foreign_key_check_lock);
|
|
||||||
goto try_again;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (!trx->has_dict_foreign_key_check_lock) {
|
||||||
rw_lock_s_unlock(&dict_foreign_key_check_lock);
|
rw_lock_s_unlock(&dict_foreign_key_check_lock);
|
||||||
|
|
||||||
if (phase == 2) {
|
|
||||||
mutex_exit(&(dict_sys->mutex));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return(TRUE);
|
return(TRUE);
|
||||||
@ -131,10 +114,8 @@ try_again:
|
|||||||
foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
|
foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!trx->has_dict_foreign_key_check_lock) {
|
||||||
rw_lock_s_unlock(&dict_foreign_key_check_lock);
|
rw_lock_s_unlock(&dict_foreign_key_check_lock);
|
||||||
|
|
||||||
if (phase == 2) {
|
|
||||||
mutex_exit(&(dict_sys->mutex));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return(FALSE);
|
return(FALSE);
|
||||||
@ -160,8 +141,17 @@ row_upd_check_references_constraints(
|
|||||||
dict_foreign_t* foreign;
|
dict_foreign_t* foreign;
|
||||||
mem_heap_t* heap;
|
mem_heap_t* heap;
|
||||||
dtuple_t* entry;
|
dtuple_t* entry;
|
||||||
|
trx_t* trx;
|
||||||
rec_t* rec;
|
rec_t* rec;
|
||||||
ulint err;
|
ulint err;
|
||||||
|
ibool got_s_lock = FALSE;
|
||||||
|
|
||||||
|
if (UT_LIST_GET_FIRST(table->referenced_list) == NULL) {
|
||||||
|
|
||||||
|
return(DB_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
trx = thr_get_trx(thr);
|
||||||
|
|
||||||
rec = btr_pcur_get_rec(pcur);
|
rec = btr_pcur_get_rec(pcur);
|
||||||
|
|
||||||
@ -173,17 +163,61 @@ row_upd_check_references_constraints(
|
|||||||
|
|
||||||
mtr_start(mtr);
|
mtr_start(mtr);
|
||||||
|
|
||||||
|
if (!trx->has_dict_foreign_key_check_lock) {
|
||||||
|
got_s_lock = TRUE;
|
||||||
|
|
||||||
rw_lock_s_lock(&dict_foreign_key_check_lock);
|
rw_lock_s_lock(&dict_foreign_key_check_lock);
|
||||||
|
|
||||||
|
trx->has_dict_foreign_key_check_lock = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
foreign = UT_LIST_GET_FIRST(table->referenced_list);
|
foreign = UT_LIST_GET_FIRST(table->referenced_list);
|
||||||
|
|
||||||
while (foreign) {
|
while (foreign) {
|
||||||
if (foreign->referenced_index == index) {
|
if (foreign->referenced_index == index) {
|
||||||
|
if (foreign->foreign_table == NULL) {
|
||||||
|
dict_table_get(foreign->foreign_table_name,
|
||||||
|
trx);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (foreign->foreign_table) {
|
||||||
|
mutex_enter(&(dict_sys->mutex));
|
||||||
|
|
||||||
|
(foreign->foreign_table
|
||||||
|
->n_foreign_key_checks_running)++;
|
||||||
|
|
||||||
|
mutex_exit(&(dict_sys->mutex));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* NOTE that if the thread ends up waiting for a lock
|
||||||
|
we will release dict_foreign_key_check_lock
|
||||||
|
temporarily! But the counter on the table
|
||||||
|
protects 'foreign' from 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, index, entry, thr);
|
||||||
|
|
||||||
|
if (foreign->foreign_table) {
|
||||||
|
mutex_enter(&(dict_sys->mutex));
|
||||||
|
|
||||||
|
ut_a(foreign->foreign_table
|
||||||
|
->n_foreign_key_checks_running > 0);
|
||||||
|
|
||||||
|
(foreign->foreign_table
|
||||||
|
->n_foreign_key_checks_running)--;
|
||||||
|
|
||||||
|
mutex_exit(&(dict_sys->mutex));
|
||||||
|
}
|
||||||
|
|
||||||
if (err != DB_SUCCESS) {
|
if (err != DB_SUCCESS) {
|
||||||
rw_lock_s_unlock(&dict_foreign_key_check_lock);
|
if (got_s_lock) {
|
||||||
|
rw_lock_s_unlock(
|
||||||
|
&dict_foreign_key_check_lock);
|
||||||
|
trx->has_dict_foreign_key_check_lock
|
||||||
|
= FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
mem_heap_free(heap);
|
mem_heap_free(heap);
|
||||||
|
|
||||||
return(err);
|
return(err);
|
||||||
@ -193,7 +227,11 @@ row_upd_check_references_constraints(
|
|||||||
foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
|
foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (got_s_lock) {
|
||||||
rw_lock_s_unlock(&dict_foreign_key_check_lock);
|
rw_lock_s_unlock(&dict_foreign_key_check_lock);
|
||||||
|
trx->has_dict_foreign_key_check_lock = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
mem_heap_free(heap);
|
mem_heap_free(heap);
|
||||||
|
|
||||||
return(DB_SUCCESS);
|
return(DB_SUCCESS);
|
||||||
@ -222,6 +260,9 @@ upd_node_create(
|
|||||||
node->index = NULL;
|
node->index = NULL;
|
||||||
node->update = NULL;
|
node->update = NULL;
|
||||||
|
|
||||||
|
node->cascade_heap = NULL;
|
||||||
|
node->cascade_node = NULL;
|
||||||
|
|
||||||
node->select = NULL;
|
node->select = NULL;
|
||||||
|
|
||||||
node->heap = mem_heap_create(128);
|
node->heap = mem_heap_create(128);
|
||||||
@ -1027,7 +1068,7 @@ row_upd_sec_index_entry(
|
|||||||
|
|
||||||
index = node->index;
|
index = node->index;
|
||||||
|
|
||||||
check_ref = row_upd_index_is_referenced(index);
|
check_ref = row_upd_index_is_referenced(index, thr_get_trx(thr));
|
||||||
|
|
||||||
heap = mem_heap_create(1024);
|
heap = mem_heap_create(1024);
|
||||||
|
|
||||||
@ -1391,7 +1432,7 @@ row_upd_clust_step(
|
|||||||
|
|
||||||
index = dict_table_get_first_index(node->table);
|
index = dict_table_get_first_index(node->table);
|
||||||
|
|
||||||
check_ref = row_upd_index_is_referenced(index);
|
check_ref = row_upd_index_is_referenced(index, thr_get_trx(thr));
|
||||||
|
|
||||||
pcur = node->pcur;
|
pcur = node->pcur;
|
||||||
|
|
||||||
|
@ -2017,15 +2017,18 @@ srv_suspend_mysql_thread(
|
|||||||
/*=====================*/
|
/*=====================*/
|
||||||
/* out: TRUE if the lock wait timeout was
|
/* out: TRUE if the lock wait timeout was
|
||||||
exceeded */
|
exceeded */
|
||||||
que_thr_t* thr) /* in: query thread associated with
|
que_thr_t* thr) /* in: query thread associated with the MySQL
|
||||||
the MySQL OS thread */
|
OS thread */
|
||||||
{
|
{
|
||||||
srv_slot_t* slot;
|
srv_slot_t* slot;
|
||||||
os_event_t event;
|
os_event_t event;
|
||||||
double wait_time;
|
double wait_time;
|
||||||
|
trx_t* trx;
|
||||||
|
|
||||||
ut_ad(!mutex_own(&kernel_mutex));
|
ut_ad(!mutex_own(&kernel_mutex));
|
||||||
|
|
||||||
|
trx = thr_get_trx(thr);
|
||||||
|
|
||||||
os_event_set(srv_lock_timeout_thread_event);
|
os_event_set(srv_lock_timeout_thread_event);
|
||||||
|
|
||||||
mutex_enter(&kernel_mutex);
|
mutex_enter(&kernel_mutex);
|
||||||
@ -2061,10 +2064,21 @@ srv_suspend_mysql_thread(
|
|||||||
|
|
||||||
srv_conc_force_exit_innodb(thr_get_trx(thr));
|
srv_conc_force_exit_innodb(thr_get_trx(thr));
|
||||||
|
|
||||||
|
/* Release possible foreign key check latch */
|
||||||
|
if (trx->has_dict_foreign_key_check_lock) {
|
||||||
|
|
||||||
|
rw_lock_s_unlock(&dict_foreign_key_check_lock);
|
||||||
|
}
|
||||||
|
|
||||||
/* Wait for the release */
|
/* Wait for the release */
|
||||||
|
|
||||||
os_event_wait(event);
|
os_event_wait(event);
|
||||||
|
|
||||||
|
if (trx->has_dict_foreign_key_check_lock) {
|
||||||
|
|
||||||
|
rw_lock_s_lock(&dict_foreign_key_check_lock);
|
||||||
|
}
|
||||||
|
|
||||||
/* Return back inside InnoDB */
|
/* Return back inside InnoDB */
|
||||||
|
|
||||||
srv_conc_force_enter_innodb(thr_get_trx(thr));
|
srv_conc_force_enter_innodb(thr_get_trx(thr));
|
||||||
|
@ -220,7 +220,7 @@ mutex_create_func(
|
|||||||
char* cfile_name, /* in: file name where created */
|
char* cfile_name, /* in: file name where created */
|
||||||
ulint cline) /* in: file line where created */
|
ulint cline) /* in: file line where created */
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
#if defined(_WIN32) && defined(UNIV_CAN_USE_X86_ASSEMBLER)
|
||||||
mutex_reset_lock_word(mutex);
|
mutex_reset_lock_word(mutex);
|
||||||
#else
|
#else
|
||||||
os_fast_mutex_init(&(mutex->os_fast_mutex));
|
os_fast_mutex_init(&(mutex->os_fast_mutex));
|
||||||
@ -273,7 +273,7 @@ mutex_free(
|
|||||||
|
|
||||||
mutex_exit(&mutex_list_mutex);
|
mutex_exit(&mutex_list_mutex);
|
||||||
|
|
||||||
#ifndef _WIN32
|
#if !defined(_WIN32) || !defined(UNIV_CAN_USE_X86_ASSEMBLER)
|
||||||
os_fast_mutex_free(&(mutex->os_fast_mutex));
|
os_fast_mutex_free(&(mutex->os_fast_mutex));
|
||||||
#endif
|
#endif
|
||||||
/* If we free the mutex protecting the mutex list (freeing is
|
/* If we free the mutex protecting the mutex list (freeing is
|
||||||
@ -1009,7 +1009,7 @@ sync_thread_add_level(
|
|||||||
} else if (level == SYNC_ANY_LATCH) {
|
} else if (level == SYNC_ANY_LATCH) {
|
||||||
ut_a(sync_thread_levels_g(array, SYNC_ANY_LATCH));
|
ut_a(sync_thread_levels_g(array, SYNC_ANY_LATCH));
|
||||||
} else if (level == SYNC_TRX_SYS_HEADER) {
|
} else if (level == SYNC_TRX_SYS_HEADER) {
|
||||||
ut_a(sync_thread_levels_contain(array, SYNC_KERNEL));
|
ut_a(sync_thread_levels_g(array, SYNC_TRX_SYS_HEADER));
|
||||||
} else if (level == SYNC_DOUBLEWRITE) {
|
} else if (level == SYNC_DOUBLEWRITE) {
|
||||||
ut_a(sync_thread_levels_g(array, SYNC_DOUBLEWRITE));
|
ut_a(sync_thread_levels_g(array, SYNC_DOUBLEWRITE));
|
||||||
} else if (level == SYNC_BUF_BLOCK) {
|
} else if (level == SYNC_BUF_BLOCK) {
|
||||||
|
@ -438,7 +438,6 @@ trx_sys_update_mysql_binlog_offset(
|
|||||||
trx_sysf_t* sys_header;
|
trx_sysf_t* sys_header;
|
||||||
char namebuf[TRX_SYS_MYSQL_LOG_NAME_LEN];
|
char namebuf[TRX_SYS_MYSQL_LOG_NAME_LEN];
|
||||||
|
|
||||||
ut_ad(mutex_own(&kernel_mutex));
|
|
||||||
ut_ad(trx->mysql_log_file_name);
|
ut_ad(trx->mysql_log_file_name);
|
||||||
|
|
||||||
memset(namebuf, ' ', TRX_SYS_MYSQL_LOG_NAME_LEN - 1);
|
memset(namebuf, ' ', TRX_SYS_MYSQL_LOG_NAME_LEN - 1);
|
||||||
@ -524,7 +523,7 @@ trx_sys_print_mysql_binlog_offset(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"InnoDB: Last MySQL binlog file offset %lu %lu, file name %s\n",
|
"InnoDB: Last MySQL binlog file position %lu %lu, file name %s\n",
|
||||||
mach_read_from_4(sys_header + TRX_SYS_MYSQL_LOG_INFO
|
mach_read_from_4(sys_header + TRX_SYS_MYSQL_LOG_INFO
|
||||||
+ TRX_SYS_MYSQL_LOG_OFFSET_HIGH),
|
+ TRX_SYS_MYSQL_LOG_OFFSET_HIGH),
|
||||||
mach_read_from_4(sys_header + TRX_SYS_MYSQL_LOG_INFO
|
mach_read_from_4(sys_header + TRX_SYS_MYSQL_LOG_INFO
|
||||||
|
@ -71,6 +71,9 @@ trx_create(
|
|||||||
trx->type = TRX_USER;
|
trx->type = TRX_USER;
|
||||||
trx->conc_state = TRX_NOT_STARTED;
|
trx->conc_state = TRX_NOT_STARTED;
|
||||||
|
|
||||||
|
trx->check_foreigns = TRUE;
|
||||||
|
trx->check_unique_secondary = TRUE;
|
||||||
|
|
||||||
trx->dict_operation = FALSE;
|
trx->dict_operation = FALSE;
|
||||||
|
|
||||||
trx->mysql_thd = NULL;
|
trx->mysql_thd = NULL;
|
||||||
@ -113,6 +116,7 @@ trx_create(
|
|||||||
trx->lock_heap = mem_heap_create_in_buffer(256);
|
trx->lock_heap = mem_heap_create_in_buffer(256);
|
||||||
UT_LIST_INIT(trx->trx_locks);
|
UT_LIST_INIT(trx->trx_locks);
|
||||||
|
|
||||||
|
trx->has_dict_foreign_key_check_lock = FALSE;
|
||||||
trx->has_search_latch = FALSE;
|
trx->has_search_latch = FALSE;
|
||||||
trx->search_latch_timeout = BTR_SEA_TIMEOUT;
|
trx->search_latch_timeout = BTR_SEA_TIMEOUT;
|
||||||
|
|
||||||
@ -703,8 +707,7 @@ trx_commit_off_kernel(
|
|||||||
|
|
||||||
/*-------------------------------------*/
|
/*-------------------------------------*/
|
||||||
|
|
||||||
/* Only in some performance tests the variable srv_flush..
|
/* Most MySQL users run with srv_flush.. set to FALSE: */
|
||||||
will be set to FALSE: */
|
|
||||||
|
|
||||||
if (srv_flush_log_at_trx_commit) {
|
if (srv_flush_log_at_trx_commit) {
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user