Commit 0a780db9 authored by marko's avatar marko

branches/zip: Merge 1575:1664 from trunk.

parent d3255c0b
......@@ -16,6 +16,9 @@
SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX")
SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX")
ADD_DEFINITIONS(-DMYSQL_SERVER -D_WIN32 -DWIN32 -D_LIB)
IF(EMBEDDED_ONLY)
ADD_DEFINITIONS(-DUSE_TLS)
ENDIF(EMBEDDED_ONLY)
INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/zlib
include
......
......@@ -56,7 +56,9 @@ noinst_HEADERS = include/btr0btr.h include/btr0btr.ic \
include/ha0ha.ic include/hash0hash.h \
include/hash0hash.ic include/ibuf0ibuf.h \
include/ibuf0ibuf.ic include/ibuf0types.h \
include/lock0iter.h \
include/lock0lock.h include/lock0lock.ic \
include/lock0priv.h include/lock0priv.ic \
include/lock0types.h include/log0log.h \
include/log0log.ic include/log0recv.h \
include/log0recv.ic include/mach0data.h \
......@@ -134,7 +136,8 @@ libinnobase_a_SOURCES = btr/btr0btr.c btr/btr0cur.c btr/btr0pcur.c \
eval/eval0eval.c eval/eval0proc.c \
fil/fil0fil.c fsp/fsp0fsp.c fut/fut0fut.c \
fut/fut0lst.c ha/ha0ha.c ha/hash0hash.c \
ibuf/ibuf0ibuf.c lock/lock0lock.c \
ibuf/ibuf0ibuf.c lock/lock0iter.c \
lock/lock0lock.c \
log/log0log.c log/log0recv.c mach/mach0data.c \
mem/mem0mem.c mem/mem0pool.c mtr/mtr0log.c \
mtr/mtr0mtr.c os/os0file.c os/os0proc.c \
......@@ -158,8 +161,8 @@ libinnobase_a_SOURCES = btr/btr0btr.c btr/btr0cur.c btr/btr0pcur.c \
ut/ut0ut.c ut/ut0vec.c ut/ut0wqueue.c \
handler/ha_innodb.cc
libinnobase_a_CXXFLAGS= $(AM_CFLAGS) -DMYSQL_SERVER
libinnobase_a_CFLAGS = $(AM_CFLAGS) -DMYSQL_SERVER
libinnobase_a_CXXFLAGS= $(AM_CFLAGS)
libinnobase_a_CFLAGS = $(AM_CFLAGS)
EXTRA_LTLIBRARIES = ha_innodb.la
pkglib_LTLIBRARIES = @plugin_innobase_shared_target@
......
......@@ -895,7 +895,7 @@ btr_search_guess_on_hash(
btr_search_n_succ++;
#endif
if (UNIV_LIKELY(!has_search_latch)
&& buf_block_peek_if_too_old(block)) {
&& buf_page_peek_if_too_old(&block->page)) {
buf_page_make_young(&block->page);
}
......
......@@ -1329,9 +1329,7 @@ buf_block_make_young(
/* Note that we read freed_page_clock's without holding any mutex:
this is allowed since the result is used only in heuristics */
if (buf_pool->freed_page_clock
>= buf_page_get_freed_page_clock(bpage)
+ 1 + (buf_pool->curr_size / 4)) {
if (buf_page_peek_if_too_old(bpage)) {
mutex_enter(&buf_pool->mutex);
/* There has been freeing activity in the LRU list:
......
......@@ -350,6 +350,18 @@ dict_table_get_col_name(
return(s);
}
/************************************************************************
Acquire the autoinc lock.*/
void
dict_table_autoinc_lock(
/*====================*/
dict_table_t* table)
{
mutex_enter(&table->autoinc_mutex);
}
/************************************************************************
Initializes the autoinc counter. It is not an error to initialize an already
initialized counter. */
......@@ -360,54 +372,8 @@ dict_table_autoinc_initialize(
dict_table_t* table, /* in: table */
ib_longlong value) /* in: next value to assign to a row */
{
mutex_enter(&(table->autoinc_mutex));
table->autoinc_inited = TRUE;
table->autoinc = value;
mutex_exit(&(table->autoinc_mutex));
}
/************************************************************************
Gets the next autoinc value (== autoinc counter value), 0 if not yet
initialized. If initialized, increments the counter by 1. */
ib_longlong
dict_table_autoinc_get(
/*===================*/
/* out: value for a new row, or 0 */
dict_table_t* table) /* in: table */
{
ib_longlong value;
mutex_enter(&(table->autoinc_mutex));
if (!table->autoinc_inited) {
value = 0;
} else {
value = table->autoinc;
table->autoinc = table->autoinc + 1;
}
mutex_exit(&(table->autoinc_mutex));
return(value);
}
/************************************************************************
Decrements the autoinc counter value by 1. */
void
dict_table_autoinc_decrement(
/*=========================*/
dict_table_t* table) /* in: table */
{
mutex_enter(&(table->autoinc_mutex));
table->autoinc = table->autoinc - 1;
mutex_exit(&(table->autoinc_mutex));
}
/************************************************************************
......@@ -422,32 +388,6 @@ dict_table_autoinc_read(
{
ib_longlong value;
mutex_enter(&(table->autoinc_mutex));
if (!table->autoinc_inited) {
value = 0;
} else {
value = table->autoinc;
}
mutex_exit(&(table->autoinc_mutex));
return(value);
}
/************************************************************************
Peeks the autoinc counter value, 0 if not yet initialized. Does not
increment the counter. The read not protected by any mutex! */
ib_longlong
dict_table_autoinc_peek(
/*====================*/
/* out: value of the counter */
dict_table_t* table) /* in: table */
{
ib_longlong value;
if (!table->autoinc_inited) {
value = 0;
......@@ -459,7 +399,7 @@ dict_table_autoinc_peek(
}
/************************************************************************
Updates the autoinc counter if the value supplied is equal or bigger than the
Updates the autoinc counter if the value supplied is greater than the
current value. If not inited, does nothing. */
void
......@@ -469,15 +409,21 @@ dict_table_autoinc_update(
dict_table_t* table, /* in: table */
ib_longlong value) /* in: value which was assigned to a row */
{
mutex_enter(&(table->autoinc_mutex));
if (table->autoinc_inited && value > table->autoinc) {
if (table->autoinc_inited) {
if (value >= table->autoinc) {
table->autoinc = value + 1;
}
table->autoinc = value;
}
}
/************************************************************************
Release the autoinc lock.*/
mutex_exit(&(table->autoinc_mutex));
void
dict_table_autoinc_unlock(
/*======================*/
dict_table_t* table) /* in: release autoinc lock for this table */
{
mutex_exit(&table->autoinc_mutex);
}
/**************************************************************************
......
......@@ -92,6 +92,11 @@ dict_mem_table_create(
mutex_create(&table->autoinc_mutex, SYNC_DICT_AUTOINC_MUTEX);
table->autoinc_inited = FALSE;
/* The actual increment value will be set by MySQL, we simply
default to 1 here.*/
table->autoinc_increment = 1;
#ifdef UNIV_DEBUG
table->magic_n = DICT_TABLE_MAGIC_N;
#endif /* UNIV_DEBUG */
......
......@@ -14,6 +14,9 @@ if [ $# -ne 2 ] ; then
die "Usage: export.sh revision-number-of-last-snapshot current-revision-number"
fi
START_REV=$(($1 + 1))
END_REV=$2
set +u
if test -z $EDITOR; then
die "\$EDITOR is not set"
......@@ -22,10 +25,11 @@ set -u
rm -rf to-mysql
mkdir to-mysql{,/storage,/patches,/mysql-test{,/t,/r,/include}}
svn log -v -r "$(($1 + 1)):BASE" > to-mysql/log
svn log -v -r "$START_REV:BASE" > to-mysql/log
svn export -q . to-mysql/storage/innobase
seq $(($1+1)) $2|while read REV
REV=$START_REV
while [ $REV -le $END_REV ]
do
PATCH=to-mysql/patches/r$REV.patch
svn log -v -r$REV > $PATCH
......@@ -35,6 +39,7 @@ do
else
rm $PATCH
fi
REV=$(($REV + 1))
done
cd to-mysql/storage/innobase
......
......@@ -2983,7 +2983,7 @@ will be able to insert new data to the database without running out the
tablespace. Only free extents are taken into account and we also subtract
the safety margin required by the above function fsp_reserve_free_extents. */
ulint
ullint
fsp_get_available_space_in_free_extents(
/*====================================*/
/* out: available space in kB */
......@@ -3056,10 +3056,12 @@ fsp_get_available_space_in_free_extents(
}
if (!zip_size) {
return(((n_free - reserve) * FSP_EXTENT_SIZE)
return((ullint) (n_free - reserve)
* FSP_EXTENT_SIZE
* (UNIV_PAGE_SIZE / 1024));
} else {
return(((n_free - reserve) * FSP_EXTENT_SIZE)
return((ullint) (n_free - reserve)
* FSP_EXTENT_SIZE
* (zip_size / 1024));
}
}
......
......@@ -36,22 +36,7 @@
#include "ha_innodb.h"
#include <mysql/plugin.h>
#ifdef MYSQL_SERVER
/* Define some macros until these functions are declared in <mysql/plugin.h>.
Once these functions are defined by MySQL, we may consider
removing -DMYSQL_SERVER from ../Makefile.am as well. */
#define thd_charset(thd) (thd)->charset()
#define thd_get_xid(thd,xid_) ((*xid_) = (thd)->transaction.xid_state.xid)
#define thd_memdup(thd,str,len) (thd)->memdup(str, len)
#define thd_killed(thd) (thd)->killed
#define thd_slave_thread(thd) (thd)->slave_thread
#define thd_query(thd) (&(thd)->query)
#define thd_non_transactional_update(thd) ((thd)->no_trans_update.all)
#define mysql_bin_log_file_name() mysql_bin_log.get_log_fname()
#define mysql_bin_log_file_pos() mysql_bin_log.get_log_file()->pos_in_file
#define mysql_tmpfile() fileno(tmpfile())/* BUGGY: leaks memory, Bug #3998 */
#define mysql_query_cache_invalidate4(a,b,c,d) query_cache.invalidate(a,b,c,d)
#else /* MYSQL_SERVER */
#ifndef MYSQL_SERVER
/* This is needed because of Bug #3596. Let us hope that pthread_mutex_t
is defined the same in both builds: the MySQL server and the InnoDB plugin. */
extern pthread_mutex_t LOCK_thread_count;
......@@ -81,33 +66,33 @@ typedef uchar mysql_byte;
/* Include necessary InnoDB headers */
extern "C" {
#include "univ.i"
#include "buf0buddy.h"
#include "os0file.h"
#include "os0thread.h"
#include "srv0start.h"
#include "srv0srv.h"
#include "trx0roll.h"
#include "trx0trx.h"
#include "trx0sys.h"
#include "mtr0mtr.h"
#include "row0ins.h"
#include "row0mysql.h"
#include "row0sel.h"
#include "row0upd.h"
#include "log0log.h"
#include "lock0lock.h"
#include "dict0crea.h"
#include "btr0cur.h"
#include "btr0btr.h"
#include "fsp0fsp.h"
#include "sync0sync.h"
#include "fil0fil.h"
#include "trx0xa.h"
#include "row0merge.h"
#include "thr0loc.h"
#include "dict0boot.h"
#include "ha_prototypes.h"
#include "../storage/innobase/include/univ.i"
#include "../storage/innobase/include/buf0buddy.h"
#include "../storage/innobase/include/os0file.h"
#include "../storage/innobase/include/os0thread.h"
#include "../storage/innobase/include/srv0start.h"
#include "../storage/innobase/include/srv0srv.h"
#include "../storage/innobase/include/trx0roll.h"
#include "../storage/innobase/include/trx0trx.h"
#include "../storage/innobase/include/trx0sys.h"
#include "../storage/innobase/include/mtr0mtr.h"
#include "../storage/innobase/include/row0ins.h"
#include "../storage/innobase/include/row0mysql.h"
#include "../storage/innobase/include/row0sel.h"
#include "../storage/innobase/include/row0upd.h"
#include "../storage/innobase/include/log0log.h"
#include "../storage/innobase/include/lock0lock.h"
#include "../storage/innobase/include/dict0crea.h"
#include "../storage/innobase/include/btr0cur.h"
#include "../storage/innobase/include/btr0btr.h"
#include "../storage/innobase/include/fsp0fsp.h"
#include "../storage/innobase/include/sync0sync.h"
#include "../storage/innobase/include/fil0fil.h"
#include "../storage/innobase/include/trx0xa.h"
#include "../storage/innobase/include/row0merge.h"
#include "../storage/innobase/include/thr0loc.h"
#include "../storage/innobase/include/dict0boot.h"
#include "../storage/innobase/include/ha_prototypes.h"
}
static long innobase_mirrored_log_groups, innobase_log_files_in_group,
......@@ -670,7 +655,7 @@ convert_error_code_to_mysql(
} else if (error == (int) DB_TABLE_NOT_FOUND) {
return(HA_ERR_KEY_NOT_FOUND);
return(HA_ERR_NO_SUCH_TABLE);
} else if (error == (int) DB_TOO_BIG_RECORD) {
......@@ -897,7 +882,28 @@ innobase_mysql_tmpfile(void)
/*========================*/
/* out: temporary file descriptor, or < 0 on error */
{
return(mysql_tmpfile());
int fd2 = -1;
File fd = mysql_tmpfile("ib");
if (fd >= 0) {
/* Copy the file descriptor, so that the additional resources
allocated by create_temp_file() can be freed by invoking
my_close().
Because the file descriptor returned by this function
will be passed to fdopen(), it will be closed by invoking
fclose(), which in turn will invoke close() instead of
my_close(). */
fd2 = dup(fd);
if (fd2 < 0) {
DBUG_PRINT("error",("Got error %d on dup",fd2));
my_errno=errno;
my_error(EE_OUT_OF_FILERESOURCES,
MYF(ME_BELL+ME_WAITTANG),
"ib*", my_errno);
}
my_close(fd, MYF(MY_WME));
}
return(fd2);
}
/*************************************************************************
......@@ -980,6 +986,7 @@ ha_innobase::ha_innobase(handlerton *hton, TABLE_SHARE *table_arg)
HA_CAN_SQL_HANDLER |
HA_PRIMARY_KEY_REQUIRED_FOR_POSITION |
HA_PRIMARY_KEY_IN_READ_INDEX |
HA_BINLOG_ROW_CAPABLE |
HA_CAN_GEOMETRY | HA_PARTIAL_COLUMN_READ |
HA_TABLE_SCAN_ON_INDEX),
start_of_scan(0),
......@@ -1671,7 +1678,6 @@ innobase_init(
DBUG_RETURN(FALSE);
error:
innobase_hton->state = SHOW_OPTION_DISABLED;
DBUG_RETURN(TRUE);
}
......@@ -1921,6 +1927,8 @@ retry:
trx_mark_sql_stat_end(trx);
}
trx->n_autoinc_rows = 0; /* Reset the number AUTO-INC rows required */
if (trx->declared_to_be_inside_innodb) {
/* Release our possible ticket in the FIFO */
......@@ -2301,6 +2309,21 @@ ha_innobase::get_row_type() const
return(ROW_TYPE_NOT_USED);
}
/********************************************************************
Get the table flags to use for the statement. */
handler::Table_flags
ha_innobase::table_flags() const
{
/* Need to use tx_isolation here since table flags is (also)
called before prebuilt is inited. */
ulong const tx_isolation = thd_tx_isolation(current_thd);
if (tx_isolation <= ISO_READ_COMMITTED)
return int_table_flags;
return int_table_flags | HA_BINLOG_STMT_CAPABLE;
}
/********************************************************************
Gives the file extension of an InnoDB single-table tablespace. */
static const char* ha_innobase_exts[] = {
......@@ -3328,6 +3351,93 @@ skip_field:
}
}
/************************************************************************
This special handling is really to overcome the limitations of MySQL's
binlogging. We need to eliminate the non-determinism that will arise in
INSERT ... SELECT type of statements, since MySQL binlog only stores the
min value of the autoinc interval. Once that is fixed we can get rid of
the special lock handling.*/
ulong
ha_innobase::innobase_autoinc_lock(void)
/*====================================*/
/* out: DB_SUCCESS if all OK else
error code */
{
ulint error = DB_SUCCESS;
if (thd_sql_command(user_thd) == SQLCOM_INSERT) {
dict_table_autoinc_lock(prebuilt->table);
/* We peek at the dict_table_t::auto_inc_lock to check if
another statement has locked it */
if (prebuilt->trx->auto_inc_lock != NULL) {
/* Release the mutex to avoid deadlocks */
dict_table_autoinc_unlock(prebuilt->table);
goto acquire_auto_inc_lock;
}
} else {
acquire_auto_inc_lock:
error = row_lock_table_autoinc_for_mysql(prebuilt);
if (error == DB_SUCCESS) {
dict_table_autoinc_lock(prebuilt->table);
}
}
return(ulong(error));
}
/************************************************************************
Reset the autoinc value in the table.*/
ulong
ha_innobase::innobase_reset_autoinc(
/*================================*/
/* out: DB_SUCCESS if all went well
else error code */
ulonglong autoinc) /* in: value to store */
{
ulint error;
error = innobase_autoinc_lock();
if (error == DB_SUCCESS) {
dict_table_autoinc_initialize(prebuilt->table, autoinc);
dict_table_autoinc_unlock(prebuilt->table);
}
return(ulong(error));
}
/************************************************************************
Store the autoinc value in the table. The autoinc value is only set if
it's greater than the existing autoinc value in the table.*/
ulong
ha_innobase::innobase_set_max_autoinc(
/*==================================*/
/* out: DB_SUCCES if all went well
else error code */
ulonglong auto_inc) /* in: value to store */
{
ulint error;
error = innobase_autoinc_lock();
if (error == DB_SUCCESS) {
dict_table_autoinc_update(prebuilt->table, auto_inc);
dict_table_autoinc_unlock(prebuilt->table);
}
return(ulong(error));
}
/************************************************************************
Stores a row in an InnoDB database, to the table specified in this
handle. */
......@@ -3338,9 +3448,7 @@ ha_innobase::write_row(
/* out: error code */
mysql_byte* record) /* in: a row in MySQL format */
{
int error;
longlong auto_inc;
longlong dummy;
int error = 0;
ibool auto_inc_used= FALSE;
ulint sql_command;
trx_t* trx = thd_to_trx(user_thd);
......@@ -3439,62 +3547,20 @@ no_commit:
num_write_row++;
/* This is the case where the table has an auto-increment column */
if (table->next_number_field && record == table->record[0]) {
/* This is the case where the table has an
auto-increment column */
/* Initialize the auto-inc counter if it has not been
initialized yet */
if (0 == dict_table_autoinc_peek(prebuilt->table)) {
/* This call initializes the counter */
error = innobase_read_and_init_auto_inc(&dummy);
if (error) {
/* Deadlock or lock wait timeout */
if ((error = update_auto_increment())) {
goto func_exit;
}
/* We have to set sql_stat_start to TRUE because
the above call probably has called a select, and
has reset that flag; row_insert_for_mysql has to
know to set the IX intention lock on the table,
something it only does at the start of each
statement */
prebuilt->sql_stat_start = TRUE;
}
/* We have to use the transactional lock mechanism on the
auto-inc counter of the table to ensure that replication and
roll-forward of the binlog exactly imitates also the given
auto-inc values. The lock is released at each SQL statement's
end. This lock also prevents a race where two threads would
call ::get_auto_increment() simultaneously. */
error = row_lock_table_autoinc_for_mysql(prebuilt);
if (error != DB_SUCCESS) {
/* Deadlock or lock wait timeout */
error = convert_error_code_to_mysql(error, user_thd);
goto func_exit;
}
/* We must use the handler code to update the auto-increment
value to be sure that we increment it correctly. */
if ((error= update_auto_increment()))
goto func_exit;
auto_inc_used = 1;
auto_inc_used = TRUE;
}
if (prebuilt->mysql_template == NULL
|| prebuilt->template_type != ROW_MYSQL_WHOLE_ROW) {
/* Build the template used in converting quickly between
the two database formats */
......@@ -3505,40 +3571,63 @@ no_commit:
error = row_insert_for_mysql((byte*) record, prebuilt);
if (error == DB_SUCCESS && auto_inc_used) {
/* Handle duplicate key errors */
if (auto_inc_used) {
ulonglong auto_inc;
/* Fetch the value that was set in the autoincrement field */
/* Note the number of rows processed for this statement, used
by get_auto_increment() to determine the number of AUTO-INC
values to reserve. This is only useful for a mult-value INSERT
and is a statement level counter.*/
if (trx->n_autoinc_rows > 0) {
--trx->n_autoinc_rows;
}
/* Get the value that MySQL attempted to store in the table.*/
auto_inc = table->next_number_field->val_int();
if (auto_inc != 0) {
/* This call will update the counter according to the
value that was inserted in the table */
switch (error) {
case DB_DUPLICATE_KEY:
dict_table_autoinc_update(prebuilt->table, auto_inc);
/* A REPLACE command and LOAD DATA INFILE REPLACE
handle a duplicate key error themselves, but we
must update the autoinc counter if we are performing
those statements. */
switch (sql_command) {
case SQLCOM_LOAD:
if ((trx->duplicates
& (TRX_DUP_IGNORE | TRX_DUP_REPLACE))) {
goto set_max_autoinc;
}
break;
case SQLCOM_REPLACE:
case SQLCOM_INSERT_SELECT:
case SQLCOM_REPLACE_SELECT:
goto set_max_autoinc;
break;
default:
break;
}
/* A REPLACE command and LOAD DATA INFILE REPLACE handle a duplicate
key error themselves, and we must update the autoinc counter if we are
performing those statements. */
break;
if (error == DB_DUPLICATE_KEY && auto_inc_used
&& (sql_command == SQLCOM_REPLACE
|| sql_command == SQLCOM_REPLACE_SELECT
|| (sql_command == SQLCOM_INSERT
&& ((trx->duplicates
& (TRX_DUP_IGNORE | TRX_DUP_REPLACE))
== TRX_DUP_IGNORE))
|| (sql_command == SQLCOM_LOAD
&& ((trx->duplicates
& (TRX_DUP_IGNORE | TRX_DUP_REPLACE))
== (TRX_DUP_IGNORE | TRX_DUP_REPLACE))))) {
case DB_SUCCESS:
/* If the actual value inserted is greater than
the upper limit of the interval, then we try and
update the table upper limit. Note: last_value
will be 0 if get_auto_increment() was not called.*/
auto_inc = table->next_number_field->val_int();
if (auto_inc > prebuilt->last_value) {
set_max_autoinc:
auto_inc += prebuilt->table->autoinc_increment;
if (auto_inc != 0) {
dict_table_autoinc_update(prebuilt->table, auto_inc);
innobase_set_max_autoinc(auto_inc);
}
break;
}
}
......@@ -3546,8 +3635,6 @@ no_commit:
error = convert_error_code_to_mysql(error, user_thd);
/* Tell InnoDB server that there might be work for
utility threads: */
func_exit:
innobase_active_small();
......@@ -3749,6 +3836,32 @@ ha_innobase::update_row(
error = row_update_for_mysql((byte*) old_row, prebuilt);
/* We need to do some special AUTOINC handling for the following case:
INSERT INTO t (c1,c2) VALUES(x,y) ON DUPLICATE KEY UPDATE ...
We need to use the AUTOINC counter that was actually used by
MySQL in the UPDATE statement, which can be different from the
value used in the INSERT statement.*/
if (error == DB_SUCCESS
&& table->next_number_field
&& new_row == table->record[0]
&& thd_sql_command(user_thd) == SQLCOM_INSERT
&& (trx->duplicates & (TRX_DUP_IGNORE | TRX_DUP_REPLACE))
== TRX_DUP_IGNORE) {
longlong auto_inc;
auto_inc = table->next_number_field->val_int();
if (auto_inc != 0) {
auto_inc += prebuilt->table->autoinc_increment;
innobase_set_max_autoinc(auto_inc);
}
}
innodb_srv_conc_exit_innodb(trx);
error = convert_error_code_to_mysql(error, user_thd);
......@@ -3777,6 +3890,19 @@ ha_innobase::delete_row(
ut_a(prebuilt->trx == trx);
/* Only if the table has an AUTOINC column */
if (table->found_next_number_field && record == table->record[0]) {
ulonglong dummy = 0;
error = innobase_get_auto_increment(&dummy);
if (error == DB_SUCCESS) {
dict_table_autoinc_unlock(prebuilt->table);
} else {
goto error_exit;
}
}
if (!prebuilt->upd_node) {
row_get_prebuilt_update_vector(prebuilt);
}
......@@ -3791,6 +3917,7 @@ ha_innobase::delete_row(
innodb_srv_conc_exit_innodb(trx);
error_exit:
error = convert_error_code_to_mysql(error, user_thd);
/* Tell the InnoDB server that there might be work for
......@@ -4135,41 +4262,66 @@ ha_innobase::index_read_last(
}
/************************************************************************
Changes the active index of a handle. */
Get the index for a handle. Does not change active index.*/
int
ha_innobase::change_active_index(
/*=============================*/
/* out: 0 or error code */
uint keynr) /* in: use this index; MAX_KEY means always clustered
index, even if it was internally generated by
InnoDB */
dict_index_t*
ha_innobase::innobase_get_index(
/*============================*/
/* out: NULL or index instance. */
uint keynr) /* in: use this index; MAX_KEY means always
clustered index, even if it was internally
generated by InnoDB */
{
KEY* key = 0;
DBUG_ENTER("change_active_index");
dict_index_t* index = 0;
DBUG_ENTER("innobase_get_index");
ha_statistic_increment(&SSV::ha_read_key_count);
ut_ad(user_thd == ha_thd());
ut_a(prebuilt->trx == thd_to_trx(user_thd));
active_index = keynr;
if (keynr != MAX_KEY && table->s->keys > 0) {
key = table->key_info + active_index;
key = table->key_info + keynr;
prebuilt->index = dict_table_get_index_on_name(
prebuilt->table, key->name);
index = dict_table_get_index_on_name(prebuilt->table,
key->name);
} else {
prebuilt->index = dict_table_get_first_index(prebuilt->table);
index = dict_table_get_first_index(prebuilt->table);
}
if (!prebuilt->index) {
if (!index) {
sql_print_error(
"Innodb could not find key n:o %u with name %s "
"from dict cache for table %s",
keynr, key ? key->name : "NULL",
prebuilt->table->name);
}
DBUG_RETURN(index);
}
/************************************************************************
Changes the active index of a handle. */
int
ha_innobase::change_active_index(
/*=============================*/
/* out: 0 or error code */
uint keynr) /* in: use this index; MAX_KEY means always clustered
index, even if it was internally generated by
InnoDB */
{
DBUG_ENTER("change_active_index");
ut_ad(user_thd == ha_thd());
ut_a(prebuilt->trx == thd_to_trx(user_thd));
active_index = keynr;
prebuilt->index = innobase_get_index(keynr);
if (!prebuilt->index) {
DBUG_RETURN(1);
}
......@@ -5022,7 +5174,10 @@ ha_innobase::create(
maximum value in the column. */
auto_inc_value = create_info->auto_increment_value;
dict_table_autoinc_lock(innobase_table);
dict_table_autoinc_initialize(innobase_table, auto_inc_value);
dict_table_autoinc_unlock(innobase_table);
}
/* Tell the InnoDB server that there might be work for
......@@ -5943,8 +6098,8 @@ ha_innobase::update_table_comment(
mutex_enter(&srv_dict_tmpfile_mutex);
rewind(srv_dict_tmpfile);
fprintf(srv_dict_tmpfile, "InnoDB free: %lu kB",
(ulong) fsp_get_available_space_in_free_extents(
fprintf(srv_dict_tmpfile, "InnoDB free: %llu kB",
fsp_get_available_space_in_free_extents(
prebuilt->table->space));
dict_print_info_on_foreign_keys(FALSE, srv_dict_tmpfile,
......@@ -6068,8 +6223,8 @@ ha_innobase::get_foreign_key_list(THD *thd, List<FOREIGN_KEY_INFO> *f_key_list)
while (tmp_buff[i] != '/')
i++;
tmp_buff+= i + 1;
f_key_info.forein_id= make_lex_string(thd, 0, tmp_buff,
(uint) strlen(tmp_buff), 1);
f_key_info.forein_id = thd_make_lex_string(thd, 0,
tmp_buff, (uint) strlen(tmp_buff), 1);
tmp_buff= foreign->referenced_table_name;
/* Database name */
......@@ -6081,22 +6236,23 @@ ha_innobase::get_foreign_key_list(THD *thd, List<FOREIGN_KEY_INFO> *f_key_list)
}
db_name[i]= 0;
ulen= filename_to_tablename(db_name, uname, sizeof(uname));
f_key_info.referenced_db= make_lex_string(thd, 0, uname, ulen, 1);
f_key_info.referenced_db = thd_make_lex_string(thd, 0,
uname, ulen, 1);
/* Table name */
tmp_buff+= i + 1;
ulen= filename_to_tablename(tmp_buff, uname, sizeof(uname));
f_key_info.referenced_table= make_lex_string(thd, 0, uname,
ulen, 1);
f_key_info.referenced_table = thd_make_lex_string(thd, 0,
uname, ulen, 1);
for (i= 0;;) {
tmp_buff= foreign->foreign_col_names[i];
name= make_lex_string(thd, name, tmp_buff,
(uint) strlen(tmp_buff), 1);
name = thd_make_lex_string(thd, name,
tmp_buff, (uint) strlen(tmp_buff), 1);
f_key_info.foreign_fields.push_back(name);
tmp_buff= foreign->referenced_col_names[i];
name= make_lex_string(thd, name, tmp_buff,
(uint) strlen(tmp_buff), 1);
name = thd_make_lex_string(thd, name,
tmp_buff, (uint) strlen(tmp_buff), 1);
f_key_info.referenced_fields.push_back(name);
if (++i >= foreign->n_fields)
break;
......@@ -6123,8 +6279,8 @@ ha_innobase::get_foreign_key_list(THD *thd, List<FOREIGN_KEY_INFO> *f_key_list)
length=8;
tmp_buff= "RESTRICT";
}
f_key_info.delete_method= make_lex_string(thd, f_key_info.delete_method,
tmp_buff, length, 1);
f_key_info.delete_method = thd_make_lex_string(
thd, f_key_info.delete_method, tmp_buff, length, 1);
if (foreign->type & DICT_FOREIGN_ON_UPDATE_CASCADE)
......@@ -6147,19 +6303,19 @@ ha_innobase::get_foreign_key_list(THD *thd, List<FOREIGN_KEY_INFO> *f_key_list)
length=8;
tmp_buff= "RESTRICT";
}
f_key_info.update_method= make_lex_string(thd, f_key_info.update_method,
tmp_buff, length, 1);
f_key_info.update_method = thd_make_lex_string(
thd, f_key_info.update_method, tmp_buff, length, 1);
if (foreign->referenced_index &&
foreign->referenced_index->name)
{
f_key_info.referenced_key_name=
make_lex_string(thd, f_key_info.referenced_key_name,
f_key_info.referenced_key_name = thd_make_lex_string(
thd, f_key_info.referenced_key_name,
foreign->referenced_index->name,
strlen(foreign->referenced_index->name), 1);
}
FOREIGN_KEY_INFO *pf_key_info = (FOREIGN_KEY_INFO *)
thd_memdup(thd, &f_key_info, sizeof f_key_info);
thd_memdup(thd, &f_key_info, sizeof(FOREIGN_KEY_INFO));
f_key_list->push_back(pf_key_info);
foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
}
......@@ -6422,6 +6578,29 @@ ha_innobase::external_lock(
update_thd(thd);
/* Statement based binlogging does not work in isolation level
READ UNCOMMITTED and READ COMMITTED since the necessary
locks cannot be taken. In this case, we print an
informative error message and return with an error. */
if (lock_type == F_WRLCK)
{
ulong const binlog_format= thd_binlog_format(thd);
ulong const tx_isolation = thd_tx_isolation(current_thd);
if (tx_isolation <= ISO_READ_COMMITTED &&
binlog_format == BINLOG_FORMAT_STMT)
{
char buf[256];
my_snprintf(buf, sizeof(buf),
"Transaction level '%s' in"
" InnoDB is not safe for binlog mode '%s'",
tx_isolation_names[tx_isolation],
binlog_format_names[binlog_format]);
my_error(ER_BINLOG_LOGGING_IMPOSSIBLE, MYF(0), buf);
DBUG_RETURN(HA_ERR_LOGGING_IMPOSSIBLE);
}
}
trx = prebuilt->trx;
prebuilt->sql_stat_start = TRUE;
......@@ -6666,10 +6845,6 @@ innodb_show_status(
DBUG_ENTER("innodb_show_status");
if (hton->state != SHOW_OPTION_YES) {
DBUG_RETURN(FALSE);
}
trx = check_trx_exists(thd);
innobase_release_stat_resources(trx);
......@@ -7091,18 +7266,6 @@ ha_innobase::store_lock(
&& !thd_tablespace_op(thd)
&& sql_command != SQLCOM_TRUNCATE
&& sql_command != SQLCOM_OPTIMIZE
#ifdef __WIN__
/* For alter table on win32 for successful
operation completion it is used TL_WRITE(=10) lock
instead of TL_WRITE_ALLOW_READ(=6), however here
in innodb handler TL_WRITE is lifted to
TL_WRITE_ALLOW_WRITE, which causes race condition
when several clients do alter table simultaneously
(bug #17264). This fix avoids the problem. */
&& sql_command != SQLCOM_ALTER_TABLE
#endif
&& sql_command != SQLCOM_CREATE_TABLE) {
lock_type = TL_WRITE_ALLOW_WRITE;
......@@ -7141,15 +7304,15 @@ the value of the auto-inc counter. */
int
ha_innobase::innobase_read_and_init_auto_inc(
/*=========================================*/
/* out: 0 or error code: deadlock or lock wait
timeout */
longlong* ret) /* out: auto-inc value */
/* out: 0 or error code:
deadlock or lock wait timeout */
longlong* value) /* out: the autoinc value */
{
longlong auto_inc;
ulint old_select_lock_type;
ibool trx_was_not_started = FALSE;
ibool stmt_start;
int error;
int mysql_error = 0;
dict_table_t* innodb_table = prebuilt->table;
ibool trx_was_not_started = FALSE;
ut_a(prebuilt);
ut_a(prebuilt->table);
......@@ -7170,116 +7333,117 @@ ha_innobase::innobase_read_and_init_auto_inc(
trx_search_latch_release_if_reserved(prebuilt->trx);
auto_inc = dict_table_autoinc_read(prebuilt->table);
if (auto_inc != 0) {
/* Already initialized */
*ret = auto_inc;
dict_table_autoinc_lock(prebuilt->table);
error = 0;
auto_inc = dict_table_autoinc_read(prebuilt->table);
goto func_exit_early;
/* Was the AUTOINC counter reset during normal processing, if
so then we simply start count from 1. No need to go to the index.*/
if (auto_inc == 0 && innodb_table->autoinc_inited) {
++auto_inc;
dict_table_autoinc_initialize(innodb_table, auto_inc);
}
error = row_lock_table_autoinc_for_mysql(prebuilt);
if (auto_inc == 0) {
dict_index_t* index;
ulint error = DB_SUCCESS;
const char* autoinc_col_name;
if (error != DB_SUCCESS) {
error = convert_error_code_to_mysql(error, user_thd);
ut_a(!innodb_table->autoinc_inited);
goto func_exit_early;
}
index = innobase_get_index(table->s->next_number_index);
/* Check again if someone has initialized the counter meanwhile */
auto_inc = dict_table_autoinc_read(prebuilt->table);
autoinc_col_name = table->found_next_number_field->field_name;
if (auto_inc != 0) {
*ret = auto_inc;
error = row_search_max_autoinc(
index, autoinc_col_name, &auto_inc);
error = 0;
if (error == DB_SUCCESS) {
++auto_inc;
dict_table_autoinc_initialize(innodb_table, auto_inc);
} else {
fprintf(stderr, " InnoDB error: Couldn't read the "
"max AUTOINC value from index (%s).\n",
index->name);
goto func_exit_early;
mysql_error = 1;
}
}
(void) extra(HA_EXTRA_KEYREAD);
index_init(table->s->next_number_index, 1);
*value = auto_inc;
/* Starting from 5.0.9, we use a consistent read to read the auto-inc
column maximum value. This eliminates the spurious deadlocks caused
by the row X-lock that we previously used. Note the following flaw
in our algorithm: if some other user meanwhile UPDATEs the auto-inc
column, our consistent read will not return the largest value. We
accept this flaw, since the deadlocks were a bigger trouble. */
dict_table_autoinc_unlock(prebuilt->table);
/* Fetch all the columns in the key */
/* Since MySQL does not seem to call autocommit after SHOW TABLE
STATUS (even if we would register the trx here), we commit our
transaction here if it was started here. This is to eliminate a
dangling transaction. If the user had AUTOCOMMIT=0, then SHOW
TABLE STATUS does leave a dangling transaction if the user does not
himself call COMMIT. */
prebuilt->hint_need_to_fetch_extra_cols = ROW_RETRIEVE_ALL_COLS;
if (trx_was_not_started) {
old_select_lock_type = prebuilt->select_lock_type;
prebuilt->select_lock_type = LOCK_NONE;
innobase_commit_low(prebuilt->trx);
}
/* Eliminate an InnoDB error print that happens when we try to SELECT
from a table when no table has been locked in ::external_lock(). */
prebuilt->trx->n_mysql_tables_in_use++;
prebuilt->sql_stat_start = stmt_start;
error = index_last(table->record[1]);
return(mysql_error);
}
prebuilt->trx->n_mysql_tables_in_use--;
prebuilt->select_lock_type = old_select_lock_type;
/*******************************************************************************
Read the next autoinc value, initialize the table if it's not initialized.
On return if there is no error then the tables AUTOINC lock is locked.*/
if (error) {
if (error == HA_ERR_END_OF_FILE) {
/* The table was empty, initialize to 1 */
auto_inc = 1;
ulong
ha_innobase::innobase_get_auto_increment(
ulonglong* value) /* out: autoinc value */
{
ulint error;
error = 0;
} else {
/* This should not happen in a consistent read */
sql_print_error("Consistent read of auto-inc column "
"returned %lu", (ulong) error);
auto_inc = -1;
do {
error = innobase_autoinc_lock();
goto func_exit;
}
} else {
/* Initialize to max(col) + 1; we use
'found_next_number_field' below because MySQL in SHOW TABLE
STATUS does not seem to set 'next_number_field'. The comment
in table.h says that 'next_number_field' is set when it is
'active'.
Since 5.1 MySQL enforces that we announce fields which we will
read; as we only do a val_*() call, dbug_tmp_use_all_columns()
with read_set is sufficient. */
if (error == DB_SUCCESS) {
ib_longlong autoinc;
my_bitmap_map *old_map;
old_map= dbug_tmp_use_all_columns(table, table->read_set);
auto_inc = (longlong) table->found_next_number_field->
val_int_offset(table->s->rec_buff_length) + 1;
dbug_tmp_restore_column_map(table->read_set, old_map);
}
/* Determine the first value of the interval */
autoinc = dict_table_autoinc_read(prebuilt->table);
dict_table_autoinc_initialize(prebuilt->table, auto_inc);
/* We need to initialize the AUTO-INC value, for
that we release all locks.*/
if (autoinc <= 0) {
trx_t* trx;
func_exit:
(void) extra(HA_EXTRA_NO_KEYREAD);
trx = prebuilt->trx;
dict_table_autoinc_unlock(prebuilt->table);
index_end();
if (trx->auto_inc_lock) {
/* If we had reserved the AUTO-INC
lock in this SQL statement we release
it before retrying.*/
row_unlock_table_autoinc_for_mysql(trx);
}
*ret = auto_inc;
/* Just to make sure */
ut_a(!trx->auto_inc_lock);
func_exit_early:
/* Since MySQL does not seem to call autocommit after SHOW TABLE
STATUS (even if we would register the trx here), we commit our
transaction here if it was started here. This is to eliminate a
dangling transaction. If the user had AUTOCOMMIT=0, then SHOW
TABLE STATUS does leave a dangling transaction if the user does not
himself call COMMIT. */
int mysql_error;
if (trx_was_not_started) {
mysql_error = innobase_read_and_init_auto_inc(
&autoinc);
innobase_commit_low(prebuilt->trx);
if (!mysql_error) {
/* Should have read the proper value */
ut_a(autoinc > 0);
} else {
error = DB_ERROR;
}
prebuilt->sql_stat_start = stmt_start;
} else {
*value = (ulonglong) autoinc;
}
}
} while (*value == 0 && error == DB_SUCCESS);
return(error);
}
......@@ -7292,37 +7456,87 @@ auto-inc counter in *first_value, and ULONGLONG_MAX in *nb_reserved_values (as
we have a table-level lock). offset, increment, nb_desired_values are ignored.
*first_value is set to -1 if error (deadlock or lock wait timeout) */
void ha_innobase::get_auto_increment(
void
ha_innobase::get_auto_increment(
/*=================================*/
ulonglong offset, /* in */
ulonglong increment, /* in */
ulonglong nb_desired_values, /* in */
ulonglong *first_value, /* out */
ulonglong *nb_reserved_values) /* out */
ulonglong offset, /* in: */
ulonglong increment, /* in: table autoinc increment */
ulonglong nb_desired_values, /* in: number of values reqd */
ulonglong *first_value, /* out: the autoinc value */
ulonglong *nb_reserved_values) /* out: count of reserved values */
{
longlong nr;
int error;
ulint error;
ulonglong autoinc = 0;
/* Prepare prebuilt->trx in the table handle */
update_thd(ha_thd());
error = innobase_read_and_init_auto_inc(&nr);
error = innobase_get_auto_increment(&autoinc);
if (error) {
/* This should never happen in the current (5.0.6) code, since
we call this function only after the counter has been
initialized. */
if (error != DB_SUCCESS) {
/* This should never happen in the code > ver 5.0.6,
since we call this function only after the counter
has been initialized. */
ut_print_timestamp(stderr);
sql_print_error("Error %lu in ::get_auto_increment()",
(ulong) error);
*first_value= (~(ulonglong) 0);
sql_print_error("Error %lu in ::get_auto_increment()", error);
*first_value = (~(ulonglong) 0);
return;
}
*first_value= (ulonglong) nr;
/* table-level autoinc lock reserves up to +inf */
*nb_reserved_values= ULONGLONG_MAX;
/* This is a hack, since nb_desired_values seems to be accurate only
for the first call to get_auto_increment() for multi-row INSERT and
meaningless for other statements e.g, LOAD etc. Subsequent calls to
this method for the same statement results in different values which
don't make sense. Therefore we store the value the first time we are
called and count down from that as rows are written (see write_row()).
We make one exception, if the *first_value is precomputed by MySQL
we use that value. And set the number of reserved values to 1 if
this is the first time we were called for the SQL statement, this
will force MySQL to call us for the next value. If we are in the
middle of a multi-row insert we preserve the existing counter.*/
if (*first_value == 0) {
/* Called for the first time ? */
if (prebuilt->trx->n_autoinc_rows == 0) {
prebuilt->trx->n_autoinc_rows = nb_desired_values;
/* It's possible for nb_desired_values to be 0:
e.g., INSERT INTO T1(C) SELECT C FROM T2; */
if (nb_desired_values == 0) {
++prebuilt->trx->n_autoinc_rows;
}
}
*first_value = autoinc;
} else if (prebuilt->trx->n_autoinc_rows == 0) {
prebuilt->trx->n_autoinc_rows = 1;
}
ut_a(prebuilt->trx->n_autoinc_rows > 0);
*nb_reserved_values = prebuilt->trx->n_autoinc_rows;
/* Compute the last value in the interval */
prebuilt->last_value = *first_value + (*nb_reserved_values * increment);
ut_a(prebuilt->last_value >= *first_value);
/* Update the table autoinc variable */
dict_table_autoinc_update(prebuilt->table, prebuilt->last_value);
/* The increment to be used to increase the AUTOINC value, we use
this in write_row() and update_row() to increase the autoinc counter
for columns that are filled by the user.*/
prebuilt->table->autoinc_increment = increment;
dict_table_autoinc_unlock(prebuilt->table);
}
/* See comment in handler.h */
......@@ -7343,7 +7557,7 @@ ha_innobase::reset_auto_increment(ulonglong value)
DBUG_RETURN(error);
}
dict_table_autoinc_initialize(prebuilt->table, value);
innobase_reset_autoinc(value);
DBUG_RETURN(0);
}
......@@ -7596,7 +7810,7 @@ innobase_xa_prepare(
return(0);
}
thd_get_xid(thd, &trx->xid);
thd_get_xid(thd, (MYSQL_XID*) &trx->xid);
/* Release a possible FIFO ticket and search latch. Since we will
reserve the kernel mutex, we have to release the search system latch
......@@ -7629,6 +7843,7 @@ innobase_xa_prepare(
row_unlock_table_autoinc_for_mysql(trx);
}
/* Store the current undo_no of the transaction so that we
know where to roll back if we have to roll back the next
SQL statement */
......
......@@ -32,7 +32,10 @@ typedef struct st_innobase_share {
} INNOBASE_SHARE;
struct dict_index_struct;
struct row_prebuilt_struct;
typedef struct dict_index_struct dict_index_t;
typedef struct row_prebuilt_struct row_prebuilt_t;
/* The class defining a handle to an Innodb table */
......@@ -54,7 +57,7 @@ class ha_innobase: public handler
ulong upd_and_key_val_buff_len;
/* the length of each of the previous
two buffers */
ulong int_table_flags;
Table_flags int_table_flags;
uint primary_key;
ulong start_of_scan; /* this is set to 1 when we are
starting a table scan but have not
......@@ -70,6 +73,11 @@ class ha_innobase: public handler
int change_active_index(uint keynr);
int general_fetch(uchar* buf, uint direction, uint match_mode);
int innobase_read_and_init_auto_inc(longlong* ret);
ulong innobase_autoinc_lock();
ulong innobase_set_max_autoinc(ulonglong auto_inc);
ulong innobase_reset_autoinc(ulonglong auto_inc);
ulong innobase_get_auto_increment(ulonglong* value);
dict_index_t* innobase_get_index(uint keynr);
/* Init values for the class: */
public:
......@@ -84,7 +92,7 @@ class ha_innobase: public handler
const char* table_type() const { return("InnoDB");}
const char *index_type(uint key_number) { return "BTREE"; }
const char** bas_ext() const;
ulonglong table_flags() const { return int_table_flags; }
Table_flags table_flags() const;
ulong index_flags(uint idx, uint part, bool all_parts) const {
return(HA_READ_NEXT | HA_READ_PREV | HA_READ_ORDER
| HA_READ_RANGE | HA_KEYREAD_ONLY);
......@@ -191,6 +199,52 @@ class ha_innobase: public handler
uint table_changes);
};
/* Some accessor functions which the InnoDB plugin needs, but which
can not be added to mysql/plugin.h as part of the public interface;
the definitions are bracketed with #ifdef INNODB_COMPATIBILITY_HOOKS */
#ifndef INNODB_COMPATIBILITY_HOOKS
#error InnoDB needs MySQL to be built with #define INNODB_COMPATIBILITY_HOOKS
#endif
extern "C" {
struct charset_info_st *thd_charset(MYSQL_THD thd);
char **thd_query(MYSQL_THD thd);
/** Get the file name of the MySQL binlog.
* @return the name of the binlog file
*/
const char* mysql_bin_log_file_name(void);
/** Get the current position of the MySQL binlog.
* @return byte offset from the beginning of the binlog
*/
ulonglong mysql_bin_log_file_pos(void);
/**
Check if a user thread is a replication slave thread
@param thd user thread
@retval 0 the user thread is not a replication slave thread
@retval 1 the user thread is a replication slave thread
*/
int thd_slave_thread(const MYSQL_THD thd);
/**
Check if a user thread is running a non-transactional update
@param thd user thread
@retval 0 the user thread is not running a non-transactional update
@retval 1 the user thread is running a non-transactional update
*/
int thd_non_transactional_update(const MYSQL_THD thd);
/**
Get the user thread's binary logging format
@param thd user thread
@return Value to be used as index into the binlog_format_names array
*/
int thd_binlog_format(const MYSQL_THD thd);
}
/*
don't delete it - it may be re-enabled later
as an optimization for the most common case InnoDB+binlog
......
......@@ -382,11 +382,11 @@ of dropping from the buffer pool. NOTE: does not reserve the buffer pool
mutex. */
UNIV_INLINE
ibool
buf_block_peek_if_too_old(
/*======================*/
buf_page_peek_if_too_old(
/*=====================*/
/* out: TRUE if should be made
younger */
const buf_block_t* block); /* in: block to make younger */
const buf_page_t* bpage); /* in: block to make younger */
/************************************************************************
Returns the current state of is_hashed of a page. FALSE if the page is
not in the pool. NOTE that this operation does not fix the page in the
......
......@@ -41,15 +41,15 @@ of dropping from the buffer pool. NOTE: does not reserve the buffer pool
mutex. */
UNIV_INLINE
ibool
buf_block_peek_if_too_old(
/*======================*/
buf_page_peek_if_too_old(
/*=====================*/
/* out: TRUE if should be made
younger */
const buf_block_t* block) /* in: block to make younger */
const buf_page_t* bpage) /* in: block to make younger */
{
return(buf_pool->freed_page_clock
>= buf_block_get_freed_page_clock(block)
+ 1 + (buf_pool->curr_size / 1024));
>= buf_page_get_freed_page_clock(bpage)
+ 1 + (buf_pool->curr_size / 4));
}
/*************************************************************************
......
......@@ -164,6 +164,13 @@ dict_col_name_is_reserved(
/* out: TRUE if name is reserved */
const char* name); /* in: column name */
/************************************************************************
Acquire the autoinc lock.*/
void
dict_table_autoinc_lock(
/*====================*/
dict_table_t* table); /* in: table */
/************************************************************************
Initializes the autoinc counter. It is not an error to initialize an already
initialized counter. */
......@@ -173,22 +180,6 @@ dict_table_autoinc_initialize(
dict_table_t* table, /* in: table */
ib_longlong value); /* in: next value to assign to a row */
/************************************************************************
Gets the next autoinc value (== autoinc counter value), 0 if not yet
initialized. If initialized, increments the counter by 1. */
ib_longlong
dict_table_autoinc_get(
/*===================*/
/* out: value for a new row, or 0 */
dict_table_t* table); /* in: table */
/************************************************************************
Decrements the autoinc counter value by 1. */
void
dict_table_autoinc_decrement(
/*=========================*/
dict_table_t* table); /* in: table */
/************************************************************************
Reads the next autoinc value (== autoinc counter value), 0 if not yet
initialized. */
......@@ -198,15 +189,6 @@ dict_table_autoinc_read(
/* out: value for a new row, or 0 */
dict_table_t* table); /* in: table */
/************************************************************************
Peeks the autoinc counter value, 0 if not yet initialized. Does not
increment the counter. The read not protected by any mutex! */
ib_longlong
dict_table_autoinc_peek(
/*====================*/
/* out: value of the counter */
dict_table_t* table); /* in: table */
/************************************************************************
Updates the autoinc counter if the value supplied is equal or bigger than the
current value. If not inited, does nothing. */
......@@ -216,6 +198,13 @@ dict_table_autoinc_update(
dict_table_t* table, /* in: table */
ib_longlong value); /* in: value which was assigned to a row */
/************************************************************************
Release the autoinc lock.*/
void
dict_table_autoinc_unlock(
/*======================*/
dict_table_t* table); /* in: table */
/**************************************************************************
Adds system columns to a table object. */
......
......@@ -433,6 +433,10 @@ struct dict_table_struct{
SELECT MAX(auto inc column) */
ib_longlong autoinc;/* autoinc counter value to give to the
next inserted row */
ib_longlong autoinc_increment;
/* The increment step of the auto increment
column. Value must be greater than or equal
to 1 */
/*----------------------*/
UT_LIST_BASE_NODE_T(row_prebuilt_t) prebuilts;
/* base node for the prebuilts defined
......
......@@ -257,7 +257,7 @@ will be able to insert new data to the database without running out the
tablespace. Only free extents are taken into account and we also subtract
the safety margin required by the above function fsp_reserve_free_extents. */
ulint
ullint
fsp_get_available_space_in_free_extents(
/*====================================*/
/* out: available space in kB */
......
/******************************************************
Lock queue iterator type and function prototypes.
(c) 2007 Innobase Oy
Created July 16, 2007 Vasil Dimov
*******************************************************/
#ifndef lock0iter_h
#define lock0iter_h
#include "univ.i"
#include "lock0types.h"
typedef struct lock_queue_iterator_struct {
const lock_t* current_lock;
/* In case this is a record lock queue (not table lock queue)
then bit_no is the record number within the heap in which the
record is stored. */
ulint bit_no;
} lock_queue_iterator_t;
/***********************************************************************
Initialize lock queue iterator so that it starts to iterate from
"lock". bit_no specifies the record number within the heap where the
record is stored. It can be undefined (ULINT_UNDEFINED) in two cases:
1. If the lock is a table lock, thus we have a table lock queue;
2. If the lock is a record lock and it is a wait lock. In this case
bit_no is calculated in this function by using
lock_rec_find_set_bit(). There is exactly one bit set in the bitmap
of a wait lock. */
void
lock_queue_iterator_reset(
/*======================*/
lock_queue_iterator_t* iter, /* out: iterator */
const lock_t* lock, /* in: lock to start from */
ulint bit_no);/* in: record number in the
heap */
/***********************************************************************
Gets the previous lock in the lock queue, returns NULL if there are no
more locks (i.e. the current lock is the first one). The iterator is
receded (if not-NULL is returned). */
const lock_t*
lock_queue_iterator_get_prev(
/*=========================*/
/* out: previous lock or NULL */
lock_queue_iterator_t* iter); /* in/out: iterator */
#endif /* lock0iter_h */
......@@ -597,6 +597,19 @@ lock_is_table_exclusive(
dict_table_t* table, /* in: table */
trx_t* trx); /* in: transaction */
/*************************************************************************
Checks if a lock request lock1 has to wait for request lock2. */
ibool
lock_has_to_wait(
/*=============*/
/* out: TRUE if lock1 has to wait for
lock2 to be removed */
const lock_t* lock1, /* in: waiting lock */
const lock_t* lock2); /* in: another lock; NOTE that it is
assumed that this has a lock bit set
on the same record as in lock1 if the
locks are record locks */
/*************************************************************************
Checks that a transaction id is sensible, i.e., not in the future. */
ibool
......@@ -641,7 +654,7 @@ lock_print_info_all_transactions(
FILE* file); /* in: file where to print */
/*************************************************************************
Return approximate number or record locks (bits set in the bitmap) for
this transaction. Since delete-marked records ma ybe removed, the
this transaction. Since delete-marked records may be removed, the
record count will not be precise. */
ulint
......
/******************************************************
Lock module internal structures and methods.
(c) 2007 Innobase Oy
Created July 12, 2007 Vasil Dimov
*******************************************************/
#ifndef lock0priv_h
#define lock0priv_h
#ifndef LOCK_MODULE_IMPLEMENTATION
/* If you need to access members of the structures defined in this
file, please write appropriate functions that retrieve them and put
those functions in lock/ */
#error Do not include lock0priv.h outside of the lock/ module
#endif
#include "univ.i"
#include "dict0types.h"
#include "hash0hash.h"
#include "trx0types.h"
#include "ut0lst.h"
/* A table lock */
typedef struct lock_table_struct lock_table_t;
struct lock_table_struct {
dict_table_t* table; /* database table in dictionary
cache */
UT_LIST_NODE_T(lock_t)
locks; /* list of locks on the same
table */
};
/* Record lock for a page */
typedef struct lock_rec_struct lock_rec_t;
struct lock_rec_struct {
ulint space; /* space id */
ulint page_no; /* page number */
ulint n_bits; /* number of bits in the lock
bitmap; NOTE: the lock bitmap is
placed immediately after the
lock struct */
};
/* Lock struct */
struct lock_struct {
trx_t* trx; /* transaction owning the
lock */
UT_LIST_NODE_T(lock_t)
trx_locks; /* list of the locks of the
transaction */
ulint type_mode; /* lock type, mode, LOCK_GAP or
LOCK_REC_NOT_GAP,
LOCK_INSERT_INTENTION,
wait flag, ORed */
hash_node_t hash; /* hash chain node for a record
lock */
dict_index_t* index; /* index for a record lock */
union {
lock_table_t tab_lock;/* table lock */
lock_rec_t rec_lock;/* record lock */
} un_member;
};
/*************************************************************************
Gets the type of a lock. */
UNIV_INLINE
ulint
lock_get_type(
/*==========*/
/* out: LOCK_TABLE or LOCK_REC */
const lock_t* lock); /* in: lock */
/**************************************************************************
Looks for a set bit in a record lock bitmap. Returns ULINT_UNDEFINED,
if none found. */
ulint
lock_rec_find_set_bit(
/*==================*/
/* out: bit index == heap number of
the record, or ULINT_UNDEFINED if none found */
const lock_t* lock); /* in: record lock with at least one bit set */
/*************************************************************************
Gets the previous record lock set on a record. */
const lock_t*
lock_rec_get_prev(
/*==============*/
/* out: previous lock on the same
record, NULL if none exists */
const lock_t* in_lock,/* in: record lock */
ulint heap_no);/* in: heap number of the record */
#ifndef UNIV_NONINL
#include "lock0priv.ic"
#endif
#endif /* lock0priv_h */
/******************************************************
Lock module internal inline methods.
(c) 2007 Innobase Oy
Created July 16, 2007 Vasil Dimov
*******************************************************/
/* This file contains only methods which are used in
lock/lock0* files, other than lock/lock0lock.c.
I.e. lock/lock0lock.c contains more internal inline
methods but they are used only in that file. */
#ifndef LOCK_MODULE_IMPLEMENTATION
#error Do not include lock0priv.ic outside of the lock/ module
#endif
/*************************************************************************
Gets the type of a lock. */
UNIV_INLINE
ulint
lock_get_type(
/*==========*/
/* out: LOCK_TABLE or LOCK_REC */
const lock_t* lock) /* in: lock */
{
ut_ad(lock);
return(lock->type_mode & LOCK_TYPE_MASK);
}
/* vim: set filetype=c: */
......@@ -766,6 +766,7 @@ struct row_prebuilt_struct {
to this heap */
mem_heap_t* old_vers_heap; /* memory heap where a previous
version is built in consistent read */
ulonglong last_value; /* last value of AUTO-INC interval */
UT_LIST_NODE_T(row_prebuilt_t) prebuilts;
/* list node of table->prebuilts */
ulint magic_n2; /* this should be the same as
......
......@@ -171,7 +171,17 @@ row_search_check_if_query_cache_permitted(
trx_t* trx, /* in: transaction object */
const char* norm_name); /* in: concatenation of database name,
'/' char, table name */
/***********************************************************************
Read the max AUTOINC value from an index. */
ulint
row_search_max_autoinc(
/*===================*/
/* out: DB_SUCCESS if all OK else
error code */
dict_index_t* index, /* in: index to search */
const char* col_name, /* in: autoinc column name */
ib_longlong* value); /* out: AUTOINC value read */
/* A structure for caching column values for prefetched rows */
struct sel_buf_struct{
......
......@@ -694,6 +694,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 */
ulint n_autoinc_rows; /* no. of AUTO-INC rows required for
an SQL statement. This is useful for
multi-row INSERTs */
/*------------------------------*/
char detailed_error[256]; /* detailed error message for last
error, or empty. */
......
......@@ -231,6 +231,8 @@ typedef longlong ib_longlong;
typedef ulonglong ib_uint64_t;
#endif
typedef unsigned long long int ullint;
#ifndef __WIN__
#if SIZEOF_LONG != SIZEOF_VOIDP
#error "Error: InnoDB's ulint must be of the same size as void*"
......
/******************************************************
Lock queue iterator. Can iterate over table and record
lock queues.
(c) 2007 Innobase Oy
Created July 16, 2007 Vasil Dimov
*******************************************************/
#define LOCK_MODULE_IMPLEMENTATION
#include "univ.i"
#include "lock0iter.h"
#include "lock0lock.h"
#include "lock0priv.h"
#include "ut0dbg.h"
#include "ut0lst.h"
/***********************************************************************
Initialize lock queue iterator so that it starts to iterate from
"lock". bit_no specifies the record number within the heap where the
record is stored. It can be undefined (ULINT_UNDEFINED) in two cases:
1. If the lock is a table lock, thus we have a table lock queue;
2. If the lock is a record lock and it is a wait lock. In this case
bit_no is calculated in this function by using
lock_rec_find_set_bit(). There is exactly one bit set in the bitmap
of a wait lock. */
void
lock_queue_iterator_reset(
/*======================*/
lock_queue_iterator_t* iter, /* out: iterator */
const lock_t* lock, /* in: lock to start from */
ulint bit_no) /* in: record number in the
heap */
{
iter->current_lock = lock;
if (bit_no != ULINT_UNDEFINED) {
iter->bit_no = bit_no;
} else {
switch (lock_get_type(lock)) {
case LOCK_TABLE:
iter->bit_no = ULINT_UNDEFINED;
break;
case LOCK_REC:
iter->bit_no = lock_rec_find_set_bit(lock);
ut_a(iter->bit_no != ULINT_UNDEFINED);
break;
default:
ut_error;
}
}
}
/***********************************************************************
Gets the previous lock in the lock queue, returns NULL if there are no
more locks (i.e. the current lock is the first one). The iterator is
receded (if not-NULL is returned). */
const lock_t*
lock_queue_iterator_get_prev(
/*=========================*/
/* out: previous lock or NULL */
lock_queue_iterator_t* iter) /* in/out: iterator */
{
const lock_t* prev_lock;
switch (lock_get_type(iter->current_lock)) {
case LOCK_REC:
prev_lock = lock_rec_get_prev(
iter->current_lock, iter->bit_no);
break;
case LOCK_TABLE:
prev_lock = UT_LIST_GET_PREV(
un_member.tab_lock.locks, iter->current_lock);
break;
default:
ut_error;
}
if (prev_lock != NULL) {
iter->current_lock = prev_lock;
}
return(prev_lock);
}
......@@ -6,10 +6,14 @@ The transaction lock system
Created 5/7/1996 Heikki Tuuri
*******************************************************/
#define LOCK_MODULE_IMPLEMENTATION
#include "lock0lock.h"
#include "lock0priv.h"
#ifdef UNIV_NONINL
#include "lock0lock.ic"
#include "lock0priv.ic"
#endif
#include "usr0sess.h"
......@@ -373,42 +377,6 @@ lock_rec_validate_page(
/* The lock system */
lock_sys_t* lock_sys = NULL;
/* A table lock */
typedef struct lock_table_struct lock_table_t;
struct lock_table_struct{
dict_table_t* table; /* database table in dictionary cache */
UT_LIST_NODE_T(lock_t)
locks; /* list of locks on the same table */
};
/* Record lock for a page */
typedef struct lock_rec_struct lock_rec_t;
struct lock_rec_struct{
ulint space; /* space id */
ulint page_no; /* page number */
ulint n_bits; /* number of bits in the lock bitmap */
/* NOTE: the lock bitmap is placed immediately
after the lock struct */
};
/* Lock struct */
struct lock_struct{
trx_t* trx; /* transaction owning the lock */
UT_LIST_NODE_T(lock_t)
trx_locks; /* list of the locks of the
transaction */
ulint type_mode; /* lock type, mode, LOCK_GAP or
LOCK_REC_NOT_GAP,
LOCK_INSERT_INTENTION,
wait flag, ORed */
hash_node_t hash; /* hash chain node for a record lock */
dict_index_t* index; /* index for a record lock */
union {
lock_table_t tab_lock;/* table lock */
lock_rec_t rec_lock;/* record lock */
} un_member;
};
/* We store info on the latest deadlock error to this buffer. InnoDB
Monitor will then fetch it and print */
ibool lock_deadlock_found = FALSE;
......@@ -454,20 +422,6 @@ lock_deadlock_recursive(
LOCK_MAX_DEPTH_IN_DEADLOCK_CHECK, we
return LOCK_VICTIM_IS_START */
/*************************************************************************
Gets the type of a lock. */
UNIV_INLINE
ulint
lock_get_type(
/*==========*/
/* out: LOCK_TABLE or LOCK_REC */
const lock_t* lock) /* in: lock */
{
ut_ad(lock);
return(lock->type_mode & LOCK_TYPE_MASK);
}
/*************************************************************************
Gets the nth bit of a record lock. */
UNIV_INLINE
......@@ -1021,7 +975,7 @@ lock_rec_has_to_wait(
/*************************************************************************
Checks if a lock request lock1 has to wait for request lock2. */
static
ibool
lock_has_to_wait(
/*=============*/
......@@ -1095,7 +1049,7 @@ lock_rec_set_nth_bit(
/**************************************************************************
Looks for a set bit in a record lock bitmap. Returns ULINT_UNDEFINED,
if none found. */
static
ulint
lock_rec_find_set_bit(
/*==================*/
......@@ -1359,7 +1313,7 @@ lock_rec_copy(
/*************************************************************************
Gets the previous record lock set on a record. */
static
const lock_t*
lock_rec_get_prev(
/*==============*/
......
......@@ -58,6 +58,16 @@ ibool recv_needed_recovery = FALSE;
ibool recv_lsn_checks_on = FALSE;
/* There are two conditions under which we scan the logs, the first
is normal startup and the second is when we do a recovery from an
archive.
This flag is set if we are doing a scan from the last checkpoint during
startup. If we find log entries that were written after the last checkpoint
we know that the server was not cleanly shutdown. We must then initialize
the crash recovery environment before attempting to store these entries in
the log hash table. */
ibool recv_log_scan_is_startup_type = FALSE;
/* If the following is TRUE, the buffer pool file pages must be invalidated
after recovery and no ibuf operations are allowed; this becomes TRUE if
the log record hash table becomes too full, and log records must be merged
......@@ -100,6 +110,16 @@ the recovery failed and the database may be corrupt. */
ib_uint64_t recv_max_page_lsn;
/* prototypes */
/***********************************************************
Initialize crash recovery environment. Can be called iff
recv_needed_recovery == FALSE. */
static
void
recv_init_crash_recovery(void);
/*===========================*/
/************************************************************
Creates the recovery system. */
......@@ -2339,6 +2359,20 @@ recv_scan_log_recs(
if (scanned_lsn > recv_sys->scanned_lsn) {
/* We have found more entries. If this scan is
of startup type, we must initiate crash recovery
environment before parsing these log records. */
if (recv_log_scan_is_startup_type
&& !recv_needed_recovery) {
fprintf(stderr,
"InnoDB: Log scan progressed"
" past the checkpoint lsn %llu\n",
recv_sys->scanned_lsn);
recv_init_crash_recovery();
}
/* We were able to find more log data: add it to the
parsing buffer if parse_start_lsn is already
non-zero */
......@@ -2460,6 +2494,47 @@ recv_group_scan_log_recs(
#endif /* UNIV_DEBUG */
}
/***********************************************************
Initialize crash recovery environment. Can be called iff
recv_needed_recovery == FALSE. */
static
void
recv_init_crash_recovery(void)
/*==========================*/
{
ut_a(!recv_needed_recovery);
recv_needed_recovery = TRUE;
ut_print_timestamp(stderr);
fprintf(stderr,
" InnoDB: Database was not"
" shut down normally!\n"
"InnoDB: Starting crash recovery.\n");
fprintf(stderr,
"InnoDB: Reading tablespace information"
" from the .ibd files...\n");
fil_load_single_table_tablespaces();
/* If we are using the doublewrite method, we will
check if there are half-written pages in data files,
and restore them from the doublewrite buffer if
possible */
if (srv_force_recovery < SRV_FORCE_NO_LOG_REDO) {
fprintf(stderr,
"InnoDB: Restoring possible"
" half-written data pages from"
" the doublewrite\n"
"InnoDB: buffer...\n");
trx_sys_doublewrite_init_or_restore_pages(TRUE);
}
}
/************************************************************
Recovers from a checkpoint. When this function returns, the database is able
to start processing of new user transactions, but the function
......@@ -2589,81 +2664,6 @@ recv_recovery_from_checkpoint_start(
recv_sys->recovered_lsn = checkpoint_lsn;
srv_start_lsn = checkpoint_lsn;
/* NOTE: we always do a 'recovery' at startup, but only if
there is something wrong we will print a message to the
user about recovery: */
if (checkpoint_lsn != max_flushed_lsn
|| checkpoint_lsn != min_flushed_lsn) {
if (checkpoint_lsn < max_flushed_lsn) {
fprintf(stderr,
"InnoDB: #########################"
"#################################\n"
"InnoDB: "
"WARNING!\n"
"InnoDB: The log sequence number"
" in ibdata files is higher\n"
"InnoDB: than the log sequence number"
" in the ib_logfiles! Are you sure\n"
"InnoDB: you are using the right"
" ib_logfiles to start up"
" the database?\n"
"InnoDB: Log sequence number in"
" ib_logfiles is %llu, log\n"
"InnoDB: sequence numbers stamped"
" to ibdata file headers are between\n"
"InnoDB: %llu and %llu.\n"
"InnoDB: #########################"
"#################################\n",
checkpoint_lsn,
min_flushed_lsn,
max_flushed_lsn);
}
recv_needed_recovery = TRUE;
ut_print_timestamp(stderr);
fprintf(stderr,
" InnoDB: Database was not"
" shut down normally!\n"
"InnoDB: Starting crash recovery.\n");
fprintf(stderr,
"InnoDB: Reading tablespace information"
" from the .ibd files...\n");
fil_load_single_table_tablespaces();
/* If we are using the doublewrite method, we will
check if there are half-written pages in data files,
and restore them from the doublewrite buffer if
possible */
if (srv_force_recovery < SRV_FORCE_NO_LOG_REDO) {
fprintf(stderr,
"InnoDB: Restoring possible"
" half-written data pages from"
" the doublewrite\n"
"InnoDB: buffer...\n");
trx_sys_doublewrite_init_or_restore_pages(
TRUE);
}
ut_print_timestamp(stderr);
fprintf(stderr,
" InnoDB: Starting log scan"
" based on checkpoint at\n"
"InnoDB: log sequence number %llu.\n",
checkpoint_lsn);
} else {
/* Init the doublewrite buffer memory structure */
trx_sys_doublewrite_init_or_restore_pages(FALSE);
}
}
contiguous_lsn = ut_uint64_align_down(recv_sys->scanned_lsn,
......@@ -2713,6 +2713,8 @@ recv_recovery_from_checkpoint_start(
group = UT_LIST_GET_NEXT(log_groups, group);
}
/* Set the flag to publish that we are doing startup scan. */
recv_log_scan_is_startup_type = (type == LOG_CHECKPOINT);
while (group) {
old_scanned_lsn = recv_sys->scanned_lsn;
......@@ -2734,6 +2736,57 @@ recv_recovery_from_checkpoint_start(
group = UT_LIST_GET_NEXT(log_groups, group);
}
/* Done with startup scan. Clear the flag. */
recv_log_scan_is_startup_type = FALSE;
if (type == LOG_CHECKPOINT) {
/* NOTE: we always do a 'recovery' at startup, but only if
there is something wrong we will print a message to the
user about recovery: */
if (checkpoint_lsn != max_flushed_lsn
|| checkpoint_lsn != min_flushed_lsn) {
if (checkpoint_lsn < max_flushed_lsn) {
fprintf(stderr,
"InnoDB: #########################"
"#################################\n"
"InnoDB: "
"WARNING!\n"
"InnoDB: The log sequence number"
" in ibdata files is higher\n"
"InnoDB: than the log sequence number"
" in the ib_logfiles! Are you sure\n"
"InnoDB: you are using the right"
" ib_logfiles to start up"
" the database?\n"
"InnoDB: Log sequence number in"
" ib_logfiles is %llu, log\n"
"InnoDB: sequence numbers stamped"
" to ibdata file headers are between\n"
"InnoDB: %llu and %llu.\n"
"InnoDB: #########################"
"#################################\n",
checkpoint_lsn,
min_flushed_lsn,
max_flushed_lsn);
}
if (!recv_needed_recovery) {
fprintf(stderr,
"InnoDB: The log sequence number"
" in ibdata files does not match\n"
"InnoDB: the log sequence number"
" in the ib_logfiles!\n");
recv_init_crash_recovery();
}
}
if (!recv_needed_recovery) {
/* Init the doublewrite buffer memory structure */
trx_sys_doublewrite_init_or_restore_pages(FALSE);
}
}
/* We currently have only one log group */
if (group_scanned_lsn < checkpoint_lsn) {
ut_print_timestamp(stderr);
......@@ -2786,15 +2839,7 @@ recv_recovery_from_checkpoint_start(
recv_synchronize_groups(up_to_date_group);
if (!recv_needed_recovery) {
if (checkpoint_lsn != recv_sys->recovered_lsn) {
fprintf(stderr,
"InnoDB: Warning: we did not need to do"
" crash recovery, but log scan\n"
"InnoDB: progressed past the checkpoint"
" lsn %llu up to lsn %llu\n",
checkpoint_lsn,
recv_sys->recovered_lsn);
}
ut_a(checkpoint_lsn == recv_sys->recovered_lsn);
} else {
srv_start_lsn = recv_sys->recovered_lsn;
}
......
disable_query_log;
--require r/true.require
select support = 'Enabled' as `TRUE` from information_schema.engines where engine = 'innodb';
select (support = 'YES' or support = 'DEFAULT') as `TRUE` from information_schema.engines where engine = 'innodb';
enable_query_log;
......@@ -501,7 +501,7 @@ ERROR 23000: Duplicate entry 'test2' for key 'ggid'
select * from t1;
id ggid email passwd
1 this will work
3 test2 this will work
4 test2 this will work
select * from t1 where id=1;
id ggid email passwd
1 this will work
......@@ -1086,6 +1086,39 @@ n d
1 30
2 20
drop table t1,t2;
CREATE TABLE `t1` (
`a` int(11) NOT NULL auto_increment,
`b` int(11) default NULL,
PRIMARY KEY (`a`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 ;
CREATE TABLE `t2` (
`a` int(11) NOT NULL auto_increment,
`b` int(11) default NULL,
PRIMARY KEY (`a`)
) ENGINE=INNODB DEFAULT CHARSET=latin1 ;
insert into t1 values (1,1),(2,2);
insert into t2 values (1,1),(4,4);
reset master;
UPDATE t2,t1 SET t2.a=t1.a+2;
ERROR 23000: Duplicate entry '3' for key 'PRIMARY'
select * from t2 /* must be (3,1), (4,4) */;
a b
1 1
4 4
show master status /* there must no UPDATE in binlog */;
File Position Binlog_Do_DB Binlog_Ignore_DB
master-bin.000001 106
delete from t1;
delete from t2;
insert into t1 values (1,2),(3,4),(4,4);
insert into t2 values (1,2),(3,4),(4,4);
reset master;
UPDATE t2,t1 SET t2.a=t2.b where t2.a=t1.a;
ERROR 23000: Duplicate entry '4' for key 'PRIMARY'
show master status /* there must be no UPDATE query event */;
File Position Binlog_Do_DB Binlog_Ignore_DB
master-bin.000001 106
drop table t1, t2;
create table t1 (a int, b int) engine=innodb;
insert into t1 values(20,null);
select t2.b, ifnull(t2.b,"this is null") from t1 as t2 left join t1 as t3 on
......@@ -1607,7 +1640,7 @@ t2 CREATE TABLE `t2` (
) ENGINE=InnoDB DEFAULT CHARSET=latin1
drop table t2;
create table t2 (id int(11) not null, id2 int(11) not null, constraint t1_id_fk foreign key (id2,id) references t1 (id)) engine = innodb;
ERROR HY000: Can't create table 'test.t2' (errno: 150)
ERROR 42000: Incorrect foreign key definition for 't1_id_fk': Key reference and table reference don't match
create table t2 (a int auto_increment primary key, b int, index(b), foreign key (b) references t1(id), unique(b)) engine=innodb;
show create table t2;
Table Create Table
......@@ -1632,30 +1665,6 @@ t2 CREATE TABLE `t2` (
CONSTRAINT `t2_ibfk_2` FOREIGN KEY (`b`) REFERENCES `t1` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
drop table t2, t1;
flush status;
show status like "binlog_cache_use";
Variable_name Value
Binlog_cache_use 0
show status like "binlog_cache_disk_use";
Variable_name Value
Binlog_cache_disk_use 0
create table t1 (a int) engine=innodb;
show status like "binlog_cache_use";
Variable_name Value
Binlog_cache_use 1
show status like "binlog_cache_disk_use";
Variable_name Value
Binlog_cache_disk_use 1
begin;
delete from t1;
commit;
show status like "binlog_cache_use";
Variable_name Value
Binlog_cache_use 2
show status like "binlog_cache_disk_use";
Variable_name Value
Binlog_cache_disk_use 1
drop table t1;
create table t1 (c char(10), index (c,c)) engine=innodb;
ERROR 42S21: Duplicate column name 'c'
create table t1 (c1 char(10), c2 char(10), index (c1,c2,c1)) engine=innodb;
......@@ -1775,13 +1784,13 @@ Variable_name Value
Innodb_page_size 16384
show status like "Innodb_rows_deleted";
Variable_name Value
Innodb_rows_deleted 2070
Innodb_rows_deleted 72
show status like "Innodb_rows_inserted";
Variable_name Value
Innodb_rows_inserted 3083
Innodb_rows_inserted 1088
show status like "Innodb_rows_updated";
Variable_name Value
Innodb_rows_updated 886
Innodb_rows_updated 888
show status like "Innodb_row_lock_waits";
Variable_name Value
Innodb_row_lock_waits 0
......
......@@ -13,6 +13,11 @@
-- source include/not_embedded.inc
-- source include/have_innodb.inc
-- source include/have_log_bin.inc
# Disabling it temporarily for statement-based logging since some
# tests are not safe while binlog is on.
-- source include/have_binlog_format_mixed_or_row.inc
#
# Small basic test with ignore
......@@ -53,7 +58,7 @@ INSERT INTO t1 VALUES (1,0,0),(3,1,1),(4,1,1),(8,2,2),(9,2,2),(17,3,2),(22,4,2),
update t1 set parent_id=parent_id+100;
select * from t1 where parent_id=102;
update t1 set id=id+1000;
-- error ER_DUP_ENTRY_WITH_KEY_NAME,1022
-- error ER_DUP_ENTRY,1022
update t1 set id=1024 where id=1009;
select * from t1;
update ignore t1 set id=id+1; # This will change all rows
......@@ -134,13 +139,13 @@ commit;
select n, "after commit" from t1;
commit;
insert into t1 values (5);
-- error ER_DUP_ENTRY_WITH_KEY_NAME
-- error ER_DUP_ENTRY
insert into t1 values (4);
commit;
select n, "after commit" from t1;
set autocommit=1;
insert into t1 values (6);
-- error ER_DUP_ENTRY_WITH_KEY_NAME
-- error ER_DUP_ENTRY
insert into t1 values (4);
select n from t1;
set autocommit=0;
......@@ -214,7 +219,7 @@ drop table t1;
CREATE TABLE t1 (id char(8) not null primary key, val int not null) engine=innodb;
insert into t1 values ('pippo', 12);
-- error ER_DUP_ENTRY_WITH_KEY_NAME
-- error ER_DUP_ENTRY
insert into t1 values ('pippo', 12); # Gives error
delete from t1;
delete from t1 where id = 'pippo';
......@@ -342,9 +347,9 @@ CREATE TABLE t1 (
insert into t1 (ggid,passwd) values ('test1','xxx');
insert into t1 (ggid,passwd) values ('test2','yyy');
-- error ER_DUP_ENTRY_WITH_KEY_NAME
-- error ER_DUP_ENTRY
insert into t1 (ggid,passwd) values ('test2','this will fail');
-- error ER_DUP_ENTRY_WITH_KEY_NAME
-- error ER_DUP_ENTRY
insert into t1 (ggid,id) values ('this will fail',1);
select * from t1 where ggid='test1';
......@@ -353,7 +358,7 @@ select * from t1 where id=2;
replace into t1 (ggid,id) values ('this will work',1);
replace into t1 (ggid,passwd) values ('test2','this will work');
-- error ER_DUP_ENTRY_WITH_KEY_NAME
-- error ER_DUP_ENTRY
update t1 set id=100,ggid='test2' where id=1;
select * from t1;
select * from t1 where id=1;
......@@ -524,7 +529,7 @@ drop table t1;
create table t1 (id int NOT NULL,id2 int NOT NULL,id3 int NOT NULL,dummy1 char(30),primary key (id,id2),index index_id3 (id3)) engine=innodb;
insert into t1 values (0,0,0,'ABCDEFGHIJ'),(2,2,2,'BCDEFGHIJK'),(1,1,1,'CDEFGHIJKL');
LOCK TABLES t1 WRITE;
--error ER_DUP_ENTRY_WITH_KEY_NAME
--error ER_DUP_ENTRY
insert into t1 values (99,1,2,'D'),(1,1,2,'D');
select id from t1;
select id from t1;
......@@ -535,7 +540,7 @@ create table t1 (id int NOT NULL,id2 int NOT NULL,id3 int NOT NULL,dummy1 char(3
insert into t1 values (0,0,0,'ABCDEFGHIJ'),(2,2,2,'BCDEFGHIJK'),(1,1,1,'CDEFGHIJKL');
LOCK TABLES t1 WRITE;
begin;
--error ER_DUP_ENTRY_WITH_KEY_NAME
--error ER_DUP_ENTRY
insert into t1 values (99,1,2,'D'),(1,1,2,'D');
select id from t1;
insert ignore into t1 values (100,1,2,'D'),(1,1,99,'D');
......@@ -754,6 +759,45 @@ select * from t1;
select * from t2;
drop table t1,t2;
#
# Bug#27716 multi-update did partially and has not binlogged
#
CREATE TABLE `t1` (
`a` int(11) NOT NULL auto_increment,
`b` int(11) default NULL,
PRIMARY KEY (`a`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 ;
CREATE TABLE `t2` (
`a` int(11) NOT NULL auto_increment,
`b` int(11) default NULL,
PRIMARY KEY (`a`)
) ENGINE=INNODB DEFAULT CHARSET=latin1 ;
# A. testing multi_update::send_eof() execution branch
insert into t1 values (1,1),(2,2);
insert into t2 values (1,1),(4,4);
reset master;
--error ER_DUP_ENTRY
UPDATE t2,t1 SET t2.a=t1.a+2;
# check
select * from t2 /* must be (3,1), (4,4) */;
show master status /* there must no UPDATE in binlog */;
# B. testing multi_update::send_error() execution branch
delete from t1;
delete from t2;
insert into t1 values (1,2),(3,4),(4,4);
insert into t2 values (1,2),(3,4),(4,4);
reset master;
--error ER_DUP_ENTRY
UPDATE t2,t1 SET t2.a=t2.b where t2.a=t1.a;
show master status /* there must be no UPDATE query event */;
# cleanup bug#27716
drop table t1, t2;
#
# Testing of IFNULL
#
......@@ -1134,7 +1178,7 @@ drop table t2;
# Clean up filename -- embedded server reports whole path without .frm,
# regular server reports relative path with .frm (argh!)
--replace_result \\ / $MYSQL_TEST_DIR . /var/master-data/ / t2.frm t2
--error 1005
--error ER_WRONG_FK_DEF
create table t2 (id int(11) not null, id2 int(11) not null, constraint t1_id_fk foreign key (id2,id) references t1 (id)) engine = innodb;
# bug#3749
......@@ -1147,41 +1191,6 @@ show create table t2;
drop table t2, t1;
#
# Let us test binlog_cache_use and binlog_cache_disk_use status vars.
# Actually this test has nothing to do with innodb per se, it just requires
# transactional table.
#
flush status;
show status like "binlog_cache_use";
show status like "binlog_cache_disk_use";
create table t1 (a int) engine=innodb;
# Now we are going to create transaction which is long enough so its
# transaction binlog will be flushed to disk...
let $1=2000;
disable_query_log;
begin;
while ($1)
{
eval insert into t1 values( $1 );
dec $1;
}
commit;
enable_query_log;
show status like "binlog_cache_use";
show status like "binlog_cache_disk_use";
# Transaction which should not be flushed to disk and so should not
# increase binlog_cache_disk_use.
begin;
delete from t1;
commit;
show status like "binlog_cache_use";
show status like "binlog_cache_disk_use";
drop table t1;
#
# Bug #6126: Duplicate columns in keys gives misleading error message
#
......@@ -1408,7 +1417,7 @@ create table t1 (rowid int not null auto_increment, val int not null,primary
key (rowid), unique(val)) engine=innodb;
replace into t1 (val) values ('1'),('2');
replace into t1 (val) values ('1'),('2');
--error ER_DUP_ENTRY_WITH_KEY_NAME
--error ER_DUP_ENTRY
insert into t1 (val) values ('1'),('2');
select * from t1;
drop table t1;
......@@ -1421,7 +1430,7 @@ create table t1 (a int not null auto_increment primary key, val int) engine=Inno
insert into t1 (val) values (1);
update t1 set a=2 where a=1;
# We should get the following error because InnoDB does not update the counter
--error ER_DUP_ENTRY_WITH_KEY_NAME
--error ER_DUP_ENTRY
insert into t1 (val) values (1);
select * from t1;
drop table t1;
......@@ -1744,13 +1753,13 @@ create table t3 (s1 varchar(2) binary,primary key (s1)) engine=innodb;
create table t4 (s1 char(2) binary,primary key (s1)) engine=innodb;
insert into t1 values (0x41),(0x4120),(0x4100);
-- error ER_DUP_ENTRY_WITH_KEY_NAME
-- error ER_DUP_ENTRY
insert into t2 values (0x41),(0x4120),(0x4100);
insert into t2 values (0x41),(0x4120);
-- error ER_DUP_ENTRY_WITH_KEY_NAME
-- error ER_DUP_ENTRY
insert into t3 values (0x41),(0x4120),(0x4100);
insert into t3 values (0x41),(0x4100);
-- error ER_DUP_ENTRY_WITH_KEY_NAME
-- error ER_DUP_ENTRY
insert into t4 values (0x41),(0x4120),(0x4100);
insert into t4 values (0x41),(0x4100);
select hex(s1) from t1;
......
......@@ -10,12 +10,18 @@
SET storage_engine=InnoDB;
# we do not really care about what gets output-ed, we are only
# we do not really care about what gets printed, we are only
# interested in getting the deadlock resolved according to our
# expectations
-- disable_query_log
-- disable_result_log
# we want to use "-- eval statement1; statement2" which does not work with
# prepared statements. Because this test should not behave differently with
# or without prepared statements we disable them so the test does not fail
# if someone runs ./mysql-test-run.pl --ps-protocol
-- disable_ps_protocol
-- disable_warnings
DROP TABLE IF EXISTS t1, t2, t3, t4, t5_nontrans;
-- enable_warnings
......
......@@ -456,10 +456,9 @@ os_file_handle_error_no_exit(
#undef USE_FILE_LOCK
#define USE_FILE_LOCK
#if defined(UNIV_HOTBACKUP) || defined(__WIN__) || defined(__FreeBSD__) || defined(__NETWARE__)
#if defined(UNIV_HOTBACKUP) || defined(__WIN__) || defined(__NETWARE__)
/* InnoDB Hot Backup does not lock the data files.
* On Windows, mandatory locking is used.
* On FreeBSD with LinuxThreads, advisory locking does not work properly.
*/
# undef USE_FILE_LOCK
#endif
......
......@@ -3,7 +3,6 @@ MYSQL_STORAGE_ENGINE(innobase, innodb, [InnoDB Storage Engine],
MYSQL_PLUGIN_DIRECTORY(innobase, [storage/innobase])
MYSQL_PLUGIN_STATIC(innobase, [libinnobase.a])
MYSQL_PLUGIN_DYNAMIC(innobase, [ha_innodb.la])
MYSQL_PLUGIN_DEPENDS_ON_MYSQL_INTERNALS(innobase, [handler/ha_innodb.cc])
MYSQL_PLUGIN_ACTIONS(innobase, [
AC_CHECK_LIB(rt, aio_read, [innodb_system_libs="-lrt"])
AC_SUBST(innodb_system_libs)
......@@ -41,5 +40,4 @@ MYSQL_PLUGIN_ACTIONS(innobase, [
CFLAGS="$CFLAGS -DUNIV_MUST_NOT_INLINE";;
esac
])
MYSQL_PLUGIN_DEPENDS_ON_MYSQL_INTERNALS(innobase, [handler/ha_innodb.cc])
......@@ -3143,6 +3143,8 @@ next_rec:
dict_table_change_id_in_cache(table, new_id);
}
/* MySQL calls ha_innobase::reset_auto_increment() which does
the same thing. */
dict_table_autoinc_initialize(table, 0);
dict_update_statistics(table);
......
......@@ -4577,3 +4577,169 @@ row_search_check_if_query_cache_permitted(
return(ret);
}
/***********************************************************************
Read the AUTOINC column from the current row. */
static
ib_longlong
row_search_autoinc_read_column(
/*===========================*/
/* out: value read from the column */
dict_index_t* index, /* in: index to read from */
const rec_t* rec, /* in: current rec */
ulint col_no, /* in: column number */
ibool unsigned_type) /* in: signed or unsigned flag */
{
ulint len;
byte* ptr;
const byte* data;
ib_longlong value;
mem_heap_t* heap = NULL;
byte dest[sizeof(value)];
ulint offsets_[REC_OFFS_NORMAL_SIZE];
ulint* offsets = offsets_;
*offsets_ = sizeof offsets_ / sizeof *offsets_;
/* TODO: We have to cast away the const of rec for now. This needs
to be fixed later.*/
offsets = rec_get_offsets(
(rec_t*) rec, index, offsets, ULINT_UNDEFINED, &heap);
/* TODO: We have to cast away the const of rec for now. This needs
to be fixed later.*/
data = rec_get_nth_field((rec_t*)rec, offsets, col_no, &len);
ut_a(len != UNIV_SQL_NULL);
ut_a(len <= sizeof value);
/* Convert integer data from Innobase to a little-endian format,
sign bit restored to normal */
for (ptr = dest + len; ptr != dest; ++data) {
--ptr;
*ptr = *data;
}
if (!unsigned_type) {
dest[len - 1] ^= 128;
}
/* The assumption here is that the AUTOINC value can't be negative.*/
switch (len) {
case 8:
value = *(ib_longlong*) ptr;
break;
case 4:
value = *(ib_uint32_t*) ptr;
break;
case 2:
value = *(uint16 *) ptr;
break;
case 1:
value = *ptr;
break;
default:
ut_error;
}
if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
}
ut_a(value >= 0);
return(value);
}
/***********************************************************************
Get the last row. */
static
const rec_t*
row_search_autoinc_get_rec(
/*=======================*/
/* out: current rec or NULL */
btr_pcur_t* pcur, /* in: the current cursor */
mtr_t* mtr) /* in: mini transaction */
{
do {
const rec_t* rec = btr_pcur_get_rec(pcur);
if (page_rec_is_user_rec(rec)) {
return(rec);
}
} while (btr_pcur_move_to_prev(pcur, mtr));
return(NULL);
}
/***********************************************************************
Read the max AUTOINC value from an index. */
ulint
row_search_max_autoinc(
/*===================*/
/* out: DB_SUCCESS if all OK else
error code, DB_RECORD_NOT_FOUND if
column name can't be found in index */
dict_index_t* index, /* in: index to search */
const char* col_name, /* in: name of autoinc column */
ib_longlong* value) /* out: AUTOINC value read */
{
ulint i;
ulint n_cols;
dict_field_t* dfield = NULL;
ulint error = DB_SUCCESS;
n_cols = dict_index_get_n_ordering_defined_by_user(index);
/* Search the index for the AUTOINC column name */
for (i = 0; i < n_cols; ++i) {
dfield = dict_index_get_nth_field(index, i);
if (strcmp(col_name, dfield->name) == 0) {
break;
}
}
*value = 0;
/* Must find the AUTOINC column name */
if (i < n_cols && dfield) {
mtr_t mtr;
btr_pcur_t pcur;
mtr_start(&mtr);
/* Open at the high/right end (FALSE), and INIT
cursor (TRUE) */
btr_pcur_open_at_index_side(
FALSE, index, BTR_SEARCH_LEAF, &pcur, TRUE, &mtr);
if (page_get_n_recs(btr_pcur_get_page(&pcur)) > 0) {
const rec_t* rec;
rec = row_search_autoinc_get_rec(&pcur, &mtr);
if (rec != NULL) {
ibool unsigned_type = (
dfield->col->prtype & DATA_UNSIGNED);
*value = row_search_autoinc_read_column(
index, rec, i, unsigned_type);
}
}
btr_pcur_close(&pcur);
mtr_commit(&mtr);
} else {
error = DB_RECORD_NOT_FOUND;
}
return(error);
}
......@@ -15,16 +15,34 @@ Created 9/11/1995 Heikki Tuuri
#include "mem0mem.h"
#include "srv0srv.h"
/* number of system calls made during shared latching */
ulint rw_s_system_call_count = 0;
/* number of spin waits on rw-latches,
resulted during shared (read) locks */
ulint rw_s_spin_wait_count = 0;
/* number of OS waits on rw-latches,
resulted during shared (read) locks */
ulint rw_s_os_wait_count = 0;
/* number of unlocks (that unlock shared locks),
set only when UNIV_SYNC_PERF_STAT is defined */
ulint rw_s_exit_count = 0;
/* number of system calls made during exclusive latching */
ulint rw_x_system_call_count = 0;
/* number of spin waits on rw-latches,
resulted during exclusive (write) locks */
ulint rw_x_spin_wait_count = 0;
/* number of OS waits on rw-latches,
resulted during exclusive (write) locks */
ulint rw_x_os_wait_count = 0;
/* number of unlocks (that unlock exclusive locks),
set only when UNIV_SYNC_PERF_STAT is defined */
ulint rw_x_exit_count = 0;
/* The global list of rw-locks */
......
......@@ -115,6 +115,7 @@ ulint mutex_system_call_count = 0;
/* Number of spin waits on mutexes: for performance monitoring */
/* round=one iteration of a spin loop */
ulint mutex_spin_round_count = 0;
ulint mutex_spin_wait_count = 0;
ulint mutex_os_wait_count = 0;
......
......@@ -182,6 +182,8 @@ trx_create(
memset(&trx->xid, 0, sizeof(trx->xid));
trx->xid.formatID = -1;
trx->n_autoinc_rows = 0;
trx_reset_new_rec_lock_info(trx);
return(trx);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment