summaryrefslogtreecommitdiff
path: root/innobase
diff options
context:
space:
mode:
Diffstat (limited to 'innobase')
-rw-r--r--innobase/btr/btr0btr.c23
-rw-r--r--innobase/btr/btr0cur.c8
-rw-r--r--innobase/buf/buf0buf.c10
-rw-r--r--innobase/data/data0type.c78
-rw-r--r--innobase/dict/dict0crea.c26
-rw-r--r--innobase/dict/dict0dict.c210
-rw-r--r--innobase/dict/dict0load.c78
-rw-r--r--innobase/dict/dict0mem.c1
-rw-r--r--innobase/fil/fil0fil.c276
-rw-r--r--innobase/fsp/fsp0fsp.c6
-rw-r--r--innobase/ibuf/ibuf0ibuf.c5
-rw-r--r--innobase/include/data0type.h23
-rw-r--r--innobase/include/dict0dict.h21
-rw-r--r--innobase/include/dict0mem.h22
-rw-r--r--innobase/include/fil0fil.h14
-rw-r--r--innobase/include/mem0mem.h8
-rw-r--r--innobase/include/mem0mem.ic14
-rw-r--r--innobase/include/os0file.h23
-rw-r--r--innobase/include/row0mysql.h8
-rw-r--r--innobase/include/row0row.h3
-rw-r--r--innobase/include/row0sel.h3
-rw-r--r--innobase/include/row0upd.h5
-rw-r--r--innobase/include/row0upd.ic5
-rw-r--r--innobase/include/srv0srv.h13
-rw-r--r--innobase/include/sync0arr.h4
-rw-r--r--innobase/include/trx0rec.h1
-rw-r--r--innobase/include/trx0sys.h4
-rw-r--r--innobase/include/ut0byte.h19
-rw-r--r--innobase/include/ut0mem.h10
-rw-r--r--innobase/include/ut0mem.ic2
-rw-r--r--innobase/include/ut0ut.h13
-rw-r--r--innobase/lock/lock0lock.c108
-rw-r--r--innobase/log/log0log.c44
-rw-r--r--innobase/log/log0recv.c6
-rw-r--r--innobase/mem/mem0mem.c14
-rw-r--r--innobase/os/os0file.c155
-rw-r--r--innobase/page/page0page.c6
-rw-r--r--innobase/pars/pars0opt.c15
-rw-r--r--innobase/pars/pars0pars.c2
-rw-r--r--innobase/rem/rem0cmp.c5
-rw-r--r--innobase/row/row0ins.c189
-rw-r--r--innobase/row/row0mysql.c210
-rw-r--r--innobase/row/row0purge.c4
-rw-r--r--innobase/row/row0row.c72
-rw-r--r--innobase/row/row0sel.c107
-rw-r--r--innobase/row/row0umod.c18
-rw-r--r--innobase/row/row0upd.c43
-rw-r--r--innobase/srv/srv0srv.c60
-rw-r--r--innobase/srv/srv0start.c53
-rw-r--r--innobase/sync/sync0arr.c20
-rw-r--r--innobase/trx/trx0purge.c62
-rw-r--r--innobase/trx/trx0rec.c71
-rw-r--r--innobase/trx/trx0roll.c4
-rw-r--r--innobase/trx/trx0rseg.c7
-rw-r--r--innobase/trx/trx0undo.c2
-rw-r--r--innobase/ut/ut0byte.c48
-rw-r--r--innobase/ut/ut0dbg.c5
-rw-r--r--innobase/ut/ut0mem.c8
-rw-r--r--innobase/ut/ut0ut.c49
59 files changed, 1585 insertions, 738 deletions
diff --git a/innobase/btr/btr0btr.c b/innobase/btr/btr0btr.c
index 27d798f925a..ae967e0525e 100644
--- a/innobase/btr/btr0btr.c
+++ b/innobase/btr/btr0btr.c
@@ -595,10 +595,10 @@ btr_page_get_father_for_rec(
buf_page_print(buf_frame_align(node_ptr));
fputs("InnoDB: Corruption of an index tree: table ", stderr);
- ut_print_name(stderr,
+ ut_print_name(stderr, NULL,
UT_LIST_GET_FIRST(tree->tree_indexes)->table_name);
fputs(", index ", stderr);
- ut_print_name(stderr,
+ ut_print_name(stderr, NULL,
UT_LIST_GET_FIRST(tree->tree_indexes)->name);
fprintf(stderr, ",\n"
"InnoDB: father ptr page no %lu, child page no %lu\n",
@@ -610,8 +610,8 @@ btr_page_get_father_for_rec(
fputs(
"InnoDB: You should dump + drop + reimport the table to fix the\n"
"InnoDB: corruption. If the crash happens at the database startup, see\n"
-"InnoDB: section 6.1 of http://www.innodb.com/ibman.php about forcing\n"
-"InnoDB: recovery. Then dump + drop + reimport.\n", stderr);
+"InnoDB: http://dev.mysql.com/doc/mysql/en/Forcing_recovery.html about\n"
+"InnoDB: forcing recovery. Then dump + drop + reimport.\n", stderr);
}
ut_a(btr_node_ptr_get_child_page_no(node_ptr) ==
@@ -2341,7 +2341,7 @@ btr_index_rec_validate_report(
dict_index_t* index) /* in: index */
{
fputs("InnoDB: Record in ", stderr);
- dict_index_name_print(stderr, index);
+ dict_index_name_print(stderr, NULL, index);
fprintf(stderr, ", page %lu, at offset %lu\n",
buf_frame_get_page_no(page), (ulint)(rec - page));
}
@@ -2400,14 +2400,17 @@ btr_index_rec_validate(
dtype_t* type = dict_index_get_nth_type(index, i);
rec_get_nth_field(rec, i, &len);
-
+
+ /* Note that prefix indexes are not fixed size even when
+ their type is CHAR. */
+
if ((dict_index_get_nth_field(index, i)->prefix_len == 0
&& len != UNIV_SQL_NULL && dtype_is_fixed_size(type)
&& len != dtype_get_fixed_size(type))
||
(dict_index_get_nth_field(index, i)->prefix_len > 0
- && len != UNIV_SQL_NULL && dtype_is_fixed_size(type)
- && len !=
+ && len != UNIV_SQL_NULL
+ && len >
dict_index_get_nth_field(index, i)->prefix_len)) {
btr_index_rec_validate_report(page, rec, index);
@@ -2479,7 +2482,7 @@ btr_validate_report1(
{
fprintf(stderr, "InnoDB: Error in page %lu of ",
buf_frame_get_page_no(page));
- dict_index_name_print(stderr, index);
+ dict_index_name_print(stderr, NULL, index);
if (level) {
fprintf(stderr, ", index tree level %lu", level);
}
@@ -2500,7 +2503,7 @@ btr_validate_report2(
fprintf(stderr, "InnoDB: Error in pages %lu and %lu of ",
buf_frame_get_page_no(page1),
buf_frame_get_page_no(page2));
- dict_index_name_print(stderr, index);
+ dict_index_name_print(stderr, NULL, index);
if (level) {
fprintf(stderr, ", index tree level %lu", level);
}
diff --git a/innobase/btr/btr0cur.c b/innobase/btr/btr0cur.c
index be201da4510..48de5644908 100644
--- a/innobase/btr/btr0cur.c
+++ b/innobase/btr/btr0cur.c
@@ -839,7 +839,7 @@ static
void
btr_cur_trx_report(
/*===============*/
- const trx_t* trx, /* in: transaction */
+ trx_t* trx, /* in: transaction */
const dict_index_t* index, /* in: index */
const char* op) /* in: operation */
{
@@ -847,7 +847,7 @@ btr_cur_trx_report(
ut_dulint_get_high(trx->id),
ut_dulint_get_low(trx->id));
fputs(op, stderr);
- dict_index_name_print(stderr, index);
+ dict_index_name_print(stderr, trx, index);
putc('\n', stderr);
}
@@ -899,7 +899,7 @@ btr_cur_optimistic_insert(
if (!dtuple_check_typed_no_assert(entry)) {
fputs("InnoDB: Error in a tuple to insert into ", stderr);
- dict_index_name_print(stderr, index);
+ dict_index_name_print(stderr, thr_get_trx(thr), index);
}
if (btr_cur_print_record_ops && thr) {
@@ -1001,7 +1001,7 @@ calculate_sizes_again:
fputs("InnoDB: Error: cannot insert tuple ", stderr);
dtuple_print(stderr, entry);
fputs(" into ", stderr);
- dict_index_name_print(stderr, index);
+ dict_index_name_print(stderr, thr_get_trx(thr), index);
fprintf(stderr, "\nInnoDB: max insert size %lu\n",
(ulong) max_size);
ut_error;
diff --git a/innobase/buf/buf0buf.c b/innobase/buf/buf0buf.c
index bee322a1631..4b1f2d0ab99 100644
--- a/innobase/buf/buf0buf.c
+++ b/innobase/buf/buf0buf.c
@@ -427,7 +427,7 @@ buf_page_print(
btr_page_get_index_id(read_buf));
if (index) {
fputs("InnoDB: (", stderr);
- dict_index_name_print(stderr, index);
+ dict_index_name_print(stderr, NULL, index);
fputs(")\n", stderr);
}
}
@@ -1836,9 +1836,9 @@ buf_page_io_complete(
"InnoDB: by dumping, dropping, and reimporting\n"
"InnoDB: the corrupt table. You can use CHECK\n"
"InnoDB: TABLE to scan your table for corruption.\n"
- "InnoDB: Look also at section 6.1 of\n"
- "InnoDB: http://www.innodb.com/ibman.php about\n"
- "InnoDB: forcing recovery.\n", stderr);
+ "InnoDB: See also "
+ "http://dev.mysql.com/doc/mysql/en/Forcing_recovery.html\n"
+ "InnoDB: about forcing recovery.\n", stderr);
if (srv_force_recovery < SRV_FORCE_IGNORE_CORRUPT) {
fputs(
@@ -2124,7 +2124,7 @@ buf_print(void)
if (index) {
putc(' ', stderr);
- dict_index_name_print(stderr, index);
+ dict_index_name_print(stderr, NULL, index);
}
putc('\n', stderr);
diff --git a/innobase/data/data0type.c b/innobase/data/data0type.c
index 97d93b1b0ec..714cf92bc65 100644
--- a/innobase/data/data0type.c
+++ b/innobase/data/data0type.c
@@ -12,6 +12,27 @@ Created 1/16/1996 Heikki Tuuri
#include "data0type.ic"
#endif
+/**********************************************************************
+This function is used to find the storage length in bytes of the first n
+characters for prefix indexes using a multibyte character set. The function
+finds charset information and returns length of prefix_len characters in the
+index field in bytes.
+
+NOTE: the prototype of this function is copied from ha_innodb.cc! If you change
+this function, you MUST change also the prototype here! */
+
+ulint
+innobase_get_at_most_n_mbchars(
+/*===========================*/
+ /* out: number of bytes occupied by the first
+ n characters */
+ ulint charset_id, /* in: character set id */
+ ulint prefix_len, /* in: prefix length in bytes of the index
+ (this has to be divided by mbmaxlen to get the
+ number of CHARACTERS n in the prefix) */
+ ulint data_len, /* in: length of the string in bytes */
+ const char* str); /* in: character string */
+
/* At the database startup we store the default-charset collation number of
this MySQL installation to this global variable. If we have < 4.1.2 format
column definitions, or records in the insert buffer, we use this
@@ -24,6 +45,63 @@ dtype_t dtype_binary_val = {DATA_BINARY, 0, 0, 0};
dtype_t* dtype_binary = &dtype_binary_val;
/*************************************************************************
+Checks if a string type has to be compared by the MySQL comparison functions.
+InnoDB internally only handles binary byte string comparisons, as well as
+latin1_swedish_ci strings. For example, UTF-8 strings have to be compared
+by MySQL. */
+
+ibool
+dtype_str_needs_mysql_cmp(
+/*======================*/
+ /* out: TRUE if a string type that requires
+ comparison with MySQL functions */
+ dtype_t* dtype) /* in: type struct */
+{
+ if (dtype->mtype == DATA_MYSQL
+ || dtype->mtype == DATA_VARMYSQL
+ || (dtype->mtype == DATA_BLOB
+ && 0 == (dtype->prtype & DATA_BINARY_TYPE)
+ && dtype_get_charset_coll(dtype->prtype) !=
+ data_mysql_latin1_swedish_charset_coll)) {
+ return(TRUE);
+ }
+
+ return(FALSE);
+}
+
+/*************************************************************************
+For the documentation of this function, see innobase_get_at_most_n_mbchars()
+in ha_innodb.cc. */
+
+ulint
+dtype_get_at_most_n_mbchars(
+/*========================*/
+ dtype_t* dtype,
+ ulint prefix_len,
+ ulint data_len,
+ const char* str)
+{
+ ut_a(data_len != UNIV_SQL_NULL);
+
+ if (dtype_str_needs_mysql_cmp(dtype)) {
+ return(innobase_get_at_most_n_mbchars(
+ dtype_get_charset_coll(dtype->prtype),
+ prefix_len, data_len, str));
+ }
+
+ /* We assume here that the string types that InnoDB itself can compare
+ are single-byte charsets! */
+
+ if (prefix_len < data_len) {
+
+ return(prefix_len);
+
+ }
+
+ return(data_len);
+}
+
+/*************************************************************************
Checks if a data main type is a string type. Also a BLOB is considered a
string type. */
diff --git a/innobase/dict/dict0crea.c b/innobase/dict/dict0crea.c
index 1e4d906b7b5..137964b26c1 100644
--- a/innobase/dict/dict0crea.c
+++ b/innobase/dict/dict0crea.c
@@ -205,6 +205,8 @@ dict_build_table_def_step(
dict_table_t* cluster_table;
dtuple_t* row;
ulint error;
+ const char* path_or_name;
+ ibool is_path;
mtr_t mtr;
#ifdef UNIV_SYNC_DEBUG
@@ -245,8 +247,19 @@ dict_build_table_def_step(
table->space = 0; /* reset to zero for the call below */
+ if (table->dir_path_of_temp_table) {
+ /* We place tables created with CREATE TEMPORARY
+ TABLE in the tmp dir of mysqld server */
+
+ path_or_name = table->dir_path_of_temp_table;
+ is_path = TRUE;
+ } else {
+ path_or_name = table->name;
+ is_path = FALSE;
+ }
+
error = fil_create_new_single_table_tablespace(
- &(table->space), table->name,
+ &(table->space), path_or_name, is_path,
FIL_IBD_FILE_INITIAL_SIZE);
if (error != DB_SUCCESS) {
@@ -501,11 +514,14 @@ dict_build_index_def_step(
dict_table_t* table;
dict_index_t* index;
dtuple_t* row;
+ trx_t* trx;
#ifdef UNIV_SYNC_DEBUG
ut_ad(mutex_own(&(dict_sys->mutex)));
#endif /* UNIV_SYNC_DEBUG */
+ trx = thr_get_trx(thr);
+
index = node->index;
table = dict_table_get_low(index->table_name);
@@ -514,7 +530,7 @@ dict_build_index_def_step(
return(DB_TABLE_NOT_FOUND);
}
- thr_get_trx(thr)->table_id = table->id;
+ trx->table_id = table->id;
node->table = table;
@@ -1264,9 +1280,9 @@ loop:
ut_print_timestamp(ef);
fputs(" Error in foreign key constraint creation for table ",
ef);
- ut_print_name(ef, table->name);
+ ut_print_name(ef, trx, table->name);
fputs(".\nA foreign key constraint of name ", ef);
- ut_print_name(ef, foreign->id);
+ ut_print_name(ef, trx, foreign->id);
fputs("\nalready exists."
" (Note that internally InnoDB adds 'databasename/'\n"
"in front of the user-defined constraint name).\n",
@@ -1286,7 +1302,7 @@ loop:
ut_print_timestamp(ef);
fputs(" Internal error in foreign key constraint creation"
" for table ", ef);
- ut_print_name(ef, table->name);
+ ut_print_name(ef, trx, table->name);
fputs(".\n"
"See the MySQL .err log in the datadir for more information.\n", ef);
mutex_exit(&dict_foreign_err_mutex);
diff --git a/innobase/dict/dict0dict.c b/innobase/dict/dict0dict.c
index eeefd7bf1ae..c3d0d8d9ac1 100644
--- a/innobase/dict/dict0dict.c
+++ b/innobase/dict/dict0dict.c
@@ -53,6 +53,30 @@ rw_lock_t dict_operation_lock; /* table create, drop, etc. reserve
/* Identifies generated InnoDB foreign key names */
static char dict_ibfk[] = "_ibfk_";
+/**********************************************************************
+Compares NUL-terminated UTF-8 strings case insensitively.
+
+NOTE: the prototype of this function is copied from ha_innodb.cc! If you change
+this function, you MUST change also the prototype here! */
+extern
+int
+innobase_strcasecmp(
+/*================*/
+ /* out: 0 if a=b, <0 if a<b, >1 if a>b */
+ const char* a, /* in: first string to compare */
+ const char* b); /* in: second string to compare */
+
+/**********************************************************************
+Makes all characters in a NUL-terminated UTF-8 string lower case.
+
+NOTE: the prototype of this function is copied from ha_innodb.cc! If you change
+this function, you MUST change also the prototype here! */
+extern
+void
+innobase_casedn_str(
+/*================*/
+ char* a); /* in/out: string to put in lower case */
+
/**************************************************************************
Adds a column to the data dictionary hash table. */
static
@@ -527,8 +551,10 @@ dict_index_contains_col_or_prefix(
}
/************************************************************************
-Looks for a matching field in an index. The column and the prefix len have
-to be the same. */
+Looks for a matching field in an index. The column has to be the same. The
+column in index must be complete, or must contain a prefix longer than the
+column in index2. That is, we must be able to construct the prefix in index2
+from the prefix in index. */
ulint
dict_index_get_nth_field_pos(
@@ -556,7 +582,9 @@ dict_index_get_nth_field_pos(
field = dict_index_get_nth_field(index, pos);
if (field->col == field2->col
- && field->prefix_len == field2->prefix_len) {
+ && (field->prefix_len == 0
+ || (field->prefix_len >= field2->prefix_len
+ && field2->prefix_len != 0))) {
return(pos);
}
@@ -939,8 +967,16 @@ dict_table_rename_in_cache(
.ibd file */
if (table->space != 0) {
- success = fil_rename_tablespace(table->name, table->space,
- new_name);
+ if (table->dir_path_of_temp_table != NULL) {
+ fprintf(stderr,
+"InnoDB: Error: trying to rename a table %s (%s) created with CREATE\n"
+"InnoDB: TEMPORARY TABLE\n", table->name, table->dir_path_of_temp_table);
+ success = FALSE;
+ } else {
+ success = fil_rename_tablespace(table->name,
+ table->space, new_name);
+ }
+
if (!success) {
return(FALSE);
@@ -2054,7 +2090,7 @@ dict_foreign_find_index(
break;
}
- if (0 != ut_cmp_in_lower_case(columns[i],
+ if (0 != innobase_strcasecmp(columns[i],
col_name)) {
break;
}
@@ -2085,14 +2121,14 @@ Report an error in a foreign key definition. */
static
void
dict_foreign_error_report_low(
+/*==========================*/
FILE* file, /* in: output stream */
const char* name) /* in: table name */
{
rewind(file);
ut_print_timestamp(file);
- fputs(" Error in foreign key constraint of table ", file);
- ut_print_name(file, name);
- fputs(":\n", file);
+ fprintf(file, " Error in foreign key constraint of table %s:\n",
+ name);
}
/**************************************************************************
@@ -2100,6 +2136,7 @@ Report an error in a foreign key definition. */
static
void
dict_foreign_error_report(
+/*======================*/
FILE* file, /* in: output stream */
dict_foreign_t* fk, /* in: foreign key constraint */
const char* msg) /* in: the error message */
@@ -2108,12 +2145,13 @@ dict_foreign_error_report(
dict_foreign_error_report_low(file, fk->foreign_table_name);
fputs(msg, file);
fputs(" Constraint:\n", file);
- dict_print_info_on_foreign_key_in_create_format(file, fk);
+ dict_print_info_on_foreign_key_in_create_format(file, NULL, fk);
if (fk->foreign_index) {
fputs("\nThe index in the foreign key in table is ", file);
- ut_print_name(file, fk->foreign_index->name);
+ ut_print_name(file, NULL, fk->foreign_index->name);
fputs(
-"See http://www.innodb.com/ibman.php for correct foreign key definition.\n",
+"\nSee http://dev.mysql.com/doc/mysql/en/InnoDB_foreign_key_constraints.html\n"
+"for correct foreign key definition.\n",
file);
}
mutex_exit(&dict_foreign_err_mutex);
@@ -2230,7 +2268,7 @@ dict_foreign_add_to_cache(
Scans from pointer onwards. Stops if is at the start of a copy of
'string' where characters are compared without case sensitivity. Stops
also at '\0'. */
-static
+
const char*
dict_scan_to(
/*=========*/
@@ -2422,7 +2460,7 @@ dict_scan_col(
col = dict_table_get_nth_col(table, i);
- if (0 == ut_cmp_in_lower_case(col->name, *name)) {
+ if (0 == innobase_strcasecmp(col->name, *name)) {
/* Found */
*success = TRUE;
@@ -2514,30 +2552,19 @@ dict_scan_table_name(
table_name_len = strlen(table_name);
+ /* Copy database_name, '/', table_name, '\0' */
ref = mem_heap_alloc(heap, database_name_len + table_name_len + 2);
-
-#ifdef __WIN__
- ut_cpy_in_lower_case(ref, database_name, database_name_len);
-#else
+ memcpy(ref, database_name, database_name_len);
+ ref[database_name_len] = '/';
+ memcpy(ref + database_name_len + 1, table_name, table_name_len + 1);
+#ifndef __WIN__
if (srv_lower_case_table_names) {
- ut_cpy_in_lower_case(ref, database_name, database_name_len);
- } else {
- memcpy(ref, database_name, database_name_len);
+#endif /* !__WIN__ */
+ /* The table name is always put to lower case on Windows. */
+ innobase_casedn_str(ref);
+#ifndef __WIN__
}
-#endif
- (ref)[database_name_len] = '/';
-
-#ifdef __WIN__
- ut_cpy_in_lower_case(ref + database_name_len + 1,
- table_name, table_name_len + 1);
-#else
- if (srv_lower_case_table_names) {
- ut_cpy_in_lower_case(ref + database_name_len + 1,
- table_name, table_name_len + 1);
- } else {
- strcpy(ref + database_name_len + 1, table_name);
- }
-#endif
+#endif /* !__WIN__ */
*success = TRUE;
*ref_name = ref;
@@ -2588,7 +2615,9 @@ dict_strip_comments(
char* str;
const char* sptr;
char* ptr;
-
+ /* unclosed quote character (0 if none) */
+ char quote = 0;
+
str = mem_alloc(strlen(sql_string) + 1);
sptr = sql_string;
@@ -2603,8 +2632,18 @@ scan_more:
return(str);
}
-
- if (*sptr == '#'
+
+ if (*sptr == quote) {
+ /* Closing quote character: do not look for
+ starting quote or comments. */
+ quote = 0;
+ } else if (quote) {
+ /* Within quotes: do not look for
+ starting quotes or comments. */
+ } else if (*sptr == '"' || *sptr == '`') {
+ /* Starting quote: remember the quote character. */
+ quote = *sptr;
+ } else if (*sptr == '#'
|| (0 == memcmp("-- ", sptr, 3))) {
for (;;) {
/* In Unix a newline is 0x0A while in Windows
@@ -2619,9 +2658,7 @@ scan_more:
sptr++;
}
- }
-
- if (*sptr == '/' && *(sptr + 1) == '*') {
+ } else if (!quote && *sptr == '/' && *(sptr + 1) == '*') {
for (;;) {
if (*sptr == '*' && *(sptr + 1) == '/') {
@@ -2946,10 +2983,11 @@ col_loop1:
mutex_enter(&dict_foreign_err_mutex);
dict_foreign_error_report_low(ef, name);
fputs("There is no index in table ", ef);
- ut_print_name(ef, name);
+ ut_print_name(ef, NULL, name);
fprintf(ef, " where the columns appear\n"
"as the first columns. Constraint:\n%s\n"
-"See http://www.innodb.com/ibman.php for correct foreign key definition.\n",
+"See http://dev.mysql.com/doc/mysql/en/InnoDB_foreign_key_constraints.html\n"
+"for correct foreign key definition.\n",
start_of_latest_foreign);
mutex_exit(&dict_foreign_err_mutex);
@@ -3214,7 +3252,8 @@ try_find_index:
"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"
-"See http://www.innodb.com/ibman.php for correct foreign key definition.\n",
+"See http://dev.mysql.com/doc/mysql/en/InnoDB_foreign_key_constraints.html\n"
+"for correct foreign key definition.\n",
start_of_latest_foreign);
mutex_exit(&dict_foreign_err_mutex);
@@ -3389,12 +3428,12 @@ loop:
ut_print_timestamp(ef);
fputs(
" Error in dropping of a foreign key constraint of table ", ef);
- ut_print_name(ef, table->name);
+ ut_print_name(ef, NULL, table->name);
fputs(",\n"
"in SQL command\n", ef);
fputs(str, ef);
fputs("\nCannot find a constraint with the given id ", ef);
- ut_print_name(ef, id);
+ ut_print_name(ef, NULL, id);
fputs(".\n", ef);
mutex_exit(&dict_foreign_err_mutex);
@@ -3411,7 +3450,7 @@ syntax_error:
ut_print_timestamp(ef);
fputs(
" Syntax error in dropping of a foreign key constraint of table ", ef);
- ut_print_name(ef, table->name);
+ ut_print_name(ef, NULL, table->name);
fprintf(ef, ",\n"
"close to:\n%s\n in SQL command\n%s\n", ptr, str);
mutex_exit(&dict_foreign_err_mutex);
@@ -3818,9 +3857,11 @@ dict_update_statistics_low(
if (table->ibd_file_missing) {
ut_print_timestamp(stderr);
fprintf(stderr,
-" InnoDB: cannot calculate statistics for table %s\n"
-"InnoDB: because the .ibd file is missing. See section 15.1 of\n"
-"InnoDB: http:/www.innodb.com/ibman.html for help\n", table->name);
+ " InnoDB: cannot calculate statistics for table %s\n"
+"InnoDB: because the .ibd file is missing. For help, please refer to\n"
+"InnoDB: "
+"http://dev.mysql.com/doc/mysql/en/InnoDB_troubleshooting_datadict.html\n",
+ table->name);
return;
}
@@ -3906,25 +3947,19 @@ dict_foreign_print_low(
ut_ad(mutex_own(&(dict_sys->mutex)));
#endif /* UNIV_SYNC_DEBUG */
- fputs(" FOREIGN KEY CONSTRAINT ", stderr);
- ut_print_name(stderr, foreign->id);
- fputs(": ", stderr);
- ut_print_name(stderr, foreign->foreign_table_name);
- fputs(" (", stderr);
+ fprintf(stderr, " FOREIGN KEY CONSTRAINT %s: %s (",
+ foreign->id, foreign->foreign_table_name);
for (i = 0; i < foreign->n_fields; i++) {
- putc(' ', stderr);
- ut_print_name(stderr, foreign->foreign_col_names[i]);
+ fprintf(stderr, " %s", foreign->foreign_col_names[i]);
}
- fputs(" )\n"
- " REFERENCES ", stderr);
- ut_print_name(stderr, foreign->referenced_table_name);
- fputs(" (", stderr);
+ fprintf(stderr, " )\n"
+ " REFERENCES %s (",
+ foreign->referenced_table_name);
for (i = 0; i < foreign->n_fields; i++) {
- putc(' ', stderr);
- ut_print_name(stderr, foreign->referenced_col_names[i]);
+ fprintf(stderr, " %s", foreign->referenced_col_names[i]);
}
fputs(" )\n", stderr);
@@ -3981,12 +4016,11 @@ dict_table_print_low(
dict_update_statistics_low(table, TRUE);
- fputs("--------------------------------------\n"
- "TABLE: name ", stderr);
- ut_print_name(stderr, table->name);
fprintf(stderr,
- ", id %lu %lu, columns %lu, indexes %lu, appr.rows %lu\n"
- " COLUMNS: ",
+"--------------------------------------\n"
+"TABLE: name %s, id %lu %lu, columns %lu, indexes %lu, appr.rows %lu\n"
+" COLUMNS: ",
+ table->name,
(ulong) ut_dulint_get_high(table->id),
(ulong) ut_dulint_get_low(table->id),
(ulong) table->n_cols,
@@ -4037,8 +4071,7 @@ dict_col_print_low(
#endif /* UNIV_SYNC_DEBUG */
type = dict_col_get_type(col);
- ut_print_name(stderr, col->name);
- fputs(": ", stderr);
+ fprintf(stderr, "%s: ", col->name);
dtype_print(type);
}
@@ -4068,13 +4101,12 @@ dict_index_print_low(
n_vals = index->stat_n_diff_key_vals[1];
}
- fputs(" INDEX: ", stderr);
- dict_index_name_print(stderr, index);
fprintf(stderr,
- ", id %lu %lu, fields %lu/%lu, type %lu\n"
+ " INDEX: name %s, id %lu %lu, fields %lu/%lu, type %lu\n"
" root page %lu, appr.key vals %lu,"
" leaf pages %lu, size pages %lu\n"
" FIELDS: ",
+ index->name,
(ulong) ut_dulint_get_high(tree->id),
(ulong) ut_dulint_get_low(tree->id),
(ulong) index->n_user_defined_cols,
@@ -4106,8 +4138,7 @@ dict_field_print_low(
#ifdef UNIV_SYNC_DEBUG
ut_ad(mutex_own(&(dict_sys->mutex)));
#endif /* UNIV_SYNC_DEBUG */
- putc(' ', stderr);
- ut_print_name(stderr, field->name);
+ fprintf(stderr, " %s", field->name);
if (field->prefix_len != 0) {
fprintf(stderr, "(%lu)", (ulong) field->prefix_len);
@@ -4122,6 +4153,7 @@ void
dict_print_info_on_foreign_key_in_create_format(
/*============================================*/
FILE* file, /* in: file where to print */
+ trx_t* trx, /* in: transaction */
dict_foreign_t* foreign)/* in: foreign key constraint */
{
const char* stripped_id;
@@ -4136,11 +4168,11 @@ dict_print_info_on_foreign_key_in_create_format(
}
fputs(",\n CONSTRAINT ", file);
- ut_print_name(file, stripped_id);
+ ut_print_name(file, trx, stripped_id);
fputs(" FOREIGN KEY (", file);
for (i = 0;;) {
- ut_print_name(file, foreign->foreign_col_names[i]);
+ ut_print_name(file, trx, foreign->foreign_col_names[i]);
if (++i < foreign->n_fields) {
fputs(", ", file);
} else {
@@ -4153,7 +4185,7 @@ dict_print_info_on_foreign_key_in_create_format(
if (dict_tables_have_same_db(foreign->foreign_table_name,
foreign->referenced_table_name)) {
/* Do not print the database name of the referenced table */
- ut_print_name(file, dict_remove_db_name(
+ ut_print_name(file, trx, dict_remove_db_name(
foreign->referenced_table_name));
} else {
/* Look for the '/' in the table name */
@@ -4163,16 +4195,17 @@ dict_print_info_on_foreign_key_in_create_format(
i++;
}
- ut_print_namel(file, foreign->referenced_table_name, i);
+ ut_print_namel(file, trx, foreign->referenced_table_name, i);
putc('.', file);
- ut_print_name(file, foreign->referenced_table_name + i + 1);
+ ut_print_name(file, trx,
+ foreign->referenced_table_name + i + 1);
}
putc(' ', file);
putc('(', file);
for (i = 0;;) {
- ut_print_name(file, foreign->referenced_col_names[i]);
+ ut_print_name(file, trx, foreign->referenced_col_names[i]);
if (++i < foreign->n_fields) {
fputs(", ", file);
} else {
@@ -4218,6 +4251,7 @@ dict_print_info_on_foreign_keys(
a CREATE TABLE, otherwise in the format
of SHOW TABLE STATUS */
FILE* file, /* in: file where to print */
+ trx_t* trx, /* in: transaction */
dict_table_t* table) /* in: table */
{
dict_foreign_t* foreign;
@@ -4235,7 +4269,7 @@ dict_print_info_on_foreign_keys(
while (foreign != NULL) {
if (create_table_format) {
dict_print_info_on_foreign_key_in_create_format(
- file, foreign);
+ file, trx, foreign);
} else {
ulint i;
fputs("; (", file);
@@ -4245,19 +4279,20 @@ dict_print_info_on_foreign_keys(
putc(' ', file);
}
- ut_print_name(file,
+ ut_print_name(file, trx,
foreign->foreign_col_names[i]);
}
fputs(") REFER ", file);
- ut_print_name(file, foreign->referenced_table_name);
+ ut_print_name(file, trx,
+ foreign->referenced_table_name);
putc('(', file);
for (i = 0; i < foreign->n_fields; i++) {
if (i) {
putc(' ', file);
}
- ut_print_name(file,
+ ut_print_name(file, trx,
foreign->referenced_col_names[i]);
}
@@ -4300,10 +4335,11 @@ void
dict_index_name_print(
/*==================*/
FILE* file, /* in: output stream */
+ trx_t* trx, /* in: transaction */
const dict_index_t* index) /* in: index to print */
{
fputs("index ", file);
- ut_print_name(file, index->name);
+ ut_print_name(file, trx, index->name);
fputs(" of table ", file);
- ut_print_name(file, index->table_name);
+ ut_print_name(file, trx, index->table_name);
}
diff --git a/innobase/dict/dict0load.c b/innobase/dict/dict0load.c
index ee4ae9dd1a1..d430eadc97b 100644
--- a/innobase/dict/dict0load.c
+++ b/innobase/dict/dict0load.c
@@ -30,7 +30,7 @@ dict_get_first_table_name_in_db(
/* out, own: table name, NULL if
does not exist; the caller must
free the memory in the string! */
- const char* name) /* in: database name which ends to '/' */
+ const char* name) /* in: database name which ends in '/' */
{
dict_table_t* sys_tables;
btr_pcur_t pcur;
@@ -92,7 +92,7 @@ loop:
/* We found one */
- char* table_name = mem_strdupl(field, len);
+ char* table_name = mem_strdupl((char*) field, len);
btr_pcur_close(&pcur);
mtr_commit(&mtr);
@@ -154,7 +154,7 @@ loop:
/* We found one */
- char* table_name = mem_strdupl(field, len);
+ char* table_name = mem_strdupl((char*) field, len);
btr_pcur_store_position(&pcur, &mtr);
@@ -165,7 +165,7 @@ loop:
if (table == NULL) {
fputs("InnoDB: Failed to load table ", stderr);
- ut_print_namel(stderr, field, len);
+ ut_print_namel(stderr, NULL, field, len);
putc('\n', stderr);
} else {
/* The table definition was corrupt if there
@@ -246,7 +246,7 @@ loop:
/* We found one */
- char* name = mem_strdupl(field, len);
+ char* name = mem_strdupl((char*) field, len);
field = rec_get_nth_field(rec, 9, &len);
ut_a(len == 4);
@@ -262,7 +262,7 @@ loop:
exists; print a warning to the .err log if not */
fil_space_for_table_exists_in_mem(space_id, name,
- TRUE, TRUE);
+ FALSE, TRUE, TRUE);
}
mem_free(name);
@@ -347,7 +347,7 @@ dict_load_columns(
dict_table_get_first_index(sys_columns), 4))->name));
field = rec_get_nth_field(rec, 4, &len);
- name = mem_heap_strdupl(heap, field, len);
+ name = mem_heap_strdupl(heap, (char*) field, len);
field = rec_get_nth_field(rec, 5, &len);
mtype = mach_read_from_4(field);
@@ -389,18 +389,16 @@ Report that an index field or index for a table has been delete marked. */
static
void
dict_load_report_deleted_index(
+/*===========================*/
const char* name, /* in: table name */
ulint field) /* in: index field, or ULINT_UNDEFINED */
{
- fputs("InnoDB: Error: data dictionary entry"
- " for table ", stderr);
- ut_print_name(stderr, name);
- fputs(" is corrupt!\n", stderr);
+ fprintf(stderr, "InnoDB: Error: data dictionary entry"
+ " for table %s is corrupt!\n", name);
if (field != ULINT_UNDEFINED) {
fprintf(stderr,
"InnoDB: Index field %lu is delete marked.\n", field);
- }
- else {
+ } else {
fputs("InnoDB: An index is delete marked.\n", stderr);
}
}
@@ -496,7 +494,7 @@ dict_load_fields(
field = rec_get_nth_field(rec, 4, &len);
dict_mem_index_add_field(index,
- mem_heap_strdupl(heap, field, len), 0, prefix_len);
+ mem_heap_strdupl(heap, (char*) field, len), 0, prefix_len);
btr_pcur_move_to_next_user_rec(&pcur, &mtr);
}
@@ -599,7 +597,7 @@ dict_load_indexes(
dict_table_get_first_index(sys_indexes), 4))->name));
field = rec_get_nth_field(rec, 4, &name_len);
- name_buf = mem_heap_strdupl(heap, field, name_len);
+ name_buf = mem_heap_strdupl(heap, (char*) field, name_len);
field = rec_get_nth_field(rec, 5, &len);
n_fields = mach_read_from_4(field);
@@ -620,12 +618,10 @@ dict_load_indexes(
if (page_no == FIL_NULL) {
- fputs("InnoDB: Error: trying to load index ", stderr);
- ut_print_name(stderr, name_buf);
- fputs(" for table ", stderr);
- ut_print_name(stderr, table->name);
- fputs("\n"
- "InnoDB: but the index tree has been freed!\n", stderr);
+ fprintf(stderr,
+ "InnoDB: Error: trying to load index %s for table %s\n"
+ "InnoDB: but the index tree has been freed!\n",
+ name_buf, table->name);
btr_pcur_close(&pcur);
mtr_commit(&mtr);
@@ -636,12 +632,10 @@ dict_load_indexes(
if ((type & DICT_CLUSTERED) == 0
&& NULL == dict_table_get_first_index(table)) {
- fputs("InnoDB: Error: trying to load index ", stderr);
- ut_print_namel(stderr, name_buf, name_len);
- fputs(" for table ", stderr);
- ut_print_name(stderr, table->name);
- fputs("\n"
- "InnoDB: but the first index is not clustered!\n", stderr);
+ fprintf(stderr,
+ "InnoDB: Error: trying to load index %s for table %s\n"
+ "InnoDB: but the first index is not clustered!\n",
+ name_buf, table->name);
btr_pcur_close(&pcur);
mtr_commit(&mtr);
@@ -767,7 +761,7 @@ dict_load_table(
/* Check if the tablespace exists and has the right name */
if (space != 0) {
if (fil_space_for_table_exists_in_mem(space, name, FALSE,
- FALSE)) {
+ FALSE, FALSE)) {
/* Ok; (if we did a crash recovery then the tablespace
can already be in the memory cache) */
} else {
@@ -811,7 +805,7 @@ dict_load_table(
table->mix_id = mach_read_from_8(field);
field = rec_get_nth_field(rec, 8, &len);
- table->cluster_name = mem_heap_strdupl(heap, field, len);
+ table->cluster_name = mem_heap_strdupl(heap, (char*) field, len);
#endif
}
@@ -944,7 +938,7 @@ dict_load_table_on_id(
/* Now we get the table name from the record */
field = rec_get_nth_field(rec, 1, &len);
/* Load the table definition to memory */
- table = dict_load_table(mem_heap_strdupl(heap, field, len));
+ table = dict_load_table(mem_heap_strdupl(heap, (char*) field, len));
btr_pcur_close(&pcur);
mtr_commit(&mtr);
@@ -1036,11 +1030,11 @@ dict_load_foreign_cols(
field = rec_get_nth_field(rec, 4, &len);
foreign->foreign_col_names[i] =
- mem_heap_strdupl(foreign->heap, field, len);
+ mem_heap_strdupl(foreign->heap, (char*) field, len);
field = rec_get_nth_field(rec, 5, &len);
foreign->referenced_col_names[i] =
- mem_heap_strdupl(foreign->heap, field, len);
+ mem_heap_strdupl(foreign->heap, (char*) field, len);
btr_pcur_move_to_next_user_rec(&pcur, &mtr);
}
@@ -1097,10 +1091,9 @@ dict_load_foreign(
|| rec_get_deleted_flag(rec)) {
/* Not found */
- fputs("InnoDB: Error A: cannot load foreign constraint ",
- stderr);
- ut_print_name(stderr, id);
- putc('\n', stderr);
+ fprintf(stderr,
+ "InnoDB: Error A: cannot load foreign constraint %s\n",
+ id);
btr_pcur_close(&pcur);
mtr_commit(&mtr);
@@ -1114,10 +1107,9 @@ dict_load_foreign(
/* Check if the id in record is the searched one */
if (len != ut_strlen(id) || ut_memcmp(id, field, len) != 0) {
- fputs("InnoDB: Error B: cannot load foreign constraint ",
- stderr);
- ut_print_name(stderr, id);
- putc('\n', stderr);
+ fprintf(stderr,
+ "InnoDB: Error B: cannot load foreign constraint %s\n",
+ id);
btr_pcur_close(&pcur);
mtr_commit(&mtr);
@@ -1146,11 +1138,11 @@ dict_load_foreign(
field = rec_get_nth_field(rec, 3, &len);
foreign->foreign_table_name =
- mem_heap_strdupl(foreign->heap, field, len);
+ mem_heap_strdupl(foreign->heap, (char*) field, len);
field = rec_get_nth_field(rec, 4, &len);
foreign->referenced_table_name =
- mem_heap_strdupl(foreign->heap, field, len);
+ mem_heap_strdupl(foreign->heap, (char*) field, len);
btr_pcur_close(&pcur);
mtr_commit(&mtr);
@@ -1264,7 +1256,7 @@ loop:
/* Now we get a foreign key constraint id */
field = rec_get_nth_field(rec, 1, &len);
- id = mem_heap_strdupl(heap, field, len);
+ id = mem_heap_strdupl(heap, (char*) field, len);
btr_pcur_store_position(&pcur, &mtr);
diff --git a/innobase/dict/dict0mem.c b/innobase/dict/dict0mem.c
index 8f05475df47..1d45585aac1 100644
--- a/innobase/dict/dict0mem.c
+++ b/innobase/dict/dict0mem.c
@@ -50,6 +50,7 @@ dict_mem_table_create(
table->type = DICT_TABLE_ORDINARY;
table->name = mem_heap_strdup(heap, name);
+ table->dir_path_of_temp_table = NULL;
table->space = space;
table->ibd_file_missing = FALSE;
table->tablespace_discarded = FALSE;
diff --git a/innobase/fil/fil0fil.c b/innobase/fil/fil0fil.c
index 885738deae2..7d57468f632 100644
--- a/innobase/fil/fil0fil.c
+++ b/innobase/fil/fil0fil.c
@@ -428,7 +428,9 @@ fil_node_create(
ut_print_timestamp(stderr);
fprintf(stderr,
" InnoDB: Error: Could not find tablespace %lu for\n"
-"InnoDB: file %s from the tablespace memory cache.\n", (ulong) id, name);
+"InnoDB: file ", (ulong) id);
+ ut_print_filename(stderr, name);
+ fputs(" in the tablespace memory cache.\n", stderr);
mem_free(node->name);
mem_free(node);
@@ -596,16 +598,19 @@ fil_try_to_close_file_in_LRU(
}
if (print_info && node->n_pending_flushes > 0) {
- fprintf(stderr,
-"InnoDB: cannot close file %s, because n_pending_flushes %lu\n", node->name,
+ fputs("InnoDB: cannot close file ", stderr);
+ ut_print_filename(stderr, node->name);
+ fprintf(stderr, ", because n_pending_flushes %lu\n",
(ulong) node->n_pending_flushes);
}
if (print_info
&& node->modification_counter != node->flush_counter) {
+ fputs("InnoDB: cannot close file ", stderr);
+ ut_print_filename(stderr, node->name);
fprintf(stderr,
-"InnoDB: cannot close file %s, because mod_count %lld != fl_count %lld\n",
- node->name, node->modification_counter,
+ ", because mod_count %lld != fl_count %lld\n",
+ node->modification_counter,
node->flush_counter);
}
@@ -660,10 +665,11 @@ retry:
for a while */
if (count2 > 20000) {
+ fputs("InnoDB: Warning: tablespace ", stderr);
+ ut_print_filename(stderr, space->name);
fprintf(stderr,
-"InnoDB: Warning: tablespace %s has i/o ops stopped for a long time %lu\n",
- space->name,
- (ulong) count2);
+ " has i/o ops stopped for a long time %lu\n",
+ (ulong) count2);
}
mutex_exit(&(system->mutex));
@@ -833,11 +839,12 @@ try_again:
ut_print_timestamp(stderr);
fprintf(stderr,
" InnoDB: Warning: trying to init to the tablespace memory cache\n"
-"InnoDB: a tablespace %lu of name %s,\n"
-"InnoDB: but a tablespace %lu of the same name %s\n"
+"InnoDB: a tablespace %lu of name ", (ulong) id);
+ ut_print_filename(stderr, name);
+ fprintf(stderr, ",\n"
+"InnoDB: but a tablespace %lu of the same name\n"
"InnoDB: already exists in the tablespace memory cache!\n",
- (ulong) id, name,
- (ulong) space->id, space->name);
+ (ulong) space->id);
if (id == 0 || purpose != FIL_TABLESPACE) {
@@ -868,10 +875,14 @@ try_again:
if (space != NULL) {
fprintf(stderr,
-"InnoDB: Error: trying to add tablespace %lu of name %s\n"
+"InnoDB: Error: trying to add tablespace %lu of name ", (ulong) id);
+ ut_print_filename(stderr, name);
+ fprintf(stderr, "\n"
"InnoDB: to the tablespace memory cache, but tablespace\n"
-"InnoDB: %lu of name %s already exists in the tablespace\n"
-"InnoDB: memory cache!\n", (ulong) id, name, (ulong) space->id, space->name);
+"InnoDB: %lu of name ", (ulong) space->id);
+ ut_print_filename(stderr, space->name);
+ fputs(" already exists in the tablespace\n"
+"InnoDB: memory cache!\n", stderr);
mutex_exit(&(system->mutex));
@@ -948,7 +959,7 @@ fil_assign_new_space_id(void)
"InnoDB: Current counter is %lu and it must not exceed %lu!\n"
"InnoDB: To reset the counter to zero you have to dump all your tables and\n"
"InnoDB: recreate the whole InnoDB installation.\n", (ulong) id,
- (ulong) SRV_LOG_SPACE_FIRST_ID);
+ (ulong) SRV_LOG_SPACE_FIRST_ID);
}
if (id >= SRV_LOG_SPACE_FIRST_ID) {
@@ -1729,7 +1740,7 @@ fil_op_log_parse_or_replay(
ut_a(DB_SUCCESS ==
fil_create_new_single_table_tablespace(
- &space_id, name,
+ &space_id, name, FALSE,
FIL_IBD_FILE_INITIAL_SIZE));
}
}
@@ -1772,10 +1783,12 @@ stop_ibuf_merges:
} else {
if (count > 5000) {
ut_print_timestamp(stderr);
- fprintf(stderr,
-" InnoDB: Warning: trying to delete tablespace %s,\n"
+ fputs(
+" InnoDB: Warning: trying to delete tablespace ", stderr);
+ ut_print_filename(stderr, space->name);
+ fprintf(stderr, ",\n"
"InnoDB: but there are %lu pending ibuf merges on it.\n"
-"InnoDB: Loop %lu.\n", space->name, (ulong) space->n_pending_ibuf_merges,
+"InnoDB: Loop %lu.\n", (ulong) space->n_pending_ibuf_merges,
(ulong) count);
}
@@ -1819,10 +1832,12 @@ try_again:
if (space->n_pending_flushes > 0 || node->n_pending > 0) {
if (count > 1000) {
ut_print_timestamp(stderr);
- fprintf(stderr,
-" InnoDB: Warning: trying to delete tablespace %s,\n"
+ fputs(
+" InnoDB: Warning: trying to delete tablespace ", stderr);
+ ut_print_filename(stderr, space->name);
+ fprintf(stderr, ",\n"
"InnoDB: but there are %lu flushes and %lu pending i/o's on it\n"
-"InnoDB: Loop %lu.\n", space->name, (ulong) space->n_pending_flushes,
+"InnoDB: Loop %lu.\n", (ulong) space->n_pending_flushes,
(ulong) node->n_pending,
(ulong) count);
}
@@ -1853,6 +1868,10 @@ try_again:
if (success) {
success = os_file_delete(path);
+
+ if (!success) {
+ success = os_file_delete_if_exists(path);
+ }
}
if (success) {
@@ -1931,8 +1950,9 @@ fil_rename_tablespace_in_mem(
HASH_SEARCH(name_hash, system->name_hash, ut_fold_string(old_name),
space2, 0 == strcmp(old_name, space2->name));
if (space != space2) {
- fprintf(stderr,
-"InnoDB: Error: cannot find %s in tablespace memory cache\n", old_name);
+ fputs("InnoDB: Error: cannot find ", stderr);
+ ut_print_filename(stderr, old_name);
+ fputs(" in tablespace memory cache\n", stderr);
return(FALSE);
}
@@ -1940,8 +1960,9 @@ fil_rename_tablespace_in_mem(
HASH_SEARCH(name_hash, system->name_hash, ut_fold_string(path),
space2, 0 == strcmp(path, space2->name));
if (space2 != NULL) {
- fprintf(stderr,
-"InnoDB: Error: %s is already in tablespace memory cache\n", path);
+ fputs("InnoDB: Error: ", stderr);
+ ut_print_filename(stderr, path);
+ fputs(" is already in tablespace memory cache\n", stderr);
return(FALSE);
}
@@ -1960,25 +1981,34 @@ fil_rename_tablespace_in_mem(
}
/***********************************************************************
-Allocates a file name for a single-table tablespace.
-The string must be freed by caller with mem_free(). */
+Allocates a file name for a single-table tablespace. The string must be freed
+by caller with mem_free(). */
static
char*
fil_make_ibd_name(
/*==============*/
/* out, own: file name */
- const char* name) /* in: table name */
+ const char* name, /* in: table name or a dir path of a
+ TEMPORARY table */
+ ibool is_temp) /* in: TRUE if it is a dir path */
{
ulint namelen = strlen(name);
ulint dirlen = strlen(fil_path_to_mysql_datadir);
char* filename = mem_alloc(namelen + dirlen + sizeof "/.ibd");
- memcpy(filename, fil_path_to_mysql_datadir, dirlen);
- filename[dirlen] = '/';
- memcpy(filename + dirlen + 1, name, namelen);
- memcpy(filename + dirlen + namelen + 1, ".ibd", sizeof ".ibd");
+ if (is_temp) {
+ memcpy(filename, name, namelen);
+ memcpy(filename + namelen, ".ibd", sizeof ".ibd");
+ } else {
+ memcpy(filename, fil_path_to_mysql_datadir, dirlen);
+ filename[dirlen] = '/';
+
+ memcpy(filename + dirlen + 1, name, namelen);
+ memcpy(filename + dirlen + namelen + 1, ".ibd", sizeof ".ibd");
+ }
srv_normalize_path_for_win(filename);
+
return(filename);
}
@@ -2019,10 +2049,11 @@ retry:
if (count > 1000) {
ut_print_timestamp(stderr);
- fprintf(stderr,
-" InnoDB: Warning: problems renaming %s to %s, %lu iterations\n",
- old_name, new_name,
- (ulong) count);
+ fputs(" InnoDB: Warning: problems renaming ", stderr);
+ ut_print_filename(stderr, old_name);
+ fputs(" to ", stderr);
+ ut_print_filename(stderr, new_name);
+ fprintf(stderr, ", %lu iterations\n", (ulong) count);
}
mutex_enter(&(system->mutex));
@@ -2032,8 +2063,9 @@ retry:
if (space == NULL) {
fprintf(stderr,
"InnoDB: Error: cannot find space id %lu from the tablespace memory cache\n"
-"InnoDB: though the table %s in a rename operation should have that id\n",
- (ulong) id, old_name);
+"InnoDB: though the table ", (ulong) id);
+ ut_print_filename(stderr, old_name);
+ fputs(" in a rename operation should have that id\n", stderr);
mutex_exit(&(system->mutex));
return(FALSE);
@@ -2085,7 +2117,7 @@ retry:
/* Check that the old name in the space is right */
if (old_name_was_specified) {
- old_path = fil_make_ibd_name(old_name);
+ old_path = fil_make_ibd_name(old_name, FALSE);
ut_a(strcmp(space->name, old_path) == 0);
ut_a(strcmp(node->name, old_path) == 0);
@@ -2094,7 +2126,7 @@ retry:
}
/* Rename the tablespace and the node in the memory cache */
- path = fil_make_ibd_name(new_name);
+ path = fil_make_ibd_name(new_name, FALSE);
success = fil_rename_tablespace_in_mem(space, node, path);
if (success) {
@@ -2134,7 +2166,8 @@ retry:
Creates a new single-table tablespace to a database directory of MySQL.
Database directories are under the 'datadir' of MySQL. The datadir is the
directory of a running mysqld program. We can refer to it by simply the
-path '.'. */
+path '.'. Tables created with CREATE TEMPORARY TABLE we place in the temp
+dir of the mysqld server. */
ulint
fil_create_new_single_table_tablespace(
@@ -2145,7 +2178,10 @@ fil_create_new_single_table_tablespace(
otherwise output */
const char* tablename, /* in: the table name in the usual
databasename/tablename format
- of InnoDB */
+ of InnoDB, or a dir path to a temp
+ table */
+ ibool is_temp, /* in: TRUE if a table created with
+ CREATE TEMPORARY TABLE */
ulint size) /* in: the initial size of the
tablespace file in pages,
must be >= FIL_IBD_FILE_INITIAL_SIZE */
@@ -2160,28 +2196,31 @@ fil_create_new_single_table_tablespace(
ut_a(size >= FIL_IBD_FILE_INITIAL_SIZE);
- path = fil_make_ibd_name(tablename);
+ path = fil_make_ibd_name(tablename, is_temp);
file = os_file_create(path, OS_FILE_CREATE, OS_FILE_NORMAL,
OS_DATA_FILE, &ret);
if (ret == FALSE) {
ut_print_timestamp(stderr);
- fprintf(stderr,
-" InnoDB: Error creating file %s.\n", path);
+ fputs(" InnoDB: Error creating file ", stderr);
+ ut_print_filename(stderr, path);
+ fputs(".\n", stderr);
/* The following call will print an error message */
err = os_file_get_last_error(TRUE);
if (err == OS_FILE_ALREADY_EXISTS) {
- fprintf(stderr,
+ fputs(
"InnoDB: The file already exists though the corresponding table did not\n"
"InnoDB: exist in the InnoDB data dictionary. Have you moved InnoDB\n"
"InnoDB: .ibd files around without using the SQL commands\n"
"InnoDB: DISCARD TABLESPACE and IMPORT TABLESPACE, or did\n"
"InnoDB: mysqld crash in the middle of CREATE TABLE? You can\n"
-"InnoDB: resolve the problem by removing the file %s\n"
-"InnoDB: under the 'datadir' of MySQL.\n", path);
+"InnoDB: resolve the problem by removing the file ", stderr);
+ ut_print_filename(stderr, path);
+ fputs("\n"
+"InnoDB: under the 'datadir' of MySQL.\n", stderr);
mem_free(path);
return(DB_TABLESPACE_ALREADY_EXISTS);
@@ -2249,16 +2288,20 @@ fil_create_new_single_table_tablespace(
ut_free(buf2);
if (!ret) {
- fprintf(stderr,
-"InnoDB: Error: could not write the first page to tablespace %s\n", path);
+ fputs(
+"InnoDB: Error: could not write the first page to tablespace ", stderr);
+ ut_print_filename(stderr, path);
+ putc('\n', stderr);
goto error_exit;
}
ret = os_file_flush(file);
if (!ret) {
- fprintf(stderr,
-"InnoDB: Error: file flush of tablespace %s failed\n", path);
+ fputs(
+"InnoDB: Error: file flush of tablespace ", stderr);
+ ut_print_filename(stderr, path);
+ fputs(" failed\n", stderr);
goto error_exit;
}
@@ -2322,11 +2365,21 @@ fil_reset_too_high_lsns(
ulint page_no;
ibool success;
- filepath = fil_make_ibd_name(name);
+ filepath = fil_make_ibd_name(name, FALSE);
file = os_file_create_simple_no_error_handling(filepath, OS_FILE_OPEN,
OS_FILE_READ_WRITE, &success);
if (!success) {
+ /* The following call prints an error message */
+ os_file_get_last_error(TRUE);
+
+ ut_print_timestamp(stderr);
+
+ fputs(
+" InnoDB: Error: trying to open a table, but could not\n"
+"InnoDB: open the tablespace file ", stderr);
+ ut_print_filename(stderr, filepath);
+ fputs("!\n", stderr);
mem_free(filepath);
return(FALSE);
@@ -2361,12 +2414,14 @@ fil_reset_too_high_lsns(
fprintf(stderr,
" InnoDB: Flush lsn in the tablespace file %lu to be imported\n"
"InnoDB: is %lu %lu, which exceeds current system lsn %lu %lu.\n"
-"InnoDB: We reset the lsn's in the file %s.\n",
+"InnoDB: We reset the lsn's in the file ",
(ulong) space_id,
(ulong) ut_dulint_get_high(flush_lsn),
(ulong) ut_dulint_get_low(flush_lsn),
(ulong) ut_dulint_get_high(current_lsn),
- (ulong) ut_dulint_get_low(current_lsn), filepath);
+ (ulong) ut_dulint_get_low(current_lsn));
+ ut_print_filename(stderr, filepath);
+ fputs(".\n", stderr);
/* Loop through all the pages in the tablespace and reset the lsn and
the page checksum if necessary */
@@ -2454,7 +2509,7 @@ fil_open_single_table_tablespace(
ulint space_id;
ibool ret = TRUE;
- filepath = fil_make_ibd_name(name);
+ filepath = fil_make_ibd_name(name, FALSE);
file = os_file_create_simple_no_error_handling(filepath, OS_FILE_OPEN,
OS_FILE_READ_ONLY, &success);
@@ -2464,14 +2519,19 @@ fil_open_single_table_tablespace(
ut_print_timestamp(stderr);
- fprintf(stderr,
+ fputs(
" InnoDB: Error: trying to open a table, but could not\n"
-"InnoDB: open the tablespace file %s!\n", filepath);
- fprintf(stderr,
-"InnoDB: have you moved InnoDB .ibd files around without using the\n"
+"InnoDB: open the tablespace file ", stderr);
+ ut_print_filename(stderr, filepath);
+ fputs("!\n"
+"InnoDB: Have you moved InnoDB .ibd files around without using the\n"
"InnoDB: commands DISCARD TABLESPACE and IMPORT TABLESPACE?\n"
-"InnoDB: You can look from section 15.1 of http://www.innodb.com/ibman.html\n"
-"InnoDB: how to resolve the issue.\n");
+"InnoDB: It is also possible that this is a table created with\n"
+"InnoDB: CREATE TEMPORARY TABLE, and MySQL removed the .ibd file for this.\n"
+"InnoDB: Please refer to\n"
+"InnoDB:"
+" http://dev.mysql.com/doc/mysql/en/InnoDB_troubleshooting_datadict.html\n"
+"InnoDB: how to resolve the issue.\n", stderr);
mem_free(filepath);
@@ -2493,14 +2553,17 @@ fil_open_single_table_tablespace(
if (space_id != id) {
ut_print_timestamp(stderr);
- fprintf(stderr,
-" InnoDB: Error: tablespace id in file %s is %lu, but in the InnoDB\n"
-"InnoDB: data dictionary it is %lu.\n", filepath, (ulong) space_id, (ulong) id);
- fprintf(stderr,
+ fputs(
+" InnoDB: Error: tablespace id in file ", stderr);
+ ut_print_filename(stderr, filepath);
+ fprintf(stderr, " is %lu, but in the InnoDB\n"
+"InnoDB: data dictionary it is %lu.\n"
"InnoDB: Have you moved InnoDB .ibd files around without using the\n"
"InnoDB: commands DISCARD TABLESPACE and IMPORT TABLESPACE?\n"
-"InnoDB: You can look from section 15.1 of http://www.innodb.com/ibman.html\n"
-"InnoDB: how to resolve the issue.\n");
+"InnoDB: Please refer to\n"
+"InnoDB:"
+" http://dev.mysql.com/doc/mysql/en/InnoDB_troubleshooting_datadict.html\n"
+"InnoDB: how to resolve the issue.\n", (ulong) space_id, (ulong) id);
ret = FALSE;
@@ -2867,8 +2930,10 @@ next_file_item:
}
if (0 != os_file_closedir(dbdir)) {
- fprintf(stderr,
-"InnoDB: Warning: could not close database directory %s\n", dbpath);
+ fputs(
+"InnoDB: Warning: could not close database directory ", stderr);
+ ut_print_filename(stderr, dbpath);
+ putc('\n', stderr);
}
}
@@ -2921,9 +2986,10 @@ fil_print_orphaned_tablespaces(void)
while (space) {
if (space->purpose == FIL_TABLESPACE && space->id != 0
&& !space->mark) {
- fprintf(stderr,
-"InnoDB: Warning: tablespace %s of id %lu has no matching table in\n"
-"InnoDB: the InnoDB data dictionary.\n", space->name, (ulong) space->id);
+ fputs("InnoDB: Warning: tablespace ", stderr);
+ ut_print_filename(stderr, space->name);
+ fprintf(stderr, " of id %lu has no matching table in\n"
+"InnoDB: the InnoDB data dictionary.\n", (ulong) space->id);
}
space = UT_LIST_GET_NEXT(space_list, space);
@@ -3014,7 +3080,10 @@ fil_space_for_table_exists_in_mem(
exists in the memory cache */
ulint id, /* in: space id */
const char* name, /* in: table name in the standard
- 'databasename/tablename' format */
+ 'databasename/tablename' format or
+ the dir path to a temp table */
+ ibool is_temp, /* in: TRUE if created with CREATE
+ TEMPORARY TABLE */
ibool mark_space, /* in: in crash recovery, at database
startup we mark all spaces which have
an associated table in the InnoDB
@@ -3036,7 +3105,7 @@ fil_space_for_table_exists_in_mem(
mutex_enter(&(system->mutex));
- path = fil_make_ibd_name(name);
+ path = fil_make_ibd_name(name, is_temp);
/* Look if there is a space with the same id */
@@ -3072,26 +3141,34 @@ fil_space_for_table_exists_in_mem(
if (space == NULL) {
if (namespace == NULL) {
ut_print_timestamp(stderr);
- fprintf(stderr,
-" InnoDB: Error: table %s\n"
+ fputs(" InnoDB: Error: table ", stderr);
+ ut_print_filename(stderr, name);
+ fprintf(stderr, "\n"
"InnoDB: in InnoDB data dictionary has tablespace id %lu,\n"
"InnoDB: but tablespace with that id or name does not exist. Have\n"
-"InnoDB: you deleted or moved .ibd files?\n",
- name, (ulong) id);
+"InnoDB: you deleted or moved .ibd files?\n"
+"InnoDB: This may also be a table created with CREATE TEMPORARY TABLE\n"
+"InnoDB: whose .ibd and .frm files MySQL automatically removed, but the\n"
+"InnoDB: table still exists in the InnoDB internal data dictionary.\n",
+ (ulong) id);
} else {
ut_print_timestamp(stderr);
- fprintf(stderr,
-" InnoDB: Error: table %s\n"
+ fputs(" InnoDB: Error: table ", stderr);
+ ut_print_filename(stderr, name);
+ fprintf(stderr, "\n"
"InnoDB: in InnoDB data dictionary has tablespace id %lu,\n"
"InnoDB: but tablespace with that id does not exist. There is\n"
"InnoDB: a tablespace of name %s and id %lu, though. Have\n"
"InnoDB: you deleted or moved .ibd files?\n",
- name, (ulong) id, namespace->name,
+ (ulong) id, namespace->name,
(ulong) namespace->id);
}
- fprintf(stderr,
-"InnoDB: You can look from section 15.1 of http://www.innodb.com/ibman.html\n"
-"InnoDB: how to resolve the issue.\n");
+ error_exit:
+ fputs(
+"InnoDB: Please refer to\n"
+"InnoDB:"
+" http://dev.mysql.com/doc/mysql/en/InnoDB_troubleshooting_datadict.html\n"
+"InnoDB: how to resolve the issue.\n", stderr);
mem_free(path);
mutex_exit(&(system->mutex));
@@ -3101,26 +3178,23 @@ fil_space_for_table_exists_in_mem(
if (0 != strcmp(space->name, path)) {
ut_print_timestamp(stderr);
- fprintf(stderr,
-" InnoDB: Error: table %s\n"
+ fputs(" InnoDB: Error: table ", stderr);
+ ut_print_filename(stderr, name);
+ fprintf(stderr, "\n"
"InnoDB: in InnoDB data dictionary has tablespace id %lu,\n"
"InnoDB: but tablespace with that id has name %s.\n"
-"InnoDB: Have you deleted or moved .ibd files?\n", name, (ulong) id, space->name);
+"InnoDB: Have you deleted or moved .ibd files?\n", (ulong) id, space->name);
if (namespace != NULL) {
- fprintf(stderr,
+ fputs(
"InnoDB: There is a tablespace with the right name\n"
-"InnoDB: %s, but its id is %lu.\n", namespace->name, (ulong) namespace->id);
+"InnoDB: ", stderr);
+ ut_print_filename(stderr, namespace->name);
+ fprintf(stderr, ", but its id is %lu.\n",
+ (ulong) namespace->id);
}
- fprintf(stderr,
-"InnoDB: You can look from section 15.1 of http://www.innodb.com/ibman.html\n"
-"InnoDB: how to resolve the issue.\n");
-
- mem_free(path);
- mutex_exit(&(system->mutex));
-
- return(FALSE);
+ goto error_exit;
}
mem_free(path);
@@ -3150,7 +3224,7 @@ fil_get_space_id_for_table(
mutex_enter(&(system->mutex));
- path = fil_make_ibd_name(name);
+ path = fil_make_ibd_name(name, FALSE);
/* Look if there is a space with the same name; the name is the
directory path to the file */
diff --git a/innobase/fsp/fsp0fsp.c b/innobase/fsp/fsp0fsp.c
index 34b6de76ff4..e1621cc2765 100644
--- a/innobase/fsp/fsp0fsp.c
+++ b/innobase/fsp/fsp0fsp.c
@@ -2972,9 +2972,9 @@ fseg_free_page_low(
"InnoDB: database!\n", (ulong) page);
crash:
fputs(
-"InnoDB: If the InnoDB recovery crashes here, see section 6.1\n"
-"InnoDB: of http://www.innodb.com/ibman.php about forcing recovery.\n",
- stderr);
+"InnoDB: Please refer to\n"
+"InnoDB: http://dev.mysql.com/doc/mysql/en/Forcing_recovery.html\n"
+"InnoDB: about forcing recovery.\n", stderr);
ut_error;
}
diff --git a/innobase/ibuf/ibuf0ibuf.c b/innobase/ibuf/ibuf0ibuf.c
index f05e69863a3..b3c8ade2414 100644
--- a/innobase/ibuf/ibuf0ibuf.c
+++ b/innobase/ibuf/ibuf0ibuf.c
@@ -3268,8 +3268,9 @@ leave_loop:
mutex_exit(&ibuf_mutex);
- printf("Discarded %lu ibuf entries for space %lu\n", (ulong) n_inserts,
- (ulong) space);
+ fprintf(stderr,
+ "InnoDB: Discarded %lu ibuf entries for space %lu\n",
+ (ulong) n_inserts, (ulong) space);
ibuf_exit();
diff --git a/innobase/include/data0type.h b/innobase/include/data0type.h
index fe38a224a66..c263d2bf613 100644
--- a/innobase/include/data0type.h
+++ b/innobase/include/data0type.h
@@ -145,6 +145,29 @@ store the charset-collation number; one byte is left unused, though */
#define DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE 6
/*************************************************************************
+Checks if a string type has to be compared by the MySQL comparison functions.
+InnoDB internally only handles binary byte string comparisons, as well as
+latin1_swedish_ci strings. For example, UTF-8 strings have to be compared
+by MySQL. */
+
+ibool
+dtype_str_needs_mysql_cmp(
+/*======================*/
+ /* out: TRUE if a string type that requires
+ comparison with MySQL functions */
+ dtype_t* dtype); /* in: type struct */
+/*************************************************************************
+For the documentation of this function, see innobase_get_at_most_n_mbchars()
+in ha_innodb.cc. */
+
+ulint
+dtype_get_at_most_n_mbchars(
+/*========================*/
+ dtype_t* dtype,
+ ulint prefix_len,
+ ulint data_len,
+ const char* str);
+/*************************************************************************
Checks if a data main type is a string type. Also a BLOB is considered a
string type. */
diff --git a/innobase/include/dict0dict.h b/innobase/include/dict0dict.h
index ebb34f7dda0..ca632691450 100644
--- a/innobase/include/dict0dict.h
+++ b/innobase/include/dict0dict.h
@@ -356,6 +356,7 @@ dict_print_info_on_foreign_keys(
a CREATE TABLE, otherwise in the format
of SHOW TABLE STATUS */
FILE* file, /* in: file where to print */
+ trx_t* trx, /* in: transaction */
dict_table_t* table); /* in: table */
/**************************************************************************
Outputs info on a foreign key of a table in a format suitable for
@@ -364,6 +365,7 @@ void
dict_print_info_on_foreign_key_in_create_format(
/*============================================*/
FILE* file, /* in: file where to print */
+ trx_t* trx, /* in: transaction */
dict_foreign_t* foreign);/* in: foreign key constraint */
/************************************************************************
Displays the names of the index and the table. */
@@ -371,6 +373,7 @@ void
dict_index_name_print(
/*==================*/
FILE* file, /* in: output stream */
+ trx_t* trx, /* in: transaction */
const dict_index_t* index); /* in: index to print */
/************************************************************************
Gets the first index on the table (the clustered index). */
@@ -601,8 +604,10 @@ dict_index_contains_col_or_prefix(
dict_index_t* index, /* in: index */
ulint n); /* in: column number */
/************************************************************************
-Looks for a matching field in an index. The column and the prefix len has
-to be the same. */
+Looks for a matching field in an index. The column has to be the same. The
+column in index must be complete, or must contain a prefix longer than the
+column in index2. That is, we must be able to construct the prefix in index2
+from the prefix in index. */
ulint
dict_index_get_nth_field_pos(
@@ -886,6 +891,18 @@ dict_tables_have_same_db(
const char* name2); /* in: table name in the form
dbname '/' tablename */
+/*************************************************************************
+Scans from pointer onwards. Stops if is at the start of a copy of
+'string' where characters are compared without case sensitivity. Stops
+also at '\0'. */
+
+const char*
+dict_scan_to(
+/*=========*/
+ /* out: scanned up to this */
+ const char* ptr, /* in: scan from */
+ const char* string);/* in: look for this */
+
/* Buffers for storing detailed information about the latest foreign key
and unique key errors */
extern FILE* dict_foreign_err_file;
diff --git a/innobase/include/dict0mem.h b/innobase/include/dict0mem.h
index 3fc3e850987..1e496a25477 100644
--- a/innobase/include/dict0mem.h
+++ b/innobase/include/dict0mem.h
@@ -151,7 +151,12 @@ struct dict_col_struct{
in some of the functions below */
};
-#define DICT_MAX_COL_PREFIX_LEN 512
+/* DICT_MAX_COL_PREFIX_LEN is measured in bytes. Starting from 4.1.6, we
+set max col prefix len to < 3 * 256, so that one can create a column prefix
+index on 255 characters of a TEXT field also in the UTF-8 charset. In that
+charset, a character may take at most 3 bytes. */
+
+#define DICT_MAX_COL_PREFIX_LEN 768
/* Data structure for a field in an index */
struct dict_field_struct{
@@ -160,9 +165,12 @@ struct dict_field_struct{
ulint order; /* flags for ordering this field:
DICT_DESCEND, ... */
ulint prefix_len; /* 0 or the length of the column
- prefix in a MySQL index of type, e.g.,
- INDEX (textcol(25)); must be smaller
- than DICT_MAX_COL_PREFIX_LEN */
+ prefix in bytes in a MySQL index of
+ type, e.g., INDEX (textcol(25));
+ must be smaller than
+ DICT_MAX_COL_PREFIX_LEN; NOTE that
+ in the UTF-8 charset, MySQL sets this
+ to 3 * the prefix len in UTF-8 chars */
};
/* Data structure for an index tree */
@@ -297,6 +305,12 @@ struct dict_table_struct{
ulint type; /* DICT_TABLE_ORDINARY, ... */
mem_heap_t* heap; /* memory heap */
const char* name; /* table name */
+ const char* dir_path_of_temp_table;/* NULL or the directory path
+ where a TEMPORARY table that was explicitly
+ created by a user should be placed if
+ innodb_file_per_table is defined in my.cnf;
+ in Unix this is usually /tmp/..., in Windows
+ \temp\... */
ulint space; /* space where the clustered index of the
table is placed */
ibool ibd_file_missing;/* TRUE if this is in a single-table
diff --git a/innobase/include/fil0fil.h b/innobase/include/fil0fil.h
index 45549aee63c..5a5db77073a 100644
--- a/innobase/include/fil0fil.h
+++ b/innobase/include/fil0fil.h
@@ -339,11 +339,13 @@ fil_rename_tablespace(
const char* new_name); /* in: new table name in the standard
databasename/tablename format
of InnoDB */
+
/***********************************************************************
Creates a new single-table tablespace to a database directory of MySQL.
Database directories are under the 'datadir' of MySQL. The datadir is the
directory of a running mysqld program. We can refer to it by simply the
-path '.'. */
+path '.'. Tables created with CREATE TEMPORARY TABLE we place in the temp
+dir of the mysqld server. */
ulint
fil_create_new_single_table_tablespace(
@@ -354,7 +356,10 @@ fil_create_new_single_table_tablespace(
otherwise output */
const char* tablename, /* in: the table name in the usual
databasename/tablename format
- of InnoDB */
+ of InnoDB, or a dir path to a temp
+ table */
+ ibool is_temp, /* in: TRUE if a table created with
+ CREATE TEMPORARY TABLE */
ulint size); /* in: the initial size of the
tablespace file in pages,
must be >= FIL_IBD_FILE_INITIAL_SIZE */
@@ -446,7 +451,10 @@ fil_space_for_table_exists_in_mem(
exists in the memory cache */
ulint id, /* in: space id */
const char* name, /* in: table name in the standard
- 'databasename/tablename' format */
+ 'databasename/tablename' format or
+ the dir path to a temp table */
+ ibool is_temp, /* in: TRUE if created with CREATE
+ TEMPORARY TABLE */
ibool mark_space, /* in: in crash recovery, at database
startup we mark all spaces which have
an associated table in the InnoDB
diff --git a/innobase/include/mem0mem.h b/innobase/include/mem0mem.h
index cd01ac77bf3..87afdb8f91c 100644
--- a/innobase/include/mem0mem.h
+++ b/innobase/include/mem0mem.h
@@ -136,10 +136,8 @@ void
mem_heap_free_func(
/*===============*/
mem_heap_t* heap, /* in, own: heap to be freed */
- const char* file_name __attribute__((unused)),
- /* in: file name where freed */
- ulint line __attribute__((unused)));
- /* in: line where freed */
+ const char* file_name, /* in: file name where freed */
+ ulint line); /* in: line where freed */
/*******************************************************************
Allocates n bytes of memory from a memory heap. */
UNIV_INLINE
@@ -295,7 +293,7 @@ mem_strdupq(
/**************************************************************************
Duplicates a NUL-terminated string, allocated from a memory heap. */
-UNIV_INLINE
+
char*
mem_heap_strdup(
/*============*/
diff --git a/innobase/include/mem0mem.ic b/innobase/include/mem0mem.ic
index d97b7d6c4dd..714c30e3642 100644
--- a/innobase/include/mem0mem.ic
+++ b/innobase/include/mem0mem.ic
@@ -628,20 +628,6 @@ mem_strdupq(
}
/**************************************************************************
-Duplicates a NUL-terminated string, allocated from a memory heap. */
-UNIV_INLINE
-char*
-mem_heap_strdup(
-/*============*/
- /* out, own: a copy of the string */
- mem_heap_t* heap, /* in: memory heap where string is allocated */
- const char* str) /* in: string to be copied */
-{
- ulint len = strlen(str) + 1;
- return(memcpy(mem_heap_alloc(heap, len), str, len));
-}
-
-/**************************************************************************
Makes a NUL-terminated copy of a nonterminated string,
allocated from a memory heap. */
UNIV_INLINE
diff --git a/innobase/include/os0file.h b/innobase/include/os0file.h
index f1647c47bce..d1439faf29f 100644
--- a/innobase/include/os0file.h
+++ b/innobase/include/os0file.h
@@ -14,6 +14,7 @@ Created 10/21/1995 Heikki Tuuri
#ifndef __WIN__
#include <dirent.h>
#include <sys/stat.h>
+#include <time.h>
#endif
extern ibool os_do_not_call_flush_at_each_write;
@@ -142,12 +143,15 @@ bigger than 4000 bytes */
#define OS_FILE_MAX_PATH 4000
/* Struct used in fetching information of a file in a directory */
-typedef struct os_file_stat_struct os_file_stat_t;
struct os_file_stat_struct{
- char name[OS_FILE_MAX_PATH]; /* path to a file */
- os_file_type_t type; /* file type */
- ib_longlong size; /* file size */
+ char name[OS_FILE_MAX_PATH]; /* path to a file */
+ os_file_type_t type; /* file type */
+ ib_longlong size; /* file size */
+ time_t ctime; /* creation time */
+ time_t mtime; /* modification time */
+ time_t atime; /* access time */
};
+typedef struct os_file_stat_struct os_file_stat_t;
#ifdef __WIN__
typedef HANDLE os_file_dir_t; /* directory stream */
@@ -686,5 +690,14 @@ no pending io operations. */
ibool
os_aio_all_slots_free(void);
/*=======================*/
- /* out: TRUE if all free */
+
+/***********************************************************************
+This function returns information about the specified file */
+ibool
+os_file_get_status(
+/*===============*/
+ /* out: TRUE if stat information found */
+ const char* path, /* in: pathname of the file */
+ os_file_stat_t* stat_info); /* information of a file in a directory */
+
#endif
diff --git a/innobase/include/row0mysql.h b/innobase/include/row0mysql.h
index a576a637c79..6e1865dae1d 100644
--- a/innobase/include/row0mysql.h
+++ b/innobase/include/row0mysql.h
@@ -559,9 +559,11 @@ struct row_prebuilt_struct {
dtuple_t* clust_ref; /* prebuilt dtuple used in
sel/upd/del */
ulint select_lock_type;/* LOCK_NONE, LOCK_S, or LOCK_X */
- ulint stored_select_lock_type;/* inside LOCK TABLES, either
- LOCK_S or LOCK_X depending on the lock
- type */
+ ulint stored_select_lock_type;/* this field is used to
+ remember the original select_lock_type
+ that was decided in ha_innodb.cc,
+ ::store_lock(), ::external_lock(),
+ etc. */
ulint mysql_row_len; /* length in bytes of a row in the
MySQL format */
ulint n_rows_fetched; /* number of rows fetched after
diff --git a/innobase/include/row0row.h b/innobase/include/row0row.h
index 3956f3c1692..951e211fb37 100644
--- a/innobase/include/row0row.h
+++ b/innobase/include/row0row.h
@@ -147,12 +147,13 @@ row_build_row_ref_in_tuple(
dtuple_t* ref, /* in/out: row reference built; see the
NOTE below! */
dict_index_t* index, /* in: index */
- rec_t* rec); /* in: record in the index;
+ rec_t* rec, /* in: record in the index;
NOTE: the data fields in ref will point
directly into this record, therefore,
the buffer page of this record must be
at least s-latched and the latch held
as long as the row reference is used! */
+ trx_t* trx); /* in: transaction */
/***********************************************************************
From a row build a row reference with which we can search the clustered
index record. */
diff --git a/innobase/include/row0sel.h b/innobase/include/row0sel.h
index 0be224eb255..bb6fb70ca86 100644
--- a/innobase/include/row0sel.h
+++ b/innobase/include/row0sel.h
@@ -105,7 +105,8 @@ row_sel_convert_mysql_key_to_innobase(
ulint buf_len, /* in: buffer length */
dict_index_t* index, /* in: index of the key value */
byte* key_ptr, /* in: MySQL key value */
- ulint key_len); /* in: MySQL key value length */
+ ulint key_len, /* in: MySQL key value length */
+ trx_t* trx); /* in: transaction */
/************************************************************************
Searches for rows in the database. This is used in the interface to
MySQL. This function opens a cursor, and also implements fetch next
diff --git a/innobase/include/row0upd.h b/innobase/include/row0upd.h
index f5e0a88231f..28210364833 100644
--- a/innobase/include/row0upd.h
+++ b/innobase/include/row0upd.h
@@ -55,7 +55,8 @@ upd_field_set_field_no(
upd_field_t* upd_field, /* in: update vector field */
ulint field_no, /* in: field number in a clustered
index */
- dict_index_t* index); /* in: index */
+ dict_index_t* index, /* in: index */
+ trx_t* trx); /* in: transaction */
/*************************************************************************
Writes into the redo log the values of trx id and roll ptr and enough info
to determine their positions within a clustered index record. */
@@ -149,6 +150,7 @@ row_upd_build_sec_rec_difference_binary(
dict_index_t* index, /* in: index */
dtuple_t* entry, /* in: entry to insert */
rec_t* rec, /* in: secondary index record */
+ trx_t* trx, /* in: transaction */
mem_heap_t* heap); /* in: memory heap from which allocated */
/*******************************************************************
Builds an update vector from those fields, excluding the roll ptr and
@@ -166,6 +168,7 @@ row_upd_build_difference_binary(
externally stored fields in entry, or NULL */
ulint n_ext_vec,/* in: number of fields in ext_vec */
rec_t* rec, /* in: clustered index record */
+ trx_t* trx, /* in: transaction */
mem_heap_t* heap); /* in: memory heap from which allocated */
/***************************************************************
Replaces the new column values stored in the update vector to the index entry
diff --git a/innobase/include/row0upd.ic b/innobase/include/row0upd.ic
index d89938d696a..a124228a0de 100644
--- a/innobase/include/row0upd.ic
+++ b/innobase/include/row0upd.ic
@@ -78,7 +78,8 @@ upd_field_set_field_no(
upd_field_t* upd_field, /* in: update vector field */
ulint field_no, /* in: field number in a clustered
index */
- dict_index_t* index) /* in: index */
+ dict_index_t* index, /* in: index */
+ trx_t* trx) /* in: transaction */
{
upd_field->field_no = field_no;
@@ -86,7 +87,7 @@ upd_field_set_field_no(
fprintf(stderr,
"InnoDB: Error: trying to access field %lu in ",
(ulong) field_no);
- dict_index_name_print(stderr, index);
+ dict_index_name_print(stderr, trx, index);
fprintf(stderr, "\n"
"InnoDB: but index only has %lu fields\n",
(ulong) dict_index_get_n_fields(index));
diff --git a/innobase/include/srv0srv.h b/innobase/include/srv0srv.h
index 2e42c2f5036..6cfe9cef927 100644
--- a/innobase/include/srv0srv.h
+++ b/innobase/include/srv0srv.h
@@ -24,7 +24,8 @@ extern os_event_t srv_lock_timeout_thread_event;
/* If the last data file is auto-extended, we add this many pages to it
at a time */
-#define SRV_AUTO_EXTEND_INCREMENT (8 * ((1024 * 1024) / UNIV_PAGE_SIZE))
+#define SRV_AUTO_EXTEND_INCREMENT \
+ (srv_auto_extend_increment * ((1024 * 1024) / UNIV_PAGE_SIZE))
/* This is set to TRUE if the MySQL user has set it in MySQL */
extern ibool srv_lower_case_table_names;
@@ -51,6 +52,7 @@ extern ulint* srv_data_file_is_raw_partition;
extern ibool srv_auto_extend_last_data_file;
extern ulint srv_last_file_size_max;
+extern ulint srv_auto_extend_increment;
extern ibool srv_created_new_raw;
@@ -98,7 +100,10 @@ extern ulint srv_max_n_threads;
extern lint srv_conc_n_threads;
extern ibool srv_fast_shutdown;
-
+extern ibool srv_very_fast_shutdown; /* if this TRUE, do not flush the
+ buffer pool to data files at the
+ shutdown; we effectively 'crash'
+ InnoDB */
extern ibool srv_innodb_status;
extern ibool srv_use_doublewrite_buf;
@@ -106,8 +111,11 @@ extern ibool srv_use_doublewrite_buf;
extern ibool srv_set_thread_priorities;
extern int srv_query_thread_priority;
+extern ulint srv_max_purge_lag;
extern ibool srv_use_awe;
extern ibool srv_use_adaptive_hash_indexes;
+
+extern ulint srv_max_purge_lag;
/*-------------------------------------------*/
extern ulint srv_n_rows_inserted;
@@ -161,6 +169,7 @@ extern ulint srv_test_array_size;
extern ulint srv_activity_count;
extern ulint srv_fatal_semaphore_wait_threshold;
+extern ulint srv_dml_needed_delay;
extern mutex_t* kernel_mutex_temp;/* mutex protecting the server, trx structs,
query threads, and lock table: we allocate
diff --git a/innobase/include/sync0arr.h b/innobase/include/sync0arr.h
index 92691d5fdd9..fecd910683e 100644
--- a/innobase/include/sync0arr.h
+++ b/innobase/include/sync0arr.h
@@ -97,9 +97,11 @@ sync_arr_wake_threads_if_sema_free(void);
/**************************************************************************
Prints warnings of long semaphore waits to stderr. */
-void
+ibool
sync_array_print_long_waits(void);
/*=============================*/
+ /* out: TRUE if fatal semaphore wait threshold
+ was exceeded */
/************************************************************************
Validates the integrity of the wait array. Checks
that the number of reserved cells equals the count variable. */
diff --git a/innobase/include/trx0rec.h b/innobase/include/trx0rec.h
index 50d942d9040..9d7f41cd94e 100644
--- a/innobase/include/trx0rec.h
+++ b/innobase/include/trx0rec.h
@@ -145,6 +145,7 @@ trx_undo_update_rec_get_update(
dulint trx_id, /* in: transaction id from this undorecord */
dulint roll_ptr,/* in: roll pointer from this undo record */
ulint info_bits,/* in: info bits from this undo record */
+ trx_t* trx, /* in: transaction */
mem_heap_t* heap, /* in: memory heap from which the memory
needed is allocated */
upd_t** upd); /* out, own: update vector */
diff --git a/innobase/include/trx0sys.h b/innobase/include/trx0sys.h
index 8f402881224..31e8607f8a0 100644
--- a/innobase/include/trx0sys.h
+++ b/innobase/include/trx0sys.h
@@ -432,6 +432,10 @@ struct trx_sys_struct{
trx_rseg_t* rseg_array[TRX_SYS_N_RSEGS];
/* Pointer array to rollback segments;
NULL if slot not in use */
+ ulint rseg_history_len;/* Length of the TRX_RSEG_HISTORY
+ list (update undo logs for committed
+ transactions), protected by
+ rseg->mutex */
UT_LIST_BASE_NODE_T(read_view_t) view_list;
/* List of read views sorted on trx no,
biggest first */
diff --git a/innobase/include/ut0byte.h b/innobase/include/ut0byte.h
index fed6a23d144..a62c2e2e318 100644
--- a/innobase/include/ut0byte.h
+++ b/innobase/include/ut0byte.h
@@ -229,25 +229,6 @@ ut_bit_set_nth(
ulint a, /* in: ulint */
ulint n, /* in: nth bit requested */
ibool val); /* in: value for the bit to set */
-/****************************************************************
-Copies a string to a memory location, setting characters to lower case. */
-
-void
-ut_cpy_in_lower_case(
-/*=================*/
- char* dest, /* in: destination */
- const char* source, /* in: source */
- ulint len); /* in: string length */
-/****************************************************************
-Compares two strings when converted to lower case. */
-
-int
-ut_cmp_in_lower_case(
-/*=================*/
- /* out: -1, 0, 1 if str1 < str2, str1 == str2,
- str1 > str2, respectively */
- const char* str1, /* in: string1 */
- const char* str2); /* in: string2 */
#ifndef UNIV_NONINL
#include "ut0byte.ic"
diff --git a/innobase/include/ut0mem.h b/innobase/include/ut0mem.h
index 2e02b3f0b6b..73ecb25101a 100644
--- a/innobase/include/ut0mem.h
+++ b/innobase/include/ut0mem.h
@@ -117,7 +117,7 @@ int
ut_strcmp(const void* str1, const void* str2);
/**************************************************************************
-Determine the length of a string when it is quoted with ut_strcpyq(). */
+Compute strlen(ut_strcpyq(str, q)). */
UNIV_INLINE
ulint
ut_strlenq(
@@ -127,7 +127,9 @@ ut_strlenq(
char q); /* in: the quote character */
/**************************************************************************
-Make a quoted copy of a string. */
+Make a quoted copy of a NUL-terminated string. Leading and trailing
+quotes will not be included; only embedded quotes will be escaped.
+See also ut_strlenq() and ut_memcpyq(). */
char*
ut_strcpyq(
@@ -138,7 +140,9 @@ ut_strcpyq(
const char* src); /* in: null-terminated string */
/**************************************************************************
-Make a quoted copy of a fixed-length string. */
+Make a quoted copy of a fixed-length string. Leading and trailing
+quotes will not be included; only embedded quotes will be escaped.
+See also ut_strlenq() and ut_strcpyq(). */
char*
ut_memcpyq(
diff --git a/innobase/include/ut0mem.ic b/innobase/include/ut0mem.ic
index 3bb30a80f22..76c721112a0 100644
--- a/innobase/include/ut0mem.ic
+++ b/innobase/include/ut0mem.ic
@@ -49,7 +49,7 @@ ut_strcmp(const void* str1, const void* str2)
}
/**************************************************************************
-Determine the length of a string when it is quoted with ut_strcpyq(). */
+Compute strlen(ut_strcpyq(str, q)). */
UNIV_INLINE
ulint
ut_strlenq(
diff --git a/innobase/include/ut0ut.h b/innobase/include/ut0ut.h
index f4a682c57ec..dee8785c9e7 100644
--- a/innobase/include/ut0ut.h
+++ b/innobase/include/ut0ut.h
@@ -198,12 +198,24 @@ ut_print_buf(
ulint len); /* in: length of the buffer */
/**************************************************************************
+Outputs a NUL-terminated file name, quoted with apostrophes. */
+
+void
+ut_print_filename(
+/*==============*/
+ FILE* f, /* in: output stream */
+ const char* name); /* in: name to print */
+
+/**************************************************************************
Outputs a NUL-terminated string, quoted as an SQL identifier. */
+struct trx_struct;
+
void
ut_print_name(
/*==========*/
FILE* f, /* in: output stream */
+ struct trx_struct*trx, /* in: transaction */
const char* name); /* in: name to print */
/**************************************************************************
@@ -213,6 +225,7 @@ void
ut_print_namel(
/*==========*/
FILE* f, /* in: output stream */
+ struct trx_struct*trx, /* in: transaction (NULL=no quotes) */
const char* name, /* in: name to print */
ulint namelen);/* in: length of name */
diff --git a/innobase/lock/lock0lock.c b/innobase/lock/lock0lock.c
index c9c0cd109a9..68073647248 100644
--- a/innobase/lock/lock0lock.c
+++ b/innobase/lock/lock0lock.c
@@ -365,6 +365,37 @@ lock_deadlock_recursive(
ulint* cost); /* in/out: number of calculation steps thus
far: if this exceeds LOCK_MAX_N_STEPS_...
we return TRUE */
+/*************************************************************************
+Gets the nth bit of a record lock. */
+UNIV_INLINE
+ibool
+lock_rec_get_nth_bit(
+/*=================*/
+ /* out: TRUE if bit set */
+ lock_t* lock, /* in: record lock */
+ ulint i) /* in: index of the bit */
+{
+ ulint byte_index;
+ ulint bit_index;
+ ulint b;
+
+ ut_ad(lock);
+ ut_ad(lock_get_type(lock) == LOCK_REC);
+
+ if (i >= lock->un_member.rec_lock.n_bits) {
+
+ return(FALSE);
+ }
+
+ byte_index = i / 8;
+ bit_index = i % 8;
+
+ b = (ulint)*((byte*)lock + sizeof(lock_t) + byte_index);
+
+ return(ut_bit_get_nth(b, bit_index));
+}
+
+/*************************************************************************/
#define lock_mutex_enter_kernel() mutex_enter(&kernel_mutex)
#define lock_mutex_exit_kernel() mutex_exit(&kernel_mutex)
@@ -398,7 +429,7 @@ lock_check_trx_id_sanity(
stderr);
rec_print(stderr, rec);
fputs("InnoDB: in ", stderr);
- dict_index_name_print(stderr, index);
+ dict_index_name_print(stderr, NULL, index);
fprintf(stderr, "\n"
"InnoDB: is %lu %lu which is higher than the global trx id counter %lu %lu!\n"
"InnoDB: The table is corrupt. You have to do dump + drop + reimport.\n",
@@ -756,9 +787,13 @@ lock_rec_has_to_wait(
ulint type_mode,/* in: precise mode of the new lock to set:
LOCK_S or LOCK_X, possibly ORed to
LOCK_GAP or LOCK_REC_NOT_GAP, LOCK_INSERT_INTENTION */
- lock_t* lock2) /* in: another record lock; NOTE that it is assumed
+ lock_t* lock2, /* in: another record lock; NOTE that it is assumed
that this has a lock bit set on the same record as
in the new lock we are setting */
+ ibool lock_is_on_supremum) /* in: TRUE if we are setting the lock
+ on the 'supremum' record of an index
+ page: we know then that the lock request
+ is really for a 'gap' type lock */
{
ut_ad(trx && lock2);
ut_ad(lock_get_type(lock2) == LOCK_REC);
@@ -770,10 +805,22 @@ lock_rec_has_to_wait(
/* We have somewhat complex rules when gap type record locks
cause waits */
- if ((type_mode & LOCK_REC_NOT_GAP)
+ if ((lock_is_on_supremum || (type_mode & LOCK_GAP))
+ && !(type_mode & LOCK_INSERT_INTENTION)) {
+
+ /* Gap type locks without LOCK_INSERT_INTENTION flag
+ do not need to wait for anything. This is because
+ different users can have conflicting lock types
+ on gaps. */
+
+ return(FALSE);
+ }
+
+ if (!(type_mode & LOCK_INSERT_INTENTION)
&& lock_rec_get_gap(lock2)) {
- /* Lock on just the record does not need to wait for
- a gap type lock */
+
+ /* Record lock (LOCK_ORDINARY or LOCK_REC_NOT_GAP
+ does not need to wait for a gap type lock */
return(FALSE);
}
@@ -829,9 +876,13 @@ lock_has_to_wait(
lock_get_mode(lock2))) {
if (lock_get_type(lock1) == LOCK_REC) {
ut_ad(lock_get_type(lock2) == LOCK_REC);
-
+
+ /* If this lock request is for a supremum record
+ then the second bit on the lock bitmap is set */
+
return(lock_rec_has_to_wait(lock1->trx,
- lock1->type_mode, lock2));
+ lock1->type_mode, lock2,
+ lock_rec_get_nth_bit(lock1,1)));
}
return(TRUE);
@@ -854,36 +905,6 @@ lock_rec_get_n_bits(
return(lock->un_member.rec_lock.n_bits);
}
-/*************************************************************************
-Gets the nth bit of a record lock. */
-UNIV_INLINE
-ibool
-lock_rec_get_nth_bit(
-/*=================*/
- /* out: TRUE if bit set */
- lock_t* lock, /* in: record lock */
- ulint i) /* in: index of the bit */
-{
- ulint byte_index;
- ulint bit_index;
- ulint b;
-
- ut_ad(lock);
- ut_ad(lock_get_type(lock) == LOCK_REC);
-
- if (i >= lock->un_member.rec_lock.n_bits) {
-
- return(FALSE);
- }
-
- byte_index = i / 8;
- bit_index = i % 8;
-
- b = (ulint)*((byte*)lock + sizeof(lock_t) + byte_index);
-
- return(ut_bit_get_nth(b, bit_index));
-}
-
/**************************************************************************
Sets the nth bit of a record lock to TRUE. */
UNIV_INLINE
@@ -1420,7 +1441,8 @@ lock_rec_other_has_conflicting(
lock = lock_rec_get_first(rec);
while (lock) {
- if (lock_rec_has_to_wait(trx, mode, lock)) {
+ if (lock_rec_has_to_wait(trx, mode, lock,
+ page_rec_is_supremum(rec))) {
return(lock);
}
@@ -1651,7 +1673,7 @@ lock_rec_enqueue_waiting(
fputs(
" InnoDB: Error: a record lock wait happens in a dictionary operation!\n"
"InnoDB: Table name ", stderr);
- ut_print_name(stderr, index->table_name);
+ ut_print_name(stderr, trx, index->table_name);
fputs(".\n"
"InnoDB: Submit a detailed bug report to http://bugs.mysql.com\n",
stderr);
@@ -1688,7 +1710,7 @@ lock_rec_enqueue_waiting(
if (lock_print_waits) {
fprintf(stderr, "Lock wait for trx %lu in index ",
(ulong) ut_dulint_get_low(trx->id));
- ut_print_name(stderr, index->name);
+ ut_print_name(stderr, trx, index->name);
}
return(DB_LOCK_WAIT);
@@ -3293,7 +3315,7 @@ lock_table_enqueue_waiting(
fputs(
" InnoDB: Error: a table lock wait happens in a dictionary operation!\n"
"InnoDB: Table name ", stderr);
- ut_print_name(stderr, table->name);
+ ut_print_name(stderr, trx, table->name);
fputs(".\n"
"InnoDB: Submit a detailed bug report to http://bugs.mysql.com\n",
stderr);
@@ -3820,7 +3842,7 @@ lock_table_print(
fputs("EXPLICIT ", file);
}
fputs("TABLE LOCK table ", file);
- ut_print_name(file, lock->un_member.tab_lock.table->name);
+ ut_print_name(file, lock->trx, lock->un_member.tab_lock.table->name);
fprintf(file, " trx id %lu %lu",
(ulong) (lock->trx)->id.high, (ulong) (lock->trx)->id.low);
@@ -3871,7 +3893,7 @@ lock_rec_print(
fprintf(file, "RECORD LOCKS space id %lu page no %lu n bits %lu ",
(ulong) space, (ulong) page_no,
(ulong) lock_rec_get_n_bits(lock));
- dict_index_name_print(file, lock->index);
+ dict_index_name_print(file, lock->trx, lock->index);
fprintf(file, " trx id %lu %lu",
(ulong) (lock->trx)->id.high,
(ulong) (lock->trx)->id.low);
diff --git a/innobase/log/log0log.c b/innobase/log/log0log.c
index 923ab448e07..e08adb013b5 100644
--- a/innobase/log/log0log.c
+++ b/innobase/log/log0log.c
@@ -689,10 +689,9 @@ failure:
"InnoDB: To get mysqld to start up, set innodb_thread_concurrency in my.cnf\n"
"InnoDB: to a lower value, for example, to 8. After an ERROR-FREE shutdown\n"
"InnoDB: of mysqld you can adjust the size of ib_logfiles, as explained in\n"
-"InnoDB: section 5 of http://www.innodb.com/ibman.php",
+"InnoDB: http://dev.mysql.com/doc/mysql/en/Adding_and_removing.html\n"
+"InnoDB: Cannot continue operation. Calling exit(1).\n",
(ulong)srv_thread_concurrency);
- fprintf(stderr,
-"InnoDB: Cannot continue operation. Calling exit(1).\n");
exit(1);
}
@@ -3049,13 +3048,25 @@ loop:
#ifdef UNIV_LOG_ARCHIVE
log_archive_all();
#endif /* UNIV_LOG_ARCHIVE */
- log_make_checkpoint_at(ut_dulint_max, TRUE);
+
+ if (!srv_very_fast_shutdown) {
+ /* In a 'very fast' shutdown we do not flush the buffer pool:
+ it is essentially a 'crash' of the InnoDB server. */
+
+ log_make_checkpoint_at(ut_dulint_max, TRUE);
+ } else {
+ /* Make sure that the log is all flushed to disk, so that
+ we can recover all committed transactions in a crash
+ recovery */
+ log_buffer_flush_to_disk();
+ }
mutex_enter(&(log_sys->mutex));
lsn = log_sys->lsn;
- if (ut_dulint_cmp(lsn, log_sys->last_checkpoint_lsn) != 0
+ if ((ut_dulint_cmp(lsn, log_sys->last_checkpoint_lsn) != 0
+ && !srv_very_fast_shutdown)
#ifdef UNIV_LOG_ARCHIVE
|| (srv_log_archive_on
&& ut_dulint_cmp(lsn,
@@ -3099,11 +3110,12 @@ loop:
fil_flush_file_spaces(FIL_TABLESPACE);
fil_flush_file_spaces(FIL_LOG);
- /* The next fil_write_... will pass the buffer pool: therefore
- it is essential that the buffer pool has been completely flushed
- to disk! */
+ /* The call fil_write_flushed_lsn_to_data_files() will pass the buffer
+ pool: therefore it is essential that the buffer pool has been
+ completely flushed to disk! (We do not call fil_write... if the
+ 'very fast' shutdown is enabled.) */
- if (!buf_all_freed()) {
+ if (!srv_very_fast_shutdown && !buf_all_freed()) {
goto loop;
}
@@ -3126,7 +3138,7 @@ loop:
/* Make some checks that the server really is quiet */
ut_a(srv_n_threads_active[SRV_MASTER] == 0);
- ut_a(buf_all_freed());
+ ut_a(srv_very_fast_shutdown || buf_all_freed());
ut_a(0 == ut_dulint_cmp(lsn, log_sys->lsn));
if (ut_dulint_cmp(lsn, srv_start_lsn) < 0) {
@@ -3141,7 +3153,15 @@ loop:
srv_shutdown_lsn = lsn;
- fil_write_flushed_lsn_to_data_files(lsn, arch_log_no);
+ if (!srv_very_fast_shutdown) {
+ /* In a 'very fast' shutdown we do not flush the buffer pool:
+ it is essentially a 'crash' of the InnoDB server. Then we must
+ not write the lsn stamps to the data files, since at a
+ startup InnoDB deduces from the stamps if the previous
+ shutdown was clean. */
+
+ fil_write_flushed_lsn_to_data_files(lsn, arch_log_no);
+ }
fil_flush_file_spaces(FIL_TABLESPACE);
@@ -3149,7 +3169,7 @@ loop:
/* Make some checks that the server really is quiet */
ut_a(srv_n_threads_active[SRV_MASTER] == 0);
- ut_a(buf_all_freed());
+ ut_a(srv_very_fast_shutdown || buf_all_freed());
ut_a(0 == ut_dulint_cmp(lsn, log_sys->lsn));
}
diff --git a/innobase/log/log0recv.c b/innobase/log/log0recv.c
index e5b0300239a..10f921bb1f0 100644
--- a/innobase/log/log0recv.c
+++ b/innobase/log/log0recv.c
@@ -538,8 +538,8 @@ recv_find_max_checkpoint(
"InnoDB: If this error appears when you are creating an InnoDB database,\n"
"InnoDB: the problem may be that during an earlier attempt you managed\n"
"InnoDB: to create the InnoDB data files, but log file creation failed.\n"
-"InnoDB: If that is the case, please refer to section 3.1 of\n"
-"InnoDB: http://www.innodb.com/ibman.php\n");
+"InnoDB: If that is the case, please refer to\n"
+"InnoDB: http://dev.mysql.com/doc/mysql/en/Error_creating_InnoDB.html\n");
return(DB_ERROR);
}
@@ -1884,7 +1884,7 @@ recv_report_corrupt_log(
"InnoDB: far enough in recovery! Please run CHECK TABLE\n"
"InnoDB: on your InnoDB tables to check that they are ok!\n"
"InnoDB: If mysqld crashes after this recovery, look at\n"
- "InnoDB: section 6.1 of http://www.innodb.com/ibman.php\n"
+ "InnoDB: http://dev.mysql.com/doc/mysql/en/Forcing_recovery.html\n"
"InnoDB: about forcing recovery.\n", stderr);
fflush(stderr);
diff --git a/innobase/mem/mem0mem.c b/innobase/mem/mem0mem.c
index c090b25a632..85f0119d02a 100644
--- a/innobase/mem/mem0mem.c
+++ b/innobase/mem/mem0mem.c
@@ -102,6 +102,20 @@ mem_alloc_func_noninline(
return(mem_alloc_func(n, file_name, line));
}
+/**************************************************************************
+Duplicates a NUL-terminated string, allocated from a memory heap. */
+
+char*
+mem_heap_strdup(
+/*============*/
+ /* out, own: a copy of the string */
+ mem_heap_t* heap, /* in: memory heap where string is allocated */
+ const char* str) /* in: string to be copied */
+{
+ ulint len = strlen(str) + 1;
+ return(memcpy(mem_heap_alloc(heap, len), str, len));
+}
+
/*******************************************************************
Creates a memory heap block where data can be allocated. */
diff --git a/innobase/os/os0file.c b/innobase/os/os0file.c
index 392580eb570..5c140e4b798 100644
--- a/innobase/os/os0file.c
+++ b/innobase/os/os0file.c
@@ -234,8 +234,9 @@ os_file_get_last_error(
"InnoDB: of the same name as a data file.\n");
} else {
fprintf(stderr,
- "InnoDB: See section 13.2 at http://www.innodb.com/ibman.php\n"
- "InnoDB: about operating system error numbers.\n");
+ "InnoDB: Some operating system error numbers are described at\n"
+ "InnoDB: "
+ "http://dev.mysql.com/doc/mysql/en/Operating_System_error_codes.html\n");
}
}
@@ -280,8 +281,9 @@ os_file_get_last_error(
}
fprintf(stderr,
- "InnoDB: See also section 13.2 at http://www.innodb.com/ibman.php\n"
- "InnoDB: about operating system error numbers.\n");
+ "InnoDB: Some operating system error numbers are described at\n"
+ "InnoDB: "
+ "http://dev.mysql.com/doc/mysql/en/Operating_System_error_codes.html\n");
}
}
@@ -408,14 +410,11 @@ os_file_handle_error_no_exit(
/*=========================*/
/* out: TRUE if we should retry the
operation */
- os_file_t file, /* in: file pointer */
const char* name, /* in: name of a file or NULL */
const char* operation)/* in: operation */
{
ulint err;
- UT_NOT_USED(file);
-
err = os_file_get_last_error(FALSE);
if (err == OS_FILE_DISK_FULL) {
@@ -622,7 +621,7 @@ os_file_closedir(
ret = FindClose(dir);
if (!ret) {
- os_file_handle_error_no_exit(NULL, NULL, "closedir");
+ os_file_handle_error_no_exit(NULL, "closedir");
return(-1);
}
@@ -634,7 +633,7 @@ os_file_closedir(
ret = closedir(dir);
if (ret) {
- os_file_handle_error_no_exit(0, NULL, "closedir");
+ os_file_handle_error_no_exit(NULL, "closedir");
}
return(ret);
@@ -703,7 +702,7 @@ http://www.mysql.com/doc/en/Windows_symbolic_links.html */
return(1);
} else {
- os_file_handle_error_no_exit(NULL, dirname,
+ os_file_handle_error_no_exit(dirname,
"readdir_next_file");
return(-1);
}
@@ -735,7 +734,7 @@ next_file:
ret = stat(full_path, &statinfo);
if (ret) {
- os_file_handle_error_no_exit(0, full_path, "stat");
+ os_file_handle_error_no_exit(full_path, "stat");
ut_free(full_path);
@@ -1324,7 +1323,7 @@ loop:
ret = unlink((const char*)name);
if (ret != 0 && errno != ENOENT) {
- os_file_handle_error(name, "delete");
+ os_file_handle_error_no_exit(name, "delete");
return(FALSE);
}
@@ -1386,7 +1385,7 @@ loop:
ret = unlink((const char*)name);
if (ret != 0) {
- os_file_handle_error(name, "delete");
+ os_file_handle_error_no_exit(name, "delete");
return(FALSE);
}
@@ -1805,7 +1804,7 @@ os_file_pread(
os_file_n_pending_preads++;
os_mutex_exit(os_file_count_mutex);
- n_bytes = pread(file, buf, n, offs);
+ n_bytes = pread(file, buf, (ssize_t)n, offs);
os_mutex_enter(os_file_count_mutex);
os_file_n_pending_preads--;
@@ -1830,7 +1829,7 @@ os_file_pread(
return(ret);
}
- ret = read(file, buf, n);
+ ret = read(file, buf, (ssize_t)n);
os_mutex_exit(os_file_seek_mutexes[i]);
@@ -1880,7 +1879,7 @@ os_file_pwrite(
os_file_n_pending_pwrites++;
os_mutex_exit(os_file_count_mutex);
- ret = pwrite(file, buf, n, offs);
+ ret = pwrite(file, buf, (ssize_t)n, offs);
os_mutex_enter(os_file_count_mutex);
os_file_n_pending_pwrites--;
@@ -1915,7 +1914,7 @@ os_file_pwrite(
return(ret);
}
- ret = write(file, buf, n);
+ ret = write(file, buf, (ssize_t)n);
if (srv_unix_file_flush_method != SRV_UNIX_LITTLESYNC
&& srv_unix_file_flush_method != SRV_UNIX_NOSYNC
@@ -2008,6 +2007,11 @@ try_again:
return(TRUE);
}
+
+ fprintf(stderr,
+"InnoDB: Error: tried to read %lu bytes at offset %lu %lu.\n"
+"InnoDB: Was only able to read %ld.\n", (ulong)n, (ulong)offset_high,
+ (ulong)offset, (long)ret);
#endif
#ifdef __WIN__
error_handling:
@@ -2110,7 +2114,7 @@ try_again:
#ifdef __WIN__
error_handling:
#endif
- retry = os_file_handle_error_no_exit(file, NULL, "read");
+ retry = os_file_handle_error_no_exit(NULL, "read");
if (retry) {
goto try_again;
@@ -2174,8 +2178,9 @@ retry:
fprintf(stderr,
" InnoDB: Error: File pointer positioning to file %s failed at\n"
"InnoDB: offset %lu %lu. Operating system error number %lu.\n"
-"InnoDB: Look from section 13.2 at http://www.innodb.com/ibman.php\n"
-"InnoDB: what the error number means.\n",
+"InnoDB: Some operating system error numbers are described at\n"
+"InnoDB: "
+"http://dev.mysql.com/doc/mysql/en/Operating_System_error_codes.html\n",
name, (ulong) offset_high, (ulong) offset,
(ulong) GetLastError());
@@ -2232,8 +2237,9 @@ retry:
}
fprintf(stderr,
-"InnoDB: See also section 13.2 at http://www.innodb.com/ibman.php\n"
-"InnoDB: about operating system error numbers.\n");
+"InnoDB: Some operating system error numbers are described at\n"
+"InnoDB: "
+"http://dev.mysql.com/doc/mysql/en/Operating_System_error_codes.html\n");
os_has_said_disk_full = TRUE;
}
@@ -2267,8 +2273,9 @@ retry:
}
fprintf(stderr,
-"InnoDB: See also section 13.2 at http://www.innodb.com/ibman.php\n"
-"InnoDB: about operating system error numbers.\n");
+"InnoDB: Some operating system error numbers are described at\n"
+"InnoDB: "
+"http://dev.mysql.com/doc/mysql/en/Operating_System_error_codes.html\n");
os_has_said_disk_full = TRUE;
}
@@ -2300,7 +2307,7 @@ os_file_status(
} else if (ret) {
/* file exists, but stat call failed */
- os_file_handle_error_no_exit(0, path, "stat");
+ os_file_handle_error_no_exit(path, "stat");
return(FALSE);
}
@@ -2328,7 +2335,7 @@ os_file_status(
} else if (ret) {
/* file exists, but stat call failed */
- os_file_handle_error_no_exit(0, path, "stat");
+ os_file_handle_error_no_exit(path, "stat");
return(FALSE);
}
@@ -2349,6 +2356,83 @@ os_file_status(
#endif
}
+/***********************************************************************
+This function returns information about the specified file */
+
+ibool
+os_file_get_status(
+/*===========*/
+ /* out: TRUE if stat information found */
+ const char* path, /* in: pathname of the file */
+ os_file_stat_t* stat_info) /* information of a file in a directory */
+{
+#ifdef __WIN__
+ int ret;
+ struct _stat statinfo;
+
+ ret = _stat(path, &statinfo);
+ if (ret && (errno == ENOENT || errno == ENOTDIR)) {
+ /* file does not exist */
+
+ return(FALSE);
+ } else if (ret) {
+ /* file exists, but stat call failed */
+
+ os_file_handle_error_no_exit(path, "stat");
+
+ return(FALSE);
+ }
+ if (_S_IFDIR & statinfo.st_mode) {
+ stat_info->type = OS_FILE_TYPE_DIR;
+ } else if (_S_IFREG & statinfo.st_mode) {
+ stat_info->type = OS_FILE_TYPE_FILE;
+ } else {
+ stat_info->type = OS_FILE_TYPE_UNKNOWN;
+ }
+
+ stat_info->ctime = statinfo.st_ctime;
+ stat_info->atime = statinfo.st_atime;
+ stat_info->mtime = statinfo.st_mtime;
+ stat_info->size = statinfo.st_size;
+
+ return(TRUE);
+#else
+ int ret;
+ struct stat statinfo;
+
+ ret = stat(path, &statinfo);
+
+ if (ret && (errno == ENOENT || errno == ENOTDIR)) {
+ /* file does not exist */
+
+ return(FALSE);
+ } else if (ret) {
+ /* file exists, but stat call failed */
+
+ os_file_handle_error_no_exit(path, "stat");
+
+ return(FALSE);
+ }
+
+ if (S_ISDIR(statinfo.st_mode)) {
+ stat_info->type = OS_FILE_TYPE_DIR;
+ } else if (S_ISLNK(statinfo.st_mode)) {
+ stat_info->type = OS_FILE_TYPE_LINK;
+ } else if (S_ISREG(statinfo.st_mode)) {
+ stat_info->type = OS_FILE_TYPE_FILE;
+ } else {
+ stat_info->type = OS_FILE_TYPE_UNKNOWN;
+ }
+
+ stat_info->ctime = statinfo.st_ctime;
+ stat_info->atime = statinfo.st_atime;
+ stat_info->mtime = statinfo.st_mtime;
+ stat_info->size = statinfo.st_size;
+
+ return(TRUE);
+#endif
+}
+
/* path name separator character */
#ifdef __WIN__
# define OS_FILE_PATH_SEPARATOR '\\'
@@ -3466,6 +3550,8 @@ restart:
/* NOTE! We only access constant fields in os_aio_array. Therefore
we do not have to acquire the protecting mutex yet */
+ srv_set_io_thread_op_info(global_segment,
+ "looking for i/o requests (a)");
ut_ad(os_aio_validate());
ut_ad(segment < array->n_segments);
@@ -3484,6 +3570,9 @@ restart:
os_mutex_enter(array->mutex);
+ srv_set_io_thread_op_info(global_segment,
+ "looking for i/o requests (b)");
+
/* Check if there is a slot for which the i/o has already been
done */
@@ -3596,6 +3685,8 @@ consecutive_loop:
}
}
+ srv_set_io_thread_op_info(global_segment, "consecutive i/o requests");
+
/* We have now collected n_consecutive i/o requests in the array;
allocate a single buffer which can hold all data, and perform the
i/o */
@@ -3741,6 +3832,8 @@ slot_io_done:
return(ret);
wait_for_io:
+ srv_set_io_thread_op_info(global_segment, "resetting wait event");
+
/* We wait here until there again can be i/os in the segment
of this thread */
@@ -3832,9 +3925,17 @@ os_aio_print(
ulint i;
for (i = 0; i < srv_n_file_io_threads; i++) {
- fprintf(file, "I/O thread %lu state: %s (%s)\n", (ulong) i,
+ fprintf(file, "I/O thread %lu state: %s (%s)", (ulong) i,
srv_io_thread_op_info[i],
srv_io_thread_function[i]);
+
+#ifndef __WIN__
+ if (os_aio_segment_wait_events[i]->is_set) {
+ fprintf(file, " ev set");
+ }
+#endif
+
+ fprintf(file, "\n");
}
fputs("Pending normal aio reads:", file);
diff --git a/innobase/page/page0page.c b/innobase/page/page0page.c
index b5f411c43fc..343f300fc77 100644
--- a/innobase/page/page0page.c
+++ b/innobase/page/page0page.c
@@ -1579,7 +1579,7 @@ page_validate(
fputs("InnoDB: Record heap and dir overlap on a page ",
stderr);
- dict_index_name_print(stderr, index);
+ dict_index_name_print(stderr, NULL, index);
fprintf(stderr, ", %p, %p\n",
page_header_get_ptr(page, PAGE_HEAP_TOP),
page_dir_get_nth_slot(page, n_slots - 1));
@@ -1610,7 +1610,7 @@ page_validate(
fprintf(stderr,
"InnoDB: Records in wrong order on page %lu",
(ulong) buf_frame_get_page_no(page));
- dict_index_name_print(stderr, index);
+ dict_index_name_print(stderr, NULL, index);
fputs("\nInnoDB: previous record ", stderr);
rec_print(stderr, old_rec);
fputs("\nInnoDB: record ", stderr);
@@ -1752,7 +1752,7 @@ func_exit:
func_exit2:
fprintf(stderr, "InnoDB: Apparent corruption in page %lu in ",
(ulong) buf_frame_get_page_no(page));
- dict_index_name_print(stderr, index);
+ dict_index_name_print(stderr, NULL, index);
putc('\n', stderr);
buf_page_print(page);
}
diff --git a/innobase/pars/pars0opt.c b/innobase/pars/pars0opt.c
index 7ba4af15243..88022e2efe1 100644
--- a/innobase/pars/pars0opt.c
+++ b/innobase/pars/pars0opt.c
@@ -1094,6 +1094,19 @@ opt_clust_access(
for (i = 0; i < n_fields; i++) {
pos = dict_index_get_nth_field_pos(index, clust_index, i);
+ ut_a(pos != ULINT_UNDEFINED);
+
+ /* We optimize here only queries to InnoDB's internal system
+ tables, and they should not contain column prefix indexes. */
+
+ if (dict_index_get_nth_field(index, pos)->prefix_len != 0
+ || dict_index_get_nth_field(clust_index, i)
+ ->prefix_len != 0) {
+ fprintf(stderr,
+"InnoDB: Error in pars0opt.c: table %s has prefix_len != 0\n",
+ index->table_name);
+ }
+
*(plan->clust_map + i) = pos;
ut_ad((pos != ULINT_UNDEFINED)
@@ -1229,7 +1242,7 @@ opt_print_query_plan(
}
fputs("Table ", stderr);
- dict_index_name_print(stderr, plan->index);
+ dict_index_name_print(stderr, NULL, plan->index);
fprintf(stderr,"; exact m. %lu, match %lu, end conds %lu\n",
(unsigned long) plan->n_exact_match,
(unsigned long) n_fields,
diff --git a/innobase/pars/pars0pars.c b/innobase/pars/pars0pars.c
index e4b388cba82..846cb060a7e 100644
--- a/innobase/pars/pars0pars.c
+++ b/innobase/pars/pars0pars.c
@@ -886,7 +886,7 @@ pars_process_assign_list(
upd_field_set_field_no(upd_field,
dict_index_get_nth_col_pos(clust_index,
col_sym->col_no),
- clust_index);
+ clust_index, NULL);
upd_field->exp = assign_node->val;
if (!dtype_is_fixed_size(
diff --git a/innobase/rem/rem0cmp.c b/innobase/rem/rem0cmp.c
index 6e8f3d82ef3..041fb7914e2 100644
--- a/innobase/rem/rem0cmp.c
+++ b/innobase/rem/rem0cmp.c
@@ -452,7 +452,7 @@ cmp_dtuple_rec_with_match(
ulint cur_bytes; /* number of already matched bytes
in current field */
int ret = 3333; /* return value */
-
+
ut_ad(dtuple && rec && matched_fields && matched_bytes);
ut_ad(dtuple_check_typed(dtuple));
@@ -541,7 +541,8 @@ cmp_dtuple_rec_with_match(
&& dtype_get_charset_coll(cur_type->prtype) !=
data_mysql_latin1_swedish_charset_coll)) {
- ret = cmp_whole_field(cur_type,
+ ret = cmp_whole_field(
+ cur_type,
dfield_get_data(dtuple_field), dtuple_f_len,
rec_b_ptr, rec_f_len);
diff --git a/innobase/row/row0ins.c b/innobase/row/row0ins.c
index 0da749212d2..c45818ddd26 100644
--- a/innobase/row/row0ins.c
+++ b/innobase/row/row0ins.c
@@ -50,6 +50,15 @@ innobase_invalidate_query_cache(
ulint full_name_len); /* in: full name length where also the null
chars count */
+/**********************************************************************
+This function returns true if SQL-query in the current thread
+is either REPLACE or LOAD DATA INFILE REPLACE.
+NOTE that /mysql/innobase/row/row0ins.c must contain the
+prototype for this function ! */
+
+ibool
+innobase_query_is_replace(void);
+/*===========================*/
/*************************************************************************
Creates an insert node struct. */
@@ -252,7 +261,7 @@ row_ins_sec_index_entry_by_modify(
heap = mem_heap_create(1024);
update = row_upd_build_sec_rec_difference_binary(cursor->index,
- entry, rec, heap);
+ entry, rec, thr_get_trx(thr), heap);
if (mode == BTR_MODIFY_LEAF) {
/* Try an optimistic updating of the record, keeping changes
within the page */
@@ -316,7 +325,7 @@ row_ins_clust_index_entry_by_modify(
roll_ptr */
update = row_upd_build_difference_binary(cursor->index, entry, ext_vec,
- n_ext_vec, rec, heap);
+ n_ext_vec, rec, thr_get_trx(thr), heap);
if (mode == BTR_MODIFY_LEAF) {
/* Try optimistic updating of the record, keeping changes
within the page */
@@ -554,29 +563,30 @@ row_ins_foreign_report_err(
table */
{
FILE* ef = dict_foreign_err_file;
+ trx_t* trx = thr_get_trx(thr);
mutex_enter(&dict_foreign_err_mutex);
rewind(ef);
ut_print_timestamp(ef);
fputs(" Transaction:\n", ef);
- trx_print(ef, thr_get_trx(thr));
+ trx_print(ef, trx);
fputs("Foreign key constraint fails for table ", ef);
- ut_print_name(ef, foreign->foreign_table_name);
+ ut_print_name(ef, trx, foreign->foreign_table_name);
fputs(":\n", ef);
- dict_print_info_on_foreign_key_in_create_format(ef, foreign);
+ dict_print_info_on_foreign_key_in_create_format(ef, trx, foreign);
putc('\n', ef);
fputs(errstr, ef);
fputs(" in parent table, in index ", ef);
- ut_print_name(ef, foreign->referenced_index->name);
+ ut_print_name(ef, trx, foreign->referenced_index->name);
if (entry) {
fputs(" tuple:\n", ef);
dtuple_print(ef, entry);
}
fputs("\nBut in child table ", ef);
- ut_print_name(ef, foreign->foreign_table_name);
+ ut_print_name(ef, trx, foreign->foreign_table_name);
fputs(", in index ", ef);
- ut_print_name(ef, foreign->foreign_index->name);
+ ut_print_name(ef, trx, foreign->foreign_index->name);
if (rec) {
fputs(", there is a record:\n", ef);
rec_print(ef, rec);
@@ -612,19 +622,19 @@ row_ins_foreign_report_add_err(
fputs(" Transaction:\n", ef);
trx_print(ef, trx);
fputs("Foreign key constraint fails for table ", ef);
- ut_print_name(ef, foreign->foreign_table_name);
+ ut_print_name(ef, trx, foreign->foreign_table_name);
fputs(":\n", ef);
- dict_print_info_on_foreign_key_in_create_format(ef, foreign);
+ dict_print_info_on_foreign_key_in_create_format(ef, trx, foreign);
fputs("\nTrying to add in child table, in index ", ef);
- ut_print_name(ef, foreign->foreign_index->name);
+ ut_print_name(ef, trx, foreign->foreign_index->name);
if (entry) {
fputs(" tuple:\n", ef);
dtuple_print(ef, entry);
}
fputs("\nBut in parent table ", ef);
- ut_print_name(ef, foreign->referenced_table_name);
+ ut_print_name(ef, trx, foreign->referenced_table_name);
fputs(", in index ", ef);
- ut_print_name(ef, foreign->referenced_index->name);
+ ut_print_name(ef, trx, foreign->referenced_index->name);
fputs(",\nthe closest match we can find is record:\n", ef);
if (rec && page_rec_is_supremum(rec)) {
/* If the cursor ended on a supremum record, it is better
@@ -704,11 +714,13 @@ row_ins_foreign_check_on_constraint(
ulint n_to_update;
ulint err;
ulint i;
-
+ trx_t* trx;
ut_a(thr && foreign && pcur && mtr);
+ trx = thr_get_trx(thr);
+
/* Since we are going to delete or update a row, we have to invalidate
the MySQL query cache for table */
@@ -847,7 +859,7 @@ row_ins_foreign_check_on_constraint(
fputs(
"InnoDB: error in cascade of a foreign key op\n"
"InnoDB: ", stderr);
- dict_index_name_print(stderr, index);
+ dict_index_name_print(stderr, trx, index);
fputs("\n"
"InnoDB: record ", stderr);
@@ -968,6 +980,23 @@ row_ins_foreign_check_on_constraint(
err = row_update_cascade_for_mysql(thr, cascade,
foreign->foreign_table);
+
+ if (foreign->foreign_table->n_foreign_key_checks_running == 0) {
+ fprintf(stderr,
+"InnoDB: error: table %s has the counter 0 though there is\n"
+"InnoDB: a FOREIGN KEY check running on it.\n",
+ foreign->foreign_table->name);
+ }
+
+ /* Release the data dictionary latch for a while, so that we do not
+ starve other threads from doing CREATE TABLE etc. if we have a huge
+ cascaded operation running. The counter n_foreign_key_checks_running
+ will prevent other users from dropping or ALTERing the table when we
+ release the latch. */
+
+ row_mysql_unfreeze_data_dictionary(thr_get_trx(thr));
+ row_mysql_freeze_data_dictionary(thr_get_trx(thr));
+
mtr_start(mtr);
/* Restore pcur position */
@@ -1022,6 +1051,33 @@ row_ins_set_shared_rec_lock(
return(err);
}
+
+/*************************************************************************
+Sets a exclusive lock on a record. Used in locking possible duplicate key
+records */
+static
+ulint
+row_ins_set_exclusive_rec_lock(
+/*============================*/
+ /* out: DB_SUCCESS or error code */
+ ulint type, /* in: LOCK_ORDINARY, LOCK_GAP, or
+ LOCK_REC_NOT_GAP type lock */
+ rec_t* rec, /* in: record */
+ dict_index_t* index, /* in: index */
+ que_thr_t* thr) /* in: query thread */
+{
+ ulint err;
+
+ if (index->type & DICT_CLUSTERED) {
+ err = lock_clust_rec_read_check_and_lock(0, rec, index, LOCK_X,
+ type, thr);
+ } else {
+ err = lock_sec_rec_read_check_and_lock(0, rec, index, LOCK_X,
+ type, thr);
+ }
+
+ return(err);
+}
/*******************************************************************
Checks if foreign key constraint fails for an index entry. Sets shared locks
@@ -1057,6 +1113,7 @@ row_ins_check_foreign_constraint(
ulint err;
ulint i;
mtr_t mtr;
+ trx_t* trx = thr_get_trx(thr);
run_again:
#ifdef UNIV_SYNC_DEBUG
@@ -1065,7 +1122,7 @@ run_again:
err = DB_SUCCESS;
- if (thr_get_trx(thr)->check_foreigns == FALSE) {
+ if (trx->check_foreigns == FALSE) {
/* The user has suppressed foreign key checks currently for
this session */
@@ -1123,18 +1180,18 @@ run_again:
rewind(ef);
ut_print_timestamp(ef);
fputs(" Transaction:\n", ef);
- trx_print(ef, thr_get_trx(thr));
+ trx_print(ef, trx);
fputs("Foreign key constraint fails for table ", ef);
- ut_print_name(ef, foreign->foreign_table_name);
+ ut_print_name(ef, trx, foreign->foreign_table_name);
fputs(":\n", ef);
dict_print_info_on_foreign_key_in_create_format(ef,
- foreign);
+ trx, foreign);
fputs("\nTrying to add to index ", ef);
- ut_print_name(ef, foreign->foreign_index->name);
+ ut_print_name(ef, trx, foreign->foreign_index->name);
fputs(" tuple:\n", ef);
dtuple_print(ef, entry);
fputs("\nBut the parent table ", ef);
- ut_print_name(ef, foreign->referenced_table_name);
+ ut_print_name(ef, trx, foreign->referenced_table_name);
fputs(" does not currently exist!\n", ef);
mutex_exit(&dict_foreign_err_mutex);
@@ -1267,7 +1324,7 @@ run_again:
if (check_ref) {
err = DB_NO_REFERENCED_ROW;
row_ins_foreign_report_add_err(
- thr_get_trx(thr), foreign, rec, entry);
+ trx, foreign, rec, entry);
} else {
err = DB_SUCCESS;
}
@@ -1283,7 +1340,7 @@ next_rec:
if (check_ref) {
rec = btr_pcur_get_rec(&pcur);
row_ins_foreign_report_add_err(
- thr_get_trx(thr), foreign, rec, entry);
+ trx, foreign, rec, entry);
err = DB_NO_REFERENCED_ROW;
} else {
err = DB_SUCCESS;
@@ -1302,18 +1359,18 @@ next_rec:
do_possible_lock_wait:
if (err == DB_LOCK_WAIT) {
- thr_get_trx(thr)->error_state = err;
+ trx->error_state = err;
que_thr_stop_for_mysql(thr);
srv_suspend_mysql_thread(thr);
- if (thr_get_trx(thr)->error_state == DB_SUCCESS) {
+ if (trx->error_state == DB_SUCCESS) {
goto run_again;
}
- err = thr_get_trx(thr)->error_state;
+ err = trx->error_state;
}
return(err);
@@ -1451,7 +1508,9 @@ row_ins_scan_sec_index_for_duplicate(
ulint err = DB_SUCCESS;
ibool moved;
mtr_t mtr;
-
+ trx_t* trx;
+ const char* ptr;
+
n_unique = dict_index_get_n_unique(index);
/* If the secondary index is unique, but one of the fields in the
@@ -1488,8 +1547,23 @@ row_ins_scan_sec_index_for_duplicate(
/* Try to place a lock on the index record */
- err = row_ins_set_shared_rec_lock(LOCK_ORDINARY, rec, index,
- thr);
+ trx = thr_get_trx(thr);
+ ut_ad(trx);
+
+ if (innobase_query_is_replace()) {
+
+ /* The manual defines the REPLACE semantics that it
+ is either an INSERT or DELETE(s) for duplicate key
+ + INSERT. Therefore, we should take X-lock for
+ duplicates */
+
+ err = row_ins_set_exclusive_rec_lock(
+ LOCK_ORDINARY,rec,index,thr);
+ } else {
+
+ err = row_ins_set_shared_rec_lock(
+ LOCK_ORDINARY, rec, index,thr);
+ }
if (err != DB_SUCCESS) {
@@ -1556,6 +1630,7 @@ row_ins_duplicate_error_in_clust(
page_t* page;
ulint n_unique;
trx_t* trx = thr_get_trx(thr);
+ const char* ptr;
UT_NOT_USED(mtr);
@@ -1588,9 +1663,24 @@ row_ins_duplicate_error_in_clust(
is needed in logical logging of MySQL to make
sure that in roll-forward we get the same duplicate
errors as in original execution */
-
- err = row_ins_set_shared_rec_lock(LOCK_REC_NOT_GAP,
- rec, cursor->index, thr);
+
+ if (innobase_query_is_replace()) {
+
+ /* The manual defines the REPLACE semantics
+ that it is either an INSERT or DELETE(s)
+ for duplicate key + INSERT. Therefore, we
+ should take X-lock for duplicates */
+
+ err = row_ins_set_exclusive_rec_lock(
+ LOCK_REC_NOT_GAP,rec,cursor->index,
+ thr);
+ } else {
+
+ err = row_ins_set_shared_rec_lock(
+ LOCK_REC_NOT_GAP,rec, cursor->index,
+ thr);
+ }
+
if (err != DB_SUCCESS) {
return(err);
@@ -1611,8 +1701,24 @@ row_ins_duplicate_error_in_clust(
if (rec != page_get_supremum_rec(page)) {
- err = row_ins_set_shared_rec_lock(LOCK_REC_NOT_GAP,
- rec, cursor->index, thr);
+
+ /* The manual defines the REPLACE semantics that it
+ is either an INSERT or DELETE(s) for duplicate key
+ + INSERT. Therefore, we should take X-lock for
+ duplicates. */
+
+ if (innobase_query_is_replace()) {
+
+ err = row_ins_set_exclusive_rec_lock(
+ LOCK_REC_NOT_GAP,
+ rec,cursor->index,thr);
+ } else {
+
+ err = row_ins_set_shared_rec_lock(
+ LOCK_REC_NOT_GAP,rec,
+ cursor->index, thr);
+ }
+
if (err != DB_SUCCESS) {
return(err);
@@ -1913,6 +2019,7 @@ row_ins_index_entry_set_vals(
dfield_t* row_field;
ulint n_fields;
ulint i;
+ dtype_t* cur_type;
ut_ad(entry && row);
@@ -1926,10 +2033,14 @@ row_ins_index_entry_set_vals(
/* Check column prefix indexes */
if (ind_field->prefix_len > 0
- && dfield_get_len(row_field) != UNIV_SQL_NULL
- && dfield_get_len(row_field) > ind_field->prefix_len) {
-
- field->len = ind_field->prefix_len;
+ && dfield_get_len(row_field) != UNIV_SQL_NULL) {
+
+ cur_type = dict_col_get_type(
+ dict_field_get_col(ind_field));
+
+ field->len = dtype_get_at_most_n_mbchars(cur_type,
+ ind_field->prefix_len,
+ dfield_get_len(row_field), row_field->data);
} else {
field->len = row_field->len;
}
@@ -2214,4 +2325,4 @@ error_handling:
}
return(thr);
-}
+}
diff --git a/innobase/row/row0mysql.c b/innobase/row/row0mysql.c
index 2e8c3adf94f..241ddc310e8 100644
--- a/innobase/row/row0mysql.c
+++ b/innobase/row/row0mysql.c
@@ -92,6 +92,19 @@ row_mysql_is_system_table(
|| 0 == strcmp(name + 6, "user")
|| 0 == strcmp(name + 6, "db"));
}
+
+/***********************************************************************
+Delays an INSERT, DELETE or UPDATE operation if the purge is lagging. */
+static
+void
+row_mysql_delay_if_needed(void)
+/*===========================*/
+{
+ if (srv_dml_needed_delay) {
+ os_thread_sleep(srv_dml_needed_delay);
+ }
+}
+
/***********************************************************************
Reads a MySQL format variable-length field (like VARCHAR) length and
returns pointer to the field data. */
@@ -326,8 +339,9 @@ handle_new_error:
"InnoDB: a case of widespread corruption, dump all InnoDB\n"
"InnoDB: tables and recreate the whole InnoDB tablespace.\n"
"InnoDB: If the mysqld server crashes after the startup or when\n"
- "InnoDB: you dump the tables, look at section 6.1 of\n"
- "InnoDB: http://www.innodb.com/ibman.html for help.\n", stderr);
+ "InnoDB: you dump the tables, look at\n"
+ "InnoDB: http://dev.mysql.com/doc/mysql/en/Forcing_recovery.html"
+ " for help.\n", stderr);
} else {
fprintf(stderr, "InnoDB: unknown error code %lu\n",
@@ -444,7 +458,7 @@ row_prebuilt_free(
"InnoDB: table handle. Magic n %lu, magic n2 %lu, table name",
(ulong) prebuilt->magic_n,
(ulong) prebuilt->magic_n2);
- ut_print_name(stderr, prebuilt->table->name);
+ ut_print_name(stderr, NULL, prebuilt->table->name);
putc('\n', stderr);
mem_analyze_corruption((byte*)prebuilt);
@@ -537,7 +551,7 @@ row_update_prebuilt_trx(
"InnoDB: Error: trying to use a corrupt\n"
"InnoDB: table handle. Magic n %lu, table name",
(ulong) prebuilt->magic_n);
- ut_print_name(stderr, prebuilt->table->name);
+ ut_print_name(stderr, NULL, prebuilt->table->name);
putc('\n', stderr);
mem_analyze_corruption((byte*)prebuilt);
@@ -851,7 +865,7 @@ row_insert_for_mysql(
"InnoDB: Error: trying to free a corrupt\n"
"InnoDB: table handle. Magic n %lu, table name",
(ulong) prebuilt->magic_n);
- ut_print_name(stderr, prebuilt->table->name);
+ ut_print_name(stderr, prebuilt->trx, prebuilt->table->name);
putc('\n', stderr);
mem_analyze_corruption((byte*)prebuilt);
@@ -873,6 +887,8 @@ row_insert_for_mysql(
trx->op_info = "inserting";
+ row_mysql_delay_if_needed();
+
trx_start_if_not_started(trx);
if (node == NULL) {
@@ -1066,7 +1082,7 @@ row_update_for_mysql(
"InnoDB: Error: trying to free a corrupt\n"
"InnoDB: table handle. Magic n %lu, table name",
(ulong) prebuilt->magic_n);
- ut_print_name(stderr, prebuilt->table->name);
+ ut_print_name(stderr, prebuilt->trx, prebuilt->table->name);
putc('\n', stderr);
mem_analyze_corruption((byte*)prebuilt);
@@ -1088,6 +1104,8 @@ row_update_for_mysql(
trx->op_info = "updating or deleting";
+ row_mysql_delay_if_needed();
+
trx_start_if_not_started(trx);
node = prebuilt->upd_node;
@@ -1551,7 +1569,7 @@ row_create_table_for_mysql(
if (err == DB_OUT_OF_FILE_SPACE) {
fputs("InnoDB: Warning: cannot create table ", stderr);
- ut_print_name(stderr, table->name);
+ ut_print_name(stderr, trx, table->name);
fputs(" because tablespace full\n", stderr);
row_drop_table_for_mysql(table->name, trx, FALSE);
@@ -1559,7 +1577,7 @@ row_create_table_for_mysql(
ut_print_timestamp(stderr);
fputs(" InnoDB: Error: table ", stderr);
- ut_print_name(stderr, table->name);
+ ut_print_name(stderr, trx, table->name);
fputs(" already exists in InnoDB internal\n"
"InnoDB: data dictionary. Have you deleted the .frm file\n"
"InnoDB: and not used DROP TABLE? Have you used DROP DATABASE\n"
@@ -1567,11 +1585,12 @@ row_create_table_for_mysql(
"InnoDB: See the Restrictions section of the InnoDB manual.\n"
"InnoDB: You can drop the orphaned table inside InnoDB by\n"
"InnoDB: creating an InnoDB table with the same name in another\n"
- "InnoDB: database and moving the .frm file to the current database.\n"
+ "InnoDB: database and copying the .frm file to the current database.\n"
"InnoDB: Then MySQL thinks the table exists, and DROP TABLE will\n"
"InnoDB: succeed.\n"
- "InnoDB: You can look for further help from section 15.1 of\n"
- "InnoDB: http://www.innodb.com/ibman.php\n", stderr);
+ "InnoDB: You can look for further help from\n"
+ "InnoDB: http://dev.mysql.com/doc/mysql/en/"
+ "InnoDB_troubleshooting_datadict.html\n", stderr);
}
/* We may also get err == DB_ERROR if the .ibd file for the
@@ -1613,6 +1632,8 @@ row_create_index_for_mysql(
trx->op_info = "creating index";
+ trx_start_if_not_started(trx);
+
/* Check that the same column does not appear twice in the index.
Starting from 4.0.14, InnoDB should be able to cope with that, but
safer not to allow them. */
@@ -1626,10 +1647,10 @@ row_create_index_for_mysql(
ut_print_timestamp(stderr);
fputs(" InnoDB: Error: column ", stderr);
- ut_print_name(stderr,
+ ut_print_name(stderr, trx,
dict_index_get_nth_field(index, i)->name);
fputs(" appears twice in ", stderr);
- dict_index_name_print(stderr, index);
+ dict_index_name_print(stderr, trx, index);
fputs("\n"
"InnoDB: This is not allowed in InnoDB.\n",
stderr);
@@ -1639,9 +1660,16 @@ row_create_index_for_mysql(
goto error_handling;
}
}
- }
+
+ /* Check also that prefix_len < DICT_MAX_COL_PREFIX_LEN */
- trx_start_if_not_started(trx);
+ if (dict_index_get_nth_field(index, i)->prefix_len
+ >= DICT_MAX_COL_PREFIX_LEN) {
+ err = DB_TOO_BIG_RECORD;
+
+ goto error_handling;
+ }
+ }
if (row_mysql_is_recovered_tmp_table(index->table_name)) {
@@ -1778,7 +1806,7 @@ row_drop_table_for_mysql_in_background(
if (error != DB_SUCCESS) {
ut_print_timestamp(stderr);
fputs(" InnoDB: Error: Dropping table ", stderr);
- ut_print_name(stderr, name);
+ ut_print_name(stderr, trx, name);
fputs(" in background drop list failed\n", stderr);
}
@@ -1857,9 +1885,9 @@ already_dropped:
UT_LIST_REMOVE(row_mysql_drop_list, row_mysql_drop_list, drop);
ut_print_timestamp(stderr);
- fputs(" InnoDB: Dropped table ", stderr);
- ut_print_name(stderr, drop->table_name);
- fputs(" in background drop queue.\n", stderr);
+ fprintf(stderr,
+ " InnoDB: Dropped table %s in background drop queue.\n",
+ drop->table_name);
mem_free(drop->table_name);
@@ -1971,9 +1999,9 @@ row_discard_tablespace_for_mysql(
"new_id_high INT;\n"
"table_name CHAR;\n"
"BEGIN\n"
- "table_name := ";
+ "table_name := '";
static const char discard_tablespace_proc2[] =
- ";\n"
+ "';\n"
"new_id_high := %lu;\n"
"new_id_low := %lu;\n"
"new_id := CONCAT(TO_BINARY(new_id_high, 4), TO_BINARY(new_id_low, 4));\n"
@@ -2014,7 +2042,7 @@ row_discard_tablespace_for_mysql(
if (table->space == 0) {
ut_print_timestamp(stderr);
fputs(" InnoDB: Error: table ", stderr);
- ut_print_name(stderr, name);
+ ut_print_name(stderr, trx, name);
fputs("\n"
"InnoDB: is in the system tablespace 0 which cannot be discarded\n", stderr);
err = DB_ERROR;
@@ -2125,6 +2153,12 @@ row_import_tablespace_for_mysql(
success = fil_reset_too_high_lsns(name, current_lsn);
if (!success) {
+ ut_print_timestamp(stderr);
+ fputs(" InnoDB: Error: cannot reset lsn's in table ", stderr);
+ ut_print_name(stderr, trx, name);
+ fputs("\n"
+ "InnoDB: in ALTER TABLE ... IMPORT TABLESPACE\n", stderr);
+
err = DB_ERROR;
row_mysql_lock_data_dictionary(trx);
@@ -2140,6 +2174,14 @@ row_import_tablespace_for_mysql(
table = dict_table_get_low(name);
if (!table) {
+ ut_print_timestamp(stderr);
+ fputs(" InnoDB: table ", stderr);
+ ut_print_name(stderr, trx, name);
+ fputs("\n"
+"InnoDB: does not exist in the InnoDB data dictionary\n"
+"InnoDB: in ALTER TABLE ... IMPORT TABLESPACE\n",
+ stderr);
+
err = DB_TABLE_NOT_FOUND;
goto funct_exit;
@@ -2148,7 +2190,7 @@ row_import_tablespace_for_mysql(
if (table->space == 0) {
ut_print_timestamp(stderr);
fputs(" InnoDB: Error: table ", stderr);
- ut_print_name(stderr, name);
+ ut_print_name(stderr, trx, name);
fputs("\n"
"InnoDB: is in the system tablespace 0 which cannot be imported\n", stderr);
err = DB_ERROR;
@@ -2161,7 +2203,7 @@ row_import_tablespace_for_mysql(
fputs(
" InnoDB: Error: you are trying to IMPORT a tablespace\n"
"InnoDB: ", stderr);
- ut_print_name(stderr, name);
+ ut_print_name(stderr, trx, name);
fputs(", though you have not called DISCARD on it yet\n"
"InnoDB: during the lifetime of the mysqld process!\n", stderr);
@@ -2181,6 +2223,17 @@ row_import_tablespace_for_mysql(
table->ibd_file_missing = FALSE;
table->tablespace_discarded = FALSE;
} else {
+ if (table->ibd_file_missing) {
+ ut_print_timestamp(stderr);
+ fputs(
+" InnoDB: cannot find of open in the database directory the .ibd file of\n"
+"InnoDB: table ", stderr);
+ ut_print_name(stderr, trx, name);
+ fputs("\n"
+"InnoDB: in ALTER TABLE ... IMPORT TABLESPACE\n",
+ stderr);
+ }
+
err = DB_ERROR;
}
@@ -2215,14 +2268,17 @@ row_drop_table_for_mysql(
ulint err;
const char* table_name;
ulint namelen;
+ char* dir_path_of_temp_table = NULL;
ibool success;
ibool locked_dictionary = FALSE;
char* quoted_name;
char* sql;
+
/* We use the private SQL parser of Innobase to generate the
query graphs needed in deleting the dictionary data from system
tables in Innobase. Deleting a row from SYS_INDEXES table also
frees the file segments of the B-tree associated with the index. */
+
static const char str1[] =
"PROCEDURE DROP_TABLE_PROC () IS\n"
"table_name CHAR;\n"
@@ -2343,6 +2399,7 @@ row_drop_table_for_mysql(
memcpy(sql, str1, (sizeof str1) - 1);
memcpy(sql + (sizeof str1) - 1, quoted_name, namelen);
memcpy(sql + (sizeof str1) - 1 + namelen, str2, sizeof str2);
+ mem_free(quoted_name);
/* Serialize data dictionary operations with dictionary mutex:
no deadlocks can occur then in these operations */
@@ -2378,13 +2435,14 @@ row_drop_table_for_mysql(
ut_print_timestamp(stderr);
fputs(" InnoDB: Error: table ", stderr);
- ut_print_name(stderr, name);
+ ut_print_name(stderr, trx, name);
fputs(" does not exist in the InnoDB internal\n"
"InnoDB: data dictionary though MySQL is trying to drop it.\n"
"InnoDB: Have you copied the .frm file of the table to the\n"
"InnoDB: MySQL database directory from another database?\n"
- "InnoDB: You can look for further help from section 15.1 of\n"
- "InnoDB: http://www.innodb.com/ibman.php\n", stderr);
+ "InnoDB: You can look for further help from\n"
+ "InnoDB: http://dev.mysql.com/doc/mysql/en/"
+ "InnoDB_troubleshooting_datadict.html\n", stderr);
goto funct_exit;
}
@@ -2412,10 +2470,10 @@ row_drop_table_for_mysql(
ut_print_timestamp(ef);
fputs(" Cannot drop table ", ef);
- ut_print_name(ef, name);
+ ut_print_name(ef, trx, name);
fputs("\n"
"because it is referenced by ", ef);
- ut_print_name(ef, foreign->foreign_table_name);
+ ut_print_name(ef, trx, foreign->foreign_table_name);
putc('\n', ef);
mutex_exit(&dict_foreign_err_mutex);
@@ -2427,7 +2485,7 @@ row_drop_table_for_mysql(
ut_print_timestamp(stderr);
fputs(" InnoDB: Warning: MySQL is trying to drop table ",
stderr);
- ut_print_name(stderr, table->name);
+ ut_print_name(stderr, trx, table->name);
fputs("\n"
"InnoDB: though there are still open handles to it.\n"
"InnoDB: Adding the table to the background drop queue.\n",
@@ -2444,10 +2502,10 @@ row_drop_table_for_mysql(
ut_print_timestamp(stderr);
fputs(" InnoDB: You are trying to drop table ", stderr);
- ut_print_name(stderr, table->name);
+ ut_print_name(stderr, trx, table->name);
fputs("\n"
- "InnoDB: though there are foreign key check running on it.\n"
- "InnoDB: Adding the table to the background drop queue.\n",
+ "InnoDB: though there is a foreign key check running on it.\n"
+ "InnoDB: Adding the table to the background drop queue.\n",
stderr);
row_add_table_to_background_drop_list(table);
@@ -2479,14 +2537,28 @@ row_drop_table_for_mysql(
ut_error;
} else {
+ ibool is_path;
+ const char* name_or_path;
+
space_id = table->space;
+
+ if (table->dir_path_of_temp_table != NULL) {
+ dir_path_of_temp_table =
+ mem_strdup(table->dir_path_of_temp_table);
+ is_path = TRUE;
+ name_or_path = dir_path_of_temp_table;
+ } else {
+ is_path = FALSE;
+ name_or_path = name;
+ }
+
dict_table_remove_from_cache(table);
if (dict_load_table(name) != NULL) {
ut_print_timestamp(stderr);
fputs(" InnoDB: Error: not able to remove table ",
stderr);
- ut_print_name(stderr, name);
+ ut_print_name(stderr, trx, name);
fputs(" from the dictionary cache!\n", stderr);
err = DB_ERROR;
}
@@ -2495,9 +2567,17 @@ row_drop_table_for_mysql(
wrong: we do not want to delete valuable data of the user */
if (err == DB_SUCCESS && space_id > 0) {
- if (!fil_space_for_table_exists_in_mem(space_id, name,
+ if (!fil_space_for_table_exists_in_mem(space_id,
+ name_or_path,
+ is_path,
FALSE, TRUE)) {
- err = DB_ERROR;
+ err = DB_SUCCESS;
+
+ fprintf(stderr,
+"InnoDB: We removed now the InnoDB internal data dictionary entry\n"
+"InnoDB: of table ");
+ ut_print_name(stderr, trx, name);
+ fprintf(stderr, ".\n");
goto funct_exit;
}
@@ -2505,11 +2585,17 @@ row_drop_table_for_mysql(
success = fil_delete_tablespace(space_id);
if (!success) {
+ fprintf(stderr,
+"InnoDB: We removed now the InnoDB internal data dictionary entry\n"
+"InnoDB: of table ");
+ ut_print_name(stderr, trx, name);
+ fprintf(stderr, ".\n");
+
ut_print_timestamp(stderr);
fprintf(stderr,
" InnoDB: Error: not able to delete tablespace %lu of table ",
(ulong) space_id);
- ut_print_name(stderr, name);
+ ut_print_name(stderr, trx, name);
fputs("!\n", stderr);
err = DB_ERROR;
}
@@ -2521,6 +2607,10 @@ funct_exit:
row_mysql_unlock_data_dictionary(trx);
}
+ if (dir_path_of_temp_table) {
+ mem_free(dir_path_of_temp_table);
+ }
+
que_graph_free(graph);
trx_commit_for_mysql(trx);
@@ -2573,10 +2663,10 @@ loop:
ut_print_timestamp(stderr);
fputs(
" InnoDB: Warning: MySQL is trying to drop database ", stderr);
- ut_print_name(stderr, name);
+ ut_print_name(stderr, trx, name);
fputs("\n"
"InnoDB: though there are still open handles to table ", stderr);
- ut_print_name(stderr, table_name);
+ ut_print_name(stderr, trx, table_name);
fputs(".\n", stderr);
os_thread_sleep(1000000);
@@ -2592,10 +2682,10 @@ loop:
if (err != DB_SUCCESS) {
fputs("InnoDB: DROP DATABASE ", stderr);
- ut_print_name(stderr, name);
+ ut_print_name(stderr, trx, name);
fprintf(stderr, " failed with error %lu for table ",
(ulint) err);
- ut_print_name(stderr, table_name);
+ ut_print_name(stderr, trx, table_name);
putc('\n', stderr);
break;
}
@@ -2776,7 +2866,7 @@ row_rename_table_for_mysql(
ut_print_timestamp(stderr);
fputs(" InnoDB: Error: table ", stderr);
- ut_print_name(stderr, old_name);
+ ut_print_name(stderr, trx, old_name);
fputs(" does not exist in the InnoDB internal\n"
"InnoDB: data dictionary though MySQL is trying to rename the table.\n"
"InnoDB: Have you copied the .frm file of the table to the\n"
@@ -2791,7 +2881,7 @@ row_rename_table_for_mysql(
ut_print_timestamp(stderr);
fputs(" InnoDB: Error: table ", stderr);
- ut_print_name(stderr, old_name);
+ ut_print_name(stderr, trx, old_name);
fputs(
" does not have an .ibd file in the database directory.\n"
"InnoDB: You can look for further help from section 15.1 of\n"
@@ -2923,22 +3013,24 @@ row_rename_table_for_mysql(
if (err == DB_DUPLICATE_KEY) {
ut_print_timestamp(stderr);
fputs(" InnoDB: Error: table ", stderr);
- ut_print_name(stderr, new_name);
+ ut_print_name(stderr, trx, new_name);
fputs(" exists in the InnoDB internal data\n"
"InnoDB: dictionary though MySQL is trying rename table ", stderr);
- ut_print_name(stderr, old_name);
+ ut_print_name(stderr, trx, old_name);
fputs(" to it.\n"
"InnoDB: Have you deleted the .frm file and not used DROP TABLE?\n"
- "InnoDB: You can look for further help from section 15.1 of\n"
- "InnoDB: http://www.innodb.com/ibman.php\n"
+ "InnoDB: You can look for further help from\n"
+ "InnoDB: http://dev.mysql.com/doc/mysql/en/"
+ "InnoDB_troubleshooting_datadict.html\n"
"InnoDB: If table ", stderr);
- ut_print_name(stderr, new_name);
- fputs(" is a temporary table #sql..., then it can be that\n"
+ ut_print_name(stderr, trx, new_name);
+ fputs(
+ " is a temporary table #sql..., then it can be that\n"
"InnoDB: there are still queries running on the table, and it will be\n"
"InnoDB: dropped automatically when the queries end.\n"
"InnoDB: You can drop the orphaned table inside InnoDB by\n"
"InnoDB: creating an InnoDB table with the same name in another\n"
- "InnoDB: database and moving the .frm file to the current database.\n"
+ "InnoDB: database and copying the .frm file to the current database.\n"
"InnoDB: Then MySQL thinks the table exists, and DROP TABLE will\n"
"InnoDB: succeed.\n", stderr);
}
@@ -2958,9 +3050,9 @@ row_rename_table_for_mysql(
ut_print_timestamp(stderr);
fputs(" InnoDB: Error in table rename, cannot rename ",
stderr);
- ut_print_name(stderr, old_name);
+ ut_print_name(stderr, trx, old_name);
fputs(" to ", stderr);
- ut_print_name(stderr, new_name);
+ ut_print_name(stderr, trx, new_name);
putc('\n', stderr);
err = DB_ERROR;
@@ -2982,14 +3074,14 @@ row_rename_table_for_mysql(
ut_print_timestamp(stderr);
fputs(" InnoDB: Error: in ALTER TABLE ",
stderr);
- ut_print_name(stderr, new_name);
+ ut_print_name(stderr, trx, new_name);
fputs("\n"
"InnoDB: has or is referenced in foreign key constraints\n"
"InnoDB: which are not compatible with the new table definition.\n",
stderr);
ut_a(dict_table_rename_in_cache(table,
- old_name, FALSE));
+ old_name, FALSE));
trx->error_state = DB_SUCCESS;
trx_general_rollback_for_mysql(trx, FALSE,
NULL);
@@ -3005,14 +3097,14 @@ row_rename_table_for_mysql(
fputs(
" InnoDB: Error: in RENAME TABLE table ",
stderr);
- ut_print_name(stderr, new_name);
+ ut_print_name(stderr, trx, new_name);
fputs("\n"
"InnoDB: is referenced in foreign key constraints\n"
"InnoDB: which are not compatible with the new table definition.\n",
stderr);
ut_a(dict_table_rename_in_cache(table,
- old_name, FALSE));
+ old_name, FALSE));
trx->error_state = DB_SUCCESS;
trx_general_rollback_for_mysql(trx, FALSE,
@@ -3129,7 +3221,8 @@ loop:
fputs("InnoDB: index records in a wrong order in ",
stderr);
not_ok:
- dict_index_name_print(stderr, index);
+ dict_index_name_print(stderr,
+ prebuilt->trx, index);
fputs("\n"
"InnoDB: prev record ", stderr);
dtuple_print(stderr, prev_entry);
@@ -3215,7 +3308,8 @@ row_check_table_for_mysql(
ret = DB_ERROR;
fputs("Error: ", stderr);
- dict_index_name_print(stderr, index);
+ dict_index_name_print(stderr,
+ prebuilt->trx, index);
fprintf(stderr,
" contains %lu entries, should be %lu\n",
(ulong) n_rows,
diff --git a/innobase/row/row0purge.c b/innobase/row/row0purge.c
index 8f5f0831dc6..f7e01169b9d 100644
--- a/innobase/row/row0purge.c
+++ b/innobase/row/row0purge.c
@@ -543,8 +543,8 @@ row_purge_parse_undo_rec(
node->heap);
ptr = trx_undo_update_rec_get_update(ptr, clust_index, type, trx_id,
- roll_ptr, info_bits, node->heap,
- &(node->update));
+ roll_ptr, info_bits, trx,
+ node->heap, &(node->update));
/* Read to the partial row the fields that occur in indexes */
diff --git a/innobase/row/row0row.c b/innobase/row/row0row.c
index 680539764fd..38714b0c49b 100644
--- a/innobase/row/row0row.c
+++ b/innobase/row/row0row.c
@@ -113,6 +113,8 @@ row_build_index_entry(
dfield_t* dfield2;
dict_col_t* col;
ulint i;
+ ulint storage_len;
+ dtype_t* cur_type;
ut_ad(row && index && heap);
ut_ad(dtuple_check_typed(row));
@@ -139,10 +141,17 @@ row_build_index_entry(
/* If a column prefix index, take only the prefix */
if (ind_field->prefix_len > 0
- && dfield_get_len(dfield2) != UNIV_SQL_NULL
- && dfield_get_len(dfield2) > ind_field->prefix_len) {
+ && dfield_get_len(dfield2) != UNIV_SQL_NULL) {
- dfield_set_len(dfield, ind_field->prefix_len);
+ cur_type = dict_col_get_type(
+ dict_field_get_col(ind_field));
+
+ storage_len = dtype_get_at_most_n_mbchars(
+ cur_type,
+ ind_field->prefix_len,
+ dfield_get_len(dfield2), dfield2->data);
+
+ dfield_set_len(dfield, storage_len);
}
}
@@ -334,6 +343,7 @@ row_build_row_ref(
ulint ref_len;
ulint pos;
byte* buf;
+ ulint clust_col_prefix_len;
ulint i;
ut_ad(index && rec && heap);
@@ -366,6 +376,24 @@ row_build_row_ref(
field = rec_get_nth_field(rec, pos, &len);
dfield_set_data(dfield, field, len);
+
+ /* If the primary key contains a column prefix, then the
+ secondary index may contain a longer prefix of the same
+ column, or the full column, and we must adjust the length
+ accordingly. */
+
+ clust_col_prefix_len =
+ dict_index_get_nth_field(clust_index, i)->prefix_len;
+
+ if (clust_col_prefix_len > 0) {
+ if (len != UNIV_SQL_NULL) {
+
+ dfield_set_len(dfield,
+ dtype_get_at_most_n_mbchars(
+ dfield_get_type(dfield),
+ clust_col_prefix_len, len, field));
+ }
+ }
}
ut_ad(dtuple_check_typed(ref));
@@ -383,12 +411,13 @@ row_build_row_ref_in_tuple(
dtuple_t* ref, /* in/out: row reference built; see the
NOTE below! */
dict_index_t* index, /* in: index */
- rec_t* rec) /* in: record in the index;
+ rec_t* rec, /* in: record in the index;
NOTE: the data fields in ref will point
directly into this record, therefore,
the buffer page of this record must be
at least s-latched and the latch held
as long as the row reference is used! */
+ trx_t* trx) /* in: transaction */
{
dict_index_t* clust_index;
dfield_t* dfield;
@@ -396,6 +425,7 @@ row_build_row_ref_in_tuple(
ulint len;
ulint ref_len;
ulint pos;
+ ulint clust_col_prefix_len;
ulint i;
ut_a(ref && index && rec);
@@ -403,9 +433,9 @@ row_build_row_ref_in_tuple(
if (!index->table) {
fputs("InnoDB: table ", stderr);
notfound:
- ut_print_name(stderr, index->table_name);
+ ut_print_name(stderr, trx, index->table_name);
fputs(" for index ", stderr);
- ut_print_name(stderr, index->name);
+ ut_print_name(stderr, trx, index->name);
fputs(" not found\n", stderr);
ut_error;
}
@@ -433,6 +463,24 @@ row_build_row_ref_in_tuple(
field = rec_get_nth_field(rec, pos, &len);
dfield_set_data(dfield, field, len);
+
+ /* If the primary key contains a column prefix, then the
+ secondary index may contain a longer prefix of the same
+ column, or the full column, and we must adjust the length
+ accordingly. */
+
+ clust_col_prefix_len =
+ dict_index_get_nth_field(clust_index, i)->prefix_len;
+
+ if (clust_col_prefix_len > 0) {
+ if (len != UNIV_SQL_NULL) {
+
+ dfield_set_len(dfield,
+ dtype_get_at_most_n_mbchars(
+ dfield_get_type(dfield),
+ clust_col_prefix_len, len, field));
+ }
+ }
}
ut_ad(dtuple_check_typed(ref));
@@ -460,6 +508,7 @@ row_build_row_ref_from_row(
dict_col_t* col;
ulint ref_len;
ulint i;
+ dtype_t* cur_type;
ut_ad(ref && table && row);
@@ -481,10 +530,15 @@ row_build_row_ref_from_row(
dfield_copy(dfield, dfield2);
if (field->prefix_len > 0
- && dfield->len != UNIV_SQL_NULL
- && dfield->len > field->prefix_len) {
+ && dfield->len != UNIV_SQL_NULL) {
+
+ cur_type = dict_col_get_type(
+ dict_field_get_col(field));
- dfield->len = field->prefix_len;
+ dfield->len = dtype_get_at_most_n_mbchars(
+ cur_type,
+ field->prefix_len,
+ dfield->len, dfield->data);
}
}
diff --git a/innobase/row/row0sel.c b/innobase/row/row0sel.c
index dc6694fc18c..71163bc35b6 100644
--- a/innobase/row/row0sel.c
+++ b/innobase/row/row0sel.c
@@ -76,6 +76,7 @@ row_sel_sec_rec_is_for_clust_rec(
ulint clust_len;
ulint n;
ulint i;
+ dtype_t* cur_type;
UT_NOT_USED(clust_index);
@@ -91,10 +92,15 @@ row_sel_sec_rec_is_for_clust_rec(
sec_field = rec_get_nth_field(sec_rec, i, &sec_len);
if (ifield->prefix_len > 0
- && clust_len != UNIV_SQL_NULL
- && clust_len > ifield->prefix_len) {
+ && clust_len != UNIV_SQL_NULL) {
- clust_len = ifield->prefix_len;
+ cur_type = dict_col_get_type(
+ dict_field_get_col(ifield));
+
+ clust_len = dtype_get_at_most_n_mbchars(
+ cur_type,
+ ifield->prefix_len,
+ clust_len, clust_field);
}
if (0 != cmp_data_data(dict_col_get_type(col),
@@ -1942,7 +1948,8 @@ row_sel_convert_mysql_key_to_innobase(
ulint buf_len, /* in: buffer length */
dict_index_t* index, /* in: index of the key value */
byte* key_ptr, /* in: MySQL key value */
- ulint key_len) /* in: MySQL key value length */
+ ulint key_len, /* in: MySQL key value length */
+ trx_t* trx) /* in: transaction */
{
byte* original_buf = buf;
byte* original_key_ptr = key_ptr;
@@ -2017,19 +2024,15 @@ row_sel_convert_mysql_key_to_innobase(
/* MySQL stores the actual data length to the first 2
bytes after the optional SQL NULL marker byte. The
- storage format is little-endian. */
-
- /* There are no key fields > 255 bytes currently in
- MySQL */
- if (key_ptr[data_offset + 1] != 0) {
- ut_print_timestamp(stderr);
- fputs(
-" InnoDB: Error: BLOB or TEXT prefix > 255 bytes in query to table ", stderr);
- ut_print_name(stderr, index->table_name);
- putc('\n', stderr);
- }
-
- data_len = key_ptr[data_offset];
+ storage format is little-endian, that is, the most
+ significant byte at a higher address. In UTF-8, MySQL
+ seems to reserve field->prefix_len bytes for
+ storing this field in the key value buffer, even
+ though the actual value only takes data_len bytes
+ from the start. */
+
+ data_len = key_ptr[data_offset]
+ + 256 * key_ptr[data_offset + 1];
data_field_len = data_offset + 2 + field->prefix_len;
data_offset += 2;
@@ -2037,6 +2040,17 @@ row_sel_convert_mysql_key_to_innobase(
store the column value like it would
be a fixed char field */
} else if (field->prefix_len > 0) {
+ /* Looks like MySQL pads unused end bytes in the
+ prefix with space. Therefore, also in UTF-8, it is ok
+ to compare with a prefix containing full prefix_len
+ bytes, and no need to take at most prefix_len / 3
+ UTF-8 characters from the start.
+ If the prefix is used as the upper end of a LIKE
+ 'abc%' query, then MySQL pads the end with chars
+ 0xff. TODO: in that case does it any harm to compare
+ with the full prefix_len bytes. How do characters
+ 0xff in UTF-8 behave? */
+
data_len = field->prefix_len;
data_field_len = data_offset + data_len;
} else {
@@ -2069,11 +2083,13 @@ row_sel_convert_mysql_key_to_innobase(
ut_print_timestamp(stderr);
- fprintf(stderr,
+ fputs(
" InnoDB: Warning: using a partial-field key prefix in search.\n"
- "InnoDB: Table name %s, index name %s. Last data field length %lu bytes,\n"
+ "InnoDB: ", stderr);
+ dict_index_name_print(stderr, trx, index);
+ fprintf(stderr, ". Last data field length %lu bytes,\n"
"InnoDB: key ptr now exceeds key end by %lu bytes.\n"
- "InnoDB: Key value in the MySQL format:\n", index->table_name, index->name,
+ "InnoDB: Key value in the MySQL format:\n",
(ulong) data_field_len,
(ulong) (key_ptr - key_end));
fflush(stderr);
@@ -2116,7 +2132,7 @@ row_sel_store_row_id_to_prebuilt(
if (len != DATA_ROW_ID_LEN) {
fprintf(stderr,
"InnoDB: Error: Row id field is wrong length %lu in ", (ulong) len);
- dict_index_name_print(stderr, index);
+ dict_index_name_print(stderr, prebuilt->trx, index);
fprintf(stderr, "\n"
"InnoDB: Field number %lu, record:\n",
(ulong) dict_index_get_sys_col_pos(index, DATA_ROW_ID));
@@ -2275,7 +2291,11 @@ row_sel_store_mysql_rec(
ut_print_timestamp(stderr);
fprintf(stderr,
" InnoDB: Warning: could not allocate %lu + 1000000 bytes to retrieve\n"
-"InnoDB: a big column. Table name %s\n", (ulong) len, prebuilt->table->name);
+"InnoDB: a big column. Table name ", (ulong) len);
+ ut_print_name(stderr,
+ prebuilt->trx,
+ prebuilt->table->name);
+ putc('\n', stderr);
if (extern_field_heap) {
mem_heap_free(
@@ -2407,8 +2427,9 @@ row_sel_get_clust_rec_for_mysql(
trx_t* trx;
*out_rec = NULL;
+ trx = thr_get_trx(thr);
- row_build_row_ref_in_tuple(prebuilt->clust_ref, sec_index, rec);
+ row_build_row_ref_in_tuple(prebuilt->clust_ref, sec_index, rec, trx);
clust_index = dict_table_get_first_index(sec_index->table);
@@ -2441,7 +2462,7 @@ row_sel_get_clust_rec_for_mysql(
fputs(" InnoDB: error clustered record"
" for sec rec not found\n"
"InnoDB: ", stderr);
- dict_index_name_print(stderr, sec_index);
+ dict_index_name_print(stderr, trx, sec_index);
fputs("\n"
"InnoDB: sec index record ", stderr);
rec_print(stderr, rec);
@@ -2449,7 +2470,7 @@ row_sel_get_clust_rec_for_mysql(
"InnoDB: clust index record ", stderr);
rec_print(stderr, clust_rec);
putc('\n', stderr);
- trx_print(stderr, thr_get_trx(thr));
+ trx_print(stderr, trx);
fputs("\n"
"InnoDB: Submit a detailed bug report to http://bugs.mysql.com\n", stderr);
@@ -2477,8 +2498,6 @@ row_sel_get_clust_rec_for_mysql(
/* This is a non-locking consistent read: if necessary, fetch
a previous version of the record */
- trx = thr_get_trx(thr);
-
old_vers = NULL;
/* If the isolation level allows reading of uncommitted data,
@@ -2800,7 +2819,7 @@ row_search_for_mysql(
rec_t* index_rec;
rec_t* clust_rec;
rec_t* old_vers;
- ulint err;
+ ulint err = DB_SUCCESS;
ibool moved;
ibool cons_read_requires_clust_rec;
ibool was_lock_wait;
@@ -2828,7 +2847,7 @@ row_search_for_mysql(
"InnoDB: Error: trying to free a corrupt\n"
"InnoDB: table handle. Magic n %lu, table name ",
(ulong) prebuilt->magic_n);
- ut_print_name(stderr, prebuilt->table->name);
+ ut_print_name(stderr, trx, prebuilt->table->name);
putc('\n', stderr);
mem_analyze_corruption((byte*)prebuilt);
@@ -3209,26 +3228,20 @@ rec_loop:
if (prebuilt->select_lock_type != LOCK_NONE
&& set_also_gap_locks) {
- /* Try to place a lock on the index record */
+ /* Try to place a lock on the index record */
- /* If innodb_locks_unsafe_for_binlog option is used,
- we lock only the record, i.e. next-key locking is
- not used.
- */
- if ( srv_locks_unsafe_for_binlog )
- {
- err = sel_set_rec_lock(rec, index,
- prebuilt->select_lock_type,
- LOCK_REC_NOT_GAP, thr);
- }
- else
+ /* If innodb_locks_unsafe_for_binlog option is used,
+ we do not lock gaps. Supremum record is really
+ a gap and therefore we do not set locks there. */
+
+ if ( srv_locks_unsafe_for_binlog == FALSE )
{
- err = sel_set_rec_lock(rec, index,
+ err = sel_set_rec_lock(rec, index,
prebuilt->select_lock_type,
LOCK_ORDINARY, thr);
}
-
- if (err != DB_SUCCESS) {
+
+ if (err != DB_SUCCESS) {
goto lock_wait_or_error;
}
@@ -3262,7 +3275,7 @@ rec_loop:
(ulong) (rec - buf_frame_align(rec)),
(ulong) next_offs,
(ulong) buf_frame_get_page_no(rec));
- dict_index_name_print(stderr, index);
+ dict_index_name_print(stderr, trx, index);
fputs(". Run CHECK TABLE. You may need to\n"
"InnoDB: restore from a backup, or dump + drop + reimport the table.\n",
stderr);
@@ -3280,7 +3293,7 @@ rec_loop:
(ulong) (rec - buf_frame_align(rec)),
(ulong) next_offs,
(ulong) buf_frame_get_page_no(rec));
- dict_index_name_print(stderr, index);
+ dict_index_name_print(stderr, trx, index);
fputs(". We try to skip the rest of the page.\n",
stderr);
@@ -3299,7 +3312,7 @@ rec_loop:
(ulong) (rec - buf_frame_align(rec)),
(ulong) next_offs,
(ulong) buf_frame_get_page_no(rec));
- dict_index_name_print(stderr, index);
+ dict_index_name_print(stderr, trx, index);
fputs(". We try to skip the record.\n",
stderr);
diff --git a/innobase/row/row0umod.c b/innobase/row/row0umod.c
index d47227166f3..e16d696314b 100644
--- a/innobase/row/row0umod.c
+++ b/innobase/row/row0umod.c
@@ -422,6 +422,7 @@ row_undo_mod_del_unmark_sec_and_undo_update(
ibool found;
big_rec_t* dummy_big_rec;
mtr_t mtr;
+ trx_t* trx = thr_get_trx(thr);
log_free_check();
mtr_start(&mtr);
@@ -431,7 +432,7 @@ row_undo_mod_del_unmark_sec_and_undo_update(
if (!found) {
fputs("InnoDB: error in sec index entry del undo in\n"
"InnoDB: ", stderr);
- dict_index_name_print(stderr, index);
+ dict_index_name_print(stderr, trx, index);
fputs("\n"
"InnoDB: tuple ", stderr);
dtuple_print(stderr, entry);
@@ -439,7 +440,7 @@ row_undo_mod_del_unmark_sec_and_undo_update(
"InnoDB: record ", stderr);
rec_print(stderr, btr_pcur_get_rec(&pcur));
putc('\n', stderr);
- trx_print(stderr, thr_get_trx(thr));
+ trx_print(stderr, trx);
fputs("\n"
"InnoDB: Submit a detailed bug report to http://bugs.mysql.com\n", stderr);
} else {
@@ -451,7 +452,7 @@ row_undo_mod_del_unmark_sec_and_undo_update(
heap = mem_heap_create(100);
update = row_upd_build_sec_rec_difference_binary(index, entry,
- btr_cur_get_rec(btr_cur), heap);
+ btr_cur_get_rec(btr_cur), trx, heap);
if (upd_get_n_fields(update) == 0) {
/* Do nothing */
@@ -671,14 +672,15 @@ row_undo_mod_parse_undo_rec(
ulint type;
ulint cmpl_info;
ibool dummy_extern;
-
+ trx_t* trx;
+
ut_ad(node && thr);
-
+ trx = thr_get_trx(thr);
ptr = trx_undo_rec_get_pars(node->undo_rec, &type, &cmpl_info,
&dummy_extern, &undo_no, &table_id);
node->rec_type = type;
- node->table = dict_table_get_on_id(table_id, thr_get_trx(thr));
+ node->table = dict_table_get_on_id(table_id, trx);
/* TODO: other fixes associated with DROP TABLE + rollback in the
same table by another user */
@@ -704,8 +706,8 @@ row_undo_mod_parse_undo_rec(
node->heap);
trx_undo_update_rec_get_update(ptr, clust_index, type, trx_id,
- roll_ptr, info_bits, node->heap,
- &(node->update));
+ roll_ptr, info_bits, trx,
+ node->heap, &(node->update));
node->new_roll_ptr = roll_ptr;
node->new_trx_id = trx_id;
node->cmpl_info = cmpl_info;
diff --git a/innobase/row/row0upd.c b/innobase/row/row0upd.c
index d35ae0a3e38..a449b9f1736 100644
--- a/innobase/row/row0upd.c
+++ b/innobase/row/row0upd.c
@@ -685,6 +685,7 @@ row_upd_build_sec_rec_difference_binary(
dict_index_t* index, /* in: index */
dtuple_t* entry, /* in: entry to insert */
rec_t* rec, /* in: secondary index record */
+ trx_t* trx, /* in: transaction */
mem_heap_t* heap) /* in: memory heap from which allocated */
{
upd_field_t* upd_field;
@@ -725,7 +726,7 @@ row_upd_build_sec_rec_difference_binary(
dfield_copy(&(upd_field->new_val), dfield);
- upd_field_set_field_no(upd_field, i, index);
+ upd_field_set_field_no(upd_field, i, index, trx);
upd_field->extern_storage = FALSE;
@@ -754,6 +755,7 @@ row_upd_build_difference_binary(
externally stored fields in entry, or NULL */
ulint n_ext_vec,/* in: number of fields in ext_vec */
rec_t* rec, /* in: clustered index record */
+ trx_t* trx, /* in: transaction */
mem_heap_t* heap) /* in: memory heap from which allocated */
{
upd_field_t* upd_field;
@@ -800,7 +802,7 @@ row_upd_build_difference_binary(
dfield_copy(&(upd_field->new_val), dfield);
- upd_field_set_field_no(upd_field, i, index);
+ upd_field_set_field_no(upd_field, i, index, trx);
if (upd_ext_vec_contains(ext_vec, n_ext_vec, i)) {
upd_field->extern_storage = TRUE;
@@ -842,6 +844,7 @@ row_upd_index_replace_new_col_vals_index_pos(
dfield_t* new_val;
ulint j;
ulint i;
+ dtype_t* cur_type;
ut_ad(index);
@@ -871,10 +874,17 @@ row_upd_index_replace_new_col_vals_index_pos(
}
if (field->prefix_len > 0
- && new_val->len != UNIV_SQL_NULL
- && new_val->len > field->prefix_len) {
+ && new_val->len != UNIV_SQL_NULL) {
- dfield->len = field->prefix_len;
+ cur_type = dict_col_get_type(
+ dict_field_get_col(field));
+
+ dfield->len =
+ dtype_get_at_most_n_mbchars(
+ cur_type,
+ field->prefix_len,
+ new_val->len,
+ new_val->data);
}
}
}
@@ -904,6 +914,7 @@ row_upd_index_replace_new_col_vals(
dfield_t* new_val;
ulint j;
ulint i;
+ dtype_t* cur_type;
ut_ad(index);
@@ -933,10 +944,17 @@ row_upd_index_replace_new_col_vals(
}
if (field->prefix_len > 0
- && new_val->len != UNIV_SQL_NULL
- && new_val->len > field->prefix_len) {
+ && new_val->len != UNIV_SQL_NULL) {
+
+ cur_type = dict_col_get_type(
+ dict_field_get_col(field));
- dfield->len = field->prefix_len;
+ dfield->len =
+ dtype_get_at_most_n_mbchars(
+ cur_type,
+ field->prefix_len,
+ new_val->len,
+ new_val->data);
}
}
}
@@ -1200,10 +1218,11 @@ row_upd_sec_index_entry(
rec_t* rec;
ulint err = DB_SUCCESS;
mtr_t mtr;
-
+ trx_t* trx = thr_get_trx(thr);
+
index = node->index;
- check_ref = row_upd_index_is_referenced(index, thr_get_trx(thr));
+ check_ref = row_upd_index_is_referenced(index, trx);
heap = mem_heap_create(1024);
@@ -1222,7 +1241,7 @@ row_upd_sec_index_entry(
if (!found) {
fputs("InnoDB: error in sec index entry update in\n"
"InnoDB: ", stderr);
- dict_index_name_print(stderr, index);
+ dict_index_name_print(stderr, trx, index);
fputs("\n"
"InnoDB: tuple ", stderr);
dtuple_print(stderr, entry);
@@ -1231,7 +1250,7 @@ row_upd_sec_index_entry(
rec_print(stderr, rec);
putc('\n', stderr);
- trx_print(stderr, thr_get_trx(thr));
+ trx_print(stderr, trx);
fputs("\n"
"InnoDB: Submit a detailed bug report to http://bugs.mysql.com\n", stderr);
diff --git a/innobase/srv/srv0srv.c b/innobase/srv/srv0srv.c
index 389cd5b779d..b8d03cfab5f 100644
--- a/innobase/srv/srv0srv.c
+++ b/innobase/srv/srv0srv.c
@@ -58,6 +58,10 @@ ulint srv_activity_count = 0;
/* The following is the maximum allowed duration of a lock wait. */
ulint srv_fatal_semaphore_wait_threshold = 600;
+/* How much data manipulation language (DML) statements need to be delayed,
+in microseconds, in order to reduce the lagging of the purge thread. */
+ulint srv_dml_needed_delay = 0;
+
ibool srv_lock_timeout_and_monitor_active = FALSE;
ibool srv_error_monitor_active = FALSE;
@@ -92,6 +96,9 @@ ulint srv_last_file_size_max = 0; /* if != 0, this tells
the max size auto-extending
may increase the last data
file size */
+ulint srv_auto_extend_increment = 8; /* If the last data file is
+ auto-extended, we add this
+ many pages to it at a time */
ulint* srv_data_file_is_raw_partition = NULL;
/* If the following is TRUE we do not allow inserts etc. This protects
@@ -242,6 +249,10 @@ merge to completion before shutdown */
ibool srv_fast_shutdown = FALSE;
+ibool srv_very_fast_shutdown = FALSE; /* if this TRUE, do not flush the
+ buffer pool to data files at the
+ shutdown; we effectively 'crash'
+ InnoDB */
/* Generate a innodb_status.<pid> file */
ibool srv_innodb_status = FALSE;
@@ -255,6 +266,8 @@ disable adaptive hash indexes */
ibool srv_use_awe = FALSE;
ibool srv_use_adaptive_hash_indexes = TRUE;
+/* Maximum allowable purge history length. <=0 means 'infinite'. */
+ulint srv_max_purge_lag = 0;
/*-------------------------------------------*/
ulint srv_n_spin_wait_rounds = 20;
@@ -938,7 +951,13 @@ retry:
trx->op_info = "sleeping before joining InnoDB queue";
- os_thread_sleep(50000);
+ /* Peter Zaitsev suggested that we take the sleep away
+ altogether. But the sleep may be good in pathological
+ situations of lots of thread switches. Simply put some
+ threads aside for a while to reduce the number of thread
+ switches. */
+
+ os_thread_sleep(10000);
trx->op_info = "";
@@ -1801,7 +1820,8 @@ srv_error_monitor_thread(
/* in: a dummy parameter required by
os_thread_create */
{
- ulint cnt = 0;
+ /* number of successive fatal timeouts observed */
+ ulint fatal_cnt = 0;
dulint old_lsn;
dulint new_lsn;
@@ -1814,8 +1834,6 @@ srv_error_monitor_thread(
loop:
srv_error_monitor_active = TRUE;
- cnt++;
-
/* Try to track a strange bug reported by Harald Fuchs and others,
where the lsn seems to decrease at times */
@@ -1842,7 +1860,20 @@ loop:
srv_refresh_innodb_monitor_stats();
}
- sync_array_print_long_waits();
+ if (sync_array_print_long_waits()) {
+ fatal_cnt++;
+ if (fatal_cnt > 5) {
+
+ fprintf(stderr,
+"InnoDB: Error: semaphore wait has lasted > %lu seconds\n"
+"InnoDB: We intentionally crash the server, because it appears to be hung.\n",
+ srv_fatal_semaphore_wait_threshold);
+
+ ut_error;
+ }
+ } else {
+ fatal_cnt = 0;
+ }
/* Flush stderr so that a database user gets the output
to possible MySQL error file */
@@ -2169,7 +2200,8 @@ loop:
/*****************************************************************/
background_loop:
/* ---- In this loop we run background operations when the server
- is quiet from user activity */
+ is quiet from user activity. Also in the case of a shutdown, we
+ loop here, flushing the buffer pool to the data files. */
/* The server has been quiet for a while: start running background
operations */
@@ -2242,7 +2274,16 @@ background_loop:
flush_loop:
srv_main_thread_op_info = "flushing buffer pool pages";
- n_pages_flushed = buf_flush_batch(BUF_FLUSH_LIST, 100, ut_dulint_max);
+
+ if (!srv_very_fast_shutdown) {
+ n_pages_flushed =
+ buf_flush_batch(BUF_FLUSH_LIST, 100, ut_dulint_max);
+ } else {
+ /* In a 'very fast' shutdown we do not flush the buffer pool
+ to data files: we set n_pages_flushed to 0 artificially. */
+
+ n_pages_flushed = 0;
+ }
srv_main_thread_op_info = "reserving kernel mutex";
@@ -2295,7 +2336,10 @@ flush_loop:
/* If we are doing a fast shutdown (= the default)
we do not do purge or insert buffer merge. But we
- flush the buffer pool completely to disk. */
+ flush the buffer pool completely to disk.
+ In a 'very fast' shutdown we do not flush the buffer
+ pool to data files: we have set n_pages_flushed to
+ 0 artificially. */
goto background_loop;
}
diff --git a/innobase/srv/srv0start.c b/innobase/srv/srv0start.c
index 4a0335086f0..9709f5235de 100644
--- a/innobase/srv/srv0start.c
+++ b/innobase/srv/srv0start.c
@@ -95,6 +95,19 @@ static char* srv_monitor_file_name;
#define SRV_N_PENDING_IOS_PER_THREAD OS_AIO_N_PENDING_IOS_PER_THREAD
#define SRV_MAX_N_PENDING_SYNC_IOS 100
+
+/* Avoid warnings when using purify */
+
+#ifdef HAVE_purify
+static int inno_bcmp(register const char *s1, register const char *s2,
+ register uint len)
+{
+ while (len-- != 0 && *s1++ == *s2++) ;
+ return len+1;
+}
+#define memcmp(A,B,C) inno_bcmp((A),(B),(C))
+#endif
+
/*************************************************************************
Reads the data files and their sizes from a character string given in
the .cnf file. */
@@ -1055,34 +1068,15 @@ innobase_start_or_create_for_mysql(void)
srv_file_flush_method_str);
return(DB_ERROR);
}
-
- /* Set the maximum number of threads which can wait for a semaphore
- inside InnoDB */
-#if defined(__WIN__) || defined(__NETWARE__)
-/* Create less event semaphores because Win 98/ME had difficulty creating
-40000 event semaphores.
-Comment from Novell, Inc.: also, these just take a lot of memory on
-NetWare. */
- srv_max_n_threads = 1000;
-#else
- if (srv_pool_size >= 8 * 1024) {
- /* Here we still have srv_pool_size counted
- in kilobytes, srv_boot converts the value to
- pages; if buffer pool is less than 8 MB,
- assume fewer threads. */
- srv_max_n_threads = 10000;
- } else {
- srv_max_n_threads = 1000; /* saves several MB of memory,
- especially in 64-bit
- computers */
- }
-#endif
/* Note that the call srv_boot() also changes the values of
srv_pool_size etc. to the units used by InnoDB internally */
/* Set the maximum number of threads which can wait for a semaphore
- inside InnoDB */
+ inside InnoDB: this is the 'sync wait array' size, as well as the
+ maximum number of threads that can wait in the 'srv_conc array' for
+ their time to enter InnoDB. */
+
#if defined(__WIN__) || defined(__NETWARE__)
/* Create less event semaphores because Win 98/ME had difficulty creating
@@ -1091,11 +1085,16 @@ Comment from Novell, Inc.: also, these just take a lot of memory on
NetWare. */
srv_max_n_threads = 1000;
#else
- if (srv_pool_size >= 8 * 1024 * 1024) {
+ if (srv_pool_size >= 1000 * 1024) {
/* Here we still have srv_pool_size counted
- in bytes, srv_boot converts the value to
- pages; if buffer pool is less than 8 MB,
+ in kilobytes (in 4.0 this was in bytes)
+ srv_boot() converts the value to
+ pages; if buffer pool is less than 1000 MB,
assume fewer threads. */
+ srv_max_n_threads = 50000;
+
+ } else if (srv_pool_size >= 8 * 1024) {
+
srv_max_n_threads = 10000;
} else {
srv_max_n_threads = 1000; /* saves several MB of memory,
@@ -1103,7 +1102,7 @@ NetWare. */
computers */
}
#endif
- err = srv_boot();
+ err = srv_boot(); /* This changes srv_pool_size to units of a page */
if (err != DB_SUCCESS) {
diff --git a/innobase/sync/sync0arr.c b/innobase/sync/sync0arr.c
index 7cd221df6a5..198ef49ca9f 100644
--- a/innobase/sync/sync0arr.c
+++ b/innobase/sync/sync0arr.c
@@ -61,10 +61,7 @@ struct sync_cell_struct {
thread */
ibool waiting; /* TRUE if the thread has already
called sync_array_event_wait
- on this cell but not yet
- sync_array_free_cell (which
- actually resets wait_object and thus
- whole cell) */
+ on this cell */
ibool event_set; /* TRUE if the event is set */
os_event_t event; /* operating system event
semaphore handle */
@@ -897,15 +894,18 @@ sync_arr_wake_threads_if_sema_free(void)
/**************************************************************************
Prints warnings of long semaphore waits to stderr. */
-void
+ibool
sync_array_print_long_waits(void)
/*=============================*/
+ /* out: TRUE if fatal semaphore wait threshold
+ was exceeded */
{
sync_cell_t* cell;
ibool old_val;
ibool noticed = FALSE;
ulint i;
ulint fatal_timeout = srv_fatal_semaphore_wait_threshold;
+ ibool fatal = FALSE;
for (i = 0; i < sync_primary_wait_array->n_cells; i++) {
@@ -922,13 +922,7 @@ sync_array_print_long_waits(void)
if (cell->wait_object != NULL
&& difftime(time(NULL), cell->reservation_time)
> fatal_timeout) {
-
- fprintf(stderr,
-"InnoDB: Error: semaphore wait has lasted > %lu seconds\n"
-"InnoDB: We intentionally crash the server, because it appears to be hung.\n",
- fatal_timeout);
-
- ut_error;
+ fatal = TRUE;
}
}
@@ -956,6 +950,8 @@ sync_array_print_long_waits(void)
fprintf(stderr,
"InnoDB: ###### Diagnostic info printed to the standard error stream\n");
}
+
+ return(fatal);
}
/**************************************************************************
diff --git a/innobase/trx/trx0purge.c b/innobase/trx/trx0purge.c
index 3d5f0d3f03a..6726d7ca609 100644
--- a/innobase/trx/trx0purge.c
+++ b/innobase/trx/trx0purge.c
@@ -295,6 +295,9 @@ trx_purge_add_update_undo_to_history(
/* Add the log as the first in the history list */
flst_add_first(rseg_header + TRX_RSEG_HISTORY,
undo_header + TRX_UNDO_HISTORY_NODE, mtr);
+ mutex_enter(&kernel_mutex);
+ trx_sys->rseg_history_len++;
+ mutex_exit(&kernel_mutex);
/* Write the trx number to the undo log header */
mlog_write_dulint(undo_header + TRX_UNDO_TRX_NO, trx->no, mtr);
@@ -386,6 +389,12 @@ loop:
flst_cut_end(rseg_hdr + TRX_RSEG_HISTORY,
log_hdr + TRX_UNDO_HISTORY_NODE, n_removed_logs, &mtr);
+
+ mutex_enter(&kernel_mutex);
+ ut_ad(trx_sys->rseg_history_len >= n_removed_logs);
+ trx_sys->rseg_history_len -= n_removed_logs;
+ mutex_exit(&kernel_mutex);
+
freed = FALSE;
while (!freed) {
@@ -470,6 +479,11 @@ loop:
}
if (cmp >= 0) {
+ mutex_enter(&kernel_mutex);
+ ut_a(trx_sys->rseg_history_len >= n_removed_logs);
+ trx_sys->rseg_history_len -= n_removed_logs;
+ mutex_exit(&kernel_mutex);
+
flst_truncate_end(rseg_hdr + TRX_RSEG_HISTORY,
log_hdr + TRX_UNDO_HISTORY_NODE,
n_removed_logs, &mtr);
@@ -1031,6 +1045,54 @@ trx_purge(void)
purge_sys->view = NULL;
mem_heap_empty(purge_sys->heap);
+ /* Determine how much data manipulation language (DML) statements
+ need to be delayed in order to reduce the lagging of the purge
+ thread. */
+ srv_dml_needed_delay = 0; /* in microseconds; default: no delay */
+
+ /* If we cannot advance the 'purge view' because of an old
+ 'consistent read view', then the DML statements cannot be delayed.
+ Also, srv_max_purge_lag <= 0 means 'infinity'. */
+ if (srv_max_purge_lag > 0
+ && !UT_LIST_GET_LAST(trx_sys->view_list)) {
+ float ratio = (float) trx_sys->rseg_history_len
+ / srv_max_purge_lag;
+ if (ratio > ULINT_MAX / 10000) {
+ /* Avoid overflow: maximum delay is 4295 seconds */
+ srv_dml_needed_delay = ULINT_MAX;
+ } else if (ratio > 1) {
+ /* If the history list length exceeds the
+ innodb_max_purge_lag, the
+ data manipulation statements are delayed
+ by at least 5000 microseconds. */
+ srv_dml_needed_delay = (ulint) ((ratio - .5) * 10000);
+ }
+ }
+
+ /* Determine how much data manipulation language (DML) statements
+ need to be delayed in order to reduce the lagging of the purge
+ thread. */
+ srv_dml_needed_delay = 0; /* in microseconds; default: no delay */
+
+ /* If we cannot advance the 'purge view' because of an old
+ 'consistent read view', then the DML statements cannot be delayed.
+ Also, srv_max_purge_lag <= 0 means 'infinity'. */
+ if (srv_max_purge_lag > 0
+ && !UT_LIST_GET_LAST(trx_sys->view_list)) {
+ float ratio = (float) trx_sys->rseg_history_len
+ / srv_max_purge_lag;
+ if (ratio > ULINT_MAX / 10000) {
+ /* Avoid overflow: maximum delay is 4295 seconds */
+ srv_dml_needed_delay = ULINT_MAX;
+ } else if (ratio > 1) {
+ /* If the history list length exceeds the
+ innodb_max_purge_lag, the
+ data manipulation statements are delayed
+ by at least 5000 microseconds. */
+ srv_dml_needed_delay = (ulint) ((ratio - .5) * 10000);
+ }
+ }
+
purge_sys->view = read_view_oldest_copy_or_open_new(NULL,
purge_sys->heap);
mutex_exit(&kernel_mutex);
diff --git a/innobase/trx/trx0rec.c b/innobase/trx/trx0rec.c
index 382f723a05c..fe429d1cc62 100644
--- a/innobase/trx/trx0rec.c
+++ b/innobase/trx/trx0rec.c
@@ -770,6 +770,7 @@ trx_undo_update_rec_get_update(
dulint trx_id, /* in: transaction id from this undo record */
dulint roll_ptr,/* in: roll pointer from this undo record */
ulint info_bits,/* in: info bits from this undo record */
+ trx_t* trx, /* in: transaction */
mem_heap_t* heap, /* in: memory heap from which the memory
needed is allocated */
upd_t** upd) /* out, own: update vector */
@@ -803,7 +804,7 @@ trx_undo_update_rec_get_update(
upd_field_set_field_no(upd_field,
dict_index_get_sys_col_pos(index, DATA_TRX_ID),
- index);
+ index, trx);
dfield_set_data(&(upd_field->new_val), buf, DATA_TRX_ID_LEN);
upd_field = upd_get_nth_field(update, n_fields + 1);
@@ -812,7 +813,7 @@ trx_undo_update_rec_get_update(
upd_field_set_field_no(upd_field,
dict_index_get_sys_col_pos(index, DATA_ROLL_PTR),
- index);
+ index, trx);
dfield_set_data(&(upd_field->new_val), buf, DATA_ROLL_PTR_LEN);
/* Store then the updated ordinary columns to the update vector */
@@ -824,13 +825,13 @@ trx_undo_update_rec_get_update(
if (field_no >= dict_index_get_n_fields(index)) {
fprintf(stderr,
"InnoDB: Error: trying to access update undo rec field %lu in ", (ulong) field_no);
- dict_index_name_print(stderr, index);
+ dict_index_name_print(stderr, trx, index);
fprintf(stderr, "\n"
"InnoDB: but index has only %lu fields\n"
"InnoDB: Submit a detailed bug report to http://bugs.mysql.com\n"
"InnoDB: Run also CHECK TABLE ",
(ulong) dict_index_get_n_fields(index));
- ut_print_name(stderr, index->table_name);
+ ut_print_name(stderr, trx, index->table_name);
fprintf(stderr, "\n"
"InnoDB: n_fields = %lu, i = %lu, ptr %p\n",
(ulong) n_fields, (ulong) i, ptr);
@@ -841,7 +842,7 @@ trx_undo_update_rec_get_update(
upd_field = upd_get_nth_field(update, i);
- upd_field_set_field_no(upd_field, field_no, index);
+ upd_field_set_field_no(upd_field, field_no, index, trx);
if (len != UNIV_SQL_NULL && len >= UNIV_EXTERN_STORAGE_FIELD) {
@@ -1257,7 +1258,7 @@ trx_undo_prev_version_build(
ibool dummy_extern;
byte* buf;
ulint err;
- ulint i;
+
#ifdef UNIV_SYNC_DEBUG
ut_ad(rw_lock_own(&(purge_sys->latch), RW_LOCK_SHARED));
#endif /* UNIV_SYNC_DEBUG */
@@ -1266,12 +1267,11 @@ trx_undo_prev_version_build(
mtr_memo_contains(index_mtr, buf_block_align(index_rec),
MTR_MEMO_PAGE_X_FIX));
if (!(index->type & DICT_CLUSTERED)) {
- fputs("InnoDB: Error: trying to access"
- " update undo rec for non-clustered ", stderr);
- dict_index_name_print(stderr, index);
- fputs("\n"
-"InnoDB: Submit a detailed bug report to http://bugs.mysql.com\n"
- "InnoDB: index record ", stderr);
+ fprintf(stderr, "InnoDB: Error: trying to access"
+ " update undo rec for non-clustered index %s\n"
+ "InnoDB: Submit a detailed bug report to"
+ " http://bugs.mysql.com\n"
+ "InnoDB: index record ", index->name);
rec_print(stderr, index_rec);
fputs("\n"
"InnoDB: record version ", stderr);
@@ -1309,32 +1309,29 @@ trx_undo_prev_version_build(
ptr = trx_undo_rec_skip_row_ref(ptr, index);
ptr = trx_undo_update_rec_get_update(ptr, index, type, trx_id,
- roll_ptr, info_bits, heap, &update);
+ roll_ptr, info_bits, NULL, heap, &update);
if (ut_dulint_cmp(table_id, index->table->id) != 0) {
ptr = NULL;
- fputs("InnoDB: Error: trying to access"
- " update undo rec for table ", stderr);
- ut_print_name(stderr, index->table_name);
- fputs("\n"
+ fprintf(stderr,
+"InnoDB: Error: trying to access update undo rec for table %s\n"
"InnoDB: but the table id in the undo record is wrong\n"
"InnoDB: Submit a detailed bug report to http://bugs.mysql.com\n"
-"InnoDB: Run also CHECK TABLE ", stderr);
- ut_print_name(stderr, index->table_name);
- putc('\n', stderr);
+"InnoDB: Run also CHECK TABLE %s\n",
+ index->table_name, index->table_name);
}
if (ptr == NULL) {
/* The record was corrupted, return an error; these printfs
should catch an elusive bug in row_vers_old_has_index_entry */
- fputs("InnoDB: ", stderr);
- dict_index_name_print(stderr, index);
- fprintf(stderr, ", n_uniq %lu\n"
+ fprintf(stderr,
+ "InnoDB: table %s, index %s, n_uniq %lu\n"
"InnoDB: undo rec address %p, type %lu cmpl_info %lu\n"
"InnoDB: undo rec table id %lu %lu, index table id %lu %lu\n"
"InnoDB: dump of 150 bytes in undo rec: ",
+ index->table_name, index->name,
(ulong) dict_index_get_n_unique(index),
undo_rec, (ulong) type, (ulong) cmpl_info,
(ulong) ut_dulint_get_high(table_id),
@@ -1366,7 +1363,18 @@ trx_undo_prev_version_build(
}
if (row_upd_changes_field_size_or_external(rec, index, update)) {
-
+ ulint* ext_vect;
+ ulint n_ext_vect;
+
+ /* We have to set the appropriate extern storage bits in the
+ old version of the record: the extern bits in rec for those
+ fields that update does NOT update, as well as the the bits for
+ those fields that update updates to become externally stored
+ fields. Store the info to ext_vect: */
+
+ ext_vect = mem_alloc(sizeof(ulint) * rec_get_n_fields(rec));
+ n_ext_vect = btr_push_update_extern_fields(ext_vect, rec,
+ update);
entry = row_rec_to_index_entry(ROW_COPY_DATA, index, rec,
heap);
row_upd_index_replace_new_col_vals(entry, index, update, heap);
@@ -1374,6 +1382,11 @@ trx_undo_prev_version_build(
buf = mem_heap_alloc(heap, rec_get_converted_size(entry));
*old_vers = rec_convert_dtuple_to_rec(buf, entry);
+
+ /* Now set the extern bits in the old version of the record */
+ rec_set_field_extern_bits(*old_vers, ext_vect, n_ext_vect,
+ NULL);
+ mem_free(ext_vect);
} else {
buf = mem_heap_alloc(heap, rec_get_size(rec));
@@ -1382,15 +1395,5 @@ trx_undo_prev_version_build(
row_upd_rec_in_place(*old_vers, update);
}
- for (i = 0; i < upd_get_n_fields(update); i++) {
-
- if (upd_get_nth_field(update, i)->extern_storage) {
-
- rec_set_nth_field_extern_bit(*old_vers,
- upd_get_nth_field(update, i)->field_no,
- TRUE, NULL);
- }
- }
-
return(DB_SUCCESS);
}
diff --git a/innobase/trx/trx0roll.c b/innobase/trx/trx0roll.c
index e65755a0f73..eb7c7f43f03 100644
--- a/innobase/trx/trx0roll.c
+++ b/innobase/trx/trx0roll.c
@@ -229,7 +229,7 @@ trx_rollback_to_savepoint_for_mysql(
if (trx->conc_state == TRX_NOT_STARTED) {
ut_print_timestamp(stderr);
fputs(" InnoDB: Error: transaction has a savepoint ", stderr);
- ut_print_name(stderr, savep->name);
+ ut_print_name(stderr, trx, savep->name);
fputs(" though it is not started\n", stderr);
return(DB_ERROR);
}
@@ -467,7 +467,7 @@ loop:
if (table) {
fputs("InnoDB: Table found: dropping table ", stderr);
- ut_print_name(stderr, table->name);
+ ut_print_name(stderr, trx, table->name);
fputs(" in recovery\n", stderr);
err = row_drop_table_for_mysql(table->name, trx, TRUE);
diff --git a/innobase/trx/trx0rseg.c b/innobase/trx/trx0rseg.c
index e3885c86def..a01d4bb835d 100644
--- a/innobase/trx/trx0rseg.c
+++ b/innobase/trx/trx0rseg.c
@@ -135,6 +135,7 @@ trx_rseg_mem_create(
trx_ulogf_t* undo_log_hdr;
fil_addr_t node_addr;
ulint sum_of_undo_sizes;
+ ulint len;
#ifdef UNIV_SYNC_DEBUG
ut_ad(mutex_own(&kernel_mutex));
@@ -166,7 +167,9 @@ trx_rseg_mem_create(
MLOG_4BYTES, mtr)
+ 1 + sum_of_undo_sizes;
- if (flst_get_len(rseg_header + TRX_RSEG_HISTORY, mtr) > 0) {
+ len = flst_get_len(rseg_header + TRX_RSEG_HISTORY, mtr);
+ if (len > 0) {
+ trx_sys->rseg_history_len += len;
node_addr = trx_purge_get_log_from_hist(
flst_get_last(rseg_header + TRX_RSEG_HISTORY,
@@ -206,6 +209,8 @@ trx_rseg_list_and_array_init(
UT_LIST_INIT(trx_sys->rseg_list);
+ trx_sys->rseg_history_len = 0;
+
for (i = 0; i < TRX_SYS_N_RSEGS; i++) {
page_no = trx_sysf_rseg_get_page_no(sys_header, i, mtr);
diff --git a/innobase/trx/trx0undo.c b/innobase/trx/trx0undo.c
index 79566fe01c3..c1edc223cbc 100644
--- a/innobase/trx/trx0undo.c
+++ b/innobase/trx/trx0undo.c
@@ -404,7 +404,7 @@ trx_undo_seg_create(
ut_print_timestamp(stderr);
fprintf(stderr,
"InnoDB: Warning: cannot find a free slot for an undo log. Do you have too\n"
-"InnoDB: many active transactions running concurrently?");
+"InnoDB: many active transactions running concurrently?\n");
return(NULL);
}
diff --git a/innobase/ut/ut0byte.c b/innobase/ut/ut0byte.c
index 8764103dc36..cc83aacc90b 100644
--- a/innobase/ut/ut0byte.c
+++ b/innobase/ut/ut0byte.c
@@ -29,51 +29,3 @@ ut_dulint_sort(dulint* arr, dulint* aux_arr, ulint low, ulint high)
UT_SORT_FUNCTION_BODY(ut_dulint_sort, arr, aux_arr, low, high,
ut_dulint_cmp);
}
-
-/****************************************************************
-Copies a string to a memory location, setting characters to lower case. */
-
-void
-ut_cpy_in_lower_case(
-/*=================*/
- char* dest, /* in: destination */
- const char* source, /* in: source */
- ulint len) /* in: string length */
-{
- ulint i;
-
- for (i = 0; i < len; i++) {
- dest[i] = tolower(source[i]);
- }
-}
-
-/****************************************************************
-Compares two strings when converted to lower case. */
-
-int
-ut_cmp_in_lower_case(
-/*=================*/
- /* out: -1, 0, 1 if str1 < str2, str1 == str2,
- str1 > str2, respectively */
- const char* str1, /* in: string1 */
- const char* str2) /* in: string2 */
-{
- for (;;) {
- int c1, c2;
- if (!*str1) {
- return(*str2 ? -1 : 0);
- } else if (!*str2) {
- return 1;
- }
- c1 = tolower(*str1++);
- c2 = tolower(*str2++);
- if (c1 < c2) {
- return(-1);
- }
- if (c1 > c2) {
- return(1);
- }
- }
-
- return(0);
-}
diff --git a/innobase/ut/ut0dbg.c b/innobase/ut/ut0dbg.c
index 2a0cfe1f13a..0f6a27d35d9 100644
--- a/innobase/ut/ut0dbg.c
+++ b/innobase/ut/ut0dbg.c
@@ -31,8 +31,9 @@ const char* ut_dbg_msg_trap =
"InnoDB: Submit a detailed bug report to http://bugs.mysql.com.\n"
"InnoDB: If you get repeated assertion failures or crashes, even\n"
"InnoDB: immediately after the mysqld startup, there may be\n"
-"InnoDB: corruption in the InnoDB tablespace. See section 6.1 of\n"
-"InnoDB: http://www.innodb.com/ibman.php about forcing recovery.\n";
+"InnoDB: corruption in the InnoDB tablespace. Please refer to\n"
+"InnoDB: http://dev.mysql.com/doc/mysql/en/Forcing_recovery.html\n"
+"InnoDB: about forcing recovery.\n";
const char* ut_dbg_msg_stop =
"InnoDB: Thread %lu stopped in file %s line %lu\n";
diff --git a/innobase/ut/ut0mem.c b/innobase/ut/ut0mem.c
index 09410e348c2..a6002d7fd83 100644
--- a/innobase/ut/ut0mem.c
+++ b/innobase/ut/ut0mem.c
@@ -313,7 +313,9 @@ ut_free_all_mem(void)
}
/**************************************************************************
-Make a quoted copy of a string. */
+Make a quoted copy of a NUL-terminated string. Leading and trailing
+quotes will not be included; only embedded quotes will be escaped.
+See also ut_strlenq() and ut_memcpyq(). */
char*
ut_strcpyq(
@@ -333,7 +335,9 @@ ut_strcpyq(
}
/**************************************************************************
-Make a quoted copy of a fixed-length string. */
+Make a quoted copy of a fixed-length string. Leading and trailing
+quotes will not be included; only embedded quotes will be escaped.
+See also ut_strlenq() and ut_strcpyq(). */
char*
ut_memcpyq(
diff --git a/innobase/ut/ut0ut.c b/innobase/ut/ut0ut.c
index 39850227162..b67be77b29e 100644
--- a/innobase/ut/ut0ut.c
+++ b/innobase/ut/ut0ut.c
@@ -16,18 +16,22 @@ Created 5/11/1994 Heikki Tuuri
#include <string.h>
#include "ut0sort.h"
+#include "trx0trx.h"
ibool ut_always_false = FALSE;
/*********************************************************************
Get the quote character to be used in SQL identifiers.
This definition must match the one in sql/ha_innodb.cc! */
-
-char
-mysql_get_identifier_quote_char(void);
-/*=================================*/
+extern
+int
+mysql_get_identifier_quote_char(
+/*============================*/
/* out: quote character to be
- used in SQL identifiers */
+ used in SQL identifiers; EOF if none */
+ trx_t* trx, /* in: transaction */
+ const char* name, /* in: name to print */
+ ulint namelen);/* in: length of name */
/************************************************************
Gets the high 32 bits in a ulint. That is makes a shift >> 32,
@@ -333,6 +337,31 @@ ut_2_power_up(
return(res);
}
+/**************************************************************************
+Outputs a NUL-terminated file name, quoted with apostrophes. */
+
+void
+ut_print_filename(
+/*==============*/
+ FILE* f, /* in: output stream */
+ const char* name) /* in: name to print */
+{
+ putc('\'', f);
+ for (;;) {
+ int c = *name++;
+ switch (c) {
+ case 0:
+ goto done;
+ case '\'':
+ putc(c, f);
+ /* fall through */
+ default:
+ putc(c, f);
+ }
+ }
+done:
+ putc('\'', f);
+}
/**************************************************************************
Outputs a NUL-terminated string, quoted as an SQL identifier. */
@@ -341,9 +370,10 @@ void
ut_print_name(
/*==========*/
FILE* f, /* in: output stream */
+ trx_t* trx, /* in: transaction */
const char* name) /* in: name to print */
{
- ut_print_namel(f, name, strlen(name));
+ ut_print_namel(f, trx, name, strlen(name));
}
/**************************************************************************
@@ -353,12 +383,17 @@ void
ut_print_namel(
/*==========*/
FILE* f, /* in: output stream */
+ trx_t* trx, /* in: transaction (NULL=no quotes) */
const char* name, /* in: name to print */
ulint namelen)/* in: length of name */
{
const char* s = name;
const char* e = s + namelen;
- char q = mysql_get_identifier_quote_char();
+ int q = mysql_get_identifier_quote_char(trx, name, namelen);
+ if (q == EOF) {
+ fwrite(name, 1, namelen, f);
+ return;
+ }
putc(q, f);
while (s < e) {
int c = *s++;