summaryrefslogtreecommitdiff
path: root/innobase
diff options
context:
space:
mode:
authorunknown <ramil@mysql.com>2005-10-24 11:36:29 +0500
committerunknown <ramil@mysql.com>2005-10-24 11:36:29 +0500
commit39af58dbd46636bf4d5bcdda56a090905f740ad7 (patch)
tree619517758503f7aaf39c2b8b7a147627ef05ce4a /innobase
parent811c6d216ec224a019dad5a99e356720677b6d22 (diff)
parentd29ecd5e91adf6eaeb4f2afef0db30648fe08065 (diff)
downloadmariadb-git-39af58dbd46636bf4d5bcdda56a090905f740ad7.tar.gz
Merge rkalimullin@bk-internal.mysql.com:/home/bk/mysql-5.0
into mysql.com:/usr/home/ram/work/5.0.b10303 mysql-test/r/query_cache.result: Auto merged mysql-test/t/query_cache.test: Auto merged sql/sql_cache.cc: Auto merged sql/sql_select.cc: Auto merged
Diffstat (limited to 'innobase')
-rw-r--r--innobase/buf/buf0buf.c4
-rw-r--r--innobase/buf/buf0flu.c4
-rw-r--r--innobase/data/data0data.c10
-rw-r--r--innobase/dict/dict0dict.c50
-rw-r--r--innobase/include/btr0btr.h10
-rw-r--r--innobase/include/data0type.ic2
-rw-r--r--innobase/include/dict0dict.h12
-rw-r--r--innobase/include/dict0mem.h14
-rw-r--r--innobase/include/mem0mem.h3
-rw-r--r--innobase/include/mem0mem.ic3
-rw-r--r--innobase/include/os0file.h11
-rw-r--r--innobase/include/page0page.ic13
-rw-r--r--innobase/include/rem0rec.h9
-rw-r--r--innobase/include/rem0rec.ic16
-rw-r--r--innobase/include/row0mysql.h16
-rw-r--r--innobase/include/trx0trx.h21
-rw-r--r--innobase/include/univ.i4
-rw-r--r--innobase/include/ut0mem.h25
-rw-r--r--innobase/mem/mem0mem.c4
-rw-r--r--innobase/os/os0file.c23
-rw-r--r--innobase/os/os0proc.c9
-rw-r--r--innobase/os/os0sync.c16
-rw-r--r--innobase/rem/rem0rec.c2
-rw-r--r--innobase/row/row0ins.c43
-rw-r--r--innobase/row/row0mysql.c34
-rw-r--r--innobase/row/row0sel.c101
-rw-r--r--innobase/row/row0upd.c12
-rw-r--r--innobase/srv/srv0start.c2
-rw-r--r--innobase/trx/trx0sys.c19
-rw-r--r--innobase/trx/trx0trx.c27
-rw-r--r--innobase/ut/ut0mem.c48
31 files changed, 444 insertions, 123 deletions
diff --git a/innobase/buf/buf0buf.c b/innobase/buf/buf0buf.c
index aa3aef7f97c..3a3b64dd51b 100644
--- a/innobase/buf/buf0buf.c
+++ b/innobase/buf/buf0buf.c
@@ -321,7 +321,9 @@ buf_page_is_corrupted(
fprintf(stderr,
" InnoDB: Error: page %lu log sequence number %lu %lu\n"
"InnoDB: is in the future! Current system log sequence number %lu %lu.\n"
-"InnoDB: Your database may be corrupt.\n",
+"InnoDB: Your database may be corrupt or you may have copied the InnoDB\n"
+"InnoDB: tablespace but not the InnoDB log files. See\n"
+"http://dev.mysql.com/doc/mysql/en/backing-up.html for more information.\n",
(ulong) mach_read_from_4(read_buf + FIL_PAGE_OFFSET),
(ulong) ut_dulint_get_high(
mach_read_from_8(read_buf + FIL_PAGE_LSN)),
diff --git a/innobase/buf/buf0flu.c b/innobase/buf/buf0flu.c
index ffb16790b2d..e39d1ae0a71 100644
--- a/innobase/buf/buf0flu.c
+++ b/innobase/buf/buf0flu.c
@@ -230,7 +230,7 @@ buf_flush_buffered_writes(void)
ulint len2;
ulint i;
- if (trx_doublewrite == NULL) {
+ if (!srv_use_doublewrite_buf || trx_doublewrite == NULL) {
os_aio_simulated_wake_handler_threads();
return;
@@ -503,7 +503,7 @@ buf_flush_write_block_low(
#endif
buf_flush_init_for_writing(block->frame, block->newest_modification,
block->space, block->offset);
- if (!trx_doublewrite) {
+ if (!srv_use_doublewrite_buf || !trx_doublewrite) {
fil_io(OS_FILE_WRITE | OS_AIO_SIMULATED_WAKE_LATER,
FALSE, block->space, block->offset, 0, UNIV_PAGE_SIZE,
(void*)block->frame, (void*)block);
diff --git a/innobase/data/data0data.c b/innobase/data/data0data.c
index 194213a04e1..19304a7a8e1 100644
--- a/innobase/data/data0data.c
+++ b/innobase/data/data0data.c
@@ -561,12 +561,12 @@ dtuple_convert_big_rec(
}
/* We do not store externally fields which are smaller than
- DICT_MAX_COL_PREFIX_LEN */
+ DICT_MAX_INDEX_COL_LEN */
- ut_a(DICT_MAX_COL_PREFIX_LEN > REC_1BYTE_OFFS_LIMIT);
+ ut_a(DICT_MAX_INDEX_COL_LEN > REC_1BYTE_OFFS_LIMIT);
if (longest < BTR_EXTERN_FIELD_REF_SIZE + 10
- + DICT_MAX_COL_PREFIX_LEN) {
+ + DICT_MAX_INDEX_COL_LEN) {
/* Cannot shorten more */
mem_heap_free(heap);
@@ -588,10 +588,10 @@ dtuple_convert_big_rec(
dfield = dtuple_get_nth_field(entry, longest_i);
vector->fields[n_fields].field_no = longest_i;
- ut_a(dfield->len > DICT_MAX_COL_PREFIX_LEN);
+ ut_a(dfield->len > DICT_MAX_INDEX_COL_LEN);
vector->fields[n_fields].len = dfield->len
- - DICT_MAX_COL_PREFIX_LEN;
+ - DICT_MAX_INDEX_COL_LEN;
vector->fields[n_fields].data = mem_heap_alloc(heap,
vector->fields[n_fields].len);
diff --git a/innobase/dict/dict0dict.c b/innobase/dict/dict0dict.c
index 9580a80e7e7..fb95ffbd80c 100644
--- a/innobase/dict/dict0dict.c
+++ b/innobase/dict/dict0dict.c
@@ -1625,7 +1625,7 @@ dict_index_add_col(
variable-length fields, so that the extern flag can be embedded in
the length word. */
- if (field->fixed_len > DICT_MAX_COL_PREFIX_LEN) {
+ if (field->fixed_len > DICT_MAX_INDEX_COL_LEN) {
field->fixed_len = 0;
}
@@ -2189,7 +2189,7 @@ 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, NULL, fk);
+ dict_print_info_on_foreign_key_in_create_format(file, NULL, fk, TRUE);
if (fk->foreign_index) {
fputs("\nThe index in the foreign key in table is ", file);
ut_print_name(file, NULL, fk->foreign_index->name);
@@ -2871,8 +2871,12 @@ dict_create_foreign_constraints_low(
table2 can be written also with the database
name before it: test.table2; the default
database is the database of parameter name */
- const char* name) /* in: table full name in the normalized form
+ const char* name, /* in: table full name in the normalized form
database_name/table_name */
+ ibool reject_fks)
+ /* in: if TRUE, fail with error code
+ DB_CANNOT_ADD_CONSTRAINT if any foreign
+ keys are found. */
{
dict_table_t* table;
dict_table_t* referenced_table;
@@ -2994,6 +2998,18 @@ loop:
}
if (*ptr == '\0') {
+ /* The proper way to reject foreign keys for temporary
+ tables would be to split the lexing and syntactical
+ analysis of foreign key clauses from the actual adding
+ of them, so that ha_innodb.cc could first parse the SQL
+ command, determine if there are any foreign keys, and
+ if so, immediately reject the command if the table is a
+ temporary one. For now, this kludge will work. */
+ if (reject_fks && (UT_LIST_GET_LEN(table->foreign_list) > 0))
+ {
+ return DB_CANNOT_ADD_CONSTRAINT;
+ }
+
/**********************************************************/
/* The following call adds the foreign key constraints
to the data dictionary system tables on disk */
@@ -3417,9 +3433,12 @@ dict_create_foreign_constraints(
name before it: test.table2; the
default database id the database of
parameter name */
- const char* name) /* in: table full name in the
+ const char* name, /* in: table full name in the
normalized form
database_name/table_name */
+ ibool reject_fks) /* in: if TRUE, fail with error
+ code DB_CANNOT_ADD_CONSTRAINT if
+ any foreign keys are found. */
{
char* str;
ulint err;
@@ -3428,7 +3447,8 @@ dict_create_foreign_constraints(
str = dict_strip_comments(sql_string);
heap = mem_heap_create(10000);
- err = dict_create_foreign_constraints_low(trx, heap, str, name);
+ err = dict_create_foreign_constraints_low(trx, heap, str, name,
+ reject_fks);
mem_heap_free(heap);
mem_free(str);
@@ -4310,9 +4330,10 @@ CREATE TABLE. */
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 */
+ FILE* file, /* in: file where to print */
+ trx_t* trx, /* in: transaction */
+ dict_foreign_t* foreign, /* in: foreign key constraint */
+ ibool add_newline) /* in: whether to add a newline */
{
const char* stripped_id;
ulint i;
@@ -4325,7 +4346,16 @@ dict_print_info_on_foreign_key_in_create_format(
stripped_id = foreign->id;
}
- fputs(",\n CONSTRAINT ", file);
+ putc(',', file);
+
+ if (add_newline) {
+ /* SHOW CREATE TABLE wants constraints each printed nicely
+ on its own line, while error messages want no newlines
+ inserted. */
+ fputs("\n ", file);
+ }
+
+ fputs(" CONSTRAINT ", file);
ut_print_name(file, trx, stripped_id);
fputs(" FOREIGN KEY (", file);
@@ -4427,7 +4457,7 @@ dict_print_info_on_foreign_keys(
while (foreign != NULL) {
if (create_table_format) {
dict_print_info_on_foreign_key_in_create_format(
- file, trx, foreign);
+ file, trx, foreign, TRUE);
} else {
ulint i;
fputs("; (", file);
diff --git a/innobase/include/btr0btr.h b/innobase/include/btr0btr.h
index 1f3a32fa70c..d28b0b129a1 100644
--- a/innobase/include/btr0btr.h
+++ b/innobase/include/btr0btr.h
@@ -23,16 +23,6 @@ special big record storage structure */
#define BTR_PAGE_MAX_REC_SIZE (UNIV_PAGE_SIZE / 2 - 200)
-/* Maximum key size in a B-tree: the records on non-leaf levels must be
-shorter than this */
-
-#define BTR_PAGE_MAX_KEY_SIZE 1024
-
-/* If data in page drops below this limit, we try to compress it.
-NOTE! The value has to be > 2 * BTR_MAX_KEY_SIZE */
-
-#define BTR_COMPRESS_LIMIT (UNIV_PAGE_SIZE / 4 + 1);
-
/* Latching modes for the search function (in btr0cur.*) */
#define BTR_SEARCH_LEAF RW_S_LATCH
#define BTR_MODIFY_LEAF RW_X_LATCH
diff --git a/innobase/include/data0type.ic b/innobase/include/data0type.ic
index 06d45dd5501..d4a7b3c64b8 100644
--- a/innobase/include/data0type.ic
+++ b/innobase/include/data0type.ic
@@ -420,7 +420,7 @@ dtype_get_fixed_size(
}
/***************************************************************************
-Returns the size of a fixed size data type, 0 if not a fixed size type. */
+Returns the minimum size of a data type. */
UNIV_INLINE
ulint
dtype_get_min_size(
diff --git a/innobase/include/dict0dict.h b/innobase/include/dict0dict.h
index d9cda402bac..5215d51cabe 100644
--- a/innobase/include/dict0dict.h
+++ b/innobase/include/dict0dict.h
@@ -228,9 +228,12 @@ dict_create_foreign_constraints(
name before it: test.table2; the
default database id the database of
parameter name */
- const char* name); /* in: table full name in the
+ const char* name, /* in: table full name in the
normalized form
database_name/table_name */
+ ibool reject_fks); /* in: if TRUE, fail with error
+ code DB_CANNOT_ADD_CONSTRAINT if
+ any foreign keys are found. */
/**************************************************************************
Parses the CONSTRAINT id's to be dropped in an ALTER TABLE statement. */
@@ -372,9 +375,10 @@ CREATE TABLE. */
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 */
+ FILE* file, /* in: file where to print */
+ trx_t* trx, /* in: transaction */
+ dict_foreign_t* foreign, /* in: foreign key constraint */
+ ibool add_newline); /* in: whether to add a newline */
/************************************************************************
Displays the names of the index and the table. */
void
diff --git a/innobase/include/dict0mem.h b/innobase/include/dict0mem.h
index ff6c4ec9b28..7eec86d0bcb 100644
--- a/innobase/include/dict0mem.h
+++ b/innobase/include/dict0mem.h
@@ -152,12 +152,12 @@ struct dict_col_struct{
in some of the functions below */
};
-/* 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. */
+/* DICT_MAX_INDEX_COL_LEN is measured in bytes and is the max index column
+length + 1. Starting from 4.1.6, we set it 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
+#define DICT_MAX_INDEX_COL_LEN 768
/* Data structure for a field in an index */
struct dict_field_struct{
@@ -169,12 +169,12 @@ struct dict_field_struct{
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
+ DICT_MAX_INDEX_COL_LEN; NOTE that
in the UTF-8 charset, MySQL sets this
to 3 * the prefix len in UTF-8 chars */
ulint fixed_len; /* 0 or the fixed length of the
column if smaller than
- DICT_MAX_COL_PREFIX_LEN */
+ DICT_MAX_INDEX_COL_LEN */
ulint fixed_offs; /* offset to the field, or
ULINT_UNDEFINED if it is not fixed
within the record (due to preceding
diff --git a/innobase/include/mem0mem.h b/innobase/include/mem0mem.h
index 87afdb8f91c..3768e93c03e 100644
--- a/innobase/include/mem0mem.h
+++ b/innobase/include/mem0mem.h
@@ -99,8 +99,7 @@ heap freeing. */
/*********************************************************************
NOTE: Use the corresponding macros instead of this function. Creates a
memory heap which allocates memory from dynamic space. For debugging
-purposes, takes also the file name and line as argument in the debug
-version. */
+purposes, takes also the file name and line as argument. */
UNIV_INLINE
mem_heap_t*
mem_heap_create_func(
diff --git a/innobase/include/mem0mem.ic b/innobase/include/mem0mem.ic
index 8c87c884d78..28562f7c9f8 100644
--- a/innobase/include/mem0mem.ic
+++ b/innobase/include/mem0mem.ic
@@ -371,8 +371,7 @@ mem_heap_free_top(
/*********************************************************************
NOTE: Use the corresponding macros instead of this function. Creates a
memory heap which allocates memory from dynamic space. For debugging
-purposes, takes also the file name and line as argument in the debug
-version. */
+purposes, takes also the file name and line as argument. */
UNIV_INLINE
mem_heap_t*
mem_heap_create_func(
diff --git a/innobase/include/os0file.h b/innobase/include/os0file.h
index adbc4afafd2..224fd59a76b 100644
--- a/innobase/include/os0file.h
+++ b/innobase/include/os0file.h
@@ -432,6 +432,17 @@ os_file_read(
offset */
ulint n); /* in: number of bytes to read */
/***********************************************************************
+Rewind file to its start, read at most size - 1 bytes from it to str, and
+NUL-terminate str. All errors are silently ignored. This function is
+mostly meant to be used with temporary files. */
+
+void
+os_file_read_string(
+/*================*/
+ FILE* file, /* in: file to read from */
+ char* str, /* in: buffer where to read */
+ ulint size); /* in: size of buffer */
+/***********************************************************************
Requests a synchronous positioned read operation. This function does not do
any error handling. In case of error it returns FALSE. */
diff --git a/innobase/include/page0page.ic b/innobase/include/page0page.ic
index fd5281fdbec..655ff245aa8 100644
--- a/innobase/include/page0page.ic
+++ b/innobase/include/page0page.ic
@@ -175,6 +175,19 @@ page_rec_is_comp(
/* out: nonzero if in compact format */
const rec_t* rec) /* in: record */
{
+#ifdef UNIV_RELEASE_NOT_YET_STABLE
+ if (UNIV_UNLIKELY((ulint)rec < (ulint)(buf_pool->frame_zero))
+ || UNIV_UNLIKELY((ulint)rec >= (ulint)(buf_pool->high_end))) {
+
+ ut_print_timestamp(stderr);
+ fprintf(stderr,
+"InnoDB: Error: trying to read a stray page rec %p\n"
+"InnoDB: buf pool start is at %p, end at %p\n",
+ rec, buf_pool->frame_zero,
+ buf_pool->high_end);
+ ut_error;
+ }
+#endif
return(page_is_comp(ut_align_down((rec_t*) rec, UNIV_PAGE_SIZE)));
}
diff --git a/innobase/include/rem0rec.h b/innobase/include/rem0rec.h
index 1d15b8d1c77..69b397c9682 100644
--- a/innobase/include/rem0rec.h
+++ b/innobase/include/rem0rec.h
@@ -312,6 +312,15 @@ rec_offs_nth_extern(
const ulint* offsets,/* in: array returned by rec_get_offsets() */
ulint n); /* in: nth field */
/**********************************************************
+Returns nonzero if the SQL NULL bit is set in nth field of rec. */
+UNIV_INLINE
+ulint
+rec_offs_nth_sql_null(
+/*==================*/
+ /* out: nonzero if SQL NULL */
+ const ulint* offsets,/* in: array returned by rec_get_offsets() */
+ ulint n); /* in: nth field */
+/**********************************************************
Gets the physical size of a field. */
UNIV_INLINE
ulint
diff --git a/innobase/include/rem0rec.ic b/innobase/include/rem0rec.ic
index e2dceb6bae5..9c24f385f4f 100644
--- a/innobase/include/rem0rec.ic
+++ b/innobase/include/rem0rec.ic
@@ -955,6 +955,22 @@ rec_offs_nth_extern(
}
/**********************************************************
+Returns nonzero if the SQL NULL bit is set in nth field of rec. */
+UNIV_INLINE
+ulint
+rec_offs_nth_sql_null(
+/*==================*/
+ /* out: nonzero if SQL NULL */
+ const ulint* offsets,/* in: array returned by rec_get_offsets() */
+ ulint n) /* in: nth field */
+{
+ ut_ad(rec_offs_validate(NULL, NULL, offsets));
+ ut_ad(n < rec_offs_n_fields(offsets));
+ return(UNIV_UNLIKELY(rec_offs_base(offsets)[1 + n]
+ & REC_OFFS_SQL_NULL));
+}
+
+/**********************************************************
Gets the physical size of a field. */
UNIV_INLINE
ulint
diff --git a/innobase/include/row0mysql.h b/innobase/include/row0mysql.h
index 4e6ff73b0f8..b5da4634d98 100644
--- a/innobase/include/row0mysql.h
+++ b/innobase/include/row0mysql.h
@@ -335,8 +335,14 @@ int
row_create_index_for_mysql(
/*=======================*/
/* out: error number or DB_SUCCESS */
- dict_index_t* index, /* in: index defintion */
- trx_t* trx); /* in: transaction handle */
+ dict_index_t* index, /* in: index definition */
+ trx_t* trx, /* in: transaction handle */
+ const ulint* field_lengths); /* in: if not NULL, must contain
+ dict_index_get_n_fields(index)
+ actual field lengths for the
+ index columns, which are
+ then checked for not being too
+ large. */
/*************************************************************************
Scans a table create SQL string and adds to the data dictionary
the foreign key constraints declared in the string. This function
@@ -355,9 +361,13 @@ row_table_add_foreign_constraints(
FOREIGN KEY (a, b) REFERENCES table2(c, d),
table2 can be written also with the
database name before it: test.table2 */
- const char* name); /* in: table full name in the
+ const char* name, /* in: table full name in the
normalized form
database_name/table_name */
+ ibool reject_fks); /* in: if TRUE, fail with error
+ code DB_CANNOT_ADD_CONSTRAINT if
+ any foreign keys are found. */
+
/*************************************************************************
The master thread in srv0srv.c calls this regularly to drop tables which
we must drop in background after queries to them have ended. Such lazy
diff --git a/innobase/include/trx0trx.h b/innobase/include/trx0trx.h
index 5dbf003594f..0dc82893ad1 100644
--- a/innobase/include/trx0trx.h
+++ b/innobase/include/trx0trx.h
@@ -56,6 +56,22 @@ void
trx_search_latch_release_if_reserved(
/*=================================*/
trx_t* trx); /* in: transaction */
+/**********************************************************************
+Set detailed error message for the transaction. */
+void
+trx_set_detailed_error(
+/*===================*/
+ trx_t* trx, /* in: transaction struct */
+ const char* msg); /* in: detailed error message */
+/*****************************************************************
+Set detailed error message for the transaction from a file. Note that the
+file is rewinded before reading from it. */
+
+void
+trx_set_detailed_error_from_file(
+/*=============================*/
+ trx_t* trx, /* in: transaction struct */
+ FILE* file); /* in: file to read message from */
/********************************************************************
Retrieves the error_info field from a trx. */
@@ -205,7 +221,7 @@ trx_recover_for_mysql(
XID* xid_list, /* in/out: prepared transactions */
ulint len); /* in: number of slots in xid_list */
/***********************************************************************
-This function is used to commit one X/Open XA distributed transaction
+This function is used to find one X/Open XA distributed transaction
which is in the prepared state */
trx_t *
trx_get_trx_by_xid(
@@ -649,6 +665,9 @@ struct trx_struct{
trx_undo_arr_t* undo_no_arr; /* array of undo numbers of undo log
records which are currently processed
by a rollback operation */
+ /*------------------------------*/
+ char detailed_error[256]; /* detailed error message for last
+ error, or empty. */
};
#define TRX_MAX_N_THREADS 32 /* maximum number of concurrent
diff --git a/innobase/include/univ.i b/innobase/include/univ.i
index 6849dcd9c51..15650f22ed8 100644
--- a/innobase/include/univ.i
+++ b/innobase/include/univ.i
@@ -80,6 +80,10 @@ memory is read outside the allocated blocks. */
/* Make a non-inline debug version */
+/* You can remove this define when the release is stable. This define adds
+some consistency checks to code. They use a little CPU time. */
+#define UNIV_RELEASE_NOT_YET_STABLE
+
/*
#define UNIV_DEBUG
#define UNIV_MEM_DEBUG
diff --git a/innobase/include/ut0mem.h b/innobase/include/ut0mem.h
index 74357f6bf13..b9bbe0b5c92 100644
--- a/innobase/include/ut0mem.h
+++ b/innobase/include/ut0mem.h
@@ -119,6 +119,31 @@ int
ut_strcmp(const void* str1, const void* str2);
/**************************************************************************
+Copies up to size - 1 characters from the NUL-terminated string src to
+dst, NUL-terminating the result. Returns strlen(src), so truncation
+occurred if the return value >= size. */
+
+ulint
+ut_strlcpy(
+/*=======*/
+ /* out: strlen(src) */
+ char* dst, /* in: destination buffer */
+ const char* src, /* in: source buffer */
+ ulint size); /* in: size of destination buffer */
+
+/**************************************************************************
+Like ut_strlcpy, but if src doesn't fit in dst completely, copies the last
+(size - 1) bytes of src, not the first. */
+
+ulint
+ut_strlcpy_rev(
+/*===========*/
+ /* out: strlen(src) */
+ char* dst, /* in: destination buffer */
+ const char* src, /* in: source buffer */
+ ulint size); /* in: size of destination buffer */
+
+/**************************************************************************
Compute strlen(ut_strcpyq(str, q)). */
UNIV_INLINE
ulint
diff --git a/innobase/mem/mem0mem.c b/innobase/mem/mem0mem.c
index 85f0119d02a..daf78008d45 100644
--- a/innobase/mem/mem0mem.c
+++ b/innobase/mem/mem0mem.c
@@ -187,9 +187,7 @@ mem_heap_create_block(
}
block->magic_n = MEM_BLOCK_MAGIC_N;
- ut_memcpy(&(block->file_name), file_name + ut_strlen(file_name) - 7,
- 7);
- block->file_name[7]='\0';
+ ut_strlcpy_rev(block->file_name, file_name, sizeof(block->file_name));
block->line = line;
#ifdef MEM_PERIODIC_CHECK
diff --git a/innobase/os/os0file.c b/innobase/os/os0file.c
index 9c87b59f018..20a3303d12d 100644
--- a/innobase/os/os0file.c
+++ b/innobase/os/os0file.c
@@ -2249,6 +2249,29 @@ error_handling:
}
/***********************************************************************
+Rewind file to its start, read at most size - 1 bytes from it to str, and
+NUL-terminate str. All errors are silently ignored. This function is
+mostly meant to be used with temporary files. */
+
+void
+os_file_read_string(
+/*================*/
+ FILE* file, /* in: file to read from */
+ char* str, /* in: buffer where to read */
+ ulint size) /* in: size of buffer */
+{
+ size_t flen;
+
+ if (size == 0) {
+ return;
+ }
+
+ rewind(file);
+ flen = fread(str, 1, size - 1, file);
+ str[flen] = '\0';
+}
+
+/***********************************************************************
Requests a synchronous write operation. */
ibool
diff --git a/innobase/os/os0proc.c b/innobase/os/os0proc.c
index 167aed93de7..24bb007e504 100644
--- a/innobase/os/os0proc.c
+++ b/innobase/os/os0proc.c
@@ -292,6 +292,9 @@ os_awe_allocate_physical_mem(
return(TRUE);
#else
+ UT_NOT_USED(n_megabytes);
+ UT_NOT_USED(page_info);
+
return(FALSE);
#endif
}
@@ -349,6 +352,8 @@ os_awe_allocate_virtual_mem_window(
return(ptr);
#else
+ UT_NOT_USED(size);
+
return(NULL);
#endif
}
@@ -476,6 +481,10 @@ os_awe_map_physical_mem_to_window(
return(TRUE);
#else
+ UT_NOT_USED(ptr);
+ UT_NOT_USED(n_mem_pages);
+ UT_NOT_USED(page_info);
+
return(FALSE);
#endif
}
diff --git a/innobase/os/os0sync.c b/innobase/os/os0sync.c
index 356d7c8c163..487e8f40a39 100644
--- a/innobase/os/os0sync.c
+++ b/innobase/os/os0sync.c
@@ -631,7 +631,21 @@ os_fast_mutex_free(
DeleteCriticalSection((LPCRITICAL_SECTION) fast_mutex);
#else
- ut_a(0 == pthread_mutex_destroy(fast_mutex));
+ int ret;
+
+ ret = pthread_mutex_destroy(fast_mutex);
+
+ if (ret != 0) {
+ ut_print_timestamp(stderr);
+ fprintf(stderr,
+" InnoDB: error: return value %lu when calling\n"
+"InnoDB: pthread_mutex_destroy().\n", (ulint)ret);
+ fprintf(stderr,
+"InnoDB: Byte contents of the pthread mutex at %p:\n", fast_mutex);
+ ut_print_buf(stderr, (const byte*)fast_mutex,
+ sizeof(os_fast_mutex_t));
+ fprintf(stderr, "\n");
+ }
#endif
if (os_sync_mutex_inited) {
/* When freeing the last mutexes, we have
diff --git a/innobase/rem/rem0rec.c b/innobase/rem/rem0rec.c
index fbc33aea669..9480c978755 100644
--- a/innobase/rem/rem0rec.c
+++ b/innobase/rem/rem0rec.c
@@ -621,7 +621,7 @@ rec_set_nth_field_extern_bit_new(
if (field->fixed_len) {
/* fixed-length fields cannot be external
(Fixed-length fields longer than
- DICT_MAX_COL_PREFIX_LEN will be treated as
+ DICT_MAX_INDEX_COL_LEN will be treated as
variable-length ones in dict_index_add_col().) */
ut_ad(i != ith);
continue;
diff --git a/innobase/row/row0ins.c b/innobase/row/row0ins.c
index 75d8117a73e..5e833372299 100644
--- a/innobase/row/row0ins.c
+++ b/innobase/row/row0ins.c
@@ -579,6 +579,32 @@ row_ins_cascade_calc_update_vec(
}
/*************************************************************************
+Set detailed error message associated with foreign key errors for
+the given transaction. */
+static
+void
+row_ins_set_detailed(
+/*=================*/
+ trx_t* trx, /* in: transaction */
+ dict_foreign_t* foreign) /* in: foreign key constraint */
+{
+
+ FILE* tf = os_file_create_tmpfile();
+
+ if (tf) {
+ ut_print_name(tf, trx, foreign->foreign_table_name);
+ dict_print_info_on_foreign_key_in_create_format(tf, trx,
+ foreign, FALSE);
+
+ trx_set_detailed_error_from_file(trx, tf);
+
+ fclose(tf);
+ } else {
+ trx_set_detailed_error(trx, "temp file creation failed");
+ }
+}
+
+/*************************************************************************
Reports a foreign key error associated with an update or a delete of a
parent table index entry. */
static
@@ -598,6 +624,8 @@ row_ins_foreign_report_err(
FILE* ef = dict_foreign_err_file;
trx_t* trx = thr_get_trx(thr);
+ row_ins_set_detailed(trx, foreign);
+
mutex_enter(&dict_foreign_err_mutex);
rewind(ef);
ut_print_timestamp(ef);
@@ -607,7 +635,8 @@ row_ins_foreign_report_err(
fputs("Foreign key constraint fails for table ", ef);
ut_print_name(ef, trx, foreign->foreign_table_name);
fputs(":\n", ef);
- dict_print_info_on_foreign_key_in_create_format(ef, trx, foreign);
+ dict_print_info_on_foreign_key_in_create_format(ef, trx, foreign,
+ TRUE);
putc('\n', ef);
fputs(errstr, ef);
fputs(" in parent table, in index ", ef);
@@ -648,7 +677,9 @@ row_ins_foreign_report_add_err(
child table */
{
FILE* ef = dict_foreign_err_file;
-
+
+ row_ins_set_detailed(trx, foreign);
+
mutex_enter(&dict_foreign_err_mutex);
rewind(ef);
ut_print_timestamp(ef);
@@ -657,7 +688,8 @@ row_ins_foreign_report_add_err(
fputs("Foreign key constraint fails for table ", ef);
ut_print_name(ef, trx, foreign->foreign_table_name);
fputs(":\n", ef);
- dict_print_info_on_foreign_key_in_create_format(ef, trx, foreign);
+ dict_print_info_on_foreign_key_in_create_format(ef, trx, foreign,
+ TRUE);
fputs("\nTrying to add in child table, in index ", ef);
ut_print_name(ef, trx, foreign->foreign_index->name);
if (entry) {
@@ -1224,6 +1256,9 @@ run_again:
if (check_table == NULL || check_table->ibd_file_missing) {
if (check_ref) {
FILE* ef = dict_foreign_err_file;
+
+ row_ins_set_detailed(trx, foreign);
+
mutex_enter(&dict_foreign_err_mutex);
rewind(ef);
ut_print_timestamp(ef);
@@ -1233,7 +1268,7 @@ run_again:
ut_print_name(ef, trx, foreign->foreign_table_name);
fputs(":\n", ef);
dict_print_info_on_foreign_key_in_create_format(ef,
- trx, foreign);
+ trx, foreign, TRUE);
fputs("\nTrying to add to index ", ef);
ut_print_name(ef, trx, foreign->foreign_index->name);
fputs(" tuple:\n", ef);
diff --git a/innobase/row/row0mysql.c b/innobase/row/row0mysql.c
index 2ac0824b331..82f7daf2ed8 100644
--- a/innobase/row/row0mysql.c
+++ b/innobase/row/row0mysql.c
@@ -513,14 +513,15 @@ handle_new_error:
return(TRUE);
- } else if (err == DB_DEADLOCK || err == DB_LOCK_WAIT_TIMEOUT
+ } else if (err == DB_DEADLOCK
|| err == DB_LOCK_TABLE_FULL) {
/* Roll back the whole transaction; this resolution was added
to version 3.23.43 */
trx_general_rollback_for_mysql(trx, FALSE, NULL);
- } else if (err == DB_OUT_OF_FILE_SPACE) {
+ } else if (err == DB_OUT_OF_FILE_SPACE
+ || err == DB_LOCK_WAIT_TIMEOUT) {
if (savept) {
/* Roll back the latest, possibly incomplete
insertion or update */
@@ -1972,13 +1973,20 @@ row_create_index_for_mysql(
/*=======================*/
/* out: error number or DB_SUCCESS */
dict_index_t* index, /* in: index definition */
- trx_t* trx) /* in: transaction handle */
+ trx_t* trx, /* in: transaction handle */
+ const ulint* field_lengths) /* in: if not NULL, must contain
+ dict_index_get_n_fields(index)
+ actual field lengths for the
+ index columns, which are
+ then checked for not being too
+ large. */
{
ind_node_t* node;
mem_heap_t* heap;
que_thr_t* thr;
ulint err;
ulint i, j;
+ ulint len;
#ifdef UNIV_SYNC_DEBUG
ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
@@ -2017,10 +2025,16 @@ row_create_index_for_mysql(
}
}
- /* Check also that prefix_len < DICT_MAX_COL_PREFIX_LEN */
+ /* Check also that prefix_len and actual length
+ < DICT_MAX_INDEX_COL_LEN */
+
+ len = dict_index_get_nth_field(index, i)->prefix_len;
- if (dict_index_get_nth_field(index, i)->prefix_len
- >= DICT_MAX_COL_PREFIX_LEN) {
+ if (field_lengths) {
+ len = ut_max(len, field_lengths[i]);
+ }
+
+ if (len >= DICT_MAX_INDEX_COL_LEN) {
err = DB_TOO_BIG_RECORD;
goto error_handling;
@@ -2087,9 +2101,12 @@ row_table_add_foreign_constraints(
FOREIGN KEY (a, b) REFERENCES table2(c, d),
table2 can be written also with the
database name before it: test.table2 */
- const char* name) /* in: table full name in the
+ const char* name, /* in: table full name in the
normalized form
database_name/table_name */
+ ibool reject_fks) /* in: if TRUE, fail with error
+ code DB_CANNOT_ADD_CONSTRAINT if
+ any foreign keys are found. */
{
ulint err;
@@ -2110,7 +2127,8 @@ row_table_add_foreign_constraints(
trx->dict_operation = TRUE;
- err = dict_create_foreign_constraints(trx, sql_string, name);
+ err = dict_create_foreign_constraints(trx, sql_string, name,
+ reject_fks);
if (err == DB_SUCCESS) {
/* Check that also referencing constraints are ok */
diff --git a/innobase/row/row0sel.c b/innobase/row/row0sel.c
index a77010d939b..1b66f14f5d7 100644
--- a/innobase/row/row0sel.c
+++ b/innobase/row/row0sel.c
@@ -2724,7 +2724,9 @@ row_sel_get_clust_rec_for_mysql(
if (trx->isolation_level > TRX_ISO_READ_UNCOMMITTED
&& !lock_clust_rec_cons_read_sees(clust_rec, clust_index,
*offsets, trx->read_view)) {
-
+
+ /* The following call returns 'offsets' associated with
+ 'old_vers' */
err = row_sel_build_prev_vers_for_mysql(
trx->read_view, clust_index,
prebuilt, clust_rec,
@@ -3055,13 +3057,14 @@ row_search_for_mysql(
cursor 'direction' should be 0. */
{
dict_index_t* index = prebuilt->index;
+ ibool comp = index->table->comp;
dtuple_t* search_tuple = prebuilt->search_tuple;
btr_pcur_t* pcur = prebuilt->pcur;
trx_t* trx = prebuilt->trx;
dict_index_t* clust_index;
que_thr_t* thr;
rec_t* rec;
- rec_t* index_rec;
+ rec_t* result_rec;
rec_t* clust_rec;
rec_t* old_vers;
ulint err = DB_SUCCESS;
@@ -3491,7 +3494,7 @@ rec_loop:
/* PHASE 4: Look for matching records in a loop */
rec = btr_pcur_get_rec(pcur);
- ut_ad(!!page_rec_is_comp(rec) == index->table->comp);
+ ut_ad(!!page_rec_is_comp(rec) == comp);
#ifdef UNIV_SEARCH_DEBUG
/*
fputs("Using ", stderr);
@@ -3544,19 +3547,23 @@ rec_loop:
/* Do sanity checks in case our cursor has bumped into page
corruption */
- if (page_rec_is_comp(rec)) {
+ if (comp) {
next_offs = rec_get_next_offs(rec, TRUE);
if (UNIV_UNLIKELY(next_offs < PAGE_NEW_SUPREMUM)) {
+
goto wrong_offs;
}
} else {
next_offs = rec_get_next_offs(rec, FALSE);
if (UNIV_UNLIKELY(next_offs < PAGE_OLD_SUPREMUM)) {
+
goto wrong_offs;
}
}
+
if (UNIV_UNLIKELY(next_offs >= UNIV_PAGE_SIZE - PAGE_DIR)) {
- wrong_offs:
+
+wrong_offs:
if (srv_force_recovery == 0 || moves_up == FALSE) {
ut_print_timestamp(stderr);
buf_page_print(buf_frame_align(rec));
@@ -3599,6 +3606,9 @@ rec_loop:
goto next_rec;
}
}
+ /*-------------------------------------------------------------*/
+
+ /* Calculate the 'offsets' associated with 'rec' */
offsets = rec_get_offsets(rec, index, offsets, ULINT_UNDEFINED, &heap);
@@ -3619,8 +3629,6 @@ rec_loop:
}
}
- /*-------------------------------------------------------------*/
-
/* Note that we cannot trust the up_match value in the cursor at this
place because we can arrive here after moving the cursor! Thus
we have to recompare rec and search_tuple to determine if they
@@ -3711,7 +3719,7 @@ rec_loop:
if (!set_also_gap_locks
|| srv_locks_unsafe_for_binlog
|| (unique_search && !UNIV_UNLIKELY(rec_get_deleted_flag(
- rec, page_rec_is_comp(rec))))) {
+ rec, comp)))) {
goto no_gap_lock;
} else {
@@ -3767,6 +3775,8 @@ no_gap_lock:
&& !lock_clust_rec_cons_read_sees(rec, index,
offsets, trx->read_view)) {
+ /* The following call returns 'offsets'
+ associated with 'old_vers' */
err = row_sel_build_prev_vers_for_mysql(
trx->read_view, clust_index,
prebuilt, rec,
@@ -3795,19 +3805,20 @@ no_gap_lock:
is necessary, because we can only get the undo
information via the clustered index record. */
- /* Get the clustered index record if needed */
- index_rec = rec;
ut_ad(index != clust_index);
goto requires_clust_rec;
}
}
- if (UNIV_UNLIKELY(rec_get_deleted_flag(rec, page_rec_is_comp(rec)))) {
+ /* NOTE that at this point rec can be an old version of a clustered
+ index record built for a consistent read. We cannot assume after this
+ point that rec is on a buffer pool page. Functions like
+ page_rec_is_comp() cannot be used! */
- /* The record is delete-marked: we can skip it if this is
- not a consistent read which might see an earlier version
- of a non-clustered index record */
+ if (UNIV_UNLIKELY(rec_get_deleted_flag(rec, comp))) {
+
+ /* The record is delete-marked: we can skip it */
if (srv_locks_unsafe_for_binlog
&& prebuilt->select_lock_type != LOCK_NONE) {
@@ -3823,25 +3834,26 @@ no_gap_lock:
goto next_rec;
}
- /* Get the clustered index record if needed and if we did
- not do the search using the clustered index */
-
- index_rec = rec;
+ /* Get the clustered index record if needed, if we did not do the
+ search using the clustered index. */
if (index != clust_index && prebuilt->need_to_access_clustered) {
requires_clust_rec:
- /* Before and after this "if" block, "offsets" will be
- related to "rec", which may be in a secondary index "index" or
- the clustered index ("clust_index"). However, after this
- "if" block, "rec" may be pointing to
- "clust_rec" of "clust_index". */
+ /* We use a 'goto' to the preceding label if a consistent
+ read of a secondary index record requires us to look up old
+ versions of the associated clustered index record. */
+
ut_ad(rec_offs_validate(rec, index, offsets));
/* It was a non-clustered index and we must fetch also the
clustered index record */
mtr_has_extra_clust_latch = TRUE;
+
+ /* The following call returns 'offsets' associated with
+ 'clust_rec'. Note that 'clust_rec' can be an old version
+ built for a consistent read. */
err = row_sel_get_clust_rec_for_mysql(prebuilt, index, rec,
thr, &clust_rec,
@@ -3858,8 +3870,7 @@ requires_clust_rec:
goto next_rec;
}
- if (UNIV_UNLIKELY(rec_get_deleted_flag(clust_rec,
- page_rec_is_comp(clust_rec)))) {
+ if (UNIV_UNLIKELY(rec_get_deleted_flag(clust_rec, comp))) {
/* The record is delete marked: we can skip it */
@@ -3879,17 +3890,27 @@ requires_clust_rec:
}
if (prebuilt->need_to_access_clustered) {
- rec = clust_rec;
- ut_ad(rec_offs_validate(rec, clust_index, offsets));
+
+ result_rec = clust_rec;
+
+ ut_ad(rec_offs_validate(result_rec, clust_index,
+ offsets));
} else {
+ /* We used 'offsets' for the clust rec, recalculate
+ them for 'rec' */
offsets = rec_get_offsets(rec, index, offsets,
ULINT_UNDEFINED, &heap);
+ result_rec = rec;
}
+ } else {
+ result_rec = rec;
}
- /* We found a qualifying row */
- ut_ad(rec_offs_validate(rec,
- rec == clust_rec ? clust_index : index,
+ /* We found a qualifying record 'result_rec'. At this point,
+ 'offsets' are associated with 'result_rec'. */
+
+ ut_ad(rec_offs_validate(result_rec,
+ result_rec != rec ? clust_index : index,
offsets));
if ((match_mode == ROW_SEL_EXACT
@@ -3910,8 +3931,8 @@ requires_clust_rec:
not cache rows because there the cursor is a scrollable
cursor. */
- row_sel_push_cache_row_for_mysql(prebuilt, rec, offsets);
-
+ row_sel_push_cache_row_for_mysql(prebuilt, result_rec,
+ offsets);
if (prebuilt->n_fetch_cached == MYSQL_FETCH_CACHE_SIZE) {
goto got_row;
@@ -3920,13 +3941,14 @@ requires_clust_rec:
goto next_rec;
} else {
if (prebuilt->template_type == ROW_MYSQL_DUMMY_TEMPLATE) {
- memcpy(buf + 4, rec - rec_offs_extra_size(offsets),
+ memcpy(buf + 4, result_rec
+ - rec_offs_extra_size(offsets),
rec_offs_size(offsets));
mach_write_to_4(buf,
rec_offs_extra_size(offsets) + 4);
} else {
if (!row_sel_store_mysql_rec(buf, prebuilt,
- rec, offsets)) {
+ result_rec, offsets)) {
err = DB_TOO_BIG_RECORD;
goto lock_wait_or_error;
@@ -3934,15 +3956,18 @@ requires_clust_rec:
}
if (prebuilt->clust_index_was_generated) {
- if (rec != index_rec) {
+ if (result_rec != rec) {
offsets = rec_get_offsets(
- index_rec, index, offsets,
+ rec, index, offsets,
ULINT_UNDEFINED, &heap);
}
- row_sel_store_row_id_to_prebuilt(prebuilt, index_rec,
+ row_sel_store_row_id_to_prebuilt(prebuilt, rec,
index, offsets);
}
}
+
+ /* From this point on, 'offsets' are invalid. */
+
got_row:
/* We have an optimization to save CPU time: if this is a consistent
read on a unique condition on the clustered index, then we do not
@@ -3993,7 +4018,7 @@ next_rec:
if (moves_up) {
if (UNIV_UNLIKELY(!btr_pcur_move_to_next(pcur, &mtr))) {
- not_moved:
+not_moved:
btr_pcur_store_position(pcur, &mtr);
if (match_mode != 0) {
diff --git a/innobase/row/row0upd.c b/innobase/row/row0upd.c
index 4f44dbeae67..ff1ad1dfd05 100644
--- a/innobase/row/row0upd.c
+++ b/innobase/row/row0upd.c
@@ -395,6 +395,18 @@ row_upd_changes_field_size_or_external(
old_len = rec_offs_nth_size(offsets, upd_field->field_no);
+ if (rec_offs_comp(offsets)
+ && rec_offs_nth_sql_null(offsets, upd_field->field_no)) {
+ /* Note that in the compact table format, for a
+ variable length field, an SQL NULL will use zero
+ bytes in the offset array at the start of the physical
+ record, but a zero-length value (empty string) will
+ use one byte! Thus, we cannot use update-in-place
+ if we update an SQL NULL varchar to an empty string! */
+
+ old_len = UNIV_SQL_NULL;
+ }
+
if (old_len != new_len) {
return(TRUE);
diff --git a/innobase/srv/srv0start.c b/innobase/srv/srv0start.c
index 325b0a109cf..e5151ebf631 100644
--- a/innobase/srv/srv0start.c
+++ b/innobase/srv/srv0start.c
@@ -1540,7 +1540,7 @@ NetWare. */
#endif
sync_order_checks_on = TRUE;
- if (srv_use_doublewrite_buf && trx_doublewrite == NULL) {
+ if (trx_doublewrite == NULL) {
/* Create the doublewrite buffer to a new tablespace */
trx_sys_create_doublewrite_buf();
diff --git a/innobase/trx/trx0sys.c b/innobase/trx/trx0sys.c
index bf48c30e942..23f1dc40d00 100644
--- a/innobase/trx/trx0sys.c
+++ b/innobase/trx/trx0sys.c
@@ -126,22 +126,6 @@ trx_doublewrite_init(
}
/********************************************************************
-Frees the doublewrite buffer. */
-static
-void
-trx_doublewrite_free(void)
-/*======================*/
-{
- mutex_free(&(trx_doublewrite->mutex));
-
- mem_free(trx_doublewrite->buf_block_arr);
- ut_free(trx_doublewrite->write_buf_unaligned);
-
- mem_free(trx_doublewrite);
- trx_doublewrite = NULL;
-}
-
-/********************************************************************
Marks the trx sys header when we have successfully upgraded to the >= 4.1.x
multiple tablespace format. */
@@ -529,9 +513,6 @@ trx_sys_doublewrite_init_or_restore_pages(
fil_flush_file_spaces(FIL_TABLESPACE);
- if (!srv_use_doublewrite_buf)
- trx_doublewrite_free();
-
leave_func:
ut_free(unaligned_read_buf);
}
diff --git a/innobase/trx/trx0trx.c b/innobase/trx/trx0trx.c
index 078befb81d2..090057f5d46 100644
--- a/innobase/trx/trx0trx.c
+++ b/innobase/trx/trx0trx.c
@@ -52,6 +52,32 @@ trx_start_if_not_started_noninline(
trx_start_if_not_started(trx);
}
+/*****************************************************************
+Set detailed error message for the transaction. */
+
+void
+trx_set_detailed_error(
+/*===================*/
+ trx_t* trx, /* in: transaction struct */
+ const char* msg) /* in: detailed error message */
+{
+ ut_strlcpy(trx->detailed_error, msg, sizeof(trx->detailed_error));
+}
+
+/*****************************************************************
+Set detailed error message for the transaction from a file. Note that the
+file is rewinded before reading from it. */
+
+void
+trx_set_detailed_error_from_file(
+/*=============================*/
+ trx_t* trx, /* in: transaction struct */
+ FILE* file) /* in: file to read message from */
+{
+ os_file_read_string(file, trx->detailed_error,
+ sizeof(trx->detailed_error));
+}
+
/********************************************************************
Retrieves the error_info field from a trx. */
@@ -130,6 +156,7 @@ trx_create(
trx->undo_no_arr = NULL;
trx->error_state = DB_SUCCESS;
+ trx->detailed_error[0] = '\0';
trx->sess = sess;
trx->que_state = TRX_QUE_RUNNING;
diff --git a/innobase/ut/ut0mem.c b/innobase/ut/ut0mem.c
index 3e8fd79a739..47b1e24e5e1 100644
--- a/innobase/ut/ut0mem.c
+++ b/innobase/ut/ut0mem.c
@@ -343,6 +343,54 @@ ut_free_all_mem(void)
}
/**************************************************************************
+Copies up to size - 1 characters from the NUL-terminated string src to
+dst, NUL-terminating the result. Returns strlen(src), so truncation
+occurred if the return value >= size. */
+
+ulint
+ut_strlcpy(
+/*=======*/
+ /* out: strlen(src) */
+ char* dst, /* in: destination buffer */
+ const char* src, /* in: source buffer */
+ ulint size) /* in: size of destination buffer */
+{
+ ulint src_size = strlen(src);
+
+ if (size != 0) {
+ ulint n = ut_min(src_size, size - 1);
+
+ memcpy(dst, src, n);
+ dst[n] = '\0';
+ }
+
+ return(src_size);
+}
+
+/**************************************************************************
+Like ut_strlcpy, but if src doesn't fit in dst completely, copies the last
+(size - 1) bytes of src, not the first. */
+
+ulint
+ut_strlcpy_rev(
+/*===========*/
+ /* out: strlen(src) */
+ char* dst, /* in: destination buffer */
+ const char* src, /* in: source buffer */
+ ulint size) /* in: size of destination buffer */
+{
+ ulint src_size = strlen(src);
+
+ if (size != 0) {
+ ulint n = ut_min(src_size, size - 1);
+
+ memcpy(dst, src + src_size - n, n + 1);
+ }
+
+ return(src_size);
+}
+
+/**************************************************************************
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(). */