This commit is contained in:
Georgi Kodinov 2011-01-10 15:08:33 +02:00
commit 83b4e920e2
43 changed files with 769 additions and 482 deletions

View file

@ -126,7 +126,9 @@ struct tm *gmtime_r(const time_t *timep,struct tm *tmp);
void pthread_exit(void *a); /* was #define pthread_exit(A) ExitThread(A)*/
#define ETIMEDOUT 145 /* Win32 doesn't have this */
#ifndef ETIMEDOUT
#define ETIMEDOUT 145 /* Win32 might not have this */
#endif
#define getpid() GetCurrentThreadId()
#define HAVE_LOCALTIME_R 1
#define _REENTRANT 1

View file

@ -664,6 +664,7 @@ extern void init_glob_errs(void);
extern void wait_for_free_space(const char *filename, int errors);
extern FILE *my_fopen(const char *FileName,int Flags,myf MyFlags);
extern FILE *my_fdopen(File Filedes,const char *name, int Flags,myf MyFlags);
extern FILE *my_freopen(const char *path, const char *mode, FILE *stream);
extern int my_fclose(FILE *fd,myf MyFlags);
extern int my_chsize(File fd,my_off_t newlength, int filler, myf MyFlags);
extern int my_sync(File fd, myf my_flags);

View file

@ -12,6 +12,7 @@ create table C(id int not null auto_increment primary key, f1 int not null, fore
insert into A values(1), (2);
--disable_query_log
begin;
let $i=257;
while ($i)
{
@ -24,6 +25,7 @@ while ($i)
insert into C(f1) values(2);
dec $i;
}
commit;
--enable_query_log
# Following Deletes should not report error

View file

@ -0,0 +1,26 @@
drop table if exists t1;
SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1;
CREATE TABLE t1 (c1 INT PRIMARY KEY AUTO_INCREMENT) ENGINE=InnoDB;
INSERT INTO t1 VALUES (null);
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`c1` int(11) NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`c1`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=latin1
DELETE FROM t1;
OPTIMIZE TABLE t1;
Table Op Msg_type Msg_text
test.t1 optimize note Table does not support optimize, doing recreate + analyze instead
test.t1 optimize status OK
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`c1` int(11) NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`c1`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=latin1
INSERT INTO t1 VALUES(null);
SELECT * FROM t1;
c1
2
DROP TABLE t1;

View file

@ -1,5 +1,8 @@
drop table if exists t1,t2,t3,t4;
drop database if exists mysqltest;
CREATE TABLE bug58912 (a BLOB, b TEXT, PRIMARY KEY(a(1))) ENGINE=InnoDB;
INSERT INTO bug58912 VALUES(REPEAT('a',8000),REPEAT('b',8000));
UPDATE bug58912 SET a=REPEAT('a',7999);
create table t1 (id int unsigned not null auto_increment, code tinyint unsigned not null, name char(20) not null, primary key (id), key (code), unique (name)) engine=innodb;
insert into t1 (code, name) values (1, 'Tim'), (1, 'Monty'), (2, 'David'), (2, 'Erik'), (3, 'Sasha'), (3, 'Jeremy'), (4, 'Matt');
select id, code, name from t1 order by id;
@ -1676,10 +1679,10 @@ variable_value - @innodb_rows_deleted_orig
71
SELECT variable_value - @innodb_rows_inserted_orig FROM information_schema.global_status WHERE LOWER(variable_name) = 'innodb_rows_inserted';
variable_value - @innodb_rows_inserted_orig
1066
1067
SELECT variable_value - @innodb_rows_updated_orig FROM information_schema.global_status WHERE LOWER(variable_name) = 'innodb_rows_updated';
variable_value - @innodb_rows_updated_orig
865
866
SELECT variable_value - @innodb_row_lock_waits_orig FROM information_schema.global_status WHERE LOWER(variable_name) = 'innodb_row_lock_waits';
variable_value - @innodb_row_lock_waits_orig
0
@ -3239,3 +3242,4 @@ Variable_name Value
Handler_update 1
Variable_name Value
Handler_delete 1
DROP TABLE bug58912;

View file

@ -0,0 +1,29 @@
-- source include/have_innodb_plugin.inc
# embedded server ignores 'delayed', so skip this
-- source include/not_embedded.inc
let $innodb_file_format_check_orig=`select @@innodb_file_format_check`;
--disable_warnings
drop table if exists t1;
--enable_warnings
#
# Bug #18274 InnoDB auto_increment field reset on OPTIMIZE TABLE
SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1;
CREATE TABLE t1 (c1 INT PRIMARY KEY AUTO_INCREMENT) ENGINE=InnoDB;
INSERT INTO t1 VALUES (null);
SHOW CREATE TABLE t1;
DELETE FROM t1;
OPTIMIZE TABLE t1;
SHOW CREATE TABLE t1;
INSERT INTO t1 VALUES(null);
SELECT * FROM t1;
DROP TABLE t1;
#
# restore environment to the state it was before this test execution
#
-- disable_query_log
eval set global innodb_file_format_check=$innodb_file_format_check_orig;

View file

@ -43,6 +43,15 @@ drop table if exists t1,t2,t3,t4;
drop database if exists mysqltest;
--enable_warnings
# Bug#58912 InnoDB unnecessarily avoids update-in-place on column prefixes
CREATE TABLE bug58912 (a BLOB, b TEXT, PRIMARY KEY(a(1))) ENGINE=InnoDB;
INSERT INTO bug58912 VALUES(REPEAT('a',8000),REPEAT('b',8000));
UPDATE bug58912 SET a=REPEAT('a',7999);
# The above statements used to trigger a failure during purge when
# Bug#55284 was fixed while Bug#58912 was not. Defer the DROP TABLE,
# so that purge gets a chance to run (and a double free of the
# off-page column can be detected, if one is to occur.)
#
# Small basic test with ignore
#
@ -2541,6 +2550,9 @@ SET GLOBAL innodb_thread_concurrency = @innodb_thread_concurrency_orig;
-- enable_query_log
# Clean up after the Bug#55284/Bug#58912 test case.
DROP TABLE bug58912;
#######################################################################
# #
# Please, DO NOT TOUCH this file as well as the innodb.result file. #

View file

@ -12,6 +12,7 @@ create table C(id int not null auto_increment primary key, f1 int not null, fore
insert into A values(1), (2);
--disable_query_log
begin;
let $i=257;
while ($i)
{
@ -24,6 +25,7 @@ while ($i)
insert into C(f1) values(2);
dec $i;
}
commit;
--enable_query_log
# Following Deletes should not report error

View file

@ -18,6 +18,10 @@
#include <errno.h>
#include "mysys_err.h"
#if defined(__FreeBSD__)
extern int getosreldate(void);
#endif
static void make_ftype(char * to,int flag);
/*
@ -97,8 +101,137 @@ FILE *my_fopen(const char *filename, int flags, myf MyFlags)
} /* my_fopen */
/* Close a stream */
#if defined(_WIN32)
static FILE *my_win_freopen(const char *path, const char *mode, FILE *stream)
{
int handle_fd, fd= _fileno(stream);
HANDLE osfh;
DBUG_ASSERT(path && stream);
/* Services don't have stdout/stderr on Windows, so _fileno returns -1. */
if (fd < 0)
{
if (!freopen(path, mode, stream))
return NULL;
fd= _fileno(stream);
}
if ((osfh= CreateFile(path, GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE |
FILE_SHARE_DELETE, NULL,
OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL,
NULL)) == INVALID_HANDLE_VALUE)
return NULL;
if ((handle_fd= _open_osfhandle((intptr_t)osfh,
_O_APPEND | _O_TEXT)) == -1)
{
CloseHandle(osfh);
return NULL;
}
if (_dup2(handle_fd, fd) < 0)
{
CloseHandle(osfh);
return NULL;
}
_close(handle_fd);
return stream;
}
#elif defined(__FreeBSD__)
/* No close operation hook. */
static int no_close(void *cookie __attribute__((unused)))
{
return 0;
}
/*
A hack around a race condition in the implementation of freopen.
The race condition steams from the fact that the current fd of
the stream is closed before its number is used to duplicate the
new file descriptor. This defeats the desired atomicity of the
close and duplicate of dup2().
See PR number 79887 for reference:
http://www.freebsd.org/cgi/query-pr.cgi?pr=79887
*/
static FILE *my_freebsd_freopen(const char *path, const char *mode, FILE *stream)
{
int old_fd;
FILE *result;
flockfile(stream);
old_fd= fileno(stream);
/* Use a no operation close hook to avoid having the fd closed. */
stream->_close= no_close;
/* Relies on the implicit dup2 to close old_fd. */
result= freopen(path, mode, stream);
/* If successful, the _close hook was replaced. */
if (result == NULL)
close(old_fd);
else
funlockfile(result);
return result;
}
#endif
/**
Change the file associated with a file stream.
@param path Path to file.
@param mode Mode of the stream.
@param stream File stream.
@note
This function is used to redirect stdout and stderr to a file and
subsequently to close and reopen that file for log rotation.
@retval A FILE pointer on success. Otherwise, NULL.
*/
FILE *my_freopen(const char *path, const char *mode, FILE *stream)
{
FILE *result;
#if defined(_WIN32)
result= my_win_freopen(path, mode, stream);
#elif defined(__FreeBSD__)
/*
XXX: Once the fix is ported to the stable releases, this should
be dependent upon the specific FreeBSD versions. Check at:
http://www.freebsd.org/cgi/query-pr.cgi?pr=79887
*/
if (getosreldate() > 900027)
result= freopen(path, mode, stream);
else
result= my_freebsd_freopen(path, mode, stream);
#else
result= freopen(path, mode, stream);
#endif
return result;
}
/* Close a stream */
int my_fclose(FILE *fd, myf MyFlags)
{
int err,file;

View file

@ -5171,80 +5171,26 @@ void sql_perror(const char *message)
}
#ifdef __WIN__
/*
Change the file associated with two output streams. Used to
redirect stdout and stderr to a file. The streams are reopened
only for appending (writing at end of file).
*/
extern "C" my_bool reopen_fstreams(const char *filename,
FILE *outstream, FILE *errstream)
{
int handle_fd;
int err_fd, out_fd;
HANDLE osfh;
if (outstream && !my_freopen(filename, "a", outstream))
return TRUE;
DBUG_ASSERT(filename && errstream);
// Services don't have stdout/stderr on Windows, so _fileno returns -1.
err_fd= _fileno(errstream);
if (err_fd < 0)
{
if (!freopen(filename, "a+", errstream))
return TRUE;
if (errstream && !my_freopen(filename, "a", errstream))
return TRUE;
/* The error stream must be unbuffered. */
if (errstream)
setbuf(errstream, NULL);
err_fd= _fileno(errstream);
}
if (outstream)
{
out_fd= _fileno(outstream);
if (out_fd < 0)
{
if (!freopen(filename, "a+", outstream))
return TRUE;
out_fd= _fileno(outstream);
}
}
if ((osfh= CreateFile(filename, GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE |
FILE_SHARE_DELETE, NULL,
OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL,
NULL)) == INVALID_HANDLE_VALUE)
return TRUE;
if ((handle_fd= _open_osfhandle((intptr_t)osfh,
_O_APPEND | _O_TEXT)) == -1)
{
CloseHandle(osfh);
return TRUE;
}
if (_dup2(handle_fd, err_fd) < 0)
{
CloseHandle(osfh);
return TRUE;
}
if (outstream && _dup2(handle_fd, out_fd) < 0)
{
CloseHandle(osfh);
return TRUE;
}
_close(handle_fd);
return FALSE;
}
#else
extern "C" my_bool reopen_fstreams(const char *filename,
FILE *outstream, FILE *errstream)
{
if (outstream && !freopen(filename, "a+", outstream))
return TRUE;
if (errstream && !freopen(filename, "a+", errstream))
return TRUE;
return FALSE;
}
#endif
/*

View file

@ -4647,9 +4647,10 @@ static int get_schema_constraints_record(THD *thd, TABLE_LIST *tables,
TABLE *show_table= tables->table;
KEY *key_info=show_table->key_info;
uint primary_key= show_table->s->primary_key;
show_table->file->info(HA_STATUS_VARIABLE |
HA_STATUS_NO_LOCK |
HA_STATUS_TIME);
// This is not needed since no statistics are displayed.
// show_table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK | HA_STATUS_TIME);
for (uint i=0 ; i < show_table->s->keys ; i++, key_info++)
{
if (i != primary_key && !(key_info->flags & HA_NOSAME))
@ -4831,9 +4832,10 @@ static int get_schema_key_column_usage_record(THD *thd,
TABLE *show_table= tables->table;
KEY *key_info=show_table->key_info;
uint primary_key= show_table->s->primary_key;
show_table->file->info(HA_STATUS_VARIABLE |
HA_STATUS_NO_LOCK |
HA_STATUS_TIME);
// This is not needed since no statistics are displayed.
// show_table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK | HA_STATUS_TIME);
for (uint i=0 ; i < show_table->s->keys ; i++, key_info++)
{
if (i != primary_key && !(key_info->flags & HA_NOSAME))
@ -5562,9 +5564,9 @@ get_referential_constraints_record(THD *thd, TABLE_LIST *tables,
{
List<FOREIGN_KEY_INFO> f_key_list;
TABLE *show_table= tables->table;
show_table->file->info(HA_STATUS_VARIABLE |
HA_STATUS_NO_LOCK |
HA_STATUS_TIME);
// This is not needed since no statistics are displayed.
// show_table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK | HA_STATUS_TIME);
show_table->file->get_foreign_key_list(thd, &f_key_list);
FOREIGN_KEY_INFO *f_key_info;

View file

@ -610,7 +610,7 @@ btr_page_get_father_for_rec(
"InnoDB: corruption. If the crash happens at "
"the database startup, see\n"
"InnoDB: http://dev.mysql.com/doc/refman/5.1/en/"
"forcing-recovery.html about\n"
"forcing-innodb-recovery.html about\n"
"InnoDB: forcing recovery. "
"Then dump + drop + reimport.\n", stderr);
}

View file

@ -334,7 +334,7 @@ buf_page_is_corrupted(
"InnoDB: tablespace but not the InnoDB "
"log files. See\n"
"InnoDB: http://dev.mysql.com/doc/refman/"
"5.1/en/forcing-recovery.html\n"
"5.1/en/forcing-innodb-recovery.html\n"
"InnoDB: for more information.\n",
(ulong) mach_read_from_4(read_buf
+ FIL_PAGE_OFFSET),
@ -2067,7 +2067,7 @@ buf_page_io_complete(
" table for corruption.\n"
"InnoDB: See also"
" http://dev.mysql.com/doc/refman/5.1/en/"
"forcing-recovery.html\n"
"forcing-innodb-recovery.html\n"
"InnoDB: about forcing recovery.\n", stderr);
if (srv_force_recovery < SRV_FORCE_IGNORE_CORRUPT) {

View file

@ -2217,7 +2217,7 @@ dict_scan_to(
quote = '\0';
} else if (quote) {
/* Within quotes: do nothing. */
} else if (*ptr == '`' || *ptr == '"') {
} else if (*ptr == '`' || *ptr == '"' || *ptr == '\'') {
/* Starting quote: remember the quote character. */
quote = *ptr;
} else {

View file

@ -87,6 +87,8 @@ dict_mem_table_create(
table->big_rows = 0;
table->fk_max_recusive_level = 0;
mutex_create(&table->autoinc_mutex, SYNC_DICT_AUTOINC_MUTEX);
table->autoinc = 0;

View file

@ -3046,7 +3046,7 @@ fseg_free_page_low(
crash:
fputs("InnoDB: Please refer to\n"
"InnoDB: http://dev.mysql.com/doc/refman/5.1/en/"
"forcing-recovery.html\n"
"forcing-innodb-recovery.html\n"
"InnoDB: about forcing recovery.\n", stderr);
ut_error;
}

View file

@ -218,7 +218,7 @@ buf_block_align(
"InnoDB: corruption. If this happens in an"
" InnoDB database recovery, see\n"
"InnoDB: http://dev.mysql.com/doc/refman/5.1/en/"
"forcing-recovery.html\n"
"forcing-innodb-recovery.html\n"
"InnoDB: how to force recovery.\n",
ptr, frame_zero,
buf_pool->high_end);
@ -257,7 +257,7 @@ buf_frame_align(
"InnoDB: corruption. If this happens in an"
" InnoDB database recovery, see\n"
"InnoDB: http://dev.mysql.com/doc/refman/5.1/en/"
"forcing-recovery.html\n"
"forcing-innodb-recovery.html\n"
"InnoDB: how to force recovery.\n",
ptr, buf_pool->frame_zero,
buf_pool->high_end);

View file

@ -1826,7 +1826,7 @@ recv_report_corrupt_log(
"InnoDB: on your InnoDB tables to check that they are ok!\n"
"InnoDB: If mysqld crashes after this recovery, look at\n"
"InnoDB: http://dev.mysql.com/doc/refman/5.1/en/"
"forcing-recovery.html\n"
"forcing-innodb-recovery.html\n"
"InnoDB: about forcing recovery.\n", stderr);
fflush(stderr);

View file

@ -552,7 +552,7 @@ handle_new_error:
" after the startup or when\n"
"InnoDB: you dump the tables, look at\n"
"InnoDB: http://dev.mysql.com/doc/refman/5.1/en/"
"forcing-recovery.html"
"forcing-innodb-recovery.html"
" for help.\n", stderr);
} else if (err == DB_FOREIGN_EXCEED_MAX_CASCADE) {

View file

@ -58,7 +58,7 @@ ut_dbg_assertion_failed(
"InnoDB: immediately after the mysqld startup, there may be\n"
"InnoDB: corruption in the InnoDB tablespace. Please refer to\n"
"InnoDB: http://dev.mysql.com/doc/refman/5.1/en/"
"forcing-recovery.html\n"
"forcing-innodb-recovery.html\n"
"InnoDB: about forcing recovery.\n", stderr);
#if defined(UNIV_SYNC_DEBUG) || !defined(UT_DBG_USE_ABORT)
ut_dbg_stop_threads = TRUE;

View file

@ -8,7 +8,37 @@
include/univ.i:
Fix Bug#58643 InnoDB: too long table name
2011-01-06 The InnoDB Team
* handler/i_s.cc, include/trx0i_s.h, trx/trx0i_s.c:
Fix Bug#55397 cannot select from innodb_trx when trx_query contains
blobs that aren't strings
2011-01-04 The InnoDB Team
* dict/dict0dict.c:
Fix Bug#59197 double quote in field comment prevents foreign
key constraint creation
2010-12-21 The InnoDB Team
* include/btr0cur.h, include/row0upd.h, btr/btr0cur.c,
row/row0umod.c, row/row0upd.c:
Fix Bug#55284 Double free of off-page columns due to lock wait
while updating PRIMARY KEY
2010-12-21 The InnoDB Team
* include/data0data.h, include/data0data.ic, include/row0upd.h,
btr/btr0cur.c, row/row0purge.c, row/row0umod.c, row/row0upd.c,
innodb.result, innodb.test:
Fix Bug#58912 InnoDB unnecessarily avoids update-in-place
on column prefix indexes
2010-12-09 The InnoDB Team
* buf/buf0lru.c:
Fix Bug#57600 output of I/O sum[%lu] can go negative
2010-11-11 The InnoDB Team
* thr/thr0loc.c, trx/trx0i_s.c:
Fix Bug#57802 Empty ASSERTION parameter passed to the HASH_SEARCH macro

View file

@ -663,7 +663,7 @@ btr_page_get_father_node_ptr_func(
" to fix the\n"
"InnoDB: corruption. If the crash happens at "
"the database startup, see\n"
"InnoDB: " REFMAN "forcing-recovery.html about\n"
"InnoDB: " REFMAN "forcing-innodb-recovery.html about\n"
"InnoDB: forcing recovery. "
"Then dump + drop + reimport.\n", stderr);

View file

@ -1756,7 +1756,8 @@ btr_cur_update_in_place(
NOT call it if index is secondary */
if (!dict_index_is_clust(index)
|| row_upd_changes_ord_field_binary(NULL, index, update)) {
|| row_upd_changes_ord_field_binary(NULL, NULL,
index, update)) {
/* Remove possible hash index pointer to this record */
btr_search_update_hash_on_delete(cursor);
@ -2508,27 +2509,24 @@ ulint
btr_cur_del_mark_set_clust_rec(
/*===========================*/
ulint flags, /*!< in: undo logging and locking flags */
btr_cur_t* cursor, /*!< in: cursor */
buf_block_t* block, /*!< in/out: buffer block of the record */
rec_t* rec, /*!< in/out: record */
dict_index_t* index, /*!< in: clustered index of the record */
const ulint* offsets,/*!< in: rec_get_offsets(rec) */
ibool val, /*!< in: value to set */
que_thr_t* thr, /*!< in: query thread */
mtr_t* mtr) /*!< in: mtr */
{
dict_index_t* index;
buf_block_t* block;
roll_ptr_t roll_ptr;
ulint err;
rec_t* rec;
page_zip_des_t* page_zip;
trx_t* trx;
mem_heap_t* heap = NULL;
ulint offsets_[REC_OFFS_NORMAL_SIZE];
ulint* offsets = offsets_;
rec_offs_init(offsets_);
rec = btr_cur_get_rec(cursor);
index = cursor->index;
ut_ad(dict_index_is_clust(index));
ut_ad(rec_offs_validate(rec, index, offsets));
ut_ad(!!page_rec_is_comp(rec) == dict_table_is_comp(index->table));
offsets = rec_get_offsets(rec, index, offsets, ULINT_UNDEFINED, &heap);
ut_ad(buf_block_get_frame(block) == page_align(rec));
ut_ad(page_is_leaf(page_align(rec)));
#ifdef UNIV_DEBUG
if (btr_cur_print_record_ops && thr) {
@ -2540,13 +2538,12 @@ btr_cur_del_mark_set_clust_rec(
ut_ad(dict_index_is_clust(index));
ut_ad(!rec_get_deleted_flag(rec, rec_offs_comp(offsets)));
err = lock_clust_rec_modify_check_and_lock(flags,
btr_cur_get_block(cursor),
err = lock_clust_rec_modify_check_and_lock(flags, block,
rec, index, offsets, thr);
if (err != DB_SUCCESS) {
goto func_exit;
return(err);
}
err = trx_undo_report_row_operation(flags, TRX_UNDO_MODIFY_OP, thr,
@ -2554,11 +2551,9 @@ btr_cur_del_mark_set_clust_rec(
&roll_ptr);
if (err != DB_SUCCESS) {
goto func_exit;
return(err);
}
block = btr_cur_get_block(cursor);
if (block->is_hashed) {
rw_lock_x_lock(&btr_search_latch);
}
@ -2581,10 +2576,6 @@ btr_cur_del_mark_set_clust_rec(
btr_cur_del_mark_set_clust_rec_log(flags, rec, index, val, trx,
roll_ptr, mtr);
func_exit:
if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
}
return(err);
}
@ -3476,108 +3467,36 @@ btr_cur_set_ownership_of_extern_field(
}
/*******************************************************************//**
Marks not updated extern fields as not-owned by this record. The ownership
is transferred to the updated record which is inserted elsewhere in the
Marks non-updated off-page fields as disowned by this record. The ownership
must be transferred to the updated record which is inserted elsewhere in the
index tree. In purge only the owner of externally stored field is allowed
to free the field.
@return TRUE if BLOB ownership was transferred */
to free the field. */
UNIV_INTERN
ibool
btr_cur_mark_extern_inherited_fields(
/*=================================*/
void
btr_cur_disown_inherited_fields(
/*============================*/
page_zip_des_t* page_zip,/*!< in/out: compressed page whose uncompressed
part will be updated, or NULL */
rec_t* rec, /*!< in/out: record in a clustered index */
dict_index_t* index, /*!< in: index of the page */
const ulint* offsets,/*!< in: array returned by rec_get_offsets() */
const upd_t* update, /*!< in: update vector */
mtr_t* mtr) /*!< in: mtr, or NULL if not logged */
mtr_t* mtr) /*!< in/out: mini-transaction */
{
ulint n;
ulint j;
ulint i;
ibool change_ownership = FALSE;
ut_ad(rec_offs_validate(rec, NULL, offsets));
ut_ad(rec_offs_validate(rec, index, offsets));
ut_ad(!rec_offs_comp(offsets) || !rec_get_node_ptr_flag(rec));
ut_ad(rec_offs_any_extern(offsets));
ut_ad(mtr);
if (!rec_offs_any_extern(offsets)) {
return(FALSE);
}
n = rec_offs_n_fields(offsets);
for (i = 0; i < n; i++) {
if (rec_offs_nth_extern(offsets, i)) {
/* Check it is not in updated fields */
if (update) {
for (j = 0; j < upd_get_n_fields(update);
j++) {
if (upd_get_nth_field(update, j)
->field_no == i) {
goto updated;
}
}
}
for (i = 0; i < rec_offs_n_fields(offsets); i++) {
if (rec_offs_nth_extern(offsets, i)
&& !upd_get_field_by_field_no(update, i)) {
btr_cur_set_ownership_of_extern_field(
page_zip, rec, index, offsets, i, FALSE, mtr);
change_ownership = TRUE;
updated:
;
}
}
return(change_ownership);
}
/*******************************************************************//**
The complement of the previous function: in an update entry may inherit
some externally stored fields from a record. We must mark them as inherited
in entry, so that they are not freed in a rollback. */
UNIV_INTERN
void
btr_cur_mark_dtuple_inherited_extern(
/*=================================*/
dtuple_t* entry, /*!< in/out: updated entry to be
inserted to clustered index */
const upd_t* update) /*!< in: update vector */
{
ulint i;
for (i = 0; i < dtuple_get_n_fields(entry); i++) {
dfield_t* dfield = dtuple_get_nth_field(entry, i);
byte* data;
ulint len;
ulint j;
if (!dfield_is_ext(dfield)) {
continue;
}
/* Check if it is in updated fields */
for (j = 0; j < upd_get_n_fields(update); j++) {
if (upd_get_nth_field(update, j)->field_no == i) {
goto is_updated;
}
}
data = dfield_get_data(dfield);
len = dfield_get_len(dfield);
data[len - BTR_EXTERN_FIELD_REF_SIZE + BTR_EXTERN_LEN]
|= BTR_EXTERN_INHERITED_FLAG;
is_updated:
;
}
}
/*******************************************************************//**
@ -3615,29 +3534,6 @@ btr_cur_unmark_extern_fields(
}
}
/*******************************************************************//**
Marks all extern fields in a dtuple as owned by the record. */
UNIV_INTERN
void
btr_cur_unmark_dtuple_extern_fields(
/*================================*/
dtuple_t* entry) /*!< in/out: clustered index entry */
{
ulint i;
for (i = 0; i < dtuple_get_n_fields(entry); i++) {
dfield_t* dfield = dtuple_get_nth_field(entry, i);
if (dfield_is_ext(dfield)) {
byte* data = dfield_get_data(dfield);
ulint len = dfield_get_len(dfield);
data[len - BTR_EXTERN_FIELD_REF_SIZE + BTR_EXTERN_LEN]
&= ~BTR_EXTERN_OWNER_FLAG;
}
}
}
/*******************************************************************//**
Flags the data tuple fields that are marked as extern storage in the
update vector. We use this function to remember which fields we must

View file

@ -375,7 +375,7 @@ buf_page_is_corrupted(
"you may have copied the InnoDB\n"
"InnoDB: tablespace but not the InnoDB "
"log files. See\n"
"InnoDB: " REFMAN "forcing-recovery.html\n"
"InnoDB: " REFMAN "forcing-innodb-recovery.html\n"
"InnoDB: for more information.\n",
(ulong) mach_read_from_4(read_buf
+ FIL_PAGE_OFFSET),
@ -3240,7 +3240,7 @@ corrupt:
"InnoDB: TABLE to scan your"
" table for corruption.\n"
"InnoDB: See also "
REFMAN "forcing-recovery.html\n"
REFMAN "forcing-innodb-recovery.html\n"
"InnoDB: about forcing recovery.\n", stderr);
if (srv_force_recovery < SRV_FORCE_IGNORE_CORRUPT) {

View file

@ -1942,6 +1942,7 @@ buf_LRU_stat_update(void)
/*=====================*/
{
buf_LRU_stat_t* item;
buf_LRU_stat_t cur_stat;
/* If we haven't started eviction yet then don't update stats. */
if (buf_pool->freed_page_clock == 0) {
@ -1955,12 +1956,19 @@ buf_LRU_stat_update(void)
buf_LRU_stat_arr_ind++;
buf_LRU_stat_arr_ind %= BUF_LRU_STAT_N_INTERVAL;
/* Add the current value and subtract the obsolete entry. */
buf_LRU_stat_sum.io += buf_LRU_stat_cur.io - item->io;
buf_LRU_stat_sum.unzip += buf_LRU_stat_cur.unzip - item->unzip;
/* Add the current value and subtract the obsolete entry.
Since buf_LRU_stat_cur is not protected by any mutex,
it can be changing between adding to buf_LRU_stat_sum
and copying to item. Assign it to local variables to make
sure the same value assign to the buf_LRU_stat_sum
and item */
cur_stat = buf_LRU_stat_cur;
buf_LRU_stat_sum.io += cur_stat.io - item->io;
buf_LRU_stat_sum.unzip += cur_stat.unzip - item->unzip;
/* Put current entry in the array. */
memcpy(item, &buf_LRU_stat_cur, sizeof *item);
memcpy(item, &cur_stat, sizeof *item);
buf_pool_mutex_exit();

View file

@ -2688,7 +2688,7 @@ dict_scan_to(
quote = '\0';
} else if (quote) {
/* Within quotes: do nothing. */
} else if (*ptr == '`' || *ptr == '"') {
} else if (*ptr == '`' || *ptr == '"' || *ptr == '\'') {
/* Starting quote: remember the quote character. */
quote = *ptr;
} else {

View file

@ -3326,7 +3326,7 @@ fseg_free_page_low(
"InnoDB: database!\n", (ulong) page);
crash:
fputs("InnoDB: Please refer to\n"
"InnoDB: " REFMAN "forcing-recovery.html\n"
"InnoDB: " REFMAN "forcing-innodb-recovery.html\n"
"InnoDB: about forcing recovery.\n", stderr);
ut_error;
}

View file

@ -6303,10 +6303,11 @@ create_clustered_index_when_no_primary(
/*****************************************************************//**
Return a display name for the row format
@return row format name */
const char *get_row_format_name(
/*============================*/
enum row_type row_format) /*!< in: Row Format */
UNIV_INTERN
const char*
get_row_format_name(
/*================*/
enum row_type row_format) /*!< in: Row Format */
{
switch (row_format) {
case ROW_TYPE_COMPACT:
@ -6321,12 +6322,38 @@ enum row_type row_format) /*!< in: Row Format */
return("DEFAULT");
case ROW_TYPE_FIXED:
return("FIXED");
default:
case ROW_TYPE_PAGE:
case ROW_TYPE_NOT_USED:
break;
}
return("NOT USED");
}
/** If file-per-table is missing, issue warning and set ret false */
#define CHECK_ERROR_ROW_TYPE_NEEDS_FILE_PER_TABLE \
if (!srv_file_per_table) { \
push_warning_printf( \
thd, MYSQL_ERROR::WARN_LEVEL_WARN, \
ER_ILLEGAL_HA_CREATE_OPTION, \
"InnoDB: ROW_FORMAT=%s requires" \
" innodb_file_per_table.", \
get_row_format_name(row_format)); \
ret = FALSE; \
}
/** If file-format is Antelope, issue warning and set ret false */
#define CHECK_ERROR_ROW_TYPE_NEEDS_GT_ANTELOPE \
if (srv_file_format < DICT_TF_FORMAT_ZIP) { \
push_warning_printf( \
thd, MYSQL_ERROR::WARN_LEVEL_WARN, \
ER_ILLEGAL_HA_CREATE_OPTION, \
"InnoDB: ROW_FORMAT=%s requires" \
" innodb_file_format > Antelope.", \
get_row_format_name(row_format)); \
ret = FALSE; \
}
/*****************************************************************//**
Validates the create options. We may build on this function
in future. For now, it checks two specifiers:
@ -6344,7 +6371,7 @@ create_options_are_valid(
{
ibool kbs_specified = FALSE;
ibool ret = TRUE;
enum row_type row_type = form->s->row_type;
enum row_type row_format = form->s->row_type;
ut_ad(thd != NULL);
@ -6353,23 +6380,6 @@ create_options_are_valid(
return(TRUE);
}
/* Check for a valid Innodb ROW_FORMAT specifier. For example,
ROW_TYPE_FIXED can be sent to Innodb */
switch (row_type) {
case ROW_TYPE_COMPACT:
case ROW_TYPE_COMPRESSED:
case ROW_TYPE_DYNAMIC:
case ROW_TYPE_REDUNDANT:
case ROW_TYPE_DEFAULT:
break;
default:
push_warning(
thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_ILLEGAL_HA_CREATE_OPTION,
"InnoDB: invalid ROW_FORMAT specifier.");
ret = FALSE;
}
ut_ad(form != NULL);
ut_ad(create_info != NULL);
@ -6382,7 +6392,23 @@ create_options_are_valid(
case 4:
case 8:
case 16:
/* Valid value. */
/* Valid KEY_BLOCK_SIZE, check its dependencies. */
if (!srv_file_per_table) {
push_warning(
thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_ILLEGAL_HA_CREATE_OPTION,
"InnoDB: KEY_BLOCK_SIZE requires"
" innodb_file_per_table.");
ret = FALSE;
}
if (srv_file_format < DICT_TF_FORMAT_ZIP) {
push_warning(
thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_ILLEGAL_HA_CREATE_OPTION,
"InnoDB: KEY_BLOCK_SIZE requires"
" innodb_file_format > Antelope.");
ret = FALSE;
}
break;
default:
push_warning_printf(
@ -6392,72 +6418,43 @@ create_options_are_valid(
" Valid values are [1, 2, 4, 8, 16]",
create_info->key_block_size);
ret = FALSE;
break;
}
}
/* If KEY_BLOCK_SIZE was specified, check for its
dependencies. */
if (kbs_specified && !srv_file_per_table) {
push_warning(
thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_ILLEGAL_HA_CREATE_OPTION,
"InnoDB: KEY_BLOCK_SIZE"
" requires innodb_file_per_table.");
ret = FALSE;
}
if (kbs_specified && srv_file_format < DICT_TF_FORMAT_ZIP) {
push_warning(
thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_ILLEGAL_HA_CREATE_OPTION,
"InnoDB: KEY_BLOCK_SIZE requires"
" innodb_file_format > Antelope.");
ret = FALSE;
}
switch (row_type) {
/* Check for a valid Innodb ROW_FORMAT specifier and
other incompatibilities. */
switch (row_format) {
case ROW_TYPE_COMPRESSED:
case ROW_TYPE_DYNAMIC:
/* These two ROW_FORMATs require srv_file_per_table
and srv_file_format > Antelope */
if (!srv_file_per_table) {
push_warning_printf(
thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_ILLEGAL_HA_CREATE_OPTION,
"InnoDB: ROW_FORMAT=%s"
" requires innodb_file_per_table.",
get_row_format_name(row_type));
ret = FALSE;
}
if (srv_file_format < DICT_TF_FORMAT_ZIP) {
push_warning_printf(
thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_ILLEGAL_HA_CREATE_OPTION,
"InnoDB: ROW_FORMAT=%s requires"
" innodb_file_format > Antelope.",
get_row_format_name(row_type));
ret = FALSE;
}
default:
CHECK_ERROR_ROW_TYPE_NEEDS_FILE_PER_TABLE;
CHECK_ERROR_ROW_TYPE_NEEDS_GT_ANTELOPE;
break;
}
switch (row_type) {
case ROW_TYPE_REDUNDANT:
case ROW_TYPE_COMPACT:
case ROW_TYPE_DYNAMIC:
/* KEY_BLOCK_SIZE is only allowed with Compressed or Default */
CHECK_ERROR_ROW_TYPE_NEEDS_FILE_PER_TABLE;
CHECK_ERROR_ROW_TYPE_NEEDS_GT_ANTELOPE;
/* fall through since dynamic also shuns KBS */
case ROW_TYPE_COMPACT:
case ROW_TYPE_REDUNDANT:
if (kbs_specified) {
push_warning_printf(
thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_ILLEGAL_HA_CREATE_OPTION,
"InnoDB: cannot specify ROW_FORMAT = %s"
" with KEY_BLOCK_SIZE.",
get_row_format_name(row_type));
ret = FALSE;
get_row_format_name(row_format));
ret = FALSE;
}
default:
break;
case ROW_TYPE_DEFAULT:
break;
case ROW_TYPE_FIXED:
case ROW_TYPE_PAGE:
case ROW_TYPE_NOT_USED:
push_warning(
thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_ILLEGAL_HA_CREATE_OPTION, \
"InnoDB: invalid ROW_FORMAT specifier.");
ret = FALSE;
break;
}
@ -6508,7 +6505,7 @@ ha_innobase::create(
const ulint file_format = srv_file_format;
const char* stmt;
size_t stmt_len;
enum row_type row_type;
enum row_type row_format;
DBUG_ENTER("ha_innobase::create");
@ -6608,8 +6605,8 @@ ha_innobase::create(
push_warning(
thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_ILLEGAL_HA_CREATE_OPTION,
"InnoDB: KEY_BLOCK_SIZE"
" requires innodb_file_per_table.");
"InnoDB: KEY_BLOCK_SIZE requires"
" innodb_file_per_table.");
flags = 0;
}
@ -6626,20 +6623,19 @@ ha_innobase::create(
push_warning_printf(
thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_ILLEGAL_HA_CREATE_OPTION,
"InnoDB: ignoring"
" KEY_BLOCK_SIZE=%lu.",
"InnoDB: ignoring KEY_BLOCK_SIZE=%lu.",
create_info->key_block_size);
}
}
row_type = form->s->row_type;
row_format = form->s->row_type;
if (flags) {
/* if ROW_FORMAT is set to default,
automatically change it to COMPRESSED.*/
if (row_type == ROW_TYPE_DEFAULT) {
row_type = ROW_TYPE_COMPRESSED;
} else if (row_type != ROW_TYPE_COMPRESSED) {
if (row_format == ROW_TYPE_DEFAULT) {
row_format = ROW_TYPE_COMPRESSED;
} else if (row_format != ROW_TYPE_COMPRESSED) {
/* ROW_FORMAT other than COMPRESSED
ignores KEY_BLOCK_SIZE. It does not
make sense to reject conflicting
@ -6656,7 +6652,7 @@ ha_innobase::create(
}
} else {
/* flags == 0 means no KEY_BLOCK_SIZE.*/
if (row_type == ROW_TYPE_COMPRESSED) {
if (row_format == ROW_TYPE_COMPRESSED) {
/* ROW_FORMAT=COMPRESSED without
KEY_BLOCK_SIZE implies half the
maximum KEY_BLOCK_SIZE. */
@ -6671,7 +6667,7 @@ ha_innobase::create(
}
}
switch (row_type) {
switch (row_format) {
case ROW_TYPE_REDUNDANT:
break;
case ROW_TYPE_COMPRESSED:
@ -6682,25 +6678,25 @@ ha_innobase::create(
ER_ILLEGAL_HA_CREATE_OPTION,
"InnoDB: ROW_FORMAT=%s requires"
" innodb_file_per_table.",
get_row_format_name(row_type));
get_row_format_name(row_format));
} else if (file_format < DICT_TF_FORMAT_ZIP) {
push_warning_printf(
thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_ILLEGAL_HA_CREATE_OPTION,
"InnoDB: ROW_FORMAT=%s requires"
" innodb_file_format > Antelope.",
get_row_format_name(row_type));
get_row_format_name(row_format));
} else {
flags |= DICT_TF_COMPACT
| (DICT_TF_FORMAT_ZIP
<< DICT_TF_FORMAT_SHIFT);
| (DICT_TF_FORMAT_ZIP
<< DICT_TF_FORMAT_SHIFT);
break;
}
/* fall through */
case ROW_TYPE_NOT_USED:
case ROW_TYPE_FIXED:
default:
case ROW_TYPE_PAGE:
push_warning(
thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_ILLEGAL_HA_CREATE_OPTION,
@ -6818,23 +6814,25 @@ ha_innobase::create(
setup at this stage and so we use thd. */
/* We need to copy the AUTOINC value from the old table if
this is an ALTER TABLE or CREATE INDEX because CREATE INDEX
does a table copy too. */
this is an ALTER|OPTIMIZE TABLE or CREATE INDEX because CREATE INDEX
does a table copy too. If query was one of :
CREATE TABLE ...AUTO_INCREMENT = x; or
ALTER TABLE...AUTO_INCREMENT = x; or
OPTIMIZE TABLE t; or
CREATE INDEX x on t(...);
Find out a table definition from the dictionary and get
the current value of the auto increment field. Set a new
value to the auto increment field if the value is greater
than the maximum value in the column. */
if (((create_info->used_fields & HA_CREATE_USED_AUTO)
|| thd_sql_command(thd) == SQLCOM_ALTER_TABLE
|| thd_sql_command(thd) == SQLCOM_OPTIMIZE
|| thd_sql_command(thd) == SQLCOM_CREATE_INDEX)
&& create_info->auto_increment_value > 0) {
/* Query was one of :
CREATE TABLE ...AUTO_INCREMENT = x; or
ALTER TABLE...AUTO_INCREMENT = x; or
CREATE INDEX x on t(...);
Find out a table definition from the dictionary and get
the current value of the auto increment field. Set a new
value to the auto increment field if the value is greater
than the maximum value in the column. */
auto_inc_value = create_info->auto_increment_value;
dict_table_autoinc_lock(innobase_table);

View file

@ -371,8 +371,16 @@ fill_innodb_trx_from_cache(
row->trx_mysql_thread_id));
/* trx_query */
OK(field_store_string(fields[IDX_TRX_QUERY],
row->trx_query));
if (row->trx_query) {
/* store will do appropriate character set
conversion check */
fields[IDX_TRX_QUERY]->store(
row->trx_query, strlen(row->trx_query),
row->trx_query_cs);
fields[IDX_TRX_QUERY]->set_notnull();
} else {
fields[IDX_TRX_QUERY]->set_null();
}
OK(schema_table_store_record(thd, table));
}

View file

@ -332,10 +332,14 @@ ulint
btr_cur_del_mark_set_clust_rec(
/*===========================*/
ulint flags, /*!< in: undo logging and locking flags */
btr_cur_t* cursor, /*!< in: cursor */
buf_block_t* block, /*!< in/out: buffer block of the record */
rec_t* rec, /*!< in/out: record */
dict_index_t* index, /*!< in: clustered index of the record */
const ulint* offsets,/*!< in: rec_get_offsets(rec) */
ibool val, /*!< in: value to set */
que_thr_t* thr, /*!< in: query thread */
mtr_t* mtr); /*!< in: mtr */
mtr_t* mtr) /*!< in: mtr */
__attribute__((nonnull));
/***********************************************************//**
Sets a secondary index record delete mark to TRUE or FALSE.
@return DB_SUCCESS, DB_LOCK_WAIT, or error number */
@ -481,40 +485,22 @@ btr_estimate_number_of_different_key_vals(
/*======================================*/
dict_index_t* index); /*!< in: index */
/*******************************************************************//**
Marks not updated extern fields as not-owned by this record. The ownership
is transferred to the updated record which is inserted elsewhere in the
Marks non-updated off-page fields as disowned by this record. The ownership
must be transferred to the updated record which is inserted elsewhere in the
index tree. In purge only the owner of externally stored field is allowed
to free the field.
@return TRUE if BLOB ownership was transferred */
to free the field. */
UNIV_INTERN
ibool
btr_cur_mark_extern_inherited_fields(
/*=================================*/
void
btr_cur_disown_inherited_fields(
/*============================*/
page_zip_des_t* page_zip,/*!< in/out: compressed page whose uncompressed
part will be updated, or NULL */
rec_t* rec, /*!< in/out: record in a clustered index */
dict_index_t* index, /*!< in: index of the page */
const ulint* offsets,/*!< in: array returned by rec_get_offsets() */
const upd_t* update, /*!< in: update vector */
mtr_t* mtr); /*!< in: mtr, or NULL if not logged */
/*******************************************************************//**
The complement of the previous function: in an update entry may inherit
some externally stored fields from a record. We must mark them as inherited
in entry, so that they are not freed in a rollback. */
UNIV_INTERN
void
btr_cur_mark_dtuple_inherited_extern(
/*=================================*/
dtuple_t* entry, /*!< in/out: updated entry to be
inserted to clustered index */
const upd_t* update); /*!< in: update vector */
/*******************************************************************//**
Marks all extern fields in a dtuple as owned by the record. */
UNIV_INTERN
void
btr_cur_unmark_dtuple_extern_fields(
/*================================*/
dtuple_t* entry); /*!< in/out: clustered index entry */
mtr_t* mtr) /*!< in/out: mini-transaction */
__attribute__((nonnull(2,3,4,5,6)));
/*******************************************************************//**
Stores the fields in big_rec_vec to the tablespace and puts pointers to
them in rec. The extern flags in rec will have to be set beforehand.

View file

@ -154,14 +154,19 @@ dfield_dup(
dfield_t* field, /*!< in/out: data field */
mem_heap_t* heap); /*!< in: memory heap where allocated */
/*********************************************************************//**
Tests if data length and content is equal for two dfields.
@return TRUE if equal */
Tests if two data fields are equal.
If len==0, tests the data length and content for equality.
If len>0, tests the first len bytes of the content for equality.
@return TRUE if both fields are NULL or if they are equal */
UNIV_INLINE
ibool
dfield_datas_are_binary_equal(
/*==========================*/
const dfield_t* field1, /*!< in: field */
const dfield_t* field2);/*!< in: field */
const dfield_t* field2, /*!< in: field */
ulint len) /*!< in: maximum prefix to compare,
or 0 to compare the whole field length */
__attribute__((nonnull, warn_unused_result));
/*********************************************************************//**
Tests if dfield data length and content is equal to the given.
@return TRUE if equal */

View file

@ -229,20 +229,30 @@ dfield_dup(
}
/*********************************************************************//**
Tests if data length and content is equal for two dfields.
@return TRUE if equal */
Tests if two data fields are equal.
If len==0, tests the data length and content for equality.
If len>0, tests the first len bytes of the content for equality.
@return TRUE if both fields are NULL or if they are equal */
UNIV_INLINE
ibool
dfield_datas_are_binary_equal(
/*==========================*/
const dfield_t* field1, /*!< in: field */
const dfield_t* field2) /*!< in: field */
const dfield_t* field2, /*!< in: field */
ulint len) /*!< in: maximum prefix to compare,
or 0 to compare the whole field length */
{
ulint len;
ulint len2 = len;
len = field1->len;
if (field1->len == UNIV_SQL_NULL || len == 0 || field1->len < len) {
len = field1->len;
}
return(len == field2->len
if (field2->len == UNIV_SQL_NULL || len2 == 0 || field2->len < len2) {
len2 = field2->len;
}
return(len == len2
&& (len == UNIV_SQL_NULL
|| !memcmp(field1->data, field2->data, len)));
}

View file

@ -286,10 +286,13 @@ row_upd_changes_ord_field_binary(
row and the data values in update are not
known when this function is called, e.g., at
compile time */
const row_ext_t*ext, /*!< NULL, or prefixes of the externally
stored columns in the old row */
dict_index_t* index, /*!< in: index of the record */
const upd_t* update);/*!< in: update vector for the row; NOTE: the
const upd_t* update) /*!< in: update vector for the row; NOTE: the
field numbers in this MUST be clustered index
positions! */
__attribute__((nonnull(3,4), warn_unused_result));
/***********************************************************//**
Checks if an update vector changes an ordering field of an index record.
This function is fast if the update vector is short or the number of ordering
@ -462,11 +465,16 @@ struct upd_node_struct{
#define UPD_NODE_INSERT_CLUSTERED 3 /* clustered index record should be
inserted, old record is already delete
marked */
#define UPD_NODE_UPDATE_ALL_SEC 4 /* an ordering field of the clustered
#define UPD_NODE_INSERT_BLOB 4 /* clustered index record should be
inserted, old record is already
delete-marked; non-updated BLOBs
should be inherited by the new record
and disowned by the old record */
#define UPD_NODE_UPDATE_ALL_SEC 5 /* an ordering field of the clustered
index record was changed, or this is
a delete operation: should update
all the secondary index records */
#define UPD_NODE_UPDATE_SOME_SEC 5 /* secondary index entries should be
#define UPD_NODE_UPDATE_SOME_SEC 6 /* secondary index entries should be
looked at and updated if an ordering
field changed */

View file

@ -110,6 +110,8 @@ struct i_s_trx_row_struct {
/*!< thd_get_thread_id() */
const char* trx_query; /*!< MySQL statement being
executed in the transaction */
struct charset_info_st* trx_query_cs; /*!< charset encode the MySQL
statement */
};
/** This structure represents INFORMATION_SCHEMA.innodb_lock_waits row */

View file

@ -46,7 +46,7 @@ Created 1/20/1994 Heikki Tuuri
#define INNODB_VERSION_MAJOR 1
#define INNODB_VERSION_MINOR 0
#define INNODB_VERSION_BUGFIX 14
#define INNODB_VERSION_BUGFIX 15
/* The following is the InnoDB version as shown in
SELECT plugin_version FROM information_schema.plugins;

View file

@ -2188,7 +2188,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: " REFMAN "forcing-recovery.html\n"
"InnoDB: " REFMAN "forcing-innodb-recovery.html\n"
"InnoDB: about forcing recovery.\n", stderr);
fflush(stderr);

View file

@ -17,6 +17,9 @@
MYSQL_STORAGE_ENGINE(innodb_plugin,, [InnoDB Storage Engine],
[Transactional Tables using InnoDB], [max,max-no-ndb])
MYSQL_PLUGIN_DIRECTORY(innodb_plugin, [storage/innodb_plugin])
# Enable if you know what you are doing (trying to link both InnoDB and
# InnoDB Plugin statically into MySQL does not work).
#MYSQL_PLUGIN_STATIC(innodb_plugin, [libinnobase.a])
MYSQL_PLUGIN_DYNAMIC(innodb_plugin, [ha_innodb_plugin.la])
MYSQL_PLUGIN_ACTIONS(innodb_plugin, [
AC_CHECK_HEADERS(sched.h)
@ -136,17 +139,24 @@ MYSQL_PLUGIN_ACTIONS(innodb_plugin, [
)
AC_MSG_CHECKING(whether Solaris libc atomic functions are available)
# either define HAVE_IB_SOLARIS_ATOMICS or not
AC_CHECK_FUNCS(atomic_cas_ulong \
# Define HAVE_IB_SOLARIS_ATOMICS if _all_ of the following
# functions are present.
AC_CHECK_FUNCS(atomic_add_long_nv \
atomic_cas_32 \
atomic_cas_64 \
atomic_add_long_nv \
atomic_swap_uchar,
atomic_cas_ulong \
atomic_swap_uchar)
AC_DEFINE([HAVE_IB_SOLARIS_ATOMICS], [1],
[Define to 1 if Solaris libc atomic functions \
are available])
)
if test "${ac_cv_func_atomic_add_long_nv}" = "yes" -a \
"${ac_cv_func_atomic_cas_32}" = "yes" -a \
"${ac_cv_func_atomic_cas_64}" = "yes" -a \
"${ac_cv_func_atomic_cas_ulong}" = "yes" -a \
"${ac_cv_func_atomic_swap_uchar}" = "yes" ; then
AC_DEFINE([HAVE_IB_SOLARIS_ATOMICS], [1],
[Define to 1 if Solaris libc atomic functions are available]
)
fi
AC_MSG_CHECKING(whether pthread_t can be used by Solaris libc atomic functions)
# either define HAVE_IB_ATOMIC_PTHREAD_T_SOLARIS or not

View file

@ -573,7 +573,7 @@ handle_new_error:
"InnoDB: If the mysqld server crashes"
" after the startup or when\n"
"InnoDB: you dump the tables, look at\n"
"InnoDB: " REFMAN "forcing-recovery.html"
"InnoDB: " REFMAN "forcing-innodb-recovery.html"
" for help.\n", stderr);
break;
case DB_FOREIGN_EXCEED_MAX_CASCADE:

View file

@ -413,7 +413,7 @@ row_purge_upd_exist_or_extern(
while (node->index != NULL) {
index = node->index;
if (row_upd_changes_ord_field_binary(NULL, node->index,
if (row_upd_changes_ord_field_binary(NULL, NULL, node->index,
node->update)) {
/* Build the older version of the index entry */
entry = row_build_index_entry(node->row, NULL,

View file

@ -668,19 +668,18 @@ row_undo_mod_upd_exist_sec(
while (node->index != NULL) {
index = node->index;
if (row_upd_changes_ord_field_binary(node->row, node->index,
node->update)) {
if (row_upd_changes_ord_field_binary(
node->row, node->ext, node->index, node->update)) {
/* Build the newest version of the index entry */
entry = row_build_index_entry(node->row, node->ext,
index, heap);
if (UNIV_UNLIKELY(!entry)) {
/* The server must have crashed in
row_upd_clust_rec_by_insert(), in
row_ins_index_entry_low() before
btr_store_big_rec_extern_fields()
has written the externally stored columns
(BLOBs) of the new clustered index entry. */
row_upd_clust_rec_by_insert() before
the updated externally stored columns (BLOBs)
of the new clustered index entry were
written. */
/* The table must be in DYNAMIC or COMPRESSED
format. REDUNDANT and COMPACT formats

View file

@ -1198,20 +1198,21 @@ row_upd_changes_ord_field_binary(
row and the data values in update are not
known when this function is called, e.g., at
compile time */
const row_ext_t*ext, /*!< NULL, or prefixes of the externally
stored columns in the old row */
dict_index_t* index, /*!< in: index of the record */
const upd_t* update) /*!< in: update vector for the row; NOTE: the
field numbers in this MUST be clustered index
positions! */
{
ulint n_unique;
ulint n_upd_fields;
ulint i, j;
dict_index_t* clust_index;
ulint n_unique;
ulint i;
const dict_index_t* clust_index;
ut_ad(update && index);
ut_ad(update);
ut_ad(index);
n_unique = dict_index_get_n_unique(index);
n_upd_fields = upd_get_n_fields(update);
clust_index = dict_table_get_first_index(index->table);
@ -1219,33 +1220,72 @@ row_upd_changes_ord_field_binary(
const dict_field_t* ind_field;
const dict_col_t* col;
ulint col_pos;
ulint col_no;
const upd_field_t* upd_field;
const dfield_t* dfield;
dfield_t dfield_ext;
ulint dfield_len;
const byte* buf;
ind_field = dict_index_get_nth_field(index, i);
col = dict_field_get_col(ind_field);
col_pos = dict_col_get_clust_pos(col, clust_index);
col_no = dict_col_get_no(col);
for (j = 0; j < n_upd_fields; j++) {
upd_field = upd_get_field_by_field_no(
update, dict_col_get_clust_pos(col, clust_index));
const upd_field_t* upd_field
= upd_get_nth_field(update, j);
if (upd_field == NULL) {
continue;
}
/* Note that if the index field is a column prefix
then it may be that row does not contain an externally
stored part of the column value, and we cannot compare
the datas */
if (row == NULL) {
ut_ad(ext == NULL);
return(TRUE);
}
if (col_pos == upd_field->field_no
&& (row == NULL
|| ind_field->prefix_len > 0
|| !dfield_datas_are_binary_equal(
dtuple_get_nth_field(row, col_no),
&(upd_field->new_val)))) {
dfield = dtuple_get_nth_field(row, col_no);
return(TRUE);
/* This treatment of column prefix indexes is loosely
based on row_build_index_entry(). */
if (UNIV_LIKELY(ind_field->prefix_len == 0)
|| dfield_is_null(dfield)) {
/* do nothing special */
} else if (UNIV_LIKELY_NULL(ext)) {
/* See if the column is stored externally. */
buf = row_ext_lookup(ext, col_no, &dfield_len);
ut_ad(col->ord_part);
if (UNIV_LIKELY_NULL(buf)) {
if (UNIV_UNLIKELY(buf == field_ref_zero)) {
/* This should never happen, but
we try to fail safe here. */
ut_ad(0);
return(TRUE);
}
goto copy_dfield;
}
} else if (dfield_is_ext(dfield)) {
dfield_len = dfield_get_len(dfield);
ut_a(dfield_len > BTR_EXTERN_FIELD_REF_SIZE);
dfield_len -= BTR_EXTERN_FIELD_REF_SIZE;
ut_a(dict_index_is_clust(index)
|| ind_field->prefix_len <= dfield_len);
buf = dfield_get_data(dfield);
copy_dfield:
ut_a(dfield_len > 0);
dfield_copy(&dfield_ext, dfield);
dfield_set_data(&dfield_ext, buf, dfield_len);
dfield = &dfield_ext;
}
if (!dfield_datas_are_binary_equal(
dfield, &upd_field->new_val,
ind_field->prefix_len)) {
return(TRUE);
}
}
@ -1329,7 +1369,7 @@ row_upd_changes_first_fields_binary(
if (col_pos == upd_field->field_no
&& !dfield_datas_are_binary_equal(
dtuple_get_nth_field(entry, i),
&(upd_field->new_val))) {
&upd_field->new_val, 0)) {
return(TRUE);
}
@ -1568,14 +1608,99 @@ row_upd_sec_step(
ut_ad(!dict_index_is_clust(node->index));
if (node->state == UPD_NODE_UPDATE_ALL_SEC
|| row_upd_changes_ord_field_binary(node->row, node->index,
node->update)) {
|| row_upd_changes_ord_field_binary(node->row, node->ext,
node->index, node->update)) {
return(row_upd_sec_index_entry(node, thr));
}
return(DB_SUCCESS);
}
#ifdef UNIV_DEBUG
# define row_upd_clust_rec_by_insert_inherit(rec,offsets,entry,update) \
row_upd_clust_rec_by_insert_inherit_func(rec,offsets,entry,update)
#else /* UNIV_DEBUG */
# define row_upd_clust_rec_by_insert_inherit(rec,offsets,entry,update) \
row_upd_clust_rec_by_insert_inherit_func(entry,update)
#endif /* UNIV_DEBUG */
/*******************************************************************//**
Mark non-updated off-page columns inherited when the primary key is
updated. We must mark them as inherited in entry, so that they are not
freed in a rollback. A limited version of this function used to be
called btr_cur_mark_dtuple_inherited_extern().
@return TRUE if any columns were inherited */
static __attribute__((warn_unused_result))
ibool
row_upd_clust_rec_by_insert_inherit_func(
/*=====================================*/
#ifdef UNIV_DEBUG
const rec_t* rec, /*!< in: old record, or NULL */
const ulint* offsets,/*!< in: rec_get_offsets(rec), or NULL */
#endif /* UNIV_DEBUG */
dtuple_t* entry, /*!< in/out: updated entry to be
inserted into the clustered index */
const upd_t* update) /*!< in: update vector */
{
ibool inherit = FALSE;
ulint i;
ut_ad(!rec == !offsets);
ut_ad(!rec || rec_offs_any_extern(offsets));
for (i = 0; i < dtuple_get_n_fields(entry); i++) {
dfield_t* dfield = dtuple_get_nth_field(entry, i);
byte* data;
ulint len;
ut_ad(!offsets
|| !rec_offs_nth_extern(offsets, i)
== !dfield_is_ext(dfield)
|| upd_get_field_by_field_no(update, i));
if (!dfield_is_ext(dfield)
|| upd_get_field_by_field_no(update, i)) {
continue;
}
#ifdef UNIV_DEBUG
if (UNIV_LIKELY(rec != NULL)) {
const byte* rec_data
= rec_get_nth_field(rec, offsets, i, &len);
ut_ad(len == dfield_get_len(dfield));
ut_ad(len != UNIV_SQL_NULL);
ut_ad(len >= BTR_EXTERN_FIELD_REF_SIZE);
rec_data += len - BTR_EXTERN_FIELD_REF_SIZE;
/* The pointer must not be zero. */
ut_ad(memcmp(rec_data, field_ref_zero,
BTR_EXTERN_FIELD_REF_SIZE));
/* The BLOB must be owned. */
ut_ad(!(rec_data[BTR_EXTERN_LEN]
& BTR_EXTERN_OWNER_FLAG));
}
#endif /* UNIV_DEBUG */
len = dfield_get_len(dfield);
ut_a(len != UNIV_SQL_NULL);
ut_a(len >= BTR_EXTERN_FIELD_REF_SIZE);
data = dfield_get_data(dfield);
data += len - BTR_EXTERN_FIELD_REF_SIZE;
/* The pointer must not be zero. */
ut_a(memcmp(data, field_ref_zero, BTR_EXTERN_FIELD_REF_SIZE));
/* The BLOB must be owned. */
ut_a(!(data[BTR_EXTERN_LEN] & BTR_EXTERN_OWNER_FLAG));
data[BTR_EXTERN_LEN] |= BTR_EXTERN_INHERITED_FLAG;
/* The BTR_EXTERN_INHERITED_FLAG only matters in
rollback. Purge will always free the extern fields of
a delete-marked row. */
inherit = TRUE;
}
return(inherit);
}
/***********************************************************//**
Marks the clustered index record deleted and inserts the updated version
of the record to the index. This function should be used when the ordering
@ -1594,14 +1719,16 @@ row_upd_clust_rec_by_insert(
a foreign key constraint */
mtr_t* mtr) /*!< in/out: mtr; gets committed here */
{
mem_heap_t* heap = NULL;
mem_heap_t* heap;
btr_pcur_t* pcur;
btr_cur_t* btr_cur;
trx_t* trx;
dict_table_t* table;
dtuple_t* entry;
ulint err;
ibool change_ownership = FALSE;
ibool change_ownership = FALSE;
rec_t* rec;
ulint* offsets = NULL;
ut_ad(node);
ut_ad(dict_index_is_clust(index));
@ -1611,53 +1738,7 @@ row_upd_clust_rec_by_insert(
pcur = node->pcur;
btr_cur = btr_pcur_get_btr_cur(pcur);
if (node->state != UPD_NODE_INSERT_CLUSTERED) {
rec_t* rec;
dict_index_t* index;
ulint offsets_[REC_OFFS_NORMAL_SIZE];
ulint* offsets;
rec_offs_init(offsets_);
err = btr_cur_del_mark_set_clust_rec(BTR_NO_LOCKING_FLAG,
btr_cur, TRUE, thr, mtr);
if (err != DB_SUCCESS) {
mtr_commit(mtr);
return(err);
}
/* Mark as not-owned the externally stored fields which the new
row inherits from the delete marked record: purge should not
free those externally stored fields even if the delete marked
record is removed from the index tree, or updated. */
rec = btr_cur_get_rec(btr_cur);
index = dict_table_get_first_index(table);
offsets = rec_get_offsets(rec, index, offsets_,
ULINT_UNDEFINED, &heap);
change_ownership = btr_cur_mark_extern_inherited_fields(
btr_cur_get_page_zip(btr_cur), rec, index, offsets,
node->update, mtr);
if (check_ref) {
/* NOTE that the following call loses
the position of pcur ! */
err = row_upd_check_references_constraints(
node, pcur, table, index, offsets, thr, mtr);
if (err != DB_SUCCESS) {
mtr_commit(mtr);
if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
}
return(err);
}
}
}
mtr_commit(mtr);
if (!heap) {
heap = mem_heap_create(500);
}
node->state = UPD_NODE_INSERT_CLUSTERED;
heap = mem_heap_create(1000);
entry = row_build_index_entry(node->upd_row, node->upd_ext,
index, heap);
@ -1665,23 +1746,104 @@ row_upd_clust_rec_by_insert(
row_upd_index_entry_sys_field(entry, index, DATA_TRX_ID, trx->id);
if (change_ownership) {
/* If we return from a lock wait, for example, we may have
extern fields marked as not-owned in entry (marked in the
if-branch above). We must unmark them, take the ownership
back. */
switch (node->state) {
default:
ut_error;
case UPD_NODE_INSERT_BLOB:
/* A lock wait occurred in row_ins_index_entry() in
the previous invocation of this function. Mark the
off-page columns in the entry inherited. */
btr_cur_unmark_dtuple_extern_fields(entry);
change_ownership = row_upd_clust_rec_by_insert_inherit(
NULL, NULL, entry, node->update);
ut_a(change_ownership);
/* fall through */
case UPD_NODE_INSERT_CLUSTERED:
/* A lock wait occurred in row_ins_index_entry() in
the previous invocation of this function. */
break;
case UPD_NODE_UPDATE_CLUSTERED:
/* This is the first invocation of the function where
we update the primary key. Delete-mark the old record
in the clustered index and prepare to insert a new entry. */
rec = btr_cur_get_rec(btr_cur);
offsets = rec_get_offsets(rec, index, NULL,
ULINT_UNDEFINED, &heap);
ut_ad(page_rec_is_user_rec(rec));
/* We must mark non-updated extern fields in entry as
inherited, so that a possible rollback will not free them. */
err = btr_cur_del_mark_set_clust_rec(
BTR_NO_LOCKING_FLAG, btr_cur_get_block(btr_cur),
rec, index, offsets, TRUE, thr, mtr);
if (err != DB_SUCCESS) {
err_exit:
mtr_commit(mtr);
mem_heap_free(heap);
return(err);
}
btr_cur_mark_dtuple_inherited_extern(entry, node->update);
/* If the the new row inherits externally stored
fields (off-page columns a.k.a. BLOBs) from the
delete-marked old record, mark them disowned by the
old record and owned by the new entry. */
if (rec_offs_any_extern(offsets)) {
change_ownership = row_upd_clust_rec_by_insert_inherit(
rec, offsets, entry, node->update);
if (change_ownership) {
btr_pcur_store_position(pcur, mtr);
}
}
if (check_ref) {
/* NOTE that the following call loses
the position of pcur ! */
err = row_upd_check_references_constraints(
node, pcur, table, index, offsets, thr, mtr);
if (err != DB_SUCCESS) {
goto err_exit;
}
}
}
mtr_commit(mtr);
err = row_ins_index_entry(index, entry,
node->upd_ext ? node->upd_ext->n_ext : 0,
TRUE, thr);
node->state = change_ownership
? UPD_NODE_INSERT_BLOB
: UPD_NODE_INSERT_CLUSTERED;
if (err == DB_SUCCESS && change_ownership) {
/* Mark the non-updated fields disowned by the old record. */
/* NOTE: this transaction has an x-lock on the record
and therefore other transactions cannot modify the
record when we have no latch on the page. In addition,
we assume that other query threads of the same
transaction do not modify the record in the meantime.
Therefore we can assert that the restoration of the
cursor succeeds. */
mtr_start(mtr);
if (!btr_pcur_restore_position(BTR_MODIFY_LEAF, pcur, mtr)) {
ut_error;
}
rec = btr_cur_get_rec(btr_cur);
offsets = rec_get_offsets(rec, index, offsets,
ULINT_UNDEFINED, &heap);
ut_ad(page_rec_is_user_rec(rec));
btr_cur_disown_inherited_fields(
btr_cur_get_page_zip(btr_cur),
rec, index, offsets, node->update, mtr);
mtr_commit(mtr);
}
mem_heap_free(heap);
return(err);
@ -1825,8 +1987,9 @@ row_upd_del_mark_clust_rec(
/* Mark the clustered index record deleted; we do not have to check
locks, because we assume that we have an x-lock on the record */
err = btr_cur_del_mark_set_clust_rec(BTR_NO_LOCKING_FLAG,
btr_cur, TRUE, thr, mtr);
err = btr_cur_del_mark_set_clust_rec(
BTR_NO_LOCKING_FLAG, btr_cur_get_block(btr_cur),
btr_cur_get_rec(btr_cur), index, offsets, TRUE, thr, mtr);
if (err == DB_SUCCESS && check_ref) {
/* NOTE that the following call loses the position of pcur ! */
@ -1973,7 +2136,8 @@ exit_func:
row_upd_store_row(node);
if (row_upd_changes_ord_field_binary(node->row, index, node->update)) {
if (row_upd_changes_ord_field_binary(node->row, node->ext, index,
node->update)) {
/* Update causes an ordering field (ordering fields within
the B-tree) of the clustered index record to change: perform
@ -2042,7 +2206,8 @@ row_upd(
}
if (node->state == UPD_NODE_UPDATE_CLUSTERED
|| node->state == UPD_NODE_INSERT_CLUSTERED) {
|| node->state == UPD_NODE_INSERT_CLUSTERED
|| node->state == UPD_NODE_INSERT_BLOB) {
log_free_check();
err = row_upd_clust_step(node, thr);

View file

@ -435,7 +435,7 @@ i_s_locks_row_validate(
/* record lock */
ut_ad(!strcmp("RECORD", row->lock_type));
ut_ad(row->lock_index != NULL);
ut_ad(row->lock_data != NULL);
/* row->lock_data == NULL if buf_page_try_get() == NULL */
ut_ad(row->lock_page != ULINT_UNDEFINED);
ut_ad(row->lock_rec != ULINT_UNDEFINED);
}
@ -498,7 +498,6 @@ fill_trx_row(
stmt = innobase_get_stmt(trx->mysql_thd, &stmt_len);
if (stmt != NULL) {
char query[TRX_I_S_TRX_QUERY_MAX_LEN + 1];
if (stmt_len > TRX_I_S_TRX_QUERY_MAX_LEN) {
@ -512,6 +511,8 @@ fill_trx_row(
cache->storage, stmt, stmt_len + 1,
MAX_ALLOWED_FOR_STORAGE(cache));
row->trx_query_cs = innobase_get_charset(trx->mysql_thd);
if (row->trx_query == NULL) {
return(FALSE);

View file

@ -79,7 +79,7 @@ ut_dbg_assertion_failed(
" or crashes, even\n"
"InnoDB: immediately after the mysqld startup, there may be\n"
"InnoDB: corruption in the InnoDB tablespace. Please refer to\n"
"InnoDB: " REFMAN "forcing-recovery.html\n"
"InnoDB: " REFMAN "forcing-innodb-recovery.html\n"
"InnoDB: about forcing recovery.\n", stderr);
#if defined(UNIV_SYNC_DEBUG) || !defined(UT_DBG_USE_ABORT)
ut_dbg_stop_threads = TRUE;