diff --git a/.bzr-mysql/default.conf b/.bzr-mysql/default.conf
index 39ebdda8d7a..782473d27aa 100644
--- a/.bzr-mysql/default.conf
+++ b/.bzr-mysql/default.conf
@@ -1,4 +1,4 @@
[MYSQL]
-post_commit_to = "commits@lists.mysql.com"
-post_push_to = "commits@lists.mysql.com"
-tree_name = "mysql-5.4"
+post_commit_to = "guilhem@sun.com, alik@sun.com"
+#post_push_to = "commits@lists.mysql.com"
+tree_name = "mysql-trunk"
diff --git a/BUILD/check-cpu b/BUILD/check-cpu
index 27e0acf69a0..f73a872fecd 100755
--- a/BUILD/check-cpu
+++ b/BUILD/check-cpu
@@ -50,8 +50,13 @@ check_cpu () {
model_name=`sysctl -n hw.model`
;;
Darwin)
- cpu_family=`uname -p`
- model_name=`machine`
+ cpu_family=`sysctl -n machdep.cpu.vendor`
+ model_name=`sysctl -n machdep.cpu.brand_string`
+ if [ -z "$cpu_family" -o -z "$model_name" ]
+ then
+ cpu_family=`uname -p`
+ model_name=`machine`
+ fi
;;
*)
cpu_family=`uname -p`;
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 6a41496f120..8fc99e5c736 100755
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -13,7 +13,7 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-CMAKE_MINIMUM_REQUIRED(VERSION 2.4.7 FATAL_ERROR)
+CMAKE_MINIMUM_REQUIRED(VERSION 2.6.0 FATAL_ERROR)
PROJECT(MySql)
@@ -32,52 +32,6 @@ ADD_DEFINITIONS(-DHAVE_YASSL)
# Set debug options
SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DFORCE_INIT_OF_VARS")
-# Note that some engines are always compiled in, MyISAM, MyISAMMRG and HEAP,
-# these three plugin defintions are dummys for symmetry
-
-SET(WITH_HEAP_STORAGE_ENGINE TRUE)
-ADD_DEFINITIONS(-DWITH_HEAP_STORAGE_ENGINE)
-SET (mysql_plugin_defs "${mysql_plugin_defs},builtin_heap_plugin")
-
-SET(WITH_MYISAM_STORAGE_ENGINE TRUE)
-ADD_DEFINITIONS(-DWITH_MYISAM_STORAGE_ENGINE)
-SET (mysql_plugin_defs "${mysql_plugin_defs},builtin_myisam_plugin")
-
-SET(WITH_MYISAMMRG_STORAGE_ENGINE TRUE)
-ADD_DEFINITIONS(-DWITH_MYISAMMRG_STORAGE_ENGINE)
-SET (mysql_plugin_defs "${mysql_plugin_defs},builtin_myisammrg_plugin")
-
-IF(WITH_ARCHIVE_STORAGE_ENGINE)
- ADD_DEFINITIONS(-DWITH_ARCHIVE_STORAGE_ENGINE)
- SET (mysql_plugin_defs "${mysql_plugin_defs},builtin_archive_plugin")
-ENDIF(WITH_ARCHIVE_STORAGE_ENGINE)
-IF(WITH_BLACKHOLE_STORAGE_ENGINE)
- ADD_DEFINITIONS(-DWITH_BLACKHOLE_STORAGE_ENGINE)
- SET (mysql_plugin_defs "${mysql_plugin_defs},builtin_blackhole_plugin")
-ENDIF(WITH_BLACKHOLE_STORAGE_ENGINE)
-IF(WITH_CSV_STORAGE_ENGINE)
- ADD_DEFINITIONS(-DWITH_CSV_STORAGE_ENGINE)
- SET (mysql_plugin_defs "${mysql_plugin_defs},builtin_csv_plugin")
-ENDIF(WITH_CSV_STORAGE_ENGINE)
-IF(WITH_EXAMPLE_STORAGE_ENGINE)
- ADD_DEFINITIONS(-DWITH_EXAMPLE_STORAGE_ENGINE)
- SET (mysql_plugin_defs "${mysql_plugin_defs},builtin_example_plugin")
-ENDIF(WITH_EXAMPLE_STORAGE_ENGINE)
-IF(WITH_INNOBASE_STORAGE_ENGINE)
- ADD_DEFINITIONS(-DWITH_INNOBASE_STORAGE_ENGINE)
- SET (mysql_plugin_defs "${mysql_plugin_defs},builtin_innobase_plugin")
-ENDIF(WITH_INNOBASE_STORAGE_ENGINE)
-IF(WITH_PARTITION_STORAGE_ENGINE)
- ADD_DEFINITIONS(-DWITH_PARTITION_STORAGE_ENGINE)
- SET (mysql_plugin_defs "${mysql_plugin_defs},builtin_partition_plugin")
-ENDIF(WITH_PARTITION_STORAGE_ENGINE)
-IF(WITH_FEDERATED_STORAGE_ENGINE)
- ADD_DEFINITIONS(-DWITH_FEDERATED_STORAGE_ENGINE)
- SET (mysql_plugin_defs "${mysql_plugin_defs},builtin_federated_plugin")
-ENDIF(WITH_FEDERATED_STORAGE_ENGINE)
-
-CONFIGURE_FILE(${CMAKE_SOURCE_DIR}/sql/sql_builtin.cc.in
- ${CMAKE_SOURCE_DIR}/sql/sql_builtin.cc @ONLY)
SET(localstatedir "C:\\mysql\\data")
CONFIGURE_FILE(${CMAKE_SOURCE_DIR}/support-files/my-huge.cnf.sh
@@ -122,6 +76,16 @@ IF(MSVC AND NOT CMAKE_GENERATOR MATCHES "Visual Studio 7")
SET(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} /wd4996")
ENDIF(MSVC AND NOT CMAKE_GENERATOR MATCHES "Visual Studio 7")
+IF(CMAKE_GENERATOR MATCHES "Visual Studio 7")
+ # VS2003 has a bug that prevents linking mysqld with module definition file
+ # (/DEF option for linker). Linker would incorrectly complain about multiply
+ # defined symbols. Workaround is to disable dynamic plugins, so /DEF is not
+ # used.
+ MESSAGE("Warning: Building MySQL with Visual Studio 2003.NET is no more supported.")
+ MESSAGE("Please use a newer version of Visual Studio.")
+ SET(WITHOUT_DYNAMIC_PLUGINS TRUE)
+ENDIF(CMAKE_GENERATOR MATCHES "Visual Studio 7")
+
# Settings for Visual Studio 7 and above.
IF(MSVC)
# replace /MDd with /MTd
@@ -165,12 +129,16 @@ IF(WIN32)
ADD_DEFINITIONS("-D_WINDOWS -D__WIN__ -D_CRT_SECURE_NO_DEPRECATE")
ENDIF(WIN32)
+# default to x86 platform. We'll check for X64 in a bit
+SET (PLATFORM X86)
+
# This definition is necessary to work around a bug with Intellisense described
# here: http://tinyurl.com/2cb428. Syntax highlighting is important for proper
# debugger functionality.
IF(CMAKE_SIZEOF_VOID_P MATCHES 8)
MESSAGE(STATUS "Detected 64-bit platform.")
ADD_DEFINITIONS("-D_WIN64")
+ SET (PLATFORM X64)
ENDIF(CMAKE_SIZEOF_VOID_P MATCHES 8)
IF(EMBED_MANIFESTS)
@@ -223,6 +191,81 @@ IF(EMBED_MANIFESTS)
ENDIF(CMAKE_GENERATOR MATCHES "Visual Studio 8 2005 Win64")
ENDIF(EMBED_MANIFESTS)
+# Figure out what engines to build and how (statically or dynamically),
+# add preprocessor defines for storage engines.
+IF(WITHOUT_DYNAMIC_PLUGINS)
+ MESSAGE("Dynamic plugins are disabled.")
+ENDIF(WITHOUT_DYNAMIC_PLUGINS)
+
+FILE(GLOB STORAGE_SUBDIRS storage/*)
+FOREACH(SUBDIR ${STORAGE_SUBDIRS})
+ FILE(RELATIVE_PATH DIRNAME ${PROJECT_SOURCE_DIR}/storage ${SUBDIR})
+ STRING(TOUPPER ${DIRNAME} ENGINE)
+ STRING(TOLOWER ${DIRNAME} ENGINE_LOWER)
+ IF (EXISTS ${SUBDIR}/CMakeLists.txt)
+ # Check MYSQL_STORAGE_ENGINE macro is present
+ FILE(STRINGS ${SUBDIR}/CMakeLists.txt HAVE_STORAGE_ENGINE REGEX MYSQL_STORAGE_ENGINE)
+ IF(HAVE_STORAGE_ENGINE)
+ SET(ENGINE_BUILD_TYPE "DYNAMIC")
+ # Read plug.in to find out if a plugin is mandatory and whether it supports
+ # build as shared library (dynamic).
+ IF(EXISTS ${SUBDIR}/plug.in)
+ FILE(READ ${SUBDIR}/plug.in PLUGIN_FILE_CONTENT)
+ STRING (REGEX MATCH "MYSQL_PLUGIN_DYNAMIC" MYSQL_PLUGIN_DYNAMIC ${PLUGIN_FILE_CONTENT})
+ STRING (REGEX MATCH "MYSQL_PLUGIN_MANDATORY" MYSQL_PLUGIN_MANDATORY ${PLUGIN_FILE_CONTENT})
+ STRING (REGEX MATCH "MYSQL_PLUGIN_STATIC" MYSQL_PLUGIN_STATIC ${PLUGIN_FILE_CONTENT})
+
+ IF(MYSQL_PLUGIN_MANDATORY)
+ SET(WITH_${ENGINE}_STORAGE_ENGINE TRUE)
+ ENDIF(MYSQL_PLUGIN_MANDATORY)
+
+ IF (WITH_${ENGINE}_STORAGE_ENGINE AND MYSQL_PLUGIN_STATIC)
+ SET(ENGINE_BUILD_TYPE "STATIC")
+ ELSEIF(NOT WITHOUT_${ENGINE}_STORAGE_ENGINE AND MYSQL_PLUGIN_DYNAMIC AND NOT WITHOUT_DYNAMIC_PLUGINS)
+ SET(ENGINE_BUILD_TYPE "DYNAMIC")
+ ELSE(WITH_${ENGINE}_STORAGE_ENGINE AND MYSQL_PLUGIN_STATIC)
+ SET(ENGINE_BUILD_TYPE "NONE")
+ ENDIF(WITH_${ENGINE}_STORAGE_ENGINE AND MYSQL_PLUGIN_STATIC)
+ IF (ENGINE_BUILD_TYPE STREQUAL "STATIC")
+ SET (mysql_plugin_defs "${mysql_plugin_defs},builtin_${ENGINE_LOWER}_plugin")
+ SET (MYSQLD_STATIC_ENGINE_LIBS ${MYSQLD_STATIC_ENGINE_LIBS} ${ENGINE_LOWER})
+ SET (STORAGE_ENGINE_DEFS "${STORAGE_ENGINE_DEFS} -DWITH_${ENGINE}_STORAGE_ENGINE")
+ SET (WITH_${ENGINE}_STORAGE_ENGINE TRUE)
+ ENDIF (ENGINE_BUILD_TYPE STREQUAL "STATIC")
+ ENDIF(EXISTS ${SUBDIR}/plug.in)
+
+ IF(NOT ENGINE_BUILD_TYPE STREQUAL "NONE")
+ LIST(APPEND ${ENGINE_BUILD_TYPE}_ENGINE_DIRECTORIES ${SUBDIR})
+ ENDIF(NOT ENGINE_BUILD_TYPE STREQUAL "NONE")
+
+ ENDIF(HAVE_STORAGE_ENGINE)
+ ENDIF(EXISTS ${SUBDIR}/CMakeLists.txt)
+ENDFOREACH(SUBDIR ${STORAGE_SUBDIRS})
+
+# Special handling for partition(not really pluggable)
+IF(NOT WITHOUT_PARTITION_STORAGE_ENGINE)
+ SET (STORAGE_ENGINE_DEFS "${STORAGE_ENGINE_DEFS} -DWITH_PARTITION_STORAGE_ENGINE")
+ SET (mysql_plugin_defs "${mysql_plugin_defs},builtin_partition_plugin")
+ENDIF(NOT WITHOUT_PARTITION_STORAGE_ENGINE)
+
+ADD_DEFINITIONS(${STORAGE_ENGINE_DEFS})
+
+# Now write out our mysql_plugin_defs struct
+CONFIGURE_FILE(${CMAKE_SOURCE_DIR}/sql/sql_builtin.cc.in
+ ${CMAKE_SOURCE_DIR}/sql/sql_builtin.cc @ONLY)
+
+# Add subdirectories for storage engines
+SET (ENGINE_BUILD_TYPE "STATIC")
+FOREACH(DIR ${STATIC_ENGINE_DIRECTORIES})
+ ADD_SUBDIRECTORY(${DIR})
+ENDFOREACH(DIR ${STATIC_ENGINE_DIRECTORIES})
+
+SET (ENGINE_BUILD_TYPE "DYNAMIC")
+FOREACH(DIR ${DYNAMIC_ENGINE_DIRECTORIES})
+ ADD_SUBDIRECTORY(${DIR})
+ENDFOREACH(DIR ${DYNAMIC_ENGINE_DIRECTORIES})
+
+
# FIXME "debug" only needed if build type is "Debug", but
# CMAKE_BUILD_TYPE is not set during configure time.
ADD_SUBDIRECTORY(vio)
@@ -235,28 +278,7 @@ ADD_SUBDIRECTORY(zlib)
ADD_SUBDIRECTORY(extra/yassl)
ADD_SUBDIRECTORY(extra/yassl/taocrypt)
ADD_SUBDIRECTORY(extra)
-ADD_SUBDIRECTORY(storage/heap)
-ADD_SUBDIRECTORY(storage/myisam)
-ADD_SUBDIRECTORY(storage/myisammrg)
ADD_SUBDIRECTORY(client)
-IF(WITH_ARCHIVE_STORAGE_ENGINE)
- ADD_SUBDIRECTORY(storage/archive)
-ENDIF(WITH_ARCHIVE_STORAGE_ENGINE)
-IF(WITH_BLACKHOLE_STORAGE_ENGINE)
- ADD_SUBDIRECTORY(storage/blackhole)
-ENDIF(WITH_BLACKHOLE_STORAGE_ENGINE)
-IF(WITH_CSV_STORAGE_ENGINE)
- ADD_SUBDIRECTORY(storage/csv)
-ENDIF(WITH_CSV_STORAGE_ENGINE)
-IF(WITH_EXAMPLE_STORAGE_ENGINE)
- ADD_SUBDIRECTORY(storage/example)
-ENDIF(WITH_EXAMPLE_STORAGE_ENGINE)
-IF(WITH_FEDERATED_STORAGE_ENGINE)
- ADD_SUBDIRECTORY(storage/federated)
-ENDIF(WITH_FEDERATED_STORAGE_ENGINE)
-IF(WITH_INNOBASE_STORAGE_ENGINE)
- ADD_SUBDIRECTORY(storage/innobase)
-ENDIF(WITH_INNOBASE_STORAGE_ENGINE)
ADD_SUBDIRECTORY(sql)
ADD_SUBDIRECTORY(libmysql)
ADD_SUBDIRECTORY(tests)
diff --git a/client/Makefile.am b/client/Makefile.am
index 94db565ba37..ecdd010575f 100644
--- a/client/Makefile.am
+++ b/client/Makefile.am
@@ -71,7 +71,7 @@ mysqldump_SOURCES= mysqldump.c \
$(top_srcdir)/mysys/mf_getdate.c
mysqlimport_SOURCES= mysqlimport.c
-
+mysqlimport_CFLAGS= -DTHREAD -UUNDEF_THREADS_HACK
mysqlimport_LDADD = $(CXXLDFLAGS) $(CLIENT_THREAD_LIBS) \
@CLIENT_EXTRA_LDFLAGS@ \
$(LIBMYSQLCLIENT_LA) \
@@ -80,14 +80,14 @@ mysqlimport_LDADD = $(CXXLDFLAGS) $(CLIENT_THREAD_LIBS) \
mysqlshow_SOURCES= mysqlshow.c
mysqlslap_SOURCES= mysqlslap.c
-mysqlslap_CFLAGS= -DTHREAD -UUNDEF_THREADS_HACK
+mysqlslap_CFLAGS= -DTHREAD -UMYSQL_CLIENT_NO_THREADS
mysqlslap_LDADD = $(CXXLDFLAGS) $(CLIENT_THREAD_LIBS) \
@CLIENT_EXTRA_LDFLAGS@ \
$(LIBMYSQLCLIENT_LA) \
$(top_builddir)/mysys/libmysys.a
mysqltest_SOURCES= mysqltest.cc
-mysqltest_CXXFLAGS= -DTHREAD -UUNDEF_THREADS_HACK
+mysqltest_CXXFLAGS= -DTHREAD -UMYSQL_CLIENT_NO_THREADS
mysqltest_LDADD = $(CXXLDFLAGS) $(CLIENT_THREAD_LIBS) \
@CLIENT_EXTRA_LDFLAGS@ \
$(LIBMYSQLCLIENT_LA) \
@@ -99,7 +99,7 @@ mysql_upgrade_SOURCES= mysql_upgrade.c \
$(top_srcdir)/mysys/my_getpagesize.c
# Fix for mit-threads
-DEFS = -DUNDEF_THREADS_HACK \
+DEFS = -DMYSQL_CLIENT_NO_THREADS \
-DDEFAULT_MYSQL_HOME="\"$(prefix)\"" \
-DDATADIR="\"$(localstatedir)\""
diff --git a/client/mysql.cc b/client/mysql.cc
index 46141cd975f..5afbc2e960b 100644
--- a/client/mysql.cc
+++ b/client/mysql.cc
@@ -115,7 +115,7 @@ extern "C" {
#define PROMPT_CHAR '\\'
#define DEFAULT_DELIMITER ";"
-#define MAX_BATCH_BUFFER_SIZE (1024L * 1024L)
+#define MAX_BATCH_BUFFER_SIZE (1024L * 1024L * 1024L)
typedef struct st_status
{
@@ -143,7 +143,8 @@ static my_bool ignore_errors=0,wait_flag=0,quick=0,
tty_password= 0, opt_nobeep=0, opt_reconnect=1,
default_charset_used= 0, opt_secure_auth= 0,
default_pager_set= 0, opt_sigint_ignore= 0,
- show_warnings= 0, executing_query= 0, interrupted_query= 0;
+ show_warnings= 0, executing_query= 0, interrupted_query= 0,
+ ignore_spaces= 0;
static my_bool debug_info_flag, debug_check_flag;
static my_bool column_types_flag;
static my_bool preserve_comments= 0;
@@ -1183,7 +1184,12 @@ int main(int argc,char *argv[])
histfile= 0;
}
}
- if (histfile)
+
+ /* We used to suggest setting MYSQL_HISTFILE=/dev/null. */
+ if (histfile && strncmp(histfile, "/dev/null", 10) == 0)
+ histfile= NULL;
+
+ if (histfile && histfile[0])
{
if (verbose)
tee_fprintf(stdout, "Reading history-file %s\n",histfile);
@@ -1218,7 +1224,8 @@ sig_handler mysql_end(int sig)
{
mysql_close(&mysql);
#ifdef HAVE_READLINE
- if (!status.batch && !quick && !opt_html && !opt_xml && histfile)
+ if (!status.batch && !quick && !opt_html && !opt_xml &&
+ histfile && histfile[0])
{
/* write-history */
if (verbose)
@@ -1345,7 +1352,7 @@ static struct my_option my_long_options[] =
{"debug", '#', "Output debug log", (uchar**) &default_dbug_option,
(uchar**) &default_dbug_option, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
#endif
- {"debug-check", OPT_DEBUG_CHECK, "Check memory and open file usage at exit .",
+ {"debug-check", OPT_DEBUG_CHECK, "Check memory and open file usage at exit.",
(uchar**) &debug_check_flag, (uchar**) &debug_check_flag, 0,
GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
{"debug-info", 'T', "Print some debug info at exit.", (uchar**) &debug_info_flag,
@@ -1372,8 +1379,9 @@ static struct my_option my_long_options[] =
{"no-named-commands", 'g',
"Named commands are disabled. Use \\* form only, or use named commands only in the beginning of a line ending with a semicolon (;) Since version 10.9 the client now starts with this option ENABLED by default! Disable with '-G'. Long format commands still work from the first line. WARNING: option deprecated; use --disable-named-commands instead.",
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
- {"ignore-spaces", 'i', "Ignore space after function names.", 0, 0, 0,
- GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"ignore-spaces", 'i', "Ignore space after function names.",
+ (uchar**) &ignore_spaces, (uchar**) &ignore_spaces, 0, GET_BOOL, NO_ARG, 0, 0,
+ 0, 0, 0, 0},
{"local-infile", OPT_LOCAL_INFILE, "Enable/disable LOAD DATA LOCAL INFILE.",
(uchar**) &opt_local_infile,
(uchar**) &opt_local_infile, 0, GET_BOOL, OPT_ARG, 0, 0, 0, 0, 0, 0},
@@ -1794,6 +1802,10 @@ static int get_options(int argc, char **argv)
my_end_arg= MY_CHECK_ERROR | MY_GIVE_INFO;
if (debug_check_flag)
my_end_arg= MY_CHECK_ERROR;
+
+ if (ignore_spaces)
+ connect_flag|= CLIENT_IGNORE_SPACE;
+
return(0);
}
@@ -1967,7 +1979,7 @@ static COMMANDS *find_command(char *name,char cmd_char)
*/
if (strstr(name, "\\g") || (strstr(name, delimiter) &&
!(strlen(name) >= 9 &&
- !my_strnncoll(charset_info,
+ !my_strnncoll(&my_charset_latin1,
(uchar*) name, 9,
(const uchar*) "delimiter",
9))))
@@ -1988,11 +2000,11 @@ static COMMANDS *find_command(char *name,char cmd_char)
{
if (commands[i].func &&
((name &&
- !my_strnncoll(charset_info,(uchar*)name,len,
+ !my_strnncoll(&my_charset_latin1, (uchar*)name, len,
(uchar*)commands[i].name,len) &&
!commands[i].name[len] &&
(!end || (end && commands[i].takes_params))) ||
- !name && commands[i].cmd_char == cmd_char))
+ (!name && commands[i].cmd_char == cmd_char)))
{
DBUG_PRINT("exit",("found command: %s", commands[i].name));
DBUG_RETURN(&commands[i]);
@@ -2151,7 +2163,7 @@ static bool add_line(String &buffer,char *line,char *in_string,
buffer.length(0);
}
else if (!*ml_comment && (!*in_string && (inchar == '#' ||
- inchar == '-' && pos[1] == '-' &&
+ (inchar == '-' && pos[1] == '-' &&
/*
The third byte is either whitespace or is the
end of the line -- which would occur only
@@ -2159,7 +2171,7 @@ static bool add_line(String &buffer,char *line,char *in_string,
itself whitespace and should also match.
*/
(my_isspace(charset_info,pos[2]) ||
- !pos[2]))))
+ !pos[2])))))
{
// Flush previously accepted characters
if (out != line)
@@ -2720,7 +2732,7 @@ static int com_server_help(String *buffer __attribute__((unused)),
{
MYSQL_ROW cur;
const char *server_cmd= buffer->ptr();
- char cmd_buf[100];
+ char cmd_buf[100 + 1];
MYSQL_RES *result;
int error;
@@ -3381,9 +3393,12 @@ print_table_data_html(MYSQL_RES *result)
{
while((field = mysql_fetch_field(result)))
{
- tee_fprintf(PAGER, "
%s | ", (field->name ?
- (field->name[0] ? field->name :
- " ") : "NULL"));
+ tee_fputs("", PAGER);
+ if (field->name && field->name[0])
+ xmlencode_print(field->name, field->name_length);
+ else
+ tee_fputs(field->name ? " " : "NULL", PAGER);
+ tee_fputs(" | ", PAGER);
}
(void) tee_fputs("", PAGER);
}
@@ -3396,7 +3411,7 @@ print_table_data_html(MYSQL_RES *result)
for (uint i=0; i < mysql_num_fields(result); i++)
{
(void) tee_fputs("", PAGER);
- safe_put_field(cur[i],lengths[i]);
+ xmlencode_print(cur[i], lengths[i]);
(void) tee_fputs(" | ", PAGER);
}
(void) tee_fputs("", PAGER);
@@ -4249,41 +4264,36 @@ com_status(String *buffer __attribute__((unused)),
MYSQL_RES *result;
LINT_INIT(result);
+ if (mysql_real_query_for_lazy(
+ C_STRING_WITH_LEN("select DATABASE(), USER() limit 1")))
+ return 0;
+
tee_puts("--------------", stdout);
usage(1); /* Print version */
- if (connected)
+ tee_fprintf(stdout, "\nConnection id:\t\t%lu\n",mysql_thread_id(&mysql));
+ /*
+ Don't remove "limit 1",
+ it is protection againts SQL_SELECT_LIMIT=0
+ */
+ if (mysql_store_result_for_lazy(&result))
{
- tee_fprintf(stdout, "\nConnection id:\t\t%lu\n",mysql_thread_id(&mysql));
- /*
- Don't remove "limit 1",
- it is protection againts SQL_SELECT_LIMIT=0
- */
- if (!mysql_query(&mysql,"select DATABASE(), USER() limit 1") &&
- (result=mysql_use_result(&mysql)))
+ MYSQL_ROW cur=mysql_fetch_row(result);
+ if (cur)
{
- MYSQL_ROW cur=mysql_fetch_row(result);
- if (cur)
- {
- tee_fprintf(stdout, "Current database:\t%s\n", cur[0] ? cur[0] : "");
- tee_fprintf(stdout, "Current user:\t\t%s\n", cur[1]);
- }
- mysql_free_result(result);
- }
+ tee_fprintf(stdout, "Current database:\t%s\n", cur[0] ? cur[0] : "");
+ tee_fprintf(stdout, "Current user:\t\t%s\n", cur[1]);
+ }
+ mysql_free_result(result);
+ }
+
#ifdef HAVE_OPENSSL
- if ((status_str= mysql_get_ssl_cipher(&mysql)))
- tee_fprintf(stdout, "SSL:\t\t\tCipher in use is %s\n",
- status_str);
- else
-#endif /* HAVE_OPENSSL */
- tee_puts("SSL:\t\t\tNot in use", stdout);
- }
+ if ((status_str= mysql_get_ssl_cipher(&mysql)))
+ tee_fprintf(stdout, "SSL:\t\t\tCipher in use is %s\n",
+ status_str);
else
- {
- vidattr(A_BOLD);
- tee_fprintf(stdout, "\nNo connection\n");
- vidattr(A_NORMAL);
- return 0;
- }
+#endif /* HAVE_OPENSSL */
+ tee_puts("SSL:\t\t\tNot in use", stdout);
+
if (skip_updates)
{
vidattr(A_BOLD);
@@ -4302,8 +4312,14 @@ com_status(String *buffer __attribute__((unused)),
tee_fprintf(stdout, "Insert id:\t\t%s\n", llstr(id, buff));
/* "limit 1" is protection against SQL_SELECT_LIMIT=0 */
- if (!mysql_query(&mysql,"select @@character_set_client, @@character_set_connection, @@character_set_server, @@character_set_database limit 1") &&
- (result=mysql_use_result(&mysql)))
+ if (mysql_real_query_for_lazy(C_STRING_WITH_LEN(
+ "select @@character_set_client, @@character_set_connection, "
+ "@@character_set_server, @@character_set_database limit 1")))
+ {
+ if (mysql_errno(&mysql) == CR_SERVER_GONE_ERROR)
+ return 0;
+ }
+ if (mysql_store_result_for_lazy(&result))
{
MYSQL_ROW cur=mysql_fetch_row(result);
if (cur)
diff --git a/client/mysql_upgrade.c b/client/mysql_upgrade.c
index 190bb2383e9..641d4a38d16 100644
--- a/client/mysql_upgrade.c
+++ b/client/mysql_upgrade.c
@@ -39,6 +39,7 @@ static uint my_end_arg= 0;
static char *opt_user= (char*)"root";
static DYNAMIC_STRING ds_args;
+static DYNAMIC_STRING conn_args;
static char *opt_password= 0;
static my_bool tty_password= 0;
@@ -115,11 +116,11 @@ static struct my_option my_long_options[]=
#endif
{"socket", 'S', "Socket file to use for connection.",
0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+#include
{"tmpdir", 't', "Directory for temporary files",
0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"user", 'u', "User for login if not current user.", (uchar**) &opt_user,
(uchar**) &opt_user, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
-#include
{"verbose", 'v', "Display more output about the process",
(uchar**) &opt_verbose, (uchar**) &opt_verbose, 0,
GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0},
@@ -135,6 +136,7 @@ static void free_used_memory(void)
free_defaults(defaults_argv);
dynstr_free(&ds_args);
+ dynstr_free(&conn_args);
}
@@ -204,7 +206,7 @@ static void add_one_option(DYNAMIC_STRING* ds,
}
}
dynstr_append_os_quoted(ds, "--", opt->name, eq, arg, NullS);
- dynstr_append(&ds_args, " ");
+ dynstr_append(ds, " ");
}
@@ -231,6 +233,8 @@ get_one_option(int optid, const struct my_option *opt,
break;
case 'p':
+ if (argument == disabled_my_option)
+ argument= (char*) ""; /* Don't require password */
tty_password= 1;
add_option= FALSE;
if (argument)
@@ -254,6 +258,15 @@ get_one_option(int optid, const struct my_option *opt,
case 'f': /* --force */
add_option= FALSE;
break;
+
+ case 'h': /* --host */
+ case 'W': /* --pipe */
+ case 'P': /* --port */
+ case 'S': /* --socket */
+ case OPT_MYSQL_PROTOCOL: /* --protocol */
+ case OPT_SHARED_MEMORY_BASE_NAME: /* --shared-memory-base-name */
+ add_one_option(&conn_args, opt, argument);
+ break;
}
if (add_option)
@@ -601,6 +614,20 @@ static void create_mysql_upgrade_info_file(void)
}
+/*
+ Print connection-related arguments.
+*/
+
+static void print_conn_args(const char *tool_name)
+{
+ if (conn_args.str[0])
+ verbose("Running '%s' with connection arguments: %s", tool_name,
+ conn_args.str);
+ else
+ verbose("Running '%s with default connection arguments", tool_name);
+}
+
+
/*
Check and upgrade(if neccessary) all tables
in the server using "mysqlcheck --check-upgrade .."
@@ -608,7 +635,7 @@ static void create_mysql_upgrade_info_file(void)
static int run_mysqlcheck_upgrade(void)
{
- verbose("Running 'mysqlcheck'...");
+ print_conn_args("mysqlcheck");
return run_tool(mysqlcheck_path,
NULL, /* Send output from mysqlcheck directly to screen */
"--no-defaults",
@@ -622,7 +649,7 @@ static int run_mysqlcheck_upgrade(void)
static int run_mysqlcheck_fixnames(void)
{
- verbose("Running 'mysqlcheck'...");
+ print_conn_args("mysqlcheck");
return run_tool(mysqlcheck_path,
NULL, /* Send output from mysqlcheck directly to screen */
"--no-defaults",
@@ -751,7 +778,8 @@ int main(int argc, char **argv)
strncpy(self_name, argv[0], FN_REFLEN);
}
- if (init_dynamic_string(&ds_args, "", 512, 256))
+ if (init_dynamic_string(&ds_args, "", 512, 256) ||
+ init_dynamic_string(&conn_args, "", 512, 256))
die("Out of memory");
load_defaults("my", load_default_groups, &argc, &argv);
diff --git a/client/mysqladmin.cc b/client/mysqladmin.cc
index df0dc1e7049..9865b67bb3b 100644
--- a/client/mysqladmin.cc
+++ b/client/mysqladmin.cc
@@ -232,6 +232,8 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
opt_count_iterations= 1;
break;
case 'p':
+ if (argument == disabled_my_option)
+ argument= (char*) ""; // Don't require password
if (argument)
{
char *start=argument;
@@ -677,10 +679,16 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv)
pos=argv[1];
for (;;)
{
- if (mysql_kill(mysql,(ulong) atol(pos)))
+ /* We don't use mysql_kill(), since it only handles 32-bit IDs. */
+ char buff[26], *out; /* "KILL " + max 20 digs + NUL */
+ out= strxmov(buff, "KILL ", NullS);
+ ullstr(strtoull(pos, NULL, 0), out);
+
+ if (mysql_query(mysql, buff))
{
- my_printf_error(0, "kill failed on %ld; error: '%s'", error_flags,
- atol(pos), mysql_error(mysql));
+ /* out still points to just the number */
+ my_printf_error(0, "kill failed on %s; error: '%s'", error_flags,
+ out, mysql_error(mysql));
error=1;
}
if (!(pos=strchr(pos,',')))
diff --git a/client/mysqlbinlog.cc b/client/mysqlbinlog.cc
index 1621db5ded8..82af7ca65f6 100644
--- a/client/mysqlbinlog.cc
+++ b/client/mysqlbinlog.cc
@@ -17,10 +17,8 @@
TODO: print the catalog (some USE catalog.db ????).
- Standalone program to read a MySQL binary log (or relay log);
- can read files produced by 3.23, 4.x, 5.0 servers.
+ Standalone program to read a MySQL binary log (or relay log).
- Can read binlogs from 3.23/4.x/5.0 and relay logs from 4.x/5.0.
Should be able to read any file of these categories, even with
--start-position.
An important fact: the Format_desc event of the log is at most the 3rd event
@@ -681,6 +679,7 @@ Exit_status process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev,
{
char ll_buff[21];
Log_event_type ev_type= ev->get_type_code();
+ my_bool destroy_evt= TRUE;
DBUG_ENTER("process_event");
print_event_info->short_form= short_form;
Exit_status retval= OK_CONTINUE;
@@ -689,8 +688,8 @@ Exit_status process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev,
Format events are not concerned by --offset and such, we always need to
read them to be able to process the wanted events.
*/
- if ((rec_count >= offset) &&
- ((my_time_t)(ev->when) >= start_datetime) ||
+ if (((rec_count >= offset) &&
+ ((my_time_t)(ev->when) >= start_datetime)) ||
(ev_type == FORMAT_DESCRIPTION_EVENT))
{
if (ev_type != FORMAT_DESCRIPTION_EVENT)
@@ -871,12 +870,63 @@ Exit_status process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev,
break;
}
case TABLE_MAP_EVENT:
+ {
+ Table_map_log_event *map= ((Table_map_log_event *)ev);
+ if (shall_skip_database(map->get_db_name()))
+ {
+ print_event_info->m_table_map_ignored.set_table(map->get_table_id(), map);
+ destroy_evt= FALSE;
+ goto end;
+ }
+ }
case WRITE_ROWS_EVENT:
case DELETE_ROWS_EVENT:
case UPDATE_ROWS_EVENT:
case PRE_GA_WRITE_ROWS_EVENT:
case PRE_GA_DELETE_ROWS_EVENT:
case PRE_GA_UPDATE_ROWS_EVENT:
+ {
+ if (ev_type != TABLE_MAP_EVENT)
+ {
+ Rows_log_event *e= (Rows_log_event*) ev;
+ Table_map_log_event *ignored_map=
+ print_event_info->m_table_map_ignored.get_table(e->get_table_id());
+ bool skip_event= (ignored_map != NULL);
+
+ /*
+ end of statement check:
+ i) destroy/free ignored maps
+ ii) if skip event, flush cache now
+ */
+ if (e->get_flags(Rows_log_event::STMT_END_F))
+ {
+ /*
+ Now is safe to clear ignored map (clear_tables will also
+ delete original table map events stored in the map).
+ */
+ if (print_event_info->m_table_map_ignored.count() > 0)
+ print_event_info->m_table_map_ignored.clear_tables();
+
+ /*
+ One needs to take into account an event that gets
+ filtered but was last event in the statement. If this is
+ the case, previous rows events that were written into
+ IO_CACHEs still need to be copied from cache to
+ result_file (as it would happen in ev->print(...) if
+ event was not skipped).
+ */
+ if (skip_event)
+ {
+ if ((copy_event_cache_to_file_and_reinit(&print_event_info->head_cache, result_file) ||
+ copy_event_cache_to_file_and_reinit(&print_event_info->body_cache, result_file)))
+ goto err;
+ }
+ }
+
+ /* skip the event check */
+ if (skip_event)
+ goto end;
+ }
/*
These events must be printed in base64 format, if printed.
base64 format requires a FD event to be safe, so if no FD
@@ -900,6 +950,7 @@ Exit_status process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev,
goto err;
}
/* FALL THROUGH */
+ }
default:
ev->print(result_file, print_event_info);
}
@@ -919,7 +970,8 @@ end:
{
if (remote_opt)
ev->temp_buf= 0;
- delete ev;
+ if (destroy_evt) /* destroy it later if not set (ignored table map) */
+ delete ev;
}
DBUG_RETURN(retval);
}
@@ -934,10 +986,13 @@ static struct my_option my_long_options[] =
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
#endif
{"base64-output", OPT_BASE64_OUTPUT_MODE,
+ /* 'unspec' is not mentioned because it is just a placeholder. */
"Determine when the output statements should be base64-encoded BINLOG "
"statements: 'never' disables it and works only for binlogs without "
"row-based events; 'auto' is the default and prints base64 only when "
"necessary (i.e., for row-based events and format description events); "
+ "'decode-rows' suppresses BINLOG statements for row events, but does "
+ "not exit as an error if a row event is found, unlike 'never'; "
"'always' prints base64 whenever possible. 'always' is for debugging "
"only and should not be used in a production system. The default is "
"'auto'. --base64-output is a short form for --base64-output=always."
@@ -1226,6 +1281,8 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
one_database = 1;
break;
case 'p':
+ if (argument == disabled_my_option)
+ argument= (char*) ""; // Don't require password
if (argument)
{
my_free(pass,MYF(MY_ALLOW_ZERO_PTR));
@@ -1529,8 +1586,7 @@ static Exit_status dump_remote_log_entries(PRINT_EVENT_INFO *print_event_info,
If reading from a remote host, ensure the temp_buf for the
Log_event class is pointing to the incoming stream.
*/
- if (remote_opt)
- ev->register_temp_buf((char*) net->read_pos + 1);
+ ev->register_temp_buf((char *) net->read_pos + 1);
Log_event_type type= ev->get_type_code();
if (glob_description_event->binlog_version >= 3 ||
diff --git a/client/mysqlcheck.c b/client/mysqlcheck.c
index d2edd084c57..c59049d8b72 100644
--- a/client/mysqlcheck.c
+++ b/client/mysqlcheck.c
@@ -286,6 +286,8 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
what_to_do= DO_UPGRADE;
break;
case 'p':
+ if (argument == disabled_my_option)
+ argument= (char*) ""; /* Don't require password */
if (argument)
{
char *start = argument;
diff --git a/client/mysqldump.c b/client/mysqldump.c
index 5a1fa3cc090..6d45d901b33 100644
--- a/client/mysqldump.c
+++ b/client/mysqldump.c
@@ -221,7 +221,7 @@ static struct my_option my_long_options[] =
(uchar**) &opt_compatible_mode_str, (uchar**) &opt_compatible_mode_str, 0,
GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"compact", OPT_COMPACT,
- "Give less verbose output (useful for debugging). Disables structure comments and header/footer constructs. Enables options --skip-add-drop-table --no-set-names --skip-disable-keys --skip-add-locks",
+ "Give less verbose output (useful for debugging). Disables structure comments and header/footer constructs. Enables options --skip-add-drop-table --skip-add-locks --skip-comments --skip-disable-keys --skip-set-charset",
(uchar**) &opt_compact, (uchar**) &opt_compact, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
0, 0},
{"complete-insert", 'c', "Use complete insert statements.",
@@ -702,6 +702,8 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
break;
#endif
case 'p':
+ if (argument == disabled_my_option)
+ argument= (char*) ""; /* Don't require password */
if (argument)
{
char *start=argument;
@@ -1395,18 +1397,19 @@ static char *cover_definer_clause_in_sp(const char *def_str,
SYNOPSIS
open_sql_file_for_table
name name of the table or view
+ flags flags (as per "man 2 open")
RETURN VALUES
0 Failed to open file
> 0 Handle of the open file
*/
-static FILE* open_sql_file_for_table(const char* table)
+static FILE* open_sql_file_for_table(const char* table, int flags)
{
FILE* res;
char filename[FN_REFLEN], tmp_path[FN_REFLEN];
convert_dirname(tmp_path,path,NullS);
res= my_fopen(fn_format(filename, table, tmp_path, ".sql", 4),
- O_WRONLY, MYF(MY_WME));
+ flags, MYF(MY_WME));
return res;
}
@@ -2288,7 +2291,7 @@ static uint get_table_structure(char *table, char *db, char *table_type,
if (path)
{
- if (!(sql_file= open_sql_file_for_table(table)))
+ if (!(sql_file= open_sql_file_for_table(table, O_WRONLY)))
DBUG_RETURN(0);
write_header(sql_file, db);
@@ -2499,7 +2502,7 @@ static uint get_table_structure(char *table, char *db, char *table_type,
{
if (path)
{
- if (!(sql_file= open_sql_file_for_table(table)))
+ if (!(sql_file= open_sql_file_for_table(table, O_WRONLY)))
DBUG_RETURN(0);
write_header(sql_file, db);
}
@@ -2723,12 +2726,10 @@ continue_xml:
DBUG_RETURN((uint) num_fields);
} /* get_table_structure */
-static void dump_trigger_old(MYSQL_RES *show_triggers_rs,
+static void dump_trigger_old(FILE *sql_file, MYSQL_RES *show_triggers_rs,
MYSQL_ROW *show_trigger_row,
const char *table_name)
{
- FILE *sql_file= md_result_file;
-
char quoted_table_name_buf[NAME_LEN * 2 + 3];
char *quoted_table_name= quote_name(table_name, quoted_table_name_buf, 1);
@@ -2794,11 +2795,10 @@ static void dump_trigger_old(MYSQL_RES *show_triggers_rs,
DBUG_VOID_RETURN;
}
-static int dump_trigger(MYSQL_RES *show_create_trigger_rs,
+static int dump_trigger(FILE *sql_file, MYSQL_RES *show_create_trigger_rs,
const char *db_name,
const char *db_cl_name)
{
- FILE *sql_file= md_result_file;
MYSQL_ROW row;
int db_cl_altered= FALSE;
@@ -2862,22 +2862,28 @@ static int dump_triggers_for_table(char *table_name, char *db_name)
uint old_opt_compatible_mode= opt_compatible_mode;
MYSQL_RES *show_triggers_rs;
MYSQL_ROW row;
+ FILE *sql_file= md_result_file;
char db_cl_name[MY_CS_NAME_SIZE];
+ int ret= TRUE;
DBUG_ENTER("dump_triggers_for_table");
DBUG_PRINT("enter", ("db: %s, table_name: %s", db_name, table_name));
+ if (path && !(sql_file= open_sql_file_for_table(table_name,
+ O_WRONLY | O_APPEND)))
+ DBUG_RETURN(1);
+
/* Do not use ANSI_QUOTES on triggers in dump */
opt_compatible_mode&= ~MASK_ANSI_QUOTES;
/* Get database collation. */
if (switch_character_set_results(mysql, "binary"))
- DBUG_RETURN(TRUE);
+ goto done;
if (fetch_db_collation(db_name, db_cl_name, sizeof (db_cl_name)))
- DBUG_RETURN(TRUE);
+ goto done;
/* Get list of triggers. */
@@ -2886,7 +2892,7 @@ static int dump_triggers_for_table(char *table_name, char *db_name)
quote_for_like(table_name, name_buff));
if (mysql_query_with_error_report(mysql, &show_triggers_rs, query_buff))
- DBUG_RETURN(TRUE);
+ goto done;
/* Dump triggers. */
@@ -2907,17 +2913,15 @@ static int dump_triggers_for_table(char *table_name, char *db_name)
provide all the necessary information to restore trigger properly.
*/
- dump_trigger_old(show_triggers_rs, &row, table_name);
+ dump_trigger_old(sql_file, show_triggers_rs, &row, table_name);
}
else
{
MYSQL_RES *show_create_trigger_rs= mysql_store_result(mysql);
if (!show_create_trigger_rs ||
- dump_trigger(show_create_trigger_rs, db_name, db_cl_name))
- {
- DBUG_RETURN(TRUE);
- }
+ dump_trigger(sql_file, show_create_trigger_rs, db_name, db_cl_name))
+ goto done;
mysql_free_result(show_create_trigger_rs);
}
@@ -2927,7 +2931,7 @@ static int dump_triggers_for_table(char *table_name, char *db_name)
mysql_free_result(show_triggers_rs);
if (switch_character_set_results(mysql, default_charset))
- DBUG_RETURN(TRUE);
+ goto done;
/*
make sure to set back opt_compatible mode to
@@ -2935,7 +2939,13 @@ static int dump_triggers_for_table(char *table_name, char *db_name)
*/
opt_compatible_mode=old_opt_compatible_mode;
- DBUG_RETURN(FALSE);
+ ret= FALSE;
+
+done:
+ if (path)
+ my_fclose(sql_file, MYF(0));
+
+ DBUG_RETURN(ret);
}
static void add_load_option(DYNAMIC_STRING *str, const char *option,
@@ -3811,6 +3821,10 @@ static int dump_all_databases()
return 1;
while ((row= mysql_fetch_row(tableres)))
{
+ if (mysql_get_server_version(mysql) >= 50003 &&
+ !my_strcasecmp(&my_charset_latin1, row[0], "information_schema"))
+ continue;
+
if (dump_all_tables_in_db(row[0]))
result=1;
}
@@ -3825,6 +3839,10 @@ static int dump_all_databases()
}
while ((row= mysql_fetch_row(tableres)))
{
+ if (mysql_get_server_version(mysql) >= 50003 &&
+ !my_strcasecmp(&my_charset_latin1, row[0], "information_schema"))
+ continue;
+
if (dump_all_views_in_db(row[0]))
result=1;
}
@@ -3931,10 +3949,6 @@ int init_dumping_tables(char *qdatabase)
static int init_dumping(char *database, int init_func(char*))
{
- if (mysql_get_server_version(mysql) >= 50003 &&
- !my_strcasecmp(&my_charset_latin1, database, "information_schema"))
- return 1;
-
if (mysql_select_db(mysql, database))
{
DB_error(mysql, "when selecting the database");
@@ -3993,6 +4007,7 @@ static int dump_all_tables_in_db(char *database)
DBUG_RETURN(1);
if (opt_xml)
print_xml_tag(md_result_file, "", "\n", "database", "name=", database, NullS);
+
if (lock_tables)
{
DYNAMIC_STRING query;
@@ -4226,7 +4241,10 @@ static int dump_selected_tables(char *db, char **table_names, int tables)
}
end= pos;
- if (lock_tables)
+ /* Can't LOCK TABLES in INFORMATION_SCHEMA, so don't try. */
+ if (lock_tables &&
+ !(mysql_get_server_version(mysql) >= 50003 &&
+ !my_strcasecmp(&my_charset_latin1, db, "information_schema")))
{
if (mysql_real_query(mysql, lock_tables_query.str,
lock_tables_query.length-1))
@@ -4780,7 +4798,7 @@ static my_bool get_view_structure(char *table, char* db)
/* If requested, open separate .sql file for this view */
if (path)
{
- if (!(sql_file= open_sql_file_for_table(table)))
+ if (!(sql_file= open_sql_file_for_table(table, O_WRONLY)))
DBUG_RETURN(1);
write_header(sql_file, db);
diff --git a/client/mysqlimport.c b/client/mysqlimport.c
index 09ba27b287a..57aee7379f2 100644
--- a/client/mysqlimport.c
+++ b/client/mysqlimport.c
@@ -221,6 +221,8 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
break;
#endif
case 'p':
+ if (argument == disabled_my_option)
+ argument= (char*) ""; /* Don't require password */
if (argument)
{
char *start=argument;
diff --git a/client/mysqlshow.c b/client/mysqlshow.c
index 0e696aed211..15f791ca8fb 100644
--- a/client/mysqlshow.c
+++ b/client/mysqlshow.c
@@ -281,6 +281,8 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
opt_verbose++;
break;
case 'p':
+ if (argument == disabled_my_option)
+ argument= (char*) ""; /* Don't require password */
if (argument)
{
char *start=argument;
diff --git a/client/mysqlslap.c b/client/mysqlslap.c
index b8515289df5..316fb6a9da3 100644
--- a/client/mysqlslap.c
+++ b/client/mysqlslap.c
@@ -712,6 +712,8 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
verbose++;
break;
case 'p':
+ if (argument == disabled_my_option)
+ argument= (char*) ""; /* Don't require password */
if (argument)
{
char *start= argument;
diff --git a/client/mysqltest.cc b/client/mysqltest.cc
index fdd4ff141bc..265d3b0a8e7 100644
--- a/client/mysqltest.cc
+++ b/client/mysqltest.cc
@@ -280,6 +280,7 @@ enum enum_commands {
Q_SEND_QUIT, Q_CHANGE_USER, Q_MKDIR, Q_RMDIR,
Q_LIST_FILES, Q_LIST_FILES_WRITE_FILE, Q_LIST_FILES_APPEND_FILE,
Q_SEND_SHUTDOWN, Q_SHUTDOWN_SERVER,
+ Q_MOVE_FILE,
Q_UNKNOWN, /* Unknown command. */
Q_COMMENT, /* Comments, ignored. */
@@ -376,6 +377,7 @@ const char *command_names[]=
"list_files_append_file",
"send_shutdown",
"shutdown_server",
+ "move_file",
0
};
@@ -966,6 +968,7 @@ void check_command_args(struct st_command *command,
for (i= 0; i < num_args; i++)
{
const struct command_arg *arg= &args[i];
+ char delimiter;
switch (arg->type) {
/* A string */
@@ -974,8 +977,15 @@ void check_command_args(struct st_command *command,
while (*ptr && *ptr == ' ')
ptr++;
start= ptr;
- /* Find end of arg, terminated by "delimiter_arg" */
- while (*ptr && *ptr != delimiter_arg)
+ delimiter = delimiter_arg;
+ /* If start of arg is ' ` or " search to matching quote end instead */
+ if (*ptr && strchr ("'`\"", *ptr))
+ {
+ delimiter= *ptr;
+ start= ++ptr;
+ }
+ /* Find end of arg, terminated by "delimiter" */
+ while (*ptr && *ptr != delimiter)
ptr++;
if (ptr > start)
{
@@ -987,6 +997,11 @@ void check_command_args(struct st_command *command,
/* Empty string */
init_dynamic_string(arg->ds, "", 0, 0);
}
+ /* Find real end of arg, terminated by "delimiter_arg" */
+ /* This will do nothing if arg was not closed by quotes */
+ while (*ptr && *ptr != delimiter_arg)
+ ptr++;
+
command->last_argument= (char*)ptr;
/* Step past the delimiter */
@@ -1445,34 +1460,38 @@ static int run_tool(const char *tool_path, DYNAMIC_STRING *ds_res, ...)
Test if diff is present. This is needed on Windows systems
as the OS returns 1 whether diff is successful or if it is
not present.
- Takes name of diff program as argument
-
+
We run diff -v and look for output in stdout.
We don't redirect stderr to stdout to make for a simplified check
Windows will output '"diff"' is not recognized... to stderr if it is
not present.
*/
-int diff_check (const char *diff_name)
+#ifdef __WIN__
+
+static int diff_check(const char *diff_name)
{
- char buf[512]= {0};
- FILE *res_file;
- char cmd[128];
- my_snprintf (cmd, sizeof(cmd), "%s -v", diff_name);
- int have_diff = 0;
+ FILE *res_file;
+ char buf[128];
+ int have_diff= 0;
- if (!(res_file= popen(cmd, "r")))
- die("popen(\"%s\", \"r\") failed", cmd);
+ my_snprintf(buf, sizeof(buf), "%s -v", diff_name);
- /* if diff is not present, nothing will be in stdout to increment have_diff */
- if (fgets(buf, sizeof(buf), res_file))
- {
- have_diff += 1;
- }
- pclose(res_file);
- return have_diff;
+ if (!(res_file= popen(buf, "r")))
+ die("popen(\"%s\", \"r\") failed", buf);
+
+ /* if diff is not present, nothing will be in stdout to increment have_diff */
+ if (fgets(buf, sizeof(buf), res_file))
+ have_diff= 1;
+
+ pclose(res_file);
+
+ return have_diff;
}
+#endif
+
+
/*
Show the diff of two files using the systems builtin diff
command. If no such diff command exist, just dump the content
@@ -1794,7 +1813,7 @@ void check_result()
log_file.file_name(), reject_file, errno);
show_diff(NULL, result_file_name, reject_file);
- die(mess);
+ die("%s", mess);
break;
}
default: /* impossible */
@@ -2889,6 +2908,42 @@ void do_copy_file(struct st_command *command)
}
+/*
+ SYNOPSIS
+ do_move_file
+ command command handle
+
+ DESCRIPTION
+ move_file
+ Move to
+*/
+
+void do_move_file(struct st_command *command)
+{
+ int error;
+ static DYNAMIC_STRING ds_from_file;
+ static DYNAMIC_STRING ds_to_file;
+ const struct command_arg move_file_args[] = {
+ { "from_file", ARG_STRING, TRUE, &ds_from_file, "Filename to move from" },
+ { "to_file", ARG_STRING, TRUE, &ds_to_file, "Filename to move to" }
+ };
+ DBUG_ENTER("do_move_file");
+
+ check_command_args(command, command->first_argument,
+ move_file_args,
+ sizeof(move_file_args)/sizeof(struct command_arg),
+ ' ');
+
+ DBUG_PRINT("info", ("Move %s to %s", ds_from_file.str, ds_to_file.str));
+ error= (my_rename(ds_from_file.str, ds_to_file.str,
+ MYF(0)) != 0);
+ handle_command_error(command, error);
+ dynstr_free(&ds_from_file);
+ dynstr_free(&ds_to_file);
+ DBUG_VOID_RETURN;
+}
+
+
/*
SYNOPSIS
do_chmod_file
@@ -4546,7 +4601,7 @@ void select_connection(struct st_command *command)
};
check_command_args(command, command->first_argument, connection_args,
sizeof(connection_args)/sizeof(struct command_arg),
- ',');
+ ' ');
DBUG_PRINT("info", ("changing connection: %s", ds_connection.str));
select_connection_name(ds_connection.str);
@@ -5665,11 +5720,11 @@ static struct my_option my_long_options[] =
{"sp-protocol", OPT_SP_PROTOCOL, "Use stored procedures for select",
(uchar**) &sp_protocol, (uchar**) &sp_protocol, 0,
GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
+#include "sslopt-longopts.h"
{"tail-lines", OPT_TAIL_LINES,
"Number of lines of the resul to include in a failure report",
(uchar**) &opt_tail_lines, (uchar**) &opt_tail_lines, 0,
GET_INT, REQUIRED_ARG, 0, 0, 10000, 0, 0, 0},
-#include "sslopt-longopts.h"
{"test-file", 'x', "Read test from/in this file (default stdin).",
0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"timer-file", 'm', "File where the timing in micro seconds is stored.",
@@ -5803,6 +5858,8 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
break;
}
case 'p':
+ if (argument == disabled_my_option)
+ argument= (char*) ""; // Don't require password
if (argument)
{
my_free(opt_pass, MYF(MY_ALLOW_ZERO_PTR));
@@ -7678,6 +7735,7 @@ int main(int argc, char **argv)
case Q_CHANGE_USER: do_change_user(command); break;
case Q_CAT_FILE: do_cat_file(command); break;
case Q_COPY_FILE: do_copy_file(command); break;
+ case Q_MOVE_FILE: do_move_file(command); break;
case Q_CHMOD_FILE: do_chmod_file(command); break;
case Q_PERL: do_perl(command); break;
case Q_DELIMITER:
diff --git a/cmd-line-utils/readline/Makefile.am b/cmd-line-utils/readline/Makefile.am
index 5fcbcde0516..e5f5717858d 100644
--- a/cmd-line-utils/readline/Makefile.am
+++ b/cmd-line-utils/readline/Makefile.am
@@ -31,7 +31,7 @@ noinst_HEADERS = readline.h chardefs.h keymaps.h \
EXTRA_DIST= emacs_keymap.c vi_keymap.c
-DEFS = -DUNDEF_THREADS_HACK -DHAVE_CONFIG_H -DNO_KILL_INTR
+DEFS = -DMYSQL_CLIENT_NO_THREADS -DHAVE_CONFIG_H -DNO_KILL_INTR
# Don't update the files from bitkeeper
%::SCCS/s.%
diff --git a/cmd-line-utils/readline/bind.c b/cmd-line-utils/readline/bind.c
index baed1dfad49..490691943a8 100644
--- a/cmd-line-utils/readline/bind.c
+++ b/cmd-line-utils/readline/bind.c
@@ -79,7 +79,7 @@ static int _rl_read_init_file PARAMS((const char *, int));
static int glean_key_from_name PARAMS((char *));
static int find_boolean_var PARAMS((const char *));
-static char *_rl_get_string_variable_value PARAMS((const char *));
+static const char *_rl_get_string_variable_value PARAMS((const char *));
static int substring_member_of_array PARAMS((char *, const char **));
static int currently_reading_init_file;
@@ -442,7 +442,7 @@ rl_translate_keyseq (seq, array, len)
{
register int i, c, l, temp;
- for (i = l = 0; c = seq[i]; i++)
+ for (i = l = 0; (c = seq[i]); i++)
{
if (c == '\\')
{
@@ -701,7 +701,7 @@ rl_function_of_keyseq (keyseq, map, type)
{
unsigned char ic = keyseq[i];
- if (META_CHAR (ic) && _rl_convert_meta_chars_to_ascii)
+ if (META_CHAR_FOR_UCHAR (ic) && _rl_convert_meta_chars_to_ascii)
{
if (map[ESC].type == ISKMAP)
{
@@ -776,7 +776,8 @@ _rl_read_file (filename, sizep)
file_size = (size_t)finfo.st_size;
/* check for overflow on very large files */
- if (file_size != finfo.st_size || file_size + 1 < file_size)
+if ((sizeof(off_t) > sizeof(size_t) && finfo.st_size > (off_t)(size_t)~0) ||
+ file_size + 1 < file_size)
{
if (file >= 0)
close (file);
@@ -807,7 +808,7 @@ _rl_read_file (filename, sizep)
/* Re-read the current keybindings file. */
int
rl_re_read_init_file (count, ignore)
- int count, ignore;
+ int count __attribute__((unused)), ignore __attribute__((unused));
{
int r;
r = rl_read_init_file ((const char *)NULL);
@@ -1031,7 +1032,7 @@ parser_if (args)
/* Invert the current parser state if there is anything on the stack. */
static int
parser_else (args)
- char *args;
+ char *args __attribute__((unused));
{
register int i;
@@ -1062,7 +1063,7 @@ parser_else (args)
_rl_parsing_conditionalized_out from the stack. */
static int
parser_endif (args)
- char *args;
+ char *args __attribute__((unused));
{
if (if_stack_depth)
_rl_parsing_conditionalized_out = if_stack[--if_stack_depth];
@@ -1185,7 +1186,7 @@ rl_parse_and_bind (string)
{
int passc = 0;
- for (i = 1; c = string[i]; i++)
+ for (i = 1; (c = string[i]); i++)
{
if (passc)
{
@@ -1276,7 +1277,7 @@ rl_parse_and_bind (string)
int delimiter, passc;
delimiter = string[i++];
- for (passc = 0; c = string[i]; i++)
+ for (passc = 0; (c = string[i]); i++)
{
if (passc)
{
@@ -1436,7 +1437,7 @@ static struct {
#if defined (VISIBLE_STATS)
{ "visible-stats", &rl_visible_stats, 0 },
#endif /* VISIBLE_STATS */
- { (char *)NULL, (int *)NULL }
+ { (char *)NULL, (int *)NULL, 0 }
};
static int
@@ -1505,7 +1506,7 @@ static struct {
{ "editing-mode", V_STRING, sv_editmode },
{ "isearch-terminators", V_STRING, sv_isrchterm },
{ "keymap", V_STRING, sv_keymap },
- { (char *)NULL, 0 }
+ { (char *)NULL, 0, (_rl_sv_func_t*)NULL }
};
static int
@@ -1532,7 +1533,7 @@ bool_to_int (value)
(value[0] == '1' && value[1] == '\0'));
}
-char *
+const char *
rl_variable_value (name)
const char *name;
{
@@ -1799,7 +1800,7 @@ rl_set_keymap_from_edit_mode ()
#endif /* VI_MODE */
}
-char *
+const char *
rl_get_keymap_name_from_edit_mode ()
{
if (rl_editing_mode == emacs_mode)
@@ -2048,7 +2049,7 @@ rl_function_dumper (print_readably)
fprintf (rl_outstream, "\n");
- for (i = 0; name = names[i]; i++)
+ for (i = 0; (name = names[i]); i++)
{
rl_command_func_t *function;
char **invokers;
@@ -2108,7 +2109,7 @@ rl_function_dumper (print_readably)
the output in such a way that it can be read back in. */
int
rl_dump_functions (count, key)
- int count, key;
+ int count __attribute__((unused)), key __attribute__((unused));
{
if (rl_dispatching)
fprintf (rl_outstream, "\r\n");
@@ -2188,7 +2189,7 @@ rl_macro_dumper (print_readably)
int
rl_dump_macros (count, key)
- int count, key;
+ int count __attribute__((unused)), key __attribute__((unused));
{
if (rl_dispatching)
fprintf (rl_outstream, "\r\n");
@@ -2197,12 +2198,13 @@ rl_dump_macros (count, key)
return (0);
}
-static char *
+static const char *
_rl_get_string_variable_value (name)
const char *name;
{
static char numbuf[32];
- char *ret;
+ const char *ret;
+ char *tmp;
if (_rl_stricmp (name, "bell-style") == 0)
{
@@ -2230,11 +2232,11 @@ _rl_get_string_variable_value (name)
{
if (_rl_isearch_terminators == 0)
return 0;
- ret = _rl_untranslate_macro_value (_rl_isearch_terminators);
- if (ret)
+ tmp = _rl_untranslate_macro_value (_rl_isearch_terminators);
+ if (tmp)
{
- strncpy (numbuf, ret, sizeof (numbuf) - 1);
- free (ret);
+ strncpy (numbuf, tmp, sizeof (numbuf) - 1);
+ free (tmp);
numbuf[sizeof(numbuf) - 1] = '\0';
}
else
@@ -2257,7 +2259,7 @@ rl_variable_dumper (print_readably)
int print_readably;
{
int i;
- char *v;
+ const char *v;
for (i = 0; boolean_varlist[i].name; i++)
{
@@ -2286,7 +2288,7 @@ rl_variable_dumper (print_readably)
the output in such a way that it can be read back in. */
int
rl_dump_variables (count, key)
- int count, key;
+ int count __attribute__((unused)), key __attribute__((unused));
{
if (rl_dispatching)
fprintf (rl_outstream, "\r\n");
diff --git a/cmd-line-utils/readline/chardefs.h b/cmd-line-utils/readline/chardefs.h
index def3a111bd3..0787d9943bb 100644
--- a/cmd-line-utils/readline/chardefs.h
+++ b/cmd-line-utils/readline/chardefs.h
@@ -59,7 +59,8 @@
#define largest_char 255 /* Largest character value. */
#define CTRL_CHAR(c) ((c) < control_character_threshold && (((c) & 0x80) == 0))
-#define META_CHAR(c) ((c) > meta_character_threshold && (c) <= largest_char)
+#define META_CHAR_FOR_UCHAR(c) ((c) > meta_character_threshold)
+#define META_CHAR(c) (META_CHAR_FOR_UCHAR(c) && (c) <= largest_char)
#define CTRL(c) ((c) & control_character_mask)
#define META(c) ((c) | meta_character_bit)
diff --git a/cmd-line-utils/readline/complete.c b/cmd-line-utils/readline/complete.c
index 916aa5dd9b9..2745e4e4801 100644
--- a/cmd-line-utils/readline/complete.c
+++ b/cmd-line-utils/readline/complete.c
@@ -359,14 +359,14 @@ rl_complete (ignore, invoking_key)
/* List the possible completions. See description of rl_complete (). */
int
rl_possible_completions (ignore, invoking_key)
- int ignore, invoking_key;
+ int ignore __attribute__((unused)), invoking_key __attribute__((unused));
{
return (rl_complete_internal ('?'));
}
int
rl_insert_completions (ignore, invoking_key)
- int ignore, invoking_key;
+ int ignore __attribute__((unused)), invoking_key __attribute__((unused));
{
return (rl_complete_internal ('*'));
}
@@ -696,7 +696,8 @@ print_filename (to_print, full_pathname)
char *to_print, *full_pathname;
{
int printed_len, extension_char, slen, tlen;
- char *s, c, *new_full_pathname, *dn;
+ char *s, c, *new_full_pathname;
+ const char *dn;
extension_char = 0;
printed_len = fnprint (to_print);
@@ -783,7 +784,7 @@ print_filename (to_print, full_pathname)
static char *
rl_quote_filename (s, rtype, qcp)
char *s;
- int rtype;
+ int rtype __attribute__((unused));
char *qcp;
{
char *r;
@@ -884,7 +885,7 @@ _rl_find_completion_word (fp, dp)
/* We didn't find an unclosed quoted substring upon which to do
completion, so use the word break characters to find the
substring on which to complete. */
- while (rl_point = MB_PREVCHAR (rl_line_buffer, rl_point, MB_FIND_ANY))
+ while ((rl_point = MB_PREVCHAR (rl_line_buffer, rl_point, MB_FIND_ANY)))
{
scan = rl_line_buffer[rl_point];
@@ -1803,7 +1804,7 @@ rl_completion_matches (text, entry_function)
match_list = (char **)xmalloc ((match_list_size + 1) * sizeof (char *));
match_list[1] = (char *)NULL;
- while (string = (*entry_function) (text, matches))
+ while ((string = (*entry_function) (text, matches)))
{
if (matches + 1 == match_list_size)
match_list = (char **)xrealloc
@@ -2111,7 +2112,7 @@ rl_filename_completion_function (text, state)
ring the bell, and reset the counter to zero. */
int
rl_menu_complete (count, ignore)
- int count, ignore;
+ int count, ignore __attribute__((unused));
{
rl_compentry_func_t *our_func;
int matching_filenames, found_quote;
diff --git a/cmd-line-utils/readline/display.c b/cmd-line-utils/readline/display.c
index 6f63faa9738..f9b88f0006c 100644
--- a/cmd-line-utils/readline/display.c
+++ b/cmd-line-utils/readline/display.c
@@ -127,7 +127,7 @@ int _rl_want_redisplay = 0;
/* The stuff that gets printed out before the actual text of the line.
This is usually pointing to rl_prompt. */
-char *rl_display_prompt = (char *)NULL;
+const char *rl_display_prompt = (const char *)NULL;
/* Pseudo-global variables declared here. */
@@ -229,7 +229,10 @@ expand_prompt (pmt, lp, lip, niflp, vlp)
int *lp, *lip, *niflp, *vlp;
{
char *r, *ret, *p, *igstart;
- int l, rl, last, ignoring, ninvis, invfl, invflset, ind, pind, physchars;
+ int l, rl, last, ignoring, ninvis, invfl, invflset, physchars;
+#if defined (HANDLE_MULTIBYTE)
+ int ind, pind;
+#endif
/* Short-circuit if we can. */
if ((MB_CUR_MAX <= 1 || rl_byte_oriented) && strchr (pmt, RL_PROMPT_START_IGNORE) == 0)
@@ -242,7 +245,7 @@ expand_prompt (pmt, lp, lip, niflp, vlp)
if (niflp)
*niflp = 0;
if (vlp)
- *vlp = lp ? *lp : strlen (r);
+ *vlp = lp ? *lp : (int)strlen (r);
return r;
}
@@ -459,9 +462,10 @@ rl_redisplay ()
register int in, out, c, linenum, cursor_linenum;
register char *line;
int inv_botlin, lb_botlin, lb_linenum, o_cpos;
- int newlines, lpos, temp, modmark, n0, num;
- char *prompt_this_line;
+ int newlines, lpos, temp, modmark;
+ const char *prompt_this_line;
#if defined (HANDLE_MULTIBYTE)
+ int num, n0;
wchar_t wc;
size_t wc_bytes;
int wc_width;
@@ -626,7 +630,6 @@ rl_redisplay ()
contents of the command line? */
while (lpos >= _rl_screenwidth)
{
- int z;
/* fix from Darin Johnson for prompt string with
invisible characters that is longer than the screen width. The
prompt_invis_chars_first_line variable could be made into an array
@@ -635,6 +638,7 @@ rl_redisplay ()
prompts that exceed two physical lines?
Additional logic fix from Edward Catmur */
#if defined (HANDLE_MULTIBYTE)
+ int z;
if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
{
n0 = num;
@@ -878,6 +882,7 @@ rl_redisplay ()
if (_rl_horizontal_scroll_mode == 0 && _rl_term_up && *_rl_term_up)
{
int nleft, pos, changed_screen_line, tx;
+ char empty_str[1] = { 0 };
if (!rl_display_fixed || forced_display)
{
@@ -902,7 +907,7 @@ rl_redisplay ()
#define VIS_LLEN(l) ((l) > _rl_vis_botlin ? 0 : (vis_lbreaks[l+1] - vis_lbreaks[l]))
#define INV_LLEN(l) (inv_lbreaks[l+1] - inv_lbreaks[l])
#define VIS_CHARS(line) (visible_line + vis_lbreaks[line])
-#define VIS_LINE(line) ((line) > _rl_vis_botlin) ? "" : VIS_CHARS(line)
+#define VIS_LINE(line) ((line) > _rl_vis_botlin) ? empty_str : VIS_CHARS(line)
#define INV_LINE(line) (invisible_line + inv_lbreaks[line])
/* For each line in the buffer, do the updating display. */
@@ -969,7 +974,7 @@ rl_redisplay ()
_rl_move_vert (linenum);
_rl_move_cursor_relative (0, tt);
_rl_clear_to_eol
- ((linenum == _rl_vis_botlin) ? strlen (tt) : _rl_screenwidth);
+ ((linenum == _rl_vis_botlin) ? (int)strlen (tt) : _rl_screenwidth);
}
}
_rl_vis_botlin = inv_botlin;
@@ -1888,7 +1893,7 @@ rl_character_len (c, pos)
uc = (unsigned char)c;
- if (META_CHAR (uc))
+ if (META_CHAR_FOR_UCHAR (uc))
return ((_rl_output_meta_chars == 0) ? 4 : 1);
if (uc == '\t')
@@ -2261,7 +2266,7 @@ static void
redraw_prompt (t)
char *t;
{
- char *oldp;
+ const char *oldp;
oldp = rl_display_prompt;
rl_save_prompt ();
diff --git a/cmd-line-utils/readline/histexpand.c b/cmd-line-utils/readline/histexpand.c
index 45377fc3b5e..ab8d8ecc866 100644
--- a/cmd-line-utils/readline/histexpand.c
+++ b/cmd-line-utils/readline/histexpand.c
@@ -87,14 +87,14 @@ char history_comment_char = '\0';
/* The list of characters which inhibit the expansion of text if found
immediately following history_expansion_char. */
-char *history_no_expand_chars = " \t\n\r=";
+const char *history_no_expand_chars = " \t\n\r=";
/* If set to a non-zero value, single quotes inhibit history expansion.
The default is 0. */
int history_quotes_inhibit_expansion = 0;
/* Used to split words by history_tokenize_internal. */
-char *history_word_delimiters = HISTORY_WORD_DELIMITERS;
+const char *history_word_delimiters = HISTORY_WORD_DELIMITERS;
/* If set, this points to a function that is called to verify that a
particular history expansion should be performed. */
@@ -203,7 +203,7 @@ get_history_event (string, caller_index, delimiting_quote)
}
/* Only a closing `?' or a newline delimit a substring search string. */
- for (local_index = i; c = string[i]; i++)
+ for (local_index = i; (c = string[i]); i++)
{
#if defined (HANDLE_MULTIBYTE)
if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
diff --git a/cmd-line-utils/readline/histfile.c b/cmd-line-utils/readline/histfile.c
index d98293d933c..118c5ebd328 100644
--- a/cmd-line-utils/readline/histfile.c
+++ b/cmd-line-utils/readline/histfile.c
@@ -186,7 +186,8 @@ read_history_range (filename, from, to)
file_size = (size_t)finfo.st_size;
/* check for overflow on very large files */
- if (file_size != finfo.st_size || file_size + 1 < file_size)
+if ((sizeof(off_t) > sizeof(size_t) && finfo.st_size > (off_t)(size_t)~0) ||
+ file_size + 1 < file_size)
{
errno = overflow_errno;
goto error_and_exit;
@@ -339,7 +340,8 @@ history_truncate_file (fname, lines)
file_size = (size_t)finfo.st_size;
/* check for overflow on very large files */
- if (file_size != finfo.st_size || file_size + 1 < file_size)
+if ((sizeof(off_t) > sizeof(size_t) && finfo.st_size > (off_t)(size_t)~0) ||
+ file_size + 1 < file_size)
{
close (file);
#if defined (EFBIG)
diff --git a/cmd-line-utils/readline/history.h b/cmd-line-utils/readline/history.h
index 14ca2a996c7..5790ed1c71d 100644
--- a/cmd-line-utils/readline/history.h
+++ b/cmd-line-utils/readline/history.h
@@ -243,9 +243,9 @@ extern int history_length;
extern int history_max_entries;
extern char history_expansion_char;
extern char history_subst_char;
-extern char *history_word_delimiters;
+extern const char *history_word_delimiters;
extern char history_comment_char;
-extern char *history_no_expand_chars;
+extern const char *history_no_expand_chars;
extern char *history_search_delimiter_chars;
extern int history_quotes_inhibit_expansion;
diff --git a/cmd-line-utils/readline/input.c b/cmd-line-utils/readline/input.c
index 62c0443d890..84c0422059a 100644
--- a/cmd-line-utils/readline/input.c
+++ b/cmd-line-utils/readline/input.c
@@ -420,7 +420,7 @@ rl_read_key ()
else
{
/* If input is coming from a macro, then use that. */
- if (c = _rl_next_macro_key ())
+ if ((c = _rl_next_macro_key ()))
return (c);
/* If the user has an event function, then call it periodically. */
diff --git a/cmd-line-utils/readline/isearch.c b/cmd-line-utils/readline/isearch.c
index 8060adb97cd..305c847d8da 100644
--- a/cmd-line-utils/readline/isearch.c
+++ b/cmd-line-utils/readline/isearch.c
@@ -75,7 +75,7 @@ static int _rl_isearch_cleanup PARAMS((_rl_search_cxt *, int));
static char *last_isearch_string;
static int last_isearch_string_len;
-static char *default_isearch_terminators = "\033\012";
+static const char *default_isearch_terminators = "\033\012";
_rl_search_cxt *
_rl_scxt_alloc (type, flags)
@@ -119,7 +119,7 @@ _rl_scxt_alloc (type, flags)
void
_rl_scxt_dispose (cxt, flags)
_rl_search_cxt *cxt;
- int flags;
+ int flags __attribute__((unused));
{
FREE (cxt->search_string);
FREE (cxt->allocated_line);
@@ -154,7 +154,7 @@ rl_forward_search_history (sign, key)
static void
rl_display_search (search_string, reverse_p, where)
char *search_string;
- int reverse_p, where;
+ int reverse_p, where __attribute__((unused));
{
char *message;
int msglen, searchlen;
@@ -614,7 +614,7 @@ _rl_isearch_cleanup (cxt, r)
backwards. */
static int
rl_search_history (direction, invoking_key)
- int direction, invoking_key;
+ int direction, invoking_key __attribute__((unused));
{
_rl_search_cxt *cxt; /* local for now, but saved globally */
int c, r;
diff --git a/cmd-line-utils/readline/kill.c b/cmd-line-utils/readline/kill.c
index 42c53948689..adae2e1cd07 100644
--- a/cmd-line-utils/readline/kill.c
+++ b/cmd-line-utils/readline/kill.c
@@ -79,7 +79,7 @@ static int rl_yank_nth_arg_internal PARAMS((int, int, int));
of kill material. */
int
rl_set_retained_kills (num)
- int num;
+ int num __attribute__((unused));
{
return 0;
}
@@ -296,7 +296,7 @@ rl_backward_kill_line (direction, ignore)
/* Kill the whole line, no matter where point is. */
int
rl_kill_full_line (count, ignore)
- int count, ignore;
+ int count __attribute__((unused)), ignore __attribute__((unused));
{
rl_begin_undo_group ();
rl_point = 0;
@@ -314,7 +314,7 @@ rl_kill_full_line (count, ignore)
using behaviour that they expect. */
int
rl_unix_word_rubout (count, key)
- int count, key;
+ int count, key __attribute__((unused));
{
int orig_point;
@@ -347,7 +347,7 @@ rl_unix_word_rubout (count, key)
deletes backward to directory separator (`/') or whitespace. */
int
rl_unix_filename_rubout (count, key)
- int count, key;
+ int count, key __attribute__((unused));
{
int orig_point, c;
@@ -391,7 +391,7 @@ rl_unix_filename_rubout (count, key)
doing. */
int
rl_unix_line_discard (count, key)
- int count, key;
+ int count __attribute__((unused)), key __attribute__((unused));
{
if (rl_point == 0)
rl_ding ();
@@ -428,7 +428,7 @@ region_kill_internal (delete)
/* Copy the text in the region to the kill ring. */
int
rl_copy_region_to_kill (count, ignore)
- int count, ignore;
+ int count __attribute__((unused)), ignore __attribute__((unused));
{
return (region_kill_internal (0));
}
@@ -436,7 +436,7 @@ rl_copy_region_to_kill (count, ignore)
/* Kill the text between the point and mark. */
int
rl_kill_region (count, ignore)
- int count, ignore;
+ int count __attribute__((unused)), ignore __attribute__((unused));
{
int r, npoint;
@@ -501,7 +501,7 @@ rl_copy_backward_word (count, key)
/* Yank back the last killed text. This ignores arguments. */
int
rl_yank (count, ignore)
- int count, ignore;
+ int count __attribute__((unused)), ignore __attribute__((unused));
{
if (rl_kill_ring == 0)
{
@@ -520,7 +520,7 @@ rl_yank (count, ignore)
yank back some other text. */
int
rl_yank_pop (count, key)
- int count, key;
+ int count __attribute__((unused)), key __attribute__((unused));
{
int l, n;
diff --git a/cmd-line-utils/readline/macro.c b/cmd-line-utils/readline/macro.c
index 3473f705335..0ee7b3077c3 100644
--- a/cmd-line-utils/readline/macro.c
+++ b/cmd-line-utils/readline/macro.c
@@ -201,7 +201,7 @@ _rl_kill_kbd_macro ()
re-executing the existing macro. */
int
rl_start_kbd_macro (ignore1, ignore2)
- int ignore1, ignore2;
+ int ignore1 __attribute__((unused)), ignore2 __attribute__((unused));
{
if (RL_ISSTATE (RL_STATE_MACRODEF))
{
@@ -226,7 +226,7 @@ rl_start_kbd_macro (ignore1, ignore2)
that many times, counting the definition as the first time. */
int
rl_end_kbd_macro (count, ignore)
- int count, ignore;
+ int count, ignore __attribute__((unused));
{
if (RL_ISSTATE (RL_STATE_MACRODEF) == 0)
{
@@ -246,7 +246,7 @@ rl_end_kbd_macro (count, ignore)
COUNT says how many times to execute it. */
int
rl_call_last_kbd_macro (count, ignore)
- int count, ignore;
+ int count, ignore __attribute__((unused));
{
if (current_macro == 0)
_rl_abort_internal ();
diff --git a/cmd-line-utils/readline/mbutil.c b/cmd-line-utils/readline/mbutil.c
index e21708fb748..b571afa18bb 100644
--- a/cmd-line-utils/readline/mbutil.c
+++ b/cmd-line-utils/readline/mbutil.c
@@ -346,8 +346,8 @@ _rl_char_value (buf, ind)
#undef _rl_find_next_mbchar
int
_rl_find_next_mbchar (string, seed, count, flags)
- char *string;
- int seed, count, flags;
+ char *string __attribute__((unused));
+ int seed, count, flags __attribute__((unused));
{
#if defined (HANDLE_MULTIBYTE)
return _rl_find_next_mbchar_internal (string, seed, count, flags);
@@ -362,8 +362,8 @@ _rl_find_next_mbchar (string, seed, count, flags)
#undef _rl_find_prev_mbchar
int
_rl_find_prev_mbchar (string, seed, flags)
- char *string;
- int seed, flags;
+ char *string __attribute__((unused));
+ int seed, flags __attribute__((unused));
{
#if defined (HANDLE_MULTIBYTE)
return _rl_find_prev_mbchar_internal (string, seed, flags);
diff --git a/cmd-line-utils/readline/misc.c b/cmd-line-utils/readline/misc.c
index e0e6893c60e..f5f0370fb6a 100644
--- a/cmd-line-utils/readline/misc.c
+++ b/cmd-line-utils/readline/misc.c
@@ -228,7 +228,7 @@ _rl_reset_argument ()
/* Start a numeric argument with initial value KEY */
int
rl_digit_argument (ignore, key)
- int ignore, key;
+ int ignore __attribute__((unused)), key;
{
_rl_arg_init ();
if (RL_ISSTATE (RL_STATE_CALLBACK))
@@ -249,7 +249,7 @@ rl_digit_argument (ignore, key)
dispatch on it. If the key is the abort character then abort. */
int
rl_universal_argument (count, key)
- int count, key;
+ int count __attribute__((unused)), key __attribute__((unused));
{
_rl_arg_init ();
rl_numeric_arg *= 4;
@@ -413,7 +413,7 @@ _rl_history_set_point ()
void
rl_replace_from_history (entry, flags)
HIST_ENTRY *entry;
- int flags; /* currently unused */
+ int flags __attribute__((unused)); /* currently unused */
{
/* Can't call with `1' because rl_undo_list might point to an undo list
from a history entry, just like we're setting up here. */
@@ -440,7 +440,7 @@ rl_replace_from_history (entry, flags)
/* Meta-< goes to the start of the history. */
int
rl_beginning_of_history (count, key)
- int count, key;
+ int count __attribute__((unused)), key;
{
return (rl_get_previous_history (1 + where_history (), key));
}
@@ -448,7 +448,7 @@ rl_beginning_of_history (count, key)
/* Meta-> goes to the end of the history. (The current line). */
int
rl_end_of_history (count, key)
- int count, key;
+ int count __attribute__((unused)), key __attribute__((unused));
{
rl_maybe_replace_line ();
using_history ();
@@ -553,7 +553,7 @@ rl_get_previous_history (count, key)
/* How to toggle back and forth between editing modes. */
int
rl_vi_editing_mode (count, key)
- int count, key;
+ int count __attribute__((unused)), key;
{
#if defined (VI_MODE)
_rl_set_insert_mode (RL_IM_INSERT, 1); /* vi mode ignores insert mode */
@@ -566,7 +566,7 @@ rl_vi_editing_mode (count, key)
int
rl_emacs_editing_mode (count, key)
- int count, key;
+ int count __attribute__((unused)), key __attribute__((unused));
{
rl_editing_mode = emacs_mode;
_rl_set_insert_mode (RL_IM_INSERT, 1); /* emacs mode default is insert mode */
@@ -577,7 +577,7 @@ rl_emacs_editing_mode (count, key)
/* Function for the rest of the library to use to set insert/overwrite mode. */
void
_rl_set_insert_mode (im, force)
- int im, force;
+ int im, force __attribute__((unused));
{
#ifdef CURSOR_MODE
_rl_set_cursor (im, force);
@@ -590,7 +590,7 @@ _rl_set_insert_mode (im, force)
mode. A negative or zero explicit argument selects insert mode. */
int
rl_overwrite_mode (count, key)
- int count, key;
+ int count, key __attribute__((unused));
{
if (rl_explicit_arg == 0)
_rl_set_insert_mode (rl_insert_mode ^ 1, 0);
diff --git a/cmd-line-utils/readline/nls.c b/cmd-line-utils/readline/nls.c
index 6ec685ed9ea..ff40b14228c 100644
--- a/cmd-line-utils/readline/nls.c
+++ b/cmd-line-utils/readline/nls.c
@@ -101,7 +101,8 @@ _rl_init_eightbit ()
/* If we have setlocale(3), just check the current LC_CTYPE category
value, and go into eight-bit mode if it's not C or POSIX. */
#if defined (HAVE_SETLOCALE)
- char *lspec, *t;
+ const char *lspec;
+ char *t;
/* Set the LC_CTYPE locale category from environment variables. */
lspec = _rl_get_locale_var ("LC_CTYPE");
@@ -127,7 +128,8 @@ _rl_init_eightbit ()
return (0);
#else /* !HAVE_SETLOCALE */
- char *lspec, *t;
+ const char *lspec;
+ char *t;
int i;
/* We don't have setlocale. Finesse it. Check the environment for the
diff --git a/cmd-line-utils/readline/readline.c b/cmd-line-utils/readline/readline.c
index 8c3cad52d36..fb92becdbf9 100644
--- a/cmd-line-utils/readline/readline.c
+++ b/cmd-line-utils/readline/readline.c
@@ -90,7 +90,7 @@ static void bind_arrow_keys_internal PARAMS((Keymap));
static void bind_arrow_keys PARAMS((void));
static void readline_default_bindings PARAMS((void));
-static void reset_default_bindings PARAMS((void));
+static void reset_default_bindings PARAMS((void)) __attribute__((unused));
static int _rl_subseq_result PARAMS((int, Keymap, int, int));
static int _rl_subseq_getchar PARAMS((int));
diff --git a/cmd-line-utils/readline/readline.h b/cmd-line-utils/readline/readline.h
index b71bf98d204..668a452c765 100644
--- a/cmd-line-utils/readline/readline.h
+++ b/cmd-line-utils/readline/readline.h
@@ -304,7 +304,7 @@ extern int rl_bind_keyseq_if_unbound PARAMS((const char *, rl_command_func_t *))
extern int rl_bind_keyseq_if_unbound_in_map PARAMS((const char *, rl_command_func_t *, Keymap));
extern int rl_generic_bind PARAMS((int, const char *, char *, Keymap));
-extern char *rl_variable_value PARAMS((const char *));
+extern const char *rl_variable_value PARAMS((const char *));
extern int rl_variable_bind PARAMS((const char *, const char *));
/* Backwards compatibility, use rl_bind_keyseq_in_map instead. */
@@ -343,7 +343,7 @@ extern void rl_set_keymap PARAMS((Keymap));
extern Keymap rl_get_keymap PARAMS((void));
/* Undocumented; used internally only. */
extern void rl_set_keymap_from_edit_mode PARAMS((void));
-extern char *rl_get_keymap_name_from_edit_mode PARAMS((void));
+extern const char *rl_get_keymap_name_from_edit_mode PARAMS((void));
/* Functions for manipulating the funmap, which maps command names to functions. */
extern int rl_add_funmap_entry PARAMS((const char *, rl_command_func_t *));
@@ -406,7 +406,7 @@ extern void rl_set_screen_size PARAMS((int, int));
extern void rl_get_screen_size PARAMS((int *, int *));
extern void rl_reset_screen_size PARAMS((void));
-extern char *rl_get_termcap PARAMS((const char *));
+extern const char *rl_get_termcap PARAMS((const char *));
/* Functions for character input. */
extern int rl_stuff_char PARAMS((int));
diff --git a/cmd-line-utils/readline/rlprivate.h b/cmd-line-utils/readline/rlprivate.h
index 64aa7bdd3fa..1ab696766b0 100644
--- a/cmd-line-utils/readline/rlprivate.h
+++ b/cmd-line-utils/readline/rlprivate.h
@@ -77,7 +77,7 @@ typedef struct __rl_search_context
int sline_len;
int sline_index;
- char *search_terminators;
+ const char *search_terminators;
} _rl_search_cxt;
/* Callback data for reading numeric arguments */
@@ -164,7 +164,7 @@ extern int rl_set_retained_kills PARAMS((int));
extern void _rl_set_screen_size PARAMS((int, int));
/* undo.c */
-extern int _rl_fix_last_undo_of_type PARAMS((int, int, int));
+extern int _rl_fix_last_undo_of_type PARAMS((enum undo_code, int, int));
/* util.c */
extern char *_rl_savestring PARAMS((const char *));
@@ -359,7 +359,7 @@ extern int _rl_vis_botlin;
extern int _rl_last_c_pos;
extern int _rl_suppress_redisplay;
extern int _rl_want_redisplay;
-extern char *rl_display_prompt;
+extern const char *rl_display_prompt;
/* isearch.c */
extern char *_rl_isearch_terminators;
@@ -398,17 +398,17 @@ extern _rl_search_cxt *_rl_nscxt;
/* terminal.c */
extern int _rl_enable_keypad;
extern int _rl_enable_meta;
-extern char *_rl_term_clreol;
-extern char *_rl_term_clrpag;
-extern char *_rl_term_im;
-extern char *_rl_term_ic;
-extern char *_rl_term_ei;
-extern char *_rl_term_DC;
-extern char *_rl_term_up;
-extern char *_rl_term_dc;
-extern char *_rl_term_cr;
-extern char *_rl_term_IC;
-extern char *_rl_term_forward_char;
+extern const char *_rl_term_clreol;
+extern const char *_rl_term_clrpag;
+extern const char *_rl_term_im;
+extern const char *_rl_term_ic;
+extern const char *_rl_term_ei;
+extern const char *_rl_term_DC;
+extern const char *_rl_term_up;
+extern const char *_rl_term_dc;
+extern const char *_rl_term_cr;
+extern const char *_rl_term_IC;
+extern const char *_rl_term_forward_char;
extern int _rl_screenheight;
extern int _rl_screenwidth;
extern int _rl_screenchars;
diff --git a/cmd-line-utils/readline/rltty.c b/cmd-line-utils/readline/rltty.c
index 8c896bd3b26..8849206fd6d 100644
--- a/cmd-line-utils/readline/rltty.c
+++ b/cmd-line-utils/readline/rltty.c
@@ -764,7 +764,7 @@ rl_deprep_terminal ()
int
rl_restart_output (count, key)
- int count, key;
+ int count __attribute__((unused)), key __attribute__((unused));
{
#if defined (__MINGW32__)
return 0;
@@ -802,7 +802,7 @@ rl_restart_output (count, key)
int
rl_stop_output (count, key)
- int count, key;
+ int count __attribute__((unused)), key __attribute__((unused));
{
#if defined (__MINGW32__)
return 0;
diff --git a/cmd-line-utils/readline/search.c b/cmd-line-utils/readline/search.c
index cfa5db1dc17..1da450a692a 100644
--- a/cmd-line-utils/readline/search.c
+++ b/cmd-line-utils/readline/search.c
@@ -211,7 +211,7 @@ _rl_nsearch_init (dir, pchar)
rl_end = rl_point = 0;
p = _rl_make_prompt_for_search (pchar ? pchar : ':');
- rl_message ("%s", p, 0);
+ rl_message ("%s", p);
free (p);
RL_SETSTATE(RL_STATE_NSEARCH);
@@ -383,7 +383,7 @@ noninc_search (dir, pchar)
code calls this, KEY will be `?'. */
int
rl_noninc_forward_search (count, key)
- int count, key;
+ int count __attribute__((unused)), key;
{
return noninc_search (1, (key == '?') ? '?' : 0);
}
@@ -392,7 +392,7 @@ rl_noninc_forward_search (count, key)
calls this, KEY will be `/'. */
int
rl_noninc_reverse_search (count, key)
- int count, key;
+ int count __attribute__((unused)), key;
{
return noninc_search (-1, (key == '/') ? '/' : 0);
}
@@ -401,7 +401,7 @@ rl_noninc_reverse_search (count, key)
for. If there is no saved search string, abort. */
int
rl_noninc_forward_search_again (count, key)
- int count, key;
+ int count __attribute__((unused)), key __attribute__((unused));
{
int r;
@@ -418,7 +418,7 @@ rl_noninc_forward_search_again (count, key)
for. If there is no saved search string, abort. */
int
rl_noninc_reverse_search_again (count, key)
- int count, key;
+ int count __attribute__((unused)), key __attribute__((unused));
{
int r;
diff --git a/cmd-line-utils/readline/terminal.c b/cmd-line-utils/readline/terminal.c
index a630bc02e05..3f92821f9dd 100644
--- a/cmd-line-utils/readline/terminal.c
+++ b/cmd-line-utils/readline/terminal.c
@@ -104,34 +104,36 @@ char PC, *BC, *UP;
#endif /* __linux__ */
/* Some strings to control terminal actions. These are output by tputs (). */
-char *_rl_term_clreol;
-char *_rl_term_clrpag;
-char *_rl_term_cr;
-char *_rl_term_backspace;
-char *_rl_term_goto;
-char *_rl_term_pc;
+const char *_rl_term_clreol;
+const char *_rl_term_clrpag;
+const char *_rl_term_cr;
+const char *_rl_term_backspace;
+char _rl_term_backspace_default[2] = { '\b', 0 };
+const char *_rl_term_goto;
+const char *_rl_term_pc;
/* Non-zero if we determine that the terminal can do character insertion. */
int _rl_terminal_can_insert = 0;
/* How to insert characters. */
-char *_rl_term_im;
-char *_rl_term_ei;
-char *_rl_term_ic;
-char *_rl_term_ip;
-char *_rl_term_IC;
+const char *_rl_term_im;
+const char *_rl_term_ei;
+const char *_rl_term_ic;
+const char *_rl_term_ip;
+const char *_rl_term_IC;
/* How to delete characters. */
-char *_rl_term_dc;
-char *_rl_term_DC;
+const char *_rl_term_dc;
+const char *_rl_term_DC;
-char *_rl_term_forward_char;
+const char *_rl_term_forward_char;
/* How to go up a line. */
-char *_rl_term_up;
+const char *_rl_term_up;
+char _rl_term_up_default[2] = { 0, 0 };
/* A visible bell; char if the terminal can be made to flash the screen. */
-static char *_rl_visible_bell;
+static const char *_rl_visible_bell;
/* Non-zero means the terminal can auto-wrap lines. */
int _rl_term_autowrap = -1;
@@ -141,33 +143,33 @@ static int term_has_meta;
/* The sequences to write to turn on and off the meta key, if this
terminal has one. */
-static char *_rl_term_mm;
-static char *_rl_term_mo;
+static const char *_rl_term_mm;
+static const char *_rl_term_mo;
/* The key sequences output by the arrow keys, if this terminal has any. */
-static char *_rl_term_ku;
-static char *_rl_term_kd;
-static char *_rl_term_kr;
-static char *_rl_term_kl;
+static const char *_rl_term_ku;
+static const char *_rl_term_kd;
+static const char *_rl_term_kr;
+static const char *_rl_term_kl;
/* How to initialize and reset the arrow keys, if this terminal has any. */
-static char *_rl_term_ks;
-static char *_rl_term_ke;
+static const char *_rl_term_ks;
+static const char *_rl_term_ke;
/* The key sequences sent by the Home and End keys, if any. */
-static char *_rl_term_kh;
-static char *_rl_term_kH;
-static char *_rl_term_at7; /* @7 */
+static const char *_rl_term_kh;
+static const char *_rl_term_kH;
+static const char *_rl_term_at7; /* @7 */
/* Delete key */
-static char *_rl_term_kD;
+static const char *_rl_term_kD;
/* Insert key */
-static char *_rl_term_kI;
+static const char *_rl_term_kI;
/* Cursor control */
-static char *_rl_term_vs; /* very visible */
-static char *_rl_term_ve; /* normal */
+static const char *_rl_term_vs; /* very visible */
+static const char *_rl_term_ve; /* normal */
static void bind_termcap_arrow_keys PARAMS((Keymap));
@@ -362,7 +364,7 @@ rl_resize_terminal ()
struct _tc_string {
const char *tc_var;
- char **tc_value;
+ const char **tc_value;
};
/* This should be kept sorted, just in case we decide to change the
@@ -409,7 +411,7 @@ get_term_capabilities (bp)
char **bp;
{
#if !defined (__DJGPP__) /* XXX - doesn't DJGPP have a termcap library? */
- register int i;
+ register unsigned int i;
for (i = 0; i < NUM_TC_STRINGS; i++)
*(tc_strings[i].tc_value) = tgetstr ((char *)tc_strings[i].tc_var, bp);
@@ -496,8 +498,9 @@ _rl_init_terminal_io (terminal_name)
tgoto if _rl_term_IC or _rl_term_DC is defined, but just in case we
change that later... */
PC = '\0';
- BC = _rl_term_backspace = "\b";
- UP = _rl_term_up;
+ _rl_term_backspace = _rl_term_backspace_default;
+ BC = (char*)_rl_term_backspace;
+ UP = (char*)_rl_term_up;
return 0;
}
@@ -507,8 +510,8 @@ _rl_init_terminal_io (terminal_name)
/* Set up the variables that the termcap library expects the application
to provide. */
PC = _rl_term_pc ? *_rl_term_pc : 0;
- BC = _rl_term_backspace;
- UP = _rl_term_up;
+ BC = (char*)_rl_term_backspace;
+ UP = (char*)_rl_term_up;
if (!_rl_term_cr)
_rl_term_cr = "\r";
@@ -568,11 +571,11 @@ bind_termcap_arrow_keys (map)
_rl_keymap = xkeymap;
}
-char *
+const char *
rl_get_termcap (cap)
const char *cap;
{
- register int i;
+ register unsigned int i;
if (tcap_initialized == 0)
return ((char *)NULL);
diff --git a/cmd-line-utils/readline/text.c b/cmd-line-utils/readline/text.c
index b26afeda525..272848c798c 100644
--- a/cmd-line-utils/readline/text.c
+++ b/cmd-line-utils/readline/text.c
@@ -410,7 +410,7 @@ rl_backward (count, key)
/* Move to the beginning of the line. */
int
rl_beg_of_line (count, key)
- int count, key;
+ int count __attribute__((unused)), key __attribute__((unused));
{
rl_point = 0;
return 0;
@@ -419,7 +419,7 @@ rl_beg_of_line (count, key)
/* Move to the end of the line. */
int
rl_end_of_line (count, key)
- int count, key;
+ int count __attribute__((unused)), key __attribute__((unused));
{
rl_point = rl_end;
return 0;
@@ -527,7 +527,7 @@ rl_backward_word (count, key)
/* Clear the current line. Numeric argument to C-l does this. */
int
rl_refresh_line (ignore1, ignore2)
- int ignore1, ignore2;
+ int ignore1 __attribute__((unused)), ignore2 __attribute__((unused));
{
int curr_line;
@@ -566,7 +566,7 @@ rl_clear_screen (count, key)
int
rl_arrow_keys (count, c)
- int count, c;
+ int count, c __attribute__((unused));
{
int ch;
@@ -884,7 +884,7 @@ _rl_insert_next_callback (data)
int
rl_quoted_insert (count, key)
- int count, key;
+ int count, key __attribute__((unused));
{
/* Let's see...should the callback interface futz with signal handling? */
#if defined (HANDLE_SIGNALS)
@@ -907,7 +907,7 @@ rl_quoted_insert (count, key)
/* Insert a tab character. */
int
rl_tab_insert (count, key)
- int count, key;
+ int count, key __attribute__((unused));
{
return (_rl_insert_char (count, '\t'));
}
@@ -917,7 +917,7 @@ rl_tab_insert (count, key)
meaning in the future. */
int
rl_newline (count, key)
- int count, key;
+ int count __attribute__((unused)), key __attribute__((unused));
{
rl_done = 1;
@@ -951,7 +951,7 @@ rl_newline (count, key)
is special cased. */
int
rl_do_lowercase_version (ignore1, ignore2)
- int ignore1, ignore2;
+ int ignore1 __attribute__((unused)), ignore2 __attribute__((unused));
{
return 0;
}
@@ -1118,7 +1118,7 @@ rl_rubout_or_delete (count, key)
/* Delete all spaces and tabs around point. */
int
rl_delete_horizontal_space (count, ignore)
- int count, ignore;
+ int count __attribute__((unused)), ignore __attribute__((unused));
{
int start = rl_point;
@@ -1163,9 +1163,9 @@ rl_delete_or_show_completions (count, key)
A K*rn shell style function. */
int
rl_insert_comment (count, key)
- int count, key;
+ int count __attribute__((unused)), key;
{
- char *rl_comment_text;
+ const char *rl_comment_text;
int rl_comment_len;
rl_beg_of_line (1, key);
@@ -1202,7 +1202,7 @@ rl_insert_comment (count, key)
/* Uppercase the word at point. */
int
rl_upcase_word (count, key)
- int count, key;
+ int count, key __attribute__((unused));
{
return (rl_change_case (count, UpCase));
}
@@ -1210,7 +1210,7 @@ rl_upcase_word (count, key)
/* Lowercase the word at point. */
int
rl_downcase_word (count, key)
- int count, key;
+ int count, key __attribute__((unused));
{
return (rl_change_case (count, DownCase));
}
@@ -1218,7 +1218,7 @@ rl_downcase_word (count, key)
/* Upcase the first letter, downcase the rest. */
int
rl_capitalize_word (count, key)
- int count, key;
+ int count, key __attribute__((unused));
{
return (rl_change_case (count, CapCase));
}
@@ -1381,7 +1381,7 @@ rl_transpose_words (count, key)
then transpose the characters before point. */
int
rl_transpose_chars (count, key)
- int count, key;
+ int count, key __attribute__((unused));
{
#if defined (HANDLE_MULTIBYTE)
char *dummy;
@@ -1557,7 +1557,7 @@ _rl_char_search_callback (data)
int
rl_char_search (count, key)
- int count, key;
+ int count, key __attribute__((unused));
{
#if defined (READLINE_CALLBACKS)
if (RL_ISSTATE (RL_STATE_CALLBACK))
@@ -1575,7 +1575,7 @@ rl_char_search (count, key)
int
rl_backward_char_search (count, key)
- int count, key;
+ int count, key __attribute__((unused));
{
#if defined (READLINE_CALLBACKS)
if (RL_ISSTATE (RL_STATE_CALLBACK))
@@ -1612,7 +1612,7 @@ _rl_set_mark_at_pos (position)
/* A bindable command to set the mark. */
int
rl_set_mark (count, key)
- int count, key;
+ int count, key __attribute__((unused));
{
return (_rl_set_mark_at_pos (rl_explicit_arg ? count : rl_point));
}
@@ -1620,7 +1620,7 @@ rl_set_mark (count, key)
/* Exchange the position of mark and point. */
int
rl_exchange_point_and_mark (count, key)
- int count, key;
+ int count __attribute__((unused)), key __attribute__((unused));
{
if (rl_mark > rl_end)
rl_mark = -1;
diff --git a/cmd-line-utils/readline/tilde.c b/cmd-line-utils/readline/tilde.c
index d50f7a0ffa4..128cc26d9a7 100644
--- a/cmd-line-utils/readline/tilde.c
+++ b/cmd-line-utils/readline/tilde.c
@@ -196,7 +196,7 @@ tilde_expand (string)
int result_size, result_index;
result_index = result_size = 0;
- if (result = strchr (string, '~'))
+ if ((result = strchr (string, '~')))
result = (char *)xmalloc (result_size = (strlen (string) + 16));
else
result = (char *)xmalloc (result_size = (strlen (string) + 1));
diff --git a/cmd-line-utils/readline/undo.c b/cmd-line-utils/readline/undo.c
index 5699193b14c..79846c26024 100644
--- a/cmd-line-utils/readline/undo.c
+++ b/cmd-line-utils/readline/undo.c
@@ -231,7 +231,8 @@ rl_do_undo ()
int
_rl_fix_last_undo_of_type (type, start, end)
- int type, start, end;
+ enum undo_code type;
+ int start, end;
{
UNDO_LIST *rl;
@@ -289,7 +290,7 @@ rl_modifying (start, end)
/* Revert the current line to its previous state. */
int
rl_revert_line (count, key)
- int count, key;
+ int count __attribute__((unused)), key __attribute__((unused));
{
if (!rl_undo_list)
rl_ding ();
@@ -309,7 +310,7 @@ rl_revert_line (count, key)
/* Do some undoing of things that were done. */
int
rl_undo_command (count, key)
- int count, key;
+ int count, key __attribute__((unused));
{
if (count < 0)
return 0; /* Nothing to do. */
diff --git a/cmd-line-utils/readline/util.c b/cmd-line-utils/readline/util.c
index 935c9c927c2..50cfea75cb9 100644
--- a/cmd-line-utils/readline/util.c
+++ b/cmd-line-utils/readline/util.c
@@ -115,14 +115,14 @@ _rl_abort_internal ()
int
rl_abort (count, key)
- int count, key;
+ int count __attribute__((unused)), key __attribute__((unused));
{
return (_rl_abort_internal ());
}
int
rl_tty_status (count, key)
- int count, key;
+ int count __attribute__((unused)), key __attribute__((unused));
{
#if defined (TIOCSTAT)
ioctl (1, TIOCSTAT, (char *)0);
@@ -172,7 +172,7 @@ rl_extend_line_buffer (len)
/* A function for simple tilde expansion. */
int
rl_tilde_expand (ignore, key)
- int ignore, key;
+ int ignore __attribute__((unused)), key __attribute__((unused));
{
register int start, end;
char *homedir, *temp;
diff --git a/cmd-line-utils/readline/vi_mode.c b/cmd-line-utils/readline/vi_mode.c
index 25213cb762f..620bb863c7b 100644
--- a/cmd-line-utils/readline/vi_mode.c
+++ b/cmd-line-utils/readline/vi_mode.c
@@ -131,7 +131,7 @@ static int _rl_vi_callback_char_search PARAMS((_rl_callback_generic_arg *));
void
_rl_vi_initialize_line ()
{
- register int i;
+ register size_t i;
for (i = 0; i < sizeof (vi_mark_chars) / sizeof (int); i++)
vi_mark_chars[i] = -1;
@@ -190,7 +190,7 @@ _rl_vi_stuff_insert (count)
puts you back into insert mode. */
int
rl_vi_redo (count, c)
- int count, c;
+ int count, c __attribute__((unused));
{
int r;
@@ -238,7 +238,7 @@ rl_vi_undo (count, key)
/* Yank the nth arg from the previous line into this line at point. */
int
rl_vi_yank_arg (count, key)
- int count, key;
+ int count, key __attribute__((unused));
{
/* Readline thinks that the first word on a line is the 0th, while vi
thinks the first word on a line is the 1st. Compensate. */
@@ -321,7 +321,7 @@ rl_vi_search (count, key)
/* Completion, from vi's point of view. */
int
rl_vi_complete (ignore, key)
- int ignore, key;
+ int ignore __attribute__((unused)), key;
{
if ((rl_point < rl_end) && (!whitespace (rl_line_buffer[rl_point])))
{
@@ -348,7 +348,7 @@ rl_vi_complete (ignore, key)
/* Tilde expansion for vi mode. */
int
rl_vi_tilde_expand (ignore, key)
- int ignore, key;
+ int ignore __attribute__((unused)), key;
{
rl_tilde_expand (0, key);
rl_vi_start_inserting (key, 1, rl_arg_sign);
@@ -419,7 +419,7 @@ rl_vi_end_word (count, key)
/* Move forward a word the way that 'W' does. */
int
rl_vi_fWord (count, ignore)
- int count, ignore;
+ int count, ignore __attribute__((unused));
{
while (count-- && rl_point < (rl_end - 1))
{
@@ -436,7 +436,7 @@ rl_vi_fWord (count, ignore)
int
rl_vi_bWord (count, ignore)
- int count, ignore;
+ int count, ignore __attribute__((unused));
{
while (count-- && rl_point > 0)
{
@@ -460,7 +460,7 @@ rl_vi_bWord (count, ignore)
int
rl_vi_eWord (count, ignore)
- int count, ignore;
+ int count, ignore __attribute__((unused));
{
while (count-- && rl_point < (rl_end - 1))
{
@@ -491,7 +491,7 @@ rl_vi_eWord (count, ignore)
int
rl_vi_fword (count, ignore)
- int count, ignore;
+ int count, ignore __attribute__((unused));
{
while (count-- && rl_point < (rl_end - 1))
{
@@ -517,7 +517,7 @@ rl_vi_fword (count, ignore)
int
rl_vi_bword (count, ignore)
- int count, ignore;
+ int count, ignore __attribute__((unused));
{
while (count-- && rl_point > 0)
{
@@ -556,7 +556,7 @@ rl_vi_bword (count, ignore)
int
rl_vi_eword (count, ignore)
- int count, ignore;
+ int count, ignore __attribute__((unused));
{
while (count-- && rl_point < rl_end - 1)
{
@@ -581,7 +581,7 @@ rl_vi_eword (count, ignore)
int
rl_vi_insert_beg (count, key)
- int count, key;
+ int count __attribute__((unused)), key;
{
rl_beg_of_line (1, key);
rl_vi_insertion_mode (1, key);
@@ -610,7 +610,7 @@ _rl_vi_append_forward (key)
int
rl_vi_append_mode (count, key)
- int count, key;
+ int count __attribute__((unused)), key;
{
_rl_vi_append_forward (key);
rl_vi_start_inserting (key, 1, rl_arg_sign);
@@ -619,7 +619,7 @@ rl_vi_append_mode (count, key)
int
rl_vi_append_eol (count, key)
- int count, key;
+ int count __attribute__((unused)), key;
{
rl_end_of_line (1, key);
rl_vi_append_mode (1, key);
@@ -629,7 +629,7 @@ rl_vi_append_eol (count, key)
/* What to do in the case of C-d. */
int
rl_vi_eof_maybe (count, c)
- int count, c;
+ int count __attribute__((unused)), c __attribute__((unused));
{
return (rl_newline (1, '\n'));
}
@@ -640,7 +640,7 @@ rl_vi_eof_maybe (count, c)
switching keymaps. */
int
rl_vi_insertion_mode (count, key)
- int count, key;
+ int count __attribute__((unused)), key;
{
_rl_keymap = vi_insertion_keymap;
_rl_vi_last_key_before_insert = key;
@@ -703,7 +703,7 @@ _rl_vi_done_inserting ()
int
rl_vi_movement_mode (count, key)
- int count, key;
+ int count __attribute__((unused)), key;
{
if (rl_point > 0)
rl_backward_char (1, key);
@@ -783,7 +783,7 @@ _rl_vi_change_mbchar_case (count)
int
rl_vi_change_case (count, ignore)
- int count, ignore;
+ int count, ignore __attribute__((unused));
{
int c, p;
@@ -1031,7 +1031,7 @@ rl_digit_loop1 ()
int
rl_vi_delete_to (count, key)
- int count, key;
+ int count __attribute__((unused)), key;
{
int c;
@@ -1057,7 +1057,7 @@ rl_vi_delete_to (count, key)
int
rl_vi_change_to (count, key)
- int count, key;
+ int count __attribute__((unused)), key;
{
int c, start_pos;
@@ -1110,7 +1110,7 @@ rl_vi_change_to (count, key)
int
rl_vi_yank_to (count, key)
- int count, key;
+ int count __attribute__((unused)), key;
{
int c, save;
@@ -1202,7 +1202,7 @@ rl_vi_delete (count, key)
int
rl_vi_back_to_indent (count, key)
- int count, key;
+ int count __attribute__((unused)), key;
{
rl_beg_of_line (1, key);
while (rl_point < rl_end && whitespace (rl_line_buffer[rl_point]))
@@ -1212,7 +1212,7 @@ rl_vi_back_to_indent (count, key)
int
rl_vi_first_print (count, key)
- int count, key;
+ int count __attribute__((unused)), key;
{
return (rl_vi_back_to_indent (1, key));
}
@@ -1319,7 +1319,7 @@ rl_vi_char_search (count, key)
/* Match brackets */
int
rl_vi_match (ignore, key)
- int ignore, key;
+ int ignore __attribute__((unused)), key;
{
int count = 1, brack, pos, tmp, pre;
@@ -1426,7 +1426,7 @@ rl_vi_bracktype (c)
static int
_rl_vi_change_char (count, c, mb)
int count, c;
- char *mb;
+ char *mb __attribute__((unused));
{
int p;
@@ -1458,8 +1458,8 @@ _rl_vi_change_char (count, c, mb)
static int
_rl_vi_callback_getchar (mb, mlen)
- char *mb;
- int mlen;
+ char *mb __attribute__((unused));
+ int mlen __attribute__((unused));
{
int c;
@@ -1494,7 +1494,7 @@ _rl_vi_callback_change_char (data)
int
rl_vi_change_char (count, key)
- int count, key;
+ int count, key __attribute__((unused));
{
int c;
char mb[MB_LEN_MAX];
@@ -1582,7 +1582,7 @@ rl_vi_overstrike_delete (count, key)
int
rl_vi_replace (count, key)
- int count, key;
+ int count __attribute__((unused)), key __attribute__((unused));
{
int i;
@@ -1663,7 +1663,7 @@ _rl_vi_set_mark ()
#if defined (READLINE_CALLBACKS)
static int
_rl_vi_callback_set_mark (data)
- _rl_callback_generic_arg *data;
+ _rl_callback_generic_arg *data __attribute__((unused));
{
_rl_callback_func = 0;
_rl_want_redisplay = 1;
@@ -1674,7 +1674,7 @@ _rl_vi_callback_set_mark (data)
int
rl_vi_set_mark (count, key)
- int count, key;
+ int count __attribute__((unused)), key __attribute__((unused));
{
#if defined (READLINE_CALLBACKS)
if (RL_ISSTATE (RL_STATE_CALLBACK))
@@ -1721,7 +1721,7 @@ _rl_vi_goto_mark ()
#if defined (READLINE_CALLBACKS)
static int
_rl_vi_callback_goto_mark (data)
- _rl_callback_generic_arg *data;
+ _rl_callback_generic_arg *data __attribute__((unused));
{
_rl_callback_func = 0;
_rl_want_redisplay = 1;
@@ -1732,7 +1732,7 @@ _rl_vi_callback_goto_mark (data)
int
rl_vi_goto_mark (count, key)
- int count, key;
+ int count __attribute__((unused)), key __attribute__((unused));
{
#if defined (READLINE_CALLBACKS)
if (RL_ISSTATE (RL_STATE_CALLBACK))
diff --git a/configure.in b/configure.in
index ec9774d05c6..a291ce73210 100644
--- a/configure.in
+++ b/configure.in
@@ -604,10 +604,11 @@ AC_SUBST(NOINST_LDFLAGS)
# Check if we are using Linux and a glibc compiled with static nss
# (this is true on the MySQL build machines to avoid NSS problems)
#
+AC_CHECK_TOOL([NM], [nm])
if test "$TARGET_LINUX" = "true" -a "$static_nss" = ""
then
- tmp=`nm /usr/lib*/libc.a | grep _nss_files_getaliasent_r`
+ tmp=`$NM ${other_libc_lib:-/usr/lib*}/libc.a | grep _nss_files_getaliasent_r1`
if test -n "$tmp"
then
STATIC_NSS_FLAGS="-lc -lnss_files -lnss_dns -lresolv"
@@ -1641,7 +1642,7 @@ esac
# Build optimized or debug version ?
# First check for gcc and g++
-if test "$ac_cv_prog_gcc" = "yes"
+if test "$GCC" = "yes"
then
DEBUG_CFLAGS="-g"
DEBUG_OPTIMIZE_CC="-O"
@@ -1649,9 +1650,16 @@ then
else
DEBUG_CFLAGS="-g"
DEBUG_OPTIMIZE_CC=""
- OPTIMIZE_CFLAGS="-O"
+ case $SYSTEM_TYPE in
+ *solaris*)
+ OPTIMIZE_CFLAGS="-O1"
+ ;;
+ *)
+ OPTIMIZE_CFLAGS="-O"
+ ;;
+ esac
fi
-if test "$ac_cv_prog_cxx_g" = "yes"
+if test "$GXX" = "yes"
then
DEBUG_CXXFLAGS="-g"
DEBUG_OPTIMIZE_CXX="-O"
@@ -1659,7 +1667,14 @@ then
else
DEBUG_CXXFLAGS="-g"
DEBUG_OPTIMIZE_CXX=""
- OPTIMIZE_CXXFLAGS="-O"
+ case $SYSTEM_TYPE in
+ *solaris*)
+ OPTIMIZE_CXXFLAGS="-O1"
+ ;;
+ *)
+ OPTIMIZE_CXXFLAGS="-O"
+ ;;
+ esac
fi
case $SYSTEM_TYPE in
@@ -2119,6 +2134,25 @@ case "$mysql_cv_sys_os" in
# unsupported priority values are passed to pthread_setschedprio.
# Since the only supported value is 1, treat it as inexistent.
;;
+ SunOS) # Bug#42599 error: `pthread_setschedprio' was not declared in this scope
+ # In some installations, the pthread.h header used by GCC does not
+ # declare the pthread_setscheprio prototype, but the function is
+ # implemented. Since the function is used in C++ code, ensure that
+ # the function prototype is present.
+ AC_MSG_CHECKING([whether pthread_setschedprio is declared])
+ AC_LANG_PUSH([C++])
+ AC_COMPILE_IFELSE([
+ AC_LANG_PROGRAM([#include ],
+ [(void)(pthread_setschedprio);])],
+ [ac_cv_func_pthread_setschedprio=yes],
+ [ac_cv_func_pthread_setschedprio=no])
+ AC_LANG_POP([C++])
+ AC_MSG_RESULT([$ac_cv_func_pthread_setschedprio])
+ if test "$ac_cv_func_pthread_setschedprio" = yes; then
+ AC_DEFINE(HAVE_PTHREAD_SETSCHEDPRIO, 1,
+ [Define to 1 if you have the `pthread_setschedprio' function.])
+ fi
+ ;;
*) AC_CHECK_FUNCS(pthread_setschedprio)
;;
esac
diff --git a/dbug/user.r b/dbug/user.r
index 19de840d0ad..ef67ef7a7cf 100644
--- a/dbug/user.r
+++ b/dbug/user.r
@@ -32,6 +32,7 @@
.\" === Set line length
.\".ll 6.5i
.TL
+.warn 0
D B U G
.P 0
C Program Debugging Package
diff --git a/extra/innochecksum.c b/extra/innochecksum.c
index 524637a1729..9bd4bfcc0cd 100644
--- a/extra/innochecksum.c
+++ b/extra/innochecksum.c
@@ -224,7 +224,7 @@ int main(int argc, char **argv)
}
else if (verbose)
{
- printf("file %s= %llu bytes (%lu pages)...\n", argv[1], size, pages);
+ printf("file %s = %llu bytes (%lu pages)...\n", argv[optind], size, pages);
printf("checking pages in range %lu to %lu\n", start_page, use_end_page ? end_page : (pages - 1));
}
diff --git a/extra/perror.c b/extra/perror.c
index 80eb2af2dae..a98a4fc3d1b 100644
--- a/extra/perror.c
+++ b/extra/perror.c
@@ -115,7 +115,7 @@ static void usage(void)
{
print_version();
puts("This software comes with ABSOLUTELY NO WARRANTY. This is free software,\nand you are welcome to modify and redistribute it under the GPL license\n");
- printf("Print a description for a system error code or an error code from\na MyISAM/ISAM/BDB table handler.\n");
+ printf("Print a description for a system error code or a MySQL error code.\n");
printf("If you want to get the error for a negative error code, you should use\n-- before the first error code to tell perror that there was no more options.\n\n");
printf("Usage: %s [OPTIONS] [ERRORCODE [ERRORCODE...]]\n",my_progname);
my_print_help(my_long_options);
diff --git a/extra/yassl/src/handshake.cpp b/extra/yassl/src/handshake.cpp
index 262b5cb3b8b..b4d9005af15 100644
--- a/extra/yassl/src/handshake.cpp
+++ b/extra/yassl/src/handshake.cpp
@@ -790,15 +790,17 @@ void processReply(SSL& ssl)
if (ssl.GetError()) return;
if (DoProcessReply(ssl))
+ {
// didn't complete process
if (!ssl.getSocket().IsNonBlocking()) {
// keep trying now, blocking ok
while (!ssl.GetError())
if (DoProcessReply(ssl) == 0) break;
- }
+ }
else
// user will have try again later, non blocking
ssl.SetError(YasslError(SSL_ERROR_WANT_READ));
+ }
}
@@ -873,10 +875,12 @@ void sendServerKeyExchange(SSL& ssl, BufferOutput buffer)
void sendChangeCipher(SSL& ssl, BufferOutput buffer)
{
if (ssl.getSecurity().get_parms().entity_ == server_end)
+ {
if (ssl.getSecurity().get_resuming())
ssl.verifyState(clientKeyExchangeComplete);
else
ssl.verifyState(clientFinishedComplete);
+ }
if (ssl.GetError()) return;
ChangeCipherSpec ccs;
diff --git a/extra/yassl/src/yassl_imp.cpp b/extra/yassl/src/yassl_imp.cpp
index 20dfe50f132..f079df8c7ce 100644
--- a/extra/yassl/src/yassl_imp.cpp
+++ b/extra/yassl/src/yassl_imp.cpp
@@ -1305,6 +1305,7 @@ void ServerHello::Process(input_buffer&, SSL& ssl)
ssl.useSecurity().use_connection().sessionID_Set_ = false;
if (ssl.getSecurity().get_resuming())
+ {
if (memcmp(session_id_, ssl.getSecurity().get_resume().GetID(),
ID_LEN) == 0) {
ssl.set_masterSecret(ssl.getSecurity().get_resume().GetSecret());
@@ -1319,6 +1320,7 @@ void ServerHello::Process(input_buffer&, SSL& ssl)
ssl.useSecurity().set_resuming(false);
ssl.useLog().Trace("server denied resumption");
}
+ }
if (ssl.CompressionOn() && !compression_method_)
ssl.UnSetCompression(); // server isn't supporting yaSSL zlib request
diff --git a/extra/yassl/taocrypt/include/modes.hpp b/extra/yassl/taocrypt/include/modes.hpp
index d1ebce7568b..4575fe1414b 100644
--- a/extra/yassl/taocrypt/include/modes.hpp
+++ b/extra/yassl/taocrypt/include/modes.hpp
@@ -96,10 +96,12 @@ inline void Mode_BASE::Process(byte* out, const byte* in, word32 sz)
if (mode_ == ECB)
ECB_Process(out, in, sz);
else if (mode_ == CBC)
+ {
if (dir_ == ENCRYPTION)
CBC_Encrypt(out, in, sz);
else
CBC_Decrypt(out, in, sz);
+ }
}
diff --git a/extra/yassl/taocrypt/src/asn.cpp b/extra/yassl/taocrypt/src/asn.cpp
index 3b1c1c2136a..78200841bda 100644
--- a/extra/yassl/taocrypt/src/asn.cpp
+++ b/extra/yassl/taocrypt/src/asn.cpp
@@ -781,10 +781,12 @@ void CertDecoder::GetDate(DateType dt)
source_.advance(length);
if (!ValidateDate(date, b, dt) && verify_)
+ {
if (dt == BEFORE)
source_.SetError(BEFORE_DATE_E);
else
source_.SetError(AFTER_DATE_E);
+ }
// save for later use
if (dt == BEFORE) {
@@ -1062,6 +1064,7 @@ word32 DecodeDSA_Signature(byte* decoded, const byte* encoded, word32 sz)
}
word32 rLen = GetLength(source);
if (rLen != 20)
+ {
if (rLen == 21) { // zero at front, eat
source.next();
--rLen;
@@ -1074,6 +1077,7 @@ word32 DecodeDSA_Signature(byte* decoded, const byte* encoded, word32 sz)
source.SetError(DSA_SZ_E);
return 0;
}
+ }
memcpy(decoded, source.get_buffer() + source.get_index(), rLen);
source.advance(rLen);
@@ -1084,6 +1088,7 @@ word32 DecodeDSA_Signature(byte* decoded, const byte* encoded, word32 sz)
}
word32 sLen = GetLength(source);
if (sLen != 20)
+ {
if (sLen == 21) {
source.next(); // zero at front, eat
--sLen;
@@ -1096,6 +1101,7 @@ word32 DecodeDSA_Signature(byte* decoded, const byte* encoded, word32 sz)
source.SetError(DSA_SZ_E);
return 0;
}
+ }
memcpy(decoded + rLen, source.get_buffer() + source.get_index(), sLen);
source.advance(sLen);
diff --git a/include/hash.h b/include/hash.h
index f4b82454b81..629b404e8a7 100644
--- a/include/hash.h
+++ b/include/hash.h
@@ -106,7 +106,7 @@ void my_hash_replace(HASH *hash, HASH_SEARCH_STATE *state, uchar *new_row);
my_bool my_hash_check(HASH *hash); /* Only in debug library */
#define my_hash_clear(H) bzero((char*) (H), sizeof(*(H)))
-#define my_hash_inited(H) ((H)->array.buffer != 0)
+#define my_hash_inited(H) ((H)->blength != 0)
#define my_hash_init_opt(A,B,C,D,E,F,G,H) \
(!my_hash_inited(A) && _my_hash_init(A,0,B,C,D,E,F,G, H CALLER_INFO))
diff --git a/include/m_ctype.h b/include/m_ctype.h
index 04cf921dfee..451c8db549b 100644
--- a/include/m_ctype.h
+++ b/include/m_ctype.h
@@ -285,7 +285,7 @@ typedef struct charset_info_st
#define ILLEGAL_CHARSET_INFO_NUMBER (~0U)
-extern CHARSET_INFO my_charset_bin;
+extern MYSQL_PLUGIN_IMPORT CHARSET_INFO my_charset_bin;
extern CHARSET_INFO my_charset_big5_chinese_ci;
extern CHARSET_INFO my_charset_big5_bin;
extern CHARSET_INFO my_charset_cp932_japanese_ci;
@@ -298,7 +298,7 @@ extern CHARSET_INFO my_charset_gb2312_chinese_ci;
extern CHARSET_INFO my_charset_gb2312_bin;
extern CHARSET_INFO my_charset_gbk_chinese_ci;
extern CHARSET_INFO my_charset_gbk_bin;
-extern CHARSET_INFO my_charset_latin1;
+extern MYSQL_PLUGIN_IMPORT CHARSET_INFO my_charset_latin1;
extern CHARSET_INFO my_charset_latin1_german2_ci;
extern CHARSET_INFO my_charset_latin1_bin;
extern CHARSET_INFO my_charset_latin2_czech_ci;
@@ -315,7 +315,7 @@ extern CHARSET_INFO my_charset_utf8_general_ci;
extern CHARSET_INFO my_charset_utf8_unicode_ci;
extern CHARSET_INFO my_charset_utf8_bin;
extern CHARSET_INFO my_charset_cp1250_czech_ci;
-extern CHARSET_INFO my_charset_filename;
+extern MYSQL_PLUGIN_IMPORT CHARSET_INFO my_charset_filename;
/* declarations for simple charsets */
extern size_t my_strnxfrm_simple(CHARSET_INFO *, uchar *, size_t,
diff --git a/include/my_global.h b/include/my_global.h
index 9e8c9bdfc70..4ad851e9e5d 100644
--- a/include/my_global.h
+++ b/include/my_global.h
@@ -276,7 +276,7 @@
#endif
/* The client defines this to avoid all thread code */
-#if defined(UNDEF_THREADS_HACK)
+#if defined(MYSQL_CLIENT_NO_THREADS) || defined(UNDEF_THREADS_HACK)
#undef THREAD
#undef HAVE_LINUXTHREADS
#undef HAVE_NPTL
@@ -1573,4 +1573,17 @@ static inline double rint(double x)
}
#endif /* HAVE_RINT */
+/*
+ MYSQL_PLUGIN_IMPORT macro is used to export mysqld data
+ (i.e variables) for usage in storage engine loadable plugins.
+ Outside of Windows, it is dummy.
+*/
+#ifndef MYSQL_PLUGIN_IMPORT
+#if (defined(_WIN32) && defined(MYSQL_DYNAMIC_PLUGIN))
+#define MYSQL_PLUGIN_IMPORT __declspec(dllimport)
+#else
+#define MYSQL_PLUGIN_IMPORT
+#endif
+#endif
+
#endif /* my_global_h */
diff --git a/include/my_sys.h b/include/my_sys.h
index 01804cd089f..222564e0b44 100644
--- a/include/my_sys.h
+++ b/include/my_sys.h
@@ -221,8 +221,8 @@ extern uint my_large_page_size;
#endif
/* charsets */
-extern CHARSET_INFO *default_charset_info;
-extern CHARSET_INFO *all_charsets[256];
+extern MYSQL_PLUGIN_IMPORT CHARSET_INFO *default_charset_info;
+extern MYSQL_PLUGIN_IMPORT CHARSET_INFO *all_charsets[256];
extern CHARSET_INFO compiled_charsets[];
/* statistics */
@@ -237,8 +237,8 @@ extern void (*my_sigtstp_cleanup)(void),
(*my_sigtstp_restart)(void),
(*my_abort_hook)(int);
/* Executed when comming from shell */
-extern int NEAR my_umask, /* Default creation mask */
- NEAR my_umask_dir,
+extern MYSQL_PLUGIN_IMPORT int NEAR my_umask; /* Default creation mask */
+extern int NEAR my_umask_dir,
NEAR my_recived_signals, /* Signals we have got */
NEAR my_safe_to_handle_signal, /* Set when allowed to SIGTSTP */
NEAR my_dont_interrupt; /* call remember_intr when set */
@@ -511,7 +511,7 @@ typedef int (*qsort2_cmp)(const void *, const void *, const void *);
((info)->write_pos + (Count) <=(info)->write_end ?\
(memcpy((info)->write_pos, (Buffer), (size_t)(Count)),\
((info)->write_pos+=(Count)),0) : \
- (*(info)->write_function)((info),(Buffer),(Count)))
+ (*(info)->write_function)((info),(uchar *)(Buffer),(Count)))
#define my_b_get(info) \
((info)->read_pos != (info)->read_end ?\
diff --git a/include/myisam.h b/include/myisam.h
index d7bfdf7191e..02251eeacb4 100644
--- a/include/myisam.h
+++ b/include/myisam.h
@@ -404,7 +404,8 @@ typedef struct st_mi_check_param
my_off_t keydata,totaldata,key_blocks,start_check_pos;
ha_rows total_records,total_deleted;
ha_checksum record_checksum,glob_crc;
- ulong use_buffers,read_buffer_length,write_buffer_length,
+ ulonglong use_buffers;
+ ulong read_buffer_length,write_buffer_length,
sort_buffer_length,sort_key_blocks;
uint out_flag,warning_printed,error_printed,verbose;
uint opt_sort_key,total_files,max_level;
diff --git a/include/myisammrg.h b/include/myisammrg.h
index dafae157ee0..446ecb7d719 100644
--- a/include/myisammrg.h
+++ b/include/myisammrg.h
@@ -88,7 +88,8 @@ extern MYRG_INFO *myrg_parent_open(const char *parent_name,
void *callback_param);
extern int myrg_attach_children(MYRG_INFO *m_info, int handle_locking,
MI_INFO *(*callback)(void*),
- void *callback_param);
+ void *callback_param,
+ my_bool *need_compat_check);
extern int myrg_detach_children(MYRG_INFO *m_info);
extern int myrg_panic(enum ha_panic_function function);
extern int myrg_rfirst(MYRG_INFO *file,uchar *buf,int inx);
diff --git a/include/mysql/plugin.h b/include/mysql/plugin.h
index a978d44b918..2e59262d061 100644
--- a/include/mysql/plugin.h
+++ b/include/mysql/plugin.h
@@ -16,6 +16,16 @@
#ifndef _my_plugin_h
#define _my_plugin_h
+
+/*
+ On Windows, exports from DLL need to be declared
+*/
+#if (defined(_WIN32) && defined(MYSQL_DYNAMIC_PLUGIN))
+#define MYSQL_PLUGIN_EXPORT extern "C" __declspec(dllexport)
+#else
+#define MYSQL_PLUGIN_EXPORT
+#endif
+
#ifdef __cplusplus
class THD;
class Item;
@@ -90,9 +100,9 @@ int PSIZE= sizeof(struct st_mysql_plugin); \
struct st_mysql_plugin DECLS[]= {
#else
#define __MYSQL_DECLARE_PLUGIN(NAME, VERSION, PSIZE, DECLS) \
-int _mysql_plugin_interface_version_= MYSQL_PLUGIN_INTERFACE_VERSION; \
-int _mysql_sizeof_struct_st_plugin_= sizeof(struct st_mysql_plugin); \
-struct st_mysql_plugin _mysql_plugin_declarations_[]= {
+MYSQL_PLUGIN_EXPORT int _mysql_plugin_interface_version_= MYSQL_PLUGIN_INTERFACE_VERSION; \
+MYSQL_PLUGIN_EXPORT int _mysql_sizeof_struct_st_plugin_= sizeof(struct st_mysql_plugin); \
+MYSQL_PLUGIN_EXPORT struct st_mysql_plugin _mysql_plugin_declarations_[]= {
#endif
#define mysql_declare_plugin(NAME) \
diff --git a/libmysql/Makefile.am b/libmysql/Makefile.am
index 21f8f372d0f..f67abfd8ac6 100644
--- a/libmysql/Makefile.am
+++ b/libmysql/Makefile.am
@@ -21,7 +21,7 @@
# This file is public domain and comes with NO WARRANTY of any kind
target = libmysqlclient.la
-target_defs = -DUNDEF_THREADS_HACK -DDONT_USE_RAID @LIB_EXTRA_CCFLAGS@
+target_defs = -DMYSQL_CLIENT_NO_THREADS -DDONT_USE_RAID @LIB_EXTRA_CCFLAGS@
LIBS = @CLIENT_LIBS@
INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include \
$(openssl_includes) @ZLIB_INCLUDES@
@@ -104,7 +104,7 @@ do-lib-dist:
echo "# A very minimal Makefile to compile" > $$dir/Makefile; \
echo "# the minimized libmysql library" >> $$dir/Makefile; \
echo "# This file is autogenerated from Makefile.am" >> $$dir/Makefile; \
- echo 'CFLAGS= -I. -DUNDEF_THREADS_HACK' >>$$dir/Makefile; \
+ echo 'CFLAGS= -I. -DMYSQL_CLIENT_NO_THREADS' >>$$dir/Makefile; \
echo "obj=$$objs" >>$$dir/Makefile; \
echo 'all: libmysql.a' >>$$dir/Makefile; \
echo 'libmysql.a: $$(obj)' >>$$dir/Makefile; \
diff --git a/libmysqld/CMakeLists.txt b/libmysqld/CMakeLists.txt
index 1c8f80768d4..8500d73863a 100644
--- a/libmysqld/CMakeLists.txt
+++ b/libmysqld/CMakeLists.txt
@@ -87,63 +87,16 @@ FOREACH(rpath ${VIO_SOURCES})
SET(LIB_SOURCES ${LIB_SOURCES} ../vio/${rpath})
ENDFOREACH(rpath)
-# Engines
-INCLUDE(${CMAKE_SOURCE_DIR}/storage/heap/CMakeLists.txt)
-FOREACH(rpath ${HEAP_SOURCES})
- SET(LIB_SOURCES ${LIB_SOURCES} ../storage/heap/${rpath})
-ENDFOREACH(rpath)
-INCLUDE(${CMAKE_SOURCE_DIR}/storage/myisam/CMakeLists.txt)
-FOREACH(rpath ${MYISAM_SOURCES})
- SET(LIB_SOURCES ${LIB_SOURCES} ../storage/myisam/${rpath})
-ENDFOREACH(rpath)
-INCLUDE(${CMAKE_SOURCE_DIR}/storage/myisammrg/CMakeLists.txt)
-FOREACH(rpath ${MYISAMMRG_SOURCES})
- SET(LIB_SOURCES ${LIB_SOURCES} ../storage/myisammrg/${rpath})
-ENDFOREACH(rpath)
-
-IF(WITH_ARCHIVE_STORAGE_ENGINE)
- INCLUDE(${CMAKE_SOURCE_DIR}/storage/archive/CMakeLists.txt)
- FOREACH(rpath ${ARCHIVE_SOURCES})
- SET(LIB_SOURCES ${LIB_SOURCES} ../storage/archive/${rpath})
+FOREACH (ENGINE_LIB ${MYSQLD_STATIC_ENGINE_LIBS})
+ INCLUDE(${CMAKE_SOURCE_DIR}/storage/${ENGINE_LIB}/CMakeLists.txt)
+ STRING(TOUPPER ${ENGINE_LIB} ENGINE_LIB_UPPER)
+ FOREACH(rpath ${${ENGINE_LIB_UPPER}_SOURCES})
+ SET(LIB_SOURCES ${LIB_SOURCES} ${CMAKE_SOURCE_DIR}/storage/${ENGINE_LIB}/${rpath})
ENDFOREACH(rpath)
-ENDIF(WITH_ARCHIVE_STORAGE_ENGINE)
+ENDFOREACH(ENGINE_LIB)
-IF(WITH_BLACKHOLE_STORAGE_ENGINE)
- INCLUDE(${CMAKE_SOURCE_DIR}/storage/blackhole/CMakeLists.txt)
- FOREACH(rpath ${BLACKHOLE_SOURCES})
- SET(LIB_SOURCES ${LIB_SOURCES} ../storage/blackhole/${rpath})
- ENDFOREACH(rpath)
-ENDIF(WITH_BLACKHOLE_STORAGE_ENGINE)
-
-IF(WITH_EXAMPLE_STORAGE_ENGINE)
- INCLUDE(${CMAKE_SOURCE_DIR}/storage/example/CMakeLists.txt)
- FOREACH(rpath ${EXAMPLE_SOURCES})
- SET(LIB_SOURCES ${LIB_SOURCES} ../storage/example/${rpath})
- ENDFOREACH(rpath)
-ENDIF(WITH_EXAMPLE_STORAGE_ENGINE)
-
-IF(WITH_FEDERATED_STORAGE_ENGINE)
- INCLUDE(${CMAKE_SOURCE_DIR}/storage/federated/CMakeLists.txt)
- FOREACH(rpath ${FEDERATED_SOURCES})
- SET(LIB_SOURCES ${LIB_SOURCES} ../storage/federated/${rpath})
- ENDFOREACH(rpath)
-ENDIF(WITH_FEDERATED_STORAGE_ENGINE)
-
-IF(WITH_INNOBASE_STORAGE_ENGINE)
- INCLUDE(${CMAKE_SOURCE_DIR}/storage/innobase/CMakeLists.txt)
- FOREACH(rpath ${INNOBASE_SOURCES})
- SET(LIB_SOURCES ${LIB_SOURCES} ../storage/innobase/${rpath})
- ENDFOREACH(rpath)
-ENDIF(WITH_INNOBASE_STORAGE_ENGINE)
-
-IF(WITH_CSV_STORAGE_ENGINE)
- INCLUDE(${CMAKE_SOURCE_DIR}/storage/csv/CMakeLists.txt)
- FOREACH(rpath ${CSV_SOURCES})
- SET(LIB_SOURCES ${LIB_SOURCES} ../storage/csv/${rpath})
- ENDFOREACH(rpath)
-ENDIF(WITH_CSV_STORAGE_ENGINE)
SET(SOURCE_SUBLIBS FALSE)
diff --git a/mysql-test/Makefile.am b/mysql-test/Makefile.am
index 5e3582d5e16..810bead1adc 100644
--- a/mysql-test/Makefile.am
+++ b/mysql-test/Makefile.am
@@ -25,6 +25,7 @@ test_SCRIPTS = mtr \
mysql-stress-test.pl
nobase_test_DATA = \
+ valgrind.supp \
lib/v1/mysql-test-run.pl \
lib/v1/mtr_cases.pl \
lib/v1/mtr_io.pl \
@@ -41,7 +42,6 @@ nobase_test_DATA = \
lib/v1/mtr_im.pl \
lib/v1/mtr_process.pl \
lib/v1/mtr_unique.pl \
-\
lib/mtr_cases.pm \
lib/mtr_gcov.pl \
lib/mtr_gprof.pl \
@@ -69,9 +69,8 @@ nobase_test_DATA = \
SUBDIRS = lib/My/SafeProcess
EXTRA_DIST = README \
- valgrind.supp \
$(test_SCRIPTS) \
- $(nobase_test_DATA)
+ $(nobase_test_DATA)
# List of directories containing test + result files and the
# related test data files that should be copied
@@ -93,12 +92,13 @@ TEST_DIRS = t r include std_data std_data/parts collections \
suite/jp suite/jp/t suite/jp/r suite/jp/std_data suite/jp/include \
suite/manual/t suite/manual/r \
suite/ndb_team suite/ndb_team/t suite/ndb_team/r \
- suite/rpl suite/rpl/data suite/rpl/include suite/rpl/r \
+ suite/rpl suite/rpl/include suite/rpl/r \
suite/rpl/t \
suite/stress/include suite/stress/t suite/stress/r \
suite/ndb suite/ndb/t suite/ndb/r \
suite/rpl_ndb suite/rpl_ndb/t suite/rpl_ndb/r \
- suite/parts suite/parts/t suite/parts/r suite/parts/inc
+ suite/parts suite/parts/t suite/parts/r suite/parts/inc \
+ suite/innodb suite/innodb/t suite/innodb/r suite/innodb/include
# Used by dist-hook and install-data-local to copy all
# test files into either dist or install directory
diff --git a/mysql-test/collections/default.experimental b/mysql-test/collections/default.experimental
index 103069f79cf..faa8ba110d3 100644
--- a/mysql-test/collections/default.experimental
+++ b/mysql-test/collections/default.experimental
@@ -1 +1,13 @@
funcs_1.charset_collation_1 # depends on compile-time decisions
+binlog.binlog_tmp_table # Bug#45578: Test binlog_tmp_table fails ramdonly on PB2: Unknown table 't2'
+main.ctype_gbk_binlog # Bug#46010: main.ctype_gbk_binlog fails sporadically : Table 't2' already exists
+rpl.rpl_row_create_table # Bug#45576: rpl_row_create_table fails on PB2
+rpl.rpl_extraColmaster_myisam # Bug#46013: rpl_extraColmaster_myisam fails on pb2
+rpl.rpl_stm_reset_slave # Bug#46014: rpl_stm_reset_slave crashes the server sporadically in pb2
+rpl.rpl_extraCol_myisam # Bug#40796
+rpl.rpl_extraColmaster_innodb # Bug#40796
+rpl.rpl_extraCol_innodb # Bug#40796
+rpl_ndb.rpl_ndb_log # Bug#38998
+rpl.rpl_innodb_bug28430 # Bug#46029
+rpl.rpl_row_basic_3innodb # Bug#45243
+rpl.rpl_truncate_3innodb # Bug#46030
diff --git a/mysql-test/collections/default.push b/mysql-test/collections/default.push
index 0879b6fde2c..0f7c8d9949e 100644
--- a/mysql-test/collections/default.push
+++ b/mysql-test/collections/default.push
@@ -1,5 +1,5 @@
-perl mysql-test-run.pl --timer --force --comment=n_mix --mysqld=--binlog-format=mixed --experimental=collections/default.experimental
-perl mysql-test-run.pl --timer --force --comment=ps_row --ps-protocol --mysqld=--binlog-format=row --experimental=collections/default.experimental
-perl mysql-test-run.pl --timer --force --comment=embedded --embedded --experimental=collections/default.experimental
-perl mysql-test-run.pl --timer --force --comment=rpl_binlog_row --suite=rpl,binlog --mysqld=--binlog-format=row --experimental=collections/default.experimental
-perl mysql-test-run.pl --timer --force --comment=funcs_1 --suite=funcs_1 --experimental=collections/default.experimental
+perl mysql-test-run.pl --timer --force --parallel=auto --comment=n_mix --mysqld=--binlog-format=mixed --experimental=collections/default.experimental
+perl mysql-test-run.pl --timer --force --parallel=auto --comment=ps_row --ps-protocol --mysqld=--binlog-format=row --experimental=collections/default.experimental
+perl mysql-test-run.pl --timer --force --parallel=auto --comment=embedded --embedded --experimental=collections/default.experimental
+perl mysql-test-run.pl --timer --force --parallel=auto --comment=rpl_binlog_row --suite=rpl,binlog --mysqld=--binlog-format=row --experimental=collections/default.experimental
+perl mysql-test-run.pl --timer --force --parallel=auto --comment=funcs_1 --suite=funcs_1 --experimental=collections/default.experimental
diff --git a/mysql-test/extra/rpl_tests/rpl_reset_slave.test b/mysql-test/extra/rpl_tests/rpl_reset_slave.test
index 2cc041a35e1..1f88c792fce 100644
--- a/mysql-test/extra/rpl_tests/rpl_reset_slave.test
+++ b/mysql-test/extra/rpl_tests/rpl_reset_slave.test
@@ -41,3 +41,57 @@ reset slave;
start slave;
sync_with_master;
show status like 'slave_open_temp_tables';
+
+#
+#Bug#34654 RESET SLAVE does not clear LAST_IO_Err*
+#
+
+# clearing the status
+stop slave;
+reset slave;
+let $last_io_errno= query_get_value(SHOW SLAVE STATUS, Last_IO_Errno, 1);
+echo *** errno must be zero: $last_io_errno ***;
+
+#
+# verifying start slave resets Last_IO_Error and Last_IO_Errno.
+#
+
+change master to master_user='impossible_user_name';
+start slave;
+source include/wait_for_slave_io_error.inc;
+let $last_io_errno= query_get_value(SHOW SLAVE STATUS, Last_IO_Errno, 1);
+--disable_query_log
+eval SELECT $last_io_errno > 0 as ONE;
+--enable_query_log
+
+source include/stop_slave.inc;
+change master to master_user='root';
+source include/start_slave.inc;
+let $last_io_errno= query_get_value(SHOW SLAVE STATUS, Last_IO_Errno, 1);
+let $last_io_error= query_get_value(SHOW SLAVE STATUS, Last_IO_Error, 1);
+--echo *** last errno must be zero: $last_io_errno ***
+--echo *** last error must be blank: $last_io_error ***
+
+#
+# verifying reset slave resets Last_{IO,SQL}_Err{or,no}
+#
+
+source include/stop_slave.inc;
+change master to master_user='impossible_user_name';
+start slave;
+source include/wait_for_slave_io_error.inc;
+let $last_io_errno= query_get_value(SHOW SLAVE STATUS, Last_IO_Errno, 1);
+--disable_query_log
+eval SELECT $last_io_errno > 0 as ONE;
+--enable_query_log
+
+source include/stop_slave.inc;
+reset slave;
+let $last_io_errno= query_get_value(SHOW SLAVE STATUS, Last_IO_Errno, 1);
+let $last_io_error= query_get_value(SHOW SLAVE STATUS, Last_IO_Error, 1);
+let $last_sql_errno= query_get_value(SHOW SLAVE STATUS, Last_SQL_Errno, 1);
+let $last_sql_error= query_get_value(SHOW SLAVE STATUS, Last_SQL_Error, 1);
+--echo *** io last errno must be zero: $last_io_errno ***
+--echo *** io last error must be blank: $last_io_error ***
+--echo *** sql last errno must be zero: $last_sql_errno ***
+--echo *** sql last error must be blank: $last_sql_error ***
diff --git a/mysql-test/include/commit.inc b/mysql-test/include/commit.inc
index a4e7d9ae601..d412eae8364 100644
--- a/mysql-test/include/commit.inc
+++ b/mysql-test/include/commit.inc
@@ -669,13 +669,9 @@ call p_verify_status_increment(1, 0, 1, 0);
insert t1 set a=3;
call p_verify_status_increment(2, 2, 2, 2);
savepoint a;
-call p_verify_status_increment(0, 0, 0, 0);
+call p_verify_status_increment(1, 0, 1, 0);
insert t1 set a=4;
---echo # Binlog does not register itself this time for other than the 1st
---echo # statement of the transaction with MIXED/STATEMENT binlog_format.
---echo # It needs registering with the ROW format. Therefore 1,0,2,2 are
---echo # the correct arguments to this test after bug#40221 fixed.
-call p_verify_status_increment(1, 0, 2, 2);
+call p_verify_status_increment(2, 2, 2, 2);
release savepoint a;
rollback;
call p_verify_status_increment(0, 0, 0, 0);
diff --git a/mysql-test/include/concurrent.inc b/mysql-test/include/concurrent.inc
index 2180ec4cc9c..66f8a65a102 100644
--- a/mysql-test/include/concurrent.inc
+++ b/mysql-test/include/concurrent.inc
@@ -659,11 +659,16 @@ drop table t1;
connection thread1;
select * from t1;
+--echo ** Cleanup
+connection thread1;
+disconnect thread1;
+--source include/wait_until_disconnected.inc
+--echo ** connection thread2
+connection thread2;
+disconnect thread2;
+--source include/wait_until_disconnected.inc
--echo ** connection default
connection default;
drop table t1;
drop user mysqltest@localhost;
-disconnect thread1;
-disconnect thread2;
-
diff --git a/mysql-test/include/grant_cache.inc b/mysql-test/include/grant_cache.inc
index 501e115f0ee..47eef1cdb67 100644
--- a/mysql-test/include/grant_cache.inc
+++ b/mysql-test/include/grant_cache.inc
@@ -171,15 +171,30 @@ show status like "Qcache_not_cached";
# Cleanup
---echo ----- switch to connection default and close connections -----
-connection default;
+--echo ----- close connections -----
+connection root;
disconnect root;
+--source include/wait_until_disconnected.inc
+connection root2;
disconnect root2;
+--source include/wait_until_disconnected.inc
+connection user1;
disconnect user1;
+--source include/wait_until_disconnected.inc
+connection user2;
disconnect user2;
+--source include/wait_until_disconnected.inc
+connection user3;
disconnect user3;
+--source include/wait_until_disconnected.inc
+connection user4;
disconnect user4;
+--source include/wait_until_disconnected.inc
+connection unkuser;
disconnect unkuser;
+--source include/wait_until_disconnected.inc
+--echo ----- switch to connection default -----
+connection default;
#
# A temporary 4.1 workaround to make this test pass if
diff --git a/mysql-test/include/handler.inc b/mysql-test/include/handler.inc
index 96f90aba8e0..6e7f53ba9b2 100644
--- a/mysql-test/include/handler.inc
+++ b/mysql-test/include/handler.inc
@@ -719,6 +719,7 @@ connection con1;
--reap
drop table t1;
disconnect con1;
+--source include/wait_until_disconnected.inc
connection default;
#
diff --git a/mysql-test/include/index_merge1.inc b/mysql-test/include/index_merge1.inc
index 5837df67a75..d137b0957c0 100644
--- a/mysql-test/include/index_merge1.inc
+++ b/mysql-test/include/index_merge1.inc
@@ -527,4 +527,30 @@ where exists (select 1 from t2, t3
drop table t0, t1, t2, t3;
+--echo #
+--echo # BUG#44810: index merge and order by with low sort_buffer_size
+--echo # crashes server!
+--echo #
+CREATE TABLE t1(a VARCHAR(128),b VARCHAR(128),KEY(A),KEY(B));
+INSERT INTO t1 VALUES (REPEAT('a',128),REPEAT('b',128));
+INSERT INTO t1 SELECT * FROM t1;
+INSERT INTO t1 SELECT * FROM t1;
+INSERT INTO t1 SELECT * FROM t1;
+INSERT INTO t1 SELECT * FROM t1;
+INSERT INTO t1 SELECT * FROM t1;
+INSERT INTO t1 SELECT * FROM t1;
+SET SESSION sort_buffer_size=1;
+EXPLAIN
+SELECT * FROM t1 FORCE INDEX(a,b) WHERE a LIKE 'a%' OR b LIKE 'b%'
+ ORDER BY a,b;
+# we don't actually care about the result : we're checking if it crashes
+--disable_result_log
+SELECT * FROM t1 FORCE INDEX(a,b) WHERE a LIKE 'a%' OR b LIKE 'b%'
+ ORDER BY a,b;
+--enable_result_log
+
+SET SESSION sort_buffer_size=DEFAULT;
+DROP TABLE t1;
+
+
--echo End of 5.0 tests
diff --git a/mysql-test/include/mix1.inc b/mysql-test/include/mix1.inc
index 7c87949830f..6dabe4864a9 100644
--- a/mysql-test/include/mix1.inc
+++ b/mysql-test/include/mix1.inc
@@ -1162,6 +1162,25 @@ ROLLBACK;
--error 1305
ROLLBACK TO SAVEPOINT s4;
+#
+# Bug#39793 Foreign keys not constructed when column has a '#' in a comment or default value
+#
+
+#This statement should be written on a single line for proper testing
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY COMMENT 'My ID#', f2 INTEGER DEFAULT NULL, f3 CHAR(10) DEFAULT 'My ID#', CONSTRAINT f2_ref FOREIGN KEY (f2) REFERENCES t1 (f1)) ENGINE=INNODB;
+SHOW CREATE TABLE t1;
+DROP TABLE t1;
+
+--echo #
+--echo # Bug #36995: valgrind error in remove_const during subquery executions
+--echo #
+
+create table t1 (a bit(1) not null,b int) engine=myisam;
+create table t2 (c int) engine=innodb;
+explain
+select b from t1 where a not in (select b from t1,t2 group by a) group by a;
+DROP TABLE t1,t2;
+
--echo End of 5.0 tests
# Fix for BUG#19243 "wrong LAST_INSERT_ID() after ON DUPLICATE KEY
@@ -1479,43 +1498,12 @@ INSERT INTO t1 VALUES
(4,1,3,'pk',NULL),(5,1,3,'c2',NULL),
(2,1,4,'c_extra',NULL),(3,1,4,'c_extra',NULL);
-EXPLAIN SELECT * FROM t1 WHERE tid = 1 AND vid = 3 ORDER BY idx DESC;
+EXPLAIN SELECT * FROM t1 FORCE INDEX (PRIMARY) WHERE tid = 1 AND vid = 3 ORDER BY idx DESC;
-SELECT * FROM t1 WHERE tid = 1 AND vid = 3 ORDER BY idx DESC;
+SELECT * FROM t1 FORCE INDEX (PRIMARY) WHERE tid = 1 AND vid = 3 ORDER BY idx DESC;
DROP TABLE t1;
-#
-# Bug#21704: Renaming column does not update FK definition.
-#
-
-#
-# --disable_warnings
-# DROP TABLE IF EXISTS t1;
-# DROP TABLE IF EXISTS t2;
-# --enable_warnings
-#
-# CREATE TABLE t1(id INT PRIMARY KEY)
-# ENGINE=innodb;
-#
-# CREATE TABLE t2(
-# t1_id INT PRIMARY KEY,
-# CONSTRAINT fk1 FOREIGN KEY (t1_id) REFERENCES t1(id))
-# ENGINE=innodb;
-#
-# --echo
-#
-# --disable_result_log
-# --error ER_ERROR_ON_RENAME
-# ALTER TABLE t1 CHANGE id id2 INT;
-# --enable_result_log
-#
-# --echo
-#
-# DROP TABLE t2;
-# DROP TABLE t1;
-#
-
--echo #
--echo # Bug #44290: explain crashes for subquery with distinct in
--echo # SQL_SELECT::test_quick_select
@@ -1535,4 +1523,31 @@ SELECT 1 FROM (SELECT COUNT(DISTINCT c1)
DROP TABLE t1;
+eval
+CREATE TABLE t1 (c1 REAL, c2 REAL, c3 REAL, KEY (c3), KEY (c2, c3))
+ ENGINE=$engine_type;
+INSERT INTO t1 VALUES (1,1,1), (1,1,1), (1,1,2), (1,1,1), (1,1,2);
+
+SELECT 1 FROM (SELECT COUNT(DISTINCT c1)
+ FROM t1 WHERE c2 IN (1, 1) AND c3 = 2 GROUP BY c2) x;
+EXPLAIN
+SELECT 1 FROM (SELECT COUNT(DISTINCT c1)
+ FROM t1 WHERE c2 IN (1, 1) AND c3 = 2 GROUP BY c2) x;
+
+DROP TABLE t1;
+
+eval
+CREATE TABLE t1 (c1 DECIMAL(12,2), c2 DECIMAL(12,2), c3 DECIMAL(12,2),
+ KEY (c3), KEY (c2, c3))
+ ENGINE=$engine_type;
+INSERT INTO t1 VALUES (1,1,1), (1,1,1), (1,1,2), (1,1,1), (1,1,2);
+
+SELECT 1 FROM (SELECT COUNT(DISTINCT c1)
+ FROM t1 WHERE c2 IN (1, 1) AND c3 = 2 GROUP BY c2) x;
+EXPLAIN
+SELECT 1 FROM (SELECT COUNT(DISTINCT c1)
+ FROM t1 WHERE c2 IN (1, 1) AND c3 = 2 GROUP BY c2) x;
+
+DROP TABLE t1;
+
--echo End of 5.1 tests
diff --git a/mysql-test/include/mtr_check.sql b/mysql-test/include/mtr_check.sql
index 12cb2c870a2..9db631a2615 100644
--- a/mysql-test/include/mtr_check.sql
+++ b/mysql-test/include/mtr_check.sql
@@ -57,3 +57,13 @@ BEGIN
mysql.user;
END||
+
+--
+-- Procedure used by test case used to force all
+-- servers to restart after testcase and thus skipping
+-- check test case after test
+--
+CREATE DEFINER=root@localhost PROCEDURE force_restart()
+BEGIN
+ SELECT 1 INTO OUTFILE 'force_restart';
+END||
diff --git a/mysql-test/include/mtr_warnings.sql b/mysql-test/include/mtr_warnings.sql
index 73287900f3c..b99402c8031 100644
--- a/mysql-test/include/mtr_warnings.sql
+++ b/mysql-test/include/mtr_warnings.sql
@@ -139,9 +139,9 @@ INSERT INTO global_suppressions VALUES
("Cannot find or open table test\/bug29807 from"),
/* innodb foreign key tests that fail in ALTER or RENAME produce this */
- ("InnoDB: Error: in ALTER TABLE `test`.`t[12]`"),
+ ("InnoDB: Error: in ALTER TABLE `test`.`t[123]`"),
("InnoDB: Error: in RENAME TABLE table `test`.`t1`"),
- ("InnoDB: Error: table `test`.`t[12]` does not exist in the InnoDB internal"),
+ ("InnoDB: Error: table `test`.`t[123]` does not exist in the InnoDB internal"),
/* Test case for Bug#14233 produces the following warnings: */
("Stored routine 'test'.'bug14233_1': invalid value in column mysql.proc"),
diff --git a/mysql-test/include/mysqldump.inc b/mysql-test/include/mysqldump.inc
new file mode 100644
index 00000000000..6227138b012
--- /dev/null
+++ b/mysql-test/include/mysqldump.inc
@@ -0,0 +1,50 @@
+################################################################################
+# mysqldump.inc
+#
+# SUMMARY: include file to facilitate testing the quality of mysqldump output
+#
+# INPUTS: Two variables:
+# $table_name - the name of the table that was dumped
+# $mysqldumpfile - the name of the file that captured mysqldump output
+#
+# OUTPUTS: minor echo data:
+# We 'echo' some stage information to the .result file:
+# 'altering original table', 'restoring from dumpfile', 'comparing'
+#
+# OTHER FILES: We use include/diff_tables.inc to compare the original, renamed
+# table with the 'restored' one.
+#
+# DESCRIPTION: This file works by being fed the name of the original table
+# and a mysqldump output file. The original table is then renamed
+# to _orig, the mysqldump file is used to recreate the
+# table, then diff_tables.inc is called to compare them.
+#
+# LIMITATIONS: Does *NOT* work with xml output!
+#
+# AUTHOR: pcrews 2009-05-21
+# Bug#40465 mysqldump.test does no checking of dump or restore
+#
+# LAST CHANGE: 2009-05-21
+#
+################################################################################
+
+--echo # Begin testing mysqldump output + restore
+--echo # Create 'original table name - _orig
+# NOTE: We use SET then let as query_get_value has issues with the extra commas
+# used in the CONCAT statement.
+eval SET @orig_table_name = CONCAT('$table_name', '_orig');
+let $orig_table_name = query_get_value(SELECT @orig_table_name,@orig_table_name,1);
+--echo # Rename original table
+eval ALTER TABLE $table_name RENAME to $orig_table_name;
+--echo # Recreate table from mysqldump output
+--exec $MYSQL test < $mysqldumpfile
+--echo # Compare original and recreated tables
+--echo # Recreated table: $table_name
+--echo # Original table: $orig_table_name
+let $diff_table_1 = $table_name;
+let $diff_table_2 = $orig_table_name;
+--source include/diff_tables.inc
+--echo # Cleanup
+--remove_file $mysqldumpfile
+eval DROP TABLE $table_name, $orig_table_name;
+
diff --git a/mysql-test/include/no_valgrind_without_big.inc b/mysql-test/include/no_valgrind_without_big.inc
new file mode 100644
index 00000000000..743e974daec
--- /dev/null
+++ b/mysql-test/include/no_valgrind_without_big.inc
@@ -0,0 +1,12 @@
+# include/no_valgrind_without_big.inc
+#
+# If we are running with Valgrind ($VALGRIND_TEST <> 0) than the resource
+# consumption (storage space needed, runtime ...) will be extreme.
+# Therefore we require that the option "--big-test" is also set.
+#
+
+if (`SELECT $VALGRIND_TEST <> 0 AND '$BIG_TEST' = ''`)
+{
+ --skip Need "--big-test" when running with Valgrind
+}
+
diff --git a/mysql-test/include/query_cache.inc b/mysql-test/include/query_cache.inc
index 77ea0021a5d..7ce97b42158 100644
--- a/mysql-test/include/query_cache.inc
+++ b/mysql-test/include/query_cache.inc
@@ -177,6 +177,7 @@ show status like "Qcache_hits";
# Final cleanup
eval set GLOBAL query_cache_size=$save_query_cache_size;
+disconnect connection1;
+--source include/wait_until_disconnected.inc
connection default;
drop table t2;
-disconnect connection1;
diff --git a/mysql-test/include/wait_for_slave_io_error.inc b/mysql-test/include/wait_for_slave_io_error.inc
new file mode 100644
index 00000000000..094406e02b2
--- /dev/null
+++ b/mysql-test/include/wait_for_slave_io_error.inc
@@ -0,0 +1,23 @@
+# ==== Purpose ====
+#
+# Waits until the IO thread of the current connection has got an
+# error, or until a timeout is reached.
+#
+# ==== Usage ====
+#
+# source include/wait_for_slave_io_error.inc;
+#
+# Parameters to this macro are $slave_timeout and
+# $slave_keep_connection. See wait_for_slave_param.inc for
+# descriptions.
+
+let $old_slave_param_comparison= $slave_param_comparison;
+
+let $slave_param= Last_IO_Errno;
+let $slave_param_comparison= !=;
+let $slave_param_value= 0;
+let $slave_error_message= Failed while waiting for slave to produce an error in its sql thread;
+source include/wait_for_slave_param.inc;
+let $slave_error_message= ;
+
+let $slave_param_comparison= $old_slave_param_comparison;
diff --git a/mysql-test/lib/My/CoreDump.pm b/mysql-test/lib/My/CoreDump.pm
index f3e9f521384..3ac9e385070 100644
--- a/mysql-test/lib/My/CoreDump.pm
+++ b/mysql-test/lib/My/CoreDump.pm
@@ -22,6 +22,33 @@ use My::Platform;
use File::Temp qw/ tempfile tempdir /;
+my $hint_mysqld; # Last resort guess for executable path
+
+# If path in core file is 79 chars we assume it's been truncated
+# Looks like we can still find the full path using 'strings'
+# If that doesn't work, use the hint (mysqld path) as last resort.
+
+sub _verify_binpath {
+ my ($binary, $core_name)= @_;
+ my $binpath;
+
+ if (length $binary != 79) {
+ $binpath= $binary;
+ print "Core generated by '$binpath'\n";
+ } else {
+ # Last occurrence of path ending in /mysql*, cut from first /
+ if (`strings '$core_name' | grep "/mysql[^/. ]*\$" | tail -1` =~ /(\/.*)/) {
+ $binpath= $1;
+ print "Guessing that core was generated by '$binpath'\n";
+ } else {
+ return unless $hint_mysqld;
+ $binpath= $hint_mysqld;
+ print "Wild guess that core was generated by '$binpath'\n";
+ }
+ }
+ return $binpath;
+}
+
sub _gdb {
my ($core_name)= @_;
@@ -33,7 +60,8 @@ sub _gdb {
`gdb -c '$core_name' --batch 2>&1` =~
/Core was generated by `([^\s\'\`]+)/;
my $binary= $1 or return;
- print "Core generated by '$binary'\n";
+
+ $binary= _verify_binpath ($binary, $core_name) or return;
# Create tempfile containing gdb commands
my ($tmp, $tmp_name) = tempfile();
@@ -73,7 +101,8 @@ sub _dbx {
`echo | dbx - '$core_name' 2>&1` =~
/Corefile specified executable: "([^"]+)"/;
my $binary= $1 or return;
- print "Core generated by '$binary'\n";
+
+ $binary= _verify_binpath ($binary, $core_name) or return;
# Find all threads
my @thr_ids = `echo threads | dbx '$binary' '$core_name' 2>&1` =~ /t@\d+/g;
@@ -203,7 +232,7 @@ sub _cdb {
my $cdb_cmd = "!sym prompts off; !analyze -v; .ecxr; !for_each_frame dv /t;!uniqstack -p;q";
my $cdb_output=
- `cdb -z $core_name -i "$image_path" -y "$symbol_path" -t 0 -lines -c "$cdb_cmd" 2>&1`;
+ `cdb -c "$cdb_cmd" -z $core_name -i "$image_path" -y "$symbol_path" -t 0 -lines 2>&1`;
return if $? >> 8;
return unless $cdb_output;
@@ -225,7 +254,8 @@ EOF
sub show {
- my ($class, $core_name)= @_;
+ my ($class, $core_name, $exe_mysqld)= @_;
+ $hint_mysqld= $exe_mysqld;
# On Windows, rely on cdb to be there...
if (IS_WINDOWS)
diff --git a/mysql-test/lib/My/File/Path.pm b/mysql-test/lib/My/File/Path.pm
index 99edeecdaf7..25a26568eee 100644
--- a/mysql-test/lib/My/File/Path.pm
+++ b/mysql-test/lib/My/File/Path.pm
@@ -164,6 +164,9 @@ sub copytree {
copytree("$from_dir/$_", "$to_dir/$_");
next;
}
+
+ # Only copy plain files
+ next unless -f "$from_dir/$_";
copy("$from_dir/$_", "$to_dir/$_");
}
closedir(DIR);
diff --git a/mysql-test/lib/My/SafeProcess.pm b/mysql-test/lib/My/SafeProcess.pm
index 5ef3286ad8e..7e102b628ca 100644
--- a/mysql-test/lib/My/SafeProcess.pm
+++ b/mysql-test/lib/My/SafeProcess.pm
@@ -536,7 +536,37 @@ sub wait_any {
return $proc;
}
+
#
+# Wait for all processes to exit
+#
+sub wait_all {
+ while(keys %running)
+ {
+ wait_any();
+ }
+}
+
+
+#
+# Check if any process has exited, but don't wait.
+#
+# Returns a reference to the SafeProcess that
+# exited or undefined
+#
+sub check_any {
+ for my $proc (values %running){
+ if ( $proc->is_child($$) ) {
+ if (not $proc->wait_one(0)) {
+ _verbose ("Found exited $proc");
+ return $proc;
+ }
+ }
+ }
+ return undef;
+}
+
+
# Overload string operator
# and fallback to default functions if no
# overloaded function is found
diff --git a/mysql-test/lib/My/SafeProcess/Base.pm b/mysql-test/lib/My/SafeProcess/Base.pm
index 3fc1b1be017..9a6871264b8 100644
--- a/mysql-test/lib/My/SafeProcess/Base.pm
+++ b/mysql-test/lib/My/SafeProcess/Base.pm
@@ -83,6 +83,13 @@ sub exit_status {
};
}
+# threads.pm may not exist everywhere, so use only on Windows.
+
+use if $^O eq "MSWin32", "threads";
+use if $^O eq "MSWin32", "threads::shared";
+
+my $win32_spawn_lock :shared;
+
#
# Create a new process
@@ -104,6 +111,8 @@ sub create_process {
if ($^O eq "MSWin32"){
+ lock($win32_spawn_lock);
+
#printf STDERR "stdin %d, stdout %d, stderr %d\n",
# fileno STDIN, fileno STDOUT, fileno STDERR;
diff --git a/mysql-test/lib/My/SafeProcess/safe_process.cc b/mysql-test/lib/My/SafeProcess/safe_process.cc
index dc7b7da28c7..50c433b9b39 100644
--- a/mysql-test/lib/My/SafeProcess/safe_process.cc
+++ b/mysql-test/lib/My/SafeProcess/safe_process.cc
@@ -89,7 +89,7 @@ static void die(const char* fmt, ...)
}
-static void kill_child (void)
+static void kill_child(void)
{
int status= 0;
@@ -119,7 +119,7 @@ static void kill_child (void)
}
-static void handle_abort (int sig)
+extern "C" void handle_abort(int sig)
{
message("Got signal %d, child_pid: %d, sending ABRT", sig, child_pid);
@@ -128,8 +128,8 @@ static void handle_abort (int sig)
}
}
-
-static void handle_signal (int sig)
+
+extern "C" void handle_signal(int sig)
{
message("Got signal %d, child_pid: %d", sig, child_pid);
terminated= 1;
@@ -152,7 +152,7 @@ int main(int argc, char* const argv[] )
pid_t own_pid= getpid();
pid_t parent_pid= getppid();
bool nocore = false;
-
+
/* Install signal handlers */
signal(SIGTERM, handle_signal);
signal(SIGINT, handle_signal);
@@ -232,10 +232,11 @@ int main(int argc, char* const argv[] )
message("setrlimit failed, errno=%d", errno);
}
}
-
+
// Signal that child is ready
buf= 37;
- write(pfd[1], &buf, 1);
+ if ((write(pfd[1], &buf, 1)) < 1)
+ die("Failed to signal that child is ready");
// Close write end
close(pfd[1]);
@@ -246,8 +247,10 @@ int main(int argc, char* const argv[] )
close(pfd[1]); // Close unused write end
// Wait for child to signal it's ready
- read(pfd[0], &buf, 1);
- if(buf != 37)
+ if ((read(pfd[0], &buf, 1)) < 1)
+ die("Failed to read signal from child");
+
+ if (buf != 37)
die("Didn't get 37 from pipe");
close(pfd[0]); // Close read end
@@ -272,7 +275,7 @@ int main(int argc, char* const argv[] )
if (WIFEXITED(status))
{
// Process has exited, collect return status
- int ret_code= WEXITSTATUS(status);
+ ret_code= WEXITSTATUS(status);
message("Child exit: %d", ret_code);
// Exit with exit status of the child
exit(ret_code);
@@ -287,6 +290,6 @@ int main(int argc, char* const argv[] )
}
kill_child();
- exit(1);
+ return 1;
}
diff --git a/mysql-test/lib/My/SafeProcess/safe_process_win.cc b/mysql-test/lib/My/SafeProcess/safe_process_win.cc
index 4fb89f098ed..80c1b7a97f2 100755
--- a/mysql-test/lib/My/SafeProcess/safe_process_win.cc
+++ b/mysql-test/lib/My/SafeProcess/safe_process_win.cc
@@ -259,22 +259,37 @@ int main(int argc, const char** argv )
the JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE flag, making sure it will be
terminated when the last handle to it is closed(which is owned by
this process).
+
+ If breakaway from job fails on some reason, fallback is to create a
+ new process group. Process groups also allow to kill process and its
+ descedants, subject to some restrictions (processes have to run within
+ the same console,and must not ignore CTRL_BREAK)
*/
- if (CreateProcess(NULL, (LPSTR)child_args,
+ DWORD create_flags[]= {CREATE_BREAKAWAY_FROM_JOB, CREATE_NEW_PROCESS_GROUP, 0};
+ BOOL process_created= FALSE;
+ BOOL jobobject_assigned= FALSE;
+
+ for (int i=0; i < sizeof(create_flags)/sizeof(create_flags[0]); i++)
+ {
+ process_created= CreateProcess(NULL, (LPSTR)child_args,
NULL,
NULL,
TRUE, /* inherit handles */
- CREATE_SUSPENDED | CREATE_BREAKAWAY_FROM_JOB,
+ CREATE_SUSPENDED | create_flags[i],
NULL,
NULL,
&si,
- &process_info) == 0)
- die("CreateProcess failed");
+ &process_info);
+ if (process_created)
+ {
+ jobobject_assigned= AssignProcessToJobObject(job_handle, process_info.hProcess);
+ break;
+ }
+ }
- if (AssignProcessToJobObject(job_handle, process_info.hProcess) == 0)
+ if (!process_created)
{
- TerminateProcess(process_info.hProcess, 200);
- die("AssignProcessToJobObject failed");
+ die("CreateProcess failed");
}
ResumeThread(process_info.hThread);
CloseHandle(process_info.hThread);
@@ -312,6 +327,13 @@ int main(int argc, const char** argv )
message("TerminateJobObject failed");
CloseHandle(job_handle);
message("Job terminated and closed");
+
+ if (!jobobject_assigned)
+ {
+ GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, process_info.dwProcessId);
+ TerminateProcess(process_info.hProcess, 202);
+ }
+
if (wait_res != WAIT_OBJECT_0 + CHILD)
{
/* The child has not yet returned, wait for it */
diff --git a/mysql-test/lib/mtr_cases.pm b/mysql-test/lib/mtr_cases.pm
index 23a85ef7ecc..c9c0f1796e5 100644
--- a/mysql-test/lib/mtr_cases.pm
+++ b/mysql-test/lib/mtr_cases.pm
@@ -33,7 +33,7 @@ our $print_testcases;
our $skip_rpl;
our $do_test;
our $skip_test;
-our $opt_skip_combination;
+our $skip_combinations;
our $binlog_format;
our $enable_disabled;
our $default_storage_engine;
@@ -119,11 +119,22 @@ sub collect_test_cases ($$) {
if ( $test->{name} =~ /.*\.$tname/ )
{
$found= 1;
+ last;
}
}
if ( not $found )
{
- mtr_error("Could not find '$tname' in '$suites' suite(s)");
+ mtr_error("Could not find '$tname' in '$suites' suite(s)") unless $sname;
+ # If suite was part of name, find it there
+ my ($this_case) = collect_one_suite($sname, [ $tname ]);
+ if ($this_case)
+ {
+ push (@$cases, $this_case);
+ }
+ else
+ {
+ mtr_error("Could not find '$tname' in '$sname' suite");
+ }
}
}
}
@@ -375,7 +386,7 @@ sub collect_one_suite($)
# Read combinations for this suite and build testcases x combinations
# if any combinations exists
# ----------------------------------------------------------------------
- if ( ! $opt_skip_combination )
+ if ( ! $skip_combinations )
{
my @combinations;
my $combination_file= "$suitedir/combinations";
@@ -464,6 +475,66 @@ sub collect_one_suite($)
#print_testcases(@cases);
}
}
+
+ # ----------------------------------------------------------------------
+ # Testing InnoDB plugin.
+ # ----------------------------------------------------------------------
+ my $lib_innodb_plugin=
+ mtr_file_exists(::vs_config_dirs('storage/innodb_plugin', 'ha_innodb_plugin.dll'),
+ "$::basedir/storage/innodb_plugin/.libs/ha_innodb_plugin.so",
+ "$::basedir/lib/mysql/plugin/ha_innodb_plugin.so",
+ "$::basedir/lib/mysql/plugin/ha_innodb_plugin.dll");
+ if ($::mysql_version_id >= 50100 && !(IS_WINDOWS && $::opt_embedded_server) &&
+ $lib_innodb_plugin)
+ {
+ my @new_cases;
+
+ foreach my $test (@cases)
+ {
+ next if ($test->{'skip'} || !$test->{'innodb_test'});
+ # Exceptions
+ next if ($test->{'name'} eq 'main.innodb'); # Failed with wrong errno (fk)
+ # innodb_file_per_table is rw with innodb_plugin
+ next if ($test->{'name'} eq 'sys_vars.innodb_file_per_table_basic');
+ # innodb_lock_wait_timeout is rw with innodb_plugin
+ next if ($test->{'name'} eq 'sys_vars.innodb_lock_wait_timeout_basic');
+ # Diff around innodb_thread_concurrency variable
+ next if ($test->{'name'} eq 'sys_vars.innodb_thread_concurrency_basic');
+ # Copy test options
+ my $new_test= My::Test->new();
+ while (my ($key, $value) = each(%$test))
+ {
+ if (ref $value eq "ARRAY")
+ {
+ push(@{$new_test->{$key}}, @$value);
+ }
+ else
+ {
+ $new_test->{$key}= $value;
+ }
+ }
+ my $plugin_filename= basename($lib_innodb_plugin);
+ push(@{$new_test->{master_opt}}, '--ignore-builtin-innodb');
+ push(@{$new_test->{master_opt}}, '--plugin-dir=' . dirname($lib_innodb_plugin));
+ push(@{$new_test->{master_opt}}, "--plugin_load=innodb=$plugin_filename;innodb_locks=$plugin_filename");
+ push(@{$new_test->{slave_opt}}, '--ignore-builtin-innodb');
+ push(@{$new_test->{slave_opt}}, '--plugin-dir=' . dirname($lib_innodb_plugin));
+ push(@{$new_test->{slave_opt}}, "--plugin_load=innodb=$plugin_filename;innodb_locks=$plugin_filename");
+ if ($new_test->{combination})
+ {
+ $new_test->{combination}.= ' + InnoDB plugin';
+ }
+ else
+ {
+ $new_test->{combination}= 'InnoDB plugin';
+ }
+ push(@new_cases, $new_test);
+ }
+ push(@cases, @new_cases);
+ }
+ # ----------------------------------------------------------------------
+ # End of testing InnoDB plugin.
+ # ----------------------------------------------------------------------
optimize_cases(\@cases);
#print_testcases(@cases);
@@ -887,7 +958,8 @@ sub collect_one_test_case {
if ( $tinfo->{'innodb_test'} )
{
# This is a test that need innodb
- if ( $::mysqld_variables{'innodb'} ne "TRUE" )
+ if ( $::mysqld_variables{'innodb'} eq "OFF" ||
+ ! exists $::mysqld_variables{'innodb'} )
{
# innodb is not supported, skip it
$tinfo->{'skip'}= 1;
diff --git a/mysql-test/lib/mtr_process.pl b/mysql-test/lib/mtr_process.pl
index a99119a199d..a42627c93cd 100644
--- a/mysql-test/lib/mtr_process.pl
+++ b/mysql-test/lib/mtr_process.pl
@@ -21,7 +21,25 @@
use strict;
use Socket;
use Errno;
+use My::Platform;
+use if IS_WINDOWS, "Net::Ping";
+# Ancient perl might not have port_number method for Net::Ping.
+# Check it and use fallback to connect() if it is not present.
+BEGIN
+{
+ my $use_netping= 0;
+ if (IS_WINDOWS)
+ {
+ my $ping = Net::Ping->new();
+ if ($ping->can("port_number"))
+ {
+ $use_netping= 1;
+ }
+ }
+ eval 'sub USE_NETPING { $use_netping }';
+}
+
sub sleep_until_file_created ($$$);
sub mtr_ping_port ($);
@@ -30,6 +48,24 @@ sub mtr_ping_port ($) {
mtr_verbose("mtr_ping_port: $port");
+ if (IS_WINDOWS && USE_NETPING)
+ {
+ # Under Windows, connect to a port that is not open is slow
+ # It takes ~1sec. Net::Ping with small timeout is much faster.
+ my $ping = Net::Ping->new();
+ $ping->port_number($port);
+ if ($ping->ping("localhost",0.1))
+ {
+ mtr_verbose("USED");
+ return 1;
+ }
+ else
+ {
+ mtr_verbose("FREE");
+ return 0;
+ }
+ }
+
my $remote= "localhost";
my $iaddr= inet_aton($remote);
if ( ! $iaddr )
diff --git a/mysql-test/lib/mtr_report.pm b/mysql-test/lib/mtr_report.pm
index 9c6ab35ee5e..a246c5bbef6 100644
--- a/mysql-test/lib/mtr_report.pm
+++ b/mysql-test/lib/mtr_report.pm
@@ -30,6 +30,8 @@ our @EXPORT= qw(report_option mtr_print_line mtr_print_thick_line
mtr_report_test);
use mtr_match;
+use My::Platform;
+use POSIX qw[ _exit ];
require "mtr_io.pl";
my $tot_real_time= 0;
@@ -69,6 +71,8 @@ sub _mtr_report_test_name ($) {
print _name(), _timestamp();
printf "%-40s ", $tname;
+ my $worker = $tinfo->{worker};
+ printf "w$worker " if $worker;
return $tname;
}
@@ -217,8 +221,8 @@ sub mtr_report_test ($) {
}
-sub mtr_report_stats ($) {
- my $tests= shift;
+sub mtr_report_stats ($;$) {
+ my ($tests, $dont_error)= @_;
# ----------------------------------------------------------------------
# Find out how we where doing
@@ -257,6 +261,17 @@ sub mtr_report_stats ($) {
$tot_restarts++;
}
+ # Add counts for repeated runs, if any.
+ # Note that the last run has already been counted above.
+ my $num_repeat = $tinfo->{'repeat'} - 1;
+ if ( $num_repeat > 0 )
+ {
+ $tot_tests += $num_repeat;
+ my $rep_failed = $tinfo->{'rep_failures'} || 0;
+ $tot_failed += $rep_failed;
+ $tot_passed += $num_repeat - $rep_failed;
+ }
+
# Look for warnings produced by mysqltest
my $base_file= mtr_match_extension($tinfo->{'result_file'},
"result"); # Trim extension
@@ -336,7 +351,7 @@ sub mtr_report_stats ($) {
foreach my $tinfo (@$tests)
{
my $tname= $tinfo->{'name'};
- if ( $tinfo->{failures} and ! $seen{$tname})
+ if ( ($tinfo->{failures} || $tinfo->{rep_failures}) and ! $seen{$tname})
{
print " $tname";
$seen{$tname}= 1;
@@ -359,7 +374,7 @@ sub mtr_report_stats ($) {
if ( $tot_failed != 0 || $found_problems)
{
- mtr_error("there were failing test cases");
+ mtr_error("there were failing test cases") unless $dont_error;
}
}
@@ -459,7 +474,14 @@ sub mtr_warning (@) {
sub mtr_error (@) {
print STDERR _name(), _timestamp(),
"mysql-test-run: *** ERROR: ", join(" ", @_), "\n";
- exit(1);
+ if (IS_WINDOWS)
+ {
+ POSIX::_exit(1);
+ }
+ else
+ {
+ exit(1);
+ }
}
diff --git a/mysql-test/lib/mtr_unique.pm b/mysql-test/lib/mtr_unique.pm
index 294a5d7b4d6..6b60157422d 100644
--- a/mysql-test/lib/mtr_unique.pm
+++ b/mysql-test/lib/mtr_unique.pm
@@ -28,32 +28,36 @@ sub msg {
# print "### unique($$) - ", join(" ", @_), "\n";
}
-my $file;
+my $dir;
if(!IS_WINDOWS)
{
- $file= "/tmp/mysql-test-ports";
+ $dir= "/tmp/mysql-unique-ids";
}
else
{
- $file= $ENV{'TEMP'}."/mysql-test-ports";
-}
-
-
-my %mtr_unique_ids;
-
-END {
- my $allocated_id= $mtr_unique_ids{$$};
- if (defined $allocated_id)
+ # Try to use machine-wide directory location for unique IDs,
+ # $ALLUSERSPROFILE . IF it is not available, fallback to $TEMP
+ # which is typically a per-user temporary directory
+ if (exists $ENV{'ALLUSERSPROFILE'} && -w $ENV{'ALLUSERSPROFILE'})
{
- mtr_release_unique_id($allocated_id);
+ $dir= $ENV{'ALLUSERSPROFILE'}."/mysql-unique-ids";
}
- delete $mtr_unique_ids{$$};
+ else
+ {
+ $dir= $ENV{'TEMP'}."/mysql-unique-ids";
+ }
+}
+
+my $mtr_unique_fh = undef;
+
+END
+{
+ mtr_release_unique_id();
}
#
-# Get a unique, numerical ID, given a file name (where all
-# requested IDs are stored), a minimum and a maximum value.
+# Get a unique, numerical ID in a specified range.
#
# If no unique ID within the specified parameters can be
# obtained, return undef.
@@ -61,135 +65,63 @@ END {
sub mtr_get_unique_id($$) {
my ($min, $max)= @_;;
- msg("get, '$file', $min-$max");
+ msg("get $min-$max, $$");
- die "Can only get one unique id per process!" if $mtr_unique_ids{$$};
+ die "Can only get one unique id per process!" if defined $mtr_unique_fh;
- my $ret = undef;
- my $changed = 0;
- if(eval("readlink '$file'") || eval("readlink '$file.sem'")) {
- die 'lock file is a symbolic link';
- }
+ # Make sure our ID directory exists
+ if (! -d $dir)
+ {
+ # If there is a file with the reserved
+ # directory name, just delete the file.
+ if (-e $dir)
+ {
+ unlink($dir);
+ }
- chmod 0777, "$file.sem";
- open SEM, ">", "$file.sem" or die "can't write to $file.sem";
- flock SEM, LOCK_EX or die "can't lock $file.sem";
- if(! -e $file) {
- open FILE, ">", $file or die "can't create $file";
- close FILE;
- }
+ mkdir $dir;
+ chmod 0777, $dir;
- msg("HAVE THE LOCK");
-
- if(eval("readlink '$file'") || eval("readlink '$file.sem'")) {
- die 'lock file is a symbolic link';
- }
-
- chmod 0777, $file;
- open FILE, "+<", $file or die "can't open $file";
- #select undef,undef,undef,0.2;
- seek FILE, 0, 0;
- my %taken = ();
- while() {
- chomp;
- my ($id, $pid) = split / /;
- $taken{$id} = $pid;
- msg("taken: $id, $pid");
- # Check if process with given pid is alive
- if(!process_alive($pid)) {
- print "Removing slot $id used by missing process $pid\n";
- msg("Removing slot $id used by missing process $pid");
- delete $taken{$id};
- $changed++;
+ if(! -d $dir)
+ {
+ die "can't make directory $dir";
}
}
- for(my $i=$min; $i<=$max; ++$i) {
- if(! exists $taken{$i}) {
- $ret = $i;
- $taken{$i} = $$;
- $changed++;
- # Remember the id this process got
- $mtr_unique_ids{$$}= $i;
- msg(" got $i");
- last;
+
+
+ my $fh;
+ for(my $id = $min; $id <= $max; $id++)
+ {
+ open( $fh, ">$dir/$id");
+ chmod 0666, "$dir/$id";
+ # Try to lock the file exclusively. If lock succeeds, we're done.
+ if (flock($fh, LOCK_EX|LOCK_NB))
+ {
+ # Store file handle - we would need it to release the ID (==unlock the file)
+ $mtr_unique_fh = $fh;
+ return $id;
+ }
+ else
+ {
+ close $fh;
}
}
- if($changed) {
- seek FILE, 0, 0;
- truncate FILE, 0 or die "can't truncate $file";
- for my $k (keys %taken) {
- print FILE $k . ' ' . $taken{$k} . "\n";
- }
- }
- close FILE;
-
- msg("RELEASING THE LOCK");
- flock SEM, LOCK_UN or warn "can't unlock $file.sem";
- close SEM;
-
- return $ret;
+ return undef;
}
#
# Release a unique ID.
#
-sub mtr_release_unique_id($) {
- my ($myid)= @_;
-
- msg("release, $myid");
-
-
- if(eval("readlink '$file'") || eval("readlink '$file.sem'")) {
- die 'lock file is a symbolic link';
- }
-
- open SEM, ">", "$file.sem" or die "can't write to $file.sem";
- flock SEM, LOCK_EX or die "can't lock $file.sem";
-
- msg("HAVE THE LOCK");
-
- if(eval("readlink '$file'") || eval("readlink '$file.sem'")) {
- die 'lock file is a symbolic link';
- }
-
- if(! -e $file) {
- open FILE, ">", $file or die "can't create $file";
- close FILE;
- }
- open FILE, "+<", $file or die "can't open $file";
- #select undef,undef,undef,0.2;
- seek FILE, 0, 0;
- my %taken = ();
- while() {
- chomp;
- my ($id, $pid) = split / /;
- msg(" taken, $id $pid");
- $taken{$id} = $pid;
- }
-
- if ($taken{$myid} != $$)
+sub mtr_release_unique_id()
+{
+ msg("release $$");
+ if (defined $mtr_unique_fh)
{
- msg(" The unique id for this process does not match pid");
+ close $mtr_unique_fh;
+ $mtr_unique_fh = undef;
}
-
-
- msg(" removing $myid");
- delete $taken{$myid};
- seek FILE, 0, 0;
- truncate FILE, 0 or die "can't truncate $file";
- for my $k (keys %taken) {
- print FILE $k . ' ' . $taken{$k} . "\n";
- }
- close FILE;
-
- msg("RELEASE THE LOCK");
-
- flock SEM, LOCK_UN or warn "can't unlock $file.sem";
- close SEM;
-
- delete $mtr_unique_ids{$$};
}
diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl
index 3949148ec49..9e168463e99 100755
--- a/mysql-test/mysql-test-run.pl
+++ b/mysql-test/mysql-test-run.pl
@@ -126,7 +126,7 @@ my $path_config_file; # The generated config file, var/my.cnf
# executables will be used by the test suite.
our $opt_vs_config = $ENV{'MTR_VS_CONFIG'};
-my $DEFAULT_SUITES= "main,binlog,federated,rpl,rpl_ndb,ndb";
+my $DEFAULT_SUITES= "main,binlog,federated,rpl,rpl_ndb,ndb,innodb";
my $opt_suites;
our $opt_verbose= 0; # Verbose output, enable with --verbose
@@ -209,6 +209,7 @@ sub check_timeout { return $opt_testcase_timeout * 6; };
my $opt_start;
my $opt_start_dirty;
+my $opt_wait_all;
my $opt_repeat= 1;
my $opt_retry= 3;
my $opt_retry_failure= 2;
@@ -312,7 +313,7 @@ sub main {
#######################################################################
my $num_tests= @$tests;
- if ( not defined $opt_parallel ) {
+ if ( $opt_parallel eq "auto" ) {
# Try to find a suitable value for number of workers
my $sys_info= My::SysInfo->new();
@@ -429,6 +430,7 @@ sub run_test_server ($$$) {
my $completed= [];
my %running;
my $result;
+ my $exe_mysqld= find_mysqld($basedir) || ""; # Used as hint to CoreDump
my $suite_timeout_proc= My::SafeProcess->timer(suite_timeout());
@@ -500,7 +502,7 @@ sub run_test_server ($$$) {
mtr_report(" - found '$core_name'",
"($num_saved_cores/$opt_max_save_core)");
- My::CoreDump->show($core_file);
+ My::CoreDump->show($core_file, $exe_mysqld);
if ($num_saved_cores >= $opt_max_save_core) {
mtr_report(" - deleting it, already saved",
@@ -515,6 +517,7 @@ sub run_test_server ($$$) {
}
}
$num_saved_datadir++;
+ $num_failed_test++ unless $result->{retries};
if ( !$opt_force ) {
# Test has failed, force is off
@@ -525,11 +528,12 @@ sub run_test_server ($$$) {
elsif ($opt_max_test_fail > 0 and
$num_failed_test >= $opt_max_test_fail) {
$suite_timeout_proc->kill();
+ push(@$completed, $result);
+ mtr_report_stats($completed, 1);
mtr_report("Too many tests($num_failed_test) failed!",
"Terminating...");
return undef;
}
- $num_failed_test++;
}
# Retry test run after test failure
@@ -554,9 +558,11 @@ sub run_test_server ($$$) {
# Repeat test $opt_repeat number of times
my $repeat= $result->{repeat} || 1;
- if ($repeat < $opt_repeat)
+ # Don't repeat if test was skipped
+ if ($repeat < $opt_repeat && $result->{'result'} ne 'MTR_RES_SKIPPED')
{
$result->{retries}= 0;
+ $result->{rep_failures}++ if $result->{failures};
$result->{failures}= 0;
delete($result->{result});
$result->{repeat}= $repeat+1;
@@ -655,6 +661,7 @@ sub run_test_server ($$$) {
# ----------------------------------------------------
if ( ! $suite_timeout_proc->wait_one(0) )
{
+ mtr_report_stats($completed, 1);
mtr_report("Test suite timeout! Terminating...");
return undef;
}
@@ -719,6 +726,8 @@ sub run_worker ($) {
delete($test->{'comment'});
delete($test->{'logfile'});
+ $test->{worker} = $thread_num if $opt_parallel > 1;
+
run_testcase($test);
#$test->{result}= 'MTR_RES_PASSED';
# Send it back, now with results set
@@ -786,7 +795,7 @@ sub command_line_setup {
'vs-config' => \$opt_vs_config,
# Max number of parallel threads to use
- 'parallel=i' => \$opt_parallel,
+ 'parallel=s' => \$opt_parallel,
# Config file to use as template for all tests
'defaults-file=s' => \&collect_option,
@@ -876,6 +885,7 @@ sub command_line_setup {
'sleep=i' => \$opt_sleep,
'start-dirty' => \$opt_start_dirty,
'start' => \$opt_start,
+ 'wait-all' => \$opt_wait_all,
'print-testcases' => \&collect_option,
'repeat=i' => \$opt_repeat,
'retry=i' => \$opt_retry,
@@ -1125,9 +1135,9 @@ sub command_line_setup {
# --------------------------------------------------------------------------
# Check parallel value
# --------------------------------------------------------------------------
- if ($opt_parallel < 1)
+ if ($opt_parallel ne "auto" && $opt_parallel < 1)
{
- mtr_error("0 or negative parallel value makes no sense, use positive number");
+ mtr_error("0 or negative parallel value makes no sense, use 'auto' or positive number");
}
# --------------------------------------------------------------------------
@@ -1233,6 +1243,15 @@ sub command_line_setup {
}
}
+ # --------------------------------------------------------------------------
+ # Check use of wait-all
+ # --------------------------------------------------------------------------
+
+ if ($opt_wait_all && ! ($opt_start_dirty || $opt_start))
+ {
+ mtr_error("--wait-all can only be used with --start or --start-dirty");
+ }
+
# --------------------------------------------------------------------------
# Check timeout arguments
# --------------------------------------------------------------------------
@@ -1323,29 +1342,31 @@ sub set_build_thread_ports($) {
if ( lc($opt_build_thread) eq 'auto' ) {
my $found_free = 0;
- $build_thread = 250; # Start attempts from here
+ $build_thread = 300; # Start attempts from here
while (! $found_free)
{
- $build_thread= mtr_get_unique_id($build_thread, 299);
+ $build_thread= mtr_get_unique_id($build_thread, 349);
if ( !defined $build_thread ) {
- mtr_error("Could not get a unique build thread id");
+ mtr_error("Could not get a unique build thread id");
}
$found_free= check_ports_free($build_thread);
# If not free, release and try from next number
- mtr_release_unique_id($build_thread++) unless $found_free;
+ if (! $found_free) {
+ mtr_release_unique_id();
+ $build_thread++;
+ }
}
}
else
{
$build_thread = $opt_build_thread + $thread - 1;
+ if (! check_ports_free($build_thread)) {
+ # Some port was not free(which one has already been printed)
+ mtr_error("Some port(s) was not free")
+ }
}
$ENV{MTR_BUILD_THREAD}= $build_thread;
- if (! check_ports_free($build_thread)) {
- # Some port was not free(which one has already been printed)
- mtr_error("Some port(s) was not free")
- }
-
# Calculate baseport
$baseport= $build_thread * 10 + 10000;
if ( $baseport < 5001 or $baseport + 9 >= 32767 )
@@ -1739,15 +1760,26 @@ sub environment_setup {
# --------------------------------------------------------------------------
# Add the path where mysqld will find ha_example.so
# --------------------------------------------------------------------------
- if ($mysql_version_id >= 50100) {
+ if ($mysql_version_id >= 50100 && !(IS_WINDOWS && $opt_embedded_server)) {
+ my $plugin_filename;
+ if (IS_WINDOWS)
+ {
+ $plugin_filename = "ha_example.dll";
+ }
+ else
+ {
+ $plugin_filename = "ha_example.so";
+ }
my $lib_example_plugin=
- mtr_file_exists(vs_config_dirs('storage/example', 'ha_example.dll'),
- "$basedir/storage/example/.libs/ha_example.so",);
+ mtr_file_exists(vs_config_dirs('storage/example',$plugin_filename),
+ "$basedir/storage/example/.libs/".$plugin_filename);
$ENV{'EXAMPLE_PLUGIN'}=
($lib_example_plugin ? basename($lib_example_plugin) : "");
$ENV{'EXAMPLE_PLUGIN_OPT'}= "--plugin-dir=".
($lib_example_plugin ? dirname($lib_example_plugin) : "");
+ $ENV{'HA_EXAMPLE_SO'}="'".$plugin_filename."'";
+ $ENV{'EXAMPLE_PLUGIN_LOAD'}="--plugin_load=;EXAMPLE=".$plugin_filename.";";
}
# ----------------------------------------------------
@@ -3134,6 +3166,26 @@ sub find_analyze_request
}
+# The test can leave a file in var/tmp/ to signal
+# that all servers should be restarted
+sub restart_forced_by_test
+{
+ my $restart = 0;
+ foreach my $mysqld ( mysqlds() )
+ {
+ my $datadir = $mysqld->value('datadir');
+ my $force_restart_file = "$datadir/mtr/force_restart";
+ if ( -f $force_restart_file )
+ {
+ mtr_verbose("Restart of servers forced by test");
+ $restart = 1;
+ last;
+ }
+ }
+ return $restart;
+}
+
+
# Return timezone value of tinfo or default value
sub timezone {
my ($tinfo)= @_;
@@ -3175,7 +3227,7 @@ sub run_testcase ($) {
{
# Remove old datadirs
- clean_datadir();
+ clean_datadir() unless $opt_start_dirty;
# Restore old ENV
while (my ($option, $value)= each( %old_env )) {
@@ -3242,19 +3294,29 @@ sub run_testcase ($) {
# --------------------------------------------------------------------
# If --start or --start-dirty given, stop here to let user manually
# run tests
+ # If --wait-all is also given, do the same, but don't die if one
+ # server exits
# ----------------------------------------------------------------------
+
if ( $opt_start or $opt_start_dirty )
{
mtr_print("\nStarted", started(all_servers()));
mtr_print("Waiting for server(s) to exit...");
- my $proc= My::SafeProcess->wait_any();
- if ( grep($proc eq $_, started(all_servers())) )
- {
- mtr_print("Server $proc died");
+ if ( $opt_wait_all ) {
+ My::SafeProcess->wait_all();
+ mtr_print( "All servers exited" );
+ exit(1);
+ }
+ else {
+ my $proc= My::SafeProcess->wait_any();
+ if ( grep($proc eq $_, started(all_servers())) )
+ {
+ mtr_print("Server $proc died");
+ exit(1);
+ }
+ mtr_print("Unknown process $proc died");
exit(1);
}
- mtr_print("Unknown process $proc died");
- exit(1);
}
my $test_timeout_proc= My::SafeProcess->timer(testcase_timeout());
@@ -3272,10 +3334,38 @@ sub run_testcase ($) {
}
my $test= start_mysqltest($tinfo);
+ # Set only when we have to keep waiting after expectedly died server
+ my $keep_waiting_proc = 0;
while (1)
{
- my $proc= My::SafeProcess->wait_any();
+ my $proc;
+ if ($keep_waiting_proc)
+ {
+ # Any other process exited?
+ $proc = My::SafeProcess->check_any();
+ if ($proc)
+ {
+ mtr_verbose ("Found exited process $proc");
+ # If that was the timeout, cancel waiting
+ if ( $proc eq $test_timeout_proc )
+ {
+ $keep_waiting_proc = 0;
+ }
+ }
+ else
+ {
+ $proc = $keep_waiting_proc;
+ }
+ }
+ else
+ {
+ $proc= My::SafeProcess->wait_any();
+ }
+
+ # Will be restored if we need to keep waiting
+ $keep_waiting_proc = 0;
+
unless ( defined $proc )
{
mtr_error("wait_any failed");
@@ -3302,7 +3392,11 @@ sub run_testcase ($) {
if ( $res == 0 )
{
my $check_res;
- if ( $opt_check_testcases and
+ if ( restart_forced_by_test() )
+ {
+ stop_all_servers();
+ }
+ elsif ( $opt_check_testcases and
$check_res= check_testcase($tinfo, "after"))
{
if ($check_res == 1) {
@@ -3367,8 +3461,12 @@ sub run_testcase ($) {
# ----------------------------------------------------
# Check if it was an expected crash
# ----------------------------------------------------
- if ( check_expected_crash_and_restart($proc) )
+ my $check_crash = check_expected_crash_and_restart($proc);
+ if ($check_crash)
{
+ # Keep waiting if it returned 2, if 1 don't wait or stop waiting.
+ $keep_waiting_proc = 0 if $check_crash == 1;
+ $keep_waiting_proc = $proc if $check_crash == 2;
next;
}
@@ -3709,16 +3807,16 @@ sub check_expected_crash_and_restart {
{
mtr_verbose("Crash was expected, file '$expect_file' exists");
- while (1){
-
+ for (my $waits = 0; $waits < 50; $waits++)
+ {
# If last line in expect file starts with "wait"
# sleep a little and try again, thus allowing the
# test script to control when the server should start
- # up again
+ # up again. Keep trying for up to 5s at a time.
my $last_line= mtr_lastlinesfromfile($expect_file, 1);
if ($last_line =~ /^wait/ )
{
- mtr_verbose("Test says wait before restart");
+ mtr_verbose("Test says wait before restart") if $waits == 0;
mtr_milli_sleep(100);
next;
}
@@ -3728,11 +3826,11 @@ sub check_expected_crash_and_restart {
# Start server with same settings as last time
mysqld_start($mysqld, $mysqld->{'started_opts'});
- last;
+ return 1;
}
+ # Loop ran through: we should keep waiting after a re-check
+ return 2;
}
-
- return 1;
}
# Not an expected crash
@@ -4431,14 +4529,17 @@ sub start_servers($) {
my $mysqld_basedir= $mysqld->value('basedir');
if ( $basedir eq $mysqld_basedir )
{
- # Copy datadir from installed system db
- for my $path ( "$opt_vardir", "$opt_vardir/..") {
- my $install_db= "$path/install.db";
- copytree($install_db, $datadir)
- if -d $install_db;
+ if (! $opt_start_dirty) # If dirty, keep possibly grown system db
+ {
+ # Copy datadir from installed system db
+ for my $path ( "$opt_vardir", "$opt_vardir/..") {
+ my $install_db= "$path/install.db";
+ copytree($install_db, $datadir)
+ if -d $install_db;
+ }
+ mtr_error("Failed to copy system db to '$datadir'")
+ unless -d $datadir;
}
- mtr_error("Failed to copy system db to '$datadir'")
- unless -d $datadir;
}
else
{
@@ -4978,10 +5079,13 @@ Options to control what engine/variation to run
vs-config Visual Studio configuration used to create executables
(default: MTR_VS_CONFIG environment variable)
- config|defaults-file= Use fixed config template for all
+ defaults-file= Use fixed config template for all
tests
defaults_extra_file= Extra config template to add to
all generated configs
+ combination= Use at least twice to run tests with specified
+ options to mysqld
+ skip-combinations Ignore combination file (or options)
Options to control directories to use
tmpdir=DIR The directory where temporary files are stored
@@ -5004,7 +5108,6 @@ Options to control what test suites or cases to run
force Continue to run the suite after failure
with-ndbcluster-only Run only tests that include "ndb" in the filename
skip-ndb[cluster] Skip all tests that need cluster
- skip-ndb[cluster]-slave Skip all tests that need a slave cluster
do-test=PREFIX or REGEX
Run test cases which name are prefixed with PREFIX
or fulfills REGEX
@@ -5019,6 +5122,9 @@ Options to control what test suites or cases to run
The default is: "$DEFAULT_SUITES"
skip-rpl Skip the replication test cases.
big-test Also run tests marked as "big"
+ enable-disabled Run also tests marked as disabled
+ print_testcases Don't run the tests but print details about all the
+ selected tests, in the order they would be run.
Options that specify ports
@@ -5087,7 +5193,7 @@ Options for valgrind
valgrind-options=ARGS Deprecated, use --valgrind-option
valgrind-option=ARGS Option to give valgrind, replaces default option(s),
can be specified more then once
- valgrind-path=[EXE] Path to the valgrind executable
+ valgrind-path= Path to the valgrind executable
callgrind Instruct valgrind to use callgrind
Misc options
@@ -5095,14 +5201,19 @@ Misc options
comment=STR Write STR to the output
notimer Don't show test case execution time
verbose More verbose output(use multiple times for even more)
+ verbose-restart Write when and why servers are restarted
start Only initialize and start the servers, using the
startup settings for the first specified test case
Example:
$0 --start alias &
start-dirty Only start the servers (without initialization) for
the first specified test case
+ wait-all If --start or --start-dirty option is used, wait for all
+ servers to exit before finishing the process
fast Run as fast as possible, dont't wait for servers
to shutdown etc.
+ parallel=N Run tests in N parallel threads (default=1)
+ Use parallel=auto for auto-setting of N
repeat=N Run each test N number of times
retry=N Retry tests that fail N times, limit number of failures
to $opt_retry_failure
@@ -5120,6 +5231,12 @@ Misc options
sleep=SECONDS Passed to mysqltest, will be used as fixed sleep time
gcov Collect coverage information after the test.
The result is a gcov file per source and header file.
+ experimental= Refer to list of tests considered experimental;
+ failures will be marked exp-fail instead of fail.
+ report-features First run a "test" that reports mysql features
+ timestamp Print timestamp before each test report line
+ timediff With --timestamp, also print time passed since
+ *previous* test started
HERE
exit(1);
diff --git a/mysql-test/r/bug46080.result b/mysql-test/r/bug46080.result
new file mode 100644
index 00000000000..18c7c22829a
--- /dev/null
+++ b/mysql-test/r/bug46080.result
@@ -0,0 +1,14 @@
+#
+# Bug #46080: group_concat(... order by) crashes server when
+# sort_buffer_size cannot allocate
+#
+CREATE TABLE t1(a CHAR(255));
+INSERT INTO t1 VALUES ('a');
+SET @@SESSION.sort_buffer_size=5*16*1000000;
+SET @@SESSION.max_heap_table_size=5*1000000;
+# Must not crash.
+SELECT GROUP_CONCAT(a ORDER BY a) FROM t1 GROUP BY a;
+DROP TABLE t1;
+SET @@SESSION.sort_buffer_size=default;
+SET @@SESSION.max_heap_table_size=default;
+End of 5.0 tests
diff --git a/mysql-test/r/cast.result b/mysql-test/r/cast.result
index c1af92c5f8d..dd61396e485 100644
--- a/mysql-test/r/cast.result
+++ b/mysql-test/r/cast.result
@@ -439,3 +439,16 @@ HOUR(NULL) MINUTE(NULL) SECOND(NULL)
NULL NULL NULL
DROP TABLE t1;
End of 5.0 tests
+#
+# Bug #44766: valgrind error when using convert() in a subquery
+#
+CREATE TABLE t1(a tinyint);
+INSERT INTO t1 VALUES (127);
+SELECT 1 FROM
+(
+SELECT CONVERT(t2.a USING UTF8) FROM t1, t1 t2 LIMIT 1
+) AS s LIMIT 1;
+1
+1
+DROP TABLE t1;
+End of 5.1 tests
diff --git a/mysql-test/r/commit_1innodb.result b/mysql-test/r/commit_1innodb.result
index de80dba47c1..cabd4c29c1d 100644
--- a/mysql-test/r/commit_1innodb.result
+++ b/mysql-test/r/commit_1innodb.result
@@ -766,15 +766,11 @@ call p_verify_status_increment(2, 2, 2, 2);
SUCCESS
savepoint a;
-call p_verify_status_increment(0, 0, 0, 0);
+call p_verify_status_increment(1, 0, 1, 0);
SUCCESS
insert t1 set a=4;
-# Binlog does not register itself this time for other than the 1st
-# statement of the transaction with MIXED/STATEMENT binlog_format.
-# It needs registering with the ROW format. Therefore 1,0,2,2 are
-# the correct arguments to this test after bug#40221 fixed.
-call p_verify_status_increment(1, 0, 2, 2);
+call p_verify_status_increment(2, 2, 2, 2);
SUCCESS
release savepoint a;
diff --git a/mysql-test/r/concurrent_innodb_safelog.result b/mysql-test/r/concurrent_innodb_safelog.result
index e6adaac1068..24a84afb9ce 100644
--- a/mysql-test/r/concurrent_innodb_safelog.result
+++ b/mysql-test/r/concurrent_innodb_safelog.result
@@ -785,6 +785,8 @@ eta tipo c
70 1 iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii
80 22 jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj
90 11 kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
+** Cleanup
+** connection thread2
** connection default
drop table t1;
drop user mysqltest@localhost;
diff --git a/mysql-test/r/concurrent_innodb_unsafelog.result b/mysql-test/r/concurrent_innodb_unsafelog.result
index e9c53d4cfa0..35fc2d89cfe 100644
--- a/mysql-test/r/concurrent_innodb_unsafelog.result
+++ b/mysql-test/r/concurrent_innodb_unsafelog.result
@@ -781,6 +781,8 @@ eta tipo c
70 1 iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii
80 1 jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj
90 11 kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
+** Cleanup
+** connection thread2
** connection default
drop table t1;
drop user mysqltest@localhost;
diff --git a/mysql-test/r/consistent_snapshot.result b/mysql-test/r/consistent_snapshot.result
index 694c996a58e..3a0227b1a1a 100644
--- a/mysql-test/r/consistent_snapshot.result
+++ b/mysql-test/r/consistent_snapshot.result
@@ -1,6 +1,9 @@
DROP TABLE IF EXISTS t1;
# Establish connection con1 (user=root)
# Establish connection con2 (user=root)
+### Test 1:
+### - While a consistent snapshot transaction is executed,
+### no external inserts should be visible to the transaction.
# Switch to connection con1
CREATE TABLE t1 (a INT) ENGINE=innodb;
START TRANSACTION WITH CONSISTENT SNAPSHOT;
@@ -10,6 +13,9 @@ INSERT INTO t1 VALUES(1);
SELECT * FROM t1;
a
COMMIT;
+### Test 2:
+### - For any non-consistent snapshot transaction, external
+### committed inserts should be visible to the transaction.
DELETE FROM t1;
START TRANSACTION;
# Switch to connection con2
@@ -19,5 +25,18 @@ SELECT * FROM t1;
a
1
COMMIT;
+### Test 3:
+### - Bug#44664: valgrind warning for COMMIT_AND_CHAIN and ROLLBACK_AND_CHAIN
+### Chaining a transaction does not retain consistency level.
+START TRANSACTION WITH CONSISTENT SNAPSHOT;
+DELETE FROM t1;
+COMMIT WORK AND CHAIN;
+# Switch to connection con2
+INSERT INTO t1 VALUES(1);
+# Switch to connection con1
+SELECT * FROM t1;
+a
+1
+COMMIT;
# Switch to connection default + close connections con1 and con2
DROP TABLE t1;
diff --git a/mysql-test/r/ctype_cp932_binlog_row.result b/mysql-test/r/ctype_cp932_binlog_row.result
index 0370b7a1cf6..cbac6b14669 100644
--- a/mysql-test/r/ctype_cp932_binlog_row.result
+++ b/mysql-test/r/ctype_cp932_binlog_row.result
@@ -9,10 +9,10 @@ EXECUTE stmt1 USING @var1;
show binlog events from ;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Query # # use `test`; CREATE TABLE t1(f1 blob)
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
-master-bin.000001 # Query # # use `test`; COMMIT
+master-bin.000001 # Query # # COMMIT
SELECT HEX(f1) FROM t1;
HEX(f1)
8300
diff --git a/mysql-test/r/ctype_cp932_binlog_stm.result b/mysql-test/r/ctype_cp932_binlog_stm.result
index 0cd2d395ebc..044885d1ea7 100644
--- a/mysql-test/r/ctype_cp932_binlog_stm.result
+++ b/mysql-test/r/ctype_cp932_binlog_stm.result
@@ -9,7 +9,7 @@ EXECUTE stmt1 USING @var1;
show binlog events from ;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Query # # use `test`; CREATE TABLE t1(f1 blob)
-master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES('ƒ\0')
+master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES(0x8300)
SELECT HEX(f1) FROM t1;
HEX(f1)
8300
@@ -29,21 +29,29 @@ HEX(s1) HEX(s2) d
466F6F2773206120426172 ED40ED41ED42 47.93
DROP PROCEDURE bug18293|
DROP TABLE t4|
-SHOW BINLOG EVENTS FROM 369|
+SHOW BINLOG EVENTS FROM 370|
Log_name Pos Event_type Server_id End_log_pos Info
-master-bin.000001 369 Query 1 535 use `test`; CREATE TABLE t4 (s1 CHAR(50) CHARACTER SET latin1,
+master-bin.000001 370 Query 1 536 use `test`; CREATE TABLE t4 (s1 CHAR(50) CHARACTER SET latin1,
s2 CHAR(50) CHARACTER SET cp932,
d DECIMAL(10,2))
-master-bin.000001 535 Query 1 784 use `test`; CREATE DEFINER=`root`@`localhost` PROCEDURE `bug18293`(IN ins1 CHAR(50),
+master-bin.000001 536 Query 1 785 use `test`; CREATE DEFINER=`root`@`localhost` PROCEDURE `bug18293`(IN ins1 CHAR(50),
IN ins2 CHAR(50) CHARACTER SET cp932,
IN ind DECIMAL(10,2))
BEGIN
INSERT INTO t4 VALUES (ins1, ins2, ind);
END
-master-bin.000001 784 Query 1 1048 use `test`; INSERT INTO t4 VALUES ( NAME_CONST('ins1',_latin1 0x466F6F2773206120426172 COLLATE 'latin1_swedish_ci'), NAME_CONST('ins2',_cp932 0xED40ED41ED42 COLLATE 'cp932_japanese_ci'), NAME_CONST('ind',47.93))
-master-bin.000001 1048 Query 1 1137 use `test`; DROP PROCEDURE bug18293
-master-bin.000001 1137 Query 1 1216 use `test`; DROP TABLE t4
+master-bin.000001 785 Query 1 1049 use `test`; INSERT INTO t4 VALUES ( NAME_CONST('ins1',_latin1 0x466F6F2773206120426172 COLLATE 'latin1_swedish_ci'), NAME_CONST('ins2',_cp932 0xED40ED41ED42 COLLATE 'cp932_japanese_ci'), NAME_CONST('ind',47.93))
+master-bin.000001 1049 Query 1 1138 use `test`; DROP PROCEDURE bug18293
+master-bin.000001 1138 Query 1 1217 use `test`; DROP TABLE t4
End of 5.0 tests
-SHOW BINLOG EVENTS FROM 364;
+SHOW BINLOG EVENTS FROM 365;
ERROR HY000: Error when executing command SHOW BINLOG EVENTS: Wrong offset or I/O error
+Bug#44352 UPPER/LOWER function doesn't work correctly on cp932 and sjis environment.
+CREATE TABLE t1 (a varchar(16)) character set cp932;
+INSERT INTO t1 VALUES (0x8372835E),(0x8352835E);
+SELECT hex(a), hex(lower(a)), hex(upper(a)) FROM t1 ORDER BY binary(a);
+hex(a) hex(lower(a)) hex(upper(a))
+8352835E 8352835E 8352835E
+8372835E 8372835E 8372835E
+DROP TABLE t1;
End of 5.1 tests
diff --git a/mysql-test/r/ctype_gbk_binlog.result b/mysql-test/r/ctype_gbk_binlog.result
new file mode 100644
index 00000000000..a49e170ff19
--- /dev/null
+++ b/mysql-test/r/ctype_gbk_binlog.result
@@ -0,0 +1,26 @@
+SET NAMES gbk;
+CREATE TABLE t1 (
+f1 BLOB
+) ENGINE=MyISAM DEFAULT CHARSET=gbk;
+CREATE PROCEDURE p1(IN val BLOB)
+BEGIN
+SET @tval = val;
+SET @sql_cmd = CONCAT_WS(' ', 'insert into t1(f1) values(?)');
+PREPARE stmt FROM @sql_cmd;
+EXECUTE stmt USING @tval;
+DEALLOCATE PREPARE stmt;
+END|
+SET @`tcontent`:=_binary 0x50434B000900000000000000E9000000 COLLATE `binary`/*!*/;
+CALL p1(@`tcontent`);
+FLUSH LOGS;
+DROP PROCEDURE p1;
+RENAME TABLE t1 to t2;
+SELECT hex(f1) FROM t2;
+hex(f1)
+50434B000900000000000000E9000000
+SELECT hex(f1) FROM t1;
+hex(f1)
+50434B000900000000000000E9000000
+DROP PROCEDURE p1;
+DROP TABLE t1;
+DROP TABLE t2;
diff --git a/mysql-test/r/ctype_ldml.result b/mysql-test/r/ctype_ldml.result
index 5dc9ea35cc3..711921eb526 100644
--- a/mysql-test/r/ctype_ldml.result
+++ b/mysql-test/r/ctype_ldml.result
@@ -40,6 +40,14 @@ abcd abcd
efgh efgh
ijkl ijkl
DROP TABLE t1;
+#
+# Bug#43827 Server closes connections and restarts
+#
+CREATE TABLE t1 (c1 VARCHAR(10) CHARACTER SET utf8 COLLATE utf8_test_ci);
+INSERT INTO t1 SELECT REPEAT('a',11);
+Warnings:
+Warning 1265 Data truncated for column 'c1' at row 1
+DROP TABLE t1;
show collation like 'ucs2_vn_ci';
Collation Charset Id Default Compiled Sortlen
ucs2_vn_ci ucs2 242 8
diff --git a/mysql-test/r/ctype_sjis.result b/mysql-test/r/ctype_sjis.result
index 91d6ebd9795..1469e335f23 100644
--- a/mysql-test/r/ctype_sjis.result
+++ b/mysql-test/r/ctype_sjis.result
@@ -209,3 +209,13 @@ SET NAMES sjis;
SELECT HEX('²“‘@Œ\') FROM DUAL;
HEX('²“‘@Œ\')
8DB2939181408C5C
+# Start of 5.1 tests
+Bug#44352 UPPER/LOWER function doesn't work correctly on cp932 and sjis environment.
+CREATE TABLE t1 (a varchar(16)) character set sjis;
+INSERT INTO t1 VALUES (0x8372835E),(0x8352835E);
+SELECT hex(a), hex(lower(a)), hex(upper(a)) FROM t1 ORDER BY binary(a);
+hex(a) hex(lower(a)) hex(upper(a))
+8352835E 8352835E 8352835E
+8372835E 8372835E 8372835E
+DROP TABLE t1;
+# End of 5.1 tests
diff --git a/mysql-test/r/ddl_i18n_koi8r.result b/mysql-test/r/ddl_i18n_koi8r.result
index af3a0899181..fe24c17a1c5 100644
--- a/mysql-test/r/ddl_i18n_koi8r.result
+++ b/mysql-test/r/ddl_i18n_koi8r.result
@@ -2829,7 +2829,11 @@ t2 CREATE TABLE `t2` (
`col1` varchar(10) COLLATE cp1251_general_cs DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=cp1251 COLLATE=cp1251_general_cs
+---> connection: con2
+
+---> connection: con3
+
---> connection: default
-use test|
-DROP DATABASE mysqltest1|
-DROP DATABASE mysqltest2|
+USE test;
+DROP DATABASE mysqltest1;
+DROP DATABASE mysqltest2;
diff --git a/mysql-test/r/ddl_i18n_utf8.result b/mysql-test/r/ddl_i18n_utf8.result
index 10c2afcadc1..cf4272bf90c 100644
--- a/mysql-test/r/ddl_i18n_utf8.result
+++ b/mysql-test/r/ddl_i18n_utf8.result
@@ -2829,7 +2829,11 @@ t2 CREATE TABLE `t2` (
`col1` varchar(10) COLLATE cp1251_general_cs DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=cp1251 COLLATE=cp1251_general_cs
+---> connection: con2
+
+---> connection: con3
+
---> connection: default
-use test|
-DROP DATABASE mysqltest1|
-DROP DATABASE mysqltest2|
+USE test;
+DROP DATABASE mysqltest1;
+DROP DATABASE mysqltest2;
diff --git a/mysql-test/r/derived.result b/mysql-test/r/derived.result
index 306c51fb8cf..80f04ffd455 100644
--- a/mysql-test/r/derived.result
+++ b/mysql-test/r/derived.result
@@ -383,3 +383,21 @@ select t2.* from (select * from t1) as A inner join t2 on A.ID = t2.FID;
ID DATA FID
drop table t1, t2;
drop user mysqltest_1;
+# End of 4.1 tests
+SELECT 0 FROM
+(SELECT 0) t01, (SELECT 0) t02, (SELECT 0) t03, (SELECT 0) t04, (SELECT 0) t05,
+(SELECT 0) t06, (SELECT 0) t07, (SELECT 0) t08, (SELECT 0) t09, (SELECT 0) t10,
+(SELECT 0) t11, (SELECT 0) t12, (SELECT 0) t13, (SELECT 0) t14, (SELECT 0) t15,
+(SELECT 0) t16, (SELECT 0) t17, (SELECT 0) t18, (SELECT 0) t19, (SELECT 0) t20,
+(SELECT 0) t21, (SELECT 0) t22, (SELECT 0) t23, (SELECT 0) t24, (SELECT 0) t25,
+(SELECT 0) t26, (SELECT 0) t27, (SELECT 0) t28, (SELECT 0) t29, (SELECT 0) t30,
+(SELECT 0) t31, (SELECT 0) t32, (SELECT 0) t33, (SELECT 0) t34, (SELECT 0) t35,
+(SELECT 0) t36, (SELECT 0) t37, (SELECT 0) t38, (SELECT 0) t39, (SELECT 0) t40,
+(SELECT 0) t41, (SELECT 0) t42, (SELECT 0) t43, (SELECT 0) t44, (SELECT 0) t45,
+(SELECT 0) t46, (SELECT 0) t47, (SELECT 0) t48, (SELECT 0) t49, (SELECT 0) t50,
+(SELECT 0) t51, (SELECT 0) t52, (SELECT 0) t53, (SELECT 0) t54, (SELECT 0) t55,
+(SELECT 0) t56, (SELECT 0) t57, (SELECT 0) t58, (SELECT 0) t59, (SELECT 0) t60,
+(SELECT 0) t61;
+0
+0
+# End of 5.0 tests
diff --git a/mysql-test/r/distinct.result b/mysql-test/r/distinct.result
index f71bbd175e3..e0324af8cfd 100644
--- a/mysql-test/r/distinct.result
+++ b/mysql-test/r/distinct.result
@@ -629,21 +629,21 @@ SELECT DISTINCT @v5:= fruit_id, @v6:= fruit_name INTO @v7, @v8 FROM t1 WHERE
fruit_name = 'APPLE';
SELECT @v5, @v6, @v7, @v8;
@v5 @v6 @v7 @v8
-3 PEAR 3 PEAR
+2 APPLE 2 APPLE
SELECT DISTINCT @v5 + fruit_id, CONCAT(@v6, fruit_name) INTO @v9, @v10 FROM t1
WHERE fruit_name = 'APPLE';
SELECT @v5, @v6, @v7, @v8, @v9, @v10;
@v5 @v6 @v7 @v8 @v9 @v10
-3 PEAR 3 PEAR 5 PEARAPPLE
+2 APPLE 2 APPLE 4 APPLEAPPLE
SELECT DISTINCT @v11:= @v5 + fruit_id, @v12:= CONCAT(@v6, fruit_name) INTO
@v13, @v14 FROM t1 WHERE fruit_name = 'APPLE';
SELECT @v11, @v12, @v13, @v14;
@v11 @v12 @v13 @v14
-6 PEARPEAR 6 PEARPEAR
+4 APPLEAPPLE 4 APPLEAPPLE
SELECT DISTINCT @v13, @v14 INTO @v15, @v16 FROM t1 WHERE fruit_name = 'APPLE';
SELECT @v15, @v16;
@v15 @v16
-6 PEARPEAR
+4 APPLEAPPLE
SELECT DISTINCT 2 + 2, 'Bob' INTO @v17, @v18 FROM t1 WHERE fruit_name =
'APPLE';
SELECT @v17, @v18;
diff --git a/mysql-test/r/events_stress.result b/mysql-test/r/events_stress.result
index 17eb32b36b7..9b9f3caaff6 100644
--- a/mysql-test/r/events_stress.result
+++ b/mysql-test/r/events_stress.result
@@ -63,3 +63,4 @@ DROP TABLE fill_it1;
DROP TABLE fill_it2;
DROP TABLE fill_it3;
DROP DATABASE events_test;
+SET GLOBAL event_scheduler=off;
diff --git a/mysql-test/r/func_compress.result b/mysql-test/r/func_compress.result
index 8e14b7695ee..b4e61d0e4fc 100644
--- a/mysql-test/r/func_compress.result
+++ b/mysql-test/r/func_compress.result
@@ -117,4 +117,13 @@ Warnings:
Error 1259 ZLIB: Input data corrupted
Error 1259 ZLIB: Input data corrupted
drop table t1;
+CREATE TABLE t1 (c1 INT);
+INSERT INTO t1 VALUES (1), (1111), (11111);
+SELECT UNCOMPRESS(c1), UNCOMPRESSED_LENGTH(c1) FROM t1;
+UNCOMPRESS(c1) UNCOMPRESSED_LENGTH(c1)
+NULL NULL
+NULL NULL
+NULL 825307441
+EXPLAIN EXTENDED SELECT * FROM (SELECT UNCOMPRESSED_LENGTH(c1) FROM t1) AS s;
+DROP TABLE t1;
End of 5.0 tests
diff --git a/mysql-test/r/func_concat.result b/mysql-test/r/func_concat.result
index 7e7c163716e..75b4888fbb2 100644
--- a/mysql-test/r/func_concat.result
+++ b/mysql-test/r/func_concat.result
@@ -89,3 +89,34 @@ c1 c2
First
DROP TABLE t1;
# End of 5.0 tests
+#
+# Bug #44743: Join in combination with concat does not always work
+#
+CREATE TABLE t1 (
+a VARCHAR(100) NOT NULL DEFAULT '0',
+b VARCHAR(2) NOT NULL DEFAULT '',
+c VARCHAR(2) NOT NULL DEFAULT '',
+d TEXT NOT NULL,
+PRIMARY KEY (a, b, c),
+KEY (a)
+) DEFAULT CHARSET=utf8;
+INSERT INTO t1 VALUES ('gui_A', 'a', 'b', 'str1'),
+('gui_AB', 'a', 'b', 'str2'), ('gui_ABC', 'a', 'b', 'str3');
+CREATE TABLE t2 (
+a VARCHAR(100) NOT NULL DEFAULT '',
+PRIMARY KEY (a)
+) DEFAULT CHARSET=latin1;
+INSERT INTO t2 VALUES ('A'), ('AB'), ('ABC');
+SELECT CONCAT('gui_', t2.a), t1.d FROM t2
+LEFT JOIN t1 ON t1.a = CONCAT('gui_', t2.a) AND t1.b = 'a' AND t1.c = 'b';
+CONCAT('gui_', t2.a) d
+gui_A str1
+gui_AB str2
+gui_ABC str3
+EXPLAIN SELECT CONCAT('gui_', t2.a), t1.d FROM t2
+LEFT JOIN t1 ON t1.a = CONCAT('gui_', t2.a) AND t1.b = 'a' AND t1.c = 'b';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 index NULL PRIMARY 102 NULL 3 Using index
+1 SIMPLE t1 eq_ref PRIMARY,a PRIMARY 318 func,const,const 1
+DROP TABLE t1, t2;
+# End of 5.1 tests
diff --git a/mysql-test/r/func_crypt.result b/mysql-test/r/func_crypt.result
index 25b921681c5..c2f369b3941 100644
--- a/mysql-test/r/func_crypt.result
+++ b/mysql-test/r/func_crypt.result
@@ -95,3 +95,14 @@ Note 1003 select password('idkfa ') AS `password('idkfa ')`,old_password('idkfa'
select encrypt('1234','_.');
encrypt('1234','_.')
#
+#
+# Bug #44767: invalid memory reads in password() and old_password()
+# functions
+#
+CREATE TABLE t1(c1 MEDIUMBLOB);
+INSERT INTO t1 VALUES (REPEAT('a', 1024));
+SELECT OLD_PASSWORD(c1), PASSWORD(c1) FROM t1;
+OLD_PASSWORD(c1) PASSWORD(c1)
+77023ffe214c04ff *82E58A2C08AAFE72C8EB523069CD8ADB33F78F58
+DROP TABLE t1;
+End of 5.0 tests
diff --git a/mysql-test/r/func_in.result b/mysql-test/r/func_in.result
index 1e967b668c5..88a822a2fa6 100644
--- a/mysql-test/r/func_in.result
+++ b/mysql-test/r/func_in.result
@@ -587,4 +587,25 @@ SELECT CASE c1 WHEN c1 + 1 THEN 1 END, ABS(AVG(c0)) FROM t1;
CASE c1 WHEN c1 + 1 THEN 1 END ABS(AVG(c0))
NULL 1.0000
DROP TABLE t1;
+CREATE TABLE t1(a TEXT, b INT, c INT UNSIGNED, d DECIMAL(12,2), e REAL);
+INSERT INTO t1 VALUES('iynfj', 1, 1, 1, 1);
+INSERT INTO t1 VALUES('innfj', 2, 2, 2, 2);
+SELECT SUM( DISTINCT a ) FROM t1 GROUP BY a HAVING a IN ( AVG( 1 ), 1 + a);
+SUM( DISTINCT a )
+SELECT SUM( DISTINCT b ) FROM t1 GROUP BY b HAVING b IN ( AVG( 1 ), 1 + b);
+SUM( DISTINCT b )
+1
+SELECT SUM( DISTINCT c ) FROM t1 GROUP BY c HAVING c IN ( AVG( 1 ), 1 + c);
+SUM( DISTINCT c )
+1
+SELECT SUM( DISTINCT d ) FROM t1 GROUP BY d HAVING d IN ( AVG( 1 ), 1 + d);
+SUM( DISTINCT d )
+1.00
+SELECT SUM( DISTINCT e ) FROM t1 GROUP BY e HAVING e IN ( AVG( 1 ), 1 + e);
+SUM( DISTINCT e )
+1
+SELECT SUM( DISTINCT e ) FROM t1 GROUP BY b,c,d HAVING (b,c,d) IN
+((AVG( 1 ), 1 + c, 1 + d), (AVG( 1 ), 2 + c, 2 + d));
+SUM( DISTINCT e )
+DROP TABLE t1;
End of 5.1 tests
diff --git a/mysql-test/r/func_math.result b/mysql-test/r/func_math.result
index c3d2db2d553..fd7ef72409e 100644
--- a/mysql-test/r/func_math.result
+++ b/mysql-test/r/func_math.result
@@ -437,6 +437,13 @@ a ROUND(a)
-1e+16 -10000000000000002
1e+16 10000000000000002
DROP TABLE t1;
+CREATE TABLE t1(f1 LONGTEXT) engine=myisam;
+INSERT INTO t1 VALUES ('a');
+SELECT 1 FROM (SELECT ROUND(f1) AS a FROM t1) AS s WHERE a LIKE 'a';
+1
+SELECT 1 FROM (SELECT ROUND(f1, f1) AS a FROM t1) AS s WHERE a LIKE 'a';
+1
+DROP TABLE t1;
End of 5.0 tests
SELECT 1e308 + 1e308;
1e308 + 1e308
@@ -456,4 +463,23 @@ NULL
SELECT POW(10, 309);
POW(10, 309)
NULL
+#
+# Bug #44768: SIGFPE crash when selecting rand from a view
+# containing null
+#
+CREATE OR REPLACE VIEW v1 AS SELECT NULL AS a;
+SELECT RAND(a) FROM v1;
+RAND(a)
+0.155220427694936
+DROP VIEW v1;
+SELECT RAND(a) FROM (SELECT NULL AS a) b;
+RAND(a)
+0.155220427694936
+CREATE TABLE t1 (i INT);
+INSERT INTO t1 VALUES (NULL);
+SELECT RAND(i) FROM t1;
+RAND(i)
+0.155220427694936
+DROP TABLE t1;
+#
End of 5.1 tests
diff --git a/mysql-test/r/func_set.result b/mysql-test/r/func_set.result
index ecdc35ac4cd..14ebc8203ec 100644
--- a/mysql-test/r/func_set.result
+++ b/mysql-test/r/func_set.result
@@ -146,3 +146,16 @@ NULL
0
0
drop table t1;
+CREATE TABLE t1( a SET('a', 'b', 'c') );
+CREATE TABLE t2( a SET('a', 'b', 'c') );
+INSERT INTO t1 VALUES ('d');
+Warnings:
+Warning 1265 Data truncated for column 'a' at row 1
+INSERT INTO t2 VALUES ('');
+SELECT CONVERT( a USING latin1 ) FROM t1;
+CONVERT( a USING latin1 )
+
+SELECT CONVERT( a USING latin1 ) FROM t2;
+CONVERT( a USING latin1 )
+
+DROP TABLE t1, t2;
diff --git a/mysql-test/r/func_str.result b/mysql-test/r/func_str.result
index 25cbf2470ed..a0c3935fde0 100644
--- a/mysql-test/r/func_str.result
+++ b/mysql-test/r/func_str.result
@@ -2525,6 +2525,15 @@ SELECT DATE_FORMAT(c, GET_FORMAT(DATE, 'eur')) h, CONCAT(UPPER(aa),', ', aa) i F
h i
31.12.2008 AAAAAA, aaaaaa
DROP TABLE t1;
+#
+# BUG#44774: load_file function produces valgrind warnings
+#
+CREATE TABLE t1 (a TINYBLOB);
+INSERT INTO t1 VALUES ('aaaaaaaa');
+SELECT LOAD_FILE(a) FROM t1;
+LOAD_FILE(a)
+NULL
+DROP TABLE t1;
End of 5.0 tests
drop table if exists t1;
create table t1(f1 tinyint default null)engine=myisam;
diff --git a/mysql-test/r/gis.result b/mysql-test/r/gis.result
index 494b7a36532..a3708d06a1c 100644
--- a/mysql-test/r/gis.result
+++ b/mysql-test/r/gis.result
@@ -984,4 +984,52 @@ f4 geometry YES NULL
f5 datetime YES NULL
drop view v1;
drop table t1;
+SELECT MultiPoint(12345,'');
+MultiPoint(12345,'')
+NULL
+SELECT MultiPoint(123451,'');
+MultiPoint(123451,'')
+NULL
+SELECT MultiPoint(1234512,'');
+MultiPoint(1234512,'')
+NULL
+SELECT MultiPoint(12345123,'');
+MultiPoint(12345123,'')
+NULL
+SELECT MultiLineString(12345,'');
+MultiLineString(12345,'')
+NULL
+SELECT MultiLineString(123451,'');
+MultiLineString(123451,'')
+NULL
+SELECT MultiLineString(1234512,'');
+MultiLineString(1234512,'')
+NULL
+SELECT MultiLineString(12345123,'');
+MultiLineString(12345123,'')
+NULL
+SELECT LineString(12345,'');
+LineString(12345,'')
+NULL
+SELECT LineString(123451,'');
+LineString(123451,'')
+NULL
+SELECT LineString(1234512,'');
+LineString(1234512,'')
+NULL
+SELECT LineString(12345123,'');
+LineString(12345123,'')
+NULL
+SELECT Polygon(12345,'');
+Polygon(12345,'')
+NULL
+SELECT Polygon(123451,'');
+Polygon(123451,'')
+NULL
+SELECT Polygon(1234512,'');
+Polygon(1234512,'')
+NULL
+SELECT Polygon(12345123,'');
+Polygon(12345123,'')
+NULL
End of 5.1 tests
diff --git a/mysql-test/r/grant.result b/mysql-test/r/grant.result
index de80a83d538..a677d71b266 100644
--- a/mysql-test/r/grant.result
+++ b/mysql-test/r/grant.result
@@ -1358,3 +1358,58 @@ DROP USER 'userbug33464'@'localhost';
USE test;
DROP DATABASE dbbug33464;
SET @@global.log_bin_trust_function_creators= @old_log_bin_trust_function_creators;
+CREATE USER user1;
+CREATE USER user2;
+GRANT CREATE ON db1.* TO 'user1'@'localhost';
+GRANT CREATE ROUTINE ON db1.* TO 'user1'@'localhost';
+GRANT CREATE ON db1.* TO 'user2'@'%';
+GRANT CREATE ROUTINE ON db1.* TO 'user2'@'%';
+FLUSH PRIVILEGES;
+SHOW GRANTS FOR 'user1'@'localhost';
+Grants for user1@localhost
+GRANT USAGE ON *.* TO 'user1'@'localhost'
+GRANT CREATE, CREATE ROUTINE ON `db1`.* TO 'user1'@'localhost'
+** Connect as user1 and create a procedure.
+** The creation will imply implicitly assigned
+** EXECUTE and ALTER ROUTINE privileges to
+** the current user user1@localhost.
+SELECT @@GLOBAL.sql_mode;
+@@GLOBAL.sql_mode
+
+SELECT @@SESSION.sql_mode;
+@@SESSION.sql_mode
+
+CREATE DATABASE db1;
+CREATE PROCEDURE db1.proc1(p1 INT)
+BEGIN
+SET @x = 0;
+REPEAT SET @x = @x + 1; UNTIL @x > p1 END REPEAT;
+END ;||
+** Connect as user2 and create a procedure.
+** Implicitly assignment of privileges will
+** fail because the user2@localhost is an
+** unknown user.
+CREATE PROCEDURE db1.proc2(p1 INT)
+BEGIN
+SET @x = 0;
+REPEAT SET @x = @x + 1; UNTIL @x > p1 END REPEAT;
+END ;||
+Warnings:
+Warning 1404 Failed to grant EXECUTE and ALTER ROUTINE privileges
+SHOW GRANTS FOR 'user1'@'localhost';
+Grants for user1@localhost
+GRANT USAGE ON *.* TO 'user1'@'localhost'
+GRANT CREATE, CREATE ROUTINE ON `db1`.* TO 'user1'@'localhost'
+GRANT EXECUTE, ALTER ROUTINE ON PROCEDURE `db1`.`proc1` TO 'user1'@'localhost'
+SHOW GRANTS FOR 'user2';
+Grants for user2@%
+GRANT USAGE ON *.* TO 'user2'@'%'
+GRANT CREATE, CREATE ROUTINE ON `db1`.* TO 'user2'@'%'
+DROP PROCEDURE db1.proc1;
+DROP PROCEDURE db1.proc2;
+REVOKE ALL ON db1.* FROM 'user1'@'localhost';
+REVOKE ALL ON db1.* FROM 'user2'@'%';
+DROP USER 'user1';
+DROP USER 'user1'@'localhost';
+DROP USER 'user2';
+DROP DATABASE db1;
diff --git a/mysql-test/r/grant_cache_no_prot.result b/mysql-test/r/grant_cache_no_prot.result
index cb9acaf540d..32bb9cce90e 100644
--- a/mysql-test/r/grant_cache_no_prot.result
+++ b/mysql-test/r/grant_cache_no_prot.result
@@ -206,7 +206,8 @@ Qcache_hits 8
show status like "Qcache_not_cached";
Variable_name Value
Qcache_not_cached 8
------ switch to connection default and close connections -----
+----- close connections -----
+----- switch to connection default -----
set names binary;
delete from mysql.user where user in ("mysqltest_1","mysqltest_2","mysqltest_3");
delete from mysql.db where user in ("mysqltest_1","mysqltest_2","mysqltest_3");
diff --git a/mysql-test/r/grant_cache_ps_prot.result b/mysql-test/r/grant_cache_ps_prot.result
index cf1450f3b75..281468ee2e1 100644
--- a/mysql-test/r/grant_cache_ps_prot.result
+++ b/mysql-test/r/grant_cache_ps_prot.result
@@ -206,7 +206,8 @@ Qcache_hits 8
show status like "Qcache_not_cached";
Variable_name Value
Qcache_not_cached 5
------ switch to connection default and close connections -----
+----- close connections -----
+----- switch to connection default -----
set names binary;
delete from mysql.user where user in ("mysqltest_1","mysqltest_2","mysqltest_3");
delete from mysql.db where user in ("mysqltest_1","mysqltest_2","mysqltest_3");
diff --git a/mysql-test/r/group_min_max.result b/mysql-test/r/group_min_max.result
index b17884c4f7a..27448d3e949 100644
--- a/mysql-test/r/group_min_max.result
+++ b/mysql-test/r/group_min_max.result
@@ -2462,4 +2462,43 @@ c
1
2
DROP TABLE t1;
+#
+# Bug #45386: Wrong query result with MIN function in field list,
+# WHERE and GROUP BY clause
+#
+CREATE TABLE t (a INT, b INT, INDEX (a,b));
+INSERT INTO t VALUES (2,0), (2,0), (2,1), (2,1);
+INSERT INTO t SELECT * FROM t;
+# test MIN
+#should use range with index for group by
+EXPLAIN
+SELECT a, MIN(b) FROM t WHERE b <> 0 GROUP BY a;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t range NULL a 10 NULL 9 Using where; Using index for group-by
+#should return 1 row
+SELECT a, MIN(b) FROM t WHERE b <> 0 GROUP BY a;
+a MIN(b)
+2 1
+# test MAX
+#should use range with index for group by
+EXPLAIN
+SELECT a, MAX(b) FROM t WHERE b <> 1 GROUP BY a;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t range NULL a 10 NULL 9 Using where; Using index for group-by
+#should return 1 row
+SELECT a, MAX(b) FROM t WHERE b <> 1 GROUP BY a;
+a MAX(b)
+2 0
+# test 3 ranges and use the middle one
+INSERT INTO t SELECT a, 2 FROM t;
+#should use range with index for group by
+EXPLAIN
+SELECT a, MAX(b) FROM t WHERE b > 0 AND b < 2 GROUP BY a;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t range NULL a 10 NULL 9 Using where; Using index for group-by
+#should return 1 row
+SELECT a, MAX(b) FROM t WHERE b > 0 AND b < 2 GROUP BY a;
+a MAX(b)
+2 1
+DROP TABLE t;
End of 5.0 tests
diff --git a/mysql-test/r/heap_btree.result b/mysql-test/r/heap_btree.result
index 9db03855c01..7ad0f212d99 100644
--- a/mysql-test/r/heap_btree.result
+++ b/mysql-test/r/heap_btree.result
@@ -336,4 +336,11 @@ a b
NULL NULL
NULL 1
drop table t1;
+#
+# bug#39918 - memory (heap) engine crashing while executing self join with delete
+#
+CREATE TABLE t1(a INT, KEY USING BTREE (a)) ENGINE=MEMORY;
+INSERT INTO t1 VALUES(1),(1);
+DELETE a1 FROM t1 AS a1, t1 AS a2 WHERE a1.a=a2.a;
+DROP TABLE t1;
End of 5.0 tests
diff --git a/mysql-test/r/index_merge_myisam.result b/mysql-test/r/index_merge_myisam.result
index 8a935d87457..c639b20de91 100644
--- a/mysql-test/r/index_merge_myisam.result
+++ b/mysql-test/r/index_merge_myisam.result
@@ -557,6 +557,30 @@ a
1
2
drop table t0, t1, t2, t3;
+#
+# BUG#44810: index merge and order by with low sort_buffer_size
+# crashes server!
+#
+CREATE TABLE t1(a VARCHAR(128),b VARCHAR(128),KEY(A),KEY(B));
+INSERT INTO t1 VALUES (REPEAT('a',128),REPEAT('b',128));
+INSERT INTO t1 SELECT * FROM t1;
+INSERT INTO t1 SELECT * FROM t1;
+INSERT INTO t1 SELECT * FROM t1;
+INSERT INTO t1 SELECT * FROM t1;
+INSERT INTO t1 SELECT * FROM t1;
+INSERT INTO t1 SELECT * FROM t1;
+SET SESSION sort_buffer_size=1;
+Warnings:
+Warning 1292 Truncated incorrect sort_buffer_size value: '1'
+EXPLAIN
+SELECT * FROM t1 FORCE INDEX(a,b) WHERE a LIKE 'a%' OR b LIKE 'b%'
+ORDER BY a,b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index_merge a,b a,b 131,131 NULL 64 Using sort_union(a,b); Using where; Using filesort
+SELECT * FROM t1 FORCE INDEX(a,b) WHERE a LIKE 'a%' OR b LIKE 'b%'
+ORDER BY a,b;
+SET SESSION sort_buffer_size=DEFAULT;
+DROP TABLE t1;
End of 5.0 tests
#---------------- ROR-index_merge tests -----------------------
SET SESSION STORAGE_ENGINE = MyISAM;
diff --git a/mysql-test/r/information_schema_db.result b/mysql-test/r/information_schema_db.result
index 475839569c7..6305f8cd47a 100644
--- a/mysql-test/r/information_schema_db.result
+++ b/mysql-test/r/information_schema_db.result
@@ -61,7 +61,7 @@ begin
select table_name from information_schema.key_column_usage
order by table_name;
end|
-create table t1
+create table t1
(f1 int(10) unsigned not null,
f2 varchar(100) not null,
primary key (f1), unique key (f2));
@@ -203,15 +203,15 @@ View Create View character_set_client collation_connection
v2 CREATE ALGORITHM=UNDEFINED DEFINER=`testdb_2`@`localhost` SQL SECURITY DEFINER VIEW `v2` AS select `v1`.`f1` AS `f1` from `testdb_1`.`v1` latin1 latin1_swedish_ci
show create view testdb_1.v1;
ERROR 42000: SHOW VIEW command denied to user 'testdb_2'@'localhost' for table 'v1'
-select table_name from information_schema.columns a
+select table_name from information_schema.columns a
where a.table_name = 'v2';
table_name
v2
-select view_definition from information_schema.views a
+select view_definition from information_schema.views a
where a.table_name = 'v2';
view_definition
select `v1`.`f1` AS `f1` from `testdb_1`.`v1`
-select view_definition from information_schema.views a
+select view_definition from information_schema.views a
where a.table_name = 'testdb_1.v1';
view_definition
select * from v2;
diff --git a/mysql-test/r/init_file.result b/mysql-test/r/init_file.result
index 8e014815a9c..43ed908ad01 100644
--- a/mysql-test/r/init_file.result
+++ b/mysql-test/r/init_file.result
@@ -4,6 +4,7 @@ SELECT * INTO @Y FROM init_file.startup limit 1,1;
SELECT YEAR(@X)-YEAR(@Y);
YEAR(@X)-YEAR(@Y)
0
+DROP DATABASE init_file;
ok
end of 4.1 tests
select * from t1;
@@ -19,3 +20,5 @@ y
3
11
13
+drop table t1, t2;
+call mtr.force_restart();
diff --git a/mysql-test/r/innodb_bug21704.result b/mysql-test/r/innodb_bug21704.result
new file mode 100644
index 00000000000..b8e0b15d50d
--- /dev/null
+++ b/mysql-test/r/innodb_bug21704.result
@@ -0,0 +1,55 @@
+#
+# Bug#21704: Renaming column does not update FK definition.
+#
+
+# Test that it's not possible to rename columns participating in a
+# foreign key (either in the referencing or referenced table).
+
+DROP TABLE IF EXISTS t1;
+DROP TABLE IF EXISTS t2;
+DROP TABLE IF EXISTS t3;
+CREATE TABLE t1 (a INT PRIMARY KEY, b INT) ROW_FORMAT=COMPACT ENGINE=INNODB;
+CREATE TABLE t2 (a INT PRIMARY KEY, b INT,
+CONSTRAINT fk1 FOREIGN KEY (a) REFERENCES t1(a))
+ROW_FORMAT=COMPACT ENGINE=INNODB;
+CREATE TABLE t3 (a INT PRIMARY KEY, b INT, KEY(b), C INT,
+CONSTRAINT fk2 FOREIGN KEY (b) REFERENCES t3 (a))
+ROW_FORMAT=COMPACT ENGINE=INNODB;
+INSERT INTO t1 VALUES (1,1),(2,2),(3,3);
+INSERT INTO t2 VALUES (1,1),(2,2),(3,3);
+INSERT INTO t3 VALUES (1,1,1),(2,2,2),(3,3,3);
+
+# Test renaming the column in the referenced table.
+
+ALTER TABLE t1 CHANGE a c INT;
+ERROR HY000: Error on rename of '#sql-temporary' to './test/t1' (errno: 150)
+# Ensure that online column rename works.
+ALTER TABLE t1 CHANGE b c INT;
+affected rows: 0
+info: Records: 0 Duplicates: 0 Warnings: 0
+
+# Test renaming the column in the referencing table
+
+ALTER TABLE t2 CHANGE a c INT;
+ERROR HY000: Error on rename of '#sql-temporary' to './test/t2' (errno: 150)
+# Ensure that online column rename works.
+ALTER TABLE t2 CHANGE b c INT;
+affected rows: 0
+info: Records: 0 Duplicates: 0 Warnings: 0
+
+# Test with self-referential constraints
+
+ALTER TABLE t3 CHANGE a d INT;
+ERROR HY000: Error on rename of '#sql-temporary' to './test/t3' (errno: 150)
+ALTER TABLE t3 CHANGE b d INT;
+ERROR HY000: Error on rename of '#sql-temporary' to './test/t3' (errno: 150)
+# Ensure that online column rename works.
+ALTER TABLE t3 CHANGE c d INT;
+affected rows: 0
+info: Records: 0 Duplicates: 0 Warnings: 0
+
+# Cleanup.
+
+DROP TABLE t3;
+DROP TABLE t2;
+DROP TABLE t1;
diff --git a/mysql-test/r/innodb_bug40565.result b/mysql-test/r/innodb_bug40565.result
new file mode 100644
index 00000000000..21e923d9336
--- /dev/null
+++ b/mysql-test/r/innodb_bug40565.result
@@ -0,0 +1,9 @@
+create table bug40565(value decimal(4,2)) engine=innodb;
+insert into bug40565 values (1), (null);
+update bug40565 set value=NULL;
+affected rows: 1
+info: Rows matched: 2 Changed: 1 Warnings: 0
+update bug40565 set value=NULL;
+affected rows: 0
+info: Rows matched: 2 Changed: 0 Warnings: 0
+drop table bug40565;
diff --git a/mysql-test/r/innodb_bug42101-nonzero.result b/mysql-test/r/innodb_bug42101-nonzero.result
new file mode 100644
index 00000000000..277dfffdd35
--- /dev/null
+++ b/mysql-test/r/innodb_bug42101-nonzero.result
@@ -0,0 +1,26 @@
+set global innodb_commit_concurrency=0;
+ERROR HY000: Incorrect arguments to SET
+select @@innodb_commit_concurrency;
+@@innodb_commit_concurrency
+1
+set global innodb_commit_concurrency=1;
+select @@innodb_commit_concurrency;
+@@innodb_commit_concurrency
+1
+set global innodb_commit_concurrency=42;
+select @@innodb_commit_concurrency;
+@@innodb_commit_concurrency
+42
+set global innodb_commit_concurrency=DEFAULT;
+select @@innodb_commit_concurrency;
+@@innodb_commit_concurrency
+1
+set global innodb_commit_concurrency=0;
+ERROR HY000: Incorrect arguments to SET
+select @@innodb_commit_concurrency;
+@@innodb_commit_concurrency
+1
+set global innodb_commit_concurrency=1;
+select @@innodb_commit_concurrency;
+@@innodb_commit_concurrency
+1
diff --git a/mysql-test/r/innodb_bug42101.result b/mysql-test/r/innodb_bug42101.result
new file mode 100644
index 00000000000..805097ffe9d
--- /dev/null
+++ b/mysql-test/r/innodb_bug42101.result
@@ -0,0 +1,22 @@
+set global innodb_commit_concurrency=0;
+select @@innodb_commit_concurrency;
+@@innodb_commit_concurrency
+0
+set global innodb_commit_concurrency=1;
+ERROR HY000: Incorrect arguments to SET
+select @@innodb_commit_concurrency;
+@@innodb_commit_concurrency
+0
+set global innodb_commit_concurrency=42;
+ERROR HY000: Incorrect arguments to SET
+select @@innodb_commit_concurrency;
+@@innodb_commit_concurrency
+0
+set global innodb_commit_concurrency=0;
+select @@innodb_commit_concurrency;
+@@innodb_commit_concurrency
+0
+set global innodb_commit_concurrency=DEFAULT;
+select @@innodb_commit_concurrency;
+@@innodb_commit_concurrency
+0
diff --git a/mysql-test/r/innodb_bug45357.result b/mysql-test/r/innodb_bug45357.result
new file mode 100644
index 00000000000..7adeff2062f
--- /dev/null
+++ b/mysql-test/r/innodb_bug45357.result
@@ -0,0 +1,7 @@
+set session transaction isolation level read committed;
+create table bug45357(a int, b int,key(b))engine=innodb;
+insert into bug45357 values (25170,6122);
+update bug45357 set a=1 where b=30131;
+delete from bug45357 where b < 20996;
+delete from bug45357 where b < 7001;
+drop table bug45357;
diff --git a/mysql-test/r/innodb_mysql.result b/mysql-test/r/innodb_mysql.result
index 191a8578d4c..3ff5f04b6c6 100644
--- a/mysql-test/r/innodb_mysql.result
+++ b/mysql-test/r/innodb_mysql.result
@@ -1408,6 +1408,30 @@ SAVEPOINT s4;
ROLLBACK;
ROLLBACK TO SAVEPOINT s4;
ERROR 42000: SAVEPOINT s4 does not exist
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY COMMENT 'My ID#', f2 INTEGER DEFAULT NULL, f3 CHAR(10) DEFAULT 'My ID#', CONSTRAINT f2_ref FOREIGN KEY (f2) REFERENCES t1 (f1)) ENGINE=INNODB;
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f1` int(11) NOT NULL COMMENT 'My ID#',
+ `f2` int(11) DEFAULT NULL,
+ `f3` char(10) DEFAULT 'My ID#',
+ PRIMARY KEY (`f1`),
+ KEY `f2_ref` (`f2`),
+ CONSTRAINT `f2_ref` FOREIGN KEY (`f2`) REFERENCES `t1` (`f1`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+DROP TABLE t1;
+#
+# Bug #36995: valgrind error in remove_const during subquery executions
+#
+create table t1 (a bit(1) not null,b int) engine=myisam;
+create table t2 (c int) engine=innodb;
+explain
+select b from t1 where a not in (select b from t1,t2 group by a) group by a;
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
+2 DEPENDENT SUBQUERY t1 system NULL NULL NULL NULL 0 const row not found
+2 DEPENDENT SUBQUERY t2 ALL NULL NULL NULL NULL 1
+DROP TABLE t1,t2;
End of 5.0 tests
CREATE TABLE `t2` (
`k` int(11) NOT NULL auto_increment,
@@ -1677,10 +1701,10 @@ INSERT INTO t1 VALUES
(4,1,2,'c2',NULL),(5,1,2,'c1',NULL),(2,1,3,'c2',NULL),(3,1,3,'c2',NULL),
(4,1,3,'pk',NULL),(5,1,3,'c2',NULL),
(2,1,4,'c_extra',NULL),(3,1,4,'c_extra',NULL);
-EXPLAIN SELECT * FROM t1 WHERE tid = 1 AND vid = 3 ORDER BY idx DESC;
+EXPLAIN SELECT * FROM t1 FORCE INDEX (PRIMARY) WHERE tid = 1 AND vid = 3 ORDER BY idx DESC;
id select_type table type possible_keys key key_len ref rows Extra
-1 SIMPLE t1 index vid PRIMARY 12 NULL 16 Using where
-SELECT * FROM t1 WHERE tid = 1 AND vid = 3 ORDER BY idx DESC;
+1 SIMPLE t1 index NULL PRIMARY 12 NULL 16 Using where
+SELECT * FROM t1 FORCE INDEX (PRIMARY) WHERE tid = 1 AND vid = 3 ORDER BY idx DESC;
vid tid idx name type
3 1 4 c_extra NULL
3 1 3 c2 NULL
@@ -1706,6 +1730,35 @@ id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY system NULL NULL NULL NULL 1
2 DERIVED t1 index c3,c2 c2 10 NULL 5
DROP TABLE t1;
+CREATE TABLE t1 (c1 REAL, c2 REAL, c3 REAL, KEY (c3), KEY (c2, c3))
+ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1,1,1), (1,1,1), (1,1,2), (1,1,1), (1,1,2);
+SELECT 1 FROM (SELECT COUNT(DISTINCT c1)
+FROM t1 WHERE c2 IN (1, 1) AND c3 = 2 GROUP BY c2) x;
+1
+1
+EXPLAIN
+SELECT 1 FROM (SELECT COUNT(DISTINCT c1)
+FROM t1 WHERE c2 IN (1, 1) AND c3 = 2 GROUP BY c2) x;
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY system NULL NULL NULL NULL 1
+2 DERIVED t1 index c3,c2 c2 18 NULL 5
+DROP TABLE t1;
+CREATE TABLE t1 (c1 DECIMAL(12,2), c2 DECIMAL(12,2), c3 DECIMAL(12,2),
+KEY (c3), KEY (c2, c3))
+ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1,1,1), (1,1,1), (1,1,2), (1,1,1), (1,1,2);
+SELECT 1 FROM (SELECT COUNT(DISTINCT c1)
+FROM t1 WHERE c2 IN (1, 1) AND c3 = 2 GROUP BY c2) x;
+1
+1
+EXPLAIN
+SELECT 1 FROM (SELECT COUNT(DISTINCT c1)
+FROM t1 WHERE c2 IN (1, 1) AND c3 = 2 GROUP BY c2) x;
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY system NULL NULL NULL NULL 1
+2 DERIVED t1 index c3,c2 c2 14 NULL 5
+DROP TABLE t1;
End of 5.1 tests
drop table if exists t1, t2, t3;
create table t1(a int);
@@ -2040,4 +2093,119 @@ DROP TABLE t4;
DROP TABLE t1;
DROP TABLE t2;
DROP TABLE t3;
+CREATE TABLE t1 (a INT, b INT, KEY (a)) ENGINE = INNODB;
+CREATE TABLE t2 (a INT KEY, b INT, KEY (b)) ENGINE = INNODB;
+CREATE TABLE t3 (a INT, b INT KEY, KEY (a)) ENGINE = INNODB;
+CREATE TABLE t4 (a INT KEY, b INT, KEY (b)) ENGINE = INNODB;
+INSERT INTO t1 VALUES (1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6);
+INSERT INTO t2 VALUES (1, 1), (2, 2), (3, 3), (4, 4), (5, 5);
+INSERT INTO t3 VALUES (1, 101), (2, 102), (3, 103), (4, 104), (5, 105), (6, 106);
+INSERT INTO t4 VALUES (1, 1), (2, 2), (3, 3), (4, 4), (5, 5);
+UPDATE t1, t2 SET t1.a = t1.a + 100, t2.b = t1.a + 10
+WHERE t1.a BETWEEN 2 AND 4 AND t2.a = t1.b;
+SELECT * FROM t2;
+a b
+1 1
+2 12
+3 13
+4 14
+5 5
+UPDATE t3, t4 SET t3.a = t3.a + 100, t4.b = t3.a + 10
+WHERE t3.a BETWEEN 2 AND 4 AND t4.a = t3.b - 100;
+SELECT * FROM t4;
+a b
+1 1
+2 12
+3 13
+4 14
+5 5
+DROP TABLE t1, t2, t3, t4;
+#
+# Bug#44886: SIGSEGV in test_if_skip_sort_order() -
+# uninitialized variable used as subscript
+#
+CREATE TABLE t1 (a INT, b INT, c INT, d INT, PRIMARY KEY (b), KEY (a,c))
+ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1,1,1,0);
+CREATE TABLE t2 (a INT, b INT, e INT, KEY (e)) ENGINE=InnoDB;
+INSERT INTO t2 VALUES (1,1,2);
+CREATE TABLE t3 (a INT, b INT) ENGINE=MyISAM;
+INSERT INTO t3 VALUES (1, 1);
+SELECT * FROM t1, t2, t3
+WHERE t1.a = t3.a AND (t1.b = t3.b OR t1.d) AND t2.b = t1.b AND t2.e = 2
+GROUP BY t1.b;
+a b c d a b e a b
+1 1 1 0 1 1 2 1 1
+DROP TABLE t1, t2, t3;
+#
+# Bug #45828: Optimizer won't use partial primary key if another
+# index can prevent filesort
+#
+CREATE TABLE `t1` (
+c1 int NOT NULL,
+c2 int NOT NULL,
+c3 int NOT NULL,
+PRIMARY KEY (c1,c2),
+KEY (c3)
+) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (5,2,1246276747);
+INSERT INTO t1 VALUES (2,1,1246281721);
+INSERT INTO t1 VALUES (7,3,1246281756);
+INSERT INTO t1 VALUES (4,2,1246282139);
+INSERT INTO t1 VALUES (3,1,1246282230);
+INSERT INTO t1 VALUES (1,0,1246282712);
+INSERT INTO t1 VALUES (8,3,1246282765);
+INSERT INTO t1 SELECT c1+10,c2+10,c3+10 FROM t1;
+INSERT INTO t1 SELECT c1+100,c2+100,c3+100 from t1;
+INSERT INTO t1 SELECT c1+1000,c2+1000,c3+1000 from t1;
+INSERT INTO t1 SELECT c1+10000,c2+10000,c3+10000 from t1;
+INSERT INTO t1 SELECT c1+100000,c2+100000,c3+100000 from t1;
+INSERT INTO t1 SELECT c1+1000000,c2+1000000,c3+1000000 from t1;
+SELECT * FROM t1 WHERE c1 = 99999999 AND c3 > 1 ORDER BY c3;
+c1 c2 c3
+EXPLAIN SELECT * FROM t1 WHERE c1 = 99999999 AND c3 > 1 ORDER BY c3;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ref PRIMARY,c3 PRIMARY 4 const 1 Using where; Using filesort
+EXPLAIN SELECT * FROM t1 FORCE INDEX (PRIMARY) WHERE c1 = 99999999 AND c3 > 1 ORDER BY c3;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ref PRIMARY PRIMARY 4 const 1 Using where; Using filesort
+CREATE TABLE t2 (
+c1 int NOT NULL,
+c2 int NOT NULL,
+c3 int NOT NULL,
+KEY (c1,c2),
+KEY (c3)
+) ENGINE=InnoDB;
+explain SELECT * FROM t2 WHERE c1 = 99999999 AND c3 > 1 ORDER BY c3;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t2 ref c1,c3 c1 4 const 1 Using where; Using filesort
+DROP TABLE t1,t2;
+#
+# 36259: Optimizing with ORDER BY
+#
+CREATE TABLE t1 (
+a INT NOT NULL AUTO_INCREMENT,
+b INT NOT NULL,
+c INT NOT NULL,
+d VARCHAR(5),
+e INT NOT NULL,
+PRIMARY KEY (a), KEY i2 (b,c,d)
+) ENGINE=InnoDB;
+INSERT INTO t1 (b,c,d,e) VALUES (1,1,'a',1), (2,2,'b',2);
+INSERT INTO t1 (b,c,d,e) SELECT RAND()*10000, RAND()*10000, d, e FROM t1;
+INSERT INTO t1 (b,c,d,e) SELECT RAND()*10000, RAND()*10000, d, e FROM t1;
+INSERT INTO t1 (b,c,d,e) SELECT RAND()*10000, RAND()*10000, d, e FROM t1;
+INSERT INTO t1 (b,c,d,e) SELECT RAND()*10000, RAND()*10000, d, e FROM t1;
+INSERT INTO t1 (b,c,d,e) SELECT RAND()*10000, RAND()*10000, d, e FROM t1;
+INSERT INTO t1 (b,c,d,e) SELECT RAND()*10000, RAND()*10000, d, e FROM t1;
+EXPLAIN SELECT * FROM t1 WHERE b=1 AND c=1 ORDER BY a;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ref i2 i2 8 const,const 1 Using where; Using filesort
+EXPLAIN SELECT * FROM t1 FORCE INDEX(i2) WHERE b=1 and c=1 ORDER BY a;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ref i2 i2 8 const,const 1 Using where; Using filesort
+EXPLAIN SELECT * FROM t1 FORCE INDEX(PRIMARY) WHERE b=1 AND c=1 ORDER BY a;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index NULL PRIMARY 4 NULL 128 Using where
+DROP TABLE t1;
End of 5.1 tests
diff --git a/mysql-test/r/insert_select.result b/mysql-test/r/insert_select.result
index 780e91ea73f..2f2cc6334a9 100644
--- a/mysql-test/r/insert_select.result
+++ b/mysql-test/r/insert_select.result
@@ -765,6 +765,11 @@ f1 f2
2 2
10 10
DROP TABLE t1, t2;
+CREATE TABLE t1 ( a INT KEY, b INT );
+INSERT INTO t1 VALUES ( 0, 1 );
+INSERT INTO t1 ( b ) SELECT MAX( b ) FROM t1 WHERE b = 2;
+ERROR 23000: Duplicate entry '0' for key 'PRIMARY'
+DROP TABLE t1;
SET SQL_MODE='STRICT_TRANS_TABLES,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION';
CREATE TABLE t1 (c VARCHAR(30), INDEX ix_c (c(10)));
CREATE TABLE t2 (d VARCHAR(10));
diff --git a/mysql-test/r/log_tables_debug.result b/mysql-test/r/log_tables_debug.result
new file mode 100644
index 00000000000..daedb8c103a
--- /dev/null
+++ b/mysql-test/r/log_tables_debug.result
@@ -0,0 +1,24 @@
+SET @old_general_log= @@global.general_log;
+SET @old_general_log_file= @@global.general_log_file;
+SET @old_slow_query_log= @@global.slow_query_log;
+SET @old_slow_query_log_file= @@global.slow_query_log_file;
+#
+# Bug#45387 Information about statement id for prepared
+# statements missed from general log
+#
+SET @@global.general_log = ON;
+SET @@global.general_log_file = 'bug45387_general.log';
+SET SESSION debug='+d,reset_log_last_time';
+FLUSH LOGS;
+SET @@global.general_log = @old_general_log;
+SET @@global.general_log_file = @old_general_log_file;
+SET SESSION debug='-d';
+Bug#45387: ID match.
+End of 5.1 tests
+#
+# Cleanup
+#
+SET global general_log = @old_general_log;
+SET global general_log_file = @old_general_log_file;
+SET global slow_query_log = @old_slow_query_log;
+SET global slow_query_log_file = @old_slow_query_log_file;
diff --git a/mysql-test/r/merge.result b/mysql-test/r/merge.result
index f53b328d14e..bf9108459d7 100644
--- a/mysql-test/r/merge.result
+++ b/mysql-test/r/merge.result
@@ -2127,4 +2127,18 @@ SELECT * FROM m1;
ERROR HY000: Unable to open underlying table which is differently defined or of non-MyISAM type or doesn't exist
DROP VIEW v1;
DROP TABLE m1, t1;
+#
+# Bug #45796: invalid memory reads and writes when altering merge and
+# base tables
+#
+CREATE TABLE t1(c1 INT) ENGINE=MyISAM;
+CREATE TABLE m1(c1 INT) ENGINE=MERGE UNION=(t1);
+ALTER TABLE m1 ADD INDEX idx_c1(c1);
+SELECT * FROM m1;
+ERROR HY000: Unable to open underlying table which is differently defined or of non-MyISAM type or doesn't exist
+ALTER TABLE t1 ADD INDEX idx_c1(c1);
+SELECT * FROM m1;
+c1
+DROP TABLE m1;
+DROP TABLE t1;
End of 5.1 tests
diff --git a/mysql-test/r/mysql-bug45236.result b/mysql-test/r/mysql-bug45236.result
new file mode 100644
index 00000000000..cefcb1d314c
--- /dev/null
+++ b/mysql-test/r/mysql-bug45236.result
@@ -0,0 +1,8 @@
+DROP TABLE IF EXISTS t1;
+SET @old_max_allowed_packet= @@global.max_allowed_packet;
+SET @@global.max_allowed_packet = 1024 * 1024 + 1024;
+CREATE TABLE t1(data LONGBLOB);
+INSERT INTO t1 SELECT CONCAT(REPEAT('1', 1024*1024 - 27),
+"\'\r dummydb dummyhost");
+DROP TABLE t1;
+SET @@global.max_allowed_packet = @old_max_allowed_packet;
diff --git a/mysql-test/r/mysql.result b/mysql-test/r/mysql.result
index 5054c3aa76f..e704f81e187 100644
--- a/mysql-test/r/mysql.result
+++ b/mysql-test/r/mysql.result
@@ -192,6 +192,13 @@ delimiter
1
1
1
+COUNT (*)
+1
+COUNT (*)
+1
+COUNT (*)
+1
+ERROR 2005 (HY000) at line 1: Unknown MySQL server host 'invalid_hostname' (errno)
End of 5.0 tests
WARNING: --server-arg option not supported in this configuration.
Warning (Code 1286): Unknown table engine 'nonexistent'
@@ -200,4 +207,5 @@ Warning (Code 1286): Unknown table engine 'nonexistent2'
Warning (Code 1266): Using storage engine MyISAM for table 't2'
Error (Code 1050): Table 't2' already exists
drop tables t1, t2;
+
End of tests
diff --git a/mysql-test/r/mysqlbinlog.result b/mysql-test/r/mysqlbinlog.result
index b55a96b6f30..295a2f41d40 100644
--- a/mysql-test/r/mysqlbinlog.result
+++ b/mysql-test/r/mysqlbinlog.result
@@ -471,4 +471,7 @@ IS NOT NULL
1
*** Unsigned server_id 4294967295 is found: 1 ***
SET @@global.server_id= 1;
+RESET MASTER;
+FLUSH LOGS;
+End of 5.0 tests
End of 5.1 tests
diff --git a/mysql-test/r/mysqldump.result b/mysql-test/r/mysqldump.result
index c97131563cb..2f8e0ce5ec1 100644
--- a/mysql-test/r/mysqldump.result
+++ b/mysql-test/r/mysqldump.result
@@ -3563,9 +3563,6 @@ grant REPLICATION CLIENT on *.* to mysqltest_1@localhost;
drop table t1;
drop user mysqltest_1@localhost;
#
-# Bug#21527 mysqldump incorrectly tries to LOCK TABLES on the
-# information_schema database.
-#
# Bug#21424 mysqldump failing to export/import views
#
create database mysqldump_myDB;
@@ -3605,6 +3602,39 @@ drop user myDB_User@localhost;
drop database mysqldump_myDB;
use test;
#
+# Bug #21527 mysqldump incorrectly tries to LOCK TABLES on the
+# information_schema database.
+#
+# Bug #33762: mysqldump can not dump INFORMATION_SCHEMA
+#
+DROP TABLE IF EXISTS `TABLES`;
+/*!40101 SET @saved_cs_client = @@character_set_client */;
+/*!40101 SET character_set_client = utf8 */;
+CREATE TEMPORARY TABLE `TABLES` (
+ `TABLE_CATALOG` varchar(512) DEFAULT NULL,
+ `TABLE_SCHEMA` varchar(64) NOT NULL DEFAULT '',
+ `TABLE_NAME` varchar(64) NOT NULL DEFAULT '',
+ `TABLE_TYPE` varchar(64) NOT NULL DEFAULT '',
+ `ENGINE` varchar(64) DEFAULT NULL,
+ `VERSION` bigint(21) unsigned DEFAULT NULL,
+ `ROW_FORMAT` varchar(10) DEFAULT NULL,
+ `TABLE_ROWS` bigint(21) unsigned DEFAULT NULL,
+ `AVG_ROW_LENGTH` bigint(21) unsigned DEFAULT NULL,
+ `DATA_LENGTH` bigint(21) unsigned DEFAULT NULL,
+ `MAX_DATA_LENGTH` bigint(21) unsigned DEFAULT NULL,
+ `INDEX_LENGTH` bigint(21) unsigned DEFAULT NULL,
+ `DATA_FREE` bigint(21) unsigned DEFAULT NULL,
+ `AUTO_INCREMENT` bigint(21) unsigned DEFAULT NULL,
+ `CREATE_TIME` datetime DEFAULT NULL,
+ `UPDATE_TIME` datetime DEFAULT NULL,
+ `CHECK_TIME` datetime DEFAULT NULL,
+ `TABLE_COLLATION` varchar(32) DEFAULT NULL,
+ `CHECKSUM` bigint(21) unsigned DEFAULT NULL,
+ `CREATE_OPTIONS` varchar(255) DEFAULT NULL,
+ `TABLE_COMMENT` varchar(80) NOT NULL DEFAULT ''
+) ENGINE=MEMORY DEFAULT CHARSET=utf8;
+/*!40101 SET character_set_client = @saved_cs_client */;
+#
# Bug#19745 mysqldump --xml produces invalid xml
#
DROP TABLE IF EXISTS t1;
@@ -4006,6 +4036,181 @@ UNLOCK TABLES;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
DROP TABLE t1;
+create table t1 (a text , b text);
+create table t2 (a text , b text);
+insert t1 values ("Duck, Duck", "goose");
+insert t1 values ("Duck, Duck", "pidgeon");
+insert t2 values ("We the people", "in order to perform");
+insert t2 values ("a more perfect", "union");
+select * from t1;
+a b
+Duck, Duck goose
+Duck, Duck pidgeon
+select * from t2;
+a b
+We the people in order to perform
+a more perfect union
+test.t1: Records: 2 Deleted: 0 Skipped: 0 Warnings: 0
+test.t2: Records: 2 Deleted: 0 Skipped: 0 Warnings: 0
+select * from t1;
+a b
+Duck, Duck goose
+Duck, Duck pidgeon
+Duck, Duck goose
+Duck, Duck pidgeon
+select * from t2;
+a b
+We the people in order to perform
+a more perfect union
+We the people in order to perform
+a more perfect union
+create table words(a varchar(255));
+create table words2(b varchar(255));
+select * from t1;
+a b
+Duck, Duck goose
+Duck, Duck pidgeon
+Duck, Duck goose
+Duck, Duck pidgeon
+Duck, Duck goose
+Duck, Duck pidgeon
+select * from t2;
+a b
+We the people in order to perform
+a more perfect union
+We the people in order to perform
+a more perfect union
+We the people in order to perform
+a more perfect union
+select * from words;
+a
+Aarhus
+Aaron
+Ababa
+aback
+abaft
+abandon
+abandoned
+abandoning
+abandonment
+abandons
+Aarhus
+Aaron
+Ababa
+aback
+abaft
+abandon
+abandoned
+abandoning
+abandonment
+abandons
+abase
+abased
+abasement
+abasements
+abases
+abash
+abashed
+abashes
+abashing
+abasing
+abate
+abated
+abatement
+abatements
+abater
+abates
+abating
+Abba
+abbe
+abbey
+abbeys
+abbot
+abbots
+Abbott
+abbreviate
+abbreviated
+abbreviates
+abbreviating
+abbreviation
+abbreviations
+Abby
+abdomen
+abdomens
+abdominal
+abduct
+abducted
+abduction
+abductions
+abductor
+abductors
+abducts
+Abe
+abed
+Abel
+Abelian
+Abelson
+Aberdeen
+Abernathy
+aberrant
+aberration
+select * from words2;
+b
+abase
+abased
+abasement
+abasements
+abases
+abash
+abashed
+abashes
+abashing
+abasing
+abate
+abated
+abatement
+abatements
+abater
+abates
+abating
+Abba
+abbe
+abbey
+abbeys
+abbot
+abbots
+Abbott
+abbreviate
+abbreviated
+abbreviates
+abbreviating
+abbreviation
+abbreviations
+Abby
+abdomen
+abdomens
+abdominal
+abduct
+abducted
+abduction
+abductions
+abductor
+abductors
+abducts
+Abe
+abed
+Abel
+Abelian
+Abelson
+Aberdeen
+Abernathy
+aberrant
+aberration
+drop table words;
+mysql-import: Error: 1146, Table 'test.words' doesn't exist, when using table: words
+drop table t1;
+drop table t2;
+drop table words2;
#
# Bug#16853 mysqldump doesn't show events
#
@@ -4226,6 +4431,57 @@ DROP DATABASE mysqldump_test_db;
# -- End of test case for Bug#32538.
SET @@GLOBAL.CONCURRENT_INSERT = @OLD_CONCURRENT_INSERT;
+
+Bug #34861 - mysqldump with --tab gives weird output for triggers.
+
+CREATE TABLE t1 (f1 INT);
+CREATE TRIGGER tr1 BEFORE UPDATE ON t1 FOR EACH ROW SET @f1 = 1;
+CREATE PROCEDURE pr1 () SELECT "Meow";
+CREATE EVENT ev1 ON SCHEDULE AT '2030-01-01 00:00:00' DO SELECT "Meow";
+
+SHOW TRIGGERS;
+Trigger Event Table Statement Timing Created sql_mode Definer character_set_client collation_connection Database Collation
+tr1 UPDATE t1 SET @f1 = 1 BEFORE NULL root@localhost latin1 latin1_swedish_ci latin1_swedish_ci
+SHOW EVENTS;
+Db Name Definer Time zone Type Execute at Interval value Interval field Starts Ends Status Originator character_set_client collation_connection Database Collation
+test ev1 root@localhost SYSTEM ONE TIME 2030-01-01 00:00:00 NULL NULL NULL NULL ENABLED 1 latin1 latin1_swedish_ci latin1_swedish_ci
+SELECT name,body FROM mysql.proc WHERE NAME = 'pr1';
+name body
+pr1 SELECT "Meow"
+
+dump table; if anything goes to stdout, it ends up here: ---------------
+
+drop everything
+DROP EVENT ev1;
+DROP TRIGGER tr1;
+DROP TABLE t1;
+DROP PROCEDURE pr1;
+
+reload table; this should restore table and trigger
+SHOW TRIGGERS;
+Trigger Event Table Statement Timing Created sql_mode Definer character_set_client collation_connection Database Collation
+tr1 UPDATE t1 SET @f1 = 1 BEFORE NULL root@localhost latin1 latin1_swedish_ci latin1_swedish_ci
+SHOW EVENTS;
+Db Name Definer Time zone Type Execute at Interval value Interval field Starts Ends Status Originator character_set_client collation_connection Database Collation
+SELECT name,body FROM mysql.proc WHERE NAME = 'pr1';
+name body
+
+reload db; this should restore routines and events
+SHOW TRIGGERS;
+Trigger Event Table Statement Timing Created sql_mode Definer character_set_client collation_connection Database Collation
+tr1 UPDATE t1 SET @f1 = 1 BEFORE NULL root@localhost latin1 latin1_swedish_ci latin1_swedish_ci
+SHOW EVENTS;
+Db Name Definer Time zone Type Execute at Interval value Interval field Starts Ends Status Originator character_set_client collation_connection Database Collation
+test ev1 root@localhost SYSTEM ONE TIME 2030-01-01 00:00:00 NULL NULL NULL NULL ENABLED 1 latin1 latin1_swedish_ci latin1_swedish_ci
+SELECT name,body FROM mysql.proc WHERE NAME = 'pr1';
+name body
+pr1 SELECT "Meow"
+
+cleanup
+DROP EVENT IF EXISTS ev1;
+DROP PROCEDURE IF EXISTS pr1;
+DROP TRIGGER IF EXISTS tr1;
+DROP TABLE IF EXISTS t1;
#
# End of 5.1 tests
#
diff --git a/mysql-test/r/mysqldump_restore.result b/mysql-test/r/mysqldump_restore.result
new file mode 100644
index 00000000000..16698251913
--- /dev/null
+++ b/mysql-test/r/mysqldump_restore.result
@@ -0,0 +1,110 @@
+# Set concurrent_insert = 0 to prevent random errors
+# will reset to original value at the end of the test
+SET @old_concurrent_insert = @@global.concurrent_insert;
+SET @@global.concurrent_insert = 0;
+# Pre-test cleanup
+DROP TABLE IF EXISTS t1;
+# Begin tests
+#
+# Bug#2005 Long decimal comparison bug.
+#
+CREATE TABLE t1 (a DECIMAL(64, 20));
+INSERT INTO t1 VALUES ("1234567890123456789012345678901234567890"),
+("0987654321098765432109876543210987654321");
+# Begin testing mysqldump output + restore
+# Create 'original table name - _orig
+SET @orig_table_name = CONCAT('test.t1', '_orig');
+# Rename original table
+ALTER TABLE test.t1 RENAME to test.t1_orig;
+# Recreate table from mysqldump output
+# Compare original and recreated tables
+# Recreated table: test.t1
+# Original table: test.t1_orig
+Comparing tables test.t1 and test.t1_orig
+# Cleanup
+DROP TABLE test.t1, test.t1_orig;
+#
+# Bug#3361 mysqldump quotes DECIMAL values inconsistently
+#
+CREATE TABLE t1 (a DECIMAL(10,5), b FLOAT);
+INSERT INTO t1 VALUES (1.2345, 2.3456);
+INSERT INTO t1 VALUES ('1.2345', 2.3456);
+INSERT INTO t1 VALUES ("1.2345", 2.3456);
+SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='ANSI_QUOTES';
+INSERT INTO t1 VALUES (1.2345, 2.3456);
+INSERT INTO t1 VALUES ('1.2345', 2.3456);
+INSERT INTO t1 VALUES ("1.2345", 2.3456);
+ERROR 42S22: Unknown column '1.2345' in 'field list'
+SET SQL_MODE=@OLD_SQL_MODE;
+# Begin testing mysqldump output + restore
+# Create 'original table name - _orig
+SET @orig_table_name = CONCAT('test.t1', '_orig');
+# Rename original table
+ALTER TABLE test.t1 RENAME to test.t1_orig;
+# Recreate table from mysqldump output
+# Compare original and recreated tables
+# Recreated table: test.t1
+# Original table: test.t1_orig
+Comparing tables test.t1 and test.t1_orig
+# Cleanup
+DROP TABLE test.t1, test.t1_orig;
+#
+# Bug#1994 mysqldump does not correctly dump UCS2 data
+# Bug#4261 mysqldump 10.7 (mysql 4.1.2) --skip-extended-insert drops NULL from inserts
+#
+CREATE TABLE t1 (a VARCHAR(255)) DEFAULT CHARSET koi8r;
+INSERT INTO t1 VALUES (_koi8r x'C1C2C3C4C5'), (NULL);
+# Begin testing mysqldump output + restore
+# Create 'original table name - _orig
+SET @orig_table_name = CONCAT('test.t1', '_orig');
+# Rename original table
+ALTER TABLE test.t1 RENAME to test.t1_orig;
+# Recreate table from mysqldump output
+# Compare original and recreated tables
+# Recreated table: test.t1
+# Original table: test.t1_orig
+Comparing tables test.t1 and test.t1_orig
+# Cleanup
+DROP TABLE test.t1, test.t1_orig;
+#
+# WL#2319 Exclude Tables from dump
+#
+CREATE TABLE t1 (a INT);
+CREATE TABLE t2 (a INT);
+INSERT INTO t1 VALUES (1),(2),(3);
+INSERT INTO t2 VALUES (4),(5),(6);
+# Begin testing mysqldump output + restore
+# Create 'original table name - _orig
+SET @orig_table_name = CONCAT('test.t2', '_orig');
+# Rename original table
+ALTER TABLE test.t2 RENAME to test.t2_orig;
+# Recreate table from mysqldump output
+# Compare original and recreated tables
+# Recreated table: test.t2
+# Original table: test.t2_orig
+Comparing tables test.t2 and test.t2_orig
+# Cleanup
+DROP TABLE test.t2, test.t2_orig;
+DROP TABLE t1;
+#
+# Bug#8830 mysqldump --skip-extended-insert causes --hex-blob to dump wrong values
+#
+CREATE TABLE t1 (`b` blob);
+INSERT INTO `t1` VALUES (0x602010000280100005E71A);
+# Begin testing mysqldump output + restore
+# Create 'original table name - _orig
+SET @orig_table_name = CONCAT('test.t1', '_orig');
+# Rename original table
+ALTER TABLE test.t1 RENAME to test.t1_orig;
+# Recreate table from mysqldump output
+# Compare original and recreated tables
+# Recreated table: test.t1
+# Original table: test.t1_orig
+Comparing tables test.t1 and test.t1_orig
+# Cleanup
+DROP TABLE test.t1, test.t1_orig;
+# End tests
+# Cleanup
+# Reset concurrent_insert to its original value
+SET @@global.concurrent_insert = @old_concurrent_insert;
+# remove mysqldumpfile
diff --git a/mysql-test/r/mysqltest.result b/mysql-test/r/mysqltest.result
index a9c20e34517..52a1734ea54 100644
--- a/mysql-test/r/mysqltest.result
+++ b/mysql-test/r/mysqltest.result
@@ -545,6 +545,8 @@ mysqltest: At line 1: Failed to open file 'non_existing_file'
mysqltest: At line 1: Missing required argument 'filename' to command 'file_exists'
mysqltest: At line 1: Missing required argument 'from_file' to command 'copy_file'
mysqltest: At line 1: Missing required argument 'to_file' to command 'copy_file'
+mysqltest: At line 1: Missing required argument 'from_file' to command 'move_file'
+mysqltest: At line 1: Missing required argument 'to_file' to command 'move_file'
mysqltest: At line 1: Missing required argument 'mode' to command 'chmod'
mysqltest: At line 1: You must write a 4 digit octal number for mode
mysqltest: At line 1: You must write a 4 digit octal number for mode
@@ -697,6 +699,7 @@ statement="SHOW COLUMNS FROM t1" row_number=1, column_name="Type", Value=int(11)
statement=SHOW COLUMNS FROM t1 row_number=1, column_name=Default, Value=NULL
value= ->A B<-
value= 1
+value= 2
mysqltest: At line 1: query_get_value - argument list started with '(' must be ended with ')'
mysqltest: At line 1: Missing required argument 'query' to command 'query_get_value'
mysqltest: At line 1: Missing required argument 'column name' to command 'query_get_value'
diff --git a/mysql-test/r/openssl_1.result b/mysql-test/r/openssl_1.result
index c408c14b716..b0dd3acd662 100644
--- a/mysql-test/r/openssl_1.result
+++ b/mysql-test/r/openssl_1.result
@@ -202,4 +202,10 @@ Ssl_cipher RC4-SHA
select 'is still running; no cipher request crashed the server' as result from dual;
result
is still running; no cipher request crashed the server
+GRANT SELECT ON test.* TO bug42158@localhost REQUIRE X509;
+FLUSH PRIVILEGES;
+SHOW STATUS LIKE 'Ssl_cipher';
+Variable_name Value
+Ssl_cipher DHE-RSA-AES256-SHA
+DROP USER bug42158@localhost;
End of 5.1 tests
diff --git a/mysql-test/r/partition.result b/mysql-test/r/partition.result
index f69ba522a9c..8e3fbde1ea8 100644
--- a/mysql-test/r/partition.result
+++ b/mysql-test/r/partition.result
@@ -1924,5 +1924,72 @@ EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a>=200;
id select_type table partitions type possible_keys key key_len ref rows Extra
1 SIMPLE t1 p2,p3 ALL NULL NULL NULL NULL 3 Using where
DROP TABLE t1;
+CREATE TABLE t1 ( a INT, b INT, c INT, KEY bc(b, c) )
+PARTITION BY KEY (a, b) PARTITIONS 3
+;
+INSERT INTO t1 VALUES
+(17, 1, -8),
+(3, 1, -7),
+(23, 1, -6),
+(22, 1, -5),
+(11, 1, -4),
+(21, 1, -3),
+(19, 1, -2),
+(30, 1, -1),
+(20, 1, 1),
+(16, 1, 2),
+(18, 1, 3),
+(9, 1, 4),
+(15, 1, 5),
+(28, 1, 6),
+(29, 1, 7),
+(25, 1, 8),
+(10, 1, 9),
+(13, 1, 10),
+(27, 1, 11),
+(24, 1, 12),
+(12, 1, 13),
+(26, 1, 14),
+(14, 1, 15)
+;
+SELECT b, c FROM t1 WHERE b = 1 GROUP BY b, c;
+b c
+1 -8
+1 -7
+1 -6
+1 -5
+1 -4
+1 -3
+1 -2
+1 -1
+1 1
+1 2
+1 3
+1 4
+1 5
+1 6
+1 7
+1 8
+1 9
+1 10
+1 11
+1 12
+1 13
+1 14
+1 15
+EXPLAIN
+SELECT b, c FROM t1 WHERE b = 1 GROUP BY b, c;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range bc bc 10 NULL 7 Using where; Using index for group-by
+DROP TABLE t1;
+#
+# Bug #45807: crash accessing partitioned table and sql_mode
+# contains ONLY_FULL_GROUP_BY
+#
+SET SESSION SQL_MODE='ONLY_FULL_GROUP_BY';
+CREATE TABLE t1(id INT,KEY(id)) ENGINE=MYISAM
+PARTITION BY HASH(id) PARTITIONS 2;
+DROP TABLE t1;
+SET SESSION SQL_MODE=DEFAULT;
End of 5.1 tests
SET @@global.general_log= @old_general_log;
diff --git a/mysql-test/r/query_cache_debug.result b/mysql-test/r/query_cache_debug.result
index b03a71d3fec..eb59e62c8ba 100644
--- a/mysql-test/r/query_cache_debug.result
+++ b/mysql-test/r/query_cache_debug.result
@@ -71,3 +71,111 @@ DROP TABLE t1,t2;
SET GLOBAL concurrent_insert= DEFAULT;
SET GLOBAL query_cache_size= DEFAULT;
SET GLOBAL query_cache_type= DEFAULT;
+#
+# Bug43758 Query cache can lock up threads in 'freeing items' state
+#
+FLUSH STATUS;
+SET GLOBAL query_cache_type=DEMAND;
+SET GLOBAL query_cache_size= 1024*768;
+DROP TABLE IF EXISTS t1,t2,t3,t4,t5;
+CREATE TABLE t1 (a VARCHAR(100));
+CREATE TABLE t2 (a VARCHAR(100));
+CREATE TABLE t3 (a VARCHAR(100));
+CREATE TABLE t4 (a VARCHAR(100));
+CREATE TABLE t5 (a VARCHAR(100));
+INSERT INTO t1 VALUES ('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'),('bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb');
+INSERT INTO t2 VALUES ('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'),('bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb');
+INSERT INTO t3 VALUES ('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'),('bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb');
+INSERT INTO t4 VALUES ('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'),('bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb');
+INSERT INTO t5 VALUES ('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'),('bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb');
+=================================== Connection thd1
+**
+** Load Query Cache with a result set and one table.
+**
+SELECT SQL_CACHE * FROM t1;
+a
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
+*************************************************************************
+** We want to accomplish the following state:
+** - Query cache status: TABLE_FLUSH_IN_PROGRESS
+** - THD1: invalidate_table_internal (iterating query blocks)
+** - THD2: query_cache_insert (cond_wait)
+** - THD3: query_cache_insert (cond_wait)
+** - No thread should be holding the structure_guard_mutex.
+**
+** First step is to place a DELETE-statement on the debug hook just
+** before the mutex lock in invalidate_table_internal.
+** This will allow new result sets to be written into the QC.
+**
+SET SESSION debug='+d,wait_in_query_cache_invalidate1';
+SET SESSION debug='+d,wait_in_query_cache_invalidate2';
+DELETE FROM t1 WHERE a like '%a%';;
+=================================== Connection default
+** Assert that the expect process status is obtained.
+**
+=================================== Connection thd2
+** On THD2: Insert a result into the cache. This attempt will be blocked
+** because of a debug hook placed just before the mutex lock after which
+** the first part of the result set is written.
+SET SESSION debug='+d,wait_in_query_cache_insert';
+SELECT SQL_CACHE * FROM t2 UNION SELECT * FROM t3;
+=================================== Connection thd3
+** On THD3: Insert another result into the cache and block on the same
+** debug hook.
+SET SESSION debug='+d,wait_in_query_cache_insert';
+SELECT SQL_CACHE * FROM t4 UNION SELECT * FROM t5;;
+=================================== Connection default
+** Assert that the two SELECT-stmt threads to reach the hook.
+**
+**
+** Signal the DELETE thread, THD1, to continue. It will enter the mutex
+** lock and set query cache status to TABLE_FLUSH_IN_PROGRESS and then
+** unlock the mutex before stopping on the next debug hook.
+SELECT SQL_NO_CACHE id FROM information_schema.processlist WHERE state='wait_in_query_cache_invalidate1' LIMIT 1 INTO @flush_thread_id;
+KILL QUERY @flush_thread_id;
+** Assert that we reach the next debug hook.
+**
+** Signal the remaining debug hooks blocking THD2 and THD3.
+** The threads will grab the guard mutex enter the wait condition and
+** and finally release the mutex. The threads will continue to wait
+** until a broadcast signal reaches them causing both threads to
+** come alive and check the condition.
+SELECT SQL_NO_CACHE id FROM information_schema.processlist WHERE state='wait_in_query_cache_insert' ORDER BY id ASC LIMIT 1 INTO @thread_id;
+KILL QUERY @thread_id;
+SELECT SQL_NO_CACHE id FROM information_schema.processlist WHERE state='wait_in_query_cache_insert' ORDER BY id DESC LIMIT 1 INTO @thread_id;
+KILL QUERY @thread_id;
+**
+** Finally signal the DELETE statement on THD1 one last time.
+** The stmt will complete the query cache invalidation and return
+** cache status to NO_FLUSH_IN_PROGRESS. On the status change
+** One signal will be sent to the thread group waiting for executing
+** invalidations and a broadcast signal will be sent to the thread
+** group holding result set writers.
+SELECT SQL_NO_CACHE id FROM information_schema.processlist WHERE state='wait_in_query_cache_invalidate2' LIMIT 1 INTO @flush_thread_id;
+KILL QUERY @flush_thread_id;
+**
+*************************************************************************
+** No tables should be locked
+=================================== Connection thd2
+a
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
+DELETE FROM t1;
+DELETE FROM t2;
+DELETE FROM t3;
+=================================== Connection thd3
+a
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
+DELETE FROM t4;
+DELETE FROM t5;
+=================================== Connection thd1
+** Done.
+SET GLOBAL query_cache_size= 0;
+# Restore defaults
+RESET QUERY CACHE;
+FLUSH STATUS;
+DROP TABLE t1,t2,t3,t4,t5;
+SET GLOBAL query_cache_size= DEFAULT;
+SET GLOBAL query_cache_type= DEFAULT;
diff --git a/mysql-test/r/select.result b/mysql-test/r/select.result
index 09c7d1b329d..50b5c3c13fb 100644
--- a/mysql-test/r/select.result
+++ b/mysql-test/r/select.result
@@ -4457,4 +4457,83 @@ id select_type table type possible_keys key key_len ref rows filtered Extra
Warnings:
Note 1003 select '0' AS `a`,'0' AS `b`,'0' AS `c` from `test`.`t1` where 1
DROP TABLE t1;
+#
+# Bug#45266: Uninitialized variable lead to an empty result.
+#
+drop table if exists A,AA,B,BB;
+CREATE TABLE `A` (
+`pk` int(11) NOT NULL AUTO_INCREMENT,
+`date_key` date NOT NULL,
+`date_nokey` date NOT NULL,
+`datetime_key` datetime NOT NULL,
+`int_nokey` int(11) NOT NULL,
+`time_key` time NOT NULL,
+`time_nokey` time NOT NULL,
+PRIMARY KEY (`pk`),
+KEY `date_key` (`date_key`),
+KEY `time_key` (`time_key`),
+KEY `datetime_key` (`datetime_key`)
+);
+CREATE TABLE `AA` (
+`pk` int(11) NOT NULL AUTO_INCREMENT,
+`int_nokey` int(11) NOT NULL,
+`time_key` time NOT NULL,
+KEY `time_key` (`time_key`),
+PRIMARY KEY (`pk`)
+);
+CREATE TABLE `B` (
+`date_nokey` date NOT NULL,
+`date_key` date NOT NULL,
+`time_key` time NOT NULL,
+`datetime_nokey` datetime NOT NULL,
+`varchar_key` varchar(1) NOT NULL,
+KEY `date_key` (`date_key`),
+KEY `time_key` (`time_key`),
+KEY `varchar_key` (`varchar_key`)
+);
+INSERT INTO `B` VALUES ('2003-07-28','2003-07-28','15:13:38','0000-00-00 00:00:00','f'),('0000-00-00','0000-00-00','00:05:48','2004-07-02 14:34:13','x');
+CREATE TABLE `BB` (
+`pk` int(11) NOT NULL AUTO_INCREMENT,
+`int_nokey` int(11) NOT NULL,
+`date_key` date NOT NULL,
+`varchar_nokey` varchar(1) NOT NULL,
+`date_nokey` date NOT NULL,
+PRIMARY KEY (`pk`),
+KEY `date_key` (`date_key`)
+);
+INSERT INTO `BB` VALUES (10,8,'0000-00-00','i','0000-00-00'),(11,0,'2005-08-18','','2005-08-18');
+SELECT table1 . `pk` AS field1
+FROM
+(BB AS table1 INNER JOIN
+(AA AS table2 STRAIGHT_JOIN A AS table3
+ON ( table3 . `date_key` = table2 . `pk` ))
+ON ( table3 . `datetime_key` = table2 . `int_nokey` ))
+WHERE ( table3 . `date_key` <= 4 AND table2 . `pk` = table1 . `varchar_nokey`)
+GROUP BY field1 ;
+field1
+SELECT table3 .`date_key` field1
+FROM
+B table1 LEFT JOIN B table3 JOIN
+(BB table6 JOIN A table7 ON table6 .`varchar_nokey`)
+ON table6 .`int_nokey` ON table6 .`date_key`
+ WHERE NOT ( table1 .`varchar_key` AND table7 .`pk`) GROUP BY field1;
+field1
+NULL
+SELECT table4 . `time_nokey` AS field1 FROM
+(AA AS table1 CROSS JOIN
+(AA AS table2 STRAIGHT_JOIN
+(B AS table3 STRAIGHT_JOIN A AS table4
+ON ( table4 . `date_key` = table3 . `time_key` ))
+ON ( table4 . `pk` = table3 . `date_nokey` ))
+ON ( table4 . `time_key` = table3 . `datetime_nokey` ))
+WHERE ( table4 . `time_key` < table1 . `time_key` AND
+table1 . `int_nokey` != 'f')
+GROUP BY field1 ORDER BY field1 , field1;
+field1
+SELECT table1 .`time_key` field2 FROM B table1 LEFT JOIN BB JOIN A table5 ON table5 .`date_nokey` ON table5 .`int_nokey` GROUP BY field2;
+field2
+00:05:48
+15:13:38
+drop table A,AA,B,BB;
+#end of test for bug#45266
End of 5.1 tests
diff --git a/mysql-test/r/sp-error.result b/mysql-test/r/sp-error.result
index 35d61ce757d..17ab2b79043 100644
--- a/mysql-test/r/sp-error.result
+++ b/mysql-test/r/sp-error.result
@@ -1660,3 +1660,13 @@ declare continue handler for sqlstate '00000' set @x=0;
end$$
ERROR 42000: Bad SQLSTATE: '00000'
LOAD DATA INFILE '../../tmp/proc.txt' INTO TABLE mysql.proc;
+CREATE TABLE t1 (a INT, b INT);
+INSERT INTO t1 VALUES (1,1), (2,2);
+SELECT MAX (a) FROM t1 WHERE b = 999999;
+ERROR 42000: FUNCTION test.MAX does not exist. Check the 'Function Name Parsing and Resolution' section in the Reference Manual
+SELECT AVG (a) FROM t1 WHERE b = 999999;
+AVG (a)
+NULL
+SELECT non_existent (a) FROM t1 WHERE b = 999999;
+ERROR 42000: FUNCTION test.non_existent does not exist
+DROP TABLE t1;
diff --git a/mysql-test/r/sp-fib.result b/mysql-test/r/sp-fib.result
new file mode 100644
index 00000000000..a26e104c1e8
--- /dev/null
+++ b/mysql-test/r/sp-fib.result
@@ -0,0 +1,33 @@
+drop table if exists t3;
+create table t3 ( f bigint unsigned not null );
+drop procedure if exists fib;
+create procedure fib(n int unsigned)
+begin
+if n > 1 then
+begin
+declare x, y bigint unsigned;
+declare c cursor for select f from t3 order by f desc limit 2;
+open c;
+fetch c into y;
+fetch c into x;
+insert into t3 values (x+y);
+call fib(n-1);
+## Close the cursor AFTER the recursion to ensure that the stack
+## frame is somewhat intact.
+close c;
+end;
+end if;
+end|
+set @@max_sp_recursion_depth= 20|
+insert into t3 values (0), (1)|
+call fib(4)|
+select * from t3 order by f asc|
+f
+0
+1
+1
+2
+3
+drop table t3|
+drop procedure fib|
+set @@max_sp_recursion_depth= 0|
diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result
index 9574841bc35..3ad556b8c30 100644
--- a/mysql-test/r/sp.result
+++ b/mysql-test/r/sp.result
@@ -1337,52 +1337,6 @@ drop procedure opp|
drop procedure ip|
show procedure status where name like '%p%' and db='test'|
Db Name Type Definer Modified Created Security_type Comment character_set_client collation_connection Database Collation
-drop table if exists t3|
-create table t3 ( f bigint unsigned not null )|
-drop procedure if exists fib|
-create procedure fib(n int unsigned)
-begin
-if n > 1 then
-begin
-declare x, y bigint unsigned;
-declare c cursor for select f from t3 order by f desc limit 2;
-open c;
-fetch c into y;
-fetch c into x;
-close c;
-insert into t3 values (x+y);
-call fib(n-1);
-end;
-end if;
-end|
-set @@max_sp_recursion_depth= 20|
-insert into t3 values (0), (1)|
-call fib(3)|
-select * from t3 order by f asc|
-f
-0
-1
-1
-2
-truncate table t3|
-insert into t3 values (0), (1)|
-call fib(10)|
-select * from t3 order by f asc|
-f
-0
-1
-1
-2
-3
-5
-8
-13
-21
-34
-55
-drop table t3|
-drop procedure fib|
-set @@max_sp_recursion_depth= 0|
drop procedure if exists bar|
create procedure bar(x char(16), y int)
comment "111111111111" sql security invoker
diff --git a/mysql-test/r/sp_notembedded.result b/mysql-test/r/sp_notembedded.result
index d15efc6d7d7..c6641e673ee 100644
--- a/mysql-test/r/sp_notembedded.result
+++ b/mysql-test/r/sp_notembedded.result
@@ -233,4 +233,19 @@ rl_acquirer old
drop procedure p1;
drop table t1;
set session low_priority_updates=default;
+INSERT INTO mysql.user (Host, User, Password, Select_priv, Insert_priv, Update_priv,
+Delete_priv, Create_priv, Drop_priv, Reload_priv, Shutdown_priv, Process_priv, File_priv,
+Grant_priv, References_priv, Index_priv, Alter_priv, Show_db_priv, Super_priv,
+Create_tmp_table_priv, Lock_tables_priv, Execute_priv, Repl_slave_priv, Repl_client_priv,
+Create_view_priv, Show_view_priv, Create_routine_priv, Alter_routine_priv,
+Create_user_priv, ssl_type, ssl_cipher, x509_issuer, x509_subject, max_questions,
+max_updates, max_connections, max_user_connections)
+VALUES('%', 'mysqltest_1', password(''), 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'N', 'N', 'N',
+'N', 'N', 'N', 'Y', 'Y', 'N', 'N', 'Y', 'Y', 'N', 'N', 'N', 'N', 'N', 'Y', 'Y', 'N', '',
+'', '', '', '0', '0', '0', '0');
+FLUSH PRIVILEGES;
+CREATE PROCEDURE p1(i INT) BEGIN END;
+DROP PROCEDURE p1;
+DELETE FROM mysql.user WHERE User='mysqltest_1';
+FLUSH PRIVILEGES;
set @@global.concurrent_insert= @old_concurrent_insert;
diff --git a/mysql-test/r/sql_mode.result b/mysql-test/r/sql_mode.result
index 401340f204c..0b0d5a38d0b 100644
--- a/mysql-test/r/sql_mode.result
+++ b/mysql-test/r/sql_mode.result
@@ -506,3 +506,24 @@ mysqltest_32753@localhost
set session sql_mode=@OLD_SQL_MODE;
flush privileges;
drop user mysqltest_32753@localhost;
+DROP TABLE IF EXISTS t1,t2;
+CREATE USER 'user_PCTFL'@'localhost' identified by 'PWD';
+CREATE USER 'user_no_PCTFL'@'localhost' identified by 'PWD';
+CREATE TABLE t1 (f1 BIGINT);
+CREATE TABLE t2 (f1 CHAR(3) NOT NULL, f2 CHAR(20));
+GRANT ALL ON t1 TO 'user_PCTFL'@'localhost','user_no_PCTFL'@'localhost';
+GRANT SELECT(f1) ON t2 TO 'user_PCTFL'@'localhost','user_no_PCTFL'@'localhost';
+SET @OLD_SQL_MODE = @@SESSION.SQL_MODE;
+SET SESSION SQL_MODE = 'PAD_CHAR_TO_FULL_LENGTH';
+DROP USER 'user_PCTFL'@'localhost';
+SET SESSION SQL_MODE = @OLD_SQL_MODE;
+DROP USER 'user_no_PCTFL'@'localhost';
+FLUSH PRIVILEGES;
+SELECT * FROM mysql.db WHERE Host = 'localhost' AND User LIKE 'user_%PCTFL';
+Host Db User Select_priv Insert_priv Update_priv Delete_priv Create_priv Drop_priv Grant_priv References_priv Index_priv Alter_priv Create_tmp_table_priv Lock_tables_priv Create_view_priv Show_view_priv Create_routine_priv Alter_routine_priv Execute_priv Event_priv Trigger_priv
+SELECT * FROM mysql.tables_priv WHERE Host = 'localhost' AND User LIKE 'user_%PCTFL';
+Host Db User Table_name Grantor Timestamp Table_priv Column_priv
+SELECT * FROM mysql.columns_priv WHERE Host = 'localhost' AND User LIKE 'user_%PCTFL';
+Host Db User Table_name Column_name Timestamp Column_priv
+DROP TABLE t1;
+DROP TABLE t2;
diff --git a/mysql-test/r/status.result b/mysql-test/r/status.result
index ca815540c29..ce3acba9b8a 100644
--- a/mysql-test/r/status.result
+++ b/mysql-test/r/status.result
@@ -1,13 +1,15 @@
set @old_concurrent_insert= @@global.concurrent_insert;
set @@global.concurrent_insert= 0;
+SET @old_log_output = @@global.log_output;
+SET GLOBAL LOG_OUTPUT = 'FILE';
flush status;
show status like 'Table_lock%';
Variable_name Value
-Table_locks_immediate 1
+Table_locks_immediate 0
Table_locks_waited 0
select * from information_schema.session_status where variable_name like 'Table_lock%';
VARIABLE_NAME VARIABLE_VALUE
-TABLE_LOCKS_IMMEDIATE 2
+TABLE_LOCKS_IMMEDIATE 0
TABLE_LOCKS_WAITED 0
# Switched to connection: con1
set sql_log_bin=0;
@@ -154,7 +156,7 @@ Variable_name Value
Com_show_status 3
show status like 'hand%write%';
Variable_name Value
-Handler_write 5
+Handler_write 0
show status like '%tmp%';
Variable_name Value
Created_tmp_disk_tables 0
@@ -162,7 +164,7 @@ Created_tmp_files 0
Created_tmp_tables 0
show status like 'hand%write%';
Variable_name Value
-Handler_write 7
+Handler_write 0
show status like '%tmp%';
Variable_name Value
Created_tmp_disk_tables 0
@@ -237,3 +239,4 @@ SELECT 9;
DROP PROCEDURE p1;
DROP FUNCTION f1;
set @@global.concurrent_insert= @old_concurrent_insert;
+SET GLOBAL log_output = @old_log_output;
diff --git a/mysql-test/r/subselect3.result b/mysql-test/r/subselect3.result
index e0f361a0f4f..f055b40116a 100644
--- a/mysql-test/r/subselect3.result
+++ b/mysql-test/r/subselect3.result
@@ -849,6 +849,25 @@ ROW(1,2) = (SELECT 1, 1) ROW(1,2) IN (SELECT 1, 1)
SELECT ROW(1,2) = (SELECT 1, 2), ROW(1,2) IN (SELECT 1, 2);
ROW(1,2) = (SELECT 1, 2) ROW(1,2) IN (SELECT 1, 2)
1 1
+CREATE TABLE t1 (a INT, b INT, c INT);
+INSERT INTO t1 VALUES (1,1,1), (1,1,1);
+EXPLAIN EXTENDED
+SELECT c FROM
+( SELECT
+(SELECT COUNT(a) FROM
+(SELECT COUNT(b) FROM t1) AS x GROUP BY c
+) FROM t1 GROUP BY b
+) AS y;
+ERROR 42S22: Unknown column 'c' in 'field list'
+SHOW WARNINGS;
+Level Code Message
+Note 1276 Field or reference 'test.t1.a' of SELECT #3 was resolved in SELECT #2
+Note 1276 Field or reference 'test.t1.c' of SELECT #3 was resolved in SELECT #2
+Error 1054 Unknown column 'c' in 'field list'
+Note 1003 select `c` AS `c` from (select (select count(`test`.`t1`.`a`) AS `COUNT(a)` from (select count(`test`.`t1`.`b`) AS `COUNT(b)` from `test`.`t1`) `x` group by `c`) AS `(SELECT COUNT(a) FROM
+(SELECT COUNT(b) FROM t1) AS x GROUP BY c
+)` from `test`.`t1` group by `test`.`t1`.`b`) `y`
+DROP TABLE t1;
End of 5.0 tests
create table t0 (a int);
insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
diff --git a/mysql-test/r/trigger.result b/mysql-test/r/trigger.result
index 23f15f618f2..4476735735c 100644
--- a/mysql-test/r/trigger.result
+++ b/mysql-test/r/trigger.result
@@ -2073,4 +2073,18 @@ select @a, @b;
drop trigger trg1;
drop trigger trg2;
drop table t1, t2;
+CREATE TABLE t1 ( a INT, b INT );
+CREATE TABLE t2 ( a INT AUTO_INCREMENT KEY, b INT );
+INSERT INTO t1 (a) VALUES (1);
+CREATE TRIGGER tr1
+BEFORE INSERT ON t2
+FOR EACH ROW
+BEGIN
+UPDATE a_nonextisting_table SET a = 1;
+END//
+CREATE TABLE IF NOT EXISTS t2 ( a INT, b INT ) SELECT a, b FROM t1;
+ERROR 42S02: Table 'test.a_nonextisting_table' doesn't exist
+SELECT * FROM t2;
+a b
+DROP TABLE t1, t2;
End of 5.1 tests.
diff --git a/mysql-test/r/trigger_notembedded.result b/mysql-test/r/trigger_notembedded.result
index 1e13bff03b1..335e6910a3a 100644
--- a/mysql-test/r/trigger_notembedded.result
+++ b/mysql-test/r/trigger_notembedded.result
@@ -462,4 +462,18 @@ unlock tables;
select * from t1;
i
drop table t1;
+CREATE DATABASE db1;
+CREATE TABLE db1.t1 (a char(30)) ENGINE=MEMORY;
+CREATE TRIGGER db1.trg AFTER INSERT ON db1.t1 FOR EACH ROW
+INSERT INTO db1.t1 VALUES('Some very sensitive data goes here');
+CREATE USER 'no_rights'@'localhost';
+REVOKE ALL ON *.* FROM 'no_rights'@'localhost';
+FLUSH PRIVILEGES;
+SELECT trigger_name FROM INFORMATION_SCHEMA.TRIGGERS
+WHERE trigger_schema = 'db1';
+trigger_name
+SHOW CREATE TRIGGER db1.trg;
+ERROR 42000: Access denied; you need the TRIGGER privilege for this operation
+DROP USER 'no_rights'@'localhost';
+DROP DATABASE db1;
End of 5.1 tests.
diff --git a/mysql-test/r/type_newdecimal.result b/mysql-test/r/type_newdecimal.result
index f2b08d1c6b7..748aadee4fb 100644
--- a/mysql-test/r/type_newdecimal.result
+++ b/mysql-test/r/type_newdecimal.result
@@ -1524,10 +1524,10 @@ Warnings:
Warning 1264 Out of range value for column 'f1' at row 1
DESC t1;
Field Type Null Key Default Extra
-f1 decimal(59,30) NO 0.000000000000000000000000000000
+f1 decimal(65,30) NO 0.000000000000000000000000000000
SELECT f1 FROM t1;
f1
-99999999999999999999999999999.999999999999999999999999999999
+99999999999999999999999999999999999.999999999999999999999999999999
DROP TABLE t1;
select (1.20396873 * 0.89550000 * 0.68000000 * 1.08721696 * 0.99500000 *
1.01500000 * 1.01500000 * 0.99500000);
@@ -1577,3 +1577,56 @@ Error 1264 Out of range value for column 'cast(-13.4 as decimal(2,1))' at row 1
select cast(98.6 as decimal(2,0));
cast(98.6 as decimal(2,0))
99
+#
+# Bug #45262: Bad effects with CREATE TABLE and DECIMAL
+#
+CREATE TABLE t1 SELECT .123456789123456789123456789123456789123456789123456789123456789123456789123456789 AS my_col;
+Warnings:
+Note 1265 Data truncated for column 'my_col' at row 1
+DESCRIBE t1;
+Field Type Null Key Default Extra
+my_col decimal(30,30) NO 0.000000000000000000000000000000
+SELECT my_col FROM t1;
+my_col
+0.123456789123456789123456789123
+DROP TABLE t1;
+CREATE TABLE t1 SELECT 1 + .123456789123456789123456789123456789123456789123456789123456789123456789123456789 AS my_col;
+Warnings:
+Note 1265 Data truncated for column 'my_col' at row 1
+DESCRIBE t1;
+Field Type Null Key Default Extra
+my_col decimal(65,30) NO 0.000000000000000000000000000000
+SELECT my_col FROM t1;
+my_col
+1.123456789123456789123456789123
+DROP TABLE t1;
+CREATE TABLE t1 SELECT 1 * .123456789123456789123456789123456789123456789123456789123456789123456789123456789 AS my_col;
+Warnings:
+Note 1265 Data truncated for column 'my_col' at row 1
+DESCRIBE t1;
+Field Type Null Key Default Extra
+my_col decimal(65,30) NO 0.000000000000000000000000000000
+SELECT my_col FROM t1;
+my_col
+0.123456789123456789123456789123
+DROP TABLE t1;
+CREATE TABLE t1 SELECT 1 / .123456789123456789123456789123456789123456789123456789123456789123456789123456789 AS my_col;
+Warnings:
+Note 1265 Data truncated for column 'my_col' at row 1
+DESCRIBE t1;
+Field Type Null Key Default Extra
+my_col decimal(65,4) YES NULL
+SELECT my_col FROM t1;
+my_col
+8.1000
+DROP TABLE t1;
+CREATE TABLE t1 SELECT 1 % .123456789123456789123456789123456789123456789123456789123456789123456789123456789 AS my_col;
+Warnings:
+Note 1265 Data truncated for column 'my_col' at row 1
+DESCRIBE t1;
+Field Type Null Key Default Extra
+my_col decimal(65,30) YES NULL
+SELECT my_col FROM t1;
+my_col
+0.012345687012345687012345687012
+DROP TABLE t1;
diff --git a/mysql-test/r/type_time.result b/mysql-test/r/type_time.result
index d80a3973555..e4b90196c2d 100644
--- a/mysql-test/r/type_time.result
+++ b/mysql-test/r/type_time.result
@@ -128,3 +128,13 @@ SELECT sum(f3) FROM t1 where f2='2007-07-01 00:00:00' group by f2;
sum(f3)
3
drop table t1;
+#
+# Bug #44792: valgrind warning when casting from time to time
+#
+CREATE TABLE t1 (c TIME);
+INSERT INTO t1 VALUES ('0:00:00');
+SELECT CAST(c AS TIME) FROM t1;
+CAST(c AS TIME)
+00:00:00
+DROP TABLE t1;
+End of 5.0 tests
diff --git a/mysql-test/r/union.result b/mysql-test/r/union.result
index 23a7724984c..44a3812725a 100644
--- a/mysql-test/r/union.result
+++ b/mysql-test/r/union.result
@@ -1574,4 +1574,17 @@ SHOW FIELDS FROM t2;
Field Type Null Key Default Extra
d double(9,6) YES NULL
DROP TABLE t1, t2;
+CREATE TABLE t1(a INT);
+EXPLAIN EXTENDED
+SELECT a FROM t1
+UNION
+SELECT a FROM t1
+ORDER BY a;
+id select_type table type possible_keys key key_len ref rows filtered Extra
+1 PRIMARY t1 system NULL NULL NULL NULL 0 0.00 const row not found
+2 UNION t1 system NULL NULL NULL NULL 0 0.00 const row not found
+NULL UNION RESULT ALL NULL NULL NULL NULL NULL NULL Using filesort
+Warnings:
+Note 1003 select '0' AS `a` from `test`.`t1` union select '0' AS `a` from `test`.`t1` order by `a`
+DROP TABLE t1;
End of 5.0 tests
diff --git a/mysql-test/r/user_var.result b/mysql-test/r/user_var.result
index 8961a935006..28da1dae931 100644
--- a/mysql-test/r/user_var.result
+++ b/mysql-test/r/user_var.result
@@ -399,6 +399,17 @@ select @lastid != id, @lastid, @lastid := id from t1;
0 3 3
1 3 4
drop table t1;
+CREATE TABLE t1(a INT, b INT);
+INSERT INTO t1 VALUES (0, 0), (2, 1), (2, 3), (1, 1), (30, 20);
+SELECT a, b INTO @a, @b FROM t1 WHERE a=2 AND b=3 GROUP BY a, b;
+SELECT @a, @b;
+@a @b
+2 3
+SELECT a, b FROM t1 WHERE a=2 AND b=3 GROUP BY a, b;
+a b
+2 3
+DROP TABLE t1;
+End of 5.0 tests
CREATE TABLE t1 (i INT);
CREATE TRIGGER t_after_insert AFTER INSERT ON t1 FOR EACH ROW SET @bug42188 = 10;
INSERT INTO t1 VALUES (1);
diff --git a/mysql-test/r/variables.result b/mysql-test/r/variables.result
index f27d0b9fdd5..c1cd1840df8 100644
--- a/mysql-test/r/variables.result
+++ b/mysql-test/r/variables.result
@@ -1436,7 +1436,7 @@ Warnings:
Warning 1292 Truncated incorrect auto_increment_offset value: '0'
select @@storage_engine;
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
-def @@storage_engine 253 6 6 N 1 31 8
+def @@storage_engine 253 6 6 Y 0 31 8
@@storage_engine
MyISAM
SET @old_server_id = @@GLOBAL.server_id;
@@ -1467,4 +1467,24 @@ SELECT @@GLOBAL.server_id;
@@GLOBAL.server_id
0
SET GLOBAL server_id = @old_server_id;
+SELECT @@GLOBAL.INIT_FILE, @@GLOBAL.INIT_FILE IS NULL;
+@@GLOBAL.INIT_FILE @@GLOBAL.INIT_FILE IS NULL
+NULL 1
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES ();
+SET @bug42778= @@sql_safe_updates;
+SET @@sql_safe_updates= 0;
+DELETE FROM t1 ORDER BY (@@GLOBAL.INIT_FILE) ASC LIMIT 10;
+SET @@sql_safe_updates= @bug42778;
+DROP TABLE t1;
+#
+# BUG#10206 - InnoDB: Transaction requiring Max_BinLog_Cache_size > 4GB always rollsback
+#
+SET @old_max_binlog_cache_size = @@GLOBAL.max_binlog_cache_size;
+# Set the max_binlog_cache_size to size more than 4GB.
+SET GLOBAL max_binlog_cache_size = 5 * 1024 * 1024 * 1024;
+SELECT @@GLOBAL.max_binlog_cache_size;
+@@GLOBAL.max_binlog_cache_size
+5368709120
+SET GLOBAL max_binlog_cache_size = @old_max_binlog_cache_size;
End of 5.1 tests
diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result
index 0905fc0109b..2dc448a29d8 100644
--- a/mysql-test/r/view.result
+++ b/mysql-test/r/view.result
@@ -3700,6 +3700,136 @@ ERROR 42000: Key 'c2' doesn't exist in table 'v1'
DROP VIEW v1;
DROP TABLE t1;
# -----------------------------------------------------------------
+# -- Bug#40825: Error 1356 while selecting from a view
+# -- with a "HAVING" clause though query works
+# -----------------------------------------------------------------
+
+CREATE TABLE t1 (c INT);
+
+CREATE VIEW v1 (view_column) AS SELECT c AS alias FROM t1 HAVING alias;
+SHOW CREATE VIEW v1;
+View Create View character_set_client collation_connection
+v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`c` AS `view_column` from `t1` having `view_column` latin1 latin1_swedish_ci
+SELECT * FROM v1;
+view_column
+
+DROP VIEW v1;
+DROP TABLE t1;
+
+# -- End of test case for Bug#40825
+
+#
+# Bug #45806 crash when replacing into a view with a join!
+#
+CREATE TABLE t1(a INT UNIQUE);
+CREATE VIEW v1 AS SELECT t1.a FROM t1, t1 AS a;
+INSERT INTO t1 VALUES (1), (2);
+REPLACE INTO v1(a) SELECT 1 FROM t1,t1 AS c;
+SELECT * FROM v1;
+a
+1
+2
+1
+2
+REPLACE INTO v1(a) SELECT 3 FROM t1,t1 AS c;
+SELECT * FROM v1;
+a
+1
+2
+3
+1
+2
+3
+1
+2
+3
+DELETE FROM t1 WHERE a=3;
+INSERT INTO v1(a) SELECT 1 FROM t1,t1 AS c
+ON DUPLICATE KEY UPDATE `v1`.`a`= 1;
+SELECT * FROM v1;
+a
+1
+2
+1
+2
+CREATE VIEW v2 AS SELECT t1.a FROM t1, v1 AS a;
+REPLACE INTO v2(a) SELECT 1 FROM t1,t1 AS c;
+SELECT * FROM v2;
+a
+1
+2
+1
+2
+1
+2
+1
+2
+REPLACE INTO v2(a) SELECT 3 FROM t1,t1 AS c;
+SELECT * FROM v2;
+a
+1
+2
+3
+1
+2
+3
+1
+2
+3
+1
+2
+3
+1
+2
+3
+1
+2
+3
+1
+2
+3
+1
+2
+3
+1
+2
+3
+INSERT INTO v2(a) SELECT 1 FROM t1,t1 AS c
+ON DUPLICATE KEY UPDATE `v2`.`a`= 1;
+SELECT * FROM v2;
+a
+1
+2
+3
+1
+2
+3
+1
+2
+3
+1
+2
+3
+1
+2
+3
+1
+2
+3
+1
+2
+3
+1
+2
+3
+1
+2
+3
+DROP VIEW v1;
+DROP VIEW v2;
+DROP TABLE t1;
+# -- End of test case for Bug#45806
+# -----------------------------------------------------------------
# -- End of 5.0 tests.
# -----------------------------------------------------------------
DROP DATABASE IF EXISTS `d-1`;
@@ -3817,6 +3947,14 @@ call p();
call p();
drop view a;
drop procedure p;
+#
+# Bug #44860: ALTER TABLE on view crashes server
+#
+CREATE TABLE t1 (a INT);
+CREATE VIEW v1 AS SELECT a FROM t1;
+ALTER TABLE v1;
+DROP VIEW v1;
+DROP TABLE t1;
# -----------------------------------------------------------------
# -- End of 5.1 tests.
# -----------------------------------------------------------------
diff --git a/mysql-test/r/xa.result b/mysql-test/r/xa.result
index 592cf07522b..a597806d897 100644
--- a/mysql-test/r/xa.result
+++ b/mysql-test/r/xa.result
@@ -75,3 +75,17 @@ xa rollback 'a','c';
xa start 'a','c';
drop table t1;
End of 5.0 tests
+xa start 'a';
+xa end 'a';
+xa rollback 'a';
+xa start 'a';
+xa end 'a';
+xa rollback 'a';
+xa start 'a';
+xa end 'a';
+xa prepare 'a';
+xa commit 'a';
+xa start 'a';
+xa end 'a';
+xa prepare 'a';
+xa commit 'a';
diff --git a/mysql-test/suite/binlog/r/binlog_database.result b/mysql-test/suite/binlog/r/binlog_database.result
index 8dbe0f21852..1cc9281f3fc 100644
--- a/mysql-test/suite/binlog/r/binlog_database.result
+++ b/mysql-test/suite/binlog/r/binlog_database.result
@@ -100,15 +100,15 @@ drop table tt1, t1;
show binlog events from ;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Query # # use `test`; create table t1 (a int)
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
-master-bin.000001 # Query # # use `test`; COMMIT
+master-bin.000001 # Query # # COMMIT
master-bin.000001 # Query # # drop database if exists mysqltest1
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
-master-bin.000001 # Query # # use `test`; COMMIT
+master-bin.000001 # Query # # COMMIT
master-bin.000001 # Query # # use `test`; DROP TABLE `t1` /* generated by server */
FLUSH STATUS;
show databases;
diff --git a/mysql-test/suite/binlog/r/binlog_incident.result b/mysql-test/suite/binlog/r/binlog_incident.result
new file mode 100644
index 00000000000..d8b0357b8c4
--- /dev/null
+++ b/mysql-test/suite/binlog/r/binlog_incident.result
@@ -0,0 +1,12 @@
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (1),(2),(3);
+SELECT * FROM t1;
+a
+1
+2
+3
+REPLACE INTO t1 VALUES (4);
+DROP TABLE t1;
+FLUSH LOGS;
+Contain RELOAD DATABASE
+1
diff --git a/mysql-test/suite/binlog/r/binlog_innodb.result b/mysql-test/suite/binlog/r/binlog_innodb.result
index 919ac33ef35..1922897f631 100644
--- a/mysql-test/suite/binlog/r/binlog_innodb.result
+++ b/mysql-test/suite/binlog/r/binlog_innodb.result
@@ -66,49 +66,49 @@ COMMIT;
show binlog events from ;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Query # # use `test`; CREATE TABLE t1 (a INT PRIMARY KEY, b INT) ENGINE=INNODB
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (1,1),(2,2),(3,3),(4,4),(5,5),(6,6)
master-bin.000001 # Xid # # COMMIT /* XID */
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Query # # use `test`; UPDATE t1 SET b = 2*a WHERE a > 1
master-bin.000001 # Xid # # COMMIT /* XID */
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Update_rows # # table_id: # flags: STMT_END_F
master-bin.000001 # Xid # # COMMIT /* XID */
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Query # # use `test`; UPDATE t1 SET b = 3*a WHERE a > 3
master-bin.000001 # Xid # # COMMIT /* XID */
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Query # # use `test`; UPDATE t1 SET b = 4*a WHERE a > 4
master-bin.000001 # Xid # # COMMIT /* XID */
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Update_rows # # table_id: # flags: STMT_END_F
master-bin.000001 # Xid # # COMMIT /* XID */
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Update_rows # # table_id: # flags: STMT_END_F
master-bin.000001 # Xid # # COMMIT /* XID */
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Query # # use `test`; UPDATE t1 SET b = 3*a WHERE a > 3
master-bin.000001 # Xid # # COMMIT /* XID */
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Query # # use `test`; UPDATE t1 SET b = 4*a WHERE a > 4
master-bin.000001 # Xid # # COMMIT /* XID */
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Update_rows # # table_id: # flags: STMT_END_F
master-bin.000001 # Xid # # COMMIT /* XID */
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Update_rows # # table_id: # flags: STMT_END_F
master-bin.000001 # Xid # # COMMIT /* XID */
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Update_rows # # table_id: # flags: STMT_END_F
master-bin.000001 # Xid # # COMMIT /* XID */
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Update_rows # # table_id: # flags: STMT_END_F
master-bin.000001 # Xid # # COMMIT /* XID */
diff --git a/mysql-test/suite/binlog/r/binlog_innodb_row.result b/mysql-test/suite/binlog/r/binlog_innodb_row.result
index fab79c4bc2f..f7415610dc5 100644
--- a/mysql-test/suite/binlog/r/binlog_innodb_row.result
+++ b/mysql-test/suite/binlog/r/binlog_innodb_row.result
@@ -9,7 +9,7 @@ commit;
*** Results of the test: the binlog must have only Write_rows events not any Update_rows ***
show binlog events from ;
Log_name Pos Event_type Server_id End_log_pos Info
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
master-bin.000001 # Xid # # COMMIT /* XID */
@@ -24,7 +24,7 @@ commit;
*** Results of the test: the binlog must have only one Write_rows event not two ***
show binlog events from ;
Log_name Pos Event_type Server_id End_log_pos Info
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
master-bin.000001 # Xid # # COMMIT /* XID */
diff --git a/mysql-test/suite/binlog/r/binlog_multi_engine.result b/mysql-test/suite/binlog/r/binlog_multi_engine.result
index caae5f55d13..9252229903b 100644
--- a/mysql-test/suite/binlog/r/binlog_multi_engine.result
+++ b/mysql-test/suite/binlog/r/binlog_multi_engine.result
@@ -17,16 +17,16 @@ TRUNCATE t1b;
TRUNCATE t1n;
show binlog events from ;
Log_name Pos Event_type Server_id End_log_pos Info
-mysqld-bin.000001 # Query # # use `test`; BEGIN
+mysqld-bin.000001 # Query # # BEGIN
mysqld-bin.000001 # Query # # use `test`; INSERT INTO t1b VALUES (1,1), (1,2), (2,1), (2,2)
-mysqld-bin.000001 # Query # # use `test`; COMMIT
+mysqld-bin.000001 # Query # # COMMIT
mysqld-bin.000001 # Query # # use `test`; INSERT INTO t1m VALUES (1,1), (1,2), (2,1), (2,2)
mysqld-bin.000001 # Query # # use `test`; UPDATE t1m, t1b SET m = 2, b = 3 WHERE n = c
-mysqld-bin.000001 # Query # # use `test`; BEGIN
+mysqld-bin.000001 # Query # # BEGIN
mysqld-bin.000001 # Query # # use `test`; INSERT INTO t1n VALUES (1,1), (1,2), (2,1), (2,2)
mysqld-bin.000001 # Query # # use `test`; UPDATE t1m, t1n SET m = 2, e = 3 WHERE n = f
mysqld-bin.000001 # Query # # use `test`; UPDATE t1n, t1b SET e = 2, b = 3 WHERE f = c
-mysqld-bin.000001 # Query # # use `test`; COMMIT
+mysqld-bin.000001 # Query # # COMMIT
mysqld-bin.000001 # Query # # BEGIN
mysqld-bin.000001 # Table_map # # table_id: # (test.t1n)
mysqld-bin.000001 # Table_map # # table_id: # (mysql.ndb_apply_status)
@@ -48,9 +48,9 @@ TRUNCATE t1b;
TRUNCATE t1n;
show binlog events from ;
Log_name Pos Event_type Server_id End_log_pos Info
-mysqld-bin.000001 # Query # # use `test`; BEGIN
+mysqld-bin.000001 # Query # # BEGIN
mysqld-bin.000001 # Query # # use `test`; INSERT INTO t1b VALUES (1,1), (1,2), (2,1), (2,2)
-mysqld-bin.000001 # Query # # use `test`; COMMIT
+mysqld-bin.000001 # Query # # COMMIT
mysqld-bin.000001 # Query # # use `test`; INSERT INTO t1m VALUES (1,1), (1,2), (2,1), (2,2)
mysqld-bin.000001 # Query # # BEGIN
mysqld-bin.000001 # Table_map # # table_id: # (test.t1n)
@@ -73,14 +73,14 @@ UPDATE t1n, t1b SET e = 2, b = 3 WHERE f = c;
ERROR HY000: Binary logging not possible. Message: Statement cannot be written atomically since more than one engine involved and at least one engine is self-logging
show binlog events from ;
Log_name Pos Event_type Server_id End_log_pos Info
-mysqld-bin.000001 # Query # # use `test`; BEGIN
+mysqld-bin.000001 # Query # # BEGIN
mysqld-bin.000001 # Table_map # # table_id: # (test.t1m)
mysqld-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
-mysqld-bin.000001 # Query # # use `test`; COMMIT
-mysqld-bin.000001 # Query # # use `test`; BEGIN
+mysqld-bin.000001 # Query # # COMMIT
+mysqld-bin.000001 # Query # # BEGIN
mysqld-bin.000001 # Table_map # # table_id: # (test.t1b)
mysqld-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
-mysqld-bin.000001 # Query # # use `test`; COMMIT
+mysqld-bin.000001 # Query # # COMMIT
mysqld-bin.000001 # Query # # BEGIN
mysqld-bin.000001 # Table_map # # table_id: # (test.t1n)
mysqld-bin.000001 # Table_map # # table_id: # (mysql.ndb_apply_status)
diff --git a/mysql-test/suite/binlog/r/binlog_row_binlog.result b/mysql-test/suite/binlog/r/binlog_row_binlog.result
index 25cb7a4726f..4baa47db129 100644
--- a/mysql-test/suite/binlog/r/binlog_row_binlog.result
+++ b/mysql-test/suite/binlog/r/binlog_row_binlog.result
@@ -12,11 +12,11 @@ show binlog events from ;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Query # # use `test`; create table t1 (a int) engine=innodb
master-bin.000001 # Query # # use `test`; create table t2 (a int) engine=innodb
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
master-bin.000001 # Xid # # COMMIT /* XID */
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Table_map # # table_id: # (test.t2)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
master-bin.000001 # Xid # # COMMIT /* XID */
@@ -29,7 +29,7 @@ drop table t1;
show binlog events in 'master-bin.000001' from 106;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Query 1 # use `test`; create table t1 (n int) engine=innodb
-master-bin.000001 # Query 1 # use `test`; BEGIN
+master-bin.000001 # Query 1 # BEGIN
master-bin.000001 # Table_map 1 # table_id: # (test.t1)
master-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F
master-bin.000001 # Table_map 1 # table_id: # (test.t1)
@@ -249,7 +249,7 @@ show binlog events from 0;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 4 Format_desc 1 106 Server version, Binlog ver: 4
master-bin.000001 106 Query 1 205 use `test`; create table t1(n int) engine=innodb
-master-bin.000001 205 Query 1 273 use `test`; BEGIN
+master-bin.000001 205 Query 1 273 BEGIN
master-bin.000001 273 Table_map 1 314 table_id: # (test.t1)
master-bin.000001 314 Write_rows 1 348 table_id: # flags: STMT_END_F
master-bin.000001 348 Table_map 1 389 table_id: # (test.t1)
@@ -266,7 +266,7 @@ show binlog events from 0;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 4 Format_desc 1 106 Server version, Binlog ver: 4
master-bin.000001 106 Query 1 206 use `test`; create table t1 (a int) engine=innodb
-master-bin.000001 206 Query 1 274 use `test`; BEGIN
+master-bin.000001 206 Query 1 274 BEGIN
master-bin.000001 274 Table_map 1 315 table_id: # (test.t1)
master-bin.000001 315 Write_rows 1 349 table_id: # flags: STMT_END_F
master-bin.000001 349 Table_map 1 390 table_id: # (test.t1)
@@ -1085,10 +1085,10 @@ show binlog events from 0;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 4 Format_desc 1 106 Server version, Binlog ver: 4
master-bin.000001 106 Query 1 227 use `test`; create table t1 (a bigint unsigned, b bigint(20) unsigned)
-master-bin.000001 227 Query 1 295 use `test`; BEGIN
+master-bin.000001 227 Query 1 295 BEGIN
master-bin.000001 295 Table_map 1 337 table_id: # (test.t1)
master-bin.000001 337 Write_rows 1 383 table_id: # flags: STMT_END_F
-master-bin.000001 383 Query 1 452 use `test`; COMMIT
+master-bin.000001 383 Query 1 452 COMMIT
master-bin.000001 452 Query 1 528 use `test`; drop table t1
reset master;
CREATE DATABASE bug39182 DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci;
@@ -1192,32 +1192,32 @@ use test;
show binlog events from ;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Query # # use `test`; create table t1 (id tinyint auto_increment primary key)
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
-master-bin.000001 # Query # # use `test`; COMMIT
+master-bin.000001 # Query # # COMMIT
master-bin.000001 # Query # # use `test`; drop table t1
master-bin.000001 # Query # # use `test`; create table t1 (a int)
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Query # # use `test`; CREATE TABLE IF NOT EXISTS `t2` (
`a` int(11) DEFAULT NULL
)
-master-bin.000001 # Query # # use `test`; COMMIT
+master-bin.000001 # Query # # COMMIT
master-bin.000001 # Query # # use `test`; CREATE TABLE IF NOT EXISTS `t3` (
`a` int(11) DEFAULT NULL
)
-master-bin.000001 # Query # # use `mysql`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Table_map # # table_id: # (mysql.user)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
-master-bin.000001 # Query # # use `mysql`; COMMIT
-master-bin.000001 # Query # # use `mysql`; BEGIN
+master-bin.000001 # Query # # COMMIT
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Table_map # # table_id: # (mysql.user)
master-bin.000001 # Update_rows # # table_id: # flags: STMT_END_F
-master-bin.000001 # Query # # use `mysql`; COMMIT
-master-bin.000001 # Query # # use `mysql`; BEGIN
+master-bin.000001 # Query # # COMMIT
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Table_map # # table_id: # (mysql.user)
master-bin.000001 # Delete_rows # # table_id: # flags: STMT_END_F
-master-bin.000001 # Query # # use `mysql`; COMMIT
+master-bin.000001 # Query # # COMMIT
drop table t1,t2,t3,tt1;
create table t1 (a int not null auto_increment, primary key (a)) engine=myisam;
insert delayed into t1 values (207);
@@ -1227,46 +1227,46 @@ FLUSH TABLES;
show binlog events from ;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Query # # use `test`; create table t1 (id tinyint auto_increment primary key)
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
-master-bin.000001 # Query # # use `test`; COMMIT
+master-bin.000001 # Query # # COMMIT
master-bin.000001 # Query # # use `test`; drop table t1
master-bin.000001 # Query # # use `test`; create table t1 (a int)
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Query # # use `test`; CREATE TABLE IF NOT EXISTS `t2` (
`a` int(11) DEFAULT NULL
)
-master-bin.000001 # Query # # use `test`; COMMIT
+master-bin.000001 # Query # # COMMIT
master-bin.000001 # Query # # use `test`; CREATE TABLE IF NOT EXISTS `t3` (
`a` int(11) DEFAULT NULL
)
-master-bin.000001 # Query # # use `mysql`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Table_map # # table_id: # (mysql.user)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
-master-bin.000001 # Query # # use `mysql`; COMMIT
-master-bin.000001 # Query # # use `mysql`; BEGIN
+master-bin.000001 # Query # # COMMIT
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Table_map # # table_id: # (mysql.user)
master-bin.000001 # Update_rows # # table_id: # flags: STMT_END_F
-master-bin.000001 # Query # # use `mysql`; COMMIT
-master-bin.000001 # Query # # use `mysql`; BEGIN
+master-bin.000001 # Query # # COMMIT
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Table_map # # table_id: # (mysql.user)
master-bin.000001 # Delete_rows # # table_id: # flags: STMT_END_F
-master-bin.000001 # Query # # use `mysql`; COMMIT
+master-bin.000001 # Query # # COMMIT
master-bin.000001 # Query # # use `test`; DROP TABLE `t1`,`t2`,`t3` /* generated by server */
master-bin.000001 # Query # # use `test`; create table t1 (a int not null auto_increment, primary key (a)) engine=myisam
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
-master-bin.000001 # Query # # use `test`; COMMIT
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # COMMIT
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
-master-bin.000001 # Query # # use `test`; COMMIT
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # COMMIT
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
-master-bin.000001 # Query # # use `test`; COMMIT
+master-bin.000001 # Query # # COMMIT
master-bin.000001 # Query # # use `test`; FLUSH TABLES
insert delayed into t1 values (null),(null),(null),(null);
insert delayed into t1 values (null),(null),(400),(null);
diff --git a/mysql-test/suite/binlog/r/binlog_row_ctype_ucs.result b/mysql-test/suite/binlog/r/binlog_row_ctype_ucs.result
index 49aa64adfb5..8daed8d5c25 100644
--- a/mysql-test/suite/binlog/r/binlog_row_ctype_ucs.result
+++ b/mysql-test/suite/binlog/r/binlog_row_ctype_ucs.result
@@ -5,16 +5,15 @@ reset master;
insert into t2 values (@v);
show binlog events from ;
Log_name Pos Event_type Server_id End_log_pos Info
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Table_map # # table_id: # (test.t2)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
-master-bin.000001 # Query # # use `test`; COMMIT
+master-bin.000001 # Query # # COMMIT
flush logs;
/*!40019 SET @@session.max_insert_delayed_threads=0*/;
/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
DELIMITER /*!*/;
ROLLBACK/*!*/;
-use test/*!*/;
SET TIMESTAMP=10000/*!*/;
SET @@session.pseudo_thread_id=999999999/*!*/;
SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1, @@session.autocommit=1/*!*/;
diff --git a/mysql-test/suite/binlog/r/binlog_row_insert_select.result b/mysql-test/suite/binlog/r/binlog_row_insert_select.result
index d4370c4de12..c7386b092e4 100644
--- a/mysql-test/suite/binlog/r/binlog_row_insert_select.result
+++ b/mysql-test/suite/binlog/r/binlog_row_insert_select.result
@@ -8,10 +8,10 @@ insert into t1 select * from t2;
ERROR 23000: Duplicate entry '2' for key 'a'
show binlog events from ;
Log_name Pos Event_type Server_id End_log_pos Info
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
-master-bin.000001 # Query # # use `test`; ROLLBACK
+master-bin.000001 # Query # # ROLLBACK
select * from t1;
a
1
diff --git a/mysql-test/suite/binlog/r/binlog_row_mix_innodb_myisam.result b/mysql-test/suite/binlog/r/binlog_row_mix_innodb_myisam.result
index 4f3bc57e576..4d639c3da68 100644
--- a/mysql-test/suite/binlog/r/binlog_row_mix_innodb_myisam.result
+++ b/mysql-test/suite/binlog/r/binlog_row_mix_innodb_myisam.result
@@ -8,7 +8,7 @@ insert into t2 select * from t1;
commit;
show binlog events from ;
Log_name Pos Event_type Server_id End_log_pos Info
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
master-bin.000001 # Table_map # # table_id: # (test.t2)
@@ -25,12 +25,12 @@ Warnings:
Warning 1196 Some non-transactional changed tables couldn't be rolled back
show binlog events from ;
Log_name Pos Event_type Server_id End_log_pos Info
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
master-bin.000001 # Table_map # # table_id: # (test.t2)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
-master-bin.000001 # Query # # use `test`; ROLLBACK
+master-bin.000001 # Query # # ROLLBACK
delete from t1;
delete from t2;
reset master;
@@ -45,7 +45,7 @@ Warning 1196 Some non-transactional changed tables couldn't be rolled back
commit;
show binlog events from ;
Log_name Pos Event_type Server_id End_log_pos Info
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
master-bin.000001 # Query # # use `test`; savepoint my_savepoint
@@ -74,7 +74,7 @@ a
7
show binlog events from ;
Log_name Pos Event_type Server_id End_log_pos Info
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
master-bin.000001 # Query # # use `test`; savepoint my_savepoint
@@ -100,12 +100,12 @@ get_lock("a",10)
1
show binlog events from ;
Log_name Pos Event_type Server_id End_log_pos Info
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
master-bin.000001 # Table_map # # table_id: # (test.t2)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
-master-bin.000001 # Query # # use `test`; ROLLBACK
+master-bin.000001 # Query # # ROLLBACK
delete from t1;
delete from t2;
reset master;
@@ -113,14 +113,14 @@ insert into t1 values(9);
insert into t2 select * from t1;
show binlog events from ;
Log_name Pos Event_type Server_id End_log_pos Info
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
master-bin.000001 # Xid # # COMMIT /* XID */
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Table_map # # table_id: # (test.t2)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
-master-bin.000001 # Query # # use `test`; COMMIT
+master-bin.000001 # Query # # COMMIT
delete from t1;
delete from t2;
reset master;
@@ -129,7 +129,7 @@ begin;
insert into t2 select * from t1;
show binlog events from ;
Log_name Pos Event_type Server_id End_log_pos Info
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
master-bin.000001 # Xid # # COMMIT /* XID */
@@ -137,11 +137,11 @@ insert into t1 values(11);
commit;
show binlog events from ;
Log_name Pos Event_type Server_id End_log_pos Info
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
master-bin.000001 # Xid # # COMMIT /* XID */
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Table_map # # table_id: # (test.t2)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
master-bin.000001 # Table_map # # table_id: # (test.t1)
@@ -157,7 +157,7 @@ insert into t2 select * from t1;
commit;
show binlog events from ;
Log_name Pos Event_type Server_id End_log_pos Info
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
master-bin.000001 # Table_map # # table_id: # (test.t2)
@@ -184,7 +184,7 @@ rollback to savepoint my_savepoint;
commit;
show binlog events from ;
Log_name Pos Event_type Server_id End_log_pos Info
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
master-bin.000001 # Xid # # COMMIT /* XID */
@@ -205,7 +205,7 @@ a
18
show binlog events from ;
Log_name Pos Event_type Server_id End_log_pos Info
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
master-bin.000001 # Table_map # # table_id: # (test.t1)
@@ -257,31 +257,31 @@ get_lock("lock1",60)
1
show binlog events from ;
Log_name Pos Event_type Server_id End_log_pos Info
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
master-bin.000001 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
master-bin.000001 # Xid # # COMMIT /* XID */
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Delete_rows # # table_id: # flags: STMT_END_F
master-bin.000001 # Xid # # COMMIT /* XID */
master-bin.000001 # Query # # use `test`; alter table t2 engine=MyISAM
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
master-bin.000001 # Xid # # COMMIT /* XID */
master-bin.000001 # Query # # use `test`; drop table t1,t2
master-bin.000001 # Query # # use `test`; create table t0 (n int)
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Table_map # # table_id: # (test.t0)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
-master-bin.000001 # Query # # use `test`; COMMIT
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # COMMIT
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Table_map # # table_id: # (test.t0)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
-master-bin.000001 # Query # # use `test`; COMMIT
+master-bin.000001 # Query # # COMMIT
master-bin.000001 # Query # # use `test`; create table t2 (n int) engine=innodb
do release_lock("lock1");
drop table t0,t2;
@@ -364,46 +364,46 @@ a b
DROP TABLE t1,t2;
show binlog events from ;
Log_name Pos Event_type Server_id End_log_pos Info
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
-master-bin.000001 # Query # # use `test`; COMMIT
+master-bin.000001 # Query # # COMMIT
master-bin.000001 # Query # # use `test`; DROP TABLE if exists t2
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
-master-bin.000001 # Query # # use `test`; ROLLBACK
+master-bin.000001 # Query # # ROLLBACK
master-bin.000001 # Query # # use `test`; DROP TABLE IF EXISTS t2
master-bin.000001 # Query # # use `test`; CREATE TABLE t2 (a int, b int, primary key (a)) engine=innodb
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
-master-bin.000001 # Query # # use `test`; COMMIT
+master-bin.000001 # Query # # COMMIT
master-bin.000001 # Query # # use `test`; TRUNCATE table t2
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
-master-bin.000001 # Query # # use `test`; COMMIT
+master-bin.000001 # Query # # COMMIT
master-bin.000001 # Query # # use `test`; DROP TABLE t2
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
master-bin.000001 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
-master-bin.000001 # Query # # use `test`; ROLLBACK
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # ROLLBACK
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
-master-bin.000001 # Query # # use `test`; COMMIT
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # COMMIT
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
-master-bin.000001 # Query # # use `test`; ROLLBACK
+master-bin.000001 # Query # # ROLLBACK
master-bin.000001 # Query # # use `test`; TRUNCATE table t2
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
-master-bin.000001 # Query # # use `test`; COMMIT
+master-bin.000001 # Query # # COMMIT
master-bin.000001 # Query # # use `test`; DROP TABLE `t1` /* generated by server */
reset master;
create table t1 (a int) engine=innodb;
@@ -447,12 +447,12 @@ count(*)
2
show binlog events from ;
Log_name Pos Event_type Server_id End_log_pos Info
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Table_map # # table_id: # (test.ti)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
master-bin.000001 # Table_map # # table_id: # (test.ti)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
-master-bin.000001 # Query # # use `test`; ROLLBACK
+master-bin.000001 # Query # # ROLLBACK
select count(*) from ti /* zero */;
count(*)
0
@@ -499,11 +499,11 @@ insert into t2 values (bug27417(2));
ERROR 23000: Duplicate entry '2' for key 'PRIMARY'
show binlog events from ;
Log_name Pos Event_type Server_id End_log_pos Info
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Table_map # # table_id: # (test.t2)
master-bin.000001 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
-master-bin.000001 # Query # # use `test`; ROLLBACK
+master-bin.000001 # Query # # ROLLBACK
/* only (!) with fixes for #23333 will show there is the query */;
select count(*) from t1 /* must be 3 */;
count(*)
@@ -518,11 +518,11 @@ count(*)
2
show binlog events from ;
Log_name Pos Event_type Server_id End_log_pos Info
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Table_map # # table_id: # (test.t2)
master-bin.000001 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
-master-bin.000001 # Query # # use `test`; COMMIT
+master-bin.000001 # Query # # COMMIT
/* the query must be in regardless of #23333 */;
select count(*) from t1 /* must be 5 */;
count(*)
@@ -544,11 +544,11 @@ insert into t2 values (bug27417(1));
ERROR 23000: Duplicate entry '1' for key 'PRIMARY'
show binlog events from ;
Log_name Pos Event_type Server_id End_log_pos Info
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Table_map # # table_id: # (test.t2)
master-bin.000001 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
-master-bin.000001 # Query # # use `test`; ROLLBACK
+master-bin.000001 # Query # # ROLLBACK
/* the output must denote there is the query */;
select count(*) from t1 /* must be 1 */;
count(*)
@@ -561,12 +561,12 @@ insert into t2 select bug27417(1) union select bug27417(2);
ERROR 23000: Duplicate entry '2' for key 'PRIMARY'
show binlog events from ;
Log_name Pos Event_type Server_id End_log_pos Info
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Table_map # # table_id: # (test.t2)
master-bin.000001 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Write_rows # # table_id: #
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
-master-bin.000001 # Query # # use `test`; ROLLBACK
+master-bin.000001 # Query # # ROLLBACK
/* the output must denote there is the query */;
select count(*) from t1 /* must be 2 */;
count(*)
@@ -578,13 +578,13 @@ update t3 set b=b+bug27417(1);
ERROR 23000: Duplicate entry '4' for key 'b'
show binlog events from ;
Log_name Pos Event_type Server_id End_log_pos Info
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Table_map # # table_id: # (test.t3)
master-bin.000001 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Write_rows # # table_id: #
master-bin.000001 # Update_rows # # table_id: #
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
-master-bin.000001 # Query # # use `test`; ROLLBACK
+master-bin.000001 # Query # # ROLLBACK
/* the output must denote there is the query */;
select count(*) from t1 /* must be 2 */;
count(*)
@@ -598,11 +598,11 @@ UPDATE t4,t3 SET t4.a=t3.a + bug27417(1) /* top level non-ta table */;
ERROR 23000: Duplicate entry '2' for key 'PRIMARY'
show binlog events from ;
Log_name Pos Event_type Server_id End_log_pos Info
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Table_map # # table_id: # (test.t4)
master-bin.000001 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
-master-bin.000001 # Query # # use `test`; ROLLBACK
+master-bin.000001 # Query # # ROLLBACK
/* the output must denote there is the query */;
select count(*) from t1 /* must be 4 */;
count(*)
@@ -631,12 +631,12 @@ delete from t2;
ERROR 23000: Duplicate entry '1' for key 'PRIMARY'
show binlog events from ;
Log_name Pos Event_type Server_id End_log_pos Info
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Table_map # # table_id: # (test.t2)
master-bin.000001 # Table_map # # table_id: # (test.t3)
master-bin.000001 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
-master-bin.000001 # Query # # use `test`; ROLLBACK
+master-bin.000001 # Query # # ROLLBACK
/* the output must denote there is the query */;
select count(*) from t1 /* must be 1 */;
count(*)
@@ -654,13 +654,13 @@ delete t2.* from t2,t5 where t2.a=t5.a + 1;
ERROR 23000: Duplicate entry '1' for key 'PRIMARY'
show binlog events from ;
Log_name Pos Event_type Server_id End_log_pos Info
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Table_map # # table_id: # (test.t2)
master-bin.000001 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Delete_rows # # table_id: #
master-bin.000001 # Write_rows # # table_id: #
master-bin.000001 # Delete_rows # # table_id: # flags: STMT_END_F
-master-bin.000001 # Query # # use `test`; ROLLBACK
+master-bin.000001 # Query # # ROLLBACK
/* the output must denote there is the query */;
select count(*) from t1 /* must be 1 */;
count(*)
@@ -679,13 +679,13 @@ count(*)
2
show binlog events from ;
Log_name Pos Event_type Server_id End_log_pos Info
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Table_map # # table_id: # (test.t4)
master-bin.000001 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Write_rows # # table_id: #
master-bin.000001 # Write_rows # # table_id: #
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
-master-bin.000001 # Query # # use `test`; ROLLBACK
+master-bin.000001 # Query # # ROLLBACK
/* the output must denote there is the query */;
drop trigger trg_del_t2;
drop table t1,t2,t3,t4,t5;
@@ -706,12 +706,12 @@ count(*)
2
show binlog events from ;
Log_name Pos Event_type Server_id End_log_pos Info
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Table_map # # table_id: # (test.ti)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
master-bin.000001 # Table_map # # table_id: # (test.ti)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
-master-bin.000001 # Query # # use `test`; ROLLBACK
+master-bin.000001 # Query # # ROLLBACK
select count(*) from ti /* zero */;
count(*)
0
@@ -795,10 +795,10 @@ insert into t2 values (bug27417(1));
ERROR 23000: Duplicate entry '1' for key 'PRIMARY'
show binlog events from ;
Log_name Pos Event_type Server_id End_log_pos Info
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Intvar # # INSERT_ID=1
master-bin.000001 # Query # # use `test`; insert into t2 values (bug27417(1))
-master-bin.000001 # Query # # use `test`; ROLLBACK
+master-bin.000001 # Query # # ROLLBACK
select count(*) from t1 /* must be 1 */;
count(*)
1
@@ -810,10 +810,10 @@ insert into t2 select bug27417(1) union select bug27417(2);
ERROR 23000: Duplicate entry '2' for key 'PRIMARY'
show binlog events from ;
Log_name Pos Event_type Server_id End_log_pos Info
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Intvar # # INSERT_ID=2
master-bin.000001 # Query # # use `test`; insert into t2 select bug27417(1) union select bug27417(2)
-master-bin.000001 # Query # # use `test`; ROLLBACK
+master-bin.000001 # Query # # ROLLBACK
select count(*) from t1 /* must be 2 */;
count(*)
2
@@ -867,10 +867,10 @@ delete from t2;
ERROR 23000: Duplicate entry '1' for key 'PRIMARY'
show binlog events from ;
Log_name Pos Event_type Server_id End_log_pos Info
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Intvar # # INSERT_ID=9
master-bin.000001 # Query # # use `test`; delete from t2
-master-bin.000001 # Query # # use `test`; ROLLBACK
+master-bin.000001 # Query # # ROLLBACK
select count(*) from t1 /* must be 1 */;
count(*)
1
@@ -887,9 +887,9 @@ delete t2.* from t2,t5 where t2.a=t5.a + 1;
ERROR 23000: Duplicate entry '1' for key 'PRIMARY'
show binlog events from ;
Log_name Pos Event_type Server_id End_log_pos Info
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Query # # use `test`; delete t2.* from t2,t5 where t2.a=t5.a + 1
-master-bin.000001 # Query # # use `test`; ROLLBACK
+master-bin.000001 # Query # # ROLLBACK
select count(*) from t1 /* must be 1 */;
count(*)
1
@@ -907,14 +907,14 @@ count(*)
2
show binlog events from ;
Log_name Pos Event_type Server_id End_log_pos Info
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Intvar # # INSERT_ID=10
master-bin.000001 # User var # # @`b`=_latin1 0x3135 COLLATE latin1_swedish_ci
master-bin.000001 # Begin_load_query # # ;file_id=#;block_len=#
master-bin.000001 # Intvar # # INSERT_ID=10
master-bin.000001 # User var # # @`b`=_latin1 0x3135 COLLATE latin1_swedish_ci
master-bin.000001 # Execute_load_query # # use `test`; load data infile '../../std_data/rpl_loaddata.dat' into table t4 (a, @b) set b= @b + bug27417(2) ;file_id=#
-master-bin.000001 # Query # # use `test`; ROLLBACK
+master-bin.000001 # Query # # ROLLBACK
drop trigger trg_del_t2;
drop table t1,t2,t3,t4,t5;
drop function bug27417;
diff --git a/mysql-test/suite/binlog/r/binlog_row_mysqlbinlog_db_filter.result b/mysql-test/suite/binlog/r/binlog_row_mysqlbinlog_db_filter.result
new file mode 100644
index 00000000000..354fd832fb3
--- /dev/null
+++ b/mysql-test/suite/binlog/r/binlog_row_mysqlbinlog_db_filter.result
@@ -0,0 +1,43 @@
+RESET MASTER;
+CREATE TABLE t1 (id int);
+CREATE TABLE t2 (id int);
+CREATE TABLE t3 (txt TEXT);
+CREATE TABLE t4 (a int) ENGINE= InnoDB;
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (2);
+INSERT INTO t2 VALUES (1);
+INSERT INTO t2 VALUES (2);
+INSERT INTO t1 VALUES (3);
+LOAD DATA INFILE 'MYSQLTEST_VARDIR/std_data/words.dat' INTO TABLE t3;
+INSERT INTO t1 VALUES (4);
+CREATE DATABASE b42941;
+use b42941;
+CREATE TABLE t1 (id int);
+CREATE TABLE t2 (id int);
+CREATE TABLE t3 (txt TEXT);
+CREATE TABLE t4 (a int) ENGINE= InnoDB;
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (2);
+INSERT INTO t2 VALUES (1);
+INSERT INTO t2 VALUES (2);
+INSERT INTO t1 VALUES (3);
+LOAD DATA INFILE 'MYSQLTEST_VARDIR/std_data/words.dat' INTO TABLE t3;
+INSERT INTO t1 VALUES (4);
+INSERT INTO test.t1 VALUES (5);
+FLUSH LOGS;
+UPDATE test.t1 t11, b42941.t1 t12 SET t11.id=10, t12.id=100;
+BEGIN;
+INSERT INTO test.t4 VALUES (1);
+INSERT INTO b42941.t4 VALUES (1);
+UPDATE test.t4 tn4, b42941.t4 tt4 SET tn4.a= 10, tt4.a= 100;
+COMMIT;
+FLUSH LOGS;
+SET @b42941_output.1= LOAD_FILE('MYSQLTEST_VARDIR/tmp/b42941-mysqlbinlog.1');
+SET @b42941_output.2= LOAD_FILE('MYSQLTEST_VARDIR/tmp/b42941-mysqlbinlog.2');
+SET @b42941_output.1= LOAD_FILE('MYSQLTEST_VARDIR/tmp/b42941-mysqlbinlog.1');
+SET @b42941_output.2= LOAD_FILE('MYSQLTEST_VARDIR/tmp/b42941-mysqlbinlog.2');
+SET @b42941_output.1= LOAD_FILE('MYSQLTEST_VARDIR/tmp/b42941-mysqlbinlog.1');
+SET @b42941_output.2= LOAD_FILE('MYSQLTEST_VARDIR/tmp/b42941-mysqlbinlog.2');
+DROP DATABASE b42941;
+use test;
+DROP TABLE t1, t2, t3, t4;
diff --git a/mysql-test/suite/binlog/r/binlog_stm_binlog.result b/mysql-test/suite/binlog/r/binlog_stm_binlog.result
index efdeb30a2af..d151e31269f 100644
--- a/mysql-test/suite/binlog/r/binlog_stm_binlog.result
+++ b/mysql-test/suite/binlog/r/binlog_stm_binlog.result
@@ -6,7 +6,7 @@ show binlog events;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 4 Format_desc 1 106 Server ver: #, Binlog ver: #
master-bin.000001 106 Query 1 213 use `test`; create table t1 (a int, b int) engine=innodb
-master-bin.000001 213 Query 1 281 use `test`; BEGIN
+master-bin.000001 213 Query 1 281 BEGIN
master-bin.000001 281 Query 1 371 use `test`; insert into t1 values (1,2)
master-bin.000001 371 Xid 1 398 COMMIT /* XID */
drop table t1;
@@ -24,10 +24,10 @@ show binlog events from ;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Query # # use `test`; create table t1 (a int) engine=innodb
master-bin.000001 # Query # # use `test`; create table t2 (a int) engine=innodb
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Query # # use `test`; insert t1 values (5)
master-bin.000001 # Xid # # COMMIT /* XID */
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Query # # use `test`; insert t2 values (5)
master-bin.000001 # Xid # # COMMIT /* XID */
drop table t1,t2;
@@ -39,7 +39,7 @@ drop table t1;
show binlog events in 'master-bin.000001' from 106;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Query 1 # use `test`; create table t1 (n int) engine=innodb
-master-bin.000001 # Query 1 # use `test`; BEGIN
+master-bin.000001 # Query 1 # BEGIN
master-bin.000001 # Query 1 # use `test`; insert into t1 values(100 + 4)
master-bin.000001 # Query 1 # use `test`; insert into t1 values(99 + 4)
master-bin.000001 # Query 1 # use `test`; insert into t1 values(98 + 4)
@@ -159,7 +159,7 @@ show binlog events from 0;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 4 Format_desc 1 106 Server version, Binlog ver: 4
master-bin.000001 106 Query 1 205 use `test`; create table t1(n int) engine=innodb
-master-bin.000001 205 Query 1 273 use `test`; BEGIN
+master-bin.000001 205 Query 1 273 BEGIN
master-bin.000001 273 Query 1 361 use `test`; insert into t1 values (1)
master-bin.000001 361 Query 1 449 use `test`; insert into t1 values (2)
master-bin.000001 449 Query 1 537 use `test`; insert into t1 values (3)
@@ -173,7 +173,7 @@ show binlog events from 0;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 4 Format_desc 1 106 Server version, Binlog ver: 4
master-bin.000001 106 Query 1 206 use `test`; create table t1 (a int) engine=innodb
-master-bin.000001 206 Query 1 274 use `test`; BEGIN
+master-bin.000001 206 Query 1 274 BEGIN
master-bin.000001 274 Query 1 365 use `test`; insert into t1 values( 400 )
master-bin.000001 365 Query 1 456 use `test`; insert into t1 values( 399 )
master-bin.000001 456 Query 1 547 use `test`; insert into t1 values( 398 )
@@ -730,18 +730,18 @@ master-bin.000001 # Query # # use `mysql`; UPDATE user SET password=password('An
master-bin.000001 # Query # # use `mysql`; DELETE FROM user WHERE host='localhost' AND user='@#@'
master-bin.000001 # Query # # use `test`; drop table t1,t2,t3,tt1
master-bin.000001 # Query # # use `test`; create table t1 (a int not null auto_increment, primary key (a)) engine=myisam
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
-master-bin.000001 # Query # # use `test`; COMMIT
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # COMMIT
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
-master-bin.000001 # Query # # use `test`; COMMIT
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # COMMIT
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
-master-bin.000001 # Query # # use `test`; COMMIT
+master-bin.000001 # Query # # COMMIT
master-bin.000001 # Query # # use `test`; FLUSH TABLES
insert delayed into t1 values (null),(null),(null),(null);
insert delayed into t1 values (null),(null),(400),(null);
diff --git a/mysql-test/suite/binlog/r/binlog_stm_blackhole.result b/mysql-test/suite/binlog/r/binlog_stm_blackhole.result
index 1cd77cfbed4..f3a01f66fc2 100644
--- a/mysql-test/suite/binlog/r/binlog_stm_blackhole.result
+++ b/mysql-test/suite/binlog/r/binlog_stm_blackhole.result
@@ -109,35 +109,35 @@ Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Format_desc # # Server ver: VERSION, Binlog ver: 4
master-bin.000001 # Query # # use `test`; drop table t1,t2
master-bin.000001 # Query # # use `test`; create table t1 (a int) engine=blackhole
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Query # # use `test`; delete from t1 where a=10
-master-bin.000001 # Query # # use `test`; COMMIT
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # COMMIT
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Query # # use `test`; update t1 set a=11 where a=15
-master-bin.000001 # Query # # use `test`; COMMIT
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # COMMIT
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Query # # use `test`; insert into t1 values(1)
-master-bin.000001 # Query # # use `test`; COMMIT
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # COMMIT
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Query # # use `test`; insert ignore into t1 values(1)
-master-bin.000001 # Query # # use `test`; COMMIT
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # COMMIT
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Query # # use `test`; replace into t1 values(100)
-master-bin.000001 # Query # # use `test`; COMMIT
+master-bin.000001 # Query # # COMMIT
master-bin.000001 # Query # # use `test`; create table t2 (a varchar(200)) engine=blackhole
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Begin_load_query # # ;file_id=#;block_len=581
master-bin.000001 # Execute_load_query # # use `test`; load data infile '../../std_data/words.dat' into table t2 ;file_id=#
-master-bin.000001 # Query # # use `test`; COMMIT
+master-bin.000001 # Query # # COMMIT
master-bin.000001 # Query # # use `test`; alter table t1 add b int
master-bin.000001 # Query # # use `test`; alter table t1 drop b
master-bin.000001 # Query # # use `test`; create table t3 like t1
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Query # # use `test`; insert into t1 select * from t3
-master-bin.000001 # Query # # use `test`; COMMIT
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # COMMIT
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Query # # use `test`; replace into t1 select * from t3
-master-bin.000001 # Query # # use `test`; COMMIT
+master-bin.000001 # Query # # COMMIT
drop table t1,t2,t3;
CREATE TABLE t1(a INT) ENGINE=BLACKHOLE;
INSERT DELAYED INTO t1 VALUES(1);
@@ -167,9 +167,9 @@ show binlog events;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Format_desc # # Server ver: VERSION, Binlog ver: 4
master-bin.000001 # Query # # use `test`; create table t1 (a int) engine=blackhole
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Query # # use `test`; insert into t1 values(1)
-master-bin.000001 # Query # # use `test`; COMMIT
+master-bin.000001 # Query # # COMMIT
drop table if exists t1;
reset master;
create table t1 (a int auto_increment, primary key (a)) engine=blackhole;
@@ -181,16 +181,16 @@ insert into t1 values (55), (NULL);
show binlog events from ;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Query 1 # use `test`; create table t1 (a int auto_increment, primary key (a)) engine=blackhole
-master-bin.000001 # Query 1 # use `test`; BEGIN
+master-bin.000001 # Query 1 # BEGIN
master-bin.000001 # Intvar 1 # INSERT_ID=1
master-bin.000001 # Query 1 # use `test`; insert into t1 values (11), (NULL), (NULL), (NULL)
-master-bin.000001 # Query 1 # use `test`; COMMIT
-master-bin.000001 # Query 1 # use `test`; BEGIN
+master-bin.000001 # Query 1 # COMMIT
+master-bin.000001 # Query 1 # BEGIN
master-bin.000001 # Intvar 1 # INSERT_ID=3
master-bin.000001 # Query 1 # use `test`; insert into t1 values (NULL), (33), (NULL)
-master-bin.000001 # Query 1 # use `test`; COMMIT
-master-bin.000001 # Query 1 # use `test`; BEGIN
+master-bin.000001 # Query 1 # COMMIT
+master-bin.000001 # Query 1 # BEGIN
master-bin.000001 # Intvar 1 # INSERT_ID=5
master-bin.000001 # Query 1 # use `test`; insert into t1 values (55), (NULL)
-master-bin.000001 # Query 1 # use `test`; COMMIT
+master-bin.000001 # Query 1 # COMMIT
drop table t1;
diff --git a/mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result b/mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result
index 38488c9331d..95773a247b9 100644
--- a/mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result
+++ b/mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result
@@ -8,7 +8,7 @@ insert into t2 select * from t1;
commit;
show binlog events from ;
Log_name Pos Event_type Server_id End_log_pos Info
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Query # # use `test`; insert into t1 values(1)
master-bin.000001 # Query # # use `test`; insert into t2 select * from t1
master-bin.000001 # Xid # # COMMIT /* XID */
@@ -23,10 +23,10 @@ Warnings:
Warning 1196 Some non-transactional changed tables couldn't be rolled back
show binlog events from ;
Log_name Pos Event_type Server_id End_log_pos Info
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Query # # use `test`; insert into t1 values(2)
master-bin.000001 # Query # # use `test`; insert into t2 select * from t1
-master-bin.000001 # Query # # use `test`; ROLLBACK
+master-bin.000001 # Query # # ROLLBACK
delete from t1;
delete from t2;
reset master;
@@ -41,7 +41,7 @@ Warning 1196 Some non-transactional changed tables couldn't be rolled back
commit;
show binlog events from ;
Log_name Pos Event_type Server_id End_log_pos Info
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Query # # use `test`; insert into t1 values(3)
master-bin.000001 # Query # # use `test`; savepoint my_savepoint
master-bin.000001 # Query # # use `test`; insert into t1 values(4)
@@ -67,7 +67,7 @@ a
7
show binlog events from ;
Log_name Pos Event_type Server_id End_log_pos Info
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Query # # use `test`; insert into t1 values(5)
master-bin.000001 # Query # # use `test`; savepoint my_savepoint
master-bin.000001 # Query # # use `test`; insert into t1 values(6)
@@ -89,10 +89,10 @@ get_lock("a",10)
1
show binlog events from ;
Log_name Pos Event_type Server_id End_log_pos Info
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Query # # use `test`; insert into t1 values(8)
master-bin.000001 # Query # # use `test`; insert into t2 select * from t1
-master-bin.000001 # Query # # use `test`; ROLLBACK
+master-bin.000001 # Query # # ROLLBACK
delete from t1;
delete from t2;
reset master;
@@ -100,7 +100,7 @@ insert into t1 values(9);
insert into t2 select * from t1;
show binlog events from ;
Log_name Pos Event_type Server_id End_log_pos Info
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Query # # use `test`; insert into t1 values(9)
master-bin.000001 # Xid # # COMMIT /* XID */
master-bin.000001 # Query # # use `test`; insert into t2 select * from t1
@@ -112,7 +112,7 @@ begin;
insert into t2 select * from t1;
show binlog events from ;
Log_name Pos Event_type Server_id End_log_pos Info
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Query # # use `test`; insert into t1 values(10)
master-bin.000001 # Xid # # COMMIT /* XID */
master-bin.000001 # Query # # use `test`; insert into t2 select * from t1
@@ -120,11 +120,11 @@ insert into t1 values(11);
commit;
show binlog events from ;
Log_name Pos Event_type Server_id End_log_pos Info
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Query # # use `test`; insert into t1 values(10)
master-bin.000001 # Xid # # COMMIT /* XID */
master-bin.000001 # Query # # use `test`; insert into t2 select * from t1
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Query # # use `test`; insert into t1 values(11)
master-bin.000001 # Xid # # COMMIT /* XID */
alter table t2 engine=INNODB;
@@ -137,7 +137,7 @@ insert into t2 select * from t1;
commit;
show binlog events from ;
Log_name Pos Event_type Server_id End_log_pos Info
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Query # # use `test`; insert into t1 values(12)
master-bin.000001 # Query # # use `test`; insert into t2 select * from t1
master-bin.000001 # Xid # # COMMIT /* XID */
@@ -162,7 +162,7 @@ rollback to savepoint my_savepoint;
commit;
show binlog events from ;
Log_name Pos Event_type Server_id End_log_pos Info
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Query # # use `test`; insert into t1 values(14)
master-bin.000001 # Xid # # COMMIT /* XID */
delete from t1;
@@ -182,7 +182,7 @@ a
18
show binlog events from ;
Log_name Pos Event_type Server_id End_log_pos Info
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Query # # use `test`; insert into t1 values(16)
master-bin.000001 # Query # # use `test`; insert into t1 values(18)
master-bin.000001 # Xid # # COMMIT /* XID */
@@ -232,26 +232,26 @@ get_lock("lock1",60)
1
show binlog events from ;
Log_name Pos Event_type Server_id End_log_pos Info
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Query # # use `test`; insert into t1 values(16)
master-bin.000001 # Query # # use `test`; insert into t1 values(18)
master-bin.000001 # Xid # # COMMIT /* XID */
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Query # # use `test`; delete from t1
master-bin.000001 # Xid # # COMMIT /* XID */
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Query # # use `test`; delete from t2
master-bin.000001 # Xid # # COMMIT /* XID */
master-bin.000001 # Query # # use `test`; alter table t2 engine=MyISAM
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Query # # use `test`; insert into t1 values (1)
master-bin.000001 # Xid # # COMMIT /* XID */
master-bin.000001 # Query # # use `test`; insert into t2 values (20)
master-bin.000001 # Query # # use `test`; drop table t1,t2
master-bin.000001 # Query # # use `test`; create temporary table ti (a int) engine=innodb
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Query # # use `test`; insert into ti values(1)
-master-bin.000001 # Query # # use `test`; COMMIT
+master-bin.000001 # Query # # COMMIT
master-bin.000001 # Query # # use `test`; create temporary table t1 (a int) engine=myisam
master-bin.000001 # Query # # use `test`; insert t1 values (1)
master-bin.000001 # Query # # use `test`; create table t0 (n int)
@@ -356,9 +356,9 @@ master-bin.000001 # Query # # use `test`; INSERT INTO t1 values (8,8)
master-bin.000001 # Query # # use `test`; INSERT INTO t1 values (9,9)
master-bin.000001 # Query # # use `test`; TRUNCATE table t2
master-bin.000001 # Query # # use `test`; INSERT INTO t1 values (10,10)
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Query # # use `test`; INSERT INTO t2 values (100,100)
-master-bin.000001 # Query # # use `test`; COMMIT
+master-bin.000001 # Query # # COMMIT
master-bin.000001 # Query # # use `test`; DROP TABLE t1,t2
reset master;
create table t1 (a int) engine=innodb;
@@ -402,11 +402,11 @@ count(*)
2
show binlog events from ;
Log_name Pos Event_type Server_id End_log_pos Info
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Query # # use `test`; insert into ti values (1)
master-bin.000001 # Query # # use `test`; insert into ti values (2)
master-bin.000001 # Query # # use `test`; insert into tt select * from ti
-master-bin.000001 # Query # # use `test`; ROLLBACK
+master-bin.000001 # Query # # ROLLBACK
select count(*) from ti /* zero */;
count(*)
0
@@ -428,11 +428,11 @@ Warnings:
Warning 1196 Some non-transactional changed tables couldn't be rolled back
show binlog events from ;
Log_name Pos Event_type Server_id End_log_pos Info
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Query # # use `test`; insert into ti values (1)
master-bin.000001 # Query # # use `test`; insert into ti values (2) /* to make the dup error in the following */
master-bin.000001 # Query # # use `test`; insert into tt select * from ti /* one affected and error */
-master-bin.000001 # Query # # use `test`; ROLLBACK
+master-bin.000001 # Query # # ROLLBACK
select count(*) from ti /* zero */;
count(*)
0
@@ -499,10 +499,10 @@ insert into t2 values (bug27417(1));
ERROR 23000: Duplicate entry '1' for key 'PRIMARY'
show binlog events from ;
Log_name Pos Event_type Server_id End_log_pos Info
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Intvar # # INSERT_ID=1
master-bin.000001 # Query # # use `test`; insert into t2 values (bug27417(1))
-master-bin.000001 # Query # # use `test`; ROLLBACK
+master-bin.000001 # Query # # ROLLBACK
/* the output must denote there is the query */;
select count(*) from t1 /* must be 1 */;
count(*)
@@ -515,10 +515,10 @@ insert into t2 select bug27417(1) union select bug27417(2);
ERROR 23000: Duplicate entry '2' for key 'PRIMARY'
show binlog events from ;
Log_name Pos Event_type Server_id End_log_pos Info
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Intvar # # INSERT_ID=2
master-bin.000001 # Query # # use `test`; insert into t2 select bug27417(1) union select bug27417(2)
-master-bin.000001 # Query # # use `test`; ROLLBACK
+master-bin.000001 # Query # # ROLLBACK
/* the output must denote there is the query */;
select count(*) from t1 /* must be 2 */;
count(*)
@@ -575,10 +575,10 @@ delete from t2;
ERROR 23000: Duplicate entry '1' for key 'PRIMARY'
show binlog events from ;
Log_name Pos Event_type Server_id End_log_pos Info
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Intvar # # INSERT_ID=9
master-bin.000001 # Query # # use `test`; delete from t2
-master-bin.000001 # Query # # use `test`; ROLLBACK
+master-bin.000001 # Query # # ROLLBACK
/* the output must denote there is the query */;
select count(*) from t1 /* must be 1 */;
count(*)
@@ -596,9 +596,9 @@ delete t2.* from t2,t5 where t2.a=t5.a + 1;
ERROR 23000: Duplicate entry '1' for key 'PRIMARY'
show binlog events from ;
Log_name Pos Event_type Server_id End_log_pos Info
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Query # # use `test`; delete t2.* from t2,t5 where t2.a=t5.a + 1
-master-bin.000001 # Query # # use `test`; ROLLBACK
+master-bin.000001 # Query # # ROLLBACK
/* the output must denote there is the query */;
select count(*) from t1 /* must be 1 */;
count(*)
@@ -617,12 +617,12 @@ count(*)
2
show binlog events from ;
Log_name Pos Event_type Server_id End_log_pos Info
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Intvar # # INSERT_ID=10
master-bin.000001 # Begin_load_query # # ;file_id=#;block_len=#
master-bin.000001 # Intvar # # INSERT_ID=10
master-bin.000001 # Execute_load_query # # use `test`; load data infile '../../std_data/rpl_loaddata.dat' into table t4 (a, @b) set b= @b + bug27417(2) ;file_id=#
-master-bin.000001 # Query # # use `test`; ROLLBACK
+master-bin.000001 # Query # # ROLLBACK
/* the output must denote there is the query */;
drop trigger trg_del_t2;
drop table t1,t2,t3,t4,t5;
@@ -644,11 +644,11 @@ count(*)
2
show binlog events from ;
Log_name Pos Event_type Server_id End_log_pos Info
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Query # # use `test`; insert into ti values (1)
master-bin.000001 # Query # # use `test`; insert into ti values (2)
master-bin.000001 # Query # # use `test`; insert into tt select * from ti
-master-bin.000001 # Query # # use `test`; ROLLBACK
+master-bin.000001 # Query # # ROLLBACK
select count(*) from ti /* zero */;
count(*)
0
@@ -670,11 +670,11 @@ Warnings:
Warning 1196 Some non-transactional changed tables couldn't be rolled back
show binlog events from ;
Log_name Pos Event_type Server_id End_log_pos Info
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Query # # use `test`; insert into ti values (1)
master-bin.000001 # Query # # use `test`; insert into ti values (2) /* to make the dup error in the following */
master-bin.000001 # Query # # use `test`; insert into tt select * from ti /* one affected and error */
-master-bin.000001 # Query # # use `test`; ROLLBACK
+master-bin.000001 # Query # # ROLLBACK
select count(*) from ti /* zero */;
count(*)
0
@@ -739,10 +739,10 @@ insert into t2 values (bug27417(1));
ERROR 23000: Duplicate entry '1' for key 'PRIMARY'
show binlog events from ;
Log_name Pos Event_type Server_id End_log_pos Info
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Intvar # # INSERT_ID=1
master-bin.000001 # Query # # use `test`; insert into t2 values (bug27417(1))
-master-bin.000001 # Query # # use `test`; ROLLBACK
+master-bin.000001 # Query # # ROLLBACK
select count(*) from t1 /* must be 1 */;
count(*)
1
@@ -754,10 +754,10 @@ insert into t2 select bug27417(1) union select bug27417(2);
ERROR 23000: Duplicate entry '2' for key 'PRIMARY'
show binlog events from ;
Log_name Pos Event_type Server_id End_log_pos Info
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Intvar # # INSERT_ID=2
master-bin.000001 # Query # # use `test`; insert into t2 select bug27417(1) union select bug27417(2)
-master-bin.000001 # Query # # use `test`; ROLLBACK
+master-bin.000001 # Query # # ROLLBACK
select count(*) from t1 /* must be 2 */;
count(*)
2
@@ -811,10 +811,10 @@ delete from t2;
ERROR 23000: Duplicate entry '1' for key 'PRIMARY'
show binlog events from ;
Log_name Pos Event_type Server_id End_log_pos Info
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Intvar # # INSERT_ID=9
master-bin.000001 # Query # # use `test`; delete from t2
-master-bin.000001 # Query # # use `test`; ROLLBACK
+master-bin.000001 # Query # # ROLLBACK
select count(*) from t1 /* must be 1 */;
count(*)
1
@@ -831,9 +831,9 @@ delete t2.* from t2,t5 where t2.a=t5.a + 1;
ERROR 23000: Duplicate entry '1' for key 'PRIMARY'
show binlog events from ;
Log_name Pos Event_type Server_id End_log_pos Info
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Query # # use `test`; delete t2.* from t2,t5 where t2.a=t5.a + 1
-master-bin.000001 # Query # # use `test`; ROLLBACK
+master-bin.000001 # Query # # ROLLBACK
select count(*) from t1 /* must be 1 */;
count(*)
1
@@ -851,14 +851,14 @@ count(*)
2
show binlog events from ;
Log_name Pos Event_type Server_id End_log_pos Info
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Intvar # # INSERT_ID=10
master-bin.000001 # User var # # @`b`=_latin1 0x3135 COLLATE latin1_swedish_ci
master-bin.000001 # Begin_load_query # # ;file_id=#;block_len=#
master-bin.000001 # Intvar # # INSERT_ID=10
master-bin.000001 # User var # # @`b`=_latin1 0x3135 COLLATE latin1_swedish_ci
master-bin.000001 # Execute_load_query # # use `test`; load data infile '../../std_data/rpl_loaddata.dat' into table t4 (a, @b) set b= @b + bug27417(2) ;file_id=#
-master-bin.000001 # Query # # use `test`; ROLLBACK
+master-bin.000001 # Query # # ROLLBACK
drop trigger trg_del_t2;
drop table t1,t2,t3,t4,t5;
drop function bug27417;
diff --git a/mysql-test/suite/binlog/r/binlog_stm_ps.result b/mysql-test/suite/binlog/r/binlog_stm_ps.result
index ea7cc6f16df..3af525e297c 100644
--- a/mysql-test/suite/binlog/r/binlog_stm_ps.result
+++ b/mysql-test/suite/binlog/r/binlog_stm_ps.result
@@ -11,7 +11,7 @@ prepare s from "insert into t1 select 100 limit ?";
set @a=100;
execute s using @a;
Warnings:
-Note 1592 Statement is not safe to log in statement format.
+Note 1592 Statement may not be safe to log in statement format.
show binlog events from ;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Query # # use `test`; create table t1 (a int)
diff --git a/mysql-test/suite/binlog/r/binlog_stm_row.result b/mysql-test/suite/binlog/r/binlog_stm_row.result
index d1cc55f03b3..f96073a2b92 100644
--- a/mysql-test/suite/binlog/r/binlog_stm_row.result
+++ b/mysql-test/suite/binlog/r/binlog_stm_row.result
@@ -65,10 +65,10 @@ master-bin.000001 # Query # # use `test`; INSERT INTO t2 VALUES(2)
master-bin.000001 # Query # # use `test`; INSERT INTO t1 SELECT * FROM t2 WHERE GET_LOCK('Bug#34306', 120)
master-bin.000001 # Query # # use `test`; INSERT INTO t2 VALUES (3)
master-bin.000001 # Query # # use `test`; INSERT INTO t2 VALUES (4)
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
-master-bin.000001 # Query # # use `test`; COMMIT
+master-bin.000001 # Query # # COMMIT
DROP TABLE t1;
DROP TABLE t2;
SET GLOBAL BINLOG_FORMAT = @saved_global_binlog_format;
diff --git a/mysql-test/suite/binlog/r/binlog_stm_unsafe_warning.result b/mysql-test/suite/binlog/r/binlog_stm_unsafe_warning.result
new file mode 100644
index 00000000000..439bff0cfe1
--- /dev/null
+++ b/mysql-test/suite/binlog/r/binlog_stm_unsafe_warning.result
@@ -0,0 +1,30 @@
+### NOT filtered database => assertion: warnings ARE shown
+DROP TABLE IF EXISTS t1;
+CREATE TABLE t1 (a int, b int, primary key (a));
+INSERT INTO t1 VALUES (1,2), (2,3);
+UPDATE t1 SET b='4' WHERE a=1 LIMIT 1;
+Warnings:
+Note 1592 Statement may not be safe to log in statement format.
+UPDATE t1 SET b='5' WHERE a=2 ORDER BY a LIMIT 1;
+Warnings:
+Note 1592 Statement may not be safe to log in statement format.
+DROP TABLE t1;
+### NOT filtered database => assertion: binlog disabled and warnings ARE NOT shown
+SET SQL_LOG_BIN= 0;
+DROP TABLE IF EXISTS t1;
+CREATE TABLE t1 (a int, b int, primary key (a));
+INSERT INTO t1 VALUES (1,2), (2,3);
+UPDATE t1 SET b='4' WHERE a=1 LIMIT 1;
+UPDATE t1 SET b='5' WHERE a=2 ORDER BY a LIMIT 1;
+DROP TABLE t1;
+SET SQL_LOG_BIN= 1;
+### FILTERED database => assertion: warnings ARE NOT shown
+CREATE DATABASE b42851;
+USE b42851;
+DROP TABLE IF EXISTS t1;
+CREATE TABLE t1 (a int, b int, primary key (a));
+INSERT INTO t1 VALUES (1,2), (2,3);
+UPDATE t1 SET b='4' WHERE a=1 LIMIT 1;
+UPDATE t1 SET b='5' WHERE a=2 ORDER BY a LIMIT 1;
+DROP TABLE t1;
+DROP DATABASE b42851;
diff --git a/mysql-test/suite/binlog/r/binlog_tbl_metadata.result b/mysql-test/suite/binlog/r/binlog_tbl_metadata.result
new file mode 100644
index 00000000000..a2f185edc85
--- /dev/null
+++ b/mysql-test/suite/binlog/r/binlog_tbl_metadata.result
@@ -0,0 +1,156 @@
+RESET MASTER;
+DROP TABLE IF EXISTS `t1`;
+CREATE TABLE `t1` (
+`c1` int(11) NOT NULL AUTO_INCREMENT,
+`c2` varchar(30) NOT NULL,
+`c3` varchar(30) DEFAULT NULL,
+`c4` varchar(30) DEFAULT NULL,
+`c5` varchar(30) DEFAULT NULL,
+`c6` varchar(30) DEFAULT NULL,
+`c7` varchar(30) DEFAULT NULL,
+`c8` varchar(30) DEFAULT NULL,
+`c9` varchar(30) DEFAULT NULL,
+`c10` varchar(30) DEFAULT NULL,
+`c11` varchar(30) DEFAULT NULL,
+`c12` varchar(30) DEFAULT NULL,
+`c13` varchar(30) DEFAULT NULL,
+`c14` varchar(30) DEFAULT NULL,
+`c15` varchar(30) DEFAULT NULL,
+`c16` varchar(30) DEFAULT NULL,
+`c17` varchar(30) DEFAULT NULL,
+`c18` varchar(30) DEFAULT NULL,
+`c19` varchar(30) DEFAULT NULL,
+`c20` varchar(30) DEFAULT NULL,
+`c21` varchar(30) DEFAULT NULL,
+`c22` varchar(30) DEFAULT NULL,
+`c23` varchar(30) DEFAULT NULL,
+`c24` varchar(30) DEFAULT NULL,
+`c25` varchar(30) DEFAULT NULL,
+`c26` varchar(30) DEFAULT NULL,
+`c27` varchar(30) DEFAULT NULL,
+`c28` varchar(30) DEFAULT NULL,
+`c29` varchar(30) DEFAULT NULL,
+`c30` varchar(30) DEFAULT NULL,
+`c31` varchar(30) DEFAULT NULL,
+`c32` varchar(30) DEFAULT NULL,
+`c33` varchar(30) DEFAULT NULL,
+`c34` varchar(30) DEFAULT NULL,
+`c35` varchar(30) DEFAULT NULL,
+`c36` varchar(30) DEFAULT NULL,
+`c37` varchar(30) DEFAULT NULL,
+`c38` varchar(30) DEFAULT NULL,
+`c39` varchar(30) DEFAULT NULL,
+`c40` varchar(30) DEFAULT NULL,
+`c41` varchar(30) DEFAULT NULL,
+`c42` varchar(30) DEFAULT NULL,
+`c43` varchar(30) DEFAULT NULL,
+`c44` varchar(30) DEFAULT NULL,
+`c45` varchar(30) DEFAULT NULL,
+`c46` varchar(30) DEFAULT NULL,
+`c47` varchar(30) DEFAULT NULL,
+`c48` varchar(30) DEFAULT NULL,
+`c49` varchar(30) DEFAULT NULL,
+`c50` varchar(30) DEFAULT NULL,
+`c51` varchar(30) DEFAULT NULL,
+`c52` varchar(30) DEFAULT NULL,
+`c53` varchar(30) DEFAULT NULL,
+`c54` varchar(30) DEFAULT NULL,
+`c55` varchar(30) DEFAULT NULL,
+`c56` varchar(30) DEFAULT NULL,
+`c57` varchar(30) DEFAULT NULL,
+`c58` varchar(30) DEFAULT NULL,
+`c59` varchar(30) DEFAULT NULL,
+`c60` varchar(30) DEFAULT NULL,
+`c61` varchar(30) DEFAULT NULL,
+`c62` varchar(30) DEFAULT NULL,
+`c63` varchar(30) DEFAULT NULL,
+`c64` varchar(30) DEFAULT NULL,
+`c65` varchar(30) DEFAULT NULL,
+`c66` varchar(30) DEFAULT NULL,
+`c67` varchar(30) DEFAULT NULL,
+`c68` varchar(30) DEFAULT NULL,
+`c69` varchar(30) DEFAULT NULL,
+`c70` varchar(30) DEFAULT NULL,
+`c71` varchar(30) DEFAULT NULL,
+`c72` varchar(30) DEFAULT NULL,
+`c73` varchar(30) DEFAULT NULL,
+`c74` varchar(30) DEFAULT NULL,
+`c75` varchar(30) DEFAULT NULL,
+`c76` varchar(30) DEFAULT NULL,
+`c77` varchar(30) DEFAULT NULL,
+`c78` varchar(30) DEFAULT NULL,
+`c79` varchar(30) DEFAULT NULL,
+`c80` varchar(30) DEFAULT NULL,
+`c81` varchar(30) DEFAULT NULL,
+`c82` varchar(30) DEFAULT NULL,
+`c83` varchar(30) DEFAULT NULL,
+`c84` varchar(30) DEFAULT NULL,
+`c85` varchar(30) DEFAULT NULL,
+`c86` varchar(30) DEFAULT NULL,
+`c87` varchar(30) DEFAULT NULL,
+`c88` varchar(30) DEFAULT NULL,
+`c89` varchar(30) DEFAULT NULL,
+`c90` varchar(30) DEFAULT NULL,
+`c91` varchar(30) DEFAULT NULL,
+`c92` varchar(30) DEFAULT NULL,
+`c93` varchar(30) DEFAULT NULL,
+`c94` varchar(30) DEFAULT NULL,
+`c95` varchar(30) DEFAULT NULL,
+`c96` varchar(30) DEFAULT NULL,
+`c97` varchar(30) DEFAULT NULL,
+`c98` varchar(30) DEFAULT NULL,
+`c99` varchar(30) DEFAULT NULL,
+`c100` varchar(30) DEFAULT NULL,
+`c101` varchar(30) DEFAULT NULL,
+`c102` varchar(30) DEFAULT NULL,
+`c103` varchar(30) DEFAULT NULL,
+`c104` varchar(30) DEFAULT NULL,
+`c105` varchar(30) DEFAULT NULL,
+`c106` varchar(30) DEFAULT NULL,
+`c107` varchar(30) DEFAULT NULL,
+`c108` varchar(30) DEFAULT NULL,
+`c109` varchar(30) DEFAULT NULL,
+`c110` varchar(30) DEFAULT NULL,
+`c111` varchar(30) DEFAULT NULL,
+`c112` varchar(30) DEFAULT NULL,
+`c113` varchar(30) DEFAULT NULL,
+`c114` varchar(30) DEFAULT NULL,
+`c115` varchar(30) DEFAULT NULL,
+`c116` varchar(30) DEFAULT NULL,
+`c117` varchar(30) DEFAULT NULL,
+`c118` varchar(30) DEFAULT NULL,
+`c119` varchar(30) DEFAULT NULL,
+`c120` varchar(30) DEFAULT NULL,
+`c121` varchar(30) DEFAULT NULL,
+`c122` varchar(30) DEFAULT NULL,
+`c123` varchar(30) DEFAULT NULL,
+`c124` varchar(30) DEFAULT NULL,
+`c125` varchar(30) DEFAULT NULL,
+`c126` varchar(30) DEFAULT NULL,
+`c127` varchar(30) DEFAULT NULL,
+`c128` varchar(30) DEFAULT NULL,
+`c129` varchar(30) DEFAULT NULL,
+`c130` varchar(30) DEFAULT NULL,
+`c131` varchar(30) DEFAULT NULL,
+`c132` varchar(30) DEFAULT NULL,
+`c133` varchar(30) DEFAULT NULL,
+`c134` varchar(30) DEFAULT NULL,
+`c135` varchar(30) DEFAULT NULL,
+`c136` varchar(30) DEFAULT NULL,
+`c137` varchar(30) DEFAULT NULL,
+`c138` varchar(30) DEFAULT NULL,
+`c139` varchar(30) DEFAULT NULL,
+`c140` varchar(30) DEFAULT NULL,
+`c141` varchar(30) DEFAULT NULL,
+`c142` varchar(30) DEFAULT NULL,
+`c143` varchar(30) DEFAULT NULL,
+`c144` varchar(30) DEFAULT NULL,
+`c145` varchar(30) DEFAULT NULL,
+`c146` varchar(30) DEFAULT NULL,
+PRIMARY KEY (`c1`)
+) ENGINE=InnoDB;
+LOCK TABLES `t1` WRITE;
+INSERT INTO `t1` VALUES ('1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1');
+DROP TABLE `t1`;
+FLUSH LOGS;
+=== Using mysqlbinlog to detect failure. Before the patch mysqlbinlog would find a corrupted event, thence would fail.
diff --git a/mysql-test/suite/binlog/r/binlog_unsafe.result b/mysql-test/suite/binlog/r/binlog_unsafe.result
index 675c327e9e7..4c2c32ad8f1 100644
--- a/mysql-test/suite/binlog/r/binlog_unsafe.result
+++ b/mysql-test/suite/binlog/r/binlog_unsafe.result
@@ -10,25 +10,25 @@ INSERT DELAYED INTO t1 VALUES (5);
---- Insert directly ----
INSERT INTO t1 VALUES (@@global.sync_binlog);
Warnings:
-Note 1592 Statement is not safe to log in statement format.
+Note 1592 Statement may not be safe to log in statement format.
INSERT INTO t1 VALUES (@@session.insert_id);
Warnings:
-Note 1592 Statement is not safe to log in statement format.
+Note 1592 Statement may not be safe to log in statement format.
INSERT INTO t1 VALUES (@@global.auto_increment_increment);
Warnings:
-Note 1592 Statement is not safe to log in statement format.
+Note 1592 Statement may not be safe to log in statement format.
INSERT INTO t2 SELECT UUID();
Warnings:
-Note 1592 Statement is not safe to log in statement format.
+Note 1592 Statement may not be safe to log in statement format.
INSERT INTO t2 VALUES (@@session.sql_mode);
Warnings:
-Note 1592 Statement is not safe to log in statement format.
+Note 1592 Statement may not be safe to log in statement format.
INSERT INTO t2 VALUES (@@global.init_slave);
Warnings:
-Note 1592 Statement is not safe to log in statement format.
+Note 1592 Statement may not be safe to log in statement format.
INSERT INTO t2 VALUES (@@hostname);
Warnings:
-Note 1592 Statement is not safe to log in statement format.
+Note 1592 Statement may not be safe to log in statement format.
---- Insert from stored procedure ----
CREATE PROCEDURE proc()
BEGIN
@@ -42,13 +42,13 @@ INSERT INTO t2 VALUES (@@hostname);
END|
CALL proc();
Warnings:
-Note 1592 Statement is not safe to log in statement format.
-Note 1592 Statement is not safe to log in statement format.
-Note 1592 Statement is not safe to log in statement format.
-Note 1592 Statement is not safe to log in statement format.
-Note 1592 Statement is not safe to log in statement format.
-Note 1592 Statement is not safe to log in statement format.
-Note 1592 Statement is not safe to log in statement format.
+Note 1592 Statement may not be safe to log in statement format.
+Note 1592 Statement may not be safe to log in statement format.
+Note 1592 Statement may not be safe to log in statement format.
+Note 1592 Statement may not be safe to log in statement format.
+Note 1592 Statement may not be safe to log in statement format.
+Note 1592 Statement may not be safe to log in statement format.
+Note 1592 Statement may not be safe to log in statement format.
---- Insert from stored function ----
CREATE FUNCTION func()
RETURNS INT
@@ -66,13 +66,13 @@ SELECT func();
func()
0
Warnings:
-Note 1592 Statement is not safe to log in statement format.
-Note 1592 Statement is not safe to log in statement format.
-Note 1592 Statement is not safe to log in statement format.
-Note 1592 Statement is not safe to log in statement format.
-Note 1592 Statement is not safe to log in statement format.
-Note 1592 Statement is not safe to log in statement format.
-Note 1592 Statement is not safe to log in statement format.
+Note 1592 Statement may not be safe to log in statement format.
+Note 1592 Statement may not be safe to log in statement format.
+Note 1592 Statement may not be safe to log in statement format.
+Note 1592 Statement may not be safe to log in statement format.
+Note 1592 Statement may not be safe to log in statement format.
+Note 1592 Statement may not be safe to log in statement format.
+Note 1592 Statement may not be safe to log in statement format.
---- Insert from trigger ----
CREATE TRIGGER trig
BEFORE INSERT ON trigger_table
@@ -88,14 +88,14 @@ INSERT INTO t2 VALUES (@@hostname);
END|
INSERT INTO trigger_table VALUES ('bye.');
Warnings:
-Note 1592 Statement is not safe to log in statement format.
-Note 1592 Statement is not safe to log in statement format.
-Note 1592 Statement is not safe to log in statement format.
-Note 1592 Statement is not safe to log in statement format.
-Note 1592 Statement is not safe to log in statement format.
-Note 1592 Statement is not safe to log in statement format.
-Note 1592 Statement is not safe to log in statement format.
-Note 1592 Statement is not safe to log in statement format.
+Note 1592 Statement may not be safe to log in statement format.
+Note 1592 Statement may not be safe to log in statement format.
+Note 1592 Statement may not be safe to log in statement format.
+Note 1592 Statement may not be safe to log in statement format.
+Note 1592 Statement may not be safe to log in statement format.
+Note 1592 Statement may not be safe to log in statement format.
+Note 1592 Statement may not be safe to log in statement format.
+Note 1592 Statement may not be safe to log in statement format.
---- Insert from prepared statement ----
PREPARE p1 FROM 'INSERT INTO t1 VALUES (@@global.sync_binlog)';
PREPARE p2 FROM 'INSERT INTO t1 VALUES (@@session.insert_id)';
@@ -106,25 +106,25 @@ PREPARE p6 FROM 'INSERT INTO t2 VALUES (@@global.init_slave)';
PREPARE p7 FROM 'INSERT INTO t2 VALUES (@@hostname)';
EXECUTE p1;
Warnings:
-Note 1592 Statement is not safe to log in statement format.
+Note 1592 Statement may not be safe to log in statement format.
EXECUTE p2;
Warnings:
-Note 1592 Statement is not safe to log in statement format.
+Note 1592 Statement may not be safe to log in statement format.
EXECUTE p3;
Warnings:
-Note 1592 Statement is not safe to log in statement format.
+Note 1592 Statement may not be safe to log in statement format.
EXECUTE p4;
Warnings:
-Note 1592 Statement is not safe to log in statement format.
+Note 1592 Statement may not be safe to log in statement format.
EXECUTE p5;
Warnings:
-Note 1592 Statement is not safe to log in statement format.
+Note 1592 Statement may not be safe to log in statement format.
EXECUTE p6;
Warnings:
-Note 1592 Statement is not safe to log in statement format.
+Note 1592 Statement may not be safe to log in statement format.
EXECUTE p7;
Warnings:
-Note 1592 Statement is not safe to log in statement format.
+Note 1592 Statement may not be safe to log in statement format.
---- Insert from nested call of triggers / functions / procedures ----
CREATE PROCEDURE proc1()
INSERT INTO trigger_table VALUES ('ha!')|
@@ -154,13 +154,13 @@ EXECUTE prep6;
func5()
0
Warnings:
-Note 1592 Statement is not safe to log in statement format.
-Note 1592 Statement is not safe to log in statement format.
-Note 1592 Statement is not safe to log in statement format.
-Note 1592 Statement is not safe to log in statement format.
-Note 1592 Statement is not safe to log in statement format.
-Note 1592 Statement is not safe to log in statement format.
-Note 1592 Statement is not safe to log in statement format.
+Note 1592 Statement may not be safe to log in statement format.
+Note 1592 Statement may not be safe to log in statement format.
+Note 1592 Statement may not be safe to log in statement format.
+Note 1592 Statement may not be safe to log in statement format.
+Note 1592 Statement may not be safe to log in statement format.
+Note 1592 Statement may not be safe to log in statement format.
+Note 1592 Statement may not be safe to log in statement format.
==== Variables that should *not* be unsafe ====
INSERT INTO t1 VALUES (@@session.pseudo_thread_id);
INSERT INTO t1 VALUES (@@session.pseudo_thread_id);
@@ -195,16 +195,16 @@ DROP TABLE t1, t2, t3, trigger_table, trigger_table2;
CREATE TABLE t1(a INT, b INT, KEY(a), PRIMARY KEY(b));
INSERT INTO t1 SELECT * FROM t1 LIMIT 1;
Warnings:
-Note 1592 Statement is not safe to log in statement format.
+Note 1592 Statement may not be safe to log in statement format.
REPLACE INTO t1 SELECT * FROM t1 LIMIT 1;
Warnings:
-Note 1592 Statement is not safe to log in statement format.
+Note 1592 Statement may not be safe to log in statement format.
UPDATE t1 SET a=1 LIMIT 1;
Warnings:
-Note 1592 Statement is not safe to log in statement format.
+Note 1592 Statement may not be safe to log in statement format.
DELETE FROM t1 LIMIT 1;
Warnings:
-Note 1592 Statement is not safe to log in statement format.
+Note 1592 Statement may not be safe to log in statement format.
CREATE PROCEDURE p1()
BEGIN
INSERT INTO t1 SELECT * FROM t1 LIMIT 1;
@@ -214,10 +214,10 @@ DELETE FROM t1 LIMIT 1;
END|
CALL p1();
Warnings:
-Note 1592 Statement is not safe to log in statement format.
-Note 1592 Statement is not safe to log in statement format.
-Note 1592 Statement is not safe to log in statement format.
-Note 1592 Statement is not safe to log in statement format.
+Note 1592 Statement may not be safe to log in statement format.
+Note 1592 Statement may not be safe to log in statement format.
+Note 1592 Statement may not be safe to log in statement format.
+Note 1592 Statement may not be safe to log in statement format.
DROP PROCEDURE p1;
DROP TABLE t1;
DROP TABLE IF EXISTS t1;
@@ -225,16 +225,16 @@ CREATE TABLE t1 (a VARCHAR(100), b VARCHAR(100));
INSERT INTO t1 VALUES ('a','b');
UPDATE t1 SET b = '%s%s%s%s%s%s%s%s%s%s%s%s%s%s' WHERE a = 'a' LIMIT 1;
Warnings:
-Note 1592 Statement is not safe to log in statement format.
+Note 1592 Statement may not be safe to log in statement format.
DROP TABLE t1;
DROP TABLE IF EXISTS t1, t2;
CREATE TABLE t1(i INT PRIMARY KEY);
CREATE TABLE t2(i INT PRIMARY KEY);
CREATE TABLE t3(i INT, ch CHAR(50));
-"Should issue message Statement is not safe to log in statement format."
+"Should issue message Statement may not be safe to log in statement format."
INSERT INTO t1 SELECT * FROM t2 LIMIT 1;
Warnings:
-Note 1592 Statement is not safe to log in statement format.
+Note 1592 Statement may not be safe to log in statement format.
CREATE FUNCTION func6()
RETURNS INT
BEGIN
@@ -243,10 +243,10 @@ INSERT INTO t1 VALUES (11);
INSERT INTO t1 VALUES (12);
RETURN 0;
END|
-"Should issue message Statement is not safe to log in statement format only once"
+"Should issue message Statement may not be safe to log in statement format only once"
INSERT INTO t3 VALUES(func6(), UUID());
Warnings:
-Note 1592 Statement is not safe to log in statement format.
+Note 1592 Statement may not be safe to log in statement format.
"Check whether SET @@SQL_LOG_BIN = 0/1 doesn't work in substatements"
CREATE FUNCTION fun_check_log_bin() RETURNS INT
BEGIN
@@ -259,7 +259,7 @@ SELECT fun_check_log_bin();
fun_check_log_bin()
100
Warnings:
-Note 1592 Statement is not safe to log in statement format.
+Note 1592 Statement may not be safe to log in statement format.
"SQL_LOG_BIN should be ON still"
SHOW VARIABLES LIKE "SQL_LOG_BIN";
Variable_name Value
@@ -315,16 +315,16 @@ CREATE TABLE t1(i INT PRIMARY KEY);
CREATE TABLE t2(i INT PRIMARY KEY);
INSERT INTO t1 SELECT * FROM t2 LIMIT 1;
Warnings:
-Note 1592 Statement is not safe to log in statement format.
+Note 1592 Statement may not be safe to log in statement format.
INSERT INTO t1 VALUES(@@global.sync_binlog);
Warnings:
-Note 1592 Statement is not safe to log in statement format.
+Note 1592 Statement may not be safe to log in statement format.
UPDATE t1 SET i = 999 LIMIT 1;
Warnings:
-Note 1592 Statement is not safe to log in statement format.
+Note 1592 Statement may not be safe to log in statement format.
DELETE FROM t1 LIMIT 1;
Warnings:
-Note 1592 Statement is not safe to log in statement format.
+Note 1592 Statement may not be safe to log in statement format.
DROP TABLE t1, t2;
SET @@SESSION.SQL_MODE = @save_sql_mode;
"End of tests"
diff --git a/mysql-test/suite/binlog/t/binlog_incident-master.opt b/mysql-test/suite/binlog/t/binlog_incident-master.opt
new file mode 100644
index 00000000000..57ce0081ae5
--- /dev/null
+++ b/mysql-test/suite/binlog/t/binlog_incident-master.opt
@@ -0,0 +1 @@
+--loose-debug=+d,incident_database_resync_on_replace
\ No newline at end of file
diff --git a/mysql-test/suite/binlog/t/binlog_incident.test b/mysql-test/suite/binlog/t/binlog_incident.test
new file mode 100644
index 00000000000..208c7f24df2
--- /dev/null
+++ b/mysql-test/suite/binlog/t/binlog_incident.test
@@ -0,0 +1,27 @@
+# The purpose of this test is to provide a reference for how the
+# incident log event is represented in the output from the mysqlbinlog
+# program.
+
+source include/have_log_bin.inc;
+source include/have_debug.inc;
+
+let $MYSQLD_DATADIR= `select @@datadir`;
+
+CREATE TABLE t1 (a INT);
+
+INSERT INTO t1 VALUES (1),(2),(3);
+SELECT * FROM t1;
+
+# This will generate an incident log event and store it in the binary
+# log before the replace statement.
+REPLACE INTO t1 VALUES (4);
+
+DROP TABLE t1;
+FLUSH LOGS;
+
+exec $MYSQL_BINLOG --start-position=106 $MYSQLD_DATADIR/master-bin.000001 >$MYSQLTEST_VARDIR/tmp/binlog_incident-bug44442.sql;
+--disable_query_log
+eval SELECT cont LIKE '%RELOAD DATABASE; # Shall generate syntax error%' AS `Contain RELOAD DATABASE` FROM (SELECT load_file('$MYSQLTEST_VARDIR/tmp/binlog_incident-bug44442.sql') AS cont) AS tbl;
+--enable_query_log
+
+remove_file $MYSQLTEST_VARDIR/tmp/binlog_incident-bug44442.sql;
\ No newline at end of file
diff --git a/mysql-test/suite/binlog/t/binlog_row_mysqlbinlog_db_filter.test b/mysql-test/suite/binlog/t/binlog_row_mysqlbinlog_db_filter.test
new file mode 100644
index 00000000000..0422c204270
--- /dev/null
+++ b/mysql-test/suite/binlog/t/binlog_row_mysqlbinlog_db_filter.test
@@ -0,0 +1,143 @@
+# BUG#42941: --database parameter to mysqlbinlog fails with RBR
+#
+# WHAT
+# ====
+#
+# This test aims at checking whether a rows log event is printed or
+# not when --database parameter is used to filter events from one
+# given database.
+#
+# HOW
+# ===
+#
+# The test is implemented as follows:
+#
+# i) Some operations are done in two different databases:
+# 'test' and 'b42941';
+# ii) mysqlbinlog is used to dump the contents of the binlog file
+# filtering only events from 'b42941'. The result of the dump is
+# stored in a temporary file. (This is done with and without
+# --verbose/hexdump flag);
+# iii) The contents of the dump are loaded into a session variable;
+# iv) The variable contents are searched for 'test' and 'b42941';
+# v) Should 'test' be found, an ERROR is reported. Should 'b42941' be
+# absent, an ERROR is reported.
+
+-- source include/have_log_bin.inc
+-- source include/have_binlog_format_row.inc
+-- source include/have_innodb.inc
+
+RESET MASTER;
+-- let $MYSQLD_DATADIR= `select @@datadir`
+
+CREATE TABLE t1 (id int);
+CREATE TABLE t2 (id int);
+CREATE TABLE t3 (txt TEXT);
+CREATE TABLE t4 (a int) ENGINE= InnoDB;
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (2);
+INSERT INTO t2 VALUES (1);
+INSERT INTO t2 VALUES (2);
+INSERT INTO t1 VALUES (3);
+-- replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
+-- eval LOAD DATA INFILE '$MYSQLTEST_VARDIR/std_data/words.dat' INTO TABLE t3
+INSERT INTO t1 VALUES (4);
+
+CREATE DATABASE b42941;
+use b42941;
+CREATE TABLE t1 (id int);
+CREATE TABLE t2 (id int);
+CREATE TABLE t3 (txt TEXT);
+CREATE TABLE t4 (a int) ENGINE= InnoDB;
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (2);
+INSERT INTO t2 VALUES (1);
+INSERT INTO t2 VALUES (2);
+INSERT INTO t1 VALUES (3);
+-- replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
+-- eval LOAD DATA INFILE '$MYSQLTEST_VARDIR/std_data/words.dat' INTO TABLE t3
+INSERT INTO t1 VALUES (4);
+
+INSERT INTO test.t1 VALUES (5);
+
+FLUSH LOGS;
+
+UPDATE test.t1 t11, b42941.t1 t12 SET t11.id=10, t12.id=100;
+
+BEGIN;
+INSERT INTO test.t4 VALUES (1);
+INSERT INTO b42941.t4 VALUES (1);
+UPDATE test.t4 tn4, b42941.t4 tt4 SET tn4.a= 10, tt4.a= 100;
+COMMIT;
+
+FLUSH LOGS;
+
+-- let $log_file1= $MYSQLD_DATADIR/master-bin.000001
+-- let $log_file2= $MYSQLD_DATADIR/master-bin.000002
+-- let $outfile= $MYSQLTEST_VARDIR/tmp/b42941-mysqlbinlog
+-- let $cmd= $MYSQL_BINLOG
+
+let $i= 3;
+while($i)
+{
+ -- let $flags=--database=b42941
+
+ # construct CLI for mysqlbinlog
+ if(`SELECT $i=3`)
+ {
+ -- let $flags= $flags --verbose --hexdump
+ }
+
+ if(`SELECT $i=2`)
+ {
+ -- let $flags= $flags --verbose
+ }
+
+# if(`SELECT $i=1`)
+# {
+ # do nothing $flags is already set as it should be
+# }
+
+ # execute mysqlbinlog on the two available master binlog files
+ -- exec $cmd $flags $log_file1 > $outfile.1
+ -- exec $cmd $flags $log_file2 > $outfile.2
+
+ # load outputs into a variable
+ -- replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
+ -- eval SET @b42941_output.1= LOAD_FILE('$outfile.1')
+
+ -- replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
+ -- eval SET @b42941_output.2= LOAD_FILE('$outfile.2')
+
+ # remove unecessary files
+ -- remove_file $outfile.1
+ -- remove_file $outfile.2
+
+ # assertion: events for database test are filtered
+ if (`SELECT INSTR(@b42941_output.1, 'test')`)
+ {
+ -- echo **** ERROR **** Database name 'test' FOUND in mysqlbinlog output ($flags $outfile.1).
+ }
+
+ if (`SELECT INSTR(@b42941_output.2, 'test')`)
+ {
+ -- echo **** ERROR **** Database name 'test' FOUND in mysqlbinlog output ($flags $outfile.2).
+ }
+
+ # assertion: events for database b42941 are not filtered
+ if (!`SELECT INSTR(@b42941_output.1, 'b42941')`)
+ {
+ -- echo **** ERROR **** Database name 'b42941' NOT FOUND in mysqlbinlog output ($flags $outfile.1).
+ }
+
+ if (!`SELECT INSTR(@b42941_output.2, 'b42941')`)
+ {
+ -- echo **** ERROR **** Database name 'b42941' NOT FOUND in mysqlbinlog output ($flags $outfile.2).
+ }
+
+ dec $i;
+}
+
+DROP DATABASE b42941;
+use test;
+DROP TABLE t1, t2, t3, t4;
diff --git a/mysql-test/suite/binlog/t/binlog_stm_unsafe_warning-master.opt b/mysql-test/suite/binlog/t/binlog_stm_unsafe_warning-master.opt
new file mode 100644
index 00000000000..24c2027e399
--- /dev/null
+++ b/mysql-test/suite/binlog/t/binlog_stm_unsafe_warning-master.opt
@@ -0,0 +1 @@
+--binlog-ignore-db=b42851
diff --git a/mysql-test/suite/binlog/t/binlog_stm_unsafe_warning.test b/mysql-test/suite/binlog/t/binlog_stm_unsafe_warning.test
new file mode 100644
index 00000000000..0bf685ea921
--- /dev/null
+++ b/mysql-test/suite/binlog/t/binlog_stm_unsafe_warning.test
@@ -0,0 +1,73 @@
+# BUG#42851: Spurious "Statement is not safe to log in statement
+# format." warnings
+#
+# WHY
+# ===
+#
+# This test aims at checking that the fix that removes spurious
+# entries in the error log when the statement is filtered out from
+# binlog, is working.
+#
+# HOW
+# ===
+#
+# The test case is split into three assertions when issuing statements
+# containing LIMIT and ORDER BY:
+#
+# i) issue statements in database that is not filtered => check
+# that warnings ARE shown;
+#
+# ii) issue statements in database that is not filtered, but with
+# binlog disabled => check that warnings ARE NOT shown;
+#
+# iii) issue statements in database that is filtered => check that
+# warnings ARE NOT shown.
+
+-- source include/have_log_bin.inc
+-- source include/have_binlog_format_statement.inc
+
+-- echo ### NOT filtered database => assertion: warnings ARE shown
+
+-- disable_warnings
+DROP TABLE IF EXISTS t1;
+-- enable_warnings
+
+CREATE TABLE t1 (a int, b int, primary key (a));
+INSERT INTO t1 VALUES (1,2), (2,3);
+UPDATE t1 SET b='4' WHERE a=1 LIMIT 1;
+UPDATE t1 SET b='5' WHERE a=2 ORDER BY a LIMIT 1;
+DROP TABLE t1;
+
+-- echo ### NOT filtered database => assertion: binlog disabled and warnings ARE NOT shown
+
+SET SQL_LOG_BIN= 0;
+
+-- disable_warnings
+DROP TABLE IF EXISTS t1;
+-- enable_warnings
+
+CREATE TABLE t1 (a int, b int, primary key (a));
+INSERT INTO t1 VALUES (1,2), (2,3);
+UPDATE t1 SET b='4' WHERE a=1 LIMIT 1;
+UPDATE t1 SET b='5' WHERE a=2 ORDER BY a LIMIT 1;
+DROP TABLE t1;
+
+SET SQL_LOG_BIN= 1;
+
+-- echo ### FILTERED database => assertion: warnings ARE NOT shown
+
+CREATE DATABASE b42851;
+USE b42851;
+
+-- disable_warnings
+DROP TABLE IF EXISTS t1;
+-- enable_warnings
+
+CREATE TABLE t1 (a int, b int, primary key (a));
+INSERT INTO t1 VALUES (1,2), (2,3);
+UPDATE t1 SET b='4' WHERE a=1 LIMIT 1;
+UPDATE t1 SET b='5' WHERE a=2 ORDER BY a LIMIT 1;
+DROP TABLE t1;
+
+# clean up
+DROP DATABASE b42851;
diff --git a/mysql-test/suite/binlog/t/binlog_tbl_metadata.test b/mysql-test/suite/binlog/t/binlog_tbl_metadata.test
new file mode 100644
index 00000000000..5e847ab5fbd
--- /dev/null
+++ b/mysql-test/suite/binlog/t/binlog_tbl_metadata.test
@@ -0,0 +1,199 @@
+#
+# BUG#42749: infinite loop writing to row based binlog - processlist shows
+# "freeing items"
+#
+# WHY
+# ===
+#
+# This bug would make table map event to report data_written one byte less
+# than what would actually be written in its body. This would cause one byte shorter
+# event end_log_pos. The ultimate impact was that it would make fixing the
+# position in MYSQL_BIN_LOG::write_cache bogus or end up in an infinite loop.
+#
+# HOW
+# ===
+#
+# Checking that the patch fixes the problem is done as follows:
+# i) a table with several fields is created;
+# ii) an insert is performed;
+# iii) the logs are flushed;
+# iv) mysqlbinlog is used to check if it succeeds.
+#
+# In step iv), before the bug was fixed, the test case would fail with
+# mysqlbinlog reporting that it was unable to succeed in reading the event.
+#
+
+-- source include/have_log_bin.inc
+-- source include/have_innodb.inc
+-- source include/have_binlog_format_row.inc
+-- connection default
+
+RESET MASTER;
+
+-- disable_warnings
+DROP TABLE IF EXISTS `t1`;
+-- enable_warnings
+
+CREATE TABLE `t1` (
+ `c1` int(11) NOT NULL AUTO_INCREMENT,
+ `c2` varchar(30) NOT NULL,
+ `c3` varchar(30) DEFAULT NULL,
+ `c4` varchar(30) DEFAULT NULL,
+ `c5` varchar(30) DEFAULT NULL,
+ `c6` varchar(30) DEFAULT NULL,
+ `c7` varchar(30) DEFAULT NULL,
+ `c8` varchar(30) DEFAULT NULL,
+ `c9` varchar(30) DEFAULT NULL,
+ `c10` varchar(30) DEFAULT NULL,
+ `c11` varchar(30) DEFAULT NULL,
+ `c12` varchar(30) DEFAULT NULL,
+ `c13` varchar(30) DEFAULT NULL,
+ `c14` varchar(30) DEFAULT NULL,
+ `c15` varchar(30) DEFAULT NULL,
+ `c16` varchar(30) DEFAULT NULL,
+ `c17` varchar(30) DEFAULT NULL,
+ `c18` varchar(30) DEFAULT NULL,
+ `c19` varchar(30) DEFAULT NULL,
+ `c20` varchar(30) DEFAULT NULL,
+ `c21` varchar(30) DEFAULT NULL,
+ `c22` varchar(30) DEFAULT NULL,
+ `c23` varchar(30) DEFAULT NULL,
+ `c24` varchar(30) DEFAULT NULL,
+ `c25` varchar(30) DEFAULT NULL,
+ `c26` varchar(30) DEFAULT NULL,
+ `c27` varchar(30) DEFAULT NULL,
+ `c28` varchar(30) DEFAULT NULL,
+ `c29` varchar(30) DEFAULT NULL,
+ `c30` varchar(30) DEFAULT NULL,
+ `c31` varchar(30) DEFAULT NULL,
+ `c32` varchar(30) DEFAULT NULL,
+ `c33` varchar(30) DEFAULT NULL,
+ `c34` varchar(30) DEFAULT NULL,
+ `c35` varchar(30) DEFAULT NULL,
+ `c36` varchar(30) DEFAULT NULL,
+ `c37` varchar(30) DEFAULT NULL,
+ `c38` varchar(30) DEFAULT NULL,
+ `c39` varchar(30) DEFAULT NULL,
+ `c40` varchar(30) DEFAULT NULL,
+ `c41` varchar(30) DEFAULT NULL,
+ `c42` varchar(30) DEFAULT NULL,
+ `c43` varchar(30) DEFAULT NULL,
+ `c44` varchar(30) DEFAULT NULL,
+ `c45` varchar(30) DEFAULT NULL,
+ `c46` varchar(30) DEFAULT NULL,
+ `c47` varchar(30) DEFAULT NULL,
+ `c48` varchar(30) DEFAULT NULL,
+ `c49` varchar(30) DEFAULT NULL,
+ `c50` varchar(30) DEFAULT NULL,
+ `c51` varchar(30) DEFAULT NULL,
+ `c52` varchar(30) DEFAULT NULL,
+ `c53` varchar(30) DEFAULT NULL,
+ `c54` varchar(30) DEFAULT NULL,
+ `c55` varchar(30) DEFAULT NULL,
+ `c56` varchar(30) DEFAULT NULL,
+ `c57` varchar(30) DEFAULT NULL,
+ `c58` varchar(30) DEFAULT NULL,
+ `c59` varchar(30) DEFAULT NULL,
+ `c60` varchar(30) DEFAULT NULL,
+ `c61` varchar(30) DEFAULT NULL,
+ `c62` varchar(30) DEFAULT NULL,
+ `c63` varchar(30) DEFAULT NULL,
+ `c64` varchar(30) DEFAULT NULL,
+ `c65` varchar(30) DEFAULT NULL,
+ `c66` varchar(30) DEFAULT NULL,
+ `c67` varchar(30) DEFAULT NULL,
+ `c68` varchar(30) DEFAULT NULL,
+ `c69` varchar(30) DEFAULT NULL,
+ `c70` varchar(30) DEFAULT NULL,
+ `c71` varchar(30) DEFAULT NULL,
+ `c72` varchar(30) DEFAULT NULL,
+ `c73` varchar(30) DEFAULT NULL,
+ `c74` varchar(30) DEFAULT NULL,
+ `c75` varchar(30) DEFAULT NULL,
+ `c76` varchar(30) DEFAULT NULL,
+ `c77` varchar(30) DEFAULT NULL,
+ `c78` varchar(30) DEFAULT NULL,
+ `c79` varchar(30) DEFAULT NULL,
+ `c80` varchar(30) DEFAULT NULL,
+ `c81` varchar(30) DEFAULT NULL,
+ `c82` varchar(30) DEFAULT NULL,
+ `c83` varchar(30) DEFAULT NULL,
+ `c84` varchar(30) DEFAULT NULL,
+ `c85` varchar(30) DEFAULT NULL,
+ `c86` varchar(30) DEFAULT NULL,
+ `c87` varchar(30) DEFAULT NULL,
+ `c88` varchar(30) DEFAULT NULL,
+ `c89` varchar(30) DEFAULT NULL,
+ `c90` varchar(30) DEFAULT NULL,
+ `c91` varchar(30) DEFAULT NULL,
+ `c92` varchar(30) DEFAULT NULL,
+ `c93` varchar(30) DEFAULT NULL,
+ `c94` varchar(30) DEFAULT NULL,
+ `c95` varchar(30) DEFAULT NULL,
+ `c96` varchar(30) DEFAULT NULL,
+ `c97` varchar(30) DEFAULT NULL,
+ `c98` varchar(30) DEFAULT NULL,
+ `c99` varchar(30) DEFAULT NULL,
+ `c100` varchar(30) DEFAULT NULL,
+ `c101` varchar(30) DEFAULT NULL,
+ `c102` varchar(30) DEFAULT NULL,
+ `c103` varchar(30) DEFAULT NULL,
+ `c104` varchar(30) DEFAULT NULL,
+ `c105` varchar(30) DEFAULT NULL,
+ `c106` varchar(30) DEFAULT NULL,
+ `c107` varchar(30) DEFAULT NULL,
+ `c108` varchar(30) DEFAULT NULL,
+ `c109` varchar(30) DEFAULT NULL,
+ `c110` varchar(30) DEFAULT NULL,
+ `c111` varchar(30) DEFAULT NULL,
+ `c112` varchar(30) DEFAULT NULL,
+ `c113` varchar(30) DEFAULT NULL,
+ `c114` varchar(30) DEFAULT NULL,
+ `c115` varchar(30) DEFAULT NULL,
+ `c116` varchar(30) DEFAULT NULL,
+ `c117` varchar(30) DEFAULT NULL,
+ `c118` varchar(30) DEFAULT NULL,
+ `c119` varchar(30) DEFAULT NULL,
+ `c120` varchar(30) DEFAULT NULL,
+ `c121` varchar(30) DEFAULT NULL,
+ `c122` varchar(30) DEFAULT NULL,
+ `c123` varchar(30) DEFAULT NULL,
+ `c124` varchar(30) DEFAULT NULL,
+ `c125` varchar(30) DEFAULT NULL,
+ `c126` varchar(30) DEFAULT NULL,
+ `c127` varchar(30) DEFAULT NULL,
+ `c128` varchar(30) DEFAULT NULL,
+ `c129` varchar(30) DEFAULT NULL,
+ `c130` varchar(30) DEFAULT NULL,
+ `c131` varchar(30) DEFAULT NULL,
+ `c132` varchar(30) DEFAULT NULL,
+ `c133` varchar(30) DEFAULT NULL,
+ `c134` varchar(30) DEFAULT NULL,
+ `c135` varchar(30) DEFAULT NULL,
+ `c136` varchar(30) DEFAULT NULL,
+ `c137` varchar(30) DEFAULT NULL,
+ `c138` varchar(30) DEFAULT NULL,
+ `c139` varchar(30) DEFAULT NULL,
+ `c140` varchar(30) DEFAULT NULL,
+ `c141` varchar(30) DEFAULT NULL,
+ `c142` varchar(30) DEFAULT NULL,
+ `c143` varchar(30) DEFAULT NULL,
+ `c144` varchar(30) DEFAULT NULL,
+ `c145` varchar(30) DEFAULT NULL,
+ `c146` varchar(30) DEFAULT NULL,
+ PRIMARY KEY (`c1`)
+) ENGINE=InnoDB;
+
+LOCK TABLES `t1` WRITE;
+
+INSERT INTO `t1` VALUES ('1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1');
+
+DROP TABLE `t1`;
+
+FLUSH LOGS;
+
+-- echo === Using mysqlbinlog to detect failure. Before the patch mysqlbinlog would find a corrupted event, thence would fail.
+
+-- let $MYSQLD_DATADIR= `SELECT @@datadir`;
+-- exec $MYSQL_BINLOG $MYSQLD_DATADIR/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/mysqlbinlog_bug42749.binlog
+-- remove_file $MYSQLTEST_VARDIR/tmp/mysqlbinlog_bug42749.binlog
diff --git a/mysql-test/suite/binlog/t/binlog_unsafe.test b/mysql-test/suite/binlog/t/binlog_unsafe.test
index 1b0f0a6c30a..c4e1f31cbce 100644
--- a/mysql-test/suite/binlog/t/binlog_unsafe.test
+++ b/mysql-test/suite/binlog/t/binlog_unsafe.test
@@ -289,7 +289,7 @@ CREATE TABLE t1(i INT PRIMARY KEY);
CREATE TABLE t2(i INT PRIMARY KEY);
CREATE TABLE t3(i INT, ch CHAR(50));
---echo "Should issue message Statement is not safe to log in statement format."
+--echo "Should issue message Statement may not be safe to log in statement format."
INSERT INTO t1 SELECT * FROM t2 LIMIT 1;
DELIMITER |;
@@ -302,7 +302,7 @@ BEGIN
RETURN 0;
END|
DELIMITER ;|
---echo "Should issue message Statement is not safe to log in statement format only once"
+--echo "Should issue message Statement may not be safe to log in statement format only once"
INSERT INTO t3 VALUES(func6(), UUID());
--echo "Check whether SET @@SQL_LOG_BIN = 0/1 doesn't work in substatements"
diff --git a/mysql-test/suite/funcs_1/datadict/is_key_column_usage.inc b/mysql-test/suite/funcs_1/datadict/is_key_column_usage.inc
index c8e8a186673..098b8c6eca2 100644
--- a/mysql-test/suite/funcs_1/datadict/is_key_column_usage.inc
+++ b/mysql-test/suite/funcs_1/datadict/is_key_column_usage.inc
@@ -126,7 +126,6 @@ ORDER BY constraint_catalog, constraint_schema, constraint_name,
eval $select;
--echo # Establish connection testuser1 (user=testuser1)
-let $MASTER_MYSOCK= query_get_value(SHOW VARIABLES LIKE 'socket', Value, 1);
--replace_result $MASTER_MYPORT MYSQL_PORT $MASTER_MYSOCK MYSQL_SOCK
connect (testuser1, localhost, testuser1, , db_datadict);
eval $select;
diff --git a/mysql-test/suite/funcs_1/datadict/is_routines.inc b/mysql-test/suite/funcs_1/datadict/is_routines.inc
index 573967cbc1b..c2b547e600f 100644
--- a/mysql-test/suite/funcs_1/datadict/is_routines.inc
+++ b/mysql-test/suite/funcs_1/datadict/is_routines.inc
@@ -96,10 +96,11 @@ CREATE FUNCTION function_for_routines() RETURNS INT RETURN 0;
SELECT specific_name,routine_catalog,routine_schema,routine_name,routine_type,
routine_body,external_name,external_language,parameter_style,sql_path
FROM information_schema.routines
-WHERE routine_catalog IS NOT NULL OR external_name IS NOT NULL
+WHERE routine_schema = 'test' AND
+ (routine_catalog IS NOT NULL OR external_name IS NOT NULL
OR external_language IS NOT NULL OR sql_path IS NOT NULL
OR routine_body <> 'SQL' OR parameter_style <> 'SQL'
- OR specific_name <> routine_name;
+ OR specific_name <> routine_name);
DROP PROCEDURE sp_for_routines;
DROP FUNCTION function_for_routines;
@@ -178,7 +179,6 @@ GRANT EXECUTE ON db_datadict_2.* TO 'testuser2'@'localhost';
FLUSH PRIVILEGES;
--echo # Establish connection testuser1 (user=testuser1)
-let $MASTER_MYSOCK= query_get_value(SHOW VARIABLES LIKE 'socket', Value, 1);
--replace_result $MASTER_MYPORT MYSQL_PORT $MASTER_MYSOCK MYSQL_SOCK
connect (testuser1, localhost, testuser1, , db_datadict);
--replace_column 16 "YYYY-MM-DD hh:mm:ss" 17 "YYYY-MM-DD hh:mm:ss"
diff --git a/mysql-test/suite/funcs_1/datadict/is_schemata.inc b/mysql-test/suite/funcs_1/datadict/is_schemata.inc
index 96061d541b7..29e1f6af4ef 100644
--- a/mysql-test/suite/funcs_1/datadict/is_schemata.inc
+++ b/mysql-test/suite/funcs_1/datadict/is_schemata.inc
@@ -104,7 +104,6 @@ eval $my_select;
eval $my_show;
--echo # Establish connection testuser1 (user=testuser1)
-let $MASTER_MYSOCK= query_get_value(SHOW VARIABLES LIKE 'socket', Value, 1);
--replace_result $MASTER_MYPORT MYSQL_PORT $MASTER_MYSOCK MYSQL_SOCK
connect (testuser1, localhost, testuser1, , db_datadict_1);
# Shows db_datadict_1
diff --git a/mysql-test/suite/funcs_1/datadict/is_tables.inc b/mysql-test/suite/funcs_1/datadict/is_tables.inc
index 4f608eb02ea..d1e4608a572 100644
--- a/mysql-test/suite/funcs_1/datadict/is_tables.inc
+++ b/mysql-test/suite/funcs_1/datadict/is_tables.inc
@@ -130,7 +130,6 @@ WHERE table_schema = 'db_datadict' ORDER BY table_name;
let $my_show = SHOW TABLES FROM db_datadict;
--echo # Establish connection testuser1 (user=testuser1)
-let $MASTER_MYSOCK= query_get_value(SHOW VARIABLES LIKE 'socket', Value, 1);
--replace_result $MASTER_MYPORT MYSQL_PORT $MASTER_MYSOCK MYSQL_SOCK
connect (testuser1, localhost, testuser1, , db_datadict);
# tb2 is not granted to anyone
diff --git a/mysql-test/suite/funcs_1/datadict/is_triggers.inc b/mysql-test/suite/funcs_1/datadict/is_triggers.inc
index 70d5540e163..3b83a75295b 100644
--- a/mysql-test/suite/funcs_1/datadict/is_triggers.inc
+++ b/mysql-test/suite/funcs_1/datadict/is_triggers.inc
@@ -122,7 +122,6 @@ let $my_select = SELECT * FROM information_schema.triggers
WHERE trigger_name = 'trg1';
let $my_show = SHOW TRIGGERS FROM db_datadict;
--echo # Establish connection testuser1 (user=testuser1)
-let $MASTER_MYSOCK= query_get_value(SHOW VARIABLES LIKE 'socket', Value, 1);
--replace_result $MASTER_MYPORT MYSQL_PORT $MASTER_MYSOCK MYSQL_SOCK
connect (testuser1, localhost, testuser1, , db_datadict);
--replace_result $engine_type
diff --git a/mysql-test/suite/funcs_1/datadict/is_views.inc b/mysql-test/suite/funcs_1/datadict/is_views.inc
index 542dab05a8e..32e66e4f684 100644
--- a/mysql-test/suite/funcs_1/datadict/is_views.inc
+++ b/mysql-test/suite/funcs_1/datadict/is_views.inc
@@ -108,7 +108,6 @@ WHERE table_schema = 'db_datadict' ORDER BY table_name;
eval $select;
--echo # Establish connection testuser1 (user=testuser1)
-let $MASTER_MYSOCK= query_get_value(SHOW VARIABLES LIKE 'socket', Value, 1);
--replace_result $MASTER_MYPORT MYSQL_PORT $MASTER_MYSOCK MYSQL_SOCK
connect (testuser1, localhost, testuser1, , test);
eval $select;
diff --git a/mysql-test/suite/funcs_1/datadict/processlist_priv.inc b/mysql-test/suite/funcs_1/datadict/processlist_priv.inc
index d8e1b398bfc..b5c40c63566 100644
--- a/mysql-test/suite/funcs_1/datadict/processlist_priv.inc
+++ b/mysql-test/suite/funcs_1/datadict/processlist_priv.inc
@@ -212,7 +212,7 @@ GRANT PROCESS ON *.* TO ''@'localhost';
--echo anonymous user with PROCESS privilege
--echo SHOW/SELECT shows all processes/threads.
--echo ####################################################################################
-connect (anonymous1,localhost,'',,information_schema);
+connect (anonymous1,localhost,"''",,information_schema);
SHOW GRANTS;
--replace_column 1 ID 3 HOST_NAME 6 TIME
SHOW processlist;
@@ -253,7 +253,7 @@ REVOKE PROCESS ON *.* FROM ''@'localhost';
--echo ####################################################################################
--echo 7.1 New connection (anonymous2,localhost,'',,information_schema)
-connect (anonymous2,localhost,'',,information_schema);
+connect (anonymous2,localhost,"''",,information_schema);
--echo The anonymous user has no more the PROCESS privilege
--echo Again only the processes of the anonymous user are visible.
--echo ####################################################################################
diff --git a/mysql-test/suite/funcs_1/datadict/statistics.inc b/mysql-test/suite/funcs_1/datadict/statistics.inc
index 6f24f422b5e..00fd7a1b06b 100644
--- a/mysql-test/suite/funcs_1/datadict/statistics.inc
+++ b/mysql-test/suite/funcs_1/datadict/statistics.inc
@@ -42,7 +42,6 @@ ORDER BY table_schema, table_name, index_name, seq_in_index, column_name;
eval $my_select;
--echo # Establish connection testuser1 (user=testuser1)
-let $MASTER_MYSOCK= query_get_value(SHOW VARIABLES LIKE 'socket', Value, 1);
--replace_result $MASTER_MYPORT MYSQL_PORT $MASTER_MYSOCK MYSQL_SOCK
connect (testuser1,localhost,testuser1,,db_datadict);
--replace_column 10 #CARD#
diff --git a/mysql-test/suite/funcs_1/datadict/table_constraints.inc b/mysql-test/suite/funcs_1/datadict/table_constraints.inc
index 513057c84a0..9e57976862b 100644
--- a/mysql-test/suite/funcs_1/datadict/table_constraints.inc
+++ b/mysql-test/suite/funcs_1/datadict/table_constraints.inc
@@ -33,7 +33,6 @@ ORDER BY table_schema,table_name,constraint_name;
eval $my_select;
--echo # Establish connection testuser1 (user=testuser1)
-let $MASTER_MYSOCK= query_get_value(SHOW VARIABLES LIKE 'socket', Value, 1);
--replace_result $MASTER_MYPORT MYSQL_PORT $MASTER_MYSOCK MYSQL_SOCK
connect (testuser1,localhost,testuser1,,db_datadict);
eval $my_select;
diff --git a/mysql-test/suite/funcs_1/datadict/tables.inc b/mysql-test/suite/funcs_1/datadict/tables.inc
index 8dae7ba0ebc..5aa072d184c 100644
--- a/mysql-test/suite/funcs_1/datadict/tables.inc
+++ b/mysql-test/suite/funcs_1/datadict/tables.inc
@@ -37,7 +37,6 @@ CREATE USER testuser1@localhost;
GRANT SELECT ON test1.* TO testuser1@localhost;
--echo # Establish connection testuser1 (user=testuser1)
-let $MASTER_MYSOCK= query_get_value(SHOW VARIABLES LIKE 'socket', Value, 1);
--replace_result $MASTER_MYPORT MYSQL_PORT $MASTER_MYSOCK MYSQL_SOCK
connect (testuser1,localhost,testuser1,,test1);
--source suite/funcs_1/datadict/tables2.inc
diff --git a/mysql-test/suite/funcs_1/datadict/tables1.inc b/mysql-test/suite/funcs_1/datadict/tables1.inc
index 2dff32d81a9..2e054a9dcfb 100644
--- a/mysql-test/suite/funcs_1/datadict/tables1.inc
+++ b/mysql-test/suite/funcs_1/datadict/tables1.inc
@@ -27,7 +27,6 @@ CREATE USER testuser1@localhost;
GRANT SELECT ON test1.* TO testuser1@localhost;
--echo # Establish connection testuser1 (user=testuser1)
-let $MASTER_MYSOCK= query_get_value(SHOW VARIABLES LIKE 'socket', Value, 1);
--replace_result $MASTER_MYPORT MYSQL_PORT $MASTER_MYSOCK MYSQL_SOCK
connect (testuser1,localhost,testuser1,,test1);
--source suite/funcs_1/datadict/tables2.inc
diff --git a/mysql-test/suite/funcs_1/r/charset_collation.result b/mysql-test/suite/funcs_1/r/charset_collation.result
new file mode 100644
index 00000000000..b3183ba48e1
--- /dev/null
+++ b/mysql-test/suite/funcs_1/r/charset_collation.result
@@ -0,0 +1,40 @@
+DROP USER dbdict_test@localhost;
+CREATE USER dbdict_test@localhost;
+# Establish connection con (user=dbdict_test)
+
+SELECT *
+FROM information_schema.character_sets
+WHERE character_set_name IN ('utf8','latin1','binary')
+ORDER BY character_set_name;
+CHARACTER_SET_NAME DEFAULT_COLLATE_NAME DESCRIPTION MAXLEN
+binary binary Binary pseudo charset 1
+latin1 latin1_swedish_ci cp1252 West European 1
+utf8 utf8_general_ci UTF-8 Unicode 3
+
+SELECT *
+FROM information_schema.collations
+WHERE character_set_name IN ('utf8','latin1','binary')
+AND (collation_name LIKE CONCAT(character_set_name,'_general_ci')
+OR
+collation_name LIKE CONCAT(character_set_name,'_bin'))
+ORDER BY collation_name;
+COLLATION_NAME CHARACTER_SET_NAME ID IS_DEFAULT IS_COMPILED SORTLEN
+latin1_bin latin1 47 Yes 1
+latin1_general_ci latin1 48 Yes 1
+utf8_bin utf8 83 Yes 1
+utf8_general_ci utf8 33 Yes Yes 1
+
+SELECT *
+FROM information_schema.collation_character_set_applicability
+WHERE character_set_name IN ('utf8','latin1','binary')
+AND (collation_name LIKE CONCAT(character_set_name,'_general_ci')
+OR
+collation_name LIKE CONCAT(character_set_name,'_bin'))
+ORDER BY collation_name, character_set_name;
+COLLATION_NAME CHARACTER_SET_NAME
+latin1_bin latin1
+latin1_general_ci latin1
+utf8_bin utf8
+utf8_general_ci utf8
+# Switch to connection default + disconnect con
+DROP USER dbdict_test@localhost;
diff --git a/mysql-test/suite/funcs_1/r/charset_collation_1.result b/mysql-test/suite/funcs_1/r/charset_collation_1.result
deleted file mode 100644
index 55ed4b4704c..00000000000
--- a/mysql-test/suite/funcs_1/r/charset_collation_1.result
+++ /dev/null
@@ -1,312 +0,0 @@
-DROP USER dbdict_test@localhost;
-CREATE USER dbdict_test@localhost;
-# Establish connection con (user=dbdict_test)
-
-SELECT *
-FROM information_schema.character_sets
-ORDER BY character_set_name;
-CHARACTER_SET_NAME DEFAULT_COLLATE_NAME DESCRIPTION MAXLEN
-armscii8 armscii8_general_ci ARMSCII-8 Armenian 1
-ascii ascii_general_ci US ASCII 1
-big5 big5_chinese_ci Big5 Traditional Chinese 2
-binary binary Binary pseudo charset 1
-cp1250 cp1250_general_ci Windows Central European 1
-cp1251 cp1251_general_ci Windows Cyrillic 1
-cp1256 cp1256_general_ci Windows Arabic 1
-cp1257 cp1257_general_ci Windows Baltic 1
-cp850 cp850_general_ci DOS West European 1
-cp852 cp852_general_ci DOS Central European 1
-cp866 cp866_general_ci DOS Russian 1
-cp932 cp932_japanese_ci SJIS for Windows Japanese 2
-dec8 dec8_swedish_ci DEC West European 1
-eucjpms eucjpms_japanese_ci UJIS for Windows Japanese 3
-euckr euckr_korean_ci EUC-KR Korean 2
-gb2312 gb2312_chinese_ci GB2312 Simplified Chinese 2
-gbk gbk_chinese_ci GBK Simplified Chinese 2
-geostd8 geostd8_general_ci GEOSTD8 Georgian 1
-greek greek_general_ci ISO 8859-7 Greek 1
-hebrew hebrew_general_ci ISO 8859-8 Hebrew 1
-hp8 hp8_english_ci HP West European 1
-keybcs2 keybcs2_general_ci DOS Kamenicky Czech-Slovak 1
-koi8r koi8r_general_ci KOI8-R Relcom Russian 1
-koi8u koi8u_general_ci KOI8-U Ukrainian 1
-latin1 latin1_swedish_ci cp1252 West European 1
-latin2 latin2_general_ci ISO 8859-2 Central European 1
-latin5 latin5_turkish_ci ISO 8859-9 Turkish 1
-latin7 latin7_general_ci ISO 8859-13 Baltic 1
-macce macce_general_ci Mac Central European 1
-macroman macroman_general_ci Mac West European 1
-sjis sjis_japanese_ci Shift-JIS Japanese 2
-swe7 swe7_swedish_ci 7bit Swedish 1
-tis620 tis620_thai_ci TIS620 Thai 1
-ucs2 ucs2_general_ci UCS-2 Unicode 2
-ujis ujis_japanese_ci EUC-JP Japanese 3
-utf8 utf8_general_ci UTF-8 Unicode 3
-
-SELECT *
-FROM information_schema.collations
-ORDER BY collation_name;
-COLLATION_NAME CHARACTER_SET_NAME ID IS_DEFAULT IS_COMPILED SORTLEN
-armscii8_bin armscii8 64 0
-armscii8_general_ci armscii8 32 Yes 0
-ascii_bin ascii 65 0
-ascii_general_ci ascii 11 Yes 0
-big5_bin big5 84 Yes 1
-big5_chinese_ci big5 1 Yes Yes 1
-binary binary 63 Yes Yes 1
-cp1250_bin cp1250 66 Yes 1
-cp1250_croatian_ci cp1250 44 Yes 1
-cp1250_czech_cs cp1250 34 Yes 2
-cp1250_general_ci cp1250 26 Yes Yes 1
-cp1250_polish_ci cp1250 99 Yes 1
-cp1251_bin cp1251 50 0
-cp1251_bulgarian_ci cp1251 14 0
-cp1251_general_ci cp1251 51 Yes 0
-cp1251_general_cs cp1251 52 0
-cp1251_ukrainian_ci cp1251 23 0
-cp1256_bin cp1256 67 0
-cp1256_general_ci cp1256 57 Yes 0
-cp1257_bin cp1257 58 0
-cp1257_general_ci cp1257 59 Yes 0
-cp1257_lithuanian_ci cp1257 29 0
-cp850_bin cp850 80 0
-cp850_general_ci cp850 4 Yes 0
-cp852_bin cp852 81 0
-cp852_general_ci cp852 40 Yes 0
-cp866_bin cp866 68 0
-cp866_general_ci cp866 36 Yes 0
-cp932_bin cp932 96 Yes 1
-cp932_japanese_ci cp932 95 Yes Yes 1
-dec8_bin dec8 69 0
-dec8_swedish_ci dec8 3 Yes 0
-eucjpms_bin eucjpms 98 Yes 1
-eucjpms_japanese_ci eucjpms 97 Yes Yes 1
-euckr_bin euckr 85 Yes 1
-euckr_korean_ci euckr 19 Yes Yes 1
-gb2312_bin gb2312 86 Yes 1
-gb2312_chinese_ci gb2312 24 Yes Yes 1
-gbk_bin gbk 87 Yes 1
-gbk_chinese_ci gbk 28 Yes Yes 1
-geostd8_bin geostd8 93 0
-geostd8_general_ci geostd8 92 Yes 0
-greek_bin greek 70 0
-greek_general_ci greek 25 Yes 0
-hebrew_bin hebrew 71 0
-hebrew_general_ci hebrew 16 Yes 0
-hp8_bin hp8 72 0
-hp8_english_ci hp8 6 Yes 0
-keybcs2_bin keybcs2 73 0
-keybcs2_general_ci keybcs2 37 Yes 0
-koi8r_bin koi8r 74 0
-koi8r_general_ci koi8r 7 Yes 0
-koi8u_bin koi8u 75 0
-koi8u_general_ci koi8u 22 Yes 0
-latin1_bin latin1 47 Yes 1
-latin1_danish_ci latin1 15 Yes 1
-latin1_general_ci latin1 48 Yes 1
-latin1_general_cs latin1 49 Yes 1
-latin1_german1_ci latin1 5 Yes 1
-latin1_german2_ci latin1 31 Yes 2
-latin1_spanish_ci latin1 94 Yes 1
-latin1_swedish_ci latin1 8 Yes Yes 1
-latin2_bin latin2 77 Yes 1
-latin2_croatian_ci latin2 27 Yes 1
-latin2_czech_cs latin2 2 Yes 4
-latin2_general_ci latin2 9 Yes Yes 1
-latin2_hungarian_ci latin2 21 Yes 1
-latin5_bin latin5 78 0
-latin5_turkish_ci latin5 30 Yes 0
-latin7_bin latin7 79 0
-latin7_estonian_cs latin7 20 0
-latin7_general_ci latin7 41 Yes 0
-latin7_general_cs latin7 42 0
-macce_bin macce 43 0
-macce_general_ci macce 38 Yes 0
-macroman_bin macroman 53 0
-macroman_general_ci macroman 39 Yes 0
-sjis_bin sjis 88 Yes 1
-sjis_japanese_ci sjis 13 Yes Yes 1
-swe7_bin swe7 82 0
-swe7_swedish_ci swe7 10 Yes 0
-tis620_bin tis620 89 Yes 1
-tis620_thai_ci tis620 18 Yes Yes 4
-ucs2_bin ucs2 90 Yes 1
-ucs2_czech_ci ucs2 138 Yes 8
-ucs2_danish_ci ucs2 139 Yes 8
-ucs2_esperanto_ci ucs2 145 Yes 8
-ucs2_estonian_ci ucs2 134 Yes 8
-ucs2_general_ci ucs2 35 Yes Yes 1
-ucs2_hungarian_ci ucs2 146 Yes 8
-ucs2_icelandic_ci ucs2 129 Yes 8
-ucs2_latvian_ci ucs2 130 Yes 8
-ucs2_lithuanian_ci ucs2 140 Yes 8
-ucs2_persian_ci ucs2 144 Yes 8
-ucs2_polish_ci ucs2 133 Yes 8
-ucs2_romanian_ci ucs2 131 Yes 8
-ucs2_roman_ci ucs2 143 Yes 8
-ucs2_slovak_ci ucs2 141 Yes 8
-ucs2_slovenian_ci ucs2 132 Yes 8
-ucs2_spanish2_ci ucs2 142 Yes 8
-ucs2_spanish_ci ucs2 135 Yes 8
-ucs2_swedish_ci ucs2 136 Yes 8
-ucs2_turkish_ci ucs2 137 Yes 8
-ucs2_unicode_ci ucs2 128 Yes 8
-ujis_bin ujis 91 Yes 1
-ujis_japanese_ci ujis 12 Yes Yes 1
-utf8_bin utf8 83 Yes 1
-utf8_czech_ci utf8 202 Yes 8
-utf8_danish_ci utf8 203 Yes 8
-utf8_esperanto_ci utf8 209 Yes 8
-utf8_estonian_ci utf8 198 Yes 8
-utf8_general_ci utf8 33 Yes Yes 1
-utf8_hungarian_ci utf8 210 Yes 8
-utf8_icelandic_ci utf8 193 Yes 8
-utf8_latvian_ci utf8 194 Yes 8
-utf8_lithuanian_ci utf8 204 Yes 8
-utf8_persian_ci utf8 208 Yes 8
-utf8_polish_ci utf8 197 Yes 8
-utf8_romanian_ci utf8 195 Yes 8
-utf8_roman_ci utf8 207 Yes 8
-utf8_slovak_ci utf8 205 Yes 8
-utf8_slovenian_ci utf8 196 Yes 8
-utf8_spanish2_ci utf8 206 Yes 8
-utf8_spanish_ci utf8 199 Yes 8
-utf8_swedish_ci utf8 200 Yes 8
-utf8_turkish_ci utf8 201 Yes 8
-utf8_unicode_ci utf8 192 Yes 8
-
-
-SELECT *
-FROM information_schema.collation_character_set_applicability
-ORDER BY collation_name, character_set_name;
-COLLATION_NAME CHARACTER_SET_NAME
-armscii8_bin armscii8
-armscii8_general_ci armscii8
-ascii_bin ascii
-ascii_general_ci ascii
-big5_bin big5
-big5_chinese_ci big5
-binary binary
-cp1250_bin cp1250
-cp1250_croatian_ci cp1250
-cp1250_czech_cs cp1250
-cp1250_general_ci cp1250
-cp1250_polish_ci cp1250
-cp1251_bin cp1251
-cp1251_bulgarian_ci cp1251
-cp1251_general_ci cp1251
-cp1251_general_cs cp1251
-cp1251_ukrainian_ci cp1251
-cp1256_bin cp1256
-cp1256_general_ci cp1256
-cp1257_bin cp1257
-cp1257_general_ci cp1257
-cp1257_lithuanian_ci cp1257
-cp850_bin cp850
-cp850_general_ci cp850
-cp852_bin cp852
-cp852_general_ci cp852
-cp866_bin cp866
-cp866_general_ci cp866
-cp932_bin cp932
-cp932_japanese_ci cp932
-dec8_bin dec8
-dec8_swedish_ci dec8
-eucjpms_bin eucjpms
-eucjpms_japanese_ci eucjpms
-euckr_bin euckr
-euckr_korean_ci euckr
-filename filename
-gb2312_bin gb2312
-gb2312_chinese_ci gb2312
-gbk_bin gbk
-gbk_chinese_ci gbk
-geostd8_bin geostd8
-geostd8_general_ci geostd8
-greek_bin greek
-greek_general_ci greek
-hebrew_bin hebrew
-hebrew_general_ci hebrew
-hp8_bin hp8
-hp8_english_ci hp8
-keybcs2_bin keybcs2
-keybcs2_general_ci keybcs2
-koi8r_bin koi8r
-koi8r_general_ci koi8r
-koi8u_bin koi8u
-koi8u_general_ci koi8u
-latin1_bin latin1
-latin1_danish_ci latin1
-latin1_general_ci latin1
-latin1_general_cs latin1
-latin1_german1_ci latin1
-latin1_german2_ci latin1
-latin1_spanish_ci latin1
-latin1_swedish_ci latin1
-latin2_bin latin2
-latin2_croatian_ci latin2
-latin2_czech_cs latin2
-latin2_general_ci latin2
-latin2_hungarian_ci latin2
-latin5_bin latin5
-latin5_turkish_ci latin5
-latin7_bin latin7
-latin7_estonian_cs latin7
-latin7_general_ci latin7
-latin7_general_cs latin7
-macce_bin macce
-macce_general_ci macce
-macroman_bin macroman
-macroman_general_ci macroman
-sjis_bin sjis
-sjis_japanese_ci sjis
-swe7_bin swe7
-swe7_swedish_ci swe7
-tis620_bin tis620
-tis620_thai_ci tis620
-ucs2_bin ucs2
-ucs2_czech_ci ucs2
-ucs2_danish_ci ucs2
-ucs2_esperanto_ci ucs2
-ucs2_estonian_ci ucs2
-ucs2_general_ci ucs2
-ucs2_hungarian_ci ucs2
-ucs2_icelandic_ci ucs2
-ucs2_latvian_ci ucs2
-ucs2_lithuanian_ci ucs2
-ucs2_persian_ci ucs2
-ucs2_polish_ci ucs2
-ucs2_romanian_ci ucs2
-ucs2_roman_ci ucs2
-ucs2_slovak_ci ucs2
-ucs2_slovenian_ci ucs2
-ucs2_spanish2_ci ucs2
-ucs2_spanish_ci ucs2
-ucs2_swedish_ci ucs2
-ucs2_turkish_ci ucs2
-ucs2_unicode_ci ucs2
-ujis_bin ujis
-ujis_japanese_ci ujis
-utf8_bin utf8
-utf8_czech_ci utf8
-utf8_danish_ci utf8
-utf8_esperanto_ci utf8
-utf8_estonian_ci utf8
-utf8_general_ci utf8
-utf8_hungarian_ci utf8
-utf8_icelandic_ci utf8
-utf8_latvian_ci utf8
-utf8_lithuanian_ci utf8
-utf8_persian_ci utf8
-utf8_polish_ci utf8
-utf8_romanian_ci utf8
-utf8_roman_ci utf8
-utf8_slovak_ci utf8
-utf8_slovenian_ci utf8
-utf8_spanish2_ci utf8
-utf8_spanish_ci utf8
-utf8_swedish_ci utf8
-utf8_turkish_ci utf8
-utf8_unicode_ci utf8
-# Switch to connection default + disconnect con
-DROP USER dbdict_test@localhost;
diff --git a/mysql-test/suite/funcs_1/r/charset_collation_2.result b/mysql-test/suite/funcs_1/r/charset_collation_2.result
deleted file mode 100644
index a9fb15a588c..00000000000
--- a/mysql-test/suite/funcs_1/r/charset_collation_2.result
+++ /dev/null
@@ -1,314 +0,0 @@
-DROP USER dbdict_test@localhost;
-CREATE USER dbdict_test@localhost;
-# Establish connection con (user=dbdict_test)
-
-SELECT *
-FROM information_schema.character_sets
-ORDER BY character_set_name;
-CHARACTER_SET_NAME DEFAULT_COLLATE_NAME DESCRIPTION MAXLEN
-armscii8 armscii8_general_ci ARMSCII-8 Armenian 1
-ascii ascii_general_ci US ASCII 1
-big5 big5_chinese_ci Big5 Traditional Chinese 2
-binary binary Binary pseudo charset 1
-cp1250 cp1250_general_ci Windows Central European 1
-cp1251 cp1251_general_ci Windows Cyrillic 1
-cp1256 cp1256_general_ci Windows Arabic 1
-cp1257 cp1257_general_ci Windows Baltic 1
-cp850 cp850_general_ci DOS West European 1
-cp852 cp852_general_ci DOS Central European 1
-cp866 cp866_general_ci DOS Russian 1
-cp932 cp932_japanese_ci SJIS for Windows Japanese 2
-dec8 dec8_swedish_ci DEC West European 1
-eucjpms eucjpms_japanese_ci UJIS for Windows Japanese 3
-euckr euckr_korean_ci EUC-KR Korean 2
-gb2312 gb2312_chinese_ci GB2312 Simplified Chinese 2
-gbk gbk_chinese_ci GBK Simplified Chinese 2
-geostd8 geostd8_general_ci GEOSTD8 Georgian 1
-greek greek_general_ci ISO 8859-7 Greek 1
-hebrew hebrew_general_ci ISO 8859-8 Hebrew 1
-hp8 hp8_english_ci HP West European 1
-keybcs2 keybcs2_general_ci DOS Kamenicky Czech-Slovak 1
-koi8r koi8r_general_ci KOI8-R Relcom Russian 1
-koi8u koi8u_general_ci KOI8-U Ukrainian 1
-latin1 latin1_swedish_ci cp1252 West European 1
-latin2 latin2_general_ci ISO 8859-2 Central European 1
-latin5 latin5_turkish_ci ISO 8859-9 Turkish 1
-latin7 latin7_general_ci ISO 8859-13 Baltic 1
-macce macce_general_ci Mac Central European 1
-macroman macroman_general_ci Mac West European 1
-sjis sjis_japanese_ci Shift-JIS Japanese 2
-swe7 swe7_swedish_ci 7bit Swedish 1
-tis620 tis620_thai_ci TIS620 Thai 1
-ucs2 ucs2_general_ci UCS-2 Unicode 2
-ujis ujis_japanese_ci EUC-JP Japanese 3
-utf8 utf8_general_ci UTF-8 Unicode 3
-
-SELECT *
-FROM information_schema.collations
-ORDER BY collation_name;
-COLLATION_NAME CHARACTER_SET_NAME ID IS_DEFAULT IS_COMPILED SORTLEN
-armscii8_bin armscii8 64 0
-armscii8_general_ci armscii8 32 Yes 0
-ascii_bin ascii 65 0
-ascii_general_ci ascii 11 Yes 0
-big5_bin big5 84 Yes 1
-big5_chinese_ci big5 1 Yes Yes 1
-binary binary 63 Yes Yes 1
-cp1250_bin cp1250 66 Yes 1
-cp1250_croatian_ci cp1250 44 Yes 1
-cp1250_czech_cs cp1250 34 Yes 2
-cp1250_general_ci cp1250 26 Yes Yes 1
-cp1250_polish_ci cp1250 99 Yes 1
-cp1251_bin cp1251 50 0
-cp1251_bulgarian_ci cp1251 14 0
-cp1251_general_ci cp1251 51 Yes 0
-cp1251_general_cs cp1251 52 0
-cp1251_ukrainian_ci cp1251 23 0
-cp1256_bin cp1256 67 0
-cp1256_general_ci cp1256 57 Yes 0
-cp1257_bin cp1257 58 0
-cp1257_general_ci cp1257 59 Yes 0
-cp1257_lithuanian_ci cp1257 29 0
-cp850_bin cp850 80 0
-cp850_general_ci cp850 4 Yes 0
-cp852_bin cp852 81 0
-cp852_general_ci cp852 40 Yes 0
-cp866_bin cp866 68 0
-cp866_general_ci cp866 36 Yes 0
-cp932_bin cp932 96 Yes 1
-cp932_japanese_ci cp932 95 Yes Yes 1
-dec8_bin dec8 69 0
-dec8_swedish_ci dec8 3 Yes 0
-eucjpms_bin eucjpms 98 Yes 1
-eucjpms_japanese_ci eucjpms 97 Yes Yes 1
-euckr_bin euckr 85 Yes 1
-euckr_korean_ci euckr 19 Yes Yes 1
-gb2312_bin gb2312 86 Yes 1
-gb2312_chinese_ci gb2312 24 Yes Yes 1
-gbk_bin gbk 87 Yes 1
-gbk_chinese_ci gbk 28 Yes Yes 1
-geostd8_bin geostd8 93 0
-geostd8_general_ci geostd8 92 Yes 0
-greek_bin greek 70 0
-greek_general_ci greek 25 Yes 0
-hebrew_bin hebrew 71 0
-hebrew_general_ci hebrew 16 Yes 0
-hp8_bin hp8 72 0
-hp8_english_ci hp8 6 Yes 0
-keybcs2_bin keybcs2 73 0
-keybcs2_general_ci keybcs2 37 Yes 0
-koi8r_bin koi8r 74 0
-koi8r_general_ci koi8r 7 Yes 0
-koi8u_bin koi8u 75 0
-koi8u_general_ci koi8u 22 Yes 0
-latin1_bin latin1 47 Yes 1
-latin1_danish_ci latin1 15 Yes 1
-latin1_general_ci latin1 48 Yes 1
-latin1_general_cs latin1 49 Yes 1
-latin1_german1_ci latin1 5 Yes 1
-latin1_german2_ci latin1 31 Yes 2
-latin1_spanish_ci latin1 94 Yes 1
-latin1_swedish_ci latin1 8 Yes Yes 1
-latin2_bin latin2 77 Yes 1
-latin2_croatian_ci latin2 27 Yes 1
-latin2_czech_cs latin2 2 Yes 4
-latin2_general_ci latin2 9 Yes Yes 1
-latin2_hungarian_ci latin2 21 Yes 1
-latin5_bin latin5 78 0
-latin5_turkish_ci latin5 30 Yes 0
-latin7_bin latin7 79 0
-latin7_estonian_cs latin7 20 0
-latin7_general_ci latin7 41 Yes 0
-latin7_general_cs latin7 42 0
-macce_bin macce 43 0
-macce_general_ci macce 38 Yes 0
-macroman_bin macroman 53 0
-macroman_general_ci macroman 39 Yes 0
-sjis_bin sjis 88 Yes 1
-sjis_japanese_ci sjis 13 Yes Yes 1
-swe7_bin swe7 82 0
-swe7_swedish_ci swe7 10 Yes 0
-tis620_bin tis620 89 Yes 1
-tis620_thai_ci tis620 18 Yes Yes 4
-ucs2_bin ucs2 90 Yes 1
-ucs2_czech_ci ucs2 138 Yes 8
-ucs2_danish_ci ucs2 139 Yes 8
-ucs2_esperanto_ci ucs2 145 Yes 8
-ucs2_estonian_ci ucs2 134 Yes 8
-ucs2_general_ci ucs2 35 Yes Yes 1
-ucs2_hungarian_ci ucs2 146 Yes 8
-ucs2_icelandic_ci ucs2 129 Yes 8
-ucs2_latvian_ci ucs2 130 Yes 8
-ucs2_lithuanian_ci ucs2 140 Yes 8
-ucs2_persian_ci ucs2 144 Yes 8
-ucs2_polish_ci ucs2 133 Yes 8
-ucs2_romanian_ci ucs2 131 Yes 8
-ucs2_roman_ci ucs2 143 Yes 8
-ucs2_slovak_ci ucs2 141 Yes 8
-ucs2_slovenian_ci ucs2 132 Yes 8
-ucs2_spanish2_ci ucs2 142 Yes 8
-ucs2_spanish_ci ucs2 135 Yes 8
-ucs2_swedish_ci ucs2 136 Yes 8
-ucs2_turkish_ci ucs2 137 Yes 8
-ucs2_unicode_ci ucs2 128 Yes 8
-ujis_bin ujis 91 Yes 1
-ujis_japanese_ci ujis 12 Yes Yes 1
-utf8_bin utf8 83 Yes 1
-utf8_czech_ci utf8 202 Yes 8
-utf8_danish_ci utf8 203 Yes 8
-utf8_esperanto_ci utf8 209 Yes 8
-utf8_estonian_ci utf8 198 Yes 8
-utf8_general_ci utf8 33 Yes Yes 1
-utf8_general_cs utf8 254 Yes 1
-utf8_hungarian_ci utf8 210 Yes 8
-utf8_icelandic_ci utf8 193 Yes 8
-utf8_latvian_ci utf8 194 Yes 8
-utf8_lithuanian_ci utf8 204 Yes 8
-utf8_persian_ci utf8 208 Yes 8
-utf8_polish_ci utf8 197 Yes 8
-utf8_romanian_ci utf8 195 Yes 8
-utf8_roman_ci utf8 207 Yes 8
-utf8_slovak_ci utf8 205 Yes 8
-utf8_slovenian_ci utf8 196 Yes 8
-utf8_spanish2_ci utf8 206 Yes 8
-utf8_spanish_ci utf8 199 Yes 8
-utf8_swedish_ci utf8 200 Yes 8
-utf8_turkish_ci utf8 201 Yes 8
-utf8_unicode_ci utf8 192 Yes 8
-
-
-SELECT *
-FROM information_schema.collation_character_set_applicability
-ORDER BY collation_name, character_set_name;
-COLLATION_NAME CHARACTER_SET_NAME
-armscii8_bin armscii8
-armscii8_general_ci armscii8
-ascii_bin ascii
-ascii_general_ci ascii
-big5_bin big5
-big5_chinese_ci big5
-binary binary
-cp1250_bin cp1250
-cp1250_croatian_ci cp1250
-cp1250_czech_cs cp1250
-cp1250_general_ci cp1250
-cp1250_polish_ci cp1250
-cp1251_bin cp1251
-cp1251_bulgarian_ci cp1251
-cp1251_general_ci cp1251
-cp1251_general_cs cp1251
-cp1251_ukrainian_ci cp1251
-cp1256_bin cp1256
-cp1256_general_ci cp1256
-cp1257_bin cp1257
-cp1257_general_ci cp1257
-cp1257_lithuanian_ci cp1257
-cp850_bin cp850
-cp850_general_ci cp850
-cp852_bin cp852
-cp852_general_ci cp852
-cp866_bin cp866
-cp866_general_ci cp866
-cp932_bin cp932
-cp932_japanese_ci cp932
-dec8_bin dec8
-dec8_swedish_ci dec8
-eucjpms_bin eucjpms
-eucjpms_japanese_ci eucjpms
-euckr_bin euckr
-euckr_korean_ci euckr
-filename filename
-gb2312_bin gb2312
-gb2312_chinese_ci gb2312
-gbk_bin gbk
-gbk_chinese_ci gbk
-geostd8_bin geostd8
-geostd8_general_ci geostd8
-greek_bin greek
-greek_general_ci greek
-hebrew_bin hebrew
-hebrew_general_ci hebrew
-hp8_bin hp8
-hp8_english_ci hp8
-keybcs2_bin keybcs2
-keybcs2_general_ci keybcs2
-koi8r_bin koi8r
-koi8r_general_ci koi8r
-koi8u_bin koi8u
-koi8u_general_ci koi8u
-latin1_bin latin1
-latin1_danish_ci latin1
-latin1_general_ci latin1
-latin1_general_cs latin1
-latin1_german1_ci latin1
-latin1_german2_ci latin1
-latin1_spanish_ci latin1
-latin1_swedish_ci latin1
-latin2_bin latin2
-latin2_croatian_ci latin2
-latin2_czech_cs latin2
-latin2_general_ci latin2
-latin2_hungarian_ci latin2
-latin5_bin latin5
-latin5_turkish_ci latin5
-latin7_bin latin7
-latin7_estonian_cs latin7
-latin7_general_ci latin7
-latin7_general_cs latin7
-macce_bin macce
-macce_general_ci macce
-macroman_bin macroman
-macroman_general_ci macroman
-sjis_bin sjis
-sjis_japanese_ci sjis
-swe7_bin swe7
-swe7_swedish_ci swe7
-tis620_bin tis620
-tis620_thai_ci tis620
-ucs2_bin ucs2
-ucs2_czech_ci ucs2
-ucs2_danish_ci ucs2
-ucs2_esperanto_ci ucs2
-ucs2_estonian_ci ucs2
-ucs2_general_ci ucs2
-ucs2_hungarian_ci ucs2
-ucs2_icelandic_ci ucs2
-ucs2_latvian_ci ucs2
-ucs2_lithuanian_ci ucs2
-ucs2_persian_ci ucs2
-ucs2_polish_ci ucs2
-ucs2_romanian_ci ucs2
-ucs2_roman_ci ucs2
-ucs2_slovak_ci ucs2
-ucs2_slovenian_ci ucs2
-ucs2_spanish2_ci ucs2
-ucs2_spanish_ci ucs2
-ucs2_swedish_ci ucs2
-ucs2_turkish_ci ucs2
-ucs2_unicode_ci ucs2
-ujis_bin ujis
-ujis_japanese_ci ujis
-utf8_bin utf8
-utf8_czech_ci utf8
-utf8_danish_ci utf8
-utf8_esperanto_ci utf8
-utf8_estonian_ci utf8
-utf8_general_ci utf8
-utf8_general_cs utf8
-utf8_hungarian_ci utf8
-utf8_icelandic_ci utf8
-utf8_latvian_ci utf8
-utf8_lithuanian_ci utf8
-utf8_persian_ci utf8
-utf8_polish_ci utf8
-utf8_romanian_ci utf8
-utf8_roman_ci utf8
-utf8_slovak_ci utf8
-utf8_slovenian_ci utf8
-utf8_spanish2_ci utf8
-utf8_spanish_ci utf8
-utf8_swedish_ci utf8
-utf8_turkish_ci utf8
-utf8_unicode_ci utf8
-# Switch to connection default + disconnect con
-DROP USER dbdict_test@localhost;
diff --git a/mysql-test/suite/funcs_1/r/charset_collation_3.result b/mysql-test/suite/funcs_1/r/charset_collation_3.result
deleted file mode 100644
index 55ed4b4704c..00000000000
--- a/mysql-test/suite/funcs_1/r/charset_collation_3.result
+++ /dev/null
@@ -1,312 +0,0 @@
-DROP USER dbdict_test@localhost;
-CREATE USER dbdict_test@localhost;
-# Establish connection con (user=dbdict_test)
-
-SELECT *
-FROM information_schema.character_sets
-ORDER BY character_set_name;
-CHARACTER_SET_NAME DEFAULT_COLLATE_NAME DESCRIPTION MAXLEN
-armscii8 armscii8_general_ci ARMSCII-8 Armenian 1
-ascii ascii_general_ci US ASCII 1
-big5 big5_chinese_ci Big5 Traditional Chinese 2
-binary binary Binary pseudo charset 1
-cp1250 cp1250_general_ci Windows Central European 1
-cp1251 cp1251_general_ci Windows Cyrillic 1
-cp1256 cp1256_general_ci Windows Arabic 1
-cp1257 cp1257_general_ci Windows Baltic 1
-cp850 cp850_general_ci DOS West European 1
-cp852 cp852_general_ci DOS Central European 1
-cp866 cp866_general_ci DOS Russian 1
-cp932 cp932_japanese_ci SJIS for Windows Japanese 2
-dec8 dec8_swedish_ci DEC West European 1
-eucjpms eucjpms_japanese_ci UJIS for Windows Japanese 3
-euckr euckr_korean_ci EUC-KR Korean 2
-gb2312 gb2312_chinese_ci GB2312 Simplified Chinese 2
-gbk gbk_chinese_ci GBK Simplified Chinese 2
-geostd8 geostd8_general_ci GEOSTD8 Georgian 1
-greek greek_general_ci ISO 8859-7 Greek 1
-hebrew hebrew_general_ci ISO 8859-8 Hebrew 1
-hp8 hp8_english_ci HP West European 1
-keybcs2 keybcs2_general_ci DOS Kamenicky Czech-Slovak 1
-koi8r koi8r_general_ci KOI8-R Relcom Russian 1
-koi8u koi8u_general_ci KOI8-U Ukrainian 1
-latin1 latin1_swedish_ci cp1252 West European 1
-latin2 latin2_general_ci ISO 8859-2 Central European 1
-latin5 latin5_turkish_ci ISO 8859-9 Turkish 1
-latin7 latin7_general_ci ISO 8859-13 Baltic 1
-macce macce_general_ci Mac Central European 1
-macroman macroman_general_ci Mac West European 1
-sjis sjis_japanese_ci Shift-JIS Japanese 2
-swe7 swe7_swedish_ci 7bit Swedish 1
-tis620 tis620_thai_ci TIS620 Thai 1
-ucs2 ucs2_general_ci UCS-2 Unicode 2
-ujis ujis_japanese_ci EUC-JP Japanese 3
-utf8 utf8_general_ci UTF-8 Unicode 3
-
-SELECT *
-FROM information_schema.collations
-ORDER BY collation_name;
-COLLATION_NAME CHARACTER_SET_NAME ID IS_DEFAULT IS_COMPILED SORTLEN
-armscii8_bin armscii8 64 0
-armscii8_general_ci armscii8 32 Yes 0
-ascii_bin ascii 65 0
-ascii_general_ci ascii 11 Yes 0
-big5_bin big5 84 Yes 1
-big5_chinese_ci big5 1 Yes Yes 1
-binary binary 63 Yes Yes 1
-cp1250_bin cp1250 66 Yes 1
-cp1250_croatian_ci cp1250 44 Yes 1
-cp1250_czech_cs cp1250 34 Yes 2
-cp1250_general_ci cp1250 26 Yes Yes 1
-cp1250_polish_ci cp1250 99 Yes 1
-cp1251_bin cp1251 50 0
-cp1251_bulgarian_ci cp1251 14 0
-cp1251_general_ci cp1251 51 Yes 0
-cp1251_general_cs cp1251 52 0
-cp1251_ukrainian_ci cp1251 23 0
-cp1256_bin cp1256 67 0
-cp1256_general_ci cp1256 57 Yes 0
-cp1257_bin cp1257 58 0
-cp1257_general_ci cp1257 59 Yes 0
-cp1257_lithuanian_ci cp1257 29 0
-cp850_bin cp850 80 0
-cp850_general_ci cp850 4 Yes 0
-cp852_bin cp852 81 0
-cp852_general_ci cp852 40 Yes 0
-cp866_bin cp866 68 0
-cp866_general_ci cp866 36 Yes 0
-cp932_bin cp932 96 Yes 1
-cp932_japanese_ci cp932 95 Yes Yes 1
-dec8_bin dec8 69 0
-dec8_swedish_ci dec8 3 Yes 0
-eucjpms_bin eucjpms 98 Yes 1
-eucjpms_japanese_ci eucjpms 97 Yes Yes 1
-euckr_bin euckr 85 Yes 1
-euckr_korean_ci euckr 19 Yes Yes 1
-gb2312_bin gb2312 86 Yes 1
-gb2312_chinese_ci gb2312 24 Yes Yes 1
-gbk_bin gbk 87 Yes 1
-gbk_chinese_ci gbk 28 Yes Yes 1
-geostd8_bin geostd8 93 0
-geostd8_general_ci geostd8 92 Yes 0
-greek_bin greek 70 0
-greek_general_ci greek 25 Yes 0
-hebrew_bin hebrew 71 0
-hebrew_general_ci hebrew 16 Yes 0
-hp8_bin hp8 72 0
-hp8_english_ci hp8 6 Yes 0
-keybcs2_bin keybcs2 73 0
-keybcs2_general_ci keybcs2 37 Yes 0
-koi8r_bin koi8r 74 0
-koi8r_general_ci koi8r 7 Yes 0
-koi8u_bin koi8u 75 0
-koi8u_general_ci koi8u 22 Yes 0
-latin1_bin latin1 47 Yes 1
-latin1_danish_ci latin1 15 Yes 1
-latin1_general_ci latin1 48 Yes 1
-latin1_general_cs latin1 49 Yes 1
-latin1_german1_ci latin1 5 Yes 1
-latin1_german2_ci latin1 31 Yes 2
-latin1_spanish_ci latin1 94 Yes 1
-latin1_swedish_ci latin1 8 Yes Yes 1
-latin2_bin latin2 77 Yes 1
-latin2_croatian_ci latin2 27 Yes 1
-latin2_czech_cs latin2 2 Yes 4
-latin2_general_ci latin2 9 Yes Yes 1
-latin2_hungarian_ci latin2 21 Yes 1
-latin5_bin latin5 78 0
-latin5_turkish_ci latin5 30 Yes 0
-latin7_bin latin7 79 0
-latin7_estonian_cs latin7 20 0
-latin7_general_ci latin7 41 Yes 0
-latin7_general_cs latin7 42 0
-macce_bin macce 43 0
-macce_general_ci macce 38 Yes 0
-macroman_bin macroman 53 0
-macroman_general_ci macroman 39 Yes 0
-sjis_bin sjis 88 Yes 1
-sjis_japanese_ci sjis 13 Yes Yes 1
-swe7_bin swe7 82 0
-swe7_swedish_ci swe7 10 Yes 0
-tis620_bin tis620 89 Yes 1
-tis620_thai_ci tis620 18 Yes Yes 4
-ucs2_bin ucs2 90 Yes 1
-ucs2_czech_ci ucs2 138 Yes 8
-ucs2_danish_ci ucs2 139 Yes 8
-ucs2_esperanto_ci ucs2 145 Yes 8
-ucs2_estonian_ci ucs2 134 Yes 8
-ucs2_general_ci ucs2 35 Yes Yes 1
-ucs2_hungarian_ci ucs2 146 Yes 8
-ucs2_icelandic_ci ucs2 129 Yes 8
-ucs2_latvian_ci ucs2 130 Yes 8
-ucs2_lithuanian_ci ucs2 140 Yes 8
-ucs2_persian_ci ucs2 144 Yes 8
-ucs2_polish_ci ucs2 133 Yes 8
-ucs2_romanian_ci ucs2 131 Yes 8
-ucs2_roman_ci ucs2 143 Yes 8
-ucs2_slovak_ci ucs2 141 Yes 8
-ucs2_slovenian_ci ucs2 132 Yes 8
-ucs2_spanish2_ci ucs2 142 Yes 8
-ucs2_spanish_ci ucs2 135 Yes 8
-ucs2_swedish_ci ucs2 136 Yes 8
-ucs2_turkish_ci ucs2 137 Yes 8
-ucs2_unicode_ci ucs2 128 Yes 8
-ujis_bin ujis 91 Yes 1
-ujis_japanese_ci ujis 12 Yes Yes 1
-utf8_bin utf8 83 Yes 1
-utf8_czech_ci utf8 202 Yes 8
-utf8_danish_ci utf8 203 Yes 8
-utf8_esperanto_ci utf8 209 Yes 8
-utf8_estonian_ci utf8 198 Yes 8
-utf8_general_ci utf8 33 Yes Yes 1
-utf8_hungarian_ci utf8 210 Yes 8
-utf8_icelandic_ci utf8 193 Yes 8
-utf8_latvian_ci utf8 194 Yes 8
-utf8_lithuanian_ci utf8 204 Yes 8
-utf8_persian_ci utf8 208 Yes 8
-utf8_polish_ci utf8 197 Yes 8
-utf8_romanian_ci utf8 195 Yes 8
-utf8_roman_ci utf8 207 Yes 8
-utf8_slovak_ci utf8 205 Yes 8
-utf8_slovenian_ci utf8 196 Yes 8
-utf8_spanish2_ci utf8 206 Yes 8
-utf8_spanish_ci utf8 199 Yes 8
-utf8_swedish_ci utf8 200 Yes 8
-utf8_turkish_ci utf8 201 Yes 8
-utf8_unicode_ci utf8 192 Yes 8
-
-
-SELECT *
-FROM information_schema.collation_character_set_applicability
-ORDER BY collation_name, character_set_name;
-COLLATION_NAME CHARACTER_SET_NAME
-armscii8_bin armscii8
-armscii8_general_ci armscii8
-ascii_bin ascii
-ascii_general_ci ascii
-big5_bin big5
-big5_chinese_ci big5
-binary binary
-cp1250_bin cp1250
-cp1250_croatian_ci cp1250
-cp1250_czech_cs cp1250
-cp1250_general_ci cp1250
-cp1250_polish_ci cp1250
-cp1251_bin cp1251
-cp1251_bulgarian_ci cp1251
-cp1251_general_ci cp1251
-cp1251_general_cs cp1251
-cp1251_ukrainian_ci cp1251
-cp1256_bin cp1256
-cp1256_general_ci cp1256
-cp1257_bin cp1257
-cp1257_general_ci cp1257
-cp1257_lithuanian_ci cp1257
-cp850_bin cp850
-cp850_general_ci cp850
-cp852_bin cp852
-cp852_general_ci cp852
-cp866_bin cp866
-cp866_general_ci cp866
-cp932_bin cp932
-cp932_japanese_ci cp932
-dec8_bin dec8
-dec8_swedish_ci dec8
-eucjpms_bin eucjpms
-eucjpms_japanese_ci eucjpms
-euckr_bin euckr
-euckr_korean_ci euckr
-filename filename
-gb2312_bin gb2312
-gb2312_chinese_ci gb2312
-gbk_bin gbk
-gbk_chinese_ci gbk
-geostd8_bin geostd8
-geostd8_general_ci geostd8
-greek_bin greek
-greek_general_ci greek
-hebrew_bin hebrew
-hebrew_general_ci hebrew
-hp8_bin hp8
-hp8_english_ci hp8
-keybcs2_bin keybcs2
-keybcs2_general_ci keybcs2
-koi8r_bin koi8r
-koi8r_general_ci koi8r
-koi8u_bin koi8u
-koi8u_general_ci koi8u
-latin1_bin latin1
-latin1_danish_ci latin1
-latin1_general_ci latin1
-latin1_general_cs latin1
-latin1_german1_ci latin1
-latin1_german2_ci latin1
-latin1_spanish_ci latin1
-latin1_swedish_ci latin1
-latin2_bin latin2
-latin2_croatian_ci latin2
-latin2_czech_cs latin2
-latin2_general_ci latin2
-latin2_hungarian_ci latin2
-latin5_bin latin5
-latin5_turkish_ci latin5
-latin7_bin latin7
-latin7_estonian_cs latin7
-latin7_general_ci latin7
-latin7_general_cs latin7
-macce_bin macce
-macce_general_ci macce
-macroman_bin macroman
-macroman_general_ci macroman
-sjis_bin sjis
-sjis_japanese_ci sjis
-swe7_bin swe7
-swe7_swedish_ci swe7
-tis620_bin tis620
-tis620_thai_ci tis620
-ucs2_bin ucs2
-ucs2_czech_ci ucs2
-ucs2_danish_ci ucs2
-ucs2_esperanto_ci ucs2
-ucs2_estonian_ci ucs2
-ucs2_general_ci ucs2
-ucs2_hungarian_ci ucs2
-ucs2_icelandic_ci ucs2
-ucs2_latvian_ci ucs2
-ucs2_lithuanian_ci ucs2
-ucs2_persian_ci ucs2
-ucs2_polish_ci ucs2
-ucs2_romanian_ci ucs2
-ucs2_roman_ci ucs2
-ucs2_slovak_ci ucs2
-ucs2_slovenian_ci ucs2
-ucs2_spanish2_ci ucs2
-ucs2_spanish_ci ucs2
-ucs2_swedish_ci ucs2
-ucs2_turkish_ci ucs2
-ucs2_unicode_ci ucs2
-ujis_bin ujis
-ujis_japanese_ci ujis
-utf8_bin utf8
-utf8_czech_ci utf8
-utf8_danish_ci utf8
-utf8_esperanto_ci utf8
-utf8_estonian_ci utf8
-utf8_general_ci utf8
-utf8_hungarian_ci utf8
-utf8_icelandic_ci utf8
-utf8_latvian_ci utf8
-utf8_lithuanian_ci utf8
-utf8_persian_ci utf8
-utf8_polish_ci utf8
-utf8_romanian_ci utf8
-utf8_roman_ci utf8
-utf8_slovak_ci utf8
-utf8_slovenian_ci utf8
-utf8_spanish2_ci utf8
-utf8_spanish_ci utf8
-utf8_swedish_ci utf8
-utf8_turkish_ci utf8
-utf8_unicode_ci utf8
-# Switch to connection default + disconnect con
-DROP USER dbdict_test@localhost;
diff --git a/mysql-test/suite/funcs_1/r/is_columns_is_embedded.result b/mysql-test/suite/funcs_1/r/is_columns_is_embedded.result
index d5e1309e39f..59ad695c413 100644
--- a/mysql-test/suite/funcs_1/r/is_columns_is_embedded.result
+++ b/mysql-test/suite/funcs_1/r/is_columns_is_embedded.result
@@ -166,7 +166,7 @@ NULL information_schema PROCESSLIST HOST 3 NO varchar 64 192 NULL NULL utf8 utf
NULL information_schema PROCESSLIST ID 1 0 NO bigint NULL NULL 19 0 NULL NULL bigint(4)
NULL information_schema PROCESSLIST INFO 8 NULL YES longtext 4294967295 4294967295 NULL NULL utf8 utf8_general_ci longtext
NULL information_schema PROCESSLIST STATE 7 NULL YES varchar 64 192 NULL NULL utf8 utf8_general_ci varchar(64)
-NULL information_schema PROCESSLIST TIME 6 0 NO bigint NULL NULL 19 0 NULL NULL bigint(7)
+NULL information_schema PROCESSLIST TIME 6 0 NO int NULL NULL 10 0 NULL NULL int(7)
NULL information_schema PROCESSLIST USER 2 NO varchar 16 48 NULL NULL utf8 utf8_general_ci varchar(16)
NULL information_schema REFERENTIAL_CONSTRAINTS CONSTRAINT_CATALOG 1 NULL YES varchar 512 1536 NULL NULL utf8 utf8_general_ci varchar(512)
NULL information_schema REFERENTIAL_CONSTRAINTS CONSTRAINT_NAME 3 NO varchar 64 192 NULL NULL utf8 utf8_general_ci varchar(64)
@@ -340,6 +340,7 @@ ORDER BY CHARACTER_SET_NAME, COLLATION_NAME, COL_CML;
COL_CML DATA_TYPE CHARACTER_SET_NAME COLLATION_NAME
NULL bigint NULL NULL
NULL datetime NULL NULL
+NULL int NULL NULL
--> CHAR(0) is allowed (see manual), and here both CHARACHTER_* values
--> are 0, which is intended behavior, and the result of 0 / 0 IS NULL
SELECT CHARACTER_OCTET_LENGTH / CHARACTER_MAXIMUM_LENGTH AS COL_CML,
@@ -519,7 +520,7 @@ NULL information_schema PROCESSLIST ID bigint NULL NULL NULL NULL bigint(4)
3.0000 information_schema PROCESSLIST HOST varchar 64 192 utf8 utf8_general_ci varchar(64)
3.0000 information_schema PROCESSLIST DB varchar 64 192 utf8 utf8_general_ci varchar(64)
3.0000 information_schema PROCESSLIST COMMAND varchar 16 48 utf8 utf8_general_ci varchar(16)
-NULL information_schema PROCESSLIST TIME bigint NULL NULL NULL NULL bigint(7)
+NULL information_schema PROCESSLIST TIME int NULL NULL NULL NULL int(7)
3.0000 information_schema PROCESSLIST STATE varchar 64 192 utf8 utf8_general_ci varchar(64)
1.0000 information_schema PROCESSLIST INFO longtext 4294967295 4294967295 utf8 utf8_general_ci longtext
3.0000 information_schema REFERENTIAL_CONSTRAINTS CONSTRAINT_CATALOG varchar 512 1536 utf8 utf8_general_ci varchar(512)
diff --git a/mysql-test/suite/funcs_1/r/is_columns_myisam_embedded.result b/mysql-test/suite/funcs_1/r/is_columns_myisam_embedded.result
index d22c5cc06f7..2721dcf3c6e 100644
--- a/mysql-test/suite/funcs_1/r/is_columns_myisam_embedded.result
+++ b/mysql-test/suite/funcs_1/r/is_columns_myisam_embedded.result
@@ -514,7 +514,7 @@ NULL test tb1 f6 6 NULL YES mediumtext 16777215 16777215 NULL NULL latin1 latin1
NULL test tb1 f7 7 NULL YES longtext 4294967295 4294967295 NULL NULL latin1 latin1_swedish_ci longtext
NULL test tb1 f8 8 NULL YES tinyblob 255 255 NULL NULL NULL NULL tinyblob
NULL test tb1 f9 9 NULL YES blob 65535 65535 NULL NULL NULL NULL blob
-NULL test tb2 f100 42 00000000000000000008.8 NO double unsigned zerofill NULL NULL 22 NULL NULL NULL double unsigned zerofill
+NULL test tb2 f100 42 00000000000000000008.8 NO double NULL NULL 22 NULL NULL NULL double unsigned zerofill
NULL test tb2 f101 43 2000-01-01 NO date NULL NULL NULL NULL NULL NULL date
NULL test tb2 f102 44 00:00:20 NO time NULL NULL NULL NULL NULL NULL time
NULL test tb2 f103 45 0002-02-02 00:00:00 NO datetime NULL NULL NULL NULL NULL NULL datetime
@@ -547,32 +547,32 @@ NULL test tb2 f70 12 NULL YES decimal NULL NULL 63 30 NULL NULL decimal(63,30) u
NULL test tb2 f71 13 NULL YES decimal NULL NULL 10 0 NULL NULL decimal(10,0) unsigned zerofill
NULL test tb2 f72 14 NULL YES decimal NULL NULL 63 30 NULL NULL decimal(63,30) unsigned zerofill
NULL test tb2 f73 15 NULL YES double NULL NULL 22 NULL NULL NULL double
-NULL test tb2 f74 16 NULL YES double unsigned NULL NULL 22 NULL NULL NULL double unsigned
-NULL test tb2 f75 17 NULL YES double unsigned zerofill NULL NULL 22 NULL NULL NULL double unsigned zerofill
-NULL test tb2 f76 18 NULL YES double unsigned zerofill NULL NULL 22 NULL NULL NULL double unsigned zerofill
+NULL test tb2 f74 16 NULL YES double NULL NULL 22 NULL NULL NULL double unsigned
+NULL test tb2 f75 17 NULL YES double NULL NULL 22 NULL NULL NULL double unsigned zerofill
+NULL test tb2 f76 18 NULL YES double NULL NULL 22 NULL NULL NULL double unsigned zerofill
NULL test tb2 f77 19 7.7 YES double NULL NULL 22 NULL NULL NULL double
-NULL test tb2 f78 20 7.7 YES double unsigned NULL NULL 22 NULL NULL NULL double unsigned
-NULL test tb2 f79 21 00000000000000000007.7 YES double unsigned zerofill NULL NULL 22 NULL NULL NULL double unsigned zerofill
-NULL test tb2 f80 22 00000000000000000008.8 YES double unsigned zerofill NULL NULL 22 NULL NULL NULL double unsigned zerofill
+NULL test tb2 f78 20 7.7 YES double NULL NULL 22 NULL NULL NULL double unsigned
+NULL test tb2 f79 21 00000000000000000007.7 YES double NULL NULL 22 NULL NULL NULL double unsigned zerofill
+NULL test tb2 f80 22 00000000000000000008.8 YES double NULL NULL 22 NULL NULL NULL double unsigned zerofill
NULL test tb2 f81 23 8.8 NO float NULL NULL 12 NULL NULL NULL float
-NULL test tb2 f82 24 8.8 NO float unsigned NULL NULL 12 NULL NULL NULL float unsigned
-NULL test tb2 f83 25 0000000008.8 NO float unsigned zerofill NULL NULL 12 NULL NULL NULL float unsigned zerofill
-NULL test tb2 f84 26 0000000008.8 NO float unsigned zerofill NULL NULL 12 NULL NULL NULL float unsigned zerofill
+NULL test tb2 f82 24 8.8 NO float NULL NULL 12 NULL NULL NULL float unsigned
+NULL test tb2 f83 25 0000000008.8 NO float NULL NULL 12 NULL NULL NULL float unsigned zerofill
+NULL test tb2 f84 26 0000000008.8 NO float NULL NULL 12 NULL NULL NULL float unsigned zerofill
NULL test tb2 f85 27 8.8 NO float NULL NULL 12 NULL NULL NULL float
NULL test tb2 f86 28 8.8 NO float NULL NULL 12 NULL NULL NULL float
-NULL test tb2 f87 29 8.8 NO float unsigned NULL NULL 12 NULL NULL NULL float unsigned
-NULL test tb2 f88 30 8.8 NO float unsigned NULL NULL 12 NULL NULL NULL float unsigned
-NULL test tb2 f89 31 0000000008.8 NO float unsigned zerofill NULL NULL 12 NULL NULL NULL float unsigned zerofill
-NULL test tb2 f90 32 0000000008.8 NO float unsigned zerofill NULL NULL 12 NULL NULL NULL float unsigned zerofill
-NULL test tb2 f91 33 0000000008.8 NO float unsigned zerofill NULL NULL 12 NULL NULL NULL float unsigned zerofill
-NULL test tb2 f92 34 0000000008.8 NO float unsigned zerofill NULL NULL 12 NULL NULL NULL float unsigned zerofill
+NULL test tb2 f87 29 8.8 NO float NULL NULL 12 NULL NULL NULL float unsigned
+NULL test tb2 f88 30 8.8 NO float NULL NULL 12 NULL NULL NULL float unsigned
+NULL test tb2 f89 31 0000000008.8 NO float NULL NULL 12 NULL NULL NULL float unsigned zerofill
+NULL test tb2 f90 32 0000000008.8 NO float NULL NULL 12 NULL NULL NULL float unsigned zerofill
+NULL test tb2 f91 33 0000000008.8 NO float NULL NULL 12 NULL NULL NULL float unsigned zerofill
+NULL test tb2 f92 34 0000000008.8 NO float NULL NULL 12 NULL NULL NULL float unsigned zerofill
NULL test tb2 f93 35 8.8 NO float NULL NULL 12 NULL NULL NULL float
NULL test tb2 f94 36 8.8 NO double NULL NULL 22 NULL NULL NULL double
-NULL test tb2 f95 37 8.8 NO float unsigned NULL NULL 12 NULL NULL NULL float unsigned
-NULL test tb2 f96 38 8.8 NO double unsigned NULL NULL 22 NULL NULL NULL double unsigned
-NULL test tb2 f97 39 0000000008.8 NO float unsigned zerofill NULL NULL 12 NULL NULL NULL float unsigned zerofill
-NULL test tb2 f98 40 00000000000000000008.8 NO double unsigned zerofill NULL NULL 22 NULL NULL NULL double unsigned zerofill
-NULL test tb2 f99 41 0000000008.8 NO float unsigned zerofill NULL NULL 12 NULL NULL NULL float unsigned zerofill
+NULL test tb2 f95 37 8.8 NO float NULL NULL 12 NULL NULL NULL float unsigned
+NULL test tb2 f96 38 8.8 NO double NULL NULL 22 NULL NULL NULL double unsigned
+NULL test tb2 f97 39 0000000008.8 NO float NULL NULL 12 NULL NULL NULL float unsigned zerofill
+NULL test tb2 f98 40 00000000000000000008.8 NO double NULL NULL 22 NULL NULL NULL double unsigned zerofill
+NULL test tb2 f99 41 0000000008.8 NO float NULL NULL 12 NULL NULL NULL float unsigned zerofill
NULL test tb3 f118 1 a NO char 1 1 NULL NULL latin1 latin1_swedish_ci char(1)
NULL test tb3 f119 2 NO char 1 1 NULL NULL latin1 latin1_bin char(1)
NULL test tb3 f120 3 NO char 1 1 NULL NULL latin1 latin1_swedish_ci char(1)
@@ -646,33 +646,33 @@ NULL test tb4 f187 12 000000000000000000000000000000009.000000000000000000000000
NULL test tb4 f188 13 0000000009 NO decimal NULL NULL 10 0 NULL NULL decimal(10,0) unsigned zerofill
NULL test tb4 f189 14 000000000000000000000000000000009.000000000000000000000000000000 NO decimal NULL NULL 63 30 NULL NULL decimal(63,30) unsigned zerofill
NULL test tb4 f190 15 88.8 NO double NULL NULL 22 NULL NULL NULL double
-NULL test tb4 f191 16 88.8 NO double unsigned NULL NULL 22 NULL NULL NULL double unsigned
-NULL test tb4 f192 17 00000000000000000088.8 NO double unsigned zerofill NULL NULL 22 NULL NULL NULL double unsigned zerofill
-NULL test tb4 f193 18 00000000000000000088.8 NO double unsigned zerofill NULL NULL 22 NULL NULL NULL double unsigned zerofill
+NULL test tb4 f191 16 88.8 NO double NULL NULL 22 NULL NULL NULL double unsigned
+NULL test tb4 f192 17 00000000000000000088.8 NO double NULL NULL 22 NULL NULL NULL double unsigned zerofill
+NULL test tb4 f193 18 00000000000000000088.8 NO double NULL NULL 22 NULL NULL NULL double unsigned zerofill
NULL test tb4 f194 19 55.5 NO double NULL NULL 22 NULL NULL NULL double
-NULL test tb4 f195 20 55.5 NO double unsigned NULL NULL 22 NULL NULL NULL double unsigned
-NULL test tb4 f196 21 00000000000000000055.5 NO double unsigned zerofill NULL NULL 22 NULL NULL NULL double unsigned zerofill
-NULL test tb4 f197 22 00000000000000000055.5 NO double unsigned zerofill NULL NULL 22 NULL NULL NULL double unsigned zerofill
+NULL test tb4 f195 20 55.5 NO double NULL NULL 22 NULL NULL NULL double unsigned
+NULL test tb4 f196 21 00000000000000000055.5 NO double NULL NULL 22 NULL NULL NULL double unsigned zerofill
+NULL test tb4 f197 22 00000000000000000055.5 NO double NULL NULL 22 NULL NULL NULL double unsigned zerofill
NULL test tb4 f198 23 NULL YES float NULL NULL 12 NULL NULL NULL float
-NULL test tb4 f199 24 NULL YES float unsigned NULL NULL 12 NULL NULL NULL float unsigned
-NULL test tb4 f200 25 NULL YES float unsigned zerofill NULL NULL 12 NULL NULL NULL float unsigned zerofill
-NULL test tb4 f201 26 NULL YES float unsigned zerofill NULL NULL 12 NULL NULL NULL float unsigned zerofill
+NULL test tb4 f199 24 NULL YES float NULL NULL 12 NULL NULL NULL float unsigned
+NULL test tb4 f200 25 NULL YES float NULL NULL 12 NULL NULL NULL float unsigned zerofill
+NULL test tb4 f201 26 NULL YES float NULL NULL 12 NULL NULL NULL float unsigned zerofill
NULL test tb4 f202 27 NULL YES float NULL NULL 12 NULL NULL NULL float
NULL test tb4 f203 28 NULL YES float NULL NULL 12 NULL NULL NULL float
-NULL test tb4 f204 29 NULL YES float unsigned NULL NULL 12 NULL NULL NULL float unsigned
-NULL test tb4 f205 30 NULL YES float unsigned NULL NULL 12 NULL NULL NULL float unsigned
-NULL test tb4 f206 31 NULL YES float unsigned zerofill NULL NULL 12 NULL NULL NULL float unsigned zerofill
-NULL test tb4 f207 32 NULL YES float unsigned zerofill NULL NULL 12 NULL NULL NULL float unsigned zerofill
-NULL test tb4 f208 33 NULL YES float unsigned zerofill NULL NULL 12 NULL NULL NULL float unsigned zerofill
-NULL test tb4 f209 34 NULL YES float unsigned zerofill NULL NULL 12 NULL NULL NULL float unsigned zerofill
+NULL test tb4 f204 29 NULL YES float NULL NULL 12 NULL NULL NULL float unsigned
+NULL test tb4 f205 30 NULL YES float NULL NULL 12 NULL NULL NULL float unsigned
+NULL test tb4 f206 31 NULL YES float NULL NULL 12 NULL NULL NULL float unsigned zerofill
+NULL test tb4 f207 32 NULL YES float NULL NULL 12 NULL NULL NULL float unsigned zerofill
+NULL test tb4 f208 33 NULL YES float NULL NULL 12 NULL NULL NULL float unsigned zerofill
+NULL test tb4 f209 34 NULL YES float NULL NULL 12 NULL NULL NULL float unsigned zerofill
NULL test tb4 f210 35 NULL YES float NULL NULL 12 NULL NULL NULL float
NULL test tb4 f211 36 NULL YES double NULL NULL 22 NULL NULL NULL double
-NULL test tb4 f212 37 NULL YES float unsigned NULL NULL 12 NULL NULL NULL float unsigned
-NULL test tb4 f213 38 NULL YES double unsigned NULL NULL 22 NULL NULL NULL double unsigned
-NULL test tb4 f214 39 NULL YES float unsigned zerofill NULL NULL 12 NULL NULL NULL float unsigned zerofill
-NULL test tb4 f215 40 NULL YES double unsigned zerofill NULL NULL 22 NULL NULL NULL double unsigned zerofill
-NULL test tb4 f216 41 NULL YES float unsigned zerofill NULL NULL 12 NULL NULL NULL float unsigned zerofill
-NULL test tb4 f217 42 NULL YES double unsigned zerofill NULL NULL 22 NULL NULL NULL double unsigned zerofill
+NULL test tb4 f212 37 NULL YES float NULL NULL 12 NULL NULL NULL float unsigned
+NULL test tb4 f213 38 NULL YES double NULL NULL 22 NULL NULL NULL double unsigned
+NULL test tb4 f214 39 NULL YES float NULL NULL 12 NULL NULL NULL float unsigned zerofill
+NULL test tb4 f215 40 NULL YES double NULL NULL 22 NULL NULL NULL double unsigned zerofill
+NULL test tb4 f216 41 NULL YES float NULL NULL 12 NULL NULL NULL float unsigned zerofill
+NULL test tb4 f217 42 NULL YES double NULL NULL 22 NULL NULL NULL double unsigned zerofill
NULL test tb4 f218 43 NULL YES date NULL NULL NULL NULL NULL NULL date
NULL test tb4 f219 44 NULL YES time NULL NULL NULL NULL NULL NULL time
NULL test tb4 f220 45 NULL YES datetime NULL NULL NULL NULL NULL NULL datetime
@@ -698,7 +698,7 @@ NULL test tb4 f239 64 NULL YES varbinary 1000 1000 NULL NULL NULL NULL varbinary
NULL test tb4 f240 65 NULL YES varchar 120 120 NULL NULL latin1 latin1_swedish_ci varchar(120)
NULL test tb4 f241 66 NULL YES char 100 100 NULL NULL latin1 latin1_swedish_ci char(100)
NULL test tb4 f242 67 NULL YES bit NULL NULL 30 NULL NULL NULL bit(30)
-NULL test1 tb2 f100 42 00000000000000000008.8 NO double unsigned zerofill NULL NULL 22 NULL NULL NULL double unsigned zerofill
+NULL test1 tb2 f100 42 00000000000000000008.8 NO double NULL NULL 22 NULL NULL NULL double unsigned zerofill
NULL test1 tb2 f101 43 2000-01-01 NO date NULL NULL NULL NULL NULL NULL date
NULL test1 tb2 f102 44 00:00:20 NO time NULL NULL NULL NULL NULL NULL time
NULL test1 tb2 f103 45 0002-02-02 00:00:00 NO datetime NULL NULL NULL NULL NULL NULL datetime
@@ -731,32 +731,32 @@ NULL test1 tb2 f70 12 NULL YES decimal NULL NULL 63 30 NULL NULL decimal(63,30)
NULL test1 tb2 f71 13 NULL YES decimal NULL NULL 10 0 NULL NULL decimal(10,0) unsigned zerofill
NULL test1 tb2 f72 14 NULL YES decimal NULL NULL 63 30 NULL NULL decimal(63,30) unsigned zerofill
NULL test1 tb2 f73 15 NULL YES double NULL NULL 22 NULL NULL NULL double
-NULL test1 tb2 f74 16 NULL YES double unsigned NULL NULL 22 NULL NULL NULL double unsigned
-NULL test1 tb2 f75 17 NULL YES double unsigned zerofill NULL NULL 22 NULL NULL NULL double unsigned zerofill
-NULL test1 tb2 f76 18 NULL YES double unsigned zerofill NULL NULL 22 NULL NULL NULL double unsigned zerofill
+NULL test1 tb2 f74 16 NULL YES double NULL NULL 22 NULL NULL NULL double unsigned
+NULL test1 tb2 f75 17 NULL YES double NULL NULL 22 NULL NULL NULL double unsigned zerofill
+NULL test1 tb2 f76 18 NULL YES double NULL NULL 22 NULL NULL NULL double unsigned zerofill
NULL test1 tb2 f77 19 7.7 YES double NULL NULL 22 NULL NULL NULL double
-NULL test1 tb2 f78 20 7.7 YES double unsigned NULL NULL 22 NULL NULL NULL double unsigned
-NULL test1 tb2 f79 21 00000000000000000007.7 YES double unsigned zerofill NULL NULL 22 NULL NULL NULL double unsigned zerofill
-NULL test1 tb2 f80 22 00000000000000000008.8 YES double unsigned zerofill NULL NULL 22 NULL NULL NULL double unsigned zerofill
+NULL test1 tb2 f78 20 7.7 YES double NULL NULL 22 NULL NULL NULL double unsigned
+NULL test1 tb2 f79 21 00000000000000000007.7 YES double NULL NULL 22 NULL NULL NULL double unsigned zerofill
+NULL test1 tb2 f80 22 00000000000000000008.8 YES double NULL NULL 22 NULL NULL NULL double unsigned zerofill
NULL test1 tb2 f81 23 8.8 NO float NULL NULL 12 NULL NULL NULL float
-NULL test1 tb2 f82 24 8.8 NO float unsigned NULL NULL 12 NULL NULL NULL float unsigned
-NULL test1 tb2 f83 25 0000000008.8 NO float unsigned zerofill NULL NULL 12 NULL NULL NULL float unsigned zerofill
-NULL test1 tb2 f84 26 0000000008.8 NO float unsigned zerofill NULL NULL 12 NULL NULL NULL float unsigned zerofill
+NULL test1 tb2 f82 24 8.8 NO float NULL NULL 12 NULL NULL NULL float unsigned
+NULL test1 tb2 f83 25 0000000008.8 NO float NULL NULL 12 NULL NULL NULL float unsigned zerofill
+NULL test1 tb2 f84 26 0000000008.8 NO float NULL NULL 12 NULL NULL NULL float unsigned zerofill
NULL test1 tb2 f85 27 8.8 NO float NULL NULL 12 NULL NULL NULL float
NULL test1 tb2 f86 28 8.8 NO float NULL NULL 12 NULL NULL NULL float
-NULL test1 tb2 f87 29 8.8 NO float unsigned NULL NULL 12 NULL NULL NULL float unsigned
-NULL test1 tb2 f88 30 8.8 NO float unsigned NULL NULL 12 NULL NULL NULL float unsigned
-NULL test1 tb2 f89 31 0000000008.8 NO float unsigned zerofill NULL NULL 12 NULL NULL NULL float unsigned zerofill
-NULL test1 tb2 f90 32 0000000008.8 NO float unsigned zerofill NULL NULL 12 NULL NULL NULL float unsigned zerofill
-NULL test1 tb2 f91 33 0000000008.8 NO float unsigned zerofill NULL NULL 12 NULL NULL NULL float unsigned zerofill
-NULL test1 tb2 f92 34 0000000008.8 NO float unsigned zerofill NULL NULL 12 NULL NULL NULL float unsigned zerofill
+NULL test1 tb2 f87 29 8.8 NO float NULL NULL 12 NULL NULL NULL float unsigned
+NULL test1 tb2 f88 30 8.8 NO float NULL NULL 12 NULL NULL NULL float unsigned
+NULL test1 tb2 f89 31 0000000008.8 NO float NULL NULL 12 NULL NULL NULL float unsigned zerofill
+NULL test1 tb2 f90 32 0000000008.8 NO float NULL NULL 12 NULL NULL NULL float unsigned zerofill
+NULL test1 tb2 f91 33 0000000008.8 NO float NULL NULL 12 NULL NULL NULL float unsigned zerofill
+NULL test1 tb2 f92 34 0000000008.8 NO float NULL NULL 12 NULL NULL NULL float unsigned zerofill
NULL test1 tb2 f93 35 8.8 NO float NULL NULL 12 NULL NULL NULL float
NULL test1 tb2 f94 36 8.8 NO double NULL NULL 22 NULL NULL NULL double
-NULL test1 tb2 f95 37 8.8 NO float unsigned NULL NULL 12 NULL NULL NULL float unsigned
-NULL test1 tb2 f96 38 8.8 NO double unsigned NULL NULL 22 NULL NULL NULL double unsigned
-NULL test1 tb2 f97 39 0000000008.8 NO float unsigned zerofill NULL NULL 12 NULL NULL NULL float unsigned zerofill
-NULL test1 tb2 f98 40 00000000000000000008.8 NO double unsigned zerofill NULL NULL 22 NULL NULL NULL double unsigned zerofill
-NULL test1 tb2 f99 41 0000000008.8 NO float unsigned zerofill NULL NULL 12 NULL NULL NULL float unsigned zerofill
+NULL test1 tb2 f95 37 8.8 NO float NULL NULL 12 NULL NULL NULL float unsigned
+NULL test1 tb2 f96 38 8.8 NO double NULL NULL 22 NULL NULL NULL double unsigned
+NULL test1 tb2 f97 39 0000000008.8 NO float NULL NULL 12 NULL NULL NULL float unsigned zerofill
+NULL test1 tb2 f98 40 00000000000000000008.8 NO double NULL NULL 22 NULL NULL NULL double unsigned zerofill
+NULL test1 tb2 f99 41 0000000008.8 NO float NULL NULL 12 NULL NULL NULL float unsigned zerofill
NULL test4 t6 f1 1 NULL YES char 20 20 NULL NULL latin1 latin1_swedish_ci char(20)
NULL test4 t6 f2 2 NULL YES char 25 25 NULL NULL latin1 latin1_swedish_ci char(25)
NULL test4 t6 f3 3 NULL YES date NULL NULL NULL NULL NULL NULL date
@@ -817,11 +817,7 @@ NULL date NULL NULL
NULL datetime NULL NULL
NULL decimal NULL NULL
NULL double NULL NULL
-NULL double unsigned NULL NULL
-NULL double unsigned zerofill NULL NULL
NULL float NULL NULL
-NULL float unsigned NULL NULL
-NULL float unsigned zerofill NULL NULL
NULL int NULL NULL
NULL mediumint NULL NULL
NULL smallint NULL NULL
@@ -963,33 +959,33 @@ NULL test tb2 f70 decimal NULL NULL NULL NULL decimal(63,30) unsigned zerofill
NULL test tb2 f71 decimal NULL NULL NULL NULL decimal(10,0) unsigned zerofill
NULL test tb2 f72 decimal NULL NULL NULL NULL decimal(63,30) unsigned zerofill
NULL test tb2 f73 double NULL NULL NULL NULL double
-NULL test tb2 f74 double unsigned NULL NULL NULL NULL double unsigned
-NULL test tb2 f75 double unsigned zerofill NULL NULL NULL NULL double unsigned zerofill
-NULL test tb2 f76 double unsigned zerofill NULL NULL NULL NULL double unsigned zerofill
+NULL test tb2 f74 double NULL NULL NULL NULL double unsigned
+NULL test tb2 f75 double NULL NULL NULL NULL double unsigned zerofill
+NULL test tb2 f76 double NULL NULL NULL NULL double unsigned zerofill
NULL test tb2 f77 double NULL NULL NULL NULL double
-NULL test tb2 f78 double unsigned NULL NULL NULL NULL double unsigned
-NULL test tb2 f79 double unsigned zerofill NULL NULL NULL NULL double unsigned zerofill
-NULL test tb2 f80 double unsigned zerofill NULL NULL NULL NULL double unsigned zerofill
+NULL test tb2 f78 double NULL NULL NULL NULL double unsigned
+NULL test tb2 f79 double NULL NULL NULL NULL double unsigned zerofill
+NULL test tb2 f80 double NULL NULL NULL NULL double unsigned zerofill
NULL test tb2 f81 float NULL NULL NULL NULL float
-NULL test tb2 f82 float unsigned NULL NULL NULL NULL float unsigned
-NULL test tb2 f83 float unsigned zerofill NULL NULL NULL NULL float unsigned zerofill
-NULL test tb2 f84 float unsigned zerofill NULL NULL NULL NULL float unsigned zerofill
+NULL test tb2 f82 float NULL NULL NULL NULL float unsigned
+NULL test tb2 f83 float NULL NULL NULL NULL float unsigned zerofill
+NULL test tb2 f84 float NULL NULL NULL NULL float unsigned zerofill
NULL test tb2 f85 float NULL NULL NULL NULL float
NULL test tb2 f86 float NULL NULL NULL NULL float
-NULL test tb2 f87 float unsigned NULL NULL NULL NULL float unsigned
-NULL test tb2 f88 float unsigned NULL NULL NULL NULL float unsigned
-NULL test tb2 f89 float unsigned zerofill NULL NULL NULL NULL float unsigned zerofill
-NULL test tb2 f90 float unsigned zerofill NULL NULL NULL NULL float unsigned zerofill
-NULL test tb2 f91 float unsigned zerofill NULL NULL NULL NULL float unsigned zerofill
-NULL test tb2 f92 float unsigned zerofill NULL NULL NULL NULL float unsigned zerofill
+NULL test tb2 f87 float NULL NULL NULL NULL float unsigned
+NULL test tb2 f88 float NULL NULL NULL NULL float unsigned
+NULL test tb2 f89 float NULL NULL NULL NULL float unsigned zerofill
+NULL test tb2 f90 float NULL NULL NULL NULL float unsigned zerofill
+NULL test tb2 f91 float NULL NULL NULL NULL float unsigned zerofill
+NULL test tb2 f92 float NULL NULL NULL NULL float unsigned zerofill
NULL test tb2 f93 float NULL NULL NULL NULL float
NULL test tb2 f94 double NULL NULL NULL NULL double
-NULL test tb2 f95 float unsigned NULL NULL NULL NULL float unsigned
-NULL test tb2 f96 double unsigned NULL NULL NULL NULL double unsigned
-NULL test tb2 f97 float unsigned zerofill NULL NULL NULL NULL float unsigned zerofill
-NULL test tb2 f98 double unsigned zerofill NULL NULL NULL NULL double unsigned zerofill
-NULL test tb2 f99 float unsigned zerofill NULL NULL NULL NULL float unsigned zerofill
-NULL test tb2 f100 double unsigned zerofill NULL NULL NULL NULL double unsigned zerofill
+NULL test tb2 f95 float NULL NULL NULL NULL float unsigned
+NULL test tb2 f96 double NULL NULL NULL NULL double unsigned
+NULL test tb2 f97 float NULL NULL NULL NULL float unsigned zerofill
+NULL test tb2 f98 double NULL NULL NULL NULL double unsigned zerofill
+NULL test tb2 f99 float NULL NULL NULL NULL float unsigned zerofill
+NULL test tb2 f100 double NULL NULL NULL NULL double unsigned zerofill
NULL test tb2 f101 date NULL NULL NULL NULL date
NULL test tb2 f102 time NULL NULL NULL NULL time
NULL test tb2 f103 datetime NULL NULL NULL NULL datetime
@@ -1080,33 +1076,33 @@ NULL test tb4 f187 decimal NULL NULL NULL NULL decimal(63,30) unsigned zerofill
NULL test tb4 f188 decimal NULL NULL NULL NULL decimal(10,0) unsigned zerofill
NULL test tb4 f189 decimal NULL NULL NULL NULL decimal(63,30) unsigned zerofill
NULL test tb4 f190 double NULL NULL NULL NULL double
-NULL test tb4 f191 double unsigned NULL NULL NULL NULL double unsigned
-NULL test tb4 f192 double unsigned zerofill NULL NULL NULL NULL double unsigned zerofill
-NULL test tb4 f193 double unsigned zerofill NULL NULL NULL NULL double unsigned zerofill
+NULL test tb4 f191 double NULL NULL NULL NULL double unsigned
+NULL test tb4 f192 double NULL NULL NULL NULL double unsigned zerofill
+NULL test tb4 f193 double NULL NULL NULL NULL double unsigned zerofill
NULL test tb4 f194 double NULL NULL NULL NULL double
-NULL test tb4 f195 double unsigned NULL NULL NULL NULL double unsigned
-NULL test tb4 f196 double unsigned zerofill NULL NULL NULL NULL double unsigned zerofill
-NULL test tb4 f197 double unsigned zerofill NULL NULL NULL NULL double unsigned zerofill
+NULL test tb4 f195 double NULL NULL NULL NULL double unsigned
+NULL test tb4 f196 double NULL NULL NULL NULL double unsigned zerofill
+NULL test tb4 f197 double NULL NULL NULL NULL double unsigned zerofill
NULL test tb4 f198 float NULL NULL NULL NULL float
-NULL test tb4 f199 float unsigned NULL NULL NULL NULL float unsigned
-NULL test tb4 f200 float unsigned zerofill NULL NULL NULL NULL float unsigned zerofill
-NULL test tb4 f201 float unsigned zerofill NULL NULL NULL NULL float unsigned zerofill
+NULL test tb4 f199 float NULL NULL NULL NULL float unsigned
+NULL test tb4 f200 float NULL NULL NULL NULL float unsigned zerofill
+NULL test tb4 f201 float NULL NULL NULL NULL float unsigned zerofill
NULL test tb4 f202 float NULL NULL NULL NULL float
NULL test tb4 f203 float NULL NULL NULL NULL float
-NULL test tb4 f204 float unsigned NULL NULL NULL NULL float unsigned
-NULL test tb4 f205 float unsigned NULL NULL NULL NULL float unsigned
-NULL test tb4 f206 float unsigned zerofill NULL NULL NULL NULL float unsigned zerofill
-NULL test tb4 f207 float unsigned zerofill NULL NULL NULL NULL float unsigned zerofill
-NULL test tb4 f208 float unsigned zerofill NULL NULL NULL NULL float unsigned zerofill
-NULL test tb4 f209 float unsigned zerofill NULL NULL NULL NULL float unsigned zerofill
+NULL test tb4 f204 float NULL NULL NULL NULL float unsigned
+NULL test tb4 f205 float NULL NULL NULL NULL float unsigned
+NULL test tb4 f206 float NULL NULL NULL NULL float unsigned zerofill
+NULL test tb4 f207 float NULL NULL NULL NULL float unsigned zerofill
+NULL test tb4 f208 float NULL NULL NULL NULL float unsigned zerofill
+NULL test tb4 f209 float NULL NULL NULL NULL float unsigned zerofill
NULL test tb4 f210 float NULL NULL NULL NULL float
NULL test tb4 f211 double NULL NULL NULL NULL double
-NULL test tb4 f212 float unsigned NULL NULL NULL NULL float unsigned
-NULL test tb4 f213 double unsigned NULL NULL NULL NULL double unsigned
-NULL test tb4 f214 float unsigned zerofill NULL NULL NULL NULL float unsigned zerofill
-NULL test tb4 f215 double unsigned zerofill NULL NULL NULL NULL double unsigned zerofill
-NULL test tb4 f216 float unsigned zerofill NULL NULL NULL NULL float unsigned zerofill
-NULL test tb4 f217 double unsigned zerofill NULL NULL NULL NULL double unsigned zerofill
+NULL test tb4 f212 float NULL NULL NULL NULL float unsigned
+NULL test tb4 f213 double NULL NULL NULL NULL double unsigned
+NULL test tb4 f214 float NULL NULL NULL NULL float unsigned zerofill
+NULL test tb4 f215 double NULL NULL NULL NULL double unsigned zerofill
+NULL test tb4 f216 float NULL NULL NULL NULL float unsigned zerofill
+NULL test tb4 f217 double NULL NULL NULL NULL double unsigned zerofill
NULL test tb4 f218 date NULL NULL NULL NULL date
NULL test tb4 f219 time NULL NULL NULL NULL time
NULL test tb4 f220 datetime NULL NULL NULL NULL datetime
@@ -1147,33 +1143,33 @@ NULL test1 tb2 f70 decimal NULL NULL NULL NULL decimal(63,30) unsigned zerofill
NULL test1 tb2 f71 decimal NULL NULL NULL NULL decimal(10,0) unsigned zerofill
NULL test1 tb2 f72 decimal NULL NULL NULL NULL decimal(63,30) unsigned zerofill
NULL test1 tb2 f73 double NULL NULL NULL NULL double
-NULL test1 tb2 f74 double unsigned NULL NULL NULL NULL double unsigned
-NULL test1 tb2 f75 double unsigned zerofill NULL NULL NULL NULL double unsigned zerofill
-NULL test1 tb2 f76 double unsigned zerofill NULL NULL NULL NULL double unsigned zerofill
+NULL test1 tb2 f74 double NULL NULL NULL NULL double unsigned
+NULL test1 tb2 f75 double NULL NULL NULL NULL double unsigned zerofill
+NULL test1 tb2 f76 double NULL NULL NULL NULL double unsigned zerofill
NULL test1 tb2 f77 double NULL NULL NULL NULL double
-NULL test1 tb2 f78 double unsigned NULL NULL NULL NULL double unsigned
-NULL test1 tb2 f79 double unsigned zerofill NULL NULL NULL NULL double unsigned zerofill
-NULL test1 tb2 f80 double unsigned zerofill NULL NULL NULL NULL double unsigned zerofill
+NULL test1 tb2 f78 double NULL NULL NULL NULL double unsigned
+NULL test1 tb2 f79 double NULL NULL NULL NULL double unsigned zerofill
+NULL test1 tb2 f80 double NULL NULL NULL NULL double unsigned zerofill
NULL test1 tb2 f81 float NULL NULL NULL NULL float
-NULL test1 tb2 f82 float unsigned NULL NULL NULL NULL float unsigned
-NULL test1 tb2 f83 float unsigned zerofill NULL NULL NULL NULL float unsigned zerofill
-NULL test1 tb2 f84 float unsigned zerofill NULL NULL NULL NULL float unsigned zerofill
+NULL test1 tb2 f82 float NULL NULL NULL NULL float unsigned
+NULL test1 tb2 f83 float NULL NULL NULL NULL float unsigned zerofill
+NULL test1 tb2 f84 float NULL NULL NULL NULL float unsigned zerofill
NULL test1 tb2 f85 float NULL NULL NULL NULL float
NULL test1 tb2 f86 float NULL NULL NULL NULL float
-NULL test1 tb2 f87 float unsigned NULL NULL NULL NULL float unsigned
-NULL test1 tb2 f88 float unsigned NULL NULL NULL NULL float unsigned
-NULL test1 tb2 f89 float unsigned zerofill NULL NULL NULL NULL float unsigned zerofill
-NULL test1 tb2 f90 float unsigned zerofill NULL NULL NULL NULL float unsigned zerofill
-NULL test1 tb2 f91 float unsigned zerofill NULL NULL NULL NULL float unsigned zerofill
-NULL test1 tb2 f92 float unsigned zerofill NULL NULL NULL NULL float unsigned zerofill
+NULL test1 tb2 f87 float NULL NULL NULL NULL float unsigned
+NULL test1 tb2 f88 float NULL NULL NULL NULL float unsigned
+NULL test1 tb2 f89 float NULL NULL NULL NULL float unsigned zerofill
+NULL test1 tb2 f90 float NULL NULL NULL NULL float unsigned zerofill
+NULL test1 tb2 f91 float NULL NULL NULL NULL float unsigned zerofill
+NULL test1 tb2 f92 float NULL NULL NULL NULL float unsigned zerofill
NULL test1 tb2 f93 float NULL NULL NULL NULL float
NULL test1 tb2 f94 double NULL NULL NULL NULL double
-NULL test1 tb2 f95 float unsigned NULL NULL NULL NULL float unsigned
-NULL test1 tb2 f96 double unsigned NULL NULL NULL NULL double unsigned
-NULL test1 tb2 f97 float unsigned zerofill NULL NULL NULL NULL float unsigned zerofill
-NULL test1 tb2 f98 double unsigned zerofill NULL NULL NULL NULL double unsigned zerofill
-NULL test1 tb2 f99 float unsigned zerofill NULL NULL NULL NULL float unsigned zerofill
-NULL test1 tb2 f100 double unsigned zerofill NULL NULL NULL NULL double unsigned zerofill
+NULL test1 tb2 f95 float NULL NULL NULL NULL float unsigned
+NULL test1 tb2 f96 double NULL NULL NULL NULL double unsigned
+NULL test1 tb2 f97 float NULL NULL NULL NULL float unsigned zerofill
+NULL test1 tb2 f98 double NULL NULL NULL NULL double unsigned zerofill
+NULL test1 tb2 f99 float NULL NULL NULL NULL float unsigned zerofill
+NULL test1 tb2 f100 double NULL NULL NULL NULL double unsigned zerofill
NULL test1 tb2 f101 date NULL NULL NULL NULL date
NULL test1 tb2 f102 time NULL NULL NULL NULL time
NULL test1 tb2 f103 datetime NULL NULL NULL NULL datetime
diff --git a/mysql-test/suite/funcs_1/r/is_columns_mysql_embedded.result b/mysql-test/suite/funcs_1/r/is_columns_mysql_embedded.result
index 1d37a87f868..9c9d3cd26de 100644
--- a/mysql-test/suite/funcs_1/r/is_columns_mysql_embedded.result
+++ b/mysql-test/suite/funcs_1/r/is_columns_mysql_embedded.result
@@ -48,7 +48,7 @@ NULL mysql event last_executed 10 NULL YES datetime NULL NULL NULL NULL NULL NUL
NULL mysql event modified 9 0000-00-00 00:00:00 NO timestamp NULL NULL NULL NULL NULL NULL timestamp
NULL mysql event name 2 NO char 64 192 NULL NULL utf8 utf8_general_ci char(64) PRI
NULL mysql event on_completion 14 DROP NO enum 8 24 NULL NULL utf8 utf8_general_ci enum('DROP','PRESERVE')
-NULL mysql event originator 17 NULL NO int NULL NULL 10 0 NULL NULL int(10)
+NULL mysql event originator 17 NULL NO int NULL NULL 10 0 NULL NULL int(10) unsigned
NULL mysql event sql_mode 15 NO set 478 1434 NULL NULL utf8 utf8_general_ci set('REAL_AS_FLOAT','PIPES_AS_CONCAT','ANSI_QUOTES','IGNORE_SPACE','NOT_USED','ONLY_FULL_GROUP_BY','NO_UNSIGNED_SUBTRACTION','NO_DIR_IN_CREATE','POSTGRESQL','ORACLE','MSSQL','DB2','MAXDB','NO_KEY_OPTIONS','NO_TABLE_OPTIONS','NO_FIELD_OPTIONS','MYSQL323','MYSQL40','ANSI','NO_AUTO_VALUE_ON_ZERO','NO_BACKSLASH_ESCAPES','STRICT_TRANS_TABLES','STRICT_ALL_TABLES','NO_ZERO_IN_DATE','NO_ZERO_DATE','INVALID_DATES','ERROR_FOR_DIVISION_BY_ZERO','TRADITIONAL','NO_AUTO_CREATE_USER','HIGH_NOT_PRECEDENCE','NO_ENGINE_SUBSTITUTION','PAD_CHAR_TO_FULL_LENGTH')
NULL mysql event starts 11 NULL YES datetime NULL NULL NULL NULL NULL NULL datetime
NULL mysql event status 13 ENABLED NO enum 18 54 NULL NULL utf8 utf8_general_ci enum('ENABLED','DISABLED','SLAVESIDE_DISABLED')
@@ -60,7 +60,7 @@ NULL mysql func type 4 NULL NO enum 9 27 NULL NULL utf8 utf8_general_ci enum('fu
NULL mysql general_log argument 6 NULL NO mediumtext 16777215 16777215 NULL NULL utf8 utf8_general_ci mediumtext
NULL mysql general_log command_type 5 NULL NO varchar 64 192 NULL NULL utf8 utf8_general_ci varchar(64)
NULL mysql general_log event_time 1 CURRENT_TIMESTAMP NO timestamp NULL NULL NULL NULL NULL NULL timestamp on update CURRENT_TIMESTAMP
-NULL mysql general_log server_id 4 NULL NO int NULL NULL 10 0 NULL NULL int(11)
+NULL mysql general_log server_id 4 NULL NO int NULL NULL 10 0 NULL NULL int(10) unsigned
NULL mysql general_log thread_id 3 NULL NO int NULL NULL 10 0 NULL NULL int(11)
NULL mysql general_log user_host 2 NULL NO mediumtext 16777215 16777215 NULL NULL utf8 utf8_general_ci mediumtext
NULL mysql help_category help_category_id 1 NULL NO smallint NULL NULL 5 0 NULL NULL smallint(5) unsigned PRI
@@ -150,7 +150,7 @@ NULL mysql slow_log lock_time 4 NULL NO time NULL NULL NULL NULL NULL NULL time
NULL mysql slow_log query_time 3 NULL NO time NULL NULL NULL NULL NULL NULL time
NULL mysql slow_log rows_examined 6 NULL NO int NULL NULL 10 0 NULL NULL int(11)
NULL mysql slow_log rows_sent 5 NULL NO int NULL NULL 10 0 NULL NULL int(11)
-NULL mysql slow_log server_id 10 NULL NO int NULL NULL 10 0 NULL NULL int(11)
+NULL mysql slow_log server_id 10 NULL NO int NULL NULL 10 0 NULL NULL int(10) unsigned
NULL mysql slow_log sql_text 11 NULL NO mediumtext 16777215 16777215 NULL NULL utf8 utf8_general_ci mediumtext
NULL mysql slow_log start_time 1 CURRENT_TIMESTAMP NO timestamp NULL NULL NULL NULL NULL NULL timestamp on update CURRENT_TIMESTAMP
NULL mysql slow_log user_host 2 NULL NO mediumtext 16777215 16777215 NULL NULL utf8 utf8_general_ci mediumtext
@@ -329,7 +329,7 @@ NULL mysql event ends datetime NULL NULL NULL NULL datetime
3.0000 mysql event on_completion enum 8 24 utf8 utf8_general_ci enum('DROP','PRESERVE')
3.0000 mysql event sql_mode set 478 1434 utf8 utf8_general_ci set('REAL_AS_FLOAT','PIPES_AS_CONCAT','ANSI_QUOTES','IGNORE_SPACE','NOT_USED','ONLY_FULL_GROUP_BY','NO_UNSIGNED_SUBTRACTION','NO_DIR_IN_CREATE','POSTGRESQL','ORACLE','MSSQL','DB2','MAXDB','NO_KEY_OPTIONS','NO_TABLE_OPTIONS','NO_FIELD_OPTIONS','MYSQL323','MYSQL40','ANSI','NO_AUTO_VALUE_ON_ZERO','NO_BACKSLASH_ESCAPES','STRICT_TRANS_TABLES','STRICT_ALL_TABLES','NO_ZERO_IN_DATE','NO_ZERO_DATE','INVALID_DATES','ERROR_FOR_DIVISION_BY_ZERO','TRADITIONAL','NO_AUTO_CREATE_USER','HIGH_NOT_PRECEDENCE','NO_ENGINE_SUBSTITUTION','PAD_CHAR_TO_FULL_LENGTH')
3.0000 mysql event comment char 64 192 utf8 utf8_bin char(64)
-NULL mysql event originator int NULL NULL NULL NULL int(10)
+NULL mysql event originator int NULL NULL NULL NULL int(10) unsigned
1.0000 mysql event time_zone char 64 64 latin1 latin1_swedish_ci char(64)
3.0000 mysql event character_set_client char 32 96 utf8 utf8_bin char(32)
3.0000 mysql event collation_connection char 32 96 utf8 utf8_bin char(32)
@@ -342,7 +342,7 @@ NULL mysql func ret tinyint NULL NULL NULL NULL tinyint(1)
NULL mysql general_log event_time timestamp NULL NULL NULL NULL timestamp
1.0000 mysql general_log user_host mediumtext 16777215 16777215 utf8 utf8_general_ci mediumtext
NULL mysql general_log thread_id int NULL NULL NULL NULL int(11)
-NULL mysql general_log server_id int NULL NULL NULL NULL int(11)
+NULL mysql general_log server_id int NULL NULL NULL NULL int(10) unsigned
3.0000 mysql general_log command_type varchar 64 192 utf8 utf8_general_ci varchar(64)
1.0000 mysql general_log argument mediumtext 16777215 16777215 utf8 utf8_general_ci mediumtext
NULL mysql help_category help_category_id smallint NULL NULL NULL NULL smallint(5) unsigned
@@ -434,7 +434,7 @@ NULL mysql slow_log rows_examined int NULL NULL NULL NULL int(11)
3.0000 mysql slow_log db varchar 512 1536 utf8 utf8_general_ci varchar(512)
NULL mysql slow_log last_insert_id int NULL NULL NULL NULL int(11)
NULL mysql slow_log insert_id int NULL NULL NULL NULL int(11)
-NULL mysql slow_log server_id int NULL NULL NULL NULL int(11)
+NULL mysql slow_log server_id int NULL NULL NULL NULL int(10) unsigned
1.0000 mysql slow_log sql_text mediumtext 16777215 16777215 utf8 utf8_general_ci mediumtext
3.0000 mysql tables_priv Host char 60 180 utf8 utf8_bin char(60)
3.0000 mysql tables_priv Db char 64 192 utf8 utf8_bin char(64)
diff --git a/mysql-test/suite/funcs_1/r/is_routines.result b/mysql-test/suite/funcs_1/r/is_routines.result
index e7a900f5c0b..14a7107778c 100644
--- a/mysql-test/suite/funcs_1/r/is_routines.result
+++ b/mysql-test/suite/funcs_1/r/is_routines.result
@@ -111,10 +111,11 @@ CREATE FUNCTION function_for_routines() RETURNS INT RETURN 0;
SELECT specific_name,routine_catalog,routine_schema,routine_name,routine_type,
routine_body,external_name,external_language,parameter_style,sql_path
FROM information_schema.routines
-WHERE routine_catalog IS NOT NULL OR external_name IS NOT NULL
+WHERE routine_schema = 'test' AND
+(routine_catalog IS NOT NULL OR external_name IS NOT NULL
OR external_language IS NOT NULL OR sql_path IS NOT NULL
OR routine_body <> 'SQL' OR parameter_style <> 'SQL'
- OR specific_name <> routine_name;
+ OR specific_name <> routine_name);
specific_name routine_catalog routine_schema routine_name routine_type routine_body external_name external_language parameter_style sql_path
DROP PROCEDURE sp_for_routines;
DROP FUNCTION function_for_routines;
diff --git a/mysql-test/suite/funcs_1/r/storedproc.result b/mysql-test/suite/funcs_1/r/storedproc.result
index 7e21ddf1544..3efb361dc82 100644
--- a/mysql-test/suite/funcs_1/r/storedproc.result
+++ b/mysql-test/suite/funcs_1/r/storedproc.result
@@ -18241,8 +18241,6 @@ END//
CALL sp70_n(-1e+40);
f1
-10000000000000000000000000000000000000000
-Warnings:
-Note 1265 Data truncated for column 'f1' at row 1
CALL sp70_n( -10000000000000000000000000000000000000000 );
f1
-10000000000000000000000000000000000000000
@@ -18255,8 +18253,6 @@ END//
CALL sp71_nu(1.00e+40);
f1
10000000000000000000000000000000000000000
-Warnings:
-Note 1265 Data truncated for column 'f1' at row 1
CALL sp71_nu( 10000000000000000000000000000000000000000 );
f1
10000000000000000000000000000000000000000
@@ -18269,8 +18265,6 @@ END//
CALL sp72_nuz(1.00e+40);
f1
0000000000000000000000010000000000000000000000000000000000000000
-Warnings:
-Note 1265 Data truncated for column 'f1' at row 1
CALL sp72_nuz( 10000000000000000000000000000000000000000 );
f1
0000000000000000000000010000000000000000000000000000000000000000
@@ -18283,8 +18277,6 @@ END//
CALL sp73_n_z(1.00e+40);
f1
0000000000000000000000010000000000000000000000000000000000000000
-Warnings:
-Note 1265 Data truncated for column 'f1' at row 1
CALL sp73_n_z( 10000000000000000000000000000000000000000 );
f1
0000000000000000000000010000000000000000000000000000000000000000
diff --git a/mysql-test/suite/funcs_1/storedproc/storedproc_06.inc b/mysql-test/suite/funcs_1/storedproc/storedproc_06.inc
index d0fc6092959..f2df99fb5a3 100644
--- a/mysql-test/suite/funcs_1/storedproc/storedproc_06.inc
+++ b/mysql-test/suite/funcs_1/storedproc/storedproc_06.inc
@@ -53,7 +53,6 @@ flush privileges;
DROP PROCEDURE IF EXISTS sp1;
--enable_warnings
-let $MASTER_MYSOCK= query_get_value(SHOW VARIABLES LIKE 'socket', Value, 1);
--replace_result $MASTER_MYPORT MYSQL_PORT $MASTER_MYSOCK MYSQL_SOCK
connect (user1a, localhost, user_1, , db_storedproc_1);
--source suite/funcs_1/include/show_connection.inc
diff --git a/mysql-test/suite/funcs_1/storedproc/storedproc_10.inc b/mysql-test/suite/funcs_1/storedproc/storedproc_10.inc
index 69378541b51..83f5f2105c5 100644
--- a/mysql-test/suite/funcs_1/storedproc/storedproc_10.inc
+++ b/mysql-test/suite/funcs_1/storedproc/storedproc_10.inc
@@ -58,7 +58,6 @@ GRANT CREATE ROUTINE ON db_storedproc.* TO 'user_1'@'localhost';
GRANT SELECT ON db_storedproc.* TO 'user_2'@'localhost';
FLUSH PRIVILEGES;
-let $MASTER_MYSOCK= query_get_value(SHOW VARIABLES LIKE 'socket', Value, 1);
--replace_result $MASTER_MYPORT MYSQL_PORT $MASTER_MYSOCK MYSQL_SOCK
connect (user2_1, localhost, user_1, , db_storedproc);
--source suite/funcs_1/include/show_connection.inc
diff --git a/mysql-test/suite/funcs_1/datadict/charset_collation.inc b/mysql-test/suite/funcs_1/t/charset_collation.test
similarity index 53%
rename from mysql-test/suite/funcs_1/datadict/charset_collation.inc
rename to mysql-test/suite/funcs_1/t/charset_collation.test
index a1991346cfc..186eb1f5b85 100644
--- a/mysql-test/suite/funcs_1/datadict/charset_collation.inc
+++ b/mysql-test/suite/funcs_1/t/charset_collation.test
@@ -1,58 +1,16 @@
-# suite/funcs_1/datadict/charset_collation.inc
+# suite/funcs_1/t/charset_collation.test
#
# Tests checking the content of the information_schema tables
# character_sets
# collations
# collation_character_set_applicability
#
-#
-# The amount and properties of character_sets/collations depend on the
-# build type
-# 2007-12 MySQL 5.0, 2008-06 MySQL 5.1
-# ---------------------------------------------------------------------
-#
-# Variant 1 fits to
-# version_comment MySQL Enterprise Server (Commercial)
-# version_comment MySQL Enterprise Server (GPL)
-# version_comment MySQL Classic Server (Commercial)
-# version_comment MySQL Pushbuild Edition, build
-# (version_comment Source distribution
-# and
-# compile was without "max" - > no collation 'utf8_general_ci')
-#
-# Variant 2 fits to
-# version_comment MySQL Enterprise Server (GPL)
-# version_comment MySQL Classic Server (Commercial)
-# version_comment MySQL Pushbuild Edition, build
-# (version_comment Source distribution
-# and
-# compile was without "max" - > collation 'utf8_general_ci' exists)
-#
-# Difference between variant 1 and 2 is the collation 'utf8_general_ci'.
-#
-# Variant 3 fits to
-# version_comment MySQL Community Server (GPL)
-# version_comment MySQL Cluster Server (Commercial)
-# version_comment MySQL Advanced Server (GPL) 5.1
-# version_comment MySQL Advanced Server (Commercial) 5.1
-#
-# Difference between variant 3 and 2 is within the collation properties
-# IS_COMPILED and SORTLEN.
-#
-# 2008-06 All time excluded variant is "vanilla".
-# How to build "vanilla":
-# ./BUILD/autorun.sh
-# ./configure
-# ./make
-# Some properties of "vanilla"
-# version_comment Source distribution
-# Compared to the variants 1 to 3 a lot of character sets are missing.
-# Example: "ucs2_bin" is in variant 1 to 3 but not in "vanilla".
-#
# Created:
-# 2007-12-18 mleich - remove the unstable character_set/collation subtests
-# from include/datadict-master.inc
-# - create this new test
+# 2009-04-28 mleich Replace the charset_collation_* test which failed too often
+# because of changes
+# - in general available character sets and collations
+# - in build types
+# (Bug#40545, Bug#40209, Bug#40618, Bug#38346)
#
# Create a low privileged user.
@@ -61,8 +19,6 @@ DROP USER dbdict_test@localhost;
CREATE USER dbdict_test@localhost;
--echo # Establish connection con (user=dbdict_test)
-let $MASTER_MYSOCK= query_get_value(SHOW VARIABLES LIKE 'socket', Value, 1);
---replace_result $MASTER_MYPORT MYSQL_PORT $MASTER_MYSOCK MYSQL_SOCK
connect (con,localhost,dbdict_test,,);
################################################################################
#
@@ -98,32 +54,48 @@ connect (con,localhost,dbdict_test,,);
# combinations for which the current user and PUBLIC have no
# USAGE privilege.
#
-# Notes (2007-12-19 mleich):
+# Notes (2009-04-28 mleich):
# - The requirements are outdated because grant/revoke privilege for using a
# characterset/collation were never implemented.
-# Therefore the tests should simply check the content of these tables.
-#
+# Therefore the tests focus on the completeness and correctness of the
+# content (rows and columns) of these tables.
# - The amount of collations/character sets grows with new MySQL releases.
-#
-# - Even within the same release the amount of records within these tables
+# Even within the same release the amount of records within these tables
# can differ between different build types (community, enterprise, source,...)
-#
+# Therefore we limit the queries to character sets and collations which
+# - exist in all build types
+# - have in all build types the same "state".
+# The character set
+# - utf8 is used for Metadata
+# - ascii is a quite usual
+# The collations _general_ci and _bin seem
+# to be available all time.
#
################################################################################
+
+let $char_set_condition= character_set_name IN ('utf8','latin1','binary');
+let $collation_condition=
+ (collation_name LIKE CONCAT(character_set_name,'_general_ci')
+ OR
+ collation_name LIKE CONCAT(character_set_name,'_bin'));
--echo
-SELECT *
+eval SELECT *
FROM information_schema.character_sets
+WHERE $char_set_condition
ORDER BY character_set_name;
--echo
-SELECT *
+eval SELECT *
FROM information_schema.collations
+WHERE $char_set_condition
+ AND $collation_condition
ORDER BY collation_name;
-echo;
--echo
-SELECT *
+eval SELECT *
FROM information_schema.collation_character_set_applicability
+WHERE $char_set_condition
+ AND $collation_condition
ORDER BY collation_name, character_set_name;
diff --git a/mysql-test/suite/funcs_1/t/charset_collation_1.test b/mysql-test/suite/funcs_1/t/charset_collation_1.test
deleted file mode 100644
index 15777062a72..00000000000
--- a/mysql-test/suite/funcs_1/t/charset_collation_1.test
+++ /dev/null
@@ -1,32 +0,0 @@
-# Tests checking the content of the information_schema tables
-# character_sets
-# collations
-# collation_character_set_applicability
-#
-# Content variant 1 which should fit to
-# Enterprise or Classic builds (binaries provided by MySQL)
-# Pushbuilds
-# Source builds without "max"
-#
-# Please read suite/funcs_1/datadict/charset_collation.inc for
-# additional information.
-#
-# Created:
-# 2007-12-18 mleich - remove the unstable character_set/collation subtests
-# from include/datadict-master.inc
-# - create this new test
-#
-
-if (`SELECT EXISTS (SELECT 1 FROM information_schema.collations
- WHERE collation_name = 'utf8_general_cs')
- OR ( @@version_comment NOT LIKE '%Source%'
- AND @@version_comment NOT LIKE '%Enterprise%'
- AND @@version_comment NOT LIKE '%Classic%'
- AND @@version_comment NOT LIKE '%Pushbuild%')
- OR (SELECT count(*) = 0 FROM information_schema.collations
- WHERE collation_name = 'ucs2_bin')`)
-{
- skip Test needs Enterprise, Classic , regular Pushbuild or Source-without-max build;
-}
-
---source suite/funcs_1/datadict/charset_collation.inc
diff --git a/mysql-test/suite/funcs_1/t/charset_collation_2.test b/mysql-test/suite/funcs_1/t/charset_collation_2.test
deleted file mode 100644
index d4924953b7d..00000000000
--- a/mysql-test/suite/funcs_1/t/charset_collation_2.test
+++ /dev/null
@@ -1,24 +0,0 @@
-# Tests checking the content of the information_schema tables
-# character_sets
-# collations
-# collation_character_set_applicability
-#
-# Content variant 2 (compile from source with "max")
-#
-# Please read suite/funcs_1/datadict/charset_collation.inc for
-# additional information.
-#
-# Created:
-# 2007-12-18 mleich - remove the unstable character_set/collation subtests
-# from include/datadict-master.inc
-# - create this new test
-#
-
-if (`SELECT @@version_comment NOT LIKE '%Source%'
- OR NOT EXISTS (SELECT 1 FROM information_schema.collations
- WHERE collation_name = 'utf8_general_cs')`)
-{
- skip Test needs Source build with "max";
-}
-
---source suite/funcs_1/datadict/charset_collation.inc
diff --git a/mysql-test/suite/funcs_1/t/charset_collation_3.test b/mysql-test/suite/funcs_1/t/charset_collation_3.test
deleted file mode 100644
index e88b44e4a0f..00000000000
--- a/mysql-test/suite/funcs_1/t/charset_collation_3.test
+++ /dev/null
@@ -1,25 +0,0 @@
-# Tests checking the content of the information_schema tables
-# character_sets
-# collations
-# collation_character_set_applicability
-#
-# Content variant 3 which should fit to
-# Community and Cluster builds (binaries provided by MySQL)
-#
-# Please read suite/funcs_1/datadict/charset_collation.inc for
-# additional information.
-#
-# Created:
-# 2007-12-18 mleich - remove the unstable character_set/collation subtests
-# from include/datadict-master.inc
-# - create this new test
-#
-
-if (`SELECT @@version_comment NOT LIKE '%Community%'
- AND @@version_comment NOT LIKE '%Cluster%'
- AND @@version_comment NOT LIKE '%Advanced%'`)
-{
- skip Test needs Community, Cluster or Advanced build;
-}
-
---source suite/funcs_1/datadict/charset_collation.inc
diff --git a/mysql-test/suite/funcs_1/t/disabled.def b/mysql-test/suite/funcs_1/t/disabled.def
index 69a69c60708..3f260ca49ba 100644
--- a/mysql-test/suite/funcs_1/t/disabled.def
+++ b/mysql-test/suite/funcs_1/t/disabled.def
@@ -11,6 +11,3 @@
##############################################################################
ndb_trig_1011ext: Bug#32656 NDB: Duplicate key error aborts transaction in handler. Doesn't talk back to SQL
-charset_collation_1: Bug#38346, Bug#40209, Bug#40545, Bug#40618
-charset_collation_2: Bug#38346, Bug#40209, Bug#40545, Bug#40618
-charset_collation_3: Bug#38346, Bug#40209, Bug#40545, Bug#40618
diff --git a/mysql-test/suite/funcs_1/t/is_basics_mixed.test b/mysql-test/suite/funcs_1/t/is_basics_mixed.test
index 7d03dc5f8b0..235b91c67d0 100644
--- a/mysql-test/suite/funcs_1/t/is_basics_mixed.test
+++ b/mysql-test/suite/funcs_1/t/is_basics_mixed.test
@@ -55,7 +55,6 @@ DROP USER 'testuser1'@'localhost';
CREATE USER 'testuser1'@'localhost';
# Low privileged user
--echo # Establish connection testuser1 (user=testuser1)
-let $MASTER_MYSOCK= query_get_value(SHOW VARIABLES LIKE 'socket', Value, 1);
--replace_result $MASTER_MYPORT MYSQL_PORT $MASTER_MYSOCK MYSQL_SOCK
connect (testuser1, localhost, testuser1, , test);
SELECT DATABASE();
diff --git a/mysql-test/suite/funcs_1/t/is_column_privileges.test b/mysql-test/suite/funcs_1/t/is_column_privileges.test
index 925d07b9657..cb8c50c01b7 100644
--- a/mysql-test/suite/funcs_1/t/is_column_privileges.test
+++ b/mysql-test/suite/funcs_1/t/is_column_privileges.test
@@ -132,7 +132,6 @@ WITH GRANT OPTION;
eval $select;
--echo # Establish connection testuser1 (user=testuser1)
-let $MASTER_MYSOCK= query_get_value(SHOW VARIABLES LIKE 'socket', Value, 1);
--replace_result $MASTER_MYPORT MYSQL_PORT $MASTER_MYSOCK MYSQL_SOCK
connect (testuser1, localhost, testuser1, , db_datadict);
eval $select;
diff --git a/mysql-test/suite/funcs_1/t/is_column_privileges_is_mysql_test.test b/mysql-test/suite/funcs_1/t/is_column_privileges_is_mysql_test.test
index 98d01c60838..33269fe929c 100644
--- a/mysql-test/suite/funcs_1/t/is_column_privileges_is_mysql_test.test
+++ b/mysql-test/suite/funcs_1/t/is_column_privileges_is_mysql_test.test
@@ -46,7 +46,6 @@ eval $my_show2;
eval $my_show3;
--echo # Establish connection testuser1 (user=testuser1)
-let $MASTER_MYSOCK= query_get_value(SHOW VARIABLES LIKE 'socket', Value, 1);
--replace_result $MASTER_MYPORT MYSQL_PORT $MASTER_MYSOCK MYSQL_SOCK
connect (testuser1, localhost, testuser1, , db_datadict);
eval $my_select;
diff --git a/mysql-test/suite/funcs_1/t/is_columns.test b/mysql-test/suite/funcs_1/t/is_columns.test
index 20b832ca5c3..efb52acd48c 100644
--- a/mysql-test/suite/funcs_1/t/is_columns.test
+++ b/mysql-test/suite/funcs_1/t/is_columns.test
@@ -148,7 +148,6 @@ eval $my_show2;
eval $my_show3;
--echo # Establish connection testuser1 (user=testuser1)
-let $MASTER_MYSOCK= query_get_value(SHOW VARIABLES LIKE 'socket', Value, 1);
--replace_result $MASTER_MYPORT MYSQL_PORT $MASTER_MYSOCK MYSQL_SOCK
connect (testuser1, localhost, testuser1, , db_datadict);
--source suite/funcs_1/datadict/datadict_bug_12777.inc
diff --git a/mysql-test/suite/funcs_1/t/is_schema_privileges.test b/mysql-test/suite/funcs_1/t/is_schema_privileges.test
index c1fc70b03f7..1f408d71b39 100644
--- a/mysql-test/suite/funcs_1/t/is_schema_privileges.test
+++ b/mysql-test/suite/funcs_1/t/is_schema_privileges.test
@@ -116,7 +116,6 @@ let $show_testuser1 = SHOW GRANTS FOR 'testuser1'@'localhost';
let $show_testuser2 = SHOW GRANTS FOR 'testuser2'@'localhost';
--echo # Establish connection testuser1 (user=testuser1)
-let $MASTER_MYSOCK= query_get_value(SHOW VARIABLES LIKE 'socket', Value, 1);
--replace_result $MASTER_MYPORT MYSQL_PORT $MASTER_MYSOCK MYSQL_SOCK
connect (testuser1, localhost, testuser1, , test);
GRANT SELECT ON db_datadict_4.* TO 'testuser2'@'localhost';
diff --git a/mysql-test/suite/funcs_1/t/is_schema_privileges_is_mysql_test.test b/mysql-test/suite/funcs_1/t/is_schema_privileges_is_mysql_test.test
index d7b703ed04a..3f60f71fe9a 100644
--- a/mysql-test/suite/funcs_1/t/is_schema_privileges_is_mysql_test.test
+++ b/mysql-test/suite/funcs_1/t/is_schema_privileges_is_mysql_test.test
@@ -46,7 +46,6 @@ eval $my_show2;
eval $my_show3;
--echo # Establish connection testuser1 (user=testuser1)
-let $MASTER_MYSOCK= query_get_value(SHOW VARIABLES LIKE 'socket', Value, 1);
--replace_result $MASTER_MYPORT MYSQL_PORT $MASTER_MYSOCK MYSQL_SOCK
connect (testuser1, localhost, testuser1, , db_datadict);
eval $my_select;
diff --git a/mysql-test/suite/funcs_1/t/is_schemata_is_mysql_test.test b/mysql-test/suite/funcs_1/t/is_schemata_is_mysql_test.test
index b5f13ab323c..9bfbf0cf335 100644
--- a/mysql-test/suite/funcs_1/t/is_schemata_is_mysql_test.test
+++ b/mysql-test/suite/funcs_1/t/is_schemata_is_mysql_test.test
@@ -46,7 +46,6 @@ eval $my_show2;
eval $my_show3;
--echo # Establish connection testuser1 (user=testuser1)
-let $MASTER_MYSOCK= query_get_value(SHOW VARIABLES LIKE 'socket', Value, 1);
--replace_result $MASTER_MYPORT MYSQL_PORT $MASTER_MYSOCK MYSQL_SOCK
connect (testuser1, localhost, testuser1, , db_datadict);
eval $my_select;
diff --git a/mysql-test/suite/funcs_1/t/is_statistics.test b/mysql-test/suite/funcs_1/t/is_statistics.test
index e202e7392ea..458892a6d91 100644
--- a/mysql-test/suite/funcs_1/t/is_statistics.test
+++ b/mysql-test/suite/funcs_1/t/is_statistics.test
@@ -140,7 +140,6 @@ eval $my_show1;
eval $my_show2;
--echo # Establish connection testuser1 (user=testuser1)
-let $MASTER_MYSOCK= query_get_value(SHOW VARIABLES LIKE 'socket', Value, 1);
--replace_result $MASTER_MYPORT MYSQL_PORT $MASTER_MYSOCK MYSQL_SOCK
connect (testuser1, localhost, testuser1, , test);
# nothing visible for testuser1
diff --git a/mysql-test/suite/funcs_1/t/is_table_constraints.test b/mysql-test/suite/funcs_1/t/is_table_constraints.test
index 730e805c91e..a64b3bfaa6e 100644
--- a/mysql-test/suite/funcs_1/t/is_table_constraints.test
+++ b/mysql-test/suite/funcs_1/t/is_table_constraints.test
@@ -132,7 +132,6 @@ eval $my_show1;
eval $my_show2;
--echo # Establish connection testuser1 (user=testuser1)
-let $MASTER_MYSOCK= query_get_value(SHOW VARIABLES LIKE 'socket', Value, 1);
--replace_result $MASTER_MYPORT MYSQL_PORT $MASTER_MYSOCK MYSQL_SOCK
connect (testuser1, localhost, testuser1, , db_datadict);
SHOW GRANTS FOR 'testuser1'@'localhost';
diff --git a/mysql-test/suite/funcs_1/t/is_table_privileges.test b/mysql-test/suite/funcs_1/t/is_table_privileges.test
index 27ce22816a2..5ea0dd7c6a7 100644
--- a/mysql-test/suite/funcs_1/t/is_table_privileges.test
+++ b/mysql-test/suite/funcs_1/t/is_table_privileges.test
@@ -116,7 +116,6 @@ WHERE table_name LIKE 'tb%'
ORDER BY grantee,table_schema,table_name,privilege_type;
--echo # Establish connection testuser1 (user=testuser1)
-let $MASTER_MYSOCK= query_get_value(SHOW VARIABLES LIKE 'socket', Value, 1);
--replace_result $MASTER_MYPORT MYSQL_PORT $MASTER_MYSOCK MYSQL_SOCK
connect (testuser1, localhost, testuser1, , db_datadict);
--replace_result $other_engine_type
diff --git a/mysql-test/suite/funcs_1/t/is_user_privileges.test b/mysql-test/suite/funcs_1/t/is_user_privileges.test
index 5f8c29ca39d..1d0d3e51aae 100644
--- a/mysql-test/suite/funcs_1/t/is_user_privileges.test
+++ b/mysql-test/suite/funcs_1/t/is_user_privileges.test
@@ -114,7 +114,6 @@ eval $my_select1;
eval $my_select2;
--echo # Establish connection testuser1 (user=testuser1)
-let $MASTER_MYSOCK= query_get_value(SHOW VARIABLES LIKE 'socket', Value, 1);
--replace_result $MASTER_MYPORT MYSQL_PORT $MASTER_MYSOCK MYSQL_SOCK
connect (testuser1, localhost, testuser1, , db_datadict);
eval $my_select1;
diff --git a/mysql-test/suite/funcs_1/t/myisam_views.test b/mysql-test/suite/funcs_1/t/myisam_views.test
index 461bc0e3549..fe72843cfaf 100644
--- a/mysql-test/suite/funcs_1/t/myisam_views.test
+++ b/mysql-test/suite/funcs_1/t/myisam_views.test
@@ -1,5 +1,7 @@
#### suite/funcs_1/t/myisam_views.test
+--source include/no_valgrind_without_big.inc
+
# MyISAM tables should be used
#
# Set $engine_type
diff --git a/mysql-test/suite/funcs_1/t/ndb_storedproc_06.tes b/mysql-test/suite/funcs_1/t/ndb_storedproc_06.tes
deleted file mode 100644
index ce061da2299..00000000000
--- a/mysql-test/suite/funcs_1/t/ndb_storedproc_06.tes
+++ /dev/null
@@ -1,9 +0,0 @@
-#### suite/funcs_1/t/innodb_storedproc_06.test
-#
-# 1. Check if InnoDB is available
---source include/have_innodb.inc
-
-# 2. Set $engine_type
-let $engine_type= innodb;
-
---source suite/funcs_1/storedproc/storedproc_06.inc
diff --git a/mysql-test/suite/funcs_1/t/ndb_storedproc_08.tes b/mysql-test/suite/funcs_1/t/ndb_storedproc_08.tes
deleted file mode 100644
index c8c289c5f49..00000000000
--- a/mysql-test/suite/funcs_1/t/ndb_storedproc_08.tes
+++ /dev/null
@@ -1,9 +0,0 @@
-#### suite/funcs_1/t/innodb_storedproc_08.test
-#
-# 1. Check if InnoDB is available
---source include/have_innodb.inc
-
-# 2. Set $engine_type
-let $engine_type= innodb;
-
---source suite/funcs_1/storedproc/storedproc_08.inc
diff --git a/mysql-test/suite/funcs_1/t/storedproc.test b/mysql-test/suite/funcs_1/t/storedproc.test
index 6877b751ed2..16c4d61bf58 100644
--- a/mysql-test/suite/funcs_1/t/storedproc.test
+++ b/mysql-test/suite/funcs_1/t/storedproc.test
@@ -10,6 +10,17 @@
#
############################################################################
+# Bug#37746 - Arithmetic range ("int") is smaller than expected
+# This code is in place to ensure this test is only skipped
+# for the Win64 platform
+if(`SELECT CONVERT(@@version_compile_os using latin1) IN ("Win64")`)
+{
+--skip Bug#37746 2009-07-07 pcrews Arithmetic range ("int") is smaller than expected
+}
+
+
+
+
# This test cannot be used for the embedded server because we check here
# privileges.
--source include/not_embedded.inc
@@ -817,7 +828,6 @@ CREATE PROCEDURE sp11() insert into mysql.t1 values('a');
--replace_column 13 created 14 modified
SELECT security_type from mysql.proc where specific_name='sp11';
-let $MASTER_MYSOCK= query_get_value(SHOW VARIABLES LIKE 'socket', Value, 1);
--replace_result $MASTER_MYPORT MYSQL_PORT $MASTER_MYSOCK MYSQL_SOCK
connect (u_1, localhost, user_1, , db_storedproc);
--source suite/funcs_1/include/show_connection.inc
@@ -22430,7 +22440,9 @@ BEGIN
END//
delimiter ;//
+--disable_warnings
CALL sp70_n(-1e+40);
+--enable_warnings
eval CALL sp70_n( $minus_40 );
@@ -22446,7 +22458,9 @@ BEGIN
END//
delimiter ;//
+--disable_warnings
CALL sp71_nu(1.00e+40);
+--enable_warnings
eval CALL sp71_nu( $plus_40 );
@@ -22462,7 +22476,9 @@ BEGIN
END//
delimiter ;//
+--disable_warnings
CALL sp72_nuz(1.00e+40);
+--enable_warnings
eval CALL sp72_nuz( $plus_40 );
@@ -22478,7 +22494,9 @@ BEGIN
END//
delimiter ;//
+--disable_warnings
CALL sp73_n_z(1.00e+40);
+--enable_warnings
eval CALL sp73_n_z( $plus_40 );
diff --git a/mysql-test/suite/funcs_1/triggers/triggers_03.inc b/mysql-test/suite/funcs_1/triggers/triggers_03.inc
index e5bea5b2005..9ef6a9ac9af 100644
--- a/mysql-test/suite/funcs_1/triggers/triggers_03.inc
+++ b/mysql-test/suite/funcs_1/triggers/triggers_03.inc
@@ -62,7 +62,6 @@ let $message= Testcase 3.5.3.2/6:;
grant SELECT on priv_db.t1 to test_yesprivs@localhost;
show grants for test_yesprivs@localhost;
- let $MASTER_MYSOCK= query_get_value(SHOW VARIABLES LIKE 'socket', Value, 1);
--replace_result $MASTER_MYPORT MASTER_MYPORT $MASTER_MYSOCK MASTER_MYSOCK
connect (no_privs,localhost,test_noprivs,PWD,test,$MASTER_MYPORT,$MASTER_MYSOCK);
--replace_result $MASTER_MYPORT MASTER_MYPORT $MASTER_MYSOCK MASTER_MYSOCK
diff --git a/mysql-test/suite/funcs_1/triggers/triggers_03e_columns.inc b/mysql-test/suite/funcs_1/triggers/triggers_03e_columns.inc
index 60928ba8f35..475063587d4 100644
--- a/mysql-test/suite/funcs_1/triggers/triggers_03e_columns.inc
+++ b/mysql-test/suite/funcs_1/triggers/triggers_03e_columns.inc
@@ -36,7 +36,6 @@ let $message= ####### Testcase for column privileges of triggers: #######;
grant SELECT,UPDATE on priv_db.* to test_noprivs@localhost;
show grants for test_noprivs@localhost;
- let $MASTER_MYSOCK= query_get_value(SHOW VARIABLES LIKE 'socket', Value, 1);
--replace_result $MASTER_MYPORT MASTER_MYPORT $MASTER_MYSOCK MASTER_MYSOCK
connect (yes_privs,localhost,test_yesprivs,PWD,test,$MASTER_MYPORT,$MASTER_MYSOCK);
diff --git a/mysql-test/suite/funcs_1/triggers/triggers_03e_db_level.inc b/mysql-test/suite/funcs_1/triggers/triggers_03e_db_level.inc
index cb9d8ddc78b..e5933eb84a8 100644
--- a/mysql-test/suite/funcs_1/triggers/triggers_03e_db_level.inc
+++ b/mysql-test/suite/funcs_1/triggers/triggers_03e_db_level.inc
@@ -37,7 +37,6 @@ let $message= Testcase for db level:;
show grants for test_noprivs@localhost;
# no trigger privilege->create trigger must fail:
- let $MASTER_MYSOCK= query_get_value(SHOW VARIABLES LIKE 'socket', Value, 1);
--replace_result $MASTER_MYPORT MASTER_MYPORT $MASTER_MYSOCK MASTER_MYSOCK
connect (yes_privs,localhost,test_yesprivs,PWD,test,$MASTER_MYPORT,$MASTER_MYSOCK);
let $message= no trigger privilege on db level for create:;
diff --git a/mysql-test/suite/funcs_1/triggers/triggers_03e_db_table_mix.inc b/mysql-test/suite/funcs_1/triggers/triggers_03e_db_table_mix.inc
index de9cf61f641..82f4a28f664 100644
--- a/mysql-test/suite/funcs_1/triggers/triggers_03e_db_table_mix.inc
+++ b/mysql-test/suite/funcs_1/triggers/triggers_03e_db_table_mix.inc
@@ -41,7 +41,6 @@ let $message= ####### Testcase for mix of db and table level: #######;
grant SELECT,INSERT on priv2_db.* to test_noprivs@localhost;
show grants for test_noprivs@localhost;
- let $MASTER_MYSOCK= query_get_value(SHOW VARIABLES LIKE 'socket', Value, 1);
--replace_result $MASTER_MYPORT MASTER_MYPORT $MASTER_MYSOCK MASTER_MYSOCK
connect (yes_privs,localhost,test_yesprivs,PWD,test,$MASTER_MYPORT,$MASTER_MYSOCK);
use priv1_db;
diff --git a/mysql-test/suite/funcs_1/triggers/triggers_03e_definer.inc b/mysql-test/suite/funcs_1/triggers/triggers_03e_definer.inc
index 18c8a3ebcd5..f1efff990f1 100644
--- a/mysql-test/suite/funcs_1/triggers/triggers_03e_definer.inc
+++ b/mysql-test/suite/funcs_1/triggers/triggers_03e_definer.inc
@@ -27,7 +27,6 @@ let $message= ######### Testcase for definer: ########;
revoke ALL PRIVILEGES, GRANT OPTION FROM test_yesprivs@localhost;
- let $MASTER_MYSOCK= query_get_value(SHOW VARIABLES LIKE 'socket', Value, 1);
--replace_result $MASTER_MYPORT MASTER_MYPORT $MASTER_MYSOCK MASTER_MYSOCK
connect (yes_privs,localhost,test_yesprivs,PWD,test,$MASTER_MYPORT,$MASTER_MYSOCK);
diff --git a/mysql-test/suite/funcs_1/triggers/triggers_03e_global_db_mix.inc b/mysql-test/suite/funcs_1/triggers/triggers_03e_global_db_mix.inc
index cd90d25aefd..b6f4af7e0a7 100644
--- a/mysql-test/suite/funcs_1/triggers/triggers_03e_global_db_mix.inc
+++ b/mysql-test/suite/funcs_1/triggers/triggers_03e_global_db_mix.inc
@@ -38,7 +38,6 @@ let $message= #### Testcase for mix of user(global) and db level: ####;
grant SELECT,INSERT on *.* to test_noprivs@localhost;
show grants for test_noprivs@localhost;
- let $MASTER_MYSOCK= query_get_value(SHOW VARIABLES LIKE 'socket', Value, 1);
--replace_result $MASTER_MYPORT MASTER_MYPORT $MASTER_MYSOCK MASTER_MYSOCK
connect (yes_privs,localhost,test_yesprivs,PWD,test,$MASTER_MYPORT,$MASTER_MYSOCK);
diff --git a/mysql-test/suite/funcs_1/triggers/triggers_03e_prepare.inc b/mysql-test/suite/funcs_1/triggers/triggers_03e_prepare.inc
index f1b3bbe2cb4..ea7c385768c 100644
--- a/mysql-test/suite/funcs_1/triggers/triggers_03e_prepare.inc
+++ b/mysql-test/suite/funcs_1/triggers/triggers_03e_prepare.inc
@@ -32,7 +32,6 @@ let $message= #### Testcase for trigger privilege on execution time ########;
revoke ALL PRIVILEGES, GRANT OPTION FROM test_yesprivs@localhost;
revoke ALL PRIVILEGES, GRANT OPTION FROM test_useprivs@localhost;
- let $MASTER_MYSOCK= query_get_value(SHOW VARIABLES LIKE 'socket', Value, 1);
--replace_result $MASTER_MYPORT MASTER_MYPORT $MASTER_MYSOCK MASTER_MYSOCK
connect (yes_privs,localhost,test_yesprivs,PWD,test,$MASTER_MYPORT,$MASTER_MYSOCK);
diff --git a/mysql-test/suite/funcs_1/triggers/triggers_03e_table_level.inc b/mysql-test/suite/funcs_1/triggers/triggers_03e_table_level.inc
index 9cc272c09bc..94f30fe13c2 100644
--- a/mysql-test/suite/funcs_1/triggers/triggers_03e_table_level.inc
+++ b/mysql-test/suite/funcs_1/triggers/triggers_03e_table_level.inc
@@ -30,7 +30,6 @@ let $message= ######### Testcase for table level: ########;
set password for test_noprivs@localhost = password('PWD');
revoke ALL PRIVILEGES, GRANT OPTION FROM test_noprivs@localhost;
- let $MASTER_MYSOCK= query_get_value(SHOW VARIABLES LIKE 'socket', Value, 1);
--replace_result $MASTER_MYPORT MASTER_MYPORT $MASTER_MYSOCK MASTER_MYSOCK
connect (yes_privs,localhost,test_yesprivs,PWD,test,$MASTER_MYPORT,$MASTER_MYSOCK);
diff --git a/mysql-test/suite/funcs_1/triggers/triggers_03e_transaction.inc b/mysql-test/suite/funcs_1/triggers/triggers_03e_transaction.inc
index 53ce49c728c..e43f4ce97a3 100644
--- a/mysql-test/suite/funcs_1/triggers/triggers_03e_transaction.inc
+++ b/mysql-test/suite/funcs_1/triggers/triggers_03e_transaction.inc
@@ -27,7 +27,6 @@ let $message= ######### Testcase for transactions: ########;
revoke ALL PRIVILEGES, GRANT OPTION FROM test_yesprivs@localhost;
- let $MASTER_MYSOCK= query_get_value(SHOW VARIABLES LIKE 'socket', Value, 1);
--replace_result $MASTER_MYPORT MASTER_MYPORT $MASTER_MYSOCK MASTER_MYSOCK
connect (yes_privs,localhost,test_yesprivs,PWD,test,$MASTER_MYPORT,$MASTER_MYSOCK);
diff --git a/mysql-test/suite/funcs_1/triggers/triggers_0407.inc b/mysql-test/suite/funcs_1/triggers/triggers_0407.inc
index af45017ae6a..d68b3d79086 100644
--- a/mysql-test/suite/funcs_1/triggers/triggers_0407.inc
+++ b/mysql-test/suite/funcs_1/triggers/triggers_0407.inc
@@ -22,7 +22,6 @@ let $message= Testcase: 3.5:;
create User test_super@localhost;
set password for test_super@localhost = password('PWD');
grant ALL on *.* to test_super@localhost with grant OPTION;
- let $MASTER_MYSOCK= query_get_value(SHOW VARIABLES LIKE 'socket', Value, 1);
--replace_result $MASTER_MYPORT MASTER_MYPORT $MASTER_MYSOCK MASTER_MYSOCK
connect (con1_general,localhost,test_general,PWD,test,$MASTER_MYPORT,$MASTER_MYSOCK);
--replace_result $MASTER_MYPORT MASTER_MYPORT $MASTER_MYSOCK MASTER_MYSOCK
diff --git a/mysql-test/suite/funcs_1/triggers/triggers_08.inc b/mysql-test/suite/funcs_1/triggers/triggers_08.inc
index 4b4050b996d..087f18e8e6b 100644
--- a/mysql-test/suite/funcs_1/triggers/triggers_08.inc
+++ b/mysql-test/suite/funcs_1/triggers/triggers_08.inc
@@ -23,7 +23,6 @@ let $message= Testcase: 3.5:;
create User test_super@localhost;
set password for test_super@localhost = password('PWD');
grant ALL on *.* to test_super@localhost with grant OPTION;
- let $MASTER_MYSOCK= query_get_value(SHOW VARIABLES LIKE 'socket', Value, 1);
--replace_result $MASTER_MYPORT MASTER_MYPORT $MASTER_MYSOCK MASTER_MYSOCK
connect (con2_general,localhost,test_general,PWD,test,$MASTER_MYPORT,$MASTER_MYSOCK);
--replace_result $MASTER_MYPORT MASTER_MYPORT $MASTER_MYSOCK MASTER_MYSOCK
diff --git a/mysql-test/suite/ibmdb2i/include/have_i54.inc b/mysql-test/suite/ibmdb2i/include/have_i54.inc
new file mode 100755
index 00000000000..7054e196153
--- /dev/null
+++ b/mysql-test/suite/ibmdb2i/include/have_i54.inc
@@ -0,0 +1,20 @@
+# Check for IBM i 6.1 or later
+--disable_query_log
+system uname -rv > $MYSQLTEST_VARDIR/tmp/version;
+--disable_warnings
+drop table if exists uname_vr;
+--enable_warnings
+create temporary table uname_vr (r int, v int);
+--disable_warnings
+eval LOAD DATA INFILE "$MYSQLTEST_VARDIR/tmp/version" into table uname_vr fields terminated by ' ';
+--enable_warnings
+let $ok = `select count(*) from uname_vr where v = 5 and r = 4`;
+drop table uname_vr;
+remove_file $MYSQLTEST_VARDIR/tmp/version;
+--enable_query_log
+if (!$ok)
+{
+ skip "Need IBM i 5.4 or later";
+}
+
+
diff --git a/mysql-test/suite/ibmdb2i/r/ibmdb2i_bug_44232.result b/mysql-test/suite/ibmdb2i/r/ibmdb2i_bug_44232.result
new file mode 100755
index 00000000000..8276b401073
--- /dev/null
+++ b/mysql-test/suite/ibmdb2i/r/ibmdb2i_bug_44232.result
@@ -0,0 +1,4 @@
+create table t1 (c char(1) character set armscii8) engine=ibmdb2i;
+ERROR HY000: Can't create table 'test.t1' (errno: 2504)
+create table t1 (c char(1) character set eucjpms ) engine=ibmdb2i;
+ERROR HY000: Can't create table 'test.t1' (errno: 2504)
diff --git a/mysql-test/suite/ibmdb2i/r/ibmdb2i_bug_44610.result b/mysql-test/suite/ibmdb2i/r/ibmdb2i_bug_44610.result
new file mode 100755
index 00000000000..311e800e1b0
--- /dev/null
+++ b/mysql-test/suite/ibmdb2i/r/ibmdb2i_bug_44610.result
@@ -0,0 +1,18 @@
+create table ABC (i int) engine=ibmdb2i;
+drop table ABC;
+create table `1234567890ABC` (i int) engine=ibmdb2i;
+drop table `1234567890ABC`;
+create table `!@#$%` (i int) engine=ibmdb2i;
+drop table `!@#$%`;
+create table `ABCD#########` (i int) engine=ibmdb2i;
+drop table `ABCD#########`;
+create table `_` (i int) engine=ibmdb2i;
+drop table `_`;
+create table `abc##def` (i int) engine=ibmdb2i;
+drop table `abc##def`;
+set names utf8;
+create table İ (s1 int) engine=ibmdb2i;
+drop table İ;
+create table İİ (s1 int) engine=ibmdb2i;
+drop table İİ;
+set names latin1;
diff --git a/mysql-test/suite/ibmdb2i/r/ibmdb2i_bug_45196.result b/mysql-test/suite/ibmdb2i/r/ibmdb2i_bug_45196.result
new file mode 100644
index 00000000000..916e1d93ee5
--- /dev/null
+++ b/mysql-test/suite/ibmdb2i/r/ibmdb2i_bug_45196.result
@@ -0,0 +1,33 @@
+drop table if exists t1;
+create table t1 (c char(10), index(c)) collate ucs2_czech_ci engine=ibmdb2i;
+insert into t1 values ("ch"),("h"),("i");
+select * from t1 order by c;
+c
+h
+ch
+i
+drop table t1;
+create table t1 (c char(10), index(c)) collate utf8_czech_ci engine=ibmdb2i;
+insert into t1 values ("ch"),("h"),("i");
+select * from t1 order by c;
+c
+h
+ch
+i
+drop table t1;
+create table t1 (c char(10), index(c)) collate ucs2_danish_ci engine=ibmdb2i;
+insert into t1 values("abc"),("abcd"),("aaaa");
+select c from t1 order by c;
+c
+abc
+abcd
+aaaa
+drop table t1;
+create table t1 (c char(10), index(c)) collate utf8_danish_ci engine=ibmdb2i;
+insert into t1 values("abc"),("abcd"),("aaaa");
+select c from t1 order by c;
+c
+abc
+abcd
+aaaa
+drop table t1;
diff --git a/mysql-test/suite/ibmdb2i/r/ibmdb2i_bug_45793.result b/mysql-test/suite/ibmdb2i/r/ibmdb2i_bug_45793.result
new file mode 100644
index 00000000000..2392b746877
--- /dev/null
+++ b/mysql-test/suite/ibmdb2i/r/ibmdb2i_bug_45793.result
@@ -0,0 +1,7 @@
+drop table if exists t1;
+create table t1 (c char(10), index(c)) charset macce engine=ibmdb2i;
+insert into t1 values ("test");
+select * from t1 order by c;
+c
+test
+drop table t1;
diff --git a/mysql-test/suite/ibmdb2i/r/ibmdb2i_bug_45983.result b/mysql-test/suite/ibmdb2i/r/ibmdb2i_bug_45983.result
new file mode 100644
index 00000000000..b9f4dcfc656
--- /dev/null
+++ b/mysql-test/suite/ibmdb2i/r/ibmdb2i_bug_45983.result
@@ -0,0 +1,20 @@
+set ibmdb2i_create_index_option=1;
+drop schema if exists test1;
+create schema test1;
+use test1;
+CREATE TABLE t1 (f int primary key, index(f)) engine=ibmdb2i;
+drop table t1;
+CREATE TABLE t1 (f char(10) collate utf8_bin primary key, index(f)) engine=ibmdb2i;
+drop table t1;
+CREATE TABLE t1 (f char(10) collate latin1_swedish_ci primary key, index(f)) engine=ibmdb2i;
+drop table t1;
+CREATE TABLE t1 (f char(10) collate latin1_swedish_ci primary key, i int, index i(i,f)) engine=ibmdb2i;
+drop table t1;
+create table fd (SQSSEQ CHAR(10)) engine=ibmdb2i;
+select * from fd;
+SQSSEQ
+*HEX
+*HEX
+*HEX
+*HEX
+drop table fd;
diff --git a/mysql-test/suite/ibmdb2i/r/ibmdb2i_collations.result b/mysql-test/suite/ibmdb2i/r/ibmdb2i_collations.result
new file mode 100644
index 00000000000..4f7d71cab2d
--- /dev/null
+++ b/mysql-test/suite/ibmdb2i/r/ibmdb2i_collations.result
@@ -0,0 +1,1204 @@
+drop table if exists t1, ffd, fd;
+CREATE TABLE t1 (armscii8_bin integer, c char(10), v varchar(20), index(c), index(v)) collate armscii8_bin engine=ibmdb2i;
+CREATE TABLE t1 (armscii8_general_ci integer, c char(10), v varchar(20), index(c), index(v)) collate armscii8_general_ci engine=ibmdb2i;
+CREATE TABLE t1 (ascii_bin integer, c char(10), v varchar(20), index(c), index(v)) collate ascii_bin engine=ibmdb2i;
+insert into t1 (c,v) values ("abc","def"),("abcd", "def"),("abcde","defg"),("aaaa","bbbb");
+insert into t1 select * from t1;
+explain select c,v from t1 force index(c) where c like "ab%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range c c 11 NULL 6 Using where
+explain select c,v from t1 force index(v) where v like "de%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 23 NULL 6 Using where
+drop table t1;
+create table t1 (ascii_bin char(10) primary key) collate ascii_bin engine=ibmdb2i;
+drop table t1;
+CREATE TABLE t1 (ascii_general_ci integer, c char(10), v varchar(20), index(c), index(v)) collate ascii_general_ci engine=ibmdb2i;
+insert into t1 (c,v) values ("abc","def"),("abcd", "def"),("abcde","defg"),("aaaa","bbbb");
+insert into t1 select * from t1;
+explain select c,v from t1 force index(c) where c like "ab%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range c c 11 NULL 6 Using where
+explain select c,v from t1 force index(v) where v like "de%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 23 NULL 6 Using where
+drop table t1;
+create table t1 (ascii_general_ci char(10) primary key) collate ascii_general_ci engine=ibmdb2i;
+drop table t1;
+CREATE TABLE t1 (big5_bin integer, c char(10), v varchar(20), index(c), index(v)) collate big5_bin engine=ibmdb2i;
+insert into t1 (c,v) values ("abc","def"),("abcd", "def"),("abcde","defg"),("aaaa","bbbb");
+insert into t1 select * from t1;
+explain select c,v from t1 force index(c) where c like "ab%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range c c 21 NULL 6 Using where
+explain select c,v from t1 force index(v) where v like "de%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 43 NULL 6 Using where
+drop table t1;
+create table t1 (big5_bin char(10) primary key) collate big5_bin engine=ibmdb2i;
+drop table t1;
+CREATE TABLE t1 (big5_chinese_ci integer, c char(10), v varchar(20), index(c), index(v)) collate big5_chinese_ci engine=ibmdb2i;
+insert into t1 (c,v) values ("abc","def"),("abcd", "def"),("abcde","defg"),("aaaa","bbbb");
+insert into t1 select * from t1;
+explain select c,v from t1 force index(c) where c like "ab%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range c c 21 NULL 6 Using where
+explain select c,v from t1 force index(v) where v like "de%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 43 NULL 6 Using where
+drop table t1;
+create table t1 (big5_chinese_ci char(10) primary key) collate big5_chinese_ci engine=ibmdb2i;
+drop table t1;
+CREATE TABLE t1 (cp1250_bin integer, c char(10), v varchar(20), index(c), index(v)) collate cp1250_bin engine=ibmdb2i;
+insert into t1 (c,v) values ("abc","def"),("abcd", "def"),("abcde","defg"),("aaaa","bbbb");
+insert into t1 select * from t1;
+explain select c,v from t1 force index(c) where c like "ab%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range c c 11 NULL 6 Using where
+explain select c,v from t1 force index(v) where v like "de%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 23 NULL 6 Using where
+drop table t1;
+create table t1 (cp1250_bin char(10) primary key) collate cp1250_bin engine=ibmdb2i;
+drop table t1;
+CREATE TABLE t1 (cp1250_croatian_ci integer, c char(10), v varchar(20), index(c), index(v)) collate cp1250_croatian_ci engine=ibmdb2i;
+insert into t1 (c,v) values ("abc","def"),("abcd", "def"),("abcde","defg"),("aaaa","bbbb");
+insert into t1 select * from t1;
+explain select c,v from t1 force index(c) where c like "ab%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range c c 11 NULL 6 Using where
+explain select c,v from t1 force index(v) where v like "de%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 23 NULL 6 Using where
+drop table t1;
+create table t1 (cp1250_croatian_ci char(10) primary key) collate cp1250_croatian_ci engine=ibmdb2i;
+drop table t1;
+CREATE TABLE t1 (cp1250_czech_cs integer, c char(10), v varchar(20), index(c), index(v)) collate cp1250_czech_cs engine=ibmdb2i;
+CREATE TABLE t1 (cp1250_general_ci integer, c char(10), v varchar(20), index(c), index(v)) collate cp1250_general_ci engine=ibmdb2i;
+insert into t1 (c,v) values ("abc","def"),("abcd", "def"),("abcde","defg"),("aaaa","bbbb");
+insert into t1 select * from t1;
+explain select c,v from t1 force index(c) where c like "ab%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range c c 11 NULL 6 Using where
+explain select c,v from t1 force index(v) where v like "de%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 23 NULL 6 Using where
+drop table t1;
+create table t1 (cp1250_general_ci char(10) primary key) collate cp1250_general_ci engine=ibmdb2i;
+drop table t1;
+CREATE TABLE t1 (cp1250_polish_ci integer, c char(10), v varchar(20), index(c), index(v)) collate cp1250_polish_ci engine=ibmdb2i;
+insert into t1 (c,v) values ("abc","def"),("abcd", "def"),("abcde","defg"),("aaaa","bbbb");
+insert into t1 select * from t1;
+explain select c,v from t1 force index(c) where c like "ab%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range c c 11 NULL 6 Using where
+explain select c,v from t1 force index(v) where v like "de%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 23 NULL 6 Using where
+drop table t1;
+create table t1 (cp1250_polish_ci char(10) primary key) collate cp1250_polish_ci engine=ibmdb2i;
+drop table t1;
+CREATE TABLE t1 (cp1251_bin integer, c char(10), v varchar(20), index(c), index(v)) collate cp1251_bin engine=ibmdb2i;
+insert into t1 (c,v) values ("abc","def"),("abcd", "def"),("abcde","defg"),("aaaa","bbbb");
+insert into t1 select * from t1;
+explain select c,v from t1 force index(c) where c like "ab%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range c c 11 NULL 6 Using where
+explain select c,v from t1 force index(v) where v like "de%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 23 NULL 6 Using where
+drop table t1;
+create table t1 (cp1251_bin char(10) primary key) collate cp1251_bin engine=ibmdb2i;
+drop table t1;
+CREATE TABLE t1 (cp1251_bulgarian_ci integer, c char(10), v varchar(20), index(c), index(v)) collate cp1251_bulgarian_ci engine=ibmdb2i;
+insert into t1 (c,v) values ("abc","def"),("abcd", "def"),("abcde","defg"),("aaaa","bbbb");
+insert into t1 select * from t1;
+explain select c,v from t1 force index(c) where c like "ab%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range c c 11 NULL 6 Using where
+explain select c,v from t1 force index(v) where v like "de%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 23 NULL 6 Using where
+drop table t1;
+create table t1 (cp1251_bulgarian_ci char(10) primary key) collate cp1251_bulgarian_ci engine=ibmdb2i;
+drop table t1;
+CREATE TABLE t1 (cp1251_general_ci integer, c char(10), v varchar(20), index(c), index(v)) collate cp1251_general_ci engine=ibmdb2i;
+insert into t1 (c,v) values ("abc","def"),("abcd", "def"),("abcde","defg"),("aaaa","bbbb");
+insert into t1 select * from t1;
+explain select c,v from t1 force index(c) where c like "ab%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range c c 11 NULL 6 Using where
+explain select c,v from t1 force index(v) where v like "de%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 23 NULL 6 Using where
+drop table t1;
+create table t1 (cp1251_general_ci char(10) primary key) collate cp1251_general_ci engine=ibmdb2i;
+drop table t1;
+CREATE TABLE t1 (cp1251_general_cs integer, c char(10), v varchar(20), index(c), index(v)) collate cp1251_general_cs engine=ibmdb2i;
+insert into t1 (c,v) values ("abc","def"),("abcd", "def"),("abcde","defg"),("aaaa","bbbb");
+insert into t1 select * from t1;
+explain select c,v from t1 force index(c) where c like "ab%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range c c 11 NULL 6 Using where
+explain select c,v from t1 force index(v) where v like "de%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 23 NULL 6 Using where
+drop table t1;
+create table t1 (cp1251_general_cs char(10) primary key) collate cp1251_general_cs engine=ibmdb2i;
+drop table t1;
+CREATE TABLE t1 (cp1251_ukrainian_ci integer, c char(10), v varchar(20), index(c), index(v)) collate cp1251_ukrainian_ci engine=ibmdb2i;
+CREATE TABLE t1 (cp1256_bin integer, c char(10), v varchar(20), index(c), index(v)) collate cp1256_bin engine=ibmdb2i;
+insert into t1 (c,v) values ("abc","def"),("abcd", "def"),("abcde","defg"),("aaaa","bbbb");
+insert into t1 select * from t1;
+explain select c,v from t1 force index(c) where c like "ab%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range c c 11 NULL 6 Using where
+explain select c,v from t1 force index(v) where v like "de%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 23 NULL 6 Using where
+drop table t1;
+create table t1 (cp1256_bin char(10) primary key) collate cp1256_bin engine=ibmdb2i;
+drop table t1;
+CREATE TABLE t1 (cp1256_general_ci integer, c char(10), v varchar(20), index(c), index(v)) collate cp1256_general_ci engine=ibmdb2i;
+insert into t1 (c,v) values ("abc","def"),("abcd", "def"),("abcde","defg"),("aaaa","bbbb");
+insert into t1 select * from t1;
+explain select c,v from t1 force index(c) where c like "ab%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range c c 11 NULL 6 Using where
+explain select c,v from t1 force index(v) where v like "de%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 23 NULL 6 Using where
+drop table t1;
+create table t1 (cp1256_general_ci char(10) primary key) collate cp1256_general_ci engine=ibmdb2i;
+drop table t1;
+CREATE TABLE t1 (cp1257_bin integer, c char(10), v varchar(20), index(c), index(v)) collate cp1257_bin engine=ibmdb2i;
+CREATE TABLE t1 (cp1257_general_ci integer, c char(10), v varchar(20), index(c), index(v)) collate cp1257_general_ci engine=ibmdb2i;
+CREATE TABLE t1 (cp1257_lithuanian_ci integer, c char(10), v varchar(20), index(c), index(v)) collate cp1257_lithuanian_ci engine=ibmdb2i;
+CREATE TABLE t1 (cp850_bin integer, c char(10), v varchar(20), index(c), index(v)) collate cp850_bin engine=ibmdb2i;
+insert into t1 (c,v) values ("abc","def"),("abcd", "def"),("abcde","defg"),("aaaa","bbbb");
+insert into t1 select * from t1;
+explain select c,v from t1 force index(c) where c like "ab%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range c c 11 NULL 6 Using where
+explain select c,v from t1 force index(v) where v like "de%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 23 NULL 6 Using where
+drop table t1;
+create table t1 (cp850_bin char(10) primary key) collate cp850_bin engine=ibmdb2i;
+drop table t1;
+CREATE TABLE t1 (cp850_general_ci integer, c char(10), v varchar(20), index(c), index(v)) collate cp850_general_ci engine=ibmdb2i;
+insert into t1 (c,v) values ("abc","def"),("abcd", "def"),("abcde","defg"),("aaaa","bbbb");
+insert into t1 select * from t1;
+explain select c,v from t1 force index(c) where c like "ab%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range c c 11 NULL 6 Using where
+explain select c,v from t1 force index(v) where v like "de%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 23 NULL 6 Using where
+drop table t1;
+create table t1 (cp850_general_ci char(10) primary key) collate cp850_general_ci engine=ibmdb2i;
+drop table t1;
+CREATE TABLE t1 (cp852_bin integer, c char(10), v varchar(20), index(c), index(v)) collate cp852_bin engine=ibmdb2i;
+insert into t1 (c,v) values ("abc","def"),("abcd", "def"),("abcde","defg"),("aaaa","bbbb");
+insert into t1 select * from t1;
+explain select c,v from t1 force index(c) where c like "ab%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range c c 11 NULL 6 Using where
+explain select c,v from t1 force index(v) where v like "de%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 23 NULL 6 Using where
+drop table t1;
+create table t1 (cp852_bin char(10) primary key) collate cp852_bin engine=ibmdb2i;
+drop table t1;
+CREATE TABLE t1 (cp852_general_ci integer, c char(10), v varchar(20), index(c), index(v)) collate cp852_general_ci engine=ibmdb2i;
+insert into t1 (c,v) values ("abc","def"),("abcd", "def"),("abcde","defg"),("aaaa","bbbb");
+insert into t1 select * from t1;
+explain select c,v from t1 force index(c) where c like "ab%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range c c 11 NULL 6 Using where
+explain select c,v from t1 force index(v) where v like "de%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 23 NULL 6 Using where
+drop table t1;
+create table t1 (cp852_general_ci char(10) primary key) collate cp852_general_ci engine=ibmdb2i;
+drop table t1;
+CREATE TABLE t1 (cp866_bin integer, c char(10), v varchar(20), index(c), index(v)) collate cp866_bin engine=ibmdb2i;
+CREATE TABLE t1 (cp866_general_ci integer, c char(10), v varchar(20), index(c), index(v)) collate cp866_general_ci engine=ibmdb2i;
+CREATE TABLE t1 (cp932_bin integer, c char(10), v varchar(20), index(c), index(v)) collate cp932_bin engine=ibmdb2i;
+insert into t1 (c,v) values ("abc","def"),("abcd", "def"),("abcde","defg"),("aaaa","bbbb");
+insert into t1 select * from t1;
+explain select c,v from t1 force index(c) where c like "ab%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range c c 21 NULL 6 Using where
+explain select c,v from t1 force index(v) where v like "de%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 43 NULL 6 Using where
+drop table t1;
+create table t1 (cp932_bin char(10) primary key) collate cp932_bin engine=ibmdb2i;
+drop table t1;
+CREATE TABLE t1 (cp932_japanese_ci integer, c char(10), v varchar(20), index(c), index(v)) collate cp932_japanese_ci engine=ibmdb2i;
+insert into t1 (c,v) values ("abc","def"),("abcd", "def"),("abcde","defg"),("aaaa","bbbb");
+insert into t1 select * from t1;
+explain select c,v from t1 force index(c) where c like "ab%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range c c 21 NULL 6 Using where
+explain select c,v from t1 force index(v) where v like "de%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 43 NULL 6 Using where
+drop table t1;
+create table t1 (cp932_japanese_ci char(10) primary key) collate cp932_japanese_ci engine=ibmdb2i;
+drop table t1;
+CREATE TABLE t1 (dec8_bin integer, c char(10), v varchar(20), index(c), index(v)) collate dec8_bin engine=ibmdb2i;
+CREATE TABLE t1 (dec8_swedish_ci integer, c char(10), v varchar(20), index(c), index(v)) collate dec8_swedish_ci engine=ibmdb2i;
+CREATE TABLE t1 (eucjpms_bin integer, c char(10), v varchar(20), index(c), index(v)) collate eucjpms_bin engine=ibmdb2i;
+CREATE TABLE t1 (eucjpms_japanese_ci integer, c char(10), v varchar(20), index(c), index(v)) collate eucjpms_japanese_ci engine=ibmdb2i;
+CREATE TABLE t1 (euckr_bin integer, c char(10), v varchar(20), index(c), index(v)) collate euckr_bin engine=ibmdb2i;
+insert into t1 (c,v) values ("abc","def"),("abcd", "def"),("abcde","defg"),("aaaa","bbbb");
+insert into t1 select * from t1;
+explain select c,v from t1 force index(c) where c like "ab%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range c c 21 NULL 6 Using where
+explain select c,v from t1 force index(v) where v like "de%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 43 NULL 6 Using where
+drop table t1;
+create table t1 (euckr_bin char(10) primary key) collate euckr_bin engine=ibmdb2i;
+drop table t1;
+CREATE TABLE t1 (euckr_korean_ci integer, c char(10), v varchar(20), index(c), index(v)) collate euckr_korean_ci engine=ibmdb2i;
+insert into t1 (c,v) values ("abc","def"),("abcd", "def"),("abcde","defg"),("aaaa","bbbb");
+insert into t1 select * from t1;
+explain select c,v from t1 force index(c) where c like "ab%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range c c 21 NULL 6 Using where
+explain select c,v from t1 force index(v) where v like "de%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 43 NULL 6 Using where
+drop table t1;
+create table t1 (euckr_korean_ci char(10) primary key) collate euckr_korean_ci engine=ibmdb2i;
+drop table t1;
+CREATE TABLE t1 (gb2312_bin integer, c char(10), v varchar(20), index(c), index(v)) collate gb2312_bin engine=ibmdb2i;
+insert into t1 (c,v) values ("abc","def"),("abcd", "def"),("abcde","defg"),("aaaa","bbbb");
+insert into t1 select * from t1;
+explain select c,v from t1 force index(c) where c like "ab%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range c c 21 NULL 6 Using where
+explain select c,v from t1 force index(v) where v like "de%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 43 NULL 6 Using where
+drop table t1;
+create table t1 (gb2312_bin char(10) primary key) collate gb2312_bin engine=ibmdb2i;
+drop table t1;
+CREATE TABLE t1 (gb2312_chinese_ci integer, c char(10), v varchar(20), index(c), index(v)) collate gb2312_chinese_ci engine=ibmdb2i;
+insert into t1 (c,v) values ("abc","def"),("abcd", "def"),("abcde","defg"),("aaaa","bbbb");
+insert into t1 select * from t1;
+explain select c,v from t1 force index(c) where c like "ab%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range c c 21 NULL 6 Using where
+explain select c,v from t1 force index(v) where v like "de%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 43 NULL 6 Using where
+drop table t1;
+create table t1 (gb2312_chinese_ci char(10) primary key) collate gb2312_chinese_ci engine=ibmdb2i;
+drop table t1;
+CREATE TABLE t1 (gbk_bin integer, c char(10), v varchar(20), index(c), index(v)) collate gbk_bin engine=ibmdb2i;
+insert into t1 (c,v) values ("abc","def"),("abcd", "def"),("abcde","defg"),("aaaa","bbbb");
+insert into t1 select * from t1;
+explain select c,v from t1 force index(c) where c like "ab%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range c c 21 NULL 6 Using where
+explain select c,v from t1 force index(v) where v like "de%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 43 NULL 6 Using where
+drop table t1;
+create table t1 (gbk_bin char(10) primary key) collate gbk_bin engine=ibmdb2i;
+drop table t1;
+CREATE TABLE t1 (gbk_chinese_ci integer, c char(10), v varchar(20), index(c), index(v)) collate gbk_chinese_ci engine=ibmdb2i;
+insert into t1 (c,v) values ("abc","def"),("abcd", "def"),("abcde","defg"),("aaaa","bbbb");
+insert into t1 select * from t1;
+explain select c,v from t1 force index(c) where c like "ab%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range c c 21 NULL 6 Using where
+explain select c,v from t1 force index(v) where v like "de%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 43 NULL 6 Using where
+drop table t1;
+create table t1 (gbk_chinese_ci char(10) primary key) collate gbk_chinese_ci engine=ibmdb2i;
+drop table t1;
+CREATE TABLE t1 (geostd8_bin integer, c char(10), v varchar(20), index(c), index(v)) collate geostd8_bin engine=ibmdb2i;
+CREATE TABLE t1 (geostd8_general_ci integer, c char(10), v varchar(20), index(c), index(v)) collate geostd8_general_ci engine=ibmdb2i;
+CREATE TABLE t1 (greek_bin integer, c char(10), v varchar(20), index(c), index(v)) collate greek_bin engine=ibmdb2i;
+insert into t1 (c,v) values ("abc","def"),("abcd", "def"),("abcde","defg"),("aaaa","bbbb");
+insert into t1 select * from t1;
+explain select c,v from t1 force index(c) where c like "ab%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range c c 11 NULL 6 Using where
+explain select c,v from t1 force index(v) where v like "de%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 23 NULL 6 Using where
+drop table t1;
+create table t1 (greek_bin char(10) primary key) collate greek_bin engine=ibmdb2i;
+drop table t1;
+CREATE TABLE t1 (greek_general_ci integer, c char(10), v varchar(20), index(c), index(v)) collate greek_general_ci engine=ibmdb2i;
+insert into t1 (c,v) values ("abc","def"),("abcd", "def"),("abcde","defg"),("aaaa","bbbb");
+insert into t1 select * from t1;
+explain select c,v from t1 force index(c) where c like "ab%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range c c 11 NULL 6 Using where
+explain select c,v from t1 force index(v) where v like "de%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 23 NULL 6 Using where
+drop table t1;
+create table t1 (greek_general_ci char(10) primary key) collate greek_general_ci engine=ibmdb2i;
+drop table t1;
+CREATE TABLE t1 (hebrew_bin integer, c char(10), v varchar(20), index(c), index(v)) collate hebrew_bin engine=ibmdb2i;
+insert into t1 (c,v) values ("abc","def"),("abcd", "def"),("abcde","defg"),("aaaa","bbbb");
+insert into t1 select * from t1;
+explain select c,v from t1 force index(c) where c like "ab%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range c c 11 NULL 6 Using where
+explain select c,v from t1 force index(v) where v like "de%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 23 NULL 6 Using where
+drop table t1;
+create table t1 (hebrew_bin char(10) primary key) collate hebrew_bin engine=ibmdb2i;
+drop table t1;
+CREATE TABLE t1 (hebrew_general_ci integer, c char(10), v varchar(20), index(c), index(v)) collate hebrew_general_ci engine=ibmdb2i;
+insert into t1 (c,v) values ("abc","def"),("abcd", "def"),("abcde","defg"),("aaaa","bbbb");
+insert into t1 select * from t1;
+explain select c,v from t1 force index(c) where c like "ab%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range c c 11 NULL 6 Using where
+explain select c,v from t1 force index(v) where v like "de%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 23 NULL 6 Using where
+drop table t1;
+create table t1 (hebrew_general_ci char(10) primary key) collate hebrew_general_ci engine=ibmdb2i;
+drop table t1;
+CREATE TABLE t1 (hp8_bin integer, c char(10), v varchar(20), index(c), index(v)) collate hp8_bin engine=ibmdb2i;
+CREATE TABLE t1 (hp8_english_ci integer, c char(10), v varchar(20), index(c), index(v)) collate hp8_english_ci engine=ibmdb2i;
+CREATE TABLE t1 (keybcs2_bin integer, c char(10), v varchar(20), index(c), index(v)) collate keybcs2_bin engine=ibmdb2i;
+CREATE TABLE t1 (keybcs2_general_ci integer, c char(10), v varchar(20), index(c), index(v)) collate keybcs2_general_ci engine=ibmdb2i;
+CREATE TABLE t1 (koi8r_bin integer, c char(10), v varchar(20), index(c), index(v)) collate koi8r_bin engine=ibmdb2i;
+CREATE TABLE t1 (koi8r_general_ci integer, c char(10), v varchar(20), index(c), index(v)) collate koi8r_general_ci engine=ibmdb2i;
+CREATE TABLE t1 (koi8u_bin integer, c char(10), v varchar(20), index(c), index(v)) collate koi8u_bin engine=ibmdb2i;
+CREATE TABLE t1 (koi8u_general_ci integer, c char(10), v varchar(20), index(c), index(v)) collate koi8u_general_ci engine=ibmdb2i;
+CREATE TABLE t1 (latin1_bin integer, c char(10), v varchar(20), index(c), index(v)) collate latin1_bin engine=ibmdb2i;
+insert into t1 (c,v) values ("abc","def"),("abcd", "def"),("abcde","defg"),("aaaa","bbbb");
+insert into t1 select * from t1;
+explain select c,v from t1 force index(c) where c like "ab%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range c c 11 NULL 6 Using where
+explain select c,v from t1 force index(v) where v like "de%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 23 NULL 6 Using where
+drop table t1;
+create table t1 (latin1_bin char(10) primary key) collate latin1_bin engine=ibmdb2i;
+drop table t1;
+CREATE TABLE t1 (latin1_danish_ci integer, c char(10), v varchar(20), index(c), index(v)) collate latin1_danish_ci engine=ibmdb2i;
+insert into t1 (c,v) values ("abc","def"),("abcd", "def"),("abcde","defg"),("aaaa","bbbb");
+insert into t1 select * from t1;
+explain select c,v from t1 force index(c) where c like "ab%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range c c 11 NULL 6 Using where
+explain select c,v from t1 force index(v) where v like "de%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 23 NULL 6 Using where
+drop table t1;
+create table t1 (latin1_danish_ci char(10) primary key) collate latin1_danish_ci engine=ibmdb2i;
+drop table t1;
+CREATE TABLE t1 (latin1_general_ci integer, c char(10), v varchar(20), index(c), index(v)) collate latin1_general_ci engine=ibmdb2i;
+insert into t1 (c,v) values ("abc","def"),("abcd", "def"),("abcde","defg"),("aaaa","bbbb");
+insert into t1 select * from t1;
+explain select c,v from t1 force index(c) where c like "ab%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range c c 11 NULL 6 Using where
+explain select c,v from t1 force index(v) where v like "de%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 23 NULL 6 Using where
+drop table t1;
+create table t1 (latin1_general_ci char(10) primary key) collate latin1_general_ci engine=ibmdb2i;
+drop table t1;
+CREATE TABLE t1 (latin1_general_cs integer, c char(10), v varchar(20), index(c), index(v)) collate latin1_general_cs engine=ibmdb2i;
+insert into t1 (c,v) values ("abc","def"),("abcd", "def"),("abcde","defg"),("aaaa","bbbb");
+insert into t1 select * from t1;
+explain select c,v from t1 force index(c) where c like "ab%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range c c 11 NULL 6 Using where
+explain select c,v from t1 force index(v) where v like "de%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 23 NULL 6 Using where
+drop table t1;
+create table t1 (latin1_general_cs char(10) primary key) collate latin1_general_cs engine=ibmdb2i;
+drop table t1;
+CREATE TABLE t1 (latin1_german1_ci integer, c char(10), v varchar(20), index(c), index(v)) collate latin1_german1_ci engine=ibmdb2i;
+insert into t1 (c,v) values ("abc","def"),("abcd", "def"),("abcde","defg"),("aaaa","bbbb");
+insert into t1 select * from t1;
+explain select c,v from t1 force index(c) where c like "ab%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range c c 11 NULL 6 Using where
+explain select c,v from t1 force index(v) where v like "de%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 23 NULL 6 Using where
+drop table t1;
+create table t1 (latin1_german1_ci char(10) primary key) collate latin1_german1_ci engine=ibmdb2i;
+drop table t1;
+CREATE TABLE t1 (latin1_german2_ci integer, c char(10), v varchar(20), index(c), index(v)) collate latin1_german2_ci engine=ibmdb2i;
+CREATE TABLE t1 (latin1_spanish_ci integer, c char(10), v varchar(20), index(c), index(v)) collate latin1_spanish_ci engine=ibmdb2i;
+insert into t1 (c,v) values ("abc","def"),("abcd", "def"),("abcde","defg"),("aaaa","bbbb");
+insert into t1 select * from t1;
+explain select c,v from t1 force index(c) where c like "ab%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range c c 11 NULL 6 Using where
+explain select c,v from t1 force index(v) where v like "de%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 23 NULL 6 Using where
+drop table t1;
+create table t1 (latin1_spanish_ci char(10) primary key) collate latin1_spanish_ci engine=ibmdb2i;
+drop table t1;
+CREATE TABLE t1 (latin1_swedish_ci integer, c char(10), v varchar(20), index(c), index(v)) collate latin1_swedish_ci engine=ibmdb2i;
+insert into t1 (c,v) values ("abc","def"),("abcd", "def"),("abcde","defg"),("aaaa","bbbb");
+insert into t1 select * from t1;
+explain select c,v from t1 force index(c) where c like "ab%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range c c 11 NULL 6 Using where
+explain select c,v from t1 force index(v) where v like "de%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 23 NULL 6 Using where
+drop table t1;
+create table t1 (latin1_swedish_ci char(10) primary key) collate latin1_swedish_ci engine=ibmdb2i;
+drop table t1;
+CREATE TABLE t1 (latin2_bin integer, c char(10), v varchar(20), index(c), index(v)) collate latin2_bin engine=ibmdb2i;
+insert into t1 (c,v) values ("abc","def"),("abcd", "def"),("abcde","defg"),("aaaa","bbbb");
+insert into t1 select * from t1;
+explain select c,v from t1 force index(c) where c like "ab%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range c c 11 NULL 6 Using where
+explain select c,v from t1 force index(v) where v like "de%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 23 NULL 6 Using where
+drop table t1;
+create table t1 (latin2_bin char(10) primary key) collate latin2_bin engine=ibmdb2i;
+drop table t1;
+CREATE TABLE t1 (latin2_croatian_ci integer, c char(10), v varchar(20), index(c), index(v)) collate latin2_croatian_ci engine=ibmdb2i;
+insert into t1 (c,v) values ("abc","def"),("abcd", "def"),("abcde","defg"),("aaaa","bbbb");
+insert into t1 select * from t1;
+explain select c,v from t1 force index(c) where c like "ab%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range c c 11 NULL 6 Using where
+explain select c,v from t1 force index(v) where v like "de%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 23 NULL 6 Using where
+drop table t1;
+create table t1 (latin2_croatian_ci char(10) primary key) collate latin2_croatian_ci engine=ibmdb2i;
+drop table t1;
+CREATE TABLE t1 (latin2_czech_cs integer, c char(10), v varchar(20), index(c), index(v)) collate latin2_czech_cs engine=ibmdb2i;
+CREATE TABLE t1 (latin2_general_ci integer, c char(10), v varchar(20), index(c), index(v)) collate latin2_general_ci engine=ibmdb2i;
+insert into t1 (c,v) values ("abc","def"),("abcd", "def"),("abcde","defg"),("aaaa","bbbb");
+insert into t1 select * from t1;
+explain select c,v from t1 force index(c) where c like "ab%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range c c 11 NULL 6 Using where
+explain select c,v from t1 force index(v) where v like "de%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 23 NULL 6 Using where
+drop table t1;
+create table t1 (latin2_general_ci char(10) primary key) collate latin2_general_ci engine=ibmdb2i;
+drop table t1;
+CREATE TABLE t1 (latin2_hungarian_ci integer, c char(10), v varchar(20), index(c), index(v)) collate latin2_hungarian_ci engine=ibmdb2i;
+insert into t1 (c,v) values ("abc","def"),("abcd", "def"),("abcde","defg"),("aaaa","bbbb");
+insert into t1 select * from t1;
+explain select c,v from t1 force index(c) where c like "ab%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range c c 11 NULL 6 Using where
+explain select c,v from t1 force index(v) where v like "de%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 23 NULL 6 Using where
+drop table t1;
+create table t1 (latin2_hungarian_ci char(10) primary key) collate latin2_hungarian_ci engine=ibmdb2i;
+drop table t1;
+CREATE TABLE t1 (latin5_bin integer, c char(10), v varchar(20), index(c), index(v)) collate latin5_bin engine=ibmdb2i;
+insert into t1 (c,v) values ("abc","def"),("abcd", "def"),("abcde","defg"),("aaaa","bbbb");
+insert into t1 select * from t1;
+explain select c,v from t1 force index(c) where c like "ab%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range c c 11 NULL 6 Using where
+explain select c,v from t1 force index(v) where v like "de%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 23 NULL 6 Using where
+drop table t1;
+create table t1 (latin5_bin char(10) primary key) collate latin5_bin engine=ibmdb2i;
+drop table t1;
+CREATE TABLE t1 (latin5_turkish_ci integer, c char(10), v varchar(20), index(c), index(v)) collate latin5_turkish_ci engine=ibmdb2i;
+insert into t1 (c,v) values ("abc","def"),("abcd", "def"),("abcde","defg"),("aaaa","bbbb");
+insert into t1 select * from t1;
+explain select c,v from t1 force index(c) where c like "ab%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range c c 11 NULL 6 Using where
+explain select c,v from t1 force index(v) where v like "de%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 23 NULL 6 Using where
+drop table t1;
+create table t1 (latin5_turkish_ci char(10) primary key) collate latin5_turkish_ci engine=ibmdb2i;
+drop table t1;
+CREATE TABLE t1 (latin7_bin integer, c char(10), v varchar(20), index(c), index(v)) collate latin7_bin engine=ibmdb2i;
+CREATE TABLE t1 (latin7_estonian_cs integer, c char(10), v varchar(20), index(c), index(v)) collate latin7_estonian_cs engine=ibmdb2i;
+CREATE TABLE t1 (latin7_general_ci integer, c char(10), v varchar(20), index(c), index(v)) collate latin7_general_ci engine=ibmdb2i;
+CREATE TABLE t1 (latin7_general_cs integer, c char(10), v varchar(20), index(c), index(v)) collate latin7_general_cs engine=ibmdb2i;
+CREATE TABLE t1 (macce_bin integer, c char(10), v varchar(20), index(c), index(v)) collate macce_bin engine=ibmdb2i;
+insert into t1 (c,v) values ("abc","def"),("abcd", "def"),("abcde","defg"),("aaaa","bbbb");
+insert into t1 select * from t1;
+explain select c,v from t1 force index(c) where c like "ab%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range c c 11 NULL 6 Using where
+explain select c,v from t1 force index(v) where v like "de%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 23 NULL 6 Using where
+drop table t1;
+create table t1 (macce_bin char(10) primary key) collate macce_bin engine=ibmdb2i;
+drop table t1;
+CREATE TABLE t1 (macce_general_ci integer, c char(10), v varchar(20), index(c), index(v)) collate macce_general_ci engine=ibmdb2i;
+insert into t1 (c,v) values ("abc","def"),("abcd", "def"),("abcde","defg"),("aaaa","bbbb");
+insert into t1 select * from t1;
+explain select c,v from t1 force index(c) where c like "ab%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range c c 11 NULL 6 Using where
+explain select c,v from t1 force index(v) where v like "de%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 23 NULL 6 Using where
+drop table t1;
+create table t1 (macce_general_ci char(10) primary key) collate macce_general_ci engine=ibmdb2i;
+drop table t1;
+CREATE TABLE t1 (macroman_bin integer, c char(10), v varchar(20), index(c), index(v)) collate macroman_bin engine=ibmdb2i;
+CREATE TABLE t1 (macroman_general_ci integer, c char(10), v varchar(20), index(c), index(v)) collate macroman_general_ci engine=ibmdb2i;
+CREATE TABLE t1 (sjis_bin integer, c char(10), v varchar(20), index(c), index(v)) collate sjis_bin engine=ibmdb2i;
+insert into t1 (c,v) values ("abc","def"),("abcd", "def"),("abcde","defg"),("aaaa","bbbb");
+insert into t1 select * from t1;
+explain select c,v from t1 force index(c) where c like "ab%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range c c 21 NULL 6 Using where
+explain select c,v from t1 force index(v) where v like "de%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 43 NULL 6 Using where
+drop table t1;
+create table t1 (sjis_bin char(10) primary key) collate sjis_bin engine=ibmdb2i;
+drop table t1;
+CREATE TABLE t1 (sjis_japanese_ci integer, c char(10), v varchar(20), index(c), index(v)) collate sjis_japanese_ci engine=ibmdb2i;
+insert into t1 (c,v) values ("abc","def"),("abcd", "def"),("abcde","defg"),("aaaa","bbbb");
+insert into t1 select * from t1;
+explain select c,v from t1 force index(c) where c like "ab%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range c c 21 NULL 6 Using where
+explain select c,v from t1 force index(v) where v like "de%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 43 NULL 6 Using where
+drop table t1;
+create table t1 (sjis_japanese_ci char(10) primary key) collate sjis_japanese_ci engine=ibmdb2i;
+drop table t1;
+CREATE TABLE t1 (swe7_bin integer, c char(10), v varchar(20), index(c), index(v)) collate swe7_bin engine=ibmdb2i;
+CREATE TABLE t1 (swe7_swedish_ci integer, c char(10), v varchar(20), index(c), index(v)) collate swe7_swedish_ci engine=ibmdb2i;
+CREATE TABLE t1 (tis620_bin integer, c char(10), v varchar(20), index(c), index(v)) collate tis620_bin engine=ibmdb2i;
+insert into t1 (c,v) values ("abc","def"),("abcd", "def"),("abcde","defg"),("aaaa","bbbb");
+insert into t1 select * from t1;
+explain select c,v from t1 force index(c) where c like "ab%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range c c 11 NULL 6 Using where
+explain select c,v from t1 force index(v) where v like "de%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 23 NULL 6 Using where
+drop table t1;
+create table t1 (tis620_bin char(10) primary key) collate tis620_bin engine=ibmdb2i;
+drop table t1;
+CREATE TABLE t1 (tis620_thai_ci integer, c char(10), v varchar(20), index(c), index(v)) collate tis620_thai_ci engine=ibmdb2i;
+insert into t1 (c,v) values ("abc","def"),("abcd", "def"),("abcde","defg"),("aaaa","bbbb");
+insert into t1 select * from t1;
+explain select c,v from t1 force index(c) where c like "ab%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range c c 11 NULL 6 Using where
+explain select c,v from t1 force index(v) where v like "de%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 23 NULL 6 Using where
+drop table t1;
+create table t1 (tis620_thai_ci char(10) primary key) collate tis620_thai_ci engine=ibmdb2i;
+drop table t1;
+CREATE TABLE t1 (ucs2_bin integer, c char(10), v varchar(20), index(c), index(v)) collate ucs2_bin engine=ibmdb2i;
+insert into t1 (c,v) values ("abc","def"),("abcd", "def"),("abcde","defg"),("aaaa","bbbb");
+insert into t1 select * from t1;
+explain select c,v from t1 force index(c) where c like "ab%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range c c 21 NULL 6 Using where
+explain select c,v from t1 force index(v) where v like "de%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 43 NULL 6 Using where
+drop table t1;
+create table t1 (ucs2_bin char(10) primary key) collate ucs2_bin engine=ibmdb2i;
+drop table t1;
+CREATE TABLE t1 (ucs2_czech_ci integer, c char(10), v varchar(20), index(c), index(v)) collate ucs2_czech_ci engine=ibmdb2i;
+insert into t1 (c,v) values ("abc","def"),("abcd", "def"),("abcde","defg"),("aaaa","bbbb");
+insert into t1 select * from t1;
+explain select c,v from t1 force index(c) where c like "ab%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range c c 21 NULL 6 Using where
+explain select c,v from t1 force index(v) where v like "de%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 43 NULL 6 Using where
+drop table t1;
+create table t1 (ucs2_czech_ci char(10) primary key) collate ucs2_czech_ci engine=ibmdb2i;
+drop table t1;
+CREATE TABLE t1 (ucs2_danish_ci integer, c char(10), v varchar(20), index(c), index(v)) collate ucs2_danish_ci engine=ibmdb2i;
+insert into t1 (c,v) values ("abc","def"),("abcd", "def"),("abcde","defg"),("aaaa","bbbb");
+insert into t1 select * from t1;
+explain select c,v from t1 force index(c) where c like "ab%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range c c 21 NULL 6 Using where
+explain select c,v from t1 force index(v) where v like "de%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 43 NULL 6 Using where
+drop table t1;
+create table t1 (ucs2_danish_ci char(10) primary key) collate ucs2_danish_ci engine=ibmdb2i;
+drop table t1;
+CREATE TABLE t1 (ucs2_esperanto_ci integer, c char(10), v varchar(20), index(c), index(v)) collate ucs2_esperanto_ci engine=ibmdb2i;
+insert into t1 (c,v) values ("abc","def"),("abcd", "def"),("abcde","defg"),("aaaa","bbbb");
+insert into t1 select * from t1;
+explain select c,v from t1 force index(c) where c like "ab%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range c c 21 NULL 6 Using where
+explain select c,v from t1 force index(v) where v like "de%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 43 NULL 6 Using where
+drop table t1;
+create table t1 (ucs2_esperanto_ci char(10) primary key) collate ucs2_esperanto_ci engine=ibmdb2i;
+drop table t1;
+CREATE TABLE t1 (ucs2_estonian_ci integer, c char(10), v varchar(20), index(c), index(v)) collate ucs2_estonian_ci engine=ibmdb2i;
+insert into t1 (c,v) values ("abc","def"),("abcd", "def"),("abcde","defg"),("aaaa","bbbb");
+insert into t1 select * from t1;
+explain select c,v from t1 force index(c) where c like "ab%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range c c 21 NULL 6 Using where
+explain select c,v from t1 force index(v) where v like "de%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 43 NULL 6 Using where
+drop table t1;
+create table t1 (ucs2_estonian_ci char(10) primary key) collate ucs2_estonian_ci engine=ibmdb2i;
+drop table t1;
+CREATE TABLE t1 (ucs2_general_ci integer, c char(10), v varchar(20), index(c), index(v)) collate ucs2_general_ci engine=ibmdb2i;
+insert into t1 (c,v) values ("abc","def"),("abcd", "def"),("abcde","defg"),("aaaa","bbbb");
+insert into t1 select * from t1;
+explain select c,v from t1 force index(c) where c like "ab%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range c c 21 NULL 6 Using where
+explain select c,v from t1 force index(v) where v like "de%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 43 NULL 6 Using where
+drop table t1;
+create table t1 (ucs2_general_ci char(10) primary key) collate ucs2_general_ci engine=ibmdb2i;
+drop table t1;
+CREATE TABLE t1 (ucs2_hungarian_ci integer, c char(10), v varchar(20), index(c), index(v)) collate ucs2_hungarian_ci engine=ibmdb2i;
+insert into t1 (c,v) values ("abc","def"),("abcd", "def"),("abcde","defg"),("aaaa","bbbb");
+insert into t1 select * from t1;
+explain select c,v from t1 force index(c) where c like "ab%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range c c 21 NULL 6 Using where
+explain select c,v from t1 force index(v) where v like "de%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 43 NULL 6 Using where
+drop table t1;
+create table t1 (ucs2_hungarian_ci char(10) primary key) collate ucs2_hungarian_ci engine=ibmdb2i;
+drop table t1;
+CREATE TABLE t1 (ucs2_icelandic_ci integer, c char(10), v varchar(20), index(c), index(v)) collate ucs2_icelandic_ci engine=ibmdb2i;
+insert into t1 (c,v) values ("abc","def"),("abcd", "def"),("abcde","defg"),("aaaa","bbbb");
+insert into t1 select * from t1;
+explain select c,v from t1 force index(c) where c like "ab%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range c c 21 NULL 6 Using where
+explain select c,v from t1 force index(v) where v like "de%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 43 NULL 6 Using where
+drop table t1;
+create table t1 (ucs2_icelandic_ci char(10) primary key) collate ucs2_icelandic_ci engine=ibmdb2i;
+drop table t1;
+CREATE TABLE t1 (ucs2_latvian_ci integer, c char(10), v varchar(20), index(c), index(v)) collate ucs2_latvian_ci engine=ibmdb2i;
+insert into t1 (c,v) values ("abc","def"),("abcd", "def"),("abcde","defg"),("aaaa","bbbb");
+insert into t1 select * from t1;
+explain select c,v from t1 force index(c) where c like "ab%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range c c 21 NULL 6 Using where
+explain select c,v from t1 force index(v) where v like "de%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 43 NULL 6 Using where
+drop table t1;
+create table t1 (ucs2_latvian_ci char(10) primary key) collate ucs2_latvian_ci engine=ibmdb2i;
+drop table t1;
+CREATE TABLE t1 (ucs2_lithuanian_ci integer, c char(10), v varchar(20), index(c), index(v)) collate ucs2_lithuanian_ci engine=ibmdb2i;
+insert into t1 (c,v) values ("abc","def"),("abcd", "def"),("abcde","defg"),("aaaa","bbbb");
+insert into t1 select * from t1;
+explain select c,v from t1 force index(c) where c like "ab%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range c c 21 NULL 6 Using where
+explain select c,v from t1 force index(v) where v like "de%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 43 NULL 6 Using where
+drop table t1;
+create table t1 (ucs2_lithuanian_ci char(10) primary key) collate ucs2_lithuanian_ci engine=ibmdb2i;
+drop table t1;
+CREATE TABLE t1 (ucs2_persian_ci integer, c char(10), v varchar(20), index(c), index(v)) collate ucs2_persian_ci engine=ibmdb2i;
+insert into t1 (c,v) values ("abc","def"),("abcd", "def"),("abcde","defg"),("aaaa","bbbb");
+insert into t1 select * from t1;
+explain select c,v from t1 force index(c) where c like "ab%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range c c 21 NULL 6 Using where
+explain select c,v from t1 force index(v) where v like "de%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 43 NULL 6 Using where
+drop table t1;
+create table t1 (ucs2_persian_ci char(10) primary key) collate ucs2_persian_ci engine=ibmdb2i;
+drop table t1;
+CREATE TABLE t1 (ucs2_polish_ci integer, c char(10), v varchar(20), index(c), index(v)) collate ucs2_polish_ci engine=ibmdb2i;
+insert into t1 (c,v) values ("abc","def"),("abcd", "def"),("abcde","defg"),("aaaa","bbbb");
+insert into t1 select * from t1;
+explain select c,v from t1 force index(c) where c like "ab%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range c c 21 NULL 6 Using where
+explain select c,v from t1 force index(v) where v like "de%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 43 NULL 6 Using where
+drop table t1;
+create table t1 (ucs2_polish_ci char(10) primary key) collate ucs2_polish_ci engine=ibmdb2i;
+drop table t1;
+CREATE TABLE t1 (ucs2_romanian_ci integer, c char(10), v varchar(20), index(c), index(v)) collate ucs2_romanian_ci engine=ibmdb2i;
+insert into t1 (c,v) values ("abc","def"),("abcd", "def"),("abcde","defg"),("aaaa","bbbb");
+insert into t1 select * from t1;
+explain select c,v from t1 force index(c) where c like "ab%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range c c 21 NULL 6 Using where
+explain select c,v from t1 force index(v) where v like "de%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 43 NULL 6 Using where
+drop table t1;
+create table t1 (ucs2_romanian_ci char(10) primary key) collate ucs2_romanian_ci engine=ibmdb2i;
+drop table t1;
+CREATE TABLE t1 (ucs2_roman_ci integer, c char(10), v varchar(20), index(c), index(v)) collate ucs2_roman_ci engine=ibmdb2i;
+CREATE TABLE t1 (ucs2_slovak_ci integer, c char(10), v varchar(20), index(c), index(v)) collate ucs2_slovak_ci engine=ibmdb2i;
+insert into t1 (c,v) values ("abc","def"),("abcd", "def"),("abcde","defg"),("aaaa","bbbb");
+insert into t1 select * from t1;
+explain select c,v from t1 force index(c) where c like "ab%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range c c 21 NULL 6 Using where
+explain select c,v from t1 force index(v) where v like "de%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 43 NULL 6 Using where
+drop table t1;
+create table t1 (ucs2_slovak_ci char(10) primary key) collate ucs2_slovak_ci engine=ibmdb2i;
+drop table t1;
+CREATE TABLE t1 (ucs2_slovenian_ci integer, c char(10), v varchar(20), index(c), index(v)) collate ucs2_slovenian_ci engine=ibmdb2i;
+insert into t1 (c,v) values ("abc","def"),("abcd", "def"),("abcde","defg"),("aaaa","bbbb");
+insert into t1 select * from t1;
+explain select c,v from t1 force index(c) where c like "ab%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range c c 21 NULL 6 Using where
+explain select c,v from t1 force index(v) where v like "de%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 43 NULL 6 Using where
+drop table t1;
+create table t1 (ucs2_slovenian_ci char(10) primary key) collate ucs2_slovenian_ci engine=ibmdb2i;
+drop table t1;
+CREATE TABLE t1 (ucs2_spanish2_ci integer, c char(10), v varchar(20), index(c), index(v)) collate ucs2_spanish2_ci engine=ibmdb2i;
+CREATE TABLE t1 (ucs2_spanish_ci integer, c char(10), v varchar(20), index(c), index(v)) collate ucs2_spanish_ci engine=ibmdb2i;
+insert into t1 (c,v) values ("abc","def"),("abcd", "def"),("abcde","defg"),("aaaa","bbbb");
+insert into t1 select * from t1;
+explain select c,v from t1 force index(c) where c like "ab%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range c c 21 NULL 6 Using where
+explain select c,v from t1 force index(v) where v like "de%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 43 NULL 6 Using where
+drop table t1;
+create table t1 (ucs2_spanish_ci char(10) primary key) collate ucs2_spanish_ci engine=ibmdb2i;
+drop table t1;
+CREATE TABLE t1 (ucs2_swedish_ci integer, c char(10), v varchar(20), index(c), index(v)) collate ucs2_swedish_ci engine=ibmdb2i;
+insert into t1 (c,v) values ("abc","def"),("abcd", "def"),("abcde","defg"),("aaaa","bbbb");
+insert into t1 select * from t1;
+explain select c,v from t1 force index(c) where c like "ab%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range c c 21 NULL 6 Using where
+explain select c,v from t1 force index(v) where v like "de%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 43 NULL 6 Using where
+drop table t1;
+create table t1 (ucs2_swedish_ci char(10) primary key) collate ucs2_swedish_ci engine=ibmdb2i;
+drop table t1;
+CREATE TABLE t1 (ucs2_turkish_ci integer, c char(10), v varchar(20), index(c), index(v)) collate ucs2_turkish_ci engine=ibmdb2i;
+insert into t1 (c,v) values ("abc","def"),("abcd", "def"),("abcde","defg"),("aaaa","bbbb");
+insert into t1 select * from t1;
+explain select c,v from t1 force index(c) where c like "ab%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range c c 21 NULL 6 Using where
+explain select c,v from t1 force index(v) where v like "de%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 43 NULL 6 Using where
+drop table t1;
+create table t1 (ucs2_turkish_ci char(10) primary key) collate ucs2_turkish_ci engine=ibmdb2i;
+drop table t1;
+CREATE TABLE t1 (ucs2_unicode_ci integer, c char(10), v varchar(20), index(c), index(v)) collate ucs2_unicode_ci engine=ibmdb2i;
+insert into t1 (c,v) values ("abc","def"),("abcd", "def"),("abcde","defg"),("aaaa","bbbb");
+insert into t1 select * from t1;
+explain select c,v from t1 force index(c) where c like "ab%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range c c 21 NULL 6 Using where
+explain select c,v from t1 force index(v) where v like "de%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 43 NULL 6 Using where
+drop table t1;
+create table t1 (ucs2_unicode_ci char(10) primary key) collate ucs2_unicode_ci engine=ibmdb2i;
+drop table t1;
+CREATE TABLE t1 (ujis_bin integer, c char(10), v varchar(20), index(c), index(v)) collate ujis_bin engine=ibmdb2i;
+insert into t1 (c,v) values ("abc","def"),("abcd", "def"),("abcde","defg"),("aaaa","bbbb");
+insert into t1 select * from t1;
+explain select c,v from t1 force index(c) where c like "ab%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range c c 31 NULL 6 Using where
+explain select c,v from t1 force index(v) where v like "de%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 63 NULL 6 Using where
+drop table t1;
+create table t1 (ujis_bin char(10) primary key) collate ujis_bin engine=ibmdb2i;
+drop table t1;
+CREATE TABLE t1 (ujis_japanese_ci integer, c char(10), v varchar(20), index(c), index(v)) collate ujis_japanese_ci engine=ibmdb2i;
+insert into t1 (c,v) values ("abc","def"),("abcd", "def"),("abcde","defg"),("aaaa","bbbb");
+insert into t1 select * from t1;
+explain select c,v from t1 force index(c) where c like "ab%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range c c 31 NULL 6 Using where
+explain select c,v from t1 force index(v) where v like "de%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 63 NULL 6 Using where
+drop table t1;
+create table t1 (ujis_japanese_ci char(10) primary key) collate ujis_japanese_ci engine=ibmdb2i;
+drop table t1;
+CREATE TABLE t1 (utf8_bin integer, c char(10), v varchar(20), index(c), index(v)) collate utf8_bin engine=ibmdb2i;
+insert into t1 (c,v) values ("abc","def"),("abcd", "def"),("abcde","defg"),("aaaa","bbbb");
+insert into t1 select * from t1;
+explain select c,v from t1 force index(c) where c like "ab%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range c c 31 NULL 6 Using where
+explain select c,v from t1 force index(v) where v like "de%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 63 NULL 6 Using where
+drop table t1;
+create table t1 (utf8_bin char(10) primary key) collate utf8_bin engine=ibmdb2i;
+drop table t1;
+CREATE TABLE t1 (utf8_czech_ci integer, c char(10), v varchar(20), index(c), index(v)) collate utf8_czech_ci engine=ibmdb2i;
+insert into t1 (c,v) values ("abc","def"),("abcd", "def"),("abcde","defg"),("aaaa","bbbb");
+insert into t1 select * from t1;
+explain select c,v from t1 force index(c) where c like "ab%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range c c 31 NULL 6 Using where
+explain select c,v from t1 force index(v) where v like "de%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 63 NULL 6 Using where
+drop table t1;
+create table t1 (utf8_czech_ci char(10) primary key) collate utf8_czech_ci engine=ibmdb2i;
+drop table t1;
+CREATE TABLE t1 (utf8_danish_ci integer, c char(10), v varchar(20), index(c), index(v)) collate utf8_danish_ci engine=ibmdb2i;
+insert into t1 (c,v) values ("abc","def"),("abcd", "def"),("abcde","defg"),("aaaa","bbbb");
+insert into t1 select * from t1;
+explain select c,v from t1 force index(c) where c like "ab%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range c c 31 NULL 6 Using where
+explain select c,v from t1 force index(v) where v like "de%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 63 NULL 6 Using where
+drop table t1;
+create table t1 (utf8_danish_ci char(10) primary key) collate utf8_danish_ci engine=ibmdb2i;
+drop table t1;
+CREATE TABLE t1 (utf8_esperanto_ci integer, c char(10), v varchar(20), index(c), index(v)) collate utf8_esperanto_ci engine=ibmdb2i;
+insert into t1 (c,v) values ("abc","def"),("abcd", "def"),("abcde","defg"),("aaaa","bbbb");
+insert into t1 select * from t1;
+explain select c,v from t1 force index(c) where c like "ab%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range c c 31 NULL 6 Using where
+explain select c,v from t1 force index(v) where v like "de%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 63 NULL 6 Using where
+drop table t1;
+create table t1 (utf8_esperanto_ci char(10) primary key) collate utf8_esperanto_ci engine=ibmdb2i;
+drop table t1;
+CREATE TABLE t1 (utf8_estonian_ci integer, c char(10), v varchar(20), index(c), index(v)) collate utf8_estonian_ci engine=ibmdb2i;
+insert into t1 (c,v) values ("abc","def"),("abcd", "def"),("abcde","defg"),("aaaa","bbbb");
+insert into t1 select * from t1;
+explain select c,v from t1 force index(c) where c like "ab%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range c c 31 NULL 6 Using where
+explain select c,v from t1 force index(v) where v like "de%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 63 NULL 6 Using where
+drop table t1;
+create table t1 (utf8_estonian_ci char(10) primary key) collate utf8_estonian_ci engine=ibmdb2i;
+drop table t1;
+CREATE TABLE t1 (utf8_general_ci integer, c char(10), v varchar(20), index(c), index(v)) collate utf8_general_ci engine=ibmdb2i;
+insert into t1 (c,v) values ("abc","def"),("abcd", "def"),("abcde","defg"),("aaaa","bbbb");
+insert into t1 select * from t1;
+explain select c,v from t1 force index(c) where c like "ab%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range c c 31 NULL 6 Using where
+explain select c,v from t1 force index(v) where v like "de%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 63 NULL 6 Using where
+drop table t1;
+create table t1 (utf8_general_ci char(10) primary key) collate utf8_general_ci engine=ibmdb2i;
+drop table t1;
+CREATE TABLE t1 (utf8_hungarian_ci integer, c char(10), v varchar(20), index(c), index(v)) collate utf8_hungarian_ci engine=ibmdb2i;
+insert into t1 (c,v) values ("abc","def"),("abcd", "def"),("abcde","defg"),("aaaa","bbbb");
+insert into t1 select * from t1;
+explain select c,v from t1 force index(c) where c like "ab%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range c c 31 NULL 6 Using where
+explain select c,v from t1 force index(v) where v like "de%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 63 NULL 6 Using where
+drop table t1;
+create table t1 (utf8_hungarian_ci char(10) primary key) collate utf8_hungarian_ci engine=ibmdb2i;
+drop table t1;
+CREATE TABLE t1 (utf8_icelandic_ci integer, c char(10), v varchar(20), index(c), index(v)) collate utf8_icelandic_ci engine=ibmdb2i;
+insert into t1 (c,v) values ("abc","def"),("abcd", "def"),("abcde","defg"),("aaaa","bbbb");
+insert into t1 select * from t1;
+explain select c,v from t1 force index(c) where c like "ab%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range c c 31 NULL 6 Using where
+explain select c,v from t1 force index(v) where v like "de%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 63 NULL 6 Using where
+drop table t1;
+create table t1 (utf8_icelandic_ci char(10) primary key) collate utf8_icelandic_ci engine=ibmdb2i;
+drop table t1;
+CREATE TABLE t1 (utf8_latvian_ci integer, c char(10), v varchar(20), index(c), index(v)) collate utf8_latvian_ci engine=ibmdb2i;
+insert into t1 (c,v) values ("abc","def"),("abcd", "def"),("abcde","defg"),("aaaa","bbbb");
+insert into t1 select * from t1;
+explain select c,v from t1 force index(c) where c like "ab%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range c c 31 NULL 6 Using where
+explain select c,v from t1 force index(v) where v like "de%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 63 NULL 6 Using where
+drop table t1;
+create table t1 (utf8_latvian_ci char(10) primary key) collate utf8_latvian_ci engine=ibmdb2i;
+drop table t1;
+CREATE TABLE t1 (utf8_lithuanian_ci integer, c char(10), v varchar(20), index(c), index(v)) collate utf8_lithuanian_ci engine=ibmdb2i;
+insert into t1 (c,v) values ("abc","def"),("abcd", "def"),("abcde","defg"),("aaaa","bbbb");
+insert into t1 select * from t1;
+explain select c,v from t1 force index(c) where c like "ab%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range c c 31 NULL 6 Using where
+explain select c,v from t1 force index(v) where v like "de%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 63 NULL 6 Using where
+drop table t1;
+create table t1 (utf8_lithuanian_ci char(10) primary key) collate utf8_lithuanian_ci engine=ibmdb2i;
+drop table t1;
+CREATE TABLE t1 (utf8_persian_ci integer, c char(10), v varchar(20), index(c), index(v)) collate utf8_persian_ci engine=ibmdb2i;
+insert into t1 (c,v) values ("abc","def"),("abcd", "def"),("abcde","defg"),("aaaa","bbbb");
+insert into t1 select * from t1;
+explain select c,v from t1 force index(c) where c like "ab%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range c c 31 NULL 6 Using where
+explain select c,v from t1 force index(v) where v like "de%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 63 NULL 6 Using where
+drop table t1;
+create table t1 (utf8_persian_ci char(10) primary key) collate utf8_persian_ci engine=ibmdb2i;
+drop table t1;
+CREATE TABLE t1 (utf8_polish_ci integer, c char(10), v varchar(20), index(c), index(v)) collate utf8_polish_ci engine=ibmdb2i;
+insert into t1 (c,v) values ("abc","def"),("abcd", "def"),("abcde","defg"),("aaaa","bbbb");
+insert into t1 select * from t1;
+explain select c,v from t1 force index(c) where c like "ab%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range c c 31 NULL 6 Using where
+explain select c,v from t1 force index(v) where v like "de%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 63 NULL 6 Using where
+drop table t1;
+create table t1 (utf8_polish_ci char(10) primary key) collate utf8_polish_ci engine=ibmdb2i;
+drop table t1;
+CREATE TABLE t1 (utf8_romanian_ci integer, c char(10), v varchar(20), index(c), index(v)) collate utf8_romanian_ci engine=ibmdb2i;
+insert into t1 (c,v) values ("abc","def"),("abcd", "def"),("abcde","defg"),("aaaa","bbbb");
+insert into t1 select * from t1;
+explain select c,v from t1 force index(c) where c like "ab%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range c c 31 NULL 6 Using where
+explain select c,v from t1 force index(v) where v like "de%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 63 NULL 6 Using where
+drop table t1;
+create table t1 (utf8_romanian_ci char(10) primary key) collate utf8_romanian_ci engine=ibmdb2i;
+drop table t1;
+CREATE TABLE t1 (utf8_roman_ci integer, c char(10), v varchar(20), index(c), index(v)) collate utf8_roman_ci engine=ibmdb2i;
+CREATE TABLE t1 (utf8_slovak_ci integer, c char(10), v varchar(20), index(c), index(v)) collate utf8_slovak_ci engine=ibmdb2i;
+insert into t1 (c,v) values ("abc","def"),("abcd", "def"),("abcde","defg"),("aaaa","bbbb");
+insert into t1 select * from t1;
+explain select c,v from t1 force index(c) where c like "ab%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range c c 31 NULL 6 Using where
+explain select c,v from t1 force index(v) where v like "de%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 63 NULL 6 Using where
+drop table t1;
+create table t1 (utf8_slovak_ci char(10) primary key) collate utf8_slovak_ci engine=ibmdb2i;
+drop table t1;
+CREATE TABLE t1 (utf8_slovenian_ci integer, c char(10), v varchar(20), index(c), index(v)) collate utf8_slovenian_ci engine=ibmdb2i;
+insert into t1 (c,v) values ("abc","def"),("abcd", "def"),("abcde","defg"),("aaaa","bbbb");
+insert into t1 select * from t1;
+explain select c,v from t1 force index(c) where c like "ab%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range c c 31 NULL 6 Using where
+explain select c,v from t1 force index(v) where v like "de%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 63 NULL 6 Using where
+drop table t1;
+create table t1 (utf8_slovenian_ci char(10) primary key) collate utf8_slovenian_ci engine=ibmdb2i;
+drop table t1;
+CREATE TABLE t1 (utf8_spanish2_ci integer, c char(10), v varchar(20), index(c), index(v)) collate utf8_spanish2_ci engine=ibmdb2i;
+CREATE TABLE t1 (utf8_spanish_ci integer, c char(10), v varchar(20), index(c), index(v)) collate utf8_spanish_ci engine=ibmdb2i;
+insert into t1 (c,v) values ("abc","def"),("abcd", "def"),("abcde","defg"),("aaaa","bbbb");
+insert into t1 select * from t1;
+explain select c,v from t1 force index(c) where c like "ab%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range c c 31 NULL 6 Using where
+explain select c,v from t1 force index(v) where v like "de%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 63 NULL 6 Using where
+drop table t1;
+create table t1 (utf8_spanish_ci char(10) primary key) collate utf8_spanish_ci engine=ibmdb2i;
+drop table t1;
+CREATE TABLE t1 (utf8_swedish_ci integer, c char(10), v varchar(20), index(c), index(v)) collate utf8_swedish_ci engine=ibmdb2i;
+insert into t1 (c,v) values ("abc","def"),("abcd", "def"),("abcde","defg"),("aaaa","bbbb");
+insert into t1 select * from t1;
+explain select c,v from t1 force index(c) where c like "ab%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range c c 31 NULL 6 Using where
+explain select c,v from t1 force index(v) where v like "de%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 63 NULL 6 Using where
+drop table t1;
+create table t1 (utf8_swedish_ci char(10) primary key) collate utf8_swedish_ci engine=ibmdb2i;
+drop table t1;
+CREATE TABLE t1 (utf8_turkish_ci integer, c char(10), v varchar(20), index(c), index(v)) collate utf8_turkish_ci engine=ibmdb2i;
+insert into t1 (c,v) values ("abc","def"),("abcd", "def"),("abcde","defg"),("aaaa","bbbb");
+insert into t1 select * from t1;
+explain select c,v from t1 force index(c) where c like "ab%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range c c 31 NULL 6 Using where
+explain select c,v from t1 force index(v) where v like "de%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 63 NULL 6 Using where
+drop table t1;
+create table t1 (utf8_turkish_ci char(10) primary key) collate utf8_turkish_ci engine=ibmdb2i;
+drop table t1;
+CREATE TABLE t1 (utf8_unicode_ci integer, c char(10), v varchar(20), index(c), index(v)) collate utf8_unicode_ci engine=ibmdb2i;
+insert into t1 (c,v) values ("abc","def"),("abcd", "def"),("abcde","defg"),("aaaa","bbbb");
+insert into t1 select * from t1;
+explain select c,v from t1 force index(c) where c like "ab%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range c c 31 NULL 6 Using where
+explain select c,v from t1 force index(v) where v like "de%";
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 range v v 63 NULL 6 Using where
+drop table t1;
+create table t1 (utf8_unicode_ci char(10) primary key) collate utf8_unicode_ci engine=ibmdb2i;
+drop table t1;
+create table ffd (WHCHD1 CHAR(20), WHCSID decimal(5,0)) engine=ibmdb2i;
+create table fd (SQSSEQ CHAR(10)) engine=ibmdb2i;
+create temporary table intermed (row integer key auto_increment, cs char(30), ccsid integer);
+insert into intermed (cs, ccsid) select * from ffd;
+create temporary table intermed2 (row integer key auto_increment, srtseq char(10));
+insert into intermed2 (srtseq) select * from fd;
+select ccsid, cs, srtseq from intermed inner join intermed2 on intermed.row = intermed2.row;
+ccsid cs srtseq
+500 "ascii_bin" QBLA101F4U
+500 "ascii_general_ci" QALA101F4S
+1200 "big5_bin" QBCHT04B0U
+1200 "big5_chinese_ci" QACHT04B0S
+1153 "cp1250_bin" QELA20481U
+1153 "cp1250_croatian_ci" QALA20481S
+1153 "cp1250_general_ci" QCLA20481S
+1153 "cp1250_polish_ci" QDLA20481S
+1025 "cp1251_bin" QCCYR0401U
+1025 "cp1251_bulgarian_ci QACYR0401S
+1025 "cp1251_general_ci" QBCYR0401S
+1025 "cp1251_general_cs" QBCYR0401U
+420 "cp1256_bin" QBARA01A4U
+420 "cp1256_general_ci" QAARA01A4S
+500 "cp850_bin" QDLA101F4U
+500 "cp850_general_ci" QCLA101F4S
+870 "cp852_bin" QBLA20366U
+870 "cp852_general_ci" QALA20366S
+1200 "cp932_bin" QBJPN04B0U
+1200 "cp932_japanese_ci" QAJPN04B0S
+1200 "euckr_bin" QBKOR04B0U
+1200 "euckr_korean_ci" QAKOR04B0S
+1200 "gb2312_bin" QBCHS04B0U
+1200 "gb2312_chinese_ci" QACHS04B0S
+1200 "gbk_bin" QDCHS04B0U
+1200 "gbk_chinese_ci" QCCHS04B0S
+875 "greek_bin" QBELL036BU
+875 "greek_general_ci" QAELL036BS
+424 "hebrew_bin" QBHEB01A8U
+424 "hebrew_general_ci" QAHEB01A8S
+1148 "latin1_bin" QFLA1047CU
+1148 "latin1_danish_ci" QALA1047CS
+1148 "latin1_general_ci" QBLA1047CS
+1148 "latin1_general_cs" QBLA1047CU
+1148 "latin1_german1_ci" QCLA1047CS
+1148 "latin1_spanish_ci" QDLA1047CS
+1148 "latin1_swedish_ci" QELA1047CS
+870 "latin2_bin" QGLA20366U
+870 "latin2_croatian_ci" QCLA20366S
+870 "latin2_general_ci" QELA20366S
+870 "latin2_hungarian_ci QFLA20366S
+1026 "latin5_bin" QBTRK0402U
+1026 "latin5_turkish_ci" QATRK0402S
+870 "macce_bin" QILA20366U
+870 "macce_general_ci" QHLA20366S
+1200 "sjis_bin" QDJPN04B0U
+1200 "sjis_japanese_ci" QCJPN04B0S
+838 "tis620_bin" QBTHA0346U
+838 "tis620_thai_ci" QATHA0346S
+13488 "ucs2_bin" *HEX
+13488 "ucs2_czech_ci" I34ACS_CZ
+13488 "ucs2_danish_ci" I34ADA_DK
+13488 "ucs2_esperanto_ci" I34AEO
+13488 "ucs2_estonian_ci" I34AET
+13488 "ucs2_general_ci" QAUCS04B0S
+13488 "ucs2_hungarian_ci" I34AHU
+13488 "ucs2_icelandic_ci" I34AIS
+13488 "ucs2_latvian_ci" I34ALV
+13488 "ucs2_lithuanian_ci" I34ALT
+13488 "ucs2_persian_ci" I34AFA
+13488 "ucs2_polish_ci" I34APL
+13488 "ucs2_romanian_ci" I34ARO
+13488 "ucs2_slovak_ci" I34ASK
+13488 "ucs2_slovenian_ci" I34ASL
+13488 "ucs2_spanish_ci" I34AES
+13488 "ucs2_swedish_ci" I34ASW
+13488 "ucs2_turkish_ci" I34ATR
+13488 "ucs2_unicode_ci" I34AEN
+1200 "ujis_bin" QFJPN04B0U
+1200 "ujis_japanese_ci" QEJPN04B0S
+1208 "utf8_bin" *HEX
+1208 "utf8_czech_ci" I34ACS_CZ
+1208 "utf8_danish_ci" I34ADA_DK
+1208 "utf8_esperanto_ci" I34AEO
+1208 "utf8_estonian_ci" I34AET
+1200 "utf8_general_ci" QAUCS04B0S
+1208 "utf8_hungarian_ci" I34AHU
+1208 "utf8_icelandic_ci" I34AIS
+1208 "utf8_latvian_ci" I34ALV
+1208 "utf8_lithuanian_ci" I34ALT
+1208 "utf8_persian_ci" I34AFA
+1208 "utf8_polish_ci" I34APL
+1208 "utf8_romanian_ci" I34ARO
+1208 "utf8_slovak_ci" I34ASK
+1208 "utf8_slovenian_ci" I34ASL
+1208 "utf8_spanish_ci" I34AES
+1208 "utf8_swedish_ci" I34ASW
+1208 "utf8_turkish_ci" I34ATR
+1208 "utf8_unicode_ci" I34AEN
+drop table ffd, fd;
diff --git a/mysql-test/suite/ibmdb2i/t/ibmdb2i_bug_44232.test b/mysql-test/suite/ibmdb2i/t/ibmdb2i_bug_44232.test
new file mode 100755
index 00000000000..ea29b5abcd4
--- /dev/null
+++ b/mysql-test/suite/ibmdb2i/t/ibmdb2i_bug_44232.test
@@ -0,0 +1,8 @@
+--source suite/ibmdb2i/include/have_ibmdb2i.inc
+--source suite/ibmdb2i/include/have_i54.inc
+
+--error 1005
+create table t1 (c char(1) character set armscii8) engine=ibmdb2i;
+
+--error 1005
+create table t1 (c char(1) character set eucjpms ) engine=ibmdb2i;
diff --git a/mysql-test/suite/ibmdb2i/t/ibmdb2i_bug_44610.test b/mysql-test/suite/ibmdb2i/t/ibmdb2i_bug_44610.test
new file mode 100755
index 00000000000..da69b5d9148
--- /dev/null
+++ b/mysql-test/suite/ibmdb2i/t/ibmdb2i_bug_44610.test
@@ -0,0 +1,28 @@
+source suite/ibmdb2i/include/have_ibmdb2i.inc;
+
+# Test RCDFMT generation for a variety of kinds of table names
+create table ABC (i int) engine=ibmdb2i;
+drop table ABC;
+
+create table `1234567890ABC` (i int) engine=ibmdb2i;
+drop table `1234567890ABC`;
+
+create table `!@#$%` (i int) engine=ibmdb2i;
+drop table `!@#$%`;
+
+create table `ABCD#########` (i int) engine=ibmdb2i;
+drop table `ABCD#########`;
+
+create table `_` (i int) engine=ibmdb2i;
+drop table `_`;
+
+create table `abc##def` (i int) engine=ibmdb2i;
+drop table `abc##def`;
+
+set names utf8;
+create table İ (s1 int) engine=ibmdb2i;
+drop table İ;
+
+create table İİ (s1 int) engine=ibmdb2i;
+drop table İİ;
+set names latin1;
diff --git a/mysql-test/suite/ibmdb2i/t/ibmdb2i_bug_45196.test b/mysql-test/suite/ibmdb2i/t/ibmdb2i_bug_45196.test
new file mode 100644
index 00000000000..17b1d658975
--- /dev/null
+++ b/mysql-test/suite/ibmdb2i/t/ibmdb2i_bug_45196.test
@@ -0,0 +1,26 @@
+source suite/ibmdb2i/include/have_ibmdb2i.inc;
+source suite/ibmdb2i/include/have_i61.inc;
+
+--disable_warnings
+drop table if exists t1;
+--enable_warnings
+
+create table t1 (c char(10), index(c)) collate ucs2_czech_ci engine=ibmdb2i;
+insert into t1 values ("ch"),("h"),("i");
+select * from t1 order by c;
+drop table t1;
+
+create table t1 (c char(10), index(c)) collate utf8_czech_ci engine=ibmdb2i;
+insert into t1 values ("ch"),("h"),("i");
+select * from t1 order by c;
+drop table t1;
+
+create table t1 (c char(10), index(c)) collate ucs2_danish_ci engine=ibmdb2i;
+insert into t1 values("abc"),("abcd"),("aaaa");
+select c from t1 order by c;
+drop table t1;
+
+create table t1 (c char(10), index(c)) collate utf8_danish_ci engine=ibmdb2i;
+insert into t1 values("abc"),("abcd"),("aaaa");
+select c from t1 order by c;
+drop table t1;
diff --git a/mysql-test/suite/ibmdb2i/t/ibmdb2i_bug_45793.test b/mysql-test/suite/ibmdb2i/t/ibmdb2i_bug_45793.test
new file mode 100644
index 00000000000..93fb78ff421
--- /dev/null
+++ b/mysql-test/suite/ibmdb2i/t/ibmdb2i_bug_45793.test
@@ -0,0 +1,11 @@
+source suite/ibmdb2i/include/have_ibmdb2i.inc;
+source suite/ibmdb2i/include/have_i61.inc;
+
+--disable_warnings
+drop table if exists t1;
+--enable_warnings
+
+create table t1 (c char(10), index(c)) charset macce engine=ibmdb2i;
+insert into t1 values ("test");
+select * from t1 order by c;
+drop table t1;
diff --git a/mysql-test/suite/ibmdb2i/t/ibmdb2i_bug_45983.test b/mysql-test/suite/ibmdb2i/t/ibmdb2i_bug_45983.test
new file mode 100644
index 00000000000..695d8e90ada
--- /dev/null
+++ b/mysql-test/suite/ibmdb2i/t/ibmdb2i_bug_45983.test
@@ -0,0 +1,47 @@
+source suite/ibmdb2i/include/have_ibmdb2i.inc;
+
+# Confirm that ibmdb2i_create_index_option causes additional *HEX sorted indexes to be created for all non-binary keys.
+
+set ibmdb2i_create_index_option=1;
+--disable_warnings
+drop schema if exists test1;
+create schema test1;
+use test1;
+--enable_warnings
+
+--disable_abort_on_error
+--error 0,255
+exec system "DLTF QGPL/FDOUT" > /dev/null;
+--enable_abort_on_error
+
+#No additional index because no string fields in key
+CREATE TABLE t1 (f int primary key, index(f)) engine=ibmdb2i;
+--error 255
+exec system "DSPFD FILE(\"test1\"/PRIM0001) TYPE(*SEQ) OUTPUT(*OUTFILE) OUTFILE(QGPL/FDOUT) OUTMBR(*FIRST *ADD)" > /dev/null;
+--error 255
+exec system "DSPFD FILE(\"test1\"/\"f___H_t1\") TYPE(*SEQ) OUTPUT(*OUTFILE) OUTFILE(QGPL/FDOUT) OUTMBR(*FIRST *ADD)" > /dev/null;
+drop table t1;
+
+#No additional index because binary sorting
+CREATE TABLE t1 (f char(10) collate utf8_bin primary key, index(f)) engine=ibmdb2i;
+--error 255
+exec system "DSPFD FILE(\"test1\"/PRIM0001) TYPE(*SEQ) OUTPUT(*OUTFILE) OUTFILE(QGPL/FDOUT) OUTMBR(*FIRST *ADD)" > /dev/null;
+--error 255
+exec system "DSPFD FILE(\"test1\"/\"f___H_t1\") TYPE(*SEQ) OUTPUT(*OUTFILE) OUTFILE(QGPL/FDOUT) OUTMBR(*FIRST *ADD)" > /dev/null;
+drop table t1;
+
+CREATE TABLE t1 (f char(10) collate latin1_swedish_ci primary key, index(f)) engine=ibmdb2i;
+exec system "DSPFD FILE(\"test1\"/PRIM0001) TYPE(*SEQ) OUTPUT(*OUTFILE) OUTFILE(QGPL/FDOUT) OUTMBR(*FIRST *ADD)" > /dev/null;
+exec system "DSPFD FILE(\"test1\"/\"f___H_t1\") TYPE(*SEQ) OUTPUT(*OUTFILE) OUTFILE(QGPL/FDOUT) OUTMBR(*FIRST *ADD)" > /dev/null;
+drop table t1;
+
+CREATE TABLE t1 (f char(10) collate latin1_swedish_ci primary key, i int, index i(i,f)) engine=ibmdb2i;
+exec system "DSPFD FILE(\"test1\"/PRIM0001) TYPE(*SEQ) OUTPUT(*OUTFILE) OUTFILE(QGPL/FDOUT) OUTMBR(*FIRST *ADD)" > /dev/null;
+exec system "DSPFD FILE(\"test1\"/\"i___H_t1\") TYPE(*SEQ) OUTPUT(*OUTFILE) OUTFILE(QGPL/FDOUT) OUTMBR(*FIRST *ADD)" > /dev/null;
+drop table t1;
+
+
+create table fd (SQSSEQ CHAR(10)) engine=ibmdb2i;
+system system "CPYF FROMFILE(QGPL/FDOUT) TOFILE(\"test1\"/\"fd\") mbropt(*replace) fmtopt(*drop *map)" > /dev/null;
+select * from fd;
+drop table fd;
diff --git a/mysql-test/suite/ibmdb2i/t/ibmdb2i_collations.test b/mysql-test/suite/ibmdb2i/t/ibmdb2i_collations.test
new file mode 100644
index 00000000000..899f330d360
--- /dev/null
+++ b/mysql-test/suite/ibmdb2i/t/ibmdb2i_collations.test
@@ -0,0 +1,44 @@
+source suite/ibmdb2i/include/have_ibmdb2i.inc;
+source suite/ibmdb2i/include/have_i61.inc;
+--disable_warnings
+drop table if exists t1, ffd, fd;
+--enable_warnings
+
+--disable_abort_on_error
+--error 0,255
+exec system "DLTF QGPL/FFDOUT" > /dev/null;
+--error 0,255
+exec system "DLTF QGPL/FDOUT" > /dev/null;
+--enable_abort_on_error
+let $count= query_get_value(select count(*) from information_schema.COLLATIONS where COLLATION_NAME <> "binary", count(*),1);
+
+while ($count)
+{
+ let $collation = query_get_value(select COLLATION_NAME from information_schema.COLLATIONS where COLLATION_NAME <> "binary" order by COLLATION_NAME desc, COLLATION_NAME, $count);
+ error 0,1005,2504,2028;
+ eval CREATE TABLE t1 ($collation integer, c char(10), v varchar(20), index(c), index(v)) collate $collation engine=ibmdb2i;
+ if (!$mysql_errno)
+ {
+ insert into t1 (c,v) values ("abc","def"),("abcd", "def"),("abcde","defg"),("aaaa","bbbb");
+ insert into t1 select * from t1;
+ explain select c,v from t1 force index(c) where c like "ab%";
+ explain select c,v from t1 force index(v) where v like "de%";
+ drop table t1;
+ eval create table t1 ($collation char(10) primary key) collate $collation engine=ibmdb2i;
+ system system "DSPFFD FILE(\"test\"/\"t1\") OUTPUT(*OUTFILE) OUTFILE(QGPL/FFDOUT) OUTMBR(*FIRST *ADD)" > /dev/null;
+ system system "DSPFD FILE(\"test\"/\"t1\") TYPE(*SEQ) OUTPUT(*OUTFILE) OUTFILE(QGPL/FDOUT) OUTMBR(*FIRST *ADD)" > /dev/null;
+ drop table t1;
+ }
+ dec $count;
+}
+
+create table ffd (WHCHD1 CHAR(20), WHCSID decimal(5,0)) engine=ibmdb2i;
+system system "CPYF FROMFILE(QGPL/FFDOUT) TOFILE(\"test\"/\"ffd\") mbropt(*replace) fmtopt(*drop *map)" > /dev/null;
+create table fd (SQSSEQ CHAR(10)) engine=ibmdb2i;
+system system "CPYF FROMFILE(QGPL/FDOUT) TOFILE(\"test\"/\"fd\") mbropt(*replace) fmtopt(*drop *map)" > /dev/null;
+create temporary table intermed (row integer key auto_increment, cs char(30), ccsid integer);
+insert into intermed (cs, ccsid) select * from ffd;
+create temporary table intermed2 (row integer key auto_increment, srtseq char(10));
+insert into intermed2 (srtseq) select * from fd;
+select ccsid, cs, srtseq from intermed inner join intermed2 on intermed.row = intermed2.row;
+drop table ffd, fd;
diff --git a/mysql-test/suite/innodb/include/have_innodb_plugin.inc b/mysql-test/suite/innodb/include/have_innodb_plugin.inc
new file mode 100644
index 00000000000..24af3274ada
--- /dev/null
+++ b/mysql-test/suite/innodb/include/have_innodb_plugin.inc
@@ -0,0 +1,4 @@
+disable_query_log;
+--require r/true.require
+select (PLUGIN_LIBRARY LIKE 'ha_innodb_plugin%') as `TRUE` from information_schema.plugins where PLUGIN_NAME='InnoDB';
+enable_query_log;
diff --git a/mysql-test/suite/innodb/include/innodb-index.inc b/mysql-test/suite/innodb/include/innodb-index.inc
new file mode 100644
index 00000000000..37de3162abe
--- /dev/null
+++ b/mysql-test/suite/innodb/include/innodb-index.inc
@@ -0,0 +1,26 @@
+--eval create table t1(a int not null, b int, c char(10), d varchar(20), primary key (a)) engine = innodb default charset=$charset
+insert into t1 values (1,1,'ab','ab'),(2,2,'ac','ac'),(3,2,'ad','ad'),(4,4,'afe','afe');
+commit;
+--error ER_DUP_ENTRY
+alter table t1 add unique index (b);
+insert into t1 values(8,9,'fff','fff');
+select * from t1;
+show create table t1;
+alter table t1 add index (b);
+insert into t1 values(10,10,'kkk','iii');
+select * from t1;
+select * from t1 force index(b) order by b;
+explain select * from t1 force index(b) order by b;
+show create table t1;
+alter table t1 add unique index (c), add index (d);
+insert into t1 values(11,11,'aaa','mmm');
+select * from t1;
+select * from t1 force index(b) order by b;
+select * from t1 force index(c) order by c;
+select * from t1 force index(d) order by d;
+explain select * from t1 force index(b) order by b;
+explain select * from t1 force index(c) order by c;
+explain select * from t1 force index(d) order by d;
+show create table t1;
+check table t1;
+drop table t1;
diff --git a/mysql-test/suite/innodb/r/innodb-analyze.result b/mysql-test/suite/innodb/r/innodb-analyze.result
new file mode 100644
index 00000000000..2aee004a2d6
--- /dev/null
+++ b/mysql-test/suite/innodb/r/innodb-analyze.result
@@ -0,0 +1,2 @@
+Variable_name Value
+innodb_stats_sample_pages 1
diff --git a/mysql-test/suite/innodb/r/innodb-index.result b/mysql-test/suite/innodb/r/innodb-index.result
new file mode 100644
index 00000000000..a7d66b15300
--- /dev/null
+++ b/mysql-test/suite/innodb/r/innodb-index.result
@@ -0,0 +1,1170 @@
+create table t1(a int not null, b int, c char(10) not null, d varchar(20)) engine = innodb;
+insert into t1 values (5,5,'oo','oo'),(4,4,'tr','tr'),(3,4,'ad','ad'),(2,3,'ak','ak');
+commit;
+alter table t1 add index b (b), add index b (b);
+ERROR 42000: Duplicate key name 'b'
+alter table t1 add index (b,b);
+ERROR 42S21: Duplicate column name 'b'
+alter table t1 add index d2 (d);
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) NOT NULL,
+ `b` int(11) DEFAULT NULL,
+ `c` char(10) NOT NULL,
+ `d` varchar(20) DEFAULT NULL,
+ KEY `d2` (`d`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+explain select * from t1 force index(d2) order by d;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index NULL d2 23 NULL 4
+select * from t1 force index (d2) order by d;
+a b c d
+3 4 ad ad
+2 3 ak ak
+5 5 oo oo
+4 4 tr tr
+alter table t1 add unique index (b);
+ERROR 23000: Duplicate entry '4' for key 'b'
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) NOT NULL,
+ `b` int(11) DEFAULT NULL,
+ `c` char(10) NOT NULL,
+ `d` varchar(20) DEFAULT NULL,
+ KEY `d2` (`d`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+alter table t1 add index (b);
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) NOT NULL,
+ `b` int(11) DEFAULT NULL,
+ `c` char(10) NOT NULL,
+ `d` varchar(20) DEFAULT NULL,
+ KEY `d2` (`d`),
+ KEY `b` (`b`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+CREATE TABLE `t1#1`(a INT PRIMARY KEY) ENGINE=InnoDB;
+alter table t1 add unique index (c), add index (d);
+ERROR HY000: Table 'test.t1#1' already exists
+rename table `t1#1` to `t1#2`;
+alter table t1 add unique index (c), add index (d);
+ERROR HY000: Table 'test.t1#2' already exists
+drop table `t1#2`;
+alter table t1 add unique index (c), add index (d);
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) NOT NULL,
+ `b` int(11) DEFAULT NULL,
+ `c` char(10) NOT NULL,
+ `d` varchar(20) DEFAULT NULL,
+ UNIQUE KEY `c` (`c`),
+ KEY `d2` (`d`),
+ KEY `b` (`b`),
+ KEY `d` (`d`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+explain select * from t1 force index(c) order by c;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index NULL c 10 NULL 4
+alter table t1 add primary key (a), drop index c;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) NOT NULL,
+ `b` int(11) DEFAULT NULL,
+ `c` char(10) NOT NULL,
+ `d` varchar(20) DEFAULT NULL,
+ PRIMARY KEY (`a`),
+ KEY `d2` (`d`),
+ KEY `b` (`b`),
+ KEY `d` (`d`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+alter table t1 add primary key (c);
+ERROR 42000: Multiple primary key defined
+alter table t1 drop primary key, add primary key (b);
+ERROR 23000: Duplicate entry '4' for key 'PRIMARY'
+create unique index c on t1 (c);
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) NOT NULL,
+ `b` int(11) DEFAULT NULL,
+ `c` char(10) NOT NULL,
+ `d` varchar(20) DEFAULT NULL,
+ PRIMARY KEY (`a`),
+ UNIQUE KEY `c` (`c`),
+ KEY `d2` (`d`),
+ KEY `b` (`b`),
+ KEY `d` (`d`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+explain select * from t1 force index(c) order by c;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index NULL c 10 NULL 4
+select * from t1 force index(c) order by c;
+a b c d
+3 4 ad ad
+2 3 ak ak
+5 5 oo oo
+4 4 tr tr
+alter table t1 drop index b, add index (b);
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) NOT NULL,
+ `b` int(11) DEFAULT NULL,
+ `c` char(10) NOT NULL,
+ `d` varchar(20) DEFAULT NULL,
+ PRIMARY KEY (`a`),
+ UNIQUE KEY `c` (`c`),
+ KEY `d2` (`d`),
+ KEY `d` (`d`),
+ KEY `b` (`b`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+insert into t1 values(6,1,'ggg','ggg');
+select * from t1;
+a b c d
+2 3 ak ak
+3 4 ad ad
+4 4 tr tr
+5 5 oo oo
+6 1 ggg ggg
+select * from t1 force index(b) order by b;
+a b c d
+6 1 ggg ggg
+2 3 ak ak
+3 4 ad ad
+4 4 tr tr
+5 5 oo oo
+select * from t1 force index(c) order by c;
+a b c d
+3 4 ad ad
+2 3 ak ak
+6 1 ggg ggg
+5 5 oo oo
+4 4 tr tr
+select * from t1 force index(d) order by d;
+a b c d
+3 4 ad ad
+2 3 ak ak
+6 1 ggg ggg
+5 5 oo oo
+4 4 tr tr
+explain select * from t1 force index(b) order by b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index NULL b 5 NULL 5
+explain select * from t1 force index(c) order by c;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index NULL c 10 NULL 5
+explain select * from t1 force index(d) order by d;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index NULL d 23 NULL 5
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) NOT NULL,
+ `b` int(11) DEFAULT NULL,
+ `c` char(10) NOT NULL,
+ `d` varchar(20) DEFAULT NULL,
+ PRIMARY KEY (`a`),
+ UNIQUE KEY `c` (`c`),
+ KEY `d2` (`d`),
+ KEY `d` (`d`),
+ KEY `b` (`b`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+drop table t1;
+create table t1(a int not null, b int, c char(10), d varchar(20), primary key (a)) engine = innodb;
+insert into t1 values (1,1,'ab','ab'),(2,2,'ac','ac'),(3,3,'ad','ad'),(4,4,'afe','afe');
+commit;
+alter table t1 add index (c(2));
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) NOT NULL,
+ `b` int(11) DEFAULT NULL,
+ `c` char(10) DEFAULT NULL,
+ `d` varchar(20) DEFAULT NULL,
+ PRIMARY KEY (`a`),
+ KEY `c` (`c`(2))
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+alter table t1 add unique index (d(10));
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) NOT NULL,
+ `b` int(11) DEFAULT NULL,
+ `c` char(10) DEFAULT NULL,
+ `d` varchar(20) DEFAULT NULL,
+ PRIMARY KEY (`a`),
+ UNIQUE KEY `d` (`d`(10)),
+ KEY `c` (`c`(2))
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+insert into t1 values(5,1,'ggg','ggg');
+select * from t1;
+a b c d
+1 1 ab ab
+2 2 ac ac
+3 3 ad ad
+4 4 afe afe
+5 1 ggg ggg
+select * from t1 force index(c) order by c;
+a b c d
+1 1 ab ab
+2 2 ac ac
+3 3 ad ad
+4 4 afe afe
+5 1 ggg ggg
+select * from t1 force index(d) order by d;
+a b c d
+1 1 ab ab
+2 2 ac ac
+3 3 ad ad
+4 4 afe afe
+5 1 ggg ggg
+explain select * from t1 order by b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 5 Using filesort
+explain select * from t1 force index(c) order by c;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 5 Using filesort
+explain select * from t1 force index(d) order by d;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 5 Using filesort
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) NOT NULL,
+ `b` int(11) DEFAULT NULL,
+ `c` char(10) DEFAULT NULL,
+ `d` varchar(20) DEFAULT NULL,
+ PRIMARY KEY (`a`),
+ UNIQUE KEY `d` (`d`(10)),
+ KEY `c` (`c`(2))
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+alter table t1 drop index d;
+insert into t1 values(8,9,'fff','fff');
+select * from t1;
+a b c d
+1 1 ab ab
+2 2 ac ac
+3 3 ad ad
+4 4 afe afe
+5 1 ggg ggg
+8 9 fff fff
+select * from t1 force index(c) order by c;
+a b c d
+1 1 ab ab
+2 2 ac ac
+3 3 ad ad
+4 4 afe afe
+8 9 fff fff
+5 1 ggg ggg
+explain select * from t1 order by b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 6 Using filesort
+explain select * from t1 force index(c) order by c;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 6 Using filesort
+explain select * from t1 order by d;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 6 Using filesort
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) NOT NULL,
+ `b` int(11) DEFAULT NULL,
+ `c` char(10) DEFAULT NULL,
+ `d` varchar(20) DEFAULT NULL,
+ PRIMARY KEY (`a`),
+ KEY `c` (`c`(2))
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+drop table t1;
+create table t1(a int not null, b int, c char(10), d varchar(20), primary key (a)) engine = innodb;
+insert into t1 values (1,1,'ab','ab'),(2,2,'ac','ac'),(3,2,'ad','ad'),(4,4,'afe','afe');
+commit;
+alter table t1 add unique index (b,c);
+insert into t1 values(8,9,'fff','fff');
+select * from t1;
+a b c d
+1 1 ab ab
+2 2 ac ac
+3 2 ad ad
+4 4 afe afe
+8 9 fff fff
+select * from t1 force index(b) order by b;
+a b c d
+1 1 ab ab
+2 2 ac ac
+3 2 ad ad
+4 4 afe afe
+8 9 fff fff
+explain select * from t1 force index(b) order by b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index NULL b 16 NULL 5
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) NOT NULL,
+ `b` int(11) DEFAULT NULL,
+ `c` char(10) DEFAULT NULL,
+ `d` varchar(20) DEFAULT NULL,
+ PRIMARY KEY (`a`),
+ UNIQUE KEY `b` (`b`,`c`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+alter table t1 add index (b,c);
+insert into t1 values(11,11,'kkk','kkk');
+select * from t1;
+a b c d
+1 1 ab ab
+2 2 ac ac
+3 2 ad ad
+4 4 afe afe
+8 9 fff fff
+11 11 kkk kkk
+select * from t1 force index(b) order by b;
+a b c d
+1 1 ab ab
+2 2 ac ac
+3 2 ad ad
+4 4 afe afe
+8 9 fff fff
+11 11 kkk kkk
+explain select * from t1 force index(b) order by b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index NULL b 16 NULL 6
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) NOT NULL,
+ `b` int(11) DEFAULT NULL,
+ `c` char(10) DEFAULT NULL,
+ `d` varchar(20) DEFAULT NULL,
+ PRIMARY KEY (`a`),
+ UNIQUE KEY `b` (`b`,`c`),
+ KEY `b_2` (`b`,`c`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+alter table t1 add unique index (c,d);
+insert into t1 values(13,13,'yyy','aaa');
+select * from t1;
+a b c d
+1 1 ab ab
+2 2 ac ac
+3 2 ad ad
+4 4 afe afe
+8 9 fff fff
+11 11 kkk kkk
+13 13 yyy aaa
+select * from t1 force index(b) order by b;
+a b c d
+1 1 ab ab
+2 2 ac ac
+3 2 ad ad
+4 4 afe afe
+8 9 fff fff
+11 11 kkk kkk
+13 13 yyy aaa
+select * from t1 force index(c) order by c;
+a b c d
+1 1 ab ab
+2 2 ac ac
+3 2 ad ad
+4 4 afe afe
+8 9 fff fff
+11 11 kkk kkk
+13 13 yyy aaa
+explain select * from t1 force index(b) order by b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index NULL b 16 NULL 7
+explain select * from t1 force index(c) order by c;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index NULL c 34 NULL 7
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) NOT NULL,
+ `b` int(11) DEFAULT NULL,
+ `c` char(10) DEFAULT NULL,
+ `d` varchar(20) DEFAULT NULL,
+ PRIMARY KEY (`a`),
+ UNIQUE KEY `b` (`b`,`c`),
+ UNIQUE KEY `c` (`c`,`d`),
+ KEY `b_2` (`b`,`c`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+drop table t1;
+create table t1(a int not null, b int not null, c int, primary key (a), key (b)) engine = innodb;
+create table t3(a int not null, c int not null, d int, primary key (a), key (c)) engine = innodb;
+create table t4(a int not null, d int not null, e int, primary key (a), key (d)) engine = innodb;
+create table t2(a int not null, b int not null, c int not null, d int not null, e int,
+foreign key (b) references t1(b) on delete cascade,
+foreign key (c) references t3(c), foreign key (d) references t4(d))
+engine = innodb;
+alter table t1 drop index b;
+ERROR HY000: Cannot drop index 'b': needed in a foreign key constraint
+alter table t3 drop index c;
+ERROR HY000: Cannot drop index 'c': needed in a foreign key constraint
+alter table t4 drop index d;
+ERROR HY000: Cannot drop index 'd': needed in a foreign key constraint
+alter table t2 drop index b;
+ERROR HY000: Cannot drop index 'b': needed in a foreign key constraint
+alter table t2 drop index b, drop index c, drop index d;
+ERROR HY000: Cannot drop index 'b': needed in a foreign key constraint
+create unique index dc on t2 (d,c);
+create index dc on t1 (b,c);
+alter table t2 add primary key (a);
+insert into t1 values (1,1,1);
+insert into t3 values (1,1,1);
+insert into t4 values (1,1,1);
+insert into t2 values (1,1,1,1,1);
+commit;
+alter table t4 add constraint dc foreign key (a) references t1(a);
+show create table t4;
+Table Create Table
+t4 CREATE TABLE `t4` (
+ `a` int(11) NOT NULL,
+ `d` int(11) NOT NULL,
+ `e` int(11) DEFAULT NULL,
+ PRIMARY KEY (`a`),
+ KEY `d` (`d`),
+ CONSTRAINT `dc` FOREIGN KEY (`a`) REFERENCES `t1` (`a`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+alter table t3 add constraint dc foreign key (a) references t1(a);
+ERROR HY000: Can't create table '#sql-temporary' (errno: 121)
+show create table t3;
+Table Create Table
+t3 CREATE TABLE `t3` (
+ `a` int(11) NOT NULL,
+ `c` int(11) NOT NULL,
+ `d` int(11) DEFAULT NULL,
+ PRIMARY KEY (`a`),
+ KEY `c` (`c`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+alter table t2 drop index b, add index (b);
+show create table t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `a` int(11) NOT NULL,
+ `b` int(11) NOT NULL,
+ `c` int(11) NOT NULL,
+ `d` int(11) NOT NULL,
+ `e` int(11) DEFAULT NULL,
+ PRIMARY KEY (`a`),
+ UNIQUE KEY `dc` (`d`,`c`),
+ KEY `c` (`c`),
+ KEY `b` (`b`),
+ CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`b`) REFERENCES `t1` (`b`) ON DELETE CASCADE,
+ CONSTRAINT `t2_ibfk_2` FOREIGN KEY (`c`) REFERENCES `t3` (`c`),
+ CONSTRAINT `t2_ibfk_3` FOREIGN KEY (`d`) REFERENCES `t4` (`d`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+delete from t1;
+ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`t4`, CONSTRAINT `dc` FOREIGN KEY (`a`) REFERENCES `t1` (`a`))
+drop index dc on t4;
+ERROR 42000: Can't DROP 'dc'; check that column/key exists
+alter table t3 drop foreign key dc;
+ERROR HY000: Error on rename of './test/t3' to '#sql2-temporary' (errno: 152)
+alter table t4 drop foreign key dc;
+select * from t2;
+a b c d e
+1 1 1 1 1
+delete from t1;
+select * from t2;
+a b c d e
+drop table t2,t4,t3,t1;
+create table t1(a int not null, b int, c char(10), d varchar(20), primary key (a)) engine = innodb default charset=utf8;
+insert into t1 values (1,1,'ab','ab'),(2,2,'ac','ac'),(3,2,'ad','ad'),(4,4,'afe','afe');
+commit;
+alter table t1 add unique index (b);
+ERROR 23000: Duplicate entry '2' for key 'b'
+insert into t1 values(8,9,'fff','fff');
+select * from t1;
+a b c d
+1 1 ab ab
+2 2 ac ac
+3 2 ad ad
+4 4 afe afe
+8 9 fff fff
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) NOT NULL,
+ `b` int(11) DEFAULT NULL,
+ `c` char(10) DEFAULT NULL,
+ `d` varchar(20) DEFAULT NULL,
+ PRIMARY KEY (`a`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8
+alter table t1 add index (b);
+insert into t1 values(10,10,'kkk','iii');
+select * from t1;
+a b c d
+1 1 ab ab
+2 2 ac ac
+3 2 ad ad
+4 4 afe afe
+8 9 fff fff
+10 10 kkk iii
+select * from t1 force index(b) order by b;
+a b c d
+1 1 ab ab
+2 2 ac ac
+3 2 ad ad
+4 4 afe afe
+8 9 fff fff
+10 10 kkk iii
+explain select * from t1 force index(b) order by b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index NULL b 5 NULL 6
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) NOT NULL,
+ `b` int(11) DEFAULT NULL,
+ `c` char(10) DEFAULT NULL,
+ `d` varchar(20) DEFAULT NULL,
+ PRIMARY KEY (`a`),
+ KEY `b` (`b`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8
+alter table t1 add unique index (c), add index (d);
+insert into t1 values(11,11,'aaa','mmm');
+select * from t1;
+a b c d
+1 1 ab ab
+2 2 ac ac
+3 2 ad ad
+4 4 afe afe
+8 9 fff fff
+10 10 kkk iii
+11 11 aaa mmm
+select * from t1 force index(b) order by b;
+a b c d
+1 1 ab ab
+2 2 ac ac
+3 2 ad ad
+4 4 afe afe
+8 9 fff fff
+10 10 kkk iii
+11 11 aaa mmm
+select * from t1 force index(c) order by c;
+a b c d
+11 11 aaa mmm
+1 1 ab ab
+2 2 ac ac
+3 2 ad ad
+4 4 afe afe
+8 9 fff fff
+10 10 kkk iii
+select * from t1 force index(d) order by d;
+a b c d
+1 1 ab ab
+2 2 ac ac
+3 2 ad ad
+4 4 afe afe
+8 9 fff fff
+10 10 kkk iii
+11 11 aaa mmm
+explain select * from t1 force index(b) order by b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index NULL b 5 NULL 7
+explain select * from t1 force index(c) order by c;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index NULL c 31 NULL 7
+explain select * from t1 force index(d) order by d;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index NULL d 63 NULL 7
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) NOT NULL,
+ `b` int(11) DEFAULT NULL,
+ `c` char(10) DEFAULT NULL,
+ `d` varchar(20) DEFAULT NULL,
+ PRIMARY KEY (`a`),
+ UNIQUE KEY `c` (`c`),
+ KEY `b` (`b`),
+ KEY `d` (`d`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8
+check table t1;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+drop table t1;
+create table t1(a int not null, b int) engine = innodb;
+insert into t1 values (1,1),(1,1),(1,1),(1,1);
+alter table t1 add unique index (a);
+ERROR 23000: Duplicate entry '1' for key 'a'
+alter table t1 add unique index (b);
+ERROR 23000: Duplicate entry '1' for key 'b'
+alter table t1 add unique index (a), add unique index(b);
+ERROR 23000: Duplicate entry '1' for key 'a'
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) NOT NULL,
+ `b` int(11) DEFAULT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+drop table t1;
+create table t1(a int not null, c int not null,b int, primary key(a), unique key(c), key(b)) engine = innodb;
+alter table t1 drop index c, drop index b;
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) NOT NULL,
+ `c` int(11) NOT NULL,
+ `b` int(11) DEFAULT NULL,
+ PRIMARY KEY (`a`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+drop table t1;
+create table t1(a int not null, b int, primary key(a)) engine = innodb;
+alter table t1 add index (b);
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) NOT NULL,
+ `b` int(11) DEFAULT NULL,
+ PRIMARY KEY (`a`),
+ KEY `b` (`b`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+drop table t1;
+create table t1(a int not null, b int, c char(10), d varchar(20), primary key (a)) engine = innodb;
+insert into t1 values (1,1,'ab','ab'),(2,2,'ac','ac'),(3,3,'ac','ac'),(4,4,'afe','afe'),(5,4,'affe','affe');
+alter table t1 add unique index (b), add unique index (c), add unique index (d);
+ERROR 23000: Duplicate entry '4' for key 'b'
+alter table t1 add unique index (c), add unique index (b), add index (d);
+ERROR 23000: Duplicate entry 'ac' for key 'c'
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) NOT NULL,
+ `b` int(11) DEFAULT NULL,
+ `c` char(10) DEFAULT NULL,
+ `d` varchar(20) DEFAULT NULL,
+ PRIMARY KEY (`a`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+drop table t1;
+create table t1(a int not null, b int not null, c int, primary key (a), key(c)) engine=innodb;
+insert into t1 values (5,1,5),(4,2,4),(3,3,3),(2,4,2),(1,5,1);
+alter table t1 add unique index (b);
+insert into t1 values (10,20,20),(11,19,19),(12,18,18),(13,17,17);
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) NOT NULL,
+ `b` int(11) NOT NULL,
+ `c` int(11) DEFAULT NULL,
+ PRIMARY KEY (`a`),
+ UNIQUE KEY `b` (`b`),
+ KEY `c` (`c`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+check table t1;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+explain select * from t1 force index(c) order by c;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index NULL c 5 NULL 9
+explain select * from t1 order by a;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index NULL PRIMARY 4 NULL 9
+explain select * from t1 force index(b) order by b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index NULL b 4 NULL 9
+select * from t1 order by a;
+a b c
+1 5 1
+2 4 2
+3 3 3
+4 2 4
+5 1 5
+10 20 20
+11 19 19
+12 18 18
+13 17 17
+select * from t1 force index(b) order by b;
+a b c
+5 1 5
+4 2 4
+3 3 3
+2 4 2
+1 5 1
+13 17 17
+12 18 18
+11 19 19
+10 20 20
+select * from t1 force index(c) order by c;
+a b c
+1 5 1
+2 4 2
+3 3 3
+4 2 4
+5 1 5
+13 17 17
+12 18 18
+11 19 19
+10 20 20
+drop table t1;
+create table t1(a int not null, b int not null) engine=innodb;
+insert into t1 values (1,1);
+alter table t1 add primary key(b);
+insert into t1 values (2,2);
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) NOT NULL,
+ `b` int(11) NOT NULL,
+ PRIMARY KEY (`b`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+check table t1;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+select * from t1;
+a b
+1 1
+2 2
+explain select * from t1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 2
+explain select * from t1 order by a;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL NULL NULL NULL NULL 2 Using filesort
+explain select * from t1 order by b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index NULL PRIMARY 4 NULL 2
+checksum table t1;
+Table Checksum
+test.t1 582702641
+drop table t1;
+create table t1(a int not null) engine=innodb;
+insert into t1 values (1);
+alter table t1 add primary key(a);
+insert into t1 values (2);
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) NOT NULL,
+ PRIMARY KEY (`a`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+check table t1;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+commit;
+select * from t1;
+a
+1
+2
+explain select * from t1;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index NULL PRIMARY 4 NULL 2 Using index
+explain select * from t1 order by a;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index NULL PRIMARY 4 NULL 2 Using index
+drop table t1;
+create table t2(d varchar(17) primary key) engine=innodb default charset=utf8;
+create table t3(a int primary key) engine=innodb;
+insert into t3 values(22),(44),(33),(55),(66);
+insert into t2 values ('jejdkrun87'),('adfd72nh9k'),
+('adfdpplkeock'),('adfdijnmnb78k'),('adfdijn0loKNHJik');
+create table t1(a int, b blob, c text, d text not null)
+engine=innodb default charset = utf8;
+insert into t1
+select a,left(repeat(d,100*a),65535),repeat(d,20*a),d from t2,t3;
+drop table t2, t3;
+select count(*) from t1 where a=44;
+count(*)
+5
+select a,
+length(b),b=left(repeat(d,100*a),65535),length(c),c=repeat(d,20*a),d from t1;
+a length(b) b=left(repeat(d,100*a),65535) length(c) c=repeat(d,20*a) d
+22 22000 1 4400 1 adfd72nh9k
+22 35200 1 7040 1 adfdijn0loKNHJik
+22 28600 1 5720 1 adfdijnmnb78k
+22 26400 1 5280 1 adfdpplkeock
+22 22000 1 4400 1 jejdkrun87
+33 33000 1 6600 1 adfd72nh9k
+33 52800 1 10560 1 adfdijn0loKNHJik
+33 42900 1 8580 1 adfdijnmnb78k
+33 39600 1 7920 1 adfdpplkeock
+33 33000 1 6600 1 jejdkrun87
+44 44000 1 8800 1 adfd72nh9k
+44 65535 1 14080 1 adfdijn0loKNHJik
+44 57200 1 11440 1 adfdijnmnb78k
+44 52800 1 10560 1 adfdpplkeock
+44 44000 1 8800 1 jejdkrun87
+55 55000 1 11000 1 adfd72nh9k
+55 65535 1 17600 1 adfdijn0loKNHJik
+55 65535 1 14300 1 adfdijnmnb78k
+55 65535 1 13200 1 adfdpplkeock
+55 55000 1 11000 1 jejdkrun87
+66 65535 1 13200 1 adfd72nh9k
+66 65535 1 21120 1 adfdijn0loKNHJik
+66 65535 1 17160 1 adfdijnmnb78k
+66 65535 1 15840 1 adfdpplkeock
+66 65535 1 13200 1 jejdkrun87
+alter table t1 add primary key (a), add key (b(20));
+ERROR 23000: Duplicate entry '22' for key 'PRIMARY'
+delete from t1 where a%2;
+check table t1;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+alter table t1 add primary key (a,b(255),c(255)), add key (b(767));
+select count(*) from t1 where a=44;
+count(*)
+5
+select a,
+length(b),b=left(repeat(d,100*a),65535),length(c),c=repeat(d,20*a),d from t1;
+a length(b) b=left(repeat(d,100*a),65535) length(c) c=repeat(d,20*a) d
+22 22000 1 4400 1 adfd72nh9k
+22 35200 1 7040 1 adfdijn0loKNHJik
+22 28600 1 5720 1 adfdijnmnb78k
+22 26400 1 5280 1 adfdpplkeock
+22 22000 1 4400 1 jejdkrun87
+44 44000 1 8800 1 adfd72nh9k
+44 65535 1 14080 1 adfdijn0loKNHJik
+44 57200 1 11440 1 adfdijnmnb78k
+44 52800 1 10560 1 adfdpplkeock
+44 44000 1 8800 1 jejdkrun87
+66 65535 1 13200 1 adfd72nh9k
+66 65535 1 21120 1 adfdijn0loKNHJik
+66 65535 1 17160 1 adfdijnmnb78k
+66 65535 1 15840 1 adfdpplkeock
+66 65535 1 13200 1 jejdkrun87
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) NOT NULL DEFAULT '0',
+ `b` blob NOT NULL,
+ `c` text NOT NULL,
+ `d` text NOT NULL,
+ PRIMARY KEY (`a`,`b`(255),`c`(255)),
+ KEY `b` (`b`(767))
+) ENGINE=InnoDB DEFAULT CHARSET=utf8
+check table t1;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+explain select * from t1 where b like 'adfd%';
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL b NULL NULL NULL 15 Using where
+create table t2(a int, b varchar(255), primary key(a,b)) engine=innodb;
+insert into t2 select a,left(b,255) from t1;
+drop table t1;
+rename table t2 to t1;
+set innodb_lock_wait_timeout=1;
+begin;
+select a from t1 limit 1 for update;
+a
+22
+set innodb_lock_wait_timeout=1;
+create index t1ba on t1 (b,a);
+ERROR HY000: Lock wait timeout exceeded; try restarting transaction
+commit;
+begin;
+select a from t1 limit 1 lock in share mode;
+a
+22
+create index t1ba on t1 (b,a);
+drop index t1ba on t1;
+ERROR HY000: Lock wait timeout exceeded; try restarting transaction
+commit;
+explain select a from t1 order by b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index NULL t1ba 261 NULL 15 Using index
+select a,sleep(2+a/100) from t1 order by b limit 3;
+select sleep(1);
+sleep(1)
+0
+drop index t1ba on t1;
+a sleep(2+a/100)
+22 0
+44 0
+66 0
+explain select a from t1 order by b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index NULL PRIMARY 261 NULL 15 Using index; Using filesort
+select a from t1 order by b limit 3;
+a
+22
+66
+44
+commit;
+drop table t1;
+set global innodb_file_per_table=on;
+set global innodb_file_format='Barracuda';
+create table t1(a blob,b blob,c blob,d blob,e blob,f blob,g blob,h blob,
+i blob,j blob,k blob,l blob,m blob,n blob,o blob,p blob,
+q blob,r blob,s blob,t blob,u blob)
+engine=innodb row_format=dynamic;
+create index t1a on t1 (a(1));
+create index t1b on t1 (b(1));
+create index t1c on t1 (c(1));
+create index t1d on t1 (d(1));
+create index t1e on t1 (e(1));
+create index t1f on t1 (f(1));
+create index t1g on t1 (g(1));
+create index t1h on t1 (h(1));
+create index t1i on t1 (i(1));
+create index t1j on t1 (j(1));
+create index t1k on t1 (k(1));
+create index t1l on t1 (l(1));
+create index t1m on t1 (m(1));
+create index t1n on t1 (n(1));
+create index t1o on t1 (o(1));
+create index t1p on t1 (p(1));
+create index t1q on t1 (q(1));
+create index t1r on t1 (r(1));
+create index t1s on t1 (s(1));
+create index t1t on t1 (t(1));
+create index t1u on t1 (u(1));
+ERROR HY000: Too big row
+create index t1ut on t1 (u(1), t(1));
+ERROR HY000: Too big row
+create index t1st on t1 (s(1), t(1));
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` blob,
+ `b` blob,
+ `c` blob,
+ `d` blob,
+ `e` blob,
+ `f` blob,
+ `g` blob,
+ `h` blob,
+ `i` blob,
+ `j` blob,
+ `k` blob,
+ `l` blob,
+ `m` blob,
+ `n` blob,
+ `o` blob,
+ `p` blob,
+ `q` blob,
+ `r` blob,
+ `s` blob,
+ `t` blob,
+ `u` blob,
+ KEY `t1a` (`a`(1)),
+ KEY `t1b` (`b`(1)),
+ KEY `t1c` (`c`(1)),
+ KEY `t1d` (`d`(1)),
+ KEY `t1e` (`e`(1)),
+ KEY `t1f` (`f`(1)),
+ KEY `t1g` (`g`(1)),
+ KEY `t1h` (`h`(1)),
+ KEY `t1i` (`i`(1)),
+ KEY `t1j` (`j`(1)),
+ KEY `t1k` (`k`(1)),
+ KEY `t1l` (`l`(1)),
+ KEY `t1m` (`m`(1)),
+ KEY `t1n` (`n`(1)),
+ KEY `t1o` (`o`(1)),
+ KEY `t1p` (`p`(1)),
+ KEY `t1q` (`q`(1)),
+ KEY `t1r` (`r`(1)),
+ KEY `t1s` (`s`(1)),
+ KEY `t1t` (`t`(1)),
+ KEY `t1st` (`s`(1),`t`(1))
+) ENGINE=InnoDB DEFAULT CHARSET=latin1 ROW_FORMAT=DYNAMIC
+create index t1u on t1 (u(1));
+ERROR HY000: Too big row
+alter table t1 row_format=compact;
+create index t1u on t1 (u(1));
+drop table t1;
+set global innodb_file_per_table=0;
+set global innodb_file_format=Antelope;
+SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0;
+SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0;
+CREATE TABLE t1(
+c1 BIGINT(12) NOT NULL,
+PRIMARY KEY (c1)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1;
+CREATE TABLE t2(
+c1 BIGINT(16) NOT NULL,
+c2 BIGINT(12) NOT NULL,
+c3 BIGINT(12) NOT NULL,
+PRIMARY KEY (c1)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1;
+ALTER TABLE t2 ADD CONSTRAINT fk_t2_ca
+FOREIGN KEY (c3) REFERENCES t1(c1);
+SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS;
+SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS;
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `c1` bigint(16) NOT NULL,
+ `c2` bigint(12) NOT NULL,
+ `c3` bigint(12) NOT NULL,
+ PRIMARY KEY (`c1`),
+ KEY `fk_t2_ca` (`c3`),
+ CONSTRAINT `fk_t2_ca` FOREIGN KEY (`c3`) REFERENCES `t1` (`c1`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+CREATE INDEX i_t2_c3_c2 ON t2(c3, c2);
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `c1` bigint(16) NOT NULL,
+ `c2` bigint(12) NOT NULL,
+ `c3` bigint(12) NOT NULL,
+ PRIMARY KEY (`c1`),
+ KEY `i_t2_c3_c2` (`c3`,`c2`),
+ CONSTRAINT `fk_t2_ca` FOREIGN KEY (`c3`) REFERENCES `t1` (`c1`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS;
+SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS;
+INSERT INTO t2 VALUES(0,0,0);
+ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `fk_t2_ca` FOREIGN KEY (`c3`) REFERENCES `t1` (`c1`))
+INSERT INTO t1 VALUES(0);
+INSERT INTO t2 VALUES(0,0,0);
+DROP TABLE t2;
+CREATE TABLE t2(
+c1 BIGINT(16) NOT NULL,
+c2 BIGINT(12) NOT NULL,
+c3 BIGINT(12) NOT NULL,
+PRIMARY KEY (c1,c2,c3)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1;
+ALTER TABLE t2 ADD CONSTRAINT fk_t2_ca
+FOREIGN KEY (c3) REFERENCES t1(c1);
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `c1` bigint(16) NOT NULL,
+ `c2` bigint(12) NOT NULL,
+ `c3` bigint(12) NOT NULL,
+ PRIMARY KEY (`c1`,`c2`,`c3`),
+ KEY `fk_t2_ca` (`c3`),
+ CONSTRAINT `fk_t2_ca` FOREIGN KEY (`c3`) REFERENCES `t1` (`c1`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+CREATE INDEX i_t2_c3_c2 ON t2(c3, c2);
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `c1` bigint(16) NOT NULL,
+ `c2` bigint(12) NOT NULL,
+ `c3` bigint(12) NOT NULL,
+ PRIMARY KEY (`c1`,`c2`,`c3`),
+ KEY `i_t2_c3_c2` (`c3`,`c2`),
+ CONSTRAINT `fk_t2_ca` FOREIGN KEY (`c3`) REFERENCES `t1` (`c1`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+INSERT INTO t2 VALUES(0,0,1);
+ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `fk_t2_ca` FOREIGN KEY (`c3`) REFERENCES `t1` (`c1`))
+INSERT INTO t2 VALUES(0,0,0);
+DELETE FROM t1;
+ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `fk_t2_ca` FOREIGN KEY (`c3`) REFERENCES `t1` (`c1`))
+DELETE FROM t2;
+DROP TABLE t2;
+DROP TABLE t1;
+CREATE TABLE t1(
+c1 BIGINT(12) NOT NULL,
+c2 INT(4) NOT NULL,
+PRIMARY KEY (c2,c1)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1;
+CREATE TABLE t2(
+c1 BIGINT(16) NOT NULL,
+c2 BIGINT(12) NOT NULL,
+c3 BIGINT(12) NOT NULL,
+PRIMARY KEY (c1)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1;
+ALTER TABLE t2 ADD CONSTRAINT fk_t2_ca
+FOREIGN KEY (c3,c2) REFERENCES t1(c1,c1);
+ERROR HY000: Can't create table '#sql-temporary' (errno: 150)
+ALTER TABLE t2 ADD CONSTRAINT fk_t2_ca
+FOREIGN KEY (c3,c2) REFERENCES t1(c1,c2);
+ERROR HY000: Can't create table '#sql-temporary' (errno: 150)
+ALTER TABLE t2 ADD CONSTRAINT fk_t2_ca
+FOREIGN KEY (c3,c2) REFERENCES t1(c2,c1);
+ERROR HY000: Can't create table '#sql-temporary' (errno: 150)
+ALTER TABLE t1 MODIFY COLUMN c2 BIGINT(12) NOT NULL;
+ALTER TABLE t2 ADD CONSTRAINT fk_t2_ca
+FOREIGN KEY (c3,c2) REFERENCES t1(c1,c2);
+ERROR HY000: Can't create table '#sql-temporary' (errno: 150)
+ALTER TABLE t2 ADD CONSTRAINT fk_t2_ca
+FOREIGN KEY (c3,c2) REFERENCES t1(c2,c1);
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `c1` bigint(12) NOT NULL,
+ `c2` bigint(12) NOT NULL,
+ PRIMARY KEY (`c2`,`c1`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `c1` bigint(16) NOT NULL,
+ `c2` bigint(12) NOT NULL,
+ `c3` bigint(12) NOT NULL,
+ PRIMARY KEY (`c1`),
+ KEY `fk_t2_ca` (`c3`,`c2`),
+ CONSTRAINT `fk_t2_ca` FOREIGN KEY (`c3`, `c2`) REFERENCES `t1` (`c2`, `c1`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+CREATE INDEX i_t2_c2_c1 ON t2(c2, c1);
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `c1` bigint(16) NOT NULL,
+ `c2` bigint(12) NOT NULL,
+ `c3` bigint(12) NOT NULL,
+ PRIMARY KEY (`c1`),
+ KEY `fk_t2_ca` (`c3`,`c2`),
+ KEY `i_t2_c2_c1` (`c2`,`c1`),
+ CONSTRAINT `fk_t2_ca` FOREIGN KEY (`c3`, `c2`) REFERENCES `t1` (`c2`, `c1`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+CREATE INDEX i_t2_c3_c1_c2 ON t2(c3, c1, c2);
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `c1` bigint(16) NOT NULL,
+ `c2` bigint(12) NOT NULL,
+ `c3` bigint(12) NOT NULL,
+ PRIMARY KEY (`c1`),
+ KEY `fk_t2_ca` (`c3`,`c2`),
+ KEY `i_t2_c2_c1` (`c2`,`c1`),
+ KEY `i_t2_c3_c1_c2` (`c3`,`c1`,`c2`),
+ CONSTRAINT `fk_t2_ca` FOREIGN KEY (`c3`, `c2`) REFERENCES `t1` (`c2`, `c1`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+CREATE INDEX i_t2_c3_c2 ON t2(c3, c2);
+SHOW CREATE TABLE t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `c1` bigint(16) NOT NULL,
+ `c2` bigint(12) NOT NULL,
+ `c3` bigint(12) NOT NULL,
+ PRIMARY KEY (`c1`),
+ KEY `i_t2_c2_c1` (`c2`,`c1`),
+ KEY `i_t2_c3_c1_c2` (`c3`,`c1`,`c2`),
+ KEY `i_t2_c3_c2` (`c3`,`c2`),
+ CONSTRAINT `fk_t2_ca` FOREIGN KEY (`c3`, `c2`) REFERENCES `t1` (`c2`, `c1`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+DROP TABLE t2;
+DROP TABLE t1;
+CREATE TABLE t1 (a INT, b CHAR(1)) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (3,'a'),(3,'b'),(1,'c'),(0,'d'),(1,'e');
+BEGIN;
+SELECT * FROM t1;
+a b
+3 a
+3 b
+1 c
+0 d
+1 e
+CREATE INDEX t1a ON t1(a);
+SELECT * FROM t1;
+a b
+3 a
+3 b
+1 c
+0 d
+1 e
+SELECT * FROM t1 FORCE INDEX(t1a) ORDER BY a;
+ERROR HY000: Table definition has changed, please retry transaction
+SELECT * FROM t1;
+a b
+3 a
+3 b
+1 c
+0 d
+1 e
+COMMIT;
+SELECT * FROM t1 FORCE INDEX(t1a) ORDER BY a;
+a b
+0 d
+1 c
+1 e
+3 a
+3 b
+DROP TABLE t1;
diff --git a/mysql-test/suite/innodb/r/innodb-index_ucs2.result b/mysql-test/suite/innodb/r/innodb-index_ucs2.result
new file mode 100644
index 00000000000..c8a1e8c7da1
--- /dev/null
+++ b/mysql-test/suite/innodb/r/innodb-index_ucs2.result
@@ -0,0 +1,116 @@
+create table t1(a int not null, b int, c char(10), d varchar(20), primary key (a)) engine = innodb default charset=ucs2;
+insert into t1 values (1,1,'ab','ab'),(2,2,'ac','ac'),(3,2,'ad','ad'),(4,4,'afe','afe');
+commit;
+alter table t1 add unique index (b);
+ERROR 23000: Duplicate entry '2' for key 'b'
+insert into t1 values(8,9,'fff','fff');
+select * from t1;
+a b c d
+1 1 ab ab
+2 2 ac ac
+3 2 ad ad
+4 4 afe afe
+8 9 fff fff
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) NOT NULL,
+ `b` int(11) DEFAULT NULL,
+ `c` char(10) DEFAULT NULL,
+ `d` varchar(20) DEFAULT NULL,
+ PRIMARY KEY (`a`)
+) ENGINE=InnoDB DEFAULT CHARSET=ucs2
+alter table t1 add index (b);
+insert into t1 values(10,10,'kkk','iii');
+select * from t1;
+a b c d
+1 1 ab ab
+2 2 ac ac
+3 2 ad ad
+4 4 afe afe
+8 9 fff fff
+10 10 kkk iii
+select * from t1 force index(b) order by b;
+a b c d
+1 1 ab ab
+2 2 ac ac
+3 2 ad ad
+4 4 afe afe
+8 9 fff fff
+10 10 kkk iii
+explain select * from t1 force index(b) order by b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index NULL b 5 NULL 6
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) NOT NULL,
+ `b` int(11) DEFAULT NULL,
+ `c` char(10) DEFAULT NULL,
+ `d` varchar(20) DEFAULT NULL,
+ PRIMARY KEY (`a`),
+ KEY `b` (`b`)
+) ENGINE=InnoDB DEFAULT CHARSET=ucs2
+alter table t1 add unique index (c), add index (d);
+insert into t1 values(11,11,'aaa','mmm');
+select * from t1;
+a b c d
+1 1 ab ab
+2 2 ac ac
+3 2 ad ad
+4 4 afe afe
+8 9 fff fff
+10 10 kkk iii
+11 11 aaa mmm
+select * from t1 force index(b) order by b;
+a b c d
+1 1 ab ab
+2 2 ac ac
+3 2 ad ad
+4 4 afe afe
+8 9 fff fff
+10 10 kkk iii
+11 11 aaa mmm
+select * from t1 force index(c) order by c;
+a b c d
+11 11 aaa mmm
+1 1 ab ab
+2 2 ac ac
+3 2 ad ad
+4 4 afe afe
+8 9 fff fff
+10 10 kkk iii
+select * from t1 force index(d) order by d;
+a b c d
+1 1 ab ab
+2 2 ac ac
+3 2 ad ad
+4 4 afe afe
+8 9 fff fff
+10 10 kkk iii
+11 11 aaa mmm
+explain select * from t1 force index(b) order by b;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index NULL b 5 NULL 7
+explain select * from t1 force index(c) order by c;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index NULL c 21 NULL 7
+explain select * from t1 force index(d) order by d;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index NULL d 43 NULL 7
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) NOT NULL,
+ `b` int(11) DEFAULT NULL,
+ `c` char(10) DEFAULT NULL,
+ `d` varchar(20) DEFAULT NULL,
+ PRIMARY KEY (`a`),
+ UNIQUE KEY `c` (`c`),
+ KEY `b` (`b`),
+ KEY `d` (`d`)
+) ENGINE=InnoDB DEFAULT CHARSET=ucs2
+check table t1;
+Table Op Msg_type Msg_text
+test.t1 check status OK
+drop table t1;
diff --git a/mysql-test/suite/innodb/r/innodb-timeout.result b/mysql-test/suite/innodb/r/innodb-timeout.result
new file mode 100644
index 00000000000..be9a688cd72
--- /dev/null
+++ b/mysql-test/suite/innodb/r/innodb-timeout.result
@@ -0,0 +1,38 @@
+set global innodb_lock_wait_timeout=42;
+select @@innodb_lock_wait_timeout;
+@@innodb_lock_wait_timeout
+42
+set innodb_lock_wait_timeout=1;
+select @@innodb_lock_wait_timeout;
+@@innodb_lock_wait_timeout
+1
+select @@innodb_lock_wait_timeout;
+@@innodb_lock_wait_timeout
+42
+set global innodb_lock_wait_timeout=347;
+select @@innodb_lock_wait_timeout;
+@@innodb_lock_wait_timeout
+42
+set innodb_lock_wait_timeout=1;
+select @@innodb_lock_wait_timeout;
+@@innodb_lock_wait_timeout
+1
+select @@innodb_lock_wait_timeout;
+@@innodb_lock_wait_timeout
+347
+create table t1(a int primary key)engine=innodb;
+begin;
+insert into t1 values(1),(2),(3);
+select * from t1 for update;
+commit;
+a
+1
+2
+3
+begin;
+insert into t1 values(4);
+select * from t1 for update;
+commit;
+ERROR HY000: Lock wait timeout exceeded; try restarting transaction
+drop table t1;
+set global innodb_lock_wait_timeout=50;
diff --git a/mysql-test/suite/innodb/r/innodb-use-sys-malloc.result b/mysql-test/suite/innodb/r/innodb-use-sys-malloc.result
new file mode 100644
index 00000000000..2ec4c7c8130
--- /dev/null
+++ b/mysql-test/suite/innodb/r/innodb-use-sys-malloc.result
@@ -0,0 +1,48 @@
+SELECT @@GLOBAL.innodb_use_sys_malloc;
+@@GLOBAL.innodb_use_sys_malloc
+1
+1 Expected
+SET @@GLOBAL.innodb_use_sys_malloc=0;
+ERROR HY000: Variable 'innodb_use_sys_malloc' is a read only variable
+Expected error 'Read only variable'
+SELECT @@GLOBAL.innodb_use_sys_malloc;
+@@GLOBAL.innodb_use_sys_malloc
+1
+1 Expected
+drop table if exists t1;
+create table t1(a int not null) engine=innodb DEFAULT CHARSET=latin1;
+insert into t1 values (1),(2),(3),(4),(5),(6),(7);
+select * from t1;
+a
+1
+2
+3
+4
+5
+6
+7
+drop table t1;
+SELECT @@GLOBAL.innodb_use_sys_malloc;
+@@GLOBAL.innodb_use_sys_malloc
+1
+1 Expected
+SET @@GLOBAL.innodb_use_sys_malloc=0;
+ERROR HY000: Variable 'innodb_use_sys_malloc' is a read only variable
+Expected error 'Read only variable'
+SELECT @@GLOBAL.innodb_use_sys_malloc;
+@@GLOBAL.innodb_use_sys_malloc
+1
+1 Expected
+drop table if exists t1;
+create table t1(a int not null) engine=innodb DEFAULT CHARSET=latin1;
+insert into t1 values (1),(2),(3),(4),(5),(6),(7);
+select * from t1;
+a
+1
+2
+3
+4
+5
+6
+7
+drop table t1;
diff --git a/mysql-test/suite/innodb/r/innodb-zip.result b/mysql-test/suite/innodb/r/innodb-zip.result
new file mode 100644
index 00000000000..c81401743a5
--- /dev/null
+++ b/mysql-test/suite/innodb/r/innodb-zip.result
@@ -0,0 +1,421 @@
+set global innodb_file_per_table=off;
+set global innodb_file_format=`0`;
+create table t0(a int primary key) engine=innodb row_format=compressed;
+Warnings:
+Warning 1478 InnoDB: ROW_FORMAT=COMPRESSED requires innodb_file_per_table.
+Warning 1478 InnoDB: assuming ROW_FORMAT=COMPACT.
+create table t00(a int primary key) engine=innodb
+key_block_size=4 row_format=compressed;
+Warnings:
+Warning 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_per_table.
+Warning 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_format > Antelope.
+Warning 1478 InnoDB: ignoring KEY_BLOCK_SIZE=4.
+Warning 1478 InnoDB: ROW_FORMAT=COMPRESSED requires innodb_file_per_table.
+Warning 1478 InnoDB: assuming ROW_FORMAT=COMPACT.
+create table t1(a int primary key) engine=innodb row_format=dynamic;
+Warnings:
+Warning 1478 InnoDB: ROW_FORMAT=DYNAMIC requires innodb_file_per_table.
+Warning 1478 InnoDB: assuming ROW_FORMAT=COMPACT.
+create table t2(a int primary key) engine=innodb row_format=redundant;
+create table t3(a int primary key) engine=innodb row_format=compact;
+create table t4(a int primary key) engine=innodb key_block_size=9;
+Warnings:
+Warning 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_per_table.
+Warning 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_format > Antelope.
+Warning 1478 InnoDB: ignoring KEY_BLOCK_SIZE=9.
+create table t5(a int primary key) engine=innodb
+key_block_size=1 row_format=redundant;
+Warnings:
+Warning 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_per_table.
+Warning 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_format > Antelope.
+Warning 1478 InnoDB: ignoring KEY_BLOCK_SIZE=1.
+set global innodb_file_per_table=on;
+create table t6(a int primary key) engine=innodb
+key_block_size=1 row_format=redundant;
+Warnings:
+Warning 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_format > Antelope.
+Warning 1478 InnoDB: ignoring KEY_BLOCK_SIZE=1.
+set global innodb_file_format=`1`;
+create table t7(a int primary key) engine=innodb
+key_block_size=1 row_format=redundant;
+Warnings:
+Warning 1478 InnoDB: ignoring KEY_BLOCK_SIZE=1 unless ROW_FORMAT=COMPRESSED.
+create table t8(a int primary key) engine=innodb
+key_block_size=1 row_format=fixed;
+Warnings:
+Warning 1478 InnoDB: ignoring KEY_BLOCK_SIZE=1 unless ROW_FORMAT=COMPRESSED.
+Warning 1478 InnoDB: assuming ROW_FORMAT=COMPACT.
+create table t9(a int primary key) engine=innodb
+key_block_size=1 row_format=compact;
+Warnings:
+Warning 1478 InnoDB: ignoring KEY_BLOCK_SIZE=1 unless ROW_FORMAT=COMPRESSED.
+create table t10(a int primary key) engine=innodb
+key_block_size=1 row_format=dynamic;
+Warnings:
+Warning 1478 InnoDB: ignoring KEY_BLOCK_SIZE=1 unless ROW_FORMAT=COMPRESSED.
+create table t11(a int primary key) engine=innodb
+key_block_size=1 row_format=compressed;
+create table t12(a int primary key) engine=innodb
+key_block_size=1;
+create table t13(a int primary key) engine=innodb
+row_format=compressed;
+create table t14(a int primary key) engine=innodb key_block_size=9;
+Warnings:
+Warning 1478 InnoDB: ignoring KEY_BLOCK_SIZE=9.
+SELECT table_schema, table_name, row_format
+FROM information_schema.tables WHERE engine='innodb';
+table_schema table_name row_format
+test t0 Compact
+test t00 Compact
+test t1 Compact
+test t10 Dynamic
+test t11 Compressed
+test t12 Compressed
+test t13 Compressed
+test t14 Compact
+test t2 Redundant
+test t3 Compact
+test t4 Compact
+test t5 Redundant
+test t6 Redundant
+test t7 Redundant
+test t8 Compact
+test t9 Compact
+drop table t0,t00,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14;
+alter table t1 key_block_size=0;
+Warnings:
+Warning 1478 InnoDB: ignoring KEY_BLOCK_SIZE=0.
+alter table t1 row_format=dynamic;
+SELECT table_schema, table_name, row_format
+FROM information_schema.tables WHERE engine='innodb';
+table_schema table_name row_format
+test t1 Dynamic
+alter table t1 row_format=compact;
+SELECT table_schema, table_name, row_format
+FROM information_schema.tables WHERE engine='innodb';
+table_schema table_name row_format
+test t1 Compact
+alter table t1 row_format=redundant;
+SELECT table_schema, table_name, row_format
+FROM information_schema.tables WHERE engine='innodb';
+table_schema table_name row_format
+test t1 Redundant
+drop table t1;
+create table t1(a int not null, b text, index(b(10))) engine=innodb
+key_block_size=1;
+create table t2(b text)engine=innodb;
+insert into t2 values(concat('1abcdefghijklmnopqrstuvwxyz', repeat('A',5000)));
+insert into t1 select 1, b from t2;
+commit;
+begin;
+update t1 set b=repeat('B',100);
+select a,left(b,40) from t1 natural join t2;
+a left(b,40)
+1 1abcdefghijklmnopqrstuvwxyzAAAAAAAAAAAAA
+rollback;
+select a,left(b,40) from t1 natural join t2;
+a left(b,40)
+1 1abcdefghijklmnopqrstuvwxyzAAAAAAAAAAAAA
+SELECT table_schema, table_name, row_format
+FROM information_schema.tables WHERE engine='innodb';
+table_schema table_name row_format
+test t1 Compressed
+test t2 Compact
+drop table t1,t2;
+SET SESSION innodb_strict_mode = off;
+CREATE TABLE t1(
+c TEXT NOT NULL, d TEXT NOT NULL,
+PRIMARY KEY (c(767),d(767)))
+ENGINE=InnoDB ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=1 CHARSET=ASCII;
+ERROR 42000: Row size too large. The maximum row size for the used table type, not counting BLOBs, is 8126. You have to change some columns to TEXT or BLOBs
+CREATE TABLE t1(
+c TEXT NOT NULL, d TEXT NOT NULL,
+PRIMARY KEY (c(767),d(767)))
+ENGINE=InnoDB ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=2 CHARSET=ASCII;
+ERROR 42000: Row size too large. The maximum row size for the used table type, not counting BLOBs, is 8126. You have to change some columns to TEXT or BLOBs
+CREATE TABLE t1(
+c TEXT NOT NULL, d TEXT NOT NULL,
+PRIMARY KEY (c(767),d(767)))
+ENGINE=InnoDB ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=4 CHARSET=ASCII;
+drop table t1;
+CREATE TABLE t1(c TEXT, PRIMARY KEY (c(440)))
+ENGINE=InnoDB ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=1 CHARSET=ASCII;
+ERROR 42000: Row size too large. The maximum row size for the used table type, not counting BLOBs, is 8126. You have to change some columns to TEXT or BLOBs
+CREATE TABLE t1(c TEXT, PRIMARY KEY (c(439)))
+ENGINE=InnoDB ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=1 CHARSET=ASCII;
+INSERT INTO t1 VALUES(REPEAT('A',512)),(REPEAT('B',512));
+DROP TABLE t1;
+create table t1( c1 int not null, c2 blob, c3 blob, c4 blob,
+primary key(c1, c2(22), c3(22)))
+engine = innodb row_format = dynamic;
+begin;
+insert into t1 values(1, repeat('A', 20000), repeat('B', 20000),
+repeat('C', 20000));
+update t1 set c3 = repeat('D', 20000) where c1 = 1;
+commit;
+select count(*) from t1 where c2 = repeat('A', 20000);
+count(*)
+1
+select count(*) from t1 where c3 = repeat('D', 20000);
+count(*)
+1
+select count(*) from t1 where c4 = repeat('C', 20000);
+count(*)
+1
+update t1 set c3 = repeat('E', 20000) where c1 = 1;
+drop table t1;
+set global innodb_file_format=`0`;
+select @@innodb_file_format;
+@@innodb_file_format
+Antelope
+set global innodb_file_format=`1`;
+select @@innodb_file_format;
+@@innodb_file_format
+Barracuda
+set global innodb_file_format=`2`;
+ERROR HY000: Incorrect arguments to SET
+set global innodb_file_format=`-1`;
+ERROR HY000: Incorrect arguments to SET
+set global innodb_file_format=`Antelope`;
+set global innodb_file_format=`Barracuda`;
+set global innodb_file_format=`Cheetah`;
+ERROR HY000: Incorrect arguments to SET
+set global innodb_file_format=`abc`;
+ERROR HY000: Incorrect arguments to SET
+set global innodb_file_format=`1a`;
+ERROR HY000: Incorrect arguments to SET
+set global innodb_file_format=``;
+ERROR HY000: Incorrect arguments to SET
+set global innodb_file_per_table = on;
+set global innodb_file_format = `1`;
+set innodb_strict_mode = off;
+create table t1 (id int primary key) engine = innodb key_block_size = 0;
+Warnings:
+Warning 1478 InnoDB: ignoring KEY_BLOCK_SIZE=0.
+drop table t1;
+set innodb_strict_mode = on;
+create table t1 (id int primary key) engine = innodb key_block_size = 0;
+ERROR HY000: Can't create table 'test.t1' (errno: 1478)
+show errors;
+Level Code Message
+Error 1478 InnoDB: invalid KEY_BLOCK_SIZE = 0. Valid values are [1, 2, 4, 8, 16]
+Error 1005 Can't create table 'test.t1' (errno: 1478)
+create table t2 (id int primary key) engine = innodb key_block_size = 9;
+ERROR HY000: Can't create table 'test.t2' (errno: 1478)
+show errors;
+Level Code Message
+Error 1478 InnoDB: invalid KEY_BLOCK_SIZE = 9. Valid values are [1, 2, 4, 8, 16]
+Error 1005 Can't create table 'test.t2' (errno: 1478)
+create table t3 (id int primary key) engine = innodb key_block_size = 1;
+create table t4 (id int primary key) engine = innodb key_block_size = 2;
+create table t5 (id int primary key) engine = innodb key_block_size = 4;
+create table t6 (id int primary key) engine = innodb key_block_size = 8;
+create table t7 (id int primary key) engine = innodb key_block_size = 16;
+create table t8 (id int primary key) engine = innodb row_format = compressed;
+create table t9 (id int primary key) engine = innodb row_format = dynamic;
+create table t10(id int primary key) engine = innodb row_format = compact;
+create table t11(id int primary key) engine = innodb row_format = redundant;
+SELECT table_schema, table_name, row_format
+FROM information_schema.tables WHERE engine='innodb';
+table_schema table_name row_format
+test t10 Compact
+test t11 Redundant
+test t3 Compressed
+test t4 Compressed
+test t5 Compressed
+test t6 Compressed
+test t7 Compressed
+test t8 Compressed
+test t9 Dynamic
+drop table t3, t4, t5, t6, t7, t8, t9, t10, t11;
+create table t1 (id int primary key) engine = innodb
+key_block_size = 8 row_format = compressed;
+create table t2 (id int primary key) engine = innodb
+key_block_size = 8 row_format = redundant;
+ERROR HY000: Can't create table 'test.t2' (errno: 1478)
+show errors;
+Level Code Message
+Error 1478 InnoDB: cannot specify ROW_FORMAT = REDUNDANT with KEY_BLOCK_SIZE.
+Error 1005 Can't create table 'test.t2' (errno: 1478)
+create table t3 (id int primary key) engine = innodb
+key_block_size = 8 row_format = compact;
+ERROR HY000: Can't create table 'test.t3' (errno: 1478)
+show errors;
+Level Code Message
+Error 1478 InnoDB: cannot specify ROW_FORMAT = COMPACT with KEY_BLOCK_SIZE.
+Error 1005 Can't create table 'test.t3' (errno: 1478)
+create table t4 (id int primary key) engine = innodb
+key_block_size = 8 row_format = dynamic;
+ERROR HY000: Can't create table 'test.t4' (errno: 1478)
+show errors;
+Level Code Message
+Error 1478 InnoDB: cannot specify ROW_FORMAT = DYNAMIC with KEY_BLOCK_SIZE.
+Error 1005 Can't create table 'test.t4' (errno: 1478)
+create table t5 (id int primary key) engine = innodb
+key_block_size = 8 row_format = default;
+ERROR HY000: Can't create table 'test.t5' (errno: 1478)
+show errors;
+Level Code Message
+Error 1478 InnoDB: cannot specify ROW_FORMAT = COMPACT with KEY_BLOCK_SIZE.
+Error 1005 Can't create table 'test.t5' (errno: 1478)
+SELECT table_schema, table_name, row_format
+FROM information_schema.tables WHERE engine='innodb';
+table_schema table_name row_format
+test t1 Compressed
+drop table t1;
+create table t1 (id int primary key) engine = innodb
+key_block_size = 9 row_format = redundant;
+ERROR HY000: Can't create table 'test.t1' (errno: 1478)
+show errors;
+Level Code Message
+Error 1478 InnoDB: invalid KEY_BLOCK_SIZE = 9. Valid values are [1, 2, 4, 8, 16]
+Error 1478 InnoDB: cannot specify ROW_FORMAT = REDUNDANT with KEY_BLOCK_SIZE.
+Error 1005 Can't create table 'test.t1' (errno: 1478)
+create table t2 (id int primary key) engine = innodb
+key_block_size = 9 row_format = compact;
+ERROR HY000: Can't create table 'test.t2' (errno: 1478)
+show errors;
+Level Code Message
+Error 1478 InnoDB: invalid KEY_BLOCK_SIZE = 9. Valid values are [1, 2, 4, 8, 16]
+Error 1478 InnoDB: cannot specify ROW_FORMAT = COMPACT with KEY_BLOCK_SIZE.
+Error 1005 Can't create table 'test.t2' (errno: 1478)
+create table t2 (id int primary key) engine = innodb
+key_block_size = 9 row_format = dynamic;
+ERROR HY000: Can't create table 'test.t2' (errno: 1478)
+show errors;
+Level Code Message
+Error 1478 InnoDB: invalid KEY_BLOCK_SIZE = 9. Valid values are [1, 2, 4, 8, 16]
+Error 1478 InnoDB: cannot specify ROW_FORMAT = DYNAMIC with KEY_BLOCK_SIZE.
+Error 1005 Can't create table 'test.t2' (errno: 1478)
+SELECT table_schema, table_name, row_format
+FROM information_schema.tables WHERE engine='innodb';
+table_schema table_name row_format
+set global innodb_file_per_table = off;
+create table t1 (id int primary key) engine = innodb key_block_size = 1;
+ERROR HY000: Can't create table 'test.t1' (errno: 1478)
+show errors;
+Level Code Message
+Error 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_per_table.
+Error 1005 Can't create table 'test.t1' (errno: 1478)
+create table t2 (id int primary key) engine = innodb key_block_size = 2;
+ERROR HY000: Can't create table 'test.t2' (errno: 1478)
+show errors;
+Level Code Message
+Error 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_per_table.
+Error 1005 Can't create table 'test.t2' (errno: 1478)
+create table t3 (id int primary key) engine = innodb key_block_size = 4;
+ERROR HY000: Can't create table 'test.t3' (errno: 1478)
+show errors;
+Level Code Message
+Error 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_per_table.
+Error 1005 Can't create table 'test.t3' (errno: 1478)
+create table t4 (id int primary key) engine = innodb key_block_size = 8;
+ERROR HY000: Can't create table 'test.t4' (errno: 1478)
+show errors;
+Level Code Message
+Error 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_per_table.
+Error 1005 Can't create table 'test.t4' (errno: 1478)
+create table t5 (id int primary key) engine = innodb key_block_size = 16;
+ERROR HY000: Can't create table 'test.t5' (errno: 1478)
+show errors;
+Level Code Message
+Error 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_per_table.
+Error 1005 Can't create table 'test.t5' (errno: 1478)
+create table t6 (id int primary key) engine = innodb row_format = compressed;
+ERROR HY000: Can't create table 'test.t6' (errno: 1478)
+show errors;
+Level Code Message
+Error 1478 InnoDB: ROW_FORMAT=COMPRESSED requires innodb_file_per_table.
+Error 1005 Can't create table 'test.t6' (errno: 1478)
+create table t7 (id int primary key) engine = innodb row_format = dynamic;
+ERROR HY000: Can't create table 'test.t7' (errno: 1478)
+show errors;
+Level Code Message
+Error 1478 InnoDB: ROW_FORMAT=DYNAMIC requires innodb_file_per_table.
+Error 1005 Can't create table 'test.t7' (errno: 1478)
+create table t8 (id int primary key) engine = innodb row_format = compact;
+create table t9 (id int primary key) engine = innodb row_format = redundant;
+SELECT table_schema, table_name, row_format
+FROM information_schema.tables WHERE engine='innodb';
+table_schema table_name row_format
+test t8 Compact
+test t9 Redundant
+drop table t8, t9;
+set global innodb_file_per_table = on;
+set global innodb_file_format = `0`;
+create table t1 (id int primary key) engine = innodb key_block_size = 1;
+ERROR HY000: Can't create table 'test.t1' (errno: 1478)
+show errors;
+Level Code Message
+Error 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_format > Antelope.
+Error 1005 Can't create table 'test.t1' (errno: 1478)
+create table t2 (id int primary key) engine = innodb key_block_size = 2;
+ERROR HY000: Can't create table 'test.t2' (errno: 1478)
+show errors;
+Level Code Message
+Error 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_format > Antelope.
+Error 1005 Can't create table 'test.t2' (errno: 1478)
+create table t3 (id int primary key) engine = innodb key_block_size = 4;
+ERROR HY000: Can't create table 'test.t3' (errno: 1478)
+show errors;
+Level Code Message
+Error 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_format > Antelope.
+Error 1005 Can't create table 'test.t3' (errno: 1478)
+create table t4 (id int primary key) engine = innodb key_block_size = 8;
+ERROR HY000: Can't create table 'test.t4' (errno: 1478)
+show errors;
+Level Code Message
+Error 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_format > Antelope.
+Error 1005 Can't create table 'test.t4' (errno: 1478)
+create table t5 (id int primary key) engine = innodb key_block_size = 16;
+ERROR HY000: Can't create table 'test.t5' (errno: 1478)
+show errors;
+Level Code Message
+Error 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_format > Antelope.
+Error 1005 Can't create table 'test.t5' (errno: 1478)
+create table t6 (id int primary key) engine = innodb row_format = compressed;
+ERROR HY000: Can't create table 'test.t6' (errno: 1478)
+show errors;
+Level Code Message
+Error 1478 InnoDB: ROW_FORMAT=COMPRESSED requires innodb_file_format > Antelope.
+Error 1005 Can't create table 'test.t6' (errno: 1478)
+create table t7 (id int primary key) engine = innodb row_format = dynamic;
+ERROR HY000: Can't create table 'test.t7' (errno: 1478)
+show errors;
+Level Code Message
+Error 1478 InnoDB: ROW_FORMAT=DYNAMIC requires innodb_file_format > Antelope.
+Error 1005 Can't create table 'test.t7' (errno: 1478)
+create table t8 (id int primary key) engine = innodb row_format = compact;
+create table t9 (id int primary key) engine = innodb row_format = redundant;
+SELECT table_schema, table_name, row_format
+FROM information_schema.tables WHERE engine='innodb';
+table_schema table_name row_format
+test t8 Compact
+test t9 Redundant
+drop table t8, t9;
+set global innodb_file_per_table=0;
+set global innodb_file_format=Antelope;
+set global innodb_file_per_table=on;
+set global innodb_file_format=`Barracuda`;
+set global innodb_file_format_check=`Antelope`;
+create table normal_table (
+c1 int
+) engine = innodb;
+select @@innodb_file_format_check;
+@@innodb_file_format_check
+Antelope
+create table zip_table (
+c1 int
+) engine = innodb key_block_size = 8;
+select @@innodb_file_format_check;
+@@innodb_file_format_check
+Barracuda
+set global innodb_file_format_check=`Antelope`;
+select @@innodb_file_format_check;
+@@innodb_file_format_check
+Antelope
+show table status;
+select @@innodb_file_format_check;
+@@innodb_file_format_check
+Barracuda
+drop table normal_table, zip_table;
diff --git a/mysql-test/suite/innodb/r/innodb_bug36169.result b/mysql-test/suite/innodb/r/innodb_bug36169.result
new file mode 100644
index 00000000000..aa80e4d7aa4
--- /dev/null
+++ b/mysql-test/suite/innodb/r/innodb_bug36169.result
@@ -0,0 +1,2 @@
+SET GLOBAL innodb_file_format='Barracuda';
+SET GLOBAL innodb_file_per_table=ON;
diff --git a/mysql-test/suite/innodb/r/innodb_bug36172.result b/mysql-test/suite/innodb/r/innodb_bug36172.result
new file mode 100644
index 00000000000..195775f74c8
--- /dev/null
+++ b/mysql-test/suite/innodb/r/innodb_bug36172.result
@@ -0,0 +1 @@
+SET storage_engine=InnoDB;
diff --git a/mysql-test/suite/innodb/r/innodb_bug40360.result b/mysql-test/suite/innodb/r/innodb_bug40360.result
new file mode 100644
index 00000000000..ef4cf463903
--- /dev/null
+++ b/mysql-test/suite/innodb/r/innodb_bug40360.result
@@ -0,0 +1,4 @@
+SET TX_ISOLATION='READ-COMMITTED';
+CREATE TABLE bug40360 (a INT) engine=innodb;
+INSERT INTO bug40360 VALUES (1);
+DROP TABLE bug40360;
diff --git a/mysql-test/suite/innodb/r/innodb_bug41904.result b/mysql-test/suite/innodb/r/innodb_bug41904.result
new file mode 100644
index 00000000000..6070d32d181
--- /dev/null
+++ b/mysql-test/suite/innodb/r/innodb_bug41904.result
@@ -0,0 +1,4 @@
+CREATE TABLE bug41904 (id INT PRIMARY KEY, uniquecol CHAR(15)) ENGINE=InnoDB;
+INSERT INTO bug41904 VALUES (1,NULL), (2,NULL);
+CREATE UNIQUE INDEX ui ON bug41904 (uniquecol);
+DROP TABLE bug41904;
diff --git a/mysql-test/suite/innodb/r/innodb_bug44032.result b/mysql-test/suite/innodb/r/innodb_bug44032.result
new file mode 100644
index 00000000000..da2a000b06e
--- /dev/null
+++ b/mysql-test/suite/innodb/r/innodb_bug44032.result
@@ -0,0 +1,7 @@
+CREATE TABLE bug44032(c CHAR(3) CHARACTER SET UTF8) ROW_FORMAT=REDUNDANT
+ENGINE=InnoDB;
+INSERT INTO bug44032 VALUES('abc'),(0xEFBCA4EFBCA4EFBCA4);
+UPDATE bug44032 SET c='DDD' WHERE c=0xEFBCA4EFBCA4EFBCA4;
+UPDATE bug44032 SET c=NULL WHERE c='DDD';
+UPDATE bug44032 SET c='DDD' WHERE c IS NULL;
+DROP TABLE bug44032;
diff --git a/mysql-test/suite/innodb/r/innodb_file_format.result b/mysql-test/suite/innodb/r/innodb_file_format.result
new file mode 100644
index 00000000000..9cfac5f001c
--- /dev/null
+++ b/mysql-test/suite/innodb/r/innodb_file_format.result
@@ -0,0 +1,44 @@
+select @@innodb_file_format;
+@@innodb_file_format
+Antelope
+select @@innodb_file_format_check;
+@@innodb_file_format_check
+Antelope
+set global innodb_file_format=antelope;
+set global innodb_file_format=barracuda;
+set global innodb_file_format=cheetah;
+ERROR HY000: Incorrect arguments to SET
+select @@innodb_file_format;
+@@innodb_file_format
+Barracuda
+set global innodb_file_format=default;
+select @@innodb_file_format;
+@@innodb_file_format
+Antelope
+set global innodb_file_format=on;
+ERROR HY000: Incorrect arguments to SET
+set global innodb_file_format=off;
+ERROR HY000: Incorrect arguments to SET
+select @@innodb_file_format;
+@@innodb_file_format
+Antelope
+set global innodb_file_format_check=antelope;
+set global innodb_file_format_check=barracuda;
+set global innodb_file_format_check=cheetah;
+ERROR HY000: Incorrect arguments to SET
+select @@innodb_file_format_check;
+@@innodb_file_format_check
+Barracuda
+set global innodb_file_format_check=default;
+Warnings:
+Warning 1210 Ignoring SET innodb_file_format=on
+select @@innodb_file_format_check;
+@@innodb_file_format_check
+Barracuda
+set global innodb_file_format=on;
+ERROR HY000: Incorrect arguments to SET
+set global innodb_file_format=off;
+ERROR HY000: Incorrect arguments to SET
+select @@innodb_file_format_check;
+@@innodb_file_format_check
+Barracuda
diff --git a/mysql-test/suite/innodb/r/innodb_information_schema.result b/mysql-test/suite/innodb/r/innodb_information_schema.result
new file mode 100644
index 00000000000..396cae579ce
--- /dev/null
+++ b/mysql-test/suite/innodb/r/innodb_information_schema.result
@@ -0,0 +1,23 @@
+lock_mode lock_type lock_table lock_index lock_rec lock_data
+X RECORD `test`.```t'\"_str` `PRIMARY` 2 '1', 'abc', '''abc', 'abc''', 'a''bc', 'a''bc''', '''abc'''''
+X RECORD `test`.```t'\"_str` `PRIMARY` 2 '1', 'abc', '''abc', 'abc''', 'a''bc', 'a''bc''', '''abc'''''
+X RECORD `test`.```t'\"_str` `PRIMARY` 3 '2', 'abc', '"abc', 'abc"', 'a"bc', 'a"bc"', '"abc""'
+X RECORD `test`.```t'\"_str` `PRIMARY` 3 '2', 'abc', '"abc', 'abc"', 'a"bc', 'a"bc"', '"abc""'
+X RECORD `test`.```t'\"_str` `PRIMARY` 4 '3', 'abc', '\\abc', 'abc\\', 'a\\bc', 'a\\bc\\', '\\abc\\\\'
+X RECORD `test`.```t'\"_str` `PRIMARY` 4 '3', 'abc', '\\abc', 'abc\\', 'a\\bc', 'a\\bc\\', '\\abc\\\\'
+X RECORD `test`.```t'\"_str` `PRIMARY` 5 '4', 'abc', '\0abc', 'abc\0', 'a\0bc', 'a\0bc\0', 'a\0bc\0\0'
+X RECORD `test`.```t'\"_str` `PRIMARY` 5 '4', 'abc', '\0abc', 'abc\0', 'a\0bc', 'a\0bc\0', 'a\0bc\0\0'
+X RECORD `test`.`t_min` `PRIMARY` 2 -128, 0, -32768, 0, -8388608, 0, -2147483648, 0, -9223372036854775808, 0
+X RECORD `test`.`t_min` `PRIMARY` 2 -128, 0, -32768, 0, -8388608, 0, -2147483648, 0, -9223372036854775808, 0
+X RECORD `test`.`t_max` `PRIMARY` 2 127, 255, 32767, 65535, 8388607, 16777215, 2147483647, 4294967295, 9223372036854775807, 18446744073709551615
+X RECORD `test`.`t_max` `PRIMARY` 2 127, 255, 32767, 65535, 8388607, 16777215, 2147483647, 4294967295, 9223372036854775807, 18446744073709551615
+X RECORD `test`.```t'\"_str` `PRIMARY` 1 supremum pseudo-record
+X RECORD `test`.```t'\"_str` `PRIMARY` 1 supremum pseudo-record
+lock_table COUNT(*)
+`test`.`t_max` 2
+`test`.`t_min` 2
+`test`.```t'\"_str` 10
+lock_table COUNT(*)
+"test"."t_max" 2
+"test"."t_min" 2
+"test"."`t'\""_str" 10
diff --git a/mysql-test/suite/innodb/t/disabled.def b/mysql-test/suite/innodb/t/disabled.def
new file mode 100644
index 00000000000..baf8c89f539
--- /dev/null
+++ b/mysql-test/suite/innodb/t/disabled.def
@@ -0,0 +1 @@
+innodb-index: InnoDB: Error: table `test`.`t1#1` already exists in InnoDB internal
diff --git a/mysql-test/suite/innodb/t/innodb-analyze.test b/mysql-test/suite/innodb/t/innodb-analyze.test
new file mode 100644
index 00000000000..870e6434797
--- /dev/null
+++ b/mysql-test/suite/innodb/t/innodb-analyze.test
@@ -0,0 +1,66 @@
+#
+# Test that mysqld does not crash when running ANALYZE TABLE with
+# different values of the parameter innodb_stats_sample_pages.
+#
+
+-- source include/have_innodb.inc
+-- source suite/innodb/include/have_innodb_plugin.inc
+
+# we care only that the following SQL commands do not produce errors
+# and do not crash the server
+-- disable_query_log
+-- disable_result_log
+-- enable_warnings
+
+SET GLOBAL innodb_stats_sample_pages=0;
+
+# check that the value has been adjusted to 1
+-- enable_result_log
+SHOW VARIABLES LIKE 'innodb_stats_sample_pages';
+-- disable_result_log
+
+CREATE TABLE innodb_analyze (
+ a INT,
+ b INT,
+ KEY(a),
+ KEY(b,a)
+) ENGINE=InnoDB;
+
+# test with empty table
+
+ANALYZE TABLE innodb_analyze;
+
+SET GLOBAL innodb_stats_sample_pages=2;
+ANALYZE TABLE innodb_analyze;
+
+SET GLOBAL innodb_stats_sample_pages=4;
+ANALYZE TABLE innodb_analyze;
+
+SET GLOBAL innodb_stats_sample_pages=8;
+ANALYZE TABLE innodb_analyze;
+
+SET GLOBAL innodb_stats_sample_pages=16;
+ANALYZE TABLE innodb_analyze;
+
+INSERT INTO innodb_analyze VALUES
+(1,1), (1,1), (1,2), (1,3), (1,4), (1,5),
+(8,1), (8,8), (8,2), (7,1), (1,4), (3,5);
+
+SET GLOBAL innodb_stats_sample_pages=1;
+ANALYZE TABLE innodb_analyze;
+
+SET GLOBAL innodb_stats_sample_pages=2;
+ANALYZE TABLE innodb_analyze;
+
+SET GLOBAL innodb_stats_sample_pages=4;
+ANALYZE TABLE innodb_analyze;
+
+SET GLOBAL innodb_stats_sample_pages=8;
+ANALYZE TABLE innodb_analyze;
+
+SET GLOBAL innodb_stats_sample_pages=16;
+ANALYZE TABLE innodb_analyze;
+
+DROP TABLE innodb_analyze;
+
+SET GLOBAL innodb_stats_sample_pages=DEFAULT;
diff --git a/mysql-test/suite/innodb/t/innodb-index.test b/mysql-test/suite/innodb/t/innodb-index.test
new file mode 100644
index 00000000000..54aff3a42c0
--- /dev/null
+++ b/mysql-test/suite/innodb/t/innodb-index.test
@@ -0,0 +1,534 @@
+-- source include/have_innodb.inc
+
+create table t1(a int not null, b int, c char(10) not null, d varchar(20)) engine = innodb;
+insert into t1 values (5,5,'oo','oo'),(4,4,'tr','tr'),(3,4,'ad','ad'),(2,3,'ak','ak');
+commit;
+--error ER_DUP_KEYNAME
+alter table t1 add index b (b), add index b (b);
+--error ER_DUP_FIELDNAME
+alter table t1 add index (b,b);
+alter table t1 add index d2 (d);
+show create table t1;
+explain select * from t1 force index(d2) order by d;
+select * from t1 force index (d2) order by d;
+--error ER_DUP_ENTRY
+alter table t1 add unique index (b);
+show create table t1;
+alter table t1 add index (b);
+show create table t1;
+
+# Check how existing tables interfere with temporary tables.
+CREATE TABLE `t1#1`(a INT PRIMARY KEY) ENGINE=InnoDB;
+
+--error 156
+alter table t1 add unique index (c), add index (d);
+rename table `t1#1` to `t1#2`;
+--error 156
+alter table t1 add unique index (c), add index (d);
+drop table `t1#2`;
+
+alter table t1 add unique index (c), add index (d);
+show create table t1;
+explain select * from t1 force index(c) order by c;
+alter table t1 add primary key (a), drop index c;
+show create table t1;
+--error ER_MULTIPLE_PRI_KEY
+alter table t1 add primary key (c);
+--error ER_DUP_ENTRY
+alter table t1 drop primary key, add primary key (b);
+create unique index c on t1 (c);
+show create table t1;
+explain select * from t1 force index(c) order by c;
+select * from t1 force index(c) order by c;
+alter table t1 drop index b, add index (b);
+show create table t1;
+insert into t1 values(6,1,'ggg','ggg');
+select * from t1;
+select * from t1 force index(b) order by b;
+select * from t1 force index(c) order by c;
+select * from t1 force index(d) order by d;
+explain select * from t1 force index(b) order by b;
+explain select * from t1 force index(c) order by c;
+explain select * from t1 force index(d) order by d;
+show create table t1;
+drop table t1;
+
+create table t1(a int not null, b int, c char(10), d varchar(20), primary key (a)) engine = innodb;
+insert into t1 values (1,1,'ab','ab'),(2,2,'ac','ac'),(3,3,'ad','ad'),(4,4,'afe','afe');
+commit;
+alter table t1 add index (c(2));
+show create table t1;
+alter table t1 add unique index (d(10));
+show create table t1;
+insert into t1 values(5,1,'ggg','ggg');
+select * from t1;
+select * from t1 force index(c) order by c;
+select * from t1 force index(d) order by d;
+explain select * from t1 order by b;
+explain select * from t1 force index(c) order by c;
+explain select * from t1 force index(d) order by d;
+show create table t1;
+alter table t1 drop index d;
+insert into t1 values(8,9,'fff','fff');
+select * from t1;
+select * from t1 force index(c) order by c;
+explain select * from t1 order by b;
+explain select * from t1 force index(c) order by c;
+explain select * from t1 order by d;
+show create table t1;
+drop table t1;
+
+create table t1(a int not null, b int, c char(10), d varchar(20), primary key (a)) engine = innodb;
+insert into t1 values (1,1,'ab','ab'),(2,2,'ac','ac'),(3,2,'ad','ad'),(4,4,'afe','afe');
+commit;
+alter table t1 add unique index (b,c);
+insert into t1 values(8,9,'fff','fff');
+select * from t1;
+select * from t1 force index(b) order by b;
+explain select * from t1 force index(b) order by b;
+show create table t1;
+alter table t1 add index (b,c);
+insert into t1 values(11,11,'kkk','kkk');
+select * from t1;
+select * from t1 force index(b) order by b;
+explain select * from t1 force index(b) order by b;
+show create table t1;
+alter table t1 add unique index (c,d);
+insert into t1 values(13,13,'yyy','aaa');
+select * from t1;
+select * from t1 force index(b) order by b;
+select * from t1 force index(c) order by c;
+explain select * from t1 force index(b) order by b;
+explain select * from t1 force index(c) order by c;
+show create table t1;
+drop table t1;
+
+create table t1(a int not null, b int not null, c int, primary key (a), key (b)) engine = innodb;
+create table t3(a int not null, c int not null, d int, primary key (a), key (c)) engine = innodb;
+create table t4(a int not null, d int not null, e int, primary key (a), key (d)) engine = innodb;
+create table t2(a int not null, b int not null, c int not null, d int not null, e int,
+foreign key (b) references t1(b) on delete cascade,
+foreign key (c) references t3(c), foreign key (d) references t4(d))
+engine = innodb;
+--error ER_DROP_INDEX_FK
+alter table t1 drop index b;
+--error ER_DROP_INDEX_FK
+alter table t3 drop index c;
+--error ER_DROP_INDEX_FK
+alter table t4 drop index d;
+--error ER_DROP_INDEX_FK
+alter table t2 drop index b;
+--error ER_DROP_INDEX_FK
+alter table t2 drop index b, drop index c, drop index d;
+# Apparently, the following makes mysql_alter_table() drop index d.
+create unique index dc on t2 (d,c);
+create index dc on t1 (b,c);
+# This should preserve the foreign key constraints.
+alter table t2 add primary key (a);
+insert into t1 values (1,1,1);
+insert into t3 values (1,1,1);
+insert into t4 values (1,1,1);
+insert into t2 values (1,1,1,1,1);
+commit;
+alter table t4 add constraint dc foreign key (a) references t1(a);
+show create table t4;
+--replace_regex /'test\.#sql-[0-9a-f_]*'/'#sql-temporary'/
+# a foreign key 'test/dc' already exists
+--error ER_CANT_CREATE_TABLE
+alter table t3 add constraint dc foreign key (a) references t1(a);
+show create table t3;
+alter table t2 drop index b, add index (b);
+show create table t2;
+--error ER_ROW_IS_REFERENCED_2
+delete from t1;
+--error ER_CANT_DROP_FIELD_OR_KEY
+drop index dc on t4;
+# there is no foreign key dc on t3
+--replace_regex /'\.\/test\/#sql2-[0-9a-f-]*'/'#sql2-temporary'/
+--error ER_ERROR_ON_RENAME
+alter table t3 drop foreign key dc;
+alter table t4 drop foreign key dc;
+select * from t2;
+delete from t1;
+select * from t2;
+
+drop table t2,t4,t3,t1;
+
+-- let charset = utf8
+-- source suite/innodb/include/innodb-index.inc
+
+create table t1(a int not null, b int) engine = innodb;
+insert into t1 values (1,1),(1,1),(1,1),(1,1);
+--error ER_DUP_ENTRY
+alter table t1 add unique index (a);
+--error ER_DUP_ENTRY
+alter table t1 add unique index (b);
+--error ER_DUP_ENTRY
+alter table t1 add unique index (a), add unique index(b);
+show create table t1;
+drop table t1;
+
+create table t1(a int not null, c int not null,b int, primary key(a), unique key(c), key(b)) engine = innodb;
+alter table t1 drop index c, drop index b;
+show create table t1;
+drop table t1;
+
+create table t1(a int not null, b int, primary key(a)) engine = innodb;
+alter table t1 add index (b);
+show create table t1;
+drop table t1;
+
+create table t1(a int not null, b int, c char(10), d varchar(20), primary key (a)) engine = innodb;
+insert into t1 values (1,1,'ab','ab'),(2,2,'ac','ac'),(3,3,'ac','ac'),(4,4,'afe','afe'),(5,4,'affe','affe');
+--error ER_DUP_ENTRY
+alter table t1 add unique index (b), add unique index (c), add unique index (d);
+--error ER_DUP_ENTRY
+alter table t1 add unique index (c), add unique index (b), add index (d);
+show create table t1;
+drop table t1;
+
+create table t1(a int not null, b int not null, c int, primary key (a), key(c)) engine=innodb;
+insert into t1 values (5,1,5),(4,2,4),(3,3,3),(2,4,2),(1,5,1);
+alter table t1 add unique index (b);
+insert into t1 values (10,20,20),(11,19,19),(12,18,18),(13,17,17);
+show create table t1;
+check table t1;
+explain select * from t1 force index(c) order by c;
+explain select * from t1 order by a;
+explain select * from t1 force index(b) order by b;
+select * from t1 order by a;
+select * from t1 force index(b) order by b;
+select * from t1 force index(c) order by c;
+drop table t1;
+
+create table t1(a int not null, b int not null) engine=innodb;
+insert into t1 values (1,1);
+alter table t1 add primary key(b);
+insert into t1 values (2,2);
+show create table t1;
+check table t1;
+select * from t1;
+explain select * from t1;
+explain select * from t1 order by a;
+explain select * from t1 order by b;
+checksum table t1;
+drop table t1;
+
+create table t1(a int not null) engine=innodb;
+insert into t1 values (1);
+alter table t1 add primary key(a);
+insert into t1 values (2);
+show create table t1;
+check table t1;
+commit;
+select * from t1;
+explain select * from t1;
+explain select * from t1 order by a;
+drop table t1;
+
+create table t2(d varchar(17) primary key) engine=innodb default charset=utf8;
+create table t3(a int primary key) engine=innodb;
+
+insert into t3 values(22),(44),(33),(55),(66);
+
+insert into t2 values ('jejdkrun87'),('adfd72nh9k'),
+('adfdpplkeock'),('adfdijnmnb78k'),('adfdijn0loKNHJik');
+
+create table t1(a int, b blob, c text, d text not null)
+engine=innodb default charset = utf8;
+
+# r2667 The following test is disabled because MySQL behavior changed.
+# r2667 The test was added with this comment:
+# r2667
+# r2667 ------------------------------------------------------------------------
+# r2667 r1699 | marko | 2007-08-10 19:53:19 +0300 (Fri, 10 Aug 2007) | 5 lines
+# r2667
+# r2667 branches/zip: Add changes that accidentally omitted from r1698:
+# r2667
+# r2667 innodb-index.test, innodb-index.result: Add a test for creating
+# r2667 a PRIMARY KEY on a column that contains a NULL value.
+# r2667 ------------------------------------------------------------------------
+# r2667
+# r2667 but in BZR-r2667:
+# r2667 http://bazaar.launchpad.net/~mysql/mysql-server/mysql-5.1/revision/davi%40mysql.com-20080617141221-8yre8ys9j4uw3xx5?start_revid=joerg%40mysql.com-20080630105418-7qoe5ehomgrcdb89
+# r2667 MySQL changed the behavior to do full table copy when creating PRIMARY INDEX
+# r2667 on a non-NULL column instead of calling ::add_index() which would fail (and
+# r2667 this is what we were testing here). Before r2667 the code execution path was
+# r2667 like this (when adding PRIMARY INDEX on a non-NULL column with ALTER TABLE):
+# r2667
+# r2667 mysql_alter_table()
+# r2667 compare_tables() // would return ALTER_TABLE_INDEX_CHANGED
+# r2667 ::add_index() // would fail with "primary index cannot contain NULL"
+# r2667
+# r2667 after r2667 the code execution path is the following:
+# r2667
+# r2667 mysql_alter_table()
+# r2667 compare_tables() // returns ALTER_TABLE_DATA_CHANGED
+# r2667 full copy is done, without calling ::add_index()
+# r2667
+# r2667 To enable, remove "# r2667: " below.
+# r2667
+# r2667: insert into t1 values (null,null,null,'null');
+insert into t1
+select a,left(repeat(d,100*a),65535),repeat(d,20*a),d from t2,t3;
+drop table t2, t3;
+select count(*) from t1 where a=44;
+select a,
+length(b),b=left(repeat(d,100*a),65535),length(c),c=repeat(d,20*a),d from t1;
+# r2667: --error ER_PRIMARY_CANT_HAVE_NULL
+# r2667: alter table t1 add primary key (a), add key (b(20));
+# r2667: delete from t1 where d='null';
+--error ER_DUP_ENTRY
+alter table t1 add primary key (a), add key (b(20));
+delete from t1 where a%2;
+check table t1;
+alter table t1 add primary key (a,b(255),c(255)), add key (b(767));
+select count(*) from t1 where a=44;
+select a,
+length(b),b=left(repeat(d,100*a),65535),length(c),c=repeat(d,20*a),d from t1;
+show create table t1;
+check table t1;
+explain select * from t1 where b like 'adfd%';
+
+#
+# Test locking
+#
+
+create table t2(a int, b varchar(255), primary key(a,b)) engine=innodb;
+insert into t2 select a,left(b,255) from t1;
+drop table t1;
+rename table t2 to t1;
+
+connect (a,localhost,root,,);
+connect (b,localhost,root,,);
+connection a;
+set innodb_lock_wait_timeout=1;
+begin;
+# Obtain an IX lock on the table
+select a from t1 limit 1 for update;
+connection b;
+set innodb_lock_wait_timeout=1;
+# This would require an S lock on the table, conflicting with the IX lock.
+--error ER_LOCK_WAIT_TIMEOUT
+create index t1ba on t1 (b,a);
+connection a;
+commit;
+begin;
+# Obtain an IS lock on the table
+select a from t1 limit 1 lock in share mode;
+connection b;
+# This will require an S lock on the table. No conflict with the IS lock.
+create index t1ba on t1 (b,a);
+# This would require an X lock on the table, conflicting with the IS lock.
+--error ER_LOCK_WAIT_TIMEOUT
+drop index t1ba on t1;
+connection a;
+commit;
+explain select a from t1 order by b;
+--send
+select a,sleep(2+a/100) from t1 order by b limit 3;
+
+# The following DROP INDEX will succeed, altough the SELECT above has
+# opened a read view. However, during the execution of the SELECT,
+# MySQL should hold a table lock that should block the execution
+# of the DROP INDEX below.
+
+connection b;
+select sleep(1);
+drop index t1ba on t1;
+
+# After the index was dropped, subsequent SELECTs will use the same
+# read view, but they should not be accessing the dropped index any more.
+
+connection a;
+reap;
+explain select a from t1 order by b;
+select a from t1 order by b limit 3;
+commit;
+
+connection default;
+disconnect a;
+disconnect b;
+
+drop table t1;
+
+let $per_table=`select @@innodb_file_per_table`;
+let $format=`select @@innodb_file_format`;
+set global innodb_file_per_table=on;
+set global innodb_file_format='Barracuda';
+# Test creating a table that could lead to undo log overflow.
+# In the undo log, we write a 768-byte prefix (REC_MAX_INDEX_COL_LEN)
+# of each externally stored column that appears as a column prefix in an index.
+# For this test case, it would suffice to write 1 byte, though.
+create table t1(a blob,b blob,c blob,d blob,e blob,f blob,g blob,h blob,
+ i blob,j blob,k blob,l blob,m blob,n blob,o blob,p blob,
+ q blob,r blob,s blob,t blob,u blob)
+ engine=innodb row_format=dynamic;
+create index t1a on t1 (a(1));
+create index t1b on t1 (b(1));
+create index t1c on t1 (c(1));
+create index t1d on t1 (d(1));
+create index t1e on t1 (e(1));
+create index t1f on t1 (f(1));
+create index t1g on t1 (g(1));
+create index t1h on t1 (h(1));
+create index t1i on t1 (i(1));
+create index t1j on t1 (j(1));
+create index t1k on t1 (k(1));
+create index t1l on t1 (l(1));
+create index t1m on t1 (m(1));
+create index t1n on t1 (n(1));
+create index t1o on t1 (o(1));
+create index t1p on t1 (p(1));
+create index t1q on t1 (q(1));
+create index t1r on t1 (r(1));
+create index t1s on t1 (s(1));
+create index t1t on t1 (t(1));
+--error 139
+create index t1u on t1 (u(1));
+--error 139
+create index t1ut on t1 (u(1), t(1));
+create index t1st on t1 (s(1), t(1));
+show create table t1;
+--error 139
+create index t1u on t1 (u(1));
+alter table t1 row_format=compact;
+create index t1u on t1 (u(1));
+
+drop table t1;
+eval set global innodb_file_per_table=$per_table;
+eval set global innodb_file_format=$format;
+
+#
+# Test to check whether CREATE INDEX handles implicit foreign key
+# constraint modifications (Issue #70, Bug #38786)
+#
+SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0;
+SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0;
+
+CREATE TABLE t1(
+ c1 BIGINT(12) NOT NULL,
+ PRIMARY KEY (c1)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1;
+
+CREATE TABLE t2(
+ c1 BIGINT(16) NOT NULL,
+ c2 BIGINT(12) NOT NULL,
+ c3 BIGINT(12) NOT NULL,
+ PRIMARY KEY (c1)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1;
+
+ALTER TABLE t2 ADD CONSTRAINT fk_t2_ca
+ FOREIGN KEY (c3) REFERENCES t1(c1);
+
+SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS;
+SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS;
+
+SHOW CREATE TABLE t2;
+
+CREATE INDEX i_t2_c3_c2 ON t2(c3, c2);
+
+SHOW CREATE TABLE t2;
+
+SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS;
+SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS;
+
+--error ER_NO_REFERENCED_ROW_2
+INSERT INTO t2 VALUES(0,0,0);
+INSERT INTO t1 VALUES(0);
+INSERT INTO t2 VALUES(0,0,0);
+
+DROP TABLE t2;
+
+CREATE TABLE t2(
+ c1 BIGINT(16) NOT NULL,
+ c2 BIGINT(12) NOT NULL,
+ c3 BIGINT(12) NOT NULL,
+ PRIMARY KEY (c1,c2,c3)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1;
+
+ALTER TABLE t2 ADD CONSTRAINT fk_t2_ca
+ FOREIGN KEY (c3) REFERENCES t1(c1);
+
+SHOW CREATE TABLE t2;
+
+CREATE INDEX i_t2_c3_c2 ON t2(c3, c2);
+
+SHOW CREATE TABLE t2;
+--error ER_NO_REFERENCED_ROW_2
+INSERT INTO t2 VALUES(0,0,1);
+INSERT INTO t2 VALUES(0,0,0);
+--error ER_ROW_IS_REFERENCED_2
+DELETE FROM t1;
+DELETE FROM t2;
+
+DROP TABLE t2;
+DROP TABLE t1;
+
+CREATE TABLE t1(
+ c1 BIGINT(12) NOT NULL,
+ c2 INT(4) NOT NULL,
+ PRIMARY KEY (c2,c1)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1;
+
+CREATE TABLE t2(
+ c1 BIGINT(16) NOT NULL,
+ c2 BIGINT(12) NOT NULL,
+ c3 BIGINT(12) NOT NULL,
+ PRIMARY KEY (c1)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1;
+
+--replace_regex /'test\.#sql-[0-9_a-f-]*'/'#sql-temporary'/
+--error ER_CANT_CREATE_TABLE
+ALTER TABLE t2 ADD CONSTRAINT fk_t2_ca
+ FOREIGN KEY (c3,c2) REFERENCES t1(c1,c1);
+--replace_regex /'test\.#sql-[0-9_a-f-]*'/'#sql-temporary'/
+--error ER_CANT_CREATE_TABLE
+ALTER TABLE t2 ADD CONSTRAINT fk_t2_ca
+ FOREIGN KEY (c3,c2) REFERENCES t1(c1,c2);
+--replace_regex /'test\.#sql-[0-9_a-f-]*'/'#sql-temporary'/
+--error ER_CANT_CREATE_TABLE
+ALTER TABLE t2 ADD CONSTRAINT fk_t2_ca
+ FOREIGN KEY (c3,c2) REFERENCES t1(c2,c1);
+ALTER TABLE t1 MODIFY COLUMN c2 BIGINT(12) NOT NULL;
+--replace_regex /'test\.#sql-[0-9_a-f-]*'/'#sql-temporary'/
+--error ER_CANT_CREATE_TABLE
+ALTER TABLE t2 ADD CONSTRAINT fk_t2_ca
+ FOREIGN KEY (c3,c2) REFERENCES t1(c1,c2);
+
+ALTER TABLE t2 ADD CONSTRAINT fk_t2_ca
+ FOREIGN KEY (c3,c2) REFERENCES t1(c2,c1);
+SHOW CREATE TABLE t1;
+SHOW CREATE TABLE t2;
+CREATE INDEX i_t2_c2_c1 ON t2(c2, c1);
+SHOW CREATE TABLE t2;
+CREATE INDEX i_t2_c3_c1_c2 ON t2(c3, c1, c2);
+SHOW CREATE TABLE t2;
+CREATE INDEX i_t2_c3_c2 ON t2(c3, c2);
+SHOW CREATE TABLE t2;
+
+DROP TABLE t2;
+DROP TABLE t1;
+
+connect (a,localhost,root,,);
+connect (b,localhost,root,,);
+connection a;
+CREATE TABLE t1 (a INT, b CHAR(1)) ENGINE=InnoDB;
+INSERT INTO t1 VALUES (3,'a'),(3,'b'),(1,'c'),(0,'d'),(1,'e');
+connection b;
+BEGIN;
+SELECT * FROM t1;
+connection a;
+CREATE INDEX t1a ON t1(a);
+connection b;
+SELECT * FROM t1;
+--error ER_TABLE_DEF_CHANGED
+SELECT * FROM t1 FORCE INDEX(t1a) ORDER BY a;
+SELECT * FROM t1;
+COMMIT;
+SELECT * FROM t1 FORCE INDEX(t1a) ORDER BY a;
+connection default;
+disconnect a;
+disconnect b;
+
+DROP TABLE t1;
diff --git a/mysql-test/suite/innodb/t/innodb-index_ucs2.test b/mysql-test/suite/innodb/t/innodb-index_ucs2.test
new file mode 100644
index 00000000000..db4626ac346
--- /dev/null
+++ b/mysql-test/suite/innodb/t/innodb-index_ucs2.test
@@ -0,0 +1,5 @@
+-- source include/have_innodb.inc
+-- source include/have_ucs2.inc
+
+-- let charset = ucs2
+-- source suite/innodb/include/innodb-index.inc
diff --git a/mysql-test/suite/innodb/t/innodb-timeout.test b/mysql-test/suite/innodb/t/innodb-timeout.test
new file mode 100644
index 00000000000..1ee1ad63180
--- /dev/null
+++ b/mysql-test/suite/innodb/t/innodb-timeout.test
@@ -0,0 +1,65 @@
+-- source include/have_innodb.inc
+-- source suite/innodb/include/have_innodb_plugin.inc
+
+let $timeout=`select @@innodb_lock_wait_timeout`;
+set global innodb_lock_wait_timeout=42;
+
+connect (a,localhost,root,,);
+connect (b,localhost,root,,);
+
+connection a;
+select @@innodb_lock_wait_timeout;
+set innodb_lock_wait_timeout=1;
+select @@innodb_lock_wait_timeout;
+
+connection b;
+select @@innodb_lock_wait_timeout;
+set global innodb_lock_wait_timeout=347;
+select @@innodb_lock_wait_timeout;
+set innodb_lock_wait_timeout=1;
+select @@innodb_lock_wait_timeout;
+
+connect (c,localhost,root,,);
+connection c;
+select @@innodb_lock_wait_timeout;
+connection default;
+disconnect c;
+
+connection a;
+create table t1(a int primary key)engine=innodb;
+begin;
+insert into t1 values(1),(2),(3);
+
+connection b;
+--send
+select * from t1 for update;
+
+connection a;
+commit;
+
+connection b;
+reap;
+
+connection a;
+begin;
+insert into t1 values(4);
+
+connection b;
+--send
+select * from t1 for update;
+
+connection a;
+sleep 2;
+commit;
+
+connection b;
+--error ER_LOCK_WAIT_TIMEOUT
+reap;
+drop table t1;
+
+connection default;
+
+disconnect a;
+disconnect b;
+
+eval set global innodb_lock_wait_timeout=$timeout;
diff --git a/mysql-test/suite/innodb/t/innodb-use-sys-malloc-master.opt b/mysql-test/suite/innodb/t/innodb-use-sys-malloc-master.opt
new file mode 100644
index 00000000000..8ec086387f8
--- /dev/null
+++ b/mysql-test/suite/innodb/t/innodb-use-sys-malloc-master.opt
@@ -0,0 +1,2 @@
+--loose-innodb-use-sys-malloc=true
+--loose-innodb-use-sys-malloc=true
diff --git a/mysql-test/suite/innodb/t/innodb-use-sys-malloc.test b/mysql-test/suite/innodb/t/innodb-use-sys-malloc.test
new file mode 100644
index 00000000000..4df3ca9d27c
--- /dev/null
+++ b/mysql-test/suite/innodb/t/innodb-use-sys-malloc.test
@@ -0,0 +1,49 @@
+--source include/have_innodb.inc
+-- source suite/innodb/include/have_innodb_plugin.inc
+
+#display current value of innodb_use_sys_malloc
+SELECT @@GLOBAL.innodb_use_sys_malloc;
+--echo 1 Expected
+
+#try changing it. Should fail.
+--error ER_INCORRECT_GLOBAL_LOCAL_VAR
+SET @@GLOBAL.innodb_use_sys_malloc=0;
+--echo Expected error 'Read only variable'
+
+SELECT @@GLOBAL.innodb_use_sys_malloc;
+--echo 1 Expected
+
+
+#do some stuff to see if it works.
+--disable_warnings
+drop table if exists t1;
+--enable_warnings
+
+create table t1(a int not null) engine=innodb DEFAULT CHARSET=latin1;
+insert into t1 values (1),(2),(3),(4),(5),(6),(7);
+select * from t1;
+drop table t1;
+--source include/have_innodb.inc
+
+#display current value of innodb_use_sys_malloc
+SELECT @@GLOBAL.innodb_use_sys_malloc;
+--echo 1 Expected
+
+#try changing it. Should fail.
+--error ER_INCORRECT_GLOBAL_LOCAL_VAR
+SET @@GLOBAL.innodb_use_sys_malloc=0;
+--echo Expected error 'Read only variable'
+
+SELECT @@GLOBAL.innodb_use_sys_malloc;
+--echo 1 Expected
+
+
+#do some stuff to see if it works.
+--disable_warnings
+drop table if exists t1;
+--enable_warnings
+
+create table t1(a int not null) engine=innodb DEFAULT CHARSET=latin1;
+insert into t1 values (1),(2),(3),(4),(5),(6),(7);
+select * from t1;
+drop table t1;
diff --git a/mysql-test/suite/innodb/t/innodb-zip.test b/mysql-test/suite/innodb/t/innodb-zip.test
new file mode 100644
index 00000000000..3ee278b7c5a
--- /dev/null
+++ b/mysql-test/suite/innodb/t/innodb-zip.test
@@ -0,0 +1,344 @@
+-- source include/have_innodb.inc
+-- source suite/innodb/include/have_innodb_plugin.inc
+
+let $per_table=`select @@innodb_file_per_table`;
+let $format=`select @@innodb_file_format`;
+let $innodb_file_format_check_orig=`select @@innodb_file_format_check`;
+set global innodb_file_per_table=off;
+set global innodb_file_format=`0`;
+
+create table t0(a int primary key) engine=innodb row_format=compressed;
+create table t00(a int primary key) engine=innodb
+key_block_size=4 row_format=compressed;
+create table t1(a int primary key) engine=innodb row_format=dynamic;
+create table t2(a int primary key) engine=innodb row_format=redundant;
+create table t3(a int primary key) engine=innodb row_format=compact;
+create table t4(a int primary key) engine=innodb key_block_size=9;
+create table t5(a int primary key) engine=innodb
+key_block_size=1 row_format=redundant;
+
+set global innodb_file_per_table=on;
+create table t6(a int primary key) engine=innodb
+key_block_size=1 row_format=redundant;
+set global innodb_file_format=`1`;
+create table t7(a int primary key) engine=innodb
+key_block_size=1 row_format=redundant;
+create table t8(a int primary key) engine=innodb
+key_block_size=1 row_format=fixed;
+create table t9(a int primary key) engine=innodb
+key_block_size=1 row_format=compact;
+create table t10(a int primary key) engine=innodb
+key_block_size=1 row_format=dynamic;
+create table t11(a int primary key) engine=innodb
+key_block_size=1 row_format=compressed;
+create table t12(a int primary key) engine=innodb
+key_block_size=1;
+create table t13(a int primary key) engine=innodb
+row_format=compressed;
+create table t14(a int primary key) engine=innodb key_block_size=9;
+
+SELECT table_schema, table_name, row_format
+FROM information_schema.tables WHERE engine='innodb';
+
+drop table t0,t00,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14;
+alter table t1 key_block_size=0;
+alter table t1 row_format=dynamic;
+SELECT table_schema, table_name, row_format
+FROM information_schema.tables WHERE engine='innodb';
+alter table t1 row_format=compact;
+SELECT table_schema, table_name, row_format
+FROM information_schema.tables WHERE engine='innodb';
+alter table t1 row_format=redundant;
+SELECT table_schema, table_name, row_format
+FROM information_schema.tables WHERE engine='innodb';
+drop table t1;
+
+create table t1(a int not null, b text, index(b(10))) engine=innodb
+key_block_size=1;
+
+create table t2(b text)engine=innodb;
+insert into t2 values(concat('1abcdefghijklmnopqrstuvwxyz', repeat('A',5000)));
+
+insert into t1 select 1, b from t2;
+commit;
+
+connect (a,localhost,root,,);
+connect (b,localhost,root,,);
+
+connection a;
+begin;
+update t1 set b=repeat('B',100);
+
+connection b;
+select a,left(b,40) from t1 natural join t2;
+
+connection a;
+rollback;
+
+connection b;
+select a,left(b,40) from t1 natural join t2;
+
+connection default;
+disconnect a;
+disconnect b;
+
+SELECT table_schema, table_name, row_format
+FROM information_schema.tables WHERE engine='innodb';
+drop table t1,t2;
+
+# The following should fail even in non-strict mode.
+SET SESSION innodb_strict_mode = off;
+--error ER_TOO_BIG_ROWSIZE
+CREATE TABLE t1(
+ c TEXT NOT NULL, d TEXT NOT NULL,
+ PRIMARY KEY (c(767),d(767)))
+ENGINE=InnoDB ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=1 CHARSET=ASCII;
+--error ER_TOO_BIG_ROWSIZE
+CREATE TABLE t1(
+ c TEXT NOT NULL, d TEXT NOT NULL,
+ PRIMARY KEY (c(767),d(767)))
+ENGINE=InnoDB ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=2 CHARSET=ASCII;
+CREATE TABLE t1(
+ c TEXT NOT NULL, d TEXT NOT NULL,
+ PRIMARY KEY (c(767),d(767)))
+ENGINE=InnoDB ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=4 CHARSET=ASCII;
+drop table t1;
+--error ER_TOO_BIG_ROWSIZE
+CREATE TABLE t1(c TEXT, PRIMARY KEY (c(440)))
+ENGINE=InnoDB ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=1 CHARSET=ASCII;
+CREATE TABLE t1(c TEXT, PRIMARY KEY (c(439)))
+ENGINE=InnoDB ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=1 CHARSET=ASCII;
+INSERT INTO t1 VALUES(REPEAT('A',512)),(REPEAT('B',512));
+DROP TABLE t1;
+
+#
+# Test blob column inheritance (mantis issue#36)
+#
+
+create table t1( c1 int not null, c2 blob, c3 blob, c4 blob,
+ primary key(c1, c2(22), c3(22)))
+ engine = innodb row_format = dynamic;
+begin;
+insert into t1 values(1, repeat('A', 20000), repeat('B', 20000),
+ repeat('C', 20000));
+
+update t1 set c3 = repeat('D', 20000) where c1 = 1;
+commit;
+
+# one blob column which is unchanged in update and part of PK
+# one blob column which is changed and part of of PK
+# one blob column which is not part of PK and is unchanged
+select count(*) from t1 where c2 = repeat('A', 20000);
+select count(*) from t1 where c3 = repeat('D', 20000);
+select count(*) from t1 where c4 = repeat('C', 20000);
+
+update t1 set c3 = repeat('E', 20000) where c1 = 1;
+drop table t1;
+
+#
+#
+# Test innodb_file_format
+#
+set global innodb_file_format=`0`;
+select @@innodb_file_format;
+set global innodb_file_format=`1`;
+select @@innodb_file_format;
+-- error ER_WRONG_ARGUMENTS
+set global innodb_file_format=`2`;
+-- error ER_WRONG_ARGUMENTS
+set global innodb_file_format=`-1`;
+set global innodb_file_format=`Antelope`;
+set global innodb_file_format=`Barracuda`;
+-- error ER_WRONG_ARGUMENTS
+set global innodb_file_format=`Cheetah`;
+-- error ER_WRONG_ARGUMENTS
+set global innodb_file_format=`abc`;
+-- error ER_WRONG_ARGUMENTS
+set global innodb_file_format=`1a`;
+-- error ER_WRONG_ARGUMENTS
+set global innodb_file_format=``;
+
+#test strict mode.
+# this does not work anymore, has been removed from mysqltest
+# -- enable_errors
+set global innodb_file_per_table = on;
+set global innodb_file_format = `1`;
+
+set innodb_strict_mode = off;
+create table t1 (id int primary key) engine = innodb key_block_size = 0;
+drop table t1;
+
+#set strict_mode
+set innodb_strict_mode = on;
+
+#Test different values of KEY_BLOCK_SIZE
+
+--error ER_CANT_CREATE_TABLE
+create table t1 (id int primary key) engine = innodb key_block_size = 0;
+show errors;
+
+--error ER_CANT_CREATE_TABLE
+create table t2 (id int primary key) engine = innodb key_block_size = 9;
+show errors;
+
+
+create table t3 (id int primary key) engine = innodb key_block_size = 1;
+create table t4 (id int primary key) engine = innodb key_block_size = 2;
+create table t5 (id int primary key) engine = innodb key_block_size = 4;
+create table t6 (id int primary key) engine = innodb key_block_size = 8;
+create table t7 (id int primary key) engine = innodb key_block_size = 16;
+
+#check various ROW_FORMAT values.
+create table t8 (id int primary key) engine = innodb row_format = compressed;
+create table t9 (id int primary key) engine = innodb row_format = dynamic;
+create table t10(id int primary key) engine = innodb row_format = compact;
+create table t11(id int primary key) engine = innodb row_format = redundant;
+
+SELECT table_schema, table_name, row_format
+FROM information_schema.tables WHERE engine='innodb';
+drop table t3, t4, t5, t6, t7, t8, t9, t10, t11;
+
+#test different values of ROW_FORMAT with KEY_BLOCK_SIZE
+create table t1 (id int primary key) engine = innodb
+key_block_size = 8 row_format = compressed;
+
+--error ER_CANT_CREATE_TABLE
+create table t2 (id int primary key) engine = innodb
+key_block_size = 8 row_format = redundant;
+show errors;
+
+--error ER_CANT_CREATE_TABLE
+create table t3 (id int primary key) engine = innodb
+key_block_size = 8 row_format = compact;
+show errors;
+
+--error ER_CANT_CREATE_TABLE
+create table t4 (id int primary key) engine = innodb
+key_block_size = 8 row_format = dynamic;
+show errors;
+
+--error ER_CANT_CREATE_TABLE
+create table t5 (id int primary key) engine = innodb
+key_block_size = 8 row_format = default;
+show errors;
+
+SELECT table_schema, table_name, row_format
+FROM information_schema.tables WHERE engine='innodb';
+drop table t1;
+
+#test multiple errors
+--error ER_CANT_CREATE_TABLE
+create table t1 (id int primary key) engine = innodb
+key_block_size = 9 row_format = redundant;
+show errors;
+
+--error ER_CANT_CREATE_TABLE
+create table t2 (id int primary key) engine = innodb
+key_block_size = 9 row_format = compact;
+show errors;
+
+--error ER_CANT_CREATE_TABLE
+create table t2 (id int primary key) engine = innodb
+key_block_size = 9 row_format = dynamic;
+show errors;
+
+SELECT table_schema, table_name, row_format
+FROM information_schema.tables WHERE engine='innodb';
+
+#test valid values with innodb_file_per_table unset
+set global innodb_file_per_table = off;
+
+--error ER_CANT_CREATE_TABLE
+create table t1 (id int primary key) engine = innodb key_block_size = 1;
+show errors;
+--error ER_CANT_CREATE_TABLE
+create table t2 (id int primary key) engine = innodb key_block_size = 2;
+show errors;
+--error ER_CANT_CREATE_TABLE
+create table t3 (id int primary key) engine = innodb key_block_size = 4;
+show errors;
+--error ER_CANT_CREATE_TABLE
+create table t4 (id int primary key) engine = innodb key_block_size = 8;
+show errors;
+--error ER_CANT_CREATE_TABLE
+create table t5 (id int primary key) engine = innodb key_block_size = 16;
+show errors;
+--error ER_CANT_CREATE_TABLE
+create table t6 (id int primary key) engine = innodb row_format = compressed;
+show errors;
+--error ER_CANT_CREATE_TABLE
+create table t7 (id int primary key) engine = innodb row_format = dynamic;
+show errors;
+create table t8 (id int primary key) engine = innodb row_format = compact;
+create table t9 (id int primary key) engine = innodb row_format = redundant;
+
+SELECT table_schema, table_name, row_format
+FROM information_schema.tables WHERE engine='innodb';
+drop table t8, t9;
+
+#test valid values with innodb_file_format unset
+set global innodb_file_per_table = on;
+set global innodb_file_format = `0`;
+
+--error ER_CANT_CREATE_TABLE
+create table t1 (id int primary key) engine = innodb key_block_size = 1;
+show errors;
+--error ER_CANT_CREATE_TABLE
+create table t2 (id int primary key) engine = innodb key_block_size = 2;
+show errors;
+--error ER_CANT_CREATE_TABLE
+create table t3 (id int primary key) engine = innodb key_block_size = 4;
+show errors;
+--error ER_CANT_CREATE_TABLE
+create table t4 (id int primary key) engine = innodb key_block_size = 8;
+show errors;
+--error ER_CANT_CREATE_TABLE
+create table t5 (id int primary key) engine = innodb key_block_size = 16;
+show errors;
+--error ER_CANT_CREATE_TABLE
+create table t6 (id int primary key) engine = innodb row_format = compressed;
+show errors;
+--error ER_CANT_CREATE_TABLE
+create table t7 (id int primary key) engine = innodb row_format = dynamic;
+show errors;
+create table t8 (id int primary key) engine = innodb row_format = compact;
+create table t9 (id int primary key) engine = innodb row_format = redundant;
+
+SELECT table_schema, table_name, row_format
+FROM information_schema.tables WHERE engine='innodb';
+drop table t8, t9;
+
+eval set global innodb_file_per_table=$per_table;
+eval set global innodb_file_format=$format;
+#
+# Testing of tablespace tagging
+#
+-- disable_info
+set global innodb_file_per_table=on;
+set global innodb_file_format=`Barracuda`;
+set global innodb_file_format_check=`Antelope`;
+create table normal_table (
+ c1 int
+) engine = innodb;
+select @@innodb_file_format_check;
+create table zip_table (
+ c1 int
+) engine = innodb key_block_size = 8;
+select @@innodb_file_format_check;
+set global innodb_file_format_check=`Antelope`;
+select @@innodb_file_format_check;
+-- disable_result_log
+show table status;
+-- enable_result_log
+select @@innodb_file_format_check;
+drop table normal_table, zip_table;
+-- disable_result_log
+
+#
+# restore environment to the state it was before this test execution
+#
+
+-- disable_query_log
+eval set global innodb_file_format=$format;
+eval set global innodb_file_per_table=$per_table;
+eval set global innodb_file_format_check=$innodb_file_format_check_orig;
diff --git a/mysql-test/suite/innodb/t/innodb_bug36169.test b/mysql-test/suite/innodb/t/innodb_bug36169.test
new file mode 100644
index 00000000000..da852b816f4
--- /dev/null
+++ b/mysql-test/suite/innodb/t/innodb_bug36169.test
@@ -0,0 +1,1159 @@
+#
+# Bug#36169 create innodb compressed table with too large row size crashed
+# http://bugs.mysql.com/36169
+#
+
+-- source include/have_innodb.inc
+-- source suite/innodb/include/have_innodb_plugin.inc
+
+SET GLOBAL innodb_file_format='Barracuda';
+SET GLOBAL innodb_file_per_table=ON;
+
+#
+# The following is copied from http://bugs.mysql.com/36169
+# (http://bugs.mysql.com/file.php?id=9121)
+# Probably it can be simplified but that is not obvious.
+#
+
+# we care only that the following SQL commands do produce errors
+# as expected and do not crash the server
+-- disable_query_log
+-- disable_result_log
+
+# Generating 10 tables
+# Creating a table with 94 columns and 24 indexes
+DROP TABLE IF EXISTS `table0`;
+--error ER_TOO_BIG_ROWSIZE
+CREATE TABLE IF NOT EXISTS `table0`
+(`col0` BOOL,
+`col1` BOOL,
+`col2` TINYINT,
+`col3` DATE,
+`col4` TIME,
+`col5` SET ('test1','test2','test3'),
+`col6` TIME,
+`col7` TEXT,
+`col8` DECIMAL,
+`col9` SET ('test1','test2','test3'),
+`col10` FLOAT,
+`col11` DOUBLE PRECISION,
+`col12` ENUM ('test1','test2','test3'),
+`col13` TINYBLOB,
+`col14` YEAR,
+`col15` SET ('test1','test2','test3'),
+`col16` NUMERIC,
+`col17` NUMERIC,
+`col18` BLOB,
+`col19` DATETIME,
+`col20` DOUBLE PRECISION,
+`col21` DECIMAL,
+`col22` DATETIME,
+`col23` NUMERIC,
+`col24` NUMERIC,
+`col25` LONGTEXT,
+`col26` TINYBLOB,
+`col27` TIME,
+`col28` TINYBLOB,
+`col29` ENUM ('test1','test2','test3'),
+`col30` SMALLINT,
+`col31` REAL,
+`col32` FLOAT,
+`col33` CHAR (175),
+`col34` TINYTEXT,
+`col35` TINYTEXT,
+`col36` TINYBLOB,
+`col37` TINYBLOB,
+`col38` TINYTEXT,
+`col39` MEDIUMBLOB,
+`col40` TIMESTAMP,
+`col41` DOUBLE,
+`col42` SMALLINT,
+`col43` LONGBLOB,
+`col44` VARCHAR (80),
+`col45` MEDIUMTEXT,
+`col46` NUMERIC,
+`col47` BIGINT,
+`col48` DATE,
+`col49` TINYBLOB,
+`col50` DATE,
+`col51` BOOL,
+`col52` MEDIUMINT,
+`col53` FLOAT,
+`col54` TINYBLOB,
+`col55` LONGTEXT,
+`col56` SMALLINT,
+`col57` ENUM ('test1','test2','test3'),
+`col58` DATETIME,
+`col59` MEDIUMTEXT,
+`col60` VARCHAR (232),
+`col61` NUMERIC,
+`col62` YEAR,
+`col63` SMALLINT,
+`col64` TIMESTAMP,
+`col65` BLOB,
+`col66` LONGBLOB,
+`col67` INT,
+`col68` LONGTEXT,
+`col69` ENUM ('test1','test2','test3'),
+`col70` INT,
+`col71` TIME,
+`col72` TIMESTAMP,
+`col73` TIMESTAMP,
+`col74` VARCHAR (170),
+`col75` SET ('test1','test2','test3'),
+`col76` TINYBLOB,
+`col77` BIGINT,
+`col78` NUMERIC,
+`col79` DATETIME,
+`col80` YEAR,
+`col81` NUMERIC,
+`col82` LONGBLOB,
+`col83` TEXT,
+`col84` CHAR (83),
+`col85` DECIMAL,
+`col86` FLOAT,
+`col87` INT,
+`col88` VARCHAR (145),
+`col89` DATE,
+`col90` DECIMAL,
+`col91` DECIMAL,
+`col92` MEDIUMBLOB,
+`col93` TIME,
+KEY `idx0` (`col69`,`col90`,`col8`),
+KEY `idx1` (`col60`),
+KEY `idx2` (`col60`,`col70`,`col74`),
+KEY `idx3` (`col22`,`col32`,`col72`,`col30`),
+KEY `idx4` (`col29`),
+KEY `idx5` (`col19`,`col45`(143)),
+KEY `idx6` (`col46`,`col48`,`col5`,`col39`(118)),
+KEY `idx7` (`col48`,`col61`),
+KEY `idx8` (`col93`),
+KEY `idx9` (`col31`),
+KEY `idx10` (`col30`,`col21`),
+KEY `idx11` (`col67`),
+KEY `idx12` (`col44`,`col6`,`col8`,`col38`(226)),
+KEY `idx13` (`col71`,`col41`,`col15`,`col49`(88)),
+KEY `idx14` (`col78`),
+KEY `idx15` (`col63`,`col67`,`col64`),
+KEY `idx16` (`col17`,`col86`),
+KEY `idx17` (`col77`,`col56`,`col10`,`col55`(24)),
+KEY `idx18` (`col62`),
+KEY `idx19` (`col31`,`col57`,`col56`,`col53`),
+KEY `idx20` (`col46`),
+KEY `idx21` (`col83`(54)),
+KEY `idx22` (`col51`,`col7`(120)),
+KEY `idx23` (`col7`(163),`col31`,`col71`,`col14`)
+)engine=innodb ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=1;
+
+# Creating a table with 10 columns and 32 indexes
+DROP TABLE IF EXISTS `table1`;
+--error ER_TOO_BIG_ROWSIZE
+CREATE TABLE IF NOT EXISTS `table1`
+(`col0` CHAR (113),
+`col1` FLOAT,
+`col2` BIGINT,
+`col3` DECIMAL,
+`col4` BLOB,
+`col5` LONGTEXT,
+`col6` SET ('test1','test2','test3'),
+`col7` BIGINT,
+`col8` BIGINT,
+`col9` TINYBLOB,
+KEY `idx0` (`col5`(101),`col7`,`col8`),
+KEY `idx1` (`col8`),
+KEY `idx2` (`col4`(177),`col9`(126),`col6`,`col3`),
+KEY `idx3` (`col5`(160)),
+KEY `idx4` (`col9`(242)),
+KEY `idx5` (`col4`(139),`col2`,`col3`),
+KEY `idx6` (`col7`),
+KEY `idx7` (`col6`,`col2`,`col0`,`col3`),
+KEY `idx8` (`col9`(66)),
+KEY `idx9` (`col5`(253)),
+KEY `idx10` (`col1`,`col7`,`col2`),
+KEY `idx11` (`col9`(242),`col0`,`col8`,`col5`(163)),
+KEY `idx12` (`col8`),
+KEY `idx13` (`col0`,`col9`(37)),
+KEY `idx14` (`col0`),
+KEY `idx15` (`col5`(111)),
+KEY `idx16` (`col8`,`col0`,`col5`(13)),
+KEY `idx17` (`col4`(139)),
+KEY `idx18` (`col5`(189),`col2`,`col3`,`col9`(136)),
+KEY `idx19` (`col0`,`col3`,`col1`,`col8`),
+KEY `idx20` (`col8`),
+KEY `idx21` (`col0`,`col7`,`col9`(227),`col3`),
+KEY `idx22` (`col0`),
+KEY `idx23` (`col2`),
+KEY `idx24` (`col3`),
+KEY `idx25` (`col2`,`col3`),
+KEY `idx26` (`col0`),
+KEY `idx27` (`col5`(254)),
+KEY `idx28` (`col3`),
+KEY `idx29` (`col3`),
+KEY `idx30` (`col7`,`col3`,`col0`,`col4`(220)),
+KEY `idx31` (`col4`(1),`col0`)
+)engine=innodb ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=1;
+
+# Creating a table with 141 columns and 18 indexes
+DROP TABLE IF EXISTS `table2`;
+--error ER_TOO_BIG_ROWSIZE
+CREATE TABLE IF NOT EXISTS `table2`
+(`col0` BOOL,
+`col1` MEDIUMINT,
+`col2` VARCHAR (209),
+`col3` MEDIUMBLOB,
+`col4` CHAR (13),
+`col5` DOUBLE,
+`col6` TINYTEXT,
+`col7` REAL,
+`col8` SMALLINT,
+`col9` BLOB,
+`col10` TINYINT,
+`col11` DECIMAL,
+`col12` BLOB,
+`col13` DECIMAL,
+`col14` LONGBLOB,
+`col15` SMALLINT,
+`col16` LONGBLOB,
+`col17` TINYTEXT,
+`col18` FLOAT,
+`col19` CHAR (78),
+`col20` MEDIUMTEXT,
+`col21` SET ('test1','test2','test3'),
+`col22` MEDIUMINT,
+`col23` INT,
+`col24` MEDIUMBLOB,
+`col25` ENUM ('test1','test2','test3'),
+`col26` TINYBLOB,
+`col27` VARCHAR (116),
+`col28` TIMESTAMP,
+`col29` BLOB,
+`col30` SMALLINT,
+`col31` DOUBLE PRECISION,
+`col32` DECIMAL,
+`col33` DECIMAL,
+`col34` TEXT,
+`col35` MEDIUMINT,
+`col36` MEDIUMINT,
+`col37` BIGINT,
+`col38` VARCHAR (253),
+`col39` TINYBLOB,
+`col40` MEDIUMBLOB,
+`col41` BIGINT,
+`col42` DOUBLE,
+`col43` TEXT,
+`col44` BLOB,
+`col45` TIME,
+`col46` MEDIUMINT,
+`col47` DOUBLE PRECISION,
+`col48` SET ('test1','test2','test3'),
+`col49` DOUBLE PRECISION,
+`col50` VARCHAR (97),
+`col51` TEXT,
+`col52` NUMERIC,
+`col53` ENUM ('test1','test2','test3'),
+`col54` MEDIUMTEXT,
+`col55` MEDIUMINT,
+`col56` DATETIME,
+`col57` DATETIME,
+`col58` MEDIUMTEXT,
+`col59` CHAR (244),
+`col60` LONGBLOB,
+`col61` MEDIUMBLOB,
+`col62` DOUBLE,
+`col63` SMALLINT,
+`col64` BOOL,
+`col65` SMALLINT,
+`col66` VARCHAR (212),
+`col67` TIME,
+`col68` REAL,
+`col69` BOOL,
+`col70` BIGINT,
+`col71` DATE,
+`col72` TINYINT,
+`col73` ENUM ('test1','test2','test3'),
+`col74` DATE,
+`col75` TIME,
+`col76` DATETIME,
+`col77` BOOL,
+`col78` TINYTEXT,
+`col79` MEDIUMINT,
+`col80` NUMERIC,
+`col81` LONGTEXT,
+`col82` SET ('test1','test2','test3'),
+`col83` DOUBLE PRECISION,
+`col84` NUMERIC,
+`col85` VARCHAR (184),
+`col86` DOUBLE PRECISION,
+`col87` MEDIUMTEXT,
+`col88` MEDIUMBLOB,
+`col89` BOOL,
+`col90` SMALLINT,
+`col91` TINYINT,
+`col92` ENUM ('test1','test2','test3'),
+`col93` BOOL,
+`col94` TIMESTAMP,
+`col95` BOOL,
+`col96` MEDIUMTEXT,
+`col97` DECIMAL,
+`col98` BOOL,
+`col99` DECIMAL,
+`col100` MEDIUMINT,
+`col101` DOUBLE PRECISION,
+`col102` TINYINT,
+`col103` BOOL,
+`col104` MEDIUMINT,
+`col105` DECIMAL,
+`col106` NUMERIC,
+`col107` TIMESTAMP,
+`col108` MEDIUMBLOB,
+`col109` TINYBLOB,
+`col110` SET ('test1','test2','test3'),
+`col111` YEAR,
+`col112` TIMESTAMP,
+`col113` CHAR (201),
+`col114` BOOL,
+`col115` TINYINT,
+`col116` DOUBLE,
+`col117` TINYINT,
+`col118` TIMESTAMP,
+`col119` SET ('test1','test2','test3'),
+`col120` SMALLINT,
+`col121` TINYBLOB,
+`col122` TIMESTAMP,
+`col123` BLOB,
+`col124` DATE,
+`col125` SMALLINT,
+`col126` ENUM ('test1','test2','test3'),
+`col127` MEDIUMBLOB,
+`col128` DOUBLE PRECISION,
+`col129` REAL,
+`col130` VARCHAR (159),
+`col131` MEDIUMBLOB,
+`col132` BIGINT,
+`col133` INT,
+`col134` SET ('test1','test2','test3'),
+`col135` CHAR (198),
+`col136` SET ('test1','test2','test3'),
+`col137` MEDIUMTEXT,
+`col138` SMALLINT,
+`col139` BLOB,
+`col140` LONGBLOB,
+KEY `idx0` (`col14`(139),`col24`(208),`col38`,`col35`),
+KEY `idx1` (`col48`,`col118`,`col29`(131),`col100`),
+KEY `idx2` (`col86`,`col67`,`col43`(175)),
+KEY `idx3` (`col19`),
+KEY `idx4` (`col40`(220),`col67`),
+KEY `idx5` (`col99`,`col56`),
+KEY `idx6` (`col68`,`col28`,`col137`(157)),
+KEY `idx7` (`col51`(160),`col99`,`col45`,`col39`(9)),
+KEY `idx8` (`col15`,`col52`,`col90`,`col94`),
+KEY `idx9` (`col24`(3),`col139`(248),`col108`(118),`col41`),
+KEY `idx10` (`col36`,`col92`,`col114`),
+KEY `idx11` (`col115`,`col9`(116)),
+KEY `idx12` (`col130`,`col93`,`col134`),
+KEY `idx13` (`col123`(65)),
+KEY `idx14` (`col44`(90),`col86`,`col119`),
+KEY `idx15` (`col69`),
+KEY `idx16` (`col132`,`col81`(118),`col18`),
+KEY `idx17` (`col24`(250),`col7`,`col92`,`col45`)
+)engine=innodb ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=1;
+
+# Creating a table with 199 columns and 1 indexes
+DROP TABLE IF EXISTS `table3`;
+--error ER_TOO_BIG_ROWSIZE
+CREATE TABLE IF NOT EXISTS `table3`
+(`col0` SMALLINT,
+`col1` SET ('test1','test2','test3'),
+`col2` TINYTEXT,
+`col3` DOUBLE,
+`col4` NUMERIC,
+`col5` DATE,
+`col6` BIGINT,
+`col7` DOUBLE,
+`col8` TEXT,
+`col9` INT,
+`col10` REAL,
+`col11` TINYINT,
+`col12` NUMERIC,
+`col13` NUMERIC,
+`col14` TIME,
+`col15` DOUBLE,
+`col16` REAL,
+`col17` MEDIUMBLOB,
+`col18` YEAR,
+`col19` TINYTEXT,
+`col20` YEAR,
+`col21` CHAR (250),
+`col22` TINYINT,
+`col23` TINYINT,
+`col24` SMALLINT,
+`col25` DATETIME,
+`col26` MEDIUMINT,
+`col27` LONGBLOB,
+`col28` VARCHAR (106),
+`col29` FLOAT,
+`col30` MEDIUMTEXT,
+`col31` TINYBLOB,
+`col32` BIGINT,
+`col33` YEAR,
+`col34` REAL,
+`col35` MEDIUMBLOB,
+`col36` LONGTEXT,
+`col37` LONGBLOB,
+`col38` BIGINT,
+`col39` FLOAT,
+`col40` TIME,
+`col41` DATETIME,
+`col42` BOOL,
+`col43` BIGINT,
+`col44` SMALLINT,
+`col45` TIME,
+`col46` DOUBLE PRECISION,
+`col47` TIME,
+`col48` TINYTEXT,
+`col49` DOUBLE PRECISION,
+`col50` BIGINT,
+`col51` NUMERIC,
+`col52` TINYBLOB,
+`col53` DATE,
+`col54` DECIMAL,
+`col55` SMALLINT,
+`col56` TINYTEXT,
+`col57` ENUM ('test1','test2','test3'),
+`col58` YEAR,
+`col59` TIME,
+`col60` TINYINT,
+`col61` DECIMAL,
+`col62` DOUBLE,
+`col63` DATE,
+`col64` LONGTEXT,
+`col65` DOUBLE,
+`col66` VARCHAR (88),
+`col67` MEDIUMTEXT,
+`col68` DATE,
+`col69` MEDIUMINT,
+`col70` DECIMAL,
+`col71` MEDIUMTEXT,
+`col72` LONGTEXT,
+`col73` REAL,
+`col74` DOUBLE,
+`col75` TIME,
+`col76` DATE,
+`col77` DECIMAL,
+`col78` MEDIUMBLOB,
+`col79` NUMERIC,
+`col80` BIGINT,
+`col81` YEAR,
+`col82` SMALLINT,
+`col83` MEDIUMINT,
+`col84` TINYINT,
+`col85` MEDIUMBLOB,
+`col86` TIME,
+`col87` MEDIUMBLOB,
+`col88` LONGTEXT,
+`col89` BOOL,
+`col90` BLOB,
+`col91` LONGBLOB,
+`col92` YEAR,
+`col93` BLOB,
+`col94` INT,
+`col95` TINYTEXT,
+`col96` TINYINT,
+`col97` DECIMAL,
+`col98` ENUM ('test1','test2','test3'),
+`col99` MEDIUMINT,
+`col100` TINYINT,
+`col101` MEDIUMBLOB,
+`col102` TINYINT,
+`col103` SET ('test1','test2','test3'),
+`col104` TIMESTAMP,
+`col105` TEXT,
+`col106` DATETIME,
+`col107` MEDIUMTEXT,
+`col108` CHAR (220),
+`col109` TIME,
+`col110` VARCHAR (131),
+`col111` DECIMAL,
+`col112` FLOAT,
+`col113` SMALLINT,
+`col114` BIGINT,
+`col115` LONGBLOB,
+`col116` SET ('test1','test2','test3'),
+`col117` ENUM ('test1','test2','test3'),
+`col118` BLOB,
+`col119` MEDIUMTEXT,
+`col120` SET ('test1','test2','test3'),
+`col121` DATETIME,
+`col122` FLOAT,
+`col123` VARCHAR (242),
+`col124` YEAR,
+`col125` MEDIUMBLOB,
+`col126` TIME,
+`col127` BOOL,
+`col128` TINYBLOB,
+`col129` DOUBLE,
+`col130` TINYINT,
+`col131` BIGINT,
+`col132` SMALLINT,
+`col133` INT,
+`col134` DOUBLE PRECISION,
+`col135` MEDIUMBLOB,
+`col136` SET ('test1','test2','test3'),
+`col137` TINYTEXT,
+`col138` DOUBLE PRECISION,
+`col139` NUMERIC,
+`col140` BLOB,
+`col141` SET ('test1','test2','test3'),
+`col142` INT,
+`col143` VARCHAR (26),
+`col144` BLOB,
+`col145` REAL,
+`col146` SET ('test1','test2','test3'),
+`col147` LONGBLOB,
+`col148` TEXT,
+`col149` BLOB,
+`col150` CHAR (189),
+`col151` LONGTEXT,
+`col152` INT,
+`col153` FLOAT,
+`col154` LONGTEXT,
+`col155` DATE,
+`col156` LONGBLOB,
+`col157` TINYBLOB,
+`col158` REAL,
+`col159` DATE,
+`col160` TIME,
+`col161` YEAR,
+`col162` DOUBLE,
+`col163` VARCHAR (90),
+`col164` FLOAT,
+`col165` NUMERIC,
+`col166` ENUM ('test1','test2','test3'),
+`col167` DOUBLE PRECISION,
+`col168` DOUBLE PRECISION,
+`col169` TINYBLOB,
+`col170` TIME,
+`col171` SMALLINT,
+`col172` TINYTEXT,
+`col173` SMALLINT,
+`col174` DOUBLE,
+`col175` VARCHAR (14),
+`col176` VARCHAR (90),
+`col177` REAL,
+`col178` MEDIUMINT,
+`col179` TINYBLOB,
+`col180` FLOAT,
+`col181` TIMESTAMP,
+`col182` REAL,
+`col183` DOUBLE PRECISION,
+`col184` BIGINT,
+`col185` INT,
+`col186` MEDIUMTEXT,
+`col187` TIME,
+`col188` FLOAT,
+`col189` TIME,
+`col190` INT,
+`col191` FLOAT,
+`col192` MEDIUMINT,
+`col193` TINYINT,
+`col194` MEDIUMTEXT,
+`col195` DATE,
+`col196` TIME,
+`col197` YEAR,
+`col198` CHAR (206),
+KEY `idx0` (`col39`,`col23`)
+)engine=innodb ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=1;
+
+# Creating a table with 133 columns and 16 indexes
+DROP TABLE IF EXISTS `table4`;
+--error ER_TOO_BIG_ROWSIZE
+CREATE TABLE IF NOT EXISTS `table4`
+(`col0` VARCHAR (60),
+`col1` NUMERIC,
+`col2` LONGTEXT,
+`col3` MEDIUMTEXT,
+`col4` LONGTEXT,
+`col5` LONGBLOB,
+`col6` LONGBLOB,
+`col7` DATETIME,
+`col8` TINYTEXT,
+`col9` BLOB,
+`col10` BOOL,
+`col11` BIGINT,
+`col12` TEXT,
+`col13` VARCHAR (213),
+`col14` TINYBLOB,
+`col15` BOOL,
+`col16` MEDIUMTEXT,
+`col17` DOUBLE,
+`col18` TEXT,
+`col19` BLOB,
+`col20` SET ('test1','test2','test3'),
+`col21` TINYINT,
+`col22` DATETIME,
+`col23` TINYINT,
+`col24` ENUM ('test1','test2','test3'),
+`col25` REAL,
+`col26` BOOL,
+`col27` FLOAT,
+`col28` LONGBLOB,
+`col29` DATETIME,
+`col30` FLOAT,
+`col31` SET ('test1','test2','test3'),
+`col32` LONGBLOB,
+`col33` NUMERIC,
+`col34` YEAR,
+`col35` VARCHAR (146),
+`col36` BIGINT,
+`col37` DATETIME,
+`col38` DATE,
+`col39` SET ('test1','test2','test3'),
+`col40` CHAR (112),
+`col41` FLOAT,
+`col42` YEAR,
+`col43` TIME,
+`col44` DOUBLE,
+`col45` NUMERIC,
+`col46` FLOAT,
+`col47` DECIMAL,
+`col48` BIGINT,
+`col49` DECIMAL,
+`col50` YEAR,
+`col51` MEDIUMTEXT,
+`col52` LONGBLOB,
+`col53` SET ('test1','test2','test3'),
+`col54` BLOB,
+`col55` FLOAT,
+`col56` REAL,
+`col57` REAL,
+`col58` TEXT,
+`col59` MEDIUMBLOB,
+`col60` INT,
+`col61` INT,
+`col62` DATE,
+`col63` TEXT,
+`col64` DATE,
+`col65` ENUM ('test1','test2','test3'),
+`col66` DOUBLE PRECISION,
+`col67` TINYTEXT,
+`col68` TINYBLOB,
+`col69` FLOAT,
+`col70` BLOB,
+`col71` DATETIME,
+`col72` DOUBLE,
+`col73` LONGTEXT,
+`col74` TIME,
+`col75` DATETIME,
+`col76` VARCHAR (122),
+`col77` MEDIUMTEXT,
+`col78` MEDIUMTEXT,
+`col79` BOOL,
+`col80` LONGTEXT,
+`col81` TINYTEXT,
+`col82` NUMERIC,
+`col83` DOUBLE PRECISION,
+`col84` DATE,
+`col85` YEAR,
+`col86` BLOB,
+`col87` TINYTEXT,
+`col88` DOUBLE PRECISION,
+`col89` MEDIUMINT,
+`col90` MEDIUMTEXT,
+`col91` NUMERIC,
+`col92` DATETIME,
+`col93` NUMERIC,
+`col94` SET ('test1','test2','test3'),
+`col95` TINYTEXT,
+`col96` SET ('test1','test2','test3'),
+`col97` YEAR,
+`col98` MEDIUMINT,
+`col99` TEXT,
+`col100` TEXT,
+`col101` TIME,
+`col102` VARCHAR (225),
+`col103` TINYTEXT,
+`col104` TEXT,
+`col105` MEDIUMTEXT,
+`col106` TINYINT,
+`col107` TEXT,
+`col108` LONGBLOB,
+`col109` LONGTEXT,
+`col110` TINYTEXT,
+`col111` CHAR (56),
+`col112` YEAR,
+`col113` ENUM ('test1','test2','test3'),
+`col114` TINYBLOB,
+`col115` DATETIME,
+`col116` DATE,
+`col117` TIME,
+`col118` MEDIUMTEXT,
+`col119` DOUBLE PRECISION,
+`col120` FLOAT,
+`col121` TIMESTAMP,
+`col122` MEDIUMINT,
+`col123` YEAR,
+`col124` DATE,
+`col125` TEXT,
+`col126` FLOAT,
+`col127` TINYTEXT,
+`col128` BOOL,
+`col129` NUMERIC,
+`col130` TIMESTAMP,
+`col131` INT,
+`col132` MEDIUMBLOB,
+KEY `idx0` (`col130`),
+KEY `idx1` (`col30`,`col55`,`col19`(31)),
+KEY `idx2` (`col104`(186)),
+KEY `idx3` (`col131`),
+KEY `idx4` (`col64`,`col93`,`col2`(11)),
+KEY `idx5` (`col34`,`col121`,`col22`),
+KEY `idx6` (`col33`,`col55`,`col83`),
+KEY `idx7` (`col17`,`col87`(245),`col99`(17)),
+KEY `idx8` (`col65`,`col120`),
+KEY `idx9` (`col82`),
+KEY `idx10` (`col9`(72)),
+KEY `idx11` (`col88`),
+KEY `idx12` (`col128`,`col9`(200),`col71`,`col66`),
+KEY `idx13` (`col77`(126)),
+KEY `idx14` (`col105`(26),`col13`,`col117`),
+KEY `idx15` (`col4`(246),`col130`,`col115`,`col3`(141))
+)engine=innodb ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=1;
+
+# Creating a table with 176 columns and 13 indexes
+DROP TABLE IF EXISTS `table5`;
+--error ER_TOO_BIG_ROWSIZE
+CREATE TABLE IF NOT EXISTS `table5`
+(`col0` MEDIUMTEXT,
+`col1` VARCHAR (90),
+`col2` TINYTEXT,
+`col3` TIME,
+`col4` BOOL,
+`col5` TINYTEXT,
+`col6` BOOL,
+`col7` TIMESTAMP,
+`col8` TINYBLOB,
+`col9` TINYINT,
+`col10` YEAR,
+`col11` SET ('test1','test2','test3'),
+`col12` TEXT,
+`col13` CHAR (248),
+`col14` BIGINT,
+`col15` TEXT,
+`col16` TINYINT,
+`col17` NUMERIC,
+`col18` SET ('test1','test2','test3'),
+`col19` LONGBLOB,
+`col20` FLOAT,
+`col21` INT,
+`col22` TEXT,
+`col23` BOOL,
+`col24` DECIMAL,
+`col25` DOUBLE PRECISION,
+`col26` FLOAT,
+`col27` TINYBLOB,
+`col28` NUMERIC,
+`col29` MEDIUMBLOB,
+`col30` DATE,
+`col31` LONGTEXT,
+`col32` DATE,
+`col33` FLOAT,
+`col34` BIGINT,
+`col35` TINYTEXT,
+`col36` MEDIUMTEXT,
+`col37` TIME,
+`col38` INT,
+`col39` TINYINT,
+`col40` SET ('test1','test2','test3'),
+`col41` CHAR (130),
+`col42` SMALLINT,
+`col43` INT,
+`col44` MEDIUMTEXT,
+`col45` VARCHAR (126),
+`col46` INT,
+`col47` DOUBLE PRECISION,
+`col48` BIGINT,
+`col49` MEDIUMTEXT,
+`col50` TINYBLOB,
+`col51` MEDIUMINT,
+`col52` TEXT,
+`col53` VARCHAR (208),
+`col54` VARCHAR (207),
+`col55` NUMERIC,
+`col56` DATETIME,
+`col57` ENUM ('test1','test2','test3'),
+`col58` NUMERIC,
+`col59` TINYBLOB,
+`col60` VARCHAR (73),
+`col61` MEDIUMTEXT,
+`col62` TINYBLOB,
+`col63` DATETIME,
+`col64` NUMERIC,
+`col65` MEDIUMINT,
+`col66` DATETIME,
+`col67` NUMERIC,
+`col68` TINYINT,
+`col69` VARCHAR (58),
+`col70` DECIMAL,
+`col71` MEDIUMTEXT,
+`col72` DATE,
+`col73` TIME,
+`col74` DOUBLE PRECISION,
+`col75` DECIMAL,
+`col76` MEDIUMBLOB,
+`col77` REAL,
+`col78` YEAR,
+`col79` YEAR,
+`col80` LONGBLOB,
+`col81` BLOB,
+`col82` BIGINT,
+`col83` ENUM ('test1','test2','test3'),
+`col84` NUMERIC,
+`col85` SET ('test1','test2','test3'),
+`col86` MEDIUMTEXT,
+`col87` LONGBLOB,
+`col88` TIME,
+`col89` ENUM ('test1','test2','test3'),
+`col90` DECIMAL,
+`col91` FLOAT,
+`col92` DATETIME,
+`col93` TINYTEXT,
+`col94` TIMESTAMP,
+`col95` TIMESTAMP,
+`col96` TEXT,
+`col97` REAL,
+`col98` VARCHAR (198),
+`col99` TIME,
+`col100` TINYINT,
+`col101` BIGINT,
+`col102` LONGBLOB,
+`col103` LONGBLOB,
+`col104` MEDIUMINT,
+`col105` MEDIUMTEXT,
+`col106` TIMESTAMP,
+`col107` SMALLINT,
+`col108` NUMERIC,
+`col109` DECIMAL,
+`col110` FLOAT,
+`col111` DECIMAL,
+`col112` REAL,
+`col113` TINYTEXT,
+`col114` FLOAT,
+`col115` VARCHAR (7),
+`col116` LONGTEXT,
+`col117` DATE,
+`col118` BIGINT,
+`col119` TEXT,
+`col120` BIGINT,
+`col121` BLOB,
+`col122` CHAR (110),
+`col123` NUMERIC,
+`col124` MEDIUMBLOB,
+`col125` NUMERIC,
+`col126` NUMERIC,
+`col127` BOOL,
+`col128` TIME,
+`col129` TINYBLOB,
+`col130` TINYBLOB,
+`col131` DATE,
+`col132` INT,
+`col133` VARCHAR (123),
+`col134` CHAR (238),
+`col135` VARCHAR (225),
+`col136` LONGTEXT,
+`col137` LONGBLOB,
+`col138` REAL,
+`col139` TINYBLOB,
+`col140` DATETIME,
+`col141` TINYTEXT,
+`col142` LONGBLOB,
+`col143` BIGINT,
+`col144` VARCHAR (236),
+`col145` TEXT,
+`col146` YEAR,
+`col147` DECIMAL,
+`col148` TEXT,
+`col149` MEDIUMBLOB,
+`col150` TINYINT,
+`col151` BOOL,
+`col152` VARCHAR (72),
+`col153` INT,
+`col154` VARCHAR (165),
+`col155` TINYINT,
+`col156` MEDIUMTEXT,
+`col157` DOUBLE PRECISION,
+`col158` TIME,
+`col159` MEDIUMBLOB,
+`col160` LONGBLOB,
+`col161` DATETIME,
+`col162` DOUBLE PRECISION,
+`col163` BLOB,
+`col164` ENUM ('test1','test2','test3'),
+`col165` TIMESTAMP,
+`col166` DATE,
+`col167` TINYBLOB,
+`col168` TINYBLOB,
+`col169` LONGBLOB,
+`col170` DATETIME,
+`col171` BIGINT,
+`col172` VARCHAR (30),
+`col173` LONGTEXT,
+`col174` TIME,
+`col175` FLOAT,
+KEY `idx0` (`col16`,`col156`(139),`col97`,`col120`),
+KEY `idx1` (`col24`,`col0`(108)),
+KEY `idx2` (`col117`,`col173`(34),`col132`,`col82`),
+KEY `idx3` (`col2`(86)),
+KEY `idx4` (`col2`(43)),
+KEY `idx5` (`col83`,`col35`(87),`col111`),
+KEY `idx6` (`col6`,`col134`,`col92`),
+KEY `idx7` (`col56`),
+KEY `idx8` (`col30`,`col53`,`col129`(66)),
+KEY `idx9` (`col53`,`col113`(211),`col32`,`col15`(75)),
+KEY `idx10` (`col34`),
+KEY `idx11` (`col126`),
+KEY `idx12` (`col24`)
+)engine=innodb ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=1;
+
+# Creating a table with 179 columns and 46 indexes
+DROP TABLE IF EXISTS `table6`;
+-- error ER_TOO_BIG_ROWSIZE
+--error ER_TOO_BIG_ROWSIZE
+CREATE TABLE IF NOT EXISTS `table6`
+(`col0` ENUM ('test1','test2','test3'),
+`col1` MEDIUMBLOB,
+`col2` MEDIUMBLOB,
+`col3` DATETIME,
+`col4` DATE,
+`col5` YEAR,
+`col6` REAL,
+`col7` NUMERIC,
+`col8` MEDIUMBLOB,
+`col9` TEXT,
+`col10` TIMESTAMP,
+`col11` DOUBLE,
+`col12` DOUBLE,
+`col13` SMALLINT,
+`col14` TIMESTAMP,
+`col15` DECIMAL,
+`col16` DATE,
+`col17` TEXT,
+`col18` LONGBLOB,
+`col19` BIGINT,
+`col20` FLOAT,
+`col21` DATETIME,
+`col22` TINYINT,
+`col23` MEDIUMBLOB,
+`col24` SET ('test1','test2','test3'),
+`col25` TIME,
+`col26` TEXT,
+`col27` LONGTEXT,
+`col28` BIGINT,
+`col29` REAL,
+`col30` YEAR,
+`col31` MEDIUMBLOB,
+`col32` MEDIUMINT,
+`col33` FLOAT,
+`col34` TEXT,
+`col35` DATE,
+`col36` TIMESTAMP,
+`col37` REAL,
+`col38` BLOB,
+`col39` BLOB,
+`col40` BLOB,
+`col41` TINYBLOB,
+`col42` INT,
+`col43` TINYINT,
+`col44` REAL,
+`col45` BIGINT,
+`col46` TIMESTAMP,
+`col47` BLOB,
+`col48` ENUM ('test1','test2','test3'),
+`col49` BOOL,
+`col50` CHAR (109),
+`col51` DOUBLE,
+`col52` DOUBLE PRECISION,
+`col53` ENUM ('test1','test2','test3'),
+`col54` FLOAT,
+`col55` DOUBLE PRECISION,
+`col56` CHAR (166),
+`col57` TEXT,
+`col58` TIME,
+`col59` DECIMAL,
+`col60` TEXT,
+`col61` ENUM ('test1','test2','test3'),
+`col62` LONGTEXT,
+`col63` YEAR,
+`col64` DOUBLE,
+`col65` CHAR (87),
+`col66` DATE,
+`col67` BOOL,
+`col68` MEDIUMBLOB,
+`col69` DATETIME,
+`col70` DECIMAL,
+`col71` TIME,
+`col72` REAL,
+`col73` LONGTEXT,
+`col74` BLOB,
+`col75` REAL,
+`col76` INT,
+`col77` INT,
+`col78` FLOAT,
+`col79` DOUBLE,
+`col80` MEDIUMINT,
+`col81` ENUM ('test1','test2','test3'),
+`col82` VARCHAR (221),
+`col83` BIGINT,
+`col84` TINYINT,
+`col85` BIGINT,
+`col86` FLOAT,
+`col87` MEDIUMBLOB,
+`col88` CHAR (126),
+`col89` MEDIUMBLOB,
+`col90` DATETIME,
+`col91` TINYINT,
+`col92` DOUBLE,
+`col93` NUMERIC,
+`col94` DATE,
+`col95` BLOB,
+`col96` DATETIME,
+`col97` TIME,
+`col98` LONGBLOB,
+`col99` INT,
+`col100` SET ('test1','test2','test3'),
+`col101` TINYBLOB,
+`col102` INT,
+`col103` MEDIUMBLOB,
+`col104` MEDIUMTEXT,
+`col105` FLOAT,
+`col106` TINYBLOB,
+`col107` VARCHAR (26),
+`col108` TINYINT,
+`col109` TIME,
+`col110` TINYBLOB,
+`col111` LONGBLOB,
+`col112` TINYTEXT,
+`col113` FLOAT,
+`col114` TINYINT,
+`col115` NUMERIC,
+`col116` TIME,
+`col117` SET ('test1','test2','test3'),
+`col118` DATE,
+`col119` SMALLINT,
+`col120` BLOB,
+`col121` TINYTEXT,
+`col122` REAL,
+`col123` YEAR,
+`col124` REAL,
+`col125` BOOL,
+`col126` BLOB,
+`col127` REAL,
+`col128` MEDIUMBLOB,
+`col129` TIMESTAMP,
+`col130` LONGBLOB,
+`col131` MEDIUMBLOB,
+`col132` YEAR,
+`col133` YEAR,
+`col134` INT,
+`col135` MEDIUMINT,
+`col136` MEDIUMINT,
+`col137` TINYTEXT,
+`col138` TINYBLOB,
+`col139` BLOB,
+`col140` SET ('test1','test2','test3'),
+`col141` ENUM ('test1','test2','test3'),
+`col142` ENUM ('test1','test2','test3'),
+`col143` TINYTEXT,
+`col144` DATETIME,
+`col145` TEXT,
+`col146` DOUBLE PRECISION,
+`col147` DECIMAL,
+`col148` MEDIUMTEXT,
+`col149` TINYTEXT,
+`col150` SET ('test1','test2','test3'),
+`col151` MEDIUMTEXT,
+`col152` CHAR (126),
+`col153` DOUBLE,
+`col154` CHAR (243),
+`col155` SET ('test1','test2','test3'),
+`col156` SET ('test1','test2','test3'),
+`col157` DATETIME,
+`col158` DOUBLE,
+`col159` NUMERIC,
+`col160` DECIMAL,
+`col161` FLOAT,
+`col162` LONGBLOB,
+`col163` LONGTEXT,
+`col164` INT,
+`col165` TIME,
+`col166` CHAR (27),
+`col167` VARCHAR (63),
+`col168` TEXT,
+`col169` TINYBLOB,
+`col170` TINYBLOB,
+`col171` ENUM ('test1','test2','test3'),
+`col172` INT,
+`col173` TIME,
+`col174` DECIMAL,
+`col175` DOUBLE,
+`col176` MEDIUMBLOB,
+`col177` LONGBLOB,
+`col178` CHAR (43),
+KEY `idx0` (`col131`(219)),
+KEY `idx1` (`col67`,`col122`,`col59`,`col87`(33)),
+KEY `idx2` (`col83`,`col42`,`col57`(152)),
+KEY `idx3` (`col106`(124)),
+KEY `idx4` (`col173`,`col80`,`col165`,`col89`(78)),
+KEY `idx5` (`col174`,`col145`(108),`col23`(228),`col141`),
+KEY `idx6` (`col157`,`col140`),
+KEY `idx7` (`col130`(188),`col15`),
+KEY `idx8` (`col52`),
+KEY `idx9` (`col144`),
+KEY `idx10` (`col155`),
+KEY `idx11` (`col62`(230),`col1`(109)),
+KEY `idx12` (`col151`(24),`col95`(85)),
+KEY `idx13` (`col114`),
+KEY `idx14` (`col42`,`col98`(56),`col146`),
+KEY `idx15` (`col147`,`col39`(254),`col35`),
+KEY `idx16` (`col79`),
+KEY `idx17` (`col65`),
+KEY `idx18` (`col149`(165),`col168`(119),`col32`,`col117`),
+KEY `idx19` (`col64`),
+KEY `idx20` (`col93`),
+KEY `idx21` (`col64`,`col113`,`col104`(182)),
+KEY `idx22` (`col52`,`col111`(189)),
+KEY `idx23` (`col45`),
+KEY `idx24` (`col154`,`col107`,`col110`(159)),
+KEY `idx25` (`col149`(1),`col87`(131)),
+KEY `idx26` (`col58`,`col115`,`col63`),
+KEY `idx27` (`col95`(9),`col0`,`col87`(113)),
+KEY `idx28` (`col92`,`col130`(1)),
+KEY `idx29` (`col151`(129),`col137`(254),`col13`),
+KEY `idx30` (`col49`),
+KEY `idx31` (`col28`),
+KEY `idx32` (`col83`,`col146`),
+KEY `idx33` (`col155`,`col90`,`col17`(245)),
+KEY `idx34` (`col174`,`col169`(44),`col107`),
+KEY `idx35` (`col113`),
+KEY `idx36` (`col52`),
+KEY `idx37` (`col16`,`col120`(190)),
+KEY `idx38` (`col28`),
+KEY `idx39` (`col131`(165)),
+KEY `idx40` (`col135`,`col26`(86)),
+KEY `idx41` (`col69`,`col94`),
+KEY `idx42` (`col105`,`col151`(38),`col97`),
+KEY `idx43` (`col88`),
+KEY `idx44` (`col176`(100),`col42`,`col73`(189),`col94`),
+KEY `idx45` (`col2`(27),`col27`(116))
+)engine=innodb ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=1;
+
+DROP TABLE IF EXISTS table0;
+DROP TABLE IF EXISTS table1;
+DROP TABLE IF EXISTS table2;
+DROP TABLE IF EXISTS table3;
+DROP TABLE IF EXISTS table4;
+DROP TABLE IF EXISTS table5;
+DROP TABLE IF EXISTS table6;
+
+SET GLOBAL innodb_file_per_table=DEFAULT;
+SET GLOBAL innodb_file_format='Antelope';
+SET GLOBAL innodb_file_format_check='Antelope';
diff --git a/mysql-test/suite/innodb/t/innodb_bug36172.test b/mysql-test/suite/innodb/t/innodb_bug36172.test
new file mode 100644
index 00000000000..9e1308d5fc3
--- /dev/null
+++ b/mysql-test/suite/innodb/t/innodb_bug36172.test
@@ -0,0 +1,31 @@
+#
+# Test case for bug 36172
+#
+
+-- source include/not_embedded.inc
+-- source include/have_innodb.inc
+-- source suite/innodb/include/have_innodb_plugin.inc
+
+SET storage_engine=InnoDB;
+
+# we do not really care about what gets printed, we are only
+# interested in getting success or failure according to our
+# expectations
+
+-- disable_query_log
+-- disable_result_log
+
+SET GLOBAL innodb_file_format='Barracuda';
+SET GLOBAL innodb_file_per_table=on;
+
+DROP TABLE IF EXISTS `table0`;
+CREATE TABLE `table0` ( `col0` tinyint(1) DEFAULT NULL, `col1` tinyint(1) DEFAULT NULL, `col2` tinyint(4) DEFAULT NULL, `col3` date DEFAULT NULL, `col4` time DEFAULT NULL, `col5` set('test1','test2','test3') DEFAULT NULL, `col6` time DEFAULT NULL, `col7` text, `col8` decimal(10,0) DEFAULT NULL, `col9` set('test1','test2','test3') DEFAULT NULL, `col10` float DEFAULT NULL, `col11` double DEFAULT NULL, `col12` enum('test1','test2','test3') DEFAULT NULL, `col13` tinyblob, `col14` year(4) DEFAULT NULL, `col15` set('test1','test2','test3') DEFAULT NULL, `col16` decimal(10,0) DEFAULT NULL, `col17` decimal(10,0) DEFAULT NULL, `col18` blob, `col19` datetime DEFAULT NULL, `col20` double DEFAULT NULL, `col21` decimal(10,0) DEFAULT NULL, `col22` datetime DEFAULT NULL, `col23` decimal(10,0) DEFAULT NULL, `col24` decimal(10,0) DEFAULT NULL, `col25` longtext, `col26` tinyblob, `col27` time DEFAULT NULL, `col28` tinyblob, `col29` enum('test1','test2','test3') DEFAULT NULL, `col30` smallint(6) DEFAULT NULL, `col31` double DEFAULT NULL, `col32` float DEFAULT NULL, `col33` char(175) DEFAULT NULL, `col34` tinytext, `col35` tinytext, `col36` tinyblob, `col37` tinyblob, `col38` tinytext, `col39` mediumblob, `col40` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, `col41` double DEFAULT NULL, `col42` smallint(6) DEFAULT NULL, `col43` longblob, `col44` varchar(80) DEFAULT NULL, `col45` mediumtext, `col46` decimal(10,0) DEFAULT NULL, `col47` bigint(20) DEFAULT NULL, `col48` date DEFAULT NULL, `col49` tinyblob, `col50` date DEFAULT NULL, `col51` tinyint(1) DEFAULT NULL, `col52` mediumint(9) DEFAULT NULL, `col53` float DEFAULT NULL, `col54` tinyblob, `col55` longtext, `col56` smallint(6) DEFAULT NULL, `col57` enum('test1','test2','test3') DEFAULT NULL, `col58` datetime DEFAULT NULL, `col59` mediumtext, `col60` varchar(232) DEFAULT NULL, `col61` decimal(10,0) DEFAULT NULL, `col62` year(4) DEFAULT NULL, `col63` smallint(6) DEFAULT NULL, `col64` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', `col65` blob, `col66` longblob, `col67` int(11) DEFAULT NULL, `col68` longtext, `col69` enum('test1','test2','test3') DEFAULT NULL, `col70` int(11) DEFAULT NULL, `col71` time DEFAULT NULL, `col72` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', `col73` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', `col74` varchar(170) DEFAULT NULL, `col75` set('test1','test2','test3') DEFAULT NULL, `col76` tinyblob, `col77` bigint(20) DEFAULT NULL, `col78` decimal(10,0) DEFAULT NULL, `col79` datetime DEFAULT NULL, `col80` year(4) DEFAULT NULL, `col81` decimal(10,0) DEFAULT NULL, `col82` longblob, `col83` text, `col84` char(83) DEFAULT NULL, `col85` decimal(10,0) DEFAULT NULL, `col86` float DEFAULT NULL, `col87` int(11) DEFAULT NULL, `col88` varchar(145) DEFAULT NULL, `col89` date DEFAULT NULL, `col90` decimal(10,0) DEFAULT NULL, `col91` decimal(10,0) DEFAULT NULL, `col92` mediumblob, `col93` time DEFAULT NULL, KEY `idx0` (`col69`,`col90`,`col8`), KEY `idx1` (`col60`), KEY `idx2` (`col60`,`col70`,`col74`), KEY `idx3` (`col22`,`col32`,`col72`,`col30`), KEY `idx4` (`col29`), KEY `idx5` (`col19`,`col45`(143)), KEY `idx6` (`col46`,`col48`,`col5`,`col39`(118)), KEY `idx7` (`col48`,`col61`), KEY `idx8` (`col93`), KEY `idx9` (`col31`), KEY `idx10` (`col30`,`col21`), KEY `idx11` (`col67`), KEY `idx12` (`col44`,`col6`,`col8`,`col38`(226)), KEY `idx13` (`col71`,`col41`,`col15`,`col49`(88)), KEY `idx14` (`col78`), KEY `idx15` (`col63`,`col67`,`col64`), KEY `idx16` (`col17`,`col86`), KEY `idx17` (`col77`,`col56`,`col10`,`col55`(24)), KEY `idx18` (`col62`), KEY `idx19` (`col31`,`col57`,`col56`,`col53`), KEY `idx20` (`col46`), KEY `idx21` (`col83`(54)), KEY `idx22` (`col51`,`col7`(120)), KEY `idx23` (`col7`(163),`col31`,`col71`,`col14`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=2;
+insert ignore into `table0` set `col23` = 7887371.5084383683, `col24` = 4293854615.6906948000, `col25` = 'vitalist', `col26` = 'widespread', `col27` = '3570490', `col28` = 'habitual', `col30` = -5471, `col31` = 4286985783.6771750000, `col32` = 6354540.9826654866, `col33` = 'defoliation', `col34` = 'logarithms', `col35` = 'tegument\'s', `col36` = 'scouting\'s', `col37` = 'intermittency', `col38` = 'elongates', `col39` = 'prophecies', `col40` = '20560103035939', `col41` = 4292809130.0544143000, `col42` = 22057, `col43` = 'Hess\'s', `col44` = 'bandstand', `col45` = 'phenylketonuria', `col46` = 6338767.4018677324, `col47` = 5310247, `col48` = '12592418', `col49` = 'churchman\'s', `col50` = '32226125', `col51` = -58, `col52` = -6207968, `col53` = 1244839.3255104220, `col54` = 'robotized', `col55` = 'monotonous', `col56` = -26909, `col58` = '20720107023550', `col59` = 'suggestiveness\'s', `col60` = 'gemology', `col61` = 4287800670.2229986000, `col62` = '1944', `col63` = -16827, `col64` = '20700107212324', `col65` = 'Nicolais', `col66` = 'apteryx', `col67` = 6935317, `col68` = 'stroganoff', `col70` = 3316430, `col71` = '3277608', `col72` = '19300511045918', `col73` = '20421201003327', `col74` = 'attenuant', `col75` = '15173', `col76` = 'upstroke\'s', `col77` = 8118987, `col78` = 6791516.2735374002, `col79` = '20780701144624', `col80` = '2134', `col81` = 4290682351.3127537000, `col82` = 'unexplainably', `col83` = 'Storm', `col84` = 'Greyso\'s', `col85` = 4289119212.4306774000, `col86` = 7617575.8796655172, `col87` = -6325335, `col88` = 'fondue\'s', `col89` = '40608940', `col90` = 1659421.8093508712, `col91` = 8346904.6584368423, `col92` = 'reloads', `col93` = '5188366';
+CHECK TABLE table0 EXTENDED;
+INSERT IGNORE INTO `table0` SET `col19` = '19940127002709', `col20` = 2383927.9055146948, `col21` = 4293243420.5621204000, `col22` = '20511211123705', `col23` = 4289899778.6573381000, `col24` = 4293449279.0540481000, `col25` = 'emphysemic', `col26` = 'dentally', `col27` = '2347406', `col28` = 'eruct', `col30` = 1222, `col31` = 4294372994.9941406000, `col32` = 4291385574.1173744000, `col33` = 'borrowing\'s', `col34` = 'septics', `col35` = 'ratter\'s', `col36` = 'Kaye', `col37` = 'Florentia', `col38` = 'allium', `col39` = 'barkeep', `col40` = '19510407003441', `col41` = 4293559200.4215522000, `col42` = 22482, `col43` = 'decussate', `col44` = 'Brom\'s', `col45` = 'violated', `col46` = 4925506.4635456400, `col47` = 930549, `col48` = '51296066', `col49` = 'voluminously', `col50` = '29306676', `col51` = -88, `col52` = -2153690, `col53` = 4290250202.1464887000, `col54` = 'expropriation', `col55` = 'Aberdeen\'s', `col56` = 20343, `col58` = '19640415171532', `col59` = 'extern', `col60` = 'Ubana', `col61` = 4290487961.8539081000, `col62` = '2147', `col63` = -24271, `col64` = '20750801194548', `col65` = 'Cunaxa\'s', `col66` = 'pasticcio', `col67` = 2795817, `col68` = 'Indore\'s', `col70` = 6864127, `col71` = '1817832', `col72` = '20540506114211', `col73` = '20040101012300', `col74` = 'rationalized', `col75` = '45522', `col76` = 'indene', `col77` = -6964559, `col78` = 4247535.5266884370, `col79` = '20720416124357', `col80` = '2143', `col81` = 4292060102.4466386000, `col82` = 'striving', `col83` = 'boneblack\'s', `col84` = 'redolent', `col85` = 6489697.9009369183, `col86` = 4287473465.9731131000, `col87` = 7726015, `col88` = 'perplexed', `col89` = '17153791', `col90` = 5478587.1108127078, `col91` = 4287091404.7004304000, `col92` = 'Boulez\'s', `col93` = '2931278';
+CHECK TABLE table0 EXTENDED;
+DROP TABLE table0;
+
+SET GLOBAL innodb_file_per_table=DEFAULT;
+SET GLOBAL innodb_file_format='Antelope';
+SET GLOBAL innodb_file_format_check='Antelope';
diff --git a/mysql-test/suite/innodb/t/innodb_bug40360.test b/mysql-test/suite/innodb/t/innodb_bug40360.test
new file mode 100644
index 00000000000..e88837aab4f
--- /dev/null
+++ b/mysql-test/suite/innodb/t/innodb_bug40360.test
@@ -0,0 +1,16 @@
+#
+# Make sure http://bugs.mysql.com/40360 remains fixed.
+#
+
+-- source include/not_embedded.inc
+-- source include/have_innodb.inc
+
+SET TX_ISOLATION='READ-COMMITTED';
+
+# This is the default since MySQL 5.1.29 SET BINLOG_FORMAT='STATEMENT';
+
+CREATE TABLE bug40360 (a INT) engine=innodb;
+
+INSERT INTO bug40360 VALUES (1);
+
+DROP TABLE bug40360;
diff --git a/mysql-test/suite/innodb/t/innodb_bug41904.test b/mysql-test/suite/innodb/t/innodb_bug41904.test
new file mode 100644
index 00000000000..365c5229adc
--- /dev/null
+++ b/mysql-test/suite/innodb/t/innodb_bug41904.test
@@ -0,0 +1,14 @@
+#
+# Make sure http://bugs.mysql.com/41904 remains fixed.
+#
+
+-- source include/not_embedded.inc
+-- source include/have_innodb.inc
+
+CREATE TABLE bug41904 (id INT PRIMARY KEY, uniquecol CHAR(15)) ENGINE=InnoDB;
+
+INSERT INTO bug41904 VALUES (1,NULL), (2,NULL);
+
+CREATE UNIQUE INDEX ui ON bug41904 (uniquecol);
+
+DROP TABLE bug41904;
diff --git a/mysql-test/suite/innodb/t/innodb_bug44032.test b/mysql-test/suite/innodb/t/innodb_bug44032.test
new file mode 100644
index 00000000000..a963cb8b68f
--- /dev/null
+++ b/mysql-test/suite/innodb/t/innodb_bug44032.test
@@ -0,0 +1,13 @@
+# Bug44032 no update-in-place of UTF-8 columns in ROW_FORMAT=REDUNDANT
+# (btr_cur_update_in_place not invoked when updating from/to NULL;
+# the update is performed by delete and insert instead)
+
+-- source include/have_innodb.inc
+
+CREATE TABLE bug44032(c CHAR(3) CHARACTER SET UTF8) ROW_FORMAT=REDUNDANT
+ENGINE=InnoDB;
+INSERT INTO bug44032 VALUES('abc'),(0xEFBCA4EFBCA4EFBCA4);
+UPDATE bug44032 SET c='DDD' WHERE c=0xEFBCA4EFBCA4EFBCA4;
+UPDATE bug44032 SET c=NULL WHERE c='DDD';
+UPDATE bug44032 SET c='DDD' WHERE c IS NULL;
+DROP TABLE bug44032;
diff --git a/mysql-test/suite/innodb/t/innodb_file_format.test b/mysql-test/suite/innodb/t/innodb_file_format.test
new file mode 100644
index 00000000000..293e87a413e
--- /dev/null
+++ b/mysql-test/suite/innodb/t/innodb_file_format.test
@@ -0,0 +1,41 @@
+-- source include/have_innodb.inc
+-- source suite/innodb/include/have_innodb_plugin.inc
+
+let $format=`select @@innodb_file_format`;
+let $innodb_file_format_check_orig=`select @@innodb_file_format_check`;
+
+select @@innodb_file_format;
+select @@innodb_file_format_check;
+set global innodb_file_format=antelope;
+set global innodb_file_format=barracuda;
+--error ER_WRONG_ARGUMENTS
+set global innodb_file_format=cheetah;
+select @@innodb_file_format;
+set global innodb_file_format=default;
+select @@innodb_file_format;
+--error ER_WRONG_ARGUMENTS
+set global innodb_file_format=on;
+--error ER_WRONG_ARGUMENTS
+set global innodb_file_format=off;
+select @@innodb_file_format;
+set global innodb_file_format_check=antelope;
+set global innodb_file_format_check=barracuda;
+--error ER_WRONG_ARGUMENTS
+set global innodb_file_format_check=cheetah;
+select @@innodb_file_format_check;
+set global innodb_file_format_check=default;
+select @@innodb_file_format_check;
+--error ER_WRONG_ARGUMENTS
+set global innodb_file_format=on;
+--error ER_WRONG_ARGUMENTS
+set global innodb_file_format=off;
+select @@innodb_file_format_check;
+
+#
+# restore environment to the state it was before this test execution
+#
+
+-- disable_query_log
+eval set global innodb_file_format=$format;
+eval set global innodb_file_format_check=$innodb_file_format_check_orig;
+-- enable_query_log
diff --git a/mysql-test/suite/innodb/t/innodb_information_schema.test b/mysql-test/suite/innodb/t/innodb_information_schema.test
new file mode 100644
index 00000000000..df65139448c
--- /dev/null
+++ b/mysql-test/suite/innodb/t/innodb_information_schema.test
@@ -0,0 +1,146 @@
+#
+# Test that user data is correctly "visualized" in
+# INFORMATION_SCHEMA.innodb_locks.lock_data
+#
+
+-- source include/have_innodb.inc
+-- source suite/innodb/include/have_innodb_plugin.inc
+
+-- disable_query_log
+-- disable_result_log
+
+SET storage_engine=InnoDB;
+
+-- disable_warnings
+DROP TABLE IF EXISTS t_min, t_max;
+-- enable_warnings
+
+let $table_def =
+(
+ c01 TINYINT,
+ c02 TINYINT UNSIGNED,
+ c03 SMALLINT,
+ c04 SMALLINT UNSIGNED,
+ c05 MEDIUMINT,
+ c06 MEDIUMINT UNSIGNED,
+ c07 INT,
+ c08 INT UNSIGNED,
+ c09 BIGINT,
+ c10 BIGINT UNSIGNED,
+ PRIMARY KEY(c01, c02, c03, c04, c05, c06, c07, c08, c09, c10)
+);
+
+-- eval CREATE TABLE t_min $table_def;
+INSERT INTO t_min VALUES
+(-128, 0,
+ -32768, 0,
+ -8388608, 0,
+ -2147483648, 0,
+ -9223372036854775808, 0);
+
+-- eval CREATE TABLE t_max $table_def;
+INSERT INTO t_max VALUES
+(127, 255,
+ 32767, 65535,
+ 8388607, 16777215,
+ 2147483647, 4294967295,
+ 9223372036854775807, 18446744073709551615);
+
+CREATE TABLE ```t'\"_str` (
+ c1 VARCHAR(32),
+ c2 VARCHAR(32),
+ c3 VARCHAR(32),
+ c4 VARCHAR(32),
+ c5 VARCHAR(32),
+ c6 VARCHAR(32),
+ c7 VARCHAR(32),
+ PRIMARY KEY(c1, c2, c3, c4, c5, c6, c7)
+);
+INSERT INTO ```t'\"_str` VALUES
+('1', 'abc', '''abc', 'abc''', 'a''bc', 'a''bc''', '''abc''''');
+INSERT INTO ```t'\"_str` VALUES
+('2', 'abc', '"abc', 'abc"', 'a"bc', 'a"bc"', '"abc""');
+INSERT INTO ```t'\"_str` VALUES
+('3', 'abc', '\\abc', 'abc\\', 'a\\bc', 'a\\bc\\', '\\abc\\\\');
+INSERT INTO ```t'\"_str` VALUES
+('4', 'abc', 0x00616263, 0x61626300, 0x61006263, 0x6100626300, 0x610062630000);
+
+-- connect (con_lock,localhost,root,,)
+-- connect (con_min_trylock,localhost,root,,)
+-- connect (con_max_trylock,localhost,root,,)
+-- connect (con_str_insert_supremum,localhost,root,,)
+-- connect (con_str_lock_row1,localhost,root,,)
+-- connect (con_str_lock_row2,localhost,root,,)
+-- connect (con_str_lock_row3,localhost,root,,)
+-- connect (con_str_lock_row4,localhost,root,,)
+-- connect (con_verify_innodb_locks,localhost,root,,)
+
+-- connection con_lock
+SET autocommit=0;
+SELECT * FROM t_min FOR UPDATE;
+SELECT * FROM t_max FOR UPDATE;
+SELECT * FROM ```t'\"_str` FOR UPDATE;
+
+-- connection con_min_trylock
+-- send
+SELECT * FROM t_min FOR UPDATE;
+
+-- connection con_max_trylock
+-- send
+SELECT * FROM t_max FOR UPDATE;
+
+-- connection con_str_insert_supremum
+-- send
+INSERT INTO ```t'\"_str` VALUES
+('z', 'z', 'z', 'z', 'z', 'z', 'z');
+
+-- connection con_str_lock_row1
+-- send
+SELECT * FROM ```t'\"_str` WHERE c1 = '1' FOR UPDATE;
+
+-- connection con_str_lock_row2
+-- send
+SELECT * FROM ```t'\"_str` WHERE c1 = '2' FOR UPDATE;
+
+-- connection con_str_lock_row3
+-- send
+SELECT * FROM ```t'\"_str` WHERE c1 = '3' FOR UPDATE;
+
+-- connection con_str_lock_row4
+-- send
+SELECT * FROM ```t'\"_str` WHERE c1 = '4' FOR UPDATE;
+
+# Give time to the above 2 queries to execute before continuing.
+# Without this sleep it sometimes happens that the SELECT from innodb_locks
+# executes before some of them, resulting in less than expected number
+# of rows being selected from innodb_locks.
+-- sleep 0.1
+
+-- enable_result_log
+-- connection con_verify_innodb_locks
+SELECT lock_mode, lock_type, lock_table, lock_index, lock_rec, lock_data
+FROM INFORMATION_SCHEMA.INNODB_LOCKS ORDER BY lock_data;
+
+SELECT lock_table,COUNT(*) FROM INFORMATION_SCHEMA.INNODB_LOCKS
+GROUP BY lock_table;
+
+set @save_sql_mode = @@sql_mode;
+SET SQL_MODE='ANSI_QUOTES';
+SELECT lock_table,COUNT(*) FROM INFORMATION_SCHEMA.INNODB_LOCKS
+GROUP BY lock_table;
+SET @@sql_mode=@save_sql_mode;
+-- disable_result_log
+
+-- connection default
+
+-- disconnect con_lock
+-- disconnect con_min_trylock
+-- disconnect con_max_trylock
+-- disconnect con_str_insert_supremum
+-- disconnect con_str_lock_row1
+-- disconnect con_str_lock_row2
+-- disconnect con_str_lock_row3
+-- disconnect con_str_lock_row4
+-- disconnect con_verify_innodb_locks
+
+DROP TABLE t_min, t_max, ```t'\"_str`;
diff --git a/mysql-test/suite/ndb/my.cnf b/mysql-test/suite/ndb/my.cnf
index 60769272ada..a19fdeee302 100644
--- a/mysql-test/suite/ndb/my.cnf
+++ b/mysql-test/suite/ndb/my.cnf
@@ -13,6 +13,7 @@ ndbcluster
[ENV]
NDB_CONNECTSTRING= @mysql_cluster.1.ndb_connectstring
+MASTER_MYSOCK= @mysqld.1.1.socket
MASTER_MYPORT= @mysqld.1.1.port
MASTER_MYPORT1= @mysqld.2.1.port
diff --git a/mysql-test/suite/ndb/r/ndb_binlog_format.result b/mysql-test/suite/ndb/r/ndb_binlog_format.result
index bb02002ed58..6e1fc12130f 100644
--- a/mysql-test/suite/ndb/r/ndb_binlog_format.result
+++ b/mysql-test/suite/ndb/r/ndb_binlog_format.result
@@ -15,15 +15,15 @@ COMMIT;
show binlog events from ;
Log_name Pos Event_type Server_id End_log_pos Info
mysqld-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (1,1), (1,2), (2,1), (2,2)
-mysqld-bin.000001 # Query # # use `test`; BEGIN
+mysqld-bin.000001 # Query # # BEGIN
mysqld-bin.000001 # Query # # use `test`; INSERT INTO t2 VALUES (1,1), (1,2), (2,1), (2,2)
-mysqld-bin.000001 # Query # # use `test`; COMMIT
+mysqld-bin.000001 # Query # # COMMIT
mysqld-bin.000001 # Query # # use `test`; UPDATE t1, t2 SET m = 2, b = 3 WHERE n = c
-mysqld-bin.000001 # Query # # use `test`; BEGIN
+mysqld-bin.000001 # Query # # BEGIN
mysqld-bin.000001 # Query # # use `test`; INSERT INTO t3 VALUES (1,1), (1,2), (2,1), (2,2)
mysqld-bin.000001 # Query # # use `test`; UPDATE t1, t3 SET m = 2, e = 3 WHERE n = f
mysqld-bin.000001 # Query # # use `test`; UPDATE t3, t2 SET e = 2, b = 3 WHERE f = c
-mysqld-bin.000001 # Query # # use `test`; COMMIT
+mysqld-bin.000001 # Query # # COMMIT
mysqld-bin.000001 # Query # # BEGIN
mysqld-bin.000001 # Table_map # # table_id: # (test.t3)
mysqld-bin.000001 # Table_map # # table_id: # (mysql.ndb_apply_status)
diff --git a/mysql-test/suite/ndb_team/r/rpl_ndb_mix_innodb.result b/mysql-test/suite/ndb_team/r/rpl_ndb_mix_innodb.result
index eba1222ea33..f9c077f38da 100644
--- a/mysql-test/suite/ndb_team/r/rpl_ndb_mix_innodb.result
+++ b/mysql-test/suite/ndb_team/r/rpl_ndb_mix_innodb.result
@@ -28,7 +28,7 @@ from mysql.ndb_apply_status;
show binlog events from limit 1;
Log_name Pos Event_type Server_id End_log_pos Info
-master-bin.000001 Query 1 # use `test`; BEGIN
+master-bin.000001 Query 1 # BEGIN
# Now the insert, one step after
@@ -53,7 +53,7 @@ from mysql.ndb_apply_status;
show binlog events from limit 1;
Log_name Pos Event_type Server_id End_log_pos Info
-master-bin.000001 Query 1 # use `test`; BEGIN
+master-bin.000001 Query 1 # BEGIN
show binlog events from limit 1,2;
Log_name Pos Event_type Server_id End_log_pos Info
diff --git a/mysql-test/suite/parts/r/partition_auto_increment_memory.result b/mysql-test/suite/parts/r/partition_auto_increment_memory.result
index 77bab79f020..f4d783825f4 100644
--- a/mysql-test/suite/parts/r/partition_auto_increment_memory.result
+++ b/mysql-test/suite/parts/r/partition_auto_increment_memory.result
@@ -381,12 +381,12 @@ Table Create Table
t1 CREATE TABLE `t1` (
`c1` int(11) NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`c1`)
-) ENGINE=MEMORY AUTO_INCREMENT=28 DEFAULT CHARSET=latin1
+) ENGINE=MEMORY AUTO_INCREMENT=2 DEFAULT CHARSET=latin1
/*!50100 PARTITION BY HASH (c1)
PARTITIONS 2 */
SELECT * FROM t1 ORDER BY c1;
c1
-27
+1
INSERT INTO t1 VALUES (100);
INSERT INTO t1 VALUES (NULL);
DELETE FROM t1 WHERE c1 >= 100;
diff --git a/mysql-test/suite/parts/r/partition_auto_increment_myisam.result b/mysql-test/suite/parts/r/partition_auto_increment_myisam.result
index b5b001ec17a..6abf08b68a0 100644
--- a/mysql-test/suite/parts/r/partition_auto_increment_myisam.result
+++ b/mysql-test/suite/parts/r/partition_auto_increment_myisam.result
@@ -381,12 +381,12 @@ Table Create Table
t1 CREATE TABLE `t1` (
`c1` int(11) NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`c1`)
-) ENGINE=MyISAM AUTO_INCREMENT=28 DEFAULT CHARSET=latin1
+) ENGINE=MyISAM AUTO_INCREMENT=2 DEFAULT CHARSET=latin1
/*!50100 PARTITION BY HASH (c1)
PARTITIONS 2 */
SELECT * FROM t1 ORDER BY c1;
c1
-27
+1
INSERT INTO t1 VALUES (100);
INSERT INTO t1 VALUES (NULL);
DELETE FROM t1 WHERE c1 >= 100;
diff --git a/mysql-test/suite/rpl/r/rpl_begin_commit_rollback.result b/mysql-test/suite/rpl/r/rpl_begin_commit_rollback.result
new file mode 100644
index 00000000000..23736804784
--- /dev/null
+++ b/mysql-test/suite/rpl/r/rpl_begin_commit_rollback.result
@@ -0,0 +1,109 @@
+stop slave;
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+reset master;
+reset slave;
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+start slave;
+DROP DATABASE IF EXISTS db1;
+CREATE DATABASE db1;
+use db1;
+CREATE TABLE db1.t1 (a INT) ENGINE=InnoDB;
+CREATE TABLE db1.t2 (s CHAR(255)) ENGINE=MyISAM;
+include/stop_slave.inc
+[on master]
+CREATE PROCEDURE db1.p1 ()
+BEGIN
+INSERT INTO t1 VALUES (1);
+INSERT INTO t1 VALUES (2);
+INSERT INTO t1 VALUES (3);
+INSERT INTO t1 VALUES (4);
+INSERT INTO t1 VALUES (5);
+END//
+CREATE PROCEDURE db1.p2 ()
+BEGIN
+INSERT INTO t1 VALUES (6);
+INSERT INTO t1 VALUES (7);
+INSERT INTO t1 VALUES (8);
+INSERT INTO t1 VALUES (9);
+INSERT INTO t1 VALUES (10);
+INSERT INTO t2 VALUES ('executed db1.p2()');
+END//
+INSERT INTO db1.t2 VALUES ('before call db1.p1()');
+use test;
+BEGIN;
+CALL db1.p1();
+COMMIT;
+INSERT INTO db1.t2 VALUES ('after call db1.p1()');
+SELECT * FROM db1.t1;
+a
+1
+2
+3
+4
+5
+SELECT * FROM db1.t2;
+s
+before call db1.p1()
+after call db1.p1()
+[on slave]
+start slave until master_log_file='master-bin.000001', master_log_pos=MASTER_POS;
+#
+# If we got non-zero here, then we're suffering BUG#43263
+#
+SELECT 0 as 'Must be 0';
+Must be 0
+0
+SELECT * from db1.t1;
+a
+1
+2
+3
+4
+5
+SELECT * from db1.t2;
+s
+before call db1.p1()
+[on master]
+INSERT INTO db1.t2 VALUES ('before call db1.p2()');
+BEGIN;
+CALL db1.p2();
+ROLLBACK;
+INSERT INTO db1.t2 VALUES ('after call db1.p2()');
+SELECT * FROM db1.t1;
+a
+1
+2
+3
+4
+5
+SELECT * FROM db1.t2;
+s
+before call db1.p1()
+after call db1.p1()
+before call db1.p2()
+executed db1.p2()
+after call db1.p2()
+[on slave]
+start slave until master_log_file='master-bin.000001', master_log_pos=MASTER_POS;
+#
+# If we got non-zero here, then we're suffering BUG#43263
+#
+SELECT 0 as 'Must be 0';
+Must be 0
+0
+SELECT * from db1.t1;
+a
+1
+2
+3
+4
+5
+SELECT * from db1.t2;
+s
+before call db1.p1()
+executed db1.p2()
+#
+# Clean up
+#
+DROP DATABASE db1;
+DROP DATABASE db1;
diff --git a/mysql-test/suite/rpl/r/rpl_binlog_grant.result b/mysql-test/suite/rpl/r/rpl_binlog_grant.result
index 72dc58effa1..4a789f361c6 100644
--- a/mysql-test/suite/rpl/r/rpl_binlog_grant.result
+++ b/mysql-test/suite/rpl/r/rpl_binlog_grant.result
@@ -23,7 +23,7 @@ master-bin.000001 4 Format_desc 1 106 Server ver: VERSION, Binlog ver: 4
master-bin.000001 106 Query 1 193 drop database if exists d1
master-bin.000001 193 Query 1 272 create database d1
master-bin.000001 272 Query 1 370 use `d1`; create table t (s1 int) engine=innodb
-master-bin.000001 370 Query 1 436 use `d1`; BEGIN
+master-bin.000001 370 Query 1 436 BEGIN
master-bin.000001 436 Query 1 521 use `d1`; insert into t values (1)
master-bin.000001 521 Xid 1 548 COMMIT /* XID */
master-bin.000001 548 Query 1 633 use `d1`; grant select on t to x@y
@@ -44,11 +44,11 @@ master-bin.000001 4 Format_desc 1 106 Server ver: VERSION, Binlog ver: 4
master-bin.000001 106 Query 1 193 drop database if exists d1
master-bin.000001 193 Query 1 272 create database d1
master-bin.000001 272 Query 1 370 use `d1`; create table t (s1 int) engine=innodb
-master-bin.000001 370 Query 1 436 use `d1`; BEGIN
+master-bin.000001 370 Query 1 436 BEGIN
master-bin.000001 436 Query 1 521 use `d1`; insert into t values (1)
master-bin.000001 521 Xid 1 548 COMMIT /* XID */
master-bin.000001 548 Query 1 633 use `d1`; grant select on t to x@y
-master-bin.000001 633 Query 1 699 use `d1`; BEGIN
+master-bin.000001 633 Query 1 699 BEGIN
master-bin.000001 699 Query 1 784 use `d1`; insert into t values (2)
master-bin.000001 784 Xid 1 811 COMMIT /* XID */
master-bin.000001 811 Query 1 899 use `d1`; revoke select on t from x@y
diff --git a/mysql-test/suite/rpl/r/rpl_binlog_max_cache_size.result b/mysql-test/suite/rpl/r/rpl_binlog_max_cache_size.result
new file mode 100644
index 00000000000..0e3f83d0aa5
--- /dev/null
+++ b/mysql-test/suite/rpl/r/rpl_binlog_max_cache_size.result
@@ -0,0 +1,135 @@
+stop slave;
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+reset master;
+reset slave;
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+start slave;
+CREATE TABLE t1(a INT PRIMARY KEY, data VARCHAR(30000)) ENGINE=Innodb;
+CREATE TABLE t2(a INT PRIMARY KEY, data VARCHAR(30000)) ENGINE=MyIsam;
+CREATE TABLE t3(a INT PRIMARY KEY, data VARCHAR(30000)) ENGINE=Innodb;
+########################################################################################
+# 1 - SINGLE STATEMENT
+########################################################################################
+*** Single statement on transactional table ***
+Got one of the listed errors
+*** Single statement on non-transactional table ***
+*** After WL#2687 the difference between STATEMENT/MIXED and ROW will not exist. ***
+Got one of the listed errors
+*** Single statement on both transactional and non-transactional tables. ***
+*** After WL#2687 we will be able to change the order of the tables. ***
+Got one of the listed errors
+SET GLOBAL SQL_SLAVE_SKIP_COUNTER = 1;
+START SLAVE SQL_THREAD;
+TRUNCATE TABLE t1;
+TRUNCATE TABLE t2;
+TRUNCATE TABLE t3;
+BEGIN;
+Got one of the listed errors
+Got one of the listed errors
+Got one of the listed errors
+BEGIN;
+Got one of the listed errors
+Got one of the listed errors
+Got one of the listed errors
+BEGIN;
+Got one of the listed errors
+Got one of the listed errors
+source include/diff_master_slave.inc;
+########################################################################################
+# 3 - BEGIN - COMMIT
+########################################################################################
+TRUNCATE TABLE t1;
+TRUNCATE TABLE t2;
+TRUNCATE TABLE t3;
+BEGIN;
+Got one of the listed errors
+Got one of the listed errors
+Got one of the listed errors
+COMMIT;
+source include/diff_master_slave.inc;
+########################################################################################
+# 4 - BEGIN - ROLLBACK
+########################################################################################
+TRUNCATE TABLE t1;
+TRUNCATE TABLE t2;
+TRUNCATE TABLE t3;
+BEGIN;
+Got one of the listed errors
+Got one of the listed errors
+Got one of the listed errors
+ROLLBACK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+source include/diff_master_slave.inc;
+########################################################################################
+# 5 - PROCEDURE
+########################################################################################
+TRUNCATE TABLE t1;
+TRUNCATE TABLE t2;
+TRUNCATE TABLE t3;
+CREATE PROCEDURE p1(pd VARCHAR(30000))
+BEGIN
+INSERT INTO t1 (a, data) VALUES (1, pd);
+INSERT INTO t1 (a, data) VALUES (2, pd);
+INSERT INTO t1 (a, data) VALUES (3, pd);
+INSERT INTO t1 (a, data) VALUES (4, pd);
+INSERT INTO t1 (a, data) VALUES (5, 's');
+END//
+TRUNCATE TABLE t1;
+TRUNCATE TABLE t1;
+BEGIN;
+Got one of the listed errors
+COMMIT;
+TRUNCATE TABLE t1;
+BEGIN;
+Got one of the listed errors
+ROLLBACK;
+source include/diff_master_slave.inc;
+########################################################################################
+# 6 - XID
+########################################################################################
+TRUNCATE TABLE t1;
+TRUNCATE TABLE t2;
+TRUNCATE TABLE t3;
+BEGIN;
+Got one of the listed errors
+Got one of the listed errors
+Got one of the listed errors
+ROLLBACK TO sv;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+COMMIT;
+source include/diff_master_slave.inc;
+########################################################################################
+# 7 - NON-TRANS TABLE
+########################################################################################
+TRUNCATE TABLE t1;
+TRUNCATE TABLE t2;
+TRUNCATE TABLE t3;
+BEGIN;
+Got one of the listed errors
+Got one of the listed errors
+Got one of the listed errors
+Got one of the listed errors
+Got one of the listed errors
+COMMIT;
+BEGIN;
+Got one of the listed errors
+COMMIT;
+########################################################################################
+# CLEAN
+########################################################################################
+DROP TABLE t1;
+DROP TABLE t2;
+DROP TABLE t3;
+DROP TABLE IF EXISTS t4;
+DROP TABLE IF EXISTS t5;
+DROP TABLE IF EXISTS t6;
+DROP PROCEDURE p1;
+DROP TABLE t1;
+DROP TABLE t2;
+DROP TABLE t3;
+DROP TABLE IF EXISTS t4;
+DROP TABLE IF EXISTS t5;
+DROP TABLE IF EXISTS t6;
+DROP PROCEDURE p1;
diff --git a/mysql-test/suite/rpl/r/rpl_concurrency_error.result b/mysql-test/suite/rpl/r/rpl_concurrency_error.result
new file mode 100644
index 00000000000..ba617667d5a
--- /dev/null
+++ b/mysql-test/suite/rpl/r/rpl_concurrency_error.result
@@ -0,0 +1,119 @@
+stop slave;
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+reset master;
+reset slave;
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+start slave;
+########################################################################
+# Environment
+########################################################################
+CREATE TABLE t (i INT, PRIMARY KEY(i), f CHAR(8)) engine = Innodb;
+CREATE TABLE n (d DATETIME, f CHAR(32)) engine = MyIsam;
+CREATE TRIGGER tr AFTER UPDATE ON t FOR EACH ROW
+BEGIN
+INSERT INTO n VALUES ( now(), concat( 'updated t: ', old.f, ' -> ', new.f ) );
+END |
+INSERT INTO t VALUES (4,'black'), (2,'red'), (3,'yelow'), (1,'cyan');
+########################################################################
+# Testing ER_LOCK_WAIT_TIMEOUT
+########################################################################
+SET AUTOCOMMIT = 1;
+BEGIN;
+UPDATE t SET f = 'yellow 2' WHERE i = 3;
+SET AUTOCOMMIT = 1;
+BEGIN;
+UPDATE t SET f = 'magenta 2' WHERE f = 'red';
+ERROR HY000: Lock wait timeout exceeded; try restarting transaction
+INSERT INTO t VALUES (5 + (2 * 10),"brown");
+INSERT INTO n VALUES (now(),"brown");
+COMMIT;
+ROLLBACK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+show binlog events from ;
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 # Query # # BEGIN
+master-bin.000001 # Query # # use `test`; UPDATE t SET f = 'magenta 2' WHERE f = 'red'
+master-bin.000001 # Query # # ROLLBACK
+master-bin.000001 # Query # # BEGIN
+master-bin.000001 # Query # # use `test`; UPDATE t SET f = 'yellow 2' WHERE i = 3
+master-bin.000001 # Xid # # COMMIT /* XID */
+master-bin.000001 # Query # # BEGIN
+master-bin.000001 # Query # # use `test`; INSERT INTO t VALUES (5 + (2 * 10),"brown")
+master-bin.000001 # Query # # use `test`; INSERT INTO n VALUES (now(),"brown")
+master-bin.000001 # Query # # ROLLBACK
+SET AUTOCOMMIT = 1;
+BEGIN;
+UPDATE t SET f = 'gray 2' WHERE i = 3;
+SET AUTOCOMMIT = 1;
+BEGIN;
+UPDATE t SET f = 'dark blue 2' WHERE f = 'red';
+ERROR HY000: Lock wait timeout exceeded; try restarting transaction
+INSERT INTO t VALUES (6 + (2 * 10),"brown");
+INSERT INTO n VALUES (now(),"brown");
+COMMIT;
+COMMIT;
+show binlog events from ;
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 # Query # # BEGIN
+master-bin.000001 # Query # # use `test`; UPDATE t SET f = 'dark blue 2' WHERE f = 'red'
+master-bin.000001 # Query # # ROLLBACK
+master-bin.000001 # Query # # BEGIN
+master-bin.000001 # Query # # use `test`; UPDATE t SET f = 'gray 2' WHERE i = 3
+master-bin.000001 # Xid # # COMMIT /* XID */
+master-bin.000001 # Query # # BEGIN
+master-bin.000001 # Query # # use `test`; INSERT INTO t VALUES (6 + (2 * 10),"brown")
+master-bin.000001 # Query # # use `test`; INSERT INTO n VALUES (now(),"brown")
+master-bin.000001 # Xid # # COMMIT /* XID */
+SET AUTOCOMMIT = 0;
+UPDATE t SET f = 'yellow 1' WHERE i = 3;
+SET AUTOCOMMIT = 0;
+UPDATE t SET f = 'magenta 1' WHERE f = 'red';
+ERROR HY000: Lock wait timeout exceeded; try restarting transaction
+INSERT INTO t VALUES (5 + (1 * 10),"brown");
+INSERT INTO n VALUES (now(),"brown");
+COMMIT;
+ROLLBACK;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+show binlog events from ;
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 # Query # # BEGIN
+master-bin.000001 # Query # # use `test`; UPDATE t SET f = 'magenta 1' WHERE f = 'red'
+master-bin.000001 # Query # # ROLLBACK
+master-bin.000001 # Query # # BEGIN
+master-bin.000001 # Query # # use `test`; UPDATE t SET f = 'yellow 1' WHERE i = 3
+master-bin.000001 # Xid # # COMMIT /* XID */
+master-bin.000001 # Query # # BEGIN
+master-bin.000001 # Query # # use `test`; INSERT INTO t VALUES (5 + (1 * 10),"brown")
+master-bin.000001 # Query # # use `test`; INSERT INTO n VALUES (now(),"brown")
+master-bin.000001 # Query # # ROLLBACK
+SET AUTOCOMMIT = 0;
+UPDATE t SET f = 'gray 1' WHERE i = 3;
+SET AUTOCOMMIT = 0;
+UPDATE t SET f = 'dark blue 1' WHERE f = 'red';
+ERROR HY000: Lock wait timeout exceeded; try restarting transaction
+INSERT INTO t VALUES (6 + (1 * 10),"brown");
+INSERT INTO n VALUES (now(),"brown");
+COMMIT;
+COMMIT;
+show binlog events from ;
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 # Query # # BEGIN
+master-bin.000001 # Query # # use `test`; UPDATE t SET f = 'dark blue 1' WHERE f = 'red'
+master-bin.000001 # Query # # ROLLBACK
+master-bin.000001 # Query # # BEGIN
+master-bin.000001 # Query # # use `test`; UPDATE t SET f = 'gray 1' WHERE i = 3
+master-bin.000001 # Xid # # COMMIT /* XID */
+master-bin.000001 # Query # # BEGIN
+master-bin.000001 # Query # # use `test`; INSERT INTO t VALUES (6 + (1 * 10),"brown")
+master-bin.000001 # Query # # use `test`; INSERT INTO n VALUES (now(),"brown")
+master-bin.000001 # Xid # # COMMIT /* XID */
+source include/diff_master_slave.inc;
+source include/diff_master_slave.inc;
+########################################################################
+# Cleanup
+########################################################################
+DROP TRIGGER tr;
+DROP TABLE t;
+DROP TABLE n;
diff --git a/mysql-test/suite/rpl/r/rpl_innodb_mixed_dml.result b/mysql-test/suite/rpl/r/rpl_innodb_mixed_dml.result
index 1e795a85ce1..033f71c16b7 100644
--- a/mysql-test/suite/rpl/r/rpl_innodb_mixed_dml.result
+++ b/mysql-test/suite/rpl/r/rpl_innodb_mixed_dml.result
@@ -836,178 +836,178 @@ master-bin.000001 # Format_desc 1 # Server ver: #
master-bin.000001 # Query 1 # CREATE DATABASE test_rpl
master-bin.000001 # Query 1 # use `test_rpl`; CREATE TABLE t1 (a int auto_increment not null, b char(254), PRIMARY KEY(a)) ENGINE=innodb
master-bin.000001 # Query 1 # use `test_rpl`; CREATE TABLE t2 (a int auto_increment not null, b char(254), PRIMARY KEY(a)) ENGINE=innodb
-master-bin.000001 # Query 1 # use `test_rpl`; BEGIN
+master-bin.000001 # Query 1 # BEGIN
master-bin.000001 # Query 1 # use `test_rpl`; INSERT INTO t1 VALUES(1, 't1, text 1')
master-bin.000001 # Xid 1 # #
-master-bin.000001 # Query 1 # use `test_rpl`; BEGIN
+master-bin.000001 # Query 1 # BEGIN
master-bin.000001 # Query 1 # use `test_rpl`; INSERT INTO t1 VALUES(2, 't1, text 2')
master-bin.000001 # Xid 1 # #
-master-bin.000001 # Query 1 # use `test_rpl`; BEGIN
+master-bin.000001 # Query 1 # BEGIN
master-bin.000001 # Query 1 # use `test_rpl`; INSERT INTO t2 VALUES(1, 't2, text 1')
master-bin.000001 # Xid 1 # #
-master-bin.000001 # Query 1 # use `test_rpl`; BEGIN
+master-bin.000001 # Query 1 # BEGIN
master-bin.000001 # Query 1 # use `test_rpl`; DELETE FROM t1 WHERE a = 1
master-bin.000001 # Xid 1 # #
-master-bin.000001 # Query 1 # use `test_rpl`; BEGIN
+master-bin.000001 # Query 1 # BEGIN
master-bin.000001 # Table_map 1 # table_id: # (test_rpl.t2)
master-bin.000001 # Delete_rows 1 # table_id: # flags: STMT_END_F
master-bin.000001 # Xid 1 # #
-master-bin.000001 # Query 1 # use `test_rpl`; BEGIN
+master-bin.000001 # Query 1 # BEGIN
master-bin.000001 # Query 1 # use `test_rpl`; DELETE FROM t1
master-bin.000001 # Xid 1 # #
-master-bin.000001 # Query 1 # use `test_rpl`; BEGIN
+master-bin.000001 # Query 1 # BEGIN
master-bin.000001 # Query 1 # use `test_rpl`; DELETE FROM t2
master-bin.000001 # Xid 1 # #
-master-bin.000001 # Query 1 # use `test_rpl`; BEGIN
+master-bin.000001 # Query 1 # BEGIN
master-bin.000001 # Query 1 # use `test_rpl`; INSERT INTO t1 VALUES(1, 't1, text 1')
master-bin.000001 # Xid 1 # #
-master-bin.000001 # Query 1 # use `test_rpl`; BEGIN
+master-bin.000001 # Query 1 # BEGIN
master-bin.000001 # Table_map 1 # table_id: # (test_rpl.t1)
master-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F
master-bin.000001 # Xid 1 # #
-master-bin.000001 # Query 1 # use `test_rpl`; BEGIN
+master-bin.000001 # Query 1 # BEGIN
master-bin.000001 # Query 1 # use `test_rpl`; INSERT INTO t2 SELECT * FROM t1
master-bin.000001 # Xid 1 # #
-master-bin.000001 # Query 1 # use `test_rpl`; BEGIN
+master-bin.000001 # Query 1 # BEGIN
master-bin.000001 # Query 1 # use `test_rpl`; INSERT INTO t2 VALUES (1, 't1, text 1') ON DUPLICATE KEY UPDATE b = 't2, text 1'
master-bin.000001 # Xid 1 # #
-master-bin.000001 # Query 1 # use `test_rpl`; BEGIN
+master-bin.000001 # Query 1 # BEGIN
master-bin.000001 # Query 1 # use `test_rpl`; DELETE FROM t1 WHERE a = 2
master-bin.000001 # Xid 1 # #
-master-bin.000001 # Query 1 # use `test_rpl`; BEGIN
+master-bin.000001 # Query 1 # BEGIN
master-bin.000001 # Query 1 # use `test_rpl`; DELETE FROM t2 WHERE a = 2
master-bin.000001 # Xid 1 # #
-master-bin.000001 # Query 1 # use `test_rpl`; BEGIN
+master-bin.000001 # Query 1 # BEGIN
master-bin.000001 # Query 1 # use `test_rpl`; DELETE FROM t1
master-bin.000001 # Xid 1 # #
-master-bin.000001 # Query 1 # use `test_rpl`; BEGIN
+master-bin.000001 # Query 1 # BEGIN
master-bin.000001 # Query 1 # use `test_rpl`; DELETE FROM t2
master-bin.000001 # Xid 1 # #
-master-bin.000001 # Query 1 # use `test_rpl`; BEGIN
+master-bin.000001 # Query 1 # BEGIN
master-bin.000001 # Begin_load_query 1 # ;file_id=#;block_len=#
master-bin.000001 # Execute_load_query 1 # use `test_rpl`; LOAD DATA INFILE 'MYSQLTEST_VARDIR/std_data/rpl_mixed.dat' INTO TABLE t1 FIELDS TERMINATED BY '|' ;file_id=#
master-bin.000001 # Xid 1 # #
-master-bin.000001 # Query 1 # use `test_rpl`; BEGIN
+master-bin.000001 # Query 1 # BEGIN
master-bin.000001 # Query 1 # use `test_rpl`; DELETE FROM t1
master-bin.000001 # Xid 1 # #
-master-bin.000001 # Query 1 # use `test_rpl`; BEGIN
+master-bin.000001 # Query 1 # BEGIN
master-bin.000001 # Query 1 # use `test_rpl`; DELETE FROM t2
master-bin.000001 # Xid 1 # #
-master-bin.000001 # Query 1 # use `test_rpl`; BEGIN
+master-bin.000001 # Query 1 # BEGIN
master-bin.000001 # Query 1 # use `test_rpl`; INSERT INTO t1 VALUES(1, 't1, text 1')
master-bin.000001 # Xid 1 # #
-master-bin.000001 # Query 1 # use `test_rpl`; BEGIN
+master-bin.000001 # Query 1 # BEGIN
master-bin.000001 # Query 1 # use `test_rpl`; INSERT INTO t1 VALUES(2, 't1, text 2')
master-bin.000001 # Xid 1 # #
-master-bin.000001 # Query 1 # use `test_rpl`; BEGIN
+master-bin.000001 # Query 1 # BEGIN
master-bin.000001 # Query 1 # use `test_rpl`; INSERT INTO t1 VALUES(3, 't1, text 3')
master-bin.000001 # Xid 1 # #
-master-bin.000001 # Query 1 # use `test_rpl`; BEGIN
+master-bin.000001 # Query 1 # BEGIN
master-bin.000001 # Query 1 # use `test_rpl`; REPLACE INTO t1 VALUES(1, 't1, text 11')
master-bin.000001 # Xid 1 # #
-master-bin.000001 # Query 1 # use `test_rpl`; BEGIN
+master-bin.000001 # Query 1 # BEGIN
master-bin.000001 # Table_map 1 # table_id: # (test_rpl.t1)
master-bin.000001 # Update_rows 1 # table_id: # flags: STMT_END_F
master-bin.000001 # Xid 1 # #
-master-bin.000001 # Query 1 # use `test_rpl`; BEGIN
+master-bin.000001 # Query 1 # BEGIN
master-bin.000001 # Query 1 # use `test_rpl`; REPLACE INTO t1 SET a=3, b='t1, text 33'
master-bin.000001 # Xid 1 # #
-master-bin.000001 # Query 1 # use `test_rpl`; BEGIN
+master-bin.000001 # Query 1 # BEGIN
master-bin.000001 # Query 1 # use `test_rpl`; DELETE FROM t1 WHERE a = 2
master-bin.000001 # Xid 1 # #
-master-bin.000001 # Query 1 # use `test_rpl`; BEGIN
+master-bin.000001 # Query 1 # BEGIN
master-bin.000001 # Query 1 # use `test_rpl`; DELETE FROM t1
master-bin.000001 # Xid 1 # #
-master-bin.000001 # Query 1 # use `test_rpl`; BEGIN
+master-bin.000001 # Query 1 # BEGIN
master-bin.000001 # Query 1 # use `test_rpl`; DELETE FROM t2
master-bin.000001 # Xid 1 # #
-master-bin.000001 # Query 1 # use `test_rpl`; BEGIN
+master-bin.000001 # Query 1 # BEGIN
master-bin.000001 # Query 1 # use `test_rpl`; INSERT INTO t1 VALUES(1, 't1, text 1')
master-bin.000001 # Xid 1 # #
-master-bin.000001 # Query 1 # use `test_rpl`; BEGIN
+master-bin.000001 # Query 1 # BEGIN
master-bin.000001 # Query 1 # use `test_rpl`; DELETE FROM t1
master-bin.000001 # Xid 1 # #
-master-bin.000001 # Query 1 # use `test_rpl`; BEGIN
+master-bin.000001 # Query 1 # BEGIN
master-bin.000001 # Query 1 # use `test_rpl`; DELETE FROM t2
master-bin.000001 # Xid 1 # #
-master-bin.000001 # Query 1 # use `test_rpl`; BEGIN
+master-bin.000001 # Query 1 # BEGIN
master-bin.000001 # Query 1 # use `test_rpl`; INSERT INTO t1 VALUES(1, 'CCC')
master-bin.000001 # Xid 1 # #
-master-bin.000001 # Query 1 # use `test_rpl`; BEGIN
+master-bin.000001 # Query 1 # BEGIN
master-bin.000001 # Query 1 # use `test_rpl`; INSERT INTO t1 VALUES(2, 'DDD')
master-bin.000001 # Xid 1 # #
-master-bin.000001 # Query 1 # use `test_rpl`; BEGIN
+master-bin.000001 # Query 1 # BEGIN
master-bin.000001 # Query 1 # use `test_rpl`; INSERT INTO t2 VALUES(1, 'DDD')
master-bin.000001 # Xid 1 # #
-master-bin.000001 # Query 1 # use `test_rpl`; BEGIN
+master-bin.000001 # Query 1 # BEGIN
master-bin.000001 # Query 1 # use `test_rpl`; INSERT INTO t2 VALUES(2, 'CCC')
master-bin.000001 # Xid 1 # #
-master-bin.000001 # Query 1 # use `test_rpl`; BEGIN
+master-bin.000001 # Query 1 # BEGIN
master-bin.000001 # Query 1 # use `test_rpl`; DELETE FROM t1
master-bin.000001 # Xid 1 # #
-master-bin.000001 # Query 1 # use `test_rpl`; BEGIN
+master-bin.000001 # Query 1 # BEGIN
master-bin.000001 # Query 1 # use `test_rpl`; DELETE FROM t2
master-bin.000001 # Xid 1 # #
-master-bin.000001 # Query 1 # use `test_rpl`; BEGIN
+master-bin.000001 # Query 1 # BEGIN
master-bin.000001 # Query 1 # use `test_rpl`; INSERT INTO t1 VALUES(1, 't1, text 1')
master-bin.000001 # Xid 1 # #
-master-bin.000001 # Query 1 # use `test_rpl`; BEGIN
+master-bin.000001 # Query 1 # BEGIN
master-bin.000001 # Query 1 # use `test_rpl`; INSERT INTO t2 VALUES(1, 't2, text 1')
master-bin.000001 # Xid 1 # #
-master-bin.000001 # Query 1 # use `test_rpl`; BEGIN
+master-bin.000001 # Query 1 # BEGIN
master-bin.000001 # Query 1 # use `test_rpl`; DELETE FROM t1
master-bin.000001 # Xid 1 # #
-master-bin.000001 # Query 1 # use `test_rpl`; BEGIN
+master-bin.000001 # Query 1 # BEGIN
master-bin.000001 # Query 1 # use `test_rpl`; DELETE FROM t2
master-bin.000001 # Xid 1 # #
-master-bin.000001 # Query 1 # use `test_rpl`; BEGIN
+master-bin.000001 # Query 1 # BEGIN
master-bin.000001 # Query 1 # use `test_rpl`; INSERT INTO t1 VALUES(1, 't1, text 1')
master-bin.000001 # Xid 1 # #
master-bin.000001 # Query 1 # use `test_rpl`; TRUNCATE t1
-master-bin.000001 # Query 1 # use `test_rpl`; BEGIN
+master-bin.000001 # Query 1 # BEGIN
master-bin.000001 # Query 1 # use `test_rpl`; DELETE FROM t1
master-bin.000001 # Xid 1 # #
-master-bin.000001 # Query 1 # use `test_rpl`; BEGIN
+master-bin.000001 # Query 1 # BEGIN
master-bin.000001 # Query 1 # use `test_rpl`; DELETE FROM t2
master-bin.000001 # Xid 1 # #
-master-bin.000001 # Query 1 # use `test_rpl`; BEGIN
+master-bin.000001 # Query 1 # BEGIN
master-bin.000001 # Query 1 # use `test_rpl`; INSERT INTO t1 VALUES(1, 't1, text 1')
master-bin.000001 # Xid 1 # #
-master-bin.000001 # Query 1 # use `test_rpl`; BEGIN
+master-bin.000001 # Query 1 # BEGIN
master-bin.000001 # Query 1 # use `test_rpl`; INSERT INTO t2 VALUES(1, 't2, text 1')
master-bin.000001 # Xid 1 # #
-master-bin.000001 # Query 1 # use `test_rpl`; BEGIN
+master-bin.000001 # Query 1 # BEGIN
master-bin.000001 # Query 1 # use `test_rpl`; UPDATE t1 SET b = 't1, text 1 updated' WHERE a = 1
master-bin.000001 # Xid 1 # #
-master-bin.000001 # Query 1 # use `test_rpl`; BEGIN
+master-bin.000001 # Query 1 # BEGIN
master-bin.000001 # Query 1 # use `test_rpl`; UPDATE t1, t2 SET t1.b = 'test', t2.b = 'test'
master-bin.000001 # Xid 1 # #
-master-bin.000001 # Query 1 # use `test_rpl`; BEGIN
+master-bin.000001 # Query 1 # BEGIN
master-bin.000001 # Query 1 # use `test_rpl`; DELETE FROM t1
master-bin.000001 # Xid 1 # #
-master-bin.000001 # Query 1 # use `test_rpl`; BEGIN
+master-bin.000001 # Query 1 # BEGIN
master-bin.000001 # Query 1 # use `test_rpl`; DELETE FROM t2
master-bin.000001 # Xid 1 # #
-master-bin.000001 # Query 1 # use `test_rpl`; BEGIN
+master-bin.000001 # Query 1 # BEGIN
master-bin.000001 # Query 1 # use `test_rpl`; INSERT INTO t1 VALUES (1, 'start')
master-bin.000001 # Xid 1 # #
-master-bin.000001 # Query 1 # use `test_rpl`; BEGIN
+master-bin.000001 # Query 1 # BEGIN
master-bin.000001 # Query 1 # use `test_rpl`; INSERT INTO t1 VALUES (3, 'before savepoint s1')
master-bin.000001 # Xid 1 # #
-master-bin.000001 # Query 1 # use `test_rpl`; BEGIN
+master-bin.000001 # Query 1 # BEGIN
master-bin.000001 # Query 1 # use `test_rpl`; INSERT INTO t1 VALUES (5, 'before savepoint s2')
master-bin.000001 # Query 1 # use `test_rpl`; SAVEPOINT s2
master-bin.000001 # Query 1 # use `test_rpl`; INSERT INTO t1 VALUES (6, 'after savepoint s2')
master-bin.000001 # Table_map 1 # table_id: # (test_rpl.t1)
master-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F
master-bin.000001 # Xid 1 # #
-master-bin.000001 # Query 1 # use `test_rpl`; BEGIN
+master-bin.000001 # Query 1 # BEGIN
master-bin.000001 # Query 1 # use `test_rpl`; DELETE FROM t1 WHERE a = 7
master-bin.000001 # Xid 1 # #
-master-bin.000001 # Query 1 # use `test_rpl`; BEGIN
+master-bin.000001 # Query 1 # BEGIN
master-bin.000001 # Query 1 # use `test_rpl`; DELETE FROM t1
master-bin.000001 # Xid 1 # #
-master-bin.000001 # Query 1 # use `test_rpl`; BEGIN
+master-bin.000001 # Query 1 # BEGIN
master-bin.000001 # Query 1 # use `test_rpl`; DELETE FROM t2
master-bin.000001 # Xid 1 # #
master-bin.000001 # Query 1 # use `test_rpl`; CREATE USER 'user_test_rpl'@'localhost' IDENTIFIED BY PASSWORD '*1111111111111111111111111111111111111111'
@@ -1016,7 +1016,7 @@ master-bin.000001 # Query 1 # use `test_rpl`; REVOKE SELECT ON *.* FROM 'user_te
master-bin.000001 # Query 1 # use `test_rpl`; SET PASSWORD FOR 'user_test_rpl'@'localhost'='*0000000000000000000000000000000000000000'
master-bin.000001 # Query 1 # use `test_rpl`; RENAME USER 'user_test_rpl'@'localhost' TO 'user_test_rpl_2'@'localhost'
master-bin.000001 # Query 1 # use `test_rpl`; DROP USER 'user_test_rpl_2'@'localhost'
-master-bin.000001 # Query 1 # use `test_rpl`; BEGIN
+master-bin.000001 # Query 1 # BEGIN
master-bin.000001 # Query 1 # use `test_rpl`; INSERT INTO t1 VALUES(100, 'test')
master-bin.000001 # Xid 1 # #
master-bin.000001 # Query 1 # use `test_rpl`; ANALYZE TABLE t1
@@ -1030,65 +1030,65 @@ master-bin.000001 # Query 1 # use `test_rpl`; CREATE DEFINER=`root`@`localhost`
BEGIN
UPDATE t1 SET b = UUID() WHERE a = 202;
END
-master-bin.000001 # Query 1 # use `test_rpl`; BEGIN
+master-bin.000001 # Query 1 # BEGIN
master-bin.000001 # Query 1 # use `test_rpl`; INSERT INTO t1 VALUES(201, 'test 201')
master-bin.000001 # Xid 1 # #
-master-bin.000001 # Query 1 # use `test_rpl`; BEGIN
+master-bin.000001 # Query 1 # BEGIN
master-bin.000001 # Query 1 # use `test_rpl`; UPDATE t1 SET b = 'test' WHERE a = 201
master-bin.000001 # Xid 1 # #
-master-bin.000001 # Query 1 # use `test_rpl`; BEGIN
+master-bin.000001 # Query 1 # BEGIN
master-bin.000001 # Query 1 # use `test_rpl`; INSERT INTO t1 VALUES(202, 'test 202')
master-bin.000001 # Xid 1 # #
-master-bin.000001 # Query 1 # use `test_rpl`; BEGIN
+master-bin.000001 # Query 1 # BEGIN
master-bin.000001 # Table_map 1 # table_id: # (test_rpl.t1)
master-bin.000001 # Update_rows 1 # table_id: # flags: STMT_END_F
master-bin.000001 # Xid 1 # #
-master-bin.000001 # Query 1 # use `test_rpl`; BEGIN
+master-bin.000001 # Query 1 # BEGIN
master-bin.000001 # Query 1 # use `test_rpl`; DELETE FROM t1 WHERE a = 202
master-bin.000001 # Xid 1 # #
master-bin.000001 # Query 1 # use `test_rpl`; ALTER PROCEDURE p1 COMMENT 'p1'
master-bin.000001 # Query 1 # use `test_rpl`; DROP PROCEDURE p1
master-bin.000001 # Query 1 # use `test_rpl`; DROP PROCEDURE p2
-master-bin.000001 # Query 1 # use `test_rpl`; BEGIN
+master-bin.000001 # Query 1 # BEGIN
master-bin.000001 # Query 1 # use `test_rpl`; DELETE FROM t1
master-bin.000001 # Xid 1 # #
-master-bin.000001 # Query 1 # use `test_rpl`; BEGIN
+master-bin.000001 # Query 1 # BEGIN
master-bin.000001 # Query 1 # use `test_rpl`; DELETE FROM t2
master-bin.000001 # Xid 1 # #
master-bin.000001 # Query 1 # use `test_rpl`; CREATE DEFINER=`root`@`localhost` TRIGGER tr1 BEFORE INSERT ON t1
FOR EACH ROW BEGIN
INSERT INTO t2 SET a = NEW.a, b = NEW.b;
END
-master-bin.000001 # Query 1 # use `test_rpl`; BEGIN
+master-bin.000001 # Query 1 # BEGIN
master-bin.000001 # Table_map 1 # table_id: # (test_rpl.t1)
master-bin.000001 # Table_map 1 # table_id: # (test_rpl.t2)
master-bin.000001 # Write_rows 1 # table_id: #
master-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F
master-bin.000001 # Xid 1 # #
-master-bin.000001 # Query 1 # use `test_rpl`; BEGIN
+master-bin.000001 # Query 1 # BEGIN
master-bin.000001 # Query 1 # use `test_rpl`; DELETE FROM t1
master-bin.000001 # Xid 1 # #
-master-bin.000001 # Query 1 # use `test_rpl`; BEGIN
+master-bin.000001 # Query 1 # BEGIN
master-bin.000001 # Query 1 # use `test_rpl`; DELETE FROM t2
master-bin.000001 # Xid 1 # #
master-bin.000001 # Query 1 # use `test_rpl`; DROP TRIGGER tr1
master-bin.000001 # Query 1 # use `test_rpl`; GRANT EVENT ON *.* TO 'root'@'localhost'
-master-bin.000001 # Query 1 # use `test_rpl`; BEGIN
+master-bin.000001 # Query 1 # BEGIN
master-bin.000001 # Query 1 # use `test_rpl`; INSERT INTO t1 VALUES(1, 'test1')
master-bin.000001 # Xid 1 # #
master-bin.000001 # Query 1 # use `test_rpl`; CREATE EVENT e1 ON SCHEDULE EVERY '1' SECOND COMMENT 'e_second_comment' DO DELETE FROM t1
master-bin.000001 # Query 1 # use `test_rpl`; ALTER EVENT e1 RENAME TO e2
master-bin.000001 # Query 1 # use `test_rpl`; DROP EVENT e2
-master-bin.000001 # Query 1 # use `test_rpl`; BEGIN
+master-bin.000001 # Query 1 # BEGIN
master-bin.000001 # Query 1 # use `test_rpl`; DELETE FROM t1
master-bin.000001 # Xid 1 # #
-master-bin.000001 # Query 1 # use `test_rpl`; BEGIN
+master-bin.000001 # Query 1 # BEGIN
master-bin.000001 # Query 1 # use `test_rpl`; DELETE FROM t2
master-bin.000001 # Xid 1 # #
-master-bin.000001 # Query 1 # use `test_rpl`; BEGIN
+master-bin.000001 # Query 1 # BEGIN
master-bin.000001 # Query 1 # use `test_rpl`; INSERT INTO t1 VALUES(1, 'test1')
master-bin.000001 # Xid 1 # #
-master-bin.000001 # Query 1 # use `test_rpl`; BEGIN
+master-bin.000001 # Query 1 # BEGIN
master-bin.000001 # Query 1 # use `test_rpl`; INSERT INTO t1 VALUES(2, 'test2')
master-bin.000001 # Xid 1 # #
master-bin.000001 # Query 1 # use `test_rpl`; CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS SELECT * FROM t1 WHERE a = 1
@@ -1096,10 +1096,10 @@ master-bin.000001 # Query 1 # use `test_rpl`; CREATE ALGORITHM=UNDEFINED DEFINER
master-bin.000001 # Query 1 # use `test_rpl`; ALTER ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS SELECT * FROM t1 WHERE a = 2
master-bin.000001 # Query 1 # use `test_rpl`; DROP VIEW v1
master-bin.000001 # Query 1 # use `test_rpl`; DROP VIEW v2
-master-bin.000001 # Query 1 # use `test_rpl`; BEGIN
+master-bin.000001 # Query 1 # BEGIN
master-bin.000001 # Query 1 # use `test_rpl`; DELETE FROM t1
master-bin.000001 # Xid 1 # #
-master-bin.000001 # Query 1 # use `test_rpl`; BEGIN
+master-bin.000001 # Query 1 # BEGIN
master-bin.000001 # Query 1 # use `test_rpl`; DELETE FROM t2
master-bin.000001 # Xid 1 # #
drop database test_rpl;
diff --git a/mysql-test/suite/rpl/r/rpl_rbr_to_sbr.result b/mysql-test/suite/rpl/r/rpl_rbr_to_sbr.result
index 0551240eb8a..2e707fb62c1 100644
--- a/mysql-test/suite/rpl/r/rpl_rbr_to_sbr.result
+++ b/mysql-test/suite/rpl/r/rpl_rbr_to_sbr.result
@@ -19,10 +19,10 @@ Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Format_desc 1 # Server ver: VERSION, Binlog ver: 4
master-bin.000001 # Query 1 # use `test`; CREATE TABLE t1 (a INT, b LONG)
master-bin.000001 # Query 1 # use `test`; INSERT INTO t1 VALUES (1,1), (2,2)
-master-bin.000001 # Query 1 # use `test`; BEGIN
+master-bin.000001 # Query 1 # BEGIN
master-bin.000001 # Table_map 1 # table_id: # (test.t1)
master-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F
-master-bin.000001 # Query 1 # use `test`; COMMIT
+master-bin.000001 # Query 1 # COMMIT
**** On Slave ****
SHOW SLAVE STATUS;
Slave_IO_State #
@@ -68,9 +68,9 @@ Log_name Pos Event_type Server_id End_log_pos Info
slave-bin.000001 # Format_desc 2 # Server ver: VERSION, Binlog ver: 4
slave-bin.000001 # Query 1 # use `test`; CREATE TABLE t1 (a INT, b LONG)
slave-bin.000001 # Query 1 # use `test`; INSERT INTO t1 VALUES (1,1), (2,2)
-slave-bin.000001 # Query 1 # use `test`; BEGIN
+slave-bin.000001 # Query 1 # BEGIN
slave-bin.000001 # Table_map 1 # table_id: # (test.t1)
slave-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F
-slave-bin.000001 # Query 1 # use `test`; COMMIT
+slave-bin.000001 # Query 1 # COMMIT
DROP TABLE IF EXISTS t1;
SET @@global.binlog_format= @old_binlog_format;
diff --git a/mysql-test/suite/rpl/r/rpl_row_basic_11bugs.result b/mysql-test/suite/rpl/r/rpl_row_basic_11bugs.result
index 1504c16bd7e..7920b9a981d 100644
--- a/mysql-test/suite/rpl/r/rpl_row_basic_11bugs.result
+++ b/mysql-test/suite/rpl/r/rpl_row_basic_11bugs.result
@@ -28,10 +28,10 @@ INSERT INTO t2 VALUES (3,3), (4,4);
show binlog events from ;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Query # # use `test`; CREATE TABLE t1 (a INT, b INT)
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
-master-bin.000001 # Query # # use `test`; COMMIT
+master-bin.000001 # Query # # COMMIT
**** On Slave ****
SHOW DATABASES;
Database
@@ -60,10 +60,10 @@ SHOW BINLOG EVENTS;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 4 Format_desc 1 106 Server ver: SERVER_VERSION, Binlog ver: 4
master-bin.000001 106 Query 1 192 use `test`; CREATE TABLE t1 (a INT)
-master-bin.000001 192 Query 1 260 use `test`; BEGIN
+master-bin.000001 192 Query 1 260 BEGIN
master-bin.000001 260 Table_map 1 301 table_id: # (test.t1)
master-bin.000001 301 Write_rows 1 340 table_id: # flags: STMT_END_F
-master-bin.000001 340 Query 1 409 use `test`; COMMIT
+master-bin.000001 340 Query 1 409 COMMIT
DROP TABLE t1;
================ Test for BUG#17620 ================
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
diff --git a/mysql-test/suite/rpl/r/rpl_row_create_table.result b/mysql-test/suite/rpl/r/rpl_row_create_table.result
index 29f58632fde..5bed9106009 100644
--- a/mysql-test/suite/rpl/r/rpl_row_create_table.result
+++ b/mysql-test/suite/rpl/r/rpl_row_create_table.result
@@ -150,10 +150,10 @@ a b
SHOW BINLOG EVENTS FROM 106;
Log_name Pos Event_type Server_id End_log_pos Info
# 106 Query # 206 use `test`; CREATE TABLE t7 (a INT, b INT UNIQUE)
-# 206 Query # 274 use `test`; BEGIN
+# 206 Query # 274 BEGIN
# 274 Table_map # 316 table_id: # (test.t7)
# 316 Write_rows # 372 table_id: # flags: STMT_END_F
-# 372 Query # 443 use `test`; ROLLBACK
+# 372 Query # 443 ROLLBACK
SELECT * FROM t7 ORDER BY a,b;
a b
1 2
@@ -173,10 +173,10 @@ Warnings:
Warning 1196 Some non-transactional changed tables couldn't be rolled back
SHOW BINLOG EVENTS FROM 106;
Log_name Pos Event_type Server_id End_log_pos Info
-# 106 Query # 174 use `test`; BEGIN
+# 106 Query # 174 BEGIN
# 174 Table_map # 216 table_id: # (test.t7)
# 216 Write_rows # 272 table_id: # flags: STMT_END_F
-# 272 Query # 343 use `test`; ROLLBACK
+# 272 Query # 343 ROLLBACK
SELECT * FROM t7 ORDER BY a,b;
a b
1 2
@@ -299,35 +299,35 @@ a
SHOW BINLOG EVENTS FROM 106;
Log_name Pos Event_type Server_id End_log_pos Info
# 106 Query # 192 use `test`; CREATE TABLE t1 (a INT)
-# 192 Query # 260 use `test`; BEGIN
+# 192 Query # 260 BEGIN
# 260 Table_map # 301 table_id: # (test.t1)
# 301 Write_rows # 345 table_id: # flags: STMT_END_F
-# 345 Query # 414 use `test`; COMMIT
-# 414 Query # 482 use `test`; BEGIN
+# 345 Query # 414 COMMIT
+# 414 Query # 482 BEGIN
# 482 Query # 607 use `test`; CREATE TABLE `t2` (
`a` int(11) DEFAULT NULL
) ENGINE=InnoDB
# 607 Table_map # 648 table_id: # (test.t2)
# 648 Write_rows # 692 table_id: # flags: STMT_END_F
# 692 Xid # 719 COMMIT /* XID */
-# 719 Query # 787 use `test`; BEGIN
+# 719 Query # 787 BEGIN
# 787 Query # 912 use `test`; CREATE TABLE `t3` (
`a` int(11) DEFAULT NULL
) ENGINE=InnoDB
# 912 Table_map # 953 table_id: # (test.t3)
# 953 Write_rows # 997 table_id: # flags: STMT_END_F
# 997 Xid # 1024 COMMIT /* XID */
-# 1024 Query # 1092 use `test`; BEGIN
+# 1024 Query # 1092 BEGIN
# 1092 Query # 1217 use `test`; CREATE TABLE `t4` (
`a` int(11) DEFAULT NULL
) ENGINE=InnoDB
# 1217 Table_map # 1258 table_id: # (test.t4)
# 1258 Write_rows # 1302 table_id: # flags: STMT_END_F
# 1302 Xid # 1329 COMMIT /* XID */
-# 1329 Query # 1397 use `test`; BEGIN
+# 1329 Query # 1397 BEGIN
# 1397 Table_map # 1438 table_id: # (test.t1)
# 1438 Write_rows # 1482 table_id: # flags: STMT_END_F
-# 1482 Query # 1553 use `test`; ROLLBACK
+# 1482 Query # 1553 ROLLBACK
SHOW TABLES;
Tables_in_test
t1
@@ -393,12 +393,12 @@ a
SHOW BINLOG EVENTS FROM 106;
Log_name Pos Event_type Server_id End_log_pos Info
# 106 Query # 192 use `test`; CREATE TABLE t1 (a INT)
-# 192 Query # 260 use `test`; BEGIN
+# 192 Query # 260 BEGIN
# 260 Table_map # 301 table_id: # (test.t1)
# 301 Write_rows # 345 table_id: # flags: STMT_END_F
-# 345 Query # 414 use `test`; COMMIT
+# 345 Query # 414 COMMIT
# 414 Query # 514 use `test`; CREATE TABLE t2 (a INT) ENGINE=INNODB
-# 514 Query # 582 use `test`; BEGIN
+# 514 Query # 582 BEGIN
# 582 Table_map # 623 table_id: # (test.t2)
# 623 Write_rows # 667 table_id: # flags: STMT_END_F
# 667 Table_map # 708 table_id: # (test.t2)
@@ -431,12 +431,12 @@ SELECT * FROM t2 ORDER BY a;
a
SHOW BINLOG EVENTS FROM 106;
Log_name Pos Event_type Server_id End_log_pos Info
-# 106 Query # 174 use `test`; BEGIN
+# 106 Query # 174 BEGIN
# 174 Table_map # 215 table_id: # (test.t2)
# 215 Write_rows # 259 table_id: # flags: STMT_END_F
# 259 Table_map # 300 table_id: # (test.t2)
# 300 Write_rows # 339 table_id: # flags: STMT_END_F
-# 339 Query # 410 use `test`; ROLLBACK
+# 339 Query # 410 ROLLBACK
SELECT * FROM t2 ORDER BY a;
a
DROP TABLE t1,t2;
@@ -468,12 +468,12 @@ Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Query # # DROP DATABASE IF EXISTS mysqltest1
master-bin.000001 # Query # # CREATE DATABASE mysqltest1
master-bin.000001 # Query # # use `test`; CREATE TABLE mysqltest1.without_select (f1 BIGINT)
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Query # # use `test`; CREATE TABLE `mysqltest1`.`with_select` (
`f1` int(1) NOT NULL DEFAULT '0'
)
master-bin.000001 # Table_map # # table_id: # (mysqltest1.with_select)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
-master-bin.000001 # Query # # use `test`; COMMIT
+master-bin.000001 # Query # # COMMIT
DROP DATABASE mysqltest1;
end of the tests
diff --git a/mysql-test/suite/rpl/r/rpl_row_log.result b/mysql-test/suite/rpl/r/rpl_row_log.result
index b76cc6aa15e..9593b009d1f 100644
--- a/mysql-test/suite/rpl/r/rpl_row_log.result
+++ b/mysql-test/suite/rpl/r/rpl_row_log.result
@@ -20,23 +20,23 @@ show binlog events;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Format_desc 1 # Server ver: VERSION, Binlog ver: 4
master-bin.000001 # Query 1 # use `test`; create table t1(n int not null auto_increment primary key)ENGINE=MyISAM
-master-bin.000001 # Query 1 # use `test`; BEGIN
+master-bin.000001 # Query 1 # BEGIN
master-bin.000001 # Table_map 1 # table_id: # (test.t1)
master-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F
-master-bin.000001 # Query 1 # use `test`; COMMIT
+master-bin.000001 # Query 1 # COMMIT
master-bin.000001 # Query 1 # use `test`; drop table t1
master-bin.000001 # Query 1 # use `test`; create table t1 (word char(20) not null)ENGINE=MyISAM
-master-bin.000001 # Query 1 # use `test`; BEGIN
+master-bin.000001 # Query 1 # BEGIN
master-bin.000001 # Table_map 1 # table_id: # (test.t1)
master-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F
-master-bin.000001 # Query 1 # use `test`; COMMIT
+master-bin.000001 # Query 1 # COMMIT
show binlog events from 106 limit 1;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Query 1 # use `test`; create table t1(n int not null auto_increment primary key)ENGINE=MyISAM
show binlog events from 106 limit 2;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Query 1 # use `test`; create table t1(n int not null auto_increment primary key)ENGINE=MyISAM
-master-bin.000001 # Query 1 # use `test`; BEGIN
+master-bin.000001 # Query 1 # BEGIN
show binlog events from 106 limit 2,1;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Table_map 1 # table_id: # (test.t1)
@@ -192,26 +192,26 @@ insert into t2 values (1);
show binlog events from ;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Query # # use `test`; create table t1(n int not null auto_increment primary key)ENGINE=MyISAM
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
-master-bin.000001 # Query # # use `test`; COMMIT
+master-bin.000001 # Query # # COMMIT
master-bin.000001 # Query # # use `test`; drop table t1
master-bin.000001 # Query # # use `test`; create table t1 (word char(20) not null)ENGINE=MyISAM
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
-master-bin.000001 # Query # # use `test`; COMMIT
+master-bin.000001 # Query # # COMMIT
master-bin.000001 # Rotate # # master-bin.000002;pos=4
show binlog events in 'master-bin.000002';
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000002 # Format_desc 1 # Server ver: VERSION, Binlog ver: 4
master-bin.000002 # Query 1 # use `test`; create table t3 (a int)ENGINE=MyISAM
master-bin.000002 # Query 1 # use `test`; create table t2 (n int)ENGINE=MyISAM
-master-bin.000002 # Query 1 # use `test`; BEGIN
+master-bin.000002 # Query 1 # BEGIN
master-bin.000002 # Table_map 1 # table_id: # (test.t2)
master-bin.000002 # Write_rows 1 # table_id: # flags: STMT_END_F
-master-bin.000002 # Query 1 # use `test`; COMMIT
+master-bin.000002 # Query 1 # COMMIT
show binary logs;
Log_name File_size
master-bin.000001 #
@@ -224,26 +224,26 @@ show binlog events in 'slave-bin.000001' from 4;
Log_name Pos Event_type Server_id End_log_pos Info
slave-bin.000001 # Format_desc 2 # Server ver: VERSION, Binlog ver: 4
slave-bin.000001 # Query 1 # use `test`; create table t1(n int not null auto_increment primary key)ENGINE=MyISAM
-slave-bin.000001 # Query 1 # use `test`; BEGIN
+slave-bin.000001 # Query 1 # BEGIN
slave-bin.000001 # Table_map 1 # table_id: # (test.t1)
slave-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F
-slave-bin.000001 # Query 1 # use `test`; COMMIT
+slave-bin.000001 # Query 1 # COMMIT
slave-bin.000001 # Query 1 # use `test`; drop table t1
slave-bin.000001 # Query 1 # use `test`; create table t1 (word char(20) not null)ENGINE=MyISAM
-slave-bin.000001 # Query 1 # use `test`; BEGIN
+slave-bin.000001 # Query 1 # BEGIN
slave-bin.000001 # Table_map 1 # table_id: # (test.t1)
slave-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F
-slave-bin.000001 # Query 1 # use `test`; COMMIT
+slave-bin.000001 # Query 1 # COMMIT
slave-bin.000001 # Query 1 # use `test`; create table t3 (a int)ENGINE=MyISAM
slave-bin.000001 # Rotate 2 # slave-bin.000002;pos=4
show binlog events in 'slave-bin.000002' from 4;
Log_name Pos Event_type Server_id End_log_pos Info
slave-bin.000002 # Format_desc 2 # Server ver: VERSION, Binlog ver: 4
slave-bin.000002 # Query 1 # use `test`; create table t2 (n int)ENGINE=MyISAM
-slave-bin.000002 # Query 1 # use `test`; BEGIN
+slave-bin.000002 # Query 1 # BEGIN
slave-bin.000002 # Table_map 1 # table_id: # (test.t2)
slave-bin.000002 # Write_rows 1 # table_id: # flags: STMT_END_F
-slave-bin.000002 # Query 1 # use `test`; COMMIT
+slave-bin.000002 # Query 1 # COMMIT
SHOW SLAVE STATUS;
Slave_IO_State #
Master_Host 127.0.0.1
@@ -301,14 +301,14 @@ insert into t1 values (NULL, last_insert_id()), (NULL, last_insert_id());
show binlog events from ;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Query # # use `test`; create table t1(a int auto_increment primary key, b int)
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
-master-bin.000001 # Query # # use `test`; COMMIT
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # COMMIT
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
-master-bin.000001 # Query # # use `test`; COMMIT
+master-bin.000001 # Query # # COMMIT
select * from t1;
a b
1 1
diff --git a/mysql-test/suite/rpl/r/rpl_row_log_innodb.result b/mysql-test/suite/rpl/r/rpl_row_log_innodb.result
index 809c50e1465..8526bad558b 100644
--- a/mysql-test/suite/rpl/r/rpl_row_log_innodb.result
+++ b/mysql-test/suite/rpl/r/rpl_row_log_innodb.result
@@ -20,13 +20,13 @@ show binlog events;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Format_desc 1 # Server ver: VERSION, Binlog ver: 4
master-bin.000001 # Query 1 # use `test`; create table t1(n int not null auto_increment primary key)ENGINE=InnoDB
-master-bin.000001 # Query 1 # use `test`; BEGIN
+master-bin.000001 # Query 1 # BEGIN
master-bin.000001 # Table_map 1 # table_id: # (test.t1)
master-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F
master-bin.000001 # Xid 1 # COMMIT /* XID */
master-bin.000001 # Query 1 # use `test`; drop table t1
master-bin.000001 # Query 1 # use `test`; create table t1 (word char(20) not null)ENGINE=InnoDB
-master-bin.000001 # Query 1 # use `test`; BEGIN
+master-bin.000001 # Query 1 # BEGIN
master-bin.000001 # Table_map 1 # table_id: # (test.t1)
master-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F
master-bin.000001 # Xid 1 # COMMIT /* XID */
@@ -36,7 +36,7 @@ master-bin.000001 # Query 1 # use `test`; create table t1(n int not null auto_in
show binlog events from 106 limit 2;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Query 1 # use `test`; create table t1(n int not null auto_increment primary key)ENGINE=InnoDB
-master-bin.000001 # Query 1 # use `test`; BEGIN
+master-bin.000001 # Query 1 # BEGIN
show binlog events from 106 limit 2,1;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Table_map 1 # table_id: # (test.t1)
@@ -192,13 +192,13 @@ insert into t2 values (1);
show binlog events from ;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Query # # use `test`; create table t1(n int not null auto_increment primary key)ENGINE=InnoDB
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
master-bin.000001 # Xid # # COMMIT /* XID */
master-bin.000001 # Query # # use `test`; drop table t1
master-bin.000001 # Query # # use `test`; create table t1 (word char(20) not null)ENGINE=InnoDB
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
master-bin.000001 # Xid # # COMMIT /* XID */
@@ -208,7 +208,7 @@ Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000002 # Format_desc 1 # Server ver: VERSION, Binlog ver: 4
master-bin.000002 # Query 1 # use `test`; create table t3 (a int)ENGINE=InnoDB
master-bin.000002 # Query 1 # use `test`; create table t2 (n int)ENGINE=InnoDB
-master-bin.000002 # Query 1 # use `test`; BEGIN
+master-bin.000002 # Query 1 # BEGIN
master-bin.000002 # Table_map 1 # table_id: # (test.t2)
master-bin.000002 # Write_rows 1 # table_id: # flags: STMT_END_F
master-bin.000002 # Xid 1 # COMMIT /* XID */
@@ -301,14 +301,14 @@ insert into t1 values (NULL, last_insert_id()), (NULL, last_insert_id());
show binlog events from ;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Query # # use `test`; create table t1(a int auto_increment primary key, b int)
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
-master-bin.000001 # Query # # use `test`; COMMIT
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # COMMIT
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
-master-bin.000001 # Query # # use `test`; COMMIT
+master-bin.000001 # Query # # COMMIT
select * from t1;
a b
1 1
diff --git a/mysql-test/suite/rpl/r/rpl_row_reset_slave.result b/mysql-test/suite/rpl/r/rpl_row_reset_slave.result
index 6126ec4bacc..fa40d8760a8 100644
--- a/mysql-test/suite/rpl/r/rpl_row_reset_slave.result
+++ b/mysql-test/suite/rpl/r/rpl_row_reset_slave.result
@@ -174,3 +174,26 @@ start slave;
show status like 'slave_open_temp_tables';
Variable_name Value
Slave_open_temp_tables 0
+stop slave;
+reset slave;
+*** errno must be zero: 0 ***
+change master to master_user='impossible_user_name';
+start slave;
+ONE
+1
+include/stop_slave.inc
+change master to master_user='root';
+include/start_slave.inc
+*** last errno must be zero: 0 ***
+*** last error must be blank: ***
+include/stop_slave.inc
+change master to master_user='impossible_user_name';
+start slave;
+ONE
+1
+include/stop_slave.inc
+reset slave;
+*** io last errno must be zero: 0 ***
+*** io last error must be blank: ***
+*** sql last errno must be zero: 0 ***
+*** sql last error must be blank: ***
diff --git a/mysql-test/suite/rpl/r/rpl_slave_load_tmpdir_not_exist.result b/mysql-test/suite/rpl/r/rpl_slave_load_tmpdir_not_exist.result
index a158fb5dfc4..3ed14a9cb6b 100644
--- a/mysql-test/suite/rpl/r/rpl_slave_load_tmpdir_not_exist.result
+++ b/mysql-test/suite/rpl/r/rpl_slave_load_tmpdir_not_exist.result
@@ -3,4 +3,4 @@ MASTER_CONNECT_RETRY=1,
MASTER_HOST='127.0.0.1',
MASTER_PORT=MASTER_MYPORT;
START SLAVE;
-Unable to use slave's temporary directory ../../../error - Can't read dir of '../../../error' (Errcode: 2)
+12
diff --git a/mysql-test/suite/rpl/r/rpl_slave_skip.result b/mysql-test/suite/rpl/r/rpl_slave_skip.result
index 747e8f235a8..6148de5d954 100644
--- a/mysql-test/suite/rpl/r/rpl_slave_skip.result
+++ b/mysql-test/suite/rpl/r/rpl_slave_skip.result
@@ -17,20 +17,20 @@ show binlog events from ;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Query # # use `test`; CREATE TABLE t1 (a INT, b INT)
master-bin.000001 # Query # # use `test`; CREATE TABLE t2 (c INT, d INT)
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
-master-bin.000001 # Query # # use `test`; COMMIT
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # COMMIT
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Table_map # # table_id: # (test.t2)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
-master-bin.000001 # Query # # use `test`; COMMIT
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # COMMIT
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Table_map # # table_id: # (test.t2)
master-bin.000001 # Update_rows # # table_id: #
master-bin.000001 # Update_rows # # table_id: # flags: STMT_END_F
-master-bin.000001 # Query # # use `test`; COMMIT
+master-bin.000001 # Query # # COMMIT
SELECT * FROM t1;
a b
1 1
@@ -39,8 +39,8 @@ a b
SELECT * FROM t2;
c d
1 2
-2 16
-3 54
+2 8
+3 18
**** On Slave ****
START SLAVE UNTIL MASTER_LOG_FILE='master-bin.000001', MASTER_LOG_POS=762;
SHOW SLAVE STATUS;
@@ -50,7 +50,7 @@ Master_User root
Master_Port MASTER_PORT
Connect_Retry 1
Master_Log_File master-bin.000001
-Read_Master_Log_Pos 1133
+Read_Master_Log_Pos 1115
Relay_Log_File #
Relay_Log_Pos #
Relay_Master_Log_File master-bin.000001
diff --git a/mysql-test/suite/rpl/r/rpl_stm_loadfile.result b/mysql-test/suite/rpl/r/rpl_stm_loadfile.result
index 72f58268d5f..ca76695f4d4 100644
--- a/mysql-test/suite/rpl/r/rpl_stm_loadfile.result
+++ b/mysql-test/suite/rpl/r/rpl_stm_loadfile.result
@@ -10,7 +10,7 @@ CREATE TABLE test.t1 (a INT, blob_column LONGBLOB, PRIMARY KEY(a));
INSERT INTO test.t1 VALUES(1,'test');
UPDATE test.t1 SET blob_column=LOAD_FILE('../../std_data/words2.dat') WHERE a=1;
Warnings:
-Note 1592 Statement is not safe to log in statement format.
+Note 1592 Statement may not be safe to log in statement format.
create procedure test.p1()
begin
INSERT INTO test.t1 VALUES(2,'test');
@@ -18,7 +18,7 @@ UPDATE test.t1 SET blob_column=LOAD_FILE('../../std_data/words2.dat') WHERE a=2;
end|
CALL test.p1();
Warnings:
-Note 1592 Statement is not safe to log in statement format.
+Note 1592 Statement may not be safe to log in statement format.
SELECT * FROM test.t1 ORDER BY blob_column;
a blob_column
1 abase
diff --git a/mysql-test/suite/rpl/r/rpl_stm_reset_slave.result b/mysql-test/suite/rpl/r/rpl_stm_reset_slave.result
index bb89d150af7..78d9d7c41eb 100644
--- a/mysql-test/suite/rpl/r/rpl_stm_reset_slave.result
+++ b/mysql-test/suite/rpl/r/rpl_stm_reset_slave.result
@@ -174,3 +174,26 @@ start slave;
show status like 'slave_open_temp_tables';
Variable_name Value
Slave_open_temp_tables 1
+stop slave;
+reset slave;
+*** errno must be zero: 0 ***
+change master to master_user='impossible_user_name';
+start slave;
+ONE
+1
+include/stop_slave.inc
+change master to master_user='root';
+include/start_slave.inc
+*** last errno must be zero: 0 ***
+*** last error must be blank: ***
+include/stop_slave.inc
+change master to master_user='impossible_user_name';
+start slave;
+ONE
+1
+include/stop_slave.inc
+reset slave;
+*** io last errno must be zero: 0 ***
+*** io last error must be blank: ***
+*** sql last errno must be zero: 0 ***
+*** sql last error must be blank: ***
diff --git a/mysql-test/suite/rpl/r/rpl_temporary.result b/mysql-test/suite/rpl/r/rpl_temporary.result
index 8a9ddaec9f6..631eb0677b0 100644
--- a/mysql-test/suite/rpl/r/rpl_temporary.result
+++ b/mysql-test/suite/rpl/r/rpl_temporary.result
@@ -6,6 +6,25 @@ drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
start slave;
call mtr.add_suppression("Slave: Can\'t find record in \'user\' Error_code: 1032");
reset master;
+DROP TABLE IF EXISTS t1;
+CREATE TEMPORARY TABLE t1 (a char(1));
+INSERT INTO t1 VALUES ('a');
+include/stop_slave.inc
+include/start_slave.inc
+INSERT INTO t1 VALUES ('b');
+DROP TABLE IF EXISTS t1;
+CREATE TEMPORARY TABLE `t1`(`a` tinyint,`b` char(1))engine=myisam;
+INSERT INTO `t1` set `a`=128,`b`='128';
+Warnings:
+Warning 1264 Out of range value for column 'a' at row 1
+Warning 1265 Data truncated for column 'b' at row 1
+include/stop_slave.inc
+include/start_slave.inc
+INSERT INTO `t1` set `a`=128,`b`='128';
+Warnings:
+Warning 1264 Out of range value for column 'a' at row 1
+Warning 1265 Data truncated for column 'b' at row 1
+DROP TABLE t1;
SET @save_select_limit=@@session.sql_select_limit;
SET @@session.sql_select_limit=10, @@session.pseudo_thread_id=100;
ERROR 42000: Access denied; you need the SUPER privilege for this operation
diff --git a/mysql-test/suite/rpl/r/rpl_udf.result b/mysql-test/suite/rpl/r/rpl_udf.result
index 56df5b30d93..ccf16271d01 100644
--- a/mysql-test/suite/rpl/r/rpl_udf.result
+++ b/mysql-test/suite/rpl/r/rpl_udf.result
@@ -182,19 +182,19 @@ CREATE TABLE t1(sum INT, price FLOAT(24)) ENGINE=MyISAM;
affected rows: 0
INSERT INTO t1 VALUES(myfunc_int(100), myfunc_double(50.00));
Warnings:
-Note 1592 Statement is not safe to log in statement format.
+Note 1592 Statement may not be safe to log in statement format.
affected rows: 1
INSERT INTO t1 VALUES(myfunc_int(10), myfunc_double(5.00));
Warnings:
-Note 1592 Statement is not safe to log in statement format.
+Note 1592 Statement may not be safe to log in statement format.
affected rows: 1
INSERT INTO t1 VALUES(myfunc_int(200), myfunc_double(25.00));
Warnings:
-Note 1592 Statement is not safe to log in statement format.
+Note 1592 Statement may not be safe to log in statement format.
affected rows: 1
INSERT INTO t1 VALUES(myfunc_int(1), myfunc_double(500.00));
Warnings:
-Note 1592 Statement is not safe to log in statement format.
+Note 1592 Statement may not be safe to log in statement format.
affected rows: 1
SELECT * FROM t1 ORDER BY sum;
sum price
diff --git a/mysql-test/suite/rpl/t/disabled.def b/mysql-test/suite/rpl/t/disabled.def
index b7cb6da8127..af8eef764ed 100644
--- a/mysql-test/suite/rpl/t/disabled.def
+++ b/mysql-test/suite/rpl/t/disabled.def
@@ -10,4 +10,6 @@
#
##############################################################################
-rpl_cross_version : BUG#42311 2009-03-27 joro rpl_cross_version fails on macosx
+rpl_cross_version : Bug#42311 2009-03-27 joro rpl_cross_version fails on macosx
+rpl_init_slave : Bug#44920 2009-07006 pcrews MTR2 is not processing master.opt input properly on Windows. *Must be done this way due to the nature of the bug*
+
diff --git a/mysql-test/suite/rpl/t/rpl_begin_commit_rollback-slave.opt b/mysql-test/suite/rpl/t/rpl_begin_commit_rollback-slave.opt
new file mode 100644
index 00000000000..b4abda5893f
--- /dev/null
+++ b/mysql-test/suite/rpl/t/rpl_begin_commit_rollback-slave.opt
@@ -0,0 +1 @@
+--innodb --replicate-do-db=db1
diff --git a/mysql-test/suite/rpl/t/rpl_begin_commit_rollback.test b/mysql-test/suite/rpl/t/rpl_begin_commit_rollback.test
new file mode 100644
index 00000000000..ec56e6a4f38
--- /dev/null
+++ b/mysql-test/suite/rpl/t/rpl_begin_commit_rollback.test
@@ -0,0 +1,125 @@
+source include/master-slave.inc;
+source include/have_innodb.inc;
+source include/have_binlog_format_statement.inc;
+
+disable_warnings;
+DROP DATABASE IF EXISTS db1;
+enable_warnings;
+
+CREATE DATABASE db1;
+
+use db1;
+
+CREATE TABLE db1.t1 (a INT) ENGINE=InnoDB;
+CREATE TABLE db1.t2 (s CHAR(255)) ENGINE=MyISAM;
+
+sync_slave_with_master;
+source include/stop_slave.inc;
+connection master;
+echo [on master];
+
+DELIMITER //;
+CREATE PROCEDURE db1.p1 ()
+BEGIN
+ INSERT INTO t1 VALUES (1);
+ INSERT INTO t1 VALUES (2);
+ INSERT INTO t1 VALUES (3);
+ INSERT INTO t1 VALUES (4);
+ INSERT INTO t1 VALUES (5);
+END//
+
+CREATE PROCEDURE db1.p2 ()
+BEGIN
+ INSERT INTO t1 VALUES (6);
+ INSERT INTO t1 VALUES (7);
+ INSERT INTO t1 VALUES (8);
+ INSERT INTO t1 VALUES (9);
+ INSERT INTO t1 VALUES (10);
+ INSERT INTO t2 VALUES ('executed db1.p2()');
+END//
+DELIMITER ;//
+
+INSERT INTO db1.t2 VALUES ('before call db1.p1()');
+
+# Note: the master_log_pos is set to be the position of the BEGIN + 1,
+# so before fix of BUG#43263 if the BEGIN is ignored, then all the
+# INSERTS in p1 will be replicated in AUTOCOMMIT=1 mode and the slave
+# SQL thread will stop right before the first INSERT. After fix of
+# BUG#43263, BEGIN will not be ignored by the replication db rules,
+# and then the whole transaction will be executed before slave SQL
+# stop.
+let $master_pos= query_get_value(SHOW MASTER STATUS, Position, 1);
+let $master_pos= `SELECT $master_pos + 1`;
+
+use test;
+BEGIN;
+CALL db1.p1();
+COMMIT;
+
+# The position where the following START SLAVE UNTIL will stop at
+let $master_end_trans_pos= query_get_value(SHOW MASTER STATUS, Position, 1);
+
+INSERT INTO db1.t2 VALUES ('after call db1.p1()');
+SELECT * FROM db1.t1;
+SELECT * FROM db1.t2;
+
+connection slave;
+echo [on slave];
+
+replace_result $master_pos MASTER_POS;
+eval start slave until master_log_file='master-bin.000001', master_log_pos=$master_pos;
+source include/wait_for_slave_sql_to_stop.inc;
+let $slave_sql_stop_pos= query_get_value(SHOW SLAVE STATUS, Exec_Master_Log_Pos, 1);
+let $result= query_get_value(SELECT $slave_sql_stop_pos - $master_end_trans_pos as result, result, 1);
+
+--echo #
+--echo # If we got non-zero here, then we're suffering BUG#43263
+--echo #
+eval SELECT $result as 'Must be 0';
+SELECT * from db1.t1;
+SELECT * from db1.t2;
+
+connection master;
+echo [on master];
+
+INSERT INTO db1.t2 VALUES ('before call db1.p2()');
+
+# See comments above.
+let $master_pos= query_get_value(SHOW MASTER STATUS, Position, 1);
+let $master_pos= `SELECT $master_pos + 1`;
+
+BEGIN;
+CALL db1.p2();
+disable_warnings;
+ROLLBACK;
+enable_warnings;
+let $master_end_trans_pos= query_get_value(SHOW MASTER STATUS, Position, 1);
+
+INSERT INTO db1.t2 VALUES ('after call db1.p2()');
+SELECT * FROM db1.t1;
+SELECT * FROM db1.t2;
+
+connection slave;
+echo [on slave];
+
+replace_result $master_pos MASTER_POS;
+eval start slave until master_log_file='master-bin.000001', master_log_pos=$master_pos;
+source include/wait_for_slave_sql_to_stop.inc;
+
+let $slave_sql_stop_pos= query_get_value(SHOW SLAVE STATUS, Exec_Master_Log_Pos, 1);
+let $result= query_get_value(SELECT $slave_sql_stop_pos - $master_end_trans_pos as result, result, 1);
+
+--echo #
+--echo # If we got non-zero here, then we're suffering BUG#43263
+--echo #
+eval SELECT $result as 'Must be 0';
+SELECT * from db1.t1;
+SELECT * from db1.t2;
+
+--echo #
+--echo # Clean up
+--echo #
+connection master;
+DROP DATABASE db1;
+connection slave;
+DROP DATABASE db1;
diff --git a/mysql-test/suite/rpl/t/rpl_binlog_max_cache_size-master.opt b/mysql-test/suite/rpl/t/rpl_binlog_max_cache_size-master.opt
new file mode 100644
index 00000000000..45631525481
--- /dev/null
+++ b/mysql-test/suite/rpl/t/rpl_binlog_max_cache_size-master.opt
@@ -0,0 +1 @@
+--binlog_cache_size=4096 --max_binlog_cache_size=7680
diff --git a/mysql-test/suite/rpl/t/rpl_binlog_max_cache_size.test b/mysql-test/suite/rpl/t/rpl_binlog_max_cache_size.test
new file mode 100644
index 00000000000..e1f1f8c54bb
--- /dev/null
+++ b/mysql-test/suite/rpl/t/rpl_binlog_max_cache_size.test
@@ -0,0 +1,395 @@
+########################################################################################
+# This test verifies if the binlog is not corrupted when the cache buffer is not
+# big enough to accommodate the changes and is divided in five steps:
+#
+# 1 - Single Statements:
+# 1.1 - Single statement on transactional table.
+# 1.2 - Single statement on non-transactional table.
+# 1.3 - Single statement on both transactional and non-transactional tables.
+# In both 1.2 and 1.3, an incident event is logged to notify the user that the
+# master and slave are diverging.
+#
+# 2 - Transactions ended by an implicit commit.
+#
+# 3 - Transactions ended by a COMMIT.
+#
+# 4 - Transactions ended by a ROLLBACK.
+#
+# 5 - Transactions with a failing statement that updates a non-transactional
+# table. In this case, a failure means that the statement does not get into
+# the cache and an incident event is logged to notify the user that the master
+# and slave are diverging.
+#
+########################################################################################
+
+########################################################################################
+# Configuring the environment
+########################################################################################
+--source include/have_innodb.inc
+--source include/master-slave.inc
+--source include/not_embedded.inc
+--source include/not_windows.inc
+
+CREATE TABLE t1(a INT PRIMARY KEY, data VARCHAR(30000)) ENGINE=Innodb;
+CREATE TABLE t2(a INT PRIMARY KEY, data VARCHAR(30000)) ENGINE=MyIsam;
+CREATE TABLE t3(a INT PRIMARY KEY, data VARCHAR(30000)) ENGINE=Innodb;
+
+let $data = `select concat('"', repeat('a',2000), '"')`;
+
+--echo ########################################################################################
+--echo # 1 - SINGLE STATEMENT
+--echo ########################################################################################
+
+connection master;
+
+--echo *** Single statement on transactional table ***
+--disable_query_log
+--error ER_TRANS_CACHE_FULL, ER_ERROR_ON_WRITE
+eval INSERT INTO t1 (a, data) VALUES (1,
+ CONCAT($data, $data, $data, $data, $data));
+--enable_query_log
+
+--echo *** Single statement on non-transactional table ***
+--echo *** After WL#2687 the difference between STATEMENT/MIXED and ROW will not exist. ***
+--disable_query_log
+--disable_warnings
+if (`SELECT @@binlog_format = 'STATEMENT' || @@binlog_format = 'MIXED'`)
+{
+ eval INSERT INTO t2 (a, data) VALUES (2,
+ CONCAT($data, $data, $data, $data, $data, $data));
+ --echo Got one of the listed errors
+}
+if (`SELECT @@binlog_format = 'ROW'`)
+{
+ --error ER_TRANS_CACHE_FULL, ER_ERROR_ON_WRITE
+ eval INSERT INTO t2 (a, data) VALUES (2,
+ CONCAT($data, $data, $data, $data, $data, $data));
+
+ connection slave;
+ --source include/wait_for_slave_sql_to_stop.inc
+ SET GLOBAL SQL_SLAVE_SKIP_COUNTER = 1;
+ START SLAVE SQL_THREAD;
+ --source include/wait_for_slave_sql_to_start.inc
+}
+--enable_warnings
+--enable_query_log
+
+connection master;
+
+--disable_query_log
+eval INSERT INTO t1 (a, data) VALUES (3, $data);
+eval INSERT INTO t1 (a, data) VALUES (4, $data);
+eval INSERT INTO t1 (a, data) VALUES (5, $data);
+eval INSERT INTO t2 (a, data) VALUES (3, $data);
+eval INSERT INTO t2 (a, data) VALUES (4, $data);
+eval INSERT INTO t2 (a, data) VALUES (5, $data);
+--enable_query_log
+
+--echo *** Single statement on both transactional and non-transactional tables. ***
+--echo *** After WL#2687 we will be able to change the order of the tables. ***
+--disable_query_log
+--error ER_TRANS_CACHE_FULL, ER_ERROR_ON_WRITE
+eval UPDATE t2, t1 SET t2.data = CONCAT($data, $data, $data, $data),
+ t1.data = CONCAT($data, $data, $data, $data);
+--enable_query_log
+
+connection slave;
+--source include/wait_for_slave_sql_to_stop.inc
+SET GLOBAL SQL_SLAVE_SKIP_COUNTER = 1;
+START SLAVE SQL_THREAD;
+--source include/wait_for_slave_sql_to_start.inc
+
+#--echo ########################################################################################
+#--echo # 2 - BEGIN - IMPLICIT COMMIT by DDL
+#--echo ########################################################################################
+
+connection master;
+TRUNCATE TABLE t1;
+TRUNCATE TABLE t2;
+TRUNCATE TABLE t3;
+
+BEGIN;
+--disable_query_log
+--eval INSERT INTO t1 (a, data) VALUES (1, $data);
+--eval INSERT INTO t1 (a, data) VALUES (2, $data);
+--eval INSERT INTO t1 (a, data) VALUES (3, $data);
+--error ER_TRANS_CACHE_FULL, ER_ERROR_ON_WRITE
+--eval INSERT INTO t1 (a, data) VALUES (4, $data);
+--error ER_TRANS_CACHE_FULL, ER_ERROR_ON_WRITE
+--eval INSERT INTO t1 (a, data) VALUES (5, $data);
+--error ER_TRANS_CACHE_FULL, ER_ERROR_ON_WRITE
+--eval INSERT INTO t1 (a, data) VALUES (6, $data);
+--eval INSERT INTO t1 (a, data) VALUES (7, 's');
+--eval INSERT INTO t2 (a, data) VALUES (8, 's');
+--eval INSERT INTO t1 (a, data) VALUES (9, 's');
+--enable_query_log
+
+--disable_query_log
+ALTER TABLE t3 ADD COLUMN d int;
+--enable_query_log
+
+--disable_query_log
+--eval INSERT INTO t2 (a, data) VALUES (10, $data);
+--eval INSERT INTO t2 (a, data) VALUES (11, $data);
+--eval INSERT INTO t2 (a, data) VALUES (12, $data);
+--eval INSERT INTO t2 (a, data) VALUES (13, $data);
+--enable_query_log
+
+BEGIN;
+--disable_query_log
+--eval INSERT INTO t1 (a, data) VALUES (14, $data);
+--eval INSERT INTO t1 (a, data) VALUES (15, $data);
+--eval INSERT INTO t1 (a, data) VALUES (16, $data);
+--error ER_TRANS_CACHE_FULL, ER_ERROR_ON_WRITE
+--eval INSERT INTO t1 (a, data) VALUES (17, $data);
+--error ER_TRANS_CACHE_FULL, ER_ERROR_ON_WRITE
+--eval INSERT INTO t1 (a, data) VALUES (18, $data);
+--eval INSERT INTO t1 (a, data) VALUES (19, 's');
+--eval INSERT INTO t2 (a, data) VALUES (20, 's');
+--eval INSERT INTO t1 (a, data) VALUES (21, 's');
+--enable_query_log
+
+if (`SELECT @@binlog_format = 'STATEMENT' || @@binlog_format = 'MIXED'`)
+{
+ --disable_query_log
+ CREATE TABLE t4 SELECT * FROM t1;
+ --enable_query_log
+ --echo Got one of the listed errors
+}
+if (`SELECT @@binlog_format = 'ROW'`)
+{
+ --disable_query_log
+ --error ER_TRANS_CACHE_FULL, ER_ERROR_ON_WRITE
+ CREATE TABLE t4 SELECT * FROM t1;
+ --enable_query_log
+}
+
+--disable_query_log
+--eval INSERT INTO t2 (a, data) VALUES (15, $data);
+--enable_query_log
+
+BEGIN;
+--disable_query_log
+--eval INSERT INTO t1 (a, data) VALUES (22, $data);
+--eval INSERT INTO t1 (a, data) VALUES (23, $data);
+--eval INSERT INTO t1 (a, data) VALUES (24, $data);
+--error ER_TRANS_CACHE_FULL, ER_ERROR_ON_WRITE
+--eval INSERT INTO t1 (a, data) VALUES (25, $data);
+--error ER_TRANS_CACHE_FULL, ER_ERROR_ON_WRITE
+--eval INSERT INTO t1 (a, data) VALUES (26, $data);
+--eval INSERT INTO t1 (a, data) VALUES (27, 's');
+--eval INSERT INTO t2 (a, data) VALUES (28, 's');
+--eval INSERT INTO t1 (a, data) VALUES (29, 's');
+--enable_query_log
+
+--disable_query_log
+CREATE TABLE t5 (a int);
+--enable_query_log
+
+let $diff_statement= SELECT * FROM t1;
+--source include/diff_master_slave.inc
+
+--echo ########################################################################################
+--echo # 3 - BEGIN - COMMIT
+--echo ########################################################################################
+
+connection master;
+TRUNCATE TABLE t1;
+TRUNCATE TABLE t2;
+TRUNCATE TABLE t3;
+
+BEGIN;
+--disable_query_log
+--eval INSERT INTO t1 (a, data) VALUES (1, $data);
+--eval INSERT INTO t1 (a, data) VALUES (2, $data);
+--eval INSERT INTO t1 (a, data) VALUES (3, $data);
+--error ER_TRANS_CACHE_FULL, ER_ERROR_ON_WRITE
+--eval INSERT INTO t1 (a, data) VALUES (4, $data);
+--error ER_TRANS_CACHE_FULL, ER_ERROR_ON_WRITE
+--eval INSERT INTO t1 (a, data) VALUES (5, $data);
+--error ER_TRANS_CACHE_FULL, ER_ERROR_ON_WRITE
+--eval INSERT INTO t1 (a, data) VALUES (6, $data);
+--eval INSERT INTO t1 (a, data) VALUES (7, 's');
+--eval INSERT INTO t2 (a, data) VALUES (8, 's');
+--eval INSERT INTO t1 (a, data) VALUES (9, 's');
+--enable_query_log
+COMMIT;
+
+let $diff_statement= SELECT * FROM t1;
+--source include/diff_master_slave.inc
+
+--echo ########################################################################################
+--echo # 4 - BEGIN - ROLLBACK
+--echo ########################################################################################
+
+connection master;
+TRUNCATE TABLE t1;
+TRUNCATE TABLE t2;
+TRUNCATE TABLE t3;
+
+BEGIN;
+--disable_query_log
+--eval INSERT INTO t1 (a, data) VALUES (1, $data);
+--eval INSERT INTO t1 (a, data) VALUES (2, $data);
+--eval INSERT INTO t1 (a, data) VALUES (3, $data);
+--error ER_TRANS_CACHE_FULL, ER_ERROR_ON_WRITE
+--eval INSERT INTO t1 (a, data) VALUES (4, $data);
+--error ER_TRANS_CACHE_FULL, ER_ERROR_ON_WRITE
+--eval INSERT INTO t1 (a, data) VALUES (5, $data);
+--error ER_TRANS_CACHE_FULL, ER_ERROR_ON_WRITE
+--eval INSERT INTO t1 (a, data) VALUES (6, $data);
+--eval INSERT INTO t1 (a, data) VALUES (7, 's');
+--eval INSERT INTO t2 (a, data) VALUES (8, 's');
+--eval INSERT INTO t1 (a, data) VALUES (9, 's');
+--enable_query_log
+ROLLBACK;
+
+let $diff_statement= SELECT * FROM t1;
+--source include/diff_master_slave.inc
+
+--echo ########################################################################################
+--echo # 5 - PROCEDURE
+--echo ########################################################################################
+
+connection master;
+TRUNCATE TABLE t1;
+TRUNCATE TABLE t2;
+TRUNCATE TABLE t3;
+
+DELIMITER //;
+
+CREATE PROCEDURE p1(pd VARCHAR(30000))
+BEGIN
+ INSERT INTO t1 (a, data) VALUES (1, pd);
+ INSERT INTO t1 (a, data) VALUES (2, pd);
+ INSERT INTO t1 (a, data) VALUES (3, pd);
+ INSERT INTO t1 (a, data) VALUES (4, pd);
+ INSERT INTO t1 (a, data) VALUES (5, 's');
+END//
+
+DELIMITER ;//
+
+TRUNCATE TABLE t1;
+
+--disable_query_log
+eval CALL p1($data);
+--enable_query_log
+
+TRUNCATE TABLE t1;
+
+BEGIN;
+--disable_query_log
+--error ER_TRANS_CACHE_FULL, ER_ERROR_ON_WRITE
+eval CALL p1($data);
+--enable_query_log
+COMMIT;
+
+TRUNCATE TABLE t1;
+
+BEGIN;
+--disable_query_log
+--error ER_TRANS_CACHE_FULL, ER_ERROR_ON_WRITE
+eval CALL p1($data);
+--enable_query_log
+ROLLBACK;
+
+let $diff_statement= SELECT * FROM t1;
+--source include/diff_master_slave.inc
+
+--echo ########################################################################################
+--echo # 6 - XID
+--echo ########################################################################################
+
+connection master;
+TRUNCATE TABLE t1;
+TRUNCATE TABLE t2;
+TRUNCATE TABLE t3;
+
+BEGIN;
+--disable_query_log
+--eval INSERT INTO t1 (a, data) VALUES (1, $data);
+--eval INSERT INTO t1 (a, data) VALUES (2, $data);
+--eval INSERT INTO t1 (a, data) VALUES (3, $data);
+--error ER_TRANS_CACHE_FULL, ER_ERROR_ON_WRITE
+--eval INSERT INTO t1 (a, data) VALUES (4, $data);
+SAVEPOINT sv;
+--error ER_TRANS_CACHE_FULL, ER_ERROR_ON_WRITE
+--eval INSERT INTO t1 (a, data) VALUES (5, $data);
+--error ER_TRANS_CACHE_FULL, ER_ERROR_ON_WRITE
+--eval INSERT INTO t1 (a, data) VALUES (6, $data);
+--eval INSERT INTO t1 (a, data) VALUES (7, 's');
+--eval INSERT INTO t2 (a, data) VALUES (8, 's');
+--eval INSERT INTO t1 (a, data) VALUES (9, 's');
+--enable_query_log
+ROLLBACK TO sv;
+COMMIT;
+
+let $diff_statement= SELECT * FROM t1;
+--source include/diff_master_slave.inc
+
+--echo ########################################################################################
+--echo # 7 - NON-TRANS TABLE
+--echo ########################################################################################
+
+connection master;
+TRUNCATE TABLE t1;
+TRUNCATE TABLE t2;
+TRUNCATE TABLE t3;
+
+BEGIN;
+--disable_query_log
+--eval INSERT INTO t1 (a, data) VALUES (1, $data);
+--eval INSERT INTO t1 (a, data) VALUES (2, $data);
+--eval INSERT INTO t2 (a, data) VALUES (3, $data);
+--error ER_TRANS_CACHE_FULL, ER_ERROR_ON_WRITE
+--eval INSERT INTO t1 (a, data) VALUES (4, $data);
+--error ER_TRANS_CACHE_FULL, ER_ERROR_ON_WRITE
+--eval INSERT INTO t1 (a, data) VALUES (5, $data);
+--error ER_TRANS_CACHE_FULL, ER_ERROR_ON_WRITE
+--eval INSERT INTO t1 (a, data) VALUES (6, $data);
+--error ER_TRANS_CACHE_FULL, ER_ERROR_ON_WRITE
+--eval INSERT INTO t1 (a, data) VALUES (7, $data);
+--error ER_TRANS_CACHE_FULL, ER_ERROR_ON_WRITE
+--eval UPDATE t2 SET data= CONCAT($data, $data);
+--eval INSERT INTO t1 (a, data) VALUES (8, 's');
+--eval INSERT INTO t1 (a, data) VALUES (9, 's');
+--eval INSERT INTO t2 (a, data) VALUES (10, 's');
+--eval INSERT INTO t1 (a, data) VALUES (11, 's');
+--enable_query_log
+COMMIT;
+
+BEGIN;
+--disable_query_log
+--eval INSERT INTO t1 (a, data) VALUES (15, $data);
+--eval INSERT INTO t1 (a, data) VALUES (16, $data);
+--eval INSERT INTO t2 (a, data) VALUES (17, $data);
+--error ER_TRANS_CACHE_FULL, ER_ERROR_ON_WRITE
+--eval INSERT INTO t1 (a, data) VALUES (18, $data);
+--enable_query_log
+COMMIT;
+
+connection slave;
+--source include/wait_for_slave_sql_to_stop.inc
+
+--echo ########################################################################################
+--echo # CLEAN
+--echo ########################################################################################
+
+--disable_warnings
+connection master;
+DROP TABLE t1;
+DROP TABLE t2;
+DROP TABLE t3;
+DROP TABLE IF EXISTS t4;
+DROP TABLE IF EXISTS t5;
+DROP TABLE IF EXISTS t6;
+DROP PROCEDURE p1;
+connection slave;
+DROP TABLE t1;
+DROP TABLE t2;
+DROP TABLE t3;
+DROP TABLE IF EXISTS t4;
+DROP TABLE IF EXISTS t5;
+DROP TABLE IF EXISTS t6;
+DROP PROCEDURE p1;
+--enable_warnings
diff --git a/mysql-test/suite/rpl/t/rpl_concurrency_error-master.opt b/mysql-test/suite/rpl/t/rpl_concurrency_error-master.opt
new file mode 100644
index 00000000000..a6ef074a120
--- /dev/null
+++ b/mysql-test/suite/rpl/t/rpl_concurrency_error-master.opt
@@ -0,0 +1 @@
+--innodb-lock-wait-timeout=1
diff --git a/mysql-test/suite/rpl/t/rpl_concurrency_error.test b/mysql-test/suite/rpl/t/rpl_concurrency_error.test
new file mode 100644
index 00000000000..da2951afb1a
--- /dev/null
+++ b/mysql-test/suite/rpl/t/rpl_concurrency_error.test
@@ -0,0 +1,149 @@
+###############################################################################
+#BUG#44581 Slave stops when transaction with non-transactional table gets
+#lock wait timeout
+#
+# In STMT and MIXED modes, a statement that changes both non-transactional and
+# transactional tables must be written to the binary log whenever there are
+# changes to non-transactional tables. This means that the statement gets into
+# the # binary log even when the changes to the transactional tables fail. In
+# particular, in the presence of a failure such statement is annotated with the
+# error number and wrapped in a begin/rollback. On the slave, while applying
+# the statement, it is expected the same failure and the rollback prevents the
+# transactional changes to be persisted.
+
+# This test aims to verify if a statement that updates both transactional and
+# non-transacitonal tables and fails due to concurrency problems is correctly
+# processed by the slave in the sense that the statements get into the binary
+# log, the error is ignored and only the non-transactional tables are changed.
+###############################################################################
+
+--source include/master-slave.inc
+--source include/have_innodb.inc
+--source include/have_binlog_format_statement.inc
+
+--echo ########################################################################
+--echo # Environment
+--echo ########################################################################
+connection master;
+
+CREATE TABLE t (i INT, PRIMARY KEY(i), f CHAR(8)) engine = Innodb;
+CREATE TABLE n (d DATETIME, f CHAR(32)) engine = MyIsam;
+
+DELIMITER |;
+CREATE TRIGGER tr AFTER UPDATE ON t FOR EACH ROW
+BEGIN
+ INSERT INTO n VALUES ( now(), concat( 'updated t: ', old.f, ' -> ', new.f ) );
+END |
+DELIMITER ;|
+
+INSERT INTO t VALUES (4,'black'), (2,'red'), (3,'yelow'), (1,'cyan');
+
+connect (conn1, 127.0.0.1,root,,);
+connect (conn2, 127.0.0.1,root,,);
+
+--echo ########################################################################
+--echo # Testing ER_LOCK_WAIT_TIMEOUT
+--echo ########################################################################
+
+let $type=2;
+
+while ($type)
+{
+ let $binlog_start= query_get_value("SHOW MASTER STATUS", Position, 1);
+ connection conn1;
+ if (`select $type = 2`)
+ {
+ SET AUTOCOMMIT = 1;
+ BEGIN;
+ }
+ if (`select $type = 1`)
+ {
+ SET AUTOCOMMIT = 0;
+ }
+ eval UPDATE t SET f = 'yellow $type' WHERE i = 3;
+
+ connection conn2;
+ if (`select $type = 2`)
+ {
+ SET AUTOCOMMIT = 1;
+ BEGIN;
+ }
+ if (`select $type = 1`)
+ {
+ SET AUTOCOMMIT = 0;
+ }
+ --error ER_LOCK_WAIT_TIMEOUT
+ eval UPDATE t SET f = 'magenta $type' WHERE f = 'red';
+ eval INSERT INTO t VALUES (5 + ($type * 10),"brown");
+ INSERT INTO n VALUES (now(),"brown");
+
+ connection conn1;
+ COMMIT;
+
+ connection conn2;
+ ROLLBACK;
+ --source include/show_binlog_events.inc
+
+ let $binlog_start= query_get_value("SHOW MASTER STATUS", Position, 1);
+ connection conn1;
+ if (`select $type = 2`)
+ {
+ SET AUTOCOMMIT = 1;
+ BEGIN;
+ }
+ if (`select $type = 1`)
+ {
+ SET AUTOCOMMIT = 0;
+ }
+ eval UPDATE t SET f = 'gray $type' WHERE i = 3;
+
+ connection conn2;
+ if (`select $type = 2`)
+ {
+ SET AUTOCOMMIT = 1;
+ BEGIN;
+ }
+ if (`select $type = 1`)
+ {
+ SET AUTOCOMMIT = 0;
+ }
+ --error ER_LOCK_WAIT_TIMEOUT
+ eval UPDATE t SET f = 'dark blue $type' WHERE f = 'red';
+ eval INSERT INTO t VALUES (6 + ($type * 10),"brown");
+ INSERT INTO n VALUES (now(),"brown");
+
+ connection conn1;
+ COMMIT;
+
+ connection conn2;
+ COMMIT;
+ --source include/show_binlog_events.inc
+
+ dec $type;
+}
+
+connection master;
+sync_slave_with_master;
+
+connection master;
+let $diff_statement= SELECT * FROM t order by i;
+source include/diff_master_slave.inc;
+
+connection master;
+let $diff_statement= SELECT * FROM n order by d, f;
+source include/diff_master_slave.inc;
+
+--echo ########################################################################
+--echo # Cleanup
+--echo ########################################################################
+
+connection master;
+DROP TRIGGER tr;
+DROP TABLE t;
+DROP TABLE n;
+
+sync_slave_with_master;
+
+connection master;
+disconnect conn1;
+disconnect conn2;
diff --git a/mysql-test/suite/rpl/t/rpl_incident.test b/mysql-test/suite/rpl/t/rpl_incident.test
index 38fcc116736..66893ebb93f 100644
--- a/mysql-test/suite/rpl/t/rpl_incident.test
+++ b/mysql-test/suite/rpl/t/rpl_incident.test
@@ -14,42 +14,13 @@ REPLACE INTO t1 VALUES (4);
SELECT * FROM t1;
connection slave;
-source include/wait_for_slave_sql_to_stop.inc;
+# Wait until SQL thread stops with error LOST_EVENT on master
+let $slave_sql_errno= 1590;
+source include/wait_for_slave_sql_error.inc;
# The 4 should not be inserted into the table, since the incident log
# event should have stop the slave.
--echo **** On Slave ****
-#### BEGIN DEBUG INFO ADDED BY SVEN 2008-07-18 -- SEE BUG#38077 ####
-let $tables= query_get_value(SHOW TABLES, Tables_in_test, 1);
-if (`SELECT '$tables' != 't1'`)
-{
- --echo **** TEST CASE BUG! PRINTING DEBUG INFO! ****
- --echo **** Dear developer, if you see this in the output of a test
- --echo **** case run, please add all the information below as a
- --echo **** comment to BUG#38077. If it's a pushbuild failure, please
- --echo **** include a link to the push page.
- --echo **** Thank you! /Sven
- SHOW BINLOG EVENTS;
- --echo **** master binlog ****
- --error 0,1
- --exec $MYSQL_BINLOG --hexdump $MYSQLTEST_VARDIR/log/master-bin.000001
- --echo **** slave binlog ****
- --error 0,1
- --exec $MYSQL_BINLOG --hexdump $MYSQLTEST_VARDIR/log/slave-bin.000001
- --echo **** slave status ****
- query_vertical SHOW SLAVE STATUS;
- --echo **** slave's master status ****
- SHOW MASTER STATUS;
- --echo **** slave binlog events ****
- --echo [on master]
- connection master;
- --echo **** master status ****
- SHOW MASTER STATUS;
- --echo **** master binlog events ****
- SHOW BINLOG EVENTS;
- exit;
-}
-#### END DEBUG INFO ####
SELECT * FROM t1;
--replace_result $MASTER_MYPORT MASTER_PORT
diff --git a/mysql-test/suite/rpl/t/rpl_slave_load_tmpdir_not_exist.test b/mysql-test/suite/rpl/t/rpl_slave_load_tmpdir_not_exist.test
index 3a80fa43f20..68c41abf537 100644
--- a/mysql-test/suite/rpl/t/rpl_slave_load_tmpdir_not_exist.test
+++ b/mysql-test/suite/rpl/t/rpl_slave_load_tmpdir_not_exist.test
@@ -20,5 +20,5 @@ eval CHANGE MASTER TO MASTER_USER='root',
START SLAVE;
source include/wait_for_slave_sql_to_stop.inc;
-let $error=query_get_value("show slave status", Last_SQL_Error, 1);
-echo $error;
+let $errno=query_get_value("show slave status", Last_SQL_Errno, 1);
+echo $errno;
diff --git a/mysql-test/suite/rpl/t/rpl_sp.test b/mysql-test/suite/rpl/t/rpl_sp.test
index ec6464fb095..9be630e9ae8 100644
--- a/mysql-test/suite/rpl/t/rpl_sp.test
+++ b/mysql-test/suite/rpl/t/rpl_sp.test
@@ -642,3 +642,6 @@ drop procedure ` mysqltestbug36570_p2`;
drop function mysqltestbug36570_f1;
--echo End of 5.0 tests
--echo End of 5.1 tests
+
+# Cleanup
+sync_slave_with_master;
diff --git a/mysql-test/suite/rpl/t/rpl_temporary.test b/mysql-test/suite/rpl/t/rpl_temporary.test
index 4e83d39710c..a59e4f2fd21 100644
--- a/mysql-test/suite/rpl/t/rpl_temporary.test
+++ b/mysql-test/suite/rpl/t/rpl_temporary.test
@@ -22,6 +22,77 @@ call mtr.add_suppression("Slave: Can\'t find record in \'user\' Error_code: 1032
sync_with_master;
reset master;
+
+# ##################################################################
+# BUG#41725: slave crashes when inserting into temporary table after
+# stop/start slave
+#
+# This test checks that both reported issues (assertion failure and
+# crash) go away. It is implemented as follows:
+#
+# case 1: assertion failure
+# i) create and insert into temporary table on master
+# ii) sync slave with master
+# iii) stop and restart slave
+# iv) insert into master another value
+# v) sync slave with master
+#
+#
+# case 2: crash (SIGSEV)
+# i) create and insert into temporary table on master (insert
+# produces warnings)
+# ii) sync slave with master
+# iii) stop and restart slave
+# iv) insert into master more values
+# v) sync slave with master
+
+# case 1: Assertion in Field_string::store() failed because current
+# thread reference differed from table->in_use after slave
+# restart
+
+connection master;
+
+disable_warnings;
+DROP TABLE IF EXISTS t1;
+enable_warnings;
+
+CREATE TEMPORARY TABLE t1 (a char(1));
+INSERT INTO t1 VALUES ('a');
+sync_slave_with_master;
+
+source include/stop_slave.inc;
+source include/start_slave.inc;
+
+connection master;
+INSERT INTO t1 VALUES ('b');
+sync_slave_with_master;
+
+# case 2: crash on sp_rcontext::find_handler because it used
+# reference to invalid THD object after slave restart
+
+connection master;
+
+disable_warnings;
+DROP TABLE IF EXISTS t1;
+enable_warnings;
+CREATE TEMPORARY TABLE `t1`(`a` tinyint,`b` char(1))engine=myisam;
+INSERT INTO `t1` set `a`=128,`b`='128';
+
+sync_slave_with_master;
+
+source include/stop_slave.inc;
+source include/start_slave.inc;
+
+connection master;
+INSERT INTO `t1` set `a`=128,`b`='128';
+sync_slave_with_master;
+
+# cleanup
+
+connection master;
+DROP TABLE t1;
+sync_slave_with_master;
+
connection master;
connect (con1,localhost,root,,);
diff --git a/mysql-test/suite/rpl_ndb/r/rpl_ndb_log.result b/mysql-test/suite/rpl_ndb/r/rpl_ndb_log.result
index 5b6ca5f5097..540c430e757 100644
--- a/mysql-test/suite/rpl_ndb/r/rpl_ndb_log.result
+++ b/mysql-test/suite/rpl_ndb/r/rpl_ndb_log.result
@@ -317,14 +317,14 @@ insert into t1 values (NULL, last_insert_id()), (NULL, last_insert_id());
show binlog events from ;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Query # # use `test`; create table t1(a int auto_increment primary key, b int)
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
-master-bin.000001 # Query # # use `test`; COMMIT
-master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Query # # COMMIT
+master-bin.000001 # Query # # BEGIN
master-bin.000001 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
-master-bin.000001 # Query # # use `test`; COMMIT
+master-bin.000001 # Query # # COMMIT
select * from t1;
a b
1 1
diff --git a/mysql-test/suite/rpl_ndb/r/rpl_ndb_stm_innodb.result b/mysql-test/suite/rpl_ndb/r/rpl_ndb_stm_innodb.result
index db9920dd79f..675a69d17a4 100644
--- a/mysql-test/suite/rpl_ndb/r/rpl_ndb_stm_innodb.result
+++ b/mysql-test/suite/rpl_ndb/r/rpl_ndb_stm_innodb.result
@@ -28,7 +28,7 @@ from mysql.ndb_apply_status;
show binlog events from limit 1;
Log_name Pos Event_type Server_id End_log_pos Info
-master-bin.000001 Query 1 # use `test`; BEGIN
+master-bin.000001 Query 1 # BEGIN
# Now the insert, one step after
@@ -53,7 +53,7 @@ from mysql.ndb_apply_status;
show binlog events from limit 1;
Log_name Pos Event_type Server_id End_log_pos Info
-master-bin.000001 Query 1 # use `test`; BEGIN
+master-bin.000001 Query 1 # BEGIN
show binlog events from limit 1,2;
Log_name Pos Event_type Server_id End_log_pos Info
diff --git a/mysql-test/suite/rpl_ndb/t/disabled.def b/mysql-test/suite/rpl_ndb/t/disabled.def
index 6908269d014..2f15112515e 100644
--- a/mysql-test/suite/rpl_ndb/t/disabled.def
+++ b/mysql-test/suite/rpl_ndb/t/disabled.def
@@ -11,3 +11,4 @@
##############################################################################
# the below testcase have been reworked to avoid the bug, test contains comment, keep bug open
+rpl_ndb_2ndb : Bug#45974: rpl_ndb_2ndb fails sporadically
diff --git a/mysql-test/suite/rpl_ndb/t/rpl_ndb_2other-slave.opt b/mysql-test/suite/rpl_ndb/t/rpl_ndb_2other-slave.opt
index 188b31efa8a..dff423702b4 100644
--- a/mysql-test/suite/rpl_ndb/t/rpl_ndb_2other-slave.opt
+++ b/mysql-test/suite/rpl_ndb/t/rpl_ndb_2other-slave.opt
@@ -1 +1 @@
---innodb --ndbcluster=0 --log-slave-updates=0
+--innodb --loose-ndbcluster=OFF --log-slave-updates=0
diff --git a/mysql-test/suite/sys_vars/r/innodb_data_home_dir_basic.result b/mysql-test/suite/sys_vars/r/innodb_data_home_dir_basic.result
index e4bdd79b7c3..52a97bb6c95 100644
--- a/mysql-test/suite/sys_vars/r/innodb_data_home_dir_basic.result
+++ b/mysql-test/suite/sys_vars/r/innodb_data_home_dir_basic.result
@@ -1,16 +1,16 @@
'#---------------------BS_STVARS_025_01----------------------#'
SELECT COUNT(@@GLOBAL.innodb_data_home_dir);
COUNT(@@GLOBAL.innodb_data_home_dir)
-1
-1 Expected
+0
+0 Expected
'#---------------------BS_STVARS_025_02----------------------#'
SET @@GLOBAL.innodb_data_home_dir=1;
ERROR HY000: Variable 'innodb_data_home_dir' is a read only variable
Expected error 'Read only variable'
SELECT COUNT(@@GLOBAL.innodb_data_home_dir);
COUNT(@@GLOBAL.innodb_data_home_dir)
-1
-1 Expected
+0
+0 Expected
'#---------------------BS_STVARS_025_03----------------------#'
SELECT @@GLOBAL.innodb_data_home_dir = VARIABLE_VALUE
FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES
@@ -20,8 +20,8 @@ NULL
1 Expected
SELECT COUNT(@@GLOBAL.innodb_data_home_dir);
COUNT(@@GLOBAL.innodb_data_home_dir)
-1
-1 Expected
+0
+0 Expected
SELECT COUNT(VARIABLE_VALUE)
FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES
WHERE VARIABLE_NAME='innodb_data_home_dir';
@@ -36,8 +36,8 @@ NULL
'#---------------------BS_STVARS_025_05----------------------#'
SELECT COUNT(@@innodb_data_home_dir);
COUNT(@@innodb_data_home_dir)
-1
-1 Expected
+0
+0 Expected
SELECT COUNT(@@local.innodb_data_home_dir);
ERROR HY000: Variable 'innodb_data_home_dir' is a GLOBAL variable
Expected error 'Variable is a GLOBAL variable'
@@ -46,8 +46,8 @@ ERROR HY000: Variable 'innodb_data_home_dir' is a GLOBAL variable
Expected error 'Variable is a GLOBAL variable'
SELECT COUNT(@@GLOBAL.innodb_data_home_dir);
COUNT(@@GLOBAL.innodb_data_home_dir)
-1
-1 Expected
+0
+0 Expected
SELECT innodb_data_home_dir = @@SESSION.innodb_data_home_dir;
ERROR 42S22: Unknown column 'innodb_data_home_dir' in 'field list'
Expected error 'Readonly variable'
diff --git a/mysql-test/suite/sys_vars/r/innodb_flush_method_basic.result b/mysql-test/suite/sys_vars/r/innodb_flush_method_basic.result
index 8c8924cdd86..4a85748092d 100644
--- a/mysql-test/suite/sys_vars/r/innodb_flush_method_basic.result
+++ b/mysql-test/suite/sys_vars/r/innodb_flush_method_basic.result
@@ -1,16 +1,16 @@
'#---------------------BS_STVARS_029_01----------------------#'
SELECT COUNT(@@GLOBAL.innodb_flush_method);
COUNT(@@GLOBAL.innodb_flush_method)
-1
-1 Expected
+0
+0 Expected
'#---------------------BS_STVARS_029_02----------------------#'
SET @@GLOBAL.innodb_flush_method=1;
ERROR HY000: Variable 'innodb_flush_method' is a read only variable
Expected error 'Read only variable'
SELECT COUNT(@@GLOBAL.innodb_flush_method);
COUNT(@@GLOBAL.innodb_flush_method)
-1
-1 Expected
+0
+0 Expected
'#---------------------BS_STVARS_029_03----------------------#'
SELECT @@GLOBAL.innodb_flush_method = VARIABLE_VALUE
FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES
@@ -20,8 +20,8 @@ NULL
1 Expected
SELECT COUNT(@@GLOBAL.innodb_flush_method);
COUNT(@@GLOBAL.innodb_flush_method)
-1
-1 Expected
+0
+0 Expected
SELECT COUNT(VARIABLE_VALUE)
FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES
WHERE VARIABLE_NAME='innodb_flush_method';
@@ -36,8 +36,8 @@ NULL
'#---------------------BS_STVARS_029_05----------------------#'
SELECT COUNT(@@innodb_flush_method);
COUNT(@@innodb_flush_method)
-1
-1 Expected
+0
+0 Expected
SELECT COUNT(@@local.innodb_flush_method);
ERROR HY000: Variable 'innodb_flush_method' is a GLOBAL variable
Expected error 'Variable is a GLOBAL variable'
@@ -46,8 +46,8 @@ ERROR HY000: Variable 'innodb_flush_method' is a GLOBAL variable
Expected error 'Variable is a GLOBAL variable'
SELECT COUNT(@@GLOBAL.innodb_flush_method);
COUNT(@@GLOBAL.innodb_flush_method)
-1
-1 Expected
+0
+0 Expected
SELECT innodb_flush_method = @@SESSION.innodb_flush_method;
ERROR 42S22: Unknown column 'innodb_flush_method' in 'field list'
Expected error 'Readonly variable'
diff --git a/mysql-test/suite/sys_vars/r/rpl_init_slave_func.result b/mysql-test/suite/sys_vars/r/rpl_init_slave_func.result
index 5f730bff882..bdb586e84c2 100644
--- a/mysql-test/suite/sys_vars/r/rpl_init_slave_func.result
+++ b/mysql-test/suite/sys_vars/r/rpl_init_slave_func.result
@@ -12,7 +12,7 @@ DROP TABLE IF EXISTS t1;
CREATE TEMPORARY TABLE t1 AS SELECT @@global.init_slave AS my_column;
DESCRIBE t1;
Field Type Null Key Default Extra
-my_column varchar(59) NO
+my_column varchar(59) YES NULL
DROP TABLE t1;
SELECT @@global.init_slave = 'SET @@global.max_connections = @@global.max_connections + 1';
@@global.init_slave = 'SET @@global.max_connections = @@global.max_connections + 1'
diff --git a/mysql-test/suite/sys_vars/r/ssl_capath_basic.result b/mysql-test/suite/sys_vars/r/ssl_capath_basic.result
index 3d161392917..f04b85b956f 100644
--- a/mysql-test/suite/sys_vars/r/ssl_capath_basic.result
+++ b/mysql-test/suite/sys_vars/r/ssl_capath_basic.result
@@ -1,16 +1,16 @@
'#---------------------BS_STVARS_046_01----------------------#'
SELECT COUNT(@@GLOBAL.ssl_capath);
COUNT(@@GLOBAL.ssl_capath)
-1
-1 Expected
+0
+0 Expected
'#---------------------BS_STVARS_046_02----------------------#'
SET @@GLOBAL.ssl_capath=1;
ERROR HY000: Variable 'ssl_capath' is a read only variable
Expected error 'Read only variable'
SELECT COUNT(@@GLOBAL.ssl_capath);
COUNT(@@GLOBAL.ssl_capath)
-1
-1 Expected
+0
+0 Expected
'#---------------------BS_STVARS_046_03----------------------#'
SELECT @@GLOBAL.ssl_capath = VARIABLE_VALUE
FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES
@@ -20,8 +20,8 @@ NULL
1 Expected
SELECT COUNT(@@GLOBAL.ssl_capath);
COUNT(@@GLOBAL.ssl_capath)
-1
-1 Expected
+0
+0 Expected
SELECT COUNT(VARIABLE_VALUE)
FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES
WHERE VARIABLE_NAME='ssl_capath';
@@ -36,8 +36,8 @@ NULL
'#---------------------BS_STVARS_046_05----------------------#'
SELECT COUNT(@@ssl_capath);
COUNT(@@ssl_capath)
-1
-1 Expected
+0
+0 Expected
SELECT COUNT(@@local.ssl_capath);
ERROR HY000: Variable 'ssl_capath' is a GLOBAL variable
Expected error 'Variable is a GLOBAL variable'
@@ -46,8 +46,8 @@ ERROR HY000: Variable 'ssl_capath' is a GLOBAL variable
Expected error 'Variable is a GLOBAL variable'
SELECT COUNT(@@GLOBAL.ssl_capath);
COUNT(@@GLOBAL.ssl_capath)
-1
-1 Expected
+0
+0 Expected
SELECT ssl_capath = @@SESSION.ssl_capath;
ERROR 42S22: Unknown column 'ssl_capath' in 'field list'
Expected error 'Readonly variable'
diff --git a/mysql-test/suite/sys_vars/r/ssl_cipher_basic.result b/mysql-test/suite/sys_vars/r/ssl_cipher_basic.result
index df0fc8b5aad..0eed40d0580 100644
--- a/mysql-test/suite/sys_vars/r/ssl_cipher_basic.result
+++ b/mysql-test/suite/sys_vars/r/ssl_cipher_basic.result
@@ -1,16 +1,16 @@
'#---------------------BS_STVARS_048_01----------------------#'
SELECT COUNT(@@GLOBAL.ssl_cipher);
COUNT(@@GLOBAL.ssl_cipher)
-1
-1 Expected
+0
+0 Expected
'#---------------------BS_STVARS_048_02----------------------#'
SET @@GLOBAL.ssl_cipher=1;
ERROR HY000: Variable 'ssl_cipher' is a read only variable
Expected error 'Read only variable'
SELECT COUNT(@@GLOBAL.ssl_cipher);
COUNT(@@GLOBAL.ssl_cipher)
-1
-1 Expected
+0
+0 Expected
'#---------------------BS_STVARS_048_03----------------------#'
SELECT @@GLOBAL.ssl_cipher = VARIABLE_VALUE
FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES
@@ -20,8 +20,8 @@ NULL
1 Expected
SELECT COUNT(@@GLOBAL.ssl_cipher);
COUNT(@@GLOBAL.ssl_cipher)
-1
-1 Expected
+0
+0 Expected
SELECT COUNT(VARIABLE_VALUE)
FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES
WHERE VARIABLE_NAME='ssl_cipher';
@@ -36,8 +36,8 @@ NULL
'#---------------------BS_STVARS_048_05----------------------#'
SELECT COUNT(@@ssl_cipher);
COUNT(@@ssl_cipher)
-1
-1 Expected
+0
+0 Expected
SELECT COUNT(@@local.ssl_cipher);
ERROR HY000: Variable 'ssl_cipher' is a GLOBAL variable
Expected error 'Variable is a GLOBAL variable'
@@ -46,8 +46,8 @@ ERROR HY000: Variable 'ssl_cipher' is a GLOBAL variable
Expected error 'Variable is a GLOBAL variable'
SELECT COUNT(@@GLOBAL.ssl_cipher);
COUNT(@@GLOBAL.ssl_cipher)
-1
-1 Expected
+0
+0 Expected
SELECT ssl_cipher = @@SESSION.ssl_cipher;
ERROR 42S22: Unknown column 'ssl_cipher' in 'field list'
Expected error 'Readonly variable'
diff --git a/mysql-test/suite/sys_vars/t/innodb_data_home_dir_basic.test b/mysql-test/suite/sys_vars/t/innodb_data_home_dir_basic.test
index f3b02edf83b..acf3741d5fa 100644
--- a/mysql-test/suite/sys_vars/t/innodb_data_home_dir_basic.test
+++ b/mysql-test/suite/sys_vars/t/innodb_data_home_dir_basic.test
@@ -29,7 +29,7 @@
# Displaying default value #
####################################################################
SELECT COUNT(@@GLOBAL.innodb_data_home_dir);
---echo 1 Expected
+--echo 0 Expected
--echo '#---------------------BS_STVARS_025_02----------------------#'
@@ -42,7 +42,7 @@ SET @@GLOBAL.innodb_data_home_dir=1;
--echo Expected error 'Read only variable'
SELECT COUNT(@@GLOBAL.innodb_data_home_dir);
---echo 1 Expected
+--echo 0 Expected
@@ -58,7 +58,7 @@ WHERE VARIABLE_NAME='innodb_data_home_dir';
--echo 1 Expected
SELECT COUNT(@@GLOBAL.innodb_data_home_dir);
---echo 1 Expected
+--echo 0 Expected
SELECT COUNT(VARIABLE_VALUE)
FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES
@@ -82,7 +82,7 @@ SELECT @@innodb_data_home_dir = @@GLOBAL.innodb_data_home_dir;
################################################################################
SELECT COUNT(@@innodb_data_home_dir);
---echo 1 Expected
+--echo 0 Expected
--Error ER_INCORRECT_GLOBAL_LOCAL_VAR
SELECT COUNT(@@local.innodb_data_home_dir);
@@ -93,7 +93,7 @@ SELECT COUNT(@@SESSION.innodb_data_home_dir);
--echo Expected error 'Variable is a GLOBAL variable'
SELECT COUNT(@@GLOBAL.innodb_data_home_dir);
---echo 1 Expected
+--echo 0 Expected
--Error ER_BAD_FIELD_ERROR
SELECT innodb_data_home_dir = @@SESSION.innodb_data_home_dir;
diff --git a/mysql-test/suite/sys_vars/t/innodb_flush_method_basic.test b/mysql-test/suite/sys_vars/t/innodb_flush_method_basic.test
index 531df4a2464..75af00e33af 100644
--- a/mysql-test/suite/sys_vars/t/innodb_flush_method_basic.test
+++ b/mysql-test/suite/sys_vars/t/innodb_flush_method_basic.test
@@ -29,7 +29,7 @@
# Displaying default value #
####################################################################
SELECT COUNT(@@GLOBAL.innodb_flush_method);
---echo 1 Expected
+--echo 0 Expected
--echo '#---------------------BS_STVARS_029_02----------------------#'
@@ -42,7 +42,7 @@ SET @@GLOBAL.innodb_flush_method=1;
--echo Expected error 'Read only variable'
SELECT COUNT(@@GLOBAL.innodb_flush_method);
---echo 1 Expected
+--echo 0 Expected
@@ -58,7 +58,7 @@ WHERE VARIABLE_NAME='innodb_flush_method';
--echo 1 Expected
SELECT COUNT(@@GLOBAL.innodb_flush_method);
---echo 1 Expected
+--echo 0 Expected
SELECT COUNT(VARIABLE_VALUE)
FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES
@@ -82,7 +82,7 @@ SELECT @@innodb_flush_method = @@GLOBAL.innodb_flush_method;
################################################################################
SELECT COUNT(@@innodb_flush_method);
---echo 1 Expected
+--echo 0 Expected
--Error ER_INCORRECT_GLOBAL_LOCAL_VAR
SELECT COUNT(@@local.innodb_flush_method);
@@ -93,7 +93,7 @@ SELECT COUNT(@@SESSION.innodb_flush_method);
--echo Expected error 'Variable is a GLOBAL variable'
SELECT COUNT(@@GLOBAL.innodb_flush_method);
---echo 1 Expected
+--echo 0 Expected
--Error ER_BAD_FIELD_ERROR
SELECT innodb_flush_method = @@SESSION.innodb_flush_method;
diff --git a/mysql-test/suite/sys_vars/t/ssl_capath_basic.test b/mysql-test/suite/sys_vars/t/ssl_capath_basic.test
index c32b572fb1b..ece9fe992d9 100644
--- a/mysql-test/suite/sys_vars/t/ssl_capath_basic.test
+++ b/mysql-test/suite/sys_vars/t/ssl_capath_basic.test
@@ -27,7 +27,7 @@
# Displaying default value #
####################################################################
SELECT COUNT(@@GLOBAL.ssl_capath);
---echo 1 Expected
+--echo 0 Expected
--echo '#---------------------BS_STVARS_046_02----------------------#'
@@ -40,7 +40,7 @@ SET @@GLOBAL.ssl_capath=1;
--echo Expected error 'Read only variable'
SELECT COUNT(@@GLOBAL.ssl_capath);
---echo 1 Expected
+--echo 0 Expected
@@ -56,7 +56,7 @@ WHERE VARIABLE_NAME='ssl_capath';
--echo 1 Expected
SELECT COUNT(@@GLOBAL.ssl_capath);
---echo 1 Expected
+--echo 0 Expected
SELECT COUNT(VARIABLE_VALUE)
FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES
@@ -80,7 +80,7 @@ SELECT @@ssl_capath = @@GLOBAL.ssl_capath;
################################################################################
SELECT COUNT(@@ssl_capath);
---echo 1 Expected
+--echo 0 Expected
--Error ER_INCORRECT_GLOBAL_LOCAL_VAR
SELECT COUNT(@@local.ssl_capath);
@@ -91,7 +91,7 @@ SELECT COUNT(@@SESSION.ssl_capath);
--echo Expected error 'Variable is a GLOBAL variable'
SELECT COUNT(@@GLOBAL.ssl_capath);
---echo 1 Expected
+--echo 0 Expected
--Error ER_BAD_FIELD_ERROR
SELECT ssl_capath = @@SESSION.ssl_capath;
diff --git a/mysql-test/suite/sys_vars/t/ssl_cipher_basic.test b/mysql-test/suite/sys_vars/t/ssl_cipher_basic.test
index 425f7aae442..c58b22da2d5 100644
--- a/mysql-test/suite/sys_vars/t/ssl_cipher_basic.test
+++ b/mysql-test/suite/sys_vars/t/ssl_cipher_basic.test
@@ -27,7 +27,7 @@
# Displaying default value #
####################################################################
SELECT COUNT(@@GLOBAL.ssl_cipher);
---echo 1 Expected
+--echo 0 Expected
--echo '#---------------------BS_STVARS_048_02----------------------#'
@@ -40,7 +40,7 @@ SET @@GLOBAL.ssl_cipher=1;
--echo Expected error 'Read only variable'
SELECT COUNT(@@GLOBAL.ssl_cipher);
---echo 1 Expected
+--echo 0 Expected
@@ -56,7 +56,7 @@ WHERE VARIABLE_NAME='ssl_cipher';
--echo 1 Expected
SELECT COUNT(@@GLOBAL.ssl_cipher);
---echo 1 Expected
+--echo 0 Expected
SELECT COUNT(VARIABLE_VALUE)
FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES
@@ -80,7 +80,7 @@ SELECT @@ssl_cipher = @@GLOBAL.ssl_cipher;
################################################################################
SELECT COUNT(@@ssl_cipher);
---echo 1 Expected
+--echo 0 Expected
--Error ER_INCORRECT_GLOBAL_LOCAL_VAR
SELECT COUNT(@@local.ssl_cipher);
@@ -91,7 +91,7 @@ SELECT COUNT(@@SESSION.ssl_cipher);
--echo Expected error 'Variable is a GLOBAL variable'
SELECT COUNT(@@GLOBAL.ssl_cipher);
---echo 1 Expected
+--echo 0 Expected
--Error ER_BAD_FIELD_ERROR
SELECT ssl_cipher = @@SESSION.ssl_cipher;
diff --git a/mysql-test/t/archive_bitfield.test b/mysql-test/t/archive_bitfield.test
index 1e4692270b5..2e90ce39708 100644
--- a/mysql-test/t/archive_bitfield.test
+++ b/mysql-test/t/archive_bitfield.test
@@ -94,5 +94,11 @@ INSERT INTO `t1` VALUES
(NULL,1,1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,b'100000',b'010010',b'011111',4,5,5,5,5,5,5,5,5,5,3,2,1),
(NULL,1,1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,b'000000',b'001100',b'111111',4,5,5,5,5,5,5,5,5,5,3,2,1),
(NULL,1,1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,b'111111',b'000000',b'000000',4,5,5,5,5,5,5,5,5,5,3,2,1);
+# Determine the number of open sessions
+--source include/count_sessions.inc
--exec $MYSQL_DUMP --hex-blob --compact --order-by-primary --skip-extended-insert --no-create-info test t1
drop table t1;
+# Wait till the number of open sessions is <= the number before the run with $MYSQL_DUMP
+# = The session caused by mysqldump has finished its disconnect
+--source include/wait_until_count_sessions.inc
+
diff --git a/mysql-test/t/bug46080-master.opt b/mysql-test/t/bug46080-master.opt
new file mode 100644
index 00000000000..f59740afe60
--- /dev/null
+++ b/mysql-test/t/bug46080-master.opt
@@ -0,0 +1 @@
+--skip-grant-tables --skip-name-resolve --safemalloc-mem-limit=4000000
diff --git a/mysql-test/t/bug46080.test b/mysql-test/t/bug46080.test
new file mode 100644
index 00000000000..7e56e3ce421
--- /dev/null
+++ b/mysql-test/t/bug46080.test
@@ -0,0 +1,22 @@
+--echo #
+--echo # Bug #46080: group_concat(... order by) crashes server when
+--echo # sort_buffer_size cannot allocate
+--echo #
+
+CREATE TABLE t1(a CHAR(255));
+INSERT INTO t1 VALUES ('a');
+
+SET @@SESSION.sort_buffer_size=5*16*1000000;
+SET @@SESSION.max_heap_table_size=5*1000000;
+
+--echo # Must not crash.
+--disable_result_log
+--error 0,5
+SELECT GROUP_CONCAT(a ORDER BY a) FROM t1 GROUP BY a;
+--enable_result_log
+
+DROP TABLE t1;
+SET @@SESSION.sort_buffer_size=default;
+SET @@SESSION.max_heap_table_size=default;
+
+--echo End of 5.0 tests
diff --git a/mysql-test/t/cast.test b/mysql-test/t/cast.test
index 50865215944..8e60d548c2f 100644
--- a/mysql-test/t/cast.test
+++ b/mysql-test/t/cast.test
@@ -269,3 +269,18 @@ SELECT HOUR(NULL),
DROP TABLE t1;
--echo End of 5.0 tests
+
+--echo #
+--echo # Bug #44766: valgrind error when using convert() in a subquery
+--echo #
+
+CREATE TABLE t1(a tinyint);
+INSERT INTO t1 VALUES (127);
+SELECT 1 FROM
+(
+ SELECT CONVERT(t2.a USING UTF8) FROM t1, t1 t2 LIMIT 1
+) AS s LIMIT 1;
+DROP TABLE t1;
+
+
+--echo End of 5.1 tests
diff --git a/mysql-test/t/client_xml.test b/mysql-test/t/client_xml.test
index 739b56f5ab1..0847e2b366b 100644
--- a/mysql-test/t/client_xml.test
+++ b/mysql-test/t/client_xml.test
@@ -18,6 +18,10 @@ create table t1 (
`a>b` text
);
insert into t1 values (1, 2, 'a&b ab');
+
+# Determine the number of open sessions
+--source include/count_sessions.inc
+
--exec $MYSQL --xml test -e "select * from t1"
--exec $MYSQL_DUMP --xml --skip-create test
@@ -33,3 +37,8 @@ drop table t1;
# Restore global concurrent_insert value
set @@global.concurrent_insert= @old_concurrent_insert;
+
+# Wait till the number of open sessions is <= the number before the runs with
+# $MYSQL and $MYSQL_DUMP
+# = The session caused by mysql and mysqldump have finished their disconnect
+--source include/wait_until_count_sessions.inc
diff --git a/mysql-test/t/connect.test b/mysql-test/t/connect.test
index f609240646a..9a29e4ff861 100644
--- a/mysql-test/t/connect.test
+++ b/mysql-test/t/connect.test
@@ -55,7 +55,8 @@ disconnect con4;
connect (fail_con,localhost,test,,test2);
--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT
--error ER_ACCESS_DENIED_ERROR
-connect (fail_con,localhost,test,,"");
+# Need to protect "" within '' so it's interpreted literally
+connect (fail_con,localhost,test,,'""');
--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT
--error ER_ACCESS_DENIED_ERROR
connect (fail_con,localhost,test,zorro,test2);
diff --git a/mysql-test/t/consistent_snapshot.test b/mysql-test/t/consistent_snapshot.test
index 82edf2e22b2..fb1f3bc007c 100644
--- a/mysql-test/t/consistent_snapshot.test
+++ b/mysql-test/t/consistent_snapshot.test
@@ -12,9 +12,9 @@ connect (con1,localhost,root,,);
--echo # Establish connection con2 (user=root)
connect (con2,localhost,root,,);
-### Test 1:
-### - While a consistent snapshot transaction is executed,
-### no external inserts should be visible to the transaction.
+--echo ### Test 1:
+--echo ### - While a consistent snapshot transaction is executed,
+--echo ### no external inserts should be visible to the transaction.
--echo # Switch to connection con1
connection con1;
@@ -31,9 +31,9 @@ SELECT * FROM t1; # if consistent snapshot was set as expected, we
# should see nothing.
COMMIT;
-### Test 2:
-### - For any non-consistent snapshot transaction, external
-### committed inserts should be visible to the transaction.
+--echo ### Test 2:
+--echo ### - For any non-consistent snapshot transaction, external
+--echo ### committed inserts should be visible to the transaction.
DELETE FROM t1;
START TRANSACTION; # Now we omit WITH CONSISTENT SNAPSHOT
@@ -48,6 +48,24 @@ SELECT * FROM t1; # if consistent snapshot was not set, as expected, we
# should see 1.
COMMIT;
+--echo ### Test 3:
+--echo ### - Bug#44664: valgrind warning for COMMIT_AND_CHAIN and ROLLBACK_AND_CHAIN
+--echo ### Chaining a transaction does not retain consistency level.
+
+START TRANSACTION WITH CONSISTENT SNAPSHOT;
+DELETE FROM t1;
+COMMIT WORK AND CHAIN;
+
+--echo # Switch to connection con2
+connection con2;
+INSERT INTO t1 VALUES(1);
+
+--echo # Switch to connection con1
+connection con1;
+SELECT * FROM t1; # if consistent snapshot was not set, as expected, we
+# should see 1.
+COMMIT;
+
--echo # Switch to connection default + close connections con1 and con2
connection default;
disconnect con1;
diff --git a/mysql-test/t/count_distinct3.test b/mysql-test/t/count_distinct3.test
index 2f7cf7e5260..ad2bbee95a3 100644
--- a/mysql-test/t/count_distinct3.test
+++ b/mysql-test/t/count_distinct3.test
@@ -3,6 +3,8 @@
# mysql-4.1
#
+--source include/big_test.inc
+
--disable_warnings
DROP TABLE IF EXISTS t1, t2;
--enable_warnings
diff --git a/mysql-test/t/csv.test b/mysql-test/t/csv.test
index abc161d014c..cdf274190dd 100644
--- a/mysql-test/t/csv.test
+++ b/mysql-test/t/csv.test
@@ -1800,10 +1800,11 @@ connect (con1,localhost,root,,);
# EE_FILENOTFOUND 29
--error 29
select * from t1;
+--disconnect con1
+--source include/wait_until_disconnected.inc
connection default;
unlock tables;
drop table t1;
---disconnect con1
#
# Bug#41441 repair csv table crashes debug server
diff --git a/mysql-test/t/ctype_cp932_binlog_stm.test b/mysql-test/t/ctype_cp932_binlog_stm.test
index 383009ae7c3..89df33a6df5 100644
--- a/mysql-test/t/ctype_cp932_binlog_stm.test
+++ b/mysql-test/t/ctype_cp932_binlog_stm.test
@@ -22,7 +22,7 @@ CALL bug18293("Foo's a Bar", _cp932 0xED40ED41ED42, 47.93)|
SELECT HEX(s1),HEX(s2),d FROM t4|
DROP PROCEDURE bug18293|
DROP TABLE t4|
-SHOW BINLOG EVENTS FROM 369|
+SHOW BINLOG EVENTS FROM 370|
delimiter ;|
--echo End of 5.0 tests
@@ -31,7 +31,14 @@ delimiter ;|
# #28436: Incorrect position in SHOW BINLOG EVENTS causes server coredump
# Note: 364 is a magic position (found experimentally, depends on
# the log's contents) that caused the server crash.
+
--error 1220
-SHOW BINLOG EVENTS FROM 364;
+SHOW BINLOG EVENTS FROM 365;
+
+--echo Bug#44352 UPPER/LOWER function doesn't work correctly on cp932 and sjis environment.
+CREATE TABLE t1 (a varchar(16)) character set cp932;
+INSERT INTO t1 VALUES (0x8372835E),(0x8352835E);
+SELECT hex(a), hex(lower(a)), hex(upper(a)) FROM t1 ORDER BY binary(a);
+DROP TABLE t1;
--echo End of 5.1 tests
diff --git a/mysql-test/t/ctype_gbk_binlog.test b/mysql-test/t/ctype_gbk_binlog.test
new file mode 100644
index 00000000000..a8f653d1b1e
--- /dev/null
+++ b/mysql-test/t/ctype_gbk_binlog.test
@@ -0,0 +1,36 @@
+-- source include/have_binlog_format_mixed_or_statement.inc
+-- source include/have_gbk.inc
+
+SET NAMES gbk;
+--character_set gbk
+
+CREATE TABLE t1 (
+ f1 BLOB
+) ENGINE=MyISAM DEFAULT CHARSET=gbk;
+
+delimiter |;
+CREATE PROCEDURE p1(IN val BLOB)
+BEGIN
+ SET @tval = val;
+ SET @sql_cmd = CONCAT_WS(' ', 'insert into t1(f1) values(?)');
+ PREPARE stmt FROM @sql_cmd;
+ EXECUTE stmt USING @tval;
+ DEALLOCATE PREPARE stmt;
+END|
+delimiter ;|
+
+SET @`tcontent`:=_binary 0x50434B000900000000000000E9000000 COLLATE `binary`/*!*/;
+CALL p1(@`tcontent`);
+
+FLUSH LOGS;
+DROP PROCEDURE p1;
+RENAME TABLE t1 to t2;
+
+let $MYSQLD_DATADIR= `select @@datadir`;
+--exec $MYSQL_BINLOG --force-if-open --short-form $MYSQLD_DATADIR/master-bin.000001 | $MYSQL
+SELECT hex(f1) FROM t2;
+SELECT hex(f1) FROM t1;
+
+DROP PROCEDURE p1;
+DROP TABLE t1;
+DROP TABLE t2;
diff --git a/mysql-test/t/ctype_ldml.test b/mysql-test/t/ctype_ldml.test
index 73a23a751e8..db9461bfbf7 100644
--- a/mysql-test/t/ctype_ldml.test
+++ b/mysql-test/t/ctype_ldml.test
@@ -37,6 +37,15 @@ UPDATE t1 SET col2=col1;
SELECT * FROM t1 WHERE col1=col2 ORDER BY col1;
DROP TABLE t1;
+--echo #
+--echo # Bug#43827 Server closes connections and restarts
+--echo #
+# Crash happened with a user-defined utf8 collation,
+# on attempt to insert a string longer than the column can store.
+CREATE TABLE t1 (c1 VARCHAR(10) CHARACTER SET utf8 COLLATE utf8_test_ci);
+INSERT INTO t1 SELECT REPEAT('a',11);
+DROP TABLE t1;
+
#
# Vietnamese experimental collation
#
diff --git a/mysql-test/t/ctype_sjis.test b/mysql-test/t/ctype_sjis.test
index 27cbdff451b..7de94e34dea 100644
--- a/mysql-test/t/ctype_sjis.test
+++ b/mysql-test/t/ctype_sjis.test
@@ -83,3 +83,13 @@ SET NAMES sjis;
SELECT HEX('²“‘@Œ\') FROM DUAL;
# End of 4.1 tests
+
+--echo # Start of 5.1 tests
+
+--echo Bug#44352 UPPER/LOWER function doesn't work correctly on cp932 and sjis environment.
+CREATE TABLE t1 (a varchar(16)) character set sjis;
+INSERT INTO t1 VALUES (0x8372835E),(0x8352835E);
+SELECT hex(a), hex(lower(a)), hex(upper(a)) FROM t1 ORDER BY binary(a);
+DROP TABLE t1;
+
+--echo # End of 5.1 tests
diff --git a/mysql-test/t/ddl_i18n_koi8r.test b/mysql-test/t/ddl_i18n_koi8r.test
index 2d94a899aad..fecef2f95d5 100644
--- a/mysql-test/t/ddl_i18n_koi8r.test
+++ b/mysql-test/t/ddl_i18n_koi8r.test
@@ -1128,15 +1128,22 @@ SHOW CREATE TABLE mysqltest2.t2|
#
# Cleanup.
#
+delimiter ;|
+--connection con2
+--echo
+--echo ---> connection: con2
+--disconnect con2
+--source include/wait_until_disconnected.inc
+--connection con3
+--echo
+--echo ---> connection: con3
+--disconnect con3
+--source include/wait_until_disconnected.inc
--connection default
--echo
--echo ---> connection: default
+USE test;
+DROP DATABASE mysqltest1;
+DROP DATABASE mysqltest2;
---disconnect con2
---disconnect con3
-
-use test|
-
-DROP DATABASE mysqltest1|
-DROP DATABASE mysqltest2|
diff --git a/mysql-test/t/ddl_i18n_utf8.test b/mysql-test/t/ddl_i18n_utf8.test
index 1d5415d9373..8788d0604f2 100644
--- a/mysql-test/t/ddl_i18n_utf8.test
+++ b/mysql-test/t/ddl_i18n_utf8.test
@@ -1128,15 +1128,22 @@ SHOW CREATE TABLE mysqltest2.t2|
#
# Cleanup.
#
+delimiter ;|
+--connection con2
+--echo
+--echo ---> connection: con2
+--disconnect con2
+--source include/wait_until_disconnected.inc
+--connection con3
+--echo
+--echo ---> connection: con3
+--disconnect con3
+--source include/wait_until_disconnected.inc
--connection default
--echo
--echo ---> connection: default
+USE test;
+DROP DATABASE mysqltest1;
+DROP DATABASE mysqltest2;
---disconnect con2
---disconnect con3
-
-use test|
-
-DROP DATABASE mysqltest1|
-DROP DATABASE mysqltest2|
diff --git a/mysql-test/t/derived.test b/mysql-test/t/derived.test
index 4e79fac584f..d28c19bbd18 100644
--- a/mysql-test/t/derived.test
+++ b/mysql-test/t/derived.test
@@ -273,8 +273,32 @@ select t2.* from ((select * from t1) as A inner join t2 on A.ID = t2.FID);
select t2.* from (select * from t1) as A inner join t2 on A.ID = t2.FID;
drop table t1, t2;
+connection con1;
disconnect con1;
+--source include/wait_until_disconnected.inc
connection default;
drop user mysqltest_1;
-# End of 4.1 tests
+--echo # End of 4.1 tests
+
+#
+# Bug #41156: List of derived tables acts like a chain of
+# mutually-nested subqueries
+#
+
+SELECT 0 FROM
+(SELECT 0) t01, (SELECT 0) t02, (SELECT 0) t03, (SELECT 0) t04, (SELECT 0) t05,
+(SELECT 0) t06, (SELECT 0) t07, (SELECT 0) t08, (SELECT 0) t09, (SELECT 0) t10,
+(SELECT 0) t11, (SELECT 0) t12, (SELECT 0) t13, (SELECT 0) t14, (SELECT 0) t15,
+(SELECT 0) t16, (SELECT 0) t17, (SELECT 0) t18, (SELECT 0) t19, (SELECT 0) t20,
+(SELECT 0) t21, (SELECT 0) t22, (SELECT 0) t23, (SELECT 0) t24, (SELECT 0) t25,
+(SELECT 0) t26, (SELECT 0) t27, (SELECT 0) t28, (SELECT 0) t29, (SELECT 0) t30,
+(SELECT 0) t31, (SELECT 0) t32, (SELECT 0) t33, (SELECT 0) t34, (SELECT 0) t35,
+(SELECT 0) t36, (SELECT 0) t37, (SELECT 0) t38, (SELECT 0) t39, (SELECT 0) t40,
+(SELECT 0) t41, (SELECT 0) t42, (SELECT 0) t43, (SELECT 0) t44, (SELECT 0) t45,
+(SELECT 0) t46, (SELECT 0) t47, (SELECT 0) t48, (SELECT 0) t49, (SELECT 0) t50,
+(SELECT 0) t51, (SELECT 0) t52, (SELECT 0) t53, (SELECT 0) t54, (SELECT 0) t55,
+(SELECT 0) t56, (SELECT 0) t57, (SELECT 0) t58, (SELECT 0) t59, (SELECT 0) t60,
+(SELECT 0) t61; # 61 == MAX_TABLES
+
+--echo # End of 5.0 tests
diff --git a/mysql-test/t/disabled.def b/mysql-test/t/disabled.def
index 760c29bbae6..5436b7166f4 100644
--- a/mysql-test/t/disabled.def
+++ b/mysql-test/t/disabled.def
@@ -10,8 +10,7 @@
#
##############################################################################
kill : Bug#37780 2008-12-03 HHunger need some changes to be robust enough for pushbuild.
-innodb_bug39438 : BUG#42383 2009-01-28 lsoares "This fails in embedded and on windows. Note that this test is not run on windows and on embedded in PB for main trees currently"
+innodb_bug39438 : Bug#42383 2009-01-28 lsoares "This fails in embedded and on windows. Note that this test is not run on windows and on embedded in PB for main trees currently"
query_cache_28249 : Bug#43861 2009-03-25 main.query_cache_28249 fails sporadically
+init_connect : Bug#44920 2009-07-06 pcrews MTR not processing master.opt input properly on Windows. *Must be done this way due to the nature of the bug*
-#concurrent_innodb_safelog: disabled for embedded server due to bug#43733 Select on processlist let the embedded server crash (concurrent_innodb_safelog).
-#concurrent_innodb_unsafelog: disabled for embedded server due to bug#43733.
diff --git a/mysql-test/t/drop.test b/mysql-test/t/drop.test
index 91345886e93..bb4dd3e11f9 100644
--- a/mysql-test/t/drop.test
+++ b/mysql-test/t/drop.test
@@ -117,8 +117,11 @@ connection addconroot1;
--reap
connection addconroot2;
--reap
-disconnect addconroot1;
disconnect addconroot2;
+--source include/wait_until_disconnected.inc
+connection addconroot1;
+disconnect addconroot1;
+--source include/wait_until_disconnected.inc
connection default;
--echo End of 5.0 tests
diff --git a/mysql-test/t/events_grant.test b/mysql-test/t/events_grant.test
index cff2475c5aa..8db4333cc03 100644
--- a/mysql-test/t/events_grant.test
+++ b/mysql-test/t/events_grant.test
@@ -97,7 +97,9 @@ DROP EVENT one_event;
connection default;
--echo "One event should not be there"
SELECT EVENT_CATALOG, EVENT_SCHEMA, EVENT_NAME, DEFINER, EVENT_BODY, EVENT_DEFINITION, EVENT_TYPE, EXECUTE_AT, INTERVAL_VALUE, INTERVAL_FIELD, STATUS,ON_COMPLETION, EVENT_COMMENT FROM INFORMATION_SCHEMA.EVENTS ORDER BY EVENT_SCHEMA, EVENT_NAME;
+connection ev_con1;
disconnect ev_con1;
+--source include/wait_until_disconnected.inc
connection default;
DROP USER ev_test@localhost;
DROP DATABASE events_test2;
@@ -106,9 +108,6 @@ DROP DATABASE events_test2;
# End of tests
#
-let $wait_condition=
- select count(*) = 0 from information_schema.processlist
- where db='events_test' and command = 'Connect' and user=current_user();
---source include/wait_condition.inc
+--source include/check_events_off.inc
DROP DATABASE events_test;
diff --git a/mysql-test/t/events_stress.test b/mysql-test/t/events_stress.test
index 22959898b43..e51fa734256 100644
--- a/mysql-test/t/events_stress.test
+++ b/mysql-test/t/events_stress.test
@@ -109,7 +109,7 @@ connection conn3;
--send
DROP DATABASE events_conn3_db;
connection default;
---send
+# --send
DROP DATABASE events_conn1_test2;
DROP DATABASE events_conn1_test3;
SET GLOBAL event_scheduler=off;
@@ -135,3 +135,7 @@ DROP USER event_user3@localhost;
#
DROP DATABASE events_test;
+
+# Cleanup
+SET GLOBAL event_scheduler=off;
+--source include/check_events_off.inc
diff --git a/mysql-test/t/events_trans_notembedded.test b/mysql-test/t/events_trans_notembedded.test
index 3c151dd18b1..0353d183386 100644
--- a/mysql-test/t/events_trans_notembedded.test
+++ b/mysql-test/t/events_trans_notembedded.test
@@ -50,6 +50,7 @@ delete from t1;
commit work;
# Cleanup
disconnect conn1;
+--source include/wait_until_disconnected.inc
connection default;
drop user mysqltest_user1@localhost;
drop database mysqltest_db2;
diff --git a/mysql-test/t/fix_priv_tables.test b/mysql-test/t/fix_priv_tables.test
index c7cd500f8d2..eeda9bc8d15 100644
--- a/mysql-test/t/fix_priv_tables.test
+++ b/mysql-test/t/fix_priv_tables.test
@@ -51,8 +51,13 @@ echo;
-- disable_query_log
# Run the mysql_fix_privilege_tables.sql using "mysql --force"
+# Determine the number of open sessions
+--source include/count_sessions.inc
--exec $MYSQL --force mysql < $MYSQL_FIX_PRIVILEGE_TABLES > $MYSQLTEST_VARDIR/tmp/fix_priv_tables.log 2>&1
--remove_file $MYSQLTEST_VARDIR/tmp/fix_priv_tables.log
+# Wait till the number of open sessions is <= the number before the run with $MYSQL
+# = The session caused by mysql has finished its disconnect
+--source include/wait_until_count_sessions.inc
-- enable_query_log
-- enable_result_log
diff --git a/mysql-test/t/flush.test b/mysql-test/t/flush.test
index c832cb79158..f27d4cf2fad 100644
--- a/mysql-test/t/flush.test
+++ b/mysql-test/t/flush.test
@@ -171,6 +171,7 @@ set session low_priority_updates=default;
connect (con1,localhost,root,,);
send select benchmark(200, (select sin(1))) > 1000;
disconnect con1;
+--source include/wait_until_disconnected.inc
connection default;
--echo End of 5.0 tests
diff --git a/mysql-test/t/func_compress.test b/mysql-test/t/func_compress.test
index 0a3a3823fee..d63130f190d 100644
--- a/mysql-test/t/func_compress.test
+++ b/mysql-test/t/func_compress.test
@@ -50,6 +50,7 @@ set @@global.max_allowed_packet=1048576*100;
--connect (newconn, localhost, root,,)
eval select compress(repeat('aaaaaaaaaa', IF('$LOW_MEMORY', 10, 10000000))) is null;
disconnect newconn;
+--source include/wait_until_disconnected.inc
connection default;
set @@global.max_allowed_packet=default;
@@ -88,4 +89,24 @@ select *, uncompress(a) from t1;
select *, uncompress(a), uncompress(a) is null from t1;
drop table t1;
+#
+# Bug #44796: valgrind: too many my_longlong10_to_str_8bit warnings after
+# uncompressed_length
+#
+
+CREATE TABLE t1 (c1 INT);
+INSERT INTO t1 VALUES (1), (1111), (11111);
+
+# Disable warnings to avoid dependency on max_allowed_packet value
+--disable_warnings
+SELECT UNCOMPRESS(c1), UNCOMPRESSED_LENGTH(c1) FROM t1;
+--enable_warnings
+
+# We do not need the results, just make sure there are no valgrind errors
+--disable_result_log
+EXPLAIN EXTENDED SELECT * FROM (SELECT UNCOMPRESSED_LENGTH(c1) FROM t1) AS s;
+--enable_result_log
+
+DROP TABLE t1;
+
--echo End of 5.0 tests
diff --git a/mysql-test/t/func_concat.test b/mysql-test/t/func_concat.test
index f2aa0d004e5..1c7e5823fb2 100644
--- a/mysql-test/t/func_concat.test
+++ b/mysql-test/t/func_concat.test
@@ -78,3 +78,37 @@ SELECT * FROM t1 WHERE CONCAT(c1,' ',c2) REGEXP 'First.*';
DROP TABLE t1;
--echo # End of 5.0 tests
+
+
+--echo #
+--echo # Bug #44743: Join in combination with concat does not always work
+--echo #
+CREATE TABLE t1 (
+ a VARCHAR(100) NOT NULL DEFAULT '0',
+ b VARCHAR(2) NOT NULL DEFAULT '',
+ c VARCHAR(2) NOT NULL DEFAULT '',
+ d TEXT NOT NULL,
+ PRIMARY KEY (a, b, c),
+ KEY (a)
+) DEFAULT CHARSET=utf8;
+
+INSERT INTO t1 VALUES ('gui_A', 'a', 'b', 'str1'),
+ ('gui_AB', 'a', 'b', 'str2'), ('gui_ABC', 'a', 'b', 'str3');
+
+CREATE TABLE t2 (
+ a VARCHAR(100) NOT NULL DEFAULT '',
+ PRIMARY KEY (a)
+) DEFAULT CHARSET=latin1;
+
+INSERT INTO t2 VALUES ('A'), ('AB'), ('ABC');
+
+SELECT CONCAT('gui_', t2.a), t1.d FROM t2
+ LEFT JOIN t1 ON t1.a = CONCAT('gui_', t2.a) AND t1.b = 'a' AND t1.c = 'b';
+
+EXPLAIN SELECT CONCAT('gui_', t2.a), t1.d FROM t2
+ LEFT JOIN t1 ON t1.a = CONCAT('gui_', t2.a) AND t1.b = 'a' AND t1.c = 'b';
+
+DROP TABLE t1, t2;
+
+
+--echo # End of 5.1 tests
diff --git a/mysql-test/t/func_crypt.test b/mysql-test/t/func_crypt.test
index cc3cdb9564d..6dedeaa0fef 100644
--- a/mysql-test/t/func_crypt.test
+++ b/mysql-test/t/func_crypt.test
@@ -56,3 +56,15 @@ explain extended select password('idkfa '), old_password('idkfa');
select encrypt('1234','_.');
# End of 4.1 tests
+
+--echo #
+--echo # Bug #44767: invalid memory reads in password() and old_password()
+--echo # functions
+--echo #
+
+CREATE TABLE t1(c1 MEDIUMBLOB);
+INSERT INTO t1 VALUES (REPEAT('a', 1024));
+SELECT OLD_PASSWORD(c1), PASSWORD(c1) FROM t1;
+DROP TABLE t1;
+
+--echo End of 5.0 tests
diff --git a/mysql-test/t/func_in.test b/mysql-test/t/func_in.test
index 3fc1697f146..adc074259ad 100644
--- a/mysql-test/t/func_in.test
+++ b/mysql-test/t/func_in.test
@@ -439,4 +439,21 @@ SELECT CASE c1 WHEN c1 + 1 THEN 1 END, ABS(AVG(c0)) FROM t1;
DROP TABLE t1;
+#
+# Bug #44399: crash with statement using TEXT columns, aggregates, GROUP BY,
+# and HAVING
+#
+
+CREATE TABLE t1(a TEXT, b INT, c INT UNSIGNED, d DECIMAL(12,2), e REAL);
+INSERT INTO t1 VALUES('iynfj', 1, 1, 1, 1);
+INSERT INTO t1 VALUES('innfj', 2, 2, 2, 2);
+SELECT SUM( DISTINCT a ) FROM t1 GROUP BY a HAVING a IN ( AVG( 1 ), 1 + a);
+SELECT SUM( DISTINCT b ) FROM t1 GROUP BY b HAVING b IN ( AVG( 1 ), 1 + b);
+SELECT SUM( DISTINCT c ) FROM t1 GROUP BY c HAVING c IN ( AVG( 1 ), 1 + c);
+SELECT SUM( DISTINCT d ) FROM t1 GROUP BY d HAVING d IN ( AVG( 1 ), 1 + d);
+SELECT SUM( DISTINCT e ) FROM t1 GROUP BY e HAVING e IN ( AVG( 1 ), 1 + e);
+SELECT SUM( DISTINCT e ) FROM t1 GROUP BY b,c,d HAVING (b,c,d) IN
+ ((AVG( 1 ), 1 + c, 1 + d), (AVG( 1 ), 2 + c, 2 + d));
+DROP TABLE t1;
+
--echo End of 5.1 tests
diff --git a/mysql-test/t/func_math.test b/mysql-test/t/func_math.test
index e67f5f29e3a..91fdce8addb 100644
--- a/mysql-test/t/func_math.test
+++ b/mysql-test/t/func_math.test
@@ -269,6 +269,15 @@ SELECT a, ROUND(a) FROM t1;
DROP TABLE t1;
+#
+# Bug#45152 crash with round() function on longtext column in a derived table
+#
+CREATE TABLE t1(f1 LONGTEXT) engine=myisam;
+INSERT INTO t1 VALUES ('a');
+SELECT 1 FROM (SELECT ROUND(f1) AS a FROM t1) AS s WHERE a LIKE 'a';
+SELECT 1 FROM (SELECT ROUND(f1, f1) AS a FROM t1) AS s WHERE a LIKE 'a';
+DROP TABLE t1;
+
--echo End of 5.0 tests
#
@@ -282,4 +291,22 @@ SELECT 1e300 / 1e-300;
SELECT EXP(750);
SELECT POW(10, 309);
+--echo #
+--echo # Bug #44768: SIGFPE crash when selecting rand from a view
+--echo # containing null
+--echo #
+
+CREATE OR REPLACE VIEW v1 AS SELECT NULL AS a;
+SELECT RAND(a) FROM v1;
+DROP VIEW v1;
+
+SELECT RAND(a) FROM (SELECT NULL AS a) b;
+
+CREATE TABLE t1 (i INT);
+INSERT INTO t1 VALUES (NULL);
+SELECT RAND(i) FROM t1;
+DROP TABLE t1;
+
+--echo #
+
--echo End of 5.1 tests
diff --git a/mysql-test/t/func_set.test b/mysql-test/t/func_set.test
index 5f37cd2a13e..294efa8caf1 100644
--- a/mysql-test/t/func_set.test
+++ b/mysql-test/t/func_set.test
@@ -84,3 +84,16 @@ engine=myisam default charset=latin1;
insert into t1 values (''),(null),(null),(''),(''),('');
select find_in_set(f1,f1) as a from t1,(select find_in_set(f1,f1) as b from t1) a;
drop table t1;
+#
+# Bug#45168: assertion with convert() and empty set value
+#
+CREATE TABLE t1( a SET('a', 'b', 'c') );
+CREATE TABLE t2( a SET('a', 'b', 'c') );
+
+INSERT INTO t1 VALUES ('d');
+INSERT INTO t2 VALUES ('');
+
+SELECT CONVERT( a USING latin1 ) FROM t1;
+SELECT CONVERT( a USING latin1 ) FROM t2;
+
+DROP TABLE t1, t2;
diff --git a/mysql-test/t/func_str.test b/mysql-test/t/func_str.test
index ef406d2aeca..7cb7f7f72d2 100644
--- a/mysql-test/t/func_str.test
+++ b/mysql-test/t/func_str.test
@@ -1282,6 +1282,16 @@ INSERT INTO t1 VALUES ('2008-12-31','aaaaaa');
SELECT DATE_FORMAT(c, GET_FORMAT(DATE, 'eur')) h, CONCAT(UPPER(aa),', ', aa) i FROM t1;
DROP TABLE t1;
+
+--echo #
+--echo # BUG#44774: load_file function produces valgrind warnings
+--echo #
+CREATE TABLE t1 (a TINYBLOB);
+INSERT INTO t1 VALUES ('aaaaaaaa');
+SELECT LOAD_FILE(a) FROM t1;
+DROP TABLE t1;
+
+
--echo End of 5.0 tests
#
diff --git a/mysql-test/t/gis.test b/mysql-test/t/gis.test
index 0dae4509518..4a60e777cc7 100644
--- a/mysql-test/t/gis.test
+++ b/mysql-test/t/gis.test
@@ -667,4 +667,28 @@ desc v1;
drop view v1;
drop table t1;
+#
+# Bug#44684: valgrind reports invalid reads in
+# Item_func_spatial_collection::val_str
+#
+SELECT MultiPoint(12345,'');
+SELECT MultiPoint(123451,'');
+SELECT MultiPoint(1234512,'');
+SELECT MultiPoint(12345123,'');
+
+SELECT MultiLineString(12345,'');
+SELECT MultiLineString(123451,'');
+SELECT MultiLineString(1234512,'');
+SELECT MultiLineString(12345123,'');
+
+SELECT LineString(12345,'');
+SELECT LineString(123451,'');
+SELECT LineString(1234512,'');
+SELECT LineString(12345123,'');
+
+SELECT Polygon(12345,'');
+SELECT Polygon(123451,'');
+SELECT Polygon(1234512,'');
+SELECT Polygon(12345123,'');
+
--echo End of 5.1 tests
diff --git a/mysql-test/t/grant.test b/mysql-test/t/grant.test
index 2e42bdbf06c..bcd393bd6ab 100644
--- a/mysql-test/t/grant.test
+++ b/mysql-test/t/grant.test
@@ -1471,5 +1471,59 @@ DROP DATABASE dbbug33464;
SET @@global.log_bin_trust_function_creators= @old_log_bin_trust_function_creators;
+#
+# Bug#44658 Create procedure makes server crash when user does not have ALL privilege
+#
+CREATE USER user1;
+CREATE USER user2;
+GRANT CREATE ON db1.* TO 'user1'@'localhost';
+GRANT CREATE ROUTINE ON db1.* TO 'user1'@'localhost';
+GRANT CREATE ON db1.* TO 'user2'@'%';
+GRANT CREATE ROUTINE ON db1.* TO 'user2'@'%';
+FLUSH PRIVILEGES;
+SHOW GRANTS FOR 'user1'@'localhost';
+connect (con1,localhost,user1,,);
+--echo ** Connect as user1 and create a procedure.
+--echo ** The creation will imply implicitly assigned
+--echo ** EXECUTE and ALTER ROUTINE privileges to
+--echo ** the current user user1@localhost.
+SELECT @@GLOBAL.sql_mode;
+SELECT @@SESSION.sql_mode;
+CREATE DATABASE db1;
+DELIMITER ||;
+CREATE PROCEDURE db1.proc1(p1 INT)
+ BEGIN
+ SET @x = 0;
+ REPEAT SET @x = @x + 1; UNTIL @x > p1 END REPEAT;
+ END ;||
+DELIMITER ;||
+
+connect (con2,localhost,user2,,);
+--echo ** Connect as user2 and create a procedure.
+--echo ** Implicitly assignment of privileges will
+--echo ** fail because the user2@localhost is an
+--echo ** unknown user.
+DELIMITER ||;
+CREATE PROCEDURE db1.proc2(p1 INT)
+ BEGIN
+ SET @x = 0;
+ REPEAT SET @x = @x + 1; UNTIL @x > p1 END REPEAT;
+ END ;||
+DELIMITER ;||
+
+connection default;
+SHOW GRANTS FOR 'user1'@'localhost';
+SHOW GRANTS FOR 'user2';
+disconnect con1;
+disconnect con2;
+DROP PROCEDURE db1.proc1;
+DROP PROCEDURE db1.proc2;
+REVOKE ALL ON db1.* FROM 'user1'@'localhost';
+REVOKE ALL ON db1.* FROM 'user2'@'%';
+DROP USER 'user1';
+DROP USER 'user1'@'localhost';
+DROP USER 'user2';
+DROP DATABASE db1;
+
# Wait till we reached the initial number of concurrent sessions
--source include/wait_until_count_sessions.inc
diff --git a/mysql-test/t/group_min_max.test b/mysql-test/t/group_min_max.test
index adfa77c881c..981be3efece 100644
--- a/mysql-test/t/group_min_max.test
+++ b/mysql-test/t/group_min_max.test
@@ -982,4 +982,39 @@ SELECT DISTINCT c FROM t1 WHERE d=4;
DROP TABLE t1;
+--echo #
+--echo # Bug #45386: Wrong query result with MIN function in field list,
+--echo # WHERE and GROUP BY clause
+--echo #
+
+CREATE TABLE t (a INT, b INT, INDEX (a,b));
+INSERT INTO t VALUES (2,0), (2,0), (2,1), (2,1);
+INSERT INTO t SELECT * FROM t;
+
+--echo # test MIN
+--echo #should use range with index for group by
+EXPLAIN
+SELECT a, MIN(b) FROM t WHERE b <> 0 GROUP BY a;
+--echo #should return 1 row
+SELECT a, MIN(b) FROM t WHERE b <> 0 GROUP BY a;
+
+--echo # test MAX
+--echo #should use range with index for group by
+EXPLAIN
+SELECT a, MAX(b) FROM t WHERE b <> 1 GROUP BY a;
+--echo #should return 1 row
+SELECT a, MAX(b) FROM t WHERE b <> 1 GROUP BY a;
+
+--echo # test 3 ranges and use the middle one
+INSERT INTO t SELECT a, 2 FROM t;
+
+--echo #should use range with index for group by
+EXPLAIN
+SELECT a, MAX(b) FROM t WHERE b > 0 AND b < 2 GROUP BY a;
+--echo #should return 1 row
+SELECT a, MAX(b) FROM t WHERE b > 0 AND b < 2 GROUP BY a;
+
+DROP TABLE t;
+
+
--echo End of 5.0 tests
diff --git a/mysql-test/t/heap_btree.test b/mysql-test/t/heap_btree.test
index b51eeb27331..637c6ba1c81 100644
--- a/mysql-test/t/heap_btree.test
+++ b/mysql-test/t/heap_btree.test
@@ -253,5 +253,13 @@ insert into t1 values (1, 1), (3, 3), (2, 2), (NULL, 1), (NULL, NULL), (0, 0);
select * from t1 where a is null;
drop table t1;
+-- echo #
+-- echo # bug#39918 - memory (heap) engine crashing while executing self join with delete
+-- echo #
+
+CREATE TABLE t1(a INT, KEY USING BTREE (a)) ENGINE=MEMORY;
+INSERT INTO t1 VALUES(1),(1);
+DELETE a1 FROM t1 AS a1, t1 AS a2 WHERE a1.a=a2.a;
+DROP TABLE t1;
--echo End of 5.0 tests
diff --git a/mysql-test/t/information_schema_db.test b/mysql-test/t/information_schema_db.test
index 6353e94fd51..0ff1d05f364 100644
--- a/mysql-test/t/information_schema_db.test
+++ b/mysql-test/t/information_schema_db.test
@@ -53,7 +53,7 @@ order by table_name;
end|
delimiter ;|
-create table t1
+create table t1
(f1 int(10) unsigned not null,
f2 varchar(100) not null,
primary key (f1), unique key (f2));
@@ -105,8 +105,8 @@ drop function f2;
drop view v1, v2;
#
-# Bug#20543: select on information_schema strange warnings, view, different
-# schemas/users
+# Bug#20543 select on information_schema strange warnings, view, different
+# schemas/users
#
#
create database testdb_1;
@@ -125,7 +125,7 @@ grant insert on v1 to testdb_2@localhost;
create view v5 as select f1 from t1;
grant show view on v5 to testdb_2@localhost;
---error 1227
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
create definer=`no_such_user`@`no_such_host` view v6 as select f1 from t1;
connection default;
@@ -169,46 +169,53 @@ use testdb_1;
revoke show view on v6 from testdb_2@localhost;
connection testdb_2;
---error 1142
+--error ER_TABLEACCESS_DENIED_ERROR
show fields from testdb_1.v5;
---error 1142
+--error ER_TABLEACCESS_DENIED_ERROR
show create view testdb_1.v5;
---error 1142
+--error ER_TABLEACCESS_DENIED_ERROR
show fields from testdb_1.v6;
---error 1142
+--error ER_TABLEACCESS_DENIED_ERROR
show create view testdb_1.v6;
---error 1142
+--error ER_TABLEACCESS_DENIED_ERROR
show fields from testdb_1.v7;
---error 1142
+--error ER_TABLEACCESS_DENIED_ERROR
show create view testdb_1.v7;
---error 1345
+--error ER_VIEW_NO_EXPLAIN
show create view v4;
-#--error 1345
+#--error ER_VIEW_NO_EXPLAIN
show fields from v4;
show fields from v2;
show fields from testdb_1.v1;
show create view v2;
---error 1142
+--error ER_TABLEACCESS_DENIED_ERROR
show create view testdb_1.v1;
-select table_name from information_schema.columns a
+select table_name from information_schema.columns a
where a.table_name = 'v2';
-select view_definition from information_schema.views a
+select view_definition from information_schema.views a
where a.table_name = 'v2';
-select view_definition from information_schema.views a
+select view_definition from information_schema.views a
where a.table_name = 'testdb_1.v1';
---error 1356
+--error ER_VIEW_INVALID
select * from v2;
connection default;
use test;
drop view testdb_1.v1, v2, testdb_1.v3, v4;
drop database testdb_1;
+connection testdb_1;
+disconnect testdb_1;
+--source include/wait_until_disconnected.inc
+connection testdb_2;
+disconnect testdb_2;
+--source include/wait_until_disconnected.inc
+connection default;
drop user testdb_1@localhost;
drop user testdb_2@localhost;
@@ -239,4 +246,7 @@ show create view testdb_1.v1;
connection default;
drop user mysqltest_1@localhost;
drop database testdb_1;
+connection user1;
disconnect user1;
+--source include/wait_until_disconnected.inc
+connection default;
diff --git a/mysql-test/t/init_file.test b/mysql-test/t/init_file.test
index ceb5cae9743..7eb5381651d 100644
--- a/mysql-test/t/init_file.test
+++ b/mysql-test/t/init_file.test
@@ -14,7 +14,7 @@ SELECT * INTO @X FROM init_file.startup limit 0,1;
SELECT * INTO @Y FROM init_file.startup limit 1,1;
SELECT YEAR(@X)-YEAR(@Y);
# Enable this DROP DATABASE only after resolving bug #42507
-# DROP DATABASE init_file;
+DROP DATABASE init_file;
--echo ok
--echo end of 4.1 tests
@@ -28,4 +28,9 @@ select * from t1;
# 30, 3, 11, 13
select * from t2;
# Enable this DROP TABLE only after resolving bug #42507
-#drop table t1, t2;
+drop table t1, t2;
+
+# MTR will restart server anyway, but by forcing it we avoid being warned
+# about the apparent side effect
+
+call mtr.force_restart();
diff --git a/mysql-test/t/innodb_bug21704.test b/mysql-test/t/innodb_bug21704.test
new file mode 100644
index 00000000000..c649b61034c
--- /dev/null
+++ b/mysql-test/t/innodb_bug21704.test
@@ -0,0 +1,96 @@
+-- source include/have_innodb.inc
+
+--echo #
+--echo # Bug#21704: Renaming column does not update FK definition.
+--echo #
+
+--echo
+--echo # Test that it's not possible to rename columns participating in a
+--echo # foreign key (either in the referencing or referenced table).
+--echo
+
+--disable_warnings
+DROP TABLE IF EXISTS t1;
+DROP TABLE IF EXISTS t2;
+DROP TABLE IF EXISTS t3;
+--enable_warnings
+
+CREATE TABLE t1 (a INT PRIMARY KEY, b INT) ROW_FORMAT=COMPACT ENGINE=INNODB;
+
+CREATE TABLE t2 (a INT PRIMARY KEY, b INT,
+ CONSTRAINT fk1 FOREIGN KEY (a) REFERENCES t1(a))
+ROW_FORMAT=COMPACT ENGINE=INNODB;
+
+CREATE TABLE t3 (a INT PRIMARY KEY, b INT, KEY(b), C INT,
+ CONSTRAINT fk2 FOREIGN KEY (b) REFERENCES t3 (a))
+ROW_FORMAT=COMPACT ENGINE=INNODB;
+
+INSERT INTO t1 VALUES (1,1),(2,2),(3,3);
+INSERT INTO t2 VALUES (1,1),(2,2),(3,3);
+INSERT INTO t3 VALUES (1,1,1),(2,2,2),(3,3,3);
+
+--echo
+--echo # Test renaming the column in the referenced table.
+--echo
+
+# mysqltest first does replace_regex, then replace_result
+--replace_regex /'[^']*test\/#sql-[0-9a-f_]*'/'#sql-temporary'/
+# Embedded server doesn't chdir to data directory
+--replace_result $MYSQLTEST_VARDIR . mysqld.1/data/ ''
+--error ER_ERROR_ON_RENAME
+ALTER TABLE t1 CHANGE a c INT;
+
+--echo # Ensure that online column rename works.
+
+--enable_info
+ALTER TABLE t1 CHANGE b c INT;
+--disable_info
+
+--echo
+--echo # Test renaming the column in the referencing table
+--echo
+
+# mysqltest first does replace_regex, then replace_result
+--replace_regex /'[^']*test\/#sql-[0-9a-f_]*'/'#sql-temporary'/
+# Embedded server doesn't chdir to data directory
+--replace_result $MYSQLTEST_VARDIR . mysqld.1/data/ ''
+--error ER_ERROR_ON_RENAME
+ALTER TABLE t2 CHANGE a c INT;
+
+--echo # Ensure that online column rename works.
+
+--enable_info
+ALTER TABLE t2 CHANGE b c INT;
+--disable_info
+
+--echo
+--echo # Test with self-referential constraints
+--echo
+
+# mysqltest first does replace_regex, then replace_result
+--replace_regex /'[^']*test\/#sql-[0-9a-f_]*'/'#sql-temporary'/
+# Embedded server doesn't chdir to data directory
+--replace_result $MYSQLTEST_VARDIR . mysqld.1/data/ ''
+--error ER_ERROR_ON_RENAME
+ALTER TABLE t3 CHANGE a d INT;
+
+# mysqltest first does replace_regex, then replace_result
+--replace_regex /'[^']*test\/#sql-[0-9a-f_]*'/'#sql-temporary'/
+# Embedded server doesn't chdir to data directory
+--replace_result $MYSQLTEST_VARDIR . mysqld.1/data/ ''
+--error ER_ERROR_ON_RENAME
+ALTER TABLE t3 CHANGE b d INT;
+
+--echo # Ensure that online column rename works.
+
+--enable_info
+ALTER TABLE t3 CHANGE c d INT;
+--disable_info
+
+--echo
+--echo # Cleanup.
+--echo
+
+DROP TABLE t3;
+DROP TABLE t2;
+DROP TABLE t1;
diff --git a/mysql-test/t/innodb_bug40565.test b/mysql-test/t/innodb_bug40565.test
new file mode 100644
index 00000000000..d7aa0fd514a
--- /dev/null
+++ b/mysql-test/t/innodb_bug40565.test
@@ -0,0 +1,10 @@
+# Bug #40565 Update Query Results in "1 Row Affected" But Should Be "Zero Rows"
+-- source include/have_innodb.inc
+
+create table bug40565(value decimal(4,2)) engine=innodb;
+insert into bug40565 values (1), (null);
+--enable_info
+update bug40565 set value=NULL;
+update bug40565 set value=NULL;
+--disable_info
+drop table bug40565;
diff --git a/mysql-test/t/innodb_bug42101-nonzero-master.opt b/mysql-test/t/innodb_bug42101-nonzero-master.opt
new file mode 100644
index 00000000000..d71dbe17d5b
--- /dev/null
+++ b/mysql-test/t/innodb_bug42101-nonzero-master.opt
@@ -0,0 +1 @@
+--innodb_commit_concurrency=1
diff --git a/mysql-test/t/innodb_bug42101-nonzero.test b/mysql-test/t/innodb_bug42101-nonzero.test
new file mode 100644
index 00000000000..685fdf20489
--- /dev/null
+++ b/mysql-test/t/innodb_bug42101-nonzero.test
@@ -0,0 +1,21 @@
+#
+# Bug#42101 Race condition in innodb_commit_concurrency
+# http://bugs.mysql.com/42101
+#
+
+-- source include/have_innodb.inc
+
+--error ER_WRONG_ARGUMENTS
+set global innodb_commit_concurrency=0;
+select @@innodb_commit_concurrency;
+set global innodb_commit_concurrency=1;
+select @@innodb_commit_concurrency;
+set global innodb_commit_concurrency=42;
+select @@innodb_commit_concurrency;
+set global innodb_commit_concurrency=DEFAULT;
+select @@innodb_commit_concurrency;
+--error ER_WRONG_ARGUMENTS
+set global innodb_commit_concurrency=0;
+select @@innodb_commit_concurrency;
+set global innodb_commit_concurrency=1;
+select @@innodb_commit_concurrency;
diff --git a/mysql-test/t/innodb_bug42101.test b/mysql-test/t/innodb_bug42101.test
new file mode 100644
index 00000000000..b6536490d48
--- /dev/null
+++ b/mysql-test/t/innodb_bug42101.test
@@ -0,0 +1,19 @@
+#
+# Bug#42101 Race condition in innodb_commit_concurrency
+# http://bugs.mysql.com/42101
+#
+
+-- source include/have_innodb.inc
+
+set global innodb_commit_concurrency=0;
+select @@innodb_commit_concurrency;
+--error ER_WRONG_ARGUMENTS
+set global innodb_commit_concurrency=1;
+select @@innodb_commit_concurrency;
+--error ER_WRONG_ARGUMENTS
+set global innodb_commit_concurrency=42;
+select @@innodb_commit_concurrency;
+set global innodb_commit_concurrency=0;
+select @@innodb_commit_concurrency;
+set global innodb_commit_concurrency=DEFAULT;
+select @@innodb_commit_concurrency;
diff --git a/mysql-test/t/innodb_bug45357.test b/mysql-test/t/innodb_bug45357.test
new file mode 100644
index 00000000000..81727f352dd
--- /dev/null
+++ b/mysql-test/t/innodb_bug45357.test
@@ -0,0 +1,10 @@
+-- source include/have_innodb.inc
+
+set session transaction isolation level read committed;
+
+create table bug45357(a int, b int,key(b))engine=innodb;
+insert into bug45357 values (25170,6122);
+update bug45357 set a=1 where b=30131;
+delete from bug45357 where b < 20996;
+delete from bug45357 where b < 7001;
+drop table bug45357;
diff --git a/mysql-test/t/innodb_mysql.test b/mysql-test/t/innodb_mysql.test
index ad9e726f5b4..c643465b2f3 100644
--- a/mysql-test/t/innodb_mysql.test
+++ b/mysql-test/t/innodb_mysql.test
@@ -332,4 +332,133 @@ DROP TABLE t1;
DROP TABLE t2;
DROP TABLE t3;
+#
+# Bug#43580: Issue with Innodb on multi-table update
+#
+CREATE TABLE t1 (a INT, b INT, KEY (a)) ENGINE = INNODB;
+CREATE TABLE t2 (a INT KEY, b INT, KEY (b)) ENGINE = INNODB;
+
+CREATE TABLE t3 (a INT, b INT KEY, KEY (a)) ENGINE = INNODB;
+CREATE TABLE t4 (a INT KEY, b INT, KEY (b)) ENGINE = INNODB;
+
+INSERT INTO t1 VALUES (1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6);
+INSERT INTO t2 VALUES (1, 1), (2, 2), (3, 3), (4, 4), (5, 5);
+
+INSERT INTO t3 VALUES (1, 101), (2, 102), (3, 103), (4, 104), (5, 105), (6, 106);
+INSERT INTO t4 VALUES (1, 1), (2, 2), (3, 3), (4, 4), (5, 5);
+
+UPDATE t1, t2 SET t1.a = t1.a + 100, t2.b = t1.a + 10
+WHERE t1.a BETWEEN 2 AND 4 AND t2.a = t1.b;
+--sorted_result
+SELECT * FROM t2;
+
+UPDATE t3, t4 SET t3.a = t3.a + 100, t4.b = t3.a + 10
+WHERE t3.a BETWEEN 2 AND 4 AND t4.a = t3.b - 100;
+--sorted_result
+SELECT * FROM t4;
+
+DROP TABLE t1, t2, t3, t4;
+
+--echo #
+--echo # Bug#44886: SIGSEGV in test_if_skip_sort_order() -
+--echo # uninitialized variable used as subscript
+--echo #
+
+CREATE TABLE t1 (a INT, b INT, c INT, d INT, PRIMARY KEY (b), KEY (a,c))
+ ENGINE=InnoDB;
+INSERT INTO t1 VALUES (1,1,1,0);
+
+CREATE TABLE t2 (a INT, b INT, e INT, KEY (e)) ENGINE=InnoDB;
+INSERT INTO t2 VALUES (1,1,2);
+
+CREATE TABLE t3 (a INT, b INT) ENGINE=MyISAM;
+INSERT INTO t3 VALUES (1, 1);
+
+SELECT * FROM t1, t2, t3
+ WHERE t1.a = t3.a AND (t1.b = t3.b OR t1.d) AND t2.b = t1.b AND t2.e = 2
+ GROUP BY t1.b;
+
+DROP TABLE t1, t2, t3;
+
+--echo #
+--echo # Bug #45828: Optimizer won't use partial primary key if another
+--echo # index can prevent filesort
+--echo #
+
+# Create the table
+CREATE TABLE `t1` (
+ c1 int NOT NULL,
+ c2 int NOT NULL,
+ c3 int NOT NULL,
+ PRIMARY KEY (c1,c2),
+ KEY (c3)
+) ENGINE=InnoDB;
+
+# populate with data
+INSERT INTO t1 VALUES (5,2,1246276747);
+INSERT INTO t1 VALUES (2,1,1246281721);
+INSERT INTO t1 VALUES (7,3,1246281756);
+INSERT INTO t1 VALUES (4,2,1246282139);
+INSERT INTO t1 VALUES (3,1,1246282230);
+INSERT INTO t1 VALUES (1,0,1246282712);
+INSERT INTO t1 VALUES (8,3,1246282765);
+INSERT INTO t1 SELECT c1+10,c2+10,c3+10 FROM t1;
+INSERT INTO t1 SELECT c1+100,c2+100,c3+100 from t1;
+INSERT INTO t1 SELECT c1+1000,c2+1000,c3+1000 from t1;
+INSERT INTO t1 SELECT c1+10000,c2+10000,c3+10000 from t1;
+INSERT INTO t1 SELECT c1+100000,c2+100000,c3+100000 from t1;
+INSERT INTO t1 SELECT c1+1000000,c2+1000000,c3+1000000 from t1;
+
+# query and no rows will match the c1 condition, whereas all will match c3
+SELECT * FROM t1 WHERE c1 = 99999999 AND c3 > 1 ORDER BY c3;
+
+# SHOULD use the pk.
+# index on c3 will be used instead of primary key
+EXPLAIN SELECT * FROM t1 WHERE c1 = 99999999 AND c3 > 1 ORDER BY c3;
+
+# if we force the primary key, we can see the estimate is 1
+EXPLAIN SELECT * FROM t1 FORCE INDEX (PRIMARY) WHERE c1 = 99999999 AND c3 > 1 ORDER BY c3;
+
+
+CREATE TABLE t2 (
+ c1 int NOT NULL,
+ c2 int NOT NULL,
+ c3 int NOT NULL,
+ KEY (c1,c2),
+ KEY (c3)
+) ENGINE=InnoDB;
+
+# SHOULD use the pk.
+# if we switch it from a primary key to a regular index, it works correctly as well
+explain SELECT * FROM t2 WHERE c1 = 99999999 AND c3 > 1 ORDER BY c3;
+
+DROP TABLE t1,t2;
+
+
+--echo #
+--echo # 36259: Optimizing with ORDER BY
+--echo #
+
+CREATE TABLE t1 (
+ a INT NOT NULL AUTO_INCREMENT,
+ b INT NOT NULL,
+ c INT NOT NULL,
+ d VARCHAR(5),
+ e INT NOT NULL,
+ PRIMARY KEY (a), KEY i2 (b,c,d)
+) ENGINE=InnoDB;
+
+INSERT INTO t1 (b,c,d,e) VALUES (1,1,'a',1), (2,2,'b',2);
+INSERT INTO t1 (b,c,d,e) SELECT RAND()*10000, RAND()*10000, d, e FROM t1;
+INSERT INTO t1 (b,c,d,e) SELECT RAND()*10000, RAND()*10000, d, e FROM t1;
+INSERT INTO t1 (b,c,d,e) SELECT RAND()*10000, RAND()*10000, d, e FROM t1;
+INSERT INTO t1 (b,c,d,e) SELECT RAND()*10000, RAND()*10000, d, e FROM t1;
+INSERT INTO t1 (b,c,d,e) SELECT RAND()*10000, RAND()*10000, d, e FROM t1;
+INSERT INTO t1 (b,c,d,e) SELECT RAND()*10000, RAND()*10000, d, e FROM t1;
+EXPLAIN SELECT * FROM t1 WHERE b=1 AND c=1 ORDER BY a;
+EXPLAIN SELECT * FROM t1 FORCE INDEX(i2) WHERE b=1 and c=1 ORDER BY a;
+EXPLAIN SELECT * FROM t1 FORCE INDEX(PRIMARY) WHERE b=1 AND c=1 ORDER BY a;
+
+DROP TABLE t1;
+
--echo End of 5.1 tests
diff --git a/mysql-test/t/insert_select.test b/mysql-test/t/insert_select.test
index 499db086877..f8023fcfc60 100644
--- a/mysql-test/t/insert_select.test
+++ b/mysql-test/t/insert_select.test
@@ -323,6 +323,16 @@ INSERT INTO t2 (f1, f2)
SELECT * FROM t2;
DROP TABLE t1, t2;
+#
+# Bug#44306: Assertion fail on duplicate key error in 'INSERT ... SELECT'
+# statements
+#
+CREATE TABLE t1 ( a INT KEY, b INT );
+INSERT INTO t1 VALUES ( 0, 1 );
+--error ER_DUP_ENTRY
+INSERT INTO t1 ( b ) SELECT MAX( b ) FROM t1 WHERE b = 2;
+DROP TABLE t1;
+
#
# Bug #26207: inserts don't work with shortened index
#
diff --git a/mysql-test/t/log_tables_debug.test b/mysql-test/t/log_tables_debug.test
new file mode 100644
index 00000000000..19a62614608
--- /dev/null
+++ b/mysql-test/t/log_tables_debug.test
@@ -0,0 +1,94 @@
+### t/log_tables_debug.test
+#
+# Log-related tests requiring a debug-build server.
+#
+
+# extra clean-up required due to Bug#38124, set to 1 when behavior has
+# changed (see explanation in log_state.test)
+let $fixed_bug38124 = 0;
+
+--source include/have_debug.inc
+
+# Several subtests modify global variables. Save the initial values only here,
+# but reset to the initial values per subtest.
+SET @old_general_log= @@global.general_log;
+SET @old_general_log_file= @@global.general_log_file;
+SET @old_slow_query_log= @@global.slow_query_log;
+SET @old_slow_query_log_file= @@global.slow_query_log_file;
+
+
+--echo #
+--echo # Bug#45387 Information about statement id for prepared
+--echo # statements missed from general log
+--echo #
+
+let MYSQLD_DATADIR= `SELECT @@datadir`;
+
+# set logging to our specific bug log to control the entries added
+SET @@global.general_log = ON;
+SET @@global.general_log_file = 'bug45387_general.log';
+
+# turn on output of timestamps on all log file entries
+SET SESSION debug='+d,reset_log_last_time';
+
+let CONN_ID= `SELECT CONNECTION_ID()`;
+FLUSH LOGS;
+
+# reset log settings
+SET @@global.general_log = @old_general_log;
+SET @@global.general_log_file = @old_general_log_file;
+SET SESSION debug='-d';
+
+perl;
+ # get the relevant info from the surrounding perl invocation
+ $datadir= $ENV{'MYSQLD_DATADIR'};
+ $conn_id= $ENV{'CONN_ID'};
+
+ # loop through the log file looking for the stmt querying for conn id
+ open(FILE, "$datadir/bug45387_general.log") or
+ die("Unable to read log file $datadir/bug45387_general.log: $!\n");
+ while() {
+ if (/\d{6}\s+\d+:\d+:\d+[ \t]+(\d+)[ \t]+Query[ \t]+SELECT CONNECTION_ID/) {
+ $found= $1;
+ break;
+ }
+ }
+
+ # print the result
+ if ($found == $conn_id) {
+ print "Bug#45387: ID match.\n";
+ } else {
+ print "Bug#45387: Expected ID '$conn_id', found '$found' in log file.\n";
+ print "Contents of log file:\n";
+ seek(FILE, 0, 0);
+ while($line= ) {
+ print $line;
+ }
+ }
+
+ close(FILE);
+EOF
+
+--remove_file $MYSQLD_DATADIR/bug45387_general.log
+
+--echo End of 5.1 tests
+
+
+--echo #
+--echo # Cleanup
+--echo #
+
+# Reset global system variables to initial values if forgotten somewhere above.
+SET global general_log = @old_general_log;
+SET global general_log_file = @old_general_log_file;
+SET global slow_query_log = @old_slow_query_log;
+SET global slow_query_log_file = @old_slow_query_log_file;
+if(!$fixed_bug38124)
+{
+ --disable_query_log
+ let $my_var = `SELECT @old_general_log_file`;
+ eval SET @@global.general_log_file = '$my_var';
+ let $my_var = `SELECT @old_slow_query_log_file`;
+ eval SET @@global.slow_query_log_file = '$my_var';
+ --enable_query_log
+}
diff --git a/mysql-test/t/lowercase_fs_off.test b/mysql-test/t/lowercase_fs_off.test
index 414027cb485..878564c32ab 100644
--- a/mysql-test/t/lowercase_fs_off.test
+++ b/mysql-test/t/lowercase_fs_off.test
@@ -14,16 +14,18 @@ flush privileges;
connect (sample,localhost,sample,password,d1);
connection sample;
select database();
---error 1044
+--error ER_DBACCESS_DENIED_ERROR
create database d2;
---error 1044
+--error ER_DBACCESS_DENIED_ERROR
create database D1;
disconnect sample;
+--source include/wait_until_disconnected.inc
connection master;
drop user 'sample'@'localhost';
drop database if exists d1;
disconnect master;
+--source include/wait_until_disconnected.inc
connection default;
# End of 4.1 tests
diff --git a/mysql-test/t/merge.test b/mysql-test/t/merge.test
index 5315c91daa6..8760876b7ee 100644
--- a/mysql-test/t/merge.test
+++ b/mysql-test/t/merge.test
@@ -1535,4 +1535,24 @@ SELECT * FROM m1;
DROP VIEW v1;
DROP TABLE m1, t1;
+
+--echo #
+--echo # Bug #45796: invalid memory reads and writes when altering merge and
+--echo # base tables
+--echo #
+
+CREATE TABLE t1(c1 INT) ENGINE=MyISAM;
+CREATE TABLE m1(c1 INT) ENGINE=MERGE UNION=(t1);
+ALTER TABLE m1 ADD INDEX idx_c1(c1);
+# Open the MERGE table and allocate buffers based on children's definition.
+--error ER_WRONG_MRG_TABLE
+SELECT * FROM m1;
+# Change the child table definition.
+ALTER TABLE t1 ADD INDEX idx_c1(c1);
+# Check that old buffers are not reused
+SELECT * FROM m1;
+
+DROP TABLE m1;
+DROP TABLE t1;
+
--echo End of 5.1 tests
diff --git a/mysql-test/t/multi_update2.test b/mysql-test/t/multi_update2.test
index 47f9bc7bad7..a04518f4964 100644
--- a/mysql-test/t/multi_update2.test
+++ b/mysql-test/t/multi_update2.test
@@ -2,14 +2,46 @@
# Test of update statement that uses many tables.
#
+#
+# If we are running with
+# - Valgrind -> $VALGRIND_TEST <> 0
+# - debug tracing -> @@session.debug LIKE '%trace%'
+# the resource consumption (storage space needed, runtime) will be extreme.
+# Therefore we require that the option "--big-test" is also set.
+#
+
+let $need_big= 0;
+--disable_query_log
+--error 0,ER_UNKNOWN_SYSTEM_VARIABLE
+SET @aux = @@session.debug;
+if (!$mysql_errno)
+{
+ # We have returncode 0 = the server system variable @@session.debug exists.
+ # But we only need "--big-test" in case of tracing.
+ if (`SELECT @@session.debug LIKE '%trace%'`)
+ {
+ let $need_big= 1;
+ }
+}
+--enable_query_log
+if ($VALGRIND_TEST)
+{
+ # We are running with Valgrind
+ inc $need_big;
+}
+if (`SELECT '$BIG_TEST' = '' AND $need_big = 1`)
+{
+ --skip Need "--big-test" when running with the option "--debug" or "--valgrind"
+}
+
+#
+# Bug#1820 Rows not deleted from second table on multi-table delete
+#
+
--disable_warnings
DROP TABLE IF EXISTS t1,t2;
--enable_warnings
-#
-# Bug#1820 Rows not deleted from second table on multi-table delete
-#
-
CREATE TABLE t1 ( a INT NOT NULL, b INT NOT NULL) ;
--echo # The protocolling of many inserts into t1 is suppressed.
--disable_query_log
diff --git a/mysql-test/t/mysql-bug45236.test b/mysql-test/t/mysql-bug45236.test
new file mode 100644
index 00000000000..efc10ed19ea
--- /dev/null
+++ b/mysql-test/t/mysql-bug45236.test
@@ -0,0 +1,45 @@
+#
+# Bug #45236: large blob inserts from mysqldump fail, possible memory issue ?
+#
+# This test consumes a significant amount of resources.
+# Therefore it should be kept separated from other tests.
+# Otherwise we might suffer from problems like
+# Bug#43801 mysql.test takes too long, fails due to expired timeout
+# on debx86-b in PB
+#
+
+-- source include/not_embedded.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS t1;
+--enable_warnings
+
+# Have to change the global variable as the session variable is
+# read-only.
+SET @old_max_allowed_packet= @@global.max_allowed_packet;
+# ~1 MB blob length + some space for the rest of INSERT query
+SET @@global.max_allowed_packet = 1024 * 1024 + 1024;
+
+# Create a new connection since the global max_allowed_packet
+# has no effect onr the current one
+connect (con1, localhost, root,,);
+
+CREATE TABLE t1(data LONGBLOB);
+INSERT INTO t1 SELECT CONCAT(REPEAT('1', 1024*1024 - 27),
+ "\'\r dummydb dummyhost");
+
+let $outfile= $MYSQLTEST_VARDIR/tmp/bug41486.sql;
+--error 0,1
+remove_file $outfile;
+--exec $MYSQL_DUMP --compact -t test t1 > $outfile
+# Check that the mysql client does not interpret the "\r" sequence as a command
+--exec $MYSQL --max_allowed_packet=1M test < $outfile 2>&1
+
+DROP TABLE t1;
+
+# Cleanup
+disconnect con1;
+--source include/wait_until_disconnected.inc
+remove_file $outfile;
+connection default;
+SET @@global.max_allowed_packet = @old_max_allowed_packet;
diff --git a/mysql-test/t/mysql.test b/mysql-test/t/mysql.test
index 7e970d5b104..2bb9a02e9d7 100644
--- a/mysql-test/t/mysql.test
+++ b/mysql-test/t/mysql.test
@@ -342,6 +342,21 @@ EOF
remove_file $MYSQLTEST_VARDIR/tmp/bug31060.sql;
+#
+# Bug #39101: client -i (--ignore-spaces) option does not seem to work
+#
+--exec $MYSQL -i -e "SELECT COUNT (*)"
+--exec $MYSQL --ignore-spaces -e "SELECT COUNT (*)"
+--exec $MYSQL -b -i -e "SELECT COUNT (*)"
+
+#
+# Bug#37268 'binary' character set makes CLI-internal commands case sensitive
+#
+--replace_regex /\([0-9]*\)/(errno)/
+--error 1
+--exec $MYSQL --default-character-set=binary test -e "CONNECT test invalid_hostname" 2>&1
+--exec $MYSQL --default-character-set=binary test -e "DELIMITER //" 2>&1
+
--echo End of 5.0 tests
#
@@ -367,4 +382,10 @@ remove_file $MYSQLTEST_VARDIR/tmp/bug31060.sql;
drop tables t1, t2;
+#
+# Bug #27884: mysql --html does not quote HTML special characters in output
+#
+--exec $MYSQL --html test -e "select '< & >' as '<'"
+
+--echo
--echo End of tests
diff --git a/mysql-test/t/mysqlbinlog.test b/mysql-test/t/mysqlbinlog.test
index 46060649784..7767abe43d0 100644
--- a/mysql-test/t/mysqlbinlog.test
+++ b/mysql-test/t/mysqlbinlog.test
@@ -367,4 +367,16 @@ echo *** Unsigned server_id $s_id_max is found: $s_id_unsigned ***;
eval SET @@global.server_id= $save_server_id;
--remove_file $binlog_file
+#
+# Bug #41943: mysqlbinlog.exe crashes if --hexdump option is used
+#
+
+RESET MASTER;
+FLUSH LOGS;
+
+# We do not need the results, just make sure that mysqlbinlog does not crash
+--exec $MYSQL_BINLOG --hexdump --read-from-remote-server --user=root --host=127.0.0.1 --port=$MASTER_MYPORT master-bin.000001 >/dev/null
+
+--echo End of 5.0 tests
+
--echo End of 5.1 tests
diff --git a/mysql-test/t/mysqldump.test b/mysql-test/t/mysqldump.test
index fe89d7bdafa..ec96124e14b 100644
--- a/mysql-test/t/mysqldump.test
+++ b/mysql-test/t/mysqldump.test
@@ -1,6 +1,5 @@
# Embedded server doesn't support external clients
--source include/not_embedded.inc
---source include/have_log_bin.inc
# Binlog is required
--source include/have_log_bin.inc
@@ -1395,9 +1394,6 @@ drop table t1;
drop user mysqltest_1@localhost;
---echo #
---echo # Bug#21527 mysqldump incorrectly tries to LOCK TABLES on the
---echo # information_schema database.
--echo #
--echo # Bug#21424 mysqldump failing to export/import views
--echo #
@@ -1464,6 +1460,13 @@ disconnect root;
--remove_file $MYSQLTEST_VARDIR/tmp/bug21527.sql
use test;
+--echo #
+--echo # Bug #21527 mysqldump incorrectly tries to LOCK TABLES on the
+--echo # information_schema database.
+--echo #
+--echo # Bug #33762: mysqldump can not dump INFORMATION_SCHEMA
+--echo #
+--exec $MYSQL_DUMP --compact --opt -d information_schema TABLES
--echo #
--echo # Bug#19745 mysqldump --xml produces invalid xml
@@ -1699,9 +1702,6 @@ DROP TABLE t1;
# Added for use-thread option
#
-# THIS PART OF THE TEST IS DISABLED UNTIL Bug#32991 IS FIXED
-if ($bug32991_fixed) {
-
create table t1 (a text , b text);
create table t2 (a text , b text);
insert t1 values ("Duck, Duck", "goose");
@@ -1739,8 +1739,6 @@ drop table t2;
drop table words2;
-}
-
--echo #
--echo # Bug#16853 mysqldump doesn't show events
--echo #
@@ -1954,6 +1952,59 @@ DROP DATABASE mysqldump_test_db;
SET @@GLOBAL.CONCURRENT_INSERT = @OLD_CONCURRENT_INSERT;
+###########################################################################
+
+--echo
+--echo Bug #34861 - mysqldump with --tab gives weird output for triggers.
+--echo
+
+CREATE TABLE t1 (f1 INT);
+CREATE TRIGGER tr1 BEFORE UPDATE ON t1 FOR EACH ROW SET @f1 = 1;
+CREATE PROCEDURE pr1 () SELECT "Meow";
+CREATE EVENT ev1 ON SCHEDULE AT '2030-01-01 00:00:00' DO SELECT "Meow";
+
+--echo
+SHOW TRIGGERS;
+SHOW EVENTS;
+SELECT name,body FROM mysql.proc WHERE NAME = 'pr1';
+
+--echo
+--echo dump table; if anything goes to stdout, it ends up here: ---------------
+--exec $MYSQL_DUMP --compact --routines --triggers --events --result-file=$MYSQLTEST_VARDIR/tmp/test_34861.sql --tab=$MYSQLTEST_VARDIR/tmp/ test
+
+--echo
+--echo drop everything
+DROP EVENT ev1;
+DROP TRIGGER tr1;
+DROP TABLE t1;
+DROP PROCEDURE pr1;
+
+--echo
+--echo reload table; this should restore table and trigger
+--exec $MYSQL test < $MYSQLTEST_VARDIR/tmp/t1.sql
+SHOW TRIGGERS;
+SHOW EVENTS;
+SELECT name,body FROM mysql.proc WHERE NAME = 'pr1';
+
+--echo
+--echo reload db; this should restore routines and events
+--exec $MYSQL test < $MYSQLTEST_VARDIR/tmp/test_34861.sql
+SHOW TRIGGERS;
+SHOW EVENTS;
+SELECT name,body FROM mysql.proc WHERE NAME = 'pr1';
+
+--echo
+--echo cleanup
+--remove_file $MYSQLTEST_VARDIR/tmp/t1.txt
+--remove_file $MYSQLTEST_VARDIR/tmp/t1.sql
+--remove_file $MYSQLTEST_VARDIR/tmp/test_34861.sql
+--disable_warnings
+DROP EVENT IF EXISTS ev1;
+DROP PROCEDURE IF EXISTS pr1;
+DROP TRIGGER IF EXISTS tr1;
+DROP TABLE IF EXISTS t1;
+--enable_warnings
+
###########################################################################
--echo #
diff --git a/mysql-test/t/mysqldump_restore.test b/mysql-test/t/mysqldump_restore.test
new file mode 100644
index 00000000000..835ee3ee9e9
--- /dev/null
+++ b/mysql-test/t/mysqldump_restore.test
@@ -0,0 +1,111 @@
+###############################################################################
+# mysqldump_restore.test
+#
+# Purpose: Tests if mysqldump output can be used to successfully restore
+# tables and data.
+# We CREATE a table, mysqldump it to a file, ALTER the original
+# table's name, recreate the table from the mysqldump file, then
+# utilize include/diff_tables to compare the original and recreated
+# tables.
+#
+# We use several examples from mysqldump.test here and include
+# the relevant bug numbers and headers from that test.
+#
+# NOTE: This test is not currently complete and offers only basic
+# cases of mysqldump output being restored.
+# Also, does NOT work with -X (xml) output!
+#
+# Author: pcrews
+# Created: 2009-05-21
+# Last Change:
+# Change date:
+###############################################################################
+
+# Embedded server doesn't support external clients
+--source include/not_embedded.inc
+--source include/have_log_bin.inc
+
+--echo # Set concurrent_insert = 0 to prevent random errors
+--echo # will reset to original value at the end of the test
+SET @old_concurrent_insert = @@global.concurrent_insert;
+SET @@global.concurrent_insert = 0;
+
+# Define mysqldumpfile here. It is used to capture mysqldump output
+# in order to test the output's ability to restore an exact copy of the table
+let $mysqldumpfile = $MYSQLTEST_VARDIR/tmp/mysqldumpfile.sql;
+
+--echo # Pre-test cleanup
+--disable_warnings
+DROP TABLE IF EXISTS t1;
+--enable_warnings
+
+--echo # Begin tests
+--echo #
+--echo # Bug#2005 Long decimal comparison bug.
+--echo #
+CREATE TABLE t1 (a DECIMAL(64, 20));
+INSERT INTO t1 VALUES ("1234567890123456789012345678901234567890"),
+("0987654321098765432109876543210987654321");
+--exec $MYSQL_DUMP --compact test t1 > $mysqldumpfile
+let $table_name = test.t1;
+--source include/mysqldump.inc
+
+--echo #
+--echo # Bug#3361 mysqldump quotes DECIMAL values inconsistently
+--echo #
+CREATE TABLE t1 (a DECIMAL(10,5), b FLOAT);
+# Check at first how mysql work with quoted decimal
+INSERT INTO t1 VALUES (1.2345, 2.3456);
+INSERT INTO t1 VALUES ('1.2345', 2.3456);
+INSERT INTO t1 VALUES ("1.2345", 2.3456);
+SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='ANSI_QUOTES';
+INSERT INTO t1 VALUES (1.2345, 2.3456);
+INSERT INTO t1 VALUES ('1.2345', 2.3456);
+--error ER_BAD_FIELD_ERROR
+INSERT INTO t1 VALUES ("1.2345", 2.3456);
+SET SQL_MODE=@OLD_SQL_MODE;
+
+# check how mysqldump make quoting
+--exec $MYSQL_DUMP --compact test t1 > $mysqldumpfile
+let $table_name = test.t1;
+--source include/mysqldump.inc
+
+--echo #
+--echo # Bug#1994 mysqldump does not correctly dump UCS2 data
+--echo # Bug#4261 mysqldump 10.7 (mysql 4.1.2) --skip-extended-insert drops NULL from inserts
+--echo #
+CREATE TABLE t1 (a VARCHAR(255)) DEFAULT CHARSET koi8r;
+INSERT INTO t1 VALUES (_koi8r x'C1C2C3C4C5'), (NULL);
+--exec $MYSQL_DUMP --skip-comments --skip-extended-insert test t1 > $mysqldumpfile
+let $table_name = test.t1;
+--source include/mysqldump.inc
+
+--echo #
+--echo # WL#2319 Exclude Tables from dump
+--echo #
+CREATE TABLE t1 (a INT);
+CREATE TABLE t2 (a INT);
+INSERT INTO t1 VALUES (1),(2),(3);
+INSERT INTO t2 VALUES (4),(5),(6);
+--exec $MYSQL_DUMP --skip-comments --ignore-table=test.t1 test > $mysqldumpfile
+let $table_name = test.t2;
+--source include/mysqldump.inc
+DROP TABLE t1;
+
+--echo #
+--echo # Bug#8830 mysqldump --skip-extended-insert causes --hex-blob to dump wrong values
+--echo #
+CREATE TABLE t1 (`b` blob);
+INSERT INTO `t1` VALUES (0x602010000280100005E71A);
+--exec $MYSQL_DUMP --skip-extended-insert --hex-blob test --skip-comments t1 > $mysqldumpfile
+let $table_name = test.t1;
+--source include/mysqldump.inc
+
+--echo # End tests
+
+--echo # Cleanup
+--echo # Reset concurrent_insert to its original value
+SET @@global.concurrent_insert = @old_concurrent_insert;
+--echo # remove mysqldumpfile
+--error 0,1
+--remove_file $mysqldumpfile
diff --git a/mysql-test/t/mysqltest.test b/mysql-test/t/mysqltest.test
index 55cd041aaf5..578b2bf5c6c 100644
--- a/mysql-test/t/mysqltest.test
+++ b/mysql-test/t/mysqltest.test
@@ -1780,6 +1780,56 @@ remove_file $MYSQLTEST_VARDIR/tmp/file2.tmp;
--error 1
--exec echo "copy_file from_file;" | $MYSQL_TEST 2>&1
+
+# ----------------------------------------------------------------------------
+# test for move_file
+# ----------------------------------------------------------------------------
+
+# - Check that if source file does not exist, nothing will be created.
+
+--error 1
+file_exists $MYSQLTEST_VARDIR/tmp/file1.tmp;
+--error 1
+file_exists $MYSQLTEST_VARDIR/tmp/file2.tmp;
+--error 1
+move_file $MYSQLTEST_VARDIR/tmp/file1.tmp $MYSQLTEST_VARDIR/tmp/file2.tmp;
+--error 1
+file_exists $MYSQLTEST_VARDIR/tmp/file1.tmp;
+--error 1
+file_exists $MYSQLTEST_VARDIR/tmp/file2.tmp;
+
+# - Check that if source file exists, everything works properly.
+
+--write_file $MYSQLTEST_VARDIR/tmp/file1.tmp
+file1
+EOF
+
+move_file $MYSQLTEST_VARDIR/tmp/file1.tmp $MYSQLTEST_VARDIR/tmp/file2.tmp;
+--error 1
+file_exists $MYSQLTEST_VARDIR/tmp/file1.tmp;
+file_exists $MYSQLTEST_VARDIR/tmp/file2.tmp;
+
+# - Check that if destination file exists, everything works properly.
+# (file2.tmp exists from the previous check; file1.tmp needs to be created)
+
+--write_file $MYSQLTEST_VARDIR/tmp/file1.tmp
+file1
+EOF
+
+move_file $MYSQLTEST_VARDIR/tmp/file1.tmp $MYSQLTEST_VARDIR/tmp/file2.tmp;
+--error 1
+file_exists $MYSQLTEST_VARDIR/tmp/file1.tmp;
+file_exists $MYSQLTEST_VARDIR/tmp/file2.tmp;
+remove_file $MYSQLTEST_VARDIR/tmp/file2.tmp;
+
+# - Check usage.
+
+--error 1
+--exec echo "move_file ;" | $MYSQL_TEST 2>&1
+
+--error 1
+--exec echo "move_file from_file;" | $MYSQL_TEST 2>&1
+
# ----------------------------------------------------------------------------
# test for chmod
# ----------------------------------------------------------------------------
@@ -2037,6 +2087,10 @@ let $value= query_get_value(SELECT 'A B' AS "MyColumn", MyColumn, 1);
let $value= query_get_value(SELECT 1 AS "My Column", My Column, 1);
--echo value= $value
#
+# 4.1 Query containing , protected by quotes, quotes also on column
+let $value= query_get_value('SELECT 1 as a, 2 as b', "b", 1);
+--echo value= $value
+#
#------------ Negative tests ------------
# 5. Incomplete statement including missing parameters
# 5.1 incomplete statement
diff --git a/mysql-test/t/openssl_1.test b/mysql-test/t/openssl_1.test
index 240a977fdca..baa1603faab 100644
--- a/mysql-test/t/openssl_1.test
+++ b/mysql-test/t/openssl_1.test
@@ -238,7 +238,18 @@ DROP TABLE t1;
--enable_query_log
select 'is still running; no cipher request crashed the server' as result from dual;
-##
+#
+# Bug#42158: leak: SSL_get_peer_certificate() doesn't have matching X509_free()
+#
+
+GRANT SELECT ON test.* TO bug42158@localhost REQUIRE X509;
+FLUSH PRIVILEGES;
+connect(con1,localhost,bug42158,,,,,SSL);
+SHOW STATUS LIKE 'Ssl_cipher';
+disconnect con1;
+connection default;
+DROP USER bug42158@localhost;
+
--echo End of 5.1 tests
# Wait till we reached the initial number of concurrent sessions
diff --git a/mysql-test/t/partition.test b/mysql-test/t/partition.test
index ce89609de39..8b4af201af2 100644
--- a/mysql-test/t/partition.test
+++ b/mysql-test/t/partition.test
@@ -1935,7 +1935,58 @@ INSERT INTO t1 VALUES (10), (100), (200), (300), (400);
EXPLAIN PARTITIONS SELECT * FROM t1 WHERE a>=200;
DROP TABLE t1;
+#
+# Bug#44821: select distinct on partitioned table returns wrong results
+#
+CREATE TABLE t1 ( a INT, b INT, c INT, KEY bc(b, c) )
+PARTITION BY KEY (a, b) PARTITIONS 3
+;
+
+INSERT INTO t1 VALUES
+(17, 1, -8),
+(3, 1, -7),
+(23, 1, -6),
+(22, 1, -5),
+(11, 1, -4),
+(21, 1, -3),
+(19, 1, -2),
+(30, 1, -1),
+
+(20, 1, 1),
+(16, 1, 2),
+(18, 1, 3),
+(9, 1, 4),
+(15, 1, 5),
+(28, 1, 6),
+(29, 1, 7),
+(25, 1, 8),
+(10, 1, 9),
+(13, 1, 10),
+(27, 1, 11),
+(24, 1, 12),
+(12, 1, 13),
+(26, 1, 14),
+(14, 1, 15)
+;
+
+SELECT b, c FROM t1 WHERE b = 1 GROUP BY b, c;
+
+EXPLAIN
+SELECT b, c FROM t1 WHERE b = 1 GROUP BY b, c;
+
+DROP TABLE t1;
+
+--echo #
+--echo # Bug #45807: crash accessing partitioned table and sql_mode
+--echo # contains ONLY_FULL_GROUP_BY
+--echo #
+
+SET SESSION SQL_MODE='ONLY_FULL_GROUP_BY';
+CREATE TABLE t1(id INT,KEY(id)) ENGINE=MYISAM
+ PARTITION BY HASH(id) PARTITIONS 2;
+DROP TABLE t1;
+SET SESSION SQL_MODE=DEFAULT;
+
--echo End of 5.1 tests
-
SET @@global.general_log= @old_general_log;
diff --git a/mysql-test/t/plugin.test b/mysql-test/t/plugin.test
index 0635a58a4a6..7fc62b445c9 100644
--- a/mysql-test/t/plugin.test
+++ b/mysql-test/t/plugin.test
@@ -3,13 +3,16 @@
CREATE TABLE t1(a int) ENGINE=EXAMPLE;
DROP TABLE t1;
-INSTALL PLUGIN example SONAME 'ha_example.so';
+--replace_regex /\.dll/.so/
+eval INSTALL PLUGIN example SONAME $HA_EXAMPLE_SO;
+--replace_regex /\.dll/.so/
--error 1125
-INSTALL PLUGIN EXAMPLE SONAME 'ha_example.so';
+eval INSTALL PLUGIN EXAMPLE SONAME $HA_EXAMPLE_SO;
UNINSTALL PLUGIN example;
-INSTALL PLUGIN example SONAME 'ha_example.so';
+--replace_regex /\.dll/.so/
+eval INSTALL PLUGIN example SONAME $HA_EXAMPLE_SO;
CREATE TABLE t1(a int) ENGINE=EXAMPLE;
@@ -30,8 +33,8 @@ UNINSTALL PLUGIN non_exist;
--echo # Bug#32034: check_func_enum() does not check correct values but set it
--echo # to impossible int val
--echo #
-
-INSTALL PLUGIN example SONAME 'ha_example.so';
+--replace_regex /\.dll/.so/
+eval INSTALL PLUGIN example SONAME $HA_EXAMPLE_SO;
SET GLOBAL example_enum_var= e1;
SET GLOBAL example_enum_var= e2;
@@ -45,7 +48,8 @@ UNINSTALL PLUGIN example;
#
# Bug #32757 hang with sql_mode set when setting some global variables
#
-INSTALL PLUGIN example SONAME 'ha_example.so';
+--replace_regex /\.dll/.so/
+eval INSTALL PLUGIN example SONAME $HA_EXAMPLE_SO;
select @@session.sql_mode into @old_sql_mode;
diff --git a/mysql-test/t/plugin_load-master.opt b/mysql-test/t/plugin_load-master.opt
index 66637841f16..bb7831c5769 100644
--- a/mysql-test/t/plugin_load-master.opt
+++ b/mysql-test/t/plugin_load-master.opt
@@ -1,3 +1,3 @@
$EXAMPLE_PLUGIN_OPT
-"--plugin-load=;EXAMPLE=ha_example.so;"
+$EXAMPLE_PLUGIN_LOAD
--loose-plugin-example-enum-var=e2
diff --git a/mysql-test/t/query_cache_debug.test b/mysql-test/t/query_cache_debug.test
index 8cf5e9d4b16..d30cd458e99 100644
--- a/mysql-test/t/query_cache_debug.test
+++ b/mysql-test/t/query_cache_debug.test
@@ -112,3 +112,148 @@ DROP TABLE t1,t2;
SET GLOBAL concurrent_insert= DEFAULT;
SET GLOBAL query_cache_size= DEFAULT;
SET GLOBAL query_cache_type= DEFAULT;
+
+
+--echo #
+--echo # Bug43758 Query cache can lock up threads in 'freeing items' state
+--echo #
+FLUSH STATUS;
+SET GLOBAL query_cache_type=DEMAND;
+SET GLOBAL query_cache_size= 1024*768;
+--disable_warnings
+DROP TABLE IF EXISTS t1,t2,t3,t4,t5;
+--enable_warnings
+CREATE TABLE t1 (a VARCHAR(100));
+CREATE TABLE t2 (a VARCHAR(100));
+CREATE TABLE t3 (a VARCHAR(100));
+CREATE TABLE t4 (a VARCHAR(100));
+CREATE TABLE t5 (a VARCHAR(100));
+
+INSERT INTO t1 VALUES ('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'),('bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb');
+INSERT INTO t2 VALUES ('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'),('bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb');
+INSERT INTO t3 VALUES ('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'),('bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb');
+INSERT INTO t4 VALUES ('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'),('bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb');
+INSERT INTO t5 VALUES ('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'),('bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb');
+
+connect (thd2, localhost, root, ,test);
+connect (thd3, localhost, root, ,test);
+connect (thd1, localhost, root, ,test);
+
+connection thd1;
+--echo =================================== Connection thd1
+--echo **
+--echo ** Load Query Cache with a result set and one table.
+--echo **
+SELECT SQL_CACHE * FROM t1;
+--echo *************************************************************************
+--echo ** We want to accomplish the following state:
+--echo ** - Query cache status: TABLE_FLUSH_IN_PROGRESS
+--echo ** - THD1: invalidate_table_internal (iterating query blocks)
+--echo ** - THD2: query_cache_insert (cond_wait)
+--echo ** - THD3: query_cache_insert (cond_wait)
+--echo ** - No thread should be holding the structure_guard_mutex.
+--echo **
+--echo ** First step is to place a DELETE-statement on the debug hook just
+--echo ** before the mutex lock in invalidate_table_internal.
+--echo ** This will allow new result sets to be written into the QC.
+--echo **
+SET SESSION debug='+d,wait_in_query_cache_invalidate1';
+SET SESSION debug='+d,wait_in_query_cache_invalidate2';
+--send DELETE FROM t1 WHERE a like '%a%';
+
+connection default;
+--echo =================================== Connection default
+--echo ** Assert that the expect process status is obtained.
+LET $wait_condition= SELECT SQL_NO_CACHE COUNT(*)= 1 FROM information_schema.processlist WHERE state= 'wait_in_query_cache_invalidate1';
+--source include/wait_condition.inc
+-- echo **
+
+connection thd2;
+--echo =================================== Connection thd2
+--echo ** On THD2: Insert a result into the cache. This attempt will be blocked
+--echo ** because of a debug hook placed just before the mutex lock after which
+--echo ** the first part of the result set is written.
+SET SESSION debug='+d,wait_in_query_cache_insert';
+--send SELECT SQL_CACHE * FROM t2 UNION SELECT * FROM t3
+
+connection thd3;
+--echo =================================== Connection thd3
+--echo ** On THD3: Insert another result into the cache and block on the same
+--echo ** debug hook.
+SET SESSION debug='+d,wait_in_query_cache_insert';
+--send SELECT SQL_CACHE * FROM t4 UNION SELECT * FROM t5;
+
+connection default;
+--echo =================================== Connection default
+--echo ** Assert that the two SELECT-stmt threads to reach the hook.
+LET $wait_condition= SELECT SQL_NO_CACHE COUNT(*)= 2 FROM information_schema.processlist WHERE state='wait_in_query_cache_insert';
+--source include/wait_condition.inc
+--echo **
+--echo **
+
+--echo ** Signal the DELETE thread, THD1, to continue. It will enter the mutex
+--echo ** lock and set query cache status to TABLE_FLUSH_IN_PROGRESS and then
+--echo ** unlock the mutex before stopping on the next debug hook.
+SELECT SQL_NO_CACHE id FROM information_schema.processlist WHERE state='wait_in_query_cache_invalidate1' LIMIT 1 INTO @flush_thread_id;
+KILL QUERY @flush_thread_id;
+--echo ** Assert that we reach the next debug hook.
+LET $wait_condition= SELECT SQL_NO_CACHE COUNT(*)= 1 FROM information_schema.processlist WHERE state='wait_in_query_cache_invalidate2';
+--source include/wait_condition.inc
+
+--echo **
+--echo ** Signal the remaining debug hooks blocking THD2 and THD3.
+--echo ** The threads will grab the guard mutex enter the wait condition and
+--echo ** and finally release the mutex. The threads will continue to wait
+--echo ** until a broadcast signal reaches them causing both threads to
+--echo ** come alive and check the condition.
+SELECT SQL_NO_CACHE id FROM information_schema.processlist WHERE state='wait_in_query_cache_insert' ORDER BY id ASC LIMIT 1 INTO @thread_id;
+KILL QUERY @thread_id;
+SELECT SQL_NO_CACHE id FROM information_schema.processlist WHERE state='wait_in_query_cache_insert' ORDER BY id DESC LIMIT 1 INTO @thread_id;
+KILL QUERY @thread_id;
+
+--echo **
+--echo ** Finally signal the DELETE statement on THD1 one last time.
+--echo ** The stmt will complete the query cache invalidation and return
+--echo ** cache status to NO_FLUSH_IN_PROGRESS. On the status change
+--echo ** One signal will be sent to the thread group waiting for executing
+--echo ** invalidations and a broadcast signal will be sent to the thread
+--echo ** group holding result set writers.
+SELECT SQL_NO_CACHE id FROM information_schema.processlist WHERE state='wait_in_query_cache_invalidate2' LIMIT 1 INTO @flush_thread_id;
+KILL QUERY @flush_thread_id;
+
+--echo **
+--echo *************************************************************************
+--echo ** No tables should be locked
+connection thd2;
+--echo =================================== Connection thd2
+reap;
+DELETE FROM t1;
+DELETE FROM t2;
+DELETE FROM t3;
+
+connection thd3;
+--echo =================================== Connection thd3
+reap;
+DELETE FROM t4;
+DELETE FROM t5;
+
+connection thd1;
+--echo =================================== Connection thd1
+reap;
+
+--echo ** Done.
+
+connection default;
+disconnect thd1;
+disconnect thd2;
+disconnect thd3;
+SET GLOBAL query_cache_size= 0;
+
+connection default;
+--echo # Restore defaults
+RESET QUERY CACHE;
+FLUSH STATUS;
+DROP TABLE t1,t2,t3,t4,t5;
+SET GLOBAL query_cache_size= DEFAULT;
+SET GLOBAL query_cache_type= DEFAULT;
+exit;
diff --git a/mysql-test/t/select.test b/mysql-test/t/select.test
index 715bdf0e667..7d3785ecccc 100644
--- a/mysql-test/t/select.test
+++ b/mysql-test/t/select.test
@@ -3799,4 +3799,90 @@ EXPLAIN EXTENDED SELECT * FROM t1 WHERE (a=a AND a=a AND b=b) OR b > 20;
EXPLAIN EXTENDED SELECT * FROM t1 WHERE (a=a AND b=b AND a=a) OR b > 20;
DROP TABLE t1;
+
+--echo #
+--echo # Bug#45266: Uninitialized variable lead to an empty result.
+--echo #
+--disable_warnings
+drop table if exists A,AA,B,BB;
+CREATE TABLE `A` (
+ `pk` int(11) NOT NULL AUTO_INCREMENT,
+ `date_key` date NOT NULL,
+ `date_nokey` date NOT NULL,
+ `datetime_key` datetime NOT NULL,
+ `int_nokey` int(11) NOT NULL,
+ `time_key` time NOT NULL,
+ `time_nokey` time NOT NULL,
+ PRIMARY KEY (`pk`),
+ KEY `date_key` (`date_key`),
+ KEY `time_key` (`time_key`),
+ KEY `datetime_key` (`datetime_key`)
+);
+
+CREATE TABLE `AA` (
+ `pk` int(11) NOT NULL AUTO_INCREMENT,
+ `int_nokey` int(11) NOT NULL,
+ `time_key` time NOT NULL,
+ KEY `time_key` (`time_key`),
+ PRIMARY KEY (`pk`)
+);
+
+CREATE TABLE `B` (
+ `date_nokey` date NOT NULL,
+ `date_key` date NOT NULL,
+ `time_key` time NOT NULL,
+ `datetime_nokey` datetime NOT NULL,
+ `varchar_key` varchar(1) NOT NULL,
+ KEY `date_key` (`date_key`),
+ KEY `time_key` (`time_key`),
+ KEY `varchar_key` (`varchar_key`)
+);
+
+INSERT INTO `B` VALUES ('2003-07-28','2003-07-28','15:13:38','0000-00-00 00:00:00','f'),('0000-00-00','0000-00-00','00:05:48','2004-07-02 14:34:13','x');
+
+CREATE TABLE `BB` (
+ `pk` int(11) NOT NULL AUTO_INCREMENT,
+ `int_nokey` int(11) NOT NULL,
+ `date_key` date NOT NULL,
+ `varchar_nokey` varchar(1) NOT NULL,
+ `date_nokey` date NOT NULL,
+ PRIMARY KEY (`pk`),
+ KEY `date_key` (`date_key`)
+);
+
+INSERT INTO `BB` VALUES (10,8,'0000-00-00','i','0000-00-00'),(11,0,'2005-08-18','','2005-08-18');
+# Test #1
+SELECT table1 . `pk` AS field1
+ FROM
+ (BB AS table1 INNER JOIN
+ (AA AS table2 STRAIGHT_JOIN A AS table3
+ ON ( table3 . `date_key` = table2 . `pk` ))
+ ON ( table3 . `datetime_key` = table2 . `int_nokey` ))
+ WHERE ( table3 . `date_key` <= 4 AND table2 . `pk` = table1 . `varchar_nokey`)
+ GROUP BY field1 ;
+
+SELECT table3 .`date_key` field1
+ FROM
+ B table1 LEFT JOIN B table3 JOIN
+ (BB table6 JOIN A table7 ON table6 .`varchar_nokey`)
+ ON table6 .`int_nokey` ON table6 .`date_key`
+ WHERE NOT ( table1 .`varchar_key` AND table7 .`pk`) GROUP BY field1;
+
+# Test #2
+SELECT table4 . `time_nokey` AS field1 FROM
+ (AA AS table1 CROSS JOIN
+ (AA AS table2 STRAIGHT_JOIN
+ (B AS table3 STRAIGHT_JOIN A AS table4
+ ON ( table4 . `date_key` = table3 . `time_key` ))
+ ON ( table4 . `pk` = table3 . `date_nokey` ))
+ ON ( table4 . `time_key` = table3 . `datetime_nokey` ))
+ WHERE ( table4 . `time_key` < table1 . `time_key` AND
+ table1 . `int_nokey` != 'f')
+ GROUP BY field1 ORDER BY field1 , field1;
+
+SELECT table1 .`time_key` field2 FROM B table1 LEFT JOIN BB JOIN A table5 ON table5 .`date_nokey` ON table5 .`int_nokey` GROUP BY field2;
+--enable_warnings
+
+drop table A,AA,B,BB;
+--echo #end of test for bug#45266
--echo End of 5.1 tests
diff --git a/mysql-test/t/sp-error.test b/mysql-test/t/sp-error.test
index 8d7c6d75a34..66b960c938f 100644
--- a/mysql-test/t/sp-error.test
+++ b/mysql-test/t/sp-error.test
@@ -2435,3 +2435,16 @@ delimiter ;$$
#
LOAD DATA INFILE '../../tmp/proc.txt' INTO TABLE mysql.proc;
remove_file $MYSQLTEST_VARDIR/tmp/proc.txt;
+
+#
+# Bug #38159: Function parsing problem generates misleading error message
+#
+
+CREATE TABLE t1 (a INT, b INT);
+INSERT INTO t1 VALUES (1,1), (2,2);
+--error ER_FUNC_INEXISTENT_NAME_COLLISION
+SELECT MAX (a) FROM t1 WHERE b = 999999;
+SELECT AVG (a) FROM t1 WHERE b = 999999;
+--error ER_SP_DOES_NOT_EXIST
+SELECT non_existent (a) FROM t1 WHERE b = 999999;
+DROP TABLE t1;
diff --git a/mysql-test/t/sp-fib.test b/mysql-test/t/sp-fib.test
new file mode 100644
index 00000000000..24a51b99c2d
--- /dev/null
+++ b/mysql-test/t/sp-fib.test
@@ -0,0 +1,54 @@
+# Fibonacci, for recursion test. (Yet Another Numerical series :)
+# Split from main.sp due to problems reported in Bug#15866
+
+--disable_warnings
+drop table if exists t3;
+--enable_warnings
+create table t3 ( f bigint unsigned not null );
+
+# We deliberately do it the awkward way, fetching the last two
+# values from the table, in order to exercise various statements
+# and table accesses at each turn.
+--disable_warnings
+drop procedure if exists fib;
+--enable_warnings
+
+# Now for multiple statements...
+delimiter |;
+
+create procedure fib(n int unsigned)
+begin
+ if n > 1 then
+ begin
+ declare x, y bigint unsigned;
+ declare c cursor for select f from t3 order by f desc limit 2;
+ open c;
+ fetch c into y;
+ fetch c into x;
+ insert into t3 values (x+y);
+ call fib(n-1);
+ ## Close the cursor AFTER the recursion to ensure that the stack
+ ## frame is somewhat intact.
+ close c;
+ end;
+ end if;
+end|
+
+# Enable recursion
+set @@max_sp_recursion_depth= 20|
+
+insert into t3 values (0), (1)|
+
+# The small number of recursion levels is intentional.
+# We need to avoid
+# Bug#15866 main.sp fails (thread stack limit
+# insufficient for recursive call "fib(20)")
+# which affects some platforms.
+call fib(4)|
+
+select * from t3 order by f asc|
+
+drop table t3|
+drop procedure fib|
+set @@max_sp_recursion_depth= 0|
+
diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test
index fdf6ed8f382..5eeac457958 100644
--- a/mysql-test/t/sp.test
+++ b/mysql-test/t/sp.test
@@ -1561,61 +1561,6 @@ drop procedure ip|
show procedure status where name like '%p%' and db='test'|
-# Fibonacci, for recursion test. (Yet Another Numerical series :)
-#
---disable_warnings
-drop table if exists t3|
---enable_warnings
-create table t3 ( f bigint unsigned not null )|
-
-# We deliberately do it the awkward way, fetching the last two
-# values from the table, in order to exercise various statements
-# and table accesses at each turn.
---disable_warnings
-drop procedure if exists fib|
---enable_warnings
-create procedure fib(n int unsigned)
-begin
- if n > 1 then
- begin
- declare x, y bigint unsigned;
- declare c cursor for select f from t3 order by f desc limit 2;
-
- open c;
- fetch c into y;
- fetch c into x;
- close c;
- insert into t3 values (x+y);
- call fib(n-1);
- end;
- end if;
-end|
-
-# Enable recursion
-set @@max_sp_recursion_depth= 20|
-
-# Minimum test: recursion of 3 levels
-
-insert into t3 values (0), (1)|
-
-call fib(3)|
-
-select * from t3 order by f asc|
-
-truncate table t3|
-
-# The original test, 20 levels, ran into memory limits on some machines
-# and builds. Try 10 instead...
-
-insert into t3 values (0), (1)|
-
-call fib(10)|
-
-select * from t3 order by f asc|
-drop table t3|
-drop procedure fib|
-set @@max_sp_recursion_depth= 0|
-
#
# Comment & suid
#
diff --git a/mysql-test/t/sp_notembedded.test b/mysql-test/t/sp_notembedded.test
index f540126c405..ecb37c1299c 100644
--- a/mysql-test/t/sp_notembedded.test
+++ b/mysql-test/t/sp_notembedded.test
@@ -345,6 +345,32 @@ drop procedure p1;
drop table t1;
set session low_priority_updates=default;
+#
+# Bug#44798 MySQL engine crashes when creating stored procedures with execute_priv=N
+#
+INSERT INTO mysql.user (Host, User, Password, Select_priv, Insert_priv, Update_priv,
+Delete_priv, Create_priv, Drop_priv, Reload_priv, Shutdown_priv, Process_priv, File_priv,
+Grant_priv, References_priv, Index_priv, Alter_priv, Show_db_priv, Super_priv,
+Create_tmp_table_priv, Lock_tables_priv, Execute_priv, Repl_slave_priv, Repl_client_priv,
+Create_view_priv, Show_view_priv, Create_routine_priv, Alter_routine_priv,
+Create_user_priv, ssl_type, ssl_cipher, x509_issuer, x509_subject, max_questions,
+max_updates, max_connections, max_user_connections)
+VALUES('%', 'mysqltest_1', password(''), 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'N', 'N', 'N',
+'N', 'N', 'N', 'Y', 'Y', 'N', 'N', 'Y', 'Y', 'N', 'N', 'N', 'N', 'N', 'Y', 'Y', 'N', '',
+'', '', '', '0', '0', '0', '0');
+FLUSH PRIVILEGES;
+
+connect (con1, localhost, mysqltest_1,,);
+connection con1;
+CREATE PROCEDURE p1(i INT) BEGIN END;
+disconnect con1;
+connection default;
+DROP PROCEDURE p1;
+
+DELETE FROM mysql.user WHERE User='mysqltest_1';
+FLUSH PRIVILEGES;
+
+
#
# Restore global concurrent_insert value. Keep in the end of the test file.
#
diff --git a/mysql-test/t/sql_mode.test b/mysql-test/t/sql_mode.test
index acc9cc7979e..4a9f34443cb 100644
--- a/mysql-test/t/sql_mode.test
+++ b/mysql-test/t/sql_mode.test
@@ -308,3 +308,39 @@ flush privileges;
--connection default
drop user mysqltest_32753@localhost;
+
+#
+# Bug#45100: Incomplete DROP USER in case of SQL_MODE = 'PAD_CHAR_TO_FULL_LENGTH'
+#
+
+--disable_warnings
+DROP TABLE IF EXISTS t1,t2;
+--enable_warnings
+
+# Generate some prerequisites
+CREATE USER 'user_PCTFL'@'localhost' identified by 'PWD';
+CREATE USER 'user_no_PCTFL'@'localhost' identified by 'PWD';
+
+CREATE TABLE t1 (f1 BIGINT);
+CREATE TABLE t2 (f1 CHAR(3) NOT NULL, f2 CHAR(20));
+
+# Grant privilege on a TABLE
+GRANT ALL ON t1 TO 'user_PCTFL'@'localhost','user_no_PCTFL'@'localhost';
+# Grant privilege on some COLUMN of a table
+GRANT SELECT(f1) ON t2 TO 'user_PCTFL'@'localhost','user_no_PCTFL'@'localhost';
+
+SET @OLD_SQL_MODE = @@SESSION.SQL_MODE;
+SET SESSION SQL_MODE = 'PAD_CHAR_TO_FULL_LENGTH';
+DROP USER 'user_PCTFL'@'localhost';
+SET SESSION SQL_MODE = @OLD_SQL_MODE;
+DROP USER 'user_no_PCTFL'@'localhost';
+
+FLUSH PRIVILEGES;
+
+SELECT * FROM mysql.db WHERE Host = 'localhost' AND User LIKE 'user_%PCTFL';
+SELECT * FROM mysql.tables_priv WHERE Host = 'localhost' AND User LIKE 'user_%PCTFL';
+SELECT * FROM mysql.columns_priv WHERE Host = 'localhost' AND User LIKE 'user_%PCTFL';
+
+# Cleanup
+DROP TABLE t1;
+DROP TABLE t2;
diff --git a/mysql-test/t/status.test b/mysql-test/t/status.test
index 5842f59af5c..5da210f5a69 100644
--- a/mysql-test/t/status.test
+++ b/mysql-test/t/status.test
@@ -12,6 +12,12 @@
set @old_concurrent_insert= @@global.concurrent_insert;
set @@global.concurrent_insert= 0;
+# Disable logging to table, since this will also cause table locking and unlocking, which will
+# show up in SHOW STATUS and may cause sporadic failures
+
+SET @old_log_output = @@global.log_output;
+SET GLOBAL LOG_OUTPUT = 'FILE';
+
# PS causes different statistics
--disable_ps_protocol
@@ -350,6 +356,7 @@ DROP FUNCTION f1;
# Restore global concurrent_insert value. Keep in the end of the test file.
--connection default
set @@global.concurrent_insert= @old_concurrent_insert;
+SET GLOBAL log_output = @old_log_output;
# Wait till we reached the initial number of concurrent sessions
--source include/wait_until_count_sessions.inc
diff --git a/mysql-test/t/subselect3.test b/mysql-test/t/subselect3.test
index bf461f83a20..7a2a9f328ef 100644
--- a/mysql-test/t/subselect3.test
+++ b/mysql-test/t/subselect3.test
@@ -669,6 +669,25 @@ SELECT ROW(1,2) = (SELECT NULL, 1), ROW(1,2) IN (SELECT NULL, 1);
SELECT ROW(1,2) = (SELECT 1, 1), ROW(1,2) IN (SELECT 1, 1);
SELECT ROW(1,2) = (SELECT 1, 2), ROW(1,2) IN (SELECT 1, 2);
+#
+# Bug #37362 Crash in do_field_eq
+#
+CREATE TABLE t1 (a INT, b INT, c INT);
+INSERT INTO t1 VALUES (1,1,1), (1,1,1);
+
+--error 1054
+EXPLAIN EXTENDED
+ SELECT c FROM
+ ( SELECT
+ (SELECT COUNT(a) FROM
+ (SELECT COUNT(b) FROM t1) AS x GROUP BY c
+ ) FROM t1 GROUP BY b
+ ) AS y;
+SHOW WARNINGS;
+
+DROP TABLE t1;
+
+
--echo End of 5.0 tests
#
diff --git a/mysql-test/t/trigger.test b/mysql-test/t/trigger.test
index 9a5556c518d..1e55f9d5993 100644
--- a/mysql-test/t/trigger.test
+++ b/mysql-test/t/trigger.test
@@ -2370,4 +2370,30 @@ drop trigger trg1;
drop trigger trg2;
drop table t1, t2;
+#
+# Bug#44653: Server crash noticed when executing random queries with partitions.
+#
+CREATE TABLE t1 ( a INT, b INT );
+CREATE TABLE t2 ( a INT AUTO_INCREMENT KEY, b INT );
+
+INSERT INTO t1 (a) VALUES (1);
+
+delimiter //;
+CREATE TRIGGER tr1
+BEFORE INSERT ON t2
+FOR EACH ROW
+BEGIN
+ UPDATE a_nonextisting_table SET a = 1;
+END//
+delimiter ;//
+
+--disable_abort_on_error
+CREATE TABLE IF NOT EXISTS t2 ( a INT, b INT ) SELECT a, b FROM t1;
+--enable_abort_on_error
+
+# Caused failed assertion
+SELECT * FROM t2;
+
+DROP TABLE t1, t2;
+
--echo End of 5.1 tests.
diff --git a/mysql-test/t/trigger_notembedded.test b/mysql-test/t/trigger_notembedded.test
index 9588ec6e3ed..7a7e6c6bc85 100644
--- a/mysql-test/t/trigger_notembedded.test
+++ b/mysql-test/t/trigger_notembedded.test
@@ -909,4 +909,27 @@ select * from t1;
drop table t1;
disconnect flush;
+#
+# Bug#45412 SHOW CREATE TRIGGER does not require privileges to disclose trigger data
+#
+CREATE DATABASE db1;
+CREATE TABLE db1.t1 (a char(30)) ENGINE=MEMORY;
+CREATE TRIGGER db1.trg AFTER INSERT ON db1.t1 FOR EACH ROW
+ INSERT INTO db1.t1 VALUES('Some very sensitive data goes here');
+
+CREATE USER 'no_rights'@'localhost';
+REVOKE ALL ON *.* FROM 'no_rights'@'localhost';
+FLUSH PRIVILEGES;
+
+connect (con1,localhost,no_rights,,);
+SELECT trigger_name FROM INFORMATION_SCHEMA.TRIGGERS
+ WHERE trigger_schema = 'db1';
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+SHOW CREATE TRIGGER db1.trg;
+
+connection default;
+disconnect con1;
+DROP USER 'no_rights'@'localhost';
+DROP DATABASE db1;
+
--echo End of 5.1 tests.
diff --git a/mysql-test/t/type_newdecimal.test b/mysql-test/t/type_newdecimal.test
index 4cf9ea63dad..cd3c3f81510 100644
--- a/mysql-test/t/type_newdecimal.test
+++ b/mysql-test/t/type_newdecimal.test
@@ -1257,3 +1257,32 @@ select cast(-3.4 as decimal(2,1));
select cast(99.6 as decimal(2,0));
select cast(-13.4 as decimal(2,1));
select cast(98.6 as decimal(2,0));
+
+--echo #
+--echo # Bug #45262: Bad effects with CREATE TABLE and DECIMAL
+--echo #
+
+CREATE TABLE t1 SELECT .123456789123456789123456789123456789123456789123456789123456789123456789123456789 AS my_col;
+DESCRIBE t1;
+SELECT my_col FROM t1;
+DROP TABLE t1;
+
+CREATE TABLE t1 SELECT 1 + .123456789123456789123456789123456789123456789123456789123456789123456789123456789 AS my_col;
+DESCRIBE t1;
+SELECT my_col FROM t1;
+DROP TABLE t1;
+
+CREATE TABLE t1 SELECT 1 * .123456789123456789123456789123456789123456789123456789123456789123456789123456789 AS my_col;
+DESCRIBE t1;
+SELECT my_col FROM t1;
+DROP TABLE t1;
+
+CREATE TABLE t1 SELECT 1 / .123456789123456789123456789123456789123456789123456789123456789123456789123456789 AS my_col;
+DESCRIBE t1;
+SELECT my_col FROM t1;
+DROP TABLE t1;
+
+CREATE TABLE t1 SELECT 1 % .123456789123456789123456789123456789123456789123456789123456789123456789123456789 AS my_col;
+DESCRIBE t1;
+SELECT my_col FROM t1;
+DROP TABLE t1;
diff --git a/mysql-test/t/type_time.test b/mysql-test/t/type_time.test
index 5fc763be7fe..5bb521601e5 100644
--- a/mysql-test/t/type_time.test
+++ b/mysql-test/t/type_time.test
@@ -77,3 +77,16 @@ insert into t1 values('2007-07-02', 1);
insert into t1 values('2007-07-02', 2);
SELECT sum(f3) FROM t1 where f2='2007-07-01 00:00:00' group by f2;
drop table t1;
+
+
+--echo #
+--echo # Bug #44792: valgrind warning when casting from time to time
+--echo #
+
+CREATE TABLE t1 (c TIME);
+INSERT INTO t1 VALUES ('0:00:00');
+SELECT CAST(c AS TIME) FROM t1;
+DROP TABLE t1;
+
+
+--echo End of 5.0 tests
diff --git a/mysql-test/t/union.test b/mysql-test/t/union.test
index ece7099f66e..ec169838d59 100644
--- a/mysql-test/t/union.test
+++ b/mysql-test/t/union.test
@@ -1089,4 +1089,16 @@ CREATE TABLE t2 AS SELECT d FROM t1 UNION SELECT d FROM t1;
SHOW FIELDS FROM t2;
DROP TABLE t1, t2;
+#
+# Bug#43612 crash with explain extended, union, order by
+#
+CREATE TABLE t1(a INT);
+EXPLAIN EXTENDED
+SELECT a FROM t1
+UNION
+SELECT a FROM t1
+ORDER BY a;
+DROP TABLE t1;
+
+
--echo End of 5.0 tests
diff --git a/mysql-test/t/user_var.test b/mysql-test/t/user_var.test
index fd4e538ea6c..c0740458a88 100644
--- a/mysql-test/t/user_var.test
+++ b/mysql-test/t/user_var.test
@@ -285,6 +285,18 @@ set @lastid=-1;
select @lastid != id, @lastid, @lastid := id from t1;
drop table t1;
+#
+# Bug#42009: SELECT into variable gives different results to direct SELECT
+#
+CREATE TABLE t1(a INT, b INT);
+INSERT INTO t1 VALUES (0, 0), (2, 1), (2, 3), (1, 1), (30, 20);
+SELECT a, b INTO @a, @b FROM t1 WHERE a=2 AND b=3 GROUP BY a, b;
+SELECT @a, @b;
+SELECT a, b FROM t1 WHERE a=2 AND b=3 GROUP BY a, b;
+DROP TABLE t1;
+
+--echo End of 5.0 tests
+
#
# Bug#42188: crash and/or memory corruption with user variables in trigger
#
diff --git a/mysql-test/t/variables.test b/mysql-test/t/variables.test
index 6da20409639..1580d7f36d7 100644
--- a/mysql-test/t/variables.test
+++ b/mysql-test/t/variables.test
@@ -1201,4 +1201,29 @@ SET GLOBAL server_id = -1;
SELECT @@GLOBAL.server_id;
SET GLOBAL server_id = @old_server_id;
+#
+# Bug #42778: delete order by null global variable causes
+# assertion .\filesort.cc, line 797
+#
+
+SELECT @@GLOBAL.INIT_FILE, @@GLOBAL.INIT_FILE IS NULL;
+
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES ();
+SET @bug42778= @@sql_safe_updates;
+SET @@sql_safe_updates= 0;
+DELETE FROM t1 ORDER BY (@@GLOBAL.INIT_FILE) ASC LIMIT 10;
+SET @@sql_safe_updates= @bug42778;
+
+DROP TABLE t1;
+
+--echo #
+--echo # BUG#10206 - InnoDB: Transaction requiring Max_BinLog_Cache_size > 4GB always rollsback
+--echo #
+
+SET @old_max_binlog_cache_size = @@GLOBAL.max_binlog_cache_size;
+--echo # Set the max_binlog_cache_size to size more than 4GB.
+SET GLOBAL max_binlog_cache_size = 5 * 1024 * 1024 * 1024;
+SELECT @@GLOBAL.max_binlog_cache_size;
+SET GLOBAL max_binlog_cache_size = @old_max_binlog_cache_size;
--echo End of 5.1 tests
diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test
index c9d01266e9e..7bec02e6fb6 100644
--- a/mysql-test/t/view.test
+++ b/mysql-test/t/view.test
@@ -3680,6 +3680,61 @@ SELECT * FROM v1 IGNORE INDEX (c2) WHERE c2=2;
DROP VIEW v1;
DROP TABLE t1;
+--echo # -----------------------------------------------------------------
+--echo # -- Bug#40825: Error 1356 while selecting from a view
+--echo # -- with a "HAVING" clause though query works
+--echo # -----------------------------------------------------------------
+--echo
+
+CREATE TABLE t1 (c INT);
+
+--echo
+
+CREATE VIEW v1 (view_column) AS SELECT c AS alias FROM t1 HAVING alias;
+SHOW CREATE VIEW v1;
+SELECT * FROM v1;
+
+--echo
+
+DROP VIEW v1;
+DROP TABLE t1;
+
+--echo
+--echo # -- End of test case for Bug#40825
+--echo
+
+--echo #
+--echo # Bug #45806 crash when replacing into a view with a join!
+--echo #
+CREATE TABLE t1(a INT UNIQUE);
+CREATE VIEW v1 AS SELECT t1.a FROM t1, t1 AS a;
+INSERT INTO t1 VALUES (1), (2);
+
+REPLACE INTO v1(a) SELECT 1 FROM t1,t1 AS c;
+SELECT * FROM v1;
+REPLACE INTO v1(a) SELECT 3 FROM t1,t1 AS c;
+SELECT * FROM v1;
+DELETE FROM t1 WHERE a=3;
+INSERT INTO v1(a) SELECT 1 FROM t1,t1 AS c
+ON DUPLICATE KEY UPDATE `v1`.`a`= 1;
+SELECT * FROM v1;
+
+CREATE VIEW v2 AS SELECT t1.a FROM t1, v1 AS a;
+
+REPLACE INTO v2(a) SELECT 1 FROM t1,t1 AS c;
+SELECT * FROM v2;
+REPLACE INTO v2(a) SELECT 3 FROM t1,t1 AS c;
+SELECT * FROM v2;
+INSERT INTO v2(a) SELECT 1 FROM t1,t1 AS c
+ON DUPLICATE KEY UPDATE `v2`.`a`= 1;
+SELECT * FROM v2;
+
+DROP VIEW v1;
+DROP VIEW v2;
+DROP TABLE t1;
+
+--echo # -- End of test case for Bug#45806
+
--echo # -----------------------------------------------------------------
--echo # -- End of 5.0 tests.
--echo # -----------------------------------------------------------------
@@ -3836,6 +3891,17 @@ drop procedure p;
###########################################################################
+
+--echo #
+--echo # Bug #44860: ALTER TABLE on view crashes server
+--echo #
+CREATE TABLE t1 (a INT);
+CREATE VIEW v1 AS SELECT a FROM t1;
+ALTER TABLE v1;
+DROP VIEW v1;
+DROP TABLE t1;
+
+
--echo # -----------------------------------------------------------------
--echo # -- End of 5.1 tests.
--echo # -----------------------------------------------------------------
diff --git a/mysql-test/t/xa.test b/mysql-test/t/xa.test
index 04ecf518577..7b1c6a268d5 100644
--- a/mysql-test/t/xa.test
+++ b/mysql-test/t/xa.test
@@ -124,6 +124,31 @@ drop table t1;
--echo End of 5.0 tests
+#
+# Bug#44672: Assertion failed: thd->transaction.xid_state.xid.is_null()
+#
+
+xa start 'a';
+xa end 'a';
+xa rollback 'a';
+xa start 'a';
+xa end 'a';
+xa rollback 'a';
+
+#
+# Bug#45548: XA transaction without access to InnoDB tables crashes the server
+#
+
+xa start 'a';
+xa end 'a';
+xa prepare 'a';
+xa commit 'a';
+
+xa start 'a';
+xa end 'a';
+xa prepare 'a';
+xa commit 'a';
+
# Wait till all disconnects are completed
--source include/wait_until_count_sessions.inc
diff --git a/mysys/charset.c b/mysys/charset.c
index 7a7ef0ad3ea..b23ab084e90 100644
--- a/mysys/charset.c
+++ b/mysys/charset.c
@@ -384,7 +384,7 @@ char *get_charsets_dir(char *buf)
DBUG_RETURN(res);
}
-CHARSET_INFO *all_charsets[256];
+CHARSET_INFO *all_charsets[256]={NULL};
CHARSET_INFO *default_charset_info = &my_charset_latin1;
void add_compiled_collation(CHARSET_INFO *cs)
diff --git a/mysys/hash.c b/mysys/hash.c
index e7b5352af34..63933abb085 100644
--- a/mysys/hash.c
+++ b/mysys/hash.c
@@ -45,6 +45,32 @@ static uint calc_hash(const HASH *hash, const uchar *key, size_t length)
return nr1;
}
+/**
+ @brief Initialize the hash
+
+ @details
+
+ Initialize the hash, by defining and giving valid values for
+ its elements. The failure to allocate memory for the
+ hash->array element will not result in a fatal failure. The
+ dynamic array that is part of the hash will allocate memory
+ as required during insertion.
+
+ @param[in,out] hash The hash that is initialized
+ @param[in] charset The charater set information
+ @param[in] size The hash size
+ @param[in] key_offest The key offset for the hash
+ @param[in] key_length The length of the key used in
+ the hash
+ @param[in] get_key get the key for the hash
+ @param[in] free_element pointer to the function that
+ does cleanup
+ @param[in] CALLER_INFO_PROTO flag that define the behaviour
+ of the hash
+ @return inidicates success or failure of initialization
+ @retval 0 success
+ @retval 1 failure
+*/
my_bool
_my_hash_init(HASH *hash, uint growth_size, CHARSET_INFO *charset,
ulong size, size_t key_offset, size_t key_length,
@@ -55,12 +81,6 @@ _my_hash_init(HASH *hash, uint growth_size, CHARSET_INFO *charset,
DBUG_PRINT("enter",("hash: 0x%lx size: %u", (long) hash, (uint) size));
hash->records=0;
- if (my_init_dynamic_array_ci(&hash->array, sizeof(HASH_LINK), size,
- growth_size))
- {
- hash->free=0; /* Allow call to my_hash_free */
- DBUG_RETURN(1);
- }
hash->key_offset=key_offset;
hash->key_length=key_length;
hash->blength=1;
@@ -68,7 +88,8 @@ _my_hash_init(HASH *hash, uint growth_size, CHARSET_INFO *charset,
hash->free=free_element;
hash->flags=flags;
hash->charset=charset;
- DBUG_RETURN(0);
+ DBUG_RETURN(my_init_dynamic_array_ci(&hash->array,
+ sizeof(HASH_LINK), size, growth_size));
}
@@ -114,6 +135,7 @@ void my_hash_free(HASH *hash)
my_hash_free_elements(hash);
hash->free= 0;
delete_dynamic(&hash->array);
+ hash->blength= 0;
DBUG_VOID_RETURN;
}
diff --git a/mysys/mf_format.c b/mysys/mf_format.c
index f199132626b..6afa2938fa3 100644
--- a/mysys/mf_format.c
+++ b/mysys/mf_format.c
@@ -79,7 +79,7 @@ char * fn_format(char * to, const char *name, const char *dir,
/* To long path, return original or NULL */
size_t tmp_length;
if (flag & MY_SAFE_PATH)
- return NullS;
+ DBUG_RETURN(NullS);
tmp_length= strlength(startpos);
DBUG_PRINT("error",("dev: '%s' ext: '%s' length: %u",dev,ext,
(uint) length));
diff --git a/mysys/mf_getdate.c b/mysys/mf_getdate.c
index 3a8e1be6a0b..9475bebd107 100644
--- a/mysys/mf_getdate.c
+++ b/mysys/mf_getdate.c
@@ -45,15 +45,15 @@ void get_date(register char * to, int flag, time_t date)
skr=date ? (time_t) date : my_time(0);
#if defined(HAVE_LOCALTIME_R) && defined(_REENTRANT)
if (flag & GETDATE_GMT)
- localtime_r(&skr,&tm_tmp);
- else
gmtime_r(&skr,&tm_tmp);
+ else
+ localtime_r(&skr,&tm_tmp);
start_time= &tm_tmp;
#else
if (flag & GETDATE_GMT)
- start_time= localtime(&skr);
- else
start_time= gmtime(&skr);
+ else
+ start_time= localtime(&skr);
#endif
if (flag & GETDATE_SHORT_DATE)
sprintf(to,"%02d%02d%02d",
diff --git a/mysys/my_getopt.c b/mysys/my_getopt.c
index 4b74cdbf266..fd3c2501226 100644
--- a/mysys/my_getopt.c
+++ b/mysys/my_getopt.c
@@ -20,6 +20,7 @@
#include
#include
#include
+#include
typedef void (*init_func_p)(const struct my_option *option, uchar* *variable,
longlong value);
@@ -410,7 +411,8 @@ invalid value '%s'",
argument= optend;
}
else if (optp->arg_type == OPT_ARG &&
- (optp->var_type & GET_TYPE_MASK) == GET_BOOL)
+ (((optp->var_type & GET_TYPE_MASK) == GET_BOOL) ||
+ (optp->var_type & GET_TYPE_MASK) == GET_ENUM))
{
if (optend == disabled_my_option)
*((my_bool*) value)= (my_bool) 0;
@@ -648,8 +650,18 @@ static int setval(const struct my_option *opts, uchar* *value, char *argument,
return EXIT_OUT_OF_MEMORY;
break;
case GET_ENUM:
- if (((*(int*)result_pos)= find_type(argument, opts->typelib, 2) - 1) < 0)
- return EXIT_ARGUMENT_INVALID;
+ if (((*(int*)result_pos)=
+ find_type(argument, opts->typelib, 2) - 1) < 0)
+ {
+ /*
+ Accept an integer representation of the enumerated item.
+ */
+ char *endptr;
+ unsigned int arg= (unsigned int) strtol(argument, &endptr, 10);
+ if (*endptr || arg >= opts->typelib->count)
+ return EXIT_ARGUMENT_INVALID;
+ *(int*)result_pos= arg;
+ }
break;
case GET_SET:
*((ulonglong*)result_pos)= find_typeset(argument, opts->typelib, &err);
diff --git a/mysys/safemalloc.c b/mysys/safemalloc.c
index 36d07b475e9..c484f1d4c54 100644
--- a/mysys/safemalloc.c
+++ b/mysys/safemalloc.c
@@ -174,7 +174,7 @@ void *_mymalloc(size_t size, const char *filename, uint lineno, myf MyFlags)
data[size + 3]= MAGICEND3;
irem->filename= (char *) filename;
irem->linenum= lineno;
- irem->datasize= (uint32) size;
+ irem->datasize= size;
irem->prev= NULL;
/* Add this remember structure to the linked list */
diff --git a/scripts/mysql_convert_table_format.sh b/scripts/mysql_convert_table_format.sh
index d15c7b28410..6f586d0e8e0 100644
--- a/scripts/mysql_convert_table_format.sh
+++ b/scripts/mysql_convert_table_format.sh
@@ -23,18 +23,30 @@ $opt_help=$opt_version=$opt_verbose=$opt_force=0;
$opt_user=$opt_database=$opt_password=undef;
$opt_host="localhost";
$opt_socket="";
-$opt_type="MYISAM";
+$opt_engine="MYISAM";
$opt_port=0;
$exit_status=0;
-GetOptions("force","help","host=s","password=s","user=s","type=s","verbose","version","socket=s", "port=i") ||
- usage(0);
+GetOptions(
+ "e|engine|type=s" => \$opt_type,
+ "f|force" => \$opt_force,
+ "help|?" => \$opt_help,
+ "h|host=s" => \$opt_host,
+ "p|password=s" => \$opt_password,
+ "u|user=s" => \$opt_user,
+ "v|verbose" => \$opt_verbose,
+ "V|version" => \$opt_version,
+ "S|socket=s" => \$opt_socket,
+ "P|port=i" => \$opt_port
+) || usage(0);
+
usage($opt_version) if ($#ARGV < 0 || $opt_help || $opt_version);
+
$opt_database=shift(@ARGV);
-if (uc($opt_type) eq "HEAP")
+if (grep { /^$opt_engine$/i } qw(HEAP MEMORY BLACKHOLE))
{
- print "Converting to type HEAP would delete your tables; aborting\n";
+ print "Converting to '$opt_engine' would delete your data; aborting\n";
exit(1);
}
@@ -54,21 +66,29 @@ $dbh = DBI->connect("DBI:mysql:$opt_database:${opt_host}$connect_opt",
{ PrintError => 0})
|| die "Can't connect to database $opt_database: $DBI::errstr\n";
-if ($#ARGV < 0)
+my @tables;
+
+push(@ARGV, "%") if(!@ARGV);
+
+foreach $pattern (@ARGV)
{
- # Fetch all table names from the database
my ($sth,$row);
- $sth=$dbh->prepare("show tables");
- $sth->execute || die "Can't get tables from $opt_database; $DBI::errstr\n";
+ $sth=$dbh->prepare("SHOW TABLES LIKE ?");
+ $rv= $sth->execute($pattern);
+ if(!int($rv))
+ {
+ warn "Can't get tables matching '$pattern' from $opt_database; $DBI::errstr\n";
+ exit(1) unless $opt_force;
+ }
while (($row = $sth->fetchrow_arrayref))
{
- push(@ARGV,$row->[0]);
+ push(@tables, $row->[0]);
}
$sth->finish;
}
print "Converting tables:\n" if ($opt_verbose);
-foreach $table (@ARGV)
+foreach $table (@tables)
{
my ($sth,$row);
@@ -76,14 +96,15 @@ foreach $table (@ARGV)
$sth=$dbh->prepare("show table status like '$table'");
if ($sth->execute && ($row = $sth->fetchrow_arrayref))
{
- if (uc($row->[1]) eq uc($opt_type))
+ if (uc($row->[1]) eq uc($opt_engine))
{
- print "$table is already of type $opt_type; Ignored\n";
+ print "$table already uses the '$opt_engine' engine; Ignored\n";
next;
}
}
print "converting $table\n" if ($opt_verbose);
- if (!$dbh->do("ALTER TABLE $table ENGINE=$opt_type"))
+ $table=~ s/`/``/g;
+ if (!$dbh->do("ALTER TABLE `$table` ENGINE=$opt_engine"))
{
print STDERR "Can't convert $table: Error $DBI::errstr\n";
exit(1) if (!$opt_force);
@@ -103,43 +124,43 @@ sub usage
print <options.shared_memory_base_name;
+ static const char *name_prefixes[] = {"","Global\\"};
+ const char *prefix;
+ int i;
/*
get enough space base-name + '_' + longest suffix we might ever send
@@ -490,9 +494,18 @@ HANDLE create_shared_memory(MYSQL *mysql,NET *net, uint connect_timeout)
shared_memory_base_name is unique value for each server
unique_part is uniquel value for each object (events and file-mapping)
*/
- suffix_pos = strxmov(tmp, "Global\\", shared_memory_base_name, "_", NullS);
- strmov(suffix_pos, "CONNECT_REQUEST");
- if (!(event_connect_request= OpenEvent(event_access_rights, FALSE, tmp)))
+ for (i = 0; i< array_elements(name_prefixes); i++)
+ {
+ prefix= name_prefixes[i];
+ suffix_pos = strxmov(tmp, prefix , shared_memory_base_name, "_", NullS);
+ strmov(suffix_pos, "CONNECT_REQUEST");
+ event_connect_request= OpenEvent(event_access_rights, FALSE, tmp);
+ if (event_connect_request)
+ {
+ break;
+ }
+ }
+ if (!event_connect_request)
{
error_allow = CR_SHARED_MEMORY_CONNECT_REQUEST_ERROR;
goto err;
@@ -544,7 +557,7 @@ HANDLE create_shared_memory(MYSQL *mysql,NET *net, uint connect_timeout)
unique_part is uniquel value for each object (events and file-mapping)
number_of_connection is number of connection between server and client
*/
- suffix_pos = strxmov(tmp, "Global\\", shared_memory_base_name, "_", connect_number_char,
+ suffix_pos = strxmov(tmp, prefix , shared_memory_base_name, "_", connect_number_char,
"_", NullS);
strmov(suffix_pos, "DATA");
if ((handle_file_map = OpenFileMapping(FILE_MAP_WRITE,FALSE,tmp)) == NULL)
@@ -924,6 +937,7 @@ void end_server(MYSQL *mysql)
vio_delete(mysql->net.vio);
reset_sigpipe(mysql);
mysql->net.vio= 0; /* Marker */
+ mysql_prune_stmt_list(mysql);
}
net_end(&mysql->net);
free_old_query(mysql);
@@ -2526,30 +2540,9 @@ my_bool mysql_reconnect(MYSQL *mysql)
tmp_mysql.reconnect= 1;
tmp_mysql.free_me= mysql->free_me;
- /*
- For each stmt in mysql->stmts, move it to tmp_mysql if it is
- in state MYSQL_STMT_INIT_DONE, otherwise close it.
- */
- {
- LIST *element= mysql->stmts;
- for (; element; element= element->next)
- {
- MYSQL_STMT *stmt= (MYSQL_STMT *) element->data;
- if (stmt->state != MYSQL_STMT_INIT_DONE)
- {
- stmt->mysql= 0;
- stmt->last_errno= CR_SERVER_LOST;
- strmov(stmt->last_error, ER(CR_SERVER_LOST));
- strmov(stmt->sqlstate, unknown_sqlstate);
- }
- else
- {
- tmp_mysql.stmts= list_add(tmp_mysql.stmts, &stmt->list);
- }
- /* No need to call list_delete for statement here */
- }
- mysql->stmts= NULL;
- }
+ /* Move prepared statements (if any) over to the new mysql object */
+ tmp_mysql.stmts= mysql->stmts;
+ mysql->stmts= 0;
/* Don't free options as these are now used in tmp_mysql */
bzero((char*) &mysql->options,sizeof(mysql->options));
@@ -2639,6 +2632,46 @@ static void mysql_close_free(MYSQL *mysql)
}
+/**
+ For use when the connection to the server has been lost (in which case
+ the server has discarded all information about prepared statements
+ associated with the connection).
+
+ Mark all statements in mysql->stmts by setting stmt->mysql= 0 if the
+ statement has transitioned beyond the MYSQL_STMT_INIT_DONE state, and
+ unlink the statement from the mysql->stmts list.
+
+ The remaining pruned list of statements (if any) is kept in mysql->stmts.
+
+ @param mysql pointer to the MYSQL object
+
+ @return none
+*/
+static void mysql_prune_stmt_list(MYSQL *mysql)
+{
+ LIST *element= mysql->stmts;
+ LIST *pruned_list= 0;
+
+ for (; element; element= element->next)
+ {
+ MYSQL_STMT *stmt= (MYSQL_STMT *) element->data;
+ if (stmt->state != MYSQL_STMT_INIT_DONE)
+ {
+ stmt->mysql= 0;
+ stmt->last_errno= CR_SERVER_LOST;
+ strmov(stmt->last_error, ER(CR_SERVER_LOST));
+ strmov(stmt->sqlstate, unknown_sqlstate);
+ }
+ else
+ {
+ pruned_list= list_add(pruned_list, element);
+ }
+ }
+
+ mysql->stmts= pruned_list;
+}
+
+
/*
Clear connection pointer of every statement: this is necessary
to give error on attempt to use a prepared statement of closed
diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt
index cfd049e1864..6f162f4d84d 100755
--- a/sql/CMakeLists.txt
+++ b/sql/CMakeLists.txt
@@ -39,7 +39,8 @@ SET_SOURCE_FILES_PROPERTIES(${CMAKE_SOURCE_DIR}/sql/sql_yacc.h
ADD_DEFINITIONS(-DMYSQL_SERVER -D_CONSOLE -DHAVE_DLOPEN -DHAVE_EVENT_SCHEDULER)
-ADD_EXECUTABLE(mysqld
+
+SET (SQL_SOURCE
../sql-common/client.c derror.cc des_key_file.cc
discover.cc ../libmysql/errmsg.c field.cc field_conv.cc
filesort.cc gstream.cc
@@ -82,54 +83,45 @@ ADD_EXECUTABLE(mysqld
${PROJECT_SOURCE_DIR}/include/mysql_version.h
${PROJECT_SOURCE_DIR}/sql/sql_builtin.cc
${PROJECT_SOURCE_DIR}/sql/lex_hash.h)
+ADD_LIBRARY(sql ${SQL_SOURCE})
-TARGET_LINK_LIBRARIES(mysqld
- heap myisam myisammrg mysys yassl zlib debug dbug yassl
- taocrypt strings vio regex wsock32 ws2_32)
+IF (NOT EXISTS cmake_dummy.cc)
+ FILE (WRITE cmake_dummy.cc "")
+ENDIF (NOT EXISTS cmake_dummy.cc)
+ADD_EXECUTABLE(mysqld cmake_dummy.cc)
SET_TARGET_PROPERTIES(mysqld PROPERTIES OUTPUT_NAME mysqld${MYSQLD_EXE_SUFFIX})
+SET_TARGET_PROPERTIES(mysqld PROPERTIES ENABLE_EXPORTS TRUE)
-IF(cmake_version EQUAL 20406)
-# Work around for 2.4.6 bug, OUTPUT_NAME will not set the right .PDB
-# file name. Note that COMPILE_FLAGS set some temporary pdb during build,
-# LINK_FLAGS sets the real one.
-SET_TARGET_PROPERTIES(mysqld PROPERTIES
- COMPILE_FLAGS "/Fd${CMAKE_CFG_INTDIR}/mysqld${MYSQLD_EXE_SUFFIX}.pdb"
- LINK_FLAGS "/PDB:${CMAKE_CFG_INTDIR}/mysqld${MYSQLD_EXE_SUFFIX}.pdb")
-ENDIF(cmake_version EQUAL 20406)
+SET (MYSQLD_CORE_LIBS mysys zlib dbug strings yassl taocrypt vio regex sql)
+TARGET_LINK_LIBRARIES(mysqld ${MYSQLD_CORE_LIBS} ${MYSQLD_STATIC_ENGINE_LIBS})
+TARGET_LINK_LIBRARIES(mysqld ws2_32.lib)
-IF(EMBED_MANIFESTS)
- MYSQL_EMBED_MANIFEST("mysqld" "asInvoker")
-ENDIF(EMBED_MANIFESTS)
-IF(WITH_ARCHIVE_STORAGE_ENGINE)
- TARGET_LINK_LIBRARIES(mysqld archive)
-ENDIF(WITH_ARCHIVE_STORAGE_ENGINE)
-IF(WITH_BLACKHOLE_STORAGE_ENGINE)
- TARGET_LINK_LIBRARIES(mysqld blackhole)
-ENDIF(WITH_BLACKHOLE_STORAGE_ENGINE)
-IF(WITH_CSV_STORAGE_ENGINE)
- TARGET_LINK_LIBRARIES(mysqld csv)
-ENDIF(WITH_CSV_STORAGE_ENGINE)
-IF(WITH_EXAMPLE_STORAGE_ENGINE)
- TARGET_LINK_LIBRARIES(mysqld example)
-ENDIF(WITH_EXAMPLE_STORAGE_ENGINE)
-IF(WITH_FEDERATED_STORAGE_ENGINE)
- TARGET_LINK_LIBRARIES(mysqld federated)
-ENDIF(WITH_FEDERATED_STORAGE_ENGINE)
-IF(WITH_INNOBASE_STORAGE_ENGINE)
- TARGET_LINK_LIBRARIES(mysqld innobase)
-ENDIF(WITH_INNOBASE_STORAGE_ENGINE)
-ADD_DEPENDENCIES(mysqld GenError)
+IF(MSVC AND NOT WITHOUT_DYNAMIC_PLUGINS)
+ # Set module definition file. Also use non-incremental linker,
+ # incremental appears to crash from time to time,if used with /DEF option
+ SET_TARGET_PROPERTIES(mysqld PROPERTIES LINK_FLAGS "/DEF:mysqld.def /INCREMENTAL:NO")
-# NOTE CMake 2.4.6 creates strange dependencies between files in OUTPUT,
-# so for now we only list one if more than one
+ FOREACH (CORELIB ${MYSQLD_CORE_LIBS})
+ GET_TARGET_PROPERTY(LOC ${CORELIB} LOCATION)
+ FILE(TO_NATIVE_PATH ${LOC} LOC)
+ SET (LIB_LOCATIONS ${LIB_LOCATIONS} ${LOC})
+ ENDFOREACH (CORELIB ${MYSQLD_CORE_LIBS})
+
+ ADD_CUSTOM_COMMAND(TARGET mysqld PRE_LINK
+ COMMAND cscript ARGS //nologo ${PROJECT_SOURCE_DIR}/win/create_def_file.js
+ ${PLATFORM} ${LIB_LOCATIONS} > mysqld.def
+ WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/sql)
+ENDIF(MSVC AND NOT WITHOUT_DYNAMIC_PLUGINS)
+
+ADD_DEPENDENCIES(sql GenError)
# Sql Parser custom command
ADD_CUSTOM_COMMAND(
OUTPUT ${PROJECT_SOURCE_DIR}/sql/sql_yacc.h
-# ${PROJECT_SOURCE_DIR}/sql/sql_yacc.cc
- COMMAND bison.exe ARGS -y -p MYSQL --defines=sql_yacc.h
+ ${PROJECT_SOURCE_DIR}/sql/sql_yacc.cc
+ COMMAND bison ARGS -y -p MYSQL --defines=sql_yacc.h
--output=sql_yacc.cc sql_yacc.yy
DEPENDS ${PROJECT_SOURCE_DIR}/sql/sql_yacc.yy)
@@ -146,16 +138,16 @@ ADD_CUSTOM_COMMAND(
ADD_CUSTOM_TARGET(
GenServerSource ALL
DEPENDS ${PROJECT_SOURCE_DIR}/sql/sql_yacc.h
-# ${PROJECT_SOURCE_DIR}/sql/sql_yacc.cc
+ ${PROJECT_SOURCE_DIR}/sql/sql_yacc.cc
${PROJECT_SOURCE_DIR}/sql/message.h
-# ${PROJECT_SOURCE_DIR}/sql/message.rc
+ ${PROJECT_SOURCE_DIR}/sql/message.rc
${PROJECT_SOURCE_DIR}/sql/lex_hash.h)
ADD_DEPENDENCIES(mysqld GenServerSource)
# Remove the auto-generated files as part of 'Clean Solution'
SET_DIRECTORY_PROPERTIES(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES
- "lex_hash.h;sql_yacc.h;sql_yacc.cc")
+ "lex_hash.h;sql_yacc.h;sql_yacc.cc;mysqld.def")
ADD_LIBRARY(udf_example MODULE udf_example.c udf_example.def)
ADD_DEPENDENCIES(udf_example strings GenError)
diff --git a/sql/field.cc b/sql/field.cc
index d11b509075b..ed085de1db3 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -1165,7 +1165,7 @@ bool Field_num::get_int(CHARSET_INFO *cs, const char *from, uint len,
if (unsigned_flag)
{
- if (((ulonglong) *rnd > unsigned_max) && (*rnd= (longlong) unsigned_max) ||
+ if ((((ulonglong) *rnd > unsigned_max) && (*rnd= (longlong) unsigned_max)) ||
error == MY_ERRNO_ERANGE)
{
goto out_of_range;
@@ -1350,7 +1350,7 @@ void Field::copy_from_tmp(int row_offset)
if (null_ptr)
{
*null_ptr= (uchar) ((null_ptr[0] & (uchar) ~(uint) null_bit) |
- null_ptr[row_offset] & (uchar) null_bit);
+ (null_ptr[row_offset] & (uchar) null_bit));
}
}
@@ -4081,8 +4081,8 @@ int Field_float::store(const char *from,uint len,CHARSET_INFO *cs)
int error;
char *end;
double nr= my_strntod(cs,(char*) from,len,&end,&error);
- if (error || (!len || (uint) (end-from) != len &&
- table->in_use->count_cuted_fields))
+ if (error || (!len || ((uint) (end-from) != len &&
+ table->in_use->count_cuted_fields)))
{
set_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
(error ? ER_WARN_DATA_OUT_OF_RANGE : WARN_DATA_TRUNCATED), 1);
@@ -4343,8 +4343,8 @@ int Field_double::store(const char *from,uint len,CHARSET_INFO *cs)
int error;
char *end;
double nr= my_strntod(cs,(char*) from, len, &end, &error);
- if (error || (!len || (uint) (end-from) != len &&
- table->in_use->count_cuted_fields))
+ if (error || (!len || ((uint) (end-from) != len &&
+ table->in_use->count_cuted_fields)))
{
set_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
(error ? ER_WARN_DATA_OUT_OF_RANGE : WARN_DATA_TRUNCATED), 1);
@@ -5196,7 +5196,7 @@ int Field_time::store(longlong nr, bool unsigned_val)
MYSQL_TIMESTAMP_TIME, 1);
error= 1;
}
- else if (nr > (longlong) TIME_MAX_VALUE || nr < 0 && unsigned_val)
+ else if (nr > (longlong) TIME_MAX_VALUE || (nr < 0 && unsigned_val))
{
tmp= TIME_MAX_VALUE;
set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN,
@@ -5307,7 +5307,7 @@ bool Field_time::get_time(MYSQL_TIME *ltime)
ltime->neg= 1;
tmp=-tmp;
}
- ltime->day= 0;
+ ltime->year= ltime->month= ltime->day= 0;
ltime->hour= (int) (tmp/10000);
tmp-=ltime->hour*10000;
ltime->minute= (int) tmp/100;
@@ -5361,7 +5361,7 @@ int Field_year::store(const char *from, uint len,CHARSET_INFO *cs)
int error;
longlong nr= cs->cset->strntoull10rnd(cs, from, len, 0, &end, &error);
- if (nr < 0 || nr >= 100 && nr <= 1900 || nr > 2155 ||
+ if (nr < 0 || (nr >= 100 && nr <= 1900) || nr > 2155 ||
error == MY_ERRNO_ERANGE)
{
*ptr=0;
@@ -5405,7 +5405,7 @@ int Field_year::store(double nr)
int Field_year::store(longlong nr, bool unsigned_val)
{
ASSERT_COLUMN_MARKED_FOR_WRITE;
- if (nr < 0 || nr >= 100 && nr <= 1900 || nr > 2155)
+ if (nr < 0 || (nr >= 100 && nr <= 1900) || nr > 2155)
{
*ptr= 0;
set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
@@ -6429,16 +6429,16 @@ int Field_str::store(double nr)
/* Calculate the exponent from the 'e'-format conversion */
if (anr < 1.0 && anr > 0)
{
- for (exp= 0; anr < 1e-100; exp-= 100, anr*= 1e100);
- for (; anr < 1e-10; exp-= 10, anr*= 1e10);
- for (i= 1; anr < 1 / log_10[i]; exp--, i++);
+ for (exp= 0; anr < 1e-100; exp-= 100, anr*= 1e100) ;
+ for (; anr < 1e-10; exp-= 10, anr*= 1e10) ;
+ for (i= 1; anr < 1 / log_10[i]; exp--, i++) ;
exp--;
}
else
{
- for (exp= 0; anr > 1e100; exp+= 100, anr/= 1e100);
- for (; anr > 1e10; exp+= 10, anr/= 1e10);
- for (i= 1; anr > log_10[i]; exp++, i++);
+ for (exp= 0; anr > 1e100; exp+= 100, anr/= 1e100) ;
+ for (; anr > 1e10; exp+= 10, anr/= 1e10) ;
+ for (i= 1; anr > log_10[i]; exp++, i++) ;
}
max_length= local_char_length - neg;
@@ -8833,7 +8833,7 @@ bool Field_num::eq_def(Field *field)
Field_num *from_num= (Field_num*) field;
if (unsigned_flag != from_num->unsigned_flag ||
- zerofill && !from_num->zerofill && !zero_pack() ||
+ (zerofill && !from_num->zerofill && !zero_pack()) ||
dec != from_num->dec)
return 0;
return 1;
@@ -8974,7 +8974,7 @@ int Field_bit::store(const char *from, uint length, CHARSET_INFO *cs)
ASSERT_COLUMN_MARKED_FOR_WRITE;
int delta;
- for (; length && !*from; from++, length--); // skip left 0's
+ for (; length && !*from; from++, length--) ; // skip left 0's
delta= bytes_in_rec - length;
if (delta < -1 ||
@@ -9306,7 +9306,7 @@ Field_bit::unpack(uchar *to, const uchar *from, uint param_data,
and slave have the same sizes, then use the old unpack() method.
*/
if (param_data == 0 ||
- (from_bit_len == bit_len) && (from_len == bytes_in_rec))
+ ((from_bit_len == bit_len) && (from_len == bytes_in_rec)))
{
if (bit_len > 0)
{
@@ -9385,7 +9385,7 @@ int Field_bit_as_char::store(const char *from, uint length, CHARSET_INFO *cs)
int delta;
uchar bits= (uchar) (field_length & 7);
- for (; length && !*from; from++, length--); // skip left 0's
+ for (; length && !*from; from++, length--) ; // skip left 0's
delta= bytes_in_rec - length;
if (delta < 0 ||
diff --git a/sql/field_conv.cc b/sql/field_conv.cc
index 11d0bb9cc82..3574534722e 100644
--- a/sql/field_conv.cc
+++ b/sql/field_conv.cc
@@ -99,7 +99,7 @@ static void do_field_to_null_str(Copy_field *copy)
static void do_outer_field_to_null_str(Copy_field *copy)
{
if (*copy->null_row ||
- copy->from_null_ptr && (*copy->from_null_ptr & copy->from_bit))
+ (copy->from_null_ptr && (*copy->from_null_ptr & copy->from_bit)))
{
bzero(copy->to_ptr,copy->from_length);
copy->to_null_ptr[0]=1; // Always bit 1
@@ -212,7 +212,7 @@ static void do_copy_null(Copy_field *copy)
static void do_outer_field_null(Copy_field *copy)
{
if (*copy->null_row ||
- copy->from_null_ptr && (*copy->from_null_ptr & copy->from_bit))
+ (copy->from_null_ptr && (*copy->from_null_ptr & copy->from_bit)))
{
*copy->to_null_ptr|=copy->to_bit;
copy->to_field->reset();
@@ -665,9 +665,9 @@ Copy_field::get_copy_func(Field *to,Field *from)
*/
if (to->real_type() != from->real_type() ||
!compatible_db_low_byte_first ||
- ((to->table->in_use->variables.sql_mode &
+ (((to->table->in_use->variables.sql_mode &
(MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE | MODE_INVALID_DATES)) &&
- to->type() == MYSQL_TYPE_DATE ||
+ to->type() == MYSQL_TYPE_DATE) ||
to->type() == MYSQL_TYPE_DATETIME))
{
if (from->real_type() == MYSQL_TYPE_ENUM ||
@@ -770,8 +770,8 @@ int field_conv(Field *to,Field *from)
to->table->s->db_low_byte_first == from->table->s->db_low_byte_first &&
(!(to->table->in_use->variables.sql_mode &
(MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE | MODE_INVALID_DATES)) ||
- to->type() != MYSQL_TYPE_DATE &&
- to->type() != MYSQL_TYPE_DATETIME) &&
+ (to->type() != MYSQL_TYPE_DATE &&
+ to->type() != MYSQL_TYPE_DATETIME)) &&
(from->real_type() != MYSQL_TYPE_VARCHAR ||
((Field_varstring*)from)->length_bytes ==
((Field_varstring*)to)->length_bytes))
diff --git a/sql/gstream.cc b/sql/gstream.cc
index 0c8011549f3..e2bb41b8541 100644
--- a/sql/gstream.cc
+++ b/sql/gstream.cc
@@ -75,7 +75,7 @@ bool Gis_read_stream::get_next_number(double *d)
skip_space();
if ((m_cur >= m_limit) ||
- (*m_cur < '0' || *m_cur > '9') && *m_cur != '-' && *m_cur != '+')
+ ((*m_cur < '0' || *m_cur > '9') && *m_cur != '-' && *m_cur != '+'))
{
set_error_msg("Numeric constant expected");
return 1;
diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc
index 03bae38d94c..264e5649ea9 100644
--- a/sql/ha_ndbcluster.cc
+++ b/sql/ha_ndbcluster.cc
@@ -1263,7 +1263,7 @@ int ha_ndbcluster::add_index_handle(THD *thd, NDBDICT *dict, KEY *key_info,
}
if (idx_type == UNIQUE_ORDERED_INDEX || idx_type == UNIQUE_INDEX)
{
- char unique_index_name[FN_LEN];
+ char unique_index_name[FN_LEN + 1];
static const char* unique_suffix= "$unique";
m_has_unique_index= TRUE;
strxnmov(unique_index_name, FN_LEN, index_name, unique_suffix, NullS);
@@ -5205,7 +5205,7 @@ int ha_ndbcluster::create(const char *name,
uchar *data= NULL, *pack_data= NULL;
bool create_from_engine= (create_info->table_options & HA_OPTION_CREATE_FROM_ENGINE);
bool is_truncate= (thd->lex->sql_command == SQLCOM_TRUNCATE);
- char tablespace[FN_LEN];
+ char tablespace[FN_LEN + 1];
NdbDictionary::Table::SingleUserMode single_user_mode= NdbDictionary::Table::SingleUserModeLocked;
DBUG_ENTER("ha_ndbcluster::create");
@@ -5668,7 +5668,7 @@ int ha_ndbcluster::create_index(const char *name, KEY *key_info,
NDB_INDEX_TYPE idx_type, uint idx_no)
{
int error= 0;
- char unique_name[FN_LEN];
+ char unique_name[FN_LEN + 1];
static const char* unique_suffix= "$unique";
DBUG_ENTER("ha_ndbcluster::create_ordered_index");
DBUG_PRINT("info", ("Creating index %u: %s", idx_no, name));
@@ -6716,7 +6716,7 @@ int ndbcluster_discover(handlerton *hton, THD* thd, const char *db,
size_t len;
uchar* data= NULL;
Ndb* ndb;
- char key[FN_REFLEN];
+ char key[FN_REFLEN + 1];
DBUG_ENTER("ndbcluster_discover");
DBUG_PRINT("enter", ("db: %s, name: %s", db, name));
@@ -6727,7 +6727,7 @@ int ndbcluster_discover(handlerton *hton, THD* thd, const char *db,
ERR_RETURN(ndb->getNdbError());
}
NDBDICT* dict= ndb->getDictionary();
- build_table_filename(key, sizeof(key), db, name, "", 0);
+ build_table_filename(key, sizeof(key) - 1, db, name, "", 0);
/* ndb_share reference temporary */
NDB_SHARE *share= get_share(key, 0, FALSE);
if (share)
@@ -6892,9 +6892,9 @@ int ndbcluster_drop_database_impl(const char *path)
drop_list.push_back(thd->strdup(elmt.name));
}
// Drop any tables belonging to database
- char full_path[FN_REFLEN];
+ char full_path[FN_REFLEN + 1];
char *tmp= full_path +
- build_table_filename(full_path, sizeof(full_path), dbname, "", "", 0);
+ build_table_filename(full_path, sizeof(full_path) - 1, dbname, "", "", 0);
if (ndb->setDatabaseName(dbname))
{
ERR_RETURN(ndb->getNdbError());
@@ -6963,7 +6963,7 @@ int ndb_create_table_from_engine(THD *thd, const char *db,
int ndbcluster_find_all_files(THD *thd)
{
Ndb* ndb;
- char key[FN_REFLEN];
+ char key[FN_REFLEN + 1];
NDBDICT *dict;
int unhandled, retries= 5, skipped;
DBUG_ENTER("ndbcluster_find_all_files");
@@ -7021,7 +7021,7 @@ int ndbcluster_find_all_files(THD *thd)
/* check if database exists */
char *end= key +
- build_table_filename(key, sizeof(key), elmt.database, "", "", 0);
+ build_table_filename(key, sizeof(key) - 1, elmt.database, "", "", 0);
if (my_access(key, F_OK))
{
/* no such database defined, skip table */
@@ -7102,7 +7102,7 @@ int ndbcluster_find_files(handlerton *hton, THD *thd,
{ // extra bracket to avoid gcc 2.95.3 warning
uint i;
Ndb* ndb;
- char name[FN_REFLEN];
+ char name[FN_REFLEN + 1];
HASH ndb_tables, ok_tables;
NDBDICT::List list;
@@ -7172,7 +7172,8 @@ int ndbcluster_find_files(handlerton *hton, THD *thd,
DBUG_PRINT("info", ("%s", file_name->str));
if (hash_search(&ndb_tables, (uchar*) file_name->str, file_name->length))
{
- build_table_filename(name, sizeof(name), db, file_name->str, reg_ext, 0);
+ build_table_filename(name, sizeof(name) - 1, db,
+ file_name->str, reg_ext, 0);
if (my_access(name, F_OK))
{
pthread_mutex_lock(&LOCK_open);
@@ -7194,7 +7195,8 @@ int ndbcluster_find_files(handlerton *hton, THD *thd,
}
// Check for .ndb file with this name
- build_table_filename(name, sizeof(name), db, file_name->str, ha_ndb_ext, 0);
+ build_table_filename(name, sizeof(name) - 1, db,
+ file_name->str, ha_ndb_ext, 0);
DBUG_PRINT("info", ("Check access for %s", name));
if (my_access(name, F_OK))
{
@@ -7237,7 +7239,7 @@ int ndbcluster_find_files(handlerton *hton, THD *thd,
/* setup logging to binlog for all discovered tables */
{
char *end, *end1= name +
- build_table_filename(name, sizeof(name), db, "", "", 0);
+ build_table_filename(name, sizeof(name) - 1, db, "", "", 0);
for (i= 0; i < ok_tables.records; i++)
{
file_name_str= (char*)hash_element(&ok_tables, i);
@@ -7259,7 +7261,8 @@ int ndbcluster_find_files(handlerton *hton, THD *thd,
file_name_str= (char*) hash_element(&ndb_tables, i);
if (!hash_search(&ok_tables, (uchar*) file_name_str, strlen(file_name_str)))
{
- build_table_filename(name, sizeof(name), db, file_name_str, reg_ext, 0);
+ build_table_filename(name, sizeof(name) - 1,
+ db, file_name_str, reg_ext, 0);
if (my_access(name, F_OK))
{
DBUG_PRINT("info", ("%s must be discovered", file_name_str));
@@ -7639,7 +7642,7 @@ void ndbcluster_print_error(int error, const NdbOperation *error_op)
void ha_ndbcluster::set_dbname(const char *path_name, char *dbname)
{
char *end, *ptr, *tmp_name;
- char tmp_buff[FN_REFLEN];
+ char tmp_buff[FN_REFLEN + 1];
tmp_name= tmp_buff;
/* Scan name from the end */
@@ -7665,7 +7668,7 @@ void ha_ndbcluster::set_dbname(const char *path_name, char *dbname)
ptr++;
}
#endif
- filename_to_tablename(tmp_name, dbname, FN_REFLEN);
+ filename_to_tablename(tmp_name, dbname, sizeof(tmp_buff) - 1);
}
/**
@@ -7685,7 +7688,7 @@ void
ha_ndbcluster::set_tabname(const char *path_name, char * tabname)
{
char *end, *ptr, *tmp_name;
- char tmp_buff[FN_REFLEN];
+ char tmp_buff[FN_REFLEN + 1];
tmp_name= tmp_buff;
/* Scan name from the end */
@@ -7706,7 +7709,7 @@ ha_ndbcluster::set_tabname(const char *path_name, char * tabname)
ptr++;
}
#endif
- filename_to_tablename(tmp_name, tabname, FN_REFLEN);
+ filename_to_tablename(tmp_name, tabname, sizeof(tmp_buff) - 1);
}
/**
@@ -7892,11 +7895,12 @@ uint8 ha_ndbcluster::table_cache_type()
uint ndb_get_commitcount(THD *thd, char *dbname, char *tabname,
Uint64 *commit_count)
{
- char name[FN_REFLEN];
+ char name[FN_REFLEN + 1];
NDB_SHARE *share;
DBUG_ENTER("ndb_get_commitcount");
- build_table_filename(name, sizeof(name), dbname, tabname, "", 0);
+ build_table_filename(name, sizeof(name) - 1,
+ dbname, tabname, "", 0);
DBUG_PRINT("enter", ("name: %s", name));
pthread_mutex_lock(&ndbcluster_mutex);
if (!(share=(NDB_SHARE*) hash_search(&ndbcluster_open_tables,
@@ -10040,7 +10044,7 @@ bool ha_ndbcluster::check_if_incompatible_data(HA_CREATE_INFO *create_info,
ai=1;
}
- char tablespace_name[FN_LEN];
+ char tablespace_name[FN_LEN + 1];
if (get_tablespace_name(current_thd, tablespace_name, FN_LEN))
{
if (create_info->tablespace)
diff --git a/sql/ha_ndbcluster_binlog.cc b/sql/ha_ndbcluster_binlog.cc
index baf86d739eb..f705af8bf47 100644
--- a/sql/ha_ndbcluster_binlog.cc
+++ b/sql/ha_ndbcluster_binlog.cc
@@ -788,7 +788,7 @@ static int ndbcluster_create_ndb_apply_status_table(THD *thd)
if (g_ndb_cluster_connection->get_no_ready() <= 0)
DBUG_RETURN(0);
- char buf[1024], *end;
+ char buf[1024 + 1], *end;
if (ndb_extra_logging)
sql_print_information("NDB: Creating " NDB_REP_DB "." NDB_APPLY_TABLE);
@@ -798,7 +798,7 @@ static int ndbcluster_create_ndb_apply_status_table(THD *thd)
if so, remove it since there is none in Ndb
*/
{
- build_table_filename(buf, sizeof(buf),
+ build_table_filename(buf, sizeof(buf) - 1,
NDB_REP_DB, NDB_APPLY_TABLE, reg_ext, 0);
my_delete(buf, MYF(0));
}
@@ -846,7 +846,7 @@ static int ndbcluster_create_schema_table(THD *thd)
if (g_ndb_cluster_connection->get_no_ready() <= 0)
DBUG_RETURN(0);
- char buf[1024], *end;
+ char buf[1024 + 1], *end;
if (ndb_extra_logging)
sql_print_information("NDB: Creating " NDB_REP_DB "." NDB_SCHEMA_TABLE);
@@ -856,7 +856,7 @@ static int ndbcluster_create_schema_table(THD *thd)
if so, remove it since there is none in Ndb
*/
{
- build_table_filename(buf, sizeof(buf),
+ build_table_filename(buf, sizeof(buf) - 1,
NDB_REP_DB, NDB_SCHEMA_TABLE, reg_ext, 0);
my_delete(buf, MYF(0));
}
@@ -1321,8 +1321,8 @@ int ndbcluster_log_schema_op(THD *thd, NDB_SHARE *share,
NDB_SCHEMA_OBJECT *ndb_schema_object;
{
- char key[FN_REFLEN];
- build_table_filename(key, sizeof(key), db, table_name, "", 0);
+ char key[FN_REFLEN + 1];
+ build_table_filename(key, sizeof(key) - 1, db, table_name, "", 0);
ndb_schema_object= ndb_get_schema_object(key, TRUE, FALSE);
}
@@ -1674,7 +1674,7 @@ ndb_handle_schema_change(THD *thd, Ndb *ndb, NdbEventOperation *pOp,
if (is_remote_change && is_online_alter_table)
{
const char *tabname= table_share->table_name.str;
- char key[FN_REFLEN];
+ char key[FN_REFLEN + 1];
uchar *data= 0, *pack_data= 0;
size_t length, pack_length;
int error;
@@ -1683,7 +1683,7 @@ ndb_handle_schema_change(THD *thd, Ndb *ndb, NdbEventOperation *pOp,
DBUG_PRINT("info", ("Detected frm change of table %s.%s",
dbname, tabname));
- build_table_filename(key, FN_LEN-1, dbname, tabname, NullS, 0);
+ build_table_filename(key, FN_LEN - 1, dbname, tabname, NullS, 0);
/*
If the there is no local table shadowing the altered table and
it has an frm that is different than the one on disk then
@@ -1855,9 +1855,11 @@ static void ndb_binlog_query(THD *thd, Cluster_schema *schema)
else
thd->server_id= schema->any_value;
thd->db= schema->db;
+ int errcode = query_error_code(thd, thd->killed == THD::NOT_KILLED);
thd->binlog_query(THD::STMT_QUERY_TYPE, schema->query,
schema->query_length, FALSE,
- schema->name[0] == 0 || thd->db[0] == 0);
+ schema->name[0] == 0 || thd->db[0] == 0,
+ errcode);
thd->server_id= thd_server_id_save;
thd->db= thd_db_save;
}
@@ -1924,8 +1926,8 @@ ndb_binlog_thread_handle_schema_event(THD *thd, Ndb *ndb,
break;
case SOT_TRUNCATE_TABLE:
{
- char key[FN_REFLEN];
- build_table_filename(key, sizeof(key),
+ char key[FN_REFLEN + 1];
+ build_table_filename(key, sizeof(key) - 1,
schema->db, schema->name, "", 0);
/* ndb_share reference temporary, free below */
NDB_SHARE *share= get_share(key, 0, FALSE, FALSE);
@@ -2171,8 +2173,8 @@ ndb_binlog_thread_handle_schema_event_post_epoch(THD *thd,
int log_query= 0;
{
enum SCHEMA_OP_TYPE schema_type= (enum SCHEMA_OP_TYPE)schema->type;
- char key[FN_REFLEN];
- build_table_filename(key, sizeof(key), schema->db, schema->name, "", 0);
+ char key[FN_REFLEN + 1];
+ build_table_filename(key, sizeof(key) - 1, schema->db, schema->name, "", 0);
if (schema_type == SOT_CLEAR_SLOCK)
{
pthread_mutex_lock(&ndbcluster_mutex);
@@ -2506,8 +2508,8 @@ ndb_rep_event_name(String *event_name,const char *db, const char *tbl)
bool
ndbcluster_check_if_local_table(const char *dbname, const char *tabname)
{
- char key[FN_REFLEN];
- char ndb_file[FN_REFLEN];
+ char key[FN_REFLEN + 1];
+ char ndb_file[FN_REFLEN + 1];
DBUG_ENTER("ndbcluster_check_if_local_table");
build_table_filename(key, FN_LEN-1, dbname, tabname, reg_ext, 0);
@@ -2532,9 +2534,9 @@ ndbcluster_check_if_local_tables_in_db(THD *thd, const char *dbname)
DBUG_PRINT("info", ("Looking for files in directory %s", dbname));
LEX_STRING *tabname;
List files;
- char path[FN_REFLEN];
+ char path[FN_REFLEN + 1];
- build_table_filename(path, sizeof(path), dbname, "", "", 0);
+ build_table_filename(path, sizeof(path) - 1, dbname, "", "", 0);
if (find_files(thd, &files, dbname, path, NullS, 0) != FIND_FILES_OK)
{
DBUG_PRINT("info", ("Failed to find files"));
diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc
index 67bc3156260..74742f58028 100644
--- a/sql/ha_partition.cc
+++ b/sql/ha_partition.cc
@@ -3179,6 +3179,7 @@ int ha_partition::delete_row(const uchar *buf)
int ha_partition::delete_all_rows()
{
int error;
+ bool truncate= FALSE;
handler **file;
THD *thd= ha_thd();
DBUG_ENTER("ha_partition::delete_all_rows");
@@ -3190,12 +3191,16 @@ int ha_partition::delete_all_rows()
ha_data->next_auto_inc_val= 0;
ha_data->auto_inc_initialized= FALSE;
unlock_auto_increment();
+ truncate= TRUE;
}
file= m_file;
do
{
if ((error= (*file)->ha_delete_all_rows()))
DBUG_RETURN(error);
+ /* Ignore the error */
+ if (truncate)
+ (void) (*file)->ha_reset_auto_increment(0);
} while (*(++file));
DBUG_RETURN(0);
}
diff --git a/sql/handler.cc b/sql/handler.cc
index 0de7718d113..285690ea66a 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -1074,6 +1074,13 @@ int ha_commit_trans(THD *thd, bool all)
user, or an implicit commit issued by a DDL.
*/
THD_TRANS *trans= all ? &thd->transaction.all : &thd->transaction.stmt;
+ /*
+ "real" is a nick name for a transaction for which a commit will
+ make persistent changes. E.g. a 'stmt' transaction inside a 'all'
+ transation is not 'real': even though it's possible to commit it,
+ the changes are not durable as they might be rolled back if the
+ enclosing 'all' transaction is rolled back.
+ */
bool is_real_trans= all || thd->transaction.all.ha_list == 0;
Ha_trx_info *ha_info= trans->ha_list;
my_xid xid= thd->transaction.xid_state.xid.get_my_xid();
@@ -1185,16 +1192,9 @@ end:
if (rw_trans)
start_waiting_global_read_lock(thd);
}
- else if (all)
- {
- /*
- A COMMIT of an empty transaction. There may be savepoints.
- Destroy them. If the transaction is not empty
- savepoints are cleared in ha_commit_one_phase()
- or ha_rollback_trans().
- */
+ /* Free resources and perform other cleanup even for 'empty' transactions. */
+ else if (is_real_trans)
thd->transaction.cleanup();
- }
#endif /* USING_TRANSACTIONS */
DBUG_RETURN(error);
}
@@ -1207,6 +1207,13 @@ int ha_commit_one_phase(THD *thd, bool all)
{
int error=0;
THD_TRANS *trans=all ? &thd->transaction.all : &thd->transaction.stmt;
+ /*
+ "real" is a nick name for a transaction for which a commit will
+ make persistent changes. E.g. a 'stmt' transaction inside a 'all'
+ transation is not 'real': even though it's possible to commit it,
+ the changes are not durable as they might be rolled back if the
+ enclosing 'all' transaction is rolled back.
+ */
bool is_real_trans=all || thd->transaction.all.ha_list == 0;
Ha_trx_info *ha_info= trans->ha_list, *ha_info_next;
DBUG_ENTER("ha_commit_one_phase");
@@ -1228,8 +1235,6 @@ int ha_commit_one_phase(THD *thd, bool all)
}
trans->ha_list= 0;
trans->no_2pc=0;
- if (is_real_trans)
- thd->transaction.xid_state.xid.null();
if (all)
{
#ifdef HAVE_QUERY_CACHE
@@ -1237,9 +1242,11 @@ int ha_commit_one_phase(THD *thd, bool all)
query_cache.invalidate(thd->transaction.changed_tables);
#endif
thd->variables.tx_isolation=thd->session_tx_isolation;
- thd->transaction.cleanup();
}
}
+ /* Free resources and perform other cleanup even for 'empty' transactions. */
+ if (is_real_trans)
+ thd->transaction.cleanup();
#endif /* USING_TRANSACTIONS */
DBUG_RETURN(error);
}
@@ -1250,6 +1257,13 @@ int ha_rollback_trans(THD *thd, bool all)
int error=0;
THD_TRANS *trans=all ? &thd->transaction.all : &thd->transaction.stmt;
Ha_trx_info *ha_info= trans->ha_list, *ha_info_next;
+ /*
+ "real" is a nick name for a transaction for which a commit will
+ make persistent changes. E.g. a 'stmt' transaction inside a 'all'
+ transation is not 'real': even though it's possible to commit it,
+ the changes are not durable as they might be rolled back if the
+ enclosing 'all' transaction is rolled back.
+ */
bool is_real_trans=all || thd->transaction.all.ha_list == 0;
DBUG_ENTER("ha_rollback_trans");
@@ -1295,18 +1309,13 @@ int ha_rollback_trans(THD *thd, bool all)
}
trans->ha_list= 0;
trans->no_2pc=0;
- if (is_real_trans)
- {
- if (thd->transaction_rollback_request)
- thd->transaction.xid_state.rm_error= thd->main_da.sql_errno();
- else
- thd->transaction.xid_state.xid.null();
- }
+ if (is_real_trans && thd->transaction_rollback_request)
+ thd->transaction.xid_state.rm_error= thd->main_da.sql_errno();
if (all)
thd->variables.tx_isolation=thd->session_tx_isolation;
}
/* Always cleanup. Even if there nht==0. There may be savepoints. */
- if (all)
+ if (is_real_trans)
thd->transaction.cleanup();
#endif /* USING_TRANSACTIONS */
if (all)
@@ -2284,8 +2293,8 @@ int handler::update_auto_increment()
DBUG_ASSERT(next_insert_id >= auto_inc_interval_for_cur_row.minimum());
if ((nr= table->next_number_field->val_int()) != 0 ||
- table->auto_increment_field_not_null &&
- thd->variables.sql_mode & MODE_NO_AUTO_VALUE_ON_ZERO)
+ (table->auto_increment_field_not_null &&
+ thd->variables.sql_mode & MODE_NO_AUTO_VALUE_ON_ZERO))
{
/*
Update next_insert_id if we had already generated a value in this
@@ -3575,7 +3584,7 @@ int ha_create_table_from_engine(THD* thd, const char *db, const char *name)
int error;
uchar *frmblob;
size_t frmlen;
- char path[FN_REFLEN];
+ char path[FN_REFLEN + 1];
HA_CREATE_INFO create_info;
TABLE table;
TABLE_SHARE share;
@@ -3594,7 +3603,7 @@ int ha_create_table_from_engine(THD* thd, const char *db, const char *name)
frmblob and frmlen are set, write the frm to disk
*/
- build_table_filename(path, FN_REFLEN-1, db, name, "", 0);
+ build_table_filename(path, sizeof(path) - 1, db, name, "", 0);
// Save the frm file
error= writefrm(path, frmblob, frmlen);
my_free(frmblob, MYF(0));
@@ -4821,7 +4830,7 @@ fl_log_iterator_buffer_init(struct handler_iterator *iterator)
if ((ptr= (uchar*)my_malloc(ALIGN_SIZE(sizeof(fl_buff)) +
((ALIGN_SIZE(sizeof(LEX_STRING)) +
sizeof(enum log_status) +
- + FN_REFLEN) *
+ + FN_REFLEN + 1) *
(uint) dirp->number_off_files),
MYF(0))) == 0)
{
@@ -4849,7 +4858,7 @@ fl_log_iterator_buffer_init(struct handler_iterator *iterator)
name_ptr= strxnmov(buff->names[buff->entries].str= name_ptr,
FN_REFLEN, fl_dir, file->name, NullS);
buff->names[buff->entries].length= (name_ptr -
- buff->names[buff->entries].str) - 1;
+ buff->names[buff->entries].str);
buff->statuses[buff->entries]= st;
buff->entries++;
}
diff --git a/sql/handler.h b/sql/handler.h
index d43fc4725dd..11d0f71fc72 100644
--- a/sql/handler.h
+++ b/sql/handler.h
@@ -876,9 +876,9 @@ typedef struct {
ulonglong delete_length;
ha_rows records;
ulong mean_rec_length;
- time_t create_time;
- time_t check_time;
- time_t update_time;
+ ulong create_time;
+ ulong check_time;
+ ulong update_time;
ulonglong check_sum;
} PARTITION_INFO;
@@ -1037,9 +1037,9 @@ public:
ha_rows records;
ha_rows deleted; /* Deleted records */
ulong mean_rec_length; /* physical reclength */
- time_t create_time; /* When table was created */
- time_t check_time;
- time_t update_time;
+ ulong create_time; /* When table was created */
+ ulong check_time;
+ ulong update_time;
uint block_size; /* index block size */
ha_statistics():
@@ -1932,8 +1932,8 @@ private:
/* Some extern variables used with handlers */
extern const char *ha_row_type[];
-extern const char *tx_isolation_names[];
-extern const char *binlog_format_names[];
+extern MYSQL_PLUGIN_IMPORT const char *tx_isolation_names[];
+extern MYSQL_PLUGIN_IMPORT const char *binlog_format_names[];
extern TYPELIB tx_isolation_typelib;
extern TYPELIB myisam_stats_method_typelib;
extern ulong total_ha, total_ha_2pc;
diff --git a/sql/item.cc b/sql/item.cc
index d1418b9a137..4d9004fff26 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -417,6 +417,7 @@ Item::Item(THD *thd, Item *item):
name(item->name),
orig_name(item->orig_name),
max_length(item->max_length),
+ name_length(item->name_length),
marker(item->marker),
decimals(item->decimals),
maybe_null(item->maybe_null),
@@ -424,7 +425,9 @@ Item::Item(THD *thd, Item *item):
unsigned_flag(item->unsigned_flag),
with_sum_func(item->with_sum_func),
fixed(item->fixed),
+ is_autogenerated_name(item->is_autogenerated_name),
collation(item->collation),
+ with_subselect(item->with_subselect),
cmp_context(item->cmp_context)
{
next= thd->free_list; // Put in free list
@@ -1504,10 +1507,6 @@ bool DTCollation::aggregate(DTCollation &dt, uint flags)
{
set(dt);
}
- else
- {
- // Do nothing
- }
}
else if ((flags & MY_COLL_ALLOW_SUPERSET_CONV) &&
left_is_superset(this, &dt))
@@ -2261,8 +2260,10 @@ Item_decimal::Item_decimal(const char *str_arg, uint length,
name= (char*) str_arg;
decimals= (uint8) decimal_value.frac;
fixed= 1;
- max_length= my_decimal_precision_to_length(decimal_value.intg + decimals,
- decimals, unsigned_flag);
+ max_length= my_decimal_precision_to_length_no_truncation(decimal_value.intg +
+ decimals,
+ decimals,
+ unsigned_flag);
}
Item_decimal::Item_decimal(longlong val, bool unsig)
@@ -2270,8 +2271,10 @@ Item_decimal::Item_decimal(longlong val, bool unsig)
int2my_decimal(E_DEC_FATAL_ERROR, val, unsig, &decimal_value);
decimals= (uint8) decimal_value.frac;
fixed= 1;
- max_length= my_decimal_precision_to_length(decimal_value.intg + decimals,
- decimals, unsigned_flag);
+ max_length= my_decimal_precision_to_length_no_truncation(decimal_value.intg +
+ decimals,
+ decimals,
+ unsigned_flag);
}
@@ -2280,8 +2283,10 @@ Item_decimal::Item_decimal(double val, int precision, int scale)
double2my_decimal(E_DEC_FATAL_ERROR, val, &decimal_value);
decimals= (uint8) decimal_value.frac;
fixed= 1;
- max_length= my_decimal_precision_to_length(decimal_value.intg + decimals,
- decimals, unsigned_flag);
+ max_length= my_decimal_precision_to_length_no_truncation(decimal_value.intg +
+ decimals,
+ decimals,
+ unsigned_flag);
}
@@ -2301,8 +2306,10 @@ Item_decimal::Item_decimal(my_decimal *value_par)
my_decimal2decimal(value_par, &decimal_value);
decimals= (uint8) decimal_value.frac;
fixed= 1;
- max_length= my_decimal_precision_to_length(decimal_value.intg + decimals,
- decimals, unsigned_flag);
+ max_length= my_decimal_precision_to_length_no_truncation(decimal_value.intg +
+ decimals,
+ decimals,
+ unsigned_flag);
}
@@ -2312,8 +2319,8 @@ Item_decimal::Item_decimal(const uchar *bin, int precision, int scale)
&decimal_value, precision, scale);
decimals= (uint8) decimal_value.frac;
fixed= 1;
- max_length= my_decimal_precision_to_length(precision, decimals,
- unsigned_flag);
+ max_length= my_decimal_precision_to_length_no_truncation(precision, decimals,
+ unsigned_flag);
}
@@ -2368,8 +2375,10 @@ void Item_decimal::set_decimal_value(my_decimal *value_par)
my_decimal2decimal(value_par, &decimal_value);
decimals= (uint8) decimal_value.frac;
unsigned_flag= !decimal_value.sign();
- max_length= my_decimal_precision_to_length(decimal_value.intg + decimals,
- decimals, unsigned_flag);
+ max_length= my_decimal_precision_to_length_no_truncation(decimal_value.intg +
+ decimals,
+ decimals,
+ unsigned_flag);
}
@@ -2472,8 +2481,9 @@ longlong_from_string_with_check (CHARSET_INFO *cs, const char *cptr, char *end)
TODO: Give error if we wanted a signed integer and we got an unsigned
one
*/
- if (err > 0 ||
- (end != org_end && !check_if_only_end_space(cs, end, org_end)))
+ if (!current_thd->no_errors &&
+ (err > 0 ||
+ (end != org_end && !check_if_only_end_space(cs, end, org_end))))
{
push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_TRUNCATED_WRONG_VALUE,
@@ -2640,8 +2650,9 @@ void Item_param::set_decimal(const char *str, ulong length)
str2my_decimal(E_DEC_FATAL_ERROR, str, &decimal_value, &end);
state= DECIMAL_VALUE;
decimals= decimal_value.frac;
- max_length= my_decimal_precision_to_length(decimal_value.precision(),
- decimals, unsigned_flag);
+ max_length=
+ my_decimal_precision_to_length_no_truncation(decimal_value.precision(),
+ decimals, unsigned_flag);
maybe_null= 0;
DBUG_VOID_RETURN;
}
@@ -2771,8 +2782,8 @@ bool Item_param::set_from_user_var(THD *thd, const user_var_entry *entry)
CHARSET_INFO *tocs= thd->variables.collation_connection;
uint32 dummy_offset;
- value.cs_info.character_set_of_placeholder=
- value.cs_info.character_set_client= fromcs;
+ value.cs_info.character_set_of_placeholder= fromcs;
+ value.cs_info.character_set_client= thd->variables.character_set_client;
/*
Setup source and destination character sets so that they
are different only if conversion is necessary: this will
@@ -2797,8 +2808,9 @@ bool Item_param::set_from_user_var(THD *thd, const user_var_entry *entry)
my_decimal2decimal(ent_value, &decimal_value);
state= DECIMAL_VALUE;
decimals= ent_value->frac;
- max_length= my_decimal_precision_to_length(ent_value->precision(),
- decimals, unsigned_flag);
+ max_length=
+ my_decimal_precision_to_length_no_truncation(ent_value->precision(),
+ decimals, unsigned_flag);
item_type= Item::DECIMAL_ITEM;
break;
}
@@ -3267,10 +3279,58 @@ Item_param::set_param_type_and_swap_value(Item_param *src)
str_value_ptr.swap(src->str_value_ptr);
}
+/****************************************************************************
+ Item_copy
+****************************************************************************/
+Item_copy *Item_copy::create (Item *item)
+{
+ switch (item->result_type())
+ {
+ case STRING_RESULT:
+ return new Item_copy_string (item);
+ case REAL_RESULT:
+ return new Item_copy_float (item);
+ case INT_RESULT:
+ return item->unsigned_flag ?
+ new Item_copy_uint (item) : new Item_copy_int (item);
+ case DECIMAL_RESULT:
+ return new Item_copy_decimal (item);
+
+ case ROW_RESULT:
+ DBUG_ASSERT (0);
+ }
+ /* should not happen */
+ return NULL;
+}
+
/****************************************************************************
Item_copy_string
****************************************************************************/
+double Item_copy_string::val_real()
+{
+ int err_not_used;
+ char *end_not_used;
+ return (null_value ? 0.0 :
+ my_strntod(str_value.charset(), (char*) str_value.ptr(),
+ str_value.length(), &end_not_used, &err_not_used));
+}
+
+longlong Item_copy_string::val_int()
+{
+ int err;
+ return null_value ? LL(0) : my_strntoll(str_value.charset(),str_value.ptr(),
+ str_value.length(),10, (char**) 0,
+ &err);
+}
+
+
+int Item_copy_string::save_in_field(Field *field, bool no_conversions)
+{
+ return save_str_value_in_field(field, &str_value);
+}
+
+
void Item_copy_string::copy()
{
String *res=item->val_str(&str_value);
@@ -3293,12 +3353,163 @@ my_decimal *Item_copy_string::val_decimal(my_decimal *decimal_value)
{
// Item_copy_string is used without fix_fields call
if (null_value)
- return 0;
+ return (my_decimal *) 0;
string2my_decimal(E_DEC_FATAL_ERROR, &str_value, decimal_value);
return (decimal_value);
}
+/****************************************************************************
+ Item_copy_int
+****************************************************************************/
+
+void Item_copy_int::copy()
+{
+ cached_value= item->val_int();
+ null_value=item->null_value;
+}
+
+static int save_int_value_in_field (Field *field, longlong nr,
+ bool null_value, bool unsigned_flag);
+
+int Item_copy_int::save_in_field(Field *field, bool no_conversions)
+{
+ return save_int_value_in_field(field, cached_value,
+ null_value, unsigned_flag);
+}
+
+
+String *Item_copy_int::val_str(String *str)
+{
+ if (null_value)
+ return (String *) 0;
+
+ str->set(cached_value, &my_charset_bin);
+ return str;
+}
+
+
+my_decimal *Item_copy_int::val_decimal(my_decimal *decimal_value)
+{
+ if (null_value)
+ return (my_decimal *) 0;
+
+ int2my_decimal(E_DEC_FATAL_ERROR, cached_value, unsigned_flag, decimal_value);
+ return decimal_value;
+}
+
+
+/****************************************************************************
+ Item_copy_uint
+****************************************************************************/
+
+String *Item_copy_uint::val_str(String *str)
+{
+ if (null_value)
+ return (String *) 0;
+
+ str->set((ulonglong) cached_value, &my_charset_bin);
+ return str;
+}
+
+
+/****************************************************************************
+ Item_copy_float
+****************************************************************************/
+
+String *Item_copy_float::val_str(String *str)
+{
+ if (null_value)
+ return (String *) 0;
+ else
+ {
+ double nr= val_real();
+ str->set_real(nr,decimals, &my_charset_bin);
+ return str;
+ }
+}
+
+
+my_decimal *Item_copy_float::val_decimal(my_decimal *decimal_value)
+{
+ if (null_value)
+ return (my_decimal *) 0;
+ else
+ {
+ double nr= val_real();
+ double2my_decimal(E_DEC_FATAL_ERROR, nr, decimal_value);
+ return decimal_value;
+ }
+}
+
+
+int Item_copy_float::save_in_field(Field *field, bool no_conversions)
+{
+ if (null_value)
+ return set_field_to_null(field);
+ field->set_notnull();
+ return field->store(cached_value);
+}
+
+
+/****************************************************************************
+ Item_copy_decimal
+****************************************************************************/
+
+int Item_copy_decimal::save_in_field(Field *field, bool no_conversions)
+{
+ if (null_value)
+ return set_field_to_null(field);
+ field->set_notnull();
+ return field->store_decimal(&cached_value);
+}
+
+
+String *Item_copy_decimal::val_str(String *result)
+{
+ if (null_value)
+ return (String *) 0;
+ result->set_charset(&my_charset_bin);
+ my_decimal2string(E_DEC_FATAL_ERROR, &cached_value, 0, 0, 0, result);
+ return result;
+}
+
+
+double Item_copy_decimal::val_real()
+{
+ if (null_value)
+ return 0.0;
+ else
+ {
+ double result;
+ my_decimal2double(E_DEC_FATAL_ERROR, &cached_value, &result);
+ return result;
+ }
+}
+
+
+longlong Item_copy_decimal::val_int()
+{
+ if (null_value)
+ return LL(0);
+ else
+ {
+ longlong result;
+ my_decimal2int(E_DEC_FATAL_ERROR, &cached_value, unsigned_flag, &result);
+ return result;
+ }
+}
+
+
+void Item_copy_decimal::copy()
+{
+ my_decimal *nr= item->val_decimal(&cached_value);
+ if (nr && nr != &cached_value)
+ memcpy (&cached_value, nr, sizeof (my_decimal));
+ null_value= item->null_value;
+}
+
+
/*
Functions to convert item to field (for send_fields)
*/
@@ -3390,14 +3601,12 @@ static void mark_as_dependent(THD *thd, SELECT_LEX *last, SELECT_LEX *current,
current->mark_as_dependent(last);
if (thd->lex->describe & DESCRIBE_EXTENDED)
{
- char warn_buff[MYSQL_ERRMSG_SIZE];
- sprintf(warn_buff, ER(ER_WARN_FIELD_RESOLVED),
- db_name, (db_name[0] ? "." : ""),
- table_name, (table_name [0] ? "." : ""),
- resolved_item->field_name,
- current->select_number, last->select_number);
- push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
- ER_WARN_FIELD_RESOLVED, warn_buff);
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
+ ER_WARN_FIELD_RESOLVED, ER(ER_WARN_FIELD_RESOLVED),
+ db_name, (db_name[0] ? "." : ""),
+ table_name, (table_name [0] ? "." : ""),
+ resolved_item->field_name,
+ current->select_number, last->select_number);
}
}
@@ -4209,16 +4418,22 @@ mark_non_agg_field:
Fields from outer selects added to the aggregate function
outer_fields list as its unknown at the moment whether it's
aggregated or not.
+ We're using either the select lex of the cached table (if present)
+ or the field's resolution context. context->select_lex is
+ safe for use because it's either the SELECT we want to use
+ (the current level) or a stub added by non-SELECT queries.
*/
+ SELECT_LEX *select_lex= cached_table ?
+ cached_table->select_lex : context->select_lex;
if (!thd->lex->in_sum_func)
- cached_table->select_lex->full_group_by_flag|= NON_AGG_FIELD_USED;
+ select_lex->full_group_by_flag|= NON_AGG_FIELD_USED;
else
{
if (outer_fixed)
thd->lex->in_sum_func->outer_fields.push_back(this);
else if (thd->lex->in_sum_func->nest_level !=
thd->lex->current_select->nest_level)
- cached_table->select_lex->full_group_by_flag|= NON_AGG_FIELD_USED;
+ select_lex->full_group_by_flag|= NON_AGG_FIELD_USED;
}
}
return FALSE;
@@ -4875,7 +5090,10 @@ int Item_null::save_safe_in_field(Field *field)
/*
This implementation can lose str_value content, so if the
Item uses str_value to store something, it should
- reimplement it's ::save_in_field() as Item_string, for example, does
+ reimplement it's ::save_in_field() as Item_string, for example, does.
+
+ Note: all Item_XXX::val_str(str) methods must NOT rely on the fact that
+ str != str_value. For example, see fix for bug #44743.
*/
int Item::save_in_field(Field *field, bool no_conversions)
@@ -4945,10 +5163,9 @@ int Item_uint::save_in_field(Field *field, bool no_conversions)
return Item_int::save_in_field(field, no_conversions);
}
-
-int Item_int::save_in_field(Field *field, bool no_conversions)
+static int save_int_value_in_field (Field *field, longlong nr,
+ bool null_value, bool unsigned_flag)
{
- longlong nr=val_int();
if (null_value)
return set_field_to_null(field);
field->set_notnull();
@@ -4956,6 +5173,12 @@ int Item_int::save_in_field(Field *field, bool no_conversions)
}
+int Item_int::save_in_field(Field *field, bool no_conversions)
+{
+ return save_int_value_in_field (field, val_int(), null_value, unsigned_flag);
+}
+
+
int Item_decimal::save_in_field(Field *field, bool no_conversions)
{
field->set_notnull();
@@ -5812,7 +6035,8 @@ void Item_ref::print(String *str, enum_query_type query_type)
!table_name && name && alias_name_used)
{
THD *thd= current_thd;
- append_identifier(thd, str, name, (uint) strlen(name));
+ append_identifier(thd, str, (*ref)->real_item()->name,
+ (*ref)->real_item()->name_length);
}
else
(*ref)->print(str, query_type);
@@ -7084,8 +7308,9 @@ bool Item_type_holder::join_types(THD *thd, Item *item)
int item_prec = max(prev_decimal_int_part, item_int_part) + decimals;
int precision= min(item_prec, DECIMAL_MAX_PRECISION);
unsigned_flag&= item->unsigned_flag;
- max_length= my_decimal_precision_to_length(precision, decimals,
- unsigned_flag);
+ max_length= my_decimal_precision_to_length_no_truncation(precision,
+ decimals,
+ unsigned_flag);
}
switch (Field::result_merge_type(fld_type))
diff --git a/sql/item.h b/sql/item.h
index 96a4e9f7a31..3dfcd7c2612 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -2443,48 +2443,203 @@ public:
#include "item_xmlfunc.h"
#endif
-class Item_copy_string :public Item
+/**
+ Base class to implement typed value caching Item classes
+
+ Item_copy_ classes are very similar to the corresponding Item_
+ classes (e.g. Item_copy_int is similar to Item_int) but they add
+ the following additional functionality to Item_ :
+ 1. Nullability
+ 2. Possibility to store the value not only on instantiation time,
+ but also later.
+ Item_copy_ classes are a functionality subset of Item_cache_
+ classes, as e.g. they don't support comparisons with the original Item
+ as Item_cache_ classes do.
+ Item_copy_ classes are used in GROUP BY calculation.
+ TODO: Item_copy should be made an abstract interface and Item_copy_
+ classes should inherit both the respective Item_ class and the interface.
+ Ideally we should drop Item_copy_ classes altogether and merge
+ their functionality to Item_cache_ (and these should be made to inherit
+ from Item_).
+*/
+
+class Item_copy :public Item
{
+protected:
+
+ /**
+ Stores the type of the resulting field that would be used to store the data
+ in the cache. This is to avoid calls to the original item.
+ */
enum enum_field_types cached_field_type;
-public:
+
+ /** The original item that is copied */
Item *item;
- Item_copy_string(Item *i) :item(i)
+
+ /**
+ Stores the result type of the original item, so it can be returned
+ without calling the original item's method
+ */
+ Item_result cached_result_type;
+
+ /**
+ Constructor of the Item_copy class
+
+ stores metadata information about the original class as well as a
+ pointer to it.
+ */
+ Item_copy(Item *i)
{
+ item= i;
null_value=maybe_null=item->maybe_null;
decimals=item->decimals;
max_length=item->max_length;
name=item->name;
cached_field_type= item->field_type();
+ cached_result_type= item->result_type();
+ unsigned_flag= item->unsigned_flag;
}
+
+public:
+ /**
+ Factory method to create the appropriate subclass dependent on the type of
+ the original item.
+
+ @param item the original item.
+ */
+ static Item_copy *create (Item *item);
+
+ /**
+ Update the cache with the value of the original item
+
+ This is the method that updates the cached value.
+ It must be explicitly called by the user of this class to store the value
+ of the orginal item in the cache.
+ */
+ virtual void copy() = 0;
+
+ Item *get_item() { return item; }
+ /** All of the subclasses should have the same type tag */
enum Type type() const { return COPY_STR_ITEM; }
- enum Item_result result_type () const { return STRING_RESULT; }
enum_field_types field_type() const { return cached_field_type; }
- double val_real()
- {
- int err_not_used;
- char *end_not_used;
- return (null_value ? 0.0 :
- my_strntod(str_value.charset(), (char*) str_value.ptr(),
- str_value.length(), &end_not_used, &err_not_used));
- }
- longlong val_int()
- {
- int err;
- return null_value ? LL(0) : my_strntoll(str_value.charset(),str_value.ptr(),
- str_value.length(),10, (char**) 0,
- &err);
- }
- String *val_str(String*);
- my_decimal *val_decimal(my_decimal *);
+ enum Item_result result_type () const { return cached_result_type; }
+
void make_field(Send_field *field) { item->make_field(field); }
- void copy();
- int save_in_field(Field *field, bool no_conversions)
- {
- return save_str_value_in_field(field, &str_value);
- }
table_map used_tables() const { return (table_map) 1L; }
bool const_item() const { return 0; }
bool is_null() { return null_value; }
+
+ /*
+ Override the methods below as pure virtual to make sure all the
+ sub-classes implement them.
+ */
+
+ virtual String *val_str(String*) = 0;
+ virtual my_decimal *val_decimal(my_decimal *) = 0;
+ virtual double val_real() = 0;
+ virtual longlong val_int() = 0;
+ virtual int save_in_field(Field *field, bool no_conversions) = 0;
+};
+
+/**
+ Implementation of a string cache.
+
+ Uses Item::str_value for storage
+*/
+class Item_copy_string : public Item_copy
+{
+public:
+ Item_copy_string (Item *item) : Item_copy(item) {}
+
+ String *val_str(String*);
+ my_decimal *val_decimal(my_decimal *);
+ double val_real();
+ longlong val_int();
+ void copy();
+ int save_in_field(Field *field, bool no_conversions);
+};
+
+
+class Item_copy_int : public Item_copy
+{
+protected:
+ longlong cached_value;
+public:
+ Item_copy_int (Item *i) : Item_copy(i) {}
+ int save_in_field(Field *field, bool no_conversions);
+
+ virtual String *val_str(String*);
+ virtual my_decimal *val_decimal(my_decimal *);
+ virtual double val_real()
+ {
+ return null_value ? 0.0 : (double) cached_value;
+ }
+ virtual longlong val_int()
+ {
+ return null_value ? LL(0) : cached_value;
+ }
+ virtual void copy();
+};
+
+
+class Item_copy_uint : public Item_copy_int
+{
+public:
+ Item_copy_uint (Item *item) : Item_copy_int(item)
+ {
+ unsigned_flag= 1;
+ }
+
+ String *val_str(String*);
+ double val_real()
+ {
+ return null_value ? 0.0 : (double) (ulonglong) cached_value;
+ }
+};
+
+
+class Item_copy_float : public Item_copy
+{
+protected:
+ double cached_value;
+public:
+ Item_copy_float (Item *i) : Item_copy(i) {}
+ int save_in_field(Field *field, bool no_conversions);
+
+ String *val_str(String*);
+ my_decimal *val_decimal(my_decimal *);
+ double val_real()
+ {
+ return null_value ? 0.0 : cached_value;
+ }
+ longlong val_int()
+ {
+ return (longlong) rint(val_real());
+ }
+ void copy()
+ {
+ cached_value= item->val_real();
+ null_value= item->null_value;
+ }
+};
+
+
+class Item_copy_decimal : public Item_copy
+{
+protected:
+ my_decimal cached_value;
+public:
+ Item_copy_decimal (Item *i) : Item_copy(i) {}
+ int save_in_field(Field *field, bool no_conversions);
+
+ String *val_str(String*);
+ my_decimal *val_decimal(my_decimal *)
+ {
+ return null_value ? NULL: &cached_value;
+ }
+ double val_real();
+ longlong val_int();
+ void copy();
};
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index a9bfea1b806..1ff9ca6a419 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -1484,8 +1484,8 @@ longlong Item_func_truth::val_int()
bool Item_in_optimizer::fix_left(THD *thd, Item **ref)
{
- if (!args[0]->fixed && args[0]->fix_fields(thd, args) ||
- !cache && !(cache= Item_cache::get_cache(args[0])))
+ if ((!args[0]->fixed && args[0]->fix_fields(thd, args)) ||
+ (!cache && !(cache= Item_cache::get_cache(args[0]))))
return 1;
cache->setup(args[0]);
@@ -2724,16 +2724,6 @@ void Item_func_case::fix_length_and_dec()
nagg++;
if (!(found_types= collect_cmp_types(agg, nagg)))
return;
- if (with_sum_func || current_thd->lex->current_select->group_list.elements)
- {
- /*
- See TODO commentary in the setup_copy_fields function:
- item in a group may be wrapped with an Item_copy_string item.
- That item has a STRING_RESULT result type, so we need
- to take this type into account.
- */
- found_types |= (1 << item_cmp_type(left_result_type, STRING_RESULT));
- }
for (i= 0; i <= (uint)DECIMAL_RESULT; i++)
{
@@ -2770,8 +2760,9 @@ void Item_func_case::fix_length_and_dec()
agg_num_lengths(args[i + 1]);
if (else_expr_num != -1)
agg_num_lengths(args[else_expr_num]);
- max_length= my_decimal_precision_to_length(max_length + decimals, decimals,
- unsigned_flag);
+ max_length= my_decimal_precision_to_length_no_truncation(max_length +
+ decimals, decimals,
+ unsigned_flag);
}
}
@@ -3006,8 +2997,8 @@ int cmp_longlong(void *cmp_arg,
One of the args is unsigned and is too big to fit into the
positive signed range. Report no match.
*/
- if (a->unsigned_flag && ((ulonglong) a->val) > (ulonglong) LONGLONG_MAX ||
- b->unsigned_flag && ((ulonglong) b->val) > (ulonglong) LONGLONG_MAX)
+ if ((a->unsigned_flag && ((ulonglong) a->val) > (ulonglong) LONGLONG_MAX) ||
+ (b->unsigned_flag && ((ulonglong) b->val) > (ulonglong) LONGLONG_MAX))
return a->unsigned_flag ? 1 : -1;
/*
Although the signedness differs both args can fit into the signed
diff --git a/sql/item_func.cc b/sql/item_func.cc
index 876aee719a3..0af3c4954cd 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -452,11 +452,45 @@ Field *Item_func::tmp_table_field(TABLE *table)
return make_string_field(table);
break;
case DECIMAL_RESULT:
- field= new Field_new_decimal(my_decimal_precision_to_length(decimal_precision(),
- decimals,
- unsigned_flag),
- maybe_null, name, decimals, unsigned_flag);
+ {
+ uint8 dec= decimals;
+ uint8 intg= decimal_precision() - dec;
+ uint32 len= max_length;
+
+ /*
+ Trying to put too many digits overall in a DECIMAL(prec,dec)
+ will always throw a warning. We must limit dec to
+ DECIMAL_MAX_SCALE however to prevent an assert() later.
+ */
+
+ if (dec > 0)
+ {
+ int overflow;
+
+ dec= min(dec, DECIMAL_MAX_SCALE);
+
+ /*
+ If the value still overflows the field with the corrected dec,
+ we'll throw out decimals rather than integers. This is still
+ bad and of course throws a truncation warning.
+ */
+
+ const int required_length=
+ my_decimal_precision_to_length(intg + dec, dec,
+ unsigned_flag);
+
+ overflow= required_length - len;
+
+ if (overflow > 0)
+ dec= max(0, dec - overflow); // too long, discard fract
+ else
+ /* Corrected value fits. */
+ len= required_length;
+ }
+
+ field= new Field_new_decimal(len, maybe_null, name, dec, unsigned_flag);
break;
+ }
case ROW_RESULT:
default:
// This case should never be chosen
@@ -545,8 +579,8 @@ void Item_func::count_decimal_length()
set_if_smaller(unsigned_flag, args[i]->unsigned_flag);
}
int precision= min(max_int_part + decimals, DECIMAL_MAX_PRECISION);
- max_length= my_decimal_precision_to_length(precision, decimals,
- unsigned_flag);
+ max_length= my_decimal_precision_to_length_no_truncation(precision, decimals,
+ unsigned_flag);
}
@@ -1141,16 +1175,15 @@ void Item_func_additive_op::result_precision()
decimals= max(args[0]->decimals, args[1]->decimals);
int arg1_int= args[0]->decimal_precision() - args[0]->decimals;
int arg2_int= args[1]->decimal_precision() - args[1]->decimals;
- int est_prec= max(arg1_int, arg2_int) + 1 + decimals;
- int precision= min(est_prec, DECIMAL_MAX_PRECISION);
+ int precision= max(arg1_int, arg2_int) + 1 + decimals;
/* Integer operations keep unsigned_flag if one of arguments is unsigned */
if (result_type() == INT_RESULT)
unsigned_flag= args[0]->unsigned_flag | args[1]->unsigned_flag;
else
unsigned_flag= args[0]->unsigned_flag & args[1]->unsigned_flag;
- max_length= my_decimal_precision_to_length(precision, decimals,
- unsigned_flag);
+ max_length= my_decimal_precision_to_length_no_truncation(precision, decimals,
+ unsigned_flag);
}
@@ -1255,7 +1288,8 @@ void Item_func_mul::result_precision()
decimals= min(args[0]->decimals + args[1]->decimals, DECIMAL_MAX_SCALE);
uint est_prec = args[0]->decimal_precision() + args[1]->decimal_precision();
uint precision= min(est_prec, DECIMAL_MAX_PRECISION);
- max_length= my_decimal_precision_to_length(precision, decimals,unsigned_flag);
+ max_length= my_decimal_precision_to_length_no_truncation(precision, decimals,
+ unsigned_flag);
}
@@ -1311,8 +1345,8 @@ void Item_func_div::result_precision()
else
unsigned_flag= args[0]->unsigned_flag & args[1]->unsigned_flag;
decimals= min(args[0]->decimals + prec_increment, DECIMAL_MAX_SCALE);
- max_length= my_decimal_precision_to_length(precision, decimals,
- unsigned_flag);
+ max_length= my_decimal_precision_to_length_no_truncation(precision, decimals,
+ unsigned_flag);
}
@@ -1944,8 +1978,8 @@ void Item_func_round::fix_length_and_dec()
unsigned_flag= args[0]->unsigned_flag;
if (!args[1]->const_item())
{
- max_length= args[0]->max_length;
decimals= args[0]->decimals;
+ max_length= float_length(decimals);
if (args[0]->result_type() == DECIMAL_RESULT)
{
max_length++;
@@ -1965,8 +1999,8 @@ void Item_func_round::fix_length_and_dec()
if (args[0]->decimals == NOT_FIXED_DEC)
{
- max_length= args[0]->max_length;
decimals= min(decimals_to_set, NOT_FIXED_DEC);
+ max_length= float_length(decimals);
hybrid_type= REAL_RESULT;
return;
}
@@ -1999,8 +2033,9 @@ void Item_func_round::fix_length_and_dec()
precision-= decimals_delta - length_increase;
decimals= min(decimals_to_set, DECIMAL_MAX_SCALE);
- max_length= my_decimal_precision_to_length(precision, decimals,
- unsigned_flag);
+ max_length= my_decimal_precision_to_length_no_truncation(precision,
+ decimals,
+ unsigned_flag);
break;
}
default:
@@ -2143,9 +2178,6 @@ bool Item_func_rand::fix_fields(THD *thd,Item **ref)
if (!rand && !(rand= (struct rand_struct*)
thd->stmt_arena->alloc(sizeof(*rand))))
return TRUE;
-
- if (args[0]->const_item())
- seed_random (args[0]);
}
else
{
@@ -2175,8 +2207,21 @@ void Item_func_rand::update_used_tables()
double Item_func_rand::val_real()
{
DBUG_ASSERT(fixed == 1);
- if (arg_count && !args[0]->const_item())
- seed_random (args[0]);
+ if (arg_count)
+ {
+ if (!args[0]->const_item())
+ seed_random(args[0]);
+ else if (first_eval)
+ {
+ /*
+ Constantness of args[0] may be set during JOIN::optimize(), if arg[0]
+ is a field item of "constant" table. Thus, we have to evaluate
+ seed_random() for constant arg there but not at the fix_fields method.
+ */
+ first_eval= FALSE;
+ seed_random(args[0]);
+ }
+ }
return my_rnd(rand);
}
@@ -2233,8 +2278,9 @@ void Item_func_min_max::fix_length_and_dec()
}
}
else if ((cmp_type == DECIMAL_RESULT) || (cmp_type == INT_RESULT))
- max_length= my_decimal_precision_to_length(max_int_part+decimals, decimals,
- unsigned_flag);
+ max_length= my_decimal_precision_to_length_no_truncation(max_int_part +
+ decimals, decimals,
+ unsigned_flag);
cached_field_type= agg_field_type(args, arg_count);
}
@@ -4177,6 +4223,41 @@ Item_func_set_user_var::check(bool use_result_field)
}
+/**
+ @brief Evaluate and store item's result.
+ This function is invoked on "SELECT ... INTO @var ...".
+
+ @param item An item to get value from.
+*/
+
+void Item_func_set_user_var::save_item_result(Item *item)
+{
+ DBUG_ENTER("Item_func_set_user_var::save_item_result");
+
+ switch (cached_result_type) {
+ case REAL_RESULT:
+ save_result.vreal= item->val_result();
+ break;
+ case INT_RESULT:
+ save_result.vint= item->val_int_result();
+ unsigned_flag= item->unsigned_flag;
+ break;
+ case STRING_RESULT:
+ save_result.vstr= item->str_result(&value);
+ break;
+ case DECIMAL_RESULT:
+ save_result.vdec= item->val_decimal_result(&decimal_buff);
+ break;
+ case ROW_RESULT:
+ default:
+ // Should never happen
+ DBUG_ASSERT(0);
+ break;
+ }
+ DBUG_VOID_RETURN;
+}
+
+
/**
This functions is invoked on
SET \@variable or \@variable:= expression.
@@ -4418,8 +4499,8 @@ int Item_func_set_user_var::save_in_field(Field *field, bool no_conversions,
update();
if (result_type() == STRING_RESULT ||
- result_type() == REAL_RESULT &&
- field->result_type() == STRING_RESULT)
+ (result_type() == REAL_RESULT &&
+ field->result_type() == STRING_RESULT))
{
String *result;
CHARSET_INFO *cs= collation.collation;
@@ -4835,10 +4916,20 @@ bool Item_func_get_system_var::is_written_to_binlog()
}
+void Item_func_get_system_var::update_null_value()
+{
+ THD *thd= current_thd;
+ int save_no_errors= thd->no_errors;
+ thd->no_errors= TRUE;
+ Item::update_null_value();
+ thd->no_errors= save_no_errors;
+}
+
+
void Item_func_get_system_var::fix_length_and_dec()
{
char *cptr;
- maybe_null=0;
+ maybe_null= TRUE;
max_length= 0;
if (var->check_type(var_type))
@@ -5747,6 +5838,14 @@ Item_func_sp::func_name() const
}
+int my_missing_function_error(const LEX_STRING &token, const char *func_name)
+{
+ if (token.length && is_lex_native_function (&token))
+ return my_error(ER_FUNC_INEXISTENT_NAME_COLLISION, MYF(0), func_name);
+ else
+ return my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "FUNCTION", func_name);
+}
+
/**
@brief Initialize the result field by creating a temporary dummy table
@@ -5779,7 +5878,7 @@ Item_func_sp::init_result_field(THD *thd)
if (!(m_sp= sp_find_routine(thd, TYPE_ENUM_FUNCTION, m_name,
&thd->sp_func_cache, TRUE)))
{
- my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "FUNCTION", m_name->m_qname.str);
+ my_missing_function_error (m_name->m_name, m_name->m_qname.str);
context->process_error(thd);
DBUG_RETURN(TRUE);
}
diff --git a/sql/item_func.h b/sql/item_func.h
index d23d821baf6..514f93a39ea 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -378,7 +378,8 @@ public:
Item_decimal_typecast(Item *a, int len, int dec) :Item_func(a)
{
decimals= dec;
- max_length= my_decimal_precision_to_length(len, dec, unsigned_flag);
+ max_length= my_decimal_precision_to_length_no_truncation(len, dec,
+ unsigned_flag);
}
String *val_str(String *str);
double val_real();
@@ -696,14 +697,16 @@ public:
class Item_func_rand :public Item_real_func
{
struct rand_struct *rand;
+ bool first_eval; // TRUE if val_real() is called 1st time
public:
- Item_func_rand(Item *a) :Item_real_func(a), rand(0) {}
+ Item_func_rand(Item *a) :Item_real_func(a), rand(0), first_eval(TRUE) {}
Item_func_rand() :Item_real_func() {}
double val_real();
const char *func_name() const { return "rand"; }
bool const_item() const { return 0; }
void update_used_tables();
bool fix_fields(THD *thd, Item **ref);
+ void cleanup() { first_eval= TRUE; Item_real_func::cleanup(); }
private:
void seed_random (Item * val);
};
@@ -1341,6 +1344,7 @@ public:
bool send(Protocol *protocol, String *str_arg);
void make_field(Send_field *tmp_field);
bool check(bool use_result_field);
+ void save_item_result(Item *item);
bool update();
enum Item_result result_type () const { return cached_result_type; }
bool fix_fields(THD *thd, Item **ref);
@@ -1452,6 +1456,7 @@ public:
LEX_STRING *component_arg, const char *name_arg,
size_t name_len_arg);
enum Functype functype() const { return GSYSVAR_FUNC; }
+ void update_null_value();
void fix_length_and_dec();
void print(String *str, enum_query_type query_type);
bool const_item() const { return true; }
diff --git a/sql/item_geofunc.cc b/sql/item_geofunc.cc
index 24a92c78e9c..a34204b7181 100644
--- a/sql/item_geofunc.cc
+++ b/sql/item_geofunc.cc
@@ -416,7 +416,10 @@ String *Item_func_spatial_collection::val_str(String *str)
else
{
enum Geometry::wkbType wkb_type;
- const char *data= res->ptr() + 4/*SRID*/ + 1;
+ const uint data_offset= 4/*SRID*/ + 1;
+ if (res->length() < data_offset + sizeof(uint32))
+ goto err;
+ const char *data= res->ptr() + data_offset;
/*
In the case of named collection we must check that items
@@ -439,7 +442,7 @@ String *Item_func_spatial_collection::val_str(String *str)
break;
case Geometry::wkb_linestring:
- if (str->append(data, POINT_DATA_SIZE, 512))
+ if (len < POINT_DATA_SIZE || str->append(data, POINT_DATA_SIZE, 512))
goto err;
break;
case Geometry::wkb_polygon:
@@ -448,11 +451,15 @@ String *Item_func_spatial_collection::val_str(String *str)
double x1, y1, x2, y2;
const char *org_data= data;
- if (len < 4 + 2 * POINT_DATA_SIZE)
+ if (len < 4)
goto err;
n_points= uint4korr(data);
data+= 4;
+
+ if (n_points < 2 || len < 4 + n_points * POINT_DATA_SIZE)
+ goto err;
+
float8get(x1, data);
data+= SIZEOF_STORED_DOUBLE;
float8get(y1, data);
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc
index 267036e4a3d..be94f19f597 100644
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.cc
@@ -1629,16 +1629,17 @@ String *Item_func_password::val_str(String *str)
return 0;
if (res->length() == 0)
return &my_empty_string;
- make_scrambled_password(tmp_value, res->c_ptr());
+ my_make_scrambled_password(tmp_value, res->ptr(), res->length());
str->set(tmp_value, SCRAMBLED_PASSWORD_CHAR_LENGTH, res->charset());
return str;
}
-char *Item_func_password::alloc(THD *thd, const char *password)
+char *Item_func_password::alloc(THD *thd, const char *password,
+ size_t pass_len)
{
char *buff= (char *) thd->alloc(SCRAMBLED_PASSWORD_CHAR_LENGTH+1);
if (buff)
- make_scrambled_password(buff, password);
+ my_make_scrambled_password(buff, password, pass_len);
return buff;
}
@@ -1652,16 +1653,17 @@ String *Item_func_old_password::val_str(String *str)
return 0;
if (res->length() == 0)
return &my_empty_string;
- make_scrambled_password_323(tmp_value, res->c_ptr());
+ my_make_scrambled_password_323(tmp_value, res->ptr(), res->length());
str->set(tmp_value, SCRAMBLED_PASSWORD_CHAR_LENGTH_323, res->charset());
return str;
}
-char *Item_func_old_password::alloc(THD *thd, const char *password)
+char *Item_func_old_password::alloc(THD *thd, const char *password,
+ size_t pass_len)
{
char *buff= (char *) thd->alloc(SCRAMBLED_PASSWORD_CHAR_LENGTH_323+1);
if (buff)
- make_scrambled_password_323(buff, password);
+ my_make_scrambled_password_323(buff, password, pass_len);
return buff;
}
@@ -2706,7 +2708,13 @@ String *Item_func_conv_charset::val_str(String *str)
DBUG_ASSERT(fixed == 1);
if (use_cached_value)
return null_value ? 0 : &str_value;
- String *arg= args[0]->val_str(str);
+ /*
+ Here we don't pass 'str' as a parameter to args[0]->val_str()
+ as 'str' may point to 'str_value' (e.g. see Item::save_in_field()),
+ which we use below to convert string.
+ Use argument's 'str_value' instead.
+ */
+ String *arg= args[0]->val_str(&args[0]->str_value);
uint dummy_errors;
if (!arg)
{
@@ -2943,7 +2951,7 @@ String *Item_load_file::val_str(String *str)
)
goto err;
- (void) fn_format(path, file_name->c_ptr(), mysql_real_data_home, "",
+ (void) fn_format(path, file_name->c_ptr_safe(), mysql_real_data_home, "",
MY_RELATIVE_PATH | MY_UNPACK_FILENAME);
/* Read only allowed from within dir specified by secure_file_priv */
@@ -2969,7 +2977,7 @@ String *Item_load_file::val_str(String *str)
}
if (tmp_value.alloc(stat_info.st_size))
goto err;
- if ((file = my_open(file_name->c_ptr(), O_RDONLY, MYF(0))) < 0)
+ if ((file = my_open(file_name->ptr(), O_RDONLY, MYF(0))) < 0)
goto err;
if (my_read(file, (uchar*) tmp_value.ptr(), stat_info.st_size, MYF(MY_NABP)))
{
@@ -3219,7 +3227,21 @@ longlong Item_func_uncompressed_length::val_int()
if (res->is_empty()) return 0;
/*
- res->ptr() using is safe because we have tested that string is not empty,
+ If length is <= 4 bytes, data is corrupt. This is the best we can do
+ to detect garbage input without decompressing it.
+ */
+ if (res->length() <= 4)
+ {
+ push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
+ ER_ZLIB_Z_DATA_ERROR,
+ ER(ER_ZLIB_Z_DATA_ERROR));
+ null_value= 1;
+ return 0;
+ }
+
+ /*
+ res->ptr() using is safe because we have tested that string is at least
+ 5 bytes long.
res->c_ptr() is not used because:
- we do not need \0 terminated string to get first 4 bytes
- c_ptr() tests simbol after string end (uninitialiozed memory) which
diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h
index 5265f608344..2cdb45100ae 100644
--- a/sql/item_strfunc.h
+++ b/sql/item_strfunc.h
@@ -268,7 +268,7 @@ public:
String *val_str(String *str);
void fix_length_and_dec() { max_length= SCRAMBLED_PASSWORD_CHAR_LENGTH; }
const char *func_name() const { return "password"; }
- static char *alloc(THD *thd, const char *password);
+ static char *alloc(THD *thd, const char *password, size_t pass_len);
};
@@ -287,7 +287,7 @@ public:
String *val_str(String *str);
void fix_length_and_dec() { max_length= SCRAMBLED_PASSWORD_CHAR_LENGTH_323; }
const char *func_name() const { return "old_password"; }
- static char *alloc(THD *thd, const char *password);
+ static char *alloc(THD *thd, const char *password, size_t pass_len);
};
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc
index 3981b91a27c..00c09679737 100644
--- a/sql/item_subselect.cc
+++ b/sql/item_subselect.cc
@@ -1314,8 +1314,8 @@ Item_in_subselect::row_value_transformer(JOIN *join)
Item *item_having_part2= 0;
for (uint i= 0; i < cols_num; i++)
{
- DBUG_ASSERT(left_expr->fixed &&
- select_lex->ref_pointer_array[i]->fixed ||
+ DBUG_ASSERT((left_expr->fixed &&
+ select_lex->ref_pointer_array[i]->fixed) ||
(select_lex->ref_pointer_array[i]->type() == REF_ITEM &&
((Item_ref*)(select_lex->ref_pointer_array[i]))->ref_type() ==
Item_ref::OUTER_REF));
@@ -1392,8 +1392,8 @@ Item_in_subselect::row_value_transformer(JOIN *join)
for (uint i= 0; i < cols_num; i++)
{
Item *item, *item_isnull;
- DBUG_ASSERT(left_expr->fixed &&
- select_lex->ref_pointer_array[i]->fixed ||
+ DBUG_ASSERT((left_expr->fixed &&
+ select_lex->ref_pointer_array[i]->fixed) ||
(select_lex->ref_pointer_array[i]->type() == REF_ITEM &&
((Item_ref*)(select_lex->ref_pointer_array[i]))->ref_type() ==
Item_ref::OUTER_REF));
diff --git a/sql/item_sum.cc b/sql/item_sum.cc
index a6d8bb8a52d..38251294053 100644
--- a/sql/item_sum.cc
+++ b/sql/item_sum.cc
@@ -798,8 +798,9 @@ void Item_sum_sum::fix_length_and_dec()
{
/* SUM result can't be longer than length(arg) + length(MAX_ROWS) */
int precision= args[0]->decimal_precision() + DECIMAL_LONGLONG_DIGITS;
- max_length= my_decimal_precision_to_length(precision, decimals,
- unsigned_flag);
+ max_length= my_decimal_precision_to_length_no_truncation(precision,
+ decimals,
+ unsigned_flag);
curr_dec_buff= 0;
hybrid_type= DECIMAL_RESULT;
my_decimal_set_zero(dec_buffs);
@@ -1233,8 +1234,9 @@ void Item_sum_avg::fix_length_and_dec()
{
int precision= args[0]->decimal_precision() + prec_increment;
decimals= min(args[0]->decimals + prec_increment, DECIMAL_MAX_SCALE);
- max_length= my_decimal_precision_to_length(precision, decimals,
- unsigned_flag);
+ max_length= my_decimal_precision_to_length_no_truncation(precision,
+ decimals,
+ unsigned_flag);
f_precision= min(precision+DECIMAL_LONGLONG_DIGITS, DECIMAL_MAX_PRECISION);
f_scale= args[0]->decimals;
dec_bin_size= my_decimal_get_binary_size(f_precision, f_scale);
@@ -1439,8 +1441,9 @@ void Item_sum_variance::fix_length_and_dec()
{
int precision= args[0]->decimal_precision()*2 + prec_increment;
decimals= min(args[0]->decimals + prec_increment, DECIMAL_MAX_SCALE);
- max_length= my_decimal_precision_to_length(precision, decimals,
- unsigned_flag);
+ max_length= my_decimal_precision_to_length_no_truncation(precision,
+ decimals,
+ unsigned_flag);
break;
}
@@ -2640,8 +2643,8 @@ bool Item_sum_count_distinct::setup(THD *thd)
enum enum_field_types f_type= f->type();
tree_key_length+= f->pack_length();
if ((f_type == MYSQL_TYPE_VARCHAR) ||
- !f->binary() && (f_type == MYSQL_TYPE_STRING ||
- f_type == MYSQL_TYPE_VAR_STRING))
+ (!f->binary() && (f_type == MYSQL_TYPE_STRING ||
+ f_type == MYSQL_TYPE_VAR_STRING)))
{
all_binary= FALSE;
break;
@@ -3324,8 +3327,13 @@ bool Item_func_group_concat::add()
TREE_ELEMENT *el= 0; // Only for safety
if (row_eligible && tree)
+ {
el= tree_insert(tree, table->record[0] + table->s->null_bytes, 0,
tree->custom_arg);
+ /* check if there was enough memory to insert the row */
+ if (!el)
+ return 1;
+ }
/*
If the row is not a duplicate (el->count == 1)
we can dump the row here in case of GROUP_CONCAT(DISTINCT...)
diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc
index 8caff22eab9..d79b0b02998 100644
--- a/sql/item_timefunc.cc
+++ b/sql/item_timefunc.cc
@@ -446,7 +446,7 @@ static bool extract_date_time(DATE_TIME_FORMAT *format,
strict_week_number= (*ptr=='V' || *ptr=='v');
tmp= (char*) val + min(val_len, 2);
if ((week_number= (int) my_strtoll10(val, &tmp, &error)) < 0 ||
- strict_week_number && !week_number ||
+ (strict_week_number && !week_number) ||
week_number > 53)
goto err;
val= tmp;
@@ -542,10 +542,10 @@ static bool extract_date_time(DATE_TIME_FORMAT *format,
%V,%v require %X,%x resprectively,
%U,%u should be used with %Y and not %X or %x
*/
- if (strict_week_number &&
+ if ((strict_week_number &&
(strict_week_number_year < 0 ||
- strict_week_number_year_type != sunday_first_n_first_week_non_iso) ||
- !strict_week_number && strict_week_number_year >= 0)
+ strict_week_number_year_type != sunday_first_n_first_week_non_iso)) ||
+ (!strict_week_number && strict_week_number_year >= 0))
goto err;
/* Number of days since year 0 till 1st Jan of this year */
diff --git a/sql/log.cc b/sql/log.cc
index ed2eff6625d..8bb6ba8e9c6 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -153,7 +153,8 @@ private:
class binlog_trx_data {
public:
binlog_trx_data()
- : at_least_one_stmt(0), m_pending(0), before_stmt_pos(MY_OFF_T_UNDEF)
+ : at_least_one_stmt(0), incident(FALSE), m_pending(0),
+ before_stmt_pos(MY_OFF_T_UNDEF)
{
trans_log.end_of_file= max_binlog_cache_size;
}
@@ -184,6 +185,7 @@ public:
delete pending();
set_pending(0);
reinit_io_cache(&trans_log, WRITE_CACHE, pos, 0, 0);
+ trans_log.end_of_file= max_binlog_cache_size;
if (pos < before_stmt_pos)
before_stmt_pos= MY_OFF_T_UNDEF;
@@ -206,6 +208,7 @@ public:
if (!empty())
truncate(0);
before_stmt_pos= MY_OFF_T_UNDEF;
+ incident= FALSE;
trans_log.end_of_file= max_binlog_cache_size;
DBUG_ASSERT(empty());
}
@@ -222,11 +225,22 @@ public:
IO_CACHE trans_log; // The transaction cache
+ void set_incident(void)
+ {
+ incident= TRUE;
+ }
+
+ bool has_incident(void)
+ {
+ return(incident);
+ }
+
/**
Boolean that is true if there is at least one statement in the
transaction cache.
*/
bool at_least_one_stmt;
+ bool incident;
private:
/*
@@ -942,7 +956,7 @@ bool LOGGER::slow_log_print(THD *thd, const char *query, uint query_length,
bool error= FALSE;
Log_event_handler **current_handler;
bool is_command= FALSE;
- char user_host_buff[MAX_USER_HOST_SIZE];
+ char user_host_buff[MAX_USER_HOST_SIZE + 1];
Security_context *sctx= thd->security_ctx;
uint user_host_len= 0;
ulonglong query_utime, lock_utime;
@@ -1008,7 +1022,7 @@ bool LOGGER::general_log_write(THD *thd, enum enum_server_command command,
{
bool error= FALSE;
Log_event_handler **current_handler= general_log_handler_list;
- char user_host_buff[MAX_USER_HOST_SIZE];
+ char user_host_buff[MAX_USER_HOST_SIZE + 1];
Security_context *sctx= thd->security_ctx;
ulong id;
uint user_host_len= 0;
@@ -1391,7 +1405,8 @@ binlog_end_trans(THD *thd, binlog_trx_data *trx_data,
*/
if (end_ev != NULL)
{
- thd->binlog_flush_pending_rows_event(TRUE);
+ if (thd->binlog_flush_pending_rows_event(TRUE))
+ DBUG_RETURN(1);
/*
Doing a commit or a rollback including non-transactional tables,
i.e., ending a transaction where we might write the transaction
@@ -1402,7 +1417,8 @@ binlog_end_trans(THD *thd, binlog_trx_data *trx_data,
were, we would have to ensure that we're not ending a statement
inside a stored function.
*/
- error= mysql_bin_log.write(thd, &trx_data->trans_log, end_ev);
+ error= mysql_bin_log.write(thd, &trx_data->trans_log, end_ev,
+ trx_data->has_incident());
trx_data->reset();
/*
@@ -1428,7 +1444,11 @@ binlog_end_trans(THD *thd, binlog_trx_data *trx_data,
*/
thd->binlog_remove_pending_rows_event(TRUE);
if (all || !(thd->options & (OPTION_BEGIN | OPTION_NOT_AUTOCOMMIT)))
+ {
+ if (trx_data->has_incident())
+ mysql_bin_log.write_incident(thd, TRUE);
trx_data->reset();
+ }
else // ...statement
trx_data->truncate(trx_data->before_stmt_pos);
@@ -1502,8 +1522,7 @@ static int binlog_commit(handlerton *hton, THD *thd, bool all)
YESNO(thd->transaction.stmt.modified_non_trans_table)));
if (!in_transaction || all)
{
- Query_log_event qev(thd, STRING_WITH_LEN("COMMIT"), TRUE, FALSE);
- qev.error_code= 0; // see comment in MYSQL_LOG::write(THD, IO_CACHE)
+ Query_log_event qev(thd, STRING_WITH_LEN("COMMIT"), TRUE, TRUE, 0);
error= binlog_end_trans(thd, trx_data, &qev, all);
goto end;
}
@@ -1545,9 +1564,11 @@ static int binlog_rollback(handlerton *hton, THD *thd, bool all)
YESNO(all),
YESNO(thd->transaction.all.modified_non_trans_table),
YESNO(thd->transaction.stmt.modified_non_trans_table)));
- if (all && thd->transaction.all.modified_non_trans_table ||
- !all && thd->transaction.stmt.modified_non_trans_table ||
- (thd->options & OPTION_KEEP_LOG))
+ if ((all && thd->transaction.all.modified_non_trans_table) ||
+ (!all && thd->transaction.stmt.modified_non_trans_table &&
+ !mysql_bin_log.check_write_error(thd)) ||
+ ((thd->options & OPTION_KEEP_LOG) &&
+ !mysql_bin_log.check_write_error(thd)))
{
/*
We write the transaction cache with a rollback last if we have
@@ -1557,18 +1578,25 @@ static int binlog_rollback(handlerton *hton, THD *thd, bool all)
transactional table in that statement as well, which needs to be
rolled back on the slave.
*/
- Query_log_event qev(thd, STRING_WITH_LEN("ROLLBACK"), TRUE, FALSE);
- qev.error_code= 0; // see comment in MYSQL_LOG::write(THD, IO_CACHE)
+ Query_log_event qev(thd, STRING_WITH_LEN("ROLLBACK"), TRUE, TRUE, 0);
error= binlog_end_trans(thd, trx_data, &qev, all);
}
- else if (all && !thd->transaction.all.modified_non_trans_table ||
- !all && !thd->transaction.stmt.modified_non_trans_table)
+ else
{
/*
- If we have modified only transactional tables, we can truncate
- the transaction cache without writing anything to the binary
- log.
+ We reach this point if either only transactional tables were modified or
+ the effect of a statement that did not get into the binlog needs to be
+ rolled back. In the latter case, if a statement changed non-transactional
+ tables or had the OPTION_KEEP_LOG associated, we write an incident event
+ to the binlog in order to stop slaves and notify users that some changes
+ on the master did not get into the binlog and slaves will be inconsistent.
+ On the other hand, if a statement is transactional, we just safely roll it
+ back.
*/
+ if ((thd->transaction.stmt.modified_non_trans_table ||
+ (thd->options & OPTION_KEEP_LOG)) &&
+ mysql_bin_log.check_write_error(thd))
+ trx_data->set_incident();
error= binlog_end_trans(thd, trx_data, 0, all);
}
if (!all)
@@ -1576,6 +1604,44 @@ static int binlog_rollback(handlerton *hton, THD *thd, bool all)
DBUG_RETURN(error);
}
+void MYSQL_BIN_LOG::set_write_error(THD *thd)
+{
+ DBUG_ENTER("MYSQL_BIN_LOG::set_write_error");
+
+ write_error= 1;
+
+ if (check_write_error(thd))
+ DBUG_VOID_RETURN;
+
+ if (my_errno == EFBIG)
+ my_message(ER_TRANS_CACHE_FULL, ER(ER_TRANS_CACHE_FULL), MYF(MY_WME));
+ else
+ my_error(ER_ERROR_ON_WRITE, MYF(MY_WME), name, errno);
+
+ DBUG_VOID_RETURN;
+}
+
+bool MYSQL_BIN_LOG::check_write_error(THD *thd)
+{
+ DBUG_ENTER("MYSQL_BIN_LOG::check_write_error");
+
+ bool checked= FALSE;
+
+ if (!thd->is_error())
+ DBUG_RETURN(checked);
+
+ switch (thd->main_da.sql_errno())
+ {
+ case ER_TRANS_CACHE_FULL:
+ case ER_ERROR_ON_WRITE:
+ case ER_BINLOG_LOGGING_IMPOSSIBLE:
+ checked= TRUE;
+ break;
+ }
+
+ DBUG_RETURN(checked);
+}
+
/**
@note
How do we handle this (unlikely but legal) case:
@@ -1606,10 +1672,11 @@ static int binlog_savepoint_set(handlerton *hton, THD *thd, void *sv)
binlog_trans_log_savepos(thd, (my_off_t*) sv);
/* Write it to the binary log */
-
+
+ int errcode= query_error_code(thd, thd->killed == THD::NOT_KILLED);
int const error=
thd->binlog_query(THD::STMT_QUERY_TYPE,
- thd->query, thd->query_length, TRUE, FALSE);
+ thd->query, thd->query_length, TRUE, FALSE, errcode);
DBUG_RETURN(error);
}
@@ -1625,9 +1692,10 @@ static int binlog_savepoint_rollback(handlerton *hton, THD *thd, void *sv)
if (unlikely(thd->transaction.all.modified_non_trans_table ||
(thd->options & OPTION_KEEP_LOG)))
{
+ int errcode= query_error_code(thd, thd->killed == THD::NOT_KILLED);
int error=
thd->binlog_query(THD::STMT_QUERY_TYPE,
- thd->query, thd->query_length, TRUE, FALSE);
+ thd->query, thd->query_length, TRUE, FALSE, errcode);
DBUG_RETURN(error);
}
binlog_trans_log_truncate(thd, *(my_off_t*)sv);
@@ -2065,6 +2133,9 @@ bool MYSQL_QUERY_LOG::write(time_t event_time, const char *user_host,
/* Test if someone closed between the is_open test and lock */
if (is_open())
{
+ /* for testing output of timestamp and thread id */
+ DBUG_EXECUTE_IF("reset_log_last_time", last_time= 0;);
+
/* Note that my_b_write() assumes it knows the length for this */
if (event_time != last_time)
{
@@ -2073,7 +2144,7 @@ bool MYSQL_QUERY_LOG::write(time_t event_time, const char *user_host,
localtime_r(&event_time, &start);
time_buff_len= my_snprintf(local_time_buff, MAX_TIME_SIZE,
- "%02d%02d%02d %2d:%02d:%02d",
+ "%02d%02d%02d %2d:%02d:%02d\t",
start.tm_year % 100, start.tm_mon + 1,
start.tm_mday, start.tm_hour,
start.tm_min, start.tm_sec);
@@ -3851,6 +3922,7 @@ MYSQL_BIN_LOG::flush_and_set_pending_rows_event(THD *thd,
if (pending->write(file))
{
pthread_mutex_unlock(&LOCK_log);
+ set_write_error(thd);
DBUG_RETURN(1);
}
@@ -3925,7 +3997,8 @@ bool MYSQL_BIN_LOG::write(Log_event *event_info)
*/
bool const end_stmt=
thd->prelocked_mode && thd->lex->requires_prelocking();
- thd->binlog_flush_pending_rows_event(end_stmt);
+ if (thd->binlog_flush_pending_rows_event(end_stmt))
+ DBUG_RETURN(error);
pthread_mutex_lock(&LOCK_log);
@@ -3976,8 +4049,7 @@ bool MYSQL_BIN_LOG::write(Log_event *event_info)
DBUG_PRINT("info", ("Using trans_log: cache: %d, trans_log_pos: %lu",
event_info->get_cache_stmt(),
(ulong) trans_log_pos));
- if (trans_log_pos == 0)
- thd->binlog_start_trans_and_stmt();
+ thd->binlog_start_trans_and_stmt();
file= trans_log;
}
/*
@@ -4055,7 +4127,8 @@ bool MYSQL_BIN_LOG::write(Log_event *event_info)
Write the SQL command
*/
- if (event_info->write(file))
+ if (event_info->write(file) ||
+ DBUG_EVALUATE_IF("injecting_fault_writing", 1, 0))
goto err;
if (file == &log_file) // we are writing to the real log (disk)
@@ -4069,13 +4142,7 @@ bool MYSQL_BIN_LOG::write(Log_event *event_info)
err:
if (error)
- {
- if (my_errno == EFBIG)
- my_message(ER_TRANS_CACHE_FULL, ER(ER_TRANS_CACHE_FULL), MYF(0));
- else
- my_error(ER_ERROR_ON_WRITE, MYF(0), name, errno);
- write_error=1;
- }
+ set_write_error(thd);
}
if (event_info->flags & LOG_EVENT_UPDATE_TABLE_MAP_VERSION_F)
@@ -4327,6 +4394,58 @@ int MYSQL_BIN_LOG::write_cache(IO_CACHE *cache, bool lock_log, bool sync_log)
return 0; // All OK
}
+/*
+ Helper function to get the error code of the query to be binlogged.
+ */
+int query_error_code(THD *thd, bool not_killed)
+{
+ int error;
+
+ if (not_killed)
+ {
+ error= thd->is_error() ? thd->main_da.sql_errno() : 0;
+
+ /* thd->main_da.sql_errno() might be ER_SERVER_SHUTDOWN or
+ ER_QUERY_INTERRUPTED, So here we need to make sure that error
+ is not set to these errors when specified not_killed by the
+ caller.
+ */
+ if (error == ER_SERVER_SHUTDOWN || error == ER_QUERY_INTERRUPTED)
+ error= 0;
+ }
+ else
+ {
+ /* killed status for DELAYED INSERT thread should never be used */
+ DBUG_ASSERT(!(thd->system_thread & SYSTEM_THREAD_DELAYED_INSERT));
+ error= thd->killed_errno();
+ }
+
+ return error;
+}
+
+bool MYSQL_BIN_LOG::write_incident(THD *thd, bool lock)
+{
+ uint error= 0;
+ DBUG_ENTER("MYSQL_BIN_LOG::write_incident");
+ LEX_STRING const write_error_msg=
+ { C_STRING_WITH_LEN("error writing to the binary log") };
+ Incident incident= INCIDENT_LOST_EVENTS;
+ Incident_log_event ev(thd, incident, write_error_msg);
+ if (lock)
+ pthread_mutex_lock(&LOCK_log);
+ ev.write(&log_file);
+ if (lock)
+ {
+ if (!error && !(error= flush_and_sync()))
+ {
+ signal_update();
+ rotate_and_purge(RP_LOCK_LOG_IS_ALREADY_LOCKED);
+ }
+ pthread_mutex_unlock(&LOCK_log);
+ }
+ DBUG_RETURN(error);
+}
+
/**
Write a cached log entry to the binary log.
- To support transaction over replication, we wrap the transaction
@@ -4339,6 +4458,9 @@ int MYSQL_BIN_LOG::write_cache(IO_CACHE *cache, bool lock_log, bool sync_log)
@param cache The cache to copy to the binlog
@param commit_event The commit event to print after writing the
contents of the cache.
+ @param incident Defines if an incident event should be created to
+ notify that some non-transactional changes did
+ not get into the binlog.
@note
We only come here if there is something in the cache.
@@ -4348,7 +4470,8 @@ int MYSQL_BIN_LOG::write_cache(IO_CACHE *cache, bool lock_log, bool sync_log)
'cache' needs to be reinitialized after this functions returns.
*/
-bool MYSQL_BIN_LOG::write(THD *thd, IO_CACHE *cache, Log_event *commit_event)
+bool MYSQL_BIN_LOG::write(THD *thd, IO_CACHE *cache, Log_event *commit_event,
+ bool incident)
{
DBUG_ENTER("MYSQL_BIN_LOG::write(THD *, IO_CACHE *, Log_event *)");
VOID(pthread_mutex_lock(&LOCK_log));
@@ -4370,19 +4493,8 @@ bool MYSQL_BIN_LOG::write(THD *thd, IO_CACHE *cache, Log_event *commit_event)
transaction is either a BEGIN..COMMIT block or a single
statement in autocommit mode.
*/
- Query_log_event qinfo(thd, STRING_WITH_LEN("BEGIN"), TRUE, FALSE);
- /*
- Imagine this is rollback due to net timeout, after all
- statements of the transaction succeeded. Then we want a
- zero-error code in BEGIN. In other words, if there was a
- really serious error code it's already in the statement's
- events, there is no need to put it also in this internally
- generated event, and as this event is generated late it would
- lead to false alarms.
+ Query_log_event qinfo(thd, STRING_WITH_LEN("BEGIN"), TRUE, TRUE, 0);
- This is safer than thd->clear_error() against kills at shutdown.
- */
- qinfo.error_code= 0;
/*
Now this Query_log_event has artificial log_pos 0. It must be
adjusted to reflect the real position in the log. Not doing it
@@ -4408,6 +4520,10 @@ bool MYSQL_BIN_LOG::write(THD *thd, IO_CACHE *cache, Log_event *commit_event)
if (commit_event && commit_event->write(&log_file))
goto err;
+
+ if (incident && write_incident(thd, FALSE))
+ goto err;
+
if (flush_and_sync())
goto err;
DBUG_EXECUTE_IF("half_binlogged_transaction", abort(););
diff --git a/sql/log.h b/sql/log.h
index d54df8add3b..d306d6f7182 100644
--- a/sql/log.h
+++ b/sql/log.h
@@ -356,9 +356,12 @@ public:
void new_file();
bool write(Log_event* event_info); // binary log write
- bool write(THD *thd, IO_CACHE *cache, Log_event *commit_event);
+ bool write(THD *thd, IO_CACHE *cache, Log_event *commit_event, bool incident);
+ bool write_incident(THD *thd, bool lock);
int write_cache(IO_CACHE *cache, bool lock_log, bool flush_and_sync);
+ void set_write_error(THD *thd);
+ bool check_write_error(THD *thd);
void start_union_events(THD *thd, query_id_t query_id_param);
void stop_union_events(THD *thd);
@@ -581,4 +584,6 @@ enum enum_binlog_format {
};
extern TYPELIB binlog_format_typelib;
+int query_error_code(THD *thd, bool not_killed);
+
#endif /* LOG_H */
diff --git a/sql/log_event.cc b/sql/log_event.cc
index 1a8cb8ee4fa..5f77ab3dcc4 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -369,6 +369,34 @@ int convert_handler_error(int error, THD* thd, TABLE *table)
return (actual_error);
}
+inline bool concurrency_error_code(int error)
+{
+ switch (error)
+ {
+ case ER_LOCK_WAIT_TIMEOUT:
+ case ER_LOCK_DEADLOCK:
+ case ER_XA_RBDEADLOCK:
+ return TRUE;
+ default:
+ return (FALSE);
+ }
+}
+
+inline bool unexpected_error_code(int unexpected_error)
+{
+ switch (unexpected_error)
+ {
+ case ER_NET_READ_ERROR:
+ case ER_NET_ERROR_ON_WRITE:
+ case ER_QUERY_INTERRUPTED:
+ case ER_SERVER_SHUTDOWN:
+ case ER_NEW_ABORTING_CONNECTION:
+ return(TRUE);
+ default:
+ return(FALSE);
+ }
+}
+
/*
pretty_print_str()
*/
@@ -791,8 +819,8 @@ Log_event::do_shall_skip(Relay_log_info *rli)
(ulong) server_id, (ulong) ::server_id,
rli->replicate_same_server_id,
rli->slave_skip_counter));
- if (server_id == ::server_id && !rli->replicate_same_server_id ||
- rli->slave_skip_counter == 1 && rli->is_in_group())
+ if ((server_id == ::server_id && !rli->replicate_same_server_id) ||
+ (rli->slave_skip_counter == 1 && rli->is_in_group()))
return EVENT_SKIP_IGNORE;
else if (rli->slave_skip_counter > 0)
return EVENT_SKIP_COUNT;
@@ -2316,19 +2344,16 @@ Query_log_event::Query_log_event()
query_length - size of the `query_arg' array
using_trans - there is a modified transactional table
suppress_use - suppress the generation of 'USE' statements
- killed_status_arg - an optional with default to THD::KILLED_NO_VALUE
- if the value is different from the default, the arg
- is set to the current thd->killed value.
- A caller might need to masquerade thd->killed with
- THD::NOT_KILLED.
+ errcode - the error code of the query
+
DESCRIPTION
Creates an event for binlogging
- The value for local `killed_status' can be supplied by caller.
+ The value for `errcode' should be supplied by caller.
*/
Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg,
ulong query_length, bool using_trans,
- bool suppress_use,
- THD::killed_state killed_status_arg)
+ bool suppress_use, int errcode)
+
:Log_event(thd_arg,
(thd_arg->thread_specific_used ? LOG_EVENT_THREAD_SPECIFIC_F :
0) |
@@ -2349,22 +2374,7 @@ Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg,
{
time_t end_time;
- if (killed_status_arg == THD::KILLED_NO_VALUE)
- killed_status_arg= thd_arg->killed;
- error_code=
- (killed_status_arg == THD::NOT_KILLED) ?
- (thd_arg->is_error() ? thd_arg->main_da.sql_errno() : 0) :
- ((thd_arg->system_thread & SYSTEM_THREAD_DELAYED_INSERT) ? 0 :
- thd_arg->killed_errno());
-
- /* thd_arg->main_da.sql_errno() might be ER_SERVER_SHUTDOWN or
- ER_QUERY_INTERRUPTED, So here we need to make sure that
- error_code is not set to these errors when specified NOT_KILLED
- by the caller
- */
- if ((killed_status_arg == THD::NOT_KILLED) &&
- (error_code == ER_SERVER_SHUTDOWN || error_code == ER_QUERY_INTERRUPTED))
- error_code= 0;
+ error_code= errcode;
time(&end_time);
exec_time = (ulong) (end_time - thd_arg->start_time);
@@ -2751,7 +2761,8 @@ void Query_log_event::print_query_header(IO_CACHE* file,
if (!(flags & LOG_EVENT_SUPPRESS_USE_F) && db)
{
- if ((different_db= memcmp(print_event_info->db, db, db_len + 1)))
+ different_db= memcmp(print_event_info->db, db, db_len + 1);
+ if (different_db)
memcpy(print_event_info->db, db, db_len + 1);
if (db[0] && different_db)
my_b_printf(file, "use %s%s\n", db, print_event_info->delimiter);
@@ -3008,7 +3019,10 @@ int Query_log_event::do_apply_event(Relay_log_info const *rli,
::do_apply_event(), then the companion SET also have so
we don't need to reset_one_shot_variables().
*/
- if (rpl_filter->db_ok(thd->db))
+ if (!strncmp(query_arg, "BEGIN", q_len_arg) ||
+ !strncmp(query_arg, "COMMIT", q_len_arg) ||
+ !strncmp(query_arg, "ROLLBACK", q_len_arg) ||
+ rpl_filter->db_ok(thd->db))
{
thd->set_time((time_t)when);
thd->query_length= q_len_arg;
@@ -3020,7 +3034,7 @@ int Query_log_event::do_apply_event(Relay_log_info const *rli,
DBUG_PRINT("query",("%s",thd->query));
if (ignored_error_code((expected_error= error_code)) ||
- !check_expected_error(thd,rli,expected_error))
+ !unexpected_error_code(expected_error))
{
if (flags2_inited)
/*
@@ -3152,8 +3166,8 @@ compare_errors:
actual_error= thd->is_error() ? thd->main_da.sql_errno() : 0;
DBUG_PRINT("info",("expected_error: %d sql_errno: %d",
expected_error, actual_error));
- if ((expected_error != actual_error) &&
- expected_error &&
+ if ((expected_error && expected_error != actual_error &&
+ !concurrency_error_code(expected_error)) &&
!ignored_error_code(actual_error) &&
!ignored_error_code(expected_error))
{
@@ -3172,7 +3186,8 @@ Default database: '%s'. Query: '%s'",
/*
If we get the same error code as expected, or they should be ignored.
*/
- else if (expected_error == actual_error ||
+ else if ((expected_error == actual_error &&
+ !concurrency_error_code(expected_error)) ||
ignored_error_code(actual_error))
{
DBUG_PRINT("info",("error ignored"));
@@ -3344,8 +3359,8 @@ void Start_log_event_v3::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
my_b_printf(&cache," at startup");
my_b_printf(&cache, "\n");
if (flags & LOG_EVENT_BINLOG_IN_USE_F)
- my_b_printf(&cache, "# Warning: this binlog was not closed properly. "
- "Most probably mysqld crashed writing it.\n");
+ my_b_printf(&cache, "# Warning: this binlog is either in use or was not "
+ "closed properly.\n");
}
if (!is_artificial_event() && created)
{
@@ -4366,7 +4381,7 @@ void Load_log_event::print(FILE* file_arg, PRINT_EVENT_INFO* print_event_info,
{
if (i)
my_b_printf(&cache, ",");
- my_b_printf(&cache, field);
+ my_b_printf(&cache, "%s", field);
field += field_lens[i] + 1;
}
@@ -6619,9 +6634,9 @@ Execute_load_query_log_event(THD *thd_arg, const char* query_arg,
uint fn_pos_end_arg,
enum_load_dup_handling dup_handling_arg,
bool using_trans, bool suppress_use,
- THD::killed_state killed_err_arg):
+ int errcode):
Query_log_event(thd_arg, query_arg, query_length_arg, using_trans,
- suppress_use, killed_err_arg),
+ suppress_use, errcode),
file_id(thd_arg->file_id), fn_pos_start(fn_pos_start_arg),
fn_pos_end(fn_pos_end_arg), dup_handling(dup_handling_arg)
{
@@ -6694,7 +6709,7 @@ void Execute_load_query_log_event::print(FILE* file,
{
my_b_write(&cache, (uchar*) query, fn_pos_start);
my_b_printf(&cache, " LOCAL INFILE \'");
- my_b_printf(&cache, local_fname);
+ my_b_printf(&cache, "%s", local_fname);
my_b_printf(&cache, "\'");
if (dup_handling == LOAD_DUP_REPLACE)
my_b_printf(&cache, " REPLACE");
@@ -6912,8 +6927,8 @@ Rows_log_event::Rows_log_event(THD *thd_arg, TABLE *tbl_arg, ulong tid,
solution, to be able to terminate a started statement in the
binary log: the extraneous events will be removed in the future.
*/
- DBUG_ASSERT(tbl_arg && tbl_arg->s && tid != ~0UL ||
- !tbl_arg && !cols && tid == ~0UL);
+ DBUG_ASSERT((tbl_arg && tbl_arg->s && tid != ~0UL) ||
+ (!tbl_arg && !cols && tid == ~0UL));
if (thd_arg->options & OPTION_NO_FOREIGN_KEY_CHECKS)
set_flags(NO_FOREIGN_KEY_CHECKS_F);
@@ -7105,7 +7120,7 @@ int Rows_log_event::do_add_row_data(uchar *row_data, size_t length)
#endif
DBUG_ASSERT(m_rows_buf <= m_rows_cur);
- DBUG_ASSERT(!m_rows_buf || m_rows_end && m_rows_buf < m_rows_end);
+ DBUG_ASSERT(!m_rows_buf || (m_rows_end && m_rows_buf < m_rows_end));
DBUG_ASSERT(m_rows_cur <= m_rows_end);
/* The cast will always work since m_rows_cur <= m_rows_end */
@@ -7862,10 +7877,11 @@ Table_map_log_event::Table_map_log_event(THD *thd, TABLE *tbl, ulong tid,
/*
Now set the size of the data to the size of the field metadata array
- plus one or two bytes for number of elements in the field metadata array.
+ plus one or three bytes (see pack.c:net_store_length) for number of
+ elements in the field metadata array.
*/
if (m_field_metadata_size > 255)
- m_data_size+= m_field_metadata_size + 2;
+ m_data_size+= m_field_metadata_size + 3;
else
m_data_size+= m_field_metadata_size + 1;
@@ -9312,7 +9328,7 @@ Incident_log_event::print(FILE *file,
Write_on_release_cache cache(&print_event_info->head_cache, file);
print_header(&cache, print_event_info, FALSE);
- my_b_printf(&cache, "\n# Incident: %s", description());
+ my_b_printf(&cache, "\n# Incident: %s\nRELOAD DATABASE; # Shall generate syntax error\n", description());
}
#endif
diff --git a/sql/log_event.h b/sql/log_event.h
index bda53da8ab0..8202dddcc76 100644
--- a/sql/log_event.h
+++ b/sql/log_event.h
@@ -676,6 +676,7 @@ typedef struct st_print_event_info
#ifdef MYSQL_CLIENT
uint verbose;
table_mapping m_table_map;
+ table_mapping m_table_map_ignored;
#endif
/*
@@ -1623,8 +1624,7 @@ public:
#ifndef MYSQL_CLIENT
Query_log_event(THD* thd_arg, const char* query_arg, ulong query_length,
- bool using_trans, bool suppress_use,
- THD::killed_state killed_err_arg= THD::KILLED_NO_VALUE);
+ bool using_trans, bool suppress_use, int error);
const char* get_db() { return db; }
#ifdef HAVE_REPLICATION
void pack_info(Protocol* protocol);
@@ -2875,8 +2875,7 @@ public:
uint fn_pos_end_arg,
enum_load_dup_handling dup_handling_arg,
bool using_trans, bool suppress_use,
- THD::killed_state
- killed_err_arg= THD::KILLED_NO_VALUE);
+ int errcode);
#ifdef HAVE_REPLICATION
void pack_info(Protocol* protocol);
#endif /* HAVE_REPLICATION */
diff --git a/sql/my_decimal.h b/sql/my_decimal.h
index 0e79f70ab4e..21669e82c44 100644
--- a/sql/my_decimal.h
+++ b/sql/my_decimal.h
@@ -183,6 +183,19 @@ inline uint my_decimal_length_to_precision(uint length, uint scale,
(unsigned_flag || !length ? 0:1));
}
+inline uint32 my_decimal_precision_to_length_no_truncation(uint precision,
+ uint8 scale,
+ bool unsigned_flag)
+{
+ /*
+ When precision is 0 it means that original length was also 0. Thus
+ unsigned_flag is ignored in this case.
+ */
+ DBUG_ASSERT(precision || !scale);
+ return (uint32)(precision + (scale > 0 ? 1 : 0) +
+ (unsigned_flag || !precision ? 0 : 1));
+}
+
inline uint32 my_decimal_precision_to_length(uint precision, uint8 scale,
bool unsigned_flag)
{
@@ -192,8 +205,8 @@ inline uint32 my_decimal_precision_to_length(uint precision, uint8 scale,
*/
DBUG_ASSERT(precision || !scale);
set_if_smaller(precision, DECIMAL_MAX_PRECISION);
- return (uint32)(precision + (scale>0 ? 1:0) +
- (unsigned_flag || !precision ? 0:1));
+ return my_decimal_precision_to_length_no_truncation(precision, scale,
+ unsigned_flag);
}
inline
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index 949fabe3928..8a7501ba108 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -82,9 +82,9 @@ extern query_id_t global_query_id;
inline query_id_t next_query_id() { return global_query_id++; }
/* useful constants */
-extern const key_map key_map_empty;
-extern key_map key_map_full; /* Should be threaded as const */
-extern const char *primary_key_name;
+extern MYSQL_PLUGIN_IMPORT const key_map key_map_empty;
+extern MYSQL_PLUGIN_IMPORT key_map key_map_full; /* Should be threaded as const */
+extern MYSQL_PLUGIN_IMPORT const char *primary_key_name;
#include "mysql_com.h"
#include
@@ -123,8 +123,10 @@ char* query_table_status(THD *thd,const char *db,const char *table_name);
"in MySQL %s. Please use %s instead.", (Old), (Ver), (New)); \
} while(0)
-extern CHARSET_INFO *system_charset_info, *files_charset_info ;
-extern CHARSET_INFO *national_charset_info, *table_alias_charset;
+extern MYSQL_PLUGIN_IMPORT CHARSET_INFO *system_charset_info;
+extern MYSQL_PLUGIN_IMPORT CHARSET_INFO *files_charset_info ;
+extern MYSQL_PLUGIN_IMPORT CHARSET_INFO *national_charset_info;
+extern MYSQL_PLUGIN_IMPORT CHARSET_INFO *table_alias_charset;
enum Derivation
@@ -690,14 +692,19 @@ typedef struct st_sql_list {
}
} SQL_LIST;
-
+#if defined(MYSQL_DYNAMIC_PLUGIN) && defined(_WIN32)
+extern "C" THD *_current_thd_noinline();
+#define _current_thd() _current_thd_noinline()
+#else
extern pthread_key(THD*, THR_THD);
inline THD *_current_thd(void)
{
return my_pthread_getspecific_ptr(THD*,THR_THD);
}
+#endif
#define current_thd _current_thd()
+
/**
The meat of thd_proc_info(THD*, char*), a macro that packs the last
three calling-info parameters.
@@ -1415,14 +1422,14 @@ enum enum_schema_tables get_schema_table_idx(ST_SCHEMA_TABLE *schema_table);
/* sql_prepare.cc */
-void mysql_stmt_prepare(THD *thd, const char *packet, uint packet_length);
-void mysql_stmt_execute(THD *thd, char *packet, uint packet_length);
-void mysql_stmt_close(THD *thd, char *packet);
+void mysqld_stmt_prepare(THD *thd, const char *packet, uint packet_length);
+void mysqld_stmt_execute(THD *thd, char *packet, uint packet_length);
+void mysqld_stmt_close(THD *thd, char *packet);
void mysql_sql_stmt_prepare(THD *thd);
void mysql_sql_stmt_execute(THD *thd);
void mysql_sql_stmt_close(THD *thd);
-void mysql_stmt_fetch(THD *thd, char *packet, uint packet_length);
-void mysql_stmt_reset(THD *thd, char *packet);
+void mysqld_stmt_fetch(THD *thd, char *packet, uint packet_length);
+void mysqld_stmt_reset(THD *thd, char *packet);
void mysql_stmt_get_longdata(THD *thd, char *pos, ulong packet_length);
void reinit_stmt_before_use(THD *thd, LEX *lex);
@@ -1884,8 +1891,12 @@ extern time_t server_start_time, flush_status_time;
#endif /* MYSQL_SERVER */
#if defined MYSQL_SERVER || defined INNODB_COMPATIBILITY_HOOKS
extern uint mysql_data_home_len;
-extern char *mysql_data_home,server_version[SERVER_VERSION_LENGTH],
- mysql_real_data_home[], mysql_unpacked_real_data_home[];
+
+extern MYSQL_PLUGIN_IMPORT char *mysql_data_home;
+extern char server_version[SERVER_VERSION_LENGTH];
+extern MYSQL_PLUGIN_IMPORT char mysql_real_data_home[];
+extern char mysql_unpacked_real_data_home[];
+
extern CHARSET_INFO *character_set_filesystem;
#endif /* MYSQL_SERVER || INNODB_COMPATIBILITY_HOOKS */
#ifdef MYSQL_SERVER
@@ -1893,10 +1904,13 @@ extern char *opt_mysql_tmpdir, mysql_charsets_dir[],
def_ft_boolean_syntax[sizeof(ft_boolean_syntax)];
extern int mysql_unpacked_real_data_home_len;
#define mysql_tmpdir (my_tmpdir(&mysql_tmpdir_list))
-extern MY_TMPDIR mysql_tmpdir_list;
+extern MYSQL_PLUGIN_IMPORT MY_TMPDIR mysql_tmpdir_list;
extern const LEX_STRING command_name[];
-extern const char *first_keyword, *my_localhost, *delayed_user, *binary_keyword;
-extern const char **errmesg; /* Error messages */
+
+extern const char *first_keyword, *delayed_user, *binary_keyword;
+extern MYSQL_PLUGIN_IMPORT const char *my_localhost;
+extern MYSQL_PLUGIN_IMPORT const char **errmesg; /* Error messages */
+
extern const char *myisam_recover_options_str;
extern const char *in_left_expr_name, *in_additional_cond, *in_having_cond;
extern const char * const TRG_EXT;
@@ -1910,8 +1924,8 @@ extern Le_creator le_creator;
extern char language[FN_REFLEN];
#endif /* MYSQL_SERVER */
#if defined MYSQL_SERVER || defined INNODB_COMPATIBILITY_HOOKS
-extern char reg_ext[FN_EXTLEN];
-extern uint reg_ext_length;
+extern MYSQL_PLUGIN_IMPORT char reg_ext[FN_EXTLEN];
+extern MYSQL_PLUGIN_IMPORT uint reg_ext_length;
#endif /* MYSQL_SERVER || INNODB_COMPATIBILITY_HOOKS */
#ifdef MYSQL_SERVER
extern char glob_hostname[FN_REFLEN], mysql_home[FN_REFLEN];
@@ -1931,20 +1945,22 @@ extern ulong slave_open_temp_tables;
extern ulong query_cache_size, query_cache_min_res_unit;
extern ulong slow_launch_threads, slow_launch_time;
extern ulong table_cache_size, table_def_size;
-extern ulong max_connections,max_connect_errors, connect_timeout;
+extern MYSQL_PLUGIN_IMPORT ulong max_connections;
+extern ulong max_connect_errors, connect_timeout;
extern ulong slave_net_timeout, slave_trans_retries;
extern uint max_user_connections;
extern ulong what_to_log,flush_time;
extern ulong query_buff_size;
extern ulong max_prepared_stmt_count, prepared_stmt_count;
-extern ulong binlog_cache_size, max_binlog_cache_size, open_files_limit;
+extern ulong binlog_cache_size, open_files_limit;
+extern ulonglong max_binlog_cache_size;
extern ulong max_binlog_size, max_relay_log_size;
extern ulong opt_binlog_rows_event_max_size;
extern ulong rpl_recovery_rank, thread_cache_size, thread_pool_size;
extern ulong back_log;
#endif /* MYSQL_SERVER */
#if defined MYSQL_SERVER || defined INNODB_COMPATIBILITY_HOOKS
-extern ulong specialflag;
+extern ulong MYSQL_PLUGIN_IMPORT specialflag;
#endif /* MYSQL_SERVER || INNODB_COMPATIBILITY_HOOKS */
#ifdef MYSQL_SERVER
extern ulong current_pid;
@@ -1957,7 +1973,7 @@ extern uint protocol_version, mysqld_port, dropping_tables;
extern uint delay_key_write_options;
#endif /* MYSQL_SERVER */
#if defined MYSQL_SERVER || defined INNODB_COMPATIBILITY_HOOKS
-extern uint lower_case_table_names;
+extern MYSQL_PLUGIN_IMPORT uint lower_case_table_names;
#endif /* MYSQL_SERVER || INNODB_COMPATIBILITY_HOOKS */
#ifdef MYSQL_SERVER
extern bool opt_endinfo, using_udf_functions;
@@ -1965,7 +1981,7 @@ extern my_bool locked_in_memory;
extern bool opt_using_transactions;
#endif /* MYSQL_SERVER */
#if defined MYSQL_SERVER || defined INNODB_COMPATIBILITY_HOOKS
-extern bool mysqld_embedded;
+extern MYSQL_PLUGIN_IMPORT bool mysqld_embedded;
#endif /* MYSQL_SERVER || INNODB_COMPATIBILITY_HOOKS */
#ifdef MYSQL_SERVER
extern bool opt_large_files, server_id_supplied;
@@ -2003,7 +2019,7 @@ extern uint opt_large_page_size;
extern char *opt_logname, *opt_slow_logname;
extern const char *log_output_str;
-extern MYSQL_BIN_LOG mysql_bin_log;
+extern MYSQL_PLUGIN_IMPORT MYSQL_BIN_LOG mysql_bin_log;
extern LOGGER logger;
extern TABLE_LIST general_log, slow_log;
extern FILE *bootstrap_file;
@@ -2011,13 +2027,14 @@ extern int bootstrap_error;
extern FILE *stderror_file;
extern pthread_key(MEM_ROOT**,THR_MALLOC);
extern pthread_mutex_t LOCK_mysql_create_db,LOCK_Acl,LOCK_open, LOCK_lock_db,
- LOCK_thread_count,LOCK_mapped_file,LOCK_user_locks, LOCK_status,
+ LOCK_mapped_file,LOCK_user_locks, LOCK_status,
LOCK_error_log, LOCK_delayed_insert, LOCK_uuid_generator,
LOCK_delayed_status, LOCK_delayed_create, LOCK_crypt, LOCK_timezone,
LOCK_slave_list, LOCK_active_mi, LOCK_manager, LOCK_global_read_lock,
LOCK_global_system_variables, LOCK_user_conn,
LOCK_prepared_stmt_count,
LOCK_bytes_sent, LOCK_bytes_received, LOCK_connection_count;
+extern MYSQL_PLUGIN_IMPORT pthread_mutex_t LOCK_thread_count;
#ifdef HAVE_OPENSSL
extern pthread_mutex_t LOCK_des_key_file;
#endif
@@ -2037,7 +2054,7 @@ extern const String my_null_string;
extern SHOW_VAR status_vars[];
#endif /* MYSQL_SERVER */
#if defined MYSQL_SERVER || defined INNODB_COMPATIBILITY_HOOKS
-extern struct system_variables global_system_variables;
+extern MYSQL_PLUGIN_IMPORT struct system_variables global_system_variables;
#endif /* MYSQL_SERVER || INNODB_COMPATIBILITY_HOOKS */
#ifdef MYSQL_SERVER
extern struct system_variables max_system_variables;
@@ -2255,6 +2272,16 @@ char *fn_rext(char *name);
#if defined MYSQL_SERVER || defined INNODB_COMPATIBILITY_HOOKS
uint strconvert(CHARSET_INFO *from_cs, const char *from,
CHARSET_INFO *to_cs, char *to, uint to_length, uint *errors);
+/* depends on errmsg.txt Database `db`, Table `t` ... */
+#define EXPLAIN_FILENAME_MAX_EXTRA_LENGTH 63
+enum enum_explain_filename_mode
+{
+ EXPLAIN_ALL_VERBOSE= 0,
+ EXPLAIN_PARTITIONS_VERBOSE,
+ EXPLAIN_PARTITIONS_AS_COMMENT
+};
+uint explain_filename(const char *from, char *to, uint to_length,
+ enum_explain_filename_mode explain_mode);
uint filename_to_tablename(const char *from, char *to, uint to_length);
uint tablename_to_filename(const char *from, char *to, uint to_length);
uint check_n_cut_mysql50_prefix(const char *from, char *to, uint to_length);
@@ -2313,6 +2340,12 @@ extern void turn_parser_debug_on();
SQL_CRYPT *get_crypt_for_frm(void);
#endif
+/* password.c */
+extern "C" void my_make_scrambled_password_323(char *to, const char *password,
+ size_t pass_len);
+extern "C" void my_make_scrambled_password(char *to, const char *password,
+ size_t pass_len);
+
#include "sql_view.h"
/* Some inline functions for more speed */
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 140b7d1490d..83101f6ed0e 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -519,7 +519,8 @@ ulong slave_net_timeout, slave_trans_retries;
ulong slave_exec_mode_options;
const char *slave_exec_mode_str= "STRICT";
ulong thread_cache_size=0, thread_pool_size= 0;
-ulong binlog_cache_size=0, max_binlog_cache_size=0;
+ulong binlog_cache_size=0;
+ulonglong max_binlog_cache_size=0;
ulong query_cache_size=0;
ulong refresh_version; /* Increments on each reload */
query_id_t global_query_id;
@@ -994,6 +995,7 @@ static void close_connections(void)
}
(void) pthread_mutex_unlock(&LOCK_thread_count);
+ close_active_mi();
DBUG_PRINT("quit",("close_connections thread"));
DBUG_VOID_RETURN;
}
@@ -1675,7 +1677,6 @@ static void network_init(void)
opt_enable_named_pipe)
{
- pipe_name[sizeof(pipe_name)-1]= 0; /* Safety if too long string */
strxnmov(pipe_name, sizeof(pipe_name)-1, "\\\\.\\pipe\\",
mysqld_unix_port, NullS);
bzero((char*) &saPipeSecurity, sizeof(saPipeSecurity));
@@ -4870,8 +4871,9 @@ void handle_connection_in_main_thread(THD *thd)
safe_mutex_assert_owner(&LOCK_thread_count);
thread_cache_size=0; // Safety
threads.append(thd);
- (void) pthread_mutex_unlock(&LOCK_thread_count);
- handle_one_connection((void*) thd);
+ pthread_mutex_unlock(&LOCK_thread_count);
+ thd->start_utime= my_micro_time();
+ handle_one_connection(thd);
}
@@ -4896,7 +4898,7 @@ void create_thread_to_handle_connection(THD *thd)
thread_created++;
threads.append(thd);
DBUG_PRINT("info",(("creating thread %lu"), thd->thread_id));
- thd->connect_utime= thd->start_utime= my_micro_time();
+ thd->prior_thr_create_utime= thd->start_utime= my_micro_time();
if ((error=pthread_create(&thd->real_id,&connection_attrib,
handle_one_connection,
(void*) thd)))
@@ -6679,7 +6681,7 @@ log and this option does nothing anymore.",
{"max_binlog_cache_size", OPT_MAX_BINLOG_CACHE_SIZE,
"Can be used to restrict the total size used to cache a multi-transaction query.",
(uchar**) &max_binlog_cache_size, (uchar**) &max_binlog_cache_size, 0,
- GET_ULONG, REQUIRED_ARG, ULONG_MAX, IO_SIZE, ULONG_MAX, 0, IO_SIZE, 0},
+ GET_ULL, REQUIRED_ARG, ULONG_MAX, IO_SIZE, ULONGLONG_MAX, 0, IO_SIZE, 0},
{"max_binlog_size", OPT_MAX_BINLOG_SIZE,
"Binary log will be rotated automatically when the size exceeds this \
value. Will also apply to relay logs if max_relay_log_size is 0. \
@@ -6862,7 +6864,7 @@ The minimum value for this variable is 4096.",
(uchar**) &opt_plugin_dir_ptr, (uchar**) &opt_plugin_dir_ptr, 0,
GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"plugin-load", OPT_PLUGIN_LOAD,
- "Optional colon-separated list of plugins to load, where each plugin is "
+ "Optional semicolon-separated list of plugins to load, where each plugin is "
"identified as name=library, where name is the plugin name and library "
"is the plugin library in plugin_dir.",
(uchar**) &opt_plugin_load, (uchar**) &opt_plugin_load, 0,
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index 147874611ce..e3aef02637f 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -3760,8 +3760,8 @@ TABLE_READ_PLAN *get_best_disjunct_quick(PARAM *param, SEL_IMERGE *imerge,
DBUG_PRINT("info", ("index_merge scans cost %g", imerge_cost));
if (imerge_too_expensive || (imerge_cost > read_time) ||
- (non_cpk_scan_records+cpk_scan_records >= param->table->file->stats.records) &&
- read_time != DBL_MAX)
+ ((non_cpk_scan_records+cpk_scan_records >= param->table->file->stats.records) &&
+ read_time != DBL_MAX))
{
/*
Bail out if it is obvious that both index_merge and ROR-union will be
@@ -7950,7 +7950,7 @@ QUICK_RANGE_SELECT *get_quick_select_for_ref(THD *thd, TABLE *table,
goto err;
quick->records= records;
- if (cp_buffer_from_ref(thd, table, ref) && thd->is_fatal_error ||
+ if ((cp_buffer_from_ref(thd, table, ref) && thd->is_fatal_error) ||
!(range= new(alloc) QUICK_RANGE()))
goto err; // out of memory
@@ -8556,7 +8556,7 @@ int QUICK_RANGE_SELECT::get_next_prefix(uint prefix_length,
result= file->read_range_first(last_range->min_keypart_map ? &start_key : 0,
last_range->max_keypart_map ? &end_key : 0,
test(last_range->flag & EQ_RANGE),
- sorted);
+ TRUE);
if (last_range->flag == (UNIQUE_RANGE | EQ_RANGE))
last_range= 0; // Stop searching
@@ -8826,7 +8826,7 @@ int QUICK_RANGE_SELECT::cmp_prev(QUICK_RANGE *range_arg)
cmp= key_cmp(key_part_info, range_arg->min_key,
range_arg->min_length);
- if (cmp > 0 || cmp == 0 && !(range_arg->flag & NEAR_MIN))
+ if (cmp > 0 || (cmp == 0 && !(range_arg->flag & NEAR_MIN)))
return 0;
return 1; // outside of range
}
@@ -10886,8 +10886,14 @@ int QUICK_GROUP_MIN_MAX_SELECT::next_min_in_range()
/* Compare the found key with max_key. */
int cmp_res= key_cmp(index_info->key_part, max_key,
real_prefix_len + min_max_arg_len);
- if (!((cur_range->flag & NEAR_MAX) && (cmp_res == -1) ||
- (cmp_res <= 0)))
+ /*
+ The key is outside of the range if:
+ the interval is open and the key is equal to the maximum boundry
+ or
+ the key is greater than the maximum
+ */
+ if (((cur_range->flag & NEAR_MAX) && cmp_res == 0) ||
+ cmp_res > 0)
{
result= HA_ERR_KEY_NOT_FOUND;
continue;
@@ -11004,8 +11010,14 @@ int QUICK_GROUP_MIN_MAX_SELECT::next_max_in_range()
/* Compare the found key with min_key. */
int cmp_res= key_cmp(index_info->key_part, min_key,
real_prefix_len + min_max_arg_len);
- if (!((cur_range->flag & NEAR_MIN) && (cmp_res == 1) ||
- (cmp_res >= 0)))
+ /*
+ The key is outside of the range if:
+ the interval is open and the key is equal to the minimum boundry
+ or
+ the key is less than the minimum
+ */
+ if (((cur_range->flag & NEAR_MIN) && cmp_res == 0) ||
+ cmp_res < 0)
continue;
}
/* If we got to this point, the current key qualifies as MAX. */
diff --git a/sql/opt_sum.cc b/sql/opt_sum.cc
index 3ccc1e5cf41..8e7265ba1ad 100644
--- a/sql/opt_sum.cc
+++ b/sql/opt_sum.cc
@@ -744,8 +744,8 @@ static bool matching_cond(bool max_fl, TABLE_REF *ref, KEY *keyinfo,
}
else if (eq_type)
{
- if (!is_null && !cond->val_int() ||
- is_null && !test(part->field->is_null()))
+ if ((!is_null && !cond->val_int()) ||
+ (is_null && !test(part->field->is_null())))
return 0; // Impossible test
}
else if (is_field_part)
diff --git a/sql/parse_file.cc b/sql/parse_file.cc
index f2dbeba1bbf..3d65fa1de31 100644
--- a/sql/parse_file.cc
+++ b/sql/parse_file.cc
@@ -231,7 +231,7 @@ sql_create_definition_file(const LEX_STRING *dir, const LEX_STRING *file_name,
including dir name, file name itself, and an extension,
and with unpack_filename() executed over it.
*/
- path_end= strxnmov(path, FN_REFLEN, file_name->str, NullS) - path;
+ path_end= strxnmov(path, sizeof(path) - 1, file_name->str, NullS) - path;
}
// temporary file name
@@ -314,7 +314,7 @@ my_bool rename_in_schema_file(THD *thd,
const char *schema, const char *old_name,
const char *new_db, const char *new_name)
{
- char old_path[FN_REFLEN], new_path[FN_REFLEN], arc_path[FN_REFLEN];
+ char old_path[FN_REFLEN + 1], new_path[FN_REFLEN + 1], arc_path[FN_REFLEN + 1];
build_table_filename(old_path, sizeof(old_path) - 1,
schema, old_name, reg_ext, 0);
diff --git a/sql/password.c b/sql/password.c
index 1ff67888ea4..9204c660b77 100644
--- a/sql/password.c
+++ b/sql/password.c
@@ -137,16 +137,35 @@ void hash_password(ulong *result, const char *password, uint password_len)
Create password to be stored in user database from raw string
Used for pre-4.1 password handling
SYNOPSIS
- make_scrambled_password_323()
+ my_make_scrambled_password_323()
to OUT store scrambled password here
password IN user-supplied password
+ pass_len IN length of password string
+*/
+
+void my_make_scrambled_password_323(char *to, const char *password,
+ size_t pass_len)
+{
+ ulong hash_res[2];
+ hash_password(hash_res, password, (uint) pass_len);
+ sprintf(to, "%08lx%08lx", hash_res[0], hash_res[1]);
+}
+
+
+/*
+ Wrapper around my_make_scrambled_password_323() to maintain client lib ABI
+ compatibility.
+ In server code usage of my_make_scrambled_password_323() is preferred to
+ avoid strlen().
+ SYNOPSIS
+ make_scrambled_password_323()
+ to OUT store scrambled password here
+ password IN NULL-terminated string with user-supplied password
*/
void make_scrambled_password_323(char *to, const char *password)
{
- ulong hash_res[2];
- hash_password(hash_res, password, (uint) strlen(password));
- sprintf(to, "%08lx%08lx", hash_res[0], hash_res[1]);
+ my_make_scrambled_password_323(to, password, strlen(password));
}
@@ -383,20 +402,21 @@ my_crypt(char *to, const uchar *s1, const uchar *s2, uint len)
The result of this function is used as return value from PASSWORD() and
is stored in the database.
SYNOPSIS
- make_scrambled_password()
+ my_make_scrambled_password()
buf OUT buffer of size 2*SHA1_HASH_SIZE + 2 to store hex string
- password IN NULL-terminated password string
+ password IN password string
+ pass_len IN length of password string
*/
-void
-make_scrambled_password(char *to, const char *password)
+void my_make_scrambled_password(char *to, const char *password,
+ size_t pass_len)
{
SHA1_CONTEXT sha1_context;
uint8 hash_stage2[SHA1_HASH_SIZE];
mysql_sha1_reset(&sha1_context);
/* stage 1: hash password */
- mysql_sha1_input(&sha1_context, (uint8 *) password, (uint) strlen(password));
+ mysql_sha1_input(&sha1_context, (uint8 *) password, (uint) pass_len);
mysql_sha1_result(&sha1_context, (uint8 *) to);
/* stage 2: hash stage1 output */
mysql_sha1_reset(&sha1_context);
@@ -409,6 +429,23 @@ make_scrambled_password(char *to, const char *password)
}
+/*
+ Wrapper around my_make_scrambled_password() to maintain client lib ABI
+ compatibility.
+ In server code usage of my_make_scrambled_password() is preferred to
+ avoid strlen().
+ SYNOPSIS
+ make_scrambled_password()
+ buf OUT buffer of size 2*SHA1_HASH_SIZE + 2 to store hex string
+ password IN NULL-terminated password string
+*/
+
+void make_scrambled_password(char *to, const char *password)
+{
+ my_make_scrambled_password(to, password, strlen(password));
+}
+
+
/*
Produce an obscure octet sequence from password and random
string, recieved from the server. This sequence corresponds to the
diff --git a/sql/rpl_reporting.cc b/sql/rpl_reporting.cc
index 28f257790c7..a09140de3c4 100644
--- a/sql/rpl_reporting.cc
+++ b/sql/rpl_reporting.cc
@@ -13,6 +13,7 @@ Slave_reporting_capability::report(loglevel level, int err_code,
va_list args;
va_start(args, msg);
+ pthread_mutex_lock(&err_lock);
switch (level)
{
case ERROR_LEVEL:
@@ -38,6 +39,7 @@ Slave_reporting_capability::report(loglevel level, int err_code,
my_vsnprintf(pbuff, pbuffsize, msg, args);
+ pthread_mutex_unlock(&err_lock);
va_end(args);
/* If the msg string ends with '.', do not add a ',' it would be ugly */
@@ -46,3 +48,8 @@ Slave_reporting_capability::report(loglevel level, int err_code,
(pbuff[0] && *(strend(pbuff)-1) == '.') ? "" : ",",
err_code);
}
+
+Slave_reporting_capability::~Slave_reporting_capability()
+{
+ pthread_mutex_destroy(&err_lock);
+}
diff --git a/sql/rpl_reporting.h b/sql/rpl_reporting.h
index 2e3fa3cea83..ce33407e516 100644
--- a/sql/rpl_reporting.h
+++ b/sql/rpl_reporting.h
@@ -16,6 +16,8 @@
class Slave_reporting_capability
{
public:
+ /** lock used to synchronize m_last_error on 'SHOW SLAVE STATUS' **/
+ mutable pthread_mutex_t err_lock;
/**
Constructor.
@@ -24,6 +26,7 @@ public:
Slave_reporting_capability(char const *thread_name)
: m_thread_name(thread_name)
{
+ pthread_mutex_init(&err_lock, MY_MUTEX_INIT_FAST);
}
/**
@@ -44,7 +47,9 @@ public:
STATUS.
*/
void clear_error() {
+ pthread_mutex_lock(&err_lock);
m_last_error.clear();
+ pthread_mutex_unlock(&err_lock);
}
/**
@@ -72,6 +77,7 @@ public:
Error const& last_error() const { return m_last_error; }
+ virtual ~Slave_reporting_capability()= 0;
private:
/**
Last error produced by the I/O or SQL thread respectively.
@@ -79,6 +85,10 @@ private:
mutable Error m_last_error;
char const *const m_thread_name;
+
+ // not implemented
+ Slave_reporting_capability(const Slave_reporting_capability& rhs);
+ Slave_reporting_capability& operator=(const Slave_reporting_capability& rhs);
};
#endif // RPL_REPORTING_H
diff --git a/sql/rpl_rli.cc b/sql/rpl_rli.cc
index e93417374fe..18fbae9bb9d 100644
--- a/sql/rpl_rli.cc
+++ b/sql/rpl_rli.cc
@@ -104,9 +104,16 @@ int init_relay_log_info(Relay_log_info* rli,
rli->tables_to_lock= 0;
rli->tables_to_lock_count= 0;
- fn_format(rli->slave_patternload_file, PREFIX_SQL_LOAD, slave_load_tmpdir, "",
- MY_PACK_FILENAME | MY_UNPACK_FILENAME |
- MY_RETURN_REAL_PATH);
+ char pattern[FN_REFLEN];
+ if (fn_format(pattern, PREFIX_SQL_LOAD, slave_load_tmpdir, "",
+ MY_SAFE_PATH | MY_RETURN_REAL_PATH) == NullS)
+ {
+ pthread_mutex_unlock(&rli->data_lock);
+ sql_print_error("Unable to use slave's temporary directory %s",
+ slave_load_tmpdir);
+ DBUG_RETURN(1);
+ }
+ unpack_filename(rli->slave_patternload_file, pattern);
rli->slave_patternload_file_size= strlen(rli->slave_patternload_file);
/*
@@ -940,6 +947,7 @@ int purge_relay_logs(Relay_log_info* rli, THD *thd, bool just_reset,
if (count_relay_log_space(rli))
{
*errmsg= "Error counting relay log space";
+ error=1;
goto err;
}
if (!just_reset)
diff --git a/sql/set_var.cc b/sql/set_var.cc
index bc8c91342e6..0b89333ce03 100644
--- a/sql/set_var.cc
+++ b/sql/set_var.cc
@@ -359,8 +359,8 @@ static sys_var_const sys_lower_case_table_names(&vars,
&lower_case_table_names);
static sys_var_thd_ulong_session_readonly sys_max_allowed_packet(&vars, "max_allowed_packet",
&SV::max_allowed_packet);
-static sys_var_long_ptr sys_max_binlog_cache_size(&vars, "max_binlog_cache_size",
- &max_binlog_cache_size);
+static sys_var_ulonglong_ptr sys_max_binlog_cache_size(&vars, "max_binlog_cache_size",
+ &max_binlog_cache_size);
static sys_var_long_ptr sys_max_binlog_size(&vars, "max_binlog_size",
&max_binlog_size,
fix_max_binlog_size);
diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt
index f9b66990e93..42bca02984d 100644
--- a/sql/share/errmsg.txt
+++ b/sql/share/errmsg.txt
@@ -6076,7 +6076,7 @@ ER_SLAVE_INCIDENT
ER_NO_PARTITION_FOR_GIVEN_VALUE_SILENT
eng "Table has no partition for some existing values"
ER_BINLOG_UNSAFE_STATEMENT
- eng "Statement is not safe to log in statement format."
+ eng "Statement may not be safe to log in statement format."
swe "Detta är inte säkert att logga i statement-format."
ER_SLAVE_FATAL_ERROR
eng "Fatal error: %s"
@@ -6177,3 +6177,27 @@ ER_TOO_LONG_TABLE_COMMENT
ER_TOO_LONG_FIELD_COMMENT
eng "Comment for field '%-.64s' is too long (max = %lu)"
por "Comentário para o campo '%-.64s' é longo demais (max = %lu)"
+
+ER_FUNC_INEXISTENT_NAME_COLLISION 42000
+ eng "FUNCTION %s does not exist. Check the 'Function Name Parsing and Resolution' section in the Reference Manual"
+
+# When updating these, please update EXPLAIN_FILENAME_MAX_EXTRA_LENGTH in
+# mysql_priv.h with the new maximal additional length for explain_filename.
+ER_DATABASE_NAME
+ eng "Database `%s`"
+ swe "Databas `%s`"
+ER_TABLE_NAME
+ eng "Table `%s`"
+ swe "Tabell `%s`"
+ER_PARTITION_NAME
+ eng "Partition `%s`"
+ swe "Partition `%s`"
+ER_SUBPARTITION_NAME
+ eng "Subpartition `%s`"
+ swe "Subpartition `%s`"
+ER_TEMPORARY_NAME
+ eng "Temporary"
+ swe "Temporär"
+ER_RENAMED_NAME
+ eng "Renamed"
+ swe "Namnändrad"
diff --git a/sql/slave.cc b/sql/slave.cc
index 81c18c5e04b..81be7064f89 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -389,6 +389,13 @@ void init_slave_skip_errors(const char* arg)
DBUG_VOID_RETURN;
}
+static void set_thd_in_use_temporary_tables(Relay_log_info *rli)
+{
+ TABLE *table;
+
+ for (table= rli->save_temporary_tables ; table ; table= table->next)
+ table->in_use= rli->sql_thd;
+}
int terminate_slave_threads(Master_info* mi,int thread_mask,bool skip_lock)
{
@@ -661,7 +668,7 @@ static int end_slave_on_walk(Master_info* mi, uchar* /*unused*/)
/*
- Free all resources used by slave
+ Release slave threads at time of executing shutdown.
SYNOPSIS
end_slave()
@@ -687,14 +694,31 @@ void end_slave()
once multi-master code is ready.
*/
terminate_slave_threads(active_mi,SLAVE_FORCE_ALL);
- end_master_info(active_mi);
- delete active_mi;
- active_mi= 0;
}
pthread_mutex_unlock(&LOCK_active_mi);
DBUG_VOID_RETURN;
}
+/**
+ Free all resources used by slave threads at time of executing shutdown.
+ The routine must be called after all possible users of @c active_mi
+ have left.
+
+ SYNOPSIS
+ close_active_mi()
+
+*/
+void close_active_mi()
+{
+ pthread_mutex_lock(&LOCK_active_mi);
+ if (active_mi)
+ {
+ end_master_info(active_mi);
+ delete active_mi;
+ active_mi= 0;
+ }
+ pthread_mutex_unlock(&LOCK_active_mi);
+}
static bool io_slave_killed(THD* thd, Master_info* mi)
{
@@ -803,7 +827,7 @@ int init_strvar_from_file(char *var, int max_size, IO_CACHE *f,
up to and including newline.
*/
int c;
- while (((c=my_b_get(f)) != '\n' && c != my_b_EOF));
+ while (((c=my_b_get(f)) != '\n' && c != my_b_EOF)) ;
}
DBUG_RETURN(0);
}
@@ -1486,6 +1510,8 @@ bool show_master_info(THD* thd, Master_info* mi)
pthread_mutex_lock(&mi->data_lock);
pthread_mutex_lock(&mi->rli.data_lock);
+ pthread_mutex_lock(&mi->err_lock);
+ pthread_mutex_lock(&mi->rli.err_lock);
protocol->store(mi->host, &my_charset_bin);
protocol->store(mi->user, &my_charset_bin);
protocol->store((uint32) mi->port);
@@ -1585,6 +1611,8 @@ bool show_master_info(THD* thd, Master_info* mi)
// Last_SQL_Error
protocol->store(mi->rli.last_error().message, &my_charset_bin);
+ pthread_mutex_unlock(&mi->rli.err_lock);
+ pthread_mutex_unlock(&mi->err_lock);
pthread_mutex_unlock(&mi->rli.data_lock);
pthread_mutex_unlock(&mi->data_lock);
@@ -1856,25 +1884,6 @@ static ulong read_event(MYSQL* mysql, Master_info *mi, bool* suppress_warnings)
DBUG_RETURN(len - 1);
}
-
-int check_expected_error(THD* thd, Relay_log_info const *rli,
- int expected_error)
-{
- DBUG_ENTER("check_expected_error");
-
- switch (expected_error) {
- case ER_NET_READ_ERROR:
- case ER_NET_ERROR_ON_WRITE:
- case ER_QUERY_INTERRUPTED:
- case ER_SERVER_SHUTDOWN:
- case ER_NEW_ABORTING_CONNECTION:
- DBUG_RETURN(1);
- default:
- DBUG_RETURN(0);
- }
-}
-
-
/*
Check if the current error is of temporary nature of not.
Some errors are temporary in nature, such as
@@ -2228,7 +2237,7 @@ static int exec_relay_log_event(THD* thd, Relay_log_info* rli)
"the slave_transaction_retries variable.",
slave_trans_retries);
}
- else if (exec_res && !temp_err ||
+ else if ((exec_res && !temp_err) ||
(opt_using_transactions &&
rli->group_relay_log_pos == rli->event_relay_log_pos))
{
@@ -2390,6 +2399,7 @@ pthread_handler_t handle_slave_io(void *arg)
pthread_detach_this_thread();
thd->thread_stack= (char*) &thd; // remember where our stack is
+ mi->clear_error();
if (init_slave_thread(thd, SLAVE_THD_IO))
{
pthread_cond_broadcast(&mi->start_cond);
@@ -2504,6 +2514,7 @@ requesting master dump") ||
goto connected;
});
+ DBUG_ASSERT(mi->last_error().number == 0);
while (!io_slave_killed(thd,mi))
{
ulong event_len;
@@ -2668,13 +2679,20 @@ err:
LOAD DATA INFILE.
*/
static
-int check_temp_dir(char* tmp_dir, char *tmp_file)
+int check_temp_dir(char* tmp_file)
{
int fd;
MY_DIR *dirp;
+ char tmp_dir[FN_REFLEN];
+ size_t tmp_dir_size;
DBUG_ENTER("check_temp_dir");
+ /*
+ Get the directory from the temporary file.
+ */
+ dirname_part(tmp_dir, tmp_file, &tmp_dir_size);
+
/*
Check if the directory exists.
*/
@@ -2750,6 +2768,7 @@ pthread_handler_t handle_slave_sql(void *arg)
}
thd->init_for_queries();
thd->temporary_tables = rli->save_temporary_tables; // restore temp tables
+ set_thd_in_use_temporary_tables(rli); // (re)set sql_thd in use for saved temp tables
pthread_mutex_lock(&LOCK_thread_count);
threads.append(thd);
pthread_mutex_unlock(&LOCK_thread_count);
@@ -2830,7 +2849,7 @@ log '%s' at position %s, relay log '%s' position: %s", RPL_LOG_NAME,
llstr(rli->group_master_log_pos,llbuff),rli->group_relay_log_name,
llstr(rli->group_relay_log_pos,llbuff1));
- if (check_temp_dir(slave_load_tmpdir, rli->slave_patternload_file))
+ if (check_temp_dir(rli->slave_patternload_file))
{
rli->report(ERROR_LEVEL, thd->main_da.sql_errno(),
"Unable to use slave's temporary directory %s - %s",
@@ -2996,6 +3015,7 @@ the slave SQL thread with \"SLAVE START\". We stopped at log \
DBUG_ASSERT(rli->sql_thd == thd);
THD_CHECK_SENTRY(thd);
rli->sql_thd= 0;
+ set_thd_in_use_temporary_tables(rli); // (re)set sql_thd in use for saved temp tables
pthread_mutex_lock(&LOCK_thread_count);
THD_CHECK_SENTRY(thd);
delete thd;
@@ -3694,6 +3714,7 @@ static int connect_to_master(THD* thd, MYSQL* mysql, Master_info* mi,
if (!slave_was_killed)
{
+ mi->clear_error(); // clear possible left over reconnect error
if (reconnect)
{
if (!suppress_warnings && global_system_variables.log_warnings)
diff --git a/sql/slave.h b/sql/slave.h
index abd63315e62..a44a7eed83e 100644
--- a/sql/slave.h
+++ b/sql/slave.h
@@ -171,10 +171,10 @@ bool rpl_master_has_bug(const Relay_log_info *rli, uint bug_id, bool report,
bool rpl_master_erroneous_autoinc(THD* thd);
const char *print_slave_db_safe(const char *db);
-int check_expected_error(THD* thd, Relay_log_info const *rli, int error_code);
void skip_load_data_infile(NET* net);
-void end_slave(); /* clean up */
+void end_slave(); /* release slave threads */
+void close_active_mi(); /* clean up slave threads data */
void clear_until_condition(Relay_log_info* rli);
void clear_slave_error(Relay_log_info* rli);
void end_relay_log_info(Relay_log_info* rli);
diff --git a/sql/sp.cc b/sql/sp.cc
index 8c8149d0afc..29e228f5e45 100644
--- a/sql/sp.cc
+++ b/sql/sp.cc
@@ -941,7 +941,7 @@ sp_create_routine(THD *thd, int type, sp_head *sp)
/* Such a statement can always go directly to binlog, no trans cache */
thd->binlog_query(THD::MYSQL_QUERY_TYPE,
log_query.c_ptr(), log_query.length(),
- FALSE, FALSE, THD::NOT_KILLED);
+ FALSE, FALSE, 0);
thd->variables.sql_mode= 0;
}
@@ -1308,13 +1308,20 @@ sp_find_routine(THD *thd, int type, sp_name *name, sp_cache **cp,
/**
This is used by sql_acl.cc:mysql_routine_grant() and is used to find
the routines in 'routines'.
+
+ @param thd Thread handler
+ @param routines List of needles in the hay stack
+ @param any Any of the needles are good enough
+
+ @return
+ @retval FALSE Found.
+ @retval TRUE Not found
*/
-int
-sp_exist_routines(THD *thd, TABLE_LIST *routines, bool any, bool no_error)
+bool
+sp_exist_routines(THD *thd, TABLE_LIST *routines, bool any)
{
TABLE_LIST *routine;
- bool result= 0;
bool sp_object_found;
DBUG_ENTER("sp_exists_routine");
for (routine= routines; routine; routine= routine->next_global)
@@ -1336,21 +1343,16 @@ sp_exist_routines(THD *thd, TABLE_LIST *routines, bool any, bool no_error)
if (sp_object_found)
{
if (any)
- DBUG_RETURN(1);
- result= 1;
+ break;
}
else if (!any)
{
- if (!no_error)
- {
- my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "FUNCTION or PROCEDURE",
- routine->table_name);
- DBUG_RETURN(-1);
- }
- DBUG_RETURN(0);
+ my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "FUNCTION or PROCEDURE",
+ routine->table_name);
+ DBUG_RETURN(TRUE);
}
}
- DBUG_RETURN(result);
+ DBUG_RETURN(FALSE);
}
diff --git a/sql/sp.h b/sql/sp.h
index 75088ea0b83..75c6856f64b 100644
--- a/sql/sp.h
+++ b/sql/sp.h
@@ -39,8 +39,8 @@ sp_head *
sp_find_routine(THD *thd, int type, sp_name *name,
sp_cache **cp, bool cache_only);
-int
-sp_exist_routines(THD *thd, TABLE_LIST *procs, bool any, bool no_error);
+bool
+sp_exist_routines(THD *thd, TABLE_LIST *procs, bool any);
int
sp_routine_exists_in_table(THD *thd, int type, sp_name *name);
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index d6984bf5ad0..b7ad8c5c906 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -1780,8 +1780,9 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount,
thd->options= binlog_save_options;
if (thd->binlog_evt_union.unioned_events)
{
+ int errcode = query_error_code(thd, thd->killed == THD::NOT_KILLED);
Query_log_event qinfo(thd, binlog_buf.ptr(), binlog_buf.length(),
- thd->binlog_evt_union.unioned_events_trans, FALSE);
+ thd->binlog_evt_union.unioned_events_trans, FALSE, errcode);
if (mysql_bin_log.write(&qinfo) &&
thd->binlog_evt_union.unioned_events_trans)
{
diff --git a/sql/spatial.h b/sql/spatial.h
index dbf5da6665b..86c2ed8c197 100644
--- a/sql/spatial.h
+++ b/sql/spatial.h
@@ -116,12 +116,12 @@ struct MBR
int touches(const MBR *mbr)
{
/* The following should be safe, even if we compare doubles */
- return ((((mbr->xmin == xmax) || (mbr->xmax == xmin)) &&
- (((mbr->ymin >= ymin) && (mbr->ymin <= ymax)) ||
- ((mbr->ymax >= ymin) && (mbr->ymax <= ymax)))) ||
- (((mbr->ymin == ymax) || (mbr->ymax == ymin)) &&
- (((mbr->xmin >= xmin) && (mbr->xmin <= xmax)) ||
- ((mbr->xmax >= xmin) && (mbr->xmax <= xmax)))));
+ return ((mbr->xmin == xmax || mbr->xmax == xmin) &&
+ ((mbr->ymin >= ymin && mbr->ymin <= ymax) ||
+ (mbr->ymax >= ymin && mbr->ymax <= ymax))) ||
+ ((mbr->ymin == ymax || mbr->ymax == ymin) &&
+ ((mbr->xmin >= xmin && mbr->xmin <= xmax) ||
+ (mbr->xmax >= xmin && mbr->xmax <= xmax)));
}
int within(const MBR *mbr)
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index b1dbb7031ce..ab18a2d1d04 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -936,6 +936,7 @@ int acl_getroot(THD *thd, USER_RESOURCES *mqh,
#ifdef HAVE_OPENSSL
Vio *vio=thd->net.vio;
SSL *ssl= (SSL*) vio->ssl_arg;
+ X509 *cert;
#endif
/*
@@ -964,8 +965,11 @@ int acl_getroot(THD *thd, USER_RESOURCES *mqh,
*/
if (vio_type(vio) == VIO_TYPE_SSL &&
SSL_get_verify_result(ssl) == X509_V_OK &&
- SSL_get_peer_certificate(ssl))
+ (cert= SSL_get_peer_certificate(ssl)))
+ {
user_access= acl_user->access;
+ X509_free(cert);
+ }
break;
case SSL_TYPE_SPECIFIED: /* Client should have specified attrib */
/*
@@ -974,7 +978,6 @@ int acl_getroot(THD *thd, USER_RESOURCES *mqh,
If cipher name is specified, we compare it to actual cipher in
use.
*/
- X509 *cert;
if (vio_type(vio) != VIO_TYPE_SSL ||
SSL_get_verify_result(ssl) != X509_V_OK)
break;
@@ -1014,6 +1017,7 @@ int acl_getroot(THD *thd, USER_RESOURCES *mqh,
sql_print_information("X509 issuer mismatch: should be '%s' "
"but is '%s'", acl_user->x509_issuer, ptr);
free(ptr);
+ X509_free(cert);
user_access=NO_ACCESS;
break;
}
@@ -1033,12 +1037,15 @@ int acl_getroot(THD *thd, USER_RESOURCES *mqh,
sql_print_information("X509 subject mismatch: should be '%s' but is '%s'",
acl_user->x509_subject, ptr);
free(ptr);
+ X509_free(cert);
user_access=NO_ACCESS;
break;
}
user_access= acl_user->access;
free(ptr);
}
+ /* Deallocate the X509 certificate. */
+ X509_free(cert);
break;
#else /* HAVE_OPENSSL */
default:
@@ -1185,12 +1192,12 @@ static void acl_update_user(const char *user, const char *host,
for (uint i=0 ; i < acl_users.elements ; i++)
{
ACL_USER *acl_user=dynamic_element(&acl_users,i,ACL_USER*);
- if (!acl_user->user && !user[0] ||
- acl_user->user && !strcmp(user,acl_user->user))
+ if ((!acl_user->user && !user[0]) ||
+ (acl_user->user && !strcmp(user,acl_user->user)))
{
- if (!acl_user->host.hostname && !host[0] ||
- acl_user->host.hostname &&
- !my_strcasecmp(system_charset_info, host, acl_user->host.hostname))
+ if ((!acl_user->host.hostname && !host[0]) ||
+ (acl_user->host.hostname &&
+ !my_strcasecmp(system_charset_info, host, acl_user->host.hostname)))
{
acl_user->access=privileges;
if (mqh->specified_limits & USER_RESOURCES::QUERIES_PER_HOUR)
@@ -1268,16 +1275,16 @@ static void acl_update_db(const char *user, const char *host, const char *db,
for (uint i=0 ; i < acl_dbs.elements ; i++)
{
ACL_DB *acl_db=dynamic_element(&acl_dbs,i,ACL_DB*);
- if (!acl_db->user && !user[0] ||
- acl_db->user &&
- !strcmp(user,acl_db->user))
+ if ((!acl_db->user && !user[0]) ||
+ (acl_db->user &&
+ !strcmp(user,acl_db->user)))
{
- if (!acl_db->host.hostname && !host[0] ||
- acl_db->host.hostname &&
- !strcmp(host, acl_db->host.hostname))
+ if ((!acl_db->host.hostname && !host[0]) ||
+ (acl_db->host.hostname &&
+ !strcmp(host, acl_db->host.hostname)))
{
- if (!acl_db->db && !db[0] ||
- acl_db->db && !strcmp(db,acl_db->db))
+ if ((!acl_db->db && !db[0]) ||
+ (acl_db->db && !strcmp(db,acl_db->db)))
{
if (privileges)
acl_db->access=privileges;
@@ -1486,8 +1493,8 @@ bool acl_check_host(const char *host, const char *ip)
return 0;
VOID(pthread_mutex_lock(&acl_cache->lock));
- if (host && hash_search(&acl_check_hosts,(uchar*) host,strlen(host)) ||
- ip && hash_search(&acl_check_hosts,(uchar*) ip, strlen(ip)))
+ if ((host && hash_search(&acl_check_hosts,(uchar*) host,strlen(host))) ||
+ (ip && hash_search(&acl_check_hosts,(uchar*) ip, strlen(ip))))
{
VOID(pthread_mutex_unlock(&acl_cache->lock));
return 0; // Found host
@@ -1648,7 +1655,7 @@ bool change_password(THD *thd, const char *host, const char *user,
new_password));
thd->clear_error();
thd->binlog_query(THD::MYSQL_QUERY_TYPE, buff, query_length,
- FALSE, FALSE, THD::NOT_KILLED);
+ FALSE, FALSE, 0);
}
end:
close_thread_tables(thd);
@@ -1704,8 +1711,8 @@ find_acl_user(const char *host, const char *user, my_bool exact)
host,
acl_user->host.hostname ? acl_user->host.hostname :
""));
- if (!acl_user->user && !user[0] ||
- acl_user->user && !strcmp(user,acl_user->user))
+ if ((!acl_user->user && !user[0]) ||
+ (acl_user->user && !strcmp(user,acl_user->user)))
{
if (exact ? !my_strcasecmp(system_charset_info, host,
acl_user->host.hostname ?
@@ -2988,8 +2995,8 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list,
{
if (!(rights & CREATE_ACL))
{
- char buf[FN_REFLEN];
- build_table_filename(buf, sizeof(buf), table_list->db,
+ char buf[FN_REFLEN + 1];
+ build_table_filename(buf, sizeof(buf) - 1, table_list->db,
table_list->table_name, reg_ext, 0);
fn_format(buf, buf, "", "", MY_UNPACK_FILENAME | MY_RESOLVE_SYMLINKS |
MY_RETURN_REAL_PATH | MY_APPEND_EXT);
@@ -3191,26 +3198,24 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list,
}
-/*
+/**
Store routine level grants in the privilege tables
- SYNOPSIS
- mysql_routine_grant()
- thd Thread handle
- table_list List of routines to give grant
- is_proc true indicates routine list are procedures
- user_list List of users to give grant
- rights Table level grant
- revoke_grant Set to 1 if this is a REVOKE command
+ @param thd Thread handle
+ @param table_list List of routines to give grant
+ @param is_proc Is this a list of procedures?
+ @param user_list List of users to give grant
+ @param rights Table level grant
+ @param revoke_grant Is this is a REVOKE command?
- RETURN
- 0 ok
- 1 error
+ @return
+ @retval FALSE Success.
+ @retval TRUE An error occurred.
*/
bool mysql_routine_grant(THD *thd, TABLE_LIST *table_list, bool is_proc,
List &user_list, ulong rights,
- bool revoke_grant, bool no_error)
+ bool revoke_grant, bool write_to_binlog)
{
List_iterator str_list (user_list);
LEX_USER *Str, *tmp_Str;
@@ -3221,22 +3226,20 @@ bool mysql_routine_grant(THD *thd, TABLE_LIST *table_list, bool is_proc,
if (!initialized)
{
- if (!no_error)
- my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0),
- "--skip-grant-tables");
+ my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0),
+ "--skip-grant-tables");
DBUG_RETURN(TRUE);
}
if (rights & ~PROC_ACLS)
{
- if (!no_error)
- my_message(ER_ILLEGAL_GRANT_FOR_TABLE, ER(ER_ILLEGAL_GRANT_FOR_TABLE),
- MYF(0));
+ my_message(ER_ILLEGAL_GRANT_FOR_TABLE, ER(ER_ILLEGAL_GRANT_FOR_TABLE),
+ MYF(0));
DBUG_RETURN(TRUE);
}
if (!revoke_grant)
{
- if (sp_exist_routines(thd, table_list, is_proc, no_error)<0)
+ if (sp_exist_routines(thd, table_list, is_proc))
DBUG_RETURN(TRUE);
}
@@ -3317,9 +3320,8 @@ bool mysql_routine_grant(THD *thd, TABLE_LIST *table_list, bool is_proc,
{
if (revoke_grant)
{
- if (!no_error)
- my_error(ER_NONEXISTING_PROC_GRANT, MYF(0),
- Str->user.str, Str->host.str, table_name);
+ my_error(ER_NONEXISTING_PROC_GRANT, MYF(0),
+ Str->user.str, Str->host.str, table_name);
result= TRUE;
continue;
}
@@ -3344,16 +3346,14 @@ bool mysql_routine_grant(THD *thd, TABLE_LIST *table_list, bool is_proc,
}
thd->mem_root= old_root;
pthread_mutex_unlock(&acl_cache->lock);
- if (!result && !no_error)
+
+ if (write_to_binlog)
{
write_bin_log(thd, TRUE, thd->query, thd->query_length);
}
rw_unlock(&LOCK_grant);
- if (!result && !no_error)
- my_ok(thd);
-
/* Tables are automatically closed */
DBUG_RETURN(result);
}
@@ -5319,16 +5319,13 @@ static int handle_grant_struct(uint struct_no, bool drop,
uint elements;
const char *user;
const char *host;
- ACL_USER *acl_user;
- ACL_DB *acl_db;
- GRANT_NAME *grant_name;
+ ACL_USER *acl_user= NULL;
+ ACL_DB *acl_db= NULL;
+ GRANT_NAME *grant_name= NULL;
DBUG_ENTER("handle_grant_struct");
DBUG_PRINT("info",("scan struct: %u search: '%s'@'%s'",
struct_no, user_from->user.str, user_from->host.str));
- LINT_INIT(acl_user);
- LINT_INIT(acl_db);
- LINT_INIT(grant_name);
LINT_INIT(user);
LINT_INIT(host);
@@ -5696,6 +5693,7 @@ bool mysql_drop_user(THD *thd, List &list)
List_iterator user_list(list);
TABLE_LIST tables[GRANT_TABLES];
bool some_users_deleted= FALSE;
+ ulong old_sql_mode= thd->variables.sql_mode;
DBUG_ENTER("mysql_drop_user");
/*
@@ -5709,6 +5707,8 @@ bool mysql_drop_user(THD *thd, List &list)
if ((result= open_grant_tables(thd, tables)))
DBUG_RETURN(result != 1);
+ thd->variables.sql_mode&= ~MODE_PAD_CHAR_TO_FULL_LENGTH;
+
rw_wrlock(&LOCK_grant);
VOID(pthread_mutex_lock(&acl_cache->lock));
@@ -5741,6 +5741,7 @@ bool mysql_drop_user(THD *thd, List &list)
rw_unlock(&LOCK_grant);
close_thread_tables(thd);
+ thd->variables.sql_mode= old_sql_mode;
DBUG_RETURN(result);
}
@@ -6150,21 +6151,20 @@ bool sp_revoke_privileges(THD *thd, const char *sp_db, const char *sp_name,
}
-/*
+/**
Grant EXECUTE,ALTER privilege for a stored procedure
- SYNOPSIS
- sp_grant_privileges()
- thd The current thread.
- db DB of the stored procedure
- name Name of the stored procedure
+ @param thd The current thread.
+ @param sp_db
+ @param sp_name
+ @param is_proc
- RETURN
- 0 OK.
- < 0 Error. Error message not yet sent.
+ @return
+ @retval FALSE Success
+ @retval TRUE An error occured. Error message not yet sent.
*/
-int sp_grant_privileges(THD *thd, const char *sp_db, const char *sp_name,
+bool sp_grant_privileges(THD *thd, const char *sp_db, const char *sp_name,
bool is_proc)
{
Security_context *sctx= thd->security_ctx;
@@ -6174,6 +6174,7 @@ int sp_grant_privileges(THD *thd, const char *sp_db, const char *sp_name,
bool result;
ACL_USER *au;
char passwd_buff[SCRAMBLED_PASSWORD_CHAR_LENGTH+1];
+ Dummy_error_handler error_handler;
DBUG_ENTER("sp_grant_privileges");
if (!(combo=(LEX_USER*) thd->alloc(sizeof(st_lex_user))))
@@ -6224,8 +6225,11 @@ int sp_grant_privileges(THD *thd, const char *sp_db, const char *sp_name,
}
else
{
- my_error(ER_PASSWD_LENGTH, MYF(0), SCRAMBLED_PASSWORD_CHAR_LENGTH);
- return -1;
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_PASSWD_LENGTH,
+ ER(ER_PASSWD_LENGTH),
+ SCRAMBLED_PASSWORD_CHAR_LENGTH);
+ return TRUE;
}
combo->password.str= passwd_buff;
}
@@ -6239,10 +6243,17 @@ int sp_grant_privileges(THD *thd, const char *sp_db, const char *sp_name,
DBUG_RETURN(TRUE);
thd->lex->ssl_type= SSL_TYPE_NOT_SPECIFIED;
+ thd->lex->ssl_cipher= thd->lex->x509_subject= thd->lex->x509_issuer= 0;
bzero((char*) &thd->lex->mqh, sizeof(thd->lex->mqh));
+ /*
+ Only care about whether the operation failed or succeeded
+ as all errors will be handled later.
+ */
+ thd->push_internal_handler(&error_handler);
result= mysql_routine_grant(thd, tables, is_proc, user_list,
- DEFAULT_CREATE_PROC_ACLS, 0, 1);
+ DEFAULT_CREATE_PROC_ACLS, FALSE, FALSE);
+ thd->pop_internal_handler();
DBUG_RETURN(result);
}
diff --git a/sql/sql_acl.h b/sql/sql_acl.h
index 9ae17a4bf02..a8090fba2e7 100644
--- a/sql/sql_acl.h
+++ b/sql/sql_acl.h
@@ -233,7 +233,7 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table, List &user_list,
bool revoke);
bool mysql_routine_grant(THD *thd, TABLE_LIST *table, bool is_proc,
List &user_list, ulong rights,
- bool revoke, bool no_error);
+ bool revoke, bool write_to_binlog);
my_bool grant_init();
void grant_free(void);
my_bool grant_reload(THD *thd);
@@ -264,7 +264,7 @@ void fill_effective_table_privileges(THD *thd, GRANT_INFO *grant,
const char *db, const char *table);
bool sp_revoke_privileges(THD *thd, const char *sp_db, const char *sp_name,
bool is_proc);
-int sp_grant_privileges(THD *thd, const char *sp_db, const char *sp_name,
+bool sp_grant_privileges(THD *thd, const char *sp_db, const char *sp_name,
bool is_proc);
bool check_routine_level_acl(THD *thd, const char *db, const char *name,
bool is_proc);
diff --git a/sql/sql_analyse.cc b/sql/sql_analyse.cc
index 9ca6e0a0a2b..d273b3319ee 100644
--- a/sql/sql_analyse.cc
+++ b/sql/sql_analyse.cc
@@ -246,7 +246,7 @@ bool test_if_number(NUM_INFO *info, const char *str, uint str_len)
}
DBUG_RETURN(0);
}
- for (str++; *(end - 1) == '0'; end--); // jump over zeros at the end
+ for (str++; *(end - 1) == '0'; end--) ; // jump over zeros at the end
if (str == end) // number was something like '123.000'
{
char *endpos= (char*) str;
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 0dc29f7e3c2..88e1620b152 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -473,13 +473,14 @@ static TABLE_SHARE
@todo Rework alternative ways to deal with ER_NO_SUCH TABLE.
*/
- if (share || thd->is_error() && thd->main_da.sql_errno() != ER_NO_SUCH_TABLE)
+ if (share || (thd->is_error() && thd->main_da.sql_errno() != ER_NO_SUCH_TABLE))
DBUG_RETURN(share);
/* Table didn't exist. Check if some engine can provide it */
- if ((tmp= ha_create_table_from_engine(thd, table_list->db,
- table_list->table_name)) < 0)
+ tmp= ha_create_table_from_engine(thd, table_list->db,
+ table_list->table_name);
+ if (tmp < 0)
{
/*
No such table in any engine.
@@ -1431,11 +1432,10 @@ static inline uint tmpkeyval(THD *thd, TABLE *table)
void close_temporary_tables(THD *thd)
{
TABLE *table;
- TABLE *next;
+ TABLE *next= NULL;
TABLE *prev_table;
/* Assume thd->options has OPTION_QUOTE_SHOW_CREATE */
bool was_quote_show= TRUE;
- LINT_INIT(next);
if (!thd->temporary_tables)
return;
@@ -1541,7 +1541,7 @@ void close_temporary_tables(THD *thd)
thd->variables.character_set_client= system_charset_info;
Query_log_event qinfo(thd, s_query.ptr(),
s_query.length() - 1 /* to remove trailing ',' */,
- 0, FALSE, THD::NOT_KILLED);
+ 0, FALSE, 0);
thd->variables.character_set_client= cs_save;
mysql_bin_log.write(&qinfo);
thd->variables.pseudo_thread_id= save_pseudo_thread_id;
@@ -2432,7 +2432,7 @@ bool lock_table_name_if_not_cached(THD *thd, const char *db,
bool check_if_table_exists(THD *thd, TABLE_LIST *table, bool *exists)
{
- char path[FN_REFLEN];
+ char path[FN_REFLEN + 1];
int rc;
DBUG_ENTER("check_if_table_exists");
@@ -2617,8 +2617,8 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
distance > 0 - we have lock mode higher then we require
distance == 0 - we have lock mode exactly which we need
*/
- if (best_distance < 0 && distance > best_distance ||
- distance >= 0 && distance < best_distance)
+ if ((best_distance < 0 && distance > best_distance) ||
+ (distance >= 0 && distance < best_distance))
{
best_distance= distance;
best_table= table;
@@ -2649,7 +2649,7 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
real fix will be made after definition cache will be made)
*/
{
- char path[FN_REFLEN];
+ char path[FN_REFLEN + 1];
enum legacy_db_type not_used;
build_table_filename(path, sizeof(path) - 1,
table_list->db, table_list->table_name, reg_ext, 0);
@@ -2963,6 +2963,7 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
table->insert_values= 0;
table->fulltext_searched= 0;
table->file->ft_handler= 0;
+ table->reginfo.impossible_range= 0;
/* Catch wrong handling of the auto_increment_field_not_null. */
DBUG_ASSERT(!table->auto_increment_field_not_null);
table->auto_increment_field_not_null= FALSE;
@@ -4015,9 +4016,10 @@ retry:
/* this DELETE FROM is needed even with row-based binlogging */
end = strxmov(strmov(query, "DELETE FROM `"),
share->db.str,"`.`",share->table_name.str,"`", NullS);
+ int errcode= query_error_code(thd, TRUE);
thd->binlog_query(THD::STMT_QUERY_TYPE,
query, (ulong)(end-query),
- FALSE, FALSE, THD::NOT_KILLED);
+ FALSE, FALSE, errcode);
my_free(query, MYF(0));
}
else
@@ -5585,6 +5587,13 @@ static void update_field_dependencies(THD *thd, Field *field, TABLE *table)
other_bitmap= table->read_set;
}
+ /*
+ The test-and-set mechanism in the bitmap is not reliable during
+ multi-UPDATE statements under MARK_COLUMNS_READ mode
+ (thd->mark_used_columns == MARK_COLUMNS_READ), as this bitmap contains
+ only those columns that are used in the SET clause. I.e they are being
+ set here. See multi_update::prepare()
+ */
if (bitmap_fast_test_and_set(current_bitmap, field->field_index))
{
if (thd->mark_used_columns == MARK_COLUMNS_WRITE)
@@ -6332,7 +6341,7 @@ find_field_in_tables(THD *thd, Item_ident *item,
(report_error == REPORT_ALL_ERRORS ||
report_error == REPORT_EXCEPT_NON_UNIQUE))
{
- char buff[NAME_LEN*2+1];
+ char buff[NAME_LEN*2 + 2];
if (db && db[0])
{
strxnmov(buff,sizeof(buff)-1,db,".",table_name,NullS);
@@ -6405,8 +6414,7 @@ find_item_in_list(Item *find, List- &items, uint *counter,
(and not an item that happens to have a name).
*/
bool is_ref_by_name= 0;
- uint unaliased_counter;
- LINT_INIT(unaliased_counter); // Dependent on found_unaliased
+ uint unaliased_counter= 0;
*resolution= NOT_RESOLVED;
@@ -7431,7 +7439,7 @@ bool setup_fields(THD *thd, Item **ref_pointer_array,
thd->lex->current_select->cur_pos_in_select_list= 0;
while ((item= it++))
{
- if (!item->fixed && item->fix_fields(thd, it.ref()) ||
+ if ((!item->fixed && item->fix_fields(thd, it.ref())) ||
(item= *(it.ref()))->check_cols(1))
{
thd->lex->current_select->is_item_list_lookup= save_is_item_list_lookup;
@@ -7745,8 +7753,8 @@ insert_fields(THD *thd, Name_resolution_context *context, const char *db_name,
DBUG_ASSERT(tables->is_leaf_for_name_resolution());
- if (table_name && my_strcasecmp(table_alias_charset, table_name,
- tables->alias) ||
+ if ((table_name && my_strcasecmp(table_alias_charset, table_name,
+ tables->alias)) ||
(db_name && strcmp(tables->db,db_name)))
continue;
@@ -7777,8 +7785,8 @@ insert_fields(THD *thd, Name_resolution_context *context, const char *db_name,
information_schema table, or a nested table reference. See the comment
for TABLE_LIST.
*/
- if (!(table && !tables->view && (table->grant.privilege & SELECT_ACL) ||
- tables->view && (tables->grant.privilege & SELECT_ACL)) &&
+ if (!((table && !tables->view && (table->grant.privilege & SELECT_ACL)) ||
+ (tables->view && (tables->grant.privilege & SELECT_ACL))) &&
!any_privileges)
{
field_iterator.set(tables);
@@ -7832,7 +7840,7 @@ insert_fields(THD *thd, Name_resolution_context *context, const char *db_name,
*/
if (any_privileges)
{
- DBUG_ASSERT(tables->field_translation == NULL && table ||
+ DBUG_ASSERT((tables->field_translation == NULL && table) ||
tables->is_natural_join);
DBUG_ASSERT(item->type() == Item::FIELD_ITEM);
Item_field *fld= (Item_field*) item;
@@ -7971,7 +7979,7 @@ int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves,
if (*conds)
{
thd->where="where clause";
- if (!(*conds)->fixed && (*conds)->fix_fields(thd, conds) ||
+ if ((!(*conds)->fixed && (*conds)->fix_fields(thd, conds)) ||
(*conds)->check_cols(1))
goto err_no_arena;
}
@@ -7991,8 +7999,8 @@ int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves,
{
/* Make a join an a expression */
thd->where="on clause";
- if (!embedded->on_expr->fixed &&
- embedded->on_expr->fix_fields(thd, &embedded->on_expr) ||
+ if ((!embedded->on_expr->fixed &&
+ embedded->on_expr->fix_fields(thd, &embedded->on_expr)) ||
embedded->on_expr->check_cols(1))
goto err_no_arena;
select_lex->cond_count++;
@@ -8147,8 +8155,8 @@ fill_record_n_invoke_before_triggers(THD *thd, List
- &fields,
enum trg_event_type event)
{
return (fill_record(thd, fields, values, ignore_errors) ||
- triggers && triggers->process_triggers(thd, event,
- TRG_ACTION_BEFORE, TRUE));
+ (triggers && triggers->process_triggers(thd, event,
+ TRG_ACTION_BEFORE, TRUE)));
}
@@ -8242,8 +8250,8 @@ fill_record_n_invoke_before_triggers(THD *thd, Field **ptr,
enum trg_event_type event)
{
return (fill_record(thd, ptr, values, ignore_errors) ||
- triggers && triggers->process_triggers(thd, event,
- TRG_ACTION_BEFORE, TRUE));
+ (triggers && triggers->process_triggers(thd, event,
+ TRG_ACTION_BEFORE, TRUE)));
}
diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc
index 7c104ccc455..52de41ef1b2 100644
--- a/sql/sql_cache.cc
+++ b/sql/sql_cache.cc
@@ -353,11 +353,6 @@ TODO list:
#define RW_UNLOCK(M) {DBUG_PRINT("lock", ("rwlock unlock 0x%lx",(ulong)(M))); \
if (!rw_unlock(M)) DBUG_PRINT("lock", ("rwlock unlock ok")); \
else DBUG_PRINT("lock", ("rwlock unlock FAILED %d", errno)); }
-#define STRUCT_LOCK(M) {DBUG_PRINT("lock", ("%d struct lock...",__LINE__)); \
- pthread_mutex_lock(M);DBUG_PRINT("lock", ("struct lock OK"));}
-#define STRUCT_UNLOCK(M) { \
- DBUG_PRINT("lock", ("%d struct unlock...",__LINE__)); \
- pthread_mutex_unlock(M);DBUG_PRINT("lock", ("struct unlock OK"));}
#define BLOCK_LOCK_WR(B) {DBUG_PRINT("lock", ("%d LOCK_WR 0x%lx",\
__LINE__,(ulong)(B))); \
B->query()->lock_writing();}
@@ -404,8 +399,6 @@ static void debug_wait_for_kill(const char *info)
#define RW_WLOCK(M) rw_wrlock(M)
#define RW_RLOCK(M) rw_rdlock(M)
#define RW_UNLOCK(M) rw_unlock(M)
-#define STRUCT_LOCK(M) pthread_mutex_lock(M)
-#define STRUCT_UNLOCK(M) pthread_mutex_unlock(M)
#define BLOCK_LOCK_WR(B) B->query()->lock_writing()
#define BLOCK_LOCK_RD(B) B->query()->lock_reading()
#define BLOCK_UNLOCK_WR(B) B->query()->unlock_writing()
@@ -420,6 +413,140 @@ TYPELIB query_cache_type_typelib=
};
+/**
+ Serialize access to the query cache.
+ If the lock cannot be granted the thread hangs in a conditional wait which
+ is signalled on each unlock.
+
+ The lock attempt will also fail without wait if lock_and_suspend() is in
+ effect by another thread. This enables a quick path in execution to skip waits
+ when the outcome is known.
+
+ @return
+ @retval FALSE An exclusive lock was taken
+ @retval TRUE The locking attempt failed
+*/
+
+bool Query_cache::try_lock(void)
+{
+ bool interrupt= FALSE;
+ DBUG_ENTER("Query_cache::try_lock");
+
+ pthread_mutex_lock(&structure_guard_mutex);
+ while (1)
+ {
+ if (m_cache_lock_status == Query_cache::UNLOCKED)
+ {
+ m_cache_lock_status= Query_cache::LOCKED;
+#ifndef DBUG_OFF
+ THD *thd= current_thd;
+ if (thd)
+ m_cache_lock_thread_id= thd->thread_id;
+#endif
+ break;
+ }
+ else if (m_cache_lock_status == Query_cache::LOCKED_NO_WAIT)
+ {
+ /*
+ If query cache is protected by a LOCKED_NO_WAIT lock this thread
+ should avoid using the query cache as it is being evicted.
+ */
+ interrupt= TRUE;
+ break;
+ }
+ else
+ {
+ DBUG_ASSERT(m_cache_lock_status == Query_cache::LOCKED);
+ pthread_cond_wait(&COND_cache_status_changed, &structure_guard_mutex);
+ }
+ }
+ pthread_mutex_unlock(&structure_guard_mutex);
+
+ DBUG_RETURN(interrupt);
+}
+
+
+/**
+ Serialize access to the query cache.
+ If the lock cannot be granted the thread hangs in a conditional wait which
+ is signalled on each unlock.
+
+ This method also suspends the query cache so that other threads attempting to
+ lock the cache with try_lock() will fail directly without waiting.
+
+ It is used by all methods which flushes or destroys the whole cache.
+ */
+
+void Query_cache::lock_and_suspend(void)
+{
+ DBUG_ENTER("Query_cache::lock_and_suspend");
+
+ pthread_mutex_lock(&structure_guard_mutex);
+ while (m_cache_lock_status != Query_cache::UNLOCKED)
+ pthread_cond_wait(&COND_cache_status_changed, &structure_guard_mutex);
+ m_cache_lock_status= Query_cache::LOCKED_NO_WAIT;
+#ifndef DBUG_OFF
+ THD *thd= current_thd;
+ if (thd)
+ m_cache_lock_thread_id= thd->thread_id;
+#endif
+ /* Wake up everybody, a whole cache flush is starting! */
+ pthread_cond_broadcast(&COND_cache_status_changed);
+ pthread_mutex_unlock(&structure_guard_mutex);
+
+ DBUG_VOID_RETURN;
+}
+
+/**
+ Serialize access to the query cache.
+ If the lock cannot be granted the thread hangs in a conditional wait which
+ is signalled on each unlock.
+
+ It is used by all methods which invalidates one or more tables.
+ */
+
+void Query_cache::lock(void)
+{
+ DBUG_ENTER("Query_cache::lock");
+
+ pthread_mutex_lock(&structure_guard_mutex);
+ while (m_cache_lock_status != Query_cache::UNLOCKED)
+ pthread_cond_wait(&COND_cache_status_changed, &structure_guard_mutex);
+ m_cache_lock_status= Query_cache::LOCKED;
+#ifndef DBUG_OFF
+ THD *thd= current_thd;
+ if (thd)
+ m_cache_lock_thread_id= thd->thread_id;
+#endif
+ pthread_mutex_unlock(&structure_guard_mutex);
+
+ DBUG_VOID_RETURN;
+}
+
+
+/**
+ Set the query cache to UNLOCKED and signal waiting threads.
+*/
+
+void Query_cache::unlock(void)
+{
+ DBUG_ENTER("Query_cache::unlock");
+ pthread_mutex_lock(&structure_guard_mutex);
+#ifndef DBUG_OFF
+ THD *thd= current_thd;
+ if (thd)
+ DBUG_ASSERT(m_cache_lock_thread_id == thd->thread_id);
+#endif
+ DBUG_ASSERT(m_cache_lock_status == Query_cache::LOCKED ||
+ m_cache_lock_status == Query_cache::LOCKED_NO_WAIT);
+ m_cache_lock_status= Query_cache::UNLOCKED;
+ DBUG_PRINT("Query_cache",("Sending signal"));
+ pthread_cond_signal(&COND_cache_status_changed);
+ pthread_mutex_unlock(&structure_guard_mutex);
+ DBUG_VOID_RETURN;
+}
+
+
/**
Helper function for determine if a SELECT statement has a SQL_NO_CACHE
directive.
@@ -714,14 +841,8 @@ void query_cache_insert(NET *net, const char *packet, ulong length)
DBUG_EXECUTE_IF("wait_in_query_cache_insert",
debug_wait_for_kill("wait_in_query_cache_insert"); );
- STRUCT_LOCK(&query_cache.structure_guard_mutex);
- bool interrupt;
- query_cache.wait_while_table_flush_is_in_progress(&interrupt);
- if (interrupt)
- {
- STRUCT_UNLOCK(&query_cache.structure_guard_mutex);
+ if (query_cache.try_lock())
DBUG_VOID_RETURN;
- }
Query_cache_block *query_block= (Query_cache_block*)net->query_cache_query;
if (!query_block)
@@ -730,7 +851,7 @@ void query_cache_insert(NET *net, const char *packet, ulong length)
We lost the writer and the currently processed query has been
invalidated; there is nothing left to do.
*/
- STRUCT_UNLOCK(&query_cache.structure_guard_mutex);
+ query_cache.unlock();
DBUG_VOID_RETURN;
}
@@ -756,7 +877,7 @@ void query_cache_insert(NET *net, const char *packet, ulong length)
query_cache.free_query(query_block);
query_cache.refused++;
// append_result_data no success => we need unlock
- STRUCT_UNLOCK(&query_cache.structure_guard_mutex);
+ query_cache.unlock();
DBUG_VOID_RETURN;
}
@@ -778,14 +899,8 @@ void query_cache_abort(NET *net)
if (net->query_cache_query == 0)
DBUG_VOID_RETURN;
- STRUCT_LOCK(&query_cache.structure_guard_mutex);
- bool interrupt;
- query_cache.wait_while_table_flush_is_in_progress(&interrupt);
- if (interrupt)
- {
- STRUCT_UNLOCK(&query_cache.structure_guard_mutex);
+ if (query_cache.try_lock())
DBUG_VOID_RETURN;
- }
/*
While we were waiting another thread might have changed the status
@@ -804,8 +919,7 @@ void query_cache_abort(NET *net)
DBUG_EXECUTE("check_querycache",query_cache.check_integrity(1););
}
- STRUCT_UNLOCK(&query_cache.structure_guard_mutex);
-
+ query_cache.unlock();
DBUG_VOID_RETURN;
}
@@ -833,15 +947,8 @@ void query_cache_end_of_result(THD *thd)
emb_count_querycache_size(thd));
#endif
- STRUCT_LOCK(&query_cache.structure_guard_mutex);
-
- bool interrupt;
- query_cache.wait_while_table_flush_is_in_progress(&interrupt);
- if (interrupt)
- {
- STRUCT_UNLOCK(&query_cache.structure_guard_mutex);
+ if (query_cache.try_lock())
DBUG_VOID_RETURN;
- }
query_block= ((Query_cache_block*) thd->net.query_cache_query);
if (query_block)
@@ -870,10 +977,9 @@ void query_cache_end_of_result(THD *thd)
*/
DBUG_ASSERT(0);
query_cache.free_query(query_block);
- STRUCT_UNLOCK(&query_cache.structure_guard_mutex);
+ query_cache.unlock();
DBUG_VOID_RETURN;
}
-
last_result_block= header->result()->prev;
allign_size= ALIGN_SIZE(last_result_block->used);
len= max(query_cache.min_allocation_unit, allign_size);
@@ -886,13 +992,11 @@ void query_cache_end_of_result(THD *thd)
/* Drop the writer. */
header->writer(0);
thd->net.query_cache_query= 0;
-
BLOCK_UNLOCK_WR(query_block);
DBUG_EXECUTE("check_querycache",query_cache.check_integrity(1););
}
-
- STRUCT_UNLOCK(&query_cache.structure_guard_mutex);
+ query_cache.unlock();
DBUG_VOID_RETURN;
}
@@ -952,11 +1056,7 @@ ulong Query_cache::resize(ulong query_cache_size_arg)
query_cache_size_arg));
DBUG_ASSERT(initialized);
- STRUCT_LOCK(&structure_guard_mutex);
- while (is_flushing())
- pthread_cond_wait(&COND_cache_status_changed, &structure_guard_mutex);
- m_cache_status= Query_cache::FLUSH_IN_PROGRESS;
- STRUCT_UNLOCK(&structure_guard_mutex);
+ lock_and_suspend();
/*
Wait for all readers and writers to exit. When the list of all queries
@@ -988,13 +1088,10 @@ ulong Query_cache::resize(ulong query_cache_size_arg)
query_cache_size= query_cache_size_arg;
new_query_cache_size= init_cache();
- STRUCT_LOCK(&structure_guard_mutex);
- m_cache_status= Query_cache::NO_FLUSH_IN_PROGRESS;
- pthread_cond_signal(&COND_cache_status_changed);
if (new_query_cache_size)
DBUG_EXECUTE("check_querycache",check_integrity(1););
- STRUCT_UNLOCK(&structure_guard_mutex);
+ unlock();
DBUG_RETURN(new_query_cache_size);
}
@@ -1091,15 +1188,16 @@ def_week_frmt: %lu, in_trans: %d, autocommit: %d",
*/
ha_release_temporary_latches(thd);
- STRUCT_LOCK(&structure_guard_mutex);
- if (query_cache_size == 0 || is_flushing())
+ /*
+ A table- or a full flush operation can potentially take a long time to
+ finish. We choose not to wait for them and skip caching statements
+ instead.
+ */
+ if (try_lock())
+ DBUG_VOID_RETURN;
+ if (query_cache_size == 0)
{
- /*
- A table- or a full flush operation can potentially take a long time to
- finish. We choose not to wait for them and skip caching statements
- instead.
- */
- STRUCT_UNLOCK(&structure_guard_mutex);
+ unlock();
DBUG_VOID_RETURN;
}
DUMP(this);
@@ -1107,7 +1205,7 @@ def_week_frmt: %lu, in_trans: %d, autocommit: %d",
if (ask_handler_allowance(thd, tables_used))
{
refused++;
- STRUCT_UNLOCK(&structure_guard_mutex);
+ unlock();
DBUG_VOID_RETURN;
}
@@ -1155,7 +1253,7 @@ def_week_frmt: %lu, in_trans: %d, autocommit: %d",
DBUG_PRINT("qcache", ("insertion in query hash"));
header->unlock_n_destroy();
free_memory_block(query_block);
- STRUCT_UNLOCK(&structure_guard_mutex);
+ unlock();
goto end;
}
if (!register_all_tables(query_block, tables_used, local_tables))
@@ -1165,7 +1263,7 @@ def_week_frmt: %lu, in_trans: %d, autocommit: %d",
hash_delete(&queries, (uchar *) query_block);
header->unlock_n_destroy();
free_memory_block(query_block);
- STRUCT_UNLOCK(&structure_guard_mutex);
+ unlock();
goto end;
}
double_linked_list_simple_include(query_block, &queries_blocks);
@@ -1175,7 +1273,7 @@ def_week_frmt: %lu, in_trans: %d, autocommit: %d",
header->writer(net);
header->tables_type(tables_type);
- STRUCT_UNLOCK(&structure_guard_mutex);
+ unlock();
// init_n_lock make query block locked
BLOCK_UNLOCK_WR(query_block);
@@ -1184,7 +1282,7 @@ def_week_frmt: %lu, in_trans: %d, autocommit: %d",
{
// We have not enough memory to store query => do nothing
refused++;
- STRUCT_UNLOCK(&structure_guard_mutex);
+ unlock();
DBUG_PRINT("warning", ("Can't allocate query"));
}
}
@@ -1192,7 +1290,7 @@ def_week_frmt: %lu, in_trans: %d, autocommit: %d",
{
// Another thread is processing the same query => do nothing
refused++;
- STRUCT_UNLOCK(&structure_guard_mutex);
+ unlock();
DBUG_PRINT("qcache", ("Another thread process same query"));
}
}
@@ -1291,18 +1389,17 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length)
}
}
- STRUCT_LOCK(&structure_guard_mutex);
+ /*
+ Try to obtain an exclusive lock on the query cache. If the cache is
+ disabled or if a full cache flush is in progress, the attempt to
+ get the lock is aborted.
+ */
+ if (try_lock())
+ goto err;
if (query_cache_size == 0)
goto err_unlock;
- if (is_flushing())
- {
- /* Return; Query cache is temporarily disabled while we flush. */
- DBUG_PRINT("qcache",("query cache disabled"));
- goto err_unlock;
- }
-
/*
Check that we haven't forgot to reset the query cache variables;
make sure there are no attached query cache writer to this thread.
@@ -1436,7 +1533,7 @@ def_week_frmt: %lu, in_trans: %d, autocommit: %d",
DBUG_PRINT("qcache",
("Temporary table detected: '%s.%s'",
table_list.db, table_list.alias));
- STRUCT_UNLOCK(&structure_guard_mutex);
+ unlock();
/*
We should not store result of this query because it contain
temporary tables => assign following variable to make check
@@ -1457,7 +1554,7 @@ def_week_frmt: %lu, in_trans: %d, autocommit: %d",
DBUG_PRINT("qcache",
("probably no SELECT access to %s.%s => return to normal processing",
table_list.db, table_list.alias));
- STRUCT_UNLOCK(&structure_guard_mutex);
+ unlock();
thd->lex->safe_to_cache_query=0; // Don't try to cache this
BLOCK_UNLOCK_RD(query_block);
DBUG_RETURN(-1); // Privilege error
@@ -1500,7 +1597,7 @@ def_week_frmt: %lu, in_trans: %d, autocommit: %d",
}
move_to_query_list_end(query_block);
hits++;
- STRUCT_UNLOCK(&structure_guard_mutex);
+ unlock();
/*
Send cached result to client
@@ -1540,7 +1637,7 @@ def_week_frmt: %lu, in_trans: %d, autocommit: %d",
DBUG_RETURN(1); // Result sent to client
err_unlock:
- STRUCT_UNLOCK(&structure_guard_mutex);
+ unlock();
err:
MYSQL_QUERY_CACHE_MISS(thd->query);
DBUG_RETURN(0); // Query was not cached
@@ -1661,47 +1758,6 @@ void Query_cache::invalidate(THD *thd, const char *key, uint32 key_length,
}
-/**
- Synchronize the thread with any flushing operations.
-
- This helper function is called whenever a thread needs to operate on the
- query cache structure (example: during invalidation). If a table flush is in
- progress this function will wait for it to stop. If a full flush is in
- progress, the function will set the interrupt parameter to indicate that the
- current operation is redundant and should be interrupted.
-
- @param[out] interrupt This out-parameter will be set to TRUE if the calling
- function is redundant and should be interrupted.
-
- @return If the interrupt-parameter is TRUE then m_cache_status is set to
- NO_FLUSH_IN_PROGRESS. If the interrupt-parameter is FALSE then
- m_cache_status is set to FLUSH_IN_PROGRESS.
- The structure_guard_mutex will in any case be locked.
-*/
-
-void Query_cache::wait_while_table_flush_is_in_progress(bool *interrupt)
-{
- while (is_flushing())
- {
- /*
- If there already is a full flush in progress query cache isn't enabled
- and additional flushes are redundant; just return instead.
- */
- if (m_cache_status == Query_cache::FLUSH_IN_PROGRESS)
- {
- *interrupt= TRUE;
- return;
- }
- /*
- If a table flush is in progress; wait on cache status to change.
- */
- if (m_cache_status == Query_cache::TABLE_FLUSH_IN_PROGRESS)
- pthread_cond_wait(&COND_cache_status_changed, &structure_guard_mutex);
- }
- *interrupt= FALSE;
-}
-
-
/**
Remove all cached queries that uses the given database.
*/
@@ -1711,14 +1767,11 @@ void Query_cache::invalidate(char *db)
bool restart= FALSE;
DBUG_ENTER("Query_cache::invalidate (db)");
- STRUCT_LOCK(&structure_guard_mutex);
- bool interrupt;
- wait_while_table_flush_is_in_progress(&interrupt);
- if (interrupt)
- {
- STRUCT_UNLOCK(&structure_guard_mutex);
- return;
- }
+ /*
+ Lock the query cache and queue all invalidation attempts to avoid
+ the risk of a race between invalidation, cache inserts and flushes.
+ */
+ lock();
THD *thd= current_thd;
@@ -1774,7 +1827,7 @@ void Query_cache::invalidate(char *db)
} while (restart);
} // end if( tables_blocks )
}
- STRUCT_UNLOCK(&structure_guard_mutex);
+ unlock();
DBUG_VOID_RETURN;
}
@@ -1798,7 +1851,10 @@ void Query_cache::invalidate_by_MyISAM_filename(const char *filename)
void Query_cache::flush()
{
DBUG_ENTER("Query_cache::flush");
- STRUCT_LOCK(&structure_guard_mutex);
+ DBUG_EXECUTE_IF("wait_in_query_cache_flush1",
+ debug_wait_for_kill("wait_in_query_cache_flush1"););
+
+ lock_and_suspend();
if (query_cache_size > 0)
{
DUMP(this);
@@ -1807,7 +1863,7 @@ void Query_cache::flush()
}
DBUG_EXECUTE("check_querycache",query_cache.check_integrity(1););
- STRUCT_UNLOCK(&structure_guard_mutex);
+ unlock();
DBUG_VOID_RETURN;
}
@@ -1826,18 +1882,16 @@ void Query_cache::pack(ulong join_limit, uint iteration_limit)
{
DBUG_ENTER("Query_cache::pack");
- bool interrupt;
- STRUCT_LOCK(&structure_guard_mutex);
- wait_while_table_flush_is_in_progress(&interrupt);
- if (interrupt)
- {
- STRUCT_UNLOCK(&structure_guard_mutex);
+ /*
+ If the entire qc is being invalidated we can bail out early
+ instead of waiting for the lock.
+ */
+ if (try_lock())
DBUG_VOID_RETURN;
- }
if (query_cache_size == 0)
{
- STRUCT_UNLOCK(&structure_guard_mutex);
+ unlock();
DBUG_VOID_RETURN;
}
@@ -1847,7 +1901,7 @@ void Query_cache::pack(ulong join_limit, uint iteration_limit)
pack_cache();
} while ((++i < iteration_limit) && join_results(join_limit));
- STRUCT_UNLOCK(&structure_guard_mutex);
+ unlock();
DBUG_VOID_RETURN;
}
@@ -1862,9 +1916,9 @@ void Query_cache::destroy()
else
{
/* Underlying code expects the lock. */
- STRUCT_LOCK(&structure_guard_mutex);
+ lock_and_suspend();
free_cache();
- STRUCT_UNLOCK(&structure_guard_mutex);
+ unlock();
pthread_cond_destroy(&COND_cache_status_changed);
pthread_mutex_destroy(&structure_guard_mutex);
@@ -1883,7 +1937,7 @@ void Query_cache::init()
DBUG_ENTER("Query_cache::init");
pthread_mutex_init(&structure_guard_mutex,MY_MUTEX_INIT_FAST);
pthread_cond_init(&COND_cache_status_changed, NULL);
- m_cache_status= Query_cache::NO_FLUSH_IN_PROGRESS;
+ m_cache_lock_status= Query_cache::UNLOCKED;
initialized = 1;
DBUG_VOID_RETURN;
}
@@ -2123,23 +2177,9 @@ void Query_cache::free_cache()
void Query_cache::flush_cache()
{
- /*
- If there is flush in progress, wait for it to finish, and then do
- our flush. This is necessary because something could be added to
- the cache before we acquire the lock again, and some code (like
- Query_cache::free_cache()) depends on the fact that after the
- flush the cache is empty.
- */
- while (is_flushing())
- pthread_cond_wait(&COND_cache_status_changed, &structure_guard_mutex);
-
- /*
- Setting 'FLUSH_IN_PROGRESS' will prevent other threads from using
- the cache while we are in the middle of the flush, and we release
- the lock so that other threads won't block.
- */
- m_cache_status= Query_cache::FLUSH_IN_PROGRESS;
- STRUCT_UNLOCK(&structure_guard_mutex);
+
+ DBUG_EXECUTE_IF("wait_in_query_cache_flush2",
+ debug_wait_for_kill("wait_in_query_cache_flush2"););
my_hash_reset(&queries);
while (queries_blocks != 0)
@@ -2147,10 +2187,6 @@ void Query_cache::flush_cache()
BLOCK_LOCK_WR(queries_blocks);
free_query_internal(queries_blocks);
}
-
- STRUCT_LOCK(&structure_guard_mutex);
- m_cache_status= Query_cache::NO_FLUSH_IN_PROGRESS;
- pthread_cond_signal(&COND_cache_status_changed);
}
/*
@@ -2330,10 +2366,6 @@ Query_cache::write_block_data(ulong data_len, uchar* data,
}
-/*
- On success STRUCT_UNLOCK(&query_cache.structure_guard_mutex) will be done.
-*/
-
my_bool
Query_cache::append_result_data(Query_cache_block **current_block,
ulong data_len, uchar* data,
@@ -2353,10 +2385,6 @@ Query_cache::append_result_data(Query_cache_block **current_block,
if (*current_block == 0)
{
DBUG_PRINT("qcache", ("allocated first result data block %lu", data_len));
- /*
- STRUCT_UNLOCK(&structure_guard_mutex) Will be done by
- write_result_data if success;
- */
DBUG_RETURN(write_result_data(current_block, data_len, data, query_block,
Query_cache_block::RES_BEG));
}
@@ -2387,10 +2415,6 @@ Query_cache::append_result_data(Query_cache_block **current_block,
DBUG_PRINT("qcache", ("allocate new block for %lu bytes",
data_len-last_block_free_space));
Query_cache_block *new_block = 0;
- /*
- On success STRUCT_UNLOCK(&structure_guard_mutex) will be done
- by the next call
- */
success = write_result_data(&new_block, data_len-last_block_free_space,
(uchar*)(((uchar*)data)+last_block_free_space),
query_block,
@@ -2405,7 +2429,7 @@ Query_cache::append_result_data(Query_cache_block **current_block,
else
{
// It is success (nobody can prevent us write data)
- STRUCT_UNLOCK(&structure_guard_mutex);
+ unlock();
}
// Now finally write data to the last block
@@ -2443,7 +2467,7 @@ my_bool Query_cache::write_result_data(Query_cache_block **result_block,
if (success)
{
// It is success (nobody can prevent us write data)
- STRUCT_UNLOCK(&structure_guard_mutex);
+ unlock();
uint headers_len = (ALIGN_SIZE(sizeof(Query_cache_block)) +
ALIGN_SIZE(sizeof(Query_cache_result)));
#ifndef EMBEDDED_LIBRARY
@@ -2601,6 +2625,18 @@ void Query_cache::invalidate_table(THD *thd, TABLE *table)
void Query_cache::invalidate_table(THD *thd, uchar * key, uint32 key_length)
{
+#ifdef TO_BE_REMOVED
+/*
+ This ifdef'd piece comes from Summit, it's a manual backport (2008-10-15) of
+ http://lists.mysql.com/commits/56418.
+ But that was an early, non-final patch: after that backport was made, the
+ author of the patch decided to abandon it, and his final patch (put into 6.0)
+ was different.
+ Then 5.1's code was changed for some other reasons, so now we have a
+ conflict between the old patch backported to Summit and the latest 5.1.
+ The backport cannot stay, it has to be removed and then rewritten if
+ desired.
+*/
bool interrupt;
if (m_query_cache_is_disabled)
@@ -2619,28 +2655,35 @@ void Query_cache::invalidate_table(THD *thd, uchar * key, uint32 key_length)
STRUCT_UNLOCK(&structure_guard_mutex);
return;
}
+||||||| BASE-REVISION
+ bool interrupt;
+ STRUCT_LOCK(&structure_guard_mutex);
+ wait_while_table_flush_is_in_progress(&interrupt);
+ if (interrupt)
+ {
+ STRUCT_UNLOCK(&structure_guard_mutex);
+ return;
+ }
+=======
+/* current 5.1 code: */
+#endif
+ DBUG_EXECUTE_IF("wait_in_query_cache_invalidate1",
+ debug_wait_for_kill("wait_in_query_cache_invalidate1"); );
/*
- Setting 'TABLE_FLUSH_IN_PROGRESS' will temporarily disable the cache
- so that structural changes to cache won't block the entire server.
- However, threads requesting to change the query cache will still have
- to wait for the flush to finish.
+ Lock the query cache and queue all invalidation attempts to avoid
+ the risk of a race between invalidation, cache inserts and flushes.
*/
- m_cache_status= Query_cache::TABLE_FLUSH_IN_PROGRESS;
- STRUCT_UNLOCK(&structure_guard_mutex);
+ lock();
+
+ DBUG_EXECUTE_IF("wait_in_query_cache_invalidate2",
+ debug_wait_for_kill("wait_in_query_cache_invalidate2"); );
+
if (query_cache_size > 0)
invalidate_table_internal(thd, key, key_length);
- STRUCT_LOCK(&structure_guard_mutex);
- m_cache_status= Query_cache::NO_FLUSH_IN_PROGRESS;
-
- /*
- net_real_write might be waiting on a change on the m_cache_status
- variable.
- */
- pthread_cond_signal(&COND_cache_status_changed);
- STRUCT_UNLOCK(&structure_guard_mutex);
+ unlock();
}
@@ -2649,7 +2692,7 @@ void Query_cache::invalidate_table(THD *thd, uchar * key, uint32 key_length)
The caller must ensure that no other thread is trying to work with
the query cache when this function is executed.
- @pre structure_guard_mutex is acquired or TABLE_FLUSH_IN_PROGRESS is set.
+ @pre structure_guard_mutex is acquired or LOCKED is set.
*/
void
@@ -2667,7 +2710,7 @@ Query_cache::invalidate_table_internal(THD *thd, uchar *key, uint32 key_length)
/**
Invalidate a linked list of query cache blocks.
- Each block tries to aquire a block level lock before
+ Each block tries to acquire a block level lock before
free_query is a called. This function will in turn affect
related table- and result-blocks.
@@ -4191,10 +4234,7 @@ my_bool Query_cache::check_integrity(bool locked)
DBUG_ENTER("check_integrity");
if (!locked)
- STRUCT_LOCK(&structure_guard_mutex);
-
- while (is_flushing())
- pthread_cond_wait(&COND_cache_status_changed,&structure_guard_mutex);
+ lock_and_suspend();
if (hash_check(&queries))
{
@@ -4443,7 +4483,7 @@ my_bool Query_cache::check_integrity(bool locked)
}
DBUG_ASSERT(result == 0);
if (!locked)
- STRUCT_UNLOCK(&structure_guard_mutex);
+ unlock();
DBUG_RETURN(result);
}
diff --git a/sql/sql_cache.h b/sql/sql_cache.h
index 15e97238335..a8636381956 100644
--- a/sql/sql_cache.h
+++ b/sql/sql_cache.h
@@ -272,12 +272,12 @@ public:
private:
+#ifndef DBUG_OFF
+ my_thread_id m_cache_lock_thread_id;
+#endif
pthread_cond_t COND_cache_status_changed;
-
- enum Cache_status { NO_FLUSH_IN_PROGRESS, FLUSH_IN_PROGRESS,
- TABLE_FLUSH_IN_PROGRESS };
-
- Cache_status m_cache_status;
+ enum Cache_lock_status { UNLOCKED, LOCKED_NO_WAIT, LOCKED };
+ Cache_lock_status m_cache_lock_status;
bool m_query_cache_is_disabled;
@@ -382,8 +382,6 @@ protected:
Query_cache_block *pprev);
my_bool join_results(ulong join_limit);
- void wait_while_table_flush_is_in_progress(bool *interrupt);
-
/*
Following function control structure_guard_mutex
by themself or don't need structure_guard_mutex
@@ -480,12 +478,6 @@ protected:
friend void query_cache_abort(NET *net);
bool is_disabled(void) { return m_query_cache_is_disabled; }
-
- bool is_flushing(void)
- {
- return (m_cache_status != Query_cache::NO_FLUSH_IN_PROGRESS);
- }
-
/*
The following functions are only used when debugging
We don't protect these with ifndef DBUG_OFF to not have to recompile
@@ -503,6 +495,11 @@ protected:
Query_cache_block_table * point,
const char *name);
my_bool in_blocks(Query_cache_block * point);
+
+ bool try_lock(void);
+ void lock(void);
+ void lock_and_suspend(void);
+ void unlock(void);
};
extern Query_cache query_cache;
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index b73822f5a48..5933b233901 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -27,6 +27,7 @@
#include "mysql_priv.h"
#include "rpl_rli.h"
+#include "rpl_filter.h"
#include "rpl_record.h"
#include "slave.h"
#include
@@ -546,6 +547,7 @@ THD::THD()
first_successful_insert_id_in_prev_stmt_for_binlog(0),
first_successful_insert_id_in_cur_stmt(0),
stmt_depends_on_first_successful_insert_id_in_prev_stmt(FALSE),
+ examined_row_count(0),
global_read_lock(0),
is_fatal_error(0),
transaction_rollback_request(0),
@@ -590,7 +592,7 @@ THD::THD()
// Must be reset to handle error with THD's created for init of mysqld
lex->current_select= 0;
start_time=(time_t) 0;
- start_utime= 0L;
+ start_utime= prior_thr_create_utime= 0L;
utime_after_lock= 0L;
current_linfo = 0;
slave_thread = 0;
@@ -674,31 +676,40 @@ THD::THD()
void THD::push_internal_handler(Internal_error_handler *handler)
{
- /*
- TODO: The current implementation is limited to 1 handler at a time only.
- THD and sp_rcontext need to be modified to use a common handler stack.
- */
- DBUG_ASSERT(m_internal_handler == NULL);
- m_internal_handler= handler;
+ if (m_internal_handler)
+ {
+ handler->m_prev_internal_handler= m_internal_handler;
+ m_internal_handler= handler;
+ }
+ else
+ {
+ m_internal_handler= handler;
+ }
}
bool THD::handle_error(uint sql_errno, const char *message,
MYSQL_ERROR::enum_warning_level level)
{
- if (m_internal_handler)
+ if (!m_internal_handler)
+ return FALSE;
+
+ for (Internal_error_handler *error_handler= m_internal_handler;
+ error_handler;
+ error_handler= m_internal_handler->m_prev_internal_handler)
{
- return m_internal_handler->handle_error(sql_errno, message, level, this);
+ if (error_handler->handle_error(sql_errno, message, level, this))
+ return TRUE;
}
- return FALSE; // 'FALSE', as per coding style
+ return FALSE;
}
void THD::pop_internal_handler()
{
DBUG_ASSERT(m_internal_handler != NULL);
- m_internal_handler= NULL;
+ m_internal_handler= m_internal_handler->m_prev_internal_handler;
}
extern "C"
@@ -746,6 +757,12 @@ void thd_get_xid(const MYSQL_THD thd, MYSQL_XID *xid)
*xid = *(MYSQL_XID *) &thd->transaction.xid_state.xid;
}
+#ifdef _WIN32
+extern "C" THD *_current_thd_noinline(void)
+{
+ return my_pthread_getspecific_ptr(THD*,THR_THD);
+}
+#endif
/*
Init common variables that has to be reset on start and on change_user
*/
@@ -2599,7 +2616,7 @@ bool select_dumpvar::send_data(List
- &items)
{
Item_func_set_user_var *suv= new Item_func_set_user_var(mv->s, item);
suv->fix_fields(thd, 0);
- suv->check(0);
+ suv->save_item_result(item);
suv->update();
}
}
@@ -3649,7 +3666,7 @@ show_query_type(THD::enum_binlog_query_type qtype)
*/
int THD::binlog_query(THD::enum_binlog_query_type qtype, char const *query_arg,
ulong query_len, bool is_trans, bool suppress_use,
- THD::killed_state killed_status_arg)
+ int errcode)
{
DBUG_ENTER("THD::binlog_query");
DBUG_PRINT("enter", ("qtype: %s query: '%s'",
@@ -3674,7 +3691,8 @@ int THD::binlog_query(THD::enum_binlog_query_type qtype, char const *query_arg,
we should print a warning.
*/
if (sql_log_bin_toplevel && lex->is_stmt_unsafe() &&
- variables.binlog_format == BINLOG_FORMAT_STMT)
+ variables.binlog_format == BINLOG_FORMAT_STMT &&
+ binlog_filter->db_ok(this->db))
{
/*
A warning can be elevated a error when STRICT sql mode.
@@ -3716,7 +3734,7 @@ int THD::binlog_query(THD::enum_binlog_query_type qtype, char const *query_arg,
*/
{
Query_log_event qinfo(this, query_arg, query_len, is_trans, suppress_use,
- killed_status_arg);
+ errcode);
qinfo.flags|= LOG_EVENT_UPDATE_TABLE_MAP_VERSION_F;
/*
Binlog table maps will be irrelevant after a Query_log_event
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 158f4bc27d6..e7e56cf9a4b 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -91,7 +91,7 @@ enum enum_mark_columns
extern char internal_table_name[2];
extern char empty_c_string[1];
-extern const char **errmesg;
+extern MYSQL_PLUGIN_IMPORT const char **errmesg;
#define TC_LOG_PAGE_SIZE 8192
#define TC_LOG_MIN_SIZE (3*TC_LOG_PAGE_SIZE)
@@ -1036,7 +1036,10 @@ show_system_thread(enum_thread_type thread)
class Internal_error_handler
{
protected:
- Internal_error_handler() {}
+ Internal_error_handler() :
+ m_prev_internal_handler(NULL)
+ {}
+
virtual ~Internal_error_handler() {}
public:
@@ -1069,6 +1072,28 @@ public:
const char *message,
MYSQL_ERROR::enum_warning_level level,
THD *thd) = 0;
+private:
+ Internal_error_handler *m_prev_internal_handler;
+ friend class THD;
+};
+
+
+/**
+ Implements the trivial error handler which cancels all error states
+ and prevents an SQLSTATE to be set.
+*/
+
+class Dummy_error_handler : public Internal_error_handler
+{
+public:
+ bool handle_error(uint sql_errno,
+ const char *message,
+ MYSQL_ERROR::enum_warning_level level,
+ THD *thd)
+ {
+ /* Ignore error */
+ return TRUE;
+ }
};
@@ -1345,7 +1370,8 @@ public:
/* remote (peer) port */
uint16 peer_port;
time_t start_time, user_time;
- ulonglong connect_utime, thr_create_utime; // track down slow pthread_create
+ // track down slow pthread_create
+ ulonglong prior_thr_create_utime, thr_create_utime;
ulonglong start_utime, utime_after_lock;
thr_lock_type update_lock_default;
@@ -1439,6 +1465,14 @@ public:
{
changed_tables= 0;
savepoints= 0;
+ /*
+ If rm_error is raised, it means that this piece of a distributed
+ transaction has failed and must be rolled back. But the user must
+ rollback it explicitly, so don't start a new distributed XA until
+ then.
+ */
+ if (!xid_state.rm_error)
+ xid_state.xid.null();
#ifdef USING_TRANSACTIONS
free_root(&mem_root,MYF(MY_KEEP_PREALLOC));
#endif
@@ -1889,7 +1923,7 @@ public:
int binlog_query(enum_binlog_query_type qtype,
char const *query, ulong query_len,
bool is_trans, bool suppress_use,
- THD::killed_state killed_err_arg= THD::KILLED_NO_VALUE);
+ int errcode);
#endif
/*
@@ -2210,6 +2244,9 @@ public:
thd_scheduler scheduler;
public:
+ inline Internal_error_handler *get_internal_handler()
+ { return m_internal_handler; }
+
/**
Add an internal error handler to the thread execution context.
@param handler the exception handler to add
diff --git a/sql/sql_connect.cc b/sql/sql_connect.cc
index 06528a27da5..3952567c329 100644
--- a/sql/sql_connect.cc
+++ b/sql/sql_connect.cc
@@ -1075,8 +1075,8 @@ static void prepare_new_connection_state(THD* thd)
pthread_handler_t handle_one_connection(void *arg)
{
THD *thd= (THD*) arg;
- ulong launch_time= (ulong) ((thd->thr_create_utime= my_micro_time()) -
- thd->connect_utime);
+
+ thd->thr_create_utime= my_micro_time();
if (thread_scheduler.init_new_connection_thread())
{
@@ -1085,8 +1085,20 @@ pthread_handler_t handle_one_connection(void *arg)
thread_scheduler.end_thread(thd,0);
return 0;
}
- if (launch_time >= slow_launch_time*1000000L)
- statistic_increment(slow_launch_threads,&LOCK_status);
+
+ /*
+ If a thread was created to handle this connection:
+ increment slow_launch_threads counter if it took more than
+ slow_launch_time seconds to create the thread.
+ */
+ if (thd->prior_thr_create_utime)
+ {
+ ulong launch_time= (ulong) (thd->thr_create_utime -
+ thd->prior_thr_create_utime);
+ if (launch_time >= slow_launch_time*1000000L)
+ statistic_increment(slow_launch_threads, &LOCK_status);
+ thd->prior_thr_create_utime= 0;
+ }
/*
handle_one_connection() is normally the only way a thread would
diff --git a/sql/sql_db.cc b/sql/sql_db.cc
index 5a266c3fac9..98d17fdd318 100644
--- a/sql/sql_db.cc
+++ b/sql/sql_db.cc
@@ -181,8 +181,7 @@ uchar* dboptions_get_key(my_dbopt_t *opt, size_t *length,
static inline void write_to_binlog(THD *thd, char *query, uint q_len,
char *db, uint db_len)
{
- Query_log_event qinfo(thd, query, q_len, 0, 0, THD::NOT_KILLED);
- qinfo.error_code= 0;
+ Query_log_event qinfo(thd, query, q_len, 0, 0, 0);
qinfo.db= db;
qinfo.db_len= db_len;
mysql_bin_log.write(&qinfo);
@@ -538,13 +537,13 @@ err1:
bool load_db_opt_by_name(THD *thd, const char *db_name,
HA_CREATE_INFO *db_create_info)
{
- char db_opt_path[FN_REFLEN];
+ char db_opt_path[FN_REFLEN + 1];
/*
Pass an empty file name, and the database options file name as extension
to avoid table name to file name encoding.
*/
- (void) build_table_filename(db_opt_path, sizeof(db_opt_path),
+ (void) build_table_filename(db_opt_path, sizeof(db_opt_path) - 1,
db_name, "", MY_DB_OPT_FILE, 0);
return load_db_opt(thd, db_opt_path, db_create_info);
@@ -646,7 +645,7 @@ int mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create_info,
VOID(pthread_mutex_lock(&LOCK_mysql_create_db));
/* Check directory */
- path_len= build_table_filename(path, sizeof(path), db, "", "", 0);
+ path_len= build_table_filename(path, sizeof(path) - 1, db, "", "", 0);
path[path_len-1]= 0; // Remove last '/' from path
if (my_stat(path,&stat_info,MYF(0)))
@@ -723,8 +722,9 @@ int mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create_info,
if (mysql_bin_log.is_open())
{
+ int errcode= query_error_code(thd, TRUE);
Query_log_event qinfo(thd, query, query_length, 0,
- /* suppress_use */ TRUE, THD::NOT_KILLED);
+ /* suppress_use */ TRUE, errcode);
/*
Write should use the database being created as the "current
@@ -791,7 +791,7 @@ bool mysql_alter_db(THD *thd, const char *db, HA_CREATE_INFO *create_info)
We pass MY_DB_OPT_FILE as "extension" to avoid
"table name to file name" encoding.
*/
- build_table_filename(path, sizeof(path), db, "", MY_DB_OPT_FILE, 0);
+ build_table_filename(path, sizeof(path) - 1, db, "", MY_DB_OPT_FILE, 0);
if ((error=write_db_opt(thd, path, create_info)))
goto exit;
@@ -811,8 +811,9 @@ bool mysql_alter_db(THD *thd, const char *db, HA_CREATE_INFO *create_info)
if (mysql_bin_log.is_open())
{
+ int errcode= query_error_code(thd, TRUE);
Query_log_event qinfo(thd, thd->query, thd->query_length, 0,
- /* suppress_use */ TRUE, THD::NOT_KILLED);
+ /* suppress_use */ TRUE, errcode);
/*
Write should use the database being created as the "current
@@ -883,7 +884,7 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
VOID(pthread_mutex_lock(&LOCK_mysql_create_db));
- length= build_table_filename(path, sizeof(path), db, "", "", 0);
+ length= build_table_filename(path, sizeof(path) - 1, db, "", "", 0);
strmov(path+length, MY_DB_OPT_FILE); // Append db option file name
del_dbopt(path); // Remove dboption hash entry
path[length]= '\0'; // Remove file name
@@ -958,8 +959,9 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
}
if (mysql_bin_log.is_open())
{
+ int errcode= query_error_code(thd, TRUE);
Query_log_event qinfo(thd, query, query_length, 0,
- /* suppress_use */ TRUE, THD::NOT_KILLED);
+ /* suppress_use */ TRUE, errcode);
/*
Write should use the database being created as the "current
database" and not the threads current database, which is the
@@ -1839,7 +1841,7 @@ bool mysql_upgrade_db(THD *thd, LEX_STRING *old_db)
for (uint idx=0 ; idx < nfiles && !thd->killed ; idx++)
{
FILEINFO *file= dirp->dir_entry + idx;
- char *extension, tname[FN_REFLEN];
+ char *extension, tname[FN_REFLEN + 1];
LEX_STRING table_str;
DBUG_PRINT("info",("Examining: %s", file->name));
@@ -1928,7 +1930,7 @@ bool mysql_upgrade_db(THD *thd, LEX_STRING *old_db)
for (uint idx=0 ; idx < nfiles ; idx++)
{
FILEINFO *file= dirp->dir_entry + idx;
- char oldname[FN_REFLEN], newname[FN_REFLEN];
+ char oldname[FN_REFLEN + 1], newname[FN_REFLEN + 1];
DBUG_PRINT("info",("Examining: %s", file->name));
/* skiping . and .. and MY_DB_OPT_FILE */
@@ -1958,8 +1960,9 @@ bool mysql_upgrade_db(THD *thd, LEX_STRING *old_db)
/* Step8: logging */
if (mysql_bin_log.is_open())
{
+ int errcode= query_error_code(thd, TRUE);
Query_log_event qinfo(thd, thd->query, thd->query_length,
- 0, TRUE, THD::NOT_KILLED);
+ 0, TRUE, errcode);
thd->clear_error();
mysql_bin_log.write(&qinfo);
}
@@ -1997,10 +2000,10 @@ exit:
bool check_db_dir_existence(const char *db_name)
{
- char db_dir_path[FN_REFLEN];
+ char db_dir_path[FN_REFLEN + 1];
uint db_dir_path_len;
- db_dir_path_len= build_table_filename(db_dir_path, sizeof(db_dir_path),
+ db_dir_path_len= build_table_filename(db_dir_path, sizeof(db_dir_path) - 1,
db_name, "", "", 0);
if (db_dir_path_len && db_dir_path[db_dir_path_len - 1] == FN_LIBCHAR)
diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc
index 1b42e522491..677098d275a 100644
--- a/sql/sql_delete.cc
+++ b/sql/sql_delete.cc
@@ -389,8 +389,12 @@ cleanup:
FALSE :
transactional_table;
+ int errcode= 0;
if (error < 0)
thd->clear_error();
+ else
+ errcode= query_error_code(thd, killed_status == THD::NOT_KILLED);
+
/*
[binlog]: If 'handler::delete_all_rows()' was called and the
storage engine does not inject the rows itself, we replicate
@@ -402,9 +406,9 @@ cleanup:
*/
int log_result= thd->binlog_query(query_type,
thd->query, thd->query_length,
- is_trans, FALSE, killed_status);
+ is_trans, FALSE, errcode);
- if (log_result && transactional_table)
+ if (log_result)
{
error=1;
}
@@ -582,6 +586,11 @@ int mysql_multi_delete_prepare(THD *thd)
}
}
}
+ /*
+ Reset the exclude flag to false so it doesn't interfare
+ with further calls to unique_table
+ */
+ lex->select_lex.exclude_from_table_unique_test= FALSE;
DBUG_RETURN(FALSE);
}
@@ -617,11 +626,24 @@ multi_delete::initialize_tables(JOIN *join)
DBUG_RETURN(1);
table_map tables_to_delete_from=0;
+ delete_while_scanning= 1;
for (walk= delete_tables; walk; walk= walk->next_local)
+ {
tables_to_delete_from|= walk->table->map;
+ if (delete_while_scanning &&
+ unique_table(thd, walk, join->tables_list, false))
+ {
+ /*
+ If the table we are going to delete from appears
+ in join, we need to defer delete. So the delete
+ doesn't interfers with the scaning of results.
+ */
+ delete_while_scanning= 0;
+ }
+ }
+
walk= delete_tables;
- delete_while_scanning= 1;
for (JOIN_TAB *tab=join->join_tab, *end=join->join_tab+join->tables;
tab < end;
tab++)
@@ -784,7 +806,7 @@ void multi_delete::abort()
/* the error was handled or nothing deleted and no side effects return */
if (error_handled ||
- !thd->transaction.stmt.modified_non_trans_table && !deleted)
+ (!thd->transaction.stmt.modified_non_trans_table && !deleted))
DBUG_VOID_RETURN;
/* Something already deleted so we have to invalidate cache */
@@ -818,9 +840,10 @@ void multi_delete::abort()
*/
if (mysql_bin_log.is_open())
{
+ int errcode= query_error_code(thd, thd->killed == THD::NOT_KILLED);
thd->binlog_query(THD::ROW_QUERY_TYPE,
thd->query, thd->query_length,
- transactional_tables, FALSE);
+ transactional_tables, FALSE, errcode);
}
thd->transaction.all.modified_non_trans_table= true;
}
@@ -961,11 +984,14 @@ bool multi_delete::send_eof()
{
if (mysql_bin_log.is_open())
{
+ int errcode= 0;
if (local_error == 0)
thd->clear_error();
+ else
+ errcode= query_error_code(thd, killed_status == THD::NOT_KILLED);
if (thd->binlog_query(THD::ROW_QUERY_TYPE,
thd->query, thd->query_length,
- transactional_tables, FALSE, killed_status) &&
+ transactional_tables, FALSE, errcode) &&
!normal_tables)
{
local_error=1; // Log write failed: roll back the SQL statement
@@ -1025,7 +1051,7 @@ static bool mysql_truncate_by_delete(THD *thd, TABLE_LIST *table_list)
bool mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok)
{
HA_CREATE_INFO create_info;
- char path[FN_REFLEN];
+ char path[FN_REFLEN + 1];
TABLE *table;
bool error;
uint path_length;
@@ -1062,7 +1088,7 @@ bool mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok)
goto end;
}
- path_length= build_table_filename(path, sizeof(path), table_list->db,
+ path_length= build_table_filename(path, sizeof(path) - 1, table_list->db,
table_list->table_name, reg_ext, 0);
if (!dont_send_ok)
diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc
index 41be98621a6..37adf5c403a 100644
--- a/sql/sql_derived.cc
+++ b/sql/sql_derived.cc
@@ -179,6 +179,7 @@ exit:
{
if (thd->is_error() &&
(thd->main_da.sql_errno() == ER_BAD_FIELD_ERROR ||
+ thd->main_da.sql_errno() == ER_FUNC_INEXISTENT_NAME_COLLISION ||
thd->main_da.sql_errno() == ER_SP_DOES_NOT_EXIST))
{
thd->clear_error();
diff --git a/sql/sql_help.cc b/sql/sql_help.cc
index f51ad318568..2818aa5082c 100644
--- a/sql/sql_help.cc
+++ b/sql/sql_help.cc
@@ -526,7 +526,7 @@ int send_variant_2_list(MEM_ROOT *mem_root, Protocol *protocol,
String **end= pointers + names->elements;
List_iterator it(*names);
- for (pos= pointers; pos!=end; (*pos++= it++));
+ for (pos= pointers; pos!=end; (*pos++= it++)) ;
my_qsort(pointers,names->elements,sizeof(String*),string_ptr_cmp);
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index 9eef9d224e6..77b83b0e6fe 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -301,9 +301,7 @@ static int check_update_fields(THD *thd, TABLE_LIST *insert_table_list,
List
- &update_fields, table_map *map)
{
TABLE *table= insert_table_list->table;
- my_bool timestamp_mark;
-
- LINT_INIT(timestamp_mark);
+ my_bool timestamp_mark= 0;
if (table->timestamp_field)
{
@@ -393,7 +391,7 @@ void upgrade_lock_type(THD *thd, thr_lock_type *lock_type,
bool is_multi_insert)
{
if (duplic == DUP_UPDATE ||
- duplic == DUP_REPLACE && *lock_type == TL_WRITE_CONCURRENT_INSERT)
+ (duplic == DUP_REPLACE && *lock_type == TL_WRITE_CONCURRENT_INSERT))
{
*lock_type= TL_WRITE_DEFAULT;
return;
@@ -858,11 +856,13 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
*/
query_cache_invalidate3(thd, table_list, 1);
}
- if (changed && error <= 0 || thd->transaction.stmt.modified_non_trans_table
- || was_insert_delayed)
+ if ((changed && error <= 0) ||
+ thd->transaction.stmt.modified_non_trans_table ||
+ was_insert_delayed)
{
if (mysql_bin_log.is_open())
{
+ int errcode= 0;
if (error <= 0)
{
/*
@@ -877,6 +877,9 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
/* todo: consider removing */
thd->clear_error();
}
+ else
+ errcode= query_error_code(thd, thd->killed == THD::NOT_KILLED);
+
/* bug#22725:
A query which per-row-loop can not be interrupted with
@@ -893,8 +896,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
if (thd->binlog_query(THD::ROW_QUERY_TYPE,
thd->query, thd->query_length,
transactional_table, FALSE,
- (error>0) ? thd->killed : THD::NOT_KILLED) &&
- transactional_table)
+ errcode))
{
error=1;
}
@@ -1113,6 +1115,33 @@ static bool mysql_prepare_insert_check_table(THD *thd, TABLE_LIST *table_list,
}
+/*
+ Get extra info for tables we insert into
+
+ @param table table(TABLE object) we insert into,
+ might be NULL in case of view
+ @param table(TABLE_LIST object) or view we insert into
+*/
+
+static void prepare_for_positional_update(TABLE *table, TABLE_LIST *tables)
+{
+ if (table)
+ {
+ if(table->reginfo.lock_type != TL_WRITE_DELAYED)
+ table->prepare_for_position();
+ return;
+ }
+
+ DBUG_ASSERT(tables->view);
+ List_iterator it(*tables->view_tables);
+ TABLE_LIST *tbl;
+ while ((tbl= it++))
+ prepare_for_positional_update(tbl->table, tbl);
+
+ return;
+}
+
+
/*
Prepare items in INSERT statement
@@ -1262,9 +1291,8 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list,
Only call prepare_for_posistion() if we are not performing a DELAYED
operation. It will instead be executed by delayed insert thread.
*/
- if ((duplic == DUP_UPDATE || duplic == DUP_REPLACE) &&
- (table->reginfo.lock_type != TL_WRITE_DELAYED))
- table->prepare_for_position();
+ if (duplic == DUP_UPDATE || duplic == DUP_REPLACE)
+ prepare_for_positional_update(table, table_list);
DBUG_RETURN(FALSE);
}
@@ -2667,6 +2695,12 @@ bool Delayed_insert::handle_inserts(void)
thd.variables.time_zone = row->time_zone;
}
+ /* if the delayed insert was killed, the killed status is
+ ignored while binlogging */
+ int errcode= 0;
+ if (thd.killed == THD::NOT_KILLED)
+ errcode= query_error_code(&thd, TRUE);
+
/*
If the query has several rows to insert, only the first row will come
here. In row-based binlogging, this means that the first row will be
@@ -2677,7 +2711,7 @@ bool Delayed_insert::handle_inserts(void)
*/
thd.binlog_query(THD::ROW_QUERY_TYPE,
row->query.str, row->query.length,
- FALSE, FALSE);
+ FALSE, FALSE, errcode);
thd.time_zone_used = backup_time_zone_used;
thd.variables.time_zone = backup_time_zone;
@@ -3090,7 +3124,10 @@ bool select_insert::send_data(List
- &values)
store_values(values);
thd->count_cuted_fields= CHECK_FIELD_IGNORE;
if (thd->is_error())
+ {
+ table->auto_increment_field_not_null= FALSE;
DBUG_RETURN(1);
+ }
if (table_list) // Not CREATE ... SELECT
{
switch (table_list->view_check_option(thd, info.ignore)) {
@@ -3104,6 +3141,9 @@ bool select_insert::send_data(List
- &values)
// Release latches in case bulk insert takes a long time
ha_release_temporary_latches(thd);
+ // Release latches in case bulk insert takes a long time
+ ha_release_temporary_latches(thd);
+
error= write_record(thd, table, &info);
table->auto_increment_field_not_null= FALSE;
@@ -3176,7 +3216,8 @@ bool select_insert::send_eof()
table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
table->file->extra(HA_EXTRA_WRITE_CANNOT_REPLACE);
- if (changed= (info.copied || info.deleted || info.updated))
+ changed= (info.copied || info.deleted || info.updated);
+ if (changed)
{
/*
We must invalidate the table in the query cache before binlog writing
@@ -3197,11 +3238,14 @@ bool select_insert::send_eof()
*/
if (mysql_bin_log.is_open())
{
+ int errcode= 0;
if (!error)
thd->clear_error();
+ else
+ errcode= query_error_code(thd, killed_status == THD::NOT_KILLED);
thd->binlog_query(THD::ROW_QUERY_TYPE,
thd->query, thd->query_length,
- trans_table, FALSE, killed_status);
+ trans_table, FALSE, errcode);
}
table->file->ha_release_auto_increment();
@@ -3268,8 +3312,11 @@ void select_insert::abort() {
if (thd->transaction.stmt.modified_non_trans_table)
{
if (mysql_bin_log.is_open())
+ {
+ int errcode= query_error_code(thd, thd->killed == THD::NOT_KILLED);
thd->binlog_query(THD::ROW_QUERY_TYPE, thd->query, thd->query_length,
- transactional_table, FALSE);
+ transactional_table, FALSE, errcode);
+ }
if (!thd->current_stmt_binlog_row_based && !can_rollback_data())
thd->transaction.all.modified_non_trans_table= TRUE;
if (changed)
@@ -3661,10 +3708,14 @@ select_create::binlog_show_create_table(TABLE **tables, uint count)
DBUG_ASSERT(result == 0); /* store_create_info() always return 0 */
if (mysql_bin_log.is_open())
+ {
+ int errcode= query_error_code(thd, thd->killed == THD::NOT_KILLED);
thd->binlog_query(THD::STMT_QUERY_TYPE,
query.ptr(), query.length(),
/* is_trans */ TRUE,
- /* suppress_use */ FALSE);
+ /* suppress_use */ FALSE,
+ errcode);
+ }
}
void select_create::store_values(List
- &values)
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index b96ac91679b..444a8ae0736 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -433,6 +433,16 @@ bool is_keyword(const char *name, uint len)
return get_hash_symbol(name,len,0)!=0;
}
+/**
+ Check if name is a sql function
+
+ @param name checked name
+
+ @return is this a native function or not
+ @retval 0 name is a function
+ @retval 1 name isn't a function
+*/
+
bool is_lex_native_function(const LEX_STRING *name)
{
DBUG_ASSERT(name != NULL);
@@ -770,7 +780,7 @@ bool consume_comment(Lex_input_stream *lip, int remaining_recursions_permitted)
int MYSQLlex(void *arg, void *yythd)
{
- reg1 uchar c;
+ reg1 uchar c= 0;
bool comment_closed;
int tokval, result_state;
uint length;
@@ -788,7 +798,6 @@ int MYSQLlex(void *arg, void *yythd)
lip->start_token();
state=lip->next_state;
lip->next_state=MY_LEX_OPERATOR_OR_IDENT;
- LINT_INIT(c);
for (;;)
{
switch (state) {
@@ -917,7 +926,7 @@ int MYSQLlex(void *arg, void *yythd)
else
#endif
{
- for (result_state= c; ident_map[c= lip->yyGet()]; result_state|= c);
+ for (result_state= c; ident_map[c= lip->yyGet()]; result_state|= c) ;
/* If there were non-ASCII characters, mark that we must convert */
result_state= result_state & 0x80 ? IDENT_QUOTED : IDENT;
}
@@ -929,7 +938,7 @@ int MYSQLlex(void *arg, void *yythd)
If we find a space then this can't be an identifier. We notice this
below by checking start != lex->ptr.
*/
- for (; state_map[c] == MY_LEX_SKIP ; c= lip->yyGet());
+ for (; state_map[c] == MY_LEX_SKIP ; c= lip->yyGet()) ;
}
if (start == lip->get_ptr() && c == '.' && ident_map[lip->yyPeek()])
lip->next_state=MY_LEX_IDENT_SEP;
@@ -1002,7 +1011,7 @@ int MYSQLlex(void *arg, void *yythd)
}
else if (c == 'b')
{
- while ((c= lip->yyGet()) == '0' || c == '1');
+ while ((c= lip->yyGet()) == '0' || c == '1') ;
if ((lip->yyLength() >= 3) && !ident_map[c])
{
/* Skip '0b' */
@@ -1061,7 +1070,7 @@ int MYSQLlex(void *arg, void *yythd)
else
#endif
{
- for (result_state=0; ident_map[c= lip->yyGet()]; result_state|= c);
+ for (result_state=0; ident_map[c= lip->yyGet()]; result_state|= c) ;
/* If there were non-ASCII characters, mark that we must convert */
result_state= result_state & 0x80 ? IDENT_QUOTED : IDENT;
}
@@ -1161,7 +1170,7 @@ int MYSQLlex(void *arg, void *yythd)
case MY_LEX_BIN_NUMBER: // Found b'bin-string'
lip->yySkip(); // Accept opening '
- while ((c= lip->yyGet()) == '0' || c == '1');
+ while ((c= lip->yyGet()) == '0' || c == '1') ;
if (c != '\'')
return(ABORT_SYM); // Illegal hex constant
lip->yySkip(); // Accept closing '
@@ -1436,7 +1445,7 @@ int MYSQLlex(void *arg, void *yythd)
[(global | local | session) .]variable_name
*/
- for (result_state= 0; ident_map[c= lip->yyGet()]; result_state|= c);
+ for (result_state= 0; ident_map[c= lip->yyGet()]; result_state|= c) ;
/* If there were non-ASCII characters, mark that we must convert */
result_state= result_state & 0x80 ? IDENT_QUOTED : IDENT;
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 62106a2500b..22b7d2e359c 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -1976,4 +1976,6 @@ extern bool is_lex_native_function(const LEX_STRING *name);
@} (End of group Semantic_Analysis)
*/
+int my_missing_function_error(const LEX_STRING &token, const char *name);
+
#endif /* MYSQL_SERVER */
diff --git a/sql/sql_list.h b/sql/sql_list.h
index 0d267111dad..22df77afeb3 100644
--- a/sql/sql_list.h
+++ b/sql/sql_list.h
@@ -86,7 +86,7 @@ struct list_node :public Sql_alloc
};
-extern list_node end_of_list;
+extern MYSQL_PLUGIN_IMPORT list_node end_of_list;
class base_list :public Sql_alloc
{
diff --git a/sql/sql_load.cc b/sql/sql_load.cc
index d4f499b8d44..1758a6df5f9 100644
--- a/sql/sql_load.cc
+++ b/sql/sql_load.cc
@@ -86,7 +86,7 @@ static int read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
static bool write_execute_load_query_log_event(THD *thd,
bool duplicates, bool ignore,
bool transactional_table,
- THD::killed_state killed_status);
+ int errcode);
#endif /* EMBEDDED_LIBRARY */
/*
@@ -483,10 +483,12 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
/* If the file was not empty, wrote_create_file is true */
if (lf_info.wrote_create_file)
{
+ int errcode= query_error_code(thd, killed_status == THD::NOT_KILLED);
+
if (thd->transaction.stmt.modified_non_trans_table)
write_execute_load_query_log_event(thd, handle_duplicates,
ignore, transactional_table,
- killed_status);
+ errcode);
else
{
Delete_file_log_event d(thd, db, transactional_table);
@@ -528,8 +530,9 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
read_info.end_io_cache();
if (lf_info.wrote_create_file)
{
+ int errcode= query_error_code(thd, killed_status == THD::NOT_KILLED);
write_execute_load_query_log_event(thd, handle_duplicates, ignore,
- transactional_table,killed_status);
+ transactional_table, errcode);
}
}
}
@@ -553,7 +556,7 @@ err:
static bool write_execute_load_query_log_event(THD *thd,
bool duplicates, bool ignore,
bool transactional_table,
- THD::killed_state killed_err_arg)
+ int errcode)
{
Execute_load_query_log_event
e(thd, thd->query, thd->query_length,
@@ -561,7 +564,7 @@ static bool write_execute_load_query_log_event(THD *thd,
(uint) ((char*)thd->lex->fname_end - (char*)thd->query),
(duplicates == DUP_REPLACE) ? LOAD_DUP_REPLACE :
(ignore ? LOAD_DUP_IGNORE : LOAD_DUP_ERROR),
- transactional_table, FALSE, killed_err_arg);
+ transactional_table, FALSE, errcode);
e.flags|= LOG_EVENT_UPDATE_TABLE_MAP_VERSION_F;
return mysql_bin_log.write(&e);
}
@@ -747,9 +750,9 @@ read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
real_item= item->real_item();
- if (!read_info.enclosed &&
+ if ((!read_info.enclosed &&
(enclosed_length && length == 4 &&
- !memcmp(pos, STRING_WITH_LEN("NULL"))) ||
+ !memcmp(pos, STRING_WITH_LEN("NULL")))) ||
(length == 1 && read_info.found_null))
{
@@ -1148,8 +1151,8 @@ int READ_INFO::read_field()
}
// End of enclosed field if followed by field_term or line_term
if (chr == my_b_EOF ||
- chr == line_term_char && terminator(line_term_ptr,
- line_term_length))
+ (chr == line_term_char && terminator(line_term_ptr,
+ line_term_length)))
{ // Maybe unexpected linefeed
enclosed=1;
found_end_of_line=1;
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 87497b35bd3..0faed66cd4e 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -196,11 +196,8 @@ bool begin_trans(THD *thd)
error= -1;
else
{
- LEX *lex= thd->lex;
thd->options|= OPTION_BEGIN;
thd->server_status|= SERVER_STATUS_IN_TRANS;
- if (lex->start_transaction_opt & MYSQL_START_TRANS_OPT_WITH_CONS_SNAPSHOT)
- error= ha_start_consistent_snapshot(thd);
}
return error;
}
@@ -1173,12 +1170,12 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
}
case COM_STMT_EXECUTE:
{
- mysql_stmt_execute(thd, packet, packet_length);
+ mysqld_stmt_execute(thd, packet, packet_length);
break;
}
case COM_STMT_FETCH:
{
- mysql_stmt_fetch(thd, packet, packet_length);
+ mysqld_stmt_fetch(thd, packet, packet_length);
break;
}
case COM_STMT_SEND_LONG_DATA:
@@ -1188,17 +1185,17 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
}
case COM_STMT_PREPARE:
{
- mysql_stmt_prepare(thd, packet, packet_length);
+ mysqld_stmt_prepare(thd, packet, packet_length);
break;
}
case COM_STMT_CLOSE:
{
- mysql_stmt_close(thd, packet);
+ mysqld_stmt_close(thd, packet);
break;
}
case COM_STMT_RESET:
{
- mysql_stmt_reset(thd, packet);
+ mysqld_stmt_reset(thd, packet);
break;
}
case COM_QUERY:
@@ -1372,7 +1369,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
if (check_access(thd, CREATE_ACL, db.str , 0, 1, 0,
is_schema_db(db.str)))
break;
- general_log_print(thd, command, packet);
+ general_log_print(thd, command, "%.*s", db.length, db.str);
bzero(&create_info, sizeof(create_info));
mysql_create_db(thd, (lower_case_table_names == 2 ? alias.str : db.str),
&create_info, 0);
@@ -1397,7 +1394,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
break;
}
- general_log_write(thd, command, db.str, db.length);
+ general_log_write(thd, command, "%.*s", db.length, db.str);
mysql_rm_db(thd, db.str, 0, 0);
break;
}
@@ -1582,14 +1579,6 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
break;
}
- /* If commit fails, we should be able to reset the OK status. */
- thd->main_da.can_overwrite_status= TRUE;
- ha_autocommit_or_rollback(thd, thd->is_error());
- thd->main_da.can_overwrite_status= FALSE;
-
- thd->transaction.stmt.reset();
-
-
/* report error issued during command execution */
if (thd->killed_errno())
{
@@ -1602,6 +1591,13 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
thd->mysys_var->abort= 0;
}
+ /* If commit fails, we should be able to reset the OK status. */
+ thd->main_da.can_overwrite_status= TRUE;
+ ha_autocommit_or_rollback(thd, thd->is_error());
+ thd->main_da.can_overwrite_status= FALSE;
+
+ thd->transaction.stmt.reset();
+
net_end_statement(thd);
query_cache_end_of_result(thd);
@@ -3946,7 +3942,9 @@ end_with_restore_list:
res= mysql_routine_grant(thd, all_tables,
lex->type == TYPE_ENUM_PROCEDURE,
lex->users_list, grants,
- lex->sql_command == SQLCOM_REVOKE, 0);
+ lex->sql_command == SQLCOM_REVOKE, TRUE);
+ if (!res)
+ my_ok(thd);
}
else
{
@@ -4090,6 +4088,11 @@ end_with_restore_list:
}
if (begin_trans(thd))
goto error;
+ if (lex->start_transaction_opt & MYSQL_START_TRANS_OPT_WITH_CONS_SNAPSHOT)
+ {
+ if (ha_start_consistent_snapshot(thd))
+ goto error;
+ }
my_ok(thd);
break;
case SQLCOM_COMMIT:
@@ -5230,7 +5233,7 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
if (schema_db)
{
- if (!(sctx->master_access & FILE_ACL) && (want_access & FILE_ACL) ||
+ if ((!(sctx->master_access & FILE_ACL) && (want_access & FILE_ACL)) ||
(want_access & ~(SELECT_ACL | EXTRA_ACL | FILE_ACL)))
{
if (!no_errors)
@@ -5264,7 +5267,7 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
DBUG_RETURN(FALSE);
}
if (((want_access & ~sctx->master_access) & ~(DB_ACLS | EXTRA_ACL)) ||
- ! db && dont_check_global_grants)
+ (! db && dont_check_global_grants))
{ // We can never grant this
DBUG_PRINT("error",("No possible access"));
if (!no_errors)
@@ -5542,7 +5545,7 @@ bool check_some_access(THD *thd, ulong want_access, TABLE_LIST *table)
if (!check_access(thd, access, table->db,
&table->grant.privilege, 0, 1,
test(table->schema_table)) &&
- !check_grant(thd, access, table, 0, 1, 1))
+ !check_grant(thd, access, table, 0, 1, 1))
DBUG_RETURN(0);
}
}
@@ -5798,7 +5801,7 @@ mysql_new_select(LEX *lex, bool move_down)
/*
Don't evaluate this subquery during statement prepare even if
it's a constant one. The flag is switched off in the end of
- mysql_stmt_prepare.
+ mysqld_stmt_prepare.
*/
if (thd->stmt_arena->is_stmt_prepare())
select_lex->uncacheable|= UNCACHEABLE_PREPARE;
@@ -7873,7 +7876,7 @@ bool parse_sql(THD *thd,
/* Check that if MYSQLparse() failed, thd->is_error() is set. */
DBUG_ASSERT(!mysql_parse_status ||
- mysql_parse_status && thd->is_error());
+ (mysql_parse_status && thd->is_error()));
/* Reset parser state. */
diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc
index 4a50650b6f4..284eaebbe87 100644
--- a/sql/sql_partition.cc
+++ b/sql/sql_partition.cc
@@ -918,6 +918,9 @@ bool fix_fields_part_func(THD *thd, Item* func_expr, TABLE *table,
Set-up the TABLE_LIST object to be a list with a single table
Set the object to zero to create NULL pointers and set alias
and real name to table name and get database name from file name.
+ TODO: Consider generalizing or refactoring Lex::add_table_to_list() so
+ it can be used in all places where we create TABLE_LIST objects.
+ Also consider creating appropriate constructors for TABLE_LIST.
*/
bzero((void*)&tables, sizeof(TABLE_LIST));
@@ -925,6 +928,13 @@ bool fix_fields_part_func(THD *thd, Item* func_expr, TABLE *table,
tables.table= table;
tables.next_local= 0;
tables.next_name_resolution_table= 0;
+ /*
+ Cache the table in Item_fields. All the tables can be cached except
+ the trigger pseudo table.
+ */
+ tables.cacheable_table= TRUE;
+ context= thd->lex->current_context();
+ tables.select_lex= context->select_lex;
strmov(db_name_string, table->s->normalized_path.str);
dir_length= dirname_length(db_name_string);
db_name_string[dir_length - 1]= 0;
@@ -932,7 +942,6 @@ bool fix_fields_part_func(THD *thd, Item* func_expr, TABLE *table,
db_name= &db_name_string[home_dir_length];
tables.db= db_name;
- context= thd->lex->current_context();
table->map= 1; //To ensure correct calculation of const item
table->get_fields_in_item_tree= TRUE;
save_table_list= context->table_list;
@@ -964,8 +973,9 @@ bool fix_fields_part_func(THD *thd, Item* func_expr, TABLE *table,
save_use_only_table_context= thd->lex->use_only_table_context;
thd->lex->use_only_table_context= TRUE;
+ thd->lex->current_select->cur_pos_in_select_list= UNDEF_POS;
- error= func_expr->fix_fields(thd, (Item**)0);
+ error= func_expr->fix_fields(thd, (Item**)&func_expr);
thd->lex->use_only_table_context= save_use_only_table_context;
@@ -5090,7 +5100,7 @@ static bool mysql_change_partitions(ALTER_PARTITION_PARAM_TYPE *lpt)
handler *file= lpt->table->file;
DBUG_ENTER("mysql_change_partitions");
- build_table_filename(path, sizeof(path), lpt->db, lpt->table_name, "", 0);
+ build_table_filename(path, sizeof(path) - 1, lpt->db, lpt->table_name, "", 0);
if ((error= file->ha_change_partitions(lpt->create_info, path, &lpt->copied,
&lpt->deleted, lpt->pack_frm_data,
lpt->pack_frm_len)))
@@ -5130,7 +5140,7 @@ static bool mysql_rename_partitions(ALTER_PARTITION_PARAM_TYPE *lpt)
int error;
DBUG_ENTER("mysql_rename_partitions");
- build_table_filename(path, sizeof(path), lpt->db, lpt->table_name, "", 0);
+ build_table_filename(path, sizeof(path) - 1, lpt->db, lpt->table_name, "", 0);
if ((error= lpt->table->file->ha_rename_partitions(path)))
{
if (error != 1)
@@ -5171,7 +5181,7 @@ static bool mysql_drop_partitions(ALTER_PARTITION_PARAM_TYPE *lpt)
int error;
DBUG_ENTER("mysql_drop_partitions");
- build_table_filename(path, sizeof(path), lpt->db, lpt->table_name, "", 0);
+ build_table_filename(path, sizeof(path) - 1, lpt->db, lpt->table_name, "", 0);
if ((error= lpt->table->file->ha_drop_partitions(path)))
{
lpt->table->file->print_error(error, MYF(0));
@@ -5516,10 +5526,10 @@ static bool write_log_drop_shadow_frm(ALTER_PARTITION_PARAM_TYPE *lpt)
partition_info *part_info= lpt->part_info;
DDL_LOG_MEMORY_ENTRY *log_entry;
DDL_LOG_MEMORY_ENTRY *exec_log_entry= NULL;
- char shadow_path[FN_REFLEN];
+ char shadow_path[FN_REFLEN + 1];
DBUG_ENTER("write_log_drop_shadow_frm");
- build_table_shadow_filename(shadow_path, sizeof(shadow_path), lpt);
+ build_table_shadow_filename(shadow_path, sizeof(shadow_path) - 1, lpt);
pthread_mutex_lock(&LOCK_gdl);
if (write_log_replace_delete_frm(lpt, 0UL, NULL,
(const char*)shadow_path, FALSE))
@@ -5559,15 +5569,15 @@ static bool write_log_rename_frm(ALTER_PARTITION_PARAM_TYPE *lpt)
partition_info *part_info= lpt->part_info;
DDL_LOG_MEMORY_ENTRY *log_entry;
DDL_LOG_MEMORY_ENTRY *exec_log_entry= part_info->exec_log_entry;
- char path[FN_REFLEN];
- char shadow_path[FN_REFLEN];
+ char path[FN_REFLEN + 1];
+ char shadow_path[FN_REFLEN + 1];
DDL_LOG_MEMORY_ENTRY *old_first_log_entry= part_info->first_log_entry;
DBUG_ENTER("write_log_rename_frm");
part_info->first_log_entry= NULL;
- build_table_filename(path, sizeof(path), lpt->db,
+ build_table_filename(path, sizeof(path) - 1, lpt->db,
lpt->table_name, "", 0);
- build_table_shadow_filename(shadow_path, sizeof(shadow_path), lpt);
+ build_table_shadow_filename(shadow_path, sizeof(shadow_path) - 1, lpt);
pthread_mutex_lock(&LOCK_gdl);
if (write_log_replace_delete_frm(lpt, 0UL, shadow_path, path, TRUE))
goto error;
@@ -5610,16 +5620,16 @@ static bool write_log_drop_partition(ALTER_PARTITION_PARAM_TYPE *lpt)
partition_info *part_info= lpt->part_info;
DDL_LOG_MEMORY_ENTRY *log_entry;
DDL_LOG_MEMORY_ENTRY *exec_log_entry= part_info->exec_log_entry;
- char tmp_path[FN_REFLEN];
- char path[FN_REFLEN];
+ char tmp_path[FN_REFLEN + 1];
+ char path[FN_REFLEN + 1];
uint next_entry= 0;
DDL_LOG_MEMORY_ENTRY *old_first_log_entry= part_info->first_log_entry;
DBUG_ENTER("write_log_drop_partition");
part_info->first_log_entry= NULL;
- build_table_filename(path, sizeof(path), lpt->db,
+ build_table_filename(path, sizeof(path) - 1, lpt->db,
lpt->table_name, "", 0);
- build_table_filename(tmp_path, sizeof(tmp_path), lpt->db,
+ build_table_filename(tmp_path, sizeof(tmp_path) - 1, lpt->db,
lpt->table_name, "#", 0);
pthread_mutex_lock(&LOCK_gdl);
if (write_log_dropped_partitions(lpt, &next_entry, (const char*)path,
@@ -5669,14 +5679,14 @@ static bool write_log_add_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt)
partition_info *part_info= lpt->part_info;
DDL_LOG_MEMORY_ENTRY *log_entry;
DDL_LOG_MEMORY_ENTRY *exec_log_entry= NULL;
- char tmp_path[FN_REFLEN];
- char path[FN_REFLEN];
+ char tmp_path[FN_REFLEN + 1];
+ char path[FN_REFLEN + 1];
uint next_entry= 0;
DBUG_ENTER("write_log_add_change_partition");
- build_table_filename(path, sizeof(path), lpt->db,
+ build_table_filename(path, sizeof(path) - 1, lpt->db,
lpt->table_name, "", 0);
- build_table_filename(tmp_path, sizeof(tmp_path), lpt->db,
+ build_table_filename(tmp_path, sizeof(tmp_path) - 1, lpt->db,
lpt->table_name, "#", 0);
pthread_mutex_lock(&LOCK_gdl);
if (write_log_dropped_partitions(lpt, &next_entry, (const char*)path,
@@ -5723,16 +5733,16 @@ static bool write_log_final_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt)
partition_info *part_info= lpt->part_info;
DDL_LOG_MEMORY_ENTRY *log_entry;
DDL_LOG_MEMORY_ENTRY *exec_log_entry= part_info->exec_log_entry;
- char path[FN_REFLEN];
- char shadow_path[FN_REFLEN];
+ char path[FN_REFLEN + 1];
+ char shadow_path[FN_REFLEN + 1];
DDL_LOG_MEMORY_ENTRY *old_first_log_entry= part_info->first_log_entry;
uint next_entry= 0;
DBUG_ENTER("write_log_final_change_partition");
part_info->first_log_entry= NULL;
- build_table_filename(path, sizeof(path), lpt->db,
+ build_table_filename(path, sizeof(path) - 1, lpt->db,
lpt->table_name, "", 0);
- build_table_shadow_filename(shadow_path, sizeof(shadow_path), lpt);
+ build_table_shadow_filename(shadow_path, sizeof(shadow_path) - 1, lpt);
pthread_mutex_lock(&LOCK_gdl);
if (write_log_dropped_partitions(lpt, &next_entry, (const char*)path,
lpt->alter_info->flags & ALTER_REORGANIZE_PARTITION))
diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc
index 1465b6d2d30..da168d36429 100644
--- a/sql/sql_plugin.cc
+++ b/sql/sql_plugin.cc
@@ -29,6 +29,18 @@
extern struct st_mysql_plugin *mysqld_builtins[];
+/**
+ @note The order of the enumeration is critical.
+ @see construct_options
+*/
+static const char *global_plugin_typelib_names[]=
+ { "OFF", "ON", "FORCE", NULL };
+enum enum_plugin_load_policy {PLUGIN_OFF, PLUGIN_ON, PLUGIN_FORCE};
+static TYPELIB global_plugin_typelib=
+ { array_elements(global_plugin_typelib_names)-1,
+ "", global_plugin_typelib_names, NULL };
+
+
char *opt_plugin_load= NULL;
char *opt_plugin_dir_ptr;
char opt_plugin_dir[FN_REFLEN];
@@ -192,7 +204,7 @@ static void plugin_load(MEM_ROOT *tmp_root, int *argc, char **argv);
static bool plugin_load_list(MEM_ROOT *tmp_root, int *argc, char **argv,
const char *list);
static int test_plugin_options(MEM_ROOT *, struct st_plugin_int *,
- int *, char **, my_bool);
+ int *, char **);
static bool register_builtin(struct st_mysql_plugin *, struct st_plugin_int *,
struct st_plugin_int **);
static void unlock_variables(THD *thd, struct system_variables *vars);
@@ -751,7 +763,7 @@ static bool plugin_add(MEM_ROOT *tmp_root,
tmp.name.length= name_len;
tmp.ref_count= 0;
tmp.state= PLUGIN_IS_UNINITIALIZED;
- if (test_plugin_options(tmp_root, &tmp, argc, argv, true))
+ if (test_plugin_options(tmp_root, &tmp, argc, argv))
tmp.state= PLUGIN_IS_DISABLED;
if ((tmp_plugin_ptr= plugin_insert_or_reuse(&tmp)))
@@ -997,7 +1009,6 @@ static int plugin_initialize(struct st_plugin_int *plugin)
DBUG_ENTER("plugin_initialize");
safe_mutex_assert_owner(&LOCK_plugin);
-
if (plugin_type_initialize[plugin->plugin->type])
{
if ((*plugin_type_initialize[plugin->plugin->type])(plugin))
@@ -1083,6 +1094,20 @@ uchar *get_bookmark_hash_key(const uchar *buff, size_t *length,
return (uchar*) var->key;
}
+static inline void convert_dash_to_underscore(char *str, int len)
+{
+ for (char *p= str; p <= str+len; p++)
+ if (*p == '-')
+ *p= '_';
+}
+
+static inline void convert_underscore_to_dash(char *str, int len)
+{
+ for (char *p= str; p <= str+len; p++)
+ if (*p == '_')
+ *p= '-';
+}
+
/*
The logic is that we first load and initialize all compiled in plugins.
@@ -1094,11 +1119,12 @@ uchar *get_bookmark_hash_key(const uchar *buff, size_t *length,
int plugin_init(int *argc, char **argv, int flags)
{
uint i;
- bool def_enabled, is_myisam;
+ bool is_myisam;
struct st_mysql_plugin **builtins;
struct st_mysql_plugin *plugin;
struct st_plugin_int tmp, *plugin_ptr, **reap;
MEM_ROOT tmp_root;
+ bool reaped_mandatory_plugin= FALSE;
DBUG_ENTER("plugin_init");
if (initialized)
@@ -1142,17 +1168,13 @@ int plugin_init(int *argc, char **argv, int flags)
!my_strnncoll(&my_charset_latin1, (const uchar*) plugin->name,
6, (const uchar*) "InnoDB", 6))
continue;
- /* by default, ndbcluster and federated are disabled */
- def_enabled=
- my_strcasecmp(&my_charset_latin1, plugin->name, "NDBCLUSTER") != 0 &&
- my_strcasecmp(&my_charset_latin1, plugin->name, "FEDERATED") != 0;
bzero(&tmp, sizeof(tmp));
tmp.plugin= plugin;
tmp.name.str= (char *)plugin->name;
tmp.name.length= strlen(plugin->name);
tmp.state= 0;
free_root(&tmp_root, MYF(MY_MARK_BLOCKS_FREE));
- if (test_plugin_options(&tmp_root, &tmp, argc, argv, def_enabled))
+ if (test_plugin_options(&tmp_root, &tmp, argc, argv))
tmp.state= PLUGIN_IS_DISABLED;
else
tmp.state= PLUGIN_IS_UNINITIALIZED;
@@ -1227,6 +1249,8 @@ int plugin_init(int *argc, char **argv, int flags)
while ((plugin_ptr= *(--reap)))
{
pthread_mutex_unlock(&LOCK_plugin);
+ if (plugin_ptr->is_mandatory)
+ reaped_mandatory_plugin= TRUE;
plugin_deinitialize(plugin_ptr, true);
pthread_mutex_lock(&LOCK_plugin);
plugin_del(plugin_ptr);
@@ -1234,6 +1258,8 @@ int plugin_init(int *argc, char **argv, int flags)
pthread_mutex_unlock(&LOCK_plugin);
my_afree(reap);
+ if (reaped_mandatory_plugin)
+ goto err;
end:
free_root(&tmp_root, MYF(0));
@@ -1299,7 +1325,7 @@ bool plugin_register_builtin(THD *thd, struct st_mysql_plugin *plugin)
pthread_mutex_lock(&LOCK_plugin);
rw_wrlock(&LOCK_system_variables_hash);
- if (test_plugin_options(thd->mem_root, &tmp, &dummy_argc, NULL, true))
+ if (test_plugin_options(thd->mem_root, &tmp, &dummy_argc, NULL))
goto end;
tmp.state= PLUGIN_IS_UNINITIALIZED;
if ((result= register_builtin(plugin, &tmp, &ptr)))
@@ -2889,59 +2915,78 @@ my_bool get_one_plugin_option(int optid __attribute__((unused)),
}
+/**
+ Creates a set of my_option objects associated with a specified plugin-
+ handle.
+
+ @param mem_root Memory allocator to be used.
+ @param tmp A pointer to a plugin handle
+ @param[out] options A pointer to a pre-allocated static array
+
+ The set is stored in the pre-allocated static array supplied to the function.
+ The size of the array is calculated as (number_of_plugin_varaibles*2+3). The
+ reason is that each option can have a prefix '--plugin-' in addtion to the
+ shorter form '--<plugin-name>'. There is also space allocated for
+ terminating NULL pointers.
+
+ @return
+ @retval -1 An error occurred
+ @retval 0 Success
+*/
+
static int construct_options(MEM_ROOT *mem_root, struct st_plugin_int *tmp,
- my_option *options, my_bool **enabled,
- bool can_disable)
+ my_option *options)
{
const char *plugin_name= tmp->plugin->name;
- uint namelen= strlen(plugin_name), optnamelen;
- uint buffer_length= namelen * 4 + (can_disable ? 75 : 10);
- char *name= (char*) alloc_root(mem_root, buffer_length) + 1;
- char *optname, *p;
+ const LEX_STRING plugin_dash = { C_STRING_WITH_LEN("plugin-") };
+ uint plugin_name_len= strlen(plugin_name);
+ uint optnamelen;
+ const int max_comment_len= 180;
+ char *comment= (char *) alloc_root(mem_root, max_comment_len + 1);
+ char *optname;
+
int index= 0, offset= 0;
st_mysql_sys_var *opt, **plugin_option;
st_bookmark *v;
+
+ /** Used to circumvent the const attribute on my_option::name */
+ char *plugin_name_ptr, *plugin_name_with_prefix_ptr;
+
DBUG_ENTER("construct_options");
- DBUG_PRINT("plugin", ("plugin: '%s' enabled: %d can_disable: %d",
- plugin_name, **enabled, can_disable));
+ options[0].name= plugin_name_ptr= (char*) alloc_root(mem_root,
+ plugin_name_len + 1);
+ strcpy(plugin_name_ptr, plugin_name);
+ my_casedn_str(&my_charset_latin1, plugin_name_ptr);
+ convert_underscore_to_dash(plugin_name_ptr, plugin_name_len);
/* support --skip-plugin-foo syntax */
- memcpy(name, plugin_name, namelen + 1);
- my_casedn_str(&my_charset_latin1, name);
- strxmov(name + namelen + 1, "plugin-", name, NullS);
- /* Now we have namelen + 1 + 7 + namelen + 1 == namelen * 2 + 9. */
+ options[1].name= plugin_name_with_prefix_ptr= (char*) alloc_root(mem_root,
+ plugin_name_len +
+ plugin_dash.length + 1);
+ strxmov(plugin_name_with_prefix_ptr, plugin_dash.str, options[0].name, NullS);
- for (p= name + namelen*2 + 8; p > name; p--)
- if (*p == '_')
- *p= '-';
+ options[0].id= options[1].id= 256; /* must be >255. dup id ok */
+ options[0].var_type= options[1].var_type= GET_ENUM;
+ options[0].arg_type= options[1].arg_type= OPT_ARG;
+ options[0].def_value= options[1].def_value= 1; /* ON */
+ options[0].typelib= options[1].typelib= &global_plugin_typelib;
- if (can_disable)
- {
- strxmov(name + namelen*2 + 10, "Enable ", plugin_name, " plugin. "
- "Disable with --skip-", name," (will save memory).", NullS);
- /*
- Now we have namelen * 2 + 10 (one char unused) + 7 + namelen + 9 +
- 20 + namelen + 20 + 1 == namelen * 4 + 67.
- */
-
- options[0].comment= name + namelen*2 + 10;
- }
+ strxnmov(comment, max_comment_len, "Enable or disable ", plugin_name,
+ " plugin. Possible values are ON, OFF, FORCE (don't start "
+ "if the plugin fails to load).", NullS);
+ options[0].comment= comment;
/*
- NOTE: 'name' is one char above the allocated buffer!
- NOTE: This code assumes that 'my_bool' and 'char' are of same size.
+ Allocate temporary space for the value of the tristate.
+ This option will have a limited lifetime and is not used beyond
+ server initialization.
+ GET_ENUM value is an integer.
*/
- *((my_bool *)(name -1))= **enabled;
- *enabled= (my_bool *)(name - 1);
+ options[0].value= options[1].value= (uchar **)alloc_root(mem_root,
+ sizeof(int));
+ *((uint*) options[0].value)= *((uint*) options[1].value)=
+ (uint) options[0].def_value;
-
- options[1].name= (options[0].name= name) + namelen + 1;
- options[0].id= options[1].id= 256; /* must be >255. dup id ok */
- options[0].var_type= options[1].var_type= GET_BOOL;
- options[0].arg_type= options[1].arg_type= NO_ARG;
- options[0].def_value= options[1].def_value= **enabled;
- options[0].value= options[0].u_max_value=
- options[1].value= options[1].u_max_value= (uchar**) (name - 1);
options+= 2;
/*
@@ -2955,7 +3000,7 @@ static int construct_options(MEM_ROOT *mem_root, struct st_plugin_int *tmp,
opt= *plugin_option;
if (!(opt->flags & PLUGIN_VAR_THDLOCAL))
continue;
- if (!(register_var(name, opt->name, opt->flags)))
+ if (!(register_var(plugin_name_ptr, opt->name, opt->flags)))
continue;
switch (opt->flags & PLUGIN_VAR_TYPEMASK) {
case PLUGIN_VAR_BOOL:
@@ -3020,7 +3065,7 @@ static int construct_options(MEM_ROOT *mem_root, struct st_plugin_int *tmp,
if (!opt->update)
{
opt->update= update_func_str;
- if (!(opt->flags & PLUGIN_VAR_MEMALLOC | PLUGIN_VAR_READONLY))
+ if (!(opt->flags & (PLUGIN_VAR_MEMALLOC | PLUGIN_VAR_READONLY)))
{
opt->flags|= PLUGIN_VAR_READONLY;
sql_print_warning("Server variable %s of plugin %s was forced "
@@ -3062,14 +3107,14 @@ static int construct_options(MEM_ROOT *mem_root, struct st_plugin_int *tmp,
if (!(opt->flags & PLUGIN_VAR_THDLOCAL))
{
optnamelen= strlen(opt->name);
- optname= (char*) alloc_root(mem_root, namelen + optnamelen + 2);
- strxmov(optname, name, "-", opt->name, NullS);
- optnamelen= namelen + optnamelen + 1;
+ optname= (char*) alloc_root(mem_root, plugin_name_len + optnamelen + 2);
+ strxmov(optname, plugin_name_ptr, "-", opt->name, NullS);
+ optnamelen= plugin_name_len + optnamelen + 1;
}
else
{
/* this should not fail because register_var should create entry */
- if (!(v= find_bookmark(name, opt->name, opt->flags)))
+ if (!(v= find_bookmark(plugin_name_ptr, opt->name, opt->flags)))
{
sql_print_error("Thread local variable '%s' not allocated "
"in plugin '%s'.", opt->name, plugin_name);
@@ -3085,10 +3130,7 @@ static int construct_options(MEM_ROOT *mem_root, struct st_plugin_int *tmp,
(optnamelen= v->name_len) + 1);
}
- /* convert '_' to '-' */
- for (p= optname; *p; p++)
- if (*p == '_')
- *p= '-';
+ convert_underscore_to_dash(optname, optnamelen);
options->name= optname;
options->comment= opt->comment;
@@ -3103,10 +3145,13 @@ static int construct_options(MEM_ROOT *mem_root, struct st_plugin_int *tmp,
else
options->value= options->u_max_value= *(uchar***) (opt + 1);
+ char *option_name_ptr;
options[1]= options[0];
- options[1].name= p= (char*) alloc_root(mem_root, optnamelen + 8);
- options[1].comment= 0; // hidden
- strxmov(p, "plugin-", optname, NullS);
+ options[1].name= option_name_ptr= (char*) alloc_root(mem_root,
+ plugin_dash.length +
+ optnamelen + 1);
+ options[1].comment= 0; /* Hidden from the help text */
+ strxmov(option_name_ptr, plugin_dash.str, optname, NullS);
options+= 2;
}
@@ -3120,55 +3165,57 @@ static my_option *construct_help_options(MEM_ROOT *mem_root,
{
st_mysql_sys_var **opt;
my_option *opts;
- my_bool dummy, can_disable;
- my_bool *dummy2= &dummy;
uint count= EXTRA_OPTIONS;
DBUG_ENTER("construct_help_options");
- for (opt= p->plugin->system_vars; opt && *opt; opt++, count+= 2);
+ for (opt= p->plugin->system_vars; opt && *opt; opt++, count+= 2)
+ ;
if (!(opts= (my_option*) alloc_root(mem_root, sizeof(my_option) * count)))
DBUG_RETURN(NULL);
bzero(opts, sizeof(my_option) * count);
- dummy= TRUE; /* plugin is enabled. */
-
- can_disable=
- my_strcasecmp(&my_charset_latin1, p->name.str, "MyISAM") &&
- my_strcasecmp(&my_charset_latin1, p->name.str, "MEMORY");
-
- if (construct_options(mem_root, p, opts, &dummy2, can_disable))
+ if (construct_options(mem_root, p, opts))
DBUG_RETURN(NULL);
DBUG_RETURN(opts);
}
-/*
- SYNOPSIS
- test_plugin_options()
- tmp_root temporary scratch space
- plugin internal plugin structure
- argc user supplied arguments
- argv user supplied arguments
- default_enabled default plugin enable status
- RETURNS:
- 0 SUCCESS - plugin should be enabled/loaded
- NOTE:
- Requires that a write-lock is held on LOCK_system_variables_hash
+/**
+ Create and register system variables supplied from the plugin and
+ assigns initial values from corresponding command line arguments.
+
+ @param tmp_root Temporary scratch space
+ @param[out] plugin Internal plugin structure
+ @param argc Number of command line arguments
+ @param argv Command line argument vector
+
+ The plugin will be updated with a policy on how to handle errors during
+ initialization.
+
+ @note Requires that a write-lock is held on LOCK_system_variables_hash
+
+ @return How initialization of the plugin should be handled.
+ @retval 0 Initialization should proceed.
+ @retval 1 Plugin is disabled.
+ @retval -1 An error has occurred.
*/
+
static int test_plugin_options(MEM_ROOT *tmp_root, struct st_plugin_int *tmp,
- int *argc, char **argv, my_bool default_enabled)
+ int *argc, char **argv)
{
struct sys_var_chain chain= { NULL, NULL };
- my_bool enabled_saved= default_enabled, can_disable;
- my_bool *enabled= &default_enabled;
+ my_bool can_disable;
+ bool disable_plugin;
+ enum_plugin_load_policy plugin_load_policy= PLUGIN_ON;
+
MEM_ROOT *mem_root= alloc_root_inited(&tmp->mem_root) ?
&tmp->mem_root : &plugin_mem_root;
st_mysql_sys_var **opt;
my_option *opts= NULL;
- char *p, *varname;
+ char *varname;
int error;
st_mysql_sys_var *o;
sys_var *v;
@@ -3177,13 +3224,17 @@ static int test_plugin_options(MEM_ROOT *tmp_root, struct st_plugin_int *tmp,
DBUG_ENTER("test_plugin_options");
DBUG_ASSERT(tmp->plugin && tmp->name.str);
+ /*
+ The 'federated' and 'ndbcluster' storage engines are always disabled by
+ default.
+ */
+ if (!(my_strcasecmp(&my_charset_latin1, tmp->name.str, "federated") &&
+ my_strcasecmp(&my_charset_latin1, tmp->name.str, "ndbcluster")))
+ plugin_load_policy= PLUGIN_OFF;
+
for (opt= tmp->plugin->system_vars; opt && *opt; opt++)
count+= 2; /* --{plugin}-{optname} and --plugin-{plugin}-{optname} */
- can_disable=
- my_strcasecmp(&my_charset_latin1, tmp->name.str, "MyISAM") &&
- my_strcasecmp(&my_charset_latin1, tmp->name.str, "MEMORY");
-
if (count > EXTRA_OPTIONS || (*argc > 1))
{
if (!(opts= (my_option*) alloc_root(tmp_root, sizeof(my_option) * count)))
@@ -3193,12 +3244,18 @@ static int test_plugin_options(MEM_ROOT *tmp_root, struct st_plugin_int *tmp,
}
bzero(opts, sizeof(my_option) * count);
- if (construct_options(tmp_root, tmp, opts, &enabled, can_disable))
+ if (construct_options(tmp_root, tmp, opts))
{
sql_print_error("Bad options for plugin '%s'.", tmp->name.str);
DBUG_RETURN(-1);
}
+ /*
+ We adjust the default value to account for the hardcoded exceptions
+ we have set for the federated and ndbcluster storage engines.
+ */
+ opts[0].def_value= opts[1].def_value= (int)plugin_load_policy;
+
error= handle_options(argc, &argv, opts, get_one_plugin_option);
(*argc)++; /* add back one for the program name */
@@ -3208,64 +3265,79 @@ static int test_plugin_options(MEM_ROOT *tmp_root, struct st_plugin_int *tmp,
tmp->name.str);
goto err;
}
+ /*
+ Set plugin loading policy from option value. First element in the option
+ list is always the option value.
+ */
+ plugin_load_policy= (enum_plugin_load_policy)*(uint*)opts[0].value;
}
- if (!*enabled && !can_disable)
+ disable_plugin= (plugin_load_policy == PLUGIN_OFF);
+ /*
+ The 'MyISAM' and 'Memory' storage engines currently can't be disabled.
+ */
+ can_disable=
+ my_strcasecmp(&my_charset_latin1, tmp->name.str, "MyISAM") &&
+ my_strcasecmp(&my_charset_latin1, tmp->name.str, "MEMORY");
+
+ tmp->is_mandatory= (plugin_load_policy == PLUGIN_FORCE) || !can_disable;
+
+ if (disable_plugin && !can_disable)
{
sql_print_warning("Plugin '%s' cannot be disabled", tmp->name.str);
- *enabled= TRUE;
+ disable_plugin= FALSE;
+ }
+
+ /*
+ If the plugin is disabled it should not be initialized.
+ */
+ if (disable_plugin)
+ {
+ if (global_system_variables.log_warnings)
+ sql_print_information("Plugin '%s' is disabled.",
+ tmp->name.str);
+ if (opts)
+ my_cleanup_options(opts);
+ DBUG_RETURN(1);
}
error= 1;
-
- if (*enabled)
+ for (opt= tmp->plugin->system_vars; opt && *opt; opt++)
{
- for (opt= tmp->plugin->system_vars; opt && *opt; opt++)
+ if (((o= *opt)->flags & PLUGIN_VAR_NOSYSVAR))
+ continue;
+ if ((var= find_bookmark(tmp->name.str, o->name, o->flags)))
+ v= new (mem_root) sys_var_pluginvar(var->key + 1, o);
+ else
{
- if (((o= *opt)->flags & PLUGIN_VAR_NOSYSVAR))
- continue;
-
- if ((var= find_bookmark(tmp->name.str, o->name, o->flags)))
- v= new (mem_root) sys_var_pluginvar(var->key + 1, o);
- else
- {
- len= tmp->name.length + strlen(o->name) + 2;
- varname= (char*) alloc_root(mem_root, len);
- strxmov(varname, tmp->name.str, "-", o->name, NullS);
- my_casedn_str(&my_charset_latin1, varname);
-
- for (p= varname; *p; p++)
- if (*p == '-')
- *p= '_';
-
- v= new (mem_root) sys_var_pluginvar(varname, o);
- }
- DBUG_ASSERT(v); /* check that an object was actually constructed */
-
- /*
- Add to the chain of variables.
- Done like this for easier debugging so that the
- pointer to v is not lost on optimized builds.
- */
- v->chain_sys_var(&chain);
+ len= tmp->name.length + strlen(o->name) + 2;
+ varname= (char*) alloc_root(mem_root, len);
+ strxmov(varname, tmp->name.str, "-", o->name, NullS);
+ my_casedn_str(&my_charset_latin1, varname);
+ convert_dash_to_underscore(varname, len-1);
+ v= new (mem_root) sys_var_pluginvar(varname, o);
}
- if (chain.first)
+ DBUG_ASSERT(v); /* check that an object was actually constructed */
+ /*
+ Add to the chain of variables.
+ Done like this for easier debugging so that the
+ pointer to v is not lost on optimized builds.
+ */
+ v->chain_sys_var(&chain);
+ } /* end for */
+ if (chain.first)
+ {
+ chain.last->next = NULL;
+ if (mysql_add_sys_var_chain(chain.first, NULL))
{
- chain.last->next = NULL;
- if (mysql_add_sys_var_chain(chain.first, NULL))
- {
- sql_print_error("Plugin '%s' has conflicting system variables",
- tmp->name.str);
- goto err;
- }
- tmp->system_vars= chain.first;
+ sql_print_error("Plugin '%s' has conflicting system variables",
+ tmp->name.str);
+ goto err;
}
- DBUG_RETURN(0);
+ tmp->system_vars= chain.first;
}
-
- if (enabled_saved && global_system_variables.log_warnings)
- sql_print_information("Plugin '%s' disabled by command line option",
- tmp->name.str);
+ DBUG_RETURN(0);
+
err:
if (opts)
my_cleanup_options(opts);
diff --git a/sql/sql_plugin.h b/sql/sql_plugin.h
index 8ae38d58845..004d0d5abb7 100644
--- a/sql/sql_plugin.h
+++ b/sql/sql_plugin.h
@@ -79,6 +79,7 @@ struct st_plugin_int
void *data; /* plugin type specific, e.g. handlerton */
MEM_ROOT mem_root; /* memory for dynamic plugin structures */
sys_var *system_vars; /* server variables for this plugin */
+ bool is_mandatory; /* If true then plugin must not fail to load */
};
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index 29d948472c7..8921f7c0d82 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -717,9 +717,9 @@ static void setup_one_conversion_function(THD *thd, Item_param *param,
prepared statement, parameter markers are replaced with variable names.
Example:
@verbatim
- mysql_stmt_prepare("UPDATE t1 SET a=a*1.25 WHERE a=?")
+ mysqld_stmt_prepare("UPDATE t1 SET a=a*1.25 WHERE a=?")
--> general logs gets [Prepare] UPDATE t1 SET a*1.25 WHERE a=?"
- mysql_stmt_execute(stmt);
+ mysqld_stmt_execute(stmt);
--> general and binary logs get
[Execute] UPDATE t1 SET a*1.25 WHERE a=1"
@endverbatim
@@ -1435,8 +1435,8 @@ static bool mysql_test_set_fields(Prepared_statement *stmt,
THD *thd= stmt->thd;
set_var_base *var;
- if (tables && check_table_access(thd, SELECT_ACL, tables, UINT_MAX, FALSE) ||
- open_normal_and_derived_tables(thd, tables, 0))
+ if ((tables && check_table_access(thd, SELECT_ACL, tables, UINT_MAX, FALSE))
+ || open_normal_and_derived_tables(thd, tables, 0))
goto error;
while ((var= it++))
@@ -1471,13 +1471,13 @@ static bool mysql_test_call_fields(Prepared_statement *stmt,
THD *thd= stmt->thd;
Item *item;
- if (tables && check_table_access(thd, SELECT_ACL, tables, UINT_MAX, FALSE) ||
+ if ((tables && check_table_access(thd, SELECT_ACL, tables, UINT_MAX, FALSE)) ||
open_normal_and_derived_tables(thd, tables, 0))
goto err;
while ((item= it++))
{
- if (!item->fixed && item->fix_fields(thd, it.ref()) ||
+ if ((!item->fixed && item->fix_fields(thd, it.ref())) ||
item->check_cols(1))
goto err;
}
@@ -2057,11 +2057,11 @@ static bool init_param_array(Prepared_statement *stmt)
to the client, otherwise an error message is set in THD.
*/
-void mysql_stmt_prepare(THD *thd, const char *packet, uint packet_length)
+void mysqld_stmt_prepare(THD *thd, const char *packet, uint packet_length)
{
Prepared_statement *stmt;
bool error;
- DBUG_ENTER("mysql_stmt_prepare");
+ DBUG_ENTER("mysqld_stmt_prepare");
DBUG_PRINT("prep_query", ("%s", packet));
@@ -2228,9 +2228,8 @@ void mysql_sql_stmt_prepare(THD *thd)
LEX_STRING *name= &lex->prepared_stmt_name;
Prepared_statement *stmt;
const char *query;
- uint query_len;
+ uint query_len= 0;
DBUG_ENTER("mysql_sql_stmt_prepare");
- LINT_INIT(query_len);
DBUG_ASSERT(thd->protocol == &thd->protocol_text);
if ((stmt= (Prepared_statement*) thd->stmt_map.find_by_name(name)))
@@ -2424,7 +2423,7 @@ static void reset_stmt_params(Prepared_statement *stmt)
client, otherwise an error message is set in THD.
*/
-void mysql_stmt_execute(THD *thd, char *packet_arg, uint packet_length)
+void mysqld_stmt_execute(THD *thd, char *packet_arg, uint packet_length)
{
uchar *packet= (uchar*)packet_arg; // GCC 4.0.1 workaround
ulong stmt_id= uint4korr(packet);
@@ -2434,7 +2433,7 @@ void mysql_stmt_execute(THD *thd, char *packet_arg, uint packet_length)
uchar *packet_end= packet + packet_length;
Prepared_statement *stmt;
bool open_cursor;
- DBUG_ENTER("mysql_stmt_execute");
+ DBUG_ENTER("mysqld_stmt_execute");
packet+= 9; /* stmt_id + 5 bytes of flags */
@@ -2445,7 +2444,7 @@ void mysql_stmt_execute(THD *thd, char *packet_arg, uint packet_length)
{
char llbuf[22];
my_error(ER_UNKNOWN_STMT_HANDLER, MYF(0), sizeof(llbuf),
- llstr(stmt_id, llbuf), "mysql_stmt_execute");
+ llstr(stmt_id, llbuf), "mysqld_stmt_execute");
DBUG_VOID_RETURN;
}
@@ -2462,6 +2461,9 @@ void mysql_stmt_execute(THD *thd, char *packet_arg, uint packet_length)
stmt->execute_loop(&expanded_query, open_cursor, packet, packet_end);
+ /* Close connection socket; for use with client testing (Bug#43560). */
+ DBUG_EXECUTE_IF("close_conn_after_stmt_execute", vio_close(thd->net.vio););
+
DBUG_VOID_RETURN;
}
@@ -2523,7 +2525,7 @@ void mysql_sql_stmt_execute(THD *thd)
@param packet_length Length of packet
*/
-void mysql_stmt_fetch(THD *thd, char *packet, uint packet_length)
+void mysqld_stmt_fetch(THD *thd, char *packet, uint packet_length)
{
/* assume there is always place for 8-16 bytes */
ulong stmt_id= uint4korr(packet);
@@ -2531,7 +2533,7 @@ void mysql_stmt_fetch(THD *thd, char *packet, uint packet_length)
Prepared_statement *stmt;
Statement stmt_backup;
Server_side_cursor *cursor;
- DBUG_ENTER("mysql_stmt_fetch");
+ DBUG_ENTER("mysqld_stmt_fetch");
/* First of all clear possible warnings from the previous command */
mysql_reset_thd_for_next_command(thd);
@@ -2540,7 +2542,7 @@ void mysql_stmt_fetch(THD *thd, char *packet, uint packet_length)
{
char llbuf[22];
my_error(ER_UNKNOWN_STMT_HANDLER, MYF(0), sizeof(llbuf),
- llstr(stmt_id, llbuf), "mysql_stmt_fetch");
+ llstr(stmt_id, llbuf), "mysqld_stmt_fetch");
DBUG_VOID_RETURN;
}
@@ -2581,9 +2583,9 @@ void mysql_stmt_fetch(THD *thd, char *packet, uint packet_length)
This function resets statement to the state it was right after prepare.
It can be used to:
- - clear an error happened during mysql_stmt_send_long_data
+ - clear an error happened during mysqld_stmt_send_long_data
- cancel long data stream for all placeholders without
- having to call mysql_stmt_execute.
+ having to call mysqld_stmt_execute.
- close an open cursor
Sends 'OK' packet in case of success (statement was reset)
or 'ERROR' packet (unrecoverable error/statement not found/etc).
@@ -2592,12 +2594,12 @@ void mysql_stmt_fetch(THD *thd, char *packet, uint packet_length)
@param packet Packet with stmt id
*/
-void mysql_stmt_reset(THD *thd, char *packet)
+void mysqld_stmt_reset(THD *thd, char *packet)
{
/* There is always space for 4 bytes in buffer */
ulong stmt_id= uint4korr(packet);
Prepared_statement *stmt;
- DBUG_ENTER("mysql_stmt_reset");
+ DBUG_ENTER("mysqld_stmt_reset");
/* First of all clear possible warnings from the previous command */
mysql_reset_thd_for_next_command(thd);
@@ -2607,7 +2609,7 @@ void mysql_stmt_reset(THD *thd, char *packet)
{
char llbuf[22];
my_error(ER_UNKNOWN_STMT_HANDLER, MYF(0), sizeof(llbuf),
- llstr(stmt_id, llbuf), "mysql_stmt_reset");
+ llstr(stmt_id, llbuf), "mysqld_stmt_reset");
DBUG_VOID_RETURN;
}
@@ -2615,7 +2617,7 @@ void mysql_stmt_reset(THD *thd, char *packet)
/*
Clear parameters from data which could be set by
- mysql_stmt_send_long_data() call.
+ mysqld_stmt_send_long_data() call.
*/
reset_stmt_params(stmt);
@@ -2636,12 +2638,12 @@ void mysql_stmt_reset(THD *thd, char *packet)
we don't send any reply to this command.
*/
-void mysql_stmt_close(THD *thd, char *packet)
+void mysqld_stmt_close(THD *thd, char *packet)
{
/* There is always space for 4 bytes in packet buffer */
ulong stmt_id= uint4korr(packet);
Prepared_statement *stmt;
- DBUG_ENTER("mysql_stmt_close");
+ DBUG_ENTER("mysqld_stmt_close");
thd->main_da.disable_status();
@@ -2740,7 +2742,7 @@ void mysql_stmt_get_longdata(THD *thd, char *packet, ulong packet_length)
stmt->state= Query_arena::ERROR;
stmt->last_errno= ER_WRONG_ARGUMENTS;
sprintf(stmt->last_error, ER(ER_WRONG_ARGUMENTS),
- "mysql_stmt_send_long_data");
+ "mysqld_stmt_send_long_data");
DBUG_VOID_RETURN;
}
#endif
@@ -2844,7 +2846,7 @@ void Prepared_statement::setup_set_params()
Decide if we have to expand the query (because we must write it to logs or
because we want to look it up in the query cache) or not.
*/
- if (mysql_bin_log.is_open() && is_update_query(lex->sql_command) ||
+ if ((mysql_bin_log.is_open() && is_update_query(lex->sql_command)) ||
opt_log || opt_slow_log ||
query_cache_is_cacheable_query(lex))
{
@@ -3164,7 +3166,7 @@ Prepared_statement::set_parameters(String *expanded_query,
if (res)
{
my_error(ER_WRONG_ARGUMENTS, MYF(0),
- is_sql_ps ? "EXECUTE" : "mysql_stmt_execute");
+ is_sql_ps ? "EXECUTE" : "mysqld_stmt_execute");
reset_stmt_params(this);
}
return res;
@@ -3295,7 +3297,7 @@ Prepared_statement::reprepare()
&cur_db_changed))
return TRUE;
- error= (name.str && copy.set_name(&name) ||
+ error= ((name.str && copy.set_name(&name)) ||
copy.prepare(query, query_length) ||
validate_metadata(©));
@@ -3626,11 +3628,11 @@ error:
}
-/** Common part of DEALLOCATE PREPARE and mysql_stmt_close. */
+/** Common part of DEALLOCATE PREPARE and mysqld_stmt_close. */
void Prepared_statement::deallocate()
{
- /* We account deallocate in the same manner as mysql_stmt_close */
+ /* We account deallocate in the same manner as mysqld_stmt_close */
status_var_increment(thd->status_var.com_stmt_close);
/* Statement map calls delete stmt on erase */
thd->stmt_map.erase(this);
diff --git a/sql/sql_profile.h b/sql/sql_profile.h
index b5537487d26..245959e0953 100644
--- a/sql/sql_profile.h
+++ b/sql/sql_profile.h
@@ -16,25 +16,12 @@
#ifndef _SQL_PROFILE_H
#define _SQL_PROFILE_H
-#if __STDC_VERSION__ < 199901L
-# if __GNUC__ >= 2
-# define __func__ __FUNCTION__
-# else
-# define __func__ _unknown_func_
-extern const char * const _unknown_func_;
-# endif
-#elif defined(_MSC_VER)
-# if _MSC_VER < 1300
-# define __func__ _unknown_func_
-extern const char * const _unknown_func_;
-# else
-# define __func__ __FUNCTION__
-# endif
-#elif defined(__BORLANDC__)
-# define __func__ __FUNC__
+#ifndef __func__
+#ifdef __FUNCTION__
+#define __func__ __FUNCTION__
#else
-# define __func__ _unknown_func_
-extern const char * const _unknown_func_;
+#define __func__ "unknown function"
+#endif
#endif
extern ST_FIELD_INFO query_profile_statistics_info[];
diff --git a/sql/sql_rename.cc b/sql/sql_rename.cc
index d4331b12cd4..0e0b8eb60b9 100644
--- a/sql/sql_rename.cc
+++ b/sql/sql_rename.cc
@@ -244,7 +244,7 @@ do_rename(THD *thd, TABLE_LIST *ren_table, char *new_db, char *new_table_name,
char *new_table_alias, bool skip_error)
{
int rc= 1;
- char name[FN_REFLEN];
+ char name[FN_REFLEN + 1];
const char *new_alias, *old_alias;
frm_type_enum frm_type;
enum legacy_db_type table_type;
@@ -261,14 +261,16 @@ do_rename(THD *thd, TABLE_LIST *ren_table, char *new_db, char *new_table_name,
old_alias= ren_table->table_name;
new_alias= new_table_name;
}
- build_table_filename(name, sizeof(name),
+ DBUG_ASSERT(new_alias);
+
+ build_table_filename(name, sizeof(name) - 1,
new_db, new_alias, reg_ext, 0);
if (!access(name,F_OK))
{
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_alias);
DBUG_RETURN(1); // This can't be skipped
}
- build_table_filename(name, sizeof(name),
+ build_table_filename(name, sizeof(name) - 1,
ren_table->db, old_alias, reg_ext, 0);
frm_type= mysql_frm_type(thd, name, &table_type);
diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc
index 06c6c022780..476c8aaaefb 100644
--- a/sql/sql_repl.cc
+++ b/sql/sql_repl.cc
@@ -147,7 +147,7 @@ static int send_file(THD *thd)
if (errmsg)
{
sql_print_error("Failed in send_file() %s", errmsg);
- DBUG_PRINT("error", (errmsg));
+ DBUG_PRINT("error", ("%s", errmsg));
}
DBUG_RETURN(error);
}
@@ -1043,6 +1043,7 @@ int reset_slave(THD *thd, Master_info* mi)
Reset errors (the idea is that we forget about the
old master).
*/
+ mi->clear_error();
mi->rli.clear_error();
mi->rli.clear_until_condition();
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index b6cf3848eee..0f2b3183c0c 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -1353,7 +1353,7 @@ JOIN::optimize()
join_tab[const_tables].type != JT_ALL &&
join_tab[const_tables].type != JT_FT &&
join_tab[const_tables].type != JT_REF_OR_NULL &&
- (order && simple_order || group_list && simple_group))
+ ((order && simple_order) || (group_list && simple_group)))
{
if (add_ref_to_table_cond(thd,&join_tab[const_tables])) {
DBUG_RETURN(1);
@@ -1871,9 +1871,9 @@ JOIN::exec()
like SEC_TO_TIME(SUM(...)).
*/
- if (curr_join->group_list && (!test_if_subpart(curr_join->group_list,
+ if ((curr_join->group_list && (!test_if_subpart(curr_join->group_list,
curr_join->order) ||
- curr_join->select_distinct) ||
+ curr_join->select_distinct)) ||
(curr_join->select_distinct &&
curr_join->tmp_table_param.using_indirect_summary_function))
{ /* Must copy to another table */
@@ -2251,6 +2251,14 @@ JOIN::destroy()
cond_equal= 0;
cleanup(1);
+ /* Cleanup items referencing temporary table columns */
+ if (!tmp_all_fields3.is_empty())
+ {
+ List_iterator_fast
- it(tmp_all_fields3);
+ Item *item;
+ while ((item= it++))
+ item->cleanup();
+ }
if (exec_tmp_table1)
free_tmp_table(thd, exec_tmp_table1);
if (exec_tmp_table2)
@@ -2339,9 +2347,10 @@ mysql_select(THD *thd, Item ***rref_pointer_array,
}
else
{
- if (err= join->prepare(rref_pointer_array, tables, wild_num,
- conds, og_num, order, group, having, proc_param,
- select_lex, unit))
+ err= join->prepare(rref_pointer_array, tables, wild_num,
+ conds, og_num, order, group, having, proc_param,
+ select_lex, unit);
+ if (err)
{
goto err;
}
@@ -2356,9 +2365,10 @@ mysql_select(THD *thd, Item ***rref_pointer_array,
DBUG_RETURN(TRUE);
thd_proc_info(thd, "init");
thd->used_tables=0; // Updated by setup_fields
- if (err= join->prepare(rref_pointer_array, tables, wild_num,
- conds, og_num, order, group, having, proc_param,
- select_lex, unit))
+ err= join->prepare(rref_pointer_array, tables, wild_num,
+ conds, og_num, order, group, having, proc_param,
+ select_lex, unit);
+ if (err)
{
goto err;
}
@@ -2425,7 +2435,6 @@ static ha_rows get_quick_record_count(THD *thd, SQL_SELECT *select,
if (select)
{
select->head=table;
- table->reginfo.impossible_range=0;
if ((error= select->test_quick_select(thd, *(key_map *)keys,(table_map) 0,
limit, 0)) == 1)
DBUG_RETURN(select->quick->records);
@@ -3836,7 +3845,7 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab,
if (use->key == prev->key && use->table == prev->table)
{
if (prev->keypart+1 < use->keypart ||
- prev->keypart == use->keypart && found_eq_constant)
+ (prev->keypart == use->keypart && found_eq_constant))
continue; /* remove */
}
else if (use->keypart != 0) // First found must be 0
@@ -5141,8 +5150,8 @@ best_extension_by_limited_search(JOIN *join,
{
if (best_record_count > current_record_count ||
best_read_time > current_read_time ||
- idx == join->const_tables && // 's' is the first table in the QEP
- s->table == join->sort_by_table)
+ (idx == join->const_tables && // 's' is the first table in the QEP
+ s->table == join->sort_by_table))
{
if (best_record_count >= current_record_count &&
best_read_time >= current_read_time &&
@@ -5268,7 +5277,7 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count,
double current_read_time=read_time+best;
if (best_record_count > current_record_count ||
best_read_time > current_read_time ||
- idx == join->const_tables && s->table == join->sort_by_table)
+ (idx == join->const_tables && s->table == join->sort_by_table))
{
if (best_record_count >= current_record_count &&
best_read_time >= current_read_time &&
@@ -6215,8 +6224,8 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
the index if we are using limit and this is the first table
*/
- if (cond &&
- (!tab->keys.is_subset(tab->const_keys) && i > 0) ||
+ if ((cond &&
+ !tab->keys.is_subset(tab->const_keys) && i > 0) ||
(!tab->const_keys.is_clear_all() && i == join->const_tables &&
join->unit->select_limit_cnt <
join->best_positions[i].records_read &&
@@ -7087,15 +7096,17 @@ return_zero_rows(JOIN *join, select_result *result,TABLE_LIST *tables,
if (!(result->send_fields(fields,
Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF)))
{
+ bool send_error= FALSE;
if (send_row)
{
List_iterator_fast
- it(fields);
Item *item;
while ((item= it++))
item->no_rows_in_result();
- result->send_data(fields);
+ send_error= result->send_data(fields);
}
- result->send_eof(); // Should be safe
+ if (!send_error)
+ result->send_eof(); // Should be safe
}
/* Update results for FOUND_ROWS */
join->thd->limit_found_rows= join->thd->examined_row_count= 0;
@@ -7347,7 +7358,7 @@ static bool check_simple_equality(Item *left_item, Item *right_item,
left_item_equal->merge(right_item_equal);
/* Remove the merged multiple equality from the list */
List_iterator li(cond_equal->current_level);
- while ((li++) != right_item_equal);
+ while ((li++) != right_item_equal) ;
li.remove();
}
}
@@ -9383,13 +9394,17 @@ static Field *create_tmp_field_from_item(THD *thd, Item *item, TABLE *table,
+1: for decimal point
*/
- overflow= my_decimal_precision_to_length(intg + dec, dec,
- item->unsigned_flag) - len;
+ const int required_length=
+ my_decimal_precision_to_length(intg + dec, dec,
+ item->unsigned_flag);
+
+ overflow= required_length - len;
if (overflow > 0)
dec= max(0, dec - overflow); // too long, discard fract
else
- len -= item->decimals - dec; // corrected value fits
+ /* Corrected value fits. */
+ len= required_length;
}
new_field= new Field_new_decimal(len, maybe_null, item->name,
@@ -10025,9 +10040,9 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List
- &fields,
reclength=1; // Dummy select
/* Use packed rows if there is blobs or a lot of space to gain */
if (blob_count ||
- string_total_length >= STRING_TOTAL_LENGTH_TO_PACK_ROWS &&
+ (string_total_length >= STRING_TOTAL_LENGTH_TO_PACK_ROWS &&
(reclength / string_total_length <= RATIO_TO_PACK_ROWS ||
- string_total_length / string_count >= AVG_STRING_LENGTH_TO_PACK_ROWS))
+ string_total_length / string_count >= AVG_STRING_LENGTH_TO_PACK_ROWS)))
use_packed_rows= 1;
share->reclength= reclength;
@@ -10828,9 +10843,8 @@ do_select(JOIN *join,List
- *fields,TABLE *table,Procedure *procedure)
{
int rc= 0;
enum_nested_loop_state error= NESTED_LOOP_OK;
- JOIN_TAB *join_tab;
+ JOIN_TAB *join_tab= NULL;
DBUG_ENTER("do_select");
- LINT_INIT(join_tab);
join->procedure=procedure;
join->tmp_table= table; /* Save for easy recursion */
@@ -12651,7 +12665,10 @@ static int test_if_order_by_key(ORDER *order, TABLE *table, uint idx,
one row). The sorting doesn't matter.
*/
if (key_part == key_part_end && reverse == 0)
+ {
+ *used_key_parts= 0;
DBUG_RETURN(1);
+ }
}
else
DBUG_RETURN(0);
@@ -13066,9 +13083,9 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
*/
uint nr;
key_map keys;
- uint best_key_parts;
- int best_key_direction;
- ha_rows best_records;
+ uint best_key_parts= 0;
+ int best_key_direction= 0;
+ ha_rows best_records= 0;
double read_time;
int best_key= -1;
bool is_best_covering= FALSE;
@@ -13078,9 +13095,6 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
ha_rows table_records= table->file->stats.records;
bool group= join->group && order == join->group_list;
ha_rows ref_key_quick_rows= HA_POS_ERROR;
- LINT_INIT(best_key_parts);
- LINT_INIT(best_key_direction);
- LINT_INIT(best_records);
/*
If not used with LIMIT, only use keys if the whole query can be
@@ -13121,12 +13135,20 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
for (nr=0; nr < table->s->keys ; nr++)
{
int direction;
+
if (keys.is_set(nr) &&
(direction= test_if_order_by_key(order, table, nr, &used_key_parts)))
{
+ /*
+ At this point we are sure that ref_key is a non-ordering
+ key (where "ordering key" is a key that will return rows
+ in the order required by ORDER BY).
+ */
+ DBUG_ASSERT (ref_key != (int) nr);
+
bool is_covering= table->covering_keys.is_set(nr) ||
- nr == table->s->primary_key &&
- table->file->primary_key_is_clustered();
+ (nr == table->s->primary_key &&
+ table->file->primary_key_is_clustered());
/*
Don't use an index scan with ORDER BY without limit.
@@ -13139,7 +13161,7 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
*/
if (is_covering ||
select_limit != HA_POS_ERROR ||
- ref_key < 0 && (group || table->force_index))
+ (ref_key < 0 && (group || table->force_index)))
{
double rec_per_key;
double index_scan_time;
@@ -13148,7 +13170,8 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
select_limit= table_records;
if (group)
{
- rec_per_key= keyinfo->rec_per_key[used_key_parts-1];
+ rec_per_key= used_key_parts ? keyinfo->rec_per_key[used_key_parts-1]
+ : 1;
set_if_bigger(rec_per_key, 1);
/*
With a grouping query each group containing on average
@@ -13203,13 +13226,13 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
*/
index_scan_time= select_limit/rec_per_key *
min(rec_per_key, table->file->scan_time());
- if (is_covering ||
- ref_key < 0 && (group || table->force_index) ||
+ if ((ref_key < 0 && is_covering) ||
+ (ref_key < 0 && (group || table->force_index)) ||
index_scan_time < read_time)
{
ha_rows quick_records= table_records;
- if (is_best_covering && !is_covering ||
- is_covering && ref_key_quick_rows < select_limit)
+ if ((is_best_covering && !is_covering) ||
+ (is_covering && ref_key_quick_rows < select_limit))
continue;
if (table->quick_keys.is_set(nr))
quick_records= table->quick_rows[nr];
@@ -13417,8 +13440,8 @@ create_sort_index(THD *thd, JOIN *join, ORDER *order,
*/
if ((order != join->group_list ||
!(join->select_options & SELECT_BIG_RESULT) ||
- select && select->quick &&
- select->quick->get_type() == QUICK_SELECT_I::QS_TYPE_GROUP_MIN_MAX) &&
+ (select && select->quick &&
+ select->quick->get_type() == QUICK_SELECT_I::QS_TYPE_GROUP_MIN_MAX)) &&
test_if_skip_sort_order(tab,order,select_limit,0,
is_order_by ? &table->keys_in_use_for_order_by :
&table->keys_in_use_for_group_by))
@@ -13479,9 +13502,24 @@ create_sort_index(THD *thd, JOIN *join, ORDER *order,
tab->records= table->sort.found_records; // For SQL_CALC_ROWS
if (select)
{
+ /*
+ We need to preserve tablesort's output resultset here, because
+ QUICK_INDEX_MERGE_SELECT::~QUICK_INDEX_MERGE_SELECT (called by
+ SQL_SELECT::cleanup()) may free it assuming it's the result of the quick
+ select operation that we no longer need. Note that all the other parts of
+ this data structure are cleaned up when
+ QUICK_INDEX_MERGE_SELECT::get_next encounters end of data, so the next
+ SQL_SELECT::cleanup() call changes sort.io_cache alone.
+ */
+ IO_CACHE *tablesort_result_cache;
+
+ tablesort_result_cache= table->sort.io_cache;
+ table->sort.io_cache= NULL;
+
select->cleanup(); // filesort did select
tab->select= 0;
table->quick_keys.clear_all(); // as far as we cleanup select->quick
+ table->sort.io_cache= tablesort_result_cache;
}
tab->select_cond=0;
tab->last_inner= 0;
@@ -13855,7 +13893,7 @@ SORT_FIELD *make_unireg_sortorder(ORDER *order, uint *length,
pos->field= ((Item_sum*) item)->get_tmp_table_field();
else if (item->type() == Item::COPY_STR_ITEM)
{ // Blob patch
- pos->item= ((Item_copy_string*) item)->item;
+ pos->item= ((Item_copy*) item)->get_item();
}
else
pos->item= *order->item;
@@ -14244,8 +14282,8 @@ find_order_in_list(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
/* Lookup the current GROUP field in the FROM clause. */
order_item_type= order_item->type();
from_field= (Field*) not_found_field;
- if (is_group_field &&
- order_item_type == Item::FIELD_ITEM ||
+ if ((is_group_field &&
+ order_item_type == Item::FIELD_ITEM) ||
order_item_type == Item::REF_ITEM)
{
from_field= find_field_in_tables(thd, (Item_ident*) order_item, tables,
@@ -14680,7 +14718,7 @@ get_sort_by_table(ORDER *a,ORDER *b,TABLE_LIST *tables)
if (!map || (map & (RAND_TABLE_BIT | OUTER_REF_TABLE_BIT)))
DBUG_RETURN(0);
- for (; !(map & tables->table->map); tables= tables->next_leaf);
+ for (; !(map & tables->table->map); tables= tables->next_leaf) ;
if (map != tables->table->map)
DBUG_RETURN(0); // More than one table
DBUG_PRINT("exit",("sort by table: %d",tables->table->tablenr));
@@ -14926,7 +14964,7 @@ setup_copy_fields(THD *thd, TMP_TABLE_PARAM *param,
pos= item;
if (item->field->flags & BLOB_FLAG)
{
- if (!(pos= new Item_copy_string(pos)))
+ if (!(pos= Item_copy::create(pos)))
goto err;
/*
Item_copy_string::copy for function can call
@@ -14980,7 +15018,7 @@ setup_copy_fields(THD *thd, TMP_TABLE_PARAM *param,
on how the value is to be used: In some cases this may be an
argument in a group function, like: IF(ISNULL(col),0,COUNT(*))
*/
- if (!(pos=new Item_copy_string(pos)))
+ if (!(pos= Item_copy::create(pos)))
goto err;
if (i < border) // HAVING, ORDER and GROUP BY
{
@@ -15033,8 +15071,8 @@ copy_fields(TMP_TABLE_PARAM *param)
(*ptr->do_copy)(ptr);
List_iterator_fast
- it(param->copy_funcs);
- Item_copy_string *item;
- while ((item = (Item_copy_string*) it++))
+ Item_copy *item;
+ while ((item = (Item_copy*) it++))
item->copy();
}
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index d08b3a248c4..d07e951bfd1 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -601,7 +601,7 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list)
if (open_normal_and_derived_tables(thd, table_list, 0))
{
if (!table_list->view ||
- thd->is_error() && thd->main_da.sql_errno() != ER_VIEW_INVALID)
+ (thd->is_error() && thd->main_da.sql_errno() != ER_VIEW_INVALID))
DBUG_RETURN(TRUE);
/*
@@ -2819,8 +2819,8 @@ make_table_name_list(THD *thd, List *table_names, LEX *lex,
LOOKUP_FIELD_VALUES *lookup_field_vals,
bool with_i_schema, LEX_STRING *db_name)
{
- char path[FN_REFLEN];
- build_table_filename(path, sizeof(path), db_name->str, "", "", 0);
+ char path[FN_REFLEN + 1];
+ build_table_filename(path, sizeof(path) - 1, db_name->str, "", "", 0);
if (!lookup_field_vals->wild_table_value &&
lookup_field_vals->table_value.str)
{
@@ -2982,8 +2982,8 @@ static int fill_schema_table_names(THD *thd, TABLE *table,
else
{
enum legacy_db_type not_used;
- char path[FN_REFLEN];
- (void) build_table_filename(path, sizeof(path), db_name->str,
+ char path[FN_REFLEN + 1];
+ (void) build_table_filename(path, sizeof(path) - 1, db_name->str,
table_name->str, reg_ext, 0);
switch (mysql_frm_type(thd, path, ¬_used)) {
case FRMTYPE_ERROR:
@@ -3238,10 +3238,10 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
if lookup value is empty string then
it's impossible table name or db name
*/
- if (lookup_field_vals.db_value.str &&
- !lookup_field_vals.db_value.str[0] ||
- lookup_field_vals.table_value.str &&
- !lookup_field_vals.table_value.str[0])
+ if ((lookup_field_vals.db_value.str &&
+ !lookup_field_vals.db_value.str[0]) ||
+ (lookup_field_vals.table_value.str &&
+ !lookup_field_vals.table_value.str[0]))
{
error= 0;
goto err;
@@ -3470,7 +3470,7 @@ int fill_schema_schemata(THD *thd, TABLE_LIST *tables, COND *cond)
MY_STAT stat_info;
if (!lookup_field_vals.db_value.str[0])
DBUG_RETURN(0);
- path_len= build_table_filename(path, sizeof(path),
+ path_len= build_table_filename(path, sizeof(path) - 1,
lookup_field_vals.db_value.str, "", "", 0);
path[path_len-1]= 0;
if (!my_stat(path,&stat_info,MYF(0)))
@@ -4116,10 +4116,10 @@ bool store_schema_proc(THD *thd, TABLE *table, TABLE *proc_table,
TYPE_ENUM_PROCEDURE))
return 0;
- if (lex->sql_command == SQLCOM_SHOW_STATUS_PROC &&
- proc_table->field[2]->val_int() == TYPE_ENUM_PROCEDURE ||
- lex->sql_command == SQLCOM_SHOW_STATUS_FUNC &&
- proc_table->field[2]->val_int() == TYPE_ENUM_FUNCTION ||
+ if ((lex->sql_command == SQLCOM_SHOW_STATUS_PROC &&
+ proc_table->field[2]->val_int() == TYPE_ENUM_PROCEDURE) ||
+ (lex->sql_command == SQLCOM_SHOW_STATUS_FUNC &&
+ proc_table->field[2]->val_int() == TYPE_ENUM_FUNCTION) ||
(sql_command_flags[lex->sql_command] & CF_STATUS_COMMAND) == 0)
{
restore_record(table, s->default_values);
@@ -7071,6 +7071,12 @@ bool show_create_trigger(THD *thd, const sp_name *trg_name)
if (!lst)
return TRUE;
+ if (check_table_access(thd, TRIGGER_ACL, lst, 1, TRUE))
+ {
+ my_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, MYF(0), "TRIGGER");
+ return TRUE;
+ }
+
/*
Open the table by name in order to load Table_triggers_list object.
diff --git a/sql/sql_string.cc b/sql/sql_string.cc
index 1dd7b55d136..7759985ba85 100644
--- a/sql/sql_string.cc
+++ b/sql/sql_string.cc
@@ -322,12 +322,24 @@ bool String::set_or_copy_aligned(const char *str,uint32 arg_length,
return copy_aligned(str, arg_length, offset, cs);
}
- /* Copy with charset conversion */
+
+/**
+ Copies the character data into this String, with optional character set
+ conversion.
+
+ @return
+ FALSE ok
+ TRUE Could not allocate result buffer
+
+*/
bool String::copy(const char *str, uint32 arg_length,
CHARSET_INFO *from_cs, CHARSET_INFO *to_cs, uint *errors)
{
uint32 offset;
+
+ DBUG_ASSERT(!str || str != Ptr);
+
if (!needs_conversion(arg_length, from_cs, to_cs, &offset))
{
*errors= 0;
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 29d43155778..e752421223a 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -68,6 +68,234 @@ static void wait_for_kill_signal(THD *thd)
#endif
+/**
+ @brief Helper function for explain_filename
+*/
+static char* add_identifier(char *to_p, const char * end_p,
+ const char* name, uint name_len, int errcode)
+{
+ uint res;
+ uint errors;
+ const char *conv_name;
+ char tmp_name[FN_REFLEN];
+ char conv_string[FN_REFLEN];
+
+ DBUG_ENTER("add_identifier");
+ if (!name[name_len])
+ conv_name= name;
+ else
+ {
+ strnmov(tmp_name, name, name_len);
+ tmp_name[name_len]= 0;
+ conv_name= tmp_name;
+ }
+ res= strconvert(&my_charset_filename, conv_name, system_charset_info,
+ conv_string, FN_REFLEN, &errors);
+ if (!res || errors)
+ conv_name= name;
+ else
+ {
+ DBUG_PRINT("info", ("conv '%s' -> '%s'", conv_name, conv_string));
+ conv_name= conv_string;
+ }
+
+ if (errcode)
+ to_p+= my_snprintf(to_p, end_p - to_p, ER(errcode), conv_name);
+ else
+ to_p+= my_snprintf(to_p, end_p - to_p, "`%s`", conv_name);
+ return to_p;
+}
+
+
+/**
+ @brief Explain a path name by split it to database, table etc.
+
+ @details Break down the path name to its logic parts
+ (database, table, partition, subpartition).
+ filename_to_tablename cannot be used on partitions, due to the #P# part.
+ There can be up to 6 '#', #P# for partition, #SP# for subpartition
+ and #TMP# or #REN# for temporary or renamed partitions.
+ This should be used when something should be presented to a user in a
+ diagnostic, error etc. when it would be useful to know what a particular
+ file [and directory] means. Such as SHOW ENGINE STATUS, error messages etc.
+
+ @param from Path name in my_charset_filename
+ Null terminated in my_charset_filename, normalized
+ to use '/' as directory separation character.
+ @param to Explained name in system_charset_info
+ @param to_length Size of to buffer
+ @param explain_mode Requested output format.
+ EXPLAIN_ALL_VERBOSE ->
+ [Database `db`, ]Table `tbl`[,[ Temporary| Renamed]
+ Partition `p` [, Subpartition `sp`]]
+ EXPLAIN_PARTITIONS_VERBOSE -> `db`.`tbl`
+ [[ Temporary| Renamed] Partition `p`
+ [, Subpartition `sp`]]
+ EXPLAIN_PARTITIONS_AS_COMMENT -> `db`.`tbl` |*
+ [,[ Temporary| Renamed] Partition `p`
+ [, Subpartition `sp`]] *|
+ (| is really a /, and it is all in one line)
+
+ @retval Length of returned string
+*/
+
+uint explain_filename(const char *from,
+ char *to,
+ uint to_length,
+ enum_explain_filename_mode explain_mode)
+{
+ uint res= 0;
+ char *to_p= to;
+ char *end_p= to_p + to_length;
+ const char *db_name= NULL;
+ int db_name_len= 0;
+ const char *table_name;
+ int table_name_len= 0;
+ const char *part_name= NULL;
+ int part_name_len= 0;
+ const char *subpart_name= NULL;
+ int subpart_name_len= 0;
+ enum enum_file_name_type {NORMAL, TEMP, RENAMED} name_type= NORMAL;
+ const char *tmp_p;
+ DBUG_ENTER("explain_filename");
+ DBUG_PRINT("enter", ("from '%s'", from));
+ tmp_p= from;
+ table_name= from;
+ /*
+ If '/' then take last directory part as database.
+ '/' is the directory separator, not FN_LIB_CHAR
+ */
+ while ((tmp_p= strchr(tmp_p, '/')))
+ {
+ db_name= table_name;
+ /* calculate the length */
+ db_name_len= tmp_p - db_name;
+ tmp_p++;
+ table_name= tmp_p;
+ }
+ tmp_p= table_name;
+ while (!res && (tmp_p= strchr(tmp_p, '#')))
+ {
+ tmp_p++;
+ switch (tmp_p[0]) {
+ case 'P':
+ case 'p':
+ if (tmp_p[1] == '#')
+ part_name= tmp_p + 2;
+ else
+ res= 1;
+ tmp_p+= 2;
+ break;
+ case 'S':
+ case 's':
+ if ((tmp_p[1] == 'P' || tmp_p[1] == 'p') && tmp_p[2] == '#')
+ {
+ part_name_len= tmp_p - part_name - 1;
+ subpart_name= tmp_p + 3;
+ }
+ else
+ res= 2;
+ tmp_p+= 3;
+ break;
+ case 'T':
+ case 't':
+ if ((tmp_p[1] == 'M' || tmp_p[1] == 'm') &&
+ (tmp_p[2] == 'P' || tmp_p[2] == 'p') &&
+ tmp_p[3] == '#' && !tmp_p[4])
+ name_type= TEMP;
+ else
+ res= 3;
+ tmp_p+= 4;
+ break;
+ case 'R':
+ case 'r':
+ if ((tmp_p[1] == 'E' || tmp_p[1] == 'e') &&
+ (tmp_p[2] == 'N' || tmp_p[2] == 'n') &&
+ tmp_p[3] == '#' && !tmp_p[4])
+ name_type= RENAMED;
+ else
+ res= 4;
+ tmp_p+= 4;
+ break;
+ default:
+ res= 5;
+ }
+ }
+ if (res)
+ {
+ /* Better to give something back if we fail parsing, than nothing at all */
+ DBUG_PRINT("info", ("Error in explain_filename: %u", res));
+ sql_print_warning("Invalid (old?) table or database name '%s'", from);
+ DBUG_RETURN(my_snprintf(to, to_length,
+ "",
+ res, from));
+ }
+ if (part_name)
+ {
+ table_name_len= part_name - table_name - 3;
+ if (subpart_name)
+ subpart_name_len= strlen(subpart_name);
+ else
+ part_name_len= strlen(part_name);
+ if (name_type != NORMAL)
+ {
+ if (subpart_name)
+ subpart_name_len-= 5;
+ else
+ part_name_len-= 5;
+ }
+ }
+ if (db_name)
+ {
+ if (explain_mode == EXPLAIN_ALL_VERBOSE)
+ {
+ to_p= add_identifier(to_p, end_p, db_name, db_name_len,
+ ER_DATABASE_NAME);
+ to_p= strnmov(to_p, ", ", end_p - to_p);
+ }
+ else
+ {
+ to_p= add_identifier(to_p, end_p, db_name, db_name_len, 0);
+ to_p= strnmov(to_p, ".", end_p - to_p);
+ }
+ }
+ if (explain_mode == EXPLAIN_ALL_VERBOSE)
+ to_p= add_identifier(to_p, end_p, table_name, table_name_len,
+ ER_TABLE_NAME);
+ else
+ to_p= add_identifier(to_p, end_p, table_name, table_name_len, 0);
+ if (part_name)
+ {
+ if (explain_mode == EXPLAIN_PARTITIONS_AS_COMMENT)
+ to_p= strnmov(to_p, " /* ", end_p - to_p);
+ else if (explain_mode == EXPLAIN_PARTITIONS_VERBOSE)
+ to_p= strnmov(to_p, " ", end_p - to_p);
+ else
+ to_p= strnmov(to_p, ", ", end_p - to_p);
+ if (name_type != NORMAL)
+ {
+ if (name_type == TEMP)
+ to_p= strnmov(to_p, ER(ER_TEMPORARY_NAME), end_p - to_p);
+ else
+ to_p= strnmov(to_p, ER(ER_RENAMED_NAME), end_p - to_p);
+ to_p= strnmov(to_p, " ", end_p - to_p);
+ }
+ to_p= add_identifier(to_p, end_p, part_name, part_name_len,
+ ER_PARTITION_NAME);
+ if (subpart_name)
+ {
+ to_p= strnmov(to_p, ", ", end_p - to_p);
+ to_p= add_identifier(to_p, end_p, subpart_name, subpart_name_len,
+ ER_SUBPARTITION_NAME);
+ }
+ if (explain_mode == EXPLAIN_PARTITIONS_AS_COMMENT)
+ to_p= strnmov(to_p, " */", end_p - to_p);
+ }
+ DBUG_PRINT("exit", ("to '%s'", to));
+ DBUG_RETURN(to_p - to);
+}
+
+
/*
Translate a file name to a table name (WL #1324).
@@ -1287,7 +1515,7 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags)
/*
Build shadow frm file name
*/
- build_table_shadow_filename(shadow_path, sizeof(shadow_path), lpt);
+ build_table_shadow_filename(shadow_path, sizeof(shadow_path) - 1, lpt);
strxmov(shadow_frm_name, shadow_path, reg_ext, NullS);
if (flags & WFRM_WRITE_SHADOW)
{
@@ -1362,7 +1590,7 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags)
/*
Build frm file name
*/
- build_table_filename(path, sizeof(path), lpt->db,
+ build_table_filename(path, sizeof(path) - 1, lpt->db,
lpt->table_name, "", 0);
strxmov(frm_name, path, reg_ext, NullS);
/*
@@ -1460,10 +1688,13 @@ void write_bin_log(THD *thd, bool clear_error,
{
if (mysql_bin_log.is_open())
{
+ int errcode= 0;
if (clear_error)
thd->clear_error();
+ else
+ errcode= query_error_code(thd, TRUE);
thd->binlog_query(THD::STMT_QUERY_TYPE,
- query, query_length, FALSE, FALSE, THD::NOT_KILLED);
+ query, query_length, FALSE, FALSE, errcode);
}
}
@@ -1561,7 +1792,7 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
bool dont_log_query)
{
TABLE_LIST *table;
- char path[FN_REFLEN], *alias;
+ char path[FN_REFLEN + 1], *alias;
uint path_length;
String wrong_tables;
int error= 0;
@@ -1691,13 +1922,14 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
}
alias= (lower_case_table_names == 2) ? table->alias : table->table_name;
/* remove .frm file and engine files */
- path_length= build_table_filename(path, sizeof(path), db, alias, reg_ext,
+ path_length= build_table_filename(path, sizeof(path) - 1, db, alias,
+ reg_ext,
table->internal_tmp_table ?
FN_IS_TMP : 0);
}
if (drop_temporary ||
- (table_type == NULL &&
- (access(path, F_OK) &&
+ ((table_type == NULL &&
+ access(path, F_OK) &&
ha_create_table_from_engine(thd, db, alias)) ||
(!drop_view &&
mysql_frm_type(thd, path, &frm_db_type) != FRMTYPE_TABLE)))
@@ -1779,7 +2011,7 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
if (!dont_log_query)
{
if (!thd->current_stmt_binlog_row_based ||
- non_temp_tables_count > 0 && !tmp_table_deleted)
+ (non_temp_tables_count > 0 && !tmp_table_deleted))
{
/*
In this case, we are either using statement-based
@@ -1847,11 +2079,11 @@ err_with_placeholders:
bool quick_rm_table(handlerton *base,const char *db,
const char *table_name, uint flags)
{
- char path[FN_REFLEN];
+ char path[FN_REFLEN + 1];
bool error= 0;
DBUG_ENTER("quick_rm_table");
- uint path_length= build_table_filename(path, sizeof(path),
+ uint path_length= build_table_filename(path, sizeof(path) - 1,
db, table_name, reg_ext, flags);
if (my_delete(path,MYF(0)))
error= 1; /* purecov: inspected */
@@ -2488,8 +2720,8 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
}
/* Don't pack rows in old tables if the user has requested this */
if ((sql_field->flags & BLOB_FLAG) ||
- sql_field->sql_type == MYSQL_TYPE_VARCHAR &&
- create_info->row_type != ROW_TYPE_FIXED)
+ (sql_field->sql_type == MYSQL_TYPE_VARCHAR &&
+ create_info->row_type != ROW_TYPE_FIXED))
(*db_options)|= HA_OPTION_PACK_RECORD;
it2.rewind();
}
@@ -2958,7 +3190,7 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
sql_field->sql_type == MYSQL_TYPE_VARCHAR ||
sql_field->pack_flag & FIELDFLAG_BLOB)))
{
- if (column_nr == 0 && (sql_field->pack_flag & FIELDFLAG_BLOB) ||
+ if ((column_nr == 0 && (sql_field->pack_flag & FIELDFLAG_BLOB)) ||
sql_field->sql_type == MYSQL_TYPE_VARCHAR)
key_info->flags|= HA_BINARY_PACK_KEY | HA_VAR_LENGTH_KEY;
else
@@ -3126,7 +3358,7 @@ static bool prepare_blob_field(THD *thd, Create_field *sql_field)
}
sql_field->sql_type= MYSQL_TYPE_BLOB;
sql_field->flags|= BLOB_FLAG;
- sprintf(warn_buff, ER(ER_AUTO_CONVERT), sql_field->field_name,
+ my_snprintf(warn_buff, sizeof(warn_buff), ER(ER_AUTO_CONVERT), sql_field->field_name,
(sql_field->charset == &my_charset_bin) ? "VARBINARY" : "VARCHAR",
(sql_field->charset == &my_charset_bin) ? "BLOB" : "TEXT");
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, ER_AUTO_CONVERT,
@@ -3240,7 +3472,7 @@ bool mysql_create_table_no_lock(THD *thd,
bool internal_tmp_table,
uint select_field_count)
{
- char path[FN_REFLEN];
+ char path[FN_REFLEN + 1];
uint path_length;
const char *alias;
uint db_options, key_count;
@@ -3448,7 +3680,7 @@ bool mysql_create_table_no_lock(THD *thd,
}
else
{
- path_length= build_table_filename(path, sizeof(path), db, alias, reg_ext,
+ path_length= build_table_filename(path, sizeof(path) - 1, db, alias, reg_ext,
internal_tmp_table ? FN_IS_TMP : 0);
}
@@ -3762,7 +3994,8 @@ mysql_rename_table(handlerton *base, const char *old_db,
const char *new_name, uint flags)
{
THD *thd= current_thd;
- char from[FN_REFLEN], to[FN_REFLEN], lc_from[FN_REFLEN], lc_to[FN_REFLEN];
+ char from[FN_REFLEN + 1], to[FN_REFLEN + 1],
+ lc_from[FN_REFLEN + 1], lc_to[FN_REFLEN + 1];
char *from_base= from, *to_base= to;
char tmp_name[NAME_LEN+1];
handler *file;
@@ -3774,9 +4007,9 @@ mysql_rename_table(handlerton *base, const char *old_db,
file= (base == NULL ? 0 :
get_new_handler((TABLE_SHARE*) 0, thd->mem_root, base));
- build_table_filename(from, sizeof(from), old_db, old_name, "",
+ build_table_filename(from, sizeof(from) - 1, old_db, old_name, "",
flags & FN_FROM_IS_TMP);
- build_table_filename(to, sizeof(to), new_db, new_name, "",
+ build_table_filename(to, sizeof(to) - 1, new_db, new_name, "",
flags & FN_TO_IS_TMP);
/*
@@ -3789,13 +4022,13 @@ mysql_rename_table(handlerton *base, const char *old_db,
{
strmov(tmp_name, old_name);
my_casedn_str(files_charset_info, tmp_name);
- build_table_filename(lc_from, sizeof(lc_from), old_db, tmp_name, "",
+ build_table_filename(lc_from, sizeof(lc_from) - 1, old_db, tmp_name, "",
flags & FN_FROM_IS_TMP);
from_base= lc_from;
strmov(tmp_name, new_name);
my_casedn_str(files_charset_info, tmp_name);
- build_table_filename(lc_to, sizeof(lc_to), new_db, tmp_name, "",
+ build_table_filename(lc_to, sizeof(lc_to) - 1, new_db, tmp_name, "",
flags & FN_TO_IS_TMP);
to_base= lc_to;
}
@@ -3926,16 +4159,16 @@ static int prepare_for_restore(THD* thd, TABLE_LIST* table,
else
{
char* backup_dir= thd->lex->backup_dir;
- char src_path[FN_REFLEN], dst_path[FN_REFLEN], uname[FN_REFLEN];
+ char src_path[FN_REFLEN], dst_path[FN_REFLEN + 1], uname[FN_REFLEN];
char* table_name= table->table_name;
char* db= table->db;
- VOID(tablename_to_filename(table->table_name, uname, sizeof(uname)));
+ VOID(tablename_to_filename(table->table_name, uname, sizeof(uname) - 1));
if (fn_format_relative_to_data_home(src_path, uname, backup_dir, reg_ext))
DBUG_RETURN(-1); // protect buffer overflow
- build_table_filename(dst_path, sizeof(dst_path),
+ build_table_filename(dst_path, sizeof(dst_path) - 1,
db, table_name, reg_ext, 0);
if (lock_and_wait_for_table_name(thd,table))
@@ -4547,7 +4780,7 @@ send_result_message:
const char *err_msg= thd->main_da.message();
if (!thd->vio_ok())
{
- sql_print_error(err_msg);
+ sql_print_error("%s", err_msg);
}
else
{
@@ -4857,7 +5090,7 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, TABLE_LIST* src_table,
HA_CREATE_INFO *create_info)
{
TABLE *name_lock= 0;
- char src_path[FN_REFLEN], dst_path[FN_REFLEN];
+ char src_path[FN_REFLEN], dst_path[FN_REFLEN + 1];
uint dst_path_length;
char *db= table->db;
char *table_name= table->table_name;
@@ -4867,7 +5100,7 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, TABLE_LIST* src_table,
#ifdef WITH_PARTITION_STORAGE_ENGINE
char tmp_path[FN_REFLEN];
#endif
- char ts_name[FN_LEN];
+ char ts_name[FN_LEN + 1];
DBUG_ENTER("mysql_create_like_table");
@@ -4916,7 +5149,7 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, TABLE_LIST* src_table,
goto err;
if (!name_lock)
goto table_exists;
- dst_path_length= build_table_filename(dst_path, sizeof(dst_path),
+ dst_path_length= build_table_filename(dst_path, sizeof(dst_path) - 1,
db, table_name, reg_ext, 0);
if (!access(dst_path, F_OK))
goto table_exists;
@@ -5314,7 +5547,7 @@ compare_tables(TABLE *table,
create_info->used_fields & HA_CREATE_USED_ENGINE ||
create_info->used_fields & HA_CREATE_USED_CHARSET ||
create_info->used_fields & HA_CREATE_USED_DEFAULT_CHARSET ||
- create_info->used_fields & HA_CREATE_USED_ROW_FORMAT ||
+ (table->s->row_type != create_info->row_type) ||
create_info->used_fields & HA_CREATE_USED_PACK_KEYS ||
create_info->used_fields & HA_CREATE_USED_MAX_ROWS ||
(alter_info->flags & (ALTER_RECREATE | ALTER_FOREIGN_KEY)) ||
@@ -5358,8 +5591,8 @@ compare_tables(TABLE *table,
/* Don't pack rows in old tables if the user has requested this. */
if (create_info->row_type == ROW_TYPE_DYNAMIC ||
(tmp_new_field->flags & BLOB_FLAG) ||
- tmp_new_field->sql_type == MYSQL_TYPE_VARCHAR &&
- create_info->row_type != ROW_TYPE_FIXED)
+ (tmp_new_field->sql_type == MYSQL_TYPE_VARCHAR &&
+ create_info->row_type != ROW_TYPE_FIXED))
create_info->table_options|= HA_OPTION_PACK_RECORD;
/* Check if field was renamed */
@@ -5657,7 +5890,7 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
if (!create_info->tablespace && create_info->storage_media != HA_SM_MEMORY)
{
- char *tablespace= static_cast(thd->alloc(FN_LEN));
+ char *tablespace= static_cast(thd->alloc(FN_LEN + 1));
/*
Regular alter table of disk stored table (no tablespace/storage change)
Copy tablespace name
@@ -6024,10 +6257,10 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
{
TABLE *table, *new_table= 0, *name_lock= 0;
int error= 0;
- char tmp_name[80],old_name[32],new_name_buff[FN_REFLEN];
+ char tmp_name[80],old_name[32],new_name_buff[FN_REFLEN + 1];
char new_alias_buff[FN_REFLEN], *table_name, *db, *new_alias, *alias;
char index_file[FN_REFLEN], data_file[FN_REFLEN];
- char path[FN_REFLEN];
+ char path[FN_REFLEN + 1];
char reg_path[FN_REFLEN+1];
ha_rows copied,deleted;
handlerton *old_db_type, *new_db_type, *save_old_db_type;
@@ -6040,21 +6273,15 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
#endif
bool need_lock_for_indexes= TRUE;
KEY *key_info_buffer;
- uint index_drop_count;
- uint *index_drop_buffer;
- uint index_add_count;
- uint *index_add_buffer;
- uint candidate_key_count;
+ uint index_drop_count= 0;
+ uint *index_drop_buffer= NULL;
+ uint index_add_count= 0;
+ uint *index_add_buffer= NULL;
+ uint candidate_key_count= 0;
bool committed= 0;
bool no_pk;
DBUG_ENTER("mysql_alter_table");
- LINT_INIT(index_add_count);
- LINT_INIT(index_drop_count);
- LINT_INIT(index_add_buffer);
- LINT_INIT(index_drop_buffer);
- LINT_INIT(candidate_key_count);
-
/*
Check if we attempt to alter mysql.slow_log or
mysql.general_log table and return an error if
@@ -6108,8 +6335,8 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
db=table_list->db;
if (!new_db || !my_strcasecmp(table_alias_charset, new_db, db))
new_db= db;
- build_table_filename(reg_path, sizeof(reg_path), db, table_name, reg_ext, 0);
- build_table_filename(path, sizeof(path), db, table_name, "", 0);
+ build_table_filename(reg_path, sizeof(reg_path) - 1, db, table_name, reg_ext, 0);
+ build_table_filename(path, sizeof(path) - 1, db, table_name, "", 0);
mysql_ha_rm_tables(thd, table_list, FALSE);
@@ -6139,6 +6366,20 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
/* Sic: there is a race here */
if (frm_type == FRMTYPE_VIEW && !(alter_info->flags & ~ALTER_RENAME))
{
+ /*
+ The following branch handles "ALTER VIEW v1 /no arguments/;"
+ This feature is not documented one.
+ However, before "OPTIMIZE TABLE t1;" was implemented,
+ ALTER TABLE with no alter_specifications was used to force-rebuild
+ the table. That's why this grammar is allowed. That's why we ignore
+ it for views. So just do nothing in such a case.
+ */
+ if (!new_name)
+ {
+ my_ok(thd);
+ DBUG_RETURN(FALSE);
+ }
+
/*
Avoid problems with a rename on a table that we have locked or
if the user is trying to to do this in a transcation context
@@ -6166,7 +6407,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
{
thd->clear_error();
Query_log_event qinfo(thd, thd->query, thd->query_length,
- 0, FALSE, THD::NOT_KILLED);
+ 0, FALSE, 0);
mysql_bin_log.write(&qinfo);
}
my_ok(thd);
@@ -6242,7 +6483,7 @@ view_err:
DBUG_RETURN(TRUE);
}
- build_table_filename(new_name_buff, sizeof(new_name_buff),
+ build_table_filename(new_name_buff, sizeof(new_name_buff) - 1,
new_db, new_name_buff, reg_ext, 0);
if (!access(new_name_buff, F_OK))
{
@@ -6293,7 +6534,10 @@ view_err:
}
if (create_info->row_type == ROW_TYPE_NOT_USED)
+ {
create_info->row_type= table->s->row_type;
+ create_info->used_fields |= HA_CREATE_USED_ROW_FORMAT;
+ }
DBUG_PRINT("info", ("old type: %s new type: %s",
ha_resolve_storage_engine_name(old_db_type),
@@ -6740,9 +6984,9 @@ view_err:
}
else
{
- char path[FN_REFLEN];
+ char path[FN_REFLEN + 1];
/* table is a normal table: Create temporary table in same directory */
- build_table_filename(path, sizeof(path), new_db, tmp_name, "",
+ build_table_filename(path, sizeof(path) - 1, new_db, tmp_name, "",
FN_IS_TMP);
/* Open our intermediate table */
new_table=open_temporary_table(thd, path, new_db, tmp_name,0);
@@ -6972,12 +7216,12 @@ view_err:
}
else if (mysql_rename_table(new_db_type, new_db, tmp_name, new_db,
new_alias, FN_FROM_IS_TMP) ||
- (new_name != table_name || new_db != db) && // we also do rename
+ ((new_name != table_name || new_db != db) && // we also do rename
(need_copy_table != ALTER_TABLE_METADATA_ONLY ||
mysql_rename_table(save_old_db_type, db, table_name, new_db,
new_alias, NO_FRM_RENAME)) &&
Table_triggers_list::change_table_name(thd, db, table_name,
- new_db, new_alias))
+ new_db, new_alias)))
{
/* Try to get everything back. */
error=1;
@@ -7070,7 +7314,7 @@ view_err:
*/
char path[FN_REFLEN];
TABLE *t_table;
- build_table_filename(path, sizeof(path), new_db, table_name, "", 0);
+ build_table_filename(path + 1, sizeof(path) - 1, new_db, table_name, "", 0);
t_table= open_temporary_table(thd, path, new_db, tmp_name, 0);
if (t_table)
{
diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc
index 8cab8fff2f3..c055268ecca 100644
--- a/sql/sql_trigger.cc
+++ b/sql/sql_trigger.cc
@@ -344,7 +344,7 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create)
need second part of condition below, since check_access() function also
checks that db is specified.
*/
- if (!thd->lex->spname->m_db.length || create && !tables->db_length)
+ if (!thd->lex->spname->m_db.length || (create && !tables->db_length))
{
my_error(ER_NO_DB_ERROR, MYF(0));
DBUG_RETURN(TRUE);
diff --git a/sql/sql_union.cc b/sql/sql_union.cc
index fd3036e3d80..cbf94ad7181 100644
--- a/sql/sql_union.cc
+++ b/sql/sql_union.cc
@@ -653,10 +653,22 @@ bool st_select_lex_unit::cleanup()
join->tables= 0;
}
error|= fake_select_lex->cleanup();
- if (fake_select_lex->order_list.elements)
+ /*
+ There are two cases when we should clean order items:
+ 1. UNION with SELECTs which all enclosed into braces
+ in this case global_parameters == fake_select_lex
+ 2. UNION where last SELECT is not enclosed into braces
+ in this case global_parameters == 'last select'
+ So we should use global_parameters->order_list for
+ proper order list clean up.
+ Note: global_parameters and fake_select_lex are always
+ initialized for UNION
+ */
+ DBUG_ASSERT(global_parameters);
+ if (global_parameters->order_list.elements)
{
ORDER *ord;
- for (ord= (ORDER*)fake_select_lex->order_list.first; ord; ord= ord->next)
+ for (ord= (ORDER*)global_parameters->order_list.first; ord; ord= ord->next)
(*ord->item)->cleanup();
}
}
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index 1edd6952a34..d7c9fc83270 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -797,12 +797,15 @@ int mysql_update(THD *thd,
{
if (mysql_bin_log.is_open())
{
+ int errcode= 0;
if (error < 0)
thd->clear_error();
+ else
+ errcode= query_error_code(thd, killed_status == THD::NOT_KILLED);
+
if (thd->binlog_query(THD::ROW_QUERY_TYPE,
thd->query, thd->query_length,
- transactional_table, FALSE, killed_status) &&
- transactional_table)
+ transactional_table, FALSE, errcode))
{
error=1; // Rollback update
}
@@ -820,7 +823,7 @@ int mysql_update(THD *thd,
if (error < 0)
{
char buff[STRING_BUFFER_USUAL_SIZE];
- sprintf(buff, ER(ER_UPDATE_INFO), (ulong) found, (ulong) updated,
+ my_snprintf(buff, sizeof(buff), ER(ER_UPDATE_INFO), (ulong) found, (ulong) updated,
(ulong) thd->cuted_fields);
thd->row_count_func=
(thd->client_capabilities & CLIENT_FOUND_ROWS) ? found : updated;
@@ -1035,7 +1038,6 @@ reopen_tables:
DBUG_RETURN(TRUE);
}
- table->mark_columns_needed_for_update();
DBUG_PRINT("info",("setting table `%s` for update", tl->alias));
/*
If table will be updated we should not downgrade lock for it and
@@ -1281,13 +1283,41 @@ int multi_update::prepare(List
- ¬_used_values,
DBUG_RETURN(1);
}
+ /*
+ We gather the set of columns read during evaluation of SET expression in
+ TABLE::tmp_set by pointing TABLE::read_set to it and then restore it after
+ setup_fields().
+ */
+ for (table_ref= leaves; table_ref; table_ref= table_ref->next_leaf)
+ {
+ TABLE *table= table_ref->table;
+ if (tables_to_update & table->map)
+ {
+ DBUG_ASSERT(table->read_set == &table->def_read_set);
+ table->read_set= &table->tmp_set;
+ bitmap_clear_all(table->read_set);
+ }
+ }
+
/*
We have to check values after setup_tables to get covering_keys right in
reference tables
*/
- if (setup_fields(thd, 0, *values, MARK_COLUMNS_READ, 0, 0))
- DBUG_RETURN(1);
+ int error= setup_fields(thd, 0, *values, MARK_COLUMNS_READ, 0, 0);
+
+ for (table_ref= leaves; table_ref; table_ref= table_ref->next_leaf)
+ {
+ TABLE *table= table_ref->table;
+ if (tables_to_update & table->map)
+ {
+ table->read_set= &table->def_read_set;
+ bitmap_union(table->read_set, &table->tmp_set);
+ }
+ }
+
+ if (error)
+ DBUG_RETURN(1);
/*
Save tables beeing updated in update_tables
@@ -1382,6 +1412,8 @@ int multi_update::prepare(List
- ¬_used_values,
a row in this table will never be read twice. This is true under
the following conditions:
+ - No column is both written to and read in SET expressions.
+
- We are doing a table scan and the data is in a separate file (MyISAM) or
if we don't update a clustered key.
@@ -1396,6 +1428,9 @@ int multi_update::prepare(List
- ¬_used_values,
WARNING
This code is a bit dependent of how make_join_readinfo() works.
+ The field table->tmp_set is used for keeping track of which fields are
+ read during evaluation of the SET expression. See multi_update::prepare.
+
RETURN
0 Not safe to update
1 Safe to update
@@ -1416,6 +1451,8 @@ static bool safe_update_on_fly(THD *thd, JOIN_TAB *join_tab,
case JT_REF_OR_NULL:
return !is_key_used(table, join_tab->ref.key, table->write_set);
case JT_ALL:
+ if (bitmap_is_overlapping(&table->tmp_set, table->write_set))
+ return FALSE;
/* If range search on index */
if (join_tab->quick)
return !join_tab->quick->is_keys_used(table->write_set);
@@ -1471,17 +1508,18 @@ multi_update::initialize_tables(JOIN *join)
ORDER group;
TMP_TABLE_PARAM *tmp_param;
- table->mark_columns_needed_for_update();
if (ignore)
table->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
if (table == main_table) // First table in join
{
if (safe_update_on_fly(thd, join->join_tab, table_ref, all_tables))
{
- table_to_update= main_table; // Update table on the fly
+ table->mark_columns_needed_for_update();
+ table_to_update= table; // Update table on the fly
continue;
}
}
+ table->mark_columns_needed_for_update();
table->prepare_for_position();
/*
@@ -1782,7 +1820,7 @@ void multi_update::abort()
{
/* the error was handled or nothing deleted and no side effects return */
if (error_handled ||
- !thd->transaction.stmt.modified_non_trans_table && !updated)
+ (!thd->transaction.stmt.modified_non_trans_table && !updated))
return;
/* Something already updated so we have to invalidate cache */
@@ -1819,9 +1857,10 @@ void multi_update::abort()
got caught and if happens later the killed error is written
into repl event.
*/
+ int errcode= query_error_code(thd, thd->killed == THD::NOT_KILLED);
thd->binlog_query(THD::ROW_QUERY_TYPE,
thd->query, thd->query_length,
- transactional_tables, FALSE);
+ transactional_tables, FALSE, errcode);
}
thd->transaction.all.modified_non_trans_table= TRUE;
}
@@ -2047,12 +2086,14 @@ bool multi_update::send_eof()
{
if (mysql_bin_log.is_open())
{
+ int errcode= 0;
if (local_error == 0)
thd->clear_error();
+ else
+ errcode= query_error_code(thd, killed_status == THD::NOT_KILLED);
if (thd->binlog_query(THD::ROW_QUERY_TYPE,
thd->query, thd->query_length,
- transactional_tables, FALSE, killed_status) &&
- trans_safe)
+ transactional_tables, FALSE, errcode))
{
local_error= 1; // Rollback update
}
@@ -2073,8 +2114,8 @@ bool multi_update::send_eof()
id= thd->arg_of_last_insert_id_function ?
thd->first_successful_insert_id_in_prev_stmt : 0;
- sprintf(buff, ER(ER_UPDATE_INFO), (ulong) found, (ulong) updated,
- (ulong) thd->cuted_fields);
+ my_snprintf(buff, sizeof(buff), ER(ER_UPDATE_INFO),
+ (ulong) found, (ulong) updated, (ulong) thd->cuted_fields);
thd->row_count_func=
(thd->client_capabilities & CLIENT_FOUND_ROWS) ? found : updated;
::my_ok(thd, (ulong) thd->row_count_func, id, buff);
diff --git a/sql/sql_view.cc b/sql/sql_view.cc
index 4f207f78688..2a4c5c950fe 100644
--- a/sql/sql_view.cc
+++ b/sql/sql_view.cc
@@ -661,8 +661,9 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views,
buff.append(STRING_WITH_LEN(" AS "));
buff.append(views->source.str, views->source.length);
+ int errcode= query_error_code(thd, TRUE);
thd->binlog_query(THD::STMT_QUERY_TYPE,
- buff.ptr(), buff.length(), FALSE, FALSE, THD::NOT_KILLED);
+ buff.ptr(), buff.length(), FALSE, FALSE, errcode);
}
VOID(pthread_mutex_unlock(&LOCK_open));
@@ -800,7 +801,7 @@ static int mysql_register_view(THD *thd, TABLE_LIST *view,
char md5[MD5_BUFF_LENGTH];
bool can_be_merged;
- char dir_buff[FN_REFLEN], path_buff[FN_REFLEN];
+ char dir_buff[FN_REFLEN + 1], path_buff[FN_REFLEN + 1];
LEX_STRING dir, file, path;
int error= 0;
DBUG_ENTER("mysql_register_view");
@@ -877,11 +878,11 @@ static int mysql_register_view(THD *thd, TABLE_LIST *view,
}
loop_out:
/* print file name */
- dir.length= build_table_filename(dir_buff, sizeof(dir_buff),
+ dir.length= build_table_filename(dir_buff, sizeof(dir_buff) - 1,
view->db, "", "", 0);
dir.str= dir_buff;
- path.length= build_table_filename(path_buff, sizeof(path_buff),
+ path.length= build_table_filename(path_buff, sizeof(path_buff) - 1,
view->db, view->table_name, reg_ext, 0);
path.str= path_buff;
@@ -1568,7 +1569,7 @@ err:
bool mysql_drop_view(THD *thd, TABLE_LIST *views, enum_drop_mode drop_mode)
{
- char path[FN_REFLEN];
+ char path[FN_REFLEN + 1];
TABLE_LIST *view;
String non_existant_views;
char *wrong_object_db= NULL, *wrong_object_name= NULL;
@@ -1583,7 +1584,7 @@ bool mysql_drop_view(THD *thd, TABLE_LIST *views, enum_drop_mode drop_mode)
{
TABLE_SHARE *share;
frm_type_enum type= FRMTYPE_ERROR;
- build_table_filename(path, sizeof(path),
+ build_table_filename(path, sizeof(path) - 1,
view->db, view->table_name, reg_ext, 0);
if (access(path, F_OK) ||
@@ -1928,7 +1929,7 @@ mysql_rename_view(THD *thd,
{
LEX_STRING pathstr;
File_parser *parser;
- char path_buff[FN_REFLEN];
+ char path_buff[FN_REFLEN + 1];
bool error= TRUE;
DBUG_ENTER("mysql_rename_view");
@@ -1941,7 +1942,7 @@ mysql_rename_view(THD *thd,
is_equal(&view_type, parser->type()))
{
TABLE_LIST view_def;
- char dir_buff[FN_REFLEN];
+ char dir_buff[FN_REFLEN + 1];
LEX_STRING dir, file;
/*
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 0b158ff7574..7d6a7ade540 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -5925,7 +5925,7 @@ alter_list_item:
MYSQL_YYABORT;
}
if (check_table_name($3->table.str,$3->table.length) ||
- $3->db.str && check_db_name(&$3->db))
+ ($3->db.str && check_db_name(&$3->db)))
{
my_error(ER_WRONG_TABLE_NAME, MYF(0), $3->table.str);
MYSQL_YYABORT;
@@ -6079,8 +6079,8 @@ slave_until:
| UNTIL_SYM slave_until_opts
{
LEX *lex=Lex;
- if ((lex->mi.log_file_name || lex->mi.pos) &&
- (lex->mi.relay_log_name || lex->mi.relay_log_pos) ||
+ if (((lex->mi.log_file_name || lex->mi.pos) &&
+ (lex->mi.relay_log_name || lex->mi.relay_log_pos)) ||
!((lex->mi.log_file_name && lex->mi.pos) ||
(lex->mi.relay_log_name && lex->mi.relay_log_pos)))
{
@@ -8493,6 +8493,7 @@ table_factor:
MYSQL_YYABORT;
sel->add_joined_table($$);
lex->pop_context();
+ lex->nest_level--;
}
else if ($4 || $6)
{
@@ -8501,7 +8502,11 @@ table_factor:
MYSQL_YYABORT;
}
else
+ {
+ /* nested join: FROM (t1 JOIN t2 ...),
+ nest_level is the same as in the outer query */
$$= $3;
+ }
}
;
@@ -12118,15 +12123,16 @@ text_or_password:
| PASSWORD '(' TEXT_STRING ')'
{
$$= $3.length ? YYTHD->variables.old_passwords ?
- Item_func_old_password::alloc(YYTHD, $3.str) :
- Item_func_password::alloc(YYTHD, $3.str) :
+ Item_func_old_password::alloc(YYTHD, $3.str, $3.length) :
+ Item_func_password::alloc(YYTHD, $3.str, $3.length) :
$3.str;
if ($$ == NULL)
MYSQL_YYABORT;
}
| OLD_PASSWORD '(' TEXT_STRING ')'
{
- $$= $3.length ? Item_func_old_password::alloc(YYTHD, $3.str) :
+ $$= $3.length ? Item_func_old_password::alloc(YYTHD, $3.str,
+ $3.length) :
$3.str;
if ($$ == NULL)
MYSQL_YYABORT;
@@ -12588,7 +12594,7 @@ grant_user:
(char *) YYTHD->alloc(SCRAMBLED_PASSWORD_CHAR_LENGTH_323+1);
if (buff == NULL)
MYSQL_YYABORT;
- make_scrambled_password_323(buff, $4.str);
+ my_make_scrambled_password_323(buff, $4.str, $4.length);
$1->password.str= buff;
$1->password.length= SCRAMBLED_PASSWORD_CHAR_LENGTH_323;
}
@@ -12598,7 +12604,7 @@ grant_user:
(char *) YYTHD->alloc(SCRAMBLED_PASSWORD_CHAR_LENGTH+1);
if (buff == NULL)
MYSQL_YYABORT;
- make_scrambled_password(buff, $4.str);
+ my_make_scrambled_password(buff, $4.str, $4.length);
$1->password.str= buff;
$1->password.length= SCRAMBLED_PASSWORD_CHAR_LENGTH;
}
diff --git a/sql/structs.h b/sql/structs.h
index 0a20eee0e9a..a58c18f97c5 100644
--- a/sql/structs.h
+++ b/sql/structs.h
@@ -107,6 +107,10 @@ typedef struct st_reginfo { /* Extra info about reg */
struct st_join_table *join_tab; /* Used by SELECT() */
enum thr_lock_type lock_type; /* How database is used */
bool not_exists_optimize;
+ /*
+ TRUE <=> range optimizer found that there is no rows satisfying
+ table conditions.
+ */
bool impossible_range;
} REGINFO;
diff --git a/sql/table.cc b/sql/table.cc
index d24ee4c6a27..60a27e136b1 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -464,34 +464,35 @@ inline bool is_system_table_name(const char *name, uint length)
CHARSET_INFO *ci= system_charset_info;
return (
- /* mysql.proc table */
- length == 4 &&
- my_tolower(ci, name[0]) == 'p' &&
- my_tolower(ci, name[1]) == 'r' &&
- my_tolower(ci, name[2]) == 'o' &&
- my_tolower(ci, name[3]) == 'c' ||
+ /* mysql.proc table */
+ (length == 4 &&
+ my_tolower(ci, name[0]) == 'p' &&
+ my_tolower(ci, name[1]) == 'r' &&
+ my_tolower(ci, name[2]) == 'o' &&
+ my_tolower(ci, name[3]) == 'c') ||
- length > 4 &&
- (
- /* one of mysql.help* tables */
- my_tolower(ci, name[0]) == 'h' &&
- my_tolower(ci, name[1]) == 'e' &&
- my_tolower(ci, name[2]) == 'l' &&
- my_tolower(ci, name[3]) == 'p' ||
+ (length > 4 &&
+ (
+ /* one of mysql.help* tables */
+ (my_tolower(ci, name[0]) == 'h' &&
+ my_tolower(ci, name[1]) == 'e' &&
+ my_tolower(ci, name[2]) == 'l' &&
+ my_tolower(ci, name[3]) == 'p') ||
- /* one of mysql.time_zone* tables */
- my_tolower(ci, name[0]) == 't' &&
- my_tolower(ci, name[1]) == 'i' &&
- my_tolower(ci, name[2]) == 'm' &&
- my_tolower(ci, name[3]) == 'e' ||
+ /* one of mysql.time_zone* tables */
+ (my_tolower(ci, name[0]) == 't' &&
+ my_tolower(ci, name[1]) == 'i' &&
+ my_tolower(ci, name[2]) == 'm' &&
+ my_tolower(ci, name[3]) == 'e') ||
- /* mysql.event table */
- my_tolower(ci, name[0]) == 'e' &&
- my_tolower(ci, name[1]) == 'v' &&
- my_tolower(ci, name[2]) == 'e' &&
- my_tolower(ci, name[3]) == 'n' &&
- my_tolower(ci, name[4]) == 't'
- )
+ /* mysql.event table */
+ (my_tolower(ci, name[0]) == 'e' &&
+ my_tolower(ci, name[1]) == 'v' &&
+ my_tolower(ci, name[2]) == 'e' &&
+ my_tolower(ci, name[3]) == 'n' &&
+ my_tolower(ci, name[4]) == 't')
+ )
+ )
);
}
@@ -779,7 +780,7 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head,
strpos=disk_buff+6;
if (!(rec_per_key= (ulong*) alloc_root(&share->mem_root,
- sizeof(ulong*)*key_parts)))
+ sizeof(ulong)*key_parts)))
goto err;
for (i=0 ; i < keys ; i++, keyinfo++)
@@ -3314,8 +3315,8 @@ bool TABLE_LIST::prep_check_option(THD *thd, uint8 check_opt_type)
{
const char *save_where= thd->where;
thd->where= "check option";
- if (!check_option->fixed &&
- check_option->fix_fields(thd, &check_option) ||
+ if ((!check_option->fixed &&
+ check_option->fix_fields(thd, &check_option)) ||
check_option->check_cols(1))
{
DBUG_RETURN(TRUE);
@@ -3341,6 +3342,7 @@ void TABLE_LIST::hide_view_error(THD *thd)
if (thd->main_da.sql_errno() == ER_BAD_FIELD_ERROR ||
thd->main_da.sql_errno() == ER_SP_DOES_NOT_EXIST ||
+ thd->main_da.sql_errno() == ER_FUNC_INEXISTENT_NAME_COLLISION ||
thd->main_da.sql_errno() == ER_PROCACCESS_DENIED_ERROR ||
thd->main_da.sql_errno() == ER_COLUMNACCESS_DENIED_ERROR ||
thd->main_da.sql_errno() == ER_TABLEACCESS_DENIED_ERROR ||
@@ -4030,7 +4032,7 @@ void Field_iterator_table_ref::set_field_iterator()
/* Necesary, but insufficient conditions. */
DBUG_ASSERT(table_ref->is_natural_join ||
table_ref->nested_join ||
- table_ref->join_columns &&
+ (table_ref->join_columns &&
/* This is a merge view. */
((table_ref->field_translation &&
table_ref->join_columns->elements ==
@@ -4039,7 +4041,7 @@ void Field_iterator_table_ref::set_field_iterator()
/* This is stored table or a tmptable view. */
(!table_ref->field_translation &&
table_ref->join_columns->elements ==
- table_ref->table->s->fields)));
+ table_ref->table->s->fields))));
field_it= &natural_join_it;
DBUG_PRINT("info",("field_it for '%s' is Field_iterator_natural_join",
table_ref->alias));
diff --git a/sql/thr_malloc.cc b/sql/thr_malloc.cc
index 6bf43b51df0..0764fe8be33 100644
--- a/sql/thr_malloc.cc
+++ b/sql/thr_malloc.cc
@@ -21,7 +21,7 @@
extern "C" {
void sql_alloc_error_handler(void)
{
- sql_print_error(ER(ER_OUT_OF_RESOURCES));
+ sql_print_error("%s", ER(ER_OUT_OF_RESOURCES));
THD *thd= current_thd;
if (thd)
diff --git a/sql/time.cc b/sql/time.cc
index a6619cf4cee..962b65e454c 100644
--- a/sql/time.cc
+++ b/sql/time.cc
@@ -111,8 +111,8 @@ uint calc_week(MYSQL_TIME *l_time, uint week_behaviour, uint *year)
if (l_time->month == 1 && l_time->day <= 7-weekday)
{
if (!week_year &&
- (first_weekday && weekday != 0 ||
- !first_weekday && weekday >= 4))
+ ((first_weekday && weekday != 0) ||
+ (!first_weekday && weekday >= 4)))
return 0;
week_year= 1;
(*year)--;
@@ -129,8 +129,8 @@ uint calc_week(MYSQL_TIME *l_time, uint week_behaviour, uint *year)
if (week_year && days >= 52*7)
{
weekday= (weekday + calc_days_in_year(*year)) % 7;
- if (!first_weekday && weekday < 4 ||
- first_weekday && weekday == 0)
+ if ((!first_weekday && weekday < 4) ||
+ (first_weekday && weekday == 0))
{
(*year)++;
return 1;
diff --git a/sql/tztime.cc b/sql/tztime.cc
index 2a94e179600..c7a4ad049ec 100644
--- a/sql/tztime.cc
+++ b/sql/tztime.cc
@@ -447,8 +447,8 @@ prepare_tz_info(TIME_ZONE_INFO *sp, MEM_ROOT *storage)
}
if (end_t == MY_TIME_T_MAX ||
- (cur_off_and_corr > 0) &&
- (end_t >= MY_TIME_T_MAX - cur_off_and_corr))
+ ((cur_off_and_corr > 0) &&
+ (end_t >= MY_TIME_T_MAX - cur_off_and_corr)))
/* end of t space */
break;
diff --git a/sql/uniques.cc b/sql/uniques.cc
index 858bedb04cd..7b6b628f924 100644
--- a/sql/uniques.cc
+++ b/sql/uniques.cc
@@ -603,9 +603,9 @@ bool Unique::get(TABLE *table)
outfile=table->sort.io_cache=(IO_CACHE*) my_malloc(sizeof(IO_CACHE),
MYF(MY_ZEROFILL));
- if (!outfile || ! my_b_inited(outfile) &&
+ if (!outfile || (! my_b_inited(outfile) &&
open_cached_file(outfile,mysql_tmpdir,TEMP_PREFIX,READ_RECORD_BUFFER,
- MYF(MY_WME)))
+ MYF(MY_WME))))
return 1;
reinit_io_cache(outfile,WRITE_CACHE,0L,0,0);
diff --git a/sql/unireg.cc b/sql/unireg.cc
index 51293184ad8..68a352e4a44 100644
--- a/sql/unireg.cc
+++ b/sql/unireg.cc
@@ -37,8 +37,7 @@ static bool pack_header(uchar *forminfo,enum legacy_db_type table_type,
List &create_fields,
uint info_length, uint screens, uint table_options,
ulong data_offset, handler *file);
-static uint get_interval_id(uint *int_count,List &create_fields,
- Create_field *last_field);
+static uint get_interval_id(uint *,List &, Create_field *);
static bool pack_fields(File file, List &create_fields,
ulong data_offset);
static bool make_empty_rec(THD *thd, int file, enum legacy_db_type table_type,
diff --git a/storage/Makefile.am b/storage/Makefile.am
index 4f19be3a361..8aa1e4f7dc6 100644
--- a/storage/Makefile.am
+++ b/storage/Makefile.am
@@ -18,7 +18,7 @@
AUTOMAKE_OPTIONS = foreign
# These are built from source in the Docs directory
-EXTRA_DIST =
+EXTRA_DIST = mysql_storage_engine.cmake
SUBDIRS = @mysql_se_dirs@
DIST_SUBDIRS = @mysql_se_distdirs@
diff --git a/storage/archive/CMakeLists.txt b/storage/archive/CMakeLists.txt
index 1c53ad15c07..ce4d92d3f99 100644
--- a/storage/archive/CMakeLists.txt
+++ b/storage/archive/CMakeLists.txt
@@ -13,17 +13,6 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX")
-SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX")
-
-INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/zlib
- ${CMAKE_SOURCE_DIR}/sql
- ${CMAKE_SOURCE_DIR}/regex
- ${CMAKE_SOURCE_DIR}/extra/yassl/include)
-
+INCLUDE("${PROJECT_SOURCE_DIR}/storage/mysql_storage_engine.cmake")
SET(ARCHIVE_SOURCES azio.c ha_archive.cc ha_archive.h)
-
-IF(NOT SOURCE_SUBLIBS)
- ADD_LIBRARY(archive ${ARCHIVE_SOURCES})
- ADD_DEPENDENCIES(archive GenError)
-ENDIF(NOT SOURCE_SUBLIBS)
+MYSQL_STORAGE_ENGINE(ARCHIVE)
diff --git a/storage/archive/ha_archive.cc b/storage/archive/ha_archive.cc
index 46e9a99c446..7f7f3534a22 100644
--- a/storage/archive/ha_archive.cc
+++ b/storage/archive/ha_archive.cc
@@ -1497,8 +1497,8 @@ int ha_archive::info(uint flag)
stats.mean_rec_length= table->s->reclength + buffer.alloced_length();
stats.data_file_length= file_stat.st_size;
- stats.create_time= file_stat.st_ctime;
- stats.update_time= file_stat.st_mtime;
+ stats.create_time= (ulong) file_stat.st_ctime;
+ stats.update_time= (ulong) file_stat.st_mtime;
stats.max_data_file_length= share->rows_recorded * stats.mean_rec_length;
}
stats.delete_length= 0;
diff --git a/storage/blackhole/CMakeLists.txt b/storage/blackhole/CMakeLists.txt
index b11330db255..b762228d7fd 100644
--- a/storage/blackhole/CMakeLists.txt
+++ b/storage/blackhole/CMakeLists.txt
@@ -16,13 +16,7 @@
SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX")
SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX")
-INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/sql
- ${CMAKE_SOURCE_DIR}/regex
- ${CMAKE_SOURCE_DIR}/extra/yassl/include)
-
+INCLUDE("${PROJECT_SOURCE_DIR}/storage/mysql_storage_engine.cmake")
SET(BLACKHOLE_SOURCES ha_blackhole.cc ha_blackhole.h)
-IF(NOT SOURCE_SUBLIBS)
- ADD_LIBRARY(blackhole ${BLACKHOLE_SOURCES})
- ADD_DEPENDENCIES(blackhole GenError)
-ENDIF(NOT SOURCE_SUBLIBS)
+MYSQL_STORAGE_ENGINE(BLACKHOLE)
diff --git a/storage/csv/CMakeLists.txt b/storage/csv/CMakeLists.txt
index 528b9928c76..eb21a9b048c 100644
--- a/storage/csv/CMakeLists.txt
+++ b/storage/csv/CMakeLists.txt
@@ -16,13 +16,6 @@
SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX")
SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX")
-INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/sql
- ${CMAKE_SOURCE_DIR}/regex
- ${CMAKE_SOURCE_DIR}/extra/yassl/include)
-
+INCLUDE("${PROJECT_SOURCE_DIR}/storage/mysql_storage_engine.cmake")
SET(CSV_SOURCES ha_tina.cc ha_tina.h transparent_file.cc transparent_file.h)
-
-IF(NOT SOURCE_SUBLIBS)
- ADD_LIBRARY(csv ${CSV_SOURCES})
- ADD_DEPENDENCIES(csv GenError)
-ENDIF(NOT SOURCE_SUBLIBS)
+MYSQL_STORAGE_ENGINE(CSV)
\ No newline at end of file
diff --git a/storage/example/CMakeLists.txt b/storage/example/CMakeLists.txt
index 0af60e1df83..a328da107bd 100644
--- a/storage/example/CMakeLists.txt
+++ b/storage/example/CMakeLists.txt
@@ -15,14 +15,6 @@
SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX")
SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX")
-
-INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/sql
- ${CMAKE_SOURCE_DIR}/regex
- ${CMAKE_SOURCE_DIR}/extra/yassl/include)
-
+INCLUDE("${PROJECT_SOURCE_DIR}/storage/mysql_storage_engine.cmake")
SET(EXAMPLE_SOURCES ha_example.cc)
-
-IF(NOT SOURCE_SUBLIBS)
- ADD_LIBRARY(example ${EXAMPLE_SOURCES})
- ADD_DEPENDENCIES(example GenError)
-ENDIF(NOT SOURCE_SUBLIBS)
+MYSQL_STORAGE_ENGINE(EXAMPLE)
diff --git a/storage/federated/CMakeLists.txt b/storage/federated/CMakeLists.txt
index b96f68a3c37..fa54d36481a 100644
--- a/storage/federated/CMakeLists.txt
+++ b/storage/federated/CMakeLists.txt
@@ -13,16 +13,6 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX")
-SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX")
-
-INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/sql
- ${CMAKE_SOURCE_DIR}/regex
- ${CMAKE_SOURCE_DIR}/extra/yassl/include)
-
+INCLUDE("${PROJECT_SOURCE_DIR}/storage/mysql_storage_engine.cmake")
SET(FEDERATED_SOURCES ha_federated.cc)
-
-IF(NOT SOURCE_SUBLIBS)
- ADD_LIBRARY(federated ${FEDERATED_SOURCES})
- ADD_DEPENDENCIES(federated GenError)
-ENDIF(NOT SOURCE_SUBLIBS)
+MYSQL_STORAGE_ENGINE(FEDERATED)
diff --git a/storage/federated/ha_federated.cc b/storage/federated/ha_federated.cc
index e22e342c65e..a3fa42d7d05 100644
--- a/storage/federated/ha_federated.cc
+++ b/storage/federated/ha_federated.cc
@@ -2856,34 +2856,32 @@ int ha_federated::info(uint flag)
if (!(row= mysql_fetch_row(result)))
goto error;
- if (flag & (HA_STATUS_VARIABLE | HA_STATUS_CONST))
- {
- /*
- deleted is set in ha_federated::info
- */
- /*
- need to figure out what this means as far as federated is concerned,
- since we don't have a "file"
+ /*
+ deleted is set in ha_federated::info
+ */
+ /*
+ need to figure out what this means as far as federated is concerned,
+ since we don't have a "file"
- data_file_length = ?
- index_file_length = ?
- delete_length = ?
- */
- if (row[4] != NULL)
- stats.records= (ha_rows) my_strtoll10(row[4], (char**) 0,
+ data_file_length = ?
+ index_file_length = ?
+ delete_length = ?
+ */
+ if (row[4] != NULL)
+ stats.records= (ha_rows) my_strtoll10(row[4], (char**) 0,
&error);
- if (row[5] != NULL)
- stats.mean_rec_length= (ulong) my_strtoll10(row[5], (char**) 0, &error);
+ if (row[5] != NULL)
+ stats.mean_rec_length= (ulong) my_strtoll10(row[5], (char**) 0, &error);
- stats.data_file_length= stats.records * stats.mean_rec_length;
+ stats.data_file_length= stats.records * stats.mean_rec_length;
- if (row[12] != NULL)
- stats.update_time= (time_t) my_strtoll10(row[12], (char**) 0,
+ if (row[12] != NULL)
+ stats.update_time= (ulong) my_strtoll10(row[12], (char**) 0,
&error);
- if (row[13] != NULL)
- stats.check_time= (time_t) my_strtoll10(row[13], (char**) 0,
+ if (row[13] != NULL)
+ stats.check_time= (ulong) my_strtoll10(row[13], (char**) 0,
&error);
- }
+
/*
size of IO operations (This is based on a good guess, no high science
involved)
diff --git a/storage/heap/CMakeLists.txt b/storage/heap/CMakeLists.txt
index f8f0aa91464..c2d2cd1290f 100755
--- a/storage/heap/CMakeLists.txt
+++ b/storage/heap/CMakeLists.txt
@@ -16,18 +16,10 @@
SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX")
SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX")
-INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/zlib
- ${CMAKE_SOURCE_DIR}/sql
- ${CMAKE_SOURCE_DIR}/regex
- ${CMAKE_SOURCE_DIR}/extra/yassl/include)
-
+INCLUDE("${PROJECT_SOURCE_DIR}/storage/mysql_storage_engine.cmake")
SET(HEAP_SOURCES _check.c _rectest.c hp_block.c hp_clear.c hp_close.c hp_create.c
ha_heap.cc
hp_delete.c hp_extra.c hp_hash.c hp_info.c hp_open.c hp_panic.c
hp_rename.c hp_rfirst.c hp_rkey.c hp_rlast.c hp_rnext.c hp_rprev.c
hp_rrnd.c hp_rsame.c hp_scan.c hp_static.c hp_update.c hp_write.c)
-
-IF(NOT SOURCE_SUBLIBS)
- ADD_LIBRARY(heap ${HEAP_SOURCES})
- ADD_DEPENDENCIES(heap GenError)
-ENDIF(NOT SOURCE_SUBLIBS)
+MYSQL_STORAGE_ENGINE(HEAP)
diff --git a/storage/heap/ha_heap.cc b/storage/heap/ha_heap.cc
index 1f74ad0f941..99c1ca5d2e9 100644
--- a/storage/heap/ha_heap.cc
+++ b/storage/heap/ha_heap.cc
@@ -440,6 +440,14 @@ int ha_heap::delete_all_rows()
return 0;
}
+
+int ha_heap::reset_auto_increment(ulonglong value)
+{
+ file->s->auto_increment= value;
+ return 0;
+}
+
+
int ha_heap::external_lock(THD *thd, int lock_type)
{
return 0; // No external locking
diff --git a/storage/heap/ha_heap.h b/storage/heap/ha_heap.h
index 5c5ad43658e..22722129f4c 100644
--- a/storage/heap/ha_heap.h
+++ b/storage/heap/ha_heap.h
@@ -98,6 +98,7 @@ public:
int reset();
int external_lock(THD *thd, int lock_type);
int delete_all_rows(void);
+ int reset_auto_increment(ulonglong value);
int disable_indexes(uint mode);
int enable_indexes(uint mode);
int indexes_are_disabled(void);
diff --git a/storage/ibmdb2i/db2i_charsetSupport.cc b/storage/ibmdb2i/db2i_charsetSupport.cc
index 2609d42887e..83bf1b9448b 100644
--- a/storage/ibmdb2i/db2i_charsetSupport.cc
+++ b/storage/ibmdb2i/db2i_charsetSupport.cc
@@ -129,8 +129,8 @@ struct IconvMap
{
struct HashKey
{
- uint16 direction; // This is a uint16 instead of a uchar to avoid garbage data in the key from compiler padding
- uint16 db2CCSID;
+ uint32 direction; // These are uint32s to avoid garbage data in the key from compiler padding
+ uint32 db2CCSID;
const CHARSET_INFO* myCharset;
} hashKey;
iconv_t iconvDesc;
@@ -245,11 +245,16 @@ static int32 getNewTextDesc(const int32 inType,
else if ((inType == Qlg_TypeAS400CCSID) && (outType == Qlg_TypeAix41))
{
// Override non-standard charsets
- if (unlikely(strcmp("1148", in) == 0))
+ if (strcmp("1148", in) == 0)
{
strcpy(out, "IBM-1148");
DBUG_RETURN(0);
}
+ else if (unlikely(strcmp("1153", in) == 0))
+ {
+ strcpy(out, "IBM-1153");
+ DBUG_RETURN(0);
+ }
}
char argBuf[sizeof(ArgList)+15];
@@ -268,8 +273,15 @@ static int32 getNewTextDesc(const int32 inType,
RESULT_INT32);
if (unlikely(arguments->base.result.s_int32.r_int32 < 0))
{
- getErrTxt(DB2I_ERR_ILECALL,"QlgCvtTextDescToDesc",arguments->base.result.s_int32.r_int32);
- DBUG_RETURN(DB2I_ERR_ILECALL);
+ if (arguments->base.result.s_int32.r_int32 == Qlg_InDescriptorNotFound)
+ {
+ DBUG_RETURN(DB2I_ERR_UNSUPP_CHARSET);
+ }
+ else
+ {
+ getErrTxt(DB2I_ERR_ILECALL,"QlgCvtTextDescToDesc",arguments->base.result.s_int32.r_int32);
+ DBUG_RETURN(DB2I_ERR_ILECALL);
+ }
}
// Store the conversion information into a cache entry
@@ -372,6 +384,11 @@ static int32 convertTextDesc(const int32 inType, const int32 outType, const char
strcpy(outDesc,"IBM-1256");
DBUG_RETURN(0);
}
+ else if (strcmp("macce", inDescOverride) == 0)
+ {
+ strcpy(outDesc,"IBM-1282");
+ DBUG_RETURN(0);
+ }
}
else if (outType == Qlg_TypeAS400CCSID)
{
@@ -428,8 +445,13 @@ int32 convertIANAToDb2Ccsid(const char* parmIANADesc, uint16* db2Ccsid)
int aixEncodingScheme;
int db2EncodingScheme;
rc = convertTextDesc(Qlg_TypeIANA, Qlg_TypeAS400CCSID, parmIANADesc, aixCcsidString);
- if (rc != 0)
+ if (unlikely(rc))
+ {
+ if (rc == DB2I_ERR_UNSUPP_CHARSET)
+ getErrTxt(DB2I_ERR_UNSUPP_CHARSET, parmIANADesc);
+
return rc;
+ }
aixCcsid = atoi(aixCcsidString);
rc = getEncodingScheme(aixCcsid, aixEncodingScheme);
if (rc != 0)
@@ -571,6 +593,11 @@ int32 getAssociatedCCSID(const uint16 inCcsid, const int inEncodingScheme, uint1
*outCcsid = 1148;
DBUG_RETURN(0);
}
+ else if ((inCcsid == 1250) && (inEncodingScheme == 0x1100))
+ {
+ *outCcsid = 1153;
+ DBUG_RETURN(0);
+ }
if (!ptrInited)
{
@@ -646,32 +673,38 @@ static int32 openNewConversion(enum_conversionDirection direction,
there equivalent iconv descriptions.
*/
rc = convertTextDesc(Qlg_TypeIANA, Qlg_TypeAix41, mysqlCSName, mysqlAix41Desc);
- if (rc)
+ if (unlikely(rc))
+ {
+ if (rc == DB2I_ERR_UNSUPP_CHARSET)
+ getErrTxt(DB2I_ERR_UNSUPP_CHARSET, mysqlCSName);
+
DBUG_RETURN(rc);
+ }
CHARSET_INFO *cs= &my_charset_bin;
(uint)(cs->cset->long10_to_str)(cs,db2CcsidString,sizeof(db2CcsidString), 10, db2CCSID);
rc = convertTextDesc(Qlg_TypeAS400CCSID, Qlg_TypeAix41, db2CcsidString, db2Aix41Desc);
- if (rc)
- DBUG_RETURN(rc);
+ if (unlikely(rc))
+ {
+ if (rc == DB2I_ERR_UNSUPP_CHARSET)
+ getErrTxt(DB2I_ERR_UNSUPP_CHARSET, mysqlCSName);
+
+ DBUG_RETURN(rc);
+ }
/* Call iconv to open the conversion. */
if (direction == toDB2)
{
newConversion = iconv_open(db2Aix41Desc, mysqlAix41Desc);
- if (newConversion == (iconv_t) -1)
- {
- getErrTxt(DB2I_ERR_ICONV_OPEN, mysqlAix41Desc, db2Aix41Desc, errno);
- DBUG_RETURN(DB2I_ERR_ICONV_OPEN);
- }
}
else
{
newConversion = iconv_open(mysqlAix41Desc, db2Aix41Desc);
- if (newConversion == (iconv_t) -1)
- {
- getErrTxt(DB2I_ERR_ICONV_OPEN, db2Aix41Desc, mysqlAix41Desc, errno);
- DBUG_RETURN(DB2I_ERR_ICONV_OPEN);
- }
+ }
+
+ if (unlikely(newConversion == (iconv_t) -1))
+ {
+ getErrTxt(DB2I_ERR_UNSUPP_CHARSET, mysqlCSName);
+ DBUG_RETURN(DB2I_ERR_UNSUPP_CHARSET);
}
/* Insert the new conversion into the cache. */
diff --git a/storage/ibmdb2i/db2i_collationSupport.cc b/storage/ibmdb2i/db2i_collationSupport.cc
index a41f211a689..65a17fd2452 100644
--- a/storage/ibmdb2i/db2i_collationSupport.cc
+++ b/storage/ibmdb2i/db2i_collationSupport.cc
@@ -44,7 +44,7 @@ OF SUCH DAMAGE.
between corresponding array slots but is incomplete without case-sensitivity
markers dynamically added to the mySqlSortSequence names.
*/
-#define MAX_COLLATION 89
+#define MAX_COLLATION 87
static const char* mySQLCollation[MAX_COLLATION] =
{
{"ascii_general"},
@@ -52,7 +52,6 @@ static const char* mySQLCollation[MAX_COLLATION] =
{"big5_chinese"},
{"big5"},
{"cp1250_croatian"},
- {"cp1250_czech"},
{"cp1250_general"},
{"cp1250_polish"},
{"cp1250"},
@@ -84,7 +83,6 @@ static const char* mySQLCollation[MAX_COLLATION] =
{"latin1_swedish"},
{"latin1"},
{"latin2_croatian"},
- {"latin2_czech"},
{"latin2_general"},
{"latin2_hungarian"},
{"latin2"},
@@ -146,7 +144,6 @@ static const char* mySqlSortSequence[MAX_COLLATION] =
{"QACHT04B0"},
{"QBCHT04B0"},
{"QALA20481"},
- {"QBLA20481"},
{"QCLA20481"},
{"QDLA20481"},
{"QELA20481"},
@@ -178,7 +175,6 @@ static const char* mySqlSortSequence[MAX_COLLATION] =
{"QELA1047C"},
{"QFLA1047C"},
{"QCLA20366"},
- {"QDLA20366"},
{"QELA20366"},
{"QFLA20366"},
{"QGLA20366"},
@@ -190,8 +186,8 @@ static const char* mySqlSortSequence[MAX_COLLATION] =
{"QDJPN04B0"},
{"QATHA0346"},
{"QBTHA0346"},
- {"ACS"},
- {"ADA"},
+ {"ACS_CZ"},
+ {"ADA_DK"},
{"AEO"},
{"AET"},
{"QAUCS04B0"},
@@ -211,8 +207,8 @@ static const char* mySqlSortSequence[MAX_COLLATION] =
{"*HEX"},
{"QEJPN04B0"},
{"QFJPN04B0"},
- {"ACS"},
- {"ADA"},
+ {"ACS_CZ"},
+ {"ADA_DK"},
{"AEO"},
{"AET"},
{"QAUCS04B0"},
diff --git a/storage/ibmdb2i/db2i_conversion.cc b/storage/ibmdb2i/db2i_conversion.cc
index f746be6ab50..9a85eb01c9b 100644
--- a/storage/ibmdb2i/db2i_conversion.cc
+++ b/storage/ibmdb2i/db2i_conversion.cc
@@ -137,7 +137,9 @@ int ha_ibmdb2i::convertFieldChars(enum_conversionDirection direction,
char* output,
size_t ilen,
size_t olen,
- size_t* outDataLen)
+ size_t* outDataLen,
+ bool tacitErrors,
+ size_t* substChars)
{
DBUG_PRINT("ha_ibmdb2i::convertFieldChars",("Direction: %d; length = %d", direction, ilen));
@@ -151,32 +153,32 @@ int ha_ibmdb2i::convertFieldChars(enum_conversionDirection direction,
if (unlikely(conversion == (iconv_t)(-1)))
{
- return (DB2I_ERR_ICONV_OPEN);
+ return (DB2I_ERR_UNSUPP_CHARSET);
}
size_t initOLen= olen;
size_t substitutedChars = 0;
int rc = iconv(conversion, (char**)&input, &ilen, &output, &olen, &substitutedChars );
+ if (outDataLen) *outDataLen = initOLen - olen;
+ if (substChars) *substChars = substitutedChars;
if (unlikely(rc < 0))
{
int er = errno;
if (er == EILSEQ)
{
- getErrTxt(DB2I_ERR_ILL_CHAR, table->field[fieldID]->field_name);
+ if (!tacitErrors) getErrTxt(DB2I_ERR_ILL_CHAR, table->field[fieldID]->field_name);
return (DB2I_ERR_ILL_CHAR);
}
else
{
- getErrTxt(DB2I_ERR_ICONV,er);
+ if (!tacitErrors) getErrTxt(DB2I_ERR_ICONV,er);
return (DB2I_ERR_ICONV);
}
}
- if (unlikely(substitutedChars))
+ if (unlikely(substitutedChars) && (!tacitErrors))
{
warning(ha_thd(), DB2I_ERR_SUB_CHARS, table->field[fieldID]->field_name);
}
-
- if (outDataLen) *outDataLen = initOLen - olen;
return (0);
}
@@ -555,12 +557,12 @@ int ha_ibmdb2i::getFieldTypeMapping(Field* field,
return 1;
if (fieldCharSet->mbmaxlen > 1)
{
- if (strncmp(fieldCharSet->name, "ucs2_", sizeof("ucs2_")) == 0 ) // UCS2
+ if (memcmp(fieldCharSet->name, "ucs2_", sizeof("ucs2_")-1) == 0 ) // UCS2
{
sprintf(stringBuildBuffer, "GRAPHIC(%d)", max(fieldLength / fieldCharSet->mbmaxlen, 1)); // Number of characters
db2Ccsid = 13488;
}
- else if (strncmp(fieldCharSet->name, "utf8_", sizeof("utf8_")) == 0 &&
+ else if (memcmp(fieldCharSet->name, "utf8_", sizeof("utf8_")-1) == 0 &&
strcmp(fieldCharSet->name, "utf8_general_ci") != 0)
{
sprintf(stringBuildBuffer, "CHAR(%d)", max(fieldLength, 1)); // Number of bytes
@@ -584,12 +586,12 @@ int ha_ibmdb2i::getFieldTypeMapping(Field* field,
{
if (fieldCharSet->mbmaxlen > 1)
{
- if (strncmp(fieldCharSet->name, "ucs2_", sizeof("ucs2_")) == 0 ) // UCS2
+ if (memcmp(fieldCharSet->name, "ucs2_", sizeof("ucs2_")-1) == 0 ) // UCS2
{
sprintf(stringBuildBuffer, "VARGRAPHIC(%d)", max(fieldLength / fieldCharSet->mbmaxlen, 1)); // Number of characters
db2Ccsid = 13488;
}
- else if (strncmp(fieldCharSet->name, "utf8_", sizeof("utf8_")) == 0 &&
+ else if (memcmp(fieldCharSet->name, "utf8_", sizeof("utf8_")-1) == 0 &&
strcmp(fieldCharSet->name, "utf8_general_ci") != 0)
{
sprintf(stringBuildBuffer, "VARCHAR(%d)", max(fieldLength, 1)); // Number of bytes
@@ -611,12 +613,12 @@ int ha_ibmdb2i::getFieldTypeMapping(Field* field,
{
if (fieldCharSet->mbmaxlen > 1)
{
- if (strncmp(fieldCharSet->name, "ucs2_", sizeof("ucs2_")) == 0 ) // UCS2
+ if (memcmp(fieldCharSet->name, "ucs2_", sizeof("ucs2_")-1) == 0 ) // UCS2
{
sprintf(stringBuildBuffer, "LONG VARGRAPHIC ");
db2Ccsid = 13488;
}
- else if (strncmp(fieldCharSet->name, "utf8_", sizeof("utf8_")) == 0 &&
+ else if (memcmp(fieldCharSet->name, "utf8_", sizeof("utf8_")-1) == 0 &&
strcmp(fieldCharSet->name, "utf8_general_ci") != 0)
{
sprintf(stringBuildBuffer, "LONG VARCHAR ");
@@ -639,12 +641,12 @@ int ha_ibmdb2i::getFieldTypeMapping(Field* field,
if (fieldCharSet->mbmaxlen > 1)
{
- if (strncmp(fieldCharSet->name, "ucs2_", sizeof("ucs2_")) == 0 ) // UCS2
+ if (memcmp(fieldCharSet->name, "ucs2_", sizeof("ucs2_")-1) == 0 ) // UCS2
{
sprintf(stringBuildBuffer, "DBCLOB(%d)", max(fieldLength / fieldCharSet->mbmaxlen, 1)); // Number of characters
db2Ccsid = 13488;
}
- else if (strncmp(fieldCharSet->name, "utf8_", sizeof("utf8_")) == 0 &&
+ else if (memcmp(fieldCharSet->name, "utf8_", sizeof("utf8_")-1) == 0 &&
strcmp(fieldCharSet->name, "utf8_general_ci") != 0)
{
sprintf(stringBuildBuffer, "CLOB(%d)", max(fieldLength, 1)); // Number of bytes
@@ -670,6 +672,17 @@ int ha_ibmdb2i::getFieldTypeMapping(Field* field,
if (rtnCode)
return rtnCode;
}
+
+ if (db2Ccsid != 1208 &&
+ db2Ccsid != 13488)
+ {
+ // Check whether there is a character conversion available.
+ iconv_t temp;
+ int32 rc = getConversion(toDB2, fieldCharSet, db2Ccsid, temp);
+ if (unlikely(rc))
+ return rc;
+ }
+
sprintf(stringBuildBuffer, " CCSID %d ", db2Ccsid);
mapping.append(stringBuildBuffer);
}
@@ -1078,7 +1091,7 @@ int32 ha_ibmdb2i::convertMySQLtoDB2(Field* field, const DB2Field& db2Field, char
if (bytesToStore)
memcpy(db2Buf, dataToStore, bytesToStore);
if (bytesToPad)
- wmemset((wchar_t*)(db2Buf + bytesToStore), 0x0020, bytesToPad/2);
+ memset16((db2Buf + bytesToStore), 0x0020, bytesToPad/2);
}
else
{
@@ -1101,7 +1114,7 @@ int32 ha_ibmdb2i::convertMySQLtoDB2(Field* field, const DB2Field& db2Field, char
bytesToStore = db2BytesToStore;
}
if (db2BytesToStore < maxDb2BytesToStore) // If need to pad
- wmemset((wchar_t*)(db2Buf + db2BytesToStore), 0x0020, (maxDb2BytesToStore - db2BytesToStore)/2);
+ memset16((db2Buf + db2BytesToStore), 0x0020, (maxDb2BytesToStore - db2BytesToStore)/2);
}
if (db2FieldType == QMY_VARGRAPHIC)
diff --git a/storage/ibmdb2i/db2i_errors.cc b/storage/ibmdb2i/db2i_errors.cc
index 43dd539447f..dd50e40e61b 100644
--- a/storage/ibmdb2i/db2i_errors.cc
+++ b/storage/ibmdb2i/db2i_errors.cc
@@ -52,7 +52,7 @@ static const char* engineErrors[MAX_MSGSTRING] =
{"Error opening codeset conversion from %.64s to %.64s (errno = %d)"},
{"Invalid %-.10s name '%-.128s'"},
{"Unsupported move from '%-.128s' to '%-.128s' on RENAME TABLE statement"},
- {"Unsupported schema '%-.128s' specified on RENAME TABLE statement"},
+ {"The %-.64s character set is not supported."},
{"Auto_increment is not allowed for a partitioned table"},
{"Character set conversion error due to unknown encoding scheme %d"},
{""},
diff --git a/storage/ibmdb2i/db2i_errors.h b/storage/ibmdb2i/db2i_errors.h
index 0f6fbef33f6..b6dd314ef50 100644
--- a/storage/ibmdb2i/db2i_errors.h
+++ b/storage/ibmdb2i/db2i_errors.h
@@ -54,7 +54,7 @@ enum DB2I_errors
DB2I_ERR_ICONV_OPEN,
DB2I_ERR_INVALID_NAME,
DB2I_ERR_RENAME_MOVE,
- DB2I_ERR_RENAME_QTEMP,
+ DB2I_ERR_UNSUPP_CHARSET,
DB2I_ERR_PART_AUTOINC,
DB2I_ERR_UNKNOWN_ENCODING,
DB2I_ERR_RESERVED,
diff --git a/storage/ibmdb2i/db2i_misc.h b/storage/ibmdb2i/db2i_misc.h
index 9e20f01208b..f0b527aaad0 100644
--- a/storage/ibmdb2i/db2i_misc.h
+++ b/storage/ibmdb2i/db2i_misc.h
@@ -109,5 +109,21 @@ bool isOrdinaryIdentifier(const char* s)
}
return true;
}
+
+/**
+ Fill memory with a 16-bit word.
+ @param p Pointer to space to fill.
+ @param v Value to fill
+ @param l Length of space (in 16-bit words)
+*/
+void memset16(void* p, uint16 v, size_t l)
+{
+ uint16* p2=(uint16*)p;
+ while (l--)
+ {
+ *(p2++) = v;
+ }
+}
+
#endif
diff --git a/storage/ibmdb2i/db2i_myconv.h b/storage/ibmdb2i/db2i_myconv.h
index a9e87474505..98032748148 100644
--- a/storage/ibmdb2i/db2i_myconv.h
+++ b/storage/ibmdb2i/db2i_myconv.h
@@ -220,6 +220,7 @@ INTERN size_t myconv_dmap(myconv_t cd,
} else {
*pOut=dmapS2S[*pIn];
if (*pOut == 0x00) {
+ errno=EILSEQ; /* 116 */
*outBytesLeft-=(*inBytesLeft-inLen);
*inBytesLeft=inLen;
*outBuf=pOut;
diff --git a/storage/ibmdb2i/db2i_rir.cc b/storage/ibmdb2i/db2i_rir.cc
index a80a181c9ac..091c4d98383 100644
--- a/storage/ibmdb2i/db2i_rir.cc
+++ b/storage/ibmdb2i/db2i_rir.cc
@@ -51,7 +51,6 @@ static inline int getKeyCntFromMap(key_part_map keypart_map)
return (cnt);
}
-
/**
@brief
Given a starting key and an ending key, estimate the number of rows that
@@ -270,81 +269,163 @@ ha_rows ha_ibmdb2i::records_in_range(uint inx,
DB2Field& db2Field = db2Table->db2Field(field->field_index);
litDefPtr->DataType = db2Field.getType();
/*
- Convert the literal to DB2 format.
- */
- rc = convertMySQLtoDB2(field,
- db2Field,
- literalPtr,
- (uchar*)minPtr+((curKey.key_part[partsInUse].null_bit)? 1 : 0));
+ Convert the literal to DB2 format
+ */
+ if ((field->type() != MYSQL_TYPE_BIT) && // Don't do conversion on BIT data
+ (field->charset() != &my_charset_bin) && // Don't do conversion on BINARY data
+ (litDefPtr->DataType == QMY_CHAR ||
+ litDefPtr->DataType == QMY_VARCHAR ||
+ litDefPtr->DataType == QMY_GRAPHIC ||
+ litDefPtr->DataType == QMY_VARGRAPHIC))
+ {
+ // Most of the code is required by the considerable wrangling needed
+ // to prepare partial keys for use by DB2
+ // 1. UTF8 (CCSID 1208) data can be copied across unmodified if it is
+ // utf8_bin. Otherwise, we need to convert the min and max
+ // characters into the min and max characters employed
+ // by the DB2 sort sequence. This is complicated by the fact that
+ // the character widths are not always equal.
+ // 2. Likewise, UCS2 (CCSID 13488) data can be copied across unmodified
+ // if it is ucs2_bin or ucs2_general_ci. Otherwise, we need to
+ // convert the min and max characters into the min and max characters
+ // employed by the DB2 sort sequence.
+ // 3. All other data will use standard iconv conversions. If an
+ // unconvertible character is encountered, we assume it is the min
+ // char and fill the remainder of the DB2 key with 0s. This may not
+ // always be accurate, but it is probably sufficient for range
+ // estimations.
+ const char* keyData = minPtr+((curKey.key_part[partsInUse].null_bit)? 1 : 0);
+ char* db2Data = literalPtr;
+ uint16 outLen = db2Field.getByteLengthInRecord();
+ uint16 inLen;
+ if (litDefPtr->DataType == QMY_VARCHAR ||
+ litDefPtr->DataType == QMY_VARGRAPHIC)
+ {
+ inLen = *(uint8*)keyData + ((*(uint8*)(keyData+1)) << 8);
+ keyData += 2;
+ outLen -= sizeof(uint16);
+ db2Data += sizeof(uint16);
+ }
+ else
+ {
+ inLen = field->max_display_length();
+ }
+
+ size_t convertedBytes = 0;
+ if (db2Field.getCCSID() == 1208)
+ {
+ DBUG_ASSERT(inLen <= outLen);
+ if (strcmp(field->charset()->name, "utf8_bin"))
+ {
+ const char* end = keyData+inLen;
+ const char* curKey = keyData;
+ char* curDB2 = db2Data;
+ uint32 min = field->charset()->min_sort_char;
+ while ((curKey < end) && (curDB2 < db2Data+outLen-3))
+ {
+ my_wc_t temp;
+ int len = field->charset()->cset->mb_wc(field->charset(),
+ &temp,
+ (const uchar*)curKey,
+ (const uchar*)end);
+ if (temp != min)
+ {
+ DBUG_ASSERT(len <= 3);
+ switch (len)
+ {
+ case 3: *(curDB2+2) = *(curKey+2);
+ case 2: *(curDB2+1) = *(curKey+1);
+ case 1: *(curDB2) = *(curKey);
+ }
+ curDB2 += len;
+ }
+ else
+ {
+ *(curDB2++) = 0xEF;
+ *(curDB2++) = 0xBF;
+ *(curDB2++) = 0xBF;
+ }
+ curKey += len;
+ }
+ convertedBytes = curDB2 - db2Data;
+ }
+ else
+ {
+ memcpy(db2Data, keyData, inLen);
+ convertedBytes = inLen;
+ }
+ rc = 0;
+ }
+ else if (db2Field.getCCSID() == 13488)
+ {
+ DBUG_ASSERT(inLen <= outLen);
+ if (strcmp(field->charset()->name, "ucs2_bin") &&
+ strcmp(field->charset()->name, "ucs2_general_ci"))
+ {
+ const char* end = keyData+inLen;
+ const uint16* curKey = (uint16*)keyData;
+ uint16* curDB2 = (uint16*)db2Data;
+ uint16 min = field->charset()->min_sort_char;
+ while (curKey < (uint16*)end)
+ {
+ if (*curKey != min)
+ *curDB2 = *curKey;
+ else
+ *curDB2 = 0xFFFF;
+ ++curKey;
+ ++curDB2;
+ }
+ }
+ else
+ {
+ memcpy(db2Data, keyData, inLen);
+ }
+ convertedBytes = inLen;
+ rc = 0;
+ }
+ else
+ {
+ rc = convertFieldChars(toDB2,
+ field->field_index,
+ keyData,
+ db2Data,
+ inLen,
+ outLen,
+ &convertedBytes,
+ true);
+
+ if (rc == DB2I_ERR_ILL_CHAR)
+ {
+ // If an illegal character is encountered, we fill the remainder
+ // of the key with 0x00. This was implemented as a corollary to
+ // Bug#45012, though it should probably remain even after that
+ // bug is fixed.
+ memset(db2Data+convertedBytes, 0x00, outLen-convertedBytes);
+ convertedBytes = outLen;
+ rc = 0;
+ }
+ }
+
+ if (!rc &&
+ (litDefPtr->DataType == QMY_VARGRAPHIC ||
+ litDefPtr->DataType == QMY_VARCHAR))
+ {
+ *(uint16*)(db2Data-sizeof(uint16)) =
+ convertedBytes / (litDefPtr->DataType == QMY_VARGRAPHIC ? 2 : 1);
+ }
+
+ }
+ else // Non-character fields
+ {
+ rc = convertMySQLtoDB2(field,
+ db2Field,
+ literalPtr,
+ (uchar*)minPtr+((curKey.key_part[partsInUse].null_bit)? 1 : 0));
+ }
+
if (rc != 0) break;
litDefPtr->Offset = (uint32_t)(literalPtr - literalsPtr);
litDefPtr->Length = db2Field.getByteLengthInRecord();
- tempLen = litDefPtr->Length;
- /*
- Do additional conversion of a character or graphic value.
- */
- CHARSET_INFO* fieldCharSet = field->charset();
- if ((field->type() != MYSQL_TYPE_BIT) && // Don't do conversion on BIT data
- (field->charset() != &my_charset_bin) && // Don't do conversion on BINARY data
- (litDefPtr->DataType == QMY_CHAR || litDefPtr->DataType == QMY_VARCHAR ||
- litDefPtr->DataType == QMY_GRAPHIC || litDefPtr->DataType == QMY_VARGRAPHIC))
- {
- if (litDefPtr->DataType == QMY_VARCHAR ||
- litDefPtr->DataType == QMY_VARGRAPHIC)
- tempPtr = literalPtr + sizeof(uint16);
- else
- tempPtr = literalPtr;
- /* The following code checks to determine if MySQL is passing a
- partial key. DB2 will accept a partial field value, but only
- in the last field position of the key composite (and only if
- there is no ICU sort sequence on the index). */
- tempMinPtr = (char*)minPtr+((curKey.key_part[partsInUse].null_bit)? 1 : 0);
- if (field->type() == MYSQL_TYPE_VARCHAR)
- {
- /* MySQL always stores key lengths as 2 bytes, little-endian. */
- tempLen = *(uint8*)tempMinPtr + ((*(uint8*)(tempMinPtr+1)) << 8);
- tempMinPtr = (char*)((char*)tempMinPtr + 2);
- }
- else
- tempLen = field->field_length;
-
- /* Determine if we are dealing with a partial key and if so, find the end of the partial key. */
- if (litDefPtr->DataType == QMY_CHAR || litDefPtr->DataType == QMY_VARCHAR )
- { /* Char or varchar. If UTF8, no conversion is done to DB2 graphic.) */
- endOfMinPtr = (char*)memchr(tempMinPtr,field->charset()->min_sort_char,tempLen);
- if (endOfMinPtr)
- endOfLiteralPtr = tempPtr + ((uint32_t)(endOfMinPtr - tempMinPtr));
- }
- else
- {
- if (strncmp(fieldCharSet->csname, "utf8", sizeof("utf8")) == 0)
- { /* The MySQL charset is UTF8 but we are converting to graphic on DB2. Divide number of UTF8 bytes
- by 3 to get the number of characters, then multiple by 2 for double-byte graphic.*/
- endOfMinPtr = (char*)memchr(tempMinPtr,field->charset()->min_sort_char,tempLen);
- if (endOfMinPtr)
- endOfLiteralPtr = tempPtr + (((uint32_t)((endOfMinPtr - tempMinPtr)) / 3) * 2);
- }
- else
- { /* The DB2 data type is graphic or vargraphic, and we are not converting from UTF8 to graphic. */
- endOfMinPtr = (char*)wmemchr((wchar_t*)tempMinPtr,field->charset()->min_sort_char,tempLen/2);
- if (endOfMinPtr)
- endOfLiteralPtr = tempPtr + (endOfMinPtr - tempMinPtr);
- }
- }
- /* Enforce here that a partial is only allowed on the last field position
- of the key composite */
- if (endOfLiteralPtr)
- {
- if ((partsInUse + 1) < minKeyCnt)
- {
- rc = HA_POS_ERROR;
- break;
- }
- endByte = endOfLiteralPtr - tempPtr;
- /* We're making an assumption that if MySQL gives us a partial key,
- the length of the partial is the same for both the min_key and max_key. */
- }
- }
literalPtr = literalPtr + litDefPtr->Length; // Bump pointer for next literal
}
/* If there is a max_key value for this field, and if the max_key value is
@@ -389,28 +470,168 @@ ha_rows ha_ibmdb2i::records_in_range(uint inx,
/*
Convert the literal to DB2 format
*/
- rc = convertMySQLtoDB2(field,
- db2Field,
- literalPtr,
- (uchar*)maxPtr+((curKey.key_part[partsInUse].null_bit)? 1 : 0));
+ if ((field->type() != MYSQL_TYPE_BIT) && // Don't do conversion on BIT data
+ (field->charset() != &my_charset_bin) && // Don't do conversion on BINARY data
+ (litDefPtr->DataType == QMY_CHAR ||
+ litDefPtr->DataType == QMY_VARCHAR ||
+ litDefPtr->DataType == QMY_GRAPHIC ||
+ litDefPtr->DataType == QMY_VARGRAPHIC))
+ {
+ // We need to handle char fields in a special way in order to account
+ // for partial keys. Refer to the note above for a description of the
+ // basic design.
+ char* keyData = maxPtr+((curKey.key_part[partsInUse].null_bit)? 1 : 0);
+ char* db2Data = literalPtr;
+ uint16 outLen = db2Field.getByteLengthInRecord();
+ uint16 inLen;
+ if (litDefPtr->DataType == QMY_VARCHAR ||
+ litDefPtr->DataType == QMY_VARGRAPHIC)
+ {
+ inLen = *(uint8*)keyData + ((*(uint8*)(keyData+1)) << 8);
+ keyData += 2;
+ outLen -= sizeof(uint16);
+ db2Data += sizeof(uint16);
+ }
+ else
+ {
+ inLen = field->max_display_length();
+ }
+
+ size_t convertedBytes;
+ if (db2Field.getCCSID() == 1208)
+ {
+ if (strcmp(field->charset()->name, "utf8_bin"))
+ {
+ const char* end = keyData+inLen;
+ const char* curKey = keyData;
+ char* curDB2 = db2Data;
+ uint32 max = field->charset()->max_sort_char;
+ while (curKey < end && (curDB2 < db2Data+outLen-3))
+ {
+ my_wc_t temp;
+ int len = field->charset()->cset->mb_wc(field->charset(), &temp, (const uchar*)curKey, (const uchar*)end);
+ if (temp != max)
+ {
+ DBUG_ASSERT(len <= 3);
+ switch (len)
+ {
+ case 3: *(curDB2+2) = *(curKey+2);
+ case 2: *(curDB2+1) = *(curKey+1);
+ case 1: *(curDB2) = *(curKey);
+ }
+ curDB2 += len;
+ }
+ else
+ {
+ *(curDB2++) = 0xE4;
+ *(curDB2++) = 0xB6;
+ *(curDB2++) = 0xBF;
+ }
+ curKey += len;
+ }
+ convertedBytes = curDB2 - db2Data;
+ }
+ else
+ {
+ DBUG_ASSERT(inLen <= outLen);
+ memcpy(db2Data, keyData, inLen);
+ convertedBytes = inLen;
+ }
+ rc = 0;
+ }
+ else if (db2Field.getCCSID() == 13488)
+ {
+ if (strcmp(field->charset()->name, "ucs2_bin") &&
+ strcmp(field->charset()->name, "ucs2_general_ci"))
+ {
+ char* end = keyData+inLen;
+ uint16* curKey = (uint16*)keyData;
+ uint16* curDB2 = (uint16*)db2Data;
+ uint16 max = field->charset()->max_sort_char;
+ while (curKey < (uint16*)end)
+ {
+ if (*curKey != max)
+ *curDB2 = *curKey;
+ else
+ *curDB2 = 0x4DBF;
+ ++curKey;
+ ++curDB2;
+ }
+ }
+ else
+ {
+ memcpy(db2Data, keyData, outLen);
+ }
+ rc = 0;
+ }
+ else
+ {
+ size_t substituteChars = 0;
+ rc = convertFieldChars(toDB2,
+ field->field_index,
+ keyData,
+ db2Data,
+ inLen,
+ outLen,
+ &convertedBytes,
+ true,
+ &substituteChars);
+
+ if (rc == DB2I_ERR_ILL_CHAR)
+ {
+ // If an illegal character is encountered, we fill the remainder
+ // of the key with 0xFF. This was implemented to work around
+ // Bug#45012, though it should probably remain even after that
+ // bug is fixed.
+ memset(db2Data+convertedBytes, 0xFF, outLen-convertedBytes);
+ rc = 0;
+ }
+ else if ((substituteChars &&
+ (litDefPtr->DataType == QMY_VARCHAR ||
+ litDefPtr->DataType == QMY_CHAR)) ||
+ strcmp(field->charset()->name, "cp1251_bulgarian_ci") == 0)
+ {
+ // When iconv translates the max_sort_char with a substitute
+ // character, we have no way to know whether this affects
+ // the sort order of the key. Therefore, to be safe, when
+ // we know that substitute characters have been used in a
+ // single-byte string, we traverse the translated key
+ // in reverse, replacing substitue characters with 0xFF, which
+ // always sorts with the greatest weight in DB2 sort sequences.
+ // cp1251_bulgarian_ci is also handled this way because the
+ // max_sort_char is a control character which does not sort
+ // equivalently in DB2.
+ DBUG_ASSERT(inLen == outLen);
+ char* tmpKey = keyData + inLen - 1;
+ char* tmpDB2 = db2Data + outLen - 1;
+ while (*tmpKey == field->charset()->max_sort_char &&
+ *tmpDB2 != 0xFF)
+ {
+ *tmpDB2 = 0xFF;
+ --tmpKey;
+ --tmpDB2;
+ }
+ }
+ }
+
+ if (!rc &&
+ (litDefPtr->DataType == QMY_VARGRAPHIC ||
+ litDefPtr->DataType == QMY_VARCHAR))
+ {
+ *(uint16*)(db2Data-sizeof(uint16)) =
+ outLen / (litDefPtr->DataType == QMY_VARGRAPHIC ? 2 : 1);
+ }
+ }
+ else
+ {
+ rc = convertMySQLtoDB2(field,
+ db2Field,
+ literalPtr,
+ (uchar*)maxPtr+((curKey.key_part[partsInUse].null_bit)? 1 : 0));
+ }
if (rc != 0) break;
litDefPtr->Offset = (uint32_t)(literalPtr - literalsPtr);
litDefPtr->Length = db2Field.getByteLengthInRecord();
- tempLen = litDefPtr->Length;
- /*
- Now convert a character or graphic value.
- */
- if ((field->type() != MYSQL_TYPE_BIT) &&
- (litDefPtr->DataType == QMY_CHAR || litDefPtr->DataType == QMY_VARCHAR ||
- litDefPtr->DataType == QMY_GRAPHIC || litDefPtr->DataType == QMY_VARGRAPHIC))
- {
- if (litDefPtr->DataType == QMY_VARCHAR || litDefPtr->DataType == QMY_VARGRAPHIC)
- {
- tempPtr = literalPtr + sizeof(uint16);
- }
- else
- tempPtr = literalPtr;
- }
literalPtr = literalPtr + litDefPtr->Length; // Bump pointer for next literal
}
boundsPtr->HiBound.Position = literalCnt;
diff --git a/storage/ibmdb2i/ha_ibmdb2i.cc b/storage/ibmdb2i/ha_ibmdb2i.cc
index 46c84de4aee..0fc2d1e83dc 100644
--- a/storage/ibmdb2i/ha_ibmdb2i.cc
+++ b/storage/ibmdb2i/ha_ibmdb2i.cc
@@ -2230,34 +2230,19 @@ int ha_ibmdb2i::create(const char *name, TABLE *table_arg,
}
}
- bool primaryHasStringField = false;
-
+ String fieldDefinition(128);
+
if (table_arg->s->primary_key != MAX_KEY && !isTemporary)
{
- KEY& curKey = table_arg->key_info[table_arg->s->primary_key];
- query.append(STRING_WITH_LEN(", PRIMARY KEY( "));
- for (int j = 0; j < curKey.key_parts; ++j)
- {
- if (j != 0)
- {
- query.append( STRING_WITH_LEN(" , ") );
- }
- Field* field = curKey.key_part[j].field;
- convertMySQLNameToDB2Name(field->field_name, colName, sizeof(colName));
- query.append(colName);
- enum_field_types type = field->real_type();
- if (type == MYSQL_TYPE_VARCHAR || type == MYSQL_TYPE_BLOB ||
- type == MYSQL_TYPE_STRING)
- {
- rc = updateAssociatedSortSequence(field->charset(),
- &fileSortSequenceType,
- fileSortSequence,
- fileSortSequenceLibrary);
- if (rc) DBUG_RETURN (rc);
- primaryHasStringField = true;
- }
- }
- query.append(STRING_WITH_LEN(" ) "));
+ query.append(STRING_WITH_LEN(", PRIMARY KEY "));
+ rc = buildIndexFieldList(fieldDefinition,
+ table_arg->key_info[table_arg->s->primary_key],
+ true,
+ &fileSortSequenceType,
+ fileSortSequence,
+ fileSortSequenceLibrary);
+ if (rc) DBUG_RETURN(rc);
+ query.append(fieldDefinition);
}
rc = buildDB2ConstraintString(thd->lex,
@@ -2273,11 +2258,29 @@ int ha_ibmdb2i::create(const char *name, TABLE *table_arg,
if (isTemporary)
query.append(STRING_WITH_LEN(" ON COMMIT PRESERVE ROWS "));
-
+
+ if (create_info->alias)
+ generateAndAppendRCDFMT(create_info->alias, query);
+ else if (((TABLE_LIST*)(thd->lex->select_lex.table_list.first))->table_name)
+ generateAndAppendRCDFMT((char*)((TABLE_LIST*)(thd->lex->select_lex.table_list.first))->table_name, query);
+
DBUG_PRINT("ha_ibmdb2i::create", ("Sent to DB2: %s",query.c_ptr()));
SqlStatementStream sqlStream(query.length());
sqlStream.addStatement(query,fileSortSequence,fileSortSequenceLibrary);
+ if (table_arg->s->primary_key != MAX_KEY &&
+ !isTemporary &&
+ (THDVAR(thd, create_index_option)==1) &&
+ (fileSortSequenceType != 'B') &&
+ (fileSortSequenceType != ' '))
+ {
+ rc = generateShadowIndex(sqlStream,
+ table_arg->key_info[table_arg->s->primary_key],
+ libName,
+ fileName,
+ fieldDefinition);
+ if (rc) DBUG_RETURN(rc);
+ }
for (uint i = 0; i < table_arg->s->keys; ++i)
{
if (i != table_arg->s->primary_key || isTemporary)
@@ -3007,52 +3010,27 @@ int32 ha_ibmdb2i::buildCreateIndexStatement(SqlStatementStream& sqlStream,
}
String fieldDefinition(128);
- fieldDefinition.length(0);
- fieldDefinition.append(STRING_WITH_LEN(" ( "));
- for (int j = 0; j < key.key_parts; ++j)
- {
- char colName[MAX_DB2_COLNAME_LENGTH+1];
- if (j != 0)
- {
- fieldDefinition.append(STRING_WITH_LEN(" , "));
- }
- Field* field = key.key_part[j].field;
- convertMySQLNameToDB2Name(field->field_name, colName, sizeof(colName));
- fieldDefinition.append(colName);
- rc = updateAssociatedSortSequence(field->charset(),
- &fileSortSequenceType,
- fileSortSequence,
- fileSortSequenceLibrary);
- if (rc) DBUG_RETURN (rc);
- }
- fieldDefinition.append(STRING_WITH_LEN(" ) "));
+ rc = buildIndexFieldList(fieldDefinition,
+ key,
+ isPrimary,
+ &fileSortSequenceType,
+ fileSortSequence,
+ fileSortSequenceLibrary);
+ if (rc) DBUG_RETURN(rc);
+
query.append(fieldDefinition);
if ((THDVAR(ha_thd(), create_index_option)==1) &&
- (fileSortSequenceType != 'B'))
+ (fileSortSequenceType != 'B') &&
+ (fileSortSequenceType != ' '))
{
- String shadowQuery(256);
- shadowQuery.length(0);
-
- shadowQuery.append(STRING_WITH_LEN("CREATE INDEX "));
-
- shadowQuery.append(db2LibName);
- shadowQuery.append('.');
- if (db2i_table::appendQualifiedIndexFileName(key.name, db2FileName, shadowQuery, db2i_table::ASCII_SQL, typeHex))
- {
- getErrTxt(DB2I_ERR_INVALID_NAME,"index","*generated*");
- DBUG_RETURN(DB2I_ERR_INVALID_NAME );
- }
-
- shadowQuery.append(STRING_WITH_LEN(" ON "));
-
- shadowQuery.append(db2LibName);
- shadowQuery.append('.');
- shadowQuery.append(db2FileName);
- shadowQuery.append(fieldDefinition);
- DBUG_PRINT("ha_ibmdb2i::buildCreateIndexStatement", ("Sent to DB2: %s",shadowQuery.c_ptr_safe()));
- sqlStream.addStatement(shadowQuery,"*HEX","QSYS");
+ rc = generateShadowIndex(sqlStream,
+ key,
+ db2LibName,
+ db2FileName,
+ fieldDefinition);
+ if (rc) DBUG_RETURN(rc);
}
DBUG_PRINT("ha_ibmdb2i::buildCreateIndexStatement", ("Sent to DB2: %s",query.c_ptr_safe()));
@@ -3061,7 +3039,97 @@ int32 ha_ibmdb2i::buildCreateIndexStatement(SqlStatementStream& sqlStream,
DBUG_RETURN(0);
}
+/**
+ Generate the SQL syntax for the list of fields to be assigned to the
+ specified key. The corresponding sort sequence is also calculated.
+
+ @param[out] appendHere The string to receive the generated SQL
+ @param key The key to evaluate
+ @param isPrimary True if this is being generated on behalf of the primary key
+ @param[out] fileSortSequenceType The type of the associated sort sequence
+ @param[out] fileSortSequence The name of the associated sort sequence
+ @param[out] fileSortSequenceLibrary The library of the associated sort sequence
+
+ @return 0 if successful; error value otherwise
+*/
+int32 ha_ibmdb2i::buildIndexFieldList(String& appendHere,
+ const KEY& key,
+ bool isPrimary,
+ char* fileSortSequenceType,
+ char* fileSortSequence,
+ char* fileSortSequenceLibrary)
+{
+ DBUG_ENTER("ha_ibmdb2i::buildIndexFieldList");
+ appendHere.append(STRING_WITH_LEN(" ( "));
+ for (int j = 0; j < key.key_parts; ++j)
+ {
+ char colName[MAX_DB2_COLNAME_LENGTH+1];
+ if (j != 0)
+ {
+ appendHere.append(STRING_WITH_LEN(" , "));
+ }
+
+ KEY_PART_INFO& kpi = key.key_part[j];
+ Field* field = kpi.field;
+
+ convertMySQLNameToDB2Name(field->field_name,
+ colName,
+ sizeof(colName));
+ appendHere.append(colName);
+
+ int32 rc;
+ rc = updateAssociatedSortSequence(field->charset(),
+ fileSortSequenceType,
+ fileSortSequence,
+ fileSortSequenceLibrary);
+ if (rc) DBUG_RETURN (rc);
+ }
+
+ appendHere.append(STRING_WITH_LEN(" ) "));
+
+ DBUG_RETURN(0);
+}
+
+/**
+ Generate an SQL statement that defines a *HEX sorted index to implement
+ the ibmdb2i_create_index.
+
+ @param[out] stream The stream to append the generated statement to
+ @param key The key to evaluate
+ @param[out] libName The library containg the table
+ @param[out] fileName The DB2-compatible name of the table
+ @param[out] fieldDefinition The list of the fields in the index, in SQL syntax
+
+ @return 0 if successful; error value otherwise
+*/
+int32 ha_ibmdb2i::generateShadowIndex(SqlStatementStream& stream,
+ const KEY& key,
+ const char* libName,
+ const char* fileName,
+ const String& fieldDefinition)
+{
+ String shadowQuery(256);
+ shadowQuery.length(0);
+ shadowQuery.append(STRING_WITH_LEN("CREATE INDEX "));
+ shadowQuery.append(libName);
+ shadowQuery.append('.');
+ if (db2i_table::appendQualifiedIndexFileName(key.name, fileName, shadowQuery, db2i_table::ASCII_SQL, typeHex))
+ {
+ getErrTxt(DB2I_ERR_INVALID_NAME,"index","*generated*");
+ return DB2I_ERR_INVALID_NAME;
+ }
+ shadowQuery.append(STRING_WITH_LEN(" ON "));
+ shadowQuery.append(libName);
+ shadowQuery.append('.');
+ shadowQuery.append(fileName);
+ shadowQuery.append(fieldDefinition);
+ DBUG_PRINT("ha_ibmdb2i::generateShadowIndex", ("Sent to DB2: %s",shadowQuery.c_ptr_safe()));
+ stream.addStatement(shadowQuery,"*HEX","QSYS");
+ return 0;
+}
+
+
void ha_ibmdb2i::doInitialRead(char orientation,
uint32 rowsToBuffer,
ILEMemHandle key,
diff --git a/storage/ibmdb2i/ha_ibmdb2i.h b/storage/ibmdb2i/ha_ibmdb2i.h
index e90f152919c..b2a43232f2d 100644
--- a/storage/ibmdb2i/ha_ibmdb2i.h
+++ b/storage/ibmdb2i/ha_ibmdb2i.h
@@ -383,7 +383,15 @@ private:
int32 prepareWriteBufferForLobs();
uint32 adjustLobBuffersForRead();
bool lobFieldsRequested();
- int convertFieldChars(enum_conversionDirection direction, uint16 fieldID, const char* input, char* output, size_t ilen, size_t olen, size_t* outDataLen);
+ int convertFieldChars(enum_conversionDirection direction,
+ uint16 fieldID,
+ const char* input,
+ char* output,
+ size_t ilen,
+ size_t olen,
+ size_t* outDataLen,
+ bool tacitErrors=FALSE,
+ size_t* substChars=NULL);
/**
Fast integer log2 function
@@ -522,6 +530,13 @@ private:
bool isPrimary,
const char* db2LibName,
const char* db2FileName);
+
+ int32 buildIndexFieldList(String& appendHere,
+ const KEY& key,
+ bool isPrimary,
+ char* fileSortSequenceType,
+ char* fileSortSequence,
+ char* fileSortSequenceLibrary);
// Specify NULL for data when using the data pointed to by field
int32 convertMySQLtoDB2(Field* field, const DB2Field& db2Field, char* db2Buf, const uchar* data = NULL);
@@ -746,5 +761,62 @@ private:
free_root(&conversionBufferMemroot, MYF(0));
}
}
-
+
+
+/**
+ Generate a valid RCDFMT name based on the name of the table.
+
+ The RCDFMT name is devised by munging the name of the table,
+ uppercasing all ascii alpha-numeric characters and replacing all other
+ characters with underscores until up to ten characters have been generated.
+
+ @param tableName The name of the table, as given on the MySQL
+ CREATE TABLE statement
+ @param[out] query The string to receive the generated RCDFMT name
+*/
+ static void generateAndAppendRCDFMT(const char* tableName, String& query)
+ {
+ char rcdfmt[11];
+
+ // The RCDFMT name must begin with an alpha character.
+ // We enforce this by skipping to the first alpha character in the table
+ // name. If no alpha character exists, we use 'X' for the RCDFMT name;
+
+ while (*tableName &&
+ (!my_isascii(*tableName) ||
+ !my_isalpha(system_charset_info, *tableName)))
+ {
+ tableName += my_mbcharlen(system_charset_info, *tableName);
+ }
+
+ if (unlikely(!(*tableName)))
+ {
+ rcdfmt[0]= 'X';
+ rcdfmt[1]= 0;
+ }
+ else
+ {
+ int r= 0;
+ while ((r < sizeof(rcdfmt)-1) && *tableName)
+ {
+ if (my_isascii(*tableName) &&
+ my_isalnum(system_charset_info, *tableName))
+ rcdfmt[r] = my_toupper(system_charset_info, *tableName);
+ else
+ rcdfmt[r] = '_';
+
+ ++r;
+ tableName += my_mbcharlen(system_charset_info, *tableName);
+ }
+ rcdfmt[r]= 0;
+ }
+ query.append(STRING_WITH_LEN(" RCDFMT "));
+ query.append(rcdfmt);
+ }
+
+ int32 generateShadowIndex(SqlStatementStream& stream,
+ const KEY& key,
+ const char* libName,
+ const char* fileName,
+ const String& fieldDefinition);
};
diff --git a/storage/innobase/CMakeLists.txt b/storage/innobase/CMakeLists.txt
deleted file mode 100755
index 249a600834d..00000000000
--- a/storage/innobase/CMakeLists.txt
+++ /dev/null
@@ -1,92 +0,0 @@
-# Copyright (C) 2006 MySQL AB
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; version 2 of the License.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-
-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 -D_LIB)
-
-# Bug 19424 - InnoDB: Possibly a memory overrun of the buffer being freed (64-bit Visual C)
-# Removing Win64 compiler optimizations for all innodb/mem/* files.
-IF(CMAKE_GENERATOR MATCHES "Visual Studio" AND CMAKE_SIZEOF_VOID_P MATCHES 8)
- SET_SOURCE_FILES_PROPERTIES(${CMAKE_SOURCE_DIR}/storage/innobase/mem/mem0mem.c
- ${CMAKE_SOURCE_DIR}/storage/innobase/mem/mem0pool.c
- PROPERTIES COMPILE_FLAGS -Od)
-ENDIF(CMAKE_GENERATOR MATCHES "Visual Studio" AND CMAKE_SIZEOF_VOID_P MATCHES 8)
-
-IF (WIN32)
- IF (NOT WITHOUT_ATOMICS)
-# Check if this Windows version supports atomic instructions
- IF (CMAKE_SIZEOF_VOID_P MATCHES 8)
-# Check for 64 bit atomics
- TRY_RUN(RUN_RES COMPILE_RES ${CMAKE_BINARY_DIR}
- ${CMAKE_SOURCE_DIR}/storage/innobase/win_atomics64_test.c)
- IF (COMPILE_RES AND NOT RUN_RES)
- MESSAGE("Adding support for Win64 atomics")
- ADD_DEFINITIONS(-DWIN_ATOMICS64)
- ENDIF (COMPILE_RES AND NOT RUN_RES)
- ELSE (CMAKE_SIZEOF_VOID_P MATCHES 8)
-# Check for 32 bit atomics
- TRY_RUN(RUN_RES COMPILE_RES ${CMAKE_BINARY_DIR}
- ${CMAKE_SOURCE_DIR}/storage/innobase/win_atomics32_test.c)
- IF (COMPILE_RES AND NOT RUN_RES)
- MESSAGE("Adding support for Win32 atomics")
- ADD_DEFINITIONS(-DWIN_ATOMICS32)
- ENDIF (COMPILE_RES AND NOT RUN_RES)
- ENDIF (CMAKE_SIZEOF_VOID_P MATCHES 8)
- ENDIF (NOT WITHOUT_ATOMICS)
-ENDIF (WIN32)
-INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/zlib
- ${CMAKE_SOURCE_DIR}/storage/innobase/include
- ${CMAKE_SOURCE_DIR}/storage/innobase/handler
- ${CMAKE_SOURCE_DIR}/sql
- ${CMAKE_SOURCE_DIR}/regex
- ${CMAKE_SOURCE_DIR}/extra/yassl/include)
-
-SET(INNOBASE_SOURCES btr/btr0btr.c btr/btr0cur.c btr/btr0pcur.c btr/btr0sea.c
- buf/buf0buf.c buf/buf0flu.c buf/buf0lru.c buf/buf0rea.c
- data/data0data.c data/data0type.c
- dict/dict0boot.c dict/dict0crea.c dict/dict0dict.c dict/dict0load.c dict/dict0mem.c
- dyn/dyn0dyn.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
- pars/lexyy.c pars/pars0grm.c pars/pars0opt.c pars/pars0pars.c pars/pars0sym.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 os/os0sync.c os/os0thread.c
- page/page0cur.c page/page0page.c
- que/que0que.c
- handler/ha_innodb.cc
- read/read0read.c
- rem/rem0cmp.c rem/rem0rec.c
- row/row0ins.c row/row0mysql.c row/row0purge.c row/row0row.c row/row0sel.c row/row0uins.c
- row/row0umod.c row/row0undo.c row/row0upd.c row/row0vers.c
- srv/srv0que.c srv/srv0srv.c srv/srv0start.c
- sync/sync0arr.c sync/sync0rw.c sync/sync0sync.c
- thr/thr0loc.c
- trx/trx0purge.c trx/trx0rec.c trx/trx0roll.c trx/trx0rseg.c trx/trx0sys.c trx/trx0trx.c trx/trx0undo.c
- usr/usr0sess.c
- ut/ut0byte.c ut/ut0dbg.c ut/ut0mem.c ut/ut0rnd.c ut/ut0ut.c ut/ut0vec.c ut/ut0list.c ut/ut0wqueue.c)
-
-IF(NOT SOURCE_SUBLIBS)
- ADD_LIBRARY(innobase ${INNOBASE_SOURCES})
- ADD_DEPENDENCIES(innobase GenError)
-ENDIF(NOT SOURCE_SUBLIBS)
diff --git a/storage/innobase/Makefile.am b/storage/innobase/Makefile.am
deleted file mode 100644
index 180d2ca0b87..00000000000
--- a/storage/innobase/Makefile.am
+++ /dev/null
@@ -1,175 +0,0 @@
-# Copyright (C) 2001, 2004, 2006 MySQL AB & Innobase Oy
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; version 2 of the License.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-
-# Process this file with automake to create Makefile.in
-
-MYSQLDATAdir= $(localstatedir)
-MYSQLSHAREdir= $(pkgdatadir)
-MYSQLBASEdir= $(prefix)
-MYSQLLIBdir= $(pkglibdir)
-pkgplugindir= $(pkglibdir)/plugin
-INCLUDES= -I$(top_srcdir)/include -I$(top_builddir)/include \
- -I$(top_srcdir)/regex \
- -I$(top_srcdir)/storage/innobase/include \
- -I$(top_srcdir)/sql \
- -I$(srcdir)
-
-DEFS= @DEFS@
-
-
-noinst_HEADERS= include/btr0btr.h include/btr0btr.ic \
- include/btr0cur.h include/btr0cur.ic \
- include/btr0pcur.h include/btr0pcur.ic \
- include/btr0sea.h include/btr0sea.ic \
- include/btr0types.h include/buf0buf.h \
- include/buf0buf.ic include/buf0flu.h \
- include/buf0flu.ic include/buf0lru.h \
- include/buf0lru.ic include/buf0rea.h \
- include/buf0types.h include/data0data.h \
- include/data0data.ic include/data0type.h \
- include/data0type.ic include/data0types.h \
- include/db0err.h include/dict0boot.h \
- include/dict0boot.ic include/dict0crea.h \
- include/dict0crea.ic include/dict0dict.h \
- include/dict0dict.ic include/dict0load.h \
- include/dict0load.ic include/dict0mem.h \
- include/dict0mem.ic include/dict0types.h \
- include/dyn0dyn.h include/dyn0dyn.ic \
- include/eval0eval.h include/eval0eval.ic \
- include/eval0proc.h include/eval0proc.ic \
- include/fil0fil.h include/fsp0fsp.h \
- include/fsp0fsp.ic include/fut0fut.h \
- include/fut0fut.ic include/fut0lst.h \
- include/fut0lst.ic include/ha0ha.h \
- 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 \
- include/mach0data.ic include/mem0dbg.h \
- include/mem0dbg.ic mem/mem0dbg.c \
- include/mem0mem.h include/mem0mem.ic \
- include/mem0pool.h include/mem0pool.ic \
- include/mtr0log.h include/mtr0log.ic \
- include/mtr0mtr.h include/mtr0mtr.ic \
- include/mtr0types.h include/os0file.h \
- include/os0proc.h include/os0proc.ic \
- include/os0sync.h include/os0sync.ic \
- include/os0thread.h include/os0thread.ic \
- include/page0cur.h include/page0cur.ic \
- include/page0page.h include/page0page.ic \
- include/page0types.h include/pars0grm.h \
- include/pars0opt.h include/pars0opt.ic \
- include/pars0pars.h include/pars0pars.ic \
- include/pars0sym.h include/pars0sym.ic \
- include/pars0types.h include/que0que.h \
- include/que0que.ic include/que0types.h \
- include/read0read.h include/read0read.ic \
- include/read0types.h include/rem0cmp.h \
- include/rem0cmp.ic include/rem0rec.h \
- include/rem0rec.ic include/rem0types.h \
- include/row0ins.h include/row0ins.ic \
- include/row0mysql.h include/row0mysql.ic \
- include/row0purge.h include/row0purge.ic \
- include/row0row.h include/row0row.ic \
- include/row0sel.h include/row0sel.ic \
- include/row0types.h include/row0uins.h \
- include/row0uins.ic include/row0umod.h \
- include/row0umod.ic include/row0undo.h \
- include/row0undo.ic include/row0upd.h \
- include/row0upd.ic include/row0vers.h \
- include/row0vers.ic include/srv0que.h \
- include/srv0srv.h include/srv0srv.ic \
- include/srv0start.h include/sync0arr.h \
- include/sync0arr.ic include/sync0rw.h \
- include/sync0rw.ic include/sync0sync.h \
- include/sync0sync.ic include/sync0types.h \
- include/thr0loc.h include/thr0loc.ic \
- include/trx0purge.h include/trx0purge.ic \
- include/trx0rec.h include/trx0rec.ic \
- include/trx0roll.h include/trx0roll.ic \
- include/trx0rseg.h include/trx0rseg.ic \
- include/trx0sys.h include/trx0sys.ic \
- include/trx0trx.h include/trx0trx.ic \
- include/trx0types.h include/trx0undo.h \
- include/trx0undo.ic include/trx0xa.h \
- include/univ.i include/usr0sess.h \
- include/usr0sess.ic include/usr0types.h \
- include/ut0byte.h include/ut0byte.ic \
- include/ut0dbg.h include/ut0lst.h \
- include/ut0mem.h include/ut0mem.ic \
- include/ut0rnd.h include/ut0rnd.ic \
- include/ut0sort.h include/ut0ut.h \
- include/ut0ut.ic include/ut0vec.h \
- include/ut0vec.ic include/ut0list.h \
- include/ut0list.ic include/ut0wqueue.h \
- include/ha_prototypes.h handler/ha_innodb.h
-
-EXTRA_LIBRARIES= libinnobase.a
-noinst_LIBRARIES= @plugin_innobase_static_target@
-libinnobase_a_SOURCES= btr/btr0btr.c btr/btr0cur.c btr/btr0pcur.c \
- btr/btr0sea.c buf/buf0buf.c buf/buf0flu.c \
- buf/buf0lru.c buf/buf0rea.c data/data0data.c \
- data/data0type.c dict/dict0boot.c \
- dict/dict0crea.c dict/dict0dict.c \
- dict/dict0load.c dict/dict0mem.c dyn/dyn0dyn.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/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 \
- os/os0sync.c os/os0thread.c page/page0cur.c \
- page/page0page.c pars/lexyy.c pars/pars0grm.c \
- pars/pars0opt.c pars/pars0pars.c \
- pars/pars0sym.c que/que0que.c read/read0read.c \
- rem/rem0cmp.c rem/rem0rec.c row/row0ins.c \
- row/row0mysql.c row/row0purge.c row/row0row.c \
- row/row0sel.c row/row0uins.c row/row0umod.c \
- row/row0undo.c row/row0upd.c row/row0vers.c \
- srv/srv0que.c srv/srv0srv.c srv/srv0start.c \
- sync/sync0arr.c sync/sync0rw.c \
- sync/sync0sync.c thr/thr0loc.c trx/trx0purge.c \
- trx/trx0rec.c trx/trx0roll.c trx/trx0rseg.c \
- trx/trx0sys.c trx/trx0trx.c trx/trx0undo.c \
- usr/usr0sess.c ut/ut0byte.c ut/ut0dbg.c \
- ut/ut0list.c ut/ut0mem.c ut/ut0rnd.c \
- ut/ut0ut.c ut/ut0vec.c ut/ut0wqueue.c \
- handler/ha_innodb.cc
-
-libinnobase_a_CXXFLAGS= $(AM_CFLAGS)
-libinnobase_a_CFLAGS= $(AM_CFLAGS)
-
-EXTRA_LTLIBRARIES= ha_innodb.la
-pkgplugin_LTLIBRARIES= @plugin_innobase_shared_target@
-
-ha_innodb_la_LDFLAGS= -module -rpath $(pkgplugindir)
-ha_innodb_la_CXXFLAGS= $(AM_CFLAGS) $(INNODB_DYNAMIC_CFLAGS)
-ha_innodb_la_CFLAGS= $(AM_CFLAGS) $(INNODB_DYNAMIC_CFLAGS)
-ha_innodb_la_SOURCES= $(libinnobase_a_SOURCES)
-
-EXTRA_DIST= CMakeLists.txt plug.in \
- pars/make_bison.sh pars/make_flex.sh \
- pars/pars0grm.y pars/pars0lex.l \
- win_atomics32_test.c win_atomics64_test.c
-
-# Don't update the files from bitkeeper
-%::SCCS/s.%
diff --git a/storage/innobase/btr/btr0btr.c b/storage/innobase/btr/btr0btr.c
deleted file mode 100644
index 6e8b43aeb8d..00000000000
--- a/storage/innobase/btr/btr0btr.c
+++ /dev/null
@@ -1,3077 +0,0 @@
-/******************************************************
-The B-tree
-
-(c) 1994-1996 Innobase Oy
-
-Created 6/2/1994 Heikki Tuuri
-*******************************************************/
-
-#include "btr0btr.h"
-
-#ifdef UNIV_NONINL
-#include "btr0btr.ic"
-#endif
-
-#include "fsp0fsp.h"
-#include "page0page.h"
-#include "btr0cur.h"
-#include "btr0sea.h"
-#include "btr0pcur.h"
-#include "rem0cmp.h"
-#include "lock0lock.h"
-#include "ibuf0ibuf.h"
-#include "trx0trx.h"
-
-/*
-Latching strategy of the InnoDB B-tree
---------------------------------------
-A tree latch protects all non-leaf nodes of the tree. Each node of a tree
-also has a latch of its own.
-
-A B-tree operation normally first acquires an S-latch on the tree. It
-searches down the tree and releases the tree latch when it has the
-leaf node latch. To save CPU time we do not acquire any latch on
-non-leaf nodes of the tree during a search, those pages are only bufferfixed.
-
-If an operation needs to restructure the tree, it acquires an X-latch on
-the tree before searching to a leaf node. If it needs, for example, to
-split a leaf,
-(1) InnoDB decides the split point in the leaf,
-(2) allocates a new page,
-(3) inserts the appropriate node pointer to the first non-leaf level,
-(4) releases the tree X-latch,
-(5) and then moves records from the leaf to the new allocated page.
-
-Node pointers
--------------
-Leaf pages of a B-tree contain the index records stored in the
-tree. On levels n > 0 we store 'node pointers' to pages on level
-n - 1. For each page there is exactly one node pointer stored:
-thus the our tree is an ordinary B-tree, not a B-link tree.
-
-A node pointer contains a prefix P of an index record. The prefix
-is long enough so that it determines an index record uniquely.
-The file page number of the child page is added as the last
-field. To the child page we can store node pointers or index records
-which are >= P in the alphabetical order, but < P1 if there is
-a next node pointer on the level, and P1 is its prefix.
-
-If a node pointer with a prefix P points to a non-leaf child,
-then the leftmost record in the child must have the same
-prefix P. If it points to a leaf node, the child is not required
-to contain any record with a prefix equal to P. The leaf case
-is decided this way to allow arbitrary deletions in a leaf node
-without touching upper levels of the tree.
-
-We have predefined a special minimum record which we
-define as the smallest record in any alphabetical order.
-A minimum record is denoted by setting a bit in the record
-header. A minimum record acts as the prefix of a node pointer
-which points to a leftmost node on any level of the tree.
-
-File page allocation
---------------------
-In the root node of a B-tree there are two file segment headers.
-The leaf pages of a tree are allocated from one file segment, to
-make them consecutive on disk if possible. From the other file segment
-we allocate pages for the non-leaf levels of the tree.
-*/
-
-/****************************************************************
-Returns the upper level node pointer to a page. It is assumed that
-mtr holds an x-latch on the tree. */
-static
-rec_t*
-btr_page_get_father_node_ptr(
-/*=========================*/
- /* out: pointer to node pointer record */
- dict_index_t* index, /* in: index tree */
- page_t* page, /* in: page: must contain at least one
- user record */
- mtr_t* mtr); /* in: mtr */
-/*****************************************************************
-Empties an index page. */
-static
-void
-btr_page_empty(
-/*===========*/
- page_t* page, /* in: page to be emptied */
- mtr_t* mtr); /* in: mtr */
-/*****************************************************************
-Returns TRUE if the insert fits on the appropriate half-page
-with the chosen split_rec. */
-static
-ibool
-btr_page_insert_fits(
-/*=================*/
- /* out: TRUE if fits */
- btr_cur_t* cursor, /* in: cursor at which insert
- should be made */
- rec_t* split_rec, /* in: suggestion for first record
- on upper half-page, or NULL if
- tuple should be first */
- const ulint* offsets, /* in: rec_get_offsets(
- split_rec, cursor->index) */
- dtuple_t* tuple, /* in: tuple to insert */
- mem_heap_t* heap); /* in: temporary memory heap */
-
-/******************************************************************
-Gets the root node of a tree and x-latches it. */
-
-page_t*
-btr_root_get(
-/*=========*/
- /* out: root page, x-latched */
- dict_index_t* index, /* in: index tree */
- mtr_t* mtr) /* in: mtr */
-{
- ulint space;
- ulint root_page_no;
- page_t* root;
-
- space = dict_index_get_space(index);
- root_page_no = dict_index_get_page(index);
-
- root = btr_page_get(space, root_page_no, RW_X_LATCH, mtr);
- ut_a((ibool)!!page_is_comp(root) == dict_table_is_comp(index->table));
-
- return(root);
-}
-
-/*****************************************************************
-Gets pointer to the previous user record in the tree. It is assumed that
-the caller has appropriate latches on the page and its neighbor. */
-
-rec_t*
-btr_get_prev_user_rec(
-/*==================*/
- /* out: previous user record, NULL if there is none */
- rec_t* rec, /* in: record on leaf level */
- mtr_t* mtr) /* in: mtr holding a latch on the page, and if
- needed, also to the previous page */
-{
- page_t* page;
- page_t* prev_page;
- ulint prev_page_no;
- ulint space;
-
- if (!page_rec_is_infimum(rec)) {
-
- rec_t* prev_rec = page_rec_get_prev(rec);
-
- if (!page_rec_is_infimum(prev_rec)) {
-
- return(prev_rec);
- }
- }
-
- page = buf_frame_align(rec);
- prev_page_no = btr_page_get_prev(page, mtr);
- space = buf_frame_get_space_id(page);
-
- if (prev_page_no != FIL_NULL) {
-
- prev_page = buf_page_get_with_no_latch(space, prev_page_no,
- mtr);
- /* The caller must already have a latch to the brother */
- ut_ad((mtr_memo_contains(mtr, buf_block_align(prev_page),
- MTR_MEMO_PAGE_S_FIX))
- || (mtr_memo_contains(mtr, buf_block_align(prev_page),
- MTR_MEMO_PAGE_X_FIX)));
- ut_a(page_is_comp(prev_page) == page_is_comp(page));
-#ifdef UNIV_BTR_DEBUG
- ut_a(btr_page_get_next(prev_page, mtr)
- == buf_frame_get_page_no(page));
-#endif /* UNIV_BTR_DEBUG */
-
- return(page_rec_get_prev(page_get_supremum_rec(prev_page)));
- }
-
- return(NULL);
-}
-
-/*****************************************************************
-Gets pointer to the next user record in the tree. It is assumed that the
-caller has appropriate latches on the page and its neighbor. */
-
-rec_t*
-btr_get_next_user_rec(
-/*==================*/
- /* out: next user record, NULL if there is none */
- rec_t* rec, /* in: record on leaf level */
- mtr_t* mtr) /* in: mtr holding a latch on the page, and if
- needed, also to the next page */
-{
- page_t* page;
- page_t* next_page;
- ulint next_page_no;
- ulint space;
-
- if (!page_rec_is_supremum(rec)) {
-
- rec_t* next_rec = page_rec_get_next(rec);
-
- if (!page_rec_is_supremum(next_rec)) {
-
- return(next_rec);
- }
- }
-
- page = buf_frame_align(rec);
- next_page_no = btr_page_get_next(page, mtr);
- space = buf_frame_get_space_id(page);
-
- if (next_page_no != FIL_NULL) {
-
- next_page = buf_page_get_with_no_latch(space, next_page_no,
- mtr);
- /* The caller must already have a latch to the brother */
- ut_ad((mtr_memo_contains(mtr, buf_block_align(next_page),
- MTR_MEMO_PAGE_S_FIX))
- || (mtr_memo_contains(mtr, buf_block_align(next_page),
- MTR_MEMO_PAGE_X_FIX)));
-#ifdef UNIV_BTR_DEBUG
- ut_a(btr_page_get_prev(next_page, mtr)
- == buf_frame_get_page_no(page));
-#endif /* UNIV_BTR_DEBUG */
-
- ut_a(page_is_comp(next_page) == page_is_comp(page));
- return(page_rec_get_next(page_get_infimum_rec(next_page)));
- }
-
- return(NULL);
-}
-
-/******************************************************************
-Creates a new index page (not the root, and also not
-used in page reorganization). */
-static
-void
-btr_page_create(
-/*============*/
- page_t* page, /* in: page to be created */
- dict_index_t* index, /* in: index */
- mtr_t* mtr) /* in: mtr */
-{
- ut_ad(mtr_memo_contains(mtr, buf_block_align(page),
- MTR_MEMO_PAGE_X_FIX));
- page_create(page, mtr, dict_table_is_comp(index->table));
- buf_block_align(page)->check_index_page_at_flush = TRUE;
-
- btr_page_set_index_id(page, index->id, mtr);
-}
-
-/******************************************************************
-Allocates a new file page to be used in an ibuf tree. Takes the page from
-the free list of the tree, which must contain pages! */
-static
-page_t*
-btr_page_alloc_for_ibuf(
-/*====================*/
- /* out: new allocated page, x-latched */
- dict_index_t* index, /* in: index tree */
- mtr_t* mtr) /* in: mtr */
-{
- fil_addr_t node_addr;
- page_t* root;
- page_t* new_page;
-
- root = btr_root_get(index, mtr);
-
- node_addr = flst_get_first(root + PAGE_HEADER
- + PAGE_BTR_IBUF_FREE_LIST, mtr);
- ut_a(node_addr.page != FIL_NULL);
-
- new_page = buf_page_get(dict_index_get_space(index), node_addr.page,
- RW_X_LATCH, mtr);
-#ifdef UNIV_SYNC_DEBUG
- buf_page_dbg_add_level(new_page, SYNC_TREE_NODE_NEW);
-#endif /* UNIV_SYNC_DEBUG */
-
- flst_remove(root + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST,
- new_page + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST_NODE,
- mtr);
- ut_ad(flst_validate(root + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST,
- mtr));
-
- return(new_page);
-}
-
-/******************************************************************
-Allocates a new file page to be used in an index tree. NOTE: we assume
-that the caller has made the reservation for free extents! */
-
-page_t*
-btr_page_alloc(
-/*===========*/
- /* out: new allocated page, x-latched;
- NULL if out of space */
- dict_index_t* index, /* in: index */
- ulint hint_page_no, /* in: hint of a good page */
- byte file_direction, /* in: direction where a possible
- page split is made */
- ulint level, /* in: level where the page is placed
- in the tree */
- mtr_t* mtr) /* in: mtr */
-{
- fseg_header_t* seg_header;
- page_t* root;
- page_t* new_page;
- ulint new_page_no;
-
- if (index->type & DICT_IBUF) {
-
- return(btr_page_alloc_for_ibuf(index, mtr));
- }
-
- root = btr_root_get(index, mtr);
-
- if (level == 0) {
- seg_header = root + PAGE_HEADER + PAGE_BTR_SEG_LEAF;
- } else {
- seg_header = root + PAGE_HEADER + PAGE_BTR_SEG_TOP;
- }
-
- /* Parameter TRUE below states that the caller has made the
- reservation for free extents, and thus we know that a page can
- be allocated: */
-
- new_page_no = fseg_alloc_free_page_general(seg_header, hint_page_no,
- file_direction, TRUE, mtr);
- if (new_page_no == FIL_NULL) {
-
- return(NULL);
- }
-
- new_page = buf_page_get(dict_index_get_space(index), new_page_no,
- RW_X_LATCH, mtr);
-#ifdef UNIV_SYNC_DEBUG
- buf_page_dbg_add_level(new_page, SYNC_TREE_NODE_NEW);
-#endif /* UNIV_SYNC_DEBUG */
-
- return(new_page);
-}
-
-/******************************************************************
-Gets the number of pages in a B-tree. */
-
-ulint
-btr_get_size(
-/*=========*/
- /* out: number of pages */
- dict_index_t* index, /* in: index */
- ulint flag) /* in: BTR_N_LEAF_PAGES or BTR_TOTAL_SIZE */
-{
- fseg_header_t* seg_header;
- page_t* root;
- ulint n;
- ulint dummy;
- mtr_t mtr;
-
- mtr_start(&mtr);
-
- mtr_s_lock(dict_index_get_lock(index), &mtr);
-
- root = btr_root_get(index, &mtr);
-
- if (flag == BTR_N_LEAF_PAGES) {
- seg_header = root + PAGE_HEADER + PAGE_BTR_SEG_LEAF;
-
- fseg_n_reserved_pages(seg_header, &n, &mtr);
-
- } else if (flag == BTR_TOTAL_SIZE) {
- seg_header = root + PAGE_HEADER + PAGE_BTR_SEG_TOP;
-
- n = fseg_n_reserved_pages(seg_header, &dummy, &mtr);
-
- seg_header = root + PAGE_HEADER + PAGE_BTR_SEG_LEAF;
-
- n += fseg_n_reserved_pages(seg_header, &dummy, &mtr);
- } else {
- ut_error;
- }
-
- mtr_commit(&mtr);
-
- return(n);
-}
-
-/******************************************************************
-Frees a page used in an ibuf tree. Puts the page to the free list of the
-ibuf tree. */
-static
-void
-btr_page_free_for_ibuf(
-/*===================*/
- dict_index_t* index, /* in: index tree */
- page_t* page, /* in: page to be freed, x-latched */
- mtr_t* mtr) /* in: mtr */
-{
- page_t* root;
-
- ut_ad(mtr_memo_contains(mtr, buf_block_align(page),
- MTR_MEMO_PAGE_X_FIX));
- root = btr_root_get(index, mtr);
-
- flst_add_first(root + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST,
- page + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST_NODE, mtr);
-
- ut_ad(flst_validate(root + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST,
- mtr));
-}
-
-/******************************************************************
-Frees a file page used in an index tree. Can be used also to (BLOB)
-external storage pages, because the page level 0 can be given as an
-argument. */
-
-void
-btr_page_free_low(
-/*==============*/
- dict_index_t* index, /* in: index tree */
- page_t* page, /* in: page to be freed, x-latched */
- ulint level, /* in: page level */
- mtr_t* mtr) /* in: mtr */
-{
- fseg_header_t* seg_header;
- page_t* root;
- ulint space;
- ulint page_no;
-
- ut_ad(mtr_memo_contains(mtr, buf_block_align(page),
- MTR_MEMO_PAGE_X_FIX));
- /* The page gets invalid for optimistic searches: increment the frame
- modify clock */
-
- buf_frame_modify_clock_inc(page);
-
- if (index->type & DICT_IBUF) {
-
- btr_page_free_for_ibuf(index, page, mtr);
-
- return;
- }
-
- root = btr_root_get(index, mtr);
-
- if (level == 0) {
- seg_header = root + PAGE_HEADER + PAGE_BTR_SEG_LEAF;
- } else {
- seg_header = root + PAGE_HEADER + PAGE_BTR_SEG_TOP;
- }
-
- space = buf_frame_get_space_id(page);
- page_no = buf_frame_get_page_no(page);
-
- fseg_free_page(seg_header, space, page_no, mtr);
-}
-
-/******************************************************************
-Frees a file page used in an index tree. NOTE: cannot free field external
-storage pages because the page must contain info on its level. */
-
-void
-btr_page_free(
-/*==========*/
- dict_index_t* index, /* in: index tree */
- page_t* page, /* in: page to be freed, x-latched */
- mtr_t* mtr) /* in: mtr */
-{
- ulint level;
-
- ut_ad(mtr_memo_contains(mtr, buf_block_align(page),
- MTR_MEMO_PAGE_X_FIX));
- level = btr_page_get_level(page, mtr);
-
- btr_page_free_low(index, page, level, mtr);
-}
-
-/******************************************************************
-Sets the child node file address in a node pointer. */
-UNIV_INLINE
-void
-btr_node_ptr_set_child_page_no(
-/*===========================*/
- rec_t* rec, /* in: node pointer record */
- const ulint* offsets,/* in: array returned by rec_get_offsets() */
- ulint page_no,/* in: child node address */
- mtr_t* mtr) /* in: mtr */
-{
- byte* field;
- ulint len;
-
- ut_ad(rec_offs_validate(rec, NULL, offsets));
- ut_ad(0 < btr_page_get_level(buf_frame_align(rec), mtr));
- ut_ad(!rec_offs_comp(offsets) || rec_get_node_ptr_flag(rec));
-
- /* The child address is in the last field */
- field = rec_get_nth_field(rec, offsets,
- rec_offs_n_fields(offsets) - 1, &len);
-
- ut_ad(len == 4);
-
- mlog_write_ulint(field, page_no, MLOG_4BYTES, mtr);
-}
-
-/****************************************************************
-Returns the child page of a node pointer and x-latches it. */
-static
-page_t*
-btr_node_ptr_get_child(
-/*===================*/
- /* out: child page, x-latched */
- rec_t* node_ptr,/* in: node pointer */
- const ulint* offsets,/* in: array returned by rec_get_offsets() */
- mtr_t* mtr) /* in: mtr */
-{
- ulint page_no;
- ulint space;
- page_t* page;
-
- ut_ad(rec_offs_validate(node_ptr, NULL, offsets));
- space = buf_frame_get_space_id(node_ptr);
- page_no = btr_node_ptr_get_child_page_no(node_ptr, offsets);
-
- page = btr_page_get(space, page_no, RW_X_LATCH, mtr);
-
- return(page);
-}
-
-/****************************************************************
-Returns the upper level node pointer to a page. It is assumed that mtr holds
-an x-latch on the tree. */
-static
-rec_t*
-btr_page_get_father_for_rec(
-/*========================*/
- /* out: pointer to node pointer record,
- its page x-latched */
- dict_index_t* index, /* in: index tree */
- page_t* page, /* in: page: must contain at least one
- user record */
- rec_t* user_rec,/* in: user_record on page */
- mtr_t* mtr) /* in: mtr */
-{
- mem_heap_t* heap;
- dtuple_t* tuple;
- btr_cur_t cursor;
- rec_t* node_ptr;
- ulint offsets_[REC_OFFS_NORMAL_SIZE];
- ulint* offsets = offsets_;
- *offsets_ = (sizeof offsets_) / sizeof *offsets_;
-
- ut_ad(mtr_memo_contains(mtr, dict_index_get_lock(index),
- MTR_MEMO_X_LOCK));
- ut_a(page_rec_is_user_rec(user_rec));
-
- ut_ad(dict_index_get_page(index) != buf_frame_get_page_no(page));
-
- heap = mem_heap_create(100);
-
- tuple = dict_index_build_node_ptr(index, user_rec, 0, heap,
- btr_page_get_level(page, mtr));
-
- btr_cur_search_to_nth_level(index,
- btr_page_get_level(page, mtr) + 1,
- tuple, PAGE_CUR_LE,
- BTR_CONT_MODIFY_TREE, &cursor, 0, mtr);
-
- node_ptr = btr_cur_get_rec(&cursor);
- offsets = rec_get_offsets(node_ptr, index, offsets,
- ULINT_UNDEFINED, &heap);
-
- if (UNIV_UNLIKELY(btr_node_ptr_get_child_page_no(node_ptr, offsets)
- != buf_frame_get_page_no(page))) {
- rec_t* print_rec;
- fputs("InnoDB: Dump of the child page:\n", stderr);
- buf_page_print(buf_frame_align(page));
- fputs("InnoDB: Dump of the parent page:\n", stderr);
- buf_page_print(buf_frame_align(node_ptr));
-
- fputs("InnoDB: Corruption of an index tree: table ", stderr);
- ut_print_name(stderr, NULL, TRUE, index->table_name);
- fputs(", index ", stderr);
- ut_print_name(stderr, NULL, FALSE, index->name);
- fprintf(stderr, ",\n"
- "InnoDB: father ptr page no %lu, child page no %lu\n",
- (ulong)
- btr_node_ptr_get_child_page_no(node_ptr, offsets),
- (ulong) buf_frame_get_page_no(page));
- print_rec = page_rec_get_next(page_get_infimum_rec(page));
- offsets = rec_get_offsets(print_rec, index,
- offsets, ULINT_UNDEFINED, &heap);
- page_rec_print(print_rec, offsets);
- offsets = rec_get_offsets(node_ptr, index, offsets,
- ULINT_UNDEFINED, &heap);
- page_rec_print(node_ptr, offsets);
-
- fputs("InnoDB: You should dump + drop + reimport the table"
- " to fix the\n"
- "InnoDB: corruption. If the crash happens at "
- "the database startup, see\n"
- "InnoDB: http://dev.mysql.com/doc/refman/5.1/en/"
- "forcing-recovery.html about\n"
- "InnoDB: forcing recovery. "
- "Then dump + drop + reimport.\n", stderr);
- }
-
- ut_a(btr_node_ptr_get_child_page_no(node_ptr, offsets)
- == buf_frame_get_page_no(page));
- mem_heap_free(heap);
-
- return(node_ptr);
-}
-
-/****************************************************************
-Returns the upper level node pointer to a page. It is assumed that
-mtr holds an x-latch on the tree. */
-static
-rec_t*
-btr_page_get_father_node_ptr(
-/*=========================*/
- /* out: pointer to node pointer record */
- dict_index_t* index, /* in: index tree */
- page_t* page, /* in: page: must contain at least one
- user record */
- mtr_t* mtr) /* in: mtr */
-{
- return(btr_page_get_father_for_rec(
- index, page,
- page_rec_get_next(page_get_infimum_rec(page)), mtr));
-}
-
-/****************************************************************
-Creates the root node for a new index tree. */
-
-ulint
-btr_create(
-/*=======*/
- /* out: page number of the created root, FIL_NULL if
- did not succeed */
- ulint type, /* in: type of the index */
- ulint space, /* in: space where created */
- dulint index_id,/* in: index id */
- ulint comp, /* in: nonzero=compact page format */
- mtr_t* mtr) /* in: mini-transaction handle */
-{
- ulint page_no;
- buf_frame_t* ibuf_hdr_frame;
- buf_frame_t* frame;
- page_t* page;
-
- /* Create the two new segments (one, in the case of an ibuf tree) for
- the index tree; the segment headers are put on the allocated root page
- (for an ibuf tree, not in the root, but on a separate ibuf header
- page) */
-
- if (type & DICT_IBUF) {
- /* Allocate first the ibuf header page */
- ibuf_hdr_frame = fseg_create(
- space, 0, IBUF_HEADER + IBUF_TREE_SEG_HEADER, mtr);
-
-#ifdef UNIV_SYNC_DEBUG
- buf_page_dbg_add_level(ibuf_hdr_frame, SYNC_TREE_NODE_NEW);
-#endif /* UNIV_SYNC_DEBUG */
- ut_ad(buf_frame_get_page_no(ibuf_hdr_frame)
- == IBUF_HEADER_PAGE_NO);
- /* Allocate then the next page to the segment: it will be the
- tree root page */
-
- page_no = fseg_alloc_free_page(ibuf_hdr_frame + IBUF_HEADER
- + IBUF_TREE_SEG_HEADER,
- IBUF_TREE_ROOT_PAGE_NO,
- FSP_UP, mtr);
- ut_ad(page_no == IBUF_TREE_ROOT_PAGE_NO);
-
- frame = buf_page_get(space, page_no, RW_X_LATCH, mtr);
- } else {
- frame = fseg_create(space, 0, PAGE_HEADER + PAGE_BTR_SEG_TOP,
- mtr);
- }
-
- if (frame == NULL) {
-
- return(FIL_NULL);
- }
-
- page_no = buf_frame_get_page_no(frame);
-
-#ifdef UNIV_SYNC_DEBUG
- buf_page_dbg_add_level(frame, SYNC_TREE_NODE_NEW);
-#endif /* UNIV_SYNC_DEBUG */
-
- if (type & DICT_IBUF) {
- /* It is an insert buffer tree: initialize the free list */
-
- ut_ad(page_no == IBUF_TREE_ROOT_PAGE_NO);
-
- flst_init(frame + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST, mtr);
- } else {
- /* It is a non-ibuf tree: create a file segment for leaf
- pages */
- fseg_create(space, page_no, PAGE_HEADER + PAGE_BTR_SEG_LEAF,
- mtr);
- /* The fseg create acquires a second latch on the page,
- therefore we must declare it: */
-#ifdef UNIV_SYNC_DEBUG
- buf_page_dbg_add_level(frame, SYNC_TREE_NODE_NEW);
-#endif /* UNIV_SYNC_DEBUG */
- }
-
- /* Create a new index page on the the allocated segment page */
- page = page_create(frame, mtr, comp);
- buf_block_align(page)->check_index_page_at_flush = TRUE;
-
- /* Set the index id of the page */
- btr_page_set_index_id(page, index_id, mtr);
-
- /* Set the level of the new index page */
- btr_page_set_level(page, 0, mtr);
-
- /* Set the next node and previous node fields */
- btr_page_set_next(page, FIL_NULL, mtr);
- btr_page_set_prev(page, FIL_NULL, mtr);
-
- /* We reset the free bits for the page to allow creation of several
- trees in the same mtr, otherwise the latch on a bitmap page would
- prevent it because of the latching order */
-
- ibuf_reset_free_bits_with_type(type, page);
-
- /* In the following assertion we test that two records of maximum
- allowed size fit on the root page: this fact is needed to ensure
- correctness of split algorithms */
-
- ut_ad(page_get_max_insert_size(page, 2) > 2 * BTR_PAGE_MAX_REC_SIZE);
-
- return(page_no);
-}
-
-/****************************************************************
-Frees a B-tree except the root page, which MUST be freed after this
-by calling btr_free_root. */
-
-void
-btr_free_but_not_root(
-/*==================*/
- ulint space, /* in: space where created */
- ulint root_page_no) /* in: root page number */
-{
- ibool finished;
- page_t* root;
- mtr_t mtr;
-
-leaf_loop:
- mtr_start(&mtr);
-
- root = btr_page_get(space, root_page_no, RW_X_LATCH, &mtr);
-
- /* NOTE: page hash indexes are dropped when a page is freed inside
- fsp0fsp. */
-
- finished = fseg_free_step(root + PAGE_HEADER + PAGE_BTR_SEG_LEAF,
- &mtr);
- mtr_commit(&mtr);
-
- if (!finished) {
-
- goto leaf_loop;
- }
-top_loop:
- mtr_start(&mtr);
-
- root = btr_page_get(space, root_page_no, RW_X_LATCH, &mtr);
-
- finished = fseg_free_step_not_header(
- root + PAGE_HEADER + PAGE_BTR_SEG_TOP, &mtr);
- mtr_commit(&mtr);
-
- if (!finished) {
-
- goto top_loop;
- }
-}
-
-/****************************************************************
-Frees the B-tree root page. Other tree MUST already have been freed. */
-
-void
-btr_free_root(
-/*==========*/
- ulint space, /* in: space where created */
- ulint root_page_no, /* in: root page number */
- mtr_t* mtr) /* in: a mini-transaction which has already
- been started */
-{
- ibool finished;
- page_t* root;
-
- root = btr_page_get(space, root_page_no, RW_X_LATCH, mtr);
-
- btr_search_drop_page_hash_index(root);
-top_loop:
- finished = fseg_free_step(root + PAGE_HEADER + PAGE_BTR_SEG_TOP, mtr);
- if (!finished) {
-
- goto top_loop;
- }
-}
-
-/*****************************************************************
-Reorganizes an index page. */
-static
-void
-btr_page_reorganize_low(
-/*====================*/
- ibool recovery,/* in: TRUE if called in recovery:
- locks should not be updated, i.e.,
- there cannot exist locks on the
- page, and a hash index should not be
- dropped: it cannot exist */
- page_t* page, /* in: page to be reorganized */
- dict_index_t* index, /* in: record descriptor */
- mtr_t* mtr) /* in: mtr */
-{
- page_t* new_page;
- ulint log_mode;
- ulint data_size1;
- ulint data_size2;
- ulint max_ins_size1;
- ulint max_ins_size2;
-
- ut_ad(mtr_memo_contains(mtr, buf_block_align(page),
- MTR_MEMO_PAGE_X_FIX));
- ut_ad(!!page_is_comp(page) == dict_table_is_comp(index->table));
- data_size1 = page_get_data_size(page);
- max_ins_size1 = page_get_max_insert_size_after_reorganize(page, 1);
-
- /* Write the log record */
- mlog_open_and_write_index(mtr, page, index, page_is_comp(page)
- ? MLOG_COMP_PAGE_REORGANIZE
- : MLOG_PAGE_REORGANIZE, 0);
-
- /* Turn logging off */
- log_mode = mtr_set_log_mode(mtr, MTR_LOG_NONE);
-
- new_page = buf_frame_alloc();
-
- /* Copy the old page to temporary space */
- buf_frame_copy(new_page, page);
-
- if (!recovery) {
- btr_search_drop_page_hash_index(page);
- }
-
- /* Recreate the page: note that global data on page (possible
- segment headers, next page-field, etc.) is preserved intact */
-
- page_create(page, mtr, page_is_comp(page));
- buf_block_align(page)->check_index_page_at_flush = TRUE;
-
- /* Copy the records from the temporary space to the recreated page;
- do not copy the lock bits yet */
-
- page_copy_rec_list_end_no_locks(page, new_page,
- page_get_infimum_rec(new_page),
- index, mtr);
- /* Copy max trx id to recreated page */
- page_set_max_trx_id(page, page_get_max_trx_id(new_page));
-
- if (!recovery) {
- /* Update the record lock bitmaps */
- lock_move_reorganize_page(page, new_page);
- }
-
- data_size2 = page_get_data_size(page);
- max_ins_size2 = page_get_max_insert_size_after_reorganize(page, 1);
-
- if (data_size1 != data_size2 || max_ins_size1 != max_ins_size2) {
- buf_page_print(page);
- buf_page_print(new_page);
- fprintf(stderr,
- "InnoDB: Error: page old data size %lu"
- " new data size %lu\n"
- "InnoDB: Error: page old max ins size %lu"
- " new max ins size %lu\n"
- "InnoDB: Submit a detailed bug report"
- " to http://bugs.mysql.com\n",
- (unsigned long) data_size1, (unsigned long) data_size2,
- (unsigned long) max_ins_size1,
- (unsigned long) max_ins_size2);
- }
-
- buf_frame_free(new_page);
-
- /* Restore logging mode */
- mtr_set_log_mode(mtr, log_mode);
-}
-
-/*****************************************************************
-Reorganizes an index page. */
-
-void
-btr_page_reorganize(
-/*================*/
- page_t* page, /* in: page to be reorganized */
- dict_index_t* index, /* in: record descriptor */
- mtr_t* mtr) /* in: mtr */
-{
- btr_page_reorganize_low(FALSE, page, index, mtr);
-}
-
-/***************************************************************
-Parses a redo log record of reorganizing a page. */
-
-byte*
-btr_parse_page_reorganize(
-/*======================*/
- /* out: end of log record or NULL */
- byte* ptr, /* in: buffer */
- byte* end_ptr __attribute__((unused)),
- /* in: buffer end */
- dict_index_t* index, /* in: record descriptor */
- page_t* page, /* in: page or NULL */
- mtr_t* mtr) /* in: mtr or NULL */
-{
- ut_ad(ptr && end_ptr);
-
- /* The record is empty, except for the record initial part */
-
- if (page) {
- btr_page_reorganize_low(TRUE, page, index, mtr);
- }
-
- return(ptr);
-}
-
-/*****************************************************************
-Empties an index page. */
-static
-void
-btr_page_empty(
-/*===========*/
- page_t* page, /* in: page to be emptied */
- mtr_t* mtr) /* in: mtr */
-{
- ut_ad(mtr_memo_contains(mtr, buf_block_align(page),
- MTR_MEMO_PAGE_X_FIX));
- btr_search_drop_page_hash_index(page);
-
- /* Recreate the page: note that global data on page (possible
- segment headers, next page-field, etc.) is preserved intact */
-
- page_create(page, mtr, page_is_comp(page));
- buf_block_align(page)->check_index_page_at_flush = TRUE;
-}
-
-/*****************************************************************
-Makes tree one level higher by splitting the root, and inserts
-the tuple. It is assumed that mtr contains an x-latch on the tree.
-NOTE that the operation of this function must always succeed,
-we cannot reverse it: therefore enough free disk space must be
-guaranteed to be available before this function is called. */
-
-rec_t*
-btr_root_raise_and_insert(
-/*======================*/
- /* out: inserted record */
- btr_cur_t* cursor, /* in: cursor at which to insert: must be
- on the root page; when the function returns,
- the cursor is positioned on the predecessor
- of the inserted record */
- dtuple_t* tuple, /* in: tuple to insert */
- mtr_t* mtr) /* in: mtr */
-{
- dict_index_t* index;
- page_t* root;
- page_t* new_page;
- ulint new_page_no;
- rec_t* rec;
- mem_heap_t* heap;
- dtuple_t* node_ptr;
- ulint level;
- rec_t* node_ptr_rec;
- page_cur_t* page_cursor;
-
- root = btr_cur_get_page(cursor);
- index = btr_cur_get_index(cursor);
-
- ut_ad(dict_index_get_page(index) == buf_frame_get_page_no(root));
- ut_ad(mtr_memo_contains(mtr, dict_index_get_lock(index),
- MTR_MEMO_X_LOCK));
- ut_ad(mtr_memo_contains(mtr, buf_block_align(root),
- MTR_MEMO_PAGE_X_FIX));
- btr_search_drop_page_hash_index(root);
-
- /* Allocate a new page to the tree. Root splitting is done by first
- moving the root records to the new page, emptying the root, putting
- a node pointer to the new page, and then splitting the new page. */
-
- new_page = btr_page_alloc(index, 0, FSP_NO_DIR,
- btr_page_get_level(root, mtr), mtr);
-
- btr_page_create(new_page, index, mtr);
-
- level = btr_page_get_level(root, mtr);
-
- /* Set the levels of the new index page and root page */
- btr_page_set_level(new_page, level, mtr);
- btr_page_set_level(root, level + 1, mtr);
-
- /* Set the next node and previous node fields of new page */
- btr_page_set_next(new_page, FIL_NULL, mtr);
- btr_page_set_prev(new_page, FIL_NULL, mtr);
-
- /* Move the records from root to the new page */
-
- page_move_rec_list_end(new_page, root, page_get_infimum_rec(root),
- index, mtr);
- /* If this is a pessimistic insert which is actually done to
- perform a pessimistic update then we have stored the lock
- information of the record to be inserted on the infimum of the
- root page: we cannot discard the lock structs on the root page */
-
- lock_update_root_raise(new_page, root);
-
- /* Create a memory heap where the node pointer is stored */
- heap = mem_heap_create(100);
-
- rec = page_rec_get_next(page_get_infimum_rec(new_page));
- new_page_no = buf_frame_get_page_no(new_page);
-
- /* Build the node pointer (= node key and page address) for the
- child */
-
- node_ptr = dict_index_build_node_ptr(index, rec, new_page_no, heap,
- level);
- /* Reorganize the root to get free space */
- btr_page_reorganize(root, index, mtr);
-
- page_cursor = btr_cur_get_page_cur(cursor);
-
- /* Insert node pointer to the root */
-
- page_cur_set_before_first(root, page_cursor);
-
- node_ptr_rec = page_cur_tuple_insert(page_cursor, node_ptr,
- index, mtr);
-
- ut_ad(node_ptr_rec);
-
- /* The node pointer must be marked as the predefined minimum record,
- as there is no lower alphabetical limit to records in the leftmost
- node of a level: */
-
- btr_set_min_rec_mark(node_ptr_rec, page_is_comp(root), mtr);
-
- /* Free the memory heap */
- mem_heap_free(heap);
-
- /* We play safe and reset the free bits for the new page */
-
-#if 0
- fprintf(stderr, "Root raise new page no %lu\n",
- buf_frame_get_page_no(new_page));
-#endif
-
- ibuf_reset_free_bits(index, new_page);
- /* Reposition the cursor to the child node */
- page_cur_search(new_page, index, tuple,
- PAGE_CUR_LE, page_cursor);
-
- /* Split the child and insert tuple */
- return(btr_page_split_and_insert(cursor, tuple, mtr));
-}
-
-/*****************************************************************
-Decides if the page should be split at the convergence point of inserts
-converging to the left. */
-
-ibool
-btr_page_get_split_rec_to_left(
-/*===========================*/
- /* out: TRUE if split recommended */
- btr_cur_t* cursor, /* in: cursor at which to insert */
- rec_t** split_rec) /* out: if split recommended,
- the first record on upper half page,
- or NULL if tuple to be inserted should
- be first */
-{
- page_t* page;
- rec_t* insert_point;
- rec_t* infimum;
-
- page = btr_cur_get_page(cursor);
- insert_point = btr_cur_get_rec(cursor);
-
- if (page_header_get_ptr(page, PAGE_LAST_INSERT)
- == page_rec_get_next(insert_point)) {
-
- infimum = page_get_infimum_rec(page);
-
- /* If the convergence is in the middle of a page, include also
- the record immediately before the new insert to the upper
- page. Otherwise, we could repeatedly move from page to page
- lots of records smaller than the convergence point. */
-
- if (infimum != insert_point
- && page_rec_get_next(infimum) != insert_point) {
-
- *split_rec = insert_point;
- } else {
- *split_rec = page_rec_get_next(insert_point);
- }
-
- return(TRUE);
- }
-
- return(FALSE);
-}
-
-/*****************************************************************
-Decides if the page should be split at the convergence point of inserts
-converging to the right. */
-
-ibool
-btr_page_get_split_rec_to_right(
-/*============================*/
- /* out: TRUE if split recommended */
- btr_cur_t* cursor, /* in: cursor at which to insert */
- rec_t** split_rec) /* out: if split recommended,
- the first record on upper half page,
- or NULL if tuple to be inserted should
- be first */
-{
- page_t* page;
- rec_t* insert_point;
-
- page = btr_cur_get_page(cursor);
- insert_point = btr_cur_get_rec(cursor);
-
- /* We use eager heuristics: if the new insert would be right after
- the previous insert on the same page, we assume that there is a
- pattern of sequential inserts here. */
-
- if (UNIV_LIKELY(page_header_get_ptr(page, PAGE_LAST_INSERT)
- == insert_point)) {
-
- rec_t* next_rec;
-
- next_rec = page_rec_get_next(insert_point);
-
- if (page_rec_is_supremum(next_rec)) {
-split_at_new:
- /* Split at the new record to insert */
- *split_rec = NULL;
- } else {
- rec_t* next_next_rec = page_rec_get_next(next_rec);
- if (page_rec_is_supremum(next_next_rec)) {
-
- goto split_at_new;
- }
-
- /* If there are >= 2 user records up from the insert
- point, split all but 1 off. We want to keep one because
- then sequential inserts can use the adaptive hash
- index, as they can do the necessary checks of the right
- search position just by looking at the records on this
- page. */
-
- *split_rec = next_next_rec;
- }
-
- return(TRUE);
- }
-
- return(FALSE);
-}
-
-/*****************************************************************
-Calculates a split record such that the tuple will certainly fit on
-its half-page when the split is performed. We assume in this function
-only that the cursor page has at least one user record. */
-static
-rec_t*
-btr_page_get_sure_split_rec(
-/*========================*/
- /* out: split record, or NULL if
- tuple will be the first record on
- upper half-page */
- btr_cur_t* cursor, /* in: cursor at which insert
- should be made */
- dtuple_t* tuple) /* in: tuple to insert */
-{
- page_t* page;
- ulint insert_size;
- ulint free_space;
- ulint total_data;
- ulint total_n_recs;
- ulint total_space;
- ulint incl_data;
- rec_t* ins_rec;
- rec_t* rec;
- rec_t* next_rec;
- ulint n;
- mem_heap_t* heap;
- ulint* offsets;
-
- page = btr_cur_get_page(cursor);
-
- insert_size = rec_get_converted_size(cursor->index, tuple);
- free_space = page_get_free_space_of_empty(page_is_comp(page));
-
- /* free_space is now the free space of a created new page */
-
- total_data = page_get_data_size(page) + insert_size;
- total_n_recs = page_get_n_recs(page) + 1;
- ut_ad(total_n_recs >= 2);
- total_space = total_data + page_dir_calc_reserved_space(total_n_recs);
-
- n = 0;
- incl_data = 0;
- ins_rec = btr_cur_get_rec(cursor);
- rec = page_get_infimum_rec(page);
-
- heap = NULL;
- offsets = NULL;
-
- /* We start to include records to the left half, and when the
- space reserved by them exceeds half of total_space, then if
- the included records fit on the left page, they will be put there
- if something was left over also for the right page,
- otherwise the last included record will be the first on the right
- half page */
-
- for (;;) {
- /* Decide the next record to include */
- if (rec == ins_rec) {
- rec = NULL; /* NULL denotes that tuple is
- now included */
- } else if (rec == NULL) {
- rec = page_rec_get_next(ins_rec);
- } else {
- rec = page_rec_get_next(rec);
- }
-
- if (rec == NULL) {
- /* Include tuple */
- incl_data += insert_size;
- } else {
- offsets = rec_get_offsets(rec, cursor->index,
- offsets, ULINT_UNDEFINED,
- &heap);
- incl_data += rec_offs_size(offsets);
- }
-
- n++;
-
- if (incl_data + page_dir_calc_reserved_space(n)
- >= total_space / 2) {
-
- if (incl_data + page_dir_calc_reserved_space(n)
- <= free_space) {
- /* The next record will be the first on
- the right half page if it is not the
- supremum record of page */
-
- if (rec == ins_rec) {
- rec = NULL;
-
- goto func_exit;
- } else if (rec == NULL) {
- next_rec = page_rec_get_next(ins_rec);
- } else {
- next_rec = page_rec_get_next(rec);
- }
- ut_ad(next_rec);
- if (!page_rec_is_supremum(next_rec)) {
- rec = next_rec;
- }
- }
-
-func_exit:
- if (UNIV_LIKELY_NULL(heap)) {
- mem_heap_free(heap);
- }
- return(rec);
- }
- }
-}
-
-/*****************************************************************
-Returns TRUE if the insert fits on the appropriate half-page with the
-chosen split_rec. */
-static
-ibool
-btr_page_insert_fits(
-/*=================*/
- /* out: TRUE if fits */
- btr_cur_t* cursor, /* in: cursor at which insert
- should be made */
- rec_t* split_rec, /* in: suggestion for first record
- on upper half-page, or NULL if
- tuple to be inserted should be first */
- const ulint* offsets, /* in: rec_get_offsets(
- split_rec, cursor->index) */
- dtuple_t* tuple, /* in: tuple to insert */
- mem_heap_t* heap) /* in: temporary memory heap */
-{
- page_t* page;
- ulint insert_size;
- ulint free_space;
- ulint total_data;
- ulint total_n_recs;
- rec_t* rec;
- rec_t* end_rec;
- ulint* offs;
-
- page = btr_cur_get_page(cursor);
-
- ut_ad(!split_rec == !offsets);
- ut_ad(!offsets
- || !page_is_comp(page) == !rec_offs_comp(offsets));
- ut_ad(!offsets
- || rec_offs_validate(split_rec, cursor->index, offsets));
-
- insert_size = rec_get_converted_size(cursor->index, tuple);
- free_space = page_get_free_space_of_empty(page_is_comp(page));
-
- /* free_space is now the free space of a created new page */
-
- total_data = page_get_data_size(page) + insert_size;
- total_n_recs = page_get_n_recs(page) + 1;
-
- /* We determine which records (from rec to end_rec, not including
- end_rec) will end up on the other half page from tuple when it is
- inserted. */
-
- if (split_rec == NULL) {
- rec = page_rec_get_next(page_get_infimum_rec(page));
- end_rec = page_rec_get_next(btr_cur_get_rec(cursor));
-
- } else if (cmp_dtuple_rec(tuple, split_rec, offsets) >= 0) {
-
- rec = page_rec_get_next(page_get_infimum_rec(page));
- end_rec = split_rec;
- } else {
- rec = split_rec;
- end_rec = page_get_supremum_rec(page);
- }
-
- if (total_data + page_dir_calc_reserved_space(total_n_recs)
- <= free_space) {
-
- /* Ok, there will be enough available space on the
- half page where the tuple is inserted */
-
- return(TRUE);
- }
-
- offs = NULL;
-
- while (rec != end_rec) {
- /* In this loop we calculate the amount of reserved
- space after rec is removed from page. */
-
- offs = rec_get_offsets(rec, cursor->index, offs,
- ULINT_UNDEFINED, &heap);
-
- total_data -= rec_offs_size(offs);
- total_n_recs--;
-
- if (total_data + page_dir_calc_reserved_space(total_n_recs)
- <= free_space) {
-
- /* Ok, there will be enough available space on the
- half page where the tuple is inserted */
-
- return(TRUE);
- }
-
- rec = page_rec_get_next(rec);
- }
-
- return(FALSE);
-}
-
-/***********************************************************
-Inserts a data tuple to a tree on a non-leaf level. It is assumed
-that mtr holds an x-latch on the tree. */
-
-void
-btr_insert_on_non_leaf_level(
-/*=========================*/
- dict_index_t* index, /* in: index */
- ulint level, /* in: level, must be > 0 */
- dtuple_t* tuple, /* in: the record to be inserted */
- mtr_t* mtr) /* in: mtr */
-{
- big_rec_t* dummy_big_rec;
- btr_cur_t cursor;
- ulint err;
- rec_t* rec;
-
- ut_ad(level > 0);
-
- btr_cur_search_to_nth_level(index, level, tuple, PAGE_CUR_LE,
- BTR_CONT_MODIFY_TREE,
- &cursor, 0, mtr);
-
- err = btr_cur_pessimistic_insert(BTR_NO_LOCKING_FLAG
- | BTR_KEEP_SYS_FLAG
- | BTR_NO_UNDO_LOG_FLAG,
- &cursor, tuple, &rec,
- &dummy_big_rec, NULL, mtr);
- ut_a(err == DB_SUCCESS);
-}
-
-/******************************************************************
-Attaches the halves of an index page on the appropriate level in an
-index tree. */
-static
-void
-btr_attach_half_pages(
-/*==================*/
- dict_index_t* index, /* in: the index tree */
- page_t* page, /* in: page to be split */
- rec_t* split_rec, /* in: first record on upper
- half page */
- page_t* new_page, /* in: the new half page */
- ulint direction, /* in: FSP_UP or FSP_DOWN */
- mtr_t* mtr) /* in: mtr */
-{
- ulint space;
- rec_t* node_ptr;
- page_t* prev_page;
- page_t* next_page;
- ulint prev_page_no;
- ulint next_page_no;
- ulint level;
- page_t* lower_page;
- page_t* upper_page;
- ulint lower_page_no;
- ulint upper_page_no;
- dtuple_t* node_ptr_upper;
- mem_heap_t* heap;
-
- ut_ad(mtr_memo_contains(mtr, buf_block_align(page),
- MTR_MEMO_PAGE_X_FIX));
- ut_ad(mtr_memo_contains(mtr, buf_block_align(new_page),
- MTR_MEMO_PAGE_X_FIX));
- ut_a(page_is_comp(page) == page_is_comp(new_page));
-
- /* Create a memory heap where the data tuple is stored */
- heap = mem_heap_create(1024);
-
- /* Based on split direction, decide upper and lower pages */
- if (direction == FSP_DOWN) {
-
- lower_page_no = buf_frame_get_page_no(new_page);
- upper_page_no = buf_frame_get_page_no(page);
- lower_page = new_page;
- upper_page = page;
-
- /* Look up the index for the node pointer to page */
- node_ptr = btr_page_get_father_node_ptr(index, page, mtr);
-
- /* Replace the address of the old child node (= page) with the
- address of the new lower half */
-
- btr_node_ptr_set_child_page_no(node_ptr,
- rec_get_offsets(
- node_ptr, index,
- NULL, ULINT_UNDEFINED,
- &heap),
- lower_page_no, mtr);
- mem_heap_empty(heap);
- } else {
- lower_page_no = buf_frame_get_page_no(page);
- upper_page_no = buf_frame_get_page_no(new_page);
- lower_page = page;
- upper_page = new_page;
- }
-
- /* Get the level of the split pages */
- level = btr_page_get_level(page, mtr);
-
- /* Build the node pointer (= node key and page address) for the upper
- half */
-
- node_ptr_upper = dict_index_build_node_ptr(index, split_rec,
- upper_page_no, heap, level);
-
- /* Insert it next to the pointer to the lower half. Note that this
- may generate recursion leading to a split on the higher level. */
-
- btr_insert_on_non_leaf_level(index, level + 1, node_ptr_upper, mtr);
-
- /* Free the memory heap */
- mem_heap_free(heap);
-
- /* Get the previous and next pages of page */
-
- prev_page_no = btr_page_get_prev(page, mtr);
- next_page_no = btr_page_get_next(page, mtr);
- space = buf_frame_get_space_id(page);
-
- /* Update page links of the level */
-
- if (prev_page_no != FIL_NULL) {
-
- prev_page = btr_page_get(space, prev_page_no, RW_X_LATCH, mtr);
- ut_a(page_is_comp(prev_page) == page_is_comp(page));
-#ifdef UNIV_BTR_DEBUG
- ut_a(btr_page_get_next(prev_page, mtr)
- == buf_frame_get_page_no(page));
-#endif /* UNIV_BTR_DEBUG */
-
- btr_page_set_next(prev_page, lower_page_no, mtr);
- }
-
- if (next_page_no != FIL_NULL) {
-
- next_page = btr_page_get(space, next_page_no, RW_X_LATCH, mtr);
- ut_a(page_is_comp(next_page) == page_is_comp(page));
-
- btr_page_set_prev(next_page, upper_page_no, mtr);
- }
-
- btr_page_set_prev(lower_page, prev_page_no, mtr);
- btr_page_set_next(lower_page, upper_page_no, mtr);
- btr_page_set_level(lower_page, level, mtr);
-
- btr_page_set_prev(upper_page, lower_page_no, mtr);
- btr_page_set_next(upper_page, next_page_no, mtr);
- btr_page_set_level(upper_page, level, mtr);
-}
-
-/*****************************************************************
-Splits an index page to halves and inserts the tuple. It is assumed
-that mtr holds an x-latch to the index tree. NOTE: the tree x-latch
-is released within this function! NOTE that the operation of this
-function must always succeed, we cannot reverse it: therefore
-enough free disk space must be guaranteed to be available before
-this function is called. */
-
-rec_t*
-btr_page_split_and_insert(
-/*======================*/
- /* out: inserted record; NOTE: the tree
- x-latch is released! NOTE: 2 free disk
- pages must be available! */
- btr_cur_t* cursor, /* in: cursor at which to insert; when the
- function returns, the cursor is positioned
- on the predecessor of the inserted record */
- dtuple_t* tuple, /* in: tuple to insert */
- mtr_t* mtr) /* in: mtr */
-{
- page_t* page;
- ulint page_no;
- byte direction;
- ulint hint_page_no;
- page_t* new_page;
- rec_t* split_rec;
- page_t* left_page;
- page_t* right_page;
- page_t* insert_page;
- page_cur_t* page_cursor;
- rec_t* first_rec;
- byte* buf = 0; /* remove warning */
- rec_t* move_limit;
- ibool insert_will_fit;
- ulint n_iterations = 0;
- rec_t* rec;
- mem_heap_t* heap;
- ulint n_uniq;
- ulint* offsets;
-
- heap = mem_heap_create(1024);
- n_uniq = dict_index_get_n_unique_in_tree(cursor->index);
-func_start:
- mem_heap_empty(heap);
- offsets = NULL;
-
- ut_ad(mtr_memo_contains(mtr, dict_index_get_lock(cursor->index),
- MTR_MEMO_X_LOCK));
-#ifdef UNIV_SYNC_DEBUG
- ut_ad(rw_lock_own(dict_index_get_lock(cursor->index), RW_LOCK_EX));
-#endif /* UNIV_SYNC_DEBUG */
-
- page = btr_cur_get_page(cursor);
-
- ut_ad(mtr_memo_contains(mtr, buf_block_align(page),
- MTR_MEMO_PAGE_X_FIX));
- ut_ad(page_get_n_recs(page) >= 2);
-
- page_no = buf_frame_get_page_no(page);
-
- /* 1. Decide the split record; split_rec == NULL means that the
- tuple to be inserted should be the first record on the upper
- half-page */
-
- if (n_iterations > 0) {
- direction = FSP_UP;
- hint_page_no = page_no + 1;
- split_rec = btr_page_get_sure_split_rec(cursor, tuple);
-
- } else if (btr_page_get_split_rec_to_right(cursor, &split_rec)) {
- direction = FSP_UP;
- hint_page_no = page_no + 1;
-
- } else if (btr_page_get_split_rec_to_left(cursor, &split_rec)) {
- direction = FSP_DOWN;
- hint_page_no = page_no - 1;
- } else {
- direction = FSP_UP;
- hint_page_no = page_no + 1;
- split_rec = page_get_middle_rec(page);
- }
-
- /* 2. Allocate a new page to the index */
- new_page = btr_page_alloc(cursor->index, hint_page_no, direction,
- btr_page_get_level(page, mtr), mtr);
- btr_page_create(new_page, cursor->index, mtr);
-
- /* 3. Calculate the first record on the upper half-page, and the
- first record (move_limit) on original page which ends up on the
- upper half */
-
- if (split_rec != NULL) {
- first_rec = split_rec;
- move_limit = split_rec;
- } else {
- buf = mem_alloc(rec_get_converted_size(cursor->index, tuple));
-
- first_rec = rec_convert_dtuple_to_rec(buf,
- cursor->index, tuple);
- move_limit = page_rec_get_next(btr_cur_get_rec(cursor));
- }
-
- /* 4. Do first the modifications in the tree structure */
-
- btr_attach_half_pages(cursor->index, page, first_rec,
- new_page, direction, mtr);
-
- if (split_rec == NULL) {
- mem_free(buf);
- }
-
- /* If the split is made on the leaf level and the insert will fit
- on the appropriate half-page, we may release the tree x-latch.
- We can then move the records after releasing the tree latch,
- thus reducing the tree latch contention. */
-
- if (split_rec) {
- offsets = rec_get_offsets(split_rec, cursor->index, offsets,
- n_uniq, &heap);
-
- insert_will_fit = btr_page_insert_fits(cursor,
- split_rec, offsets,
- tuple, heap);
- } else {
- insert_will_fit = btr_page_insert_fits(cursor,
- NULL, NULL,
- tuple, heap);
- }
-
- if (insert_will_fit && (btr_page_get_level(page, mtr) == 0)) {
-
- mtr_memo_release(mtr, dict_index_get_lock(cursor->index),
- MTR_MEMO_X_LOCK);
- }
-
- /* 5. Move then the records to the new page */
- if (direction == FSP_DOWN) {
- /* fputs("Split left\n", stderr); */
-
- page_move_rec_list_start(new_page, page, move_limit,
- cursor->index, mtr);
- left_page = new_page;
- right_page = page;
-
- lock_update_split_left(right_page, left_page);
- } else {
- /* fputs("Split right\n", stderr); */
-
- page_move_rec_list_end(new_page, page, move_limit,
- cursor->index, mtr);
- left_page = page;
- right_page = new_page;
-
- lock_update_split_right(right_page, left_page);
- }
-
- /* 6. The split and the tree modification is now completed. Decide the
- page where the tuple should be inserted */
-
- if (split_rec == NULL) {
- insert_page = right_page;
-
- } else {
- offsets = rec_get_offsets(first_rec, cursor->index,
- offsets, n_uniq, &heap);
-
- if (cmp_dtuple_rec(tuple, first_rec, offsets) >= 0) {
-
- insert_page = right_page;
- } else {
- insert_page = left_page;
- }
- }
-
- /* 7. Reposition the cursor for insert and try insertion */
- page_cursor = btr_cur_get_page_cur(cursor);
-
- page_cur_search(insert_page, cursor->index, tuple,
- PAGE_CUR_LE, page_cursor);
-
- rec = page_cur_tuple_insert(page_cursor, tuple, cursor->index, mtr);
-
- if (rec != NULL) {
- /* Insert fit on the page: update the free bits for the
- left and right pages in the same mtr */
-
- ibuf_update_free_bits_for_two_pages_low(cursor->index,
- left_page,
- right_page, mtr);
- /* fprintf(stderr, "Split and insert done %lu %lu\n",
- buf_frame_get_page_no(left_page),
- buf_frame_get_page_no(right_page)); */
- mem_heap_free(heap);
- return(rec);
- }
-
- /* 8. If insert did not fit, try page reorganization */
-
- btr_page_reorganize(insert_page, cursor->index, mtr);
-
- page_cur_search(insert_page, cursor->index, tuple,
- PAGE_CUR_LE, page_cursor);
- rec = page_cur_tuple_insert(page_cursor, tuple, cursor->index, mtr);
-
- if (rec == NULL) {
- /* The insert did not fit on the page: loop back to the
- start of the function for a new split */
-
- /* We play safe and reset the free bits for new_page */
- ibuf_reset_free_bits(cursor->index, new_page);
-
- /* fprintf(stderr, "Split second round %lu\n",
- buf_frame_get_page_no(page)); */
- n_iterations++;
- ut_ad(n_iterations < 2);
- ut_ad(!insert_will_fit);
-
- goto func_start;
- }
-
- /* Insert fit on the page: update the free bits for the
- left and right pages in the same mtr */
-
- ibuf_update_free_bits_for_two_pages_low(cursor->index, left_page,
- right_page, mtr);
-#if 0
- fprintf(stderr, "Split and insert done %lu %lu\n",
- buf_frame_get_page_no(left_page),
- buf_frame_get_page_no(right_page));
-#endif
-
- ut_ad(page_validate(left_page, cursor->index));
- ut_ad(page_validate(right_page, cursor->index));
-
- mem_heap_free(heap);
- return(rec);
-}
-
-/*****************************************************************
-Removes a page from the level list of pages. */
-static
-void
-btr_level_list_remove(
-/*==================*/
- page_t* page, /* in: page to remove */
- mtr_t* mtr) /* in: mtr */
-{
- ulint space;
- ulint prev_page_no;
- page_t* prev_page;
- ulint next_page_no;
- page_t* next_page;
-
- ut_ad(page && mtr);
- ut_ad(mtr_memo_contains(mtr, buf_block_align(page),
- MTR_MEMO_PAGE_X_FIX));
- /* Get the previous and next page numbers of page */
-
- prev_page_no = btr_page_get_prev(page, mtr);
- next_page_no = btr_page_get_next(page, mtr);
- space = buf_frame_get_space_id(page);
-
- /* Update page links of the level */
-
- if (prev_page_no != FIL_NULL) {
-
- prev_page = btr_page_get(space, prev_page_no, RW_X_LATCH, mtr);
- ut_a(page_is_comp(prev_page) == page_is_comp(page));
-#ifdef UNIV_BTR_DEBUG
- ut_a(btr_page_get_next(prev_page, mtr)
- == buf_frame_get_page_no(page));
-#endif /* UNIV_BTR_DEBUG */
-
- btr_page_set_next(prev_page, next_page_no, mtr);
- }
-
- if (next_page_no != FIL_NULL) {
-
- next_page = btr_page_get(space, next_page_no, RW_X_LATCH, mtr);
- ut_a(page_is_comp(next_page) == page_is_comp(page));
-#ifdef UNIV_BTR_DEBUG
- ut_a(btr_page_get_prev(next_page, mtr)
- == buf_frame_get_page_no(page));
-#endif /* UNIV_BTR_DEBUG */
-
- btr_page_set_prev(next_page, prev_page_no, mtr);
- }
-}
-
-/********************************************************************
-Writes the redo log record for setting an index record as the predefined
-minimum record. */
-UNIV_INLINE
-void
-btr_set_min_rec_mark_log(
-/*=====================*/
- rec_t* rec, /* in: record */
- ulint comp, /* nonzero=compact record format */
- mtr_t* mtr) /* in: mtr */
-{
- mlog_write_initial_log_record(
- rec, comp ? MLOG_COMP_REC_MIN_MARK : MLOG_REC_MIN_MARK, mtr);
-
- /* Write rec offset as a 2-byte ulint */
- mlog_catenate_ulint(mtr, page_offset(rec), MLOG_2BYTES);
-}
-
-/********************************************************************
-Parses the redo log record for setting an index record as the predefined
-minimum record. */
-
-byte*
-btr_parse_set_min_rec_mark(
-/*=======================*/
- /* out: end of log record or NULL */
- byte* ptr, /* in: buffer */
- byte* end_ptr,/* in: buffer end */
- ulint comp, /* in: nonzero=compact page format */
- page_t* page, /* in: page or NULL */
- mtr_t* mtr) /* in: mtr or NULL */
-{
- rec_t* rec;
-
- if (end_ptr < ptr + 2) {
-
- return(NULL);
- }
-
- if (page) {
- ut_a(!page_is_comp(page) == !comp);
-
- rec = page + mach_read_from_2(ptr);
-
- btr_set_min_rec_mark(rec, comp, mtr);
- }
-
- return(ptr + 2);
-}
-
-/********************************************************************
-Sets a record as the predefined minimum record. */
-
-void
-btr_set_min_rec_mark(
-/*=================*/
- rec_t* rec, /* in: record */
- ulint comp, /* in: nonzero=compact page format */
- mtr_t* mtr) /* in: mtr */
-{
- ulint info_bits;
-
- info_bits = rec_get_info_bits(rec, comp);
-
- rec_set_info_bits(rec, comp, info_bits | REC_INFO_MIN_REC_FLAG);
-
- btr_set_min_rec_mark_log(rec, comp, mtr);
-}
-
-/*****************************************************************
-Deletes on the upper level the node pointer to a page. */
-
-void
-btr_node_ptr_delete(
-/*================*/
- dict_index_t* index, /* in: index tree */
- page_t* page, /* in: page whose node pointer is deleted */
- mtr_t* mtr) /* in: mtr */
-{
- rec_t* node_ptr;
- btr_cur_t cursor;
- ibool compressed;
- ulint err;
-
- ut_ad(mtr_memo_contains(mtr, buf_block_align(page),
- MTR_MEMO_PAGE_X_FIX));
- /* Delete node pointer on father page */
-
- node_ptr = btr_page_get_father_node_ptr(index, page, mtr);
-
- btr_cur_position(index, node_ptr, &cursor);
- compressed = btr_cur_pessimistic_delete(&err, TRUE, &cursor, FALSE,
- mtr);
- ut_a(err == DB_SUCCESS);
-
- if (!compressed) {
- btr_cur_compress_if_useful(&cursor, mtr);
- }
-}
-
-/*****************************************************************
-If page is the only on its level, this function moves its records to the
-father page, thus reducing the tree height. */
-static
-void
-btr_lift_page_up(
-/*=============*/
- dict_index_t* index, /* in: index tree */
- page_t* page, /* in: page which is the only on its level;
- must not be empty: use
- btr_discard_only_page_on_level if the last
- record from the page should be removed */
- mtr_t* mtr) /* in: mtr */
-{
- page_t* father_page;
- page_t* iter_page;
- page_t* pages[BTR_MAX_LEVELS];
- ulint page_level;
- ulint root_page_no;
- ulint ancestors;
- ulint i;
-
- ut_ad(btr_page_get_prev(page, mtr) == FIL_NULL);
- ut_ad(btr_page_get_next(page, mtr) == FIL_NULL);
- ut_ad(mtr_memo_contains(mtr, buf_block_align(page),
- MTR_MEMO_PAGE_X_FIX));
- father_page = buf_frame_align(
- btr_page_get_father_node_ptr(index, page, mtr));
-
- page_level = btr_page_get_level(page, mtr);
- root_page_no = dict_index_get_page(index);
-
- ancestors = 1;
- pages[0] = father_page;
-
- /* Store all ancestor pages so we can reset their levels later on.
- We have to do all the searches on the tree now because later on,
- after we've replaced the first level, the tree is in an inconsistent
- state and can not be searched. */
- iter_page = father_page;
- for (;;) {
- if (buf_block_get_page_no(buf_block_align(iter_page))
- == root_page_no) {
-
- break;
- }
-
- ut_a(ancestors < BTR_MAX_LEVELS);
-
- iter_page = buf_frame_align(
- btr_page_get_father_node_ptr(index, iter_page, mtr));
-
- pages[ancestors++] = iter_page;
- }
-
- btr_search_drop_page_hash_index(page);
-
- /* Make the father empty */
- btr_page_empty(father_page, mtr);
-
- /* Move records to the father */
- page_copy_rec_list_end(father_page, page, page_get_infimum_rec(page),
- index, mtr);
- lock_update_copy_and_discard(father_page, page);
-
- /* Go upward to root page, decreasing levels by one. */
- for (i = 0; i < ancestors; i++) {
- iter_page = pages[i];
-
- ut_ad(btr_page_get_level(iter_page, mtr) == (page_level + 1));
-
- btr_page_set_level(iter_page, page_level, mtr);
- page_level++;
- }
-
- /* Free the file page */
- btr_page_free(index, page, mtr);
-
- /* We play safe and reset the free bits for the father */
- ibuf_reset_free_bits(index, father_page);
- ut_ad(page_validate(father_page, index));
- ut_ad(btr_check_node_ptr(index, father_page, mtr));
-}
-
-/*****************************************************************
-Tries to merge the page first to the left immediate brother if such a
-brother exists, and the node pointers to the current page and to the brother
-reside on the same page. If the left brother does not satisfy these
-conditions, looks at the right brother. If the page is the only one on that
-level lifts the records of the page to the father page, thus reducing the
-tree height. It is assumed that mtr holds an x-latch on the tree and on the
-page. If cursor is on the leaf level, mtr must also hold x-latches to the
-brothers, if they exist. NOTE: it is assumed that the caller has reserved
-enough free extents so that the compression will always succeed if done! */
-
-void
-btr_compress(
-/*=========*/
- btr_cur_t* cursor, /* in: cursor on the page to merge or lift;
- the page must not be empty: in record delete
- use btr_discard_page if the page would become
- empty */
- mtr_t* mtr) /* in: mtr */
-{
- dict_index_t* index;
- ulint space;
- ulint left_page_no;
- ulint right_page_no;
- page_t* merge_page;
- page_t* father_page;
- ibool is_left;
- page_t* page;
- rec_t* orig_pred;
- rec_t* orig_succ;
- rec_t* node_ptr;
- ulint data_size;
- ulint n_recs;
- ulint max_ins_size;
- ulint max_ins_size_reorg;
- ulint level;
- ulint comp;
-
- page = btr_cur_get_page(cursor);
- index = btr_cur_get_index(cursor);
- comp = page_is_comp(page);
- ut_a((ibool)!!comp == dict_table_is_comp(index->table));
-
- ut_ad(mtr_memo_contains(mtr, dict_index_get_lock(index),
- MTR_MEMO_X_LOCK));
- ut_ad(mtr_memo_contains(mtr, buf_block_align(page),
- MTR_MEMO_PAGE_X_FIX));
- level = btr_page_get_level(page, mtr);
- space = dict_index_get_space(index);
-
- left_page_no = btr_page_get_prev(page, mtr);
- right_page_no = btr_page_get_next(page, mtr);
-
-#if 0
- fprintf(stderr, "Merge left page %lu right %lu \n",
- left_page_no, right_page_no);
-#endif
-
- node_ptr = btr_page_get_father_node_ptr(index, page, mtr);
- ut_ad(!comp || rec_get_status(node_ptr) == REC_STATUS_NODE_PTR);
- father_page = buf_frame_align(node_ptr);
- ut_a(comp == page_is_comp(father_page));
-
- /* Decide the page to which we try to merge and which will inherit
- the locks */
-
- is_left = left_page_no != FIL_NULL;
-
- if (is_left) {
-
- merge_page = btr_page_get(space, left_page_no, RW_X_LATCH,
- mtr);
-#ifdef UNIV_BTR_DEBUG
- ut_a(btr_page_get_next(merge_page, mtr)
- == buf_frame_get_page_no(page));
-#endif /* UNIV_BTR_DEBUG */
- } else if (right_page_no != FIL_NULL) {
-
- merge_page = btr_page_get(space, right_page_no, RW_X_LATCH,
- mtr);
-#ifdef UNIV_BTR_DEBUG
- ut_a(btr_page_get_prev(merge_page, mtr)
- == buf_frame_get_page_no(page));
-#endif /* UNIV_BTR_DEBUG */
- } else {
- /* The page is the only one on the level, lift the records
- to the father */
- btr_lift_page_up(index, page, mtr);
-
- return;
- }
-
- n_recs = page_get_n_recs(page);
- data_size = page_get_data_size(page);
- ut_a(page_is_comp(merge_page) == comp);
-
- max_ins_size_reorg = page_get_max_insert_size_after_reorganize(
- merge_page, n_recs);
- if (data_size > max_ins_size_reorg) {
-
- /* No space for merge */
-
- return;
- }
-
- ut_ad(page_validate(merge_page, index));
-
- max_ins_size = page_get_max_insert_size(merge_page, n_recs);
-
- if (data_size > max_ins_size) {
-
- /* We have to reorganize merge_page */
-
- btr_page_reorganize(merge_page, index, mtr);
-
- max_ins_size = page_get_max_insert_size(merge_page, n_recs);
-
- ut_ad(page_validate(merge_page, index));
- ut_ad(page_get_max_insert_size(merge_page, n_recs)
- == max_ins_size_reorg);
- }
-
- if (data_size > max_ins_size) {
-
- /* Add fault tolerance, though this should never happen */
-
- return;
- }
-
- btr_search_drop_page_hash_index(page);
-
- /* Remove the page from the level list */
- btr_level_list_remove(page, mtr);
-
- if (is_left) {
- btr_node_ptr_delete(index, page, mtr);
- } else {
- mem_heap_t* heap = NULL;
- ulint offsets_[REC_OFFS_NORMAL_SIZE];
- *offsets_ = (sizeof offsets_) / sizeof *offsets_;
- /* Replace the address of the old child node (= page) with the
- address of the merge page to the right */
-
- btr_node_ptr_set_child_page_no(node_ptr,
- rec_get_offsets(
- node_ptr, index,
- offsets_,
- ULINT_UNDEFINED,
- &heap),
- right_page_no, mtr);
- if (UNIV_LIKELY_NULL(heap)) {
- mem_heap_free(heap);
- }
- btr_node_ptr_delete(index, merge_page, mtr);
- }
-
- /* Move records to the merge page */
- if (is_left) {
- orig_pred = page_rec_get_prev(
- page_get_supremum_rec(merge_page));
- page_copy_rec_list_start(merge_page, page,
- page_get_supremum_rec(page),
- index, mtr);
-
- lock_update_merge_left(merge_page, orig_pred, page);
- } else {
- orig_succ = page_rec_get_next(
- page_get_infimum_rec(merge_page));
- page_copy_rec_list_end(merge_page, page,
- page_get_infimum_rec(page),
- index, mtr);
-
- lock_update_merge_right(orig_succ, page);
- }
-
- /* We have added new records to merge_page: update its free bits */
- ibuf_update_free_bits_if_full(index, merge_page,
- UNIV_PAGE_SIZE, ULINT_UNDEFINED);
-
- ut_ad(page_validate(merge_page, index));
-
- /* Free the file page */
- btr_page_free(index, page, mtr);
-
- ut_ad(btr_check_node_ptr(index, merge_page, mtr));
-}
-
-/*****************************************************************
-Discards a page that is the only page on its level. */
-static
-void
-btr_discard_only_page_on_level(
-/*===========================*/
- dict_index_t* index, /* in: index tree */
- page_t* page, /* in: page which is the only on its level */
- mtr_t* mtr) /* in: mtr */
-{
- rec_t* node_ptr;
- page_t* father_page;
- ulint page_level;
-
- ut_ad(btr_page_get_prev(page, mtr) == FIL_NULL);
- ut_ad(btr_page_get_next(page, mtr) == FIL_NULL);
- ut_ad(mtr_memo_contains(mtr, buf_block_align(page),
- MTR_MEMO_PAGE_X_FIX));
- btr_search_drop_page_hash_index(page);
-
- node_ptr = btr_page_get_father_node_ptr(index, page, mtr);
- father_page = buf_frame_align(node_ptr);
-
- page_level = btr_page_get_level(page, mtr);
-
- lock_update_discard(page_get_supremum_rec(father_page), page);
-
- btr_page_set_level(father_page, page_level, mtr);
-
- /* Free the file page */
- btr_page_free(index, page, mtr);
-
- if (buf_frame_get_page_no(father_page) == dict_index_get_page(index)) {
- /* The father is the root page */
-
- btr_page_empty(father_page, mtr);
-
- /* We play safe and reset the free bits for the father */
- ibuf_reset_free_bits(index, father_page);
- } else {
- ut_ad(page_get_n_recs(father_page) == 1);
-
- btr_discard_only_page_on_level(index, father_page, mtr);
- }
-}
-
-/*****************************************************************
-Discards a page from a B-tree. This is used to remove the last record from
-a B-tree page: the whole page must be removed at the same time. This cannot
-be used for the root page, which is allowed to be empty. */
-
-void
-btr_discard_page(
-/*=============*/
- btr_cur_t* cursor, /* in: cursor on the page to discard: not on
- the root page */
- mtr_t* mtr) /* in: mtr */
-{
- dict_index_t* index;
- ulint space;
- ulint left_page_no;
- ulint right_page_no;
- page_t* merge_page;
- page_t* page;
- rec_t* node_ptr;
-
- page = btr_cur_get_page(cursor);
- index = btr_cur_get_index(cursor);
-
- ut_ad(dict_index_get_page(index) != buf_frame_get_page_no(page));
- ut_ad(mtr_memo_contains(mtr, dict_index_get_lock(index),
- MTR_MEMO_X_LOCK));
- ut_ad(mtr_memo_contains(mtr, buf_block_align(page),
- MTR_MEMO_PAGE_X_FIX));
- space = dict_index_get_space(index);
-
- /* Decide the page which will inherit the locks */
-
- left_page_no = btr_page_get_prev(page, mtr);
- right_page_no = btr_page_get_next(page, mtr);
-
- if (left_page_no != FIL_NULL) {
- merge_page = btr_page_get(space, left_page_no, RW_X_LATCH,
- mtr);
-#ifdef UNIV_BTR_DEBUG
- ut_a(btr_page_get_next(merge_page, mtr)
- == buf_frame_get_page_no(page));
-#endif /* UNIV_BTR_DEBUG */
- } else if (right_page_no != FIL_NULL) {
- merge_page = btr_page_get(space, right_page_no, RW_X_LATCH,
- mtr);
-#ifdef UNIV_BTR_DEBUG
- ut_a(btr_page_get_prev(merge_page, mtr)
- == buf_frame_get_page_no(page));
-#endif /* UNIV_BTR_DEBUG */
- } else {
- btr_discard_only_page_on_level(index, page, mtr);
-
- return;
- }
-
- ut_a(page_is_comp(merge_page) == page_is_comp(page));
- btr_search_drop_page_hash_index(page);
-
- if (left_page_no == FIL_NULL && btr_page_get_level(page, mtr) > 0) {
-
- /* We have to mark the leftmost node pointer on the right
- side page as the predefined minimum record */
-
- node_ptr = page_rec_get_next(page_get_infimum_rec(merge_page));
-
- ut_ad(page_rec_is_user_rec(node_ptr));
-
- btr_set_min_rec_mark(node_ptr, page_is_comp(merge_page), mtr);
- }
-
- btr_node_ptr_delete(index, page, mtr);
-
- /* Remove the page from the level list */
- btr_level_list_remove(page, mtr);
-
- if (left_page_no != FIL_NULL) {
- lock_update_discard(page_get_supremum_rec(merge_page), page);
- } else {
- lock_update_discard(page_rec_get_next(
- page_get_infimum_rec(merge_page)),
- page);
- }
-
- /* Free the file page */
- btr_page_free(index, page, mtr);
-
- ut_ad(btr_check_node_ptr(index, merge_page, mtr));
-}
-
-#ifdef UNIV_BTR_PRINT
-/*****************************************************************
-Prints size info of a B-tree. */
-
-void
-btr_print_size(
-/*===========*/
- dict_index_t* index) /* in: index tree */
-{
- page_t* root;
- fseg_header_t* seg;
- mtr_t mtr;
-
- if (index->type & DICT_IBUF) {
- fputs("Sorry, cannot print info of an ibuf tree:"
- " use ibuf functions\n", stderr);
-
- return;
- }
-
- mtr_start(&mtr);
-
- root = btr_root_get(index, &mtr);
-
- seg = root + PAGE_HEADER + PAGE_BTR_SEG_TOP;
-
- fputs("INFO OF THE NON-LEAF PAGE SEGMENT\n", stderr);
- fseg_print(seg, &mtr);
-
- if (!(index->type & DICT_UNIVERSAL)) {
-
- seg = root + PAGE_HEADER + PAGE_BTR_SEG_LEAF;
-
- fputs("INFO OF THE LEAF PAGE SEGMENT\n", stderr);
- fseg_print(seg, &mtr);
- }
-
- mtr_commit(&mtr);
-}
-
-/****************************************************************
-Prints recursively index tree pages. */
-static
-void
-btr_print_recursive(
-/*================*/
- dict_index_t* index, /* in: index tree */
- page_t* page, /* in: index page */
- ulint width, /* in: print this many entries from start
- and end */
- mem_heap_t** heap, /* in/out: heap for rec_get_offsets() */
- ulint** offsets,/* in/out: buffer for rec_get_offsets() */
- mtr_t* mtr) /* in: mtr */
-{
- page_cur_t cursor;
- ulint n_recs;
- ulint i = 0;
- mtr_t mtr2;
- rec_t* node_ptr;
- page_t* child;
-
- ut_ad(mtr_memo_contains(mtr, buf_block_align(page),
- MTR_MEMO_PAGE_X_FIX));
- fprintf(stderr, "NODE ON LEVEL %lu page number %lu\n",
- (ulong) btr_page_get_level(page, mtr),
- (ulong) buf_frame_get_page_no(page));
-
- page_print(page, index, width, width);
-
- n_recs = page_get_n_recs(page);
-
- page_cur_set_before_first(page, &cursor);
- page_cur_move_to_next(&cursor);
-
- while (!page_cur_is_after_last(&cursor)) {
-
- if (0 == btr_page_get_level(page, mtr)) {
-
- /* If this is the leaf level, do nothing */
-
- } else if ((i <= width) || (i >= n_recs - width)) {
-
- mtr_start(&mtr2);
-
- node_ptr = page_cur_get_rec(&cursor);
-
- *offsets = rec_get_offsets(node_ptr, index, *offsets,
- ULINT_UNDEFINED, heap);
- child = btr_node_ptr_get_child(node_ptr,
- *offsets, &mtr2);
- btr_print_recursive(index, child, width,
- heap, offsets, &mtr2);
- mtr_commit(&mtr2);
- }
-
- page_cur_move_to_next(&cursor);
- i++;
- }
-}
-
-/******************************************************************
-Prints directories and other info of all nodes in the tree. */
-
-void
-btr_print_index(
-/*============*/
- dict_index_t* index, /* in: index */
- ulint width) /* in: print this many entries from start
- and end */
-{
- mtr_t mtr;
- page_t* root;
- mem_heap_t* heap = NULL;
- ulint offsets_[REC_OFFS_NORMAL_SIZE];
- ulint* offsets = offsets_;
- *offsets_ = (sizeof offsets_) / sizeof *offsets_;
-
- fputs("--------------------------\n"
- "INDEX TREE PRINT\n", stderr);
-
- mtr_start(&mtr);
-
- root = btr_root_get(index, &mtr);
-
- btr_print_recursive(index, root, width, &heap, &offsets, &mtr);
- if (UNIV_LIKELY_NULL(heap)) {
- mem_heap_free(heap);
- }
-
- mtr_commit(&mtr);
-
- btr_validate_index(index, NULL);
-}
-#endif /* UNIV_BTR_PRINT */
-
-#ifdef UNIV_DEBUG
-/****************************************************************
-Checks that the node pointer to a page is appropriate. */
-
-ibool
-btr_check_node_ptr(
-/*===============*/
- /* out: TRUE */
- dict_index_t* index, /* in: index tree */
- page_t* page, /* in: index page */
- mtr_t* mtr) /* in: mtr */
-{
- mem_heap_t* heap;
- rec_t* node_ptr;
- dtuple_t* node_ptr_tuple;
-
- ut_ad(mtr_memo_contains(mtr, buf_block_align(page),
- MTR_MEMO_PAGE_X_FIX));
- if (dict_index_get_page(index) == buf_frame_get_page_no(page)) {
-
- return(TRUE);
- }
-
- node_ptr = btr_page_get_father_node_ptr(index, page, mtr);
-
- if (btr_page_get_level(page, mtr) == 0) {
-
- return(TRUE);
- }
-
- heap = mem_heap_create(256);
-
- node_ptr_tuple = dict_index_build_node_ptr(
- index, page_rec_get_next(page_get_infimum_rec(page)), 0, heap,
- btr_page_get_level(page, mtr));
-
- ut_a(!cmp_dtuple_rec(node_ptr_tuple, node_ptr,
- rec_get_offsets(node_ptr, index,
- NULL, ULINT_UNDEFINED, &heap)));
-
- mem_heap_free(heap);
-
- return(TRUE);
-}
-#endif /* UNIV_DEBUG */
-
-/****************************************************************
-Display identification information for a record. */
-static
-void
-btr_index_rec_validate_report(
-/*==========================*/
- page_t* page, /* in: index page */
- rec_t* rec, /* in: index record */
- dict_index_t* index) /* in: index */
-{
- fputs("InnoDB: Record in ", stderr);
- dict_index_name_print(stderr, NULL, index);
- fprintf(stderr, ", page %lu, at offset %lu\n",
- buf_frame_get_page_no(page), (ulint)(rec - page));
-}
-
-/****************************************************************
-Checks the size and number of fields in a record based on the definition of
-the index. */
-
-ibool
-btr_index_rec_validate(
-/*===================*/
- /* out: TRUE if ok */
- rec_t* rec, /* in: index record */
- dict_index_t* index, /* in: index */
- ibool dump_on_error) /* in: TRUE if the function
- should print hex dump of record
- and page on error */
-{
- ulint len;
- ulint n;
- ulint i;
- page_t* page;
- mem_heap_t* heap = NULL;
- ulint offsets_[REC_OFFS_NORMAL_SIZE];
- ulint* offsets = offsets_;
- *offsets_ = (sizeof offsets_) / sizeof *offsets_;
-
- page = buf_frame_align(rec);
-
- if (UNIV_UNLIKELY(index->type & DICT_UNIVERSAL)) {
- /* The insert buffer index tree can contain records from any
- other index: we cannot check the number of fields or
- their length */
-
- return(TRUE);
- }
-
- if (UNIV_UNLIKELY((ibool)!!page_is_comp(page)
- != dict_table_is_comp(index->table))) {
- btr_index_rec_validate_report(page, rec, index);
- fprintf(stderr, "InnoDB: compact flag=%lu, should be %lu\n",
- (ulong) !!page_is_comp(page),
- (ulong) dict_table_is_comp(index->table));
-
- return(FALSE);
- }
-
- n = dict_index_get_n_fields(index);
-
- if (!page_is_comp(page)
- && UNIV_UNLIKELY(rec_get_n_fields_old(rec) != n)) {
- btr_index_rec_validate_report(page, rec, index);
- fprintf(stderr, "InnoDB: has %lu fields, should have %lu\n",
- (ulong) rec_get_n_fields_old(rec), (ulong) n);
-
- if (dump_on_error) {
- buf_page_print(page);
-
- fputs("InnoDB: corrupt record ", stderr);
- rec_print_old(stderr, rec);
- putc('\n', stderr);
- }
- return(FALSE);
- }
-
- offsets = rec_get_offsets(rec, index, offsets, ULINT_UNDEFINED, &heap);
-
- for (i = 0; i < n; i++) {
- ulint fixed_size = dict_col_get_fixed_size(
- dict_index_get_nth_col(index, i));
-
- rec_get_nth_field(rec, offsets, i, &len);
-
- /* Note that if fixed_size != 0, it equals the
- length of a fixed-size column in the clustered index.
- A prefix index of the column is of fixed, but different
- length. When fixed_size == 0, prefix_len is the maximum
- length of the prefix index column. */
-
- if ((dict_index_get_nth_field(index, i)->prefix_len == 0
- && len != UNIV_SQL_NULL && fixed_size
- && len != fixed_size)
- || (dict_index_get_nth_field(index, i)->prefix_len > 0
- && len != UNIV_SQL_NULL
- && len
- > dict_index_get_nth_field(index, i)->prefix_len)) {
-
- btr_index_rec_validate_report(page, rec, index);
- fprintf(stderr,
- "InnoDB: field %lu len is %lu,"
- " should be %lu\n",
- (ulong) i, (ulong) len, (ulong) fixed_size);
-
- if (dump_on_error) {
- buf_page_print(page);
-
- fputs("InnoDB: corrupt record ", stderr);
- rec_print_new(stderr, rec, offsets);
- putc('\n', stderr);
- }
- if (UNIV_LIKELY_NULL(heap)) {
- mem_heap_free(heap);
- }
- return(FALSE);
- }
- }
-
- if (UNIV_LIKELY_NULL(heap)) {
- mem_heap_free(heap);
- }
- return(TRUE);
-}
-
-/****************************************************************
-Checks the size and number of fields in records based on the definition of
-the index. */
-static
-ibool
-btr_index_page_validate(
-/*====================*/
- /* out: TRUE if ok */
- page_t* page, /* in: index page */
- dict_index_t* index) /* in: index */
-{
- page_cur_t cur;
- ibool ret = TRUE;
-
- page_cur_set_before_first(page, &cur);
- page_cur_move_to_next(&cur);
-
- for (;;) {
- if (page_cur_is_after_last(&cur)) {
-
- break;
- }
-
- if (!btr_index_rec_validate(cur.rec, index, TRUE)) {
-
- return(FALSE);
- }
-
- page_cur_move_to_next(&cur);
- }
-
- return(ret);
-}
-
-/****************************************************************
-Report an error on one page of an index tree. */
-static
-void
-btr_validate_report1(
-/*=================*/
- /* out: TRUE if ok */
- dict_index_t* index, /* in: index */
- ulint level, /* in: B-tree level */
- page_t* page) /* in: index page */
-{
- fprintf(stderr, "InnoDB: Error in page %lu of ",
- buf_frame_get_page_no(page));
- dict_index_name_print(stderr, NULL, index);
- if (level) {
- fprintf(stderr, ", index tree level %lu", level);
- }
- putc('\n', stderr);
-}
-
-/****************************************************************
-Report an error on two pages of an index tree. */
-static
-void
-btr_validate_report2(
-/*=================*/
- /* out: TRUE if ok */
- dict_index_t* index, /* in: index */
- ulint level, /* in: B-tree level */
- page_t* page1, /* in: first index page */
- page_t* page2) /* in: second index page */
-{
- fprintf(stderr, "InnoDB: Error in pages %lu and %lu of ",
- buf_frame_get_page_no(page1),
- buf_frame_get_page_no(page2));
- dict_index_name_print(stderr, NULL, index);
- if (level) {
- fprintf(stderr, ", index tree level %lu", level);
- }
- putc('\n', stderr);
-}
-
-/****************************************************************
-Validates index tree level. */
-static
-ibool
-btr_validate_level(
-/*===============*/
- /* out: TRUE if ok */
- dict_index_t* index, /* in: index tree */
- trx_t* trx, /* in: transaction or NULL */
- ulint level) /* in: level number */
-{
- ulint space;
- page_t* page;
- page_t* right_page = 0; /* remove warning */
- page_t* father_page;
- page_t* right_father_page;
- rec_t* node_ptr;
- rec_t* right_node_ptr;
- rec_t* rec;
- ulint right_page_no;
- ulint left_page_no;
- page_cur_t cursor;
- dtuple_t* node_ptr_tuple;
- ibool ret = TRUE;
- mtr_t mtr;
- mem_heap_t* heap = mem_heap_create(256);
- ulint* offsets = NULL;
- ulint* offsets2= NULL;
-
- mtr_start(&mtr);
-
- mtr_x_lock(dict_index_get_lock(index), &mtr);
-
- page = btr_root_get(index, &mtr);
-
- space = buf_frame_get_space_id(page);
-
- while (level != btr_page_get_level(page, &mtr)) {
-
- ut_a(btr_page_get_level(page, &mtr) > 0);
-
- page_cur_set_before_first(page, &cursor);
- page_cur_move_to_next(&cursor);
-
- node_ptr = page_cur_get_rec(&cursor);
- offsets = rec_get_offsets(node_ptr, index, offsets,
- ULINT_UNDEFINED, &heap);
- page = btr_node_ptr_get_child(node_ptr, offsets, &mtr);
- }
-
- /* Now we are on the desired level. Loop through the pages on that
- level. */
-loop:
- if (trx_is_interrupted(trx)) {
- mtr_commit(&mtr);
- mem_heap_free(heap);
- return(ret);
- }
- mem_heap_empty(heap);
- offsets = offsets2 = NULL;
- mtr_x_lock(dict_index_get_lock(index), &mtr);
-
- /* Check ordering etc. of records */
-
- if (!page_validate(page, index)) {
- btr_validate_report1(index, level, page);
-
- ret = FALSE;
- } else if (level == 0) {
- /* We are on level 0. Check that the records have the right
- number of fields, and field lengths are right. */
-
- if (!btr_index_page_validate(page, index)) {
-
- ret = FALSE;
- }
- }
-
- ut_a(btr_page_get_level(page, &mtr) == level);
-
- right_page_no = btr_page_get_next(page, &mtr);
- left_page_no = btr_page_get_prev(page, &mtr);
-
- ut_a((page_get_n_recs(page) > 0)
- || ((level == 0)
- && (buf_frame_get_page_no(page)
- == dict_index_get_page(index))));
-
- if (right_page_no != FIL_NULL) {
- rec_t* right_rec;
- right_page = btr_page_get(space, right_page_no, RW_X_LATCH,
- &mtr);
- if (UNIV_UNLIKELY(btr_page_get_prev(right_page, &mtr)
- != buf_frame_get_page_no(page))) {
- btr_validate_report2(index, level, page, right_page);
- fputs("InnoDB: broken FIL_PAGE_NEXT"
- " or FIL_PAGE_PREV links\n", stderr);
- buf_page_print(page);
- buf_page_print(right_page);
-
- ret = FALSE;
- }
-
- if (UNIV_UNLIKELY(page_is_comp(right_page)
- != page_is_comp(page))) {
- btr_validate_report2(index, level, page, right_page);
- fputs("InnoDB: 'compact' flag mismatch\n", stderr);
- buf_page_print(page);
- buf_page_print(right_page);
-
- ret = FALSE;
-
- goto node_ptr_fails;
- }
-
- rec = page_rec_get_prev(page_get_supremum_rec(page));
- right_rec = page_rec_get_next(page_get_infimum_rec(
- right_page));
- offsets = rec_get_offsets(rec, index,
- offsets, ULINT_UNDEFINED, &heap);
- offsets2 = rec_get_offsets(right_rec, index,
- offsets2, ULINT_UNDEFINED, &heap);
- if (UNIV_UNLIKELY(cmp_rec_rec(rec, right_rec,
- offsets, offsets2,
- index) >= 0)) {
-
- btr_validate_report2(index, level, page, right_page);
-
- fputs("InnoDB: records in wrong order"
- " on adjacent pages\n", stderr);
-
- buf_page_print(page);
- buf_page_print(right_page);
-
- fputs("InnoDB: record ", stderr);
- rec = page_rec_get_prev(page_get_supremum_rec(page));
- rec_print(stderr, rec, index);
- putc('\n', stderr);
- fputs("InnoDB: record ", stderr);
- rec = page_rec_get_next(
- page_get_infimum_rec(right_page));
- rec_print(stderr, rec, index);
- putc('\n', stderr);
-
- ret = FALSE;
- }
- }
-
- if (level > 0 && left_page_no == FIL_NULL) {
- ut_a(REC_INFO_MIN_REC_FLAG & rec_get_info_bits(
- page_rec_get_next(page_get_infimum_rec(page)),
- page_is_comp(page)));
- }
-
- if (buf_frame_get_page_no(page) != dict_index_get_page(index)) {
-
- /* Check father node pointers */
-
- node_ptr = btr_page_get_father_node_ptr(index, page, &mtr);
- father_page = buf_frame_align(node_ptr);
- offsets = rec_get_offsets(node_ptr, index,
- offsets, ULINT_UNDEFINED, &heap);
-
- if (btr_node_ptr_get_child_page_no(node_ptr, offsets)
- != buf_frame_get_page_no(page)
- || node_ptr != btr_page_get_father_for_rec(
- index, page,
- page_rec_get_prev(page_get_supremum_rec(page)),
- &mtr)) {
- btr_validate_report1(index, level, page);
-
- fputs("InnoDB: node pointer to the page is wrong\n",
- stderr);
-
- buf_page_print(father_page);
- buf_page_print(page);
-
- fputs("InnoDB: node ptr ", stderr);
- rec_print_new(stderr, node_ptr, offsets);
-
- fprintf(stderr, "\n"
- "InnoDB: node ptr child page n:o %lu\n",
- (unsigned long) btr_node_ptr_get_child_page_no
- (node_ptr, offsets));
-
- fputs("InnoDB: record on page ", stderr);
- rec = btr_page_get_father_for_rec(
- index, page,
- page_rec_get_prev(page_get_supremum_rec(page)),
- &mtr);
- rec_print(stderr, rec, index);
- putc('\n', stderr);
- ret = FALSE;
-
- goto node_ptr_fails;
- }
-
- if (btr_page_get_level(page, &mtr) > 0) {
- offsets = rec_get_offsets(node_ptr, index,
- offsets, ULINT_UNDEFINED,
- &heap);
-
- node_ptr_tuple = dict_index_build_node_ptr(
- index,
- page_rec_get_next(page_get_infimum_rec(page)),
- 0, heap, btr_page_get_level(page, &mtr));
-
- if (cmp_dtuple_rec(node_ptr_tuple, node_ptr,
- offsets)) {
- rec_t* first_rec = page_rec_get_next(
- page_get_infimum_rec(page));
-
- btr_validate_report1(index, level, page);
-
- buf_page_print(father_page);
- buf_page_print(page);
-
- fputs("InnoDB: Error: node ptrs differ"
- " on levels > 0\n"
- "InnoDB: node ptr ", stderr);
- rec_print_new(stderr, node_ptr, offsets);
- fputs("InnoDB: first rec ", stderr);
- rec_print(stderr, first_rec, index);
- putc('\n', stderr);
- ret = FALSE;
-
- goto node_ptr_fails;
- }
- }
-
- if (left_page_no == FIL_NULL) {
- ut_a(node_ptr == page_rec_get_next(
- page_get_infimum_rec(father_page)));
- ut_a(btr_page_get_prev(father_page, &mtr) == FIL_NULL);
- }
-
- if (right_page_no == FIL_NULL) {
- ut_a(node_ptr == page_rec_get_prev(
- page_get_supremum_rec(father_page)));
- ut_a(btr_page_get_next(father_page, &mtr) == FIL_NULL);
- } else {
- right_node_ptr = btr_page_get_father_node_ptr(
- index, right_page, &mtr);
- if (page_rec_get_next(node_ptr)
- != page_get_supremum_rec(father_page)) {
-
- if (right_node_ptr
- != page_rec_get_next(node_ptr)) {
- ret = FALSE;
- fputs("InnoDB: node pointer to"
- " the right page is wrong\n",
- stderr);
-
- btr_validate_report1(index, level,
- page);
-
- buf_page_print(father_page);
- buf_page_print(page);
- buf_page_print(right_page);
- }
- } else {
- right_father_page = buf_frame_align(
- right_node_ptr);
-
- if (right_node_ptr != page_rec_get_next(
- page_get_infimum_rec(
- right_father_page))) {
- ret = FALSE;
- fputs("InnoDB: node pointer 2 to"
- " the right page is wrong\n",
- stderr);
-
- btr_validate_report1(index, level,
- page);
-
- buf_page_print(father_page);
- buf_page_print(right_father_page);
- buf_page_print(page);
- buf_page_print(right_page);
- }
-
- if (buf_frame_get_page_no(right_father_page)
- != btr_page_get_next(father_page, &mtr)) {
-
- ret = FALSE;
- fputs("InnoDB: node pointer 3 to"
- " the right page is wrong\n",
- stderr);
-
- btr_validate_report1(index, level,
- page);
-
- buf_page_print(father_page);
- buf_page_print(right_father_page);
- buf_page_print(page);
- buf_page_print(right_page);
- }
- }
- }
- }
-
-node_ptr_fails:
- /* Commit the mini-transaction to release the latch on 'page'.
- Re-acquire the latch on right_page, which will become 'page'
- on the next loop. The page has already been checked. */
- mtr_commit(&mtr);
-
- if (right_page_no != FIL_NULL) {
- mtr_start(&mtr);
-
- page = btr_page_get(space, right_page_no, RW_X_LATCH, &mtr);
-
- goto loop;
- }
-
- mem_heap_free(heap);
- return(ret);
-}
-
-/******************************************************************
-Checks the consistency of an index tree. */
-
-ibool
-btr_validate_index(
-/*===============*/
- /* out: TRUE if ok */
- dict_index_t* index, /* in: index */
- trx_t* trx) /* in: transaction or NULL */
-{
- mtr_t mtr;
- page_t* root;
- ulint i;
- ulint n;
-
- mtr_start(&mtr);
- mtr_x_lock(dict_index_get_lock(index), &mtr);
-
- root = btr_root_get(index, &mtr);
- n = btr_page_get_level(root, &mtr);
-
- for (i = 0; i <= n && !trx_is_interrupted(trx); i++) {
- if (!btr_validate_level(index, trx, n - i)) {
-
- mtr_commit(&mtr);
-
- return(FALSE);
- }
- }
-
- mtr_commit(&mtr);
-
- return(TRUE);
-}
diff --git a/storage/innobase/btr/btr0cur.c b/storage/innobase/btr/btr0cur.c
deleted file mode 100644
index a2f62255dd6..00000000000
--- a/storage/innobase/btr/btr0cur.c
+++ /dev/null
@@ -1,3848 +0,0 @@
-/******************************************************
-The index tree cursor
-
-All changes that row operations make to a B-tree or the records
-there must go through this module! Undo log records are written here
-of every modify or insert of a clustered index record.
-
- NOTE!!!
-To make sure we do not run out of disk space during a pessimistic
-insert or update, we have to reserve 2 x the height of the index tree
-many pages in the tablespace before we start the operation, because
-if leaf splitting has been started, it is difficult to undo, except
-by crashing the database and doing a roll-forward.
-
-(c) 1994-2001 Innobase Oy
-
-Created 10/16/1994 Heikki Tuuri
-*******************************************************/
-
-#include "btr0cur.h"
-
-#ifdef UNIV_NONINL
-#include "btr0cur.ic"
-#endif
-
-#include "page0page.h"
-#include "rem0rec.h"
-#include "rem0cmp.h"
-#include "btr0btr.h"
-#include "btr0sea.h"
-#include "row0upd.h"
-#include "trx0rec.h"
-#include "que0que.h"
-#include "row0row.h"
-#include "srv0srv.h"
-#include "ibuf0ibuf.h"
-#include "lock0lock.h"
-
-#ifdef UNIV_DEBUG
-/* If the following is set to TRUE, this module prints a lot of
-trace information of individual record operations */
-ibool btr_cur_print_record_ops = FALSE;
-#endif /* UNIV_DEBUG */
-
-ulint btr_cur_n_non_sea = 0;
-ulint btr_cur_n_sea = 0;
-ulint btr_cur_n_non_sea_old = 0;
-ulint btr_cur_n_sea_old = 0;
-
-/* In the optimistic insert, if the insert does not fit, but this much space
-can be released by page reorganize, then it is reorganized */
-
-#define BTR_CUR_PAGE_REORGANIZE_LIMIT (UNIV_PAGE_SIZE / 32)
-
-/* When estimating number of different key values in an index, sample
-this many index pages */
-#define BTR_KEY_VAL_ESTIMATE_N_PAGES 8
-
-/* The structure of a BLOB part header */
-/*--------------------------------------*/
-#define BTR_BLOB_HDR_PART_LEN 0 /* BLOB part len on this
- page */
-#define BTR_BLOB_HDR_NEXT_PAGE_NO 4 /* next BLOB part page no,
- FIL_NULL if none */
-/*--------------------------------------*/
-#define BTR_BLOB_HDR_SIZE 8
-
-/***********************************************************************
-Marks all extern fields in a record as owned by the record. This function
-should be called if the delete mark of a record is removed: a not delete
-marked record always owns all its extern fields. */
-static
-void
-btr_cur_unmark_extern_fields(
-/*=========================*/
- rec_t* rec, /* in: record in a clustered index */
- mtr_t* mtr, /* in: mtr */
- const ulint* offsets);/* in: array returned by rec_get_offsets() */
-/***********************************************************************
-Adds path information to the cursor for the current page, for which
-the binary search has been performed. */
-static
-void
-btr_cur_add_path_info(
-/*==================*/
- btr_cur_t* cursor, /* in: cursor positioned on a page */
- ulint height, /* in: height of the page in tree;
- 0 means leaf node */
- ulint root_height); /* in: root node height in tree */
-/***************************************************************
-Frees the externally stored fields for a record, if the field is mentioned
-in the update vector. */
-static
-void
-btr_rec_free_updated_extern_fields(
-/*===============================*/
- dict_index_t* index, /* in: index of rec; the index tree MUST be
- X-latched */
- rec_t* rec, /* in: record */
- const ulint* offsets,/* in: rec_get_offsets(rec, index) */
- upd_t* update, /* in: update vector */
- ibool do_not_free_inherited,/* in: TRUE if called in a
- rollback and we do not want to free
- inherited fields */
- mtr_t* mtr); /* in: mini-transaction handle which contains
- an X-latch to record page and to the tree */
-/***************************************************************
-Gets the externally stored size of a record, in units of a database page. */
-static
-ulint
-btr_rec_get_externally_stored_len(
-/*==============================*/
- /* out: externally stored part,
- in units of a database page */
- rec_t* rec, /* in: record */
- const ulint* offsets);/* in: array returned by rec_get_offsets() */
-
-/*==================== B-TREE SEARCH =========================*/
-
-/************************************************************************
-Latches the leaf page or pages requested. */
-static
-void
-btr_cur_latch_leaves(
-/*=================*/
- page_t* page, /* in: leaf page where the search
- converged */
- ulint space, /* in: space id */
- ulint page_no, /* in: page number of the leaf */
- ulint latch_mode, /* in: BTR_SEARCH_LEAF, ... */
- btr_cur_t* cursor, /* in: cursor */
- mtr_t* mtr) /* in: mtr */
-{
- ulint left_page_no;
- ulint right_page_no;
- page_t* get_page;
-
- ut_ad(page && mtr);
-
- if (latch_mode == BTR_SEARCH_LEAF) {
-
- get_page = btr_page_get(space, page_no, RW_S_LATCH, mtr);
- ut_a(page_is_comp(get_page) == page_is_comp(page));
- buf_block_align(get_page)->check_index_page_at_flush = TRUE;
-
- } else if (latch_mode == BTR_MODIFY_LEAF) {
-
- get_page = btr_page_get(space, page_no, RW_X_LATCH, mtr);
- ut_a(page_is_comp(get_page) == page_is_comp(page));
- buf_block_align(get_page)->check_index_page_at_flush = TRUE;
-
- } else if (latch_mode == BTR_MODIFY_TREE) {
-
- /* x-latch also brothers from left to right */
- left_page_no = btr_page_get_prev(page, mtr);
-
- if (left_page_no != FIL_NULL) {
- get_page = btr_page_get(space, left_page_no,
- RW_X_LATCH, mtr);
-#ifdef UNIV_BTR_DEBUG
- ut_a(btr_page_get_next(get_page, mtr)
- == buf_frame_get_page_no(page));
-#endif /* UNIV_BTR_DEBUG */
- ut_a(page_is_comp(get_page) == page_is_comp(page));
- buf_block_align(get_page)->check_index_page_at_flush
- = TRUE;
- }
-
- get_page = btr_page_get(space, page_no, RW_X_LATCH, mtr);
- ut_a(page_is_comp(get_page) == page_is_comp(page));
- buf_block_align(get_page)->check_index_page_at_flush = TRUE;
-
- right_page_no = btr_page_get_next(page, mtr);
-
- if (right_page_no != FIL_NULL) {
- get_page = btr_page_get(space, right_page_no,
- RW_X_LATCH, mtr);
-#ifdef UNIV_BTR_DEBUG
- ut_a(btr_page_get_prev(get_page, mtr)
- == buf_frame_get_page_no(page));
-#endif /* UNIV_BTR_DEBUG */
- buf_block_align(get_page)->check_index_page_at_flush
- = TRUE;
- }
-
- } else if (latch_mode == BTR_SEARCH_PREV) {
-
- /* s-latch also left brother */
- left_page_no = btr_page_get_prev(page, mtr);
-
- if (left_page_no != FIL_NULL) {
- cursor->left_page = btr_page_get(space, left_page_no,
- RW_S_LATCH, mtr);
-#ifdef UNIV_BTR_DEBUG
- ut_a(btr_page_get_next(cursor->left_page, mtr)
- == buf_frame_get_page_no(page));
-#endif /* UNIV_BTR_DEBUG */
- ut_a(page_is_comp(cursor->left_page)
- == page_is_comp(page));
- buf_block_align(cursor->left_page)
- ->check_index_page_at_flush = TRUE;
- }
-
- get_page = btr_page_get(space, page_no, RW_S_LATCH, mtr);
- ut_a(page_is_comp(get_page) == page_is_comp(page));
- buf_block_align(get_page)->check_index_page_at_flush = TRUE;
-
- } else if (latch_mode == BTR_MODIFY_PREV) {
-
- /* x-latch also left brother */
- left_page_no = btr_page_get_prev(page, mtr);
-
- if (left_page_no != FIL_NULL) {
- cursor->left_page = btr_page_get(space, left_page_no,
- RW_X_LATCH, mtr);
-#ifdef UNIV_BTR_DEBUG
- ut_a(btr_page_get_next(cursor->left_page, mtr)
- == buf_frame_get_page_no(page));
-#endif /* UNIV_BTR_DEBUG */
- ut_a(page_is_comp(cursor->left_page)
- == page_is_comp(page));
- buf_block_align(cursor->left_page)
- ->check_index_page_at_flush = TRUE;
- }
-
- get_page = btr_page_get(space, page_no, RW_X_LATCH, mtr);
- ut_a(page_is_comp(get_page) == page_is_comp(page));
- buf_block_align(get_page)->check_index_page_at_flush = TRUE;
- } else {
- ut_error;
- }
-}
-
-/************************************************************************
-Searches an index tree and positions a tree cursor on a given level.
-NOTE: n_fields_cmp in tuple must be set so that it cannot be compared
-to node pointer page number fields on the upper levels of the tree!
-Note that if mode is PAGE_CUR_LE, which is used in inserts, then
-cursor->up_match and cursor->low_match both will have sensible values.
-If mode is PAGE_CUR_GE, then up_match will a have a sensible value.
-
-If mode is PAGE_CUR_LE , cursor is left at the place where an insert of the
-search tuple should be performed in the B-tree. InnoDB does an insert
-immediately after the cursor. Thus, the cursor may end up on a user record,
-or on a page infimum record. */
-
-void
-btr_cur_search_to_nth_level(
-/*========================*/
- dict_index_t* index, /* in: index */
- ulint level, /* in: the tree level of search */
- dtuple_t* tuple, /* in: data tuple; NOTE: n_fields_cmp in
- tuple must be set so that it cannot get
- compared to the node ptr page number field! */
- ulint mode, /* in: PAGE_CUR_L, ...;
- Inserts should always be made using
- PAGE_CUR_LE to search the position! */
- ulint latch_mode, /* in: BTR_SEARCH_LEAF, ..., ORed with
- BTR_INSERT and BTR_ESTIMATE;
- cursor->left_page is used to store a pointer
- to the left neighbor page, in the cases
- BTR_SEARCH_PREV and BTR_MODIFY_PREV;
- NOTE that if has_search_latch
- is != 0, we maybe do not have a latch set
- on the cursor page, we assume
- the caller uses his search latch
- to protect the record! */
- btr_cur_t* cursor, /* in/out: tree cursor; the cursor page is
- s- or x-latched, but see also above! */
- ulint has_search_latch,/* in: info on the latch mode the
- caller currently has on btr_search_latch:
- RW_S_LATCH, or 0 */
- mtr_t* mtr) /* in: mtr */
-{
- page_cur_t* page_cursor;
- page_t* page;
- page_t* guess;
- rec_t* node_ptr;
- ulint page_no;
- ulint space;
- ulint up_match;
- ulint up_bytes;
- ulint low_match;
- ulint low_bytes;
- ulint height;
- ulint savepoint;
- ulint rw_latch;
- ulint page_mode;
- ulint insert_planned;
- ulint buf_mode;
- ulint estimate;
- ulint ignore_sec_unique;
- ulint root_height = 0; /* remove warning */
-#ifdef BTR_CUR_ADAPT
- btr_search_t* info;
-#endif
- mem_heap_t* heap = NULL;
- ulint offsets_[REC_OFFS_NORMAL_SIZE];
- ulint* offsets = offsets_;
- *offsets_ = (sizeof offsets_) / sizeof *offsets_;
- /* Currently, PAGE_CUR_LE is the only search mode used for searches
- ending to upper levels */
-
- ut_ad(level == 0 || mode == PAGE_CUR_LE);
- ut_ad(dict_index_check_search_tuple(index, tuple));
- ut_ad(!(index->type & DICT_IBUF) || ibuf_inside());
- ut_ad(dtuple_check_typed(tuple));
-
-#ifdef UNIV_DEBUG
- cursor->up_match = ULINT_UNDEFINED;
- cursor->low_match = ULINT_UNDEFINED;
-#endif
- insert_planned = latch_mode & BTR_INSERT;
- estimate = latch_mode & BTR_ESTIMATE;
- ignore_sec_unique = latch_mode & BTR_IGNORE_SEC_UNIQUE;
- latch_mode = latch_mode & ~(BTR_INSERT | BTR_ESTIMATE
- | BTR_IGNORE_SEC_UNIQUE);
-
- ut_ad(!insert_planned || (mode == PAGE_CUR_LE));
-
- cursor->flag = BTR_CUR_BINARY;
- cursor->index = index;
-
-#ifndef BTR_CUR_ADAPT
- guess = NULL;
-#else
- info = btr_search_get_info(index);
-
- guess = info->root_guess;
-
-#ifdef BTR_CUR_HASH_ADAPT
-
-#ifdef UNIV_SEARCH_PERF_STAT
- info->n_searches++;
-#endif
- if (rw_lock_get_writer(&btr_search_latch) == RW_LOCK_NOT_LOCKED
- && latch_mode <= BTR_MODIFY_LEAF && info->last_hash_succ
- && !estimate
-#ifdef PAGE_CUR_LE_OR_EXTENDS
- && mode != PAGE_CUR_LE_OR_EXTENDS
-#endif /* PAGE_CUR_LE_OR_EXTENDS */
- && srv_use_adaptive_hash_indexes
- && btr_search_guess_on_hash(index, info, tuple, mode,
- latch_mode, cursor,
- has_search_latch, mtr)) {
-
- /* Search using the hash index succeeded */
-
- ut_ad(cursor->up_match != ULINT_UNDEFINED
- || mode != PAGE_CUR_GE);
- ut_ad(cursor->up_match != ULINT_UNDEFINED
- || mode != PAGE_CUR_LE);
- ut_ad(cursor->low_match != ULINT_UNDEFINED
- || mode != PAGE_CUR_LE);
- btr_cur_n_sea++;
-
- return;
- }
-#endif
-#endif
- btr_cur_n_non_sea++;
-
- /* If the hash search did not succeed, do binary search down the
- tree */
-
- if (has_search_latch) {
- /* Release possible search latch to obey latching order */
- rw_lock_s_unlock(&btr_search_latch);
- }
-
- /* Store the position of the tree latch we push to mtr so that we
- know how to release it when we have latched leaf node(s) */
-
- savepoint = mtr_set_savepoint(mtr);
-
- if (latch_mode == BTR_MODIFY_TREE) {
- mtr_x_lock(dict_index_get_lock(index), mtr);
-
- } else if (latch_mode == BTR_CONT_MODIFY_TREE) {
- /* Do nothing */
- ut_ad(mtr_memo_contains(mtr, dict_index_get_lock(index),
- MTR_MEMO_X_LOCK));
- } else {
- mtr_s_lock(dict_index_get_lock(index), mtr);
- }
-
- page_cursor = btr_cur_get_page_cur(cursor);
-
- space = dict_index_get_space(index);
- page_no = dict_index_get_page(index);
-
- up_match = 0;
- up_bytes = 0;
- low_match = 0;
- low_bytes = 0;
-
- height = ULINT_UNDEFINED;
- rw_latch = RW_NO_LATCH;
- buf_mode = BUF_GET;
-
- /* We use these modified search modes on non-leaf levels of the
- B-tree. These let us end up in the right B-tree leaf. In that leaf
- we use the original search mode. */
-
- switch (mode) {
- case PAGE_CUR_GE:
- page_mode = PAGE_CUR_L;
- break;
- case PAGE_CUR_G:
- page_mode = PAGE_CUR_LE;
- break;
- default:
-#ifdef PAGE_CUR_LE_OR_EXTENDS
- ut_ad(mode == PAGE_CUR_L || mode == PAGE_CUR_LE
- || mode == PAGE_CUR_LE_OR_EXTENDS);
-#else /* PAGE_CUR_LE_OR_EXTENDS */
- ut_ad(mode == PAGE_CUR_L || mode == PAGE_CUR_LE);
-#endif /* PAGE_CUR_LE_OR_EXTENDS */
- page_mode = mode;
- break;
- }
-
- /* Loop and search until we arrive at the desired level */
-
- for (;;) {
- if ((height == 0) && (latch_mode <= BTR_MODIFY_LEAF)) {
-
- rw_latch = latch_mode;
-
- if (insert_planned
- && ibuf_should_try(index, ignore_sec_unique)) {
-
- /* Try insert to the insert buffer if the
- page is not in the buffer pool */
-
- buf_mode = BUF_GET_IF_IN_POOL;
- }
- }
-retry_page_get:
- page = buf_page_get_gen(space, page_no, rw_latch, guess,
- buf_mode,
- __FILE__, __LINE__,
- mtr);
- if (page == NULL) {
- /* This must be a search to perform an insert;
- try insert to the insert buffer */
-
- ut_ad(buf_mode == BUF_GET_IF_IN_POOL);
- ut_ad(insert_planned);
- ut_ad(cursor->thr);
-
- if (ibuf_should_try(index, ignore_sec_unique)
- && ibuf_insert(tuple, index, space, page_no,
- cursor->thr)) {
- /* Insertion to the insert buffer succeeded */
- cursor->flag = BTR_CUR_INSERT_TO_IBUF;
- if (UNIV_LIKELY_NULL(heap)) {
- mem_heap_free(heap);
- }
- goto func_exit;
- }
-
- /* Insert to the insert buffer did not succeed:
- retry page get */
-
- buf_mode = BUF_GET;
-
- goto retry_page_get;
- }
-
- buf_block_align(page)->check_index_page_at_flush = TRUE;
-
-#ifdef UNIV_SYNC_DEBUG
- if (rw_latch != RW_NO_LATCH) {
- buf_page_dbg_add_level(page, SYNC_TREE_NODE);
- }
-#endif
- ut_ad(0 == ut_dulint_cmp(index->id,
- btr_page_get_index_id(page)));
-
- if (height == ULINT_UNDEFINED) {
- /* We are in the root node */
-
- height = btr_page_get_level(page, mtr);
- root_height = height;
- cursor->tree_height = root_height + 1;
-#ifdef BTR_CUR_ADAPT
- if (page != guess) {
- info->root_guess = page;
- }
-#endif
- }
-
- if (height == 0) {
- if (rw_latch == RW_NO_LATCH) {
-
- btr_cur_latch_leaves(page, space,
- page_no, latch_mode,
- cursor, mtr);
- }
-
- if ((latch_mode != BTR_MODIFY_TREE)
- && (latch_mode != BTR_CONT_MODIFY_TREE)) {
-
- /* Release the tree s-latch */
-
- mtr_release_s_latch_at_savepoint(
- mtr, savepoint,
- dict_index_get_lock(index));
- }
-
- page_mode = mode;
- }
-
- page_cur_search_with_match(page, index, tuple, page_mode,
- &up_match, &up_bytes,
- &low_match, &low_bytes,
- page_cursor);
- if (estimate) {
- btr_cur_add_path_info(cursor, height, root_height);
- }
-
- /* If this is the desired level, leave the loop */
-
- ut_ad(height == btr_page_get_level(
- page_cur_get_page(page_cursor), mtr));
-
- if (level == height) {
-
- if (level > 0) {
- /* x-latch the page */
- page = btr_page_get(space,
- page_no, RW_X_LATCH, mtr);
- ut_a((ibool)!!page_is_comp(page)
- == dict_table_is_comp(index->table));
- }
-
- break;
- }
-
- ut_ad(height > 0);
-
- height--;
- guess = NULL;
-
- node_ptr = page_cur_get_rec(page_cursor);
- offsets = rec_get_offsets(node_ptr, cursor->index, offsets,
- ULINT_UNDEFINED, &heap);
- /* Go to the child node */
- page_no = btr_node_ptr_get_child_page_no(node_ptr, offsets);
- }
-
- if (UNIV_LIKELY_NULL(heap)) {
- mem_heap_free(heap);
- }
-
- if (level == 0) {
- cursor->low_match = low_match;
- cursor->low_bytes = low_bytes;
- cursor->up_match = up_match;
- cursor->up_bytes = up_bytes;
-
-#ifdef BTR_CUR_ADAPT
- if (srv_use_adaptive_hash_indexes) {
-
- btr_search_info_update(index, cursor);
- }
-#endif
- ut_ad(cursor->up_match != ULINT_UNDEFINED
- || mode != PAGE_CUR_GE);
- ut_ad(cursor->up_match != ULINT_UNDEFINED
- || mode != PAGE_CUR_LE);
- ut_ad(cursor->low_match != ULINT_UNDEFINED
- || mode != PAGE_CUR_LE);
- }
-
-func_exit:
- if (has_search_latch) {
-
- rw_lock_s_lock(&btr_search_latch);
- }
-}
-
-/*********************************************************************
-Opens a cursor at either end of an index. */
-
-void
-btr_cur_open_at_index_side(
-/*=======================*/
- ibool from_left, /* in: TRUE if open to the low end,
- FALSE if to the high end */
- dict_index_t* index, /* in: index */
- ulint latch_mode, /* in: latch mode */
- btr_cur_t* cursor, /* in: cursor */
- mtr_t* mtr) /* in: mtr */
-{
- page_cur_t* page_cursor;
- page_t* page;
- ulint page_no;
- ulint space;
- ulint height;
- ulint root_height = 0; /* remove warning */
- rec_t* node_ptr;
- ulint estimate;
- ulint savepoint;
- mem_heap_t* heap = NULL;
- ulint offsets_[REC_OFFS_NORMAL_SIZE];
- ulint* offsets = offsets_;
- *offsets_ = (sizeof offsets_) / sizeof *offsets_;
-
- estimate = latch_mode & BTR_ESTIMATE;
- latch_mode = latch_mode & ~BTR_ESTIMATE;
-
- /* Store the position of the tree latch we push to mtr so that we
- know how to release it when we have latched the leaf node */
-
- savepoint = mtr_set_savepoint(mtr);
-
- if (latch_mode == BTR_MODIFY_TREE) {
- mtr_x_lock(dict_index_get_lock(index), mtr);
- } else {
- mtr_s_lock(dict_index_get_lock(index), mtr);
- }
-
- page_cursor = btr_cur_get_page_cur(cursor);
- cursor->index = index;
-
- space = dict_index_get_space(index);
- page_no = dict_index_get_page(index);
-
- height = ULINT_UNDEFINED;
-
- for (;;) {
- page = buf_page_get_gen(space, page_no, RW_NO_LATCH, NULL,
- BUF_GET,
- __FILE__, __LINE__,
- mtr);
- ut_ad(0 == ut_dulint_cmp(index->id,
- btr_page_get_index_id(page)));
-
- buf_block_align(page)->check_index_page_at_flush = TRUE;
-
- if (height == ULINT_UNDEFINED) {
- /* We are in the root node */
-
- height = btr_page_get_level(page, mtr);
- root_height = height;
- }
-
- if (height == 0) {
- btr_cur_latch_leaves(page, space, page_no,
- latch_mode, cursor, mtr);
-
- /* In versions <= 3.23.52 we had forgotten to
- release the tree latch here. If in an index scan
- we had to scan far to find a record visible to the
- current transaction, that could starve others
- waiting for the tree latch. */
-
- if ((latch_mode != BTR_MODIFY_TREE)
- && (latch_mode != BTR_CONT_MODIFY_TREE)) {
-
- /* Release the tree s-latch */
-
- mtr_release_s_latch_at_savepoint(
- mtr, savepoint,
- dict_index_get_lock(index));
- }
- }
-
- if (from_left) {
- page_cur_set_before_first(page, page_cursor);
- } else {
- page_cur_set_after_last(page, page_cursor);
- }
-
- if (height == 0) {
- if (estimate) {
- btr_cur_add_path_info(cursor, height,
- root_height);
- }
-
- break;
- }
-
- ut_ad(height > 0);
-
- if (from_left) {
- page_cur_move_to_next(page_cursor);
- } else {
- page_cur_move_to_prev(page_cursor);
- }
-
- if (estimate) {
- btr_cur_add_path_info(cursor, height, root_height);
- }
-
- height--;
-
- node_ptr = page_cur_get_rec(page_cursor);
- offsets = rec_get_offsets(node_ptr, cursor->index, offsets,
- ULINT_UNDEFINED, &heap);
- /* Go to the child node */
- page_no = btr_node_ptr_get_child_page_no(node_ptr, offsets);
- }
-
- if (UNIV_LIKELY_NULL(heap)) {
- mem_heap_free(heap);
- }
-}
-
-/**************************************************************************
-Positions a cursor at a randomly chosen position within a B-tree. */
-
-void
-btr_cur_open_at_rnd_pos(
-/*====================*/
- dict_index_t* index, /* in: index */
- ulint latch_mode, /* in: BTR_SEARCH_LEAF, ... */
- btr_cur_t* cursor, /* in/out: B-tree cursor */
- mtr_t* mtr) /* in: mtr */
-{
- page_cur_t* page_cursor;
- page_t* page;
- ulint page_no;
- ulint space;
- ulint height;
- rec_t* node_ptr;
- mem_heap_t* heap = NULL;
- ulint offsets_[REC_OFFS_NORMAL_SIZE];
- ulint* offsets = offsets_;
- *offsets_ = (sizeof offsets_) / sizeof *offsets_;
-
- if (latch_mode == BTR_MODIFY_TREE) {
- mtr_x_lock(dict_index_get_lock(index), mtr);
- } else {
- mtr_s_lock(dict_index_get_lock(index), mtr);
- }
-
- page_cursor = btr_cur_get_page_cur(cursor);
- cursor->index = index;
-
- space = dict_index_get_space(index);
- page_no = dict_index_get_page(index);
-
- height = ULINT_UNDEFINED;
-
- for (;;) {
- page = buf_page_get_gen(space, page_no, RW_NO_LATCH, NULL,
- BUF_GET,
- __FILE__, __LINE__,
- mtr);
- ut_ad(0 == ut_dulint_cmp(index->id,
- btr_page_get_index_id(page)));
-
- if (height == ULINT_UNDEFINED) {
- /* We are in the root node */
-
- height = btr_page_get_level(page, mtr);
- }
-
- if (height == 0) {
- btr_cur_latch_leaves(page, space, page_no,
- latch_mode, cursor, mtr);
- }
-
- page_cur_open_on_rnd_user_rec(page, page_cursor);
-
- if (height == 0) {
-
- break;
- }
-
- ut_ad(height > 0);
-
- height--;
-
- node_ptr = page_cur_get_rec(page_cursor);
- offsets = rec_get_offsets(node_ptr, cursor->index, offsets,
- ULINT_UNDEFINED, &heap);
- /* Go to the child node */
- page_no = btr_node_ptr_get_child_page_no(node_ptr, offsets);
- }
-
- if (UNIV_LIKELY_NULL(heap)) {
- mem_heap_free(heap);
- }
-}
-
-/*==================== B-TREE INSERT =========================*/
-
-/*****************************************************************
-Inserts a record if there is enough space, or if enough space can
-be freed by reorganizing. Differs from _optimistic_insert because
-no heuristics is applied to whether it pays to use CPU time for
-reorganizing the page or not. */
-static
-rec_t*
-btr_cur_insert_if_possible(
-/*=======================*/
- /* out: pointer to inserted record if succeed,
- else NULL */
- btr_cur_t* cursor, /* in: cursor on page after which to insert;
- cursor stays valid */
- dtuple_t* tuple, /* in: tuple to insert; the size info need not
- have been stored to tuple */
- ibool* reorg, /* out: TRUE if reorganization occurred */
- mtr_t* mtr) /* in: mtr */
-{
- page_cur_t* page_cursor;
- page_t* page;
- rec_t* rec;
-
- ut_ad(dtuple_check_typed(tuple));
-
- *reorg = FALSE;
-
- page = btr_cur_get_page(cursor);
-
- ut_ad(mtr_memo_contains(mtr, buf_block_align(page),
- MTR_MEMO_PAGE_X_FIX));
- page_cursor = btr_cur_get_page_cur(cursor);
-
- /* Now, try the insert */
- rec = page_cur_tuple_insert(page_cursor, tuple, cursor->index, mtr);
-
- if (!rec) {
- /* If record did not fit, reorganize */
-
- btr_page_reorganize(page, cursor->index, mtr);
-
- *reorg = TRUE;
-
- page_cur_search(page, cursor->index, tuple,
- PAGE_CUR_LE, page_cursor);
-
- rec = page_cur_tuple_insert(page_cursor, tuple,
- cursor->index, mtr);
- }
-
- return(rec);
-}
-
-/*****************************************************************
-For an insert, checks the locks and does the undo logging if desired. */
-UNIV_INLINE
-ulint
-btr_cur_ins_lock_and_undo(
-/*======================*/
- /* out: DB_SUCCESS, DB_WAIT_LOCK,
- DB_FAIL, or error number */
- ulint flags, /* in: undo logging and locking flags: if
- not zero, the parameters index and thr
- should be specified */
- btr_cur_t* cursor, /* in: cursor on page after which to insert */
- dtuple_t* entry, /* in: entry to insert */
- que_thr_t* thr, /* in: query thread or NULL */
- ibool* inherit)/* out: TRUE if the inserted new record maybe
- should inherit LOCK_GAP type locks from the
- successor record */
-{
- dict_index_t* index;
- ulint err;
- rec_t* rec;
- dulint roll_ptr;
-
- /* Check if we have to wait for a lock: enqueue an explicit lock
- request if yes */
-
- rec = btr_cur_get_rec(cursor);
- index = cursor->index;
-
- err = lock_rec_insert_check_and_lock(flags, rec, index, thr, inherit);
-
- if (err != DB_SUCCESS) {
-
- return(err);
- }
-
- if ((index->type & DICT_CLUSTERED) && !(index->type & DICT_IBUF)) {
-
- err = trx_undo_report_row_operation(flags, TRX_UNDO_INSERT_OP,
- thr, index, entry,
- NULL, 0, NULL,
- &roll_ptr);
- if (err != DB_SUCCESS) {
-
- return(err);
- }
-
- /* Now we can fill in the roll ptr field in entry */
-
- if (!(flags & BTR_KEEP_SYS_FLAG)) {
-
- row_upd_index_entry_sys_field(entry, index,
- DATA_ROLL_PTR, roll_ptr);
- }
- }
-
- return(DB_SUCCESS);
-}
-
-#ifdef UNIV_DEBUG
-/*****************************************************************
-Report information about a transaction. */
-static
-void
-btr_cur_trx_report(
-/*===============*/
- trx_t* trx, /* in: transaction */
- const dict_index_t* index, /* in: index */
- const char* op) /* in: operation */
-{
- fprintf(stderr, "Trx with id %lu %lu going to ",
- ut_dulint_get_high(trx->id),
- ut_dulint_get_low(trx->id));
- fputs(op, stderr);
- dict_index_name_print(stderr, trx, index);
- putc('\n', stderr);
-}
-#endif /* UNIV_DEBUG */
-
-/*****************************************************************
-Tries to perform an insert to a page in an index tree, next to cursor.
-It is assumed that mtr holds an x-latch on the page. The operation does
-not succeed if there is too little space on the page. If there is just
-one record on the page, the insert will always succeed; this is to
-prevent trying to split a page with just one record. */
-
-ulint
-btr_cur_optimistic_insert(
-/*======================*/
- /* out: DB_SUCCESS, DB_WAIT_LOCK,
- DB_FAIL, or error number */
- ulint flags, /* in: undo logging and locking flags: if not
- zero, the parameters index and thr should be
- specified */
- btr_cur_t* cursor, /* in: cursor on page after which to insert;
- cursor stays valid */
- dtuple_t* entry, /* in: entry to insert */
- rec_t** rec, /* out: pointer to inserted record if
- succeed */
- big_rec_t** big_rec,/* out: big rec vector whose fields have to
- be stored externally by the caller, or
- NULL */
- que_thr_t* thr, /* in: query thread or NULL */
- mtr_t* mtr) /* in: mtr */
-{
- big_rec_t* big_rec_vec = NULL;
- dict_index_t* index;
- page_cur_t* page_cursor;
- page_t* page;
- ulint max_size;
- rec_t* dummy_rec;
- ulint level;
- ibool reorg;
- ibool inherit;
- ulint rec_size;
- ulint type;
- ulint err;
-
- *big_rec = NULL;
-
- page = btr_cur_get_page(cursor);
- index = cursor->index;
-
- if (!dtuple_check_typed_no_assert(entry)) {
- fputs("InnoDB: Error in a tuple to insert into ", stderr);
- dict_index_name_print(stderr, thr_get_trx(thr), index);
- }
-#ifdef UNIV_DEBUG
- if (btr_cur_print_record_ops && thr) {
- btr_cur_trx_report(thr_get_trx(thr), index, "insert into ");
- dtuple_print(stderr, entry);
- }
-#endif /* UNIV_DEBUG */
-
- ut_ad(mtr_memo_contains(mtr, buf_block_align(page),
- MTR_MEMO_PAGE_X_FIX));
- max_size = page_get_max_insert_size_after_reorganize(page, 1);
- level = btr_page_get_level(page, mtr);
-
-calculate_sizes_again:
- /* Calculate the record size when entry is converted to a record */
- rec_size = rec_get_converted_size(index, entry);
-
- if (rec_size
- >= ut_min(page_get_free_space_of_empty(page_is_comp(page)) / 2,
- REC_MAX_DATA_SIZE)) {
-
- /* The record is so big that we have to store some fields
- externally on separate database pages */
-
- big_rec_vec = dtuple_convert_big_rec(index, entry, NULL, 0);
-
- if (big_rec_vec == NULL) {
-
- return(DB_TOO_BIG_RECORD);
- }
-
- goto calculate_sizes_again;
- }
-
- /* If there have been many consecutive inserts, and we are on the leaf
- level, check if we have to split the page to reserve enough free space
- for future updates of records. */
-
- type = index->type;
-
- if ((type & DICT_CLUSTERED)
- && (dict_index_get_space_reserve() + rec_size > max_size)
- && (page_get_n_recs(page) >= 2)
- && (0 == level)
- && (btr_page_get_split_rec_to_right(cursor, &dummy_rec)
- || btr_page_get_split_rec_to_left(cursor, &dummy_rec))) {
-
- if (big_rec_vec) {
- dtuple_convert_back_big_rec(index, entry, big_rec_vec);
- }
-
- return(DB_FAIL);
- }
-
- if (!(((max_size >= rec_size)
- && (max_size >= BTR_CUR_PAGE_REORGANIZE_LIMIT))
- || (page_get_max_insert_size(page, 1) >= rec_size)
- || (page_get_n_recs(page) <= 1))) {
-
- if (big_rec_vec) {
- dtuple_convert_back_big_rec(index, entry, big_rec_vec);
- }
- return(DB_FAIL);
- }
-
- /* Check locks and write to the undo log, if specified */
- err = btr_cur_ins_lock_and_undo(flags, cursor, entry, thr, &inherit);
-
- if (err != DB_SUCCESS) {
-
- if (big_rec_vec) {
- dtuple_convert_back_big_rec(index, entry, big_rec_vec);
- }
- return(err);
- }
-
- page_cursor = btr_cur_get_page_cur(cursor);
-
- reorg = FALSE;
-
- /* Now, try the insert */
-
- *rec = page_cur_insert_rec_low(page_cursor, entry, index,
- NULL, NULL, mtr);
- if (UNIV_UNLIKELY(!(*rec))) {
- /* If the record did not fit, reorganize */
- btr_page_reorganize(page, index, mtr);
-
- ut_ad(page_get_max_insert_size(page, 1) == max_size);
-
- reorg = TRUE;
-
- page_cur_search(page, index, entry, PAGE_CUR_LE, page_cursor);
-
- *rec = page_cur_tuple_insert(page_cursor, entry, index, mtr);
-
- if (UNIV_UNLIKELY(!*rec)) {
- fputs("InnoDB: Error: cannot insert tuple ", stderr);
- dtuple_print(stderr, entry);
- fputs(" into ", stderr);
- dict_index_name_print(stderr, thr_get_trx(thr), index);
- fprintf(stderr, "\nInnoDB: max insert size %lu\n",
- (ulong) max_size);
- ut_error;
- }
- }
-
-#ifdef BTR_CUR_HASH_ADAPT
- if (!reorg && (0 == level) && (cursor->flag == BTR_CUR_HASH)) {
- btr_search_update_hash_node_on_insert(cursor);
- } else {
- btr_search_update_hash_on_insert(cursor);
- }
-#endif
-
- if (!(flags & BTR_NO_LOCKING_FLAG) && inherit) {
-
- lock_update_insert(*rec);
- }
-
-#if 0
- fprintf(stderr, "Insert into page %lu, max ins size %lu,"
- " rec %lu ind type %lu\n",
- buf_frame_get_page_no(page), max_size,
- rec_size + PAGE_DIR_SLOT_SIZE, type);
-#endif
- if (!(type & DICT_CLUSTERED)) {
- /* We have added a record to page: update its free bits */
- ibuf_update_free_bits_if_full(cursor->index, page, max_size,
- rec_size + PAGE_DIR_SLOT_SIZE);
- }
-
- *big_rec = big_rec_vec;
-
- return(DB_SUCCESS);
-}
-
-/*****************************************************************
-Performs an insert on a page of an index tree. It is assumed that mtr
-holds an x-latch on the tree and on the cursor page. If the insert is
-made on the leaf level, to avoid deadlocks, mtr must also own x-latches
-to brothers of page, if those brothers exist. */
-
-ulint
-btr_cur_pessimistic_insert(
-/*=======================*/
- /* out: DB_SUCCESS or error number */
- ulint flags, /* in: undo logging and locking flags: if not
- zero, the parameter thr should be
- specified; if no undo logging is specified,
- then the caller must have reserved enough
- free extents in the file space so that the
- insertion will certainly succeed */
- btr_cur_t* cursor, /* in: cursor after which to insert;
- cursor stays valid */
- dtuple_t* entry, /* in: entry to insert */
- rec_t** rec, /* out: pointer to inserted record if
- succeed */
- big_rec_t** big_rec,/* out: big rec vector whose fields have to
- be stored externally by the caller, or
- NULL */
- que_thr_t* thr, /* in: query thread or NULL */
- mtr_t* mtr) /* in: mtr */
-{
- dict_index_t* index = cursor->index;
- big_rec_t* big_rec_vec = NULL;
- page_t* page;
- ulint err;
- ibool dummy_inh;
- ibool success;
- ulint n_extents = 0;
- ulint n_reserved;
-
- ut_ad(dtuple_check_typed(entry));
-
- *big_rec = NULL;
-
- page = btr_cur_get_page(cursor);
-
- ut_ad(mtr_memo_contains(mtr,
- dict_index_get_lock(btr_cur_get_index(cursor)),
- MTR_MEMO_X_LOCK));
- ut_ad(mtr_memo_contains(mtr, buf_block_align(page),
- MTR_MEMO_PAGE_X_FIX));
-
- /* Try first an optimistic insert; reset the cursor flag: we do not
- assume anything of how it was positioned */
-
- cursor->flag = BTR_CUR_BINARY;
-
- err = btr_cur_optimistic_insert(flags, cursor, entry, rec, big_rec,
- thr, mtr);
- if (err != DB_FAIL) {
-
- return(err);
- }
-
- /* Retry with a pessimistic insert. Check locks and write to undo log,
- if specified */
-
- err = btr_cur_ins_lock_and_undo(flags, cursor, entry, thr, &dummy_inh);
-
- if (err != DB_SUCCESS) {
-
- return(err);
- }
-
- if (!(flags & BTR_NO_UNDO_LOG_FLAG)) {
- /* First reserve enough free space for the file segments
- of the index tree, so that the insert will not fail because
- of lack of space */
-
- n_extents = cursor->tree_height / 16 + 3;
-
- success = fsp_reserve_free_extents(&n_reserved, index->space,
- n_extents, FSP_NORMAL, mtr);
- if (!success) {
- err = DB_OUT_OF_FILE_SPACE;
-
- return(err);
- }
- }
-
- if (rec_get_converted_size(index, entry)
- >= ut_min(page_get_free_space_of_empty(page_is_comp(page)) / 2,
- REC_MAX_DATA_SIZE)) {
-
- /* The record is so big that we have to store some fields
- externally on separate database pages */
-
- big_rec_vec = dtuple_convert_big_rec(index, entry, NULL, 0);
-
- if (big_rec_vec == NULL) {
-
- if (n_extents > 0) {
- fil_space_release_free_extents(index->space,
- n_reserved);
- }
- return(DB_TOO_BIG_RECORD);
- }
- }
-
- if (dict_index_get_page(index) == buf_frame_get_page_no(page)) {
-
- /* The page is the root page */
- *rec = btr_root_raise_and_insert(cursor, entry, mtr);
- } else {
- *rec = btr_page_split_and_insert(cursor, entry, mtr);
- }
-
- btr_cur_position(index, page_rec_get_prev(*rec), cursor);
-
-#ifdef BTR_CUR_ADAPT
- btr_search_update_hash_on_insert(cursor);
-#endif
- if (!(flags & BTR_NO_LOCKING_FLAG)) {
-
- lock_update_insert(*rec);
- }
-
- err = DB_SUCCESS;
-
- if (n_extents > 0) {
- fil_space_release_free_extents(index->space, n_reserved);
- }
-
- *big_rec = big_rec_vec;
-
- return(err);
-}
-
-/*==================== B-TREE UPDATE =========================*/
-
-/*****************************************************************
-For an update, checks the locks and does the undo logging. */
-UNIV_INLINE
-ulint
-btr_cur_upd_lock_and_undo(
-/*======================*/
- /* out: DB_SUCCESS, DB_WAIT_LOCK, or error
- number */
- ulint flags, /* in: undo logging and locking flags */
- btr_cur_t* cursor, /* in: cursor on record to update */
- upd_t* update, /* in: update vector */
- ulint cmpl_info,/* in: compiler info on secondary index
- updates */
- que_thr_t* thr, /* in: query thread */
- dulint* roll_ptr)/* out: roll pointer */
-{
- dict_index_t* index;
- rec_t* rec;
- ulint err;
-
- ut_ad(cursor && update && thr && roll_ptr);
-
- rec = btr_cur_get_rec(cursor);
- index = cursor->index;
-
- if (!(index->type & DICT_CLUSTERED)) {
- /* We do undo logging only when we update a clustered index
- record */
- return(lock_sec_rec_modify_check_and_lock(flags, rec, index,
- thr));
- }
-
- /* Check if we have to wait for a lock: enqueue an explicit lock
- request if yes */
-
- err = DB_SUCCESS;
-
- if (!(flags & BTR_NO_LOCKING_FLAG)) {
- mem_heap_t* heap = NULL;
- ulint offsets_[REC_OFFS_NORMAL_SIZE];
- *offsets_ = (sizeof offsets_) / sizeof *offsets_;
-
- err = lock_clust_rec_modify_check_and_lock(
- flags, rec, index,
- rec_get_offsets(rec, index, offsets_,
- ULINT_UNDEFINED, &heap), thr);
- if (UNIV_LIKELY_NULL(heap)) {
- mem_heap_free(heap);
- }
- if (err != DB_SUCCESS) {
-
- return(err);
- }
- }
-
- /* Append the info about the update in the undo log */
-
- err = trx_undo_report_row_operation(flags, TRX_UNDO_MODIFY_OP, thr,
- index, NULL, update,
- cmpl_info, rec, roll_ptr);
- return(err);
-}
-
-/***************************************************************
-Writes a redo log record of updating a record in-place. */
-UNIV_INLINE
-void
-btr_cur_update_in_place_log(
-/*========================*/
- ulint flags, /* in: flags */
- rec_t* rec, /* in: record */
- dict_index_t* index, /* in: index where cursor positioned */
- upd_t* update, /* in: update vector */
- trx_t* trx, /* in: transaction */
- dulint roll_ptr, /* in: roll ptr */
- mtr_t* mtr) /* in: mtr */
-{
- byte* log_ptr;
- page_t* page = page_align(rec);
- ut_ad(flags < 256);
- ut_ad(!!page_is_comp(page) == dict_table_is_comp(index->table));
-
- log_ptr = mlog_open_and_write_index(mtr, rec, index, page_is_comp(page)
- ? MLOG_COMP_REC_UPDATE_IN_PLACE
- : MLOG_REC_UPDATE_IN_PLACE,
- 1 + DATA_ROLL_PTR_LEN + 14 + 2
- + MLOG_BUF_MARGIN);
-
- if (!log_ptr) {
- /* Logging in mtr is switched off during crash recovery */
- return;
- }
-
- /* The code below assumes index is a clustered index: change index to
- the clustered index if we are updating a secondary index record (or we
- could as well skip writing the sys col values to the log in this case
- because they are not needed for a secondary index record update) */
-
- index = dict_table_get_first_index(index->table);
-
- mach_write_to_1(log_ptr, flags);
- log_ptr++;
-
- log_ptr = row_upd_write_sys_vals_to_log(index, trx, roll_ptr, log_ptr,
- mtr);
- mach_write_to_2(log_ptr, page_offset(rec));
- log_ptr += 2;
-
- row_upd_index_write_log(update, log_ptr, mtr);
-}
-
-/***************************************************************
-Parses a redo log record of updating a record in-place. */
-
-byte*
-btr_cur_parse_update_in_place(
-/*==========================*/
- /* out: end of log record or NULL */
- byte* ptr, /* in: buffer */
- byte* end_ptr,/* in: buffer end */
- page_t* page, /* in: page or NULL */
- dict_index_t* index) /* in: index corresponding to page */
-{
- ulint flags;
- rec_t* rec;
- upd_t* update;
- ulint pos;
- dulint trx_id;
- dulint roll_ptr;
- ulint rec_offset;
- mem_heap_t* heap;
- ulint* offsets;
-
- if (end_ptr < ptr + 1) {
-
- return(NULL);
- }
-
- flags = mach_read_from_1(ptr);
- ptr++;
-
- ptr = row_upd_parse_sys_vals(ptr, end_ptr, &pos, &trx_id, &roll_ptr);
-
- if (ptr == NULL) {
-
- return(NULL);
- }
-
- if (end_ptr < ptr + 2) {
-
- return(NULL);
- }
-
- rec_offset = mach_read_from_2(ptr);
- ptr += 2;
-
- ut_a(rec_offset <= UNIV_PAGE_SIZE);
-
- heap = mem_heap_create(256);
-
- ptr = row_upd_index_parse(ptr, end_ptr, heap, &update);
-
- if (!ptr || !page) {
-
- goto func_exit;
- }
-
- ut_a((ibool)!!page_is_comp(page) == dict_table_is_comp(index->table));
- rec = page + rec_offset;
-
- /* We do not need to reserve btr_search_latch, as the page is only
- being recovered, and there cannot be a hash index to it. */
-
- offsets = rec_get_offsets(rec, index, NULL, ULINT_UNDEFINED, &heap);
-
- if (!(flags & BTR_KEEP_SYS_FLAG)) {
- row_upd_rec_sys_fields_in_recovery(rec, offsets,
- pos, trx_id, roll_ptr);
- }
-
- row_upd_rec_in_place(rec, offsets, update);
-
-func_exit:
- mem_heap_free(heap);
-
- return(ptr);
-}
-
-/*****************************************************************
-Updates a record when the update causes no size changes in its fields.
-We assume here that the ordering fields of the record do not change. */
-
-ulint
-btr_cur_update_in_place(
-/*====================*/
- /* out: DB_SUCCESS or error number */
- ulint flags, /* in: undo logging and locking flags */
- btr_cur_t* cursor, /* in: cursor on the record to update;
- cursor stays valid and positioned on the
- same record */
- upd_t* update, /* in: update vector */
- ulint cmpl_info,/* in: compiler info on secondary index
- updates */
- que_thr_t* thr, /* in: query thread */
- mtr_t* mtr) /* in: mtr */
-{
- dict_index_t* index;
- buf_block_t* block;
- ulint err;
- rec_t* rec;
- dulint roll_ptr = ut_dulint_zero;
- trx_t* trx;
- ulint was_delete_marked;
- mem_heap_t* heap = NULL;
- ulint offsets_[REC_OFFS_NORMAL_SIZE];
- ulint* offsets = offsets_;
- *offsets_ = (sizeof offsets_) / sizeof *offsets_;
-
- rec = btr_cur_get_rec(cursor);
- index = cursor->index;
- ut_ad(!!page_rec_is_comp(rec) == dict_table_is_comp(index->table));
- trx = thr_get_trx(thr);
- offsets = rec_get_offsets(rec, index, offsets, ULINT_UNDEFINED, &heap);
-#ifdef UNIV_DEBUG
- if (btr_cur_print_record_ops && thr) {
- btr_cur_trx_report(trx, index, "update ");
- rec_print_new(stderr, rec, offsets);
- }
-#endif /* UNIV_DEBUG */
-
- /* Do lock checking and undo logging */
- err = btr_cur_upd_lock_and_undo(flags, cursor, update, cmpl_info,
- thr, &roll_ptr);
- if (UNIV_UNLIKELY(err != DB_SUCCESS)) {
-
- if (UNIV_LIKELY_NULL(heap)) {
- mem_heap_free(heap);
- }
- return(err);
- }
-
- block = buf_block_align(rec);
- ut_ad(!!page_is_comp(buf_block_get_frame(block))
- == dict_table_is_comp(index->table));
-
- if (block->is_hashed) {
- /* The function row_upd_changes_ord_field_binary works only
- if the update vector was built for a clustered index, we must
- NOT call it if index is secondary */
-
- if (!(index->type & DICT_CLUSTERED)
- || row_upd_changes_ord_field_binary(NULL, index, update)) {
-
- /* Remove possible hash index pointer to this record */
- btr_search_update_hash_on_delete(cursor);
- }
-
- rw_lock_x_lock(&btr_search_latch);
- }
-
- if (!(flags & BTR_KEEP_SYS_FLAG)) {
- row_upd_rec_sys_fields(rec, index, offsets, trx, roll_ptr);
- }
-
- was_delete_marked = rec_get_deleted_flag(
- rec, page_is_comp(buf_block_get_frame(block)));
-
- row_upd_rec_in_place(rec, offsets, update);
-
- if (block->is_hashed) {
- rw_lock_x_unlock(&btr_search_latch);
- }
-
- btr_cur_update_in_place_log(flags, rec, index, update, trx, roll_ptr,
- mtr);
- if (was_delete_marked
- && !rec_get_deleted_flag(rec, page_is_comp(
- buf_block_get_frame(block)))) {
- /* The new updated record owns its possible externally
- stored fields */
-
- btr_cur_unmark_extern_fields(rec, mtr, offsets);
- }
-
- if (UNIV_LIKELY_NULL(heap)) {
- mem_heap_free(heap);
- }
- return(DB_SUCCESS);
-}
-
-/*****************************************************************
-Tries to update a record on a page in an index tree. It is assumed that mtr
-holds an x-latch on the page. The operation does not succeed if there is too
-little space on the page or if the update would result in too empty a page,
-so that tree compression is recommended. We assume here that the ordering
-fields of the record do not change. */
-
-ulint
-btr_cur_optimistic_update(
-/*======================*/
- /* out: DB_SUCCESS, or DB_OVERFLOW if the
- updated record does not fit, DB_UNDERFLOW
- if the page would become too empty */
- ulint flags, /* in: undo logging and locking flags */
- btr_cur_t* cursor, /* in: cursor on the record to update;
- cursor stays valid and positioned on the
- same record */
- upd_t* update, /* in: update vector; this must also
- contain trx id and roll ptr fields */
- ulint cmpl_info,/* in: compiler info on secondary index
- updates */
- que_thr_t* thr, /* in: query thread */
- mtr_t* mtr) /* in: mtr */
-{
- dict_index_t* index;
- page_cur_t* page_cursor;
- ulint err;
- page_t* page;
- rec_t* rec;
- ulint max_size;
- ulint new_rec_size;
- ulint old_rec_size;
- dtuple_t* new_entry;
- dulint roll_ptr;
- trx_t* trx;
- mem_heap_t* heap;
- ibool reorganized = FALSE;
- ulint i;
- ulint* offsets;
-
- page = btr_cur_get_page(cursor);
- rec = btr_cur_get_rec(cursor);
- index = cursor->index;
- ut_ad(!!page_rec_is_comp(rec) == dict_table_is_comp(index->table));
-
- heap = mem_heap_create(1024);
- offsets = rec_get_offsets(rec, index, NULL, ULINT_UNDEFINED, &heap);
-
-#ifdef UNIV_DEBUG
- if (btr_cur_print_record_ops && thr) {
- btr_cur_trx_report(thr_get_trx(thr), index, "update ");
- rec_print_new(stderr, rec, offsets);
- }
-#endif /* UNIV_DEBUG */
-
- ut_ad(mtr_memo_contains(mtr, buf_block_align(page),
- MTR_MEMO_PAGE_X_FIX));
- if (!row_upd_changes_field_size_or_external(index, offsets, update)) {
-
- /* The simplest and the most common case: the update does not
- change the size of any field and none of the updated fields is
- externally stored in rec or update */
- mem_heap_free(heap);
- return(btr_cur_update_in_place(flags, cursor, update,
- cmpl_info, thr, mtr));
- }
-
- for (i = 0; i < upd_get_n_fields(update); i++) {
- if (upd_get_nth_field(update, i)->extern_storage) {
-
- /* Externally stored fields are treated in pessimistic
- update */
-
- mem_heap_free(heap);
- return(DB_OVERFLOW);
- }
- }
-
- if (rec_offs_any_extern(offsets)) {
- /* Externally stored fields are treated in pessimistic
- update */
-
- mem_heap_free(heap);
- return(DB_OVERFLOW);
- }
-
- page_cursor = btr_cur_get_page_cur(cursor);
-
- new_entry = row_rec_to_index_entry(ROW_COPY_DATA, index, rec, heap);
-
- row_upd_index_replace_new_col_vals_index_pos(new_entry, index, update,
- FALSE, NULL);
- old_rec_size = rec_offs_size(offsets);
- new_rec_size = rec_get_converted_size(index, new_entry);
-
- if (UNIV_UNLIKELY(new_rec_size
- >= (page_get_free_space_of_empty(page_is_comp(page))
- / 2))) {
-
- mem_heap_free(heap);
-
- return(DB_OVERFLOW);
- }
-
- max_size = old_rec_size
- + page_get_max_insert_size_after_reorganize(page, 1);
-
- if (UNIV_UNLIKELY(page_get_data_size(page)
- - old_rec_size + new_rec_size
- < BTR_CUR_PAGE_COMPRESS_LIMIT)) {
-
- /* The page would become too empty */
-
- mem_heap_free(heap);
-
- return(DB_UNDERFLOW);
- }
-
- if (!(((max_size >= BTR_CUR_PAGE_REORGANIZE_LIMIT)
- && (max_size >= new_rec_size))
- || (page_get_n_recs(page) <= 1))) {
-
- /* There was not enough space, or it did not pay to
- reorganize: for simplicity, we decide what to do assuming a
- reorganization is needed, though it might not be necessary */
-
- mem_heap_free(heap);
-
- return(DB_OVERFLOW);
- }
-
- /* Do lock checking and undo logging */
- err = btr_cur_upd_lock_and_undo(flags, cursor, update, cmpl_info, thr,
- &roll_ptr);
- if (err != DB_SUCCESS) {
-
- mem_heap_free(heap);
-
- return(err);
- }
-
- /* Ok, we may do the replacement. Store on the page infimum the
- explicit locks on rec, before deleting rec (see the comment in
- .._pessimistic_update). */
-
- lock_rec_store_on_page_infimum(page, rec);
-
- btr_search_update_hash_on_delete(cursor);
-
- page_cur_delete_rec(page_cursor, index, offsets, mtr);
-
- page_cur_move_to_prev(page_cursor);
-
- trx = thr_get_trx(thr);
-
- if (!(flags & BTR_KEEP_SYS_FLAG)) {
- row_upd_index_entry_sys_field(new_entry, index, DATA_ROLL_PTR,
- roll_ptr);
- row_upd_index_entry_sys_field(new_entry, index, DATA_TRX_ID,
- trx->id);
- }
-
- rec = btr_cur_insert_if_possible(cursor, new_entry, &reorganized, mtr);
-
- ut_a(rec); /* <- We calculated above the insert would fit */
-
- if (!rec_get_deleted_flag(rec, page_is_comp(page))) {
- /* The new inserted record owns its possible externally
- stored fields */
-
- offsets = rec_get_offsets(rec, index, offsets,
- ULINT_UNDEFINED, &heap);
- btr_cur_unmark_extern_fields(rec, mtr, offsets);
- }
-
- /* Restore the old explicit lock state on the record */
-
- lock_rec_restore_from_page_infimum(rec, page);
-
- page_cur_move_to_next(page_cursor);
-
- mem_heap_free(heap);
-
- return(DB_SUCCESS);
-}
-
-/*****************************************************************
-If, in a split, a new supremum record was created as the predecessor of the
-updated record, the supremum record must inherit exactly the locks on the
-updated record. In the split it may have inherited locks from the successor
-of the updated record, which is not correct. This function restores the
-right locks for the new supremum. */
-static
-void
-btr_cur_pess_upd_restore_supremum(
-/*==============================*/
- rec_t* rec, /* in: updated record */
- mtr_t* mtr) /* in: mtr */
-{
- page_t* page;
- page_t* prev_page;
- ulint space;
- ulint prev_page_no;
-
- page = buf_frame_align(rec);
-
- if (page_rec_get_next(page_get_infimum_rec(page)) != rec) {
- /* Updated record is not the first user record on its page */
-
- return;
- }
-
- space = buf_frame_get_space_id(page);
- prev_page_no = btr_page_get_prev(page, mtr);
-
- ut_ad(prev_page_no != FIL_NULL);
- prev_page = buf_page_get_with_no_latch(space, prev_page_no, mtr);
-#ifdef UNIV_BTR_DEBUG
- ut_a(btr_page_get_next(prev_page, mtr)
- == buf_frame_get_page_no(page));
-#endif /* UNIV_BTR_DEBUG */
-
- /* We must already have an x-latch to prev_page! */
- ut_ad(mtr_memo_contains(mtr, buf_block_align(prev_page),
- MTR_MEMO_PAGE_X_FIX));
-
- lock_rec_reset_and_inherit_gap_locks(page_get_supremum_rec(prev_page),
- rec);
-}
-
-/*****************************************************************
-Performs an update of a record on a page of a tree. It is assumed
-that mtr holds an x-latch on the tree and on the cursor page. If the
-update is made on the leaf level, to avoid deadlocks, mtr must also
-own x-latches to brothers of page, if those brothers exist. We assume
-here that the ordering fields of the record do not change. */
-
-ulint
-btr_cur_pessimistic_update(
-/*=======================*/
- /* out: DB_SUCCESS or error code */
- ulint flags, /* in: undo logging, locking, and rollback
- flags */
- btr_cur_t* cursor, /* in: cursor on the record to update */
- big_rec_t** big_rec,/* out: big rec vector whose fields have to
- be stored externally by the caller, or NULL */
- upd_t* update, /* in: update vector; this is allowed also
- contain trx id and roll ptr fields, but
- the values in update vector have no effect */
- ulint cmpl_info,/* in: compiler info on secondary index
- updates */
- que_thr_t* thr, /* in: query thread */
- mtr_t* mtr) /* in: mtr */
-{
- big_rec_t* big_rec_vec = NULL;
- big_rec_t* dummy_big_rec;
- dict_index_t* index;
- page_t* page;
- rec_t* rec;
- page_cur_t* page_cursor;
- dtuple_t* new_entry;
- mem_heap_t* heap;
- ulint err;
- ulint optim_err;
- ibool dummy_reorganized;
- dulint roll_ptr;
- trx_t* trx;
- ibool was_first;
- ibool success;
- ulint n_extents = 0;
- ulint n_reserved;
- ulint* ext_vect;
- ulint n_ext_vect;
- ulint reserve_flag;
- ulint* offsets = NULL;
-
- *big_rec = NULL;
-
- page = btr_cur_get_page(cursor);
- rec = btr_cur_get_rec(cursor);
- index = cursor->index;
-
- ut_ad(mtr_memo_contains(mtr, dict_index_get_lock(index),
- MTR_MEMO_X_LOCK));
- ut_ad(mtr_memo_contains(mtr, buf_block_align(page),
- MTR_MEMO_PAGE_X_FIX));
-
- optim_err = btr_cur_optimistic_update(flags, cursor, update,
- cmpl_info, thr, mtr);
-
- if (optim_err != DB_UNDERFLOW && optim_err != DB_OVERFLOW) {
-
- return(optim_err);
- }
-
- /* Do lock checking and undo logging */
- err = btr_cur_upd_lock_and_undo(flags, cursor, update, cmpl_info,
- thr, &roll_ptr);
- if (err != DB_SUCCESS) {
-
- return(err);
- }
-
- if (optim_err == DB_OVERFLOW) {
- /* First reserve enough free space for the file segments
- of the index tree, so that the update will not fail because
- of lack of space */
-
- n_extents = cursor->tree_height / 16 + 3;
-
- if (flags & BTR_NO_UNDO_LOG_FLAG) {
- reserve_flag = FSP_CLEANING;
- } else {
- reserve_flag = FSP_NORMAL;
- }
-
- success = fsp_reserve_free_extents(&n_reserved, index->space,
- n_extents,
- reserve_flag, mtr);
- if (!success) {
- err = DB_OUT_OF_FILE_SPACE;
-
- return(err);
- }
- }
-
- heap = mem_heap_create(1024);
- offsets = rec_get_offsets(rec, index, NULL, ULINT_UNDEFINED, &heap);
-
- trx = thr_get_trx(thr);
-
- new_entry = row_rec_to_index_entry(ROW_COPY_DATA, index, rec, heap);
-
- row_upd_index_replace_new_col_vals_index_pos(new_entry, index, update,
- FALSE, heap);
- if (!(flags & BTR_KEEP_SYS_FLAG)) {
- row_upd_index_entry_sys_field(new_entry, index, DATA_ROLL_PTR,
- roll_ptr);
- row_upd_index_entry_sys_field(new_entry, index, DATA_TRX_ID,
- trx->id);
- }
-
- if (flags & BTR_NO_UNDO_LOG_FLAG) {
- /* We are in a transaction rollback undoing a row
- update: we must free possible externally stored fields
- which got new values in the update, if they are not
- inherited values. They can be inherited if we have
- updated the primary key to another value, and then
- update it back again. */
-
- ut_a(big_rec_vec == NULL);
-
- btr_rec_free_updated_extern_fields(index, rec, offsets,
- update, TRUE, mtr);
- }
-
- /* We have to set appropriate extern storage bits in the new
- record to be inserted: we have to remember which fields were such */
-
- ext_vect = mem_heap_alloc(heap, sizeof(ulint)
- * dict_index_get_n_fields(index));
- ut_ad(!page_is_comp(page) || !rec_get_node_ptr_flag(rec));
- offsets = rec_get_offsets(rec, index, offsets,
- ULINT_UNDEFINED, &heap);
- n_ext_vect = btr_push_update_extern_fields(ext_vect, offsets, update);
-
- if (UNIV_UNLIKELY(rec_get_converted_size(index, new_entry)
- >= ut_min(page_get_free_space_of_empty(
- page_is_comp(page)) / 2,
- REC_MAX_DATA_SIZE))) {
-
- big_rec_vec = dtuple_convert_big_rec(index, new_entry,
- ext_vect, n_ext_vect);
- if (big_rec_vec == NULL) {
-
- err = DB_TOO_BIG_RECORD;
- goto return_after_reservations;
- }
- }
-
- page_cursor = btr_cur_get_page_cur(cursor);
-
- /* Store state of explicit locks on rec on the page infimum record,
- before deleting rec. The page infimum acts as a dummy carrier of the
- locks, taking care also of lock releases, before we can move the locks
- back on the actual record. There is a special case: if we are
- inserting on the root page and the insert causes a call of
- btr_root_raise_and_insert. Therefore we cannot in the lock system
- delete the lock structs set on the root page even if the root
- page carries just node pointers. */
-
- lock_rec_store_on_page_infimum(buf_frame_align(rec), rec);
-
- btr_search_update_hash_on_delete(cursor);
-
- page_cur_delete_rec(page_cursor, index, offsets, mtr);
-
- page_cur_move_to_prev(page_cursor);
-
- rec = btr_cur_insert_if_possible(cursor, new_entry,
- &dummy_reorganized, mtr);
- ut_a(rec || optim_err != DB_UNDERFLOW);
-
- if (rec) {
- lock_rec_restore_from_page_infimum(rec, page);
- rec_set_field_extern_bits(rec, index,
- ext_vect, n_ext_vect, mtr);
-
- offsets = rec_get_offsets(rec, index, offsets,
- ULINT_UNDEFINED, &heap);
-
- if (!rec_get_deleted_flag(rec, rec_offs_comp(offsets))) {
- /* The new inserted record owns its possible externally
- stored fields */
- btr_cur_unmark_extern_fields(rec, mtr, offsets);
- }
-
- btr_cur_compress_if_useful(cursor, mtr);
-
- err = DB_SUCCESS;
- goto return_after_reservations;
- }
-
- if (page_cur_is_before_first(page_cursor)) {
- /* The record to be updated was positioned as the first user
- record on its page */
-
- was_first = TRUE;
- } else {
- was_first = FALSE;
- }
-
- /* The first parameter means that no lock checking and undo logging
- is made in the insert */
-
- err = btr_cur_pessimistic_insert(BTR_NO_UNDO_LOG_FLAG
- | BTR_NO_LOCKING_FLAG
- | BTR_KEEP_SYS_FLAG,
- cursor, new_entry, &rec,
- &dummy_big_rec, NULL, mtr);
- ut_a(rec);
- ut_a(err == DB_SUCCESS);
- ut_a(dummy_big_rec == NULL);
-
- rec_set_field_extern_bits(rec, index, ext_vect, n_ext_vect, mtr);
- offsets = rec_get_offsets(rec, index, offsets, ULINT_UNDEFINED, &heap);
-
- if (!rec_get_deleted_flag(rec, rec_offs_comp(offsets))) {
- /* The new inserted record owns its possible externally
- stored fields */
-
- btr_cur_unmark_extern_fields(rec, mtr, offsets);
- }
-
- lock_rec_restore_from_page_infimum(rec, page);
-
- /* If necessary, restore also the correct lock state for a new,
- preceding supremum record created in a page split. While the old
- record was nonexistent, the supremum might have inherited its locks
- from a wrong record. */
-
- if (!was_first) {
- btr_cur_pess_upd_restore_supremum(rec, mtr);
- }
-
-return_after_reservations:
- mem_heap_free(heap);
-
- if (n_extents > 0) {
- fil_space_release_free_extents(index->space, n_reserved);
- }
-
- *big_rec = big_rec_vec;
-
- return(err);
-}
-
-/*==================== B-TREE DELETE MARK AND UNMARK ===============*/
-
-/********************************************************************
-Writes the redo log record for delete marking or unmarking of an index
-record. */
-UNIV_INLINE
-void
-btr_cur_del_mark_set_clust_rec_log(
-/*===============================*/
- ulint flags, /* in: flags */
- rec_t* rec, /* in: record */
- dict_index_t* index, /* in: index of the record */
- ibool val, /* in: value to set */
- trx_t* trx, /* in: deleting transaction */
- dulint roll_ptr,/* in: roll ptr to the undo log record */
- mtr_t* mtr) /* in: mtr */
-{
- byte* log_ptr;
- ut_ad(flags < 256);
- ut_ad(val <= 1);
-
- ut_ad(!!page_rec_is_comp(rec) == dict_table_is_comp(index->table));
-
- log_ptr = mlog_open_and_write_index(mtr, rec, index,
- page_rec_is_comp(rec)
- ? MLOG_COMP_REC_CLUST_DELETE_MARK
- : MLOG_REC_CLUST_DELETE_MARK,
- 1 + 1 + DATA_ROLL_PTR_LEN
- + 14 + 2);
-
- if (!log_ptr) {
- /* Logging in mtr is switched off during crash recovery */
- return;
- }
-
- mach_write_to_1(log_ptr, flags);
- log_ptr++;
- mach_write_to_1(log_ptr, val);
- log_ptr++;
-
- log_ptr = row_upd_write_sys_vals_to_log(index, trx, roll_ptr, log_ptr,
- mtr);
- mach_write_to_2(log_ptr, page_offset(rec));
- log_ptr += 2;
-
- mlog_close(mtr, log_ptr);
-}
-
-/********************************************************************
-Parses the redo log record for delete marking or unmarking of a clustered
-index record. */
-
-byte*
-btr_cur_parse_del_mark_set_clust_rec(
-/*=================================*/
- /* out: end of log record or NULL */
- byte* ptr, /* in: buffer */
- byte* end_ptr,/* in: buffer end */
- dict_index_t* index, /* in: index corresponding to page */
- page_t* page) /* in: page or NULL */
-{
- ulint flags;
- ulint val;
- ulint pos;
- dulint trx_id;
- dulint roll_ptr;
- ulint offset;
- rec_t* rec;
-
- ut_ad(!page
- || !!page_is_comp(page) == dict_table_is_comp(index->table));
-
- if (end_ptr < ptr + 2) {
-
- return(NULL);
- }
-
- flags = mach_read_from_1(ptr);
- ptr++;
- val = mach_read_from_1(ptr);
- ptr++;
-
- ptr = row_upd_parse_sys_vals(ptr, end_ptr, &pos, &trx_id, &roll_ptr);
-
- if (ptr == NULL) {
-
- return(NULL);
- }
-
- if (end_ptr < ptr + 2) {
-
- return(NULL);
- }
-
- offset = mach_read_from_2(ptr);
- ptr += 2;
-
- ut_a(offset <= UNIV_PAGE_SIZE);
-
- if (page) {
- rec = page + offset;
-
- if (!(flags & BTR_KEEP_SYS_FLAG)) {
- mem_heap_t* heap = NULL;
- ulint offsets_[REC_OFFS_NORMAL_SIZE];
- *offsets_ = (sizeof offsets_) / sizeof *offsets_;
-
- row_upd_rec_sys_fields_in_recovery(
- rec, rec_get_offsets(rec, index, offsets_,
- ULINT_UNDEFINED, &heap),
- pos, trx_id, roll_ptr);
- if (UNIV_LIKELY_NULL(heap)) {
- mem_heap_free(heap);
- }
- }
-
- /* We do not need to reserve btr_search_latch, as the page
- is only being recovered, and there cannot be a hash index to
- it. */
-
- rec_set_deleted_flag(rec, page_is_comp(page), val);
- }
-
- return(ptr);
-}
-
-/***************************************************************
-Marks a clustered index record deleted. Writes an undo log record to
-undo log on this delete marking. Writes in the trx id field the id
-of the deleting transaction, and in the roll ptr field pointer to the
-undo log record created. */
-
-ulint
-btr_cur_del_mark_set_clust_rec(
-/*===========================*/
- /* out: DB_SUCCESS, DB_LOCK_WAIT, or error
- number */
- ulint flags, /* in: undo logging and locking flags */
- btr_cur_t* cursor, /* in: cursor */
- 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;
- dulint roll_ptr;
- ulint err;
- rec_t* rec;
- trx_t* trx;
- mem_heap_t* heap = NULL;
- ulint offsets_[REC_OFFS_NORMAL_SIZE];
- ulint* offsets = offsets_;
- *offsets_ = (sizeof offsets_) / sizeof *offsets_;
-
- rec = btr_cur_get_rec(cursor);
- index = cursor->index;
- ut_ad(!!page_rec_is_comp(rec) == dict_table_is_comp(index->table));
- offsets = rec_get_offsets(rec, index, offsets, ULINT_UNDEFINED, &heap);
-
-#ifdef UNIV_DEBUG
- if (btr_cur_print_record_ops && thr) {
- btr_cur_trx_report(thr_get_trx(thr), index, "del mark ");
- rec_print_new(stderr, rec, offsets);
- }
-#endif /* UNIV_DEBUG */
-
- ut_ad(index->type & DICT_CLUSTERED);
- ut_ad(!rec_get_deleted_flag(rec, rec_offs_comp(offsets)));
-
- err = lock_clust_rec_modify_check_and_lock(flags,
- rec, index, offsets, thr);
-
- if (err != DB_SUCCESS) {
-
- if (UNIV_LIKELY_NULL(heap)) {
- mem_heap_free(heap);
- }
- return(err);
- }
-
- err = trx_undo_report_row_operation(flags, TRX_UNDO_MODIFY_OP, thr,
- index, NULL, NULL, 0, rec,
- &roll_ptr);
- if (err != DB_SUCCESS) {
-
- if (UNIV_LIKELY_NULL(heap)) {
- mem_heap_free(heap);
- }
- return(err);
- }
-
- block = buf_block_align(rec);
-
- if (block->is_hashed) {
- rw_lock_x_lock(&btr_search_latch);
- }
-
- rec_set_deleted_flag(rec, rec_offs_comp(offsets), val);
-
- trx = thr_get_trx(thr);
-
- if (!(flags & BTR_KEEP_SYS_FLAG)) {
- row_upd_rec_sys_fields(rec, index, offsets, trx, roll_ptr);
- }
-
- if (block->is_hashed) {
- rw_lock_x_unlock(&btr_search_latch);
- }
-
- btr_cur_del_mark_set_clust_rec_log(flags, rec, index, val, trx,
- roll_ptr, mtr);
- if (UNIV_LIKELY_NULL(heap)) {
- mem_heap_free(heap);
- }
- return(DB_SUCCESS);
-}
-
-/********************************************************************
-Writes the redo log record for a delete mark setting of a secondary
-index record. */
-UNIV_INLINE
-void
-btr_cur_del_mark_set_sec_rec_log(
-/*=============================*/
- rec_t* rec, /* in: record */
- ibool val, /* in: value to set */
- mtr_t* mtr) /* in: mtr */
-{
- byte* log_ptr;
- ut_ad(val <= 1);
-
- log_ptr = mlog_open(mtr, 11 + 1 + 2);
-
- if (!log_ptr) {
- /* Logging in mtr is switched off during crash recovery:
- in that case mlog_open returns NULL */
- return;
- }
-
- log_ptr = mlog_write_initial_log_record_fast(
- rec, MLOG_REC_SEC_DELETE_MARK, log_ptr, mtr);
- mach_write_to_1(log_ptr, val);
- log_ptr++;
-
- mach_write_to_2(log_ptr, page_offset(rec));
- log_ptr += 2;
-
- mlog_close(mtr, log_ptr);
-}
-
-/********************************************************************
-Parses the redo log record for delete marking or unmarking of a secondary
-index record. */
-
-byte*
-btr_cur_parse_del_mark_set_sec_rec(
-/*===============================*/
- /* out: end of log record or NULL */
- byte* ptr, /* in: buffer */
- byte* end_ptr,/* in: buffer end */
- page_t* page) /* in: page or NULL */
-{
- ulint val;
- ulint offset;
- rec_t* rec;
-
- if (end_ptr < ptr + 3) {
-
- return(NULL);
- }
-
- val = mach_read_from_1(ptr);
- ptr++;
-
- offset = mach_read_from_2(ptr);
- ptr += 2;
-
- ut_a(offset <= UNIV_PAGE_SIZE);
-
- if (page) {
- rec = page + offset;
-
- /* We do not need to reserve btr_search_latch, as the page
- is only being recovered, and there cannot be a hash index to
- it. */
-
- rec_set_deleted_flag(rec, page_is_comp(page), val);
- }
-
- return(ptr);
-}
-
-/***************************************************************
-Sets a secondary index record delete mark to TRUE or FALSE. */
-
-ulint
-btr_cur_del_mark_set_sec_rec(
-/*=========================*/
- /* out: DB_SUCCESS, DB_LOCK_WAIT, or error
- number */
- ulint flags, /* in: locking flag */
- btr_cur_t* cursor, /* in: cursor */
- ibool val, /* in: value to set */
- que_thr_t* thr, /* in: query thread */
- mtr_t* mtr) /* in: mtr */
-{
- buf_block_t* block;
- rec_t* rec;
- ulint err;
-
- rec = btr_cur_get_rec(cursor);
-
-#ifdef UNIV_DEBUG
- if (btr_cur_print_record_ops && thr) {
- btr_cur_trx_report(thr_get_trx(thr), cursor->index,
- "del mark ");
- rec_print(stderr, rec, cursor->index);
- }
-#endif /* UNIV_DEBUG */
-
- err = lock_sec_rec_modify_check_and_lock(flags, rec, cursor->index,
- thr);
- if (err != DB_SUCCESS) {
-
- return(err);
- }
-
- block = buf_block_align(rec);
- ut_ad(!!page_is_comp(buf_block_get_frame(block))
- == dict_table_is_comp(cursor->index->table));
-
- if (block->is_hashed) {
- rw_lock_x_lock(&btr_search_latch);
- }
-
- rec_set_deleted_flag(rec, page_is_comp(buf_block_get_frame(block)),
- val);
-
- if (block->is_hashed) {
- rw_lock_x_unlock(&btr_search_latch);
- }
-
- btr_cur_del_mark_set_sec_rec_log(rec, val, mtr);
-
- return(DB_SUCCESS);
-}
-
-/***************************************************************
-Sets a secondary index record delete mark to FALSE. This function is only
-used by the insert buffer insert merge mechanism. */
-
-void
-btr_cur_del_unmark_for_ibuf(
-/*========================*/
- rec_t* rec, /* in: record to delete unmark */
- mtr_t* mtr) /* in: mtr */
-{
- /* We do not need to reserve btr_search_latch, as the page has just
- been read to the buffer pool and there cannot be a hash index to it. */
-
- rec_set_deleted_flag(rec, page_is_comp(buf_frame_align(rec)), FALSE);
-
- btr_cur_del_mark_set_sec_rec_log(rec, FALSE, mtr);
-}
-
-/*==================== B-TREE RECORD REMOVE =========================*/
-
-/*****************************************************************
-Tries to compress a page of the tree on the leaf level. It is assumed
-that mtr holds an x-latch on the tree and on the cursor page. To avoid
-deadlocks, mtr must also own x-latches to brothers of page, if those
-brothers exist. NOTE: it is assumed that the caller has reserved enough
-free extents so that the compression will always succeed if done! */
-
-void
-btr_cur_compress(
-/*=============*/
- btr_cur_t* cursor, /* in: cursor on the page to compress;
- cursor does not stay valid */
- mtr_t* mtr) /* in: mtr */
-{
- ut_ad(mtr_memo_contains(mtr,
- dict_index_get_lock(btr_cur_get_index(cursor)),
- MTR_MEMO_X_LOCK));
- ut_ad(mtr_memo_contains(mtr, buf_block_align(btr_cur_get_rec(cursor)),
- MTR_MEMO_PAGE_X_FIX));
- ut_ad(btr_page_get_level(btr_cur_get_page(cursor), mtr) == 0);
-
- btr_compress(cursor, mtr);
-}
-
-/*****************************************************************
-Tries to compress a page of the tree if it seems useful. It is assumed
-that mtr holds an x-latch on the tree and on the cursor page. To avoid
-deadlocks, mtr must also own x-latches to brothers of page, if those
-brothers exist. NOTE: it is assumed that the caller has reserved enough
-free extents so that the compression will always succeed if done! */
-
-ibool
-btr_cur_compress_if_useful(
-/*=======================*/
- /* out: TRUE if compression occurred */
- btr_cur_t* cursor, /* in: cursor on the page to compress;
- cursor does not stay valid if compression
- occurs */
- mtr_t* mtr) /* in: mtr */
-{
- ut_ad(mtr_memo_contains(mtr,
- dict_index_get_lock(btr_cur_get_index(cursor)),
- MTR_MEMO_X_LOCK));
- ut_ad(mtr_memo_contains(mtr, buf_block_align(btr_cur_get_rec(cursor)),
- MTR_MEMO_PAGE_X_FIX));
-
- if (btr_cur_compress_recommendation(cursor, mtr)) {
-
- btr_compress(cursor, mtr);
-
- return(TRUE);
- }
-
- return(FALSE);
-}
-
-/***********************************************************
-Removes the record on which the tree cursor is positioned on a leaf page.
-It is assumed that the mtr has an x-latch on the page where the cursor is
-positioned, but no latch on the whole tree. */
-
-ibool
-btr_cur_optimistic_delete(
-/*======================*/
- /* out: TRUE if success, i.e., the page
- did not become too empty */
- btr_cur_t* cursor, /* in: cursor on leaf page, on the record to
- delete; cursor stays valid: if deletion
- succeeds, on function exit it points to the
- successor of the deleted record */
- mtr_t* mtr) /* in: mtr */
-{
- page_t* page;
- ulint max_ins_size;
- rec_t* rec;
- mem_heap_t* heap = NULL;
- ulint offsets_[REC_OFFS_NORMAL_SIZE];
- ulint* offsets = offsets_;
- ibool no_compress_needed;
- *offsets_ = (sizeof offsets_) / sizeof *offsets_;
-
- ut_ad(mtr_memo_contains(mtr, buf_block_align(btr_cur_get_rec(cursor)),
- MTR_MEMO_PAGE_X_FIX));
- /* This is intended only for leaf page deletions */
-
- page = btr_cur_get_page(cursor);
-
- ut_ad(btr_page_get_level(page, mtr) == 0);
-
- rec = btr_cur_get_rec(cursor);
- offsets = rec_get_offsets(rec, cursor->index, offsets,
- ULINT_UNDEFINED, &heap);
-
- no_compress_needed = !rec_offs_any_extern(offsets)
- && btr_cur_can_delete_without_compress(
- cursor, rec_offs_size(offsets), mtr);
-
- if (no_compress_needed) {
-
- lock_update_delete(rec);
-
- btr_search_update_hash_on_delete(cursor);
-
- max_ins_size = page_get_max_insert_size_after_reorganize(
- page, 1);
- page_cur_delete_rec(btr_cur_get_page_cur(cursor),
- cursor->index, offsets, mtr);
-
- ibuf_update_free_bits_low(cursor->index, page, max_ins_size,
- mtr);
- }
-
- if (UNIV_LIKELY_NULL(heap)) {
- mem_heap_free(heap);
- }
-
- return(no_compress_needed);
-}
-
-/*****************************************************************
-Removes the record on which the tree cursor is positioned. Tries
-to compress the page if its fillfactor drops below a threshold
-or if it is the only page on the level. It is assumed that mtr holds
-an x-latch on the tree and on the cursor page. To avoid deadlocks,
-mtr must also own x-latches to brothers of page, if those brothers
-exist. */
-
-ibool
-btr_cur_pessimistic_delete(
-/*=======================*/
- /* out: TRUE if compression occurred */
- ulint* err, /* out: DB_SUCCESS or DB_OUT_OF_FILE_SPACE;
- the latter may occur because we may have
- to update node pointers on upper levels,
- and in the case of variable length keys
- these may actually grow in size */
- ibool has_reserved_extents, /* in: TRUE if the
- caller has already reserved enough free
- extents so that he knows that the operation
- will succeed */
- btr_cur_t* cursor, /* in: cursor on the record to delete;
- if compression does not occur, the cursor
- stays valid: it points to successor of
- deleted record on function exit */
- ibool in_rollback,/* in: TRUE if called in rollback */
- mtr_t* mtr) /* in: mtr */
-{
- page_t* page;
- dict_index_t* index;
- rec_t* rec;
- dtuple_t* node_ptr;
- ulint n_extents = 0;
- ulint n_reserved;
- ibool success;
- ibool ret = FALSE;
- ulint level;
- mem_heap_t* heap;
- ulint* offsets;
-
- page = btr_cur_get_page(cursor);
- index = btr_cur_get_index(cursor);
-
- ut_ad(mtr_memo_contains(mtr, dict_index_get_lock(index),
- MTR_MEMO_X_LOCK));
- ut_ad(mtr_memo_contains(mtr, buf_block_align(page),
- MTR_MEMO_PAGE_X_FIX));
- if (!has_reserved_extents) {
- /* First reserve enough free space for the file segments
- of the index tree, so that the node pointer updates will
- not fail because of lack of space */
-
- n_extents = cursor->tree_height / 32 + 1;
-
- success = fsp_reserve_free_extents(&n_reserved,
- index->space,
- n_extents,
- FSP_CLEANING, mtr);
- if (!success) {
- *err = DB_OUT_OF_FILE_SPACE;
-
- return(FALSE);
- }
- }
-
- heap = mem_heap_create(1024);
- rec = btr_cur_get_rec(cursor);
-
- offsets = rec_get_offsets(rec, index, NULL, ULINT_UNDEFINED, &heap);
-
- /* Free externally stored fields if the record is neither
- a node pointer nor in two-byte format.
- This avoids an unnecessary loop. */
- if (page_is_comp(page)
- ? !rec_get_node_ptr_flag(rec)
- : !rec_get_1byte_offs_flag(rec)) {
- btr_rec_free_externally_stored_fields(index,
- rec, offsets,
- in_rollback, mtr);
- }
-
- if (UNIV_UNLIKELY(page_get_n_recs(page) < 2)
- && UNIV_UNLIKELY(dict_index_get_page(btr_cur_get_index(cursor))
- != buf_frame_get_page_no(page))) {
-
- /* If there is only one record, drop the whole page in
- btr_discard_page, if this is not the root page */
-
- btr_discard_page(cursor, mtr);
-
- *err = DB_SUCCESS;
- ret = TRUE;
-
- goto return_after_reservations;
- }
-
- lock_update_delete(rec);
- level = btr_page_get_level(page, mtr);
-
- if (level > 0
- && UNIV_UNLIKELY(rec == page_rec_get_next(
- page_get_infimum_rec(page)))) {
-
- rec_t* next_rec = page_rec_get_next(rec);
-
- if (btr_page_get_prev(page, mtr) == FIL_NULL) {
-
- /* If we delete the leftmost node pointer on a
- non-leaf level, we must mark the new leftmost node
- pointer as the predefined minimum record */
-
- btr_set_min_rec_mark(next_rec, page_is_comp(page),
- mtr);
- } else {
- /* Otherwise, if we delete the leftmost node pointer
- on a page, we have to change the father node pointer
- so that it is equal to the new leftmost node pointer
- on the page */
-
- btr_node_ptr_delete(index, page, mtr);
-
- node_ptr = dict_index_build_node_ptr(
- index, next_rec, buf_frame_get_page_no(page),
- heap, level);
-
- btr_insert_on_non_leaf_level(index,
- level + 1, node_ptr, mtr);
- }
- }
-
- btr_search_update_hash_on_delete(cursor);
-
- page_cur_delete_rec(btr_cur_get_page_cur(cursor), index, offsets, mtr);
-
- ut_ad(btr_check_node_ptr(index, page, mtr));
-
- *err = DB_SUCCESS;
-
-return_after_reservations:
- mem_heap_free(heap);
-
- if (ret == FALSE) {
- ret = btr_cur_compress_if_useful(cursor, mtr);
- }
-
- if (n_extents > 0) {
- fil_space_release_free_extents(index->space, n_reserved);
- }
-
- return(ret);
-}
-
-/***********************************************************************
-Adds path information to the cursor for the current page, for which
-the binary search has been performed. */
-static
-void
-btr_cur_add_path_info(
-/*==================*/
- btr_cur_t* cursor, /* in: cursor positioned on a page */
- ulint height, /* in: height of the page in tree;
- 0 means leaf node */
- ulint root_height) /* in: root node height in tree */
-{
- btr_path_t* slot;
- rec_t* rec;
-
- ut_a(cursor->path_arr);
-
- if (root_height >= BTR_PATH_ARRAY_N_SLOTS - 1) {
- /* Do nothing; return empty path */
-
- slot = cursor->path_arr;
- slot->nth_rec = ULINT_UNDEFINED;
-
- return;
- }
-
- if (height == 0) {
- /* Mark end of slots for path */
- slot = cursor->path_arr + root_height + 1;
- slot->nth_rec = ULINT_UNDEFINED;
- }
-
- rec = btr_cur_get_rec(cursor);
-
- slot = cursor->path_arr + (root_height - height);
-
- slot->nth_rec = page_rec_get_n_recs_before(rec);
- slot->n_recs = page_get_n_recs(buf_frame_align(rec));
-}
-
-/***********************************************************************
-Estimates the number of rows in a given index range. */
-
-ib_longlong
-btr_estimate_n_rows_in_range(
-/*=========================*/
- /* out: estimated number of rows */
- dict_index_t* index, /* in: index */
- dtuple_t* tuple1, /* in: range start, may also be empty tuple */
- ulint mode1, /* in: search mode for range start */
- dtuple_t* tuple2, /* in: range end, may also be empty tuple */
- ulint mode2) /* in: search mode for range end */
-{
- btr_path_t path1[BTR_PATH_ARRAY_N_SLOTS];
- btr_path_t path2[BTR_PATH_ARRAY_N_SLOTS];
- btr_cur_t cursor;
- btr_path_t* slot1;
- btr_path_t* slot2;
- ibool diverged;
- ibool diverged_lot;
- ulint divergence_level;
- ib_longlong n_rows;
- ulint i;
- mtr_t mtr;
-
- mtr_start(&mtr);
-
- cursor.path_arr = path1;
-
- if (dtuple_get_n_fields(tuple1) > 0) {
-
- btr_cur_search_to_nth_level(index, 0, tuple1, mode1,
- BTR_SEARCH_LEAF | BTR_ESTIMATE,
- &cursor, 0, &mtr);
- } else {
- btr_cur_open_at_index_side(TRUE, index,
- BTR_SEARCH_LEAF | BTR_ESTIMATE,
- &cursor, &mtr);
- }
-
- mtr_commit(&mtr);
-
- mtr_start(&mtr);
-
- cursor.path_arr = path2;
-
- if (dtuple_get_n_fields(tuple2) > 0) {
-
- btr_cur_search_to_nth_level(index, 0, tuple2, mode2,
- BTR_SEARCH_LEAF | BTR_ESTIMATE,
- &cursor, 0, &mtr);
- } else {
- btr_cur_open_at_index_side(FALSE, index,
- BTR_SEARCH_LEAF | BTR_ESTIMATE,
- &cursor, &mtr);
- }
-
- mtr_commit(&mtr);
-
- /* We have the path information for the range in path1 and path2 */
-
- n_rows = 1;
- diverged = FALSE; /* This becomes true when the path is not
- the same any more */
- diverged_lot = FALSE; /* This becomes true when the paths are
- not the same or adjacent any more */
- divergence_level = 1000000; /* This is the level where paths diverged
- a lot */
- for (i = 0; ; i++) {
- ut_ad(i < BTR_PATH_ARRAY_N_SLOTS);
-
- slot1 = path1 + i;
- slot2 = path2 + i;
-
- if (slot1->nth_rec == ULINT_UNDEFINED
- || slot2->nth_rec == ULINT_UNDEFINED) {
-
- if (i > divergence_level + 1) {
- /* In trees whose height is > 1 our algorithm
- tends to underestimate: multiply the estimate
- by 2: */
-
- n_rows = n_rows * 2;
- }
-
- /* Do not estimate the number of rows in the range
- to over 1 / 2 of the estimated rows in the whole
- table */
-
- if (n_rows > index->table->stat_n_rows / 2) {
- n_rows = index->table->stat_n_rows / 2;
-
- /* If there are just 0 or 1 rows in the table,
- then we estimate all rows are in the range */
-
- if (n_rows == 0) {
- n_rows = index->table->stat_n_rows;
- }
- }
-
- return(n_rows);
- }
-
- if (!diverged && slot1->nth_rec != slot2->nth_rec) {
-
- diverged = TRUE;
-
- if (slot1->nth_rec < slot2->nth_rec) {
- n_rows = slot2->nth_rec - slot1->nth_rec;
-
- if (n_rows > 1) {
- diverged_lot = TRUE;
- divergence_level = i;
- }
- } else {
- /* Maybe the tree has changed between
- searches */
-
- return(10);
- }
-
- } else if (diverged && !diverged_lot) {
-
- if (slot1->nth_rec < slot1->n_recs
- || slot2->nth_rec > 1) {
-
- diverged_lot = TRUE;
- divergence_level = i;
-
- n_rows = 0;
-
- if (slot1->nth_rec < slot1->n_recs) {
- n_rows += slot1->n_recs
- - slot1->nth_rec;
- }
-
- if (slot2->nth_rec > 1) {
- n_rows += slot2->nth_rec - 1;
- }
- }
- } else if (diverged_lot) {
-
- n_rows = (n_rows * (slot1->n_recs + slot2->n_recs))
- / 2;
- }
- }
-}
-
-/***********************************************************************
-Estimates the number of different key values in a given index, for
-each n-column prefix of the index where n <= dict_index_get_n_unique(index).
-The estimates are stored in the array index->stat_n_diff_key_vals. */
-
-void
-btr_estimate_number_of_different_key_vals(
-/*======================================*/
- dict_index_t* index) /* in: index */
-{
- btr_cur_t cursor;
- page_t* page;
- rec_t* rec;
- ulint n_cols;
- ulint matched_fields;
- ulint matched_bytes;
- ib_longlong* n_diff;
- ulint not_empty_flag = 0;
- ulint total_external_size = 0;
- ulint i;
- ulint j;
- ulint add_on;
- mtr_t mtr;
- mem_heap_t* heap = NULL;
- ulint offsets_rec_[REC_OFFS_NORMAL_SIZE];
- ulint offsets_next_rec_[REC_OFFS_NORMAL_SIZE];
- ulint* offsets_rec = offsets_rec_;
- ulint* offsets_next_rec= offsets_next_rec_;
- *offsets_rec_ = (sizeof offsets_rec_) / sizeof *offsets_rec_;
- *offsets_next_rec_
- = (sizeof offsets_next_rec_) / sizeof *offsets_next_rec_;
-
- n_cols = dict_index_get_n_unique(index);
-
- n_diff = mem_alloc((n_cols + 1) * sizeof(ib_longlong));
-
- memset(n_diff, 0, (n_cols + 1) * sizeof(ib_longlong));
-
- /* We sample some pages in the index to get an estimate */
-
- for (i = 0; i < BTR_KEY_VAL_ESTIMATE_N_PAGES; i++) {
- rec_t* supremum;
- mtr_start(&mtr);
-
- btr_cur_open_at_rnd_pos(index, BTR_SEARCH_LEAF, &cursor, &mtr);
-
- /* Count the number of different key values for each prefix of
- the key on this index page. If the prefix does not determine
- the index record uniquely in te B-tree, then we subtract one
- because otherwise our algorithm would give a wrong estimate
- for an index where there is just one key value. */
-
- page = btr_cur_get_page(&cursor);
-
- supremum = page_get_supremum_rec(page);
- rec = page_rec_get_next(page_get_infimum_rec(page));
-
- if (rec != supremum) {
- not_empty_flag = 1;
- offsets_rec = rec_get_offsets(rec, index, offsets_rec,
- ULINT_UNDEFINED, &heap);
- }
-
- while (rec != supremum) {
- rec_t* next_rec = page_rec_get_next(rec);
- if (next_rec == supremum) {
- break;
- }
-
- matched_fields = 0;
- matched_bytes = 0;
- offsets_next_rec = rec_get_offsets(next_rec, index,
- offsets_next_rec,
- n_cols, &heap);
-
- cmp_rec_rec_with_match(rec, next_rec,
- offsets_rec, offsets_next_rec,
- index, &matched_fields,
- &matched_bytes);
-
- for (j = matched_fields + 1; j <= n_cols; j++) {
- /* We add one if this index record has
- a different prefix from the previous */
-
- n_diff[j]++;
- }
-
- total_external_size
- += btr_rec_get_externally_stored_len(
- rec, offsets_rec);
-
- rec = next_rec;
- /* Initialize offsets_rec for the next round
- and assign the old offsets_rec buffer to
- offsets_next_rec. */
- {
- ulint* offsets_tmp = offsets_rec;
- offsets_rec = offsets_next_rec;
- offsets_next_rec = offsets_tmp;
- }
- }
-
-
- if (n_cols == dict_index_get_n_unique_in_tree(index)) {
-
- /* If there is more than one leaf page in the tree,
- we add one because we know that the first record
- on the page certainly had a different prefix than the
- last record on the previous index page in the
- alphabetical order. Before this fix, if there was
- just one big record on each clustered index page, the
- algorithm grossly underestimated the number of rows
- in the table. */
-
- if (btr_page_get_prev(page, &mtr) != FIL_NULL
- || btr_page_get_next(page, &mtr) != FIL_NULL) {
-
- n_diff[n_cols]++;
- }
- }
-
- offsets_rec = rec_get_offsets(rec, index, offsets_rec,
- ULINT_UNDEFINED, &heap);
- total_external_size += btr_rec_get_externally_stored_len(
- rec, offsets_rec);
- mtr_commit(&mtr);
- }
-
- /* If we saw k borders between different key values on
- BTR_KEY_VAL_ESTIMATE_N_PAGES leaf pages, we can estimate how many
- there will be in index->stat_n_leaf_pages */
-
- /* We must take into account that our sample actually represents
- also the pages used for external storage of fields (those pages are
- included in index->stat_n_leaf_pages) */
-
- for (j = 0; j <= n_cols; j++) {
- index->stat_n_diff_key_vals[j]
- = ((n_diff[j]
- * (ib_longlong)index->stat_n_leaf_pages
- + BTR_KEY_VAL_ESTIMATE_N_PAGES - 1
- + total_external_size
- + not_empty_flag)
- / (BTR_KEY_VAL_ESTIMATE_N_PAGES
- + total_external_size));
-
- /* If the tree is small, smaller than
- 10 * BTR_KEY_VAL_ESTIMATE_N_PAGES + total_external_size, then
- the above estimate is ok. For bigger trees it is common that we
- do not see any borders between key values in the few pages
- we pick. But still there may be BTR_KEY_VAL_ESTIMATE_N_PAGES
- different key values, or even more. Let us try to approximate
- that: */
-
- add_on = index->stat_n_leaf_pages
- / (10 * (BTR_KEY_VAL_ESTIMATE_N_PAGES
- + total_external_size));
-
- if (add_on > BTR_KEY_VAL_ESTIMATE_N_PAGES) {
- add_on = BTR_KEY_VAL_ESTIMATE_N_PAGES;
- }
-
- index->stat_n_diff_key_vals[j] += add_on;
- }
-
- mem_free(n_diff);
- if (UNIV_LIKELY_NULL(heap)) {
- mem_heap_free(heap);
- }
-}
-
-/*================== EXTERNAL STORAGE OF BIG FIELDS ===================*/
-
-/***************************************************************
-Gets the externally stored size of a record, in units of a database page. */
-static
-ulint
-btr_rec_get_externally_stored_len(
-/*==============================*/
- /* out: externally stored part,
- in units of a database page */
- rec_t* rec, /* in: record */
- const ulint* offsets)/* in: array returned by rec_get_offsets() */
-{
- ulint n_fields;
- byte* data;
- ulint local_len;
- ulint extern_len;
- ulint total_extern_len = 0;
- ulint i;
-
- ut_ad(!rec_offs_comp(offsets) || !rec_get_node_ptr_flag(rec));
- n_fields = rec_offs_n_fields(offsets);
-
- for (i = 0; i < n_fields; i++) {
- if (rec_offs_nth_extern(offsets, i)) {
-
- data = rec_get_nth_field(rec, offsets, i, &local_len);
-
- local_len -= BTR_EXTERN_FIELD_REF_SIZE;
-
- extern_len = mach_read_from_4(data + local_len
- + BTR_EXTERN_LEN + 4);
-
- total_extern_len += ut_calc_align(extern_len,
- UNIV_PAGE_SIZE);
- }
- }
-
- return(total_extern_len / UNIV_PAGE_SIZE);
-}
-
-/***********************************************************************
-Sets the ownership bit of an externally stored field in a record. */
-static
-void
-btr_cur_set_ownership_of_extern_field(
-/*==================================*/
- rec_t* rec, /* in: clustered index record */
- const ulint* offsets,/* in: array returned by rec_get_offsets() */
- ulint i, /* in: field number */
- ibool val, /* in: value to set */
- mtr_t* mtr) /* in: mtr */
-{
- byte* data;
- ulint local_len;
- ulint byte_val;
-
- data = rec_get_nth_field(rec, offsets, i, &local_len);
-
- ut_a(local_len >= BTR_EXTERN_FIELD_REF_SIZE);
-
- local_len -= BTR_EXTERN_FIELD_REF_SIZE;
-
- byte_val = mach_read_from_1(data + local_len + BTR_EXTERN_LEN);
-
- if (val) {
- byte_val = byte_val & (~BTR_EXTERN_OWNER_FLAG);
- } else {
- byte_val = byte_val | BTR_EXTERN_OWNER_FLAG;
- }
-
- mlog_write_ulint(data + local_len + BTR_EXTERN_LEN, byte_val,
- MLOG_1BYTE, mtr);
-}
-
-/***********************************************************************
-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
-index tree. In purge only the owner of externally stored field is allowed
-to free the field. */
-
-void
-btr_cur_mark_extern_inherited_fields(
-/*=================================*/
- rec_t* rec, /* in: record in a clustered index */
- const ulint* offsets,/* in: array returned by rec_get_offsets() */
- upd_t* update, /* in: update vector */
- mtr_t* mtr) /* in: mtr */
-{
- ibool is_updated;
- ulint n;
- ulint j;
- ulint i;
-
- ut_ad(rec_offs_validate(rec, NULL, offsets));
- ut_ad(!rec_offs_comp(offsets) || !rec_get_node_ptr_flag(rec));
- 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 */
- is_updated = FALSE;
-
- if (update) {
- for (j = 0; j < upd_get_n_fields(update);
- j++) {
- if (upd_get_nth_field(update, j)
- ->field_no == i) {
- is_updated = TRUE;
- }
- }
- }
-
- if (!is_updated) {
- btr_cur_set_ownership_of_extern_field(
- rec, offsets, i, FALSE, mtr);
- }
- }
- }
-}
-
-/***********************************************************************
-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. */
-
-void
-btr_cur_mark_dtuple_inherited_extern(
-/*=================================*/
- dtuple_t* entry, /* in: updated entry to be inserted to
- clustered index */
- ulint* ext_vec, /* in: array of extern fields in the
- original record */
- ulint n_ext_vec, /* in: number of elements in ext_vec */
- upd_t* update) /* in: update vector */
-{
- dfield_t* dfield;
- ulint byte_val;
- byte* data;
- ulint len;
- ibool is_updated;
- ulint j;
- ulint i;
-
- if (ext_vec == NULL) {
-
- return;
- }
-
- for (i = 0; i < n_ext_vec; i++) {
-
- /* Check ext_vec[i] is in updated fields */
- is_updated = FALSE;
-
- for (j = 0; j < upd_get_n_fields(update); j++) {
- if (upd_get_nth_field(update, j)->field_no
- == ext_vec[i]) {
- is_updated = TRUE;
- }
- }
-
- if (!is_updated) {
- dfield = dtuple_get_nth_field(entry, ext_vec[i]);
-
- data = (byte*) dfield_get_data(dfield);
- len = dfield_get_len(dfield);
-
- len -= BTR_EXTERN_FIELD_REF_SIZE;
-
- byte_val = mach_read_from_1(data + len
- + BTR_EXTERN_LEN);
-
- byte_val = byte_val | BTR_EXTERN_INHERITED_FLAG;
-
- mach_write_to_1(data + len + BTR_EXTERN_LEN, byte_val);
- }
- }
-}
-
-/***********************************************************************
-Marks all extern fields in a record as owned by the record. This function
-should be called if the delete mark of a record is removed: a not delete
-marked record always owns all its extern fields. */
-static
-void
-btr_cur_unmark_extern_fields(
-/*=========================*/
- rec_t* rec, /* in: record in a clustered index */
- mtr_t* mtr, /* in: mtr */
- const ulint* offsets)/* in: array returned by rec_get_offsets() */
-{
- ulint n;
- ulint i;
-
- ut_ad(!rec_offs_comp(offsets) || !rec_get_node_ptr_flag(rec));
- n = rec_offs_n_fields(offsets);
-
- for (i = 0; i < n; i++) {
- if (rec_offs_nth_extern(offsets, i)) {
-
- btr_cur_set_ownership_of_extern_field(rec, offsets, i,
- TRUE, mtr);
- }
- }
-}
-
-/***********************************************************************
-Marks all extern fields in a dtuple as owned by the record. */
-
-void
-btr_cur_unmark_dtuple_extern_fields(
-/*================================*/
- dtuple_t* entry, /* in: clustered index entry */
- ulint* ext_vec, /* in: array of numbers of fields
- which have been stored externally */
- ulint n_ext_vec) /* in: number of elements in ext_vec */
-{
- dfield_t* dfield;
- ulint byte_val;
- byte* data;
- ulint len;
- ulint i;
-
- for (i = 0; i < n_ext_vec; i++) {
- dfield = dtuple_get_nth_field(entry, ext_vec[i]);
-
- data = (byte*) dfield_get_data(dfield);
- len = dfield_get_len(dfield);
-
- len -= BTR_EXTERN_FIELD_REF_SIZE;
-
- byte_val = mach_read_from_1(data + len + BTR_EXTERN_LEN);
-
- byte_val = byte_val & (~BTR_EXTERN_OWNER_FLAG);
-
- mach_write_to_1(data + len + BTR_EXTERN_LEN, byte_val);
- }
-}
-
-/***********************************************************************
-Stores the positions of the fields marked as extern storage in the update
-vector, and also those fields who are marked as extern storage in rec
-and not mentioned in updated fields. We use this function to remember
-which fields we must mark as extern storage in a record inserted for an
-update. */
-
-ulint
-btr_push_update_extern_fields(
-/*==========================*/
- /* out: number of values stored in ext_vect */
- ulint* ext_vect,/* in: array of ulints, must be preallocated
- to have space for all fields in rec */
- const ulint* offsets,/* in: array returned by rec_get_offsets() */
- upd_t* update) /* in: update vector or NULL */
-{
- ulint n_pushed = 0;
- ibool is_updated;
- ulint n;
- ulint j;
- ulint i;
-
- if (update) {
- n = upd_get_n_fields(update);
-
- for (i = 0; i < n; i++) {
-
- if (upd_get_nth_field(update, i)->extern_storage) {
-
- ext_vect[n_pushed] = upd_get_nth_field(
- update, i)->field_no;
-
- n_pushed++;
- }
- }
- }
-
- 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 */
- is_updated = FALSE;
-
- if (update) {
- for (j = 0; j < upd_get_n_fields(update);
- j++) {
- if (upd_get_nth_field(update, j)
- ->field_no == i) {
- is_updated = TRUE;
- }
- }
- }
-
- if (!is_updated) {
- ext_vect[n_pushed] = i;
- n_pushed++;
- }
- }
- }
-
- return(n_pushed);
-}
-
-/***********************************************************************
-Returns the length of a BLOB part stored on the header page. */
-static
-ulint
-btr_blob_get_part_len(
-/*==================*/
- /* out: part length */
- byte* blob_header) /* in: blob header */
-{
- return(mach_read_from_4(blob_header + BTR_BLOB_HDR_PART_LEN));
-}
-
-/***********************************************************************
-Returns the page number where the next BLOB part is stored. */
-static
-ulint
-btr_blob_get_next_page_no(
-/*======================*/
- /* out: page number or FIL_NULL if
- no more pages */
- byte* blob_header) /* in: blob header */
-{
- return(mach_read_from_4(blob_header + BTR_BLOB_HDR_NEXT_PAGE_NO));
-}
-
-/***********************************************************************
-Stores the fields in big_rec_vec to the tablespace and puts pointers to
-them in rec. The fields are stored on pages allocated from leaf node
-file segment of the index tree. */
-
-ulint
-btr_store_big_rec_extern_fields(
-/*============================*/
- /* out: DB_SUCCESS or error */
- dict_index_t* index, /* in: index of rec; the index tree
- MUST be X-latched */
- rec_t* rec, /* in: record */
- const ulint* offsets, /* in: rec_get_offsets(rec, index);
- the "external storage" flags in offsets
- will not correspond to rec when
- this function returns */
- big_rec_t* big_rec_vec, /* in: vector containing fields
- to be stored externally */
- mtr_t* local_mtr __attribute__((unused))) /* in: mtr
- containing the latch to rec and to the
- tree */
-{
- byte* data;
- ulint local_len;
- ulint extern_len;
- ulint store_len;
- ulint page_no;
- page_t* page;
- ulint space_id;
- page_t* prev_page;
- page_t* rec_page;
- ulint prev_page_no;
- ulint hint_page_no;
- ulint i;
- mtr_t mtr;
-
- ut_ad(rec_offs_validate(rec, index, offsets));
- ut_ad(mtr_memo_contains(local_mtr, dict_index_get_lock(index),
- MTR_MEMO_X_LOCK));
- ut_ad(mtr_memo_contains(local_mtr, buf_block_align(rec),
- MTR_MEMO_PAGE_X_FIX));
- ut_a(index->type & DICT_CLUSTERED);
-
- space_id = buf_frame_get_space_id(rec);
-
- /* We have to create a file segment to the tablespace
- for each field and put the pointer to the field in rec */
-
- for (i = 0; i < big_rec_vec->n_fields; i++) {
-
- data = rec_get_nth_field(rec, offsets,
- big_rec_vec->fields[i].field_no,
- &local_len);
- ut_a(local_len >= BTR_EXTERN_FIELD_REF_SIZE);
- local_len -= BTR_EXTERN_FIELD_REF_SIZE;
- extern_len = big_rec_vec->fields[i].len;
-
- ut_a(extern_len > 0);
-
- prev_page_no = FIL_NULL;
-
- while (extern_len > 0) {
- mtr_start(&mtr);
-
- if (prev_page_no == FIL_NULL) {
- hint_page_no = buf_frame_get_page_no(rec) + 1;
- } else {
- hint_page_no = prev_page_no + 1;
- }
-
- page = btr_page_alloc(index, hint_page_no,
- FSP_NO_DIR, 0, &mtr);
- if (page == NULL) {
-
- mtr_commit(&mtr);
-
- return(DB_OUT_OF_FILE_SPACE);
- }
-
- mlog_write_ulint(page + FIL_PAGE_TYPE,
- FIL_PAGE_TYPE_BLOB,
- MLOG_2BYTES, &mtr);
-
- page_no = buf_frame_get_page_no(page);
-
- if (prev_page_no != FIL_NULL) {
- prev_page = buf_page_get(space_id,
- prev_page_no,
- RW_X_LATCH, &mtr);
-
-#ifdef UNIV_SYNC_DEBUG
- buf_page_dbg_add_level(prev_page,
- SYNC_EXTERN_STORAGE);
-#endif /* UNIV_SYNC_DEBUG */
-
- mlog_write_ulint(prev_page + FIL_PAGE_DATA
- + BTR_BLOB_HDR_NEXT_PAGE_NO,
- page_no, MLOG_4BYTES, &mtr);
- }
-
- if (extern_len > (UNIV_PAGE_SIZE - FIL_PAGE_DATA
- - BTR_BLOB_HDR_SIZE
- - FIL_PAGE_DATA_END)) {
- store_len = UNIV_PAGE_SIZE - FIL_PAGE_DATA
- - BTR_BLOB_HDR_SIZE
- - FIL_PAGE_DATA_END;
- } else {
- store_len = extern_len;
- }
-
- mlog_write_string(page + FIL_PAGE_DATA
- + BTR_BLOB_HDR_SIZE,
- big_rec_vec->fields[i].data
- + big_rec_vec->fields[i].len
- - extern_len,
- store_len, &mtr);
- mlog_write_ulint(page + FIL_PAGE_DATA
- + BTR_BLOB_HDR_PART_LEN,
- store_len, MLOG_4BYTES, &mtr);
- mlog_write_ulint(page + FIL_PAGE_DATA
- + BTR_BLOB_HDR_NEXT_PAGE_NO,
- FIL_NULL, MLOG_4BYTES, &mtr);
-
- extern_len -= store_len;
-
- rec_page = buf_page_get(space_id,
- buf_frame_get_page_no(data),
- RW_X_LATCH, &mtr);
-#ifdef UNIV_SYNC_DEBUG
- buf_page_dbg_add_level(rec_page, SYNC_NO_ORDER_CHECK);
-#endif /* UNIV_SYNC_DEBUG */
- mlog_write_ulint(data + local_len + BTR_EXTERN_LEN, 0,
- MLOG_4BYTES, &mtr);
- mlog_write_ulint(data + local_len + BTR_EXTERN_LEN + 4,
- big_rec_vec->fields[i].len
- - extern_len,
- MLOG_4BYTES, &mtr);
-
- if (prev_page_no == FIL_NULL) {
- mlog_write_ulint(data + local_len
- + BTR_EXTERN_SPACE_ID,
- space_id,
- MLOG_4BYTES, &mtr);
-
- mlog_write_ulint(data + local_len
- + BTR_EXTERN_PAGE_NO,
- page_no,
- MLOG_4BYTES, &mtr);
-
- mlog_write_ulint(data + local_len
- + BTR_EXTERN_OFFSET,
- FIL_PAGE_DATA,
- MLOG_4BYTES, &mtr);
-
- /* Set the bit denoting that this field
- in rec is stored externally */
-
- rec_set_nth_field_extern_bit(
- rec, index,
- big_rec_vec->fields[i].field_no,
- TRUE, &mtr);
- }
-
- prev_page_no = page_no;
-
- mtr_commit(&mtr);
- }
- }
-
- return(DB_SUCCESS);
-}
-
-/***********************************************************************
-Frees the space in an externally stored field to the file space
-management if the field in data is owned the externally stored field,
-in a rollback we may have the additional condition that the field must
-not be inherited. */
-
-void
-btr_free_externally_stored_field(
-/*=============================*/
- dict_index_t* index, /* in: index of the data, the index
- tree MUST be X-latched; if the tree
- height is 1, then also the root page
- must be X-latched! (this is relevant
- in the case this function is called
- from purge where 'data' is located on
- an undo log page, not an index
- page) */
- byte* data, /* in: internally stored data
- + reference to the externally
- stored part */
- ulint local_len, /* in: length of data */
- ibool do_not_free_inherited,/* in: TRUE if called in a
- rollback and we do not want to free
- inherited fields */
- mtr_t* local_mtr __attribute__((unused))) /* in: mtr
- containing the latch to data an an
- X-latch to the index tree */
-{
- page_t* page;
- page_t* rec_page;
- ulint space_id;
- ulint page_no;
- ulint offset;
- ulint extern_len;
- ulint next_page_no;
- ulint part_len;
- mtr_t mtr;
-
- ut_a(local_len >= BTR_EXTERN_FIELD_REF_SIZE);
- ut_ad(mtr_memo_contains(local_mtr, dict_index_get_lock(index),
- MTR_MEMO_X_LOCK));
- ut_ad(mtr_memo_contains(local_mtr, buf_block_align(data),
- MTR_MEMO_PAGE_X_FIX));
- ut_a(local_len >= BTR_EXTERN_FIELD_REF_SIZE);
- local_len -= BTR_EXTERN_FIELD_REF_SIZE;
-
- for (;;) {
- mtr_start(&mtr);
-
- rec_page = buf_page_get(buf_frame_get_space_id(data),
- buf_frame_get_page_no(data),
- RW_X_LATCH, &mtr);
-#ifdef UNIV_SYNC_DEBUG
- buf_page_dbg_add_level(rec_page, SYNC_NO_ORDER_CHECK);
-#endif /* UNIV_SYNC_DEBUG */
- space_id = mach_read_from_4(data + local_len
- + BTR_EXTERN_SPACE_ID);
-
- page_no = mach_read_from_4(data + local_len
- + BTR_EXTERN_PAGE_NO);
-
- offset = mach_read_from_4(data + local_len
- + BTR_EXTERN_OFFSET);
- extern_len = mach_read_from_4(data + local_len
- + BTR_EXTERN_LEN + 4);
-
- /* If extern len is 0, then there is no external storage data
- at all */
-
- if (extern_len == 0) {
-
- mtr_commit(&mtr);
-
- return;
- }
-
- if (mach_read_from_1(data + local_len + BTR_EXTERN_LEN)
- & BTR_EXTERN_OWNER_FLAG) {
- /* This field does not own the externally
- stored field: do not free! */
-
- mtr_commit(&mtr);
-
- return;
- }
-
- if (do_not_free_inherited
- && mach_read_from_1(data + local_len + BTR_EXTERN_LEN)
- & BTR_EXTERN_INHERITED_FLAG) {
- /* Rollback and inherited field: do not free! */
-
- mtr_commit(&mtr);
-
- return;
- }
-
- page = buf_page_get(space_id, page_no, RW_X_LATCH, &mtr);
-#ifdef UNIV_SYNC_DEBUG
- buf_page_dbg_add_level(page, SYNC_EXTERN_STORAGE);
-#endif /* UNIV_SYNC_DEBUG */
- next_page_no = mach_read_from_4(page + FIL_PAGE_DATA
- + BTR_BLOB_HDR_NEXT_PAGE_NO);
-
- part_len = btr_blob_get_part_len(page + FIL_PAGE_DATA);
-
- ut_a(extern_len >= part_len);
-
- /* We must supply the page level (= 0) as an argument
- because we did not store it on the page (we save the space
- overhead from an index page header. */
-
- btr_page_free_low(index, page, 0, &mtr);
-
- mlog_write_ulint(data + local_len + BTR_EXTERN_PAGE_NO,
- next_page_no,
- MLOG_4BYTES, &mtr);
- mlog_write_ulint(data + local_len + BTR_EXTERN_LEN + 4,
- extern_len - part_len,
- MLOG_4BYTES, &mtr);
- if (next_page_no == FIL_NULL) {
- ut_a(extern_len - part_len == 0);
- }
-
- if (extern_len - part_len == 0) {
- ut_a(next_page_no == FIL_NULL);
- }
-
- mtr_commit(&mtr);
- }
-}
-
-/***************************************************************
-Frees the externally stored fields for a record. */
-
-void
-btr_rec_free_externally_stored_fields(
-/*==================================*/
- dict_index_t* index, /* in: index of the data, the index
- tree MUST be X-latched */
- rec_t* rec, /* in: record */
- const ulint* offsets,/* in: rec_get_offsets(rec, index) */
- ibool do_not_free_inherited,/* in: TRUE if called in a
- rollback and we do not want to free
- inherited fields */
- mtr_t* mtr) /* in: mini-transaction handle which contains
- an X-latch to record page and to the index
- tree */
-{
- ulint n_fields;
- byte* data;
- ulint len;
- ulint i;
-
- ut_ad(rec_offs_validate(rec, index, offsets));
- ut_ad(mtr_memo_contains(mtr, buf_block_align(rec),
- MTR_MEMO_PAGE_X_FIX));
- /* Free possible externally stored fields in the record */
-
- ut_ad(dict_table_is_comp(index->table) == !!rec_offs_comp(offsets));
- n_fields = rec_offs_n_fields(offsets);
-
- for (i = 0; i < n_fields; i++) {
- if (rec_offs_nth_extern(offsets, i)) {
-
- data = rec_get_nth_field(rec, offsets, i, &len);
- btr_free_externally_stored_field(index, data, len,
- do_not_free_inherited,
- mtr);
- }
- }
-}
-
-/***************************************************************
-Frees the externally stored fields for a record, if the field is mentioned
-in the update vector. */
-static
-void
-btr_rec_free_updated_extern_fields(
-/*===============================*/
- dict_index_t* index, /* in: index of rec; the index tree MUST be
- X-latched */
- rec_t* rec, /* in: record */
- const ulint* offsets,/* in: rec_get_offsets(rec, index) */
- upd_t* update, /* in: update vector */
- ibool do_not_free_inherited,/* in: TRUE if called in a
- rollback and we do not want to free
- inherited fields */
- mtr_t* mtr) /* in: mini-transaction handle which contains
- an X-latch to record page and to the tree */
-{
- upd_field_t* ufield;
- ulint n_fields;
- byte* data;
- ulint len;
- ulint i;
-
- ut_ad(rec_offs_validate(rec, index, offsets));
- ut_ad(mtr_memo_contains(mtr, buf_block_align(rec),
- MTR_MEMO_PAGE_X_FIX));
-
- /* Free possible externally stored fields in the record */
-
- n_fields = upd_get_n_fields(update);
-
- for (i = 0; i < n_fields; i++) {
- ufield = upd_get_nth_field(update, i);
-
- if (rec_offs_nth_extern(offsets, ufield->field_no)) {
-
- data = rec_get_nth_field(rec, offsets,
- ufield->field_no, &len);
- btr_free_externally_stored_field(index, data, len,
- do_not_free_inherited,
- mtr);
- }
- }
-}
-
-/***********************************************************************
-Copies an externally stored field of a record to mem heap. Parameter
-data contains a pointer to 'internally' stored part of the field:
-possibly some data, and the reference to the externally stored part in
-the last 20 bytes of data. */
-
-byte*
-btr_copy_externally_stored_field(
-/*=============================*/
- /* out: the whole field copied to heap */
- ulint* len, /* out: length of the whole field */
- byte* data, /* in: 'internally' stored part of the
- field containing also the reference to
- the external part */
- ulint local_len,/* in: length of data */
- mem_heap_t* heap) /* in: mem heap */
-{
- page_t* page;
- ulint space_id;
- ulint page_no;
- ulint offset;
- ulint extern_len;
- byte* blob_header;
- ulint part_len;
- byte* buf;
- ulint copied_len;
- mtr_t mtr;
-
- ut_a(local_len >= BTR_EXTERN_FIELD_REF_SIZE);
-
- local_len -= BTR_EXTERN_FIELD_REF_SIZE;
-
- space_id = mach_read_from_4(data + local_len + BTR_EXTERN_SPACE_ID);
-
- page_no = mach_read_from_4(data + local_len + BTR_EXTERN_PAGE_NO);
-
- offset = mach_read_from_4(data + local_len + BTR_EXTERN_OFFSET);
-
- /* Currently a BLOB cannot be bigger that 4 GB; we
- leave the 4 upper bytes in the length field unused */
-
- extern_len = mach_read_from_4(data + local_len + BTR_EXTERN_LEN + 4);
-
- buf = mem_heap_alloc(heap, local_len + extern_len);
-
- ut_memcpy(buf, data, local_len);
- copied_len = local_len;
-
- if (extern_len == 0) {
- *len = copied_len;
-
- return(buf);
- }
-
- for (;;) {
- mtr_start(&mtr);
-
- page = buf_page_get(space_id, page_no, RW_S_LATCH, &mtr);
-#ifdef UNIV_SYNC_DEBUG
- buf_page_dbg_add_level(page, SYNC_EXTERN_STORAGE);
-#endif /* UNIV_SYNC_DEBUG */
- blob_header = page + offset;
-
- part_len = btr_blob_get_part_len(blob_header);
-
- ut_memcpy(buf + copied_len, blob_header + BTR_BLOB_HDR_SIZE,
- part_len);
- copied_len += part_len;
-
- page_no = btr_blob_get_next_page_no(blob_header);
-
- mtr_commit(&mtr);
-
- if (page_no == FIL_NULL) {
- ut_a(copied_len == local_len + extern_len);
-
- *len = copied_len;
-
- return(buf);
- }
-
- /* On other BLOB pages except the first the BLOB header
- always is at the page data start: */
-
- offset = FIL_PAGE_DATA;
-
- ut_a(copied_len < local_len + extern_len);
- }
-}
-
-/***********************************************************************
-Copies an externally stored field of a record to mem heap. */
-
-byte*
-btr_rec_copy_externally_stored_field(
-/*=================================*/
- /* out: the field copied to heap */
- rec_t* rec, /* in: record */
- const ulint* offsets,/* in: array returned by rec_get_offsets() */
- ulint no, /* in: field number */
- ulint* len, /* out: length of the field */
- mem_heap_t* heap) /* in: mem heap */
-{
- ulint local_len;
- byte* data;
-
- ut_ad(rec_offs_validate(rec, NULL, offsets));
- ut_a(rec_offs_nth_extern(offsets, no));
-
- /* An externally stored field can contain some initial
- data from the field, and in the last 20 bytes it has the
- space id, page number, and offset where the rest of the
- field data is stored, and the data length in addition to
- the data stored locally. We may need to store some data
- locally to get the local record length above the 128 byte
- limit so that field offsets are stored in two bytes, and
- the extern bit is available in those two bytes. */
-
- data = rec_get_nth_field(rec, offsets, no, &local_len);
-
- return(btr_copy_externally_stored_field(len, data, local_len, heap));
-}
diff --git a/storage/innobase/buf/buf0buf.c b/storage/innobase/buf/buf0buf.c
deleted file mode 100644
index 5b4f0ee6ecb..00000000000
--- a/storage/innobase/buf/buf0buf.c
+++ /dev/null
@@ -1,2590 +0,0 @@
-/* Innobase relational database engine; Copyright (C) 2001 Innobase Oy
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License 2
- as published by the Free Software Foundation in June 1991.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License 2
- along with this program (in file COPYING); if not, write to the Free
- Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
-/******************************************************
-The database buffer buf_pool
-
-(c) 1995 Innobase Oy
-
-Created 11/5/1995 Heikki Tuuri
-*******************************************************/
-
-#include "buf0buf.h"
-
-#ifdef UNIV_NONINL
-#include "buf0buf.ic"
-#endif
-
-#include "mem0mem.h"
-#include "btr0btr.h"
-#include "fil0fil.h"
-#include "lock0lock.h"
-#include "btr0sea.h"
-#include "ibuf0ibuf.h"
-#include "dict0dict.h"
-#include "log0recv.h"
-#include "log0log.h"
-#include "trx0undo.h"
-#include "srv0srv.h"
-
-/*
- IMPLEMENTATION OF THE BUFFER POOL
- =================================
-
-Performance improvement:
-------------------------
-Thread scheduling in NT may be so slow that the OS wait mechanism should
-not be used even in waiting for disk reads to complete.
-Rather, we should put waiting query threads to the queue of
-waiting jobs, and let the OS thread do something useful while the i/o
-is processed. In this way we could remove most OS thread switches in
-an i/o-intensive benchmark like TPC-C.
-
-A possibility is to put a user space thread library between the database
-and NT. User space thread libraries might be very fast.
-
-SQL Server 7.0 can be configured to use 'fibers' which are lightweight
-threads in NT. These should be studied.
-
- Buffer frames and blocks
- ------------------------
-Following the terminology of Gray and Reuter, we call the memory
-blocks where file pages are loaded buffer frames. For each buffer
-frame there is a control block, or shortly, a block, in the buffer
-control array. The control info which does not need to be stored
-in the file along with the file page, resides in the control block.
-
- Buffer pool struct
- ------------------
-The buffer buf_pool contains a single mutex which protects all the
-control data structures of the buf_pool. The content of a buffer frame is
-protected by a separate read-write lock in its control block, though.
-These locks can be locked and unlocked without owning the buf_pool mutex.
-The OS events in the buf_pool struct can be waited for without owning the
-buf_pool mutex.
-
-The buf_pool mutex is a hot-spot in main memory, causing a lot of
-memory bus traffic on multiprocessor systems when processors
-alternately access the mutex. On our Pentium, the mutex is accessed
-maybe every 10 microseconds. We gave up the solution to have mutexes
-for each control block, for instance, because it seemed to be
-complicated.
-
-A solution to reduce mutex contention of the buf_pool mutex is to
-create a separate mutex for the page hash table. On Pentium,
-accessing the hash table takes 2 microseconds, about half
-of the total buf_pool mutex hold time.
-
- Control blocks
- --------------
-
-The control block contains, for instance, the bufferfix count
-which is incremented when a thread wants a file page to be fixed
-in a buffer frame. The bufferfix operation does not lock the
-contents of the frame, however. For this purpose, the control
-block contains a read-write lock.
-
-The buffer frames have to be aligned so that the start memory
-address of a frame is divisible by the universal page size, which
-is a power of two.
-
-We intend to make the buffer buf_pool size on-line reconfigurable,
-that is, the buf_pool size can be changed without closing the database.
-Then the database administarator may adjust it to be bigger
-at night, for example. The control block array must
-contain enough control blocks for the maximum buffer buf_pool size
-which is used in the particular database.
-If the buf_pool size is cut, we exploit the virtual memory mechanism of
-the OS, and just refrain from using frames at high addresses. Then the OS
-can swap them to disk.
-
-The control blocks containing file pages are put to a hash table
-according to the file address of the page.
-We could speed up the access to an individual page by using
-"pointer swizzling": we could replace the page references on
-non-leaf index pages by direct pointers to the page, if it exists
-in the buf_pool. We could make a separate hash table where we could
-chain all the page references in non-leaf pages residing in the buf_pool,
-using the page reference as the hash key,
-and at the time of reading of a page update the pointers accordingly.
-Drawbacks of this solution are added complexity and,
-possibly, extra space required on non-leaf pages for memory pointers.
-A simpler solution is just to speed up the hash table mechanism
-in the database, using tables whose size is a power of 2.
-
- Lists of blocks
- ---------------
-
-There are several lists of control blocks. The free list contains
-blocks which are currently not used.
-
-The LRU-list contains all the blocks holding a file page
-except those for which the bufferfix count is non-zero.
-The pages are in the LRU list roughly in the order of the last
-access to the page, so that the oldest pages are at the end of the
-list. We also keep a pointer to near the end of the LRU list,
-which we can use when we want to artificially age a page in the
-buf_pool. This is used if we know that some page is not needed
-again for some time: we insert the block right after the pointer,
-causing it to be replaced sooner than would noramlly be the case.
-Currently this aging mechanism is used for read-ahead mechanism
-of pages, and it can also be used when there is a scan of a full
-table which cannot fit in the memory. Putting the pages near the
-of the LRU list, we make sure that most of the buf_pool stays in the
-main memory, undisturbed.
-
-The chain of modified blocks contains the blocks
-holding file pages that have been modified in the memory
-but not written to disk yet. The block with the oldest modification
-which has not yet been written to disk is at the end of the chain.
-
- Loading a file page
- -------------------
-
-First, a victim block for replacement has to be found in the
-buf_pool. It is taken from the free list or searched for from the
-end of the LRU-list. An exclusive lock is reserved for the frame,
-the io_fix field is set in the block fixing the block in buf_pool,
-and the io-operation for loading the page is queued. The io-handler thread
-releases the X-lock on the frame and resets the io_fix field
-when the io operation completes.
-
-A thread may request the above operation using the function
-buf_page_get(). It may then continue to request a lock on the frame.
-The lock is granted when the io-handler releases the x-lock.
-
- Read-ahead
- ----------
-
-The read-ahead mechanism is intended to be intelligent and
-isolated from the semantically higher levels of the database
-index management. From the higher level we only need the
-information if a file page has a natural successor or
-predecessor page. On the leaf level of a B-tree index,
-these are the next and previous pages in the natural
-order of the pages.
-
-Let us first explain the read-ahead mechanism when the leafs
-of a B-tree are scanned in an ascending or descending order.
-When a read page is the first time referenced in the buf_pool,
-the buffer manager checks if it is at the border of a so-called
-linear read-ahead area. The tablespace is divided into these
-areas of size 64 blocks, for example. So if the page is at the
-border of such an area, the read-ahead mechanism checks if
-all the other blocks in the area have been accessed in an
-ascending or descending order. If this is the case, the system
-looks at the natural successor or predecessor of the page,
-checks if that is at the border of another area, and in this case
-issues read-requests for all the pages in that area. Maybe
-we could relax the condition that all the pages in the area
-have to be accessed: if data is deleted from a table, there may
-appear holes of unused pages in the area.
-
-A different read-ahead mechanism is used when there appears
-to be a random access pattern to a file.
-If a new page is referenced in the buf_pool, and several pages
-of its random access area (for instance, 32 consecutive pages
-in a tablespace) have recently been referenced, we may predict
-that the whole area may be needed in the near future, and issue
-the read requests for the whole area.
-
- AWE implementation
- ------------------
-
-By a 'block' we mean the buffer header of type buf_block_t. By a 'page'
-we mean the physical 16 kB memory area allocated from RAM for that block.
-By a 'frame' we mean a 16 kB area in the virtual address space of the
-process, in the frame_mem of buf_pool.
-
-We can map pages to the frames of the buffer pool.
-
-1) A buffer block allocated to use as a non-data page, e.g., to the lock
-table, is always mapped to a frame.
-2) A bufferfixed or io-fixed data page is always mapped to a frame.
-3) When we need to map a block to frame, we look from the list
-awe_LRU_free_mapped and try to unmap its last block, but note that
-bufferfixed or io-fixed pages cannot be unmapped.
-4) For every frame in the buffer pool there is always a block whose page is
-mapped to it. When we create the buffer pool, we map the first elements
-in the free list to the frames.
-5) When we have AWE enabled, we disable adaptive hash indexes.
-*/
-
-/* Value in microseconds */
-static const int WAIT_FOR_READ = 20000;
-
-buf_pool_t* buf_pool = NULL; /* The buffer buf_pool of the database */
-
-#ifdef UNIV_DEBUG
-ulint buf_dbg_counter = 0; /* This is used to insert validation
- operations in excution in the
- debug version */
-ibool buf_debug_prints = FALSE; /* If this is set TRUE,
- the program prints info whenever
- read-ahead or flush occurs */
-#endif /* UNIV_DEBUG */
-/************************************************************************
-Calculates a page checksum which is stored to the page when it is written
-to a file. Note that we must be careful to calculate the same value on
-32-bit and 64-bit architectures. */
-
-ulint
-buf_calc_page_new_checksum(
-/*=======================*/
- /* out: checksum */
- byte* page) /* in: buffer page */
-{
- ulint checksum;
-
- /* Since the field FIL_PAGE_FILE_FLUSH_LSN, and in versions <= 4.1.x
- ..._ARCH_LOG_NO, are written outside the buffer pool to the first
- pages of data files, we have to skip them in the page checksum
- calculation.
- We must also skip the field FIL_PAGE_SPACE_OR_CHKSUM where the
- checksum is stored, and also the last 8 bytes of page because
- there we store the old formula checksum. */
-
- checksum = ut_fold_binary(page + FIL_PAGE_OFFSET,
- FIL_PAGE_FILE_FLUSH_LSN - FIL_PAGE_OFFSET)
- + ut_fold_binary(page + FIL_PAGE_DATA,
- UNIV_PAGE_SIZE - FIL_PAGE_DATA
- - FIL_PAGE_END_LSN_OLD_CHKSUM);
- checksum = checksum & 0xFFFFFFFFUL;
-
- return(checksum);
-}
-
-/************************************************************************
-In versions < 4.0.14 and < 4.1.1 there was a bug that the checksum only
-looked at the first few bytes of the page. This calculates that old
-checksum.
-NOTE: we must first store the new formula checksum to
-FIL_PAGE_SPACE_OR_CHKSUM before calculating and storing this old checksum
-because this takes that field as an input! */
-
-ulint
-buf_calc_page_old_checksum(
-/*=======================*/
- /* out: checksum */
- byte* page) /* in: buffer page */
-{
- ulint checksum;
-
- checksum = ut_fold_binary(page, FIL_PAGE_FILE_FLUSH_LSN);
-
- checksum = checksum & 0xFFFFFFFFUL;
-
- return(checksum);
-}
-
-/************************************************************************
-Checks if a page is corrupt. */
-
-ibool
-buf_page_is_corrupted(
-/*==================*/
- /* out: TRUE if corrupted */
- byte* read_buf) /* in: a database page */
-{
- ulint checksum;
- ulint old_checksum;
- ulint checksum_field;
- ulint old_checksum_field;
-#ifndef UNIV_HOTBACKUP
- dulint current_lsn;
-#endif
- if (mach_read_from_4(read_buf + FIL_PAGE_LSN + 4)
- != mach_read_from_4(read_buf + UNIV_PAGE_SIZE
- - FIL_PAGE_END_LSN_OLD_CHKSUM + 4)) {
-
- /* Stored log sequence numbers at the start and the end
- of page do not match */
-
- return(TRUE);
- }
-
-#ifndef UNIV_HOTBACKUP
- if (recv_lsn_checks_on && log_peek_lsn(¤t_lsn)) {
- if (ut_dulint_cmp(current_lsn,
- mach_read_from_8(read_buf + FIL_PAGE_LSN))
- < 0) {
- ut_print_timestamp(stderr);
-
- fprintf(stderr,
- " InnoDB: Error: page %lu log sequence number"
- " %lu %lu\n"
- "InnoDB: is in the future! Current system "
- "log sequence number %lu %lu.\n"
- "InnoDB: Your database may be corrupt or "
- "you may have copied the InnoDB\n"
- "InnoDB: tablespace but not the InnoDB "
- "log files. See\n"
- "InnoDB: http://dev.mysql.com/doc/refman/"
- "5.1/en/forcing-recovery.html\n"
- "InnoDB: for more information.\n",
- (ulong) mach_read_from_4(read_buf
- + FIL_PAGE_OFFSET),
- (ulong) ut_dulint_get_high
- (mach_read_from_8(read_buf + FIL_PAGE_LSN)),
- (ulong) ut_dulint_get_low
- (mach_read_from_8(read_buf + FIL_PAGE_LSN)),
- (ulong) ut_dulint_get_high(current_lsn),
- (ulong) ut_dulint_get_low(current_lsn));
- }
- }
-#endif
-
- /* If we use checksums validation, make additional check before
- returning TRUE to ensure that the checksum is not equal to
- BUF_NO_CHECKSUM_MAGIC which might be stored by InnoDB with checksums
- disabled. Otherwise, skip checksum calculation and return FALSE */
-
- if (srv_use_checksums) {
- old_checksum = buf_calc_page_old_checksum(read_buf);
-
- old_checksum_field = mach_read_from_4(
- read_buf + UNIV_PAGE_SIZE
- - FIL_PAGE_END_LSN_OLD_CHKSUM);
-
- /* There are 2 valid formulas for old_checksum_field:
-
- 1. Very old versions of InnoDB only stored 8 byte lsn to the
- start and the end of the page.
-
- 2. Newer InnoDB versions store the old formula checksum
- there. */
-
- if (old_checksum_field != mach_read_from_4(read_buf
- + FIL_PAGE_LSN)
- && old_checksum_field != old_checksum
- && old_checksum_field != BUF_NO_CHECKSUM_MAGIC) {
-
- return(TRUE);
- }
-
- checksum = buf_calc_page_new_checksum(read_buf);
- checksum_field = mach_read_from_4(read_buf
- + FIL_PAGE_SPACE_OR_CHKSUM);
-
- /* InnoDB versions < 4.0.14 and < 4.1.1 stored the space id
- (always equal to 0), to FIL_PAGE_SPACE_SPACE_OR_CHKSUM */
-
- if (checksum_field != 0 && checksum_field != checksum
- && checksum_field != BUF_NO_CHECKSUM_MAGIC) {
-
- return(TRUE);
- }
- }
-
- return(FALSE);
-}
-
-/************************************************************************
-Prints a page to stderr. */
-
-void
-buf_page_print(
-/*===========*/
- byte* read_buf) /* in: a database page */
-{
- dict_index_t* index;
- ulint checksum;
- ulint old_checksum;
-
- ut_print_timestamp(stderr);
- fprintf(stderr, " InnoDB: Page dump in ascii and hex (%lu bytes):\n",
- (ulint)UNIV_PAGE_SIZE);
- ut_print_buf(stderr, read_buf, UNIV_PAGE_SIZE);
- fputs("InnoDB: End of page dump\n", stderr);
-
- checksum = srv_use_checksums
- ? buf_calc_page_new_checksum(read_buf) : BUF_NO_CHECKSUM_MAGIC;
- old_checksum = srv_use_checksums
- ? buf_calc_page_old_checksum(read_buf) : BUF_NO_CHECKSUM_MAGIC;
-
- ut_print_timestamp(stderr);
- fprintf(stderr,
- " InnoDB: Page checksum %lu, prior-to-4.0.14-form"
- " checksum %lu\n"
- "InnoDB: stored checksum %lu, prior-to-4.0.14-form"
- " stored checksum %lu\n"
- "InnoDB: Page lsn %lu %lu, low 4 bytes of lsn"
- " at page end %lu\n"
- "InnoDB: Page number (if stored to page already) %lu,\n"
- "InnoDB: space id (if created with >= MySQL-4.1.1"
- " and stored already) %lu\n",
- (ulong) checksum, (ulong) old_checksum,
- (ulong) mach_read_from_4(read_buf + FIL_PAGE_SPACE_OR_CHKSUM),
- (ulong) mach_read_from_4(read_buf + UNIV_PAGE_SIZE
- - FIL_PAGE_END_LSN_OLD_CHKSUM),
- (ulong) mach_read_from_4(read_buf + FIL_PAGE_LSN),
- (ulong) mach_read_from_4(read_buf + FIL_PAGE_LSN + 4),
- (ulong) mach_read_from_4(read_buf + UNIV_PAGE_SIZE
- - FIL_PAGE_END_LSN_OLD_CHKSUM + 4),
- (ulong) mach_read_from_4(read_buf + FIL_PAGE_OFFSET),
- (ulong) mach_read_from_4(read_buf
- + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID));
-
- if (mach_read_from_2(read_buf + TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_TYPE)
- == TRX_UNDO_INSERT) {
- fprintf(stderr,
- "InnoDB: Page may be an insert undo log page\n");
- } else if (mach_read_from_2(read_buf + TRX_UNDO_PAGE_HDR
- + TRX_UNDO_PAGE_TYPE)
- == TRX_UNDO_UPDATE) {
- fprintf(stderr,
- "InnoDB: Page may be an update undo log page\n");
- }
-
- switch (fil_page_get_type(read_buf)) {
- case FIL_PAGE_INDEX:
- fprintf(stderr,
- "InnoDB: Page may be an index page where"
- " index id is %lu %lu\n",
- (ulong) ut_dulint_get_high
- (btr_page_get_index_id(read_buf)),
- (ulong) ut_dulint_get_low
- (btr_page_get_index_id(read_buf)));
-
- /* If the code is in ibbackup, dict_sys may be uninitialized,
- i.e., NULL */
-
- if (dict_sys != NULL) {
-
- index = dict_index_find_on_id_low(
- btr_page_get_index_id(read_buf));
- if (index) {
- fputs("InnoDB: (", stderr);
- dict_index_name_print(stderr, NULL, index);
- fputs(")\n", stderr);
- }
- }
- break;
- case FIL_PAGE_INODE:
- fputs("InnoDB: Page may be an 'inode' page\n", stderr);
- break;
- case FIL_PAGE_IBUF_FREE_LIST:
- fputs("InnoDB: Page may be an insert buffer free list page\n",
- stderr);
- break;
- case FIL_PAGE_TYPE_ALLOCATED:
- fputs("InnoDB: Page may be a freshly allocated page\n",
- stderr);
- break;
- case FIL_PAGE_IBUF_BITMAP:
- fputs("InnoDB: Page may be an insert buffer bitmap page\n",
- stderr);
- break;
- case FIL_PAGE_TYPE_SYS:
- fputs("InnoDB: Page may be a system page\n",
- stderr);
- break;
- case FIL_PAGE_TYPE_TRX_SYS:
- fputs("InnoDB: Page may be a transaction system page\n",
- stderr);
- break;
- case FIL_PAGE_TYPE_FSP_HDR:
- fputs("InnoDB: Page may be a file space header page\n",
- stderr);
- break;
- case FIL_PAGE_TYPE_XDES:
- fputs("InnoDB: Page may be an extent descriptor page\n",
- stderr);
- break;
- case FIL_PAGE_TYPE_BLOB:
- fputs("InnoDB: Page may be a BLOB page\n",
- stderr);
- break;
- }
-}
-
-/************************************************************************
-Initializes a buffer control block when the buf_pool is created. */
-static
-void
-buf_block_init(
-/*===========*/
- buf_block_t* block, /* in: pointer to control block */
- byte* frame) /* in: pointer to buffer frame, or NULL if in
- the case of AWE there is no frame */
-{
- block->magic_n = 0;
-
- block->state = BUF_BLOCK_NOT_USED;
-
- block->frame = frame;
-
- block->awe_info = NULL;
-
- block->buf_fix_count = 0;
- block->io_fix = 0;
-
- block->modify_clock = ut_dulint_zero;
-
- block->file_page_was_freed = FALSE;
-
- block->check_index_page_at_flush = FALSE;
- block->index = NULL;
-
- block->in_free_list = FALSE;
- block->in_LRU_list = FALSE;
-
- block->n_pointers = 0;
-
- mutex_create(&block->mutex, SYNC_BUF_BLOCK);
-
- rw_lock_create(&block->lock, SYNC_LEVEL_VARYING);
- ut_ad(rw_lock_validate(&(block->lock)));
-
-#ifdef UNIV_SYNC_DEBUG
- rw_lock_create(&block->debug_latch, SYNC_NO_ORDER_CHECK);
-#endif /* UNIV_SYNC_DEBUG */
-}
-
-/************************************************************************
-Creates the buffer pool. */
-
-buf_pool_t*
-buf_pool_init(
-/*==========*/
- /* out, own: buf_pool object, NULL if not
- enough memory or error */
- ulint max_size, /* in: maximum size of the buf_pool in
- blocks */
- ulint curr_size, /* in: current size to use, must be <=
- max_size, currently must be equal to
- max_size */
- ulint n_frames) /* in: number of frames; if AWE is used,
- this is the size of the address space window
- where physical memory pages are mapped; if
- AWE is not used then this must be the same
- as max_size */
-{
- byte* frame;
- ulint i;
- buf_block_t* block;
-
- ut_a(max_size == curr_size);
- ut_a(srv_use_awe || n_frames == max_size);
-
- if (n_frames > curr_size) {
- fprintf(stderr,
- "InnoDB: AWE: Error: you must specify in my.cnf"
- " .._awe_mem_mb larger\n"
- "InnoDB: than .._buffer_pool_size. Now the former"
- " is %lu pages,\n"
- "InnoDB: the latter %lu pages.\n",
- (ulong) curr_size, (ulong) n_frames);
-
- return(NULL);
- }
-
- buf_pool = mem_alloc(sizeof(buf_pool_t));
-
- /* 1. Initialize general fields
- ---------------------------- */
- mutex_create(&buf_pool->mutex, SYNC_BUF_POOL);
-
- mutex_enter(&(buf_pool->mutex));
-
- if (srv_use_awe) {
- /*----------------------------------------*/
- /* Allocate the virtual address space window, i.e., the
- buffer pool frames */
-
- buf_pool->frame_mem = os_awe_allocate_virtual_mem_window(
- UNIV_PAGE_SIZE * (n_frames + 1));
-
- /* Allocate the physical memory for AWE and the AWE info array
- for buf_pool */
-
- if ((curr_size % ((1024 * 1024) / UNIV_PAGE_SIZE)) != 0) {
-
- fprintf(stderr,
- "InnoDB: AWE: Error: physical memory must be"
- " allocated in full megabytes.\n"
- "InnoDB: Trying to allocate %lu"
- " database pages.\n",
- (ulong) curr_size);
-
- return(NULL);
- }
-
- if (!os_awe_allocate_physical_mem(&(buf_pool->awe_info),
- curr_size
- / ((1024 * 1024)
- / UNIV_PAGE_SIZE))) {
-
- return(NULL);
- }
- /*----------------------------------------*/
- } else {
- buf_pool->frame_mem = os_mem_alloc_large(
- UNIV_PAGE_SIZE * (n_frames + 1), TRUE, FALSE);
- }
-
- if (buf_pool->frame_mem == NULL) {
-
- return(NULL);
- }
-
- buf_pool->blocks = ut_malloc(sizeof(buf_block_t) * max_size);
-
- if (buf_pool->blocks == NULL) {
-
- return(NULL);
- }
-
- buf_pool->max_size = max_size;
- buf_pool->curr_size = curr_size;
-
- buf_pool->n_frames = n_frames;
-
- /* Align pointer to the first frame */
-
- frame = ut_align(buf_pool->frame_mem, UNIV_PAGE_SIZE);
-
- buf_pool->frame_zero = frame;
- buf_pool->high_end = frame + UNIV_PAGE_SIZE * n_frames;
-
- if (srv_use_awe) {
- /*----------------------------------------*/
- /* Map an initial part of the allocated physical memory to
- the window */
-
- os_awe_map_physical_mem_to_window(buf_pool->frame_zero,
- n_frames
- * (UNIV_PAGE_SIZE
- / OS_AWE_X86_PAGE_SIZE),
- buf_pool->awe_info);
- /*----------------------------------------*/
- }
-
- buf_pool->blocks_of_frames = ut_malloc(sizeof(void*) * n_frames);
-
- if (buf_pool->blocks_of_frames == NULL) {
-
- return(NULL);
- }
-
- /* Init block structs and assign frames for them; in the case of
- AWE there are less frames than blocks. Then we assign the frames
- to the first blocks (we already mapped the memory above). We also
- init the awe_info for every block. */
-
- for (i = 0; i < max_size; i++) {
-
- block = buf_pool_get_nth_block(buf_pool, i);
-
- if (i < n_frames) {
- frame = buf_pool->frame_zero + i * UNIV_PAGE_SIZE;
- *(buf_pool->blocks_of_frames + i) = block;
- } else {
- frame = NULL;
- }
-
- buf_block_init(block, frame);
-
- if (srv_use_awe) {
- /*----------------------------------------*/
- block->awe_info = buf_pool->awe_info
- + i * (UNIV_PAGE_SIZE / OS_AWE_X86_PAGE_SIZE);
- /*----------------------------------------*/
- }
- }
-
- buf_pool->page_hash = hash_create(2 * max_size);
-
- buf_pool->n_pend_reads = 0;
-
- buf_pool->last_printout_time = time(NULL);
-
- buf_pool->n_pages_read = 0;
- buf_pool->n_pages_written = 0;
- buf_pool->n_pages_created = 0;
- buf_pool->n_pages_awe_remapped = 0;
-
- buf_pool->n_page_gets = 0;
- buf_pool->n_page_gets_old = 0;
- buf_pool->n_pages_read_old = 0;
- buf_pool->n_pages_written_old = 0;
- buf_pool->n_pages_created_old = 0;
- buf_pool->n_pages_awe_remapped_old = 0;
-
- /* 2. Initialize flushing fields
- ---------------------------- */
- UT_LIST_INIT(buf_pool->flush_list);
-
- for (i = BUF_FLUSH_LRU; i <= BUF_FLUSH_LIST; i++) {
- buf_pool->n_flush[i] = 0;
- buf_pool->init_flush[i] = FALSE;
- buf_pool->no_flush[i] = os_event_create(NULL);
- }
-
- buf_pool->LRU_flush_ended = 0;
-
- buf_pool->ulint_clock = 1;
- buf_pool->freed_page_clock = 0;
-
- /* 3. Initialize LRU fields
- ---------------------------- */
- UT_LIST_INIT(buf_pool->LRU);
-
- buf_pool->LRU_old = NULL;
-
- UT_LIST_INIT(buf_pool->awe_LRU_free_mapped);
-
- /* Add control blocks to the free list */
- UT_LIST_INIT(buf_pool->free);
-
- for (i = 0; i < curr_size; i++) {
-
- block = buf_pool_get_nth_block(buf_pool, i);
-
- if (block->frame) {
- /* Wipe contents of frame to eliminate a Purify
- warning */
-
-#ifdef HAVE_purify
- memset(block->frame, '\0', UNIV_PAGE_SIZE);
-#endif
- if (srv_use_awe) {
- /* Add to the list of blocks mapped to
- frames */
-
- UT_LIST_ADD_LAST(awe_LRU_free_mapped,
- buf_pool->awe_LRU_free_mapped,
- block);
- }
- }
-
- UT_LIST_ADD_LAST(free, buf_pool->free, block);
- block->in_free_list = TRUE;
- }
-
- mutex_exit(&(buf_pool->mutex));
-
- if (srv_use_adaptive_hash_indexes) {
- btr_search_sys_create(curr_size * UNIV_PAGE_SIZE
- / sizeof(void*) / 64);
- } else {
- /* Create only a small dummy system */
- btr_search_sys_create(1000);
- }
-
- return(buf_pool);
-}
-
-/************************************************************************
-Maps the page of block to a frame, if not mapped yet. Unmaps some page
-from the end of the awe_LRU_free_mapped. */
-
-void
-buf_awe_map_page_to_frame(
-/*======================*/
- buf_block_t* block, /* in: block whose page should be
- mapped to a frame */
- ibool add_to_mapped_list) /* in: TRUE if we in the case
- we need to map the page should also
- add the block to the
- awe_LRU_free_mapped list */
-{
- buf_block_t* bck;
-
- ut_ad(mutex_own(&(buf_pool->mutex)));
- ut_ad(block);
-
- if (block->frame) {
-
- return;
- }
-
- /* Scan awe_LRU_free_mapped from the end and try to find a block
- which is not bufferfixed or io-fixed */
-
- bck = UT_LIST_GET_LAST(buf_pool->awe_LRU_free_mapped);
-
- while (bck) {
- ibool skip;
-
- mutex_enter(&bck->mutex);
-
- skip = (bck->state == BUF_BLOCK_FILE_PAGE
- && (bck->buf_fix_count != 0 || bck->io_fix != 0));
-
- if (skip) {
- mutex_exit(&bck->mutex);
-
- /* We have to skip this */
- bck = UT_LIST_GET_PREV(awe_LRU_free_mapped, bck);
- } else {
- /* We can map block to the frame of bck */
-
- os_awe_map_physical_mem_to_window(
- bck->frame,
- UNIV_PAGE_SIZE / OS_AWE_X86_PAGE_SIZE,
- block->awe_info);
-
- block->frame = bck->frame;
-
- *(buf_pool->blocks_of_frames
- + (((ulint)(block->frame
- - buf_pool->frame_zero))
- >> UNIV_PAGE_SIZE_SHIFT))
- = block;
-
- bck->frame = NULL;
- UT_LIST_REMOVE(awe_LRU_free_mapped,
- buf_pool->awe_LRU_free_mapped,
- bck);
-
- if (add_to_mapped_list) {
- UT_LIST_ADD_FIRST(
- awe_LRU_free_mapped,
- buf_pool->awe_LRU_free_mapped,
- block);
- }
-
- buf_pool->n_pages_awe_remapped++;
-
- mutex_exit(&bck->mutex);
-
- return;
- }
- }
-
- fprintf(stderr,
- "InnoDB: AWE: Fatal error: cannot find a page to unmap\n"
- "InnoDB: awe_LRU_free_mapped list length %lu\n",
- (ulong) UT_LIST_GET_LEN(buf_pool->awe_LRU_free_mapped));
-
- ut_a(0);
-}
-
-/************************************************************************
-Allocates a buffer block. */
-UNIV_INLINE
-buf_block_t*
-buf_block_alloc(void)
-/*=================*/
- /* out, own: the allocated block; also if AWE
- is used it is guaranteed that the page is
- mapped to a frame */
-{
- buf_block_t* block;
-
- block = buf_LRU_get_free_block();
-
- return(block);
-}
-
-/************************************************************************
-Moves to the block to the start of the LRU list if there is a danger
-that the block would drift out of the buffer pool. */
-UNIV_INLINE
-void
-buf_block_make_young(
-/*=================*/
- buf_block_t* block) /* in: block to make younger */
-{
- ut_ad(!mutex_own(&(buf_pool->mutex)));
-
- /* 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_block_peek_if_too_old(block)) {
-
- mutex_enter(&buf_pool->mutex);
- /* There has been freeing activity in the LRU list:
- best to move to the head of the LRU list */
-
- buf_LRU_make_block_young(block);
- mutex_exit(&buf_pool->mutex);
- }
-}
-
-/************************************************************************
-Moves a page to the start of the buffer pool LRU list. This high-level
-function can be used to prevent an important page from from slipping out of
-the buffer pool. */
-
-void
-buf_page_make_young(
-/*================*/
- buf_frame_t* frame) /* in: buffer frame of a file page */
-{
- buf_block_t* block;
-
- mutex_enter(&(buf_pool->mutex));
-
- block = buf_block_align(frame);
-
- ut_a(block->state == BUF_BLOCK_FILE_PAGE);
-
- buf_LRU_make_block_young(block);
-
- mutex_exit(&(buf_pool->mutex));
-}
-
-/************************************************************************
-Frees a buffer block which does not contain a file page. */
-UNIV_INLINE
-void
-buf_block_free(
-/*===========*/
- buf_block_t* block) /* in, own: block to be freed */
-{
- mutex_enter(&(buf_pool->mutex));
-
- mutex_enter(&block->mutex);
-
- ut_a(block->state != BUF_BLOCK_FILE_PAGE);
-
- buf_LRU_block_free_non_file_page(block);
-
- mutex_exit(&block->mutex);
-
- mutex_exit(&(buf_pool->mutex));
-}
-
-/*************************************************************************
-Allocates a buffer frame. */
-
-buf_frame_t*
-buf_frame_alloc(void)
-/*=================*/
- /* out: buffer frame */
-{
- return(buf_block_alloc()->frame);
-}
-
-/*************************************************************************
-Frees a buffer frame which does not contain a file page. */
-
-void
-buf_frame_free(
-/*===========*/
- buf_frame_t* frame) /* in: buffer frame */
-{
- buf_block_free(buf_block_align(frame));
-}
-
-/************************************************************************
-Returns the buffer control block if the page can be found in the buffer
-pool. NOTE that it is possible that the page is not yet read
-from disk, though. This is a very low-level function: use with care! */
-
-buf_block_t*
-buf_page_peek_block(
-/*================*/
- /* out: control block if found from page hash table,
- otherwise NULL; NOTE that the page is not necessarily
- yet read from disk! */
- ulint space, /* in: space id */
- ulint offset) /* in: page number */
-{
- buf_block_t* block;
-
- mutex_enter_fast(&(buf_pool->mutex));
-
- block = buf_page_hash_get(space, offset);
-
- mutex_exit(&(buf_pool->mutex));
-
- return(block);
-}
-
-/************************************************************************
-Resets the check_index_page_at_flush field of a page if found in the buffer
-pool. */
-
-void
-buf_reset_check_index_page_at_flush(
-/*================================*/
- ulint space, /* in: space id */
- ulint offset) /* in: page number */
-{
- buf_block_t* block;
-
- mutex_enter_fast(&(buf_pool->mutex));
-
- block = buf_page_hash_get(space, offset);
-
- if (block) {
- block->check_index_page_at_flush = FALSE;
- }
-
- mutex_exit(&(buf_pool->mutex));
-}
-
-/************************************************************************
-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
-pool if it is found there. */
-
-ibool
-buf_page_peek_if_search_hashed(
-/*===========================*/
- /* out: TRUE if page hash index is built in search
- system */
- ulint space, /* in: space id */
- ulint offset) /* in: page number */
-{
- buf_block_t* block;
- ibool is_hashed;
-
- mutex_enter_fast(&(buf_pool->mutex));
-
- block = buf_page_hash_get(space, offset);
-
- if (!block) {
- is_hashed = FALSE;
- } else {
- is_hashed = block->is_hashed;
- }
-
- mutex_exit(&(buf_pool->mutex));
-
- return(is_hashed);
-}
-
-/************************************************************************
-Returns TRUE if the page can be found in the buffer pool hash table. NOTE
-that it is possible that the page is not yet read from disk, though. */
-
-ibool
-buf_page_peek(
-/*==========*/
- /* out: TRUE if found from page hash table,
- NOTE that the page is not necessarily yet read
- from disk! */
- ulint space, /* in: space id */
- ulint offset) /* in: page number */
-{
- if (buf_page_peek_block(space, offset)) {
-
- return(TRUE);
- }
-
- return(FALSE);
-}
-
-/************************************************************************
-Sets file_page_was_freed TRUE if the page is found in the buffer pool.
-This function should be called when we free a file page and want the
-debug version to check that it is not accessed any more unless
-reallocated. */
-
-buf_block_t*
-buf_page_set_file_page_was_freed(
-/*=============================*/
- /* out: control block if found from page hash table,
- otherwise NULL */
- ulint space, /* in: space id */
- ulint offset) /* in: page number */
-{
- buf_block_t* block;
-
- mutex_enter_fast(&(buf_pool->mutex));
-
- block = buf_page_hash_get(space, offset);
-
- if (block) {
- block->file_page_was_freed = TRUE;
- }
-
- mutex_exit(&(buf_pool->mutex));
-
- return(block);
-}
-
-/************************************************************************
-Sets file_page_was_freed FALSE if the page is found in the buffer pool.
-This function should be called when we free a file page and want the
-debug version to check that it is not accessed any more unless
-reallocated. */
-
-buf_block_t*
-buf_page_reset_file_page_was_freed(
-/*===============================*/
- /* out: control block if found from page hash table,
- otherwise NULL */
- ulint space, /* in: space id */
- ulint offset) /* in: page number */
-{
- buf_block_t* block;
-
- mutex_enter_fast(&(buf_pool->mutex));
-
- block = buf_page_hash_get(space, offset);
-
- if (block) {
- block->file_page_was_freed = FALSE;
- }
-
- mutex_exit(&(buf_pool->mutex));
-
- return(block);
-}
-
-/************************************************************************
-This is the general function used to get access to a database page. */
-
-buf_frame_t*
-buf_page_get_gen(
-/*=============*/
- /* out: pointer to the frame or NULL */
- ulint space, /* in: space id */
- ulint offset, /* in: page number */
- ulint rw_latch,/* in: RW_S_LATCH, RW_X_LATCH, RW_NO_LATCH */
- buf_frame_t* guess, /* in: guessed frame or NULL */
- ulint mode, /* in: BUF_GET, BUF_GET_IF_IN_POOL,
- BUF_GET_NO_LATCH, BUF_GET_NOWAIT */
- const char* file, /* in: file name */
- ulint line, /* in: line where called */
- mtr_t* mtr) /* in: mini-transaction */
-{
- buf_block_t* block;
- ibool accessed;
- ulint fix_type;
- ibool success;
- ibool must_read;
-
- ut_ad(mtr);
- ut_ad((rw_latch == RW_S_LATCH)
- || (rw_latch == RW_X_LATCH)
- || (rw_latch == RW_NO_LATCH));
- ut_ad((mode != BUF_GET_NO_LATCH) || (rw_latch == RW_NO_LATCH));
- ut_ad((mode == BUF_GET) || (mode == BUF_GET_IF_IN_POOL)
- || (mode == BUF_GET_NO_LATCH) || (mode == BUF_GET_NOWAIT));
-#ifndef UNIV_LOG_DEBUG
- ut_ad(!ibuf_inside() || ibuf_page(space, offset));
-#endif
- buf_pool->n_page_gets++;
-loop:
- block = NULL;
- mutex_enter_fast(&(buf_pool->mutex));
-
- if (guess) {
- block = buf_block_align(guess);
-
- if ((offset != block->offset) || (space != block->space)
- || (block->state != BUF_BLOCK_FILE_PAGE)) {
-
- block = NULL;
- }
- }
-
- if (block == NULL) {
- block = buf_page_hash_get(space, offset);
- }
-
- if (block == NULL) {
- /* Page not in buf_pool: needs to be read from file */
-
- mutex_exit(&(buf_pool->mutex));
-
- if (mode == BUF_GET_IF_IN_POOL) {
-
- return(NULL);
- }
-
- buf_read_page(space, offset);
-
-#ifdef UNIV_DEBUG
- buf_dbg_counter++;
-
- if (buf_dbg_counter % 37 == 0) {
- ut_ad(buf_validate());
- }
-#endif
- goto loop;
- }
-
- mutex_enter(&block->mutex);
-
- ut_a(block->state == BUF_BLOCK_FILE_PAGE);
-
- must_read = FALSE;
-
- if (block->io_fix == BUF_IO_READ) {
-
- must_read = TRUE;
-
- if (mode == BUF_GET_IF_IN_POOL) {
- /* The page is only being read to buffer */
- mutex_exit(&buf_pool->mutex);
- mutex_exit(&block->mutex);
-
- return(NULL);
- }
- }
-
- /* If AWE is enabled and the page is not mapped to a frame, then
- map it */
-
- if (block->frame == NULL) {
- ut_a(srv_use_awe);
-
- /* We set second parameter TRUE because the block is in the
- LRU list and we must put it to awe_LRU_free_mapped list once
- mapped to a frame */
-
- buf_awe_map_page_to_frame(block, TRUE);
- }
-
-#ifdef UNIV_SYNC_DEBUG
- buf_block_buf_fix_inc_debug(block, file, line);
-#else
- buf_block_buf_fix_inc(block);
-#endif
- mutex_exit(&buf_pool->mutex);
-
- /* Check if this is the first access to the page */
-
- accessed = block->accessed;
-
- block->accessed = TRUE;
-
- mutex_exit(&block->mutex);
-
- buf_block_make_young(block);
-
-#ifdef UNIV_DEBUG_FILE_ACCESSES
- ut_a(block->file_page_was_freed == FALSE);
-#endif
-
-#ifdef UNIV_DEBUG
- buf_dbg_counter++;
-
- if (buf_dbg_counter % 5771 == 0) {
- ut_ad(buf_validate());
- }
-#endif
- ut_ad(block->buf_fix_count > 0);
- ut_ad(block->state == BUF_BLOCK_FILE_PAGE);
-
- if (mode == BUF_GET_NOWAIT) {
- if (rw_latch == RW_S_LATCH) {
- success = rw_lock_s_lock_nowait(&(block->lock),
- file, line);
- fix_type = MTR_MEMO_PAGE_S_FIX;
- } else {
- ut_ad(rw_latch == RW_X_LATCH);
- success = rw_lock_x_lock_func_nowait(&(block->lock),
- file, line);
- fix_type = MTR_MEMO_PAGE_X_FIX;
- }
-
- if (!success) {
- mutex_enter(&block->mutex);
-
- block->buf_fix_count--;
-
- mutex_exit(&block->mutex);
-#ifdef UNIV_SYNC_DEBUG
- rw_lock_s_unlock(&(block->debug_latch));
-#endif
-
- return(NULL);
- }
- } else if (rw_latch == RW_NO_LATCH) {
-
- if (must_read) {
- /* Let us wait until the read operation
- completes */
-
- for (;;) {
- mutex_enter(&block->mutex);
-
- if (block->io_fix == BUF_IO_READ) {
-
- mutex_exit(&block->mutex);
-
- os_thread_sleep(WAIT_FOR_READ);
- } else {
-
- mutex_exit(&block->mutex);
-
- break;
- }
- }
- }
-
- fix_type = MTR_MEMO_BUF_FIX;
- } else if (rw_latch == RW_S_LATCH) {
-
- rw_lock_s_lock_func(&(block->lock), 0, file, line);
-
- fix_type = MTR_MEMO_PAGE_S_FIX;
- } else {
- rw_lock_x_lock_func(&(block->lock), 0, file, line);
-
- fix_type = MTR_MEMO_PAGE_X_FIX;
- }
-
- mtr_memo_push(mtr, block, fix_type);
-
- if (!accessed) {
- /* In the case of a first access, try to apply linear
- read-ahead */
-
- buf_read_ahead_linear(space, offset);
- }
-
-#ifdef UNIV_IBUF_DEBUG
- ut_a(ibuf_count_get(block->space, block->offset) == 0);
-#endif
- return(block->frame);
-}
-
-/************************************************************************
-This is the general function used to get optimistic access to a database
-page. */
-
-ibool
-buf_page_optimistic_get_func(
-/*=========================*/
- /* out: TRUE if success */
- ulint rw_latch,/* in: RW_S_LATCH, RW_X_LATCH */
- buf_block_t* block, /* in: guessed buffer block */
- buf_frame_t* guess, /* in: guessed frame; note that AWE may move
- frames */
- dulint modify_clock,/* in: modify clock value if mode is
- ..._GUESS_ON_CLOCK */
- const char* file, /* in: file name */
- ulint line, /* in: line where called */
- mtr_t* mtr) /* in: mini-transaction */
-{
- ibool accessed;
- ibool success;
- ulint fix_type;
-
- ut_ad(mtr && block);
- ut_ad((rw_latch == RW_S_LATCH) || (rw_latch == RW_X_LATCH));
-
- /* If AWE is used, block may have a different frame now, e.g., NULL */
-
- mutex_enter(&block->mutex);
-
- if (UNIV_UNLIKELY(block->state != BUF_BLOCK_FILE_PAGE)
- || UNIV_UNLIKELY(block->frame != guess)) {
-
- mutex_exit(&block->mutex);
-
- return(FALSE);
- }
-
-#ifdef UNIV_SYNC_DEBUG
- buf_block_buf_fix_inc_debug(block, file, line);
-#else
- buf_block_buf_fix_inc(block);
-#endif
- accessed = block->accessed;
- block->accessed = TRUE;
-
- mutex_exit(&block->mutex);
-
- buf_block_make_young(block);
-
- /* Check if this is the first access to the page */
-
- ut_ad(!ibuf_inside() || ibuf_page(block->space, block->offset));
-
- if (rw_latch == RW_S_LATCH) {
- success = rw_lock_s_lock_nowait(&(block->lock),
- file, line);
- fix_type = MTR_MEMO_PAGE_S_FIX;
- } else {
- success = rw_lock_x_lock_func_nowait(&(block->lock),
- file, line);
- fix_type = MTR_MEMO_PAGE_X_FIX;
- }
-
- if (UNIV_UNLIKELY(!success)) {
- mutex_enter(&block->mutex);
-
- block->buf_fix_count--;
-
- mutex_exit(&block->mutex);
-
-#ifdef UNIV_SYNC_DEBUG
- rw_lock_s_unlock(&(block->debug_latch));
-#endif
- return(FALSE);
- }
-
- if (UNIV_UNLIKELY(!UT_DULINT_EQ(modify_clock, block->modify_clock))) {
-#ifdef UNIV_SYNC_DEBUG
- buf_page_dbg_add_level(block->frame, SYNC_NO_ORDER_CHECK);
-#endif /* UNIV_SYNC_DEBUG */
- if (rw_latch == RW_S_LATCH) {
- rw_lock_s_unlock(&(block->lock));
- } else {
- rw_lock_x_unlock(&(block->lock));
- }
-
- mutex_enter(&block->mutex);
-
- block->buf_fix_count--;
-
- mutex_exit(&block->mutex);
-
-#ifdef UNIV_SYNC_DEBUG
- rw_lock_s_unlock(&(block->debug_latch));
-#endif
- return(FALSE);
- }
-
- mtr_memo_push(mtr, block, fix_type);
-
-#ifdef UNIV_DEBUG
- buf_dbg_counter++;
-
- if (buf_dbg_counter % 5771 == 0) {
- ut_ad(buf_validate());
- }
-#endif
- ut_ad(block->buf_fix_count > 0);
- ut_ad(block->state == BUF_BLOCK_FILE_PAGE);
-
-#ifdef UNIV_DEBUG_FILE_ACCESSES
- ut_a(block->file_page_was_freed == FALSE);
-#endif
- if (UNIV_UNLIKELY(!accessed)) {
- /* In the case of a first access, try to apply linear
- read-ahead */
-
- buf_read_ahead_linear(buf_frame_get_space_id(guess),
- buf_frame_get_page_no(guess));
- }
-
-#ifdef UNIV_IBUF_DEBUG
- ut_a(ibuf_count_get(block->space, block->offset) == 0);
-#endif
- buf_pool->n_page_gets++;
-
- return(TRUE);
-}
-
-/************************************************************************
-This is used to get access to a known database page, when no waiting can be
-done. For example, if a search in an adaptive hash index leads us to this
-frame. */
-
-ibool
-buf_page_get_known_nowait(
-/*======================*/
- /* out: TRUE if success */
- ulint rw_latch,/* in: RW_S_LATCH, RW_X_LATCH */
- buf_frame_t* guess, /* in: the known page frame */
- ulint mode, /* in: BUF_MAKE_YOUNG or BUF_KEEP_OLD */
- const char* file, /* in: file name */
- ulint line, /* in: line where called */
- mtr_t* mtr) /* in: mini-transaction */
-{
- buf_block_t* block;
- ibool success;
- ulint fix_type;
-
- ut_ad(mtr);
- ut_ad((rw_latch == RW_S_LATCH) || (rw_latch == RW_X_LATCH));
-
- block = buf_block_align(guess);
-
- mutex_enter(&block->mutex);
-
- if (block->state == BUF_BLOCK_REMOVE_HASH) {
- /* Another thread is just freeing the block from the LRU list
- of the buffer pool: do not try to access this page; this
- attempt to access the page can only come through the hash
- index because when the buffer block state is ..._REMOVE_HASH,
- we have already removed it from the page address hash table
- of the buffer pool. */
-
- mutex_exit(&block->mutex);
-
- return(FALSE);
- }
-
- ut_a(block->state == BUF_BLOCK_FILE_PAGE);
-
-#ifdef UNIV_SYNC_DEBUG
- buf_block_buf_fix_inc_debug(block, file, line);
-#else
- buf_block_buf_fix_inc(block);
-#endif
- mutex_exit(&block->mutex);
-
- if (mode == BUF_MAKE_YOUNG) {
- buf_block_make_young(block);
- }
-
- ut_ad(!ibuf_inside() || (mode == BUF_KEEP_OLD));
-
- if (rw_latch == RW_S_LATCH) {
- success = rw_lock_s_lock_nowait(&(block->lock),
- file, line);
- fix_type = MTR_MEMO_PAGE_S_FIX;
- } else {
- success = rw_lock_x_lock_func_nowait(&(block->lock),
- file, line);
- fix_type = MTR_MEMO_PAGE_X_FIX;
- }
-
- if (!success) {
- mutex_enter(&block->mutex);
-
- block->buf_fix_count--;
-
- mutex_exit(&block->mutex);
-
-#ifdef UNIV_SYNC_DEBUG
- rw_lock_s_unlock(&(block->debug_latch));
-#endif
-
- return(FALSE);
- }
-
- mtr_memo_push(mtr, block, fix_type);
-
-#ifdef UNIV_DEBUG
- buf_dbg_counter++;
-
- if (buf_dbg_counter % 5771 == 0) {
- ut_ad(buf_validate());
- }
-#endif
- ut_ad(block->buf_fix_count > 0);
- ut_ad(block->state == BUF_BLOCK_FILE_PAGE);
-#ifdef UNIV_DEBUG_FILE_ACCESSES
- ut_a(block->file_page_was_freed == FALSE);
-#endif
-
-#ifdef UNIV_IBUF_DEBUG
- ut_a((mode == BUF_KEEP_OLD)
- || (ibuf_count_get(block->space, block->offset) == 0));
-#endif
- buf_pool->n_page_gets++;
-
- return(TRUE);
-}
-
-/************************************************************************
-Inits a page to the buffer buf_pool, for use in ibbackup --restore. */
-
-void
-buf_page_init_for_backup_restore(
-/*=============================*/
- ulint space, /* in: space id */
- ulint offset, /* in: offset of the page within space
- in units of a page */
- buf_block_t* block) /* in: block to init */
-{
- /* Set the state of the block */
- block->magic_n = BUF_BLOCK_MAGIC_N;
-
- block->state = BUF_BLOCK_FILE_PAGE;
- block->space = space;
- block->offset = offset;
-
- block->lock_hash_val = 0;
-
- block->freed_page_clock = 0;
-
- block->newest_modification = ut_dulint_zero;
- block->oldest_modification = ut_dulint_zero;
-
- block->accessed = FALSE;
- block->buf_fix_count = 0;
- block->io_fix = 0;
-
- block->n_hash_helps = 0;
- block->is_hashed = FALSE;
- block->n_fields = 1;
- block->n_bytes = 0;
- block->left_side = TRUE;
-
- block->file_page_was_freed = FALSE;
-}
-
-/************************************************************************
-Inits a page to the buffer buf_pool. */
-static
-void
-buf_page_init(
-/*==========*/
- ulint space, /* in: space id */
- ulint offset, /* in: offset of the page within space
- in units of a page */
- buf_block_t* block) /* in: block to init */
-{
-
- ut_ad(mutex_own(&(buf_pool->mutex)));
- ut_ad(mutex_own(&(block->mutex)));
- ut_a(block->state != BUF_BLOCK_FILE_PAGE);
-
- /* Set the state of the block */
- block->magic_n = BUF_BLOCK_MAGIC_N;
-
- block->state = BUF_BLOCK_FILE_PAGE;
- block->space = space;
- block->offset = offset;
-
- block->check_index_page_at_flush = FALSE;
- block->index = NULL;
-
- block->lock_hash_val = lock_rec_hash(space, offset);
-
-#ifdef UNIV_DEBUG_VALGRIND
- if (!space) {
- /* Silence valid Valgrind warnings about uninitialized
- data being written to data files. There are some unused
- bytes on some pages that InnoDB does not initialize. */
- UNIV_MEM_VALID(block->frame, UNIV_PAGE_SIZE);
- }
-#endif /* UNIV_DEBUG_VALGRIND */
-
- /* Insert into the hash table of file pages */
-
- if (buf_page_hash_get(space, offset)) {
- fprintf(stderr,
- "InnoDB: Error: page %lu %lu already found"
- " in the hash table\n",
- (ulong) space,
- (ulong) offset);
-#ifdef UNIV_DEBUG
- buf_print();
- buf_LRU_print();
- buf_validate();
- buf_LRU_validate();
-#endif /* UNIV_DEBUG */
- ut_a(0);
- }
-
- HASH_INSERT(buf_block_t, hash, buf_pool->page_hash,
- buf_page_address_fold(space, offset), block);
-
- block->freed_page_clock = 0;
-
- block->newest_modification = ut_dulint_zero;
- block->oldest_modification = ut_dulint_zero;
-
- block->accessed = FALSE;
- block->buf_fix_count = 0;
- block->io_fix = 0;
-
- block->n_hash_helps = 0;
- block->is_hashed = FALSE;
- block->n_fields = 1;
- block->n_bytes = 0;
- block->left_side = TRUE;
-
- block->file_page_was_freed = FALSE;
-}
-
-/************************************************************************
-Function which inits a page for read to the buffer buf_pool. If the page is
-(1) already in buf_pool, or
-(2) if we specify to read only ibuf pages and the page is not an ibuf page, or
-(3) if the space is deleted or being deleted,
-then this function does nothing.
-Sets the io_fix flag to BUF_IO_READ and sets a non-recursive exclusive lock
-on the buffer frame. The io-handler must take care that the flag is cleared
-and the lock released later. This is one of the functions which perform the
-state transition NOT_USED => FILE_PAGE to a block (the other is
-buf_page_create). */
-
-buf_block_t*
-buf_page_init_for_read(
-/*===================*/
- /* out: pointer to the block or NULL */
- ulint* err, /* out: DB_SUCCESS or DB_TABLESPACE_DELETED */
- ulint mode, /* in: BUF_READ_IBUF_PAGES_ONLY, ... */
- ulint space, /* in: space id */
- ib_longlong tablespace_version,/* in: prevents reading from a wrong
- version of the tablespace in case we have done
- DISCARD + IMPORT */
- ulint offset) /* in: page number */
-{
- buf_block_t* block;
- mtr_t mtr;
-
- ut_ad(buf_pool);
-
- *err = DB_SUCCESS;
-
- if (mode == BUF_READ_IBUF_PAGES_ONLY) {
- /* It is a read-ahead within an ibuf routine */
-
- ut_ad(!ibuf_bitmap_page(offset));
- ut_ad(ibuf_inside());
-
- mtr_start(&mtr);
-
- if (!ibuf_page_low(space, offset, &mtr)) {
-
- mtr_commit(&mtr);
-
- return(NULL);
- }
- } else {
- ut_ad(mode == BUF_READ_ANY_PAGE);
- }
-
- block = buf_block_alloc();
-
- ut_a(block);
-
- mutex_enter(&(buf_pool->mutex));
- mutex_enter(&block->mutex);
-
- if (fil_tablespace_deleted_or_being_deleted_in_mem(
- space, tablespace_version)) {
- *err = DB_TABLESPACE_DELETED;
- }
-
- if (*err == DB_TABLESPACE_DELETED
- || NULL != buf_page_hash_get(space, offset)) {
-
- /* The page belongs to a space which has been
- deleted or is being deleted, or the page is
- already in buf_pool, return */
-
- mutex_exit(&block->mutex);
- mutex_exit(&(buf_pool->mutex));
-
- buf_block_free(block);
-
- if (mode == BUF_READ_IBUF_PAGES_ONLY) {
-
- mtr_commit(&mtr);
- }
-
- return(NULL);
- }
-
- ut_ad(block);
-
- buf_page_init(space, offset, block);
-
- /* The block must be put to the LRU list, to the old blocks */
-
- buf_LRU_add_block(block, TRUE); /* TRUE == to old blocks */
-
- block->io_fix = BUF_IO_READ;
-
- buf_pool->n_pend_reads++;
-
- /* We set a pass-type x-lock on the frame because then the same
- thread which called for the read operation (and is running now at
- this point of code) can wait for the read to complete by waiting
- for the x-lock on the frame; if the x-lock were recursive, the
- same thread would illegally get the x-lock before the page read
- is completed. The x-lock is cleared by the io-handler thread. */
-
- rw_lock_x_lock_gen(&(block->lock), BUF_IO_READ);
-
- mutex_exit(&block->mutex);
- mutex_exit(&(buf_pool->mutex));
-
- if (mode == BUF_READ_IBUF_PAGES_ONLY) {
-
- mtr_commit(&mtr);
- }
-
- return(block);
-}
-
-/************************************************************************
-Initializes a page to the buffer buf_pool. The page is usually not read
-from a file even if it cannot be found in the buffer buf_pool. This is one
-of the functions which perform to a block a state transition NOT_USED =>
-FILE_PAGE (the other is buf_page_init_for_read above). */
-
-buf_frame_t*
-buf_page_create(
-/*============*/
- /* out: pointer to the frame, page bufferfixed */
- ulint space, /* in: space id */
- ulint offset, /* in: offset of the page within space in units of
- a page */
- mtr_t* mtr) /* in: mini-transaction handle */
-{
- buf_frame_t* frame;
- buf_block_t* block;
- buf_block_t* free_block = NULL;
-
- ut_ad(mtr);
-
- free_block = buf_LRU_get_free_block();
-
- mutex_enter(&(buf_pool->mutex));
-
- block = buf_page_hash_get(space, offset);
-
- if (block != NULL) {
-#ifdef UNIV_IBUF_DEBUG
- ut_a(ibuf_count_get(block->space, block->offset) == 0);
-#endif
- block->file_page_was_freed = FALSE;
-
- /* Page can be found in buf_pool */
- mutex_exit(&(buf_pool->mutex));
-
- buf_block_free(free_block);
-
- frame = buf_page_get_with_no_latch(space, offset, mtr);
-
- return(frame);
- }
-
- /* If we get here, the page was not in buf_pool: init it there */
-
-#ifdef UNIV_DEBUG
- if (buf_debug_prints) {
- fprintf(stderr, "Creating space %lu page %lu to buffer\n",
- (ulong) space, (ulong) offset);
- }
-#endif /* UNIV_DEBUG */
-
- block = free_block;
-
- mutex_enter(&block->mutex);
-
- buf_page_init(space, offset, block);
-
- /* The block must be put to the LRU list */
- buf_LRU_add_block(block, FALSE);
-
-#ifdef UNIV_SYNC_DEBUG
- buf_block_buf_fix_inc_debug(block, __FILE__, __LINE__);
-#else
- buf_block_buf_fix_inc(block);
-#endif
- buf_pool->n_pages_created++;
-
- mutex_exit(&(buf_pool->mutex));
-
- mtr_memo_push(mtr, block, MTR_MEMO_BUF_FIX);
-
- block->accessed = TRUE;
-
- mutex_exit(&block->mutex);
-
- /* Delete possible entries for the page from the insert buffer:
- such can exist if the page belonged to an index which was dropped */
-
- ibuf_merge_or_delete_for_page(NULL, space, offset, TRUE);
-
- /* Flush pages from the end of the LRU list if necessary */
- buf_flush_free_margin();
-
- frame = block->frame;
-
- memset(frame + FIL_PAGE_PREV, 0xff, 4);
- memset(frame + FIL_PAGE_NEXT, 0xff, 4);
- mach_write_to_2(frame + FIL_PAGE_TYPE, FIL_PAGE_TYPE_ALLOCATED);
-
- /* Reset to zero the file flush lsn field in the page; if the first
- page of an ibdata file is 'created' in this function into the buffer
- pool then we lose the original contents of the file flush lsn stamp.
- Then InnoDB could in a crash recovery print a big, false, corruption
- warning if the stamp contains an lsn bigger than the ib_logfile lsn. */
-
- memset(frame + FIL_PAGE_FILE_FLUSH_LSN, 0, 8);
-
-#ifdef UNIV_DEBUG
- buf_dbg_counter++;
-
- if (buf_dbg_counter % 357 == 0) {
- ut_ad(buf_validate());
- }
-#endif
-#ifdef UNIV_IBUF_DEBUG
- ut_a(ibuf_count_get(block->space, block->offset) == 0);
-#endif
- return(frame);
-}
-
-/************************************************************************
-Completes an asynchronous read or write request of a file page to or from
-the buffer pool. */
-
-void
-buf_page_io_complete(
-/*=================*/
- buf_block_t* block) /* in: pointer to the block in question */
-{
- ulint io_type;
-
- ut_ad(block);
-
- ut_a(block->state == BUF_BLOCK_FILE_PAGE);
-
- /* We do not need protect block->io_fix here by block->mutex to read
- it because this is the only function where we can change the value
- from BUF_IO_READ or BUF_IO_WRITE to some other value, and our code
- ensures that this is the only thread that handles the i/o for this
- block. */
-
- io_type = block->io_fix;
-
- if (io_type == BUF_IO_READ) {
- /* If this page is not uninitialized and not in the
- doublewrite buffer, then the page number and space id
- should be the same as in block. */
- ulint read_page_no = mach_read_from_4(
- block->frame + FIL_PAGE_OFFSET);
- ulint read_space_id = mach_read_from_4(
- block->frame + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID);
-
- if (!block->space
- && trx_doublewrite_page_inside(block->offset)) {
-
- ut_print_timestamp(stderr);
- fprintf(stderr,
- " InnoDB: Error: reading page %lu\n"
- "InnoDB: which is in the"
- " doublewrite buffer!\n",
- (ulong) block->offset);
- } else if (!read_space_id && !read_page_no) {
- /* This is likely an uninitialized page. */
- } else if ((block->space && block->space != read_space_id)
- || block->offset != read_page_no) {
- /* We did not compare space_id to read_space_id
- if block->space == 0, because the field on the
- page may contain garbage in MySQL < 4.1.1,
- which only supported block->space == 0. */
-
- ut_print_timestamp(stderr);
- fprintf(stderr,
- " InnoDB: Error: space id and page n:o"
- " stored in the page\n"
- "InnoDB: read in are %lu:%lu,"
- " should be %lu:%lu!\n",
- (ulong) read_space_id, (ulong) read_page_no,
- (ulong) block->space, (ulong) block->offset);
- }
- /* From version 3.23.38 up we store the page checksum
- to the 4 first bytes of the page end lsn field */
-
- if (buf_page_is_corrupted(block->frame)) {
- fprintf(stderr,
- "InnoDB: Database page corruption on disk"
- " or a failed\n"
- "InnoDB: file read of page %lu.\n",
- (ulong) block->offset);
-
- fputs("InnoDB: You may have to recover"
- " from a backup.\n", stderr);
-
- buf_page_print(block->frame);
-
- fprintf(stderr,
- "InnoDB: Database page corruption on disk"
- " or a failed\n"
- "InnoDB: file read of page %lu.\n",
- (ulong) block->offset);
- fputs("InnoDB: You may have to recover"
- " from a backup.\n", stderr);
- fputs("InnoDB: It is also possible that"
- " your operating\n"
- "InnoDB: system has corrupted its"
- " own file cache\n"
- "InnoDB: and rebooting your computer"
- " removes the\n"
- "InnoDB: error.\n"
- "InnoDB: If the corrupt page is an index page\n"
- "InnoDB: you can also try to"
- " fix the corruption\n"
- "InnoDB: by dumping, dropping,"
- " and reimporting\n"
- "InnoDB: the corrupt table."
- " You can use CHECK\n"
- "InnoDB: TABLE to scan your"
- " table for corruption.\n"
- "InnoDB: See also"
- " http://dev.mysql.com/doc/refman/5.1/en/"
- "forcing-recovery.html\n"
- "InnoDB: about forcing recovery.\n", stderr);
-
- if (srv_force_recovery < SRV_FORCE_IGNORE_CORRUPT) {
- fputs("InnoDB: Ending processing because of"
- " a corrupt database page.\n",
- stderr);
- exit(1);
- }
- }
-
- if (recv_recovery_is_on()) {
- recv_recover_page(FALSE, TRUE, block->frame,
- block->space, block->offset);
- }
-
- if (!recv_no_ibuf_operations) {
- ibuf_merge_or_delete_for_page(
- block->frame, block->space, block->offset,
- TRUE);
- }
- }
-
- mutex_enter(&(buf_pool->mutex));
- mutex_enter(&block->mutex);
-
-#ifdef UNIV_IBUF_DEBUG
- ut_a(ibuf_count_get(block->space, block->offset) == 0);
-#endif
- /* Because this thread which does the unlocking is not the same that
- did the locking, we use a pass value != 0 in unlock, which simply
- removes the newest lock debug record, without checking the thread
- id. */
-
- block->io_fix = 0;
-
- if (io_type == BUF_IO_READ) {
- /* NOTE that the call to ibuf may have moved the ownership of
- the x-latch to this OS thread: do not let this confuse you in
- debugging! */
-
- ut_ad(buf_pool->n_pend_reads > 0);
- buf_pool->n_pend_reads--;
- buf_pool->n_pages_read++;
-
- rw_lock_x_unlock_gen(&(block->lock), BUF_IO_READ);
-
-#ifdef UNIV_DEBUG
- if (buf_debug_prints) {
- fputs("Has read ", stderr);
- }
-#endif /* UNIV_DEBUG */
- } else {
- ut_ad(io_type == BUF_IO_WRITE);
-
- /* Write means a flush operation: call the completion
- routine in the flush system */
-
- buf_flush_write_complete(block);
-
- rw_lock_s_unlock_gen(&(block->lock), BUF_IO_WRITE);
-
- buf_pool->n_pages_written++;
-
-#ifdef UNIV_DEBUG
- if (buf_debug_prints) {
- fputs("Has written ", stderr);
- }
-#endif /* UNIV_DEBUG */
- }
-
- mutex_exit(&block->mutex);
- mutex_exit(&(buf_pool->mutex));
-
-#ifdef UNIV_DEBUG
- if (buf_debug_prints) {
- fprintf(stderr, "page space %lu page no %lu\n",
- (ulong) block->space, (ulong) block->offset);
- }
-#endif /* UNIV_DEBUG */
-}
-
-/*************************************************************************
-Invalidates the file pages in the buffer pool when an archive recovery is
-completed. All the file pages buffered must be in a replaceable state when
-this function is called: not latched and not modified. */
-
-void
-buf_pool_invalidate(void)
-/*=====================*/
-{
- ibool freed;
-
- ut_ad(buf_all_freed());
-
- freed = TRUE;
-
- while (freed) {
- freed = buf_LRU_search_and_free_block(100);
- }
-
- mutex_enter(&(buf_pool->mutex));
-
- ut_ad(UT_LIST_GET_LEN(buf_pool->LRU) == 0);
-
- mutex_exit(&(buf_pool->mutex));
-}
-
-#ifdef UNIV_DEBUG
-/*************************************************************************
-Validates the buffer buf_pool data structure. */
-
-ibool
-buf_validate(void)
-/*==============*/
-{
- buf_block_t* block;
- ulint i;
- ulint n_single_flush = 0;
- ulint n_lru_flush = 0;
- ulint n_list_flush = 0;
- ulint n_lru = 0;
- ulint n_flush = 0;
- ulint n_free = 0;
- ulint n_page = 0;
-
- ut_ad(buf_pool);
-
- mutex_enter(&(buf_pool->mutex));
-
- for (i = 0; i < buf_pool->curr_size; i++) {
-
- block = buf_pool_get_nth_block(buf_pool, i);
-
- mutex_enter(&block->mutex);
-
- if (block->state == BUF_BLOCK_FILE_PAGE) {
-
- ut_a(buf_page_hash_get(block->space,
- block->offset) == block);
- n_page++;
-
-#ifdef UNIV_IBUF_DEBUG
- ut_a((block->io_fix == BUF_IO_READ)
- || ibuf_count_get(block->space, block->offset)
- == 0);
-#endif
- if (block->io_fix == BUF_IO_WRITE) {
-
- if (block->flush_type == BUF_FLUSH_LRU) {
- n_lru_flush++;
- ut_a(rw_lock_is_locked(
- &block->lock,
- RW_LOCK_SHARED));
- } else if (block->flush_type
- == BUF_FLUSH_LIST) {
- n_list_flush++;
- } else if (block->flush_type
- == BUF_FLUSH_SINGLE_PAGE) {
- n_single_flush++;
- } else {
- ut_error;
- }
-
- } else if (block->io_fix == BUF_IO_READ) {
-
- ut_a(rw_lock_is_locked(&(block->lock),
- RW_LOCK_EX));
- }
-
- n_lru++;
-
- if (ut_dulint_cmp(block->oldest_modification,
- ut_dulint_zero) > 0) {
- n_flush++;
- }
-
- } else if (block->state == BUF_BLOCK_NOT_USED) {
- n_free++;
- }
-
- mutex_exit(&block->mutex);
- }
-
- if (n_lru + n_free > buf_pool->curr_size) {
- fprintf(stderr, "n LRU %lu, n free %lu\n",
- (ulong) n_lru, (ulong) n_free);
- ut_error;
- }
-
- ut_a(UT_LIST_GET_LEN(buf_pool->LRU) == n_lru);
- if (UT_LIST_GET_LEN(buf_pool->free) != n_free) {
- fprintf(stderr, "Free list len %lu, free blocks %lu\n",
- (ulong) UT_LIST_GET_LEN(buf_pool->free),
- (ulong) n_free);
- ut_error;
- }
- ut_a(UT_LIST_GET_LEN(buf_pool->flush_list) == n_flush);
-
- ut_a(buf_pool->n_flush[BUF_FLUSH_SINGLE_PAGE] == n_single_flush);
- ut_a(buf_pool->n_flush[BUF_FLUSH_LIST] == n_list_flush);
- ut_a(buf_pool->n_flush[BUF_FLUSH_LRU] == n_lru_flush);
-
- mutex_exit(&(buf_pool->mutex));
-
- ut_a(buf_LRU_validate());
- ut_a(buf_flush_validate());
-
- return(TRUE);
-}
-
-/*************************************************************************
-Prints info of the buffer buf_pool data structure. */
-
-void
-buf_print(void)
-/*===========*/
-{
- dulint* index_ids;
- ulint* counts;
- ulint size;
- ulint i;
- ulint j;
- dulint id;
- ulint n_found;
- buf_frame_t* frame;
- dict_index_t* index;
-
- ut_ad(buf_pool);
-
- size = buf_pool->curr_size;
-
- index_ids = mem_alloc(sizeof(dulint) * size);
- counts = mem_alloc(sizeof(ulint) * size);
-
- mutex_enter(&(buf_pool->mutex));
-
- fprintf(stderr,
- "buf_pool size %lu\n"
- "database pages %lu\n"
- "free pages %lu\n"
- "modified database pages %lu\n"
- "n pending reads %lu\n"
- "n pending flush LRU %lu list %lu single page %lu\n"
- "pages read %lu, created %lu, written %lu\n",
- (ulong) size,
- (ulong) UT_LIST_GET_LEN(buf_pool->LRU),
- (ulong) UT_LIST_GET_LEN(buf_pool->free),
- (ulong) UT_LIST_GET_LEN(buf_pool->flush_list),
- (ulong) buf_pool->n_pend_reads,
- (ulong) buf_pool->n_flush[BUF_FLUSH_LRU],
- (ulong) buf_pool->n_flush[BUF_FLUSH_LIST],
- (ulong) buf_pool->n_flush[BUF_FLUSH_SINGLE_PAGE],
- (ulong) buf_pool->n_pages_read, buf_pool->n_pages_created,
- (ulong) buf_pool->n_pages_written);
-
- /* Count the number of blocks belonging to each index in the buffer */
-
- n_found = 0;
-
- for (i = 0; i < size; i++) {
- frame = buf_pool_get_nth_block(buf_pool, i)->frame;
-
- if (fil_page_get_type(frame) == FIL_PAGE_INDEX) {
-
- id = btr_page_get_index_id(frame);
-
- /* Look for the id in the index_ids array */
- j = 0;
-
- while (j < n_found) {
-
- if (ut_dulint_cmp(index_ids[j], id) == 0) {
- (counts[j])++;
-
- break;
- }
- j++;
- }
-
- if (j == n_found) {
- n_found++;
- index_ids[j] = id;
- counts[j] = 1;
- }
- }
- }
-
- mutex_exit(&(buf_pool->mutex));
-
- for (i = 0; i < n_found; i++) {
- index = dict_index_get_if_in_cache(index_ids[i]);
-
- fprintf(stderr,
- "Block count for index %lu in buffer is about %lu",
- (ulong) ut_dulint_get_low(index_ids[i]),
- (ulong) counts[i]);
-
- if (index) {
- putc(' ', stderr);
- dict_index_name_print(stderr, NULL, index);
- }
-
- putc('\n', stderr);
- }
-
- mem_free(index_ids);
- mem_free(counts);
-
- ut_a(buf_validate());
-}
-
-/*************************************************************************
-Returns the number of latched pages in the buffer pool. */
-
-ulint
-buf_get_latched_pages_number(void)
-{
- buf_block_t* block;
- ulint i;
- ulint fixed_pages_number = 0;
-
- mutex_enter(&(buf_pool->mutex));
-
- for (i = 0; i < buf_pool->curr_size; i++) {
-
- block = buf_pool_get_nth_block(buf_pool, i);
-
- if (block->magic_n == BUF_BLOCK_MAGIC_N) {
- mutex_enter(&block->mutex);
-
- if (block->buf_fix_count != 0 || block->io_fix != 0) {
- fixed_pages_number++;
- }
-
- mutex_exit(&block->mutex);
- }
- }
-
- mutex_exit(&(buf_pool->mutex));
-
- return(fixed_pages_number);
-}
-#endif /* UNIV_DEBUG */
-
-/*************************************************************************
-Returns the number of pending buf pool ios. */
-
-ulint
-buf_get_n_pending_ios(void)
-/*=======================*/
-{
- return(buf_pool->n_pend_reads
- + buf_pool->n_flush[BUF_FLUSH_LRU]
- + buf_pool->n_flush[BUF_FLUSH_LIST]
- + buf_pool->n_flush[BUF_FLUSH_SINGLE_PAGE]);
-}
-
-/*************************************************************************
-Returns the ratio in percents of modified pages in the buffer pool /
-database pages in the buffer pool. */
-
-ulint
-buf_get_modified_ratio_pct(void)
-/*============================*/
-{
- ulint ratio;
-
- mutex_enter(&(buf_pool->mutex));
-
- ratio = (100 * UT_LIST_GET_LEN(buf_pool->flush_list))
- / (1 + UT_LIST_GET_LEN(buf_pool->LRU)
- + UT_LIST_GET_LEN(buf_pool->free));
-
- /* 1 + is there to avoid division by zero */
-
- mutex_exit(&(buf_pool->mutex));
-
- return(ratio);
-}
-
-/*************************************************************************
-Prints info of the buffer i/o. */
-
-void
-buf_print_io(
-/*=========*/
- FILE* file) /* in/out: buffer where to print */
-{
- time_t current_time;
- double time_elapsed;
- ulint size;
-
- ut_ad(buf_pool);
- size = buf_pool->curr_size;
-
- mutex_enter(&(buf_pool->mutex));
-
- if (srv_use_awe) {
- fprintf(stderr,
- "AWE: Buffer pool memory frames %lu\n",
- (ulong) buf_pool->n_frames);
-
- fprintf(stderr,
- "AWE: Database pages and free buffers"
- " mapped in frames %lu\n",
- (ulong)
- UT_LIST_GET_LEN(buf_pool->awe_LRU_free_mapped));
- }
- fprintf(file,
- "Buffer pool size %lu\n"
- "Free buffers %lu\n"
- "Database pages %lu\n"
- "Modified db pages %lu\n"
- "Pending reads %lu\n"
- "Pending writes: LRU %lu, flush list %lu, single page %lu\n",
- (ulong) size,
- (ulong) UT_LIST_GET_LEN(buf_pool->free),
- (ulong) UT_LIST_GET_LEN(buf_pool->LRU),
- (ulong) UT_LIST_GET_LEN(buf_pool->flush_list),
- (ulong) buf_pool->n_pend_reads,
- (ulong) buf_pool->n_flush[BUF_FLUSH_LRU]
- + buf_pool->init_flush[BUF_FLUSH_LRU],
- (ulong) buf_pool->n_flush[BUF_FLUSH_LIST]
- + buf_pool->init_flush[BUF_FLUSH_LIST],
- (ulong) buf_pool->n_flush[BUF_FLUSH_SINGLE_PAGE]);
-
- current_time = time(NULL);
- time_elapsed = 0.001 + difftime(current_time,
- buf_pool->last_printout_time);
- buf_pool->last_printout_time = current_time;
-
- fprintf(file,
- "Pages read %lu, created %lu, written %lu\n"
- "%.2f reads/s, %.2f creates/s, %.2f writes/s\n",
- (ulong) buf_pool->n_pages_read,
- (ulong) buf_pool->n_pages_created,
- (ulong) buf_pool->n_pages_written,
- (buf_pool->n_pages_read - buf_pool->n_pages_read_old)
- / time_elapsed,
- (buf_pool->n_pages_created - buf_pool->n_pages_created_old)
- / time_elapsed,
- (buf_pool->n_pages_written - buf_pool->n_pages_written_old)
- / time_elapsed);
-
- if (srv_use_awe) {
- fprintf(file, "AWE: %.2f page remaps/s\n",
- (buf_pool->n_pages_awe_remapped
- - buf_pool->n_pages_awe_remapped_old)
- / time_elapsed);
- }
-
- if (buf_pool->n_page_gets > buf_pool->n_page_gets_old) {
- fprintf(file, "Buffer pool hit rate %lu / 1000\n",
- (ulong)
- (1000 - ((1000 * (buf_pool->n_pages_read
- - buf_pool->n_pages_read_old))
- / (buf_pool->n_page_gets
- - buf_pool->n_page_gets_old))));
- } else {
- fputs("No buffer pool page gets since the last printout\n",
- file);
- }
-
- buf_pool->n_page_gets_old = buf_pool->n_page_gets;
- buf_pool->n_pages_read_old = buf_pool->n_pages_read;
- buf_pool->n_pages_created_old = buf_pool->n_pages_created;
- buf_pool->n_pages_written_old = buf_pool->n_pages_written;
- buf_pool->n_pages_awe_remapped_old = buf_pool->n_pages_awe_remapped;
-
- mutex_exit(&(buf_pool->mutex));
-}
-
-/**************************************************************************
-Refreshes the statistics used to print per-second averages. */
-
-void
-buf_refresh_io_stats(void)
-/*======================*/
-{
- buf_pool->last_printout_time = time(NULL);
- buf_pool->n_page_gets_old = buf_pool->n_page_gets;
- buf_pool->n_pages_read_old = buf_pool->n_pages_read;
- buf_pool->n_pages_created_old = buf_pool->n_pages_created;
- buf_pool->n_pages_written_old = buf_pool->n_pages_written;
- buf_pool->n_pages_awe_remapped_old = buf_pool->n_pages_awe_remapped;
-}
-
-/*************************************************************************
-Checks that all file pages in the buffer are in a replaceable state. */
-
-ibool
-buf_all_freed(void)
-/*===============*/
-{
- buf_block_t* block;
- ulint i;
-
- ut_ad(buf_pool);
-
- mutex_enter(&(buf_pool->mutex));
-
- for (i = 0; i < buf_pool->curr_size; i++) {
-
- block = buf_pool_get_nth_block(buf_pool, i);
-
- mutex_enter(&block->mutex);
-
- if (block->state == BUF_BLOCK_FILE_PAGE) {
-
- if (!buf_flush_ready_for_replace(block)) {
-
- fprintf(stderr,
- "Page %lu %lu still fixed or dirty\n",
- (ulong) block->space,
- (ulong) block->offset);
- ut_error;
- }
- }
-
- mutex_exit(&block->mutex);
- }
-
- mutex_exit(&(buf_pool->mutex));
-
- return(TRUE);
-}
-
-/*************************************************************************
-Checks that there currently are no pending i/o-operations for the buffer
-pool. */
-
-ibool
-buf_pool_check_no_pending_io(void)
-/*==============================*/
- /* out: TRUE if there is no pending i/o */
-{
- ibool ret;
-
- mutex_enter(&(buf_pool->mutex));
-
- if (buf_pool->n_pend_reads + buf_pool->n_flush[BUF_FLUSH_LRU]
- + buf_pool->n_flush[BUF_FLUSH_LIST]
- + buf_pool->n_flush[BUF_FLUSH_SINGLE_PAGE]) {
- ret = FALSE;
- } else {
- ret = TRUE;
- }
-
- mutex_exit(&(buf_pool->mutex));
-
- return(ret);
-}
-
-/*************************************************************************
-Gets the current length of the free list of buffer blocks. */
-
-ulint
-buf_get_free_list_len(void)
-/*=======================*/
-{
- ulint len;
-
- mutex_enter(&(buf_pool->mutex));
-
- len = UT_LIST_GET_LEN(buf_pool->free);
-
- mutex_exit(&(buf_pool->mutex));
-
- return(len);
-}
diff --git a/storage/innobase/buf/buf0flu.c b/storage/innobase/buf/buf0flu.c
deleted file mode 100644
index 423c08c0569..00000000000
--- a/storage/innobase/buf/buf0flu.c
+++ /dev/null
@@ -1,1115 +0,0 @@
-/******************************************************
-The database buffer buf_pool flush algorithm
-
-(c) 1995-2001 Innobase Oy
-
-Created 11/11/1995 Heikki Tuuri
-*******************************************************/
-
-#include "buf0flu.h"
-
-#ifdef UNIV_NONINL
-#include "buf0flu.ic"
-#include "trx0sys.h"
-#endif
-
-#include "ut0byte.h"
-#include "ut0lst.h"
-#include "page0page.h"
-#include "fil0fil.h"
-#include "buf0buf.h"
-#include "buf0lru.h"
-#include "buf0rea.h"
-#include "ibuf0ibuf.h"
-#include "log0log.h"
-#include "os0file.h"
-#include "trx0sys.h"
-#include "srv0srv.h"
-
-/* When flushed, dirty blocks are searched in neighborhoods of this size, and
-flushed along with the original page. */
-
-#define BUF_FLUSH_AREA ut_min(BUF_READ_AHEAD_AREA,\
- buf_pool->curr_size / 16)
-
-/**********************************************************************
-Validates the flush list. */
-static
-ibool
-buf_flush_validate_low(void);
-/*========================*/
- /* out: TRUE if ok */
-
-/************************************************************************
-Inserts a modified block into the flush list. */
-
-void
-buf_flush_insert_into_flush_list(
-/*=============================*/
- buf_block_t* block) /* in: block which is modified */
-{
- ut_ad(mutex_own(&(buf_pool->mutex)));
- ut_a(block->state == BUF_BLOCK_FILE_PAGE);
-
- ut_ad((UT_LIST_GET_FIRST(buf_pool->flush_list) == NULL)
- || (ut_dulint_cmp((UT_LIST_GET_FIRST(buf_pool->flush_list))
- ->oldest_modification,
- block->oldest_modification) <= 0));
-
- UT_LIST_ADD_FIRST(flush_list, buf_pool->flush_list, block);
-
- ut_ad(buf_flush_validate_low());
-}
-
-/************************************************************************
-Inserts a modified block into the flush list in the right sorted position.
-This function is used by recovery, because there the modifications do not
-necessarily come in the order of lsn's. */
-
-void
-buf_flush_insert_sorted_into_flush_list(
-/*====================================*/
- buf_block_t* block) /* in: block which is modified */
-{
- buf_block_t* prev_b;
- buf_block_t* b;
-
- ut_ad(mutex_own(&(buf_pool->mutex)));
-
- prev_b = NULL;
- b = UT_LIST_GET_FIRST(buf_pool->flush_list);
-
- while (b && (ut_dulint_cmp(b->oldest_modification,
- block->oldest_modification) > 0)) {
- prev_b = b;
- b = UT_LIST_GET_NEXT(flush_list, b);
- }
-
- if (prev_b == NULL) {
- UT_LIST_ADD_FIRST(flush_list, buf_pool->flush_list, block);
- } else {
- UT_LIST_INSERT_AFTER(flush_list, buf_pool->flush_list, prev_b,
- block);
- }
-
- ut_ad(buf_flush_validate_low());
-}
-
-/************************************************************************
-Returns TRUE if the file page block is immediately suitable for replacement,
-i.e., the transition FILE_PAGE => NOT_USED allowed. */
-
-ibool
-buf_flush_ready_for_replace(
-/*========================*/
- /* out: TRUE if can replace immediately */
- buf_block_t* block) /* in: buffer control block, must be in state
- BUF_BLOCK_FILE_PAGE and in the LRU list */
-{
- ut_ad(mutex_own(&(buf_pool->mutex)));
- ut_ad(mutex_own(&block->mutex));
- if (block->state != BUF_BLOCK_FILE_PAGE) {
- ut_print_timestamp(stderr);
- fprintf(stderr,
- " InnoDB: Error: buffer block state %lu"
- " in the LRU list!\n",
- (ulong)block->state);
- ut_print_buf(stderr, block, sizeof(buf_block_t));
-
- return(FALSE);
- }
-
- if ((ut_dulint_cmp(block->oldest_modification, ut_dulint_zero) > 0)
- || (block->buf_fix_count != 0)
- || (block->io_fix != 0)) {
-
- return(FALSE);
- }
-
- return(TRUE);
-}
-
-/************************************************************************
-Returns TRUE if the block is modified and ready for flushing. */
-UNIV_INLINE
-ibool
-buf_flush_ready_for_flush(
-/*======================*/
- /* out: TRUE if can flush immediately */
- buf_block_t* block, /* in: buffer control block, must be in state
- BUF_BLOCK_FILE_PAGE */
- ulint flush_type)/* in: BUF_FLUSH_LRU or BUF_FLUSH_LIST */
-{
- ut_ad(mutex_own(&(buf_pool->mutex)));
- ut_ad(mutex_own(&(block->mutex)));
- ut_a(block->state == BUF_BLOCK_FILE_PAGE);
-
- if ((ut_dulint_cmp(block->oldest_modification, ut_dulint_zero) > 0)
- && (block->io_fix == 0)) {
- if (flush_type != BUF_FLUSH_LRU) {
-
- return(TRUE);
-
- } else if (block->buf_fix_count == 0) {
-
- /* If we are flushing the LRU list, to avoid deadlocks
- we require the block not to be bufferfixed, and hence
- not latched. */
-
- return(TRUE);
- }
- }
-
- return(FALSE);
-}
-
-/************************************************************************
-Updates the flush system data structures when a write is completed. */
-
-void
-buf_flush_write_complete(
-/*=====================*/
- buf_block_t* block) /* in: pointer to the block in question */
-{
- ut_ad(block);
-#ifdef UNIV_SYNC_DEBUG
- ut_ad(mutex_own(&(buf_pool->mutex)));
-#endif /* UNIV_SYNC_DEBUG */
- ut_a(block->state == BUF_BLOCK_FILE_PAGE);
-
- block->oldest_modification = ut_dulint_zero;
-
- UT_LIST_REMOVE(flush_list, buf_pool->flush_list, block);
-
- ut_d(UT_LIST_VALIDATE(flush_list, buf_block_t, buf_pool->flush_list));
-
- (buf_pool->n_flush[block->flush_type])--;
-
- if (block->flush_type == BUF_FLUSH_LRU) {
- /* Put the block to the end of the LRU list to wait to be
- moved to the free list */
-
- buf_LRU_make_block_old(block);
-
- buf_pool->LRU_flush_ended++;
- }
-
- /* fprintf(stderr, "n pending flush %lu\n",
- buf_pool->n_flush[block->flush_type]); */
-
- if ((buf_pool->n_flush[block->flush_type] == 0)
- && (buf_pool->init_flush[block->flush_type] == FALSE)) {
-
- /* The running flush batch has ended */
-
- os_event_set(buf_pool->no_flush[block->flush_type]);
- }
-}
-
-/************************************************************************
-Flushes possible buffered writes from the doublewrite memory buffer to disk,
-and also wakes up the aio thread if simulated aio is used. It is very
-important to call this function after a batch of writes has been posted,
-and also when we may have to wait for a page latch! Otherwise a deadlock
-of threads can occur. */
-static
-void
-buf_flush_buffered_writes(void)
-/*===========================*/
-{
- buf_block_t* block;
- byte* write_buf;
- ulint len;
- ulint len2;
- ulint i;
-
- if (!srv_use_doublewrite_buf || trx_doublewrite == NULL) {
- os_aio_simulated_wake_handler_threads();
-
- return;
- }
-
- mutex_enter(&(trx_doublewrite->mutex));
-
- /* Write first to doublewrite buffer blocks. We use synchronous
- aio and thus know that file write has been completed when the
- control returns. */
-
- if (trx_doublewrite->first_free == 0) {
-
- mutex_exit(&(trx_doublewrite->mutex));
-
- return;
- }
-
- for (i = 0; i < trx_doublewrite->first_free; i++) {
-
- block = trx_doublewrite->buf_block_arr[i];
- ut_a(block->state == BUF_BLOCK_FILE_PAGE);
-
- if (mach_read_from_4(block->frame + FIL_PAGE_LSN + 4)
- != mach_read_from_4(block->frame + UNIV_PAGE_SIZE
- - FIL_PAGE_END_LSN_OLD_CHKSUM + 4)) {
- ut_print_timestamp(stderr);
- fprintf(stderr,
- " InnoDB: ERROR: The page to be written"
- " seems corrupt!\n"
- "InnoDB: The lsn fields do not match!"
- " Noticed in the buffer pool\n"
- "InnoDB: before posting to the"
- " doublewrite buffer.\n");
- }
-
- if (block->check_index_page_at_flush
- && !page_simple_validate(block->frame)) {
-
- buf_page_print(block->frame);
-
- ut_print_timestamp(stderr);
- fprintf(stderr,
- " InnoDB: Apparent corruption of an"
- " index page n:o %lu in space %lu\n"
- "InnoDB: to be written to data file."
- " We intentionally crash server\n"
- "InnoDB: to prevent corrupt data"
- " from ending up in data\n"
- "InnoDB: files.\n",
- (ulong) block->offset, (ulong) block->space);
-
- ut_error;
- }
- }
-
- /* increment the doublewrite flushed pages counter */
- srv_dblwr_pages_written+= trx_doublewrite->first_free;
- srv_dblwr_writes++;
-
- if (trx_doublewrite->first_free > TRX_SYS_DOUBLEWRITE_BLOCK_SIZE) {
- len = TRX_SYS_DOUBLEWRITE_BLOCK_SIZE * UNIV_PAGE_SIZE;
- } else {
- len = trx_doublewrite->first_free * UNIV_PAGE_SIZE;
- }
-
- fil_io(OS_FILE_WRITE,
- TRUE, TRX_SYS_SPACE,
- trx_doublewrite->block1, 0, len,
- (void*)trx_doublewrite->write_buf, NULL);
-
- write_buf = trx_doublewrite->write_buf;
-
- for (len2 = 0; len2 + UNIV_PAGE_SIZE <= len; len2 += UNIV_PAGE_SIZE) {
- if (mach_read_from_4(write_buf + len2 + FIL_PAGE_LSN + 4)
- != mach_read_from_4(write_buf + len2 + UNIV_PAGE_SIZE
- - FIL_PAGE_END_LSN_OLD_CHKSUM + 4)) {
- ut_print_timestamp(stderr);
- fprintf(stderr,
- " InnoDB: ERROR: The page to be written"
- " seems corrupt!\n"
- "InnoDB: The lsn fields do not match!"
- " Noticed in the doublewrite block1.\n");
- }
- }
-
- if (trx_doublewrite->first_free > TRX_SYS_DOUBLEWRITE_BLOCK_SIZE) {
- len = (trx_doublewrite->first_free
- - TRX_SYS_DOUBLEWRITE_BLOCK_SIZE) * UNIV_PAGE_SIZE;
-
- fil_io(OS_FILE_WRITE,
- TRUE, TRX_SYS_SPACE,
- trx_doublewrite->block2, 0, len,
- (void*)(trx_doublewrite->write_buf
- + TRX_SYS_DOUBLEWRITE_BLOCK_SIZE
- * UNIV_PAGE_SIZE),
- NULL);
-
- write_buf = trx_doublewrite->write_buf
- + TRX_SYS_DOUBLEWRITE_BLOCK_SIZE * UNIV_PAGE_SIZE;
- for (len2 = 0; len2 + UNIV_PAGE_SIZE <= len;
- len2 += UNIV_PAGE_SIZE) {
- if (mach_read_from_4(write_buf + len2
- + FIL_PAGE_LSN + 4)
- != mach_read_from_4(write_buf + len2
- + UNIV_PAGE_SIZE
- - FIL_PAGE_END_LSN_OLD_CHKSUM
- + 4)) {
- ut_print_timestamp(stderr);
- fprintf(stderr,
- " InnoDB: ERROR: The page to be"
- " written seems corrupt!\n"
- "InnoDB: The lsn fields do not match!"
- " Noticed in"
- " the doublewrite block2.\n");
- }
- }
- }
-
- /* Now flush the doublewrite buffer data to disk */
-
- fil_flush(TRX_SYS_SPACE);
-
- /* We know that the writes have been flushed to disk now
- and in recovery we will find them in the doublewrite buffer
- blocks. Next do the writes to the intended positions. */
-
- for (i = 0; i < trx_doublewrite->first_free; i++) {
- block = trx_doublewrite->buf_block_arr[i];
-
- if (mach_read_from_4(block->frame + FIL_PAGE_LSN + 4)
- != mach_read_from_4(block->frame + UNIV_PAGE_SIZE
- - FIL_PAGE_END_LSN_OLD_CHKSUM + 4)) {
- ut_print_timestamp(stderr);
- fprintf(stderr,
- " InnoDB: ERROR: The page to be written"
- " seems corrupt!\n"
- "InnoDB: The lsn fields do not match!"
- " Noticed in the buffer pool\n"
- "InnoDB: after posting and flushing"
- " the doublewrite buffer.\n"
- "InnoDB: Page buf fix count %lu,"
- " io fix %lu, state %lu\n",
- (ulong)block->buf_fix_count,
- (ulong)block->io_fix,
- (ulong)block->state);
- }
- ut_a(block->state == BUF_BLOCK_FILE_PAGE);
-
- fil_io(OS_FILE_WRITE | OS_AIO_SIMULATED_WAKE_LATER,
- FALSE, block->space, block->offset, 0, UNIV_PAGE_SIZE,
- (void*)block->frame, (void*)block);
- }
-
- /* Wake possible simulated aio thread to actually post the
- writes to the operating system */
-
- os_aio_simulated_wake_handler_threads();
-
- /* Wait that all async writes to tablespaces have been posted to
- the OS */
-
- os_aio_wait_until_no_pending_writes();
-
- /* Now we flush the data to disk (for example, with fsync) */
-
- fil_flush_file_spaces(FIL_TABLESPACE);
-
- /* We can now reuse the doublewrite memory buffer: */
-
- trx_doublewrite->first_free = 0;
-
- mutex_exit(&(trx_doublewrite->mutex));
-}
-
-/************************************************************************
-Posts a buffer page for writing. If the doublewrite memory buffer is
-full, calls buf_flush_buffered_writes and waits for for free space to
-appear. */
-static
-void
-buf_flush_post_to_doublewrite_buf(
-/*==============================*/
- buf_block_t* block) /* in: buffer block to write */
-{
-try_again:
- mutex_enter(&(trx_doublewrite->mutex));
-
- ut_a(block->state == BUF_BLOCK_FILE_PAGE);
-
- if (trx_doublewrite->first_free
- >= 2 * TRX_SYS_DOUBLEWRITE_BLOCK_SIZE) {
- mutex_exit(&(trx_doublewrite->mutex));
-
- buf_flush_buffered_writes();
-
- goto try_again;
- }
-
- ut_memcpy(trx_doublewrite->write_buf
- + UNIV_PAGE_SIZE * trx_doublewrite->first_free,
- block->frame, UNIV_PAGE_SIZE);
-
- trx_doublewrite->buf_block_arr[trx_doublewrite->first_free] = block;
-
- trx_doublewrite->first_free++;
-
- if (trx_doublewrite->first_free
- >= 2 * TRX_SYS_DOUBLEWRITE_BLOCK_SIZE) {
- mutex_exit(&(trx_doublewrite->mutex));
-
- buf_flush_buffered_writes();
-
- return;
- }
-
- mutex_exit(&(trx_doublewrite->mutex));
-}
-
-/************************************************************************
-Initializes a page for writing to the tablespace. */
-
-void
-buf_flush_init_for_writing(
-/*=======================*/
- byte* page, /* in: page */
- dulint newest_lsn, /* in: newest modification lsn to the page */
- ulint space, /* in: space id */
- ulint page_no) /* in: page number */
-{
- /* Write the newest modification lsn to the page header and trailer */
- mach_write_to_8(page + FIL_PAGE_LSN, newest_lsn);
-
- mach_write_to_8(page + UNIV_PAGE_SIZE - FIL_PAGE_END_LSN_OLD_CHKSUM,
- newest_lsn);
- /* Write the page number and the space id */
-
- mach_write_to_4(page + FIL_PAGE_OFFSET, page_no);
- mach_write_to_4(page + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID, space);
-
- /* Store the new formula checksum */
-
- mach_write_to_4(page + FIL_PAGE_SPACE_OR_CHKSUM,
- srv_use_checksums
- ? buf_calc_page_new_checksum(page)
- : BUF_NO_CHECKSUM_MAGIC);
-
- /* We overwrite the first 4 bytes of the end lsn field to store
- the old formula checksum. Since it depends also on the field
- FIL_PAGE_SPACE_OR_CHKSUM, it has to be calculated after storing the
- new formula checksum. */
-
- mach_write_to_4(page + UNIV_PAGE_SIZE - FIL_PAGE_END_LSN_OLD_CHKSUM,
- srv_use_checksums
- ? buf_calc_page_old_checksum(page)
- : BUF_NO_CHECKSUM_MAGIC);
-}
-
-/************************************************************************
-Does an asynchronous write of a buffer page. NOTE: in simulated aio and
-also when the doublewrite buffer is used, we must call
-buf_flush_buffered_writes after we have posted a batch of writes! */
-static
-void
-buf_flush_write_block_low(
-/*======================*/
- buf_block_t* block) /* in: buffer block to write */
-{
-#ifdef UNIV_LOG_DEBUG
- static ibool univ_log_debug_warned;
-#endif /* UNIV_LOG_DEBUG */
- ut_a(block->state == BUF_BLOCK_FILE_PAGE);
-
-#ifdef UNIV_IBUF_DEBUG
- ut_a(ibuf_count_get(block->space, block->offset) == 0);
-#endif
- ut_ad(!ut_dulint_is_zero(block->newest_modification));
-
-#ifdef UNIV_LOG_DEBUG
- if (!univ_log_debug_warned) {
- univ_log_debug_warned = TRUE;
- fputs("Warning: cannot force log to disk if"
- " UNIV_LOG_DEBUG is defined!\n"
- "Crash recovery will not work!\n",
- stderr);
- }
-#else
- /* Force the log to the disk before writing the modified block */
- log_write_up_to(block->newest_modification, LOG_WAIT_ALL_GROUPS, TRUE);
-#endif
- buf_flush_init_for_writing(block->frame, block->newest_modification,
- block->space, block->offset);
- if (!srv_use_doublewrite_buf || !trx_doublewrite) {
- fil_io(OS_FILE_WRITE | OS_AIO_SIMULATED_WAKE_LATER,
- FALSE, block->space, block->offset, 0, UNIV_PAGE_SIZE,
- (void*)block->frame, (void*)block);
- } else {
- buf_flush_post_to_doublewrite_buf(block);
- }
-}
-
-/************************************************************************
-Writes a page asynchronously from the buffer buf_pool to a file, if it can be
-found in the buf_pool and it is in a flushable state. NOTE: in simulated aio
-we must call os_aio_simulated_wake_handler_threads after we have posted a batch
-of writes! */
-static
-ulint
-buf_flush_try_page(
-/*===============*/
- /* out: 1 if a page was flushed, 0 otherwise */
- ulint space, /* in: space id */
- ulint offset, /* in: page offset */
- ulint flush_type) /* in: BUF_FLUSH_LRU, BUF_FLUSH_LIST, or
- BUF_FLUSH_SINGLE_PAGE */
-{
- buf_block_t* block;
- ibool locked;
-
- ut_ad(flush_type == BUF_FLUSH_LRU || flush_type == BUF_FLUSH_LIST
- || flush_type == BUF_FLUSH_SINGLE_PAGE);
-
- mutex_enter(&(buf_pool->mutex));
-
- block = buf_page_hash_get(space, offset);
-
- ut_a(!block || block->state == BUF_BLOCK_FILE_PAGE);
-
- if (!block) {
- mutex_exit(&(buf_pool->mutex));
- return(0);
- }
-
- mutex_enter(&block->mutex);
-
- if (flush_type == BUF_FLUSH_LIST
- && buf_flush_ready_for_flush(block, flush_type)) {
-
- block->io_fix = BUF_IO_WRITE;
-
- /* If AWE is enabled and the page is not mapped to a frame,
- then map it */
-
- if (block->frame == NULL) {
- ut_a(srv_use_awe);
-
- /* We set second parameter TRUE because the block is
- in the LRU list and we must put it to
- awe_LRU_free_mapped list once mapped to a frame */
-
- buf_awe_map_page_to_frame(block, TRUE);
- }
-
- block->flush_type = flush_type;
-
- if (buf_pool->n_flush[flush_type] == 0) {
-
- os_event_reset(buf_pool->no_flush[flush_type]);
- }
-
- (buf_pool->n_flush[flush_type])++;
-
- locked = FALSE;
-
- /* If the simulated aio thread is not running, we must
- not wait for any latch, as we may end up in a deadlock:
- if buf_fix_count == 0, then we know we need not wait */
-
- if (block->buf_fix_count == 0) {
- rw_lock_s_lock_gen(&(block->lock), BUF_IO_WRITE);
-
- locked = TRUE;
- }
-
- mutex_exit(&block->mutex);
- mutex_exit(&(buf_pool->mutex));
-
- if (!locked) {
- buf_flush_buffered_writes();
-
- rw_lock_s_lock_gen(&(block->lock), BUF_IO_WRITE);
- }
-
-#ifdef UNIV_DEBUG
- if (buf_debug_prints) {
- fprintf(stderr,
- "Flushing page space %lu, page no %lu \n",
- (ulong) block->space, (ulong) block->offset);
- }
-#endif /* UNIV_DEBUG */
-
- buf_flush_write_block_low(block);
-
- return(1);
-
- } else if (flush_type == BUF_FLUSH_LRU
- && buf_flush_ready_for_flush(block, flush_type)) {
-
- /* VERY IMPORTANT:
- Because any thread may call the LRU flush, even when owning
- locks on pages, to avoid deadlocks, we must make sure that the
- s-lock is acquired on the page without waiting: this is
- accomplished because in the if-condition above we require
- the page not to be bufferfixed (in function
- ..._ready_for_flush). */
-
- block->io_fix = BUF_IO_WRITE;
-
- /* If AWE is enabled and the page is not mapped to a frame,
- then map it */
-
- if (block->frame == NULL) {
- ut_a(srv_use_awe);
-
- /* We set second parameter TRUE because the block is
- in the LRU list and we must put it to
- awe_LRU_free_mapped list once mapped to a frame */
-
- buf_awe_map_page_to_frame(block, TRUE);
- }
-
- block->flush_type = flush_type;
-
- if (buf_pool->n_flush[flush_type] == 0) {
-
- os_event_reset(buf_pool->no_flush[flush_type]);
- }
-
- (buf_pool->n_flush[flush_type])++;
-
- rw_lock_s_lock_gen(&(block->lock), BUF_IO_WRITE);
-
- /* Note that the s-latch is acquired before releasing the
- buf_pool mutex: this ensures that the latch is acquired
- immediately. */
-
- mutex_exit(&block->mutex);
- mutex_exit(&(buf_pool->mutex));
-
- buf_flush_write_block_low(block);
-
- return(1);
-
- } else if (flush_type == BUF_FLUSH_SINGLE_PAGE
- && buf_flush_ready_for_flush(block, flush_type)) {
-
- block->io_fix = BUF_IO_WRITE;
-
- /* If AWE is enabled and the page is not mapped to a frame,
- then map it */
-
- if (block->frame == NULL) {
- ut_a(srv_use_awe);
-
- /* We set second parameter TRUE because the block is
- in the LRU list and we must put it to
- awe_LRU_free_mapped list once mapped to a frame */
-
- buf_awe_map_page_to_frame(block, TRUE);
- }
-
- block->flush_type = flush_type;
-
- if (buf_pool->n_flush[block->flush_type] == 0) {
-
- os_event_reset(buf_pool->no_flush[block->flush_type]);
- }
-
- (buf_pool->n_flush[flush_type])++;
-
- mutex_exit(&block->mutex);
- mutex_exit(&(buf_pool->mutex));
-
- rw_lock_s_lock_gen(&(block->lock), BUF_IO_WRITE);
-
-#ifdef UNIV_DEBUG
- if (buf_debug_prints) {
- fprintf(stderr,
- "Flushing single page space %lu,"
- " page no %lu \n",
- (ulong) block->space,
- (ulong) block->offset);
- }
-#endif /* UNIV_DEBUG */
-
- buf_flush_write_block_low(block);
-
- return(1);
- }
-
- mutex_exit(&block->mutex);
- mutex_exit(&(buf_pool->mutex));
-
- return(0);
-}
-
-/***************************************************************
-Flushes to disk all flushable pages within the flush area. */
-static
-ulint
-buf_flush_try_neighbors(
-/*====================*/
- /* out: number of pages flushed */
- ulint space, /* in: space id */
- ulint offset, /* in: page offset */
- ulint flush_type) /* in: BUF_FLUSH_LRU or BUF_FLUSH_LIST */
-{
- buf_block_t* block;
- ulint low, high;
- ulint count = 0;
- ulint i;
-
- ut_ad(flush_type == BUF_FLUSH_LRU || flush_type == BUF_FLUSH_LIST);
-
- low = (offset / BUF_FLUSH_AREA) * BUF_FLUSH_AREA;
- high = (offset / BUF_FLUSH_AREA + 1) * BUF_FLUSH_AREA;
-
- if (UT_LIST_GET_LEN(buf_pool->LRU) < BUF_LRU_OLD_MIN_LEN) {
- /* If there is little space, it is better not to flush any
- block except from the end of the LRU list */
-
- low = offset;
- high = offset + 1;
- }
-
- /* fprintf(stderr, "Flush area: low %lu high %lu\n", low, high); */
-
- if (high > fil_space_get_size(space)) {
- high = fil_space_get_size(space);
- }
-
- mutex_enter(&(buf_pool->mutex));
-
- for (i = low; i < high; i++) {
-
- block = buf_page_hash_get(space, i);
- ut_a(!block || block->state == BUF_BLOCK_FILE_PAGE);
-
- if (!block) {
-
- continue;
-
- } else if (flush_type == BUF_FLUSH_LRU && i != offset
- && !block->old) {
-
- /* We avoid flushing 'non-old' blocks in an LRU flush,
- because the flushed blocks are soon freed */
-
- continue;
- } else {
-
- mutex_enter(&block->mutex);
-
- if (buf_flush_ready_for_flush(block, flush_type)
- && (i == offset || block->buf_fix_count == 0)) {
- /* We only try to flush those
- neighbors != offset where the buf fix count is
- zero, as we then know that we probably can
- latch the page without a semaphore wait.
- Semaphore waits are expensive because we must
- flush the doublewrite buffer before we start
- waiting. */
-
- mutex_exit(&block->mutex);
-
- mutex_exit(&(buf_pool->mutex));
-
- /* Note: as we release the buf_pool mutex
- above, in buf_flush_try_page we cannot be sure
- the page is still in a flushable state:
- therefore we check it again inside that
- function. */
-
- count += buf_flush_try_page(space, i,
- flush_type);
-
- mutex_enter(&(buf_pool->mutex));
- } else {
- mutex_exit(&block->mutex);
- }
- }
- }
-
- mutex_exit(&(buf_pool->mutex));
-
- return(count);
-}
-
-/***********************************************************************
-This utility flushes dirty blocks from the end of the LRU list or flush_list.
-NOTE 1: in the case of an LRU flush the calling thread may own latches to
-pages: to avoid deadlocks, this function must be written so that it cannot
-end up waiting for these latches! NOTE 2: in the case of a flush list flush,
-the calling thread is not allowed to own any latches on pages! */
-
-ulint
-buf_flush_batch(
-/*============*/
- /* out: number of blocks for which the write
- request was queued; ULINT_UNDEFINED if there
- was a flush of the same type already running */
- ulint flush_type, /* in: BUF_FLUSH_LRU or BUF_FLUSH_LIST; if
- BUF_FLUSH_LIST, then the caller must not own
- any latches on pages */
- ulint min_n, /* in: wished minimum mumber of blocks flushed
- (it is not guaranteed that the actual number
- is that big, though) */
- dulint lsn_limit) /* in the case BUF_FLUSH_LIST all blocks whose
- oldest_modification is smaller than this
- should be flushed (if their number does not
- exceed min_n), otherwise ignored */
-{
- buf_block_t* block;
- ulint page_count = 0;
- ulint old_page_count;
- ulint space;
- ulint offset;
- ibool found;
-
- ut_ad((flush_type == BUF_FLUSH_LRU)
- || (flush_type == BUF_FLUSH_LIST));
-#ifdef UNIV_SYNC_DEBUG
- ut_ad((flush_type != BUF_FLUSH_LIST)
- || sync_thread_levels_empty_gen(TRUE));
-#endif /* UNIV_SYNC_DEBUG */
- mutex_enter(&(buf_pool->mutex));
-
- if ((buf_pool->n_flush[flush_type] > 0)
- || (buf_pool->init_flush[flush_type] == TRUE)) {
-
- /* There is already a flush batch of the same type running */
-
- mutex_exit(&(buf_pool->mutex));
-
- return(ULINT_UNDEFINED);
- }
-
- (buf_pool->init_flush)[flush_type] = TRUE;
-
- for (;;) {
- /* If we have flushed enough, leave the loop */
- if (page_count >= min_n) {
-
- break;
- }
-
- /* Start from the end of the list looking for a suitable
- block to be flushed. */
-
- if (flush_type == BUF_FLUSH_LRU) {
- block = UT_LIST_GET_LAST(buf_pool->LRU);
- } else {
- ut_ad(flush_type == BUF_FLUSH_LIST);
-
- block = UT_LIST_GET_LAST(buf_pool->flush_list);
- if (!block
- || (ut_dulint_cmp(block->oldest_modification,
- lsn_limit) >= 0)) {
- /* We have flushed enough */
-
- break;
- }
- }
-
- found = FALSE;
-
- /* Note that after finding a single flushable page, we try to
- flush also all its neighbors, and after that start from the
- END of the LRU list or flush list again: the list may change
- during the flushing and we cannot safely preserve within this
- function a pointer to a block in the list! */
-
- while ((block != NULL) && !found) {
- ut_a(block->state == BUF_BLOCK_FILE_PAGE);
-
- mutex_enter(&block->mutex);
-
- if (buf_flush_ready_for_flush(block, flush_type)) {
-
- found = TRUE;
- space = block->space;
- offset = block->offset;
-
- mutex_exit(&block->mutex);
- mutex_exit(&(buf_pool->mutex));
-
- old_page_count = page_count;
-
- /* Try to flush also all the neighbors */
- page_count += buf_flush_try_neighbors(
- space, offset, flush_type);
- /* fprintf(stderr,
- "Flush type %lu, page no %lu, neighb %lu\n",
- flush_type, offset,
- page_count - old_page_count); */
-
- mutex_enter(&(buf_pool->mutex));
-
- } else if (flush_type == BUF_FLUSH_LRU) {
-
- mutex_exit(&block->mutex);
-
- block = UT_LIST_GET_PREV(LRU, block);
- } else {
- ut_ad(flush_type == BUF_FLUSH_LIST);
-
- mutex_exit(&block->mutex);
-
- block = UT_LIST_GET_PREV(flush_list, block);
- }
- }
-
- /* If we could not find anything to flush, leave the loop */
-
- if (!found) {
- break;
- }
- }
-
- (buf_pool->init_flush)[flush_type] = FALSE;
-
- if ((buf_pool->n_flush[flush_type] == 0)
- && (buf_pool->init_flush[flush_type] == FALSE)) {
-
- /* The running flush batch has ended */
-
- os_event_set(buf_pool->no_flush[flush_type]);
- }
-
- mutex_exit(&(buf_pool->mutex));
-
- buf_flush_buffered_writes();
-
-#ifdef UNIV_DEBUG
- if (buf_debug_prints && page_count > 0) {
- ut_a(flush_type == BUF_FLUSH_LRU
- || flush_type == BUF_FLUSH_LIST);
- fprintf(stderr, flush_type == BUF_FLUSH_LRU
- ? "Flushed %lu pages in LRU flush\n"
- : "Flushed %lu pages in flush list flush\n",
- (ulong) page_count);
- }
-#endif /* UNIV_DEBUG */
-
- srv_buf_pool_flushed += page_count;
-
- return(page_count);
-}
-
-/**********************************************************************
-Waits until a flush batch of the given type ends */
-
-void
-buf_flush_wait_batch_end(
-/*=====================*/
- ulint type) /* in: BUF_FLUSH_LRU or BUF_FLUSH_LIST */
-{
- ut_ad((type == BUF_FLUSH_LRU) || (type == BUF_FLUSH_LIST));
-
- os_event_wait(buf_pool->no_flush[type]);
-}
-
-/**********************************************************************
-Gives a recommendation of how many blocks should be flushed to establish
-a big enough margin of replaceable blocks near the end of the LRU list
-and in the free list. */
-static
-ulint
-buf_flush_LRU_recommendation(void)
-/*==============================*/
- /* out: number of blocks which should be flushed
- from the end of the LRU list */
-{
- buf_block_t* block;
- ulint n_replaceable;
- ulint distance = 0;
-
- mutex_enter(&(buf_pool->mutex));
-
- n_replaceable = UT_LIST_GET_LEN(buf_pool->free);
-
- block = UT_LIST_GET_LAST(buf_pool->LRU);
-
- while ((block != NULL)
- && (n_replaceable < BUF_FLUSH_FREE_BLOCK_MARGIN
- + BUF_FLUSH_EXTRA_MARGIN)
- && (distance < BUF_LRU_FREE_SEARCH_LEN)) {
-
- mutex_enter(&block->mutex);
-
- if (buf_flush_ready_for_replace(block)) {
- n_replaceable++;
- }
-
- mutex_exit(&block->mutex);
-
- distance++;
-
- block = UT_LIST_GET_PREV(LRU, block);
- }
-
- mutex_exit(&(buf_pool->mutex));
-
- if (n_replaceable >= BUF_FLUSH_FREE_BLOCK_MARGIN) {
-
- return(0);
- }
-
- return(BUF_FLUSH_FREE_BLOCK_MARGIN + BUF_FLUSH_EXTRA_MARGIN
- - n_replaceable);
-}
-
-/*************************************************************************
-Flushes pages from the end of the LRU list if there is too small a margin
-of replaceable pages there or in the free list. VERY IMPORTANT: this function
-is called also by threads which have locks on pages. To avoid deadlocks, we
-flush only pages such that the s-lock required for flushing can be acquired
-immediately, without waiting. */
-
-void
-buf_flush_free_margin(void)
-/*=======================*/
-{
- ulint n_to_flush;
- ulint n_flushed;
-
- n_to_flush = buf_flush_LRU_recommendation();
-
- if (n_to_flush > 0) {
- n_flushed = buf_flush_batch(BUF_FLUSH_LRU, n_to_flush,
- ut_dulint_zero);
- if (n_flushed == ULINT_UNDEFINED) {
- /* There was an LRU type flush batch already running;
- let us wait for it to end */
-
- buf_flush_wait_batch_end(BUF_FLUSH_LRU);
- }
- }
-}
-
-/**********************************************************************
-Validates the flush list. */
-static
-ibool
-buf_flush_validate_low(void)
-/*========================*/
- /* out: TRUE if ok */
-{
- buf_block_t* block;
- dulint om;
-
- UT_LIST_VALIDATE(flush_list, buf_block_t, buf_pool->flush_list);
-
- block = UT_LIST_GET_FIRST(buf_pool->flush_list);
-
- while (block != NULL) {
- om = block->oldest_modification;
- ut_a(block->state == BUF_BLOCK_FILE_PAGE);
- ut_a(ut_dulint_cmp(om, ut_dulint_zero) > 0);
-
- block = UT_LIST_GET_NEXT(flush_list, block);
-
- if (block) {
- ut_a(ut_dulint_cmp(om, block->oldest_modification)
- >= 0);
- }
- }
-
- return(TRUE);
-}
-
-/**********************************************************************
-Validates the flush list. */
-
-ibool
-buf_flush_validate(void)
-/*====================*/
- /* out: TRUE if ok */
-{
- ibool ret;
-
- mutex_enter(&(buf_pool->mutex));
-
- ret = buf_flush_validate_low();
-
- mutex_exit(&(buf_pool->mutex));
-
- return(ret);
-}
diff --git a/storage/innobase/buf/buf0lru.c b/storage/innobase/buf/buf0lru.c
deleted file mode 100644
index d3c787d1578..00000000000
--- a/storage/innobase/buf/buf0lru.c
+++ /dev/null
@@ -1,1237 +0,0 @@
-/******************************************************
-The database buffer replacement algorithm
-
-(c) 1995 Innobase Oy
-
-Created 11/5/1995 Heikki Tuuri
-*******************************************************/
-
-#include "buf0lru.h"
-
-#ifdef UNIV_NONINL
-#include "buf0lru.ic"
-#include "srv0srv.h" /* Needed to getsrv_print_innodb_monitor */
-#endif
-
-#include "ut0byte.h"
-#include "ut0lst.h"
-#include "ut0rnd.h"
-#include "sync0sync.h"
-#include "sync0rw.h"
-#include "hash0hash.h"
-#include "os0sync.h"
-#include "fil0fil.h"
-#include "btr0btr.h"
-#include "buf0buf.h"
-#include "buf0flu.h"
-#include "buf0rea.h"
-#include "btr0sea.h"
-#include "os0file.h"
-#include "log0recv.h"
-
-/* The number of blocks from the LRU_old pointer onward, including the block
-pointed to, must be 3/8 of the whole LRU list length, except that the
-tolerance defined below is allowed. Note that the tolerance must be small
-enough such that for even the BUF_LRU_OLD_MIN_LEN long LRU list, the
-LRU_old pointer is not allowed to point to either end of the LRU list. */
-
-#define BUF_LRU_OLD_TOLERANCE 20
-
-/* The whole LRU list length is divided by this number to determine an
-initial segment in buf_LRU_get_recent_limit */
-
-#define BUF_LRU_INITIAL_RATIO 8
-
-/* When dropping the search hash index entries before deleting an ibd
-file, we build a local array of pages belonging to that tablespace
-in the buffer pool. Following is the size of that array. */
-#define BUF_LRU_DROP_SEARCH_HASH_SIZE 1024
-
-/* If we switch on the InnoDB monitor because there are too few available
-frames in the buffer pool, we set this to TRUE */
-ibool buf_lru_switched_on_innodb_mon = FALSE;
-
-/**********************************************************************
-Takes a block out of the LRU list and page hash table and sets the block
-state to BUF_BLOCK_REMOVE_HASH. */
-static
-void
-buf_LRU_block_remove_hashed_page(
-/*=============================*/
- buf_block_t* block); /* in: block, must contain a file page and
- be in a state where it can be freed; there
- may or may not be a hash index to the page */
-/**********************************************************************
-Puts a file page whose has no hash index to the free list. */
-static
-void
-buf_LRU_block_free_hashed_page(
-/*===========================*/
- buf_block_t* block); /* in: block, must contain a file page and
- be in a state where it can be freed */
-
-/**********************************************************************
-Attempts to drop page hash index on a batch of pages belonging to a
-particular space id. */
-static
-void
-buf_LRU_drop_page_hash_batch(
-/*=========================*/
- ulint id, /* in: space id */
- const ulint* arr, /* in: array of page_no */
- ulint count) /* in: number of entries in array */
-{
- ulint i;
-
- ut_ad(arr != NULL);
- ut_ad(count <= BUF_LRU_DROP_SEARCH_HASH_SIZE);
-
- for (i = 0; i < count; ++i) {
- btr_search_drop_page_hash_when_freed(id, arr[i]);
- }
-}
-
-/**********************************************************************
-When doing a DROP TABLE/DISCARD TABLESPACE we have to drop all page
-hash index entries belonging to that table. This function tries to
-do that in batch. Note that this is a 'best effort' attempt and does
-not guarantee that ALL hash entries will be removed. */
-static
-void
-buf_LRU_drop_page_hash_for_tablespace(
-/*==================================*/
- ulint id) /* in: space id */
-{
- buf_block_t* block;
- ulint* page_arr;
- ulint num_entries;
-
- page_arr = ut_malloc(sizeof(ulint)
- * BUF_LRU_DROP_SEARCH_HASH_SIZE);
- mutex_enter(&buf_pool->mutex);
-
-scan_again:
- num_entries = 0;
- block = UT_LIST_GET_LAST(buf_pool->LRU);
-
- while (block != NULL) {
- buf_block_t* prev_block;
-
- mutex_enter(&block->mutex);
- prev_block = UT_LIST_GET_PREV(LRU, block);
-
- ut_a(block->state == BUF_BLOCK_FILE_PAGE);
-
- if (block->space != id
- || block->buf_fix_count > 0
- || block->io_fix != 0) {
- /* We leave the fixed pages as is in this scan.
- To be dealt with later in the final scan. */
- mutex_exit(&block->mutex);
- goto next_page;
- }
-
- ut_ad(block->space == id);
- if (block->is_hashed) {
-
- /* Store the offset(i.e.: page_no) in the array
- so that we can drop hash index in a batch
- later. */
- page_arr[num_entries] = block->offset;
- mutex_exit(&block->mutex);
- ut_a(num_entries < BUF_LRU_DROP_SEARCH_HASH_SIZE);
- ++num_entries;
-
- if (num_entries < BUF_LRU_DROP_SEARCH_HASH_SIZE) {
- goto next_page;
- }
- /* Array full. We release the buf_pool->mutex to
- obey the latching order. */
- mutex_exit(&buf_pool->mutex);
-
- buf_LRU_drop_page_hash_batch(id, page_arr,
- num_entries);
- num_entries = 0;
- mutex_enter(&buf_pool->mutex);
- } else {
- mutex_exit(&block->mutex);
- }
-
-next_page:
- /* Note that we may have released the buf_pool->mutex
- above after reading the prev_block during processing
- of a page_hash_batch (i.e.: when the array was full).
- This means that prev_block can change in LRU list.
- This is OK because this function is a 'best effort'
- to drop as many search hash entries as possible and
- it does not guarantee that ALL such entries will be
- dropped. */
- block = prev_block;
-
- /* If, however, block has been removed from LRU list
- to the free list then we should restart the scan.
- block->state is protected by buf_pool->mutex. */
- if (block && block->state != BUF_BLOCK_FILE_PAGE) {
- ut_a(num_entries == 0);
- goto scan_again;
- }
- }
-
- mutex_exit(&buf_pool->mutex);
-
- /* Drop any remaining batch of search hashed pages. */
- buf_LRU_drop_page_hash_batch(id, page_arr, num_entries);
- ut_free(page_arr);
-}
-
-/**********************************************************************
-Invalidates all pages belonging to a given tablespace when we are deleting
-the data file(s) of that tablespace. */
-
-void
-buf_LRU_invalidate_tablespace(
-/*==========================*/
- ulint id) /* in: space id */
-{
- buf_block_t* block;
- ulint page_no;
- ibool all_freed;
-
- /* Before we attempt to drop pages one by one we first
- attempt to drop page hash index entries in batches to make
- it more efficient. The batching attempt is a best effort
- attempt and does not guarantee that all pages hash entries
- will be dropped. We get rid of remaining page hash entries
- one by one below. */
- buf_LRU_drop_page_hash_for_tablespace(id);
-
-scan_again:
- mutex_enter(&(buf_pool->mutex));
-
- all_freed = TRUE;
-
- block = UT_LIST_GET_LAST(buf_pool->LRU);
-
- while (block != NULL) {
- buf_block_t* prev_block;
-
- mutex_enter(&block->mutex);
- prev_block = UT_LIST_GET_PREV(LRU, block);
-
- ut_a(block->state == BUF_BLOCK_FILE_PAGE);
-
- if (block->space == id
- && (block->buf_fix_count > 0 || block->io_fix != 0)) {
-
- /* We cannot remove this page during this scan yet;
- maybe the system is currently reading it in, or
- flushing the modifications to the file */
-
- all_freed = FALSE;
-
- goto next_page;
- }
-
- if (block->space == id) {
-#ifdef UNIV_DEBUG
- if (buf_debug_prints) {
- fprintf(stderr,
- "Dropping space %lu page %lu\n",
- (ulong) block->space,
- (ulong) block->offset);
- }
-#endif
- if (block->is_hashed) {
- page_no = block->offset;
-
- mutex_exit(&block->mutex);
-
- mutex_exit(&(buf_pool->mutex));
-
- /* Note that the following call will acquire
- an S-latch on the page */
-
- btr_search_drop_page_hash_when_freed(id,
- page_no);
- goto scan_again;
- }
-
- if (0 != ut_dulint_cmp(block->oldest_modification,
- ut_dulint_zero)) {
-
- /* Remove from the flush list of modified
- blocks */
- block->oldest_modification = ut_dulint_zero;
-
- UT_LIST_REMOVE(flush_list,
- buf_pool->flush_list, block);
- }
-
- /* Remove from the LRU list */
- buf_LRU_block_remove_hashed_page(block);
- buf_LRU_block_free_hashed_page(block);
- }
-next_page:
- mutex_exit(&block->mutex);
- block = prev_block;
- }
-
- mutex_exit(&(buf_pool->mutex));
-
- if (!all_freed) {
- os_thread_sleep(20000);
-
- goto scan_again;
- }
-}
-
-/**********************************************************************
-Gets the minimum LRU_position field for the blocks in an initial segment
-(determined by BUF_LRU_INITIAL_RATIO) of the LRU list. The limit is not
-guaranteed to be precise, because the ulint_clock may wrap around. */
-
-ulint
-buf_LRU_get_recent_limit(void)
-/*==========================*/
- /* out: the limit; zero if could not determine it */
-{
- buf_block_t* block;
- ulint len;
- ulint limit;
-
- mutex_enter(&(buf_pool->mutex));
-
- len = UT_LIST_GET_LEN(buf_pool->LRU);
-
- if (len < BUF_LRU_OLD_MIN_LEN) {
- /* The LRU list is too short to do read-ahead */
-
- mutex_exit(&(buf_pool->mutex));
-
- return(0);
- }
-
- block = UT_LIST_GET_FIRST(buf_pool->LRU);
-
- limit = block->LRU_position - len / BUF_LRU_INITIAL_RATIO;
-
- mutex_exit(&(buf_pool->mutex));
-
- return(limit);
-}
-
-/**********************************************************************
-Look for a replaceable block from the end of the LRU list and put it to
-the free list if found. */
-
-ibool
-buf_LRU_search_and_free_block(
-/*==========================*/
- /* out: TRUE if freed */
- ulint n_iterations) /* in: how many times this has been called
- repeatedly without result: a high value means
- that we should search farther; if value is
- k < 10, then we only search k/10 * [number
- of pages in the buffer pool] from the end
- of the LRU list */
-{
- buf_block_t* block;
- ulint distance = 0;
- ibool freed;
-
- mutex_enter(&(buf_pool->mutex));
-
- freed = FALSE;
- block = UT_LIST_GET_LAST(buf_pool->LRU);
-
- while (block != NULL) {
- ut_a(block->in_LRU_list);
-
- mutex_enter(&block->mutex);
-
- if (buf_flush_ready_for_replace(block)) {
-
-#ifdef UNIV_DEBUG
- if (buf_debug_prints) {
- fprintf(stderr,
- "Putting space %lu page %lu"
- " to free list\n",
- (ulong) block->space,
- (ulong) block->offset);
- }
-#endif /* UNIV_DEBUG */
-
- buf_LRU_block_remove_hashed_page(block);
-
- mutex_exit(&(buf_pool->mutex));
- mutex_exit(&block->mutex);
-
- /* Remove possible adaptive hash index built on the
- page; in the case of AWE the block may not have a
- frame at all */
-
- if (block->frame) {
- /* The page was declared uninitialized
- by buf_LRU_block_remove_hashed_page().
- We need to flag the contents of the
- page valid (which it still is) in
- order to avoid bogus Valgrind
- warnings. */
- UNIV_MEM_VALID(block->frame, UNIV_PAGE_SIZE);
- btr_search_drop_page_hash_index(block->frame);
- UNIV_MEM_INVALID(block->frame, UNIV_PAGE_SIZE);
- }
-
- ut_a(block->buf_fix_count == 0);
-
- mutex_enter(&(buf_pool->mutex));
- mutex_enter(&block->mutex);
-
- buf_LRU_block_free_hashed_page(block);
- freed = TRUE;
- mutex_exit(&block->mutex);
-
- break;
- }
-
- mutex_exit(&block->mutex);
-
- block = UT_LIST_GET_PREV(LRU, block);
- distance++;
-
- if (!freed && n_iterations <= 10
- && distance > 100 + (n_iterations * buf_pool->curr_size)
- / 10) {
- buf_pool->LRU_flush_ended = 0;
-
- mutex_exit(&(buf_pool->mutex));
-
- return(FALSE);
- }
- }
- if (buf_pool->LRU_flush_ended > 0) {
- buf_pool->LRU_flush_ended--;
- }
- if (!freed) {
- buf_pool->LRU_flush_ended = 0;
- }
- mutex_exit(&(buf_pool->mutex));
-
- return(freed);
-}
-
-/**********************************************************************
-Tries to remove LRU flushed blocks from the end of the LRU list and put them
-to the free list. This is beneficial for the efficiency of the insert buffer
-operation, as flushed pages from non-unique non-clustered indexes are here
-taken out of the buffer pool, and their inserts redirected to the insert
-buffer. Otherwise, the flushed blocks could get modified again before read
-operations need new buffer blocks, and the i/o work done in flushing would be
-wasted. */
-
-void
-buf_LRU_try_free_flushed_blocks(void)
-/*=================================*/
-{
- mutex_enter(&(buf_pool->mutex));
-
- while (buf_pool->LRU_flush_ended > 0) {
-
- mutex_exit(&(buf_pool->mutex));
-
- buf_LRU_search_and_free_block(1);
-
- mutex_enter(&(buf_pool->mutex));
- }
-
- mutex_exit(&(buf_pool->mutex));
-}
-
-/**********************************************************************
-Returns TRUE if less than 25 % of the buffer pool is available. This can be
-used in heuristics to prevent huge transactions eating up the whole buffer
-pool for their locks. */
-
-ibool
-buf_LRU_buf_pool_running_out(void)
-/*==============================*/
- /* out: TRUE if less than 25 % of buffer pool
- left */
-{
- ibool ret = FALSE;
-
- mutex_enter(&(buf_pool->mutex));
-
- if (!recv_recovery_on && UT_LIST_GET_LEN(buf_pool->free)
- + UT_LIST_GET_LEN(buf_pool->LRU) < buf_pool->max_size / 4) {
-
- ret = TRUE;
- }
-
- mutex_exit(&(buf_pool->mutex));
-
- return(ret);
-}
-
-/**********************************************************************
-Returns a free block from buf_pool. The block is taken off the free list.
-If it is empty, blocks are moved from the end of the LRU list to the free
-list. */
-
-buf_block_t*
-buf_LRU_get_free_block(void)
-/*========================*/
- /* out: the free control block; also if AWE is
- used, it is guaranteed that the block has its
- page mapped to a frame when we return */
-{
- buf_block_t* block = NULL;
- ibool freed;
- ulint n_iterations = 1;
- ibool mon_value_was = FALSE;
- ibool started_monitor = FALSE;
-loop:
- mutex_enter(&(buf_pool->mutex));
-
- if (!recv_recovery_on && UT_LIST_GET_LEN(buf_pool->free)
- + UT_LIST_GET_LEN(buf_pool->LRU) < buf_pool->max_size / 20) {
- ut_print_timestamp(stderr);
-
- fprintf(stderr,
- " InnoDB: ERROR: over 95 percent of the buffer pool"
- " is occupied by\n"
- "InnoDB: lock heaps or the adaptive hash index!"
- " Check that your\n"
- "InnoDB: transactions do not set too many row locks.\n"
- "InnoDB: Your buffer pool size is %lu MB."
- " Maybe you should make\n"
- "InnoDB: the buffer pool bigger?\n"
- "InnoDB: We intentionally generate a seg fault"
- " to print a stack trace\n"
- "InnoDB: on Linux!\n",
- (ulong) (buf_pool->curr_size
- / (1024 * 1024 / UNIV_PAGE_SIZE)));
-
- ut_error;
-
- } else if (!recv_recovery_on && UT_LIST_GET_LEN(buf_pool->free)
- + UT_LIST_GET_LEN(buf_pool->LRU) < buf_pool->max_size / 3) {
-
- if (!buf_lru_switched_on_innodb_mon) {
-
- /* Over 67 % of the buffer pool is occupied by lock
- heaps or the adaptive hash index. This may be a memory
- leak! */
-
- ut_print_timestamp(stderr);
- fprintf(stderr,
- " InnoDB: WARNING: over 67 percent of"
- " the buffer pool is occupied by\n"
- "InnoDB: lock heaps or the adaptive"
- " hash index! Check that your\n"
- "InnoDB: transactions do not set too many"
- " row locks.\n"
- "InnoDB: Your buffer pool size is %lu MB."
- " Maybe you should make\n"
- "InnoDB: the buffer pool bigger?\n"
- "InnoDB: Starting the InnoDB Monitor to print"
- " diagnostics, including\n"
- "InnoDB: lock heap and hash index sizes.\n",
- (ulong) (buf_pool->curr_size
- / (1024 * 1024 / UNIV_PAGE_SIZE)));
-
- buf_lru_switched_on_innodb_mon = TRUE;
- srv_print_innodb_monitor = TRUE;
- os_event_set(srv_lock_timeout_thread_event);
- }
- } else if (buf_lru_switched_on_innodb_mon) {
-
- /* Switch off the InnoDB Monitor; this is a simple way
- to stop the monitor if the situation becomes less urgent,
- but may also surprise users if the user also switched on the
- monitor! */
-
- buf_lru_switched_on_innodb_mon = FALSE;
- srv_print_innodb_monitor = FALSE;
- }
-
- /* If there is a block in the free list, take it */
- if (UT_LIST_GET_LEN(buf_pool->free) > 0) {
-
- block = UT_LIST_GET_FIRST(buf_pool->free);
- ut_a(block->in_free_list);
- UT_LIST_REMOVE(free, buf_pool->free, block);
- block->in_free_list = FALSE;
- ut_a(block->state != BUF_BLOCK_FILE_PAGE);
- ut_a(!block->in_LRU_list);
-
- if (srv_use_awe) {
- if (block->frame) {
- /* Remove from the list of mapped pages */
-
- UT_LIST_REMOVE(awe_LRU_free_mapped,
- buf_pool->awe_LRU_free_mapped,
- block);
- } else {
- /* We map the page to a frame; second param
- FALSE below because we do not want it to be
- added to the awe_LRU_free_mapped list */
-
- buf_awe_map_page_to_frame(block, FALSE);
- }
- }
-
- mutex_enter(&block->mutex);
-
- block->state = BUF_BLOCK_READY_FOR_USE;
- UNIV_MEM_ALLOC(block->frame, UNIV_PAGE_SIZE);
-
- mutex_exit(&block->mutex);
-
- mutex_exit(&(buf_pool->mutex));
-
- if (started_monitor) {
- srv_print_innodb_monitor = mon_value_was;
- }
-
- return(block);
- }
-
- /* If no block was in the free list, search from the end of the LRU
- list and try to free a block there */
-
- mutex_exit(&(buf_pool->mutex));
-
- freed = buf_LRU_search_and_free_block(n_iterations);
-
- if (freed > 0) {
- goto loop;
- }
-
- if (n_iterations > 30) {
- ut_print_timestamp(stderr);
- fprintf(stderr,
- "InnoDB: Warning: difficult to find free blocks from\n"
- "InnoDB: the buffer pool (%lu search iterations)!"
- " Consider\n"
- "InnoDB: increasing the buffer pool size.\n"
- "InnoDB: It is also possible that"
- " in your Unix version\n"
- "InnoDB: fsync is very slow, or"
- " completely frozen inside\n"
- "InnoDB: the OS kernel. Then upgrading to"
- " a newer version\n"
- "InnoDB: of your operating system may help."
- " Look at the\n"
- "InnoDB: number of fsyncs in diagnostic info below.\n"
- "InnoDB: Pending flushes (fsync) log: %lu;"
- " buffer pool: %lu\n"
- "InnoDB: %lu OS file reads, %lu OS file writes,"
- " %lu OS fsyncs\n"
- "InnoDB: Starting InnoDB Monitor to print further\n"
- "InnoDB: diagnostics to the standard output.\n",
- (ulong) n_iterations,
- (ulong) fil_n_pending_log_flushes,
- (ulong) fil_n_pending_tablespace_flushes,
- (ulong) os_n_file_reads, (ulong) os_n_file_writes,
- (ulong) os_n_fsyncs);
-
- mon_value_was = srv_print_innodb_monitor;
- started_monitor = TRUE;
- srv_print_innodb_monitor = TRUE;
- os_event_set(srv_lock_timeout_thread_event);
- }
-
- /* No free block was found: try to flush the LRU list */
-
- buf_flush_free_margin();
- ++srv_buf_pool_wait_free;
-
- os_aio_simulated_wake_handler_threads();
-
- mutex_enter(&(buf_pool->mutex));
-
- if (buf_pool->LRU_flush_ended > 0) {
- /* We have written pages in an LRU flush. To make the insert
- buffer more efficient, we try to move these pages to the free
- list. */
-
- mutex_exit(&(buf_pool->mutex));
-
- buf_LRU_try_free_flushed_blocks();
- } else {
- mutex_exit(&(buf_pool->mutex));
- }
-
- if (n_iterations > 10) {
-
- os_thread_sleep(500000);
- }
-
- n_iterations++;
-
- goto loop;
-}
-
-/***********************************************************************
-Moves the LRU_old pointer so that the length of the old blocks list
-is inside the allowed limits. */
-UNIV_INLINE
-void
-buf_LRU_old_adjust_len(void)
-/*========================*/
-{
- ulint old_len;
- ulint new_len;
-
- ut_a(buf_pool->LRU_old);
- ut_ad(mutex_own(&(buf_pool->mutex)));
- ut_ad(3 * (BUF_LRU_OLD_MIN_LEN / 8) > BUF_LRU_OLD_TOLERANCE + 5);
-
- for (;;) {
- old_len = buf_pool->LRU_old_len;
- new_len = 3 * (UT_LIST_GET_LEN(buf_pool->LRU) / 8);
-
- ut_a(buf_pool->LRU_old->in_LRU_list);
-
- /* Update the LRU_old pointer if necessary */
-
- if (old_len < new_len - BUF_LRU_OLD_TOLERANCE) {
-
- buf_pool->LRU_old = UT_LIST_GET_PREV(
- LRU, buf_pool->LRU_old);
- (buf_pool->LRU_old)->old = TRUE;
- buf_pool->LRU_old_len++;
-
- } else if (old_len > new_len + BUF_LRU_OLD_TOLERANCE) {
-
- (buf_pool->LRU_old)->old = FALSE;
- buf_pool->LRU_old = UT_LIST_GET_NEXT(
- LRU, buf_pool->LRU_old);
- buf_pool->LRU_old_len--;
- } else {
- ut_a(buf_pool->LRU_old); /* Check that we did not
- fall out of the LRU list */
- return;
- }
- }
-}
-
-/***********************************************************************
-Initializes the old blocks pointer in the LRU list. This function should be
-called when the LRU list grows to BUF_LRU_OLD_MIN_LEN length. */
-static
-void
-buf_LRU_old_init(void)
-/*==================*/
-{
- buf_block_t* block;
-
- ut_ad(mutex_own(&(buf_pool->mutex)));
- ut_a(UT_LIST_GET_LEN(buf_pool->LRU) == BUF_LRU_OLD_MIN_LEN);
-
- /* We first initialize all blocks in the LRU list as old and then use
- the adjust function to move the LRU_old pointer to the right
- position */
-
- block = UT_LIST_GET_FIRST(buf_pool->LRU);
-
- while (block != NULL) {
- ut_a(block->state == BUF_BLOCK_FILE_PAGE);
- ut_a(block->in_LRU_list);
- block->old = TRUE;
- block = UT_LIST_GET_NEXT(LRU, block);
- }
-
- buf_pool->LRU_old = UT_LIST_GET_FIRST(buf_pool->LRU);
- buf_pool->LRU_old_len = UT_LIST_GET_LEN(buf_pool->LRU);
-
- buf_LRU_old_adjust_len();
-}
-
-/**********************************************************************
-Removes a block from the LRU list. */
-UNIV_INLINE
-void
-buf_LRU_remove_block(
-/*=================*/
- buf_block_t* block) /* in: control block */
-{
- ut_ad(buf_pool);
- ut_ad(block);
- ut_ad(mutex_own(&(buf_pool->mutex)));
-
- ut_a(block->state == BUF_BLOCK_FILE_PAGE);
- ut_a(block->in_LRU_list);
-
- /* If the LRU_old pointer is defined and points to just this block,
- move it backward one step */
-
- if (block == buf_pool->LRU_old) {
-
- /* Below: the previous block is guaranteed to exist, because
- the LRU_old pointer is only allowed to differ by the
- tolerance value from strict 3/8 of the LRU list length. */
-
- buf_pool->LRU_old = UT_LIST_GET_PREV(LRU, block);
- (buf_pool->LRU_old)->old = TRUE;
-
- buf_pool->LRU_old_len++;
- ut_a(buf_pool->LRU_old);
- }
-
- /* Remove the block from the LRU list */
- UT_LIST_REMOVE(LRU, buf_pool->LRU, block);
- block->in_LRU_list = FALSE;
-
- if (srv_use_awe && block->frame) {
- /* Remove from the list of mapped pages */
-
- UT_LIST_REMOVE(awe_LRU_free_mapped,
- buf_pool->awe_LRU_free_mapped, block);
- }
-
- /* If the LRU list is so short that LRU_old not defined, return */
- if (UT_LIST_GET_LEN(buf_pool->LRU) < BUF_LRU_OLD_MIN_LEN) {
-
- buf_pool->LRU_old = NULL;
-
- return;
- }
-
- ut_ad(buf_pool->LRU_old);
-
- /* Update the LRU_old_len field if necessary */
- if (block->old) {
-
- buf_pool->LRU_old_len--;
- }
-
- /* Adjust the length of the old block list if necessary */
- buf_LRU_old_adjust_len();
-}
-
-/**********************************************************************
-Adds a block to the LRU list end. */
-UNIV_INLINE
-void
-buf_LRU_add_block_to_end_low(
-/*=========================*/
- buf_block_t* block) /* in: control block */
-{
- buf_block_t* last_block;
-
- ut_ad(buf_pool);
- ut_ad(block);
- ut_ad(mutex_own(&(buf_pool->mutex)));
-
- ut_a(block->state == BUF_BLOCK_FILE_PAGE);
-
- block->old = TRUE;
-
- last_block = UT_LIST_GET_LAST(buf_pool->LRU);
-
- if (last_block) {
- block->LRU_position = last_block->LRU_position;
- } else {
- block->LRU_position = buf_pool_clock_tic();
- }
-
- ut_a(!block->in_LRU_list);
- UT_LIST_ADD_LAST(LRU, buf_pool->LRU, block);
- block->in_LRU_list = TRUE;
-
- if (srv_use_awe && block->frame) {
- /* Add to the list of mapped pages */
-
- UT_LIST_ADD_LAST(awe_LRU_free_mapped,
- buf_pool->awe_LRU_free_mapped, block);
- }
-
- if (UT_LIST_GET_LEN(buf_pool->LRU) >= BUF_LRU_OLD_MIN_LEN) {
-
- buf_pool->LRU_old_len++;
- }
-
- if (UT_LIST_GET_LEN(buf_pool->LRU) > BUF_LRU_OLD_MIN_LEN) {
-
- ut_ad(buf_pool->LRU_old);
-
- /* Adjust the length of the old block list if necessary */
-
- buf_LRU_old_adjust_len();
-
- } else if (UT_LIST_GET_LEN(buf_pool->LRU) == BUF_LRU_OLD_MIN_LEN) {
-
- /* The LRU list is now long enough for LRU_old to become
- defined: init it */
-
- buf_LRU_old_init();
- }
-}
-
-/**********************************************************************
-Adds a block to the LRU list. */
-UNIV_INLINE
-void
-buf_LRU_add_block_low(
-/*==================*/
- buf_block_t* block, /* in: control block */
- ibool old) /* in: TRUE if should be put to the old blocks
- in the LRU list, else put to the start; if the
- LRU list is very short, the block is added to
- the start, regardless of this parameter */
-{
- ulint cl;
-
- ut_ad(buf_pool);
- ut_ad(block);
- ut_ad(mutex_own(&(buf_pool->mutex)));
-
- ut_a(block->state == BUF_BLOCK_FILE_PAGE);
- ut_a(!block->in_LRU_list);
-
- block->old = old;
- cl = buf_pool_clock_tic();
-
- if (srv_use_awe && block->frame) {
- /* Add to the list of mapped pages; for simplicity we always
- add to the start, even if the user would have set 'old'
- TRUE */
-
- UT_LIST_ADD_FIRST(awe_LRU_free_mapped,
- buf_pool->awe_LRU_free_mapped, block);
- }
-
- if (!old || (UT_LIST_GET_LEN(buf_pool->LRU) < BUF_LRU_OLD_MIN_LEN)) {
-
- UT_LIST_ADD_FIRST(LRU, buf_pool->LRU, block);
-
- block->LRU_position = cl;
- block->freed_page_clock = buf_pool->freed_page_clock;
- } else {
- UT_LIST_INSERT_AFTER(LRU, buf_pool->LRU, buf_pool->LRU_old,
- block);
- buf_pool->LRU_old_len++;
-
- /* We copy the LRU position field of the previous block
- to the new block */
-
- block->LRU_position = (buf_pool->LRU_old)->LRU_position;
- }
-
- block->in_LRU_list = TRUE;
-
- if (UT_LIST_GET_LEN(buf_pool->LRU) > BUF_LRU_OLD_MIN_LEN) {
-
- ut_ad(buf_pool->LRU_old);
-
- /* Adjust the length of the old block list if necessary */
-
- buf_LRU_old_adjust_len();
-
- } else if (UT_LIST_GET_LEN(buf_pool->LRU) == BUF_LRU_OLD_MIN_LEN) {
-
- /* The LRU list is now long enough for LRU_old to become
- defined: init it */
-
- buf_LRU_old_init();
- }
-}
-
-/**********************************************************************
-Adds a block to the LRU list. */
-
-void
-buf_LRU_add_block(
-/*==============*/
- buf_block_t* block, /* in: control block */
- ibool old) /* in: TRUE if should be put to the old
- blocks in the LRU list, else put to the start;
- if the LRU list is very short, the block is
- added to the start, regardless of this
- parameter */
-{
- buf_LRU_add_block_low(block, old);
-}
-
-/**********************************************************************
-Moves a block to the start of the LRU list. */
-
-void
-buf_LRU_make_block_young(
-/*=====================*/
- buf_block_t* block) /* in: control block */
-{
- buf_LRU_remove_block(block);
- buf_LRU_add_block_low(block, FALSE);
-}
-
-/**********************************************************************
-Moves a block to the end of the LRU list. */
-
-void
-buf_LRU_make_block_old(
-/*===================*/
- buf_block_t* block) /* in: control block */
-{
- buf_LRU_remove_block(block);
- buf_LRU_add_block_to_end_low(block);
-}
-
-/**********************************************************************
-Puts a block back to the free list. */
-
-void
-buf_LRU_block_free_non_file_page(
-/*=============================*/
- buf_block_t* block) /* in: block, must not contain a file page */
-{
-
- ut_ad(mutex_own(&(buf_pool->mutex)));
- ut_ad(mutex_own(&block->mutex));
- ut_ad(block);
-
- ut_a((block->state == BUF_BLOCK_MEMORY)
- || (block->state == BUF_BLOCK_READY_FOR_USE));
-
- ut_a(block->n_pointers == 0);
- ut_a(!block->in_free_list);
-
- block->state = BUF_BLOCK_NOT_USED;
-
- UNIV_MEM_ALLOC(block->frame, UNIV_PAGE_SIZE);
-#ifdef UNIV_DEBUG
- /* Wipe contents of page to reveal possible stale pointers to it */
- memset(block->frame, '\0', UNIV_PAGE_SIZE);
-#endif
- UT_LIST_ADD_FIRST(free, buf_pool->free, block);
- block->in_free_list = TRUE;
-
- UNIV_MEM_ASSERT_AND_FREE(block->frame, UNIV_PAGE_SIZE);
-
- if (srv_use_awe && block->frame) {
- /* Add to the list of mapped pages */
-
- UT_LIST_ADD_FIRST(awe_LRU_free_mapped,
- buf_pool->awe_LRU_free_mapped, block);
- }
-}
-
-/**********************************************************************
-Takes a block out of the LRU list and page hash table and sets the block
-state to BUF_BLOCK_REMOVE_HASH. */
-static
-void
-buf_LRU_block_remove_hashed_page(
-/*=============================*/
- buf_block_t* block) /* in: block, must contain a file page and
- be in a state where it can be freed; there
- may or may not be a hash index to the page */
-{
- ut_ad(mutex_own(&(buf_pool->mutex)));
- ut_ad(mutex_own(&block->mutex));
- ut_ad(block);
-
- ut_a(block->state == BUF_BLOCK_FILE_PAGE);
- ut_a(block->io_fix == 0);
- ut_a(block->buf_fix_count == 0);
- ut_a(ut_dulint_cmp(block->oldest_modification, ut_dulint_zero) == 0);
-
- buf_LRU_remove_block(block);
-
- buf_pool->freed_page_clock += 1;
-
- /* Note that if AWE is enabled the block may not have a frame at all */
-
- buf_block_modify_clock_inc(block);
-
- if (block != buf_page_hash_get(block->space, block->offset)) {
- fprintf(stderr,
- "InnoDB: Error: page %lu %lu not found"
- " in the hash table\n",
- (ulong) block->space,
- (ulong) block->offset);
- if (buf_page_hash_get(block->space, block->offset)) {
- fprintf(stderr,
- "InnoDB: In hash table we find block"
- " %p of %lu %lu which is not %p\n",
- (void*) buf_page_hash_get
- (block->space, block->offset),
- (ulong) buf_page_hash_get
- (block->space, block->offset)->space,
- (ulong) buf_page_hash_get
- (block->space, block->offset)->offset,
- (void*) block);
- }
-
-#ifdef UNIV_DEBUG
- buf_print();
- buf_LRU_print();
- buf_validate();
- buf_LRU_validate();
-#endif
- ut_a(0);
- }
-
- HASH_DELETE(buf_block_t, hash, buf_pool->page_hash,
- buf_page_address_fold(block->space, block->offset),
- block);
-
- UNIV_MEM_INVALID(block->frame, UNIV_PAGE_SIZE);
- block->state = BUF_BLOCK_REMOVE_HASH;
-}
-
-/**********************************************************************
-Puts a file page whose has no hash index to the free list. */
-static
-void
-buf_LRU_block_free_hashed_page(
-/*===========================*/
- buf_block_t* block) /* in: block, must contain a file page and
- be in a state where it can be freed */
-{
- ut_ad(mutex_own(&(buf_pool->mutex)));
- ut_ad(mutex_own(&block->mutex));
-
- ut_a(block->state == BUF_BLOCK_REMOVE_HASH);
-
- block->state = BUF_BLOCK_MEMORY;
-
- buf_LRU_block_free_non_file_page(block);
-}
-
-#ifdef UNIV_DEBUG
-/**************************************************************************
-Validates the LRU list. */
-
-ibool
-buf_LRU_validate(void)
-/*==================*/
-{
- buf_block_t* block;
- ulint old_len;
- ulint new_len;
- ulint LRU_pos;
-
- ut_ad(buf_pool);
- mutex_enter(&(buf_pool->mutex));
-
- if (UT_LIST_GET_LEN(buf_pool->LRU) >= BUF_LRU_OLD_MIN_LEN) {
-
- ut_a(buf_pool->LRU_old);
- old_len = buf_pool->LRU_old_len;
- new_len = 3 * (UT_LIST_GET_LEN(buf_pool->LRU) / 8);
- ut_a(old_len >= new_len - BUF_LRU_OLD_TOLERANCE);
- ut_a(old_len <= new_len + BUF_LRU_OLD_TOLERANCE);
- }
-
- UT_LIST_VALIDATE(LRU, buf_block_t, buf_pool->LRU);
-
- block = UT_LIST_GET_FIRST(buf_pool->LRU);
-
- old_len = 0;
-
- while (block != NULL) {
-
- ut_a(block->state == BUF_BLOCK_FILE_PAGE);
-
- if (block->old) {
- old_len++;
- }
-
- if (buf_pool->LRU_old && (old_len == 1)) {
- ut_a(buf_pool->LRU_old == block);
- }
-
- LRU_pos = block->LRU_position;
-
- block = UT_LIST_GET_NEXT(LRU, block);
-
- if (block) {
- /* If the following assert fails, it may
- not be an error: just the buf_pool clock
- has wrapped around */
- ut_a(LRU_pos >= block->LRU_position);
- }
- }
-
- if (buf_pool->LRU_old) {
- ut_a(buf_pool->LRU_old_len == old_len);
- }
-
- UT_LIST_VALIDATE(free, buf_block_t, buf_pool->free);
-
- block = UT_LIST_GET_FIRST(buf_pool->free);
-
- while (block != NULL) {
- ut_a(block->state == BUF_BLOCK_NOT_USED);
-
- block = UT_LIST_GET_NEXT(free, block);
- }
-
- mutex_exit(&(buf_pool->mutex));
- return(TRUE);
-}
-
-/**************************************************************************
-Prints the LRU list. */
-
-void
-buf_LRU_print(void)
-/*===============*/
-{
- buf_block_t* block;
- buf_frame_t* frame;
- ulint len;
-
- ut_ad(buf_pool);
- mutex_enter(&(buf_pool->mutex));
-
- fprintf(stderr, "Pool ulint clock %lu\n",
- (ulong) buf_pool->ulint_clock);
-
- block = UT_LIST_GET_FIRST(buf_pool->LRU);
-
- len = 0;
-
- while (block != NULL) {
-
- fprintf(stderr, "BLOCK %lu ", (ulong) block->offset);
-
- if (block->old) {
- fputs("old ", stderr);
- }
-
- if (block->buf_fix_count) {
- fprintf(stderr, "buffix count %lu ",
- (ulong) block->buf_fix_count);
- }
-
- if (block->io_fix) {
- fprintf(stderr, "io_fix %lu ", (ulong) block->io_fix);
- }
-
- if (ut_dulint_cmp(block->oldest_modification,
- ut_dulint_zero) > 0) {
- fputs("modif. ", stderr);
- }
-
- frame = buf_block_get_frame(block);
-
- fprintf(stderr, "LRU pos %lu type %lu index id %lu ",
- (ulong) block->LRU_position,
- (ulong) fil_page_get_type(frame),
- (ulong) ut_dulint_get_low
- (btr_page_get_index_id(frame)));
-
- block = UT_LIST_GET_NEXT(LRU, block);
- if (++len == 10) {
- len = 0;
- putc('\n', stderr);
- }
- }
-
- mutex_exit(&(buf_pool->mutex));
-}
-#endif /* UNIV_DEBUG */
diff --git a/storage/innobase/data/data0data.c b/storage/innobase/data/data0data.c
deleted file mode 100644
index 0f03de4ca9d..00000000000
--- a/storage/innobase/data/data0data.c
+++ /dev/null
@@ -1,681 +0,0 @@
-/************************************************************************
-SQL data field and tuple
-
-(c) 1994-1996 Innobase Oy
-
-Created 5/30/1994 Heikki Tuuri
-*************************************************************************/
-
-#include "data0data.h"
-
-#ifdef UNIV_NONINL
-#include "data0data.ic"
-#endif
-
-#include "rem0rec.h"
-#include "rem0cmp.h"
-#include "page0page.h"
-#include "dict0dict.h"
-#include "btr0cur.h"
-
-#include
-
-#ifdef UNIV_DEBUG
-byte data_error; /* data pointers of tuple fields are initialized
- to point here for error checking */
-
-ulint data_dummy; /* this is used to fool the compiler in
- dtuple_validate */
-#endif /* UNIV_DEBUG */
-
-/* Some non-inlined functions used in the MySQL interface: */
-void
-dfield_set_data_noninline(
- dfield_t* field, /* in: field */
- void* data, /* in: data */
- ulint len) /* in: length or UNIV_SQL_NULL */
-{
- dfield_set_data(field, data, len);
-}
-void*
-dfield_get_data_noninline(
- dfield_t* field) /* in: field */
-{
- return(dfield_get_data(field));
-}
-ulint
-dfield_get_len_noninline(
- dfield_t* field) /* in: field */
-{
- return(dfield_get_len(field));
-}
-ulint
-dtuple_get_n_fields_noninline(
- dtuple_t* tuple) /* in: tuple */
-{
- return(dtuple_get_n_fields(tuple));
-}
-dfield_t*
-dtuple_get_nth_field_noninline(
- dtuple_t* tuple, /* in: tuple */
- ulint n) /* in: index of field */
-{
- return(dtuple_get_nth_field(tuple, n));
-}
-
-/*************************************************************************
-Tests if dfield data length and content is equal to the given. */
-
-ibool
-dfield_data_is_binary_equal(
-/*========================*/
- /* out: TRUE if equal */
- dfield_t* field, /* in: field */
- ulint len, /* in: data length or UNIV_SQL_NULL */
- byte* data) /* in: data */
-{
- if (len != field->len) {
-
- return(FALSE);
- }
-
- if (len == UNIV_SQL_NULL) {
-
- return(TRUE);
- }
-
- if (0 != ut_memcmp(field->data, data, len)) {
-
- return(FALSE);
- }
-
- return(TRUE);
-}
-
-/****************************************************************
-Returns TRUE if lengths of two dtuples are equal and respective data fields
-in them are equal when compared with collation in char fields (not as binary
-strings). */
-
-ibool
-dtuple_datas_are_ordering_equal(
-/*============================*/
- /* out: TRUE if length and fieds are equal
- when compared with cmp_data_data:
- NOTE: in character type fields some letters
- are identified with others! (collation) */
- dtuple_t* tuple1, /* in: tuple 1 */
- dtuple_t* tuple2) /* in: tuple 2 */
-{
- dfield_t* field1;
- dfield_t* field2;
- ulint n_fields;
- ulint i;
-
- ut_ad(tuple1 && tuple2);
- ut_ad(tuple1->magic_n == DATA_TUPLE_MAGIC_N);
- ut_ad(tuple2->magic_n == DATA_TUPLE_MAGIC_N);
- ut_ad(dtuple_check_typed(tuple1));
- ut_ad(dtuple_check_typed(tuple2));
-
- n_fields = dtuple_get_n_fields(tuple1);
-
- if (n_fields != dtuple_get_n_fields(tuple2)) {
-
- return(FALSE);
- }
-
- for (i = 0; i < n_fields; i++) {
-
- field1 = dtuple_get_nth_field(tuple1, i);
- field2 = dtuple_get_nth_field(tuple2, i);
-
- if (0 != cmp_dfield_dfield(field1, field2)) {
-
- return(FALSE);
- }
- }
-
- return(TRUE);
-}
-
-/*************************************************************************
-Creates a dtuple for use in MySQL. */
-
-dtuple_t*
-dtuple_create_for_mysql(
-/*====================*/
- /* out, own created dtuple */
- void** heap, /* out: created memory heap */
- ulint n_fields) /* in: number of fields */
-{
- *heap = (void*)mem_heap_create(500);
-
- return(dtuple_create(*((mem_heap_t**)heap), n_fields));
-}
-
-/*************************************************************************
-Frees a dtuple used in MySQL. */
-
-void
-dtuple_free_for_mysql(
-/*==================*/
- void* heap) /* in: memory heap where tuple was created */
-{
- mem_heap_free((mem_heap_t*)heap);
-}
-
-/*************************************************************************
-Sets number of fields used in a tuple. Normally this is set in
-dtuple_create, but if you want later to set it smaller, you can use this. */
-
-void
-dtuple_set_n_fields(
-/*================*/
- dtuple_t* tuple, /* in: tuple */
- ulint n_fields) /* in: number of fields */
-{
- ut_ad(tuple);
-
- tuple->n_fields = n_fields;
- tuple->n_fields_cmp = n_fields;
-}
-
-/**************************************************************
-Checks that a data field is typed. */
-static
-ibool
-dfield_check_typed_no_assert(
-/*=========================*/
- /* out: TRUE if ok */
- dfield_t* field) /* in: data field */
-{
- if (dfield_get_type(field)->mtype > DATA_MYSQL
- || dfield_get_type(field)->mtype < DATA_VARCHAR) {
-
- fprintf(stderr,
- "InnoDB: Error: data field type %lu, len %lu\n",
- (ulong) dfield_get_type(field)->mtype,
- (ulong) dfield_get_len(field));
- return(FALSE);
- }
-
- return(TRUE);
-}
-
-/**************************************************************
-Checks that a data tuple is typed. */
-
-ibool
-dtuple_check_typed_no_assert(
-/*=========================*/
- /* out: TRUE if ok */
- dtuple_t* tuple) /* in: tuple */
-{
- dfield_t* field;
- ulint i;
-
- if (dtuple_get_n_fields(tuple) > REC_MAX_N_FIELDS) {
- fprintf(stderr,
- "InnoDB: Error: index entry has %lu fields\n",
- (ulong) dtuple_get_n_fields(tuple));
-dump:
- fputs("InnoDB: Tuple contents: ", stderr);
- dtuple_print(stderr, tuple);
- putc('\n', stderr);
-
- return(FALSE);
- }
-
- for (i = 0; i < dtuple_get_n_fields(tuple); i++) {
-
- field = dtuple_get_nth_field(tuple, i);
-
- if (!dfield_check_typed_no_assert(field)) {
- goto dump;
- }
- }
-
- return(TRUE);
-}
-
-/**************************************************************
-Checks that a data field is typed. Asserts an error if not. */
-
-ibool
-dfield_check_typed(
-/*===============*/
- /* out: TRUE if ok */
- dfield_t* field) /* in: data field */
-{
- if (dfield_get_type(field)->mtype > DATA_MYSQL
- || dfield_get_type(field)->mtype < DATA_VARCHAR) {
-
- fprintf(stderr,
- "InnoDB: Error: data field type %lu, len %lu\n",
- (ulong) dfield_get_type(field)->mtype,
- (ulong) dfield_get_len(field));
-
- ut_error;
- }
-
- return(TRUE);
-}
-
-/**************************************************************
-Checks that a data tuple is typed. Asserts an error if not. */
-
-ibool
-dtuple_check_typed(
-/*===============*/
- /* out: TRUE if ok */
- dtuple_t* tuple) /* in: tuple */
-{
- dfield_t* field;
- ulint i;
-
- for (i = 0; i < dtuple_get_n_fields(tuple); i++) {
-
- field = dtuple_get_nth_field(tuple, i);
-
- ut_a(dfield_check_typed(field));
- }
-
- return(TRUE);
-}
-
-#ifdef UNIV_DEBUG
-/**************************************************************
-Validates the consistency of a tuple which must be complete, i.e,
-all fields must have been set. */
-
-ibool
-dtuple_validate(
-/*============*/
- /* out: TRUE if ok */
- dtuple_t* tuple) /* in: tuple */
-{
- dfield_t* field;
- byte* data;
- ulint n_fields;
- ulint len;
- ulint i;
- ulint j;
-
- ut_ad(tuple->magic_n == DATA_TUPLE_MAGIC_N);
-
- n_fields = dtuple_get_n_fields(tuple);
-
- /* We dereference all the data of each field to test
- for memory traps */
-
- for (i = 0; i < n_fields; i++) {
-
- field = dtuple_get_nth_field(tuple, i);
- len = dfield_get_len(field);
-
- if (len != UNIV_SQL_NULL) {
-
- data = field->data;
-
- for (j = 0; j < len; j++) {
-
- data_dummy += *data; /* fool the compiler not
- to optimize out this
- code */
- data++;
- }
- }
- }
-
- ut_a(dtuple_check_typed(tuple));
-
- return(TRUE);
-}
-#endif /* UNIV_DEBUG */
-
-/*****************************************************************
-Pretty prints a dfield value according to its data type. */
-
-void
-dfield_print(
-/*=========*/
- dfield_t* dfield) /* in: dfield */
-{
- byte* data;
- ulint len;
- ulint mtype;
- ulint i;
-
- len = dfield_get_len(dfield);
- data = dfield_get_data(dfield);
-
- if (len == UNIV_SQL_NULL) {
- fputs("NULL", stderr);
-
- return;
- }
-
- mtype = dtype_get_mtype(dfield_get_type(dfield));
-
- if ((mtype == DATA_CHAR) || (mtype == DATA_VARCHAR)) {
-
- for (i = 0; i < len; i++) {
- int c = *data++;
- putc(isprint(c) ? c : ' ', stderr);
- }
- } else if (mtype == DATA_INT) {
- ut_a(len == 4); /* only works for 32-bit integers */
- fprintf(stderr, "%d", (int)mach_read_from_4(data));
- } else {
- ut_error;
- }
-}
-
-/*****************************************************************
-Pretty prints a dfield value according to its data type. Also the hex string
-is printed if a string contains non-printable characters. */
-
-void
-dfield_print_also_hex(
-/*==================*/
- dfield_t* dfield) /* in: dfield */
-{
- byte* data;
- ulint len;
- ulint mtype;
- ulint i;
- ibool print_also_hex;
-
- len = dfield_get_len(dfield);
- data = dfield_get_data(dfield);
-
- if (len == UNIV_SQL_NULL) {
- fputs("NULL", stderr);
-
- return;
- }
-
- mtype = dtype_get_mtype(dfield_get_type(dfield));
-
- if ((mtype == DATA_CHAR) || (mtype == DATA_VARCHAR)) {
-
- print_also_hex = FALSE;
-
- for (i = 0; i < len; i++) {
- int c = *data++;
- if (!isprint(c)) {
- print_also_hex = TRUE;
- c = ' ';
- }
- putc(c, stderr);
- }
-
- if (!print_also_hex) {
-
- return;
- }
-
- fputs(" Hex: ", stderr);
-
- data = dfield_get_data(dfield);
-
- for (i = 0; i < len; i++) {
- fprintf(stderr, "%02lx", (ulint)*data);
-
- data++;
- }
- } else if (mtype == DATA_INT) {
- ut_a(len == 4); /* only works for 32-bit integers */
- fprintf(stderr, "%d", (int)mach_read_from_4(data));
- } else {
- ut_error;
- }
-}
-
-/*****************************************************************
-Print a dfield value using ut_print_buf. */
-static
-void
-dfield_print_raw(
-/*=============*/
- FILE* f, /* in: output stream */
- dfield_t* dfield) /* in: dfield */
-{
- ulint len = dfield->len;
- if (len != UNIV_SQL_NULL) {
- ulint print_len = ut_min(len, 1000);
- ut_print_buf(f, dfield->data, print_len);
- if (len != print_len) {
- fprintf(f, "(total %lu bytes)", (ulong) len);
- }
- } else {
- fputs(" SQL NULL", f);
- }
-}
-
-/**************************************************************
-The following function prints the contents of a tuple. */
-
-void
-dtuple_print(
-/*=========*/
- FILE* f, /* in: output stream */
- dtuple_t* tuple) /* in: tuple */
-{
- ulint n_fields;
- ulint i;
-
- n_fields = dtuple_get_n_fields(tuple);
-
- fprintf(f, "DATA TUPLE: %lu fields;\n", (ulong) n_fields);
-
- for (i = 0; i < n_fields; i++) {
- fprintf(f, " %lu:", (ulong) i);
-
- dfield_print_raw(f, dtuple_get_nth_field(tuple, i));
-
- putc(';', f);
- }
-
- putc('\n', f);
- ut_ad(dtuple_validate(tuple));
-}
-
-/******************************************************************
-Moves parts of long fields in entry to the big record vector so that
-the size of tuple drops below the maximum record size allowed in the
-database. Moves data only from those fields which are not necessary
-to determine uniquely the insertion place of the tuple in the index. */
-
-big_rec_t*
-dtuple_convert_big_rec(
-/*===================*/
- /* out, own: created big record vector,
- NULL if we are not able to shorten
- the entry enough, i.e., if there are
- too many short fields in entry */
- dict_index_t* index, /* in: index */
- dtuple_t* entry, /* in: index entry */
- ulint* ext_vec,/* in: array of externally stored fields,
- or NULL: if a field already is externally
- stored, then we cannot move it to the vector
- this function returns */
- ulint n_ext_vec)/* in: number of elements is ext_vec */
-{
- mem_heap_t* heap;
- big_rec_t* vector;
- dfield_t* dfield;
- ulint size;
- ulint n_fields;
- ulint longest;
- ulint longest_i = ULINT_MAX;
- ibool is_externally_stored;
- ulint i;
- ulint j;
-
- ut_a(dtuple_check_typed_no_assert(entry));
-
- size = rec_get_converted_size(index, entry);
-
- if (UNIV_UNLIKELY(size > 1000000000)) {
- fprintf(stderr,
- "InnoDB: Warning: tuple size very big: %lu\n",
- (ulong) size);
- fputs("InnoDB: Tuple contents: ", stderr);
- dtuple_print(stderr, entry);
- putc('\n', stderr);
- }
-
- heap = mem_heap_create(size + dtuple_get_n_fields(entry)
- * sizeof(big_rec_field_t) + 1000);
-
- vector = mem_heap_alloc(heap, sizeof(big_rec_t));
-
- vector->heap = heap;
- vector->fields = mem_heap_alloc(heap, dtuple_get_n_fields(entry)
- * sizeof(big_rec_field_t));
-
- /* Decide which fields to shorten: the algorithm is to look for
- the longest field whose type is DATA_BLOB */
-
- n_fields = 0;
-
- while (rec_get_converted_size(index, entry)
- >= ut_min(page_get_free_space_of_empty(
- dict_table_is_comp(index->table)) / 2,
- REC_MAX_DATA_SIZE)) {
-
- longest = 0;
- for (i = dict_index_get_n_unique_in_tree(index);
- i < dtuple_get_n_fields(entry); i++) {
-
- /* Skip over fields which already are externally
- stored */
-
- is_externally_stored = FALSE;
-
- if (ext_vec) {
- for (j = 0; j < n_ext_vec; j++) {
- if (ext_vec[j] == i) {
- is_externally_stored = TRUE;
- }
- }
- }
-
- if (!is_externally_stored) {
-
- dfield = dtuple_get_nth_field(entry, i);
-
- if (dfield->len != UNIV_SQL_NULL
- && dfield->len > longest) {
-
- longest = dfield->len;
-
- longest_i = i;
- }
- }
- }
-
- /* We do not store externally fields which are smaller than
- DICT_MAX_INDEX_COL_LEN */
-
-#if DICT_MAX_INDEX_COL_LEN <= REC_1BYTE_OFFS_LIMIT
-# error "DICT_MAX_INDEX_COL_LEN <= REC_1BYTE_OFFS_LIMIT"
-#endif
-
- if (longest < BTR_EXTERN_FIELD_REF_SIZE + 10
- + DICT_MAX_INDEX_COL_LEN) {
- /* Cannot shorten more */
-
- mem_heap_free(heap);
-
- return(NULL);
- }
-
- /* Move data from field longest_i to big rec vector;
- we do not let data size of the remaining entry
- drop below 128 which is the limit for the 2-byte
- offset storage format in a physical record. This
- we accomplish by storing 128 bytes of data in entry
- itself, and only the remaining part to big rec vec.
-
- We store the first bytes locally to the record. Then
- we can calculate all ordering fields in all indexes
- from locally stored data. */
-
- dfield = dtuple_get_nth_field(entry, longest_i);
- vector->fields[n_fields].field_no = longest_i;
-
- ut_a(dfield->len > DICT_MAX_INDEX_COL_LEN);
-
- vector->fields[n_fields].len = dfield->len
- - DICT_MAX_INDEX_COL_LEN;
-
- vector->fields[n_fields].data = mem_heap_alloc(
- heap, vector->fields[n_fields].len);
-
- /* Copy data (from the end of field) to big rec vector */
-
- ut_memcpy(vector->fields[n_fields].data,
- ((byte*)dfield->data) + dfield->len
- - vector->fields[n_fields].len,
- vector->fields[n_fields].len);
- dfield->len = dfield->len - vector->fields[n_fields].len
- + BTR_EXTERN_FIELD_REF_SIZE;
-
- /* Set the extern field reference in dfield to zero */
- memset(((byte*)dfield->data)
- + dfield->len - BTR_EXTERN_FIELD_REF_SIZE,
- 0, BTR_EXTERN_FIELD_REF_SIZE);
- n_fields++;
- }
-
- vector->n_fields = n_fields;
- return(vector);
-}
-
-/******************************************************************
-Puts back to entry the data stored in vector. Note that to ensure the
-fields in entry can accommodate the data, vector must have been created
-from entry with dtuple_convert_big_rec. */
-
-void
-dtuple_convert_back_big_rec(
-/*========================*/
- dict_index_t* index __attribute__((unused)), /* in: index */
- dtuple_t* entry, /* in: entry whose data was put to vector */
- big_rec_t* vector) /* in, own: big rec vector; it is
- freed in this function */
-{
- dfield_t* dfield;
- ulint i;
-
- for (i = 0; i < vector->n_fields; i++) {
-
- dfield = dtuple_get_nth_field(entry,
- vector->fields[i].field_no);
- /* Copy data from big rec vector */
-
- ut_memcpy(((byte*)dfield->data)
- + dfield->len - BTR_EXTERN_FIELD_REF_SIZE,
- vector->fields[i].data,
- vector->fields[i].len);
- dfield->len = dfield->len + vector->fields[i].len
- - BTR_EXTERN_FIELD_REF_SIZE;
- }
-
- mem_heap_free(vector->heap);
-}
-
-/******************************************************************
-Frees the memory in a big rec vector. */
-
-void
-dtuple_big_rec_free(
-/*================*/
- big_rec_t* vector) /* in, own: big rec vector; it is
- freed in this function */
-{
- mem_heap_free(vector->heap);
-}
diff --git a/storage/innobase/dyn/dyn0dyn.c b/storage/innobase/dyn/dyn0dyn.c
deleted file mode 100644
index bcf2fda2b08..00000000000
--- a/storage/innobase/dyn/dyn0dyn.c
+++ /dev/null
@@ -1,48 +0,0 @@
-/******************************************************
-The dynamically allocated array
-
-(c) 1996 Innobase Oy
-
-Created 2/5/1996 Heikki Tuuri
-*******************************************************/
-
-#include "dyn0dyn.h"
-#ifdef UNIV_NONINL
-#include "dyn0dyn.ic"
-#endif
-
-/****************************************************************
-Adds a new block to a dyn array. */
-
-dyn_block_t*
-dyn_array_add_block(
-/*================*/
- /* out: created block */
- dyn_array_t* arr) /* in: dyn array */
-{
- mem_heap_t* heap;
- dyn_block_t* block;
-
- ut_ad(arr);
- ut_ad(arr->magic_n == DYN_BLOCK_MAGIC_N);
-
- if (arr->heap == NULL) {
- UT_LIST_INIT(arr->base);
- UT_LIST_ADD_FIRST(list, arr->base, arr);
-
- arr->heap = mem_heap_create(sizeof(dyn_block_t));
- }
-
- block = dyn_array_get_last_block(arr);
- block->used = block->used | DYN_BLOCK_FULL_FLAG;
-
- heap = arr->heap;
-
- block = mem_heap_alloc(heap, sizeof(dyn_block_t));
-
- block->used = 0;
-
- UT_LIST_ADD_LAST(list, arr->base, block);
-
- return(block);
-}
diff --git a/storage/innobase/fut/fut0fut.c b/storage/innobase/fut/fut0fut.c
deleted file mode 100644
index 7f7a8fa39e7..00000000000
--- a/storage/innobase/fut/fut0fut.c
+++ /dev/null
@@ -1,14 +0,0 @@
-/**********************************************************************
-File-based utilities
-
-(c) 1995 Innobase Oy
-
-Created 12/13/1995 Heikki Tuuri
-***********************************************************************/
-
-#include "fut0fut.h"
-
-#ifdef UNIV_NONINL
-#include "fut0fut.ic"
-#endif
-
diff --git a/storage/innobase/ha/ha0ha.c b/storage/innobase/ha/ha0ha.c
deleted file mode 100644
index 077497493b4..00000000000
--- a/storage/innobase/ha/ha0ha.c
+++ /dev/null
@@ -1,380 +0,0 @@
-/************************************************************************
-The hash table with external chains
-
-(c) 1994-1997 Innobase Oy
-
-Created 8/22/1994 Heikki Tuuri
-*************************************************************************/
-
-#include "ha0ha.h"
-#ifdef UNIV_NONINL
-#include "ha0ha.ic"
-#endif
-
-#include "buf0buf.h"
-
-/*****************************************************************
-Creates a hash table with >= n array cells. The actual number of cells is
-chosen to be a prime number slightly bigger than n. */
-
-hash_table_t*
-ha_create_func(
-/*===========*/
- /* out, own: created table */
- ibool in_btr_search, /* in: TRUE if the hash table is used in
- the btr_search module */
- ulint n, /* in: number of array cells */
-#ifdef UNIV_SYNC_DEBUG
- ulint mutex_level, /* in: level of the mutexes in the latching
- order: this is used in the debug version */
-#endif /* UNIV_SYNC_DEBUG */
- ulint n_mutexes) /* in: number of mutexes to protect the
- hash table: must be a power of 2, or 0 */
-{
- hash_table_t* table;
- ulint i;
-
- table = hash_create(n);
-
- if (in_btr_search) {
- table->adaptive = TRUE;
- } else {
- table->adaptive = FALSE;
- }
-
- /* Creating MEM_HEAP_BTR_SEARCH type heaps can potentially fail,
- but in practise it never should in this case, hence the asserts. */
-
- if (n_mutexes == 0) {
- if (in_btr_search) {
- table->heap = mem_heap_create_in_btr_search(4096);
- ut_a(table->heap);
- } else {
- table->heap = mem_heap_create_in_buffer(4096);
- }
-
- return(table);
- }
-
- hash_create_mutexes(table, n_mutexes, mutex_level);
-
- table->heaps = mem_alloc(n_mutexes * sizeof(void*));
-
- for (i = 0; i < n_mutexes; i++) {
- if (in_btr_search) {
- table->heaps[i] = mem_heap_create_in_btr_search(4096);
- ut_a(table->heaps[i]);
- } else {
- table->heaps[i] = mem_heap_create_in_buffer(4096);
- }
- }
-
- return(table);
-}
-
-/*****************************************************************
-Inserts an entry into a hash table. If an entry with the same fold number
-is found, its node is updated to point to the new data, and no new node
-is inserted. */
-
-ibool
-ha_insert_for_fold(
-/*===============*/
- /* out: TRUE if succeed, FALSE if no more
- memory could be allocated */
- hash_table_t* table, /* in: hash table */
- ulint fold, /* in: folded value of data; if a node with
- the same fold value already exists, it is
- updated to point to the same data, and no new
- node is created! */
- void* data) /* in: data, must not be NULL */
-{
- hash_cell_t* cell;
- ha_node_t* node;
- ha_node_t* prev_node;
- buf_block_t* prev_block;
- ulint hash;
-
- ut_ad(table && data);
- ut_ad(!table->mutexes || mutex_own(hash_get_mutex(table, fold)));
-
- hash = hash_calc_hash(fold, table);
-
- cell = hash_get_nth_cell(table, hash);
-
- prev_node = cell->node;
-
- while (prev_node != NULL) {
- if (prev_node->fold == fold) {
- if (table->adaptive) {
- prev_block = buf_block_align(prev_node->data);
- ut_a(prev_block->n_pointers > 0);
- prev_block->n_pointers--;
- buf_block_align(data)->n_pointers++;
- }
-
- prev_node->data = data;
-
- return(TRUE);
- }
-
- prev_node = prev_node->next;
- }
-
- /* We have to allocate a new chain node */
-
- node = mem_heap_alloc(hash_get_heap(table, fold), sizeof(ha_node_t));
-
- if (node == NULL) {
- /* It was a btr search type memory heap and at the moment
- no more memory could be allocated: return */
-
- ut_ad(hash_get_heap(table, fold)->type & MEM_HEAP_BTR_SEARCH);
-
- return(FALSE);
- }
-
- ha_node_set_data(node, data);
-
- if (table->adaptive) {
- buf_block_align(data)->n_pointers++;
- }
-
- node->fold = fold;
-
- node->next = NULL;
-
- prev_node = cell->node;
-
- if (prev_node == NULL) {
-
- cell->node = node;
-
- return(TRUE);
- }
-
- while (prev_node->next != NULL) {
-
- prev_node = prev_node->next;
- }
-
- prev_node->next = node;
-
- return(TRUE);
-}
-
-/***************************************************************
-Deletes a hash node. */
-
-void
-ha_delete_hash_node(
-/*================*/
- hash_table_t* table, /* in: hash table */
- ha_node_t* del_node) /* in: node to be deleted */
-{
- if (table->adaptive) {
- ut_a(buf_block_align(del_node->data)->n_pointers > 0);
- buf_block_align(del_node->data)->n_pointers--;
- }
-
- HASH_DELETE_AND_COMPACT(ha_node_t, next, table, del_node);
-}
-
-/*****************************************************************
-Deletes an entry from a hash table. */
-
-void
-ha_delete(
-/*======*/
- hash_table_t* table, /* in: hash table */
- ulint fold, /* in: folded value of data */
- void* data) /* in: data, must not be NULL and must exist
- in the hash table */
-{
- ha_node_t* node;
-
- ut_ad(!table->mutexes || mutex_own(hash_get_mutex(table, fold)));
-
- node = ha_search_with_data(table, fold, data);
-
- ut_a(node);
-
- ha_delete_hash_node(table, node);
-}
-
-/*************************************************************
-Looks for an element when we know the pointer to the data, and updates
-the pointer to data, if found. */
-
-void
-ha_search_and_update_if_found(
-/*==========================*/
- hash_table_t* table, /* in: hash table */
- ulint fold, /* in: folded value of the searched data */
- void* data, /* in: pointer to the data */
- void* new_data)/* in: new pointer to the data */
-{
- ha_node_t* node;
-
- ut_ad(!table->mutexes || mutex_own(hash_get_mutex(table, fold)));
-
- node = ha_search_with_data(table, fold, data);
-
- if (node) {
- if (table->adaptive) {
- ut_a(buf_block_align(node->data)->n_pointers > 0);
- buf_block_align(node->data)->n_pointers--;
- buf_block_align(new_data)->n_pointers++;
- }
-
- node->data = new_data;
- }
-}
-
-/*********************************************************************
-Removes from the chain determined by fold all nodes whose data pointer
-points to the page given. */
-
-void
-ha_remove_all_nodes_to_page(
-/*========================*/
- hash_table_t* table, /* in: hash table */
- ulint fold, /* in: fold value */
- page_t* page) /* in: buffer page */
-{
- ha_node_t* node;
-
- ut_ad(!table->mutexes || mutex_own(hash_get_mutex(table, fold)));
-
- node = ha_chain_get_first(table, fold);
-
- while (node) {
- if (buf_frame_align(ha_node_get_data(node)) == page) {
-
- /* Remove the hash node */
-
- ha_delete_hash_node(table, node);
-
- /* Start again from the first node in the chain
- because the deletion may compact the heap of
- nodes and move other nodes! */
-
- node = ha_chain_get_first(table, fold);
- } else {
- node = ha_chain_get_next(node);
- }
- }
-#ifdef UNIV_DEBUG
- /* Check that all nodes really got deleted */
-
- node = ha_chain_get_first(table, fold);
-
- while (node) {
- ut_a(buf_frame_align(ha_node_get_data(node)) != page);
-
- node = ha_chain_get_next(node);
- }
-#endif
-}
-
-/*****************************************************************
-Validates a given range of the cells in hash table. */
-
-ibool
-ha_validate(
-/*========*/
- /* out: TRUE if ok */
- hash_table_t* table, /* in: hash table */
- ulint start_index, /* in: start index */
- ulint end_index) /* in: end index */
-{
- hash_cell_t* cell;
- ha_node_t* node;
- ibool ok = TRUE;
- ulint i;
-
- ut_a(start_index <= end_index);
- ut_a(start_index < hash_get_n_cells(table));
- ut_a(end_index < hash_get_n_cells(table));
-
- for (i = start_index; i <= end_index; i++) {
-
- cell = hash_get_nth_cell(table, i);
-
- node = cell->node;
-
- while (node) {
- if (hash_calc_hash(node->fold, table) != i) {
- ut_print_timestamp(stderr);
- fprintf(stderr,
- "InnoDB: Error: hash table node"
- " fold value %lu does not\n"
- "InnoDB: match the cell number %lu.\n",
- (ulong) node->fold, (ulong) i);
-
- ok = FALSE;
- }
-
- node = node->next;
- }
- }
-
- return(ok);
-}
-
-/*****************************************************************
-Prints info of a hash table. */
-
-void
-ha_print_info(
-/*==========*/
- FILE* file, /* in: file where to print */
- hash_table_t* table) /* in: hash table */
-{
-#ifdef UNIV_DEBUG
-/* Some of the code here is disabled for performance reasons in production
-builds, see http://bugs.mysql.com/36941 */
-#define PRINT_USED_CELLS
-#endif /* UNIV_DEBUG */
-
-#ifdef PRINT_USED_CELLS
- hash_cell_t* cell;
- ulint cells = 0;
- ulint i;
-#endif /* PRINT_USED_CELLS */
- ulint n_bufs;
-
-#ifdef PRINT_USED_CELLS
- for (i = 0; i < hash_get_n_cells(table); i++) {
-
- cell = hash_get_nth_cell(table, i);
-
- if (cell->node) {
-
- cells++;
- }
- }
-#endif /* PRINT_USED_CELLS */
-
- fprintf(file, "Hash table size %lu",
- (ulong) hash_get_n_cells(table));
-
-#ifdef PRINT_USED_CELLS
- fprintf(file, ", used cells %lu", (ulong) cells);
-#endif /* PRINT_USED_CELLS */
-
- if (table->heaps == NULL && table->heap != NULL) {
-
- /* This calculation is intended for the adaptive hash
- index: how many buffer frames we have reserved? */
-
- n_bufs = UT_LIST_GET_LEN(table->heap->base) - 1;
-
- if (table->heap->free_block) {
- n_bufs++;
- }
-
- fprintf(file, ", node heap has %lu buffer(s)\n",
- (ulong) n_bufs);
- }
-}
diff --git a/storage/innobase/ha/hash0hash.c b/storage/innobase/ha/hash0hash.c
deleted file mode 100644
index 4807015eee5..00000000000
--- a/storage/innobase/ha/hash0hash.c
+++ /dev/null
@@ -1,153 +0,0 @@
-/******************************************************
-The simple hash table utility
-
-(c) 1997 Innobase Oy
-
-Created 5/20/1997 Heikki Tuuri
-*******************************************************/
-
-#include "hash0hash.h"
-#ifdef UNIV_NONINL
-#include "hash0hash.ic"
-#endif
-
-#include "mem0mem.h"
-
-/****************************************************************
-Reserves the mutex for a fold value in a hash table. */
-
-void
-hash_mutex_enter(
-/*=============*/
- hash_table_t* table, /* in: hash table */
- ulint fold) /* in: fold */
-{
- mutex_enter(hash_get_mutex(table, fold));
-}
-
-/****************************************************************
-Releases the mutex for a fold value in a hash table. */
-
-void
-hash_mutex_exit(
-/*============*/
- hash_table_t* table, /* in: hash table */
- ulint fold) /* in: fold */
-{
- mutex_exit(hash_get_mutex(table, fold));
-}
-
-/****************************************************************
-Reserves all the mutexes of a hash table, in an ascending order. */
-
-void
-hash_mutex_enter_all(
-/*=================*/
- hash_table_t* table) /* in: hash table */
-{
- ulint i;
-
- for (i = 0; i < table->n_mutexes; i++) {
-
- mutex_enter(table->mutexes + i);
- }
-}
-
-/****************************************************************
-Releases all the mutexes of a hash table. */
-
-void
-hash_mutex_exit_all(
-/*================*/
- hash_table_t* table) /* in: hash table */
-{
- ulint i;
-
- for (i = 0; i < table->n_mutexes; i++) {
-
- mutex_exit(table->mutexes + i);
- }
-}
-
-/*****************************************************************
-Creates a hash table with >= n array cells. The actual number of cells is
-chosen to be a prime number slightly bigger than n. */
-
-hash_table_t*
-hash_create(
-/*========*/
- /* out, own: created table */
- ulint n) /* in: number of array cells */
-{
- hash_cell_t* array;
- ulint prime;
- hash_table_t* table;
- ulint i;
- hash_cell_t* cell;
-
- prime = ut_find_prime(n);
-
- table = mem_alloc(sizeof(hash_table_t));
-
- array = ut_malloc(sizeof(hash_cell_t) * prime);
-
- table->adaptive = FALSE;
- table->array = array;
- table->n_cells = prime;
- table->n_mutexes = 0;
- table->mutexes = NULL;
- table->heaps = NULL;
- table->heap = NULL;
- table->magic_n = HASH_TABLE_MAGIC_N;
-
- /* Initialize the cell array */
-
- for (i = 0; i < prime; i++) {
-
- cell = hash_get_nth_cell(table, i);
- cell->node = NULL;
- }
-
- return(table);
-}
-
-/*****************************************************************
-Frees a hash table. */
-
-void
-hash_table_free(
-/*============*/
- hash_table_t* table) /* in, own: hash table */
-{
- ut_a(table->mutexes == NULL);
-
- ut_free(table->array);
- mem_free(table);
-}
-
-/*****************************************************************
-Creates a mutex array to protect a hash table. */
-
-void
-hash_create_mutexes_func(
-/*=====================*/
- hash_table_t* table, /* in: hash table */
-#ifdef UNIV_SYNC_DEBUG
- ulint sync_level, /* in: latching order level of the
- mutexes: used in the debug version */
-#endif /* UNIV_SYNC_DEBUG */
- ulint n_mutexes) /* in: number of mutexes, must be a
- power of 2 */
-{
- ulint i;
-
- ut_a(n_mutexes == ut_2_power_up(n_mutexes));
-
- table->mutexes = mem_alloc(n_mutexes * sizeof(mutex_t));
-
- for (i = 0; i < n_mutexes; i++) {
- mutex_create(table->mutexes + i, sync_level);
- }
-
- table->n_mutexes = n_mutexes;
-}
diff --git a/storage/innobase/include/btr0btr.h b/storage/innobase/include/btr0btr.h
deleted file mode 100644
index 1573de7e818..00000000000
--- a/storage/innobase/include/btr0btr.h
+++ /dev/null
@@ -1,451 +0,0 @@
-/******************************************************
-The B-tree
-
-(c) 1994-1996 Innobase Oy
-
-Created 6/2/1994 Heikki Tuuri
-*******************************************************/
-
-#ifndef btr0btr_h
-#define btr0btr_h
-
-#include "univ.i"
-
-#include "dict0dict.h"
-#include "data0data.h"
-#include "page0cur.h"
-#include "rem0rec.h"
-#include "mtr0mtr.h"
-#include "btr0types.h"
-
-/* Maximum record size which can be stored on a page, without using the
-special big record storage structure */
-
-#define BTR_PAGE_MAX_REC_SIZE (UNIV_PAGE_SIZE / 2 - 200)
-
-/* Maximum depth of a B-tree in InnoDB. Note that this isn't a maximum as
-such; none of the tree operations avoid producing trees bigger than this. It
-is instead a "max depth that other code must work with", useful for e.g.
-fixed-size arrays that must store some information about each level in a
-tree. In other words: if a B-tree with bigger depth than this is
-encountered, it is not acceptable for it to lead to mysterious memory
-corruption, but it is acceptable for the program to die with a clear assert
-failure. */
-#define BTR_MAX_LEVELS 100
-
-/* Latching modes for btr_cur_search_to_nth_level(). */
-#define BTR_SEARCH_LEAF RW_S_LATCH
-#define BTR_MODIFY_LEAF RW_X_LATCH
-#define BTR_NO_LATCHES RW_NO_LATCH
-#define BTR_MODIFY_TREE 33
-#define BTR_CONT_MODIFY_TREE 34
-#define BTR_SEARCH_PREV 35
-#define BTR_MODIFY_PREV 36
-
-/* If this is ORed to the latch mode, it means that the search tuple will be
-inserted to the index, at the searched position */
-#define BTR_INSERT 512
-
-/* This flag ORed to latch mode says that we do the search in query
-optimization */
-#define BTR_ESTIMATE 1024
-
-/* This flag ORed to latch mode says that we can ignore possible
-UNIQUE definition on secondary indexes when we decide if we can use the
-insert buffer to speed up inserts */
-#define BTR_IGNORE_SEC_UNIQUE 2048
-
-/******************************************************************
-Gets the root node of a tree and x-latches it. */
-
-page_t*
-btr_root_get(
-/*=========*/
- /* out: root page, x-latched */
- dict_index_t* index, /* in: index tree */
- mtr_t* mtr); /* in: mtr */
-/******************************************************************
-Gets a buffer page and declares its latching order level. */
-UNIV_INLINE
-page_t*
-btr_page_get(
-/*=========*/
- ulint space, /* in: space id */
- ulint page_no, /* in: page number */
- ulint mode, /* in: latch mode */
- mtr_t* mtr); /* in: mtr */
-/******************************************************************
-Gets the index id field of a page. */
-UNIV_INLINE
-dulint
-btr_page_get_index_id(
-/*==================*/
- /* out: index id */
- page_t* page); /* in: index page */
-/************************************************************
-Gets the node level field in an index page. */
-UNIV_INLINE
-ulint
-btr_page_get_level_low(
-/*===================*/
- /* out: level, leaf level == 0 */
- page_t* page); /* in: index page */
-/************************************************************
-Gets the node level field in an index page. */
-UNIV_INLINE
-ulint
-btr_page_get_level(
-/*===============*/
- /* out: level, leaf level == 0 */
- page_t* page, /* in: index page */
- mtr_t* mtr); /* in: mini-transaction handle */
-/************************************************************
-Gets the next index page number. */
-UNIV_INLINE
-ulint
-btr_page_get_next(
-/*==============*/
- /* out: next page number */
- page_t* page, /* in: index page */
- mtr_t* mtr); /* in: mini-transaction handle */
-/************************************************************
-Gets the previous index page number. */
-UNIV_INLINE
-ulint
-btr_page_get_prev(
-/*==============*/
- /* out: prev page number */
- page_t* page, /* in: index page */
- mtr_t* mtr); /* in: mini-transaction handle */
-/*****************************************************************
-Gets pointer to the previous user record in the tree. It is assumed
-that the caller has appropriate latches on the page and its neighbor. */
-
-rec_t*
-btr_get_prev_user_rec(
-/*==================*/
- /* out: previous user record, NULL if there is none */
- rec_t* rec, /* in: record on leaf level */
- mtr_t* mtr); /* in: mtr holding a latch on the page, and if
- needed, also to the previous page */
-/*****************************************************************
-Gets pointer to the next user record in the tree. It is assumed
-that the caller has appropriate latches on the page and its neighbor. */
-
-rec_t*
-btr_get_next_user_rec(
-/*==================*/
- /* out: next user record, NULL if there is none */
- rec_t* rec, /* in: record on leaf level */
- mtr_t* mtr); /* in: mtr holding a latch on the page, and if
- needed, also to the next page */
-/******************************************************************
-Releases the latch on a leaf page and bufferunfixes it. */
-UNIV_INLINE
-void
-btr_leaf_page_release(
-/*==================*/
- page_t* page, /* in: page */
- ulint latch_mode, /* in: BTR_SEARCH_LEAF or BTR_MODIFY_LEAF */
- mtr_t* mtr); /* in: mtr */
-/******************************************************************
-Gets the child node file address in a node pointer. */
-UNIV_INLINE
-ulint
-btr_node_ptr_get_child_page_no(
-/*===========================*/
- /* out: child node address */
- rec_t* rec, /* in: node pointer record */
- const ulint* offsets);/* in: array returned by rec_get_offsets() */
-/****************************************************************
-Creates the root node for a new index tree. */
-
-ulint
-btr_create(
-/*=======*/
- /* out: page number of the created root, FIL_NULL if
- did not succeed */
- ulint type, /* in: type of the index */
- ulint space, /* in: space where created */
- dulint index_id,/* in: index id */
- ulint comp, /* in: nonzero=compact page format */
- mtr_t* mtr); /* in: mini-transaction handle */
-/****************************************************************
-Frees a B-tree except the root page, which MUST be freed after this
-by calling btr_free_root. */
-
-void
-btr_free_but_not_root(
-/*==================*/
- ulint space, /* in: space where created */
- ulint root_page_no); /* in: root page number */
-/****************************************************************
-Frees the B-tree root page. Other tree MUST already have been freed. */
-
-void
-btr_free_root(
-/*==========*/
- ulint space, /* in: space where created */
- ulint root_page_no, /* in: root page number */
- mtr_t* mtr); /* in: a mini-transaction which has already
- been started */
-/*****************************************************************
-Makes tree one level higher by splitting the root, and inserts
-the tuple. It is assumed that mtr contains an x-latch on the tree.
-NOTE that the operation of this function must always succeed,
-we cannot reverse it: therefore enough free disk space must be
-guaranteed to be available before this function is called. */
-
-rec_t*
-btr_root_raise_and_insert(
-/*======================*/
- /* out: inserted record */
- btr_cur_t* cursor, /* in: cursor at which to insert: must be
- on the root page; when the function returns,
- the cursor is positioned on the predecessor
- of the inserted record */
- dtuple_t* tuple, /* in: tuple to insert */
- mtr_t* mtr); /* in: mtr */
-/*****************************************************************
-Reorganizes an index page. */
-
-void
-btr_page_reorganize(
-/*================*/
- page_t* page, /* in: page to be reorganized */
- dict_index_t* index, /* in: record descriptor */
- mtr_t* mtr); /* in: mtr */
-/*****************************************************************
-Decides if the page should be split at the convergence point of
-inserts converging to left. */
-
-ibool
-btr_page_get_split_rec_to_left(
-/*===========================*/
- /* out: TRUE if split recommended */
- btr_cur_t* cursor, /* in: cursor at which to insert */
- rec_t** split_rec);/* out: if split recommended,
- the first record on upper half page,
- or NULL if tuple should be first */
-/*****************************************************************
-Decides if the page should be split at the convergence point of
-inserts converging to right. */
-
-ibool
-btr_page_get_split_rec_to_right(
-/*============================*/
- /* out: TRUE if split recommended */
- btr_cur_t* cursor, /* in: cursor at which to insert */
- rec_t** split_rec);/* out: if split recommended,
- the first record on upper half page,
- or NULL if tuple should be first */
-/*****************************************************************
-Splits an index page to halves and inserts the tuple. It is assumed
-that mtr holds an x-latch to the index tree. NOTE: the tree x-latch
-is released within this function! NOTE that the operation of this
-function must always succeed, we cannot reverse it: therefore
-enough free disk space must be guaranteed to be available before
-this function is called. */
-
-rec_t*
-btr_page_split_and_insert(
-/*======================*/
- /* out: inserted record; NOTE: the tree
- x-latch is released! NOTE: 2 free disk
- pages must be available! */
- btr_cur_t* cursor, /* in: cursor at which to insert; when the
- function returns, the cursor is positioned
- on the predecessor of the inserted record */
- dtuple_t* tuple, /* in: tuple to insert */
- mtr_t* mtr); /* in: mtr */
-/***********************************************************
-Inserts a data tuple to a tree on a non-leaf level. It is assumed
-that mtr holds an x-latch on the tree. */
-
-void
-btr_insert_on_non_leaf_level(
-/*=========================*/
- dict_index_t* index, /* in: index */
- ulint level, /* in: level, must be > 0 */
- dtuple_t* tuple, /* in: the record to be inserted */
- mtr_t* mtr); /* in: mtr */
-/********************************************************************
-Sets a record as the predefined minimum record. */
-
-void
-btr_set_min_rec_mark(
-/*=================*/
- rec_t* rec, /* in: record */
- ulint comp, /* in: nonzero=compact page format */
- mtr_t* mtr); /* in: mtr */
-/*****************************************************************
-Deletes on the upper level the node pointer to a page. */
-
-void
-btr_node_ptr_delete(
-/*================*/
- dict_index_t* index, /* in: index tree */
- page_t* page, /* in: page whose node pointer is deleted */
- mtr_t* mtr); /* in: mtr */
-#ifdef UNIV_DEBUG
-/****************************************************************
-Checks that the node pointer to a page is appropriate. */
-
-ibool
-btr_check_node_ptr(
-/*===============*/
- /* out: TRUE */
- dict_index_t* index, /* in: index tree */
- page_t* page, /* in: index page */
- mtr_t* mtr); /* in: mtr */
-#endif /* UNIV_DEBUG */
-/*****************************************************************
-Tries to merge the page first to the left immediate brother if such a
-brother exists, and the node pointers to the current page and to the
-brother reside on the same page. If the left brother does not satisfy these
-conditions, looks at the right brother. If the page is the only one on that
-level lifts the records of the page to the father page, thus reducing the
-tree height. It is assumed that mtr holds an x-latch on the tree and on the
-page. If cursor is on the leaf level, mtr must also hold x-latches to
-the brothers, if they exist. NOTE: it is assumed that the caller has reserved
-enough free extents so that the compression will always succeed if done! */
-void
-btr_compress(
-/*=========*/
- btr_cur_t* cursor, /* in: cursor on the page to merge or lift;
- the page must not be empty: in record delete
- use btr_discard_page if the page would become
- empty */
- mtr_t* mtr); /* in: mtr */
-/*****************************************************************
-Discards a page from a B-tree. This is used to remove the last record from
-a B-tree page: the whole page must be removed at the same time. This cannot
-be used for the root page, which is allowed to be empty. */
-
-void
-btr_discard_page(
-/*=============*/
- btr_cur_t* cursor, /* in: cursor on the page to discard: not on
- the root page */
- mtr_t* mtr); /* in: mtr */
-/********************************************************************
-Parses the redo log record for setting an index record as the predefined
-minimum record. */
-
-byte*
-btr_parse_set_min_rec_mark(
-/*=======================*/
- /* out: end of log record or NULL */
- byte* ptr, /* in: buffer */
- byte* end_ptr,/* in: buffer end */
- ulint comp, /* in: nonzero=compact page format */
- page_t* page, /* in: page or NULL */
- mtr_t* mtr); /* in: mtr or NULL */
-/***************************************************************
-Parses a redo log record of reorganizing a page. */
-
-byte*
-btr_parse_page_reorganize(
-/*======================*/
- /* out: end of log record or NULL */
- byte* ptr, /* in: buffer */
- byte* end_ptr,/* in: buffer end */
- dict_index_t* index, /* in: record descriptor */
- page_t* page, /* in: page or NULL */
- mtr_t* mtr); /* in: mtr or NULL */
-/******************************************************************
-Gets the number of pages in a B-tree. */
-
-ulint
-btr_get_size(
-/*=========*/
- /* out: number of pages */
- dict_index_t* index, /* in: index */
- ulint flag); /* in: BTR_N_LEAF_PAGES or BTR_TOTAL_SIZE */
-/******************************************************************
-Allocates a new file page to be used in an index tree. NOTE: we assume
-that the caller has made the reservation for free extents! */
-
-page_t*
-btr_page_alloc(
-/*===========*/
- /* out: new allocated page, x-latched;
- NULL if out of space */
- dict_index_t* index, /* in: index tree */
- ulint hint_page_no, /* in: hint of a good page */
- byte file_direction, /* in: direction where a possible
- page split is made */
- ulint level, /* in: level where the page is placed
- in the tree */
- mtr_t* mtr); /* in: mtr */
-/******************************************************************
-Frees a file page used in an index tree. NOTE: cannot free field external
-storage pages because the page must contain info on its level. */
-
-void
-btr_page_free(
-/*==========*/
- dict_index_t* index, /* in: index tree */
- page_t* page, /* in: page to be freed, x-latched */
- mtr_t* mtr); /* in: mtr */
-/******************************************************************
-Frees a file page used in an index tree. Can be used also to BLOB
-external storage pages, because the page level 0 can be given as an
-argument. */
-
-void
-btr_page_free_low(
-/*==============*/
- dict_index_t* index, /* in: index tree */
- page_t* page, /* in: page to be freed, x-latched */
- ulint level, /* in: page level */
- mtr_t* mtr); /* in: mtr */
-#ifdef UNIV_BTR_PRINT
-/*****************************************************************
-Prints size info of a B-tree. */
-
-void
-btr_print_size(
-/*===========*/
- dict_index_t* index); /* in: index tree */
-/******************************************************************
-Prints directories and other info of all nodes in the index. */
-
-void
-btr_print_index(
-/*============*/
- dict_index_t* index, /* in: index */
- ulint width); /* in: print this many entries from start
- and end */
-#endif /* UNIV_BTR_PRINT */
-/****************************************************************
-Checks the size and number of fields in a record based on the definition of
-the index. */
-
-ibool
-btr_index_rec_validate(
-/*===================*/
- /* out: TRUE if ok */
- rec_t* rec, /* in: index record */
- dict_index_t* index, /* in: index */
- ibool dump_on_error); /* in: TRUE if the function
- should print hex dump of record
- and page on error */
-/******************************************************************
-Checks the consistency of an index tree. */
-
-ibool
-btr_validate_index(
-/*===============*/
- /* out: TRUE if ok */
- dict_index_t* index, /* in: index */
- trx_t* trx); /* in: transaction or NULL */
-
-#define BTR_N_LEAF_PAGES 1
-#define BTR_TOTAL_SIZE 2
-
-#ifndef UNIV_NONINL
-#include "btr0btr.ic"
-#endif
-
-#endif
diff --git a/storage/innobase/include/btr0btr.ic b/storage/innobase/include/btr0btr.ic
deleted file mode 100644
index 4a88f58b318..00000000000
--- a/storage/innobase/include/btr0btr.ic
+++ /dev/null
@@ -1,234 +0,0 @@
-/******************************************************
-The B-tree
-
-(c) 1994-1996 Innobase Oy
-
-Created 6/2/1994 Heikki Tuuri
-*******************************************************/
-
-#include "mach0data.h"
-#include "mtr0mtr.h"
-#include "mtr0log.h"
-
-#define BTR_MAX_NODE_LEVEL 50 /* used in debug checking */
-
-/******************************************************************
-Gets a buffer page and declares its latching order level. */
-UNIV_INLINE
-page_t*
-btr_page_get(
-/*=========*/
- ulint space, /* in: space id */
- ulint page_no, /* in: page number */
- ulint mode, /* in: latch mode */
- mtr_t* mtr) /* in: mtr */
-{
- page_t* page;
-
- page = buf_page_get(space, page_no, mode, mtr);
-#ifdef UNIV_SYNC_DEBUG
- if (mode != RW_NO_LATCH) {
-
- buf_page_dbg_add_level(page, SYNC_TREE_NODE);
- }
-#endif
- return(page);
-}
-
-/******************************************************************
-Sets the index id field of a page. */
-UNIV_INLINE
-void
-btr_page_set_index_id(
-/*==================*/
- page_t* page, /* in: page to be created */
- dulint id, /* in: index id */
- mtr_t* mtr) /* in: mtr */
-{
- mlog_write_dulint(page + PAGE_HEADER + PAGE_INDEX_ID, id, mtr);
-}
-
-/******************************************************************
-Gets the index id field of a page. */
-UNIV_INLINE
-dulint
-btr_page_get_index_id(
-/*==================*/
- /* out: index id */
- page_t* page) /* in: index page */
-{
- return(mach_read_from_8(page + PAGE_HEADER + PAGE_INDEX_ID));
-}
-
-/************************************************************
-Gets the node level field in an index page. */
-UNIV_INLINE
-ulint
-btr_page_get_level_low(
-/*===================*/
- /* out: level, leaf level == 0 */
- page_t* page) /* in: index page */
-{
- ulint level;
-
- ut_ad(page);
-
- level = mach_read_from_2(page + PAGE_HEADER + PAGE_LEVEL);
-
- ut_ad(level <= BTR_MAX_NODE_LEVEL);
-
- return(level);
-}
-
-/************************************************************
-Gets the node level field in an index page. */
-UNIV_INLINE
-ulint
-btr_page_get_level(
-/*===============*/
- /* out: level, leaf level == 0 */
- page_t* page, /* in: index page */
- mtr_t* mtr __attribute__((unused))) /* in: mini-transaction handle */
-{
- ut_ad(page && mtr);
-
- return(btr_page_get_level_low(page));
-}
-
-/************************************************************
-Sets the node level field in an index page. */
-UNIV_INLINE
-void
-btr_page_set_level(
-/*===============*/
- page_t* page, /* in: index page */
- ulint level, /* in: level, leaf level == 0 */
- mtr_t* mtr) /* in: mini-transaction handle */
-{
- ut_ad(page && mtr);
- ut_ad(level <= BTR_MAX_NODE_LEVEL);
-
- mlog_write_ulint(page + PAGE_HEADER + PAGE_LEVEL, level,
- MLOG_2BYTES, mtr);
-}
-
-/************************************************************
-Gets the next index page number. */
-UNIV_INLINE
-ulint
-btr_page_get_next(
-/*==============*/
- /* out: next page number */
- page_t* page, /* in: index page */
- mtr_t* mtr __attribute__((unused))) /* in: mini-transaction handle */
-{
- ut_ad(page && mtr);
- ut_ad(mtr_memo_contains(mtr, buf_block_align(page),
- MTR_MEMO_PAGE_X_FIX)
- || mtr_memo_contains(mtr, buf_block_align(page),
- MTR_MEMO_PAGE_S_FIX));
-
- return(mach_read_from_4(page + FIL_PAGE_NEXT));
-}
-
-/************************************************************
-Sets the next index page field. */
-UNIV_INLINE
-void
-btr_page_set_next(
-/*==============*/
- page_t* page, /* in: index page */
- ulint next, /* in: next page number */
- mtr_t* mtr) /* in: mini-transaction handle */
-{
- ut_ad(page && mtr);
-
- mlog_write_ulint(page + FIL_PAGE_NEXT, next, MLOG_4BYTES, mtr);
-}
-
-/************************************************************
-Gets the previous index page number. */
-UNIV_INLINE
-ulint
-btr_page_get_prev(
-/*==============*/
- /* out: prev page number */
- page_t* page, /* in: index page */
- mtr_t* mtr __attribute__((unused))) /* in: mini-transaction handle */
-{
- ut_ad(page && mtr);
-
- return(mach_read_from_4(page + FIL_PAGE_PREV));
-}
-
-/************************************************************
-Sets the previous index page field. */
-UNIV_INLINE
-void
-btr_page_set_prev(
-/*==============*/
- page_t* page, /* in: index page */
- ulint prev, /* in: previous page number */
- mtr_t* mtr) /* in: mini-transaction handle */
-{
- ut_ad(page && mtr);
-
- mlog_write_ulint(page + FIL_PAGE_PREV, prev, MLOG_4BYTES, mtr);
-}
-
-/******************************************************************
-Gets the child node file address in a node pointer. */
-UNIV_INLINE
-ulint
-btr_node_ptr_get_child_page_no(
-/*===========================*/
- /* out: child node address */
- rec_t* rec, /* in: node pointer record */
- const ulint* offsets)/* in: array returned by rec_get_offsets() */
-{
- byte* field;
- ulint len;
- ulint page_no;
-
- ut_ad(!rec_offs_comp(offsets) || rec_get_node_ptr_flag(rec));
-
- /* The child address is in the last field */
- field = rec_get_nth_field(rec, offsets,
- rec_offs_n_fields(offsets) - 1, &len);
-
- ut_ad(len == 4);
-
- page_no = mach_read_from_4(field);
-
- if (UNIV_UNLIKELY(page_no == 0)) {
- fprintf(stderr,
- "InnoDB: a nonsensical page number 0"
- " in a node ptr record at offset %lu\n",
- (ulong) page_offset(rec));
- buf_page_print(buf_frame_align(rec));
- }
-
- return(page_no);
-}
-
-/******************************************************************
-Releases the latches on a leaf page and bufferunfixes it. */
-UNIV_INLINE
-void
-btr_leaf_page_release(
-/*==================*/
- page_t* page, /* in: page */
- ulint latch_mode, /* in: BTR_SEARCH_LEAF or BTR_MODIFY_LEAF */
- mtr_t* mtr) /* in: mtr */
-{
- ut_ad(!mtr_memo_contains(mtr, buf_block_align(page),
- MTR_MEMO_MODIFY));
- if (latch_mode == BTR_SEARCH_LEAF) {
- mtr_memo_release(mtr, buf_block_align(page),
- MTR_MEMO_PAGE_S_FIX);
- } else {
- ut_ad(latch_mode == BTR_MODIFY_LEAF);
- mtr_memo_release(mtr, buf_block_align(page),
- MTR_MEMO_PAGE_X_FIX);
- }
-}
diff --git a/storage/innobase/include/btr0cur.h b/storage/innobase/include/btr0cur.h
deleted file mode 100644
index 213dcb7f568..00000000000
--- a/storage/innobase/include/btr0cur.h
+++ /dev/null
@@ -1,706 +0,0 @@
-/******************************************************
-The index tree cursor
-
-(c) 1994-1996 Innobase Oy
-
-Created 10/16/1994 Heikki Tuuri
-*******************************************************/
-
-#ifndef btr0cur_h
-#define btr0cur_h
-
-#include "univ.i"
-#include "dict0dict.h"
-#include "data0data.h"
-#include "page0cur.h"
-#include "btr0types.h"
-#include "que0types.h"
-#include "row0types.h"
-#include "ha0ha.h"
-
-/* Mode flags for btr_cur operations; these can be ORed */
-#define BTR_NO_UNDO_LOG_FLAG 1 /* do no undo logging */
-#define BTR_NO_LOCKING_FLAG 2 /* do no record lock checking */
-#define BTR_KEEP_SYS_FLAG 4 /* sys fields will be found from the
- update vector or inserted entry */
-
-#define BTR_CUR_ADAPT
-#define BTR_CUR_HASH_ADAPT
-
-/*************************************************************
-Returns the page cursor component of a tree cursor. */
-UNIV_INLINE
-page_cur_t*
-btr_cur_get_page_cur(
-/*=================*/
- /* out: pointer to page cursor component */
- btr_cur_t* cursor);/* in: tree cursor */
-/*************************************************************
-Returns the record pointer of a tree cursor. */
-UNIV_INLINE
-rec_t*
-btr_cur_get_rec(
-/*============*/
- /* out: pointer to record */
- btr_cur_t* cursor);/* in: tree cursor */
-/*************************************************************
-Invalidates a tree cursor by setting record pointer to NULL. */
-UNIV_INLINE
-void
-btr_cur_invalidate(
-/*===============*/
- btr_cur_t* cursor);/* in: tree cursor */
-/*************************************************************
-Returns the page of a tree cursor. */
-UNIV_INLINE
-page_t*
-btr_cur_get_page(
-/*=============*/
- /* out: pointer to page */
- btr_cur_t* cursor);/* in: tree cursor */
-/*************************************************************
-Returns the index of a cursor. */
-UNIV_INLINE
-dict_index_t*
-btr_cur_get_index(
-/*==============*/
- /* out: index */
- btr_cur_t* cursor);/* in: B-tree cursor */
-/*************************************************************
-Positions a tree cursor at a given record. */
-UNIV_INLINE
-void
-btr_cur_position(
-/*=============*/
- dict_index_t* index, /* in: index */
- rec_t* rec, /* in: record in tree */
- btr_cur_t* cursor);/* in: cursor */
-/************************************************************************
-Searches an index tree and positions a tree cursor on a given level.
-NOTE: n_fields_cmp in tuple must be set so that it cannot be compared
-to node pointer page number fields on the upper levels of the tree!
-Note that if mode is PAGE_CUR_LE, which is used in inserts, then
-cursor->up_match and cursor->low_match both will have sensible values.
-If mode is PAGE_CUR_GE, then up_match will a have a sensible value. */
-
-void
-btr_cur_search_to_nth_level(
-/*========================*/
- dict_index_t* index, /* in: index */
- ulint level, /* in: the tree level of search */
- dtuple_t* tuple, /* in: data tuple; NOTE: n_fields_cmp in
- tuple must be set so that it cannot get
- compared to the node ptr page number field! */
- ulint mode, /* in: PAGE_CUR_L, ...;
- NOTE that if the search is made using a unique
- prefix of a record, mode should be PAGE_CUR_LE,
- not PAGE_CUR_GE, as the latter may end up on
- the previous page of the record! Inserts
- should always be made using PAGE_CUR_LE to
- search the position! */
- ulint latch_mode, /* in: BTR_SEARCH_LEAF, ..., ORed with
- BTR_INSERT and BTR_ESTIMATE;
- cursor->left_page is used to store a pointer
- to the left neighbor page, in the cases
- BTR_SEARCH_PREV and BTR_MODIFY_PREV;
- NOTE that if has_search_latch
- is != 0, we maybe do not have a latch set
- on the cursor page, we assume
- the caller uses his search latch
- to protect the record! */
- btr_cur_t* cursor, /* in/out: tree cursor; the cursor page is
- s- or x-latched, but see also above! */
- ulint has_search_latch,/* in: latch mode the caller
- currently has on btr_search_latch:
- RW_S_LATCH, or 0 */
- mtr_t* mtr); /* in: mtr */
-/*********************************************************************
-Opens a cursor at either end of an index. */
-
-void
-btr_cur_open_at_index_side(
-/*=======================*/
- ibool from_left, /* in: TRUE if open to the low end,
- FALSE if to the high end */
- dict_index_t* index, /* in: index */
- ulint latch_mode, /* in: latch mode */
- btr_cur_t* cursor, /* in: cursor */
- mtr_t* mtr); /* in: mtr */
-/**************************************************************************
-Positions a cursor at a randomly chosen position within a B-tree. */
-
-void
-btr_cur_open_at_rnd_pos(
-/*====================*/
- dict_index_t* index, /* in: index */
- ulint latch_mode, /* in: BTR_SEARCH_LEAF, ... */
- btr_cur_t* cursor, /* in/out: B-tree cursor */
- mtr_t* mtr); /* in: mtr */
-/*****************************************************************
-Tries to perform an insert to a page in an index tree, next to cursor.
-It is assumed that mtr holds an x-latch on the page. The operation does
-not succeed if there is too little space on the page. If there is just
-one record on the page, the insert will always succeed; this is to
-prevent trying to split a page with just one record. */
-
-ulint
-btr_cur_optimistic_insert(
-/*======================*/
- /* out: DB_SUCCESS, DB_WAIT_LOCK,
- DB_FAIL, or error number */
- ulint flags, /* in: undo logging and locking flags: if not
- zero, the parameters index and thr should be
- specified */
- btr_cur_t* cursor, /* in: cursor on page after which to insert;
- cursor stays valid */
- dtuple_t* entry, /* in: entry to insert */
- rec_t** rec, /* out: pointer to inserted record if
- succeed */
- big_rec_t** big_rec,/* out: big rec vector whose fields have to
- be stored externally by the caller, or
- NULL */
- que_thr_t* thr, /* in: query thread or NULL */
- mtr_t* mtr); /* in: mtr */
-/*****************************************************************
-Performs an insert on a page of an index tree. It is assumed that mtr
-holds an x-latch on the tree and on the cursor page. If the insert is
-made on the leaf level, to avoid deadlocks, mtr must also own x-latches
-to brothers of page, if those brothers exist. */
-
-ulint
-btr_cur_pessimistic_insert(
-/*=======================*/
- /* out: DB_SUCCESS or error number */
- ulint flags, /* in: undo logging and locking flags: if not
- zero, the parameter thr should be
- specified; if no undo logging is specified,
- then the caller must have reserved enough
- free extents in the file space so that the
- insertion will certainly succeed */
- btr_cur_t* cursor, /* in: cursor after which to insert;
- cursor stays valid */
- dtuple_t* entry, /* in: entry to insert */
- rec_t** rec, /* out: pointer to inserted record if
- succeed */
- big_rec_t** big_rec,/* out: big rec vector whose fields have to
- be stored externally by the caller, or
- NULL */
- que_thr_t* thr, /* in: query thread or NULL */
- mtr_t* mtr); /* in: mtr */
-/*****************************************************************
-Updates a record when the update causes no size changes in its fields. */
-
-ulint
-btr_cur_update_in_place(
-/*====================*/
- /* out: DB_SUCCESS or error number */
- ulint flags, /* in: undo logging and locking flags */
- btr_cur_t* cursor, /* in: cursor on the record to update;
- cursor stays valid and positioned on the
- same record */
- upd_t* update, /* in: update vector */
- ulint cmpl_info,/* in: compiler info on secondary index
- updates */
- que_thr_t* thr, /* in: query thread */
- mtr_t* mtr); /* in: mtr */
-/*****************************************************************
-Tries to update a record on a page in an index tree. It is assumed that mtr
-holds an x-latch on the page. The operation does not succeed if there is too
-little space on the page or if the update would result in too empty a page,
-so that tree compression is recommended. */
-
-ulint
-btr_cur_optimistic_update(
-/*======================*/
- /* out: DB_SUCCESS, or DB_OVERFLOW if the
- updated record does not fit, DB_UNDERFLOW
- if the page would become too empty */
- ulint flags, /* in: undo logging and locking flags */
- btr_cur_t* cursor, /* in: cursor on the record to update;
- cursor stays valid and positioned on the
- same record */
- upd_t* update, /* in: update vector; this must also
- contain trx id and roll ptr fields */
- ulint cmpl_info,/* in: compiler info on secondary index
- updates */
- que_thr_t* thr, /* in: query thread */
- mtr_t* mtr); /* in: mtr */
-/*****************************************************************
-Performs an update of a record on a page of a tree. It is assumed
-that mtr holds an x-latch on the tree and on the cursor page. If the
-update is made on the leaf level, to avoid deadlocks, mtr must also
-own x-latches to brothers of page, if those brothers exist. */
-
-ulint
-btr_cur_pessimistic_update(
-/*=======================*/
- /* out: DB_SUCCESS or error code */
- ulint flags, /* in: undo logging, locking, and rollback
- flags */
- btr_cur_t* cursor, /* in: cursor on the record to update */
- big_rec_t** big_rec,/* out: big rec vector whose fields have to
- be stored externally by the caller, or NULL */
- upd_t* update, /* in: update vector; this is allowed also
- contain trx id and roll ptr fields, but
- the values in update vector have no effect */
- ulint cmpl_info,/* in: compiler info on secondary index
- updates */
- que_thr_t* thr, /* in: query thread */
- mtr_t* mtr); /* in: mtr */
-/***************************************************************
-Marks a clustered index record deleted. Writes an undo log record to
-undo log on this delete marking. Writes in the trx id field the id
-of the deleting transaction, and in the roll ptr field pointer to the
-undo log record created. */
-
-ulint
-btr_cur_del_mark_set_clust_rec(
-/*===========================*/
- /* out: DB_SUCCESS, DB_LOCK_WAIT, or error
- number */
- ulint flags, /* in: undo logging and locking flags */
- btr_cur_t* cursor, /* in: cursor */
- ibool val, /* in: value to set */
- que_thr_t* thr, /* in: query thread */
- mtr_t* mtr); /* in: mtr */
-/***************************************************************
-Sets a secondary index record delete mark to TRUE or FALSE. */
-
-ulint
-btr_cur_del_mark_set_sec_rec(
-/*=========================*/
- /* out: DB_SUCCESS, DB_LOCK_WAIT, or error
- number */
- ulint flags, /* in: locking flag */
- btr_cur_t* cursor, /* in: cursor */
- ibool val, /* in: value to set */
- que_thr_t* thr, /* in: query thread */
- mtr_t* mtr); /* in: mtr */
-/***************************************************************
-Sets a secondary index record delete mark to FALSE. This function is
-only used by the insert buffer insert merge mechanism. */
-
-void
-btr_cur_del_unmark_for_ibuf(
-/*========================*/
- rec_t* rec, /* in: record to delete unmark */
- mtr_t* mtr); /* in: mtr */
-/*****************************************************************
-Tries to compress a page of the tree on the leaf level. It is assumed
-that mtr holds an x-latch on the tree and on the cursor page. To avoid
-deadlocks, mtr must also own x-latches to brothers of page, if those
-brothers exist. NOTE: it is assumed that the caller has reserved enough
-free extents so that the compression will always succeed if done! */
-
-void
-btr_cur_compress(
-/*=============*/
- btr_cur_t* cursor, /* in: cursor on the page to compress;
- cursor does not stay valid */
- mtr_t* mtr); /* in: mtr */
-/*****************************************************************
-Tries to compress a page of the tree if it seems useful. It is assumed
-that mtr holds an x-latch on the tree and on the cursor page. To avoid
-deadlocks, mtr must also own x-latches to brothers of page, if those
-brothers exist. NOTE: it is assumed that the caller has reserved enough
-free extents so that the compression will always succeed if done! */
-
-ibool
-btr_cur_compress_if_useful(
-/*=======================*/
- /* out: TRUE if compression occurred */
- btr_cur_t* cursor, /* in: cursor on the page to compress;
- cursor does not stay valid if compression
- occurs */
- mtr_t* mtr); /* in: mtr */
-/***********************************************************
-Removes the record on which the tree cursor is positioned. It is assumed
-that the mtr has an x-latch on the page where the cursor is positioned,
-but no latch on the whole tree. */
-
-ibool
-btr_cur_optimistic_delete(
-/*======================*/
- /* out: TRUE if success, i.e., the page
- did not become too empty */
- btr_cur_t* cursor, /* in: cursor on the record to delete;
- cursor stays valid: if deletion succeeds,
- on function exit it points to the successor
- of the deleted record */
- mtr_t* mtr); /* in: mtr */
-/*****************************************************************
-Removes the record on which the tree cursor is positioned. Tries
-to compress the page if its fillfactor drops below a threshold
-or if it is the only page on the level. It is assumed that mtr holds
-an x-latch on the tree and on the cursor page. To avoid deadlocks,
-mtr must also own x-latches to brothers of page, if those brothers
-exist. */
-
-ibool
-btr_cur_pessimistic_delete(
-/*=======================*/
- /* out: TRUE if compression occurred */
- ulint* err, /* out: DB_SUCCESS or DB_OUT_OF_FILE_SPACE;
- the latter may occur because we may have
- to update node pointers on upper levels,
- and in the case of variable length keys
- these may actually grow in size */
- ibool has_reserved_extents, /* in: TRUE if the
- caller has already reserved enough free
- extents so that he knows that the operation
- will succeed */
- btr_cur_t* cursor, /* in: cursor on the record to delete;
- if compression does not occur, the cursor
- stays valid: it points to successor of
- deleted record on function exit */
- ibool in_rollback,/* in: TRUE if called in rollback */
- mtr_t* mtr); /* in: mtr */
-/***************************************************************
-Parses a redo log record of updating a record in-place. */
-
-byte*
-btr_cur_parse_update_in_place(
-/*==========================*/
- /* out: end of log record or NULL */
- byte* ptr, /* in: buffer */
- byte* end_ptr,/* in: buffer end */
- page_t* page, /* in: page or NULL */
- dict_index_t* index); /* in: index corresponding to page */
-/********************************************************************
-Parses the redo log record for delete marking or unmarking of a clustered
-index record. */
-
-byte*
-btr_cur_parse_del_mark_set_clust_rec(
-/*=================================*/
- /* out: end of log record or NULL */
- byte* ptr, /* in: buffer */
- byte* end_ptr,/* in: buffer end */
- dict_index_t* index, /* in: index corresponding to page */
- page_t* page); /* in: page or NULL */
-/********************************************************************
-Parses the redo log record for delete marking or unmarking of a secondary
-index record. */
-
-byte*
-btr_cur_parse_del_mark_set_sec_rec(
-/*===============================*/
- /* out: end of log record or NULL */
- byte* ptr, /* in: buffer */
- byte* end_ptr,/* in: buffer end */
- page_t* page); /* in: page or NULL */
-/***********************************************************************
-Estimates the number of rows in a given index range. */
-
-ib_longlong
-btr_estimate_n_rows_in_range(
-/*=========================*/
- /* out: estimated number of rows */
- dict_index_t* index, /* in: index */
- dtuple_t* tuple1, /* in: range start, may also be empty tuple */
- ulint mode1, /* in: search mode for range start */
- dtuple_t* tuple2, /* in: range end, may also be empty tuple */
- ulint mode2); /* in: search mode for range end */
-/***********************************************************************
-Estimates the number of different key values in a given index, for
-each n-column prefix of the index where n <= dict_index_get_n_unique(index).
-The estimates are stored in the array index->stat_n_diff_key_vals. */
-
-void
-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
-index tree. In purge only the owner of externally stored field is allowed
-to free the field. */
-
-void
-btr_cur_mark_extern_inherited_fields(
-/*=================================*/
- rec_t* rec, /* in: record in a clustered index */
- const ulint* offsets,/* in: array returned by rec_get_offsets() */
- upd_t* update, /* in: update vector */
- mtr_t* mtr); /* in: mtr */
-/***********************************************************************
-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. */
-
-void
-btr_cur_mark_dtuple_inherited_extern(
-/*=================================*/
- dtuple_t* entry, /* in: updated entry to be inserted to
- clustered index */
- ulint* ext_vec, /* in: array of extern fields in the
- original record */
- ulint n_ext_vec, /* in: number of elements in ext_vec */
- upd_t* update); /* in: update vector */
-/***********************************************************************
-Marks all extern fields in a dtuple as owned by the record. */
-
-void
-btr_cur_unmark_dtuple_extern_fields(
-/*================================*/
- dtuple_t* entry, /* in: clustered index entry */
- ulint* ext_vec, /* in: array of numbers of fields
- which have been stored externally */
- ulint n_ext_vec); /* in: number of elements in ext_vec */
-/***********************************************************************
-Stores the fields in big_rec_vec to the tablespace and puts pointers to
-them in rec. The fields are stored on pages allocated from leaf node
-file segment of the index tree. */
-
-ulint
-btr_store_big_rec_extern_fields(
-/*============================*/
- /* out: DB_SUCCESS or error */
- dict_index_t* index, /* in: index of rec; the index tree
- MUST be X-latched */
- rec_t* rec, /* in: record */
- const ulint* offsets, /* in: rec_get_offsets(rec, index);
- the "external storage" flags in offsets
- will not correspond to rec when
- this function returns */
- big_rec_t* big_rec_vec, /* in: vector containing fields
- to be stored externally */
- mtr_t* local_mtr); /* in: mtr containing the latch to
- rec and to the tree */
-/***********************************************************************
-Frees the space in an externally stored field to the file space
-management if the field in data is owned the externally stored field,
-in a rollback we may have the additional condition that the field must
-not be inherited. */
-
-void
-btr_free_externally_stored_field(
-/*=============================*/
- dict_index_t* index, /* in: index of the data, the index
- tree MUST be X-latched; if the tree
- height is 1, then also the root page
- must be X-latched! (this is relevant
- in the case this function is called
- from purge where 'data' is located on
- an undo log page, not an index
- page) */
- byte* data, /* in: internally stored data
- + reference to the externally
- stored part */
- ulint local_len, /* in: length of data */
- ibool do_not_free_inherited,/* in: TRUE if called in a
- rollback and we do not want to free
- inherited fields */
- mtr_t* local_mtr); /* in: mtr containing the latch to
- data an an X-latch to the index
- tree */
-/***************************************************************
-Frees the externally stored fields for a record. */
-
-void
-btr_rec_free_externally_stored_fields(
-/*==================================*/
- dict_index_t* index, /* in: index of the data, the index
- tree MUST be X-latched */
- rec_t* rec, /* in: record */
- const ulint* offsets,/* in: rec_get_offsets(rec, index) */
- ibool do_not_free_inherited,/* in: TRUE if called in a
- rollback and we do not want to free
- inherited fields */
- mtr_t* mtr); /* in: mini-transaction handle which contains
- an X-latch to record page and to the index
- tree */
-/***********************************************************************
-Copies an externally stored field of a record to mem heap. */
-
-byte*
-btr_rec_copy_externally_stored_field(
-/*=================================*/
- /* out: the field copied to heap */
- rec_t* rec, /* in: record */
- const ulint* offsets,/* in: array returned by rec_get_offsets() */
- ulint no, /* in: field number */
- ulint* len, /* out: length of the field */
- mem_heap_t* heap); /* in: mem heap */
-/***********************************************************************
-Copies an externally stored field of a record to mem heap. Parameter
-data contains a pointer to 'internally' stored part of the field:
-possibly some data, and the reference to the externally stored part in
-the last 20 bytes of data. */
-
-byte*
-btr_copy_externally_stored_field(
-/*=============================*/
- /* out: the whole field copied to heap */
- ulint* len, /* out: length of the whole field */
- byte* data, /* in: 'internally' stored part of the
- field containing also the reference to
- the external part */
- ulint local_len,/* in: length of data */
- mem_heap_t* heap); /* in: mem heap */
-/***********************************************************************
-Stores the positions of the fields marked as extern storage in the update
-vector, and also those fields who are marked as extern storage in rec
-and not mentioned in updated fields. We use this function to remember
-which fields we must mark as extern storage in a record inserted for an
-update. */
-
-ulint
-btr_push_update_extern_fields(
-/*==========================*/
- /* out: number of values stored in ext_vect */
- ulint* ext_vect,/* in: array of ulints, must be preallocated
- to have space for all fields in rec */
- const ulint* offsets,/* in: array returned by rec_get_offsets() */
- upd_t* update);/* in: update vector or NULL */
-
-
-/*######################################################################*/
-
-/* In the pessimistic delete, if the page data size drops below this
-limit, merging it to a neighbor is tried */
-
-#define BTR_CUR_PAGE_COMPRESS_LIMIT (UNIV_PAGE_SIZE / 2)
-
-/* A slot in the path array. We store here info on a search path down the
-tree. Each slot contains data on a single level of the tree. */
-
-typedef struct btr_path_struct btr_path_t;
-struct btr_path_struct{
- ulint nth_rec; /* index of the record
- where the page cursor stopped on
- this level (index in alphabetical
- order); value ULINT_UNDEFINED
- denotes array end */
- ulint n_recs; /* number of records on the page */
-};
-
-#define BTR_PATH_ARRAY_N_SLOTS 250 /* size of path array (in slots) */
-
-/* The tree cursor: the definition appears here only for the compiler
-to know struct size! */
-
-struct btr_cur_struct {
- dict_index_t* index; /* index where positioned */
- page_cur_t page_cur; /* page cursor */
- page_t* left_page; /* this field is used to store
- a pointer to the left neighbor
- page, in the cases
- BTR_SEARCH_PREV and
- BTR_MODIFY_PREV */
- /*------------------------------*/
- que_thr_t* thr; /* this field is only used when
- btr_cur_search_... is called for an
- index entry insertion: the calling
- query thread is passed here to be
- used in the insert buffer */
- /*------------------------------*/
- /* The following fields are used in btr_cur_search... to pass
- information: */
- ulint flag; /* BTR_CUR_HASH, BTR_CUR_HASH_FAIL,
- BTR_CUR_BINARY, or
- BTR_CUR_INSERT_TO_IBUF */
- ulint tree_height; /* Tree height if the search is done
- for a pessimistic insert or update
- operation */
- ulint up_match; /* If the search mode was PAGE_CUR_LE,
- the number of matched fields to the
- the first user record to the right of
- the cursor record after
- btr_cur_search_...;
- for the mode PAGE_CUR_GE, the matched
- fields to the first user record AT THE
- CURSOR or to the right of it;
- NOTE that the up_match and low_match
- values may exceed the correct values
- for comparison to the adjacent user
- record if that record is on a
- different leaf page! (See the note in
- row_ins_duplicate_key.) */
- ulint up_bytes; /* number of matched bytes to the
- right at the time cursor positioned;
- only used internally in searches: not
- defined after the search */
- ulint low_match; /* if search mode was PAGE_CUR_LE,
- the number of matched fields to the
- first user record AT THE CURSOR or
- to the left of it after
- btr_cur_search_...;
- NOT defined for PAGE_CUR_GE or any
- other search modes; see also the NOTE
- in up_match! */
- ulint low_bytes; /* number of matched bytes to the
- right at the time cursor positioned;
- only used internally in searches: not
- defined after the search */
- ulint n_fields; /* prefix length used in a hash
- search if hash_node != NULL */
- ulint n_bytes; /* hash prefix bytes if hash_node !=
- NULL */
- ulint fold; /* fold value used in the search if
- flag is BTR_CUR_HASH */
- /*------------------------------*/
- btr_path_t* path_arr; /* in estimating the number of
- rows in range, we store in this array
- information of the path through
- the tree */
-};
-
-/* Values for the flag documenting the used search method */
-#define BTR_CUR_HASH 1 /* successful shortcut using the hash
- index */
-#define BTR_CUR_HASH_FAIL 2 /* failure using hash, success using
- binary search: the misleading hash
- reference is stored in the field
- hash_node, and might be necessary to
- update */
-#define BTR_CUR_BINARY 3 /* success using the binary search */
-#define BTR_CUR_INSERT_TO_IBUF 4 /* performed the intended insert to
- the insert buffer */
-
-/* If pessimistic delete fails because of lack of file space,
-there is still a good change of success a little later: try this many times,
-and sleep this many microseconds in between */
-#define BTR_CUR_RETRY_DELETE_N_TIMES 100
-#define BTR_CUR_RETRY_SLEEP_TIME 50000
-
-/* The reference in a field for which data is stored on a different page.
-The reference is at the end of the 'locally' stored part of the field.
-'Locally' means storage in the index record.
-We store locally a long enough prefix of each column so that we can determine
-the ordering parts of each index record without looking into the externally
-stored part. */
-
-/*--------------------------------------*/
-#define BTR_EXTERN_SPACE_ID 0 /* space id where stored */
-#define BTR_EXTERN_PAGE_NO 4 /* page no where stored */
-#define BTR_EXTERN_OFFSET 8 /* offset of BLOB header
- on that page */
-#define BTR_EXTERN_LEN 12 /* 8 bytes containing the
- length of the externally
- stored part of the BLOB.
- The 2 highest bits are
- reserved to the flags below. */
-/*--------------------------------------*/
-#define BTR_EXTERN_FIELD_REF_SIZE 20
-
-/* The highest bit of BTR_EXTERN_LEN (i.e., the highest bit of the byte
-at lowest address) is set to 1 if this field does not 'own' the externally
-stored field; only the owner field is allowed to free the field in purge!
-If the 2nd highest bit is 1 then it means that the externally stored field
-was inherited from an earlier version of the row. In rollback we are not
-allowed to free an inherited external field. */
-
-#define BTR_EXTERN_OWNER_FLAG 128
-#define BTR_EXTERN_INHERITED_FLAG 64
-
-extern ulint btr_cur_n_non_sea;
-extern ulint btr_cur_n_sea;
-extern ulint btr_cur_n_non_sea_old;
-extern ulint btr_cur_n_sea_old;
-
-#ifndef UNIV_NONINL
-#include "btr0cur.ic"
-#endif
-
-#endif
diff --git a/storage/innobase/include/btr0cur.ic b/storage/innobase/include/btr0cur.ic
deleted file mode 100644
index bd2c46eb734..00000000000
--- a/storage/innobase/include/btr0cur.ic
+++ /dev/null
@@ -1,154 +0,0 @@
-/******************************************************
-The index tree cursor
-
-(c) 1994-1996 Innobase Oy
-
-Created 10/16/1994 Heikki Tuuri
-*******************************************************/
-
-#include "btr0btr.h"
-
-/*************************************************************
-Returns the page cursor component of a tree cursor. */
-UNIV_INLINE
-page_cur_t*
-btr_cur_get_page_cur(
-/*=================*/
- /* out: pointer to page cursor component */
- btr_cur_t* cursor) /* in: tree cursor */
-{
- return(&(cursor->page_cur));
-}
-
-/*************************************************************
-Returns the record pointer of a tree cursor. */
-UNIV_INLINE
-rec_t*
-btr_cur_get_rec(
-/*============*/
- /* out: pointer to record */
- btr_cur_t* cursor) /* in: tree cursor */
-{
- return(page_cur_get_rec(&(cursor->page_cur)));
-}
-
-/*************************************************************
-Invalidates a tree cursor by setting record pointer to NULL. */
-UNIV_INLINE
-void
-btr_cur_invalidate(
-/*===============*/
- btr_cur_t* cursor) /* in: tree cursor */
-{
- page_cur_invalidate(&(cursor->page_cur));
-}
-
-/*************************************************************
-Returns the page of a tree cursor. */
-UNIV_INLINE
-page_t*
-btr_cur_get_page(
-/*=============*/
- /* out: pointer to page */
- btr_cur_t* cursor) /* in: tree cursor */
-{
- return(buf_frame_align(page_cur_get_rec(&(cursor->page_cur))));
-}
-
-/*************************************************************
-Returns the index of a cursor. */
-UNIV_INLINE
-dict_index_t*
-btr_cur_get_index(
-/*==============*/
- /* out: index */
- btr_cur_t* cursor) /* in: B-tree cursor */
-{
- return(cursor->index);
-}
-
-/*************************************************************
-Positions a tree cursor at a given record. */
-UNIV_INLINE
-void
-btr_cur_position(
-/*=============*/
- dict_index_t* index, /* in: index */
- rec_t* rec, /* in: record in tree */
- btr_cur_t* cursor) /* in: cursor */
-{
- page_cur_position(rec, btr_cur_get_page_cur(cursor));
-
- cursor->index = index;
-}
-
-/*************************************************************************
-Checks if compressing an index page where a btr cursor is placed makes
-sense. */
-UNIV_INLINE
-ibool
-btr_cur_compress_recommendation(
-/*============================*/
- /* out: TRUE if compression is recommended */
- btr_cur_t* cursor, /* in: btr cursor */
- mtr_t* mtr) /* in: mtr */
-{
- page_t* page;
-
- ut_ad(mtr_memo_contains(mtr, buf_block_align(btr_cur_get_rec(cursor)),
- MTR_MEMO_PAGE_X_FIX));
-
- page = btr_cur_get_page(cursor);
-
- if ((page_get_data_size(page) < BTR_CUR_PAGE_COMPRESS_LIMIT)
- || ((btr_page_get_next(page, mtr) == FIL_NULL)
- && (btr_page_get_prev(page, mtr) == FIL_NULL))) {
-
- /* The page fillfactor has dropped below a predefined
- minimum value OR the level in the B-tree contains just
- one page: we recommend compression if this is not the
- root page. */
-
- return(dict_index_get_page(cursor->index)
- != buf_frame_get_page_no(page));
- }
-
- return(FALSE);
-}
-
-/*************************************************************************
-Checks if the record on which the cursor is placed can be deleted without
-making tree compression necessary (or, recommended). */
-UNIV_INLINE
-ibool
-btr_cur_can_delete_without_compress(
-/*================================*/
- /* out: TRUE if can be deleted without
- recommended compression */
- btr_cur_t* cursor, /* in: btr cursor */
- ulint rec_size,/* in: rec_get_size(btr_cur_get_rec(cursor))*/
- mtr_t* mtr) /* in: mtr */
-{
- page_t* page;
-
- ut_ad(mtr_memo_contains(mtr, buf_block_align(btr_cur_get_rec(cursor)),
- MTR_MEMO_PAGE_X_FIX));
-
- page = btr_cur_get_page(cursor);
-
- if ((page_get_data_size(page) - rec_size < BTR_CUR_PAGE_COMPRESS_LIMIT)
- || ((btr_page_get_next(page, mtr) == FIL_NULL)
- && (btr_page_get_prev(page, mtr) == FIL_NULL))
- || (page_get_n_recs(page) < 2)) {
-
- /* The page fillfactor will drop below a predefined
- minimum value, OR the level in the B-tree contains just
- one page, OR the page will become empty: we recommend
- compression if this is not the root page. */
-
- return(dict_index_get_page(cursor->index)
- == buf_frame_get_page_no(page));
- }
-
- return(TRUE);
-}
diff --git a/storage/innobase/include/btr0sea.ic b/storage/innobase/include/btr0sea.ic
deleted file mode 100644
index f4e33027c25..00000000000
--- a/storage/innobase/include/btr0sea.ic
+++ /dev/null
@@ -1,67 +0,0 @@
-/************************************************************************
-The index tree adaptive search
-
-(c) 1996 Innobase Oy
-
-Created 2/17/1996 Heikki Tuuri
-*************************************************************************/
-
-#include "dict0mem.h"
-#include "btr0cur.h"
-#include "buf0buf.h"
-
-/*************************************************************************
-Updates the search info. */
-
-void
-btr_search_info_update_slow(
-/*========================*/
- btr_search_t* info, /* in/out: search info */
- btr_cur_t* cursor);/* in: cursor which was just positioned */
-
-/************************************************************************
-Returns search info for an index. */
-UNIV_INLINE
-btr_search_t*
-btr_search_get_info(
-/*================*/
- /* out: search info; search mutex reserved */
- dict_index_t* index) /* in: index */
-{
- ut_ad(index);
-
- return(index->search_info);
-}
-
-/*************************************************************************
-Updates the search info. */
-UNIV_INLINE
-void
-btr_search_info_update(
-/*===================*/
- dict_index_t* index, /* in: index of the cursor */
- btr_cur_t* cursor) /* in: cursor which was just positioned */
-{
- btr_search_t* info;
-
-#ifdef UNIV_SYNC_DEBUG
- ut_ad(!rw_lock_own(&btr_search_latch, RW_LOCK_SHARED));
- ut_ad(!rw_lock_own(&btr_search_latch, RW_LOCK_EX));
-#endif /* UNIV_SYNC_DEBUG */
-
- info = btr_search_get_info(index);
-
- info->hash_analysis++;
-
- if (info->hash_analysis < BTR_SEARCH_HASH_ANALYSIS) {
-
- /* Do nothing */
-
- return;
-
- }
-
- ut_ad(cursor->flag != BTR_CUR_HASH);
-
- btr_search_info_update_slow(info, cursor);
-}
diff --git a/storage/innobase/include/btr0types.h b/storage/innobase/include/btr0types.h
deleted file mode 100644
index 8fa0bf0602d..00000000000
--- a/storage/innobase/include/btr0types.h
+++ /dev/null
@@ -1,21 +0,0 @@
-/************************************************************************
-The index tree general types
-
-(c) 1996 Innobase Oy
-
-Created 2/17/1996 Heikki Tuuri
-*************************************************************************/
-
-#ifndef btr0types_h
-#define btr0types_h
-
-#include "univ.i"
-
-#include "rem0types.h"
-#include "page0types.h"
-
-typedef struct btr_pcur_struct btr_pcur_t;
-typedef struct btr_cur_struct btr_cur_t;
-typedef struct btr_search_struct btr_search_t;
-
-#endif
diff --git a/storage/innobase/include/buf0buf.h b/storage/innobase/include/buf0buf.h
deleted file mode 100644
index 3e8972d9182..00000000000
--- a/storage/innobase/include/buf0buf.h
+++ /dev/null
@@ -1,1074 +0,0 @@
-/* Innobase relational database engine; Copyright (C) 2001 Innobase Oy
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License 2
- as published by the Free Software Foundation in June 1991.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License 2
- along with this program (in file COPYING); if not, write to the Free
- Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
-/******************************************************
-The database buffer pool high-level routines
-
-(c) 1995 Innobase Oy
-
-Created 11/5/1995 Heikki Tuuri
-*******************************************************/
-
-#ifndef buf0buf_h
-#define buf0buf_h
-
-#include "univ.i"
-#include "fil0fil.h"
-#include "mtr0types.h"
-#include "buf0types.h"
-#include "sync0rw.h"
-#include "hash0hash.h"
-#include "ut0byte.h"
-#include "os0proc.h"
-
-/* Flags for flush types */
-#define BUF_FLUSH_LRU 1
-#define BUF_FLUSH_SINGLE_PAGE 2
-#define BUF_FLUSH_LIST 3 /* An array in the pool struct
- has size BUF_FLUSH_LIST + 1: if you
- add more flush types, put them in
- the middle! */
-/* Modes for buf_page_get_gen */
-#define BUF_GET 10 /* get always */
-#define BUF_GET_IF_IN_POOL 11 /* get if in pool */
-#define BUF_GET_NOWAIT 12 /* get if can set the latch without
- waiting */
-#define BUF_GET_NO_LATCH 14 /* get and bufferfix, but set no latch;
- we have separated this case, because
- it is error-prone programming not to
- set a latch, and it should be used
- with care */
-/* Modes for buf_page_get_known_nowait */
-#define BUF_MAKE_YOUNG 51
-#define BUF_KEEP_OLD 52
-/* Magic value to use instead of checksums when they are disabled */
-#define BUF_NO_CHECKSUM_MAGIC 0xDEADBEEFUL
-
-extern buf_pool_t* buf_pool; /* The buffer pool of the database */
-#ifdef UNIV_DEBUG
-extern ibool buf_debug_prints;/* If this is set TRUE, the program
- prints info whenever read or flush
- occurs */
-#endif /* UNIV_DEBUG */
-extern ulint srv_buf_pool_write_requests; /* variable to count write request
- issued */
-
-/************************************************************************
-Creates the buffer pool. */
-
-buf_pool_t*
-buf_pool_init(
-/*==========*/
- /* out, own: buf_pool object, NULL if not
- enough memory or error */
- ulint max_size, /* in: maximum size of the buf_pool in
- blocks */
- ulint curr_size, /* in: current size to use, must be <=
- max_size, currently must be equal to
- max_size */
- ulint n_frames); /* in: number of frames; if AWE is used,
- this is the size of the address space window
- where physical memory pages are mapped; if
- AWE is not used then this must be the same
- as max_size */
-/*************************************************************************
-Gets the current size of buffer buf_pool in bytes. In the case of AWE, the
-size of AWE window (= the frames). */
-UNIV_INLINE
-ulint
-buf_pool_get_curr_size(void);
-/*========================*/
- /* out: size in bytes */
-/*************************************************************************
-Gets the maximum size of buffer pool in bytes. In the case of AWE, the
-size of AWE window (= the frames). */
-UNIV_INLINE
-ulint
-buf_pool_get_max_size(void);
-/*=======================*/
- /* out: size in bytes */
-/************************************************************************
-Gets the smallest oldest_modification lsn for any page in the pool. Returns
-ut_dulint_zero if all modified pages have been flushed to disk. */
-UNIV_INLINE
-dulint
-buf_pool_get_oldest_modification(void);
-/*==================================*/
- /* out: oldest modification in pool,
- ut_dulint_zero if none */
-/*************************************************************************
-Allocates a buffer frame. */
-
-buf_frame_t*
-buf_frame_alloc(void);
-/*==================*/
- /* out: buffer frame */
-/*************************************************************************
-Frees a buffer frame which does not contain a file page. */
-
-void
-buf_frame_free(
-/*===========*/
- buf_frame_t* frame); /* in: buffer frame */
-/*************************************************************************
-Copies contents of a buffer frame to a given buffer. */
-UNIV_INLINE
-byte*
-buf_frame_copy(
-/*===========*/
- /* out: buf */
- byte* buf, /* in: buffer to copy to */
- buf_frame_t* frame); /* in: buffer frame */
-/******************************************************************
-NOTE! The following macros should be used instead of buf_page_get_gen,
-to improve debugging. Only values RW_S_LATCH and RW_X_LATCH are allowed
-in LA! */
-#define buf_page_get(SP, OF, LA, MTR) buf_page_get_gen(\
- SP, OF, LA, NULL,\
- BUF_GET, __FILE__, __LINE__, MTR)
-/******************************************************************
-Use these macros to bufferfix a page with no latching. Remember not to
-read the contents of the page unless you know it is safe. Do not modify
-the contents of the page! We have separated this case, because it is
-error-prone programming not to set a latch, and it should be used
-with care. */
-#define buf_page_get_with_no_latch(SP, OF, MTR) buf_page_get_gen(\
- SP, OF, RW_NO_LATCH, NULL,\
- BUF_GET_NO_LATCH, __FILE__, __LINE__, MTR)
-/******************************************************************
-NOTE! The following macros should be used instead of buf_page_get_gen, to
-improve debugging. Only values RW_S_LATCH and RW_X_LATCH are allowed as LA! */
-#define buf_page_get_nowait(SP, OF, LA, MTR) buf_page_get_gen(\
- SP, OF, LA, NULL,\
- BUF_GET_NOWAIT, __FILE__, __LINE__, MTR)
-/******************************************************************
-NOTE! The following macros should be used instead of
-buf_page_optimistic_get_func, to improve debugging. Only values RW_S_LATCH and
-RW_X_LATCH are allowed as LA! */
-#define buf_page_optimistic_get(LA, BL, G, MC, MTR) \
- buf_page_optimistic_get_func(LA, BL, G, MC, __FILE__, __LINE__, MTR)
-/************************************************************************
-This is the general function used to get optimistic access to a database
-page. */
-
-ibool
-buf_page_optimistic_get_func(
-/*=========================*/
- /* out: TRUE if success */
- ulint rw_latch,/* in: RW_S_LATCH, RW_X_LATCH */
- buf_block_t* block, /* in: guessed block */
- buf_frame_t* guess, /* in: guessed frame; note that AWE may move
- frames */
- dulint modify_clock,/* in: modify clock value if mode is
- ..._GUESS_ON_CLOCK */
- const char* file, /* in: file name */
- ulint line, /* in: line where called */
- mtr_t* mtr); /* in: mini-transaction */
-/************************************************************************
-Tries to get the page, but if file io is required, releases all latches
-in mtr down to the given savepoint. If io is required, this function
-retrieves the page to buffer buf_pool, but does not bufferfix it or latch
-it. */
-UNIV_INLINE
-buf_frame_t*
-buf_page_get_release_on_io(
-/*=======================*/
- /* out: pointer to the frame, or NULL
- if not in buffer buf_pool */
- ulint space, /* in: space id */
- ulint offset, /* in: offset of the page within space
- in units of a page */
- buf_frame_t* guess, /* in: guessed frame or NULL */
- ulint rw_latch, /* in: RW_X_LATCH, RW_S_LATCH,
- or RW_NO_LATCH */
- ulint savepoint, /* in: mtr savepoint */
- mtr_t* mtr); /* in: mtr */
-/************************************************************************
-This is used to get access to a known database page, when no waiting can be
-done. */
-
-ibool
-buf_page_get_known_nowait(
-/*======================*/
- /* out: TRUE if success */
- ulint rw_latch,/* in: RW_S_LATCH, RW_X_LATCH */
- buf_frame_t* guess, /* in: the known page frame */
- ulint mode, /* in: BUF_MAKE_YOUNG or BUF_KEEP_OLD */
- const char* file, /* in: file name */
- ulint line, /* in: line where called */
- mtr_t* mtr); /* in: mini-transaction */
-/************************************************************************
-This is the general function used to get access to a database page. */
-
-buf_frame_t*
-buf_page_get_gen(
-/*=============*/
- /* out: pointer to the frame or NULL */
- ulint space, /* in: space id */
- ulint offset, /* in: page number */
- ulint rw_latch,/* in: RW_S_LATCH, RW_X_LATCH, RW_NO_LATCH */
- buf_frame_t* guess, /* in: guessed frame or NULL */
- ulint mode, /* in: BUF_GET, BUF_GET_IF_IN_POOL,
- BUF_GET_NO_LATCH */
- const char* file, /* in: file name */
- ulint line, /* in: line where called */
- mtr_t* mtr); /* in: mini-transaction */
-/************************************************************************
-Initializes a page to the buffer buf_pool. The page is usually not read
-from a file even if it cannot be found in the buffer buf_pool. This is one
-of the functions which perform to a block a state transition NOT_USED =>
-FILE_PAGE (the other is buf_page_init_for_read above). */
-
-buf_frame_t*
-buf_page_create(
-/*============*/
- /* out: pointer to the frame, page bufferfixed */
- ulint space, /* in: space id */
- ulint offset, /* in: offset of the page within space in units of
- a page */
- mtr_t* mtr); /* in: mini-transaction handle */
-/************************************************************************
-Inits a page to the buffer buf_pool, for use in ibbackup --restore. */
-
-void
-buf_page_init_for_backup_restore(
-/*=============================*/
- ulint space, /* in: space id */
- ulint offset, /* in: offset of the page within space
- in units of a page */
- buf_block_t* block); /* in: block to init */
-/************************************************************************
-Decrements the bufferfix count of a buffer control block and releases
-a latch, if specified. */
-UNIV_INLINE
-void
-buf_page_release(
-/*=============*/
- buf_block_t* block, /* in: buffer block */
- ulint rw_latch, /* in: RW_S_LATCH, RW_X_LATCH,
- RW_NO_LATCH */
- mtr_t* mtr); /* in: mtr */
-/************************************************************************
-Moves a page to the start of the buffer pool LRU list. This high-level
-function can be used to prevent an important page from from slipping out of
-the buffer pool. */
-
-void
-buf_page_make_young(
-/*================*/
- buf_frame_t* frame); /* in: buffer frame of a file page */
-/************************************************************************
-Returns TRUE if the page can be found in the buffer pool hash table. NOTE
-that it is possible that the page is not yet read from disk, though. */
-
-ibool
-buf_page_peek(
-/*==========*/
- /* out: TRUE if found from page hash table,
- NOTE that the page is not necessarily yet read
- from disk! */
- ulint space, /* in: space id */
- ulint offset);/* in: page number */
-/************************************************************************
-Returns the buffer control block if the page can be found in the buffer
-pool. NOTE that it is possible that the page is not yet read
-from disk, though. This is a very low-level function: use with care! */
-
-buf_block_t*
-buf_page_peek_block(
-/*================*/
- /* out: control block if found from page hash table,
- otherwise NULL; NOTE that the page is not necessarily
- yet read from disk! */
- ulint space, /* in: space id */
- ulint offset);/* in: page number */
-/************************************************************************
-Resets the check_index_page_at_flush field of a page if found in the buffer
-pool. */
-
-void
-buf_reset_check_index_page_at_flush(
-/*================================*/
- ulint space, /* in: space id */
- ulint offset);/* in: page number */
-/************************************************************************
-Sets file_page_was_freed TRUE if the page is found in the buffer pool.
-This function should be called when we free a file page and want the
-debug version to check that it is not accessed any more unless
-reallocated. */
-
-buf_block_t*
-buf_page_set_file_page_was_freed(
-/*=============================*/
- /* out: control block if found from page hash table,
- otherwise NULL */
- ulint space, /* in: space id */
- ulint offset); /* in: page number */
-/************************************************************************
-Sets file_page_was_freed FALSE if the page is found in the buffer pool.
-This function should be called when we free a file page and want the
-debug version to check that it is not accessed any more unless
-reallocated. */
-
-buf_block_t*
-buf_page_reset_file_page_was_freed(
-/*===============================*/
- /* out: control block if found from page hash table,
- otherwise NULL */
- ulint space, /* in: space id */
- ulint offset); /* in: page number */
-/************************************************************************
-Recommends a move of a block to the start of the LRU list if there is danger
-of dropping from the buffer pool. NOTE: does not reserve the buffer pool
-mutex. */
-UNIV_INLINE
-ibool
-buf_block_peek_if_too_old(
-/*======================*/
- /* out: TRUE if should be made younger */
- buf_block_t* block); /* 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
-pool if it is found there. */
-
-ibool
-buf_page_peek_if_search_hashed(
-/*===========================*/
- /* out: TRUE if page hash index is built in search
- system */
- ulint space, /* in: space id */
- ulint offset);/* in: page number */
-/************************************************************************
-Gets the youngest modification log sequence number for a frame.
-Returns zero if not file page or no modification occurred yet. */
-UNIV_INLINE
-dulint
-buf_frame_get_newest_modification(
-/*==============================*/
- /* out: newest modification to page */
- buf_frame_t* frame); /* in: pointer to a frame */
-/************************************************************************
-Increments the modify clock of a frame by 1. The caller must (1) own the
-pool mutex and block bufferfix count has to be zero, (2) or own an x-lock
-on the block. */
-UNIV_INLINE
-dulint
-buf_frame_modify_clock_inc(
-/*=======================*/
- /* out: new value */
- buf_frame_t* frame); /* in: pointer to a frame */
-/************************************************************************
-Increments the modify clock of a frame by 1. The caller must (1) own the
-buf_pool mutex and block bufferfix count has to be zero, (2) or own an x-lock
-on the block. */
-UNIV_INLINE
-dulint
-buf_block_modify_clock_inc(
-/*=======================*/
- /* out: new value */
- buf_block_t* block); /* in: block */
-/************************************************************************
-Returns the value of the modify clock. The caller must have an s-lock
-or x-lock on the block. */
-UNIV_INLINE
-dulint
-buf_block_get_modify_clock(
-/*=======================*/
- /* out: value */
- buf_block_t* block); /* in: block */
-/************************************************************************
-Calculates a page checksum which is stored to the page when it is written
-to a file. Note that we must be careful to calculate the same value
-on 32-bit and 64-bit architectures. */
-
-ulint
-buf_calc_page_new_checksum(
-/*=======================*/
- /* out: checksum */
- byte* page); /* in: buffer page */
-/************************************************************************
-In versions < 4.0.14 and < 4.1.1 there was a bug that the checksum only
-looked at the first few bytes of the page. This calculates that old
-checksum.
-NOTE: we must first store the new formula checksum to
-FIL_PAGE_SPACE_OR_CHKSUM before calculating and storing this old checksum
-because this takes that field as an input! */
-
-ulint
-buf_calc_page_old_checksum(
-/*=======================*/
- /* out: checksum */
- byte* page); /* in: buffer page */
-/************************************************************************
-Checks if a page is corrupt. */
-
-ibool
-buf_page_is_corrupted(
-/*==================*/
- /* out: TRUE if corrupted */
- byte* read_buf); /* in: a database page */
-/**************************************************************************
-Gets the page number of a pointer pointing within a buffer frame containing
-a file page. */
-UNIV_INLINE
-ulint
-buf_frame_get_page_no(
-/*==================*/
- /* out: page number */
- byte* ptr); /* in: pointer to within a buffer frame */
-/**************************************************************************
-Gets the space id of a pointer pointing within a buffer frame containing a
-file page. */
-UNIV_INLINE
-ulint
-buf_frame_get_space_id(
-/*===================*/
- /* out: space id */
- byte* ptr); /* in: pointer to within a buffer frame */
-/**************************************************************************
-Gets the space id, page offset, and byte offset within page of a
-pointer pointing to a buffer frame containing a file page. */
-UNIV_INLINE
-void
-buf_ptr_get_fsp_addr(
-/*=================*/
- byte* ptr, /* in: pointer to a buffer frame */
- ulint* space, /* out: space id */
- fil_addr_t* addr); /* out: page offset and byte offset */
-/**************************************************************************
-Gets the hash value of the page the pointer is pointing to. This can be used
-in searches in the lock hash table. */
-UNIV_INLINE
-ulint
-buf_frame_get_lock_hash_val(
-/*========================*/
- /* out: lock hash value */
- byte* ptr); /* in: pointer to within a buffer frame */
-/**************************************************************************
-Gets the mutex number protecting the page record lock hash chain in the lock
-table. */
-UNIV_INLINE
-mutex_t*
-buf_frame_get_mutex(
-/*================*/
- /* out: mutex */
- byte* ptr); /* in: pointer to within a buffer frame */
-/***********************************************************************
-Gets the frame the pointer is pointing to. */
-UNIV_INLINE
-buf_frame_t*
-buf_frame_align(
-/*============*/
- /* out: pointer to frame */
- byte* ptr); /* in: pointer to a frame */
-/***********************************************************************
-Checks if a pointer points to the block array of the buffer pool (blocks, not
-the frames). */
-UNIV_INLINE
-ibool
-buf_pool_is_block(
-/*==============*/
- /* out: TRUE if pointer to block */
- void* ptr); /* in: pointer to memory */
-#ifdef UNIV_DEBUG
-/*************************************************************************
-Validates the buffer pool data structure. */
-
-ibool
-buf_validate(void);
-/*==============*/
-/*************************************************************************
-Prints info of the buffer pool data structure. */
-
-void
-buf_print(void);
-/*============*/
-
-/*************************************************************************
-Returns the number of latched pages in the buffer pool. */
-
-ulint
-buf_get_latched_pages_number(void);
-/*==============================*/
-#endif /* UNIV_DEBUG */
-
-/************************************************************************
-Prints a page to stderr. */
-
-void
-buf_page_print(
-/*===========*/
- byte* read_buf); /* in: a database page */
-
-/*************************************************************************
-Returns the number of pending buf pool ios. */
-
-ulint
-buf_get_n_pending_ios(void);
-/*=======================*/
-/*************************************************************************
-Prints info of the buffer i/o. */
-
-void
-buf_print_io(
-/*=========*/
- FILE* file); /* in: file where to print */
-/*************************************************************************
-Returns the ratio in percents of modified pages in the buffer pool /
-database pages in the buffer pool. */
-
-ulint
-buf_get_modified_ratio_pct(void);
-/*============================*/
-/**************************************************************************
-Refreshes the statistics used to print per-second averages. */
-
-void
-buf_refresh_io_stats(void);
-/*======================*/
-/*************************************************************************
-Checks that all file pages in the buffer are in a replaceable state. */
-
-ibool
-buf_all_freed(void);
-/*===============*/
-/*************************************************************************
-Checks that there currently are no pending i/o-operations for the buffer
-pool. */
-
-ibool
-buf_pool_check_no_pending_io(void);
-/*==============================*/
- /* out: TRUE if there is no pending i/o */
-/*************************************************************************
-Invalidates the file pages in the buffer pool when an archive recovery is
-completed. All the file pages buffered must be in a replaceable state when
-this function is called: not latched and not modified. */
-
-void
-buf_pool_invalidate(void);
-/*=====================*/
-
-/*========================================================================
---------------------------- LOWER LEVEL ROUTINES -------------------------
-=========================================================================*/
-
-/************************************************************************
-Maps the page of block to a frame, if not mapped yet. Unmaps some page
-from the end of the awe_LRU_free_mapped. */
-
-void
-buf_awe_map_page_to_frame(
-/*======================*/
- buf_block_t* block, /* in: block whose page should be
- mapped to a frame */
- ibool add_to_mapped_list);/* in: TRUE if we in the case
- we need to map the page should also
- add the block to the
- awe_LRU_free_mapped list */
-#ifdef UNIV_SYNC_DEBUG
-/*************************************************************************
-Adds latch level info for the rw-lock protecting the buffer frame. This
-should be called in the debug version after a successful latching of a
-page if we know the latching order level of the acquired latch. */
-UNIV_INLINE
-void
-buf_page_dbg_add_level(
-/*===================*/
- buf_frame_t* frame, /* in: buffer page where we have acquired
- a latch */
- ulint level); /* in: latching order level */
-#endif /* UNIV_SYNC_DEBUG */
-/*************************************************************************
-Gets a pointer to the memory frame of a block. */
-UNIV_INLINE
-buf_frame_t*
-buf_block_get_frame(
-/*================*/
- /* out: pointer to the frame */
- buf_block_t* block); /* in: pointer to the control block */
-/*************************************************************************
-Gets the space id of a block. */
-UNIV_INLINE
-ulint
-buf_block_get_space(
-/*================*/
- /* out: space id */
- buf_block_t* block); /* in: pointer to the control block */
-/*************************************************************************
-Gets the page number of a block. */
-UNIV_INLINE
-ulint
-buf_block_get_page_no(
-/*==================*/
- /* out: page number */
- buf_block_t* block); /* in: pointer to the control block */
-/***********************************************************************
-Gets the block to whose frame the pointer is pointing to. */
-UNIV_INLINE
-buf_block_t*
-buf_block_align(
-/*============*/
- /* out: pointer to block */
- byte* ptr); /* in: pointer to a frame */
-/************************************************************************
-This function is used to get info if there is an io operation
-going on on a buffer page. */
-UNIV_INLINE
-ibool
-buf_page_io_query(
-/*==============*/
- /* out: TRUE if io going on */
- buf_block_t* block); /* in: pool block, must be bufferfixed */
-/***********************************************************************
-Accessor function for block array. */
-UNIV_INLINE
-buf_block_t*
-buf_pool_get_nth_block(
-/*===================*/
- /* out: pointer to block */
- buf_pool_t* pool, /* in: pool */
- ulint i); /* in: index of the block */
-/************************************************************************
-Function which inits a page for read to the buffer buf_pool. If the page is
-(1) already in buf_pool, or
-(2) if we specify to read only ibuf pages and the page is not an ibuf page, or
-(3) if the space is deleted or being deleted,
-then this function does nothing.
-Sets the io_fix flag to BUF_IO_READ and sets a non-recursive exclusive lock
-on the buffer frame. The io-handler must take care that the flag is cleared
-and the lock released later. This is one of the functions which perform the
-state transition NOT_USED => FILE_PAGE to a block (the other is
-buf_page_create). */
-
-buf_block_t*
-buf_page_init_for_read(
-/*===================*/
- /* out: pointer to the block or NULL */
- ulint* err, /* out: DB_SUCCESS or DB_TABLESPACE_DELETED */
- ulint mode, /* in: BUF_READ_IBUF_PAGES_ONLY, ... */
- ulint space, /* in: space id */
- ib_longlong tablespace_version,/* in: prevents reading from a wrong
- version of the tablespace in case we have done
- DISCARD + IMPORT */
- ulint offset);/* in: page number */
-/************************************************************************
-Completes an asynchronous read or write request of a file page to or from
-the buffer pool. */
-
-void
-buf_page_io_complete(
-/*=================*/
- buf_block_t* block); /* in: pointer to the block in question */
-/************************************************************************
-Calculates a folded value of a file page address to use in the page hash
-table. */
-UNIV_INLINE
-ulint
-buf_page_address_fold(
-/*==================*/
- /* out: the folded value */
- ulint space, /* in: space id */
- ulint offset);/* in: offset of the page within space */
-/**********************************************************************
-Returns the control block of a file page, NULL if not found. */
-UNIV_INLINE
-buf_block_t*
-buf_page_hash_get(
-/*==============*/
- /* out: block, NULL if not found */
- ulint space, /* in: space id */
- ulint offset);/* in: offset of the page within space */
-/***********************************************************************
-Increments the pool clock by one and returns its new value. Remember that
-in the 32 bit version the clock wraps around at 4 billion! */
-UNIV_INLINE
-ulint
-buf_pool_clock_tic(void);
-/*====================*/
- /* out: new clock value */
-/*************************************************************************
-Gets the current length of the free list of buffer blocks. */
-
-ulint
-buf_get_free_list_len(void);
-/*=======================*/
-
-
-
-/* The buffer control block structure */
-
-struct buf_block_struct{
-
- /* 1. General fields */
-
- ulint magic_n; /* magic number to check */
- ulint state; /* state of the control block:
- BUF_BLOCK_NOT_USED, ...; changing
- this is only allowed when a thread
- has BOTH the buffer pool mutex AND
- block->mutex locked */
- byte* frame; /* pointer to buffer frame which
- is of size UNIV_PAGE_SIZE, and
- aligned to an address divisible by
- UNIV_PAGE_SIZE; if AWE is used, this
- will be NULL for the pages which are
- currently not mapped into the virtual
- address space window of the buffer
- pool */
- os_awe_t* awe_info; /* if AWE is used, then an array of
- awe page infos for
- UNIV_PAGE_SIZE / OS_AWE_X86_PAGE_SIZE
- (normally = 4) physical memory
- pages; otherwise NULL */
- ulint space; /* space id of the page */
- ulint offset; /* page number within the space */
- ulint lock_hash_val; /* hashed value of the page address
- in the record lock hash table */
- mutex_t mutex; /* mutex protecting this block:
- state (also protected by the buffer
- pool mutex), io_fix, buf_fix_count,
- and accessed; we introduce this new
- mutex in InnoDB-5.1 to relieve
- contention on the buffer pool mutex */
- rw_lock_t lock; /* read-write lock of the buffer
- frame */
- buf_block_t* hash; /* node used in chaining to the page
- hash table */
- ibool check_index_page_at_flush;
- /* TRUE if we know that this is
- an index page, and want the database
- to check its consistency before flush;
- note that there may be pages in the
- buffer pool which are index pages,
- but this flag is not set because
- we do not keep track of all pages */
- /* 2. Page flushing fields */
-
- UT_LIST_NODE_T(buf_block_t) flush_list;
- /* node of the modified, not yet
- flushed blocks list */
- dulint newest_modification;
- /* log sequence number of the youngest
- modification to this block, zero if
- not modified */
- dulint oldest_modification;
- /* log sequence number of the START of
- the log entry written of the oldest
- modification to this block which has
- not yet been flushed on disk; zero if
- all modifications are on disk */
- ulint flush_type; /* if this block is currently being
- flushed to disk, this tells the
- flush_type: BUF_FLUSH_LRU or
- BUF_FLUSH_LIST */
-
- /* 3. LRU replacement algorithm fields */
-
- UT_LIST_NODE_T(buf_block_t) free;
- /* node of the free block list */
- ibool in_free_list; /* TRUE if in the free list; used in
- debugging */
- UT_LIST_NODE_T(buf_block_t) LRU;
- /* node of the LRU list */
- UT_LIST_NODE_T(buf_block_t) awe_LRU_free_mapped;
- /* in the AWE version node in the
- list of free and LRU blocks which are
- mapped to a frame */
- ibool in_LRU_list; /* TRUE of the page is in the LRU list;
- used in debugging */
- ulint LRU_position; /* value which monotonically
- decreases (or may stay constant if
- the block is in the old blocks) toward
- the end of the LRU list, if the pool
- ulint_clock has not wrapped around:
- NOTE that this value can only be used
- in heuristic algorithms, because of
- the possibility of a wrap-around! */
- ulint freed_page_clock;/* the value of freed_page_clock
- of the buffer pool when this block was
- the last time put to the head of the
- LRU list; a thread is allowed to
- read this for heuristic purposes
- without holding any mutex or latch */
- ibool old; /* TRUE if the block is in the old
- blocks in the LRU list */
- ibool accessed; /* TRUE if the page has been accessed
- while in the buffer pool: read-ahead
- may read in pages which have not been
- accessed yet; this is protected by
- block->mutex; a thread is allowed to
- read this for heuristic purposes
- without holding any mutex or latch */
- ulint buf_fix_count; /* count of how manyfold this block
- is currently bufferfixed; this is
- protected by block->mutex */
- ulint io_fix; /* if a read is pending to the frame,
- io_fix is BUF_IO_READ, in the case
- of a write BUF_IO_WRITE, otherwise 0;
- this is protected by block->mutex */
- /* 4. Optimistic search field */
-
- dulint modify_clock; /* this clock is incremented every
- time a pointer to a record on the
- page may become obsolete; this is
- used in the optimistic cursor
- positioning: if the modify clock has
- not changed, we know that the pointer
- is still valid; this field may be
- changed if the thread (1) owns the
- pool mutex and the page is not
- bufferfixed, or (2) the thread has an
- x-latch on the block */
-
- /* 5. Hash search fields: NOTE that the first 4 fields are NOT
- protected by any semaphore! */
-
- ulint n_hash_helps; /* counter which controls building
- of a new hash index for the page */
- ulint n_fields; /* recommended prefix length for hash
- search: number of full fields */
- ulint n_bytes; /* recommended prefix: number of bytes
- in an incomplete field */
- ibool left_side; /* TRUE or FALSE, depending on
- whether the leftmost record of several
- records with the same prefix should be
- indexed in the hash index */
-
- /* These 6 fields may only be modified when we have
- an x-latch on btr_search_latch AND
- a) we are holding an s-latch or x-latch on block->lock or
- b) we know that block->buf_fix_count == 0.
-
- An exception to this is when we init or create a page
- in the buffer pool in buf0buf.c. */
-
- ibool is_hashed; /* TRUE if hash index has already been
- built on this page; note that it does
- not guarantee that the index is
- complete, though: there may have been
- hash collisions, record deletions,
- etc. */
- ulint n_pointers; /* used in debugging: the number of
- pointers in the adaptive hash index
- pointing to this frame */
- ulint curr_n_fields; /* prefix length for hash indexing:
- number of full fields */
- ulint curr_n_bytes; /* number of bytes in hash indexing */
- ibool curr_left_side; /* TRUE or FALSE in hash indexing */
- dict_index_t* index; /* Index for which the adaptive
- hash index has been created. */
- /* 6. Debug fields */
-#ifdef UNIV_SYNC_DEBUG
- rw_lock_t debug_latch; /* in the debug version, each thread
- which bufferfixes the block acquires
- an s-latch here; so we can use the
- debug utilities in sync0rw */
-#endif
- ibool file_page_was_freed;
- /* this is set to TRUE when fsp
- frees a page in buffer pool */
-};
-
-#define BUF_BLOCK_MAGIC_N 41526563
-
-/* The buffer pool structure. NOTE! The definition appears here only for
-other modules of this directory (buf) to see it. Do not use from outside! */
-
-struct buf_pool_struct{
-
- /* 1. General fields */
-
- mutex_t mutex; /* mutex protecting the buffer pool
- struct and control blocks, except the
- read-write lock in them */
- byte* frame_mem; /* pointer to the memory area which
- was allocated for the frames; in AWE
- this is the virtual address space
- window where we map pages stored
- in physical memory */
- byte* frame_zero; /* pointer to the first buffer frame:
- this may differ from frame_mem, because
- this is aligned by the frame size */
- byte* high_end; /* pointer to the end of the buffer
- frames */
- ulint n_frames; /* number of frames */
- buf_block_t* blocks; /* array of buffer control blocks */
- buf_block_t** blocks_of_frames;/* inverse mapping which can be used
- to retrieve the buffer control block
- of a frame; this is an array which
- lists the blocks of frames in the
- order frame_zero,
- frame_zero + UNIV_PAGE_SIZE, ...
- a control block is always assigned
- for each frame, even if the frame does
- not contain any data; note that in AWE
- there are more control blocks than
- buffer frames */
- os_awe_t* awe_info; /* if AWE is used, AWE info for the
- physical 4 kB memory pages associated
- with buffer frames */
- ulint max_size; /* number of control blocks ==
- maximum pool size in pages */
- ulint curr_size; /* current pool size in pages;
- currently always the same as
- max_size */
- hash_table_t* page_hash; /* hash table of the file pages */
-
- ulint n_pend_reads; /* number of pending read operations */
-
- time_t last_printout_time; /* when buf_print was last time
- called */
- ulint n_pages_read; /* number read operations */
- ulint n_pages_written;/* number write operations */
- ulint n_pages_created;/* number of pages created in the pool
- with no read */
- ulint n_page_gets; /* number of page gets performed;
- also successful searches through
- the adaptive hash index are
- counted as page gets; this field
- is NOT protected by the buffer
- pool mutex */
- ulint n_pages_awe_remapped; /* if AWE is enabled, the
- number of remaps of blocks to
- buffer frames */
- ulint n_page_gets_old;/* n_page_gets when buf_print was
- last time called: used to calculate
- hit rate */
- ulint n_pages_read_old;/* n_pages_read when buf_print was
- last time called */
- ulint n_pages_written_old;/* number write operations */
- ulint n_pages_created_old;/* number of pages created in
- the pool with no read */
- ulint n_pages_awe_remapped_old;
- /* 2. Page flushing algorithm fields */
-
- UT_LIST_BASE_NODE_T(buf_block_t) flush_list;
- /* base node of the modified block
- list */
- ibool init_flush[BUF_FLUSH_LIST + 1];
- /* this is TRUE when a flush of the
- given type is being initialized */
- ulint n_flush[BUF_FLUSH_LIST + 1];
- /* this is the number of pending
- writes in the given flush type */
- os_event_t no_flush[BUF_FLUSH_LIST + 1];
- /* this is in the set state when there
- is no flush batch of the given type
- running */
- ulint ulint_clock; /* a sequence number used to count
- time. NOTE! This counter wraps
- around at 4 billion (if ulint ==
- 32 bits)! */
- ulint freed_page_clock;/* a sequence number used to count the
- number of buffer blocks removed from
- the end of the LRU list; NOTE that
- this counter may wrap around at 4
- billion! A thread is allowed to
- read this for heuristic purposes
- without holding any mutex or latch */
- ulint LRU_flush_ended;/* when an LRU flush ends for a page,
- this is incremented by one; this is
- set to zero when a buffer block is
- allocated */
-
- /* 3. LRU replacement algorithm fields */
-
- UT_LIST_BASE_NODE_T(buf_block_t) free;
- /* base node of the free block list;
- in the case of AWE, at the start are
- always free blocks for which the
- physical memory is mapped to a frame */
- UT_LIST_BASE_NODE_T(buf_block_t) LRU;
- /* base node of the LRU list */
- buf_block_t* LRU_old; /* pointer to the about 3/8 oldest
- blocks in the LRU list; NULL if LRU
- length less than BUF_LRU_OLD_MIN_LEN */
- ulint LRU_old_len; /* length of the LRU list from
- the block to which LRU_old points
- onward, including that block;
- see buf0lru.c for the restrictions
- on this value; not defined if
- LRU_old == NULL */
- UT_LIST_BASE_NODE_T(buf_block_t) awe_LRU_free_mapped;
- /* list of those blocks which are
- in the LRU list or the free list, and
- where the page is mapped to a frame;
- thus, frames allocated, e.g., to the
- locki table, are not in this list */
-};
-
-/* States of a control block */
-#define BUF_BLOCK_NOT_USED 211 /* is in the free list */
-#define BUF_BLOCK_READY_FOR_USE 212 /* when buf_get_free_block returns
- a block, it is in this state */
-#define BUF_BLOCK_FILE_PAGE 213 /* contains a buffered file page */
-#define BUF_BLOCK_MEMORY 214 /* contains some main memory object */
-#define BUF_BLOCK_REMOVE_HASH 215 /* hash index should be removed
- before putting to the free list */
-
-/* Io_fix states of a control block; these must be != 0 */
-#define BUF_IO_READ 561
-#define BUF_IO_WRITE 562
-
-/************************************************************************
-Let us list the consistency conditions for different control block states.
-
-NOT_USED: is in free list, not in LRU list, not in flush list, nor
- page hash table
-READY_FOR_USE: is not in free list, LRU list, or flush list, nor page
- hash table
-MEMORY: is not in free list, LRU list, or flush list, nor page
- hash table
-FILE_PAGE: space and offset are defined, is in page hash table
- if io_fix == BUF_IO_WRITE,
- pool: no_flush[block->flush_type] is in reset state,
- pool: n_flush[block->flush_type] > 0
-
- (1) if buf_fix_count == 0, then
- is in LRU list, not in free list
- is in flush list,
- if and only if oldest_modification > 0
- is x-locked,
- if and only if io_fix == BUF_IO_READ
- is s-locked,
- if and only if io_fix == BUF_IO_WRITE
-
- (2) if buf_fix_count > 0, then
- is not in LRU list, not in free list
- is in flush list,
- if and only if oldest_modification > 0
- if io_fix == BUF_IO_READ,
- is x-locked
- if io_fix == BUF_IO_WRITE,
- is s-locked
-
-State transitions:
-
-NOT_USED => READY_FOR_USE
-READY_FOR_USE => MEMORY
-READY_FOR_USE => FILE_PAGE
-MEMORY => NOT_USED
-FILE_PAGE => NOT_USED NOTE: This transition is allowed if and only if
- (1) buf_fix_count == 0,
- (2) oldest_modification == 0, and
- (3) io_fix == 0.
-*/
-
-#ifndef UNIV_NONINL
-#include "buf0buf.ic"
-#endif
-
-#endif
diff --git a/storage/innobase/include/buf0buf.ic b/storage/innobase/include/buf0buf.ic
deleted file mode 100644
index 4e96e13b8dc..00000000000
--- a/storage/innobase/include/buf0buf.ic
+++ /dev/null
@@ -1,665 +0,0 @@
-/******************************************************
-The database buffer buf_pool
-
-(c) 1995 Innobase Oy
-
-Created 11/5/1995 Heikki Tuuri
-*******************************************************/
-
-#include "buf0flu.h"
-#include "buf0lru.h"
-#include "buf0rea.h"
-#include "mtr0mtr.h"
-
-#ifdef UNIV_DEBUG
-extern ulint buf_dbg_counter; /* This is used to insert validation
- operations in execution in the
- debug version */
-#endif /* UNIV_DEBUG */
-/************************************************************************
-Recommends a move of a block to the start of the LRU list if there is danger
-of dropping from the buffer pool. NOTE: does not reserve the buffer pool
-mutex. */
-UNIV_INLINE
-ibool
-buf_block_peek_if_too_old(
-/*======================*/
- /* out: TRUE if should be made younger */
- buf_block_t* block) /* in: block to make younger */
-{
- return(buf_pool->freed_page_clock >= block->freed_page_clock
- + 1 + (buf_pool->curr_size / 4));
-}
-
-/*************************************************************************
-Gets the current size of buffer buf_pool in bytes. In the case of AWE, the
-size of AWE window (= the frames). */
-UNIV_INLINE
-ulint
-buf_pool_get_curr_size(void)
-/*========================*/
- /* out: size in bytes */
-{
- return((buf_pool->n_frames) * UNIV_PAGE_SIZE);
-}
-
-/*************************************************************************
-Gets the maximum size of buffer buf_pool in bytes. In the case of AWE, the
-size of AWE window (= the frames). */
-UNIV_INLINE
-ulint
-buf_pool_get_max_size(void)
-/*=======================*/
- /* out: size in bytes */
-{
- return((buf_pool->n_frames) * UNIV_PAGE_SIZE);
-}
-
-/***********************************************************************
-Accessor function for block array. */
-UNIV_INLINE
-buf_block_t*
-buf_pool_get_nth_block(
-/*===================*/
- /* out: pointer to block */
- buf_pool_t* buf_pool,/* in: buf_pool */
- ulint i) /* in: index of the block */
-{
- ut_ad(buf_pool);
- ut_ad(i < buf_pool->max_size);
-
- return(i + buf_pool->blocks);
-}
-
-/***********************************************************************
-Checks if a pointer points to the block array of the buffer pool (blocks, not
-the frames). */
-UNIV_INLINE
-ibool
-buf_pool_is_block(
-/*==============*/
- /* out: TRUE if pointer to block */
- void* ptr) /* in: pointer to memory */
-{
- if ((buf_pool->blocks <= (buf_block_t*)ptr)
- && ((buf_block_t*)ptr < buf_pool->blocks
- + buf_pool->max_size)) {
-
- return(TRUE);
- }
-
- return(FALSE);
-}
-
-/************************************************************************
-Gets the smallest oldest_modification lsn for any page in the pool. Returns
-ut_dulint_zero if all modified pages have been flushed to disk. */
-UNIV_INLINE
-dulint
-buf_pool_get_oldest_modification(void)
-/*==================================*/
- /* out: oldest modification in pool,
- ut_dulint_zero if none */
-{
- buf_block_t* block;
- dulint lsn;
-
- mutex_enter(&(buf_pool->mutex));
-
- block = UT_LIST_GET_LAST(buf_pool->flush_list);
-
- if (block == NULL) {
- lsn = ut_dulint_zero;
- } else {
- lsn = block->oldest_modification;
- }
-
- mutex_exit(&(buf_pool->mutex));
-
- return(lsn);
-}
-
-/***********************************************************************
-Increments the buf_pool clock by one and returns its new value. Remember
-that in the 32 bit version the clock wraps around at 4 billion! */
-UNIV_INLINE
-ulint
-buf_pool_clock_tic(void)
-/*====================*/
- /* out: new clock value */
-{
- ut_ad(mutex_own(&(buf_pool->mutex)));
-
- buf_pool->ulint_clock++;
-
- return(buf_pool->ulint_clock);
-}
-
-/*************************************************************************
-Gets a pointer to the memory frame of a block. */
-UNIV_INLINE
-buf_frame_t*
-buf_block_get_frame(
-/*================*/
- /* out: pointer to the frame */
- buf_block_t* block) /* in: pointer to the control block */
-{
- ut_ad(block);
- ut_ad(block >= buf_pool->blocks);
- ut_ad(block < buf_pool->blocks + buf_pool->max_size);
- ut_ad(block->state != BUF_BLOCK_NOT_USED);
- ut_ad((block->state != BUF_BLOCK_FILE_PAGE)
- || (block->buf_fix_count > 0));
-
- return(block->frame);
-}
-
-/*************************************************************************
-Gets the space id of a block. */
-UNIV_INLINE
-ulint
-buf_block_get_space(
-/*================*/
- /* out: space id */
- buf_block_t* block) /* in: pointer to the control block */
-{
- ut_ad(block);
- ut_ad(block >= buf_pool->blocks);
- ut_ad(block < buf_pool->blocks + buf_pool->max_size);
- ut_a(block->state == BUF_BLOCK_FILE_PAGE);
- ut_ad(block->buf_fix_count > 0);
-
- return(block->space);
-}
-
-/*************************************************************************
-Gets the page number of a block. */
-UNIV_INLINE
-ulint
-buf_block_get_page_no(
-/*==================*/
- /* out: page number */
- buf_block_t* block) /* in: pointer to the control block */
-{
- ut_ad(block);
- ut_ad(block >= buf_pool->blocks);
- ut_ad(block < buf_pool->blocks + buf_pool->max_size);
- ut_a(block->state == BUF_BLOCK_FILE_PAGE);
- ut_ad(block->buf_fix_count > 0);
-
- return(block->offset);
-}
-
-/***********************************************************************
-Gets the block to whose frame the pointer is pointing to. */
-UNIV_INLINE
-buf_block_t*
-buf_block_align(
-/*============*/
- /* out: pointer to block */
- byte* ptr) /* in: pointer to a frame */
-{
- buf_block_t* block;
- buf_frame_t* frame_zero;
-
- ut_ad(ptr);
-
- frame_zero = buf_pool->frame_zero;
-
- if (UNIV_UNLIKELY((ulint)ptr < (ulint)frame_zero)
- || UNIV_UNLIKELY((ulint)ptr > (ulint)(buf_pool->high_end))) {
-
- ut_print_timestamp(stderr);
- fprintf(stderr,
- "InnoDB: Error: trying to access a stray pointer %p\n"
- "InnoDB: buf pool start is at %p, end at %p\n"
- "InnoDB: Probable reason is database corruption"
- " or memory\n"
- "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"
- "InnoDB: how to force recovery.\n",
- ptr, frame_zero,
- buf_pool->high_end);
- ut_error;
- }
-
- block = *(buf_pool->blocks_of_frames + (((ulint)(ptr - frame_zero))
- >> UNIV_PAGE_SIZE_SHIFT));
- return(block);
-}
-
-/***********************************************************************
-Gets the frame the pointer is pointing to. */
-UNIV_INLINE
-buf_frame_t*
-buf_frame_align(
-/*============*/
- /* out: pointer to frame */
- byte* ptr) /* in: pointer to a frame */
-{
- buf_frame_t* frame;
-
- ut_ad(ptr);
-
- frame = ut_align_down(ptr, UNIV_PAGE_SIZE);
-
- if (UNIV_UNLIKELY((ulint)frame < (ulint)(buf_pool->frame_zero))
- || UNIV_UNLIKELY((ulint)frame >= (ulint)(buf_pool->high_end))) {
-
- ut_print_timestamp(stderr);
- fprintf(stderr,
- "InnoDB: Error: trying to access a stray pointer %p\n"
- "InnoDB: buf pool start is at %p, end at %p\n"
- "InnoDB: Probable reason is database corruption"
- " or memory\n"
- "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"
- "InnoDB: how to force recovery.\n",
- ptr, buf_pool->frame_zero,
- buf_pool->high_end);
- ut_error;
- }
-
- return(frame);
-}
-
-/**************************************************************************
-Gets the page number of a pointer pointing within a buffer frame containing
-a file page. */
-UNIV_INLINE
-ulint
-buf_frame_get_page_no(
-/*==================*/
- /* out: page number */
- byte* ptr) /* in: pointer to within a buffer frame */
-{
- return(buf_block_get_page_no(buf_block_align(ptr)));
-}
-
-/**************************************************************************
-Gets the space id of a pointer pointing within a buffer frame containing a
-file page. */
-UNIV_INLINE
-ulint
-buf_frame_get_space_id(
-/*===================*/
- /* out: space id */
- byte* ptr) /* in: pointer to within a buffer frame */
-{
- return(buf_block_get_space(buf_block_align(ptr)));
-}
-
-/**************************************************************************
-Gets the space id, page offset, and byte offset within page of a
-pointer pointing to a buffer frame containing a file page. */
-UNIV_INLINE
-void
-buf_ptr_get_fsp_addr(
-/*=================*/
- byte* ptr, /* in: pointer to a buffer frame */
- ulint* space, /* out: space id */
- fil_addr_t* addr) /* out: page offset and byte offset */
-{
- buf_block_t* block;
-
- block = buf_block_align(ptr);
-
- *space = buf_block_get_space(block);
- addr->page = buf_block_get_page_no(block);
- addr->boffset = ptr - buf_frame_align(ptr);
-}
-
-/**************************************************************************
-Gets the hash value of the page the pointer is pointing to. This can be used
-in searches in the lock hash table. */
-UNIV_INLINE
-ulint
-buf_frame_get_lock_hash_val(
-/*========================*/
- /* out: lock hash value */
- byte* ptr) /* in: pointer to within a buffer frame */
-{
- buf_block_t* block;
-
- block = buf_block_align(ptr);
-
- return(block->lock_hash_val);
-}
-
-/**************************************************************************
-Gets the mutex number protecting the page record lock hash chain in the lock
-table. */
-UNIV_INLINE
-mutex_t*
-buf_frame_get_mutex(
-/*================*/
- /* out: mutex */
- byte* ptr) /* in: pointer to within a buffer frame */
-{
- buf_block_t* block;
-
- block = buf_block_align(ptr);
-
- return(&block->mutex);
-}
-
-/*************************************************************************
-Copies contents of a buffer frame to a given buffer. */
-UNIV_INLINE
-byte*
-buf_frame_copy(
-/*===========*/
- /* out: buf */
- byte* buf, /* in: buffer to copy to */
- buf_frame_t* frame) /* in: buffer frame */
-{
- ut_ad(buf && frame);
-
- ut_memcpy(buf, frame, UNIV_PAGE_SIZE);
-
- return(buf);
-}
-
-/************************************************************************
-Calculates a folded value of a file page address to use in the page hash
-table. */
-UNIV_INLINE
-ulint
-buf_page_address_fold(
-/*==================*/
- /* out: the folded value */
- ulint space, /* in: space id */
- ulint offset) /* in: offset of the page within space */
-{
- return((space << 20) + space + offset);
-}
-
-/************************************************************************
-This function is used to get info if there is an io operation
-going on on a buffer page. */
-UNIV_INLINE
-ibool
-buf_page_io_query(
-/*==============*/
- /* out: TRUE if io going on */
- buf_block_t* block) /* in: buf_pool block, must be bufferfixed */
-{
- mutex_enter(&(buf_pool->mutex));
-
- ut_ad(block->state == BUF_BLOCK_FILE_PAGE);
- ut_ad(block->buf_fix_count > 0);
-
- if (block->io_fix != 0) {
- mutex_exit(&(buf_pool->mutex));
-
- return(TRUE);
- }
-
- mutex_exit(&(buf_pool->mutex));
-
- return(FALSE);
-}
-
-/************************************************************************
-Gets the youngest modification log sequence number for a frame. Returns zero
-if not a file page or no modification occurred yet. */
-UNIV_INLINE
-dulint
-buf_frame_get_newest_modification(
-/*==============================*/
- /* out: newest modification to the page */
- buf_frame_t* frame) /* in: pointer to a frame */
-{
- buf_block_t* block;
- dulint lsn;
-
- ut_ad(frame);
-
- block = buf_block_align(frame);
-
- mutex_enter(&(buf_pool->mutex));
-
- if (block->state == BUF_BLOCK_FILE_PAGE) {
- lsn = block->newest_modification;
- } else {
- lsn = ut_dulint_zero;
- }
-
- mutex_exit(&(buf_pool->mutex));
-
- return(lsn);
-}
-
-/************************************************************************
-Increments the modify clock of a frame by 1. The caller must (1) own the
-buf_pool mutex and block bufferfix count has to be zero, (2) or own an x-lock
-on the block. */
-UNIV_INLINE
-dulint
-buf_frame_modify_clock_inc(
-/*=======================*/
- /* out: new value */
- buf_frame_t* frame) /* in: pointer to a frame */
-{
- buf_block_t* block;
-
- ut_ad(frame);
-
- block = buf_block_align(frame);
-
-#ifdef UNIV_SYNC_DEBUG
- ut_ad((mutex_own(&(buf_pool->mutex)) && (block->buf_fix_count == 0))
- || rw_lock_own(&(block->lock), RW_LOCK_EXCLUSIVE));
-#endif /* UNIV_SYNC_DEBUG */
-
- UT_DULINT_INC(block->modify_clock);
-
- return(block->modify_clock);
-}
-
-/************************************************************************
-Increments the modify clock of a frame by 1. The caller must (1) own the
-buf_pool mutex and block bufferfix count has to be zero, (2) or own an x-lock
-on the block. */
-UNIV_INLINE
-dulint
-buf_block_modify_clock_inc(
-/*=======================*/
- /* out: new value */
- buf_block_t* block) /* in: block */
-{
-#ifdef UNIV_SYNC_DEBUG
- ut_ad((mutex_own(&(buf_pool->mutex)) && (block->buf_fix_count == 0))
- || rw_lock_own(&(block->lock), RW_LOCK_EXCLUSIVE));
-#endif /* UNIV_SYNC_DEBUG */
-
- UT_DULINT_INC(block->modify_clock);
-
- return(block->modify_clock);
-}
-
-/************************************************************************
-Returns the value of the modify clock. The caller must have an s-lock
-or x-lock on the block. */
-UNIV_INLINE
-dulint
-buf_block_get_modify_clock(
-/*=======================*/
- /* out: value */
- buf_block_t* block) /* in: block */
-{
-#ifdef UNIV_SYNC_DEBUG
- ut_ad(rw_lock_own(&(block->lock), RW_LOCK_SHARED)
- || rw_lock_own(&(block->lock), RW_LOCK_EXCLUSIVE));
-#endif /* UNIV_SYNC_DEBUG */
-
- return(block->modify_clock);
-}
-
-#ifdef UNIV_SYNC_DEBUG
-/***********************************************************************
-Increments the bufferfix count. */
-UNIV_INLINE
-void
-buf_block_buf_fix_inc_debug(
-/*========================*/
- buf_block_t* block, /* in: block to bufferfix */
- const char* file __attribute__ ((unused)), /* in: file name */
- ulint line __attribute__ ((unused))) /* in: line */
-{
- ibool ret;
-
- ret = rw_lock_s_lock_nowait(&(block->debug_latch), file, line);
-
- ut_ad(ret == TRUE);
- ut_ad(mutex_own(&block->mutex));
- block->buf_fix_count++;
-}
-#else /* UNIV_SYNC_DEBUG */
-/***********************************************************************
-Increments the bufferfix count. */
-UNIV_INLINE
-void
-buf_block_buf_fix_inc(
-/*==================*/
- buf_block_t* block) /* in: block to bufferfix */
-{
- ut_ad(mutex_own(&block->mutex));
-
- block->buf_fix_count++;
-}
-#endif /* UNIV_SYNC_DEBUG */
-/**********************************************************************
-Returns the control block of a file page, NULL if not found. */
-UNIV_INLINE
-buf_block_t*
-buf_page_hash_get(
-/*==============*/
- /* out: block, NULL if not found */
- ulint space, /* in: space id */
- ulint offset) /* in: offset of the page within space */
-{
- buf_block_t* block;
- ulint fold;
-
- ut_ad(buf_pool);
- ut_ad(mutex_own(&(buf_pool->mutex)));
-
- /* Look for the page in the hash table */
-
- fold = buf_page_address_fold(space, offset);
-
- HASH_SEARCH(hash, buf_pool->page_hash, fold, block,
- (block->space == space) && (block->offset == offset));
- ut_a(block == NULL || block->state == BUF_BLOCK_FILE_PAGE);
-
- return(block);
-}
-
-/************************************************************************
-Tries to get the page, but if file io is required, releases all latches
-in mtr down to the given savepoint. If io is required, this function
-retrieves the page to buffer buf_pool, but does not bufferfix it or latch
-it. */
-UNIV_INLINE
-buf_frame_t*
-buf_page_get_release_on_io(
-/*=======================*/
- /* out: pointer to the frame, or NULL
- if not in buffer buf_pool */
- ulint space, /* in: space id */
- ulint offset, /* in: offset of the page within space
- in units of a page */
- buf_frame_t* guess, /* in: guessed frame or NULL */
- ulint rw_latch, /* in: RW_X_LATCH, RW_S_LATCH,
- or RW_NO_LATCH */
- ulint savepoint, /* in: mtr savepoint */
- mtr_t* mtr) /* in: mtr */
-{
- buf_frame_t* frame;
-
- frame = buf_page_get_gen(space, offset, rw_latch, guess,
- BUF_GET_IF_IN_POOL,
- __FILE__, __LINE__,
- mtr);
- if (frame != NULL) {
-
- return(frame);
- }
-
- /* The page was not in the buffer buf_pool: release the latches
- down to the savepoint */
-
- mtr_rollback_to_savepoint(mtr, savepoint);
-
- buf_page_get(space, offset, RW_S_LATCH, mtr);
-
- /* When we get here, the page is in buffer, but we release
- the latches again down to the savepoint, before returning */
-
- mtr_rollback_to_savepoint(mtr, savepoint);
-
- return(NULL);
-}
-
-/************************************************************************
-Decrements the bufferfix count of a buffer control block and releases
-a latch, if specified. */
-UNIV_INLINE
-void
-buf_page_release(
-/*=============*/
- buf_block_t* block, /* in: buffer block */
- ulint rw_latch, /* in: RW_S_LATCH, RW_X_LATCH,
- RW_NO_LATCH */
- mtr_t* mtr) /* in: mtr */
-{
- ut_ad(block);
-
- ut_a(block->state == BUF_BLOCK_FILE_PAGE);
- ut_a(block->buf_fix_count > 0);
-
- if (rw_latch == RW_X_LATCH && mtr->modifications) {
- mutex_enter(&buf_pool->mutex);
- buf_flush_note_modification(block, mtr);
- mutex_exit(&buf_pool->mutex);
- }
-
- mutex_enter(&block->mutex);
-
-#ifdef UNIV_SYNC_DEBUG
- rw_lock_s_unlock(&(block->debug_latch));
-#endif
- block->buf_fix_count--;
-
- mutex_exit(&block->mutex);
-
- if (rw_latch == RW_S_LATCH) {
- rw_lock_s_unlock(&(block->lock));
- } else if (rw_latch == RW_X_LATCH) {
- rw_lock_x_unlock(&(block->lock));
- }
-}
-
-#ifdef UNIV_SYNC_DEBUG
-/*************************************************************************
-Adds latch level info for the rw-lock protecting the buffer frame. This
-should be called in the debug version after a successful latching of a
-page if we know the latching order level of the acquired latch. If
-UNIV_SYNC_DEBUG is not defined, compiles to an empty function. */
-UNIV_INLINE
-void
-buf_page_dbg_add_level(
-/*===================*/
- buf_frame_t* frame __attribute__((unused)), /* in: buffer page
- where we have acquired latch */
- ulint level __attribute__((unused))) /* in: latching order
- level */
-{
- sync_thread_add_level(&(buf_block_align(frame)->lock), level);
-}
-#endif /* UNIV_SYNC_DEBUG */
diff --git a/storage/innobase/include/buf0flu.h b/storage/innobase/include/buf0flu.h
deleted file mode 100644
index 322848509f4..00000000000
--- a/storage/innobase/include/buf0flu.h
+++ /dev/null
@@ -1,120 +0,0 @@
-/******************************************************
-The database buffer pool flush algorithm
-
-(c) 1995 Innobase Oy
-
-Created 11/5/1995 Heikki Tuuri
-*******************************************************/
-
-#ifndef buf0flu_h
-#define buf0flu_h
-
-#include "univ.i"
-#include "buf0types.h"
-#include "ut0byte.h"
-#include "mtr0types.h"
-
-/************************************************************************
-Updates the flush system data structures when a write is completed. */
-
-void
-buf_flush_write_complete(
-/*=====================*/
- buf_block_t* block); /* in: pointer to the block in question */
-/*************************************************************************
-Flushes pages from the end of the LRU list if there is too small
-a margin of replaceable pages there. */
-
-void
-buf_flush_free_margin(void);
-/*=======================*/
-/************************************************************************
-Initializes a page for writing to the tablespace. */
-
-void
-buf_flush_init_for_writing(
-/*=======================*/
- byte* page, /* in: page */
- dulint newest_lsn, /* in: newest modification lsn to the page */
- ulint space, /* in: space id */
- ulint page_no); /* in: page number */
-/***********************************************************************
-This utility flushes dirty blocks from the end of the LRU list or flush_list.
-NOTE 1: in the case of an LRU flush the calling thread may own latches to
-pages: to avoid deadlocks, this function must be written so that it cannot
-end up waiting for these latches! NOTE 2: in the case of a flush list flush,
-the calling thread is not allowed to own any latches on pages! */
-
-ulint
-buf_flush_batch(
-/*============*/
- /* out: number of blocks for which the write
- request was queued */
- ulint flush_type, /* in: BUF_FLUSH_LRU or BUF_FLUSH_LIST; if
- BUF_FLUSH_LIST, then the caller must not own
- any latches on pages */
- ulint min_n, /* in: wished minimum mumber of blocks flushed
- (it is not guaranteed that the actual number
- is that big, though) */
- dulint lsn_limit); /* in the case BUF_FLUSH_LIST all blocks whose
- oldest_modification is smaller than this
- should be flushed (if their number does not
- exceed min_n), otherwise ignored */
-/**********************************************************************
-Waits until a flush batch of the given type ends */
-
-void
-buf_flush_wait_batch_end(
-/*=====================*/
- ulint type); /* in: BUF_FLUSH_LRU or BUF_FLUSH_LIST */
-/************************************************************************
-This function should be called at a mini-transaction commit, if a page was
-modified in it. Puts the block to the list of modified blocks, if it not
-already in it. */
-UNIV_INLINE
-void
-buf_flush_note_modification(
-/*========================*/
- buf_block_t* block, /* in: block which is modified */
- mtr_t* mtr); /* in: mtr */
-/************************************************************************
-This function should be called when recovery has modified a buffer page. */
-UNIV_INLINE
-void
-buf_flush_recv_note_modification(
-/*=============================*/
- buf_block_t* block, /* in: block which is modified */
- dulint start_lsn, /* in: start lsn of the first mtr in a
- set of mtr's */
- dulint end_lsn); /* in: end lsn of the last mtr in the
- set of mtr's */
-/************************************************************************
-Returns TRUE if the file page block is immediately suitable for replacement,
-i.e., transition FILE_PAGE => NOT_USED allowed. */
-ibool
-buf_flush_ready_for_replace(
-/*========================*/
- /* out: TRUE if can replace immediately */
- buf_block_t* block); /* in: buffer control block, must be in state
- BUF_BLOCK_FILE_PAGE and in the LRU list */
-/**********************************************************************
-Validates the flush list. */
-
-ibool
-buf_flush_validate(void);
-/*====================*/
- /* out: TRUE if ok */
-
-/* When buf_flush_free_margin is called, it tries to make this many blocks
-available to replacement in the free list and at the end of the LRU list (to
-make sure that a read-ahead batch can be read efficiently in a single
-sweep). */
-
-#define BUF_FLUSH_FREE_BLOCK_MARGIN (5 + BUF_READ_AHEAD_AREA)
-#define BUF_FLUSH_EXTRA_MARGIN (BUF_FLUSH_FREE_BLOCK_MARGIN / 4 + 100)
-
-#ifndef UNIV_NONINL
-#include "buf0flu.ic"
-#endif
-
-#endif
diff --git a/storage/innobase/include/buf0flu.ic b/storage/innobase/include/buf0flu.ic
deleted file mode 100644
index ae873c42088..00000000000
--- a/storage/innobase/include/buf0flu.ic
+++ /dev/null
@@ -1,106 +0,0 @@
-/******************************************************
-The database buffer pool flush algorithm
-
-(c) 1995 Innobase Oy
-
-Created 11/5/1995 Heikki Tuuri
-*******************************************************/
-
-#include "buf0buf.h"
-#include "mtr0mtr.h"
-
-/************************************************************************
-Inserts a modified block into the flush list. */
-
-void
-buf_flush_insert_into_flush_list(
-/*=============================*/
- buf_block_t* block); /* in: block which is modified */
-/************************************************************************
-Inserts a modified block into the flush list in the right sorted position.
-This function is used by recovery, because there the modifications do not
-necessarily come in the order of lsn's. */
-
-void
-buf_flush_insert_sorted_into_flush_list(
-/*====================================*/
- buf_block_t* block); /* in: block which is modified */
-
-/************************************************************************
-This function should be called at a mini-transaction commit, if a page was
-modified in it. Puts the block to the list of modified blocks, if it is not
-already in it. */
-UNIV_INLINE
-void
-buf_flush_note_modification(
-/*========================*/
- buf_block_t* block, /* in: block which is modified */
- mtr_t* mtr) /* in: mtr */
-{
- ut_ad(block);
- ut_ad(block->state == BUF_BLOCK_FILE_PAGE);
- ut_ad(block->buf_fix_count > 0);
-#ifdef UNIV_SYNC_DEBUG
- ut_ad(rw_lock_own(&(block->lock), RW_LOCK_EX));
-#endif /* UNIV_SYNC_DEBUG */
- ut_ad(mutex_own(&(buf_pool->mutex)));
-
- ut_ad(ut_dulint_cmp(mtr->start_lsn, ut_dulint_zero) != 0);
- ut_ad(mtr->modifications);
- ut_ad(ut_dulint_cmp(block->newest_modification, mtr->end_lsn) <= 0);
-
- block->newest_modification = mtr->end_lsn;
-
- if (ut_dulint_is_zero(block->oldest_modification)) {
-
- block->oldest_modification = mtr->start_lsn;
- ut_ad(!ut_dulint_is_zero(block->oldest_modification));
-
- buf_flush_insert_into_flush_list(block);
- } else {
- ut_ad(ut_dulint_cmp(block->oldest_modification,
- mtr->start_lsn) <= 0);
- }
-
- ++srv_buf_pool_write_requests;
-}
-
-/************************************************************************
-This function should be called when recovery has modified a buffer page. */
-UNIV_INLINE
-void
-buf_flush_recv_note_modification(
-/*=============================*/
- buf_block_t* block, /* in: block which is modified */
- dulint start_lsn, /* in: start lsn of the first mtr in a
- set of mtr's */
- dulint end_lsn) /* in: end lsn of the last mtr in the
- set of mtr's */
-{
- ut_ad(block);
- ut_ad(block->state == BUF_BLOCK_FILE_PAGE);
- ut_ad(block->buf_fix_count > 0);
-#ifdef UNIV_SYNC_DEBUG
- ut_ad(rw_lock_own(&(block->lock), RW_LOCK_EX));
-#endif /* UNIV_SYNC_DEBUG */
-
- mutex_enter(&(buf_pool->mutex));
-
- ut_ad(ut_dulint_cmp(block->newest_modification, end_lsn) <= 0);
-
- block->newest_modification = end_lsn;
-
- if (ut_dulint_is_zero(block->oldest_modification)) {
-
- block->oldest_modification = start_lsn;
-
- ut_ad(!ut_dulint_is_zero(block->oldest_modification));
-
- buf_flush_insert_sorted_into_flush_list(block);
- } else {
- ut_ad(ut_dulint_cmp(block->oldest_modification,
- start_lsn) <= 0);
- }
-
- mutex_exit(&(buf_pool->mutex));
-}
diff --git a/storage/innobase/include/buf0lru.h b/storage/innobase/include/buf0lru.h
deleted file mode 100644
index 6d26fd4d3b2..00000000000
--- a/storage/innobase/include/buf0lru.h
+++ /dev/null
@@ -1,144 +0,0 @@
-/******************************************************
-The database buffer pool LRU replacement algorithm
-
-(c) 1995 Innobase Oy
-
-Created 11/5/1995 Heikki Tuuri
-*******************************************************/
-
-#ifndef buf0lru_h
-#define buf0lru_h
-
-#include "univ.i"
-#include "ut0byte.h"
-#include "buf0types.h"
-
-/**********************************************************************
-Tries to remove LRU flushed blocks from the end of the LRU list and put them
-to the free list. This is beneficial for the efficiency of the insert buffer
-operation, as flushed pages from non-unique non-clustered indexes are here
-taken out of the buffer pool, and their inserts redirected to the insert
-buffer. Otherwise, the flushed blocks could get modified again before read
-operations need new buffer blocks, and the i/o work done in flushing would be
-wasted. */
-
-void
-buf_LRU_try_free_flushed_blocks(void);
-/*==================================*/
-/**********************************************************************
-Returns TRUE if less than 25 % of the buffer pool is available. This can be
-used in heuristics to prevent huge transactions eating up the whole buffer
-pool for their locks. */
-
-ibool
-buf_LRU_buf_pool_running_out(void);
-/*==============================*/
- /* out: TRUE if less than 25 % of buffer pool
- left */
-
-/*#######################################################################
-These are low-level functions
-#########################################################################*/
-
-/* Minimum LRU list length for which the LRU_old pointer is defined */
-
-#define BUF_LRU_OLD_MIN_LEN 80
-
-#define BUF_LRU_FREE_SEARCH_LEN (5 + 2 * BUF_READ_AHEAD_AREA)
-
-/**********************************************************************
-Invalidates all pages belonging to a given tablespace when we are deleting
-the data file(s) of that tablespace. A PROBLEM: if readahead is being started,
-what guarantees that it will not try to read in pages after this operation has
-completed? */
-
-void
-buf_LRU_invalidate_tablespace(
-/*==========================*/
- ulint id); /* in: space id */
-/**********************************************************************
-Gets the minimum LRU_position field for the blocks in an initial segment
-(determined by BUF_LRU_INITIAL_RATIO) of the LRU list. The limit is not
-guaranteed to be precise, because the ulint_clock may wrap around. */
-
-ulint
-buf_LRU_get_recent_limit(void);
-/*==========================*/
- /* out: the limit; zero if could not determine it */
-/**********************************************************************
-Look for a replaceable block from the end of the LRU list and put it to
-the free list if found. */
-
-ibool
-buf_LRU_search_and_free_block(
-/*==========================*/
- /* out: TRUE if freed */
- ulint n_iterations); /* in: how many times this has been called
- repeatedly without result: a high value means
- that we should search farther; if value is
- k < 10, then we only search k/10 * number
- of pages in the buffer pool from the end
- of the LRU list */
-/**********************************************************************
-Returns a free block from the buf_pool. The block is taken off the
-free list. If it is empty, blocks are moved from the end of the
-LRU list to the free list. */
-
-buf_block_t*
-buf_LRU_get_free_block(void);
-/*=========================*/
- /* out: the free control block; also if AWE is
- used, it is guaranteed that the block has its
- page mapped to a frame when we return */
-/**********************************************************************
-Puts a block back to the free list. */
-
-void
-buf_LRU_block_free_non_file_page(
-/*=============================*/
- buf_block_t* block); /* in: block, must not contain a file page */
-/**********************************************************************
-Adds a block to the LRU list. */
-
-void
-buf_LRU_add_block(
-/*==============*/
- buf_block_t* block, /* in: control block */
- ibool old); /* in: TRUE if should be put to the old
- blocks in the LRU list, else put to the
- start; if the LRU list is very short, added to
- the start regardless of this parameter */
-/**********************************************************************
-Moves a block to the start of the LRU list. */
-
-void
-buf_LRU_make_block_young(
-/*=====================*/
- buf_block_t* block); /* in: control block */
-/**********************************************************************
-Moves a block to the end of the LRU list. */
-
-void
-buf_LRU_make_block_old(
-/*===================*/
- buf_block_t* block); /* in: control block */
-#ifdef UNIV_DEBUG
-/**************************************************************************
-Validates the LRU list. */
-
-ibool
-buf_LRU_validate(void);
-/*==================*/
-/**************************************************************************
-Prints the LRU list. */
-
-void
-buf_LRU_print(void);
-/*===============*/
-#endif /* UNIV_DEBUG */
-
-#ifndef UNIV_NONINL
-#include "buf0lru.ic"
-#endif
-
-#endif
diff --git a/storage/innobase/include/buf0lru.ic b/storage/innobase/include/buf0lru.ic
deleted file mode 100644
index 7b8ee457b0b..00000000000
--- a/storage/innobase/include/buf0lru.ic
+++ /dev/null
@@ -1,8 +0,0 @@
-/******************************************************
-The database buffer replacement algorithm
-
-(c) 1995 Innobase Oy
-
-Created 11/5/1995 Heikki Tuuri
-*******************************************************/
-
diff --git a/storage/innobase/include/buf0types.h b/storage/innobase/include/buf0types.h
deleted file mode 100644
index 44fdfa80e73..00000000000
--- a/storage/innobase/include/buf0types.h
+++ /dev/null
@@ -1,20 +0,0 @@
-/******************************************************
-The database buffer pool global types for the directory
-
-(c) 1995 Innobase Oy
-
-Created 11/17/1995 Heikki Tuuri
-*******************************************************/
-
-#ifndef buf0types_h
-#define buf0types_h
-
-typedef struct buf_block_struct buf_block_t;
-typedef struct buf_pool_struct buf_pool_t;
-
-/* The 'type' used of a buffer frame */
-typedef byte buf_frame_t;
-
-
-#endif
-
diff --git a/storage/innobase/include/data0data.h b/storage/innobase/include/data0data.h
deleted file mode 100644
index 40592c3c0ce..00000000000
--- a/storage/innobase/include/data0data.h
+++ /dev/null
@@ -1,424 +0,0 @@
-/************************************************************************
-SQL data field and tuple
-
-(c) 1994-1996 Innobase Oy
-
-Created 5/30/1994 Heikki Tuuri
-*************************************************************************/
-
-#ifndef data0data_h
-#define data0data_h
-
-#include "univ.i"
-
-#include "data0types.h"
-#include "data0type.h"
-#include "mem0mem.h"
-#include "dict0types.h"
-
-typedef struct big_rec_struct big_rec_t;
-
-/* Some non-inlined functions used in the MySQL interface: */
-void
-dfield_set_data_noninline(
- dfield_t* field, /* in: field */
- void* data, /* in: data */
- ulint len); /* in: length or UNIV_SQL_NULL */
-void*
-dfield_get_data_noninline(
- dfield_t* field); /* in: field */
-ulint
-dfield_get_len_noninline(
- dfield_t* field); /* in: field */
-ulint
-dtuple_get_n_fields_noninline(
- dtuple_t* tuple); /* in: tuple */
-dfield_t*
-dtuple_get_nth_field_noninline(
- dtuple_t* tuple, /* in: tuple */
- ulint n); /* in: index of field */
-
-/*************************************************************************
-Gets pointer to the type struct of SQL data field. */
-UNIV_INLINE
-dtype_t*
-dfield_get_type(
-/*============*/
- /* out: pointer to the type struct */
- dfield_t* field); /* in: SQL data field */
-/*************************************************************************
-Sets the type struct of SQL data field. */
-UNIV_INLINE
-void
-dfield_set_type(
-/*============*/
- dfield_t* field, /* in: SQL data field */
- dtype_t* type); /* in: pointer to data type struct */
-/*************************************************************************
-Gets pointer to the data in a field. */
-UNIV_INLINE
-void*
-dfield_get_data(
-/*============*/
- /* out: pointer to data */
- dfield_t* field); /* in: field */
-/*************************************************************************
-Gets length of field data. */
-UNIV_INLINE
-ulint
-dfield_get_len(
-/*===========*/
- /* out: length of data; UNIV_SQL_NULL if
- SQL null data */
- dfield_t* field); /* in: field */
-/*************************************************************************
-Sets length in a field. */
-UNIV_INLINE
-void
-dfield_set_len(
-/*===========*/
- dfield_t* field, /* in: field */
- ulint len); /* in: length or UNIV_SQL_NULL */
-/*************************************************************************
-Sets pointer to the data and length in a field. */
-UNIV_INLINE
-void
-dfield_set_data(
-/*============*/
- dfield_t* field, /* in: field */
- const void* data, /* in: data */
- ulint len); /* in: length or UNIV_SQL_NULL */
-/**************************************************************************
-Writes an SQL null field full of zeros. */
-UNIV_INLINE
-void
-data_write_sql_null(
-/*================*/
- byte* data, /* in: pointer to a buffer of size len */
- ulint len); /* in: SQL null size in bytes */
-/*************************************************************************
-Copies the data and len fields. */
-UNIV_INLINE
-void
-dfield_copy_data(
-/*=============*/
- dfield_t* field1, /* in: field to copy to */
- dfield_t* field2);/* in: field to copy from */
-/*************************************************************************
-Copies a data field to another. */
-UNIV_INLINE
-void
-dfield_copy(
-/*========*/
- dfield_t* field1, /* in: field to copy to */
- dfield_t* field2);/* in: field to copy from */
-/*************************************************************************
-Tests if data length and content is equal for two dfields. */
-UNIV_INLINE
-ibool
-dfield_datas_are_binary_equal(
-/*==========================*/
- /* out: TRUE if equal */
- dfield_t* field1, /* in: field */
- dfield_t* field2);/* in: field */
-/*************************************************************************
-Tests if dfield data length and content is equal to the given. */
-
-ibool
-dfield_data_is_binary_equal(
-/*========================*/
- /* out: TRUE if equal */
- dfield_t* field, /* in: field */
- ulint len, /* in: data length or UNIV_SQL_NULL */
- byte* data); /* in: data */
-/*************************************************************************
-Gets number of fields in a data tuple. */
-UNIV_INLINE
-ulint
-dtuple_get_n_fields(
-/*================*/
- /* out: number of fields */
- dtuple_t* tuple); /* in: tuple */
-/*************************************************************************
-Gets nth field of a tuple. */
-UNIV_INLINE
-dfield_t*
-dtuple_get_nth_field(
-/*=================*/
- /* out: nth field */
- dtuple_t* tuple, /* in: tuple */
- ulint n); /* in: index of field */
-/*************************************************************************
-Gets info bits in a data tuple. */
-UNIV_INLINE
-ulint
-dtuple_get_info_bits(
-/*=================*/
- /* out: info bits */
- dtuple_t* tuple); /* in: tuple */
-/*************************************************************************
-Sets info bits in a data tuple. */
-UNIV_INLINE
-void
-dtuple_set_info_bits(
-/*=================*/
- dtuple_t* tuple, /* in: tuple */
- ulint info_bits); /* in: info bits */
-/*************************************************************************
-Gets number of fields used in record comparisons. */
-UNIV_INLINE
-ulint
-dtuple_get_n_fields_cmp(
-/*====================*/
- /* out: number of fields used in comparisons
- in rem0cmp.* */
- dtuple_t* tuple); /* in: tuple */
-/*************************************************************************
-Gets number of fields used in record comparisons. */
-UNIV_INLINE
-void
-dtuple_set_n_fields_cmp(
-/*====================*/
- dtuple_t* tuple, /* in: tuple */
- ulint n_fields_cmp); /* in: number of fields used in
- comparisons in rem0cmp.* */
-/**************************************************************
-Creates a data tuple to a memory heap. The default value for number
-of fields used in record comparisons for this tuple is n_fields. */
-UNIV_INLINE
-dtuple_t*
-dtuple_create(
-/*==========*/
- /* out, own: created tuple */
- mem_heap_t* heap, /* in: memory heap where the tuple
- is created */
- ulint n_fields); /* in: number of fields */
-
-/*************************************************************************
-Creates a dtuple for use in MySQL. */
-
-dtuple_t*
-dtuple_create_for_mysql(
-/*====================*/
- /* out, own created dtuple */
- void** heap, /* out: created memory heap */
- ulint n_fields); /* in: number of fields */
-/*************************************************************************
-Frees a dtuple used in MySQL. */
-
-void
-dtuple_free_for_mysql(
-/*==================*/
- void* heap);
-/*************************************************************************
-Sets number of fields used in a tuple. Normally this is set in
-dtuple_create, but if you want later to set it smaller, you can use this. */
-
-void
-dtuple_set_n_fields(
-/*================*/
- dtuple_t* tuple, /* in: tuple */
- ulint n_fields); /* in: number of fields */
-/**************************************************************
-The following function returns the sum of data lengths of a tuple. The space
-occupied by the field structs or the tuple struct is not counted. */
-UNIV_INLINE
-ulint
-dtuple_get_data_size(
-/*=================*/
- /* out: sum of data lens */
- dtuple_t* tuple); /* in: typed data tuple */
-/****************************************************************
-Returns TRUE if lengths of two dtuples are equal and respective data fields
-in them are equal when compared with collation in char fields (not as binary
-strings). */
-
-ibool
-dtuple_datas_are_ordering_equal(
-/*============================*/
- /* out: TRUE if length and fieds are equal
- when compared with cmp_data_data:
- NOTE: in character type fields some letters
- are identified with others! (collation) */
- dtuple_t* tuple1, /* in: tuple 1 */
- dtuple_t* tuple2);/* in: tuple 2 */
-/****************************************************************
-Folds a prefix given as the number of fields of a tuple. */
-UNIV_INLINE
-ulint
-dtuple_fold(
-/*========*/
- /* out: the folded value */
- dtuple_t* tuple, /* in: the tuple */
- ulint n_fields,/* in: number of complete fields to fold */
- ulint n_bytes,/* in: number of bytes to fold in an
- incomplete last field */
- dulint tree_id);/* in: index tree id */
-/***********************************************************************
-Sets types of fields binary in a tuple. */
-UNIV_INLINE
-void
-dtuple_set_types_binary(
-/*====================*/
- dtuple_t* tuple, /* in: data tuple */
- ulint n); /* in: number of fields to set */
-/**************************************************************************
-Checks if a dtuple contains an SQL null value. */
-UNIV_INLINE
-ibool
-dtuple_contains_null(
-/*=================*/
- /* out: TRUE if some field is SQL null */
- dtuple_t* tuple); /* in: dtuple */
-/**************************************************************
-Checks that a data field is typed. Asserts an error if not. */
-
-ibool
-dfield_check_typed(
-/*===============*/
- /* out: TRUE if ok */
- dfield_t* field); /* in: data field */
-/**************************************************************
-Checks that a data tuple is typed. Asserts an error if not. */
-
-ibool
-dtuple_check_typed(
-/*===============*/
- /* out: TRUE if ok */
- dtuple_t* tuple); /* in: tuple */
-/**************************************************************
-Checks that a data tuple is typed. */
-
-ibool
-dtuple_check_typed_no_assert(
-/*=========================*/
- /* out: TRUE if ok */
- dtuple_t* tuple); /* in: tuple */
-#ifdef UNIV_DEBUG
-/**************************************************************
-Validates the consistency of a tuple which must be complete, i.e,
-all fields must have been set. */
-
-ibool
-dtuple_validate(
-/*============*/
- /* out: TRUE if ok */
- dtuple_t* tuple); /* in: tuple */
-#endif /* UNIV_DEBUG */
-/*****************************************************************
-Pretty prints a dfield value according to its data type. */
-
-void
-dfield_print(
-/*=========*/
- dfield_t* dfield);/* in: dfield */
-/*****************************************************************
-Pretty prints a dfield value according to its data type. Also the hex string
-is printed if a string contains non-printable characters. */
-
-void
-dfield_print_also_hex(
-/*==================*/
- dfield_t* dfield); /* in: dfield */
-/**************************************************************
-The following function prints the contents of a tuple. */
-
-void
-dtuple_print(
-/*=========*/
- FILE* f, /* in: output stream */
- dtuple_t* tuple); /* in: tuple */
-/******************************************************************
-Moves parts of long fields in entry to the big record vector so that
-the size of tuple drops below the maximum record size allowed in the
-database. Moves data only from those fields which are not necessary
-to determine uniquely the insertion place of the tuple in the index. */
-
-big_rec_t*
-dtuple_convert_big_rec(
-/*===================*/
- /* out, own: created big record vector,
- NULL if we are not able to shorten
- the entry enough, i.e., if there are
- too many short fields in entry */
- dict_index_t* index, /* in: index */
- dtuple_t* entry, /* in: index entry */
- ulint* ext_vec,/* in: array of externally stored fields,
- or NULL: if a field already is externally
- stored, then we cannot move it to the vector
- this function returns */
- ulint n_ext_vec);/* in: number of elements is ext_vec */
-/******************************************************************
-Puts back to entry the data stored in vector. Note that to ensure the
-fields in entry can accommodate the data, vector must have been created
-from entry with dtuple_convert_big_rec. */
-
-void
-dtuple_convert_back_big_rec(
-/*========================*/
- dict_index_t* index, /* in: index */
- dtuple_t* entry, /* in: entry whose data was put to vector */
- big_rec_t* vector);/* in, own: big rec vector; it is
- freed in this function */
-/******************************************************************
-Frees the memory in a big rec vector. */
-
-void
-dtuple_big_rec_free(
-/*================*/
- big_rec_t* vector); /* in, own: big rec vector; it is
- freed in this function */
-
-/*######################################################################*/
-
-/* Structure for an SQL data field */
-struct dfield_struct{
- void* data; /* pointer to data */
- ulint len; /* data length; UNIV_SQL_NULL if SQL null; */
- dtype_t type; /* type of data */
-};
-
-struct dtuple_struct {
- ulint info_bits; /* info bits of an index record:
- the default is 0; this field is used
- if an index record is built from
- a data tuple */
- ulint n_fields; /* number of fields in dtuple */
- ulint n_fields_cmp; /* number of fields which should
- be used in comparison services
- of rem0cmp.*; the index search
- is performed by comparing only these
- fields, others are ignored; the
- default value in dtuple creation is
- the same value as n_fields */
- dfield_t* fields; /* fields */
- UT_LIST_NODE_T(dtuple_t) tuple_list;
- /* data tuples can be linked into a
- list using this field */
- ulint magic_n;
-};
-#define DATA_TUPLE_MAGIC_N 65478679
-
-/* A slot for a field in a big rec vector */
-
-typedef struct big_rec_field_struct big_rec_field_t;
-struct big_rec_field_struct {
- ulint field_no; /* field number in record */
- ulint len; /* stored data len */
- byte* data; /* stored data */
-};
-
-/* Storage format for overflow data in a big record, that is, a record
-which needs external storage of data fields */
-
-struct big_rec_struct {
- mem_heap_t* heap; /* memory heap from which allocated */
- ulint n_fields; /* number of stored fields */
- big_rec_field_t* fields; /* stored fields */
-};
-
-#ifndef UNIV_NONINL
-#include "data0data.ic"
-#endif
-
-#endif
diff --git a/storage/innobase/include/data0data.ic b/storage/innobase/include/data0data.ic
deleted file mode 100644
index 753fa9ba45f..00000000000
--- a/storage/innobase/include/data0data.ic
+++ /dev/null
@@ -1,436 +0,0 @@
-/************************************************************************
-SQL data field and tuple
-
-(c) 1994-1996 Innobase Oy
-
-Created 5/30/1994 Heikki Tuuri
-*************************************************************************/
-
-#include "mem0mem.h"
-#include "ut0rnd.h"
-
-#ifdef UNIV_DEBUG
-extern byte data_error;
-#endif /* UNIV_DEBUG */
-
-/*************************************************************************
-Gets pointer to the type struct of SQL data field. */
-UNIV_INLINE
-dtype_t*
-dfield_get_type(
-/*============*/
- /* out: pointer to the type struct */
- dfield_t* field) /* in: SQL data field */
-{
- ut_ad(field);
-
- return(&(field->type));
-}
-
-/*************************************************************************
-Sets the type struct of SQL data field. */
-UNIV_INLINE
-void
-dfield_set_type(
-/*============*/
- dfield_t* field, /* in: SQL data field */
- dtype_t* type) /* in: pointer to data type struct */
-{
- ut_ad(field && type);
-
- field->type = *type;
-}
-
-/*************************************************************************
-Gets pointer to the data in a field. */
-UNIV_INLINE
-void*
-dfield_get_data(
-/*============*/
- /* out: pointer to data */
- dfield_t* field) /* in: field */
-{
- ut_ad(field);
- ut_ad((field->len == UNIV_SQL_NULL)
- || (field->data != &data_error));
-
- return(field->data);
-}
-
-/*************************************************************************
-Gets length of field data. */
-UNIV_INLINE
-ulint
-dfield_get_len(
-/*===========*/
- /* out: length of data; UNIV_SQL_NULL if
- SQL null data */
- dfield_t* field) /* in: field */
-{
- ut_ad(field);
- ut_ad((field->len == UNIV_SQL_NULL)
- || (field->data != &data_error));
-
- return(field->len);
-}
-
-/*************************************************************************
-Sets length in a field. */
-UNIV_INLINE
-void
-dfield_set_len(
-/*===========*/
- dfield_t* field, /* in: field */
- ulint len) /* in: length or UNIV_SQL_NULL */
-{
- ut_ad(field);
-
- field->len = len;
-}
-
-/*************************************************************************
-Sets pointer to the data and length in a field. */
-UNIV_INLINE
-void
-dfield_set_data(
-/*============*/
- dfield_t* field, /* in: field */
- const void* data, /* in: data */
- ulint len) /* in: length or UNIV_SQL_NULL */
-{
- ut_ad(field);
-
- field->data = (void*) data;
- field->len = len;
-}
-
-/*************************************************************************
-Copies the data and len fields. */
-UNIV_INLINE
-void
-dfield_copy_data(
-/*=============*/
- dfield_t* field1, /* in: field to copy to */
- dfield_t* field2) /* in: field to copy from */
-{
- ut_ad(field1 && field2);
-
- field1->data = field2->data;
- field1->len = field2->len;
-}
-
-/*************************************************************************
-Copies a data field to another. */
-UNIV_INLINE
-void
-dfield_copy(
-/*========*/
- dfield_t* field1, /* in: field to copy to */
- dfield_t* field2) /* in: field to copy from */
-{
- *field1 = *field2;
-}
-
-/*************************************************************************
-Tests if data length and content is equal for two dfields. */
-UNIV_INLINE
-ibool
-dfield_datas_are_binary_equal(
-/*==========================*/
- /* out: TRUE if equal */
- dfield_t* field1, /* in: field */
- dfield_t* field2) /* in: field */
-{
- ulint len;
-
- len = field1->len;
-
- if ((len != field2->len)
- || ((len != UNIV_SQL_NULL)
- && (0 != ut_memcmp(field1->data, field2->data,
- len)))) {
-
- return(FALSE);
- }
-
- return(TRUE);
-}
-
-/*************************************************************************
-Gets info bits in a data tuple. */
-UNIV_INLINE
-ulint
-dtuple_get_info_bits(
-/*=================*/
- /* out: info bits */
- dtuple_t* tuple) /* in: tuple */
-{
- ut_ad(tuple);
-
- return(tuple->info_bits);
-}
-
-/*************************************************************************
-Sets info bits in a data tuple. */
-UNIV_INLINE
-void
-dtuple_set_info_bits(
-/*=================*/
- dtuple_t* tuple, /* in: tuple */
- ulint info_bits) /* in: info bits */
-{
- ut_ad(tuple);
-
- tuple->info_bits = info_bits;
-}
-
-/*************************************************************************
-Gets number of fields used in record comparisons. */
-UNIV_INLINE
-ulint
-dtuple_get_n_fields_cmp(
-/*====================*/
- /* out: number of fields used in comparisons
- in rem0cmp.* */
- dtuple_t* tuple) /* in: tuple */
-{
- ut_ad(tuple);
-
- return(tuple->n_fields_cmp);
-}
-
-/*************************************************************************
-Sets number of fields used in record comparisons. */
-UNIV_INLINE
-void
-dtuple_set_n_fields_cmp(
-/*====================*/
- dtuple_t* tuple, /* in: tuple */
- ulint n_fields_cmp) /* in: number of fields used in
- comparisons in rem0cmp.* */
-{
- ut_ad(tuple);
- ut_ad(n_fields_cmp <= tuple->n_fields);
-
- tuple->n_fields_cmp = n_fields_cmp;
-}
-
-/*************************************************************************
-Gets number of fields in a data tuple. */
-UNIV_INLINE
-ulint
-dtuple_get_n_fields(
-/*================*/
- /* out: number of fields */
- dtuple_t* tuple) /* in: tuple */
-{
- ut_ad(tuple);
-
- return(tuple->n_fields);
-}
-
-/*************************************************************************
-Gets nth field of a tuple. */
-UNIV_INLINE
-dfield_t*
-dtuple_get_nth_field(
-/*=================*/
- /* out: nth field */
- dtuple_t* tuple, /* in: tuple */
- ulint n) /* in: index of field */
-{
- ut_ad(tuple);
- ut_ad(n < tuple->n_fields);
-
- return(tuple->fields + n);
-}
-
-/**************************************************************
-Creates a data tuple to a memory heap. The default value for number
-of fields used in record comparisons for this tuple is n_fields. */
-UNIV_INLINE
-dtuple_t*
-dtuple_create(
-/*==========*/
- /* out, own: created tuple */
- mem_heap_t* heap, /* in: memory heap where the tuple
- is created */
- ulint n_fields) /* in: number of fields */
-{
- dtuple_t* tuple;
-
- ut_ad(heap);
-
- tuple = (dtuple_t*) mem_heap_alloc(heap, sizeof(dtuple_t)
- + n_fields * sizeof(dfield_t));
- tuple->info_bits = 0;
- tuple->n_fields = n_fields;
- tuple->n_fields_cmp = n_fields;
- tuple->fields = (dfield_t*)(((byte*)tuple) + sizeof(dtuple_t));
-
-#ifdef UNIV_DEBUG
- tuple->magic_n = DATA_TUPLE_MAGIC_N;
-
- { /* In the debug version, initialize fields to an error value */
- ulint i;
-
- for (i = 0; i < n_fields; i++) {
- (tuple->fields + i)->data = &data_error;
- dfield_get_type(tuple->fields + i)->mtype = DATA_ERROR;
- }
- }
-#endif
- return(tuple);
-}
-
-/**************************************************************
-The following function returns the sum of data lengths of a tuple. The space
-occupied by the field structs or the tuple struct is not counted. Neither
-is possible space in externally stored parts of the field. */
-UNIV_INLINE
-ulint
-dtuple_get_data_size(
-/*=================*/
- /* out: sum of data lengths */
- dtuple_t* tuple) /* in: typed data tuple */
-{
- dfield_t* field;
- ulint n_fields;
- ulint len;
- ulint i;
- ulint sum = 0;
-
- ut_ad(tuple);
- ut_ad(dtuple_check_typed(tuple));
- ut_ad(tuple->magic_n == DATA_TUPLE_MAGIC_N);
-
- n_fields = tuple->n_fields;
-
- for (i = 0; i < n_fields; i++) {
- field = dtuple_get_nth_field(tuple, i);
- len = dfield_get_len(field);
-
- if (len == UNIV_SQL_NULL) {
- len = dtype_get_sql_null_size(dfield_get_type(field));
- }
-
- sum += len;
- }
-
- return(sum);
-}
-
-/***********************************************************************
-Sets types of fields binary in a tuple. */
-UNIV_INLINE
-void
-dtuple_set_types_binary(
-/*====================*/
- dtuple_t* tuple, /* in: data tuple */
- ulint n) /* in: number of fields to set */
-{
- dtype_t* dfield_type;
- ulint i;
-
- for (i = 0; i < n; i++) {
- dfield_type = dfield_get_type(dtuple_get_nth_field(tuple, i));
- dtype_set(dfield_type, DATA_BINARY, 0, 0);
- }
-}
-
-/****************************************************************
-Folds a prefix given as the number of fields of a tuple. */
-UNIV_INLINE
-ulint
-dtuple_fold(
-/*========*/
- /* out: the folded value */
- dtuple_t* tuple, /* in: the tuple */
- ulint n_fields,/* in: number of complete fields to fold */
- ulint n_bytes,/* in: number of bytes to fold in an
- incomplete last field */
- dulint tree_id)/* in: index tree id */
-{
- dfield_t* field;
- ulint i;
- byte* data;
- ulint len;
- ulint fold;
-
- ut_ad(tuple);
- ut_ad(tuple->magic_n == DATA_TUPLE_MAGIC_N);
- ut_ad(dtuple_check_typed(tuple));
-
- fold = ut_fold_dulint(tree_id);
-
- for (i = 0; i < n_fields; i++) {
- field = dtuple_get_nth_field(tuple, i);
-
- data = (byte*) dfield_get_data(field);
- len = dfield_get_len(field);
-
- if (len != UNIV_SQL_NULL) {
- fold = ut_fold_ulint_pair(fold,
- ut_fold_binary(data, len));
- }
- }
-
- if (n_bytes > 0) {
- field = dtuple_get_nth_field(tuple, i);
-
- data = (byte*) dfield_get_data(field);
- len = dfield_get_len(field);
-
- if (len != UNIV_SQL_NULL) {
- if (len > n_bytes) {
- len = n_bytes;
- }
-
- fold = ut_fold_ulint_pair(fold,
- ut_fold_binary(data, len));
- }
- }
-
- return(fold);
-}
-
-/**************************************************************************
-Writes an SQL null field full of zeros. */
-UNIV_INLINE
-void
-data_write_sql_null(
-/*================*/
- byte* data, /* in: pointer to a buffer of size len */
- ulint len) /* in: SQL null size in bytes */
-{
- ulint j;
-
- for (j = 0; j < len; j++) {
- data[j] = '\0';
- }
-}
-
-/**************************************************************************
-Checks if a dtuple contains an SQL null value. */
-UNIV_INLINE
-ibool
-dtuple_contains_null(
-/*=================*/
- /* out: TRUE if some field is SQL null */
- dtuple_t* tuple) /* in: dtuple */
-{
- ulint n;
- ulint i;
-
- n = dtuple_get_n_fields(tuple);
-
- for (i = 0; i < n; i++) {
- if (dfield_get_len(dtuple_get_nth_field(tuple, i))
- == UNIV_SQL_NULL) {
-
- return(TRUE);
- }
- }
-
- return(FALSE);
-}
diff --git a/storage/innobase/include/data0types.h b/storage/innobase/include/data0types.h
deleted file mode 100644
index ab314f8f471..00000000000
--- a/storage/innobase/include/data0types.h
+++ /dev/null
@@ -1,19 +0,0 @@
-/************************************************************************
-Some type definitions
-
-(c) 1994-2000 Innobase Oy
-
-Created 9/21/2000 Heikki Tuuri
-*************************************************************************/
-
-#ifndef data0types_h
-#define data0types_h
-
-/* SQL data field struct */
-typedef struct dfield_struct dfield_t;
-
-/* SQL data tuple struct */
-typedef struct dtuple_struct dtuple_t;
-
-#endif
-
diff --git a/storage/innobase/include/db0err.h b/storage/innobase/include/db0err.h
deleted file mode 100644
index ed7ce151718..00000000000
--- a/storage/innobase/include/db0err.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/******************************************************
-Global error codes for the database
-
-(c) 1996 Innobase Oy
-
-Created 5/24/1996 Heikki Tuuri
-*******************************************************/
-
-#ifndef db0err_h
-#define db0err_h
-
-
-#define DB_SUCCESS 10
-
-/* The following are error codes */
-#define DB_ERROR 11
-#define DB_OUT_OF_MEMORY 12
-#define DB_OUT_OF_FILE_SPACE 13
-#define DB_LOCK_WAIT 14
-#define DB_DEADLOCK 15
-#define DB_ROLLBACK 16
-#define DB_DUPLICATE_KEY 17
-#define DB_QUE_THR_SUSPENDED 18
-#define DB_MISSING_HISTORY 19 /* required history data has been
- deleted due to lack of space in
- rollback segment */
-#define DB_CLUSTER_NOT_FOUND 30
-#define DB_TABLE_NOT_FOUND 31
-#define DB_MUST_GET_MORE_FILE_SPACE 32 /* the database has to be stopped
- and restarted with more file space */
-#define DB_TABLE_IS_BEING_USED 33
-#define DB_TOO_BIG_RECORD 34 /* a record in an index would become
- bigger than 1/2 free space in a page
- frame */
-#define DB_LOCK_WAIT_TIMEOUT 35 /* lock wait lasted too long */
-#define DB_NO_REFERENCED_ROW 36 /* referenced key value not found
- for a foreign key in an insert or
- update of a row */
-#define DB_ROW_IS_REFERENCED 37 /* cannot delete or update a row
- because it contains a key value
- which is referenced */
-#define DB_CANNOT_ADD_CONSTRAINT 38 /* adding a foreign key constraint
- to a table failed */
-#define DB_CORRUPTION 39 /* data structure corruption noticed */
-#define DB_COL_APPEARS_TWICE_IN_INDEX 40/* InnoDB cannot handle an index
- where same column appears twice */
-#define DB_CANNOT_DROP_CONSTRAINT 41 /* dropping a foreign key constraint
- from a table failed */
-#define DB_NO_SAVEPOINT 42 /* no savepoint exists with the given
- name */
-#define DB_TABLESPACE_ALREADY_EXISTS 43 /* we cannot create a new single-table
- tablespace because a file of the same
- name already exists */
-#define DB_TABLESPACE_DELETED 44 /* tablespace does not exist or is
- being dropped right now */
-#define DB_LOCK_TABLE_FULL 45 /* lock structs have exhausted the
- buffer pool (for big transactions,
- InnoDB stores the lock structs in the
- buffer pool) */
-#define DB_FOREIGN_DUPLICATE_KEY 46 /* foreign key constraints
- activated by the operation would
- lead to a duplicate key in some
- table */
-#define DB_TOO_MANY_CONCURRENT_TRXS 47 /* when InnoDB runs out of the
- preconfigured undo slots, this can
- only happen when there are too many
- concurrent transactions */
-#define DB_UNSUPPORTED 48 /* when InnoDB sees any artefact or
- a feature that it can't recoginize or
- work with e.g., FT indexes created by
- a later version of the engine. */
-/* The following are partial failure codes */
-#define DB_FAIL 1000
-#define DB_OVERFLOW 1001
-#define DB_UNDERFLOW 1002
-#define DB_STRONG_FAIL 1003
-#define DB_RECORD_NOT_FOUND 1500
-#define DB_END_OF_INDEX 1501
-
-#endif
diff --git a/storage/innobase/include/dict0crea.ic b/storage/innobase/include/dict0crea.ic
deleted file mode 100644
index b4da2d7e03f..00000000000
--- a/storage/innobase/include/dict0crea.ic
+++ /dev/null
@@ -1,8 +0,0 @@
-/******************************************************
-Database object creation
-
-(c) 1996 Innobase Oy
-
-Created 1/8/1996 Heikki Tuuri
-*******************************************************/
-
diff --git a/storage/innobase/include/dict0dict.h b/storage/innobase/include/dict0dict.h
deleted file mode 100644
index 7d5ff09c7a6..00000000000
--- a/storage/innobase/include/dict0dict.h
+++ /dev/null
@@ -1,1002 +0,0 @@
-/******************************************************
-Data dictionary system
-
-(c) 1996 Innobase Oy
-
-Created 1/8/1996 Heikki Tuuri
-*******************************************************/
-
-#ifndef dict0dict_h
-#define dict0dict_h
-
-#include "univ.i"
-#include "dict0types.h"
-#include "dict0mem.h"
-#include "data0type.h"
-#include "data0data.h"
-#include "sync0sync.h"
-#include "sync0rw.h"
-#include "mem0mem.h"
-#include "rem0types.h"
-#include "btr0types.h"
-#include "ut0mem.h"
-#include "ut0lst.h"
-#include "hash0hash.h"
-#include "ut0rnd.h"
-#include "ut0byte.h"
-#include "trx0types.h"
-
-#ifndef UNIV_HOTBACKUP
-/**********************************************************************
-Makes all characters in a NUL-terminated UTF-8 string lower case. */
-
-void
-dict_casedn_str(
-/*============*/
- char* a); /* in/out: string to put in lower case */
-#endif /* !UNIV_HOTBACKUP */
-/************************************************************************
-Get the database name length in a table name. */
-
-ulint
-dict_get_db_name_len(
-/*=================*/
- /* out: database name length */
- const char* name); /* in: table name in the form
- dbname '/' tablename */
-/************************************************************************
-Return the end of table name where we have removed dbname and '/'. */
-
-const char*
-dict_remove_db_name(
-/*================*/
- /* out: table name */
- const char* name); /* in: table name in the form
- dbname '/' tablename */
-/************************************************************************
-Decrements the count of open MySQL handles to a table. */
-
-void
-dict_table_decrement_handle_count(
-/*==============================*/
- dict_table_t* table); /* in: table */
-/**************************************************************************
-Inits the data dictionary module. */
-
-void
-dict_init(void);
-/*===========*/
-/************************************************************************
-Gets the space id of every table of the data dictionary and makes a linear
-list and a hash table of them to the data dictionary cache. This function
-can be called at database startup if we did not need to do a crash recovery.
-In crash recovery we must scan the space id's from the .ibd files in MySQL
-database directories. */
-
-void
-dict_load_space_id_list(void);
-/*=========================*/
-/*************************************************************************
-Gets the column data type. */
-UNIV_INLINE
-void
-dict_col_copy_type(
-/*===============*/
- const dict_col_t* col, /* in: column */
- dtype_t* type); /* out: data type */
-/*************************************************************************
-Gets the column data type. */
-
-void
-dict_col_copy_type_noninline(
-/*=========================*/
- const dict_col_t* col, /* in: column */
- dtype_t* type); /* out: data type */
-#ifdef UNIV_DEBUG
-/*************************************************************************
-Assert that a column and a data type match. */
-UNIV_INLINE
-ibool
-dict_col_type_assert_equal(
-/*=======================*/
- /* out: TRUE */
- const dict_col_t* col, /* in: column */
- const dtype_t* type); /* in: data type */
-#endif /* UNIV_DEBUG */
-/***************************************************************************
-Returns the minimum size of the column. */
-UNIV_INLINE
-ulint
-dict_col_get_min_size(
-/*==================*/
- /* out: minimum size */
- const dict_col_t* col); /* in: column */
-/***************************************************************************
-Returns the maximum size of the column. */
-UNIV_INLINE
-ulint
-dict_col_get_max_size(
-/*==================*/
- /* out: maximum size */
- const dict_col_t* col); /* in: column */
-/***************************************************************************
-Returns the size of a fixed size column, 0 if not a fixed size column. */
-UNIV_INLINE
-ulint
-dict_col_get_fixed_size(
-/*====================*/
- /* out: fixed size, or 0 */
- const dict_col_t* col); /* in: column */
-/***************************************************************************
-Returns the ROW_FORMAT=REDUNDANT stored SQL NULL size of a column.
-For fixed length types it is the fixed length of the type, otherwise 0. */
-UNIV_INLINE
-ulint
-dict_col_get_sql_null_size(
-/*=======================*/
- /* out: SQL null storage size
- in ROW_FORMAT=REDUNDANT */
- const dict_col_t* col); /* in: column */
-
-/*************************************************************************
-Gets the column number. */
-UNIV_INLINE
-ulint
-dict_col_get_no(
-/*============*/
- const dict_col_t* col);
-/*************************************************************************
-Gets the column position in the clustered index. */
-UNIV_INLINE
-ulint
-dict_col_get_clust_pos(
-/*===================*/
- const dict_col_t* col, /* in: table column */
- const dict_index_t* clust_index); /* in: clustered index */
-/*************************************************************************
-Gets the column position in the clustered index. */
-
-ulint
-dict_col_get_clust_pos_noninline(
-/*=============================*/
- const dict_col_t* col, /* in: table column */
- const dict_index_t* clust_index); /* in: clustered index */
-/********************************************************************
-If the given column name is reserved for InnoDB system columns, return
-TRUE. */
-
-ibool
-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 */
-/************************************************************************
-Unconditionally set the autoinc counter. */
-
-void
-dict_table_autoinc_initialize(
-/*==========================*/
- dict_table_t* table, /* in: table */
- ib_ulonglong value); /* in: next value to assign to a row */
-/************************************************************************
-Reads the next autoinc value (== autoinc counter value), 0 if not yet
-initialized. */
-
-ib_ulonglong
-dict_table_autoinc_read(
-/*====================*/
- /* out: value for a new row, or 0 */
- dict_table_t* table); /* in: table */
-/************************************************************************
-Updates the autoinc counter if the value supplied is greater than the
-current value. */
-
-void
-dict_table_autoinc_update_if_greater(
-/*=================================*/
-
- dict_table_t* table, /* in: table */
- ib_ulonglong 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. */
-
-void
-dict_table_add_system_columns(
-/*==========================*/
- dict_table_t* table, /* in/out: table */
- mem_heap_t* heap); /* in: temporary heap */
-/**************************************************************************
-Adds a table object to the dictionary cache. */
-
-void
-dict_table_add_to_cache(
-/*====================*/
- dict_table_t* table, /* in: table */
- mem_heap_t* heap); /* in: temporary heap */
-/**************************************************************************
-Removes a table object from the dictionary cache. */
-
-void
-dict_table_remove_from_cache(
-/*=========================*/
- dict_table_t* table); /* in, own: table */
-/**************************************************************************
-Renames a table object. */
-
-ibool
-dict_table_rename_in_cache(
-/*=======================*/
- /* out: TRUE if success */
- dict_table_t* table, /* in: table */
- const char* new_name, /* in: new name */
- ibool rename_also_foreigns);/* in: in ALTER TABLE we want
- to preserve the original table name
- in constraints which reference it */
-/**************************************************************************
-Change the id of a table object in the dictionary cache. This is used in
-DISCARD TABLESPACE. */
-
-void
-dict_table_change_id_in_cache(
-/*==========================*/
- dict_table_t* table, /* in: table object already in cache */
- dulint new_id);/* in: new id to set */
-/**************************************************************************
-Adds a foreign key constraint object to the dictionary cache. May free
-the object if there already is an object with the same identifier in.
-At least one of foreign table or referenced table must already be in
-the dictionary cache! */
-
-ulint
-dict_foreign_add_to_cache(
-/*======================*/
- /* out: DB_SUCCESS or error code */
- dict_foreign_t* foreign, /* in, own: foreign key constraint */
- ibool check_charsets);/* in: TRUE=check charset
- compatibility */
-/*************************************************************************
-Checks if a table is referenced by foreign keys. */
-
-ibool
-dict_table_referenced_by_foreign_key(
-/*=================================*/
- /* out: TRUE if table is referenced by a
- foreign key */
- dict_table_t* table); /* in: InnoDB table */
-/**************************************************************************
-Determines whether a string starts with the specified keyword. */
-
-ibool
-dict_str_starts_with_keyword(
-/*=========================*/
- /* out: TRUE if str starts
- with keyword */
- void* mysql_thd, /* in: MySQL thread handle */
- const char* str, /* in: string to scan for keyword */
- const char* keyword); /* in: keyword to look for */
-/*************************************************************************
-Scans a table create SQL string and adds to the data dictionary
-the foreign key constraints declared in the string. This function
-should be called after the indexes for a table have been created.
-Each foreign key constraint must be accompanied with indexes in
-bot participating tables. The indexes are allowed to contain more
-fields than mentioned in the constraint. */
-
-ulint
-dict_create_foreign_constraints(
-/*============================*/
- /* out: error code or DB_SUCCESS */
- trx_t* trx, /* in: transaction */
- const char* sql_string, /* in: table create statement where
- foreign keys are declared like:
- FOREIGN KEY (a, b) REFERENCES
- table2(c, d), table2 can be written
- also with the database
- name before it: test.table2; the
- default database id the database of
- parameter name */
- const char* name, /* in: table full name in the
- normalized form
- database_name/table_name */
- ibool reject_fks); /* in: if TRUE, fail with error
- code DB_CANNOT_ADD_CONSTRAINT if
- any foreign keys are found. */
-/**************************************************************************
-Parses the CONSTRAINT id's to be dropped in an ALTER TABLE statement. */
-
-ulint
-dict_foreign_parse_drop_constraints(
-/*================================*/
- /* out: DB_SUCCESS or
- DB_CANNOT_DROP_CONSTRAINT if
- syntax error or the constraint
- id does not match */
- mem_heap_t* heap, /* in: heap from which we can
- allocate memory */
- trx_t* trx, /* in: transaction */
- dict_table_t* table, /* in: table */
- ulint* n, /* out: number of constraints
- to drop */
- const char*** constraints_to_drop); /* out: id's of the
- constraints to drop */
-/**************************************************************************
-Returns a table object and optionally increment its MySQL open handle count.
-NOTE! This is a high-level function to be used mainly from outside the
-'dict' directory. Inside this directory dict_table_get_low is usually the
-appropriate function. */
-
-dict_table_t*
-dict_table_get(
-/*===========*/
- /* out: table, NULL if
- does not exist */
- const char* table_name, /* in: table name */
- ibool inc_mysql_count);
- /* in: whether to increment the open
- handle count on the table */
-/**************************************************************************
-Returns a table object based on table id. */
-
-dict_table_t*
-dict_table_get_on_id(
-/*=================*/
- /* out: table, NULL if does not exist */
- dulint table_id, /* in: table id */
- trx_t* trx); /* in: transaction handle */
-/**************************************************************************
-Returns a table object based on table id. */
-UNIV_INLINE
-dict_table_t*
-dict_table_get_on_id_low(
-/*=====================*/
- /* out: table, NULL if does not exist */
- dulint table_id); /* in: table id */
-/**************************************************************************
-Checks if a table is in the dictionary cache. */
-UNIV_INLINE
-dict_table_t*
-dict_table_check_if_in_cache_low(
-/*=============================*/
- /* out: table, NULL if not found */
- const char* table_name); /* in: table name */
-/**************************************************************************
-Gets a table; loads it to the dictionary cache if necessary. A low-level
-function. */
-UNIV_INLINE
-dict_table_t*
-dict_table_get_low(
-/*===============*/
- /* out: table, NULL if not found */
- const char* table_name); /* in: table name */
-/**************************************************************************
-A noninlined version of dict_table_get_low. */
-
-dict_table_t*
-dict_table_get_low_noninlined(
-/*==========================*/
- /* out: table, NULL if not found */
- const char* table_name); /* in: table name */
-/**************************************************************************
-Returns an index object. */
-UNIV_INLINE
-dict_index_t*
-dict_table_get_index(
-/*=================*/
- /* out: index, NULL if does not exist */
- dict_table_t* table, /* in: table */
- const char* name); /* in: index name */
-/**************************************************************************
-Returns an index object. */
-
-dict_index_t*
-dict_table_get_index_noninline(
-/*===========================*/
- /* out: index, NULL if does not exist */
- dict_table_t* table, /* in: table */
- const char* name); /* in: index name */
-/**************************************************************************
-Returns a column's name. */
-
-const char*
-dict_table_get_col_name(
-/*====================*/
- /* out: column name. NOTE: not
- guaranteed to stay valid if table is
- modified in any way (columns added,
- etc.). */
- const dict_table_t* table, /* in: table */
- ulint col_nr);/* in: column number */
-
-/**************************************************************************
-Prints a table definition. */
-
-void
-dict_table_print(
-/*=============*/
- dict_table_t* table); /* in: table */
-/**************************************************************************
-Prints a table data. */
-
-void
-dict_table_print_low(
-/*=================*/
- dict_table_t* table); /* in: table */
-/**************************************************************************
-Prints a table data when we know the table name. */
-
-void
-dict_table_print_by_name(
-/*=====================*/
- const char* name);
-/**************************************************************************
-Outputs info on foreign keys of a table. */
-
-void
-dict_print_info_on_foreign_keys(
-/*============================*/
- ibool create_table_format, /* in: if TRUE then print in
- a format suitable to be inserted into
- a CREATE TABLE, otherwise in the format
- of SHOW TABLE STATUS */
- FILE* file, /* in: file where to print */
- trx_t* trx, /* in: transaction */
- dict_table_t* table); /* in: table */
-/**************************************************************************
-Outputs info on a foreign key of a table in a format suitable for
-CREATE TABLE. */
-void
-dict_print_info_on_foreign_key_in_create_format(
-/*============================================*/
- FILE* file, /* in: file where to print */
- trx_t* trx, /* in: transaction */
- dict_foreign_t* foreign, /* in: foreign key constraint */
- ibool add_newline); /* in: whether to add a newline */
-/************************************************************************
-Displays the names of the index and the table. */
-void
-dict_index_name_print(
-/*==================*/
- FILE* file, /* in: output stream */
- trx_t* trx, /* in: transaction */
- const dict_index_t* index); /* in: index to print */
-/************************************************************************
-Gets the first index on the table (the clustered index). */
-UNIV_INLINE
-dict_index_t*
-dict_table_get_first_index(
-/*=======================*/
- /* out: index, NULL if none exists */
- dict_table_t* table); /* in: table */
-/************************************************************************
-Gets the first index on the table (the clustered index). */
-
-dict_index_t*
-dict_table_get_first_index_noninline(
-/*=================================*/
- /* out: index, NULL if none exists */
- dict_table_t* table); /* in: table */
-/************************************************************************
-Gets the next index on the table. */
-UNIV_INLINE
-dict_index_t*
-dict_table_get_next_index(
-/*======================*/
- /* out: index, NULL if none left */
- dict_index_t* index); /* in: index */
-/************************************************************************
-Gets the next index on the table. */
-
-dict_index_t*
-dict_table_get_next_index_noninline(
-/*================================*/
- /* out: index, NULL if none left */
- dict_index_t* index); /* in: index */
-/************************************************************************
-Gets the number of user-defined columns in a table in the dictionary
-cache. */
-UNIV_INLINE
-ulint
-dict_table_get_n_user_cols(
-/*=======================*/
- /* out: number of user-defined (e.g., not
- ROW_ID) columns of a table */
- dict_table_t* table); /* in: table */
-/************************************************************************
-Gets the number of system columns in a table in the dictionary cache. */
-UNIV_INLINE
-ulint
-dict_table_get_n_sys_cols(
-/*======================*/
- /* out: number of system (e.g.,
- ROW_ID) columns of a table */
- dict_table_t* table); /* in: table */
-/************************************************************************
-Gets the number of all columns (also system) in a table in the dictionary
-cache. */
-UNIV_INLINE
-ulint
-dict_table_get_n_cols(
-/*==================*/
- /* out: number of columns of a table */
- dict_table_t* table); /* in: table */
-/************************************************************************
-Gets the nth column of a table. */
-UNIV_INLINE
-const dict_col_t*
-dict_table_get_nth_col(
-/*===================*/
- /* out: pointer to column object */
- const dict_table_t* table, /* in: table */
- ulint pos); /* in: position of column */
-/************************************************************************
-Gets the nth column of a table. */
-
-const dict_col_t*
-dict_table_get_nth_col_noninline(
-/*=============================*/
- /* out: pointer to column object */
- const dict_table_t* table, /* in: table */
- ulint pos); /* in: position of column */
-/************************************************************************
-Gets the given system column of a table. */
-UNIV_INLINE
-const dict_col_t*
-dict_table_get_sys_col(
-/*===================*/
- /* out: pointer to column object */
- const dict_table_t* table, /* in: table */
- ulint sys); /* in: DATA_ROW_ID, ... */
-/************************************************************************
-Gets the given system column number of a table. */
-UNIV_INLINE
-ulint
-dict_table_get_sys_col_no(
-/*======================*/
- /* out: column number */
- dict_table_t* table, /* in: table */
- ulint sys); /* in: DATA_ROW_ID, ... */
-/************************************************************************
-Check whether the table uses the compact page format. */
-UNIV_INLINE
-ibool
-dict_table_is_comp(
-/*===============*/
- /* out: TRUE if table uses the
- compact page format */
- const dict_table_t* table); /* in: table */
-/************************************************************************
-Check whether the table uses the compact page format. */
-
-ibool
-dict_table_is_comp_noninline(
-/*=========================*/
- /* out: TRUE if table uses the
- compact page format */
- const dict_table_t* table); /* in: table */
-/************************************************************************
-Checks if a column is in the ordering columns of the clustered index of a
-table. Column prefixes are treated like whole columns. */
-
-ibool
-dict_table_col_in_clustered_key(
-/*============================*/
- /* out: TRUE if the column, or its prefix, is
- in the clustered key */
- dict_table_t* table, /* in: table */
- ulint n); /* in: column number */
-/***********************************************************************
-Copies types of columns contained in table to tuple. */
-
-void
-dict_table_copy_types(
-/*==================*/
- dtuple_t* tuple, /* in: data tuple */
- dict_table_t* table); /* in: index */
-/**************************************************************************
-Looks for an index with the given id. NOTE that we do not reserve
-the dictionary mutex: this function is for emergency purposes like
-printing info of a corrupt database page! */
-
-dict_index_t*
-dict_index_find_on_id_low(
-/*======================*/
- /* out: index or NULL if not found from cache */
- dulint id); /* in: index id */
-/**************************************************************************
-Adds an index to the dictionary cache. */
-
-void
-dict_index_add_to_cache(
-/*====================*/
- dict_table_t* table, /* in: table on which the index is */
- dict_index_t* index, /* in, own: index; NOTE! The index memory
- object is freed in this function! */
- ulint page_no);/* in: root page number of the index */
-/************************************************************************
-Gets the number of fields in the internal representation of an index,
-including fields added by the dictionary system. */
-UNIV_INLINE
-ulint
-dict_index_get_n_fields(
-/*====================*/
- /* out: number of fields */
- dict_index_t* index); /* in: an internal representation of index
- (in the dictionary cache) */
-/************************************************************************
-Gets the number of fields in the internal representation of an index
-that uniquely determine the position of an index entry in the index, if
-we do not take multiversioning into account: in the B-tree use the value
-returned by dict_index_get_n_unique_in_tree. */
-UNIV_INLINE
-ulint
-dict_index_get_n_unique(
-/*====================*/
- /* out: number of fields */
- dict_index_t* index); /* in: an internal representation of index
- (in the dictionary cache) */
-/************************************************************************
-Gets the number of fields in the internal representation of an index
-which uniquely determine the position of an index entry in the index, if
-we also take multiversioning into account. */
-UNIV_INLINE
-ulint
-dict_index_get_n_unique_in_tree(
-/*============================*/
- /* out: number of fields */
- dict_index_t* index); /* in: an internal representation of index
- (in the dictionary cache) */
-/************************************************************************
-Gets the number of user-defined ordering fields in the index. In the internal
-representation we add the row id to the ordering fields to make all indexes
-unique, but this function returns the number of fields the user defined
-in the index as ordering fields. */
-UNIV_INLINE
-ulint
-dict_index_get_n_ordering_defined_by_user(
-/*======================================*/
- /* out: number of fields */
- dict_index_t* index); /* in: an internal representation of index
- (in the dictionary cache) */
-/************************************************************************
-Gets the nth field of an index. */
-UNIV_INLINE
-dict_field_t*
-dict_index_get_nth_field(
-/*=====================*/
- /* out: pointer to field object */
- dict_index_t* index, /* in: index */
- ulint pos); /* in: position of field */
-/************************************************************************
-Gets pointer to the nth column in an index. */
-UNIV_INLINE
-const dict_col_t*
-dict_index_get_nth_col(
-/*===================*/
- /* out: column */
- const dict_index_t* index, /* in: index */
- ulint pos); /* in: position of the field */
-/************************************************************************
-Gets the column number of the nth field in an index. */
-UNIV_INLINE
-ulint
-dict_index_get_nth_col_no(
-/*======================*/
- /* out: column number */
- const dict_index_t* index, /* in: index */
- ulint pos); /* in: position of the field */
-/************************************************************************
-Looks for column n in an index. */
-
-ulint
-dict_index_get_nth_col_pos(
-/*=======================*/
- /* out: position in internal representation
- of the index; if not contained, returns
- ULINT_UNDEFINED */
- dict_index_t* index, /* in: index */
- ulint n); /* in: column number */
-/************************************************************************
-Returns TRUE if the index contains a column or a prefix of that column. */
-
-ibool
-dict_index_contains_col_or_prefix(
-/*==============================*/
- /* out: TRUE if contains the column or its
- prefix */
- dict_index_t* index, /* in: index */
- ulint n); /* in: column number */
-/************************************************************************
-Looks for a matching field in an index. The column has to be the same. The
-column in index must be complete, or must contain a prefix longer than the
-column in index2. That is, we must be able to construct the prefix in index2
-from the prefix in index. */
-
-ulint
-dict_index_get_nth_field_pos(
-/*=========================*/
- /* out: position in internal representation
- of the index; if not contained, returns
- ULINT_UNDEFINED */
- dict_index_t* index, /* in: index from which to search */
- dict_index_t* index2, /* in: index */
- ulint n); /* in: field number in index2 */
-/************************************************************************
-Looks for column n position in the clustered index. */
-
-ulint
-dict_table_get_nth_col_pos(
-/*=======================*/
- /* out: position in internal representation
- of the clustered index */
- dict_table_t* table, /* in: table */
- ulint n); /* in: column number */
-/************************************************************************
-Returns the position of a system column in an index. */
-UNIV_INLINE
-ulint
-dict_index_get_sys_col_pos(
-/*=======================*/
- /* out: position, ULINT_UNDEFINED if not
- contained */
- dict_index_t* index, /* in: index */
- ulint type); /* in: DATA_ROW_ID, ... */
-/***********************************************************************
-Adds a column to index. */
-
-void
-dict_index_add_col(
-/*===============*/
- dict_index_t* index, /* in: index */
- dict_table_t* table, /* in: table */
- dict_col_t* col, /* in: column */
- ulint prefix_len); /* in: column prefix length */
-/***********************************************************************
-Copies types of fields contained in index to tuple. */
-
-void
-dict_index_copy_types(
-/*==================*/
- dtuple_t* tuple, /* in: data tuple */
- dict_index_t* index, /* in: index */
- ulint n_fields); /* in: number of field types to copy */
-/*************************************************************************
-Gets the field column. */
-UNIV_INLINE
-const dict_col_t*
-dict_field_get_col(
-/*===============*/
- const dict_field_t* field);
-
-#ifdef UNIV_DEBUG
-/**************************************************************************
-Returns an index object if it is found in the dictionary cache. */
-
-dict_index_t*
-dict_index_get_if_in_cache(
-/*=======================*/
- /* out: index, NULL if not found */
- dulint index_id); /* in: index id */
-/**************************************************************************
-Checks that a tuple has n_fields_cmp value in a sensible range, so that
-no comparison can occur with the page number field in a node pointer. */
-
-ibool
-dict_index_check_search_tuple(
-/*==========================*/
- /* out: TRUE if ok */
- dict_index_t* index, /* in: index */
- dtuple_t* tuple); /* in: tuple used in a search */
-#endif /* UNIV_DEBUG */
-/**************************************************************************
-Builds a node pointer out of a physical record and a page number. */
-
-dtuple_t*
-dict_index_build_node_ptr(
-/*======================*/
- /* out, own: node pointer */
- dict_index_t* index, /* in: index */
- rec_t* rec, /* in: record for which to build node
- pointer */
- ulint page_no,/* in: page number to put in node pointer */
- mem_heap_t* heap, /* in: memory heap where pointer created */
- ulint level); /* in: level of rec in tree: 0 means leaf
- level */
-/**************************************************************************
-Copies an initial segment of a physical record, long enough to specify an
-index entry uniquely. */
-
-rec_t*
-dict_index_copy_rec_order_prefix(
-/*=============================*/
- /* out: pointer to the prefix record */
- dict_index_t* index, /* in: index */
- rec_t* rec, /* in: record for which to copy prefix */
- ulint* n_fields,/* out: number of fields copied */
- byte** buf, /* in/out: memory buffer for the copied prefix,
- or NULL */
- ulint* buf_size);/* in/out: buffer size */
-/**************************************************************************
-Builds a typed data tuple out of a physical record. */
-
-dtuple_t*
-dict_index_build_data_tuple(
-/*========================*/
- /* out, own: data tuple */
- dict_index_t* index, /* in: index */
- rec_t* rec, /* in: record for which to build data tuple */
- ulint n_fields,/* in: number of data fields */
- mem_heap_t* heap); /* in: memory heap where tuple created */
-/*************************************************************************
-Gets the space id of the root of the index tree. */
-UNIV_INLINE
-ulint
-dict_index_get_space(
-/*=================*/
- /* out: space id */
- dict_index_t* index); /* in: index */
-/*************************************************************************
-Sets the space id of the root of the index tree. */
-UNIV_INLINE
-void
-dict_index_set_space(
-/*=================*/
- dict_index_t* index, /* in: index */
- ulint space); /* in: space id */
-/*************************************************************************
-Gets the page number of the root of the index tree. */
-UNIV_INLINE
-ulint
-dict_index_get_page(
-/*================*/
- /* out: page number */
- dict_index_t* tree); /* in: index */
-/*************************************************************************
-Sets the page number of the root of index tree. */
-UNIV_INLINE
-void
-dict_index_set_page(
-/*================*/
- dict_index_t* index, /* in: index */
- ulint page); /* in: page number */
-/*************************************************************************
-Gets the type of the index tree. */
-UNIV_INLINE
-ulint
-dict_index_get_type(
-/*================*/
- /* out: type */
- dict_index_t* index); /* in: index */
-/*************************************************************************
-Gets the read-write lock of the index tree. */
-UNIV_INLINE
-rw_lock_t*
-dict_index_get_lock(
-/*================*/
- /* out: read-write lock */
- dict_index_t* index); /* in: index */
-/************************************************************************
-Returns free space reserved for future updates of records. This is
-relevant only in the case of many consecutive inserts, as updates
-which make the records bigger might fragment the index. */
-UNIV_INLINE
-ulint
-dict_index_get_space_reserve(void);
-/*==============================*/
- /* out: number of free bytes on page,
- reserved for updates */
-/*************************************************************************
-Calculates the minimum record length in an index. */
-
-ulint
-dict_index_calc_min_rec_len(
-/*========================*/
- dict_index_t* index); /* in: index */
-/*************************************************************************
-Calculates new estimates for table and index statistics. The statistics
-are used in query optimization. */
-
-void
-dict_update_statistics_low(
-/*=======================*/
- dict_table_t* table, /* in: table */
- ibool has_dict_mutex);/* in: TRUE if the caller has the
- dictionary mutex */
-/*************************************************************************
-Calculates new estimates for table and index statistics. The statistics
-are used in query optimization. */
-
-void
-dict_update_statistics(
-/*===================*/
- dict_table_t* table); /* in: table */
-/************************************************************************
-Reserves the dictionary system mutex for MySQL. */
-
-void
-dict_mutex_enter_for_mysql(void);
-/*============================*/
-/************************************************************************
-Releases the dictionary system mutex for MySQL. */
-
-void
-dict_mutex_exit_for_mysql(void);
-/*===========================*/
-/************************************************************************
-Checks if the database name in two table names is the same. */
-
-ibool
-dict_tables_have_same_db(
-/*=====================*/
- /* out: TRUE if same db name */
- const char* name1, /* in: table name in the form
- dbname '/' tablename */
- const char* name2); /* in: table name in the form
- dbname '/' tablename */
-/*************************************************************************
-Scans from pointer onwards. Stops if is at the start of a copy of
-'string' where characters are compared without case sensitivity. Stops
-also at '\0'. */
-
-const char*
-dict_scan_to(
-/*=========*/
- /* out: scanned up to this */
- const char* ptr, /* in: scan from */
- const char* string);/* in: look for this */
-/* Buffers for storing detailed information about the latest foreign key
-and unique key errors */
-extern FILE* dict_foreign_err_file;
-extern mutex_t dict_foreign_err_mutex; /* mutex protecting the buffers */
-
-extern dict_sys_t* dict_sys; /* the dictionary system */
-extern rw_lock_t dict_operation_lock;
-
-/* Dictionary system struct */
-struct dict_sys_struct{
- mutex_t mutex; /* mutex protecting the data
- dictionary; protects also the
- disk-based dictionary system tables;
- this mutex serializes CREATE TABLE
- and DROP TABLE, as well as reading
- the dictionary data for a table from
- system tables */
- dulint row_id; /* the next row id to assign;
- NOTE that at a checkpoint this
- must be written to the dict system
- header and flushed to a file; in
- recovery this must be derived from
- the log records */
- hash_table_t* table_hash; /* hash table of the tables, based
- on name */
- hash_table_t* table_id_hash; /* hash table of the tables, based
- on id */
- UT_LIST_BASE_NODE_T(dict_table_t)
- table_LRU; /* LRU list of tables */
- ulint size; /* varying space in bytes occupied
- by the data dictionary table and
- index objects */
- dict_table_t* sys_tables; /* SYS_TABLES table */
- dict_table_t* sys_columns; /* SYS_COLUMNS table */
- dict_table_t* sys_indexes; /* SYS_INDEXES table */
- dict_table_t* sys_fields; /* SYS_FIELDS table */
-};
-
-#ifndef UNIV_NONINL
-#include "dict0dict.ic"
-#endif
-
-#endif
diff --git a/storage/innobase/include/dict0load.ic b/storage/innobase/include/dict0load.ic
deleted file mode 100644
index 1a207fbf0fd..00000000000
--- a/storage/innobase/include/dict0load.ic
+++ /dev/null
@@ -1,9 +0,0 @@
-/******************************************************
-Loads to the memory cache database object definitions
-from dictionary tables
-
-(c) 1996 Innobase Oy
-
-Created 4/24/1996 Heikki Tuuri
-*******************************************************/
-
diff --git a/storage/innobase/include/dict0mem.h b/storage/innobase/include/dict0mem.h
deleted file mode 100644
index ac28fdb1bae..00000000000
--- a/storage/innobase/include/dict0mem.h
+++ /dev/null
@@ -1,431 +0,0 @@
-/******************************************************
-Data dictionary memory object creation
-
-(c) 1996 Innobase Oy
-
-Created 1/8/1996 Heikki Tuuri
-*******************************************************/
-
-#ifndef dict0mem_h
-#define dict0mem_h
-
-#include "univ.i"
-#include "dict0types.h"
-#include "data0type.h"
-#include "data0data.h"
-#include "mem0mem.h"
-#include "rem0types.h"
-#include "btr0types.h"
-#include "ut0mem.h"
-#include "ut0lst.h"
-#include "ut0rnd.h"
-#include "ut0byte.h"
-#include "sync0rw.h"
-#include "lock0types.h"
-#include "hash0hash.h"
-#include "que0types.h"
-
-/* Type flags of an index: OR'ing of the flags is allowed to define a
-combination of types */
-#define DICT_CLUSTERED 1 /* clustered index */
-#define DICT_UNIQUE 2 /* unique index */
-#define DICT_UNIVERSAL 4 /* index which can contain records from any
- other index */
-#define DICT_IBUF 8 /* insert buffer tree */
-
-/* Types for a table object */
-#define DICT_TABLE_ORDINARY 1
-#if 0 /* not implemented */
-#define DICT_TABLE_CLUSTER_MEMBER 2
-#define DICT_TABLE_CLUSTER 3 /* this means that the table is
- really a cluster definition */
-#endif
-
-/* Table flags */
-#define DICT_TF_COMPACT 1 /* compact page format */
-
-/**************************************************************************
-Creates a table memory object. */
-
-dict_table_t*
-dict_mem_table_create(
-/*==================*/
- /* out, own: table object */
- const char* name, /* in: table name */
- ulint space, /* in: space where the clustered index
- of the table is placed; this parameter
- is ignored if the table is made
- a member of a cluster */
- ulint n_cols, /* in: number of columns */
- ulint flags); /* in: table flags */
-/********************************************************************
-Free a table memory object. */
-
-void
-dict_mem_table_free(
-/*================*/
- dict_table_t* table); /* in: table */
-/**************************************************************************
-Adds a column definition to a table. */
-
-void
-dict_mem_table_add_col(
-/*===================*/
- dict_table_t* table, /* in: table */
- mem_heap_t* heap, /* in: temporary memory heap, or NULL */
- const char* name, /* in: column name, or NULL */
- ulint mtype, /* in: main datatype */
- ulint prtype, /* in: precise type */
- ulint len); /* in: precision */
-/**************************************************************************
-Creates an index memory object. */
-
-dict_index_t*
-dict_mem_index_create(
-/*==================*/
- /* out, own: index object */
- const char* table_name, /* in: table name */
- const char* index_name, /* in: index name */
- ulint space, /* in: space where the index tree is
- placed, ignored if the index is of
- the clustered type */
- ulint type, /* in: DICT_UNIQUE,
- DICT_CLUSTERED, ... ORed */
- ulint n_fields); /* in: number of fields */
-/**************************************************************************
-Adds a field definition to an index. NOTE: does not take a copy
-of the column name if the field is a column. The memory occupied
-by the column name may be released only after publishing the index. */
-
-void
-dict_mem_index_add_field(
-/*=====================*/
- dict_index_t* index, /* in: index */
- const char* name, /* in: column name */
- ulint prefix_len); /* in: 0 or the column prefix length
- in a MySQL index like
- INDEX (textcol(25)) */
-/**************************************************************************
-Frees an index memory object. */
-
-void
-dict_mem_index_free(
-/*================*/
- dict_index_t* index); /* in: index */
-/**************************************************************************
-Creates and initializes a foreign constraint memory object. */
-
-dict_foreign_t*
-dict_mem_foreign_create(void);
-/*=========================*/
- /* out, own: foreign constraint struct */
-
-/* Data structure for a column in a table */
-struct dict_col_struct{
- /*----------------------*/
- /* The following are copied from dtype_t,
- so that all bit-fields can be packed tightly. */
- unsigned mtype:8; /* main data type */
- unsigned prtype:24; /* precise type; MySQL data
- type, charset code, flags to
- indicate nullability,
- signedness, whether this is a
- binary string, whether this is
- a true VARCHAR where MySQL
- uses 2 bytes to store the length */
-
- /* the remaining fields do not affect alphabetical ordering: */
-
- unsigned len:16; /* length; for MySQL data this
- is field->pack_length(),
- except that for a >= 5.0.3
- type true VARCHAR this is the
- maximum byte length of the
- string data (in addition to
- the string, MySQL uses 1 or 2
- bytes to store the string length) */
-
- unsigned mbminlen:2; /* minimum length of a
- character, in bytes */
- unsigned mbmaxlen:3; /* maximum length of a
- character, in bytes */
- /*----------------------*/
- /* End of definitions copied from dtype_t */
-
- unsigned ind:10; /* table column position
- (starting from 0) */
- unsigned ord_part:1; /* nonzero if this column
- appears in the ordering fields
- of an index */
-};
-
-/* DICT_MAX_INDEX_COL_LEN is measured in bytes and is the maximum
-indexed column length (or indexed prefix length). It is set to 3*256,
-so that one can create a column prefix index on 256 characters of a
-TEXT or VARCHAR column also in the UTF-8 charset. In that charset,
-a character may take at most 3 bytes.
-This constant MUST NOT BE CHANGED, or the compatibility of InnoDB data
-files would be at risk! */
-
-#define DICT_MAX_INDEX_COL_LEN 768
-
-/* Data structure for a field in an index */
-struct dict_field_struct{
- dict_col_t* col; /* pointer to the table column */
- const char* name; /* name of the column */
- unsigned prefix_len:10; /* 0 or the length of the column
- prefix in bytes in a MySQL index of
- type, e.g., INDEX (textcol(25));
- must be smaller than
- DICT_MAX_INDEX_COL_LEN; NOTE that
- in the UTF-8 charset, MySQL sets this
- to 3 * the prefix len in UTF-8 chars */
- unsigned fixed_len:10; /* 0 or the fixed length of the
- column if smaller than
- DICT_MAX_INDEX_COL_LEN */
-};
-
-/* Data structure for an index */
-struct dict_index_struct{
- dulint id; /* id of the index */
- mem_heap_t* heap; /* memory heap */
- ulint type; /* index type */
- const char* name; /* index name */
- const char* table_name; /* table name */
- dict_table_t* table; /* back pointer to table */
- unsigned space:32;
- /* space where the index tree is placed */
- unsigned page:32;/* index tree root page number */
- unsigned trx_id_offset:10;/* position of the the trx id column
- in a clustered index record, if the fields
- before it are known to be of a fixed size,
- 0 otherwise */
- unsigned n_user_defined_cols:10;
- /* number of columns the user defined to
- be in the index: in the internal
- representation we add more columns */
- unsigned n_uniq:10;/* number of fields from the beginning
- which are enough to determine an index
- entry uniquely */
- unsigned n_def:10;/* number of fields defined so far */
- unsigned n_fields:10;/* number of fields in the index */
- unsigned n_nullable:10;/* number of nullable fields */
- unsigned cached:1;/* TRUE if the index object is in the
- dictionary cache */
- dict_field_t* fields; /* array of field descriptions */
- UT_LIST_NODE_T(dict_index_t)
- indexes;/* list of indexes of the table */
- btr_search_t* search_info; /* info used in optimistic searches */
- /*----------------------*/
- ib_longlong* stat_n_diff_key_vals;
- /* approximate number of different key values
- for this index, for each n-column prefix
- where n <= dict_get_n_unique(index); we
- periodically calculate new estimates */
- ulint stat_index_size;
- /* approximate index size in database pages */
- ulint stat_n_leaf_pages;
- /* approximate number of leaf pages in the
- index tree */
- rw_lock_t lock; /* read-write lock protecting the upper levels
- of the index tree */
-#ifdef UNIV_DEBUG
- ulint magic_n;/* magic number */
-# define DICT_INDEX_MAGIC_N 76789786
-#endif
-};
-
-/* Data structure for a foreign key constraint; an example:
-FOREIGN KEY (A, B) REFERENCES TABLE2 (C, D) */
-
-struct dict_foreign_struct{
- mem_heap_t* heap; /* this object is allocated from
- this memory heap */
- char* id; /* id of the constraint as a
- null-terminated string */
- unsigned n_fields:10; /* number of indexes' first fields
- for which the the foreign key
- constraint is defined: we allow the
- indexes to contain more fields than
- mentioned in the constraint, as long
- as the first fields are as mentioned */
- unsigned type:6; /* 0 or DICT_FOREIGN_ON_DELETE_CASCADE
- or DICT_FOREIGN_ON_DELETE_SET_NULL */
- char* foreign_table_name;/* foreign table name */
- dict_table_t* foreign_table; /* table where the foreign key is */
- const char** foreign_col_names;/* names of the columns in the
- foreign key */
- char* referenced_table_name;/* referenced table name */
- dict_table_t* referenced_table;/* table where the referenced key
- is */
- const char** referenced_col_names;/* names of the referenced
- columns in the referenced table */
- dict_index_t* foreign_index; /* foreign index; we require that
- both tables contain explicitly defined
- indexes for the constraint: InnoDB
- does not generate new indexes
- implicitly */
- dict_index_t* referenced_index;/* referenced index */
- UT_LIST_NODE_T(dict_foreign_t)
- foreign_list; /* list node for foreign keys of the
- table */
- UT_LIST_NODE_T(dict_foreign_t)
- referenced_list;/* list node for referenced keys of the
- table */
-};
-
-/* The flags for ON_UPDATE and ON_DELETE can be ORed; the default is that
-a foreign key constraint is enforced, therefore RESTRICT just means no flag */
-#define DICT_FOREIGN_ON_DELETE_CASCADE 1
-#define DICT_FOREIGN_ON_DELETE_SET_NULL 2
-#define DICT_FOREIGN_ON_UPDATE_CASCADE 4
-#define DICT_FOREIGN_ON_UPDATE_SET_NULL 8
-#define DICT_FOREIGN_ON_DELETE_NO_ACTION 16
-#define DICT_FOREIGN_ON_UPDATE_NO_ACTION 32
-
-
-/* Data structure for a database table */
-struct dict_table_struct{
- dulint id; /* id of the table */
- mem_heap_t* heap; /* memory heap */
- const char* name; /* table name */
- const char* dir_path_of_temp_table;/* NULL or the directory path
- where a TEMPORARY table that was explicitly
- created by a user should be placed if
- innodb_file_per_table is defined in my.cnf;
- in Unix this is usually /tmp/..., in Windows
- \temp\... */
- unsigned space:32;
- /* space where the clustered index of the
- table is placed */
- unsigned ibd_file_missing:1;
- /* TRUE if this is in a single-table
- tablespace and the .ibd file is missing; then
- we must return in ha_innodb.cc an error if the
- user tries to query such an orphaned table */
- unsigned tablespace_discarded:1;
- /* this flag is set TRUE when the user
- calls DISCARD TABLESPACE on this
- table, and reset to FALSE in IMPORT
- TABLESPACE */
- unsigned cached:1;/* TRUE if the table object has been added
- to the dictionary cache */
- unsigned flags:8;/* DICT_TF_COMPACT, ... */
- unsigned n_def:10;/* number of columns defined so far */
- unsigned n_cols:10;/* number of columns */
- dict_col_t* cols; /* array of column descriptions */
- const char* col_names;
- /* Column names packed in a character string
- "name1\0name2\0...nameN\0". Until
- the string contains n_cols, it will be
- allocated from a temporary heap. The final
- string will be allocated from table->heap. */
- hash_node_t name_hash; /* hash chain node */
- hash_node_t id_hash; /* hash chain node */
- UT_LIST_BASE_NODE_T(dict_index_t)
- indexes; /* list of indexes of the table */
- UT_LIST_BASE_NODE_T(dict_foreign_t)
- foreign_list;/* list of foreign key constraints
- in the table; these refer to columns
- in other tables */
- UT_LIST_BASE_NODE_T(dict_foreign_t)
- referenced_list;/* list of foreign key constraints
- which refer to this table */
- UT_LIST_NODE_T(dict_table_t)
- table_LRU; /* node of the LRU list of tables */
- ulint n_mysql_handles_opened;
- /* count of how many handles MySQL has opened
- to this table; dropping of the table is
- NOT allowed until this count gets to zero;
- MySQL does NOT itself check the number of
- open handles at drop */
- ulint n_foreign_key_checks_running;
- /* count of how many foreign key check
- operations are currently being performed
- on the table: we cannot drop the table while
- there are foreign key checks running on
- it! */
- lock_t* auto_inc_lock;/* a buffer for an auto-inc lock
- for this table: we allocate the memory here
- so that individual transactions can get it
- and release it without a need to allocate
- space from the lock heap of the trx:
- otherwise the lock heap would grow rapidly
- if we do a large insert from a select */
- dulint query_cache_inv_trx_id;
- /* transactions whose trx id < than this
- number are not allowed to store to the MySQL
- query cache or retrieve from it; when a trx
- with undo logs commits, it sets this to the
- value of the trx id counter for the tables it
- had an IX lock on */
- UT_LIST_BASE_NODE_T(lock_t)
- locks; /* list of locks on the table */
-#ifdef UNIV_DEBUG
- /*----------------------*/
- ibool does_not_fit_in_memory;
- /* this field is used to specify in simulations
- tables which are so big that disk should be
- accessed: disk access is simulated by
- putting the thread to sleep for a while;
- NOTE that this flag is not stored to the data
- dictionary on disk, and the database will
- forget about value TRUE if it has to reload
- the table definition from disk */
-#endif /* UNIV_DEBUG */
- /*----------------------*/
- unsigned big_rows:1;
- /* flag: TRUE if the maximum length of
- a single row exceeds BIG_ROW_SIZE;
- initialized in dict_table_add_to_cache() */
- unsigned stat_initialized:1; /* TRUE if statistics have
- been calculated the first time
- after database startup or table creation */
- ib_longlong stat_n_rows;
- /* approximate number of rows in the table;
- we periodically calculate new estimates */
- ulint stat_clustered_index_size;
- /* approximate clustered index size in
- database pages */
- ulint stat_sum_of_other_index_sizes;
- /* other indexes in database pages */
- ulint stat_modified_counter;
- /* when a row is inserted, updated, or deleted,
- we add 1 to this number; we calculate new
- estimates for the stat_... values for the
- table and the indexes at an interval of 2 GB
- or when about 1 / 16 of table has been
- modified; also when the estimate operation is
- called for MySQL SHOW TABLE STATUS; the
- counter is reset to zero at statistics
- calculation; this counter is not protected by
- any latch, because this is only used for
- heuristics */
- /*----------------------*/
- mutex_t autoinc_mutex;
- /* mutex protecting the autoincrement
- counter */
- ib_ulonglong autoinc;/* autoinc counter value to give to the
- next inserted row */
- ulong n_waiting_or_granted_auto_inc_locks;
- /* This counter is used to track the number
- of granted and pending autoinc locks on this
- table. This value is set after acquiring the
- kernel mutex but we peek the contents to
- determine whether other transactions have
- acquired the AUTOINC lock or not. Of course
- only one transaction can be granted the
- lock but there can be multiple waiters. */
- /*----------------------*/
-
-#ifdef UNIV_DEBUG
- ulint magic_n;/* magic number */
-# define DICT_TABLE_MAGIC_N 76333786
-#endif /* UNIV_DEBUG */
-};
-
-#ifndef UNIV_NONINL
-#include "dict0mem.ic"
-#endif
-
-#endif
diff --git a/storage/innobase/include/dict0mem.ic b/storage/innobase/include/dict0mem.ic
deleted file mode 100644
index 9bcefc2a51f..00000000000
--- a/storage/innobase/include/dict0mem.ic
+++ /dev/null
@@ -1,9 +0,0 @@
-/**********************************************************************
-Data dictionary memory object creation
-
-(c) 1996 Innobase Oy
-
-Created 1/8/1996 Heikki Tuuri
-***********************************************************************/
-
-
diff --git a/storage/innobase/include/dict0types.h b/storage/innobase/include/dict0types.h
deleted file mode 100644
index b90545f2105..00000000000
--- a/storage/innobase/include/dict0types.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/******************************************************
-Data dictionary global types
-
-(c) 1996 Innobase Oy
-
-Created 1/8/1996 Heikki Tuuri
-*******************************************************/
-
-#ifndef dict0types_h
-#define dict0types_h
-
-typedef struct dict_sys_struct dict_sys_t;
-typedef struct dict_col_struct dict_col_t;
-typedef struct dict_field_struct dict_field_t;
-typedef struct dict_index_struct dict_index_t;
-typedef struct dict_table_struct dict_table_t;
-typedef struct dict_foreign_struct dict_foreign_t;
-
-/* A cluster object is a table object with the type field set to
-DICT_CLUSTERED */
-
-typedef dict_table_t dict_cluster_t;
-
-typedef struct ind_node_struct ind_node_t;
-typedef struct tab_node_struct tab_node_t;
-
-#endif
diff --git a/storage/innobase/include/dyn0dyn.h b/storage/innobase/include/dyn0dyn.h
deleted file mode 100644
index 7affccbf67e..00000000000
--- a/storage/innobase/include/dyn0dyn.h
+++ /dev/null
@@ -1,166 +0,0 @@
-/******************************************************
-The dynamically allocated array
-
-(c) 1996 Innobase Oy
-
-Created 2/5/1996 Heikki Tuuri
-*******************************************************/
-
-#ifndef dyn0dyn_h
-#define dyn0dyn_h
-
-#include "univ.i"
-#include "ut0lst.h"
-#include "mem0mem.h"
-
-typedef struct dyn_block_struct dyn_block_t;
-typedef dyn_block_t dyn_array_t;
-
-
-/* This is the initial 'payload' size of a dynamic array;
-this must be > MLOG_BUF_MARGIN + 30! */
-#define DYN_ARRAY_DATA_SIZE 512
-
-/*************************************************************************
-Initializes a dynamic array. */
-UNIV_INLINE
-dyn_array_t*
-dyn_array_create(
-/*=============*/
- /* out: initialized dyn array */
- dyn_array_t* arr); /* in: pointer to a memory buffer of
- size sizeof(dyn_array_t) */
-/****************************************************************
-Frees a dynamic array. */
-UNIV_INLINE
-void
-dyn_array_free(
-/*===========*/
- dyn_array_t* arr); /* in: dyn array */
-/*************************************************************************
-Makes room on top of a dyn array and returns a pointer to a buffer in it.
-After copying the elements, the caller must close the buffer using
-dyn_array_close. */
-UNIV_INLINE
-byte*
-dyn_array_open(
-/*===========*/
- /* out: pointer to the buffer */
- dyn_array_t* arr, /* in: dynamic array */
- ulint size); /* in: size in bytes of the buffer; MUST be
- smaller than DYN_ARRAY_DATA_SIZE! */
-/*************************************************************************
-Closes the buffer returned by dyn_array_open. */
-UNIV_INLINE
-void
-dyn_array_close(
-/*============*/
- dyn_array_t* arr, /* in: dynamic array */
- byte* ptr); /* in: buffer space from ptr up was not used */
-/*************************************************************************
-Makes room on top of a dyn array and returns a pointer to
-the added element. The caller must copy the element to
-the pointer returned. */
-UNIV_INLINE
-void*
-dyn_array_push(
-/*===========*/
- /* out: pointer to the element */
- dyn_array_t* arr, /* in: dynamic array */
- ulint size); /* in: size in bytes of the element */
-/****************************************************************
-Returns pointer to an element in dyn array. */
-UNIV_INLINE
-void*
-dyn_array_get_element(
-/*==================*/
- /* out: pointer to element */
- dyn_array_t* arr, /* in: dyn array */
- ulint pos); /* in: position of element as bytes
- from array start */
-/****************************************************************
-Returns the size of stored data in a dyn array. */
-UNIV_INLINE
-ulint
-dyn_array_get_data_size(
-/*====================*/
- /* out: data size in bytes */
- dyn_array_t* arr); /* in: dyn array */
-/****************************************************************
-Gets the first block in a dyn array. */
-UNIV_INLINE
-dyn_block_t*
-dyn_array_get_first_block(
-/*======================*/
- dyn_array_t* arr); /* in: dyn array */
-/****************************************************************
-Gets the last block in a dyn array. */
-UNIV_INLINE
-dyn_block_t*
-dyn_array_get_last_block(
-/*=====================*/
- dyn_array_t* arr); /* in: dyn array */
-/************************************************************************
-Gets the next block in a dyn array. */
-UNIV_INLINE
-dyn_block_t*
-dyn_array_get_next_block(
-/*=====================*/
- /* out: pointer to next, NULL if end of list */
- dyn_array_t* arr, /* in: dyn array */
- dyn_block_t* block); /* in: dyn array block */
-/************************************************************************
-Gets the number of used bytes in a dyn array block. */
-UNIV_INLINE
-ulint
-dyn_block_get_used(
-/*===============*/
- /* out: number of bytes used */
- dyn_block_t* block); /* in: dyn array block */
-/************************************************************************
-Gets pointer to the start of data in a dyn array block. */
-UNIV_INLINE
-byte*
-dyn_block_get_data(
-/*===============*/
- /* out: pointer to data */
- dyn_block_t* block); /* in: dyn array block */
-/************************************************************
-Pushes n bytes to a dyn array. */
-UNIV_INLINE
-void
-dyn_push_string(
-/*============*/
- dyn_array_t* arr, /* in: dyn array */
- const byte* str, /* in: string to write */
- ulint len); /* in: string length */
-
-/*#################################################################*/
-
-/* NOTE! Do not use the fields of the struct directly: the definition
-appears here only for the compiler to know its size! */
-struct dyn_block_struct{
- mem_heap_t* heap; /* in the first block this is != NULL
- if dynamic allocation has been needed */
- ulint used; /* number of data bytes used in this block */
- byte data[DYN_ARRAY_DATA_SIZE];
- /* storage for array elements */
- UT_LIST_BASE_NODE_T(dyn_block_t) base;
- /* linear list of dyn blocks: this node is
- used only in the first block */
- UT_LIST_NODE_T(dyn_block_t) list;
- /* linear list node: used in all blocks */
-#ifdef UNIV_DEBUG
- ulint buf_end;/* only in the debug version: if dyn array is
- opened, this is the buffer end offset, else
- this is 0 */
- ulint magic_n;
-#endif
-};
-
-
-#ifndef UNIV_NONINL
-#include "dyn0dyn.ic"
-#endif
-
-#endif
diff --git a/storage/innobase/include/eval0proc.h b/storage/innobase/include/eval0proc.h
deleted file mode 100644
index 8416551d0ba..00000000000
--- a/storage/innobase/include/eval0proc.h
+++ /dev/null
@@ -1,87 +0,0 @@
-/******************************************************
-Executes SQL stored procedures and their control structures
-
-(c) 1998 Innobase Oy
-
-Created 1/20/1998 Heikki Tuuri
-*******************************************************/
-
-#ifndef eval0proc_h
-#define eval0proc_h
-
-#include "univ.i"
-#include "que0types.h"
-#include "pars0sym.h"
-#include "pars0pars.h"
-
-/**************************************************************************
-Performs an execution step of a procedure node. */
-UNIV_INLINE
-que_thr_t*
-proc_step(
-/*======*/
- /* out: query thread to run next or NULL */
- que_thr_t* thr); /* in: query thread */
-/**************************************************************************
-Performs an execution step of an if-statement node. */
-
-que_thr_t*
-if_step(
-/*====*/
- /* out: query thread to run next or NULL */
- que_thr_t* thr); /* in: query thread */
-/**************************************************************************
-Performs an execution step of a while-statement node. */
-
-que_thr_t*
-while_step(
-/*=======*/
- /* out: query thread to run next or NULL */
- que_thr_t* thr); /* in: query thread */
-/**************************************************************************
-Performs an execution step of a for-loop node. */
-
-que_thr_t*
-for_step(
-/*=====*/
- /* out: query thread to run next or NULL */
- que_thr_t* thr); /* in: query thread */
-/**************************************************************************
-Performs an execution step of an assignment statement node. */
-
-que_thr_t*
-assign_step(
-/*========*/
- /* out: query thread to run next or NULL */
- que_thr_t* thr); /* in: query thread */
-/**************************************************************************
-Performs an execution step of a procedure call node. */
-UNIV_INLINE
-que_thr_t*
-proc_eval_step(
-/*===========*/
- /* out: query thread to run next or NULL */
- que_thr_t* thr); /* in: query thread */
-/**************************************************************************
-Performs an execution step of an exit statement node. */
-
-que_thr_t*
-exit_step(
-/*======*/
- /* out: query thread to run next or NULL */
- que_thr_t* thr); /* in: query thread */
-/**************************************************************************
-Performs an execution step of a return-statement node. */
-
-que_thr_t*
-return_step(
-/*========*/
- /* out: query thread to run next or NULL */
- que_thr_t* thr); /* in: query thread */
-
-
-#ifndef UNIV_NONINL
-#include "eval0proc.ic"
-#endif
-
-#endif
diff --git a/storage/innobase/include/eval0proc.ic b/storage/innobase/include/eval0proc.ic
deleted file mode 100644
index cf738056576..00000000000
--- a/storage/innobase/include/eval0proc.ic
+++ /dev/null
@@ -1,71 +0,0 @@
-/******************************************************
-Executes SQL stored procedures and their control structures
-
-(c) 1998 Innobase Oy
-
-Created 1/20/1998 Heikki Tuuri
-*******************************************************/
-
-#include "pars0pars.h"
-#include "que0que.h"
-#include "eval0eval.h"
-
-/**************************************************************************
-Performs an execution step of a procedure node. */
-UNIV_INLINE
-que_thr_t*
-proc_step(
-/*======*/
- /* out: query thread to run next or NULL */
- que_thr_t* thr) /* in: query thread */
-{
- proc_node_t* node;
-
- ut_ad(thr);
-
- node = thr->run_node;
- ut_ad(que_node_get_type(node) == QUE_NODE_PROC);
-
- if (thr->prev_node == que_node_get_parent(node)) {
- /* Start execution from the first statement in the statement
- list */
-
- thr->run_node = node->stat_list;
- } else {
- /* Move to the next statement */
- ut_ad(que_node_get_next(thr->prev_node) == NULL);
-
- thr->run_node = NULL;
- }
-
- if (thr->run_node == NULL) {
- thr->run_node = que_node_get_parent(node);
- }
-
- return(thr);
-}
-
-/**************************************************************************
-Performs an execution step of a procedure call node. */
-UNIV_INLINE
-que_thr_t*
-proc_eval_step(
-/*===========*/
- /* out: query thread to run next or NULL */
- que_thr_t* thr) /* in: query thread */
-{
- func_node_t* node;
-
- ut_ad(thr);
-
- node = thr->run_node;
- ut_ad(que_node_get_type(node) == QUE_NODE_FUNC);
-
- /* Evaluate the procedure */
-
- eval_exp(node);
-
- thr->run_node = que_node_get_parent(node);
-
- return(thr);
-}
diff --git a/storage/innobase/include/fsp0fsp.h b/storage/innobase/include/fsp0fsp.h
deleted file mode 100644
index 82e95a2e920..00000000000
--- a/storage/innobase/include/fsp0fsp.h
+++ /dev/null
@@ -1,391 +0,0 @@
-/******************************************************
-File space management
-
-(c) 1995 Innobase Oy
-
-Created 12/18/1995 Heikki Tuuri
-*******************************************************/
-
-#ifndef fsp0fsp_h
-#define fsp0fsp_h
-
-#include "univ.i"
-
-#include "mtr0mtr.h"
-#include "fut0lst.h"
-#include "ut0byte.h"
-#include "page0types.h"
-
-/* If records are inserted in order, there are the following
-flags to tell this (their type is made byte for the compiler
-to warn if direction and hint parameters are switched in
-fseg_alloc_free_page): */
-#define FSP_UP ((byte)111) /* alphabetically upwards */
-#define FSP_DOWN ((byte)112) /* alphabetically downwards */
-#define FSP_NO_DIR ((byte)113) /* no order */
-
-/* File space extent size in pages */
-#define FSP_EXTENT_SIZE 64
-
-/* On a page of any file segment, data may be put starting from this offset: */
-#define FSEG_PAGE_DATA FIL_PAGE_DATA
-
-/* File segment header which points to the inode describing the file segment */
-typedef byte fseg_header_t;
-
-#define FSEG_HDR_SPACE 0 /* space id of the inode */
-#define FSEG_HDR_PAGE_NO 4 /* page number of the inode */
-#define FSEG_HDR_OFFSET 8 /* byte offset of the inode */
-
-#define FSEG_HEADER_SIZE 10
-
-/**************************************************************************
-Initializes the file space system. */
-
-void
-fsp_init(void);
-/*==========*/
-/**************************************************************************
-Gets the current free limit of a tablespace. The free limit means the
-place of the first page which has never been put to the the free list
-for allocation. The space above that address is initialized to zero.
-Sets also the global variable log_fsp_current_free_limit. */
-
-ulint
-fsp_header_get_free_limit(
-/*======================*/
- /* out: free limit in megabytes */
- ulint space); /* in: space id, must be 0 */
-/**************************************************************************
-Gets the size of the tablespace from the tablespace header. If we do not
-have an auto-extending data file, this should be equal to the size of the
-data files. If there is an auto-extending data file, this can be smaller. */
-
-ulint
-fsp_header_get_tablespace_size(
-/*===========================*/
- /* out: size in pages */
- ulint space); /* in: space id, must be 0 */
-/**************************************************************************
-Reads the file space size stored in the header page. */
-
-ulint
-fsp_get_size_low(
-/*=============*/
- /* out: tablespace size stored in the space header */
- page_t* page); /* in: header page (page 0 in the tablespace) */
-/**************************************************************************
-Reads the space id from the first page of a tablespace. */
-
-ulint
-fsp_header_get_space_id(
-/*====================*/
- /* out: space id, ULINT UNDEFINED if error */
- page_t* page); /* in: first page of a tablespace */
-/**************************************************************************
-Writes the space id to a tablespace header. This function is used past the
-buffer pool when we in fil0fil.c create a new single-table tablespace. */
-
-void
-fsp_header_write_space_id(
-/*======================*/
- page_t* page, /* in: first page in the space */
- ulint space_id); /* in: space id */
-/**************************************************************************
-Initializes the space header of a new created space and creates also the
-insert buffer tree root if space == 0. */
-
-void
-fsp_header_init(
-/*============*/
- ulint space, /* in: space id */
- ulint size, /* in: current size in blocks */
- mtr_t* mtr); /* in: mini-transaction handle */
-/**************************************************************************
-Increases the space size field of a space. */
-
-void
-fsp_header_inc_size(
-/*================*/
- ulint space, /* in: space id */
- ulint size_inc,/* in: size increment in pages */
- mtr_t* mtr); /* in: mini-transaction handle */
-/**************************************************************************
-Creates a new segment. */
-
-page_t*
-fseg_create(
-/*========*/
- /* out: the page where the segment header is placed,
- x-latched, NULL if could not create segment
- because of lack of space */
- ulint space, /* in: space id */
- ulint page, /* in: page where the segment header is placed: if
- this is != 0, the page must belong to another segment,
- if this is 0, a new page will be allocated and it
- will belong to the created segment */
- ulint byte_offset, /* in: byte offset of the created segment header
- on the page */
- mtr_t* mtr); /* in: mtr */
-/**************************************************************************
-Creates a new segment. */
-
-page_t*
-fseg_create_general(
-/*================*/
- /* out: the page where the segment header is placed,
- x-latched, NULL if could not create segment
- because of lack of space */
- ulint space, /* in: space id */
- ulint page, /* in: page where the segment header is placed: if
- this is != 0, the page must belong to another segment,
- if this is 0, a new page will be allocated and it
- will belong to the created segment */
- ulint byte_offset, /* in: byte offset of the created segment header
- on the page */
- ibool has_done_reservation, /* in: TRUE if the caller has already
- done the reservation for the pages with
- fsp_reserve_free_extents (at least 2 extents: one for
- the inode and the other for the segment) then there is
- no need to do the check for this individual
- operation */
- mtr_t* mtr); /* in: mtr */
-/**************************************************************************
-Calculates the number of pages reserved by a segment, and how many pages are
-currently used. */
-
-ulint
-fseg_n_reserved_pages(
-/*==================*/
- /* out: number of reserved pages */
- fseg_header_t* header, /* in: segment header */
- ulint* used, /* out: number of pages used (<= reserved) */
- mtr_t* mtr); /* in: mtr handle */
-/**************************************************************************
-Allocates a single free page from a segment. This function implements
-the intelligent allocation strategy which tries to minimize
-file space fragmentation. */
-
-ulint
-fseg_alloc_free_page(
-/*=================*/
- /* out: the allocated page offset
- FIL_NULL if no page could be allocated */
- fseg_header_t* seg_header, /* in: segment header */
- ulint hint, /* in: hint of which page would be desirable */
- byte direction, /* in: if the new page is needed because
- of an index page split, and records are
- inserted there in order, into which
- direction they go alphabetically: FSP_DOWN,
- FSP_UP, FSP_NO_DIR */
- mtr_t* mtr); /* in: mtr handle */
-/**************************************************************************
-Allocates a single free page from a segment. This function implements
-the intelligent allocation strategy which tries to minimize file space
-fragmentation. */
-
-ulint
-fseg_alloc_free_page_general(
-/*=========================*/
- /* out: allocated page offset, FIL_NULL if no
- page could be allocated */
- fseg_header_t* seg_header,/* in: segment header */
- ulint hint, /* in: hint of which page would be desirable */
- byte direction,/* in: if the new page is needed because
- of an index page split, and records are
- inserted there in order, into which
- direction they go alphabetically: FSP_DOWN,
- FSP_UP, FSP_NO_DIR */
- ibool has_done_reservation, /* in: TRUE if the caller has
- already done the reservation for the page
- with fsp_reserve_free_extents, then there
- is no need to do the check for this individual
- page */
- mtr_t* mtr); /* in: mtr handle */
-/**************************************************************************
-Reserves free pages from a tablespace. All mini-transactions which may
-use several pages from the tablespace should call this function beforehand
-and reserve enough free extents so that they certainly will be able
-to do their operation, like a B-tree page split, fully. Reservations
-must be released with function fil_space_release_free_extents!
-
-The alloc_type below has the following meaning: FSP_NORMAL means an
-operation which will probably result in more space usage, like an
-insert in a B-tree; FSP_UNDO means allocation to undo logs: if we are
-deleting rows, then this allocation will in the long run result in
-less space usage (after a purge); FSP_CLEANING means allocation done
-in a physical record delete (like in a purge) or other cleaning operation
-which will result in less space usage in the long run. We prefer the latter
-two types of allocation: when space is scarce, FSP_NORMAL allocations
-will not succeed, but the latter two allocations will succeed, if possible.
-The purpose is to avoid dead end where the database is full but the
-user cannot free any space because these freeing operations temporarily
-reserve some space.
-
-Single-table tablespaces whose size is < 32 pages are a special case. In this
-function we would liberally reserve several 64 page extents for every page
-split or merge in a B-tree. But we do not want to waste disk space if the table
-only occupies < 32 pages. That is why we apply different rules in that special
-case, just ensuring that there are 3 free pages available. */
-
-ibool
-fsp_reserve_free_extents(
-/*=====================*/
- /* out: TRUE if we were able to make the reservation */
- ulint* n_reserved,/* out: number of extents actually reserved; if we
- return TRUE and the tablespace size is < 64 pages,
- then this can be 0, otherwise it is n_ext */
- ulint space, /* in: space id */
- ulint n_ext, /* in: number of extents to reserve */
- ulint alloc_type,/* in: FSP_NORMAL, FSP_UNDO, or FSP_CLEANING */
- mtr_t* mtr); /* in: mtr */
-/**************************************************************************
-This function should be used to get information on how much we still
-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. */
-
-ullint
-fsp_get_available_space_in_free_extents(
-/*====================================*/
- /* out: available space in kB */
- ulint space); /* in: space id */
-/**************************************************************************
-Frees a single page of a segment. */
-
-void
-fseg_free_page(
-/*===========*/
- fseg_header_t* seg_header, /* in: segment header */
- ulint space, /* in: space id */
- ulint page, /* in: page offset */
- mtr_t* mtr); /* in: mtr handle */
-/***********************************************************************
-Frees a segment. The freeing is performed in several mini-transactions,
-so that there is no danger of bufferfixing too many buffer pages. */
-
-void
-fseg_free(
-/*======*/
- ulint space, /* in: space id */
- ulint page_no,/* in: page number where the segment header is
- placed */
- ulint offset);/* in: byte offset of the segment header on that
- page */
-/**************************************************************************
-Frees part of a segment. This function can be used to free a segment
-by repeatedly calling this function in different mini-transactions.
-Doing the freeing in a single mini-transaction might result in
-too big a mini-transaction. */
-
-ibool
-fseg_free_step(
-/*===========*/
- /* out: TRUE if freeing completed */
- fseg_header_t* header, /* in, own: segment header; NOTE: if the header
- resides on the first page of the frag list
- of the segment, this pointer becomes obsolete
- after the last freeing step */
- mtr_t* mtr); /* in: mtr */
-/**************************************************************************
-Frees part of a segment. Differs from fseg_free_step because this function
-leaves the header page unfreed. */
-
-ibool
-fseg_free_step_not_header(
-/*======================*/
- /* out: TRUE if freeing completed, except the
- header page */
- fseg_header_t* header, /* in: segment header which must reside on
- the first fragment page of the segment */
- mtr_t* mtr); /* in: mtr */
-/***************************************************************************
-Checks if a page address is an extent descriptor page address. */
-UNIV_INLINE
-ibool
-fsp_descr_page(
-/*===========*/
- /* out: TRUE if a descriptor page */
- ulint page_no);/* in: page number */
-/***************************************************************
-Parses a redo log record of a file page init. */
-
-byte*
-fsp_parse_init_file_page(
-/*=====================*/
- /* out: end of log record or NULL */
- byte* ptr, /* in: buffer */
- byte* end_ptr,/* in: buffer end */
- page_t* page); /* in: page or NULL */
-/***********************************************************************
-Validates the file space system and its segments. */
-
-ibool
-fsp_validate(
-/*=========*/
- /* out: TRUE if ok */
- ulint space); /* in: space id */
-/***********************************************************************
-Prints info of a file space. */
-
-void
-fsp_print(
-/*======*/
- ulint space); /* in: space id */
-/***********************************************************************
-Validates a segment. */
-
-ibool
-fseg_validate(
-/*==========*/
- /* out: TRUE if ok */
- fseg_header_t* header, /* in: segment header */
- mtr_t* mtr2); /* in: mtr */
-/***********************************************************************
-Writes info of a segment. */
-
-void
-fseg_print(
-/*=======*/
- fseg_header_t* header, /* in: segment header */
- mtr_t* mtr); /* in: mtr */
-
-/* Flags for fsp_reserve_free_extents */
-#define FSP_NORMAL 1000000
-#define FSP_UNDO 2000000
-#define FSP_CLEANING 3000000
-
-/* Number of pages described in a single descriptor page: currently each page
-description takes less than 1 byte; a descriptor page is repeated every
-this many file pages */
-#define XDES_DESCRIBED_PER_PAGE UNIV_PAGE_SIZE
-
-/* The space low address page map */
-/*--------------------------------------*/
- /* The following two pages are repeated
- every XDES_DESCRIBED_PER_PAGE pages in
- every tablespace. */
-#define FSP_XDES_OFFSET 0 /* extent descriptor */
-#define FSP_IBUF_BITMAP_OFFSET 1 /* insert buffer bitmap */
- /* The ibuf bitmap pages are the ones whose
- page number is the number above plus a
- multiple of XDES_DESCRIBED_PER_PAGE */
-
-#define FSP_FIRST_INODE_PAGE_NO 2 /* in every tablespace */
- /* The following pages exist
- in the system tablespace (space 0). */
-#define FSP_IBUF_HEADER_PAGE_NO 3 /* in tablespace 0 */
-#define FSP_IBUF_TREE_ROOT_PAGE_NO 4 /* in tablespace 0 */
- /* The ibuf tree root page number in
- tablespace 0; its fseg inode is on the page
- number FSP_FIRST_INODE_PAGE_NO */
-#define FSP_TRX_SYS_PAGE_NO 5 /* in tablespace 0 */
-#define FSP_FIRST_RSEG_PAGE_NO 6 /* in tablespace 0 */
-#define FSP_DICT_HDR_PAGE_NO 7 /* in tablespace 0 */
-/*--------------------------------------*/
-
-#ifndef UNIV_NONINL
-#include "fsp0fsp.ic"
-#endif
-
-#endif
diff --git a/storage/innobase/include/fsp0fsp.ic b/storage/innobase/include/fsp0fsp.ic
deleted file mode 100644
index 89cd9263bd6..00000000000
--- a/storage/innobase/include/fsp0fsp.ic
+++ /dev/null
@@ -1,24 +0,0 @@
-/******************************************************
-File space management
-
-(c) 1995 Innobase Oy
-
-Created 12/18/1995 Heikki Tuuri
-*******************************************************/
-
-/***************************************************************************
-Checks if a page address is an extent descriptor page address. */
-UNIV_INLINE
-ibool
-fsp_descr_page(
-/*===========*/
- /* out: TRUE if a descriptor page */
- ulint page_no)/* in: page number */
-{
- if (page_no % XDES_DESCRIBED_PER_PAGE == FSP_XDES_OFFSET) {
-
- return(TRUE);
- }
-
- return(FALSE);
-}
diff --git a/storage/innobase/include/fut0fut.h b/storage/innobase/include/fut0fut.h
deleted file mode 100644
index b9546b4e1a0..00000000000
--- a/storage/innobase/include/fut0fut.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/**********************************************************************
-File-based utilities
-
-(c) 1995 Innobase Oy
-
-Created 12/13/1995 Heikki Tuuri
-***********************************************************************/
-
-
-#ifndef fut0fut_h
-#define fut0fut_h
-
-#include "univ.i"
-
-#include "fil0fil.h"
-#include "mtr0mtr.h"
-
-/************************************************************************
-Gets a pointer to a file address and latches the page. */
-UNIV_INLINE
-byte*
-fut_get_ptr(
-/*========*/
- /* out: pointer to a byte in a frame; the file
- page in the frame is bufferfixed and latched */
- ulint space, /* in: space id */
- fil_addr_t addr, /* in: file address */
- ulint rw_latch, /* in: RW_S_LATCH, RW_X_LATCH */
- mtr_t* mtr); /* in: mtr handle */
-
-#ifndef UNIV_NONINL
-#include "fut0fut.ic"
-#endif
-
-#endif
-
diff --git a/storage/innobase/include/fut0fut.ic b/storage/innobase/include/fut0fut.ic
deleted file mode 100644
index 6a107786376..00000000000
--- a/storage/innobase/include/fut0fut.ic
+++ /dev/null
@@ -1,38 +0,0 @@
-/**********************************************************************
-File-based utilities
-
-(c) 1995 Innobase Oy
-
-Created 12/13/1995 Heikki Tuuri
-***********************************************************************/
-
-#include "sync0rw.h"
-#include "buf0buf.h"
-
-/************************************************************************
-Gets a pointer to a file address and latches the page. */
-UNIV_INLINE
-byte*
-fut_get_ptr(
-/*========*/
- /* out: pointer to a byte in a frame; the file
- page in the frame is bufferfixed and latched */
- ulint space, /* in: space id */
- fil_addr_t addr, /* in: file address */
- ulint rw_latch, /* in: RW_S_LATCH, RW_X_LATCH */
- mtr_t* mtr) /* in: mtr handle */
-{
- byte* ptr;
-
- ut_ad(mtr);
- ut_ad(addr.boffset < UNIV_PAGE_SIZE);
- ut_ad((rw_latch == RW_S_LATCH) || (rw_latch == RW_X_LATCH));
-
- ptr = buf_page_get(space, addr.page, rw_latch, mtr) + addr.boffset;
-
-#ifdef UNIV_SYNC_DEBUG
- buf_page_dbg_add_level(ptr, SYNC_NO_ORDER_CHECK);
-#endif /* UNIV_SYNC_DEBUG */
-
- return(ptr);
-}
diff --git a/storage/innobase/include/fut0lst.h b/storage/innobase/include/fut0lst.h
deleted file mode 100644
index 5427e2248da..00000000000
--- a/storage/innobase/include/fut0lst.h
+++ /dev/null
@@ -1,198 +0,0 @@
-/**********************************************************************
-File-based list utilities
-
-(c) 1995 Innobase Oy
-
-Created 11/28/1995 Heikki Tuuri
-***********************************************************************/
-
-#ifndef fut0lst_h
-#define fut0lst_h
-
-#include "univ.i"
-
-#include "fil0fil.h"
-#include "mtr0mtr.h"
-
-
-/* The C 'types' of base node and list node: these should be used to
-write self-documenting code. Of course, the sizeof macro cannot be
-applied to these types! */
-
-typedef byte flst_base_node_t;
-typedef byte flst_node_t;
-
-/* The physical size of a list base node in bytes */
-#define FLST_BASE_NODE_SIZE (4 + 2 * FIL_ADDR_SIZE)
-
-/* The physical size of a list node in bytes */
-#define FLST_NODE_SIZE (2 * FIL_ADDR_SIZE)
-
-
-/************************************************************************
-Initializes a list base node. */
-UNIV_INLINE
-void
-flst_init(
-/*======*/
- flst_base_node_t* base, /* in: pointer to base node */
- mtr_t* mtr); /* in: mini-transaction handle */
-/************************************************************************
-Adds a node as the last node in a list. */
-
-void
-flst_add_last(
-/*==========*/
- flst_base_node_t* base, /* in: pointer to base node of list */
- flst_node_t* node, /* in: node to add */
- mtr_t* mtr); /* in: mini-transaction handle */
-/************************************************************************
-Adds a node as the first node in a list. */
-
-void
-flst_add_first(
-/*===========*/
- flst_base_node_t* base, /* in: pointer to base node of list */
- flst_node_t* node, /* in: node to add */
- mtr_t* mtr); /* in: mini-transaction handle */
-/************************************************************************
-Inserts a node after another in a list. */
-
-void
-flst_insert_after(
-/*==============*/
- flst_base_node_t* base, /* in: pointer to base node of list */
- flst_node_t* node1, /* in: node to insert after */
- flst_node_t* node2, /* in: node to add */
- mtr_t* mtr); /* in: mini-transaction handle */
-/************************************************************************
-Inserts a node before another in a list. */
-
-void
-flst_insert_before(
-/*===============*/
- flst_base_node_t* base, /* in: pointer to base node of list */
- flst_node_t* node2, /* in: node to insert */
- flst_node_t* node3, /* in: node to insert before */
- mtr_t* mtr); /* in: mini-transaction handle */
-/************************************************************************
-Removes a node. */
-
-void
-flst_remove(
-/*========*/
- flst_base_node_t* base, /* in: pointer to base node of list */
- flst_node_t* node2, /* in: node to remove */
- mtr_t* mtr); /* in: mini-transaction handle */
-/************************************************************************
-Cuts off the tail of the list, including the node given. The number of
-nodes which will be removed must be provided by the caller, as this function
-does not measure the length of the tail. */
-
-void
-flst_cut_end(
-/*=========*/
- flst_base_node_t* base, /* in: pointer to base node of list */
- flst_node_t* node2, /* in: first node to remove */
- ulint n_nodes,/* in: number of nodes to remove,
- must be >= 1 */
- mtr_t* mtr); /* in: mini-transaction handle */
-/************************************************************************
-Cuts off the tail of the list, not including the given node. The number of
-nodes which will be removed must be provided by the caller, as this function
-does not measure the length of the tail. */
-
-void
-flst_truncate_end(
-/*==============*/
- flst_base_node_t* base, /* in: pointer to base node of list */
- flst_node_t* node2, /* in: first node not to remove */
- ulint n_nodes,/* in: number of nodes to remove */
- mtr_t* mtr); /* in: mini-transaction handle */
-/************************************************************************
-Gets list length. */
-UNIV_INLINE
-ulint
-flst_get_len(
-/*=========*/
- /* out: length */
- flst_base_node_t* base, /* in: pointer to base node */
- mtr_t* mtr); /* in: mini-transaction handle */
-/************************************************************************
-Gets list first node address. */
-UNIV_INLINE
-fil_addr_t
-flst_get_first(
-/*===========*/
- /* out: file address */
- flst_base_node_t* base, /* in: pointer to base node */
- mtr_t* mtr); /* in: mini-transaction handle */
-/************************************************************************
-Gets list last node address. */
-UNIV_INLINE
-fil_addr_t
-flst_get_last(
-/*==========*/
- /* out: file address */
- flst_base_node_t* base, /* in: pointer to base node */
- mtr_t* mtr); /* in: mini-transaction handle */
-/************************************************************************
-Gets list next node address. */
-UNIV_INLINE
-fil_addr_t
-flst_get_next_addr(
-/*===============*/
- /* out: file address */
- flst_node_t* node, /* in: pointer to node */
- mtr_t* mtr); /* in: mini-transaction handle */
-/************************************************************************
-Gets list prev node address. */
-UNIV_INLINE
-fil_addr_t
-flst_get_prev_addr(
-/*===============*/
- /* out: file address */
- flst_node_t* node, /* in: pointer to node */
- mtr_t* mtr); /* in: mini-transaction handle */
-/************************************************************************
-Writes a file address. */
-UNIV_INLINE
-void
-flst_write_addr(
-/*============*/
- fil_faddr_t* faddr, /* in: pointer to file faddress */
- fil_addr_t addr, /* in: file address */
- mtr_t* mtr); /* in: mini-transaction handle */
-/************************************************************************
-Reads a file address. */
-UNIV_INLINE
-fil_addr_t
-flst_read_addr(
-/*===========*/
- /* out: file address */
- fil_faddr_t* faddr, /* in: pointer to file faddress */
- mtr_t* mtr); /* in: mini-transaction handle */
-/************************************************************************
-Validates a file-based list. */
-
-ibool
-flst_validate(
-/*==========*/
- /* out: TRUE if ok */
- flst_base_node_t* base, /* in: pointer to base node of list */
- mtr_t* mtr1); /* in: mtr */
-/************************************************************************
-Prints info of a file-based list. */
-
-void
-flst_print(
-/*=======*/
- flst_base_node_t* base, /* in: pointer to base node of list */
- mtr_t* mtr); /* in: mtr */
-
-
-#ifndef UNIV_NONINL
-#include "fut0lst.ic"
-#endif
-
-#endif
diff --git a/storage/innobase/include/ha0ha.h b/storage/innobase/include/ha0ha.h
deleted file mode 100644
index beaa06ae755..00000000000
--- a/storage/innobase/include/ha0ha.h
+++ /dev/null
@@ -1,140 +0,0 @@
-/******************************************************
-The hash table with external chains
-
-(c) 1994-1997 Innobase Oy
-
-Created 8/18/1994 Heikki Tuuri
-*******************************************************/
-
-#ifndef ha0ha_h
-#define ha0ha_h
-
-#include "univ.i"
-
-#include "hash0hash.h"
-#include "page0types.h"
-
-/*****************************************************************
-Looks for an element in a hash table. */
-UNIV_INLINE
-void*
-ha_search_and_get_data(
-/*===================*/
- /* out: pointer to the data of the first hash
- table node in chain having the fold number,
- NULL if not found */
- hash_table_t* table, /* in: hash table */
- ulint fold); /* in: folded value of the searched data */
-/*************************************************************
-Looks for an element when we know the pointer to the data and updates
-the pointer to data if found. */
-
-void
-ha_search_and_update_if_found(
-/*==========================*/
- hash_table_t* table, /* in: hash table */
- ulint fold, /* in: folded value of the searched data */
- void* data, /* in: pointer to the data */
- void* new_data);/* in: new pointer to the data */
-/*****************************************************************
-Creates a hash table with >= n array cells. The actual number of cells is
-chosen to be a prime number slightly bigger than n. */
-
-hash_table_t*
-ha_create_func(
-/*===========*/
- /* out, own: created table */
- ibool in_btr_search, /* in: TRUE if the hash table is used in
- the btr_search module */
- ulint n, /* in: number of array cells */
-#ifdef UNIV_SYNC_DEBUG
- ulint mutex_level, /* in: level of the mutexes in the latching
- order: this is used in the debug version */
-#endif /* UNIV_SYNC_DEBUG */
- ulint n_mutexes); /* in: number of mutexes to protect the
- hash table: must be a power of 2 */
-#ifdef UNIV_SYNC_DEBUG
-# define ha_create(b,n_c,n_m,level) ha_create_func(b,n_c,level,n_m)
-#else /* UNIV_SYNC_DEBUG */
-# define ha_create(b,n_c,n_m,level) ha_create_func(b,n_c,n_m)
-#endif /* UNIV_SYNC_DEBUG */
-/*****************************************************************
-Inserts an entry into a hash table. If an entry with the same fold number
-is found, its node is updated to point to the new data, and no new node
-is inserted. */
-
-ibool
-ha_insert_for_fold(
-/*===============*/
- /* out: TRUE if succeed, FALSE if no more
- memory could be allocated */
- hash_table_t* table, /* in: hash table */
- ulint fold, /* in: folded value of data; if a node with
- the same fold value already exists, it is
- updated to point to the same data, and no new
- node is created! */
- void* data); /* in: data, must not be NULL */
-/*****************************************************************
-Deletes an entry from a hash table. */
-
-void
-ha_delete(
-/*======*/
- hash_table_t* table, /* in: hash table */
- ulint fold, /* in: folded value of data */
- void* data); /* in: data, must not be NULL and must exist
- in the hash table */
-/*************************************************************
-Looks for an element when we know the pointer to the data and deletes
-it from the hash table if found. */
-UNIV_INLINE
-ibool
-ha_search_and_delete_if_found(
-/*==========================*/
- /* out: TRUE if found */
- hash_table_t* table, /* in: hash table */
- ulint fold, /* in: folded value of the searched data */
- void* data); /* in: pointer to the data */
-/*********************************************************************
-Removes from the chain determined by fold all nodes whose data pointer
-points to the page given. */
-
-void
-ha_remove_all_nodes_to_page(
-/*========================*/
- hash_table_t* table, /* in: hash table */
- ulint fold, /* in: fold value */
- page_t* page); /* in: buffer page */
-/*****************************************************************
-Validates a given range of the cells in hash table. */
-
-ibool
-ha_validate(
-/*========*/
- /* out: TRUE if ok */
- hash_table_t* table, /* in: hash table */
- ulint start_index, /* in: start index */
- ulint end_index); /* in: end index */
-/*****************************************************************
-Prints info of a hash table. */
-
-void
-ha_print_info(
-/*==========*/
- FILE* file, /* in: file where to print */
- hash_table_t* table); /* in: hash table */
-
-/* The hash table external chain node */
-
-typedef struct ha_node_struct ha_node_t;
-struct ha_node_struct {
- ha_node_t* next; /* next chain node or NULL if none */
- void* data; /* pointer to the data */
- ulint fold; /* fold value for the data */
-};
-
-#ifndef UNIV_NONINL
-#include "ha0ha.ic"
-#endif
-
-#endif
diff --git a/storage/innobase/include/ha0ha.ic b/storage/innobase/include/ha0ha.ic
deleted file mode 100644
index fb264377f28..00000000000
--- a/storage/innobase/include/ha0ha.ic
+++ /dev/null
@@ -1,185 +0,0 @@
-/************************************************************************
-The hash table with external chains
-
-(c) 1994-1997 Innobase Oy
-
-Created 8/18/1994 Heikki Tuuri
-*************************************************************************/
-
-#include "ut0rnd.h"
-#include "mem0mem.h"
-
-/***************************************************************
-Deletes a hash node. */
-
-void
-ha_delete_hash_node(
-/*================*/
- hash_table_t* table, /* in: hash table */
- ha_node_t* del_node); /* in: node to be deleted */
-
-/**********************************************************************
-Gets a hash node data. */
-UNIV_INLINE
-void*
-ha_node_get_data(
-/*=============*/
- /* out: pointer to the data */
- ha_node_t* node) /* in: hash chain node */
-{
- return(node->data);
-}
-
-/**********************************************************************
-Sets hash node data. */
-UNIV_INLINE
-void
-ha_node_set_data(
-/*=============*/
- ha_node_t* node, /* in: hash chain node */
- void* data) /* in: pointer to the data */
-{
- node->data = data;
-}
-
-/**********************************************************************
-Gets the next node in a hash chain. */
-UNIV_INLINE
-ha_node_t*
-ha_chain_get_next(
-/*==============*/
- /* out: next node, NULL if none */
- ha_node_t* node) /* in: hash chain node */
-{
- return(node->next);
-}
-
-/**********************************************************************
-Gets the first node in a hash chain. */
-UNIV_INLINE
-ha_node_t*
-ha_chain_get_first(
-/*===============*/
- /* out: first node, NULL if none */
- hash_table_t* table, /* in: hash table */
- ulint fold) /* in: fold value determining the chain */
-{
- return(hash_get_nth_cell(table, hash_calc_hash(fold, table))->node);
-}
-
-/*****************************************************************
-Looks for an element in a hash table. */
-UNIV_INLINE
-ha_node_t*
-ha_search(
-/*======*/
- /* out: pointer to the first hash table node
- in chain having the fold number, NULL if not
- found */
- hash_table_t* table, /* in: hash table */
- ulint fold) /* in: folded value of the searched data */
-{
- ha_node_t* node;
-
- ut_ad(!table->mutexes || mutex_own(hash_get_mutex(table, fold)));
-
- node = ha_chain_get_first(table, fold);
-
- while (node) {
- if (node->fold == fold) {
-
- return(node);
- }
-
- node = ha_chain_get_next(node);
- }
-
- return(NULL);
-}
-
-/*****************************************************************
-Looks for an element in a hash table. */
-UNIV_INLINE
-void*
-ha_search_and_get_data(
-/*===================*/
- /* out: pointer to the data of the first hash
- table node in chain having the fold number,
- NULL if not found */
- hash_table_t* table, /* in: hash table */
- ulint fold) /* in: folded value of the searched data */
-{
- ha_node_t* node;
-
- ut_ad(!table->mutexes || mutex_own(hash_get_mutex(table, fold)));
-
- node = ha_chain_get_first(table, fold);
-
- while (node) {
- if (node->fold == fold) {
-
- return(node->data);
- }
-
- node = ha_chain_get_next(node);
- }
-
- return(NULL);
-}
-
-/*************************************************************
-Looks for an element when we know the pointer to the data. */
-UNIV_INLINE
-ha_node_t*
-ha_search_with_data(
-/*================*/
- /* out: pointer to the hash table node, NULL
- if not found in the table */
- hash_table_t* table, /* in: hash table */
- ulint fold, /* in: folded value of the searched data */
- void* data) /* in: pointer to the data */
-{
- ha_node_t* node;
-
- ut_ad(!table->mutexes || mutex_own(hash_get_mutex(table, fold)));
-
- node = ha_chain_get_first(table, fold);
-
- while (node) {
- if (node->data == data) {
-
- return(node);
- }
-
- node = ha_chain_get_next(node);
- }
-
- return(NULL);
-}
-
-/*************************************************************
-Looks for an element when we know the pointer to the data, and deletes
-it from the hash table, if found. */
-UNIV_INLINE
-ibool
-ha_search_and_delete_if_found(
-/*==========================*/
- /* out: TRUE if found */
- hash_table_t* table, /* in: hash table */
- ulint fold, /* in: folded value of the searched data */
- void* data) /* in: pointer to the data */
-{
- ha_node_t* node;
-
- ut_ad(!table->mutexes || mutex_own(hash_get_mutex(table, fold)));
-
- node = ha_search_with_data(table, fold, data);
-
- if (node) {
- ha_delete_hash_node(table, node);
-
- return(TRUE);
- }
-
- return(FALSE);
-}
diff --git a/storage/innobase/include/ha_prototypes.h b/storage/innobase/include/ha_prototypes.h
deleted file mode 100644
index 6bfc43579b3..00000000000
--- a/storage/innobase/include/ha_prototypes.h
+++ /dev/null
@@ -1,76 +0,0 @@
-#ifndef HA_INNODB_PROTOTYPES_H
-#define HA_INNODB_PROTOTYPES_H
-
-#ifndef UNIV_HOTBACKUP
-
-#include "univ.i" /* ulint, uint */
-#include "m_ctype.h" /* CHARSET_INFO */
-
-/* Prototypes for global functions in ha_innodb.cc that are called by
-InnoDB's C-code. */
-
-/*************************************************************************
-Wrapper around MySQL's copy_and_convert function, see it for
-documentation. */
-
-ulint
-innobase_convert_string(
-/*====================*/
- void* to,
- ulint to_length,
- CHARSET_INFO* to_cs,
- const void* from,
- ulint from_length,
- CHARSET_INFO* from_cs,
- uint* errors);
-
-/*********************************************************************
-Display an SQL identifier. */
-
-void
-innobase_print_identifier(
-/*======================*/
- FILE* f, /* in: output stream */
- trx_t* trx, /* in: transaction */
- ibool table_id,/* in: TRUE=print a table name,
- FALSE=print other identifier */
- const char* name, /* in: name to print */
- ulint namelen);/* in: length of name */
-
-/**********************************************************************
-Returns true if the thread is the replication thread on the slave
-server. Used in srv_conc_enter_innodb() to determine if the thread
-should be allowed to enter InnoDB - the replication thread is treated
-differently than other threads. Also used in
-srv_conc_force_exit_innodb(). */
-
-ibool
-thd_is_replication_slave_thread(
-/*============================*/
- /* out: true if thd is the replication thread */
- void* thd); /* in: thread handle (THD*) */
-
-/**********************************************************************
-Returns true if the transaction this thread is processing has edited
-non-transactional tables. Used by the deadlock detector when deciding
-which transaction to rollback in case of a deadlock - we try to avoid
-rolling back transactions that have edited non-transactional tables. */
-
-ibool
-thd_has_edited_nontrans_tables(
-/*===========================*/
- /* out: true if non-transactional tables have
- been edited */
- void* thd); /* in: thread handle (THD*) */
-
-/**********************************************************************
-Returns true if the thread is executing a SELECT statement. */
-
-ibool
-thd_is_select(
-/*==========*/
- /* out: true if thd is executing SELECT */
- const void* thd); /* in: thread handle (THD*) */
-
-#endif
-#endif
diff --git a/storage/innobase/include/hash0hash.ic b/storage/innobase/include/hash0hash.ic
deleted file mode 100644
index d246d8ee831..00000000000
--- a/storage/innobase/include/hash0hash.ic
+++ /dev/null
@@ -1,131 +0,0 @@
-/******************************************************
-The simple hash table utility
-
-(c) 1997 Innobase Oy
-
-Created 5/20/1997 Heikki Tuuri
-*******************************************************/
-
-#include "ut0rnd.h"
-
-/****************************************************************
-Gets the nth cell in a hash table. */
-UNIV_INLINE
-hash_cell_t*
-hash_get_nth_cell(
-/*==============*/
- /* out: pointer to cell */
- hash_table_t* table, /* in: hash table */
- ulint n) /* in: cell index */
-{
- ut_ad(n < table->n_cells);
-
- return(table->array + n);
-}
-
-/*****************************************************************
-Returns the number of cells in a hash table. */
-UNIV_INLINE
-ulint
-hash_get_n_cells(
-/*=============*/
- /* out: number of cells */
- hash_table_t* table) /* in: table */
-{
- return(table->n_cells);
-}
-
-/******************************************************************
-Calculates the hash value from a folded value. */
-UNIV_INLINE
-ulint
-hash_calc_hash(
-/*===========*/
- /* out: hashed value */
- ulint fold, /* in: folded value */
- hash_table_t* table) /* in: hash table */
-{
- return(ut_hash_ulint(fold, table->n_cells));
-}
-
-/****************************************************************
-Gets the mutex index for a fold value in a hash table. */
-UNIV_INLINE
-ulint
-hash_get_mutex_no(
-/*==============*/
- /* out: mutex number */
- hash_table_t* table, /* in: hash table */
- ulint fold) /* in: fold */
-{
- return(ut_2pow_remainder(hash_calc_hash(fold, table),
- table->n_mutexes));
-}
-
-/****************************************************************
-Gets the nth heap in a hash table. */
-UNIV_INLINE
-mem_heap_t*
-hash_get_nth_heap(
-/*==============*/
- /* out: mem heap */
- hash_table_t* table, /* in: hash table */
- ulint i) /* in: index of the heap */
-{
- ut_ad(i < table->n_mutexes);
-
- return(table->heaps[i]);
-}
-
-/****************************************************************
-Gets the heap for a fold value in a hash table. */
-UNIV_INLINE
-mem_heap_t*
-hash_get_heap(
-/*==========*/
- /* out: mem heap */
- hash_table_t* table, /* in: hash table */
- ulint fold) /* in: fold */
-{
- ulint i;
-
- if (table->heap) {
- return(table->heap);
- }
-
- i = hash_get_mutex_no(table, fold);
-
- return(hash_get_nth_heap(table, i));
-}
-
-/****************************************************************
-Gets the nth mutex in a hash table. */
-UNIV_INLINE
-mutex_t*
-hash_get_nth_mutex(
-/*===============*/
- /* out: mutex */
- hash_table_t* table, /* in: hash table */
- ulint i) /* in: index of the mutex */
-{
- ut_ad(i < table->n_mutexes);
-
- return(table->mutexes + i);
-}
-
-/****************************************************************
-Gets the mutex for a fold value in a hash table. */
-UNIV_INLINE
-mutex_t*
-hash_get_mutex(
-/*===========*/
- /* out: mutex */
- hash_table_t* table, /* in: hash table */
- ulint fold) /* in: fold */
-{
- ulint i;
-
- i = hash_get_mutex_no(table, fold);
-
- return(hash_get_nth_mutex(table, i));
-}
diff --git a/storage/innobase/include/ibuf0ibuf.h b/storage/innobase/include/ibuf0ibuf.h
deleted file mode 100644
index 77fefe2020b..00000000000
--- a/storage/innobase/include/ibuf0ibuf.h
+++ /dev/null
@@ -1,309 +0,0 @@
-/******************************************************
-Insert buffer
-
-(c) 1997 Innobase Oy
-
-Created 7/19/1997 Heikki Tuuri
-*******************************************************/
-
-#ifndef ibuf0ibuf_h
-#define ibuf0ibuf_h
-
-#include "univ.i"
-
-#include "dict0mem.h"
-#include "dict0dict.h"
-#include "mtr0mtr.h"
-#include "que0types.h"
-#include "ibuf0types.h"
-#include "fsp0fsp.h"
-
-extern ibuf_t* ibuf;
-
-/**********************************************************************
-Creates the insert buffer data struct for a single tablespace. Reads the
-root page of the insert buffer tree in the tablespace. This function can
-be called only after the dictionary system has been initialized, as this
-creates also the insert buffer table and index for this tablespace. */
-
-ibuf_data_t*
-ibuf_data_init_for_space(
-/*=====================*/
- /* out, own: ibuf data struct, linked to the list
- in ibuf control structure. */
- ulint space); /* in: space id */
-/**********************************************************************
-Creates the insert buffer data structure at a database startup and
-initializes the data structures for the insert buffer of each tablespace. */
-
-void
-ibuf_init_at_db_start(void);
-/*=======================*/
-/*************************************************************************
-Reads the biggest tablespace id from the high end of the insert buffer
-tree and updates the counter in fil_system. */
-
-void
-ibuf_update_max_tablespace_id(void);
-/*===============================*/
-/*************************************************************************
-Initializes an ibuf bitmap page. */
-
-void
-ibuf_bitmap_page_init(
-/*==================*/
- page_t* page, /* in: bitmap page */
- mtr_t* mtr); /* in: mtr */
-/****************************************************************************
-Resets the free bits of the page in the ibuf bitmap. This is done in a
-separate mini-transaction, hence this operation does not restrict further
-work to only ibuf bitmap operations, which would result if the latch to the
-bitmap page were kept. */
-
-void
-ibuf_reset_free_bits_with_type(
-/*===========================*/
- ulint type, /* in: index type */
- page_t* page); /* in: index page; free bits are set to 0 if the index
- is non-clustered and non-unique and the page level is
- 0 */
-/****************************************************************************
-Resets the free bits of the page in the ibuf bitmap. This is done in a
-separate mini-transaction, hence this operation does not restrict further
-work to solely ibuf bitmap operations, which would result if the latch to
-the bitmap page were kept. */
-
-void
-ibuf_reset_free_bits(
-/*=================*/
- dict_index_t* index, /* in: index */
- page_t* page); /* in: index page; free bits are set to 0 if
- the index is non-clustered and non-unique and
- the page level is 0 */
-/****************************************************************************
-Updates the free bits of the page in the ibuf bitmap if there is not enough
-free on the page any more. This is done in a separate mini-transaction, hence
-this operation does not restrict further work to only ibuf bitmap operations,
-which would result if the latch to the bitmap page were kept. */
-UNIV_INLINE
-void
-ibuf_update_free_bits_if_full(
-/*==========================*/
- dict_index_t* index, /* in: index */
- page_t* page, /* in: index page to which we have added new
- records; the free bits are updated if the
- index is non-clustered and non-unique and
- the page level is 0, and the page becomes
- fuller */
- ulint max_ins_size,/* in: value of maximum insert size with
- reorganize before the latest operation
- performed to the page */
- ulint increase);/* in: upper limit for the additional space
- used in the latest operation, if known, or
- ULINT_UNDEFINED */
-/**************************************************************************
-Updates the free bits for the page to reflect the present state. Does this
-in the mtr given, which means that the latching order rules virtually
-prevent any further operations for this OS thread until mtr is committed. */
-
-void
-ibuf_update_free_bits_low(
-/*======================*/
- dict_index_t* index, /* in: index */
- page_t* page, /* in: index page */
- ulint max_ins_size, /* in: value of maximum insert size
- with reorganize before the latest
- operation performed to the page */
- mtr_t* mtr); /* in: mtr */
-/**************************************************************************
-Updates the free bits for the two pages to reflect the present state. Does
-this in the mtr given, which means that the latching order rules virtually
-prevent any further operations until mtr is committed. */
-
-void
-ibuf_update_free_bits_for_two_pages_low(
-/*====================================*/
- dict_index_t* index, /* in: index */
- page_t* page1, /* in: index page */
- page_t* page2, /* in: index page */
- mtr_t* mtr); /* in: mtr */
-/**************************************************************************
-A basic partial test if an insert to the insert buffer could be possible and
-recommended. */
-UNIV_INLINE
-ibool
-ibuf_should_try(
-/*============*/
- dict_index_t* index, /* in: index where to insert */
- ulint ignore_sec_unique); /* in: if != 0, we should
- ignore UNIQUE constraint on
- a secondary index when we
- decide */
-/**********************************************************************
-Returns TRUE if the current OS thread is performing an insert buffer
-routine. */
-
-ibool
-ibuf_inside(void);
-/*=============*/
- /* out: TRUE if inside an insert buffer routine: for instance,
- a read-ahead of non-ibuf pages is then forbidden */
-/***************************************************************************
-Checks if a page address is an ibuf bitmap page (level 3 page) address. */
-UNIV_INLINE
-ibool
-ibuf_bitmap_page(
-/*=============*/
- /* out: TRUE if a bitmap page */
- ulint page_no);/* in: page number */
-/***************************************************************************
-Checks if a page is a level 2 or 3 page in the ibuf hierarchy of pages. */
-
-ibool
-ibuf_page(
-/*======*/
- /* out: TRUE if level 2 or level 3 page */
- ulint space, /* in: space id */
- ulint page_no);/* in: page number */
-/***************************************************************************
-Checks if a page is a level 2 or 3 page in the ibuf hierarchy of pages. */
-
-ibool
-ibuf_page_low(
-/*==========*/
- /* out: TRUE if level 2 or level 3 page */
- ulint space, /* in: space id */
- ulint page_no,/* in: page number */
- mtr_t* mtr); /* in: mtr which will contain an x-latch to the
- bitmap page if the page is not one of the fixed
- address ibuf pages */
-/***************************************************************************
-Frees excess pages from the ibuf free list. This function is called when an OS
-thread calls fsp services to allocate a new file segment, or a new page to a
-file segment, and the thread did not own the fsp latch before this call. */
-
-void
-ibuf_free_excess_pages(
-/*===================*/
- ulint space); /* in: space id */
-/*************************************************************************
-Makes an index insert to the insert buffer, instead of directly to the disk
-page, if this is possible. Does not do insert if the index is clustered
-or unique. */
-
-ibool
-ibuf_insert(
-/*========*/
- /* out: TRUE if success */
- dtuple_t* entry, /* in: index entry to insert */
- dict_index_t* index, /* in: index where to insert */
- ulint space, /* in: space id where to insert */
- ulint page_no,/* in: page number where to insert */
- que_thr_t* thr); /* in: query thread */
-/*************************************************************************
-When an index page is read from a disk to the buffer pool, this function
-inserts to the page the possible index entries buffered in the insert buffer.
-The entries are deleted from the insert buffer. If the page is not read, but
-created in the buffer pool, this function deletes its buffered entries from
-the insert buffer; there can exist entries for such a page if the page
-belonged to an index which subsequently was dropped. */
-
-void
-ibuf_merge_or_delete_for_page(
-/*==========================*/
- page_t* page, /* in: if page has been read from disk, pointer to
- the page x-latched, else NULL */
- ulint space, /* in: space id of the index page */
- ulint page_no,/* in: page number of the index page */
- ibool update_ibuf_bitmap);/* in: normally this is set to TRUE, but if
- we have deleted or are deleting the tablespace, then we
- naturally do not want to update a non-existent bitmap
- page */
-/*************************************************************************
-Deletes all entries in the insert buffer for a given space id. This is used
-in DISCARD TABLESPACE and IMPORT TABLESPACE.
-NOTE: this does not update the page free bitmaps in the space. The space will
-become CORRUPT when you call this function! */
-
-void
-ibuf_delete_for_discarded_space(
-/*============================*/
- ulint space); /* in: space id */
-/*************************************************************************
-Contracts insert buffer trees by reading pages to the buffer pool. */
-
-ulint
-ibuf_contract(
-/*==========*/
- /* out: a lower limit for the combined size in bytes
- of entries which will be merged from ibuf trees to the
- pages read, 0 if ibuf is empty */
- ibool sync); /* in: TRUE if the caller wants to wait for the
- issued read with the highest tablespace address
- to complete */
-/*************************************************************************
-Contracts insert buffer trees by reading pages to the buffer pool. */
-
-ulint
-ibuf_contract_for_n_pages(
-/*======================*/
- /* out: a lower limit for the combined size in bytes
- of entries which will be merged from ibuf trees to the
- pages read, 0 if ibuf is empty */
- ibool sync, /* in: TRUE if the caller wants to wait for the
- issued read with the highest tablespace address
- to complete */
- ulint n_pages);/* in: try to read at least this many pages to
- the buffer pool and merge the ibuf contents to
- them */
-/*************************************************************************
-Parses a redo log record of an ibuf bitmap page init. */
-
-byte*
-ibuf_parse_bitmap_init(
-/*===================*/
- /* out: end of log record or NULL */
- byte* ptr, /* in: buffer */
- byte* end_ptr,/* in: buffer end */
- page_t* page, /* in: page or NULL */
- mtr_t* mtr); /* in: mtr or NULL */
-#ifdef UNIV_IBUF_DEBUG
-/**********************************************************************
-Gets the ibuf count for a given page. */
-
-ulint
-ibuf_count_get(
-/*===========*/
- /* out: number of entries in the insert buffer
- currently buffered for this page */
- ulint space, /* in: space id */
- ulint page_no);/* in: page number */
-#endif
-/**********************************************************************
-Looks if the insert buffer is empty. */
-
-ibool
-ibuf_is_empty(void);
-/*===============*/
- /* out: TRUE if empty */
-/**********************************************************************
-Prints info of ibuf. */
-
-void
-ibuf_print(
-/*=======*/
- FILE* file); /* in: file where to print */
-
-#define IBUF_HEADER_PAGE_NO FSP_IBUF_HEADER_PAGE_NO
-#define IBUF_TREE_ROOT_PAGE_NO FSP_IBUF_TREE_ROOT_PAGE_NO
-
-/* The ibuf header page currently contains only the file segment header
-for the file segment from which the pages for the ibuf tree are allocated */
-#define IBUF_HEADER PAGE_DATA
-#define IBUF_TREE_SEG_HEADER 0 /* fseg header for ibuf tree */
-
-#ifndef UNIV_NONINL
-#include "ibuf0ibuf.ic"
-#endif
-
-#endif
diff --git a/storage/innobase/include/ibuf0ibuf.ic b/storage/innobase/include/ibuf0ibuf.ic
deleted file mode 100644
index 4d65a7f5250..00000000000
--- a/storage/innobase/include/ibuf0ibuf.ic
+++ /dev/null
@@ -1,224 +0,0 @@
-/******************************************************
-Insert buffer
-
-(c) 1997 Innobase Oy
-
-Created 7/19/1997 Heikki Tuuri
-*******************************************************/
-
-#include "buf0lru.h"
-#include "page0page.h"
-
-extern ulint ibuf_flush_count;
-
-/* If this number is n, an index page must contain at least the page size
-per n bytes of free space for ibuf to try to buffer inserts to this page.
-If there is this much of free space, the corresponding bits are set in the
-ibuf bitmap. */
-#define IBUF_PAGE_SIZE_PER_FREE_SPACE 32
-
-/* Insert buffer data struct for a single tablespace */
-struct ibuf_data_struct{
- ulint space; /* space id */
- ulint seg_size;/* allocated pages if the file segment
- containing ibuf header and tree */
- ulint size; /* size of the insert buffer tree in pages */
- ibool empty; /* after an insert to the ibuf tree is
- performed, this is set to FALSE, and if a
- contract operation finds the tree empty, this
- is set to TRUE */
- ulint free_list_len;
- /* length of the free list */
- ulint height; /* tree height */
- dict_index_t* index; /* insert buffer index */
- UT_LIST_NODE_T(ibuf_data_t) data_list;
- /* list of ibuf data structs */
- ulint n_inserts;/* number of inserts made to the insert
- buffer */
- ulint n_merges;/* number of pages merged */
- ulint n_merged_recs;/* number of records merged */
-};
-
-struct ibuf_struct{
- ulint size; /* current size of the ibuf index
- trees in pages */
- ulint max_size; /* recommended maximum size in pages
- for the ibuf index tree */
- UT_LIST_BASE_NODE_T(ibuf_data_t) data_list;
- /* list of ibuf data structs for
- each tablespace */
-};
-
-/****************************************************************************
-Sets the free bit of the page in the ibuf bitmap. This is done in a separate
-mini-transaction, hence this operation does not restrict further work to only
-ibuf bitmap operations, which would result if the latch to the bitmap page
-were kept. */
-
-void
-ibuf_set_free_bits(
-/*===============*/
- ulint type, /* in: index type */
- page_t* page, /* in: index page; free bit is reset if the index is
- a non-clustered non-unique, and page level is 0 */
- ulint val, /* in: value to set: < 4 */
- ulint max_val);/* in: ULINT_UNDEFINED or a maximum value which
- the bits must have before setting; this is for
- debugging */
-
-/**************************************************************************
-A basic partial test if an insert to the insert buffer could be possible and
-recommended. */
-UNIV_INLINE
-ibool
-ibuf_should_try(
-/*============*/
- dict_index_t* index, /* in: index where to insert */
- ulint ignore_sec_unique) /* in: if != 0, we should
- ignore UNIQUE constraint on
- a secondary index when we
- decide */
-{
- if (!(index->type & DICT_CLUSTERED)
- && (ignore_sec_unique || !(index->type & DICT_UNIQUE))) {
-
- ibuf_flush_count++;
-
- if (ibuf_flush_count % 8 == 0) {
-
- buf_LRU_try_free_flushed_blocks();
- }
-
- return(TRUE);
- }
-
- return(FALSE);
-}
-
-/***************************************************************************
-Checks if a page address is an ibuf bitmap page address. */
-UNIV_INLINE
-ibool
-ibuf_bitmap_page(
-/*=============*/
- /* out: TRUE if a bitmap page */
- ulint page_no)/* in: page number */
-{
- if (page_no % XDES_DESCRIBED_PER_PAGE == FSP_IBUF_BITMAP_OFFSET) {
-
- return(TRUE);
- }
-
- return(FALSE);
-}
-
-/*************************************************************************
-Translates the free space on a page to a value in the ibuf bitmap.*/
-UNIV_INLINE
-ulint
-ibuf_index_page_calc_free_bits(
-/*===========================*/
- /* out: value for ibuf bitmap bits */
- ulint max_ins_size) /* in: maximum insert size after reorganize
- for the page */
-{
- ulint n;
-
- n = max_ins_size / (UNIV_PAGE_SIZE / IBUF_PAGE_SIZE_PER_FREE_SPACE);
-
- if (n == 3) {
- n = 2;
- }
-
- if (n > 3) {
- n = 3;
- }
-
- return(n);
-}
-
-/*************************************************************************
-Translates the ibuf free bits to the free space on a page in bytes. */
-UNIV_INLINE
-ulint
-ibuf_index_page_calc_free_from_bits(
-/*================================*/
- /* out: maximum insert size after reorganize for the
- page */
- ulint bits) /* in: value for ibuf bitmap bits */
-{
- ut_ad(bits < 4);
-
- if (bits == 3) {
- return(4 * UNIV_PAGE_SIZE / IBUF_PAGE_SIZE_PER_FREE_SPACE);
- }
-
- return(bits * UNIV_PAGE_SIZE / IBUF_PAGE_SIZE_PER_FREE_SPACE);
-}
-
-/*************************************************************************
-Translates the free space on a page to a value in the ibuf bitmap.*/
-UNIV_INLINE
-ulint
-ibuf_index_page_calc_free(
-/*======================*/
- /* out: value for ibuf bitmap bits */
- page_t* page) /* in: non-unique secondary index page */
-{
- return(ibuf_index_page_calc_free_bits(
- page_get_max_insert_size_after_reorganize(page, 1)));
-}
-
-/****************************************************************************
-Updates the free bits of the page in the ibuf bitmap if there is not enough
-free on the page any more. This is done in a separate mini-transaction, hence
-this operation does not restrict further work to only ibuf bitmap operations,
-which would result if the latch to the bitmap page were kept. */
-UNIV_INLINE
-void
-ibuf_update_free_bits_if_full(
-/*==========================*/
- dict_index_t* index, /* in: index */
- page_t* page, /* in: index page to which we have added new
- records; the free bits are updated if the
- index is non-clustered and non-unique and
- the page level is 0, and the page becomes
- fuller */
- ulint max_ins_size,/* in: value of maximum insert size with
- reorganize before the latest operation
- performed to the page */
- ulint increase)/* in: upper limit for the additional space
- used in the latest operation, if known, or
- ULINT_UNDEFINED */
-{
- ulint before;
- ulint after;
-
- before = ibuf_index_page_calc_free_bits(max_ins_size);
-
- if (max_ins_size >= increase) {
-#if ULINT32_UNDEFINED <= UNIV_PAGE_SIZE
-# error "ULINT32_UNDEFINED <= UNIV_PAGE_SIZE"
-#endif
- after = ibuf_index_page_calc_free_bits(max_ins_size
- - increase);
-#ifdef UNIV_IBUF_DEBUG
- ut_a(after <= ibuf_index_page_calc_free(page));
-#endif
- } else {
- after = ibuf_index_page_calc_free(page);
- }
-
- if (after == 0) {
- /* We move the page to the front of the buffer pool LRU list:
- the purpose of this is to prevent those pages to which we
- cannot make inserts using the insert buffer from slipping
- out of the buffer pool */
-
- buf_page_make_young(page);
- }
-
- if (before > after) {
- ibuf_set_free_bits(index->type, page, after, before);
- }
-}
diff --git a/storage/innobase/include/ibuf0types.h b/storage/innobase/include/ibuf0types.h
deleted file mode 100644
index fb202ac44b0..00000000000
--- a/storage/innobase/include/ibuf0types.h
+++ /dev/null
@@ -1,15 +0,0 @@
-/******************************************************
-Insert buffer global types
-
-(c) 1997 Innobase Oy
-
-Created 7/29/1997 Heikki Tuuri
-*******************************************************/
-
-#ifndef ibuf0types_h
-#define ibuf0types_h
-
-typedef struct ibuf_data_struct ibuf_data_t;
-typedef struct ibuf_struct ibuf_t;
-
-#endif
diff --git a/storage/innobase/include/lock0lock.h b/storage/innobase/include/lock0lock.h
deleted file mode 100644
index 635724bf5a1..00000000000
--- a/storage/innobase/include/lock0lock.h
+++ /dev/null
@@ -1,709 +0,0 @@
-/******************************************************
-The transaction lock system
-
-(c) 1996 Innobase Oy
-
-Created 5/7/1996 Heikki Tuuri
-*******************************************************/
-
-#ifndef lock0lock_h
-#define lock0lock_h
-
-#include "univ.i"
-#include "trx0types.h"
-#include "rem0types.h"
-#include "dict0types.h"
-#include "que0types.h"
-#include "page0types.h"
-#include "lock0types.h"
-#include "read0types.h"
-#include "hash0hash.h"
-
-#ifdef UNIV_DEBUG
-extern ibool lock_print_waits;
-#endif /* UNIV_DEBUG */
-/* Buffer for storing information about the most recent deadlock error */
-extern FILE* lock_latest_err_file;
-
-/*************************************************************************
-Gets the size of a lock struct. */
-
-ulint
-lock_get_size(void);
-/*===============*/
- /* out: size in bytes */
-/*************************************************************************
-Creates the lock system at database start. */
-
-void
-lock_sys_create(
-/*============*/
- ulint n_cells); /* in: number of slots in lock hash table */
-/*************************************************************************
-Checks if some transaction has an implicit x-lock on a record in a secondary
-index. */
-
-trx_t*
-lock_sec_rec_some_has_impl_off_kernel(
-/*==================================*/
- /* out: transaction which has the x-lock, or
- NULL */
- rec_t* rec, /* in: user record */
- dict_index_t* index, /* in: secondary index */
- const ulint* offsets);/* in: rec_get_offsets(rec, index) */
-/*************************************************************************
-Checks if some transaction has an implicit x-lock on a record in a clustered
-index. */
-UNIV_INLINE
-trx_t*
-lock_clust_rec_some_has_impl(
-/*=========================*/
- /* out: transaction which has the x-lock, or
- NULL */
- rec_t* rec, /* in: user record */
- dict_index_t* index, /* in: clustered index */
- const ulint* offsets);/* in: rec_get_offsets(rec, index) */
-/*****************************************************************
-Makes a record to inherit the locks of another record as gap type
-locks, but does not reset the lock bits of the other record. Also
-waiting lock requests on rec are inherited as GRANTED gap locks. */
-
-void
-lock_rec_inherit_to_gap(
-/*====================*/
- rec_t* heir, /* in: record which inherits */
- rec_t* rec); /* in: record from which inherited; does NOT reset
- the locks on this record */
-/*****************************************************************
-Updates the lock table when we have reorganized a page. NOTE: we copy
-also the locks set on the infimum of the page; the infimum may carry
-locks if an update of a record is occurring on the page, and its locks
-were temporarily stored on the infimum. */
-
-void
-lock_move_reorganize_page(
-/*======================*/
- page_t* page, /* in: old index page */
- page_t* new_page); /* in: reorganized page */
-/*****************************************************************
-Moves the explicit locks on user records to another page if a record
-list end is moved to another page. */
-
-void
-lock_move_rec_list_end(
-/*===================*/
- page_t* new_page, /* in: index page to move to */
- page_t* page, /* in: index page */
- rec_t* rec); /* in: record on page: this is the
- first record moved */
-/*****************************************************************
-Moves the explicit locks on user records to another page if a record
-list start is moved to another page. */
-
-void
-lock_move_rec_list_start(
-/*=====================*/
- page_t* new_page, /* in: index page to move to */
- page_t* page, /* in: index page */
- rec_t* rec, /* in: record on page: this is the
- first record NOT copied */
- rec_t* old_end); /* in: old previous-to-last record on
- new_page before the records were copied */
-/*****************************************************************
-Updates the lock table when a page is split to the right. */
-
-void
-lock_update_split_right(
-/*====================*/
- page_t* right_page, /* in: right page */
- page_t* left_page); /* in: left page */
-/*****************************************************************
-Updates the lock table when a page is merged to the right. */
-
-void
-lock_update_merge_right(
-/*====================*/
- rec_t* orig_succ, /* in: original successor of infimum
- on the right page before merge */
- page_t* left_page); /* in: merged index page which will be
- discarded */
-/*****************************************************************
-Updates the lock table when the root page is copied to another in
-btr_root_raise_and_insert. Note that we leave lock structs on the
-root page, even though they do not make sense on other than leaf
-pages: the reason is that in a pessimistic update the infimum record
-of the root page will act as a dummy carrier of the locks of the record
-to be updated. */
-
-void
-lock_update_root_raise(
-/*===================*/
- page_t* new_page, /* in: index page to which copied */
- page_t* root); /* in: root page */
-/*****************************************************************
-Updates the lock table when a page is copied to another and the original page
-is removed from the chain of leaf pages, except if page is the root! */
-
-void
-lock_update_copy_and_discard(
-/*=========================*/
- page_t* new_page, /* in: index page to which copied */
- page_t* page); /* in: index page; NOT the root! */
-/*****************************************************************
-Updates the lock table when a page is split to the left. */
-
-void
-lock_update_split_left(
-/*===================*/
- page_t* right_page, /* in: right page */
- page_t* left_page); /* in: left page */
-/*****************************************************************
-Updates the lock table when a page is merged to the left. */
-
-void
-lock_update_merge_left(
-/*===================*/
- page_t* left_page, /* in: left page to which merged */
- rec_t* orig_pred, /* in: original predecessor of supremum
- on the left page before merge */
- page_t* right_page); /* in: merged index page which will be
- discarded */
-/*****************************************************************
-Resets the original locks on heir and replaces them with gap type locks
-inherited from rec. */
-
-void
-lock_rec_reset_and_inherit_gap_locks(
-/*=================================*/
- rec_t* heir, /* in: heir record */
- rec_t* rec); /* in: record */
-/*****************************************************************
-Updates the lock table when a page is discarded. */
-
-void
-lock_update_discard(
-/*================*/
- rec_t* heir, /* in: record which will inherit the locks */
- page_t* page); /* in: index page which will be discarded */
-/*****************************************************************
-Updates the lock table when a new user record is inserted. */
-
-void
-lock_update_insert(
-/*===============*/
- rec_t* rec); /* in: the inserted record */
-/*****************************************************************
-Updates the lock table when a record is removed. */
-
-void
-lock_update_delete(
-/*===============*/
- rec_t* rec); /* in: the record to be removed */
-/*************************************************************************
-Stores on the page infimum record the explicit locks of another record.
-This function is used to store the lock state of a record when it is
-updated and the size of the record changes in the update. The record
-is in such an update moved, perhaps to another page. The infimum record
-acts as a dummy carrier record, taking care of lock releases while the
-actual record is being moved. */
-
-void
-lock_rec_store_on_page_infimum(
-/*===========================*/
- page_t* page, /* in: page containing the record */
- rec_t* rec); /* in: record whose lock state is stored
- on the infimum record of the same page; lock
- bits are reset on the record */
-/*************************************************************************
-Restores the state of explicit lock requests on a single record, where the
-state was stored on the infimum of the page. */
-
-void
-lock_rec_restore_from_page_infimum(
-/*===============================*/
- rec_t* rec, /* in: record whose lock state is restored */
- page_t* page); /* in: page (rec is not necessarily on this page)
- whose infimum stored the lock state; lock bits are
- reset on the infimum */
-/*************************************************************************
-Returns TRUE if there are explicit record locks on a page. */
-
-ibool
-lock_rec_expl_exist_on_page(
-/*========================*/
- /* out: TRUE if there are explicit record locks on
- the page */
- ulint space, /* in: space id */
- ulint page_no);/* in: page number */
-/*************************************************************************
-Checks if locks of other transactions prevent an immediate insert of
-a record. If they do, first tests if the query thread should anyway
-be suspended for some reason; if not, then puts the transaction and
-the query thread to the lock wait state and inserts a waiting request
-for a gap x-lock to the lock queue. */
-
-ulint
-lock_rec_insert_check_and_lock(
-/*===========================*/
- /* out: DB_SUCCESS, DB_LOCK_WAIT,
- DB_DEADLOCK, or DB_QUE_THR_SUSPENDED */
- ulint flags, /* in: if BTR_NO_LOCKING_FLAG bit is set,
- does nothing */
- rec_t* rec, /* in: record after which to insert */
- dict_index_t* index, /* in: index */
- que_thr_t* thr, /* in: query thread */
- ibool* inherit);/* out: set to TRUE if the new inserted
- record maybe should inherit LOCK_GAP type
- locks from the successor record */
-/*************************************************************************
-Checks if locks of other transactions prevent an immediate modify (update,
-delete mark, or delete unmark) of a clustered index record. If they do,
-first tests if the query thread should anyway be suspended for some
-reason; if not, then puts the transaction and the query thread to the
-lock wait state and inserts a waiting request for a record x-lock to the
-lock queue. */
-
-ulint
-lock_clust_rec_modify_check_and_lock(
-/*=================================*/
- /* out: DB_SUCCESS, DB_LOCK_WAIT,
- DB_DEADLOCK, or DB_QUE_THR_SUSPENDED */
- ulint flags, /* in: if BTR_NO_LOCKING_FLAG bit is set,
- does nothing */
- rec_t* rec, /* in: record which should be modified */
- dict_index_t* index, /* in: clustered index */
- const ulint* offsets,/* in: rec_get_offsets(rec, index) */
- que_thr_t* thr); /* in: query thread */
-/*************************************************************************
-Checks if locks of other transactions prevent an immediate modify
-(delete mark or delete unmark) of a secondary index record. */
-
-ulint
-lock_sec_rec_modify_check_and_lock(
-/*===============================*/
- /* out: DB_SUCCESS, DB_LOCK_WAIT,
- DB_DEADLOCK, or DB_QUE_THR_SUSPENDED */
- ulint flags, /* in: if BTR_NO_LOCKING_FLAG bit is set,
- does nothing */
- rec_t* rec, /* in: record which should be modified;
- NOTE: as this is a secondary index, we
- always have to modify the clustered index
- record first: see the comment below */
- dict_index_t* index, /* in: secondary index */
- que_thr_t* thr); /* in: query thread */
-/*************************************************************************
-Like the counterpart for a clustered index below, but now we read a
-secondary index record. */
-
-ulint
-lock_sec_rec_read_check_and_lock(
-/*=============================*/
- /* out: DB_SUCCESS, DB_LOCK_WAIT,
- DB_DEADLOCK, or DB_QUE_THR_SUSPENDED */
- ulint flags, /* in: if BTR_NO_LOCKING_FLAG bit is set,
- does nothing */
- rec_t* rec, /* in: user record or page supremum record
- which should be read or passed over by a read
- cursor */
- dict_index_t* index, /* in: secondary index */
- const ulint* offsets,/* in: rec_get_offsets(rec, index) */
- ulint mode, /* in: mode of the lock which the read cursor
- should set on records: LOCK_S or LOCK_X; the
- latter is possible in SELECT FOR UPDATE */
- ulint gap_mode,/* in: LOCK_ORDINARY, LOCK_GAP, or
- LOCK_REC_NOT_GAP */
- que_thr_t* thr); /* in: query thread */
-/*************************************************************************
-Checks if locks of other transactions prevent an immediate read, or passing
-over by a read cursor, of a clustered index record. If they do, first tests
-if the query thread should anyway be suspended for some reason; if not, then
-puts the transaction and the query thread to the lock wait state and inserts a
-waiting request for a record lock to the lock queue. Sets the requested mode
-lock on the record. */
-
-ulint
-lock_clust_rec_read_check_and_lock(
-/*===============================*/
- /* out: DB_SUCCESS, DB_LOCK_WAIT,
- DB_DEADLOCK, or DB_QUE_THR_SUSPENDED */
- ulint flags, /* in: if BTR_NO_LOCKING_FLAG bit is set,
- does nothing */
- rec_t* rec, /* in: user record or page supremum record
- which should be read or passed over by a read
- cursor */
- dict_index_t* index, /* in: clustered index */
- const ulint* offsets,/* in: rec_get_offsets(rec, index) */
- ulint mode, /* in: mode of the lock which the read cursor
- should set on records: LOCK_S or LOCK_X; the
- latter is possible in SELECT FOR UPDATE */
- ulint gap_mode,/* in: LOCK_ORDINARY, LOCK_GAP, or
- LOCK_REC_NOT_GAP */
- que_thr_t* thr); /* in: query thread */
-/*************************************************************************
-Checks if locks of other transactions prevent an immediate read, or passing
-over by a read cursor, of a clustered index record. If they do, first tests
-if the query thread should anyway be suspended for some reason; if not, then
-puts the transaction and the query thread to the lock wait state and inserts a
-waiting request for a record lock to the lock queue. Sets the requested mode
-lock on the record. This is an alternative version of
-lock_clust_rec_read_check_and_lock() that does not require the parameter
-"offsets". */
-
-ulint
-lock_clust_rec_read_check_and_lock_alt(
-/*===================================*/
- /* out: DB_SUCCESS, DB_LOCK_WAIT,
- DB_DEADLOCK, or DB_QUE_THR_SUSPENDED */
- ulint flags, /* in: if BTR_NO_LOCKING_FLAG bit is set,
- does nothing */
- rec_t* rec, /* in: user record or page supremum record
- which should be read or passed over by a read
- cursor */
- dict_index_t* index, /* in: clustered index */
- ulint mode, /* in: mode of the lock which the read cursor
- should set on records: LOCK_S or LOCK_X; the
- latter is possible in SELECT FOR UPDATE */
- ulint gap_mode,/* in: LOCK_ORDINARY, LOCK_GAP, or
- LOCK_REC_NOT_GAP */
- que_thr_t* thr); /* in: query thread */
-/*************************************************************************
-Checks that a record is seen in a consistent read. */
-
-ibool
-lock_clust_rec_cons_read_sees(
-/*==========================*/
- /* out: TRUE if sees, or FALSE if an earlier
- version of the record should be retrieved */
- rec_t* rec, /* in: user record which should be read or
- passed over by a read cursor */
- dict_index_t* index, /* in: clustered index */
- const ulint* offsets,/* in: rec_get_offsets(rec, index) */
- read_view_t* view); /* in: consistent read view */
-/*************************************************************************
-Checks that a non-clustered index record is seen in a consistent read. */
-
-ulint
-lock_sec_rec_cons_read_sees(
-/*========================*/
- /* out: TRUE if certainly sees, or FALSE if an
- earlier version of the clustered index record
- might be needed: NOTE that a non-clustered
- index page contains so little information on
- its modifications that also in the case FALSE,
- the present version of rec may be the right,
- but we must check this from the clustered
- index record */
- rec_t* rec, /* in: user record which should be read or
- passed over by a read cursor */
- dict_index_t* index, /* in: non-clustered index */
- read_view_t* view); /* in: consistent read view */
-/*************************************************************************
-Locks the specified database table in the mode given. If the lock cannot
-be granted immediately, the query thread is put to wait. */
-
-ulint
-lock_table(
-/*=======*/
- /* out: DB_SUCCESS, DB_LOCK_WAIT,
- DB_DEADLOCK, or DB_QUE_THR_SUSPENDED */
- ulint flags, /* in: if BTR_NO_LOCKING_FLAG bit is set,
- does nothing */
- dict_table_t* table, /* in: database table in dictionary cache */
- ulint mode, /* in: lock mode */
- que_thr_t* thr); /* in: query thread */
-/*************************************************************************
-Checks if there are any locks set on the table. */
-
-ibool
-lock_is_on_table(
-/*=============*/
- /* out: TRUE if there are lock(s) */
- dict_table_t* table); /* in: database table in dictionary cache */
-/*****************************************************************
-Removes a granted record lock of a transaction from the queue and grants
-locks to other transactions waiting in the queue if they now are entitled
-to a lock. */
-
-void
-lock_rec_unlock(
-/*============*/
- trx_t* trx, /* in: transaction that has set a record
- lock */
- rec_t* rec, /* in: record */
- ulint lock_mode); /* in: LOCK_S or LOCK_X */
-/*************************************************************************
-Releases a table lock.
-Releases possible other transactions waiting for this lock. */
-
-void
-lock_table_unlock(
-/*==============*/
- lock_t* lock); /* in: lock */
-/*************************************************************************
-Releases an auto-inc lock a transaction possibly has on a table.
-Releases possible other transactions waiting for this lock. */
-
-void
-lock_table_unlock_auto_inc(
-/*=======================*/
- trx_t* trx); /* in: transaction */
-/*************************************************************************
-Releases transaction locks, and releases possible other transactions waiting
-because of these locks. */
-
-void
-lock_release_off_kernel(
-/*====================*/
- trx_t* trx); /* in: transaction */
-/*************************************************************************
-Cancels a waiting lock request and releases possible other transactions
-waiting behind it. */
-
-void
-lock_cancel_waiting_and_release(
-/*============================*/
- lock_t* lock); /* in: waiting lock request */
-
-/*************************************************************************
-Removes locks on a table to be dropped or truncated.
-If remove_also_table_sx_locks is TRUE then table-level S and X locks are
-also removed in addition to other table-level and record-level locks.
-No lock, that is going to be removed, is allowed to be a wait lock. */
-
-void
-lock_remove_all_on_table(
-/*=====================*/
- dict_table_t* table, /* in: table to be dropped
- or truncated */
- ibool remove_also_table_sx_locks);/* in: also removes
- table S and X locks */
-
-/*************************************************************************
-Calculates the fold value of a page file address: used in inserting or
-searching for a lock in the hash table. */
-UNIV_INLINE
-ulint
-lock_rec_fold(
-/*==========*/
- /* out: folded value */
- ulint space, /* in: space */
- ulint page_no);/* in: page number */
-/*************************************************************************
-Calculates the hash value of a page file address: used in inserting or
-searching for a lock in the hash table. */
-UNIV_INLINE
-ulint
-lock_rec_hash(
-/*==========*/
- /* out: hashed value */
- ulint space, /* in: space */
- ulint page_no);/* in: page number */
-/*************************************************************************
-Gets the source table of an ALTER TABLE transaction. The table must be
-covered by an IX or IS table lock. */
-
-dict_table_t*
-lock_get_src_table(
-/*===============*/
- /* out: the source table of transaction,
- if it is covered by an IX or IS table lock;
- dest if there is no source table, and
- NULL if the transaction is locking more than
- two tables or an inconsistency is found */
- trx_t* trx, /* in: transaction */
- dict_table_t* dest, /* in: destination of ALTER TABLE */
- ulint* mode); /* out: lock mode of the source table */
-/*************************************************************************
-Determine if the given table is exclusively "owned" by the given
-transaction, i.e., transaction holds LOCK_IX and possibly LOCK_AUTO_INC
-on the table. */
-
-ibool
-lock_is_table_exclusive(
-/*====================*/
- /* out: TRUE if table is only locked by trx,
- with LOCK_IX, and possibly LOCK_AUTO_INC */
- 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 */
- lock_t* lock1, /* in: waiting lock */
- 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
-lock_check_trx_id_sanity(
-/*=====================*/
- /* out: TRUE if ok */
- dulint trx_id, /* in: trx id */
- rec_t* rec, /* in: user record */
- dict_index_t* index, /* in: clustered index */
- const ulint* offsets, /* in: rec_get_offsets(rec, index) */
- ibool has_kernel_mutex);/* in: TRUE if the caller owns the
- kernel mutex */
-/*************************************************************************
-Validates the lock queue on a single record. */
-
-ibool
-lock_rec_queue_validate(
-/*====================*/
- /* out: TRUE if ok */
- rec_t* rec, /* in: record to look at */
- dict_index_t* index, /* in: index, or NULL if not known */
- const ulint* offsets);/* in: rec_get_offsets(rec, index) */
-/*************************************************************************
-Prints info of a table lock. */
-
-void
-lock_table_print(
-/*=============*/
- FILE* file, /* in: file where to print */
- lock_t* lock); /* in: table type lock */
-/*************************************************************************
-Prints info of a record lock. */
-
-void
-lock_rec_print(
-/*===========*/
- FILE* file, /* in: file where to print */
- lock_t* lock); /* in: record type lock */
-/*************************************************************************
-Prints info of locks for all transactions. */
-
-void
-lock_print_info_summary(
-/*====================*/
- FILE* file); /* in: file where to print */
-/*************************************************************************
-Prints info of locks for each transaction. */
-
-void
-lock_print_info_all_transactions(
-/*=============================*/
- FILE* file); /* in: file where to print */
-/*************************************************************************
-Validates the lock queue on a table. */
-
-ibool
-lock_table_queue_validate(
-/*======================*/
- /* out: TRUE if ok */
- dict_table_t* table); /* in: table */
-/*************************************************************************
-Validates the record lock queues on a page. */
-
-ibool
-lock_rec_validate_page(
-/*===================*/
- /* out: TRUE if ok */
- ulint space, /* in: space id */
- ulint page_no);/* in: page number */
-/*************************************************************************
-Validates the lock system. */
-
-ibool
-lock_validate(void);
-/*===============*/
- /* out: TRUE if ok */
-/*************************************************************************
-Return approximate number or record locks (bits set in the bitmap) for
-this transaction. Since delete-marked records may be removed, the
-record count will not be precise. */
-
-ulint
-lock_number_of_rows_locked(
-/*=======================*/
- trx_t* trx); /* in: transaction */
-
-/* The lock system */
-extern lock_sys_t* lock_sys;
-
-/* Lock modes and types */
-/* Basic modes */
-#define LOCK_NONE 0 /* this flag is used elsewhere to note
- consistent read */
-#define LOCK_IS 2 /* intention shared */
-#define LOCK_IX 3 /* intention exclusive */
-#define LOCK_S 4 /* shared */
-#define LOCK_X 5 /* exclusive */
-#define LOCK_AUTO_INC 6 /* locks the auto-inc counter of a table
- in an exclusive mode */
-#define LOCK_MODE_MASK 0xFUL /* mask used to extract mode from the
- type_mode field in a lock */
-/* Lock types */
-#define LOCK_TABLE 16 /* these type values should be so high that */
-#define LOCK_REC 32 /* they can be ORed to the lock mode */
-#define LOCK_TYPE_MASK 0xF0UL /* mask used to extract lock type from the
- type_mode field in a lock */
-/* Waiting lock flag */
-#define LOCK_WAIT 256 /* this wait bit should be so high that
- it can be ORed to the lock mode and type;
- when this bit is set, it means that the
- lock has not yet been granted, it is just
- waiting for its turn in the wait queue */
-/* Precise modes */
-#define LOCK_ORDINARY 0 /* this flag denotes an ordinary next-key lock
- in contrast to LOCK_GAP or LOCK_REC_NOT_GAP */
-#define LOCK_GAP 512 /* this gap bit should be so high that
- it can be ORed to the other flags;
- when this bit is set, it means that the
- lock holds only on the gap before the record;
- for instance, an x-lock on the gap does not
- give permission to modify the record on which
- the bit is set; locks of this type are created
- when records are removed from the index chain
- of records */
-#define LOCK_REC_NOT_GAP 1024 /* this bit means that the lock is only on
- the index record and does NOT block inserts
- to the gap before the index record; this is
- used in the case when we retrieve a record
- with a unique key, and is also used in
- locking plain SELECTs (not part of UPDATE
- or DELETE) when the user has set the READ
- COMMITTED isolation level */
-#define LOCK_INSERT_INTENTION 2048 /* this bit is set when we place a waiting
- gap type record lock request in order to let
- an insert of an index record to wait until
- there are no conflicting locks by other
- transactions on the gap; note that this flag
- remains set when the waiting lock is granted,
- or if the lock is inherited to a neighboring
- record */
-
-/* When lock bits are reset, the following flags are available: */
-#define LOCK_RELEASE_WAIT 1
-#define LOCK_NOT_RELEASE_WAIT 2
-
-/* Lock operation struct */
-typedef struct lock_op_struct lock_op_t;
-struct lock_op_struct{
- dict_table_t* table; /* table to be locked */
- ulint mode; /* lock mode */
-};
-
-#define LOCK_OP_START 1
-#define LOCK_OP_COMPLETE 2
-
-/* The lock system struct */
-struct lock_sys_struct{
- hash_table_t* rec_hash; /* hash table of the record locks */
-};
-
-/* The lock system */
-extern lock_sys_t* lock_sys;
-
-
-#ifndef UNIV_NONINL
-#include "lock0lock.ic"
-#endif
-
-#endif
diff --git a/storage/innobase/include/lock0lock.ic b/storage/innobase/include/lock0lock.ic
deleted file mode 100644
index 311623b190b..00000000000
--- a/storage/innobase/include/lock0lock.ic
+++ /dev/null
@@ -1,81 +0,0 @@
-/******************************************************
-The transaction lock system
-
-(c) 1996 Innobase Oy
-
-Created 5/7/1996 Heikki Tuuri
-*******************************************************/
-
-#include "sync0sync.h"
-#include "srv0srv.h"
-#include "dict0dict.h"
-#include "row0row.h"
-#include "trx0sys.h"
-#include "trx0trx.h"
-#include "buf0buf.h"
-#include "page0page.h"
-#include "page0cur.h"
-#include "row0vers.h"
-#include "que0que.h"
-#include "btr0cur.h"
-#include "read0read.h"
-#include "log0recv.h"
-
-/*************************************************************************
-Calculates the fold value of a page file address: used in inserting or
-searching for a lock in the hash table. */
-UNIV_INLINE
-ulint
-lock_rec_fold(
-/*==========*/
- /* out: folded value */
- ulint space, /* in: space */
- ulint page_no)/* in: page number */
-{
- return(ut_fold_ulint_pair(space, page_no));
-}
-
-/*************************************************************************
-Calculates the hash value of a page file address: used in inserting or
-searching for a lock in the hash table. */
-UNIV_INLINE
-ulint
-lock_rec_hash(
-/*==========*/
- /* out: hashed value */
- ulint space, /* in: space */
- ulint page_no)/* in: page number */
-{
- return(hash_calc_hash(lock_rec_fold(space, page_no),
- lock_sys->rec_hash));
-}
-
-/*************************************************************************
-Checks if some transaction has an implicit x-lock on a record in a clustered
-index. */
-UNIV_INLINE
-trx_t*
-lock_clust_rec_some_has_impl(
-/*=========================*/
- /* out: transaction which has the x-lock, or
- NULL */
- rec_t* rec, /* in: user record */
- dict_index_t* index, /* in: clustered index */
- const ulint* offsets)/* in: rec_get_offsets(rec, index) */
-{
- dulint trx_id;
-
- ut_ad(mutex_own(&kernel_mutex));
- ut_ad(index->type & DICT_CLUSTERED);
- ut_ad(page_rec_is_user_rec(rec));
-
- trx_id = row_get_rec_trx_id(rec, index, offsets);
-
- if (trx_is_active(trx_id)) {
- /* The modifying or inserting transaction is active */
-
- return(trx_get_on_id(trx_id));
- }
-
- return(NULL);
-}
diff --git a/storage/innobase/include/lock0priv.h b/storage/innobase/include/lock0priv.h
deleted file mode 100644
index 7703a2b7def..00000000000
--- a/storage/innobase/include/lock0priv.h
+++ /dev/null
@@ -1,101 +0,0 @@
-/******************************************************
-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 */
- lock_t* lock); /* in: record lock with at least one bit set */
-
-/*************************************************************************
-Gets the previous record lock set on a record. */
-
-lock_t*
-lock_rec_get_prev(
-/*==============*/
- /* out: previous lock on the same record, NULL if
- none exists */
- 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 */
diff --git a/storage/innobase/include/lock0priv.ic b/storage/innobase/include/lock0priv.ic
deleted file mode 100644
index 4bc8397509d..00000000000
--- a/storage/innobase/include/lock0priv.ic
+++ /dev/null
@@ -1,32 +0,0 @@
-/******************************************************
-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: */
diff --git a/storage/innobase/include/lock0types.h b/storage/innobase/include/lock0types.h
deleted file mode 100644
index 43fd2d60da5..00000000000
--- a/storage/innobase/include/lock0types.h
+++ /dev/null
@@ -1,16 +0,0 @@
-/******************************************************
-The transaction lock system global types
-
-(c) 1996 Innobase Oy
-
-Created 5/7/1996 Heikki Tuuri
-*******************************************************/
-
-#ifndef lock0types_h
-#define lock0types_h
-
-#define lock_t ib_lock_t
-typedef struct lock_struct lock_t;
-typedef struct lock_sys_struct lock_sys_t;
-
-#endif
diff --git a/storage/innobase/include/log0recv.h b/storage/innobase/include/log0recv.h
deleted file mode 100644
index 091bbe34562..00000000000
--- a/storage/innobase/include/log0recv.h
+++ /dev/null
@@ -1,349 +0,0 @@
-/******************************************************
-Recovery
-
-(c) 1997 Innobase Oy
-
-Created 9/20/1997 Heikki Tuuri
-*******************************************************/
-
-#ifndef log0recv_h
-#define log0recv_h
-
-#include "univ.i"
-#include "ut0byte.h"
-#include "page0types.h"
-#include "hash0hash.h"
-#include "log0log.h"
-
-#ifdef UNIV_HOTBACKUP
-extern ibool recv_replay_file_ops;
-#endif /* UNIV_HOTBACKUP */
-
-/***********************************************************************
-Reads the checkpoint info needed in hot backup. */
-
-ibool
-recv_read_cp_info_for_backup(
-/*=========================*/
- /* out: TRUE if success */
- byte* hdr, /* in: buffer containing the log group header */
- dulint* lsn, /* out: checkpoint lsn */
- ulint* offset, /* out: checkpoint offset in the log group */
- ulint* fsp_limit,/* out: fsp limit of space 0, 1000000000 if the
- database is running with < version 3.23.50 of InnoDB */
- dulint* cp_no, /* out: checkpoint number */
- dulint* first_header_lsn);
- /* out: lsn of of the start of the first log file */
-/***********************************************************************
-Scans the log segment and n_bytes_scanned is set to the length of valid
-log scanned. */
-
-void
-recv_scan_log_seg_for_backup(
-/*=========================*/
- byte* buf, /* in: buffer containing log data */
- ulint buf_len, /* in: data length in that buffer */
- dulint* scanned_lsn, /* in/out: lsn of buffer start,
- we return scanned lsn */
- ulint* scanned_checkpoint_no,
- /* in/out: 4 lowest bytes of the
- highest scanned checkpoint number so
- far */
- ulint* n_bytes_scanned);/* out: how much we were able to
- scan, smaller than buf_len if log
- data ended here */
-/***********************************************************************
-Returns TRUE if recovery is currently running. */
-UNIV_INLINE
-ibool
-recv_recovery_is_on(void);
-/*=====================*/
-/***********************************************************************
-Returns TRUE if recovery from backup is currently running. */
-UNIV_INLINE
-ibool
-recv_recovery_from_backup_is_on(void);
-/*=================================*/
-/****************************************************************************
-Applies the hashed log records to the page, if the page lsn is less than the
-lsn of a log record. This can be called when a buffer page has just been
-read in, or also for a page already in the buffer pool. */
-
-void
-recv_recover_page(
-/*==============*/
- ibool recover_backup, /* in: TRUE if we are recovering a backup
- page: then we do not acquire any latches
- since the page was read in outside the
- buffer pool */
- ibool just_read_in, /* in: TRUE if the i/o-handler calls this for
- a freshly read page */
- page_t* page, /* in: buffer page */
- ulint space, /* in: space id */
- ulint page_no); /* in: page number */
-/************************************************************
-Recovers from a checkpoint. When this function returns, the database is able
-to start processing of new user transactions, but the function
-recv_recovery_from_checkpoint_finish should be called later to complete
-the recovery and free the resources used in it. */
-
-ulint
-recv_recovery_from_checkpoint_start(
-/*================================*/
- /* out: error code or DB_SUCCESS */
- ulint type, /* in: LOG_CHECKPOINT or LOG_ARCHIVE */
- dulint limit_lsn, /* in: recover up to this lsn if possible */
- dulint min_flushed_lsn,/* in: min flushed lsn from data files */
- dulint max_flushed_lsn);/* in: max flushed lsn from data files */
-/************************************************************
-Completes recovery from a checkpoint. */
-
-void
-recv_recovery_from_checkpoint_finish(void);
-/*======================================*/
-/***********************************************************
-Scans log from a buffer and stores new log data to the parsing buffer. Parses
-and hashes the log records if new data found. */
-
-ibool
-recv_scan_log_recs(
-/*===============*/
- /* out: TRUE if limit_lsn has been reached, or
- not able to scan any more in this log group */
- ibool apply_automatically,/* in: TRUE if we want this function to
- apply log records automatically when the
- hash table becomes full; in the hot backup tool
- the tool does the applying, not this
- function */
- ulint available_memory,/* in: we let the hash table of recs to grow
- to this size, at the maximum */
- ibool store_to_hash, /* in: TRUE if the records should be stored
- to the hash table; this is set to FALSE if just
- debug checking is needed */
- byte* buf, /* in: buffer containing a log segment or
- garbage */
- ulint len, /* in: buffer length */
- dulint start_lsn, /* in: buffer start lsn */
- dulint* contiguous_lsn, /* in/out: it is known that all log groups
- contain contiguous log data up to this lsn */
- dulint* group_scanned_lsn);/* out: scanning succeeded up to this lsn */
-/**********************************************************
-Resets the logs. The contents of log files will be lost! */
-
-void
-recv_reset_logs(
-/*============*/
- dulint lsn, /* in: reset to this lsn rounded up to
- be divisible by OS_FILE_LOG_BLOCK_SIZE,
- after which we add LOG_BLOCK_HDR_SIZE */
-#ifdef UNIV_LOG_ARCHIVE
- ulint arch_log_no, /* in: next archived log file number */
-#endif /* UNIV_LOG_ARCHIVE */
- ibool new_logs_created);/* in: TRUE if resetting logs is done
- at the log creation; FALSE if it is done
- after archive recovery */
-#ifdef UNIV_HOTBACKUP
-/**********************************************************
-Creates new log files after a backup has been restored. */
-
-void
-recv_reset_log_files_for_backup(
-/*============================*/
- const char* log_dir, /* in: log file directory path */
- ulint n_log_files, /* in: number of log files */
- ulint log_file_size, /* in: log file size */
- dulint lsn); /* in: new start lsn, must be
- divisible by OS_FILE_LOG_BLOCK_SIZE */
-#endif /* UNIV_HOTBACKUP */
-/************************************************************
-Creates the recovery system. */
-
-void
-recv_sys_create(void);
-/*=================*/
-/************************************************************
-Inits the recovery system for a recovery operation. */
-
-void
-recv_sys_init(
-/*==========*/
- ibool recover_from_backup, /* in: TRUE if this is called
- to recover from a hot backup */
- ulint available_memory); /* in: available memory in bytes */
-/***********************************************************************
-Empties the hash table of stored log records, applying them to appropriate
-pages. */
-
-void
-recv_apply_hashed_log_recs(
-/*=======================*/
- ibool allow_ibuf); /* in: if TRUE, also ibuf operations are
- allowed during the application; if FALSE,
- no ibuf operations are allowed, and after
- the application all file pages are flushed to
- disk and invalidated in buffer pool: this
- alternative means that no new log records
- can be generated during the application */
-#ifdef UNIV_HOTBACKUP
-/***********************************************************************
-Applies log records in the hash table to a backup. */
-
-void
-recv_apply_log_recs_for_backup(void);
-/*================================*/
-#endif
-#ifdef UNIV_LOG_ARCHIVE
-/************************************************************
-Recovers from archived log files, and also from log files, if they exist. */
-
-ulint
-recv_recovery_from_archive_start(
-/*=============================*/
- /* out: error code or DB_SUCCESS */
- dulint min_flushed_lsn,/* in: min flushed lsn field from the
- data files */
- dulint limit_lsn, /* in: recover up to this lsn if possible */
- ulint first_log_no); /* in: number of the first archived log file
- to use in the recovery; the file will be
- searched from INNOBASE_LOG_ARCH_DIR specified
- in server config file */
-/************************************************************
-Completes recovery from archive. */
-
-void
-recv_recovery_from_archive_finish(void);
-/*===================================*/
-#endif /* UNIV_LOG_ARCHIVE */
-
-/* Block of log record data */
-typedef struct recv_data_struct recv_data_t;
-struct recv_data_struct{
- recv_data_t* next; /* pointer to the next block or NULL */
- /* the log record data is stored physically
- immediately after this struct, max amount
- RECV_DATA_BLOCK_SIZE bytes of it */
-};
-
-/* Stored log record struct */
-typedef struct recv_struct recv_t;
-struct recv_struct{
- byte type; /* log record type */
- ulint len; /* log record body length in bytes */
- recv_data_t* data; /* chain of blocks containing the log record
- body */
- dulint start_lsn;/* start lsn of the log segment written by
- the mtr which generated this log record: NOTE
- that this is not necessarily the start lsn of
- this log record */
- dulint end_lsn;/* end lsn of the log segment written by
- the mtr which generated this log record: NOTE
- that this is not necessarily the end lsn of
- this log record */
- UT_LIST_NODE_T(recv_t)
- rec_list;/* list of log records for this page */
-};
-
-/* Hashed page file address struct */
-typedef struct recv_addr_struct recv_addr_t;
-struct recv_addr_struct{
- ulint state; /* RECV_NOT_PROCESSED, RECV_BEING_PROCESSED,
- or RECV_PROCESSED */
- ulint space; /* space id */
- ulint page_no;/* page number */
- UT_LIST_BASE_NODE_T(recv_t)
- rec_list;/* list of log records for this page */
- hash_node_t addr_hash;
-};
-
-/* Recovery system data structure */
-typedef struct recv_sys_struct recv_sys_t;
-struct recv_sys_struct{
- mutex_t mutex; /* mutex protecting the fields apply_log_recs,
- n_addrs, and the state field in each recv_addr
- struct */
- ibool apply_log_recs;
- /* this is TRUE when log rec application to
- pages is allowed; this flag tells the
- i/o-handler if it should do log record
- application */
- ibool apply_batch_on;
- /* this is TRUE when a log rec application
- batch is running */
- dulint lsn; /* log sequence number */
- ulint last_log_buf_size;
- /* size of the log buffer when the database
- last time wrote to the log */
- byte* last_block;
- /* possible incomplete last recovered log
- block */
- byte* last_block_buf_start;
- /* the nonaligned start address of the
- preceding buffer */
- byte* buf; /* buffer for parsing log records */
- ulint len; /* amount of data in buf */
- dulint parse_start_lsn;
- /* this is the lsn from which we were able to
- start parsing log records and adding them to
- the hash table; ut_dulint_zero if a suitable
- start point not found yet */
- dulint scanned_lsn;
- /* the log data has been scanned up to this
- lsn */
- ulint scanned_checkpoint_no;
- /* the log data has been scanned up to this
- checkpoint number (lowest 4 bytes) */
- ulint recovered_offset;
- /* start offset of non-parsed log records in
- buf */
- dulint recovered_lsn;
- /* the log records have been parsed up to
- this lsn */
- dulint limit_lsn;/* recovery should be made at most up to this
- lsn */
- ibool found_corrupt_log;
- /* this is set to TRUE if we during log
- scan find a corrupt log block, or a corrupt
- log record, or there is a log parsing
- buffer overflow */
- log_group_t* archive_group;
- /* in archive recovery: the log group whose
- archive is read */
- mem_heap_t* heap; /* memory heap of log records and file
- addresses*/
- hash_table_t* addr_hash;/* hash table of file addresses of pages */
- ulint n_addrs;/* number of not processed hashed file
- addresses in the hash table */
-};
-
-extern recv_sys_t* recv_sys;
-extern ibool recv_recovery_on;
-extern ibool recv_no_ibuf_operations;
-extern ibool recv_needed_recovery;
-
-extern ibool recv_lsn_checks_on;
-#ifdef UNIV_HOTBACKUP
-extern ibool recv_is_making_a_backup;
-#endif /* UNIV_HOTBACKUP */
-extern ulint recv_max_parsed_page_no;
-
-/* Size of the parsing buffer; it must accommodate RECV_SCAN_SIZE many
-times! */
-#define RECV_PARSING_BUF_SIZE (2 * 1024 * 1024)
-
-/* Size of block reads when the log groups are scanned forward to do a
-roll-forward */
-#define RECV_SCAN_SIZE (4 * UNIV_PAGE_SIZE)
-
-/* States of recv_addr_struct */
-#define RECV_NOT_PROCESSED 71
-#define RECV_BEING_READ 72
-#define RECV_BEING_PROCESSED 73
-#define RECV_PROCESSED 74
-
-extern ulint recv_n_pool_free_frames;
-
-#ifndef UNIV_NONINL
-#include "log0recv.ic"
-#endif
-
-#endif
diff --git a/storage/innobase/include/log0recv.ic b/storage/innobase/include/log0recv.ic
deleted file mode 100644
index 489641bade2..00000000000
--- a/storage/innobase/include/log0recv.ic
+++ /dev/null
@@ -1,35 +0,0 @@
-/******************************************************
-Recovery
-
-(c) 1997 Innobase Oy
-
-Created 9/20/1997 Heikki Tuuri
-*******************************************************/
-
-#include "sync0sync.h"
-#include "mem0mem.h"
-#include "log0log.h"
-#include "os0file.h"
-
-extern ibool recv_recovery_from_backup_on;
-
-/***********************************************************************
-Returns TRUE if recovery is currently running. */
-UNIV_INLINE
-ibool
-recv_recovery_is_on(void)
-/*=====================*/
-{
- return(recv_recovery_on);
-}
-
-/***********************************************************************
-Returns TRUE if recovery from backup is currently running. */
-UNIV_INLINE
-ibool
-recv_recovery_from_backup_is_on(void)
-/*=================================*/
-{
- return(recv_recovery_from_backup_on);
-}
-
diff --git a/storage/innobase/include/mach0data.h b/storage/innobase/include/mach0data.h
deleted file mode 100644
index 25b619b3f12..00000000000
--- a/storage/innobase/include/mach0data.h
+++ /dev/null
@@ -1,345 +0,0 @@
-/**********************************************************************
-Utilities for converting data from the database file
-to the machine format.
-
-(c) 1995 Innobase Oy
-
-Created 11/28/1995 Heikki Tuuri
-***********************************************************************/
-
-#ifndef mach0data_h
-#define mach0data_h
-
-#include "univ.i"
-#include "ut0byte.h"
-
-/* The data and all fields are always stored in a database file
-in the same format: ascii, big-endian, ... .
-All data in the files MUST be accessed using the functions in this
-module. */
-
-/***********************************************************
-The following function is used to store data in one byte. */
-UNIV_INLINE
-void
-mach_write_to_1(
-/*============*/
- byte* b, /* in: pointer to byte where to store */
- ulint n); /* in: ulint integer to be stored, >= 0, < 256 */
-/************************************************************
-The following function is used to fetch data from one byte. */
-UNIV_INLINE
-ulint
-mach_read_from_1(
-/*=============*/
- /* out: ulint integer, >= 0, < 256 */
- byte* b); /* in: pointer to byte */
-/***********************************************************
-The following function is used to store data in two consecutive
-bytes. We store the most significant byte to the lower address. */
-UNIV_INLINE
-void
-mach_write_to_2(
-/*============*/
- byte* b, /* in: pointer to two bytes where to store */
- ulint n); /* in: ulint integer to be stored, >= 0, < 64k */
-/************************************************************
-The following function is used to fetch data from two consecutive
-bytes. The most significant byte is at the lowest address. */
-UNIV_INLINE
-ulint
-mach_read_from_2(
-/*=============*/
- /* out: ulint integer, >= 0, < 64k */
- byte* b); /* in: pointer to two bytes */
-
-/************************************************************
-The following function is used to convert a 16-bit data item
-to the canonical format, for fast bytewise equality test
-against memory. */
-UNIV_INLINE
-uint16
-mach_encode_2(
-/*==========*/
- /* out: 16-bit integer in canonical format */
- ulint n); /* in: integer in machine-dependent format */
-/************************************************************
-The following function is used to convert a 16-bit data item
-from the canonical format, for fast bytewise equality test
-against memory. */
-UNIV_INLINE
-ulint
-mach_decode_2(
-/*==========*/
- /* out: integer in machine-dependent format */
- uint16 n); /* in: 16-bit integer in canonical format */
-/***********************************************************
-The following function is used to store data in 3 consecutive
-bytes. We store the most significant byte to the lowest address. */
-UNIV_INLINE
-void
-mach_write_to_3(
-/*============*/
- byte* b, /* in: pointer to 3 bytes where to store */
- ulint n); /* in: ulint integer to be stored */
-/************************************************************
-The following function is used to fetch data from 3 consecutive
-bytes. The most significant byte is at the lowest address. */
-UNIV_INLINE
-ulint
-mach_read_from_3(
-/*=============*/
- /* out: ulint integer */
- byte* b); /* in: pointer to 3 bytes */
-/***********************************************************
-The following function is used to store data in four consecutive
-bytes. We store the most significant byte to the lowest address. */
-UNIV_INLINE
-void
-mach_write_to_4(
-/*============*/
- byte* b, /* in: pointer to four bytes where to store */
- ulint n); /* in: ulint integer to be stored */
-/************************************************************
-The following function is used to fetch data from 4 consecutive
-bytes. The most significant byte is at the lowest address. */
-UNIV_INLINE
-ulint
-mach_read_from_4(
-/*=============*/
- /* out: ulint integer */
- byte* b); /* in: pointer to four bytes */
-/*************************************************************
-Writes a ulint in a compressed form (1..5 bytes). */
-UNIV_INLINE
-ulint
-mach_write_compressed(
-/*==================*/
- /* out: stored size in bytes */
- byte* b, /* in: pointer to memory where to store */
- ulint n); /* in: ulint integer to be stored */
-/*************************************************************
-Returns the size of an ulint when written in the compressed form. */
-UNIV_INLINE
-ulint
-mach_get_compressed_size(
-/*=====================*/
- /* out: compressed size in bytes */
- ulint n); /* in: ulint integer to be stored */
-/*************************************************************
-Reads a ulint in a compressed form. */
-UNIV_INLINE
-ulint
-mach_read_compressed(
-/*=================*/
- /* out: read integer */
- byte* b); /* in: pointer to memory from where to read */
-/***********************************************************
-The following function is used to store data in 6 consecutive
-bytes. We store the most significant byte to the lowest address. */
-UNIV_INLINE
-void
-mach_write_to_6(
-/*============*/
- byte* b, /* in: pointer to 6 bytes where to store */
- dulint n); /* in: dulint integer to be stored */
-/************************************************************
-The following function is used to fetch data from 6 consecutive
-bytes. The most significant byte is at the lowest address. */
-UNIV_INLINE
-dulint
-mach_read_from_6(
-/*=============*/
- /* out: dulint integer */
- byte* b); /* in: pointer to 6 bytes */
-/***********************************************************
-The following function is used to store data in 7 consecutive
-bytes. We store the most significant byte to the lowest address. */
-UNIV_INLINE
-void
-mach_write_to_7(
-/*============*/
- byte* b, /* in: pointer to 7 bytes where to store */
- dulint n); /* in: dulint integer to be stored */
-/************************************************************
-The following function is used to fetch data from 7 consecutive
-bytes. The most significant byte is at the lowest address. */
-UNIV_INLINE
-dulint
-mach_read_from_7(
-/*=============*/
- /* out: dulint integer */
- byte* b); /* in: pointer to 7 bytes */
-/***********************************************************
-The following function is used to store data in 8 consecutive
-bytes. We store the most significant byte to the lowest address. */
-UNIV_INLINE
-void
-mach_write_to_8(
-/*============*/
- byte* b, /* in: pointer to 8 bytes where to store */
- dulint n); /* in: dulint integer to be stored */
-/************************************************************
-The following function is used to fetch data from 8 consecutive
-bytes. The most significant byte is at the lowest address. */
-UNIV_INLINE
-dulint
-mach_read_from_8(
-/*=============*/
- /* out: dulint integer */
- byte* b); /* in: pointer to 8 bytes */
-/*************************************************************
-Writes a dulint in a compressed form (5..9 bytes). */
-UNIV_INLINE
-ulint
-mach_dulint_write_compressed(
-/*=========================*/
- /* out: size in bytes */
- byte* b, /* in: pointer to memory where to store */
- dulint n); /* in: dulint integer to be stored */
-/*************************************************************
-Returns the size of a dulint when written in the compressed form. */
-UNIV_INLINE
-ulint
-mach_dulint_get_compressed_size(
-/*============================*/
- /* out: compressed size in bytes */
- dulint n); /* in: dulint integer to be stored */
-/*************************************************************
-Reads a dulint in a compressed form. */
-UNIV_INLINE
-dulint
-mach_dulint_read_compressed(
-/*========================*/
- /* out: read dulint */
- byte* b); /* in: pointer to memory from where to read */
-/*************************************************************
-Writes a dulint in a compressed form (1..11 bytes). */
-UNIV_INLINE
-ulint
-mach_dulint_write_much_compressed(
-/*==============================*/
- /* out: size in bytes */
- byte* b, /* in: pointer to memory where to store */
- dulint n); /* in: dulint integer to be stored */
-/*************************************************************
-Returns the size of a dulint when written in the compressed form. */
-UNIV_INLINE
-ulint
-mach_dulint_get_much_compressed_size(
-/*=================================*/
- /* out: compressed size in bytes */
- dulint n); /* in: dulint integer to be stored */
-/*************************************************************
-Reads a dulint in a compressed form. */
-UNIV_INLINE
-dulint
-mach_dulint_read_much_compressed(
-/*=============================*/
- /* out: read dulint */
- byte* b); /* in: pointer to memory from where to read */
-/*************************************************************
-Reads a ulint in a compressed form if the log record fully contains it. */
-
-byte*
-mach_parse_compressed(
-/*==================*/
- /* out: pointer to end of the stored field, NULL if
- not complete */
- byte* ptr, /* in: pointer to buffer from where to read */
- byte* end_ptr,/* in: pointer to end of the buffer */
- ulint* val); /* out: read value */
-/*************************************************************
-Reads a dulint in a compressed form if the log record fully contains it. */
-
-byte*
-mach_dulint_parse_compressed(
-/*=========================*/
- /* out: pointer to end of the stored field, NULL if
- not complete */
- byte* ptr, /* in: pointer to buffer from where to read */
- byte* end_ptr,/* in: pointer to end of the buffer */
- dulint* val); /* out: read value */
-/*************************************************************
-Reads a double. It is stored in a little-endian format. */
-UNIV_INLINE
-double
-mach_double_read(
-/*=============*/
- /* out: double read */
- byte* b); /* in: pointer to memory from where to read */
-/*************************************************************
-Writes a double. It is stored in a little-endian format. */
-UNIV_INLINE
-void
-mach_double_write(
-/*==============*/
- byte* b, /* in: pointer to memory where to write */
- double d); /* in: double */
-/*************************************************************
-Reads a float. It is stored in a little-endian format. */
-UNIV_INLINE
-float
-mach_float_read(
-/*============*/
- /* out: float read */
- byte* b); /* in: pointer to memory from where to read */
-/*************************************************************
-Writes a float. It is stored in a little-endian format. */
-UNIV_INLINE
-void
-mach_float_write(
-/*=============*/
- byte* b, /* in: pointer to memory where to write */
- float d); /* in: float */
-/*************************************************************
-Reads a ulint stored in the little-endian format. */
-UNIV_INLINE
-ulint
-mach_read_from_n_little_endian(
-/*===========================*/
- /* out: unsigned long int */
- byte* buf, /* in: from where to read */
- ulint buf_size); /* in: from how many bytes to read */
-/*************************************************************
-Writes a ulint in the little-endian format. */
-UNIV_INLINE
-void
-mach_write_to_n_little_endian(
-/*==========================*/
- byte* dest, /* in: where to write */
- ulint dest_size, /* in: into how many bytes to write */
- ulint n); /* in: unsigned long int to write */
-/*************************************************************
-Reads a ulint stored in the little-endian format. */
-UNIV_INLINE
-ulint
-mach_read_from_2_little_endian(
-/*===========================*/
- /* out: unsigned long int */
- byte* buf); /* in: from where to read */
-/*************************************************************
-Writes a ulint in the little-endian format. */
-UNIV_INLINE
-void
-mach_write_to_2_little_endian(
-/*==========================*/
- byte* dest, /* in: where to write */
- ulint n); /* in: unsigned long int to write */
-
-/*************************************************************
-Convert integral type from storage byte order (big endian) to
-host byte order. */
-UNIV_INLINE
-ullint
-mach_read_int_type(
-/*===============*/
- /* out: integer value */
- const byte* src, /* in: where to read from */
- ulint len, /* in: length of src */
- ibool unsigned_type); /* in: signed or unsigned flag */
-#ifndef UNIV_NONINL
-#include "mach0data.ic"
-#endif
-
-#endif
diff --git a/storage/innobase/include/mem0pool.h b/storage/innobase/include/mem0pool.h
deleted file mode 100644
index bf659ca9a72..00000000000
--- a/storage/innobase/include/mem0pool.h
+++ /dev/null
@@ -1,108 +0,0 @@
-/******************************************************
-The lowest-level memory management
-
-(c) 1994, 1995 Innobase Oy
-
-Created 6/9/1994 Heikki Tuuri
-*******************************************************/
-
-#ifndef mem0pool_h
-#define mem0pool_h
-
-#include "univ.i"
-#include "os0file.h"
-#include "ut0lst.h"
-
-typedef struct mem_area_struct mem_area_t;
-typedef struct mem_pool_struct mem_pool_t;
-
-/* The common memory pool */
-extern mem_pool_t* mem_comm_pool;
-
-/* Memory area header */
-
-struct mem_area_struct{
- ulint size_and_free; /* memory area size is obtained by
- anding with ~MEM_AREA_FREE; area in
- a free list if ANDing with
- MEM_AREA_FREE results in nonzero */
- UT_LIST_NODE_T(mem_area_t)
- free_list; /* free list node */
-};
-
-/* Each memory area takes this many extra bytes for control information */
-#define MEM_AREA_EXTRA_SIZE (ut_calc_align(sizeof(struct mem_area_struct),\
- UNIV_MEM_ALIGNMENT))
-
-/************************************************************************
-Creates a memory pool. */
-
-mem_pool_t*
-mem_pool_create(
-/*============*/
- /* out: memory pool */
- ulint size); /* in: pool size in bytes */
-/************************************************************************
-Allocates memory from a pool. NOTE: This low-level function should only be
-used in mem0mem.*! */
-
-void*
-mem_area_alloc(
-/*===========*/
- /* out, own: allocated memory buffer */
- ulint size, /* in: allocated size in bytes; for optimum
- space usage, the size should be a power of 2
- minus MEM_AREA_EXTRA_SIZE */
- mem_pool_t* pool); /* in: memory pool */
-/************************************************************************
-Frees memory to a pool. */
-
-void
-mem_area_free(
-/*==========*/
- void* ptr, /* in, own: pointer to allocated memory
- buffer */
- mem_pool_t* pool); /* in: memory pool */
-/************************************************************************
-Returns the amount of reserved memory. */
-
-ulint
-mem_pool_get_reserved(
-/*==================*/
- /* out: reserved mmeory in bytes */
- mem_pool_t* pool); /* in: memory pool */
-/************************************************************************
-Reserves the mem pool mutex. */
-
-void
-mem_pool_mutex_enter(void);
-/*======================*/
-/************************************************************************
-Releases the mem pool mutex. */
-
-void
-mem_pool_mutex_exit(void);
-/*=====================*/
-/************************************************************************
-Validates a memory pool. */
-
-ibool
-mem_pool_validate(
-/*==============*/
- /* out: TRUE if ok */
- mem_pool_t* pool); /* in: memory pool */
-/************************************************************************
-Prints info of a memory pool. */
-
-void
-mem_pool_print_info(
-/*================*/
- FILE* outfile,/* in: output file to write to */
- mem_pool_t* pool); /* in: memory pool */
-
-
-#ifndef UNIV_NONINL
-#include "mem0pool.ic"
-#endif
-
-#endif
diff --git a/storage/innobase/include/mem0pool.ic b/storage/innobase/include/mem0pool.ic
deleted file mode 100644
index 4e8c08733ed..00000000000
--- a/storage/innobase/include/mem0pool.ic
+++ /dev/null
@@ -1,7 +0,0 @@
-/************************************************************************
-The lowest-level memory management
-
-(c) 1994, 1995 Innobase Oy
-
-Created 6/8/1994 Heikki Tuuri
-*************************************************************************/
diff --git a/storage/innobase/include/mtr0log.h b/storage/innobase/include/mtr0log.h
deleted file mode 100644
index 6a3920aa8a1..00000000000
--- a/storage/innobase/include/mtr0log.h
+++ /dev/null
@@ -1,217 +0,0 @@
-/******************************************************
-Mini-transaction logging routines
-
-(c) 1995 Innobase Oy
-
-Created 12/7/1995 Heikki Tuuri
-*******************************************************/
-
-#ifndef mtr0log_h
-#define mtr0log_h
-
-#include "univ.i"
-#include "mtr0mtr.h"
-#include "dict0types.h"
-
-/************************************************************
-Writes 1 - 4 bytes to a file page buffered in the buffer pool.
-Writes the corresponding log record to the mini-transaction log. */
-
-void
-mlog_write_ulint(
-/*=============*/
- byte* ptr, /* in: pointer where to write */
- ulint val, /* in: value to write */
- byte type, /* in: MLOG_1BYTE, MLOG_2BYTES, MLOG_4BYTES */
- mtr_t* mtr); /* in: mini-transaction handle */
-/************************************************************
-Writes 8 bytes to a file page buffered in the buffer pool.
-Writes the corresponding log record to the mini-transaction log. */
-
-void
-mlog_write_dulint(
-/*==============*/
- byte* ptr, /* in: pointer where to write */
- dulint val, /* in: value to write */
- mtr_t* mtr); /* in: mini-transaction handle */
-/************************************************************
-Writes a string to a file page buffered in the buffer pool. Writes the
-corresponding log record to the mini-transaction log. */
-
-void
-mlog_write_string(
-/*==============*/
- byte* ptr, /* in: pointer where to write */
- const byte* str, /* in: string to write */
- ulint len, /* in: string length */
- mtr_t* mtr); /* in: mini-transaction handle */
-/************************************************************
-Writes initial part of a log record consisting of one-byte item
-type and four-byte space and page numbers. */
-
-void
-mlog_write_initial_log_record(
-/*==========================*/
- byte* ptr, /* in: pointer to (inside) a buffer frame
- holding the file page where modification
- is made */
- byte type, /* in: log item type: MLOG_1BYTE, ... */
- mtr_t* mtr); /* in: mini-transaction handle */
-/************************************************************
-Writes a log record about an .ibd file create/delete/rename. */
-UNIV_INLINE
-byte*
-mlog_write_initial_log_record_for_file_op(
-/*======================================*/
- /* out: new value of log_ptr */
- ulint type, /* in: MLOG_FILE_CREATE, MLOG_FILE_DELETE, or
- MLOG_FILE_RENAME */
- ulint space_id,/* in: space id, if applicable */
- ulint page_no,/* in: page number (not relevant currently) */
- byte* log_ptr,/* in: pointer to mtr log which has been opened */
- mtr_t* mtr); /* in: mtr */
-/************************************************************
-Catenates 1 - 4 bytes to the mtr log. */
-UNIV_INLINE
-void
-mlog_catenate_ulint(
-/*================*/
- mtr_t* mtr, /* in: mtr */
- ulint val, /* in: value to write */
- ulint type); /* in: MLOG_1BYTE, MLOG_2BYTES, MLOG_4BYTES */
-/************************************************************
-Catenates n bytes to the mtr log. */
-
-void
-mlog_catenate_string(
-/*=================*/
- mtr_t* mtr, /* in: mtr */
- const byte* str, /* in: string to write */
- ulint len); /* in: string length */
-/************************************************************
-Catenates a compressed ulint to mlog. */
-UNIV_INLINE
-void
-mlog_catenate_ulint_compressed(
-/*===========================*/
- mtr_t* mtr, /* in: mtr */
- ulint val); /* in: value to write */
-/************************************************************
-Catenates a compressed dulint to mlog. */
-UNIV_INLINE
-void
-mlog_catenate_dulint_compressed(
-/*============================*/
- mtr_t* mtr, /* in: mtr */
- dulint val); /* in: value to write */
-/************************************************************
-Opens a buffer to mlog. It must be closed with mlog_close. */
-UNIV_INLINE
-byte*
-mlog_open(
-/*======*/
- /* out: buffer, NULL if log mode MTR_LOG_NONE */
- mtr_t* mtr, /* in: mtr */
- ulint size); /* in: buffer size in bytes; MUST be
- smaller than DYN_ARRAY_DATA_SIZE! */
-/************************************************************
-Closes a buffer opened to mlog. */
-UNIV_INLINE
-void
-mlog_close(
-/*=======*/
- mtr_t* mtr, /* in: mtr */
- byte* ptr); /* in: buffer space from ptr up was not used */
-/************************************************************
-Writes the initial part of a log record (3..11 bytes).
-If the implementation of this function is changed, all
-size parameters to mlog_open() should be adjusted accordingly! */
-UNIV_INLINE
-byte*
-mlog_write_initial_log_record_fast(
-/*===============================*/
- /* out: new value of log_ptr */
- byte* ptr, /* in: pointer to (inside) a buffer frame holding the
- file page where modification is made */
- byte type, /* in: log item type: MLOG_1BYTE, ... */
- byte* log_ptr,/* in: pointer to mtr log which has been opened */
- mtr_t* mtr); /* in: mtr */
-/************************************************************
-Parses an initial log record written by mlog_write_initial_log_record. */
-
-byte*
-mlog_parse_initial_log_record(
-/*==========================*/
- /* out: parsed record end, NULL if not a complete
- record */
- byte* ptr, /* in: buffer */
- byte* end_ptr,/* in: buffer end */
- byte* type, /* out: log record type: MLOG_1BYTE, ... */
- ulint* space, /* out: space id */
- ulint* page_no);/* out: page number */
-/************************************************************
-Parses a log record written by mlog_write_ulint or mlog_write_dulint. */
-
-byte*
-mlog_parse_nbytes(
-/*==============*/
- /* out: parsed record end, NULL if not a complete
- record */
- ulint type, /* in: log record type: MLOG_1BYTE, ... */
- byte* ptr, /* in: buffer */
- byte* end_ptr,/* in: buffer end */
- byte* page); /* in: page where to apply the log record, or NULL */
-/************************************************************
-Parses a log record written by mlog_write_string. */
-
-byte*
-mlog_parse_string(
-/*==============*/
- /* out: parsed record end, NULL if not a complete
- record */
- byte* ptr, /* in: buffer */
- byte* end_ptr,/* in: buffer end */
- byte* page); /* in: page where to apply the log record, or NULL */
-
-
-/************************************************************
-Opens a buffer for mlog, writes the initial log record and,
-if needed, the field lengths of an index. Reserves space
-for further log entries. The log entry must be closed with
-mtr_close(). */
-
-byte*
-mlog_open_and_write_index(
-/*======================*/
- /* out: buffer, NULL if log mode
- MTR_LOG_NONE */
- mtr_t* mtr, /* in: mtr */
- byte* rec, /* in: index record or page */
- dict_index_t* index, /* in: record descriptor */
- byte type, /* in: log item type */
- ulint size); /* in: requested buffer size in bytes
- (if 0, calls mlog_close() and returns NULL) */
-
-/************************************************************
-Parses a log record written by mlog_open_and_write_index. */
-
-byte*
-mlog_parse_index(
-/*=============*/
- /* out: parsed record end,
- NULL if not a complete record */
- byte* ptr, /* in: buffer */
- byte* end_ptr,/* in: buffer end */
- /* out: new value of log_ptr */
- ibool comp, /* in: TRUE=compact record format */
- dict_index_t** index); /* out, own: dummy index */
-
-/* Insert, update, and maybe other functions may use this value to define an
-extra mlog buffer size for variable size data */
-#define MLOG_BUF_MARGIN 256
-
-#ifndef UNIV_NONINL
-#include "mtr0log.ic"
-#endif
-
-#endif
diff --git a/storage/innobase/include/mtr0log.ic b/storage/innobase/include/mtr0log.ic
deleted file mode 100644
index 5b1d1ed34d9..00000000000
--- a/storage/innobase/include/mtr0log.ic
+++ /dev/null
@@ -1,227 +0,0 @@
-/******************************************************
-Mini-transaction logging routines
-
-(c) 1995 Innobase Oy
-
-Created 12/7/1995 Heikki Tuuri
-*******************************************************/
-
-#include "mach0data.h"
-#include "ut0lst.h"
-#include "buf0buf.h"
-
-/************************************************************
-Opens a buffer to mlog. It must be closed with mlog_close. */
-UNIV_INLINE
-byte*
-mlog_open(
-/*======*/
- /* out: buffer, NULL if log mode MTR_LOG_NONE */
- mtr_t* mtr, /* in: mtr */
- ulint size) /* in: buffer size in bytes; MUST be
- smaller than DYN_ARRAY_DATA_SIZE! */
-{
- dyn_array_t* mlog;
-
- mtr->modifications = TRUE;
-
- if (mtr_get_log_mode(mtr) == MTR_LOG_NONE) {
-
- return(NULL);
- }
-
- mlog = &(mtr->log);
-
- return(dyn_array_open(mlog, size));
-}
-
-/************************************************************
-Closes a buffer opened to mlog. */
-UNIV_INLINE
-void
-mlog_close(
-/*=======*/
- mtr_t* mtr, /* in: mtr */
- byte* ptr) /* in: buffer space from ptr up was not used */
-{
- dyn_array_t* mlog;
-
- ut_ad(mtr_get_log_mode(mtr) != MTR_LOG_NONE);
-
- mlog = &(mtr->log);
-
- dyn_array_close(mlog, ptr);
-}
-
-/************************************************************
-Catenates 1 - 4 bytes to the mtr log. The value is not compressed. */
-UNIV_INLINE
-void
-mlog_catenate_ulint(
-/*================*/
- mtr_t* mtr, /* in: mtr */
- ulint val, /* in: value to write */
- ulint type) /* in: MLOG_1BYTE, MLOG_2BYTES, MLOG_4BYTES */
-{
- dyn_array_t* mlog;
- byte* ptr;
-
- if (mtr_get_log_mode(mtr) == MTR_LOG_NONE) {
-
- return;
- }
-
- mlog = &(mtr->log);
-
-#if MLOG_1BYTE != 1
-# error "MLOG_1BYTE != 1"
-#endif
-#if MLOG_2BYTES != 2
-# error "MLOG_2BYTES != 2"
-#endif
-#if MLOG_4BYTES != 4
-# error "MLOG_4BYTES != 4"
-#endif
-#if MLOG_8BYTES != 8
-# error "MLOG_8BYTES != 8"
-#endif
- ptr = dyn_array_push(mlog, type);
-
- if (type == MLOG_4BYTES) {
- mach_write_to_4(ptr, val);
- } else if (type == MLOG_2BYTES) {
- mach_write_to_2(ptr, val);
- } else {
- ut_ad(type == MLOG_1BYTE);
- mach_write_to_1(ptr, val);
- }
-}
-
-/************************************************************
-Catenates a compressed ulint to mlog. */
-UNIV_INLINE
-void
-mlog_catenate_ulint_compressed(
-/*===========================*/
- mtr_t* mtr, /* in: mtr */
- ulint val) /* in: value to write */
-{
- byte* log_ptr;
-
- log_ptr = mlog_open(mtr, 10);
-
- /* If no logging is requested, we may return now */
- if (log_ptr == NULL) {
-
- return;
- }
-
- log_ptr += mach_write_compressed(log_ptr, val);
-
- mlog_close(mtr, log_ptr);
-}
-
-/************************************************************
-Catenates a compressed dulint to mlog. */
-UNIV_INLINE
-void
-mlog_catenate_dulint_compressed(
-/*============================*/
- mtr_t* mtr, /* in: mtr */
- dulint val) /* in: value to write */
-{
- byte* log_ptr;
-
- log_ptr = mlog_open(mtr, 15);
-
- /* If no logging is requested, we may return now */
- if (log_ptr == NULL) {
-
- return;
- }
-
- log_ptr += mach_dulint_write_compressed(log_ptr, val);
-
- mlog_close(mtr, log_ptr);
-}
-
-/************************************************************
-Writes the initial part of a log record (3..11 bytes).
-If the implementation of this function is changed, all
-size parameters to mlog_open() should be adjusted accordingly! */
-UNIV_INLINE
-byte*
-mlog_write_initial_log_record_fast(
-/*===============================*/
- /* out: new value of log_ptr */
- byte* ptr, /* in: pointer to (inside) a buffer frame holding the
- file page where modification is made */
- byte type, /* in: log item type: MLOG_1BYTE, ... */
- byte* log_ptr,/* in: pointer to mtr log which has been opened */
- mtr_t* mtr) /* in: mtr */
-{
- buf_block_t* block;
- ulint space;
- ulint offset;
-
- ut_ad(mtr_memo_contains(mtr, buf_block_align(ptr),
- MTR_MEMO_PAGE_X_FIX));
- ut_ad(type <= MLOG_BIGGEST_TYPE);
- ut_ad(ptr && log_ptr);
-
- block = buf_block_align(ptr);
-
- space = buf_block_get_space(block);
- offset = buf_block_get_page_no(block);
-
- mach_write_to_1(log_ptr, type);
- log_ptr++;
- log_ptr += mach_write_compressed(log_ptr, space);
- log_ptr += mach_write_compressed(log_ptr, offset);
-
- mtr->n_log_recs++;
-
-#ifdef UNIV_LOG_DEBUG
- /* fprintf(stderr,
- "Adding to mtr log record type %lu space %lu page no %lu\n",
- type, space, offset); */
-#endif
-
-#ifdef UNIV_DEBUG
- /* We now assume that all x-latched pages have been modified! */
-
- if (!mtr_memo_contains(mtr, block, MTR_MEMO_MODIFY)) {
-
- mtr_memo_push(mtr, block, MTR_MEMO_MODIFY);
- }
-#endif
- return(log_ptr);
-}
-
-/************************************************************
-Writes a log record about an .ibd file create/delete/rename. */
-UNIV_INLINE
-byte*
-mlog_write_initial_log_record_for_file_op(
-/*======================================*/
- /* out: new value of log_ptr */
- ulint type, /* in: MLOG_FILE_CREATE, MLOG_FILE_DELETE, or
- MLOG_FILE_RENAME */
- ulint space_id,/* in: space id, if applicable */
- ulint page_no,/* in: page number (not relevant currently) */
- byte* log_ptr,/* in: pointer to mtr log which has been opened */
- mtr_t* mtr) /* in: mtr */
-{
- ut_ad(log_ptr);
-
- mach_write_to_1(log_ptr, type);
- log_ptr++;
-
- /* We write dummy space id and page number */
- log_ptr += mach_write_compressed(log_ptr, space_id);
- log_ptr += mach_write_compressed(log_ptr, page_no);
-
- mtr->n_log_recs++;
-
- return(log_ptr);
-}
diff --git a/storage/innobase/include/mtr0mtr.h b/storage/innobase/include/mtr0mtr.h
deleted file mode 100644
index 2a160d27e0c..00000000000
--- a/storage/innobase/include/mtr0mtr.h
+++ /dev/null
@@ -1,347 +0,0 @@
-/******************************************************
-Mini-transaction buffer
-
-(c) 1995 Innobase Oy
-
-Created 11/26/1995 Heikki Tuuri
-*******************************************************/
-
-#ifndef mtr0mtr_h
-#define mtr0mtr_h
-
-#include "univ.i"
-#include "mem0mem.h"
-#include "dyn0dyn.h"
-#include "buf0types.h"
-#include "sync0rw.h"
-#include "ut0byte.h"
-#include "mtr0types.h"
-#include "page0types.h"
-
-/* Logging modes for a mini-transaction */
-#define MTR_LOG_ALL 21 /* default mode: log all operations
- modifying disk-based data */
-#define MTR_LOG_NONE 22 /* log no operations */
-/*#define MTR_LOG_SPACE 23 */ /* log only operations modifying
- file space page allocation data
- (operations in fsp0fsp.* ) */
-#define MTR_LOG_SHORT_INSERTS 24 /* inserts are logged in a shorter
- form */
-
-/* Types for the mlock objects to store in the mtr memo; NOTE that the
-first 3 values must be RW_S_LATCH, RW_X_LATCH, RW_NO_LATCH */
-#define MTR_MEMO_PAGE_S_FIX RW_S_LATCH
-#define MTR_MEMO_PAGE_X_FIX RW_X_LATCH
-#define MTR_MEMO_BUF_FIX RW_NO_LATCH
-#define MTR_MEMO_MODIFY 54
-#define MTR_MEMO_S_LOCK 55
-#define MTR_MEMO_X_LOCK 56
-
-/* Log item types: we have made them to be of the type 'byte'
-for the compiler to warn if val and type parameters are switched
-in a call to mlog_write_ulint. NOTE! For 1 - 8 bytes, the
-flag value must give the length also! */
-#define MLOG_SINGLE_REC_FLAG 128 /* if the mtr contains only
- one log record for one page,
- i.e., write_initial_log_record
- has been called only once,
- this flag is ORed to the type
- of that first log record */
-#define MLOG_1BYTE (1) /* one byte is written */
-#define MLOG_2BYTES (2) /* 2 bytes ... */
-#define MLOG_4BYTES (4) /* 4 bytes ... */
-#define MLOG_8BYTES (8) /* 8 bytes ... */
-#define MLOG_REC_INSERT ((byte)9) /* record insert */
-#define MLOG_REC_CLUST_DELETE_MARK ((byte)10) /* mark clustered index record
- deleted */
-#define MLOG_REC_SEC_DELETE_MARK ((byte)11) /* mark secondary index record
- deleted */
-#define MLOG_REC_UPDATE_IN_PLACE ((byte)13) /* update of a record,
- preserves record field sizes */
-#define MLOG_REC_DELETE ((byte)14) /* delete a record from a
- page */
-#define MLOG_LIST_END_DELETE ((byte)15) /* delete record list end on
- index page */
-#define MLOG_LIST_START_DELETE ((byte)16) /* delete record list start on
- index page */
-#define MLOG_LIST_END_COPY_CREATED ((byte)17) /* copy record list end to a
- new created index page */
-#define MLOG_PAGE_REORGANIZE ((byte)18) /* reorganize an index page */
-#define MLOG_PAGE_CREATE ((byte)19) /* create an index page */
-#define MLOG_UNDO_INSERT ((byte)20) /* insert entry in an undo
- log */
-#define MLOG_UNDO_ERASE_END ((byte)21) /* erase an undo log
- page end */
-#define MLOG_UNDO_INIT ((byte)22) /* initialize a page in an
- undo log */
-#define MLOG_UNDO_HDR_DISCARD ((byte)23) /* discard an update undo log
- header */
-#define MLOG_UNDO_HDR_REUSE ((byte)24) /* reuse an insert undo log
- header */
-#define MLOG_UNDO_HDR_CREATE ((byte)25) /* create an undo log header */
-#define MLOG_REC_MIN_MARK ((byte)26) /* mark an index record as the
- predefined minimum record */
-#define MLOG_IBUF_BITMAP_INIT ((byte)27) /* initialize an ibuf bitmap
- page */
-/*#define MLOG_FULL_PAGE ((byte)28) full contents of a page */
-#define MLOG_INIT_FILE_PAGE ((byte)29) /* this means that a file page
- is taken into use and the prior
- contents of the page should be
- ignored: in recovery we must
- not trust the lsn values stored
- to the file page */
-#define MLOG_WRITE_STRING ((byte)30) /* write a string to a page */
-#define MLOG_MULTI_REC_END ((byte)31) /* if a single mtr writes
- log records for several pages,
- this log record ends the
- sequence of these records */
-#define MLOG_DUMMY_RECORD ((byte)32) /* dummy log record used to
- pad a log block full */
-#define MLOG_FILE_CREATE ((byte)33) /* log record about an .ibd
- file creation */
-#define MLOG_FILE_RENAME ((byte)34) /* log record about an .ibd
- file rename */
-#define MLOG_FILE_DELETE ((byte)35) /* log record about an .ibd
- file deletion */
-#define MLOG_COMP_REC_MIN_MARK ((byte)36) /* mark a compact index record
- as the predefined minimum
- record */
-#define MLOG_COMP_PAGE_CREATE ((byte)37) /* create a compact
- index page */
-#define MLOG_COMP_REC_INSERT ((byte)38) /* compact record insert */
-#define MLOG_COMP_REC_CLUST_DELETE_MARK ((byte)39)
- /* mark compact clustered index
- record deleted */
-#define MLOG_COMP_REC_SEC_DELETE_MARK ((byte)40)/* mark compact secondary index
- record deleted; this log
- record type is redundant, as
- MLOG_REC_SEC_DELETE_MARK is
- independent of the record
- format. */
-#define MLOG_COMP_REC_UPDATE_IN_PLACE ((byte)41)/* update of a compact record,
- preserves record field sizes */
-#define MLOG_COMP_REC_DELETE ((byte)42) /* delete a compact record
- from a page */
-#define MLOG_COMP_LIST_END_DELETE ((byte)43) /* delete compact record list
- end on index page */
-#define MLOG_COMP_LIST_START_DELETE ((byte)44) /* delete compact record list
- start on index page */
-#define MLOG_COMP_LIST_END_COPY_CREATED ((byte)45)
- /* copy compact record list end
- to a new created index page */
-#define MLOG_COMP_PAGE_REORGANIZE ((byte)46) /* reorganize an index page */
-
-#define MLOG_BIGGEST_TYPE ((byte)46) /* biggest value (used in
- asserts) */
-
-/*******************************************************************
-Starts a mini-transaction and creates a mini-transaction handle
-and buffer in the memory buffer given by the caller. */
-UNIV_INLINE
-mtr_t*
-mtr_start(
-/*======*/
- /* out: mtr buffer which also acts as
- the mtr handle */
- mtr_t* mtr); /* in: memory buffer for the mtr buffer */
-/*******************************************************************
-Starts a mini-transaction and creates a mini-transaction handle
-and buffer in the memory buffer given by the caller. */
-
-mtr_t*
-mtr_start_noninline(
-/*================*/
- /* out: mtr buffer which also acts as
- the mtr handle */
- mtr_t* mtr); /* in: memory buffer for the mtr buffer */
-/*******************************************************************
-Commits a mini-transaction. */
-
-void
-mtr_commit(
-/*=======*/
- mtr_t* mtr); /* in: mini-transaction */
-/**************************************************************
-Sets and returns a savepoint in mtr. */
-UNIV_INLINE
-ulint
-mtr_set_savepoint(
-/*==============*/
- /* out: savepoint */
- mtr_t* mtr); /* in: mtr */
-/**************************************************************
-Releases the latches stored in an mtr memo down to a savepoint.
-NOTE! The mtr must not have made changes to buffer pages after the
-savepoint, as these can be handled only by mtr_commit. */
-
-void
-mtr_rollback_to_savepoint(
-/*======================*/
- mtr_t* mtr, /* in: mtr */
- ulint savepoint); /* in: savepoint */
-/**************************************************************
-Releases the (index tree) s-latch stored in an mtr memo after a
-savepoint. */
-UNIV_INLINE
-void
-mtr_release_s_latch_at_savepoint(
-/*=============================*/
- mtr_t* mtr, /* in: mtr */
- ulint savepoint, /* in: savepoint */
- rw_lock_t* lock); /* in: latch to release */
-/*******************************************************************
-Gets the logging mode of a mini-transaction. */
-UNIV_INLINE
-ulint
-mtr_get_log_mode(
-/*=============*/
- /* out: logging mode: MTR_LOG_NONE, ... */
- mtr_t* mtr); /* in: mtr */
-/*******************************************************************
-Changes the logging mode of a mini-transaction. */
-UNIV_INLINE
-ulint
-mtr_set_log_mode(
-/*=============*/
- /* out: old mode */
- mtr_t* mtr, /* in: mtr */
- ulint mode); /* in: logging mode: MTR_LOG_NONE, ... */
-/************************************************************
-Reads 1 - 4 bytes from a file page buffered in the buffer pool. */
-
-ulint
-mtr_read_ulint(
-/*===========*/
- /* out: value read */
- byte* ptr, /* in: pointer from where to read */
- ulint type, /* in: MLOG_1BYTE, MLOG_2BYTES, MLOG_4BYTES */
- mtr_t* mtr); /* in: mini-transaction handle */
-/************************************************************
-Reads 8 bytes from a file page buffered in the buffer pool. */
-
-dulint
-mtr_read_dulint(
-/*============*/
- /* out: value read */
- byte* ptr, /* in: pointer from where to read */
- mtr_t* mtr); /* in: mini-transaction handle */
-/*************************************************************************
-This macro locks an rw-lock in s-mode. */
-#define mtr_s_lock(B, MTR) mtr_s_lock_func((B), __FILE__, __LINE__,\
- (MTR))
-/*************************************************************************
-This macro locks an rw-lock in x-mode. */
-#define mtr_x_lock(B, MTR) mtr_x_lock_func((B), __FILE__, __LINE__,\
- (MTR))
-/*************************************************************************
-NOTE! Use the macro above!
-Locks a lock in s-mode. */
-UNIV_INLINE
-void
-mtr_s_lock_func(
-/*============*/
- rw_lock_t* lock, /* in: rw-lock */
- const char* file, /* in: file name */
- ulint line, /* in: line number */
- mtr_t* mtr); /* in: mtr */
-/*************************************************************************
-NOTE! Use the macro above!
-Locks a lock in x-mode. */
-UNIV_INLINE
-void
-mtr_x_lock_func(
-/*============*/
- rw_lock_t* lock, /* in: rw-lock */
- const char* file, /* in: file name */
- ulint line, /* in: line number */
- mtr_t* mtr); /* in: mtr */
-
-/*******************************************************
-Releases an object in the memo stack. */
-
-void
-mtr_memo_release(
-/*=============*/
- mtr_t* mtr, /* in: mtr */
- void* object, /* in: object */
- ulint type); /* in: object type: MTR_MEMO_S_LOCK, ... */
-#ifdef UNIV_DEBUG
-/**************************************************************
-Checks if memo contains the given item. */
-UNIV_INLINE
-ibool
-mtr_memo_contains(
-/*==============*/
- /* out: TRUE if contains */
- mtr_t* mtr, /* in: mtr */
- void* object, /* in: object to search */
- ulint type); /* in: type of object */
-/*************************************************************
-Prints info of an mtr handle. */
-
-void
-mtr_print(
-/*======*/
- mtr_t* mtr); /* in: mtr */
-#endif /* UNIV_DEBUG */
-/*######################################################################*/
-
-#define MTR_BUF_MEMO_SIZE 200 /* number of slots in memo */
-
-/*******************************************************************
-Returns the log object of a mini-transaction buffer. */
-UNIV_INLINE
-dyn_array_t*
-mtr_get_log(
-/*========*/
- /* out: log */
- mtr_t* mtr); /* in: mini-transaction */
-/*******************************************************
-Pushes an object to an mtr memo stack. */
-UNIV_INLINE
-void
-mtr_memo_push(
-/*==========*/
- mtr_t* mtr, /* in: mtr */
- void* object, /* in: object */
- ulint type); /* in: object type: MTR_MEMO_S_LOCK, ... */
-
-
-/* Type definition of a mini-transaction memo stack slot. */
-typedef struct mtr_memo_slot_struct mtr_memo_slot_t;
-struct mtr_memo_slot_struct{
- ulint type; /* type of the stored object (MTR_MEMO_S_LOCK, ...) */
- void* object; /* pointer to the object */
-};
-
-/* Mini-transaction handle and buffer */
-struct mtr_struct{
- ulint state; /* MTR_ACTIVE, MTR_COMMITTING, MTR_COMMITTED */
- dyn_array_t memo; /* memo stack for locks etc. */
- dyn_array_t log; /* mini-transaction log */
- ibool modifications;
- /* TRUE if the mtr made modifications to
- buffer pool pages */
- ulint n_log_recs;
- /* count of how many page initial log records
- have been written to the mtr log */
- ulint log_mode; /* specifies which operations should be
- logged; default value MTR_LOG_ALL */
- dulint start_lsn;/* start lsn of the possible log entry for
- this mtr */
- dulint end_lsn;/* end lsn of the possible log entry for
- this mtr */
- ulint magic_n;
-};
-
-#define MTR_MAGIC_N 54551
-
-#define MTR_ACTIVE 12231
-#define MTR_COMMITTING 56456
-#define MTR_COMMITTED 34676
-
-#ifndef UNIV_NONINL
-#include "mtr0mtr.ic"
-#endif
-
-#endif
diff --git a/storage/innobase/include/mtr0types.h b/storage/innobase/include/mtr0types.h
deleted file mode 100644
index e3b6ec9a84f..00000000000
--- a/storage/innobase/include/mtr0types.h
+++ /dev/null
@@ -1,14 +0,0 @@
-/******************************************************
-Mini-transaction buffer global types
-
-(c) 1995 Innobase Oy
-
-Created 11/26/1995 Heikki Tuuri
-*******************************************************/
-
-#ifndef mtr0types_h
-#define mtr0types_h
-
-typedef struct mtr_struct mtr_t;
-
-#endif
diff --git a/storage/innobase/include/os0proc.h b/storage/innobase/include/os0proc.h
deleted file mode 100644
index f54e08de7ee..00000000000
--- a/storage/innobase/include/os0proc.h
+++ /dev/null
@@ -1,148 +0,0 @@
-/******************************************************
-The interface to the operating system
-process control primitives
-
-(c) 1995 Innobase Oy
-
-Created 9/30/1995 Heikki Tuuri
-*******************************************************/
-
-#ifndef os0proc_h
-#define os0proc_h
-
-#include "univ.i"
-
-#ifdef UNIV_LINUX
-#include
-#include
-#endif
-
-typedef void* os_process_t;
-typedef unsigned long int os_process_id_t;
-
-/* The cell type in os_awe_allocate_mem page info */
-#if defined(__WIN2000__) && defined(ULONG_PTR)
-typedef ULONG_PTR os_awe_t;
-#else
-typedef ulint os_awe_t;
-#endif
-
-/* Physical page size when Windows AWE is used. This is the normal
-page size of an Intel x86 processor. We cannot use AWE with 2 MB or 4 MB
-pages. */
-#define OS_AWE_X86_PAGE_SIZE 4096
-
-extern ibool os_use_large_pages;
-/* Large page size. This may be a boot-time option on some platforms */
-extern ulint os_large_page_size;
-
-/********************************************************************
-Windows AWE support. Tries to enable the "lock pages in memory" privilege for
-the current process so that the current process can allocate memory-locked
-virtual address space to act as the window where AWE maps physical memory. */
-
-ibool
-os_awe_enable_lock_pages_in_mem(void);
-/*=================================*/
- /* out: TRUE if success, FALSE if error;
- prints error info to stderr if no success */
-/********************************************************************
-Allocates physical RAM memory up to 64 GB in an Intel 32-bit x86
-processor. */
-
-ibool
-os_awe_allocate_physical_mem(
-/*=========================*/
- /* out: TRUE if success */
- os_awe_t** page_info, /* out, own: array of opaque data containing
- the info for allocated physical memory pages;
- each allocated 4 kB physical memory page has
- one slot of type os_awe_t in the array */
- ulint n_megabytes); /* in: number of megabytes to allocate */
-/********************************************************************
-Allocates a window in the virtual address space where we can map then
-pages of physical memory. */
-
-byte*
-os_awe_allocate_virtual_mem_window(
-/*===============================*/
- /* out, own: allocated memory, or NULL if did not
- succeed */
- ulint size); /* in: virtual memory allocation size in bytes, must
- be < 2 GB */
-/********************************************************************
-With this function you can map parts of physical memory allocated with
-the ..._allocate_physical_mem to the virtual address space allocated with
-the previous function. Intel implements this so that the process page
-tables are updated accordingly. A test on a 1.5 GHz AMD processor and XP
-showed that this takes < 1 microsecond, much better than the estimated 80 us
-for copying a 16 kB page memory to memory. But, the operation will at least
-partially invalidate the translation lookaside buffer (TLB) of all
-processors. Under a real-world load the performance hit may be bigger. */
-
-ibool
-os_awe_map_physical_mem_to_window(
-/*==============================*/
- /* out: TRUE if success; the function
- calls exit(1) in case of an error */
- byte* ptr, /* in: a page-aligned pointer to
- somewhere in the virtual address
- space window; we map the physical mem
- pages here */
- ulint n_mem_pages, /* in: number of 4 kB mem pages to
- map */
- os_awe_t* page_info); /* in: array of page infos for those
- pages; each page has one slot in the
- array */
-/********************************************************************
-Converts the current process id to a number. It is not guaranteed that the
-number is unique. In Linux returns the 'process number' of the current
-thread. That number is the same as one sees in 'top', for example. In Linux
-the thread id is not the same as one sees in 'top'. */
-
-ulint
-os_proc_get_number(void);
-/*====================*/
-/********************************************************************
-Allocates non-cacheable memory. */
-
-void*
-os_mem_alloc_nocache(
-/*=================*/
- /* out: allocated memory */
- ulint n); /* in: number of bytes */
-/********************************************************************
-Allocates large pages memory. */
-
-void*
-os_mem_alloc_large(
-/*===============*/
- /* out: allocated memory */
- ulint n, /* in: number of bytes */
- ibool set_to_zero, /* in: TRUE if allocated memory
- should be set to zero if
- UNIV_SET_MEM_TO_ZERO is defined */
- ibool assert_on_error);/* in: if TRUE, we crash mysqld if
- the memory cannot be allocated */
-/********************************************************************
-Frees large pages memory. */
-
-void
-os_mem_free_large(
-/*==============*/
-void *ptr); /* in: number of bytes */
-/********************************************************************
-Sets the priority boost for threads released from waiting within the current
-process. */
-
-void
-os_process_set_priority_boost(
-/*==========================*/
- ibool do_boost); /* in: TRUE if priority boost should be done,
- FALSE if not */
-
-#ifndef UNIV_NONINL
-#include "os0proc.ic"
-#endif
-
-#endif
diff --git a/storage/innobase/include/os0proc.ic b/storage/innobase/include/os0proc.ic
deleted file mode 100644
index 651ba1f17e3..00000000000
--- a/storage/innobase/include/os0proc.ic
+++ /dev/null
@@ -1,10 +0,0 @@
-/******************************************************
-The interface to the operating system
-process control primitives
-
-(c) 1995 Innobase Oy
-
-Created 9/30/1995 Heikki Tuuri
-*******************************************************/
-
-
diff --git a/storage/innobase/include/os0sync.h b/storage/innobase/include/os0sync.h
deleted file mode 100644
index 26d2786e33b..00000000000
--- a/storage/innobase/include/os0sync.h
+++ /dev/null
@@ -1,311 +0,0 @@
-/******************************************************
-The interface to the operating system
-synchronization primitives.
-
-(c) 1995 Innobase Oy
-
-Created 9/6/1995 Heikki Tuuri
-*******************************************************/
-#ifndef os0sync_h
-#define os0sync_h
-
-#include "univ.i"
-#include "ut0lst.h"
-
-#ifdef HAVE_SOLARIS_ATOMIC
-#include
-#endif
-
-#ifdef __WIN__
-
-#define os_fast_mutex_t CRITICAL_SECTION
-
-typedef HANDLE os_native_event_t;
-
-typedef struct os_event_struct os_event_struct_t;
-typedef os_event_struct_t* os_event_t;
-
-struct os_event_struct {
- os_native_event_t handle;
- /* Windows event */
- UT_LIST_NODE_T(os_event_struct_t) os_event_list;
- /* list of all created events */
-};
-#else
-typedef pthread_mutex_t os_fast_mutex_t;
-
-typedef struct os_event_struct os_event_struct_t;
-typedef os_event_struct_t* os_event_t;
-
-struct os_event_struct {
- os_fast_mutex_t os_mutex; /* this mutex protects the next
- fields */
- ibool is_set; /* this is TRUE when the event is
- in the signaled state, i.e., a thread
- does not stop if it tries to wait for
- this event */
- ib_longlong signal_count; /* this is incremented each time
- the event becomes signaled */
- pthread_cond_t cond_var; /* condition variable is used in
- waiting for the event */
- UT_LIST_NODE_T(os_event_struct_t) os_event_list;
- /* list of all created events */
-};
-#endif
-
-typedef struct os_mutex_struct os_mutex_str_t;
-typedef os_mutex_str_t* os_mutex_t;
-
-#define OS_SYNC_INFINITE_TIME ((ulint)(-1))
-
-#define OS_SYNC_TIME_EXCEEDED 1
-
-/* Mutex protecting counts and the event and OS 'slow' mutex lists */
-extern os_mutex_t os_sync_mutex;
-
-/* This is incremented by 1 in os_thread_create and decremented by 1 in
-os_thread_exit */
-extern ulint os_thread_count;
-
-extern ulint os_event_count;
-extern ulint os_mutex_count;
-extern ulint os_fast_mutex_count;
-
-/*************************************************************
-Initializes global event and OS 'slow' mutex lists. */
-
-void
-os_sync_init(void);
-/*==============*/
-/*************************************************************
-Frees created events and OS 'slow' mutexes. */
-
-void
-os_sync_free(void);
-/*==============*/
-/*************************************************************
-Creates an event semaphore, i.e., a semaphore which may just have two states:
-signaled and nonsignaled. The created event is manual reset: it must be reset
-explicitly by calling sync_os_reset_event. */
-
-os_event_t
-os_event_create(
-/*============*/
- /* out: the event handle */
- const char* name); /* in: the name of the event, if NULL
- the event is created without a name */
-#ifdef __WIN__
-/*************************************************************
-Creates an auto-reset event semaphore, i.e., an event which is automatically
-reset when a single thread is released. Works only in Windows. */
-
-os_event_t
-os_event_create_auto(
-/*=================*/
- /* out: the event handle */
- const char* name); /* in: the name of the event, if NULL
- the event is created without a name */
-#endif
-/**************************************************************
-Sets an event semaphore to the signaled state: lets waiting threads
-proceed. */
-
-void
-os_event_set(
-/*=========*/
- os_event_t event); /* in: event to set */
-/**************************************************************
-Resets an event semaphore to the nonsignaled state. Waiting threads will
-stop to wait for the event.
-The return value should be passed to os_even_wait_low() if it is desired
-that this thread should not wait in case of an intervening call to
-os_event_set() between this os_event_reset() and the
-os_event_wait_low() call. See comments for os_event_wait_low(). */
-
-ib_longlong
-os_event_reset(
-/*===========*/
- os_event_t event); /* in: event to reset */
-/**************************************************************
-Frees an event object. */
-
-void
-os_event_free(
-/*==========*/
- os_event_t event); /* in: event to free */
-
-/**************************************************************
-Waits for an event object until it is in the signaled state. If
-srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS this also exits the
-waiting thread when the event becomes signaled (or immediately if the
-event is already in the signaled state).
-
-Typically, if the event has been signalled after the os_event_reset()
-we'll return immediately because event->is_set == TRUE.
-There are, however, situations (e.g.: sync_array code) where we may
-lose this information. For example:
-
-thread A calls os_event_reset()
-thread B calls os_event_set() [event->is_set == TRUE]
-thread C calls os_event_reset() [event->is_set == FALSE]
-thread A calls os_event_wait() [infinite wait!]
-thread C calls os_event_wait() [infinite wait!]
-
-Where such a scenario is possible, to avoid infinite wait, the
-value returned by os_event_reset() should be passed in as
-reset_sig_count. */
-
-#define os_event_wait(event) os_event_wait_low((event), 0)
-
-void
-os_event_wait_low(
-/*==============*/
- os_event_t event, /* in: event to wait */
- ib_longlong reset_sig_count);/* in: zero or the value
- returned by previous call of
- os_event_reset(). */
-
-/**************************************************************
-Waits for an event object until it is in the signaled state or
-a timeout is exceeded. In Unix the timeout is always infinite. */
-
-ulint
-os_event_wait_time(
-/*===============*/
- /* out: 0 if success,
- OS_SYNC_TIME_EXCEEDED if timeout
- was exceeded */
- os_event_t event, /* in: event to wait */
- ulint time); /* in: timeout in microseconds, or
- OS_SYNC_INFINITE_TIME */
-#ifdef __WIN__
-/**************************************************************
-Waits for any event in an OS native event array. Returns if even a single
-one is signaled or becomes signaled. */
-
-ulint
-os_event_wait_multiple(
-/*===================*/
- /* out: index of the event
- which was signaled */
- ulint n, /* in: number of events in the
- array */
- os_native_event_t* native_event_array);
- /* in: pointer to an array of event
- handles */
-#endif
-/*************************************************************
-Creates an operating system mutex semaphore. Because these are slow, the
-mutex semaphore of InnoDB itself (mutex_t) should be used where possible. */
-
-os_mutex_t
-os_mutex_create(
-/*============*/
- /* out: the mutex handle */
- const char* name); /* in: the name of the mutex, if NULL
- the mutex is created without a name */
-/**************************************************************
-Acquires ownership of a mutex semaphore. */
-
-void
-os_mutex_enter(
-/*===========*/
- os_mutex_t mutex); /* in: mutex to acquire */
-/**************************************************************
-Releases ownership of a mutex. */
-
-void
-os_mutex_exit(
-/*==========*/
- os_mutex_t mutex); /* in: mutex to release */
-/**************************************************************
-Frees an mutex object. */
-
-void
-os_mutex_free(
-/*==========*/
- os_mutex_t mutex); /* in: mutex to free */
-/**************************************************************
-Acquires ownership of a fast mutex. Currently in Windows this is the same
-as os_fast_mutex_lock! */
-UNIV_INLINE
-ulint
-os_fast_mutex_trylock(
-/*==================*/
- /* out: 0 if success, != 0 if
- was reserved by another
- thread */
- os_fast_mutex_t* fast_mutex); /* in: mutex to acquire */
-/**************************************************************
-Releases ownership of a fast mutex. */
-
-void
-os_fast_mutex_unlock(
-/*=================*/
- os_fast_mutex_t* fast_mutex); /* in: mutex to release */
-/*************************************************************
-Initializes an operating system fast mutex semaphore. */
-
-void
-os_fast_mutex_init(
-/*===============*/
- os_fast_mutex_t* fast_mutex); /* in: fast mutex */
-/**************************************************************
-Acquires ownership of a fast mutex. */
-
-void
-os_fast_mutex_lock(
-/*===============*/
- os_fast_mutex_t* fast_mutex); /* in: mutex to acquire */
-/**************************************************************
-Frees an mutex object. */
-
-void
-os_fast_mutex_free(
-/*===============*/
- os_fast_mutex_t* fast_mutex); /* in: mutex to free */
-
-#ifdef UNIV_SYNC_ATOMIC
-/**************************************************************
-Atomic compare-and-swap for InnoDB. Currently requires GCC atomic builtins. */
-UNIV_INLINE
-ibool
-os_compare_and_swap(
-/*================*/
- /* out: true if swapped */
- volatile lint* ptr, /* in: pointer to target */
- lint oldVal, /* in: value to compare to */
- lint newVal); /* in: value to swap in */
-
-/**************************************************************
-Atomic increment for InnoDB. Currently requires GCC atomic builtins. */
-UNIV_INLINE
-lint
-os_atomic_increment(
-/*================*/
- /* out: resulting value */
- volatile lint* ptr, /* in: pointer to target */
- lint amount); /* in: amount of increment */
-
-/**************************************************************
-Memory barrier operations for InnoDB.
-Currently requires GCC atomic builtins. */
-UNIV_INLINE
-void
-os_memory_barrier_load();
-
-UNIV_INLINE
-void
-os_memory_barrier_store();
-
-UNIV_INLINE
-void
-os_memory_barrier();
-
-#endif /* UNIV_SYNC_ATOMIC */
-
-#ifndef UNIV_NONINL
-#include "os0sync.ic"
-#endif
-
-#endif
diff --git a/storage/innobase/include/os0sync.ic b/storage/innobase/include/os0sync.ic
deleted file mode 100644
index d1307134172..00000000000
--- a/storage/innobase/include/os0sync.ic
+++ /dev/null
@@ -1,152 +0,0 @@
-/******************************************************
-The interface to the operating system synchronization primitives.
-
-(c) 1995 Innobase Oy
-
-Created 9/6/1995 Heikki Tuuri
-*******************************************************/
-
-#ifdef __WIN__
-#include
-#endif
-
-/**************************************************************
-Acquires ownership of a fast mutex. Currently in Windows this is the same
-as os_fast_mutex_lock! */
-UNIV_INLINE
-ulint
-os_fast_mutex_trylock(
-/*==================*/
- /* out: 0 if success, != 0 if
- was reserved by another
- thread */
- os_fast_mutex_t* fast_mutex) /* in: mutex to acquire */
-{
-#ifdef __WIN__
- EnterCriticalSection(fast_mutex);
-
- return(0);
-#else
-#if defined(UNIV_HOTBACKUP) && defined(UNIV_HPUX10)
- /* Since the hot backup version is standalone, MySQL does not redefine
- pthread_mutex_trylock for HP-UX-10.20, and consequently we must invert
- the return value here */
-
- return((ulint) (1 - pthread_mutex_trylock(fast_mutex)));
-#else
- /* NOTE that the MySQL my_pthread.h redefines pthread_mutex_trylock
- so that it returns 0 on success. In the operating system
- libraries, HP-UX-10.20 follows the old Posix 1003.4a Draft 4 and
- returns 1 on success (but MySQL remaps that to 0), while Linux,
- FreeBSD, Solaris, AIX, Tru64 Unix, HP-UX-11.0 return 0 on success. */
-
- return((ulint) pthread_mutex_trylock(fast_mutex));
-#endif
-#endif
-}
-
-#ifdef UNIV_SYNC_ATOMIC
-/**************************************************************
-Atomic compare-and-swap for InnoDB. Currently requires GCC atomic builtins
-or Solaris atomic_* functions. */
-UNIV_INLINE
-ibool
-os_compare_and_swap(
-/*================*/
- /* out: true if swapped */
- volatile lint* ptr, /* in: pointer to target */
- lint oldVal, /* in: value to compare to */
- lint newVal) /* in: value to swap in */
-{
-#ifdef HAVE_GCC_ATOMIC_BUILTINS
- return (__sync_bool_compare_and_swap(ptr, oldVal, newVal));
-#elif HAVE_SOLARIS_ATOMIC
- lint retVal = (lint)atomic_cas_ulong((volatile ulong_t *)ptr,
- oldVal, newVal);
- return (retVal == oldVal);
-#elif WIN_ATOMICS32
- lint retVal = (lint)InterlockedCompareExchange(ptr, newVal, oldVal);
- return (retVal == oldVal);
-#elif WIN_ATOMICS64
- lint retVal = (lint)InterlockedCompareExchange64(ptr, newVal, oldVal);
- return (retVal == oldVal);
-#else
-#error "Need support for atomic ops"
-#endif
-}
-
-/**************************************************************
-Memory barrier for load */
-UNIV_INLINE
-void
-os_memory_barrier_load()
-{
-#ifdef HAVE_GCC_ATOMIC_BUILTINS
- __sync_synchronize();
-#elif HAVE_SOLARIS_ATOMIC
- membar_consumer();
-#elif WIN_ATOMICS32
- MemoryBarrier();
-#elif WIN_ATOMICS64
- MemoryBarrier();
-#endif
-}
-
-/**************************************************************
-Memory barrier for store */
-UNIV_INLINE
-void
-os_memory_barrier_store()
-{
-#ifdef HAVE_GCC_ATOMIC_BUILTINS
- __sync_synchronize();
-#elif HAVE_SOLARIS_ATOMIC
- membar_producer();
-#elif WIN_ATOMICS32
- MemoryBarrier();
-#elif WIN_ATOMICS64
- MemoryBarrier();
-#endif
-}
-
-/**************************************************************
-Memory barrier */
-UNIV_INLINE
-void
-os_memory_barrier()
-{
-#ifdef HAVE_GCC_ATOMIC_BUILTINS
- __sync_synchronize();
-#elif HAVE_SOLARIS_ATOMIC
- membar_enter();
-#elif WIN_ATOMICS32
- MemoryBarrier();
-#elif WIN_ATOMICS64
- MemoryBarrier();
-#endif
-}
-
-
-/**************************************************************
-Atomic increment for InnoDB. Currently requires GCC atomic builtins. */
-UNIV_INLINE
-lint
-os_atomic_increment(
-/*================*/
- /* out: resulting value */
- volatile lint* ptr, /* in: pointer to target */
- lint amount) /* in: amount of increment */
-{
-#ifdef HAVE_GCC_ATOMIC_BUILTINS
- return (__sync_add_and_fetch(ptr, amount));
-#elif HAVE_SOLARIS_ATOMIC
- return ((lint)atomic_add_long_nv((volatile ulong_t *)ptr, amount));
-#elif WIN_ATOMICS32
- return ((lint)InterlockedExchangeAdd(ptr, amount) + amount);
-#elif WIN_ATOMICS64
- return ((lint)InterlockedExchangeAdd64(ptr, amount) + amount);
-#else
-#error "Need support for atomic ops"
-#endif
-}
-#endif /* UNIV_SYNC_ATOMIC */
diff --git a/storage/innobase/include/os0thread.ic b/storage/innobase/include/os0thread.ic
deleted file mode 100644
index a75aa3abb34..00000000000
--- a/storage/innobase/include/os0thread.ic
+++ /dev/null
@@ -1,8 +0,0 @@
-/******************************************************
-The interface to the operating system
-process and thread control primitives
-
-(c) 1995 Innobase Oy
-
-Created 9/8/1995 Heikki Tuuri
-*******************************************************/
diff --git a/storage/innobase/include/page0cur.h b/storage/innobase/include/page0cur.h
deleted file mode 100644
index 04f731414a3..00000000000
--- a/storage/innobase/include/page0cur.h
+++ /dev/null
@@ -1,286 +0,0 @@
-/************************************************************************
-The page cursor
-
-(c) 1994-1996 Innobase Oy
-
-Created 10/4/1994 Heikki Tuuri
-*************************************************************************/
-
-#ifndef page0cur_h
-#define page0cur_h
-
-#include "univ.i"
-
-#include "page0types.h"
-#include "page0page.h"
-#include "rem0rec.h"
-#include "data0data.h"
-#include "mtr0mtr.h"
-
-
-#define PAGE_CUR_ADAPT
-
-/* Page cursor search modes; the values must be in this order! */
-
-#define PAGE_CUR_UNSUPP 0
-#define PAGE_CUR_G 1
-#define PAGE_CUR_GE 2
-#define PAGE_CUR_L 3
-#define PAGE_CUR_LE 4
-/*#define PAGE_CUR_LE_OR_EXTENDS 5*/ /* This is a search mode used in
- "column LIKE 'abc%' ORDER BY column DESC";
- we have to find strings which are <= 'abc' or
- which extend it */
-#ifdef UNIV_SEARCH_DEBUG
-# define PAGE_CUR_DBG 6 /* As PAGE_CUR_LE, but skips search shortcut */
-#endif /* UNIV_SEARCH_DEBUG */
-
-#ifdef PAGE_CUR_ADAPT
-# ifdef UNIV_SEARCH_PERF_STAT
-extern ulint page_cur_short_succ;
-# endif /* UNIV_SEARCH_PERF_STAT */
-#endif /* PAGE_CUR_ADAPT */
-
-/*************************************************************
-Gets pointer to the page frame where the cursor is positioned. */
-UNIV_INLINE
-page_t*
-page_cur_get_page(
-/*==============*/
- /* out: page */
- page_cur_t* cur); /* in: page cursor */
-/*************************************************************
-Gets the record where the cursor is positioned. */
-UNIV_INLINE
-rec_t*
-page_cur_get_rec(
-/*=============*/
- /* out: record */
- page_cur_t* cur); /* in: page cursor */
-/*************************************************************
-Sets the cursor object to point before the first user record
-on the page. */
-UNIV_INLINE
-void
-page_cur_set_before_first(
-/*======================*/
- page_t* page, /* in: index page */
- page_cur_t* cur); /* in: cursor */
-/*************************************************************
-Sets the cursor object to point after the last user record on
-the page. */
-UNIV_INLINE
-void
-page_cur_set_after_last(
-/*====================*/
- page_t* page, /* in: index page */
- page_cur_t* cur); /* in: cursor */
-/*************************************************************
-Returns TRUE if the cursor is before first user record on page. */
-UNIV_INLINE
-ibool
-page_cur_is_before_first(
-/*=====================*/
- /* out: TRUE if at start */
- const page_cur_t* cur); /* in: cursor */
-/*************************************************************
-Returns TRUE if the cursor is after last user record. */
-UNIV_INLINE
-ibool
-page_cur_is_after_last(
-/*===================*/
- /* out: TRUE if at end */
- const page_cur_t* cur); /* in: cursor */
-/**************************************************************
-Positions the cursor on the given record. */
-UNIV_INLINE
-void
-page_cur_position(
-/*==============*/
- rec_t* rec, /* in: record on a page */
- page_cur_t* cur); /* in: page cursor */
-/**************************************************************
-Invalidates a page cursor by setting the record pointer NULL. */
-UNIV_INLINE
-void
-page_cur_invalidate(
-/*================*/
- page_cur_t* cur); /* in: page cursor */
-/**************************************************************
-Moves the cursor to the next record on page. */
-UNIV_INLINE
-void
-page_cur_move_to_next(
-/*==================*/
- page_cur_t* cur); /* in: cursor; must not be after last */
-/**************************************************************
-Moves the cursor to the previous record on page. */
-UNIV_INLINE
-void
-page_cur_move_to_prev(
-/*==================*/
- page_cur_t* cur); /* in: cursor; must not before first */
-/***************************************************************
-Inserts a record next to page cursor. Returns pointer to inserted record if
-succeed, i.e., enough space available, NULL otherwise. The cursor stays at
-the same position. */
-UNIV_INLINE
-rec_t*
-page_cur_tuple_insert(
-/*==================*/
- /* out: pointer to record if succeed, NULL
- otherwise */
- page_cur_t* cursor, /* in: a page cursor */
- dtuple_t* tuple, /* in: pointer to a data tuple */
- dict_index_t* index, /* in: record descriptor */
- mtr_t* mtr); /* in: mini-transaction handle */
-/***************************************************************
-Inserts a record next to page cursor. Returns pointer to inserted record if
-succeed, i.e., enough space available, NULL otherwise. The cursor stays at
-the same position. */
-UNIV_INLINE
-rec_t*
-page_cur_rec_insert(
-/*================*/
- /* out: pointer to record if succeed, NULL
- otherwise */
- page_cur_t* cursor, /* in: a page cursor */
- rec_t* rec, /* in: record to insert */
- dict_index_t* index, /* in: record descriptor */
- ulint* offsets,/* in: rec_get_offsets(rec, index) */
- mtr_t* mtr); /* in: mini-transaction handle */
-/***************************************************************
-Inserts a record next to page cursor. Returns pointer to inserted record if
-succeed, i.e., enough space available, NULL otherwise. The record to be
-inserted can be in a data tuple or as a physical record. The other parameter
-must then be NULL. The cursor stays at the same position. */
-
-rec_t*
-page_cur_insert_rec_low(
-/*====================*/
- /* out: pointer to record if succeed, NULL
- otherwise */
- page_cur_t* cursor, /* in: a page cursor */
- dtuple_t* tuple, /* in: pointer to a data tuple or NULL */
- dict_index_t* index, /* in: record descriptor */
- rec_t* rec, /* in: pointer to a physical record or NULL */
- ulint* offsets,/* in: rec_get_offsets(rec, index) or NULL */
- mtr_t* mtr); /* in: mini-transaction handle */
-/*****************************************************************
-Copies records from page to a newly created page, from a given record onward,
-including that record. Infimum and supremum records are not copied. */
-
-void
-page_copy_rec_list_end_to_created_page(
-/*===================================*/
- page_t* new_page, /* in: index page to copy to */
- page_t* page, /* in: index page */
- rec_t* rec, /* in: first record to copy */
- dict_index_t* index, /* in: record descriptor */
- mtr_t* mtr); /* in: mtr */
-/***************************************************************
-Deletes a record at the page cursor. The cursor is moved to the
-next record after the deleted one. */
-
-void
-page_cur_delete_rec(
-/*================*/
- page_cur_t* cursor, /* in: a page cursor */
- dict_index_t* index, /* in: record descriptor */
- const ulint* offsets,/* in: rec_get_offsets(cursor->rec, index) */
- mtr_t* mtr); /* in: mini-transaction handle */
-/********************************************************************
-Searches the right position for a page cursor. */
-UNIV_INLINE
-ulint
-page_cur_search(
-/*============*/
- /* out: number of matched fields on the left */
- page_t* page, /* in: index page */
- dict_index_t* index, /* in: record descriptor */
- dtuple_t* tuple, /* in: data tuple */
- ulint mode, /* in: PAGE_CUR_L, PAGE_CUR_LE, PAGE_CUR_G,
- or PAGE_CUR_GE */
- page_cur_t* cursor);/* out: page cursor */
-/********************************************************************
-Searches the right position for a page cursor. */
-
-void
-page_cur_search_with_match(
-/*=======================*/
- page_t* page, /* in: index page */
- dict_index_t* index, /* in: record descriptor */
- dtuple_t* tuple, /* in: data tuple */
- ulint mode, /* in: PAGE_CUR_L, PAGE_CUR_LE, PAGE_CUR_G,
- or PAGE_CUR_GE */
- ulint* iup_matched_fields,
- /* in/out: already matched fields in upper
- limit record */
- ulint* iup_matched_bytes,
- /* in/out: already matched bytes in a field
- not yet completely matched */
- ulint* ilow_matched_fields,
- /* in/out: already matched fields in lower
- limit record */
- ulint* ilow_matched_bytes,
- /* in/out: already matched bytes in a field
- not yet completely matched */
- page_cur_t* cursor); /* out: page cursor */
-/***************************************************************
-Positions a page cursor on a randomly chosen user record on a page. If there
-are no user records, sets the cursor on the infimum record. */
-
-void
-page_cur_open_on_rnd_user_rec(
-/*==========================*/
- page_t* page, /* in: page */
- page_cur_t* cursor);/* in/out: page cursor */
-/***************************************************************
-Parses a log record of a record insert on a page. */
-
-byte*
-page_cur_parse_insert_rec(
-/*======================*/
- /* out: end of log record or NULL */
- ibool is_short,/* in: TRUE if short inserts */
- byte* ptr, /* in: buffer */
- byte* end_ptr,/* in: buffer end */
- dict_index_t* index, /* in: record descriptor */
- page_t* page, /* in: page or NULL */
- mtr_t* mtr); /* in: mtr or NULL */
-/**************************************************************
-Parses a log record of copying a record list end to a new created page. */
-
-byte*
-page_parse_copy_rec_list_to_created_page(
-/*=====================================*/
- /* out: end of log record or NULL */
- byte* ptr, /* in: buffer */
- byte* end_ptr,/* in: buffer end */
- dict_index_t* index, /* in: record descriptor */
- page_t* page, /* in: page or NULL */
- mtr_t* mtr); /* in: mtr or NULL */
-/***************************************************************
-Parses log record of a record delete on a page. */
-
-byte*
-page_cur_parse_delete_rec(
-/*======================*/
- /* out: pointer to record end or NULL */
- byte* ptr, /* in: buffer */
- byte* end_ptr,/* in: buffer end */
- dict_index_t* index, /* in: record descriptor */
- page_t* page, /* in: page or NULL */
- mtr_t* mtr); /* in: mtr or NULL */
-
-/* Index page cursor */
-
-struct page_cur_struct{
- byte* rec; /* pointer to a record on page */
-};
-
-#ifndef UNIV_NONINL
-#include "page0cur.ic"
-#endif
-
-#endif
diff --git a/storage/innobase/include/page0cur.ic b/storage/innobase/include/page0cur.ic
deleted file mode 100644
index b747874abc2..00000000000
--- a/storage/innobase/include/page0cur.ic
+++ /dev/null
@@ -1,210 +0,0 @@
-/************************************************************************
-The page cursor
-
-(c) 1994-1996 Innobase Oy
-
-Created 10/4/1994 Heikki Tuuri
-*************************************************************************/
-
-#include "page0page.h"
-
-
-/*************************************************************
-Gets pointer to the page frame where the cursor is positioned. */
-UNIV_INLINE
-page_t*
-page_cur_get_page(
-/*==============*/
- /* out: page */
- page_cur_t* cur) /* in: page cursor */
-{
- ut_ad(cur);
-
- return(buf_frame_align(cur->rec));
-}
-
-/*************************************************************
-Gets the record where the cursor is positioned. */
-UNIV_INLINE
-rec_t*
-page_cur_get_rec(
-/*=============*/
- /* out: record */
- page_cur_t* cur) /* in: page cursor */
-{
- ut_ad(cur);
-
- return(cur->rec);
-}
-
-/*************************************************************
-Sets the cursor object to point before the first user record
-on the page. */
-UNIV_INLINE
-void
-page_cur_set_before_first(
-/*======================*/
- page_t* page, /* in: index page */
- page_cur_t* cur) /* in: cursor */
-{
- cur->rec = page_get_infimum_rec(page);
-}
-
-/*************************************************************
-Sets the cursor object to point after the last user record on
-the page. */
-UNIV_INLINE
-void
-page_cur_set_after_last(
-/*====================*/
- page_t* page, /* in: index page */
- page_cur_t* cur) /* in: cursor */
-{
- cur->rec = page_get_supremum_rec(page);
-}
-
-/*************************************************************
-Returns TRUE if the cursor is before first user record on page. */
-UNIV_INLINE
-ibool
-page_cur_is_before_first(
-/*=====================*/
- /* out: TRUE if at start */
- const page_cur_t* cur) /* in: cursor */
-{
- return(page_rec_is_infimum(cur->rec));
-}
-
-/*************************************************************
-Returns TRUE if the cursor is after last user record. */
-UNIV_INLINE
-ibool
-page_cur_is_after_last(
-/*===================*/
- /* out: TRUE if at end */
- const page_cur_t* cur) /* in: cursor */
-{
- return(page_rec_is_supremum(cur->rec));
-}
-
-/**************************************************************
-Positions the cursor on the given record. */
-UNIV_INLINE
-void
-page_cur_position(
-/*==============*/
- rec_t* rec, /* in: record on a page */
- page_cur_t* cur) /* in: page cursor */
-{
- ut_ad(rec && cur);
-
- cur->rec = rec;
-}
-
-/**************************************************************
-Invalidates a page cursor by setting the record pointer NULL. */
-UNIV_INLINE
-void
-page_cur_invalidate(
-/*================*/
- page_cur_t* cur) /* in: page cursor */
-{
- ut_ad(cur);
-
- cur->rec = NULL;
-}
-
-/**************************************************************
-Moves the cursor to the next record on page. */
-UNIV_INLINE
-void
-page_cur_move_to_next(
-/*==================*/
- page_cur_t* cur) /* in: cursor; must not be after last */
-{
- ut_ad(!page_cur_is_after_last(cur));
-
- cur->rec = page_rec_get_next(cur->rec);
-}
-
-/**************************************************************
-Moves the cursor to the previous record on page. */
-UNIV_INLINE
-void
-page_cur_move_to_prev(
-/*==================*/
- page_cur_t* cur) /* in: page cursor, not before first */
-{
- ut_ad(!page_cur_is_before_first(cur));
-
- cur->rec = page_rec_get_prev(cur->rec);
-}
-
-/********************************************************************
-Searches the right position for a page cursor. */
-UNIV_INLINE
-ulint
-page_cur_search(
-/*============*/
- /* out: number of matched fields on the left */
- page_t* page, /* in: index page */
- dict_index_t* index, /* in: record descriptor */
- dtuple_t* tuple, /* in: data tuple */
- ulint mode, /* in: PAGE_CUR_L, PAGE_CUR_LE, PAGE_CUR_G,
- or PAGE_CUR_GE */
- page_cur_t* cursor) /* out: page cursor */
-{
- ulint low_matched_fields = 0;
- ulint low_matched_bytes = 0;
- ulint up_matched_fields = 0;
- ulint up_matched_bytes = 0;
-
- ut_ad(dtuple_check_typed(tuple));
-
- page_cur_search_with_match(page, index, tuple, mode,
- &up_matched_fields,
- &up_matched_bytes,
- &low_matched_fields,
- &low_matched_bytes,
- cursor);
- return(low_matched_fields);
-}
-
-/***************************************************************
-Inserts a record next to page cursor. Returns pointer to inserted record if
-succeed, i.e., enough space available, NULL otherwise. The cursor stays at
-the same position. */
-UNIV_INLINE
-rec_t*
-page_cur_tuple_insert(
-/*==================*/
- /* out: pointer to record if succeed, NULL
- otherwise */
- page_cur_t* cursor, /* in: a page cursor */
- dtuple_t* tuple, /* in: pointer to a data tuple */
- dict_index_t* index, /* in: record descriptor */
- mtr_t* mtr) /* in: mini-transaction handle */
-{
- return(page_cur_insert_rec_low(cursor, tuple, index, NULL, NULL, mtr));
-}
-
-/***************************************************************
-Inserts a record next to page cursor. Returns pointer to inserted record if
-succeed, i.e., enough space available, NULL otherwise. The cursor stays at
-the same position. */
-UNIV_INLINE
-rec_t*
-page_cur_rec_insert(
-/*================*/
- /* out: pointer to record if succeed, NULL
- otherwise */
- page_cur_t* cursor, /* in: a page cursor */
- rec_t* rec, /* in: record to insert */
- dict_index_t* index, /* in: record descriptor */
- ulint* offsets,/* in: rec_get_offsets(rec, index) */
- mtr_t* mtr) /* in: mini-transaction handle */
-{
- return(page_cur_insert_rec_low(cursor, NULL, index, rec,
- offsets, mtr));
-}
-
diff --git a/storage/innobase/include/page0page.h b/storage/innobase/include/page0page.h
deleted file mode 100644
index 273007c2778..00000000000
--- a/storage/innobase/include/page0page.h
+++ /dev/null
@@ -1,829 +0,0 @@
-/******************************************************
-Index page routines
-
-(c) 1994-1996 Innobase Oy
-
-Created 2/2/1994 Heikki Tuuri
-*******************************************************/
-
-#ifndef page0page_h
-#define page0page_h
-
-#include "univ.i"
-
-#include "page0types.h"
-#include "fil0fil.h"
-#include "buf0buf.h"
-#include "data0data.h"
-#include "dict0dict.h"
-#include "rem0rec.h"
-#include "fsp0fsp.h"
-#include "mtr0mtr.h"
-
-#ifdef UNIV_MATERIALIZE
-#undef UNIV_INLINE
-#define UNIV_INLINE
-#endif
-
-/* PAGE HEADER
- ===========
-
-Index page header starts at the first offset left free by the FIL-module */
-
-typedef byte page_header_t;
-
-#define PAGE_HEADER FSEG_PAGE_DATA /* index page header starts at this
- offset */
-/*-----------------------------*/
-#define PAGE_N_DIR_SLOTS 0 /* number of slots in page directory */
-#define PAGE_HEAP_TOP 2 /* pointer to record heap top */
-#define PAGE_N_HEAP 4 /* number of records in the heap,
- bit 15=flag: new-style compact page format */
-#define PAGE_FREE 6 /* pointer to start of page free record list */
-#define PAGE_GARBAGE 8 /* number of bytes in deleted records */
-#define PAGE_LAST_INSERT 10 /* pointer to the last inserted record, or
- NULL if this info has been reset by a delete,
- for example */
-#define PAGE_DIRECTION 12 /* last insert direction: PAGE_LEFT, ... */
-#define PAGE_N_DIRECTION 14 /* number of consecutive inserts to the same
- direction */
-#define PAGE_N_RECS 16 /* number of user records on the page */
-#define PAGE_MAX_TRX_ID 18 /* highest id of a trx which may have modified
- a record on the page; a dulint; defined only
- in secondary indexes; specifically, not in an
- ibuf tree; NOTE: this may be modified only
- when the thread has an x-latch to the page,
- and ALSO an x-latch to btr_search_latch
- if there is a hash index to the page! */
-#define PAGE_HEADER_PRIV_END 26 /* end of private data structure of the page
- header which are set in a page create */
-/*----*/
-#define PAGE_LEVEL 26 /* level of the node in an index tree; the
- leaf level is the level 0 */
-#define PAGE_INDEX_ID 28 /* index id where the page belongs */
-#define PAGE_BTR_SEG_LEAF 36 /* file segment header for the leaf pages in
- a B-tree: defined only on the root page of a
- B-tree, but not in the root of an ibuf tree */
-#define PAGE_BTR_IBUF_FREE_LIST PAGE_BTR_SEG_LEAF
-#define PAGE_BTR_IBUF_FREE_LIST_NODE PAGE_BTR_SEG_LEAF
- /* in the place of PAGE_BTR_SEG_LEAF and _TOP
- there is a free list base node if the page is
- the root page of an ibuf tree, and at the same
- place is the free list node if the page is in
- a free list */
-#define PAGE_BTR_SEG_TOP (36 + FSEG_HEADER_SIZE)
- /* file segment header for the non-leaf pages
- in a B-tree: defined only on the root page of
- a B-tree, but not in the root of an ibuf
- tree */
-/*----*/
-#define PAGE_DATA (PAGE_HEADER + 36 + 2 * FSEG_HEADER_SIZE)
- /* start of data on the page */
-
-#define PAGE_OLD_INFIMUM (PAGE_DATA + 1 + REC_N_OLD_EXTRA_BYTES)
- /* offset of the page infimum record on an
- old-style page */
-#define PAGE_OLD_SUPREMUM (PAGE_DATA + 2 + 2 * REC_N_OLD_EXTRA_BYTES + 8)
- /* offset of the page supremum record on an
- old-style page */
-#define PAGE_OLD_SUPREMUM_END (PAGE_OLD_SUPREMUM + 9)
- /* offset of the page supremum record end on
- an old-style page */
-#define PAGE_NEW_INFIMUM (PAGE_DATA + REC_N_NEW_EXTRA_BYTES)
- /* offset of the page infimum record on a
- new-style compact page */
-#define PAGE_NEW_SUPREMUM (PAGE_DATA + 2 * REC_N_NEW_EXTRA_BYTES + 8)
- /* offset of the page supremum record on a
- new-style compact page */
-#define PAGE_NEW_SUPREMUM_END (PAGE_NEW_SUPREMUM + 8)
- /* offset of the page supremum record end on
- a new-style compact page */
-/*-----------------------------*/
-
-/* Directions of cursor movement */
-#define PAGE_LEFT 1
-#define PAGE_RIGHT 2
-#define PAGE_SAME_REC 3
-#define PAGE_SAME_PAGE 4
-#define PAGE_NO_DIRECTION 5
-
-/* PAGE DIRECTORY
- ==============
-*/
-
-typedef byte page_dir_slot_t;
-typedef page_dir_slot_t page_dir_t;
-
-/* Offset of the directory start down from the page end. We call the
-slot with the highest file address directory start, as it points to
-the first record in the list of records. */
-#define PAGE_DIR FIL_PAGE_DATA_END
-
-/* We define a slot in the page directory as two bytes */
-#define PAGE_DIR_SLOT_SIZE 2
-
-/* The offset of the physically lower end of the directory, counted from
-page end, when the page is empty */
-#define PAGE_EMPTY_DIR_START (PAGE_DIR + 2 * PAGE_DIR_SLOT_SIZE)
-
-/* The maximum and minimum number of records owned by a directory slot. The
-number may drop below the minimum in the first and the last slot in the
-directory. */
-#define PAGE_DIR_SLOT_MAX_N_OWNED 8
-#define PAGE_DIR_SLOT_MIN_N_OWNED 4
-
-/****************************************************************
-Gets the start of a page. */
-UNIV_INLINE
-page_t*
-page_align(
-/*=======*/
- /* out: start of the page */
- void* ptr) /* in: pointer to page frame */
- __attribute__((const));
-/****************************************************************
-Gets the offset within a page. */
-UNIV_INLINE
-ulint
-page_offset(
-/*========*/
- /* out: offset from the start of the page */
- const void* ptr) /* in: pointer to page frame */
- __attribute__((const));
-/*****************************************************************
-Returns the max trx id field value. */
-UNIV_INLINE
-dulint
-page_get_max_trx_id(
-/*================*/
- page_t* page); /* in: page */
-/*****************************************************************
-Sets the max trx id field value. */
-
-void
-page_set_max_trx_id(
-/*================*/
- page_t* page, /* in: page */
- dulint trx_id);/* in: transaction id */
-/*****************************************************************
-Sets the max trx id field value if trx_id is bigger than the previous
-value. */
-UNIV_INLINE
-void
-page_update_max_trx_id(
-/*===================*/
- page_t* page, /* in: page */
- dulint trx_id); /* in: transaction id */
-/*****************************************************************
-Reads the given header field. */
-UNIV_INLINE
-ulint
-page_header_get_field(
-/*==================*/
- page_t* page, /* in: page */
- ulint field); /* in: PAGE_N_DIR_SLOTS, ... */
-/*****************************************************************
-Sets the given header field. */
-UNIV_INLINE
-void
-page_header_set_field(
-/*==================*/
- page_t* page, /* in: page */
- ulint field, /* in: PAGE_N_DIR_SLOTS, ... */
- ulint val); /* in: value */
-/*****************************************************************
-Returns the pointer stored in the given header field. */
-UNIV_INLINE
-byte*
-page_header_get_ptr(
-/*================*/
- /* out: pointer or NULL */
- page_t* page, /* in: page */
- ulint field); /* in: PAGE_FREE, ... */
-/*****************************************************************
-Sets the pointer stored in the given header field. */
-UNIV_INLINE
-void
-page_header_set_ptr(
-/*================*/
- page_t* page, /* in: page */
- ulint field, /* in: PAGE_FREE, ... */
- byte* ptr); /* in: pointer or NULL*/
-/*****************************************************************
-Resets the last insert info field in the page header. Writes to mlog
-about this operation. */
-UNIV_INLINE
-void
-page_header_reset_last_insert(
-/*==========================*/
- page_t* page, /* in: page */
- mtr_t* mtr); /* in: mtr */
-/****************************************************************
-Gets the first record on the page. */
-UNIV_INLINE
-rec_t*
-page_get_infimum_rec(
-/*=================*/
- /* out: the first record in record list */
- page_t* page); /* in: page which must have record(s) */
-/****************************************************************
-Gets the last record on the page. */
-UNIV_INLINE
-rec_t*
-page_get_supremum_rec(
-/*==================*/
- /* out: the last record in record list */
- page_t* page); /* in: page which must have record(s) */
-/****************************************************************
-Returns the middle record of record list. If there are an even number
-of records in the list, returns the first record of upper half-list. */
-
-rec_t*
-page_get_middle_rec(
-/*================*/
- /* out: middle record */
- page_t* page); /* in: page */
-/*****************************************************************
-Compares a data tuple to a physical record. Differs from the function
-cmp_dtuple_rec_with_match in the way that the record must reside on an
-index page, and also page infimum and supremum records can be given in
-the parameter rec. These are considered as the negative infinity and
-the positive infinity in the alphabetical order. */
-UNIV_INLINE
-int
-page_cmp_dtuple_rec_with_match(
-/*===========================*/
- /* out: 1, 0, -1, if dtuple is greater, equal,
- less than rec, respectively, when only the
- common first fields are compared */
- dtuple_t* dtuple, /* in: data tuple */
- rec_t* rec, /* in: physical record on a page; may also
- be page infimum or supremum, in which case
- matched-parameter values below are not
- affected */
- const ulint* offsets,/* in: array returned by rec_get_offsets() */
- ulint* matched_fields, /* in/out: number of already completely
- matched fields; when function returns
- contains the value for current comparison */
- ulint* matched_bytes); /* in/out: number of already matched
- bytes within the first field not completely
- matched; when function returns contains the
- value for current comparison */
-/*****************************************************************
-Gets the number of user records on page (the infimum and supremum records
-are not user records). */
-UNIV_INLINE
-ulint
-page_get_n_recs(
-/*============*/
- /* out: number of user records */
- page_t* page); /* in: index page */
-/*******************************************************************
-Returns the number of records before the given record in chain.
-The number includes infimum and supremum records. */
-
-ulint
-page_rec_get_n_recs_before(
-/*=======================*/
- /* out: number of records */
- rec_t* rec); /* in: the physical record */
-/*****************************************************************
-Gets the number of records in the heap. */
-UNIV_INLINE
-ulint
-page_dir_get_n_heap(
-/*================*/
- /* out: number of user records */
- page_t* page); /* in: index page */
-/*****************************************************************
-Sets the number of records in the heap. */
-UNIV_INLINE
-void
-page_dir_set_n_heap(
-/*================*/
- page_t* page, /* in: index page */
- ulint n_heap);/* in: number of records */
-/*****************************************************************
-Gets the number of dir slots in directory. */
-UNIV_INLINE
-ulint
-page_dir_get_n_slots(
-/*=================*/
- /* out: number of slots */
- page_t* page); /* in: index page */
-/*****************************************************************
-Sets the number of dir slots in directory. */
-UNIV_INLINE
-void
-page_dir_set_n_slots(
-/*=================*/
- /* out: number of slots */
- page_t* page, /* in: index page */
- ulint n_slots);/* in: number of slots */
-/*****************************************************************
-Gets pointer to nth directory slot. */
-UNIV_INLINE
-page_dir_slot_t*
-page_dir_get_nth_slot(
-/*==================*/
- /* out: pointer to dir slot */
- page_t* page, /* in: index page */
- ulint n); /* in: position */
-/******************************************************************
-Used to check the consistency of a record on a page. */
-UNIV_INLINE
-ibool
-page_rec_check(
-/*===========*/
- /* out: TRUE if succeed */
- rec_t* rec); /* in: record */
-/*******************************************************************
-Gets the record pointed to by a directory slot. */
-UNIV_INLINE
-rec_t*
-page_dir_slot_get_rec(
-/*==================*/
- /* out: pointer to record */
- page_dir_slot_t* slot); /* in: directory slot */
-/*******************************************************************
-This is used to set the record offset in a directory slot. */
-UNIV_INLINE
-void
-page_dir_slot_set_rec(
-/*==================*/
- page_dir_slot_t* slot, /* in: directory slot */
- rec_t* rec); /* in: record on the page */
-/*******************************************************************
-Gets the number of records owned by a directory slot. */
-UNIV_INLINE
-ulint
-page_dir_slot_get_n_owned(
-/*======================*/
- /* out: number of records */
- page_dir_slot_t* slot); /* in: page directory slot */
-/*******************************************************************
-This is used to set the owned records field of a directory slot. */
-UNIV_INLINE
-void
-page_dir_slot_set_n_owned(
-/*======================*/
- page_dir_slot_t* slot, /* in: directory slot */
- ulint n); /* in: number of records owned
- by the slot */
-/****************************************************************
-Calculates the space reserved for directory slots of a given
-number of records. The exact value is a fraction number
-n * PAGE_DIR_SLOT_SIZE / PAGE_DIR_SLOT_MIN_N_OWNED, and it is
-rounded upwards to an integer. */
-UNIV_INLINE
-ulint
-page_dir_calc_reserved_space(
-/*=========================*/
- ulint n_recs); /* in: number of records */
-/*******************************************************************
-Looks for the directory slot which owns the given record. */
-
-ulint
-page_dir_find_owner_slot(
-/*=====================*/
- /* out: the directory slot number */
- rec_t* rec); /* in: the physical record */
-/****************************************************************
-Determine whether the page is in new-style compact format. */
-UNIV_INLINE
-ulint
-page_is_comp(
-/*=========*/
- /* out: nonzero if the page is in compact
- format, zero if it is in old-style format */
- page_t* page); /* in: index page */
-/****************************************************************
-TRUE if the record is on a page in compact format. */
-UNIV_INLINE
-ulint
-page_rec_is_comp(
-/*=============*/
- /* out: nonzero if in compact format */
- const rec_t* rec); /* in: record */
-/****************************************************************
-Gets the pointer to the next record on the page. */
-UNIV_INLINE
-rec_t*
-page_rec_get_next(
-/*==============*/
- /* out: pointer to next record */
- rec_t* rec); /* in: pointer to record, must not be page
- supremum */
-/****************************************************************
-Sets the pointer to the next record on the page. */
-UNIV_INLINE
-void
-page_rec_set_next(
-/*==============*/
- rec_t* rec, /* in: pointer to record, must not be
- page supremum */
- rec_t* next); /* in: pointer to next record, must not
- be page infimum */
-/****************************************************************
-Gets the pointer to the previous record. */
-UNIV_INLINE
-rec_t*
-page_rec_get_prev(
-/*==============*/
- /* out: pointer to previous record */
- rec_t* rec); /* in: pointer to record,
- must not be page infimum */
-/****************************************************************
-TRUE if the record is a user record on the page. */
-UNIV_INLINE
-ibool
-page_rec_is_user_rec_low(
-/*=====================*/
- /* out: TRUE if a user record */
- ulint offset);/* in: record offset on page */
-/****************************************************************
-TRUE if the record is the supremum record on a page. */
-UNIV_INLINE
-ibool
-page_rec_is_supremum_low(
-/*=====================*/
- /* out: TRUE if the supremum record */
- ulint offset);/* in: record offset on page */
-/****************************************************************
-TRUE if the record is the infimum record on a page. */
-UNIV_INLINE
-ibool
-page_rec_is_infimum_low(
-/*====================*/
- /* out: TRUE if the infimum record */
- ulint offset);/* in: record offset on page */
-
-/****************************************************************
-TRUE if the record is a user record on the page. */
-UNIV_INLINE
-ibool
-page_rec_is_user_rec(
-/*=================*/
- /* out: TRUE if a user record */
- const rec_t* rec); /* in: record */
-/****************************************************************
-TRUE if the record is the supremum record on a page. */
-UNIV_INLINE
-ibool
-page_rec_is_supremum(
-/*=================*/
- /* out: TRUE if the supremum record */
- const rec_t* rec); /* in: record */
-/****************************************************************
-TRUE if the record is the infimum record on a page. */
-UNIV_INLINE
-ibool
-page_rec_is_infimum(
-/*================*/
- /* out: TRUE if the infimum record */
- const rec_t* rec); /* in: record */
-/*******************************************************************
-Looks for the record which owns the given record. */
-UNIV_INLINE
-rec_t*
-page_rec_find_owner_rec(
-/*====================*/
- /* out: the owner record */
- rec_t* rec); /* in: the physical record */
-/***************************************************************************
-This is a low-level operation which is used in a database index creation
-to update the page number of a created B-tree to a data dictionary
-record. */
-
-void
-page_rec_write_index_page_no(
-/*=========================*/
- rec_t* rec, /* in: record to update */
- ulint i, /* in: index of the field to update */
- ulint page_no,/* in: value to write */
- mtr_t* mtr); /* in: mtr */
-/****************************************************************
-Returns the maximum combined size of records which can be inserted on top
-of record heap. */
-UNIV_INLINE
-ulint
-page_get_max_insert_size(
-/*=====================*/
- /* out: maximum combined size for inserted records */
- page_t* page, /* in: index page */
- ulint n_recs); /* in: number of records */
-/****************************************************************
-Returns the maximum combined size of records which can be inserted on top
-of record heap if page is first reorganized. */
-UNIV_INLINE
-ulint
-page_get_max_insert_size_after_reorganize(
-/*======================================*/
- /* out: maximum combined size for inserted records */
- page_t* page, /* in: index page */
- ulint n_recs);/* in: number of records */
-/*****************************************************************
-Calculates free space if a page is emptied. */
-UNIV_INLINE
-ulint
-page_get_free_space_of_empty(
-/*=========================*/
- /* out: free space */
- ulint comp) /* in: nonzero=compact page format */
- __attribute__((const));
-/*****************************************************************
-Calculates free space if a page is emptied. */
-
-ulint
-page_get_free_space_of_empty_noninline(
-/*===================================*/
- /* out: free space */
- ulint comp) /* in: nonzero=compact page format */
- __attribute__((const));
-/****************************************************************
-Returns the sum of the sizes of the records in the record list
-excluding the infimum and supremum records. */
-UNIV_INLINE
-ulint
-page_get_data_size(
-/*===============*/
- /* out: data in bytes */
- page_t* page); /* in: index page */
-/****************************************************************
-Allocates a block of memory from an index page. */
-
-byte*
-page_mem_alloc(
-/*===========*/
- /* out: pointer to start of allocated
- buffer, or NULL if allocation fails */
- page_t* page, /* in: index page */
- ulint need, /* in: number of bytes needed */
- dict_index_t* index, /* in: record descriptor */
- ulint* heap_no);/* out: this contains the heap number
- of the allocated record
- if allocation succeeds */
-/****************************************************************
-Puts a record to free list. */
-UNIV_INLINE
-void
-page_mem_free(
-/*==========*/
- page_t* page, /* in: index page */
- rec_t* rec, /* in: pointer to the (origin of) record */
- const ulint* offsets);/* in: array returned by rec_get_offsets() */
-/**************************************************************
-The index page creation function. */
-
-page_t*
-page_create(
-/*========*/
- /* out: pointer to the page */
- buf_frame_t* frame, /* in: a buffer frame where the page is
- created */
- mtr_t* mtr, /* in: mini-transaction handle */
- ulint comp); /* in: nonzero=compact page format */
-/*****************************************************************
-Differs from page_copy_rec_list_end, because this function does not
-touch the lock table and max trx id on page. */
-
-void
-page_copy_rec_list_end_no_locks(
-/*============================*/
- page_t* new_page, /* in: index page to copy to */
- page_t* page, /* in: index page */
- rec_t* rec, /* in: record on page */
- dict_index_t* index, /* in: record descriptor */
- mtr_t* mtr); /* in: mtr */
-/*****************************************************************
-Copies records from page to new_page, from the given record onward,
-including that record. Infimum and supremum records are not copied.
-The records are copied to the start of the record list on new_page. */
-
-void
-page_copy_rec_list_end(
-/*===================*/
- page_t* new_page, /* in: index page to copy to */
- page_t* page, /* in: index page */
- rec_t* rec, /* in: record on page */
- dict_index_t* index, /* in: record descriptor */
- mtr_t* mtr); /* in: mtr */
-/*****************************************************************
-Copies records from page to new_page, up to the given record, NOT
-including that record. Infimum and supremum records are not copied.
-The records are copied to the end of the record list on new_page. */
-
-void
-page_copy_rec_list_start(
-/*=====================*/
- page_t* new_page, /* in: index page to copy to */
- page_t* page, /* in: index page */
- rec_t* rec, /* in: record on page */
- dict_index_t* index, /* in: record descriptor */
- mtr_t* mtr); /* in: mtr */
-/*****************************************************************
-Deletes records from a page from a given record onward, including that record.
-The infimum and supremum records are not deleted. */
-
-void
-page_delete_rec_list_end(
-/*=====================*/
- page_t* page, /* in: index page */
- rec_t* rec, /* in: record on page */
- dict_index_t* index, /* in: record descriptor */
- ulint n_recs, /* in: number of records to delete,
- or ULINT_UNDEFINED if not known */
- ulint size, /* in: the sum of the sizes of the
- records in the end of the chain to
- delete, or ULINT_UNDEFINED if not known */
- mtr_t* mtr); /* in: mtr */
-/*****************************************************************
-Deletes records from page, up to the given record, NOT including
-that record. Infimum and supremum records are not deleted. */
-
-void
-page_delete_rec_list_start(
-/*=======================*/
- page_t* page, /* in: index page */
- rec_t* rec, /* in: record on page */
- dict_index_t* index, /* in: record descriptor */
- mtr_t* mtr); /* in: mtr */
-/*****************************************************************
-Moves record list end to another page. Moved records include
-split_rec. */
-
-void
-page_move_rec_list_end(
-/*===================*/
- page_t* new_page, /* in: index page where to move */
- page_t* page, /* in: index page */
- rec_t* split_rec, /* in: first record to move */
- dict_index_t* index, /* in: record descriptor */
- mtr_t* mtr); /* in: mtr */
-/*****************************************************************
-Moves record list start to another page. Moved records do not include
-split_rec. */
-
-void
-page_move_rec_list_start(
-/*=====================*/
- page_t* new_page, /* in: index page where to move */
- page_t* page, /* in: index page */
- rec_t* split_rec, /* in: first record not to move */
- dict_index_t* index, /* in: record descriptor */
- mtr_t* mtr); /* in: mtr */
-/********************************************************************
-Splits a directory slot which owns too many records. */
-
-void
-page_dir_split_slot(
-/*================*/
- page_t* page, /* in: the index page in question */
- ulint slot_no); /* in: the directory slot */
-/*****************************************************************
-Tries to balance the given directory slot with too few records
-with the upper neighbor, so that there are at least the minimum number
-of records owned by the slot; this may result in the merging of
-two slots. */
-
-void
-page_dir_balance_slot(
-/*==================*/
- page_t* page, /* in: index page */
- ulint slot_no); /* in: the directory slot */
-/**************************************************************
-Parses a log record of a record list end or start deletion. */
-
-byte*
-page_parse_delete_rec_list(
-/*=======================*/
- /* out: end of log record or NULL */
- byte type, /* in: MLOG_LIST_END_DELETE,
- MLOG_LIST_START_DELETE,
- MLOG_COMP_LIST_END_DELETE or
- MLOG_COMP_LIST_START_DELETE */
- byte* ptr, /* in: buffer */
- byte* end_ptr,/* in: buffer end */
- dict_index_t* index, /* in: record descriptor */
- page_t* page, /* in: page or NULL */
- mtr_t* mtr); /* in: mtr or NULL */
-/***************************************************************
-Parses a redo log record of creating a page. */
-
-byte*
-page_parse_create(
-/*==============*/
- /* out: end of log record or NULL */
- byte* ptr, /* in: buffer */
- byte* end_ptr,/* in: buffer end */
- ulint comp, /* in: nonzero=compact page format */
- page_t* page, /* in: page or NULL */
- mtr_t* mtr); /* in: mtr or NULL */
-/****************************************************************
-Prints record contents including the data relevant only in
-the index page context. */
-
-void
-page_rec_print(
-/*===========*/
- rec_t* rec, /* in: physical record */
- const ulint* offsets);/* in: record descriptor */
-/*******************************************************************
-This is used to print the contents of the directory for
-debugging purposes. */
-
-void
-page_dir_print(
-/*===========*/
- page_t* page, /* in: index page */
- ulint pr_n); /* in: print n first and n last entries */
-/*******************************************************************
-This is used to print the contents of the page record list for
-debugging purposes. */
-
-void
-page_print_list(
-/*============*/
- page_t* page, /* in: index page */
- dict_index_t* index, /* in: dictionary index of the page */
- ulint pr_n); /* in: print n first and n last entries */
-/*******************************************************************
-Prints the info in a page header. */
-
-void
-page_header_print(
-/*==============*/
- page_t* page);
-/*******************************************************************
-This is used to print the contents of the page for
-debugging purposes. */
-
-void
-page_print(
-/*=======*/
- page_t* page, /* in: index page */
- dict_index_t* index, /* in: dictionary index of the page */
- ulint dn, /* in: print dn first and last entries
- in directory */
- ulint rn); /* in: print rn first and last records
- in directory */
-/*******************************************************************
-The following is used to validate a record on a page. This function
-differs from rec_validate as it can also check the n_owned field and
-the heap_no field. */
-
-ibool
-page_rec_validate(
-/*==============*/
- /* out: TRUE if ok */
- rec_t* rec, /* in: physical record */
- const ulint* offsets);/* in: array returned by rec_get_offsets() */
-/*******************************************************************
-Checks that the first directory slot points to the infimum record and
-the last to the supremum. This function is intended to track if the
-bug fixed in 4.0.14 has caused corruption to users' databases. */
-
-void
-page_check_dir(
-/*===========*/
- page_t* page); /* in: index page */
-/*******************************************************************
-This function checks the consistency of an index page when we do not
-know the index. This is also resilient so that this should never crash
-even if the page is total garbage. */
-
-ibool
-page_simple_validate(
-/*=================*/
- /* out: TRUE if ok */
- page_t* page); /* in: index page */
-/*******************************************************************
-This function checks the consistency of an index page. */
-
-ibool
-page_validate(
-/*==========*/
- /* out: TRUE if ok */
- page_t* page, /* in: index page */
- dict_index_t* index); /* in: data dictionary index containing
- the page record type definition */
-/*******************************************************************
-Looks in the page record list for a record with the given heap number. */
-
-rec_t*
-page_find_rec_with_heap_no(
-/*=======================*/
- /* out: record, NULL if not found */
- page_t* page, /* in: index page */
- ulint heap_no);/* in: heap number */
-
-#ifdef UNIV_MATERIALIZE
-#undef UNIV_INLINE
-#define UNIV_INLINE UNIV_INLINE_ORIGINAL
-#endif
-
-#ifndef UNIV_NONINL
-#include "page0page.ic"
-#endif
-
-#endif
diff --git a/storage/innobase/include/page0page.ic b/storage/innobase/include/page0page.ic
deleted file mode 100644
index d9e67f3eeeb..00000000000
--- a/storage/innobase/include/page0page.ic
+++ /dev/null
@@ -1,851 +0,0 @@
-/******************************************************
-Index page routines
-
-(c) 1994-1996 Innobase Oy
-
-Created 2/2/1994 Heikki Tuuri
-*******************************************************/
-
-#include "mach0data.h"
-#include "rem0cmp.h"
-#include "mtr0log.h"
-
-#ifdef UNIV_MATERIALIZE
-#undef UNIV_INLINE
-#define UNIV_INLINE
-#endif
-
-/****************************************************************
-Gets the start of a page. */
-UNIV_INLINE
-page_t*
-page_align(
-/*=======*/
- /* out: start of the page */
- void* ptr) /* in: pointer to page frame */
-{
- return((page_t*) ut_align_down(ptr, UNIV_PAGE_SIZE));
-}
-/****************************************************************
-Gets the offset within a page. */
-UNIV_INLINE
-ulint
-page_offset(
-/*========*/
- /* out: offset from the start of the page */
- const void* ptr) /* in: pointer to page frame */
-{
- return(ut_align_offset(ptr, UNIV_PAGE_SIZE));
-}
-/*****************************************************************
-Returns the max trx id field value. */
-UNIV_INLINE
-dulint
-page_get_max_trx_id(
-/*================*/
- page_t* page) /* in: page */
-{
- ut_ad(page);
-
- return(mach_read_from_8(page + PAGE_HEADER + PAGE_MAX_TRX_ID));
-}
-
-/*****************************************************************
-Sets the max trx id field value if trx_id is bigger than the previous
-value. */
-UNIV_INLINE
-void
-page_update_max_trx_id(
-/*===================*/
- page_t* page, /* in: page */
- dulint trx_id) /* in: transaction id */
-{
- ut_ad(page);
-
- if (ut_dulint_cmp(page_get_max_trx_id(page), trx_id) < 0) {
-
- page_set_max_trx_id(page, trx_id);
- }
-}
-
-/*****************************************************************
-Reads the given header field. */
-UNIV_INLINE
-ulint
-page_header_get_field(
-/*==================*/
- page_t* page, /* in: page */
- ulint field) /* in: PAGE_LEVEL, ... */
-{
- ut_ad(page);
- ut_ad(field <= PAGE_INDEX_ID);
-
- return(mach_read_from_2(page + PAGE_HEADER + field));
-}
-
-/*****************************************************************
-Sets the given header field. */
-UNIV_INLINE
-void
-page_header_set_field(
-/*==================*/
- page_t* page, /* in: page */
- ulint field, /* in: PAGE_LEVEL, ... */
- ulint val) /* in: value */
-{
- ut_ad(page);
- ut_ad(field <= PAGE_N_RECS);
- ut_ad(field == PAGE_N_HEAP || val < UNIV_PAGE_SIZE);
- ut_ad(field != PAGE_N_HEAP || (val & 0x7fff) < UNIV_PAGE_SIZE);
-
- mach_write_to_2(page + PAGE_HEADER + field, val);
-}
-
-/*****************************************************************
-Returns the pointer stored in the given header field. */
-UNIV_INLINE
-byte*
-page_header_get_ptr(
-/*================*/
- /* out: pointer or NULL */
- page_t* page, /* in: page */
- ulint field) /* in: PAGE_FREE, ... */
-{
- ulint offs;
-
- ut_ad(page);
- ut_ad((field == PAGE_FREE)
- || (field == PAGE_LAST_INSERT)
- || (field == PAGE_HEAP_TOP));
-
- offs = page_header_get_field(page, field);
-
- ut_ad((field != PAGE_HEAP_TOP) || offs);
-
- if (offs == 0) {
-
- return(NULL);
- }
-
- return(page + offs);
-}
-
-/*****************************************************************
-Sets the pointer stored in the given header field. */
-UNIV_INLINE
-void
-page_header_set_ptr(
-/*================*/
- page_t* page, /* in: page */
- ulint field, /* in: PAGE_FREE, ... */
- byte* ptr) /* in: pointer or NULL*/
-{
- ulint offs;
-
- ut_ad(page);
- ut_ad((field == PAGE_FREE)
- || (field == PAGE_LAST_INSERT)
- || (field == PAGE_HEAP_TOP));
-
- if (ptr == NULL) {
- offs = 0;
- } else {
- offs = ptr - page;
- }
-
- ut_ad((field != PAGE_HEAP_TOP) || offs);
-
- page_header_set_field(page, field, offs);
-}
-
-/*****************************************************************
-Resets the last insert info field in the page header. Writes to mlog
-about this operation. */
-UNIV_INLINE
-void
-page_header_reset_last_insert(
-/*==========================*/
- page_t* page, /* in: page */
- mtr_t* mtr) /* in: mtr */
-{
- ut_ad(page && mtr);
-
- mlog_write_ulint(page + PAGE_HEADER + PAGE_LAST_INSERT, 0,
- MLOG_2BYTES, mtr);
-}
-
-/****************************************************************
-Determine whether the page is in new-style compact format. */
-UNIV_INLINE
-ulint
-page_is_comp(
-/*=========*/
- /* out: nonzero if the page is in compact
- format, zero if it is in old-style format */
- page_t* page) /* in: index page */
-{
- return(UNIV_EXPECT(page_header_get_field(page, PAGE_N_HEAP) & 0x8000,
- 0x8000));
-}
-
-/****************************************************************
-TRUE if the record is on a page in compact format. */
-UNIV_INLINE
-ulint
-page_rec_is_comp(
-/*=============*/
- /* out: nonzero if in compact format */
- const rec_t* rec) /* in: record */
-{
- return(page_is_comp(page_align((rec_t*) rec)));
-}
-
-/****************************************************************
-Gets the first record on the page. */
-UNIV_INLINE
-rec_t*
-page_get_infimum_rec(
-/*=================*/
- /* out: the first record in record list */
- page_t* page) /* in: page which must have record(s) */
-{
- ut_ad(page);
-
- if (page_is_comp(page)) {
- return(page + PAGE_NEW_INFIMUM);
- } else {
- return(page + PAGE_OLD_INFIMUM);
- }
-}
-
-/****************************************************************
-Gets the last record on the page. */
-UNIV_INLINE
-rec_t*
-page_get_supremum_rec(
-/*==================*/
- /* out: the last record in record list */
- page_t* page) /* in: page which must have record(s) */
-{
- ut_ad(page);
-
- if (page_is_comp(page)) {
- return(page + PAGE_NEW_SUPREMUM);
- } else {
- return(page + PAGE_OLD_SUPREMUM);
- }
-}
-
-/****************************************************************
-TRUE if the record is a user record on the page. */
-UNIV_INLINE
-ibool
-page_rec_is_user_rec_low(
-/*=====================*/
- /* out: TRUE if a user record */
- ulint offset) /* in: record offset on page */
-{
- ut_ad(offset >= PAGE_NEW_INFIMUM);
-#if PAGE_OLD_INFIMUM < PAGE_NEW_INFIMUM
-# error "PAGE_OLD_INFIMUM < PAGE_NEW_INFIMUM"
-#endif
-#if PAGE_OLD_SUPREMUM < PAGE_NEW_SUPREMUM
-# error "PAGE_OLD_SUPREMUM < PAGE_NEW_SUPREMUM"
-#endif
-#if PAGE_NEW_INFIMUM > PAGE_OLD_SUPREMUM
-# error "PAGE_NEW_INFIMUM > PAGE_OLD_SUPREMUM"
-#endif
-#if PAGE_OLD_INFIMUM > PAGE_NEW_SUPREMUM
-# error "PAGE_OLD_INFIMUM > PAGE_NEW_SUPREMUM"
-#endif
-#if PAGE_NEW_SUPREMUM > PAGE_OLD_SUPREMUM_END
-# error "PAGE_NEW_SUPREMUM > PAGE_OLD_SUPREMUM_END"
-#endif
-#if PAGE_OLD_SUPREMUM > PAGE_NEW_SUPREMUM_END
-# error "PAGE_OLD_SUPREMUM > PAGE_NEW_SUPREMUM_END"
-#endif
- ut_ad(offset <= UNIV_PAGE_SIZE - PAGE_EMPTY_DIR_START);
-
- return(UNIV_LIKELY(offset != PAGE_NEW_SUPREMUM)
- && UNIV_LIKELY(offset != PAGE_NEW_INFIMUM)
- && UNIV_LIKELY(offset != PAGE_OLD_INFIMUM)
- && UNIV_LIKELY(offset != PAGE_OLD_SUPREMUM));
-}
-
-/****************************************************************
-TRUE if the record is the supremum record on a page. */
-UNIV_INLINE
-ibool
-page_rec_is_supremum_low(
-/*=====================*/
- /* out: TRUE if the supremum record */
- ulint offset) /* in: record offset on page */
-{
- ut_ad(offset >= PAGE_NEW_INFIMUM);
- ut_ad(offset <= UNIV_PAGE_SIZE - PAGE_EMPTY_DIR_START);
-
- return(UNIV_UNLIKELY(offset == PAGE_NEW_SUPREMUM)
- || UNIV_UNLIKELY(offset == PAGE_OLD_SUPREMUM));
-}
-
-/****************************************************************
-TRUE if the record is the infimum record on a page. */
-UNIV_INLINE
-ibool
-page_rec_is_infimum_low(
-/*====================*/
- /* out: TRUE if the infimum record */
- ulint offset) /* in: record offset on page */
-{
- ut_ad(offset >= PAGE_NEW_INFIMUM);
- ut_ad(offset <= UNIV_PAGE_SIZE - PAGE_EMPTY_DIR_START);
-
- return(UNIV_UNLIKELY(offset == PAGE_NEW_INFIMUM)
- || UNIV_UNLIKELY(offset == PAGE_OLD_INFIMUM));
-}
-
-/****************************************************************
-TRUE if the record is a user record on the page. */
-UNIV_INLINE
-ibool
-page_rec_is_user_rec(
-/*=================*/
- /* out: TRUE if a user record */
- const rec_t* rec) /* in: record */
-{
- return(page_rec_is_user_rec_low(page_offset(rec)));
-}
-
-/****************************************************************
-TRUE if the record is the supremum record on a page. */
-UNIV_INLINE
-ibool
-page_rec_is_supremum(
-/*=================*/
- /* out: TRUE if the supremum record */
- const rec_t* rec) /* in: record */
-{
- return(page_rec_is_supremum_low(page_offset(rec)));
-}
-
-/****************************************************************
-TRUE if the record is the infimum record on a page. */
-UNIV_INLINE
-ibool
-page_rec_is_infimum(
-/*================*/
- /* out: TRUE if the infimum record */
- const rec_t* rec) /* in: record */
-{
- return(page_rec_is_infimum_low(page_offset(rec)));
-}
-
-/*****************************************************************
-Compares a data tuple to a physical record. Differs from the function
-cmp_dtuple_rec_with_match in the way that the record must reside on an
-index page, and also page infimum and supremum records can be given in
-the parameter rec. These are considered as the negative infinity and
-the positive infinity in the alphabetical order. */
-UNIV_INLINE
-int
-page_cmp_dtuple_rec_with_match(
-/*===========================*/
- /* out: 1, 0, -1, if dtuple is greater, equal,
- less than rec, respectively, when only the
- common first fields are compared */
- dtuple_t* dtuple, /* in: data tuple */
- rec_t* rec, /* in: physical record on a page; may also
- be page infimum or supremum, in which case
- matched-parameter values below are not
- affected */
- const ulint* offsets,/* in: array returned by rec_get_offsets() */
- ulint* matched_fields, /* in/out: number of already completely
- matched fields; when function returns
- contains the value for current comparison */
- ulint* matched_bytes) /* in/out: number of already matched
- bytes within the first field not completely
- matched; when function returns contains the
- value for current comparison */
-{
- ulint rec_offset;
-
- ut_ad(dtuple_check_typed(dtuple));
- ut_ad(rec_offs_validate(rec, NULL, offsets));
- ut_ad(!rec_offs_comp(offsets) == !page_rec_is_comp(rec));
-
- rec_offset = page_offset(rec);
-
- if (UNIV_UNLIKELY(rec_offset == PAGE_NEW_INFIMUM)
- || UNIV_UNLIKELY(rec_offset == PAGE_OLD_INFIMUM)) {
- return(1);
- }
- if (UNIV_UNLIKELY(rec_offset == PAGE_NEW_SUPREMUM)
- || UNIV_UNLIKELY(rec_offset == PAGE_OLD_SUPREMUM)) {
- return(-1);
- }
-
- return(cmp_dtuple_rec_with_match(dtuple, rec, offsets,
- matched_fields,
- matched_bytes));
-}
-
-/*****************************************************************
-Gets the number of user records on page (infimum and supremum records
-are not user records). */
-UNIV_INLINE
-ulint
-page_get_n_recs(
-/*============*/
- /* out: number of user records */
- page_t* page) /* in: index page */
-{
- return(page_header_get_field(page, PAGE_N_RECS));
-}
-
-/*****************************************************************
-Gets the number of dir slots in directory. */
-UNIV_INLINE
-ulint
-page_dir_get_n_slots(
-/*=================*/
- /* out: number of slots */
- page_t* page) /* in: index page */
-{
- return(page_header_get_field(page, PAGE_N_DIR_SLOTS));
-}
-/*****************************************************************
-Sets the number of dir slots in directory. */
-UNIV_INLINE
-void
-page_dir_set_n_slots(
-/*=================*/
- /* out: number of slots */
- page_t* page, /* in: index page */
- ulint n_slots)/* in: number of slots */
-{
- page_header_set_field(page, PAGE_N_DIR_SLOTS, n_slots);
-}
-
-/*****************************************************************
-Gets the number of records in the heap. */
-UNIV_INLINE
-ulint
-page_dir_get_n_heap(
-/*================*/
- /* out: number of user records */
- page_t* page) /* in: index page */
-{
- return(page_header_get_field(page, PAGE_N_HEAP) & 0x7fff);
-}
-
-/*****************************************************************
-Sets the number of records in the heap. */
-UNIV_INLINE
-void
-page_dir_set_n_heap(
-/*================*/
- page_t* page, /* in: index page */
- ulint n_heap) /* in: number of records */
-{
- ut_ad(n_heap < 0x8000);
-
- page_header_set_field(page, PAGE_N_HEAP, n_heap
- | (0x8000
- & page_header_get_field(page, PAGE_N_HEAP)));
-}
-
-/*****************************************************************
-Gets pointer to nth directory slot. */
-UNIV_INLINE
-page_dir_slot_t*
-page_dir_get_nth_slot(
-/*==================*/
- /* out: pointer to dir slot */
- page_t* page, /* in: index page */
- ulint n) /* in: position */
-{
- ut_ad(page_dir_get_n_slots(page) > n);
-
- return(page + UNIV_PAGE_SIZE - PAGE_DIR
- - (n + 1) * PAGE_DIR_SLOT_SIZE);
-}
-
-/******************************************************************
-Used to check the consistency of a record on a page. */
-UNIV_INLINE
-ibool
-page_rec_check(
-/*===========*/
- /* out: TRUE if succeed */
- rec_t* rec) /* in: record */
-{
- page_t* page;
-
- ut_a(rec);
-
- page = buf_frame_align(rec);
-
- ut_a(rec <= page_header_get_ptr(page, PAGE_HEAP_TOP));
- ut_a(rec >= page + PAGE_DATA);
-
- return(TRUE);
-}
-
-/*******************************************************************
-Gets the record pointed to by a directory slot. */
-UNIV_INLINE
-rec_t*
-page_dir_slot_get_rec(
-/*==================*/
- /* out: pointer to record */
- page_dir_slot_t* slot) /* in: directory slot */
-{
- return(buf_frame_align(slot) + mach_read_from_2(slot));
-}
-
-/*******************************************************************
-This is used to set the record offset in a directory slot. */
-UNIV_INLINE
-void
-page_dir_slot_set_rec(
-/*==================*/
- page_dir_slot_t* slot, /* in: directory slot */
- rec_t* rec) /* in: record on the page */
-{
- ut_ad(page_rec_check(rec));
-
- mach_write_to_2(slot, page_offset(rec));
-}
-
-/*******************************************************************
-Gets the number of records owned by a directory slot. */
-UNIV_INLINE
-ulint
-page_dir_slot_get_n_owned(
-/*======================*/
- /* out: number of records */
- page_dir_slot_t* slot) /* in: page directory slot */
-{
- rec_t* rec = page_dir_slot_get_rec(slot);
- return(rec_get_n_owned(rec, page_rec_is_comp(rec)));
-}
-
-/*******************************************************************
-This is used to set the owned records field of a directory slot. */
-UNIV_INLINE
-void
-page_dir_slot_set_n_owned(
-/*======================*/
- page_dir_slot_t* slot, /* in: directory slot */
- ulint n) /* in: number of records owned
- by the slot */
-{
- rec_t* rec = page_dir_slot_get_rec(slot);
- rec_set_n_owned(rec, page_rec_is_comp(rec), n);
-}
-
-/****************************************************************
-Calculates the space reserved for directory slots of a given number of
-records. The exact value is a fraction number n * PAGE_DIR_SLOT_SIZE /
-PAGE_DIR_SLOT_MIN_N_OWNED, and it is rounded upwards to an integer. */
-UNIV_INLINE
-ulint
-page_dir_calc_reserved_space(
-/*=========================*/
- ulint n_recs) /* in: number of records */
-{
- return((PAGE_DIR_SLOT_SIZE * n_recs + PAGE_DIR_SLOT_MIN_N_OWNED - 1)
- / PAGE_DIR_SLOT_MIN_N_OWNED);
-}
-
-/****************************************************************
-Gets the pointer to the next record on the page. */
-UNIV_INLINE
-rec_t*
-page_rec_get_next(
-/*==============*/
- /* out: pointer to next record */
- rec_t* rec) /* in: pointer to record */
-{
- ulint offs;
- page_t* page;
-
- ut_ad(page_rec_check(rec));
-
- page = page_align(rec);
-
- offs = rec_get_next_offs(rec, page_is_comp(page));
-
- if (UNIV_UNLIKELY(offs >= UNIV_PAGE_SIZE)) {
- fprintf(stderr,
- "InnoDB: Next record offset is nonsensical %lu"
- " in record at offset %lu\n"
- "InnoDB: rec address %p, first buffer frame %p\n"
- "InnoDB: buffer pool high end %p, buf fix count %lu\n",
- (ulong)offs, (ulong)(rec - page),
- (void*) rec, (void*) buf_pool->frame_zero,
- (void*) buf_pool->high_end,
- (ulong) buf_block_align(rec)->buf_fix_count);
- buf_page_print(page);
-
- ut_error;
- }
-
- if (UNIV_UNLIKELY(offs == 0)) {
-
- return(NULL);
- }
-
- return(page + offs);
-}
-
-/****************************************************************
-Sets the pointer to the next record on the page. */
-UNIV_INLINE
-void
-page_rec_set_next(
-/*==============*/
- rec_t* rec, /* in: pointer to record, must not be page supremum */
- rec_t* next) /* in: pointer to next record, must not be page
- infimum */
-{
- page_t* page;
- ulint offs;
-
- ut_ad(page_rec_check(rec));
- ut_ad(!page_rec_is_supremum(rec));
- page = page_align(rec);
-
- if (next) {
- ut_ad(!page_rec_is_infimum(next));
- ut_ad(page == page_align(next));
- offs = (ulint) (next - page);
- } else {
- offs = 0;
- }
-
- rec_set_next_offs(rec, page_is_comp(page), offs);
-}
-
-/****************************************************************
-Gets the pointer to the previous record. */
-UNIV_INLINE
-rec_t*
-page_rec_get_prev(
-/*==============*/
- /* out: pointer to previous record */
- rec_t* rec) /* in: pointer to record, must not be page
- infimum */
-{
- page_dir_slot_t* slot;
- ulint slot_no;
- rec_t* rec2;
- rec_t* prev_rec = NULL;
- page_t* page;
-
- ut_ad(page_rec_check(rec));
-
- page = page_align(rec);
-
- ut_ad(!page_rec_is_infimum(rec));
-
- slot_no = page_dir_find_owner_slot(rec);
-
- ut_a(slot_no != 0);
-
- slot = page_dir_get_nth_slot(page, slot_no - 1);
-
- rec2 = page_dir_slot_get_rec(slot);
-
- while (rec != rec2) {
- prev_rec = rec2;
- rec2 = page_rec_get_next(rec2);
- }
-
- ut_a(prev_rec);
-
- return(prev_rec);
-}
-
-/*******************************************************************
-Looks for the record which owns the given record. */
-UNIV_INLINE
-rec_t*
-page_rec_find_owner_rec(
-/*====================*/
- /* out: the owner record */
- rec_t* rec) /* in: the physical record */
-{
- ut_ad(page_rec_check(rec));
-
- if (page_rec_is_comp(rec)) {
- while (rec_get_n_owned(rec, TRUE) == 0) {
- rec = page_rec_get_next(rec);
- }
- } else {
- while (rec_get_n_owned(rec, FALSE) == 0) {
- rec = page_rec_get_next(rec);
- }
- }
-
- return(rec);
-}
-
-/****************************************************************
-Returns the sum of the sizes of the records in the record list, excluding
-the infimum and supremum records. */
-UNIV_INLINE
-ulint
-page_get_data_size(
-/*===============*/
- /* out: data in bytes */
- page_t* page) /* in: index page */
-{
- ulint ret;
-
- ret = (ulint)(page_header_get_field(page, PAGE_HEAP_TOP)
- - (page_is_comp(page)
- ? PAGE_NEW_SUPREMUM_END
- : PAGE_OLD_SUPREMUM_END)
- - page_header_get_field(page, PAGE_GARBAGE));
-
- ut_ad(ret < UNIV_PAGE_SIZE);
-
- return(ret);
-}
-
-/*****************************************************************
-Calculates free space if a page is emptied. */
-UNIV_INLINE
-ulint
-page_get_free_space_of_empty(
-/*=========================*/
- /* out: free space */
- ulint comp) /* in: nonzero=compact page layout */
-{
- if (UNIV_LIKELY(comp)) {
- return((ulint)(UNIV_PAGE_SIZE
- - PAGE_NEW_SUPREMUM_END
- - PAGE_DIR
- - 2 * PAGE_DIR_SLOT_SIZE));
- }
-
- return((ulint)(UNIV_PAGE_SIZE
- - PAGE_OLD_SUPREMUM_END
- - PAGE_DIR
- - 2 * PAGE_DIR_SLOT_SIZE));
-}
-
-/****************************************************************
-Each user record on a page, and also the deleted user records in the heap
-takes its size plus the fraction of the dir cell size /
-PAGE_DIR_SLOT_MIN_N_OWNED bytes for it. If the sum of these exceeds the
-value of page_get_free_space_of_empty, the insert is impossible, otherwise
-it is allowed. This function returns the maximum combined size of records
-which can be inserted on top of the record heap. */
-UNIV_INLINE
-ulint
-page_get_max_insert_size(
-/*=====================*/
- /* out: maximum combined size for inserted records */
- page_t* page, /* in: index page */
- ulint n_recs) /* in: number of records */
-{
- ulint occupied;
- ulint free_space;
-
- if (page_is_comp(page)) {
- occupied = page_header_get_field(page, PAGE_HEAP_TOP)
- - PAGE_NEW_SUPREMUM_END
- + page_dir_calc_reserved_space(
- n_recs + page_dir_get_n_heap(page) - 2);
-
- free_space = page_get_free_space_of_empty(TRUE);
- } else {
- occupied = page_header_get_field(page, PAGE_HEAP_TOP)
- - PAGE_OLD_SUPREMUM_END
- + page_dir_calc_reserved_space(
- n_recs + page_dir_get_n_heap(page) - 2);
-
- free_space = page_get_free_space_of_empty(FALSE);
- }
-
- /* Above the 'n_recs +' part reserves directory space for the new
- inserted records; the '- 2' excludes page infimum and supremum
- records */
-
- if (occupied > free_space) {
-
- return(0);
- }
-
- return(free_space - occupied);
-}
-
-/****************************************************************
-Returns the maximum combined size of records which can be inserted on top
-of the record heap if a page is first reorganized. */
-UNIV_INLINE
-ulint
-page_get_max_insert_size_after_reorganize(
-/*======================================*/
- /* out: maximum combined size for inserted records */
- page_t* page, /* in: index page */
- ulint n_recs) /* in: number of records */
-{
- ulint occupied;
- ulint free_space;
-
- occupied = page_get_data_size(page)
- + page_dir_calc_reserved_space(n_recs + page_get_n_recs(page));
-
- free_space = page_get_free_space_of_empty(page_is_comp(page));
-
- if (occupied > free_space) {
-
- return(0);
- }
-
- return(free_space - occupied);
-}
-
-/****************************************************************
-Puts a record to free list. */
-UNIV_INLINE
-void
-page_mem_free(
-/*==========*/
- page_t* page, /* in: index page */
- rec_t* rec, /* in: pointer to the (origin of) record */
- const ulint* offsets)/* in: array returned by rec_get_offsets() */
-{
- rec_t* free;
- ulint garbage;
-
- ut_ad(rec_offs_validate(rec, NULL, offsets));
- ut_ad(!rec_offs_comp(offsets) == !page_rec_is_comp(rec));
- free = page_header_get_ptr(page, PAGE_FREE);
-
- page_rec_set_next(rec, free);
- page_header_set_ptr(page, PAGE_FREE, rec);
-
-#if 0 /* It's better not to destroy the user's data. */
-
- /* Clear the data bytes of the deleted record in order to improve
- the compression ratio of the page and to make it easier to read
- page dumps in corruption reports. The extra bytes of the record
- cannot be cleared, because page_mem_alloc() needs them in order
- to determine the size of the deleted record. */
- memset(rec, 0, rec_offs_data_size(offsets));
-#endif
-
- garbage = page_header_get_field(page, PAGE_GARBAGE);
-
- page_header_set_field(page, PAGE_GARBAGE,
- garbage + rec_offs_size(offsets));
-}
-
-#ifdef UNIV_MATERIALIZE
-#undef UNIV_INLINE
-#define UNIV_INLINE UNIV_INLINE_ORIGINAL
-#endif
diff --git a/storage/innobase/include/page0types.h b/storage/innobase/include/page0types.h
deleted file mode 100644
index 1fbeeb0f60f..00000000000
--- a/storage/innobase/include/page0types.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/******************************************************
-Index page routines
-
-(c) 1994-1996 Innobase Oy
-
-Created 2/2/1994 Heikki Tuuri
-*******************************************************/
-
-#ifndef page0types_h
-#define page0types_h
-
-#include "univ.i"
-
-/* Type of the index page */
-/* The following define eliminates a name collision on HP-UX */
-#define page_t ib_page_t
-typedef byte page_t;
-typedef struct page_search_struct page_search_t;
-typedef struct page_cur_struct page_cur_t;
-
-
-#endif
diff --git a/storage/innobase/include/pars0opt.h b/storage/innobase/include/pars0opt.h
deleted file mode 100644
index ff92cc062d9..00000000000
--- a/storage/innobase/include/pars0opt.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/******************************************************
-Simple SQL optimizer
-
-(c) 1997 Innobase Oy
-
-Created 12/21/1997 Heikki Tuuri
-*******************************************************/
-
-#ifndef pars0opt_h
-#define pars0opt_h
-
-#include "univ.i"
-#include "que0types.h"
-#include "usr0types.h"
-#include "pars0sym.h"
-#include "dict0types.h"
-#include "row0sel.h"
-
-/***********************************************************************
-Optimizes a select. Decides which indexes to tables to use. The tables
-are accessed in the order that they were written to the FROM part in the
-select statement. */
-
-void
-opt_search_plan(
-/*============*/
- sel_node_t* sel_node); /* in: parsed select node */
-/***********************************************************************
-Looks for occurrences of the columns of the table in the query subgraph and
-adds them to the list of columns if an occurrence of the same column does not
-already exist in the list. If the column is already in the list, puts a value
-indirection to point to the occurrence in the column list, except if the
-column occurrence we are looking at is in the column list, in which case
-nothing is done. */
-
-void
-opt_find_all_cols(
-/*==============*/
- ibool copy_val, /* in: if TRUE, new found columns are
- added as columns to copy */
- dict_index_t* index, /* in: index to use */
- sym_node_list_t* col_list, /* in: base node of a list where
- to add new found columns */
- plan_t* plan, /* in: plan or NULL */
- que_node_t* exp); /* in: expression or condition */
-/************************************************************************
-Prints info of a query plan. */
-
-void
-opt_print_query_plan(
-/*=================*/
- sel_node_t* sel_node); /* in: select node */
-
-#ifndef UNIV_NONINL
-#include "pars0opt.ic"
-#endif
-
-#endif
diff --git a/storage/innobase/include/pars0opt.ic b/storage/innobase/include/pars0opt.ic
deleted file mode 100644
index 0bfa8526bee..00000000000
--- a/storage/innobase/include/pars0opt.ic
+++ /dev/null
@@ -1,7 +0,0 @@
-/******************************************************
-Simple SQL optimizer
-
-(c) 1997 Innobase Oy
-
-Created 12/21/1997 Heikki Tuuri
-*******************************************************/
diff --git a/storage/innobase/include/pars0pars.h b/storage/innobase/include/pars0pars.h
deleted file mode 100644
index 1c6c550d313..00000000000
--- a/storage/innobase/include/pars0pars.h
+++ /dev/null
@@ -1,731 +0,0 @@
-/******************************************************
-SQL parser
-
-(c) 1996 Innobase Oy
-
-Created 11/19/1996 Heikki Tuuri
-*******************************************************/
-
-#ifndef pars0pars_h
-#define pars0pars_h
-
-#include "univ.i"
-#include "que0types.h"
-#include "usr0types.h"
-#include "pars0types.h"
-#include "row0types.h"
-#include "trx0types.h"
-#include "ut0vec.h"
-
-/* Type of the user functions. The first argument is always InnoDB-supplied
-and varies in type, while 'user_arg' is a user-supplied argument. The
-meaning of the return type also varies. See the individual use cases, e.g.
-the FETCH statement, for details on them. */
-typedef void* (*pars_user_func_cb_t)(void* arg, void* user_arg);
-
-extern int yydebug;
-
-/* If the following is set TRUE, the lexer will print the SQL string
-as it tokenizes it */
-
-#ifdef UNIV_SQL_DEBUG
-extern ibool pars_print_lexed;
-#endif /* UNIV_SQL_DEBUG */
-
-/* Global variable used while parsing a single procedure or query : the code is
-NOT re-entrant */
-extern sym_tab_t* pars_sym_tab_global;
-
-extern pars_res_word_t pars_to_char_token;
-extern pars_res_word_t pars_to_number_token;
-extern pars_res_word_t pars_to_binary_token;
-extern pars_res_word_t pars_binary_to_number_token;
-extern pars_res_word_t pars_substr_token;
-extern pars_res_word_t pars_replstr_token;
-extern pars_res_word_t pars_concat_token;
-extern pars_res_word_t pars_length_token;
-extern pars_res_word_t pars_instr_token;
-extern pars_res_word_t pars_sysdate_token;
-extern pars_res_word_t pars_printf_token;
-extern pars_res_word_t pars_assert_token;
-extern pars_res_word_t pars_rnd_token;
-extern pars_res_word_t pars_rnd_str_token;
-extern pars_res_word_t pars_count_token;
-extern pars_res_word_t pars_sum_token;
-extern pars_res_word_t pars_distinct_token;
-extern pars_res_word_t pars_binary_token;
-extern pars_res_word_t pars_blob_token;
-extern pars_res_word_t pars_int_token;
-extern pars_res_word_t pars_char_token;
-extern pars_res_word_t pars_float_token;
-extern pars_res_word_t pars_update_token;
-extern pars_res_word_t pars_asc_token;
-extern pars_res_word_t pars_desc_token;
-extern pars_res_word_t pars_open_token;
-extern pars_res_word_t pars_close_token;
-extern pars_res_word_t pars_share_token;
-extern pars_res_word_t pars_unique_token;
-extern pars_res_word_t pars_clustered_token;
-
-extern ulint pars_star_denoter;
-
-/* Procedure parameter types */
-#define PARS_INPUT 0
-#define PARS_OUTPUT 1
-#define PARS_NOT_PARAM 2
-
-int
-yyparse(void);
-
-/*****************************************************************
-Parses an SQL string returning the query graph. */
-
-que_t*
-pars_sql(
-/*=====*/
- /* out, own: the query graph */
- pars_info_t* info, /* in: extra information, or NULL */
- const char* str); /* in: SQL string */
-/*****************************************************************
-Retrieves characters to the lexical analyzer. */
-
-void
-pars_get_lex_chars(
-/*===============*/
- char* buf, /* in/out: buffer where to copy */
- int* result, /* out: number of characters copied or EOF */
- int max_size); /* in: maximum number of characters which fit
- in the buffer */
-/*****************************************************************
-Called by yyparse on error. */
-
-void
-yyerror(
-/*====*/
- const char* s); /* in: error message string */
-/*************************************************************************
-Parses a variable declaration. */
-
-sym_node_t*
-pars_variable_declaration(
-/*======================*/
- /* out, own: symbol table node of type
- SYM_VAR */
- sym_node_t* node, /* in: symbol table node allocated for the
- id of the variable */
- pars_res_word_t* type); /* in: pointer to a type token */
-/*************************************************************************
-Parses a function expression. */
-
-func_node_t*
-pars_func(
-/*======*/
- /* out, own: function node in a query tree */
- que_node_t* res_word,/* in: function name reserved word */
- que_node_t* arg); /* in: first argument in the argument list */
-/*************************************************************************
-Parses an operator expression. */
-
-func_node_t*
-pars_op(
-/*====*/
- /* out, own: function node in a query tree */
- int func, /* in: operator token code */
- que_node_t* arg1, /* in: first argument */
- que_node_t* arg2); /* in: second argument or NULL for an unary
- operator */
-/*************************************************************************
-Parses an ORDER BY clause. Order by a single column only is supported. */
-
-order_node_t*
-pars_order_by(
-/*==========*/
- /* out, own: order-by node in a query tree */
- sym_node_t* column, /* in: column name */
- pars_res_word_t* asc); /* in: &pars_asc_token or pars_desc_token */
-/*************************************************************************
-Parses a select list; creates a query graph node for the whole SELECT
-statement. */
-
-sel_node_t*
-pars_select_list(
-/*=============*/
- /* out, own: select node in a query
- tree */
- que_node_t* select_list, /* in: select list */
- sym_node_t* into_list); /* in: variables list or NULL */
-/*************************************************************************
-Parses a cursor declaration. */
-
-que_node_t*
-pars_cursor_declaration(
-/*====================*/
- /* out: sym_node */
- sym_node_t* sym_node, /* in: cursor id node in the symbol
- table */
- sel_node_t* select_node); /* in: select node */
-/*************************************************************************
-Parses a function declaration. */
-
-que_node_t*
-pars_function_declaration(
-/*======================*/
- /* out: sym_node */
- sym_node_t* sym_node); /* in: function id node in the symbol
- table */
-/*************************************************************************
-Parses a select statement. */
-
-sel_node_t*
-pars_select_statement(
-/*==================*/
- /* out, own: select node in a query
- tree */
- sel_node_t* select_node, /* in: select node already containing
- the select list */
- sym_node_t* table_list, /* in: table list */
- que_node_t* search_cond, /* in: search condition or NULL */
- pars_res_word_t* for_update, /* in: NULL or &pars_update_token */
- pars_res_word_t* consistent_read,/* in: NULL or
- &pars_consistent_token */
- order_node_t* order_by); /* in: NULL or an order-by node */
-/*************************************************************************
-Parses a column assignment in an update. */
-
-col_assign_node_t*
-pars_column_assignment(
-/*===================*/
- /* out: column assignment node */
- sym_node_t* column, /* in: column to assign */
- que_node_t* exp); /* in: value to assign */
-/*************************************************************************
-Parses a delete or update statement start. */
-
-upd_node_t*
-pars_update_statement_start(
-/*========================*/
- /* out, own: update node in a query
- tree */
- ibool is_delete, /* in: TRUE if delete */
- sym_node_t* table_sym, /* in: table name node */
- col_assign_node_t* col_assign_list);/* in: column assignment list, NULL
- if delete */
-/*************************************************************************
-Parses an update or delete statement. */
-
-upd_node_t*
-pars_update_statement(
-/*==================*/
- /* out, own: update node in a query
- tree */
- upd_node_t* node, /* in: update node */
- sym_node_t* cursor_sym, /* in: pointer to a cursor entry in
- the symbol table or NULL */
- que_node_t* search_cond); /* in: search condition or NULL */
-/*************************************************************************
-Parses an insert statement. */
-
-ins_node_t*
-pars_insert_statement(
-/*==================*/
- /* out, own: update node in a query
- tree */
- sym_node_t* table_sym, /* in: table name node */
- que_node_t* values_list, /* in: value expression list or NULL */
- sel_node_t* select); /* in: select condition or NULL */
-/*************************************************************************
-Parses a procedure parameter declaration. */
-
-sym_node_t*
-pars_parameter_declaration(
-/*=======================*/
- /* out, own: symbol table node of type
- SYM_VAR */
- sym_node_t* node, /* in: symbol table node allocated for the
- id of the parameter */
- ulint param_type,
- /* in: PARS_INPUT or PARS_OUTPUT */
- pars_res_word_t* type); /* in: pointer to a type token */
-/*************************************************************************
-Parses an elsif element. */
-
-elsif_node_t*
-pars_elsif_element(
-/*===============*/
- /* out: elsif node */
- que_node_t* cond, /* in: if-condition */
- que_node_t* stat_list); /* in: statement list */
-/*************************************************************************
-Parses an if-statement. */
-
-if_node_t*
-pars_if_statement(
-/*==============*/
- /* out: if-statement node */
- que_node_t* cond, /* in: if-condition */
- que_node_t* stat_list, /* in: statement list */
- que_node_t* else_part); /* in: else-part statement list */
-/*************************************************************************
-Parses a for-loop-statement. */
-
-for_node_t*
-pars_for_statement(
-/*===============*/
- /* out: for-statement node */
- sym_node_t* loop_var, /* in: loop variable */
- que_node_t* loop_start_limit,/* in: loop start expression */
- que_node_t* loop_end_limit, /* in: loop end expression */
- que_node_t* stat_list); /* in: statement list */
-/*************************************************************************
-Parses a while-statement. */
-
-while_node_t*
-pars_while_statement(
-/*=================*/
- /* out: while-statement node */
- que_node_t* cond, /* in: while-condition */
- que_node_t* stat_list); /* in: statement list */
-/*************************************************************************
-Parses an exit statement. */
-
-exit_node_t*
-pars_exit_statement(void);
-/*=====================*/
- /* out: exit statement node */
-/*************************************************************************
-Parses a return-statement. */
-
-return_node_t*
-pars_return_statement(void);
-/*=======================*/
- /* out: return-statement node */
-/*************************************************************************
-Parses a procedure call. */
-
-func_node_t*
-pars_procedure_call(
-/*================*/
- /* out: function node */
- que_node_t* res_word,/* in: procedure name reserved word */
- que_node_t* args); /* in: argument list */
-/*************************************************************************
-Parses an assignment statement. */
-
-assign_node_t*
-pars_assignment_statement(
-/*======================*/
- /* out: assignment statement node */
- sym_node_t* var, /* in: variable to assign */
- que_node_t* val); /* in: value to assign */
-/*************************************************************************
-Parses a fetch statement. into_list or user_func (but not both) must be
-non-NULL. */
-
-fetch_node_t*
-pars_fetch_statement(
-/*=================*/
- /* out: fetch statement node */
- sym_node_t* cursor, /* in: cursor node */
- sym_node_t* into_list, /* in: variables to set, or NULL */
- sym_node_t* user_func); /* in: user function name, or NULL */
-/*************************************************************************
-Parses an open or close cursor statement. */
-
-open_node_t*
-pars_open_statement(
-/*================*/
- /* out: fetch statement node */
- ulint type, /* in: ROW_SEL_OPEN_CURSOR
- or ROW_SEL_CLOSE_CURSOR */
- sym_node_t* cursor); /* in: cursor node */
-/*************************************************************************
-Parses a row_printf-statement. */
-
-row_printf_node_t*
-pars_row_printf_statement(
-/*======================*/
- /* out: row_printf-statement node */
- sel_node_t* sel_node); /* in: select node */
-/*************************************************************************
-Parses a commit statement. */
-
-commit_node_t*
-pars_commit_statement(void);
-/*=======================*/
-/*************************************************************************
-Parses a rollback statement. */
-
-roll_node_t*
-pars_rollback_statement(void);
-/*=========================*/
-/*************************************************************************
-Parses a column definition at a table creation. */
-
-sym_node_t*
-pars_column_def(
-/*============*/
- /* out: column sym table
- node */
- sym_node_t* sym_node, /* in: column node in the
- symbol table */
- pars_res_word_t* type, /* in: data type */
- sym_node_t* len, /* in: length of column, or
- NULL */
- void* is_unsigned, /* in: if not NULL, column
- is of type UNSIGNED. */
- void* is_not_null); /* in: if not NULL, column
- is of type NOT NULL. */
-/*************************************************************************
-Parses a table creation operation. */
-
-tab_node_t*
-pars_create_table(
-/*==============*/
- /* out: table create subgraph */
- sym_node_t* table_sym, /* in: table name node in the symbol
- table */
- sym_node_t* column_defs, /* in: list of column names */
- void* not_fit_in_memory);/* in: a non-NULL pointer means that
- this is a table which in simulations
- should be simulated as not fitting
- in memory; thread is put to sleep
- to simulate disk accesses; NOTE that
- this flag is not stored to the data
- dictionary on disk, and the database
- will forget about non-NULL value if
- it has to reload the table definition
- from disk */
-/*************************************************************************
-Parses an index creation operation. */
-
-ind_node_t*
-pars_create_index(
-/*==============*/
- /* out: index create subgraph */
- pars_res_word_t* unique_def, /* in: not NULL if a unique index */
- pars_res_word_t* clustered_def, /* in: not NULL if a clustered index */
- sym_node_t* index_sym, /* in: index name node in the symbol
- table */
- sym_node_t* table_sym, /* in: table name node in the symbol
- table */
- sym_node_t* column_list); /* in: list of column names */
-/*************************************************************************
-Parses a procedure definition. */
-
-que_fork_t*
-pars_procedure_definition(
-/*======================*/
- /* out: query fork node */
- sym_node_t* sym_node, /* in: procedure id node in the symbol
- table */
- sym_node_t* param_list, /* in: parameter declaration list */
- que_node_t* stat_list); /* in: statement list */
-
-/*****************************************************************
-Parses a stored procedure call, when this is not within another stored
-procedure, that is, the client issues a procedure call directly.
-In MySQL/InnoDB, stored InnoDB procedures are invoked via the
-parsed procedure tree, not via InnoDB SQL, so this function is not used. */
-
-que_fork_t*
-pars_stored_procedure_call(
-/*=======================*/
- /* out: query graph */
- sym_node_t* sym_node); /* in: stored procedure name */
-/**********************************************************************
-Completes a query graph by adding query thread and fork nodes
-above it and prepares the graph for running. The fork created is of
-type QUE_FORK_MYSQL_INTERFACE. */
-
-que_thr_t*
-pars_complete_graph_for_exec(
-/*=========================*/
- /* out: query thread node to run */
- que_node_t* node, /* in: root node for an incomplete
- query graph */
- trx_t* trx, /* in: transaction handle */
- mem_heap_t* heap); /* in: memory heap from which allocated */
-
-/********************************************************************
-Create parser info struct.*/
-
-pars_info_t*
-pars_info_create(void);
-/*==================*/
- /* out, own: info struct */
-
-/********************************************************************
-Free info struct and everything it contains.*/
-
-void
-pars_info_free(
-/*===========*/
- pars_info_t* info); /* in: info struct */
-
-/********************************************************************
-Add bound literal. */
-
-void
-pars_info_add_literal(
-/*==================*/
- pars_info_t* info, /* in: info struct */
- const char* name, /* in: name */
- const void* address, /* in: address */
- ulint length, /* in: length of data */
- ulint type, /* in: type, e.g. DATA_FIXBINARY */
- ulint prtype); /* in: precise type, e.g.
- DATA_UNSIGNED */
-
-/********************************************************************
-Equivalent to pars_info_add_literal(info, name, str, strlen(str),
-DATA_VARCHAR, DATA_ENGLISH). */
-
-void
-pars_info_add_str_literal(
-/*======================*/
- pars_info_t* info, /* in: info struct */
- const char* name, /* in: name */
- const char* str); /* in: string */
-
-/********************************************************************
-Equivalent to:
-
-char buf[4];
-mach_write_to_4(buf, val);
-pars_info_add_literal(info, name, buf, 4, DATA_INT, 0);
-
-except that the buffer is dynamically allocated from the info struct's
-heap. */
-
-void
-pars_info_add_int4_literal(
-/*=======================*/
- pars_info_t* info, /* in: info struct */
- const char* name, /* in: name */
- lint val); /* in: value */
-
-/********************************************************************
-Equivalent to:
-
-char buf[8];
-mach_write_to_8(buf, val);
-pars_info_add_literal(info, name, buf, 8, DATA_BINARY, 0);
-
-except that the buffer is dynamically allocated from the info struct's
-heap. */
-
-void
-pars_info_add_dulint_literal(
-/*=========================*/
- pars_info_t* info, /* in: info struct */
- const char* name, /* in: name */
- dulint val); /* in: value */
-/********************************************************************
-Add user function. */
-
-void
-pars_info_add_function(
-/*===================*/
- pars_info_t* info, /* in: info struct */
- const char* name, /* in: function name */
- pars_user_func_cb_t func, /* in: function address */
- void* arg); /* in: user-supplied argument */
-
-/********************************************************************
-Add bound id. */
-
-void
-pars_info_add_id(
-/*=============*/
- pars_info_t* info, /* in: info struct */
- const char* name, /* in: name */
- const char* id); /* in: id */
-
-/********************************************************************
-Get user function with the given name.*/
-
-pars_user_func_t*
-pars_info_get_user_func(
-/*====================*/
- /* out: user func, or NULL if not
- found */
- pars_info_t* info, /* in: info struct */
- const char* name); /* in: function name to find*/
-
-/********************************************************************
-Get bound literal with the given name.*/
-
-pars_bound_lit_t*
-pars_info_get_bound_lit(
-/*====================*/
- /* out: bound literal, or NULL if
- not found */
- pars_info_t* info, /* in: info struct */
- const char* name); /* in: bound literal name to find */
-
-/********************************************************************
-Get bound id with the given name.*/
-
-pars_bound_id_t*
-pars_info_get_bound_id(
-/*===================*/
- /* out: bound id, or NULL if not
- found */
- pars_info_t* info, /* in: info struct */
- const char* name); /* in: bound id name to find */
-
-
-/* Extra information supplied for pars_sql(). */
-struct pars_info_struct {
- mem_heap_t* heap; /* our own memory heap */
-
- ib_vector_t* funcs; /* user functions, or NUll
- (pars_user_func_t*) */
- ib_vector_t* bound_lits; /* bound literals, or NULL
- (pars_bound_lit_t*) */
- ib_vector_t* bound_ids; /* bound ids, or NULL
- (pars_bound_id_t*) */
-
- ibool graph_owns_us; /* if TRUE (which is the default),
- que_graph_free() will free us */
-};
-
-/* User-supplied function and argument. */
-struct pars_user_func_struct {
- const char* name; /* function name */
- pars_user_func_cb_t func; /* function address */
- void* arg; /* user-supplied argument */
-};
-
-/* Bound literal. */
-struct pars_bound_lit_struct {
- const char* name; /* name */
- const void* address; /* address */
- ulint length; /* length of data */
- ulint type; /* type, e.g. DATA_FIXBINARY */
- ulint prtype; /* precise type, e.g. DATA_UNSIGNED */
-};
-
-/* Bound id. */
-struct pars_bound_id_struct {
- const char* name; /* name */
- const char* id; /* id */
-};
-
-/* Struct used to denote a reserved word in a parsing tree */
-struct pars_res_word_struct{
- int code; /* the token code for the reserved word from
- pars0grm.h */
-};
-
-/* A predefined function or operator node in a parsing tree; this construct
-is also used for some non-functions like the assignment ':=' */
-struct func_node_struct{
- que_common_t common; /* type: QUE_NODE_FUNC */
- int func; /* token code of the function name */
- ulint class; /* class of the function */
- que_node_t* args; /* argument(s) of the function */
- UT_LIST_NODE_T(func_node_t) cond_list;
- /* list of comparison conditions; defined
- only for comparison operator nodes except,
- presently, for OPT_SCROLL_TYPE ones */
- UT_LIST_NODE_T(func_node_t) func_node_list;
- /* list of function nodes in a parsed
- query graph */
-};
-
-/* An order-by node in a select */
-struct order_node_struct{
- que_common_t common; /* type: QUE_NODE_ORDER */
- sym_node_t* column; /* order-by column */
- ibool asc; /* TRUE if ascending, FALSE if descending */
-};
-
-/* Procedure definition node */
-struct proc_node_struct{
- que_common_t common; /* type: QUE_NODE_PROC */
- sym_node_t* proc_id; /* procedure name symbol in the symbol
- table of this same procedure */
- sym_node_t* param_list; /* input and output parameters */
- que_node_t* stat_list; /* statement list */
- sym_tab_t* sym_tab; /* symbol table of this procedure */
-};
-
-/* elsif-element node */
-struct elsif_node_struct{
- que_common_t common; /* type: QUE_NODE_ELSIF */
- que_node_t* cond; /* if condition */
- que_node_t* stat_list; /* statement list */
-};
-
-/* if-statement node */
-struct if_node_struct{
- que_common_t common; /* type: QUE_NODE_IF */
- que_node_t* cond; /* if condition */
- que_node_t* stat_list; /* statement list */
- que_node_t* else_part; /* else-part statement list */
- elsif_node_t* elsif_list; /* elsif element list */
-};
-
-/* while-statement node */
-struct while_node_struct{
- que_common_t common; /* type: QUE_NODE_WHILE */
- que_node_t* cond; /* while condition */
- que_node_t* stat_list; /* statement list */
-};
-
-/* for-loop-statement node */
-struct for_node_struct{
- que_common_t common; /* type: QUE_NODE_FOR */
- sym_node_t* loop_var; /* loop variable: this is the
- dereferenced symbol from the
- variable declarations, not the
- symbol occurrence in the for loop
- definition */
- que_node_t* loop_start_limit;/* initial value of loop variable */
- que_node_t* loop_end_limit; /* end value of loop variable */
- lint loop_end_value; /* evaluated value for the end value:
- it is calculated only when the loop
- is entered, and will not change within
- the loop */
- que_node_t* stat_list; /* statement list */
-};
-
-/* exit statement node */
-struct exit_node_struct{
- que_common_t common; /* type: QUE_NODE_EXIT */
-};
-
-/* return-statement node */
-struct return_node_struct{
- que_common_t common; /* type: QUE_NODE_RETURN */
-};
-
-/* Assignment statement node */
-struct assign_node_struct{
- que_common_t common; /* type: QUE_NODE_ASSIGNMENT */
- sym_node_t* var; /* variable to set */
- que_node_t* val; /* value to assign */
-};
-
-/* Column assignment node */
-struct col_assign_node_struct{
- que_common_t common; /* type: QUE_NODE_COL_ASSIGN */
- sym_node_t* col; /* column to set */
- que_node_t* val; /* value to assign */
-};
-
-/* Classes of functions */
-#define PARS_FUNC_ARITH 1 /* +, -, *, / */
-#define PARS_FUNC_LOGICAL 2
-#define PARS_FUNC_CMP 3
-#define PARS_FUNC_PREDEFINED 4 /* TO_NUMBER, SUBSTR, ... */
-#define PARS_FUNC_AGGREGATE 5 /* COUNT, DISTINCT, SUM */
-#define PARS_FUNC_OTHER 6 /* these are not real functions,
- e.g., := */
-
-#ifndef UNIV_NONINL
-#include "pars0pars.ic"
-#endif
-
-#endif
diff --git a/storage/innobase/include/pars0pars.ic b/storage/innobase/include/pars0pars.ic
deleted file mode 100644
index 155b6659ace..00000000000
--- a/storage/innobase/include/pars0pars.ic
+++ /dev/null
@@ -1,7 +0,0 @@
-/******************************************************
-SQL parser
-
-(c) 1996 Innobase Oy
-
-Created 11/19/1996 Heikki Tuuri
-*******************************************************/
diff --git a/storage/innobase/include/pars0sym.h b/storage/innobase/include/pars0sym.h
deleted file mode 100644
index fc7df92ff60..00000000000
--- a/storage/innobase/include/pars0sym.h
+++ /dev/null
@@ -1,223 +0,0 @@
-/******************************************************
-SQL parser symbol table
-
-(c) 1997 Innobase Oy
-
-Created 12/15/1997 Heikki Tuuri
-*******************************************************/
-
-#ifndef pars0sym_h
-#define pars0sym_h
-
-#include "univ.i"
-#include "que0types.h"
-#include "usr0types.h"
-#include "dict0types.h"
-#include "pars0types.h"
-#include "row0types.h"
-
-/**********************************************************************
-Creates a symbol table for a single stored procedure or query. */
-
-sym_tab_t*
-sym_tab_create(
-/*===========*/
- /* out, own: symbol table */
- mem_heap_t* heap); /* in: memory heap where to create */
-/**********************************************************************
-Frees the memory allocated dynamically AFTER parsing phase for variables
-etc. in the symbol table. Does not free the mem heap where the table was
-originally created. Frees also SQL explicit cursor definitions. */
-
-void
-sym_tab_free_private(
-/*=================*/
- sym_tab_t* sym_tab); /* in, own: symbol table */
-/**********************************************************************
-Adds an integer literal to a symbol table. */
-
-sym_node_t*
-sym_tab_add_int_lit(
-/*================*/
- /* out: symbol table node */
- sym_tab_t* sym_tab, /* in: symbol table */
- ulint val); /* in: integer value */
-/**********************************************************************
-Adds an string literal to a symbol table. */
-
-sym_node_t*
-sym_tab_add_str_lit(
-/*================*/
- /* out: symbol table node */
- sym_tab_t* sym_tab, /* in: symbol table */
- byte* str, /* in: string with no quotes around
- it */
- ulint len); /* in: string length */
-/**********************************************************************
-Add a bound literal to a symbol table. */
-
-sym_node_t*
-sym_tab_add_bound_lit(
-/*==================*/
- /* out: symbol table node */
- sym_tab_t* sym_tab, /* in: symbol table */
- const char* name, /* in: name of bound literal */
- ulint* lit_type); /* out: type of literal (PARS_*_LIT) */
-/**********************************************************************
-Adds an SQL null literal to a symbol table. */
-
-sym_node_t*
-sym_tab_add_null_lit(
-/*=================*/
- /* out: symbol table node */
- sym_tab_t* sym_tab); /* in: symbol table */
-/**********************************************************************
-Adds an identifier to a symbol table. */
-
-sym_node_t*
-sym_tab_add_id(
-/*===========*/
- /* out: symbol table node */
- sym_tab_t* sym_tab, /* in: symbol table */
- byte* name, /* in: identifier name */
- ulint len); /* in: identifier length */
-
-/**********************************************************************
-Add a bound identifier to a symbol table. */
-
-sym_node_t*
-sym_tab_add_bound_id(
-/*===========*/
- /* out: symbol table node */
- sym_tab_t* sym_tab, /* in: symbol table */
- const char* name); /* in: name of bound id */
-
-#define SYM_CLUST_FIELD_NO 0
-#define SYM_SEC_FIELD_NO 1
-
-struct sym_node_struct{
- que_common_t common; /* node type:
- QUE_NODE_SYMBOL */
- /* NOTE: if the data field in 'common.val' is not NULL and the symbol
- table node is not for a temporary column, the memory for the value has
- been allocated from dynamic memory and it should be freed when the
- symbol table is discarded */
-
- /* 'alias' and 'indirection' are almost the same, but not quite.
- 'alias' always points to the primary instance of the variable, while
- 'indirection' does the same only if we should use the primary
- instance's values for the node's data. This is usually the case, but
- when initializing a cursor (e.g., "DECLARE CURSOR c IS SELECT * FROM
- t WHERE id = x;"), we copy the values from the primary instance to
- the cursor's instance so that they are fixed for the duration of the
- cursor, and set 'indirection' to NULL. If we did not, the value of
- 'x' could change between fetches and things would break horribly.
-
- TODO: It would be cleaner to make 'indirection' a boolean field and
- always use 'alias' to refer to the primary node. */
-
- sym_node_t* indirection; /* pointer to
- another symbol table
- node which contains
- the value for this
- node, NULL otherwise */
- sym_node_t* alias; /* pointer to
- another symbol table
- node for which this
- node is an alias,
- NULL otherwise */
- UT_LIST_NODE_T(sym_node_t) col_var_list; /* list of table
- columns or a list of
- input variables for an
- explicit cursor */
- ibool copy_val; /* TRUE if a column
- and its value should
- be copied to dynamic
- memory when fetched */
- ulint field_nos[2]; /* if a column, in
- the position
- SYM_CLUST_FIELD_NO is
- the field number in the
- clustered index; in
- the position
- SYM_SEC_FIELD_NO
- the field number in the
- non-clustered index to
- use first; if not found
- from the index, then
- ULINT_UNDEFINED */
- ibool resolved; /* TRUE if the
- meaning of a variable
- or a column has been
- resolved; for literals
- this is always TRUE */
- ulint token_type; /* SYM_VAR, SYM_COLUMN,
- SYM_IMPLICIT_VAR,
- SYM_LIT, SYM_TABLE,
- SYM_CURSOR, ... */
- const char* name; /* name of an id */
- ulint name_len; /* id name length */
- dict_table_t* table; /* table definition
- if a table id or a
- column id */
- ulint col_no; /* column number if a
- column */
- sel_buf_t* prefetch_buf; /* NULL, or a buffer
- for cached column
- values for prefetched
- rows */
- sel_node_t* cursor_def; /* cursor definition
- select node if a
- named cursor */
- ulint param_type; /* PARS_INPUT,
- PARS_OUTPUT, or
- PARS_NOT_PARAM if not a
- procedure parameter */
- sym_tab_t* sym_table; /* back pointer to
- the symbol table */
- UT_LIST_NODE_T(sym_node_t) sym_list; /* list of symbol
- nodes */
-};
-
-struct sym_tab_struct{
- que_t* query_graph;
- /* query graph generated by the
- parser */
- const char* sql_string;
- /* SQL string to parse */
- size_t string_len;
- /* SQL string length */
- int next_char_pos;
- /* position of the next character in
- sql_string to give to the lexical
- analyzer */
- pars_info_t* info; /* extra information, or NULL */
- sym_node_list_t sym_list;
- /* list of symbol nodes in the symbol
- table */
- UT_LIST_BASE_NODE_T(func_node_t)
- func_node_list;
- /* list of function nodes in the
- parsed query graph */
- mem_heap_t* heap; /* memory heap from which we can
- allocate space */
-};
-
-/* Types of a symbol table entry */
-#define SYM_VAR 91 /* declared parameter or local
- variable of a procedure */
-#define SYM_IMPLICIT_VAR 92 /* storage for a intermediate result
- of a calculation */
-#define SYM_LIT 93 /* literal */
-#define SYM_TABLE 94 /* database table name */
-#define SYM_COLUMN 95 /* database table name */
-#define SYM_CURSOR 96 /* named cursor */
-#define SYM_PROCEDURE_NAME 97 /* stored procedure name */
-#define SYM_INDEX 98 /* database index name */
-#define SYM_FUNCTION 99 /* user function name */
-
-#ifndef UNIV_NONINL
-#include "pars0sym.ic"
-#endif
-
-#endif
diff --git a/storage/innobase/include/pars0sym.ic b/storage/innobase/include/pars0sym.ic
deleted file mode 100644
index 9508d423769..00000000000
--- a/storage/innobase/include/pars0sym.ic
+++ /dev/null
@@ -1,7 +0,0 @@
-/******************************************************
-SQL parser symbol table
-
-(c) 1997 Innobase Oy
-
-Created 12/15/1997 Heikki Tuuri
-*******************************************************/
diff --git a/storage/innobase/include/que0types.h b/storage/innobase/include/que0types.h
deleted file mode 100644
index 30e3f0a172b..00000000000
--- a/storage/innobase/include/que0types.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/******************************************************
-Query graph global types
-
-(c) 1996 Innobase Oy
-
-Created 5/27/1996 Heikki Tuuri
-*******************************************************/
-
-#ifndef que0types_h
-#define que0types_h
-
-#include "data0data.h"
-#include "dict0types.h"
-
-/* Pseudotype for all graph nodes */
-typedef void que_node_t;
-
-typedef struct que_fork_struct que_fork_t;
-
-/* Query graph root is a fork node */
-typedef que_fork_t que_t;
-
-typedef struct que_thr_struct que_thr_t;
-typedef struct que_common_struct que_common_t;
-
-/* Common struct at the beginning of each query graph node; the name of this
-substruct must be 'common' */
-
-struct que_common_struct{
- ulint type; /* query node type */
- que_node_t* parent; /* back pointer to parent node, or NULL */
- que_node_t* brother;/* pointer to a possible brother node */
- dfield_t val; /* evaluated value for an expression */
- ulint val_buf_size;
- /* buffer size for the evaluated value data,
- if the buffer has been allocated dynamically:
- if this field is != 0, and the node is a
- symbol node or a function node, then we
- have to free the data field in val
- explicitly */
-};
-
-#endif
diff --git a/storage/innobase/include/read0read.h b/storage/innobase/include/read0read.h
deleted file mode 100644
index 97b6d7e9dd9..00000000000
--- a/storage/innobase/include/read0read.h
+++ /dev/null
@@ -1,165 +0,0 @@
-/******************************************************
-Cursor read
-
-(c) 1997 Innobase Oy
-
-Created 2/16/1997 Heikki Tuuri
-*******************************************************/
-
-#ifndef read0read_h
-#define read0read_h
-
-#include "univ.i"
-
-
-#include "ut0byte.h"
-#include "ut0lst.h"
-#include "trx0trx.h"
-#include "read0types.h"
-
-/*************************************************************************
-Opens a read view where exactly the transactions serialized before this
-point in time are seen in the view. */
-
-read_view_t*
-read_view_open_now(
-/*===============*/
- /* out, own: read view struct */
- dulint cr_trx_id, /* in: trx_id of creating
- transaction, or (0, 0) used in
- purge */
- mem_heap_t* heap); /* in: memory heap from which
- allocated */
-/*************************************************************************
-Makes a copy of the oldest existing read view, or opens a new. The view
-must be closed with ..._close. */
-
-read_view_t*
-read_view_oldest_copy_or_open_new(
-/*==============================*/
- /* out, own: read view struct */
- dulint cr_trx_id, /* in: trx_id of creating
- transaction, or (0, 0) used in
- purge */
- mem_heap_t* heap); /* in: memory heap from which
- allocated */
-/*************************************************************************
-Closes a read view. */
-
-void
-read_view_close(
-/*============*/
- read_view_t* view); /* in: read view */
-/*************************************************************************
-Closes a consistent read view for MySQL. This function is called at an SQL
-statement end if the trx isolation level is <= TRX_ISO_READ_COMMITTED. */
-
-void
-read_view_close_for_mysql(
-/*======================*/
- trx_t* trx); /* in: trx which has a read view */
-/*************************************************************************
-Checks if a read view sees the specified transaction. */
-UNIV_INLINE
-ibool
-read_view_sees_trx_id(
-/*==================*/
- /* out: TRUE if sees */
- read_view_t* view, /* in: read view */
- dulint trx_id);/* in: trx id */
-/*************************************************************************
-Prints a read view to stderr. */
-
-void
-read_view_print(
-/*============*/
- read_view_t* view); /* in: read view */
-/*************************************************************************
-Create a consistent cursor view for mysql to be used in cursors. In this
-consistent read view modifications done by the creating transaction or future
-transactions are not visible. */
-
-cursor_view_t*
-read_cursor_view_create_for_mysql(
-/*==============================*/
- trx_t* cr_trx);/* in: trx where cursor view is created */
-/*************************************************************************
-Close a given consistent cursor view for mysql and restore global read view
-back to a transaction read view. */
-
-void
-read_cursor_view_close_for_mysql(
-/*=============================*/
- trx_t* trx, /* in: trx */
- cursor_view_t* curview); /* in: cursor view to be closed */
-/*************************************************************************
-This function sets a given consistent cursor view to a transaction
-read view if given consistent cursor view is not NULL. Otherwise, function
-restores a global read view to a transaction read view. */
-
-void
-read_cursor_set_for_mysql(
-/*======================*/
- trx_t* trx, /* in: transaction where cursor is set */
- cursor_view_t* curview);/* in: consistent cursor view to be set */
-
-/* Read view lists the trx ids of those transactions for which a consistent
-read should not see the modifications to the database. */
-
-struct read_view_struct{
- ulint type; /* VIEW_NORMAL, VIEW_HIGH_GRANULARITY */
- dulint undo_no; /* (0, 0) or if type is VIEW_HIGH_GRANULARITY
- transaction undo_no when this high-granularity
- consistent read view was created */
- dulint low_limit_no; /* The view does not need to see the undo
- logs for transactions whose transaction number
- is strictly smaller (<) than this value: they
- can be removed in purge if not needed by other
- views */
- dulint low_limit_id; /* The read should not see any transaction
- with trx id >= this value */
- dulint up_limit_id; /* The read should see all trx ids which
- are strictly smaller (<) than this value */
- ulint n_trx_ids; /* Number of cells in the trx_ids array */
- dulint* trx_ids; /* Additional trx ids which the read should
- not see: typically, these are the active
- transactions at the time when the read is
- serialized, except the reading transaction
- itself; the trx ids in this array are in a
- descending order */
- dulint creator_trx_id; /* trx id of creating transaction, or
- (0, 0) used in purge */
- UT_LIST_NODE_T(read_view_t) view_list;
- /* List of read views in trx_sys */
-};
-
-/* Read view types */
-#define VIEW_NORMAL 1 /* Normal consistent read view
- where transaction does not see changes
- made by active transactions except
- creating transaction. */
-#define VIEW_HIGH_GRANULARITY 2 /* High-granularity read view where
- transaction does not see changes
- made by active transactions and own
- changes after a point in time when this
- read view was created. */
-
-/* Implement InnoDB framework to support consistent read views in
-cursors. This struct holds both heap where consistent read view
-is allocated and pointer to a read view. */
-
-struct cursor_view_struct{
- mem_heap_t* heap;
- /* Memory heap for the cursor view */
- read_view_t* read_view;
- /* Consistent read view of the cursor*/
- ulint n_mysql_tables_in_use;
- /* number of Innobase tables used in the
- processing of this cursor */
-};
-
-#ifndef UNIV_NONINL
-#include "read0read.ic"
-#endif
-
-#endif
diff --git a/storage/innobase/include/read0read.ic b/storage/innobase/include/read0read.ic
deleted file mode 100644
index 3aded1ca07c..00000000000
--- a/storage/innobase/include/read0read.ic
+++ /dev/null
@@ -1,81 +0,0 @@
-/******************************************************
-Cursor read
-
-(c) 1997 Innobase Oy
-
-Created 2/16/1997 Heikki Tuuri
-*******************************************************/
-
-/*************************************************************************
-Gets the nth trx id in a read view. */
-UNIV_INLINE
-dulint
-read_view_get_nth_trx_id(
-/*=====================*/
- /* out: trx id */
- read_view_t* view, /* in: read view */
- ulint n) /* in: position */
-{
- ut_ad(n < view->n_trx_ids);
-
- return(*(view->trx_ids + n));
-}
-
-/*************************************************************************
-Sets the nth trx id in a read view. */
-UNIV_INLINE
-void
-read_view_set_nth_trx_id(
-/*=====================*/
- read_view_t* view, /* in: read view */
- ulint n, /* in: position */
- dulint trx_id) /* in: trx id to set */
-{
- ut_ad(n < view->n_trx_ids);
-
- *(view->trx_ids + n) = trx_id;
-}
-
-/*************************************************************************
-Checks if a read view sees the specified transaction. */
-UNIV_INLINE
-ibool
-read_view_sees_trx_id(
-/*==================*/
- /* out: TRUE if sees */
- read_view_t* view, /* in: read view */
- dulint trx_id) /* in: trx id */
-{
- ulint n_ids;
- int cmp;
- ulint i;
-
- if (ut_dulint_cmp(trx_id, view->up_limit_id) < 0) {
-
- return(TRUE);
- }
-
- if (ut_dulint_cmp(trx_id, view->low_limit_id) >= 0) {
-
- return(FALSE);
- }
-
- /* We go through the trx ids in the array smallest first: this order
- may save CPU time, because if there was a very long running
- transaction in the trx id array, its trx id is looked at first, and
- the first two comparisons may well decide the visibility of trx_id. */
-
- n_ids = view->n_trx_ids;
-
- for (i = 0; i < n_ids; i++) {
-
- cmp = ut_dulint_cmp(
- trx_id,
- read_view_get_nth_trx_id(view, n_ids - i - 1));
- if (cmp <= 0) {
- return(cmp < 0);
- }
- }
-
- return(TRUE);
-}
diff --git a/storage/innobase/include/read0types.h b/storage/innobase/include/read0types.h
deleted file mode 100644
index 7d42728523e..00000000000
--- a/storage/innobase/include/read0types.h
+++ /dev/null
@@ -1,15 +0,0 @@
-/******************************************************
-Cursor read
-
-(c) 1997 Innobase Oy
-
-Created 2/16/1997 Heikki Tuuri
-*******************************************************/
-
-#ifndef read0types_h
-#define read0types_h
-
-typedef struct read_view_struct read_view_t;
-typedef struct cursor_view_struct cursor_view_t;
-
-#endif
diff --git a/storage/innobase/include/rem0cmp.h b/storage/innobase/include/rem0cmp.h
deleted file mode 100644
index c6a6e5de4db..00000000000
--- a/storage/innobase/include/rem0cmp.h
+++ /dev/null
@@ -1,173 +0,0 @@
-/***********************************************************************
-Comparison services for records
-
-(c) 1994-2001 Innobase Oy
-
-Created 7/1/1994 Heikki Tuuri
-************************************************************************/
-
-#ifndef rem0cmp_h
-#define rem0cmp_h
-
-#include "univ.i"
-#include "data0data.h"
-#include "data0type.h"
-#include "dict0dict.h"
-#include "rem0rec.h"
-
-/*****************************************************************
-Returns TRUE if two columns are equal for comparison purposes. */
-
-ibool
-cmp_cols_are_equal(
-/*===============*/
- /* out: TRUE if the columns are
- considered equal in comparisons */
- const dict_col_t* col1, /* in: column 1 */
- const dict_col_t* col2, /* in: column 2 */
- ibool check_charsets);
- /* in: whether to check charsets */
-/*****************************************************************
-This function is used to compare two data fields for which we know the
-data type. */
-UNIV_INLINE
-int
-cmp_data_data(
-/*==========*/
- /* out: 1, 0, -1, if data1 is greater, equal,
- less than data2, respectively */
- ulint mtype, /* in: main type */
- ulint prtype, /* in: precise type */
- byte* data1, /* in: data field (== a pointer to a memory
- buffer) */
- ulint len1, /* in: data field length or UNIV_SQL_NULL */
- byte* data2, /* in: data field (== a pointer to a memory
- buffer) */
- ulint len2); /* in: data field length or UNIV_SQL_NULL */
-/*****************************************************************
-This function is used to compare two data fields for which we know the
-data type. */
-
-int
-cmp_data_data_slow(
-/*===============*/
- /* out: 1, 0, -1, if data1 is greater, equal,
- less than data2, respectively */
- ulint mtype, /* in: main type */
- ulint prtype, /* in: precise type */
- byte* data1, /* in: data field (== a pointer to a memory
- buffer) */
- ulint len1, /* in: data field length or UNIV_SQL_NULL */
- byte* data2, /* in: data field (== a pointer to a memory
- buffer) */
- ulint len2); /* in: data field length or UNIV_SQL_NULL */
-/*****************************************************************
-This function is used to compare two dfields where at least the first
-has its data type field set. */
-UNIV_INLINE
-int
-cmp_dfield_dfield(
-/*==============*/
- /* out: 1, 0, -1, if dfield1 is greater, equal,
- less than dfield2, respectively */
- dfield_t* dfield1,/* in: data field; must have type field set */
- dfield_t* dfield2);/* in: data field */
-/*****************************************************************
-This function is used to compare a data tuple to a physical record.
-Only dtuple->n_fields_cmp first fields are taken into account for
-the the data tuple! If we denote by n = n_fields_cmp, then rec must
-have either m >= n fields, or it must differ from dtuple in some of
-the m fields rec has. If rec has an externally stored field we do not
-compare it but return with value 0 if such a comparison should be
-made. */
-
-int
-cmp_dtuple_rec_with_match(
-/*======================*/
- /* out: 1, 0, -1, if dtuple is greater, equal,
- less than rec, respectively, when only the
- common first fields are compared, or
- until the first externally stored field in
- rec */
- dtuple_t* dtuple, /* in: data tuple */
- rec_t* rec, /* in: physical record which differs from
- dtuple in some of the common fields, or which
- has an equal number or more fields than
- dtuple */
- const ulint* offsets,/* in: array returned by rec_get_offsets() */
- ulint* matched_fields, /* in/out: number of already completely
- matched fields; when function returns,
- contains the value for current comparison */
- ulint* matched_bytes); /* in/out: number of already matched
- bytes within the first field not completely
- matched; when function returns, contains the
- value for current comparison */
-/******************************************************************
-Compares a data tuple to a physical record. */
-
-int
-cmp_dtuple_rec(
-/*===========*/
- /* out: 1, 0, -1, if dtuple is greater, equal,
- less than rec, respectively; see the comments
- for cmp_dtuple_rec_with_match */
- dtuple_t* dtuple, /* in: data tuple */
- rec_t* rec, /* in: physical record */
- const ulint* offsets);/* in: array returned by rec_get_offsets() */
-/******************************************************************
-Checks if a dtuple is a prefix of a record. The last field in dtuple
-is allowed to be a prefix of the corresponding field in the record. */
-
-ibool
-cmp_dtuple_is_prefix_of_rec(
-/*========================*/
- /* out: TRUE if prefix */
- dtuple_t* dtuple, /* in: data tuple */
- rec_t* rec, /* in: physical record */
- const ulint* offsets);/* in: array returned by rec_get_offsets() */
-/*****************************************************************
-This function is used to compare two physical records. Only the common
-first fields are compared, and if an externally stored field is
-encountered, then 0 is returned. */
-
-int
-cmp_rec_rec_with_match(
-/*===================*/
- /* out: 1, 0 , -1 if rec1 is greater, equal,
- less, respectively, than rec2; only the common
- first fields are compared */
- rec_t* rec1, /* in: physical record */
- rec_t* rec2, /* in: physical record */
- const ulint* offsets1,/* in: rec_get_offsets(rec1, index) */
- const ulint* offsets2,/* in: rec_get_offsets(rec2, index) */
- dict_index_t* index, /* in: data dictionary index */
- ulint* matched_fields, /* in/out: number of already completely
- matched fields; when the function returns,
- contains the value the for current
- comparison */
- ulint* matched_bytes);/* in/out: number of already matched
- bytes within the first field not completely
- matched; when the function returns, contains
- the value for the current comparison */
-/*****************************************************************
-This function is used to compare two physical records. Only the common
-first fields are compared. */
-UNIV_INLINE
-int
-cmp_rec_rec(
-/*========*/
- /* out: 1, 0 , -1 if rec1 is greater, equal,
- less, respectively, than rec2; only the common
- first fields are compared */
- rec_t* rec1, /* in: physical record */
- rec_t* rec2, /* in: physical record */
- const ulint* offsets1,/* in: rec_get_offsets(rec1, index) */
- const ulint* offsets2,/* in: rec_get_offsets(rec2, index) */
- dict_index_t* index); /* in: data dictionary index */
-
-
-#ifndef UNIV_NONINL
-#include "rem0cmp.ic"
-#endif
-
-#endif
diff --git a/storage/innobase/include/rem0cmp.ic b/storage/innobase/include/rem0cmp.ic
deleted file mode 100644
index 52dc7ff5dc9..00000000000
--- a/storage/innobase/include/rem0cmp.ic
+++ /dev/null
@@ -1,76 +0,0 @@
-/***********************************************************************
-Comparison services for records
-
-(c) 1994-1996 Innobase Oy
-
-Created 7/1/1994 Heikki Tuuri
-************************************************************************/
-
-/*****************************************************************
-This function is used to compare two data fields for which we know the
-data type. */
-UNIV_INLINE
-int
-cmp_data_data(
-/*==========*/
- /* out: 1, 0, -1, if data1 is greater, equal,
- less than data2, respectively */
- ulint mtype, /* in: main type */
- ulint prtype, /* in: precise type */
- byte* data1, /* in: data field (== a pointer to a memory
- buffer) */
- ulint len1, /* in: data field length or UNIV_SQL_NULL */
- byte* data2, /* in: data field (== a pointer to a memory
- buffer) */
- ulint len2) /* in: data field length or UNIV_SQL_NULL */
-{
- return(cmp_data_data_slow(mtype, prtype, data1, len1, data2, len2));
-}
-
-/*****************************************************************
-This function is used to compare two dfields where at least the first
-has its data type field set. */
-UNIV_INLINE
-int
-cmp_dfield_dfield(
-/*==============*/
- /* out: 1, 0, -1, if dfield1 is greater, equal,
- less than dfield2, respectively */
- dfield_t* dfield1,/* in: data field; must have type field set */
- dfield_t* dfield2)/* in: data field */
-{
- const dtype_t* type;
-
- ut_ad(dfield_check_typed(dfield1));
-
- type = dfield_get_type(dfield1);
-
- return(cmp_data_data(type->mtype, type->prtype,
- dfield_get_data(dfield1),
- dfield_get_len(dfield1),
- dfield_get_data(dfield2),
- dfield_get_len(dfield2)));
-}
-
-/*****************************************************************
-This function is used to compare two physical records. Only the common
-first fields are compared. */
-UNIV_INLINE
-int
-cmp_rec_rec(
-/*========*/
- /* out: 1, 0 , -1 if rec1 is greater, equal,
- less, respectively, than rec2; only the common
- first fields are compared */
- rec_t* rec1, /* in: physical record */
- rec_t* rec2, /* in: physical record */
- const ulint* offsets1,/* in: rec_get_offsets(rec1, index) */
- const ulint* offsets2,/* in: rec_get_offsets(rec2, index) */
- dict_index_t* index) /* in: data dictionary index */
-{
- ulint match_f = 0;
- ulint match_b = 0;
-
- return(cmp_rec_rec_with_match(rec1, rec2, offsets1, offsets2, index,
- &match_f, &match_b));
-}
diff --git a/storage/innobase/include/rem0rec.h b/storage/innobase/include/rem0rec.h
deleted file mode 100644
index abc204bb583..00000000000
--- a/storage/innobase/include/rem0rec.h
+++ /dev/null
@@ -1,582 +0,0 @@
-/************************************************************************
-Record manager
-
-(c) 1994-1996 Innobase Oy
-
-Created 5/30/1994 Heikki Tuuri
-*************************************************************************/
-
-#ifndef rem0rec_h
-#define rem0rec_h
-
-#include "univ.i"
-#include "data0data.h"
-#include "rem0types.h"
-#include "mtr0types.h"
-
-/* Info bit denoting the predefined minimum record: this bit is set
-if and only if the record is the first user record on a non-leaf
-B-tree page that is the leftmost page on its level
-(PAGE_LEVEL is nonzero and FIL_PAGE_PREV is FIL_NULL). */
-#define REC_INFO_MIN_REC_FLAG 0x10UL
-
-/* Number of extra bytes in an old-style record,
-in addition to the data and the offsets */
-#define REC_N_OLD_EXTRA_BYTES 6
-/* Number of extra bytes in a new-style record,
-in addition to the data and the offsets */
-#define REC_N_NEW_EXTRA_BYTES 5
-
-/* Record status values */
-#define REC_STATUS_ORDINARY 0
-#define REC_STATUS_NODE_PTR 1
-#define REC_STATUS_INFIMUM 2
-#define REC_STATUS_SUPREMUM 3
-
-/* Number of elements that should be initially allocated for the
-offsets[] array, first passed to rec_get_offsets() */
-#define REC_OFFS_NORMAL_SIZE 100
-#define REC_OFFS_SMALL_SIZE 10
-
-/**********************************************************
-The following function is used to get the offset of the
-next chained record on the same page. */
-UNIV_INLINE
-ulint
-rec_get_next_offs(
-/*==============*/
- /* out: the page offset of the next
- chained record */
- rec_t* rec, /* in: physical record */
- ulint comp); /* in: nonzero=compact page format */
-/**********************************************************
-The following function is used to set the next record offset field
-of the record. */
-UNIV_INLINE
-void
-rec_set_next_offs(
-/*==============*/
- rec_t* rec, /* in: physical record */
- ulint comp, /* in: nonzero=compact page format */
- ulint next); /* in: offset of the next record */
-/**********************************************************
-The following function is used to get the number of fields
-in an old-style record. */
-UNIV_INLINE
-ulint
-rec_get_n_fields_old(
-/*=================*/
- /* out: number of data fields */
- rec_t* rec); /* in: physical record */
-/**********************************************************
-The following function is used to get the number of fields
-in a record. */
-UNIV_INLINE
-ulint
-rec_get_n_fields(
-/*=============*/
- /* out: number of data fields */
- rec_t* rec, /* in: physical record */
- dict_index_t* index); /* in: record descriptor */
-/**********************************************************
-The following function is used to get the number of records
-owned by the previous directory record. */
-UNIV_INLINE
-ulint
-rec_get_n_owned(
-/*============*/
- /* out: number of owned records */
- rec_t* rec, /* in: physical record */
- ulint comp); /* in: nonzero=compact page format */
-/**********************************************************
-The following function is used to set the number of owned
-records. */
-UNIV_INLINE
-void
-rec_set_n_owned(
-/*============*/
- rec_t* rec, /* in: physical record */
- ulint comp, /* in: nonzero=compact page format */
- ulint n_owned); /* in: the number of owned */
-/**********************************************************
-The following function is used to retrieve the info bits of
-a record. */
-UNIV_INLINE
-ulint
-rec_get_info_bits(
-/*==============*/
- /* out: info bits */
- rec_t* rec, /* in: physical record */
- ulint comp); /* in: nonzero=compact page format */
-/**********************************************************
-The following function is used to set the info bits of a record. */
-UNIV_INLINE
-void
-rec_set_info_bits(
-/*==============*/
- rec_t* rec, /* in: physical record */
- ulint comp, /* in: nonzero=compact page format */
- ulint bits); /* in: info bits */
-/**********************************************************
-The following function retrieves the status bits of a new-style record. */
-UNIV_INLINE
-ulint
-rec_get_status(
-/*===========*/
- /* out: status bits */
- rec_t* rec); /* in: physical record */
-
-/**********************************************************
-The following function is used to set the status bits of a new-style record. */
-UNIV_INLINE
-void
-rec_set_status(
-/*===========*/
- rec_t* rec, /* in: physical record */
- ulint bits); /* in: info bits */
-
-/**********************************************************
-The following function is used to retrieve the info and status
-bits of a record. (Only compact records have status bits.) */
-UNIV_INLINE
-ulint
-rec_get_info_and_status_bits(
-/*=========================*/
- /* out: info bits */
- rec_t* rec, /* in: physical record */
- ulint comp); /* in: nonzero=compact page format */
-/**********************************************************
-The following function is used to set the info and status
-bits of a record. (Only compact records have status bits.) */
-UNIV_INLINE
-void
-rec_set_info_and_status_bits(
-/*=========================*/
- rec_t* rec, /* in: physical record */
- ulint comp, /* in: nonzero=compact page format */
- ulint bits); /* in: info bits */
-
-/**********************************************************
-The following function tells if record is delete marked. */
-UNIV_INLINE
-ulint
-rec_get_deleted_flag(
-/*=================*/
- /* out: nonzero if delete marked */
- rec_t* rec, /* in: physical record */
- ulint comp); /* in: nonzero=compact page format */
-/**********************************************************
-The following function is used to set the deleted bit. */
-UNIV_INLINE
-void
-rec_set_deleted_flag(
-/*=================*/
- rec_t* rec, /* in: physical record */
- ulint comp, /* in: nonzero=compact page format */
- ulint flag); /* in: nonzero if delete marked */
-/**********************************************************
-The following function tells if a new-style record is a node pointer. */
-UNIV_INLINE
-ibool
-rec_get_node_ptr_flag(
-/*==================*/
- /* out: TRUE if node pointer */
- rec_t* rec); /* in: physical record */
-/**********************************************************
-The following function is used to get the order number
-of the record in the heap of the index page. */
-UNIV_INLINE
-ulint
-rec_get_heap_no(
-/*============*/
- /* out: heap order number */
- rec_t* rec, /* in: physical record */
- ulint comp); /* in: nonzero=compact page format */
-/**********************************************************
-The following function is used to set the heap number
-field in the record. */
-UNIV_INLINE
-void
-rec_set_heap_no(
-/*============*/
- rec_t* rec, /* in: physical record */
- ulint comp, /* in: nonzero=compact page format */
- ulint heap_no);/* in: the heap number */
-/**********************************************************
-The following function is used to test whether the data offsets
-in the record are stored in one-byte or two-byte format. */
-UNIV_INLINE
-ibool
-rec_get_1byte_offs_flag(
-/*====================*/
- /* out: TRUE if 1-byte form */
- rec_t* rec); /* in: physical record */
-/**********************************************************
-The following function determines the offsets to each field
-in the record. It can reuse a previously allocated array. */
-
-ulint*
-rec_get_offsets_func(
-/*=================*/
- /* out: the new offsets */
- rec_t* rec, /* in: physical record */
- dict_index_t* index, /* in: record descriptor */
- ulint* offsets,/* in: array consisting of offsets[0]
- allocated elements, or an array from
- rec_get_offsets(), or NULL */
- ulint n_fields,/* in: maximum number of initialized fields
- (ULINT_UNDEFINED if all fields) */
- mem_heap_t** heap, /* in/out: memory heap */
- const char* file, /* in: file name where called */
- ulint line); /* in: line number where called */
-
-#define rec_get_offsets(rec,index,offsets,n,heap) \
- rec_get_offsets_func(rec,index,offsets,n,heap,__FILE__,__LINE__)
-
-/****************************************************************
-Validates offsets returned by rec_get_offsets(). */
-UNIV_INLINE
-ibool
-rec_offs_validate(
-/*==============*/
- /* out: TRUE if valid */
- rec_t* rec, /* in: record or NULL */
- dict_index_t* index, /* in: record descriptor or NULL */
- const ulint* offsets);/* in: array returned by rec_get_offsets() */
-/****************************************************************
-Updates debug data in offsets, in order to avoid bogus
-rec_offs_validate() failures. */
-UNIV_INLINE
-void
-rec_offs_make_valid(
-/*================*/
- rec_t* rec, /* in: record */
- dict_index_t* index,/* in: record descriptor */
- ulint* offsets);/* in: array returned by rec_get_offsets() */
-
-/****************************************************************
-The following function is used to get a pointer to the nth
-data field in an old-style record. */
-
-byte*
-rec_get_nth_field_old(
-/*==================*/
- /* out: pointer to the field */
- rec_t* rec, /* in: record */
- ulint n, /* in: index of the field */
- ulint* len); /* out: length of the field; UNIV_SQL_NULL
- if SQL null */
-/****************************************************************
-Gets the physical size of an old-style field.
-Also an SQL null may have a field of size > 0,
-if the data type is of a fixed size. */
-UNIV_INLINE
-ulint
-rec_get_nth_field_size(
-/*===================*/
- /* out: field size in bytes */
- rec_t* rec, /* in: record */
- ulint n); /* in: index of the field */
-/****************************************************************
-The following function is used to get a pointer to the nth
-data field in a record. */
-UNIV_INLINE
-byte*
-rec_get_nth_field(
-/*==============*/
- /* out: pointer to the field */
- rec_t* rec, /* in: record */
- const ulint* offsets,/* in: array returned by rec_get_offsets() */
- ulint n, /* in: index of the field */
- ulint* len); /* out: length of the field; UNIV_SQL_NULL
- if SQL null */
-/**********************************************************
-Determine if the offsets are for a record in the new
-compact format. */
-UNIV_INLINE
-ulint
-rec_offs_comp(
-/*==========*/
- /* out: nonzero if compact format */
- const ulint* offsets);/* in: array returned by rec_get_offsets() */
-/**********************************************************
-Returns nonzero if the extern bit is set in nth field of rec. */
-UNIV_INLINE
-ulint
-rec_offs_nth_extern(
-/*================*/
- /* out: nonzero if externally stored */
- const ulint* offsets,/* in: array returned by rec_get_offsets() */
- ulint n); /* in: nth field */
-/**********************************************************
-Returns nonzero if the SQL NULL bit is set in nth field of rec. */
-UNIV_INLINE
-ulint
-rec_offs_nth_sql_null(
-/*==================*/
- /* out: nonzero if SQL NULL */
- const ulint* offsets,/* in: array returned by rec_get_offsets() */
- ulint n); /* in: nth field */
-/**********************************************************
-Gets the physical size of a field. */
-UNIV_INLINE
-ulint
-rec_offs_nth_size(
-/*==============*/
- /* out: length of field */
- const ulint* offsets,/* in: array returned by rec_get_offsets() */
- ulint n); /* in: nth field */
-
-/**********************************************************
-Returns TRUE if the extern bit is set in any of the fields
-of rec. */
-UNIV_INLINE
-ibool
-rec_offs_any_extern(
-/*================*/
- /* out: TRUE if a field is stored externally */
- const ulint* offsets);/* in: array returned by rec_get_offsets() */
-/***************************************************************
-Sets the value of the ith field extern storage bit. */
-UNIV_INLINE
-void
-rec_set_nth_field_extern_bit(
-/*=========================*/
- rec_t* rec, /* in: record */
- dict_index_t* index, /* in: record descriptor */
- ulint i, /* in: ith field */
- ibool val, /* in: value to set */
- mtr_t* mtr); /* in: mtr holding an X-latch to the page
- where rec is, or NULL; in the NULL case
- we do not write to log about the change */
-/***************************************************************
-Sets TRUE the extern storage bits of fields mentioned in an array. */
-
-void
-rec_set_field_extern_bits(
-/*======================*/
- rec_t* rec, /* in: record */
- dict_index_t* index, /* in: record descriptor */
- const ulint* vec, /* in: array of field numbers */
- ulint n_fields,/* in: number of fields numbers */
- mtr_t* mtr); /* in: mtr holding an X-latch to the page
- where rec is, or NULL; in the NULL case
- we do not write to log about the change */
-/***************************************************************
-This is used to modify the value of an already existing field in a record.
-The previous value must have exactly the same size as the new value. If len
-is UNIV_SQL_NULL then the field is treated as an SQL null.
-For records in ROW_FORMAT=COMPACT (new-style records), len must not be
-UNIV_SQL_NULL unless the field already is SQL null. */
-UNIV_INLINE
-void
-rec_set_nth_field(
-/*==============*/
- rec_t* rec, /* in: record */
- const ulint* offsets,/* in: array returned by rec_get_offsets() */
- ulint n, /* in: index number of the field */
- const void* data, /* in: pointer to the data if not SQL null */
- ulint len); /* in: length of the data or UNIV_SQL_NULL */
-/**************************************************************
-The following function returns the data size of an old-style physical
-record, that is the sum of field lengths. SQL null fields
-are counted as length 0 fields. The value returned by the function
-is the distance from record origin to record end in bytes. */
-UNIV_INLINE
-ulint
-rec_get_data_size_old(
-/*==================*/
- /* out: size */
- rec_t* rec); /* in: physical record */
-/**************************************************************
-The following function returns the number of fields in a record. */
-UNIV_INLINE
-ulint
-rec_offs_n_fields(
-/*==============*/
- /* out: number of fields */
- const ulint* offsets);/* in: array returned by rec_get_offsets() */
-/**************************************************************
-The following function returns the data size of a physical
-record, that is the sum of field lengths. SQL null fields
-are counted as length 0 fields. The value returned by the function
-is the distance from record origin to record end in bytes. */
-UNIV_INLINE
-ulint
-rec_offs_data_size(
-/*===============*/
- /* out: size */
- const ulint* offsets);/* in: array returned by rec_get_offsets() */
-/**************************************************************
-Returns the total size of record minus data size of record.
-The value returned by the function is the distance from record
-start to record origin in bytes. */
-UNIV_INLINE
-ulint
-rec_offs_extra_size(
-/*================*/
- /* out: size */
- const ulint* offsets);/* in: array returned by rec_get_offsets() */
-/**************************************************************
-Returns the total size of a physical record. */
-UNIV_INLINE
-ulint
-rec_offs_size(
-/*==========*/
- /* out: size */
- const ulint* offsets);/* in: array returned by rec_get_offsets() */
-/**************************************************************
-Returns a pointer to the start of the record. */
-UNIV_INLINE
-byte*
-rec_get_start(
-/*==========*/
- /* out: pointer to start */
- rec_t* rec, /* in: pointer to record */
- const ulint* offsets);/* in: array returned by rec_get_offsets() */
-/**************************************************************
-Returns a pointer to the end of the record. */
-UNIV_INLINE
-byte*
-rec_get_end(
-/*========*/
- /* out: pointer to end */
- rec_t* rec, /* in: pointer to record */
- const ulint* offsets);/* in: array returned by rec_get_offsets() */
-/*******************************************************************
-Copies a physical record to a buffer. */
-UNIV_INLINE
-rec_t*
-rec_copy(
-/*=====*/
- /* out: pointer to the origin of the copy */
- void* buf, /* in: buffer */
- const rec_t* rec, /* in: physical record */
- const ulint* offsets);/* in: array returned by rec_get_offsets() */
-/******************************************************************
-Copies the first n fields of a physical record to a new physical record in
-a buffer. */
-
-rec_t*
-rec_copy_prefix_to_buf(
-/*===================*/
- /* out, own: copied record */
- rec_t* rec, /* in: physical record */
- dict_index_t* index, /* in: record descriptor */
- ulint n_fields, /* in: number of fields to copy */
- byte** buf, /* in/out: memory buffer
- for the copied prefix, or NULL */
- ulint* buf_size); /* in/out: buffer size */
-/****************************************************************
-Folds a prefix of a physical record to a ulint. */
-UNIV_INLINE
-ulint
-rec_fold(
-/*=====*/
- /* out: the folded value */
- rec_t* rec, /* in: the physical record */
- const ulint* offsets, /* in: array returned by
- rec_get_offsets() */
- ulint n_fields, /* in: number of complete
- fields to fold */
- ulint n_bytes, /* in: number of bytes to fold
- in an incomplete last field */
- dulint tree_id); /* in: index tree id */
-/*************************************************************
-Builds a physical record out of a data tuple and stores it beginning from
-address destination. */
-
-rec_t*
-rec_convert_dtuple_to_rec(
-/*======================*/
- /* out: pointer to the origin
- of physical record */
- byte* buf, /* in: start address of the
- physical record */
- dict_index_t* index, /* in: record descriptor */
- dtuple_t* dtuple);/* in: data tuple */
-/**************************************************************
-Returns the extra size of an old-style physical record if we know its
-data size and number of fields. */
-UNIV_INLINE
-ulint
-rec_get_converted_extra_size(
-/*=========================*/
- /* out: extra size */
- ulint data_size, /* in: data size */
- ulint n_fields) /* in: number of fields */
- __attribute__((const));
-/**************************************************************
-The following function returns the size of a data tuple when converted to
-a physical record. */
-UNIV_INLINE
-ulint
-rec_get_converted_size(
-/*===================*/
- /* out: size */
- dict_index_t* index, /* in: record descriptor */
- dtuple_t* dtuple);/* in: data tuple */
-/******************************************************************
-Copies the first n fields of a physical record to a data tuple.
-The fields are copied to the memory heap. */
-
-void
-rec_copy_prefix_to_dtuple(
-/*======================*/
- dtuple_t* tuple, /* in: data tuple */
- rec_t* rec, /* in: physical record */
- dict_index_t* index, /* in: record descriptor */
- ulint n_fields, /* in: number of fields to copy */
- mem_heap_t* heap); /* in: memory heap */
-/*******************************************************************
-Validates the consistency of a physical record. */
-
-ibool
-rec_validate(
-/*=========*/
- /* out: TRUE if ok */
- rec_t* rec, /* in: physical record */
- const ulint* offsets);/* in: array returned by rec_get_offsets() */
-/*******************************************************************
-Prints an old-style physical record. */
-
-void
-rec_print_old(
-/*==========*/
- FILE* file, /* in: file where to print */
- rec_t* rec); /* in: physical record */
-/*******************************************************************
-Prints a physical record. */
-
-void
-rec_print_new(
-/*==========*/
- FILE* file, /* in: file where to print */
- rec_t* rec, /* in: physical record */
- const ulint* offsets);/* in: array returned by rec_get_offsets() */
-/*******************************************************************
-Prints a physical record. */
-
-void
-rec_print(
-/*======*/
- FILE* file, /* in: file where to print */
- rec_t* rec, /* in: physical record */
- dict_index_t* index); /* in: record descriptor */
-
-#define REC_INFO_BITS 6 /* This is single byte bit-field */
-
-/* Maximum lengths for the data in a physical record if the offsets
-are given in one byte (resp. two byte) format. */
-#define REC_1BYTE_OFFS_LIMIT 0x7FUL
-#define REC_2BYTE_OFFS_LIMIT 0x7FFFUL
-
-/* The data size of record must be smaller than this because we reserve
-two upmost bits in a two byte offset for special purposes */
-#define REC_MAX_DATA_SIZE (16 * 1024)
-
-#ifndef UNIV_NONINL
-#include "rem0rec.ic"
-#endif
-
-#endif
diff --git a/storage/innobase/include/rem0types.h b/storage/innobase/include/rem0types.h
deleted file mode 100644
index 79c162392d2..00000000000
--- a/storage/innobase/include/rem0types.h
+++ /dev/null
@@ -1,20 +0,0 @@
-/************************************************************************
-Record manager global types
-
-(c) 1994-1996 Innobase Oy
-
-Created 5/30/1994 Heikki Tuuri
-*************************************************************************/
-
-#ifndef rem0types_h
-#define rem0types_h
-
-/* We define the physical record simply as an array of bytes */
-typedef byte rec_t;
-
-/* Maximum values for various fields (for non-blob tuples) */
-#define REC_MAX_N_FIELDS (1024 - 1)
-#define REC_MAX_HEAP_NO (2 * 8192 - 1)
-#define REC_MAX_N_OWNED (16 - 1)
-
-#endif
diff --git a/storage/innobase/include/row0ins.h b/storage/innobase/include/row0ins.h
deleted file mode 100644
index b4bcc8ac5ca..00000000000
--- a/storage/innobase/include/row0ins.h
+++ /dev/null
@@ -1,169 +0,0 @@
-/******************************************************
-Insert into a table
-
-(c) 1996 Innobase Oy
-
-Created 4/20/1996 Heikki Tuuri
-*******************************************************/
-
-#ifndef row0ins_h
-#define row0ins_h
-
-#include "univ.i"
-#include "data0data.h"
-#include "que0types.h"
-#include "dict0types.h"
-#include "trx0types.h"
-#include "row0types.h"
-
-/*******************************************************************
-Checks if foreign key constraint fails for an index entry. Sets shared locks
-which lock either the success or the failure of the constraint. NOTE that
-the caller must have a shared latch on dict_foreign_key_check_lock. */
-
-ulint
-row_ins_check_foreign_constraint(
-/*=============================*/
- /* out: DB_SUCCESS, DB_LOCK_WAIT,
- DB_NO_REFERENCED_ROW,
- or DB_ROW_IS_REFERENCED */
- ibool check_ref,/* in: TRUE If we want to check that
- the referenced table is ok, FALSE if we
- want to to check the foreign key table */
- dict_foreign_t* foreign,/* in: foreign constraint; NOTE that the
- tables mentioned in it must be in the
- dictionary cache if they exist at all */
- dict_table_t* table, /* in: if check_ref is TRUE, then the foreign
- table, else the referenced table */
- dtuple_t* entry, /* in: index entry for index */
- que_thr_t* thr); /* in: query thread */
-/*************************************************************************
-Creates an insert node struct. */
-
-ins_node_t*
-ins_node_create(
-/*============*/
- /* out, own: insert node struct */
- ulint ins_type, /* in: INS_VALUES, ... */
- dict_table_t* table, /* in: table where to insert */
- mem_heap_t* heap); /* in: mem heap where created */
-/*************************************************************************
-Sets a new row to insert for an INS_DIRECT node. This function is only used
-if we have constructed the row separately, which is a rare case; this
-function is quite slow. */
-
-void
-ins_node_set_new_row(
-/*=================*/
- ins_node_t* node, /* in: insert node */
- dtuple_t* row); /* in: new row (or first row) for the node */
-/*******************************************************************
-Tries to insert an index entry to an index. If the index is clustered
-and a record with the same unique key is found, the other record is
-necessarily marked deleted by a committed transaction, or a unique key
-violation error occurs. The delete marked record is then updated to an
-existing record, and we must write an undo log record on the delete
-marked record. If the index is secondary, and a record with exactly the
-same fields is found, the other record is necessarily marked deleted.
-It is then unmarked. Otherwise, the entry is just inserted to the index. */
-
-ulint
-row_ins_index_entry_low(
-/*====================*/
- /* out: DB_SUCCESS, DB_LOCK_WAIT, DB_FAIL
- if pessimistic retry needed, or error code */
- ulint mode, /* in: BTR_MODIFY_LEAF or BTR_MODIFY_TREE,
- depending on whether we wish optimistic or
- pessimistic descent down the index tree */
- dict_index_t* index, /* in: index */
- dtuple_t* entry, /* in: index entry to insert */
- ulint* ext_vec,/* in: array containing field numbers of
- externally stored fields in entry, or NULL */
- ulint n_ext_vec,/* in: number of fields in ext_vec */
- que_thr_t* thr); /* in: query thread */
-/*******************************************************************
-Inserts an index entry to index. Tries first optimistic, then pessimistic
-descent down the tree. If the entry matches enough to a delete marked record,
-performs the insert by updating or delete unmarking the delete marked
-record. */
-
-ulint
-row_ins_index_entry(
-/*================*/
- /* out: DB_SUCCESS, DB_LOCK_WAIT,
- DB_DUPLICATE_KEY, or some other error code */
- dict_index_t* index, /* in: index */
- dtuple_t* entry, /* in: index entry to insert */
- ulint* ext_vec,/* in: array containing field numbers of
- externally stored fields in entry, or NULL */
- ulint n_ext_vec,/* in: number of fields in ext_vec */
- que_thr_t* thr); /* in: query thread */
-/***************************************************************
-Inserts a row to a table. */
-
-ulint
-row_ins(
-/*====*/
- /* out: DB_SUCCESS if operation successfully
- completed, else error code or DB_LOCK_WAIT */
- ins_node_t* node, /* in: row insert node */
- que_thr_t* thr); /* in: query thread */
-/***************************************************************
-Inserts a row to a table. This is a high-level function used in
-SQL execution graphs. */
-
-que_thr_t*
-row_ins_step(
-/*=========*/
- /* out: query thread to run next or NULL */
- que_thr_t* thr); /* in: query thread */
-
-/* Insert node structure */
-
-struct ins_node_struct{
- que_common_t common; /* node type: QUE_NODE_INSERT */
- ulint ins_type;/* INS_VALUES, INS_SEARCHED, or INS_DIRECT */
- dtuple_t* row; /* row to insert */
- dict_table_t* table; /* table where to insert */
- sel_node_t* select; /* select in searched insert */
- que_node_t* values_list;/* list of expressions to evaluate and
- insert in an INS_VALUES insert */
- ulint state; /* node execution state */
- dict_index_t* index; /* NULL, or the next index where the index
- entry should be inserted */
- dtuple_t* entry; /* NULL, or entry to insert in the index;
- after a successful insert of the entry,
- this should be reset to NULL */
- UT_LIST_BASE_NODE_T(dtuple_t)
- entry_list;/* list of entries, one for each index */
- byte* row_id_buf;/* buffer for the row id sys field in row */
- dulint trx_id; /* trx id or the last trx which executed the
- node */
- byte* trx_id_buf;/* buffer for the trx id sys field in row */
- mem_heap_t* entry_sys_heap;
- /* memory heap used as auxiliary storage;
- entry_list and sys fields are stored here;
- if this is NULL, entry list should be created
- and buffers for sys fields in row allocated */
- ulint magic_n;
-};
-
-#define INS_NODE_MAGIC_N 15849075
-
-/* Insert node types */
-#define INS_SEARCHED 0 /* INSERT INTO ... SELECT ... */
-#define INS_VALUES 1 /* INSERT INTO ... VALUES ... */
-#define INS_DIRECT 2 /* this is for internal use in dict0crea:
- insert the row directly */
-
-/* Node execution states */
-#define INS_NODE_SET_IX_LOCK 1 /* we should set an IX lock on table */
-#define INS_NODE_ALLOC_ROW_ID 2 /* row id should be allocated */
-#define INS_NODE_INSERT_ENTRIES 3 /* index entries should be built and
- inserted */
-
-#ifndef UNIV_NONINL
-#include "row0ins.ic"
-#endif
-
-#endif
diff --git a/storage/innobase/include/row0ins.ic b/storage/innobase/include/row0ins.ic
deleted file mode 100644
index 80a232d41ee..00000000000
--- a/storage/innobase/include/row0ins.ic
+++ /dev/null
@@ -1,9 +0,0 @@
-/******************************************************
-Insert into a table
-
-(c) 1996 Innobase Oy
-
-Created 4/20/1996 Heikki Tuuri
-*******************************************************/
-
-
diff --git a/storage/innobase/include/row0mysql.ic b/storage/innobase/include/row0mysql.ic
deleted file mode 100644
index aa8a70d8761..00000000000
--- a/storage/innobase/include/row0mysql.ic
+++ /dev/null
@@ -1,7 +0,0 @@
-/******************************************************
-MySQL interface for Innobase
-
-(C) 2001 Innobase Oy
-
-Created 1/23/2001 Heikki Tuuri
-*******************************************************/
diff --git a/storage/innobase/include/row0purge.h b/storage/innobase/include/row0purge.h
deleted file mode 100644
index 174dd239eb5..00000000000
--- a/storage/innobase/include/row0purge.h
+++ /dev/null
@@ -1,79 +0,0 @@
-/******************************************************
-Purge obsolete records
-
-(c) 1997 Innobase Oy
-
-Created 3/14/1997 Heikki Tuuri
-*******************************************************/
-
-#ifndef row0purge_h
-#define row0purge_h
-
-#include "univ.i"
-#include "data0data.h"
-#include "btr0types.h"
-#include "btr0pcur.h"
-#include "dict0types.h"
-#include "trx0types.h"
-#include "que0types.h"
-#include "row0types.h"
-
-/************************************************************************
-Creates a purge node to a query graph. */
-
-purge_node_t*
-row_purge_node_create(
-/*==================*/
- /* out, own: purge node */
- que_thr_t* parent, /* in: parent node, i.e., a thr node */
- mem_heap_t* heap); /* in: memory heap where created */
-/***************************************************************
-Does the purge operation for a single undo log record. This is a high-level
-function used in an SQL execution graph. */
-
-que_thr_t*
-row_purge_step(
-/*===========*/
- /* out: query thread to run next or NULL */
- que_thr_t* thr); /* in: query thread */
-
-/* Purge node structure */
-
-struct purge_node_struct{
- que_common_t common; /* node type: QUE_NODE_PURGE */
- /*----------------------*/
- /* Local storage for this graph node */
- dulint roll_ptr;/* roll pointer to undo log record */
- trx_undo_rec_t* undo_rec;/* undo log record */
- trx_undo_inf_t* reservation;/* reservation for the undo log record in
- the purge array */
- dulint undo_no;/* undo number of the record */
- ulint rec_type;/* undo log record type: TRX_UNDO_INSERT_REC,
- ... */
- btr_pcur_t pcur; /* persistent cursor used in searching the
- clustered index record */
- ibool found_clust;/* TRUE if the clustered index record
- determined by ref was found in the clustered
- index, and we were able to position pcur on
- it */
- dict_table_t* table; /* table where purge is done */
- ulint cmpl_info;/* compiler analysis info of an update */
- upd_t* update; /* update vector for a clustered index
- record */
- dtuple_t* ref; /* NULL, or row reference to the next row to
- handle */
- dtuple_t* row; /* NULL, or a copy (also fields copied to
- heap) of the indexed fields of the row to
- handle */
- dict_index_t* index; /* NULL, or the next index whose record should
- be handled */
- mem_heap_t* heap; /* memory heap used as auxiliary storage for
- row; this must be emptied after a successful
- purge of a row */
-};
-
-#ifndef UNIV_NONINL
-#include "row0purge.ic"
-#endif
-
-#endif
diff --git a/storage/innobase/include/row0purge.ic b/storage/innobase/include/row0purge.ic
deleted file mode 100644
index 50aabf0bc1b..00000000000
--- a/storage/innobase/include/row0purge.ic
+++ /dev/null
@@ -1,8 +0,0 @@
-
-/******************************************************
-Purge obsolete records
-
-(c) 1997 Innobase Oy
-
-Created 3/14/1997 Heikki Tuuri
-*******************************************************/
diff --git a/storage/innobase/include/row0row.h b/storage/innobase/include/row0row.h
deleted file mode 100644
index bea7627cd86..00000000000
--- a/storage/innobase/include/row0row.h
+++ /dev/null
@@ -1,250 +0,0 @@
-/******************************************************
-General row routines
-
-(c) 1996 Innobase Oy
-
-Created 4/20/1996 Heikki Tuuri
-*******************************************************/
-
-#ifndef row0row_h
-#define row0row_h
-
-#include "univ.i"
-#include "data0data.h"
-#include "dict0types.h"
-#include "trx0types.h"
-#include "que0types.h"
-#include "mtr0mtr.h"
-#include "rem0types.h"
-#include "read0types.h"
-#include "btr0types.h"
-
-/*************************************************************************
-Reads the trx id field from a clustered index record. */
-UNIV_INLINE
-dulint
-row_get_rec_trx_id(
-/*===============*/
- /* out: value of the field */
- rec_t* rec, /* in: record */
- dict_index_t* index, /* in: clustered index */
- const ulint* offsets);/* in: rec_get_offsets(rec, index) */
-/*************************************************************************
-Reads the roll pointer field from a clustered index record. */
-UNIV_INLINE
-dulint
-row_get_rec_roll_ptr(
-/*=================*/
- /* out: value of the field */
- rec_t* rec, /* in: record */
- dict_index_t* index, /* in: clustered index */
- const ulint* offsets);/* in: rec_get_offsets(rec, index) */
-/*************************************************************************
-Writes the trx id field to a clustered index record. */
-UNIV_INLINE
-void
-row_set_rec_trx_id(
-/*===============*/
- rec_t* rec, /* in: record */
- dict_index_t* index, /* in: clustered index */
- const ulint* offsets,/* in: rec_get_offsets(rec, index) */
- dulint trx_id);/* in: value of the field */
-/*************************************************************************
-Sets the roll pointer field in a clustered index record. */
-UNIV_INLINE
-void
-row_set_rec_roll_ptr(
-/*=================*/
- rec_t* rec, /* in: record */
- dict_index_t* index, /* in: clustered index */
- const ulint* offsets,/* in: rec_get_offsets(rec, index) */
- dulint roll_ptr);/* in: value of the field */
-/*********************************************************************
-When an insert to a table is performed, this function builds the entry which
-has to be inserted to an index on the table. */
-
-dtuple_t*
-row_build_index_entry(
-/*==================*/
- /* out: index entry which should be inserted */
- dtuple_t* row, /* in: row which should be inserted to the
- table */
- dict_index_t* index, /* in: index on the table */
- mem_heap_t* heap); /* in: memory heap from which the memory for
- the index entry is allocated */
-/***********************************************************************
-An inverse function to dict_row_build_index_entry. Builds a row from a
-record in a clustered index. */
-
-dtuple_t*
-row_build(
-/*======*/
- /* out, own: row built; see the NOTE below! */
- ulint type, /* in: ROW_COPY_POINTERS or ROW_COPY_DATA;
- the latter copies also the data fields to
- heap while the first only places pointers to
- data fields on the index page, and thus is
- more efficient */
- dict_index_t* index, /* in: clustered index */
- rec_t* rec, /* in: record in the clustered index;
- NOTE: in the case ROW_COPY_POINTERS
- the data fields in the row will point
- directly into this record, therefore,
- the buffer page of this record must be
- at least s-latched and the latch held
- as long as the row dtuple is used! */
- const ulint* offsets,/* in: rec_get_offsets(rec, index)
- or NULL, in which case this function
- will invoke rec_get_offsets() */
- mem_heap_t* heap); /* in: memory heap from which the memory
- needed is allocated */
-/***********************************************************************
-Converts an index record to a typed data tuple. */
-
-dtuple_t*
-row_rec_to_index_entry(
-/*===================*/
- /* out, own: index entry built; see the
- NOTE below! */
- ulint type, /* in: ROW_COPY_DATA, or ROW_COPY_POINTERS:
- the former copies also the data fields to
- heap as the latter only places pointers to
- data fields on the index page */
- dict_index_t* index, /* in: index */
- rec_t* rec, /* in: record in the index;
- NOTE: in the case ROW_COPY_POINTERS
- the data fields in the row will point
- directly into this record, therefore,
- the buffer page of this record must be
- at least s-latched and the latch held
- as long as the dtuple is used! */
- mem_heap_t* heap); /* in: memory heap from which the memory
- needed is allocated */
-/***********************************************************************
-Builds from a secondary index record a row reference with which we can
-search the clustered index record. */
-
-dtuple_t*
-row_build_row_ref(
-/*==============*/
- /* out, own: row reference built; see the
- NOTE below! */
- ulint type, /* in: ROW_COPY_DATA, or ROW_COPY_POINTERS:
- the former copies also the data fields to
- heap, whereas the latter only places pointers
- to data fields on the index page */
- dict_index_t* index, /* in: index */
- rec_t* rec, /* in: record in the index;
- NOTE: in the case ROW_COPY_POINTERS
- the data fields in the row will point
- directly into this record, therefore,
- the buffer page of this record must be
- at least s-latched and the latch held
- as long as the row reference is used! */
- mem_heap_t* heap); /* in: memory heap from which the memory
- needed is allocated */
-/***********************************************************************
-Builds from a secondary index record a row reference with which we can
-search the clustered index record. */
-
-void
-row_build_row_ref_in_tuple(
-/*=======================*/
- dtuple_t* ref, /* in/out: row reference built; see the
- NOTE below! */
- dict_index_t* index, /* in: index */
- rec_t* rec, /* in: record in the index;
- NOTE: the data fields in ref will point
- directly into this record, therefore,
- the buffer page of this record must be
- at least s-latched and the latch held
- as long as the row reference is used! */
- trx_t* trx); /* in: transaction */
-/***********************************************************************
-From a row build a row reference with which we can search the clustered
-index record. */
-
-void
-row_build_row_ref_from_row(
-/*=======================*/
- dtuple_t* ref, /* in/out: row reference built; see the
- NOTE below! ref must have the right number
- of fields! */
- dict_table_t* table, /* in: table */
- dtuple_t* row); /* in: row
- NOTE: the data fields in ref will point
- directly into data of this row */
-/***********************************************************************
-Builds from a secondary index record a row reference with which we can
-search the clustered index record. */
-UNIV_INLINE
-void
-row_build_row_ref_fast(
-/*===================*/
- dtuple_t* ref, /* in: typed data tuple where the
- reference is built */
- const ulint* map, /* in: array of field numbers in rec
- telling how ref should be built from
- the fields of rec */
- rec_t* rec, /* in: record in the index; must be
- preserved while ref is used, as we do
- not copy field values to heap */
- const ulint* offsets);/* in: array returned by rec_get_offsets() */
-/*******************************************************************
-Searches the clustered index record for a row, if we have the row
-reference. */
-
-ibool
-row_search_on_row_ref(
-/*==================*/
- /* out: TRUE if found */
- btr_pcur_t* pcur, /* in/out: persistent cursor, which must
- be closed by the caller */
- ulint mode, /* in: BTR_MODIFY_LEAF, ... */
- dict_table_t* table, /* in: table */
- dtuple_t* ref, /* in: row reference */
- mtr_t* mtr); /* in: mtr */
-/*************************************************************************
-Fetches the clustered index record for a secondary index record. The latches
-on the secondary index record are preserved. */
-
-rec_t*
-row_get_clust_rec(
-/*==============*/
- /* out: record or NULL, if no record found */
- ulint mode, /* in: BTR_MODIFY_LEAF, ... */
- rec_t* rec, /* in: record in a secondary index */
- dict_index_t* index, /* in: secondary index */
- dict_index_t** clust_index,/* out: clustered index */
- mtr_t* mtr); /* in: mtr */
-/*******************************************************************
-Searches an index record. */
-
-ibool
-row_search_index_entry(
-/*===================*/
- /* out: TRUE if found */
- dict_index_t* index, /* in: index */
- dtuple_t* entry, /* in: index entry */
- ulint mode, /* in: BTR_MODIFY_LEAF, ... */
- btr_pcur_t* pcur, /* in/out: persistent cursor, which must
- be closed by the caller */
- mtr_t* mtr); /* in: mtr */
-
-
-#define ROW_COPY_DATA 1
-#define ROW_COPY_POINTERS 2
-
-/* The allowed latching order of index records is the following:
-(1) a secondary index record ->
-(2) the clustered index record ->
-(3) rollback segment data for the clustered index record.
-
-No new latches may be obtained while the kernel mutex is reserved.
-However, the kernel mutex can be reserved while latches are owned. */
-
-#ifndef UNIV_NONINL
-#include "row0row.ic"
-#endif
-
-#endif
diff --git a/storage/innobase/include/row0row.ic b/storage/innobase/include/row0row.ic
deleted file mode 100644
index de417f3d971..00000000000
--- a/storage/innobase/include/row0row.ic
+++ /dev/null
@@ -1,182 +0,0 @@
-/******************************************************
-General row routines
-
-(c) 1996 Innobase Oy
-
-Created 4/20/1996 Heikki Tuuri
-*******************************************************/
-
-#include "dict0dict.h"
-#include "rem0rec.h"
-#include "trx0undo.h"
-
-/*************************************************************************
-Reads the trx id or roll ptr field from a clustered index record: this function
-is slower than the specialized inline functions. */
-
-dulint
-row_get_rec_sys_field(
-/*==================*/
- /* out: value of the field */
- ulint type, /* in: DATA_TRX_ID or DATA_ROLL_PTR */
- rec_t* rec, /* in: record */
- dict_index_t* index, /* in: clustered index */
- const ulint* offsets);/* in: rec_get_offsets(rec, index) */
-/*************************************************************************
-Sets the trx id or roll ptr field in a clustered index record: this function
-is slower than the specialized inline functions. */
-
-void
-row_set_rec_sys_field(
-/*==================*/
- /* out: value of the field */
- ulint type, /* in: DATA_TRX_ID or DATA_ROLL_PTR */
- rec_t* rec, /* in: record */
- dict_index_t* index, /* in: clustered index */
- const ulint* offsets,/* in: rec_get_offsets(rec, index) */
- dulint val); /* in: value to set */
-
-/*************************************************************************
-Reads the trx id field from a clustered index record. */
-UNIV_INLINE
-dulint
-row_get_rec_trx_id(
-/*===============*/
- /* out: value of the field */
- rec_t* rec, /* in: record */
- dict_index_t* index, /* in: clustered index */
- const ulint* offsets)/* in: rec_get_offsets(rec, index) */
-{
- ulint offset;
-
- ut_ad(index->type & DICT_CLUSTERED);
- ut_ad(rec_offs_validate(rec, index, offsets));
-
- offset = index->trx_id_offset;
-
- if (offset) {
- return(trx_read_trx_id(rec + offset));
- } else {
- return(row_get_rec_sys_field(DATA_TRX_ID,
- rec, index, offsets));
- }
-}
-
-/*************************************************************************
-Reads the roll pointer field from a clustered index record. */
-UNIV_INLINE
-dulint
-row_get_rec_roll_ptr(
-/*=================*/
- /* out: value of the field */
- rec_t* rec, /* in: record */
- dict_index_t* index, /* in: clustered index */
- const ulint* offsets)/* in: rec_get_offsets(rec, index) */
-{
- ulint offset;
-
- ut_ad(index->type & DICT_CLUSTERED);
- ut_ad(rec_offs_validate(rec, index, offsets));
-
- offset = index->trx_id_offset;
-
- if (offset) {
- return(trx_read_roll_ptr(rec + offset + DATA_TRX_ID_LEN));
- } else {
- return(row_get_rec_sys_field(DATA_ROLL_PTR,
- rec, index, offsets));
- }
-}
-
-/*************************************************************************
-Writes the trx id field to a clustered index record. */
-UNIV_INLINE
-void
-row_set_rec_trx_id(
-/*===============*/
- rec_t* rec, /* in: record */
- dict_index_t* index, /* in: clustered index */
- const ulint* offsets,/* in: rec_get_offsets(rec, index) */
- dulint trx_id) /* in: value of the field */
-{
- ulint offset;
-
- ut_ad(index->type & DICT_CLUSTERED);
- ut_ad(rec_offs_validate(rec, index, offsets));
-
- offset = index->trx_id_offset;
-
- if (offset) {
- trx_write_trx_id(rec + offset, trx_id);
- } else {
- row_set_rec_sys_field(DATA_TRX_ID,
- rec, index, offsets, trx_id);
- }
-}
-
-/*************************************************************************
-Sets the roll pointer field in a clustered index record. */
-UNIV_INLINE
-void
-row_set_rec_roll_ptr(
-/*=================*/
- rec_t* rec, /* in: record */
- dict_index_t* index, /* in: clustered index */
- const ulint* offsets,/* in: rec_get_offsets(rec, index) */
- dulint roll_ptr)/* in: value of the field */
-{
- ulint offset;
-
- ut_ad(index->type & DICT_CLUSTERED);
- ut_ad(rec_offs_validate(rec, index, offsets));
-
- offset = index->trx_id_offset;
-
- if (offset) {
- trx_write_roll_ptr(rec + offset + DATA_TRX_ID_LEN, roll_ptr);
- } else {
- row_set_rec_sys_field(DATA_ROLL_PTR,
- rec, index, offsets, roll_ptr);
- }
-}
-
-/***********************************************************************
-Builds from a secondary index record a row reference with which we can
-search the clustered index record. */
-UNIV_INLINE
-void
-row_build_row_ref_fast(
-/*===================*/
- dtuple_t* ref, /* in: typed data tuple where the
- reference is built */
- const ulint* map, /* in: array of field numbers in rec
- telling how ref should be built from
- the fields of rec */
- rec_t* rec, /* in: record in the index; must be
- preserved while ref is used, as we do
- not copy field values to heap */
- const ulint* offsets)/* in: array returned by rec_get_offsets() */
-{
- dfield_t* dfield;
- byte* field;
- ulint len;
- ulint ref_len;
- ulint field_no;
- ulint i;
-
- ut_ad(rec_offs_validate(rec, NULL, offsets));
- ref_len = dtuple_get_n_fields(ref);
-
- for (i = 0; i < ref_len; i++) {
- dfield = dtuple_get_nth_field(ref, i);
-
- field_no = *(map + i);
-
- if (field_no != ULINT_UNDEFINED) {
-
- field = rec_get_nth_field(rec, offsets,
- field_no, &len);
- dfield_set_data(dfield, field, len);
- }
- }
-}
diff --git a/storage/innobase/include/row0sel.h b/storage/innobase/include/row0sel.h
deleted file mode 100644
index a0a4ccb973b..00000000000
--- a/storage/innobase/include/row0sel.h
+++ /dev/null
@@ -1,392 +0,0 @@
-/******************************************************
-Select
-
-(c) 1997 Innobase Oy
-
-Created 12/19/1997 Heikki Tuuri
-*******************************************************/
-
-#ifndef row0sel_h
-#define row0sel_h
-
-#include "univ.i"
-#include "data0data.h"
-#include "que0types.h"
-#include "dict0types.h"
-#include "trx0types.h"
-#include "row0types.h"
-#include "que0types.h"
-#include "pars0sym.h"
-#include "btr0pcur.h"
-#include "read0read.h"
-#include "row0mysql.h"
-
-/*************************************************************************
-Creates a select node struct. */
-
-sel_node_t*
-sel_node_create(
-/*============*/
- /* out, own: select node struct */
- mem_heap_t* heap); /* in: memory heap where created */
-/*************************************************************************
-Frees the memory private to a select node when a query graph is freed,
-does not free the heap where the node was originally created. */
-
-void
-sel_node_free_private(
-/*==================*/
- sel_node_t* node); /* in: select node struct */
-/*************************************************************************
-Frees a prefetch buffer for a column, including the dynamically allocated
-memory for data stored there. */
-
-void
-sel_col_prefetch_buf_free(
-/*======================*/
- sel_buf_t* prefetch_buf); /* in, own: prefetch buffer */
-/*************************************************************************
-Gets the plan node for the nth table in a join. */
-UNIV_INLINE
-plan_t*
-sel_node_get_nth_plan(
-/*==================*/
- sel_node_t* node,
- ulint i);
-/**************************************************************************
-Performs a select step. This is a high-level function used in SQL execution
-graphs. */
-
-que_thr_t*
-row_sel_step(
-/*=========*/
- /* out: query thread to run next or NULL */
- que_thr_t* thr); /* in: query thread */
-/**************************************************************************
-Performs an execution step of an open or close cursor statement node. */
-UNIV_INLINE
-que_thr_t*
-open_step(
-/*======*/
- /* out: query thread to run next or NULL */
- que_thr_t* thr); /* in: query thread */
-/**************************************************************************
-Performs a fetch for a cursor. */
-
-que_thr_t*
-fetch_step(
-/*=======*/
- /* out: query thread to run next or NULL */
- que_thr_t* thr); /* in: query thread */
-/********************************************************************
-Sample callback function for fetch that prints each row.*/
-
-void*
-row_fetch_print(
-/*============*/
- /* out: always returns non-NULL */
- void* row, /* in: sel_node_t* */
- void* user_arg); /* in: not used */
-/********************************************************************
-Callback function for fetch that stores an unsigned 4 byte integer to the
-location pointed. The column's type must be DATA_INT, DATA_UNSIGNED, length
-= 4. */
-
-void*
-row_fetch_store_uint4(
-/*==================*/
- /* out: always returns NULL */
- void* row, /* in: sel_node_t* */
- void* user_arg); /* in: data pointer */
-/***************************************************************
-Prints a row in a select result. */
-
-que_thr_t*
-row_printf_step(
-/*============*/
- /* out: query thread to run next or NULL */
- que_thr_t* thr); /* in: query thread */
-/********************************************************************
-Converts a key value stored in MySQL format to an Innobase dtuple. The last
-field of the key value may be just a prefix of a fixed length field: hence
-the parameter key_len. But currently we do not allow search keys where the
-last field is only a prefix of the full key field len and print a warning if
-such appears. */
-
-void
-row_sel_convert_mysql_key_to_innobase(
-/*==================================*/
- dtuple_t* tuple, /* in: tuple where to build;
- NOTE: we assume that the type info
- in the tuple is already according
- to index! */
- byte* buf, /* in: buffer to use in field
- conversions */
- ulint buf_len, /* in: buffer length */
- dict_index_t* index, /* in: index of the key value */
- byte* key_ptr, /* in: MySQL key value */
- ulint key_len, /* in: MySQL key value length */
- trx_t* trx); /* in: transaction */
-/************************************************************************
-Searches for rows in the database. This is used in the interface to
-MySQL. This function opens a cursor, and also implements fetch next
-and fetch prev. NOTE that if we do a search with a full key value
-from a unique index (ROW_SEL_EXACT), then we will not store the cursor
-position and fetch next or fetch prev must not be tried to the cursor! */
-
-ulint
-row_search_for_mysql(
-/*=================*/
- /* out: DB_SUCCESS,
- DB_RECORD_NOT_FOUND,
- DB_END_OF_INDEX, DB_DEADLOCK,
- DB_LOCK_TABLE_FULL,
- or DB_TOO_BIG_RECORD */
- byte* buf, /* in/out: buffer for the fetched
- row in the MySQL format */
- ulint mode, /* in: search mode PAGE_CUR_L, ... */
- row_prebuilt_t* prebuilt, /* in: prebuilt struct for the
- table handle; this contains the info
- of search_tuple, index; if search
- tuple contains 0 fields then we
- position the cursor at the start or
- the end of the index, depending on
- 'mode' */
- ulint match_mode, /* in: 0 or ROW_SEL_EXACT or
- ROW_SEL_EXACT_PREFIX */
- ulint direction); /* in: 0 or ROW_SEL_NEXT or
- ROW_SEL_PREV; NOTE: if this is != 0,
- then prebuilt must have a pcur
- with stored position! In opening of a
- cursor 'direction' should be 0. */
-/***********************************************************************
-Checks if MySQL at the moment is allowed for this table to retrieve a
-consistent read result, or store it to the query cache. */
-
-ibool
-row_search_check_if_query_cache_permitted(
-/*======================================*/
- /* out: TRUE if storing or retrieving
- from the query cache is 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_ulonglong* value); /* out: AUTOINC value read */
-
-/* A structure for caching column values for prefetched rows */
-struct sel_buf_struct{
- byte* data; /* data, or NULL; if not NULL, this field
- has allocated memory which must be explicitly
- freed; can be != NULL even when len is
- UNIV_SQL_NULL */
- ulint len; /* data length or UNIV_SQL_NULL */
- ulint val_buf_size;
- /* size of memory buffer allocated for data:
- this can be more than len; this is defined
- when data != NULL */
-};
-
-struct plan_struct{
- dict_table_t* table; /* table struct in the dictionary
- cache */
- dict_index_t* index; /* table index used in the search */
- btr_pcur_t pcur; /* persistent cursor used to search
- the index */
- ibool asc; /* TRUE if cursor traveling upwards */
- ibool pcur_is_open; /* TRUE if pcur has been positioned
- and we can try to fetch new rows */
- ibool cursor_at_end; /* TRUE if the cursor is open but
- we know that there are no more
- qualifying rows left to retrieve from
- the index tree; NOTE though, that
- there may still be unprocessed rows in
- the prefetch stack; always FALSE when
- pcur_is_open is FALSE */
- ibool stored_cursor_rec_processed;
- /* TRUE if the pcur position has been
- stored and the record it is positioned
- on has already been processed */
- que_node_t** tuple_exps; /* array of expressions which are used
- to calculate the field values in the
- search tuple: there is one expression
- for each field in the search tuple */
- dtuple_t* tuple; /* search tuple */
- ulint mode; /* search mode: PAGE_CUR_G, ... */
- ulint n_exact_match; /* number of first fields in the search
- tuple which must be exactly matched */
- ibool unique_search; /* TRUE if we are searching an
- index record with a unique key */
- ulint n_rows_fetched; /* number of rows fetched using pcur
- after it was opened */
- ulint n_rows_prefetched;/* number of prefetched rows cached
- for fetch: fetching several rows in
- the same mtr saves CPU time */
- ulint first_prefetched;/* index of the first cached row in
- select buffer arrays for each column */
- ibool no_prefetch; /* no prefetch for this table */
- sym_node_list_t columns; /* symbol table nodes for the columns
- to retrieve from the table */
- UT_LIST_BASE_NODE_T(func_node_t)
- end_conds; /* conditions which determine the
- fetch limit of the index segment we
- have to look at: when one of these
- fails, the result set has been
- exhausted for the cursor in this
- index; these conditions are normalized
- so that in a comparison the column
- for this table is the first argument */
- UT_LIST_BASE_NODE_T(func_node_t)
- other_conds; /* the rest of search conditions we can
- test at this table in a join */
- ibool must_get_clust; /* TRUE if index is a non-clustered
- index and we must also fetch the
- clustered index record; this is the
- case if the non-clustered record does
- not contain all the needed columns, or
- if this is a single-table explicit
- cursor, or a searched update or
- delete */
- ulint* clust_map; /* map telling how clust_ref is built
- from the fields of a non-clustered
- record */
- dtuple_t* clust_ref; /* the reference to the clustered
- index entry is built here if index is
- a non-clustered index */
- btr_pcur_t clust_pcur; /* if index is non-clustered, we use
- this pcur to search the clustered
- index */
- mem_heap_t* old_vers_heap; /* memory heap used in building an old
- version of a row, or NULL */
-};
-
-struct sel_node_struct{
- que_common_t common; /* node type: QUE_NODE_SELECT */
- ulint state; /* node state */
- que_node_t* select_list; /* select list */
- sym_node_t* into_list; /* variables list or NULL */
- sym_node_t* table_list; /* table list */
- ibool asc; /* TRUE if the rows should be fetched
- in an ascending order */
- ibool set_x_locks; /* TRUE if the cursor is for update or
- delete, which means that a row x-lock
- should be placed on the cursor row */
- ibool select_will_do_update;
- /* TRUE if the select is for a searched
- update which can be performed in-place:
- in this case the select will take care
- of the update */
- ulint latch_mode; /* BTR_SEARCH_LEAF, or BTR_MODIFY_LEAF
- if select_will_do_update is TRUE */
- ulint row_lock_mode; /* LOCK_X or LOCK_S */
- ulint n_tables; /* number of tables */
- ulint fetch_table; /* number of the next table to access
- in the join */
- plan_t* plans; /* array of n_tables many plan nodes
- containing the search plan and the
- search data structures */
- que_node_t* search_cond; /* search condition */
- read_view_t* read_view; /* if the query is a non-locking
- consistent read, its read view is
- placed here, otherwise NULL */
- ibool consistent_read;/* TRUE if the select is a consistent,
- non-locking read */
- order_node_t* order_by; /* order by column definition, or
- NULL */
- ibool is_aggregate; /* TRUE if the select list consists of
- aggregate functions */
- ibool aggregate_already_fetched;
- /* TRUE if the aggregate row has
- already been fetched for the current
- cursor */
- ibool can_get_updated;/* this is TRUE if the select
- is in a single-table explicit
- cursor which can get updated
- within the stored procedure,
- or in a searched update or
- delete; NOTE that to determine
- of an explicit cursor if it
- can get updated, the parser
- checks from a stored procedure
- if it contains positioned
- update or delete statements */
- sym_node_t* explicit_cursor;/* not NULL if an explicit cursor */
- UT_LIST_BASE_NODE_T(sym_node_t)
- copy_variables; /* variables whose values we have to
- copy when an explicit cursor is opened,
- so that they do not change between
- fetches */
-};
-
-/* Select node states */
-#define SEL_NODE_CLOSED 0 /* it is a declared cursor which is not
- currently open */
-#define SEL_NODE_OPEN 1 /* intention locks not yet set on
- tables */
-#define SEL_NODE_FETCH 2 /* intention locks have been set */
-#define SEL_NODE_NO_MORE_ROWS 3 /* cursor has reached the result set
- end */
-
-/* Fetch statement node */
-struct fetch_node_struct{
- que_common_t common; /* type: QUE_NODE_FETCH */
- sel_node_t* cursor_def; /* cursor definition */
- sym_node_t* into_list; /* variables to set */
-
- pars_user_func_t*
- func; /* User callback function or NULL.
- The first argument to the function
- is a sel_node_t*, containing the
- results of the SELECT operation for
- one row. If the function returns
- NULL, it is not interested in
- further rows and the cursor is
- modified so (cursor % NOTFOUND) is
- true. If it returns not-NULL,
- continue normally. See
- row_fetch_print() for an example
- (and a useful debugging tool). */
-};
-
-/* Open or close cursor statement node */
-struct open_node_struct{
- que_common_t common; /* type: QUE_NODE_OPEN */
- ulint op_type; /* ROW_SEL_OPEN_CURSOR or
- ROW_SEL_CLOSE_CURSOR */
- sel_node_t* cursor_def; /* cursor definition */
-};
-
-/* Row printf statement node */
-struct row_printf_node_struct{
- que_common_t common; /* type: QUE_NODE_ROW_PRINTF */
- sel_node_t* sel_node; /* select */
-};
-
-#define ROW_SEL_OPEN_CURSOR 0
-#define ROW_SEL_CLOSE_CURSOR 1
-
-/* Flags for the MySQL interface */
-#define ROW_SEL_NEXT 1
-#define ROW_SEL_PREV 2
-
-#define ROW_SEL_EXACT 1 /* search using a complete key value */
-#define ROW_SEL_EXACT_PREFIX 2 /* search using a key prefix which
- must match to rows: the prefix may
- contain an incomplete field (the
- last field in prefix may be just
- a prefix of a fixed length column) */
-
-#ifndef UNIV_NONINL
-#include "row0sel.ic"
-#endif
-
-#endif
diff --git a/storage/innobase/include/row0types.h b/storage/innobase/include/row0types.h
deleted file mode 100644
index 56ca8711848..00000000000
--- a/storage/innobase/include/row0types.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/******************************************************
-Row operation global types
-
-(c) 1996 Innobase Oy
-
-Created 12/27/1996 Heikki Tuuri
-*******************************************************/
-
-#ifndef row0types_h
-#define row0types_h
-
-typedef struct plan_struct plan_t;
-
-typedef struct upd_struct upd_t;
-
-typedef struct upd_field_struct upd_field_t;
-
-typedef struct upd_node_struct upd_node_t;
-
-typedef struct del_node_struct del_node_t;
-
-typedef struct ins_node_struct ins_node_t;
-
-typedef struct sel_node_struct sel_node_t;
-
-typedef struct open_node_struct open_node_t;
-
-typedef struct fetch_node_struct fetch_node_t;
-
-typedef struct row_printf_node_struct row_printf_node_t;
-typedef struct sel_buf_struct sel_buf_t;
-
-typedef struct undo_node_struct undo_node_t;
-
-typedef struct purge_node_struct purge_node_t;
-
-#endif
diff --git a/storage/innobase/include/row0uins.h b/storage/innobase/include/row0uins.h
deleted file mode 100644
index e28d5363048..00000000000
--- a/storage/innobase/include/row0uins.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/******************************************************
-Fresh insert undo
-
-(c) 1996 Innobase Oy
-
-Created 2/25/1997 Heikki Tuuri
-*******************************************************/
-
-#ifndef row0uins_h
-#define row0uins_h
-
-#include "univ.i"
-#include "data0data.h"
-#include "dict0types.h"
-#include "trx0types.h"
-#include "que0types.h"
-#include "row0types.h"
-#include "mtr0mtr.h"
-
-/***************************************************************
-Undoes a fresh insert of a row to a table. A fresh insert means that
-the same clustered index unique key did not have any record, even delete
-marked, at the time of the insert. */
-
-ulint
-row_undo_ins(
-/*=========*/
- /* out: DB_SUCCESS */
- undo_node_t* node); /* in: row undo node */
-
-
-#ifndef UNIV_NONINL
-#include "row0uins.ic"
-#endif
-
-#endif
diff --git a/storage/innobase/include/row0uins.ic b/storage/innobase/include/row0uins.ic
deleted file mode 100644
index 2b3d5a10f95..00000000000
--- a/storage/innobase/include/row0uins.ic
+++ /dev/null
@@ -1,8 +0,0 @@
-/******************************************************
-Fresh insert undo
-
-(c) 1996 Innobase Oy
-
-Created 2/25/1997 Heikki Tuuri
-*******************************************************/
-
diff --git a/storage/innobase/include/row0umod.h b/storage/innobase/include/row0umod.h
deleted file mode 100644
index f22945e6f12..00000000000
--- a/storage/innobase/include/row0umod.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/******************************************************
-Undo modify of a row
-
-(c) 1997 Innobase Oy
-
-Created 2/27/1997 Heikki Tuuri
-*******************************************************/
-
-#ifndef row0umod_h
-#define row0umod_h
-
-#include "univ.i"
-#include "data0data.h"
-#include "dict0types.h"
-#include "trx0types.h"
-#include "que0types.h"
-#include "row0types.h"
-#include "mtr0mtr.h"
-
-/***************************************************************
-Undoes a modify operation on a row of a table. */
-
-ulint
-row_undo_mod(
-/*=========*/
- /* out: DB_SUCCESS or error code */
- undo_node_t* node, /* in: row undo node */
- que_thr_t* thr); /* in: query thread */
-
-
-#ifndef UNIV_NONINL
-#include "row0umod.ic"
-#endif
-
-#endif
diff --git a/storage/innobase/include/row0umod.ic b/storage/innobase/include/row0umod.ic
deleted file mode 100644
index fcbf4dbc1f3..00000000000
--- a/storage/innobase/include/row0umod.ic
+++ /dev/null
@@ -1,7 +0,0 @@
-/******************************************************
-Undo modify of a row
-
-(c) 1997 Innobase Oy
-
-Created 2/27/1997 Heikki Tuuri
-*******************************************************/
diff --git a/storage/innobase/include/row0undo.h b/storage/innobase/include/row0undo.h
deleted file mode 100644
index 0be09ed1822..00000000000
--- a/storage/innobase/include/row0undo.h
+++ /dev/null
@@ -1,115 +0,0 @@
-/******************************************************
-Row undo
-
-(c) 1997 Innobase Oy
-
-Created 1/8/1997 Heikki Tuuri
-*******************************************************/
-
-#ifndef row0undo_h
-#define row0undo_h
-
-#include "univ.i"
-#include "mtr0mtr.h"
-#include "trx0sys.h"
-#include "btr0types.h"
-#include "btr0pcur.h"
-#include "dict0types.h"
-#include "trx0types.h"
-#include "que0types.h"
-#include "row0types.h"
-
-/************************************************************************
-Creates a row undo node to a query graph. */
-
-undo_node_t*
-row_undo_node_create(
-/*=================*/
- /* out, own: undo node */
- trx_t* trx, /* in: transaction */
- que_thr_t* parent, /* in: parent node, i.e., a thr node */
- mem_heap_t* heap); /* in: memory heap where created */
-/***************************************************************
-Looks for the clustered index record when node has the row reference.
-The pcur in node is used in the search. If found, stores the row to node,
-and stores the position of pcur, and detaches it. The pcur must be closed
-by the caller in any case. */
-
-ibool
-row_undo_search_clust_to_pcur(
-/*==========================*/
- /* out: TRUE if found; NOTE the node->pcur
- must be closed by the caller, regardless of
- the return value */
- undo_node_t* node); /* in: row undo node */
-/***************************************************************
-Undoes a row operation in a table. This is a high-level function used
-in SQL execution graphs. */
-
-que_thr_t*
-row_undo_step(
-/*==========*/
- /* out: query thread to run next or NULL */
- que_thr_t* thr); /* in: query thread */
-
-/* A single query thread will try to perform the undo for all successive
-versions of a clustered index record, if the transaction has modified it
-several times during the execution which is rolled back. It may happen
-that the task is transferred to another query thread, if the other thread
-is assigned to handle an undo log record in the chain of different versions
-of the record, and the other thread happens to get the x-latch to the
-clustered index record at the right time.
- If a query thread notices that the clustered index record it is looking
-for is missing, or the roll ptr field in the record doed not point to the
-undo log record the thread was assigned to handle, then it gives up the undo
-task for that undo log record, and fetches the next. This situation can occur
-just in the case where the transaction modified the same record several times
-and another thread is currently doing the undo for successive versions of
-that index record. */
-
-/* Undo node structure */
-
-struct undo_node_struct{
- que_common_t common; /* node type: QUE_NODE_UNDO */
- ulint state; /* node execution state */
- trx_t* trx; /* trx for which undo is done */
- dulint roll_ptr;/* roll pointer to undo log record */
- trx_undo_rec_t* undo_rec;/* undo log record */
- dulint undo_no;/* undo number of the record */
- ulint rec_type;/* undo log record type: TRX_UNDO_INSERT_REC,
- ... */
- dulint new_roll_ptr; /* roll ptr to restore to clustered index
- record */
- dulint new_trx_id; /* trx id to restore to clustered index
- record */
- btr_pcur_t pcur; /* persistent cursor used in searching the
- clustered index record */
- dict_table_t* table; /* table where undo is done */
- ulint cmpl_info;/* compiler analysis of an update */
- upd_t* update; /* update vector for a clustered index
- record */
- dtuple_t* ref; /* row reference to the next row to handle */
- dtuple_t* row; /* a copy (also fields copied to heap) of the
- row to handle */
- dict_index_t* index; /* the next index whose record should be
- handled */
- mem_heap_t* heap; /* memory heap used as auxiliary storage for
- row; this must be emptied after undo is tried
- on a row */
-};
-
-/* Execution states for an undo node */
-#define UNDO_NODE_FETCH_NEXT 1 /* we should fetch the next undo log
- record */
-#define UNDO_NODE_PREV_VERS 2 /* the roll ptr to previous version of
- a row is stored in node, and undo
- should be done based on it */
-#define UNDO_NODE_INSERT 3
-#define UNDO_NODE_MODIFY 4
-
-
-#ifndef UNIV_NONINL
-#include "row0undo.ic"
-#endif
-
-#endif
diff --git a/storage/innobase/include/row0undo.ic b/storage/innobase/include/row0undo.ic
deleted file mode 100644
index e7f89c7de67..00000000000
--- a/storage/innobase/include/row0undo.ic
+++ /dev/null
@@ -1,7 +0,0 @@
-/******************************************************
-Row undo
-
-(c) 1997 Innobase Oy
-
-Created 1/8/1997 Heikki Tuuri
-*******************************************************/
diff --git a/storage/innobase/include/row0upd.h b/storage/innobase/include/row0upd.h
deleted file mode 100644
index efbc6d6facf..00000000000
--- a/storage/innobase/include/row0upd.h
+++ /dev/null
@@ -1,432 +0,0 @@
-/******************************************************
-Update of a row
-
-(c) 1996 Innobase Oy
-
-Created 12/27/1996 Heikki Tuuri
-*******************************************************/
-
-#ifndef row0upd_h
-#define row0upd_h
-
-#include "univ.i"
-#include "data0data.h"
-#include "btr0types.h"
-#include "btr0pcur.h"
-#include "dict0types.h"
-#include "trx0types.h"
-#include "que0types.h"
-#include "row0types.h"
-#include "pars0types.h"
-
-/*************************************************************************
-Creates an update vector object. */
-UNIV_INLINE
-upd_t*
-upd_create(
-/*=======*/
- /* out, own: update vector object */
- ulint n, /* in: number of fields */
- mem_heap_t* heap); /* in: heap from which memory allocated */
-/*************************************************************************
-Returns the number of fields in the update vector == number of columns
-to be updated by an update vector. */
-UNIV_INLINE
-ulint
-upd_get_n_fields(
-/*=============*/
- /* out: number of fields */
- upd_t* update); /* in: update vector */
-/*************************************************************************
-Returns the nth field of an update vector. */
-UNIV_INLINE
-upd_field_t*
-upd_get_nth_field(
-/*==============*/
- /* out: update vector field */
- upd_t* update, /* in: update vector */
- ulint n); /* in: field position in update vector */
-/*************************************************************************
-Sets an index field number to be updated by an update vector field. */
-UNIV_INLINE
-void
-upd_field_set_field_no(
-/*===================*/
- upd_field_t* upd_field, /* in: update vector field */
- ulint field_no, /* in: field number in a clustered
- index */
- dict_index_t* index, /* in: index */
- trx_t* trx); /* in: transaction */
-/*************************************************************************
-Writes into the redo log the values of trx id and roll ptr and enough info
-to determine their positions within a clustered index record. */
-
-byte*
-row_upd_write_sys_vals_to_log(
-/*==========================*/
- /* out: new pointer to mlog */
- dict_index_t* index, /* in: clustered index */
- trx_t* trx, /* in: transaction */
- dulint roll_ptr,/* in: roll ptr of the undo log record */
- byte* log_ptr,/* pointer to a buffer of size > 20 opened
- in mlog */
- mtr_t* mtr); /* in: mtr */
-/*************************************************************************
-Updates the trx id and roll ptr field in a clustered index record when
-a row is updated or marked deleted. */
-UNIV_INLINE
-void
-row_upd_rec_sys_fields(
-/*===================*/
- rec_t* rec, /* in: record */
- dict_index_t* index, /* in: clustered index */
- const ulint* offsets,/* in: rec_get_offsets(rec, index) */
- trx_t* trx, /* in: transaction */
- dulint roll_ptr);/* in: roll ptr of the undo log record */
-/*************************************************************************
-Sets the trx id or roll ptr field of a clustered index entry. */
-
-void
-row_upd_index_entry_sys_field(
-/*==========================*/
- dtuple_t* entry, /* in: index entry, where the memory buffers
- for sys fields are already allocated:
- the function just copies the new values to
- them */
- dict_index_t* index, /* in: clustered index */
- ulint type, /* in: DATA_TRX_ID or DATA_ROLL_PTR */
- dulint val); /* in: value to write */
-/*************************************************************************
-Creates an update node for a query graph. */
-
-upd_node_t*
-upd_node_create(
-/*============*/
- /* out, own: update node */
- mem_heap_t* heap); /* in: mem heap where created */
-/***************************************************************
-Writes to the redo log the new values of the fields occurring in the index. */
-
-void
-row_upd_index_write_log(
-/*====================*/
- upd_t* update, /* in: update vector */
- byte* log_ptr,/* in: pointer to mlog buffer: must contain at least
- MLOG_BUF_MARGIN bytes of free space; the buffer is
- closed within this function */
- mtr_t* mtr); /* in: mtr into whose log to write */
-/***************************************************************
-Returns TRUE if row update changes size of some field in index or if some
-field to be updated is stored externally in rec or update. */
-
-ibool
-row_upd_changes_field_size_or_external(
-/*===================================*/
- /* out: TRUE if the update changes the size of
- some field in index or the field is external
- in rec or update */
- dict_index_t* index, /* in: index */
- const ulint* offsets,/* in: rec_get_offsets(rec, index) */
- upd_t* update);/* in: update vector */
-/***************************************************************
-Replaces the new column values stored in the update vector to the record
-given. No field size changes are allowed. This function is used only for
-a clustered index */
-
-void
-row_upd_rec_in_place(
-/*=================*/
- rec_t* rec, /* in/out: record where replaced */
- const ulint* offsets,/* in: array returned by rec_get_offsets() */
- upd_t* update);/* in: update vector */
-/*******************************************************************
-Builds an update vector from those fields which in a secondary index entry
-differ from a record that has the equal ordering fields. NOTE: we compare
-the fields as binary strings! */
-
-upd_t*
-row_upd_build_sec_rec_difference_binary(
-/*====================================*/
- /* out, own: update vector of differing
- fields */
- dict_index_t* index, /* in: index */
- dtuple_t* entry, /* in: entry to insert */
- rec_t* rec, /* in: secondary index record */
- trx_t* trx, /* in: transaction */
- mem_heap_t* heap); /* in: memory heap from which allocated */
-/*******************************************************************
-Builds an update vector from those fields, excluding the roll ptr and
-trx id fields, which in an index entry differ from a record that has
-the equal ordering fields. NOTE: we compare the fields as binary strings! */
-
-upd_t*
-row_upd_build_difference_binary(
-/*============================*/
- /* out, own: update vector of differing
- fields, excluding roll ptr and trx id */
- dict_index_t* index, /* in: clustered index */
- dtuple_t* entry, /* in: entry to insert */
- ulint* ext_vec,/* in: array containing field numbers of
- externally stored fields in entry, or NULL */
- ulint n_ext_vec,/* in: number of fields in ext_vec */
- rec_t* rec, /* in: clustered index record */
- trx_t* trx, /* in: transaction */
- mem_heap_t* heap); /* in: memory heap from which allocated */
-/***************************************************************
-Replaces the new column values stored in the update vector to the index entry
-given. */
-
-void
-row_upd_index_replace_new_col_vals_index_pos(
-/*=========================================*/
- dtuple_t* entry, /* in/out: index entry where replaced */
- dict_index_t* index, /* in: index; NOTE that this may also be a
- non-clustered index */
- upd_t* update, /* in: an update vector built for the index so
- that the field number in an upd_field is the
- index position */
- ibool order_only,
- /* in: if TRUE, limit the replacement to
- ordering fields of index; note that this
- does not work for non-clustered indexes. */
- mem_heap_t* heap); /* in: memory heap to which we allocate and
- copy the new values, set this as NULL if you
- do not want allocation */
-/***************************************************************
-Replaces the new column values stored in the update vector to the index entry
-given. */
-
-void
-row_upd_index_replace_new_col_vals(
-/*===============================*/
- dtuple_t* entry, /* in/out: index entry where replaced */
- dict_index_t* index, /* in: index; NOTE that this may also be a
- non-clustered index */
- upd_t* update, /* in: an update vector built for the
- CLUSTERED index so that the field number in
- an upd_field is the clustered index position */
- mem_heap_t* heap); /* in: memory heap to which we allocate and
- copy the new values, set this as NULL if you
- do not want allocation */
-/***************************************************************
-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
-fields in the index is small. Otherwise, this can be quadratic.
-NOTE: we compare the fields as binary strings! */
-
-ibool
-row_upd_changes_ord_field_binary(
-/*=============================*/
- /* out: TRUE if update vector changes
- an ordering field in the index record;
- NOTE: the fields are compared as binary
- strings */
- dtuple_t* row, /* in: old value of row, or NULL if the
- row and the data values in update are not
- known when this function is called, e.g., at
- compile time */
- dict_index_t* index, /* in: index of the record */
- upd_t* update);/* in: update vector for the row; NOTE: the
- field numbers in this MUST be clustered index
- positions! */
-/***************************************************************
-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
-fields in the index is small. Otherwise, this can be quadratic.
-NOTE: we compare the fields as binary strings! */
-
-ibool
-row_upd_changes_some_index_ord_field_binary(
-/*========================================*/
- /* out: TRUE if update vector may change
- an ordering field in an index record */
- dict_table_t* table, /* in: table */
- upd_t* update);/* in: update vector for the row */
-/***************************************************************
-Updates a row in a table. This is a high-level function used
-in SQL execution graphs. */
-
-que_thr_t*
-row_upd_step(
-/*=========*/
- /* out: query thread to run next or NULL */
- que_thr_t* thr); /* in: query thread */
-/*************************************************************************
-Performs an in-place update for the current clustered index record in
-select. */
-
-void
-row_upd_in_place_in_select(
-/*=======================*/
- sel_node_t* sel_node, /* in: select node */
- que_thr_t* thr, /* in: query thread */
- mtr_t* mtr); /* in: mtr */
-/*************************************************************************
-Parses the log data of system field values. */
-
-byte*
-row_upd_parse_sys_vals(
-/*===================*/
- /* out: log data end or NULL */
- byte* ptr, /* in: buffer */
- byte* end_ptr,/* in: buffer end */
- ulint* pos, /* out: TRX_ID position in record */
- dulint* trx_id, /* out: trx id */
- dulint* roll_ptr);/* out: roll ptr */
-/*************************************************************************
-Updates the trx id and roll ptr field in a clustered index record in database
-recovery. */
-
-void
-row_upd_rec_sys_fields_in_recovery(
-/*===============================*/
- rec_t* rec, /* in: record */
- const ulint* offsets,/* in: array returned by rec_get_offsets() */
- ulint pos, /* in: TRX_ID position in rec */
- dulint trx_id, /* in: transaction id */
- dulint roll_ptr);/* in: roll ptr of the undo log record */
-/*************************************************************************
-Parses the log data written by row_upd_index_write_log. */
-
-byte*
-row_upd_index_parse(
-/*================*/
- /* out: log data end or NULL */
- byte* ptr, /* in: buffer */
- byte* end_ptr,/* in: buffer end */
- mem_heap_t* heap, /* in: memory heap where update vector is
- built */
- upd_t** update_out);/* out: update vector */
-
-
-/* Update vector field */
-struct upd_field_struct{
- ulint field_no; /* field number in an index, usually
- the clustered index, but in updating
- a secondary index record in btr0cur.c
- this is the position in the secondary
- index */
- que_node_t* exp; /* expression for calculating a new
- value: it refers to column values and
- constants in the symbol table of the
- query graph */
- dfield_t new_val; /* new value for the column */
- ibool extern_storage; /* this is set to TRUE if dfield
- actually contains a reference to
- an externally stored field */
-};
-
-/* Update vector structure */
-struct upd_struct{
- ulint info_bits; /* new value of info bits to record;
- default is 0 */
- ulint n_fields; /* number of update fields */
- upd_field_t* fields; /* array of update fields */
-};
-
-/* Update node structure which also implements the delete operation
-of a row */
-
-struct upd_node_struct{
- que_common_t common; /* node type: QUE_NODE_UPDATE */
- ibool is_delete;/* TRUE if delete, FALSE if update */
- ibool searched_update;
- /* TRUE if searched update, FALSE if
- positioned */
- ibool select_will_do_update;
- /* TRUE if a searched update where ordering
- fields will not be updated, and the size of
- the fields will not change: in this case the
- select node will take care of the update */
- ibool in_mysql_interface;
- /* TRUE if the update node was created
- for the MySQL interface */
- dict_foreign_t* foreign;/* NULL or pointer to a foreign key
- constraint if this update node is used in
- doing an ON DELETE or ON UPDATE operation */
- upd_node_t* cascade_node;/* NULL or an update node template which
- is used to implement ON DELETE/UPDATE CASCADE
- or ... SET NULL for foreign keys */
- mem_heap_t* cascade_heap;/* NULL or a mem heap where the cascade
- node is created */
- sel_node_t* select; /* query graph subtree implementing a base
- table cursor: the rows returned will be
- updated */
- btr_pcur_t* pcur; /* persistent cursor placed on the clustered
- index record which should be updated or
- deleted; the cursor is stored in the graph
- of 'select' field above, except in the case
- of the MySQL interface */
- dict_table_t* table; /* table where updated */
- upd_t* update; /* update vector for the row */
- ulint update_n_fields;
- /* when this struct is used to implement
- a cascade operation for foreign keys, we store
- here the size of the buffer allocated for use
- as the update vector */
- sym_node_list_t columns;/* symbol table nodes for the columns
- to retrieve from the table */
- ibool has_clust_rec_x_lock;
- /* TRUE if the select which retrieves the
- records to update already sets an x-lock on
- the clustered record; note that it must always
- set at least an s-lock */
- ulint cmpl_info;/* information extracted during query
- compilation; speeds up execution:
- UPD_NODE_NO_ORD_CHANGE and
- UPD_NODE_NO_SIZE_CHANGE, ORed */
- /*----------------------*/
- /* Local storage for this graph node */
- ulint state; /* node execution state */
- dict_index_t* index; /* NULL, or the next index whose record should
- be updated */
- dtuple_t* row; /* NULL, or a copy (also fields copied to
- heap) of the row to update; this must be reset
- to NULL after a successful update */
- ulint* ext_vec;/* array describing which fields are stored
- externally in the clustered index record of
- row */
- ulint n_ext_vec;/* number of fields in ext_vec */
- mem_heap_t* heap; /* memory heap used as auxiliary storage;
- this must be emptied after a successful
- update */
- /*----------------------*/
- sym_node_t* table_sym;/* table node in symbol table */
- que_node_t* col_assign_list;
- /* column assignment list */
- ulint magic_n;
-};
-
-#define UPD_NODE_MAGIC_N 1579975
-
-/* Node execution states */
-#define UPD_NODE_SET_IX_LOCK 1 /* execution came to the node from
- a node above and if the field
- has_clust_rec_x_lock is FALSE, we
- should set an intention x-lock on
- the table */
-#define UPD_NODE_UPDATE_CLUSTERED 2 /* clustered index record should be
- updated */
-#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
- 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
- looked at and updated if an ordering
- field changed */
-
-/* Compilation info flags: these must fit within 3 bits; see trx0rec.h */
-#define UPD_NODE_NO_ORD_CHANGE 1 /* no secondary index record will be
- changed in the update and no ordering
- field of the clustered index */
-#define UPD_NODE_NO_SIZE_CHANGE 2 /* no record field size will be
- changed in the update */
-
-#ifndef UNIV_NONINL
-#include "row0upd.ic"
-#endif
-
-#endif
diff --git a/storage/innobase/include/row0upd.ic b/storage/innobase/include/row0upd.ic
deleted file mode 100644
index 6173849e68f..00000000000
--- a/storage/innobase/include/row0upd.ic
+++ /dev/null
@@ -1,122 +0,0 @@
-/******************************************************
-Update of a row
-
-(c) 1996 Innobase Oy
-
-Created 12/27/1996 Heikki Tuuri
-*******************************************************/
-
-#include "mtr0log.h"
-#include "trx0trx.h"
-#include "trx0undo.h"
-#include "row0row.h"
-#include "btr0sea.h"
-
-/*************************************************************************
-Creates an update vector object. */
-UNIV_INLINE
-upd_t*
-upd_create(
-/*=======*/
- /* out, own: update vector object */
- ulint n, /* in: number of fields */
- mem_heap_t* heap) /* in: heap from which memory allocated */
-{
- upd_t* update;
- ulint i;
-
- update = mem_heap_alloc(heap, sizeof(upd_t));
-
- update->info_bits = 0;
- update->n_fields = n;
- update->fields = mem_heap_alloc(heap, sizeof(upd_field_t) * n);
-
- for (i = 0; i < n; i++) {
- update->fields[i].extern_storage = 0;
- }
-
- return(update);
-}
-
-/*************************************************************************
-Returns the number of fields in the update vector == number of columns
-to be updated by an update vector. */
-UNIV_INLINE
-ulint
-upd_get_n_fields(
-/*=============*/
- /* out: number of fields */
- upd_t* update) /* in: update vector */
-{
- ut_ad(update);
-
- return(update->n_fields);
-}
-
-/*************************************************************************
-Returns the nth field of an update vector. */
-UNIV_INLINE
-upd_field_t*
-upd_get_nth_field(
-/*==============*/
- /* out: update vector field */
- upd_t* update, /* in: update vector */
- ulint n) /* in: field position in update vector */
-{
- ut_ad(update);
- ut_ad(n < update->n_fields);
-
- return(update->fields + n);
-}
-
-/*************************************************************************
-Sets an index field number to be updated by an update vector field. */
-UNIV_INLINE
-void
-upd_field_set_field_no(
-/*===================*/
- upd_field_t* upd_field, /* in: update vector field */
- ulint field_no, /* in: field number in a clustered
- index */
- dict_index_t* index, /* in: index */
- trx_t* trx) /* in: transaction */
-{
- upd_field->field_no = field_no;
-
- if (UNIV_UNLIKELY(field_no >= dict_index_get_n_fields(index))) {
- fprintf(stderr,
- "InnoDB: Error: trying to access field %lu in ",
- (ulong) field_no);
- dict_index_name_print(stderr, trx, index);
- fprintf(stderr, "\n"
- "InnoDB: but index only has %lu fields\n",
- (ulong) dict_index_get_n_fields(index));
- }
-
- dict_col_copy_type(dict_index_get_nth_col(index, field_no),
- dfield_get_type(&(upd_field->new_val)));
-}
-
-/*************************************************************************
-Updates the trx id and roll ptr field in a clustered index record when
-a row is updated or marked deleted. */
-UNIV_INLINE
-void
-row_upd_rec_sys_fields(
-/*===================*/
- rec_t* rec, /* in: record */
- dict_index_t* index, /* in: clustered index */
- const ulint* offsets,/* in: rec_get_offsets(rec, index) */
- trx_t* trx, /* in: transaction */
- dulint roll_ptr)/* in: roll ptr of the undo log record */
-{
- ut_ad(index->type & DICT_CLUSTERED);
- ut_ad(rec_offs_validate(rec, index, offsets));
-#ifdef UNIV_SYNC_DEBUG
- ut_ad(!buf_block_align(rec)->is_hashed
- || rw_lock_own(&btr_search_latch, RW_LOCK_EX));
-#endif /* UNIV_SYNC_DEBUG */
-
- row_set_rec_trx_id(rec, index, offsets, trx->id);
- row_set_rec_roll_ptr(rec, index, offsets, roll_ptr);
-}
diff --git a/storage/innobase/include/row0vers.h b/storage/innobase/include/row0vers.h
deleted file mode 100644
index e1377112d2a..00000000000
--- a/storage/innobase/include/row0vers.h
+++ /dev/null
@@ -1,126 +0,0 @@
-/******************************************************
-Row versions
-
-(c) 1997 Innobase Oy
-
-Created 2/6/1997 Heikki Tuuri
-*******************************************************/
-
-#ifndef row0vers_h
-#define row0vers_h
-
-#include "univ.i"
-#include "data0data.h"
-#include "dict0types.h"
-#include "trx0types.h"
-#include "que0types.h"
-#include "rem0types.h"
-#include "mtr0mtr.h"
-#include "read0types.h"
-
-/*********************************************************************
-Finds out if an active transaction has inserted or modified a secondary
-index record. NOTE: the kernel mutex is temporarily released in this
-function! */
-
-trx_t*
-row_vers_impl_x_locked_off_kernel(
-/*==============================*/
- /* out: NULL if committed, else the active
- transaction; NOTE that the kernel mutex is
- temporarily released! */
- rec_t* rec, /* in: record in a secondary index */
- dict_index_t* index, /* in: the secondary index */
- const ulint* offsets);/* in: rec_get_offsets(rec, index) */
-/*********************************************************************
-Finds out if we must preserve a delete marked earlier version of a clustered
-index record, because it is >= the purge view. */
-
-ibool
-row_vers_must_preserve_del_marked(
-/*==============================*/
- /* out: TRUE if earlier version should be preserved */
- dulint trx_id, /* in: transaction id in the version */
- mtr_t* mtr); /* in: mtr holding the latch on the clustered index
- record; it will also hold the latch on purge_view */
-/*********************************************************************
-Finds out if a version of the record, where the version >= the current
-purge view, should have ientry as its secondary index entry. We check
-if there is any not delete marked version of the record where the trx
-id >= purge view, and the secondary index entry == ientry; exactly in
-this case we return TRUE. */
-
-ibool
-row_vers_old_has_index_entry(
-/*=========================*/
- /* out: TRUE if earlier version should have */
- ibool also_curr,/* in: TRUE if also rec is included in the
- versions to search; otherwise only versions
- prior to it are searched */
- rec_t* rec, /* in: record in the clustered index; the
- caller must have a latch on the page */
- mtr_t* mtr, /* in: mtr holding the latch on rec; it will
- also hold the latch on purge_view */
- dict_index_t* index, /* in: the secondary index */
- dtuple_t* ientry); /* in: the secondary index entry */
-/*********************************************************************
-Constructs the version of a clustered index record which a consistent
-read should see. We assume that the trx id stored in rec is such that
-the consistent read should not see rec in its present version. */
-
-ulint
-row_vers_build_for_consistent_read(
-/*===============================*/
- /* out: DB_SUCCESS or DB_MISSING_HISTORY */
- rec_t* rec, /* in: record in a clustered index; the
- caller must have a latch on the page; this
- latch locks the top of the stack of versions
- of this records */
- mtr_t* mtr, /* in: mtr holding the latch on rec; it will
- also hold the latch on purge_view */
- dict_index_t* index, /* in: the clustered index */
- ulint** offsets,/* in/out: offsets returned by
- rec_get_offsets(rec, index) */
- read_view_t* view, /* in: the consistent read view */
- mem_heap_t** offset_heap,/* in/out: memory heap from which
- the offsets are allocated */
- mem_heap_t* in_heap,/* in: memory heap from which the memory for
- old_vers is allocated; memory for possible
- intermediate versions is allocated and freed
- locally within the function */
- rec_t** old_vers);/* out, own: old version, or NULL if the
- record does not exist in the view, that is,
- it was freshly inserted afterwards */
-
-/*********************************************************************
-Constructs the last committed version of a clustered index record,
-which should be seen by a semi-consistent read. */
-
-ulint
-row_vers_build_for_semi_consistent_read(
-/*====================================*/
- /* out: DB_SUCCESS or DB_MISSING_HISTORY */
- rec_t* rec, /* in: record in a clustered index; the
- caller must have a latch on the page; this
- latch locks the top of the stack of versions
- of this records */
- mtr_t* mtr, /* in: mtr holding the latch on rec */
- dict_index_t* index, /* in: the clustered index */
- ulint** offsets,/* in/out: offsets returned by
- rec_get_offsets(rec, index) */
- mem_heap_t** offset_heap,/* in/out: memory heap from which
- the offsets are allocated */
- mem_heap_t* in_heap,/* in: memory heap from which the memory for
- old_vers is allocated; memory for possible
- intermediate versions is allocated and freed
- locally within the function */
- rec_t** old_vers);/* out, own: rec, old version, or NULL if the
- record does not exist in the view, that is,
- it was freshly inserted afterwards */
-
-
-#ifndef UNIV_NONINL
-#include "row0vers.ic"
-#endif
-
-#endif
diff --git a/storage/innobase/include/row0vers.ic b/storage/innobase/include/row0vers.ic
deleted file mode 100644
index ab1e264635b..00000000000
--- a/storage/innobase/include/row0vers.ic
+++ /dev/null
@@ -1,13 +0,0 @@
-/******************************************************
-Row versions
-
-(c) 1997 Innobase Oy
-
-Created 2/6/1997 Heikki Tuuri
-*******************************************************/
-
-#include "row0row.h"
-#include "dict0dict.h"
-#include "read0read.h"
-#include "page0page.h"
-#include "log0recv.h"
diff --git a/storage/innobase/include/srv0que.h b/storage/innobase/include/srv0que.h
deleted file mode 100644
index 05c339cdd32..00000000000
--- a/storage/innobase/include/srv0que.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/******************************************************
-Server query execution
-
-(c) 1996 Innobase Oy
-
-Created 6/5/1996 Heikki Tuuri
-*******************************************************/
-
-
-#ifndef srv0que_h
-#define srv0que_h
-
-#include "univ.i"
-#include "que0types.h"
-
-/**************************************************************************
-Checks if there is work to do in the server task queue. If there is, the
-thread starts processing a task. Before leaving, it again checks the task
-queue and picks a new task if any exists. This is called by a SRV_WORKER
-thread. */
-
-void
-srv_que_task_queue_check(void);
-/*==========================*/
-/**************************************************************************
-Performs round-robin on the server tasks. This is called by a SRV_WORKER
-thread every second or so. */
-
-que_thr_t*
-srv_que_round_robin(
-/*================*/
- /* out: the new (may be == thr) query thread
- to run */
- que_thr_t* thr); /* in: query thread */
-/**************************************************************************
-Enqueues a task to server task queue and releases a worker thread, if
-there exists one suspended. */
-
-void
-srv_que_task_enqueue(
-/*=================*/
- que_thr_t* thr); /* in: query thread */
-/**************************************************************************
-Enqueues a task to server task queue and releases a worker thread, if
-there exists one suspended. */
-
-void
-srv_que_task_enqueue_low(
-/*=====================*/
- que_thr_t* thr); /* in: query thread */
-
-#endif
-
diff --git a/storage/innobase/include/srv0srv.h b/storage/innobase/include/srv0srv.h
deleted file mode 100644
index 05300e38430..00000000000
--- a/storage/innobase/include/srv0srv.h
+++ /dev/null
@@ -1,572 +0,0 @@
-/******************************************************
-The server main program
-
-(c) 1995 Innobase Oy
-
-Created 10/10/1995 Heikki Tuuri
-*******************************************************/
-
-
-#ifndef srv0srv_h
-#define srv0srv_h
-
-#include "univ.i"
-#include "sync0sync.h"
-#include "os0sync.h"
-#include "que0types.h"
-#include "trx0types.h"
-
-extern const char* srv_main_thread_op_info;
-
-/* Prefix used by MySQL to indicate pre-5.1 table name encoding */
-extern const char srv_mysql50_table_name_prefix[9];
-
-/* When this event is set the lock timeout and InnoDB monitor
-thread starts running */
-extern os_event_t srv_lock_timeout_thread_event;
-
-/* If the last data file is auto-extended, we add this many pages to it
-at a time */
-#define SRV_AUTO_EXTEND_INCREMENT \
- (srv_auto_extend_increment * ((1024 * 1024) / UNIV_PAGE_SIZE))
-
-/* This is set to TRUE if the MySQL user has set it in MySQL */
-extern ibool srv_lower_case_table_names;
-
-/* Mutex for locking srv_monitor_file */
-extern mutex_t srv_monitor_file_mutex;
-/* Temporary file for innodb monitor output */
-extern FILE* srv_monitor_file;
-/* Mutex for locking srv_dict_tmpfile.
-This mutex has a very high rank; threads reserving it should not
-be holding any InnoDB latches. */
-extern mutex_t srv_dict_tmpfile_mutex;
-/* Temporary file for output from the data dictionary */
-extern FILE* srv_dict_tmpfile;
-/* Mutex for locking srv_misc_tmpfile.
-This mutex has a very low rank; threads reserving it should not
-acquire any further latches or sleep before releasing this one. */
-extern mutex_t srv_misc_tmpfile_mutex;
-/* Temporary file for miscellanous diagnostic output */
-extern FILE* srv_misc_tmpfile;
-
-/* Server parameters which are read from the initfile */
-
-extern char* srv_data_home;
-#ifdef UNIV_LOG_ARCHIVE
-extern char* srv_arch_dir;
-#endif /* UNIV_LOG_ARCHIVE */
-
-extern ibool srv_file_per_table;
-extern ibool srv_locks_unsafe_for_binlog;
-
-extern ulint srv_n_data_files;
-extern char** srv_data_file_names;
-extern ulint* srv_data_file_sizes;
-extern ulint* srv_data_file_is_raw_partition;
-
-extern ibool srv_auto_extend_last_data_file;
-extern ulint srv_last_file_size_max;
-extern ulong srv_auto_extend_increment;
-
-extern ibool srv_created_new_raw;
-
-#define SRV_NEW_RAW 1
-#define SRV_OLD_RAW 2
-
-extern char** srv_log_group_home_dirs;
-
-extern ulint srv_n_log_groups;
-extern ulint srv_n_log_files;
-extern ulint srv_log_file_size;
-extern ulint srv_log_buffer_size;
-extern ulong srv_flush_log_at_trx_commit;
-
-extern byte srv_latin1_ordering[256];/* The sort order table of the latin1
- character set */
-extern ulint srv_pool_size;
-extern ulint srv_awe_window_size;
-extern ulint srv_mem_pool_size;
-extern ulint srv_lock_table_size;
-
-extern ibool srv_thread_concurrency_timer_based;
-
-/* Number of background IO threads for read and write. Replaces
- * srv_n_file_io_threads. */
-extern ulint srv_n_read_io_threads;
-extern ulint srv_n_write_io_threads;
-/* Max number of adjacent IO requests to merge into one large request. */
-extern ulint srv_max_merged_io;
-
-/* Number of IO operations per second the server can do */
-extern ulint srv_io_capacity;
-
-/* Flush dirty pages when below max dirty percent */
-extern ibool srv_extra_dirty_writes;
-
-
-
-#ifdef UNIV_LOG_ARCHIVE
-extern ibool srv_log_archive_on;
-extern ibool srv_archive_recovery;
-extern dulint srv_archive_recovery_limit_lsn;
-#endif /* UNIV_LOG_ARCHIVE */
-
-extern ulint srv_lock_wait_timeout;
-
-extern char* srv_file_flush_method_str;
-extern ulint srv_unix_file_flush_method;
-extern ulint srv_win_file_flush_method;
-
-extern ulint srv_max_n_open_files;
-
-extern ulint srv_max_dirty_pages_pct;
-
-extern ulint srv_force_recovery;
-extern ulong srv_thread_concurrency;
-extern ulong srv_commit_concurrency;
-
-extern ulint srv_max_n_threads;
-
-extern lint srv_conc_n_threads;
-
-extern ulint srv_fast_shutdown; /* If this is 1, do not do a
- purge and index buffer merge.
- If this 2, do not even flush the
- buffer pool to data files at the
- shutdown: we effectively 'crash'
- InnoDB (but lose no committed
- transactions). */
-extern ibool srv_innodb_status;
-
-extern ibool srv_use_doublewrite_buf;
-extern ibool srv_use_checksums;
-
-extern ibool srv_set_thread_priorities;
-extern int srv_query_thread_priority;
-
-extern ulong srv_max_buf_pool_modified_pct;
-extern ulong srv_max_purge_lag;
-extern ibool srv_use_awe;
-extern ibool srv_use_adaptive_hash_indexes;
-/*-------------------------------------------*/
-
-extern ulint srv_n_rows_inserted;
-extern ulint srv_n_rows_updated;
-extern ulint srv_n_rows_deleted;
-extern ulint srv_n_rows_read;
-
-extern ibool srv_print_innodb_monitor;
-extern ibool srv_print_innodb_lock_monitor;
-extern ibool srv_print_innodb_tablespace_monitor;
-extern ibool srv_print_verbose_log;
-extern ibool srv_print_innodb_table_monitor;
-
-extern ibool srv_lock_timeout_and_monitor_active;
-extern ibool srv_error_monitor_active;
-
-extern ulong srv_n_spin_wait_rounds;
-extern ulong srv_n_free_tickets_to_enter;
-extern ulong srv_thread_sleep_delay;
-extern ulint srv_spin_wait_delay;
-extern ibool srv_priority_boost;
-
-extern ulint srv_pool_size;
-extern ulint srv_mem_pool_size;
-extern ulint srv_lock_table_size;
-
-extern ibool srv_print_thread_releases;
-extern ibool srv_print_lock_waits;
-extern ibool srv_print_buf_io;
-extern ibool srv_print_log_io;
-extern ibool srv_print_latch_waits;
-
-extern ulint srv_activity_count;
-extern ulint srv_fatal_semaphore_wait_threshold;
-extern ulint srv_dml_needed_delay;
-
-extern mutex_t* kernel_mutex_temp;/* mutex protecting the server, trx structs,
- query threads, and lock table: we allocate
- it from dynamic memory to get it to the
- same DRAM page as other hotspot semaphores */
-#define kernel_mutex (*kernel_mutex_temp)
-
-#define SRV_MAX_N_IO_THREADS 100
-
-/* Array of English strings describing the current state of an
-i/o handler thread */
-extern const char* srv_io_thread_op_info[];
-extern const char* srv_io_thread_function[];
-
-/* the number of the log write requests done */
-extern ulint srv_log_write_requests;
-
-/* the number of physical writes to the log performed */
-extern ulint srv_log_writes;
-
-/* amount of data written to the log files in bytes */
-extern ulint srv_os_log_written;
-
-/* amount of writes being done to the log files */
-extern ulint srv_os_log_pending_writes;
-
-/* we increase this counter, when there we don't have enough space in the
-log buffer and have to flush it */
-extern ulint srv_log_waits;
-
-/* variable that counts amount of data read in total (in bytes) */
-extern ulint srv_data_read;
-
-/* here we count the amount of data written in total (in bytes) */
-extern ulint srv_data_written;
-
-/* this variable counts the amount of times, when the doublewrite buffer
-was flushed */
-extern ulint srv_dblwr_writes;
-
-/* here we store the number of pages that have been flushed to the
-doublewrite buffer */
-extern ulint srv_dblwr_pages_written;
-
-/* in this variable we store the number of write requests issued */
-extern ulint srv_buf_pool_write_requests;
-
-/* here we store the number of times when we had to wait for a free page
-in the buffer pool. It happens when the buffer pool is full and we need
-to make a flush, in order to be able to read or create a page. */
-extern ulint srv_buf_pool_wait_free;
-
-/* variable to count the number of pages that were written from the
-buffer pool to disk */
-extern ulint srv_buf_pool_flushed;
-
-/* variable to count the number of buffer pool reads that led to the
-reading of a disk page */
-extern ulint srv_buf_pool_reads;
-
-/* variable to count the number of sequential read-aheads were done */
-extern ulint srv_read_ahead_seq;
-
-/* variable to count the number of random read-aheads were done */
-extern ulint srv_read_ahead_rnd;
-
-/* Number of threads that may have missed a lock wait wakeup */
-extern ulint sync_wake_ups;
-
-/* An option to enable the fix for "Bug#43660 SHOW INDEXES/ANALYZE does
-NOT update cardinality for indexes of InnoDB table". By default we are
-running with the fix disabled because MySQL 5.1 is frozen for such
-behavioral changes. */
-extern char srv_use_legacy_cardinality_algorithm;
-
-/* In this structure we store status variables to be passed to MySQL */
-typedef struct export_var_struct export_struc;
-
-extern export_struc export_vars;
-
-typedef struct srv_sys_struct srv_sys_t;
-
-/* The server system */
-extern srv_sys_t* srv_sys;
-
-/* Alternatives for the file flush option in Unix; see the InnoDB manual
-about what these mean */
-#define SRV_UNIX_FSYNC 1 /* This is the default */
-#define SRV_UNIX_O_DSYNC 2
-#define SRV_UNIX_LITTLESYNC 3
-#define SRV_UNIX_NOSYNC 4
-#define SRV_UNIX_O_DIRECT 5
-
-/* Alternatives for file i/o in Windows */
-#define SRV_WIN_IO_NORMAL 1
-#define SRV_WIN_IO_UNBUFFERED 2 /* This is the default */
-
-/* Alternatives for srv_force_recovery. Non-zero values are intended
-to help the user get a damaged database up so that he can dump intact
-tables and rows with SELECT INTO OUTFILE. The database must not otherwise
-be used with these options! A bigger number below means that all precautions
-of lower numbers are included. */
-
-#define SRV_FORCE_IGNORE_CORRUPT 1 /* let the server run even if it
- detects a corrupt page */
-#define SRV_FORCE_NO_BACKGROUND 2 /* prevent the main thread from
- running: if a crash would occur
- in purge, this prevents it */
-#define SRV_FORCE_NO_TRX_UNDO 3 /* do not run trx rollback after
- recovery */
-#define SRV_FORCE_NO_IBUF_MERGE 4 /* prevent also ibuf operations:
- if they would cause a crash, better
- not do them */
-#define SRV_FORCE_NO_UNDO_LOG_SCAN 5 /* do not look at undo logs when
- starting the database: InnoDB will
- treat even incomplete transactions
- as committed */
-#define SRV_FORCE_NO_LOG_REDO 6 /* do not do the log roll-forward
- in connection with recovery */
-
-/*************************************************************************
-Boots Innobase server. */
-
-ulint
-srv_boot(void);
-/*==========*/
- /* out: DB_SUCCESS or error code */
-/*************************************************************************
-Initializes the server. */
-
-void
-srv_init(void);
-/*==========*/
-/*************************************************************************
-Frees the OS fast mutex created in srv_boot(). */
-
-void
-srv_free(void);
-/*==========*/
-/*************************************************************************
-Initializes the synchronization primitives, memory system, and the thread
-local storage. */
-
-void
-srv_general_init(void);
-/*==================*/
-/*************************************************************************
-Gets the number of threads in the system. */
-
-ulint
-srv_get_n_threads(void);
-/*===================*/
-/*************************************************************************
-Returns the calling thread type. */
-
-ulint
-srv_get_thread_type(void);
-/*=====================*/
- /* out: SRV_COM, ... */
-/*************************************************************************
-Sets the info describing an i/o thread current state. */
-
-void
-srv_set_io_thread_op_info(
-/*======================*/
- ulint i, /* in: the 'segment' of the i/o thread */
- const char* str); /* in: constant char string describing the
- state */
-/*************************************************************************
-Releases threads of the type given from suspension in the thread table.
-NOTE! The server mutex has to be reserved by the caller! */
-
-ulint
-srv_release_threads(
-/*================*/
- /* out: number of threads released: this may be
- < n if not enough threads were suspended at the
- moment */
- ulint type, /* in: thread type */
- ulint n); /* in: number of threads to release */
-/*************************************************************************
-The master thread controlling the server. */
-
-os_thread_ret_t
-srv_master_thread(
-/*==============*/
- /* out: a dummy parameter */
- void* arg); /* in: a dummy parameter required by
- os_thread_create */
-/***********************************************************************
-Tells the Innobase server that there has been activity in the database
-and wakes up the master thread if it is suspended (not sleeping). Used
-in the MySQL interface. Note that there is a small chance that the master
-thread stays suspended (we do not protect our operation with the kernel
-mutex, for performace reasons). */
-
-void
-srv_active_wake_master_thread(void);
-/*===============================*/
-/***********************************************************************
-Wakes up the master thread if it is suspended or being suspended. */
-
-void
-srv_wake_master_thread(void);
-/*========================*/
-/*************************************************************************
-Puts an OS thread to wait if there are too many concurrent threads
-(>= srv_thread_concurrency) inside InnoDB. The threads wait in a FIFO queue. */
-
-void
-srv_conc_enter_innodb(
-/*==================*/
- trx_t* trx); /* in: transaction object associated with the
- thread */
-/*************************************************************************
-This lets a thread enter InnoDB regardless of the number of threads inside
-InnoDB. This must be called when a thread ends a lock wait. */
-
-void
-srv_conc_force_enter_innodb(
-/*========================*/
- trx_t* trx); /* in: transaction object associated with the
- thread */
-/*************************************************************************
-This must be called when a thread exits InnoDB in a lock wait or at the
-end of an SQL statement. */
-
-void
-srv_conc_force_exit_innodb(
-/*=======================*/
- trx_t* trx); /* in: transaction object associated with the
- thread */
-/*************************************************************************
-This must be called when a thread exits InnoDB. */
-
-void
-srv_conc_exit_innodb(
-/*=================*/
- trx_t* trx); /* in: transaction object associated with the
- thread */
-/*******************************************************************
-Puts a MySQL OS thread to wait for a lock to be released. If an error
-occurs during the wait trx->error_state associated with thr is
-!= DB_SUCCESS when we return. DB_LOCK_WAIT_TIMEOUT and DB_DEADLOCK
-are possible errors. DB_DEADLOCK is returned if selective deadlock
-resolution chose this transaction as a victim. */
-
-void
-srv_suspend_mysql_thread(
-/*=====================*/
- que_thr_t* thr); /* in: query thread associated with the MySQL
- OS thread */
-/************************************************************************
-Releases a MySQL OS thread waiting for a lock to be released, if the
-thread is already suspended. */
-
-void
-srv_release_mysql_thread_if_suspended(
-/*==================================*/
- que_thr_t* thr); /* in: query thread associated with the
- MySQL OS thread */
-/*************************************************************************
-A thread which wakes up threads whose lock wait may have lasted too long.
-This also prints the info output by various InnoDB monitors. */
-
-os_thread_ret_t
-srv_lock_timeout_and_monitor_thread(
-/*================================*/
- /* out: a dummy parameter */
- void* arg); /* in: a dummy parameter required by
- os_thread_create */
-/*************************************************************************
-A thread which prints warnings about semaphore waits which have lasted
-too long. These can be used to track bugs which cause hangs. */
-
-os_thread_ret_t
-srv_error_monitor_thread(
-/*=====================*/
- /* out: a dummy parameter */
- void* arg); /* in: a dummy parameter required by
- os_thread_create */
-/**********************************************************************
-Outputs to a file the output of the InnoDB Monitor. */
-
-void
-srv_printf_innodb_monitor(
-/*======================*/
- FILE* file); /* in: output stream */
-
-/**********************************************************************
-Function to pass InnoDB status variables to MySQL */
-
-void
-srv_export_innodb_status(void);
-/*=====================*/
-
-/* Types for the threads existing in the system. Threads of types 4 - 9
-are called utility threads. Note that utility threads are mainly disk
-bound, except that version threads 6 - 7 may also be CPU bound, if
-cleaning versions from the buffer pool. */
-
-#define SRV_COM 1 /* threads serving communication and queries */
-#define SRV_CONSOLE 2 /* thread serving console */
-#define SRV_WORKER 3 /* threads serving parallelized queries and
- queries released from lock wait */
-#define SRV_BUFFER 4 /* thread flushing dirty buffer blocks,
- not currently in use */
-#define SRV_RECOVERY 5 /* threads finishing a recovery,
- not currently in use */
-#define SRV_INSERT 6 /* thread flushing the insert buffer to disk,
- not currently in use */
-#define SRV_MASTER 7 /* the master thread, (whose type number must
- be biggest) */
-
-/* Thread slot in the thread table */
-typedef struct srv_slot_struct srv_slot_t;
-
-/* Thread table is an array of slots */
-typedef srv_slot_t srv_table_t;
-
-/* In this structure we store status variables to be passed to MySQL */
-struct export_var_struct{
- ulint innodb_data_pending_reads;
- ulint innodb_data_pending_writes;
- ulint innodb_data_pending_fsyncs;
- ulint innodb_data_fsyncs;
- ulint innodb_data_read;
- ulint innodb_data_writes;
- ulint innodb_data_written;
- ulint innodb_data_reads;
- ulint innodb_buffer_pool_pages_total;
- ulint innodb_buffer_pool_pages_data;
- ulint innodb_buffer_pool_pages_dirty;
- ulint innodb_buffer_pool_pages_misc;
- ulint innodb_buffer_pool_pages_free;
-#ifdef UNIV_DEBUG
- ulint innodb_buffer_pool_pages_latched;
-#endif /* UNIV_DEBUG */
- ulint innodb_buffer_pool_read_requests;
- ulint innodb_buffer_pool_reads;
- ulint innodb_buffer_pool_wait_free;
- ulint innodb_buffer_pool_pages_flushed;
- ulint innodb_buffer_pool_write_requests;
- ulint innodb_buffer_pool_read_ahead_seq;
- ulint innodb_buffer_pool_read_ahead_rnd;
- ulint innodb_dblwr_pages_written;
- ulint innodb_dblwr_writes;
- ibool innodb_have_sync_atomic;
- ibool innodb_heap_enabled;
- ulint innodb_log_waits;
- ulint innodb_log_write_requests;
- ulint innodb_log_writes;
- ulint innodb_os_log_written;
- ulint innodb_os_log_fsyncs;
- ulint innodb_os_log_pending_writes;
- ulint innodb_os_log_pending_fsyncs;
- ulint innodb_page_size;
- ulint innodb_pages_created;
- ulint innodb_pages_read;
- ulint innodb_pages_written;
- ulint innodb_row_lock_waits;
- ulint innodb_row_lock_current_waits;
- ib_longlong innodb_row_lock_time;
- ulint innodb_row_lock_time_avg;
- ulint innodb_row_lock_time_max;
- ulint innodb_rows_read;
- ulint innodb_rows_inserted;
- ulint innodb_rows_updated;
- ulint innodb_rows_deleted;
- ulint innodb_wake_ups;
-};
-
-/* The server system struct */
-struct srv_sys_struct{
- srv_table_t* threads; /* server thread table */
- UT_LIST_BASE_NODE_T(que_thr_t)
- tasks; /* task queue */
- dict_index_t* dummy_ind1; /* dummy index for old-style
- supremum and infimum records */
- dict_index_t* dummy_ind2; /* dummy index for new-style
- supremum and infimum records */
-};
-
-extern ulint srv_n_threads_active[];
-
-#endif
diff --git a/storage/innobase/include/srv0srv.ic b/storage/innobase/include/srv0srv.ic
deleted file mode 100644
index 73e0729660f..00000000000
--- a/storage/innobase/include/srv0srv.ic
+++ /dev/null
@@ -1,7 +0,0 @@
-/******************************************************
-Server main program
-
-(c) 1995 Innobase Oy
-
-Created 10/4/1995 Heikki Tuuri
-*******************************************************/
diff --git a/storage/innobase/include/srv0start.h b/storage/innobase/include/srv0start.h
deleted file mode 100644
index a04930d6516..00000000000
--- a/storage/innobase/include/srv0start.h
+++ /dev/null
@@ -1,112 +0,0 @@
-/******************************************************
-Starts the Innobase database server
-
-(c) 1995-2000 Innobase Oy
-
-Created 10/10/1995 Heikki Tuuri
-*******************************************************/
-
-
-#ifndef srv0start_h
-#define srv0start_h
-
-#include "univ.i"
-#include "ut0byte.h"
-
-/*************************************************************************
-Normalizes a directory path for Windows: converts slashes to backslashes. */
-
-void
-srv_normalize_path_for_win(
-/*=======================*/
- char* str); /* in/out: null-terminated character string */
-/*************************************************************************
-Reads the data files and their sizes from a character string given in
-the .cnf file. */
-
-ibool
-srv_parse_data_file_paths_and_sizes(
-/*================================*/
- /* out: TRUE if ok, FALSE if parsing
- error */
- char* str, /* in: the data file path string */
- char*** data_file_names, /* out, own: array of data file
- names */
- ulint** data_file_sizes, /* out, own: array of data file sizes
- in megabytes */
- ulint** data_file_is_raw_partition,/* out, own: array of flags
- showing which data files are raw
- partitions */
- ulint* n_data_files, /* out: number of data files */
- ibool* is_auto_extending, /* out: TRUE if the last data file is
- auto-extending */
- ulint* max_auto_extend_size); /* out: max auto extend size for the
- last file if specified, 0 if not */
-/*************************************************************************
-Reads log group home directories from a character string given in
-the .cnf file. */
-
-ibool
-srv_parse_log_group_home_dirs(
-/*==========================*/
- /* out: TRUE if ok, FALSE if parsing
- error */
- char* str, /* in: character string */
- char*** log_group_home_dirs); /* out, own: log group home dirs */
-/*************************************************************************
-Adds a slash or a backslash to the end of a string if it is missing
-and the string is not empty. */
-
-char*
-srv_add_path_separator_if_needed(
-/*=============================*/
- /* out: string which has the separator if the
- string is not empty */
- char* str); /* in: null-terminated character string */
-/********************************************************************
-Starts Innobase and creates a new database if database files
-are not found and the user wants. Server parameters are
-read from a file of name "srv_init" in the ib_home directory. */
-
-int
-innobase_start_or_create_for_mysql(void);
-/*====================================*/
- /* out: DB_SUCCESS or error code */
-/********************************************************************
-Shuts down the Innobase database. */
-int
-innobase_shutdown_for_mysql(void);
-/*=============================*/
- /* out: DB_SUCCESS or error code */
-extern dulint srv_shutdown_lsn;
-extern dulint srv_start_lsn;
-
-#ifdef __NETWARE__
-void set_panic_flag_for_netware(void);
-#endif
-
-#ifdef HAVE_DARWIN_THREADS
-extern ibool srv_have_fullfsync;
-#endif
-
-extern ulint srv_sizeof_trx_t_in_ha_innodb_cc;
-
-extern ibool srv_is_being_started;
-extern ibool srv_startup_is_before_trx_rollback_phase;
-extern ibool srv_is_being_shut_down;
-
-extern ibool srv_start_raw_disk_in_use;
-
-/* At a shutdown the value first climbs from 0 to SRV_SHUTDOWN_CLEANUP
-and then to SRV_SHUTDOWN_LAST_PHASE, and so on */
-
-extern ulint srv_shutdown_state;
-
-#define SRV_SHUTDOWN_CLEANUP 1
-#define SRV_SHUTDOWN_LAST_PHASE 2
-#define SRV_SHUTDOWN_EXIT_THREADS 3
-
-/* Log 'spaces' have id's >= this */
-#define SRV_LOG_SPACE_FIRST_ID 0xFFFFFFF0UL
-
-#endif
diff --git a/storage/innobase/include/sync0arr.ic b/storage/innobase/include/sync0arr.ic
deleted file mode 100644
index dbe35c033e5..00000000000
--- a/storage/innobase/include/sync0arr.ic
+++ /dev/null
@@ -1,10 +0,0 @@
-/******************************************************
-The wait array for synchronization primitives
-
-Inline code
-
-(c) 1995 Innobase Oy
-
-Created 9/5/1995 Heikki Tuuri
-*******************************************************/
-
diff --git a/storage/innobase/include/sync0types.h b/storage/innobase/include/sync0types.h
deleted file mode 100644
index 57478426f25..00000000000
--- a/storage/innobase/include/sync0types.h
+++ /dev/null
@@ -1,16 +0,0 @@
-/******************************************************
-Global types for sync
-
-(c) 1995 Innobase Oy
-
-Created 9/5/1995 Heikki Tuuri
-*******************************************************/
-
-#ifndef sync0types_h
-#define sync0types_h
-
-#define mutex_t ib_mutex_t
-typedef struct mutex_struct mutex_t;
-
-
-#endif
diff --git a/storage/innobase/include/thr0loc.ic b/storage/innobase/include/thr0loc.ic
deleted file mode 100644
index b8b8136180c..00000000000
--- a/storage/innobase/include/thr0loc.ic
+++ /dev/null
@@ -1,7 +0,0 @@
-/******************************************************
-Thread local storage
-
-(c) 1995 Innobase Oy
-
-Created 10/4/1995 Heikki Tuuri
-*******************************************************/
diff --git a/storage/innobase/include/trx0purge.ic b/storage/innobase/include/trx0purge.ic
deleted file mode 100644
index 9f1c0ed96f8..00000000000
--- a/storage/innobase/include/trx0purge.ic
+++ /dev/null
@@ -1,26 +0,0 @@
-/******************************************************
-Purge old versions
-
-(c) 1996 Innobase Oy
-
-Created 3/26/1996 Heikki Tuuri
-*******************************************************/
-
-#include "trx0undo.h"
-
-/************************************************************************
-Calculates the file address of an undo log header when we have the file
-address of its history list node. */
-UNIV_INLINE
-fil_addr_t
-trx_purge_get_log_from_hist(
-/*========================*/
- /* out: file address of the log */
- fil_addr_t node_addr) /* in: file address of the history
- list node of the log */
-{
- node_addr.boffset -= TRX_UNDO_HISTORY_NODE;
-
- return(node_addr);
-}
-
diff --git a/storage/innobase/include/trx0rec.h b/storage/innobase/include/trx0rec.h
deleted file mode 100644
index 6447b6a2e35..00000000000
--- a/storage/innobase/include/trx0rec.h
+++ /dev/null
@@ -1,303 +0,0 @@
-/******************************************************
-Transaction undo log record
-
-(c) 1996 Innobase Oy
-
-Created 3/26/1996 Heikki Tuuri
-*******************************************************/
-
-#ifndef trx0rec_h
-#define trx0rec_h
-
-#include "univ.i"
-#include "trx0types.h"
-#include "row0types.h"
-#include "mtr0mtr.h"
-#include "trx0sys.h"
-#include "dict0types.h"
-#include "que0types.h"
-#include "data0data.h"
-#include "rem0types.h"
-
-/***************************************************************************
-Copies the undo record to the heap. */
-UNIV_INLINE
-trx_undo_rec_t*
-trx_undo_rec_copy(
-/*==============*/
- /* out, own: copy of undo log record */
- trx_undo_rec_t* undo_rec, /* in: undo log record */
- mem_heap_t* heap); /* in: heap where copied */
-/**************************************************************************
-Reads the undo log record type. */
-UNIV_INLINE
-ulint
-trx_undo_rec_get_type(
-/*==================*/
- /* out: record type */
- trx_undo_rec_t* undo_rec); /* in: undo log record */
-/**************************************************************************
-Reads from an undo log record the record compiler info. */
-UNIV_INLINE
-ulint
-trx_undo_rec_get_cmpl_info(
-/*=======================*/
- /* out: compiler info */
- trx_undo_rec_t* undo_rec); /* in: undo log record */
-/**************************************************************************
-Returns TRUE if an undo log record contains an extern storage field. */
-UNIV_INLINE
-ibool
-trx_undo_rec_get_extern_storage(
-/*============================*/
- /* out: TRUE if extern */
- trx_undo_rec_t* undo_rec); /* in: undo log record */
-/**************************************************************************
-Reads the undo log record number. */
-UNIV_INLINE
-dulint
-trx_undo_rec_get_undo_no(
-/*=====================*/
- /* out: undo no */
- trx_undo_rec_t* undo_rec); /* in: undo log record */
-/**************************************************************************
-Reads from an undo log record the general parameters. */
-
-byte*
-trx_undo_rec_get_pars(
-/*==================*/
- /* out: remaining part of undo log
- record after reading these values */
- trx_undo_rec_t* undo_rec, /* in: undo log record */
- ulint* type, /* out: undo record type:
- TRX_UNDO_INSERT_REC, ... */
- ulint* cmpl_info, /* out: compiler info, relevant only
- for update type records */
- ibool* updated_extern, /* out: TRUE if we updated an
- externally stored fild */
- dulint* undo_no, /* out: undo log record number */
- dulint* table_id); /* out: table id */
-/***********************************************************************
-Builds a row reference from an undo log record. */
-
-byte*
-trx_undo_rec_get_row_ref(
-/*=====================*/
- /* out: pointer to remaining part of undo
- record */
- byte* ptr, /* in: remaining part of a copy of an undo log
- record, at the start of the row reference;
- NOTE that this copy of the undo log record must
- be preserved as long as the row reference is
- used, as we do NOT copy the data in the
- record! */
- dict_index_t* index, /* in: clustered index */
- dtuple_t** ref, /* out, own: row reference */
- mem_heap_t* heap); /* in: memory heap from which the memory
- needed is allocated */
-/***********************************************************************
-Skips a row reference from an undo log record. */
-
-byte*
-trx_undo_rec_skip_row_ref(
-/*======================*/
- /* out: pointer to remaining part of undo
- record */
- byte* ptr, /* in: remaining part in update undo log
- record, at the start of the row reference */
- dict_index_t* index); /* in: clustered index */
-/**************************************************************************
-Reads from an undo log update record the system field values of the old
-version. */
-
-byte*
-trx_undo_update_rec_get_sys_cols(
-/*=============================*/
- /* out: remaining part of undo log
- record after reading these values */
- byte* ptr, /* in: remaining part of undo log
- record after reading general
- parameters */
- dulint* trx_id, /* out: trx id */
- dulint* roll_ptr, /* out: roll ptr */
- ulint* info_bits); /* out: info bits state */
-/***********************************************************************
-Builds an update vector based on a remaining part of an undo log record. */
-
-byte*
-trx_undo_update_rec_get_update(
-/*===========================*/
- /* out: remaining part of the record,
- NULL if an error detected, which means that
- the record is corrupted */
- byte* ptr, /* in: remaining part in update undo log
- record, after reading the row reference
- NOTE that this copy of the undo log record must
- be preserved as long as the update vector is
- used, as we do NOT copy the data in the
- record! */
- dict_index_t* index, /* in: clustered index */
- ulint type, /* in: TRX_UNDO_UPD_EXIST_REC,
- TRX_UNDO_UPD_DEL_REC, or
- TRX_UNDO_DEL_MARK_REC; in the last case,
- only trx id and roll ptr fields are added to
- the update vector */
- dulint trx_id, /* in: transaction id from this undorecord */
- dulint roll_ptr,/* in: roll pointer from this undo record */
- ulint info_bits,/* in: info bits from this undo record */
- trx_t* trx, /* in: transaction */
- mem_heap_t* heap, /* in: memory heap from which the memory
- needed is allocated */
- upd_t** upd); /* out, own: update vector */
-/***********************************************************************
-Builds a partial row from an update undo log record. It contains the
-columns which occur as ordering in any index of the table. */
-
-byte*
-trx_undo_rec_get_partial_row(
-/*=========================*/
- /* out: pointer to remaining part of undo
- record */
- byte* ptr, /* in: remaining part in update undo log
- record of a suitable type, at the start of
- the stored index columns;
- NOTE that this copy of the undo log record must
- be preserved as long as the partial row is
- used, as we do NOT copy the data in the
- record! */
- dict_index_t* index, /* in: clustered index */
- dtuple_t** row, /* out, own: partial row */
- mem_heap_t* heap); /* in: memory heap from which the memory
- needed is allocated */
-/***************************************************************************
-Writes information to an undo log about an insert, update, or a delete marking
-of a clustered index record. This information is used in a rollback of the
-transaction and in consistent reads that must look to the history of this
-transaction. */
-
-ulint
-trx_undo_report_row_operation(
-/*==========================*/
- /* out: DB_SUCCESS or error code */
- ulint flags, /* in: if BTR_NO_UNDO_LOG_FLAG bit is
- set, does nothing */
- ulint op_type, /* in: TRX_UNDO_INSERT_OP or
- TRX_UNDO_MODIFY_OP */
- que_thr_t* thr, /* in: query thread */
- dict_index_t* index, /* in: clustered index */
- dtuple_t* clust_entry, /* in: in the case of an insert,
- index entry to insert into the
- clustered index, otherwise NULL */
- upd_t* update, /* in: in the case of an update,
- the update vector, otherwise NULL */
- ulint cmpl_info, /* in: compiler info on secondary
- index updates */
- rec_t* rec, /* in: case of an update or delete
- marking, the record in the clustered
- index, otherwise NULL */
- dulint* roll_ptr); /* out: rollback pointer to the
- inserted undo log record,
- ut_dulint_zero if BTR_NO_UNDO_LOG
- flag was specified */
-/**********************************************************************
-Copies an undo record to heap. This function can be called if we know that
-the undo log record exists. */
-
-trx_undo_rec_t*
-trx_undo_get_undo_rec_low(
-/*======================*/
- /* out, own: copy of the record */
- dulint roll_ptr, /* in: roll pointer to record */
- mem_heap_t* heap); /* in: memory heap where copied */
-/**********************************************************************
-Copies an undo record to heap. */
-
-ulint
-trx_undo_get_undo_rec(
-/*==================*/
- /* out: DB_SUCCESS, or
- DB_MISSING_HISTORY if the undo log
- has been truncated and we cannot
- fetch the old version; NOTE: the
- caller must have latches on the
- clustered index page and purge_view */
- dulint roll_ptr, /* in: roll pointer to record */
- dulint trx_id, /* in: id of the trx that generated
- the roll pointer: it points to an
- undo log of this transaction */
- trx_undo_rec_t** undo_rec, /* out, own: copy of the record */
- mem_heap_t* heap); /* in: memory heap where copied */
-/***********************************************************************
-Build a previous version of a clustered index record. This function checks
-that the caller has a latch on the index page of the clustered index record
-and an s-latch on the purge_view. This guarantees that the stack of versions
-is locked. */
-
-ulint
-trx_undo_prev_version_build(
-/*========================*/
- /* out: DB_SUCCESS, or DB_MISSING_HISTORY if
- the previous version is not >= purge_view,
- which means that it may have been removed,
- DB_ERROR if corrupted record */
- rec_t* index_rec,/* in: clustered index record in the
- index tree */
- mtr_t* index_mtr,/* in: mtr which contains the latch to
- index_rec page and purge_view */
- rec_t* rec, /* in: version of a clustered index record */
- dict_index_t* index, /* in: clustered index */
- ulint* offsets,/* in: rec_get_offsets(rec, index) */
- mem_heap_t* heap, /* in: memory heap from which the memory
- needed is allocated */
- rec_t** old_vers);/* out, own: previous version, or NULL if
- rec is the first inserted version, or if
- history data has been deleted */
-/***************************************************************
-Parses a redo log record of adding an undo log record. */
-
-byte*
-trx_undo_parse_add_undo_rec(
-/*========================*/
- /* out: end of log record or NULL */
- byte* ptr, /* in: buffer */
- byte* end_ptr,/* in: buffer end */
- page_t* page); /* in: page or NULL */
-/***************************************************************
-Parses a redo log record of erasing of an undo page end. */
-
-byte*
-trx_undo_parse_erase_page_end(
-/*==========================*/
- /* out: end of log record or NULL */
- byte* ptr, /* in: buffer */
- byte* end_ptr,/* in: buffer end */
- page_t* page, /* in: page or NULL */
- mtr_t* mtr); /* in: mtr or NULL */
-
-/* Types of an undo log record: these have to be smaller than 16, as the
-compilation info multiplied by 16 is ORed to this value in an undo log
-record */
-#define TRX_UNDO_INSERT_REC 11 /* fresh insert into clustered index */
-#define TRX_UNDO_UPD_EXIST_REC 12 /* update of a non-delete-marked
- record */
-#define TRX_UNDO_UPD_DEL_REC 13 /* update of a delete marked record to
- a not delete marked record; also the
- fields of the record can change */
-#define TRX_UNDO_DEL_MARK_REC 14 /* delete marking of a record; fields
- do not change */
-#define TRX_UNDO_CMPL_INFO_MULT 16 /* compilation info is multiplied by
- this and ORed to the type above */
-#define TRX_UNDO_UPD_EXTERN 128 /* This bit can be ORed to type_cmpl
- to denote that we updated external
- storage fields: used by purge to
- free the external storage */
-
-/* Operation type flags used in trx_undo_report_row_operation */
-#define TRX_UNDO_INSERT_OP 1
-#define TRX_UNDO_MODIFY_OP 2
-
-#ifndef UNIV_NONINL
-#include "trx0rec.ic"
-#endif
-
-#endif
diff --git a/storage/innobase/include/trx0rec.ic b/storage/innobase/include/trx0rec.ic
deleted file mode 100644
index a1ddc127ec7..00000000000
--- a/storage/innobase/include/trx0rec.ic
+++ /dev/null
@@ -1,86 +0,0 @@
-/******************************************************
-Transaction undo log record
-
-(c) 1996 Innobase Oy
-
-Created 3/26/1996 Heikki Tuuri
-*******************************************************/
-
-/**************************************************************************
-Reads from an undo log record the record type. */
-UNIV_INLINE
-ulint
-trx_undo_rec_get_type(
-/*==================*/
- /* out: record type */
- trx_undo_rec_t* undo_rec) /* in: undo log record */
-{
- return(mach_read_from_1(undo_rec + 2) & (TRX_UNDO_CMPL_INFO_MULT - 1));
-}
-
-/**************************************************************************
-Reads from an undo log record the record compiler info. */
-UNIV_INLINE
-ulint
-trx_undo_rec_get_cmpl_info(
-/*=======================*/
- /* out: compiler info */
- trx_undo_rec_t* undo_rec) /* in: undo log record */
-{
- return(mach_read_from_1(undo_rec + 2) / TRX_UNDO_CMPL_INFO_MULT);
-}
-
-/**************************************************************************
-Returns TRUE if an undo log record contains an extern storage field. */
-UNIV_INLINE
-ibool
-trx_undo_rec_get_extern_storage(
-/*============================*/
- /* out: TRUE if extern */
- trx_undo_rec_t* undo_rec) /* in: undo log record */
-{
- if (mach_read_from_1(undo_rec + 2) & TRX_UNDO_UPD_EXTERN) {
-
- return(TRUE);
- }
-
- return(FALSE);
-}
-
-/**************************************************************************
-Reads the undo log record number. */
-UNIV_INLINE
-dulint
-trx_undo_rec_get_undo_no(
-/*=====================*/
- /* out: undo no */
- trx_undo_rec_t* undo_rec) /* in: undo log record */
-{
- byte* ptr;
-
- ptr = undo_rec + 3;
-
- return(mach_dulint_read_much_compressed(ptr));
-}
-
-/***************************************************************************
-Copies the undo record to the heap. */
-UNIV_INLINE
-trx_undo_rec_t*
-trx_undo_rec_copy(
-/*==============*/
- /* out, own: copy of undo log record */
- trx_undo_rec_t* undo_rec, /* in: undo log record */
- mem_heap_t* heap) /* in: heap where copied */
-{
- ulint len;
- trx_undo_rec_t* rec_copy;
-
- len = mach_read_from_2(undo_rec) + buf_frame_align(undo_rec)
- - undo_rec;
- rec_copy = mem_heap_alloc(heap, len);
-
- ut_memcpy(rec_copy, undo_rec, len);
-
- return(rec_copy);
-}
diff --git a/storage/innobase/include/trx0roll.h b/storage/innobase/include/trx0roll.h
deleted file mode 100644
index c1eca3d5753..00000000000
--- a/storage/innobase/include/trx0roll.h
+++ /dev/null
@@ -1,314 +0,0 @@
-/******************************************************
-Transaction rollback
-
-(c) 1996 Innobase Oy
-
-Created 3/26/1996 Heikki Tuuri
-*******************************************************/
-
-#ifndef trx0roll_h
-#define trx0roll_h
-
-#include "univ.i"
-#include "trx0trx.h"
-#include "trx0types.h"
-#include "mtr0mtr.h"
-#include "trx0sys.h"
-
-#define trx_roll_free_all_savepoints(s) trx_roll_savepoints_free((s), NULL)
-
-/***********************************************************************
-Returns a transaction savepoint taken at this point in time. */
-
-trx_savept_t
-trx_savept_take(
-/*============*/
- /* out: savepoint */
- trx_t* trx); /* in: transaction */
-/***********************************************************************
-Creates an undo number array. */
-
-trx_undo_arr_t*
-trx_undo_arr_create(void);
-/*=====================*/
-/***********************************************************************
-Frees an undo number array. */
-
-void
-trx_undo_arr_free(
-/*==============*/
- trx_undo_arr_t* arr); /* in: undo number array */
-/***********************************************************************
-Returns pointer to nth element in an undo number array. */
-UNIV_INLINE
-trx_undo_inf_t*
-trx_undo_arr_get_nth_info(
-/*======================*/
- /* out: pointer to the nth element */
- trx_undo_arr_t* arr, /* in: undo number array */
- ulint n); /* in: position */
-/***************************************************************************
-Tries truncate the undo logs. */
-
-void
-trx_roll_try_truncate(
-/*==================*/
- trx_t* trx); /* in: transaction */
-/************************************************************************
-Pops the topmost record when the two undo logs of a transaction are seen
-as a single stack of records ordered by their undo numbers. Inserts the
-undo number of the popped undo record to the array of currently processed
-undo numbers in the transaction. When the query thread finishes processing
-of this undo record, it must be released with trx_undo_rec_release. */
-
-trx_undo_rec_t*
-trx_roll_pop_top_rec_of_trx(
-/*========================*/
- /* out: undo log record copied to heap, NULL
- if none left, or if the undo number of the
- top record would be less than the limit */
- trx_t* trx, /* in: transaction */
- dulint limit, /* in: least undo number we need */
- dulint* roll_ptr,/* out: roll pointer to undo record */
- mem_heap_t* heap); /* in: memory heap where copied */
-/************************************************************************
-Reserves an undo log record for a query thread to undo. This should be
-called if the query thread gets the undo log record not using the pop
-function above. */
-
-ibool
-trx_undo_rec_reserve(
-/*=================*/
- /* out: TRUE if succeeded */
- trx_t* trx, /* in: transaction */
- dulint undo_no);/* in: undo number of the record */
-/***********************************************************************
-Releases a reserved undo record. */
-
-void
-trx_undo_rec_release(
-/*=================*/
- trx_t* trx, /* in: transaction */
- dulint undo_no);/* in: undo number */
-/*************************************************************************
-Starts a rollback operation. */
-
-void
-trx_rollback(
-/*=========*/
- trx_t* trx, /* in: transaction */
- trx_sig_t* sig, /* in: signal starting the rollback */
- que_thr_t** next_thr);/* in/out: next query thread to run;
- if the value which is passed in is
- a pointer to a NULL pointer, then the
- calling function can start running
- a new query thread */
-/***********************************************************************
-Rollback or clean up transactions which have no user session. If the
-transaction already was committed, then we clean up a possible insert
-undo log. If the transaction was not yet committed, then we roll it back.
-Note: this is done in a background thread. */
-
-os_thread_ret_t
-trx_rollback_or_clean_all_without_sess(
-/*===================================*/
- /* out: a dummy parameter */
- void* arg __attribute__((unused)));
- /* in: a dummy parameter required by
- os_thread_create */
-/********************************************************************
-Finishes a transaction rollback. */
-
-void
-trx_finish_rollback_off_kernel(
-/*===========================*/
- que_t* graph, /* in: undo graph which can now be freed */
- trx_t* trx, /* in: transaction */
- que_thr_t** next_thr);/* in/out: next query thread to run;
- if the value which is passed in is
- a pointer to a NULL pointer, then the
- calling function can start running
- a new query thread; if this parameter is
- NULL, it is ignored */
-/********************************************************************
-Builds an undo 'query' graph for a transaction. The actual rollback is
-performed by executing this query graph like a query subprocedure call.
-The reply about the completion of the rollback will be sent by this
-graph. */
-
-que_t*
-trx_roll_graph_build(
-/*=================*/
- /* out, own: the query graph */
- trx_t* trx); /* in: trx handle */
-/*************************************************************************
-Creates a rollback command node struct. */
-
-roll_node_t*
-roll_node_create(
-/*=============*/
- /* out, own: rollback node struct */
- mem_heap_t* heap); /* in: mem heap where created */
-/***************************************************************
-Performs an execution step for a rollback command node in a query graph. */
-
-que_thr_t*
-trx_rollback_step(
-/*==============*/
- /* out: query thread to run next, or NULL */
- que_thr_t* thr); /* in: query thread */
-/***********************************************************************
-Rollback a transaction used in MySQL. */
-
-int
-trx_rollback_for_mysql(
-/*===================*/
- /* out: error code or DB_SUCCESS */
- trx_t* trx); /* in: transaction handle */
-/***********************************************************************
-Rollback the latest SQL statement for MySQL. */
-
-int
-trx_rollback_last_sql_stat_for_mysql(
-/*=================================*/
- /* out: error code or DB_SUCCESS */
- trx_t* trx); /* in: transaction handle */
-/***********************************************************************
-Rollback a transaction used in MySQL. */
-
-int
-trx_general_rollback_for_mysql(
-/*===========================*/
- /* out: error code or DB_SUCCESS */
- trx_t* trx, /* in: transaction handle */
- ibool partial,/* in: TRUE if partial rollback requested */
- trx_savept_t* savept);/* in: pointer to savepoint undo number, if
- partial rollback requested */
-/***********************************************************************
-Rolls back a transaction back to a named savepoint. Modifications after the
-savepoint are undone but InnoDB does NOT release the corresponding locks
-which are stored in memory. If a lock is 'implicit', that is, a new inserted
-row holds a lock where the lock information is carried by the trx id stored in
-the row, these locks are naturally released in the rollback. Savepoints which
-were set after this savepoint are deleted. */
-
-ulint
-trx_rollback_to_savepoint_for_mysql(
-/*================================*/
- /* out: if no savepoint
- of the name found then
- DB_NO_SAVEPOINT,
- otherwise DB_SUCCESS */
- trx_t* trx, /* in: transaction handle */
- const char* savepoint_name, /* in: savepoint name */
- ib_longlong* mysql_binlog_cache_pos);/* out: the MySQL binlog cache
- position corresponding to this
- savepoint; MySQL needs this
- information to remove the
- binlog entries of the queries
- executed after the savepoint */
-/***********************************************************************
-Creates a named savepoint. If the transaction is not yet started, starts it.
-If there is already a savepoint of the same name, this call erases that old
-savepoint and replaces it with a new. Savepoints are deleted in a transaction
-commit or rollback. */
-
-ulint
-trx_savepoint_for_mysql(
-/*====================*/
- /* out: always DB_SUCCESS */
- trx_t* trx, /* in: transaction handle */
- const char* savepoint_name, /* in: savepoint name */
- ib_longlong binlog_cache_pos); /* in: MySQL binlog cache
- position corresponding to this
- connection at the time of the
- savepoint */
-
-/***********************************************************************
-Releases a named savepoint. Savepoints which
-were set after this savepoint are deleted. */
-
-ulint
-trx_release_savepoint_for_mysql(
-/*============================*/
- /* out: if no savepoint
- of the name found then
- DB_NO_SAVEPOINT,
- otherwise DB_SUCCESS */
- trx_t* trx, /* in: transaction handle */
- const char* savepoint_name); /* in: savepoint name */
-
-/***********************************************************************
-Frees a single savepoint struct. */
-
-void
-trx_roll_savepoint_free(
-/*=====================*/
- trx_t* trx, /* in: transaction handle */
- trx_named_savept_t* savep); /* in: savepoint to free */
-
-/***********************************************************************
-Frees savepoint structs starting from savep, if savep == NULL then
-free all savepoints. */
-
-void
-trx_roll_savepoints_free(
-/*=====================*/
- trx_t* trx, /* in: transaction handle */
- trx_named_savept_t* savep); /* in: free all savepoints > this one;
- if this is NULL, free all savepoints
- of trx */
-
-extern sess_t* trx_dummy_sess;
-
-/* A cell in the array used during a rollback and a purge */
-struct trx_undo_inf_struct{
- dulint trx_no; /* transaction number: not defined during
- a rollback */
- dulint undo_no; /* undo number of an undo record */
- ibool in_use; /* TRUE if the cell is in use */
-};
-
-/* During a rollback and a purge, undo numbers of undo records currently being
-processed are stored in this array */
-
-struct trx_undo_arr_struct{
- ulint n_cells; /* number of cells in the array */
- ulint n_used; /* number of cells currently in use */
- trx_undo_inf_t* infos; /* the array of undo infos */
- mem_heap_t* heap; /* memory heap from which allocated */
-};
-
-/* Rollback command node in a query graph */
-struct roll_node_struct{
- que_common_t common; /* node type: QUE_NODE_ROLLBACK */
- ulint state; /* node execution state */
- ibool partial;/* TRUE if we want a partial rollback */
- trx_savept_t savept; /* savepoint to which to roll back, in the
- case of a partial rollback */
-};
-
-/* A savepoint set with SQL's "SAVEPOINT savepoint_id" command */
-struct trx_named_savept_struct{
- char* name; /* savepoint name */
- trx_savept_t savept; /* the undo number corresponding to
- the savepoint */
- ib_longlong mysql_binlog_cache_pos;
- /* the MySQL binlog cache position
- corresponding to this savepoint, not
- defined if the MySQL binlogging is not
- enabled */
- UT_LIST_NODE_T(trx_named_savept_t)
- trx_savepoints; /* the list of savepoints of a
- transaction */
-};
-
-/* Rollback node states */
-#define ROLL_NODE_SEND 1
-#define ROLL_NODE_WAIT 2
-
-#ifndef UNIV_NONINL
-#include "trx0roll.ic"
-#endif
-
-#endif
diff --git a/storage/innobase/include/trx0roll.ic b/storage/innobase/include/trx0roll.ic
deleted file mode 100644
index dfde83ac478..00000000000
--- a/storage/innobase/include/trx0roll.ic
+++ /dev/null
@@ -1,23 +0,0 @@
-/******************************************************
-Transaction rollback
-
-(c) 1996 Innobase Oy
-
-Created 3/26/1996 Heikki Tuuri
-*******************************************************/
-
-/***********************************************************************
-Returns pointer to nth element in an undo number array. */
-UNIV_INLINE
-trx_undo_inf_t*
-trx_undo_arr_get_nth_info(
-/*======================*/
- /* out: pointer to the nth element */
- trx_undo_arr_t* arr, /* in: undo number array */
- ulint n) /* in: position */
-{
- ut_ad(arr);
- ut_ad(n < arr->n_cells);
-
- return(arr->infos + n);
-}
diff --git a/storage/innobase/include/trx0rseg.ic b/storage/innobase/include/trx0rseg.ic
deleted file mode 100644
index eb1893587a6..00000000000
--- a/storage/innobase/include/trx0rseg.ic
+++ /dev/null
@@ -1,126 +0,0 @@
-/******************************************************
-Rollback segment
-
-(c) 1996 Innobase Oy
-
-Created 3/26/1996 Heikki Tuuri
-*******************************************************/
-
-#include "srv0srv.h"
-
-/**********************************************************************
-Gets a rollback segment header. */
-UNIV_INLINE
-trx_rsegf_t*
-trx_rsegf_get(
-/*==========*/
- /* out: rollback segment header, page
- x-latched */
- ulint space, /* in: space where placed */
- ulint page_no, /* in: page number of the header */
- mtr_t* mtr) /* in: mtr */
-{
- trx_rsegf_t* header;
-
- header = TRX_RSEG + buf_page_get(space, page_no, RW_X_LATCH, mtr);
-
-#ifdef UNIV_SYNC_DEBUG
- buf_page_dbg_add_level(header, SYNC_RSEG_HEADER);
-#endif /* UNIV_SYNC_DEBUG */
-
- return(header);
-}
-
-/**********************************************************************
-Gets a newly created rollback segment header. */
-UNIV_INLINE
-trx_rsegf_t*
-trx_rsegf_get_new(
-/*==============*/
- /* out: rollback segment header, page
- x-latched */
- ulint space, /* in: space where placed */
- ulint page_no, /* in: page number of the header */
- mtr_t* mtr) /* in: mtr */
-{
- trx_rsegf_t* header;
-
- header = TRX_RSEG + buf_page_get(space, page_no, RW_X_LATCH, mtr);
-
-#ifdef UNIV_SYNC_DEBUG
- buf_page_dbg_add_level(header, SYNC_RSEG_HEADER_NEW);
-#endif /* UNIV_SYNC_DEBUG */
-
- return(header);
-}
-
-/*******************************************************************
-Gets the file page number of the nth undo log slot. */
-UNIV_INLINE
-ulint
-trx_rsegf_get_nth_undo(
-/*===================*/
- /* out: page number of the undo log segment */
- trx_rsegf_t* rsegf, /* in: rollback segment header */
- ulint n, /* in: index of slot */
- mtr_t* mtr) /* in: mtr */
-{
- if (UNIV_UNLIKELY(n >= TRX_RSEG_N_SLOTS)) {
- fprintf(stderr,
- "InnoDB: Error: trying to get slot %lu of rseg\n",
- (ulong) n);
- ut_error;
- }
-
- return(mtr_read_ulint(rsegf + TRX_RSEG_UNDO_SLOTS
- + n * TRX_RSEG_SLOT_SIZE, MLOG_4BYTES, mtr));
-}
-
-/*******************************************************************
-Sets the file page number of the nth undo log slot. */
-UNIV_INLINE
-void
-trx_rsegf_set_nth_undo(
-/*===================*/
- trx_rsegf_t* rsegf, /* in: rollback segment header */
- ulint n, /* in: index of slot */
- ulint page_no,/* in: page number of the undo log segment */
- mtr_t* mtr) /* in: mtr */
-{
- if (UNIV_UNLIKELY(n >= TRX_RSEG_N_SLOTS)) {
- fprintf(stderr,
- "InnoDB: Error: trying to set slot %lu of rseg\n",
- (ulong) n);
- ut_error;
- }
-
- mlog_write_ulint(rsegf + TRX_RSEG_UNDO_SLOTS + n * TRX_RSEG_SLOT_SIZE,
- page_no, MLOG_4BYTES, mtr);
-}
-
-/********************************************************************
-Looks for a free slot for an undo log segment. */
-UNIV_INLINE
-ulint
-trx_rsegf_undo_find_free(
-/*=====================*/
- /* out: slot index or ULINT_UNDEFINED if not
- found */
- trx_rsegf_t* rsegf, /* in: rollback segment header */
- mtr_t* mtr) /* in: mtr */
-{
- ulint i;
- ulint page_no;
-
- for (i = 0; i < TRX_RSEG_N_SLOTS; i++) {
-
- page_no = trx_rsegf_get_nth_undo(rsegf, i, mtr);
-
- if (page_no == FIL_NULL) {
-
- return(i);
- }
- }
-
- return(ULINT_UNDEFINED);
-}
diff --git a/storage/innobase/include/trx0sys.h b/storage/innobase/include/trx0sys.h
deleted file mode 100644
index a8da5cd51a3..00000000000
--- a/storage/innobase/include/trx0sys.h
+++ /dev/null
@@ -1,453 +0,0 @@
-/******************************************************
-Transaction system
-
-(c) 1996 Innobase Oy
-
-Created 3/26/1996 Heikki Tuuri
-*******************************************************/
-
-#ifndef trx0sys_h
-#define trx0sys_h
-
-#include "univ.i"
-
-#include "trx0types.h"
-#include "mtr0mtr.h"
-#include "mtr0log.h"
-#include "ut0byte.h"
-#include "mem0mem.h"
-#include "sync0sync.h"
-#include "ut0lst.h"
-#include "buf0buf.h"
-#include "fil0fil.h"
-#include "fut0lst.h"
-#include "fsp0fsp.h"
-#include "read0types.h"
-
-/* In a MySQL replication slave, in crash recovery we store the master log
-file name and position here. We have successfully got the updates to InnoDB
-up to this position. If .._pos is -1, it means no crash recovery was needed,
-or there was no master log position info inside InnoDB. */
-
-extern char trx_sys_mysql_master_log_name[];
-extern ib_longlong trx_sys_mysql_master_log_pos;
-
-/* If this MySQL server uses binary logging, after InnoDB has been inited
-and if it has done a crash recovery, we store the binlog file name and position
-here. If .._pos is -1, it means there was no binlog position info inside
-InnoDB. */
-
-extern char trx_sys_mysql_bin_log_name[];
-extern ib_longlong trx_sys_mysql_bin_log_pos;
-
-/* The transaction system */
-extern trx_sys_t* trx_sys;
-
-/* Doublewrite system */
-extern trx_doublewrite_t* trx_doublewrite;
-extern ibool trx_doublewrite_must_reset_space_ids;
-extern ibool trx_sys_multiple_tablespace_format;
-
-/********************************************************************
-Creates the doublewrite buffer to a new InnoDB installation. The header of the
-doublewrite buffer is placed on the trx system header page. */
-
-void
-trx_sys_create_doublewrite_buf(void);
-/*================================*/
-/********************************************************************
-At a database startup initializes the doublewrite buffer memory structure if
-we already have a doublewrite buffer created in the data files. If we are
-upgrading to an InnoDB version which supports multiple tablespaces, then this
-function performs the necessary update operations. If we are in a crash
-recovery, this function uses a possible doublewrite buffer to restore
-half-written pages in the data files. */
-
-void
-trx_sys_doublewrite_init_or_restore_pages(
-/*======================================*/
- ibool restore_corrupt_pages);
-/********************************************************************
-Marks the trx sys header when we have successfully upgraded to the >= 4.1.x
-multiple tablespace format. */
-
-void
-trx_sys_mark_upgraded_to_multiple_tablespaces(void);
-/*===============================================*/
-/********************************************************************
-Determines if a page number is located inside the doublewrite buffer. */
-
-ibool
-trx_doublewrite_page_inside(
-/*========================*/
- /* out: TRUE if the location is inside
- the two blocks of the doublewrite buffer */
- ulint page_no); /* in: page number */
-/*******************************************************************
-Checks if a page address is the trx sys header page. */
-UNIV_INLINE
-ibool
-trx_sys_hdr_page(
-/*=============*/
- /* out: TRUE if trx sys header page */
- ulint space, /* in: space */
- ulint page_no);/* in: page number */
-/*********************************************************************
-Creates and initializes the central memory structures for the transaction
-system. This is called when the database is started. */
-
-void
-trx_sys_init_at_db_start(void);
-/*==========================*/
-/*********************************************************************
-Creates and initializes the transaction system at the database creation. */
-
-void
-trx_sys_create(void);
-/*================*/
-/********************************************************************
-Looks for a free slot for a rollback segment in the trx system file copy. */
-
-ulint
-trx_sysf_rseg_find_free(
-/*====================*/
- /* out: slot index or ULINT_UNDEFINED
- if not found */
- mtr_t* mtr); /* in: mtr */
-/*******************************************************************
-Gets the pointer in the nth slot of the rseg array. */
-UNIV_INLINE
-trx_rseg_t*
-trx_sys_get_nth_rseg(
-/*=================*/
- /* out: pointer to rseg object, NULL if slot
- not in use */
- trx_sys_t* sys, /* in: trx system */
- ulint n); /* in: index of slot */
-/*******************************************************************
-Sets the pointer in the nth slot of the rseg array. */
-UNIV_INLINE
-void
-trx_sys_set_nth_rseg(
-/*=================*/
- trx_sys_t* sys, /* in: trx system */
- ulint n, /* in: index of slot */
- trx_rseg_t* rseg); /* in: pointer to rseg object, NULL if slot
- not in use */
-/**************************************************************************
-Gets a pointer to the transaction system file copy and x-locks its page. */
-UNIV_INLINE
-trx_sysf_t*
-trx_sysf_get(
-/*=========*/
- /* out: pointer to system file copy, page x-locked */
- mtr_t* mtr); /* in: mtr */
-/*********************************************************************
-Gets the space of the nth rollback segment slot in the trx system
-file copy. */
-UNIV_INLINE
-ulint
-trx_sysf_rseg_get_space(
-/*====================*/
- /* out: space id */
- trx_sysf_t* sys_header, /* in: trx sys file copy */
- ulint i, /* in: slot index == rseg id */
- mtr_t* mtr); /* in: mtr */
-/*********************************************************************
-Gets the page number of the nth rollback segment slot in the trx system
-file copy. */
-UNIV_INLINE
-ulint
-trx_sysf_rseg_get_page_no(
-/*======================*/
- /* out: page number, FIL_NULL
- if slot unused */
- trx_sysf_t* sys_header, /* in: trx sys file copy */
- ulint i, /* in: slot index == rseg id */
- mtr_t* mtr); /* in: mtr */
-/*********************************************************************
-Sets the space id of the nth rollback segment slot in the trx system
-file copy. */
-UNIV_INLINE
-void
-trx_sysf_rseg_set_space(
-/*====================*/
- trx_sysf_t* sys_header, /* in: trx sys file copy */
- ulint i, /* in: slot index == rseg id */
- ulint space, /* in: space id */
- mtr_t* mtr); /* in: mtr */
-/*********************************************************************
-Sets the page number of the nth rollback segment slot in the trx system
-file copy. */
-UNIV_INLINE
-void
-trx_sysf_rseg_set_page_no(
-/*======================*/
- trx_sysf_t* sys_header, /* in: trx sys file copy */
- ulint i, /* in: slot index == rseg id */
- ulint page_no, /* in: page number, FIL_NULL if
- the slot is reset to unused */
- mtr_t* mtr); /* in: mtr */
-/*********************************************************************
-Allocates a new transaction id. */
-UNIV_INLINE
-dulint
-trx_sys_get_new_trx_id(void);
-/*========================*/
- /* out: new, allocated trx id */
-/*********************************************************************
-Allocates a new transaction number. */
-UNIV_INLINE
-dulint
-trx_sys_get_new_trx_no(void);
-/*========================*/
- /* out: new, allocated trx number */
-/*********************************************************************
-Writes a trx id to an index page. In case that the id size changes in
-some future version, this function should be used instead of
-mach_write_... */
-UNIV_INLINE
-void
-trx_write_trx_id(
-/*=============*/
- byte* ptr, /* in: pointer to memory where written */
- dulint id); /* in: id */
-/*********************************************************************
-Reads a trx id from an index page. In case that the id size changes in
-some future version, this function should be used instead of
-mach_read_... */
-UNIV_INLINE
-dulint
-trx_read_trx_id(
-/*============*/
- /* out: id */
- byte* ptr); /* in: pointer to memory from where to read */
-/********************************************************************
-Looks for the trx handle with the given id in trx_list. */
-UNIV_INLINE
-trx_t*
-trx_get_on_id(
-/*==========*/
- /* out: the trx handle or NULL if not found */
- dulint trx_id); /* in: trx id to search for */
-/********************************************************************
-Returns the minumum trx id in trx list. This is the smallest id for which
-the trx can possibly be active. (But, you must look at the trx->conc_state to
-find out if the minimum trx id transaction itself is active, or already
-committed.) */
-UNIV_INLINE
-dulint
-trx_list_get_min_trx_id(void);
-/*=========================*/
- /* out: the minimum trx id, or trx_sys->max_trx_id
- if the trx list is empty */
-/********************************************************************
-Checks if a transaction with the given id is active. */
-UNIV_INLINE
-ibool
-trx_is_active(
-/*==========*/
- /* out: TRUE if active */
- dulint trx_id);/* in: trx id of the transaction */
-/********************************************************************
-Checks that trx is in the trx list. */
-
-ibool
-trx_in_trx_list(
-/*============*/
- /* out: TRUE if is in */
- trx_t* in_trx);/* in: trx */
-/*********************************************************************
-Updates the offset information about the end of the MySQL binlog entry
-which corresponds to the transaction just being committed. In a MySQL
-replication slave updates the latest master binlog position up to which
-replication has proceeded. */
-
-void
-trx_sys_update_mysql_binlog_offset(
-/*===============================*/
- const char* file_name,/* in: MySQL log file name */
- ib_longlong offset, /* in: position in that log file */
- ulint field, /* in: offset of the MySQL log info field in
- the trx sys header */
- mtr_t* mtr); /* in: mtr */
-/*********************************************************************
-Prints to stderr the MySQL binlog offset info in the trx system header if
-the magic number shows it valid. */
-
-void
-trx_sys_print_mysql_binlog_offset(void);
-/*===================================*/
-#ifdef UNIV_HOTBACKUP
-/*********************************************************************
-Prints to stderr the MySQL binlog info in the system header if the
-magic number shows it valid. */
-
-void
-trx_sys_print_mysql_binlog_offset_from_page(
-/*========================================*/
- byte* page); /* in: buffer containing the trx system header page,
- i.e., page number TRX_SYS_PAGE_NO in the tablespace */
-#endif /* UNIV_HOTBACKUP */
-/*********************************************************************
-Prints to stderr the MySQL master log offset info in the trx system header if
-the magic number shows it valid. */
-
-void
-trx_sys_print_mysql_master_log_pos(void);
-/*====================================*/
-
-/* The automatically created system rollback segment has this id */
-#define TRX_SYS_SYSTEM_RSEG_ID 0
-
-/* Space id and page no where the trx system file copy resides */
-#define TRX_SYS_SPACE 0 /* the SYSTEM tablespace */
-#define TRX_SYS_PAGE_NO FSP_TRX_SYS_PAGE_NO
-
-/* The offset of the transaction system header on the page */
-#define TRX_SYS FSEG_PAGE_DATA
-
-/* Transaction system header */
-/*-------------------------------------------------------------*/
-#define TRX_SYS_TRX_ID_STORE 0 /* the maximum trx id or trx number
- modulo TRX_SYS_TRX_ID_UPDATE_MARGIN
- written to a file page by any
- transaction; the assignment of
- transaction ids continues from this
- number rounded up by .._MARGIN plus
- .._MARGIN when the database is
- started */
-#define TRX_SYS_FSEG_HEADER 8 /* segment header for the tablespace
- segment the trx system is created
- into */
-#define TRX_SYS_RSEGS (8 + FSEG_HEADER_SIZE)
- /* the start of the array of rollback
- segment specification slots */
-/*-------------------------------------------------------------*/
-
-/* Max number of rollback segments: the number of segment specification slots
-in the transaction system array; rollback segment id must fit in one byte,
-therefore 256; each slot is currently 8 bytes in size */
-#define TRX_SYS_N_RSEGS 256
-
-#define TRX_SYS_MYSQL_LOG_NAME_LEN 512
-#define TRX_SYS_MYSQL_LOG_MAGIC_N 873422344
-
-/* The offset of the MySQL replication info in the trx system header;
-this contains the same fields as TRX_SYS_MYSQL_LOG_INFO below */
-#define TRX_SYS_MYSQL_MASTER_LOG_INFO (UNIV_PAGE_SIZE - 2000)
-
-/* The offset of the MySQL binlog offset info in the trx system header */
-#define TRX_SYS_MYSQL_LOG_INFO (UNIV_PAGE_SIZE - 1000)
-#define TRX_SYS_MYSQL_LOG_MAGIC_N_FLD 0 /* magic number which shows
- if we have valid data in the
- MySQL binlog info; the value
- is ..._MAGIC_N if yes */
-#define TRX_SYS_MYSQL_LOG_OFFSET_HIGH 4 /* high 4 bytes of the offset
- within that file */
-#define TRX_SYS_MYSQL_LOG_OFFSET_LOW 8 /* low 4 bytes of the offset
- within that file */
-#define TRX_SYS_MYSQL_LOG_NAME 12 /* MySQL log file name */
-
-/* The offset of the doublewrite buffer header on the trx system header page */
-#define TRX_SYS_DOUBLEWRITE (UNIV_PAGE_SIZE - 200)
-/*-------------------------------------------------------------*/
-#define TRX_SYS_DOUBLEWRITE_FSEG 0 /* fseg header of the fseg
- containing the doublewrite
- buffer */
-#define TRX_SYS_DOUBLEWRITE_MAGIC FSEG_HEADER_SIZE
- /* 4-byte magic number which
- shows if we already have
- created the doublewrite
- buffer */
-#define TRX_SYS_DOUBLEWRITE_BLOCK1 (4 + FSEG_HEADER_SIZE)
- /* page number of the
- first page in the first
- sequence of 64
- (= FSP_EXTENT_SIZE) consecutive
- pages in the doublewrite
- buffer */
-#define TRX_SYS_DOUBLEWRITE_BLOCK2 (8 + FSEG_HEADER_SIZE)
- /* page number of the
- first page in the second
- sequence of 64 consecutive
- pages in the doublewrite
- buffer */
-#define TRX_SYS_DOUBLEWRITE_REPEAT 12 /* we repeat the above 3
- numbers so that if the trx
- sys header is half-written
- to disk, we still may be able
- to recover the information */
-#define TRX_SYS_DOUBLEWRITE_SPACE_ID_STORED (24 + FSEG_HEADER_SIZE)
- /* If this is not yet set to
- .._N, we must reset the
- doublewrite buffer, because
- starting from 4.1.x the space
- id of a data page is stored to
- FIL_PAGE_ARCH_LOG_NO_OR_SPACE_NO */
-/*-------------------------------------------------------------*/
-#define TRX_SYS_DOUBLEWRITE_MAGIC_N 536853855
-#define TRX_SYS_DOUBLEWRITE_SPACE_ID_STORED_N 1783657386
-
-
-#define TRX_SYS_DOUBLEWRITE_BLOCK_SIZE FSP_EXTENT_SIZE
-
-/* Doublewrite control struct */
-struct trx_doublewrite_struct{
- mutex_t mutex; /* mutex protecting the first_free field and
- write_buf */
- ulint block1; /* the page number of the first
- doublewrite block (64 pages) */
- ulint block2; /* page number of the second block */
- ulint first_free; /* first free position in write_buf measured
- in units of UNIV_PAGE_SIZE */
- byte* write_buf; /* write buffer used in writing to the
- doublewrite buffer, aligned to an
- address divisible by UNIV_PAGE_SIZE
- (which is required by Windows aio) */
- byte* write_buf_unaligned; /* pointer to write_buf, but unaligned */
- buf_block_t**
- buf_block_arr; /* array to store pointers to the buffer
- blocks which have been cached to write_buf */
-};
-
-/* The transaction system central memory data structure; protected by the
-kernel mutex */
-struct trx_sys_struct{
- dulint max_trx_id; /* The smallest number not yet
- assigned as a transaction id or
- transaction number */
- UT_LIST_BASE_NODE_T(trx_t) trx_list;
- /* List of active and committed in
- memory transactions, sorted on trx id,
- biggest first */
- UT_LIST_BASE_NODE_T(trx_t) mysql_trx_list;
- /* List of transactions created
- for MySQL */
- UT_LIST_BASE_NODE_T(trx_rseg_t) rseg_list;
- /* List of rollback segment objects */
- trx_rseg_t* latest_rseg; /* Latest rollback segment in the
- round-robin assignment of rollback
- segments to transactions */
- trx_rseg_t* rseg_array[TRX_SYS_N_RSEGS];
- /* Pointer array to rollback segments;
- NULL if slot not in use */
- ulint rseg_history_len;/* Length of the TRX_RSEG_HISTORY
- list (update undo logs for committed
- transactions), protected by
- rseg->mutex */
- UT_LIST_BASE_NODE_T(read_view_t) view_list;
- /* List of read views sorted on trx no,
- biggest first */
-};
-
-/* When a trx id which is zero modulo this number (which must be a power of
-two) is assigned, the field TRX_SYS_TRX_ID_STORE on the transaction system
-page is updated */
-#define TRX_SYS_TRX_ID_WRITE_MARGIN 256
-
-#ifndef UNIV_NONINL
-#include "trx0sys.ic"
-#endif
-
-#endif
diff --git a/storage/innobase/include/trx0trx.ic b/storage/innobase/include/trx0trx.ic
deleted file mode 100644
index 09b2f822ff7..00000000000
--- a/storage/innobase/include/trx0trx.ic
+++ /dev/null
@@ -1,40 +0,0 @@
-/******************************************************
-The transaction
-
-(c) 1996 Innobase Oy
-
-Created 3/26/1996 Heikki Tuuri
-*******************************************************/
-
-/*****************************************************************
-Starts the transaction if it is not yet started. */
-UNIV_INLINE
-void
-trx_start_if_not_started(
-/*=====================*/
- trx_t* trx) /* in: transaction */
-{
- ut_ad(trx->conc_state != TRX_COMMITTED_IN_MEMORY);
-
- if (trx->conc_state == TRX_NOT_STARTED) {
-
- trx_start(trx, ULINT_UNDEFINED);
- }
-}
-
-/*****************************************************************
-Starts the transaction if it is not yet started. Assumes we have reserved
-the kernel mutex! */
-UNIV_INLINE
-void
-trx_start_if_not_started_low(
-/*=========================*/
- trx_t* trx) /* in: transaction */
-{
- ut_ad(trx->conc_state != TRX_COMMITTED_IN_MEMORY);
-
- if (trx->conc_state == TRX_NOT_STARTED) {
-
- trx_start_low(trx, ULINT_UNDEFINED);
- }
-}
diff --git a/storage/innobase/include/trx0types.h b/storage/innobase/include/trx0types.h
deleted file mode 100644
index 0e6ee79498c..00000000000
--- a/storage/innobase/include/trx0types.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/******************************************************
-Transaction system global type definitions
-
-(c) 1996 Innobase Oy
-
-Created 3/26/1996 Heikki Tuuri
-*******************************************************/
-
-#ifndef trx0types_h
-#define trx0types_h
-
-#include "lock0types.h"
-#include "ut0byte.h"
-
-/* Memory objects */
-typedef struct trx_struct trx_t;
-typedef struct trx_sys_struct trx_sys_t;
-typedef struct trx_doublewrite_struct trx_doublewrite_t;
-typedef struct trx_sig_struct trx_sig_t;
-typedef struct trx_rseg_struct trx_rseg_t;
-typedef struct trx_undo_struct trx_undo_t;
-typedef struct trx_undo_arr_struct trx_undo_arr_t;
-typedef struct trx_undo_inf_struct trx_undo_inf_t;
-typedef struct trx_purge_struct trx_purge_t;
-typedef struct roll_node_struct roll_node_t;
-typedef struct commit_node_struct commit_node_t;
-typedef struct trx_named_savept_struct trx_named_savept_t;
-
-/* Transaction savepoint */
-typedef struct trx_savept_struct trx_savept_t;
-struct trx_savept_struct{
- dulint least_undo_no; /* least undo number to undo */
-};
-
-/* File objects */
-typedef byte trx_sysf_t;
-typedef byte trx_rsegf_t;
-typedef byte trx_usegf_t;
-typedef byte trx_ulogf_t;
-typedef byte trx_upagef_t;
-
-/* Undo log record */
-typedef byte trx_undo_rec_t;
-
-#endif
diff --git a/storage/innobase/include/trx0undo.h b/storage/innobase/include/trx0undo.h
deleted file mode 100644
index 7f10e407746..00000000000
--- a/storage/innobase/include/trx0undo.h
+++ /dev/null
@@ -1,503 +0,0 @@
-/******************************************************
-Transaction undo log
-
-(c) 1996 Innobase Oy
-
-Created 3/26/1996 Heikki Tuuri
-*******************************************************/
-
-#ifndef trx0undo_h
-#define trx0undo_h
-
-#include "univ.i"
-#include "trx0types.h"
-#include "mtr0mtr.h"
-#include "trx0sys.h"
-#include "page0types.h"
-#include "trx0xa.h"
-
-/***************************************************************************
-Builds a roll pointer dulint. */
-UNIV_INLINE
-dulint
-trx_undo_build_roll_ptr(
-/*====================*/
- /* out: roll pointer */
- ibool is_insert, /* in: TRUE if insert undo log */
- ulint rseg_id, /* in: rollback segment id */
- ulint page_no, /* in: page number */
- ulint offset); /* in: offset of the undo entry within page */
-/***************************************************************************
-Decodes a roll pointer dulint. */
-UNIV_INLINE
-void
-trx_undo_decode_roll_ptr(
-/*=====================*/
- dulint roll_ptr, /* in: roll pointer */
- ibool* is_insert, /* out: TRUE if insert undo log */
- ulint* rseg_id, /* out: rollback segment id */
- ulint* page_no, /* out: page number */
- ulint* offset); /* out: offset of the undo entry within page */
-/***************************************************************************
-Returns TRUE if the roll pointer is of the insert type. */
-UNIV_INLINE
-ibool
-trx_undo_roll_ptr_is_insert(
-/*========================*/
- /* out: TRUE if insert undo log */
- dulint roll_ptr); /* in: roll pointer */
-/*********************************************************************
-Writes a roll ptr to an index page. In case that the size changes in
-some future version, this function should be used instead of
-mach_write_... */
-UNIV_INLINE
-void
-trx_write_roll_ptr(
-/*===============*/
- byte* ptr, /* in: pointer to memory where written */
- dulint roll_ptr); /* in: roll ptr */
-/*********************************************************************
-Reads a roll ptr from an index page. In case that the roll ptr size
-changes in some future version, this function should be used instead of
-mach_read_... */
-UNIV_INLINE
-dulint
-trx_read_roll_ptr(
-/*==============*/
- /* out: roll ptr */
- byte* ptr); /* in: pointer to memory from where to read */
-/**********************************************************************
-Gets an undo log page and x-latches it. */
-UNIV_INLINE
-page_t*
-trx_undo_page_get(
-/*==============*/
- /* out: pointer to page x-latched */
- ulint space, /* in: space where placed */
- ulint page_no, /* in: page number */
- mtr_t* mtr); /* in: mtr */
-/**********************************************************************
-Gets an undo log page and s-latches it. */
-UNIV_INLINE
-page_t*
-trx_undo_page_get_s_latched(
-/*========================*/
- /* out: pointer to page s-latched */
- ulint space, /* in: space where placed */
- ulint page_no, /* in: page number */
- mtr_t* mtr); /* in: mtr */
-/**********************************************************************
-Returns the previous undo record on the page in the specified log, or
-NULL if none exists. */
-UNIV_INLINE
-trx_undo_rec_t*
-trx_undo_page_get_prev_rec(
-/*=======================*/
- /* out: pointer to record, NULL if none */
- trx_undo_rec_t* rec, /* in: undo log record */
- ulint page_no,/* in: undo log header page number */
- ulint offset);/* in: undo log header offset on page */
-/**********************************************************************
-Returns the next undo log record on the page in the specified log, or
-NULL if none exists. */
-UNIV_INLINE
-trx_undo_rec_t*
-trx_undo_page_get_next_rec(
-/*=======================*/
- /* out: pointer to record, NULL if none */
- trx_undo_rec_t* rec, /* in: undo log record */
- ulint page_no,/* in: undo log header page number */
- ulint offset);/* in: undo log header offset on page */
-/**********************************************************************
-Returns the last undo record on the page in the specified undo log, or
-NULL if none exists. */
-UNIV_INLINE
-trx_undo_rec_t*
-trx_undo_page_get_last_rec(
-/*=======================*/
- /* out: pointer to record, NULL if none */
- page_t* undo_page,/* in: undo log page */
- ulint page_no,/* in: undo log header page number */
- ulint offset); /* in: undo log header offset on page */
-/**********************************************************************
-Returns the first undo record on the page in the specified undo log, or
-NULL if none exists. */
-UNIV_INLINE
-trx_undo_rec_t*
-trx_undo_page_get_first_rec(
-/*========================*/
- /* out: pointer to record, NULL if none */
- page_t* undo_page,/* in: undo log page */
- ulint page_no,/* in: undo log header page number */
- ulint offset);/* in: undo log header offset on page */
-/***************************************************************************
-Gets the previous record in an undo log. */
-
-trx_undo_rec_t*
-trx_undo_get_prev_rec(
-/*==================*/
- /* out: undo log record, the page s-latched,
- NULL if none */
- trx_undo_rec_t* rec, /* in: undo record */
- ulint page_no,/* in: undo log header page number */
- ulint offset, /* in: undo log header offset on page */
- mtr_t* mtr); /* in: mtr */
-/***************************************************************************
-Gets the next record in an undo log. */
-
-trx_undo_rec_t*
-trx_undo_get_next_rec(
-/*==================*/
- /* out: undo log record, the page s-latched,
- NULL if none */
- trx_undo_rec_t* rec, /* in: undo record */
- ulint page_no,/* in: undo log header page number */
- ulint offset, /* in: undo log header offset on page */
- mtr_t* mtr); /* in: mtr */
-/***************************************************************************
-Gets the first record in an undo log. */
-
-trx_undo_rec_t*
-trx_undo_get_first_rec(
-/*===================*/
- /* out: undo log record, the page latched, NULL if
- none */
- ulint space, /* in: undo log header space */
- ulint page_no,/* in: undo log header page number */
- ulint offset, /* in: undo log header offset on page */
- ulint mode, /* in: latching mode: RW_S_LATCH or RW_X_LATCH */
- mtr_t* mtr); /* in: mtr */
-/************************************************************************
-Tries to add a page to the undo log segment where the undo log is placed. */
-
-ulint
-trx_undo_add_page(
-/*==============*/
- /* out: page number if success, else
- FIL_NULL */
- trx_t* trx, /* in: transaction */
- trx_undo_t* undo, /* in: undo log memory object */
- mtr_t* mtr); /* in: mtr which does not have a latch to any
- undo log page; the caller must have reserved
- the rollback segment mutex */
-/***************************************************************************
-Truncates an undo log from the end. This function is used during a rollback
-to free space from an undo log. */
-
-void
-trx_undo_truncate_end(
-/*==================*/
- trx_t* trx, /* in: transaction whose undo log it is */
- trx_undo_t* undo, /* in: undo log */
- dulint limit); /* in: all undo records with undo number
- >= this value should be truncated */
-/***************************************************************************
-Truncates an undo log from the start. This function is used during a purge
-operation. */
-
-void
-trx_undo_truncate_start(
-/*====================*/
- trx_rseg_t* rseg, /* in: rollback segment */
- ulint space, /* in: space id of the log */
- ulint hdr_page_no, /* in: header page number */
- ulint hdr_offset, /* in: header offset on the page */
- dulint limit); /* in: all undo pages with undo numbers <
- this value should be truncated; NOTE that
- the function only frees whole pages; the
- header page is not freed, but emptied, if
- all the records there are < limit */
-/************************************************************************
-Initializes the undo log lists for a rollback segment memory copy.
-This function is only called when the database is started or a new
-rollback segment created. */
-
-ulint
-trx_undo_lists_init(
-/*================*/
- /* out: the combined size of undo log segments
- in pages */
- trx_rseg_t* rseg); /* in: rollback segment memory object */
-/**************************************************************************
-Assigns an undo log for a transaction. A new undo log is created or a cached
-undo log reused. */
-
-ulint
-trx_undo_assign_undo(
-/*=================*/
- /* out: DB_SUCCESS if undo log assign
- * successful, possible error codes are:
- * ER_TOO_MANY_CONCURRENT_TRXS
- * DB_OUT_OF_FILE_SPAC
- * DB_OUT_OF_MEMORY */
- trx_t* trx, /* in: transaction */
- ulint type); /* in: TRX_UNDO_INSERT or TRX_UNDO_UPDATE */
-/**********************************************************************
-Sets the state of the undo log segment at a transaction finish. */
-
-page_t*
-trx_undo_set_state_at_finish(
-/*=========================*/
- /* out: undo log segment header page,
- x-latched */
- trx_rseg_t* rseg, /* in: rollback segment memory object */
- trx_t* trx, /* in: transaction */
- trx_undo_t* undo, /* in: undo log memory copy */
- mtr_t* mtr); /* in: mtr */
-/**********************************************************************
-Sets the state of the undo log segment at a transaction prepare. */
-
-page_t*
-trx_undo_set_state_at_prepare(
-/*==========================*/
- /* out: undo log segment header page,
- x-latched */
- trx_t* trx, /* in: transaction */
- trx_undo_t* undo, /* in: undo log memory copy */
- mtr_t* mtr); /* in: mtr */
-
-/**************************************************************************
-Adds the update undo log header as the first in the history list, and
-frees the memory object, or puts it to the list of cached update undo log
-segments. */
-
-void
-trx_undo_update_cleanup(
-/*====================*/
- trx_t* trx, /* in: trx owning the update undo log */
- page_t* undo_page, /* in: update undo log header page,
- x-latched */
- mtr_t* mtr); /* in: mtr */
-/**********************************************************************
-Frees or caches an insert undo log after a transaction commit or rollback.
-Knowledge of inserts is not needed after a commit or rollback, therefore
-the data can be discarded. */
-
-void
-trx_undo_insert_cleanup(
-/*====================*/
- trx_t* trx); /* in: transaction handle */
-/***************************************************************
-Parses the redo log entry of an undo log page initialization. */
-
-byte*
-trx_undo_parse_page_init(
-/*=====================*/
- /* out: end of log record or NULL */
- byte* ptr, /* in: buffer */
- byte* end_ptr,/* in: buffer end */
- page_t* page, /* in: page or NULL */
- mtr_t* mtr); /* in: mtr or NULL */
-/***************************************************************
-Parses the redo log entry of an undo log page header create or reuse. */
-
-byte*
-trx_undo_parse_page_header(
-/*=======================*/
- /* out: end of log record or NULL */
- ulint type, /* in: MLOG_UNDO_HDR_CREATE or MLOG_UNDO_HDR_REUSE */
- byte* ptr, /* in: buffer */
- byte* end_ptr,/* in: buffer end */
- page_t* page, /* in: page or NULL */
- mtr_t* mtr); /* in: mtr or NULL */
-/***************************************************************
-Parses the redo log entry of an undo log page header discard. */
-
-byte*
-trx_undo_parse_discard_latest(
-/*==========================*/
- /* out: end of log record or NULL */
- byte* ptr, /* in: buffer */
- byte* end_ptr,/* in: buffer end */
- page_t* page, /* in: page or NULL */
- mtr_t* mtr); /* in: mtr or NULL */
-
-/* Types of an undo log segment */
-#define TRX_UNDO_INSERT 1 /* contains undo entries for inserts */
-#define TRX_UNDO_UPDATE 2 /* contains undo entries for updates
- and delete markings: in short,
- modifys (the name 'UPDATE' is a
- historical relic) */
-/* States of an undo log segment */
-#define TRX_UNDO_ACTIVE 1 /* contains an undo log of an active
- transaction */
-#define TRX_UNDO_CACHED 2 /* cached for quick reuse */
-#define TRX_UNDO_TO_FREE 3 /* insert undo segment can be freed */
-#define TRX_UNDO_TO_PURGE 4 /* update undo segment will not be
- reused: it can be freed in purge when
- all undo data in it is removed */
-#define TRX_UNDO_PREPARED 5 /* contains an undo log of an
- prepared transaction */
-
-/* Transaction undo log memory object; this is protected by the undo_mutex
-in the corresponding transaction object */
-
-struct trx_undo_struct{
- /*-----------------------------*/
- ulint id; /* undo log slot number within the
- rollback segment */
- ulint type; /* TRX_UNDO_INSERT or
- TRX_UNDO_UPDATE */
- ulint state; /* state of the corresponding undo log
- segment */
- ibool del_marks; /* relevant only in an update undo log:
- this is TRUE if the transaction may
- have delete marked records, because of
- a delete of a row or an update of an
- indexed field; purge is then
- necessary; also TRUE if the transaction
- has updated an externally stored
- field */
- dulint trx_id; /* id of the trx assigned to the undo
- log */
- XID xid; /* X/Open XA transaction
- identification */
- ibool dict_operation; /* TRUE if a dict operation trx */
- dulint table_id; /* if a dict operation, then the table
- id */
- trx_rseg_t* rseg; /* rseg where the undo log belongs */
- /*-----------------------------*/
- ulint space; /* space id where the undo log
- placed */
- ulint hdr_page_no; /* page number of the header page in
- the undo log */
- ulint hdr_offset; /* header offset of the undo log on the
- page */
- ulint last_page_no; /* page number of the last page in the
- undo log; this may differ from
- top_page_no during a rollback */
- ulint size; /* current size in pages */
- /*-----------------------------*/
- ulint empty; /* TRUE if the stack of undo log
- records is currently empty */
- ulint top_page_no; /* page number where the latest undo
- log record was catenated; during
- rollback the page from which the latest
- undo record was chosen */
- ulint top_offset; /* offset of the latest undo record,
- i.e., the topmost element in the undo
- log if we think of it as a stack */
- dulint top_undo_no; /* undo number of the latest record */
- page_t* guess_page; /* guess for the buffer frame where
- the top page might reside */
- /*-----------------------------*/
- UT_LIST_NODE_T(trx_undo_t) undo_list;
- /* undo log objects in the rollback
- segment are chained into lists */
-};
-
-/* The offset of the undo log page header on pages of the undo log */
-#define TRX_UNDO_PAGE_HDR FSEG_PAGE_DATA
-/*-------------------------------------------------------------*/
-/* Transaction undo log page header offsets */
-#define TRX_UNDO_PAGE_TYPE 0 /* TRX_UNDO_INSERT or
- TRX_UNDO_UPDATE */
-#define TRX_UNDO_PAGE_START 2 /* Byte offset where the undo log
- records for the LATEST transaction
- start on this page (remember that
- in an update undo log, the first page
- can contain several undo logs) */
-#define TRX_UNDO_PAGE_FREE 4 /* On each page of the undo log this
- field contains the byte offset of the
- first free byte on the page */
-#define TRX_UNDO_PAGE_NODE 6 /* The file list node in the chain
- of undo log pages */
-/*-------------------------------------------------------------*/
-#define TRX_UNDO_PAGE_HDR_SIZE (6 + FLST_NODE_SIZE)
-
-/* An update undo segment with just one page can be reused if it has
-< this number bytes used; we must leave space at least for one new undo
-log header on the page */
-
-#define TRX_UNDO_PAGE_REUSE_LIMIT (3 * UNIV_PAGE_SIZE / 4)
-
-/* An update undo log segment may contain several undo logs on its first page
-if the undo logs took so little space that the segment could be cached and
-reused. All the undo log headers are then on the first page, and the last one
-owns the undo log records on subsequent pages if the segment is bigger than
-one page. If an undo log is stored in a segment, then on the first page it is
-allowed to have zero undo records, but if the segment extends to several
-pages, then all the rest of the pages must contain at least one undo log
-record. */
-
-/* The offset of the undo log segment header on the first page of the undo
-log segment */
-
-#define TRX_UNDO_SEG_HDR (TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_HDR_SIZE)
-/*-------------------------------------------------------------*/
-#define TRX_UNDO_STATE 0 /* TRX_UNDO_ACTIVE, ... */
-#define TRX_UNDO_LAST_LOG 2 /* Offset of the last undo log header
- on the segment header page, 0 if
- none */
-#define TRX_UNDO_FSEG_HEADER 4 /* Header for the file segment which
- the undo log segment occupies */
-#define TRX_UNDO_PAGE_LIST (4 + FSEG_HEADER_SIZE)
- /* Base node for the list of pages in
- the undo log segment; defined only on
- the undo log segment's first page */
-/*-------------------------------------------------------------*/
-/* Size of the undo log segment header */
-#define TRX_UNDO_SEG_HDR_SIZE (4 + FSEG_HEADER_SIZE + FLST_BASE_NODE_SIZE)
-
-
-/* The undo log header. There can be several undo log headers on the first
-page of an update undo log segment. */
-/*-------------------------------------------------------------*/
-#define TRX_UNDO_TRX_ID 0 /* Transaction id */
-#define TRX_UNDO_TRX_NO 8 /* Transaction number of the
- transaction; defined only if the log
- is in a history list */
-#define TRX_UNDO_DEL_MARKS 16 /* Defined only in an update undo
- log: TRUE if the transaction may have
- done delete markings of records, and
- thus purge is necessary */
-#define TRX_UNDO_LOG_START 18 /* Offset of the first undo log record
- of this log on the header page; purge
- may remove undo log record from the
- log start, and therefore this is not
- necessarily the same as this log
- header end offset */
-#define TRX_UNDO_XID_EXISTS 20 /* TRUE if undo log header includes
- X/Open XA transaction identification
- XID */
-#define TRX_UNDO_DICT_TRANS 21 /* TRUE if the transaction is a table
- create, index create, or drop
- transaction: in recovery
- the transaction cannot be rolled back
- in the usual way: a 'rollback' rather
- means dropping the created or dropped
- table, if it still exists */
-#define TRX_UNDO_TABLE_ID 22 /* Id of the table if the preceding
- field is TRUE */
-#define TRX_UNDO_NEXT_LOG 30 /* Offset of the next undo log header
- on this page, 0 if none */
-#define TRX_UNDO_PREV_LOG 32 /* Offset of the previous undo log
- header on this page, 0 if none */
-#define TRX_UNDO_HISTORY_NODE 34 /* If the log is put to the history
- list, the file list node is here */
-/*-------------------------------------------------------------*/
-#define TRX_UNDO_LOG_OLD_HDR_SIZE (34 + FLST_NODE_SIZE)
-
-/* Note: the writing of the undo log old header is coded by a log record
-MLOG_UNDO_HDR_CREATE or MLOG_UNDO_HDR_REUSE. The appending of an XID to the
-header is logged separately. In this sense, the XID is not really a member
-of the undo log header. TODO: do not append the XID to the log header if XA
-is not needed by the user. The XID wastes about 150 bytes of space in every
-undo log. In the history list we may have millions of undo logs, which means
-quite a large overhead. */
-
-/* X/Open XA Transaction Identification (XID) */
-
-#define TRX_UNDO_XA_FORMAT (TRX_UNDO_LOG_OLD_HDR_SIZE)
-#define TRX_UNDO_XA_TRID_LEN (TRX_UNDO_XA_FORMAT + 4)
-#define TRX_UNDO_XA_BQUAL_LEN (TRX_UNDO_XA_TRID_LEN + 4)
-#define TRX_UNDO_XA_XID (TRX_UNDO_XA_BQUAL_LEN + 4)
-/*--------------------------------------------------------------*/
-#define TRX_UNDO_LOG_XA_HDR_SIZE (TRX_UNDO_XA_XID + XIDDATASIZE)
- /* Total size of the header with the XA XID */
-
-#ifndef UNIV_NONINL
-#include "trx0undo.ic"
-#endif
-
-#endif
diff --git a/storage/innobase/include/trx0xa.h b/storage/innobase/include/trx0xa.h
deleted file mode 100644
index df85cd663cb..00000000000
--- a/storage/innobase/include/trx0xa.h
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * Start of xa.h header
- *
- * Define a symbol to prevent multiple inclusions of this header file
- */
-#ifndef XA_H
-#define XA_H
-
-/*
- * Transaction branch identification: XID and NULLXID:
- */
-#ifndef XIDDATASIZE
-
-#define XIDDATASIZE 128 /* size in bytes */
-#define MAXGTRIDSIZE 64 /* maximum size in bytes of gtrid */
-#define MAXBQUALSIZE 64 /* maximum size in bytes of bqual */
-
-struct xid_t {
- long formatID; /* format identifier */
- long gtrid_length; /* value from 1 through 64 */
- long bqual_length; /* value from 1 through 64 */
- char data[XIDDATASIZE];
-};
-typedef struct xid_t XID;
-#endif
-/*
- * A value of -1 in formatID means that the XID is null.
- */
-
-
-#ifdef NOTDEFINED
-/* Let us comment this out to remove compiler errors!!!!!!!!!!!! */
-
-/*
- * Declarations of routines by which RMs call TMs:
- */
-extern int ax_reg __P((int, XID *, long));
-extern int ax_unreg __P((int, long));
-
-/*
- * XA Switch Data Structure
- */
-#define RMNAMESZ 32 /* length of resource manager name, */
- /* including the null terminator */
-#define MAXINFOSIZE 256 /* maximum size in bytes of xa_info */
- /* strings, including the null
- terminator */
-
-
-struct xa_switch_t {
- char name[RMNAMESZ]; /* name of resource manager */
- long flags; /* resource manager specific options */
- long version; /* must be 0 */
- int (*xa_open_entry) /* xa_open function pointer */
- __P((char *, int, long));
- int (*xa_close_entry) /* xa_close function pointer */
- __P((char *, int, long));
- int (*xa_start_entry) /* xa_start function pointer */
- __P((XID *, int, long));
- int (*xa_end_entry) /* xa_end function pointer */
- __P((XID *, int, long));
- int (*xa_rollback_entry) /* xa_rollback function pointer */
- __P((XID *, int, long));
- int (*xa_prepare_entry) /* xa_prepare function pointer */
- __P((XID *, int, long));
- int (*xa_commit_entry) /* xa_commit function pointer */
- __P((XID *, int, long));
- int (*xa_recover_entry) /* xa_recover function pointer */
- __P((XID *, long, int, long));
- int (*xa_forget_entry) /* xa_forget function pointer */
- __P((XID *, int, long));
- int (*xa_complete_entry) /* xa_complete function pointer */
- __P((int *, int *, int, long));
-};
-#endif /* NOTDEFINED */
-
-
-/*
- * Flag definitions for the RM switch
- */
-#define TMNOFLAGS 0x00000000L /* no resource manager features
- selected */
-#define TMREGISTER 0x00000001L /* resource manager dynamically
- registers */
-#define TMNOMIGRATE 0x00000002L /* resource manager does not support
- association migration */
-#define TMUSEASYNC 0x00000004L /* resource manager supports
- asynchronous operations */
-/*
- * Flag definitions for xa_ and ax_ routines
- */
-/* use TMNOFLAGGS, defined above, when not specifying other flags */
-#define TMASYNC 0x80000000L /* perform routine asynchronously */
-#define TMONEPHASE 0x40000000L /* caller is using one-phase commit
- optimisation */
-#define TMFAIL 0x20000000L /* dissociates caller and marks
- transaction branch rollback-only */
-#define TMNOWAIT 0x10000000L /* return if blocking condition
- exists */
-#define TMRESUME 0x08000000L /* caller is resuming association with
- suspended transaction branch */
-#define TMSUCCESS 0x04000000L /* dissociate caller from transaction
- branch */
-#define TMSUSPEND 0x02000000L /* caller is suspending, not ending,
- association */
-#define TMSTARTRSCAN 0x01000000L /* start a recovery scan */
-#define TMENDRSCAN 0x00800000L /* end a recovery scan */
-#define TMMULTIPLE 0x00400000L /* wait for any asynchronous
- operation */
-#define TMJOIN 0x00200000L /* caller is joining existing
- transaction branch */
-#define TMMIGRATE 0x00100000L /* caller intends to perform
- migration */
-
-/*
- * ax_() return codes (transaction manager reports to resource manager)
- */
-#define TM_JOIN 2 /* caller is joining existing
- transaction branch */
-#define TM_RESUME 1 /* caller is resuming association with
- suspended transaction branch */
-#define TM_OK 0 /* normal execution */
-#define TMER_TMERR -1 /* an error occurred in the transaction
- manager */
-#define TMER_INVAL -2 /* invalid arguments were given */
-#define TMER_PROTO -3 /* routine invoked in an improper
- context */
-
-/*
- * xa_() return codes (resource manager reports to transaction manager)
- */
-#define XA_RBBASE 100 /* The inclusive lower bound of the
- rollback codes */
-#define XA_RBROLLBACK XA_RBBASE /* The rollback was caused by an
- unspecified reason */
-#define XA_RBCOMMFAIL XA_RBBASE+1 /* The rollback was caused by a
- communication failure */
-#define XA_RBDEADLOCK XA_RBBASE+2 /* A deadlock was detected */
-#define XA_RBINTEGRITY XA_RBBASE+3 /* A condition that violates the
- integrity of the resources was
- detected */
-#define XA_RBOTHER XA_RBBASE+4 /* The resource manager rolled back the
- transaction branch for a reason not
- on this list */
-#define XA_RBPROTO XA_RBBASE+5 /* A protocol error occurred in the
- resource manager */
-#define XA_RBTIMEOUT XA_RBBASE+6 /* A transaction branch took
- too long */
-#define XA_RBTRANSIENT XA_RBBASE+7 /* May retry the transaction branch */
-#define XA_RBEND XA_RBTRANSIENT /* The inclusive upper bound of the
- rollback codes */
-#define XA_NOMIGRATE 9 /* resumption must occur where
- suspension occurred */
-#define XA_HEURHAZ 8 /* the transaction branch may have
- been heuristically completed */
-#define XA_HEURCOM 7 /* the transaction branch has been
- heuristically committed */
-#define XA_HEURRB 6 /* the transaction branch has been
- heuristically rolled back */
-#define XA_HEURMIX 5 /* the transaction branch has been
- heuristically committed and rolled
- back */
-#define XA_RETRY 4 /* routine returned with no effect and
- may be re-issued */
-#define XA_RDONLY 3 /* the transaction branch was read-only
- and has been committed */
-#define XA_OK 0 /* normal execution */
-#define XAER_ASYNC -2 /* asynchronous operation already
- outstanding */
-#define XAER_RMERR -3 /* a resource manager error occurred in
- the transaction branch */
-#define XAER_NOTA -4 /* the XID is not valid */
-#define XAER_INVAL -5 /* invalid arguments were given */
-#define XAER_PROTO -6 /* routine invoked in an improper
- context */
-#define XAER_RMFAIL -7 /* resource manager unavailable */
-#define XAER_DUPID -8 /* the XID already exists */
-#define XAER_OUTSIDE -9 /* resource manager doing work outside
- transaction */
-#endif /* ifndef XA_H */
-/*
- * End of xa.h header
- */
diff --git a/storage/innobase/include/usr0sess.h b/storage/innobase/include/usr0sess.h
deleted file mode 100644
index 3ed1ea21a4d..00000000000
--- a/storage/innobase/include/usr0sess.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/******************************************************
-Sessions
-
-(c) 1996 Innobase Oy
-
-Created 6/25/1996 Heikki Tuuri
-*******************************************************/
-
-#ifndef usr0sess_h
-#define usr0sess_h
-
-#include "univ.i"
-#include "ut0byte.h"
-#include "trx0types.h"
-#include "srv0srv.h"
-#include "trx0types.h"
-#include "usr0types.h"
-#include "que0types.h"
-#include "data0data.h"
-#include "rem0rec.h"
-
-/*************************************************************************
-Opens a session. */
-
-sess_t*
-sess_open(void);
-/*============*/
- /* out, own: session object */
-/*************************************************************************
-Closes a session, freeing the memory occupied by it, if it is in a state
-where it should be closed. */
-
-ibool
-sess_try_close(
-/*===========*/
- /* out: TRUE if closed */
- sess_t* sess); /* in, own: session object */
-
-/* The session handle. All fields are protected by the kernel mutex */
-struct sess_struct{
- ulint state; /* state of the session */
- trx_t* trx; /* transaction object permanently
- assigned for the session: the
- transaction instance designated by the
- trx id changes, but the memory
- structure is preserved */
- UT_LIST_BASE_NODE_T(que_t)
- graphs; /* query graphs belonging to this
- session */
-};
-
-/* Session states */
-#define SESS_ACTIVE 1
-#define SESS_ERROR 2 /* session contains an error message
- which has not yet been communicated
- to the client */
-#ifndef UNIV_NONINL
-#include "usr0sess.ic"
-#endif
-
-#endif
diff --git a/storage/innobase/include/usr0sess.ic b/storage/innobase/include/usr0sess.ic
deleted file mode 100644
index c851d5745b9..00000000000
--- a/storage/innobase/include/usr0sess.ic
+++ /dev/null
@@ -1,7 +0,0 @@
-/******************************************************
-Sessions
-
-(c) 1996 Innobase Oy
-
-Created 6/25/1996 Heikki Tuuri
-*******************************************************/
diff --git a/storage/innobase/include/usr0types.h b/storage/innobase/include/usr0types.h
deleted file mode 100644
index 311471c1a0e..00000000000
--- a/storage/innobase/include/usr0types.h
+++ /dev/null
@@ -1,14 +0,0 @@
-/******************************************************
-Users and sessions global types
-
-(c) 1996 Innobase Oy
-
-Created 6/25/1996 Heikki Tuuri
-*******************************************************/
-
-#ifndef usr0types_h
-#define usr0types_h
-
-typedef struct sess_struct sess_t;
-
-#endif
diff --git a/storage/innobase/include/ut0byte.h b/storage/innobase/include/ut0byte.h
deleted file mode 100644
index 6533f1166ca..00000000000
--- a/storage/innobase/include/ut0byte.h
+++ /dev/null
@@ -1,250 +0,0 @@
-/**********************************************************************
-Utilities for byte operations
-
-(c) 1994, 1995 Innobase Oy
-
-Created 1/20/1994 Heikki Tuuri
-***********************************************************************/
-
-#ifndef ut0byte_h
-#define ut0byte_h
-
-
-#include "univ.i"
-
-/* Type definition for a 64-bit unsigned integer, which works also
-in 32-bit machines. NOTE! Access the fields only with the accessor
-functions. This definition appears here only for the compiler to
-know the size of a dulint. */
-
-typedef struct dulint_struct dulint;
-struct dulint_struct{
- ulint high; /* most significant 32 bits */
- ulint low; /* least significant 32 bits */
-};
-
-/* Zero value for a dulint */
-extern dulint ut_dulint_zero;
-
-/* Maximum value for a dulint */
-extern dulint ut_dulint_max;
-
-/***********************************************************
-Creates a 64-bit dulint out of two ulints. */
-UNIV_INLINE
-dulint
-ut_dulint_create(
-/*=============*/
- /* out: created dulint */
- ulint high, /* in: high-order 32 bits */
- ulint low); /* in: low-order 32 bits */
-/***********************************************************
-Gets the high-order 32 bits of a dulint. */
-UNIV_INLINE
-ulint
-ut_dulint_get_high(
-/*===============*/
- /* out: 32 bits in ulint */
- dulint d); /* in: dulint */
-/***********************************************************
-Gets the low-order 32 bits of a dulint. */
-UNIV_INLINE
-ulint
-ut_dulint_get_low(
-/*==============*/
- /* out: 32 bits in ulint */
- dulint d); /* in: dulint */
-/***********************************************************
-Converts a dulint (a struct of 2 ulints) to ib_longlong, which is a 64-bit
-integer type. */
-UNIV_INLINE
-ib_longlong
-ut_conv_dulint_to_longlong(
-/*=======================*/
- /* out: value in ib_longlong type */
- dulint d); /* in: dulint */
-/***********************************************************
-Tests if a dulint is zero. */
-UNIV_INLINE
-ibool
-ut_dulint_is_zero(
-/*==============*/
- /* out: TRUE if zero */
- dulint a); /* in: dulint */
-/***********************************************************
-Compares two dulints. */
-UNIV_INLINE
-int
-ut_dulint_cmp(
-/*==========*/
- /* out: -1 if a < b, 0 if a == b,
- 1 if a > b */
- dulint a, /* in: dulint */
- dulint b); /* in: dulint */
-/***********************************************************
-Calculates the max of two dulints. */
-UNIV_INLINE
-dulint
-ut_dulint_get_max(
-/*==============*/
- /* out: max(a, b) */
- dulint a, /* in: dulint */
- dulint b); /* in: dulint */
-/***********************************************************
-Calculates the min of two dulints. */
-UNIV_INLINE
-dulint
-ut_dulint_get_min(
-/*==============*/
- /* out: min(a, b) */
- dulint a, /* in: dulint */
- dulint b); /* in: dulint */
-/***********************************************************
-Adds a ulint to a dulint. */
-UNIV_INLINE
-dulint
-ut_dulint_add(
-/*==========*/
- /* out: sum a + b */
- dulint a, /* in: dulint */
- ulint b); /* in: ulint */
-/***********************************************************
-Subtracts a ulint from a dulint. */
-UNIV_INLINE
-dulint
-ut_dulint_subtract(
-/*===============*/
- /* out: a - b */
- dulint a, /* in: dulint */
- ulint b); /* in: ulint, b <= a */
-/***********************************************************
-Subtracts a dulint from another. NOTE that the difference must be positive
-and smaller that 4G. */
-UNIV_INLINE
-ulint
-ut_dulint_minus(
-/*============*/
- /* out: a - b */
- dulint a, /* in: dulint; NOTE a must be >= b and at most
- 2 to power 32 - 1 greater */
- dulint b); /* in: dulint */
-/************************************************************
-Rounds a dulint downward to a multiple of a power of 2. */
-UNIV_INLINE
-dulint
-ut_dulint_align_down(
-/*=================*/
- /* out: rounded value */
- dulint n, /* in: number to be rounded */
- ulint align_no); /* in: align by this number which must be a
- power of 2 */
-/************************************************************
-Rounds a dulint upward to a multiple of a power of 2. */
-UNIV_INLINE
-dulint
-ut_dulint_align_up(
-/*===============*/
- /* out: rounded value */
- dulint n, /* in: number to be rounded */
- ulint align_no); /* in: align by this number which must be a
- power of 2 */
-/***********************************************************
-Increments a dulint variable by 1. */
-#define UT_DULINT_INC(D)\
-{\
- if ((D).low == 0xFFFFFFFFUL) {\
- (D).high = (D).high + 1;\
- (D).low = 0;\
- } else {\
- (D).low = (D).low + 1;\
- }\
-}
-/***********************************************************
-Tests if two dulints are equal. */
-#define UT_DULINT_EQ(D1, D2) (((D1).low == (D2).low)\
- && ((D1).high == (D2).high))
-/****************************************************************
-Sort function for dulint arrays. */
-void
-ut_dulint_sort(dulint* arr, dulint* aux_arr, ulint low, ulint high);
-/*===============================================================*/
-/************************************************************
-The following function calculates the value of an integer n rounded
-to the least product of align_no which is >= n. align_no has to be a
-power of 2. */
-UNIV_INLINE
-ulint
-ut_calc_align(
-/*==========*/
- /* out: rounded value */
- ulint n, /* in: number to be rounded */
- ulint align_no); /* in: align by this number */
-/************************************************************
-The following function calculates the value of an integer n rounded
-to the biggest product of align_no which is <= n. align_no has to be a
-power of 2. */
-UNIV_INLINE
-ulint
-ut_calc_align_down(
-/*===============*/
- /* out: rounded value */
- ulint n, /* in: number to be rounded */
- ulint align_no); /* in: align by this number */
-/*************************************************************
-The following function rounds up a pointer to the nearest aligned address. */
-UNIV_INLINE
-void*
-ut_align(
-/*=====*/
- /* out: aligned pointer */
- void* ptr, /* in: pointer */
- ulint align_no); /* in: align by this number */
-/*************************************************************
-The following function rounds down a pointer to the nearest
-aligned address. */
-UNIV_INLINE
-void*
-ut_align_down(
-/*==========*/
- /* out: aligned pointer */
- void* ptr, /* in: pointer */
- ulint align_no) /* in: align by this number */
- __attribute__((const));
-/*************************************************************
-The following function computes the offset of a pointer from the nearest
-aligned address. */
-UNIV_INLINE
-ulint
-ut_align_offset(
-/*============*/
- /* out: distance from aligned
- pointer */
- const void* ptr, /* in: pointer */
- ulint align_no) /* in: align by this number */
- __attribute__((const));
-/*********************************************************************
-Gets the nth bit of a ulint. */
-UNIV_INLINE
-ibool
-ut_bit_get_nth(
-/*===========*/
- /* out: TRUE if nth bit is 1; 0th bit is defined to
- be the least significant */
- ulint a, /* in: ulint */
- ulint n); /* in: nth bit requested */
-/*********************************************************************
-Sets the nth bit of a ulint. */
-UNIV_INLINE
-ulint
-ut_bit_set_nth(
-/*===========*/
- /* out: the ulint with the bit set as requested */
- ulint a, /* in: ulint */
- ulint n, /* in: nth bit requested */
- ibool val); /* in: value for the bit to set */
-
-#ifndef UNIV_NONINL
-#include "ut0byte.ic"
-#endif
-
-#endif
diff --git a/storage/innobase/include/ut0byte.ic b/storage/innobase/include/ut0byte.ic
deleted file mode 100644
index 01b6c29d08f..00000000000
--- a/storage/innobase/include/ut0byte.ic
+++ /dev/null
@@ -1,397 +0,0 @@
-/******************************************************************
-Utilities for byte operations
-
-(c) 1994, 1995 Innobase Oy
-
-Created 5/30/1994 Heikki Tuuri
-*******************************************************************/
-
-/***********************************************************
-Creates a 64-bit dulint out of two ulints. */
-UNIV_INLINE
-dulint
-ut_dulint_create(
-/*=============*/
- /* out: created dulint */
- ulint high, /* in: high-order 32 bits */
- ulint low) /* in: low-order 32 bits */
-{
- dulint res;
-
- ut_ad(high <= 0xFFFFFFFF);
- ut_ad(low <= 0xFFFFFFFF);
-
- res.high = high;
- res.low = low;
-
- return(res);
-}
-
-/***********************************************************
-Gets the high-order 32 bits of a dulint. */
-UNIV_INLINE
-ulint
-ut_dulint_get_high(
-/*===============*/
- /* out: 32 bits in ulint */
- dulint d) /* in: dulint */
-{
- return(d.high);
-}
-
-/***********************************************************
-Gets the low-order 32 bits of a dulint. */
-UNIV_INLINE
-ulint
-ut_dulint_get_low(
-/*==============*/
- /* out: 32 bits in ulint */
- dulint d) /* in: dulint */
-{
- return(d.low);
-}
-
-/***********************************************************
-Converts a dulint (a struct of 2 ulints) to ib_longlong, which is a 64-bit
-integer type. */
-UNIV_INLINE
-ib_longlong
-ut_conv_dulint_to_longlong(
-/*=======================*/
- /* out: value in ib_longlong type */
- dulint d) /* in: dulint */
-{
- return((ib_longlong)d.low
- + (((ib_longlong)d.high) << 32));
-}
-
-/***********************************************************
-Tests if a dulint is zero. */
-UNIV_INLINE
-ibool
-ut_dulint_is_zero(
-/*==============*/
- /* out: TRUE if zero */
- dulint a) /* in: dulint */
-{
- if ((a.low == 0) && (a.high == 0)) {
-
- return(TRUE);
- }
-
- return(FALSE);
-}
-
-/***********************************************************
-Compares two dulints. */
-UNIV_INLINE
-int
-ut_dulint_cmp(
-/*==========*/
- /* out: -1 if a < b, 0 if a == b,
- 1 if a > b */
- dulint a, /* in: dulint */
- dulint b) /* in: dulint */
-{
- if (a.high > b.high) {
- return(1);
- } else if (a.high < b.high) {
- return(-1);
- } else if (a.low > b.low) {
- return(1);
- } else if (a.low < b.low) {
- return(-1);
- } else {
- return(0);
- }
-}
-
-/***********************************************************
-Calculates the max of two dulints. */
-UNIV_INLINE
-dulint
-ut_dulint_get_max(
-/*==============*/
- /* out: max(a, b) */
- dulint a, /* in: dulint */
- dulint b) /* in: dulint */
-{
- if (ut_dulint_cmp(a, b) > 0) {
-
- return(a);
- }
-
- return(b);
-}
-
-/***********************************************************
-Calculates the min of two dulints. */
-UNIV_INLINE
-dulint
-ut_dulint_get_min(
-/*==============*/
- /* out: min(a, b) */
- dulint a, /* in: dulint */
- dulint b) /* in: dulint */
-{
- if (ut_dulint_cmp(a, b) > 0) {
-
- return(b);
- }
-
- return(a);
-}
-
-/***********************************************************
-Adds a ulint to a dulint. */
-UNIV_INLINE
-dulint
-ut_dulint_add(
-/*==========*/
- /* out: sum a + b */
- dulint a, /* in: dulint */
- ulint b) /* in: ulint */
-{
- if (0xFFFFFFFFUL - b >= a.low) {
- a.low += b;
-
- return(a);
- }
-
- a.low = a.low - (0xFFFFFFFFUL - b) - 1;
-
- a.high++;
-
- return(a);
-}
-
-/***********************************************************
-Subtracts a ulint from a dulint. */
-UNIV_INLINE
-dulint
-ut_dulint_subtract(
-/*===============*/
- /* out: a - b */
- dulint a, /* in: dulint */
- ulint b) /* in: ulint, b <= a */
-{
- if (a.low >= b) {
- a.low -= b;
-
- return(a);
- }
-
- b -= a.low + 1;
-
- a.low = 0xFFFFFFFFUL - b;
-
- ut_ad(a.high > 0);
-
- a.high--;
-
- return(a);
-}
-
-/***********************************************************
-Subtracts a dulint from another. NOTE that the difference must be positive
-and smaller that 4G. */
-UNIV_INLINE
-ulint
-ut_dulint_minus(
-/*============*/
- /* out: a - b */
- dulint a, /* in: dulint; NOTE a must be >= b and at most
- 2 to power 32 - 1 greater */
- dulint b) /* in: dulint */
-{
- ulint diff;
-
- if (a.high == b.high) {
- ut_ad(a.low >= b.low);
-
- return(a.low - b.low);
- }
-
- ut_ad(a.high == b.high + 1);
-
- diff = (ulint)(0xFFFFFFFFUL - b.low);
- diff += 1 + a.low;
-
- ut_ad(diff > a.low);
-
- return(diff);
-}
-
-/************************************************************
-Rounds a dulint downward to a multiple of a power of 2. */
-UNIV_INLINE
-dulint
-ut_dulint_align_down(
-/*=================*/
- /* out: rounded value */
- dulint n, /* in: number to be rounded */
- ulint align_no) /* in: align by this number which must be a
- power of 2 */
-{
- ulint low, high;
-
- ut_ad(align_no > 0);
- ut_ad(((align_no - 1) & align_no) == 0);
-
- low = ut_dulint_get_low(n);
- high = ut_dulint_get_high(n);
-
- low = low & ~(align_no - 1);
-
- return(ut_dulint_create(high, low));
-}
-
-/************************************************************
-Rounds a dulint upward to a multiple of a power of 2. */
-UNIV_INLINE
-dulint
-ut_dulint_align_up(
-/*===============*/
- /* out: rounded value */
- dulint n, /* in: number to be rounded */
- ulint align_no) /* in: align by this number which must be a
- power of 2 */
-{
- return(ut_dulint_align_down(ut_dulint_add(n, align_no - 1), align_no));
-}
-
-/************************************************************
-The following function calculates the value of an integer n rounded
-to the least product of align_no which is >= n. align_no
-has to be a power of 2. */
-UNIV_INLINE
-ulint
-ut_calc_align(
-/*==========*/
- /* out: rounded value */
- ulint n, /* in: number to be rounded */
- ulint align_no) /* in: align by this number */
-{
- ut_ad(align_no > 0);
- ut_ad(((align_no - 1) & align_no) == 0);
-
- return((n + align_no - 1) & ~(align_no - 1));
-}
-
-/*************************************************************
-The following function rounds up a pointer to the nearest aligned address. */
-UNIV_INLINE
-void*
-ut_align(
-/*=====*/
- /* out: aligned pointer */
- void* ptr, /* in: pointer */
- ulint align_no) /* in: align by this number */
-{
- ut_ad(align_no > 0);
- ut_ad(((align_no - 1) & align_no) == 0);
- ut_ad(ptr);
-
- ut_ad(sizeof(void*) == sizeof(ulint));
-
- return((void*)((((ulint)ptr) + align_no - 1) & ~(align_no - 1)));
-}
-
-/************************************************************
-The following function calculates the value of an integer n rounded
-to the biggest product of align_no which is <= n. align_no has to be a
-power of 2. */
-UNIV_INLINE
-ulint
-ut_calc_align_down(
-/*===============*/
- /* out: rounded value */
- ulint n, /* in: number to be rounded */
- ulint align_no) /* in: align by this number */
-{
- ut_ad(align_no > 0);
- ut_ad(((align_no - 1) & align_no) == 0);
-
- return(n & ~(align_no - 1));
-}
-
-/*************************************************************
-The following function rounds down a pointer to the nearest
-aligned address. */
-UNIV_INLINE
-void*
-ut_align_down(
-/*==========*/
- /* out: aligned pointer */
- void* ptr, /* in: pointer */
- ulint align_no) /* in: align by this number */
-{
- ut_ad(align_no > 0);
- ut_ad(((align_no - 1) & align_no) == 0);
- ut_ad(ptr);
-
- ut_ad(sizeof(void*) == sizeof(ulint));
-
- return((void*)((((ulint)ptr)) & ~(align_no - 1)));
-}
-
-/*************************************************************
-The following function computes the offset of a pointer from the nearest
-aligned address. */
-UNIV_INLINE
-ulint
-ut_align_offset(
-/*============*/
- /* out: distance from
- aligned pointer */
- const void* ptr, /* in: pointer */
- ulint align_no) /* in: align by this number */
-{
- ut_ad(align_no > 0);
- ut_ad(((align_no - 1) & align_no) == 0);
- ut_ad(ptr);
-
- ut_ad(sizeof(void*) == sizeof(ulint));
-
- return(((ulint)ptr) & (align_no - 1));
-}
-
-/*********************************************************************
-Gets the nth bit of a ulint. */
-UNIV_INLINE
-ibool
-ut_bit_get_nth(
-/*===========*/
- /* out: TRUE if nth bit is 1; 0th bit is defined to
- be the least significant */
- ulint a, /* in: ulint */
- ulint n) /* in: nth bit requested */
-{
- ut_ad(n < 8 * sizeof(ulint));
-#if TRUE != 1
-# error "TRUE != 1"
-#endif
- return(1 & (a >> n));
-}
-
-/*********************************************************************
-Sets the nth bit of a ulint. */
-UNIV_INLINE
-ulint
-ut_bit_set_nth(
-/*===========*/
- /* out: the ulint with the bit set as requested */
- ulint a, /* in: ulint */
- ulint n, /* in: nth bit requested */
- ibool val) /* in: value for the bit to set */
-{
- ut_ad(n < 8 * sizeof(ulint));
-#if TRUE != 1
-# error "TRUE != 1"
-#endif
- if (val) {
- return(((ulint) 1 << n) | a);
- } else {
- return(~((ulint) 1 << n) & a);
- }
-}
diff --git a/storage/innobase/include/ut0dbg.h b/storage/innobase/include/ut0dbg.h
deleted file mode 100644
index a317f35f4be..00000000000
--- a/storage/innobase/include/ut0dbg.h
+++ /dev/null
@@ -1,113 +0,0 @@
-/*********************************************************************
-Debug utilities for Innobase
-
-(c) 1994, 1995 Innobase Oy
-
-Created 1/30/1994 Heikki Tuuri
-**********************************************************************/
-
-#ifndef ut0dbg_h
-#define ut0dbg_h
-
-#include "univ.i"
-#include
-#include "os0thread.h"
-
-#if defined(__GNUC__) && (__GNUC__ > 2)
-# define UT_DBG_FAIL(EXPR) UNIV_UNLIKELY(!((ulint)(EXPR)))
-#else
-extern ulint ut_dbg_zero; /* This is used to eliminate
- compiler warnings */
-# define UT_DBG_FAIL(EXPR) !((ulint)(EXPR) + ut_dbg_zero)
-#endif
-
-/*****************************************************************
-Report a failed assertion. */
-
-void
-ut_dbg_assertion_failed(
-/*====================*/
- const char* expr, /* in: the failed assertion */
- const char* file, /* in: source file containing the assertion */
- ulint line); /* in: line number of the assertion */
-
-#ifdef __NETWARE__
-/* Flag for ignoring further assertion failures.
-On NetWare, have a graceful exit rather than a segfault to avoid abends. */
-extern ibool panic_shutdown;
-/* Abort the execution. */
-void ut_dbg_panic(void);
-# define UT_DBG_PANIC ut_dbg_panic()
-/* Stop threads in ut_a(). */
-# define UT_DBG_STOP while (0) /* We do not do this on NetWare */
-#else /* __NETWARE__ */
-# if defined(__WIN__) || defined(__INTEL_COMPILER)
-# undef UT_DBG_USE_ABORT
-# elif defined(__GNUC__) && (__GNUC__ > 2)
-# define UT_DBG_USE_ABORT
-# endif
-
-# ifndef UT_DBG_USE_ABORT
-/* A null pointer that will be dereferenced to trigger a memory trap */
-extern ulint* ut_dbg_null_ptr;
-# endif
-
-# if defined(UNIV_SYNC_DEBUG) || !defined(UT_DBG_USE_ABORT)
-/* Flag for indicating that all threads should stop. This will be set
-by ut_dbg_assertion_failed(). */
-extern ibool ut_dbg_stop_threads;
-
-/*****************************************************************
-Stop a thread after assertion failure. */
-
-void
-ut_dbg_stop_thread(
-/*===============*/
- const char* file,
- ulint line);
-# endif
-
-# ifdef UT_DBG_USE_ABORT
-/* Abort the execution. */
-# define UT_DBG_PANIC abort()
-/* Stop threads (null operation) */
-# define UT_DBG_STOP while (0)
-# else /* UT_DBG_USE_ABORT */
-/* Abort the execution. */
-# define UT_DBG_PANIC \
- if (*(ut_dbg_null_ptr)) ut_dbg_null_ptr = NULL
-/* Stop threads in ut_a(). */
-# define UT_DBG_STOP do \
- if (UNIV_UNLIKELY(ut_dbg_stop_threads)) { \
- ut_dbg_stop_thread(__FILE__, (ulint) __LINE__); \
- } while (0)
-# endif /* UT_DBG_USE_ABORT */
-#endif /* __NETWARE__ */
-
-/* Abort execution if EXPR does not evaluate to nonzero. */
-#define ut_a(EXPR) do { \
- if (UT_DBG_FAIL(EXPR)) { \
- ut_dbg_assertion_failed(#EXPR, \
- __FILE__, (ulint) __LINE__); \
- UT_DBG_PANIC; \
- } \
- UT_DBG_STOP; \
-} while (0)
-
-/* Abort execution. */
-#define ut_error do { \
- ut_dbg_assertion_failed(0, __FILE__, (ulint) __LINE__); \
- UT_DBG_PANIC; \
-} while (0)
-
-#ifdef UNIV_DEBUG
-#define ut_ad(EXPR) ut_a(EXPR)
-#define ut_d(EXPR) do {EXPR;} while (0)
-#else
-#define ut_ad(EXPR)
-#define ut_d(EXPR)
-#endif
-
-#define UT_NOT_USED(A) A = A
-
-#endif
diff --git a/storage/innobase/include/ut0list.ic b/storage/innobase/include/ut0list.ic
deleted file mode 100644
index c2d3e4557f0..00000000000
--- a/storage/innobase/include/ut0list.ic
+++ /dev/null
@@ -1,23 +0,0 @@
-/********************************************************************
-Get the first node in the list. */
-UNIV_INLINE
-ib_list_node_t*
-ib_list_get_first(
-/*==============*/
- /* out: first node, or NULL */
- ib_list_t* list) /* in: list */
-{
- return(list->first);
-}
-
-/********************************************************************
-Get the last node in the list. */
-UNIV_INLINE
-ib_list_node_t*
-ib_list_get_last(
-/*=============*/
- /* out: last node, or NULL */
- ib_list_t* list) /* in: list */
-{
- return(list->last);
-}
diff --git a/storage/innobase/include/ut0mem.h b/storage/innobase/include/ut0mem.h
deleted file mode 100644
index e56895bc142..00000000000
--- a/storage/innobase/include/ut0mem.h
+++ /dev/null
@@ -1,212 +0,0 @@
-/***********************************************************************
-Memory primitives
-
-(c) 1994, 1995 Innobase Oy
-
-Created 5/30/1994 Heikki Tuuri
-************************************************************************/
-
-#ifndef ut0mem_h
-#define ut0mem_h
-
-#include "univ.i"
-#include
-#include
-
-/* The total amount of memory currently allocated from the OS with malloc */
-extern ulint ut_total_allocated_memory;
-
-UNIV_INLINE
-void*
-ut_memcpy(void* dest, const void* sour, ulint n);
-
-UNIV_INLINE
-void*
-ut_memmove(void* dest, const void* sour, ulint n);
-
-UNIV_INLINE
-int
-ut_memcmp(const void* str1, const void* str2, ulint n);
-
-
-/**************************************************************************
-Allocates memory. Sets it also to zero if UNIV_SET_MEM_TO_ZERO is
-defined and set_to_zero is TRUE. */
-
-void*
-ut_malloc_low(
-/*==========*/
- /* out, own: allocated memory */
- ulint n, /* in: number of bytes to allocate */
- ibool set_to_zero, /* in: TRUE if allocated memory
- should be set to zero if
- UNIV_SET_MEM_TO_ZERO is defined */
- ibool assert_on_error); /* in: if TRUE, we crash mysqld if
- the memory cannot be allocated */
-/**************************************************************************
-Allocates memory. Sets it also to zero if UNIV_SET_MEM_TO_ZERO is
-defined. */
-
-void*
-ut_malloc(
-/*======*/
- /* out, own: allocated memory */
- ulint n); /* in: number of bytes to allocate */
-/**************************************************************************
-Tests if malloc of n bytes would succeed. ut_malloc() asserts if memory runs
-out. It cannot be used if we want to return an error message. Prints to
-stderr a message if fails. */
-
-ibool
-ut_test_malloc(
-/*===========*/
- /* out: TRUE if succeeded */
- ulint n); /* in: try to allocate this many bytes */
-/**************************************************************************
-Frees a memory block allocated with ut_malloc. */
-
-void
-ut_free(
-/*====*/
- void* ptr); /* in, own: memory block */
-/**************************************************************************
-Implements realloc. This is needed by /pars/lexyy.c. Otherwise, you should not
-use this function because the allocation functions in mem0mem.h are the
-recommended ones in InnoDB.
-
-man realloc in Linux, 2004:
-
- realloc() changes the size of the memory block pointed to
- by ptr to size bytes. The contents will be unchanged to
- the minimum of the old and new sizes; newly allocated mem
- ory will be uninitialized. If ptr is NULL, the call is
- equivalent to malloc(size); if size is equal to zero, the
- call is equivalent to free(ptr). Unless ptr is NULL, it
- must have been returned by an earlier call to malloc(),
- calloc() or realloc().
-
-RETURN VALUE
- realloc() returns a pointer to the newly allocated memory,
- which is suitably aligned for any kind of variable and may
- be different from ptr, or NULL if the request fails. If
- size was equal to 0, either NULL or a pointer suitable to
- be passed to free() is returned. If realloc() fails the
- original block is left untouched - it is not freed or
- moved. */
-
-void*
-ut_realloc(
-/*=======*/
- /* out, own: pointer to new mem block or NULL */
- void* ptr, /* in: pointer to old block or NULL */
- ulint size); /* in: desired size */
-/**************************************************************************
-Frees in shutdown all allocated memory not freed yet. */
-
-void
-ut_free_all_mem(void);
-/*=================*/
-
-UNIV_INLINE
-char*
-ut_strcpy(char* dest, const char* sour);
-
-UNIV_INLINE
-ulint
-ut_strlen(const char* str);
-
-UNIV_INLINE
-int
-ut_strcmp(const void* str1, const void* str2);
-
-/**************************************************************************
-Copies up to size - 1 characters from the NUL-terminated string src to
-dst, NUL-terminating the result. Returns strlen(src), so truncation
-occurred if the return value >= size. */
-
-ulint
-ut_strlcpy(
-/*=======*/
- /* out: strlen(src) */
- char* dst, /* in: destination buffer */
- const char* src, /* in: source buffer */
- ulint size); /* in: size of destination buffer */
-
-/**************************************************************************
-Like ut_strlcpy, but if src doesn't fit in dst completely, copies the last
-(size - 1) bytes of src, not the first. */
-
-ulint
-ut_strlcpy_rev(
-/*===========*/
- /* out: strlen(src) */
- char* dst, /* in: destination buffer */
- const char* src, /* in: source buffer */
- ulint size); /* in: size of destination buffer */
-
-/**************************************************************************
-Compute strlen(ut_strcpyq(str, q)). */
-UNIV_INLINE
-ulint
-ut_strlenq(
-/*=======*/
- /* out: length of the string when quoted */
- const char* str, /* in: null-terminated string */
- char q); /* in: the quote character */
-
-/**************************************************************************
-Make a quoted copy of a NUL-terminated string. Leading and trailing
-quotes will not be included; only embedded quotes will be escaped.
-See also ut_strlenq() and ut_memcpyq(). */
-
-char*
-ut_strcpyq(
-/*=======*/
- /* out: pointer to end of dest */
- char* dest, /* in: output buffer */
- char q, /* in: the quote character */
- const char* src); /* in: null-terminated string */
-
-/**************************************************************************
-Make a quoted copy of a fixed-length string. Leading and trailing
-quotes will not be included; only embedded quotes will be escaped.
-See also ut_strlenq() and ut_strcpyq(). */
-
-char*
-ut_memcpyq(
-/*=======*/
- /* out: pointer to end of dest */
- char* dest, /* in: output buffer */
- char q, /* in: the quote character */
- const char* src, /* in: string to be quoted */
- ulint len); /* in: length of src */
-
-/**************************************************************************
-Return the number of times s2 occurs in s1. Overlapping instances of s2
-are only counted once. */
-
-ulint
-ut_strcount(
-/*========*/
- /* out: the number of times s2 occurs in s1 */
- const char* s1, /* in: string to search in */
- const char* s2); /* in: string to search for */
-
-/**************************************************************************
-Replace every occurrence of s1 in str with s2. Overlapping instances of s1
-are only replaced once. */
-
-char *
-ut_strreplace(
-/*==========*/
- /* out, own: modified string, must be
- freed with mem_free() */
- const char* str, /* in: string to operate on */
- const char* s1, /* in: string to replace */
- const char* s2); /* in: string to replace s1 with */
-
-#ifndef UNIV_NONINL
-#include "ut0mem.ic"
-#endif
-
-#endif
diff --git a/storage/innobase/include/ut0mem.ic b/storage/innobase/include/ut0mem.ic
deleted file mode 100644
index e0253ebf618..00000000000
--- a/storage/innobase/include/ut0mem.ic
+++ /dev/null
@@ -1,70 +0,0 @@
-/***********************************************************************
-Memory primitives
-
-(c) 1994, 1995 Innobase Oy
-
-Created 5/30/1994 Heikki Tuuri
-************************************************************************/
-
-UNIV_INLINE
-void*
-ut_memcpy(void* dest, const void* sour, ulint n)
-{
- return(memcpy(dest, sour, n));
-}
-
-UNIV_INLINE
-void*
-ut_memmove(void* dest, const void* sour, ulint n)
-{
- return(memmove(dest, sour, n));
-}
-
-UNIV_INLINE
-int
-ut_memcmp(const void* str1, const void* str2, ulint n)
-{
- return(memcmp(str1, str2, n));
-}
-
-UNIV_INLINE
-char*
-ut_strcpy(char* dest, const char* sour)
-{
- return(strcpy(dest, sour));
-}
-
-UNIV_INLINE
-ulint
-ut_strlen(const char* str)
-{
- return(strlen(str));
-}
-
-UNIV_INLINE
-int
-ut_strcmp(const void* str1, const void* str2)
-{
- return(strcmp((const char*)str1, (const char*)str2));
-}
-
-/**************************************************************************
-Compute strlen(ut_strcpyq(str, q)). */
-UNIV_INLINE
-ulint
-ut_strlenq(
-/*=======*/
- /* out: length of the string when quoted */
- const char* str, /* in: null-terminated string */
- char q) /* in: the quote character */
-{
- ulint len;
-
- for (len = 0; *str; len++, str++) {
- if (*str == q) {
- len++;
- }
- }
-
- return(len);
-}
diff --git a/storage/innobase/include/ut0rnd.h b/storage/innobase/include/ut0rnd.h
deleted file mode 100644
index 3f3fce1075c..00000000000
--- a/storage/innobase/include/ut0rnd.h
+++ /dev/null
@@ -1,121 +0,0 @@
-/**********************************************************************
-Random numbers and hashing
-
-(c) 1994, 1995 Innobase Oy
-
-Created 1/20/1994 Heikki Tuuri
-***********************************************************************/
-
-#ifndef ut0rnd_h
-#define ut0rnd_h
-
-#include "univ.i"
-
-#include "ut0byte.h"
-
-/* The 'character code' for end of field or string (used
-in folding records */
-#define UT_END_OF_FIELD 257
-
-/************************************************************
-This is used to set the random number seed. */
-UNIV_INLINE
-void
-ut_rnd_set_seed(
-/*============*/
- ulint seed); /* in: seed */
-/************************************************************
-The following function generates a series of 'random' ulint integers. */
-UNIV_INLINE
-ulint
-ut_rnd_gen_next_ulint(
-/*==================*/
- /* out: the next 'random' number */
- ulint rnd); /* in: the previous random number value */
-/*************************************************************
-The following function generates 'random' ulint integers which
-enumerate the value space (let there be N of them) of ulint integers
-in a pseudo-random fashion. Note that the same integer is repeated
-always after N calls to the generator. */
-UNIV_INLINE
-ulint
-ut_rnd_gen_ulint(void);
-/*==================*/
- /* out: the 'random' number */
-/************************************************************
-Generates a random integer from a given interval. */
-UNIV_INLINE
-ulint
-ut_rnd_interval(
-/*============*/
- /* out: the 'random' number */
- ulint low, /* in: low limit; can generate also this value */
- ulint high); /* in: high limit; can generate also this value */
-/*************************************************************
-Generates a random iboolean value. */
-UNIV_INLINE
-ibool
-ut_rnd_gen_ibool(void);
-/*=================*/
- /* out: the random value */
-/***********************************************************
-The following function generates a hash value for a ulint integer
-to a hash table of size table_size, which should be a prime or some
-random number to work reliably. */
-UNIV_INLINE
-ulint
-ut_hash_ulint(
-/*==========*/
- /* out: hash value */
- ulint key, /* in: value to be hashed */
- ulint table_size); /* in: hash table size */
-/*****************************************************************
-Folds a pair of ulints. */
-UNIV_INLINE
-ulint
-ut_fold_ulint_pair(
-/*===============*/
- /* out: folded value */
- ulint n1, /* in: ulint */
- ulint n2); /* in: ulint */
-/*****************************************************************
-Folds a dulint. */
-UNIV_INLINE
-ulint
-ut_fold_dulint(
-/*===========*/
- /* out: folded value */
- dulint d); /* in: dulint */
-/*****************************************************************
-Folds a character string ending in the null character. */
-UNIV_INLINE
-ulint
-ut_fold_string(
-/*===========*/
- /* out: folded value */
- const char* str); /* in: null-terminated string */
-/*****************************************************************
-Folds a binary string. */
-UNIV_INLINE
-ulint
-ut_fold_binary(
-/*===========*/
- /* out: folded value */
- const byte* str, /* in: string of bytes */
- ulint len); /* in: length */
-/***************************************************************
-Looks for a prime number slightly greater than the given argument.
-The prime is chosen so that it is not near any power of 2. */
-
-ulint
-ut_find_prime(
-/*==========*/
- /* out: prime */
- ulint n); /* in: positive number > 100 */
-
-
-#ifndef UNIV_NONINL
-#include "ut0rnd.ic"
-#endif
-
-#endif
diff --git a/storage/innobase/include/ut0ut.h b/storage/innobase/include/ut0ut.h
deleted file mode 100644
index 95d7ba017f1..00000000000
--- a/storage/innobase/include/ut0ut.h
+++ /dev/null
@@ -1,323 +0,0 @@
-/**********************************************************************
-Various utilities
-
-(c) 1994, 1995 Innobase Oy
-
-Created 1/20/1994 Heikki Tuuri
-***********************************************************************/
-
-#ifndef ut0ut_h
-#define ut0ut_h
-
-#include "univ.i"
-#include
-#ifndef MYSQL_SERVER
-#include
-#endif
-
-typedef time_t ib_time_t;
-
-#ifdef HAVE_PAUSE_INSTRUCTION
-#define PAUSE_INSTRUCTION() {__asm__ __volatile__ ("pause");}
-#else
-#ifdef HAVE_FAKE_PAUSE_INSTRUCTION
-#define PAUSE_INSTRUCTION() {__asm__ __volatile__ ("rep; nop");}
-#else
-#ifdef UNIV_SYNC_ATOMIC
-#define PAUSE_INSTRUCTION() \
- { \
- volatile lint volatile_var; \
- os_compare_and_swap(&volatile_var, 0, 1); \
- }
-#else
-#define PAUSE_INSTRUCTION()
-#endif
-#endif
-#endif
-
-/************************************************************
-Gets the high 32 bits in a ulint. That is makes a shift >> 32,
-but since there seem to be compiler bugs in both gcc and Visual C++,
-we do this by a special conversion. */
-
-ulint
-ut_get_high32(
-/*==========*/
- /* out: a >> 32 */
- ulint a); /* in: ulint */
-/**********************************************************
-Calculates the minimum of two ulints. */
-UNIV_INLINE
-ulint
-ut_min(
-/*===*/
- /* out: minimum */
- ulint n1, /* in: first number */
- ulint n2); /* in: second number */
-/**********************************************************
-Calculates the maximum of two ulints. */
-UNIV_INLINE
-ulint
-ut_max(
-/*===*/
- /* out: maximum */
- ulint n1, /* in: first number */
- ulint n2); /* in: second number */
-/********************************************************************
-Calculates minimum of two ulint-pairs. */
-UNIV_INLINE
-void
-ut_pair_min(
-/*========*/
- ulint* a, /* out: more significant part of minimum */
- ulint* b, /* out: less significant part of minimum */
- ulint a1, /* in: more significant part of first pair */
- ulint b1, /* in: less significant part of first pair */
- ulint a2, /* in: more significant part of second pair */
- ulint b2); /* in: less significant part of second pair */
-/**********************************************************
-Compares two ulints. */
-UNIV_INLINE
-int
-ut_ulint_cmp(
-/*=========*/
- /* out: 1 if a > b, 0 if a == b, -1 if a < b */
- ulint a, /* in: ulint */
- ulint b); /* in: ulint */
-/***********************************************************
-Compares two pairs of ulints. */
-UNIV_INLINE
-int
-ut_pair_cmp(
-/*========*/
- /* out: -1 if a < b, 0 if a == b,
- 1 if a > b */
- ulint a1, /* in: more significant part of first pair */
- ulint a2, /* in: less significant part of first pair */
- ulint b1, /* in: more significant part of second pair */
- ulint b2); /* in: less significant part of second pair */
-/*****************************************************************
-Calculates fast the remainder when divided by a power of two. */
-UNIV_INLINE
-ulint
-ut_2pow_remainder(
-/*==============*/ /* out: remainder */
- ulint n, /* in: number to be divided */
- ulint m); /* in: divisor; power of 2 */
-/*****************************************************************
-Calculates fast value rounded to a multiple of a power of 2. */
-UNIV_INLINE
-ulint
-ut_2pow_round(
-/*==========*/ /* out: value of n rounded down to nearest
- multiple of m */
- ulint n, /* in: number to be rounded */
- ulint m); /* in: divisor; power of 2 */
-/*****************************************************************
-Calculates fast the 2-logarithm of a number, rounded upward to an
-integer. */
-UNIV_INLINE
-ulint
-ut_2_log(
-/*=====*/
- /* out: logarithm in the base 2, rounded upward */
- ulint n); /* in: number */
-/*****************************************************************
-Calculates 2 to power n. */
-UNIV_INLINE
-ulint
-ut_2_exp(
-/*=====*/
- /* out: 2 to power n */
- ulint n); /* in: number */
-/*****************************************************************
-Calculates fast the number rounded up to the nearest power of 2. */
-
-ulint
-ut_2_power_up(
-/*==========*/
- /* out: first power of 2 which is >= n */
- ulint n) /* in: number != 0 */
- __attribute__((const));
-
-/* Determine how many bytes (groups of 8 bits) are needed to
-store the given number of bits. */
-#define UT_BITS_IN_BYTES(b) (((b) + 7) / 8)
-
-/****************************************************************
-Sort function for ulint arrays. */
-
-void
-ut_ulint_sort(ulint* arr, ulint* aux_arr, ulint low, ulint high);
-/*============================================================*/
-/************************************************************
-The following function returns elapsed CPU time in milliseconds. */
-
-ulint
-ut_clock(void);
-/**************************************************************
-Returns system time. We do not specify the format of the time returned:
-the only way to manipulate it is to use the function ut_difftime. */
-
-ib_time_t
-ut_time(void);
-/*=========*/
-/**************************************************************
-Returns system time.
-Upon successful completion, the value 0 is returned; otherwise the
-value -1 is returned and the global variable errno is set to indicate the
-error. */
-
-int
-ut_usectime(
-/*========*/
- /* out: 0 on success, -1 otherwise */
- ulint* sec, /* out: seconds since the Epoch */
- ulint* ms); /* out: microseconds since the Epoch+*sec */
-
-/**************************************************************
-Returns diff in microseconds (end_sec,end_ms) - (start_sec,start_ms). */
-
-ib_longlong
-ut_usecdiff(
-/*========*/
- ulint end_sec, /* in: seconds since the Epoch */
- ulint end_ms, /* in: microseconds since the Epoch+*sec1 */
- ulint start_sec, /* in: seconds since the Epoch */
- ulint start_ms); /* in: microseconds since the Epoch+*sec2 */
-
-/**************************************************************
-Returns the difference of two times in seconds. */
-
-double
-ut_difftime(
-/*========*/
- /* out: time2 - time1 expressed in seconds */
- ib_time_t time2, /* in: time */
- ib_time_t time1); /* in: time */
-/**************************************************************
-Prints a timestamp to a file. */
-
-void
-ut_print_timestamp(
-/*===============*/
- FILE* file); /* in: file where to print */
-/**************************************************************
-Sprintfs a timestamp to a buffer, 13..14 chars plus terminating NUL. */
-
-void
-ut_sprintf_timestamp(
-/*=================*/
- char* buf); /* in: buffer where to sprintf */
-/**************************************************************
-Sprintfs a timestamp to a buffer with no spaces and with ':' characters
-replaced by '_'. */
-
-void
-ut_sprintf_timestamp_without_extra_chars(
-/*=====================================*/
- char* buf); /* in: buffer where to sprintf */
-/**************************************************************
-Returns current year, month, day. */
-
-void
-ut_get_year_month_day(
-/*==================*/
- ulint* year, /* out: current year */
- ulint* month, /* out: month */
- ulint* day); /* out: day */
-/*****************************************************************
-Runs an idle loop on CPU. The argument gives the desired delay
-in microseconds on 100 MHz Pentium + Visual C++. */
-
-ulint
-ut_delay(
-/*=====*/
- /* out: dummy value */
- ulint delay); /* in: delay in microseconds on 100 MHz Pentium */
-/*****************************************************************
-Prints the contents of a memory buffer in hex and ascii. */
-
-void
-ut_print_buf(
-/*=========*/
- FILE* file, /* in: file where to print */
- const void* buf, /* in: memory buffer */
- ulint len); /* in: length of the buffer */
-
-/**************************************************************************
-Outputs a NUL-terminated file name, quoted with apostrophes. */
-
-void
-ut_print_filename(
-/*==============*/
- FILE* f, /* in: output stream */
- const char* name); /* in: name to print */
-
-/* Forward declaration of transaction handle */
-struct trx_struct;
-
-/**************************************************************************
-Outputs a fixed-length string, quoted as an SQL identifier.
-If the string contains a slash '/', the string will be
-output as two identifiers separated by a period (.),
-as in SQL database_name.identifier. */
-
-void
-ut_print_name(
-/*==========*/
- FILE* f, /* in: output stream */
- struct trx_struct*trx, /* in: transaction */
- ibool table_id,/* in: TRUE=print a table name,
- FALSE=print other identifier */
- const char* name); /* in: name to print */
-
-/**************************************************************************
-Outputs a fixed-length string, quoted as an SQL identifier.
-If the string contains a slash '/', the string will be
-output as two identifiers separated by a period (.),
-as in SQL database_name.identifier. */
-
-void
-ut_print_namel(
-/*===========*/
- FILE* f, /* in: output stream */
- struct trx_struct*trx, /* in: transaction (NULL=no quotes) */
- ibool table_id,/* in: TRUE=print a table name,
- FALSE=print other identifier */
- const char* name, /* in: name to print */
- ulint namelen);/* in: length of name */
-
-/**************************************************************************
-Catenate files. */
-
-void
-ut_copy_file(
-/*=========*/
- FILE* dest, /* in: output file */
- FILE* src); /* in: input file to be appended to output */
-
-/**************************************************************************
-snprintf(). */
-
-#ifdef __WIN__
-int
-ut_snprintf(
- /* out: number of characters that would
- have been printed if the size were
- unlimited, not including the terminating
- '\0'. */
- char* str, /* out: string */
- size_t size, /* in: str size */
- const char* fmt, /* in: format */
- ...); /* in: format values */
-#else
-#define ut_snprintf snprintf
-#endif /* __WIN__ */
-
-#ifndef UNIV_NONINL
-#include "ut0ut.ic"
-#endif
-
-#endif
-
diff --git a/storage/innobase/include/ut0ut.ic b/storage/innobase/include/ut0ut.ic
deleted file mode 100644
index 412717a094e..00000000000
--- a/storage/innobase/include/ut0ut.ic
+++ /dev/null
@@ -1,174 +0,0 @@
-/******************************************************************
-Various utilities
-
-(c) 1994, 1995 Innobase Oy
-
-Created 5/30/1994 Heikki Tuuri
-*******************************************************************/
-
-/**********************************************************
-Calculates the minimum of two ulints. */
-UNIV_INLINE
-ulint
-ut_min(
-/*===*/
- /* out: minimum */
- ulint n1, /* in: first number */
- ulint n2) /* in: second number */
-{
- return((n1 <= n2) ? n1 : n2);
-}
-
-/**********************************************************
-Calculates the maximum of two ulints. */
-UNIV_INLINE
-ulint
-ut_max(
-/*===*/
- /* out: maximum */
- ulint n1, /* in: first number */
- ulint n2) /* in: second number */
-{
- return((n1 <= n2) ? n2 : n1);
-}
-
-/********************************************************************
-Calculates minimum of two ulint-pairs. */
-UNIV_INLINE
-void
-ut_pair_min(
-/*========*/
- ulint* a, /* out: more significant part of minimum */
- ulint* b, /* out: less significant part of minimum */
- ulint a1, /* in: more significant part of first pair */
- ulint b1, /* in: less significant part of first pair */
- ulint a2, /* in: more significant part of second pair */
- ulint b2) /* in: less significant part of second pair */
-{
- if (a1 == a2) {
- *a = a1;
- *b = ut_min(b1, b2);
- } else if (a1 < a2) {
- *a = a1;
- *b = b1;
- } else {
- *a = a2;
- *b = b2;
- }
-}
-
-/**********************************************************
-Compares two ulints. */
-UNIV_INLINE
-int
-ut_ulint_cmp(
-/*=========*/
- /* out: 1 if a > b, 0 if a == b, -1 if a < b */
- ulint a, /* in: ulint */
- ulint b) /* in: ulint */
-{
- if (a < b) {
- return(-1);
- } else if (a == b) {
- return(0);
- } else {
- return(1);
- }
-}
-
-/***********************************************************
-Compares two pairs of ulints. */
-UNIV_INLINE
-int
-ut_pair_cmp(
-/*========*/
- /* out: -1 if a < b, 0 if a == b, 1 if a > b */
- ulint a1, /* in: more significant part of first pair */
- ulint a2, /* in: less significant part of first pair */
- ulint b1, /* in: more significant part of second pair */
- ulint b2) /* in: less significant part of second pair */
-{
- if (a1 > b1) {
- return(1);
- } else if (a1 < b1) {
- return(-1);
- } else if (a2 > b2) {
- return(1);
- } else if (a2 < b2) {
- return(-1);
- } else {
- return(0);
- }
-}
-
-/*****************************************************************
-Calculates fast the remainder when divided by a power of two. */
-UNIV_INLINE
-ulint
-ut_2pow_remainder(
-/*==============*/ /* out: remainder */
- ulint n, /* in: number to be divided */
- ulint m) /* in: divisor; power of 2 */
-{
- ut_ad(0x80000000UL % m == 0);
-
- return(n & (m - 1));
-}
-
-/*****************************************************************
-Calculates fast a value rounded to a multiple of a power of 2. */
-UNIV_INLINE
-ulint
-ut_2pow_round(
-/*==========*/ /* out: value of n rounded down to nearest
- multiple of m */
- ulint n, /* in: number to be rounded */
- ulint m) /* in: divisor; power of 2 */
-{
- ut_ad(0x80000000UL % m == 0);
-
- return(n & ~(m - 1));
-}
-
-/*****************************************************************
-Calculates fast the 2-logarithm of a number, rounded upward to an
-integer. */
-UNIV_INLINE
-ulint
-ut_2_log(
-/*=====*/
- /* out: logarithm in the base 2, rounded upward */
- ulint n) /* in: number != 0 */
-{
- ulint res;
-
- res = 0;
-
- ut_ad(n > 0);
-
- n = n - 1;
-
- for (;;) {
- n = n / 2;
-
- if (n == 0) {
- break;
- }
-
- res++;
- }
-
- return(res + 1);
-}
-
-/*****************************************************************
-Calculates 2 to power n. */
-UNIV_INLINE
-ulint
-ut_2_exp(
-/*=====*/
- /* out: 2 to power n */
- ulint n) /* in: number */
-{
- return((ulint) 1 << n);
-}
diff --git a/storage/innobase/include/ut0vec.h b/storage/innobase/include/ut0vec.h
deleted file mode 100644
index e0cc4dfb009..00000000000
--- a/storage/innobase/include/ut0vec.h
+++ /dev/null
@@ -1,73 +0,0 @@
-#ifndef IB_VECTOR_H
-#define IB_VECTOR_H
-
-#include "univ.i"
-#include "mem0mem.h"
-
-typedef struct ib_vector_struct ib_vector_t;
-
-/* An automatically resizing vector datatype with the following properties:
-
- -Contains void* items.
-
- -The items are owned by the caller.
-
- -All memory allocation is done through a heap owned by the caller, who is
- responsible for freeing it when done with the vector.
-
- -When the vector is resized, the old memory area is left allocated since it
- uses the same heap as the new memory area, so this is best used for
- relatively small or short-lived uses.
-*/
-
-/********************************************************************
-Create a new vector with the given initial size. */
-
-ib_vector_t*
-ib_vector_create(
-/*=============*/
- /* out: vector */
- mem_heap_t* heap, /* in: heap */
- ulint size); /* in: initial size */
-
-/********************************************************************
-Push a new element to the vector, increasing its size if necessary. */
-
-void
-ib_vector_push(
-/*===========*/
- ib_vector_t* vec, /* in: vector */
- void* elem); /* in: data element */
-
-/********************************************************************
-Get the number of elements in the vector. */
-UNIV_INLINE
-ulint
-ib_vector_size(
-/*===========*/
- /* out: number of elements in vector */
- ib_vector_t* vec); /* in: vector */
-
-/********************************************************************
-Get the n'th element. */
-UNIV_INLINE
-void*
-ib_vector_get(
-/*==========*/
- /* out: n'th element */
- ib_vector_t* vec, /* in: vector */
- ulint n); /* in: element index to get */
-
-/* See comment at beginning of file. */
-struct ib_vector_struct {
- mem_heap_t* heap; /* heap */
- void** data; /* data elements */
- ulint used; /* number of elements currently used */
- ulint total; /* number of elements allocated */
-};
-
-#ifndef UNIV_NONINL
-#include "ut0vec.ic"
-#endif
-
-#endif
diff --git a/storage/innobase/include/ut0vec.ic b/storage/innobase/include/ut0vec.ic
deleted file mode 100644
index 417a17d951f..00000000000
--- a/storage/innobase/include/ut0vec.ic
+++ /dev/null
@@ -1,26 +0,0 @@
-/********************************************************************
-Get number of elements in vector. */
-UNIV_INLINE
-ulint
-ib_vector_size(
-/*===========*/
- /* out: number of elements in vector */
- ib_vector_t* vec) /* in: vector */
-{
- return(vec->used);
-}
-
-/********************************************************************
-Get n'th element. */
-UNIV_INLINE
-void*
-ib_vector_get(
-/*==========*/
- /* out: n'th element */
- ib_vector_t* vec, /* in: vector */
- ulint n) /* in: element index to get */
-{
- ut_a(n < vec->used);
-
- return(vec->data[n]);
-}
diff --git a/storage/innobase/include/ut0wqueue.h b/storage/innobase/include/ut0wqueue.h
deleted file mode 100644
index 57f2297beee..00000000000
--- a/storage/innobase/include/ut0wqueue.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/***********************************************************************
-A Work queue. Threads can add work items to the queue and other threads can
-wait for work items to be available and take them off the queue for
-processing.
-
-************************************************************************/
-
-#ifndef IB_WORK_QUEUE_H
-#define IB_WORK_QUEUE_H
-
-#include "ut0list.h"
-#include "mem0mem.h"
-#include "os0sync.h"
-#include "sync0types.h"
-
-typedef struct ib_wqueue_struct ib_wqueue_t;
-
-/********************************************************************
-Create a new work queue. */
-
-ib_wqueue_t*
-ib_wqueue_create(void);
-/*===================*/
- /* out: work queue */
-
-/********************************************************************
-Free a work queue. */
-
-void
-ib_wqueue_free(
-/*===========*/
- ib_wqueue_t* wq); /* in: work queue */
-
-/********************************************************************
-Add a work item to the queue. */
-
-void
-ib_wqueue_add(
-/*==========*/
- ib_wqueue_t* wq, /* in: work queue */
- void* item, /* in: work item */
- mem_heap_t* heap); /* in: memory heap to use for allocating the
- list node */
-
-/********************************************************************
-Wait for a work item to appear in the queue. */
-
-void*
-ib_wqueue_wait(
- /* out: work item */
- ib_wqueue_t* wq); /* in: work queue */
-
-/* Work queue. */
-struct ib_wqueue_struct {
- mutex_t mutex; /* mutex protecting everything */
- ib_list_t* items; /* work item list */
- os_event_t event; /* event we use to signal additions to list */
-};
-
-#endif
diff --git a/storage/innobase/os/os0proc.c b/storage/innobase/os/os0proc.c
deleted file mode 100644
index a99fe8b6a0e..00000000000
--- a/storage/innobase/os/os0proc.c
+++ /dev/null
@@ -1,674 +0,0 @@
-/******************************************************
-The interface to the operating system
-process control primitives
-
-(c) 1995 Innobase Oy
-
-Created 9/30/1995 Heikki Tuuri
-*******************************************************/
-
-#include "os0proc.h"
-#ifdef UNIV_NONINL
-#include "os0proc.ic"
-#endif
-
-#include "ut0mem.h"
-#include "ut0byte.h"
-
-
-/*
-How to get AWE to compile on Windows?
--------------------------------------
-
-In the project settings of the innobase project the Visual C++ source,
-__WIN2000__ has to be defined.
-
-The Visual C++ has to be relatively recent and _WIN32_WINNT has to be
-defined to a value >= 0x0500 when windows.h is included.
-
-#define _WIN32_WINNT 0x0500
-
-Where does AWE work?
--------------------
-
-See the error message in os_awe_allocate_physical_mem().
-
-How to assign privileges for mysqld to use AWE?
------------------------------------------------
-
-See the error message in os_awe_enable_lock_pages_in_mem().
-
-Use Windows AWE functions in this order
----------------------------------------
-
-(1) os_awe_enable_lock_pages_in_mem();
-(2) os_awe_allocate_physical_mem();
-(3) os_awe_allocate_virtual_mem_window();
-(4) os_awe_map_physical_mem_to_window().
-
-To test 'AWE' in a computer which does not have the AWE API,
-you can compile with UNIV_SIMULATE_AWE defined in this file.
-*/
-
-#ifdef UNIV_SIMULATE_AWE
-/* If we simulate AWE, we allocate the 'physical memory' here */
-byte* os_awe_simulate_mem;
-ulint os_awe_simulate_mem_size;
-os_awe_t* os_awe_simulate_page_info;
-byte* os_awe_simulate_window;
-ulint os_awe_simulate_window_size;
-/* In simulated AWE the following contains a NULL pointer or a pointer
-to a mapped 'physical page' for each 4 kB page in the AWE window */
-byte** os_awe_simulate_map;
-#endif
-
-#ifdef __WIN2000__
-os_awe_t* os_awe_page_info;
-ulint os_awe_n_pages;
-byte* os_awe_window;
-ulint os_awe_window_size;
-#endif
-
-ibool os_use_large_pages;
-/* Large page size. This may be a boot-time option on some platforms */
-ulint os_large_page_size;
-
-/********************************************************************
-Windows AWE support. Tries to enable the "lock pages in memory" privilege for
-the current process so that the current process can allocate memory-locked
-virtual address space to act as the window where AWE maps physical memory. */
-
-ibool
-os_awe_enable_lock_pages_in_mem(void)
-/*=================================*/
- /* out: TRUE if success, FALSE if error;
- prints error info to stderr if no success */
-{
-#ifdef UNIV_SIMULATE_AWE
-
- return(TRUE);
-
-#elif defined(__WIN2000__)
- struct {
- DWORD Count;
- LUID_AND_ATTRIBUTES Privilege[1];
- } Info;
- HANDLE hProcess;
- HANDLE Token;
- BOOL Result;
-
- hProcess = GetCurrentProcess();
-
- /* Open the token of the current process */
-
- Result = OpenProcessToken(hProcess,
- TOKEN_ADJUST_PRIVILEGES, &Token);
- if (Result != TRUE) {
- fprintf(stderr,
- "InnoDB: AWE: Cannot open process token, error %lu\n",
- (ulint)GetLastError());
- return(FALSE);
- }
-
- Info.Count = 1;
-
- Info.Privilege[0].Attributes = SE_PRIVILEGE_ENABLED;
-
- /* Get the local unique identifier (LUID) of the SE_LOCK_MEMORY
- privilege */
-
- Result = LookupPrivilegeValue(NULL, SE_LOCK_MEMORY_NAME,
- &(Info.Privilege[0].Luid));
- if (Result != TRUE) {
- fprintf(stderr,
- "InnoDB: AWE: Cannot get local privilege"
- " value for %s, error %lu.\n",
- SE_LOCK_MEMORY_NAME, (ulint)GetLastError());
-
- return(FALSE);
- }
-
- /* Try to adjust the privilege */
-
- Result = AdjustTokenPrivileges(Token, FALSE,
- (PTOKEN_PRIVILEGES)&Info,
- 0, NULL, NULL);
- /* Check the result */
-
- if (Result != TRUE) {
- fprintf(stderr,
- "InnoDB: AWE: Cannot adjust process token privileges,"
- " error %u.\n",
- GetLastError());
- return(FALSE);
- } else if (GetLastError() != ERROR_SUCCESS) {
- fprintf(stderr,
- "InnoDB: AWE: Cannot enable SE_LOCK_MEMORY privilege,"
- " error %lu.\n"
- "InnoDB: In Windows XP Home you cannot use AWE."
- " In Windows 2000 and XP\n"
- "InnoDB: Professional you must go to the"
- " Control Panel, to\n"
- "InnoDB: Security Settings, to Local Policies,"
- " and enable\n"
- "InnoDB: the 'lock pages in memory' privilege"
- " for the user who runs\n"
- "InnoDB: the MySQL server.\n", GetLastError());
-
- return(FALSE);
- }
-
- CloseHandle(Token);
-
- return(TRUE);
-#else
-#ifdef __WIN__
- fprintf(stderr,
- "InnoDB: AWE: Error: to use AWE you must use"
- " a ...-nt MySQL executable.\n");
-#endif
- return(FALSE);
-#endif
-}
-
-/********************************************************************
-Allocates physical RAM memory up to 64 GB in an Intel 32-bit x86
-processor. */
-
-ibool
-os_awe_allocate_physical_mem(
-/*=========================*/
- /* out: TRUE if success */
- os_awe_t** page_info, /* out, own: array of opaque data containing
- the info for allocated physical memory pages;
- each allocated 4 kB physical memory page has
- one slot of type os_awe_t in the array */
- ulint n_megabytes) /* in: number of megabytes to allocate */
-{
-#ifdef UNIV_SIMULATE_AWE
- os_awe_simulate_page_info = ut_malloc
- (sizeof(os_awe_t) * n_megabytes
- * ((1024 * 1024) / OS_AWE_X86_PAGE_SIZE));
-
- os_awe_simulate_mem
- = ut_align(ut_malloc(4096 + 1024 * 1024 * n_megabytes), 4096);
- os_awe_simulate_mem_size = n_megabytes * 1024 * 1024;
-
- *page_info = os_awe_simulate_page_info;
-
- return(TRUE);
-
-#elif defined(__WIN2000__)
- BOOL bResult;
- os_awe_t NumberOfPages; /* Question: why does Windows
- use the name ULONG_PTR for
- a scalar integer type? Maybe
- because we may also refer to
- &NumberOfPages? */
- os_awe_t NumberOfPagesInitial;
- SYSTEM_INFO sSysInfo;
- int PFNArraySize;
-
- if (n_megabytes > 64 * 1024) {
-
- fprintf(stderr,
- "InnoDB: AWE: Error: tried to allocate %lu MB.\n"
- "InnoDB: AWE cannot allocate more than"
- " 64 GB in any computer.\n", n_megabytes);
-
- return(FALSE);
- }
-
- GetSystemInfo(&sSysInfo); /* fill the system information structure */
-
- if ((ulint)OS_AWE_X86_PAGE_SIZE != (ulint)sSysInfo.dwPageSize) {
- fprintf(stderr,
- "InnoDB: AWE: Error: this computer has a page size"
- " of %lu.\n"
- "InnoDB: Should be 4096 bytes for"
- " InnoDB AWE support to work.\n",
- (ulint)sSysInfo.dwPageSize);
-
- return(FALSE);
- }
-
- /* Calculate the number of pages of memory to request */
-
- NumberOfPages = n_megabytes * ((1024 * 1024) / OS_AWE_X86_PAGE_SIZE);
-
- /* Calculate the size of page_info for allocated physical pages */
-
- PFNArraySize = NumberOfPages * sizeof(os_awe_t);
-
- *page_info = (os_awe_t*)HeapAlloc(GetProcessHeap(), 0, PFNArraySize);
-
- if (*page_info == NULL) {
- fprintf(stderr,
- "InnoDB: AWE: Failed to allocate page info"
- " array from process heap, error %lu\n",
- (ulint)GetLastError());
-
- return(FALSE);
- }
-
- ut_total_allocated_memory += PFNArraySize;
-
- /* Enable this process' privilege to lock pages to physical memory */
-
- if (!os_awe_enable_lock_pages_in_mem()) {
-
- return(FALSE);
- }
-
- /* Allocate the physical memory */
-
- NumberOfPagesInitial = NumberOfPages;
-
- os_awe_page_info = *page_info;
- os_awe_n_pages = (ulint)NumberOfPages;
-
- /* Compilation note: if the compiler complains the function is not
- defined, see the note at the start of this file */
-
- bResult = AllocateUserPhysicalPages(GetCurrentProcess(),
- &NumberOfPages, *page_info);
- if (bResult != TRUE) {
- fprintf(stderr,
- "InnoDB: AWE: Cannot allocate physical pages,"
- " error %lu.\n",
- (ulint)GetLastError());
-
- return(FALSE);
- }
-
- if (NumberOfPagesInitial != NumberOfPages) {
- fprintf(stderr,
- "InnoDB: AWE: Error: allocated only %lu pages"
- " of %lu requested.\n"
- "InnoDB: Check that you have enough free RAM.\n"
- "InnoDB: In Windows XP Professional and"
- " 2000 Professional\n"
- "InnoDB: Windows PAE size is max 4 GB."
- " In 2000 and .NET\n"
- "InnoDB: Advanced Servers and 2000 Datacenter Server"
- " it is 32 GB,\n"
- "InnoDB: and in .NET Datacenter Server it is 64 GB.\n"
- "InnoDB: A Microsoft web page said that"
- " the processor must be an Intel\n"
- "InnoDB: processor.\n",
- (ulint)NumberOfPages,
- (ulint)NumberOfPagesInitial);
-
- return(FALSE);
- }
-
- fprintf(stderr,
- "InnoDB: Using Address Windowing Extensions (AWE);"
- " allocated %lu MB\n",
- n_megabytes);
-
- return(TRUE);
-#else
- UT_NOT_USED(n_megabytes);
- UT_NOT_USED(page_info);
-
- return(FALSE);
-#endif
-}
-
-/********************************************************************
-Allocates a window in the virtual address space where we can map then
-pages of physical memory. */
-
-byte*
-os_awe_allocate_virtual_mem_window(
-/*===============================*/
- /* out, own: allocated memory, or NULL if did not
- succeed */
- ulint size) /* in: virtual memory allocation size in bytes, must
- be < 2 GB */
-{
-#ifdef UNIV_SIMULATE_AWE
- ulint i;
-
- os_awe_simulate_window = ut_align(ut_malloc(4096 + size), 4096);
- os_awe_simulate_window_size = size;
-
- os_awe_simulate_map = ut_malloc(sizeof(byte*) * (size / 4096));
-
- for (i = 0; i < (size / 4096); i++) {
- *(os_awe_simulate_map + i) = NULL;
- }
-
- return(os_awe_simulate_window);
-
-#elif defined(__WIN2000__)
- byte* ptr;
-
- if (size > (ulint)0x7FFFFFFFUL) {
- fprintf(stderr,
- "InnoDB: AWE: Cannot allocate %lu bytes"
- " of virtual memory\n", size);
-
- return(NULL);
- }
-
- ptr = VirtualAlloc(NULL, (SIZE_T)size, MEM_RESERVE | MEM_PHYSICAL,
- PAGE_READWRITE);
- if (ptr == NULL) {
- fprintf(stderr,
- "InnoDB: AWE: Cannot allocate %lu bytes"
- " of virtual memory, error %lu\n",
- size, (ulint)GetLastError());
-
- return(NULL);
- }
-
- os_awe_window = ptr;
- os_awe_window_size = size;
-
- ut_total_allocated_memory += size;
-
- return(ptr);
-#else
- UT_NOT_USED(size);
-
- return(NULL);
-#endif
-}
-
-/********************************************************************
-With this function you can map parts of physical memory allocated with
-the ..._allocate_physical_mem to the virtual address space allocated with
-the previous function. Intel implements this so that the process page
-tables are updated accordingly. A test on a 1.5 GHz AMD processor and XP
-showed that this takes < 1 microsecond, much better than the estimated 80 us
-for copying a 16 kB page memory to memory. But, the operation will at least
-partially invalidate the translation lookaside buffer (TLB) of all
-processors. Under a real-world load the performance hit may be bigger. */
-
-ibool
-os_awe_map_physical_mem_to_window(
-/*==============================*/
- /* out: TRUE if success; the function
- calls exit(1) in case of an error */
- byte* ptr, /* in: a page-aligned pointer to
- somewhere in the virtual address
- space window; we map the physical mem
- pages here */
- ulint n_mem_pages, /* in: number of 4 kB mem pages to
- map */
- os_awe_t* page_info) /* in: array of page infos for those
- pages; each page has one slot in the
- array */
-{
-#ifdef UNIV_SIMULATE_AWE
- ulint i;
- byte** map;
- byte* page;
- byte* phys_page;
-
- ut_a(ptr >= os_awe_simulate_window);
- ut_a(ptr < os_awe_simulate_window + os_awe_simulate_window_size);
- ut_a(page_info >= os_awe_simulate_page_info);
- ut_a(page_info < os_awe_simulate_page_info
- + (os_awe_simulate_mem_size / 4096));
-
- /* First look if some other 'physical pages' are mapped at ptr,
- and copy them back to where they were if yes */
-
- map = os_awe_simulate_map
- + ((ulint)(ptr - os_awe_simulate_window)) / 4096;
- page = ptr;
-
- for (i = 0; i < n_mem_pages; i++) {
- if (*map != NULL) {
- ut_memcpy(*map, page, 4096);
- }
- map++;
- page += 4096;
- }
-
- /* Then copy to ptr the 'physical pages' determined by page_info; we
- assume page_info is a segment of the array we created at the start */
-
- phys_page = os_awe_simulate_mem
- + (ulint)(page_info - os_awe_simulate_page_info)
- * 4096;
-
- ut_memcpy(ptr, phys_page, n_mem_pages * 4096);
-
- /* Update the map */
-
- map = os_awe_simulate_map
- + ((ulint)(ptr - os_awe_simulate_window)) / 4096;
-
- for (i = 0; i < n_mem_pages; i++) {
- *map = phys_page;
-
- map++;
- phys_page += 4096;
- }
-
- return(TRUE);
-
-#elif defined(__WIN2000__)
- BOOL bResult;
- os_awe_t n_pages;
-
- n_pages = (os_awe_t)n_mem_pages;
-
- if (!(ptr >= os_awe_window)) {
- fprintf(stderr,
- "InnoDB: AWE: Error: trying to map to address %lx"
- " but AWE window start %lx\n",
- (ulint)ptr, (ulint)os_awe_window);
- ut_a(0);
- }
-
- if (!(ptr <= os_awe_window + os_awe_window_size - UNIV_PAGE_SIZE)) {
- fprintf(stderr,
- "InnoDB: AWE: Error: trying to map to address %lx"
- " but AWE window end %lx\n",
- (ulint)ptr, (ulint)os_awe_window + os_awe_window_size);
- ut_a(0);
- }
-
- if (!(page_info >= os_awe_page_info)) {
- fprintf(stderr,
- "InnoDB: AWE: Error: trying to map page info"
- " at %lx but array start %lx\n",
- (ulint)page_info, (ulint)os_awe_page_info);
- ut_a(0);
- }
-
- if (!(page_info <= os_awe_page_info + (os_awe_n_pages - 4))) {
- fprintf(stderr,
- "InnoDB: AWE: Error: trying to map page info"
- " at %lx but array end %lx\n",
- (ulint)page_info,
- (ulint)(os_awe_page_info + os_awe_n_pages));
- ut_a(0);
- }
-
- bResult = MapUserPhysicalPages((PVOID)ptr, n_pages, page_info);
-
- if (bResult != TRUE) {
- ut_print_timestamp(stderr);
- fprintf(stderr,
- " InnoDB: AWE: Mapping of %lu physical pages"
- " to address %lx failed,\n"
- "InnoDB: error %lu.\n"
- "InnoDB: Cannot continue operation.\n",
- n_mem_pages, (ulint)ptr, (ulint)GetLastError());
- exit(1);
- }
-
- return(TRUE);
-#else
- UT_NOT_USED(ptr);
- UT_NOT_USED(n_mem_pages);
- UT_NOT_USED(page_info);
-
- return(FALSE);
-#endif
-}
-
-/********************************************************************
-Converts the current process id to a number. It is not guaranteed that the
-number is unique. In Linux returns the 'process number' of the current
-thread. That number is the same as one sees in 'top', for example. In Linux
-the thread id is not the same as one sees in 'top'. */
-
-ulint
-os_proc_get_number(void)
-/*====================*/
-{
-#ifdef __WIN__
- return((ulint)GetCurrentProcessId());
-#else
- return((ulint)getpid());
-#endif
-}
-
-/********************************************************************
-Allocates non-cacheable memory. */
-
-void*
-os_mem_alloc_nocache(
-/*=================*/
- /* out: allocated memory */
- ulint n) /* in: number of bytes */
-{
-#ifdef __WIN__
- void* ptr;
-
- ptr = VirtualAlloc(NULL, n, MEM_COMMIT,
- PAGE_READWRITE | PAGE_NOCACHE);
- ut_a(ptr);
-
- return(ptr);
-#else
- return(ut_malloc(n));
-#endif
-}
-
-/********************************************************************
-Allocates large pages memory. */
-
-void*
-os_mem_alloc_large(
-/*===============*/
- /* out: allocated memory */
- ulint n, /* in: number of bytes */
- ibool set_to_zero, /* in: TRUE if allocated memory
- should be set to zero if
- UNIV_SET_MEM_TO_ZERO is defined */
- ibool assert_on_error)/* in: if TRUE, we crash mysqld if
- the memory cannot be allocated */
-{
-#ifdef HAVE_LARGE_PAGES
- ulint size;
- int shmid;
- void *ptr = NULL;
- struct shmid_ds buf;
-
- if (!os_use_large_pages || !os_large_page_size) {
- goto skip;
- }
-
-#ifdef UNIV_LINUX
- /* Align block size to os_large_page_size */
- size = ((n - 1) & ~(os_large_page_size - 1)) + os_large_page_size;
-
- shmid = shmget(IPC_PRIVATE, (size_t)size, SHM_HUGETLB | SHM_R | SHM_W);
- if (shmid < 0) {
- fprintf(stderr, "InnoDB: HugeTLB: Warning: Failed to allocate"
- " %lu bytes. errno %d\n", n, errno);
- } else {
- ptr = shmat(shmid, NULL, 0);
- if (ptr == (void *)-1) {
- fprintf(stderr, "InnoDB: HugeTLB: Warning: Failed to"
- " attach shared memory segment, errno %d\n",
- errno);
- }
-
- /* Remove the shared memory segment so that it will be
- automatically freed after memory is detached or
- process exits */
- shmctl(shmid, IPC_RMID, &buf);
- }
-#endif
-
- if (ptr) {
- if (set_to_zero) {
-#ifdef UNIV_SET_MEM_TO_ZERO
- memset(ptr, '\0', size);
-#endif
- }
-
- return(ptr);
- }
-
- fprintf(stderr, "InnoDB HugeTLB: Warning: Using conventional"
- " memory pool\n");
-skip:
-#endif /* HAVE_LARGE_PAGES */
-
- return(ut_malloc_low(n, set_to_zero, assert_on_error));
-}
-
-/********************************************************************
-Frees large pages memory. */
-
-void
-os_mem_free_large(
-/*==============*/
- void *ptr) /* in: number of bytes */
-{
-#ifdef HAVE_LARGE_PAGES
- if (os_use_large_pages && os_large_page_size
-#ifdef UNIV_LINUX
- && !shmdt(ptr)
-#endif
- ) {
- return;
- }
-#endif
-
- ut_free(ptr);
-}
-
-/********************************************************************
-Sets the priority boost for threads released from waiting within the current
-process. */
-
-void
-os_process_set_priority_boost(
-/*==========================*/
- ibool do_boost) /* in: TRUE if priority boost should be done,
- FALSE if not */
-{
-#ifdef __WIN__
- ibool no_boost;
-
- if (do_boost) {
- no_boost = FALSE;
- } else {
- no_boost = TRUE;
- }
-
-#if TRUE != 1
-# error "TRUE != 1"
-#endif
-
- /* Does not do anything currently!
- SetProcessPriorityBoost(GetCurrentProcess(), no_boost);
- */
- fputs("Warning: process priority boost setting"
- " currently not functional!\n",
- stderr);
-#else
- UT_NOT_USED(do_boost);
-#endif
-}
diff --git a/storage/innobase/page/page0cur.c b/storage/innobase/page/page0cur.c
deleted file mode 100644
index 70b7de194fd..00000000000
--- a/storage/innobase/page/page0cur.c
+++ /dev/null
@@ -1,1510 +0,0 @@
-/************************************************************************
-The page cursor
-
-(c) 1994-1996 Innobase Oy
-
-Created 10/4/1994 Heikki Tuuri
-*************************************************************************/
-
-#include "page0cur.h"
-#ifdef UNIV_NONINL
-#include "page0cur.ic"
-#endif
-
-#include "rem0cmp.h"
-#include "mtr0log.h"
-#include "log0recv.h"
-#include "rem0cmp.h"
-#include "srv0srv.h"
-#include "ut0ut.h"
-
-static ulint page_rnd = 976722341;
-
-#ifdef PAGE_CUR_ADAPT
-# ifdef UNIV_SEARCH_PERF_STAT
-ulint page_cur_short_succ = 0;
-# endif /* UNIV_SEARCH_PERF_STAT */
-
-/***********************************************************************
-This is a linear congruential generator PRNG. Returns a pseudo random
-number between 0 and 2^64-1 inclusive. The formula and the constants
-being used are:
-X[n+1] = (a * X[n] + c) mod m
-where:
-X[0] = ut_usectime()
-a = 1103515245 (3^5 * 5 * 7 * 129749)
-c = 12345 (3 * 5 * 823)
-m = 18446744073709551616 (2^64)
-*/
-#define LCG_a 1103515245
-#define LCG_c 12345
-static
-unsigned long long
-page_cur_lcg_prng()
-/*===============*/
- /* out: number between 0 and 2^64-1 */
-{
- static unsigned long long lcg_current = 0;
- static ibool initialized = FALSE;
- ulint time_sec;
- ulint time_ms;
-
- if (!initialized) {
- ut_usectime(&time_sec, &time_ms);
- lcg_current = (unsigned long long) (time_sec * 1000000
- + time_ms);
- initialized = TRUE;
- }
-
- /* no need to "% 2^64" explicitly because lcg_current is
- 64 bit and this will be done anyway */
- lcg_current = LCG_a * lcg_current + LCG_c;
-
- return(lcg_current);
-}
-
-/********************************************************************
-Tries a search shortcut based on the last insert. */
-UNIV_INLINE
-ibool
-page_cur_try_search_shortcut(
-/*=========================*/
- /* out: TRUE on success */
- page_t* page, /* in: index page */
- dict_index_t* index, /* in: record descriptor */
- dtuple_t* tuple, /* in: data tuple */
- ulint* iup_matched_fields,
- /* in/out: already matched fields in upper
- limit record */
- ulint* iup_matched_bytes,
- /* in/out: already matched bytes in a field
- not yet completely matched */
- ulint* ilow_matched_fields,
- /* in/out: already matched fields in lower
- limit record */
- ulint* ilow_matched_bytes,
- /* in/out: already matched bytes in a field
- not yet completely matched */
- page_cur_t* cursor) /* out: page cursor */
-{
- rec_t* rec;
- rec_t* next_rec;
- ulint low_match;
- ulint low_bytes;
- ulint up_match;
- ulint up_bytes;
-#ifdef UNIV_SEARCH_DEBUG
- page_cur_t cursor2;
-#endif
- ibool success = FALSE;
- mem_heap_t* heap = NULL;
- ulint offsets_[REC_OFFS_NORMAL_SIZE];
- ulint* offsets = offsets_;
- *offsets_ = (sizeof offsets_) / sizeof *offsets_;
-
- ut_ad(dtuple_check_typed(tuple));
-
- rec = page_header_get_ptr(page, PAGE_LAST_INSERT);
- offsets = rec_get_offsets(rec, index, offsets,
- dtuple_get_n_fields(tuple), &heap);
-
- ut_ad(rec);
- ut_ad(page_rec_is_user_rec(rec));
-
- ut_pair_min(&low_match, &low_bytes,
- *ilow_matched_fields, *ilow_matched_bytes,
- *iup_matched_fields, *iup_matched_bytes);
-
- up_match = low_match;
- up_bytes = low_bytes;
-
- if (page_cmp_dtuple_rec_with_match(tuple, rec, offsets,
- &low_match, &low_bytes) < 0) {
- goto exit_func;
- }
-
- next_rec = page_rec_get_next(rec);
- offsets = rec_get_offsets(next_rec, index, offsets,
- dtuple_get_n_fields(tuple), &heap);
-
- if (page_cmp_dtuple_rec_with_match(tuple, next_rec, offsets,
- &up_match, &up_bytes) >= 0) {
- goto exit_func;
- }
-
- cursor->rec = rec;
-
-#ifdef UNIV_SEARCH_DEBUG
- page_cur_search_with_match(page, index, tuple, PAGE_CUR_DBG,
- iup_matched_fields,
- iup_matched_bytes,
- ilow_matched_fields,
- ilow_matched_bytes,
- &cursor2);
- ut_a(cursor2.rec == cursor->rec);
-
- if (next_rec != page_get_supremum_rec(page)) {
-
- ut_a(*iup_matched_fields == up_match);
- ut_a(*iup_matched_bytes == up_bytes);
- }
-
- ut_a(*ilow_matched_fields == low_match);
- ut_a(*ilow_matched_bytes == low_bytes);
-#endif
- if (!page_rec_is_supremum(next_rec)) {
-
- *iup_matched_fields = up_match;
- *iup_matched_bytes = up_bytes;
- }
-
- *ilow_matched_fields = low_match;
- *ilow_matched_bytes = low_bytes;
-
-#ifdef UNIV_SEARCH_PERF_STAT
- page_cur_short_succ++;
-#endif
- success = TRUE;
-exit_func:
- if (UNIV_LIKELY_NULL(heap)) {
- mem_heap_free(heap);
- }
- return(success);
-}
-
-#endif
-
-#ifdef PAGE_CUR_LE_OR_EXTENDS
-/********************************************************************
-Checks if the nth field in a record is a character type field which extends
-the nth field in tuple, i.e., the field is longer or equal in length and has
-common first characters. */
-static
-ibool
-page_cur_rec_field_extends(
-/*=======================*/
- /* out: TRUE if rec field
- extends tuple field */
- dtuple_t* tuple, /* in: data tuple */
- rec_t* rec, /* in: record */
- const ulint* offsets,/* in: array returned by rec_get_offsets() */
- ulint n) /* in: compare nth field */
-{
- dtype_t* type;
- dfield_t* dfield;
- byte* rec_f;
- ulint rec_f_len;
-
- ut_ad(rec_offs_validate(rec, NULL, offsets));
- dfield = dtuple_get_nth_field(tuple, n);
-
- type = dfield_get_type(dfield);
-
- rec_f = rec_get_nth_field(rec, offsets, n, &rec_f_len);
-
- if (type->mtype == DATA_VARCHAR
- || type->mtype == DATA_CHAR
- || type->mtype == DATA_FIXBINARY
- || type->mtype == DATA_BINARY
- || type->mtype == DATA_BLOB
- || type->mtype == DATA_VARMYSQL
- || type->mtype == DATA_MYSQL) {
-
- if (dfield_get_len(dfield) != UNIV_SQL_NULL
- && rec_f_len != UNIV_SQL_NULL
- && rec_f_len >= dfield_get_len(dfield)
- && !cmp_data_data_slow(type,
- dfield_get_data(dfield),
- dfield_get_len(dfield),
- rec_f, dfield_get_len(dfield))) {
-
- return(TRUE);
- }
- }
-
- return(FALSE);
-}
-#endif /* PAGE_CUR_LE_OR_EXTENDS */
-
-/********************************************************************
-Searches the right position for a page cursor. */
-
-void
-page_cur_search_with_match(
-/*=======================*/
- page_t* page, /* in: index page */
- dict_index_t* index, /* in: record descriptor */
- dtuple_t* tuple, /* in: data tuple */
- ulint mode, /* in: PAGE_CUR_L, PAGE_CUR_LE, PAGE_CUR_G,
- or PAGE_CUR_GE */
- ulint* iup_matched_fields,
- /* in/out: already matched fields in upper
- limit record */
- ulint* iup_matched_bytes,
- /* in/out: already matched bytes in a field
- not yet completely matched */
- ulint* ilow_matched_fields,
- /* in/out: already matched fields in lower
- limit record */
- ulint* ilow_matched_bytes,
- /* in/out: already matched bytes in a field
- not yet completely matched */
- page_cur_t* cursor) /* out: page cursor */
-{
- ulint up;
- ulint low;
- ulint mid;
- page_dir_slot_t* slot;
- rec_t* up_rec;
- rec_t* low_rec;
- rec_t* mid_rec;
- ulint up_matched_fields;
- ulint up_matched_bytes;
- ulint low_matched_fields;
- ulint low_matched_bytes;
- ulint cur_matched_fields;
- ulint cur_matched_bytes;
- int cmp;
-#ifdef UNIV_SEARCH_DEBUG
- int dbg_cmp;
- ulint dbg_matched_fields;
- ulint dbg_matched_bytes;
-#endif
- mem_heap_t* heap = NULL;
- ulint offsets_[REC_OFFS_NORMAL_SIZE];
- ulint* offsets = offsets_;
- *offsets_ = (sizeof offsets_) / sizeof *offsets_;
-
- ut_ad(page && tuple && iup_matched_fields && iup_matched_bytes
- && ilow_matched_fields && ilow_matched_bytes && cursor);
- ut_ad(dtuple_validate(tuple));
- ut_ad(dtuple_check_typed(tuple));
-#ifdef UNIV_DEBUG
-# ifdef PAGE_CUR_DBG
- if (mode != PAGE_CUR_DBG)
-# endif /* PAGE_CUR_DBG */
-# ifdef PAGE_CUR_LE_OR_EXTENDS
- if (mode != PAGE_CUR_LE_OR_EXTENDS)
-# endif /* PAGE_CUR_LE_OR_EXTENDS */
- ut_ad(mode == PAGE_CUR_L || mode == PAGE_CUR_LE
- || mode == PAGE_CUR_G || mode == PAGE_CUR_GE);
-#endif /* UNIV_DEBUG */
-
- page_check_dir(page);
-
-#ifdef PAGE_CUR_ADAPT
- if ((page_header_get_field(page, PAGE_LEVEL) == 0)
- && (mode == PAGE_CUR_LE)
- && (page_header_get_field(page, PAGE_N_DIRECTION) > 3)
- && (page_header_get_ptr(page, PAGE_LAST_INSERT))
- && (page_header_get_field(page, PAGE_DIRECTION) == PAGE_RIGHT)) {
-
- if (page_cur_try_search_shortcut(
- page, index, tuple,
- iup_matched_fields, iup_matched_bytes,
- ilow_matched_fields, ilow_matched_bytes,
- cursor)) {
- return;
- }
- }
-# ifdef PAGE_CUR_DBG
- if (mode == PAGE_CUR_DBG) {
- mode = PAGE_CUR_LE;
- }
-# endif
-#endif
-
- /* The following flag does not work for non-latin1 char sets because
- cmp_full_field does not tell how many bytes matched */
-#ifdef PAGE_CUR_LE_OR_EXTENDS
- ut_a(mode != PAGE_CUR_LE_OR_EXTENDS);
-#endif /* PAGE_CUR_LE_OR_EXTENDS */
-
- /* If mode PAGE_CUR_G is specified, we are trying to position the
- cursor to answer a query of the form "tuple < X", where tuple is
- the input parameter, and X denotes an arbitrary physical record on
- the page. We want to position the cursor on the first X which
- satisfies the condition. */
-
- up_matched_fields = *iup_matched_fields;
- up_matched_bytes = *iup_matched_bytes;
- low_matched_fields = *ilow_matched_fields;
- low_matched_bytes = *ilow_matched_bytes;
-
- /* Perform binary search. First the search is done through the page
- directory, after that as a linear search in the list of records
- owned by the upper limit directory slot. */
-
- low = 0;
- up = page_dir_get_n_slots(page) - 1;
-
- /* Perform binary search until the lower and upper limit directory
- slots come to the distance 1 of each other */
-
- while (up - low > 1) {
- mid = (low + up) / 2;
- slot = page_dir_get_nth_slot(page, mid);
- mid_rec = page_dir_slot_get_rec(slot);
-
- ut_pair_min(&cur_matched_fields, &cur_matched_bytes,
- low_matched_fields, low_matched_bytes,
- up_matched_fields, up_matched_bytes);
-
- offsets = rec_get_offsets(mid_rec, index, offsets,
- dtuple_get_n_fields_cmp(tuple),
- &heap);
-
- cmp = cmp_dtuple_rec_with_match(tuple, mid_rec, offsets,
- &cur_matched_fields,
- &cur_matched_bytes);
- if (UNIV_LIKELY(cmp > 0)) {
-low_slot_match:
- low = mid;
- low_matched_fields = cur_matched_fields;
- low_matched_bytes = cur_matched_bytes;
-
- } else if (UNIV_EXPECT(cmp, -1)) {
-#ifdef PAGE_CUR_LE_OR_EXTENDS
- if (mode == PAGE_CUR_LE_OR_EXTENDS
- && page_cur_rec_field_extends(
- tuple, mid_rec, offsets,
- cur_matched_fields)) {
-
- goto low_slot_match;
- }
-#endif /* PAGE_CUR_LE_OR_EXTENDS */
-up_slot_match:
- up = mid;
- up_matched_fields = cur_matched_fields;
- up_matched_bytes = cur_matched_bytes;
-
- } else if (mode == PAGE_CUR_G || mode == PAGE_CUR_LE
-#ifdef PAGE_CUR_LE_OR_EXTENDS
- || mode == PAGE_CUR_LE_OR_EXTENDS
-#endif /* PAGE_CUR_LE_OR_EXTENDS */
- ) {
-
- goto low_slot_match;
- } else {
-
- goto up_slot_match;
- }
- }
-
- slot = page_dir_get_nth_slot(page, low);
- low_rec = page_dir_slot_get_rec(slot);
- slot = page_dir_get_nth_slot(page, up);
- up_rec = page_dir_slot_get_rec(slot);
-
- /* Perform linear search until the upper and lower records come to
- distance 1 of each other. */
-
- while (page_rec_get_next(low_rec) != up_rec) {
-
- mid_rec = page_rec_get_next(low_rec);
-
- ut_pair_min(&cur_matched_fields, &cur_matched_bytes,
- low_matched_fields, low_matched_bytes,
- up_matched_fields, up_matched_bytes);
-
- offsets = rec_get_offsets(mid_rec, index, offsets,
- dtuple_get_n_fields_cmp(tuple),
- &heap);
-
- cmp = cmp_dtuple_rec_with_match(tuple, mid_rec, offsets,
- &cur_matched_fields,
- &cur_matched_bytes);
- if (UNIV_LIKELY(cmp > 0)) {
-low_rec_match:
- low_rec = mid_rec;
- low_matched_fields = cur_matched_fields;
- low_matched_bytes = cur_matched_bytes;
-
- } else if (UNIV_EXPECT(cmp, -1)) {
-#ifdef PAGE_CUR_LE_OR_EXTENDS
- if (mode == PAGE_CUR_LE_OR_EXTENDS
- && page_cur_rec_field_extends(
- tuple, mid_rec, offsets,
- cur_matched_fields)) {
-
- goto low_rec_match;
- }
-#endif /* PAGE_CUR_LE_OR_EXTENDS */
-up_rec_match:
- up_rec = mid_rec;
- up_matched_fields = cur_matched_fields;
- up_matched_bytes = cur_matched_bytes;
- } else if (mode == PAGE_CUR_G || mode == PAGE_CUR_LE
-#ifdef PAGE_CUR_LE_OR_EXTENDS
- || mode == PAGE_CUR_LE_OR_EXTENDS
-#endif /* PAGE_CUR_LE_OR_EXTENDS */
- ) {
-
- goto low_rec_match;
- } else {
-
- goto up_rec_match;
- }
- }
-
-#ifdef UNIV_SEARCH_DEBUG
-
- /* Check that the lower and upper limit records have the
- right alphabetical order compared to tuple. */
- dbg_matched_fields = 0;
- dbg_matched_bytes = 0;
-
- offsets = rec_get_offsets(low_rec, index, offsets,
- ULINT_UNDEFINED, &heap);
- dbg_cmp = page_cmp_dtuple_rec_with_match(tuple, low_rec, offsets,
- &dbg_matched_fields,
- &dbg_matched_bytes);
- if (mode == PAGE_CUR_G) {
- ut_a(dbg_cmp >= 0);
- } else if (mode == PAGE_CUR_GE) {
- ut_a(dbg_cmp == 1);
- } else if (mode == PAGE_CUR_L) {
- ut_a(dbg_cmp == 1);
- } else if (mode == PAGE_CUR_LE) {
- ut_a(dbg_cmp >= 0);
- }
-
- if (low_rec != page_get_infimum_rec(page)) {
-
- ut_a(low_matched_fields == dbg_matched_fields);
- ut_a(low_matched_bytes == dbg_matched_bytes);
- }
-
- dbg_matched_fields = 0;
- dbg_matched_bytes = 0;
-
- offsets = rec_get_offsets(up_rec, index, offsets,
- ULINT_UNDEFINED, &heap);
- dbg_cmp = page_cmp_dtuple_rec_with_match(tuple, up_rec, offsets,
- &dbg_matched_fields,
- &dbg_matched_bytes);
- if (mode == PAGE_CUR_G) {
- ut_a(dbg_cmp == -1);
- } else if (mode == PAGE_CUR_GE) {
- ut_a(dbg_cmp <= 0);
- } else if (mode == PAGE_CUR_L) {
- ut_a(dbg_cmp <= 0);
- } else if (mode == PAGE_CUR_LE) {
- ut_a(dbg_cmp == -1);
- }
-
- if (up_rec != page_get_supremum_rec(page)) {
-
- ut_a(up_matched_fields == dbg_matched_fields);
- ut_a(up_matched_bytes == dbg_matched_bytes);
- }
-#endif
- if (mode <= PAGE_CUR_GE) {
- cursor->rec = up_rec;
- } else {
- cursor->rec = low_rec;
- }
-
- *iup_matched_fields = up_matched_fields;
- *iup_matched_bytes = up_matched_bytes;
- *ilow_matched_fields = low_matched_fields;
- *ilow_matched_bytes = low_matched_bytes;
- if (UNIV_LIKELY_NULL(heap)) {
- mem_heap_free(heap);
- }
-}
-
-/***************************************************************
-Positions a page cursor on a randomly chosen user record on a page. If there
-are no user records, sets the cursor on the infimum record. */
-
-void
-page_cur_open_on_rnd_user_rec(
-/*==========================*/
- page_t* page, /* in: page */
- page_cur_t* cursor) /* in/out: page cursor */
-{
- ulint rnd;
- rec_t* rec;
-
- if (page_get_n_recs(page) == 0) {
- page_cur_position(page_get_infimum_rec(page), cursor);
-
- return;
- }
-
- if (srv_use_legacy_cardinality_algorithm) {
- page_rnd += 87584577;
-
- rnd = page_rnd % page_get_n_recs(page);
- } else {
- rnd = (ulint) page_cur_lcg_prng() % page_get_n_recs(page);
- }
-
- rec = page_get_infimum_rec(page);
-
- rec = page_rec_get_next(rec);
-
- while (rnd > 0) {
- rec = page_rec_get_next(rec);
-
- rnd--;
- }
-
- page_cur_position(rec, cursor);
-}
-
-/***************************************************************
-Writes the log record of a record insert on a page. */
-static
-void
-page_cur_insert_rec_write_log(
-/*==========================*/
- rec_t* insert_rec, /* in: inserted physical record */
- ulint rec_size, /* in: insert_rec size */
- rec_t* cursor_rec, /* in: record the
- cursor is pointing to */
- dict_index_t* index, /* in: record descriptor */
- mtr_t* mtr) /* in: mini-transaction handle */
-{
- ulint cur_rec_size;
- ulint extra_size;
- ulint cur_extra_size;
- ulint min_rec_size;
- byte* ins_ptr;
- byte* cur_ptr;
- ulint extra_info_yes;
- byte* log_ptr;
- byte* log_end;
- ulint i;
- ulint comp;
-
- ut_a(rec_size < UNIV_PAGE_SIZE);
- ut_ad(buf_frame_align(insert_rec) == buf_frame_align(cursor_rec));
- ut_ad(!page_rec_is_comp(insert_rec)
- == !dict_table_is_comp(index->table));
- comp = page_rec_is_comp(insert_rec);
-
- {
- mem_heap_t* heap = NULL;
- ulint cur_offs_[REC_OFFS_NORMAL_SIZE];
- ulint ins_offs_[REC_OFFS_NORMAL_SIZE];
-
- ulint* cur_offs;
- ulint* ins_offs;
-
- *cur_offs_ = (sizeof cur_offs_) / sizeof *cur_offs_;
- *ins_offs_ = (sizeof ins_offs_) / sizeof *ins_offs_;
-
- cur_offs = rec_get_offsets(cursor_rec, index, cur_offs_,
- ULINT_UNDEFINED, &heap);
- ins_offs = rec_get_offsets(insert_rec, index, ins_offs_,
- ULINT_UNDEFINED, &heap);
-
- extra_size = rec_offs_extra_size(ins_offs);
- cur_extra_size = rec_offs_extra_size(cur_offs);
- ut_ad(rec_size == rec_offs_size(ins_offs));
- cur_rec_size = rec_offs_size(cur_offs);
-
- if (UNIV_LIKELY_NULL(heap)) {
- mem_heap_free(heap);
- }
- }
-
- ins_ptr = insert_rec - extra_size;
-
- i = 0;
-
- if (cur_extra_size == extra_size) {
- min_rec_size = ut_min(cur_rec_size, rec_size);
-
- cur_ptr = cursor_rec - cur_extra_size;
-
- /* Find out the first byte in insert_rec which differs from
- cursor_rec; skip the bytes in the record info */
-
- for (;;) {
- if (i >= min_rec_size) {
-
- break;
- } else if (*ins_ptr == *cur_ptr) {
- i++;
- ins_ptr++;
- cur_ptr++;
- } else if ((i < extra_size)
- && (i >= extra_size
- - (comp
- ? REC_N_NEW_EXTRA_BYTES
- : REC_N_OLD_EXTRA_BYTES))) {
- i = extra_size;
- ins_ptr = insert_rec;
- cur_ptr = cursor_rec;
- } else {
- break;
- }
- }
- }
-
- if (mtr_get_log_mode(mtr) != MTR_LOG_SHORT_INSERTS) {
-
- log_ptr = mlog_open_and_write_index(mtr, insert_rec, index,
- comp
- ? MLOG_COMP_REC_INSERT
- : MLOG_REC_INSERT,
- 2 + 5 + 1 + 5 + 5
- + MLOG_BUF_MARGIN);
-
- if (!log_ptr) {
- /* Logging in mtr is switched off during crash
- recovery: in that case mlog_open returns NULL */
- return;
- }
-
- log_end = &log_ptr[2 + 5 + 1 + 5 + 5 + MLOG_BUF_MARGIN];
- /* Write the cursor rec offset as a 2-byte ulint */
- mach_write_to_2(log_ptr, cursor_rec
- - buf_frame_align(cursor_rec));
- log_ptr += 2;
- } else {
- log_ptr = mlog_open(mtr, 5 + 1 + 5 + 5 + MLOG_BUF_MARGIN);
- if (!log_ptr) {
- /* Logging in mtr is switched off during crash
- recovery: in that case mlog_open returns NULL */
- return;
- }
- log_end = &log_ptr[5 + 1 + 5 + 5 + MLOG_BUF_MARGIN];
- }
-
- if ((rec_get_info_and_status_bits(insert_rec, comp)
- != rec_get_info_and_status_bits(cursor_rec, comp))
- || (extra_size != cur_extra_size)
- || (rec_size != cur_rec_size)) {
-
- extra_info_yes = 1;
- } else {
- extra_info_yes = 0;
- }
-
- /* Write the record end segment length and the extra info storage
- flag */
- log_ptr += mach_write_compressed(log_ptr, 2 * (rec_size - i)
- + extra_info_yes);
- if (extra_info_yes) {
- /* Write the info bits */
- mach_write_to_1(log_ptr,
- rec_get_info_and_status_bits(insert_rec,
- comp));
- log_ptr++;
-
- /* Write the record origin offset */
- log_ptr += mach_write_compressed(log_ptr, extra_size);
-
- /* Write the mismatch index */
- log_ptr += mach_write_compressed(log_ptr, i);
-
- ut_a(i < UNIV_PAGE_SIZE);
- ut_a(extra_size < UNIV_PAGE_SIZE);
- }
-
- /* Write to the log the inserted index record end segment which
- differs from the cursor record */
-
- rec_size -= i;
-
- if (log_ptr + rec_size <= log_end) {
- memcpy(log_ptr, ins_ptr, rec_size);
- mlog_close(mtr, log_ptr + rec_size);
- } else {
- mlog_close(mtr, log_ptr);
- ut_a(rec_size < UNIV_PAGE_SIZE);
- mlog_catenate_string(mtr, ins_ptr, rec_size);
- }
-}
-
-/***************************************************************
-Parses a log record of a record insert on a page. */
-
-byte*
-page_cur_parse_insert_rec(
-/*======================*/
- /* out: end of log record or NULL */
- ibool is_short,/* in: TRUE if short inserts */
- byte* ptr, /* in: buffer */
- byte* end_ptr,/* in: buffer end */
- dict_index_t* index, /* in: record descriptor */
- page_t* page, /* in: page or NULL */
- mtr_t* mtr) /* in: mtr or NULL */
-{
- ulint extra_info_yes;
- ulint offset = 0; /* remove warning */
- ulint origin_offset;
- ulint end_seg_len;
- ulint mismatch_index;
- rec_t* cursor_rec;
- byte buf1[1024];
- byte* buf;
- byte* ptr2 = ptr;
- ulint info_and_status_bits = 0; /* remove warning */
- page_cur_t cursor;
- mem_heap_t* heap = NULL;
- ulint offsets_[REC_OFFS_NORMAL_SIZE];
- ulint* offsets = offsets_;
- *offsets_ = (sizeof offsets_) / sizeof *offsets_;
-
- if (!is_short) {
- /* Read the cursor rec offset as a 2-byte ulint */
-
- if (end_ptr < ptr + 2) {
-
- return(NULL);
- }
-
- offset = mach_read_from_2(ptr);
-
- if (offset >= UNIV_PAGE_SIZE) {
-
- recv_sys->found_corrupt_log = TRUE;
-
- return(NULL);
- }
-
- ptr += 2;
- }
-
- ptr = mach_parse_compressed(ptr, end_ptr, &end_seg_len);
-
- if (ptr == NULL) {
-
- return(NULL);
- }
-
- extra_info_yes = end_seg_len & 0x1UL;
- end_seg_len >>= 1;
-
- if (end_seg_len >= UNIV_PAGE_SIZE) {
- recv_sys->found_corrupt_log = TRUE;
-
- return(NULL);
- }
-
- if (extra_info_yes) {
- /* Read the info bits */
-
- if (end_ptr < ptr + 1) {
-
- return(NULL);
- }
-
- info_and_status_bits = mach_read_from_1(ptr);
- ptr++;
-
- ptr = mach_parse_compressed(ptr, end_ptr, &origin_offset);
-
- if (ptr == NULL) {
-
- return(NULL);
- }
-
- ut_a(origin_offset < UNIV_PAGE_SIZE);
-
- ptr = mach_parse_compressed(ptr, end_ptr, &mismatch_index);
-
- if (ptr == NULL) {
-
- return(NULL);
- }
-
- ut_a(mismatch_index < UNIV_PAGE_SIZE);
- }
-
- if (end_ptr < ptr + end_seg_len) {
-
- return(NULL);
- }
-
- if (page == NULL) {
-
- return(ptr + end_seg_len);
- }
-
- ut_ad(!!page_is_comp(page) == dict_table_is_comp(index->table));
-
- /* Read from the log the inserted index record end segment which
- differs from the cursor record */
-
- if (is_short) {
- cursor_rec = page_rec_get_prev(page_get_supremum_rec(page));
- } else {
- cursor_rec = page + offset;
- }
-
- offsets = rec_get_offsets(cursor_rec, index, offsets,
- ULINT_UNDEFINED, &heap);
-
- if (extra_info_yes == 0) {
- info_and_status_bits = rec_get_info_and_status_bits(
- cursor_rec, page_is_comp(page));
- origin_offset = rec_offs_extra_size(offsets);
- mismatch_index = rec_offs_size(offsets) - end_seg_len;
- }
-
- if (mismatch_index + end_seg_len < sizeof buf1) {
- buf = buf1;
- } else {
- buf = mem_alloc(mismatch_index + end_seg_len);
- }
-
- /* Build the inserted record to buf */
-
- if (mismatch_index >= UNIV_PAGE_SIZE) {
- fprintf(stderr,
- "Is short %lu, info_and_status_bits %lu, offset %lu, "
- "o_offset %lu\n"
- "mismatch index %lu, end_seg_len %lu\n"
- "parsed len %lu\n",
- (ulong) is_short, (ulong) info_and_status_bits,
- (ulong) offset,
- (ulong) origin_offset,
- (ulong) mismatch_index, (ulong) end_seg_len,
- (ulong) (ptr - ptr2));
-
- fputs("Dump of 300 bytes of log:\n", stderr);
- ut_print_buf(stderr, ptr2, 300);
-
- buf_page_print(page);
-
- ut_error;
- }
-
- ut_memcpy(buf, rec_get_start(cursor_rec, offsets), mismatch_index);
- ut_memcpy(buf + mismatch_index, ptr, end_seg_len);
-
- rec_set_info_and_status_bits(buf + origin_offset, page_is_comp(page),
- info_and_status_bits);
-
- page_cur_position(cursor_rec, &cursor);
-
- offsets = rec_get_offsets(buf + origin_offset, index, offsets,
- ULINT_UNDEFINED, &heap);
- page_cur_rec_insert(&cursor, buf + origin_offset, index, offsets, mtr);
-
- if (buf != buf1) {
-
- mem_free(buf);
- }
-
- if (UNIV_LIKELY_NULL(heap)) {
- mem_heap_free(heap);
- }
-
- return(ptr + end_seg_len);
-}
-
-/***************************************************************
-Inserts a record next to page cursor. Returns pointer to inserted record if
-succeed, i.e., enough space available, NULL otherwise. The record to be
-inserted can be in a data tuple or as a physical record. The other parameter
-must then be NULL. The cursor stays at the same position. */
-
-rec_t*
-page_cur_insert_rec_low(
-/*====================*/
- /* out: pointer to record if succeed, NULL
- otherwise */
- page_cur_t* cursor, /* in: a page cursor */
- dtuple_t* tuple, /* in: pointer to a data tuple or NULL */
- dict_index_t* index, /* in: record descriptor */
- rec_t* rec, /* in: pointer to a physical record or NULL */
- ulint* offsets,/* in: rec_get_offsets(rec, index) or NULL */
- mtr_t* mtr) /* in: mini-transaction handle */
-{
- byte* insert_buf = NULL;
- ulint rec_size;
- byte* page; /* the relevant page */
- rec_t* last_insert; /* cursor position at previous
- insert */
- rec_t* insert_rec; /* inserted record */
- ulint heap_no; /* heap number of the inserted
- record */
- rec_t* current_rec; /* current record after which the
- new record is inserted */
- rec_t* next_rec; /* next record after current before
- the insertion */
- ulint owner_slot; /* the slot which owns the
- inserted record */
- rec_t* owner_rec;
- ulint n_owned;
- mem_heap_t* heap = NULL;
- ulint comp;
-
- ut_ad(cursor && mtr);
- ut_ad(tuple || rec);
- ut_ad(!(tuple && rec));
- ut_ad(rec || dtuple_check_typed(tuple));
-
- page = page_cur_get_page(cursor);
- comp = page_is_comp(page);
- ut_ad(dict_table_is_comp(index->table) == !!comp);
-
- ut_ad(cursor->rec != page_get_supremum_rec(page));
-
- /* 1. Get the size of the physical record in the page */
- if (tuple != NULL) {
- rec_size = rec_get_converted_size(index, tuple);
- } else {
- if (!offsets) {
- offsets = rec_get_offsets(rec, index, offsets,
- ULINT_UNDEFINED, &heap);
- }
- ut_ad(rec_offs_validate(rec, index, offsets));
- rec_size = rec_offs_size(offsets);
- }
-
- /* 2. Try to find suitable space from page memory management */
- insert_buf = page_mem_alloc(page, rec_size, index, &heap_no);
-
- if (insert_buf == NULL) {
- if (UNIV_LIKELY_NULL(heap)) {
- mem_heap_free(heap);
- }
- return(NULL);
- }
-
- /* 3. Create the record */
- if (tuple != NULL) {
- insert_rec = rec_convert_dtuple_to_rec(insert_buf,
- index, tuple);
- offsets = rec_get_offsets(insert_rec, index, offsets,
- ULINT_UNDEFINED, &heap);
- } else {
- insert_rec = rec_copy(insert_buf, rec, offsets);
- ut_ad(rec_offs_validate(rec, index, offsets));
- rec_offs_make_valid(insert_rec, index, offsets);
- }
-
- ut_ad(insert_rec);
- ut_ad(rec_size == rec_offs_size(offsets));
-
- /* 4. Insert the record in the linked list of records */
- current_rec = cursor->rec;
-
- ut_ad(!comp || rec_get_status(current_rec) <= REC_STATUS_INFIMUM);
- ut_ad(!comp || rec_get_status(insert_rec) < REC_STATUS_INFIMUM);
-
- next_rec = page_rec_get_next(current_rec);
- ut_ad(!comp || rec_get_status(next_rec) != REC_STATUS_INFIMUM);
- page_rec_set_next(insert_rec, next_rec);
- page_rec_set_next(current_rec, insert_rec);
-
- page_header_set_field(page, PAGE_N_RECS, 1 + page_get_n_recs(page));
-
- /* 5. Set the n_owned field in the inserted record to zero,
- and set the heap_no field */
-
- rec_set_n_owned(insert_rec, comp, 0);
- rec_set_heap_no(insert_rec, comp, heap_no);
-
- /* 6. Update the last insertion info in page header */
-
- last_insert = page_header_get_ptr(page, PAGE_LAST_INSERT);
- ut_ad(!last_insert || !comp
- || rec_get_node_ptr_flag(last_insert)
- == rec_get_node_ptr_flag(insert_rec));
-
- if (last_insert == NULL) {
- page_header_set_field(page, PAGE_DIRECTION, PAGE_NO_DIRECTION);
- page_header_set_field(page, PAGE_N_DIRECTION, 0);
-
- } else if ((last_insert == current_rec)
- && (page_header_get_field(page, PAGE_DIRECTION)
- != PAGE_LEFT)) {
-
- page_header_set_field(page, PAGE_DIRECTION, PAGE_RIGHT);
- page_header_set_field(page, PAGE_N_DIRECTION,
- page_header_get_field(
- page, PAGE_N_DIRECTION) + 1);
-
- } else if ((page_rec_get_next(insert_rec) == last_insert)
- && (page_header_get_field(page, PAGE_DIRECTION)
- != PAGE_RIGHT)) {
-
- page_header_set_field(page, PAGE_DIRECTION, PAGE_LEFT);
- page_header_set_field(page, PAGE_N_DIRECTION,
- page_header_get_field(
- page, PAGE_N_DIRECTION) + 1);
- } else {
- page_header_set_field(page, PAGE_DIRECTION, PAGE_NO_DIRECTION);
- page_header_set_field(page, PAGE_N_DIRECTION, 0);
- }
-
- page_header_set_ptr(page, PAGE_LAST_INSERT, insert_rec);
-
- /* 7. It remains to update the owner record. */
-
- owner_rec = page_rec_find_owner_rec(insert_rec);
- n_owned = rec_get_n_owned(owner_rec, comp);
- rec_set_n_owned(owner_rec, comp, n_owned + 1);
-
- /* 8. Now we have incremented the n_owned field of the owner
- record. If the number exceeds PAGE_DIR_SLOT_MAX_N_OWNED,
- we have to split the corresponding directory slot in two. */
-
- if (n_owned == PAGE_DIR_SLOT_MAX_N_OWNED) {
- owner_slot = page_dir_find_owner_slot(owner_rec);
- page_dir_split_slot(page, owner_slot);
- }
-
- /* 9. Write log record of the insert */
- page_cur_insert_rec_write_log(insert_rec, rec_size, current_rec,
- index, mtr);
-
- if (UNIV_LIKELY_NULL(heap)) {
- mem_heap_free(heap);
- }
- return(insert_rec);
-}
-
-/**************************************************************
-Writes a log record of copying a record list end to a new created page. */
-UNIV_INLINE
-byte*
-page_copy_rec_list_to_created_page_write_log(
-/*=========================================*/
- /* out: 4-byte field where to
- write the log data length */
- page_t* page, /* in: index page */
- dict_index_t* index, /* in: record descriptor */
- mtr_t* mtr) /* in: mtr */
-{
- byte* log_ptr;
-
- ut_ad(!!page_is_comp(page) == dict_table_is_comp(index->table));
-
- log_ptr = mlog_open_and_write_index(mtr, page, index,
- page_is_comp(page)
- ? MLOG_COMP_LIST_END_COPY_CREATED
- : MLOG_LIST_END_COPY_CREATED, 4);
- ut_a(log_ptr);
- mlog_close(mtr, log_ptr + 4);
-
- return(log_ptr);
-}
-
-/**************************************************************
-Parses a log record of copying a record list end to a new created page. */
-
-byte*
-page_parse_copy_rec_list_to_created_page(
-/*=====================================*/
- /* out: end of log record or NULL */
- byte* ptr, /* in: buffer */
- byte* end_ptr,/* in: buffer end */
- dict_index_t* index, /* in: record descriptor */
- page_t* page, /* in: page or NULL */
- mtr_t* mtr) /* in: mtr or NULL */
-{
- byte* rec_end;
- ulint log_data_len;
-
- if (ptr + 4 > end_ptr) {
-
- return(NULL);
- }
-
- log_data_len = mach_read_from_4(ptr);
- ptr += 4;
-
- rec_end = ptr + log_data_len;
-
- if (rec_end > end_ptr) {
-
- return(NULL);
- }
-
- if (!page) {
-
- return(rec_end);
- }
-
- while (ptr < rec_end) {
- ptr = page_cur_parse_insert_rec(TRUE, ptr, end_ptr,
- index, page, mtr);
- }
-
- ut_a(ptr == rec_end);
-
- page_header_set_ptr(page, PAGE_LAST_INSERT, NULL);
- page_header_set_field(page, PAGE_DIRECTION, PAGE_NO_DIRECTION);
- page_header_set_field(page, PAGE_N_DIRECTION, 0);
-
- return(rec_end);
-}
-
-/*****************************************************************
-Copies records from page to a newly created page, from a given record onward,
-including that record. Infimum and supremum records are not copied. */
-
-void
-page_copy_rec_list_end_to_created_page(
-/*===================================*/
- page_t* new_page, /* in: index page to copy to */
- page_t* page, /* in: index page */
- rec_t* rec, /* in: first record to copy */
- dict_index_t* index, /* in: record descriptor */
- mtr_t* mtr) /* in: mtr */
-{
- page_dir_slot_t* slot = 0; /* remove warning */
- byte* heap_top;
- rec_t* insert_rec = 0; /* remove warning */
- rec_t* prev_rec;
- ulint count;
- ulint n_recs;
- ulint slot_index;
- ulint rec_size;
- ulint log_mode;
- byte* log_ptr;
- ulint log_data_len;
- ulint comp = page_is_comp(page);
- mem_heap_t* heap = NULL;
- ulint offsets_[REC_OFFS_NORMAL_SIZE];
- ulint* offsets = offsets_;
- *offsets_ = (sizeof offsets_) / sizeof *offsets_;
-
- ut_ad(page_dir_get_n_heap(new_page) == 2);
- ut_ad(page != new_page);
- ut_ad(comp == page_is_comp(new_page));
-
- if (rec == page_get_infimum_rec(page)) {
-
- rec = page_rec_get_next(rec);
- }
-
- if (rec == page_get_supremum_rec(page)) {
-
- return;
- }
-
-#ifdef UNIV_DEBUG
- /* To pass the debug tests we have to set these dummy values
- in the debug version */
- page_dir_set_n_slots(new_page, UNIV_PAGE_SIZE / 2);
- page_header_set_ptr(new_page, PAGE_HEAP_TOP,
- new_page + UNIV_PAGE_SIZE - 1);
-#endif
-
- log_ptr = page_copy_rec_list_to_created_page_write_log(new_page,
- index, mtr);
-
- log_data_len = dyn_array_get_data_size(&(mtr->log));
-
- /* Individual inserts are logged in a shorter form */
-
- log_mode = mtr_set_log_mode(mtr, MTR_LOG_SHORT_INSERTS);
-
- prev_rec = page_get_infimum_rec(new_page);
- if (comp) {
- heap_top = new_page + PAGE_NEW_SUPREMUM_END;
- } else {
- heap_top = new_page + PAGE_OLD_SUPREMUM_END;
- }
- count = 0;
- slot_index = 0;
- n_recs = 0;
-
- /* should be do ... until, comment by Jani */
- while (rec != page_get_supremum_rec(page)) {
- offsets = rec_get_offsets(rec, index, offsets,
- ULINT_UNDEFINED, &heap);
- insert_rec = rec_copy(heap_top, rec, offsets);
-
- rec_set_next_offs(prev_rec, comp, insert_rec - new_page);
-
- rec_set_n_owned(insert_rec, comp, 0);
- rec_set_heap_no(insert_rec, comp, 2 + n_recs);
-
- rec_size = rec_offs_size(offsets);
-
- heap_top = heap_top + rec_size;
-
- ut_ad(heap_top < new_page + UNIV_PAGE_SIZE);
-
- count++;
- n_recs++;
-
- if (count == (PAGE_DIR_SLOT_MAX_N_OWNED + 1) / 2) {
-
- slot_index++;
-
- slot = page_dir_get_nth_slot(new_page, slot_index);
-
- page_dir_slot_set_rec(slot, insert_rec);
- page_dir_slot_set_n_owned(slot, count);
-
- count = 0;
- }
-
- page_cur_insert_rec_write_log(insert_rec, rec_size, prev_rec,
- index, mtr);
- prev_rec = insert_rec;
- rec = page_rec_get_next(rec);
- }
-
- if ((slot_index > 0) && (count + 1
- + (PAGE_DIR_SLOT_MAX_N_OWNED + 1) / 2
- <= PAGE_DIR_SLOT_MAX_N_OWNED)) {
- /* We can merge the two last dir slots. This operation is
- here to make this function imitate exactly the equivalent
- task made using page_cur_insert_rec, which we use in database
- recovery to reproduce the task performed by this function.
- To be able to check the correctness of recovery, it is good
- that it imitates exactly. */
-
- count += (PAGE_DIR_SLOT_MAX_N_OWNED + 1) / 2;
-
- page_dir_slot_set_n_owned(slot, 0);
-
- slot_index--;
- }
-
- if (UNIV_LIKELY_NULL(heap)) {
- mem_heap_free(heap);
- }
-
- log_data_len = dyn_array_get_data_size(&(mtr->log)) - log_data_len;
-
- ut_a(log_data_len < 100 * UNIV_PAGE_SIZE);
-
- mach_write_to_4(log_ptr, log_data_len);
-
- rec_set_next_offs(insert_rec, comp,
- comp ? PAGE_NEW_SUPREMUM : PAGE_OLD_SUPREMUM);
-
- slot = page_dir_get_nth_slot(new_page, 1 + slot_index);
-
- page_dir_slot_set_rec(slot, page_get_supremum_rec(new_page));
- page_dir_slot_set_n_owned(slot, count + 1);
-
- page_dir_set_n_slots(new_page, 2 + slot_index);
- page_header_set_ptr(new_page, PAGE_HEAP_TOP, heap_top);
- page_dir_set_n_heap(new_page, 2 + n_recs);
- page_header_set_field(new_page, PAGE_N_RECS, n_recs);
-
- page_header_set_ptr(new_page, PAGE_LAST_INSERT, NULL);
- page_header_set_field(new_page, PAGE_DIRECTION, PAGE_NO_DIRECTION);
- page_header_set_field(new_page, PAGE_N_DIRECTION, 0);
-
- /* Restore the log mode */
-
- mtr_set_log_mode(mtr, log_mode);
-}
-
-/***************************************************************
-Writes log record of a record delete on a page. */
-UNIV_INLINE
-void
-page_cur_delete_rec_write_log(
-/*==========================*/
- rec_t* rec, /* in: record to be deleted */
- dict_index_t* index, /* in: record descriptor */
- mtr_t* mtr) /* in: mini-transaction handle */
-{
- byte* log_ptr;
-
- ut_ad(!!page_rec_is_comp(rec) == dict_table_is_comp(index->table));
-
- log_ptr = mlog_open_and_write_index(mtr, rec, index,
- page_rec_is_comp(rec)
- ? MLOG_COMP_REC_DELETE
- : MLOG_REC_DELETE, 2);
-
- if (!log_ptr) {
- /* Logging in mtr is switched off during crash recovery:
- in that case mlog_open returns NULL */
- return;
- }
-
- /* Write the cursor rec offset as a 2-byte ulint */
- mach_write_to_2(log_ptr, page_offset(rec));
-
- mlog_close(mtr, log_ptr + 2);
-}
-
-/***************************************************************
-Parses log record of a record delete on a page. */
-
-byte*
-page_cur_parse_delete_rec(
-/*======================*/
- /* out: pointer to record end or NULL */
- byte* ptr, /* in: buffer */
- byte* end_ptr,/* in: buffer end */
- dict_index_t* index, /* in: record descriptor */
- page_t* page, /* in: page or NULL */
- mtr_t* mtr) /* in: mtr or NULL */
-{
- ulint offset;
- page_cur_t cursor;
-
- if (end_ptr < ptr + 2) {
-
- return(NULL);
- }
-
- /* Read the cursor rec offset as a 2-byte ulint */
- offset = mach_read_from_2(ptr);
- ptr += 2;
-
- ut_a(offset <= UNIV_PAGE_SIZE);
-
- if (page) {
- mem_heap_t* heap = NULL;
- ulint offsets_[REC_OFFS_NORMAL_SIZE];
- rec_t* rec = page + offset;
- *offsets_ = (sizeof offsets_) / sizeof *offsets_;
-
- page_cur_position(rec, &cursor);
-
- page_cur_delete_rec(&cursor, index,
- rec_get_offsets(rec, index, offsets_,
- ULINT_UNDEFINED, &heap),
- mtr);
- if (UNIV_LIKELY_NULL(heap)) {
- mem_heap_free(heap);
- }
- }
-
- return(ptr);
-}
-
-/***************************************************************
-Deletes a record at the page cursor. The cursor is moved to the next
-record after the deleted one. */
-
-void
-page_cur_delete_rec(
-/*================*/
- page_cur_t* cursor, /* in: a page cursor */
- dict_index_t* index, /* in: record descriptor */
- const ulint* offsets,/* in: rec_get_offsets(cursor->rec, index) */
- mtr_t* mtr) /* in: mini-transaction handle */
-{
- page_dir_slot_t* cur_dir_slot;
- page_dir_slot_t* prev_slot;
- page_t* page;
- rec_t* current_rec;
- rec_t* prev_rec = NULL;
- rec_t* next_rec;
- ulint cur_slot_no;
- ulint cur_n_owned;
- rec_t* rec;
-
- ut_ad(cursor && mtr);
-
- page = page_cur_get_page(cursor);
- current_rec = cursor->rec;
- ut_ad(rec_offs_validate(current_rec, index, offsets));
- ut_ad(!!page_is_comp(page) == dict_table_is_comp(index->table));
-
- /* The record must not be the supremum or infimum record. */
- ut_ad(current_rec != page_get_supremum_rec(page));
- ut_ad(current_rec != page_get_infimum_rec(page));
-
- /* Save to local variables some data associated with current_rec */
- cur_slot_no = page_dir_find_owner_slot(current_rec);
- cur_dir_slot = page_dir_get_nth_slot(page, cur_slot_no);
- cur_n_owned = page_dir_slot_get_n_owned(cur_dir_slot);
-
- /* 0. Write the log record */
- page_cur_delete_rec_write_log(current_rec, index, mtr);
-
- /* 1. Reset the last insert info in the page header and increment
- the modify clock for the frame */
-
- page_header_set_ptr(page, PAGE_LAST_INSERT, NULL);
-
- /* The page gets invalid for optimistic searches: increment the
- frame modify clock */
-
- buf_frame_modify_clock_inc(page);
-
- /* 2. Find the next and the previous record. Note that the cursor is
- left at the next record. */
-
- ut_ad(cur_slot_no > 0);
- prev_slot = page_dir_get_nth_slot(page, cur_slot_no - 1);
-
- rec = page_dir_slot_get_rec(prev_slot);
-
- /* rec now points to the record of the previous directory slot. Look
- for the immediate predecessor of current_rec in a loop. */
-
- while(current_rec != rec) {
- prev_rec = rec;
- rec = page_rec_get_next(rec);
- }
-
- page_cur_move_to_next(cursor);
- next_rec = cursor->rec;
-
- /* 3. Remove the record from the linked list of records */
-
- page_rec_set_next(prev_rec, next_rec);
- page_header_set_field(page, PAGE_N_RECS,
- (ulint)(page_get_n_recs(page) - 1));
-
- /* 4. If the deleted record is pointed to by a dir slot, update the
- record pointer in slot. In the following if-clause we assume that
- prev_rec is owned by the same slot, i.e., PAGE_DIR_SLOT_MIN_N_OWNED
- >= 2. */
-
-#if PAGE_DIR_SLOT_MIN_N_OWNED < 2
-# error "PAGE_DIR_SLOT_MIN_N_OWNED < 2"
-#endif
- ut_ad(cur_n_owned > 1);
-
- if (current_rec == page_dir_slot_get_rec(cur_dir_slot)) {
- page_dir_slot_set_rec(cur_dir_slot, prev_rec);
- }
-
- /* 5. Update the number of owned records of the slot */
-
- page_dir_slot_set_n_owned(cur_dir_slot, cur_n_owned - 1);
-
- /* 6. Free the memory occupied by the record */
- page_mem_free(page, current_rec, offsets);
-
- /* 7. Now we have decremented the number of owned records of the slot.
- If the number drops below PAGE_DIR_SLOT_MIN_N_OWNED, we balance the
- slots. */
-
- if (cur_n_owned <= PAGE_DIR_SLOT_MIN_N_OWNED) {
- page_dir_balance_slot(page, cur_slot_no);
- }
-}
-
-#ifdef UNIV_COMPILE_TEST_FUNCS
-
-/***********************************************************************
-Print the first n numbers, generated by page_cur_lcg_prng() to make sure
-(visually) that it works properly. */
-void
-test_page_cur_lcg_prng(
-/*===================*/
- int n) /* in: print first n numbers */
-{
- int i;
- unsigned long long rnd;
-
- for (i = 0; i < n; i++) {
- rnd = page_cur_lcg_prng();
- printf("%llu\t%%2=%llu %%3=%llu %%5=%llu %%7=%llu %%11=%llu\n",
- rnd,
- rnd % 2,
- rnd % 3,
- rnd % 5,
- rnd % 7,
- rnd % 11);
- }
-}
-
-#endif /* UNIV_COMPILE_TEST_FUNCS */
diff --git a/storage/innobase/page/page0page.c b/storage/innobase/page/page0page.c
deleted file mode 100644
index 543cf9e34eb..00000000000
--- a/storage/innobase/page/page0page.c
+++ /dev/null
@@ -1,2038 +0,0 @@
-/******************************************************
-Index page routines
-
-(c) 1994-1996 Innobase Oy
-
-Created 2/2/1994 Heikki Tuuri
-*******************************************************/
-
-#define THIS_MODULE
-#include "page0page.h"
-#ifdef UNIV_NONINL
-#include "page0page.ic"
-#endif
-#undef THIS_MODULE
-
-#include "page0cur.h"
-#include "lock0lock.h"
-#include "fut0lst.h"
-#include "btr0sea.h"
-#include "buf0buf.h"
-#include "srv0srv.h"
-#include "btr0btr.h"
-
-/* THE INDEX PAGE
- ==============
-
-The index page consists of a page header which contains the page's
-id and other information. On top of it are the the index records
-in a heap linked into a one way linear list according to alphabetic order.
-
-Just below page end is an array of pointers which we call page directory,
-to about every sixth record in the list. The pointers are placed in
-the directory in the alphabetical order of the records pointed to,
-enabling us to make binary search using the array. Each slot n:o I
-in the directory points to a record, where a 4-bit field contains a count
-of those records which are in the linear list between pointer I and
-the pointer I - 1 in the directory, including the record
-pointed to by pointer I and not including the record pointed to by I - 1.
-We say that the record pointed to by slot I, or that slot I, owns
-these records. The count is always kept in the range 4 to 8, with
-the exception that it is 1 for the first slot, and 1--8 for the second slot.
-
-An essentially binary search can be performed in the list of index
-records, like we could do if we had pointer to every record in the
-page directory. The data structure is, however, more efficient when
-we are doing inserts, because most inserts are just pushed on a heap.
-Only every 8th insert requires block move in the directory pointer
-table, which itself is quite small. A record is deleted from the page
-by just taking it off the linear list and updating the number of owned
-records-field of the record which owns it, and updating the page directory,
-if necessary. A special case is the one when the record owns itself.
-Because the overhead of inserts is so small, we may also increase the
-page size from the projected default of 8 kB to 64 kB without too
-much loss of efficiency in inserts. Bigger page becomes actual
-when the disk transfer rate compared to seek and latency time rises.
-On the present system, the page size is set so that the page transfer
-time (3 ms) is 20 % of the disk random access time (15 ms).
-
-When the page is split, merged, or becomes full but contains deleted
-records, we have to reorganize the page.
-
-Assuming a page size of 8 kB, a typical index page of a secondary
-index contains 300 index entries, and the size of the page directory
-is 50 x 4 bytes = 200 bytes. */
-
-/*******************************************************************
-Looks for the directory slot which owns the given record. */
-
-ulint
-page_dir_find_owner_slot(
-/*=====================*/
- /* out: the directory slot number */
- rec_t* rec) /* in: the physical record */
-{
- page_t* page;
- register uint16 rec_offs_bytes;
- register page_dir_slot_t* slot;
- register const page_dir_slot_t* first_slot;
- register rec_t* r = rec;
-
- ut_ad(page_rec_check(rec));
-
- page = buf_frame_align(rec);
- first_slot = page_dir_get_nth_slot(page, 0);
- slot = page_dir_get_nth_slot(page, page_dir_get_n_slots(page) - 1);
-
- if (page_is_comp(page)) {
- while (rec_get_n_owned(r, TRUE) == 0) {
- r = page + rec_get_next_offs(r, TRUE);
- ut_ad(r >= page + PAGE_NEW_SUPREMUM);
- ut_ad(r < page + (UNIV_PAGE_SIZE - PAGE_DIR));
- }
- } else {
- while (rec_get_n_owned(r, FALSE) == 0) {
- r = page + rec_get_next_offs(r, FALSE);
- ut_ad(r >= page + PAGE_OLD_SUPREMUM);
- ut_ad(r < page + (UNIV_PAGE_SIZE - PAGE_DIR));
- }
- }
-
- rec_offs_bytes = mach_encode_2(r - page);
-
- while (UNIV_LIKELY(*(uint16*) slot != rec_offs_bytes)) {
-
- if (UNIV_UNLIKELY(slot == first_slot)) {
- fprintf(stderr,
- "InnoDB: Probable data corruption on"
- " page %lu\n"
- "InnoDB: Original record ",
- (ulong) buf_frame_get_page_no(page));
-
- if (page_is_comp(page)) {
- fputs("(compact record)", stderr);
- } else {
- rec_print_old(stderr, rec);
- }
-
- fputs("\n"
- "InnoDB: on that page.\n"
- "InnoDB: Cannot find the dir slot for record ",
- stderr);
- if (page_is_comp(page)) {
- fputs("(compact record)", stderr);
- } else {
- rec_print_old(stderr, page
- + mach_decode_2(rec_offs_bytes));
- }
- fputs("\n"
- "InnoDB: on that page!\n", stderr);
-
- buf_page_print(page);
-
- ut_error;
- }
-
- slot += PAGE_DIR_SLOT_SIZE;
- }
-
- return(((ulint) (first_slot - slot)) / PAGE_DIR_SLOT_SIZE);
-}
-
-/******************************************************************
-Used to check the consistency of a directory slot. */
-static
-ibool
-page_dir_slot_check(
-/*================*/
- /* out: TRUE if succeed */
- page_dir_slot_t* slot) /* in: slot */
-{
- page_t* page;
- ulint n_slots;
- ulint n_owned;
-
- ut_a(slot);
-
- page = buf_frame_align(slot);
-
- n_slots = page_dir_get_n_slots(page);
-
- ut_a(slot <= page_dir_get_nth_slot(page, 0));
- ut_a(slot >= page_dir_get_nth_slot(page, n_slots - 1));
-
- ut_a(page_rec_check(page_dir_slot_get_rec(slot)));
-
- n_owned = rec_get_n_owned(page_dir_slot_get_rec(slot),
- page_is_comp(page));
-
- if (slot == page_dir_get_nth_slot(page, 0)) {
- ut_a(n_owned == 1);
- } else if (slot == page_dir_get_nth_slot(page, n_slots - 1)) {
- ut_a(n_owned >= 1);
- ut_a(n_owned <= PAGE_DIR_SLOT_MAX_N_OWNED);
- } else {
- ut_a(n_owned >= PAGE_DIR_SLOT_MIN_N_OWNED);
- ut_a(n_owned <= PAGE_DIR_SLOT_MAX_N_OWNED);
- }
-
- return(TRUE);
-}
-
-/*****************************************************************
-Sets the max trx id field value. */
-
-void
-page_set_max_trx_id(
-/*================*/
- page_t* page, /* in: page */
- dulint trx_id) /* in: transaction id */
-{
- buf_block_t* block;
-
- ut_ad(page);
-
- block = buf_block_align(page);
-
- if (block->is_hashed) {
- rw_lock_x_lock(&btr_search_latch);
- }
-
- /* It is not necessary to write this change to the redo log, as
- during a database recovery we assume that the max trx id of every
- page is the maximum trx id assigned before the crash. */
-
- mach_write_to_8(page + PAGE_HEADER + PAGE_MAX_TRX_ID, trx_id);
-
- if (block->is_hashed) {
- rw_lock_x_unlock(&btr_search_latch);
- }
-}
-
-/*****************************************************************
-Calculates free space if a page is emptied. */
-
-ulint
-page_get_free_space_of_empty_noninline(
-/*===================================*/
- /* out: free space */
- ulint comp) /* in: nonzero=compact page format */
-{
- return(page_get_free_space_of_empty(comp));
-}
-
-/****************************************************************
-Allocates a block of memory from an index page. */
-
-byte*
-page_mem_alloc(
-/*===========*/
- /* out: pointer to start of allocated
- buffer, or NULL if allocation fails */
- page_t* page, /* in: index page */
- ulint need, /* in: number of bytes needed */
- dict_index_t* index, /* in: record descriptor */
- ulint* heap_no)/* out: this contains the heap number
- of the allocated record
- if allocation succeeds */
-{
- rec_t* rec;
- byte* block;
- ulint avl_space;
- ulint garbage;
-
- ut_ad(page && heap_no);
-
- /* If there are records in the free list, look if the first is
- big enough */
-
- rec = page_header_get_ptr(page, PAGE_FREE);
-
- if (rec) {
- mem_heap_t* heap = NULL;
- ulint offsets_[REC_OFFS_NORMAL_SIZE];
- ulint* offsets = offsets_;
- *offsets_ = (sizeof offsets_) / sizeof *offsets_;
-
- offsets = rec_get_offsets(rec, index, offsets,
- ULINT_UNDEFINED, &heap);
-
- if (rec_offs_size(offsets) >= need) {
- page_header_set_ptr(page, PAGE_FREE,
- page_rec_get_next(rec));
-
- garbage = page_header_get_field(page, PAGE_GARBAGE);
- ut_ad(garbage >= need);
-
- page_header_set_field(page, PAGE_GARBAGE,
- garbage - need);
-
- *heap_no = rec_get_heap_no(rec, page_is_comp(page));
-
- block = rec_get_start(rec, offsets);
- if (UNIV_LIKELY_NULL(heap)) {
- mem_heap_free(heap);
- }
- return(block);
- }
-
- if (UNIV_LIKELY_NULL(heap)) {
- mem_heap_free(heap);
- }
- }
-
- /* Could not find space from the free list, try top of heap */
-
- avl_space = page_get_max_insert_size(page, 1);
-
- if (avl_space >= need) {
- block = page_header_get_ptr(page, PAGE_HEAP_TOP);
-
- page_header_set_ptr(page, PAGE_HEAP_TOP, block + need);
- *heap_no = page_dir_get_n_heap(page);
-
- page_dir_set_n_heap(page, 1 + *heap_no);
-
- return(block);
- }
-
- return(NULL);
-}
-
-/**************************************************************
-Writes a log record of page creation. */
-UNIV_INLINE
-void
-page_create_write_log(
-/*==================*/
- buf_frame_t* frame, /* in: a buffer frame where the page is
- created */
- mtr_t* mtr, /* in: mini-transaction handle */
- ulint comp) /* in: nonzero=compact page format */
-{
- mlog_write_initial_log_record(frame, comp
- ? MLOG_COMP_PAGE_CREATE
- : MLOG_PAGE_CREATE, mtr);
-}
-
-/***************************************************************
-Parses a redo log record of creating a page. */
-
-byte*
-page_parse_create(
-/*==============*/
- /* out: end of log record or NULL */
- byte* ptr, /* in: buffer */
- byte* end_ptr __attribute__((unused)), /* in: buffer end */
- ulint comp, /* in: nonzero=compact page format */
- page_t* page, /* in: page or NULL */
- mtr_t* mtr) /* in: mtr or NULL */
-{
- ut_ad(ptr && end_ptr);
-
- /* The record is empty, except for the record initial part */
-
- if (page) {
- page_create(page, mtr, comp);
- }
-
- return(ptr);
-}
-
-/**************************************************************
-The index page creation function. */
-
-page_t*
-page_create(
-/*========*/
- /* out: pointer to the page */
- buf_frame_t* frame, /* in: a buffer frame where the page is
- created */
- mtr_t* mtr, /* in: mini-transaction handle */
- ulint comp) /* in: nonzero=compact page format */
-{
- page_dir_slot_t* slot;
- mem_heap_t* heap;
- dtuple_t* tuple;
- dfield_t* field;
- byte* heap_top;
- rec_t* infimum_rec;
- rec_t* supremum_rec;
- page_t* page;
- dict_index_t* index;
- ulint* offsets;
-
- index = comp ? srv_sys->dummy_ind2 : srv_sys->dummy_ind1;
-
- ut_ad(frame && mtr);
-#if PAGE_BTR_IBUF_FREE_LIST + FLST_BASE_NODE_SIZE > PAGE_DATA
-# error "PAGE_BTR_IBUF_FREE_LIST + FLST_BASE_NODE_SIZE > PAGE_DATA"
-#endif
-#if PAGE_BTR_IBUF_FREE_LIST_NODE + FLST_NODE_SIZE > PAGE_DATA
-# error "PAGE_BTR_IBUF_FREE_LIST_NODE + FLST_NODE_SIZE > PAGE_DATA"
-#endif
-
- /* 1. INCREMENT MODIFY CLOCK */
- buf_frame_modify_clock_inc(frame);
-
- /* 2. WRITE LOG INFORMATION */
- page_create_write_log(frame, mtr, comp);
-
- page = frame;
-
- fil_page_set_type(page, FIL_PAGE_INDEX);
-
- heap = mem_heap_create(200);
-
- /* 3. CREATE THE INFIMUM AND SUPREMUM RECORDS */
-
- /* Create first a data tuple for infimum record */
- tuple = dtuple_create(heap, 1);
- dtuple_set_info_bits(tuple, REC_STATUS_INFIMUM);
- field = dtuple_get_nth_field(tuple, 0);
-
- dfield_set_data(field, "infimum", 8);
- dtype_set(dfield_get_type(field),
- DATA_VARCHAR, DATA_ENGLISH | DATA_NOT_NULL, 8);
- /* Set the corresponding physical record to its place in the page
- record heap */
-
- heap_top = page + PAGE_DATA;
-
- infimum_rec = rec_convert_dtuple_to_rec(heap_top, index, tuple);
-
- ut_a(infimum_rec == page
- + (comp ? PAGE_NEW_INFIMUM : PAGE_OLD_INFIMUM));
-
- rec_set_n_owned(infimum_rec, comp, 1);
- rec_set_heap_no(infimum_rec, comp, 0);
- offsets = rec_get_offsets(infimum_rec, index, NULL,
- ULINT_UNDEFINED, &heap);
-
- heap_top = rec_get_end(infimum_rec, offsets);
-
- /* Create then a tuple for supremum */
-
- tuple = dtuple_create(heap, 1);
- dtuple_set_info_bits(tuple, REC_STATUS_SUPREMUM);
- field = dtuple_get_nth_field(tuple, 0);
-
- dfield_set_data(field, "supremum", comp ? 8 : 9);
- dtype_set(dfield_get_type(field),
- DATA_VARCHAR, DATA_ENGLISH | DATA_NOT_NULL, comp ? 8 : 9);
-
- supremum_rec = rec_convert_dtuple_to_rec(heap_top, index, tuple);
-
- ut_a(supremum_rec == page
- + (comp ? PAGE_NEW_SUPREMUM : PAGE_OLD_SUPREMUM));
-
- rec_set_n_owned(supremum_rec, comp, 1);
- rec_set_heap_no(supremum_rec, comp, 1);
-
- offsets = rec_get_offsets(supremum_rec, index, offsets,
- ULINT_UNDEFINED, &heap);
- heap_top = rec_get_end(supremum_rec, offsets);
-
- ut_ad(heap_top == page
- + (comp ? PAGE_NEW_SUPREMUM_END : PAGE_OLD_SUPREMUM_END));
-
- mem_heap_free(heap);
-
- /* 4. INITIALIZE THE PAGE */
-
- page_header_set_field(page, PAGE_N_DIR_SLOTS, 2);
- page_header_set_ptr(page, PAGE_HEAP_TOP, heap_top);
- page_header_set_field(page, PAGE_N_HEAP, comp ? 0x8002 : 2);
- page_header_set_ptr(page, PAGE_FREE, NULL);
- page_header_set_field(page, PAGE_GARBAGE, 0);
- page_header_set_ptr(page, PAGE_LAST_INSERT, NULL);
- page_header_set_field(page, PAGE_DIRECTION, PAGE_NO_DIRECTION);
- page_header_set_field(page, PAGE_N_DIRECTION, 0);
- page_header_set_field(page, PAGE_N_RECS, 0);
- page_set_max_trx_id(page, ut_dulint_zero);
- memset(heap_top, 0, UNIV_PAGE_SIZE - PAGE_EMPTY_DIR_START
- - (heap_top - page));
-
- /* 5. SET POINTERS IN RECORDS AND DIR SLOTS */
-
- /* Set the slots to point to infimum and supremum. */
-
- slot = page_dir_get_nth_slot(page, 0);
- page_dir_slot_set_rec(slot, infimum_rec);
-
- slot = page_dir_get_nth_slot(page, 1);
- page_dir_slot_set_rec(slot, supremum_rec);
-
- /* Set the next pointers in infimum and supremum */
-
- rec_set_next_offs(infimum_rec, comp, (ulint)(supremum_rec - page));
- rec_set_next_offs(supremum_rec, comp, 0);
-
- return(page);
-}
-
-/*****************************************************************
-Differs from page_copy_rec_list_end, because this function does not
-touch the lock table and max trx id on page. */
-
-void
-page_copy_rec_list_end_no_locks(
-/*============================*/
- page_t* new_page, /* in: index page to copy to */
- page_t* page, /* in: index page */
- rec_t* rec, /* in: record on page */
- dict_index_t* index, /* in: record descriptor */
- mtr_t* mtr) /* in: mtr */
-{
- page_cur_t cur1;
- page_cur_t cur2;
- rec_t* sup;
- mem_heap_t* heap = NULL;
- ulint offsets_[REC_OFFS_NORMAL_SIZE];
- ulint* offsets = offsets_;
- *offsets_ = (sizeof offsets_) / sizeof *offsets_;
-
- page_cur_position(rec, &cur1);
-
- if (page_cur_is_before_first(&cur1)) {
-
- page_cur_move_to_next(&cur1);
- }
-
- ut_a((ibool)!!page_is_comp(new_page)
- == dict_table_is_comp(index->table));
- ut_a(page_is_comp(new_page) == page_is_comp(page));
- ut_a(mach_read_from_2(new_page + UNIV_PAGE_SIZE - 10) == (ulint)
- (page_is_comp(new_page)
- ? PAGE_NEW_INFIMUM : PAGE_OLD_INFIMUM));
-
- page_cur_set_before_first(new_page, &cur2);
-
- /* Copy records from the original page to the new page */
-
- sup = page_get_supremum_rec(page);
-
- for (;;) {
- rec_t* cur1_rec = page_cur_get_rec(&cur1);
- if (cur1_rec == sup) {
- break;
- }
- offsets = rec_get_offsets(cur1_rec, index, offsets,
- ULINT_UNDEFINED, &heap);
- if (UNIV_UNLIKELY(!page_cur_rec_insert(&cur2, cur1_rec, index,
- offsets, mtr))) {
- /* Track an assertion failure reported on the mailing
- list on June 18th, 2003 */
-
- buf_page_print(new_page);
- buf_page_print(page);
- ut_print_timestamp(stderr);
-
- fprintf(stderr,
- "InnoDB: rec offset %lu, cur1 offset %lu,"
- " cur2 offset %lu\n",
- (ulong)(rec - page),
- (ulong)(page_cur_get_rec(&cur1) - page),
- (ulong)(page_cur_get_rec(&cur2) - new_page));
-
- ut_error;
- }
-
- page_cur_move_to_next(&cur1);
- page_cur_move_to_next(&cur2);
- }
-
- if (UNIV_LIKELY_NULL(heap)) {
- mem_heap_free(heap);
- }
-}
-
-/*****************************************************************
-Copies records from page to new_page, from a given record onward,
-including that record. Infimum and supremum records are not copied.
-The records are copied to the start of the record list on new_page. */
-
-void
-page_copy_rec_list_end(
-/*===================*/
- page_t* new_page, /* in: index page to copy to */
- page_t* page, /* in: index page */
- rec_t* rec, /* in: record on page */
- dict_index_t* index, /* in: record descriptor */
- mtr_t* mtr) /* in: mtr */
-{
- if (page_dir_get_n_heap(new_page) == 2) {
- page_copy_rec_list_end_to_created_page(new_page, page, rec,
- index, mtr);
- } else {
- page_copy_rec_list_end_no_locks(new_page, page, rec,
- index, mtr);
- }
-
- /* Update the lock table, MAX_TRX_ID, and possible hash index */
-
- lock_move_rec_list_end(new_page, page, rec);
-
- page_update_max_trx_id(new_page, page_get_max_trx_id(page));
-
- btr_search_move_or_delete_hash_entries(new_page, page, index);
-}
-
-/*****************************************************************
-Copies records from page to new_page, up to the given record,
-NOT including that record. Infimum and supremum records are not copied.
-The records are copied to the end of the record list on new_page. */
-
-void
-page_copy_rec_list_start(
-/*=====================*/
- page_t* new_page, /* in: index page to copy to */
- page_t* page, /* in: index page */
- rec_t* rec, /* in: record on page */
- dict_index_t* index, /* in: record descriptor */
- mtr_t* mtr) /* in: mtr */
-{
- page_cur_t cur1;
- page_cur_t cur2;
- rec_t* old_end;
- mem_heap_t* heap = NULL;
- ulint offsets_[REC_OFFS_NORMAL_SIZE];
- ulint* offsets = offsets_;
- *offsets_ = (sizeof offsets_) / sizeof *offsets_;
-
- page_cur_set_before_first(page, &cur1);
-
- if (rec == page_cur_get_rec(&cur1)) {
-
- return;
- }
-
- page_cur_move_to_next(&cur1);
-
- page_cur_set_after_last(new_page, &cur2);
- page_cur_move_to_prev(&cur2);
- old_end = page_cur_get_rec(&cur2);
-
- /* Copy records from the original page to the new page */
-
- while (page_cur_get_rec(&cur1) != rec) {
- rec_t* ins_rec;
- rec_t* cur1_rec = page_cur_get_rec(&cur1);
- offsets = rec_get_offsets(cur1_rec, index, offsets,
- ULINT_UNDEFINED, &heap);
- ins_rec = page_cur_rec_insert(&cur2, cur1_rec, index,
- offsets, mtr);
- ut_a(ins_rec);
-
- page_cur_move_to_next(&cur1);
- page_cur_move_to_next(&cur2);
- }
-
- /* Update the lock table, MAX_TRX_ID, and possible hash index */
-
- lock_move_rec_list_start(new_page, page, rec, old_end);
-
- page_update_max_trx_id(new_page, page_get_max_trx_id(page));
-
- btr_search_move_or_delete_hash_entries(new_page, page, index);
-
- if (UNIV_LIKELY_NULL(heap)) {
- mem_heap_free(heap);
- }
-}
-
-/**************************************************************
-Writes a log record of a record list end or start deletion. */
-UNIV_INLINE
-void
-page_delete_rec_list_write_log(
-/*===========================*/
- rec_t* rec, /* in: record on page */
- dict_index_t* index, /* in: record descriptor */
- byte type, /* in: operation type:
- MLOG_LIST_END_DELETE, ... */
- mtr_t* mtr) /* in: mtr */
-{
- byte* log_ptr;
- ut_ad(type == MLOG_LIST_END_DELETE
- || type == MLOG_LIST_START_DELETE
- || type == MLOG_COMP_LIST_END_DELETE
- || type == MLOG_COMP_LIST_START_DELETE);
-
- log_ptr = mlog_open_and_write_index(mtr, rec, index, type, 2);
- if (log_ptr) {
- /* Write the parameter as a 2-byte ulint */
- mach_write_to_2(log_ptr, page_offset(rec));
- mlog_close(mtr, log_ptr + 2);
- }
-}
-
-/**************************************************************
-Parses a log record of a record list end or start deletion. */
-
-byte*
-page_parse_delete_rec_list(
-/*=======================*/
- /* out: end of log record or NULL */
- byte type, /* in: MLOG_LIST_END_DELETE,
- MLOG_LIST_START_DELETE,
- MLOG_COMP_LIST_END_DELETE or
- MLOG_COMP_LIST_START_DELETE */
- byte* ptr, /* in: buffer */
- byte* end_ptr,/* in: buffer end */
- dict_index_t* index, /* in: record descriptor */
- page_t* page, /* in: page or NULL */
- mtr_t* mtr) /* in: mtr or NULL */
-{
- ulint offset;
-
- ut_ad(type == MLOG_LIST_END_DELETE
- || type == MLOG_LIST_START_DELETE
- || type == MLOG_COMP_LIST_END_DELETE
- || type == MLOG_COMP_LIST_START_DELETE);
-
- /* Read the record offset as a 2-byte ulint */
-
- if (end_ptr < ptr + 2) {
-
- return(NULL);
- }
-
- offset = mach_read_from_2(ptr);
- ptr += 2;
-
- if (!page) {
-
- return(ptr);
- }
-
- ut_ad(!!page_is_comp(page) == dict_table_is_comp(index->table));
-
- if (type == MLOG_LIST_END_DELETE
- || type == MLOG_COMP_LIST_END_DELETE) {
- page_delete_rec_list_end(page, page + offset, index,
- ULINT_UNDEFINED,
- ULINT_UNDEFINED, mtr);
- } else {
- page_delete_rec_list_start(page, page + offset, index, mtr);
- }
-
- return(ptr);
-}
-
-/*****************************************************************
-Deletes records from a page from a given record onward, including that record.
-The infimum and supremum records are not deleted. */
-
-void
-page_delete_rec_list_end(
-/*=====================*/
- page_t* page, /* in: index page */
- rec_t* rec, /* in: record on page */
- dict_index_t* index, /* in: record descriptor */
- ulint n_recs, /* in: number of records to delete,
- or ULINT_UNDEFINED if not known */
- ulint size, /* in: the sum of the sizes of the
- records in the end of the chain to
- delete, or ULINT_UNDEFINED if not known */
- mtr_t* mtr) /* in: mtr */
-{
- page_dir_slot_t* slot;
- ulint slot_index;
- rec_t* last_rec;
- rec_t* prev_rec;
- rec_t* free;
- rec_t* rec2;
- ulint count;
- ulint n_owned;
- rec_t* sup;
- ulint comp;
-
- /* Reset the last insert info in the page header and increment
- the modify clock for the frame */
-
- ut_ad(size == ULINT_UNDEFINED || size < UNIV_PAGE_SIZE);
- page_header_set_ptr(page, PAGE_LAST_INSERT, NULL);
-
- /* The page gets invalid for optimistic searches: increment the
- frame modify clock */
-
- buf_frame_modify_clock_inc(page);
-
- sup = page_get_supremum_rec(page);
-
- comp = page_is_comp(page);
- if (page_rec_is_infimum_low(rec - page)) {
- rec = page_rec_get_next(rec);
- }
-
- page_delete_rec_list_write_log(rec, index, comp
- ? MLOG_COMP_LIST_END_DELETE
- : MLOG_LIST_END_DELETE, mtr);
-
- if (rec == sup) {
-
- return;
- }
-
- prev_rec = page_rec_get_prev(rec);
-
- last_rec = page_rec_get_prev(sup);
-
- if ((size == ULINT_UNDEFINED) || (n_recs == ULINT_UNDEFINED)) {
- mem_heap_t* heap = NULL;
- ulint offsets_[REC_OFFS_NORMAL_SIZE];
- ulint* offsets = offsets_;
- *offsets_ = (sizeof offsets_) / sizeof *offsets_;
- /* Calculate the sum of sizes and the number of records */
- size = 0;
- n_recs = 0;
- rec2 = rec;
-
- while (rec2 != sup) {
- ulint s;
- offsets = rec_get_offsets(rec2, index, offsets,
- ULINT_UNDEFINED, &heap);
- s = rec_offs_size(offsets);
- ut_ad(rec2 - page + s - rec_offs_extra_size(offsets)
- < UNIV_PAGE_SIZE);
- ut_ad(size + s < UNIV_PAGE_SIZE);
- size += s;
- n_recs++;
-
- rec2 = page_rec_get_next(rec2);
- }
-
- if (UNIV_LIKELY_NULL(heap)) {
- mem_heap_free(heap);
- }
- }
-
- ut_ad(size < UNIV_PAGE_SIZE);
-
- /* Update the page directory; there is no need to balance the number
- of the records owned by the supremum record, as it is allowed to be
- less than PAGE_DIR_SLOT_MIN_N_OWNED */
-
- rec2 = rec;
- count = 0;
-
- while (rec_get_n_owned(rec2, comp) == 0) {
- count++;
-
- rec2 = page_rec_get_next(rec2);
- }
-
- ut_ad(rec_get_n_owned(rec2, comp) - count > 0);
-
- n_owned = rec_get_n_owned(rec2, comp) - count;
-
- slot_index = page_dir_find_owner_slot(rec2);
- slot = page_dir_get_nth_slot(page, slot_index);
-
- page_dir_slot_set_rec(slot, sup);
- page_dir_slot_set_n_owned(slot, n_owned);
-
- page_dir_set_n_slots(page, slot_index + 1);
-
- /* Remove the record chain segment from the record chain */
- page_rec_set_next(prev_rec, page_get_supremum_rec(page));
-
- /* Catenate the deleted chain segment to the page free list */
-
- free = page_header_get_ptr(page, PAGE_FREE);
-
- page_rec_set_next(last_rec, free);
- page_header_set_ptr(page, PAGE_FREE, rec);
-
- page_header_set_field(page, PAGE_GARBAGE, size
- + page_header_get_field(page, PAGE_GARBAGE));
-
- page_header_set_field(page, PAGE_N_RECS,
- (ulint)(page_get_n_recs(page) - n_recs));
-}
-
-/*****************************************************************
-Deletes records from page, up to the given record, NOT including
-that record. Infimum and supremum records are not deleted. */
-
-void
-page_delete_rec_list_start(
-/*=======================*/
- page_t* page, /* in: index page */
- rec_t* rec, /* in: record on page */
- dict_index_t* index, /* in: record descriptor */
- mtr_t* mtr) /* in: mtr */
-{
- page_cur_t cur1;
- ulint log_mode;
- ulint offsets_[REC_OFFS_NORMAL_SIZE];
- ulint* offsets = offsets_;
- mem_heap_t* heap = NULL;
- byte type;
- *offsets_ = (sizeof offsets_) / sizeof *offsets_;
-
- ut_ad(!!page_is_comp(page) == dict_table_is_comp(index->table));
-
- if (page_is_comp(page)) {
- type = MLOG_COMP_LIST_START_DELETE;
- } else {
- type = MLOG_LIST_START_DELETE;
- }
-
- page_delete_rec_list_write_log(rec, index, type, mtr);
-
- page_cur_set_before_first(page, &cur1);
-
- if (rec == page_cur_get_rec(&cur1)) {
-
- return;
- }
-
- page_cur_move_to_next(&cur1);
-
- /* Individual deletes are not logged */
-
- log_mode = mtr_set_log_mode(mtr, MTR_LOG_NONE);
-
- while (page_cur_get_rec(&cur1) != rec) {
- offsets = rec_get_offsets(page_cur_get_rec(&cur1), index,
- offsets, ULINT_UNDEFINED, &heap);
- page_cur_delete_rec(&cur1, index, offsets, mtr);
- }
-
- if (UNIV_LIKELY_NULL(heap)) {
- mem_heap_free(heap);
- }
-
- /* Restore log mode */
-
- mtr_set_log_mode(mtr, log_mode);
-}
-
-/*****************************************************************
-Moves record list end to another page. Moved records include
-split_rec. */
-
-void
-page_move_rec_list_end(
-/*===================*/
- page_t* new_page, /* in: index page where to move */
- page_t* page, /* in: index page */
- rec_t* split_rec, /* in: first record to move */
- dict_index_t* index, /* in: record descriptor */
- mtr_t* mtr) /* in: mtr */
-{
- ulint old_data_size;
- ulint new_data_size;
- ulint old_n_recs;
- ulint new_n_recs;
-
- old_data_size = page_get_data_size(new_page);
- old_n_recs = page_get_n_recs(new_page);
-
- page_copy_rec_list_end(new_page, page, split_rec, index, mtr);
-
- new_data_size = page_get_data_size(new_page);
- new_n_recs = page_get_n_recs(new_page);
-
- ut_ad(new_data_size >= old_data_size);
-
- page_delete_rec_list_end(page, split_rec, index,
- new_n_recs - old_n_recs,
- new_data_size - old_data_size, mtr);
-}
-
-/*****************************************************************
-Moves record list start to another page. Moved records do not include
-split_rec. */
-
-void
-page_move_rec_list_start(
-/*=====================*/
- page_t* new_page, /* in: index page where to move */
- page_t* page, /* in: index page */
- rec_t* split_rec, /* in: first record not to move */
- dict_index_t* index, /* in: record descriptor */
- mtr_t* mtr) /* in: mtr */
-{
- page_copy_rec_list_start(new_page, page, split_rec, index, mtr);
-
- page_delete_rec_list_start(page, split_rec, index, mtr);
-}
-
-/***************************************************************************
-This is a low-level operation which is used in a database index creation
-to update the page number of a created B-tree to a data dictionary record. */
-
-void
-page_rec_write_index_page_no(
-/*=========================*/
- rec_t* rec, /* in: record to update */
- ulint i, /* in: index of the field to update */
- ulint page_no,/* in: value to write */
- mtr_t* mtr) /* in: mtr */
-{
- byte* data;
- ulint len;
-
- data = rec_get_nth_field_old(rec, i, &len);
-
- ut_ad(len == 4);
-
- mlog_write_ulint(data, page_no, MLOG_4BYTES, mtr);
-}
-
-/******************************************************************
-Used to delete n slots from the directory. This function updates
-also n_owned fields in the records, so that the first slot after
-the deleted ones inherits the records of the deleted slots. */
-UNIV_INLINE
-void
-page_dir_delete_slots(
-/*==================*/
- page_t* page, /* in: the index page */
- ulint start, /* in: first slot to be deleted */
- ulint n) /* in: number of slots to delete (currently
- only n == 1 allowed) */
-{
- page_dir_slot_t* slot;
- ulint i;
- ulint sum_owned = 0;
- ulint n_slots;
- rec_t* rec;
-
- ut_ad(n == 1);
- ut_ad(start > 0);
- ut_ad(start + n < page_dir_get_n_slots(page));
-
- n_slots = page_dir_get_n_slots(page);
-
- /* 1. Reset the n_owned fields of the slots to be
- deleted */
- for (i = start; i < start + n; i++) {
- slot = page_dir_get_nth_slot(page, i);
- sum_owned += page_dir_slot_get_n_owned(slot);
- page_dir_slot_set_n_owned(slot, 0);
- }
-
- /* 2. Update the n_owned value of the first non-deleted slot */
-
- slot = page_dir_get_nth_slot(page, start + n);
- page_dir_slot_set_n_owned(slot,
- sum_owned + page_dir_slot_get_n_owned(slot));
-
- /* 3. Destroy start and other slots by copying slots */
- for (i = start + n; i < n_slots; i++) {
- slot = page_dir_get_nth_slot(page, i);
- rec = page_dir_slot_get_rec(slot);
-
- slot = page_dir_get_nth_slot(page, i - n);
- page_dir_slot_set_rec(slot, rec);
- }
-
- /* 4. Update the page header */
- page_header_set_field(page, PAGE_N_DIR_SLOTS, n_slots - n);
-}
-
-/******************************************************************
-Used to add n slots to the directory. Does not set the record pointers
-in the added slots or update n_owned values: this is the responsibility
-of the caller. */
-UNIV_INLINE
-void
-page_dir_add_slots(
-/*===============*/
- page_t* page, /* in: the index page */
- ulint start, /* in: the slot above which the new slots are added */
- ulint n) /* in: number of slots to add (currently only n == 1
- allowed) */
-{
- page_dir_slot_t* slot;
- ulint n_slots;
- ulint i;
- rec_t* rec;
-
- ut_ad(n == 1);
-
- n_slots = page_dir_get_n_slots(page);
-
- ut_ad(start < n_slots - 1);
-
- /* Update the page header */
- page_dir_set_n_slots(page, n_slots + n);
-
- /* Move slots up */
-
- for (i = n_slots - 1; i > start; i--) {
-
- slot = page_dir_get_nth_slot(page, i);
- rec = page_dir_slot_get_rec(slot);
-
- slot = page_dir_get_nth_slot(page, i + n);
- page_dir_slot_set_rec(slot, rec);
- }
-}
-
-/********************************************************************
-Splits a directory slot which owns too many records. */
-
-void
-page_dir_split_slot(
-/*================*/
- page_t* page, /* in: the index page in question */
- ulint slot_no) /* in: the directory slot */
-{
- rec_t* rec;
- page_dir_slot_t* new_slot;
- page_dir_slot_t* prev_slot;
- page_dir_slot_t* slot;
- ulint i;
- ulint n_owned;
-
- ut_ad(page);
- ut_ad(slot_no > 0);
-
- slot = page_dir_get_nth_slot(page, slot_no);
-
- n_owned = page_dir_slot_get_n_owned(slot);
- ut_ad(n_owned == PAGE_DIR_SLOT_MAX_N_OWNED + 1);
-
- /* 1. We loop to find a record approximately in the middle of the
- records owned by the slot. */
-
- prev_slot = page_dir_get_nth_slot(page, slot_no - 1);
- rec = page_dir_slot_get_rec(prev_slot);
-
- for (i = 0; i < n_owned / 2; i++) {
- rec = page_rec_get_next(rec);
- }
-
- ut_ad(n_owned / 2 >= PAGE_DIR_SLOT_MIN_N_OWNED);
-
- /* 2. We add one directory slot immediately below the slot to be
- split. */
-
- page_dir_add_slots(page, slot_no - 1, 1);
-
- /* The added slot is now number slot_no, and the old slot is
- now number slot_no + 1 */
-
- new_slot = page_dir_get_nth_slot(page, slot_no);
- slot = page_dir_get_nth_slot(page, slot_no + 1);
-
- /* 3. We store the appropriate values to the new slot. */
-
- page_dir_slot_set_rec(new_slot, rec);
- page_dir_slot_set_n_owned(new_slot, n_owned / 2);
-
- /* 4. Finally, we update the number of records field of the
- original slot */
-
- page_dir_slot_set_n_owned(slot, n_owned - (n_owned / 2));
-}
-
-/*****************************************************************
-Tries to balance the given directory slot with too few records with the upper
-neighbor, so that there are at least the minimum number of records owned by
-the slot; this may result in the merging of two slots. */
-
-void
-page_dir_balance_slot(
-/*==================*/
- page_t* page, /* in: index page */
- ulint slot_no) /* in: the directory slot */
-{
- page_dir_slot_t* slot;
- page_dir_slot_t* up_slot;
- ulint n_owned;
- ulint up_n_owned;
- rec_t* old_rec;
- rec_t* new_rec;
-
- ut_ad(page);
- ut_ad(slot_no > 0);
-
- slot = page_dir_get_nth_slot(page, slot_no);
-
- /* The last directory slot cannot be balanced with the upper
- neighbor, as there is none. */
-
- if (slot_no == page_dir_get_n_slots(page) - 1) {
-
- return;
- }
-
- up_slot = page_dir_get_nth_slot(page, slot_no + 1);
-
- n_owned = page_dir_slot_get_n_owned(slot);
- up_n_owned = page_dir_slot_get_n_owned(up_slot);
-
- ut_ad(n_owned == PAGE_DIR_SLOT_MIN_N_OWNED - 1);
-
- /* If the upper slot has the minimum value of n_owned, we will merge
- the two slots, therefore we assert: */
- ut_ad(2 * PAGE_DIR_SLOT_MIN_N_OWNED - 1 <= PAGE_DIR_SLOT_MAX_N_OWNED);
-
- if (up_n_owned > PAGE_DIR_SLOT_MIN_N_OWNED) {
-
- /* In this case we can just transfer one record owned
- by the upper slot to the property of the lower slot */
- old_rec = page_dir_slot_get_rec(slot);
- new_rec = page_rec_get_next(old_rec);
-
- rec_set_n_owned(old_rec, page_is_comp(page), 0);
- rec_set_n_owned(new_rec, page_is_comp(page), n_owned + 1);
-
- page_dir_slot_set_rec(slot, new_rec);
-
- page_dir_slot_set_n_owned(up_slot, up_n_owned -1);
- } else {
- /* In this case we may merge the two slots */
- page_dir_delete_slots(page, slot_no, 1);
- }
-}
-
-/****************************************************************
-Returns the middle record of the record list. If there are an even number
-of records in the list, returns the first record of the upper half-list. */
-
-rec_t*
-page_get_middle_rec(
-/*================*/
- /* out: middle record */
- page_t* page) /* in: page */
-{
- page_dir_slot_t* slot;
- ulint middle;
- ulint i;
- ulint n_owned;
- ulint count;
- rec_t* rec;
-
- /* This many records we must leave behind */
- middle = (page_get_n_recs(page) + 2) / 2;
-
- count = 0;
-
- for (i = 0;; i++) {
-
- slot = page_dir_get_nth_slot(page, i);
- n_owned = page_dir_slot_get_n_owned(slot);
-
- if (count + n_owned > middle) {
- break;
- } else {
- count += n_owned;
- }
- }
-
- ut_ad(i > 0);
- slot = page_dir_get_nth_slot(page, i - 1);
- rec = page_dir_slot_get_rec(slot);
- rec = page_rec_get_next(rec);
-
- /* There are now count records behind rec */
-
- for (i = 0; i < middle - count; i++) {
- rec = page_rec_get_next(rec);
- }
-
- return(rec);
-}
-
-/*******************************************************************
-Returns the number of records before the given record in chain.
-The number includes infimum and supremum records. */
-
-ulint
-page_rec_get_n_recs_before(
-/*=======================*/
- /* out: number of records */
- rec_t* rec) /* in: the physical record */
-{
- page_dir_slot_t* slot;
- rec_t* slot_rec;
- page_t* page;
- ulint i;
- ulint comp;
- lint n = 0;
-
- ut_ad(page_rec_check(rec));
-
- page = buf_frame_align(rec);
- comp = page_is_comp(page);
-
- while (rec_get_n_owned(rec, comp) == 0) {
-
- rec = page_rec_get_next(rec);
- n--;
- }
-
- for (i = 0; ; i++) {
- slot = page_dir_get_nth_slot(page, i);
- slot_rec = page_dir_slot_get_rec(slot);
-
- n += rec_get_n_owned(slot_rec, comp);
-
- if (rec == slot_rec) {
-
- break;
- }
- }
-
- n--;
-
- ut_ad(n >= 0);
-
- return((ulint) n);
-}
-
-/****************************************************************
-Prints record contents including the data relevant only in
-the index page context. */
-
-void
-page_rec_print(
-/*===========*/
- rec_t* rec, /* in: physical record */
- const ulint* offsets)/* in: record descriptor */
-{
- ulint comp = page_is_comp(buf_frame_align(rec));
-
- ut_a(!comp == !rec_offs_comp(offsets));
- rec_print_new(stderr, rec, offsets);
- fprintf(stderr,
- " n_owned: %lu; heap_no: %lu; next rec: %lu\n",
- (ulong) rec_get_n_owned(rec, comp),
- (ulong) rec_get_heap_no(rec, comp),
- (ulong) rec_get_next_offs(rec, comp));
-
- page_rec_check(rec);
- rec_validate(rec, offsets);
-}
-
-/*******************************************************************
-This is used to print the contents of the directory for
-debugging purposes. */
-
-void
-page_dir_print(
-/*===========*/
- page_t* page, /* in: index page */
- ulint pr_n) /* in: print n first and n last entries */
-{
- ulint n;
- ulint i;
- page_dir_slot_t* slot;
-
- n = page_dir_get_n_slots(page);
-
- fprintf(stderr, "--------------------------------\n"
- "PAGE DIRECTORY\n"
- "Page address %p\n"
- "Directory stack top at offs: %lu; number of slots: %lu\n",
- page, (ulong)(page_dir_get_nth_slot(page, n - 1) - page),
- (ulong) n);
- for (i = 0; i < n; i++) {
- slot = page_dir_get_nth_slot(page, i);
- if ((i == pr_n) && (i < n - pr_n)) {
- fputs(" ... \n", stderr);
- }
- if ((i < pr_n) || (i >= n - pr_n)) {
- fprintf(stderr,
- "Contents of slot: %lu: n_owned: %lu,"
- " rec offs: %lu\n",
- (ulong) i,
- (ulong) page_dir_slot_get_n_owned(slot),
- (ulong)(page_dir_slot_get_rec(slot) - page));
- }
- }
- fprintf(stderr, "Total of %lu records\n"
- "--------------------------------\n",
- (ulong) (2 + page_get_n_recs(page)));
-}
-
-/*******************************************************************
-This is used to print the contents of the page record list for
-debugging purposes. */
-
-void
-page_print_list(
-/*============*/
- page_t* page, /* in: index page */
- dict_index_t* index, /* in: dictionary index of the page */
- ulint pr_n) /* in: print n first and n last entries */
-{
- page_cur_t cur;
- ulint count;
- ulint n_recs;
- mem_heap_t* heap = NULL;
- ulint offsets_[REC_OFFS_NORMAL_SIZE];
- ulint* offsets = offsets_;
- *offsets_ = (sizeof offsets_) / sizeof *offsets_;
-
- ut_a((ibool)!!page_is_comp(page) == dict_table_is_comp(index->table));
-
- fprintf(stderr,
- "--------------------------------\n"
- "PAGE RECORD LIST\n"
- "Page address %p\n", page);
-
- n_recs = page_get_n_recs(page);
-
- page_cur_set_before_first(page, &cur);
- count = 0;
- for (;;) {
- offsets = rec_get_offsets(cur.rec, index, offsets,
- ULINT_UNDEFINED, &heap);
- page_rec_print(cur.rec, offsets);
-
- if (count == pr_n) {
- break;
- }
- if (page_cur_is_after_last(&cur)) {
- break;
- }
- page_cur_move_to_next(&cur);
- count++;
- }
-
- if (n_recs > 2 * pr_n) {
- fputs(" ... \n", stderr);
- }
-
- while (!page_cur_is_after_last(&cur)) {
- page_cur_move_to_next(&cur);
-
- if (count + pr_n >= n_recs) {
- offsets = rec_get_offsets(cur.rec, index, offsets,
- ULINT_UNDEFINED, &heap);
- page_rec_print(cur.rec, offsets);
- }
- count++;
- }
-
- fprintf(stderr,
- "Total of %lu records \n"
- "--------------------------------\n",
- (ulong) (count + 1));
-
- if (UNIV_LIKELY_NULL(heap)) {
- mem_heap_free(heap);
- }
-}
-
-/*******************************************************************
-Prints the info in a page header. */
-
-void
-page_header_print(
-/*==============*/
- page_t* page)
-{
- fprintf(stderr,
- "--------------------------------\n"
- "PAGE HEADER INFO\n"
- "Page address %p, n records %lu (%s)\n"
- "n dir slots %lu, heap top %lu\n"
- "Page n heap %lu, free %lu, garbage %lu\n"
- "Page last insert %lu, direction %lu, n direction %lu\n",
- page, (ulong) page_header_get_field(page, PAGE_N_RECS),
- page_is_comp(page) ? "compact format" : "original format",
- (ulong) page_header_get_field(page, PAGE_N_DIR_SLOTS),
- (ulong) page_header_get_field(page, PAGE_HEAP_TOP),
- (ulong) page_dir_get_n_heap(page),
- (ulong) page_header_get_field(page, PAGE_FREE),
- (ulong) page_header_get_field(page, PAGE_GARBAGE),
- (ulong) page_header_get_field(page, PAGE_LAST_INSERT),
- (ulong) page_header_get_field(page, PAGE_DIRECTION),
- (ulong) page_header_get_field(page, PAGE_N_DIRECTION));
-}
-
-/*******************************************************************
-This is used to print the contents of the page for
-debugging purposes. */
-
-void
-page_print(
-/*=======*/
- page_t* page, /* in: index page */
- dict_index_t* index, /* in: dictionary index of the page */
- ulint dn, /* in: print dn first and last entries
- in directory */
- ulint rn) /* in: print rn first and last records
- in directory */
-{
- page_header_print(page);
- page_dir_print(page, dn);
- page_print_list(page, index, rn);
-}
-
-/*******************************************************************
-The following is used to validate a record on a page. This function
-differs from rec_validate as it can also check the n_owned field and
-the heap_no field. */
-
-ibool
-page_rec_validate(
-/*==============*/
- /* out: TRUE if ok */
- rec_t* rec, /* in: physical record */
- const ulint* offsets)/* in: array returned by rec_get_offsets() */
-{
- ulint n_owned;
- ulint heap_no;
- page_t* page;
- ulint comp;
-
- page = buf_frame_align(rec);
- comp = page_is_comp(page);
- ut_a(!comp == !rec_offs_comp(offsets));
-
- page_rec_check(rec);
- rec_validate(rec, offsets);
-
- n_owned = rec_get_n_owned(rec, comp);
- heap_no = rec_get_heap_no(rec, comp);
-
- if (!(n_owned <= PAGE_DIR_SLOT_MAX_N_OWNED)) {
- fprintf(stderr,
- "InnoDB: Dir slot of rec %lu, n owned too big %lu\n",
- (ulong)(rec - page), (ulong) n_owned);
- return(FALSE);
- }
-
- if (!(heap_no < page_dir_get_n_heap(page))) {
- fprintf(stderr,
- "InnoDB: Heap no of rec %lu too big %lu %lu\n",
- (ulong)(rec - page), (ulong) heap_no,
- (ulong) page_dir_get_n_heap(page));
- return(FALSE);
- }
-
- return(TRUE);
-}
-
-/*******************************************************************
-Checks that the first directory slot points to the infimum record and
-the last to the supremum. This function is intended to track if the
-bug fixed in 4.0.14 has caused corruption to users' databases. */
-
-void
-page_check_dir(
-/*===========*/
- page_t* page) /* in: index page */
-{
- ulint n_slots;
-
- n_slots = page_dir_get_n_slots(page);
-
- if (page_dir_slot_get_rec(page_dir_get_nth_slot(page, 0))
- != page_get_infimum_rec(page)) {
-
- fprintf(stderr,
- "InnoDB: Page directory corruption:"
- " infimum not pointed to\n");
- buf_page_print(page);
- }
-
- if (page_dir_slot_get_rec(page_dir_get_nth_slot(page, n_slots - 1))
- != page_get_supremum_rec(page)) {
-
- fprintf(stderr,
- "InnoDB: Page directory corruption:"
- " supremum not pointed to\n");
- buf_page_print(page);
- }
-}
-
-/*******************************************************************
-This function checks the consistency of an index page when we do not
-know the index. This is also resilient so that this should never crash
-even if the page is total garbage. */
-
-ibool
-page_simple_validate(
-/*=================*/
- /* out: TRUE if ok */
- page_t* page) /* in: index page */
-{
- page_cur_t cur;
- page_dir_slot_t* slot;
- ulint slot_no;
- ulint n_slots;
- rec_t* rec;
- byte* rec_heap_top;
- ulint count;
- ulint own_count;
- ibool ret = FALSE;
- ulint comp = page_is_comp(page);
-
- /* Check first that the record heap and the directory do not
- overlap. */
-
- n_slots = page_dir_get_n_slots(page);
-
- if (n_slots > UNIV_PAGE_SIZE / 4) {
- fprintf(stderr,
- "InnoDB: Nonsensical number %lu of page dir slots\n",
- (ulong) n_slots);
-
- goto func_exit;
- }
-
- rec_heap_top = page_header_get_ptr(page, PAGE_HEAP_TOP);
-
- if (rec_heap_top > page_dir_get_nth_slot(page, n_slots - 1)) {
-
- fprintf(stderr,
- "InnoDB: Record heap and dir overlap on a page,"
- " heap top %lu, dir %lu\n",
- (ulong)
- (page_header_get_ptr(page, PAGE_HEAP_TOP) - page),
- (ulong)
- (page_dir_get_nth_slot(page, n_slots - 1) - page));
-
- goto func_exit;
- }
-
- /* Validate the record list in a loop checking also that it is
- consistent with the page record directory. */
-
- count = 0;
- own_count = 1;
- slot_no = 0;
- slot = page_dir_get_nth_slot(page, slot_no);
-
- page_cur_set_before_first(page, &cur);
-
- for (;;) {
- rec = (&cur)->rec;
-
- if (rec > rec_heap_top) {
- fprintf(stderr,
- "InnoDB: Record %lu is above"
- " rec heap top %lu\n",
- (ulong)(rec - page),
- (ulong)(rec_heap_top - page));
-
- goto func_exit;
- }
-
- if (rec_get_n_owned(rec, comp) != 0) {
- /* This is a record pointed to by a dir slot */
- if (rec_get_n_owned(rec, comp) != own_count) {
-
- fprintf(stderr,
- "InnoDB: Wrong owned count %lu, %lu,"
- " rec %lu\n",
- (ulong) rec_get_n_owned(rec, comp),
- (ulong) own_count,
- (ulong)(rec - page));
-
- goto func_exit;
- }
-
- if (page_dir_slot_get_rec(slot) != rec) {
- fprintf(stderr,
- "InnoDB: Dir slot does not point"
- " to right rec %lu\n",
- (ulong)(rec - page));
-
- goto func_exit;
- }
-
- own_count = 0;
-
- if (!page_cur_is_after_last(&cur)) {
- slot_no++;
- slot = page_dir_get_nth_slot(page, slot_no);
- }
- }
-
- if (page_cur_is_after_last(&cur)) {
-
- break;
- }
-
- if (rec_get_next_offs(rec, comp) < FIL_PAGE_DATA
- || rec_get_next_offs(rec, comp) >= UNIV_PAGE_SIZE) {
- fprintf(stderr,
- "InnoDB: Next record offset"
- " nonsensical %lu for rec %lu\n",
- (ulong) rec_get_next_offs(rec, comp),
- (ulong)(rec - page));
-
- goto func_exit;
- }
-
- count++;
-
- if (count > UNIV_PAGE_SIZE) {
- fprintf(stderr,
- "InnoDB: Page record list appears"
- " to be circular %lu\n",
- (ulong) count);
- goto func_exit;
- }
-
- page_cur_move_to_next(&cur);
- own_count++;
- }
-
- if (rec_get_n_owned(rec, comp) == 0) {
- fprintf(stderr, "InnoDB: n owned is zero in a supremum rec\n");
-
- goto func_exit;
- }
-
- if (slot_no != n_slots - 1) {
- fprintf(stderr, "InnoDB: n slots wrong %lu, %lu\n",
- (ulong) slot_no, (ulong) (n_slots - 1));
- goto func_exit;
- }
-
- if (page_header_get_field(page, PAGE_N_RECS) + 2 != count + 1) {
- fprintf(stderr, "InnoDB: n recs wrong %lu %lu\n",
- (ulong) page_header_get_field(page, PAGE_N_RECS) + 2,
- (ulong) (count + 1));
-
- goto func_exit;
- }
-
- /* Check then the free list */
- rec = page_header_get_ptr(page, PAGE_FREE);
-
- while (rec != NULL) {
- if (rec < page + FIL_PAGE_DATA
- || rec >= page + UNIV_PAGE_SIZE) {
- fprintf(stderr,
- "InnoDB: Free list record has"
- " a nonsensical offset %lu\n",
- (ulong) (rec - page));
-
- goto func_exit;
- }
-
- if (rec > rec_heap_top) {
- fprintf(stderr,
- "InnoDB: Free list record %lu"
- " is above rec heap top %lu\n",
- (ulong) (rec - page),
- (ulong) (rec_heap_top - page));
-
- goto func_exit;
- }
-
- count++;
-
- if (count > UNIV_PAGE_SIZE) {
- fprintf(stderr,
- "InnoDB: Page free list appears"
- " to be circular %lu\n",
- (ulong) count);
- goto func_exit;
- }
-
- rec = page_rec_get_next(rec);
- }
-
- if (page_dir_get_n_heap(page) != count + 1) {
-
- fprintf(stderr, "InnoDB: N heap is wrong %lu, %lu\n",
- (ulong) page_dir_get_n_heap(page),
- (ulong) (count + 1));
-
- goto func_exit;
- }
-
- ret = TRUE;
-
-func_exit:
- return(ret);
-}
-
-/*******************************************************************
-This function checks the consistency of an index page. */
-
-ibool
-page_validate(
-/*==========*/
- /* out: TRUE if ok */
- page_t* page, /* in: index page */
- dict_index_t* index) /* in: data dictionary index containing
- the page record type definition */
-{
- page_dir_slot_t* slot;
- mem_heap_t* heap;
- page_cur_t cur;
- byte* buf;
- ulint count;
- ulint own_count;
- ulint slot_no;
- ulint data_size;
- rec_t* rec;
- rec_t* old_rec = NULL;
- ulint offs;
- ulint n_slots;
- ibool ret = FALSE;
- ulint i;
- ulint comp = page_is_comp(page);
- ulint* offsets = NULL;
- ulint* old_offsets = NULL;
-
- if ((ibool)!!comp != dict_table_is_comp(index->table)) {
- fputs("InnoDB: 'compact format' flag mismatch\n", stderr);
- goto func_exit2;
- }
- if (!page_simple_validate(page)) {
- goto func_exit2;
- }
-
- heap = mem_heap_create(UNIV_PAGE_SIZE + 200);
-
- /* The following buffer is used to check that the
- records in the page record heap do not overlap */
-
- buf = mem_heap_alloc(heap, UNIV_PAGE_SIZE);
- memset(buf, 0, UNIV_PAGE_SIZE);
-
- /* Check first that the record heap and the directory do not
- overlap. */
-
- n_slots = page_dir_get_n_slots(page);
-
- if (!(page_header_get_ptr(page, PAGE_HEAP_TOP)
- <= page_dir_get_nth_slot(page, n_slots - 1))) {
-
- fputs("InnoDB: Record heap and dir overlap on a page ",
- stderr);
- dict_index_name_print(stderr, NULL, index);
- fprintf(stderr, ", %p, %p\n",
- page_header_get_ptr(page, PAGE_HEAP_TOP),
- page_dir_get_nth_slot(page, n_slots - 1));
-
- goto func_exit;
- }
-
- /* Validate the record list in a loop checking also that
- it is consistent with the directory. */
- count = 0;
- data_size = 0;
- own_count = 1;
- slot_no = 0;
- slot = page_dir_get_nth_slot(page, slot_no);
-
- page_cur_set_before_first(page, &cur);
-
- for (;;) {
- rec = cur.rec;
- offsets = rec_get_offsets(rec, index, offsets,
- ULINT_UNDEFINED, &heap);
-
- if (comp && page_rec_is_user_rec(rec)
- && rec_get_node_ptr_flag(rec)
- != (ibool)
- (btr_page_get_level_low(page) != 0)) {
- fputs("InnoDB: node_ptr flag mismatch\n", stderr);
- goto func_exit;
- }
-
- if (!page_rec_validate(rec, offsets)) {
- goto func_exit;
- }
-
- /* Check that the records are in the ascending order */
- if ((count >= 2) && (!page_cur_is_after_last(&cur))) {
- if (!(1 == cmp_rec_rec(rec, old_rec,
- offsets, old_offsets, index))) {
- fprintf(stderr,
- "InnoDB: Records in wrong order"
- " on page %lu ",
- (ulong) buf_frame_get_page_no(page));
- dict_index_name_print(stderr, NULL, index);
- fputs("\nInnoDB: previous record ", stderr);
- rec_print_new(stderr, old_rec, old_offsets);
- fputs("\nInnoDB: record ", stderr);
- rec_print_new(stderr, rec, offsets);
- putc('\n', stderr);
-
- goto func_exit;
- }
- }
-
- if (page_rec_is_user_rec(rec)) {
-
- data_size += rec_offs_size(offsets);
- }
-
- offs = rec_get_start(rec, offsets) - page;
-
- for (i = 0; i < rec_offs_size(offsets); i++) {
- if (!buf[offs + i] == 0) {
- /* No other record may overlap this */
-
- fputs("InnoDB: Record overlaps another\n",
- stderr);
- goto func_exit;
- }
-
- buf[offs + i] = 1;
- }
-
- if (rec_get_n_owned(rec, comp) != 0) {
- /* This is a record pointed to by a dir slot */
- if (rec_get_n_owned(rec, comp) != own_count) {
- fprintf(stderr,
- "InnoDB: Wrong owned count %lu, %lu\n",
- (ulong) rec_get_n_owned(rec, comp),
- (ulong) own_count);
- goto func_exit;
- }
-
- if (page_dir_slot_get_rec(slot) != rec) {
- fputs("InnoDB: Dir slot does not"
- " point to right rec\n",
- stderr);
- goto func_exit;
- }
-
- page_dir_slot_check(slot);
-
- own_count = 0;
- if (!page_cur_is_after_last(&cur)) {
- slot_no++;
- slot = page_dir_get_nth_slot(page, slot_no);
- }
- }
-
- if (page_cur_is_after_last(&cur)) {
- break;
- }
-
- if (rec_get_next_offs(rec, comp) < FIL_PAGE_DATA
- || rec_get_next_offs(rec, comp) >= UNIV_PAGE_SIZE) {
- fprintf(stderr,
- "InnoDB: Next record offset wrong %lu\n",
- (ulong) rec_get_next_offs(rec, comp));
- goto func_exit;
- }
-
- count++;
- page_cur_move_to_next(&cur);
- own_count++;
- old_rec = rec;
- /* set old_offsets to offsets; recycle offsets */
- {
- ulint* offs = old_offsets;
- old_offsets = offsets;
- offsets = offs;
- }
- }
-
- if (rec_get_n_owned(rec, comp) == 0) {
- fputs("InnoDB: n owned is zero\n", stderr);
- goto func_exit;
- }
-
- if (slot_no != n_slots - 1) {
- fprintf(stderr, "InnoDB: n slots wrong %lu %lu\n",
- (ulong) slot_no, (ulong) (n_slots - 1));
- goto func_exit;
- }
-
- if (page_header_get_field(page, PAGE_N_RECS) + 2 != count + 1) {
- fprintf(stderr, "InnoDB: n recs wrong %lu %lu\n",
- (ulong) page_header_get_field(page, PAGE_N_RECS) + 2,
- (ulong) (count + 1));
- goto func_exit;
- }
-
- if (data_size != page_get_data_size(page)) {
- fprintf(stderr,
- "InnoDB: Summed data size %lu, returned by func %lu\n",
- (ulong) data_size, (ulong) page_get_data_size(page));
- goto func_exit;
- }
-
- /* Check then the free list */
- rec = page_header_get_ptr(page, PAGE_FREE);
-
- while (rec != NULL) {
- offsets = rec_get_offsets(rec, index, offsets,
- ULINT_UNDEFINED, &heap);
- if (!page_rec_validate(rec, offsets)) {
-
- goto func_exit;
- }
-
- count++;
- offs = rec_get_start(rec, offsets) - page;
-
- for (i = 0; i < rec_offs_size(offsets); i++) {
-
- if (buf[offs + i] != 0) {
- fputs("InnoDB: Record overlaps another"
- " in free list\n", stderr);
- goto func_exit;
- }
-
- buf[offs + i] = 1;
- }
-
- rec = page_rec_get_next(rec);
- }
-
- if (page_dir_get_n_heap(page) != count + 1) {
- fprintf(stderr, "InnoDB: N heap is wrong %lu %lu\n",
- (ulong) page_dir_get_n_heap(page),
- (ulong) count + 1);
- goto func_exit;
- }
-
- ret = TRUE;
-
-func_exit:
- mem_heap_free(heap);
-
- if (ret == FALSE) {
-func_exit2:
- fprintf(stderr, "InnoDB: Apparent corruption in page %lu in ",
- (ulong) buf_frame_get_page_no(page));
- dict_index_name_print(stderr, NULL, index);
- putc('\n', stderr);
- buf_page_print(page);
- }
-
- return(ret);
-}
-
-/*******************************************************************
-Looks in the page record list for a record with the given heap number. */
-
-rec_t*
-page_find_rec_with_heap_no(
-/*=======================*/
- /* out: record, NULL if not found */
- page_t* page, /* in: index page */
- ulint heap_no)/* in: heap number */
-{
- page_cur_t cur;
-
- page_cur_set_before_first(page, &cur);
-
- for (;;) {
- if (rec_get_heap_no(cur.rec, page_is_comp(page)) == heap_no) {
-
- return(cur.rec);
- }
-
- if (page_cur_is_after_last(&cur)) {
-
- return(NULL);
- }
-
- page_cur_move_to_next(&cur);
- }
-}
diff --git a/storage/innobase/pars/make_bison.sh b/storage/innobase/pars/make_bison.sh
deleted file mode 100755
index c11456230c4..00000000000
--- a/storage/innobase/pars/make_bison.sh
+++ /dev/null
@@ -1,10 +0,0 @@
-#!/bin/bash
-#
-# generate parser files from bison input files.
-
-set -eu
-
-bison -d pars0grm.y
-mv pars0grm.tab.c pars0grm.c
-mv pars0grm.tab.h pars0grm.h
-cp pars0grm.h ../include
diff --git a/storage/innobase/pars/make_flex.sh b/storage/innobase/pars/make_flex.sh
deleted file mode 100755
index c015327bf8c..00000000000
--- a/storage/innobase/pars/make_flex.sh
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/bin/bash
-#
-# generate lexer files from flex input files.
-
-set -eu
-
-TMPFILE=_flex_tmp.c
-OUTFILE=lexyy.c
-
-flex -o $TMPFILE pars0lex.l
-
-# AIX needs its includes done in a certain order, so include "univ.i" first
-# to be sure we get it right.
-echo '#include "univ.i"' > $OUTFILE
-
-# flex assigns a pointer to an int in one place without a cast, resulting in
-# a warning on Win64. this adds the cast.
-sed -e 's/int offset = (yy_c_buf_p) - (yytext_ptr);/int offset = (int)((yy_c_buf_p) - (yytext_ptr));/;' < $TMPFILE >> $OUTFILE
-
-rm $TMPFILE
diff --git a/storage/innobase/pars/pars0grm.h b/storage/innobase/pars/pars0grm.h
deleted file mode 100644
index 0062b8314ee..00000000000
--- a/storage/innobase/pars/pars0grm.h
+++ /dev/null
@@ -1,234 +0,0 @@
-/* A Bison parser, made by GNU Bison 1.875d. */
-
-/* Skeleton parser for Yacc-like parsing with Bison,
- Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA. */
-
-/* As a special exception, when this file is copied by Bison into a
- Bison output file, you may use that output file without restriction.
- This special exception was added by the Free Software Foundation
- in version 1.24 of Bison. */
-
-/* Tokens. */
-#ifndef YYTOKENTYPE
-# define YYTOKENTYPE
- /* Put the tokens into the symbol table, so that GDB and other debuggers
- know about them. */
- enum yytokentype {
- PARS_INT_LIT = 258,
- PARS_FLOAT_LIT = 259,
- PARS_STR_LIT = 260,
- PARS_FIXBINARY_LIT = 261,
- PARS_BLOB_LIT = 262,
- PARS_NULL_LIT = 263,
- PARS_ID_TOKEN = 264,
- PARS_AND_TOKEN = 265,
- PARS_OR_TOKEN = 266,
- PARS_NOT_TOKEN = 267,
- PARS_GE_TOKEN = 268,
- PARS_LE_TOKEN = 269,
- PARS_NE_TOKEN = 270,
- PARS_PROCEDURE_TOKEN = 271,
- PARS_IN_TOKEN = 272,
- PARS_OUT_TOKEN = 273,
- PARS_BINARY_TOKEN = 274,
- PARS_BLOB_TOKEN = 275,
- PARS_INT_TOKEN = 276,
- PARS_INTEGER_TOKEN = 277,
- PARS_FLOAT_TOKEN = 278,
- PARS_CHAR_TOKEN = 279,
- PARS_IS_TOKEN = 280,
- PARS_BEGIN_TOKEN = 281,
- PARS_END_TOKEN = 282,
- PARS_IF_TOKEN = 283,
- PARS_THEN_TOKEN = 284,
- PARS_ELSE_TOKEN = 285,
- PARS_ELSIF_TOKEN = 286,
- PARS_LOOP_TOKEN = 287,
- PARS_WHILE_TOKEN = 288,
- PARS_RETURN_TOKEN = 289,
- PARS_SELECT_TOKEN = 290,
- PARS_SUM_TOKEN = 291,
- PARS_COUNT_TOKEN = 292,
- PARS_DISTINCT_TOKEN = 293,
- PARS_FROM_TOKEN = 294,
- PARS_WHERE_TOKEN = 295,
- PARS_FOR_TOKEN = 296,
- PARS_DDOT_TOKEN = 297,
- PARS_READ_TOKEN = 298,
- PARS_ORDER_TOKEN = 299,
- PARS_BY_TOKEN = 300,
- PARS_ASC_TOKEN = 301,
- PARS_DESC_TOKEN = 302,
- PARS_INSERT_TOKEN = 303,
- PARS_INTO_TOKEN = 304,
- PARS_VALUES_TOKEN = 305,
- PARS_UPDATE_TOKEN = 306,
- PARS_SET_TOKEN = 307,
- PARS_DELETE_TOKEN = 308,
- PARS_CURRENT_TOKEN = 309,
- PARS_OF_TOKEN = 310,
- PARS_CREATE_TOKEN = 311,
- PARS_TABLE_TOKEN = 312,
- PARS_INDEX_TOKEN = 313,
- PARS_UNIQUE_TOKEN = 314,
- PARS_CLUSTERED_TOKEN = 315,
- PARS_DOES_NOT_FIT_IN_MEM_TOKEN = 316,
- PARS_ON_TOKEN = 317,
- PARS_ASSIGN_TOKEN = 318,
- PARS_DECLARE_TOKEN = 319,
- PARS_CURSOR_TOKEN = 320,
- PARS_SQL_TOKEN = 321,
- PARS_OPEN_TOKEN = 322,
- PARS_FETCH_TOKEN = 323,
- PARS_CLOSE_TOKEN = 324,
- PARS_NOTFOUND_TOKEN = 325,
- PARS_TO_CHAR_TOKEN = 326,
- PARS_TO_NUMBER_TOKEN = 327,
- PARS_TO_BINARY_TOKEN = 328,
- PARS_BINARY_TO_NUMBER_TOKEN = 329,
- PARS_SUBSTR_TOKEN = 330,
- PARS_REPLSTR_TOKEN = 331,
- PARS_CONCAT_TOKEN = 332,
- PARS_INSTR_TOKEN = 333,
- PARS_LENGTH_TOKEN = 334,
- PARS_SYSDATE_TOKEN = 335,
- PARS_PRINTF_TOKEN = 336,
- PARS_ASSERT_TOKEN = 337,
- PARS_RND_TOKEN = 338,
- PARS_RND_STR_TOKEN = 339,
- PARS_ROW_PRINTF_TOKEN = 340,
- PARS_COMMIT_TOKEN = 341,
- PARS_ROLLBACK_TOKEN = 342,
- PARS_WORK_TOKEN = 343,
- PARS_UNSIGNED_TOKEN = 344,
- PARS_EXIT_TOKEN = 345,
- PARS_FUNCTION_TOKEN = 346,
- PARS_LOCK_TOKEN = 347,
- PARS_SHARE_TOKEN = 348,
- PARS_MODE_TOKEN = 349,
- NEG = 350
- };
-#endif
-#define PARS_INT_LIT 258
-#define PARS_FLOAT_LIT 259
-#define PARS_STR_LIT 260
-#define PARS_FIXBINARY_LIT 261
-#define PARS_BLOB_LIT 262
-#define PARS_NULL_LIT 263
-#define PARS_ID_TOKEN 264
-#define PARS_AND_TOKEN 265
-#define PARS_OR_TOKEN 266
-#define PARS_NOT_TOKEN 267
-#define PARS_GE_TOKEN 268
-#define PARS_LE_TOKEN 269
-#define PARS_NE_TOKEN 270
-#define PARS_PROCEDURE_TOKEN 271
-#define PARS_IN_TOKEN 272
-#define PARS_OUT_TOKEN 273
-#define PARS_BINARY_TOKEN 274
-#define PARS_BLOB_TOKEN 275
-#define PARS_INT_TOKEN 276
-#define PARS_INTEGER_TOKEN 277
-#define PARS_FLOAT_TOKEN 278
-#define PARS_CHAR_TOKEN 279
-#define PARS_IS_TOKEN 280
-#define PARS_BEGIN_TOKEN 281
-#define PARS_END_TOKEN 282
-#define PARS_IF_TOKEN 283
-#define PARS_THEN_TOKEN 284
-#define PARS_ELSE_TOKEN 285
-#define PARS_ELSIF_TOKEN 286
-#define PARS_LOOP_TOKEN 287
-#define PARS_WHILE_TOKEN 288
-#define PARS_RETURN_TOKEN 289
-#define PARS_SELECT_TOKEN 290
-#define PARS_SUM_TOKEN 291
-#define PARS_COUNT_TOKEN 292
-#define PARS_DISTINCT_TOKEN 293
-#define PARS_FROM_TOKEN 294
-#define PARS_WHERE_TOKEN 295
-#define PARS_FOR_TOKEN 296
-#define PARS_DDOT_TOKEN 297
-#define PARS_READ_TOKEN 298
-#define PARS_ORDER_TOKEN 299
-#define PARS_BY_TOKEN 300
-#define PARS_ASC_TOKEN 301
-#define PARS_DESC_TOKEN 302
-#define PARS_INSERT_TOKEN 303
-#define PARS_INTO_TOKEN 304
-#define PARS_VALUES_TOKEN 305
-#define PARS_UPDATE_TOKEN 306
-#define PARS_SET_TOKEN 307
-#define PARS_DELETE_TOKEN 308
-#define PARS_CURRENT_TOKEN 309
-#define PARS_OF_TOKEN 310
-#define PARS_CREATE_TOKEN 311
-#define PARS_TABLE_TOKEN 312
-#define PARS_INDEX_TOKEN 313
-#define PARS_UNIQUE_TOKEN 314
-#define PARS_CLUSTERED_TOKEN 315
-#define PARS_DOES_NOT_FIT_IN_MEM_TOKEN 316
-#define PARS_ON_TOKEN 317
-#define PARS_ASSIGN_TOKEN 318
-#define PARS_DECLARE_TOKEN 319
-#define PARS_CURSOR_TOKEN 320
-#define PARS_SQL_TOKEN 321
-#define PARS_OPEN_TOKEN 322
-#define PARS_FETCH_TOKEN 323
-#define PARS_CLOSE_TOKEN 324
-#define PARS_NOTFOUND_TOKEN 325
-#define PARS_TO_CHAR_TOKEN 326
-#define PARS_TO_NUMBER_TOKEN 327
-#define PARS_TO_BINARY_TOKEN 328
-#define PARS_BINARY_TO_NUMBER_TOKEN 329
-#define PARS_SUBSTR_TOKEN 330
-#define PARS_REPLSTR_TOKEN 331
-#define PARS_CONCAT_TOKEN 332
-#define PARS_INSTR_TOKEN 333
-#define PARS_LENGTH_TOKEN 334
-#define PARS_SYSDATE_TOKEN 335
-#define PARS_PRINTF_TOKEN 336
-#define PARS_ASSERT_TOKEN 337
-#define PARS_RND_TOKEN 338
-#define PARS_RND_STR_TOKEN 339
-#define PARS_ROW_PRINTF_TOKEN 340
-#define PARS_COMMIT_TOKEN 341
-#define PARS_ROLLBACK_TOKEN 342
-#define PARS_WORK_TOKEN 343
-#define PARS_UNSIGNED_TOKEN 344
-#define PARS_EXIT_TOKEN 345
-#define PARS_FUNCTION_TOKEN 346
-#define PARS_LOCK_TOKEN 347
-#define PARS_SHARE_TOKEN 348
-#define PARS_MODE_TOKEN 349
-#define NEG 350
-
-
-
-
-#if ! defined (YYSTYPE) && ! defined (YYSTYPE_IS_DECLARED)
-typedef int YYSTYPE;
-# define yystype YYSTYPE /* obsolescent; will be withdrawn */
-# define YYSTYPE_IS_DECLARED 1
-# define YYSTYPE_IS_TRIVIAL 1
-#endif
-
-extern YYSTYPE yylval;
-
-
-
diff --git a/storage/innobase/plug.in b/storage/innobase/plug.in
deleted file mode 100644
index f7d2abed751..00000000000
--- a/storage/innobase/plug.in
+++ /dev/null
@@ -1,44 +0,0 @@
-MYSQL_STORAGE_ENGINE(innobase, innodb, [InnoDB Storage Engine],
- [Transactional Tables using InnoDB], [max,max-no-ndb])
-MYSQL_PLUGIN_DIRECTORY(innobase, [storage/innobase])
-MYSQL_PLUGIN_STATIC(innobase, [libinnobase.a])
-MYSQL_PLUGIN_DYNAMIC(innobase, [ha_innodb.la])
-MYSQL_PLUGIN_ACTIONS(innobase, [
- AC_CHECK_LIB(rt, aio_read, [innodb_system_libs="-lrt"])
- AC_SUBST(innodb_system_libs)
- AC_CHECK_HEADERS(aio.h sched.h)
- AC_CHECK_SIZEOF(int, 4)
- AC_CHECK_SIZEOF(long, 4)
- AC_CHECK_SIZEOF(void*, 4)
- AC_CHECK_FUNCS(sched_yield)
- AC_CHECK_FUNCS(fdatasync)
- AC_CHECK_FUNCS(localtime_r)
- AC_C_BIGENDIAN
- case "$target_os" in
- lin*)
- CFLAGS="$CFLAGS -DUNIV_LINUX";;
- hpux10*)
- CFLAGS="$CFLAGS -DUNIV_MUST_NOT_INLINE -DUNIV_HPUX -DUNIV_HPUX10";;
- hp*)
- CFLAGS="$CFLAGS -DUNIV_MUST_NOT_INLINE -DUNIV_HPUX";;
- aix*)
- CFLAGS="$CFLAGS -DUNIV_AIX";;
- irix*|osf*|sysv5uw7*|openbsd*)
- CFLAGS="$CFLAGS -DUNIV_MUST_NOT_INLINE";;
- *solaris*|*SunOS*)
- CFLAGS="$CFLAGS -DUNIV_SOLARIS";;
- esac
- INNODB_DYNAMIC_CFLAGS="-DMYSQL_DYNAMIC_PLUGIN"
- case "$target_cpu" in
- x86_64)
- # The AMD64 ABI forbids absolute addresses in shared libraries
- ;;
- *86)
- # Use absolute addresses on IA-32
- INNODB_DYNAMIC_CFLAGS="$INNODB_DYNAMIC_CFLAGS -prefer-non-pic"
- ;;
- esac
- AC_SUBST(INNODB_DYNAMIC_CFLAGS)
- ])
-
-# vim: set ft=config:
diff --git a/storage/innobase/row/row0row.c b/storage/innobase/row/row0row.c
deleted file mode 100644
index 08e50817db9..00000000000
--- a/storage/innobase/row/row0row.c
+++ /dev/null
@@ -1,726 +0,0 @@
-/******************************************************
-General row routines
-
-(c) 1996 Innobase Oy
-
-Created 4/20/1996 Heikki Tuuri
-*******************************************************/
-
-#include "row0row.h"
-
-#ifdef UNIV_NONINL
-#include "row0row.ic"
-#endif
-
-#include "dict0dict.h"
-#include "btr0btr.h"
-#include "mach0data.h"
-#include "trx0rseg.h"
-#include "trx0trx.h"
-#include "trx0roll.h"
-#include "trx0undo.h"
-#include "trx0purge.h"
-#include "trx0rec.h"
-#include "que0que.h"
-#include "row0row.h"
-#include "row0upd.h"
-#include "rem0cmp.h"
-#include "read0read.h"
-
-/*************************************************************************
-Reads the trx id or roll ptr field from a clustered index record: this function
-is slower than the specialized inline functions. */
-
-dulint
-row_get_rec_sys_field(
-/*==================*/
- /* out: value of the field */
- ulint type, /* in: DATA_TRX_ID or DATA_ROLL_PTR */
- rec_t* rec, /* in: record */
- dict_index_t* index, /* in: clustered index */
- const ulint* offsets)/* in: rec_get_offsets(rec, index) */
-{
- ulint pos;
- byte* field;
- ulint len;
-
- ut_ad(index->type & DICT_CLUSTERED);
-
- pos = dict_index_get_sys_col_pos(index, type);
-
- field = rec_get_nth_field(rec, offsets, pos, &len);
-
- if (type == DATA_TRX_ID) {
-
- return(trx_read_trx_id(field));
- } else {
- ut_ad(type == DATA_ROLL_PTR);
-
- return(trx_read_roll_ptr(field));
- }
-}
-
-/*************************************************************************
-Sets the trx id or roll ptr field in a clustered index record: this function
-is slower than the specialized inline functions. */
-
-void
-row_set_rec_sys_field(
-/*==================*/
- /* out: value of the field */
- ulint type, /* in: DATA_TRX_ID or DATA_ROLL_PTR */
- rec_t* rec, /* in: record */
- dict_index_t* index, /* in: clustered index */
- const ulint* offsets,/* in: rec_get_offsets(rec, index) */
- dulint val) /* in: value to set */
-{
- ulint pos;
- byte* field;
- ulint len;
-
- ut_ad(index->type & DICT_CLUSTERED);
- ut_ad(rec_offs_validate(rec, index, offsets));
-
- pos = dict_index_get_sys_col_pos(index, type);
-
- field = rec_get_nth_field(rec, offsets, pos, &len);
-
- if (type == DATA_TRX_ID) {
-
- trx_write_trx_id(field, val);
- } else {
- ut_ad(type == DATA_ROLL_PTR);
-
- trx_write_roll_ptr(field, val);
- }
-}
-
-/*********************************************************************
-When an insert to a table is performed, this function builds the entry which
-has to be inserted to an index on the table. */
-
-dtuple_t*
-row_build_index_entry(
-/*==================*/
- /* out: index entry which should be inserted */
- dtuple_t* row, /* in: row which should be inserted to the
- table */
- dict_index_t* index, /* in: index on the table */
- mem_heap_t* heap) /* in: memory heap from which the memory for
- the index entry is allocated */
-{
- dtuple_t* entry;
- ulint entry_len;
- dict_field_t* ind_field;
- dfield_t* dfield;
- dfield_t* dfield2;
- ulint i;
- ulint storage_len;
-
- ut_ad(row && index && heap);
- ut_ad(dtuple_check_typed(row));
-
- entry_len = dict_index_get_n_fields(index);
- entry = dtuple_create(heap, entry_len);
-
- if (index->type & DICT_UNIVERSAL) {
- dtuple_set_n_fields_cmp(entry, entry_len);
- } else {
- dtuple_set_n_fields_cmp(
- entry, dict_index_get_n_unique_in_tree(index));
- }
-
- for (i = 0; i < entry_len; i++) {
- const dict_col_t* col;
- ind_field = dict_index_get_nth_field(index, i);
- col = ind_field->col;
-
- dfield = dtuple_get_nth_field(entry, i);
-
- dfield2 = dtuple_get_nth_field(row, dict_col_get_no(col));
-
- dfield_copy(dfield, dfield2);
-
- /* If a column prefix index, take only the prefix */
- if (ind_field->prefix_len > 0
- && dfield_get_len(dfield2) != UNIV_SQL_NULL) {
-
- storage_len = dtype_get_at_most_n_mbchars(
- col->prtype, col->mbminlen, col->mbmaxlen,
- ind_field->prefix_len,
- dfield_get_len(dfield2), dfield2->data);
-
- dfield_set_len(dfield, storage_len);
- }
- }
-
- ut_ad(dtuple_check_typed(entry));
-
- return(entry);
-}
-
-/***********************************************************************
-An inverse function to dict_row_build_index_entry. Builds a row from a
-record in a clustered index. */
-
-dtuple_t*
-row_build(
-/*======*/
- /* out, own: row built; see the NOTE below! */
- ulint type, /* in: ROW_COPY_POINTERS or ROW_COPY_DATA;
- the latter copies also the data fields to
- heap while the first only places pointers to
- data fields on the index page, and thus is
- more efficient */
- dict_index_t* index, /* in: clustered index */
- rec_t* rec, /* in: record in the clustered index;
- NOTE: in the case ROW_COPY_POINTERS
- the data fields in the row will point
- directly into this record, therefore,
- the buffer page of this record must be
- at least s-latched and the latch held
- as long as the row dtuple is used! */
- const ulint* offsets,/* in: rec_get_offsets(rec, index)
- or NULL, in which case this function
- will invoke rec_get_offsets() */
- mem_heap_t* heap) /* in: memory heap from which the memory
- needed is allocated */
-{
- dtuple_t* row;
- dict_table_t* table;
- dict_field_t* ind_field;
- dfield_t* dfield;
- ulint n_fields;
- byte* field;
- ulint len;
- ulint row_len;
- byte* buf;
- ulint i;
- mem_heap_t* tmp_heap = NULL;
- ulint offsets_[REC_OFFS_NORMAL_SIZE];
- *offsets_ = (sizeof offsets_) / sizeof *offsets_;
-
- ut_ad(index && rec && heap);
- ut_ad(index->type & DICT_CLUSTERED);
-
- if (!offsets) {
- offsets = rec_get_offsets(rec, index, offsets_,
- ULINT_UNDEFINED, &tmp_heap);
- } else {
- ut_ad(rec_offs_validate(rec, index, offsets));
- }
-
- if (type != ROW_COPY_POINTERS) {
- /* Take a copy of rec to heap */
- buf = mem_heap_alloc(heap, rec_offs_size(offsets));
- rec = rec_copy(buf, rec, offsets);
- /* Avoid a debug assertion in rec_offs_validate(). */
- rec_offs_make_valid(rec, index, (ulint*) offsets);
- }
-
- table = index->table;
- row_len = dict_table_get_n_cols(table);
-
- row = dtuple_create(heap, row_len);
-
- dtuple_set_info_bits(row, rec_get_info_bits(
- rec, dict_table_is_comp(table)));
-
- n_fields = rec_offs_n_fields(offsets);
-
- dict_table_copy_types(row, table);
-
- for (i = 0; i < n_fields; i++) {
- ind_field = dict_index_get_nth_field(index, i);
-
- if (ind_field->prefix_len == 0) {
-
- const dict_col_t* col
- = dict_field_get_col(ind_field);
-
- dfield = dtuple_get_nth_field(row,
- dict_col_get_no(col));
- field = rec_get_nth_field(rec, offsets, i, &len);
-
- dfield_set_data(dfield, field, len);
- }
- }
-
- ut_ad(dtuple_check_typed(row));
-
- if (tmp_heap) {
- mem_heap_free(tmp_heap);
- }
-
- return(row);
-}
-
-/***********************************************************************
-Converts an index record to a typed data tuple. NOTE that externally
-stored (often big) fields are NOT copied to heap. */
-
-dtuple_t*
-row_rec_to_index_entry(
-/*===================*/
- /* out, own: index entry built; see the
- NOTE below! */
- ulint type, /* in: ROW_COPY_DATA, or ROW_COPY_POINTERS:
- the former copies also the data fields to
- heap as the latter only places pointers to
- data fields on the index page */
- dict_index_t* index, /* in: index */
- rec_t* rec, /* in: record in the index;
- NOTE: in the case ROW_COPY_POINTERS
- the data fields in the row will point
- directly into this record, therefore,
- the buffer page of this record must be
- at least s-latched and the latch held
- as long as the dtuple is used! */
- mem_heap_t* heap) /* in: memory heap from which the memory
- needed is allocated */
-{
- dtuple_t* entry;
- dfield_t* dfield;
- ulint i;
- byte* field;
- ulint len;
- ulint rec_len;
- byte* buf;
- mem_heap_t* tmp_heap = NULL;
- ulint offsets_[REC_OFFS_NORMAL_SIZE];
- ulint* offsets = offsets_;
- *offsets_ = (sizeof offsets_) / sizeof *offsets_;
-
- ut_ad(rec && heap && index);
-
- offsets = rec_get_offsets(rec, index, offsets,
- ULINT_UNDEFINED, &tmp_heap);
-
- if (type == ROW_COPY_DATA) {
- /* Take a copy of rec to heap */
- buf = mem_heap_alloc(heap, rec_offs_size(offsets));
- rec = rec_copy(buf, rec, offsets);
- /* Avoid a debug assertion in rec_offs_validate(). */
- rec_offs_make_valid(rec, index, offsets);
- }
-
- rec_len = rec_offs_n_fields(offsets);
-
- entry = dtuple_create(heap, rec_len);
-
- dtuple_set_n_fields_cmp(entry,
- dict_index_get_n_unique_in_tree(index));
- ut_ad(rec_len == dict_index_get_n_fields(index));
-
- dict_index_copy_types(entry, index, rec_len);
-
- dtuple_set_info_bits(entry,
- rec_get_info_bits(rec, rec_offs_comp(offsets)));
-
- for (i = 0; i < rec_len; i++) {
-
- dfield = dtuple_get_nth_field(entry, i);
- field = rec_get_nth_field(rec, offsets, i, &len);
-
- dfield_set_data(dfield, field, len);
- }
-
- ut_ad(dtuple_check_typed(entry));
- if (tmp_heap) {
- mem_heap_free(tmp_heap);
- }
-
- return(entry);
-}
-
-/***********************************************************************
-Builds from a secondary index record a row reference with which we can
-search the clustered index record. */
-
-dtuple_t*
-row_build_row_ref(
-/*==============*/
- /* out, own: row reference built; see the
- NOTE below! */
- ulint type, /* in: ROW_COPY_DATA, or ROW_COPY_POINTERS:
- the former copies also the data fields to
- heap, whereas the latter only places pointers
- to data fields on the index page */
- dict_index_t* index, /* in: index */
- rec_t* rec, /* in: record in the index;
- NOTE: in the case ROW_COPY_POINTERS
- the data fields in the row will point
- directly into this record, therefore,
- the buffer page of this record must be
- at least s-latched and the latch held
- as long as the row reference is used! */
- mem_heap_t* heap) /* in: memory heap from which the memory
- needed is allocated */
-{
- dict_table_t* table;
- dict_index_t* clust_index;
- dfield_t* dfield;
- dtuple_t* ref;
- byte* field;
- ulint len;
- ulint ref_len;
- ulint pos;
- byte* buf;
- ulint clust_col_prefix_len;
- ulint i;
- mem_heap_t* tmp_heap = NULL;
- ulint offsets_[REC_OFFS_NORMAL_SIZE];
- ulint* offsets = offsets_;
- *offsets_ = (sizeof offsets_) / sizeof *offsets_;
-
- ut_ad(index && rec && heap);
-
- offsets = rec_get_offsets(rec, index, offsets,
- ULINT_UNDEFINED, &tmp_heap);
-
- if (type == ROW_COPY_DATA) {
- /* Take a copy of rec to heap */
-
- buf = mem_heap_alloc(heap, rec_offs_size(offsets));
-
- rec = rec_copy(buf, rec, offsets);
- /* Avoid a debug assertion in rec_offs_validate(). */
- rec_offs_make_valid(rec, index, offsets);
- }
-
- table = index->table;
-
- clust_index = dict_table_get_first_index(table);
-
- ref_len = dict_index_get_n_unique(clust_index);
-
- ref = dtuple_create(heap, ref_len);
-
- dict_index_copy_types(ref, clust_index, ref_len);
-
- for (i = 0; i < ref_len; i++) {
- dfield = dtuple_get_nth_field(ref, i);
-
- pos = dict_index_get_nth_field_pos(index, clust_index, i);
-
- ut_a(pos != ULINT_UNDEFINED);
-
- field = rec_get_nth_field(rec, offsets, pos, &len);
-
- dfield_set_data(dfield, field, len);
-
- /* If the primary key contains a column prefix, then the
- secondary index may contain a longer prefix of the same
- column, or the full column, and we must adjust the length
- accordingly. */
-
- clust_col_prefix_len = dict_index_get_nth_field(
- clust_index, i)->prefix_len;
-
- if (clust_col_prefix_len > 0) {
- if (len != UNIV_SQL_NULL) {
-
- const dtype_t* dtype
- = dfield_get_type(dfield);
-
- dfield_set_len(dfield,
- dtype_get_at_most_n_mbchars(
- dtype->prtype,
- dtype->mbminlen,
- dtype->mbmaxlen,
- clust_col_prefix_len,
- len, (char*) field));
- }
- }
- }
-
- ut_ad(dtuple_check_typed(ref));
- if (tmp_heap) {
- mem_heap_free(tmp_heap);
- }
-
- return(ref);
-}
-
-/***********************************************************************
-Builds from a secondary index record a row reference with which we can
-search the clustered index record. */
-
-void
-row_build_row_ref_in_tuple(
-/*=======================*/
- dtuple_t* ref, /* in/out: row reference built; see the
- NOTE below! */
- dict_index_t* index, /* in: index */
- rec_t* rec, /* in: record in the index;
- NOTE: the data fields in ref will point
- directly into this record, therefore,
- the buffer page of this record must be
- at least s-latched and the latch held
- as long as the row reference is used! */
- trx_t* trx) /* in: transaction */
-{
- dict_index_t* clust_index;
- dfield_t* dfield;
- byte* field;
- ulint len;
- ulint ref_len;
- ulint pos;
- ulint clust_col_prefix_len;
- ulint i;
- mem_heap_t* heap = NULL;
- ulint offsets_[REC_OFFS_NORMAL_SIZE];
- ulint* offsets = offsets_;
- *offsets_ = (sizeof offsets_) / sizeof *offsets_;
-
- ut_a(ref);
- ut_a(index);
- ut_a(rec);
-
- if (UNIV_UNLIKELY(!index->table)) {
- fputs("InnoDB: table ", stderr);
-notfound:
- ut_print_name(stderr, trx, TRUE, index->table_name);
- fputs(" for index ", stderr);
- ut_print_name(stderr, trx, FALSE, index->name);
- fputs(" not found\n", stderr);
- ut_error;
- }
-
- clust_index = dict_table_get_first_index(index->table);
-
- if (!clust_index) {
- fputs("InnoDB: clust index for table ", stderr);
- goto notfound;
- }
-
- offsets = rec_get_offsets(rec, index, offsets, ULINT_UNDEFINED, &heap);
-
- ref_len = dict_index_get_n_unique(clust_index);
-
- ut_ad(ref_len == dtuple_get_n_fields(ref));
-
- dict_index_copy_types(ref, clust_index, ref_len);
-
- for (i = 0; i < ref_len; i++) {
- dfield = dtuple_get_nth_field(ref, i);
-
- pos = dict_index_get_nth_field_pos(index, clust_index, i);
-
- ut_a(pos != ULINT_UNDEFINED);
-
- field = rec_get_nth_field(rec, offsets, pos, &len);
-
- dfield_set_data(dfield, field, len);
-
- /* If the primary key contains a column prefix, then the
- secondary index may contain a longer prefix of the same
- column, or the full column, and we must adjust the length
- accordingly. */
-
- clust_col_prefix_len = dict_index_get_nth_field(
- clust_index, i)->prefix_len;
-
- if (clust_col_prefix_len > 0) {
- if (len != UNIV_SQL_NULL) {
-
- const dtype_t* dtype
- = dfield_get_type(dfield);
-
- dfield_set_len(dfield,
- dtype_get_at_most_n_mbchars(
- dtype->prtype,
- dtype->mbminlen,
- dtype->mbmaxlen,
- clust_col_prefix_len,
- len, (char*) field));
- }
- }
- }
-
- ut_ad(dtuple_check_typed(ref));
- if (UNIV_LIKELY_NULL(heap)) {
- mem_heap_free(heap);
- }
-}
-
-/***********************************************************************
-From a row build a row reference with which we can search the clustered
-index record. */
-
-void
-row_build_row_ref_from_row(
-/*=======================*/
- dtuple_t* ref, /* in/out: row reference built; see the
- NOTE below! ref must have the right number
- of fields! */
- dict_table_t* table, /* in: table */
- dtuple_t* row) /* in: row
- NOTE: the data fields in ref will point
- directly into data of this row */
-{
- dict_index_t* clust_index;
- ulint ref_len;
- ulint i;
-
- ut_ad(ref && table && row);
-
- clust_index = dict_table_get_first_index(table);
-
- ref_len = dict_index_get_n_unique(clust_index);
-
- ut_ad(ref_len == dtuple_get_n_fields(ref));
-
- for (i = 0; i < ref_len; i++) {
- const dict_col_t* col;
- dict_field_t* field;
- dfield_t* dfield;
- dfield_t* dfield2;
-
- dfield = dtuple_get_nth_field(ref, i);
-
- field = dict_index_get_nth_field(clust_index, i);
-
- col = dict_field_get_col(field);
-
- dfield2 = dtuple_get_nth_field(row, dict_col_get_no(col));
-
- dfield_copy(dfield, dfield2);
-
- if (field->prefix_len > 0
- && dfield->len != UNIV_SQL_NULL) {
-
- dfield->len = dtype_get_at_most_n_mbchars(
- col->prtype, col->mbminlen, col->mbmaxlen,
- field->prefix_len, dfield->len, dfield->data);
- }
- }
-
- ut_ad(dtuple_check_typed(ref));
-}
-
-/*******************************************************************
-Searches the clustered index record for a row, if we have the row reference. */
-
-ibool
-row_search_on_row_ref(
-/*==================*/
- /* out: TRUE if found */
- btr_pcur_t* pcur, /* in/out: persistent cursor, which must
- be closed by the caller */
- ulint mode, /* in: BTR_MODIFY_LEAF, ... */
- dict_table_t* table, /* in: table */
- dtuple_t* ref, /* in: row reference */
- mtr_t* mtr) /* in: mtr */
-{
- ulint low_match;
- rec_t* rec;
- dict_index_t* index;
-
- ut_ad(dtuple_check_typed(ref));
-
- index = dict_table_get_first_index(table);
-
- ut_a(dtuple_get_n_fields(ref) == dict_index_get_n_unique(index));
-
- btr_pcur_open(index, ref, PAGE_CUR_LE, mode, pcur, mtr);
-
- low_match = btr_pcur_get_low_match(pcur);
-
- rec = btr_pcur_get_rec(pcur);
-
- if (page_rec_is_infimum(rec)) {
-
- return(FALSE);
- }
-
- if (low_match != dtuple_get_n_fields(ref)) {
-
- return(FALSE);
- }
-
- return(TRUE);
-}
-
-/*************************************************************************
-Fetches the clustered index record for a secondary index record. The latches
-on the secondary index record are preserved. */
-
-rec_t*
-row_get_clust_rec(
-/*==============*/
- /* out: record or NULL, if no record found */
- ulint mode, /* in: BTR_MODIFY_LEAF, ... */
- rec_t* rec, /* in: record in a secondary index */
- dict_index_t* index, /* in: secondary index */
- dict_index_t** clust_index,/* out: clustered index */
- mtr_t* mtr) /* in: mtr */
-{
- mem_heap_t* heap;
- dtuple_t* ref;
- dict_table_t* table;
- btr_pcur_t pcur;
- ibool found;
- rec_t* clust_rec;
-
- ut_ad((index->type & DICT_CLUSTERED) == 0);
-
- table = index->table;
-
- heap = mem_heap_create(256);
-
- ref = row_build_row_ref(ROW_COPY_POINTERS, index, rec, heap);
-
- found = row_search_on_row_ref(&pcur, mode, table, ref, mtr);
-
- clust_rec = found ? btr_pcur_get_rec(&pcur) : NULL;
-
- mem_heap_free(heap);
-
- btr_pcur_close(&pcur);
-
- *clust_index = dict_table_get_first_index(table);
-
- return(clust_rec);
-}
-
-/*******************************************************************
-Searches an index record. */
-
-ibool
-row_search_index_entry(
-/*===================*/
- /* out: TRUE if found */
- dict_index_t* index, /* in: index */
- dtuple_t* entry, /* in: index entry */
- ulint mode, /* in: BTR_MODIFY_LEAF, ... */
- btr_pcur_t* pcur, /* in/out: persistent cursor, which must
- be closed by the caller */
- mtr_t* mtr) /* in: mtr */
-{
- ulint n_fields;
- ulint low_match;
- rec_t* rec;
-
- ut_ad(dtuple_check_typed(entry));
-
- btr_pcur_open(index, entry, PAGE_CUR_LE, mode, pcur, mtr);
- low_match = btr_pcur_get_low_match(pcur);
-
- rec = btr_pcur_get_rec(pcur);
-
- n_fields = dtuple_get_n_fields(entry);
-
- if (page_rec_is_infimum(rec)) {
-
- return(FALSE);
- }
-
- if (low_match != n_fields) {
- /* Not found */
-
- return(FALSE);
- }
-
- return(TRUE);
-}
diff --git a/storage/innobase/srv/srv0que.c b/storage/innobase/srv/srv0que.c
deleted file mode 100644
index e2b4e217980..00000000000
--- a/storage/innobase/srv/srv0que.c
+++ /dev/null
@@ -1,110 +0,0 @@
-/******************************************************
-Server query execution
-
-(c) 1996 Innobase Oy
-
-Created 6/5/1996 Heikki Tuuri
-*******************************************************/
-
-#include "srv0que.h"
-
-#include "srv0srv.h"
-#include "sync0sync.h"
-#include "os0thread.h"
-#include "usr0sess.h"
-#include "que0que.h"
-
-/**************************************************************************
-Checks if there is work to do in the server task queue. If there is, the
-thread starts processing a task. Before leaving, it again checks the task
-queue and picks a new task if any exists. This is called by a SRV_WORKER
-thread. */
-
-void
-srv_que_task_queue_check(void)
-/*==========================*/
-{
- que_thr_t* thr;
-
- for (;;) {
- mutex_enter(&kernel_mutex);
-
- thr = UT_LIST_GET_FIRST(srv_sys->tasks);
-
- if (thr == NULL) {
- mutex_exit(&kernel_mutex);
-
- return;
- }
-
- UT_LIST_REMOVE(queue, srv_sys->tasks, thr);
-
- mutex_exit(&kernel_mutex);
-
- que_run_threads(thr);
- }
-}
-
-/**************************************************************************
-Performs round-robin on the server tasks. This is called by a SRV_WORKER
-thread every second or so. */
-
-que_thr_t*
-srv_que_round_robin(
-/*================*/
- /* out: the new (may be == thr) query thread
- to run */
- que_thr_t* thr) /* in: query thread */
-{
- que_thr_t* new_thr;
-
- ut_ad(thr);
- ut_ad(thr->state == QUE_THR_RUNNING);
-
- mutex_enter(&kernel_mutex);
-
- UT_LIST_ADD_LAST(queue, srv_sys->tasks, thr);
-
- new_thr = UT_LIST_GET_FIRST(srv_sys->tasks);
-
- mutex_exit(&kernel_mutex);
-
- return(new_thr);
-}
-
-/**************************************************************************
-Enqueues a task to server task queue and releases a worker thread, if there
-is a suspended one. */
-
-void
-srv_que_task_enqueue_low(
-/*=====================*/
- que_thr_t* thr) /* in: query thread */
-{
- ut_ad(thr);
- ut_ad(mutex_own(&kernel_mutex));
-
- UT_LIST_ADD_LAST(queue, srv_sys->tasks, thr);
-
- srv_release_threads(SRV_WORKER, 1);
-}
-
-/**************************************************************************
-Enqueues a task to server task queue and releases a worker thread, if there
-is a suspended one. */
-
-void
-srv_que_task_enqueue(
-/*=================*/
- que_thr_t* thr) /* in: query thread */
-{
- ut_ad(thr);
-
- ut_a(0); /* Under MySQL this is never called */
-
- mutex_enter(&kernel_mutex);
-
- srv_que_task_enqueue_low(thr);
-
- mutex_exit(&kernel_mutex);
-}
diff --git a/storage/innobase/usr/usr0sess.c b/storage/innobase/usr/usr0sess.c
deleted file mode 100644
index 3740c05eaab..00000000000
--- a/storage/innobase/usr/usr0sess.c
+++ /dev/null
@@ -1,81 +0,0 @@
-/******************************************************
-Sessions
-
-(c) 1996 Innobase Oy
-
-Created 6/25/1996 Heikki Tuuri
-*******************************************************/
-
-#include "usr0sess.h"
-
-#ifdef UNIV_NONINL
-#include "usr0sess.ic"
-#endif
-
-#include "trx0trx.h"
-
-/*************************************************************************
-Closes a session, freeing the memory occupied by it. */
-static
-void
-sess_close(
-/*=======*/
- sess_t* sess); /* in, own: session object */
-
-/*************************************************************************
-Opens a session. */
-
-sess_t*
-sess_open(void)
-/*===========*/
- /* out, own: session object */
-{
- sess_t* sess;
-
- ut_ad(mutex_own(&kernel_mutex));
-
- sess = mem_alloc(sizeof(sess_t));
-
- sess->state = SESS_ACTIVE;
-
- sess->trx = trx_create(sess);
-
- UT_LIST_INIT(sess->graphs);
-
- return(sess);
-}
-
-/*************************************************************************
-Closes a session, freeing the memory occupied by it. */
-static
-void
-sess_close(
-/*=======*/
- sess_t* sess) /* in, own: session object */
-{
- ut_ad(mutex_own(&kernel_mutex));
- ut_ad(sess->trx == NULL);
-
- mem_free(sess);
-}
-
-/*************************************************************************
-Closes a session, freeing the memory occupied by it, if it is in a state
-where it should be closed. */
-
-ibool
-sess_try_close(
-/*===========*/
- /* out: TRUE if closed */
- sess_t* sess) /* in, own: session object */
-{
- ut_ad(mutex_own(&kernel_mutex));
-
- if (UT_LIST_GET_LEN(sess->graphs) == 0) {
- sess_close(sess);
-
- return(TRUE);
- }
-
- return(FALSE);
-}
diff --git a/storage/innobase/ut/ut0byte.c b/storage/innobase/ut/ut0byte.c
deleted file mode 100644
index b5467fde601..00000000000
--- a/storage/innobase/ut/ut0byte.c
+++ /dev/null
@@ -1,31 +0,0 @@
-/*******************************************************************
-Byte utilities
-
-(c) 1994, 1995 Innobase Oy
-
-Created 5/11/1994 Heikki Tuuri
-********************************************************************/
-
-#include "ut0byte.h"
-
-#ifdef UNIV_NONINL
-#include "ut0byte.ic"
-#endif
-
-#include "ut0sort.h"
-
-/* Zero value for a dulint */
-dulint ut_dulint_zero = {0, 0};
-
-/* Maximum value for a dulint */
-dulint ut_dulint_max = {0xFFFFFFFFUL, 0xFFFFFFFFUL};
-
-/****************************************************************
-Sort function for dulint arrays. */
-void
-ut_dulint_sort(dulint* arr, dulint* aux_arr, ulint low, ulint high)
-/*===============================================================*/
-{
- UT_SORT_FUNCTION_BODY(ut_dulint_sort, arr, aux_arr, low, high,
- ut_dulint_cmp);
-}
diff --git a/storage/innobase/ut/ut0dbg.c b/storage/innobase/ut/ut0dbg.c
deleted file mode 100644
index 8c4be190d77..00000000000
--- a/storage/innobase/ut/ut0dbg.c
+++ /dev/null
@@ -1,98 +0,0 @@
-/*********************************************************************
-Debug utilities for Innobase.
-
-(c) 1994, 1995 Innobase Oy
-
-Created 1/30/1994 Heikki Tuuri
-**********************************************************************/
-
-#include "univ.i"
-
-#if defined(__GNUC__) && (__GNUC__ > 2)
-#else
-/* This is used to eliminate compiler warnings */
-ulint ut_dbg_zero = 0;
-#endif
-
-#if defined(UNIV_SYNC_DEBUG) || !defined(UT_DBG_USE_ABORT)
-/* If this is set to TRUE all threads will stop into the next assertion
-and assert */
-ibool ut_dbg_stop_threads = FALSE;
-#endif
-#ifdef __NETWARE__
-ibool panic_shutdown = FALSE; /* This is set to TRUE when on NetWare there
- happens an InnoDB assertion failure or other
- fatal error condition that requires an
- immediate shutdown. */
-#elif !defined(UT_DBG_USE_ABORT)
-/* Null pointer used to generate memory trap */
-
-ulint* ut_dbg_null_ptr = NULL;
-#endif
-
-/*****************************************************************
-Report a failed assertion. */
-
-void
-ut_dbg_assertion_failed(
-/*====================*/
- const char* expr, /* in: the failed assertion (optional) */
- const char* file, /* in: source file containing the assertion */
- ulint line) /* in: line number of the assertion */
-{
- ut_print_timestamp(stderr);
- fprintf(stderr,
- " InnoDB: Assertion failure in thread %lu"
- " in file %s line %lu\n",
- os_thread_pf(os_thread_get_curr_id()), file, line);
- if (expr) {
- fprintf(stderr,
- "InnoDB: Failing assertion: %s\n", expr);
- }
-
- fputs("InnoDB: We intentionally generate a memory trap.\n"
- "InnoDB: Submit a detailed bug report"
- " to http://bugs.mysql.com.\n"
- "InnoDB: If you get repeated assertion failures"
- " or crashes, even\n"
- "InnoDB: immediately after the mysqld startup, there may be\n"
- "InnoDB: corruption in the InnoDB tablespace. Please refer to\n"
- "InnoDB: http://dev.mysql.com/doc/refman/5.1/en/"
- "forcing-recovery.html\n"
- "InnoDB: about forcing recovery.\n", stderr);
-#if defined(UNIV_SYNC_DEBUG) || !defined(UT_DBG_USE_ABORT)
- ut_dbg_stop_threads = TRUE;
-#endif
-}
-
-#ifdef __NETWARE__
-/*****************************************************************
-Shut down MySQL/InnoDB after assertion failure. */
-
-void
-ut_dbg_panic(void)
-/*==============*/
-{
- if (!panic_shutdown) {
- panic_shutdown = TRUE;
- innobase_shutdown_for_mysql();
- }
- exit(1);
-}
-#else /* __NETWARE__ */
-# if defined(UNIV_SYNC_DEBUG) || !defined(UT_DBG_USE_ABORT)
-/*****************************************************************
-Stop a thread after assertion failure. */
-
-void
-ut_dbg_stop_thread(
-/*===============*/
- const char* file,
- ulint line)
-{
- fprintf(stderr, "InnoDB: Thread %lu stopped in file %s line %lu\n",
- os_thread_pf(os_thread_get_curr_id()), file, line);
- os_thread_sleep(1000000000);
-}
-# endif
-#endif /* __NETWARE__ */
diff --git a/storage/innobase/ut/ut0vec.c b/storage/innobase/ut/ut0vec.c
deleted file mode 100644
index e0d3e84d4a2..00000000000
--- a/storage/innobase/ut/ut0vec.c
+++ /dev/null
@@ -1,54 +0,0 @@
-#include "ut0vec.h"
-#ifdef UNIV_NONINL
-#include "ut0vec.ic"
-#endif
-#include
-
-/********************************************************************
-Create a new vector with the given initial size. */
-
-ib_vector_t*
-ib_vector_create(
-/*=============*/
- /* out: vector */
- mem_heap_t* heap, /* in: heap */
- ulint size) /* in: initial size */
-{
- ib_vector_t* vec;
-
- ut_a(size > 0);
-
- vec = mem_heap_alloc(heap, sizeof(*vec));
-
- vec->heap = heap;
- vec->data = mem_heap_alloc(heap, sizeof(void*) * size);
- vec->used = 0;
- vec->total = size;
-
- return(vec);
-}
-
-/********************************************************************
-Push a new element to the vector, increasing its size if necessary. */
-
-void
-ib_vector_push(
-/*===========*/
- ib_vector_t* vec, /* in: vector */
- void* elem) /* in: data element */
-{
- if (vec->used >= vec->total) {
- void** new_data;
- ulint new_total = vec->total * 2;
-
- new_data = mem_heap_alloc(vec->heap,
- sizeof(void*) * new_total);
- memcpy(new_data, vec->data, sizeof(void*) * vec->total);
-
- vec->data = new_data;
- vec->total = new_total;
- }
-
- vec->data[vec->used] = elem;
- vec->used++;
-}
diff --git a/storage/innobase/ut/ut0wqueue.c b/storage/innobase/ut/ut0wqueue.c
deleted file mode 100644
index 7e090e89a4f..00000000000
--- a/storage/innobase/ut/ut0wqueue.c
+++ /dev/null
@@ -1,92 +0,0 @@
-#include "ut0wqueue.h"
-
-/********************************************************************
-Create a new work queue. */
-
-ib_wqueue_t*
-ib_wqueue_create(void)
-/*===================*/
- /* out: work queue */
-{
- ib_wqueue_t* wq = mem_alloc(sizeof(ib_wqueue_t));
-
- mutex_create(&wq->mutex, SYNC_WORK_QUEUE);
-
- wq->items = ib_list_create();
- wq->event = os_event_create(NULL);
-
- return(wq);
-}
-
-/********************************************************************
-Free a work queue. */
-
-void
-ib_wqueue_free(
-/*===========*/
- ib_wqueue_t* wq) /* in: work queue */
-{
- ut_a(!ib_list_get_first(wq->items));
-
- mutex_free(&wq->mutex);
- ib_list_free(wq->items);
- os_event_free(wq->event);
-
- mem_free(wq);
-}
-
-/********************************************************************
-Add a work item to the queue. */
-
-void
-ib_wqueue_add(
-/*==========*/
- ib_wqueue_t* wq, /* in: work queue */
- void* item, /* in: work item */
- mem_heap_t* heap) /* in: memory heap to use for allocating the
- list node */
-{
- mutex_enter(&wq->mutex);
-
- ib_list_add_last(wq->items, item, heap);
- os_event_set(wq->event);
-
- mutex_exit(&wq->mutex);
-}
-
-/********************************************************************
-Wait for a work item to appear in the queue. */
-
-void*
-ib_wqueue_wait(
- /* out: work item */
- ib_wqueue_t* wq) /* in: work queue */
-{
- ib_list_node_t* node;
-
- for (;;) {
- os_event_wait(wq->event);
-
- mutex_enter(&wq->mutex);
-
- node = ib_list_get_first(wq->items);
-
- if (node) {
- ib_list_remove(wq->items, node);
-
- if (!ib_list_get_first(wq->items)) {
- /* We must reset the event when the list
- gets emptied. */
- os_event_reset(wq->event);
- }
-
- break;
- }
-
- mutex_exit(&wq->mutex);
- }
-
- mutex_exit(&wq->mutex);
-
- return(node->data);
-}
diff --git a/storage/innobase/win_atomics32_test.c b/storage/innobase/win_atomics32_test.c
deleted file mode 100644
index fcb88d6b54e..00000000000
--- a/storage/innobase/win_atomics32_test.c
+++ /dev/null
@@ -1,30 +0,0 @@
-/* Copyright (C) 2009 Sun Microsystems AB
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; version 2 of the License.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
-
-#include
-
-int main()
-{
- volatile long var32 = 0;
- long add32 = 1;
- long old32 = 0;
- long exch32 = 1;
- long ret_value;
-
- ret_value = InterlockedExchangeAdd(&var32, add32);
- ret_value = InterlockedCompareExchange(&var32, exch32, old32);
- MemoryBarrier();
- return EXIT_SUCCESS;
-}
diff --git a/storage/innobase/win_atomics64_test.c b/storage/innobase/win_atomics64_test.c
deleted file mode 100644
index 123cb6d98cf..00000000000
--- a/storage/innobase/win_atomics64_test.c
+++ /dev/null
@@ -1,30 +0,0 @@
-/* Copyright (C) 2009 Sun Microsystems AB
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; version 2 of the License.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
-
-#include
-
-int main()
-{
- volatile long long var64 = 0;
- long long add64 = 1;
- long long old64 = 0;
- long long exch64 = 1;
- long long ret_value;
-
- ret_value = InterlockedExchangeAdd64(&var64, add64);
- ret_value = InterlockedCompareExchange64(&var64, exch64, old64);
- MemoryBarrier();
- return EXIT_SUCCESS;
-}
diff --git a/storage/innodb_plugin/CMakeLists.txt b/storage/innodb_plugin/CMakeLists.txt
new file mode 100644
index 00000000000..7762ece9bcd
--- /dev/null
+++ b/storage/innodb_plugin/CMakeLists.txt
@@ -0,0 +1,78 @@
+# Copyright (C) 2009 Oracle/Innobase Oy
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+# This is the CMakeLists for InnoDB Plugin
+
+
+SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX")
+SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX")
+INCLUDE("${PROJECT_SOURCE_DIR}/storage/mysql_storage_engine.cmake")
+IF (CMAKE_SIZEOF_VOID_P MATCHES 8)
+ SET(WIN64 TRUE)
+ENDIF (CMAKE_SIZEOF_VOID_P MATCHES 8)
+
+# Include directories under innodb_plugin
+INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/storage/innodb_plugin/include
+ ${CMAKE_SOURCE_DIR}/storage/innodfb_plugin/handler)
+
+# Include directories under mysql
+INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include
+ ${CMAKE_SOURCE_DIR}/sql
+ ${CMAKE_SOURCE_DIR}/regex
+ ${CMAKE_SOURCE_DIR}/zlib
+ ${CMAKE_SOURCE_DIR}/extra/yassl/include)
+
+# Removing compiler optimizations for innodb/mem/* files on 64-bit Windows
+# due to 64-bit compiler error, See MySQL Bug #19424, #36366, #34297
+IF(MSVC AND $(WIN64))
+ SET_SOURCE_FILES_PROPERTIES(mem/mem0mem.c mem/mem0pool.c
+ PROPERTIES COMPILE_FLAGS -Od)
+ENDIF(MSVC AND $(WIN64))
+
+SET(INNODB_PLUGIN_SOURCES btr/btr0btr.c btr/btr0cur.c btr/btr0pcur.c btr/btr0sea.c
+ buf/buf0buddy.c buf/buf0buf.c buf/buf0flu.c buf/buf0lru.c buf/buf0rea.c
+ data/data0data.c data/data0type.c
+ dict/dict0boot.c dict/dict0crea.c dict/dict0dict.c dict/dict0load.c dict/dict0mem.c
+ dyn/dyn0dyn.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 ha/ha0storage.c
+ ibuf/ibuf0ibuf.c
+ pars/lexyy.c pars/pars0grm.c pars/pars0opt.c pars/pars0pars.c pars/pars0sym.c
+ lock/lock0lock.c lock/lock0iter.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 os/os0sync.c os/os0thread.c
+ page/page0cur.c page/page0page.c page/page0zip.c
+ que/que0que.c
+ handler/ha_innodb.cc handler/handler0alter.cc handler/i_s.cc handler/mysql_addons.cc
+ read/read0read.c
+ rem/rem0cmp.c rem/rem0rec.c
+ row/row0ext.c row/row0ins.c row/row0merge.c row/row0mysql.c row/row0purge.c row/row0row.c
+ row/row0sel.c row/row0uins.c row/row0umod.c row/row0undo.c row/row0upd.c row/row0vers.c
+ srv/srv0que.c srv/srv0srv.c srv/srv0start.c
+ sync/sync0arr.c sync/sync0rw.c sync/sync0sync.c
+ thr/thr0loc.c
+ trx/trx0i_s.c trx/trx0purge.c trx/trx0rec.c trx/trx0roll.c trx/trx0rseg.c
+ trx/trx0sys.c trx/trx0trx.c trx/trx0undo.c
+ usr/usr0sess.c
+ ut/ut0byte.c ut/ut0dbg.c ut/ut0mem.c ut/ut0rnd.c ut/ut0ut.c ut/ut0vec.c
+ ut/ut0list.c ut/ut0wqueue.c)
+ADD_DEFINITIONS(-DHAVE_WINDOWS_ATOMICS -DINNODB_RW_LOCKS_USE_ATOMICS -DIB_HAVE_PAUSE_INSTRUCTION)
+MYSQL_STORAGE_ENGINE(INNODB_PLUGIN)
\ No newline at end of file
diff --git a/storage/innodb_plugin/COPYING b/storage/innodb_plugin/COPYING
new file mode 100644
index 00000000000..6b106e18fdb
--- /dev/null
+++ b/storage/innodb_plugin/COPYING
@@ -0,0 +1,351 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+Preamble
+========
+
+The licenses for most software are designed to take away your freedom
+to share and change it. By contrast, the GNU General Public License is
+intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+When we speak of free software, we are referring to freedom, not price.
+Our General Public Licenses are designed to make sure that you have
+the freedom to distribute copies of free software (and charge for this
+service if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs; and that you know you can do these things.
+
+To protect your rights, we need to make restrictions that forbid anyone
+to deny you these rights or to ask you to surrender the rights. These
+restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+For example, if you distribute copies of such a program, whether gratis
+or for a fee, you must give the recipients all the rights that you
+have. You must make sure that they, too, receive or can get the source
+code. And you must show them these terms so they know their rights.
+
+We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+Finally, any free program is threatened constantly by software patents.
+We wish to avoid the danger that redistributors of a free program will
+individually obtain patent licenses, in effect making the program
+proprietary. To prevent this, we have made it clear that any patent
+must be licensed for everyone's free use or not licensed at all.
+
+The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+ 0. This License applies to any program or other work which contains a
+ notice placed by the copyright holder saying it may be distributed
+ under the terms of this General Public License. The "Program",
+ below, refers to any such program or work, and a "work based on
+ the Program" means either the Program or any derivative work under
+ copyright law: that is to say, a work containing the Program or a
+ portion of it, either verbatim or with modifications and/or
+ translated into another language. (Hereinafter, translation is
+ included without limitation in the term "modification".) Each
+ licensee is addressed as "you".
+
+ Activities other than copying, distribution and modification are
+ not covered by this License; they are outside its scope. The act
+ of running the Program is not restricted, and the output from the
+ Program is covered only if its contents constitute a work based on
+ the Program (independent of having been made by running the
+ Program). Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+ source code as you receive it, in any medium, provided that you
+ conspicuously and appropriately publish on each copy an appropriate
+ copyright notice and disclaimer of warranty; keep intact all the
+ notices that refer to this License and to the absence of any
+ warranty; and give any other recipients of the Program a copy of
+ this License along with the Program.
+
+ You may charge a fee for the physical act of transferring a copy,
+ and you may at your option offer warranty protection in exchange
+ for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+ of it, thus forming a work based on the Program, and copy and
+ distribute such modifications or work under the terms of Section 1
+ above, provided that you also meet all of these conditions:
+
+ a. You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b. You must cause any work that you distribute or publish, that
+ in whole or in part contains or is derived from the Program
+ or any part thereof, to be licensed as a whole at no charge
+ to all third parties under the terms of this License.
+
+ c. If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display
+ an announcement including an appropriate copyright notice and
+ a notice that there is no warranty (or else, saying that you
+ provide a warranty) and that users may redistribute the
+ program under these conditions, and telling the user how to
+ view a copy of this License. (Exception: if the Program
+ itself is interactive but does not normally print such an
+ announcement, your work based on the Program is not required
+ to print an announcement.)
+
+ These requirements apply to the modified work as a whole. If
+ identifiable sections of that work are not derived from the
+ Program, and can be reasonably considered independent and separate
+ works in themselves, then this License, and its terms, do not
+ apply to those sections when you distribute them as separate
+ works. But when you distribute the same sections as part of a
+ whole which is a work based on the Program, the distribution of
+ the whole must be on the terms of this License, whose permissions
+ for other licensees extend to the entire whole, and thus to each
+ and every part regardless of who wrote it.
+
+ Thus, it is not the intent of this section to claim rights or
+ contest your rights to work written entirely by you; rather, the
+ intent is to exercise the right to control the distribution of
+ derivative or collective works based on the Program.
+
+ In addition, mere aggregation of another work not based on the
+ Program with the Program (or with a work based on the Program) on
+ a volume of a storage or distribution medium does not bring the
+ other work under the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+ under Section 2) in object code or executable form under the terms
+ of Sections 1 and 2 above provided that you also do one of the
+ following:
+
+ a. Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of
+ Sections 1 and 2 above on a medium customarily used for
+ software interchange; or,
+
+ b. Accompany it with a written offer, valid for at least three
+ years, to give any third-party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a
+ medium customarily used for software interchange; or,
+
+ c. Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with
+ such an offer, in accord with Subsection b above.)
+
+ The source code for a work means the preferred form of the work for
+ making modifications to it. For an executable work, complete
+ source code means all the source code for all modules it contains,
+ plus any associated interface definition files, plus the scripts
+ used to control compilation and installation of the executable.
+ However, as a special exception, the source code distributed need
+ not include anything that is normally distributed (in either
+ source or binary form) with the major components (compiler,
+ kernel, and so on) of the operating system on which the executable
+ runs, unless that component itself accompanies the executable.
+
+ If distribution of executable or object code is made by offering
+ access to copy from a designated place, then offering equivalent
+ access to copy the source code from the same place counts as
+ distribution of the source code, even though third parties are not
+ compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+ except as expressly provided under this License. Any attempt
+ otherwise to copy, modify, sublicense or distribute the Program is
+ void, and will automatically terminate your rights under this
+ License. However, parties who have received copies, or rights,
+ from you under this License will not have their licenses
+ terminated so long as such parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+ signed it. However, nothing else grants you permission to modify
+ or distribute the Program or its derivative works. These actions
+ are prohibited by law if you do not accept this License.
+ Therefore, by modifying or distributing the Program (or any work
+ based on the Program), you indicate your acceptance of this
+ License to do so, and all its terms and conditions for copying,
+ distributing or modifying the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+ Program), the recipient automatically receives a license from the
+ original licensor to copy, distribute or modify the Program
+ subject to these terms and conditions. You may not impose any
+ further restrictions on the recipients' exercise of the rights
+ granted herein. You are not responsible for enforcing compliance
+ by third parties to this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+ infringement or for any other reason (not limited to patent
+ issues), conditions are imposed on you (whether by court order,
+ agreement or otherwise) that contradict the conditions of this
+ License, they do not excuse you from the conditions of this
+ License. If you cannot distribute so as to satisfy simultaneously
+ your obligations under this License and any other pertinent
+ obligations, then as a consequence you may not distribute the
+ Program at all. For example, if a patent license would not permit
+ royalty-free redistribution of the Program by all those who
+ receive copies directly or indirectly through you, then the only
+ way you could satisfy both it and this License would be to refrain
+ entirely from distribution of the Program.
+
+ If any portion of this section is held invalid or unenforceable
+ under any particular circumstance, the balance of the section is
+ intended to apply and the section as a whole is intended to apply
+ in other circumstances.
+
+ It is not the purpose of this section to induce you to infringe any
+ patents or other property right claims or to contest validity of
+ any such claims; this section has the sole purpose of protecting
+ the integrity of the free software distribution system, which is
+ implemented by public license practices. Many people have made
+ generous contributions to the wide range of software distributed
+ through that system in reliance on consistent application of that
+ system; it is up to the author/donor to decide if he or she is
+ willing to distribute software through any other system and a
+ licensee cannot impose that choice.
+
+ This section is intended to make thoroughly clear what is believed
+ to be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+ certain countries either by patents or by copyrighted interfaces,
+ the original copyright holder who places the Program under this
+ License may add an explicit geographical distribution limitation
+ excluding those countries, so that distribution is permitted only
+ in or among countries not thus excluded. In such case, this
+ License incorporates the limitation as if written in the body of
+ this License.
+
+ 9. The Free Software Foundation may publish revised and/or new
+ versions of the General Public License from time to time. Such
+ new versions will be similar in spirit to the present version, but
+ may differ in detail to address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+ Program specifies a version number of this License which applies
+ to it and "any later version", you have the option of following
+ the terms and conditions either of that version or of any later
+ version published by the Free Software Foundation. If the Program
+ does not specify a version number of this License, you may choose
+ any version ever published by the Free Software Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+ programs whose distribution conditions are different, write to the
+ author to ask for permission. For software which is copyrighted
+ by the Free Software Foundation, write to the Free Software
+ Foundation; we sometimes make exceptions for this. Our decision
+ will be guided by the two goals of preserving the free status of
+ all derivatives of our free software and of promoting the sharing
+ and reuse of software generally.
+
+ NO WARRANTY
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO
+ WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE
+ LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+ HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT
+ WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE
+ QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+ PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY
+ SERVICING, REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+ WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY
+ MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE
+ LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL,
+ INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR
+ INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+ DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU
+ OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY
+ OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN
+ ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+How to Apply These Terms to Your New Programs
+=============================================
+
+If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these
+terms.
+
+To do so, attach the following notices to the program. It is safest to
+attach them to the start of each source file to most effectively convey
+the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ ONE LINE TO GIVE THE PROGRAM'S NAME AND A BRIEF IDEA OF WHAT IT DOES.
+ Copyright (C) YYYY NAME OF AUTHOR
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19YY NAME OF AUTHOR
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the
+appropriate parts of the General Public License. Of course, the
+commands you use may be called something other than `show w' and `show
+c'; they could even be mouse-clicks or menu items--whatever suits your
+program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ SIGNATURE OF TY COON, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program
+into proprietary programs. If your program is a subroutine library,
+you may consider it more useful to permit linking proprietary
+applications with the library. If this is what you want to do, use the
+GNU Library General Public License instead of this License.
diff --git a/storage/innodb_plugin/COPYING.Google b/storage/innodb_plugin/COPYING.Google
new file mode 100644
index 00000000000..5ade2b0e381
--- /dev/null
+++ b/storage/innodb_plugin/COPYING.Google
@@ -0,0 +1,30 @@
+Portions of this software contain modifications contributed by Google, Inc.
+These contributions are used with the following license:
+
+Copyright (c) 2008, Google Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials
+ provided with the distribution.
+ * Neither the name of the Google Inc. nor the names of its
+ contributors may be used to endorse or promote products
+ derived from this software without specific prior written
+ permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/storage/innodb_plugin/COPYING.Percona b/storage/innodb_plugin/COPYING.Percona
new file mode 100644
index 00000000000..8c786811719
--- /dev/null
+++ b/storage/innodb_plugin/COPYING.Percona
@@ -0,0 +1,30 @@
+Portions of this software contain modifications contributed by Percona, Inc.
+These contributions are used with the following license:
+
+Copyright (c) 2008, 2009, Percona Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials
+ provided with the distribution.
+ * Neither the name of the Percona Inc. nor the names of its
+ contributors may be used to endorse or promote products
+ derived from this software without specific prior written
+ permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/storage/innodb_plugin/COPYING.Sun_Microsystems b/storage/innodb_plugin/COPYING.Sun_Microsystems
new file mode 100644
index 00000000000..5a77ef3ab73
--- /dev/null
+++ b/storage/innodb_plugin/COPYING.Sun_Microsystems
@@ -0,0 +1,31 @@
+Portions of this software contain modifications contributed by
+Sun Microsystems, Inc. These contributions are used with the following
+license:
+
+Copyright (c) 2009, Sun Microsystems, Inc.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials
+ provided with the distribution.
+ * Neither the name of Sun Microsystems, Inc. nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/storage/innodb_plugin/ChangeLog b/storage/innodb_plugin/ChangeLog
new file mode 100644
index 00000000000..2b04c06f0e8
--- /dev/null
+++ b/storage/innodb_plugin/ChangeLog
@@ -0,0 +1,1149 @@
+2009-07-20 The InnoDB Team
+
+ * buf/buf0rea.c, handler/ha_innodb.cc, include/srv0srv.h,
+ srv/srv0srv.c:
+ Change the read ahead parameter name to innodb_read_ahead_threshold.
+ Change the meaning of this parameter to signify the number of pages
+ that must be sequentially accessed for InnoDB to trigger a readahead
+ request.
+
+2009-07-20 The InnoDB Team
+
+ * handler/ha_innodb.cc:
+ Fix Bug#39802 On Windows, 32-bit time_t should be enforced
+
+2009-07-16 The InnoDB Team
+
+ * include/univ.i:
+ Support inlining of functions and prefetch with Sun Studio.
+ These changes are based on contribution from Sun Microsystems Inc.
+ under a BSD license.
+
+2009-07-14 The InnoDB Team
+
+ * fil/fil0fil.c:
+ Fix Bug#45814 URL reference in InnoDB server errors needs adjusting to
+ match documentation
+
+2009-07-14 The InnoDB Team
+
+ * handler/ha_innodb.cc, mysql-test/innodb_bug21704.result,
+ mysql-test/innodb_bug21704.test:
+ Fix Bug#21704 Renaming column does not update FK definition
+
+2009-07-10 The InnoDB Team
+
+ * handler/ha_innodb.cc, srv/srv0srv.c:
+ Change the defaults for
+ innodb_sync_spin_loops: 20 -> 30
+ innodb_spin_wait_delay: 5 -> 6
+
+2009-07-08 The InnoDB Team
+
+ * buf/buf0flu.c, handler/ha_innodb.cc, include/buf0flu.h,
+ include/log0log.h, include/log0log.ic, include/srv0srv.h,
+ srv/srv0srv.c:
+ Implement the adaptive flushing of dirty pages, which uses
+ a heuristics based flushing rate of dirty pages to avoid IO
+ bursts at checkpoint. Expose new configure knob
+ innodb_adaptive_flushing to control whether the new flushing
+ algorithm should be used.
+
+2009-07-07 The InnoDB Team
+
+ * handler/ha_innodb.cc, include/srv0srv.h, log/log0log.c,
+ srv/srv0srv.c:
+ Implement IO capacity tuning. Expose new configure knob
+ innodb_io_capacity to control the master threads IO rate. The
+ ibuf merge is also changed from synchronous to asynchronous.
+ These changes are based on contribution from Google Inc.
+ under a BSD license.
+
+2009-07-02 The InnoDB Team
+
+ * include/ut0ut.h, plug.in, ut/ut0ut.c:
+ Use the PAUSE instruction inside the spinloop if it is available,
+ Thanks to Mikael Ronstrom .
+
+2009-06-29 The InnoDB Team
+
+ * handler/ha_innodb.cc, mysql-test/innodb_file_format.test,
+ mysql-test/innodb_file_format.result:
+ Do not crash on SET GLOBAL innodb_file_format=DEFAULT
+ or SET GLOBAL innodb_file_format_check=DEFAULT.
+
+2009-06-29 The InnoDB Team
+
+ * buf/buf0buf.c, buf/buf0rea.c, lock/lock0lock.c:
+ Tolerate missing tablespaces during crash recovery and when
+ printing information on locks.
+
+2009-06-29 The InnoDB Team
+
+ * buf/buf0buf.c:
+ Fix a race condition when reading buf_fix_count.
+ Currently, it is not being protected by the buffer pool mutex,
+ but by the block mutex.
+
+2009-06-29 The InnoDB Team
+
+ * handler/handler0alter.cc:
+ Start the user transaction prebuilt->trx if it was not started
+ before adding or dropping an index. Without this fix, the
+ table could be locked outside an active transaction.
+
+2009-06-25 The InnoDB Team
+
+ * handler/ha_innodb.cc, mysql-test/innodb_bug42101.test,
+ mysql-test/innodb_bug42101.result,
+ mysql-test/innodb_bug42101-nonzero.test,
+ mysql-test/innodb_bug42101-nonzero.result:
+ Fix Bug#45749 Race condition in SET GLOBAL
+ innodb_commit_concurrency=DEFAULT
+
+2009-06-25 The InnoDB Team
+
+ * dict/dict0dict.c:
+ When an index column cannot be found in the table during index
+ creation, display additional diagnostic before an assertion failure.
+ This does NOT fix Bug #44571 InnoDB Plugin crashes on ADD INDEX,
+ but it helps understand the reason of the crash.
+
+2009-06-17 The InnoDB Team
+
+ * row/row0merge.c:
+ Fix Bug#45426 UNIV_DEBUG build cause assertion error at CREATE INDEX
+
+2009-06-17 The InnoDB Team
+
+ * mysql-test/innodb_bug45357.result, mysql-test/innodb_bug45357.test,
+ row/row0mysql.c:
+ Fix Bug#45357 5.1.35 crashes with Failing assertion: index->type &
+ DICT_CLUSTERED
+
+2009-06-17 The InnoDB Team
+
+ * handler/ha_innodb.cc, mysql-test/innodb-autoinc.result,
+ mysql-test/innodb-autoinc.test:
+ Fix Bug#44030 Error: (1500) Couldn't read the MAX(ID) autoinc value
+ from the index (PRIMARY)
+
+2009-06-11 The InnoDB Team
+
+ * handler/ha_innodb.cc, mysql-test/innodb.result, srv/srv0srv.c:
+ Change the following defaults:
+ max_dirty_pages_pct: from 90 to 75, max allowed from 100 to 99
+ additional_mem_pool_size: from 1 to 8 MB
+ buffer_pool_size: from 8 to 128 MB
+ log_buffer_size: from 1 to 8 MB
+ read_io_threads/write_io_threads: from 1 to 4
+
+2009-06-09 The InnoDB Team
+
+ * handler/ha_innodb.cc, include/trx0trx.h, trx/trx0trx.c:
+ Enable Group Commit functionality that was broken in 5.0 when
+ distributed transactions were introduced.
+
+2009-06-05 The InnoDB Team
+
+ * handler/ha_innodb.cc, include/os0file.h, include/srv0srv.h,
+ os/os0file.c, srv/srv0srv.c, srv/srv0start.c:
+ Enable functionality to have multiple background IO helper threads.
+ Expose new configure knobs innodb_read_io_threads and
+ innodb_write_io_threads and deprecate innodb_file_io_threads (this
+ parameter was relevant only on windows). Internally this allows
+ multiple segments for read and write IO request arrays where one
+ thread works on one segment.
+
+2009-06-05 The InnoDB Team
+
+ * buf/buf0lru.c, buf/buf0rea.c, handler/ha_innodb.cc,
+ include/srv0srv.h, srv/srv0srv.c:
+ Fix a bug in linear read ahead:
+ 1) Take into account access pattern when deciding whether or not to
+ do linear read ahead.
+ 2) Expose a knob innodb_read_ahead_factor = [0-64] default (8),
+ dynamic, global to control linear read ahead behavior. This is the
+ value of the number of pages that InnoDB will tolerate within a
+ 64 page extent even if they are accessed out of order or have
+ not been accessed at all. This number (which varies from 0 to 64)
+ is indicative of the slack that we have when deciding about linear
+ readahead.
+ 3) Disable random read ahead. Keep the code for now.
+
+2009-06-03 The InnoDB Team
+
+ * dict/dict0dict.c, mysql-test/t/innodb_mysql.test,
+ mysql-test/r/innodb_mysql.result:
+ Fix Bug#39793 Foreign keys not constructed when column
+ has a '#' in a comment or default value
+
+2009-05-27 The InnoDB Team
+
+ * Doxyfile:
+ Allow the extraction of documentation from the code base with the
+ Doxygen tool. Convert and add many (but not yet all) comments to
+ Doxygen format.
+
+2009-05-19 The InnoDB Team
+
+ * btr/btr0btr.c, btr/btr0cur.c, lock/lock0lock.c,
+ include/page0page.ic, include/lock0lock.h, include/dict0dict.h,
+ include/page0page.h, include/dict0dict.ic, ibuf/ibuf0ibuf.c,
+ page/page0zip.c, page/page0page.c:
+ Write updates of PAGE_MAX_TRX_ID to the redo log and add debug
+ assertions for checking that PAGE_MAX_TRX_ID is valid on leaf
+ pages of secondary indexes and the insert buffer B-tree. This bug
+ could cause failures in secondary index lookups in consistent
+ reads right after crash recovery.
+
+2009-05-18 The InnoDB Team
+
+ * btr/btr0cur.c:
+ Correctly estimate the space needed on the compressed page when
+ performing an update by delete-and-insert.
+
+2009-05-14 The InnoDB Team
+
+ * handler/ha_innodb.cc, include/srv0srv.h,
+ mysql-test/innodb_bug42101-nonzero-master.opt,
+ mysql-test/innodb_bug42101-nonzero.result,
+ mysql-test/innodb_bug42101-nonzero.test,
+ mysql-test/innodb_bug42101.result, mysql-test/innodb_bug42101.test,
+ srv/srv0srv.c:
+ Fix Bug#42101 Race condition in innodb_commit_concurrency
+
+2009-05-13 The InnoDB Team
+
+ * dict/dict0dict.c:
+ Fix Bug#44320 InnoDB: missing DB_ROLL_PTR in Table Monitor COLUMNS
+ output
+
+2009-04-23 The InnoDB Team
+
+ * row/row0mysql.c:
+ When scanning indexes, report in the error log any error codes
+ returned by the search function. These error codes will still be
+ ignored in CHECK TABLE.
+
+2009-04-23 The InnoDB Team
+
+ * include/trx0types.h:
+ Define the logical type names trx_id_t, roll_ptr_t, and undo_no_t
+ and use them in place of dulint everywhere.
+
+2009-04-18 The InnoDB Team
+
+ * handler/ha_innodb.cc, include/pars0pars.h:
+ Fix Bug#29125 Windows Server X64: so many compiler warnings
+
+2009-04-16 The InnoDB Team
+
+ * include/univ.i:
+ Define REFMAN as the base URL of the MySQL Reference Manual and
+ use the macro in all diagnostic output.
+
+2009-04-16 The InnoDB Team
+
+ * CMakeLists.txt, include/os0sync.h, include/sync0sync.h,
+ include/sync0sync.ic, include/univ.i, srv/srv0start.c,
+ sync/sync0sync.c:
+ Use the Windows Interlocked functions for atomic memory
+ access.
+
+2009-04-15 The InnoDB Team
+
+ * mysql-test/innodb.result, mysql-test/innodb.test:
+ Fix Bug#43309 Test main.innodb can't be run twice
+
+2009-04-14 The InnoDB Team
+
+ * CMakeLists.txt, handler/win_delay_loader.cc,
+ win-plugin/win-plugin.diff:
+ Remove statically linked libraries from MySQL (zlib and strings).
+
+2009-04-11 The InnoDB Team
+
+ * CMakeLists.txt, win-plugin/README, win-plugin/win-plugin.diff:
+ Rewrite CMakeLists.txt.
+
+2009-04-07 The InnoDB Team
+
+ * include/os0sync.h, include/sync0rw.ic, include/sync0sync.h,
+ include/sync0sync.ic, include/univ.i, plug.in, srv/srv0srv.c,
+ srv/srv0start.c, sync/sync0arr.c, sync/sync0sync.c:
+ Enable atomics on Solaris (using the libc functions as defined in
+ atomic.h) if GCC atomic builtins are not present.
+
+2009-04-07 The InnoDB Team
+
+ * btr/btr0btr.c, dict/dict0dict.c, ibuf/ibuf0ibuf.c,
+ include/data0data.h, include/data0data.ic, include/data0type.h,
+ include/data0type.ic, include/dict0dict.h, include/dict0dict.ic,
+ include/rem0rec.ic, mysql-test/innodb.result, mysql-test/innodb.test,
+ pars/pars0pars.c, rem/rem0rec.c, row/row0upd.c:
+ Fix Bug#44032 In ROW_FORMAT=REDUNDANT, update UTF-8 CHAR
+ to/from NULL is not in-place
+
+2009-04-07 The InnoDB Team
+
+ * page/page0cur.c:
+ Fix Bug#43660 SHOW INDEXES/ANALYZE does NOT update cardinality for
+ indexes of InnoDB table
+
+2009-04-06 The InnoDB Team
+
+ * handler/ha_innodb.cc:
+ Make the parameter innodb_change_buffering settable by the
+ configuration file or mysqld command line options. Before this
+ fix, the initial value specified for this parameter was ignored.
+
+2009-04-06 The InnoDB Team
+
+ * sync/sync0rw.c:
+ Avoid a bogus failure in UNIV_SYNC_DEBUG diagnostics.
+
+2009-04-02 The InnoDB Team
+
+ * handler/ha_innodb.cc, include/srv0srv.h, srv/srv0srv.c:
+ Add new parameter innodb_spin_wait_delay to set the maximum delay
+ between polling for a spin lock.
+
+2009-04-02 The InnoDB Team
+
+ * dict/dict0crea.c, handler/ha_innodb.cc, handler/ha_innodb.h,
+ include/dict0mem.h, include/row0merge.h, include/row0mysql.h,
+ mysql-test/innodb-index.result, mysql-test/innodb-index.test,
+ row/row0merge.c, row/row0sel.c:
+ In consistent reads, refuse to use newly created indexes that may
+ lack history.
+
+2009-03-25 The InnoDB Team
+
+ * buf/buf0buf.c, handler/ha_innodb.cc, include/buf0buf.h:
+ In SHOW ENGINE INNODB MUTEX do not show the status of block->mutex,
+ block->lock, block->lock->mutex (if applicable) and all mutexes and
+ rw-locks for which number of os-waits are zero because this can
+ be overwhelming particularly when the buffer pool is very large.
+
+2009-03-20 The InnoDB Team
+
+ * buf/buf0buf.c, include/log0recv.h, log/log0recv.c:
+ Remove the compile-time constant parameters of
+ recv_recover_page(), recv_scan_log_recs(), and recv_sys_init().
+
+2009-03-20 The InnoDB Team
+
+ * data/data0type.c, handler/ha_innodb.cc, include/ha_prototypes.h:
+ Declare innobase_get_at_most_n_mbchars() in ha_prototypes.h.
+
+2009-03-20 The InnoDB Team
+
+ * fil/fil0fil.h, fil/fil0fil.c, srv/srv0start.c:
+ Add the parameter hash_size to fil_init().
+
+2009-03-20 The InnoDB Team
+
+ * fil/fil0fil.c:
+ Refer to fil_system directly, not via local variables.
+
+2009-03-20 The InnoDB Team
+
+ * page/page0page.c:
+ In page_validate(), always report the space id, page number and
+ the name of the index when corruption is noticed.
+
+2009-03-20 The InnoDB Team
+
+ * include/log0log.h, include/log0log.ic, log/log0log.c:
+ Add in/out comments or const qualifiers to some function
+ parameters as appropriate.
+
+2009-03-20 The InnoDB Team
+
+ * dict/dict0boot.c, dict/dict0dict.c, fsp/fsp0fsp.c,
+ include/dict0dict.h, include/srv0srv.h, srv/srv0srv.c,
+ page/page0page.c:
+ Replace srv_sys->dummy_ind1 and srv_sys->dummy_ind2 with
+ dict_ind_redundant and dict_ind_compact, which are
+ initialized by dict_init().
+
+2009-03-11 The InnoDB Team
+
+ InnoDB Plugin 1.0.3 released
+
+2009-03-05 The InnoDB Team
+
+ * handler/ha_innodb.cc, mysql-test/innodb-autoinc.result,
+ mysql-test/innodb-autoinc.test:
+ Fix Bug#43203 Overflow from auto incrementing causes server segv
+
+2009-02-25 The InnoDB Team
+
+ * handler/ha_innodb.cc, mysql-test/innodb-autoinc.result,
+ mysql-test/innodb-autoinc.test:
+ Fix Bug#42714 AUTO_INCREMENT errors in 5.1.31
+
+2009-02-23 The InnoDB Team
+
+ * btr/btr0cur.c:
+ Fix Bug#43043 Crash on BLOB delete operation
+
+2009-02-20 The InnoDB Team
+
+ * handler/ha_innodb.cc:
+ Make innodb_use_sys_malloc=ON the default.
+
+2009-02-20 The InnoDB Team
+
+ * handler/ha_innodb.cc, mysql-test/innodb-autoinc.result,
+ mysql-test/innodb-autoinc.test:
+ Fix Bug#42400 InnoDB autoinc code can't handle floating-point columns
+
+2009-02-18 The InnoDB Team
+
+ * include/ut0mem.h, os/os0proc.c, ut/ut0mem.c:
+ Protect ut_total_allocated_memory with ut_list_mutex in
+ os_mem_alloc_large() and os_mem_free_large(). The lack of this mutex
+ protection could cause an assertion failure during fast index
+ creation. Also, add UNIV_MEM_ALLOC and UNIV_MEM_FREE instrumentation
+ to os_mem_alloc_large() and os_mem_free_large(), so that Valgrind can
+ detect more errors.
+
+2009-02-11 The InnoDB Team
+
+ * handler/ha_innodb.cc:
+ Make innodb_thread_concurrency=0 the default. The old default value
+ was 8. A non-zero setting may be useful when InnoDB is showing severe
+ scalability problems under multiple concurrent connections.
+
+2009-02-10 The InnoDB Team
+
+ * handler/ha_innodb.cc, handler/ha_innodb.h:
+ Fix Bug#41676 Table names are case insensitive in locking
+
+2009-02-10 The InnoDB Team
+
+ * mem/mem0dbg.c, mem/mem0mem.c, mem/mem0pool.c:
+ When innodb_use_sys_malloc is set, ignore
+ innodb_additional_mem_pool_size, because nothing will be allocated
+ from mem_comm_pool.
+
+2009-02-10 The InnoDB Team
+
+ * ut/ut0mem.c:
+ Map ut_malloc_low(), ut_realloc(), and ut_free() directly to malloc(),
+ realloc(), and free() when innodb_use_sys_malloc is set. As a side
+ effect, ut_total_allocated_memory ("Total memory allocated" in the
+ "BUFFER POOL AND MEMORY" section of SHOW ENGINE INNODB STATUS) will
+ exclude any memory allocated by these functions when
+ innodb_use_sys_malloc is set.
+
+2009-02-10 The InnoDB Team
+
+ * btr/btr0cur.c, btr/btr0sea.c, buf/buf0buf.c, handler/ha_innodb.cc,
+ include/buf0buf.ic, include/os0sync.h, include/srv0srv.h,
+ include/sync0rw.h, include/sync0rw.ic, include/sync0sync.h,
+ include/sync0sync.ic, include/univ.i, row/row0sel.c, srv/srv0srv.c,
+ srv/srv0start.c, sync/sync0arr.c, sync/sync0rw.c, sync/sync0sync.c:
+ On those platforms that support it, implement the synchronization
+ primitives of InnoDB mutexes and read/write locks with GCC atomic
+ builtins instead of Pthreads mutexes and InnoDB mutexes. These changes
+ are based on a patch supplied by Mark Callaghan of Google under a BSD
+ license.
+
+2009-01-30 The InnoDB Team
+
+ * btr/btr0cur.c, btr/btr0sea.c, buf/buf0buf.c, handler/ha_innodb.cc,
+ include/btr0sea.h, include/buf0buf.h, include/sync0sync.h,
+ sync/sync0sync.c:
+ Make the configuration parameter innodb_adaptive_hash_index dynamic,
+ so that it can be changed at runtime.
+
+2009-01-29 The InnoDB Team
+
+ * handler/ha_innodb.cc, ibuf/ibuf0ibuf.c, include/ibuf0ibuf.h,
+ include/ibuf0ibuf.ic:
+ Implement the settable global variable innodb_change_buffering,
+ with the allowed values 'none' and 'inserts'. The default value
+ 'inserts' enables the buffering of inserts to non-unique secondary
+ index trees when the B-tree leaf page is not in the buffer pool.
+
+2009-01-27 The InnoDB Team
+
+ * buf/buf0lru.c:
+ Fix a race condition in buf_LRU_invalidate_tablespace(): The
+ compressed page size (zip_size) was read while the block descriptor
+ was no longer protected by a mutex. This could lead to corruption
+ when a table is dropped on a busy system that contains compressed
+ tables.
+
+2009-01-26 The InnoDB Team
+
+ * btr/btr0sea.c, buf/buf0buf.c, include/buf0buf.h, include/buf0buf.ic,
+ include/mtr0log.ic, include/row0upd.ic, mtr/mtr0mtr.c:
+ Implement buf_block_align() with pointer arithmetics, as it is in the
+ built-in InnoDB distributed with MySQL. Do not acquire the buffer pool
+ mutex before buf_block_align(). This removes a scalability bottleneck
+ in the adaptive hash index lookup. In CHECK TABLE, check that
+ buf_pool->page_hash is consistent with buf_block_align().
+
+2009-01-23 The InnoDB Team
+
+ * btr/btr0sea.c:
+ Fix Bug#42279 Race condition in btr_search_drop_page_hash_when_freed()
+
+2009-01-23 The InnoDB Team
+
+ * buf/buf0buf.c, include/buf0buf.h:
+ Remove the unused mode BUF_GET_NOWAIT of buf_page_get_gen()
+
+2009-01-20 The InnoDB Team
+
+ * include/rem0rec.h, include/rem0rec.ic:
+ Fix Bug#41571 MySQL segfaults after innodb recovery
+
+2009-01-20 The InnoDB Team
+
+ * lock/lock0lock.c:
+ Fix Bug#42152 Race condition in lock_is_table_exclusive()
+
+2009-01-14 The InnoDB Team
+
+ * include/trx0roll.h, trx/trx0roll.c, trx/trx0trx.c:
+ Fix Bug#38187 Error 153 when creating savepoints
+
+2009-01-14 The InnoDB Team
+
+ * dict/dict0load.c:
+ Fix Bug#42075 dict_load_indexes failure in dict_load_table will
+ corrupt the dictionary cache
+
+2009-01-13 The InnoDB Team
+
+ * buf/buf0buddy.c, dict/dict0dict.c, dict/dict0mem.c, fil/fil0fil.c,
+ ha/ha0storage.c, handler/ha_innodb.cc, handler/win_delay_loader.cc,
+ include/buf0buf.ic, include/dict0dict.ic, include/hash0hash.h,
+ thr/thr0loc.c, trx/trx0i_s.c:
+ Add the parameter ASSERTION to HASH_SEARCH() macro, and use it for
+ light validation of the traversed items in hash table lookups when
+ UNIV_DEBUG is enabled.
+
+2009-01-09 The InnoDB Team
+
+ * buf/buf0flu.c, include/buf0flu.h, include/buf0flu.ic:
+ Remove unused code from the functions
+ buf_flush_insert_into_flush_list() and
+ buf_flush_insert_sorted_into_flush_list().
+
+2009-01-09 The InnoDB Team
+
+ * buf/buf0flu.c:
+ Simplify the functions buf_flush_try_page() and buf_flush_batch(). Add
+ debug assertions and an explanation to buf_flush_write_block_low().
+
+2009-01-07 The InnoDB Team
+
+ * row/row0merge.c:
+ Fix a bug in recovery when dropping temporary indexes.
+
+2009-01-07 The InnoDB Team
+
+ * handler/ha_innodb.cc, handler/ha_innodb.h, handler/handler0alter.cc:
+ Fix Bug#41680 calls to trx_allocate_for_mysql are not consistent
+
+2009-01-07 The InnoDB Team
+
+ * mysql-test/innodb_bug41904.result, mysql-test/innodb_bug41904.test,
+ row/row0merge.c:
+ Fix Bug#41904 create unique index problem
+
+2009-01-02 The InnoDB Team
+
+ * handler/ha_innodb.cc, include/srv0srv.h, mem/mem0pool.c,
+ mysql-test/innodb-use-sys-malloc-master.opt,
+ mysql-test/innodb-use-sys-malloc.result,
+ mysql-test/innodb-use-sys-malloc.test, srv/srv0srv.c, srv/srv0start.c:
+ Implement the configuration parameter innodb_use_sys_malloc (false by
+ default), for disabling InnoDB's internal memory allocator and using
+ system malloc/free instead. The "BUFFER POOL AND MEMORY" section of
+ SHOW ENGINE INNODB STATUS will report "in additional pool allocated
+ allocated 0" when innodb_use_sys_malloc is set.
+
+2008-12-30 The InnoDB Team
+
+ * btr/btr0btr.c:
+ When setting the PAGE_LEVEL of a compressed B-tree page from or to 0,
+ compress the page at the same time. This is necessary, because the
+ column information stored on the compressed page will differ between
+ leaf and non-leaf pages. Leaf pages are identified by PAGE_LEVEL=0.
+ This bug can make InnoDB crash when all rows of a compressed table are
+ deleted.
+
+2008-12-17 The InnoDB Team
+
+ * include/row0sel.h, include/row0upd.h, pars/pars0pars.c,
+ row/row0mysql.c, row/row0sel.c, row/row0upd.c:
+ Remove update-in-place select from the internal SQL interpreter. It
+ was only used for updating the InnoDB internal data dictionary when
+ renaming or dropping tables. It could have caused deadlocks when
+ acquiring latches on insert buffer bitmap pages.
+
+2008-12-17 The InnoDB Team
+
+ * btr/btr0sea.c, buf/buf0buf.c, buf/buf0lru.c, ha/ha0ha.c,
+ ha/hash0hash.c, include/buf0buf.h, include/ha0ha.h, include/ha0ha.ic,
+ include/hash0hash.h, include/univ.i:
+ Introduce the preprocessor symbol UNIV_AHI_DEBUG for enabling adaptive
+ hash index debugging independently of UNIV_DEBUG.
+
+2008-12-16 The InnoDB Team
+
+ * btr/btr0cur.c:
+ Do not update the free bits in the insert buffer bitmap when inserting
+ or deleting from the insert buffer B-tree. Assert that records in the
+ insert buffer B-tree are never updated.
+
+2008-12-12 The InnoDB Team
+
+ * buf/buf0buf.c, fil/fil0fil.c, fsp/fsp0fsp.c, ibuf/ibuf0ibuf.c,
+ include/fil0fil.h, include/ibuf0ibuf.h, include/ibuf0ibuf.ic,
+ include/ibuf0types.h:
+ Clean up the insert buffer subsystem so that only one insert
+ buffer B-tree exists.
+ Originally, there were provisions in InnoDB for multiple insert
+ buffer B-trees, apparently one for each tablespace.
+ When Heikki Tuuri implemented multiple InnoDB tablespaces in
+ MySQL/InnoDB 4.1, he made the insert buffer live only in the
+ system tablespace (space 0) but left the provisions in the code.
+
+2008-12-11 The InnoDB Team
+
+ * include/srv0srv.h, os/os0proc.c, srv/srv0srv.c:
+ Fix the issue that the InnoDB plugin fails if innodb_buffer_pool_size
+ is defined bigger than 4096M on 64-bit Windows. This bug should not
+ have affected other 64-bit systems.
+
+2008-12-09 The InnoDB Team
+
+ * handler/ha_innodb.cc:
+ Fix Bug#40386 Not flushing query cache after truncate.
+
+2008-12-09 The InnoDB Team
+
+ * handler/ha_innodb.cc, srv/srv0srv.c, trx/trx0trx.c:
+ Fix Bug#40760 "set global innodb_thread_concurrency = 0;" is not safe
+
+2008-12-04 The InnoDB Team
+
+ * handler/ha_innodb.cc, handler/mysql_addons.cc,
+ include/mysql_addons.h, trx/trx0i_s.c, win-plugin/win-plugin.diff:
+ Remove dependencies to MySQL internals (defining MYSQL_SERVER).
+
+2008-12-02 The InnoDB Team
+
+ * page/page0cur.c:
+ When allocating space for a record from the free list of previously
+ purged records, zero out the DB_TRX_ID and DB_ROLL_PTR of the purged
+ record if the new record would not overwrite these fields. This fixes
+ a harmless content mismatch reported by page_zip_validate().
+
+2008-12-02 The InnoDB Team
+
+ * row/row0merge.c:
+ Replace the WHILE 1 with WHILE 1=1 in the SQL procedure, so that the
+ loop will actually be entered and temporary indexes be dropped during
+ crash recovery.
+
+2008-12-01 The InnoDB Team
+
+ InnoDB Plugin 1.0.2 released
+
+2008-10-31 The InnoDB Team
+
+ * dict/dict0mem.c, include/dict0mem.h, include/lock0lock.h,
+ include/row0mysql.h, include/trx0trx.h, include/univ.i,
+ include/ut0vec.h, include/ut0vec.ic, lock/lock0lock.c,
+ row/row0mysql.c, trx/trx0trx.c:
+ Fix Bug#26316 Triggers create duplicate entries on auto-increment
+ columns
+
+2008-10-30 The InnoDB Team
+
+ * handler/ha_innodb.cc, handler/handler0vars.h,
+ handler/win_delay_loader.cc, mysql-test/innodb_bug40360.result,
+ mysql-test/innodb_bug40360.test:
+ Fix Bug#40360 Binlog related errors with binlog off
+
+2008-10-29 The InnoDB Team
+
+ * include/data0type.ic:
+ Fix Bug#40369 dtype_get_sql_null_size() returns 0 or 1, not the size
+
+2008-10-29 The InnoDB Team
+
+ * handler/ha_innodb.cc, include/srv0srv.h, srv/srv0srv.c:
+ Fix Bug#38189 innodb_stats_on_metadata missing
+
+2008-10-28 The InnoDB Team
+
+ * CMakeLists.txt, ha_innodb.def, handler/ha_innodb.cc,
+ handler/handler0alter.cc, handler/handler0vars.h, handler/i_s.cc,
+ handler/win_delay_loader.cc, win-plugin/*:
+ Implemented the delayloading of externals for the plugin on Windows.
+ This makes it possible to build a dynamic plugin (ha_innodb.dll) on
+ Windows.
+
+2008-10-27 The InnoDB Team
+
+ * CMakeLists.txt:
+ Fix Bug#19424 InnoDB: Possibly a memory overrun of the buffer being
+ freed (64-bit Visual C)
+
+2008-10-23 The InnoDB Team
+
+ * ibuf/ibuf0ibuf.c:
+ ibuf_delete_rec(): When the cursor to the insert buffer record
+ cannot be restored, do not complain if the tablespace does not
+ exist, because the insert buffer record may have been discarded by
+ some other thread. This bug has existed in MySQL/InnoDB since
+ version 4.1, when innodb_file_per_table was implemented.
+ This may fix Bug#27276 InnoDB Error: ibuf cursor restoration fails.
+
+2008-10-22 The InnoDB Team
+
+ * dict/dict0dict.c, dict/dict0mem.c, handler/ha_innodb.cc,
+ handler/ha_innodb.h, include/dict0dict.h, include/dict0mem.h,
+ row/row0mysql.c:
+ Fix Bug#39830 Table autoinc value not updated on first insert
+ Fix Bug#35498 Cannot get table test/table1 auto-inccounter value in
+ ::info
+ Fix Bug#36411 "Failed to read auto-increment value from storage
+ engine" in 5.1.24 auto-inc
+
+2008-10-22 The InnoDB Team
+
+ * handler/ha_innodb.cc, include/row0mysql.h, row/row0mysql.c:
+ Fix Bug#40224 New AUTOINC changes mask reporting of deadlock/timeout
+ errors
+
+2008-10-16 The InnoDB Team
+
+ * dict/dict0dict.c, mysql-test/innodb-index.result,
+ mysql-test/innodb-index.test:
+ Skip the undo log size check when creating REDUNDANT and COMPACT
+ tables. In ROW_FORMAT=DYNAMIC and ROW_FORMAT=COMPRESSED, column
+ prefix indexes require that prefixes of externally stored columns
+ be written to the undo log. This may make the undo log record
+ bigger than the record on the B-tree page. The maximum size of an
+ undo log record is the page size. That must be checked for, in
+ dict_index_add_to_cache(). However, this restriction must not
+ be enforced on REDUNDANT or COMPACT tables.
+
+2008-10-15 The InnoDB Team
+
+ * btr/btr0cur.c, include/btr0cur.h, row/row0ext.c, row/row0sel.c,
+ row/row0upd.c:
+ When the server crashes while freeing an externally stored column
+ of a compressed table, the BTR_EXTERN_LEN field in the BLOB
+ pointer will be written as 0. Tolerate this in the functions that
+ deal with externally stored columns. This fixes problems after
+ crash recovery, in the rollback of incomplete transactions, and in
+ the purge of delete-marked records.
+
+2008-10-15 The InnoDB Team
+
+ * btr/btr0btr.c, include/page0zip.h, page/page0zip.c, include/univ.i:
+ When a B-tree node of a compressed table is split or merged, the
+ compression may fail. In this case, the entire compressed page
+ will be copied and the excess records will be deleted. However,
+ page_zip_copy(), now renamed to page_zip_copy_recs(), copied too
+ many fields in the page header, overwriting PAGE_BTR_SEG_LEAF and
+ PAGE_BTR_SEG_TOP when splitting the B-tree root. This caused
+ corruption of compressed tables. Furthermore, the lock table and
+ the adaptive hash index would be corrupted, because we forgot to
+ update them when invoking page_zip_copy_recs().
+
+ Introduce the symbol UNIV_ZIP_DEBUG for triggering the copying of
+ compressed pages more often, for debugging purposes.
+
+2008-10-10 The InnoDB Team
+
+ * handler/handler0alter.cc, include/row0merge.h, row/row0merge.c,
+ row/row0mysql.c:
+ Fix some locking issues, mainly in fast index creation. The
+ InnoDB data dictionary cache should be latched whenever a
+ transaction is holding locks on any data dictionary tables.
+ Otherwise, lock waits or deadlocks could occur. Furthermore, the
+ data dictionary transaction must be committed (and the locks
+ released) before the data dictionary latch is released.
+
+ ha_innobase::add_index(): Lock the data dictionary before renaming
+ or dropping the created indexes, because neither operation will
+ commit the data dictionary transaction.
+
+ ha_innobase::final_drop_index(): Commit the transactions before
+ unlocking the data dictionary.
+
+2008-10-09 The InnoDB Team
+
+ * buf/buf0lru.c:
+ Fix Bug#39939 DROP TABLE/DISCARD TABLESPACE takes long time in
+ buf_LRU_invalidate_tablespace()
+
+2008-10-08 The InnoDB Team
+
+ * dict/dict0crea.c, trx/trx0roll.c, include/row0mysql.h,
+ row/row0merge.c, row/row0mysql.c:
+ When dropping a table, hold the data dictionary latch until the
+ transaction has been committed. The data dictionary latch is
+ supposed to prevent lock waits and deadlocks in the data
+ dictionary tables. Due to this bug, DROP TABLE could cause a
+ deadlock or hang. Note that because of Bug#33650 and Bug#39833,
+ MySQL may also drop a (temporary) table when executing CREATE INDEX
+ or ALTER TABLE ... ADD INDEX.
+
+2008-10-04 The InnoDB Team
+
+ * handler/ha_innodb.cc, mysql-test/innodb_bug39438-master.opt,
+ mysql-test/innodb_bug39438.result, mysql-test/innodb_bug39438.test:
+ Fix Bug#39438 Testcase for Bug#39436 crashes on 5.1 in
+ fil_space_get_latch
+
+2008-10-04 The InnoDB Team
+
+ * include/lock0lock.h, lock/lock0lock.c,
+ mysql-test/innodb_bug38231.result, mysql-test/innodb_bug38231.test,
+ row/row0mysql.c:
+ Fix Bug#38231 Innodb crash in lock_reset_all_on_table() on TRUNCATE +
+ LOCK / UNLOCK
+
+2008-10-04 The InnoDB Team
+
+ * handler/ha_innodb.cc:
+ Fix Bug#35498 Cannot get table test/table1 auto-inccounter value in
+ ::info
+
+2008-10-04 The InnoDB Team
+
+ * handler/ha_innodb.cc, handler/ha_innodb.h:
+ Fix Bug#37788 InnoDB Plugin: AUTO_INCREMENT wrong for compressed
+ tables
+
+2008-10-04 The InnoDB Team
+
+ * dict/dict0dict.c, handler/ha_innodb.cc, handler/ha_innodb.h,
+ include/dict0dict.h, include/dict0mem.h, row/row0mysql.c:
+ Fix Bug#39830 Table autoinc value not updated on first insert
+
+2008-10-03 The InnoDB Team
+
+ * mysql-test/innodb-index.test, mysql-test/innodb-index.result,
+ mysql-test/innodb-timeout.test, mysql-test/innodb-timeout.result,
+ srv/srv0srv.c, include/srv0srv.h, handler/ha_innodb.cc,
+ include/ha_prototypes.h:
+ Fix Bug#36285 innodb_lock_wait_timeout is not dynamic, not per session
+
+2008-09-19 The InnoDB Team
+
+ * os/os0proc.c:
+ Fix a memory leak on Windows. The memory leak was due to wrong
+ parameters passed into VirtualFree() call. As the result, the
+ call fails with Windows error 87.
+
+2008-09-17 The InnoDB Team
+
+ * mysql-test/innodb.result, mysql-test/innodb-zip.result,
+ mysql-test/innodb-zip.test, mysql-test/innodb.test, ibuf/ibuf0ibuf.c,
+ dict/dict0crea.c, dict/dict0load.c, dict/dict0boot.c,
+ include/dict0dict.h, include/trx0trx.h, dict/dict0dict.c,
+ trx/trx0trx.c, include/ha_prototypes.h, handler/ha_innodb.cc:
+ When creating an index in innodb_strict_mode, check that the
+ maximum record size will never exceed the B-tree page size limit.
+ For uncompressed tables, there should always be enough space for
+ two records in an empty B-tree page. For compressed tables, there
+ should be enough space for storing two node pointer records or one
+ data record in an empty page in uncompressed format.
+ The purpose of this check is to guarantee that INSERT or UPDATE
+ will never fail due to too big record size.
+
+2008-09-17 The InnoDB Team
+
+ * btr/btr0cur.c, data/data0data.c, include/page0zip.h,
+ include/page0zip.ic, page/page0zip.c, mysql-test/innodb_bug36172.test:
+ Prevent infinite B-tree page splits in compressed tables by
+ ensuring that there will always be enough space for two node
+ pointer records in an empty B-tree page. Also, require that at
+ least one data record will fit in an empty compressed page. This
+ will reduce the maximum size of records in compressed tables.
+
+2008-09-09 The InnoDB Team
+
+ * mysql-test/innodb.result:
+ Fix the failing innodb test by merging changes that MySQL made to
+ that file (r2646.12.1 in MySQL BZR repository)
+
+2008-09-09 The InnoDB Team
+
+ * handler/ha_innodb.cc, mysql-test/innodb-autoinc.result,
+ mysql-test/innodb-autoinc.test:
+ Fix Bug#38839 auto increment does not work properly with InnoDB after
+ update
+
+2008-09-09 The InnoDB Team
+
+ * dict/dict0dict.c, handler/handler0alter.cc, include/dict0dict.h,
+ mysql-test/innodb-index.result, mysql-test/innodb-index.test:
+ Fix Bug#38786 InnoDB plugin crashes on drop table/create table with FK
+
+2008-08-21 The InnoDB Team
+
+ * handler/ha_innodb.cc, include/ha_prototypes.h, row/row0sel.c:
+ Fix Bug#37885 row_search_for_mysql may gap lock unnecessarily with SQL
+ comments in query
+
+2008-08-21 The InnoDB Team
+
+ * handler/ha_innodb.cc:
+ Fix Bug#38185 ha_innobase::info can hold locks even when called with
+ HA_STATUS_NO_LOCK
+
+2008-08-18 The InnoDB Team
+
+ * buf/buf0buf.c, buf/buf0lru.c, include/buf0buf.ic, include/univ.i:
+ Introduce UNIV_LRU_DEBUG for debugging the LRU buffer pool cache
+
+2008-08-08 The InnoDB Team
+
+ * buf/buf0lru.c, include/buf0buf.h:
+ Fix two recovery bugs that could lead to a crash in debug builds with
+ small buffer size
+
+2008-08-07 The InnoDB Team
+
+ * btr/btr0cur.c, handler/ha_innodb.cc, include/srv0srv.h,
+ srv/srv0srv.c:
+ Add a parameter innodb_stats_sample_pages to allow users to control
+ the number of index dives when InnoDB estimates the cardinality of
+ an index (ANALYZE TABLE, SHOW TABLE STATUS etc)
+
+2008-08-07 The InnoDB Team
+
+ * trx/trx0i_s.c:
+ Fix a bug that would lead to a crash if a SELECT was issued from the
+ INFORMATION_SCHEMA tables and there are rolling back transactions at
+ the same time
+
+2008-08-06 The InnoDB Team
+
+ * btr/btr0btr.c, btr/btr0cur.c, ibuf/ibuf0ibuf.c, include/btr0cur.h,
+ include/trx0roll.h, include/trx0types.h, row/row0purge.c,
+ row/row0uins.c, row/row0umod.c, trx/trx0roll.c:
+ In the rollback of incomplete transactions after crash recovery,
+ tolerate clustered index records whose externally stored columns
+ have not been written.
+
+2008-07-30 The InnoDB Team
+
+ * trx/trx0trx.c:
+ Fixes a race in recovery where the recovery thread recovering a
+ PREPARED trx and the background rollback thread can both try
+ to free the trx after its status is set to COMMITTED_IN_MEMORY.
+
+2008-07-29 The InnoDB Team
+
+ * include/trx0rec.h, row/row0purge.c, row/row0vers.c, trx/trx0rec.c:
+ Fix a BLOB corruption bug
+
+2008-07-15 The InnoDB Team
+
+ * btr/btr0sea.c, dict/dict0dict.c, include/btr0sea.h:
+ Fixed a timing hole where a thread dropping an index can free the
+ in-memory index struct while another thread is still using that
+ structure to remove entries from adaptive hash index belonging
+ to one of the pages that belongs to the index being dropped.
+
+2008-07-04 The InnoDB Team
+
+ * mysql-test/innodb-index.result:
+ Fix the failing innodb-index test by adjusting the result to a new
+ MySQL behavior (the change occured in BZR-r2667)
+
+2008-07-03 The InnoDB Team
+
+ * mysql-test/innodb-zip.result, mysql-test/innodb-zip.test:
+ Remove the negative test cases that produce warnings
+
+2008-07-02 The InnoDB Team
+
+ * mysql-test/innodb-replace.result, mysql-test/innodb-index.test:
+ Disable part of innodb-index test because MySQL changed its behavior
+ and is not calling ::add_index() anymore when adding primary index on
+ non-NULL column
+
+2008-07-01 The InnoDB Team
+
+ * mysql-test/innodb-replace.result, mysql-test/innodb-replace.test:
+ Fix the failing innodb-replace test by merging changes that MySQL
+ made to that file (r2659 in MySQL BZR repository)
+
+2008-07-01 The InnoDB Team
+
+ * lock/lock0lock.c:
+ Fix Bug#36942 Performance problem in lock_get_n_rec_locks (SHOW INNODB
+ STATUS)
+
+2008-07-01 The InnoDB Team
+
+ * ha/ha0ha.c:
+ Fix Bug#36941 Performance problem in ha_print_info (SHOW INNODB
+ STATUS)
+
+2008-07-01 The InnoDB Team
+
+ * handler/ha_innodb.cc, mysql-test/innodb-autoinc.result,
+ mysql-test/innodb-autoinc.test:
+ Fix Bug#37531 After truncate, auto_increment behaves incorrectly for
+ InnoDB
+
+2008-06-19 The InnoDB Team
+
+ * handler/ha_innodb.cc:
+ Rewrite the function innodb_plugin_init() to support parameters in
+ different order (in static and dynamic InnoDB) and to support more
+ parameters in the static InnoDB
+
+2008-06-19 The InnoDB Team
+
+ * handler/handler0alter.cc:
+ Fix a bug in ::add_index() which set the transaction state to "active"
+ but never restored it to the original value. This bug caused warnings
+ to be printed by the rpl.rpl_ddl mysql-test.
+
+2008-06-19 The InnoDB Team
+
+ * mysql-test/patches:
+ Add a directory which contains patches, which need to be applied to
+ MySQL source in order to get some mysql-tests to succeed. The patches
+ cannot be committed in MySQL repository because they are specific to
+ the InnoDB plugin.
+
+2008-06-19 The InnoDB Team
+
+ * mysql-test/innodb-zip.result, mysql-test/innodb-zip.test,
+ row/row0row.c:
+ Fix an anomaly when updating a record with BLOB prefix
+
+2008-06-18 The InnoDB Team
+
+ * include/trx0sys.h, srv/srv0start.c, trx/trx0sys.c:
+ Fix a bug in recovery which was a side effect of the file_format_check
+ changes
+
+2008-06-09 The InnoDB Team
+
+ * mysql-test/innodb.result:
+ Fix the failing innodb test by merging changes that MySQL made to that
+ file
+
+2008-06-06 The InnoDB Team
+
+ * buf/buf0buf.c, handler/ha_innodb.cc, include/buf0buf.h,
+ include/srv0srv.h, srv/srv0srv.c:
+ Fix Bug#36600 SHOW STATUS takes a lot of CPU in
+ buf_get_latched_pages_number
+
+ * handler/ha_innodb.cc, os/os0file.c:
+ Fix Bug#11894 innodb_file_per_table crashes w/ Windows .sym symbolic
+ link hack
+
+ * include/ut0ut.h, srv/srv0srv.c, ut/ut0ut.c:
+ Fix Bug#36819 ut_usectime does not handle errors from gettimeofday
+
+ * handler/ha_innodb.cc:
+ Fix Bug#35602 Failed to read auto-increment value from storage engine
+
+ * srv/srv0start.c:
+ Fix Bug#36149 Read buffer overflow in srv0start.c found during "make
+ test"
+
+2008-05-08 The InnoDB Team
+
+ * btr/btr0btr.c, mysql-test/innodb_bug36172.result,
+ mysql-test/innodb_bug36172.test:
+ Fix Bug#36172 insert into compressed innodb table crashes
+
+2008-05-08 The InnoDB Team
+
+ InnoDB Plugin 1.0.1 released
+
+2008-05-06 The InnoDB Team
+
+ * handler/ha_innodb.cc, include/srv0srv.h, include/sync0sync.h,
+ include/trx0sys.h, mysql-test/innodb-zip.result,
+ mysql-test/innodb-zip.test, srv/srv0srv.c, srv/srv0start.c,
+ sync/sync0sync.c, trx/trx0sys.c:
+ Implement the system tablespace tagging
+
+ * handler/ha_innodb.cc, handler/i_s.cc, include/univ.i,
+ srv/srv0start.c:
+ Add InnoDB version in INFORMATION_SCHEMA.PLUGINS.PLUGIN_VERSION,
+ in the startup message and in a server variable innodb_version.
+
+ * sync/sync0sync.c:
+ Fix a bug in the sync debug code where a lock with level
+ SYNC_LEVEL_VARYING would cause an assertion failure when a thread
+ tried to release it.
+
+2008-04-30 The InnoDB Team
+
+ * Makefile.am:
+ Fix Bug#36434 ha_innodb.so is installed in the wrong directory
+
+ * handler/ha_innodb.cc:
+ Merge change from MySQL (Fix Bug#35406 5.1-opt crashes on select from
+ I_S.REFERENTIAL_CONSTRAINTS):
+ ChangeSet@1.2563, 2008-03-18 19:42:04+04:00, gluh@mysql.com +1 -0
+
+ * scripts/install_innodb_plugins.sql:
+ Added
+
+ * mysql-test/innodb.result:
+ Merge change from MySQL (this fixes the failing innodb test):
+ ChangeSet@1.1810.3601.4, 2008-02-07 02:33:21+04:00
+
+ * row/row0sel.c:
+ Fix Bug#35226 RBR event crashes slave
+
+ * handler/ha_innodb.cc:
+ Change the fix for Bug#32440 to show bytes instead of kilobytes in
+ INFORMATION_SCHEMA.TABLES.DATA_FREE
+
+ * handler/ha_innodb.cc, mysql-test/innodb.result,
+ mysql-test/innodb.test:
+ Fix Bug#29507 TRUNCATE shows to many rows effected
+
+ * handler/ha_innodb.cc, mysql-test/innodb.result,
+ mysql-test/innodb.test:
+ Fix Bug#35537 Innodb doesn't increment handler_update and
+ handler_delete
+
+2008-04-29 The InnoDB Team
+
+ * handler/i_s.cc, include/srv0start.h, srv/srv0start.c:
+ Fix Bug#36310 InnoDB plugin crash
+
+2008-04-23 The InnoDB Team
+
+ * mysql-test/innodb_bug36169.result, mysql-test/innodb_bug36169.test,
+ row/row0mysql.c:
+ Fix Bug#36169 create innodb compressed table with too large row size
+ crashed
+
+ * (outside the source tree):
+ Fix Bug#36222 New InnoDB plugin 1.0 has wrong MKDIR_P defined in
+ Makefile.in
+
+2008-04-15 The InnoDB Team
+
+ InnoDB Plugin 1.0.0 released
diff --git a/storage/innodb_plugin/Doxyfile b/storage/innodb_plugin/Doxyfile
new file mode 100644
index 00000000000..62aa7dd8abc
--- /dev/null
+++ b/storage/innodb_plugin/Doxyfile
@@ -0,0 +1,1419 @@
+# Doxyfile 1.5.6
+
+# Usage: SVNVERSION=-r$(svnversion) doxygen
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+# TAG = value [value, ...]
+# For lists items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all
+# text before the first occurrence of this tag. Doxygen uses libiconv (or the
+# iconv built into libc) for the transcoding. See
+# http://www.gnu.org/software/libiconv for the list of possible encodings.
+
+DOXYFILE_ENCODING = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
+# by quotes) that should identify the project.
+
+PROJECT_NAME = "InnoDB Plugin"
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
+# if some version control system is used.
+
+PROJECT_NUMBER = 1.0$(SVNVERSION)
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# If a relative path is entered, it will be relative to the location
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY = dox
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
+# 4096 sub-directories (in 2 levels) under the output directory of each output
+# format and will distribute the generated files over these directories.
+# Enabling this option can be useful when feeding doxygen a huge amount of
+# source files, where putting all generated files in the same directory would
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
+# Croatian, Czech, Danish, Dutch, Farsi, Finnish, French, German, Greek,
+# Hungarian, Italian, Japanese, Japanese-en (Japanese with English messages),
+# Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, Polish,
+# Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish, Swedish,
+# and Ukrainian.
+
+OUTPUT_LANGUAGE = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator
+# that is used to form the text in various listings. Each string
+# in this list, if found as the leading text of the brief description, will be
+# stripped from the text and the result after processing the whole list, is
+# used as the annotated text. Otherwise, the brief description is used as-is.
+# If left blank, the following values are used ("$name" is automatically
+# replaced with the name of the entity): "The $name class" "The $name widget"
+# "The $name file" "is" "provides" "specifies" "contains"
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES = YES
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user-defined part of the path. Stripping is
+# only done if one of the specified strings matches the left-hand part of
+# the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the
+# path to strip.
+
+STRIP_FROM_PATH =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
+# the path mentioned in the documentation of a class, which tells
+# the reader which header file to include in order to use a class.
+# If left blank only the name of the header file containing the class
+# definition is used. Otherwise one should specify the include paths that
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
+# (but less readable) file names. This can be useful is your file systems
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like regular Qt-style comments
+# (thus requiring an explicit @brief command for a brief description.)
+
+JAVADOC_AUTOBRIEF = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then Doxygen will
+# interpret the first line (until the first dot) of a Qt-style
+# comment as the brief description. If set to NO, the comments
+# will behave just like regular Qt-style comments (thus requiring
+# an explicit \brief command for a brief description.)
+
+QT_AUTOBRIEF = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
+# treat a multi-line C++ special comment block (i.e. a block of //! or ///
+# comments) as a brief description. This used to be the default behaviour.
+# The new default is to treat a multi-line C++ comment block as a detailed
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the DETAILS_AT_TOP tag is set to YES then Doxygen
+# will output the detailed description near the top, like JavaDoc.
+# If set to NO, the detailed description appears after the member
+# documentation.
+
+DETAILS_AT_TOP = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# re-implements.
+
+INHERIT_DOCS = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
+# a new page for each member. If set to NO, the documentation of a member will
+# be part of the file/class/namespace that contains it.
+
+SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE = 8
+
+# This tag can be used to specify a number of aliases that acts
+# as commands in the documentation. An alias has the form "name=value".
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
+# put the command \sideeffect (or @sideeffect) in the documentation, which
+# will result in a user-defined paragraph with heading "Side Effects:".
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
+# sources only. Doxygen will then generate output that is more tailored for C.
+# For instance, some of the names that are used will be different. The list
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C = YES
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
+# sources only. Doxygen will then generate output that is more tailored for
+# Java. For instance, namespaces will be presented as packages, qualified
+# scopes will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources only. Doxygen will then generate output that is more tailored for
+# Fortran.
+
+OPTIMIZE_FOR_FORTRAN = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for
+# VHDL.
+
+OPTIMIZE_OUTPUT_VHDL = NO
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should
+# set this tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
+# func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+
+BUILTIN_STL_SUPPORT = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+
+CPP_CLI_SUPPORT = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only.
+# Doxygen will parse them like normal C++ but will assume all classes use public
+# instead of private inheritance when no explicit protection keyword is present.
+
+SIP_SUPPORT = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate getter
+# and setter methods for a property. Setting this option to YES (the default)
+# will make doxygen to replace the get and set methods by a property in the
+# documentation. This will only work if the methods are indeed getting or
+# setting a simple type. If this is not the case, or you want to show the
+# methods anyway, you should set this option to NO.
+
+IDL_PROPERTY_SUPPORT = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
+# the same type (for instance a group of public functions) to be put as a
+# subgroup of that type (e.g. under the Public Functions section). Set it to
+# NO to prevent subgrouping. Alternatively, this can be done per class using
+# the \nosubgrouping command.
+
+SUBGROUPING = YES
+
+# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum
+# is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically
+# be useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+
+TYPEDEF_HIDES_STRUCT = NO
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# will be included in the documentation.
+
+EXTRACT_PRIVATE = YES
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# will be included in the documentation.
+
+EXTRACT_STATIC = YES
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES = YES
+
+# This flag is only useful for Objective-C code. When set to YES local
+# methods, which are defined in the implementation section but not in
+# the interface are included in the documentation.
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base
+# name of the file that contains the anonymous namespace. By default
+# anonymous namespace are hidden.
+
+EXTRACT_ANON_NSPACES = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these classes will be included in the various
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
+# friend (class|struct|union) declarations.
+# If set to NO (the default) these declarations will be included in the
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
+# documentation blocks found inside the body of a function.
+# If set to NO (the default) these blocks will be appended to the
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
+# file names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put a list of the files that are included by a file in the documentation
+# of that file.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
+# is inserted in the documentation for inline members.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
+# will sort the (detailed) documentation of file and class members
+# alphabetically by member name. If set to NO the members will appear in
+# declaration order.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
+# brief documentation of file, namespace and class members alphabetically
+# by member name. If set to NO (the default) the members will appear in
+# declaration order.
+
+SORT_BRIEF_DOCS = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the
+# hierarchy of group names into alphabetical order. If set to NO (the default)
+# the group names will appear in their defined order.
+
+SORT_GROUP_NAMES = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
+# sorted by fully-qualified names, including namespaces. If set to
+# NO (the default), the class list will be sorted only by class name,
+# not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or
+# disable (NO) the todo list. This list is created by putting \todo
+# commands in the documentation.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
+# commands in the documentation.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
+# commands in the documentation.
+
+GENERATE_BUGLIST = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
+# disable (NO) the deprecated list. This list is created by putting
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
+# the initial value of a variable or define consists of for it to appear in
+# the documentation. If the initializer consists of more lines than specified
+# here it will be hidden. Use a value of 0 to hide initializers completely.
+# The appearance of the initializer of individual variables and defines in the
+# documentation can be controlled using \showinitializer or \hideinitializer
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES = YES
+
+# If the sources in your project are distributed over multiple directories
+# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
+# in the documentation. The default is NO.
+
+SHOW_DIRECTORIES = NO
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page.
+# This will remove the Files entry from the Quick Index and from the
+# Folder Tree View (if specified). The default is YES.
+
+SHOW_FILES = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the
+# Namespaces page. This will remove the Namespaces entry from the Quick Index
+# and from the Folder Tree View (if specified). The default is YES.
+
+SHOW_NAMESPACES = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command , where is the value of
+# the FILE_VERSION_FILTER tag, and is the name of an input file
+# provided by doxygen. Whatever the program writes to standard output
+# is used as the file version. See the manual for examples.
+
+FILE_VERSION_FILTER =
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET = YES
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
+# NO is used.
+
+WARNINGS = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some
+# parameters in a documented function, or documenting parameters that
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR = YES
+
+# This WARN_NO_PARAMDOC option can be abled to get warnings for
+# functions that are documented, but have no documentation for their parameters
+# or return value. If set to NO (the default) doxygen will only warn about
+# wrong or incomplete parameter documentation, but not about the absence of
+# documentation.
+
+WARN_NO_PARAMDOC = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text. Optionally the format may contain
+# $version, which will be replaced by the version of the file (if it could
+# be obtained via FILE_VERSION_FILTER)
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning
+# and error messages should be written. If left blank the output is written
+# to stderr.
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
+INPUT = . include/univ.i
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
+# also the default input encoding. Doxygen uses libiconv (or the iconv built
+# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for
+# the list of possible encodings.
+
+INPUT_ENCODING = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank the following patterns are tested:
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx
+# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90
+
+FILE_PATTERNS = *.c *.ic *.h
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
+# If left blank NO is used.
+
+RECURSIVE = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE = ut0auxconf_*
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or
+# directories that are symbolic links (a Unix filesystem feature) are excluded
+# from the input.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories. Note that the wildcards are matched
+# against the file with absolute path, so to exclude all test directories
+# for example use the pattern */test/*
+
+EXCLUDE_PATTERNS =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+
+EXCLUDE_SYMBOLS =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+
+EXAMPLE_PATH =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank all files are included.
+
+EXAMPLE_PATTERNS =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
+# the \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command , where
+# is the value of the INPUT_FILTER tag, and is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output. If FILTER_PATTERNS is specified, this tag will be
+# ignored.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form:
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
+# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER
+# is applied to all files.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+# Note: To get rid of all source code in the generated output, make sure also
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES
+# then for each documented function all documented
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+
+REFERENCES_RELATION = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
+# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
+# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
+# link to the source code. Otherwise they will link to the documentstion.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code
+# will point to the HTML generated by the htags(1) tool instead of doxygen
+# built-in source browser. The htags tool is part of GNU's global source
+# tagging system (see http://www.gnu.org/software/global/global.html). You
+# will need version 4.8.6 or higher.
+
+USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX = NO
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header.
+
+HTML_HEADER =
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard footer.
+
+HTML_FOOTER =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
+# style sheet that is used by each HTML page. It can be used to
+# fine-tune the look of the HTML output. If the tag is left blank doxygen
+# will generate a default style sheet. Note that doxygen will try to copy
+# the style sheet file to the HTML output directory, so don't put your own
+# stylesheet in the HTML output directory as well, or it will be erased!
+
+HTML_STYLESHEET =
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
+# files or namespaces will be aligned in HTML using tables. If set to
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS = YES
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP = NO
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files
+# will be generated that can be used as input for Apple's Xcode 3
+# integrated development environment, introduced with OSX 10.5 (Leopard).
+# To create a documentation set, doxygen will generate a Makefile in the
+# HTML output directory. Running make will produce the docset in that
+# directory and running "make install" will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find
+# it at startup.
+
+GENERATE_DOCSET = NO
+
+# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the
+# feed. A documentation feed provides an umbrella under which multiple
+# documentation sets from a single provider (such as a company or product suite)
+# can be grouped.
+
+DOCSET_FEEDNAME = "Doxygen generated docs"
+
+# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that
+# should uniquely identify the documentation set bundle. This should be a
+# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen
+# will append .docset to the name.
+
+DOCSET_BUNDLE_ID = org.doxygen.Project
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded. For this to work a browser that supports
+# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox
+# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari).
+
+HTML_DYNAMIC_SECTIONS = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
+# be used to specify the file name of the resulting .chm file. You
+# can add a path in front of the file if the result should not be
+# written to the html output directory.
+
+CHM_FILE =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
+# be used to specify the location (absolute path including file name) of
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING
+# is used to encode HtmlHelp index (hhk), content (hhc) and project file
+# content.
+
+CHM_INDEX_ENCODING =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND = NO
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
+# top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it.
+
+DISABLE_INDEX = NO
+
+# This tag can be used to set the number of enum values (range [1..20])
+# that doxygen will group on one line in the generated HTML documentation.
+
+ENUM_VALUES_PER_LINE = 4
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information.
+# If the tag value is set to FRAME, a side panel will be generated
+# containing a tree-like index structure (just like the one that
+# is generated for HTML Help). For this to work a browser that supports
+# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+,
+# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are
+# probably better off using the HTML help feature. Other possible values
+# for this tag are: HIERARCHIES, which will generate the Groups, Directories,
+# and Class Hiererachy pages using a tree view instead of an ordered list;
+# ALL, which combines the behavior of FRAME and HIERARCHIES; and NONE, which
+# disables this behavior completely. For backwards compatibility with previous
+# releases of Doxygen, the values YES and NO are equivalent to FRAME and NONE
+# respectively.
+
+GENERATE_TREEVIEW = NONE
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
+# used to set the initial width (in pixels) of the frame in which the tree
+# is shown.
+
+TREEVIEW_WIDTH = 250
+
+# Use this tag to change the font size of Latex formulas included
+# as images in the HTML documentation. The default is 10. Note that
+# when you change the font size after a successful doxygen run you need
+# to manually remove any form_*.png images from the HTML output directory
+# to force them to be regenerated.
+
+FORMULA_FONTSIZE = 10
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+GENERATE_LATEX = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked. If left blank `latex' will be used as the default command name.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, a4wide, letter, legal and
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS = YES
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not
+# include the index chapters (such as File Index, Compound Index, etc.)
+# in the output.
+
+LATEX_HIDE_INDICES = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimized for Word 97 and may not look very pretty with
+# other RTF readers or editors.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using WORD or other
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation.
+
+GENERATE_XML = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_SCHEMA =
+
+# The XML_DTD tag can be used to specify an XML DTD,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_DTD =
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
+# dump the program listings (including syntax highlighting
+# and cross-referencing information) to the XML output. Note that
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will
+# generate a Perl module file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
+# nicely formatted so it can be parsed by a human reader. This is useful
+# if you want to understand what is going on. On the other hand, if this
+# tag is set to NO the size of the Perl module output will be much smaller
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
+# This is useful so different doxyrules.make files included by the same
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION = YES
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_DEFINED tags.
+
+EXPAND_ONLY_PREDEF = YES
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed. To prevent a macro definition from being
+# undefined via #undef or recursively expanded use the := operator
+# instead of the = operator.
+
+PREDEFINED = DOXYGEN UNIV_DEBUG UNIV_SYNC_DEBUG __attribute__()=
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition.
+
+EXPAND_AS_DEFINED = UT_LIST_BASE_NODE_T UT_LIST_NODE_T
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all function-like macros that are alone
+# on a line, have an all uppercase name, and do not end with a semicolon. Such
+# function macros are typically used for boiler-plate code, and will confuse
+# the parser if not removed.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles.
+# Optionally an initial location of the external documentation
+# can be added for each tagfile. The format of a tag file without
+# this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where "loc1" and "loc2" can be relative or absolute paths or
+# URLs. If a location is present for each tag, the installdox tool
+# does not have to be run to correct the links.
+# Note that each tag file must have a unique name
+# (where the name does NOT include the path)
+# If a tag file is not located in the directory in which doxygen
+# is run, you must also specify the path to the tagfile here.
+
+TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE =
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
+# be listed.
+
+EXTERNAL_GROUPS = NO
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
+# or super classes. Setting the tag to NO turns the diagrams off. Note that
+# this option is superseded by the HAVE_DOT option below. This is only a
+# fallback. It is recommended to install and use dot, since it yields more
+# powerful graphs.
+
+CLASS_DIAGRAMS = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see
+# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH =
+
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT = YES
+
+# By default doxygen will write a font called FreeSans.ttf to the output
+# directory and reference it in all dot files that doxygen generates. This
+# font does not include all possible unicode characters however, so when you need
+# these (or just want a differently looking font) you can specify the font name
+# using DOT_FONTNAME. You need need to make sure dot is able to find the font,
+# which can be done by putting it in a standard location or by setting the
+# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory
+# containing the font.
+
+DOT_FONTNAME = FreeSans
+
+# By default doxygen will tell dot to use the output directory to look for the
+# FreeSans.ttf font (which doxygen will put there itself). If you specify a
+# different font using DOT_FONTNAME you can set the path where dot
+# can find it using this tag.
+
+DOT_FONTPATH =
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect inheritance relations. Setting this tag to YES will force the
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect implementation dependencies (inheritance, containment, and
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH = YES
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for groups, showing the direct groups dependencies
+
+GROUP_GRAPHS = NO
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+
+UML_LOOK = NO
+
+# If set to YES, the inheritance and collaboration graphs will show the
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
+# other documented files.
+
+INCLUDE_GRAPH = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH and HAVE_DOT options are set to YES then
+# doxygen will generate a call dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable call graphs
+# for selected functions only using the \callgraph command.
+
+CALL_GRAPH = NO
+
+# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then
+# doxygen will generate a caller dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable caller
+# graphs for selected functions only using the \callergraph command.
+
+CALLER_GRAPH = NO
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# will graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY = YES
+
+# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES
+# then doxygen will show the dependencies a directory has on other directories
+# in a graphical way. The dependency relations are determined by the #include
+# relations between the files in the directories.
+
+DIRECTORY_GRAPH = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. Possible values are png, jpg, or gif
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT = png
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
+# \dotfile command).
+
+DOTFILE_DIRS =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of
+# nodes that will be shown in the graph. If the number of nodes in a graph
+# becomes larger than this value, doxygen will truncate the graph, which is
+# visualized by representing a node as a red box. Note that doxygen if the
+# number of direct children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note
+# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+
+DOT_GRAPH_MAX_NODES = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
+# graphs generated by dot. A depth value of 3 means that only nodes reachable
+# from the root by following a path via at most 3 edges will be shown. Nodes
+# that lay further from the root node will be omitted. Note that setting this
+# option to 1 or 2 may greatly reduce the computation time needed for large
+# code bases. Also note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+
+MAX_DOT_GRAPH_DEPTH = 3
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is enabled by default, which results in a transparent
+# background. Warning: Depending on the platform used, enabling this option
+# may lead to badly anti-aliased labels on the edges of a graph (i.e. they
+# become hard to read).
+
+DOT_TRANSPARENT = YES
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10)
+# support this, this feature is disabled by default.
+
+DOT_MULTI_TARGETS = NO
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermediate dot files that are used to generate
+# the various graphs.
+
+DOT_CLEANUP = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to the search engine
+#---------------------------------------------------------------------------
+
+# The SEARCHENGINE tag specifies whether or not a search engine should be
+# used. If set to NO the values of all tags below this one will be ignored.
+
+SEARCHENGINE = NO
diff --git a/storage/innodb_plugin/Makefile.am b/storage/innodb_plugin/Makefile.am
new file mode 100644
index 00000000000..50a3c1e6cab
--- /dev/null
+++ b/storage/innodb_plugin/Makefile.am
@@ -0,0 +1,343 @@
+# Copyright (C) 2001, 2004, 2006 MySQL AB & Innobase Oy
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+# Process this file with automake to create Makefile.in
+
+MYSQLDATAdir= $(localstatedir)
+MYSQLSHAREdir= $(pkgdatadir)
+MYSQLBASEdir= $(prefix)
+MYSQLLIBdir= $(pkglibdir)
+pkgplugindir= $(pkglibdir)/plugin
+INCLUDES= -I$(top_srcdir)/include -I$(top_builddir)/include \
+ -I$(top_srcdir)/regex \
+ -I$(srcdir)/include \
+ -I$(top_srcdir)/sql \
+ -I$(srcdir) @ZLIB_INCLUDES@
+
+DEFS= @DEFS@
+
+
+noinst_HEADERS= \
+ handler/ha_innodb.h \
+ handler/handler0vars.h \
+ handler/i_s.h \
+ include/btr0btr.h \
+ include/btr0btr.ic \
+ include/btr0cur.h \
+ include/btr0cur.ic \
+ include/btr0pcur.h \
+ include/btr0pcur.ic \
+ include/btr0sea.h \
+ include/btr0sea.ic \
+ include/btr0types.h \
+ include/buf0buddy.h \
+ include/buf0buddy.ic \
+ include/buf0buf.h \
+ include/buf0buf.ic \
+ include/buf0flu.h \
+ include/buf0flu.ic \
+ include/buf0lru.h \
+ include/buf0lru.ic \
+ include/buf0rea.h \
+ include/buf0types.h \
+ include/data0data.h \
+ include/data0data.ic \
+ include/data0type.h \
+ include/data0type.ic \
+ include/data0types.h \
+ include/db0err.h \
+ include/dict0boot.h \
+ include/dict0boot.ic \
+ include/dict0crea.h \
+ include/dict0crea.ic \
+ include/dict0dict.h \
+ include/dict0dict.ic \
+ include/dict0load.h \
+ include/dict0load.ic \
+ include/dict0mem.h \
+ include/dict0mem.ic \
+ include/dict0types.h \
+ include/dyn0dyn.h \
+ include/dyn0dyn.ic \
+ include/eval0eval.h \
+ include/eval0eval.ic \
+ include/eval0proc.h \
+ include/eval0proc.ic \
+ include/fil0fil.h \
+ include/fsp0fsp.h \
+ include/fsp0fsp.ic \
+ include/fsp0types.h \
+ include/fut0fut.h \
+ include/fut0fut.ic \
+ include/fut0lst.h \
+ include/fut0lst.ic \
+ include/ha0ha.h \
+ include/ha0ha.ic \
+ include/ha0storage.h \
+ include/ha0storage.ic \
+ include/ha_prototypes.h \
+ include/handler0alter.h \
+ 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 \
+ include/mach0data.ic \
+ include/mem0dbg.h \
+ include/mem0dbg.ic \
+ include/mem0mem.h \
+ include/mem0mem.ic \
+ include/mem0pool.h \
+ include/mem0pool.ic \
+ include/mtr0log.h \
+ include/mtr0log.ic \
+ include/mtr0mtr.h \
+ include/mtr0mtr.ic \
+ include/mtr0types.h \
+ include/mysql_addons.h \
+ include/os0file.h \
+ include/os0proc.h \
+ include/os0proc.ic \
+ include/os0sync.h \
+ include/os0sync.ic \
+ include/os0thread.h \
+ include/os0thread.ic \
+ include/page0cur.h \
+ include/page0cur.ic \
+ include/page0page.h \
+ include/page0page.ic \
+ include/page0types.h \
+ include/page0zip.h \
+ include/page0zip.ic \
+ include/pars0grm.h \
+ include/pars0opt.h \
+ include/pars0opt.ic \
+ include/pars0pars.h \
+ include/pars0pars.ic \
+ include/pars0sym.h \
+ include/pars0sym.ic \
+ include/pars0types.h \
+ include/que0que.h \
+ include/que0que.ic \
+ include/que0types.h \
+ include/read0read.h \
+ include/read0read.ic \
+ include/read0types.h \
+ include/rem0cmp.h \
+ include/rem0cmp.ic \
+ include/rem0rec.h \
+ include/rem0rec.ic \
+ include/rem0types.h \
+ include/row0ext.h \
+ include/row0ext.ic \
+ include/row0ins.h \
+ include/row0ins.ic \
+ include/row0merge.h \
+ include/row0mysql.h \
+ include/row0mysql.ic \
+ include/row0purge.h \
+ include/row0purge.ic \
+ include/row0row.h \
+ include/row0row.ic \
+ include/row0sel.h \
+ include/row0sel.ic \
+ include/row0types.h \
+ include/row0uins.h \
+ include/row0uins.ic \
+ include/row0umod.h \
+ include/row0umod.ic \
+ include/row0undo.h \
+ include/row0undo.ic \
+ include/row0upd.h \
+ include/row0upd.ic \
+ include/row0vers.h \
+ include/row0vers.ic \
+ include/srv0que.h \
+ include/srv0srv.h \
+ include/srv0srv.ic \
+ include/srv0start.h \
+ include/sync0arr.h \
+ include/sync0arr.ic \
+ include/sync0rw.h \
+ include/sync0rw.ic \
+ include/sync0sync.h \
+ include/sync0sync.ic \
+ include/sync0types.h \
+ include/thr0loc.h \
+ include/thr0loc.ic \
+ include/trx0i_s.h \
+ include/trx0purge.h \
+ include/trx0purge.ic \
+ include/trx0rec.h \
+ include/trx0rec.ic \
+ include/trx0roll.h \
+ include/trx0roll.ic \
+ include/trx0rseg.h \
+ include/trx0rseg.ic \
+ include/trx0sys.h \
+ include/trx0sys.ic \
+ include/trx0trx.h \
+ include/trx0trx.ic \
+ include/trx0types.h \
+ include/trx0undo.h \
+ include/trx0undo.ic \
+ include/trx0xa.h \
+ include/univ.i \
+ include/usr0sess.h \
+ include/usr0sess.ic \
+ include/usr0types.h \
+ include/ut0auxconf.h \
+ include/ut0byte.h \
+ include/ut0byte.ic \
+ include/ut0dbg.h \
+ include/ut0list.h \
+ include/ut0list.ic \
+ include/ut0lst.h \
+ include/ut0mem.h \
+ include/ut0mem.ic \
+ include/ut0rnd.h \
+ include/ut0rnd.ic \
+ include/ut0sort.h \
+ include/ut0ut.h \
+ include/ut0ut.ic \
+ include/ut0vec.h \
+ include/ut0vec.ic \
+ include/ut0wqueue.h \
+ mem/mem0dbg.c
+
+EXTRA_LIBRARIES= libinnobase.a
+noinst_LIBRARIES= @plugin_innodb_plugin_static_target@
+libinnobase_a_SOURCES= \
+ btr/btr0btr.c \
+ btr/btr0cur.c \
+ btr/btr0pcur.c \
+ btr/btr0sea.c \
+ buf/buf0buddy.c \
+ buf/buf0buf.c \
+ buf/buf0flu.c \
+ buf/buf0lru.c \
+ buf/buf0rea.c \
+ data/data0data.c \
+ data/data0type.c \
+ dict/dict0boot.c \
+ dict/dict0crea.c \
+ dict/dict0dict.c \
+ dict/dict0load.c \
+ dict/dict0mem.c \
+ dyn/dyn0dyn.c \
+ eval/eval0eval.c \
+ eval/eval0proc.c \
+ fil/fil0fil.c \
+ fsp/fsp0fsp.c \
+ fut/fut0fut.c \
+ fut/fut0lst.c \
+ ha/ha0ha.c \
+ ha/ha0storage.c \
+ ha/hash0hash.c \
+ handler/ha_innodb.cc \
+ handler/handler0alter.cc \
+ handler/i_s.cc \
+ handler/mysql_addons.cc \
+ 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 \
+ os/os0sync.c \
+ os/os0thread.c \
+ page/page0cur.c \
+ page/page0page.c \
+ page/page0zip.c \
+ pars/lexyy.c \
+ pars/pars0grm.c \
+ pars/pars0opt.c \
+ pars/pars0pars.c \
+ pars/pars0sym.c \
+ que/que0que.c \
+ read/read0read.c \
+ rem/rem0cmp.c \
+ rem/rem0rec.c \
+ row/row0ext.c \
+ row/row0ins.c \
+ row/row0merge.c \
+ row/row0mysql.c \
+ row/row0purge.c \
+ row/row0row.c \
+ row/row0sel.c \
+ row/row0uins.c \
+ row/row0umod.c \
+ row/row0undo.c \
+ row/row0upd.c \
+ row/row0vers.c \
+ srv/srv0que.c \
+ srv/srv0srv.c \
+ srv/srv0start.c \
+ sync/sync0arr.c \
+ sync/sync0rw.c \
+ sync/sync0sync.c \
+ thr/thr0loc.c \
+ trx/trx0i_s.c \
+ trx/trx0purge.c \
+ trx/trx0rec.c \
+ trx/trx0roll.c \
+ trx/trx0rseg.c \
+ trx/trx0sys.c \
+ trx/trx0trx.c \
+ trx/trx0undo.c \
+ usr/usr0sess.c \
+ ut/ut0byte.c \
+ ut/ut0dbg.c \
+ ut/ut0list.c \
+ ut/ut0mem.c \
+ ut/ut0rnd.c \
+ ut/ut0ut.c \
+ ut/ut0vec.c \
+ ut/ut0wqueue.c
+
+libinnobase_a_CXXFLAGS= $(AM_CFLAGS)
+libinnobase_a_CFLAGS= $(AM_CFLAGS)
+
+EXTRA_LTLIBRARIES= ha_innodb_plugin.la
+pkgplugin_LTLIBRARIES= @plugin_innodb_plugin_shared_target@
+
+ha_innodb_plugin_la_LDFLAGS= -module -rpath $(pkgplugindir)
+ha_innodb_plugin_la_CXXFLAGS= $(AM_CFLAGS) $(INNODB_DYNAMIC_CFLAGS)
+ha_innodb_plugin_la_CFLAGS= $(AM_CFLAGS) $(INNODB_DYNAMIC_CFLAGS)
+ha_innodb_plugin_la_SOURCES= $(libinnobase_a_SOURCES)
+
+EXTRA_DIST= CMakeLists.txt plug.in \
+ pars/make_bison.sh pars/make_flex.sh \
+ pars/pars0grm.y pars/pars0lex.l
+
+# Don't update the files from bitkeeper
+%::SCCS/s.%
diff --git a/storage/innodb_plugin/README b/storage/innodb_plugin/README
new file mode 100644
index 00000000000..56aa8058224
--- /dev/null
+++ b/storage/innodb_plugin/README
@@ -0,0 +1,29 @@
+This is the source of the InnoDB Plugin 1.0.4 for MySQL 5.1
+===========================================================
+
+Instructions for compiling the plugin:
+--------------------------------------
+
+1. Get the latest MySQL 5.1 sources from
+ http://dev.mysql.com/downloads/mysql/5.1.html#source
+
+2. Replace the contents of the mysql-5.1.N/storage/innobase/ directory
+ with the contents of this directory.
+
+3. Optional (only necessary if you are going to run tests from the
+ mysql-test suite): cd into the innobase directory and run ./setup.sh
+
+4. Compile MySQL as usual.
+
+5. Enjoy!
+
+See the online documentation for more detailed instructions:
+http://www.innodb.com/doc/innodb_plugin-1.0/innodb-plugin-installation.html
+
+For more information about InnoDB visit
+http://www.innodb.com
+
+Please report any problems or issues with the plugin in the InnoDB Forums
+http://forums.innodb.com/ or in the MySQL Bugs database http://bugs.mysql.com
+
+Thank you for using the InnoDB plugin!
diff --git a/storage/innodb_plugin/btr/btr0btr.c b/storage/innodb_plugin/btr/btr0btr.c
new file mode 100644
index 00000000000..6ba9b36207b
--- /dev/null
+++ b/storage/innodb_plugin/btr/btr0btr.c
@@ -0,0 +1,3693 @@
+/*****************************************************************************
+
+Copyright (c) 1994, 2009, Innobase Oy. All Rights Reserved.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; version 2 of the License.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place, Suite 330, Boston, MA 02111-1307 USA
+
+*****************************************************************************/
+
+/**************************************************//**
+@file btr/btr0btr.c
+The B-tree
+
+Created 6/2/1994 Heikki Tuuri
+*******************************************************/
+
+#include "btr0btr.h"
+
+#ifdef UNIV_NONINL
+#include "btr0btr.ic"
+#endif
+
+#include "fsp0fsp.h"
+#include "page0page.h"
+#include "page0zip.h"
+
+#ifndef UNIV_HOTBACKUP
+#include "btr0cur.h"
+#include "btr0sea.h"
+#include "btr0pcur.h"
+#include "rem0cmp.h"
+#include "lock0lock.h"
+#include "ibuf0ibuf.h"
+#include "trx0trx.h"
+
+/*
+Latching strategy of the InnoDB B-tree
+--------------------------------------
+A tree latch protects all non-leaf nodes of the tree. Each node of a tree
+also has a latch of its own.
+
+A B-tree operation normally first acquires an S-latch on the tree. It
+searches down the tree and releases the tree latch when it has the
+leaf node latch. To save CPU time we do not acquire any latch on
+non-leaf nodes of the tree during a search, those pages are only bufferfixed.
+
+If an operation needs to restructure the tree, it acquires an X-latch on
+the tree before searching to a leaf node. If it needs, for example, to
+split a leaf,
+(1) InnoDB decides the split point in the leaf,
+(2) allocates a new page,
+(3) inserts the appropriate node pointer to the first non-leaf level,
+(4) releases the tree X-latch,
+(5) and then moves records from the leaf to the new allocated page.
+
+Node pointers
+-------------
+Leaf pages of a B-tree contain the index records stored in the
+tree. On levels n > 0 we store 'node pointers' to pages on level
+n - 1. For each page there is exactly one node pointer stored:
+thus the our tree is an ordinary B-tree, not a B-link tree.
+
+A node pointer contains a prefix P of an index record. The prefix
+is long enough so that it determines an index record uniquely.
+The file page number of the child page is added as the last
+field. To the child page we can store node pointers or index records
+which are >= P in the alphabetical order, but < P1 if there is
+a next node pointer on the level, and P1 is its prefix.
+
+If a node pointer with a prefix P points to a non-leaf child,
+then the leftmost record in the child must have the same
+prefix P. If it points to a leaf node, the child is not required
+to contain any record with a prefix equal to P. The leaf case
+is decided this way to allow arbitrary deletions in a leaf node
+without touching upper levels of the tree.
+
+We have predefined a special minimum record which we
+define as the smallest record in any alphabetical order.
+A minimum record is denoted by setting a bit in the record
+header. A minimum record acts as the prefix of a node pointer
+which points to a leftmost node on any level of the tree.
+
+File page allocation
+--------------------
+In the root node of a B-tree there are two file segment headers.
+The leaf pages of a tree are allocated from one file segment, to
+make them consecutive on disk if possible. From the other file segment
+we allocate pages for the non-leaf levels of the tree.
+*/
+
+#ifdef UNIV_BTR_DEBUG
+/**************************************************************//**
+Checks a file segment header within a B-tree root page.
+@return TRUE if valid */
+static
+ibool
+btr_root_fseg_validate(
+/*===================*/
+ const fseg_header_t* seg_header, /*!< in: segment header */
+ ulint space) /*!< in: tablespace identifier */
+{
+ ulint offset = mach_read_from_2(seg_header + FSEG_HDR_OFFSET);
+
+ ut_a(mach_read_from_4(seg_header + FSEG_HDR_SPACE) == space);
+ ut_a(offset >= FIL_PAGE_DATA);
+ ut_a(offset <= UNIV_PAGE_SIZE - FIL_PAGE_DATA_END);
+ return(TRUE);
+}
+#endif /* UNIV_BTR_DEBUG */
+
+/**************************************************************//**
+Gets the root node of a tree and x-latches it.
+@return root page, x-latched */
+static
+buf_block_t*
+btr_root_block_get(
+/*===============*/
+ dict_index_t* index, /*!< in: index tree */
+ mtr_t* mtr) /*!< in: mtr */
+{
+ ulint space;
+ ulint zip_size;
+ ulint root_page_no;
+ buf_block_t* block;
+
+ space = dict_index_get_space(index);
+ zip_size = dict_table_zip_size(index->table);
+ root_page_no = dict_index_get_page(index);
+
+ block = btr_block_get(space, zip_size, root_page_no, RW_X_LATCH, mtr);
+ ut_a((ibool)!!page_is_comp(buf_block_get_frame(block))
+ == dict_table_is_comp(index->table));
+#ifdef UNIV_BTR_DEBUG
+ if (!dict_index_is_ibuf(index)) {
+ const page_t* root = buf_block_get_frame(block);
+
+ ut_a(btr_root_fseg_validate(FIL_PAGE_DATA + PAGE_BTR_SEG_LEAF
+ + root, space));
+ ut_a(btr_root_fseg_validate(FIL_PAGE_DATA + PAGE_BTR_SEG_TOP
+ + root, space));
+ }
+#endif /* UNIV_BTR_DEBUG */
+
+ return(block);
+}
+
+/**************************************************************//**
+Gets the root node of a tree and x-latches it.
+@return root page, x-latched */
+UNIV_INTERN
+page_t*
+btr_root_get(
+/*=========*/
+ dict_index_t* index, /*!< in: index tree */
+ mtr_t* mtr) /*!< in: mtr */
+{
+ return(buf_block_get_frame(btr_root_block_get(index, mtr)));
+}
+
+/*************************************************************//**
+Gets pointer to the previous user record in the tree. It is assumed that
+the caller has appropriate latches on the page and its neighbor.
+@return previous user record, NULL if there is none */
+UNIV_INTERN
+rec_t*
+btr_get_prev_user_rec(
+/*==================*/
+ rec_t* rec, /*!< in: record on leaf level */
+ mtr_t* mtr) /*!< in: mtr holding a latch on the page, and if
+ needed, also to the previous page */
+{
+ page_t* page;
+ page_t* prev_page;
+ ulint prev_page_no;
+
+ if (!page_rec_is_infimum(rec)) {
+
+ rec_t* prev_rec = page_rec_get_prev(rec);
+
+ if (!page_rec_is_infimum(prev_rec)) {
+
+ return(prev_rec);
+ }
+ }
+
+ page = page_align(rec);
+ prev_page_no = btr_page_get_prev(page, mtr);
+
+ if (prev_page_no != FIL_NULL) {
+
+ ulint space;
+ ulint zip_size;
+ buf_block_t* prev_block;
+
+ space = page_get_space_id(page);
+ zip_size = fil_space_get_zip_size(space);
+
+ prev_block = buf_page_get_with_no_latch(space, zip_size,
+ prev_page_no, mtr);
+ prev_page = buf_block_get_frame(prev_block);
+ /* The caller must already have a latch to the brother */
+ ut_ad(mtr_memo_contains(mtr, prev_block,
+ MTR_MEMO_PAGE_S_FIX)
+ || mtr_memo_contains(mtr, prev_block,
+ MTR_MEMO_PAGE_X_FIX));
+#ifdef UNIV_BTR_DEBUG
+ ut_a(page_is_comp(prev_page) == page_is_comp(page));
+ ut_a(btr_page_get_next(prev_page, mtr)
+ == page_get_page_no(page));
+#endif /* UNIV_BTR_DEBUG */
+
+ return(page_rec_get_prev(page_get_supremum_rec(prev_page)));
+ }
+
+ return(NULL);
+}
+
+/*************************************************************//**
+Gets pointer to the next user record in the tree. It is assumed that the
+caller has appropriate latches on the page and its neighbor.
+@return next user record, NULL if there is none */
+UNIV_INTERN
+rec_t*
+btr_get_next_user_rec(
+/*==================*/
+ rec_t* rec, /*!< in: record on leaf level */
+ mtr_t* mtr) /*!< in: mtr holding a latch on the page, and if
+ needed, also to the next page */
+{
+ page_t* page;
+ page_t* next_page;
+ ulint next_page_no;
+
+ if (!page_rec_is_supremum(rec)) {
+
+ rec_t* next_rec = page_rec_get_next(rec);
+
+ if (!page_rec_is_supremum(next_rec)) {
+
+ return(next_rec);
+ }
+ }
+
+ page = page_align(rec);
+ next_page_no = btr_page_get_next(page, mtr);
+
+ if (next_page_no != FIL_NULL) {
+ ulint space;
+ ulint zip_size;
+ buf_block_t* next_block;
+
+ space = page_get_space_id(page);
+ zip_size = fil_space_get_zip_size(space);
+
+ next_block = buf_page_get_with_no_latch(space, zip_size,
+ next_page_no, mtr);
+ next_page = buf_block_get_frame(next_block);
+ /* The caller must already have a latch to the brother */
+ ut_ad(mtr_memo_contains(mtr, next_block, MTR_MEMO_PAGE_S_FIX)
+ || mtr_memo_contains(mtr, next_block,
+ MTR_MEMO_PAGE_X_FIX));
+#ifdef UNIV_BTR_DEBUG
+ ut_a(page_is_comp(next_page) == page_is_comp(page));
+ ut_a(btr_page_get_prev(next_page, mtr)
+ == page_get_page_no(page));
+#endif /* UNIV_BTR_DEBUG */
+
+ return(page_rec_get_next(page_get_infimum_rec(next_page)));
+ }
+
+ return(NULL);
+}
+
+/**************************************************************//**
+Creates a new index page (not the root, and also not
+used in page reorganization). @see btr_page_empty(). */
+static
+void
+btr_page_create(
+/*============*/
+ buf_block_t* block, /*!< in/out: page to be created */
+ page_zip_des_t* page_zip,/*!< in/out: compressed page, or NULL */
+ dict_index_t* index, /*!< in: index */
+ ulint level, /*!< in: the B-tree level of the page */
+ mtr_t* mtr) /*!< in: mtr */
+{
+ page_t* page = buf_block_get_frame(block);
+
+ ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX));
+
+ if (UNIV_LIKELY_NULL(page_zip)) {
+ page_create_zip(block, index, level, mtr);
+ } else {
+ page_create(block, mtr, dict_table_is_comp(index->table));
+ /* Set the level of the new index page */
+ btr_page_set_level(page, NULL, level, mtr);
+ }
+
+ block->check_index_page_at_flush = TRUE;
+
+ btr_page_set_index_id(page, page_zip, index->id, mtr);
+}
+
+/**************************************************************//**
+Allocates a new file page to be used in an ibuf tree. Takes the page from
+the free list of the tree, which must contain pages!
+@return new allocated block, x-latched */
+static
+buf_block_t*
+btr_page_alloc_for_ibuf(
+/*====================*/
+ dict_index_t* index, /*!< in: index tree */
+ mtr_t* mtr) /*!< in: mtr */
+{
+ fil_addr_t node_addr;
+ page_t* root;
+ page_t* new_page;
+ buf_block_t* new_block;
+
+ root = btr_root_get(index, mtr);
+
+ node_addr = flst_get_first(root + PAGE_HEADER
+ + PAGE_BTR_IBUF_FREE_LIST, mtr);
+ ut_a(node_addr.page != FIL_NULL);
+
+ new_block = buf_page_get(dict_index_get_space(index),
+ dict_table_zip_size(index->table),
+ node_addr.page, RW_X_LATCH, mtr);
+ new_page = buf_block_get_frame(new_block);
+ buf_block_dbg_add_level(new_block, SYNC_TREE_NODE_NEW);
+
+ flst_remove(root + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST,
+ new_page + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST_NODE,
+ mtr);
+ ut_ad(flst_validate(root + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST,
+ mtr));
+
+ return(new_block);
+}
+
+/**************************************************************//**
+Allocates a new file page to be used in an index tree. NOTE: we assume
+that the caller has made the reservation for free extents!
+@return new allocated block, x-latched; NULL if out of space */
+UNIV_INTERN
+buf_block_t*
+btr_page_alloc(
+/*===========*/
+ dict_index_t* index, /*!< in: index */
+ ulint hint_page_no, /*!< in: hint of a good page */
+ byte file_direction, /*!< in: direction where a possible
+ page split is made */
+ ulint level, /*!< in: level where the page is placed
+ in the tree */
+ mtr_t* mtr) /*!< in: mtr */
+{
+ fseg_header_t* seg_header;
+ page_t* root;
+ buf_block_t* new_block;
+ ulint new_page_no;
+
+ if (dict_index_is_ibuf(index)) {
+
+ return(btr_page_alloc_for_ibuf(index, mtr));
+ }
+
+ root = btr_root_get(index, mtr);
+
+ if (level == 0) {
+ seg_header = root + PAGE_HEADER + PAGE_BTR_SEG_LEAF;
+ } else {
+ seg_header = root + PAGE_HEADER + PAGE_BTR_SEG_TOP;
+ }
+
+ /* Parameter TRUE below states that the caller has made the
+ reservation for free extents, and thus we know that a page can
+ be allocated: */
+
+ new_page_no = fseg_alloc_free_page_general(seg_header, hint_page_no,
+ file_direction, TRUE, mtr);
+ if (new_page_no == FIL_NULL) {
+
+ return(NULL);
+ }
+
+ new_block = buf_page_get(dict_index_get_space(index),
+ dict_table_zip_size(index->table),
+ new_page_no, RW_X_LATCH, mtr);
+ buf_block_dbg_add_level(new_block, SYNC_TREE_NODE_NEW);
+
+ return(new_block);
+}
+
+/**************************************************************//**
+Gets the number of pages in a B-tree.
+@return number of pages */
+UNIV_INTERN
+ulint
+btr_get_size(
+/*=========*/
+ dict_index_t* index, /*!< in: index */
+ ulint flag) /*!< in: BTR_N_LEAF_PAGES or BTR_TOTAL_SIZE */
+{
+ fseg_header_t* seg_header;
+ page_t* root;
+ ulint n;
+ ulint dummy;
+ mtr_t mtr;
+
+ mtr_start(&mtr);
+
+ mtr_s_lock(dict_index_get_lock(index), &mtr);
+
+ root = btr_root_get(index, &mtr);
+
+ if (flag == BTR_N_LEAF_PAGES) {
+ seg_header = root + PAGE_HEADER + PAGE_BTR_SEG_LEAF;
+
+ fseg_n_reserved_pages(seg_header, &n, &mtr);
+
+ } else if (flag == BTR_TOTAL_SIZE) {
+ seg_header = root + PAGE_HEADER + PAGE_BTR_SEG_TOP;
+
+ n = fseg_n_reserved_pages(seg_header, &dummy, &mtr);
+
+ seg_header = root + PAGE_HEADER + PAGE_BTR_SEG_LEAF;
+
+ n += fseg_n_reserved_pages(seg_header, &dummy, &mtr);
+ } else {
+ ut_error;
+ }
+
+ mtr_commit(&mtr);
+
+ return(n);
+}
+
+/**************************************************************//**
+Frees a page used in an ibuf tree. Puts the page to the free list of the
+ibuf tree. */
+static
+void
+btr_page_free_for_ibuf(
+/*===================*/
+ dict_index_t* index, /*!< in: index tree */
+ buf_block_t* block, /*!< in: block to be freed, x-latched */
+ mtr_t* mtr) /*!< in: mtr */
+{
+ page_t* root;
+
+ ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX));
+ root = btr_root_get(index, mtr);
+
+ flst_add_first(root + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST,
+ buf_block_get_frame(block)
+ + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST_NODE, mtr);
+
+ ut_ad(flst_validate(root + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST,
+ mtr));
+}
+
+/**************************************************************//**
+Frees a file page used in an index tree. Can be used also to (BLOB)
+external storage pages, because the page level 0 can be given as an
+argument. */
+UNIV_INTERN
+void
+btr_page_free_low(
+/*==============*/
+ dict_index_t* index, /*!< in: index tree */
+ buf_block_t* block, /*!< in: block to be freed, x-latched */
+ ulint level, /*!< in: page level */
+ mtr_t* mtr) /*!< in: mtr */
+{
+ fseg_header_t* seg_header;
+ page_t* root;
+
+ ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX));
+ /* The page gets invalid for optimistic searches: increment the frame
+ modify clock */
+
+ buf_block_modify_clock_inc(block);
+
+ if (dict_index_is_ibuf(index)) {
+
+ btr_page_free_for_ibuf(index, block, mtr);
+
+ return;
+ }
+
+ root = btr_root_get(index, mtr);
+
+ if (level == 0) {
+ seg_header = root + PAGE_HEADER + PAGE_BTR_SEG_LEAF;
+ } else {
+ seg_header = root + PAGE_HEADER + PAGE_BTR_SEG_TOP;
+ }
+
+ fseg_free_page(seg_header,
+ buf_block_get_space(block),
+ buf_block_get_page_no(block), mtr);
+}
+
+/**************************************************************//**
+Frees a file page used in an index tree. NOTE: cannot free field external
+storage pages because the page must contain info on its level. */
+UNIV_INTERN
+void
+btr_page_free(
+/*==========*/
+ dict_index_t* index, /*!< in: index tree */
+ buf_block_t* block, /*!< in: block to be freed, x-latched */
+ mtr_t* mtr) /*!< in: mtr */
+{
+ ulint level;
+
+ level = btr_page_get_level(buf_block_get_frame(block), mtr);
+
+ btr_page_free_low(index, block, level, mtr);
+}
+
+/**************************************************************//**
+Sets the child node file address in a node pointer. */
+UNIV_INLINE
+void
+btr_node_ptr_set_child_page_no(
+/*===========================*/
+ rec_t* rec, /*!< in: node pointer record */
+ page_zip_des_t* page_zip,/*!< in/out: compressed page whose uncompressed
+ part will be updated, or NULL */
+ const ulint* offsets,/*!< in: array returned by rec_get_offsets() */
+ ulint page_no,/*!< in: child node address */
+ mtr_t* mtr) /*!< in: mtr */
+{
+ byte* field;
+ ulint len;
+
+ ut_ad(rec_offs_validate(rec, NULL, offsets));
+ ut_ad(!page_is_leaf(page_align(rec)));
+ ut_ad(!rec_offs_comp(offsets) || rec_get_node_ptr_flag(rec));
+
+ /* The child address is in the last field */
+ field = rec_get_nth_field(rec, offsets,
+ rec_offs_n_fields(offsets) - 1, &len);
+
+ ut_ad(len == REC_NODE_PTR_SIZE);
+
+ if (UNIV_LIKELY_NULL(page_zip)) {
+ page_zip_write_node_ptr(page_zip, rec,
+ rec_offs_data_size(offsets),
+ page_no, mtr);
+ } else {
+ mlog_write_ulint(field, page_no, MLOG_4BYTES, mtr);
+ }
+}
+
+/************************************************************//**
+Returns the child page of a node pointer and x-latches it.
+@return child page, x-latched */
+static
+buf_block_t*
+btr_node_ptr_get_child(
+/*===================*/
+ const rec_t* node_ptr,/*!< in: node pointer */
+ dict_index_t* index, /*!< in: index */
+ const ulint* offsets,/*!< in: array returned by rec_get_offsets() */
+ mtr_t* mtr) /*!< in: mtr */
+{
+ ulint page_no;
+ ulint space;
+
+ ut_ad(rec_offs_validate(node_ptr, index, offsets));
+ space = page_get_space_id(page_align(node_ptr));
+ page_no = btr_node_ptr_get_child_page_no(node_ptr, offsets);
+
+ return(btr_block_get(space, dict_table_zip_size(index->table),
+ page_no, RW_X_LATCH, mtr));
+}
+
+/************************************************************//**
+Returns the upper level node pointer to a page. It is assumed that mtr holds
+an x-latch on the tree.
+@return rec_get_offsets() of the node pointer record */
+static
+ulint*
+btr_page_get_father_node_ptr(
+/*=========================*/
+ ulint* offsets,/*!< in: work area for the return value */
+ mem_heap_t* heap, /*!< in: memory heap to use */
+ btr_cur_t* cursor, /*!< in: cursor pointing to user record,
+ out: cursor on node pointer record,
+ its page x-latched */
+ mtr_t* mtr) /*!< in: mtr */
+{
+ dtuple_t* tuple;
+ rec_t* user_rec;
+ rec_t* node_ptr;
+ ulint level;
+ ulint page_no;
+ dict_index_t* index;
+
+ page_no = buf_block_get_page_no(btr_cur_get_block(cursor));
+ index = btr_cur_get_index(cursor);
+
+ ut_ad(mtr_memo_contains(mtr, dict_index_get_lock(index),
+ MTR_MEMO_X_LOCK));
+
+ ut_ad(dict_index_get_page(index) != page_no);
+
+ level = btr_page_get_level(btr_cur_get_page(cursor), mtr);
+ user_rec = btr_cur_get_rec(cursor);
+ ut_a(page_rec_is_user_rec(user_rec));
+ tuple = dict_index_build_node_ptr(index, user_rec, 0, heap, level);
+
+ btr_cur_search_to_nth_level(index, level + 1, tuple, PAGE_CUR_LE,
+ BTR_CONT_MODIFY_TREE, cursor, 0, mtr);
+
+ node_ptr = btr_cur_get_rec(cursor);
+ ut_ad(!page_rec_is_comp(node_ptr)
+ || rec_get_status(node_ptr) == REC_STATUS_NODE_PTR);
+ offsets = rec_get_offsets(node_ptr, index, offsets,
+ ULINT_UNDEFINED, &heap);
+
+ if (UNIV_UNLIKELY(btr_node_ptr_get_child_page_no(node_ptr, offsets)
+ != page_no)) {
+ rec_t* print_rec;
+ fputs("InnoDB: Dump of the child page:\n", stderr);
+ buf_page_print(page_align(user_rec), 0);
+ fputs("InnoDB: Dump of the parent page:\n", stderr);
+ buf_page_print(page_align(node_ptr), 0);
+
+ fputs("InnoDB: Corruption of an index tree: table ", stderr);
+ ut_print_name(stderr, NULL, TRUE, index->table_name);
+ fputs(", index ", stderr);
+ ut_print_name(stderr, NULL, FALSE, index->name);
+ fprintf(stderr, ",\n"
+ "InnoDB: father ptr page no %lu, child page no %lu\n",
+ (ulong)
+ btr_node_ptr_get_child_page_no(node_ptr, offsets),
+ (ulong) page_no);
+ print_rec = page_rec_get_next(
+ page_get_infimum_rec(page_align(user_rec)));
+ offsets = rec_get_offsets(print_rec, index,
+ offsets, ULINT_UNDEFINED, &heap);
+ page_rec_print(print_rec, offsets);
+ offsets = rec_get_offsets(node_ptr, index, offsets,
+ ULINT_UNDEFINED, &heap);
+ page_rec_print(node_ptr, offsets);
+
+ fputs("InnoDB: You should dump + drop + reimport the table"
+ " to fix the\n"
+ "InnoDB: corruption. If the crash happens at "
+ "the database startup, see\n"
+ "InnoDB: " REFMAN "forcing-recovery.html about\n"
+ "InnoDB: forcing recovery. "
+ "Then dump + drop + reimport.\n", stderr);
+
+ ut_error;
+ }
+
+ return(offsets);
+}
+
+/************************************************************//**
+Returns the upper level node pointer to a page. It is assumed that mtr holds
+an x-latch on the tree.
+@return rec_get_offsets() of the node pointer record */
+static
+ulint*
+btr_page_get_father_block(
+/*======================*/
+ ulint* offsets,/*!< in: work area for the return value */
+ mem_heap_t* heap, /*!< in: memory heap to use */
+ dict_index_t* index, /*!< in: b-tree index */
+ buf_block_t* block, /*!< in: child page in the index */
+ mtr_t* mtr, /*!< in: mtr */
+ btr_cur_t* cursor) /*!< out: cursor on node pointer record,
+ its page x-latched */
+{
+ rec_t* rec
+ = page_rec_get_next(page_get_infimum_rec(buf_block_get_frame(
+ block)));
+ btr_cur_position(index, rec, block, cursor);
+ return(btr_page_get_father_node_ptr(offsets, heap, cursor, mtr));
+}
+
+/************************************************************//**
+Seeks to the upper level node pointer to a page.
+It is assumed that mtr holds an x-latch on the tree. */
+static
+void
+btr_page_get_father(
+/*================*/
+ dict_index_t* index, /*!< in: b-tree index */
+ buf_block_t* block, /*!< in: child page in the index */
+ mtr_t* mtr, /*!< in: mtr */
+ btr_cur_t* cursor) /*!< out: cursor on node pointer record,
+ its page x-latched */
+{
+ mem_heap_t* heap;
+ rec_t* rec
+ = page_rec_get_next(page_get_infimum_rec(buf_block_get_frame(
+ block)));
+ btr_cur_position(index, rec, block, cursor);
+
+ heap = mem_heap_create(100);
+ btr_page_get_father_node_ptr(NULL, heap, cursor, mtr);
+ mem_heap_free(heap);
+}
+
+/************************************************************//**
+Creates the root node for a new index tree.
+@return page number of the created root, FIL_NULL if did not succeed */
+UNIV_INTERN
+ulint
+btr_create(
+/*=======*/
+ ulint type, /*!< in: type of the index */
+ ulint space, /*!< in: space where created */
+ ulint zip_size,/*!< in: compressed page size in bytes
+ or 0 for uncompressed pages */
+ dulint index_id,/*!< in: index id */
+ dict_index_t* index, /*!< in: index */
+ mtr_t* mtr) /*!< in: mini-transaction handle */
+{
+ ulint page_no;
+ buf_block_t* block;
+ buf_frame_t* frame;
+ page_t* page;
+ page_zip_des_t* page_zip;
+
+ /* Create the two new segments (one, in the case of an ibuf tree) for
+ the index tree; the segment headers are put on the allocated root page
+ (for an ibuf tree, not in the root, but on a separate ibuf header
+ page) */
+
+ if (type & DICT_IBUF) {
+ /* Allocate first the ibuf header page */
+ buf_block_t* ibuf_hdr_block = fseg_create(
+ space, 0,
+ IBUF_HEADER + IBUF_TREE_SEG_HEADER, mtr);
+
+ buf_block_dbg_add_level(ibuf_hdr_block, SYNC_TREE_NODE_NEW);
+
+ ut_ad(buf_block_get_page_no(ibuf_hdr_block)
+ == IBUF_HEADER_PAGE_NO);
+ /* Allocate then the next page to the segment: it will be the
+ tree root page */
+
+ page_no = fseg_alloc_free_page(buf_block_get_frame(
+ ibuf_hdr_block)
+ + IBUF_HEADER
+ + IBUF_TREE_SEG_HEADER,
+ IBUF_TREE_ROOT_PAGE_NO,
+ FSP_UP, mtr);
+ ut_ad(page_no == IBUF_TREE_ROOT_PAGE_NO);
+
+ block = buf_page_get(space, zip_size, page_no,
+ RW_X_LATCH, mtr);
+ } else {
+ block = fseg_create(space, 0,
+ PAGE_HEADER + PAGE_BTR_SEG_TOP, mtr);
+ }
+
+ if (block == NULL) {
+
+ return(FIL_NULL);
+ }
+
+ page_no = buf_block_get_page_no(block);
+ frame = buf_block_get_frame(block);
+
+ buf_block_dbg_add_level(block, SYNC_TREE_NODE_NEW);
+
+ if (type & DICT_IBUF) {
+ /* It is an insert buffer tree: initialize the free list */
+
+ ut_ad(page_no == IBUF_TREE_ROOT_PAGE_NO);
+
+ flst_init(frame + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST, mtr);
+ } else {
+ /* It is a non-ibuf tree: create a file segment for leaf
+ pages */
+ fseg_create(space, page_no,
+ PAGE_HEADER + PAGE_BTR_SEG_LEAF, mtr);
+ /* The fseg create acquires a second latch on the page,
+ therefore we must declare it: */
+ buf_block_dbg_add_level(block, SYNC_TREE_NODE_NEW);
+ }
+
+ /* Create a new index page on the the allocated segment page */
+ page_zip = buf_block_get_page_zip(block);
+
+ if (UNIV_LIKELY_NULL(page_zip)) {
+ page = page_create_zip(block, index, 0, mtr);
+ } else {
+ page = page_create(block, mtr,
+ dict_table_is_comp(index->table));
+ /* Set the level of the new index page */
+ btr_page_set_level(page, NULL, 0, mtr);
+ }
+
+ block->check_index_page_at_flush = TRUE;
+
+ /* Set the index id of the page */
+ btr_page_set_index_id(page, page_zip, index_id, mtr);
+
+ /* Set the next node and previous node fields */
+ btr_page_set_next(page, page_zip, FIL_NULL, mtr);
+ btr_page_set_prev(page, page_zip, FIL_NULL, mtr);
+
+ /* We reset the free bits for the page to allow creation of several
+ trees in the same mtr, otherwise the latch on a bitmap page would
+ prevent it because of the latching order */
+
+ if (!(type & DICT_CLUSTERED)) {
+ ibuf_reset_free_bits(block);
+ }
+
+ /* In the following assertion we test that two records of maximum
+ allowed size fit on the root page: this fact is needed to ensure
+ correctness of split algorithms */
+
+ ut_ad(page_get_max_insert_size(page, 2) > 2 * BTR_PAGE_MAX_REC_SIZE);
+
+ return(page_no);
+}
+
+/************************************************************//**
+Frees a B-tree except the root page, which MUST be freed after this
+by calling btr_free_root. */
+UNIV_INTERN
+void
+btr_free_but_not_root(
+/*==================*/
+ ulint space, /*!< in: space where created */
+ ulint zip_size, /*!< in: compressed page size in bytes
+ or 0 for uncompressed pages */
+ ulint root_page_no) /*!< in: root page number */
+{
+ ibool finished;
+ page_t* root;
+ mtr_t mtr;
+
+leaf_loop:
+ mtr_start(&mtr);
+
+ root = btr_page_get(space, zip_size, root_page_no, RW_X_LATCH, &mtr);
+#ifdef UNIV_BTR_DEBUG
+ ut_a(btr_root_fseg_validate(FIL_PAGE_DATA + PAGE_BTR_SEG_LEAF
+ + root, space));
+ ut_a(btr_root_fseg_validate(FIL_PAGE_DATA + PAGE_BTR_SEG_TOP
+ + root, space));
+#endif /* UNIV_BTR_DEBUG */
+
+ /* NOTE: page hash indexes are dropped when a page is freed inside
+ fsp0fsp. */
+
+ finished = fseg_free_step(root + PAGE_HEADER + PAGE_BTR_SEG_LEAF,
+ &mtr);
+ mtr_commit(&mtr);
+
+ if (!finished) {
+
+ goto leaf_loop;
+ }
+top_loop:
+ mtr_start(&mtr);
+
+ root = btr_page_get(space, zip_size, root_page_no, RW_X_LATCH, &mtr);
+#ifdef UNIV_BTR_DEBUG
+ ut_a(btr_root_fseg_validate(FIL_PAGE_DATA + PAGE_BTR_SEG_TOP
+ + root, space));
+#endif /* UNIV_BTR_DEBUG */
+
+ finished = fseg_free_step_not_header(
+ root + PAGE_HEADER + PAGE_BTR_SEG_TOP, &mtr);
+ mtr_commit(&mtr);
+
+ if (!finished) {
+
+ goto top_loop;
+ }
+}
+
+/************************************************************//**
+Frees the B-tree root page. Other tree MUST already have been freed. */
+UNIV_INTERN
+void
+btr_free_root(
+/*==========*/
+ ulint space, /*!< in: space where created */
+ ulint zip_size, /*!< in: compressed page size in bytes
+ or 0 for uncompressed pages */
+ ulint root_page_no, /*!< in: root page number */
+ mtr_t* mtr) /*!< in: a mini-transaction which has already
+ been started */
+{
+ buf_block_t* block;
+ fseg_header_t* header;
+
+ block = btr_block_get(space, zip_size, root_page_no, RW_X_LATCH, mtr);
+
+ btr_search_drop_page_hash_index(block);
+
+ header = buf_block_get_frame(block) + PAGE_HEADER + PAGE_BTR_SEG_TOP;
+#ifdef UNIV_BTR_DEBUG
+ ut_a(btr_root_fseg_validate(header, space));
+#endif /* UNIV_BTR_DEBUG */
+
+ while (!fseg_free_step(header, mtr));
+}
+#endif /* !UNIV_HOTBACKUP */
+
+/*************************************************************//**
+Reorganizes an index page. */
+static
+ibool
+btr_page_reorganize_low(
+/*====================*/
+ ibool recovery,/*!< in: TRUE if called in recovery:
+ locks should not be updated, i.e.,
+ there cannot exist locks on the
+ page, and a hash index should not be
+ dropped: it cannot exist */
+ buf_block_t* block, /*!< in: page to be reorganized */
+ dict_index_t* index, /*!< in: record descriptor */
+ mtr_t* mtr) /*!< in: mtr */
+{
+ page_t* page = buf_block_get_frame(block);
+ page_zip_des_t* page_zip = buf_block_get_page_zip(block);
+ buf_block_t* temp_block;
+ page_t* temp_page;
+ ulint log_mode;
+ ulint data_size1;
+ ulint data_size2;
+ ulint max_ins_size1;
+ ulint max_ins_size2;
+ ibool success = FALSE;
+
+ ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX));
+ ut_ad(!!page_is_comp(page) == dict_table_is_comp(index->table));
+#ifdef UNIV_ZIP_DEBUG
+ ut_a(!page_zip || page_zip_validate(page_zip, page));
+#endif /* UNIV_ZIP_DEBUG */
+ data_size1 = page_get_data_size(page);
+ max_ins_size1 = page_get_max_insert_size_after_reorganize(page, 1);
+
+#ifndef UNIV_HOTBACKUP
+ /* Write the log record */
+ mlog_open_and_write_index(mtr, page, index, page_is_comp(page)
+ ? MLOG_COMP_PAGE_REORGANIZE
+ : MLOG_PAGE_REORGANIZE, 0);
+#endif /* !UNIV_HOTBACKUP */
+
+ /* Turn logging off */
+ log_mode = mtr_set_log_mode(mtr, MTR_LOG_NONE);
+
+#ifndef UNIV_HOTBACKUP
+ temp_block = buf_block_alloc(0);
+#else /* !UNIV_HOTBACKUP */
+ ut_ad(block == back_block1);
+ temp_block = back_block2;
+#endif /* !UNIV_HOTBACKUP */
+ temp_page = temp_block->frame;
+
+ /* Copy the old page to temporary space */
+ buf_frame_copy(temp_page, page);
+
+#ifndef UNIV_HOTBACKUP
+ if (UNIV_LIKELY(!recovery)) {
+ btr_search_drop_page_hash_index(block);
+ }
+
+ block->check_index_page_at_flush = TRUE;
+#endif /* !UNIV_HOTBACKUP */
+
+ /* Recreate the page: note that global data on page (possible
+ segment headers, next page-field, etc.) is preserved intact */
+
+ page_create(block, mtr, dict_table_is_comp(index->table));
+
+ /* Copy the records from the temporary space to the recreated page;
+ do not copy the lock bits yet */
+
+ page_copy_rec_list_end_no_locks(block, temp_block,
+ page_get_infimum_rec(temp_page),
+ index, mtr);
+
+ if (dict_index_is_sec_or_ibuf(index) && page_is_leaf(page)) {
+ /* Copy max trx id to recreated page */
+ trx_id_t max_trx_id = page_get_max_trx_id(temp_page);
+ page_set_max_trx_id(block, NULL, max_trx_id, mtr);
+ /* In crash recovery, dict_index_is_sec_or_ibuf() always
+ returns TRUE, even for clustered indexes. max_trx_id is
+ unused in clustered index pages. */
+ ut_ad(!ut_dulint_is_zero(max_trx_id) || recovery);
+ }
+
+ if (UNIV_LIKELY_NULL(page_zip)
+ && UNIV_UNLIKELY
+ (!page_zip_compress(page_zip, page, index, NULL))) {
+
+ /* Restore the old page and exit. */
+ buf_frame_copy(page, temp_page);
+
+ goto func_exit;
+ }
+
+#ifndef UNIV_HOTBACKUP
+ if (UNIV_LIKELY(!recovery)) {
+ /* Update the record lock bitmaps */
+ lock_move_reorganize_page(block, temp_block);
+ }
+#endif /* !UNIV_HOTBACKUP */
+
+ data_size2 = page_get_data_size(page);
+ max_ins_size2 = page_get_max_insert_size_after_reorganize(page, 1);
+
+ if (UNIV_UNLIKELY(data_size1 != data_size2)
+ || UNIV_UNLIKELY(max_ins_size1 != max_ins_size2)) {
+ buf_page_print(page, 0);
+ buf_page_print(temp_page, 0);
+ fprintf(stderr,
+ "InnoDB: Error: page old data size %lu"
+ " new data size %lu\n"
+ "InnoDB: Error: page old max ins size %lu"
+ " new max ins size %lu\n"
+ "InnoDB: Submit a detailed bug report"
+ " to http://bugs.mysql.com\n",
+ (unsigned long) data_size1, (unsigned long) data_size2,
+ (unsigned long) max_ins_size1,
+ (unsigned long) max_ins_size2);
+ } else {
+ success = TRUE;
+ }
+
+func_exit:
+#ifdef UNIV_ZIP_DEBUG
+ ut_a(!page_zip || page_zip_validate(page_zip, page));
+#endif /* UNIV_ZIP_DEBUG */
+#ifndef UNIV_HOTBACKUP
+ buf_block_free(temp_block);
+#endif /* !UNIV_HOTBACKUP */
+
+ /* Restore logging mode */
+ mtr_set_log_mode(mtr, log_mode);
+
+ return(success);
+}
+
+#ifndef UNIV_HOTBACKUP
+/*************************************************************//**
+Reorganizes an index page.
+IMPORTANT: if btr_page_reorganize() is invoked on a compressed leaf
+page of a non-clustered index, the caller must update the insert
+buffer free bits in the same mini-transaction in such a way that the
+modification will be redo-logged.
+@return TRUE on success, FALSE on failure */
+UNIV_INTERN
+ibool
+btr_page_reorganize(
+/*================*/
+ buf_block_t* block, /*!< in: page to be reorganized */
+ dict_index_t* index, /*!< in: record descriptor */
+ mtr_t* mtr) /*!< in: mtr */
+{
+ return(btr_page_reorganize_low(FALSE, block, index, mtr));
+}
+#endif /* !UNIV_HOTBACKUP */
+
+/***********************************************************//**
+Parses a redo log record of reorganizing a page.
+@return end of log record or NULL */
+UNIV_INTERN
+byte*
+btr_parse_page_reorganize(
+/*======================*/
+ byte* ptr, /*!< in: buffer */
+ byte* end_ptr __attribute__((unused)),
+ /*!< in: buffer end */
+ dict_index_t* index, /*!< in: record descriptor */
+ buf_block_t* block, /*!< in: page to be reorganized, or NULL */
+ mtr_t* mtr) /*!< in: mtr or NULL */
+{
+ ut_ad(ptr && end_ptr);
+
+ /* The record is empty, except for the record initial part */
+
+ if (UNIV_LIKELY(block != NULL)) {
+ btr_page_reorganize_low(TRUE, block, index, mtr);
+ }
+
+ return(ptr);
+}
+
+#ifndef UNIV_HOTBACKUP
+/*************************************************************//**
+Empties an index page. @see btr_page_create(). */
+static
+void
+btr_page_empty(
+/*===========*/
+ buf_block_t* block, /*!< in: page to be emptied */
+ page_zip_des_t* page_zip,/*!< out: compressed page, or NULL */
+ dict_index_t* index, /*!< in: index of the page */
+ ulint level, /*!< in: the B-tree level of the page */
+ mtr_t* mtr) /*!< in: mtr */
+{
+ page_t* page = buf_block_get_frame(block);
+
+ ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX));
+ ut_ad(page_zip == buf_block_get_page_zip(block));
+#ifdef UNIV_ZIP_DEBUG
+ ut_a(!page_zip || page_zip_validate(page_zip, page));
+#endif /* UNIV_ZIP_DEBUG */
+
+ btr_search_drop_page_hash_index(block);
+
+ /* Recreate the page: note that global data on page (possible
+ segment headers, next page-field, etc.) is preserved intact */
+
+ if (UNIV_LIKELY_NULL(page_zip)) {
+ page_create_zip(block, index, level, mtr);
+ } else {
+ page_create(block, mtr, dict_table_is_comp(index->table));
+ btr_page_set_level(page, NULL, level, mtr);
+ }
+
+ block->check_index_page_at_flush = TRUE;
+}
+
+/*************************************************************//**
+Makes tree one level higher by splitting the root, and inserts
+the tuple. It is assumed that mtr contains an x-latch on the tree.
+NOTE that the operation of this function must always succeed,
+we cannot reverse it: therefore enough free disk space must be
+guaranteed to be available before this function is called.
+@return inserted record */
+UNIV_INTERN
+rec_t*
+btr_root_raise_and_insert(
+/*======================*/
+ btr_cur_t* cursor, /*!< in: cursor at which to insert: must be
+ on the root page; when the function returns,
+ the cursor is positioned on the predecessor
+ of the inserted record */
+ const dtuple_t* tuple, /*!< in: tuple to insert */
+ ulint n_ext, /*!< in: number of externally stored columns */
+ mtr_t* mtr) /*!< in: mtr */
+{
+ dict_index_t* index;
+ page_t* root;
+ page_t* new_page;
+ ulint new_page_no;
+ rec_t* rec;
+ mem_heap_t* heap;
+ dtuple_t* node_ptr;
+ ulint level;
+ rec_t* node_ptr_rec;
+ page_cur_t* page_cursor;
+ page_zip_des_t* root_page_zip;
+ page_zip_des_t* new_page_zip;
+ buf_block_t* root_block;
+ buf_block_t* new_block;
+
+ root = btr_cur_get_page(cursor);
+ root_block = btr_cur_get_block(cursor);
+ root_page_zip = buf_block_get_page_zip(root_block);
+#ifdef UNIV_ZIP_DEBUG
+ ut_a(!root_page_zip || page_zip_validate(root_page_zip, root));
+#endif /* UNIV_ZIP_DEBUG */
+ index = btr_cur_get_index(cursor);
+#ifdef UNIV_BTR_DEBUG
+ if (!dict_index_is_ibuf(index)) {
+ ulint space = dict_index_get_space(index);
+
+ ut_a(btr_root_fseg_validate(FIL_PAGE_DATA + PAGE_BTR_SEG_LEAF
+ + root, space));
+ ut_a(btr_root_fseg_validate(FIL_PAGE_DATA + PAGE_BTR_SEG_TOP
+ + root, space));
+ }
+
+ ut_a(dict_index_get_page(index) == page_get_page_no(root));
+#endif /* UNIV_BTR_DEBUG */
+ ut_ad(mtr_memo_contains(mtr, dict_index_get_lock(index),
+ MTR_MEMO_X_LOCK));
+ ut_ad(mtr_memo_contains(mtr, root_block, MTR_MEMO_PAGE_X_FIX));
+
+ /* Allocate a new page to the tree. Root splitting is done by first
+ moving the root records to the new page, emptying the root, putting
+ a node pointer to the new page, and then splitting the new page. */
+
+ level = btr_page_get_level(root, mtr);
+
+ new_block = btr_page_alloc(index, 0, FSP_NO_DIR, level, mtr);
+ new_page = buf_block_get_frame(new_block);
+ new_page_zip = buf_block_get_page_zip(new_block);
+ ut_a(!new_page_zip == !root_page_zip);
+ ut_a(!new_page_zip
+ || page_zip_get_size(new_page_zip)
+ == page_zip_get_size(root_page_zip));
+
+ btr_page_create(new_block, new_page_zip, index, level, mtr);
+
+ /* Set the next node and previous node fields of new page */
+ btr_page_set_next(new_page, new_page_zip, FIL_NULL, mtr);
+ btr_page_set_prev(new_page, new_page_zip, FIL_NULL, mtr);
+
+ /* Copy the records from root to the new page one by one. */
+
+ if (0
+#ifdef UNIV_ZIP_COPY
+ || new_page_zip
+#endif /* UNIV_ZIP_COPY */
+ || UNIV_UNLIKELY
+ (!page_copy_rec_list_end(new_block, root_block,
+ page_get_infimum_rec(root),
+ index, mtr))) {
+ ut_a(new_page_zip);
+
+ /* Copy the page byte for byte. */
+ page_zip_copy_recs(new_page_zip, new_page,
+ root_page_zip, root, index, mtr);
+
+ /* Update the lock table and possible hash index. */
+
+ lock_move_rec_list_end(new_block, root_block,
+ page_get_infimum_rec(root));
+
+ btr_search_move_or_delete_hash_entries(new_block, root_block,
+ index);
+ }
+
+ /* If this is a pessimistic insert which is actually done to
+ perform a pessimistic update then we have stored the lock
+ information of the record to be inserted on the infimum of the
+ root page: we cannot discard the lock structs on the root page */
+
+ lock_update_root_raise(new_block, root_block);
+
+ /* Create a memory heap where the node pointer is stored */
+ heap = mem_heap_create(100);
+
+ rec = page_rec_get_next(page_get_infimum_rec(new_page));
+ new_page_no = buf_block_get_page_no(new_block);
+
+ /* Build the node pointer (= node key and page address) for the
+ child */
+
+ node_ptr = dict_index_build_node_ptr(index, rec, new_page_no, heap,
+ level);
+ /* The node pointer must be marked as the predefined minimum record,
+ as there is no lower alphabetical limit to records in the leftmost
+ node of a level: */
+ dtuple_set_info_bits(node_ptr,
+ dtuple_get_info_bits(node_ptr)
+ | REC_INFO_MIN_REC_FLAG);
+
+ /* Rebuild the root page to get free space */
+ btr_page_empty(root_block, root_page_zip, index, level + 1, mtr);
+
+ /* Set the next node and previous node fields, although
+ they should already have been set. The previous node field
+ must be FIL_NULL if root_page_zip != NULL, because the
+ REC_INFO_MIN_REC_FLAG (of the first user record) will be
+ set if and only if btr_page_get_prev() == FIL_NULL. */
+ btr_page_set_next(root, root_page_zip, FIL_NULL, mtr);
+ btr_page_set_prev(root, root_page_zip, FIL_NULL, mtr);
+
+ page_cursor = btr_cur_get_page_cur(cursor);
+
+ /* Insert node pointer to the root */
+
+ page_cur_set_before_first(root_block, page_cursor);
+
+ node_ptr_rec = page_cur_tuple_insert(page_cursor, node_ptr,
+ index, 0, mtr);
+
+ /* The root page should only contain the node pointer
+ to new_page at this point. Thus, the data should fit. */
+ ut_a(node_ptr_rec);
+
+ /* Free the memory heap */
+ mem_heap_free(heap);
+
+ /* We play safe and reset the free bits for the new page */
+
+#if 0
+ fprintf(stderr, "Root raise new page no %lu\n", new_page_no);
+#endif
+
+ if (!dict_index_is_clust(index)) {
+ ibuf_reset_free_bits(new_block);
+ }
+
+ /* Reposition the cursor to the child node */
+ page_cur_search(new_block, index, tuple,
+ PAGE_CUR_LE, page_cursor);
+
+ /* Split the child and insert tuple */
+ return(btr_page_split_and_insert(cursor, tuple, n_ext, mtr));
+}
+
+/*************************************************************//**
+Decides if the page should be split at the convergence point of inserts
+converging to the left.
+@return TRUE if split recommended */
+UNIV_INTERN
+ibool
+btr_page_get_split_rec_to_left(
+/*===========================*/
+ btr_cur_t* cursor, /*!< in: cursor at which to insert */
+ rec_t** split_rec) /*!< out: if split recommended,
+ the first record on upper half page,
+ or NULL if tuple to be inserted should
+ be first */
+{
+ page_t* page;
+ rec_t* insert_point;
+ rec_t* infimum;
+
+ page = btr_cur_get_page(cursor);
+ insert_point = btr_cur_get_rec(cursor);
+
+ if (page_header_get_ptr(page, PAGE_LAST_INSERT)
+ == page_rec_get_next(insert_point)) {
+
+ infimum = page_get_infimum_rec(page);
+
+ /* If the convergence is in the middle of a page, include also
+ the record immediately before the new insert to the upper
+ page. Otherwise, we could repeatedly move from page to page
+ lots of records smaller than the convergence point. */
+
+ if (infimum != insert_point
+ && page_rec_get_next(infimum) != insert_point) {
+
+ *split_rec = insert_point;
+ } else {
+ *split_rec = page_rec_get_next(insert_point);
+ }
+
+ return(TRUE);
+ }
+
+ return(FALSE);
+}
+
+/*************************************************************//**
+Decides if the page should be split at the convergence point of inserts
+converging to the right.
+@return TRUE if split recommended */
+UNIV_INTERN
+ibool
+btr_page_get_split_rec_to_right(
+/*============================*/
+ btr_cur_t* cursor, /*!< in: cursor at which to insert */
+ rec_t** split_rec) /*!< out: if split recommended,
+ the first record on upper half page,
+ or NULL if tuple to be inserted should
+ be first */
+{
+ page_t* page;
+ rec_t* insert_point;
+
+ page = btr_cur_get_page(cursor);
+ insert_point = btr_cur_get_rec(cursor);
+
+ /* We use eager heuristics: if the new insert would be right after
+ the previous insert on the same page, we assume that there is a
+ pattern of sequential inserts here. */
+
+ if (UNIV_LIKELY(page_header_get_ptr(page, PAGE_LAST_INSERT)
+ == insert_point)) {
+
+ rec_t* next_rec;
+
+ next_rec = page_rec_get_next(insert_point);
+
+ if (page_rec_is_supremum(next_rec)) {
+split_at_new:
+ /* Split at the new record to insert */
+ *split_rec = NULL;
+ } else {
+ rec_t* next_next_rec = page_rec_get_next(next_rec);
+ if (page_rec_is_supremum(next_next_rec)) {
+
+ goto split_at_new;
+ }
+
+ /* If there are >= 2 user records up from the insert
+ point, split all but 1 off. We want to keep one because
+ then sequential inserts can use the adaptive hash
+ index, as they can do the necessary checks of the right
+ search position just by looking at the records on this
+ page. */
+
+ *split_rec = next_next_rec;
+ }
+
+ return(TRUE);
+ }
+
+ return(FALSE);
+}
+
+/*************************************************************//**
+Calculates a split record such that the tuple will certainly fit on
+its half-page when the split is performed. We assume in this function
+only that the cursor page has at least one user record.
+@return split record, or NULL if tuple will be the first record on
+upper half-page */
+static
+rec_t*
+btr_page_get_sure_split_rec(
+/*========================*/
+ btr_cur_t* cursor, /*!< in: cursor at which insert should be made */
+ const dtuple_t* tuple, /*!< in: tuple to insert */
+ ulint n_ext) /*!< in: number of externally stored columns */
+{
+ page_t* page;
+ page_zip_des_t* page_zip;
+ ulint insert_size;
+ ulint free_space;
+ ulint total_data;
+ ulint total_n_recs;
+ ulint total_space;
+ ulint incl_data;
+ rec_t* ins_rec;
+ rec_t* rec;
+ rec_t* next_rec;
+ ulint n;
+ mem_heap_t* heap;
+ ulint* offsets;
+
+ page = btr_cur_get_page(cursor);
+
+ insert_size = rec_get_converted_size(cursor->index, tuple, n_ext);
+ free_space = page_get_free_space_of_empty(page_is_comp(page));
+
+ page_zip = btr_cur_get_page_zip(cursor);
+ if (UNIV_LIKELY_NULL(page_zip)) {
+ /* Estimate the free space of an empty compressed page. */
+ ulint free_space_zip = page_zip_empty_size(
+ cursor->index->n_fields,
+ page_zip_get_size(page_zip));
+
+ if (UNIV_LIKELY(free_space > (ulint) free_space_zip)) {
+ free_space = (ulint) free_space_zip;
+ }
+ }
+
+ /* free_space is now the free space of a created new page */
+
+ total_data = page_get_data_size(page) + insert_size;
+ total_n_recs = page_get_n_recs(page) + 1;
+ ut_ad(total_n_recs >= 2);
+ total_space = total_data + page_dir_calc_reserved_space(total_n_recs);
+
+ n = 0;
+ incl_data = 0;
+ ins_rec = btr_cur_get_rec(cursor);
+ rec = page_get_infimum_rec(page);
+
+ heap = NULL;
+ offsets = NULL;
+
+ /* We start to include records to the left half, and when the
+ space reserved by them exceeds half of total_space, then if
+ the included records fit on the left page, they will be put there
+ if something was left over also for the right page,
+ otherwise the last included record will be the first on the right
+ half page */
+
+ do {
+ /* Decide the next record to include */
+ if (rec == ins_rec) {
+ rec = NULL; /* NULL denotes that tuple is
+ now included */
+ } else if (rec == NULL) {
+ rec = page_rec_get_next(ins_rec);
+ } else {
+ rec = page_rec_get_next(rec);
+ }
+
+ if (rec == NULL) {
+ /* Include tuple */
+ incl_data += insert_size;
+ } else {
+ offsets = rec_get_offsets(rec, cursor->index,
+ offsets, ULINT_UNDEFINED,
+ &heap);
+ incl_data += rec_offs_size(offsets);
+ }
+
+ n++;
+ } while (incl_data + page_dir_calc_reserved_space(n)
+ < total_space / 2);
+
+ if (incl_data + page_dir_calc_reserved_space(n) <= free_space) {
+ /* The next record will be the first on
+ the right half page if it is not the
+ supremum record of page */
+
+ if (rec == ins_rec) {
+ rec = NULL;
+
+ goto func_exit;
+ } else if (rec == NULL) {
+ next_rec = page_rec_get_next(ins_rec);
+ } else {
+ next_rec = page_rec_get_next(rec);
+ }
+ ut_ad(next_rec);
+ if (!page_rec_is_supremum(next_rec)) {
+ rec = next_rec;
+ }
+ }
+
+func_exit:
+ if (UNIV_LIKELY_NULL(heap)) {
+ mem_heap_free(heap);
+ }
+ return(rec);
+}
+
+/*************************************************************//**
+Returns TRUE if the insert fits on the appropriate half-page with the
+chosen split_rec.
+@return TRUE if fits */
+static
+ibool
+btr_page_insert_fits(
+/*=================*/
+ btr_cur_t* cursor, /*!< in: cursor at which insert
+ should be made */
+ const rec_t* split_rec,/*!< in: suggestion for first record
+ on upper half-page, or NULL if
+ tuple to be inserted should be first */
+ const ulint* offsets,/*!< in: rec_get_offsets(
+ split_rec, cursor->index) */
+ const dtuple_t* tuple, /*!< in: tuple to insert */
+ ulint n_ext, /*!< in: number of externally stored columns */
+ mem_heap_t* heap) /*!< in: temporary memory heap */
+{
+ page_t* page;
+ ulint insert_size;
+ ulint free_space;
+ ulint total_data;
+ ulint total_n_recs;
+ const rec_t* rec;
+ const rec_t* end_rec;
+ ulint* offs;
+
+ page = btr_cur_get_page(cursor);
+
+ ut_ad(!split_rec == !offsets);
+ ut_ad(!offsets
+ || !page_is_comp(page) == !rec_offs_comp(offsets));
+ ut_ad(!offsets
+ || rec_offs_validate(split_rec, cursor->index, offsets));
+
+ insert_size = rec_get_converted_size(cursor->index, tuple, n_ext);
+ free_space = page_get_free_space_of_empty(page_is_comp(page));
+
+ /* free_space is now the free space of a created new page */
+
+ total_data = page_get_data_size(page) + insert_size;
+ total_n_recs = page_get_n_recs(page) + 1;
+
+ /* We determine which records (from rec to end_rec, not including
+ end_rec) will end up on the other half page from tuple when it is
+ inserted. */
+
+ if (split_rec == NULL) {
+ rec = page_rec_get_next(page_get_infimum_rec(page));
+ end_rec = page_rec_get_next(btr_cur_get_rec(cursor));
+
+ } else if (cmp_dtuple_rec(tuple, split_rec, offsets) >= 0) {
+
+ rec = page_rec_get_next(page_get_infimum_rec(page));
+ end_rec = split_rec;
+ } else {
+ rec = split_rec;
+ end_rec = page_get_supremum_rec(page);
+ }
+
+ if (total_data + page_dir_calc_reserved_space(total_n_recs)
+ <= free_space) {
+
+ /* Ok, there will be enough available space on the
+ half page where the tuple is inserted */
+
+ return(TRUE);
+ }
+
+ offs = NULL;
+
+ while (rec != end_rec) {
+ /* In this loop we calculate the amount of reserved
+ space after rec is removed from page. */
+
+ offs = rec_get_offsets(rec, cursor->index, offs,
+ ULINT_UNDEFINED, &heap);
+
+ total_data -= rec_offs_size(offs);
+ total_n_recs--;
+
+ if (total_data + page_dir_calc_reserved_space(total_n_recs)
+ <= free_space) {
+
+ /* Ok, there will be enough available space on the
+ half page where the tuple is inserted */
+
+ return(TRUE);
+ }
+
+ rec = page_rec_get_next_const(rec);
+ }
+
+ return(FALSE);
+}
+
+/*******************************************************//**
+Inserts a data tuple to a tree on a non-leaf level. It is assumed
+that mtr holds an x-latch on the tree. */
+UNIV_INTERN
+void
+btr_insert_on_non_leaf_level(
+/*=========================*/
+ dict_index_t* index, /*!< in: index */
+ ulint level, /*!< in: level, must be > 0 */
+ dtuple_t* tuple, /*!< in: the record to be inserted */
+ mtr_t* mtr) /*!< in: mtr */
+{
+ big_rec_t* dummy_big_rec;
+ btr_cur_t cursor;
+ ulint err;
+ rec_t* rec;
+
+ ut_ad(level > 0);
+
+ btr_cur_search_to_nth_level(index, level, tuple, PAGE_CUR_LE,
+ BTR_CONT_MODIFY_TREE,
+ &cursor, 0, mtr);
+
+ err = btr_cur_pessimistic_insert(BTR_NO_LOCKING_FLAG
+ | BTR_KEEP_SYS_FLAG
+ | BTR_NO_UNDO_LOG_FLAG,
+ &cursor, tuple, &rec,
+ &dummy_big_rec, 0, NULL, mtr);
+ ut_a(err == DB_SUCCESS);
+}
+
+/**************************************************************//**
+Attaches the halves of an index page on the appropriate level in an
+index tree. */
+static
+void
+btr_attach_half_pages(
+/*==================*/
+ dict_index_t* index, /*!< in: the index tree */
+ buf_block_t* block, /*!< in/out: page to be split */
+ rec_t* split_rec, /*!< in: first record on upper
+ half page */
+ buf_block_t* new_block, /*!< in/out: the new half page */
+ ulint direction, /*!< in: FSP_UP or FSP_DOWN */
+ mtr_t* mtr) /*!< in: mtr */
+{
+ ulint space;
+ ulint zip_size;
+ ulint prev_page_no;
+ ulint next_page_no;
+ ulint level;
+ page_t* page = buf_block_get_frame(block);
+ page_t* lower_page;
+ page_t* upper_page;
+ ulint lower_page_no;
+ ulint upper_page_no;
+ page_zip_des_t* lower_page_zip;
+ page_zip_des_t* upper_page_zip;
+ dtuple_t* node_ptr_upper;
+ mem_heap_t* heap;
+
+ ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX));
+ ut_ad(mtr_memo_contains(mtr, new_block, MTR_MEMO_PAGE_X_FIX));
+
+ /* Create a memory heap where the data tuple is stored */
+ heap = mem_heap_create(1024);
+
+ /* Based on split direction, decide upper and lower pages */
+ if (direction == FSP_DOWN) {
+
+ btr_cur_t cursor;
+ ulint* offsets;
+
+ lower_page = buf_block_get_frame(new_block);
+ lower_page_no = buf_block_get_page_no(new_block);
+ lower_page_zip = buf_block_get_page_zip(new_block);
+ upper_page = buf_block_get_frame(block);
+ upper_page_no = buf_block_get_page_no(block);
+ upper_page_zip = buf_block_get_page_zip(block);
+
+ /* Look up the index for the node pointer to page */
+ offsets = btr_page_get_father_block(NULL, heap, index,
+ block, mtr, &cursor);
+
+ /* Replace the address of the old child node (= page) with the
+ address of the new lower half */
+
+ btr_node_ptr_set_child_page_no(
+ btr_cur_get_rec(&cursor),
+ btr_cur_get_page_zip(&cursor),
+ offsets, lower_page_no, mtr);
+ mem_heap_empty(heap);
+ } else {
+ lower_page = buf_block_get_frame(block);
+ lower_page_no = buf_block_get_page_no(block);
+ lower_page_zip = buf_block_get_page_zip(block);
+ upper_page = buf_block_get_frame(new_block);
+ upper_page_no = buf_block_get_page_no(new_block);
+ upper_page_zip = buf_block_get_page_zip(new_block);
+ }
+
+ /* Get the level of the split pages */
+ level = btr_page_get_level(buf_block_get_frame(block), mtr);
+ ut_ad(level
+ == btr_page_get_level(buf_block_get_frame(new_block), mtr));
+
+ /* Build the node pointer (= node key and page address) for the upper
+ half */
+
+ node_ptr_upper = dict_index_build_node_ptr(index, split_rec,
+ upper_page_no, heap, level);
+
+ /* Insert it next to the pointer to the lower half. Note that this
+ may generate recursion leading to a split on the higher level. */
+
+ btr_insert_on_non_leaf_level(index, level + 1, node_ptr_upper, mtr);
+
+ /* Free the memory heap */
+ mem_heap_free(heap);
+
+ /* Get the previous and next pages of page */
+
+ prev_page_no = btr_page_get_prev(page, mtr);
+ next_page_no = btr_page_get_next(page, mtr);
+ space = buf_block_get_space(block);
+ zip_size = buf_block_get_zip_size(block);
+
+ /* Update page links of the level */
+
+ if (prev_page_no != FIL_NULL) {
+ buf_block_t* prev_block = btr_block_get(space, zip_size,
+ prev_page_no,
+ RW_X_LATCH, mtr);
+#ifdef UNIV_BTR_DEBUG
+ ut_a(page_is_comp(prev_block->frame) == page_is_comp(page));
+ ut_a(btr_page_get_next(prev_block->frame, mtr)
+ == buf_block_get_page_no(block));
+#endif /* UNIV_BTR_DEBUG */
+
+ btr_page_set_next(buf_block_get_frame(prev_block),
+ buf_block_get_page_zip(prev_block),
+ lower_page_no, mtr);
+ }
+
+ if (next_page_no != FIL_NULL) {
+ buf_block_t* next_block = btr_block_get(space, zip_size,
+ next_page_no,
+ RW_X_LATCH, mtr);
+#ifdef UNIV_BTR_DEBUG
+ ut_a(page_is_comp(next_block->frame) == page_is_comp(page));
+ ut_a(btr_page_get_prev(next_block->frame, mtr)
+ == page_get_page_no(page));
+#endif /* UNIV_BTR_DEBUG */
+
+ btr_page_set_prev(buf_block_get_frame(next_block),
+ buf_block_get_page_zip(next_block),
+ upper_page_no, mtr);
+ }
+
+ btr_page_set_prev(lower_page, lower_page_zip, prev_page_no, mtr);
+ btr_page_set_next(lower_page, lower_page_zip, upper_page_no, mtr);
+
+ btr_page_set_prev(upper_page, upper_page_zip, lower_page_no, mtr);
+ btr_page_set_next(upper_page, upper_page_zip, next_page_no, mtr);
+}
+
+/*************************************************************//**
+Splits an index page to halves and inserts the tuple. It is assumed
+that mtr holds an x-latch to the index tree. NOTE: the tree x-latch is
+released within this function! NOTE that the operation of this
+function must always succeed, we cannot reverse it: therefore enough
+free disk space (2 pages) must be guaranteed to be available before
+this function is called.
+
+@return inserted record */
+UNIV_INTERN
+rec_t*
+btr_page_split_and_insert(
+/*======================*/
+ btr_cur_t* cursor, /*!< in: cursor at which to insert; when the
+ function returns, the cursor is positioned
+ on the predecessor of the inserted record */
+ const dtuple_t* tuple, /*!< in: tuple to insert */
+ ulint n_ext, /*!< in: number of externally stored columns */
+ mtr_t* mtr) /*!< in: mtr */
+{
+ buf_block_t* block;
+ page_t* page;
+ page_zip_des_t* page_zip;
+ ulint page_no;
+ byte direction;
+ ulint hint_page_no;
+ buf_block_t* new_block;
+ page_t* new_page;
+ page_zip_des_t* new_page_zip;
+ rec_t* split_rec;
+ buf_block_t* left_block;
+ buf_block_t* right_block;
+ buf_block_t* insert_block;
+ page_t* insert_page;
+ page_cur_t* page_cursor;
+ rec_t* first_rec;
+ byte* buf = 0; /* remove warning */
+ rec_t* move_limit;
+ ibool insert_will_fit;
+ ibool insert_left;
+ ulint n_iterations = 0;
+ rec_t* rec;
+ mem_heap_t* heap;
+ ulint n_uniq;
+ ulint* offsets;
+
+ heap = mem_heap_create(1024);
+ n_uniq = dict_index_get_n_unique_in_tree(cursor->index);
+func_start:
+ mem_heap_empty(heap);
+ offsets = NULL;
+
+ ut_ad(mtr_memo_contains(mtr, dict_index_get_lock(cursor->index),
+ MTR_MEMO_X_LOCK));
+#ifdef UNIV_SYNC_DEBUG
+ ut_ad(rw_lock_own(dict_index_get_lock(cursor->index), RW_LOCK_EX));
+#endif /* UNIV_SYNC_DEBUG */
+
+ block = btr_cur_get_block(cursor);
+ page = buf_block_get_frame(block);
+ page_zip = buf_block_get_page_zip(block);
+
+ ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX));
+ ut_ad(page_get_n_recs(page) >= 1);
+
+ page_no = buf_block_get_page_no(block);
+
+ /* 1. Decide the split record; split_rec == NULL means that the
+ tuple to be inserted should be the first record on the upper
+ half-page */
+
+ if (n_iterations > 0) {
+ direction = FSP_UP;
+ hint_page_no = page_no + 1;
+ split_rec = btr_page_get_sure_split_rec(cursor, tuple, n_ext);
+
+ } else if (btr_page_get_split_rec_to_right(cursor, &split_rec)) {
+ direction = FSP_UP;
+ hint_page_no = page_no + 1;
+
+ } else if (btr_page_get_split_rec_to_left(cursor, &split_rec)) {
+ direction = FSP_DOWN;
+ hint_page_no = page_no - 1;
+ } else {
+ direction = FSP_UP;
+ hint_page_no = page_no + 1;
+
+ if (page_get_n_recs(page) == 1) {
+ page_cur_t pcur;
+
+ /* There is only one record in the index page
+ therefore we can't split the node in the middle
+ by default. We need to determine whether the
+ new record will be inserted to the left or right. */
+
+ /* Read the first (and only) record in the page. */
+ page_cur_set_before_first(block, &pcur);
+ page_cur_move_to_next(&pcur);
+ first_rec = page_cur_get_rec(&pcur);
+
+ offsets = rec_get_offsets(
+ first_rec, cursor->index, offsets,
+ n_uniq, &heap);
+
+ /* If the new record is less than the existing record
+ the the split in the middle will copy the existing
+ record to the new node. */
+ if (cmp_dtuple_rec(tuple, first_rec, offsets) < 0) {
+ split_rec = page_get_middle_rec(page);
+ } else {
+ split_rec = NULL;
+ }
+ } else {
+ split_rec = page_get_middle_rec(page);
+ }
+ }
+
+ /* 2. Allocate a new page to the index */
+ new_block = btr_page_alloc(cursor->index, hint_page_no, direction,
+ btr_page_get_level(page, mtr), mtr);
+ new_page = buf_block_get_frame(new_block);
+ new_page_zip = buf_block_get_page_zip(new_block);
+ btr_page_create(new_block, new_page_zip, cursor->index,
+ btr_page_get_level(page, mtr), mtr);
+
+ /* 3. Calculate the first record on the upper half-page, and the
+ first record (move_limit) on original page which ends up on the
+ upper half */
+
+ if (split_rec) {
+ first_rec = move_limit = split_rec;
+
+ offsets = rec_get_offsets(split_rec, cursor->index, offsets,
+ n_uniq, &heap);
+
+ insert_left = cmp_dtuple_rec(tuple, split_rec, offsets) < 0;
+
+ if (UNIV_UNLIKELY(!insert_left && new_page_zip
+ && n_iterations > 0)) {
+ /* If a compressed page has already been split,
+ avoid further splits by inserting the record
+ to an empty page. */
+ split_rec = NULL;
+ goto insert_right;
+ }
+ } else {
+insert_right:
+ insert_left = FALSE;
+ buf = mem_alloc(rec_get_converted_size(cursor->index,
+ tuple, n_ext));
+
+ first_rec = rec_convert_dtuple_to_rec(buf, cursor->index,
+ tuple, n_ext);
+ move_limit = page_rec_get_next(btr_cur_get_rec(cursor));
+ }
+
+ /* 4. Do first the modifications in the tree structure */
+
+ btr_attach_half_pages(cursor->index, block,
+ first_rec, new_block, direction, mtr);
+
+ /* If the split is made on the leaf level and the insert will fit
+ on the appropriate half-page, we may release the tree x-latch.
+ We can then move the records after releasing the tree latch,
+ thus reducing the tree latch contention. */
+
+ if (split_rec) {
+ insert_will_fit = !new_page_zip
+ && btr_page_insert_fits(cursor, split_rec,
+ offsets, tuple, n_ext, heap);
+ } else {
+ mem_free(buf);
+ insert_will_fit = !new_page_zip
+ && btr_page_insert_fits(cursor, NULL,
+ NULL, tuple, n_ext, heap);
+ }
+
+ if (insert_will_fit && page_is_leaf(page)) {
+
+ mtr_memo_release(mtr, dict_index_get_lock(cursor->index),
+ MTR_MEMO_X_LOCK);
+ }
+
+ /* 5. Move then the records to the new page */
+ if (direction == FSP_DOWN) {
+ /* fputs("Split left\n", stderr); */
+
+ if (0
+#ifdef UNIV_ZIP_COPY
+ || page_zip
+#endif /* UNIV_ZIP_COPY */
+ || UNIV_UNLIKELY
+ (!page_move_rec_list_start(new_block, block, move_limit,
+ cursor->index, mtr))) {
+ /* For some reason, compressing new_page failed,
+ even though it should contain fewer records than
+ the original page. Copy the page byte for byte
+ and then delete the records from both pages
+ as appropriate. Deleting will always succeed. */
+ ut_a(new_page_zip);
+
+ page_zip_copy_recs(new_page_zip, new_page,
+ page_zip, page, cursor->index, mtr);
+ page_delete_rec_list_end(move_limit - page + new_page,
+ new_block, cursor->index,
+ ULINT_UNDEFINED,
+ ULINT_UNDEFINED, mtr);
+
+ /* Update the lock table and possible hash index. */
+
+ lock_move_rec_list_start(
+ new_block, block, move_limit,
+ new_page + PAGE_NEW_INFIMUM);
+
+ btr_search_move_or_delete_hash_entries(
+ new_block, block, cursor->index);
+
+ /* Delete the records from the source page. */
+
+ page_delete_rec_list_start(move_limit, block,
+ cursor->index, mtr);
+ }
+
+ left_block = new_block;
+ right_block = block;
+
+ lock_update_split_left(right_block, left_block);
+ } else {
+ /* fputs("Split right\n", stderr); */
+
+ if (0
+#ifdef UNIV_ZIP_COPY
+ || page_zip
+#endif /* UNIV_ZIP_COPY */
+ || UNIV_UNLIKELY
+ (!page_move_rec_list_end(new_block, block, move_limit,
+ cursor->index, mtr))) {
+ /* For some reason, compressing new_page failed,
+ even though it should contain fewer records than
+ the original page. Copy the page byte for byte
+ and then delete the records from both pages
+ as appropriate. Deleting will always succeed. */
+ ut_a(new_page_zip);
+
+ page_zip_copy_recs(new_page_zip, new_page,
+ page_zip, page, cursor->index, mtr);
+ page_delete_rec_list_start(move_limit - page
+ + new_page, new_block,
+ cursor->index, mtr);
+
+ /* Update the lock table and possible hash index. */
+
+ lock_move_rec_list_end(new_block, block, move_limit);
+
+ btr_search_move_or_delete_hash_entries(
+ new_block, block, cursor->index);
+
+ /* Delete the records from the source page. */
+
+ page_delete_rec_list_end(move_limit, block,
+ cursor->index,
+ ULINT_UNDEFINED,
+ ULINT_UNDEFINED, mtr);
+ }
+
+ left_block = block;
+ right_block = new_block;
+
+ lock_update_split_right(right_block, left_block);
+ }
+
+#ifdef UNIV_ZIP_DEBUG
+ if (UNIV_LIKELY_NULL(page_zip)) {
+ ut_a(page_zip_validate(page_zip, page));
+ ut_a(page_zip_validate(new_page_zip, new_page));
+ }
+#endif /* UNIV_ZIP_DEBUG */
+
+ /* At this point, split_rec, move_limit and first_rec may point
+ to garbage on the old page. */
+
+ /* 6. The split and the tree modification is now completed. Decide the
+ page where the tuple should be inserted */
+
+ if (insert_left) {
+ insert_block = left_block;
+ } else {
+ insert_block = right_block;
+ }
+
+ insert_page = buf_block_get_frame(insert_block);
+
+ /* 7. Reposition the cursor for insert and try insertion */
+ page_cursor = btr_cur_get_page_cur(cursor);
+
+ page_cur_search(insert_block, cursor->index, tuple,
+ PAGE_CUR_LE, page_cursor);
+
+ rec = page_cur_tuple_insert(page_cursor, tuple,
+ cursor->index, n_ext, mtr);
+
+#ifdef UNIV_ZIP_DEBUG
+ {
+ page_zip_des_t* insert_page_zip
+ = buf_block_get_page_zip(insert_block);
+ ut_a(!insert_page_zip
+ || page_zip_validate(insert_page_zip, insert_page));
+ }
+#endif /* UNIV_ZIP_DEBUG */
+
+ if (UNIV_LIKELY(rec != NULL)) {
+
+ goto func_exit;
+ }
+
+ /* 8. If insert did not fit, try page reorganization */
+
+ if (UNIV_UNLIKELY
+ (!btr_page_reorganize(insert_block, cursor->index, mtr))) {
+
+ goto insert_failed;
+ }
+
+ page_cur_search(insert_block, cursor->index, tuple,
+ PAGE_CUR_LE, page_cursor);
+ rec = page_cur_tuple_insert(page_cursor, tuple, cursor->index,
+ n_ext, mtr);
+
+ if (UNIV_UNLIKELY(rec == NULL)) {
+ /* The insert did not fit on the page: loop back to the
+ start of the function for a new split */
+insert_failed:
+ /* We play safe and reset the free bits for new_page */
+ if (!dict_index_is_clust(cursor->index)) {
+ ibuf_reset_free_bits(new_block);
+ }
+
+ /* fprintf(stderr, "Split second round %lu\n",
+ page_get_page_no(page)); */
+ n_iterations++;
+ ut_ad(n_iterations < 2
+ || buf_block_get_page_zip(insert_block));
+ ut_ad(!insert_will_fit);
+
+ goto func_start;
+ }
+
+func_exit:
+ /* Insert fit on the page: update the free bits for the
+ left and right pages in the same mtr */
+
+ if (!dict_index_is_clust(cursor->index) && page_is_leaf(page)) {
+ ibuf_update_free_bits_for_two_pages_low(
+ buf_block_get_zip_size(left_block),
+ left_block, right_block, mtr);
+ }
+
+#if 0
+ fprintf(stderr, "Split and insert done %lu %lu\n",
+ buf_block_get_page_no(left_block),
+ buf_block_get_page_no(right_block));
+#endif
+
+ ut_ad(page_validate(buf_block_get_frame(left_block), cursor->index));
+ ut_ad(page_validate(buf_block_get_frame(right_block), cursor->index));
+
+ mem_heap_free(heap);
+ return(rec);
+}
+
+/*************************************************************//**
+Removes a page from the level list of pages. */
+static
+void
+btr_level_list_remove(
+/*==================*/
+ ulint space, /*!< in: space where removed */
+ ulint zip_size,/*!< in: compressed page size in bytes
+ or 0 for uncompressed pages */
+ page_t* page, /*!< in: page to remove */
+ mtr_t* mtr) /*!< in: mtr */
+{
+ ulint prev_page_no;
+ ulint next_page_no;
+
+ ut_ad(page && mtr);
+ ut_ad(mtr_memo_contains_page(mtr, page, MTR_MEMO_PAGE_X_FIX));
+ ut_ad(space == page_get_space_id(page));
+ /* Get the previous and next page numbers of page */
+
+ prev_page_no = btr_page_get_prev(page, mtr);
+ next_page_no = btr_page_get_next(page, mtr);
+
+ /* Update page links of the level */
+
+ if (prev_page_no != FIL_NULL) {
+ buf_block_t* prev_block
+ = btr_block_get(space, zip_size, prev_page_no,
+ RW_X_LATCH, mtr);
+ page_t* prev_page
+ = buf_block_get_frame(prev_block);
+#ifdef UNIV_BTR_DEBUG
+ ut_a(page_is_comp(prev_page) == page_is_comp(page));
+ ut_a(btr_page_get_next(prev_page, mtr)
+ == page_get_page_no(page));
+#endif /* UNIV_BTR_DEBUG */
+
+ btr_page_set_next(prev_page,
+ buf_block_get_page_zip(prev_block),
+ next_page_no, mtr);
+ }
+
+ if (next_page_no != FIL_NULL) {
+ buf_block_t* next_block
+ = btr_block_get(space, zip_size, next_page_no,
+ RW_X_LATCH, mtr);
+ page_t* next_page
+ = buf_block_get_frame(next_block);
+#ifdef UNIV_BTR_DEBUG
+ ut_a(page_is_comp(next_page) == page_is_comp(page));
+ ut_a(btr_page_get_prev(next_page, mtr)
+ == page_get_page_no(page));
+#endif /* UNIV_BTR_DEBUG */
+
+ btr_page_set_prev(next_page,
+ buf_block_get_page_zip(next_block),
+ prev_page_no, mtr);
+ }
+}
+
+/****************************************************************//**
+Writes the redo log record for setting an index record as the predefined
+minimum record. */
+UNIV_INLINE
+void
+btr_set_min_rec_mark_log(
+/*=====================*/
+ rec_t* rec, /*!< in: record */
+ byte type, /*!< in: MLOG_COMP_REC_MIN_MARK or MLOG_REC_MIN_MARK */
+ mtr_t* mtr) /*!< in: mtr */
+{
+ mlog_write_initial_log_record(rec, type, mtr);
+
+ /* Write rec offset as a 2-byte ulint */
+ mlog_catenate_ulint(mtr, page_offset(rec), MLOG_2BYTES);
+}
+#else /* !UNIV_HOTBACKUP */
+# define btr_set_min_rec_mark_log(rec,comp,mtr) ((void) 0)
+#endif /* !UNIV_HOTBACKUP */
+
+/****************************************************************//**
+Parses the redo log record for setting an index record as the predefined
+minimum record.
+@return end of log record or NULL */
+UNIV_INTERN
+byte*
+btr_parse_set_min_rec_mark(
+/*=======================*/
+ byte* ptr, /*!< in: buffer */
+ byte* end_ptr,/*!< in: buffer end */
+ ulint comp, /*!< in: nonzero=compact page format */
+ page_t* page, /*!< in: page or NULL */
+ mtr_t* mtr) /*!< in: mtr or NULL */
+{
+ rec_t* rec;
+
+ if (end_ptr < ptr + 2) {
+
+ return(NULL);
+ }
+
+ if (page) {
+ ut_a(!page_is_comp(page) == !comp);
+
+ rec = page + mach_read_from_2(ptr);
+
+ btr_set_min_rec_mark(rec, mtr);
+ }
+
+ return(ptr + 2);
+}
+
+/****************************************************************//**
+Sets a record as the predefined minimum record. */
+UNIV_INTERN
+void
+btr_set_min_rec_mark(
+/*=================*/
+ rec_t* rec, /*!< in: record */
+ mtr_t* mtr) /*!< in: mtr */
+{
+ ulint info_bits;
+
+ if (UNIV_LIKELY(page_rec_is_comp(rec))) {
+ info_bits = rec_get_info_bits(rec, TRUE);
+
+ rec_set_info_bits_new(rec, info_bits | REC_INFO_MIN_REC_FLAG);
+
+ btr_set_min_rec_mark_log(rec, MLOG_COMP_REC_MIN_MARK, mtr);
+ } else {
+ info_bits = rec_get_info_bits(rec, FALSE);
+
+ rec_set_info_bits_old(rec, info_bits | REC_INFO_MIN_REC_FLAG);
+
+ btr_set_min_rec_mark_log(rec, MLOG_REC_MIN_MARK, mtr);
+ }
+}
+
+#ifndef UNIV_HOTBACKUP
+/*************************************************************//**
+Deletes on the upper level the node pointer to a page. */
+UNIV_INTERN
+void
+btr_node_ptr_delete(
+/*================*/
+ dict_index_t* index, /*!< in: index tree */
+ buf_block_t* block, /*!< in: page whose node pointer is deleted */
+ mtr_t* mtr) /*!< in: mtr */
+{
+ btr_cur_t cursor;
+ ibool compressed;
+ ulint err;
+
+ ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX));
+
+ /* Delete node pointer on father page */
+ btr_page_get_father(index, block, mtr, &cursor);
+
+ compressed = btr_cur_pessimistic_delete(&err, TRUE, &cursor, RB_NONE,
+ mtr);
+ ut_a(err == DB_SUCCESS);
+
+ if (!compressed) {
+ btr_cur_compress_if_useful(&cursor, mtr);
+ }
+}
+
+/*************************************************************//**
+If page is the only on its level, this function moves its records to the
+father page, thus reducing the tree height. */
+static
+void
+btr_lift_page_up(
+/*=============*/
+ dict_index_t* index, /*!< in: index tree */
+ buf_block_t* block, /*!< in: page which is the only on its level;
+ must not be empty: use
+ btr_discard_only_page_on_level if the last
+ record from the page should be removed */
+ mtr_t* mtr) /*!< in: mtr */
+{
+ buf_block_t* father_block;
+ page_t* father_page;
+ ulint page_level;
+ page_zip_des_t* father_page_zip;
+ page_t* page = buf_block_get_frame(block);
+ ulint root_page_no;
+ buf_block_t* blocks[BTR_MAX_LEVELS];
+ ulint n_blocks; /*!< last used index in blocks[] */
+ ulint i;
+
+ ut_ad(btr_page_get_prev(page, mtr) == FIL_NULL);
+ ut_ad(btr_page_get_next(page, mtr) == FIL_NULL);
+ ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX));
+
+ page_level = btr_page_get_level(page, mtr);
+ root_page_no = dict_index_get_page(index);
+
+ {
+ btr_cur_t cursor;
+ mem_heap_t* heap = mem_heap_create(100);
+ ulint* offsets;
+ buf_block_t* b;
+
+ offsets = btr_page_get_father_block(NULL, heap, index,
+ block, mtr, &cursor);
+ father_block = btr_cur_get_block(&cursor);
+ father_page_zip = buf_block_get_page_zip(father_block);
+ father_page = buf_block_get_frame(father_block);
+
+ n_blocks = 0;
+
+ /* Store all ancestor pages so we can reset their
+ levels later on. We have to do all the searches on
+ the tree now because later on, after we've replaced
+ the first level, the tree is in an inconsistent state
+ and can not be searched. */
+ for (b = father_block;
+ buf_block_get_page_no(b) != root_page_no; ) {
+ ut_a(n_blocks < BTR_MAX_LEVELS);
+
+ offsets = btr_page_get_father_block(offsets, heap,
+ index, b,
+ mtr, &cursor);
+
+ blocks[n_blocks++] = b = btr_cur_get_block(&cursor);
+ }
+
+ mem_heap_free(heap);
+ }
+
+ btr_search_drop_page_hash_index(block);
+
+ /* Make the father empty */
+ btr_page_empty(father_block, father_page_zip, index, page_level, mtr);
+
+ /* Copy the records to the father page one by one. */
+ if (0
+#ifdef UNIV_ZIP_COPY
+ || father_page_zip
+#endif /* UNIV_ZIP_COPY */
+ || UNIV_UNLIKELY
+ (!page_copy_rec_list_end(father_block, block,
+ page_get_infimum_rec(page),
+ index, mtr))) {
+ const page_zip_des_t* page_zip
+ = buf_block_get_page_zip(block);
+ ut_a(father_page_zip);
+ ut_a(page_zip);
+
+ /* Copy the page byte for byte. */
+ page_zip_copy_recs(father_page_zip, father_page,
+ page_zip, page, index, mtr);
+
+ /* Update the lock table and possible hash index. */
+
+ lock_move_rec_list_end(father_block, block,
+ page_get_infimum_rec(page));
+
+ btr_search_move_or_delete_hash_entries(father_block, block,
+ index);
+ }
+
+ lock_update_copy_and_discard(father_block, block);
+
+ /* Go upward to root page, decrementing levels by one. */
+ for (i = 0; i < n_blocks; i++, page_level++) {
+ page_t* page = buf_block_get_frame(blocks[i]);
+ page_zip_des_t* page_zip= buf_block_get_page_zip(blocks[i]);
+
+ ut_ad(btr_page_get_level(page, mtr) == page_level + 1);
+
+ btr_page_set_level(page, page_zip, page_level, mtr);
+#ifdef UNIV_ZIP_DEBUG
+ ut_a(!page_zip || page_zip_validate(page_zip, page));
+#endif /* UNIV_ZIP_DEBUG */
+ }
+
+ /* Free the file page */
+ btr_page_free(index, block, mtr);
+
+ /* We play it safe and reset the free bits for the father */
+ if (!dict_index_is_clust(index)) {
+ ibuf_reset_free_bits(father_block);
+ }
+ ut_ad(page_validate(father_page, index));
+ ut_ad(btr_check_node_ptr(index, father_block, mtr));
+}
+
+/*************************************************************//**
+Tries to merge the page first to the left immediate brother if such a
+brother exists, and the node pointers to the current page and to the brother
+reside on the same page. If the left brother does not satisfy these
+conditions, looks at the right brother. If the page is the only one on that
+level lifts the records of the page to the father page, thus reducing the
+tree height. It is assumed that mtr holds an x-latch on the tree and on the
+page. If cursor is on the leaf level, mtr must also hold x-latches to the
+brothers, if they exist.
+@return TRUE on success */
+UNIV_INTERN
+ibool
+btr_compress(
+/*=========*/
+ btr_cur_t* cursor, /*!< in: cursor on the page to merge or lift;
+ the page must not be empty: in record delete
+ use btr_discard_page if the page would become
+ empty */
+ mtr_t* mtr) /*!< in: mtr */
+{
+ dict_index_t* index;
+ ulint space;
+ ulint zip_size;
+ ulint left_page_no;
+ ulint right_page_no;
+ buf_block_t* merge_block;
+ page_t* merge_page;
+ page_zip_des_t* merge_page_zip;
+ ibool is_left;
+ buf_block_t* block;
+ page_t* page;
+ btr_cur_t father_cursor;
+ mem_heap_t* heap;
+ ulint* offsets;
+ ulint data_size;
+ ulint n_recs;
+ ulint max_ins_size;
+ ulint max_ins_size_reorg;
+ ulint level;
+
+ block = btr_cur_get_block(cursor);
+ page = btr_cur_get_page(cursor);
+ index = btr_cur_get_index(cursor);
+ ut_a((ibool) !!page_is_comp(page) == dict_table_is_comp(index->table));
+
+ ut_ad(mtr_memo_contains(mtr, dict_index_get_lock(index),
+ MTR_MEMO_X_LOCK));
+ ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX));
+ level = btr_page_get_level(page, mtr);
+ space = dict_index_get_space(index);
+ zip_size = dict_table_zip_size(index->table);
+
+ left_page_no = btr_page_get_prev(page, mtr);
+ right_page_no = btr_page_get_next(page, mtr);
+
+#if 0
+ fprintf(stderr, "Merge left page %lu right %lu \n",
+ left_page_no, right_page_no);
+#endif
+
+ heap = mem_heap_create(100);
+ offsets = btr_page_get_father_block(NULL, heap, index, block, mtr,
+ &father_cursor);
+
+ /* Decide the page to which we try to merge and which will inherit
+ the locks */
+
+ is_left = left_page_no != FIL_NULL;
+
+ if (is_left) {
+
+ merge_block = btr_block_get(space, zip_size, left_page_no,
+ RW_X_LATCH, mtr);
+ merge_page = buf_block_get_frame(merge_block);
+#ifdef UNIV_BTR_DEBUG
+ ut_a(btr_page_get_next(merge_page, mtr)
+ == buf_block_get_page_no(block));
+#endif /* UNIV_BTR_DEBUG */
+ } else if (right_page_no != FIL_NULL) {
+
+ merge_block = btr_block_get(space, zip_size, right_page_no,
+ RW_X_LATCH, mtr);
+ merge_page = buf_block_get_frame(merge_block);
+#ifdef UNIV_BTR_DEBUG
+ ut_a(btr_page_get_prev(merge_page, mtr)
+ == buf_block_get_page_no(block));
+#endif /* UNIV_BTR_DEBUG */
+ } else {
+ /* The page is the only one on the level, lift the records
+ to the father */
+ btr_lift_page_up(index, block, mtr);
+ mem_heap_free(heap);
+ return(TRUE);
+ }
+
+ n_recs = page_get_n_recs(page);
+ data_size = page_get_data_size(page);
+#ifdef UNIV_BTR_DEBUG
+ ut_a(page_is_comp(merge_page) == page_is_comp(page));
+#endif /* UNIV_BTR_DEBUG */
+
+ max_ins_size_reorg = page_get_max_insert_size_after_reorganize(
+ merge_page, n_recs);
+ if (data_size > max_ins_size_reorg) {
+
+ /* No space for merge */
+err_exit:
+ /* We play it safe and reset the free bits. */
+ if (zip_size
+ && page_is_leaf(merge_page)
+ && !dict_index_is_clust(index)) {
+ ibuf_reset_free_bits(merge_block);
+ }
+
+ mem_heap_free(heap);
+ return(FALSE);
+ }
+
+ ut_ad(page_validate(merge_page, index));
+
+ max_ins_size = page_get_max_insert_size(merge_page, n_recs);
+
+ if (UNIV_UNLIKELY(data_size > max_ins_size)) {
+
+ /* We have to reorganize merge_page */
+
+ if (UNIV_UNLIKELY(!btr_page_reorganize(merge_block,
+ index, mtr))) {
+
+ goto err_exit;
+ }
+
+ max_ins_size = page_get_max_insert_size(merge_page, n_recs);
+
+ ut_ad(page_validate(merge_page, index));
+ ut_ad(max_ins_size == max_ins_size_reorg);
+
+ if (UNIV_UNLIKELY(data_size > max_ins_size)) {
+
+ /* Add fault tolerance, though this should
+ never happen */
+
+ goto err_exit;
+ }
+ }
+
+ merge_page_zip = buf_block_get_page_zip(merge_block);
+#ifdef UNIV_ZIP_DEBUG
+ if (UNIV_LIKELY_NULL(merge_page_zip)) {
+ const page_zip_des_t* page_zip
+ = buf_block_get_page_zip(block);
+ ut_a(page_zip);
+ ut_a(page_zip_validate(merge_page_zip, merge_page));
+ ut_a(page_zip_validate(page_zip, page));
+ }
+#endif /* UNIV_ZIP_DEBUG */
+
+ /* Move records to the merge page */
+ if (is_left) {
+ rec_t* orig_pred = page_copy_rec_list_start(
+ merge_block, block, page_get_supremum_rec(page),
+ index, mtr);
+
+ if (UNIV_UNLIKELY(!orig_pred)) {
+ goto err_exit;
+ }
+
+ btr_search_drop_page_hash_index(block);
+
+ /* Remove the page from the level list */
+ btr_level_list_remove(space, zip_size, page, mtr);
+
+ btr_node_ptr_delete(index, block, mtr);
+ lock_update_merge_left(merge_block, orig_pred, block);
+ } else {
+ rec_t* orig_succ;
+#ifdef UNIV_BTR_DEBUG
+ byte fil_page_prev[4];
+#endif /* UNIV_BTR_DEBUG */
+
+ if (UNIV_LIKELY_NULL(merge_page_zip)) {
+ /* The function page_zip_compress(), which will be
+ invoked by page_copy_rec_list_end() below,
+ requires that FIL_PAGE_PREV be FIL_NULL.
+ Clear the field, but prepare to restore it. */
+#ifdef UNIV_BTR_DEBUG
+ memcpy(fil_page_prev, merge_page + FIL_PAGE_PREV, 4);
+#endif /* UNIV_BTR_DEBUG */
+#if FIL_NULL != 0xffffffff
+# error "FIL_NULL != 0xffffffff"
+#endif
+ memset(merge_page + FIL_PAGE_PREV, 0xff, 4);
+ }
+
+ orig_succ = page_copy_rec_list_end(merge_block, block,
+ page_get_infimum_rec(page),
+ cursor->index, mtr);
+
+ if (UNIV_UNLIKELY(!orig_succ)) {
+ ut_a(merge_page_zip);
+#ifdef UNIV_BTR_DEBUG
+ /* FIL_PAGE_PREV was restored from merge_page_zip. */
+ ut_a(!memcmp(fil_page_prev,
+ merge_page + FIL_PAGE_PREV, 4));
+#endif /* UNIV_BTR_DEBUG */
+ goto err_exit;
+ }
+
+ btr_search_drop_page_hash_index(block);
+
+#ifdef UNIV_BTR_DEBUG
+ if (UNIV_LIKELY_NULL(merge_page_zip)) {
+ /* Restore FIL_PAGE_PREV in order to avoid an assertion
+ failure in btr_level_list_remove(), which will set
+ the field again to FIL_NULL. Even though this makes
+ merge_page and merge_page_zip inconsistent for a
+ split second, it is harmless, because the pages
+ are X-latched. */
+ memcpy(merge_page + FIL_PAGE_PREV, fil_page_prev, 4);
+ }
+#endif /* UNIV_BTR_DEBUG */
+
+ /* Remove the page from the level list */
+ btr_level_list_remove(space, zip_size, page, mtr);
+
+ /* Replace the address of the old child node (= page) with the
+ address of the merge page to the right */
+
+ btr_node_ptr_set_child_page_no(
+ btr_cur_get_rec(&father_cursor),
+ btr_cur_get_page_zip(&father_cursor),
+ offsets, right_page_no, mtr);
+ btr_node_ptr_delete(index, merge_block, mtr);
+
+ lock_update_merge_right(merge_block, orig_succ, block);
+ }
+
+ mem_heap_free(heap);
+
+ if (!dict_index_is_clust(index) && page_is_leaf(merge_page)) {
+ /* Update the free bits of the B-tree page in the
+ insert buffer bitmap. This has to be done in a
+ separate mini-transaction that is committed before the
+ main mini-transaction. We cannot update the insert
+ buffer bitmap in this mini-transaction, because
+ btr_compress() can be invoked recursively without
+ committing the mini-transaction in between. Since
+ insert buffer bitmap pages have a lower rank than
+ B-tree pages, we must not access other pages in the
+ same mini-transaction after accessing an insert buffer
+ bitmap page. */
+
+ /* The free bits in the insert buffer bitmap must
+ never exceed the free space on a page. It is safe to
+ decrement or reset the bits in the bitmap in a
+ mini-transaction that is committed before the
+ mini-transaction that affects the free space. */
+
+ /* It is unsafe to increment the bits in a separately
+ committed mini-transaction, because in crash recovery,
+ the free bits could momentarily be set too high. */
+
+ if (zip_size) {
+ /* Because the free bits may be incremented
+ and we cannot update the insert buffer bitmap
+ in the same mini-transaction, the only safe
+ thing we can do here is the pessimistic
+ approach: reset the free bits. */
+ ibuf_reset_free_bits(merge_block);
+ } else {
+ /* On uncompressed pages, the free bits will
+ never increase here. Thus, it is safe to
+ write the bits accurately in a separate
+ mini-transaction. */
+ ibuf_update_free_bits_if_full(merge_block,
+ UNIV_PAGE_SIZE,
+ ULINT_UNDEFINED);
+ }
+ }
+
+ ut_ad(page_validate(merge_page, index));
+#ifdef UNIV_ZIP_DEBUG
+ ut_a(!merge_page_zip || page_zip_validate(merge_page_zip, merge_page));
+#endif /* UNIV_ZIP_DEBUG */
+
+ /* Free the file page */
+ btr_page_free(index, block, mtr);
+
+ ut_ad(btr_check_node_ptr(index, merge_block, mtr));
+ return(TRUE);
+}
+
+/*************************************************************//**
+Discards a page that is the only page on its level. This will empty
+the whole B-tree, leaving just an empty root page. This function
+should never be reached, because btr_compress(), which is invoked in
+delete operations, calls btr_lift_page_up() to flatten the B-tree. */
+static
+void
+btr_discard_only_page_on_level(
+/*===========================*/
+ dict_index_t* index, /*!< in: index tree */
+ buf_block_t* block, /*!< in: page which is the only on its level */
+ mtr_t* mtr) /*!< in: mtr */
+{
+ ulint page_level = 0;
+ trx_id_t max_trx_id;
+
+ /* Save the PAGE_MAX_TRX_ID from the leaf page. */
+ max_trx_id = page_get_max_trx_id(buf_block_get_frame(block));
+
+ while (buf_block_get_page_no(block) != dict_index_get_page(index)) {
+ btr_cur_t cursor;
+ buf_block_t* father;
+ const page_t* page = buf_block_get_frame(block);
+
+ ut_a(page_get_n_recs(page) == 1);
+ ut_a(page_level == btr_page_get_level(page, mtr));
+ ut_a(btr_page_get_prev(page, mtr) == FIL_NULL);
+ ut_a(btr_page_get_next(page, mtr) == FIL_NULL);
+
+ ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX));
+ btr_search_drop_page_hash_index(block);
+
+ btr_page_get_father(index, block, mtr, &cursor);
+ father = btr_cur_get_block(&cursor);
+
+ lock_update_discard(father, PAGE_HEAP_NO_SUPREMUM, block);
+
+ /* Free the file page */
+ btr_page_free(index, block, mtr);
+
+ block = father;
+ page_level++;
+ }
+
+ /* block is the root page, which must be empty, except
+ for the node pointer to the (now discarded) block(s). */
+
+#ifdef UNIV_BTR_DEBUG
+ if (!dict_index_is_ibuf(index)) {
+ const page_t* root = buf_block_get_frame(block);
+ const ulint space = dict_index_get_space(index);
+ ut_a(btr_root_fseg_validate(FIL_PAGE_DATA + PAGE_BTR_SEG_LEAF
+ + root, space));
+ ut_a(btr_root_fseg_validate(FIL_PAGE_DATA + PAGE_BTR_SEG_TOP
+ + root, space));
+ }
+#endif /* UNIV_BTR_DEBUG */
+
+ btr_page_empty(block, buf_block_get_page_zip(block), index, 0, mtr);
+
+ if (!dict_index_is_clust(index)) {
+ /* We play it safe and reset the free bits for the root */
+ ibuf_reset_free_bits(block);
+
+ if (page_is_leaf(buf_block_get_frame(block))) {
+ ut_a(!ut_dulint_is_zero(max_trx_id));
+ page_set_max_trx_id(block,
+ buf_block_get_page_zip(block),
+ max_trx_id, mtr);
+ }
+ }
+}
+
+/*************************************************************//**
+Discards a page from a B-tree. This is used to remove the last record from
+a B-tree page: the whole page must be removed at the same time. This cannot
+be used for the root page, which is allowed to be empty. */
+UNIV_INTERN
+void
+btr_discard_page(
+/*=============*/
+ btr_cur_t* cursor, /*!< in: cursor on the page to discard: not on
+ the root page */
+ mtr_t* mtr) /*!< in: mtr */
+{
+ dict_index_t* index;
+ ulint space;
+ ulint zip_size;
+ ulint left_page_no;
+ ulint right_page_no;
+ buf_block_t* merge_block;
+ page_t* merge_page;
+ buf_block_t* block;
+ page_t* page;
+ rec_t* node_ptr;
+
+ block = btr_cur_get_block(cursor);
+ index = btr_cur_get_index(cursor);
+
+ ut_ad(dict_index_get_page(index) != buf_block_get_page_no(block));
+ ut_ad(mtr_memo_contains(mtr, dict_index_get_lock(index),
+ MTR_MEMO_X_LOCK));
+ ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX));
+ space = dict_index_get_space(index);
+ zip_size = dict_table_zip_size(index->table);
+
+ /* Decide the page which will inherit the locks */
+
+ left_page_no = btr_page_get_prev(buf_block_get_frame(block), mtr);
+ right_page_no = btr_page_get_next(buf_block_get_frame(block), mtr);
+
+ if (left_page_no != FIL_NULL) {
+ merge_block = btr_block_get(space, zip_size, left_page_no,
+ RW_X_LATCH, mtr);
+ merge_page = buf_block_get_frame(merge_block);
+#ifdef UNIV_BTR_DEBUG
+ ut_a(btr_page_get_next(merge_page, mtr)
+ == buf_block_get_page_no(block));
+#endif /* UNIV_BTR_DEBUG */
+ } else if (right_page_no != FIL_NULL) {
+ merge_block = btr_block_get(space, zip_size, right_page_no,
+ RW_X_LATCH, mtr);
+ merge_page = buf_block_get_frame(merge_block);
+#ifdef UNIV_BTR_DEBUG
+ ut_a(btr_page_get_prev(merge_page, mtr)
+ == buf_block_get_page_no(block));
+#endif /* UNIV_BTR_DEBUG */
+ } else {
+ btr_discard_only_page_on_level(index, block, mtr);
+
+ return;
+ }
+
+ page = buf_block_get_frame(block);
+ ut_a(page_is_comp(merge_page) == page_is_comp(page));
+ btr_search_drop_page_hash_index(block);
+
+ if (left_page_no == FIL_NULL && !page_is_leaf(page)) {
+
+ /* We have to mark the leftmost node pointer on the right
+ side page as the predefined minimum record */
+ node_ptr = page_rec_get_next(page_get_infimum_rec(merge_page));
+
+ ut_ad(page_rec_is_user_rec(node_ptr));
+
+ /* This will make page_zip_validate() fail on merge_page
+ until btr_level_list_remove() completes. This is harmless,
+ because everything will take place within a single
+ mini-transaction and because writing to the redo log
+ is an atomic operation (performed by mtr_commit()). */
+ btr_set_min_rec_mark(node_ptr, mtr);
+ }
+
+ btr_node_ptr_delete(index, block, mtr);
+
+ /* Remove the page from the level list */
+ btr_level_list_remove(space, zip_size, page, mtr);
+#ifdef UNIV_ZIP_DEBUG
+ {
+ page_zip_des_t* merge_page_zip
+ = buf_block_get_page_zip(merge_block);
+ ut_a(!merge_page_zip
+ || page_zip_validate(merge_page_zip, merge_page));
+ }
+#endif /* UNIV_ZIP_DEBUG */
+
+ if (left_page_no != FIL_NULL) {
+ lock_update_discard(merge_block, PAGE_HEAP_NO_SUPREMUM,
+ block);
+ } else {
+ lock_update_discard(merge_block,
+ lock_get_min_heap_no(merge_block),
+ block);
+ }
+
+ /* Free the file page */
+ btr_page_free(index, block, mtr);
+
+ ut_ad(btr_check_node_ptr(index, merge_block, mtr));
+}
+
+#ifdef UNIV_BTR_PRINT
+/*************************************************************//**
+Prints size info of a B-tree. */
+UNIV_INTERN
+void
+btr_print_size(
+/*===========*/
+ dict_index_t* index) /*!< in: index tree */
+{
+ page_t* root;
+ fseg_header_t* seg;
+ mtr_t mtr;
+
+ if (dict_index_is_ibuf(index)) {
+ fputs("Sorry, cannot print info of an ibuf tree:"
+ " use ibuf functions\n", stderr);
+
+ return;
+ }
+
+ mtr_start(&mtr);
+
+ root = btr_root_get(index, &mtr);
+
+ seg = root + PAGE_HEADER + PAGE_BTR_SEG_TOP;
+
+ fputs("INFO OF THE NON-LEAF PAGE SEGMENT\n", stderr);
+ fseg_print(seg, &mtr);
+
+ if (!(index->type & DICT_UNIVERSAL)) {
+
+ seg = root + PAGE_HEADER + PAGE_BTR_SEG_LEAF;
+
+ fputs("INFO OF THE LEAF PAGE SEGMENT\n", stderr);
+ fseg_print(seg, &mtr);
+ }
+
+ mtr_commit(&mtr);
+}
+
+/************************************************************//**
+Prints recursively index tree pages. */
+static
+void
+btr_print_recursive(
+/*================*/
+ dict_index_t* index, /*!< in: index tree */
+ buf_block_t* block, /*!< in: index page */
+ ulint width, /*!< in: print this many entries from start
+ and end */
+ mem_heap_t** heap, /*!< in/out: heap for rec_get_offsets() */
+ ulint** offsets,/*!< in/out: buffer for rec_get_offsets() */
+ mtr_t* mtr) /*!< in: mtr */
+{
+ const page_t* page = buf_block_get_frame(block);
+ page_cur_t cursor;
+ ulint n_recs;
+ ulint i = 0;
+ mtr_t mtr2;
+
+ ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX));
+ fprintf(stderr, "NODE ON LEVEL %lu page number %lu\n",
+ (ulong) btr_page_get_level(page, mtr),
+ (ulong) buf_block_get_page_no(block));
+
+ page_print(block, index, width, width);
+
+ n_recs = page_get_n_recs(page);
+
+ page_cur_set_before_first(block, &cursor);
+ page_cur_move_to_next(&cursor);
+
+ while (!page_cur_is_after_last(&cursor)) {
+
+ if (page_is_leaf(page)) {
+
+ /* If this is the leaf level, do nothing */
+
+ } else if ((i <= width) || (i >= n_recs - width)) {
+
+ const rec_t* node_ptr;
+
+ mtr_start(&mtr2);
+
+ node_ptr = page_cur_get_rec(&cursor);
+
+ *offsets = rec_get_offsets(node_ptr, index, *offsets,
+ ULINT_UNDEFINED, heap);
+ btr_print_recursive(index,
+ btr_node_ptr_get_child(node_ptr,
+ index,
+ *offsets,
+ &mtr2),
+ width, heap, offsets, &mtr2);
+ mtr_commit(&mtr2);
+ }
+
+ page_cur_move_to_next(&cursor);
+ i++;
+ }
+}
+
+/**************************************************************//**
+Prints directories and other info of all nodes in the tree. */
+UNIV_INTERN
+void
+btr_print_index(
+/*============*/
+ dict_index_t* index, /*!< in: index */
+ ulint width) /*!< in: print this many entries from start
+ and end */
+{
+ mtr_t mtr;
+ buf_block_t* root;
+ mem_heap_t* heap = NULL;
+ ulint offsets_[REC_OFFS_NORMAL_SIZE];
+ ulint* offsets = offsets_;
+ rec_offs_init(offsets_);
+
+ fputs("--------------------------\n"
+ "INDEX TREE PRINT\n", stderr);
+
+ mtr_start(&mtr);
+
+ root = btr_root_block_get(index, &mtr);
+
+ btr_print_recursive(index, root, width, &heap, &offsets, &mtr);
+ if (UNIV_LIKELY_NULL(heap)) {
+ mem_heap_free(heap);
+ }
+
+ mtr_commit(&mtr);
+
+ btr_validate_index(index, NULL);
+}
+#endif /* UNIV_BTR_PRINT */
+
+#ifdef UNIV_DEBUG
+/************************************************************//**
+Checks that the node pointer to a page is appropriate.
+@return TRUE */
+UNIV_INTERN
+ibool
+btr_check_node_ptr(
+/*===============*/
+ dict_index_t* index, /*!< in: index tree */
+ buf_block_t* block, /*!< in: index page */
+ mtr_t* mtr) /*!< in: mtr */
+{
+ mem_heap_t* heap;
+ dtuple_t* tuple;
+ ulint* offsets;
+ btr_cur_t cursor;
+ page_t* page = buf_block_get_frame(block);
+
+ ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX));
+ if (dict_index_get_page(index) == buf_block_get_page_no(block)) {
+
+ return(TRUE);
+ }
+
+ heap = mem_heap_create(256);
+ offsets = btr_page_get_father_block(NULL, heap, index, block, mtr,
+ &cursor);
+
+ if (page_is_leaf(page)) {
+
+ goto func_exit;
+ }
+
+ tuple = dict_index_build_node_ptr(
+ index, page_rec_get_next(page_get_infimum_rec(page)), 0, heap,
+ btr_page_get_level(page, mtr));
+
+ ut_a(!cmp_dtuple_rec(tuple, btr_cur_get_rec(&cursor), offsets));
+func_exit:
+ mem_heap_free(heap);
+
+ return(TRUE);
+}
+#endif /* UNIV_DEBUG */
+
+/************************************************************//**
+Display identification information for a record. */
+static
+void
+btr_index_rec_validate_report(
+/*==========================*/
+ const page_t* page, /*!< in: index page */
+ const rec_t* rec, /*!< in: index record */
+ const dict_index_t* index) /*!< in: index */
+{
+ fputs("InnoDB: Record in ", stderr);
+ dict_index_name_print(stderr, NULL, index);
+ fprintf(stderr, ", page %lu, at offset %lu\n",
+ page_get_page_no(page), (ulint) page_offset(rec));
+}
+
+/************************************************************//**
+Checks the size and number of fields in a record based on the definition of
+the index.
+@return TRUE if ok */
+UNIV_INTERN
+ibool
+btr_index_rec_validate(
+/*===================*/
+ const rec_t* rec, /*!< in: index record */
+ const dict_index_t* index, /*!< in: index */
+ ibool dump_on_error) /*!< in: TRUE if the function
+ should print hex dump of record
+ and page on error */
+{
+ ulint len;
+ ulint n;
+ ulint i;
+ const page_t* page;
+ mem_heap_t* heap = NULL;
+ ulint offsets_[REC_OFFS_NORMAL_SIZE];
+ ulint* offsets = offsets_;
+ rec_offs_init(offsets_);
+
+ page = page_align(rec);
+
+ if (UNIV_UNLIKELY(index->type & DICT_UNIVERSAL)) {
+ /* The insert buffer index tree can contain records from any
+ other index: we cannot check the number of fields or
+ their length */
+
+ return(TRUE);
+ }
+
+ if (UNIV_UNLIKELY((ibool)!!page_is_comp(page)
+ != dict_table_is_comp(index->table))) {
+ btr_index_rec_validate_report(page, rec, index);
+ fprintf(stderr, "InnoDB: compact flag=%lu, should be %lu\n",
+ (ulong) !!page_is_comp(page),
+ (ulong) dict_table_is_comp(index->table));
+
+ return(FALSE);
+ }
+
+ n = dict_index_get_n_fields(index);
+
+ if (!page_is_comp(page)
+ && UNIV_UNLIKELY(rec_get_n_fields_old(rec) != n)) {
+ btr_index_rec_validate_report(page, rec, index);
+ fprintf(stderr, "InnoDB: has %lu fields, should have %lu\n",
+ (ulong) rec_get_n_fields_old(rec), (ulong) n);
+
+ if (dump_on_error) {
+ buf_page_print(page, 0);
+
+ fputs("InnoDB: corrupt record ", stderr);
+ rec_print_old(stderr, rec);
+ putc('\n', stderr);
+ }
+ return(FALSE);
+ }
+
+ offsets = rec_get_offsets(rec, index, offsets, ULINT_UNDEFINED, &heap);
+
+ for (i = 0; i < n; i++) {
+ ulint fixed_size = dict_col_get_fixed_size(
+ dict_index_get_nth_col(index, i), page_is_comp(page));
+
+ rec_get_nth_field_offs(offsets, i, &len);
+
+ /* Note that if fixed_size != 0, it equals the
+ length of a fixed-size column in the clustered index.
+ A prefix index of the column is of fixed, but different
+ length. When fixed_size == 0, prefix_len is the maximum
+ length of the prefix index column. */
+
+ if ((dict_index_get_nth_field(index, i)->prefix_len == 0
+ && len != UNIV_SQL_NULL && fixed_size
+ && len != fixed_size)
+ || (dict_index_get_nth_field(index, i)->prefix_len > 0
+ && len != UNIV_SQL_NULL
+ && len
+ > dict_index_get_nth_field(index, i)->prefix_len)) {
+
+ btr_index_rec_validate_report(page, rec, index);
+ fprintf(stderr,
+ "InnoDB: field %lu len is %lu,"
+ " should be %lu\n",
+ (ulong) i, (ulong) len, (ulong) fixed_size);
+
+ if (dump_on_error) {
+ buf_page_print(page, 0);
+
+ fputs("InnoDB: corrupt record ", stderr);
+ rec_print_new(stderr, rec, offsets);
+ putc('\n', stderr);
+ }
+ if (UNIV_LIKELY_NULL(heap)) {
+ mem_heap_free(heap);
+ }
+ return(FALSE);
+ }
+ }
+
+ if (UNIV_LIKELY_NULL(heap)) {
+ mem_heap_free(heap);
+ }
+ return(TRUE);
+}
+
+/************************************************************//**
+Checks the size and number of fields in records based on the definition of
+the index.
+@return TRUE if ok */
+static
+ibool
+btr_index_page_validate(
+/*====================*/
+ buf_block_t* block, /*!< in: index page */
+ dict_index_t* index) /*!< in: index */
+{
+ page_cur_t cur;
+ ibool ret = TRUE;
+
+ page_cur_set_before_first(block, &cur);
+ page_cur_move_to_next(&cur);
+
+ for (;;) {
+ if (page_cur_is_after_last(&cur)) {
+
+ break;
+ }
+
+ if (!btr_index_rec_validate(cur.rec, index, TRUE)) {
+
+ return(FALSE);
+ }
+
+ page_cur_move_to_next(&cur);
+ }
+
+ return(ret);
+}
+
+/************************************************************//**
+Report an error on one page of an index tree. */
+static
+void
+btr_validate_report1(
+/*=================*/
+ dict_index_t* index, /*!< in: index */
+ ulint level, /*!< in: B-tree level */
+ const buf_block_t* block) /*!< in: index page */
+{
+ fprintf(stderr, "InnoDB: Error in page %lu of ",
+ buf_block_get_page_no(block));
+ dict_index_name_print(stderr, NULL, index);
+ if (level) {
+ fprintf(stderr, ", index tree level %lu", level);
+ }
+ putc('\n', stderr);
+}
+
+/************************************************************//**
+Report an error on two pages of an index tree. */
+static
+void
+btr_validate_report2(
+/*=================*/
+ const dict_index_t* index, /*!< in: index */
+ ulint level, /*!< in: B-tree level */
+ const buf_block_t* block1, /*!< in: first index page */
+ const buf_block_t* block2) /*!< in: second index page */
+{
+ fprintf(stderr, "InnoDB: Error in pages %lu and %lu of ",
+ buf_block_get_page_no(block1),
+ buf_block_get_page_no(block2));
+ dict_index_name_print(stderr, NULL, index);
+ if (level) {
+ fprintf(stderr, ", index tree level %lu", level);
+ }
+ putc('\n', stderr);
+}
+
+/************************************************************//**
+Validates index tree level.
+@return TRUE if ok */
+static
+ibool
+btr_validate_level(
+/*===============*/
+ dict_index_t* index, /*!< in: index tree */
+ trx_t* trx, /*!< in: transaction or NULL */
+ ulint level) /*!< in: level number */
+{
+ ulint space;
+ ulint zip_size;
+ buf_block_t* block;
+ page_t* page;
+ buf_block_t* right_block = 0; /* remove warning */
+ page_t* right_page = 0; /* remove warning */
+ page_t* father_page;
+ btr_cur_t node_cur;
+ btr_cur_t right_node_cur;
+ rec_t* rec;
+ ulint right_page_no;
+ ulint left_page_no;
+ page_cur_t cursor;
+ dtuple_t* node_ptr_tuple;
+ ibool ret = TRUE;
+ mtr_t mtr;
+ mem_heap_t* heap = mem_heap_create(256);
+ ulint* offsets = NULL;
+ ulint* offsets2= NULL;
+#ifdef UNIV_ZIP_DEBUG
+ page_zip_des_t* page_zip;
+#endif /* UNIV_ZIP_DEBUG */
+
+ mtr_start(&mtr);
+
+ mtr_x_lock(dict_index_get_lock(index), &mtr);
+
+ block = btr_root_block_get(index, &mtr);
+ page = buf_block_get_frame(block);
+
+ space = dict_index_get_space(index);
+ zip_size = dict_table_zip_size(index->table);
+
+ while (level != btr_page_get_level(page, &mtr)) {
+ const rec_t* node_ptr;
+
+ ut_a(space == buf_block_get_space(block));
+ ut_a(space == page_get_space_id(page));
+#ifdef UNIV_ZIP_DEBUG
+ page_zip = buf_block_get_page_zip(block);
+ ut_a(!page_zip || page_zip_validate(page_zip, page));
+#endif /* UNIV_ZIP_DEBUG */
+ ut_a(!page_is_leaf(page));
+
+ page_cur_set_before_first(block, &cursor);
+ page_cur_move_to_next(&cursor);
+
+ node_ptr = page_cur_get_rec(&cursor);
+ offsets = rec_get_offsets(node_ptr, index, offsets,
+ ULINT_UNDEFINED, &heap);
+ block = btr_node_ptr_get_child(node_ptr, index, offsets, &mtr);
+ page = buf_block_get_frame(block);
+ }
+
+ /* Now we are on the desired level. Loop through the pages on that
+ level. */
+loop:
+ if (trx_is_interrupted(trx)) {
+ mtr_commit(&mtr);
+ mem_heap_free(heap);
+ return(ret);
+ }
+ mem_heap_empty(heap);
+ offsets = offsets2 = NULL;
+ mtr_x_lock(dict_index_get_lock(index), &mtr);
+
+#ifdef UNIV_ZIP_DEBUG
+ page_zip = buf_block_get_page_zip(block);
+ ut_a(!page_zip || page_zip_validate(page_zip, page));
+#endif /* UNIV_ZIP_DEBUG */
+
+ /* Check ordering etc. of records */
+
+ if (!page_validate(page, index)) {
+ btr_validate_report1(index, level, block);
+
+ ret = FALSE;
+ } else if (level == 0) {
+ /* We are on level 0. Check that the records have the right
+ number of fields, and field lengths are right. */
+
+ if (!btr_index_page_validate(block, index)) {
+
+ ret = FALSE;
+ }
+ }
+
+ ut_a(btr_page_get_level(page, &mtr) == level);
+
+ right_page_no = btr_page_get_next(page, &mtr);
+ left_page_no = btr_page_get_prev(page, &mtr);
+
+ ut_a(page_get_n_recs(page) > 0 || (level == 0
+ && page_get_page_no(page)
+ == dict_index_get_page(index)));
+
+ if (right_page_no != FIL_NULL) {
+ const rec_t* right_rec;
+ right_block = btr_block_get(space, zip_size, right_page_no,
+ RW_X_LATCH, &mtr);
+ right_page = buf_block_get_frame(right_block);
+ if (UNIV_UNLIKELY(btr_page_get_prev(right_page, &mtr)
+ != page_get_page_no(page))) {
+ btr_validate_report2(index, level, block, right_block);
+ fputs("InnoDB: broken FIL_PAGE_NEXT"
+ " or FIL_PAGE_PREV links\n", stderr);
+ buf_page_print(page, 0);
+ buf_page_print(right_page, 0);
+
+ ret = FALSE;
+ }
+
+ if (UNIV_UNLIKELY(page_is_comp(right_page)
+ != page_is_comp(page))) {
+ btr_validate_report2(index, level, block, right_block);
+ fputs("InnoDB: 'compact' flag mismatch\n", stderr);
+ buf_page_print(page, 0);
+ buf_page_print(right_page, 0);
+
+ ret = FALSE;
+
+ goto node_ptr_fails;
+ }
+
+ rec = page_rec_get_prev(page_get_supremum_rec(page));
+ right_rec = page_rec_get_next(page_get_infimum_rec(
+ right_page));
+ offsets = rec_get_offsets(rec, index,
+ offsets, ULINT_UNDEFINED, &heap);
+ offsets2 = rec_get_offsets(right_rec, index,
+ offsets2, ULINT_UNDEFINED, &heap);
+ if (UNIV_UNLIKELY(cmp_rec_rec(rec, right_rec,
+ offsets, offsets2,
+ index) >= 0)) {
+
+ btr_validate_report2(index, level, block, right_block);
+
+ fputs("InnoDB: records in wrong order"
+ " on adjacent pages\n", stderr);
+
+ buf_page_print(page, 0);
+ buf_page_print(right_page, 0);
+
+ fputs("InnoDB: record ", stderr);
+ rec = page_rec_get_prev(page_get_supremum_rec(page));
+ rec_print(stderr, rec, index);
+ putc('\n', stderr);
+ fputs("InnoDB: record ", stderr);
+ rec = page_rec_get_next(
+ page_get_infimum_rec(right_page));
+ rec_print(stderr, rec, index);
+ putc('\n', stderr);
+
+ ret = FALSE;
+ }
+ }
+
+ if (level > 0 && left_page_no == FIL_NULL) {
+ ut_a(REC_INFO_MIN_REC_FLAG & rec_get_info_bits(
+ page_rec_get_next(page_get_infimum_rec(page)),
+ page_is_comp(page)));
+ }
+
+ if (buf_block_get_page_no(block) != dict_index_get_page(index)) {
+
+ /* Check father node pointers */
+
+ rec_t* node_ptr;
+
+ offsets = btr_page_get_father_block(offsets, heap, index,
+ block, &mtr, &node_cur);
+ father_page = btr_cur_get_page(&node_cur);
+ node_ptr = btr_cur_get_rec(&node_cur);
+
+ btr_cur_position(
+ index, page_rec_get_prev(page_get_supremum_rec(page)),
+ block, &node_cur);
+ offsets = btr_page_get_father_node_ptr(offsets, heap,
+ &node_cur, &mtr);
+
+ if (UNIV_UNLIKELY(node_ptr != btr_cur_get_rec(&node_cur))
+ || UNIV_UNLIKELY(btr_node_ptr_get_child_page_no(node_ptr,
+ offsets)
+ != buf_block_get_page_no(block))) {
+
+ btr_validate_report1(index, level, block);
+
+ fputs("InnoDB: node pointer to the page is wrong\n",
+ stderr);
+
+ buf_page_print(father_page, 0);
+ buf_page_print(page, 0);
+
+ fputs("InnoDB: node ptr ", stderr);
+ rec_print(stderr, node_ptr, index);
+
+ rec = btr_cur_get_rec(&node_cur);
+ fprintf(stderr, "\n"
+ "InnoDB: node ptr child page n:o %lu\n",
+ (ulong) btr_node_ptr_get_child_page_no(
+ rec, offsets));
+
+ fputs("InnoDB: record on page ", stderr);
+ rec_print_new(stderr, rec, offsets);
+ putc('\n', stderr);
+ ret = FALSE;
+
+ goto node_ptr_fails;
+ }
+
+ if (!page_is_leaf(page)) {
+ node_ptr_tuple = dict_index_build_node_ptr(
+ index,
+ page_rec_get_next(page_get_infimum_rec(page)),
+ 0, heap, btr_page_get_level(page, &mtr));
+
+ if (cmp_dtuple_rec(node_ptr_tuple, node_ptr,
+ offsets)) {
+ const rec_t* first_rec = page_rec_get_next(
+ page_get_infimum_rec(page));
+
+ btr_validate_report1(index, level, block);
+
+ buf_page_print(father_page, 0);
+ buf_page_print(page, 0);
+
+ fputs("InnoDB: Error: node ptrs differ"
+ " on levels > 0\n"
+ "InnoDB: node ptr ", stderr);
+ rec_print_new(stderr, node_ptr, offsets);
+ fputs("InnoDB: first rec ", stderr);
+ rec_print(stderr, first_rec, index);
+ putc('\n', stderr);
+ ret = FALSE;
+
+ goto node_ptr_fails;
+ }
+ }
+
+ if (left_page_no == FIL_NULL) {
+ ut_a(node_ptr == page_rec_get_next(
+ page_get_infimum_rec(father_page)));
+ ut_a(btr_page_get_prev(father_page, &mtr) == FIL_NULL);
+ }
+
+ if (right_page_no == FIL_NULL) {
+ ut_a(node_ptr == page_rec_get_prev(
+ page_get_supremum_rec(father_page)));
+ ut_a(btr_page_get_next(father_page, &mtr) == FIL_NULL);
+ } else {
+ const rec_t* right_node_ptr
+ = page_rec_get_next(node_ptr);
+
+ offsets = btr_page_get_father_block(
+ offsets, heap, index, right_block,
+ &mtr, &right_node_cur);
+ if (right_node_ptr
+ != page_get_supremum_rec(father_page)) {
+
+ if (btr_cur_get_rec(&right_node_cur)
+ != right_node_ptr) {
+ ret = FALSE;
+ fputs("InnoDB: node pointer to"
+ " the right page is wrong\n",
+ stderr);
+
+ btr_validate_report1(index, level,
+ block);
+
+ buf_page_print(father_page, 0);
+ buf_page_print(page, 0);
+ buf_page_print(right_page, 0);
+ }
+ } else {
+ page_t* right_father_page
+ = btr_cur_get_page(&right_node_cur);
+
+ if (btr_cur_get_rec(&right_node_cur)
+ != page_rec_get_next(
+ page_get_infimum_rec(
+ right_father_page))) {
+ ret = FALSE;
+ fputs("InnoDB: node pointer 2 to"
+ " the right page is wrong\n",
+ stderr);
+
+ btr_validate_report1(index, level,
+ block);
+
+ buf_page_print(father_page, 0);
+ buf_page_print(right_father_page, 0);
+ buf_page_print(page, 0);
+ buf_page_print(right_page, 0);
+ }
+
+ if (page_get_page_no(right_father_page)
+ != btr_page_get_next(father_page, &mtr)) {
+
+ ret = FALSE;
+ fputs("InnoDB: node pointer 3 to"
+ " the right page is wrong\n",
+ stderr);
+
+ btr_validate_report1(index, level,
+ block);
+
+ buf_page_print(father_page, 0);
+ buf_page_print(right_father_page, 0);
+ buf_page_print(page, 0);
+ buf_page_print(right_page, 0);
+ }
+ }
+ }
+ }
+
+node_ptr_fails:
+ /* Commit the mini-transaction to release the latch on 'page'.
+ Re-acquire the latch on right_page, which will become 'page'
+ on the next loop. The page has already been checked. */
+ mtr_commit(&mtr);
+
+ if (right_page_no != FIL_NULL) {
+ mtr_start(&mtr);
+
+ block = btr_block_get(space, zip_size, right_page_no,
+ RW_X_LATCH, &mtr);
+ page = buf_block_get_frame(block);
+
+ goto loop;
+ }
+
+ mem_heap_free(heap);
+ return(ret);
+}
+
+/**************************************************************//**
+Checks the consistency of an index tree.
+@return TRUE if ok */
+UNIV_INTERN
+ibool
+btr_validate_index(
+/*===============*/
+ dict_index_t* index, /*!< in: index */
+ trx_t* trx) /*!< in: transaction or NULL */
+{
+ mtr_t mtr;
+ page_t* root;
+ ulint i;
+ ulint n;
+
+ mtr_start(&mtr);
+ mtr_x_lock(dict_index_get_lock(index), &mtr);
+
+ root = btr_root_get(index, &mtr);
+ n = btr_page_get_level(root, &mtr);
+
+ for (i = 0; i <= n && !trx_is_interrupted(trx); i++) {
+ if (!btr_validate_level(index, trx, n - i)) {
+
+ mtr_commit(&mtr);
+
+ return(FALSE);
+ }
+ }
+
+ mtr_commit(&mtr);
+
+ return(TRUE);
+}
+#endif /* !UNIV_HOTBACKUP */
diff --git a/storage/innodb_plugin/btr/btr0cur.c b/storage/innodb_plugin/btr/btr0cur.c
new file mode 100644
index 00000000000..46dfb5d1a46
--- /dev/null
+++ b/storage/innodb_plugin/btr/btr0cur.c
@@ -0,0 +1,4847 @@
+/*****************************************************************************
+
+Copyright (c) 1994, 2009, Innobase Oy. All Rights Reserved.
+Copyright (c) 2008, Google Inc.
+
+Portions of this file contain modifications contributed and copyrighted by
+Google, Inc. Those modifications are gratefully acknowledged and are described
+briefly in the InnoDB documentation. The contributions by Google are
+incorporated with their permission, and subject to the conditions contained in
+the file COPYING.Google.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; version 2 of the License.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place, Suite 330, Boston, MA 02111-1307 USA
+
+*****************************************************************************/
+
+/**************************************************//**
+@file btr/btr0cur.c
+The index tree cursor
+
+All changes that row operations make to a B-tree or the records
+there must go through this module! Undo log records are written here
+of every modify or insert of a clustered index record.
+
+ NOTE!!!
+To make sure we do not run out of disk space during a pessimistic
+insert or update, we have to reserve 2 x the height of the index tree
+many pages in the tablespace before we start the operation, because
+if leaf splitting has been started, it is difficult to undo, except
+by crashing the database and doing a roll-forward.
+
+Created 10/16/1994 Heikki Tuuri
+*******************************************************/
+
+#include "btr0cur.h"
+
+#ifdef UNIV_NONINL
+#include "btr0cur.ic"
+#endif
+
+#include "row0upd.h"
+#ifndef UNIV_HOTBACKUP
+#include "mtr0log.h"
+#include "page0page.h"
+#include "page0zip.h"
+#include "rem0rec.h"
+#include "rem0cmp.h"
+#include "buf0lru.h"
+#include "btr0btr.h"
+#include "btr0sea.h"
+#include "trx0rec.h"
+#include "trx0roll.h" /* trx_is_recv() */
+#include "que0que.h"
+#include "row0row.h"
+#include "srv0srv.h"
+#include "ibuf0ibuf.h"
+#include "lock0lock.h"
+#include "zlib.h"
+
+#ifdef UNIV_DEBUG
+/** If the following is set to TRUE, this module prints a lot of
+trace information of individual record operations */
+UNIV_INTERN ibool btr_cur_print_record_ops = FALSE;
+#endif /* UNIV_DEBUG */
+
+/** Number of searches down the B-tree in btr_cur_search_to_nth_level(). */
+UNIV_INTERN ulint btr_cur_n_non_sea = 0;
+/** Number of successful adaptive hash index lookups in
+btr_cur_search_to_nth_level(). */
+UNIV_INTERN ulint btr_cur_n_sea = 0;
+/** Old value of btr_cur_n_non_sea. Copied by
+srv_refresh_innodb_monitor_stats(). Referenced by
+srv_printf_innodb_monitor(). */
+UNIV_INTERN ulint btr_cur_n_non_sea_old = 0;
+/** Old value of btr_cur_n_sea. Copied by
+srv_refresh_innodb_monitor_stats(). Referenced by
+srv_printf_innodb_monitor(). */
+UNIV_INTERN ulint btr_cur_n_sea_old = 0;
+
+/** In the optimistic insert, if the insert does not fit, but this much space
+can be released by page reorganize, then it is reorganized */
+#define BTR_CUR_PAGE_REORGANIZE_LIMIT (UNIV_PAGE_SIZE / 32)
+
+/** The structure of a BLOB part header */
+/* @{ */
+/*--------------------------------------*/
+#define BTR_BLOB_HDR_PART_LEN 0 /*!< BLOB part len on this
+ page */
+#define BTR_BLOB_HDR_NEXT_PAGE_NO 4 /*!< next BLOB part page no,
+ FIL_NULL if none */
+/*--------------------------------------*/
+#define BTR_BLOB_HDR_SIZE 8 /*!< Size of a BLOB
+ part header, in bytes */
+/* @} */
+#endif /* !UNIV_HOTBACKUP */
+
+/** A BLOB field reference full of zero, for use in assertions and tests.
+Initially, BLOB field references are set to zero, in
+dtuple_convert_big_rec(). */
+UNIV_INTERN const byte field_ref_zero[BTR_EXTERN_FIELD_REF_SIZE];
+
+#ifndef UNIV_HOTBACKUP
+/*******************************************************************//**
+Marks all extern fields in a record as owned by the record. This function
+should be called if the delete mark of a record is removed: a not delete
+marked record always owns all its extern fields. */
+static
+void
+btr_cur_unmark_extern_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() */
+ mtr_t* mtr); /*!< in: mtr, or NULL if not logged */
+/*******************************************************************//**
+Adds path information to the cursor for the current page, for which
+the binary search has been performed. */
+static
+void
+btr_cur_add_path_info(
+/*==================*/
+ btr_cur_t* cursor, /*!< in: cursor positioned on a page */
+ ulint height, /*!< in: height of the page in tree;
+ 0 means leaf node */
+ ulint root_height); /*!< in: root node height in tree */
+/***********************************************************//**
+Frees the externally stored fields for a record, if the field is mentioned
+in the update vector. */
+static
+void
+btr_rec_free_updated_extern_fields(
+/*===============================*/
+ dict_index_t* index, /*!< in: index of rec; the index tree MUST be
+ X-latched */
+ rec_t* rec, /*!< in: record */
+ page_zip_des_t* page_zip,/*!< in: compressed page whose uncompressed
+ part will be updated, or NULL */
+ const ulint* offsets,/*!< in: rec_get_offsets(rec, index) */
+ const upd_t* update, /*!< in: update vector */
+ enum trx_rb_ctx rb_ctx, /*!< in: rollback context */
+ mtr_t* mtr); /*!< in: mini-transaction handle which contains
+ an X-latch to record page and to the tree */
+/***********************************************************//**
+Frees the externally stored fields for a record. */
+static
+void
+btr_rec_free_externally_stored_fields(
+/*==================================*/
+ dict_index_t* index, /*!< in: index of the data, the index
+ tree MUST be X-latched */
+ rec_t* rec, /*!< in: record */
+ const ulint* offsets,/*!< in: rec_get_offsets(rec, index) */
+ page_zip_des_t* page_zip,/*!< in: compressed page whose uncompressed
+ part will be updated, or NULL */
+ enum trx_rb_ctx rb_ctx, /*!< in: rollback context */
+ mtr_t* mtr); /*!< in: mini-transaction handle which contains
+ an X-latch to record page and to the index
+ tree */
+/***********************************************************//**
+Gets the externally stored size of a record, in units of a database page.
+@return externally stored part, in units of a database page */
+static
+ulint
+btr_rec_get_externally_stored_len(
+/*==============================*/
+ rec_t* rec, /*!< in: record */
+ const ulint* offsets);/*!< in: array returned by rec_get_offsets() */
+#endif /* !UNIV_HOTBACKUP */
+
+/******************************************************//**
+The following function is used to set the deleted bit of a record. */
+UNIV_INLINE
+void
+btr_rec_set_deleted_flag(
+/*=====================*/
+ rec_t* rec, /*!< in/out: physical record */
+ page_zip_des_t* page_zip,/*!< in/out: compressed page (or NULL) */
+ ulint flag) /*!< in: nonzero if delete marked */
+{
+ if (page_rec_is_comp(rec)) {
+ rec_set_deleted_flag_new(rec, page_zip, flag);
+ } else {
+ ut_ad(!page_zip);
+ rec_set_deleted_flag_old(rec, flag);
+ }
+}
+
+#ifndef UNIV_HOTBACKUP
+/*==================== B-TREE SEARCH =========================*/
+
+/********************************************************************//**
+Latches the leaf page or pages requested. */
+static
+void
+btr_cur_latch_leaves(
+/*=================*/
+ page_t* page, /*!< in: leaf page where the search
+ converged */
+ ulint space, /*!< in: space id */
+ ulint zip_size, /*!< in: compressed page size in bytes
+ or 0 for uncompressed pages */
+ ulint page_no, /*!< in: page number of the leaf */
+ ulint latch_mode, /*!< in: BTR_SEARCH_LEAF, ... */
+ btr_cur_t* cursor, /*!< in: cursor */
+ mtr_t* mtr) /*!< in: mtr */
+{
+ ulint mode;
+ ulint left_page_no;
+ ulint right_page_no;
+ buf_block_t* get_block;
+
+ ut_ad(page && mtr);
+
+ switch (latch_mode) {
+ case BTR_SEARCH_LEAF:
+ case BTR_MODIFY_LEAF:
+ mode = latch_mode == BTR_SEARCH_LEAF ? RW_S_LATCH : RW_X_LATCH;
+ get_block = btr_block_get(space, zip_size, page_no, mode, mtr);
+#ifdef UNIV_BTR_DEBUG
+ ut_a(page_is_comp(get_block->frame) == page_is_comp(page));
+#endif /* UNIV_BTR_DEBUG */
+ get_block->check_index_page_at_flush = TRUE;
+ return;
+ case BTR_MODIFY_TREE:
+ /* x-latch also brothers from left to right */
+ left_page_no = btr_page_get_prev(page, mtr);
+
+ if (left_page_no != FIL_NULL) {
+ get_block = btr_block_get(space, zip_size,
+ left_page_no,
+ RW_X_LATCH, mtr);
+#ifdef UNIV_BTR_DEBUG
+ ut_a(page_is_comp(get_block->frame)
+ == page_is_comp(page));
+ ut_a(btr_page_get_next(get_block->frame, mtr)
+ == page_get_page_no(page));
+#endif /* UNIV_BTR_DEBUG */
+ get_block->check_index_page_at_flush = TRUE;
+ }
+
+ get_block = btr_block_get(space, zip_size, page_no,
+ RW_X_LATCH, mtr);
+#ifdef UNIV_BTR_DEBUG
+ ut_a(page_is_comp(get_block->frame) == page_is_comp(page));
+#endif /* UNIV_BTR_DEBUG */
+ get_block->check_index_page_at_flush = TRUE;
+
+ right_page_no = btr_page_get_next(page, mtr);
+
+ if (right_page_no != FIL_NULL) {
+ get_block = btr_block_get(space, zip_size,
+ right_page_no,
+ RW_X_LATCH, mtr);
+#ifdef UNIV_BTR_DEBUG
+ ut_a(page_is_comp(get_block->frame)
+ == page_is_comp(page));
+ ut_a(btr_page_get_prev(get_block->frame, mtr)
+ == page_get_page_no(page));
+#endif /* UNIV_BTR_DEBUG */
+ get_block->check_index_page_at_flush = TRUE;
+ }
+
+ return;
+
+ case BTR_SEARCH_PREV:
+ case BTR_MODIFY_PREV:
+ mode = latch_mode == BTR_SEARCH_PREV ? RW_S_LATCH : RW_X_LATCH;
+ /* latch also left brother */
+ left_page_no = btr_page_get_prev(page, mtr);
+
+ if (left_page_no != FIL_NULL) {
+ get_block = btr_block_get(space, zip_size,
+ left_page_no, mode, mtr);
+ cursor->left_block = get_block;
+#ifdef UNIV_BTR_DEBUG
+ ut_a(page_is_comp(get_block->frame)
+ == page_is_comp(page));
+ ut_a(btr_page_get_next(get_block->frame, mtr)
+ == page_get_page_no(page));
+#endif /* UNIV_BTR_DEBUG */
+ get_block->check_index_page_at_flush = TRUE;
+ }
+
+ get_block = btr_block_get(space, zip_size, page_no, mode, mtr);
+#ifdef UNIV_BTR_DEBUG
+ ut_a(page_is_comp(get_block->frame) == page_is_comp(page));
+#endif /* UNIV_BTR_DEBUG */
+ get_block->check_index_page_at_flush = TRUE;
+ return;
+ }
+
+ ut_error;
+}
+
+/********************************************************************//**
+Searches an index tree and positions a tree cursor on a given level.
+NOTE: n_fields_cmp in tuple must be set so that it cannot be compared
+to node pointer page number fields on the upper levels of the tree!
+Note that if mode is PAGE_CUR_LE, which is used in inserts, then
+cursor->up_match and cursor->low_match both will have sensible values.
+If mode is PAGE_CUR_GE, then up_match will a have a sensible value.
+
+If mode is PAGE_CUR_LE , cursor is left at the place where an insert of the
+search tuple should be performed in the B-tree. InnoDB does an insert
+immediately after the cursor. Thus, the cursor may end up on a user record,
+or on a page infimum record. */
+UNIV_INTERN
+void
+btr_cur_search_to_nth_level(
+/*========================*/
+ dict_index_t* index, /*!< in: index */
+ ulint level, /*!< in: the tree level of search */
+ const dtuple_t* tuple, /*!< in: data tuple; NOTE: n_fields_cmp in
+ tuple must be set so that it cannot get
+ compared to the node ptr page number field! */
+ ulint mode, /*!< in: PAGE_CUR_L, ...;
+ Inserts should always be made using
+ PAGE_CUR_LE to search the position! */
+ ulint latch_mode, /*!< in: BTR_SEARCH_LEAF, ..., ORed with
+ BTR_INSERT and BTR_ESTIMATE;
+ cursor->left_block is used to store a pointer
+ to the left neighbor page, in the cases
+ BTR_SEARCH_PREV and BTR_MODIFY_PREV;
+ NOTE that if has_search_latch
+ is != 0, we maybe do not have a latch set
+ on the cursor page, we assume
+ the caller uses his search latch
+ to protect the record! */
+ btr_cur_t* cursor, /*!< in/out: tree cursor; the cursor page is
+ s- or x-latched, but see also above! */
+ ulint has_search_latch,/*!< in: info on the latch mode the
+ caller currently has on btr_search_latch:
+ RW_S_LATCH, or 0 */
+ mtr_t* mtr) /*!< in: mtr */
+{
+ page_cur_t* page_cursor;
+ page_t* page;
+ buf_block_t* guess;
+ rec_t* node_ptr;
+ ulint page_no;
+ ulint space;
+ ulint up_match;
+ ulint up_bytes;
+ ulint low_match;
+ ulint low_bytes;
+ ulint height;
+ ulint savepoint;
+ ulint page_mode;
+ ulint insert_planned;
+ ulint estimate;
+ ulint ignore_sec_unique;
+ ulint root_height = 0; /* remove warning */
+#ifdef BTR_CUR_ADAPT
+ btr_search_t* info;
+#endif
+ mem_heap_t* heap = NULL;
+ ulint offsets_[REC_OFFS_NORMAL_SIZE];
+ ulint* offsets = offsets_;
+ rec_offs_init(offsets_);
+ /* Currently, PAGE_CUR_LE is the only search mode used for searches
+ ending to upper levels */
+
+ ut_ad(level == 0 || mode == PAGE_CUR_LE);
+ ut_ad(dict_index_check_search_tuple(index, tuple));
+ ut_ad(!dict_index_is_ibuf(index) || ibuf_inside());
+ ut_ad(dtuple_check_typed(tuple));
+
+#ifdef UNIV_DEBUG
+ cursor->up_match = ULINT_UNDEFINED;
+ cursor->low_match = ULINT_UNDEFINED;
+#endif
+ insert_planned = latch_mode & BTR_INSERT;
+ estimate = latch_mode & BTR_ESTIMATE;
+ ignore_sec_unique = latch_mode & BTR_IGNORE_SEC_UNIQUE;
+ latch_mode = latch_mode & ~(BTR_INSERT | BTR_ESTIMATE
+ | BTR_IGNORE_SEC_UNIQUE);
+
+ ut_ad(!insert_planned || (mode == PAGE_CUR_LE));
+
+ cursor->flag = BTR_CUR_BINARY;
+ cursor->index = index;
+
+#ifndef BTR_CUR_ADAPT
+ guess = NULL;
+#else
+ info = btr_search_get_info(index);
+
+ guess = info->root_guess;
+
+#ifdef BTR_CUR_HASH_ADAPT
+
+#ifdef UNIV_SEARCH_PERF_STAT
+ info->n_searches++;
+#endif
+ if (rw_lock_get_writer(&btr_search_latch) == RW_LOCK_NOT_LOCKED
+ && latch_mode <= BTR_MODIFY_LEAF && info->last_hash_succ
+ && !estimate
+#ifdef PAGE_CUR_LE_OR_EXTENDS
+ && mode != PAGE_CUR_LE_OR_EXTENDS
+#endif /* PAGE_CUR_LE_OR_EXTENDS */
+ /* If !has_search_latch, we do a dirty read of
+ btr_search_enabled below, and btr_search_guess_on_hash()
+ will have to check it again. */
+ && UNIV_LIKELY(btr_search_enabled)
+ && btr_search_guess_on_hash(index, info, tuple, mode,
+ latch_mode, cursor,
+ has_search_latch, mtr)) {
+
+ /* Search using the hash index succeeded */
+
+ ut_ad(cursor->up_match != ULINT_UNDEFINED
+ || mode != PAGE_CUR_GE);
+ ut_ad(cursor->up_match != ULINT_UNDEFINED
+ || mode != PAGE_CUR_LE);
+ ut_ad(cursor->low_match != ULINT_UNDEFINED
+ || mode != PAGE_CUR_LE);
+ btr_cur_n_sea++;
+
+ return;
+ }
+#endif /* BTR_CUR_HASH_ADAPT */
+#endif /* BTR_CUR_ADAPT */
+ btr_cur_n_non_sea++;
+
+ /* If the hash search did not succeed, do binary search down the
+ tree */
+
+ if (has_search_latch) {
+ /* Release possible search latch to obey latching order */
+ rw_lock_s_unlock(&btr_search_latch);
+ }
+
+ /* Store the position of the tree latch we push to mtr so that we
+ know how to release it when we have latched leaf node(s) */
+
+ savepoint = mtr_set_savepoint(mtr);
+
+ if (latch_mode == BTR_MODIFY_TREE) {
+ mtr_x_lock(dict_index_get_lock(index), mtr);
+
+ } else if (latch_mode == BTR_CONT_MODIFY_TREE) {
+ /* Do nothing */
+ ut_ad(mtr_memo_contains(mtr, dict_index_get_lock(index),
+ MTR_MEMO_X_LOCK));
+ } else {
+ mtr_s_lock(dict_index_get_lock(index), mtr);
+ }
+
+ page_cursor = btr_cur_get_page_cur(cursor);
+
+ space = dict_index_get_space(index);
+ page_no = dict_index_get_page(index);
+
+ up_match = 0;
+ up_bytes = 0;
+ low_match = 0;
+ low_bytes = 0;
+
+ height = ULINT_UNDEFINED;
+
+ /* We use these modified search modes on non-leaf levels of the
+ B-tree. These let us end up in the right B-tree leaf. In that leaf
+ we use the original search mode. */
+
+ switch (mode) {
+ case PAGE_CUR_GE:
+ page_mode = PAGE_CUR_L;
+ break;
+ case PAGE_CUR_G:
+ page_mode = PAGE_CUR_LE;
+ break;
+ default:
+#ifdef PAGE_CUR_LE_OR_EXTENDS
+ ut_ad(mode == PAGE_CUR_L || mode == PAGE_CUR_LE
+ || mode == PAGE_CUR_LE_OR_EXTENDS);
+#else /* PAGE_CUR_LE_OR_EXTENDS */
+ ut_ad(mode == PAGE_CUR_L || mode == PAGE_CUR_LE);
+#endif /* PAGE_CUR_LE_OR_EXTENDS */
+ page_mode = mode;
+ break;
+ }
+
+ /* Loop and search until we arrive at the desired level */
+
+ for (;;) {
+ ulint zip_size;
+ buf_block_t* block;
+ ulint rw_latch;
+ ulint buf_mode;
+
+ zip_size = dict_table_zip_size(index->table);
+ rw_latch = RW_NO_LATCH;
+ buf_mode = BUF_GET;
+
+ if (height == 0 && latch_mode <= BTR_MODIFY_LEAF) {
+
+ rw_latch = latch_mode;
+
+ if (insert_planned
+ && ibuf_should_try(index, ignore_sec_unique)) {
+
+ /* Try insert to the insert buffer if the
+ page is not in the buffer pool */
+
+ buf_mode = BUF_GET_IF_IN_POOL;
+ }
+ }
+
+retry_page_get:
+ block = buf_page_get_gen(space, zip_size, page_no,
+ rw_latch, guess, buf_mode,
+ __FILE__, __LINE__, mtr);
+ if (block == NULL) {
+ /* This must be a search to perform an insert;
+ try insert to the insert buffer */
+
+ ut_ad(buf_mode == BUF_GET_IF_IN_POOL);
+ ut_ad(insert_planned);
+ ut_ad(cursor->thr);
+
+ if (ibuf_insert(tuple, index, space, zip_size,
+ page_no, cursor->thr)) {
+ /* Insertion to the insert buffer succeeded */
+ cursor->flag = BTR_CUR_INSERT_TO_IBUF;
+ if (UNIV_LIKELY_NULL(heap)) {
+ mem_heap_free(heap);
+ }
+ goto func_exit;
+ }
+
+ /* Insert to the insert buffer did not succeed:
+ retry page get */
+
+ buf_mode = BUF_GET;
+
+ goto retry_page_get;
+ }
+
+ page = buf_block_get_frame(block);
+
+ block->check_index_page_at_flush = TRUE;
+
+ if (rw_latch != RW_NO_LATCH) {
+#ifdef UNIV_ZIP_DEBUG
+ const page_zip_des_t* page_zip
+ = buf_block_get_page_zip(block);
+ ut_a(!page_zip || page_zip_validate(page_zip, page));
+#endif /* UNIV_ZIP_DEBUG */
+
+ buf_block_dbg_add_level(block, SYNC_TREE_NODE);
+ }
+
+ ut_ad(0 == ut_dulint_cmp(index->id,
+ btr_page_get_index_id(page)));
+
+ if (UNIV_UNLIKELY(height == ULINT_UNDEFINED)) {
+ /* We are in the root node */
+
+ height = btr_page_get_level(page, mtr);
+ root_height = height;
+ cursor->tree_height = root_height + 1;
+#ifdef BTR_CUR_ADAPT
+ if (block != guess) {
+ info->root_guess = block;
+ }
+#endif
+ }
+
+ if (height == 0) {
+ if (rw_latch == RW_NO_LATCH) {
+
+ btr_cur_latch_leaves(page, space, zip_size,
+ page_no, latch_mode,
+ cursor, mtr);
+ }
+
+ if ((latch_mode != BTR_MODIFY_TREE)
+ && (latch_mode != BTR_CONT_MODIFY_TREE)) {
+
+ /* Release the tree s-latch */
+
+ mtr_release_s_latch_at_savepoint(
+ mtr, savepoint,
+ dict_index_get_lock(index));
+ }
+
+ page_mode = mode;
+ }
+
+ page_cur_search_with_match(block, index, tuple, page_mode,
+ &up_match, &up_bytes,
+ &low_match, &low_bytes,
+ page_cursor);
+
+ if (estimate) {
+ btr_cur_add_path_info(cursor, height, root_height);
+ }
+
+ /* If this is the desired level, leave the loop */
+
+ ut_ad(height == btr_page_get_level(
+ page_cur_get_page(page_cursor), mtr));
+
+ if (level == height) {
+
+ if (level > 0) {
+ /* x-latch the page */
+ page = btr_page_get(space, zip_size,
+ page_no, RW_X_LATCH, mtr);
+ ut_a((ibool)!!page_is_comp(page)
+ == dict_table_is_comp(index->table));
+ }
+
+ break;
+ }
+
+ ut_ad(height > 0);
+
+ height--;
+
+ guess = NULL;
+
+ node_ptr = page_cur_get_rec(page_cursor);
+ offsets = rec_get_offsets(node_ptr, cursor->index, offsets,
+ ULINT_UNDEFINED, &heap);
+ /* Go to the child node */
+ page_no = btr_node_ptr_get_child_page_no(node_ptr, offsets);
+ }
+
+ if (UNIV_LIKELY_NULL(heap)) {
+ mem_heap_free(heap);
+ }
+
+ if (level == 0) {
+ cursor->low_match = low_match;
+ cursor->low_bytes = low_bytes;
+ cursor->up_match = up_match;
+ cursor->up_bytes = up_bytes;
+
+#ifdef BTR_CUR_ADAPT
+ /* We do a dirty read of btr_search_enabled here. We
+ will properly check btr_search_enabled again in
+ btr_search_build_page_hash_index() before building a
+ page hash index, while holding btr_search_latch. */
+ if (UNIV_LIKELY(btr_search_enabled)) {
+
+ btr_search_info_update(index, cursor);
+ }
+#endif
+ ut_ad(cursor->up_match != ULINT_UNDEFINED
+ || mode != PAGE_CUR_GE);
+ ut_ad(cursor->up_match != ULINT_UNDEFINED
+ || mode != PAGE_CUR_LE);
+ ut_ad(cursor->low_match != ULINT_UNDEFINED
+ || mode != PAGE_CUR_LE);
+ }
+
+func_exit:
+ if (has_search_latch) {
+
+ rw_lock_s_lock(&btr_search_latch);
+ }
+}
+
+/*****************************************************************//**
+Opens a cursor at either end of an index. */
+UNIV_INTERN
+void
+btr_cur_open_at_index_side(
+/*=======================*/
+ ibool from_left, /*!< in: TRUE if open to the low end,
+ FALSE if to the high end */
+ dict_index_t* index, /*!< in: index */
+ ulint latch_mode, /*!< in: latch mode */
+ btr_cur_t* cursor, /*!< in: cursor */
+ mtr_t* mtr) /*!< in: mtr */
+{
+ page_cur_t* page_cursor;
+ ulint page_no;
+ ulint space;
+ ulint zip_size;
+ ulint height;
+ ulint root_height = 0; /* remove warning */
+ rec_t* node_ptr;
+ ulint estimate;
+ ulint savepoint;
+ mem_heap_t* heap = NULL;
+ ulint offsets_[REC_OFFS_NORMAL_SIZE];
+ ulint* offsets = offsets_;
+ rec_offs_init(offsets_);
+
+ estimate = latch_mode & BTR_ESTIMATE;
+ latch_mode = latch_mode & ~BTR_ESTIMATE;
+
+ /* Store the position of the tree latch we push to mtr so that we
+ know how to release it when we have latched the leaf node */
+
+ savepoint = mtr_set_savepoint(mtr);
+
+ if (latch_mode == BTR_MODIFY_TREE) {
+ mtr_x_lock(dict_index_get_lock(index), mtr);
+ } else {
+ mtr_s_lock(dict_index_get_lock(index), mtr);
+ }
+
+ page_cursor = btr_cur_get_page_cur(cursor);
+ cursor->index = index;
+
+ space = dict_index_get_space(index);
+ zip_size = dict_table_zip_size(index->table);
+ page_no = dict_index_get_page(index);
+
+ height = ULINT_UNDEFINED;
+
+ for (;;) {
+ buf_block_t* block;
+ page_t* page;
+ block = buf_page_get_gen(space, zip_size, page_no,
+ RW_NO_LATCH, NULL, BUF_GET,
+ __FILE__, __LINE__, mtr);
+ page = buf_block_get_frame(block);
+ ut_ad(0 == ut_dulint_cmp(index->id,
+ btr_page_get_index_id(page)));
+
+ block->check_index_page_at_flush = TRUE;
+
+ if (height == ULINT_UNDEFINED) {
+ /* We are in the root node */
+
+ height = btr_page_get_level(page, mtr);
+ root_height = height;
+ }
+
+ if (height == 0) {
+ btr_cur_latch_leaves(page, space, zip_size, page_no,
+ latch_mode, cursor, mtr);
+
+ /* In versions <= 3.23.52 we had forgotten to
+ release the tree latch here. If in an index scan
+ we had to scan far to find a record visible to the
+ current transaction, that could starve others
+ waiting for the tree latch. */
+
+ if ((latch_mode != BTR_MODIFY_TREE)
+ && (latch_mode != BTR_CONT_MODIFY_TREE)) {
+
+ /* Release the tree s-latch */
+
+ mtr_release_s_latch_at_savepoint(
+ mtr, savepoint,
+ dict_index_get_lock(index));
+ }
+ }
+
+ if (from_left) {
+ page_cur_set_before_first(block, page_cursor);
+ } else {
+ page_cur_set_after_last(block, page_cursor);
+ }
+
+ if (height == 0) {
+ if (estimate) {
+ btr_cur_add_path_info(cursor, height,
+ root_height);
+ }
+
+ break;
+ }
+
+ ut_ad(height > 0);
+
+ if (from_left) {
+ page_cur_move_to_next(page_cursor);
+ } else {
+ page_cur_move_to_prev(page_cursor);
+ }
+
+ if (estimate) {
+ btr_cur_add_path_info(cursor, height, root_height);
+ }
+
+ height--;
+
+ node_ptr = page_cur_get_rec(page_cursor);
+ offsets = rec_get_offsets(node_ptr, cursor->index, offsets,
+ ULINT_UNDEFINED, &heap);
+ /* Go to the child node */
+ page_no = btr_node_ptr_get_child_page_no(node_ptr, offsets);
+ }
+
+ if (UNIV_LIKELY_NULL(heap)) {
+ mem_heap_free(heap);
+ }
+}
+
+/**********************************************************************//**
+Positions a cursor at a randomly chosen position within a B-tree. */
+UNIV_INTERN
+void
+btr_cur_open_at_rnd_pos(
+/*====================*/
+ dict_index_t* index, /*!< in: index */
+ ulint latch_mode, /*!< in: BTR_SEARCH_LEAF, ... */
+ btr_cur_t* cursor, /*!< in/out: B-tree cursor */
+ mtr_t* mtr) /*!< in: mtr */
+{
+ page_cur_t* page_cursor;
+ ulint page_no;
+ ulint space;
+ ulint zip_size;
+ ulint height;
+ rec_t* node_ptr;
+ mem_heap_t* heap = NULL;
+ ulint offsets_[REC_OFFS_NORMAL_SIZE];
+ ulint* offsets = offsets_;
+ rec_offs_init(offsets_);
+
+ if (latch_mode == BTR_MODIFY_TREE) {
+ mtr_x_lock(dict_index_get_lock(index), mtr);
+ } else {
+ mtr_s_lock(dict_index_get_lock(index), mtr);
+ }
+
+ page_cursor = btr_cur_get_page_cur(cursor);
+ cursor->index = index;
+
+ space = dict_index_get_space(index);
+ zip_size = dict_table_zip_size(index->table);
+ page_no = dict_index_get_page(index);
+
+ height = ULINT_UNDEFINED;
+
+ for (;;) {
+ buf_block_t* block;
+ page_t* page;
+
+ block = buf_page_get_gen(space, zip_size, page_no,
+ RW_NO_LATCH, NULL, BUF_GET,
+ __FILE__, __LINE__, mtr);
+ page = buf_block_get_frame(block);
+ ut_ad(0 == ut_dulint_cmp(index->id,
+ btr_page_get_index_id(page)));
+
+ if (height == ULINT_UNDEFINED) {
+ /* We are in the root node */
+
+ height = btr_page_get_level(page, mtr);
+ }
+
+ if (height == 0) {
+ btr_cur_latch_leaves(page, space, zip_size, page_no,
+ latch_mode, cursor, mtr);
+ }
+
+ page_cur_open_on_rnd_user_rec(block, page_cursor);
+
+ if (height == 0) {
+
+ break;
+ }
+
+ ut_ad(height > 0);
+
+ height--;
+
+ node_ptr = page_cur_get_rec(page_cursor);
+ offsets = rec_get_offsets(node_ptr, cursor->index, offsets,
+ ULINT_UNDEFINED, &heap);
+ /* Go to the child node */
+ page_no = btr_node_ptr_get_child_page_no(node_ptr, offsets);
+ }
+
+ if (UNIV_LIKELY_NULL(heap)) {
+ mem_heap_free(heap);
+ }
+}
+
+/*==================== B-TREE INSERT =========================*/
+
+/*************************************************************//**
+Inserts a record if there is enough space, or if enough space can
+be freed by reorganizing. Differs from btr_cur_optimistic_insert because
+no heuristics is applied to whether it pays to use CPU time for
+reorganizing the page or not.
+@return pointer to inserted record if succeed, else NULL */
+static
+rec_t*
+btr_cur_insert_if_possible(
+/*=======================*/
+ btr_cur_t* cursor, /*!< in: cursor on page after which to insert;
+ cursor stays valid */
+ const dtuple_t* tuple, /*!< in: tuple to insert; the size info need not
+ have been stored to tuple */
+ ulint n_ext, /*!< in: number of externally stored columns */
+ mtr_t* mtr) /*!< in: mtr */
+{
+ page_cur_t* page_cursor;
+ buf_block_t* block;
+ rec_t* rec;
+
+ ut_ad(dtuple_check_typed(tuple));
+
+ block = btr_cur_get_block(cursor);
+
+ ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX));
+ page_cursor = btr_cur_get_page_cur(cursor);
+
+ /* Now, try the insert */
+ rec = page_cur_tuple_insert(page_cursor, tuple,
+ cursor->index, n_ext, mtr);
+
+ if (UNIV_UNLIKELY(!rec)) {
+ /* If record did not fit, reorganize */
+
+ if (btr_page_reorganize(block, cursor->index, mtr)) {
+
+ page_cur_search(block, cursor->index, tuple,
+ PAGE_CUR_LE, page_cursor);
+
+ rec = page_cur_tuple_insert(page_cursor, tuple,
+ cursor->index, n_ext, mtr);
+ }
+ }
+
+ return(rec);
+}
+
+/*************************************************************//**
+For an insert, checks the locks and does the undo logging if desired.
+@return DB_SUCCESS, DB_WAIT_LOCK, DB_FAIL, or error number */
+UNIV_INLINE
+ulint
+btr_cur_ins_lock_and_undo(
+/*======================*/
+ ulint flags, /*!< in: undo logging and locking flags: if
+ not zero, the parameters index and thr
+ should be specified */
+ btr_cur_t* cursor, /*!< in: cursor on page after which to insert */
+ const dtuple_t* entry, /*!< in: entry to insert */
+ que_thr_t* thr, /*!< in: query thread or NULL */
+ mtr_t* mtr, /*!< in/out: mini-transaction */
+ ibool* inherit)/*!< out: TRUE if the inserted new record maybe
+ should inherit LOCK_GAP type locks from the
+ successor record */
+{
+ dict_index_t* index;
+ ulint err;
+ rec_t* rec;
+ roll_ptr_t roll_ptr;
+
+ /* Check if we have to wait for a lock: enqueue an explicit lock
+ request if yes */
+
+ rec = btr_cur_get_rec(cursor);
+ index = cursor->index;
+
+ err = lock_rec_insert_check_and_lock(flags, rec,
+ btr_cur_get_block(cursor),
+ index, thr, mtr, inherit);
+
+ if (err != DB_SUCCESS) {
+
+ return(err);
+ }
+
+ if (dict_index_is_clust(index) && !dict_index_is_ibuf(index)) {
+
+ err = trx_undo_report_row_operation(flags, TRX_UNDO_INSERT_OP,
+ thr, index, entry,
+ NULL, 0, NULL,
+ &roll_ptr);
+ if (err != DB_SUCCESS) {
+
+ return(err);
+ }
+
+ /* Now we can fill in the roll ptr field in entry */
+
+ if (!(flags & BTR_KEEP_SYS_FLAG)) {
+
+ row_upd_index_entry_sys_field(entry, index,
+ DATA_ROLL_PTR, roll_ptr);
+ }
+ }
+
+ return(DB_SUCCESS);
+}
+
+#ifdef UNIV_DEBUG
+/*************************************************************//**
+Report information about a transaction. */
+static
+void
+btr_cur_trx_report(
+/*===============*/
+ trx_t* trx, /*!< in: transaction */
+ const dict_index_t* index, /*!< in: index */
+ const char* op) /*!< in: operation */
+{
+ fprintf(stderr, "Trx with id " TRX_ID_FMT " going to ",
+ TRX_ID_PREP_PRINTF(trx->id));
+ fputs(op, stderr);
+ dict_index_name_print(stderr, trx, index);
+ putc('\n', stderr);
+}
+#endif /* UNIV_DEBUG */
+
+/*************************************************************//**
+Tries to perform an insert to a page in an index tree, next to cursor.
+It is assumed that mtr holds an x-latch on the page. The operation does
+not succeed if there is too little space on the page. If there is just
+one record on the page, the insert will always succeed; this is to
+prevent trying to split a page with just one record.
+@return DB_SUCCESS, DB_WAIT_LOCK, DB_FAIL, or error number */
+UNIV_INTERN
+ulint
+btr_cur_optimistic_insert(
+/*======================*/
+ ulint flags, /*!< in: undo logging and locking flags: if not
+ zero, the parameters index and thr should be
+ specified */
+ btr_cur_t* cursor, /*!< in: cursor on page after which to insert;
+ cursor stays valid */
+ dtuple_t* entry, /*!< in/out: entry to insert */
+ rec_t** rec, /*!< out: pointer to inserted record if
+ succeed */
+ big_rec_t** big_rec,/*!< out: big rec vector whose fields have to
+ be stored externally by the caller, or
+ NULL */
+ ulint n_ext, /*!< in: number of externally stored columns */
+ que_thr_t* thr, /*!< in: query thread or NULL */
+ mtr_t* mtr) /*!< in: mtr; if this function returns
+ DB_SUCCESS on a leaf page of a secondary
+ index in a compressed tablespace, the
+ mtr must be committed before latching
+ any further pages */
+{
+ big_rec_t* big_rec_vec = NULL;
+ dict_index_t* index;
+ page_cur_t* page_cursor;
+ buf_block_t* block;
+ page_t* page;
+ ulint max_size;
+ rec_t* dummy_rec;
+ ibool leaf;
+ ibool reorg;
+ ibool inherit;
+ ulint zip_size;
+ ulint rec_size;
+ mem_heap_t* heap = NULL;
+ ulint err;
+
+ *big_rec = NULL;
+
+ block = btr_cur_get_block(cursor);
+ page = buf_block_get_frame(block);
+ index = cursor->index;
+ zip_size = buf_block_get_zip_size(block);
+#ifdef UNIV_DEBUG_VALGRIND
+ if (zip_size) {
+ UNIV_MEM_ASSERT_RW(page, UNIV_PAGE_SIZE);
+ UNIV_MEM_ASSERT_RW(block->page.zip.data, zip_size);
+ }
+#endif /* UNIV_DEBUG_VALGRIND */
+
+ if (!dtuple_check_typed_no_assert(entry)) {
+ fputs("InnoDB: Error in a tuple to insert into ", stderr);
+ dict_index_name_print(stderr, thr_get_trx(thr), index);
+ }
+#ifdef UNIV_DEBUG
+ if (btr_cur_print_record_ops && thr) {
+ btr_cur_trx_report(thr_get_trx(thr), index, "insert into ");
+ dtuple_print(stderr, entry);
+ }
+#endif /* UNIV_DEBUG */
+
+ ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX));
+ max_size = page_get_max_insert_size_after_reorganize(page, 1);
+ leaf = page_is_leaf(page);
+
+ /* Calculate the record size when entry is converted to a record */
+ rec_size = rec_get_converted_size(index, entry, n_ext);
+
+ if (page_zip_rec_needs_ext(rec_size, page_is_comp(page),
+ dtuple_get_n_fields(entry), zip_size)) {
+
+ /* The record is so big that we have to store some fields
+ externally on separate database pages */
+ big_rec_vec = dtuple_convert_big_rec(index, entry, &n_ext);
+
+ if (UNIV_UNLIKELY(big_rec_vec == NULL)) {
+
+ return(DB_TOO_BIG_RECORD);
+ }
+
+ rec_size = rec_get_converted_size(index, entry, n_ext);
+ }
+
+ if (UNIV_UNLIKELY(zip_size)) {
+ /* Estimate the free space of an empty compressed page.
+ Subtract one byte for the encoded heap_no in the
+ modification log. */
+ ulint free_space_zip = page_zip_empty_size(
+ cursor->index->n_fields, zip_size) - 1;
+ ulint n_uniq = dict_index_get_n_unique_in_tree(index);
+
+ ut_ad(dict_table_is_comp(index->table));
+
+ /* There should be enough room for two node pointer
+ records on an empty non-leaf page. This prevents
+ infinite page splits. */
+
+ if (UNIV_LIKELY(entry->n_fields >= n_uniq)
+ && UNIV_UNLIKELY(REC_NODE_PTR_SIZE
+ + rec_get_converted_size_comp_prefix(
+ index, entry->fields, n_uniq,
+ NULL)
+ /* On a compressed page, there is
+ a two-byte entry in the dense
+ page directory for every record.
+ But there is no record header. */
+ - (REC_N_NEW_EXTRA_BYTES - 2)
+ > free_space_zip / 2)) {
+
+ if (big_rec_vec) {
+ dtuple_convert_back_big_rec(
+ index, entry, big_rec_vec);
+ }
+
+ if (heap) {
+ mem_heap_free(heap);
+ }
+
+ return(DB_TOO_BIG_RECORD);
+ }
+ }
+
+ /* If there have been many consecutive inserts, and we are on the leaf
+ level, check if we have to split the page to reserve enough free space
+ for future updates of records. */
+
+ if (dict_index_is_clust(index)
+ && (page_get_n_recs(page) >= 2)
+ && UNIV_LIKELY(leaf)
+ && (dict_index_get_space_reserve() + rec_size > max_size)
+ && (btr_page_get_split_rec_to_right(cursor, &dummy_rec)
+ || btr_page_get_split_rec_to_left(cursor, &dummy_rec))) {
+fail:
+ err = DB_FAIL;
+fail_err:
+
+ if (big_rec_vec) {
+ dtuple_convert_back_big_rec(index, entry, big_rec_vec);
+ }
+
+ if (UNIV_LIKELY_NULL(heap)) {
+ mem_heap_free(heap);
+ }
+
+ return(err);
+ }
+
+ if (UNIV_UNLIKELY(max_size < BTR_CUR_PAGE_REORGANIZE_LIMIT
+ || max_size < rec_size)
+ && UNIV_LIKELY(page_get_n_recs(page) > 1)
+ && page_get_max_insert_size(page, 1) < rec_size) {
+
+ goto fail;
+ }
+
+ /* Check locks and write to the undo log, if specified */
+ err = btr_cur_ins_lock_and_undo(flags, cursor, entry,
+ thr, mtr, &inherit);
+
+ if (UNIV_UNLIKELY(err != DB_SUCCESS)) {
+
+ goto fail_err;
+ }
+
+ page_cursor = btr_cur_get_page_cur(cursor);
+
+ /* Now, try the insert */
+
+ {
+ const rec_t* page_cursor_rec = page_cur_get_rec(page_cursor);
+ *rec = page_cur_tuple_insert(page_cursor, entry, index,
+ n_ext, mtr);
+ reorg = page_cursor_rec != page_cur_get_rec(page_cursor);
+
+ if (UNIV_UNLIKELY(reorg)) {
+ ut_a(zip_size);
+ ut_a(*rec);
+ }
+ }
+
+ if (UNIV_UNLIKELY(!*rec) && UNIV_LIKELY(!reorg)) {
+ /* If the record did not fit, reorganize */
+ if (UNIV_UNLIKELY(!btr_page_reorganize(block, index, mtr))) {
+ ut_a(zip_size);
+
+ goto fail;
+ }
+
+ ut_ad(zip_size
+ || page_get_max_insert_size(page, 1) == max_size);
+
+ reorg = TRUE;
+
+ page_cur_search(block, index, entry, PAGE_CUR_LE, page_cursor);
+
+ *rec = page_cur_tuple_insert(page_cursor, entry, index,
+ n_ext, mtr);
+
+ if (UNIV_UNLIKELY(!*rec)) {
+ if (UNIV_LIKELY(zip_size != 0)) {
+
+ goto fail;
+ }
+
+ fputs("InnoDB: Error: cannot insert tuple ", stderr);
+ dtuple_print(stderr, entry);
+ fputs(" into ", stderr);
+ dict_index_name_print(stderr, thr_get_trx(thr), index);
+ fprintf(stderr, "\nInnoDB: max insert size %lu\n",
+ (ulong) max_size);
+ ut_error;
+ }
+ }
+
+ if (UNIV_LIKELY_NULL(heap)) {
+ mem_heap_free(heap);
+ }
+
+#ifdef BTR_CUR_HASH_ADAPT
+ if (!reorg && leaf && (cursor->flag == BTR_CUR_HASH)) {
+ btr_search_update_hash_node_on_insert(cursor);
+ } else {
+ btr_search_update_hash_on_insert(cursor);
+ }
+#endif
+
+ if (!(flags & BTR_NO_LOCKING_FLAG) && inherit) {
+
+ lock_update_insert(block, *rec);
+ }
+
+#if 0
+ fprintf(stderr, "Insert into page %lu, max ins size %lu,"
+ " rec %lu ind type %lu\n",
+ buf_block_get_page_no(block), max_size,
+ rec_size + PAGE_DIR_SLOT_SIZE, index->type);
+#endif
+ if (leaf && !dict_index_is_clust(index)) {
+ /* Update the free bits of the B-tree page in the
+ insert buffer bitmap. */
+
+ /* The free bits in the insert buffer bitmap must
+ never exceed the free space on a page. It is safe to
+ decrement or reset the bits in the bitmap in a
+ mini-transaction that is committed before the
+ mini-transaction that affects the free space. */
+
+ /* It is unsafe to increment the bits in a separately
+ committed mini-transaction, because in crash recovery,
+ the free bits could momentarily be set too high. */
+
+ if (zip_size) {
+ /* Update the bits in the same mini-transaction. */
+ ibuf_update_free_bits_zip(block, mtr);
+ } else {
+ /* Decrement the bits in a separate
+ mini-transaction. */
+ ibuf_update_free_bits_if_full(
+ block, max_size,
+ rec_size + PAGE_DIR_SLOT_SIZE);
+ }
+ }
+
+ *big_rec = big_rec_vec;
+
+ return(DB_SUCCESS);
+}
+
+/*************************************************************//**
+Performs an insert on a page of an index tree. It is assumed that mtr
+holds an x-latch on the tree and on the cursor page. If the insert is
+made on the leaf level, to avoid deadlocks, mtr must also own x-latches
+to brothers of page, if those brothers exist.
+@return DB_SUCCESS or error number */
+UNIV_INTERN
+ulint
+btr_cur_pessimistic_insert(
+/*=======================*/
+ ulint flags, /*!< in: undo logging and locking flags: if not
+ zero, the parameter thr should be
+ specified; if no undo logging is specified,
+ then the caller must have reserved enough
+ free extents in the file space so that the
+ insertion will certainly succeed */
+ btr_cur_t* cursor, /*!< in: cursor after which to insert;
+ cursor stays valid */
+ dtuple_t* entry, /*!< in/out: entry to insert */
+ rec_t** rec, /*!< out: pointer to inserted record if
+ succeed */
+ big_rec_t** big_rec,/*!< out: big rec vector whose fields have to
+ be stored externally by the caller, or
+ NULL */
+ ulint n_ext, /*!< in: number of externally stored columns */
+ que_thr_t* thr, /*!< in: query thread or NULL */
+ mtr_t* mtr) /*!< in: mtr */
+{
+ dict_index_t* index = cursor->index;
+ ulint zip_size = dict_table_zip_size(index->table);
+ big_rec_t* big_rec_vec = NULL;
+ mem_heap_t* heap = NULL;
+ ulint err;
+ ibool dummy_inh;
+ ibool success;
+ ulint n_extents = 0;
+ ulint n_reserved;
+
+ ut_ad(dtuple_check_typed(entry));
+
+ *big_rec = NULL;
+
+ ut_ad(mtr_memo_contains(mtr,
+ dict_index_get_lock(btr_cur_get_index(cursor)),
+ MTR_MEMO_X_LOCK));
+ ut_ad(mtr_memo_contains(mtr, btr_cur_get_block(cursor),
+ MTR_MEMO_PAGE_X_FIX));
+
+ /* Try first an optimistic insert; reset the cursor flag: we do not
+ assume anything of how it was positioned */
+
+ cursor->flag = BTR_CUR_BINARY;
+
+ err = btr_cur_optimistic_insert(flags, cursor, entry, rec,
+ big_rec, n_ext, thr, mtr);
+ if (err != DB_FAIL) {
+
+ return(err);
+ }
+
+ /* Retry with a pessimistic insert. Check locks and write to undo log,
+ if specified */
+
+ err = btr_cur_ins_lock_and_undo(flags, cursor, entry,
+ thr, mtr, &dummy_inh);
+
+ if (err != DB_SUCCESS) {
+
+ return(err);
+ }
+
+ if (!(flags & BTR_NO_UNDO_LOG_FLAG)) {
+ /* First reserve enough free space for the file segments
+ of the index tree, so that the insert will not fail because
+ of lack of space */
+
+ n_extents = cursor->tree_height / 16 + 3;
+
+ success = fsp_reserve_free_extents(&n_reserved, index->space,
+ n_extents, FSP_NORMAL, mtr);
+ if (!success) {
+ return(DB_OUT_OF_FILE_SPACE);
+ }
+ }
+
+ if (page_zip_rec_needs_ext(rec_get_converted_size(index, entry, n_ext),
+ dict_table_is_comp(index->table),
+ dict_index_get_n_fields(index),
+ zip_size)) {
+ /* The record is so big that we have to store some fields
+ externally on separate database pages */
+
+ if (UNIV_LIKELY_NULL(big_rec_vec)) {
+ /* This should never happen, but we handle
+ the situation in a robust manner. */
+ ut_ad(0);
+ dtuple_convert_back_big_rec(index, entry, big_rec_vec);
+ }
+
+ big_rec_vec = dtuple_convert_big_rec(index, entry, &n_ext);
+
+ if (big_rec_vec == NULL) {
+
+ if (n_extents > 0) {
+ fil_space_release_free_extents(index->space,
+ n_reserved);
+ }
+ return(DB_TOO_BIG_RECORD);
+ }
+ }
+
+ if (dict_index_get_page(index)
+ == buf_block_get_page_no(btr_cur_get_block(cursor))) {
+
+ /* The page is the root page */
+ *rec = btr_root_raise_and_insert(cursor, entry, n_ext, mtr);
+ } else {
+ *rec = btr_page_split_and_insert(cursor, entry, n_ext, mtr);
+ }
+
+ if (UNIV_LIKELY_NULL(heap)) {
+ mem_heap_free(heap);
+ }
+
+ ut_ad(page_rec_get_next(btr_cur_get_rec(cursor)) == *rec);
+
+#ifdef BTR_CUR_ADAPT
+ btr_search_update_hash_on_insert(cursor);
+#endif
+ if (!(flags & BTR_NO_LOCKING_FLAG)) {
+
+ lock_update_insert(btr_cur_get_block(cursor), *rec);
+ }
+
+ if (n_extents > 0) {
+ fil_space_release_free_extents(index->space, n_reserved);
+ }
+
+ *big_rec = big_rec_vec;
+
+ return(DB_SUCCESS);
+}
+
+/*==================== B-TREE UPDATE =========================*/
+
+/*************************************************************//**
+For an update, checks the locks and does the undo logging.
+@return DB_SUCCESS, DB_WAIT_LOCK, or error number */
+UNIV_INLINE
+ulint
+btr_cur_upd_lock_and_undo(
+/*======================*/
+ ulint flags, /*!< in: undo logging and locking flags */
+ btr_cur_t* cursor, /*!< in: cursor on record to update */
+ const upd_t* update, /*!< in: update vector */
+ ulint cmpl_info,/*!< in: compiler info on secondary index
+ updates */
+ que_thr_t* thr, /*!< in: query thread */
+ mtr_t* mtr, /*!< in/out: mini-transaction */
+ roll_ptr_t* roll_ptr)/*!< out: roll pointer */
+{
+ dict_index_t* index;
+ rec_t* rec;
+ ulint err;
+
+ ut_ad(cursor && update && thr && roll_ptr);
+
+ rec = btr_cur_get_rec(cursor);
+ index = cursor->index;
+
+ if (!dict_index_is_clust(index)) {
+ /* We do undo logging only when we update a clustered index
+ record */
+ return(lock_sec_rec_modify_check_and_lock(
+ flags, btr_cur_get_block(cursor), rec,
+ index, thr, mtr));
+ }
+
+ /* Check if we have to wait for a lock: enqueue an explicit lock
+ request if yes */
+
+ err = DB_SUCCESS;
+
+ if (!(flags & BTR_NO_LOCKING_FLAG)) {
+ mem_heap_t* heap = NULL;
+ ulint offsets_[REC_OFFS_NORMAL_SIZE];
+ rec_offs_init(offsets_);
+
+ err = lock_clust_rec_modify_check_and_lock(
+ flags, btr_cur_get_block(cursor), rec, index,
+ rec_get_offsets(rec, index, offsets_,
+ ULINT_UNDEFINED, &heap), thr);
+ if (UNIV_LIKELY_NULL(heap)) {
+ mem_heap_free(heap);
+ }
+ if (err != DB_SUCCESS) {
+
+ return(err);
+ }
+ }
+
+ /* Append the info about the update in the undo log */
+
+ err = trx_undo_report_row_operation(flags, TRX_UNDO_MODIFY_OP, thr,
+ index, NULL, update,
+ cmpl_info, rec, roll_ptr);
+ return(err);
+}
+
+/***********************************************************//**
+Writes a redo log record of updating a record in-place. */
+UNIV_INLINE
+void
+btr_cur_update_in_place_log(
+/*========================*/
+ ulint flags, /*!< in: flags */
+ rec_t* rec, /*!< in: record */
+ dict_index_t* index, /*!< in: index where cursor positioned */
+ const upd_t* update, /*!< in: update vector */
+ trx_t* trx, /*!< in: transaction */
+ roll_ptr_t roll_ptr, /*!< in: roll ptr */
+ mtr_t* mtr) /*!< in: mtr */
+{
+ byte* log_ptr;
+ page_t* page = page_align(rec);
+ ut_ad(flags < 256);
+ ut_ad(!!page_is_comp(page) == dict_table_is_comp(index->table));
+
+ log_ptr = mlog_open_and_write_index(mtr, rec, index, page_is_comp(page)
+ ? MLOG_COMP_REC_UPDATE_IN_PLACE
+ : MLOG_REC_UPDATE_IN_PLACE,
+ 1 + DATA_ROLL_PTR_LEN + 14 + 2
+ + MLOG_BUF_MARGIN);
+
+ if (!log_ptr) {
+ /* Logging in mtr is switched off during crash recovery */
+ return;
+ }
+
+ /* The code below assumes index is a clustered index: change index to
+ the clustered index if we are updating a secondary index record (or we
+ could as well skip writing the sys col values to the log in this case
+ because they are not needed for a secondary index record update) */
+
+ index = dict_table_get_first_index(index->table);
+
+ mach_write_to_1(log_ptr, flags);
+ log_ptr++;
+
+ log_ptr = row_upd_write_sys_vals_to_log(index, trx, roll_ptr, log_ptr,
+ mtr);
+ mach_write_to_2(log_ptr, page_offset(rec));
+ log_ptr += 2;
+
+ row_upd_index_write_log(update, log_ptr, mtr);
+}
+#endif /* UNIV_HOTBACKUP */
+
+/***********************************************************//**
+Parses a redo log record of updating a record in-place.
+@return end of log record or NULL */
+UNIV_INTERN
+byte*
+btr_cur_parse_update_in_place(
+/*==========================*/
+ byte* ptr, /*!< in: buffer */
+ byte* end_ptr,/*!< in: buffer end */
+ page_t* page, /*!< in/out: page or NULL */
+ page_zip_des_t* page_zip,/*!< in/out: compressed page, or NULL */
+ dict_index_t* index) /*!< in: index corresponding to page */
+{
+ ulint flags;
+ rec_t* rec;
+ upd_t* update;
+ ulint pos;
+ trx_id_t trx_id;
+ roll_ptr_t roll_ptr;
+ ulint rec_offset;
+ mem_heap_t* heap;
+ ulint* offsets;
+
+ if (end_ptr < ptr + 1) {
+
+ return(NULL);
+ }
+
+ flags = mach_read_from_1(ptr);
+ ptr++;
+
+ ptr = row_upd_parse_sys_vals(ptr, end_ptr, &pos, &trx_id, &roll_ptr);
+
+ if (ptr == NULL) {
+
+ return(NULL);
+ }
+
+ if (end_ptr < ptr + 2) {
+
+ return(NULL);
+ }
+
+ rec_offset = mach_read_from_2(ptr);
+ ptr += 2;
+
+ ut_a(rec_offset <= UNIV_PAGE_SIZE);
+
+ heap = mem_heap_create(256);
+
+ ptr = row_upd_index_parse(ptr, end_ptr, heap, &update);
+
+ if (!ptr || !page) {
+
+ goto func_exit;
+ }
+
+ ut_a((ibool)!!page_is_comp(page) == dict_table_is_comp(index->table));
+ rec = page + rec_offset;
+
+ /* We do not need to reserve btr_search_latch, as the page is only
+ being recovered, and there cannot be a hash index to it. */
+
+ offsets = rec_get_offsets(rec, index, NULL, ULINT_UNDEFINED, &heap);
+
+ if (!(flags & BTR_KEEP_SYS_FLAG)) {
+ row_upd_rec_sys_fields_in_recovery(rec, page_zip, offsets,
+ pos, trx_id, roll_ptr);
+ }
+
+ row_upd_rec_in_place(rec, index, offsets, update, page_zip);
+
+func_exit:
+ mem_heap_free(heap);
+
+ return(ptr);
+}
+
+#ifndef UNIV_HOTBACKUP
+/*************************************************************//**
+See if there is enough place in the page modification log to log
+an update-in-place.
+@return TRUE if enough place */
+static
+ibool
+btr_cur_update_alloc_zip(
+/*=====================*/
+ page_zip_des_t* page_zip,/*!< in/out: compressed page */
+ buf_block_t* block, /*!< in/out: buffer page */
+ dict_index_t* index, /*!< in: the index corresponding to the block */
+ ulint length, /*!< in: size needed */
+ ibool create, /*!< in: TRUE=delete-and-insert,
+ FALSE=update-in-place */
+ mtr_t* mtr) /*!< in: mini-transaction */
+{
+ ut_a(page_zip == buf_block_get_page_zip(block));
+ ut_ad(page_zip);
+ ut_ad(!dict_index_is_ibuf(index));
+
+ if (page_zip_available(page_zip, dict_index_is_clust(index),
+ length, create)) {
+ return(TRUE);
+ }
+
+ if (!page_zip->m_nonempty) {
+ /* The page has been freshly compressed, so
+ recompressing it will not help. */
+ return(FALSE);
+ }
+
+ if (!page_zip_compress(page_zip, buf_block_get_frame(block),
+ index, mtr)) {
+ /* Unable to compress the page */
+ return(FALSE);
+ }
+
+ /* After recompressing a page, we must make sure that the free
+ bits in the insert buffer bitmap will not exceed the free
+ space on the page. Because this function will not attempt
+ recompression unless page_zip_available() fails above, it is
+ safe to reset the free bits if page_zip_available() fails
+ again, below. The free bits can safely be reset in a separate
+ mini-transaction. If page_zip_available() succeeds below, we
+ can be sure that the page_zip_compress() above did not reduce
+ the free space available on the page. */
+
+ if (!page_zip_available(page_zip, dict_index_is_clust(index),
+ length, create)) {
+ /* Out of space: reset the free bits. */
+ if (!dict_index_is_clust(index)
+ && page_is_leaf(buf_block_get_frame(block))) {
+ ibuf_reset_free_bits(block);
+ }
+ return(FALSE);
+ }
+
+ return(TRUE);
+}
+
+/*************************************************************//**
+Updates a record when the update causes no size changes in its fields.
+We assume here that the ordering fields of the record do not change.
+@return DB_SUCCESS or error number */
+UNIV_INTERN
+ulint
+btr_cur_update_in_place(
+/*====================*/
+ ulint flags, /*!< in: undo logging and locking flags */
+ btr_cur_t* cursor, /*!< in: cursor on the record to update;
+ cursor stays valid and positioned on the
+ same record */
+ const upd_t* update, /*!< in: update vector */
+ ulint cmpl_info,/*!< in: compiler info on secondary index
+ updates */
+ que_thr_t* thr, /*!< in: query thread */
+ mtr_t* mtr) /*!< in: mtr; must be committed before
+ latching any further pages */
+{
+ dict_index_t* index;
+ buf_block_t* block;
+ page_zip_des_t* page_zip;
+ ulint err;
+ rec_t* rec;
+ roll_ptr_t roll_ptr = ut_dulint_zero;
+ trx_t* trx;
+ ulint was_delete_marked;
+ 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(!!page_rec_is_comp(rec) == dict_table_is_comp(index->table));
+ /* The insert buffer tree should never be updated in place. */
+ ut_ad(!dict_index_is_ibuf(index));
+
+ trx = thr_get_trx(thr);
+ offsets = rec_get_offsets(rec, index, offsets, ULINT_UNDEFINED, &heap);
+#ifdef UNIV_DEBUG
+ if (btr_cur_print_record_ops && thr) {
+ btr_cur_trx_report(trx, index, "update ");
+ rec_print_new(stderr, rec, offsets);
+ }
+#endif /* UNIV_DEBUG */
+
+ block = btr_cur_get_block(cursor);
+ page_zip = buf_block_get_page_zip(block);
+
+ /* Check that enough space is available on the compressed page. */
+ if (UNIV_LIKELY_NULL(page_zip)
+ && !btr_cur_update_alloc_zip(page_zip, block, index,
+ rec_offs_size(offsets), FALSE, mtr)) {
+ return(DB_ZIP_OVERFLOW);
+ }
+
+ /* Do lock checking and undo logging */
+ err = btr_cur_upd_lock_and_undo(flags, cursor, update, cmpl_info,
+ thr, mtr, &roll_ptr);
+ if (UNIV_UNLIKELY(err != DB_SUCCESS)) {
+
+ if (UNIV_LIKELY_NULL(heap)) {
+ mem_heap_free(heap);
+ }
+ return(err);
+ }
+
+ if (block->is_hashed) {
+ /* The function row_upd_changes_ord_field_binary works only
+ if the update vector was built for a clustered index, we must
+ NOT call it if index is secondary */
+
+ if (!dict_index_is_clust(index)
+ || row_upd_changes_ord_field_binary(NULL, index, update)) {
+
+ /* Remove possible hash index pointer to this record */
+ btr_search_update_hash_on_delete(cursor);
+ }
+
+ rw_lock_x_lock(&btr_search_latch);
+ }
+
+ if (!(flags & BTR_KEEP_SYS_FLAG)) {
+ row_upd_rec_sys_fields(rec, NULL,
+ index, offsets, trx, roll_ptr);
+ }
+
+ was_delete_marked = rec_get_deleted_flag(
+ rec, page_is_comp(buf_block_get_frame(block)));
+
+ row_upd_rec_in_place(rec, index, offsets, update, page_zip);
+
+ if (block->is_hashed) {
+ rw_lock_x_unlock(&btr_search_latch);
+ }
+
+ if (page_zip && !dict_index_is_clust(index)
+ && page_is_leaf(buf_block_get_frame(block))) {
+ /* Update the free bits in the insert buffer. */
+ ibuf_update_free_bits_zip(block, mtr);
+ }
+
+ btr_cur_update_in_place_log(flags, rec, index, update,
+ trx, roll_ptr, mtr);
+
+ if (was_delete_marked
+ && !rec_get_deleted_flag(rec, page_is_comp(
+ buf_block_get_frame(block)))) {
+ /* The new updated record owns its possible externally
+ stored fields */
+
+ btr_cur_unmark_extern_fields(page_zip,
+ rec, index, offsets, mtr);
+ }
+
+ if (UNIV_LIKELY_NULL(heap)) {
+ mem_heap_free(heap);
+ }
+ return(DB_SUCCESS);
+}
+
+/*************************************************************//**
+Tries to update a record on a page in an index tree. It is assumed that mtr
+holds an x-latch on the page. The operation does not succeed if there is too
+little space on the page or if the update would result in too empty a page,
+so that tree compression is recommended. We assume here that the ordering
+fields of the record do not change.
+@return DB_SUCCESS, or DB_OVERFLOW if the updated record does not fit,
+DB_UNDERFLOW if the page would become too empty, or DB_ZIP_OVERFLOW if
+there is not enough space left on the compressed page */
+UNIV_INTERN
+ulint
+btr_cur_optimistic_update(
+/*======================*/
+ ulint flags, /*!< in: undo logging and locking flags */
+ btr_cur_t* cursor, /*!< in: cursor on the record to update;
+ cursor stays valid and positioned on the
+ same record */
+ const upd_t* update, /*!< in: update vector; this must also
+ contain trx id and roll ptr fields */
+ ulint cmpl_info,/*!< in: compiler info on secondary index
+ updates */
+ que_thr_t* thr, /*!< in: query thread */
+ mtr_t* mtr) /*!< in: mtr; must be committed before
+ latching any further pages */
+{
+ dict_index_t* index;
+ page_cur_t* page_cursor;
+ ulint err;
+ buf_block_t* block;
+ page_t* page;
+ page_zip_des_t* page_zip;
+ rec_t* rec;
+ rec_t* orig_rec;
+ ulint max_size;
+ ulint new_rec_size;
+ ulint old_rec_size;
+ dtuple_t* new_entry;
+ roll_ptr_t roll_ptr;
+ trx_t* trx;
+ mem_heap_t* heap;
+ ulint i;
+ ulint n_ext;
+ ulint* offsets;
+
+ block = btr_cur_get_block(cursor);
+ page = buf_block_get_frame(block);
+ orig_rec = rec = btr_cur_get_rec(cursor);
+ index = cursor->index;
+ ut_ad(!!page_rec_is_comp(rec) == dict_table_is_comp(index->table));
+ ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX));
+ /* The insert buffer tree should never be updated in place. */
+ ut_ad(!dict_index_is_ibuf(index));
+
+ heap = mem_heap_create(1024);
+ offsets = rec_get_offsets(rec, index, NULL, ULINT_UNDEFINED, &heap);
+
+#ifdef UNIV_DEBUG
+ if (btr_cur_print_record_ops && thr) {
+ btr_cur_trx_report(thr_get_trx(thr), index, "update ");
+ rec_print_new(stderr, rec, offsets);
+ }
+#endif /* UNIV_DEBUG */
+
+ if (!row_upd_changes_field_size_or_external(index, offsets, update)) {
+
+ /* The simplest and the most common case: the update does not
+ change the size of any field and none of the updated fields is
+ externally stored in rec or update, and there is enough space
+ on the compressed page to log the update. */
+
+ mem_heap_free(heap);
+ return(btr_cur_update_in_place(flags, cursor, update,
+ cmpl_info, thr, mtr));
+ }
+
+ if (rec_offs_any_extern(offsets)) {
+any_extern:
+ /* Externally stored fields are treated in pessimistic
+ update */
+
+ mem_heap_free(heap);
+ return(DB_OVERFLOW);
+ }
+
+ for (i = 0; i < upd_get_n_fields(update); i++) {
+ if (dfield_is_ext(&upd_get_nth_field(update, i)->new_val)) {
+
+ goto any_extern;
+ }
+ }
+
+ page_cursor = btr_cur_get_page_cur(cursor);
+
+ new_entry = row_rec_to_index_entry(ROW_COPY_DATA, rec, index, offsets,
+ &n_ext, heap);
+ /* We checked above that there are no externally stored fields. */
+ ut_a(!n_ext);
+
+ /* The page containing the clustered index record
+ corresponding to new_entry is latched in mtr.
+ Thus the following call is safe. */
+ row_upd_index_replace_new_col_vals_index_pos(new_entry, index, update,
+ FALSE, heap);
+ old_rec_size = rec_offs_size(offsets);
+ new_rec_size = rec_get_converted_size(index, new_entry, 0);
+
+ page_zip = buf_block_get_page_zip(block);
+#ifdef UNIV_ZIP_DEBUG
+ ut_a(!page_zip || page_zip_validate(page_zip, page));
+#endif /* UNIV_ZIP_DEBUG */
+
+ if (UNIV_LIKELY_NULL(page_zip)
+ && !btr_cur_update_alloc_zip(page_zip, block, index,
+ new_rec_size, TRUE, mtr)) {
+ err = DB_ZIP_OVERFLOW;
+ goto err_exit;
+ }
+
+ if (UNIV_UNLIKELY(new_rec_size
+ >= (page_get_free_space_of_empty(page_is_comp(page))
+ / 2))) {
+
+ err = DB_OVERFLOW;
+ goto err_exit;
+ }
+
+ if (UNIV_UNLIKELY(page_get_data_size(page)
+ - old_rec_size + new_rec_size
+ < BTR_CUR_PAGE_COMPRESS_LIMIT)) {
+
+ /* The page would become too empty */
+
+ err = DB_UNDERFLOW;
+ goto err_exit;
+ }
+
+ max_size = old_rec_size
+ + page_get_max_insert_size_after_reorganize(page, 1);
+
+ if (!(((max_size >= BTR_CUR_PAGE_REORGANIZE_LIMIT)
+ && (max_size >= new_rec_size))
+ || (page_get_n_recs(page) <= 1))) {
+
+ /* There was not enough space, or it did not pay to
+ reorganize: for simplicity, we decide what to do assuming a
+ reorganization is needed, though it might not be necessary */
+
+ err = DB_OVERFLOW;
+ goto err_exit;
+ }
+
+ /* Do lock checking and undo logging */
+ err = btr_cur_upd_lock_and_undo(flags, cursor, update, cmpl_info,
+ thr, mtr, &roll_ptr);
+ if (err != DB_SUCCESS) {
+err_exit:
+ mem_heap_free(heap);
+ return(err);
+ }
+
+ /* Ok, we may do the replacement. Store on the page infimum the
+ explicit locks on rec, before deleting rec (see the comment in
+ btr_cur_pessimistic_update). */
+
+ lock_rec_store_on_page_infimum(block, rec);
+
+ btr_search_update_hash_on_delete(cursor);
+
+ /* The call to row_rec_to_index_entry(ROW_COPY_DATA, ...) above
+ invokes rec_offs_make_valid() to point to the copied record that
+ the fields of new_entry point to. We have to undo it here. */
+ ut_ad(rec_offs_validate(NULL, index, offsets));
+ rec_offs_make_valid(page_cur_get_rec(page_cursor), index, offsets);
+
+ page_cur_delete_rec(page_cursor, index, offsets, mtr);
+
+ page_cur_move_to_prev(page_cursor);
+
+ trx = thr_get_trx(thr);
+
+ if (!(flags & BTR_KEEP_SYS_FLAG)) {
+ row_upd_index_entry_sys_field(new_entry, index, DATA_ROLL_PTR,
+ roll_ptr);
+ row_upd_index_entry_sys_field(new_entry, index, DATA_TRX_ID,
+ trx->id);
+ }
+
+ /* There are no externally stored columns in new_entry */
+ rec = btr_cur_insert_if_possible(cursor, new_entry, 0/*n_ext*/, mtr);
+ ut_a(rec); /* <- We calculated above the insert would fit */
+
+ if (page_zip && !dict_index_is_clust(index)
+ && page_is_leaf(page)) {
+ /* Update the free bits in the insert buffer. */
+ ibuf_update_free_bits_zip(block, mtr);
+ }
+
+ /* Restore the old explicit lock state on the record */
+
+ lock_rec_restore_from_page_infimum(block, rec, block);
+
+ page_cur_move_to_next(page_cursor);
+
+ mem_heap_free(heap);
+
+ return(DB_SUCCESS);
+}
+
+/*************************************************************//**
+If, in a split, a new supremum record was created as the predecessor of the
+updated record, the supremum record must inherit exactly the locks on the
+updated record. In the split it may have inherited locks from the successor
+of the updated record, which is not correct. This function restores the
+right locks for the new supremum. */
+static
+void
+btr_cur_pess_upd_restore_supremum(
+/*==============================*/
+ buf_block_t* block, /*!< in: buffer block of rec */
+ const rec_t* rec, /*!< in: updated record */
+ mtr_t* mtr) /*!< in: mtr */
+{
+ page_t* page;
+ buf_block_t* prev_block;
+ ulint space;
+ ulint zip_size;
+ ulint prev_page_no;
+
+ page = buf_block_get_frame(block);
+
+ if (page_rec_get_next(page_get_infimum_rec(page)) != rec) {
+ /* Updated record is not the first user record on its page */
+
+ return;
+ }
+
+ space = buf_block_get_space(block);
+ zip_size = buf_block_get_zip_size(block);
+ prev_page_no = btr_page_get_prev(page, mtr);
+
+ ut_ad(prev_page_no != FIL_NULL);
+ prev_block = buf_page_get_with_no_latch(space, zip_size,
+ prev_page_no, mtr);
+#ifdef UNIV_BTR_DEBUG
+ ut_a(btr_page_get_next(prev_block->frame, mtr)
+ == page_get_page_no(page));
+#endif /* UNIV_BTR_DEBUG */
+
+ /* We must already have an x-latch on prev_block! */
+ ut_ad(mtr_memo_contains(mtr, prev_block, MTR_MEMO_PAGE_X_FIX));
+
+ lock_rec_reset_and_inherit_gap_locks(prev_block, block,
+ PAGE_HEAP_NO_SUPREMUM,
+ page_rec_get_heap_no(rec));
+}
+
+/*************************************************************//**
+Performs an update of a record on a page of a tree. It is assumed
+that mtr holds an x-latch on the tree and on the cursor page. If the
+update is made on the leaf level, to avoid deadlocks, mtr must also
+own x-latches to brothers of page, if those brothers exist. We assume
+here that the ordering fields of the record do not change.
+@return DB_SUCCESS or error code */
+UNIV_INTERN
+ulint
+btr_cur_pessimistic_update(
+/*=======================*/
+ ulint flags, /*!< in: undo logging, locking, and rollback
+ flags */
+ btr_cur_t* cursor, /*!< in: cursor on the record to update */
+ mem_heap_t** heap, /*!< in/out: pointer to memory heap, or NULL */
+ big_rec_t** big_rec,/*!< out: big rec vector whose fields have to
+ be stored externally by the caller, or NULL */
+ const upd_t* update, /*!< in: update vector; this is allowed also
+ contain trx id and roll ptr fields, but
+ the values in update vector have no effect */
+ ulint cmpl_info,/*!< in: compiler info on secondary index
+ updates */
+ que_thr_t* thr, /*!< in: query thread */
+ mtr_t* mtr) /*!< in: mtr; must be committed before
+ latching any further pages */
+{
+ big_rec_t* big_rec_vec = NULL;
+ big_rec_t* dummy_big_rec;
+ dict_index_t* index;
+ buf_block_t* block;
+ page_t* page;
+ page_zip_des_t* page_zip;
+ rec_t* rec;
+ page_cur_t* page_cursor;
+ dtuple_t* new_entry;
+ ulint err;
+ ulint optim_err;
+ roll_ptr_t roll_ptr;
+ trx_t* trx;
+ ibool was_first;
+ ulint n_extents = 0;
+ ulint n_reserved;
+ ulint n_ext;
+ ulint* offsets = NULL;
+
+ *big_rec = NULL;
+
+ block = btr_cur_get_block(cursor);
+ page = buf_block_get_frame(block);
+ page_zip = buf_block_get_page_zip(block);
+ rec = btr_cur_get_rec(cursor);
+ index = cursor->index;
+
+ ut_ad(mtr_memo_contains(mtr, dict_index_get_lock(index),
+ MTR_MEMO_X_LOCK));
+ ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX));
+#ifdef UNIV_ZIP_DEBUG
+ ut_a(!page_zip || page_zip_validate(page_zip, page));
+#endif /* UNIV_ZIP_DEBUG */
+ /* The insert buffer tree should never be updated in place. */
+ ut_ad(!dict_index_is_ibuf(index));
+
+ optim_err = btr_cur_optimistic_update(flags, cursor, update,
+ cmpl_info, thr, mtr);
+
+ switch (optim_err) {
+ case DB_UNDERFLOW:
+ case DB_OVERFLOW:
+ case DB_ZIP_OVERFLOW:
+ break;
+ default:
+ return(optim_err);
+ }
+
+ /* Do lock checking and undo logging */
+ err = btr_cur_upd_lock_and_undo(flags, cursor, update, cmpl_info,
+ thr, mtr, &roll_ptr);
+ if (err != DB_SUCCESS) {
+
+ return(err);
+ }
+
+ if (optim_err == DB_OVERFLOW) {
+ ulint reserve_flag;
+
+ /* First reserve enough free space for the file segments
+ of the index tree, so that the update will not fail because
+ of lack of space */
+
+ n_extents = cursor->tree_height / 16 + 3;
+
+ if (flags & BTR_NO_UNDO_LOG_FLAG) {
+ reserve_flag = FSP_CLEANING;
+ } else {
+ reserve_flag = FSP_NORMAL;
+ }
+
+ if (!fsp_reserve_free_extents(&n_reserved, index->space,
+ n_extents, reserve_flag, mtr)) {
+ return(DB_OUT_OF_FILE_SPACE);
+ }
+ }
+
+ if (!*heap) {
+ *heap = mem_heap_create(1024);
+ }
+ offsets = rec_get_offsets(rec, index, NULL, ULINT_UNDEFINED, heap);
+
+ trx = thr_get_trx(thr);
+
+ new_entry = row_rec_to_index_entry(ROW_COPY_DATA, rec, index, offsets,
+ &n_ext, *heap);
+ /* The call to row_rec_to_index_entry(ROW_COPY_DATA, ...) above
+ invokes rec_offs_make_valid() to point to the copied record that
+ the fields of new_entry point to. We have to undo it here. */
+ ut_ad(rec_offs_validate(NULL, index, offsets));
+ rec_offs_make_valid(rec, index, offsets);
+
+ /* The page containing the clustered index record
+ corresponding to new_entry is latched in mtr. If the
+ clustered index record is delete-marked, then its externally
+ stored fields cannot have been purged yet, because then the
+ purge would also have removed the clustered index record
+ itself. Thus the following call is safe. */
+ row_upd_index_replace_new_col_vals_index_pos(new_entry, index, update,
+ FALSE, *heap);
+ if (!(flags & BTR_KEEP_SYS_FLAG)) {
+ row_upd_index_entry_sys_field(new_entry, index, DATA_ROLL_PTR,
+ roll_ptr);
+ row_upd_index_entry_sys_field(new_entry, index, DATA_TRX_ID,
+ trx->id);
+ }
+
+ if ((flags & BTR_NO_UNDO_LOG_FLAG) && rec_offs_any_extern(offsets)) {
+ /* We are in a transaction rollback undoing a row
+ update: we must free possible externally stored fields
+ which got new values in the update, if they are not
+ inherited values. They can be inherited if we have
+ updated the primary key to another value, and then
+ update it back again. */
+
+ ut_ad(big_rec_vec == NULL);
+
+ btr_rec_free_updated_extern_fields(
+ index, rec, page_zip, offsets, update,
+ trx_is_recv(trx) ? RB_RECOVERY : RB_NORMAL, mtr);
+ }
+
+ /* We have to set appropriate extern storage bits in the new
+ record to be inserted: we have to remember which fields were such */
+
+ ut_ad(!page_is_comp(page) || !rec_get_node_ptr_flag(rec));
+ offsets = rec_get_offsets(rec, index, offsets, ULINT_UNDEFINED, heap);
+ n_ext += btr_push_update_extern_fields(new_entry, update, *heap);
+
+ if (UNIV_LIKELY_NULL(page_zip)) {
+ ut_ad(page_is_comp(page));
+ if (page_zip_rec_needs_ext(
+ rec_get_converted_size(index, new_entry, n_ext),
+ TRUE,
+ dict_index_get_n_fields(index),
+ page_zip_get_size(page_zip))) {
+
+ goto make_external;
+ }
+ } else if (page_zip_rec_needs_ext(
+ rec_get_converted_size(index, new_entry, n_ext),
+ page_is_comp(page), 0, 0)) {
+make_external:
+ big_rec_vec = dtuple_convert_big_rec(index, new_entry, &n_ext);
+ if (UNIV_UNLIKELY(big_rec_vec == NULL)) {
+
+ err = DB_TOO_BIG_RECORD;
+ goto return_after_reservations;
+ }
+ }
+
+ /* Store state of explicit locks on rec on the page infimum record,
+ before deleting rec. The page infimum acts as a dummy carrier of the
+ locks, taking care also of lock releases, before we can move the locks
+ back on the actual record. There is a special case: if we are
+ inserting on the root page and the insert causes a call of
+ btr_root_raise_and_insert. Therefore we cannot in the lock system
+ delete the lock structs set on the root page even if the root
+ page carries just node pointers. */
+
+ lock_rec_store_on_page_infimum(block, rec);
+
+ btr_search_update_hash_on_delete(cursor);
+
+#ifdef UNIV_ZIP_DEBUG
+ ut_a(!page_zip || page_zip_validate(page_zip, page));
+#endif /* UNIV_ZIP_DEBUG */
+ page_cursor = btr_cur_get_page_cur(cursor);
+
+ page_cur_delete_rec(page_cursor, index, offsets, mtr);
+
+ page_cur_move_to_prev(page_cursor);
+
+ rec = btr_cur_insert_if_possible(cursor, new_entry, n_ext, mtr);
+
+ if (rec) {
+ lock_rec_restore_from_page_infimum(btr_cur_get_block(cursor),
+ rec, block);
+
+ offsets = rec_get_offsets(rec, index, offsets,
+ ULINT_UNDEFINED, heap);
+
+ if (!rec_get_deleted_flag(rec, rec_offs_comp(offsets))) {
+ /* The new inserted record owns its possible externally
+ stored fields */
+ btr_cur_unmark_extern_fields(page_zip,
+ rec, index, offsets, mtr);
+ }
+
+ btr_cur_compress_if_useful(cursor, mtr);
+
+ if (page_zip && !dict_index_is_clust(index)
+ && page_is_leaf(page)) {
+ /* Update the free bits in the insert buffer. */
+ ibuf_update_free_bits_zip(block, mtr);
+ }
+
+ err = DB_SUCCESS;
+ goto return_after_reservations;
+ } else {
+ ut_a(optim_err != DB_UNDERFLOW);
+
+ /* Out of space: reset the free bits. */
+ if (!dict_index_is_clust(index)
+ && page_is_leaf(page)) {
+ ibuf_reset_free_bits(block);
+ }
+ }
+
+ /* Was the record to be updated positioned as the first user
+ record on its page? */
+ was_first = page_cur_is_before_first(page_cursor);
+
+ /* The first parameter means that no lock checking and undo logging
+ is made in the insert */
+
+ err = btr_cur_pessimistic_insert(BTR_NO_UNDO_LOG_FLAG
+ | BTR_NO_LOCKING_FLAG
+ | BTR_KEEP_SYS_FLAG,
+ cursor, new_entry, &rec,
+ &dummy_big_rec, n_ext, NULL, mtr);
+ ut_a(rec);
+ ut_a(err == DB_SUCCESS);
+ ut_a(dummy_big_rec == NULL);
+
+ if (dict_index_is_sec_or_ibuf(index)) {
+ /* Update PAGE_MAX_TRX_ID in the index page header.
+ It was not updated by btr_cur_pessimistic_insert()
+ because of BTR_NO_LOCKING_FLAG. */
+ buf_block_t* rec_block;
+
+ rec_block = btr_cur_get_block(cursor);
+
+ page_update_max_trx_id(rec_block,
+ buf_block_get_page_zip(rec_block),
+ trx->id, mtr);
+ }
+
+ if (!rec_get_deleted_flag(rec, rec_offs_comp(offsets))) {
+ /* The new inserted record owns its possible externally
+ stored fields */
+ buf_block_t* rec_block = btr_cur_get_block(cursor);
+
+#ifdef UNIV_ZIP_DEBUG
+ ut_a(!page_zip || page_zip_validate(page_zip, page));
+ page = buf_block_get_frame(rec_block);
+#endif /* UNIV_ZIP_DEBUG */
+ page_zip = buf_block_get_page_zip(rec_block);
+
+ offsets = rec_get_offsets(rec, index, offsets,
+ ULINT_UNDEFINED, heap);
+ btr_cur_unmark_extern_fields(page_zip,
+ rec, index, offsets, mtr);
+ }
+
+ lock_rec_restore_from_page_infimum(btr_cur_get_block(cursor),
+ rec, block);
+
+ /* If necessary, restore also the correct lock state for a new,
+ preceding supremum record created in a page split. While the old
+ record was nonexistent, the supremum might have inherited its locks
+ from a wrong record. */
+
+ if (!was_first) {
+ btr_cur_pess_upd_restore_supremum(btr_cur_get_block(cursor),
+ rec, mtr);
+ }
+
+return_after_reservations:
+#ifdef UNIV_ZIP_DEBUG
+ ut_a(!page_zip || page_zip_validate(page_zip, page));
+#endif /* UNIV_ZIP_DEBUG */
+
+ if (n_extents > 0) {
+ fil_space_release_free_extents(index->space, n_reserved);
+ }
+
+ *big_rec = big_rec_vec;
+
+ return(err);
+}
+
+/*==================== B-TREE DELETE MARK AND UNMARK ===============*/
+
+/****************************************************************//**
+Writes the redo log record for delete marking or unmarking of an index
+record. */
+UNIV_INLINE
+void
+btr_cur_del_mark_set_clust_rec_log(
+/*===============================*/
+ ulint flags, /*!< in: flags */
+ rec_t* rec, /*!< in: record */
+ dict_index_t* index, /*!< in: index of the record */
+ ibool val, /*!< in: value to set */
+ trx_t* trx, /*!< in: deleting transaction */
+ roll_ptr_t roll_ptr,/*!< in: roll ptr to the undo log record */
+ mtr_t* mtr) /*!< in: mtr */
+{
+ byte* log_ptr;
+ ut_ad(flags < 256);
+ ut_ad(val <= 1);
+
+ ut_ad(!!page_rec_is_comp(rec) == dict_table_is_comp(index->table));
+
+ log_ptr = mlog_open_and_write_index(mtr, rec, index,
+ page_rec_is_comp(rec)
+ ? MLOG_COMP_REC_CLUST_DELETE_MARK
+ : MLOG_REC_CLUST_DELETE_MARK,
+ 1 + 1 + DATA_ROLL_PTR_LEN
+ + 14 + 2);
+
+ if (!log_ptr) {
+ /* Logging in mtr is switched off during crash recovery */
+ return;
+ }
+
+ mach_write_to_1(log_ptr, flags);
+ log_ptr++;
+ mach_write_to_1(log_ptr, val);
+ log_ptr++;
+
+ log_ptr = row_upd_write_sys_vals_to_log(index, trx, roll_ptr, log_ptr,
+ mtr);
+ mach_write_to_2(log_ptr, page_offset(rec));
+ log_ptr += 2;
+
+ mlog_close(mtr, log_ptr);
+}
+#endif /* !UNIV_HOTBACKUP */
+
+/****************************************************************//**
+Parses the redo log record for delete marking or unmarking of a clustered
+index record.
+@return end of log record or NULL */
+UNIV_INTERN
+byte*
+btr_cur_parse_del_mark_set_clust_rec(
+/*=================================*/
+ byte* ptr, /*!< in: buffer */
+ byte* end_ptr,/*!< in: buffer end */
+ page_t* page, /*!< in/out: page or NULL */
+ page_zip_des_t* page_zip,/*!< in/out: compressed page, or NULL */
+ dict_index_t* index) /*!< in: index corresponding to page */
+{
+ ulint flags;
+ ulint val;
+ ulint pos;
+ trx_id_t trx_id;
+ roll_ptr_t roll_ptr;
+ ulint offset;
+ rec_t* rec;
+
+ ut_ad(!page
+ || !!page_is_comp(page) == dict_table_is_comp(index->table));
+
+ if (end_ptr < ptr + 2) {
+
+ return(NULL);
+ }
+
+ flags = mach_read_from_1(ptr);
+ ptr++;
+ val = mach_read_from_1(ptr);
+ ptr++;
+
+ ptr = row_upd_parse_sys_vals(ptr, end_ptr, &pos, &trx_id, &roll_ptr);
+
+ if (ptr == NULL) {
+
+ return(NULL);
+ }
+
+ if (end_ptr < ptr + 2) {
+
+ return(NULL);
+ }
+
+ offset = mach_read_from_2(ptr);
+ ptr += 2;
+
+ ut_a(offset <= UNIV_PAGE_SIZE);
+
+ if (page) {
+ rec = page + offset;
+
+ /* We do not need to reserve btr_search_latch, as the page
+ is only being recovered, and there cannot be a hash index to
+ it. */
+
+ btr_rec_set_deleted_flag(rec, page_zip, val);
+
+ if (!(flags & BTR_KEEP_SYS_FLAG)) {
+ mem_heap_t* heap = NULL;
+ ulint offsets_[REC_OFFS_NORMAL_SIZE];
+ rec_offs_init(offsets_);
+
+ row_upd_rec_sys_fields_in_recovery(
+ rec, page_zip,
+ rec_get_offsets(rec, index, offsets_,
+ ULINT_UNDEFINED, &heap),
+ pos, trx_id, roll_ptr);
+ if (UNIV_LIKELY_NULL(heap)) {
+ mem_heap_free(heap);
+ }
+ }
+ }
+
+ return(ptr);
+}
+
+#ifndef UNIV_HOTBACKUP
+/***********************************************************//**
+Marks a clustered index record deleted. Writes an undo log record to
+undo log on this delete marking. Writes in the trx id field the id
+of the deleting transaction, and in the roll ptr field pointer to the
+undo log record created.
+@return DB_SUCCESS, DB_LOCK_WAIT, or error number */
+UNIV_INTERN
+ulint
+btr_cur_del_mark_set_clust_rec(
+/*===========================*/
+ ulint flags, /*!< in: undo logging and locking flags */
+ btr_cur_t* cursor, /*!< in: cursor */
+ 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(!!page_rec_is_comp(rec) == dict_table_is_comp(index->table));
+ offsets = rec_get_offsets(rec, index, offsets, ULINT_UNDEFINED, &heap);
+
+#ifdef UNIV_DEBUG
+ if (btr_cur_print_record_ops && thr) {
+ btr_cur_trx_report(thr_get_trx(thr), index, "del mark ");
+ rec_print_new(stderr, rec, offsets);
+ }
+#endif /* UNIV_DEBUG */
+
+ 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),
+ rec, index, offsets, thr);
+
+ if (err != DB_SUCCESS) {
+
+ goto func_exit;
+ }
+
+ err = trx_undo_report_row_operation(flags, TRX_UNDO_MODIFY_OP, thr,
+ index, NULL, NULL, 0, rec,
+ &roll_ptr);
+ if (err != DB_SUCCESS) {
+
+ goto func_exit;
+ }
+
+ block = btr_cur_get_block(cursor);
+
+ if (block->is_hashed) {
+ rw_lock_x_lock(&btr_search_latch);
+ }
+
+ page_zip = buf_block_get_page_zip(block);
+
+ btr_rec_set_deleted_flag(rec, page_zip, val);
+
+ trx = thr_get_trx(thr);
+
+ if (!(flags & BTR_KEEP_SYS_FLAG)) {
+ row_upd_rec_sys_fields(rec, page_zip,
+ index, offsets, trx, roll_ptr);
+ }
+
+ if (block->is_hashed) {
+ rw_lock_x_unlock(&btr_search_latch);
+ }
+
+ 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);
+}
+
+/****************************************************************//**
+Writes the redo log record for a delete mark setting of a secondary
+index record. */
+UNIV_INLINE
+void
+btr_cur_del_mark_set_sec_rec_log(
+/*=============================*/
+ rec_t* rec, /*!< in: record */
+ ibool val, /*!< in: value to set */
+ mtr_t* mtr) /*!< in: mtr */
+{
+ byte* log_ptr;
+ ut_ad(val <= 1);
+
+ log_ptr = mlog_open(mtr, 11 + 1 + 2);
+
+ if (!log_ptr) {
+ /* Logging in mtr is switched off during crash recovery:
+ in that case mlog_open returns NULL */
+ return;
+ }
+
+ log_ptr = mlog_write_initial_log_record_fast(
+ rec, MLOG_REC_SEC_DELETE_MARK, log_ptr, mtr);
+ mach_write_to_1(log_ptr, val);
+ log_ptr++;
+
+ mach_write_to_2(log_ptr, page_offset(rec));
+ log_ptr += 2;
+
+ mlog_close(mtr, log_ptr);
+}
+#endif /* !UNIV_HOTBACKUP */
+
+/****************************************************************//**
+Parses the redo log record for delete marking or unmarking of a secondary
+index record.
+@return end of log record or NULL */
+UNIV_INTERN
+byte*
+btr_cur_parse_del_mark_set_sec_rec(
+/*===============================*/
+ byte* ptr, /*!< in: buffer */
+ byte* end_ptr,/*!< in: buffer end */
+ page_t* page, /*!< in/out: page or NULL */
+ page_zip_des_t* page_zip)/*!< in/out: compressed page, or NULL */
+{
+ ulint val;
+ ulint offset;
+ rec_t* rec;
+
+ if (end_ptr < ptr + 3) {
+
+ return(NULL);
+ }
+
+ val = mach_read_from_1(ptr);
+ ptr++;
+
+ offset = mach_read_from_2(ptr);
+ ptr += 2;
+
+ ut_a(offset <= UNIV_PAGE_SIZE);
+
+ if (page) {
+ rec = page + offset;
+
+ /* We do not need to reserve btr_search_latch, as the page
+ is only being recovered, and there cannot be a hash index to
+ it. */
+
+ btr_rec_set_deleted_flag(rec, page_zip, val);
+ }
+
+ return(ptr);
+}
+
+#ifndef UNIV_HOTBACKUP
+/***********************************************************//**
+Sets a secondary index record delete mark to TRUE or FALSE.
+@return DB_SUCCESS, DB_LOCK_WAIT, or error number */
+UNIV_INTERN
+ulint
+btr_cur_del_mark_set_sec_rec(
+/*=========================*/
+ ulint flags, /*!< in: locking flag */
+ btr_cur_t* cursor, /*!< in: cursor */
+ ibool val, /*!< in: value to set */
+ que_thr_t* thr, /*!< in: query thread */
+ mtr_t* mtr) /*!< in: mtr */
+{
+ buf_block_t* block;
+ rec_t* rec;
+ ulint err;
+
+ block = btr_cur_get_block(cursor);
+ rec = btr_cur_get_rec(cursor);
+
+#ifdef UNIV_DEBUG
+ if (btr_cur_print_record_ops && thr) {
+ btr_cur_trx_report(thr_get_trx(thr), cursor->index,
+ "del mark ");
+ rec_print(stderr, rec, cursor->index);
+ }
+#endif /* UNIV_DEBUG */
+
+ err = lock_sec_rec_modify_check_and_lock(flags,
+ btr_cur_get_block(cursor),
+ rec, cursor->index, thr, mtr);
+ if (err != DB_SUCCESS) {
+
+ return(err);
+ }
+
+ ut_ad(!!page_rec_is_comp(rec)
+ == dict_table_is_comp(cursor->index->table));
+
+ if (block->is_hashed) {
+ rw_lock_x_lock(&btr_search_latch);
+ }
+
+ btr_rec_set_deleted_flag(rec, buf_block_get_page_zip(block), val);
+
+ if (block->is_hashed) {
+ rw_lock_x_unlock(&btr_search_latch);
+ }
+
+ btr_cur_del_mark_set_sec_rec_log(rec, val, mtr);
+
+ return(DB_SUCCESS);
+}
+
+/***********************************************************//**
+Clear a secondary index record's delete mark. This function is only
+used by the insert buffer insert merge mechanism. */
+UNIV_INTERN
+void
+btr_cur_del_unmark_for_ibuf(
+/*========================*/
+ rec_t* rec, /*!< in/out: record to delete unmark */
+ page_zip_des_t* page_zip, /*!< in/out: compressed page
+ corresponding to rec, or NULL
+ when the tablespace is
+ uncompressed */
+ mtr_t* mtr) /*!< in: mtr */
+{
+ /* We do not need to reserve btr_search_latch, as the page has just
+ been read to the buffer pool and there cannot be a hash index to it. */
+
+ btr_rec_set_deleted_flag(rec, page_zip, FALSE);
+
+ btr_cur_del_mark_set_sec_rec_log(rec, FALSE, mtr);
+}
+
+/*==================== B-TREE RECORD REMOVE =========================*/
+
+/*************************************************************//**
+Tries to compress a page of the tree if it seems useful. It is assumed
+that mtr holds an x-latch on the tree and on the cursor page. To avoid
+deadlocks, mtr must also own x-latches to brothers of page, if those
+brothers exist. NOTE: it is assumed that the caller has reserved enough
+free extents so that the compression will always succeed if done!
+@return TRUE if compression occurred */
+UNIV_INTERN
+ibool
+btr_cur_compress_if_useful(
+/*=======================*/
+ btr_cur_t* cursor, /*!< in: cursor on the page to compress;
+ cursor does not stay valid if compression
+ occurs */
+ mtr_t* mtr) /*!< in: mtr */
+{
+ ut_ad(mtr_memo_contains(mtr,
+ dict_index_get_lock(btr_cur_get_index(cursor)),
+ MTR_MEMO_X_LOCK));
+ ut_ad(mtr_memo_contains(mtr, btr_cur_get_block(cursor),
+ MTR_MEMO_PAGE_X_FIX));
+
+ return(btr_cur_compress_recommendation(cursor, mtr)
+ && btr_compress(cursor, mtr));
+}
+
+/*******************************************************//**
+Removes the record on which the tree cursor is positioned on a leaf page.
+It is assumed that the mtr has an x-latch on the page where the cursor is
+positioned, but no latch on the whole tree.
+@return TRUE if success, i.e., the page did not become too empty */
+UNIV_INTERN
+ibool
+btr_cur_optimistic_delete(
+/*======================*/
+ btr_cur_t* cursor, /*!< in: cursor on leaf page, on the record to
+ delete; cursor stays valid: if deletion
+ succeeds, on function exit it points to the
+ successor of the deleted record */
+ mtr_t* mtr) /*!< in: mtr; if this function returns
+ TRUE on a leaf page of a secondary
+ index, the mtr must be committed
+ before latching any further pages */
+{
+ buf_block_t* block;
+ rec_t* rec;
+ mem_heap_t* heap = NULL;
+ ulint offsets_[REC_OFFS_NORMAL_SIZE];
+ ulint* offsets = offsets_;
+ ibool no_compress_needed;
+ rec_offs_init(offsets_);
+
+ ut_ad(mtr_memo_contains(mtr, btr_cur_get_block(cursor),
+ MTR_MEMO_PAGE_X_FIX));
+ /* This is intended only for leaf page deletions */
+
+ block = btr_cur_get_block(cursor);
+
+ ut_ad(page_is_leaf(buf_block_get_frame(block)));
+
+ rec = btr_cur_get_rec(cursor);
+ offsets = rec_get_offsets(rec, cursor->index, offsets,
+ ULINT_UNDEFINED, &heap);
+
+ no_compress_needed = !rec_offs_any_extern(offsets)
+ && btr_cur_can_delete_without_compress(
+ cursor, rec_offs_size(offsets), mtr);
+
+ if (no_compress_needed) {
+
+ page_t* page = buf_block_get_frame(block);
+ page_zip_des_t* page_zip= buf_block_get_page_zip(block);
+ ulint max_ins = 0;
+
+ lock_update_delete(block, rec);
+
+ btr_search_update_hash_on_delete(cursor);
+
+ if (!page_zip) {
+ max_ins = page_get_max_insert_size_after_reorganize(
+ page, 1);
+ }
+#ifdef UNIV_ZIP_DEBUG
+ ut_a(!page_zip || page_zip_validate(page_zip, page));
+#endif /* UNIV_ZIP_DEBUG */
+ page_cur_delete_rec(btr_cur_get_page_cur(cursor),
+ cursor->index, offsets, mtr);
+#ifdef UNIV_ZIP_DEBUG
+ ut_a(!page_zip || page_zip_validate(page_zip, page));
+#endif /* UNIV_ZIP_DEBUG */
+
+ if (dict_index_is_clust(cursor->index)
+ || dict_index_is_ibuf(cursor->index)
+ || !page_is_leaf(page)) {
+ /* The insert buffer does not handle
+ inserts to clustered indexes, to
+ non-leaf pages of secondary index B-trees,
+ or to the insert buffer. */
+ } else if (page_zip) {
+ ibuf_update_free_bits_zip(block, mtr);
+ } else {
+ ibuf_update_free_bits_low(block, max_ins, mtr);
+ }
+ }
+
+ if (UNIV_LIKELY_NULL(heap)) {
+ mem_heap_free(heap);
+ }
+
+ return(no_compress_needed);
+}
+
+/*************************************************************//**
+Removes the record on which the tree cursor is positioned. Tries
+to compress the page if its fillfactor drops below a threshold
+or if it is the only page on the level. It is assumed that mtr holds
+an x-latch on the tree and on the cursor page. To avoid deadlocks,
+mtr must also own x-latches to brothers of page, if those brothers
+exist.
+@return TRUE if compression occurred */
+UNIV_INTERN
+ibool
+btr_cur_pessimistic_delete(
+/*=======================*/
+ ulint* err, /*!< out: DB_SUCCESS or DB_OUT_OF_FILE_SPACE;
+ the latter may occur because we may have
+ to update node pointers on upper levels,
+ and in the case of variable length keys
+ these may actually grow in size */
+ ibool has_reserved_extents, /*!< in: TRUE if the
+ caller has already reserved enough free
+ extents so that he knows that the operation
+ will succeed */
+ btr_cur_t* cursor, /*!< in: cursor on the record to delete;
+ if compression does not occur, the cursor
+ stays valid: it points to successor of
+ deleted record on function exit */
+ enum trx_rb_ctx rb_ctx, /*!< in: rollback context */
+ mtr_t* mtr) /*!< in: mtr */
+{
+ buf_block_t* block;
+ page_t* page;
+ page_zip_des_t* page_zip;
+ dict_index_t* index;
+ rec_t* rec;
+ dtuple_t* node_ptr;
+ ulint n_extents = 0;
+ ulint n_reserved;
+ ibool success;
+ ibool ret = FALSE;
+ ulint level;
+ mem_heap_t* heap;
+ ulint* offsets;
+
+ block = btr_cur_get_block(cursor);
+ page = buf_block_get_frame(block);
+ index = btr_cur_get_index(cursor);
+
+ ut_ad(mtr_memo_contains(mtr, dict_index_get_lock(index),
+ MTR_MEMO_X_LOCK));
+ ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX));
+ if (!has_reserved_extents) {
+ /* First reserve enough free space for the file segments
+ of the index tree, so that the node pointer updates will
+ not fail because of lack of space */
+
+ n_extents = cursor->tree_height / 32 + 1;
+
+ success = fsp_reserve_free_extents(&n_reserved,
+ index->space,
+ n_extents,
+ FSP_CLEANING, mtr);
+ if (!success) {
+ *err = DB_OUT_OF_FILE_SPACE;
+
+ return(FALSE);
+ }
+ }
+
+ heap = mem_heap_create(1024);
+ rec = btr_cur_get_rec(cursor);
+ page_zip = buf_block_get_page_zip(block);
+#ifdef UNIV_ZIP_DEBUG
+ ut_a(!page_zip || page_zip_validate(page_zip, page));
+#endif /* UNIV_ZIP_DEBUG */
+
+ offsets = rec_get_offsets(rec, index, NULL, ULINT_UNDEFINED, &heap);
+
+ if (rec_offs_any_extern(offsets)) {
+ btr_rec_free_externally_stored_fields(index,
+ rec, offsets, page_zip,
+ rb_ctx, mtr);
+#ifdef UNIV_ZIP_DEBUG
+ ut_a(!page_zip || page_zip_validate(page_zip, page));
+#endif /* UNIV_ZIP_DEBUG */
+ }
+
+ if (UNIV_UNLIKELY(page_get_n_recs(page) < 2)
+ && UNIV_UNLIKELY(dict_index_get_page(index)
+ != buf_block_get_page_no(block))) {
+
+ /* If there is only one record, drop the whole page in
+ btr_discard_page, if this is not the root page */
+
+ btr_discard_page(cursor, mtr);
+
+ *err = DB_SUCCESS;
+ ret = TRUE;
+
+ goto return_after_reservations;
+ }
+
+ lock_update_delete(block, rec);
+ level = btr_page_get_level(page, mtr);
+
+ if (level > 0
+ && UNIV_UNLIKELY(rec == page_rec_get_next(
+ page_get_infimum_rec(page)))) {
+
+ rec_t* next_rec = page_rec_get_next(rec);
+
+ if (btr_page_get_prev(page, mtr) == FIL_NULL) {
+
+ /* If we delete the leftmost node pointer on a
+ non-leaf level, we must mark the new leftmost node
+ pointer as the predefined minimum record */
+
+ /* This will make page_zip_validate() fail until
+ page_cur_delete_rec() completes. This is harmless,
+ because everything will take place within a single
+ mini-transaction and because writing to the redo log
+ is an atomic operation (performed by mtr_commit()). */
+ btr_set_min_rec_mark(next_rec, mtr);
+ } else {
+ /* Otherwise, if we delete the leftmost node pointer
+ on a page, we have to change the father node pointer
+ so that it is equal to the new leftmost node pointer
+ on the page */
+
+ btr_node_ptr_delete(index, block, mtr);
+
+ node_ptr = dict_index_build_node_ptr(
+ index, next_rec, buf_block_get_page_no(block),
+ heap, level);
+
+ btr_insert_on_non_leaf_level(index,
+ level + 1, node_ptr, mtr);
+ }
+ }
+
+ btr_search_update_hash_on_delete(cursor);
+
+ page_cur_delete_rec(btr_cur_get_page_cur(cursor), index, offsets, mtr);
+#ifdef UNIV_ZIP_DEBUG
+ ut_a(!page_zip || page_zip_validate(page_zip, page));
+#endif /* UNIV_ZIP_DEBUG */
+
+ ut_ad(btr_check_node_ptr(index, block, mtr));
+
+ *err = DB_SUCCESS;
+
+return_after_reservations:
+ mem_heap_free(heap);
+
+ if (ret == FALSE) {
+ ret = btr_cur_compress_if_useful(cursor, mtr);
+ }
+
+ if (n_extents > 0) {
+ fil_space_release_free_extents(index->space, n_reserved);
+ }
+
+ return(ret);
+}
+
+/*******************************************************************//**
+Adds path information to the cursor for the current page, for which
+the binary search has been performed. */
+static
+void
+btr_cur_add_path_info(
+/*==================*/
+ btr_cur_t* cursor, /*!< in: cursor positioned on a page */
+ ulint height, /*!< in: height of the page in tree;
+ 0 means leaf node */
+ ulint root_height) /*!< in: root node height in tree */
+{
+ btr_path_t* slot;
+ rec_t* rec;
+
+ ut_a(cursor->path_arr);
+
+ if (root_height >= BTR_PATH_ARRAY_N_SLOTS - 1) {
+ /* Do nothing; return empty path */
+
+ slot = cursor->path_arr;
+ slot->nth_rec = ULINT_UNDEFINED;
+
+ return;
+ }
+
+ if (height == 0) {
+ /* Mark end of slots for path */
+ slot = cursor->path_arr + root_height + 1;
+ slot->nth_rec = ULINT_UNDEFINED;
+ }
+
+ rec = btr_cur_get_rec(cursor);
+
+ slot = cursor->path_arr + (root_height - height);
+
+ slot->nth_rec = page_rec_get_n_recs_before(rec);
+ slot->n_recs = page_get_n_recs(page_align(rec));
+}
+
+/*******************************************************************//**
+Estimates the number of rows in a given index range.
+@return estimated number of rows */
+UNIV_INTERN
+ib_int64_t
+btr_estimate_n_rows_in_range(
+/*=========================*/
+ dict_index_t* index, /*!< in: index */
+ const dtuple_t* tuple1, /*!< in: range start, may also be empty tuple */
+ ulint mode1, /*!< in: search mode for range start */
+ const dtuple_t* tuple2, /*!< in: range end, may also be empty tuple */
+ ulint mode2) /*!< in: search mode for range end */
+{
+ btr_path_t path1[BTR_PATH_ARRAY_N_SLOTS];
+ btr_path_t path2[BTR_PATH_ARRAY_N_SLOTS];
+ btr_cur_t cursor;
+ btr_path_t* slot1;
+ btr_path_t* slot2;
+ ibool diverged;
+ ibool diverged_lot;
+ ulint divergence_level;
+ ib_int64_t n_rows;
+ ulint i;
+ mtr_t mtr;
+
+ mtr_start(&mtr);
+
+ cursor.path_arr = path1;
+
+ if (dtuple_get_n_fields(tuple1) > 0) {
+
+ btr_cur_search_to_nth_level(index, 0, tuple1, mode1,
+ BTR_SEARCH_LEAF | BTR_ESTIMATE,
+ &cursor, 0, &mtr);
+ } else {
+ btr_cur_open_at_index_side(TRUE, index,
+ BTR_SEARCH_LEAF | BTR_ESTIMATE,
+ &cursor, &mtr);
+ }
+
+ mtr_commit(&mtr);
+
+ mtr_start(&mtr);
+
+ cursor.path_arr = path2;
+
+ if (dtuple_get_n_fields(tuple2) > 0) {
+
+ btr_cur_search_to_nth_level(index, 0, tuple2, mode2,
+ BTR_SEARCH_LEAF | BTR_ESTIMATE,
+ &cursor, 0, &mtr);
+ } else {
+ btr_cur_open_at_index_side(FALSE, index,
+ BTR_SEARCH_LEAF | BTR_ESTIMATE,
+ &cursor, &mtr);
+ }
+
+ mtr_commit(&mtr);
+
+ /* We have the path information for the range in path1 and path2 */
+
+ n_rows = 1;
+ diverged = FALSE; /* This becomes true when the path is not
+ the same any more */
+ diverged_lot = FALSE; /* This becomes true when the paths are
+ not the same or adjacent any more */
+ divergence_level = 1000000; /* This is the level where paths diverged
+ a lot */
+ for (i = 0; ; i++) {
+ ut_ad(i < BTR_PATH_ARRAY_N_SLOTS);
+
+ slot1 = path1 + i;
+ slot2 = path2 + i;
+
+ if (slot1->nth_rec == ULINT_UNDEFINED
+ || slot2->nth_rec == ULINT_UNDEFINED) {
+
+ if (i > divergence_level + 1) {
+ /* In trees whose height is > 1 our algorithm
+ tends to underestimate: multiply the estimate
+ by 2: */
+
+ n_rows = n_rows * 2;
+ }
+
+ /* Do not estimate the number of rows in the range
+ to over 1 / 2 of the estimated rows in the whole
+ table */
+
+ if (n_rows > index->table->stat_n_rows / 2) {
+ n_rows = index->table->stat_n_rows / 2;
+
+ /* If there are just 0 or 1 rows in the table,
+ then we estimate all rows are in the range */
+
+ if (n_rows == 0) {
+ n_rows = index->table->stat_n_rows;
+ }
+ }
+
+ return(n_rows);
+ }
+
+ if (!diverged && slot1->nth_rec != slot2->nth_rec) {
+
+ diverged = TRUE;
+
+ if (slot1->nth_rec < slot2->nth_rec) {
+ n_rows = slot2->nth_rec - slot1->nth_rec;
+
+ if (n_rows > 1) {
+ diverged_lot = TRUE;
+ divergence_level = i;
+ }
+ } else {
+ /* Maybe the tree has changed between
+ searches */
+
+ return(10);
+ }
+
+ } else if (diverged && !diverged_lot) {
+
+ if (slot1->nth_rec < slot1->n_recs
+ || slot2->nth_rec > 1) {
+
+ diverged_lot = TRUE;
+ divergence_level = i;
+
+ n_rows = 0;
+
+ if (slot1->nth_rec < slot1->n_recs) {
+ n_rows += slot1->n_recs
+ - slot1->nth_rec;
+ }
+
+ if (slot2->nth_rec > 1) {
+ n_rows += slot2->nth_rec - 1;
+ }
+ }
+ } else if (diverged_lot) {
+
+ n_rows = (n_rows * (slot1->n_recs + slot2->n_recs))
+ / 2;
+ }
+ }
+}
+
+/*******************************************************************//**
+Estimates the number of different key values in a given index, for
+each n-column prefix of the index where n <= dict_index_get_n_unique(index).
+The estimates are stored in the array index->stat_n_diff_key_vals. */
+UNIV_INTERN
+void
+btr_estimate_number_of_different_key_vals(
+/*======================================*/
+ dict_index_t* index) /*!< in: index */
+{
+ btr_cur_t cursor;
+ page_t* page;
+ rec_t* rec;
+ ulint n_cols;
+ ulint matched_fields;
+ ulint matched_bytes;
+ ib_int64_t* n_diff;
+ ullint n_sample_pages; /* number of pages to sample */
+ ulint not_empty_flag = 0;
+ ulint total_external_size = 0;
+ ulint i;
+ ulint j;
+ ullint add_on;
+ mtr_t mtr;
+ mem_heap_t* heap = NULL;
+ ulint offsets_rec_[REC_OFFS_NORMAL_SIZE];
+ ulint offsets_next_rec_[REC_OFFS_NORMAL_SIZE];
+ ulint* offsets_rec = offsets_rec_;
+ ulint* offsets_next_rec= offsets_next_rec_;
+ rec_offs_init(offsets_rec_);
+ rec_offs_init(offsets_next_rec_);
+
+ n_cols = dict_index_get_n_unique(index);
+
+ n_diff = mem_zalloc((n_cols + 1) * sizeof(ib_int64_t));
+
+ /* It makes no sense to test more pages than are contained
+ in the index, thus we lower the number if it is too high */
+ if (srv_stats_sample_pages > index->stat_index_size) {
+ if (index->stat_index_size > 0) {
+ n_sample_pages = index->stat_index_size;
+ } else {
+ n_sample_pages = 1;
+ }
+ } else {
+ n_sample_pages = srv_stats_sample_pages;
+ }
+
+ /* We sample some pages in the index to get an estimate */
+
+ for (i = 0; i < n_sample_pages; i++) {
+ rec_t* supremum;
+ mtr_start(&mtr);
+
+ btr_cur_open_at_rnd_pos(index, BTR_SEARCH_LEAF, &cursor, &mtr);
+
+ /* Count the number of different key values for each prefix of
+ the key on this index page. If the prefix does not determine
+ the index record uniquely in the B-tree, then we subtract one
+ because otherwise our algorithm would give a wrong estimate
+ for an index where there is just one key value. */
+
+ page = btr_cur_get_page(&cursor);
+
+ supremum = page_get_supremum_rec(page);
+ rec = page_rec_get_next(page_get_infimum_rec(page));
+
+ if (rec != supremum) {
+ not_empty_flag = 1;
+ offsets_rec = rec_get_offsets(rec, index, offsets_rec,
+ ULINT_UNDEFINED, &heap);
+ }
+
+ while (rec != supremum) {
+ rec_t* next_rec = page_rec_get_next(rec);
+ if (next_rec == supremum) {
+ break;
+ }
+
+ matched_fields = 0;
+ matched_bytes = 0;
+ offsets_next_rec = rec_get_offsets(next_rec, index,
+ offsets_next_rec,
+ n_cols, &heap);
+
+ cmp_rec_rec_with_match(rec, next_rec,
+ offsets_rec, offsets_next_rec,
+ index, &matched_fields,
+ &matched_bytes);
+
+ for (j = matched_fields + 1; j <= n_cols; j++) {
+ /* We add one if this index record has
+ a different prefix from the previous */
+
+ n_diff[j]++;
+ }
+
+ total_external_size
+ += btr_rec_get_externally_stored_len(
+ rec, offsets_rec);
+
+ rec = next_rec;
+ /* Initialize offsets_rec for the next round
+ and assign the old offsets_rec buffer to
+ offsets_next_rec. */
+ {
+ ulint* offsets_tmp = offsets_rec;
+ offsets_rec = offsets_next_rec;
+ offsets_next_rec = offsets_tmp;
+ }
+ }
+
+
+ if (n_cols == dict_index_get_n_unique_in_tree(index)) {
+
+ /* If there is more than one leaf page in the tree,
+ we add one because we know that the first record
+ on the page certainly had a different prefix than the
+ last record on the previous index page in the
+ alphabetical order. Before this fix, if there was
+ just one big record on each clustered index page, the
+ algorithm grossly underestimated the number of rows
+ in the table. */
+
+ if (btr_page_get_prev(page, &mtr) != FIL_NULL
+ || btr_page_get_next(page, &mtr) != FIL_NULL) {
+
+ n_diff[n_cols]++;
+ }
+ }
+
+ offsets_rec = rec_get_offsets(rec, index, offsets_rec,
+ ULINT_UNDEFINED, &heap);
+ total_external_size += btr_rec_get_externally_stored_len(
+ rec, offsets_rec);
+ mtr_commit(&mtr);
+ }
+
+ /* If we saw k borders between different key values on
+ n_sample_pages leaf pages, we can estimate how many
+ there will be in index->stat_n_leaf_pages */
+
+ /* We must take into account that our sample actually represents
+ also the pages used for external storage of fields (those pages are
+ included in index->stat_n_leaf_pages) */
+
+ for (j = 0; j <= n_cols; j++) {
+ index->stat_n_diff_key_vals[j]
+ = ((n_diff[j]
+ * (ib_int64_t)index->stat_n_leaf_pages
+ + n_sample_pages - 1
+ + total_external_size
+ + not_empty_flag)
+ / (n_sample_pages
+ + total_external_size));
+
+ /* If the tree is small, smaller than
+ 10 * n_sample_pages + total_external_size, then
+ the above estimate is ok. For bigger trees it is common that we
+ do not see any borders between key values in the few pages
+ we pick. But still there may be n_sample_pages
+ different key values, or even more. Let us try to approximate
+ that: */
+
+ add_on = index->stat_n_leaf_pages
+ / (10 * (n_sample_pages
+ + total_external_size));
+
+ if (add_on > n_sample_pages) {
+ add_on = n_sample_pages;
+ }
+
+ index->stat_n_diff_key_vals[j] += add_on;
+ }
+
+ mem_free(n_diff);
+ if (UNIV_LIKELY_NULL(heap)) {
+ mem_heap_free(heap);
+ }
+}
+
+/*================== EXTERNAL STORAGE OF BIG FIELDS ===================*/
+
+/***********************************************************//**
+Gets the externally stored size of a record, in units of a database page.
+@return externally stored part, in units of a database page */
+static
+ulint
+btr_rec_get_externally_stored_len(
+/*==============================*/
+ rec_t* rec, /*!< in: record */
+ const ulint* offsets)/*!< in: array returned by rec_get_offsets() */
+{
+ ulint n_fields;
+ byte* data;
+ ulint local_len;
+ ulint extern_len;
+ ulint total_extern_len = 0;
+ ulint i;
+
+ ut_ad(!rec_offs_comp(offsets) || !rec_get_node_ptr_flag(rec));
+ n_fields = rec_offs_n_fields(offsets);
+
+ for (i = 0; i < n_fields; i++) {
+ if (rec_offs_nth_extern(offsets, i)) {
+
+ data = rec_get_nth_field(rec, offsets, i, &local_len);
+
+ local_len -= BTR_EXTERN_FIELD_REF_SIZE;
+
+ extern_len = mach_read_from_4(data + local_len
+ + BTR_EXTERN_LEN + 4);
+
+ total_extern_len += ut_calc_align(extern_len,
+ UNIV_PAGE_SIZE);
+ }
+ }
+
+ return(total_extern_len / UNIV_PAGE_SIZE);
+}
+
+/*******************************************************************//**
+Sets the ownership bit of an externally stored field in a record. */
+static
+void
+btr_cur_set_ownership_of_extern_field(
+/*==================================*/
+ page_zip_des_t* page_zip,/*!< in/out: compressed page whose uncompressed
+ part will be updated, or NULL */
+ rec_t* rec, /*!< in/out: clustered index record */
+ dict_index_t* index, /*!< in: index of the page */
+ const ulint* offsets,/*!< in: array returned by rec_get_offsets() */
+ ulint i, /*!< in: field number */
+ ibool val, /*!< in: value to set */
+ mtr_t* mtr) /*!< in: mtr, or NULL if not logged */
+{
+ byte* data;
+ ulint local_len;
+ ulint byte_val;
+
+ data = rec_get_nth_field(rec, offsets, i, &local_len);
+
+ ut_a(local_len >= BTR_EXTERN_FIELD_REF_SIZE);
+
+ local_len -= BTR_EXTERN_FIELD_REF_SIZE;
+
+ byte_val = mach_read_from_1(data + local_len + BTR_EXTERN_LEN);
+
+ if (val) {
+ byte_val = byte_val & (~BTR_EXTERN_OWNER_FLAG);
+ } else {
+ byte_val = byte_val | BTR_EXTERN_OWNER_FLAG;
+ }
+
+ if (UNIV_LIKELY_NULL(page_zip)) {
+ mach_write_to_1(data + local_len + BTR_EXTERN_LEN, byte_val);
+ page_zip_write_blob_ptr(page_zip, rec, index, offsets, i, mtr);
+ } else if (UNIV_LIKELY(mtr != NULL)) {
+
+ mlog_write_ulint(data + local_len + BTR_EXTERN_LEN, byte_val,
+ MLOG_1BYTE, mtr);
+ } else {
+ mach_write_to_1(data + local_len + BTR_EXTERN_LEN, byte_val);
+ }
+}
+
+/*******************************************************************//**
+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
+index tree. In purge only the owner of externally stored field is allowed
+to free the field. */
+UNIV_INTERN
+void
+btr_cur_mark_extern_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 */
+{
+ ulint n;
+ ulint j;
+ ulint i;
+
+ ut_ad(rec_offs_validate(rec, NULL, offsets));
+ ut_ad(!rec_offs_comp(offsets) || !rec_get_node_ptr_flag(rec));
+
+ if (!rec_offs_any_extern(offsets)) {
+
+ return;
+ }
+
+ 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;
+ }
+ }
+ }
+
+ btr_cur_set_ownership_of_extern_field(
+ page_zip, rec, index, offsets, i, FALSE, mtr);
+updated:
+ ;
+ }
+ }
+}
+
+/*******************************************************************//**
+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:
+ ;
+ }
+}
+
+/*******************************************************************//**
+Marks all extern fields in a record as owned by the record. This function
+should be called if the delete mark of a record is removed: a not delete
+marked record always owns all its extern fields. */
+static
+void
+btr_cur_unmark_extern_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() */
+ mtr_t* mtr) /*!< in: mtr, or NULL if not logged */
+{
+ ulint n;
+ ulint i;
+
+ ut_ad(!rec_offs_comp(offsets) || !rec_get_node_ptr_flag(rec));
+ n = rec_offs_n_fields(offsets);
+
+ if (!rec_offs_any_extern(offsets)) {
+
+ return;
+ }
+
+ for (i = 0; i < n; i++) {
+ if (rec_offs_nth_extern(offsets, i)) {
+
+ btr_cur_set_ownership_of_extern_field(
+ page_zip, rec, index, offsets, i, TRUE, mtr);
+ }
+ }
+}
+
+/*******************************************************************//**
+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
+mark as extern storage in a record inserted for an update.
+@return number of flagged external columns */
+UNIV_INTERN
+ulint
+btr_push_update_extern_fields(
+/*==========================*/
+ dtuple_t* tuple, /*!< in/out: data tuple */
+ const upd_t* update, /*!< in: update vector */
+ mem_heap_t* heap) /*!< in: memory heap */
+{
+ ulint n_pushed = 0;
+ ulint n;
+ const upd_field_t* uf;
+
+ ut_ad(tuple);
+ ut_ad(update);
+
+ uf = update->fields;
+ n = upd_get_n_fields(update);
+
+ for (; n--; uf++) {
+ if (dfield_is_ext(&uf->new_val)) {
+ dfield_t* field
+ = dtuple_get_nth_field(tuple, uf->field_no);
+
+ if (!dfield_is_ext(field)) {
+ dfield_set_ext(field);
+ n_pushed++;
+ }
+
+ switch (uf->orig_len) {
+ byte* data;
+ ulint len;
+ byte* buf;
+ case 0:
+ break;
+ case BTR_EXTERN_FIELD_REF_SIZE:
+ /* Restore the original locally stored
+ part of the column. In the undo log,
+ InnoDB writes a longer prefix of externally
+ stored columns, so that column prefixes
+ in secondary indexes can be reconstructed. */
+ dfield_set_data(field, (byte*) dfield_get_data(field)
+ + dfield_get_len(field)
+ - BTR_EXTERN_FIELD_REF_SIZE,
+ BTR_EXTERN_FIELD_REF_SIZE);
+ dfield_set_ext(field);
+ break;
+ default:
+ /* Reconstruct the original locally
+ stored part of the column. The data
+ will have to be copied. */
+ ut_a(uf->orig_len > BTR_EXTERN_FIELD_REF_SIZE);
+
+ data = dfield_get_data(field);
+ len = dfield_get_len(field);
+
+ buf = mem_heap_alloc(heap, uf->orig_len);
+ /* Copy the locally stored prefix. */
+ memcpy(buf, data,
+ uf->orig_len
+ - BTR_EXTERN_FIELD_REF_SIZE);
+ /* Copy the BLOB pointer. */
+ memcpy(buf + uf->orig_len
+ - BTR_EXTERN_FIELD_REF_SIZE,
+ data + len - BTR_EXTERN_FIELD_REF_SIZE,
+ BTR_EXTERN_FIELD_REF_SIZE);
+
+ dfield_set_data(field, buf, uf->orig_len);
+ dfield_set_ext(field);
+ }
+ }
+ }
+
+ return(n_pushed);
+}
+
+/*******************************************************************//**
+Returns the length of a BLOB part stored on the header page.
+@return part length */
+static
+ulint
+btr_blob_get_part_len(
+/*==================*/
+ const byte* blob_header) /*!< in: blob header */
+{
+ return(mach_read_from_4(blob_header + BTR_BLOB_HDR_PART_LEN));
+}
+
+/*******************************************************************//**
+Returns the page number where the next BLOB part is stored.
+@return page number or FIL_NULL if no more pages */
+static
+ulint
+btr_blob_get_next_page_no(
+/*======================*/
+ const byte* blob_header) /*!< in: blob header */
+{
+ return(mach_read_from_4(blob_header + BTR_BLOB_HDR_NEXT_PAGE_NO));
+}
+
+/*******************************************************************//**
+Deallocate a buffer block that was reserved for a BLOB part. */
+static
+void
+btr_blob_free(
+/*==========*/
+ buf_block_t* block, /*!< in: buffer block */
+ ibool all, /*!< in: TRUE=remove also the compressed page
+ if there is one */
+ mtr_t* mtr) /*!< in: mini-transaction to commit */
+{
+ ulint space = buf_block_get_space(block);
+ ulint page_no = buf_block_get_page_no(block);
+
+ ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX));
+
+ mtr_commit(mtr);
+
+ buf_pool_mutex_enter();
+ mutex_enter(&block->mutex);
+
+ /* Only free the block if it is still allocated to
+ the same file page. */
+
+ if (buf_block_get_state(block)
+ == BUF_BLOCK_FILE_PAGE
+ && buf_block_get_space(block) == space
+ && buf_block_get_page_no(block) == page_no) {
+
+ if (buf_LRU_free_block(&block->page, all, NULL)
+ != BUF_LRU_FREED
+ && all && block->page.zip.data) {
+ /* Attempt to deallocate the uncompressed page
+ if the whole block cannot be deallocted. */
+
+ buf_LRU_free_block(&block->page, FALSE, NULL);
+ }
+ }
+
+ buf_pool_mutex_exit();
+ mutex_exit(&block->mutex);
+}
+
+/*******************************************************************//**
+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.
+The fields are stored on pages allocated from leaf node
+file segment of the index tree.
+@return DB_SUCCESS or error */
+UNIV_INTERN
+ulint
+btr_store_big_rec_extern_fields(
+/*============================*/
+ dict_index_t* index, /*!< in: index of rec; the index tree
+ MUST be X-latched */
+ buf_block_t* rec_block, /*!< in/out: block containing rec */
+ rec_t* rec, /*!< in/out: record */
+ const ulint* offsets, /*!< in: rec_get_offsets(rec, index);
+ the "external storage" flags in offsets
+ will not correspond to rec when
+ this function returns */
+ big_rec_t* big_rec_vec, /*!< in: vector containing fields
+ to be stored externally */
+ mtr_t* local_mtr __attribute__((unused))) /*!< in: mtr
+ containing the latch to rec and to the
+ tree */
+{
+ ulint rec_page_no;
+ byte* field_ref;
+ ulint extern_len;
+ ulint store_len;
+ ulint page_no;
+ ulint space_id;
+ ulint zip_size;
+ ulint prev_page_no;
+ ulint hint_page_no;
+ ulint i;
+ mtr_t mtr;
+ mem_heap_t* heap = NULL;
+ page_zip_des_t* page_zip;
+ z_stream c_stream;
+
+ ut_ad(rec_offs_validate(rec, index, offsets));
+ ut_ad(mtr_memo_contains(local_mtr, dict_index_get_lock(index),
+ MTR_MEMO_X_LOCK));
+ ut_ad(mtr_memo_contains(local_mtr, rec_block, MTR_MEMO_PAGE_X_FIX));
+ ut_ad(buf_block_get_frame(rec_block) == page_align(rec));
+ ut_a(dict_index_is_clust(index));
+
+ page_zip = buf_block_get_page_zip(rec_block);
+ ut_a(dict_table_zip_size(index->table)
+ == buf_block_get_zip_size(rec_block));
+
+ space_id = buf_block_get_space(rec_block);
+ zip_size = buf_block_get_zip_size(rec_block);
+ rec_page_no = buf_block_get_page_no(rec_block);
+ ut_a(fil_page_get_type(page_align(rec)) == FIL_PAGE_INDEX);
+
+ if (UNIV_LIKELY_NULL(page_zip)) {
+ int err;
+
+ /* Zlib deflate needs 128 kilobytes for the default
+ window size, plus 512 << memLevel, plus a few
+ kilobytes for small objects. We use reduced memLevel
+ to limit the memory consumption, and preallocate the
+ heap, hoping to avoid memory fragmentation. */
+ heap = mem_heap_create(250000);
+ page_zip_set_alloc(&c_stream, heap);
+
+ err = deflateInit2(&c_stream, Z_DEFAULT_COMPRESSION,
+ Z_DEFLATED, 15, 7, Z_DEFAULT_STRATEGY);
+ ut_a(err == Z_OK);
+ }
+
+ /* We have to create a file segment to the tablespace
+ for each field and put the pointer to the field in rec */
+
+ for (i = 0; i < big_rec_vec->n_fields; i++) {
+ ut_ad(rec_offs_nth_extern(offsets,
+ big_rec_vec->fields[i].field_no));
+ {
+ ulint local_len;
+ field_ref = rec_get_nth_field(
+ rec, offsets, big_rec_vec->fields[i].field_no,
+ &local_len);
+ ut_a(local_len >= BTR_EXTERN_FIELD_REF_SIZE);
+ local_len -= BTR_EXTERN_FIELD_REF_SIZE;
+ field_ref += local_len;
+ }
+ extern_len = big_rec_vec->fields[i].len;
+
+ ut_a(extern_len > 0);
+
+ prev_page_no = FIL_NULL;
+
+ if (UNIV_LIKELY_NULL(page_zip)) {
+ int err = deflateReset(&c_stream);
+ ut_a(err == Z_OK);
+
+ c_stream.next_in = (void*) big_rec_vec->fields[i].data;
+ c_stream.avail_in = extern_len;
+ }
+
+ for (;;) {
+ buf_block_t* block;
+ page_t* page;
+
+ mtr_start(&mtr);
+
+ if (prev_page_no == FIL_NULL) {
+ hint_page_no = 1 + rec_page_no;
+ } else {
+ hint_page_no = prev_page_no + 1;
+ }
+
+ block = btr_page_alloc(index, hint_page_no,
+ FSP_NO_DIR, 0, &mtr);
+ if (UNIV_UNLIKELY(block == NULL)) {
+
+ mtr_commit(&mtr);
+
+ if (UNIV_LIKELY_NULL(page_zip)) {
+ deflateEnd(&c_stream);
+ mem_heap_free(heap);
+ }
+
+ return(DB_OUT_OF_FILE_SPACE);
+ }
+
+ page_no = buf_block_get_page_no(block);
+ page = buf_block_get_frame(block);
+
+ if (prev_page_no != FIL_NULL) {
+ buf_block_t* prev_block;
+ page_t* prev_page;
+
+ prev_block = buf_page_get(space_id, zip_size,
+ prev_page_no,
+ RW_X_LATCH, &mtr);
+ buf_block_dbg_add_level(prev_block,
+ SYNC_EXTERN_STORAGE);
+ prev_page = buf_block_get_frame(prev_block);
+
+ if (UNIV_LIKELY_NULL(page_zip)) {
+ mlog_write_ulint(
+ prev_page + FIL_PAGE_NEXT,
+ page_no, MLOG_4BYTES, &mtr);
+ memcpy(buf_block_get_page_zip(
+ prev_block)
+ ->data + FIL_PAGE_NEXT,
+ prev_page + FIL_PAGE_NEXT, 4);
+ } else {
+ mlog_write_ulint(
+ prev_page + FIL_PAGE_DATA
+ + BTR_BLOB_HDR_NEXT_PAGE_NO,
+ page_no, MLOG_4BYTES, &mtr);
+ }
+
+ }
+
+ if (UNIV_LIKELY_NULL(page_zip)) {
+ int err;
+ page_zip_des_t* blob_page_zip;
+
+ /* Write FIL_PAGE_TYPE to the redo log
+ separately, before logging any other
+ changes to the page, so that the debug
+ assertions in
+ recv_parse_or_apply_log_rec_body() can
+ be made simpler. Before InnoDB Plugin
+ 1.0.4, the initialization of
+ FIL_PAGE_TYPE was logged as part of
+ the mlog_log_string() below. */
+
+ mlog_write_ulint(page + FIL_PAGE_TYPE,
+ prev_page_no == FIL_NULL
+ ? FIL_PAGE_TYPE_ZBLOB
+ : FIL_PAGE_TYPE_ZBLOB2,
+ MLOG_2BYTES, &mtr);
+
+ c_stream.next_out = page
+ + FIL_PAGE_DATA;
+ c_stream.avail_out
+ = page_zip_get_size(page_zip)
+ - FIL_PAGE_DATA;
+
+ err = deflate(&c_stream, Z_FINISH);
+ ut_a(err == Z_OK || err == Z_STREAM_END);
+ ut_a(err == Z_STREAM_END
+ || c_stream.avail_out == 0);
+
+ /* Write the "next BLOB page" pointer */
+ mlog_write_ulint(page + FIL_PAGE_NEXT,
+ FIL_NULL, MLOG_4BYTES, &mtr);
+ /* Initialize the unused "prev page" pointer */
+ mlog_write_ulint(page + FIL_PAGE_PREV,
+ FIL_NULL, MLOG_4BYTES, &mtr);
+ /* Write a back pointer to the record
+ into the otherwise unused area. This
+ information could be useful in
+ debugging. Later, we might want to
+ implement the possibility to relocate
+ BLOB pages. Then, we would need to be
+ able to adjust the BLOB pointer in the
+ record. We do not store the heap
+ number of the record, because it can
+ change in page_zip_reorganize() or
+ btr_page_reorganize(). However, also
+ the page number of the record may
+ change when B-tree nodes are split or
+ merged. */
+ mlog_write_ulint(page
+ + FIL_PAGE_FILE_FLUSH_LSN,
+ space_id,
+ MLOG_4BYTES, &mtr);
+ mlog_write_ulint(page
+ + FIL_PAGE_FILE_FLUSH_LSN + 4,
+ rec_page_no,
+ MLOG_4BYTES, &mtr);
+
+ /* Zero out the unused part of the page. */
+ memset(page + page_zip_get_size(page_zip)
+ - c_stream.avail_out,
+ 0, c_stream.avail_out);
+ mlog_log_string(page + FIL_PAGE_FILE_FLUSH_LSN,
+ page_zip_get_size(page_zip)
+ - FIL_PAGE_FILE_FLUSH_LSN,
+ &mtr);
+ /* Copy the page to compressed storage,
+ because it will be flushed to disk
+ from there. */
+ blob_page_zip = buf_block_get_page_zip(block);
+ ut_ad(blob_page_zip);
+ ut_ad(page_zip_get_size(blob_page_zip)
+ == page_zip_get_size(page_zip));
+ memcpy(blob_page_zip->data, page,
+ page_zip_get_size(page_zip));
+
+ if (err == Z_OK && prev_page_no != FIL_NULL) {
+
+ goto next_zip_page;
+ }
+
+ rec_block = buf_page_get(space_id, zip_size,
+ rec_page_no,
+ RW_X_LATCH, &mtr);
+ buf_block_dbg_add_level(rec_block,
+ SYNC_NO_ORDER_CHECK);
+
+ if (err == Z_STREAM_END) {
+ mach_write_to_4(field_ref
+ + BTR_EXTERN_LEN, 0);
+ mach_write_to_4(field_ref
+ + BTR_EXTERN_LEN + 4,
+ c_stream.total_in);
+ } else {
+ memset(field_ref + BTR_EXTERN_LEN,
+ 0, 8);
+ }
+
+ if (prev_page_no == FIL_NULL) {
+ mach_write_to_4(field_ref
+ + BTR_EXTERN_SPACE_ID,
+ space_id);
+
+ mach_write_to_4(field_ref
+ + BTR_EXTERN_PAGE_NO,
+ page_no);
+
+ mach_write_to_4(field_ref
+ + BTR_EXTERN_OFFSET,
+ FIL_PAGE_NEXT);
+ }
+
+ page_zip_write_blob_ptr(
+ page_zip, rec, index, offsets,
+ big_rec_vec->fields[i].field_no, &mtr);
+
+next_zip_page:
+ prev_page_no = page_no;
+
+ /* Commit mtr and release the
+ uncompressed page frame to save memory. */
+ btr_blob_free(block, FALSE, &mtr);
+
+ if (err == Z_STREAM_END) {
+ break;
+ }
+ } else {
+ mlog_write_ulint(page + FIL_PAGE_TYPE,
+ FIL_PAGE_TYPE_BLOB,
+ MLOG_2BYTES, &mtr);
+
+ if (extern_len > (UNIV_PAGE_SIZE
+ - FIL_PAGE_DATA
+ - BTR_BLOB_HDR_SIZE
+ - FIL_PAGE_DATA_END)) {
+ store_len = UNIV_PAGE_SIZE
+ - FIL_PAGE_DATA
+ - BTR_BLOB_HDR_SIZE
+ - FIL_PAGE_DATA_END;
+ } else {
+ store_len = extern_len;
+ }
+
+ mlog_write_string(page + FIL_PAGE_DATA
+ + BTR_BLOB_HDR_SIZE,
+ (const byte*)
+ big_rec_vec->fields[i].data
+ + big_rec_vec->fields[i].len
+ - extern_len,
+ store_len, &mtr);
+ mlog_write_ulint(page + FIL_PAGE_DATA
+ + BTR_BLOB_HDR_PART_LEN,
+ store_len, MLOG_4BYTES, &mtr);
+ mlog_write_ulint(page + FIL_PAGE_DATA
+ + BTR_BLOB_HDR_NEXT_PAGE_NO,
+ FIL_NULL, MLOG_4BYTES, &mtr);
+
+ extern_len -= store_len;
+
+ rec_block = buf_page_get(space_id, zip_size,
+ rec_page_no,
+ RW_X_LATCH, &mtr);
+ buf_block_dbg_add_level(rec_block,
+ SYNC_NO_ORDER_CHECK);
+
+ mlog_write_ulint(field_ref + BTR_EXTERN_LEN, 0,
+ MLOG_4BYTES, &mtr);
+ mlog_write_ulint(field_ref
+ + BTR_EXTERN_LEN + 4,
+ big_rec_vec->fields[i].len
+ - extern_len,
+ MLOG_4BYTES, &mtr);
+
+ if (prev_page_no == FIL_NULL) {
+ mlog_write_ulint(field_ref
+ + BTR_EXTERN_SPACE_ID,
+ space_id,
+ MLOG_4BYTES, &mtr);
+
+ mlog_write_ulint(field_ref
+ + BTR_EXTERN_PAGE_NO,
+ page_no,
+ MLOG_4BYTES, &mtr);
+
+ mlog_write_ulint(field_ref
+ + BTR_EXTERN_OFFSET,
+ FIL_PAGE_DATA,
+ MLOG_4BYTES, &mtr);
+ }
+
+ prev_page_no = page_no;
+
+ mtr_commit(&mtr);
+
+ if (extern_len == 0) {
+ break;
+ }
+ }
+ }
+ }
+
+ if (UNIV_LIKELY_NULL(page_zip)) {
+ deflateEnd(&c_stream);
+ mem_heap_free(heap);
+ }
+
+ return(DB_SUCCESS);
+}
+
+/*******************************************************************//**
+Check the FIL_PAGE_TYPE on an uncompressed BLOB page. */
+static
+void
+btr_check_blob_fil_page_type(
+/*=========================*/
+ ulint space_id, /*!< in: space id */
+ ulint page_no, /*!< in: page number */
+ const page_t* page, /*!< in: page */
+ ibool read) /*!< in: TRUE=read, FALSE=purge */
+{
+ ulint type = fil_page_get_type(page);
+
+ ut_a(space_id == page_get_space_id(page));
+ ut_a(page_no == page_get_page_no(page));
+
+ if (UNIV_UNLIKELY(type != FIL_PAGE_TYPE_BLOB)) {
+ ulint flags = fil_space_get_flags(space_id);
+
+ if (UNIV_LIKELY
+ ((flags & DICT_TF_FORMAT_MASK) == DICT_TF_FORMAT_51)) {
+ /* Old versions of InnoDB did not initialize
+ FIL_PAGE_TYPE on BLOB pages. Do not print
+ anything about the type mismatch when reading
+ a BLOB page that is in Antelope format.*/
+ return;
+ }
+
+ ut_print_timestamp(stderr);
+ fprintf(stderr,
+ " InnoDB: FIL_PAGE_TYPE=%lu"
+ " on BLOB %s space %lu page %lu flags %lx\n",
+ (ulong) type, read ? "read" : "purge",
+ (ulong) space_id, (ulong) page_no, (ulong) flags);
+ ut_error;
+ }
+}
+
+/*******************************************************************//**
+Frees the space in an externally stored field to the file space
+management if the field in data is owned by the externally stored field,
+in a rollback we may have the additional condition that the field must
+not be inherited. */
+UNIV_INTERN
+void
+btr_free_externally_stored_field(
+/*=============================*/
+ dict_index_t* index, /*!< in: index of the data, the index
+ tree MUST be X-latched; if the tree
+ height is 1, then also the root page
+ must be X-latched! (this is relevant
+ in the case this function is called
+ from purge where 'data' is located on
+ an undo log page, not an index
+ page) */
+ byte* field_ref, /*!< in/out: field reference */
+ const rec_t* rec, /*!< in: record containing field_ref, for
+ page_zip_write_blob_ptr(), or NULL */
+ const ulint* offsets, /*!< in: rec_get_offsets(rec, index),
+ or NULL */
+ page_zip_des_t* page_zip, /*!< in: compressed page corresponding
+ to rec, or NULL if rec == NULL */
+ ulint i, /*!< in: field number of field_ref;
+ ignored if rec == NULL */
+ enum trx_rb_ctx rb_ctx, /*!< in: rollback context */
+ mtr_t* local_mtr __attribute__((unused))) /*!< in: mtr
+ containing the latch to data an an
+ X-latch to the index tree */
+{
+ page_t* page;
+ ulint space_id;
+ ulint rec_zip_size = dict_table_zip_size(index->table);
+ ulint ext_zip_size;
+ ulint page_no;
+ ulint next_page_no;
+ mtr_t mtr;
+#ifdef UNIV_DEBUG
+ ut_ad(mtr_memo_contains(local_mtr, dict_index_get_lock(index),
+ MTR_MEMO_X_LOCK));
+ ut_ad(mtr_memo_contains_page(local_mtr, field_ref,
+ MTR_MEMO_PAGE_X_FIX));
+ ut_ad(!rec || rec_offs_validate(rec, index, offsets));
+
+ if (rec) {
+ ulint local_len;
+ const byte* f = rec_get_nth_field(rec, offsets,
+ i, &local_len);
+ ut_a(local_len >= BTR_EXTERN_FIELD_REF_SIZE);
+ local_len -= BTR_EXTERN_FIELD_REF_SIZE;
+ f += local_len;
+ ut_ad(f == field_ref);
+ }
+#endif /* UNIV_DEBUG */
+
+ if (UNIV_UNLIKELY(!memcmp(field_ref, field_ref_zero,
+ BTR_EXTERN_FIELD_REF_SIZE))) {
+ /* In the rollback of uncommitted transactions, we may
+ encounter a clustered index record whose BLOBs have
+ not been written. There is nothing to free then. */
+ ut_a(rb_ctx == RB_RECOVERY);
+ return;
+ }
+
+ space_id = mach_read_from_4(field_ref + BTR_EXTERN_SPACE_ID);
+
+ if (UNIV_UNLIKELY(space_id != dict_index_get_space(index))) {
+ ext_zip_size = fil_space_get_zip_size(space_id);
+ /* This must be an undo log record in the system tablespace,
+ that is, in row_purge_upd_exist_or_extern().
+ Currently, externally stored records are stored in the
+ same tablespace as the referring records. */
+ ut_ad(!page_get_space_id(page_align(field_ref)));
+ ut_ad(!rec);
+ ut_ad(!page_zip);
+ } else {
+ ext_zip_size = rec_zip_size;
+ }
+
+ if (!rec) {
+ /* This is a call from row_purge_upd_exist_or_extern(). */
+ ut_ad(!page_zip);
+ rec_zip_size = 0;
+ }
+
+ for (;;) {
+ buf_block_t* rec_block;
+ buf_block_t* ext_block;
+
+ mtr_start(&mtr);
+
+ rec_block = buf_page_get(page_get_space_id(
+ page_align(field_ref)),
+ rec_zip_size,
+ page_get_page_no(
+ page_align(field_ref)),
+ RW_X_LATCH, &mtr);
+ buf_block_dbg_add_level(rec_block, SYNC_NO_ORDER_CHECK);
+ page_no = mach_read_from_4(field_ref + BTR_EXTERN_PAGE_NO);
+
+ if (/* There is no external storage data */
+ page_no == FIL_NULL
+ /* This field does not own the externally stored field */
+ || (mach_read_from_1(field_ref + BTR_EXTERN_LEN)
+ & BTR_EXTERN_OWNER_FLAG)
+ /* Rollback and inherited field */
+ || (rb_ctx != RB_NONE
+ && (mach_read_from_1(field_ref + BTR_EXTERN_LEN)
+ & BTR_EXTERN_INHERITED_FLAG))) {
+
+ /* Do not free */
+ mtr_commit(&mtr);
+
+ return;
+ }
+
+ ext_block = buf_page_get(space_id, ext_zip_size, page_no,
+ RW_X_LATCH, &mtr);
+ buf_block_dbg_add_level(ext_block, SYNC_EXTERN_STORAGE);
+ page = buf_block_get_frame(ext_block);
+
+ if (ext_zip_size) {
+ /* Note that page_zip will be NULL
+ in row_purge_upd_exist_or_extern(). */
+ switch (fil_page_get_type(page)) {
+ case FIL_PAGE_TYPE_ZBLOB:
+ case FIL_PAGE_TYPE_ZBLOB2:
+ break;
+ default:
+ ut_error;
+ }
+ next_page_no = mach_read_from_4(page + FIL_PAGE_NEXT);
+
+ btr_page_free_low(index, ext_block, 0, &mtr);
+
+ if (UNIV_LIKELY(page_zip != NULL)) {
+ mach_write_to_4(field_ref + BTR_EXTERN_PAGE_NO,
+ next_page_no);
+ mach_write_to_4(field_ref + BTR_EXTERN_LEN + 4,
+ 0);
+ page_zip_write_blob_ptr(page_zip, rec, index,
+ offsets, i, &mtr);
+ } else {
+ mlog_write_ulint(field_ref
+ + BTR_EXTERN_PAGE_NO,
+ next_page_no,
+ MLOG_4BYTES, &mtr);
+ mlog_write_ulint(field_ref
+ + BTR_EXTERN_LEN + 4, 0,
+ MLOG_4BYTES, &mtr);
+ }
+ } else {
+ ut_a(!page_zip);
+ btr_check_blob_fil_page_type(space_id, page_no, page,
+ FALSE);
+
+ next_page_no = mach_read_from_4(
+ page + FIL_PAGE_DATA
+ + BTR_BLOB_HDR_NEXT_PAGE_NO);
+
+ /* We must supply the page level (= 0) as an argument
+ because we did not store it on the page (we save the
+ space overhead from an index page header. */
+
+ btr_page_free_low(index, ext_block, 0, &mtr);
+
+ mlog_write_ulint(field_ref + BTR_EXTERN_PAGE_NO,
+ next_page_no,
+ MLOG_4BYTES, &mtr);
+ /* Zero out the BLOB length. If the server
+ crashes during the execution of this function,
+ trx_rollback_or_clean_all_recovered() could
+ dereference the half-deleted BLOB, fetching a
+ wrong prefix for the BLOB. */
+ mlog_write_ulint(field_ref + BTR_EXTERN_LEN + 4,
+ 0,
+ MLOG_4BYTES, &mtr);
+ }
+
+ /* Commit mtr and release the BLOB block to save memory. */
+ btr_blob_free(ext_block, TRUE, &mtr);
+ }
+}
+
+/***********************************************************//**
+Frees the externally stored fields for a record. */
+static
+void
+btr_rec_free_externally_stored_fields(
+/*==================================*/
+ dict_index_t* index, /*!< in: index of the data, the index
+ tree MUST be X-latched */
+ rec_t* rec, /*!< in/out: record */
+ const ulint* offsets,/*!< in: rec_get_offsets(rec, index) */
+ page_zip_des_t* page_zip,/*!< in: compressed page whose uncompressed
+ part will be updated, or NULL */
+ enum trx_rb_ctx rb_ctx, /*!< in: rollback context */
+ mtr_t* mtr) /*!< in: mini-transaction handle which contains
+ an X-latch to record page and to the index
+ tree */
+{
+ ulint n_fields;
+ ulint i;
+
+ ut_ad(rec_offs_validate(rec, index, offsets));
+ ut_ad(mtr_memo_contains_page(mtr, rec, MTR_MEMO_PAGE_X_FIX));
+ /* Free possible externally stored fields in the record */
+
+ ut_ad(dict_table_is_comp(index->table) == !!rec_offs_comp(offsets));
+ n_fields = rec_offs_n_fields(offsets);
+
+ for (i = 0; i < n_fields; i++) {
+ if (rec_offs_nth_extern(offsets, i)) {
+ ulint len;
+ byte* data
+ = rec_get_nth_field(rec, offsets, i, &len);
+ ut_a(len >= BTR_EXTERN_FIELD_REF_SIZE);
+
+ btr_free_externally_stored_field(
+ index, data + len - BTR_EXTERN_FIELD_REF_SIZE,
+ rec, offsets, page_zip, i, rb_ctx, mtr);
+ }
+ }
+}
+
+/***********************************************************//**
+Frees the externally stored fields for a record, if the field is mentioned
+in the update vector. */
+static
+void
+btr_rec_free_updated_extern_fields(
+/*===============================*/
+ dict_index_t* index, /*!< in: index of rec; the index tree MUST be
+ X-latched */
+ rec_t* rec, /*!< in/out: record */
+ page_zip_des_t* page_zip,/*!< in: compressed page whose uncompressed
+ part will be updated, or NULL */
+ const ulint* offsets,/*!< in: rec_get_offsets(rec, index) */
+ const upd_t* update, /*!< in: update vector */
+ enum trx_rb_ctx rb_ctx, /*!< in: rollback context */
+ mtr_t* mtr) /*!< in: mini-transaction handle which contains
+ an X-latch to record page and to the tree */
+{
+ ulint n_fields;
+ ulint i;
+
+ ut_ad(rec_offs_validate(rec, index, offsets));
+ ut_ad(mtr_memo_contains_page(mtr, rec, MTR_MEMO_PAGE_X_FIX));
+
+ /* Free possible externally stored fields in the record */
+
+ n_fields = upd_get_n_fields(update);
+
+ for (i = 0; i < n_fields; i++) {
+ const upd_field_t* ufield = upd_get_nth_field(update, i);
+
+ if (rec_offs_nth_extern(offsets, ufield->field_no)) {
+ ulint len;
+ byte* data = rec_get_nth_field(
+ rec, offsets, ufield->field_no, &len);
+ ut_a(len >= BTR_EXTERN_FIELD_REF_SIZE);
+
+ btr_free_externally_stored_field(
+ index, data + len - BTR_EXTERN_FIELD_REF_SIZE,
+ rec, offsets, page_zip,
+ ufield->field_no, rb_ctx, mtr);
+ }
+ }
+}
+
+/*******************************************************************//**
+Copies the prefix of an uncompressed BLOB. The clustered index record
+that points to this BLOB must be protected by a lock or a page latch.
+@return number of bytes written to buf */
+static
+ulint
+btr_copy_blob_prefix(
+/*=================*/
+ byte* buf, /*!< out: the externally stored part of
+ the field, or a prefix of it */
+ ulint len, /*!< in: length of buf, in bytes */
+ ulint space_id,/*!< in: space id of the BLOB pages */
+ ulint page_no,/*!< in: page number of the first BLOB page */
+ ulint offset) /*!< in: offset on the first BLOB page */
+{
+ ulint copied_len = 0;
+
+ for (;;) {
+ mtr_t mtr;
+ buf_block_t* block;
+ const page_t* page;
+ const byte* blob_header;
+ ulint part_len;
+ ulint copy_len;
+
+ mtr_start(&mtr);
+
+ block = buf_page_get(space_id, 0, page_no, RW_S_LATCH, &mtr);
+ buf_block_dbg_add_level(block, SYNC_EXTERN_STORAGE);
+ page = buf_block_get_frame(block);
+
+ btr_check_blob_fil_page_type(space_id, page_no, page, TRUE);
+
+ blob_header = page + offset;
+ part_len = btr_blob_get_part_len(blob_header);
+ copy_len = ut_min(part_len, len - copied_len);
+
+ memcpy(buf + copied_len,
+ blob_header + BTR_BLOB_HDR_SIZE, copy_len);
+ copied_len += copy_len;
+
+ page_no = btr_blob_get_next_page_no(blob_header);
+
+ mtr_commit(&mtr);
+
+ if (page_no == FIL_NULL || copy_len != part_len) {
+ return(copied_len);
+ }
+
+ /* On other BLOB pages except the first the BLOB header
+ always is at the page data start: */
+
+ offset = FIL_PAGE_DATA;
+
+ ut_ad(copied_len <= len);
+ }
+}
+
+/*******************************************************************//**
+Copies the prefix of a compressed BLOB. The clustered index record
+that points to this BLOB must be protected by a lock or a page latch. */
+static
+void
+btr_copy_zblob_prefix(
+/*==================*/
+ z_stream* d_stream,/*!< in/out: the decompressing stream */
+ ulint zip_size,/*!< in: compressed BLOB page size */
+ ulint space_id,/*!< in: space id of the BLOB pages */
+ ulint page_no,/*!< in: page number of the first BLOB page */
+ ulint offset) /*!< in: offset on the first BLOB page */
+{
+ ulint page_type = FIL_PAGE_TYPE_ZBLOB;
+
+ ut_ad(ut_is_2pow(zip_size));
+ ut_ad(zip_size >= PAGE_ZIP_MIN_SIZE);
+ ut_ad(zip_size <= UNIV_PAGE_SIZE);
+ ut_ad(space_id);
+
+ for (;;) {
+ buf_page_t* bpage;
+ int err;
+ ulint next_page_no;
+
+ /* There is no latch on bpage directly. Instead,
+ bpage is protected by the B-tree page latch that
+ is being held on the clustered index record, or,
+ in row_merge_copy_blobs(), by an exclusive table lock. */
+ bpage = buf_page_get_zip(space_id, zip_size, page_no);
+
+ if (UNIV_UNLIKELY(!bpage)) {
+ ut_print_timestamp(stderr);
+ fprintf(stderr,
+ " InnoDB: Cannot load"
+ " compressed BLOB"
+ " page %lu space %lu\n",
+ (ulong) page_no, (ulong) space_id);
+ return;
+ }
+
+ if (UNIV_UNLIKELY
+ (fil_page_get_type(bpage->zip.data) != page_type)) {
+ ut_print_timestamp(stderr);
+ fprintf(stderr,
+ " InnoDB: Unexpected type %lu of"
+ " compressed BLOB"
+ " page %lu space %lu\n",
+ (ulong) fil_page_get_type(bpage->zip.data),
+ (ulong) page_no, (ulong) space_id);
+ goto end_of_blob;
+ }
+
+ next_page_no = mach_read_from_4(bpage->zip.data + offset);
+
+ if (UNIV_LIKELY(offset == FIL_PAGE_NEXT)) {
+ /* When the BLOB begins at page header,
+ the compressed data payload does not
+ immediately follow the next page pointer. */
+ offset = FIL_PAGE_DATA;
+ } else {
+ offset += 4;
+ }
+
+ d_stream->next_in = bpage->zip.data + offset;
+ d_stream->avail_in = zip_size - offset;
+
+ err = inflate(d_stream, Z_NO_FLUSH);
+ switch (err) {
+ case Z_OK:
+ if (!d_stream->avail_out) {
+ goto end_of_blob;
+ }
+ break;
+ case Z_STREAM_END:
+ if (next_page_no == FIL_NULL) {
+ goto end_of_blob;
+ }
+ /* fall through */
+ default:
+inflate_error:
+ ut_print_timestamp(stderr);
+ fprintf(stderr,
+ " InnoDB: inflate() of"
+ " compressed BLOB"
+ " page %lu space %lu returned %d (%s)\n",
+ (ulong) page_no, (ulong) space_id,
+ err, d_stream->msg);
+ case Z_BUF_ERROR:
+ goto end_of_blob;
+ }
+
+ if (next_page_no == FIL_NULL) {
+ if (!d_stream->avail_in) {
+ ut_print_timestamp(stderr);
+ fprintf(stderr,
+ " InnoDB: unexpected end of"
+ " compressed BLOB"
+ " page %lu space %lu\n",
+ (ulong) page_no,
+ (ulong) space_id);
+ } else {
+ err = inflate(d_stream, Z_FINISH);
+ switch (err) {
+ case Z_STREAM_END:
+ case Z_BUF_ERROR:
+ break;
+ default:
+ goto inflate_error;
+ }
+ }
+
+end_of_blob:
+ buf_page_release_zip(bpage);
+ return;
+ }
+
+ buf_page_release_zip(bpage);
+
+ /* On other BLOB pages except the first
+ the BLOB header always is at the page header: */
+
+ page_no = next_page_no;
+ offset = FIL_PAGE_NEXT;
+ page_type = FIL_PAGE_TYPE_ZBLOB2;
+ }
+}
+
+/*******************************************************************//**
+Copies the prefix of an externally stored field of a record. The
+clustered index record that points to this BLOB must be protected by a
+lock or a page latch.
+@return number of bytes written to buf */
+static
+ulint
+btr_copy_externally_stored_field_prefix_low(
+/*========================================*/
+ byte* buf, /*!< out: the externally stored part of
+ the field, or a prefix of it */
+ ulint len, /*!< in: length of buf, in bytes */
+ ulint zip_size,/*!< in: nonzero=compressed BLOB page size,
+ zero for uncompressed BLOBs */
+ ulint space_id,/*!< in: space id of the first BLOB page */
+ ulint page_no,/*!< in: page number of the first BLOB page */
+ ulint offset) /*!< in: offset on the first BLOB page */
+{
+ if (UNIV_UNLIKELY(len == 0)) {
+ return(0);
+ }
+
+ if (UNIV_UNLIKELY(zip_size)) {
+ int err;
+ z_stream d_stream;
+ mem_heap_t* heap;
+
+ /* Zlib inflate needs 32 kilobytes for the default
+ window size, plus a few kilobytes for small objects. */
+ heap = mem_heap_create(40000);
+ page_zip_set_alloc(&d_stream, heap);
+
+ err = inflateInit(&d_stream);
+ ut_a(err == Z_OK);
+
+ d_stream.next_out = buf;
+ d_stream.avail_out = len;
+ d_stream.avail_in = 0;
+
+ btr_copy_zblob_prefix(&d_stream, zip_size,
+ space_id, page_no, offset);
+ inflateEnd(&d_stream);
+ mem_heap_free(heap);
+ return(d_stream.total_out);
+ } else {
+ return(btr_copy_blob_prefix(buf, len, space_id,
+ page_no, offset));
+ }
+}
+
+/*******************************************************************//**
+Copies the prefix of an externally stored field of a record. The
+clustered index record must be protected by a lock or a page latch.
+@return the length of the copied field, or 0 if the column was being
+or has been deleted */
+UNIV_INTERN
+ulint
+btr_copy_externally_stored_field_prefix(
+/*====================================*/
+ byte* buf, /*!< out: the field, or a prefix of it */
+ ulint len, /*!< in: length of buf, in bytes */
+ ulint zip_size,/*!< in: nonzero=compressed BLOB page size,
+ zero for uncompressed BLOBs */
+ const byte* data, /*!< in: 'internally' stored part of the
+ field containing also the reference to
+ the external part; must be protected by
+ a lock or a page latch */
+ ulint local_len)/*!< in: length of data, in bytes */
+{
+ ulint space_id;
+ ulint page_no;
+ ulint offset;
+
+ ut_a(local_len >= BTR_EXTERN_FIELD_REF_SIZE);
+
+ local_len -= BTR_EXTERN_FIELD_REF_SIZE;
+
+ if (UNIV_UNLIKELY(local_len >= len)) {
+ memcpy(buf, data, len);
+ return(len);
+ }
+
+ memcpy(buf, data, local_len);
+ data += local_len;
+
+ ut_a(memcmp(data, field_ref_zero, BTR_EXTERN_FIELD_REF_SIZE));
+
+ if (!mach_read_from_4(data + BTR_EXTERN_LEN + 4)) {
+ /* The externally stored part of the column has been
+ (partially) deleted. Signal the half-deleted BLOB
+ to the caller. */
+
+ return(0);
+ }
+
+ space_id = mach_read_from_4(data + BTR_EXTERN_SPACE_ID);
+
+ page_no = mach_read_from_4(data + BTR_EXTERN_PAGE_NO);
+
+ offset = mach_read_from_4(data + BTR_EXTERN_OFFSET);
+
+ return(local_len
+ + btr_copy_externally_stored_field_prefix_low(buf + local_len,
+ len - local_len,
+ zip_size,
+ space_id, page_no,
+ offset));
+}
+
+/*******************************************************************//**
+Copies an externally stored field of a record to mem heap. The
+clustered index record must be protected by a lock or a page latch.
+@return the whole field copied to heap */
+static
+byte*
+btr_copy_externally_stored_field(
+/*=============================*/
+ ulint* len, /*!< out: length of the whole field */
+ const byte* data, /*!< in: 'internally' stored part of the
+ field containing also the reference to
+ the external part; must be protected by
+ a lock or a page latch */
+ ulint zip_size,/*!< in: nonzero=compressed BLOB page size,
+ zero for uncompressed BLOBs */
+ ulint local_len,/*!< in: length of data */
+ mem_heap_t* heap) /*!< in: mem heap */
+{
+ ulint space_id;
+ ulint page_no;
+ ulint offset;
+ ulint extern_len;
+ byte* buf;
+
+ ut_a(local_len >= BTR_EXTERN_FIELD_REF_SIZE);
+
+ local_len -= BTR_EXTERN_FIELD_REF_SIZE;
+
+ space_id = mach_read_from_4(data + local_len + BTR_EXTERN_SPACE_ID);
+
+ page_no = mach_read_from_4(data + local_len + BTR_EXTERN_PAGE_NO);
+
+ offset = mach_read_from_4(data + local_len + BTR_EXTERN_OFFSET);
+
+ /* Currently a BLOB cannot be bigger than 4 GB; we
+ leave the 4 upper bytes in the length field unused */
+
+ extern_len = mach_read_from_4(data + local_len + BTR_EXTERN_LEN + 4);
+
+ buf = mem_heap_alloc(heap, local_len + extern_len);
+
+ memcpy(buf, data, local_len);
+ *len = local_len
+ + btr_copy_externally_stored_field_prefix_low(buf + local_len,
+ extern_len,
+ zip_size,
+ space_id,
+ page_no, offset);
+
+ return(buf);
+}
+
+/*******************************************************************//**
+Copies an externally stored field of a record to mem heap.
+@return the field copied to heap */
+UNIV_INTERN
+byte*
+btr_rec_copy_externally_stored_field(
+/*=================================*/
+ const rec_t* rec, /*!< in: record in a clustered index;
+ must be protected by a lock or a page latch */
+ const ulint* offsets,/*!< in: array returned by rec_get_offsets() */
+ ulint zip_size,/*!< in: nonzero=compressed BLOB page size,
+ zero for uncompressed BLOBs */
+ ulint no, /*!< in: field number */
+ ulint* len, /*!< out: length of the field */
+ mem_heap_t* heap) /*!< in: mem heap */
+{
+ ulint local_len;
+ const byte* data;
+
+ ut_a(rec_offs_nth_extern(offsets, no));
+
+ /* An externally stored field can contain some initial
+ data from the field, and in the last 20 bytes it has the
+ space id, page number, and offset where the rest of the
+ field data is stored, and the data length in addition to
+ the data stored locally. We may need to store some data
+ locally to get the local record length above the 128 byte
+ limit so that field offsets are stored in two bytes, and
+ the extern bit is available in those two bytes. */
+
+ data = rec_get_nth_field(rec, offsets, no, &local_len);
+
+ return(btr_copy_externally_stored_field(len, data,
+ zip_size, local_len, heap));
+}
+#endif /* !UNIV_HOTBACKUP */
diff --git a/storage/innobase/btr/btr0pcur.c b/storage/innodb_plugin/btr/btr0pcur.c
similarity index 68%
rename from storage/innobase/btr/btr0pcur.c
rename to storage/innodb_plugin/btr/btr0pcur.c
index 65b3c90c809..ec98692c35b 100644
--- a/storage/innobase/btr/btr0pcur.c
+++ b/storage/innodb_plugin/btr/btr0pcur.c
@@ -1,7 +1,24 @@
-/******************************************************
-The index tree persistent cursor
+/*****************************************************************************
-(c) 1996 Innobase Oy
+Copyright (c) 1996, 2009, Innobase Oy. All Rights Reserved.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; version 2 of the License.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place, Suite 330, Boston, MA 02111-1307 USA
+
+*****************************************************************************/
+
+/**************************************************//**
+@file btr/btr0pcur.c
+The index tree persistent cursor
Created 2/23/1996 Heikki Tuuri
*******************************************************/
@@ -16,13 +33,13 @@ Created 2/23/1996 Heikki Tuuri
#include "rem0cmp.h"
#include "trx0trx.h"
-/******************************************************************
-Allocates memory for a persistent cursor object and initializes the cursor. */
-
+/**************************************************************//**
+Allocates memory for a persistent cursor object and initializes the cursor.
+@return own: persistent cursor */
+UNIV_INTERN
btr_pcur_t*
btr_pcur_create_for_mysql(void)
/*============================*/
- /* out, own: persistent cursor */
{
btr_pcur_t* pcur;
@@ -34,13 +51,13 @@ btr_pcur_create_for_mysql(void)
return(pcur);
}
-/******************************************************************
+/**************************************************************//**
Frees the memory for a persistent cursor object. */
-
+UNIV_INTERN
void
btr_pcur_free_for_mysql(
/*====================*/
- btr_pcur_t* cursor) /* in, own: persistent cursor */
+ btr_pcur_t* cursor) /*!< in, own: persistent cursor */
{
if (cursor->old_rec_buf != NULL) {
@@ -60,21 +77,22 @@ btr_pcur_free_for_mysql(
mem_free(cursor);
}
-/******************************************************************
+/**************************************************************//**
The position of the cursor is stored by taking an initial segment of the
record the cursor is positioned on, before, or after, and copying it to the
cursor data structure, or just setting a flag if the cursor id before the
first in an EMPTY tree, or after the last in an EMPTY tree. NOTE that the
page where the cursor is positioned must not be empty if the index tree is
not totally empty! */
-
+UNIV_INTERN
void
btr_pcur_store_position(
/*====================*/
- btr_pcur_t* cursor, /* in: persistent cursor */
- mtr_t* mtr) /* in: mtr */
+ btr_pcur_t* cursor, /*!< in: persistent cursor */
+ mtr_t* mtr) /*!< in: mtr */
{
page_cur_t* page_cursor;
+ buf_block_t* block;
rec_t* rec;
dict_index_t* index;
page_t* page;
@@ -83,6 +101,7 @@ btr_pcur_store_position(
ut_a(cursor->pos_state == BTR_PCUR_IS_POSITIONED);
ut_ad(cursor->latch_mode != BTR_NO_LATCHES);
+ block = btr_pcur_get_block(cursor);
index = btr_cur_get_index(btr_pcur_get_btr_cur(cursor));
page_cursor = btr_pcur_get_page_cur(cursor);
@@ -91,10 +110,8 @@ btr_pcur_store_position(
page = page_align(rec);
offs = page_offset(rec);
- ut_ad(mtr_memo_contains(mtr, buf_block_align(page),
- MTR_MEMO_PAGE_S_FIX)
- || mtr_memo_contains(mtr, buf_block_align(page),
- MTR_MEMO_PAGE_X_FIX));
+ ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_S_FIX)
+ || mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX));
ut_a(cursor->latch_mode != BTR_NO_LATCHES);
if (UNIV_UNLIKELY(page_get_n_recs(page) == 0)) {
@@ -137,20 +154,19 @@ btr_pcur_store_position(
index, rec, &cursor->old_n_fields,
&cursor->old_rec_buf, &cursor->buf_size);
- cursor->block_when_stored = buf_block_align(page);
- cursor->modify_clock = buf_block_get_modify_clock(
- cursor->block_when_stored);
+ cursor->block_when_stored = block;
+ cursor->modify_clock = buf_block_get_modify_clock(block);
}
-/******************************************************************
+/**************************************************************//**
Copies the stored position of a pcur to another pcur. */
-
+UNIV_INTERN
void
btr_pcur_copy_stored_position(
/*==========================*/
- btr_pcur_t* pcur_receive, /* in: pcur which will receive the
+ btr_pcur_t* pcur_receive, /*!< in: pcur which will receive the
position info */
- btr_pcur_t* pcur_donate) /* in: pcur from which the info is
+ btr_pcur_t* pcur_donate) /*!< in: pcur from which the info is
copied */
{
if (pcur_receive->old_rec_buf) {
@@ -172,7 +188,7 @@ btr_pcur_copy_stored_position(
pcur_receive->old_n_fields = pcur_donate->old_n_fields;
}
-/******************************************************************
+/**************************************************************//**
Restores the stored position of a persistent cursor bufferfixing the page and
obtaining the specified latches. If the cursor position was saved when the
(1) cursor was positioned on a user record: this function restores the position
@@ -183,22 +199,19 @@ infimum;
(3) cursor was positioned on the page supremum: restores to the first record
GREATER than the user record which was the predecessor of the supremum.
(4) cursor was positioned before the first or after the last in an empty tree:
-restores to before first or after the last in the tree. */
-
+restores to before first or after the last in the tree.
+@return TRUE if the cursor position was stored when it was on a user
+record and it can be restored on a user record whose ordering fields
+are identical to the ones of the original user record */
+UNIV_INTERN
ibool
btr_pcur_restore_position(
/*======================*/
- /* out: TRUE if the cursor position
- was stored when it was on a user record
- and it can be restored on a user record
- whose ordering fields are identical to
- the ones of the original user record */
- ulint latch_mode, /* in: BTR_SEARCH_LEAF, ... */
- btr_pcur_t* cursor, /* in: detached persistent cursor */
- mtr_t* mtr) /* in: mtr */
+ ulint latch_mode, /*!< in: BTR_SEARCH_LEAF, ... */
+ btr_pcur_t* cursor, /*!< in: detached persistent cursor */
+ mtr_t* mtr) /*!< in: mtr */
{
dict_index_t* index;
- page_t* page;
dtuple_t* tuple;
ulint mode;
ulint old_mode;
@@ -210,6 +223,7 @@ btr_pcur_restore_position(
|| UNIV_UNLIKELY(cursor->pos_state != BTR_PCUR_WAS_POSITIONED
&& cursor->pos_state != BTR_PCUR_IS_POSITIONED)) {
ut_print_buf(stderr, cursor, sizeof(btr_pcur_t));
+ putc('\n', stderr);
if (cursor->trx_if_known) {
trx_print(stderr, cursor->trx_if_known, 0);
}
@@ -217,9 +231,9 @@ btr_pcur_restore_position(
ut_error;
}
- if (UNIV_UNLIKELY(
- cursor->rel_pos == BTR_PCUR_AFTER_LAST_IN_TREE
- || cursor->rel_pos == BTR_PCUR_BEFORE_FIRST_IN_TREE)) {
+ if (UNIV_UNLIKELY
+ (cursor->rel_pos == BTR_PCUR_AFTER_LAST_IN_TREE
+ || cursor->rel_pos == BTR_PCUR_BEFORE_FIRST_IN_TREE)) {
/* In these cases we do not try an optimistic restoration,
but always do a search */
@@ -228,8 +242,7 @@ btr_pcur_restore_position(
cursor->rel_pos == BTR_PCUR_BEFORE_FIRST_IN_TREE,
index, latch_mode, btr_pcur_get_btr_cur(cursor), mtr);
- cursor->block_when_stored
- = buf_block_align(btr_pcur_get_page(cursor));
+ cursor->block_when_stored = btr_pcur_get_block(cursor);
return(FALSE);
}
@@ -237,25 +250,24 @@ btr_pcur_restore_position(
ut_a(cursor->old_rec);
ut_a(cursor->old_n_fields);
- page = btr_cur_get_page(btr_pcur_get_btr_cur(cursor));
-
if (UNIV_LIKELY(latch_mode == BTR_SEARCH_LEAF)
|| UNIV_LIKELY(latch_mode == BTR_MODIFY_LEAF)) {
/* Try optimistic restoration */
if (UNIV_LIKELY(buf_page_optimistic_get(
latch_mode,
- cursor->block_when_stored, page,
+ cursor->block_when_stored,
cursor->modify_clock, mtr))) {
cursor->pos_state = BTR_PCUR_IS_POSITIONED;
-#ifdef UNIV_SYNC_DEBUG
- buf_page_dbg_add_level(page, SYNC_TREE_NODE);
-#endif /* UNIV_SYNC_DEBUG */
+
+ buf_block_dbg_add_level(btr_pcur_get_block(cursor),
+ SYNC_TREE_NODE);
+
if (cursor->rel_pos == BTR_PCUR_ON) {
#ifdef UNIV_DEBUG
- rec_t* rec;
- ulint* offsets1;
- ulint* offsets2;
+ const rec_t* rec;
+ const ulint* offsets1;
+ const ulint* offsets2;
#endif /* UNIV_DEBUG */
cursor->latch_mode = latch_mode;
#ifdef UNIV_DEBUG
@@ -307,7 +319,7 @@ btr_pcur_restore_position(
cursor->search_mode = old_mode;
if (cursor->rel_pos == BTR_PCUR_ON
- && btr_pcur_is_on_user_rec(cursor, mtr)
+ && btr_pcur_is_on_user_rec(cursor)
&& 0 == cmp_dtuple_rec(tuple, btr_pcur_get_rec(cursor),
rec_get_offsets(
btr_pcur_get_rec(cursor), index,
@@ -317,8 +329,7 @@ btr_pcur_restore_position(
the cursor can now be on a different page! But we can retain
the value of old_rec */
- cursor->block_when_stored = buf_block_align(
- btr_pcur_get_page(cursor));
+ cursor->block_when_stored = btr_pcur_get_block(cursor);
cursor->modify_clock = buf_block_get_modify_clock(
cursor->block_when_stored);
cursor->old_stored = BTR_PCUR_OLD_STORED;
@@ -339,79 +350,85 @@ btr_pcur_restore_position(
return(FALSE);
}
-/******************************************************************
+/**************************************************************//**
If the latch mode of the cursor is BTR_LEAF_SEARCH or BTR_LEAF_MODIFY,
releases the page latch and bufferfix reserved by the cursor.
NOTE! In the case of BTR_LEAF_MODIFY, there should not exist changes
made by the current mini-transaction to the data protected by the
cursor latch, as then the latch must not be released until mtr_commit. */
-
+UNIV_INTERN
void
btr_pcur_release_leaf(
/*==================*/
- btr_pcur_t* cursor, /* in: persistent cursor */
- mtr_t* mtr) /* in: mtr */
+ btr_pcur_t* cursor, /*!< in: persistent cursor */
+ mtr_t* mtr) /*!< in: mtr */
{
- page_t* page;
+ buf_block_t* block;
ut_a(cursor->pos_state == BTR_PCUR_IS_POSITIONED);
ut_ad(cursor->latch_mode != BTR_NO_LATCHES);
- page = btr_cur_get_page(btr_pcur_get_btr_cur(cursor));
+ block = btr_pcur_get_block(cursor);
- btr_leaf_page_release(page, cursor->latch_mode, mtr);
+ btr_leaf_page_release(block, cursor->latch_mode, mtr);
cursor->latch_mode = BTR_NO_LATCHES;
cursor->pos_state = BTR_PCUR_WAS_POSITIONED;
}
-/*************************************************************
+/*********************************************************//**
Moves the persistent cursor to the first record on the next page. Releases the
latch on the current page, and bufferunfixes it. Note that there must not be
modifications on the current page, as then the x-latch can be released only in
mtr_commit. */
-
+UNIV_INTERN
void
btr_pcur_move_to_next_page(
/*=======================*/
- btr_pcur_t* cursor, /* in: persistent cursor; must be on the
+ btr_pcur_t* cursor, /*!< in: persistent cursor; must be on the
last record of the current page */
- mtr_t* mtr) /* in: mtr */
+ mtr_t* mtr) /*!< in: mtr */
{
- ulint next_page_no;
- ulint space;
- page_t* page;
- page_t* next_page;
+ ulint next_page_no;
+ ulint space;
+ ulint zip_size;
+ page_t* page;
+ buf_block_t* next_block;
+ page_t* next_page;
ut_a(cursor->pos_state == BTR_PCUR_IS_POSITIONED);
ut_ad(cursor->latch_mode != BTR_NO_LATCHES);
- ut_ad(btr_pcur_is_after_last_on_page(cursor, mtr));
+ ut_ad(btr_pcur_is_after_last_on_page(cursor));
cursor->old_stored = BTR_PCUR_OLD_NOT_STORED;
page = btr_pcur_get_page(cursor);
-
next_page_no = btr_page_get_next(page, mtr);
- space = buf_frame_get_space_id(page);
+ space = buf_block_get_space(btr_pcur_get_block(cursor));
+ zip_size = buf_block_get_zip_size(btr_pcur_get_block(cursor));
ut_ad(next_page_no != FIL_NULL);
- next_page = btr_page_get(space, next_page_no, cursor->latch_mode, mtr);
+ next_block = btr_block_get(space, zip_size, next_page_no,
+ cursor->latch_mode, mtr);
+ next_page = buf_block_get_frame(next_block);
#ifdef UNIV_BTR_DEBUG
- ut_a(btr_page_get_prev(next_page, mtr) == buf_frame_get_page_no(page));
-#endif /* UNIV_BTR_DEBUG */
ut_a(page_is_comp(next_page) == page_is_comp(page));
- buf_block_align(next_page)->check_index_page_at_flush = TRUE;
+ ut_a(btr_page_get_prev(next_page, mtr)
+ == buf_block_get_page_no(btr_pcur_get_block(cursor)));
+#endif /* UNIV_BTR_DEBUG */
+ next_block->check_index_page_at_flush = TRUE;
- btr_leaf_page_release(page, cursor->latch_mode, mtr);
+ btr_leaf_page_release(btr_pcur_get_block(cursor),
+ cursor->latch_mode, mtr);
- page_cur_set_before_first(next_page, btr_pcur_get_page_cur(cursor));
+ page_cur_set_before_first(next_block, btr_pcur_get_page_cur(cursor));
page_check_dir(next_page);
}
-/*************************************************************
+/*********************************************************//**
Moves the persistent cursor backward if it is on the first record of the page.
Commits mtr. Note that to prevent a possible deadlock, the operation
first stores the position of the cursor, commits mtr, acquires the necessary
@@ -420,24 +437,24 @@ alphabetical position of the cursor is guaranteed to be sensible on
return, but it may happen that the cursor is not positioned on the last
record of any page, because the structure of the tree may have changed
during the time when the cursor had no latches. */
-
+UNIV_INTERN
void
btr_pcur_move_backward_from_page(
/*=============================*/
- btr_pcur_t* cursor, /* in: persistent cursor, must be on the first
+ btr_pcur_t* cursor, /*!< in: persistent cursor, must be on the first
record of the current page */
- mtr_t* mtr) /* in: mtr */
+ mtr_t* mtr) /*!< in: mtr */
{
- ulint prev_page_no;
- ulint space;
- page_t* page;
- page_t* prev_page;
- ulint latch_mode;
- ulint latch_mode2;
+ ulint prev_page_no;
+ ulint space;
+ page_t* page;
+ buf_block_t* prev_block;
+ ulint latch_mode;
+ ulint latch_mode2;
ut_a(cursor->pos_state == BTR_PCUR_IS_POSITIONED);
ut_ad(cursor->latch_mode != BTR_NO_LATCHES);
- ut_ad(btr_pcur_is_before_first_on_page(cursor, mtr));
+ ut_ad(btr_pcur_is_before_first_on_page(cursor));
ut_ad(!btr_pcur_is_before_first_in_tree(cursor, mtr));
latch_mode = cursor->latch_mode;
@@ -465,26 +482,27 @@ btr_pcur_move_backward_from_page(
page = btr_pcur_get_page(cursor);
prev_page_no = btr_page_get_prev(page, mtr);
- space = buf_frame_get_space_id(page);
+ space = buf_block_get_space(btr_pcur_get_block(cursor));
- if (btr_pcur_is_before_first_on_page(cursor, mtr)
- && (prev_page_no != FIL_NULL)) {
+ if (prev_page_no == FIL_NULL) {
+ } else if (btr_pcur_is_before_first_on_page(cursor)) {
- prev_page = btr_pcur_get_btr_cur(cursor)->left_page;
+ prev_block = btr_pcur_get_btr_cur(cursor)->left_block;
- btr_leaf_page_release(page, latch_mode, mtr);
+ btr_leaf_page_release(btr_pcur_get_block(cursor),
+ latch_mode, mtr);
- page_cur_set_after_last(prev_page,
+ page_cur_set_after_last(prev_block,
btr_pcur_get_page_cur(cursor));
- } else if (prev_page_no != FIL_NULL) {
+ } else {
/* The repositioned cursor did not end on an infimum record on
a page. Cursor repositioning acquired a latch also on the
previous page, but we do not need the latch: release it. */
- prev_page = btr_pcur_get_btr_cur(cursor)->left_page;
+ prev_block = btr_pcur_get_btr_cur(cursor)->left_block;
- btr_leaf_page_release(prev_page, latch_mode, mtr);
+ btr_leaf_page_release(prev_block, latch_mode, mtr);
}
cursor->latch_mode = latch_mode;
@@ -492,25 +510,24 @@ btr_pcur_move_backward_from_page(
cursor->old_stored = BTR_PCUR_OLD_NOT_STORED;
}
-/*************************************************************
+/*********************************************************//**
Moves the persistent cursor to the previous record in the tree. If no records
-are left, the cursor stays 'before first in tree'. */
-
+are left, the cursor stays 'before first in tree'.
+@return TRUE if the cursor was not before first in tree */
+UNIV_INTERN
ibool
btr_pcur_move_to_prev(
/*==================*/
- /* out: TRUE if the cursor was not before first
- in tree */
- btr_pcur_t* cursor, /* in: persistent cursor; NOTE that the
+ btr_pcur_t* cursor, /*!< in: persistent cursor; NOTE that the
function may release the page latch */
- mtr_t* mtr) /* in: mtr */
+ mtr_t* mtr) /*!< in: mtr */
{
ut_ad(cursor->pos_state == BTR_PCUR_IS_POSITIONED);
ut_ad(cursor->latch_mode != BTR_NO_LATCHES);
cursor->old_stored = BTR_PCUR_OLD_NOT_STORED;
- if (btr_pcur_is_before_first_on_page(cursor, mtr)) {
+ if (btr_pcur_is_before_first_on_page(cursor)) {
if (btr_pcur_is_before_first_in_tree(cursor, mtr)) {
@@ -522,36 +539,36 @@ btr_pcur_move_to_prev(
return(TRUE);
}
- btr_pcur_move_to_prev_on_page(cursor, mtr);
+ btr_pcur_move_to_prev_on_page(cursor);
return(TRUE);
}
-/******************************************************************
+/**************************************************************//**
If mode is PAGE_CUR_G or PAGE_CUR_GE, opens a persistent cursor on the first
user record satisfying the search condition, in the case PAGE_CUR_L or
PAGE_CUR_LE, on the last user record. If no such user record exists, then
in the first case sets the cursor after last in tree, and in the latter case
before first in tree. The latching mode must be BTR_SEARCH_LEAF or
BTR_MODIFY_LEAF. */
-
+UNIV_INTERN
void
btr_pcur_open_on_user_rec(
/*======================*/
- dict_index_t* index, /* in: index */
- dtuple_t* tuple, /* in: tuple on which search done */
- ulint mode, /* in: PAGE_CUR_L, ... */
- ulint latch_mode, /* in: BTR_SEARCH_LEAF or
+ dict_index_t* index, /*!< in: index */
+ const dtuple_t* tuple, /*!< in: tuple on which search done */
+ ulint mode, /*!< in: PAGE_CUR_L, ... */
+ ulint latch_mode, /*!< in: BTR_SEARCH_LEAF or
BTR_MODIFY_LEAF */
- btr_pcur_t* cursor, /* in: memory buffer for persistent
+ btr_pcur_t* cursor, /*!< in: memory buffer for persistent
cursor */
- mtr_t* mtr) /* in: mtr */
+ mtr_t* mtr) /*!< in: mtr */
{
btr_pcur_open(index, tuple, mode, latch_mode, cursor, mtr);
if ((mode == PAGE_CUR_GE) || (mode == PAGE_CUR_G)) {
- if (btr_pcur_is_after_last_on_page(cursor, mtr)) {
+ if (btr_pcur_is_after_last_on_page(cursor)) {
btr_pcur_move_to_next_user_rec(cursor, mtr);
}
diff --git a/storage/innobase/btr/btr0sea.c b/storage/innodb_plugin/btr/btr0sea.c
similarity index 75%
rename from storage/innobase/btr/btr0sea.c
rename to storage/innodb_plugin/btr/btr0sea.c
index 8d296fdd061..faa1c13897e 100644
--- a/storage/innobase/btr/btr0sea.c
+++ b/storage/innodb_plugin/btr/btr0sea.c
@@ -1,7 +1,31 @@
-/************************************************************************
-The index tree adaptive search
+/*****************************************************************************
-(c) 1996 Innobase Oy
+Copyright (c) 1996, 2009, Innobase Oy. All Rights Reserved.
+Copyright (c) 2008, Google Inc.
+
+Portions of this file contain modifications contributed and copyrighted by
+Google, Inc. Those modifications are gratefully acknowledged and are described
+briefly in the InnoDB documentation. The contributions by Google are
+incorporated with their permission, and subject to the conditions contained in
+the file COPYING.Google.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; version 2 of the License.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place, Suite 330, Boston, MA 02111-1307 USA
+
+*****************************************************************************/
+
+/********************************************************************//**
+@file btr/btr0sea.c
+The index tree adaptive search
Created 2/17/1996 Heikki Tuuri
*************************************************************************/
@@ -19,47 +43,55 @@ Created 2/17/1996 Heikki Tuuri
#include "btr0btr.h"
#include "ha0ha.h"
-ulint btr_search_this_is_zero = 0; /* A dummy variable to fool the
- compiler */
+/** Flag: has the search system been enabled?
+Protected by btr_search_latch and btr_search_enabled_mutex. */
+UNIV_INTERN char btr_search_enabled = TRUE;
+
+/** Mutex protecting btr_search_enabled */
+static mutex_t btr_search_enabled_mutex;
+
+/** A dummy variable to fool the compiler */
+UNIV_INTERN ulint btr_search_this_is_zero = 0;
#ifdef UNIV_SEARCH_PERF_STAT
-ulint btr_search_n_succ = 0;
-ulint btr_search_n_hash_fail = 0;
+/** Number of successful adaptive hash index lookups */
+UNIV_INTERN ulint btr_search_n_succ = 0;
+/** Number of failed adaptive hash index lookups */
+UNIV_INTERN ulint btr_search_n_hash_fail = 0;
#endif /* UNIV_SEARCH_PERF_STAT */
-byte btr_sea_pad1[64]; /* padding to prevent other memory update
- hotspots from residing on the same memory
- cache line as btr_search_latch */
+/** padding to prevent other memory update
+hotspots from residing on the same memory
+cache line as btr_search_latch */
+UNIV_INTERN byte btr_sea_pad1[64];
-/* The latch protecting the adaptive search system: this latch protects the
+/** The latch protecting the adaptive search system: this latch protects the
(1) positions of records on those pages where a hash index has been built.
NOTE: It does not protect values of non-ordering fields within a record from
being updated in-place! We can use fact (1) to perform unique searches to
indexes. */
-rw_lock_t* btr_search_latch_temp; /* We will allocate the latch from
- dynamic memory to get it to the
- same DRAM page as other hotspot
- semaphores */
+/* We will allocate the latch from dynamic memory to get it to the
+same DRAM page as other hotspot semaphores */
+UNIV_INTERN rw_lock_t* btr_search_latch_temp;
-byte btr_sea_pad2[64]; /* padding to prevent other memory update
- hotspots from residing on the same memory
- cache line */
+/** padding to prevent other memory update hotspots from residing on
+the same memory cache line */
+UNIV_INTERN byte btr_sea_pad2[64];
-btr_search_sys_t* btr_search_sys;
+/** The adaptive hash index */
+UNIV_INTERN btr_search_sys_t* btr_search_sys;
-/* If the number of records on the page divided by this parameter
+/** If the number of records on the page divided by this parameter
would have been successfully accessed using a hash index, the index
is then built on the page, assuming the global limit has been reached */
-
#define BTR_SEARCH_PAGE_BUILD_LIMIT 16
-/* The global limit for consecutive potentially successful hash searches,
+/** The global limit for consecutive potentially successful hash searches,
before hash index building is started */
-
#define BTR_SEARCH_BUILD_LIMIT 100
-/************************************************************************
+/********************************************************************//**
Builds a hash index on a page with the given parameters. If the page already
has a hash index with different parameters, the old hash index is removed.
If index is non-NULL, this function checks if n_fields and n_bytes are
@@ -68,15 +100,15 @@ static
void
btr_search_build_page_hash_index(
/*=============================*/
- dict_index_t* index, /* in: index for which to build, or NULL if
+ dict_index_t* index, /*!< in: index for which to build, or NULL if
not known */
- page_t* page, /* in: index page, s- or x-latched */
- ulint n_fields,/* in: hash this many full fields */
- ulint n_bytes,/* in: hash this many bytes from the next
+ buf_block_t* block, /*!< in: index page, s- or x-latched */
+ ulint n_fields,/*!< in: hash this many full fields */
+ ulint n_bytes,/*!< in: hash this many bytes from the next
field */
- ibool left_side);/* in: hash for searches from left side? */
+ ibool left_side);/*!< in: hash for searches from left side? */
-/*********************************************************************
+/*****************************************************************//**
This function should be called before reserving any btr search mutex, if
the intended operation might add nodes to the search system hash table.
Because of the latching order, once we have reserved the btr search system
@@ -91,7 +123,6 @@ void
btr_search_check_free_space_in_heap(void)
/*=====================================*/
{
- buf_frame_t* frame;
hash_table_t* table;
mem_heap_t* heap;
@@ -109,27 +140,27 @@ btr_search_check_free_space_in_heap(void)
be enough free space in the hash table. */
if (heap->free_block == NULL) {
- frame = buf_frame_alloc();
+ buf_block_t* block = buf_block_alloc(0);
rw_lock_x_lock(&btr_search_latch);
if (heap->free_block == NULL) {
- heap->free_block = frame;
+ heap->free_block = block;
} else {
- buf_frame_free(frame);
+ buf_block_free(block);
}
rw_lock_x_unlock(&btr_search_latch);
}
}
-/*********************************************************************
+/*****************************************************************//**
Creates and initializes the adaptive search system at a database start. */
-
+UNIV_INTERN
void
btr_search_sys_create(
/*==================*/
- ulint hash_size) /* in: hash index hash table size */
+ ulint hash_size) /*!< in: hash index hash table size */
{
/* We allocate the search latch from dynamic memory:
see above at the global variable definition */
@@ -137,21 +168,60 @@ btr_search_sys_create(
btr_search_latch_temp = mem_alloc(sizeof(rw_lock_t));
rw_lock_create(&btr_search_latch, SYNC_SEARCH_SYS);
+ mutex_create(&btr_search_enabled_mutex, SYNC_SEARCH_SYS_CONF);
btr_search_sys = mem_alloc(sizeof(btr_search_sys_t));
- btr_search_sys->hash_index = ha_create(TRUE, hash_size, 0, 0);
-
+ btr_search_sys->hash_index = ha_create(hash_size, 0, 0);
}
-/*********************************************************************
-Creates and initializes a search info struct. */
+/********************************************************************//**
+Disable the adaptive hash search system and empty the index. */
+UNIV_INTERN
+void
+btr_search_disable(void)
+/*====================*/
+{
+ mutex_enter(&btr_search_enabled_mutex);
+ rw_lock_x_lock(&btr_search_latch);
+ btr_search_enabled = FALSE;
+
+ /* Clear all block->is_hashed flags and remove all entries
+ from btr_search_sys->hash_index. */
+ buf_pool_drop_hash_index();
+
+ /* btr_search_enabled_mutex should guarantee this. */
+ ut_ad(!btr_search_enabled);
+
+ rw_lock_x_unlock(&btr_search_latch);
+ mutex_exit(&btr_search_enabled_mutex);
+}
+
+/********************************************************************//**
+Enable the adaptive hash search system. */
+UNIV_INTERN
+void
+btr_search_enable(void)
+/*====================*/
+{
+ mutex_enter(&btr_search_enabled_mutex);
+ rw_lock_x_lock(&btr_search_latch);
+
+ btr_search_enabled = TRUE;
+
+ rw_lock_x_unlock(&btr_search_latch);
+ mutex_exit(&btr_search_enabled_mutex);
+}
+
+/*****************************************************************//**
+Creates and initializes a search info struct.
+@return own: search info struct */
+UNIV_INTERN
btr_search_t*
btr_search_info_create(
/*===================*/
- /* out, own: search info struct */
- mem_heap_t* heap) /* in: heap where created */
+ mem_heap_t* heap) /*!< in: heap where created */
{
btr_search_t* info;
@@ -185,14 +255,15 @@ btr_search_info_create(
return(info);
}
-/*********************************************************************
+/*****************************************************************//**
Returns the value of ref_count. The value is protected by
-btr_search_latch. */
+btr_search_latch.
+@return ref_count value. */
+UNIV_INTERN
ulint
btr_search_info_get_ref_count(
/*==========================*/
- /* out: ref_count value. */
- btr_search_t* info) /* in: search info. */
+ btr_search_t* info) /*!< in: search info. */
{
ulint ret;
@@ -210,7 +281,7 @@ btr_search_info_get_ref_count(
return(ret);
}
-/*************************************************************************
+/*********************************************************************//**
Updates the search info of an index about hash successes. NOTE that info
is NOT protected by any semaphore, to save CPU time! Do not assume its fields
are consistent. */
@@ -218,8 +289,8 @@ static
void
btr_search_info_update_hash(
/*========================*/
- btr_search_t* info, /* in/out: search info */
- btr_cur_t* cursor) /* in: cursor which was just positioned */
+ btr_search_t* info, /*!< in/out: search info */
+ btr_cur_t* cursor) /*!< in: cursor which was just positioned */
{
dict_index_t* index;
ulint n_unique;
@@ -232,7 +303,7 @@ btr_search_info_update_hash(
index = cursor->index;
- if (index->type & DICT_IBUF) {
+ if (dict_index_is_ibuf(index)) {
/* So many deletes are performed on an insert buffer tree
that we do not consider a hash index useful on it: */
@@ -330,32 +401,31 @@ set_new_recomm:
}
}
-/*************************************************************************
+/*********************************************************************//**
Updates the block search info on hash successes. NOTE that info and
block->n_hash_helps, n_fields, n_bytes, side are NOT protected by any
-semaphore, to save CPU time! Do not assume the fields are consistent. */
+semaphore, to save CPU time! Do not assume the fields are consistent.
+@return TRUE if building a (new) hash index on the block is recommended */
static
ibool
btr_search_update_block_hash_info(
/*==============================*/
- /* out: TRUE if building a (new) hash index on
- the block is recommended */
- btr_search_t* info, /* in: search info */
- buf_block_t* block, /* in: buffer block */
+ btr_search_t* info, /*!< in: search info */
+ buf_block_t* block, /*!< in: buffer block */
btr_cur_t* cursor __attribute__((unused)))
- /* in: cursor */
+ /*!< in: cursor */
{
#ifdef UNIV_SYNC_DEBUG
ut_ad(!rw_lock_own(&btr_search_latch, RW_LOCK_SHARED));
ut_ad(!rw_lock_own(&btr_search_latch, RW_LOCK_EX));
- ut_ad(rw_lock_own(&((buf_block_t*) block)->lock, RW_LOCK_SHARED)
- || rw_lock_own(&((buf_block_t*) block)->lock, RW_LOCK_EX));
+ ut_ad(rw_lock_own(&block->lock, RW_LOCK_SHARED)
+ || rw_lock_own(&block->lock, RW_LOCK_EX));
#endif /* UNIV_SYNC_DEBUG */
ut_ad(cursor);
info->last_hash_succ = FALSE;
- ut_a(block->magic_n == BUF_BLOCK_MAGIC_N);
+ ut_a(buf_block_state_valid(block));
ut_ad(info->magic_n == BTR_SEARCH_MAGIC_N);
if ((block->n_hash_helps > 0)
@@ -409,7 +479,7 @@ btr_search_update_block_hash_info(
return(FALSE);
}
-/*************************************************************************
+/*********************************************************************//**
Updates a hash node reference when it has been unsuccessfully used in a
search which could have succeeded with the used hash parameters. This can
happen because when building a hash index for a page, we do not check
@@ -421,9 +491,9 @@ static
void
btr_search_update_hash_ref(
/*=======================*/
- btr_search_t* info, /* in: search info */
- buf_block_t* block, /* in: buffer block where cursor positioned */
- btr_cur_t* cursor) /* in: cursor */
+ btr_search_t* info, /*!< in: search info */
+ buf_block_t* block, /*!< in: buffer block where cursor positioned */
+ btr_cur_t* cursor) /*!< in: cursor */
{
ulint fold;
rec_t* rec;
@@ -435,17 +505,24 @@ btr_search_update_hash_ref(
ut_ad(rw_lock_own(&(block->lock), RW_LOCK_SHARED)
|| rw_lock_own(&(block->lock), RW_LOCK_EX));
#endif /* UNIV_SYNC_DEBUG */
- ut_ad(buf_block_align(btr_cur_get_rec(cursor)) == block);
- ut_a(!block->is_hashed || block->index == cursor->index);
+ ut_ad(page_align(btr_cur_get_rec(cursor))
+ == buf_block_get_frame(block));
- if (block->is_hashed
- && (info->n_hash_potential > 0)
+ if (!block->is_hashed) {
+
+ return;
+ }
+
+ ut_a(block->index == cursor->index);
+ ut_a(!dict_index_is_ibuf(cursor->index));
+
+ if ((info->n_hash_potential > 0)
&& (block->curr_n_fields == info->n_fields)
&& (block->curr_n_bytes == info->n_bytes)
&& (block->curr_left_side == info->left_side)) {
mem_heap_t* heap = NULL;
ulint offsets_[REC_OFFS_NORMAL_SIZE];
- *offsets_ = (sizeof offsets_) / sizeof *offsets_;
+ rec_offs_init(offsets_);
rec = btr_cur_get_rec(cursor);
@@ -467,18 +544,19 @@ btr_search_update_hash_ref(
ut_ad(rw_lock_own(&btr_search_latch, RW_LOCK_EX));
#endif /* UNIV_SYNC_DEBUG */
- ha_insert_for_fold(btr_search_sys->hash_index, fold, rec);
+ ha_insert_for_fold(btr_search_sys->hash_index, fold,
+ block, rec);
}
}
-/*************************************************************************
+/*********************************************************************//**
Updates the search info. */
-
+UNIV_INTERN
void
btr_search_info_update_slow(
/*========================*/
- btr_search_t* info, /* in/out: search info */
- btr_cur_t* cursor) /* in: cursor which was just positioned */
+ btr_search_t* info, /*!< in/out: search info */
+ btr_cur_t* cursor) /*!< in: cursor which was just positioned */
{
buf_block_t* block;
ibool build_index;
@@ -490,7 +568,7 @@ btr_search_info_update_slow(
ut_ad(!rw_lock_own(&btr_search_latch, RW_LOCK_EX));
#endif /* UNIV_SYNC_DEBUG */
- block = buf_block_align(btr_cur_get_rec(cursor));
+ block = btr_cur_get_block(cursor);
/* NOTE that the following two function calls do NOT protect
info or block->n_fields etc. with any semaphore, to save CPU time!
@@ -540,7 +618,7 @@ btr_search_info_update_slow(
params2 = params + btr_search_this_is_zero;
btr_search_build_page_hash_index(cursor->index,
- block->frame,
+ block,
params2[0],
params2[1],
params2[2]);
@@ -548,28 +626,28 @@ btr_search_info_update_slow(
}
}
-/**********************************************************************
+/******************************************************************//**
Checks if a guessed position for a tree cursor is right. Note that if
mode is PAGE_CUR_LE, which is used in inserts, and the function returns
-TRUE, then cursor->up_match and cursor->low_match both have sensible values. */
+TRUE, then cursor->up_match and cursor->low_match both have sensible values.
+@return TRUE if success */
static
ibool
btr_search_check_guess(
/*===================*/
- /* out: TRUE if success */
- btr_cur_t* cursor, /* in: guessed cursor position */
+ btr_cur_t* cursor, /*!< in: guessed cursor position */
ibool can_only_compare_to_cursor_rec,
- /* in: if we do not have a latch on the page
+ /*!< in: if we do not have a latch on the page
of cursor, but only a latch on
btr_search_latch, then ONLY the columns
of the record UNDER the cursor are
protected, not the next or previous record
in the chain: we cannot look at the next or
previous record to check our guess! */
- dtuple_t* tuple, /* in: data tuple */
- ulint mode, /* in: PAGE_CUR_L, PAGE_CUR_LE, PAGE_CUR_G,
+ const dtuple_t* tuple, /*!< in: data tuple */
+ ulint mode, /*!< in: PAGE_CUR_L, PAGE_CUR_LE, PAGE_CUR_G,
or PAGE_CUR_GE */
- mtr_t* mtr) /* in: mtr */
+ mtr_t* mtr) /*!< in: mtr */
{
rec_t* rec;
ulint n_unique;
@@ -580,7 +658,7 @@ btr_search_check_guess(
ulint offsets_[REC_OFFS_NORMAL_SIZE];
ulint* offsets = offsets_;
ibool success = FALSE;
- *offsets_ = (sizeof offsets_) / sizeof *offsets_;
+ rec_offs_init(offsets_);
n_unique = dict_index_get_n_unique_in_tree(cursor->index);
@@ -641,8 +719,8 @@ btr_search_check_guess(
prev_rec = page_rec_get_prev(rec);
if (page_rec_is_infimum(prev_rec)) {
- success = btr_page_get_prev(
- buf_frame_align(prev_rec), mtr) == FIL_NULL;
+ success = btr_page_get_prev(page_align(prev_rec), mtr)
+ == FIL_NULL;
goto exit_func;
}
@@ -666,8 +744,7 @@ btr_search_check_guess(
next_rec = page_rec_get_next(rec);
if (page_rec_is_supremum(next_rec)) {
- if (btr_page_get_next(
- buf_frame_align(next_rec), mtr)
+ if (btr_page_get_next(page_align(next_rec), mtr)
== FIL_NULL) {
cursor->up_match = 0;
@@ -695,39 +772,36 @@ exit_func:
return(success);
}
-/**********************************************************************
+/******************************************************************//**
Tries to guess the right search position based on the hash search info
of the index. Note that if mode is PAGE_CUR_LE, which is used in inserts,
and the function returns TRUE, then cursor->up_match and cursor->low_match
-both have sensible values. */
-
+both have sensible values.
+@return TRUE if succeeded */
+UNIV_INTERN
ibool
btr_search_guess_on_hash(
/*=====================*/
- /* out: TRUE if succeeded */
- dict_index_t* index, /* in: index */
- btr_search_t* info, /* in: index search info */
- dtuple_t* tuple, /* in: logical record */
- ulint mode, /* in: PAGE_CUR_L, ... */
- ulint latch_mode, /* in: BTR_SEARCH_LEAF, ...;
+ dict_index_t* index, /*!< in: index */
+ btr_search_t* info, /*!< in: index search info */
+ const dtuple_t* tuple, /*!< in: logical record */
+ ulint mode, /*!< in: PAGE_CUR_L, ... */
+ ulint latch_mode, /*!< in: BTR_SEARCH_LEAF, ...;
NOTE that only if has_search_latch
is 0, we will have a latch set on
the cursor page, otherwise we assume
the caller uses his search latch
to protect the record! */
- btr_cur_t* cursor, /* out: tree cursor */
- ulint has_search_latch,/* in: latch mode the caller
+ btr_cur_t* cursor, /*!< out: tree cursor */
+ ulint has_search_latch,/*!< in: latch mode the caller
currently has on btr_search_latch:
RW_S_LATCH, RW_X_LATCH, or 0 */
- mtr_t* mtr) /* in: mtr */
+ mtr_t* mtr) /*!< in: mtr */
{
buf_block_t* block;
rec_t* rec;
- page_t* page;
ulint fold;
- ulint tuple_n_fields;
dulint index_id;
- ibool can_only_compare_to_cursor_rec = TRUE;
#ifdef notdefined
btr_cur_t cursor2;
btr_pcur_t pcur;
@@ -747,15 +821,8 @@ btr_search_guess_on_hash(
cursor->n_fields = info->n_fields;
cursor->n_bytes = info->n_bytes;
- tuple_n_fields = dtuple_get_n_fields(tuple);
-
- if (UNIV_UNLIKELY(tuple_n_fields < cursor->n_fields)) {
-
- return(FALSE);
- }
-
- if (UNIV_UNLIKELY(tuple_n_fields == cursor->n_fields)
- && (cursor->n_bytes > 0)) {
+ if (UNIV_UNLIKELY(dtuple_get_n_fields(tuple)
+ < cursor->n_fields + (cursor->n_bytes > 0))) {
return(FALSE);
}
@@ -772,6 +839,10 @@ btr_search_guess_on_hash(
if (UNIV_LIKELY(!has_search_latch)) {
rw_lock_s_lock(&btr_search_latch);
+
+ if (UNIV_UNLIKELY(!btr_search_enabled)) {
+ goto failure_unlock;
+ }
}
ut_ad(rw_lock_get_writer(&btr_search_latch) != RW_LOCK_EX);
@@ -783,12 +854,12 @@ btr_search_guess_on_hash(
goto failure_unlock;
}
- page = buf_frame_align(rec);
+ block = buf_block_align(rec);
if (UNIV_LIKELY(!has_search_latch)) {
if (UNIV_UNLIKELY(
- !buf_page_get_known_nowait(latch_mode, page,
+ !buf_page_get_known_nowait(latch_mode, block,
BUF_MAKE_YOUNG,
__FILE__, __LINE__,
mtr))) {
@@ -796,28 +867,24 @@ btr_search_guess_on_hash(
}
rw_lock_s_unlock(&btr_search_latch);
- can_only_compare_to_cursor_rec = FALSE;
-#ifdef UNIV_SYNC_DEBUG
- buf_page_dbg_add_level(page, SYNC_TREE_NODE_FROM_HASH);
-#endif /* UNIV_SYNC_DEBUG */
+ buf_block_dbg_add_level(block, SYNC_TREE_NODE_FROM_HASH);
}
- block = buf_block_align(page);
+ if (UNIV_UNLIKELY(buf_block_get_state(block) != BUF_BLOCK_FILE_PAGE)) {
+ ut_ad(buf_block_get_state(block) == BUF_BLOCK_REMOVE_HASH);
- if (UNIV_UNLIKELY(block->state == BUF_BLOCK_REMOVE_HASH)) {
if (UNIV_LIKELY(!has_search_latch)) {
- btr_leaf_page_release(page, latch_mode, mtr);
+ btr_leaf_page_release(block, latch_mode, mtr);
}
goto failure;
}
- ut_ad(block->state == BUF_BLOCK_FILE_PAGE);
ut_ad(page_rec_is_user_rec(rec));
- btr_cur_position(index, rec, cursor);
+ btr_cur_position(index, rec, block, cursor);
/* Check the validity of the guess within the page */
@@ -826,13 +893,13 @@ btr_search_guess_on_hash(
is positioned on. We cannot look at the next of the previous
record to determine if our guess for the cursor position is
right. */
- if (UNIV_EXPECT(
- ut_dulint_cmp(index_id, btr_page_get_index_id(page)), 0)
+ if (UNIV_EXPECT
+ (ut_dulint_cmp(index_id, btr_page_get_index_id(block->frame)), 0)
|| !btr_search_check_guess(cursor,
- can_only_compare_to_cursor_rec,
+ has_search_latch,
tuple, mode, mtr)) {
if (UNIV_LIKELY(!has_search_latch)) {
- btr_leaf_page_release(page, latch_mode, mtr);
+ btr_leaf_page_release(block, latch_mode, mtr);
}
goto failure;
@@ -852,7 +919,7 @@ btr_search_guess_on_hash(
/* Currently, does not work if the following fails: */
ut_ad(!has_search_latch);
- btr_leaf_page_release(page, latch_mode, mtr);
+ btr_leaf_page_release(block, latch_mode, mtr);
btr_cur_search_to_nth_level(index, 0, tuple, mode, latch_mode,
&cursor2, 0, mtr);
@@ -882,9 +949,9 @@ 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(page);
+ buf_page_make_young(&block->page);
}
/* Increment the page get statistics though we did not really
@@ -914,39 +981,41 @@ failure:
return(FALSE);
}
-/************************************************************************
+/********************************************************************//**
Drops a page hash index. */
-
+UNIV_INTERN
void
btr_search_drop_page_hash_index(
/*============================*/
- page_t* page) /* in: index page, s- or x-latched, or an index page
- for which we know that block->buf_fix_count == 0 */
+ buf_block_t* block) /*!< in: block containing index page,
+ s- or x-latched, or an index page
+ for which we know that
+ block->buf_fix_count == 0 */
{
- hash_table_t* table;
- buf_block_t* block;
- ulint n_fields;
- ulint n_bytes;
- rec_t* rec;
- ulint fold;
- ulint prev_fold;
- dulint index_id;
- ulint n_cached;
- ulint n_recs;
- ulint* folds;
- ulint i;
- mem_heap_t* heap;
- dict_index_t* index;
- ulint* offsets;
+ hash_table_t* table;
+ ulint n_fields;
+ ulint n_bytes;
+ const page_t* page;
+ const rec_t* rec;
+ ulint fold;
+ ulint prev_fold;
+ dulint index_id;
+ ulint n_cached;
+ ulint n_recs;
+ ulint* folds;
+ ulint i;
+ mem_heap_t* heap;
+ const dict_index_t* index;
+ ulint* offsets;
#ifdef UNIV_SYNC_DEBUG
ut_ad(!rw_lock_own(&btr_search_latch, RW_LOCK_SHARED));
ut_ad(!rw_lock_own(&btr_search_latch, RW_LOCK_EX));
#endif /* UNIV_SYNC_DEBUG */
+
retry:
rw_lock_s_lock(&btr_search_latch);
-
- block = buf_block_align(page);
+ page = block->frame;
if (UNIV_LIKELY(!block->is_hashed)) {
@@ -960,12 +1029,13 @@ retry:
#ifdef UNIV_SYNC_DEBUG
ut_ad(rw_lock_own(&(block->lock), RW_LOCK_SHARED)
|| rw_lock_own(&(block->lock), RW_LOCK_EX)
- || (block->buf_fix_count == 0));
+ || (block->page.buf_fix_count == 0));
#endif /* UNIV_SYNC_DEBUG */
n_fields = block->curr_n_fields;
n_bytes = block->curr_n_bytes;
index = block->index;
+ ut_a(!dict_index_is_ibuf(index));
/* NOTE: The fields of block must not be accessed after
releasing btr_search_latch, as the index page might only
@@ -985,7 +1055,7 @@ retry:
n_cached = 0;
rec = page_get_infimum_rec(page);
- rec = page_rec_get_next(rec);
+ rec = page_rec_get_next_low(rec, page_is_comp(page));
index_id = btr_page_get_index_id(page);
@@ -1013,7 +1083,7 @@ retry:
folds[n_cached] = fold;
n_cached++;
next_rec:
- rec = page_rec_get_next(rec);
+ rec = page_rec_get_next_low(rec, page_rec_is_comp(rec));
prev_fold = fold;
}
@@ -1055,6 +1125,7 @@ next_rec:
block->index = NULL;
cleanup:
+#if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
if (UNIV_UNLIKELY(block->n_pointers)) {
/* Corruption */
ut_print_timestamp(stderr);
@@ -1070,27 +1141,29 @@ cleanup:
} else {
rw_lock_x_unlock(&btr_search_latch);
}
+#else /* UNIV_AHI_DEBUG || UNIV_DEBUG */
+ rw_lock_x_unlock(&btr_search_latch);
+#endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
mem_free(folds);
}
-/************************************************************************
+/********************************************************************//**
Drops a page hash index when a page is freed from a fseg to the file system.
Drops possible hash index if the page happens to be in the buffer pool. */
-
+UNIV_INTERN
void
btr_search_drop_page_hash_when_freed(
/*=================================*/
- ulint space, /* in: space id */
- ulint page_no) /* in: page number */
+ ulint space, /*!< in: space id */
+ ulint zip_size, /*!< in: compressed page size in bytes
+ or 0 for uncompressed pages */
+ ulint page_no) /*!< in: page number */
{
- ibool is_hashed;
- page_t* page;
- mtr_t mtr;
+ buf_block_t* block;
+ mtr_t mtr;
- is_hashed = buf_page_peek_if_search_hashed(space, page_no);
-
- if (!is_hashed) {
+ if (!buf_page_peek_if_search_hashed(space, page_no)) {
return;
}
@@ -1102,7 +1175,7 @@ btr_search_drop_page_hash_when_freed(
get here. Therefore we can acquire the s-latch to the page without
having to fear a deadlock. */
- page = buf_page_get_gen(space, page_no, RW_S_LATCH, NULL,
+ block = buf_page_get_gen(space, zip_size, page_no, RW_S_LATCH, NULL,
BUF_GET_IF_IN_POOL, __FILE__, __LINE__,
&mtr);
/* Because the buffer pool mutex was released by
@@ -1111,19 +1184,17 @@ btr_search_drop_page_hash_when_freed(
before buf_page_get_gen() got a chance to acquire the buffer
pool mutex again. Thus, we must check for a NULL return. */
- if (UNIV_LIKELY(page != NULL)) {
+ if (UNIV_LIKELY(block != NULL)) {
-#ifdef UNIV_SYNC_DEBUG
- buf_page_dbg_add_level(page, SYNC_TREE_NODE_FROM_HASH);
-#endif /* UNIV_SYNC_DEBUG */
+ buf_block_dbg_add_level(block, SYNC_TREE_NODE_FROM_HASH);
- btr_search_drop_page_hash_index(page);
+ btr_search_drop_page_hash_index(block);
}
mtr_commit(&mtr);
}
-/************************************************************************
+/********************************************************************//**
Builds a hash index on a page with the given parameters. If the page already
has a hash index with different parameters, the old hash index is removed.
If index is non-NULL, this function checks if n_fields and n_bytes are
@@ -1132,15 +1203,15 @@ static
void
btr_search_build_page_hash_index(
/*=============================*/
- dict_index_t* index, /* in: index for which to build */
- page_t* page, /* in: index page, s- or x-latched */
- ulint n_fields,/* in: hash this many full fields */
- ulint n_bytes,/* in: hash this many bytes from the next
+ dict_index_t* index, /*!< in: index for which to build */
+ buf_block_t* block, /*!< in: index page, s- or x-latched */
+ ulint n_fields,/*!< in: hash this many full fields */
+ ulint n_bytes,/*!< in: hash this many bytes from the next
field */
- ibool left_side)/* in: hash for searches from left side? */
+ ibool left_side)/*!< in: hash for searches from left side? */
{
hash_table_t* table;
- buf_block_t* block;
+ page_t* page;
rec_t* rec;
rec_t* next_rec;
ulint fold;
@@ -1154,12 +1225,13 @@ btr_search_build_page_hash_index(
mem_heap_t* heap = NULL;
ulint offsets_[REC_OFFS_NORMAL_SIZE];
ulint* offsets = offsets_;
- *offsets_ = (sizeof offsets_) / sizeof *offsets_;
+ rec_offs_init(offsets_);
ut_ad(index);
+ ut_a(!dict_index_is_ibuf(index));
- block = buf_block_align(page);
table = btr_search_sys->hash_index;
+ page = buf_block_get_frame(block);
#ifdef UNIV_SYNC_DEBUG
ut_ad(!rw_lock_own(&btr_search_latch, RW_LOCK_EX));
@@ -1175,7 +1247,7 @@ btr_search_build_page_hash_index(
rw_lock_s_unlock(&btr_search_latch);
- btr_search_drop_page_hash_index(page);
+ btr_search_drop_page_hash_index(block);
} else {
rw_lock_s_unlock(&btr_search_latch);
}
@@ -1210,8 +1282,7 @@ btr_search_build_page_hash_index(
index_id = btr_page_get_index_id(page);
- rec = page_get_infimum_rec(page);
- rec = page_rec_get_next(rec);
+ rec = page_rec_get_next(page_get_infimum_rec(page));
offsets = rec_get_offsets(rec, index, offsets,
n_fields + (n_bytes > 0), &heap);
@@ -1276,6 +1347,10 @@ btr_search_build_page_hash_index(
rw_lock_x_lock(&btr_search_latch);
+ if (UNIV_UNLIKELY(!btr_search_enabled)) {
+ goto exit_func;
+ }
+
if (block->is_hashed && ((block->curr_n_fields != n_fields)
|| (block->curr_n_bytes != n_bytes)
|| (block->curr_left_side != left_side))) {
@@ -1301,7 +1376,7 @@ btr_search_build_page_hash_index(
for (i = 0; i < n_cached; i++) {
- ha_insert_for_fold(table, folds[i], recs[i]);
+ ha_insert_for_fold(table, folds[i], block, recs[i]);
}
exit_func:
@@ -1314,32 +1389,26 @@ exit_func:
}
}
-/************************************************************************
+/********************************************************************//**
Moves or deletes hash entries for moved records. If new_page is already hashed,
then the hash index for page, if any, is dropped. If new_page is not hashed,
and page is hashed, then a new hash index is built to new_page with the same
parameters as page (this often happens when a page is split). */
-
+UNIV_INTERN
void
btr_search_move_or_delete_hash_entries(
/*===================================*/
- page_t* new_page, /* in: records are copied
+ buf_block_t* new_block, /*!< in: records are copied
to this page */
- page_t* page, /* in: index page from which
+ buf_block_t* block, /*!< in: index page from which
records were copied, and the
copied records will be deleted
from this page */
- dict_index_t* index) /* in: record descriptor */
+ dict_index_t* index) /*!< in: record descriptor */
{
- buf_block_t* block;
- buf_block_t* new_block;
- ulint n_fields;
- ulint n_bytes;
- ibool left_side;
-
- block = buf_block_align(page);
- new_block = buf_block_align(new_page);
- ut_a(page_is_comp(page) == page_is_comp(new_page));
+ ulint n_fields;
+ ulint n_bytes;
+ ibool left_side;
#ifdef UNIV_SYNC_DEBUG
ut_ad(rw_lock_own(&(block->lock), RW_LOCK_EX));
@@ -1347,6 +1416,8 @@ btr_search_move_or_delete_hash_entries(
#endif /* UNIV_SYNC_DEBUG */
ut_a(!new_block->is_hashed || new_block->index == index);
ut_a(!block->is_hashed || block->index == index);
+ ut_a(!(new_block->is_hashed || block->is_hashed)
+ || !dict_index_is_ibuf(index));
rw_lock_s_lock(&btr_search_latch);
@@ -1354,7 +1425,7 @@ btr_search_move_or_delete_hash_entries(
rw_lock_s_unlock(&btr_search_latch);
- btr_search_drop_page_hash_index(page);
+ btr_search_drop_page_hash_index(block);
return;
}
@@ -1373,26 +1444,24 @@ btr_search_move_or_delete_hash_entries(
ut_a(n_fields + n_bytes > 0);
- btr_search_build_page_hash_index(index, new_page, n_fields,
+ btr_search_build_page_hash_index(index, new_block, n_fields,
n_bytes, left_side);
-#if 1 /* TODO: safe to remove? */
- ut_a(n_fields == block->curr_n_fields);
- ut_a(n_bytes == block->curr_n_bytes);
- ut_a(left_side == block->curr_left_side);
-#endif
+ ut_ad(n_fields == block->curr_n_fields);
+ ut_ad(n_bytes == block->curr_n_bytes);
+ ut_ad(left_side == block->curr_left_side);
return;
}
rw_lock_s_unlock(&btr_search_latch);
}
-/************************************************************************
+/********************************************************************//**
Updates the page hash index when a single record is deleted from a page. */
-
+UNIV_INTERN
void
btr_search_update_hash_on_delete(
/*=============================*/
- btr_cur_t* cursor) /* in: cursor which was positioned on the
+ btr_cur_t* cursor) /*!< in: cursor which was positioned on the
record to delete using btr_cur_search_...,
the record is not yet deleted */
{
@@ -1404,11 +1473,11 @@ btr_search_update_hash_on_delete(
ibool found;
ulint offsets_[REC_OFFS_NORMAL_SIZE];
mem_heap_t* heap = NULL;
- *offsets_ = (sizeof offsets_) / sizeof *offsets_;
+ rec_offs_init(offsets_);
rec = btr_cur_get_rec(cursor);
- block = buf_block_align(rec);
+ block = btr_cur_get_block(cursor);
#ifdef UNIV_SYNC_DEBUG
ut_ad(rw_lock_own(&(block->lock), RW_LOCK_EX));
@@ -1421,6 +1490,7 @@ btr_search_update_hash_on_delete(
ut_a(block->index == cursor->index);
ut_a(block->curr_n_fields + block->curr_n_bytes > 0);
+ ut_a(!dict_index_is_ibuf(cursor->index));
table = btr_search_sys->hash_index;
@@ -1438,13 +1508,13 @@ btr_search_update_hash_on_delete(
rw_lock_x_unlock(&btr_search_latch);
}
-/************************************************************************
+/********************************************************************//**
Updates the page hash index when a single record is inserted on a page. */
-
+UNIV_INTERN
void
btr_search_update_hash_node_on_insert(
/*==================================*/
- btr_cur_t* cursor) /* in: cursor which was positioned to the
+ btr_cur_t* cursor) /*!< in: cursor which was positioned to the
place to insert using btr_cur_search_...,
and the new record has been inserted next
to the cursor */
@@ -1455,7 +1525,7 @@ btr_search_update_hash_node_on_insert(
rec = btr_cur_get_rec(cursor);
- block = buf_block_align(rec);
+ block = btr_cur_get_block(cursor);
#ifdef UNIV_SYNC_DEBUG
ut_ad(rw_lock_own(&(block->lock), RW_LOCK_EX));
@@ -1467,6 +1537,7 @@ btr_search_update_hash_node_on_insert(
}
ut_a(block->index == cursor->index);
+ ut_a(!dict_index_is_ibuf(cursor->index));
rw_lock_x_lock(&btr_search_latch);
@@ -1478,7 +1549,7 @@ btr_search_update_hash_node_on_insert(
table = btr_search_sys->hash_index;
ha_search_and_update_if_found(table, cursor->fold, rec,
- page_rec_get_next(rec));
+ block, page_rec_get_next(rec));
rw_lock_x_unlock(&btr_search_latch);
} else {
@@ -1488,13 +1559,13 @@ btr_search_update_hash_node_on_insert(
}
}
-/************************************************************************
+/********************************************************************//**
Updates the page hash index when a single record is inserted on a page. */
-
+UNIV_INTERN
void
btr_search_update_hash_on_insert(
/*=============================*/
- btr_cur_t* cursor) /* in: cursor which was positioned to the
+ btr_cur_t* cursor) /*!< in: cursor which was positioned to the
place to insert using btr_cur_search_...,
and the new record has been inserted next
to the cursor */
@@ -1515,7 +1586,7 @@ btr_search_update_hash_on_insert(
mem_heap_t* heap = NULL;
ulint offsets_[REC_OFFS_NORMAL_SIZE];
ulint* offsets = offsets_;
- *offsets_ = (sizeof offsets_) / sizeof *offsets_;
+ rec_offs_init(offsets_);
table = btr_search_sys->hash_index;
@@ -1523,7 +1594,7 @@ btr_search_update_hash_on_insert(
rec = btr_cur_get_rec(cursor);
- block = buf_block_align(rec);
+ block = btr_cur_get_block(cursor);
#ifdef UNIV_SYNC_DEBUG
ut_ad(rw_lock_own(&(block->lock), RW_LOCK_EX));
@@ -1535,6 +1606,7 @@ btr_search_update_hash_on_insert(
}
ut_a(block->index == cursor->index);
+ ut_a(!dict_index_is_ibuf(cursor->index));
index_id = cursor->index->id;
@@ -1567,7 +1639,7 @@ btr_search_update_hash_on_insert(
locked = TRUE;
- ha_insert_for_fold(table, ins_fold, ins_rec);
+ ha_insert_for_fold(table, ins_fold, block, ins_rec);
}
goto check_next_rec;
@@ -1583,9 +1655,9 @@ btr_search_update_hash_on_insert(
}
if (!left_side) {
- ha_insert_for_fold(table, fold, rec);
+ ha_insert_for_fold(table, fold, block, rec);
} else {
- ha_insert_for_fold(table, ins_fold, ins_rec);
+ ha_insert_for_fold(table, ins_fold, block, ins_rec);
}
}
@@ -1600,7 +1672,7 @@ check_next_rec:
locked = TRUE;
}
- ha_insert_for_fold(table, ins_fold, ins_rec);
+ ha_insert_for_fold(table, ins_fold, block, ins_rec);
}
goto function_exit;
@@ -1617,14 +1689,14 @@ check_next_rec:
if (!left_side) {
- ha_insert_for_fold(table, ins_fold, ins_rec);
+ ha_insert_for_fold(table, ins_fold, block, ins_rec);
/*
fputs("Hash insert for ", stderr);
dict_index_name_print(stderr, cursor->index);
fprintf(stderr, " fold %lu\n", ins_fold);
*/
} else {
- ha_insert_for_fold(table, next_fold, next_rec);
+ ha_insert_for_fold(table, next_fold, block, next_rec);
}
}
@@ -1637,16 +1709,14 @@ function_exit:
}
}
-/************************************************************************
-Validates the search system. */
-
+/********************************************************************//**
+Validates the search system.
+@return TRUE if ok */
+UNIV_INTERN
ibool
btr_search_validate(void)
/*=====================*/
- /* out: TRUE if ok */
{
- buf_block_t* block;
- page_t* page;
ha_node_t* node;
ulint n_page_dumps = 0;
ibool ok = TRUE;
@@ -1660,9 +1730,10 @@ btr_search_validate(void)
btr_search_latch. */
ulint chunk_size = 10000;
- *offsets_ = (sizeof offsets_) / sizeof *offsets_;
+ rec_offs_init(offsets_);
rw_lock_x_lock(&btr_search_latch);
+ buf_pool_mutex_enter();
cell_count = hash_get_n_cells(btr_search_sys->hash_index);
@@ -1670,17 +1741,55 @@ btr_search_validate(void)
/* We release btr_search_latch every once in a while to
give other queries a chance to run. */
if ((i != 0) && ((i % chunk_size) == 0)) {
+ buf_pool_mutex_exit();
rw_lock_x_unlock(&btr_search_latch);
os_thread_yield();
rw_lock_x_lock(&btr_search_latch);
+ buf_pool_mutex_enter();
}
node = hash_get_nth_cell(btr_search_sys->hash_index, i)->node;
- while (node != NULL) {
- block = buf_block_align(node->data);
- page = buf_frame_align(node->data);
- offsets = rec_get_offsets((rec_t*) node->data,
+ for (; node != NULL; node = node->next) {
+ const buf_block_t* block
+ = buf_block_align(node->data);
+ const buf_block_t* hash_block;
+
+ if (UNIV_LIKELY(buf_block_get_state(block)
+ == BUF_BLOCK_FILE_PAGE)) {
+
+ /* The space and offset are only valid
+ for file blocks. It is possible that
+ the block is being freed
+ (BUF_BLOCK_REMOVE_HASH, see the
+ assertion and the comment below) */
+ hash_block = buf_block_hash_get(
+ buf_block_get_space(block),
+ buf_block_get_page_no(block));
+ } else {
+ hash_block = NULL;
+ }
+
+ if (hash_block) {
+ ut_a(hash_block == block);
+ } else {
+ /* When a block is being freed,
+ buf_LRU_search_and_free_block() first
+ removes the block from
+ buf_pool->page_hash by calling
+ buf_LRU_block_remove_hashed_page().
+ After that, it invokes
+ btr_search_drop_page_hash_index() to
+ remove the block from
+ btr_search_sys->hash_index. */
+
+ ut_a(buf_block_get_state(block)
+ == BUF_BLOCK_REMOVE_HASH);
+ }
+
+ ut_a(!dict_index_is_ibuf(block->index));
+
+ offsets = rec_get_offsets((const rec_t*) node->data,
block->index, offsets,
block->curr_n_fields
+ (block->curr_n_bytes > 0),
@@ -1691,7 +1800,9 @@ btr_search_validate(void)
offsets,
block->curr_n_fields,
block->curr_n_bytes,
- btr_page_get_index_id(page))) {
+ btr_page_get_index_id(block->frame))) {
+ const page_t* page = block->frame;
+
ok = FALSE;
ut_print_timestamp(stderr);
@@ -1701,7 +1812,7 @@ btr_search_validate(void)
"InnoDB: ptr mem address %p"
" index id %lu %lu,"
" node fold %lu, rec fold %lu\n",
- (ulong) buf_frame_get_page_no(page),
+ (ulong) page_get_page_no(page),
node->data,
(ulong) ut_dulint_get_high(
btr_page_get_index_id(page)),
@@ -1728,12 +1839,10 @@ btr_search_validate(void)
(ulong) block->curr_left_side);
if (n_page_dumps < 20) {
- buf_page_print(page);
+ buf_page_print(page, 0);
n_page_dumps++;
}
}
-
- node = node->next;
}
}
@@ -1743,9 +1852,11 @@ btr_search_validate(void)
/* We release btr_search_latch every once in a while to
give other queries a chance to run. */
if (i != 0) {
+ buf_pool_mutex_exit();
rw_lock_x_unlock(&btr_search_latch);
os_thread_yield();
rw_lock_x_lock(&btr_search_latch);
+ buf_pool_mutex_enter();
}
if (!ha_validate(btr_search_sys->hash_index, i, end_index)) {
@@ -1753,6 +1864,7 @@ btr_search_validate(void)
}
}
+ buf_pool_mutex_exit();
rw_lock_x_unlock(&btr_search_latch);
if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
diff --git a/storage/innodb_plugin/buf/buf0buddy.c b/storage/innodb_plugin/buf/buf0buddy.c
new file mode 100644
index 00000000000..f0e1395c307
--- /dev/null
+++ b/storage/innodb_plugin/buf/buf0buddy.c
@@ -0,0 +1,692 @@
+/*****************************************************************************
+
+Copyright (c) 2006, 2009, Innobase Oy. All Rights Reserved.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; version 2 of the License.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place, Suite 330, Boston, MA 02111-1307 USA
+
+*****************************************************************************/
+
+/**************************************************//**
+@file buf/buf0buddy.c
+Binary buddy allocator for compressed pages
+
+Created December 2006 by Marko Makela
+*******************************************************/
+
+#define THIS_MODULE
+#include "buf0buddy.h"
+#ifdef UNIV_NONINL
+# include "buf0buddy.ic"
+#endif
+#undef THIS_MODULE
+#include "buf0buf.h"
+#include "buf0lru.h"
+#include "buf0flu.h"
+#include "page0zip.h"
+
+/* Statistic counters */
+
+#ifdef UNIV_DEBUG
+/** Number of frames allocated from the buffer pool to the buddy system.
+Protected by buf_pool_mutex. */
+static ulint buf_buddy_n_frames;
+#endif /* UNIV_DEBUG */
+/** Statistics of the buddy system, indexed by block size.
+Protected by buf_pool_mutex. */
+UNIV_INTERN buf_buddy_stat_t buf_buddy_stat[BUF_BUDDY_SIZES + 1];
+
+/**********************************************************************//**
+Get the offset of the buddy of a compressed page frame.
+@return the buddy relative of page */
+UNIV_INLINE
+byte*
+buf_buddy_get(
+/*==========*/
+ byte* page, /*!< in: compressed page */
+ ulint size) /*!< in: page size in bytes */
+{
+ ut_ad(ut_is_2pow(size));
+ ut_ad(size >= BUF_BUDDY_LOW);
+ ut_ad(size < BUF_BUDDY_HIGH);
+ ut_ad(!ut_align_offset(page, size));
+
+ if (((ulint) page) & size) {
+ return(page - size);
+ } else {
+ return(page + size);
+ }
+}
+
+/**********************************************************************//**
+Add a block to the head of the appropriate buddy free list. */
+UNIV_INLINE
+void
+buf_buddy_add_to_free(
+/*==================*/
+ buf_page_t* bpage, /*!< in,own: block to be freed */
+ ulint i) /*!< in: index of buf_pool->zip_free[] */
+{
+#ifdef UNIV_DEBUG_VALGRIND
+ buf_page_t* b = UT_LIST_GET_FIRST(buf_pool->zip_free[i]);
+
+ if (b) UNIV_MEM_VALID(b, BUF_BUDDY_LOW << i);
+#endif /* UNIV_DEBUG_VALGRIND */
+
+ ut_ad(buf_pool_mutex_own());
+ ut_ad(buf_page_get_state(bpage) == BUF_BLOCK_ZIP_FREE);
+ ut_ad(buf_pool->zip_free[i].start != bpage);
+ UT_LIST_ADD_FIRST(list, buf_pool->zip_free[i], bpage);
+
+#ifdef UNIV_DEBUG_VALGRIND
+ if (b) UNIV_MEM_FREE(b, BUF_BUDDY_LOW << i);
+ UNIV_MEM_ASSERT_AND_FREE(bpage, BUF_BUDDY_LOW << i);
+#endif /* UNIV_DEBUG_VALGRIND */
+}
+
+/**********************************************************************//**
+Remove a block from the appropriate buddy free list. */
+UNIV_INLINE
+void
+buf_buddy_remove_from_free(
+/*=======================*/
+ buf_page_t* bpage, /*!< in: block to be removed */
+ ulint i) /*!< in: index of buf_pool->zip_free[] */
+{
+#ifdef UNIV_DEBUG_VALGRIND
+ buf_page_t* prev = UT_LIST_GET_PREV(list, bpage);
+ buf_page_t* next = UT_LIST_GET_NEXT(list, bpage);
+
+ if (prev) UNIV_MEM_VALID(prev, BUF_BUDDY_LOW << i);
+ if (next) UNIV_MEM_VALID(next, BUF_BUDDY_LOW << i);
+
+ ut_ad(!prev || buf_page_get_state(prev) == BUF_BLOCK_ZIP_FREE);
+ ut_ad(!next || buf_page_get_state(next) == BUF_BLOCK_ZIP_FREE);
+#endif /* UNIV_DEBUG_VALGRIND */
+
+ ut_ad(buf_pool_mutex_own());
+ ut_ad(buf_page_get_state(bpage) == BUF_BLOCK_ZIP_FREE);
+ UT_LIST_REMOVE(list, buf_pool->zip_free[i], bpage);
+
+#ifdef UNIV_DEBUG_VALGRIND
+ if (prev) UNIV_MEM_FREE(prev, BUF_BUDDY_LOW << i);
+ if (next) UNIV_MEM_FREE(next, BUF_BUDDY_LOW << i);
+#endif /* UNIV_DEBUG_VALGRIND */
+}
+
+/**********************************************************************//**
+Try to allocate a block from buf_pool->zip_free[].
+@return allocated block, or NULL if buf_pool->zip_free[] was empty */
+static
+void*
+buf_buddy_alloc_zip(
+/*================*/
+ ulint i) /*!< in: index of buf_pool->zip_free[] */
+{
+ buf_page_t* bpage;
+
+ ut_ad(buf_pool_mutex_own());
+ ut_a(i < BUF_BUDDY_SIZES);
+
+#ifndef UNIV_DEBUG_VALGRIND
+ /* Valgrind would complain about accessing free memory. */
+ ut_d(UT_LIST_VALIDATE(list, buf_page_t, buf_pool->zip_free[i],
+ ut_ad(buf_page_get_state(ut_list_node_313)
+ == BUF_BLOCK_ZIP_FREE)));
+#endif /* !UNIV_DEBUG_VALGRIND */
+ bpage = UT_LIST_GET_FIRST(buf_pool->zip_free[i]);
+
+ if (bpage) {
+ UNIV_MEM_VALID(bpage, BUF_BUDDY_LOW << i);
+ ut_a(buf_page_get_state(bpage) == BUF_BLOCK_ZIP_FREE);
+
+ buf_buddy_remove_from_free(bpage, i);
+ } else if (i + 1 < BUF_BUDDY_SIZES) {
+ /* Attempt to split. */
+ bpage = buf_buddy_alloc_zip(i + 1);
+
+ if (bpage) {
+ buf_page_t* buddy = (buf_page_t*)
+ (((char*) bpage) + (BUF_BUDDY_LOW << i));
+
+ ut_ad(!buf_pool_contains_zip(buddy));
+ ut_d(memset(buddy, i, BUF_BUDDY_LOW << i));
+ buddy->state = BUF_BLOCK_ZIP_FREE;
+ buf_buddy_add_to_free(buddy, i);
+ }
+ }
+
+#ifdef UNIV_DEBUG
+ if (bpage) {
+ memset(bpage, ~i, BUF_BUDDY_LOW << i);
+ }
+#endif /* UNIV_DEBUG */
+
+ UNIV_MEM_ALLOC(bpage, BUF_BUDDY_SIZES << i);
+
+ return(bpage);
+}
+
+/**********************************************************************//**
+Deallocate a buffer frame of UNIV_PAGE_SIZE. */
+static
+void
+buf_buddy_block_free(
+/*=================*/
+ void* buf) /*!< in: buffer frame to deallocate */
+{
+ const ulint fold = BUF_POOL_ZIP_FOLD_PTR(buf);
+ buf_page_t* bpage;
+ buf_block_t* block;
+
+ ut_ad(buf_pool_mutex_own());
+ ut_ad(!mutex_own(&buf_pool_zip_mutex));
+ ut_a(!ut_align_offset(buf, UNIV_PAGE_SIZE));
+
+ HASH_SEARCH(hash, buf_pool->zip_hash, fold, buf_page_t*, bpage,
+ ut_ad(buf_page_get_state(bpage) == BUF_BLOCK_MEMORY
+ && bpage->in_zip_hash && !bpage->in_page_hash),
+ ((buf_block_t*) bpage)->frame == buf);
+ ut_a(bpage);
+ ut_a(buf_page_get_state(bpage) == BUF_BLOCK_MEMORY);
+ ut_ad(!bpage->in_page_hash);
+ ut_ad(bpage->in_zip_hash);
+ ut_d(bpage->in_zip_hash = FALSE);
+ HASH_DELETE(buf_page_t, hash, buf_pool->zip_hash, fold, bpage);
+
+ ut_d(memset(buf, 0, UNIV_PAGE_SIZE));
+ UNIV_MEM_INVALID(buf, UNIV_PAGE_SIZE);
+
+ block = (buf_block_t*) bpage;
+ mutex_enter(&block->mutex);
+ buf_LRU_block_free_non_file_page(block);
+ mutex_exit(&block->mutex);
+
+ ut_ad(buf_buddy_n_frames > 0);
+ ut_d(buf_buddy_n_frames--);
+}
+
+/**********************************************************************//**
+Allocate a buffer block to the buddy allocator. */
+static
+void
+buf_buddy_block_register(
+/*=====================*/
+ buf_block_t* block) /*!< in: buffer frame to allocate */
+{
+ const ulint fold = BUF_POOL_ZIP_FOLD(block);
+ ut_ad(buf_pool_mutex_own());
+ ut_ad(!mutex_own(&buf_pool_zip_mutex));
+ ut_ad(buf_block_get_state(block) == BUF_BLOCK_READY_FOR_USE);
+
+ buf_block_set_state(block, BUF_BLOCK_MEMORY);
+
+ ut_a(block->frame);
+ ut_a(!ut_align_offset(block->frame, UNIV_PAGE_SIZE));
+
+ ut_ad(!block->page.in_page_hash);
+ ut_ad(!block->page.in_zip_hash);
+ ut_d(block->page.in_zip_hash = TRUE);
+ HASH_INSERT(buf_page_t, hash, buf_pool->zip_hash, fold, &block->page);
+
+ ut_d(buf_buddy_n_frames++);
+}
+
+/**********************************************************************//**
+Allocate a block from a bigger object.
+@return allocated block */
+static
+void*
+buf_buddy_alloc_from(
+/*=================*/
+ void* buf, /*!< in: a block that is free to use */
+ ulint i, /*!< in: index of buf_pool->zip_free[] */
+ ulint j) /*!< in: size of buf as an index
+ of buf_pool->zip_free[] */
+{
+ ulint offs = BUF_BUDDY_LOW << j;
+ ut_ad(j <= BUF_BUDDY_SIZES);
+ ut_ad(j >= i);
+ ut_ad(!ut_align_offset(buf, offs));
+
+ /* Add the unused parts of the block to the free lists. */
+ while (j > i) {
+ buf_page_t* bpage;
+
+ offs >>= 1;
+ j--;
+
+ bpage = (buf_page_t*) ((byte*) buf + offs);
+ ut_d(memset(bpage, j, BUF_BUDDY_LOW << j));
+ bpage->state = BUF_BLOCK_ZIP_FREE;
+#ifndef UNIV_DEBUG_VALGRIND
+ /* Valgrind would complain about accessing free memory. */
+ ut_d(UT_LIST_VALIDATE(list, buf_page_t, buf_pool->zip_free[i],
+ ut_ad(buf_page_get_state(
+ ut_list_node_313)
+ == BUF_BLOCK_ZIP_FREE)));
+#endif /* !UNIV_DEBUG_VALGRIND */
+ buf_buddy_add_to_free(bpage, j);
+ }
+
+ return(buf);
+}
+
+/**********************************************************************//**
+Allocate a block. The thread calling this function must hold
+buf_pool_mutex and must not hold buf_pool_zip_mutex or any block->mutex.
+The buf_pool_mutex may only be released and reacquired if lru != NULL.
+@return allocated block, possibly NULL if lru==NULL */
+UNIV_INTERN
+void*
+buf_buddy_alloc_low(
+/*================*/
+ ulint i, /*!< in: index of buf_pool->zip_free[],
+ or BUF_BUDDY_SIZES */
+ ibool* lru) /*!< in: pointer to a variable that will be assigned
+ TRUE if storage was allocated from the LRU list
+ and buf_pool_mutex was temporarily released,
+ or NULL if the LRU list should not be used */
+{
+ buf_block_t* block;
+
+ ut_ad(buf_pool_mutex_own());
+ ut_ad(!mutex_own(&buf_pool_zip_mutex));
+
+ if (i < BUF_BUDDY_SIZES) {
+ /* Try to allocate from the buddy system. */
+ block = buf_buddy_alloc_zip(i);
+
+ if (block) {
+
+ goto func_exit;
+ }
+ }
+
+ /* Try allocating from the buf_pool->free list. */
+ block = buf_LRU_get_free_only();
+
+ if (block) {
+
+ goto alloc_big;
+ }
+
+ if (!lru) {
+
+ return(NULL);
+ }
+
+ /* Try replacing an uncompressed page in the buffer pool. */
+ buf_pool_mutex_exit();
+ block = buf_LRU_get_free_block(0);
+ *lru = TRUE;
+ buf_pool_mutex_enter();
+
+alloc_big:
+ buf_buddy_block_register(block);
+
+ block = buf_buddy_alloc_from(block->frame, i, BUF_BUDDY_SIZES);
+
+func_exit:
+ buf_buddy_stat[i].used++;
+ return(block);
+}
+
+/**********************************************************************//**
+Try to relocate the control block of a compressed page.
+@return TRUE if relocated */
+static
+ibool
+buf_buddy_relocate_block(
+/*=====================*/
+ buf_page_t* bpage, /*!< in: block to relocate */
+ buf_page_t* dpage) /*!< in: free block to relocate to */
+{
+ buf_page_t* b;
+
+ ut_ad(buf_pool_mutex_own());
+
+ switch (buf_page_get_state(bpage)) {
+ case BUF_BLOCK_ZIP_FREE:
+ case BUF_BLOCK_NOT_USED:
+ case BUF_BLOCK_READY_FOR_USE:
+ case BUF_BLOCK_FILE_PAGE:
+ case BUF_BLOCK_MEMORY:
+ case BUF_BLOCK_REMOVE_HASH:
+ ut_error;
+ case BUF_BLOCK_ZIP_DIRTY:
+ /* Cannot relocate dirty pages. */
+ return(FALSE);
+
+ case BUF_BLOCK_ZIP_PAGE:
+ break;
+ }
+
+ mutex_enter(&buf_pool_zip_mutex);
+
+ if (!buf_page_can_relocate(bpage)) {
+ mutex_exit(&buf_pool_zip_mutex);
+ return(FALSE);
+ }
+
+ buf_relocate(bpage, dpage);
+ ut_d(bpage->state = BUF_BLOCK_ZIP_FREE);
+
+ /* relocate buf_pool->zip_clean */
+ b = UT_LIST_GET_PREV(list, dpage);
+ UT_LIST_REMOVE(list, buf_pool->zip_clean, dpage);
+
+ if (b) {
+ UT_LIST_INSERT_AFTER(list, buf_pool->zip_clean, b, dpage);
+ } else {
+ UT_LIST_ADD_FIRST(list, buf_pool->zip_clean, dpage);
+ }
+
+ mutex_exit(&buf_pool_zip_mutex);
+ return(TRUE);
+}
+
+/**********************************************************************//**
+Try to relocate a block.
+@return TRUE if relocated */
+static
+ibool
+buf_buddy_relocate(
+/*===============*/
+ void* src, /*!< in: block to relocate */
+ void* dst, /*!< in: free block to relocate to */
+ ulint i) /*!< in: index of buf_pool->zip_free[] */
+{
+ buf_page_t* bpage;
+ const ulint size = BUF_BUDDY_LOW << i;
+ ullint usec = ut_time_us(NULL);
+
+ ut_ad(buf_pool_mutex_own());
+ ut_ad(!mutex_own(&buf_pool_zip_mutex));
+ ut_ad(!ut_align_offset(src, size));
+ ut_ad(!ut_align_offset(dst, size));
+ UNIV_MEM_ASSERT_W(dst, size);
+
+ /* We assume that all memory from buf_buddy_alloc()
+ is used for either compressed pages or buf_page_t
+ objects covering compressed pages. */
+
+ /* We look inside the allocated objects returned by
+ buf_buddy_alloc() and assume that anything of
+ PAGE_ZIP_MIN_SIZE or larger is a compressed page that contains
+ a valid space_id and page_no in the page header. Should the
+ fields be invalid, we will be unable to relocate the block.
+ We also assume that anything that fits sizeof(buf_page_t)
+ actually is a properly initialized buf_page_t object. */
+
+ if (size >= PAGE_ZIP_MIN_SIZE) {
+ /* This is a compressed page. */
+ mutex_t* mutex;
+
+ /* The src block may be split into smaller blocks,
+ some of which may be free. Thus, the
+ mach_read_from_4() calls below may attempt to read
+ from free memory. The memory is "owned" by the buddy
+ allocator (and it has been allocated from the buffer
+ pool), so there is nothing wrong about this. The
+ mach_read_from_4() calls here will only trigger bogus
+ Valgrind memcheck warnings in UNIV_DEBUG_VALGRIND builds. */
+ bpage = buf_page_hash_get(
+ mach_read_from_4((const byte*) src
+ + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID),
+ mach_read_from_4((const byte*) src
+ + FIL_PAGE_OFFSET));
+
+ if (!bpage || bpage->zip.data != src) {
+ /* The block has probably been freshly
+ allocated by buf_LRU_get_free_block() but not
+ added to buf_pool->page_hash yet. Obviously,
+ it cannot be relocated. */
+
+ return(FALSE);
+ }
+
+ if (page_zip_get_size(&bpage->zip) != size) {
+ /* The block is of different size. We would
+ have to relocate all blocks covered by src.
+ For the sake of simplicity, give up. */
+ ut_ad(page_zip_get_size(&bpage->zip) < size);
+
+ return(FALSE);
+ }
+
+ /* The block must have been allocated, but it may
+ contain uninitialized data. */
+ UNIV_MEM_ASSERT_W(src, size);
+
+ mutex = buf_page_get_mutex(bpage);
+
+ mutex_enter(mutex);
+
+ if (buf_page_can_relocate(bpage)) {
+ /* Relocate the compressed page. */
+ ut_a(bpage->zip.data == src);
+ memcpy(dst, src, size);
+ bpage->zip.data = dst;
+ mutex_exit(mutex);
+success:
+ UNIV_MEM_INVALID(src, size);
+ {
+ buf_buddy_stat_t* buddy_stat
+ = &buf_buddy_stat[i];
+ buddy_stat->relocated++;
+ buddy_stat->relocated_usec
+ += ut_time_us(NULL) - usec;
+ }
+ return(TRUE);
+ }
+
+ mutex_exit(mutex);
+ } else if (i == buf_buddy_get_slot(sizeof(buf_page_t))) {
+ /* This must be a buf_page_t object. */
+ UNIV_MEM_ASSERT_RW(src, size);
+ if (buf_buddy_relocate_block(src, dst)) {
+
+ goto success;
+ }
+ }
+
+ return(FALSE);
+}
+
+/**********************************************************************//**
+Deallocate a block. */
+UNIV_INTERN
+void
+buf_buddy_free_low(
+/*===============*/
+ void* buf, /*!< in: block to be freed, must not be
+ pointed to by the buffer pool */
+ ulint i) /*!< in: index of buf_pool->zip_free[],
+ or BUF_BUDDY_SIZES */
+{
+ buf_page_t* bpage;
+ buf_page_t* buddy;
+
+ ut_ad(buf_pool_mutex_own());
+ ut_ad(!mutex_own(&buf_pool_zip_mutex));
+ ut_ad(i <= BUF_BUDDY_SIZES);
+ ut_ad(buf_buddy_stat[i].used > 0);
+
+ buf_buddy_stat[i].used--;
+recombine:
+ UNIV_MEM_ASSERT_AND_ALLOC(buf, BUF_BUDDY_LOW << i);
+ ut_d(((buf_page_t*) buf)->state = BUF_BLOCK_ZIP_FREE);
+
+ if (i == BUF_BUDDY_SIZES) {
+ buf_buddy_block_free(buf);
+ return;
+ }
+
+ ut_ad(i < BUF_BUDDY_SIZES);
+ ut_ad(buf == ut_align_down(buf, BUF_BUDDY_LOW << i));
+ ut_ad(!buf_pool_contains_zip(buf));
+
+ /* Try to combine adjacent blocks. */
+
+ buddy = (buf_page_t*) buf_buddy_get(((byte*) buf), BUF_BUDDY_LOW << i);
+
+#ifndef UNIV_DEBUG_VALGRIND
+ /* Valgrind would complain about accessing free memory. */
+
+ if (buddy->state != BUF_BLOCK_ZIP_FREE) {
+
+ goto buddy_nonfree;
+ }
+
+ /* The field buddy->state can only be trusted for free blocks.
+ If buddy->state == BUF_BLOCK_ZIP_FREE, the block is free if
+ it is in the free list. */
+#endif /* !UNIV_DEBUG_VALGRIND */
+
+ for (bpage = UT_LIST_GET_FIRST(buf_pool->zip_free[i]); bpage; ) {
+ UNIV_MEM_VALID(bpage, BUF_BUDDY_LOW << i);
+ ut_ad(buf_page_get_state(bpage) == BUF_BLOCK_ZIP_FREE);
+
+ if (bpage == buddy) {
+buddy_free:
+ /* The buddy is free: recombine */
+ buf_buddy_remove_from_free(bpage, i);
+buddy_free2:
+ ut_ad(buf_page_get_state(buddy) == BUF_BLOCK_ZIP_FREE);
+ ut_ad(!buf_pool_contains_zip(buddy));
+ i++;
+ buf = ut_align_down(buf, BUF_BUDDY_LOW << i);
+
+ goto recombine;
+ }
+
+ ut_a(bpage != buf);
+
+ {
+ buf_page_t* next = UT_LIST_GET_NEXT(list, bpage);
+ UNIV_MEM_ASSERT_AND_FREE(bpage, BUF_BUDDY_LOW << i);
+ bpage = next;
+ }
+ }
+
+#ifndef UNIV_DEBUG_VALGRIND
+buddy_nonfree:
+ /* Valgrind would complain about accessing free memory. */
+ ut_d(UT_LIST_VALIDATE(list, buf_page_t, buf_pool->zip_free[i],
+ ut_ad(buf_page_get_state(ut_list_node_313)
+ == BUF_BLOCK_ZIP_FREE)));
+#endif /* UNIV_DEBUG_VALGRIND */
+
+ /* The buddy is not free. Is there a free block of this size? */
+ bpage = UT_LIST_GET_FIRST(buf_pool->zip_free[i]);
+
+ if (bpage) {
+ /* Remove the block from the free list, because a successful
+ buf_buddy_relocate() will overwrite bpage->list. */
+
+ UNIV_MEM_VALID(bpage, BUF_BUDDY_LOW << i);
+ buf_buddy_remove_from_free(bpage, i);
+
+ /* Try to relocate the buddy of buf to the free block. */
+ if (buf_buddy_relocate(buddy, bpage, i)) {
+
+ ut_d(buddy->state = BUF_BLOCK_ZIP_FREE);
+ goto buddy_free2;
+ }
+
+ buf_buddy_add_to_free(bpage, i);
+
+ /* Try to relocate the buddy of the free block to buf. */
+ buddy = (buf_page_t*) buf_buddy_get(((byte*) bpage),
+ BUF_BUDDY_LOW << i);
+
+#ifndef UNIV_DEBUG_VALGRIND
+ /* Valgrind would complain about accessing free memory. */
+
+ /* The buddy must not be (completely) free, because we
+ always recombine adjacent free blocks.
+
+ (Parts of the buddy can be free in
+ buf_pool->zip_free[j] with j < i.) */
+ ut_d(UT_LIST_VALIDATE(list, buf_page_t, buf_pool->zip_free[i],
+ ut_ad(buf_page_get_state(
+ ut_list_node_313)
+ == BUF_BLOCK_ZIP_FREE
+ && ut_list_node_313 != buddy)));
+#endif /* !UNIV_DEBUG_VALGRIND */
+
+ if (buf_buddy_relocate(buddy, buf, i)) {
+
+ buf = bpage;
+ UNIV_MEM_VALID(bpage, BUF_BUDDY_LOW << i);
+ ut_d(buddy->state = BUF_BLOCK_ZIP_FREE);
+ goto buddy_free;
+ }
+ }
+
+ /* Free the block to the buddy list. */
+ bpage = buf;
+#ifdef UNIV_DEBUG
+ if (i < buf_buddy_get_slot(PAGE_ZIP_MIN_SIZE)) {
+ /* This area has most likely been allocated for at
+ least one compressed-only block descriptor. Check
+ that there are no live objects in the area. This is
+ not a complete check: it may yield false positives as
+ well as false negatives. Also, due to buddy blocks
+ being recombined, it is possible (although unlikely)
+ that this branch is never reached. */
+
+ char* c;
+
+# ifndef UNIV_DEBUG_VALGRIND
+ /* Valgrind would complain about accessing
+ uninitialized memory. Besides, Valgrind performs a
+ more exhaustive check, at every memory access. */
+ const buf_page_t* b = buf;
+ const buf_page_t* const b_end = (buf_page_t*)
+ ((char*) b + (BUF_BUDDY_LOW << i));
+
+ for (; b < b_end; b++) {
+ /* Avoid false positives (and cause false
+ negatives) by checking for b->space < 1000. */
+
+ if ((b->state == BUF_BLOCK_ZIP_PAGE
+ || b->state == BUF_BLOCK_ZIP_DIRTY)
+ && b->space > 0 && b->space < 1000) {
+ fprintf(stderr,
+ "buddy dirty %p %u (%u,%u) %p,%lu\n",
+ (void*) b,
+ b->state, b->space, b->offset,
+ buf, i);
+ }
+ }
+# endif /* !UNIV_DEBUG_VALGRIND */
+
+ /* Scramble the block. This should make any pointers
+ invalid and trigger a segmentation violation. Because
+ the scrambling can be reversed, it may be possible to
+ track down the object pointing to the freed data by
+ dereferencing the unscrambled bpage->LRU or
+ bpage->list pointers. */
+ for (c = (char*) buf + (BUF_BUDDY_LOW << i);
+ c-- > (char*) buf; ) {
+ *c = ~*c ^ i;
+ }
+ } else {
+ /* Fill large blocks with a constant pattern. */
+ memset(bpage, i, BUF_BUDDY_LOW << i);
+ }
+#endif /* UNIV_DEBUG */
+ bpage->state = BUF_BLOCK_ZIP_FREE;
+ buf_buddy_add_to_free(bpage, i);
+}
diff --git a/storage/innodb_plugin/buf/buf0buf.c b/storage/innodb_plugin/buf/buf0buf.c
new file mode 100644
index 00000000000..0008fcb1271
--- /dev/null
+++ b/storage/innodb_plugin/buf/buf0buf.c
@@ -0,0 +1,3942 @@
+/*****************************************************************************
+
+Copyright (c) 1995, 2009, Innobase Oy. All Rights Reserved.
+Copyright (c) 2008, Google Inc.
+
+Portions of this file contain modifications contributed and copyrighted by
+Google, Inc. Those modifications are gratefully acknowledged and are described
+briefly in the InnoDB documentation. The contributions by Google are
+incorporated with their permission, and subject to the conditions contained in
+the file COPYING.Google.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; version 2 of the License.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place, Suite 330, Boston, MA 02111-1307 USA
+
+*****************************************************************************/
+
+/**************************************************//**
+@file buf/buf0buf.c
+The database buffer buf_pool
+
+Created 11/5/1995 Heikki Tuuri
+*******************************************************/
+
+#include "buf0buf.h"
+
+#ifdef UNIV_NONINL
+#include "buf0buf.ic"
+#endif
+
+#include "mem0mem.h"
+#include "btr0btr.h"
+#include "fil0fil.h"
+#ifndef UNIV_HOTBACKUP
+#include "buf0buddy.h"
+#include "lock0lock.h"
+#include "btr0sea.h"
+#include "ibuf0ibuf.h"
+#include "trx0undo.h"
+#include "log0log.h"
+#endif /* !UNIV_HOTBACKUP */
+#include "srv0srv.h"
+#include "dict0dict.h"
+#include "log0recv.h"
+#include "page0zip.h"
+
+/*
+ IMPLEMENTATION OF THE BUFFER POOL
+ =================================
+
+Performance improvement:
+------------------------
+Thread scheduling in NT may be so slow that the OS wait mechanism should
+not be used even in waiting for disk reads to complete.
+Rather, we should put waiting query threads to the queue of
+waiting jobs, and let the OS thread do something useful while the i/o
+is processed. In this way we could remove most OS thread switches in
+an i/o-intensive benchmark like TPC-C.
+
+A possibility is to put a user space thread library between the database
+and NT. User space thread libraries might be very fast.
+
+SQL Server 7.0 can be configured to use 'fibers' which are lightweight
+threads in NT. These should be studied.
+
+ Buffer frames and blocks
+ ------------------------
+Following the terminology of Gray and Reuter, we call the memory
+blocks where file pages are loaded buffer frames. For each buffer
+frame there is a control block, or shortly, a block, in the buffer
+control array. The control info which does not need to be stored
+in the file along with the file page, resides in the control block.
+
+ Buffer pool struct
+ ------------------
+The buffer buf_pool contains a single mutex which protects all the
+control data structures of the buf_pool. The content of a buffer frame is
+protected by a separate read-write lock in its control block, though.
+These locks can be locked and unlocked without owning the buf_pool mutex.
+The OS events in the buf_pool struct can be waited for without owning the
+buf_pool mutex.
+
+The buf_pool mutex is a hot-spot in main memory, causing a lot of
+memory bus traffic on multiprocessor systems when processors
+alternately access the mutex. On our Pentium, the mutex is accessed
+maybe every 10 microseconds. We gave up the solution to have mutexes
+for each control block, for instance, because it seemed to be
+complicated.
+
+A solution to reduce mutex contention of the buf_pool mutex is to
+create a separate mutex for the page hash table. On Pentium,
+accessing the hash table takes 2 microseconds, about half
+of the total buf_pool mutex hold time.
+
+ Control blocks
+ --------------
+
+The control block contains, for instance, the bufferfix count
+which is incremented when a thread wants a file page to be fixed
+in a buffer frame. The bufferfix operation does not lock the
+contents of the frame, however. For this purpose, the control
+block contains a read-write lock.
+
+The buffer frames have to be aligned so that the start memory
+address of a frame is divisible by the universal page size, which
+is a power of two.
+
+We intend to make the buffer buf_pool size on-line reconfigurable,
+that is, the buf_pool size can be changed without closing the database.
+Then the database administarator may adjust it to be bigger
+at night, for example. The control block array must
+contain enough control blocks for the maximum buffer buf_pool size
+which is used in the particular database.
+If the buf_pool size is cut, we exploit the virtual memory mechanism of
+the OS, and just refrain from using frames at high addresses. Then the OS
+can swap them to disk.
+
+The control blocks containing file pages are put to a hash table
+according to the file address of the page.
+We could speed up the access to an individual page by using
+"pointer swizzling": we could replace the page references on
+non-leaf index pages by direct pointers to the page, if it exists
+in the buf_pool. We could make a separate hash table where we could
+chain all the page references in non-leaf pages residing in the buf_pool,
+using the page reference as the hash key,
+and at the time of reading of a page update the pointers accordingly.
+Drawbacks of this solution are added complexity and,
+possibly, extra space required on non-leaf pages for memory pointers.
+A simpler solution is just to speed up the hash table mechanism
+in the database, using tables whose size is a power of 2.
+
+ Lists of blocks
+ ---------------
+
+There are several lists of control blocks.
+
+The free list (buf_pool->free) contains blocks which are currently not
+used.
+
+The common LRU list contains all the blocks holding a file page
+except those for which the bufferfix count is non-zero.
+The pages are in the LRU list roughly in the order of the last
+access to the page, so that the oldest pages are at the end of the
+list. We also keep a pointer to near the end of the LRU list,
+which we can use when we want to artificially age a page in the
+buf_pool. This is used if we know that some page is not needed
+again for some time: we insert the block right after the pointer,
+causing it to be replaced sooner than would noramlly be the case.
+Currently this aging mechanism is used for read-ahead mechanism
+of pages, and it can also be used when there is a scan of a full
+table which cannot fit in the memory. Putting the pages near the
+of the LRU list, we make sure that most of the buf_pool stays in the
+main memory, undisturbed.
+
+The unzip_LRU list contains a subset of the common LRU list. The
+blocks on the unzip_LRU list hold a compressed file page and the
+corresponding uncompressed page frame. A block is in unzip_LRU if and
+only if the predicate buf_page_belongs_to_unzip_LRU(&block->page)
+holds. The blocks in unzip_LRU will be in same order as they are in
+the common LRU list. That is, each manipulation of the common LRU
+list will result in the same manipulation of the unzip_LRU list.
+
+The chain of modified blocks (buf_pool->flush_list) contains the blocks
+holding file pages that have been modified in the memory
+but not written to disk yet. The block with the oldest modification
+which has not yet been written to disk is at the end of the chain.
+
+The chain of unmodified compressed blocks (buf_pool->zip_clean)
+contains the control blocks (buf_page_t) of those compressed pages
+that are not in buf_pool->flush_list and for which no uncompressed
+page has been allocated in the buffer pool. The control blocks for
+uncompressed pages are accessible via buf_block_t objects that are
+reachable via buf_pool->chunks[].
+
+The chains of free memory blocks (buf_pool->zip_free[]) are used by
+the buddy allocator (buf0buddy.c) to keep track of currently unused
+memory blocks of size sizeof(buf_page_t)..UNIV_PAGE_SIZE / 2. These
+blocks are inside the UNIV_PAGE_SIZE-sized memory blocks of type
+BUF_BLOCK_MEMORY that the buddy allocator requests from the buffer
+pool. The buddy allocator is solely used for allocating control
+blocks for compressed pages (buf_page_t) and compressed page frames.
+
+ Loading a file page
+ -------------------
+
+First, a victim block for replacement has to be found in the
+buf_pool. It is taken from the free list or searched for from the
+end of the LRU-list. An exclusive lock is reserved for the frame,
+the io_fix field is set in the block fixing the block in buf_pool,
+and the io-operation for loading the page is queued. The io-handler thread
+releases the X-lock on the frame and resets the io_fix field
+when the io operation completes.
+
+A thread may request the above operation using the function
+buf_page_get(). It may then continue to request a lock on the frame.
+The lock is granted when the io-handler releases the x-lock.
+
+ Read-ahead
+ ----------
+
+The read-ahead mechanism is intended to be intelligent and
+isolated from the semantically higher levels of the database
+index management. From the higher level we only need the
+information if a file page has a natural successor or
+predecessor page. On the leaf level of a B-tree index,
+these are the next and previous pages in the natural
+order of the pages.
+
+Let us first explain the read-ahead mechanism when the leafs
+of a B-tree are scanned in an ascending or descending order.
+When a read page is the first time referenced in the buf_pool,
+the buffer manager checks if it is at the border of a so-called
+linear read-ahead area. The tablespace is divided into these
+areas of size 64 blocks, for example. So if the page is at the
+border of such an area, the read-ahead mechanism checks if
+all the other blocks in the area have been accessed in an
+ascending or descending order. If this is the case, the system
+looks at the natural successor or predecessor of the page,
+checks if that is at the border of another area, and in this case
+issues read-requests for all the pages in that area. Maybe
+we could relax the condition that all the pages in the area
+have to be accessed: if data is deleted from a table, there may
+appear holes of unused pages in the area.
+
+A different read-ahead mechanism is used when there appears
+to be a random access pattern to a file.
+If a new page is referenced in the buf_pool, and several pages
+of its random access area (for instance, 32 consecutive pages
+in a tablespace) have recently been referenced, we may predict
+that the whole area may be needed in the near future, and issue
+the read requests for the whole area.
+*/
+
+#ifndef UNIV_HOTBACKUP
+/** Value in microseconds */
+static const int WAIT_FOR_READ = 5000;
+
+/** The buffer buf_pool of the database */
+UNIV_INTERN buf_pool_t* buf_pool = NULL;
+
+/** mutex protecting the buffer pool struct and control blocks, except the
+read-write lock in them */
+UNIV_INTERN mutex_t buf_pool_mutex;
+/** mutex protecting the control blocks of compressed-only pages
+(of type buf_page_t, not buf_block_t) */
+UNIV_INTERN mutex_t buf_pool_zip_mutex;
+
+#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
+static ulint buf_dbg_counter = 0; /*!< This is used to insert validation
+ operations in excution in the
+ debug version */
+/** Flag to forbid the release of the buffer pool mutex.
+Protected by buf_pool_mutex. */
+UNIV_INTERN ulint buf_pool_mutex_exit_forbidden = 0;
+#endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
+#ifdef UNIV_DEBUG
+/** If this is set TRUE, the program prints info whenever
+read-ahead or flush occurs */
+UNIV_INTERN ibool buf_debug_prints = FALSE;
+#endif /* UNIV_DEBUG */
+
+/** A chunk of buffers. The buffer pool is allocated in chunks. */
+struct buf_chunk_struct{
+ ulint mem_size; /*!< allocated size of the chunk */
+ ulint size; /*!< size of frames[] and blocks[] */
+ void* mem; /*!< pointer to the memory area which
+ was allocated for the frames */
+ buf_block_t* blocks; /*!< array of buffer control blocks */
+};
+#endif /* !UNIV_HOTBACKUP */
+
+/********************************************************************//**
+Calculates a page checksum which is stored to the page when it is written
+to a file. Note that we must be careful to calculate the same value on
+32-bit and 64-bit architectures.
+@return checksum */
+UNIV_INTERN
+ulint
+buf_calc_page_new_checksum(
+/*=======================*/
+ const byte* page) /*!< in: buffer page */
+{
+ ulint checksum;
+
+ /* Since the field FIL_PAGE_FILE_FLUSH_LSN, and in versions <= 4.1.x
+ ..._ARCH_LOG_NO, are written outside the buffer pool to the first
+ pages of data files, we have to skip them in the page checksum
+ calculation.
+ We must also skip the field FIL_PAGE_SPACE_OR_CHKSUM where the
+ checksum is stored, and also the last 8 bytes of page because
+ there we store the old formula checksum. */
+
+ checksum = ut_fold_binary(page + FIL_PAGE_OFFSET,
+ FIL_PAGE_FILE_FLUSH_LSN - FIL_PAGE_OFFSET)
+ + ut_fold_binary(page + FIL_PAGE_DATA,
+ UNIV_PAGE_SIZE - FIL_PAGE_DATA
+ - FIL_PAGE_END_LSN_OLD_CHKSUM);
+ checksum = checksum & 0xFFFFFFFFUL;
+
+ return(checksum);
+}
+
+/********************************************************************//**
+In versions < 4.0.14 and < 4.1.1 there was a bug that the checksum only
+looked at the first few bytes of the page. This calculates that old
+checksum.
+NOTE: we must first store the new formula checksum to
+FIL_PAGE_SPACE_OR_CHKSUM before calculating and storing this old checksum
+because this takes that field as an input!
+@return checksum */
+UNIV_INTERN
+ulint
+buf_calc_page_old_checksum(
+/*=======================*/
+ const byte* page) /*!< in: buffer page */
+{
+ ulint checksum;
+
+ checksum = ut_fold_binary(page, FIL_PAGE_FILE_FLUSH_LSN);
+
+ checksum = checksum & 0xFFFFFFFFUL;
+
+ return(checksum);
+}
+
+/********************************************************************//**
+Checks if a page is corrupt.
+@return TRUE if corrupted */
+UNIV_INTERN
+ibool
+buf_page_is_corrupted(
+/*==================*/
+ const byte* read_buf, /*!< in: a database page */
+ ulint zip_size) /*!< in: size of compressed page;
+ 0 for uncompressed pages */
+{
+ ulint checksum_field;
+ ulint old_checksum_field;
+
+ if (UNIV_LIKELY(!zip_size)
+ && memcmp(read_buf + FIL_PAGE_LSN + 4,
+ read_buf + UNIV_PAGE_SIZE
+ - FIL_PAGE_END_LSN_OLD_CHKSUM + 4, 4)) {
+
+ /* Stored log sequence numbers at the start and the end
+ of page do not match */
+
+ return(TRUE);
+ }
+
+#ifndef UNIV_HOTBACKUP
+ if (recv_lsn_checks_on) {
+ ib_uint64_t current_lsn;
+
+ if (log_peek_lsn(¤t_lsn)
+ && current_lsn < mach_read_ull(read_buf + FIL_PAGE_LSN)) {
+ ut_print_timestamp(stderr);
+
+ fprintf(stderr,
+ " InnoDB: Error: page %lu log sequence number"
+ " %llu\n"
+ "InnoDB: is in the future! Current system "
+ "log sequence number %llu.\n"
+ "InnoDB: Your database may be corrupt or "
+ "you may have copied the InnoDB\n"
+ "InnoDB: tablespace but not the InnoDB "
+ "log files. See\n"
+ "InnoDB: " REFMAN "forcing-recovery.html\n"
+ "InnoDB: for more information.\n",
+ (ulong) mach_read_from_4(read_buf
+ + FIL_PAGE_OFFSET),
+ mach_read_ull(read_buf + FIL_PAGE_LSN),
+ current_lsn);
+ }
+ }
+#endif
+
+ /* If we use checksums validation, make additional check before
+ returning TRUE to ensure that the checksum is not equal to
+ BUF_NO_CHECKSUM_MAGIC which might be stored by InnoDB with checksums
+ disabled. Otherwise, skip checksum calculation and return FALSE */
+
+ if (UNIV_LIKELY(srv_use_checksums)) {
+ checksum_field = mach_read_from_4(read_buf
+ + FIL_PAGE_SPACE_OR_CHKSUM);
+
+ if (UNIV_UNLIKELY(zip_size)) {
+ return(checksum_field != BUF_NO_CHECKSUM_MAGIC
+ && checksum_field
+ != page_zip_calc_checksum(read_buf, zip_size));
+ }
+
+ old_checksum_field = mach_read_from_4(
+ read_buf + UNIV_PAGE_SIZE
+ - FIL_PAGE_END_LSN_OLD_CHKSUM);
+
+ /* There are 2 valid formulas for old_checksum_field:
+
+ 1. Very old versions of InnoDB only stored 8 byte lsn to the
+ start and the end of the page.
+
+ 2. Newer InnoDB versions store the old formula checksum
+ there. */
+
+ if (old_checksum_field != mach_read_from_4(read_buf
+ + FIL_PAGE_LSN)
+ && old_checksum_field != BUF_NO_CHECKSUM_MAGIC
+ && old_checksum_field
+ != buf_calc_page_old_checksum(read_buf)) {
+
+ return(TRUE);
+ }
+
+ /* InnoDB versions < 4.0.14 and < 4.1.1 stored the space id
+ (always equal to 0), to FIL_PAGE_SPACE_OR_CHKSUM */
+
+ if (checksum_field != 0
+ && checksum_field != BUF_NO_CHECKSUM_MAGIC
+ && checksum_field
+ != buf_calc_page_new_checksum(read_buf)) {
+
+ return(TRUE);
+ }
+ }
+
+ return(FALSE);
+}
+
+/********************************************************************//**
+Prints a page to stderr. */
+UNIV_INTERN
+void
+buf_page_print(
+/*===========*/
+ const byte* read_buf, /*!< in: a database page */
+ ulint zip_size) /*!< in: compressed page size, or
+ 0 for uncompressed pages */
+{
+#ifndef UNIV_HOTBACKUP
+ dict_index_t* index;
+#endif /* !UNIV_HOTBACKUP */
+ ulint checksum;
+ ulint old_checksum;
+ ulint size = zip_size;
+
+ if (!size) {
+ size = UNIV_PAGE_SIZE;
+ }
+
+ ut_print_timestamp(stderr);
+ fprintf(stderr, " InnoDB: Page dump in ascii and hex (%lu bytes):\n",
+ (ulong) size);
+ ut_print_buf(stderr, read_buf, size);
+ fputs("\nInnoDB: End of page dump\n", stderr);
+
+ if (zip_size) {
+ /* Print compressed page. */
+
+ switch (fil_page_get_type(read_buf)) {
+ case FIL_PAGE_TYPE_ZBLOB:
+ case FIL_PAGE_TYPE_ZBLOB2:
+ checksum = srv_use_checksums
+ ? page_zip_calc_checksum(read_buf, zip_size)
+ : BUF_NO_CHECKSUM_MAGIC;
+ ut_print_timestamp(stderr);
+ fprintf(stderr,
+ " InnoDB: Compressed BLOB page"
+ " checksum %lu, stored %lu\n"
+ "InnoDB: Page lsn %lu %lu\n"
+ "InnoDB: Page number (if stored"
+ " to page already) %lu,\n"
+ "InnoDB: space id (if stored"
+ " to page already) %lu\n",
+ (ulong) checksum,
+ (ulong) mach_read_from_4(
+ read_buf + FIL_PAGE_SPACE_OR_CHKSUM),
+ (ulong) mach_read_from_4(
+ read_buf + FIL_PAGE_LSN),
+ (ulong) mach_read_from_4(
+ read_buf + (FIL_PAGE_LSN + 4)),
+ (ulong) mach_read_from_4(
+ read_buf + FIL_PAGE_OFFSET),
+ (ulong) mach_read_from_4(
+ read_buf
+ + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID));
+ return;
+ default:
+ ut_print_timestamp(stderr);
+ fprintf(stderr,
+ " InnoDB: unknown page type %lu,"
+ " assuming FIL_PAGE_INDEX\n",
+ fil_page_get_type(read_buf));
+ /* fall through */
+ case FIL_PAGE_INDEX:
+ checksum = srv_use_checksums
+ ? page_zip_calc_checksum(read_buf, zip_size)
+ : BUF_NO_CHECKSUM_MAGIC;
+
+ ut_print_timestamp(stderr);
+ fprintf(stderr,
+ " InnoDB: Compressed page checksum %lu,"
+ " stored %lu\n"
+ "InnoDB: Page lsn %lu %lu\n"
+ "InnoDB: Page number (if stored"
+ " to page already) %lu,\n"
+ "InnoDB: space id (if stored"
+ " to page already) %lu\n",
+ (ulong) checksum,
+ (ulong) mach_read_from_4(
+ read_buf + FIL_PAGE_SPACE_OR_CHKSUM),
+ (ulong) mach_read_from_4(
+ read_buf + FIL_PAGE_LSN),
+ (ulong) mach_read_from_4(
+ read_buf + (FIL_PAGE_LSN + 4)),
+ (ulong) mach_read_from_4(
+ read_buf + FIL_PAGE_OFFSET),
+ (ulong) mach_read_from_4(
+ read_buf
+ + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID));
+ return;
+ case FIL_PAGE_TYPE_XDES:
+ /* This is an uncompressed page. */
+ break;
+ }
+ }
+
+ checksum = srv_use_checksums
+ ? buf_calc_page_new_checksum(read_buf) : BUF_NO_CHECKSUM_MAGIC;
+ old_checksum = srv_use_checksums
+ ? buf_calc_page_old_checksum(read_buf) : BUF_NO_CHECKSUM_MAGIC;
+
+ ut_print_timestamp(stderr);
+ fprintf(stderr,
+ " InnoDB: Page checksum %lu, prior-to-4.0.14-form"
+ " checksum %lu\n"
+ "InnoDB: stored checksum %lu, prior-to-4.0.14-form"
+ " stored checksum %lu\n"
+ "InnoDB: Page lsn %lu %lu, low 4 bytes of lsn"
+ " at page end %lu\n"
+ "InnoDB: Page number (if stored to page already) %lu,\n"
+ "InnoDB: space id (if created with >= MySQL-4.1.1"
+ " and stored already) %lu\n",
+ (ulong) checksum, (ulong) old_checksum,
+ (ulong) mach_read_from_4(read_buf + FIL_PAGE_SPACE_OR_CHKSUM),
+ (ulong) mach_read_from_4(read_buf + UNIV_PAGE_SIZE
+ - FIL_PAGE_END_LSN_OLD_CHKSUM),
+ (ulong) mach_read_from_4(read_buf + FIL_PAGE_LSN),
+ (ulong) mach_read_from_4(read_buf + FIL_PAGE_LSN + 4),
+ (ulong) mach_read_from_4(read_buf + UNIV_PAGE_SIZE
+ - FIL_PAGE_END_LSN_OLD_CHKSUM + 4),
+ (ulong) mach_read_from_4(read_buf + FIL_PAGE_OFFSET),
+ (ulong) mach_read_from_4(read_buf
+ + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID));
+
+#ifndef UNIV_HOTBACKUP
+ if (mach_read_from_2(read_buf + TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_TYPE)
+ == TRX_UNDO_INSERT) {
+ fprintf(stderr,
+ "InnoDB: Page may be an insert undo log page\n");
+ } else if (mach_read_from_2(read_buf + TRX_UNDO_PAGE_HDR
+ + TRX_UNDO_PAGE_TYPE)
+ == TRX_UNDO_UPDATE) {
+ fprintf(stderr,
+ "InnoDB: Page may be an update undo log page\n");
+ }
+#endif /* !UNIV_HOTBACKUP */
+
+ switch (fil_page_get_type(read_buf)) {
+ case FIL_PAGE_INDEX:
+ fprintf(stderr,
+ "InnoDB: Page may be an index page where"
+ " index id is %lu %lu\n",
+ (ulong) ut_dulint_get_high(
+ btr_page_get_index_id(read_buf)),
+ (ulong) ut_dulint_get_low(
+ btr_page_get_index_id(read_buf)));
+#ifndef UNIV_HOTBACKUP
+ index = dict_index_find_on_id_low(
+ btr_page_get_index_id(read_buf));
+ if (index) {
+ fputs("InnoDB: (", stderr);
+ dict_index_name_print(stderr, NULL, index);
+ fputs(")\n", stderr);
+ }
+#endif /* !UNIV_HOTBACKUP */
+ break;
+ case FIL_PAGE_INODE:
+ fputs("InnoDB: Page may be an 'inode' page\n", stderr);
+ break;
+ case FIL_PAGE_IBUF_FREE_LIST:
+ fputs("InnoDB: Page may be an insert buffer free list page\n",
+ stderr);
+ break;
+ case FIL_PAGE_TYPE_ALLOCATED:
+ fputs("InnoDB: Page may be a freshly allocated page\n",
+ stderr);
+ break;
+ case FIL_PAGE_IBUF_BITMAP:
+ fputs("InnoDB: Page may be an insert buffer bitmap page\n",
+ stderr);
+ break;
+ case FIL_PAGE_TYPE_SYS:
+ fputs("InnoDB: Page may be a system page\n",
+ stderr);
+ break;
+ case FIL_PAGE_TYPE_TRX_SYS:
+ fputs("InnoDB: Page may be a transaction system page\n",
+ stderr);
+ break;
+ case FIL_PAGE_TYPE_FSP_HDR:
+ fputs("InnoDB: Page may be a file space header page\n",
+ stderr);
+ break;
+ case FIL_PAGE_TYPE_XDES:
+ fputs("InnoDB: Page may be an extent descriptor page\n",
+ stderr);
+ break;
+ case FIL_PAGE_TYPE_BLOB:
+ fputs("InnoDB: Page may be a BLOB page\n",
+ stderr);
+ break;
+ case FIL_PAGE_TYPE_ZBLOB:
+ case FIL_PAGE_TYPE_ZBLOB2:
+ fputs("InnoDB: Page may be a compressed BLOB page\n",
+ stderr);
+ break;
+ }
+}
+
+#ifndef UNIV_HOTBACKUP
+/********************************************************************//**
+Initializes a buffer control block when the buf_pool is created. */
+static
+void
+buf_block_init(
+/*===========*/
+ buf_block_t* block, /*!< in: pointer to control block */
+ byte* frame) /*!< in: pointer to buffer frame */
+{
+ UNIV_MEM_DESC(frame, UNIV_PAGE_SIZE, block);
+
+ block->frame = frame;
+
+ block->page.state = BUF_BLOCK_NOT_USED;
+ block->page.buf_fix_count = 0;
+ block->page.io_fix = BUF_IO_NONE;
+
+ block->modify_clock = 0;
+
+#ifdef UNIV_DEBUG_FILE_ACCESSES
+ block->page.file_page_was_freed = FALSE;
+#endif /* UNIV_DEBUG_FILE_ACCESSES */
+
+ block->check_index_page_at_flush = FALSE;
+ block->index = NULL;
+
+#ifdef UNIV_DEBUG
+ block->page.in_page_hash = FALSE;
+ block->page.in_zip_hash = FALSE;
+ block->page.in_flush_list = FALSE;
+ block->page.in_free_list = FALSE;
+ block->page.in_LRU_list = FALSE;
+ block->in_unzip_LRU_list = FALSE;
+#endif /* UNIV_DEBUG */
+#if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
+ block->n_pointers = 0;
+#endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
+ page_zip_des_init(&block->page.zip);
+
+ mutex_create(&block->mutex, SYNC_BUF_BLOCK);
+
+ rw_lock_create(&block->lock, SYNC_LEVEL_VARYING);
+ ut_ad(rw_lock_validate(&(block->lock)));
+
+#ifdef UNIV_SYNC_DEBUG
+ rw_lock_create(&block->debug_latch, SYNC_NO_ORDER_CHECK);
+#endif /* UNIV_SYNC_DEBUG */
+}
+
+/********************************************************************//**
+Allocates a chunk of buffer frames.
+@return chunk, or NULL on failure */
+static
+buf_chunk_t*
+buf_chunk_init(
+/*===========*/
+ buf_chunk_t* chunk, /*!< out: chunk of buffers */
+ ulint mem_size) /*!< in: requested size in bytes */
+{
+ buf_block_t* block;
+ byte* frame;
+ ulint i;
+
+ /* Round down to a multiple of page size,
+ although it already should be. */
+ mem_size = ut_2pow_round(mem_size, UNIV_PAGE_SIZE);
+ /* Reserve space for the block descriptors. */
+ mem_size += ut_2pow_round((mem_size / UNIV_PAGE_SIZE) * (sizeof *block)
+ + (UNIV_PAGE_SIZE - 1), UNIV_PAGE_SIZE);
+
+ chunk->mem_size = mem_size;
+ chunk->mem = os_mem_alloc_large(&chunk->mem_size);
+
+ if (UNIV_UNLIKELY(chunk->mem == NULL)) {
+
+ return(NULL);
+ }
+
+ /* Allocate the block descriptors from
+ the start of the memory block. */
+ chunk->blocks = chunk->mem;
+
+ /* Align a pointer to the first frame. Note that when
+ os_large_page_size is smaller than UNIV_PAGE_SIZE,
+ we may allocate one fewer block than requested. When
+ it is bigger, we may allocate more blocks than requested. */
+
+ frame = ut_align(chunk->mem, UNIV_PAGE_SIZE);
+ chunk->size = chunk->mem_size / UNIV_PAGE_SIZE
+ - (frame != chunk->mem);
+
+ /* Subtract the space needed for block descriptors. */
+ {
+ ulint size = chunk->size;
+
+ while (frame < (byte*) (chunk->blocks + size)) {
+ frame += UNIV_PAGE_SIZE;
+ size--;
+ }
+
+ chunk->size = size;
+ }
+
+ /* Init block structs and assign frames for them. Then we
+ assign the frames to the first blocks (we already mapped the
+ memory above). */
+
+ block = chunk->blocks;
+
+ for (i = chunk->size; i--; ) {
+
+ buf_block_init(block, frame);
+
+#ifdef HAVE_purify
+ /* Wipe contents of frame to eliminate a Purify warning */
+ memset(block->frame, '\0', UNIV_PAGE_SIZE);
+#endif
+ /* Add the block to the free list */
+ UT_LIST_ADD_LAST(list, buf_pool->free, (&block->page));
+ ut_d(block->page.in_free_list = TRUE);
+
+ block++;
+ frame += UNIV_PAGE_SIZE;
+ }
+
+ return(chunk);
+}
+
+#ifdef UNIV_DEBUG
+/*********************************************************************//**
+Finds a block in the given buffer chunk that points to a
+given compressed page.
+@return buffer block pointing to the compressed page, or NULL */
+static
+buf_block_t*
+buf_chunk_contains_zip(
+/*===================*/
+ buf_chunk_t* chunk, /*!< in: chunk being checked */
+ const void* data) /*!< in: pointer to compressed page */
+{
+ buf_block_t* block;
+ ulint i;
+
+ ut_ad(buf_pool);
+ ut_ad(buf_pool_mutex_own());
+
+ block = chunk->blocks;
+
+ for (i = chunk->size; i--; block++) {
+ if (block->page.zip.data == data) {
+
+ return(block);
+ }
+ }
+
+ return(NULL);
+}
+
+/*********************************************************************//**
+Finds a block in the buffer pool that points to a
+given compressed page.
+@return buffer block pointing to the compressed page, or NULL */
+UNIV_INTERN
+buf_block_t*
+buf_pool_contains_zip(
+/*==================*/
+ const void* data) /*!< in: pointer to compressed page */
+{
+ ulint n;
+ buf_chunk_t* chunk = buf_pool->chunks;
+
+ for (n = buf_pool->n_chunks; n--; chunk++) {
+ buf_block_t* block = buf_chunk_contains_zip(chunk, data);
+
+ if (block) {
+ return(block);
+ }
+ }
+
+ return(NULL);
+}
+#endif /* UNIV_DEBUG */
+
+/*********************************************************************//**
+Checks that all file pages in the buffer chunk are in a replaceable state.
+@return address of a non-free block, or NULL if all freed */
+static
+const buf_block_t*
+buf_chunk_not_freed(
+/*================*/
+ buf_chunk_t* chunk) /*!< in: chunk being checked */
+{
+ buf_block_t* block;
+ ulint i;
+
+ ut_ad(buf_pool);
+ ut_ad(buf_pool_mutex_own());
+
+ block = chunk->blocks;
+
+ for (i = chunk->size; i--; block++) {
+ mutex_enter(&block->mutex);
+
+ if (buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE
+ && !buf_flush_ready_for_replace(&block->page)) {
+
+ mutex_exit(&block->mutex);
+ return(block);
+ }
+
+ mutex_exit(&block->mutex);
+ }
+
+ return(NULL);
+}
+
+/*********************************************************************//**
+Checks that all blocks in the buffer chunk are in BUF_BLOCK_NOT_USED state.
+@return TRUE if all freed */
+static
+ibool
+buf_chunk_all_free(
+/*===============*/
+ const buf_chunk_t* chunk) /*!< in: chunk being checked */
+{
+ const buf_block_t* block;
+ ulint i;
+
+ ut_ad(buf_pool);
+ ut_ad(buf_pool_mutex_own());
+
+ block = chunk->blocks;
+
+ for (i = chunk->size; i--; block++) {
+
+ if (buf_block_get_state(block) != BUF_BLOCK_NOT_USED) {
+
+ return(FALSE);
+ }
+ }
+
+ return(TRUE);
+}
+
+/********************************************************************//**
+Frees a chunk of buffer frames. */
+static
+void
+buf_chunk_free(
+/*===========*/
+ buf_chunk_t* chunk) /*!< out: chunk of buffers */
+{
+ buf_block_t* block;
+ const buf_block_t* block_end;
+
+ ut_ad(buf_pool_mutex_own());
+
+ block_end = chunk->blocks + chunk->size;
+
+ for (block = chunk->blocks; block < block_end; block++) {
+ ut_a(buf_block_get_state(block) == BUF_BLOCK_NOT_USED);
+ ut_a(!block->page.zip.data);
+
+ ut_ad(!block->page.in_LRU_list);
+ ut_ad(!block->in_unzip_LRU_list);
+ ut_ad(!block->page.in_flush_list);
+ /* Remove the block from the free list. */
+ ut_ad(block->page.in_free_list);
+ UT_LIST_REMOVE(list, buf_pool->free, (&block->page));
+
+ /* Free the latches. */
+ mutex_free(&block->mutex);
+ rw_lock_free(&block->lock);
+#ifdef UNIV_SYNC_DEBUG
+ rw_lock_free(&block->debug_latch);
+#endif /* UNIV_SYNC_DEBUG */
+ UNIV_MEM_UNDESC(block);
+ }
+
+ os_mem_free_large(chunk->mem, chunk->mem_size);
+}
+
+/********************************************************************//**
+Creates the buffer pool.
+@return own: buf_pool object, NULL if not enough memory or error */
+UNIV_INTERN
+buf_pool_t*
+buf_pool_init(void)
+/*===============*/
+{
+ buf_chunk_t* chunk;
+ ulint i;
+
+ buf_pool = mem_zalloc(sizeof(buf_pool_t));
+
+ /* 1. Initialize general fields
+ ------------------------------- */
+ mutex_create(&buf_pool_mutex, SYNC_BUF_POOL);
+ mutex_create(&buf_pool_zip_mutex, SYNC_BUF_BLOCK);
+
+ buf_pool_mutex_enter();
+
+ buf_pool->n_chunks = 1;
+ buf_pool->chunks = chunk = mem_alloc(sizeof *chunk);
+
+ UT_LIST_INIT(buf_pool->free);
+
+ if (!buf_chunk_init(chunk, srv_buf_pool_size)) {
+ mem_free(chunk);
+ mem_free(buf_pool);
+ buf_pool = NULL;
+ return(NULL);
+ }
+
+ srv_buf_pool_old_size = srv_buf_pool_size;
+ buf_pool->curr_size = chunk->size;
+ srv_buf_pool_curr_size = buf_pool->curr_size * UNIV_PAGE_SIZE;
+
+ buf_pool->page_hash = hash_create(2 * buf_pool->curr_size);
+ buf_pool->zip_hash = hash_create(2 * buf_pool->curr_size);
+
+ buf_pool->last_printout_time = time(NULL);
+
+ /* 2. Initialize flushing fields
+ -------------------------------- */
+
+ for (i = BUF_FLUSH_LRU; i < BUF_FLUSH_N_TYPES; i++) {
+ buf_pool->no_flush[i] = os_event_create(NULL);
+ }
+
+ buf_pool->ulint_clock = 1;
+
+ /* 3. Initialize LRU fields
+ --------------------------- */
+ /* All fields are initialized by mem_zalloc(). */
+
+ buf_pool_mutex_exit();
+
+ btr_search_sys_create(buf_pool->curr_size
+ * UNIV_PAGE_SIZE / sizeof(void*) / 64);
+
+ /* 4. Initialize the buddy allocator fields */
+ /* All fields are initialized by mem_zalloc(). */
+
+ return(buf_pool);
+}
+
+/********************************************************************//**
+Frees the buffer pool at shutdown. This must not be invoked before
+freeing all mutexes. */
+UNIV_INTERN
+void
+buf_pool_free(void)
+/*===============*/
+{
+ buf_chunk_t* chunk;
+ buf_chunk_t* chunks;
+
+ chunks = buf_pool->chunks;
+ chunk = chunks + buf_pool->n_chunks;
+
+ while (--chunk >= chunks) {
+ /* Bypass the checks of buf_chunk_free(), since they
+ would fail at shutdown. */
+ os_mem_free_large(chunk->mem, chunk->mem_size);
+ }
+
+ buf_pool->n_chunks = 0;
+}
+
+/********************************************************************//**
+Drops the adaptive hash index. To prevent a livelock, this function
+is only to be called while holding btr_search_latch and while
+btr_search_enabled == FALSE. */
+UNIV_INTERN
+void
+buf_pool_drop_hash_index(void)
+/*==========================*/
+{
+ ibool released_search_latch;
+
+#ifdef UNIV_SYNC_DEBUG
+ ut_ad(rw_lock_own(&btr_search_latch, RW_LOCK_EX));
+#endif /* UNIV_SYNC_DEBUG */
+ ut_ad(!btr_search_enabled);
+
+ do {
+ buf_chunk_t* chunks = buf_pool->chunks;
+ buf_chunk_t* chunk = chunks + buf_pool->n_chunks;
+
+ released_search_latch = FALSE;
+
+ while (--chunk >= chunks) {
+ buf_block_t* block = chunk->blocks;
+ ulint i = chunk->size;
+
+ for (; i--; block++) {
+ /* block->is_hashed cannot be modified
+ when we have an x-latch on btr_search_latch;
+ see the comment in buf0buf.h */
+
+ if (!block->is_hashed) {
+ continue;
+ }
+
+ /* To follow the latching order, we
+ have to release btr_search_latch
+ before acquiring block->latch. */
+ rw_lock_x_unlock(&btr_search_latch);
+ /* When we release the search latch,
+ we must rescan all blocks, because
+ some may become hashed again. */
+ released_search_latch = TRUE;
+
+ rw_lock_x_lock(&block->lock);
+
+ /* This should be guaranteed by the
+ callers, which will be holding
+ btr_search_enabled_mutex. */
+ ut_ad(!btr_search_enabled);
+
+ /* Because we did not buffer-fix the
+ block by calling buf_block_get_gen(),
+ it is possible that the block has been
+ allocated for some other use after
+ btr_search_latch was released above.
+ We do not care which file page the
+ block is mapped to. All we want to do
+ is to drop any hash entries referring
+ to the page. */
+
+ /* It is possible that
+ block->page.state != BUF_FILE_PAGE.
+ Even that does not matter, because
+ btr_search_drop_page_hash_index() will
+ check block->is_hashed before doing
+ anything. block->is_hashed can only
+ be set on uncompressed file pages. */
+
+ btr_search_drop_page_hash_index(block);
+
+ rw_lock_x_unlock(&block->lock);
+
+ rw_lock_x_lock(&btr_search_latch);
+
+ ut_ad(!btr_search_enabled);
+ }
+ }
+ } while (released_search_latch);
+}
+
+/********************************************************************//**
+Relocate a buffer control block. Relocates the block on the LRU list
+and in buf_pool->page_hash. Does not relocate bpage->list.
+The caller must take care of relocating bpage->list. */
+UNIV_INTERN
+void
+buf_relocate(
+/*=========*/
+ buf_page_t* bpage, /*!< in/out: control block being relocated;
+ buf_page_get_state(bpage) must be
+ BUF_BLOCK_ZIP_DIRTY or BUF_BLOCK_ZIP_PAGE */
+ buf_page_t* dpage) /*!< in/out: destination control block */
+{
+ buf_page_t* b;
+ ulint fold;
+
+ ut_ad(buf_pool_mutex_own());
+ ut_ad(mutex_own(buf_page_get_mutex(bpage)));
+ ut_a(buf_page_get_io_fix(bpage) == BUF_IO_NONE);
+ ut_a(bpage->buf_fix_count == 0);
+ ut_ad(bpage->in_LRU_list);
+ ut_ad(!bpage->in_zip_hash);
+ ut_ad(bpage->in_page_hash);
+ ut_ad(bpage == buf_page_hash_get(bpage->space, bpage->offset));
+#ifdef UNIV_DEBUG
+ switch (buf_page_get_state(bpage)) {
+ case BUF_BLOCK_ZIP_FREE:
+ case BUF_BLOCK_NOT_USED:
+ case BUF_BLOCK_READY_FOR_USE:
+ case BUF_BLOCK_FILE_PAGE:
+ case BUF_BLOCK_MEMORY:
+ case BUF_BLOCK_REMOVE_HASH:
+ ut_error;
+ case BUF_BLOCK_ZIP_DIRTY:
+ case BUF_BLOCK_ZIP_PAGE:
+ break;
+ }
+#endif /* UNIV_DEBUG */
+
+ memcpy(dpage, bpage, sizeof *dpage);
+
+ ut_d(bpage->in_LRU_list = FALSE);
+ ut_d(bpage->in_page_hash = FALSE);
+
+ /* relocate buf_pool->LRU */
+ b = UT_LIST_GET_PREV(LRU, bpage);
+ UT_LIST_REMOVE(LRU, buf_pool->LRU, bpage);
+
+ if (b) {
+ UT_LIST_INSERT_AFTER(LRU, buf_pool->LRU, b, dpage);
+ } else {
+ UT_LIST_ADD_FIRST(LRU, buf_pool->LRU, dpage);
+ }
+
+ if (UNIV_UNLIKELY(buf_pool->LRU_old == bpage)) {
+ buf_pool->LRU_old = dpage;
+#ifdef UNIV_LRU_DEBUG
+ /* buf_pool->LRU_old must be the first item in the LRU list
+ whose "old" flag is set. */
+ ut_a(!UT_LIST_GET_PREV(LRU, buf_pool->LRU_old)
+ || !UT_LIST_GET_PREV(LRU, buf_pool->LRU_old)->old);
+ ut_a(!UT_LIST_GET_NEXT(LRU, buf_pool->LRU_old)
+ || UT_LIST_GET_NEXT(LRU, buf_pool->LRU_old)->old);
+#endif /* UNIV_LRU_DEBUG */
+ }
+
+ ut_d(UT_LIST_VALIDATE(LRU, buf_page_t, buf_pool->LRU,
+ ut_ad(ut_list_node_313->in_LRU_list)));
+
+ /* relocate buf_pool->page_hash */
+ fold = buf_page_address_fold(bpage->space, bpage->offset);
+
+ HASH_DELETE(buf_page_t, hash, buf_pool->page_hash, fold, bpage);
+ HASH_INSERT(buf_page_t, hash, buf_pool->page_hash, fold, dpage);
+
+ UNIV_MEM_INVALID(bpage, sizeof *bpage);
+}
+
+/********************************************************************//**
+Shrinks the buffer pool. */
+static
+void
+buf_pool_shrink(
+/*============*/
+ ulint chunk_size) /*!< in: number of pages to remove */
+{
+ buf_chunk_t* chunks;
+ buf_chunk_t* chunk;
+ ulint max_size;
+ ulint max_free_size;
+ buf_chunk_t* max_chunk;
+ buf_chunk_t* max_free_chunk;
+
+ ut_ad(!buf_pool_mutex_own());
+
+try_again:
+ btr_search_disable(); /* Empty the adaptive hash index again */
+ buf_pool_mutex_enter();
+
+shrink_again:
+ if (buf_pool->n_chunks <= 1) {
+
+ /* Cannot shrink if there is only one chunk */
+ goto func_done;
+ }
+
+ /* Search for the largest free chunk
+ not larger than the size difference */
+ chunks = buf_pool->chunks;
+ chunk = chunks + buf_pool->n_chunks;
+ max_size = max_free_size = 0;
+ max_chunk = max_free_chunk = NULL;
+
+ while (--chunk >= chunks) {
+ if (chunk->size <= chunk_size
+ && chunk->size > max_free_size) {
+ if (chunk->size > max_size) {
+ max_size = chunk->size;
+ max_chunk = chunk;
+ }
+
+ if (buf_chunk_all_free(chunk)) {
+ max_free_size = chunk->size;
+ max_free_chunk = chunk;
+ }
+ }
+ }
+
+ if (!max_free_size) {
+
+ ulint dirty = 0;
+ ulint nonfree = 0;
+ buf_block_t* block;
+ buf_block_t* bend;
+
+ /* Cannot shrink: try again later
+ (do not assign srv_buf_pool_old_size) */
+ if (!max_chunk) {
+
+ goto func_exit;
+ }
+
+ block = max_chunk->blocks;
+ bend = block + max_chunk->size;
+
+ /* Move the blocks of chunk to the end of the
+ LRU list and try to flush them. */
+ for (; block < bend; block++) {
+ switch (buf_block_get_state(block)) {
+ case BUF_BLOCK_NOT_USED:
+ continue;
+ case BUF_BLOCK_FILE_PAGE:
+ break;
+ default:
+ nonfree++;
+ continue;
+ }
+
+ mutex_enter(&block->mutex);
+ /* The following calls will temporarily
+ release block->mutex and buf_pool_mutex.
+ Therefore, we have to always retry,
+ even if !dirty && !nonfree. */
+
+ if (!buf_flush_ready_for_replace(&block->page)) {
+
+ buf_LRU_make_block_old(&block->page);
+ dirty++;
+ } else if (buf_LRU_free_block(&block->page, TRUE, NULL)
+ != BUF_LRU_FREED) {
+ nonfree++;
+ }
+
+ mutex_exit(&block->mutex);
+ }
+
+ buf_pool_mutex_exit();
+
+ /* Request for a flush of the chunk if it helps.
+ Do not flush if there are non-free blocks, since
+ flushing will not make the chunk freeable. */
+ if (nonfree) {
+ /* Avoid busy-waiting. */
+ os_thread_sleep(100000);
+ } else if (dirty
+ && buf_flush_batch(BUF_FLUSH_LRU, dirty, 0)
+ == ULINT_UNDEFINED) {
+
+ buf_flush_wait_batch_end(BUF_FLUSH_LRU);
+ }
+
+ goto try_again;
+ }
+
+ max_size = max_free_size;
+ max_chunk = max_free_chunk;
+
+ srv_buf_pool_old_size = srv_buf_pool_size;
+
+ /* Rewrite buf_pool->chunks. Copy everything but max_chunk. */
+ chunks = mem_alloc((buf_pool->n_chunks - 1) * sizeof *chunks);
+ memcpy(chunks, buf_pool->chunks,
+ (max_chunk - buf_pool->chunks) * sizeof *chunks);
+ memcpy(chunks + (max_chunk - buf_pool->chunks),
+ max_chunk + 1,
+ buf_pool->chunks + buf_pool->n_chunks
+ - (max_chunk + 1));
+ ut_a(buf_pool->curr_size > max_chunk->size);
+ buf_pool->curr_size -= max_chunk->size;
+ srv_buf_pool_curr_size = buf_pool->curr_size * UNIV_PAGE_SIZE;
+ chunk_size -= max_chunk->size;
+ buf_chunk_free(max_chunk);
+ mem_free(buf_pool->chunks);
+ buf_pool->chunks = chunks;
+ buf_pool->n_chunks--;
+
+ /* Allow a slack of one megabyte. */
+ if (chunk_size > 1048576 / UNIV_PAGE_SIZE) {
+
+ goto shrink_again;
+ }
+
+func_done:
+ srv_buf_pool_old_size = srv_buf_pool_size;
+func_exit:
+ buf_pool_mutex_exit();
+ btr_search_enable();
+}
+
+/********************************************************************//**
+Rebuild buf_pool->page_hash. */
+static
+void
+buf_pool_page_hash_rebuild(void)
+/*============================*/
+{
+ ulint i;
+ ulint n_chunks;
+ buf_chunk_t* chunk;
+ hash_table_t* page_hash;
+ hash_table_t* zip_hash;
+ buf_page_t* b;
+
+ buf_pool_mutex_enter();
+
+ /* Free, create, and populate the hash table. */
+ hash_table_free(buf_pool->page_hash);
+ buf_pool->page_hash = page_hash = hash_create(2 * buf_pool->curr_size);
+ zip_hash = hash_create(2 * buf_pool->curr_size);
+
+ HASH_MIGRATE(buf_pool->zip_hash, zip_hash, buf_page_t, hash,
+ BUF_POOL_ZIP_FOLD_BPAGE);
+
+ hash_table_free(buf_pool->zip_hash);
+ buf_pool->zip_hash = zip_hash;
+
+ /* Insert the uncompressed file pages to buf_pool->page_hash. */
+
+ chunk = buf_pool->chunks;
+ n_chunks = buf_pool->n_chunks;
+
+ for (i = 0; i < n_chunks; i++, chunk++) {
+ ulint j;
+ buf_block_t* block = chunk->blocks;
+
+ for (j = 0; j < chunk->size; j++, block++) {
+ if (buf_block_get_state(block)
+ == BUF_BLOCK_FILE_PAGE) {
+ ut_ad(!block->page.in_zip_hash);
+ ut_ad(block->page.in_page_hash);
+
+ HASH_INSERT(buf_page_t, hash, page_hash,
+ buf_page_address_fold(
+ block->page.space,
+ block->page.offset),
+ &block->page);
+ }
+ }
+ }
+
+ /* Insert the compressed-only pages to buf_pool->page_hash.
+ All such blocks are either in buf_pool->zip_clean or
+ in buf_pool->flush_list. */
+
+ for (b = UT_LIST_GET_FIRST(buf_pool->zip_clean); b;
+ b = UT_LIST_GET_NEXT(list, b)) {
+ ut_a(buf_page_get_state(b) == BUF_BLOCK_ZIP_PAGE);
+ ut_ad(!b->in_flush_list);
+ ut_ad(b->in_LRU_list);
+ ut_ad(b->in_page_hash);
+ ut_ad(!b->in_zip_hash);
+
+ HASH_INSERT(buf_page_t, hash, page_hash,
+ buf_page_address_fold(b->space, b->offset), b);
+ }
+
+ for (b = UT_LIST_GET_FIRST(buf_pool->flush_list); b;
+ b = UT_LIST_GET_NEXT(list, b)) {
+ ut_ad(b->in_flush_list);
+ ut_ad(b->in_LRU_list);
+ ut_ad(b->in_page_hash);
+ ut_ad(!b->in_zip_hash);
+
+ switch (buf_page_get_state(b)) {
+ case BUF_BLOCK_ZIP_DIRTY:
+ HASH_INSERT(buf_page_t, hash, page_hash,
+ buf_page_address_fold(b->space,
+ b->offset), b);
+ break;
+ case BUF_BLOCK_FILE_PAGE:
+ /* uncompressed page */
+ break;
+ case BUF_BLOCK_ZIP_FREE:
+ case BUF_BLOCK_ZIP_PAGE:
+ case BUF_BLOCK_NOT_USED:
+ case BUF_BLOCK_READY_FOR_USE:
+ case BUF_BLOCK_MEMORY:
+ case BUF_BLOCK_REMOVE_HASH:
+ ut_error;
+ break;
+ }
+ }
+
+ buf_pool_mutex_exit();
+}
+
+/********************************************************************//**
+Resizes the buffer pool. */
+UNIV_INTERN
+void
+buf_pool_resize(void)
+/*=================*/
+{
+ buf_pool_mutex_enter();
+
+ if (srv_buf_pool_old_size == srv_buf_pool_size) {
+
+ buf_pool_mutex_exit();
+ return;
+ }
+
+ if (srv_buf_pool_curr_size + 1048576 > srv_buf_pool_size) {
+
+ buf_pool_mutex_exit();
+
+ /* Disable adaptive hash indexes and empty the index
+ in order to free up memory in the buffer pool chunks. */
+ buf_pool_shrink((srv_buf_pool_curr_size - srv_buf_pool_size)
+ / UNIV_PAGE_SIZE);
+ } else if (srv_buf_pool_curr_size + 1048576 < srv_buf_pool_size) {
+
+ /* Enlarge the buffer pool by at least one megabyte */
+
+ ulint mem_size
+ = srv_buf_pool_size - srv_buf_pool_curr_size;
+ buf_chunk_t* chunks;
+ buf_chunk_t* chunk;
+
+ chunks = mem_alloc((buf_pool->n_chunks + 1) * sizeof *chunks);
+
+ memcpy(chunks, buf_pool->chunks, buf_pool->n_chunks
+ * sizeof *chunks);
+
+ chunk = &chunks[buf_pool->n_chunks];
+
+ if (!buf_chunk_init(chunk, mem_size)) {
+ mem_free(chunks);
+ } else {
+ buf_pool->curr_size += chunk->size;
+ srv_buf_pool_curr_size = buf_pool->curr_size
+ * UNIV_PAGE_SIZE;
+ mem_free(buf_pool->chunks);
+ buf_pool->chunks = chunks;
+ buf_pool->n_chunks++;
+ }
+
+ srv_buf_pool_old_size = srv_buf_pool_size;
+ buf_pool_mutex_exit();
+ }
+
+ buf_pool_page_hash_rebuild();
+}
+
+/********************************************************************//**
+Moves the block to the start of the LRU list if there is a danger
+that the block would drift out of the buffer pool. */
+UNIV_INLINE
+void
+buf_block_make_young(
+/*=================*/
+ buf_page_t* bpage) /*!< in: block to make younger */
+{
+ ut_ad(!buf_pool_mutex_own());
+
+ /* 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_page_peek_if_too_old(bpage)) {
+
+ buf_pool_mutex_enter();
+ /* There has been freeing activity in the LRU list:
+ best to move to the head of the LRU list */
+
+ buf_LRU_make_block_young(bpage);
+ buf_pool_mutex_exit();
+ }
+}
+
+/********************************************************************//**
+Moves a page to the start of the buffer pool LRU list. This high-level
+function can be used to prevent an important page from from slipping out of
+the buffer pool. */
+UNIV_INTERN
+void
+buf_page_make_young(
+/*================*/
+ buf_page_t* bpage) /*!< in: buffer block of a file page */
+{
+ buf_pool_mutex_enter();
+
+ ut_a(buf_page_in_file(bpage));
+
+ buf_LRU_make_block_young(bpage);
+
+ buf_pool_mutex_exit();
+}
+
+/********************************************************************//**
+Resets the check_index_page_at_flush field of a page if found in the buffer
+pool. */
+UNIV_INTERN
+void
+buf_reset_check_index_page_at_flush(
+/*================================*/
+ ulint space, /*!< in: space id */
+ ulint offset) /*!< in: page number */
+{
+ buf_block_t* block;
+
+ buf_pool_mutex_enter();
+
+ block = (buf_block_t*) buf_page_hash_get(space, offset);
+
+ if (block && buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE) {
+ block->check_index_page_at_flush = FALSE;
+ }
+
+ buf_pool_mutex_exit();
+}
+
+/********************************************************************//**
+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
+pool if it is found there.
+@return TRUE if page hash index is built in search system */
+UNIV_INTERN
+ibool
+buf_page_peek_if_search_hashed(
+/*===========================*/
+ ulint space, /*!< in: space id */
+ ulint offset) /*!< in: page number */
+{
+ buf_block_t* block;
+ ibool is_hashed;
+
+ buf_pool_mutex_enter();
+
+ block = (buf_block_t*) buf_page_hash_get(space, offset);
+
+ if (!block || buf_block_get_state(block) != BUF_BLOCK_FILE_PAGE) {
+ is_hashed = FALSE;
+ } else {
+ is_hashed = block->is_hashed;
+ }
+
+ buf_pool_mutex_exit();
+
+ return(is_hashed);
+}
+
+#ifdef UNIV_DEBUG_FILE_ACCESSES
+/********************************************************************//**
+Sets file_page_was_freed TRUE if the page is found in the buffer pool.
+This function should be called when we free a file page and want the
+debug version to check that it is not accessed any more unless
+reallocated.
+@return control block if found in page hash table, otherwise NULL */
+UNIV_INTERN
+buf_page_t*
+buf_page_set_file_page_was_freed(
+/*=============================*/
+ ulint space, /*!< in: space id */
+ ulint offset) /*!< in: page number */
+{
+ buf_page_t* bpage;
+
+ buf_pool_mutex_enter();
+
+ bpage = buf_page_hash_get(space, offset);
+
+ if (bpage) {
+ bpage->file_page_was_freed = TRUE;
+ }
+
+ buf_pool_mutex_exit();
+
+ return(bpage);
+}
+
+/********************************************************************//**
+Sets file_page_was_freed FALSE if the page is found in the buffer pool.
+This function should be called when we free a file page and want the
+debug version to check that it is not accessed any more unless
+reallocated.
+@return control block if found in page hash table, otherwise NULL */
+UNIV_INTERN
+buf_page_t*
+buf_page_reset_file_page_was_freed(
+/*===============================*/
+ ulint space, /*!< in: space id */
+ ulint offset) /*!< in: page number */
+{
+ buf_page_t* bpage;
+
+ buf_pool_mutex_enter();
+
+ bpage = buf_page_hash_get(space, offset);
+
+ if (bpage) {
+ bpage->file_page_was_freed = FALSE;
+ }
+
+ buf_pool_mutex_exit();
+
+ return(bpage);
+}
+#endif /* UNIV_DEBUG_FILE_ACCESSES */
+
+/********************************************************************//**
+Get read access to a compressed page (usually of type
+FIL_PAGE_TYPE_ZBLOB or FIL_PAGE_TYPE_ZBLOB2).
+The page must be released with buf_page_release_zip().
+NOTE: the page is not protected by any latch. Mutual exclusion has to
+be implemented at a higher level. In other words, all possible
+accesses to a given page through this function must be protected by
+the same set of mutexes or latches.
+@return pointer to the block */
+UNIV_INTERN
+buf_page_t*
+buf_page_get_zip(
+/*=============*/
+ ulint space, /*!< in: space id */
+ ulint zip_size,/*!< in: compressed page size */
+ ulint offset) /*!< in: page number */
+{
+ buf_page_t* bpage;
+ mutex_t* block_mutex;
+ ibool must_read;
+
+#ifndef UNIV_LOG_DEBUG
+ ut_ad(!ibuf_inside());
+#endif
+ buf_pool->n_page_gets++;
+
+ for (;;) {
+ buf_pool_mutex_enter();
+lookup:
+ bpage = buf_page_hash_get(space, offset);
+ if (bpage) {
+ break;
+ }
+
+ /* Page not in buf_pool: needs to be read from file */
+
+ buf_pool_mutex_exit();
+
+ buf_read_page(space, zip_size, offset);
+
+#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
+ ut_a(++buf_dbg_counter % 37 || buf_validate());
+#endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
+ }
+
+ if (UNIV_UNLIKELY(!bpage->zip.data)) {
+ /* There is no compressed page. */
+err_exit:
+ buf_pool_mutex_exit();
+ return(NULL);
+ }
+
+ switch (buf_page_get_state(bpage)) {
+ case BUF_BLOCK_NOT_USED:
+ case BUF_BLOCK_READY_FOR_USE:
+ case BUF_BLOCK_MEMORY:
+ case BUF_BLOCK_REMOVE_HASH:
+ case BUF_BLOCK_ZIP_FREE:
+ break;
+ case BUF_BLOCK_ZIP_PAGE:
+ case BUF_BLOCK_ZIP_DIRTY:
+ block_mutex = &buf_pool_zip_mutex;
+ mutex_enter(block_mutex);
+ bpage->buf_fix_count++;
+ goto got_block;
+ case BUF_BLOCK_FILE_PAGE:
+ block_mutex = &((buf_block_t*) bpage)->mutex;
+ mutex_enter(block_mutex);
+
+ /* Discard the uncompressed page frame if possible. */
+ if (buf_LRU_free_block(bpage, FALSE, NULL)
+ == BUF_LRU_FREED) {
+
+ mutex_exit(block_mutex);
+ goto lookup;
+ }
+
+ buf_block_buf_fix_inc((buf_block_t*) bpage,
+ __FILE__, __LINE__);
+ goto got_block;
+ }
+
+ ut_error;
+ goto err_exit;
+
+got_block:
+ must_read = buf_page_get_io_fix(bpage) == BUF_IO_READ;
+
+ buf_pool_mutex_exit();
+
+ buf_page_set_accessed(bpage, TRUE);
+
+ mutex_exit(block_mutex);
+
+ buf_block_make_young(bpage);
+
+#ifdef UNIV_DEBUG_FILE_ACCESSES
+ ut_a(!bpage->file_page_was_freed);
+#endif
+
+#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
+ ut_a(++buf_dbg_counter % 5771 || buf_validate());
+ ut_a(bpage->buf_fix_count > 0);
+ ut_a(buf_page_in_file(bpage));
+#endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
+
+ if (must_read) {
+ /* Let us wait until the read operation
+ completes */
+
+ for (;;) {
+ enum buf_io_fix io_fix;
+
+ mutex_enter(block_mutex);
+ io_fix = buf_page_get_io_fix(bpage);
+ mutex_exit(block_mutex);
+
+ if (io_fix == BUF_IO_READ) {
+
+ os_thread_sleep(WAIT_FOR_READ);
+ } else {
+ break;
+ }
+ }
+ }
+
+#ifdef UNIV_IBUF_COUNT_DEBUG
+ ut_a(ibuf_count_get(buf_page_get_space(bpage),
+ buf_page_get_page_no(bpage)) == 0);
+#endif
+ return(bpage);
+}
+
+/********************************************************************//**
+Initialize some fields of a control block. */
+UNIV_INLINE
+void
+buf_block_init_low(
+/*===============*/
+ buf_block_t* block) /*!< in: block to init */
+{
+ block->check_index_page_at_flush = FALSE;
+ block->index = NULL;
+
+ block->n_hash_helps = 0;
+ block->is_hashed = FALSE;
+ block->n_fields = 1;
+ block->n_bytes = 0;
+ block->left_side = TRUE;
+}
+#endif /* !UNIV_HOTBACKUP */
+
+/********************************************************************//**
+Decompress a block.
+@return TRUE if successful */
+UNIV_INTERN
+ibool
+buf_zip_decompress(
+/*===============*/
+ buf_block_t* block, /*!< in/out: block */
+ ibool check) /*!< in: TRUE=verify the page checksum */
+{
+ const byte* frame = block->page.zip.data;
+
+ ut_ad(buf_block_get_zip_size(block));
+ ut_a(buf_block_get_space(block) != 0);
+
+ if (UNIV_LIKELY(check)) {
+ ulint stamp_checksum = mach_read_from_4(
+ frame + FIL_PAGE_SPACE_OR_CHKSUM);
+ ulint calc_checksum = page_zip_calc_checksum(
+ frame, page_zip_get_size(&block->page.zip));
+
+ if (UNIV_UNLIKELY(stamp_checksum != calc_checksum)) {
+ ut_print_timestamp(stderr);
+ fprintf(stderr,
+ " InnoDB: compressed page checksum mismatch"
+ " (space %u page %u): %lu != %lu\n",
+ block->page.space, block->page.offset,
+ stamp_checksum, calc_checksum);
+ return(FALSE);
+ }
+ }
+
+ switch (fil_page_get_type(frame)) {
+ case FIL_PAGE_INDEX:
+ if (page_zip_decompress(&block->page.zip,
+ block->frame)) {
+ return(TRUE);
+ }
+
+ fprintf(stderr,
+ "InnoDB: unable to decompress space %lu page %lu\n",
+ (ulong) block->page.space,
+ (ulong) block->page.offset);
+ return(FALSE);
+
+ case FIL_PAGE_TYPE_ALLOCATED:
+ case FIL_PAGE_INODE:
+ case FIL_PAGE_IBUF_BITMAP:
+ case FIL_PAGE_TYPE_FSP_HDR:
+ case FIL_PAGE_TYPE_XDES:
+ case FIL_PAGE_TYPE_ZBLOB:
+ case FIL_PAGE_TYPE_ZBLOB2:
+ /* Copy to uncompressed storage. */
+ memcpy(block->frame, frame,
+ buf_block_get_zip_size(block));
+ return(TRUE);
+ }
+
+ ut_print_timestamp(stderr);
+ fprintf(stderr,
+ " InnoDB: unknown compressed page"
+ " type %lu\n",
+ fil_page_get_type(frame));
+ return(FALSE);
+}
+
+#ifndef UNIV_HOTBACKUP
+/*******************************************************************//**
+Gets the block to whose frame the pointer is pointing to.
+@return pointer to block, never NULL */
+UNIV_INTERN
+buf_block_t*
+buf_block_align(
+/*============*/
+ const byte* ptr) /*!< in: pointer to a frame */
+{
+ buf_chunk_t* chunk;
+ ulint i;
+
+ /* TODO: protect buf_pool->chunks with a mutex (it will
+ currently remain constant after buf_pool_init()) */
+ for (chunk = buf_pool->chunks, i = buf_pool->n_chunks; i--; chunk++) {
+ lint offs = ptr - chunk->blocks->frame;
+
+ if (UNIV_UNLIKELY(offs < 0)) {
+
+ continue;
+ }
+
+ offs >>= UNIV_PAGE_SIZE_SHIFT;
+
+ if (UNIV_LIKELY((ulint) offs < chunk->size)) {
+ buf_block_t* block = &chunk->blocks[offs];
+
+ /* The function buf_chunk_init() invokes
+ buf_block_init() so that block[n].frame ==
+ block->frame + n * UNIV_PAGE_SIZE. Check it. */
+ ut_ad(block->frame == page_align(ptr));
+#ifdef UNIV_DEBUG
+ /* A thread that updates these fields must
+ hold buf_pool_mutex and block->mutex. Acquire
+ only the latter. */
+ mutex_enter(&block->mutex);
+
+ switch (buf_block_get_state(block)) {
+ case BUF_BLOCK_ZIP_FREE:
+ case BUF_BLOCK_ZIP_PAGE:
+ case BUF_BLOCK_ZIP_DIRTY:
+ /* These types should only be used in
+ the compressed buffer pool, whose
+ memory is allocated from
+ buf_pool->chunks, in UNIV_PAGE_SIZE
+ blocks flagged as BUF_BLOCK_MEMORY. */
+ ut_error;
+ break;
+ case BUF_BLOCK_NOT_USED:
+ case BUF_BLOCK_READY_FOR_USE:
+ case BUF_BLOCK_MEMORY:
+ /* Some data structures contain
+ "guess" pointers to file pages. The
+ file pages may have been freed and
+ reused. Do not complain. */
+ break;
+ case BUF_BLOCK_REMOVE_HASH:
+ /* buf_LRU_block_remove_hashed_page()
+ will overwrite the FIL_PAGE_OFFSET and
+ FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID with
+ 0xff and set the state to
+ BUF_BLOCK_REMOVE_HASH. */
+ ut_ad(page_get_space_id(page_align(ptr))
+ == 0xffffffff);
+ ut_ad(page_get_page_no(page_align(ptr))
+ == 0xffffffff);
+ break;
+ case BUF_BLOCK_FILE_PAGE:
+ ut_ad(block->page.space
+ == page_get_space_id(page_align(ptr)));
+ ut_ad(block->page.offset
+ == page_get_page_no(page_align(ptr)));
+ break;
+ }
+
+ mutex_exit(&block->mutex);
+#endif /* UNIV_DEBUG */
+
+ return(block);
+ }
+ }
+
+ /* The block should always be found. */
+ ut_error;
+ return(NULL);
+}
+
+/********************************************************************//**
+Find out if a pointer belongs to a buf_block_t. It can be a pointer to
+the buf_block_t itself or a member of it
+@return TRUE if ptr belongs to a buf_block_t struct */
+UNIV_INTERN
+ibool
+buf_pointer_is_block_field(
+/*=======================*/
+ const void* ptr) /*!< in: pointer not
+ dereferenced */
+{
+ const buf_chunk_t* chunk = buf_pool->chunks;
+ const buf_chunk_t* const echunk = chunk + buf_pool->n_chunks;
+
+ /* TODO: protect buf_pool->chunks with a mutex (it will
+ currently remain constant after buf_pool_init()) */
+ while (chunk < echunk) {
+ if (ptr >= (void *)chunk->blocks
+ && ptr < (void *)(chunk->blocks + chunk->size)) {
+
+ return(TRUE);
+ }
+
+ chunk++;
+ }
+
+ return(FALSE);
+}
+
+/********************************************************************//**
+Find out if a buffer block was created by buf_chunk_init().
+@return TRUE if "block" has been added to buf_pool->free by buf_chunk_init() */
+static
+ibool
+buf_block_is_uncompressed(
+/*======================*/
+ const buf_block_t* block) /*!< in: pointer to block,
+ not dereferenced */
+{
+ ut_ad(buf_pool_mutex_own());
+
+ if (UNIV_UNLIKELY((((ulint) block) % sizeof *block) != 0)) {
+ /* The pointer should be aligned. */
+ return(FALSE);
+ }
+
+ return(buf_pointer_is_block_field((void *)block));
+}
+
+/********************************************************************//**
+This is the general function used to get access to a database page.
+@return pointer to the block or NULL */
+UNIV_INTERN
+buf_block_t*
+buf_page_get_gen(
+/*=============*/
+ ulint space, /*!< in: space id */
+ ulint zip_size,/*!< in: compressed page size in bytes
+ or 0 for uncompressed pages */
+ ulint offset, /*!< in: page number */
+ ulint rw_latch,/*!< in: RW_S_LATCH, RW_X_LATCH, RW_NO_LATCH */
+ buf_block_t* guess, /*!< in: guessed block or NULL */
+ ulint mode, /*!< in: BUF_GET, BUF_GET_IF_IN_POOL,
+ BUF_GET_NO_LATCH */
+ const char* file, /*!< in: file name */
+ ulint line, /*!< in: line where called */
+ mtr_t* mtr) /*!< in: mini-transaction */
+{
+ buf_block_t* block;
+ ibool accessed;
+ ulint fix_type;
+ ibool must_read;
+
+ ut_ad(mtr);
+ ut_ad((rw_latch == RW_S_LATCH)
+ || (rw_latch == RW_X_LATCH)
+ || (rw_latch == RW_NO_LATCH));
+ ut_ad((mode != BUF_GET_NO_LATCH) || (rw_latch == RW_NO_LATCH));
+ ut_ad((mode == BUF_GET) || (mode == BUF_GET_IF_IN_POOL)
+ || (mode == BUF_GET_NO_LATCH));
+ ut_ad(zip_size == fil_space_get_zip_size(space));
+ ut_ad(ut_is_2pow(zip_size));
+#ifndef UNIV_LOG_DEBUG
+ ut_ad(!ibuf_inside() || ibuf_page(space, zip_size, offset, NULL));
+#endif
+ buf_pool->n_page_gets++;
+loop:
+ block = guess;
+ buf_pool_mutex_enter();
+
+ if (block) {
+ /* If the guess is a compressed page descriptor that
+ has been allocated by buf_buddy_alloc(), it may have
+ been invalidated by buf_buddy_relocate(). In that
+ case, block could point to something that happens to
+ contain the expected bits in block->page. Similarly,
+ the guess may be pointing to a buffer pool chunk that
+ has been released when resizing the buffer pool. */
+
+ if (!buf_block_is_uncompressed(block)
+ || offset != block->page.offset
+ || space != block->page.space
+ || buf_block_get_state(block) != BUF_BLOCK_FILE_PAGE) {
+
+ block = guess = NULL;
+ } else {
+ ut_ad(!block->page.in_zip_hash);
+ ut_ad(block->page.in_page_hash);
+ }
+ }
+
+ if (block == NULL) {
+ block = (buf_block_t*) buf_page_hash_get(space, offset);
+ }
+
+loop2:
+ if (block == NULL) {
+ /* Page not in buf_pool: needs to be read from file */
+
+ buf_pool_mutex_exit();
+
+ if (mode == BUF_GET_IF_IN_POOL) {
+
+ return(NULL);
+ }
+
+ buf_read_page(space, zip_size, offset);
+
+#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
+ ut_a(++buf_dbg_counter % 37 || buf_validate());
+#endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
+ goto loop;
+ }
+
+ ut_ad(page_zip_get_size(&block->page.zip) == zip_size);
+
+ must_read = buf_block_get_io_fix(block) == BUF_IO_READ;
+
+ if (must_read && mode == BUF_GET_IF_IN_POOL) {
+ /* The page is only being read to buffer */
+ buf_pool_mutex_exit();
+
+ return(NULL);
+ }
+
+ switch (buf_block_get_state(block)) {
+ buf_page_t* bpage;
+ ibool success;
+
+ case BUF_BLOCK_FILE_PAGE:
+ break;
+
+ case BUF_BLOCK_ZIP_PAGE:
+ case BUF_BLOCK_ZIP_DIRTY:
+ bpage = &block->page;
+ /* Protect bpage->buf_fix_count. */
+ mutex_enter(&buf_pool_zip_mutex);
+
+ if (bpage->buf_fix_count
+ || buf_page_get_io_fix(bpage) != BUF_IO_NONE) {
+ /* This condition often occurs when the buffer
+ is not buffer-fixed, but I/O-fixed by
+ buf_page_init_for_read(). */
+ mutex_exit(&buf_pool_zip_mutex);
+wait_until_unfixed:
+ /* The block is buffer-fixed or I/O-fixed.
+ Try again later. */
+ buf_pool_mutex_exit();
+ os_thread_sleep(WAIT_FOR_READ);
+
+ goto loop;
+ }
+
+ /* Allocate an uncompressed page. */
+ buf_pool_mutex_exit();
+ mutex_exit(&buf_pool_zip_mutex);
+
+ block = buf_LRU_get_free_block(0);
+ ut_a(block);
+
+ buf_pool_mutex_enter();
+ mutex_enter(&block->mutex);
+
+ {
+ buf_page_t* hash_bpage
+ = buf_page_hash_get(space, offset);
+
+ if (UNIV_UNLIKELY(bpage != hash_bpage)) {
+ /* The buf_pool->page_hash was modified
+ while buf_pool_mutex was released.
+ Free the block that was allocated. */
+
+ buf_LRU_block_free_non_file_page(block);
+ mutex_exit(&block->mutex);
+
+ block = (buf_block_t*) hash_bpage;
+ goto loop2;
+ }
+ }
+
+ if (UNIV_UNLIKELY
+ (bpage->buf_fix_count
+ || buf_page_get_io_fix(bpage) != BUF_IO_NONE)) {
+
+ /* The block was buffer-fixed or I/O-fixed
+ while buf_pool_mutex was not held by this thread.
+ Free the block that was allocated and try again.
+ This should be extremely unlikely. */
+
+ buf_LRU_block_free_non_file_page(block);
+ mutex_exit(&block->mutex);
+
+ goto wait_until_unfixed;
+ }
+
+ /* Move the compressed page from bpage to block,
+ and uncompress it. */
+
+ mutex_enter(&buf_pool_zip_mutex);
+
+ buf_relocate(bpage, &block->page);
+ buf_block_init_low(block);
+ block->lock_hash_val = lock_rec_hash(space, offset);
+
+ UNIV_MEM_DESC(&block->page.zip.data,
+ page_zip_get_size(&block->page.zip), block);
+
+ if (buf_page_get_state(&block->page)
+ == BUF_BLOCK_ZIP_PAGE) {
+ UT_LIST_REMOVE(list, buf_pool->zip_clean,
+ &block->page);
+ ut_ad(!block->page.in_flush_list);
+ } else {
+ /* Relocate buf_pool->flush_list. */
+ buf_page_t* b;
+
+ b = UT_LIST_GET_PREV(list, &block->page);
+ ut_ad(block->page.in_flush_list);
+ UT_LIST_REMOVE(list, buf_pool->flush_list,
+ &block->page);
+
+ if (b) {
+ UT_LIST_INSERT_AFTER(
+ list, buf_pool->flush_list, b,
+ &block->page);
+ } else {
+ UT_LIST_ADD_FIRST(
+ list, buf_pool->flush_list,
+ &block->page);
+ }
+ }
+
+ /* Buffer-fix, I/O-fix, and X-latch the block
+ for the duration of the decompression.
+ Also add the block to the unzip_LRU list. */
+ block->page.state = BUF_BLOCK_FILE_PAGE;
+
+ /* Insert at the front of unzip_LRU list */
+ buf_unzip_LRU_add_block(block, FALSE);
+
+ block->page.buf_fix_count = 1;
+ buf_block_set_io_fix(block, BUF_IO_READ);
+ rw_lock_x_lock(&block->lock);
+ mutex_exit(&block->mutex);
+ mutex_exit(&buf_pool_zip_mutex);
+ buf_pool->n_pend_unzip++;
+
+ buf_buddy_free(bpage, sizeof *bpage);
+
+ buf_pool_mutex_exit();
+
+ /* Decompress the page and apply buffered operations
+ while not holding buf_pool_mutex or block->mutex. */
+ success = buf_zip_decompress(block, srv_use_checksums);
+
+ if (UNIV_LIKELY(success)) {
+ ibuf_merge_or_delete_for_page(block, space, offset,
+ zip_size, TRUE);
+ }
+
+ /* Unfix and unlatch the block. */
+ buf_pool_mutex_enter();
+ mutex_enter(&block->mutex);
+ block->page.buf_fix_count--;
+ buf_block_set_io_fix(block, BUF_IO_NONE);
+ mutex_exit(&block->mutex);
+ buf_pool->n_pend_unzip--;
+ rw_lock_x_unlock(&block->lock);
+
+ if (UNIV_UNLIKELY(!success)) {
+
+ buf_pool_mutex_exit();
+ return(NULL);
+ }
+
+ break;
+
+ case BUF_BLOCK_ZIP_FREE:
+ case BUF_BLOCK_NOT_USED:
+ case BUF_BLOCK_READY_FOR_USE:
+ case BUF_BLOCK_MEMORY:
+ case BUF_BLOCK_REMOVE_HASH:
+ ut_error;
+ break;
+ }
+
+ ut_ad(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE);
+
+ mutex_enter(&block->mutex);
+ UNIV_MEM_ASSERT_RW(&block->page, sizeof block->page);
+
+ buf_block_buf_fix_inc(block, file, line);
+ buf_pool_mutex_exit();
+
+ /* Check if this is the first access to the page */
+
+ accessed = buf_page_is_accessed(&block->page);
+
+ buf_page_set_accessed(&block->page, TRUE);
+
+ mutex_exit(&block->mutex);
+
+ buf_block_make_young(&block->page);
+
+#ifdef UNIV_DEBUG_FILE_ACCESSES
+ ut_a(!block->page.file_page_was_freed);
+#endif
+
+#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
+ ut_a(++buf_dbg_counter % 5771 || buf_validate());
+ ut_a(block->page.buf_fix_count > 0);
+ ut_a(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE);
+#endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
+
+ switch (rw_latch) {
+ case RW_NO_LATCH:
+ if (must_read) {
+ /* Let us wait until the read operation
+ completes */
+
+ for (;;) {
+ enum buf_io_fix io_fix;
+
+ mutex_enter(&block->mutex);
+ io_fix = buf_block_get_io_fix(block);
+ mutex_exit(&block->mutex);
+
+ if (io_fix == BUF_IO_READ) {
+
+ os_thread_sleep(WAIT_FOR_READ);
+ } else {
+ break;
+ }
+ }
+ }
+
+ fix_type = MTR_MEMO_BUF_FIX;
+ break;
+
+ case RW_S_LATCH:
+ rw_lock_s_lock_func(&(block->lock), 0, file, line);
+
+ fix_type = MTR_MEMO_PAGE_S_FIX;
+ break;
+
+ default:
+ ut_ad(rw_latch == RW_X_LATCH);
+ rw_lock_x_lock_func(&(block->lock), 0, file, line);
+
+ fix_type = MTR_MEMO_PAGE_X_FIX;
+ break;
+ }
+
+ mtr_memo_push(mtr, block, fix_type);
+
+ if (!accessed) {
+ /* In the case of a first access, try to apply linear
+ read-ahead */
+
+ buf_read_ahead_linear(space, zip_size, offset);
+ }
+
+#ifdef UNIV_IBUF_COUNT_DEBUG
+ ut_a(ibuf_count_get(buf_block_get_space(block),
+ buf_block_get_page_no(block)) == 0);
+#endif
+ return(block);
+}
+
+/********************************************************************//**
+This is the general function used to get optimistic access to a database
+page.
+@return TRUE if success */
+UNIV_INTERN
+ibool
+buf_page_optimistic_get_func(
+/*=========================*/
+ ulint rw_latch,/*!< in: RW_S_LATCH, RW_X_LATCH */
+ buf_block_t* block, /*!< in: guessed buffer block */
+ ib_uint64_t modify_clock,/*!< in: modify clock value if mode is
+ ..._GUESS_ON_CLOCK */
+ const char* file, /*!< in: file name */
+ ulint line, /*!< in: line where called */
+ mtr_t* mtr) /*!< in: mini-transaction */
+{
+ ibool accessed;
+ ibool success;
+ ulint fix_type;
+
+ ut_ad(mtr && block);
+ ut_ad((rw_latch == RW_S_LATCH) || (rw_latch == RW_X_LATCH));
+
+ mutex_enter(&block->mutex);
+
+ if (UNIV_UNLIKELY(buf_block_get_state(block) != BUF_BLOCK_FILE_PAGE)) {
+
+ mutex_exit(&block->mutex);
+
+ return(FALSE);
+ }
+
+ buf_block_buf_fix_inc(block, file, line);
+ accessed = buf_page_is_accessed(&block->page);
+ buf_page_set_accessed(&block->page, TRUE);
+
+ mutex_exit(&block->mutex);
+
+ buf_block_make_young(&block->page);
+
+ /* Check if this is the first access to the page */
+
+ ut_ad(!ibuf_inside()
+ || ibuf_page(buf_block_get_space(block),
+ buf_block_get_zip_size(block),
+ buf_block_get_page_no(block), NULL));
+
+ if (rw_latch == RW_S_LATCH) {
+ success = rw_lock_s_lock_nowait(&(block->lock),
+ file, line);
+ fix_type = MTR_MEMO_PAGE_S_FIX;
+ } else {
+ success = rw_lock_x_lock_func_nowait(&(block->lock),
+ file, line);
+ fix_type = MTR_MEMO_PAGE_X_FIX;
+ }
+
+ if (UNIV_UNLIKELY(!success)) {
+ mutex_enter(&block->mutex);
+ buf_block_buf_fix_dec(block);
+ mutex_exit(&block->mutex);
+
+ return(FALSE);
+ }
+
+ if (UNIV_UNLIKELY(modify_clock != block->modify_clock)) {
+ buf_block_dbg_add_level(block, SYNC_NO_ORDER_CHECK);
+
+ if (rw_latch == RW_S_LATCH) {
+ rw_lock_s_unlock(&(block->lock));
+ } else {
+ rw_lock_x_unlock(&(block->lock));
+ }
+
+ mutex_enter(&block->mutex);
+ buf_block_buf_fix_dec(block);
+ mutex_exit(&block->mutex);
+
+ return(FALSE);
+ }
+
+ mtr_memo_push(mtr, block, fix_type);
+
+#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
+ ut_a(++buf_dbg_counter % 5771 || buf_validate());
+ ut_a(block->page.buf_fix_count > 0);
+ ut_a(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE);
+#endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
+
+#ifdef UNIV_DEBUG_FILE_ACCESSES
+ ut_a(block->page.file_page_was_freed == FALSE);
+#endif
+ if (UNIV_UNLIKELY(!accessed)) {
+ /* In the case of a first access, try to apply linear
+ read-ahead */
+
+ buf_read_ahead_linear(buf_block_get_space(block),
+ buf_block_get_zip_size(block),
+ buf_block_get_page_no(block));
+ }
+
+#ifdef UNIV_IBUF_COUNT_DEBUG
+ ut_a(ibuf_count_get(buf_block_get_space(block),
+ buf_block_get_page_no(block)) == 0);
+#endif
+ buf_pool->n_page_gets++;
+
+ return(TRUE);
+}
+
+/********************************************************************//**
+This is used to get access to a known database page, when no waiting can be
+done. For example, if a search in an adaptive hash index leads us to this
+frame.
+@return TRUE if success */
+UNIV_INTERN
+ibool
+buf_page_get_known_nowait(
+/*======================*/
+ ulint rw_latch,/*!< in: RW_S_LATCH, RW_X_LATCH */
+ buf_block_t* block, /*!< in: the known page */
+ ulint mode, /*!< in: BUF_MAKE_YOUNG or BUF_KEEP_OLD */
+ const char* file, /*!< in: file name */
+ ulint line, /*!< in: line where called */
+ mtr_t* mtr) /*!< in: mini-transaction */
+{
+ ibool success;
+ ulint fix_type;
+
+ ut_ad(mtr);
+ ut_ad((rw_latch == RW_S_LATCH) || (rw_latch == RW_X_LATCH));
+
+ mutex_enter(&block->mutex);
+
+ if (buf_block_get_state(block) == BUF_BLOCK_REMOVE_HASH) {
+ /* Another thread is just freeing the block from the LRU list
+ of the buffer pool: do not try to access this page; this
+ attempt to access the page can only come through the hash
+ index because when the buffer block state is ..._REMOVE_HASH,
+ we have already removed it from the page address hash table
+ of the buffer pool. */
+
+ mutex_exit(&block->mutex);
+
+ return(FALSE);
+ }
+
+ ut_a(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE);
+
+ buf_block_buf_fix_inc(block, file, line);
+
+ mutex_exit(&block->mutex);
+
+ if (mode == BUF_MAKE_YOUNG) {
+ buf_block_make_young(&block->page);
+ }
+
+ ut_ad(!ibuf_inside() || (mode == BUF_KEEP_OLD));
+
+ if (rw_latch == RW_S_LATCH) {
+ success = rw_lock_s_lock_nowait(&(block->lock),
+ file, line);
+ fix_type = MTR_MEMO_PAGE_S_FIX;
+ } else {
+ success = rw_lock_x_lock_func_nowait(&(block->lock),
+ file, line);
+ fix_type = MTR_MEMO_PAGE_X_FIX;
+ }
+
+ if (!success) {
+ mutex_enter(&block->mutex);
+ buf_block_buf_fix_dec(block);
+ mutex_exit(&block->mutex);
+
+ return(FALSE);
+ }
+
+ mtr_memo_push(mtr, block, fix_type);
+
+#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
+ ut_a(++buf_dbg_counter % 5771 || buf_validate());
+ ut_a(block->page.buf_fix_count > 0);
+ ut_a(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE);
+#endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
+#ifdef UNIV_DEBUG_FILE_ACCESSES
+ ut_a(block->page.file_page_was_freed == FALSE);
+#endif
+
+#ifdef UNIV_IBUF_COUNT_DEBUG
+ ut_a((mode == BUF_KEEP_OLD)
+ || (ibuf_count_get(buf_block_get_space(block),
+ buf_block_get_page_no(block)) == 0));
+#endif
+ buf_pool->n_page_gets++;
+
+ return(TRUE);
+}
+
+/*******************************************************************//**
+Given a tablespace id and page number tries to get that page. If the
+page is not in the buffer pool it is not loaded and NULL is returned.
+Suitable for using when holding the kernel mutex.
+@return pointer to a page or NULL */
+UNIV_INTERN
+const buf_block_t*
+buf_page_try_get_func(
+/*==================*/
+ ulint space_id,/*!< in: tablespace id */
+ ulint page_no,/*!< in: page number */
+ const char* file, /*!< in: file name */
+ ulint line, /*!< in: line where called */
+ mtr_t* mtr) /*!< in: mini-transaction */
+{
+ buf_block_t* block;
+ ibool success;
+ ulint fix_type;
+
+ buf_pool_mutex_enter();
+ block = buf_block_hash_get(space_id, page_no);
+
+ if (!block) {
+ buf_pool_mutex_exit();
+ return(NULL);
+ }
+
+ mutex_enter(&block->mutex);
+ buf_pool_mutex_exit();
+
+#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
+ ut_a(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE);
+ ut_a(buf_block_get_space(block) == space_id);
+ ut_a(buf_block_get_page_no(block) == page_no);
+#endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
+
+ buf_block_buf_fix_inc(block, file, line);
+ mutex_exit(&block->mutex);
+
+ fix_type = MTR_MEMO_PAGE_S_FIX;
+ success = rw_lock_s_lock_nowait(&block->lock, file, line);
+
+ if (!success) {
+ /* Let us try to get an X-latch. If the current thread
+ is holding an X-latch on the page, we cannot get an
+ S-latch. */
+
+ fix_type = MTR_MEMO_PAGE_X_FIX;
+ success = rw_lock_x_lock_func_nowait(&block->lock,
+ file, line);
+ }
+
+ if (!success) {
+ mutex_enter(&block->mutex);
+ buf_block_buf_fix_dec(block);
+ mutex_exit(&block->mutex);
+
+ return(NULL);
+ }
+
+ mtr_memo_push(mtr, block, fix_type);
+#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
+ ut_a(++buf_dbg_counter % 5771 || buf_validate());
+ ut_a(block->page.buf_fix_count > 0);
+ ut_a(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE);
+#endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
+#ifdef UNIV_DEBUG_FILE_ACCESSES
+ ut_a(block->page.file_page_was_freed == FALSE);
+#endif /* UNIV_DEBUG_FILE_ACCESSES */
+ buf_block_dbg_add_level(block, SYNC_NO_ORDER_CHECK);
+
+ buf_pool->n_page_gets++;
+
+#ifdef UNIV_IBUF_COUNT_DEBUG
+ ut_a(ibuf_count_get(buf_block_get_space(block),
+ buf_block_get_page_no(block)) == 0);
+#endif
+
+ return(block);
+}
+
+/********************************************************************//**
+Initialize some fields of a control block. */
+UNIV_INLINE
+void
+buf_page_init_low(
+/*==============*/
+ buf_page_t* bpage) /*!< in: block to init */
+{
+ bpage->flush_type = BUF_FLUSH_LRU;
+ bpage->accessed = FALSE;
+ bpage->io_fix = BUF_IO_NONE;
+ bpage->buf_fix_count = 0;
+ bpage->freed_page_clock = 0;
+ bpage->newest_modification = 0;
+ bpage->oldest_modification = 0;
+ HASH_INVALIDATE(bpage, hash);
+#ifdef UNIV_DEBUG_FILE_ACCESSES
+ bpage->file_page_was_freed = FALSE;
+#endif /* UNIV_DEBUG_FILE_ACCESSES */
+}
+
+/********************************************************************//**
+Inits a page to the buffer buf_pool. */
+static
+void
+buf_page_init(
+/*==========*/
+ ulint space, /*!< in: space id */
+ ulint offset, /*!< in: offset of the page within space
+ in units of a page */
+ buf_block_t* block) /*!< in: block to init */
+{
+ buf_page_t* hash_page;
+
+ ut_ad(buf_pool_mutex_own());
+ ut_ad(mutex_own(&(block->mutex)));
+ ut_a(buf_block_get_state(block) != BUF_BLOCK_FILE_PAGE);
+
+ /* Set the state of the block */
+ buf_block_set_file_page(block, space, offset);
+
+#ifdef UNIV_DEBUG_VALGRIND
+ if (!space) {
+ /* Silence valid Valgrind warnings about uninitialized
+ data being written to data files. There are some unused
+ bytes on some pages that InnoDB does not initialize. */
+ UNIV_MEM_VALID(block->frame, UNIV_PAGE_SIZE);
+ }
+#endif /* UNIV_DEBUG_VALGRIND */
+
+ buf_block_init_low(block);
+
+ block->lock_hash_val = lock_rec_hash(space, offset);
+
+ /* Insert into the hash table of file pages */
+
+ hash_page = buf_page_hash_get(space, offset);
+
+ if (UNIV_LIKELY_NULL(hash_page)) {
+ fprintf(stderr,
+ "InnoDB: Error: page %lu %lu already found"
+ " in the hash table: %p, %p\n",
+ (ulong) space,
+ (ulong) offset,
+ (const void*) hash_page, (const void*) block);
+#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
+ mutex_exit(&block->mutex);
+ buf_pool_mutex_exit();
+ buf_print();
+ buf_LRU_print();
+ buf_validate();
+ buf_LRU_validate();
+#endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
+ ut_error;
+ }
+
+ buf_page_init_low(&block->page);
+
+ ut_ad(!block->page.in_zip_hash);
+ ut_ad(!block->page.in_page_hash);
+ ut_d(block->page.in_page_hash = TRUE);
+ HASH_INSERT(buf_page_t, hash, buf_pool->page_hash,
+ buf_page_address_fold(space, offset), &block->page);
+}
+
+/********************************************************************//**
+Function which inits a page for read to the buffer buf_pool. If the page is
+(1) already in buf_pool, or
+(2) if we specify to read only ibuf pages and the page is not an ibuf page, or
+(3) if the space is deleted or being deleted,
+then this function does nothing.
+Sets the io_fix flag to BUF_IO_READ and sets a non-recursive exclusive lock
+on the buffer frame. The io-handler must take care that the flag is cleared
+and the lock released later.
+@return pointer to the block or NULL */
+UNIV_INTERN
+buf_page_t*
+buf_page_init_for_read(
+/*===================*/
+ ulint* err, /*!< out: DB_SUCCESS or DB_TABLESPACE_DELETED */
+ ulint mode, /*!< in: BUF_READ_IBUF_PAGES_ONLY, ... */
+ ulint space, /*!< in: space id */
+ ulint zip_size,/*!< in: compressed page size, or 0 */
+ ibool unzip, /*!< in: TRUE=request uncompressed page */
+ ib_int64_t tablespace_version,/*!< in: prevents reading from a wrong
+ version of the tablespace in case we have done
+ DISCARD + IMPORT */
+ ulint offset) /*!< in: page number */
+{
+ buf_block_t* block;
+ buf_page_t* bpage;
+ mtr_t mtr;
+ ibool lru = FALSE;
+ void* data;
+
+ ut_ad(buf_pool);
+
+ *err = DB_SUCCESS;
+
+ if (mode == BUF_READ_IBUF_PAGES_ONLY) {
+ /* It is a read-ahead within an ibuf routine */
+
+ ut_ad(!ibuf_bitmap_page(zip_size, offset));
+ ut_ad(ibuf_inside());
+
+ mtr_start(&mtr);
+
+ if (!recv_no_ibuf_operations
+ && !ibuf_page(space, zip_size, offset, &mtr)) {
+
+ mtr_commit(&mtr);
+
+ return(NULL);
+ }
+ } else {
+ ut_ad(mode == BUF_READ_ANY_PAGE);
+ }
+
+ if (zip_size && UNIV_LIKELY(!unzip)
+ && UNIV_LIKELY(!recv_recovery_is_on())) {
+ block = NULL;
+ } else {
+ block = buf_LRU_get_free_block(0);
+ ut_ad(block);
+ }
+
+ buf_pool_mutex_enter();
+
+ if (buf_page_hash_get(space, offset)) {
+ /* The page is already in the buffer pool. */
+err_exit:
+ if (block) {
+ mutex_enter(&block->mutex);
+ buf_LRU_block_free_non_file_page(block);
+ mutex_exit(&block->mutex);
+ }
+
+ bpage = NULL;
+ goto func_exit;
+ }
+
+ if (fil_tablespace_deleted_or_being_deleted_in_mem(
+ space, tablespace_version)) {
+ /* The page belongs to a space which has been
+ deleted or is being deleted. */
+ *err = DB_TABLESPACE_DELETED;
+
+ goto err_exit;
+ }
+
+ if (block) {
+ bpage = &block->page;
+ mutex_enter(&block->mutex);
+ buf_page_init(space, offset, block);
+
+ /* The block must be put to the LRU list, to the old blocks */
+ buf_LRU_add_block(bpage, TRUE/* to old blocks */);
+
+ /* We set a pass-type x-lock on the frame because then
+ the same thread which called for the read operation
+ (and is running now at this point of code) can wait
+ for the read to complete by waiting for the x-lock on
+ the frame; if the x-lock were recursive, the same
+ thread would illegally get the x-lock before the page
+ read is completed. The x-lock is cleared by the
+ io-handler thread. */
+
+ rw_lock_x_lock_gen(&block->lock, BUF_IO_READ);
+ buf_page_set_io_fix(bpage, BUF_IO_READ);
+
+ if (UNIV_UNLIKELY(zip_size)) {
+ page_zip_set_size(&block->page.zip, zip_size);
+
+ /* buf_pool_mutex may be released and
+ reacquired by buf_buddy_alloc(). Thus, we
+ must release block->mutex in order not to
+ break the latching order in the reacquisition
+ of buf_pool_mutex. We also must defer this
+ operation until after the block descriptor has
+ been added to buf_pool->LRU and
+ buf_pool->page_hash. */
+ mutex_exit(&block->mutex);
+ data = buf_buddy_alloc(zip_size, &lru);
+ mutex_enter(&block->mutex);
+ block->page.zip.data = data;
+
+ /* To maintain the invariant
+ block->in_unzip_LRU_list
+ == buf_page_belongs_to_unzip_LRU(&block->page)
+ we have to add this block to unzip_LRU
+ after block->page.zip.data is set. */
+ ut_ad(buf_page_belongs_to_unzip_LRU(&block->page));
+ buf_unzip_LRU_add_block(block, TRUE);
+ }
+
+ mutex_exit(&block->mutex);
+ } else {
+ /* Defer buf_buddy_alloc() until after the block has
+ been found not to exist. The buf_buddy_alloc() and
+ buf_buddy_free() calls may be expensive because of
+ buf_buddy_relocate(). */
+
+ /* The compressed page must be allocated before the
+ control block (bpage), in order to avoid the
+ invocation of buf_buddy_relocate_block() on
+ uninitialized data. */
+ data = buf_buddy_alloc(zip_size, &lru);
+ bpage = buf_buddy_alloc(sizeof *bpage, &lru);
+
+ /* If buf_buddy_alloc() allocated storage from the LRU list,
+ it released and reacquired buf_pool_mutex. Thus, we must
+ check the page_hash again, as it may have been modified. */
+ if (UNIV_UNLIKELY(lru)
+ && UNIV_LIKELY_NULL(buf_page_hash_get(space, offset))) {
+
+ /* The block was added by some other thread. */
+ buf_buddy_free(bpage, sizeof *bpage);
+ buf_buddy_free(data, zip_size);
+
+ bpage = NULL;
+ goto func_exit;
+ }
+
+ page_zip_des_init(&bpage->zip);
+ page_zip_set_size(&bpage->zip, zip_size);
+ bpage->zip.data = data;
+
+ mutex_enter(&buf_pool_zip_mutex);
+ UNIV_MEM_DESC(bpage->zip.data,
+ page_zip_get_size(&bpage->zip), bpage);
+ buf_page_init_low(bpage);
+ bpage->state = BUF_BLOCK_ZIP_PAGE;
+ bpage->space = space;
+ bpage->offset = offset;
+
+#ifdef UNIV_DEBUG
+ bpage->in_page_hash = FALSE;
+ bpage->in_zip_hash = FALSE;
+ bpage->in_flush_list = FALSE;
+ bpage->in_free_list = FALSE;
+ bpage->in_LRU_list = FALSE;
+#endif /* UNIV_DEBUG */
+
+ ut_d(bpage->in_page_hash = TRUE);
+ HASH_INSERT(buf_page_t, hash, buf_pool->page_hash,
+ buf_page_address_fold(space, offset), bpage);
+
+ /* The block must be put to the LRU list, to the old blocks */
+ buf_LRU_add_block(bpage, TRUE/* to old blocks */);
+ buf_LRU_insert_zip_clean(bpage);
+
+ buf_page_set_io_fix(bpage, BUF_IO_READ);
+
+ mutex_exit(&buf_pool_zip_mutex);
+ }
+
+ buf_pool->n_pend_reads++;
+func_exit:
+ buf_pool_mutex_exit();
+
+ if (mode == BUF_READ_IBUF_PAGES_ONLY) {
+
+ mtr_commit(&mtr);
+ }
+
+ ut_ad(!bpage || buf_page_in_file(bpage));
+ return(bpage);
+}
+
+/********************************************************************//**
+Initializes a page to the buffer buf_pool. The page is usually not read
+from a file even if it cannot be found in the buffer buf_pool. This is one
+of the functions which perform to a block a state transition NOT_USED =>
+FILE_PAGE (the other is buf_page_get_gen).
+@return pointer to the block, page bufferfixed */
+UNIV_INTERN
+buf_block_t*
+buf_page_create(
+/*============*/
+ ulint space, /*!< in: space id */
+ ulint offset, /*!< in: offset of the page within space in units of
+ a page */
+ ulint zip_size,/*!< in: compressed page size, or 0 */
+ mtr_t* mtr) /*!< in: mini-transaction handle */
+{
+ buf_frame_t* frame;
+ buf_block_t* block;
+ buf_block_t* free_block = NULL;
+
+ ut_ad(mtr);
+ ut_ad(space || !zip_size);
+
+ free_block = buf_LRU_get_free_block(0);
+
+ buf_pool_mutex_enter();
+
+ block = (buf_block_t*) buf_page_hash_get(space, offset);
+
+ if (block && buf_page_in_file(&block->page)) {
+#ifdef UNIV_IBUF_COUNT_DEBUG
+ ut_a(ibuf_count_get(space, offset) == 0);
+#endif
+#ifdef UNIV_DEBUG_FILE_ACCESSES
+ block->page.file_page_was_freed = FALSE;
+#endif /* UNIV_DEBUG_FILE_ACCESSES */
+
+ /* Page can be found in buf_pool */
+ buf_pool_mutex_exit();
+
+ buf_block_free(free_block);
+
+ return(buf_page_get_with_no_latch(space, zip_size,
+ offset, mtr));
+ }
+
+ /* If we get here, the page was not in buf_pool: init it there */
+
+#ifdef UNIV_DEBUG
+ if (buf_debug_prints) {
+ fprintf(stderr, "Creating space %lu page %lu to buffer\n",
+ (ulong) space, (ulong) offset);
+ }
+#endif /* UNIV_DEBUG */
+
+ block = free_block;
+
+ mutex_enter(&block->mutex);
+
+ buf_page_init(space, offset, block);
+
+ /* The block must be put to the LRU list */
+ buf_LRU_add_block(&block->page, FALSE);
+
+ buf_block_buf_fix_inc(block, __FILE__, __LINE__);
+ buf_pool->n_pages_created++;
+
+ if (zip_size) {
+ void* data;
+ ibool lru;
+
+ /* Prevent race conditions during buf_buddy_alloc(),
+ which may release and reacquire buf_pool_mutex,
+ by IO-fixing and X-latching the block. */
+
+ buf_page_set_io_fix(&block->page, BUF_IO_READ);
+ rw_lock_x_lock(&block->lock);
+
+ page_zip_set_size(&block->page.zip, zip_size);
+ mutex_exit(&block->mutex);
+ /* buf_pool_mutex may be released and reacquired by
+ buf_buddy_alloc(). Thus, we must release block->mutex
+ in order not to break the latching order in
+ the reacquisition of buf_pool_mutex. We also must
+ defer this operation until after the block descriptor
+ has been added to buf_pool->LRU and buf_pool->page_hash. */
+ data = buf_buddy_alloc(zip_size, &lru);
+ mutex_enter(&block->mutex);
+ block->page.zip.data = data;
+
+ /* To maintain the invariant
+ block->in_unzip_LRU_list
+ == buf_page_belongs_to_unzip_LRU(&block->page)
+ we have to add this block to unzip_LRU after
+ block->page.zip.data is set. */
+ ut_ad(buf_page_belongs_to_unzip_LRU(&block->page));
+ buf_unzip_LRU_add_block(block, FALSE);
+
+ buf_page_set_io_fix(&block->page, BUF_IO_NONE);
+ rw_lock_x_unlock(&block->lock);
+ }
+
+ buf_pool_mutex_exit();
+
+ mtr_memo_push(mtr, block, MTR_MEMO_BUF_FIX);
+
+ buf_page_set_accessed(&block->page, TRUE);
+
+ mutex_exit(&block->mutex);
+
+ /* Delete possible entries for the page from the insert buffer:
+ such can exist if the page belonged to an index which was dropped */
+
+ ibuf_merge_or_delete_for_page(NULL, space, offset, zip_size, TRUE);
+
+ /* Flush pages from the end of the LRU list if necessary */
+ buf_flush_free_margin();
+
+ frame = block->frame;
+
+ memset(frame + FIL_PAGE_PREV, 0xff, 4);
+ memset(frame + FIL_PAGE_NEXT, 0xff, 4);
+ mach_write_to_2(frame + FIL_PAGE_TYPE, FIL_PAGE_TYPE_ALLOCATED);
+
+ /* Reset to zero the file flush lsn field in the page; if the first
+ page of an ibdata file is 'created' in this function into the buffer
+ pool then we lose the original contents of the file flush lsn stamp.
+ Then InnoDB could in a crash recovery print a big, false, corruption
+ warning if the stamp contains an lsn bigger than the ib_logfile lsn. */
+
+ memset(frame + FIL_PAGE_FILE_FLUSH_LSN, 0, 8);
+
+#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
+ ut_a(++buf_dbg_counter % 357 || buf_validate());
+#endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
+#ifdef UNIV_IBUF_COUNT_DEBUG
+ ut_a(ibuf_count_get(buf_block_get_space(block),
+ buf_block_get_page_no(block)) == 0);
+#endif
+ return(block);
+}
+
+/********************************************************************//**
+Completes an asynchronous read or write request of a file page to or from
+the buffer pool. */
+UNIV_INTERN
+void
+buf_page_io_complete(
+/*=================*/
+ buf_page_t* bpage) /*!< in: pointer to the block in question */
+{
+ enum buf_io_fix io_type;
+ const ibool uncompressed = (buf_page_get_state(bpage)
+ == BUF_BLOCK_FILE_PAGE);
+
+ ut_a(buf_page_in_file(bpage));
+
+ /* We do not need protect io_fix here by mutex to read
+ it because this is the only function where we can change the value
+ from BUF_IO_READ or BUF_IO_WRITE to some other value, and our code
+ ensures that this is the only thread that handles the i/o for this
+ block. */
+
+ io_type = buf_page_get_io_fix(bpage);
+ ut_ad(io_type == BUF_IO_READ || io_type == BUF_IO_WRITE);
+
+ if (io_type == BUF_IO_READ) {
+ ulint read_page_no;
+ ulint read_space_id;
+ byte* frame;
+
+ if (buf_page_get_zip_size(bpage)) {
+ frame = bpage->zip.data;
+ buf_pool->n_pend_unzip++;
+ if (uncompressed
+ && !buf_zip_decompress((buf_block_t*) bpage,
+ FALSE)) {
+
+ buf_pool->n_pend_unzip--;
+ goto corrupt;
+ }
+ buf_pool->n_pend_unzip--;
+ } else {
+ ut_a(uncompressed);
+ frame = ((buf_block_t*) bpage)->frame;
+ }
+
+ /* If this page is not uninitialized and not in the
+ doublewrite buffer, then the page number and space id
+ should be the same as in block. */
+ read_page_no = mach_read_from_4(frame + FIL_PAGE_OFFSET);
+ read_space_id = mach_read_from_4(
+ frame + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID);
+
+ if (bpage->space == TRX_SYS_SPACE
+ && trx_doublewrite_page_inside(bpage->offset)) {
+
+ ut_print_timestamp(stderr);
+ fprintf(stderr,
+ " InnoDB: Error: reading page %lu\n"
+ "InnoDB: which is in the"
+ " doublewrite buffer!\n",
+ (ulong) bpage->offset);
+ } else if (!read_space_id && !read_page_no) {
+ /* This is likely an uninitialized page. */
+ } else if ((bpage->space
+ && bpage->space != read_space_id)
+ || bpage->offset != read_page_no) {
+ /* We did not compare space_id to read_space_id
+ if bpage->space == 0, because the field on the
+ page may contain garbage in MySQL < 4.1.1,
+ which only supported bpage->space == 0. */
+
+ ut_print_timestamp(stderr);
+ fprintf(stderr,
+ " InnoDB: Error: space id and page n:o"
+ " stored in the page\n"
+ "InnoDB: read in are %lu:%lu,"
+ " should be %lu:%lu!\n",
+ (ulong) read_space_id, (ulong) read_page_no,
+ (ulong) bpage->space,
+ (ulong) bpage->offset);
+ }
+
+ /* From version 3.23.38 up we store the page checksum
+ to the 4 first bytes of the page end lsn field */
+
+ if (buf_page_is_corrupted(frame,
+ buf_page_get_zip_size(bpage))) {
+corrupt:
+ fprintf(stderr,
+ "InnoDB: Database page corruption on disk"
+ " or a failed\n"
+ "InnoDB: file read of page %lu.\n"
+ "InnoDB: You may have to recover"
+ " from a backup.\n",
+ (ulong) bpage->offset);
+ buf_page_print(frame, buf_page_get_zip_size(bpage));
+ fprintf(stderr,
+ "InnoDB: Database page corruption on disk"
+ " or a failed\n"
+ "InnoDB: file read of page %lu.\n"
+ "InnoDB: You may have to recover"
+ " from a backup.\n",
+ (ulong) bpage->offset);
+ fputs("InnoDB: It is also possible that"
+ " your operating\n"
+ "InnoDB: system has corrupted its"
+ " own file cache\n"
+ "InnoDB: and rebooting your computer"
+ " removes the\n"
+ "InnoDB: error.\n"
+ "InnoDB: If the corrupt page is an index page\n"
+ "InnoDB: you can also try to"
+ " fix the corruption\n"
+ "InnoDB: by dumping, dropping,"
+ " and reimporting\n"
+ "InnoDB: the corrupt table."
+ " You can use CHECK\n"
+ "InnoDB: TABLE to scan your"
+ " table for corruption.\n"
+ "InnoDB: See also "
+ REFMAN "forcing-recovery.html\n"
+ "InnoDB: about forcing recovery.\n", stderr);
+
+ if (srv_force_recovery < SRV_FORCE_IGNORE_CORRUPT) {
+ fputs("InnoDB: Ending processing because of"
+ " a corrupt database page.\n",
+ stderr);
+ exit(1);
+ }
+ }
+
+ if (recv_recovery_is_on()) {
+ /* Pages must be uncompressed for crash recovery. */
+ ut_a(uncompressed);
+ recv_recover_page(TRUE, (buf_block_t*) bpage);
+ }
+
+ if (uncompressed && !recv_no_ibuf_operations) {
+ ibuf_merge_or_delete_for_page(
+ (buf_block_t*) bpage, bpage->space,
+ bpage->offset, buf_page_get_zip_size(bpage),
+ TRUE);
+ }
+ }
+
+ buf_pool_mutex_enter();
+ mutex_enter(buf_page_get_mutex(bpage));
+
+#ifdef UNIV_IBUF_COUNT_DEBUG
+ if (io_type == BUF_IO_WRITE || uncompressed) {
+ /* For BUF_IO_READ of compressed-only blocks, the
+ buffered operations will be merged by buf_page_get_gen()
+ after the block has been uncompressed. */
+ ut_a(ibuf_count_get(bpage->space, bpage->offset) == 0);
+ }
+#endif
+ /* Because this thread which does the unlocking is not the same that
+ did the locking, we use a pass value != 0 in unlock, which simply
+ removes the newest lock debug record, without checking the thread
+ id. */
+
+ buf_page_set_io_fix(bpage, BUF_IO_NONE);
+
+ switch (io_type) {
+ case BUF_IO_READ:
+ /* NOTE that the call to ibuf may have moved the ownership of
+ the x-latch to this OS thread: do not let this confuse you in
+ debugging! */
+
+ ut_ad(buf_pool->n_pend_reads > 0);
+ buf_pool->n_pend_reads--;
+ buf_pool->n_pages_read++;
+
+ if (uncompressed) {
+ rw_lock_x_unlock_gen(&((buf_block_t*) bpage)->lock,
+ BUF_IO_READ);
+ }
+
+ break;
+
+ case BUF_IO_WRITE:
+ /* Write means a flush operation: call the completion
+ routine in the flush system */
+
+ buf_flush_write_complete(bpage);
+
+ if (uncompressed) {
+ rw_lock_s_unlock_gen(&((buf_block_t*) bpage)->lock,
+ BUF_IO_WRITE);
+ }
+
+ buf_pool->n_pages_written++;
+
+ break;
+
+ default:
+ ut_error;
+ }
+
+#ifdef UNIV_DEBUG
+ if (buf_debug_prints) {
+ fprintf(stderr, "Has %s page space %lu page no %lu\n",
+ io_type == BUF_IO_READ ? "read" : "written",
+ (ulong) buf_page_get_space(bpage),
+ (ulong) buf_page_get_page_no(bpage));
+ }
+#endif /* UNIV_DEBUG */
+
+ mutex_exit(buf_page_get_mutex(bpage));
+ buf_pool_mutex_exit();
+}
+
+/*********************************************************************//**
+Invalidates the file pages in the buffer pool when an archive recovery is
+completed. All the file pages buffered must be in a replaceable state when
+this function is called: not latched and not modified. */
+UNIV_INTERN
+void
+buf_pool_invalidate(void)
+/*=====================*/
+{
+ ibool freed;
+
+ ut_ad(buf_all_freed());
+
+ freed = TRUE;
+
+ while (freed) {
+ freed = buf_LRU_search_and_free_block(100);
+ }
+
+ buf_pool_mutex_enter();
+
+ ut_ad(UT_LIST_GET_LEN(buf_pool->LRU) == 0);
+ ut_ad(UT_LIST_GET_LEN(buf_pool->unzip_LRU) == 0);
+
+ buf_pool_mutex_exit();
+}
+
+#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
+/*********************************************************************//**
+Validates the buffer buf_pool data structure.
+@return TRUE */
+UNIV_INTERN
+ibool
+buf_validate(void)
+/*==============*/
+{
+ buf_page_t* b;
+ buf_chunk_t* chunk;
+ ulint i;
+ ulint n_single_flush = 0;
+ ulint n_lru_flush = 0;
+ ulint n_list_flush = 0;
+ ulint n_lru = 0;
+ ulint n_flush = 0;
+ ulint n_free = 0;
+ ulint n_zip = 0;
+
+ ut_ad(buf_pool);
+
+ buf_pool_mutex_enter();
+
+ chunk = buf_pool->chunks;
+
+ /* Check the uncompressed blocks. */
+
+ for (i = buf_pool->n_chunks; i--; chunk++) {
+
+ ulint j;
+ buf_block_t* block = chunk->blocks;
+
+ for (j = chunk->size; j--; block++) {
+
+ mutex_enter(&block->mutex);
+
+ switch (buf_block_get_state(block)) {
+ case BUF_BLOCK_ZIP_FREE:
+ case BUF_BLOCK_ZIP_PAGE:
+ case BUF_BLOCK_ZIP_DIRTY:
+ /* These should only occur on
+ zip_clean, zip_free[], or flush_list. */
+ ut_error;
+ break;
+
+ case BUF_BLOCK_FILE_PAGE:
+ ut_a(buf_page_hash_get(buf_block_get_space(
+ block),
+ buf_block_get_page_no(
+ block))
+ == &block->page);
+
+#ifdef UNIV_IBUF_COUNT_DEBUG
+ ut_a(buf_page_get_io_fix(&block->page)
+ == BUF_IO_READ
+ || !ibuf_count_get(buf_block_get_space(
+ block),
+ buf_block_get_page_no(
+ block)));
+#endif
+ switch (buf_page_get_io_fix(&block->page)) {
+ case BUF_IO_NONE:
+ break;
+
+ case BUF_IO_WRITE:
+ switch (buf_page_get_flush_type(
+ &block->page)) {
+ case BUF_FLUSH_LRU:
+ n_lru_flush++;
+ ut_a(rw_lock_is_locked(
+ &block->lock,
+ RW_LOCK_SHARED));
+ break;
+ case BUF_FLUSH_LIST:
+ n_list_flush++;
+ break;
+ case BUF_FLUSH_SINGLE_PAGE:
+ n_single_flush++;
+ break;
+ default:
+ ut_error;
+ }
+
+ break;
+
+ case BUF_IO_READ:
+
+ ut_a(rw_lock_is_locked(&block->lock,
+ RW_LOCK_EX));
+ break;
+ }
+
+ n_lru++;
+
+ if (block->page.oldest_modification > 0) {
+ n_flush++;
+ }
+
+ break;
+
+ case BUF_BLOCK_NOT_USED:
+ n_free++;
+ break;
+
+ case BUF_BLOCK_READY_FOR_USE:
+ case BUF_BLOCK_MEMORY:
+ case BUF_BLOCK_REMOVE_HASH:
+ /* do nothing */
+ break;
+ }
+
+ mutex_exit(&block->mutex);
+ }
+ }
+
+ mutex_enter(&buf_pool_zip_mutex);
+
+ /* Check clean compressed-only blocks. */
+
+ for (b = UT_LIST_GET_FIRST(buf_pool->zip_clean); b;
+ b = UT_LIST_GET_NEXT(list, b)) {
+ ut_a(buf_page_get_state(b) == BUF_BLOCK_ZIP_PAGE);
+ switch (buf_page_get_io_fix(b)) {
+ case BUF_IO_NONE:
+ /* All clean blocks should be I/O-unfixed. */
+ break;
+ case BUF_IO_READ:
+ /* In buf_LRU_free_block(), we temporarily set
+ b->io_fix = BUF_IO_READ for a newly allocated
+ control block in order to prevent
+ buf_page_get_gen() from decompressing the block. */
+ break;
+ default:
+ ut_error;
+ break;
+ }
+ ut_a(!b->oldest_modification);
+ ut_a(buf_page_hash_get(b->space, b->offset) == b);
+
+ n_lru++;
+ n_zip++;
+ }
+
+ /* Check dirty compressed-only blocks. */
+
+ for (b = UT_LIST_GET_FIRST(buf_pool->flush_list); b;
+ b = UT_LIST_GET_NEXT(list, b)) {
+ ut_ad(b->in_flush_list);
+
+ switch (buf_page_get_state(b)) {
+ case BUF_BLOCK_ZIP_DIRTY:
+ ut_a(b->oldest_modification);
+ n_lru++;
+ n_flush++;
+ n_zip++;
+ switch (buf_page_get_io_fix(b)) {
+ case BUF_IO_NONE:
+ case BUF_IO_READ:
+ break;
+
+ case BUF_IO_WRITE:
+ switch (buf_page_get_flush_type(b)) {
+ case BUF_FLUSH_LRU:
+ n_lru_flush++;
+ break;
+ case BUF_FLUSH_LIST:
+ n_list_flush++;
+ break;
+ case BUF_FLUSH_SINGLE_PAGE:
+ n_single_flush++;
+ break;
+ default:
+ ut_error;
+ }
+ break;
+ }
+ break;
+ case BUF_BLOCK_FILE_PAGE:
+ /* uncompressed page */
+ break;
+ case BUF_BLOCK_ZIP_FREE:
+ case BUF_BLOCK_ZIP_PAGE:
+ case BUF_BLOCK_NOT_USED:
+ case BUF_BLOCK_READY_FOR_USE:
+ case BUF_BLOCK_MEMORY:
+ case BUF_BLOCK_REMOVE_HASH:
+ ut_error;
+ break;
+ }
+ ut_a(buf_page_hash_get(b->space, b->offset) == b);
+ }
+
+ mutex_exit(&buf_pool_zip_mutex);
+
+ if (n_lru + n_free > buf_pool->curr_size + n_zip) {
+ fprintf(stderr, "n LRU %lu, n free %lu, pool %lu zip %lu\n",
+ (ulong) n_lru, (ulong) n_free,
+ (ulong) buf_pool->curr_size, (ulong) n_zip);
+ ut_error;
+ }
+
+ ut_a(UT_LIST_GET_LEN(buf_pool->LRU) == n_lru);
+ if (UT_LIST_GET_LEN(buf_pool->free) != n_free) {
+ fprintf(stderr, "Free list len %lu, free blocks %lu\n",
+ (ulong) UT_LIST_GET_LEN(buf_pool->free),
+ (ulong) n_free);
+ ut_error;
+ }
+ ut_a(UT_LIST_GET_LEN(buf_pool->flush_list) == n_flush);
+
+ ut_a(buf_pool->n_flush[BUF_FLUSH_SINGLE_PAGE] == n_single_flush);
+ ut_a(buf_pool->n_flush[BUF_FLUSH_LIST] == n_list_flush);
+ ut_a(buf_pool->n_flush[BUF_FLUSH_LRU] == n_lru_flush);
+
+ buf_pool_mutex_exit();
+
+ ut_a(buf_LRU_validate());
+ ut_a(buf_flush_validate());
+
+ return(TRUE);
+}
+#endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
+
+#if defined UNIV_DEBUG_PRINT || defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
+/*********************************************************************//**
+Prints info of the buffer buf_pool data structure. */
+UNIV_INTERN
+void
+buf_print(void)
+/*===========*/
+{
+ dulint* index_ids;
+ ulint* counts;
+ ulint size;
+ ulint i;
+ ulint j;
+ dulint id;
+ ulint n_found;
+ buf_chunk_t* chunk;
+ dict_index_t* index;
+
+ ut_ad(buf_pool);
+
+ size = buf_pool->curr_size;
+
+ index_ids = mem_alloc(sizeof(dulint) * size);
+ counts = mem_alloc(sizeof(ulint) * size);
+
+ buf_pool_mutex_enter();
+
+ fprintf(stderr,
+ "buf_pool size %lu\n"
+ "database pages %lu\n"
+ "free pages %lu\n"
+ "modified database pages %lu\n"
+ "n pending decompressions %lu\n"
+ "n pending reads %lu\n"
+ "n pending flush LRU %lu list %lu single page %lu\n"
+ "pages read %lu, created %lu, written %lu\n",
+ (ulong) size,
+ (ulong) UT_LIST_GET_LEN(buf_pool->LRU),
+ (ulong) UT_LIST_GET_LEN(buf_pool->free),
+ (ulong) UT_LIST_GET_LEN(buf_pool->flush_list),
+ (ulong) buf_pool->n_pend_unzip,
+ (ulong) buf_pool->n_pend_reads,
+ (ulong) buf_pool->n_flush[BUF_FLUSH_LRU],
+ (ulong) buf_pool->n_flush[BUF_FLUSH_LIST],
+ (ulong) buf_pool->n_flush[BUF_FLUSH_SINGLE_PAGE],
+ (ulong) buf_pool->n_pages_read, buf_pool->n_pages_created,
+ (ulong) buf_pool->n_pages_written);
+
+ /* Count the number of blocks belonging to each index in the buffer */
+
+ n_found = 0;
+
+ chunk = buf_pool->chunks;
+
+ for (i = buf_pool->n_chunks; i--; chunk++) {
+ buf_block_t* block = chunk->blocks;
+ ulint n_blocks = chunk->size;
+
+ for (; n_blocks--; block++) {
+ const buf_frame_t* frame = block->frame;
+
+ if (fil_page_get_type(frame) == FIL_PAGE_INDEX) {
+
+ id = btr_page_get_index_id(frame);
+
+ /* Look for the id in the index_ids array */
+ j = 0;
+
+ while (j < n_found) {
+
+ if (ut_dulint_cmp(index_ids[j],
+ id) == 0) {
+ counts[j]++;
+
+ break;
+ }
+ j++;
+ }
+
+ if (j == n_found) {
+ n_found++;
+ index_ids[j] = id;
+ counts[j] = 1;
+ }
+ }
+ }
+ }
+
+ buf_pool_mutex_exit();
+
+ for (i = 0; i < n_found; i++) {
+ index = dict_index_get_if_in_cache(index_ids[i]);
+
+ fprintf(stderr,
+ "Block count for index %lu in buffer is about %lu",
+ (ulong) ut_dulint_get_low(index_ids[i]),
+ (ulong) counts[i]);
+
+ if (index) {
+ putc(' ', stderr);
+ dict_index_name_print(stderr, NULL, index);
+ }
+
+ putc('\n', stderr);
+ }
+
+ mem_free(index_ids);
+ mem_free(counts);
+
+ ut_a(buf_validate());
+}
+#endif /* UNIV_DEBUG_PRINT || UNIV_DEBUG || UNIV_BUF_DEBUG */
+
+#ifdef UNIV_DEBUG
+/*********************************************************************//**
+Returns the number of latched pages in the buffer pool.
+@return number of latched pages */
+UNIV_INTERN
+ulint
+buf_get_latched_pages_number(void)
+/*==============================*/
+{
+ buf_chunk_t* chunk;
+ buf_page_t* b;
+ ulint i;
+ ulint fixed_pages_number = 0;
+
+ buf_pool_mutex_enter();
+
+ chunk = buf_pool->chunks;
+
+ for (i = buf_pool->n_chunks; i--; chunk++) {
+ buf_block_t* block;
+ ulint j;
+
+ block = chunk->blocks;
+
+ for (j = chunk->size; j--; block++) {
+ if (buf_block_get_state(block)
+ != BUF_BLOCK_FILE_PAGE) {
+
+ continue;
+ }
+
+ mutex_enter(&block->mutex);
+
+ if (block->page.buf_fix_count != 0
+ || buf_page_get_io_fix(&block->page)
+ != BUF_IO_NONE) {
+ fixed_pages_number++;
+ }
+
+ mutex_exit(&block->mutex);
+ }
+ }
+
+ mutex_enter(&buf_pool_zip_mutex);
+
+ /* Traverse the lists of clean and dirty compressed-only blocks. */
+
+ for (b = UT_LIST_GET_FIRST(buf_pool->zip_clean); b;
+ b = UT_LIST_GET_NEXT(list, b)) {
+ ut_a(buf_page_get_state(b) == BUF_BLOCK_ZIP_PAGE);
+ ut_a(buf_page_get_io_fix(b) != BUF_IO_WRITE);
+
+ if (b->buf_fix_count != 0
+ || buf_page_get_io_fix(b) != BUF_IO_NONE) {
+ fixed_pages_number++;
+ }
+ }
+
+ for (b = UT_LIST_GET_FIRST(buf_pool->flush_list); b;
+ b = UT_LIST_GET_NEXT(list, b)) {
+ ut_ad(b->in_flush_list);
+
+ switch (buf_page_get_state(b)) {
+ case BUF_BLOCK_ZIP_DIRTY:
+ if (b->buf_fix_count != 0
+ || buf_page_get_io_fix(b) != BUF_IO_NONE) {
+ fixed_pages_number++;
+ }
+ break;
+ case BUF_BLOCK_FILE_PAGE:
+ /* uncompressed page */
+ break;
+ case BUF_BLOCK_ZIP_FREE:
+ case BUF_BLOCK_ZIP_PAGE:
+ case BUF_BLOCK_NOT_USED:
+ case BUF_BLOCK_READY_FOR_USE:
+ case BUF_BLOCK_MEMORY:
+ case BUF_BLOCK_REMOVE_HASH:
+ ut_error;
+ break;
+ }
+ }
+
+ mutex_exit(&buf_pool_zip_mutex);
+ buf_pool_mutex_exit();
+
+ return(fixed_pages_number);
+}
+#endif /* UNIV_DEBUG */
+
+/*********************************************************************//**
+Returns the number of pending buf pool ios.
+@return number of pending I/O operations */
+UNIV_INTERN
+ulint
+buf_get_n_pending_ios(void)
+/*=======================*/
+{
+ return(buf_pool->n_pend_reads
+ + buf_pool->n_flush[BUF_FLUSH_LRU]
+ + buf_pool->n_flush[BUF_FLUSH_LIST]
+ + buf_pool->n_flush[BUF_FLUSH_SINGLE_PAGE]);
+}
+
+/*********************************************************************//**
+Returns the ratio in percents of modified pages in the buffer pool /
+database pages in the buffer pool.
+@return modified page percentage ratio */
+UNIV_INTERN
+ulint
+buf_get_modified_ratio_pct(void)
+/*============================*/
+{
+ ulint ratio;
+
+ buf_pool_mutex_enter();
+
+ ratio = (100 * UT_LIST_GET_LEN(buf_pool->flush_list))
+ / (1 + UT_LIST_GET_LEN(buf_pool->LRU)
+ + UT_LIST_GET_LEN(buf_pool->free));
+
+ /* 1 + is there to avoid division by zero */
+
+ buf_pool_mutex_exit();
+
+ return(ratio);
+}
+
+/*********************************************************************//**
+Prints info of the buffer i/o. */
+UNIV_INTERN
+void
+buf_print_io(
+/*=========*/
+ FILE* file) /*!< in/out: buffer where to print */
+{
+ time_t current_time;
+ double time_elapsed;
+ ulint size;
+
+ ut_ad(buf_pool);
+ size = buf_pool->curr_size;
+
+ buf_pool_mutex_enter();
+
+ fprintf(file,
+ "Buffer pool size %lu\n"
+ "Free buffers %lu\n"
+ "Database pages %lu\n"
+ "Modified db pages %lu\n"
+ "Pending reads %lu\n"
+ "Pending writes: LRU %lu, flush list %lu, single page %lu\n",
+ (ulong) size,
+ (ulong) UT_LIST_GET_LEN(buf_pool->free),
+ (ulong) UT_LIST_GET_LEN(buf_pool->LRU),
+ (ulong) UT_LIST_GET_LEN(buf_pool->flush_list),
+ (ulong) buf_pool->n_pend_reads,
+ (ulong) buf_pool->n_flush[BUF_FLUSH_LRU]
+ + buf_pool->init_flush[BUF_FLUSH_LRU],
+ (ulong) buf_pool->n_flush[BUF_FLUSH_LIST]
+ + buf_pool->init_flush[BUF_FLUSH_LIST],
+ (ulong) buf_pool->n_flush[BUF_FLUSH_SINGLE_PAGE]);
+
+ current_time = time(NULL);
+ time_elapsed = 0.001 + difftime(current_time,
+ buf_pool->last_printout_time);
+ buf_pool->last_printout_time = current_time;
+
+ fprintf(file,
+ "Pages read %lu, created %lu, written %lu\n"
+ "%.2f reads/s, %.2f creates/s, %.2f writes/s\n",
+ (ulong) buf_pool->n_pages_read,
+ (ulong) buf_pool->n_pages_created,
+ (ulong) buf_pool->n_pages_written,
+ (buf_pool->n_pages_read - buf_pool->n_pages_read_old)
+ / time_elapsed,
+ (buf_pool->n_pages_created - buf_pool->n_pages_created_old)
+ / time_elapsed,
+ (buf_pool->n_pages_written - buf_pool->n_pages_written_old)
+ / time_elapsed);
+
+ if (buf_pool->n_page_gets > buf_pool->n_page_gets_old) {
+ fprintf(file, "Buffer pool hit rate %lu / 1000\n",
+ (ulong)
+ (1000 - ((1000 * (buf_pool->n_pages_read
+ - buf_pool->n_pages_read_old))
+ / (buf_pool->n_page_gets
+ - buf_pool->n_page_gets_old))));
+ } else {
+ fputs("No buffer pool page gets since the last printout\n",
+ file);
+ }
+
+ buf_pool->n_page_gets_old = buf_pool->n_page_gets;
+ buf_pool->n_pages_read_old = buf_pool->n_pages_read;
+ buf_pool->n_pages_created_old = buf_pool->n_pages_created;
+ buf_pool->n_pages_written_old = buf_pool->n_pages_written;
+
+ /* Print some values to help us with visualizing what is
+ happening with LRU eviction. */
+ fprintf(file,
+ "LRU len: %lu, unzip_LRU len: %lu\n"
+ "I/O sum[%lu]:cur[%lu], unzip sum[%lu]:cur[%lu]\n",
+ UT_LIST_GET_LEN(buf_pool->LRU),
+ UT_LIST_GET_LEN(buf_pool->unzip_LRU),
+ buf_LRU_stat_sum.io, buf_LRU_stat_cur.io,
+ buf_LRU_stat_sum.unzip, buf_LRU_stat_cur.unzip);
+
+ buf_pool_mutex_exit();
+}
+
+/**********************************************************************//**
+Refreshes the statistics used to print per-second averages. */
+UNIV_INTERN
+void
+buf_refresh_io_stats(void)
+/*======================*/
+{
+ buf_pool->last_printout_time = time(NULL);
+ buf_pool->n_page_gets_old = buf_pool->n_page_gets;
+ buf_pool->n_pages_read_old = buf_pool->n_pages_read;
+ buf_pool->n_pages_created_old = buf_pool->n_pages_created;
+ buf_pool->n_pages_written_old = buf_pool->n_pages_written;
+}
+
+/*********************************************************************//**
+Asserts that all file pages in the buffer are in a replaceable state.
+@return TRUE */
+UNIV_INTERN
+ibool
+buf_all_freed(void)
+/*===============*/
+{
+ buf_chunk_t* chunk;
+ ulint i;
+
+ ut_ad(buf_pool);
+
+ buf_pool_mutex_enter();
+
+ chunk = buf_pool->chunks;
+
+ for (i = buf_pool->n_chunks; i--; chunk++) {
+
+ const buf_block_t* block = buf_chunk_not_freed(chunk);
+
+ if (UNIV_LIKELY_NULL(block)) {
+ fprintf(stderr,
+ "Page %lu %lu still fixed or dirty\n",
+ (ulong) block->page.space,
+ (ulong) block->page.offset);
+ ut_error;
+ }
+ }
+
+ buf_pool_mutex_exit();
+
+ return(TRUE);
+}
+
+/*********************************************************************//**
+Checks that there currently are no pending i/o-operations for the buffer
+pool.
+@return TRUE if there is no pending i/o */
+UNIV_INTERN
+ibool
+buf_pool_check_no_pending_io(void)
+/*==============================*/
+{
+ ibool ret;
+
+ buf_pool_mutex_enter();
+
+ if (buf_pool->n_pend_reads + buf_pool->n_flush[BUF_FLUSH_LRU]
+ + buf_pool->n_flush[BUF_FLUSH_LIST]
+ + buf_pool->n_flush[BUF_FLUSH_SINGLE_PAGE]) {
+ ret = FALSE;
+ } else {
+ ret = TRUE;
+ }
+
+ buf_pool_mutex_exit();
+
+ return(ret);
+}
+
+/*********************************************************************//**
+Gets the current length of the free list of buffer blocks.
+@return length of the free list */
+UNIV_INTERN
+ulint
+buf_get_free_list_len(void)
+/*=======================*/
+{
+ ulint len;
+
+ buf_pool_mutex_enter();
+
+ len = UT_LIST_GET_LEN(buf_pool->free);
+
+ buf_pool_mutex_exit();
+
+ return(len);
+}
+#else /* !UNIV_HOTBACKUP */
+/********************************************************************//**
+Inits a page to the buffer buf_pool, for use in ibbackup --restore. */
+UNIV_INTERN
+void
+buf_page_init_for_backup_restore(
+/*=============================*/
+ ulint space, /*!< in: space id */
+ ulint offset, /*!< in: offset of the page within space
+ in units of a page */
+ ulint zip_size,/*!< in: compressed page size in bytes
+ or 0 for uncompressed pages */
+ buf_block_t* block) /*!< in: block to init */
+{
+ block->page.state = BUF_BLOCK_FILE_PAGE;
+ block->page.space = space;
+ block->page.offset = offset;
+
+ page_zip_des_init(&block->page.zip);
+
+ /* We assume that block->page.data has been allocated
+ with zip_size == UNIV_PAGE_SIZE. */
+ ut_ad(zip_size <= UNIV_PAGE_SIZE);
+ ut_ad(ut_is_2pow(zip_size));
+ page_zip_set_size(&block->page.zip, zip_size);
+ if (zip_size) {
+ block->page.zip.data = block->frame + UNIV_PAGE_SIZE;
+ }
+}
+#endif /* !UNIV_HOTBACKUP */
diff --git a/storage/innodb_plugin/buf/buf0flu.c b/storage/innodb_plugin/buf/buf0flu.c
new file mode 100644
index 00000000000..74dd0c07ca6
--- /dev/null
+++ b/storage/innodb_plugin/buf/buf0flu.c
@@ -0,0 +1,1400 @@
+/*****************************************************************************
+
+Copyright (c) 1995, 2009, Innobase Oy. All Rights Reserved.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; version 2 of the License.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place, Suite 330, Boston, MA 02111-1307 USA
+
+*****************************************************************************/
+
+/**************************************************//**
+@file buf/buf0flu.c
+The database buffer buf_pool flush algorithm
+
+Created 11/11/1995 Heikki Tuuri
+*******************************************************/
+
+#include "buf0flu.h"
+
+#ifdef UNIV_NONINL
+#include "buf0flu.ic"
+#endif
+
+#include "buf0buf.h"
+#include "srv0srv.h"
+#include "page0zip.h"
+#ifndef UNIV_HOTBACKUP
+#include "ut0byte.h"
+#include "ut0lst.h"
+#include "page0page.h"
+#include "fil0fil.h"
+#include "buf0lru.h"
+#include "buf0rea.h"
+#include "ibuf0ibuf.h"
+#include "log0log.h"
+#include "os0file.h"
+#include "trx0sys.h"
+
+/**********************************************************************
+These statistics are generated for heuristics used in estimating the
+rate at which we should flush the dirty blocks to avoid bursty IO
+activity. Note that the rate of flushing not only depends on how many
+dirty pages we have in the buffer pool but it is also a fucntion of
+how much redo the workload is generating and at what rate. */
+/* @{ */
+
+/** Number of intervals for which we keep the history of these stats.
+Each interval is 1 second, defined by the rate at which
+srv_error_monitor_thread() calls buf_flush_stat_update(). */
+#define BUF_FLUSH_STAT_N_INTERVAL 20
+
+/** Sampled values buf_flush_stat_cur.
+Not protected by any mutex. Updated by buf_flush_stat_update(). */
+static buf_flush_stat_t buf_flush_stat_arr[BUF_FLUSH_STAT_N_INTERVAL];
+
+/** Cursor to buf_flush_stat_arr[]. Updated in a round-robin fashion. */
+static ulint buf_flush_stat_arr_ind;
+
+/** Values at start of the current interval. Reset by
+buf_flush_stat_update(). */
+static buf_flush_stat_t buf_flush_stat_cur;
+
+/** Running sum of past values of buf_flush_stat_cur.
+Updated by buf_flush_stat_update(). Not protected by any mutex. */
+static buf_flush_stat_t buf_flush_stat_sum;
+
+/** Number of pages flushed through non flush_list flushes. */
+static ulint buf_lru_flush_page_count = 0;
+
+/* @} */
+
+#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
+/******************************************************************//**
+Validates the flush list.
+@return TRUE if ok */
+static
+ibool
+buf_flush_validate_low(void);
+/*========================*/
+#endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
+
+/********************************************************************//**
+Inserts a modified block into the flush list. */
+UNIV_INTERN
+void
+buf_flush_insert_into_flush_list(
+/*=============================*/
+ buf_block_t* block) /*!< in/out: block which is modified */
+{
+ ut_ad(buf_pool_mutex_own());
+ ut_ad((UT_LIST_GET_FIRST(buf_pool->flush_list) == NULL)
+ || (UT_LIST_GET_FIRST(buf_pool->flush_list)->oldest_modification
+ <= block->page.oldest_modification));
+
+ ut_ad(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE);
+ ut_ad(block->page.in_LRU_list);
+ ut_ad(block->page.in_page_hash);
+ ut_ad(!block->page.in_zip_hash);
+ ut_ad(!block->page.in_flush_list);
+ ut_d(block->page.in_flush_list = TRUE);
+ UT_LIST_ADD_FIRST(list, buf_pool->flush_list, &block->page);
+
+#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
+ ut_a(buf_flush_validate_low());
+#endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
+}
+
+/********************************************************************//**
+Inserts a modified block into the flush list in the right sorted position.
+This function is used by recovery, because there the modifications do not
+necessarily come in the order of lsn's. */
+UNIV_INTERN
+void
+buf_flush_insert_sorted_into_flush_list(
+/*====================================*/
+ buf_block_t* block) /*!< in/out: block which is modified */
+{
+ buf_page_t* prev_b;
+ buf_page_t* b;
+
+ ut_ad(buf_pool_mutex_own());
+ ut_ad(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE);
+
+ ut_ad(block->page.in_LRU_list);
+ ut_ad(block->page.in_page_hash);
+ ut_ad(!block->page.in_zip_hash);
+ ut_ad(!block->page.in_flush_list);
+ ut_d(block->page.in_flush_list = TRUE);
+
+ prev_b = NULL;
+ b = UT_LIST_GET_FIRST(buf_pool->flush_list);
+
+ while (b && b->oldest_modification > block->page.oldest_modification) {
+ ut_ad(b->in_flush_list);
+ prev_b = b;
+ b = UT_LIST_GET_NEXT(list, b);
+ }
+
+ if (prev_b == NULL) {
+ UT_LIST_ADD_FIRST(list, buf_pool->flush_list, &block->page);
+ } else {
+ UT_LIST_INSERT_AFTER(list, buf_pool->flush_list,
+ prev_b, &block->page);
+ }
+
+#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
+ ut_a(buf_flush_validate_low());
+#endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
+}
+
+/********************************************************************//**
+Returns TRUE if the file page block is immediately suitable for replacement,
+i.e., the transition FILE_PAGE => NOT_USED allowed.
+@return TRUE if can replace immediately */
+UNIV_INTERN
+ibool
+buf_flush_ready_for_replace(
+/*========================*/
+ buf_page_t* bpage) /*!< in: buffer control block, must be
+ buf_page_in_file(bpage) and in the LRU list */
+{
+ ut_ad(buf_pool_mutex_own());
+ ut_ad(mutex_own(buf_page_get_mutex(bpage)));
+ ut_ad(bpage->in_LRU_list);
+
+ if (UNIV_LIKELY(buf_page_in_file(bpage))) {
+
+ return(bpage->oldest_modification == 0
+ && buf_page_get_io_fix(bpage) == BUF_IO_NONE
+ && bpage->buf_fix_count == 0);
+ }
+
+ ut_print_timestamp(stderr);
+ fprintf(stderr,
+ " InnoDB: Error: buffer block state %lu"
+ " in the LRU list!\n",
+ (ulong) buf_page_get_state(bpage));
+ ut_print_buf(stderr, bpage, sizeof(buf_page_t));
+ putc('\n', stderr);
+
+ return(FALSE);
+}
+
+/********************************************************************//**
+Returns TRUE if the block is modified and ready for flushing.
+@return TRUE if can flush immediately */
+UNIV_INLINE
+ibool
+buf_flush_ready_for_flush(
+/*======================*/
+ buf_page_t* bpage, /*!< in: buffer control block, must be
+ buf_page_in_file(bpage) */
+ enum buf_flush flush_type)/*!< in: BUF_FLUSH_LRU or BUF_FLUSH_LIST */
+{
+ ut_a(buf_page_in_file(bpage));
+ ut_ad(buf_pool_mutex_own());
+ ut_ad(mutex_own(buf_page_get_mutex(bpage)));
+ ut_ad(flush_type == BUF_FLUSH_LRU || BUF_FLUSH_LIST);
+
+ if (bpage->oldest_modification != 0
+ && buf_page_get_io_fix(bpage) == BUF_IO_NONE) {
+ ut_ad(bpage->in_flush_list);
+
+ if (flush_type != BUF_FLUSH_LRU) {
+
+ return(TRUE);
+
+ } else if (bpage->buf_fix_count == 0) {
+
+ /* If we are flushing the LRU list, to avoid deadlocks
+ we require the block not to be bufferfixed, and hence
+ not latched. */
+
+ return(TRUE);
+ }
+ }
+
+ return(FALSE);
+}
+
+/********************************************************************//**
+Remove a block from the flush list of modified blocks. */
+UNIV_INTERN
+void
+buf_flush_remove(
+/*=============*/
+ buf_page_t* bpage) /*!< in: pointer to the block in question */
+{
+ ut_ad(buf_pool_mutex_own());
+ ut_ad(mutex_own(buf_page_get_mutex(bpage)));
+ ut_ad(bpage->in_flush_list);
+ ut_d(bpage->in_flush_list = FALSE);
+
+ switch (buf_page_get_state(bpage)) {
+ case BUF_BLOCK_ZIP_PAGE:
+ /* clean compressed pages should not be on the flush list */
+ case BUF_BLOCK_ZIP_FREE:
+ case BUF_BLOCK_NOT_USED:
+ case BUF_BLOCK_READY_FOR_USE:
+ case BUF_BLOCK_MEMORY:
+ case BUF_BLOCK_REMOVE_HASH:
+ ut_error;
+ return;
+ case BUF_BLOCK_ZIP_DIRTY:
+ buf_page_set_state(bpage, BUF_BLOCK_ZIP_PAGE);
+ UT_LIST_REMOVE(list, buf_pool->flush_list, bpage);
+ buf_LRU_insert_zip_clean(bpage);
+ break;
+ case BUF_BLOCK_FILE_PAGE:
+ UT_LIST_REMOVE(list, buf_pool->flush_list, bpage);
+ break;
+ }
+
+ bpage->oldest_modification = 0;
+
+ ut_d(UT_LIST_VALIDATE(list, buf_page_t, buf_pool->flush_list,
+ ut_ad(ut_list_node_313->in_flush_list)));
+}
+
+/********************************************************************//**
+Updates the flush system data structures when a write is completed. */
+UNIV_INTERN
+void
+buf_flush_write_complete(
+/*=====================*/
+ buf_page_t* bpage) /*!< in: pointer to the block in question */
+{
+ enum buf_flush flush_type;
+
+ ut_ad(bpage);
+
+ buf_flush_remove(bpage);
+
+ flush_type = buf_page_get_flush_type(bpage);
+ buf_pool->n_flush[flush_type]--;
+
+ if (flush_type == BUF_FLUSH_LRU) {
+ /* Put the block to the end of the LRU list to wait to be
+ moved to the free list */
+
+ buf_LRU_make_block_old(bpage);
+
+ buf_pool->LRU_flush_ended++;
+ }
+
+ /* fprintf(stderr, "n pending flush %lu\n",
+ buf_pool->n_flush[flush_type]); */
+
+ if ((buf_pool->n_flush[flush_type] == 0)
+ && (buf_pool->init_flush[flush_type] == FALSE)) {
+
+ /* The running flush batch has ended */
+
+ os_event_set(buf_pool->no_flush[flush_type]);
+ }
+}
+
+/********************************************************************//**
+Flushes possible buffered writes from the doublewrite memory buffer to disk,
+and also wakes up the aio thread if simulated aio is used. It is very
+important to call this function after a batch of writes has been posted,
+and also when we may have to wait for a page latch! Otherwise a deadlock
+of threads can occur. */
+static
+void
+buf_flush_buffered_writes(void)
+/*===========================*/
+{
+ byte* write_buf;
+ ulint len;
+ ulint len2;
+ ulint i;
+
+ if (!srv_use_doublewrite_buf || trx_doublewrite == NULL) {
+ os_aio_simulated_wake_handler_threads();
+
+ return;
+ }
+
+ mutex_enter(&(trx_doublewrite->mutex));
+
+ /* Write first to doublewrite buffer blocks. We use synchronous
+ aio and thus know that file write has been completed when the
+ control returns. */
+
+ if (trx_doublewrite->first_free == 0) {
+
+ mutex_exit(&(trx_doublewrite->mutex));
+
+ return;
+ }
+
+ for (i = 0; i < trx_doublewrite->first_free; i++) {
+
+ const buf_block_t* block;
+
+ block = (buf_block_t*) trx_doublewrite->buf_block_arr[i];
+
+ if (buf_block_get_state(block) != BUF_BLOCK_FILE_PAGE
+ || block->page.zip.data) {
+ /* No simple validate for compressed pages exists. */
+ continue;
+ }
+
+ if (UNIV_UNLIKELY
+ (memcmp(block->frame + (FIL_PAGE_LSN + 4),
+ block->frame + (UNIV_PAGE_SIZE
+ - FIL_PAGE_END_LSN_OLD_CHKSUM + 4),
+ 4))) {
+ ut_print_timestamp(stderr);
+ fprintf(stderr,
+ " InnoDB: ERROR: The page to be written"
+ " seems corrupt!\n"
+ "InnoDB: The lsn fields do not match!"
+ " Noticed in the buffer pool\n"
+ "InnoDB: before posting to the"
+ " doublewrite buffer.\n");
+ }
+
+ if (!block->check_index_page_at_flush) {
+ } else if (page_is_comp(block->frame)) {
+ if (UNIV_UNLIKELY
+ (!page_simple_validate_new(block->frame))) {
+corrupted_page:
+ buf_page_print(block->frame, 0);
+
+ ut_print_timestamp(stderr);
+ fprintf(stderr,
+ " InnoDB: Apparent corruption of an"
+ " index page n:o %lu in space %lu\n"
+ "InnoDB: to be written to data file."
+ " We intentionally crash server\n"
+ "InnoDB: to prevent corrupt data"
+ " from ending up in data\n"
+ "InnoDB: files.\n",
+ (ulong) buf_block_get_page_no(block),
+ (ulong) buf_block_get_space(block));
+
+ ut_error;
+ }
+ } else if (UNIV_UNLIKELY
+ (!page_simple_validate_old(block->frame))) {
+
+ goto corrupted_page;
+ }
+ }
+
+ /* increment the doublewrite flushed pages counter */
+ srv_dblwr_pages_written+= trx_doublewrite->first_free;
+ srv_dblwr_writes++;
+
+ len = ut_min(TRX_SYS_DOUBLEWRITE_BLOCK_SIZE,
+ trx_doublewrite->first_free) * UNIV_PAGE_SIZE;
+
+ write_buf = trx_doublewrite->write_buf;
+ i = 0;
+
+ fil_io(OS_FILE_WRITE, TRUE, TRX_SYS_SPACE, 0,
+ trx_doublewrite->block1, 0, len,
+ (void*) write_buf, NULL);
+
+ for (len2 = 0; len2 + UNIV_PAGE_SIZE <= len;
+ len2 += UNIV_PAGE_SIZE, i++) {
+ const buf_block_t* block = (buf_block_t*)
+ trx_doublewrite->buf_block_arr[i];
+
+ if (UNIV_LIKELY(!block->page.zip.data)
+ && UNIV_LIKELY(buf_block_get_state(block)
+ == BUF_BLOCK_FILE_PAGE)
+ && UNIV_UNLIKELY
+ (memcmp(write_buf + len2 + (FIL_PAGE_LSN + 4),
+ write_buf + len2
+ + (UNIV_PAGE_SIZE
+ - FIL_PAGE_END_LSN_OLD_CHKSUM + 4), 4))) {
+ ut_print_timestamp(stderr);
+ fprintf(stderr,
+ " InnoDB: ERROR: The page to be written"
+ " seems corrupt!\n"
+ "InnoDB: The lsn fields do not match!"
+ " Noticed in the doublewrite block1.\n");
+ }
+ }
+
+ if (trx_doublewrite->first_free <= TRX_SYS_DOUBLEWRITE_BLOCK_SIZE) {
+ goto flush;
+ }
+
+ len = (trx_doublewrite->first_free - TRX_SYS_DOUBLEWRITE_BLOCK_SIZE)
+ * UNIV_PAGE_SIZE;
+
+ write_buf = trx_doublewrite->write_buf
+ + TRX_SYS_DOUBLEWRITE_BLOCK_SIZE * UNIV_PAGE_SIZE;
+ ut_ad(i == TRX_SYS_DOUBLEWRITE_BLOCK_SIZE);
+
+ fil_io(OS_FILE_WRITE, TRUE, TRX_SYS_SPACE, 0,
+ trx_doublewrite->block2, 0, len,
+ (void*) write_buf, NULL);
+
+ for (len2 = 0; len2 + UNIV_PAGE_SIZE <= len;
+ len2 += UNIV_PAGE_SIZE, i++) {
+ const buf_block_t* block = (buf_block_t*)
+ trx_doublewrite->buf_block_arr[i];
+
+ if (UNIV_LIKELY(!block->page.zip.data)
+ && UNIV_LIKELY(buf_block_get_state(block)
+ == BUF_BLOCK_FILE_PAGE)
+ && UNIV_UNLIKELY
+ (memcmp(write_buf + len2 + (FIL_PAGE_LSN + 4),
+ write_buf + len2
+ + (UNIV_PAGE_SIZE
+ - FIL_PAGE_END_LSN_OLD_CHKSUM + 4), 4))) {
+ ut_print_timestamp(stderr);
+ fprintf(stderr,
+ " InnoDB: ERROR: The page to be"
+ " written seems corrupt!\n"
+ "InnoDB: The lsn fields do not match!"
+ " Noticed in"
+ " the doublewrite block2.\n");
+ }
+ }
+
+flush:
+ /* Now flush the doublewrite buffer data to disk */
+
+ fil_flush(TRX_SYS_SPACE);
+
+ /* We know that the writes have been flushed to disk now
+ and in recovery we will find them in the doublewrite buffer
+ blocks. Next do the writes to the intended positions. */
+
+ for (i = 0; i < trx_doublewrite->first_free; i++) {
+ const buf_block_t* block = (buf_block_t*)
+ trx_doublewrite->buf_block_arr[i];
+
+ ut_a(buf_page_in_file(&block->page));
+ if (UNIV_LIKELY_NULL(block->page.zip.data)) {
+ fil_io(OS_FILE_WRITE | OS_AIO_SIMULATED_WAKE_LATER,
+ FALSE, buf_page_get_space(&block->page),
+ buf_page_get_zip_size(&block->page),
+ buf_page_get_page_no(&block->page), 0,
+ buf_page_get_zip_size(&block->page),
+ (void*)block->page.zip.data,
+ (void*)block);
+
+ /* Increment the counter of I/O operations used
+ for selecting LRU policy. */
+ buf_LRU_stat_inc_io();
+
+ continue;
+ }
+
+ ut_a(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE);
+
+ if (UNIV_UNLIKELY(memcmp(block->frame + (FIL_PAGE_LSN + 4),
+ block->frame
+ + (UNIV_PAGE_SIZE
+ - FIL_PAGE_END_LSN_OLD_CHKSUM + 4),
+ 4))) {
+ ut_print_timestamp(stderr);
+ fprintf(stderr,
+ " InnoDB: ERROR: The page to be written"
+ " seems corrupt!\n"
+ "InnoDB: The lsn fields do not match!"
+ " Noticed in the buffer pool\n"
+ "InnoDB: after posting and flushing"
+ " the doublewrite buffer.\n"
+ "InnoDB: Page buf fix count %lu,"
+ " io fix %lu, state %lu\n",
+ (ulong)block->page.buf_fix_count,
+ (ulong)buf_block_get_io_fix(block),
+ (ulong)buf_block_get_state(block));
+ }
+
+ fil_io(OS_FILE_WRITE | OS_AIO_SIMULATED_WAKE_LATER,
+ FALSE, buf_block_get_space(block), 0,
+ buf_block_get_page_no(block), 0, UNIV_PAGE_SIZE,
+ (void*)block->frame, (void*)block);
+
+ /* Increment the counter of I/O operations used
+ for selecting LRU policy. */
+ buf_LRU_stat_inc_io();
+ }
+
+ /* Wake possible simulated aio thread to actually post the
+ writes to the operating system */
+
+ os_aio_simulated_wake_handler_threads();
+
+ /* Wait that all async writes to tablespaces have been posted to
+ the OS */
+
+ os_aio_wait_until_no_pending_writes();
+
+ /* Now we flush the data to disk (for example, with fsync) */
+
+ fil_flush_file_spaces(FIL_TABLESPACE);
+
+ /* We can now reuse the doublewrite memory buffer: */
+
+ trx_doublewrite->first_free = 0;
+
+ mutex_exit(&(trx_doublewrite->mutex));
+}
+
+/********************************************************************//**
+Posts a buffer page for writing. If the doublewrite memory buffer is
+full, calls buf_flush_buffered_writes and waits for for free space to
+appear. */
+static
+void
+buf_flush_post_to_doublewrite_buf(
+/*==============================*/
+ buf_page_t* bpage) /*!< in: buffer block to write */
+{
+ ulint zip_size;
+try_again:
+ mutex_enter(&(trx_doublewrite->mutex));
+
+ ut_a(buf_page_in_file(bpage));
+
+ if (trx_doublewrite->first_free
+ >= 2 * TRX_SYS_DOUBLEWRITE_BLOCK_SIZE) {
+ mutex_exit(&(trx_doublewrite->mutex));
+
+ buf_flush_buffered_writes();
+
+ goto try_again;
+ }
+
+ zip_size = buf_page_get_zip_size(bpage);
+
+ if (UNIV_UNLIKELY(zip_size)) {
+ /* Copy the compressed page and clear the rest. */
+ memcpy(trx_doublewrite->write_buf
+ + UNIV_PAGE_SIZE * trx_doublewrite->first_free,
+ bpage->zip.data, zip_size);
+ memset(trx_doublewrite->write_buf
+ + UNIV_PAGE_SIZE * trx_doublewrite->first_free
+ + zip_size, 0, UNIV_PAGE_SIZE - zip_size);
+ } else {
+ ut_a(buf_page_get_state(bpage) == BUF_BLOCK_FILE_PAGE);
+
+ memcpy(trx_doublewrite->write_buf
+ + UNIV_PAGE_SIZE * trx_doublewrite->first_free,
+ ((buf_block_t*) bpage)->frame, UNIV_PAGE_SIZE);
+ }
+
+ trx_doublewrite->buf_block_arr[trx_doublewrite->first_free] = bpage;
+
+ trx_doublewrite->first_free++;
+
+ if (trx_doublewrite->first_free
+ >= 2 * TRX_SYS_DOUBLEWRITE_BLOCK_SIZE) {
+ mutex_exit(&(trx_doublewrite->mutex));
+
+ buf_flush_buffered_writes();
+
+ return;
+ }
+
+ mutex_exit(&(trx_doublewrite->mutex));
+}
+#endif /* !UNIV_HOTBACKUP */
+
+/********************************************************************//**
+Initializes a page for writing to the tablespace. */
+UNIV_INTERN
+void
+buf_flush_init_for_writing(
+/*=======================*/
+ byte* page, /*!< in/out: page */
+ void* page_zip_, /*!< in/out: compressed page, or NULL */
+ ib_uint64_t newest_lsn) /*!< in: newest modification lsn
+ to the page */
+{
+ ut_ad(page);
+
+ if (page_zip_) {
+ page_zip_des_t* page_zip = page_zip_;
+ ulint zip_size = page_zip_get_size(page_zip);
+ ut_ad(zip_size);
+ ut_ad(ut_is_2pow(zip_size));
+ ut_ad(zip_size <= UNIV_PAGE_SIZE);
+
+ switch (UNIV_EXPECT(fil_page_get_type(page), FIL_PAGE_INDEX)) {
+ case FIL_PAGE_TYPE_ALLOCATED:
+ case FIL_PAGE_INODE:
+ case FIL_PAGE_IBUF_BITMAP:
+ case FIL_PAGE_TYPE_FSP_HDR:
+ case FIL_PAGE_TYPE_XDES:
+ /* These are essentially uncompressed pages. */
+ memcpy(page_zip->data, page, zip_size);
+ /* fall through */
+ case FIL_PAGE_TYPE_ZBLOB:
+ case FIL_PAGE_TYPE_ZBLOB2:
+ case FIL_PAGE_INDEX:
+ mach_write_ull(page_zip->data
+ + FIL_PAGE_LSN, newest_lsn);
+ memset(page_zip->data + FIL_PAGE_FILE_FLUSH_LSN, 0, 8);
+ mach_write_to_4(page_zip->data
+ + FIL_PAGE_SPACE_OR_CHKSUM,
+ srv_use_checksums
+ ? page_zip_calc_checksum(
+ page_zip->data, zip_size)
+ : BUF_NO_CHECKSUM_MAGIC);
+ return;
+ }
+
+ ut_print_timestamp(stderr);
+ fputs(" InnoDB: ERROR: The compressed page to be written"
+ " seems corrupt:", stderr);
+ ut_print_buf(stderr, page, zip_size);
+ fputs("\nInnoDB: Possibly older version of the page:", stderr);
+ ut_print_buf(stderr, page_zip->data, zip_size);
+ putc('\n', stderr);
+ ut_error;
+ }
+
+ /* Write the newest modification lsn to the page header and trailer */
+ mach_write_ull(page + FIL_PAGE_LSN, newest_lsn);
+
+ mach_write_ull(page + UNIV_PAGE_SIZE - FIL_PAGE_END_LSN_OLD_CHKSUM,
+ newest_lsn);
+
+ /* Store the new formula checksum */
+
+ mach_write_to_4(page + FIL_PAGE_SPACE_OR_CHKSUM,
+ srv_use_checksums
+ ? buf_calc_page_new_checksum(page)
+ : BUF_NO_CHECKSUM_MAGIC);
+
+ /* We overwrite the first 4 bytes of the end lsn field to store
+ the old formula checksum. Since it depends also on the field
+ FIL_PAGE_SPACE_OR_CHKSUM, it has to be calculated after storing the
+ new formula checksum. */
+
+ mach_write_to_4(page + UNIV_PAGE_SIZE - FIL_PAGE_END_LSN_OLD_CHKSUM,
+ srv_use_checksums
+ ? buf_calc_page_old_checksum(page)
+ : BUF_NO_CHECKSUM_MAGIC);
+}
+
+#ifndef UNIV_HOTBACKUP
+/********************************************************************//**
+Does an asynchronous write of a buffer page. NOTE: in simulated aio and
+also when the doublewrite buffer is used, we must call
+buf_flush_buffered_writes after we have posted a batch of writes! */
+static
+void
+buf_flush_write_block_low(
+/*======================*/
+ buf_page_t* bpage) /*!< in: buffer block to write */
+{
+ ulint zip_size = buf_page_get_zip_size(bpage);
+ page_t* frame = NULL;
+#ifdef UNIV_LOG_DEBUG
+ static ibool univ_log_debug_warned;
+#endif /* UNIV_LOG_DEBUG */
+
+ ut_ad(buf_page_in_file(bpage));
+
+ /* We are not holding buf_pool_mutex or block_mutex here.
+ Nevertheless, it is safe to access bpage, because it is
+ io_fixed and oldest_modification != 0. Thus, it cannot be
+ relocated in the buffer pool or removed from flush_list or
+ LRU_list. */
+ ut_ad(!buf_pool_mutex_own());
+ ut_ad(!mutex_own(buf_page_get_mutex(bpage)));
+ ut_ad(buf_page_get_io_fix(bpage) == BUF_IO_WRITE);
+ ut_ad(bpage->oldest_modification != 0);
+
+#ifdef UNIV_IBUF_COUNT_DEBUG
+ ut_a(ibuf_count_get(bpage->space, bpage->offset) == 0);
+#endif
+ ut_ad(bpage->newest_modification != 0);
+
+#ifdef UNIV_LOG_DEBUG
+ if (!univ_log_debug_warned) {
+ univ_log_debug_warned = TRUE;
+ fputs("Warning: cannot force log to disk if"
+ " UNIV_LOG_DEBUG is defined!\n"
+ "Crash recovery will not work!\n",
+ stderr);
+ }
+#else
+ /* Force the log to the disk before writing the modified block */
+ log_write_up_to(bpage->newest_modification, LOG_WAIT_ALL_GROUPS, TRUE);
+#endif
+ switch (buf_page_get_state(bpage)) {
+ case BUF_BLOCK_ZIP_FREE:
+ case BUF_BLOCK_ZIP_PAGE: /* The page should be dirty. */
+ case BUF_BLOCK_NOT_USED:
+ case BUF_BLOCK_READY_FOR_USE:
+ case BUF_BLOCK_MEMORY:
+ case BUF_BLOCK_REMOVE_HASH:
+ ut_error;
+ break;
+ case BUF_BLOCK_ZIP_DIRTY:
+ frame = bpage->zip.data;
+ if (UNIV_LIKELY(srv_use_checksums)) {
+ ut_a(mach_read_from_4(frame + FIL_PAGE_SPACE_OR_CHKSUM)
+ == page_zip_calc_checksum(frame, zip_size));
+ }
+ mach_write_ull(frame + FIL_PAGE_LSN,
+ bpage->newest_modification);
+ memset(frame + FIL_PAGE_FILE_FLUSH_LSN, 0, 8);
+ break;
+ case BUF_BLOCK_FILE_PAGE:
+ frame = bpage->zip.data;
+ if (!frame) {
+ frame = ((buf_block_t*) bpage)->frame;
+ }
+
+ buf_flush_init_for_writing(((buf_block_t*) bpage)->frame,
+ bpage->zip.data
+ ? &bpage->zip : NULL,
+ bpage->newest_modification);
+ break;
+ }
+
+ if (!srv_use_doublewrite_buf || !trx_doublewrite) {
+ fil_io(OS_FILE_WRITE | OS_AIO_SIMULATED_WAKE_LATER,
+ FALSE, buf_page_get_space(bpage), zip_size,
+ buf_page_get_page_no(bpage), 0,
+ zip_size ? zip_size : UNIV_PAGE_SIZE,
+ frame, bpage);
+ } else {
+ buf_flush_post_to_doublewrite_buf(bpage);
+ }
+}
+
+/********************************************************************//**
+Writes a flushable page asynchronously from the buffer pool to a file.
+NOTE: in simulated aio we must call
+os_aio_simulated_wake_handler_threads after we have posted a batch of
+writes! NOTE: buf_pool_mutex and buf_page_get_mutex(bpage) must be
+held upon entering this function, and they will be released by this
+function. */
+static
+void
+buf_flush_page(
+/*===========*/
+ buf_page_t* bpage, /*!< in: buffer control block */
+ enum buf_flush flush_type) /*!< in: BUF_FLUSH_LRU
+ or BUF_FLUSH_LIST */
+{
+ mutex_t* block_mutex;
+ ibool is_uncompressed;
+
+ ut_ad(flush_type == BUF_FLUSH_LRU || flush_type == BUF_FLUSH_LIST);
+ ut_ad(buf_pool_mutex_own());
+ ut_ad(buf_page_in_file(bpage));
+
+ block_mutex = buf_page_get_mutex(bpage);
+ ut_ad(mutex_own(block_mutex));
+
+ ut_ad(buf_flush_ready_for_flush(bpage, flush_type));
+
+ buf_page_set_io_fix(bpage, BUF_IO_WRITE);
+
+ buf_page_set_flush_type(bpage, flush_type);
+
+ if (buf_pool->n_flush[flush_type] == 0) {
+
+ os_event_reset(buf_pool->no_flush[flush_type]);
+ }
+
+ buf_pool->n_flush[flush_type]++;
+
+ is_uncompressed = (buf_page_get_state(bpage) == BUF_BLOCK_FILE_PAGE);
+ ut_ad(is_uncompressed == (block_mutex != &buf_pool_zip_mutex));
+
+ switch (flush_type) {
+ ibool is_s_latched;
+ case BUF_FLUSH_LIST:
+ /* If the simulated aio thread is not running, we must
+ not wait for any latch, as we may end up in a deadlock:
+ if buf_fix_count == 0, then we know we need not wait */
+
+ is_s_latched = (bpage->buf_fix_count == 0);
+ if (is_s_latched && is_uncompressed) {
+ rw_lock_s_lock_gen(&((buf_block_t*) bpage)->lock,
+ BUF_IO_WRITE);
+ }
+
+ mutex_exit(block_mutex);
+ buf_pool_mutex_exit();
+
+ /* Even though bpage is not protected by any mutex at
+ this point, it is safe to access bpage, because it is
+ io_fixed and oldest_modification != 0. Thus, it
+ cannot be relocated in the buffer pool or removed from
+ flush_list or LRU_list. */
+
+ if (!is_s_latched) {
+ buf_flush_buffered_writes();
+
+ if (is_uncompressed) {
+ rw_lock_s_lock_gen(&((buf_block_t*) bpage)
+ ->lock, BUF_IO_WRITE);
+ }
+ }
+
+ break;
+
+ case BUF_FLUSH_LRU:
+ /* VERY IMPORTANT:
+ Because any thread may call the LRU flush, even when owning
+ locks on pages, to avoid deadlocks, we must make sure that the
+ s-lock is acquired on the page without waiting: this is
+ accomplished because buf_flush_ready_for_flush() must hold,
+ and that requires the page not to be bufferfixed. */
+
+ if (is_uncompressed) {
+ rw_lock_s_lock_gen(&((buf_block_t*) bpage)->lock,
+ BUF_IO_WRITE);
+ }
+
+ /* Note that the s-latch is acquired before releasing the
+ buf_pool mutex: this ensures that the latch is acquired
+ immediately. */
+
+ mutex_exit(block_mutex);
+ buf_pool_mutex_exit();
+ break;
+
+ default:
+ ut_error;
+ }
+
+ /* Even though bpage is not protected by any mutex at this
+ point, it is safe to access bpage, because it is io_fixed and
+ oldest_modification != 0. Thus, it cannot be relocated in the
+ buffer pool or removed from flush_list or LRU_list. */
+
+#ifdef UNIV_DEBUG
+ if (buf_debug_prints) {
+ fprintf(stderr,
+ "Flushing %u space %u page %u\n",
+ flush_type, bpage->space, bpage->offset);
+ }
+#endif /* UNIV_DEBUG */
+ buf_flush_write_block_low(bpage);
+}
+
+/***********************************************************//**
+Flushes to disk all flushable pages within the flush area.
+@return number of pages flushed */
+static
+ulint
+buf_flush_try_neighbors(
+/*====================*/
+ ulint space, /*!< in: space id */
+ ulint offset, /*!< in: page offset */
+ enum buf_flush flush_type) /*!< in: BUF_FLUSH_LRU or
+ BUF_FLUSH_LIST */
+{
+ buf_page_t* bpage;
+ ulint low, high;
+ ulint count = 0;
+ ulint i;
+
+ ut_ad(flush_type == BUF_FLUSH_LRU || flush_type == BUF_FLUSH_LIST);
+
+ if (UT_LIST_GET_LEN(buf_pool->LRU) < BUF_LRU_OLD_MIN_LEN) {
+ /* If there is little space, it is better not to flush any
+ block except from the end of the LRU list */
+
+ low = offset;
+ high = offset + 1;
+ } else {
+ /* When flushed, dirty blocks are searched in neighborhoods of
+ this size, and flushed along with the original page. */
+
+ ulint buf_flush_area = ut_min(BUF_READ_AHEAD_AREA,
+ buf_pool->curr_size / 16);
+
+ low = (offset / buf_flush_area) * buf_flush_area;
+ high = (offset / buf_flush_area + 1) * buf_flush_area;
+ }
+
+ /* fprintf(stderr, "Flush area: low %lu high %lu\n", low, high); */
+
+ if (high > fil_space_get_size(space)) {
+ high = fil_space_get_size(space);
+ }
+
+ buf_pool_mutex_enter();
+
+ for (i = low; i < high; i++) {
+
+ bpage = buf_page_hash_get(space, i);
+
+ if (!bpage) {
+
+ continue;
+ }
+
+ ut_a(buf_page_in_file(bpage));
+
+ /* We avoid flushing 'non-old' blocks in an LRU flush,
+ because the flushed blocks are soon freed */
+
+ if (flush_type != BUF_FLUSH_LRU
+ || i == offset
+ || buf_page_is_old(bpage)) {
+ mutex_t* block_mutex = buf_page_get_mutex(bpage);
+
+ mutex_enter(block_mutex);
+
+ if (buf_flush_ready_for_flush(bpage, flush_type)
+ && (i == offset || !bpage->buf_fix_count)) {
+ /* We only try to flush those
+ neighbors != offset where the buf fix count is
+ zero, as we then know that we probably can
+ latch the page without a semaphore wait.
+ Semaphore waits are expensive because we must
+ flush the doublewrite buffer before we start
+ waiting. */
+
+ buf_flush_page(bpage, flush_type);
+ ut_ad(!mutex_own(block_mutex));
+ count++;
+
+ buf_pool_mutex_enter();
+ } else {
+ mutex_exit(block_mutex);
+ }
+ }
+ }
+
+ buf_pool_mutex_exit();
+
+ return(count);
+}
+
+/*******************************************************************//**
+This utility flushes dirty blocks from the end of the LRU list or flush_list.
+NOTE 1: in the case of an LRU flush the calling thread may own latches to
+pages: to avoid deadlocks, this function must be written so that it cannot
+end up waiting for these latches! NOTE 2: in the case of a flush list flush,
+the calling thread is not allowed to own any latches on pages!
+@return number of blocks for which the write request was queued;
+ULINT_UNDEFINED if there was a flush of the same type already running */
+UNIV_INTERN
+ulint
+buf_flush_batch(
+/*============*/
+ enum buf_flush flush_type, /*!< in: BUF_FLUSH_LRU or
+ BUF_FLUSH_LIST; if BUF_FLUSH_LIST,
+ then the caller must not own any
+ latches on pages */
+ ulint min_n, /*!< in: wished minimum mumber of blocks
+ flushed (it is not guaranteed that the
+ actual number is that big, though) */
+ ib_uint64_t lsn_limit) /*!< in the case BUF_FLUSH_LIST all
+ blocks whose oldest_modification is
+ smaller than this should be flushed
+ (if their number does not exceed
+ min_n), otherwise ignored */
+{
+ buf_page_t* bpage;
+ ulint page_count = 0;
+ ulint old_page_count;
+ ulint space;
+ ulint offset;
+
+ ut_ad((flush_type == BUF_FLUSH_LRU)
+ || (flush_type == BUF_FLUSH_LIST));
+#ifdef UNIV_SYNC_DEBUG
+ ut_ad((flush_type != BUF_FLUSH_LIST)
+ || sync_thread_levels_empty_gen(TRUE));
+#endif /* UNIV_SYNC_DEBUG */
+ buf_pool_mutex_enter();
+
+ if ((buf_pool->n_flush[flush_type] > 0)
+ || (buf_pool->init_flush[flush_type] == TRUE)) {
+
+ /* There is already a flush batch of the same type running */
+
+ buf_pool_mutex_exit();
+
+ return(ULINT_UNDEFINED);
+ }
+
+ buf_pool->init_flush[flush_type] = TRUE;
+
+ for (;;) {
+flush_next:
+ /* If we have flushed enough, leave the loop */
+ if (page_count >= min_n) {
+
+ break;
+ }
+
+ /* Start from the end of the list looking for a suitable
+ block to be flushed. */
+
+ if (flush_type == BUF_FLUSH_LRU) {
+ bpage = UT_LIST_GET_LAST(buf_pool->LRU);
+ } else {
+ ut_ad(flush_type == BUF_FLUSH_LIST);
+
+ bpage = UT_LIST_GET_LAST(buf_pool->flush_list);
+ if (!bpage
+ || bpage->oldest_modification >= lsn_limit) {
+ /* We have flushed enough */
+
+ break;
+ }
+ ut_ad(bpage->in_flush_list);
+ }
+
+ /* Note that after finding a single flushable page, we try to
+ flush also all its neighbors, and after that start from the
+ END of the LRU list or flush list again: the list may change
+ during the flushing and we cannot safely preserve within this
+ function a pointer to a block in the list! */
+
+ do {
+ mutex_t*block_mutex = buf_page_get_mutex(bpage);
+ ibool ready;
+
+ ut_a(buf_page_in_file(bpage));
+
+ mutex_enter(block_mutex);
+ ready = buf_flush_ready_for_flush(bpage, flush_type);
+ mutex_exit(block_mutex);
+
+ if (ready) {
+ space = buf_page_get_space(bpage);
+ offset = buf_page_get_page_no(bpage);
+
+ buf_pool_mutex_exit();
+
+ old_page_count = page_count;
+
+ /* Try to flush also all the neighbors */
+ page_count += buf_flush_try_neighbors(
+ space, offset, flush_type);
+ /* fprintf(stderr,
+ "Flush type %lu, page no %lu, neighb %lu\n",
+ flush_type, offset,
+ page_count - old_page_count); */
+
+ buf_pool_mutex_enter();
+ goto flush_next;
+
+ } else if (flush_type == BUF_FLUSH_LRU) {
+ bpage = UT_LIST_GET_PREV(LRU, bpage);
+ } else {
+ ut_ad(flush_type == BUF_FLUSH_LIST);
+
+ bpage = UT_LIST_GET_PREV(list, bpage);
+ ut_ad(!bpage || bpage->in_flush_list);
+ }
+ } while (bpage != NULL);
+
+ /* If we could not find anything to flush, leave the loop */
+
+ break;
+ }
+
+ buf_pool->init_flush[flush_type] = FALSE;
+
+ if (buf_pool->n_flush[flush_type] == 0) {
+
+ /* The running flush batch has ended */
+
+ os_event_set(buf_pool->no_flush[flush_type]);
+ }
+
+ buf_pool_mutex_exit();
+
+ buf_flush_buffered_writes();
+
+#ifdef UNIV_DEBUG
+ if (buf_debug_prints && page_count > 0) {
+ ut_a(flush_type == BUF_FLUSH_LRU
+ || flush_type == BUF_FLUSH_LIST);
+ fprintf(stderr, flush_type == BUF_FLUSH_LRU
+ ? "Flushed %lu pages in LRU flush\n"
+ : "Flushed %lu pages in flush list flush\n",
+ (ulong) page_count);
+ }
+#endif /* UNIV_DEBUG */
+
+ srv_buf_pool_flushed += page_count;
+
+ /* We keep track of all flushes happening as part of LRU
+ flush. When estimating the desired rate at which flush_list
+ should be flushed we factor in this value. */
+ if (flush_type == BUF_FLUSH_LRU) {
+ buf_lru_flush_page_count += page_count;
+ }
+
+ return(page_count);
+}
+
+/******************************************************************//**
+Waits until a flush batch of the given type ends */
+UNIV_INTERN
+void
+buf_flush_wait_batch_end(
+/*=====================*/
+ enum buf_flush type) /*!< in: BUF_FLUSH_LRU or BUF_FLUSH_LIST */
+{
+ ut_ad((type == BUF_FLUSH_LRU) || (type == BUF_FLUSH_LIST));
+
+ os_event_wait(buf_pool->no_flush[type]);
+}
+
+/******************************************************************//**
+Gives a recommendation of how many blocks should be flushed to establish
+a big enough margin of replaceable blocks near the end of the LRU list
+and in the free list.
+@return number of blocks which should be flushed from the end of the
+LRU list */
+static
+ulint
+buf_flush_LRU_recommendation(void)
+/*==============================*/
+{
+ buf_page_t* bpage;
+ ulint n_replaceable;
+ ulint distance = 0;
+
+ buf_pool_mutex_enter();
+
+ n_replaceable = UT_LIST_GET_LEN(buf_pool->free);
+
+ bpage = UT_LIST_GET_LAST(buf_pool->LRU);
+
+ while ((bpage != NULL)
+ && (n_replaceable < BUF_FLUSH_FREE_BLOCK_MARGIN
+ + BUF_FLUSH_EXTRA_MARGIN)
+ && (distance < BUF_LRU_FREE_SEARCH_LEN)) {
+
+ mutex_t* block_mutex = buf_page_get_mutex(bpage);
+
+ mutex_enter(block_mutex);
+
+ if (buf_flush_ready_for_replace(bpage)) {
+ n_replaceable++;
+ }
+
+ mutex_exit(block_mutex);
+
+ distance++;
+
+ bpage = UT_LIST_GET_PREV(LRU, bpage);
+ }
+
+ buf_pool_mutex_exit();
+
+ if (n_replaceable >= BUF_FLUSH_FREE_BLOCK_MARGIN) {
+
+ return(0);
+ }
+
+ return(BUF_FLUSH_FREE_BLOCK_MARGIN + BUF_FLUSH_EXTRA_MARGIN
+ - n_replaceable);
+}
+
+/*********************************************************************//**
+Flushes pages from the end of the LRU list if there is too small a margin
+of replaceable pages there or in the free list. VERY IMPORTANT: this function
+is called also by threads which have locks on pages. To avoid deadlocks, we
+flush only pages such that the s-lock required for flushing can be acquired
+immediately, without waiting. */
+UNIV_INTERN
+void
+buf_flush_free_margin(void)
+/*=======================*/
+{
+ ulint n_to_flush;
+ ulint n_flushed;
+
+ n_to_flush = buf_flush_LRU_recommendation();
+
+ if (n_to_flush > 0) {
+ n_flushed = buf_flush_batch(BUF_FLUSH_LRU, n_to_flush, 0);
+ if (n_flushed == ULINT_UNDEFINED) {
+ /* There was an LRU type flush batch already running;
+ let us wait for it to end */
+
+ buf_flush_wait_batch_end(BUF_FLUSH_LRU);
+ }
+ }
+}
+
+/*********************************************************************
+Update the historical stats that we are collecting for flush rate
+heuristics at the end of each interval.
+Flush rate heuristic depends on (a) rate of redo log generation and
+(b) the rate at which LRU flush is happening. */
+UNIV_INTERN
+void
+buf_flush_stat_update(void)
+/*=======================*/
+{
+ buf_flush_stat_t* item;
+ ib_uint64_t lsn_diff;
+ ib_uint64_t lsn;
+ ulint n_flushed;
+
+ lsn = log_get_lsn();
+ if (buf_flush_stat_cur.redo == 0) {
+ /* First time around. Just update the current LSN
+ and return. */
+ buf_flush_stat_cur.redo = lsn;
+ return;
+ }
+
+ item = &buf_flush_stat_arr[buf_flush_stat_arr_ind];
+
+ /* values for this interval */
+ lsn_diff = lsn - buf_flush_stat_cur.redo;
+ n_flushed = buf_lru_flush_page_count
+ - buf_flush_stat_cur.n_flushed;
+
+ /* add the current value and subtract the obsolete entry. */
+ buf_flush_stat_sum.redo += lsn_diff - item->redo;
+ buf_flush_stat_sum.n_flushed += n_flushed - item->n_flushed;
+
+ /* put current entry in the array. */
+ item->redo = lsn_diff;
+ item->n_flushed = n_flushed;
+
+ /* update the index */
+ buf_flush_stat_arr_ind++;
+ buf_flush_stat_arr_ind %= BUF_FLUSH_STAT_N_INTERVAL;
+
+ /* reset the current entry. */
+ buf_flush_stat_cur.redo = lsn;
+ buf_flush_stat_cur.n_flushed = buf_lru_flush_page_count;
+}
+
+/*********************************************************************
+Determines the fraction of dirty pages that need to be flushed based
+on the speed at which we generate redo log. Note that if redo log
+is generated at a significant rate without corresponding increase
+in the number of dirty pages (for example, an in-memory workload)
+it can cause IO bursts of flushing. This function implements heuristics
+to avoid this burstiness.
+@return number of dirty pages to be flushed / second */
+UNIV_INTERN
+ulint
+buf_flush_get_desired_flush_rate(void)
+/*==================================*/
+{
+ ulint redo_avg;
+ ulint lru_flush_avg;
+ ulint n_dirty;
+ ulint n_flush_req;
+ lint rate;
+ ib_uint64_t lsn = log_get_lsn();
+ ulint log_capacity = log_get_capacity();
+
+ /* log_capacity should never be zero after the initialization
+ of log subsystem. */
+ ut_ad(log_capacity != 0);
+
+ /* Get total number of dirty pages. It is OK to access
+ flush_list without holding any mtex as we are using this
+ only for heuristics. */
+ n_dirty = UT_LIST_GET_LEN(buf_pool->flush_list);
+
+ /* An overflow can happen if we generate more than 2^32 bytes
+ of redo in this interval i.e.: 4G of redo in 1 second. We can
+ safely consider this as infinity because if we ever come close
+ to 4G we'll start a synchronous flush of dirty pages. */
+ /* redo_avg below is average at which redo is generated in
+ past BUF_FLUSH_STAT_N_INTERVAL + redo generated in the current
+ interval. */
+ redo_avg = (ulint) (buf_flush_stat_sum.redo
+ / BUF_FLUSH_STAT_N_INTERVAL
+ + (lsn - buf_flush_stat_cur.redo));
+
+ /* An overflow can happen possibly if we flush more than 2^32
+ pages in BUF_FLUSH_STAT_N_INTERVAL. This is a very very
+ unlikely scenario. Even when this happens it means that our
+ flush rate will be off the mark. It won't affect correctness
+ of any subsystem. */
+ /* lru_flush_avg below is rate at which pages are flushed as
+ part of LRU flush in past BUF_FLUSH_STAT_N_INTERVAL + the
+ number of pages flushed in the current interval. */
+ lru_flush_avg = buf_flush_stat_sum.n_flushed
+ / BUF_FLUSH_STAT_N_INTERVAL
+ + (buf_lru_flush_page_count
+ - buf_flush_stat_cur.n_flushed);
+
+ n_flush_req = (n_dirty * redo_avg) / log_capacity;
+
+ /* The number of pages that we want to flush from the flush
+ list is the difference between the required rate and the
+ number of pages that we are historically flushing from the
+ LRU list */
+ rate = n_flush_req - lru_flush_avg;
+ return(rate > 0 ? (ulint) rate : 0);
+}
+
+#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
+/******************************************************************//**
+Validates the flush list.
+@return TRUE if ok */
+static
+ibool
+buf_flush_validate_low(void)
+/*========================*/
+{
+ buf_page_t* bpage;
+
+ UT_LIST_VALIDATE(list, buf_page_t, buf_pool->flush_list,
+ ut_ad(ut_list_node_313->in_flush_list));
+
+ bpage = UT_LIST_GET_FIRST(buf_pool->flush_list);
+
+ while (bpage != NULL) {
+ const ib_uint64_t om = bpage->oldest_modification;
+ ut_ad(bpage->in_flush_list);
+ ut_a(buf_page_in_file(bpage));
+ ut_a(om > 0);
+
+ bpage = UT_LIST_GET_NEXT(list, bpage);
+
+ ut_a(!bpage || om >= bpage->oldest_modification);
+ }
+
+ return(TRUE);
+}
+
+/******************************************************************//**
+Validates the flush list.
+@return TRUE if ok */
+UNIV_INTERN
+ibool
+buf_flush_validate(void)
+/*====================*/
+{
+ ibool ret;
+
+ buf_pool_mutex_enter();
+
+ ret = buf_flush_validate_low();
+
+ buf_pool_mutex_exit();
+
+ return(ret);
+}
+#endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
+#endif /* !UNIV_HOTBACKUP */
diff --git a/storage/innodb_plugin/buf/buf0lru.c b/storage/innodb_plugin/buf/buf0lru.c
new file mode 100644
index 00000000000..be53a5f5d9d
--- /dev/null
+++ b/storage/innodb_plugin/buf/buf0lru.c
@@ -0,0 +1,2066 @@
+/*****************************************************************************
+
+Copyright (c) 1995, 2009, Innobase Oy. All Rights Reserved.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; version 2 of the License.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place, Suite 330, Boston, MA 02111-1307 USA
+
+*****************************************************************************/
+
+/**************************************************//**
+@file buf/buf0lru.c
+The database buffer replacement algorithm
+
+Created 11/5/1995 Heikki Tuuri
+*******************************************************/
+
+#include "buf0lru.h"
+
+#ifdef UNIV_NONINL
+#include "buf0lru.ic"
+#endif
+
+#include "ut0byte.h"
+#include "ut0lst.h"
+#include "ut0rnd.h"
+#include "sync0sync.h"
+#include "sync0rw.h"
+#include "hash0hash.h"
+#include "os0sync.h"
+#include "fil0fil.h"
+#include "btr0btr.h"
+#include "buf0buddy.h"
+#include "buf0buf.h"
+#include "buf0flu.h"
+#include "buf0rea.h"
+#include "btr0sea.h"
+#include "ibuf0ibuf.h"
+#include "os0file.h"
+#include "page0zip.h"
+#include "log0recv.h"
+#include "srv0srv.h"
+
+/** The number of blocks from the LRU_old pointer onward, including the block
+pointed to, must be 3/8 of the whole LRU list length, except that the
+tolerance defined below is allowed. Note that the tolerance must be small
+enough such that for even the BUF_LRU_OLD_MIN_LEN long LRU list, the
+LRU_old pointer is not allowed to point to either end of the LRU list. */
+
+#define BUF_LRU_OLD_TOLERANCE 20
+
+/** The whole LRU list length is divided by this number to determine an
+initial segment in buf_LRU_get_recent_limit */
+
+#define BUF_LRU_INITIAL_RATIO 8
+
+/** When dropping the search hash index entries before deleting an ibd
+file, we build a local array of pages belonging to that tablespace
+in the buffer pool. Following is the size of that array. */
+#define BUF_LRU_DROP_SEARCH_HASH_SIZE 1024
+
+/** If we switch on the InnoDB monitor because there are too few available
+frames in the buffer pool, we set this to TRUE */
+static ibool buf_lru_switched_on_innodb_mon = FALSE;
+
+/******************************************************************//**
+These statistics are not 'of' LRU but 'for' LRU. We keep count of I/O
+and page_zip_decompress() operations. Based on the statistics,
+buf_LRU_evict_from_unzip_LRU() decides if we want to evict from
+unzip_LRU or the regular LRU. From unzip_LRU, we will only evict the
+uncompressed frame (meaning we can evict dirty blocks as well). From
+the regular LRU, we will evict the entire block (i.e.: both the
+uncompressed and compressed data), which must be clean. */
+
+/* @{ */
+
+/** Number of intervals for which we keep the history of these stats.
+Each interval is 1 second, defined by the rate at which
+srv_error_monitor_thread() calls buf_LRU_stat_update(). */
+#define BUF_LRU_STAT_N_INTERVAL 50
+
+/** Co-efficient with which we multiply I/O operations to equate them
+with page_zip_decompress() operations. */
+#define BUF_LRU_IO_TO_UNZIP_FACTOR 50
+
+/** Sampled values buf_LRU_stat_cur.
+Protected by buf_pool_mutex. Updated by buf_LRU_stat_update(). */
+static buf_LRU_stat_t buf_LRU_stat_arr[BUF_LRU_STAT_N_INTERVAL];
+/** Cursor to buf_LRU_stat_arr[] that is updated in a round-robin fashion. */
+static ulint buf_LRU_stat_arr_ind;
+
+/** Current operation counters. Not protected by any mutex. Cleared
+by buf_LRU_stat_update(). */
+UNIV_INTERN buf_LRU_stat_t buf_LRU_stat_cur;
+
+/** Running sum of past values of buf_LRU_stat_cur.
+Updated by buf_LRU_stat_update(). Protected by buf_pool_mutex. */
+UNIV_INTERN buf_LRU_stat_t buf_LRU_stat_sum;
+
+/* @} */
+
+/******************************************************************//**
+Takes a block out of the LRU list and page hash table.
+If the block is compressed-only (BUF_BLOCK_ZIP_PAGE),
+the object will be freed and buf_pool_zip_mutex will be released.
+
+If a compressed page or a compressed-only block descriptor is freed,
+other compressed pages or compressed-only block descriptors may be
+relocated.
+@return the new state of the block (BUF_BLOCK_ZIP_FREE if the state
+was BUF_BLOCK_ZIP_PAGE, or BUF_BLOCK_REMOVE_HASH otherwise) */
+static
+enum buf_page_state
+buf_LRU_block_remove_hashed_page(
+/*=============================*/
+ buf_page_t* bpage, /*!< in: block, must contain a file page and
+ be in a state where it can be freed; there
+ may or may not be a hash index to the page */
+ ibool zip); /*!< in: TRUE if should remove also the
+ compressed page of an uncompressed page */
+/******************************************************************//**
+Puts a file page whose has no hash index to the free list. */
+static
+void
+buf_LRU_block_free_hashed_page(
+/*===========================*/
+ buf_block_t* block); /*!< in: block, must contain a file page and
+ be in a state where it can be freed */
+
+/******************************************************************//**
+Determines if the unzip_LRU list should be used for evicting a victim
+instead of the general LRU list.
+@return TRUE if should use unzip_LRU */
+UNIV_INLINE
+ibool
+buf_LRU_evict_from_unzip_LRU(void)
+/*==============================*/
+{
+ ulint io_avg;
+ ulint unzip_avg;
+
+ ut_ad(buf_pool_mutex_own());
+
+ /* If the unzip_LRU list is empty, we can only use the LRU. */
+ if (UT_LIST_GET_LEN(buf_pool->unzip_LRU) == 0) {
+ return(FALSE);
+ }
+
+ /* If unzip_LRU is at most 10% of the size of the LRU list,
+ then use the LRU. This slack allows us to keep hot
+ decompressed pages in the buffer pool. */
+ if (UT_LIST_GET_LEN(buf_pool->unzip_LRU)
+ <= UT_LIST_GET_LEN(buf_pool->LRU) / 10) {
+ return(FALSE);
+ }
+
+ /* If eviction hasn't started yet, we assume by default
+ that a workload is disk bound. */
+ if (buf_pool->freed_page_clock == 0) {
+ return(TRUE);
+ }
+
+ /* Calculate the average over past intervals, and add the values
+ of the current interval. */
+ io_avg = buf_LRU_stat_sum.io / BUF_LRU_STAT_N_INTERVAL
+ + buf_LRU_stat_cur.io;
+ unzip_avg = buf_LRU_stat_sum.unzip / BUF_LRU_STAT_N_INTERVAL
+ + buf_LRU_stat_cur.unzip;
+
+ /* Decide based on our formula. If the load is I/O bound
+ (unzip_avg is smaller than the weighted io_avg), evict an
+ uncompressed frame from unzip_LRU. Otherwise we assume that
+ the load is CPU bound and evict from the regular LRU. */
+ return(unzip_avg <= io_avg * BUF_LRU_IO_TO_UNZIP_FACTOR);
+}
+
+/******************************************************************//**
+Attempts to drop page hash index on a batch of pages belonging to a
+particular space id. */
+static
+void
+buf_LRU_drop_page_hash_batch(
+/*=========================*/
+ ulint space_id, /*!< in: space id */
+ ulint zip_size, /*!< in: compressed page size in bytes
+ or 0 for uncompressed pages */
+ const ulint* arr, /*!< in: array of page_no */
+ ulint count) /*!< in: number of entries in array */
+{
+ ulint i;
+
+ ut_ad(arr != NULL);
+ ut_ad(count <= BUF_LRU_DROP_SEARCH_HASH_SIZE);
+
+ for (i = 0; i < count; ++i) {
+ btr_search_drop_page_hash_when_freed(space_id, zip_size,
+ arr[i]);
+ }
+}
+
+/******************************************************************//**
+When doing a DROP TABLE/DISCARD TABLESPACE we have to drop all page
+hash index entries belonging to that table. This function tries to
+do that in batch. Note that this is a 'best effort' attempt and does
+not guarantee that ALL hash entries will be removed. */
+static
+void
+buf_LRU_drop_page_hash_for_tablespace(
+/*==================================*/
+ ulint id) /*!< in: space id */
+{
+ buf_page_t* bpage;
+ ulint* page_arr;
+ ulint num_entries;
+ ulint zip_size;
+
+ zip_size = fil_space_get_zip_size(id);
+
+ if (UNIV_UNLIKELY(zip_size == ULINT_UNDEFINED)) {
+ /* Somehow, the tablespace does not exist. Nothing to drop. */
+ ut_ad(0);
+ return;
+ }
+
+ page_arr = ut_malloc(sizeof(ulint)
+ * BUF_LRU_DROP_SEARCH_HASH_SIZE);
+ buf_pool_mutex_enter();
+
+scan_again:
+ num_entries = 0;
+ bpage = UT_LIST_GET_LAST(buf_pool->LRU);
+
+ while (bpage != NULL) {
+ mutex_t* block_mutex = buf_page_get_mutex(bpage);
+ buf_page_t* prev_bpage;
+
+ mutex_enter(block_mutex);
+ prev_bpage = UT_LIST_GET_PREV(LRU, bpage);
+
+ ut_a(buf_page_in_file(bpage));
+
+ if (buf_page_get_state(bpage) != BUF_BLOCK_FILE_PAGE
+ || bpage->space != id
+ || bpage->buf_fix_count > 0
+ || bpage->io_fix != BUF_IO_NONE) {
+ /* We leave the fixed pages as is in this scan.
+ To be dealt with later in the final scan. */
+ mutex_exit(block_mutex);
+ goto next_page;
+ }
+
+ if (((buf_block_t*) bpage)->is_hashed) {
+
+ /* Store the offset(i.e.: page_no) in the array
+ so that we can drop hash index in a batch
+ later. */
+ page_arr[num_entries] = bpage->offset;
+ mutex_exit(block_mutex);
+ ut_a(num_entries < BUF_LRU_DROP_SEARCH_HASH_SIZE);
+ ++num_entries;
+
+ if (num_entries < BUF_LRU_DROP_SEARCH_HASH_SIZE) {
+ goto next_page;
+ }
+ /* Array full. We release the buf_pool_mutex to
+ obey the latching order. */
+ buf_pool_mutex_exit();
+
+ buf_LRU_drop_page_hash_batch(id, zip_size, page_arr,
+ num_entries);
+ num_entries = 0;
+ buf_pool_mutex_enter();
+ } else {
+ mutex_exit(block_mutex);
+ }
+
+next_page:
+ /* Note that we may have released the buf_pool mutex
+ above after reading the prev_bpage during processing
+ of a page_hash_batch (i.e.: when the array was full).
+ This means that prev_bpage can change in LRU list.
+ This is OK because this function is a 'best effort'
+ to drop as many search hash entries as possible and
+ it does not guarantee that ALL such entries will be
+ dropped. */
+ bpage = prev_bpage;
+
+ /* If, however, bpage has been removed from LRU list
+ to the free list then we should restart the scan.
+ bpage->state is protected by buf_pool mutex. */
+ if (bpage && !buf_page_in_file(bpage)) {
+ ut_a(num_entries == 0);
+ goto scan_again;
+ }
+ }
+
+ buf_pool_mutex_exit();
+
+ /* Drop any remaining batch of search hashed pages. */
+ buf_LRU_drop_page_hash_batch(id, zip_size, page_arr, num_entries);
+ ut_free(page_arr);
+}
+
+/******************************************************************//**
+Invalidates all pages belonging to a given tablespace when we are deleting
+the data file(s) of that tablespace. */
+UNIV_INTERN
+void
+buf_LRU_invalidate_tablespace(
+/*==========================*/
+ ulint id) /*!< in: space id */
+{
+ buf_page_t* bpage;
+ ibool all_freed;
+
+ /* Before we attempt to drop pages one by one we first
+ attempt to drop page hash index entries in batches to make
+ it more efficient. The batching attempt is a best effort
+ attempt and does not guarantee that all pages hash entries
+ will be dropped. We get rid of remaining page hash entries
+ one by one below. */
+ buf_LRU_drop_page_hash_for_tablespace(id);
+
+scan_again:
+ buf_pool_mutex_enter();
+
+ all_freed = TRUE;
+
+ bpage = UT_LIST_GET_LAST(buf_pool->LRU);
+
+ while (bpage != NULL) {
+ mutex_t* block_mutex = buf_page_get_mutex(bpage);
+ buf_page_t* prev_bpage;
+
+ ut_a(buf_page_in_file(bpage));
+
+ mutex_enter(block_mutex);
+ prev_bpage = UT_LIST_GET_PREV(LRU, bpage);
+
+ if (buf_page_get_space(bpage) == id) {
+ if (bpage->buf_fix_count > 0
+ || buf_page_get_io_fix(bpage) != BUF_IO_NONE) {
+
+ /* We cannot remove this page during
+ this scan yet; maybe the system is
+ currently reading it in, or flushing
+ the modifications to the file */
+
+ all_freed = FALSE;
+
+ goto next_page;
+ }
+
+#ifdef UNIV_DEBUG
+ if (buf_debug_prints) {
+ fprintf(stderr,
+ "Dropping space %lu page %lu\n",
+ (ulong) buf_page_get_space(bpage),
+ (ulong) buf_page_get_page_no(bpage));
+ }
+#endif
+ if (buf_page_get_state(bpage) == BUF_BLOCK_FILE_PAGE
+ && ((buf_block_t*) bpage)->is_hashed) {
+ ulint page_no;
+ ulint zip_size;
+
+ buf_pool_mutex_exit();
+
+ zip_size = buf_page_get_zip_size(bpage);
+ page_no = buf_page_get_page_no(bpage);
+
+ mutex_exit(block_mutex);
+
+ /* Note that the following call will acquire
+ an S-latch on the page */
+
+ btr_search_drop_page_hash_when_freed(
+ id, zip_size, page_no);
+ goto scan_again;
+ }
+
+ if (bpage->oldest_modification != 0) {
+
+ buf_flush_remove(bpage);
+ }
+
+ /* Remove from the LRU list */
+ if (buf_LRU_block_remove_hashed_page(bpage, TRUE)
+ != BUF_BLOCK_ZIP_FREE) {
+ buf_LRU_block_free_hashed_page((buf_block_t*)
+ bpage);
+ } else {
+ /* The block_mutex should have been
+ released by buf_LRU_block_remove_hashed_page()
+ when it returns BUF_BLOCK_ZIP_FREE. */
+ ut_ad(block_mutex == &buf_pool_zip_mutex);
+ ut_ad(!mutex_own(block_mutex));
+
+ /* The compressed block descriptor
+ (bpage) has been deallocated and
+ block_mutex released. Also,
+ buf_buddy_free() may have relocated
+ prev_bpage. Rescan the LRU list. */
+
+ bpage = UT_LIST_GET_LAST(buf_pool->LRU);
+ continue;
+ }
+ }
+next_page:
+ mutex_exit(block_mutex);
+ bpage = prev_bpage;
+ }
+
+ buf_pool_mutex_exit();
+
+ if (!all_freed) {
+ os_thread_sleep(20000);
+
+ goto scan_again;
+ }
+}
+
+/******************************************************************//**
+Gets the minimum LRU_position field for the blocks in an initial segment
+(determined by BUF_LRU_INITIAL_RATIO) of the LRU list. The limit is not
+guaranteed to be precise, because the ulint_clock may wrap around.
+@return the limit; zero if could not determine it */
+UNIV_INTERN
+ulint
+buf_LRU_get_recent_limit(void)
+/*==========================*/
+{
+ const buf_page_t* bpage;
+ ulint len;
+ ulint limit;
+
+ buf_pool_mutex_enter();
+
+ len = UT_LIST_GET_LEN(buf_pool->LRU);
+
+ if (len < BUF_LRU_OLD_MIN_LEN) {
+ /* The LRU list is too short to do read-ahead */
+
+ buf_pool_mutex_exit();
+
+ return(0);
+ }
+
+ bpage = UT_LIST_GET_FIRST(buf_pool->LRU);
+
+ limit = buf_page_get_LRU_position(bpage);
+ len /= BUF_LRU_INITIAL_RATIO;
+
+ buf_pool_mutex_exit();
+
+ return(limit > len ? (limit - len) : 0);
+}
+
+/********************************************************************//**
+Insert a compressed block into buf_pool->zip_clean in the LRU order. */
+UNIV_INTERN
+void
+buf_LRU_insert_zip_clean(
+/*=====================*/
+ buf_page_t* bpage) /*!< in: pointer to the block in question */
+{
+ buf_page_t* b;
+
+ ut_ad(buf_pool_mutex_own());
+ ut_ad(buf_page_get_state(bpage) == BUF_BLOCK_ZIP_PAGE);
+
+ /* Find the first successor of bpage in the LRU list
+ that is in the zip_clean list. */
+ b = bpage;
+ do {
+ b = UT_LIST_GET_NEXT(LRU, b);
+ } while (b && buf_page_get_state(b) != BUF_BLOCK_ZIP_PAGE);
+
+ /* Insert bpage before b, i.e., after the predecessor of b. */
+ if (b) {
+ b = UT_LIST_GET_PREV(list, b);
+ }
+
+ if (b) {
+ UT_LIST_INSERT_AFTER(list, buf_pool->zip_clean, b, bpage);
+ } else {
+ UT_LIST_ADD_FIRST(list, buf_pool->zip_clean, bpage);
+ }
+}
+
+/******************************************************************//**
+Try to free an uncompressed page of a compressed block from the unzip
+LRU list. The compressed page is preserved, and it need not be clean.
+@return TRUE if freed */
+UNIV_INLINE
+ibool
+buf_LRU_free_from_unzip_LRU_list(
+/*=============================*/
+ ulint n_iterations) /*!< in: how many times this has been called
+ repeatedly without result: a high value means
+ that we should search farther; we will search
+ n_iterations / 5 of the unzip_LRU list,
+ or nothing if n_iterations >= 5 */
+{
+ buf_block_t* block;
+ ulint distance;
+
+ ut_ad(buf_pool_mutex_own());
+
+ /* Theoratically it should be much easier to find a victim
+ from unzip_LRU as we can choose even a dirty block (as we'll
+ be evicting only the uncompressed frame). In a very unlikely
+ eventuality that we are unable to find a victim from
+ unzip_LRU, we fall back to the regular LRU list. We do this
+ if we have done five iterations so far. */
+
+ if (UNIV_UNLIKELY(n_iterations >= 5)
+ || !buf_LRU_evict_from_unzip_LRU()) {
+
+ return(FALSE);
+ }
+
+ distance = 100 + (n_iterations
+ * UT_LIST_GET_LEN(buf_pool->unzip_LRU)) / 5;
+
+ for (block = UT_LIST_GET_LAST(buf_pool->unzip_LRU);
+ UNIV_LIKELY(block != NULL) && UNIV_LIKELY(distance > 0);
+ block = UT_LIST_GET_PREV(unzip_LRU, block), distance--) {
+
+ enum buf_lru_free_block_status freed;
+
+ ut_ad(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE);
+ ut_ad(block->in_unzip_LRU_list);
+ ut_ad(block->page.in_LRU_list);
+
+ mutex_enter(&block->mutex);
+ freed = buf_LRU_free_block(&block->page, FALSE, NULL);
+ mutex_exit(&block->mutex);
+
+ switch (freed) {
+ case BUF_LRU_FREED:
+ return(TRUE);
+
+ case BUF_LRU_CANNOT_RELOCATE:
+ /* If we failed to relocate, try
+ regular LRU eviction. */
+ return(FALSE);
+
+ case BUF_LRU_NOT_FREED:
+ /* The block was buffer-fixed or I/O-fixed.
+ Keep looking. */
+ continue;
+ }
+
+ /* inappropriate return value from
+ buf_LRU_free_block() */
+ ut_error;
+ }
+
+ return(FALSE);
+}
+
+/******************************************************************//**
+Try to free a clean page from the common LRU list.
+@return TRUE if freed */
+UNIV_INLINE
+ibool
+buf_LRU_free_from_common_LRU_list(
+/*==============================*/
+ ulint n_iterations) /*!< in: how many times this has been called
+ repeatedly without result: a high value means
+ that we should search farther; if
+ n_iterations < 10, then we search
+ n_iterations / 10 * buf_pool->curr_size
+ pages from the end of the LRU list */
+{
+ buf_page_t* bpage;
+ ulint distance;
+
+ ut_ad(buf_pool_mutex_own());
+
+ distance = 100 + (n_iterations * buf_pool->curr_size) / 10;
+
+ for (bpage = UT_LIST_GET_LAST(buf_pool->LRU);
+ UNIV_LIKELY(bpage != NULL) && UNIV_LIKELY(distance > 0);
+ bpage = UT_LIST_GET_PREV(LRU, bpage), distance--) {
+
+ enum buf_lru_free_block_status freed;
+ mutex_t* block_mutex
+ = buf_page_get_mutex(bpage);
+
+ ut_ad(buf_page_in_file(bpage));
+ ut_ad(bpage->in_LRU_list);
+
+ mutex_enter(block_mutex);
+ freed = buf_LRU_free_block(bpage, TRUE, NULL);
+ mutex_exit(block_mutex);
+
+ switch (freed) {
+ case BUF_LRU_FREED:
+ return(TRUE);
+
+ case BUF_LRU_NOT_FREED:
+ /* The block was dirty, buffer-fixed, or I/O-fixed.
+ Keep looking. */
+ continue;
+
+ case BUF_LRU_CANNOT_RELOCATE:
+ /* This should never occur, because we
+ want to discard the compressed page too. */
+ break;
+ }
+
+ /* inappropriate return value from
+ buf_LRU_free_block() */
+ ut_error;
+ }
+
+ return(FALSE);
+}
+
+/******************************************************************//**
+Try to free a replaceable block.
+@return TRUE if found and freed */
+UNIV_INTERN
+ibool
+buf_LRU_search_and_free_block(
+/*==========================*/
+ ulint n_iterations) /*!< in: how many times this has been called
+ repeatedly without result: a high value means
+ that we should search farther; if
+ n_iterations < 10, then we search
+ n_iterations / 10 * buf_pool->curr_size
+ pages from the end of the LRU list; if
+ n_iterations < 5, then we will also search
+ n_iterations / 5 of the unzip_LRU list. */
+{
+ ibool freed = FALSE;
+
+ buf_pool_mutex_enter();
+
+ freed = buf_LRU_free_from_unzip_LRU_list(n_iterations);
+
+ if (!freed) {
+ freed = buf_LRU_free_from_common_LRU_list(n_iterations);
+ }
+
+ if (!freed) {
+ buf_pool->LRU_flush_ended = 0;
+ } else if (buf_pool->LRU_flush_ended > 0) {
+ buf_pool->LRU_flush_ended--;
+ }
+
+ buf_pool_mutex_exit();
+
+ return(freed);
+}
+
+/******************************************************************//**
+Tries to remove LRU flushed blocks from the end of the LRU list and put them
+to the free list. This is beneficial for the efficiency of the insert buffer
+operation, as flushed pages from non-unique non-clustered indexes are here
+taken out of the buffer pool, and their inserts redirected to the insert
+buffer. Otherwise, the flushed blocks could get modified again before read
+operations need new buffer blocks, and the i/o work done in flushing would be
+wasted. */
+UNIV_INTERN
+void
+buf_LRU_try_free_flushed_blocks(void)
+/*=================================*/
+{
+ buf_pool_mutex_enter();
+
+ while (buf_pool->LRU_flush_ended > 0) {
+
+ buf_pool_mutex_exit();
+
+ buf_LRU_search_and_free_block(1);
+
+ buf_pool_mutex_enter();
+ }
+
+ buf_pool_mutex_exit();
+}
+
+/******************************************************************//**
+Returns TRUE if less than 25 % of the buffer pool is available. This can be
+used in heuristics to prevent huge transactions eating up the whole buffer
+pool for their locks.
+@return TRUE if less than 25 % of buffer pool left */
+UNIV_INTERN
+ibool
+buf_LRU_buf_pool_running_out(void)
+/*==============================*/
+{
+ ibool ret = FALSE;
+
+ buf_pool_mutex_enter();
+
+ if (!recv_recovery_on && UT_LIST_GET_LEN(buf_pool->free)
+ + UT_LIST_GET_LEN(buf_pool->LRU) < buf_pool->curr_size / 4) {
+
+ ret = TRUE;
+ }
+
+ buf_pool_mutex_exit();
+
+ return(ret);
+}
+
+/******************************************************************//**
+Returns a free block from the buf_pool. The block is taken off the
+free list. If it is empty, returns NULL.
+@return a free control block, or NULL if the buf_block->free list is empty */
+UNIV_INTERN
+buf_block_t*
+buf_LRU_get_free_only(void)
+/*=======================*/
+{
+ buf_block_t* block;
+
+ ut_ad(buf_pool_mutex_own());
+
+ block = (buf_block_t*) UT_LIST_GET_FIRST(buf_pool->free);
+
+ if (block) {
+ ut_ad(block->page.in_free_list);
+ ut_d(block->page.in_free_list = FALSE);
+ ut_ad(!block->page.in_flush_list);
+ ut_ad(!block->page.in_LRU_list);
+ ut_a(!buf_page_in_file(&block->page));
+ UT_LIST_REMOVE(list, buf_pool->free, (&block->page));
+
+ mutex_enter(&block->mutex);
+
+ buf_block_set_state(block, BUF_BLOCK_READY_FOR_USE);
+ UNIV_MEM_ALLOC(block->frame, UNIV_PAGE_SIZE);
+
+ mutex_exit(&block->mutex);
+ }
+
+ return(block);
+}
+
+/******************************************************************//**
+Returns a free block from the buf_pool. The block is taken off the
+free list. If it is empty, blocks are moved from the end of the
+LRU list to the free list.
+@return the free control block, in state BUF_BLOCK_READY_FOR_USE */
+UNIV_INTERN
+buf_block_t*
+buf_LRU_get_free_block(
+/*===================*/
+ ulint zip_size) /*!< in: compressed page size in bytes,
+ or 0 if uncompressed tablespace */
+{
+ buf_block_t* block = NULL;
+ ibool freed;
+ ulint n_iterations = 1;
+ ibool mon_value_was = FALSE;
+ ibool started_monitor = FALSE;
+loop:
+ buf_pool_mutex_enter();
+
+ if (!recv_recovery_on && UT_LIST_GET_LEN(buf_pool->free)
+ + UT_LIST_GET_LEN(buf_pool->LRU) < buf_pool->curr_size / 20) {
+ ut_print_timestamp(stderr);
+
+ fprintf(stderr,
+ " InnoDB: ERROR: over 95 percent of the buffer pool"
+ " is occupied by\n"
+ "InnoDB: lock heaps or the adaptive hash index!"
+ " Check that your\n"
+ "InnoDB: transactions do not set too many row locks.\n"
+ "InnoDB: Your buffer pool size is %lu MB."
+ " Maybe you should make\n"
+ "InnoDB: the buffer pool bigger?\n"
+ "InnoDB: We intentionally generate a seg fault"
+ " to print a stack trace\n"
+ "InnoDB: on Linux!\n",
+ (ulong) (buf_pool->curr_size
+ / (1024 * 1024 / UNIV_PAGE_SIZE)));
+
+ ut_error;
+
+ } else if (!recv_recovery_on
+ && (UT_LIST_GET_LEN(buf_pool->free)
+ + UT_LIST_GET_LEN(buf_pool->LRU))
+ < buf_pool->curr_size / 3) {
+
+ if (!buf_lru_switched_on_innodb_mon) {
+
+ /* Over 67 % of the buffer pool is occupied by lock
+ heaps or the adaptive hash index. This may be a memory
+ leak! */
+
+ ut_print_timestamp(stderr);
+ fprintf(stderr,
+ " InnoDB: WARNING: over 67 percent of"
+ " the buffer pool is occupied by\n"
+ "InnoDB: lock heaps or the adaptive"
+ " hash index! Check that your\n"
+ "InnoDB: transactions do not set too many"
+ " row locks.\n"
+ "InnoDB: Your buffer pool size is %lu MB."
+ " Maybe you should make\n"
+ "InnoDB: the buffer pool bigger?\n"
+ "InnoDB: Starting the InnoDB Monitor to print"
+ " diagnostics, including\n"
+ "InnoDB: lock heap and hash index sizes.\n",
+ (ulong) (buf_pool->curr_size
+ / (1024 * 1024 / UNIV_PAGE_SIZE)));
+
+ buf_lru_switched_on_innodb_mon = TRUE;
+ srv_print_innodb_monitor = TRUE;
+ os_event_set(srv_lock_timeout_thread_event);
+ }
+ } else if (buf_lru_switched_on_innodb_mon) {
+
+ /* Switch off the InnoDB Monitor; this is a simple way
+ to stop the monitor if the situation becomes less urgent,
+ but may also surprise users if the user also switched on the
+ monitor! */
+
+ buf_lru_switched_on_innodb_mon = FALSE;
+ srv_print_innodb_monitor = FALSE;
+ }
+
+ /* If there is a block in the free list, take it */
+ block = buf_LRU_get_free_only();
+ if (block) {
+
+#ifdef UNIV_DEBUG
+ block->page.zip.m_start =
+#endif /* UNIV_DEBUG */
+ block->page.zip.m_end =
+ block->page.zip.m_nonempty =
+ block->page.zip.n_blobs = 0;
+
+ if (UNIV_UNLIKELY(zip_size)) {
+ ibool lru;
+ page_zip_set_size(&block->page.zip, zip_size);
+ block->page.zip.data = buf_buddy_alloc(zip_size, &lru);
+ UNIV_MEM_DESC(block->page.zip.data, zip_size, block);
+ } else {
+ page_zip_set_size(&block->page.zip, 0);
+ block->page.zip.data = NULL;
+ }
+
+ buf_pool_mutex_exit();
+
+ if (started_monitor) {
+ srv_print_innodb_monitor = mon_value_was;
+ }
+
+ return(block);
+ }
+
+ /* If no block was in the free list, search from the end of the LRU
+ list and try to free a block there */
+
+ buf_pool_mutex_exit();
+
+ freed = buf_LRU_search_and_free_block(n_iterations);
+
+ if (freed > 0) {
+ goto loop;
+ }
+
+ if (n_iterations > 30) {
+ ut_print_timestamp(stderr);
+ fprintf(stderr,
+ " InnoDB: Warning: difficult to find free blocks in\n"
+ "InnoDB: the buffer pool (%lu search iterations)!"
+ " Consider\n"
+ "InnoDB: increasing the buffer pool size.\n"
+ "InnoDB: It is also possible that"
+ " in your Unix version\n"
+ "InnoDB: fsync is very slow, or"
+ " completely frozen inside\n"
+ "InnoDB: the OS kernel. Then upgrading to"
+ " a newer version\n"
+ "InnoDB: of your operating system may help."
+ " Look at the\n"
+ "InnoDB: number of fsyncs in diagnostic info below.\n"
+ "InnoDB: Pending flushes (fsync) log: %lu;"
+ " buffer pool: %lu\n"
+ "InnoDB: %lu OS file reads, %lu OS file writes,"
+ " %lu OS fsyncs\n"
+ "InnoDB: Starting InnoDB Monitor to print further\n"
+ "InnoDB: diagnostics to the standard output.\n",
+ (ulong) n_iterations,
+ (ulong) fil_n_pending_log_flushes,
+ (ulong) fil_n_pending_tablespace_flushes,
+ (ulong) os_n_file_reads, (ulong) os_n_file_writes,
+ (ulong) os_n_fsyncs);
+
+ mon_value_was = srv_print_innodb_monitor;
+ started_monitor = TRUE;
+ srv_print_innodb_monitor = TRUE;
+ os_event_set(srv_lock_timeout_thread_event);
+ }
+
+ /* No free block was found: try to flush the LRU list */
+
+ buf_flush_free_margin();
+ ++srv_buf_pool_wait_free;
+
+ os_aio_simulated_wake_handler_threads();
+
+ buf_pool_mutex_enter();
+
+ if (buf_pool->LRU_flush_ended > 0) {
+ /* We have written pages in an LRU flush. To make the insert
+ buffer more efficient, we try to move these pages to the free
+ list. */
+
+ buf_pool_mutex_exit();
+
+ buf_LRU_try_free_flushed_blocks();
+ } else {
+ buf_pool_mutex_exit();
+ }
+
+ if (n_iterations > 10) {
+
+ os_thread_sleep(500000);
+ }
+
+ n_iterations++;
+
+ goto loop;
+}
+
+/*******************************************************************//**
+Moves the LRU_old pointer so that the length of the old blocks list
+is inside the allowed limits. */
+UNIV_INLINE
+void
+buf_LRU_old_adjust_len(void)
+/*========================*/
+{
+ ulint old_len;
+ ulint new_len;
+
+ ut_a(buf_pool->LRU_old);
+ ut_ad(buf_pool_mutex_own());
+#if 3 * (BUF_LRU_OLD_MIN_LEN / 8) <= BUF_LRU_OLD_TOLERANCE + 5
+# error "3 * (BUF_LRU_OLD_MIN_LEN / 8) <= BUF_LRU_OLD_TOLERANCE + 5"
+#endif
+#ifdef UNIV_LRU_DEBUG
+ /* buf_pool->LRU_old must be the first item in the LRU list
+ whose "old" flag is set. */
+ ut_a(buf_pool->LRU_old->old);
+ ut_a(!UT_LIST_GET_PREV(LRU, buf_pool->LRU_old)
+ || !UT_LIST_GET_PREV(LRU, buf_pool->LRU_old)->old);
+ ut_a(!UT_LIST_GET_NEXT(LRU, buf_pool->LRU_old)
+ || UT_LIST_GET_NEXT(LRU, buf_pool->LRU_old)->old);
+#endif /* UNIV_LRU_DEBUG */
+
+ for (;;) {
+ old_len = buf_pool->LRU_old_len;
+ new_len = 3 * (UT_LIST_GET_LEN(buf_pool->LRU) / 8);
+
+ ut_ad(buf_pool->LRU_old->in_LRU_list);
+ ut_a(buf_pool->LRU_old);
+#ifdef UNIV_LRU_DEBUG
+ ut_a(buf_pool->LRU_old->old);
+#endif /* UNIV_LRU_DEBUG */
+
+ /* Update the LRU_old pointer if necessary */
+
+ if (old_len < new_len - BUF_LRU_OLD_TOLERANCE) {
+
+ buf_pool->LRU_old = UT_LIST_GET_PREV(
+ LRU, buf_pool->LRU_old);
+#ifdef UNIV_LRU_DEBUG
+ ut_a(!buf_pool->LRU_old->old);
+#endif /* UNIV_LRU_DEBUG */
+ buf_page_set_old(buf_pool->LRU_old, TRUE);
+ buf_pool->LRU_old_len++;
+
+ } else if (old_len > new_len + BUF_LRU_OLD_TOLERANCE) {
+
+ buf_page_set_old(buf_pool->LRU_old, FALSE);
+ buf_pool->LRU_old = UT_LIST_GET_NEXT(
+ LRU, buf_pool->LRU_old);
+ buf_pool->LRU_old_len--;
+ } else {
+ return;
+ }
+ }
+}
+
+/*******************************************************************//**
+Initializes the old blocks pointer in the LRU list. This function should be
+called when the LRU list grows to BUF_LRU_OLD_MIN_LEN length. */
+static
+void
+buf_LRU_old_init(void)
+/*==================*/
+{
+ buf_page_t* bpage;
+
+ ut_ad(buf_pool_mutex_own());
+ ut_a(UT_LIST_GET_LEN(buf_pool->LRU) == BUF_LRU_OLD_MIN_LEN);
+
+ /* We first initialize all blocks in the LRU list as old and then use
+ the adjust function to move the LRU_old pointer to the right
+ position */
+
+ bpage = UT_LIST_GET_FIRST(buf_pool->LRU);
+
+ while (bpage != NULL) {
+ ut_ad(bpage->in_LRU_list);
+ buf_page_set_old(bpage, TRUE);
+ bpage = UT_LIST_GET_NEXT(LRU, bpage);
+ }
+
+ buf_pool->LRU_old = UT_LIST_GET_FIRST(buf_pool->LRU);
+ buf_pool->LRU_old_len = UT_LIST_GET_LEN(buf_pool->LRU);
+
+ buf_LRU_old_adjust_len();
+}
+
+/******************************************************************//**
+Remove a block from the unzip_LRU list if it belonged to the list. */
+static
+void
+buf_unzip_LRU_remove_block_if_needed(
+/*=================================*/
+ buf_page_t* bpage) /*!< in/out: control block */
+{
+ ut_ad(buf_pool);
+ ut_ad(bpage);
+ ut_ad(buf_page_in_file(bpage));
+ ut_ad(buf_pool_mutex_own());
+
+ if (buf_page_belongs_to_unzip_LRU(bpage)) {
+ buf_block_t* block = (buf_block_t*) bpage;
+
+ ut_ad(block->in_unzip_LRU_list);
+ ut_d(block->in_unzip_LRU_list = FALSE);
+
+ UT_LIST_REMOVE(unzip_LRU, buf_pool->unzip_LRU, block);
+ }
+}
+
+/******************************************************************//**
+Removes a block from the LRU list. */
+UNIV_INLINE
+void
+buf_LRU_remove_block(
+/*=================*/
+ buf_page_t* bpage) /*!< in: control block */
+{
+ ut_ad(buf_pool);
+ ut_ad(bpage);
+ ut_ad(buf_pool_mutex_own());
+
+ ut_a(buf_page_in_file(bpage));
+
+ ut_ad(bpage->in_LRU_list);
+
+ /* If the LRU_old pointer is defined and points to just this block,
+ move it backward one step */
+
+ if (UNIV_UNLIKELY(bpage == buf_pool->LRU_old)) {
+
+ /* Below: the previous block is guaranteed to exist, because
+ the LRU_old pointer is only allowed to differ by the
+ tolerance value from strict 3/8 of the LRU list length. */
+
+ buf_pool->LRU_old = UT_LIST_GET_PREV(LRU, bpage);
+ ut_a(buf_pool->LRU_old);
+#ifdef UNIV_LRU_DEBUG
+ ut_a(!buf_pool->LRU_old->old);
+#endif /* UNIV_LRU_DEBUG */
+ buf_page_set_old(buf_pool->LRU_old, TRUE);
+
+ buf_pool->LRU_old_len++;
+ }
+
+ /* Remove the block from the LRU list */
+ UT_LIST_REMOVE(LRU, buf_pool->LRU, bpage);
+ ut_d(bpage->in_LRU_list = FALSE);
+
+ buf_unzip_LRU_remove_block_if_needed(bpage);
+
+ /* If the LRU list is so short that LRU_old not defined, return */
+ if (UT_LIST_GET_LEN(buf_pool->LRU) < BUF_LRU_OLD_MIN_LEN) {
+
+ buf_pool->LRU_old = NULL;
+
+ return;
+ }
+
+ ut_ad(buf_pool->LRU_old);
+
+ /* Update the LRU_old_len field if necessary */
+ if (buf_page_is_old(bpage)) {
+
+ buf_pool->LRU_old_len--;
+ }
+
+ /* Adjust the length of the old block list if necessary */
+ buf_LRU_old_adjust_len();
+}
+
+/******************************************************************//**
+Adds a block to the LRU list of decompressed zip pages. */
+UNIV_INTERN
+void
+buf_unzip_LRU_add_block(
+/*====================*/
+ buf_block_t* block, /*!< in: control block */
+ ibool old) /*!< in: TRUE if should be put to the end
+ of the list, else put to the start */
+{
+ ut_ad(buf_pool);
+ ut_ad(block);
+ ut_ad(buf_pool_mutex_own());
+
+ ut_a(buf_page_belongs_to_unzip_LRU(&block->page));
+
+ ut_ad(!block->in_unzip_LRU_list);
+ ut_d(block->in_unzip_LRU_list = TRUE);
+
+ if (old) {
+ UT_LIST_ADD_LAST(unzip_LRU, buf_pool->unzip_LRU, block);
+ } else {
+ UT_LIST_ADD_FIRST(unzip_LRU, buf_pool->unzip_LRU, block);
+ }
+}
+
+/******************************************************************//**
+Adds a block to the LRU list end. */
+UNIV_INLINE
+void
+buf_LRU_add_block_to_end_low(
+/*=========================*/
+ buf_page_t* bpage) /*!< in: control block */
+{
+ buf_page_t* last_bpage;
+
+ ut_ad(buf_pool);
+ ut_ad(bpage);
+ ut_ad(buf_pool_mutex_own());
+
+ ut_a(buf_page_in_file(bpage));
+
+ last_bpage = UT_LIST_GET_LAST(buf_pool->LRU);
+
+ if (last_bpage) {
+ bpage->LRU_position = last_bpage->LRU_position;
+ } else {
+ bpage->LRU_position = buf_pool_clock_tic();
+ }
+
+ ut_ad(!bpage->in_LRU_list);
+ UT_LIST_ADD_LAST(LRU, buf_pool->LRU, bpage);
+ ut_d(bpage->in_LRU_list = TRUE);
+
+ buf_page_set_old(bpage, TRUE);
+
+ if (UT_LIST_GET_LEN(buf_pool->LRU) >= BUF_LRU_OLD_MIN_LEN) {
+
+ buf_pool->LRU_old_len++;
+ }
+
+ if (UT_LIST_GET_LEN(buf_pool->LRU) > BUF_LRU_OLD_MIN_LEN) {
+
+ ut_ad(buf_pool->LRU_old);
+
+ /* Adjust the length of the old block list if necessary */
+
+ buf_LRU_old_adjust_len();
+
+ } else if (UT_LIST_GET_LEN(buf_pool->LRU) == BUF_LRU_OLD_MIN_LEN) {
+
+ /* The LRU list is now long enough for LRU_old to become
+ defined: init it */
+
+ buf_LRU_old_init();
+ }
+
+ /* If this is a zipped block with decompressed frame as well
+ then put it on the unzip_LRU list */
+ if (buf_page_belongs_to_unzip_LRU(bpage)) {
+ buf_unzip_LRU_add_block((buf_block_t*) bpage, TRUE);
+ }
+}
+
+/******************************************************************//**
+Adds a block to the LRU list. */
+UNIV_INLINE
+void
+buf_LRU_add_block_low(
+/*==================*/
+ buf_page_t* bpage, /*!< in: control block */
+ ibool old) /*!< in: TRUE if should be put to the old blocks
+ in the LRU list, else put to the start; if the
+ LRU list is very short, the block is added to
+ the start, regardless of this parameter */
+{
+ ut_ad(buf_pool);
+ ut_ad(bpage);
+ ut_ad(buf_pool_mutex_own());
+
+ ut_a(buf_page_in_file(bpage));
+ ut_ad(!bpage->in_LRU_list);
+
+ if (!old || (UT_LIST_GET_LEN(buf_pool->LRU) < BUF_LRU_OLD_MIN_LEN)) {
+
+ UT_LIST_ADD_FIRST(LRU, buf_pool->LRU, bpage);
+
+ bpage->LRU_position = buf_pool_clock_tic();
+ bpage->freed_page_clock = buf_pool->freed_page_clock;
+ } else {
+#ifdef UNIV_LRU_DEBUG
+ /* buf_pool->LRU_old must be the first item in the LRU list
+ whose "old" flag is set. */
+ ut_a(buf_pool->LRU_old->old);
+ ut_a(!UT_LIST_GET_PREV(LRU, buf_pool->LRU_old)
+ || !UT_LIST_GET_PREV(LRU, buf_pool->LRU_old)->old);
+ ut_a(!UT_LIST_GET_NEXT(LRU, buf_pool->LRU_old)
+ || UT_LIST_GET_NEXT(LRU, buf_pool->LRU_old)->old);
+#endif /* UNIV_LRU_DEBUG */
+ UT_LIST_INSERT_AFTER(LRU, buf_pool->LRU, buf_pool->LRU_old,
+ bpage);
+ buf_pool->LRU_old_len++;
+
+ /* We copy the LRU position field of the previous block
+ to the new block */
+
+ bpage->LRU_position = (buf_pool->LRU_old)->LRU_position;
+ }
+
+ ut_d(bpage->in_LRU_list = TRUE);
+
+ buf_page_set_old(bpage, old);
+
+ if (UT_LIST_GET_LEN(buf_pool->LRU) > BUF_LRU_OLD_MIN_LEN) {
+
+ ut_ad(buf_pool->LRU_old);
+
+ /* Adjust the length of the old block list if necessary */
+
+ buf_LRU_old_adjust_len();
+
+ } else if (UT_LIST_GET_LEN(buf_pool->LRU) == BUF_LRU_OLD_MIN_LEN) {
+
+ /* The LRU list is now long enough for LRU_old to become
+ defined: init it */
+
+ buf_LRU_old_init();
+ }
+
+ /* If this is a zipped block with decompressed frame as well
+ then put it on the unzip_LRU list */
+ if (buf_page_belongs_to_unzip_LRU(bpage)) {
+ buf_unzip_LRU_add_block((buf_block_t*) bpage, old);
+ }
+}
+
+/******************************************************************//**
+Adds a block to the LRU list. */
+UNIV_INTERN
+void
+buf_LRU_add_block(
+/*==============*/
+ buf_page_t* bpage, /*!< in: control block */
+ ibool old) /*!< in: TRUE if should be put to the old
+ blocks in the LRU list, else put to the start;
+ if the LRU list is very short, the block is
+ added to the start, regardless of this
+ parameter */
+{
+ buf_LRU_add_block_low(bpage, old);
+}
+
+/******************************************************************//**
+Moves a block to the start of the LRU list. */
+UNIV_INTERN
+void
+buf_LRU_make_block_young(
+/*=====================*/
+ buf_page_t* bpage) /*!< in: control block */
+{
+ buf_LRU_remove_block(bpage);
+ buf_LRU_add_block_low(bpage, FALSE);
+}
+
+/******************************************************************//**
+Moves a block to the end of the LRU list. */
+UNIV_INTERN
+void
+buf_LRU_make_block_old(
+/*===================*/
+ buf_page_t* bpage) /*!< in: control block */
+{
+ buf_LRU_remove_block(bpage);
+ buf_LRU_add_block_to_end_low(bpage);
+}
+
+/******************************************************************//**
+Try to free a block. If bpage is a descriptor of a compressed-only
+page, the descriptor object will be freed as well.
+
+NOTE: If this function returns BUF_LRU_FREED, it will not temporarily
+release buf_pool_mutex. Furthermore, the page frame will no longer be
+accessible via bpage.
+
+The caller must hold buf_pool_mutex and buf_page_get_mutex(bpage) and
+release these two mutexes after the call. No other
+buf_page_get_mutex() may be held when calling this function.
+@return BUF_LRU_FREED if freed, BUF_LRU_CANNOT_RELOCATE or
+BUF_LRU_NOT_FREED otherwise. */
+UNIV_INTERN
+enum buf_lru_free_block_status
+buf_LRU_free_block(
+/*===============*/
+ buf_page_t* bpage, /*!< in: block to be freed */
+ ibool zip, /*!< in: TRUE if should remove also the
+ compressed page of an uncompressed page */
+ ibool* buf_pool_mutex_released)
+ /*!< in: pointer to a variable that will
+ be assigned TRUE if buf_pool_mutex
+ was temporarily released, or NULL */
+{
+ buf_page_t* b = NULL;
+ mutex_t* block_mutex = buf_page_get_mutex(bpage);
+
+ ut_ad(buf_pool_mutex_own());
+ ut_ad(mutex_own(block_mutex));
+ ut_ad(buf_page_in_file(bpage));
+ ut_ad(bpage->in_LRU_list);
+ ut_ad(!bpage->in_flush_list == !bpage->oldest_modification);
+ UNIV_MEM_ASSERT_RW(bpage, sizeof *bpage);
+
+ if (!buf_page_can_relocate(bpage)) {
+
+ /* Do not free buffer-fixed or I/O-fixed blocks. */
+ return(BUF_LRU_NOT_FREED);
+ }
+
+#ifdef UNIV_IBUF_COUNT_DEBUG
+ ut_a(ibuf_count_get(bpage->space, bpage->offset) == 0);
+#endif /* UNIV_IBUF_COUNT_DEBUG */
+
+ if (zip || !bpage->zip.data) {
+ /* This would completely free the block. */
+ /* Do not completely free dirty blocks. */
+
+ if (bpage->oldest_modification) {
+ return(BUF_LRU_NOT_FREED);
+ }
+ } else if (bpage->oldest_modification) {
+ /* Do not completely free dirty blocks. */
+
+ if (buf_page_get_state(bpage) != BUF_BLOCK_FILE_PAGE) {
+ ut_ad(buf_page_get_state(bpage)
+ == BUF_BLOCK_ZIP_DIRTY);
+ return(BUF_LRU_NOT_FREED);
+ }
+
+ goto alloc;
+ } else if (buf_page_get_state(bpage) == BUF_BLOCK_FILE_PAGE) {
+ /* Allocate the control block for the compressed page.
+ If it cannot be allocated (without freeing a block
+ from the LRU list), refuse to free bpage. */
+alloc:
+ buf_pool_mutex_exit_forbid();
+ b = buf_buddy_alloc(sizeof *b, NULL);
+ buf_pool_mutex_exit_allow();
+
+ if (UNIV_UNLIKELY(!b)) {
+ return(BUF_LRU_CANNOT_RELOCATE);
+ }
+
+ memcpy(b, bpage, sizeof *b);
+ }
+
+#ifdef UNIV_DEBUG
+ if (buf_debug_prints) {
+ fprintf(stderr, "Putting space %lu page %lu to free list\n",
+ (ulong) buf_page_get_space(bpage),
+ (ulong) buf_page_get_page_no(bpage));
+ }
+#endif /* UNIV_DEBUG */
+
+ if (buf_LRU_block_remove_hashed_page(bpage, zip)
+ != BUF_BLOCK_ZIP_FREE) {
+ ut_a(bpage->buf_fix_count == 0);
+
+ if (b) {
+ buf_page_t* prev_b = UT_LIST_GET_PREV(LRU, b);
+ const ulint fold = buf_page_address_fold(
+ bpage->space, bpage->offset);
+
+ ut_a(!buf_page_hash_get(bpage->space, bpage->offset));
+
+ b->state = b->oldest_modification
+ ? BUF_BLOCK_ZIP_DIRTY
+ : BUF_BLOCK_ZIP_PAGE;
+ UNIV_MEM_DESC(b->zip.data,
+ page_zip_get_size(&b->zip), b);
+
+ /* The fields in_page_hash and in_LRU_list of
+ the to-be-freed block descriptor should have
+ been cleared in
+ buf_LRU_block_remove_hashed_page(), which
+ invokes buf_LRU_remove_block(). */
+ ut_ad(!bpage->in_page_hash);
+ ut_ad(!bpage->in_LRU_list);
+ /* bpage->state was BUF_BLOCK_FILE_PAGE because
+ b != NULL. The type cast below is thus valid. */
+ ut_ad(!((buf_block_t*) bpage)->in_unzip_LRU_list);
+
+ /* The fields of bpage were copied to b before
+ buf_LRU_block_remove_hashed_page() was invoked. */
+ ut_ad(!b->in_zip_hash);
+ ut_ad(b->in_page_hash);
+ ut_ad(b->in_LRU_list);
+
+ HASH_INSERT(buf_page_t, hash,
+ buf_pool->page_hash, fold, b);
+
+ /* Insert b where bpage was in the LRU list. */
+ if (UNIV_LIKELY(prev_b != NULL)) {
+ ulint lru_len;
+
+ ut_ad(prev_b->in_LRU_list);
+ ut_ad(buf_page_in_file(prev_b));
+ UNIV_MEM_ASSERT_RW(prev_b, sizeof *prev_b);
+
+ UT_LIST_INSERT_AFTER(LRU, buf_pool->LRU,
+ prev_b, b);
+
+ if (buf_page_is_old(b)) {
+ buf_pool->LRU_old_len++;
+ if (UNIV_UNLIKELY
+ (buf_pool->LRU_old
+ == UT_LIST_GET_NEXT(LRU, b))) {
+
+ buf_pool->LRU_old = b;
+ }
+#ifdef UNIV_LRU_DEBUG
+ ut_a(prev_b->old
+ || !UT_LIST_GET_NEXT(LRU, b)
+ || UT_LIST_GET_NEXT(LRU, b)->old);
+ } else {
+ ut_a(!prev_b->old
+ || !UT_LIST_GET_NEXT(LRU, b)
+ || !UT_LIST_GET_NEXT(LRU, b)->old);
+#endif /* UNIV_LRU_DEBUG */
+ }
+
+ lru_len = UT_LIST_GET_LEN(buf_pool->LRU);
+
+ if (lru_len > BUF_LRU_OLD_MIN_LEN) {
+ ut_ad(buf_pool->LRU_old);
+ /* Adjust the length of the
+ old block list if necessary */
+ buf_LRU_old_adjust_len();
+ } else if (lru_len == BUF_LRU_OLD_MIN_LEN) {
+ /* The LRU list is now long
+ enough for LRU_old to become
+ defined: init it */
+ buf_LRU_old_init();
+ }
+ } else {
+ ut_d(b->in_LRU_list = FALSE);
+ buf_LRU_add_block_low(b, buf_page_is_old(b));
+ }
+
+ if (b->state == BUF_BLOCK_ZIP_PAGE) {
+ buf_LRU_insert_zip_clean(b);
+ } else {
+ buf_page_t* prev;
+
+ ut_ad(b->in_flush_list);
+ ut_d(bpage->in_flush_list = FALSE);
+
+ prev = UT_LIST_GET_PREV(list, b);
+ UT_LIST_REMOVE(list, buf_pool->flush_list, b);
+
+ if (prev) {
+ ut_ad(prev->in_flush_list);
+ UT_LIST_INSERT_AFTER(
+ list,
+ buf_pool->flush_list,
+ prev, b);
+ } else {
+ UT_LIST_ADD_FIRST(
+ list,
+ buf_pool->flush_list,
+ b);
+ }
+ }
+
+ bpage->zip.data = NULL;
+ page_zip_set_size(&bpage->zip, 0);
+
+ /* Prevent buf_page_get_gen() from
+ decompressing the block while we release
+ buf_pool_mutex and block_mutex. */
+ b->buf_fix_count++;
+ b->io_fix = BUF_IO_READ;
+ }
+
+ if (buf_pool_mutex_released) {
+ *buf_pool_mutex_released = TRUE;
+ }
+
+ buf_pool_mutex_exit();
+ mutex_exit(block_mutex);
+
+ /* Remove possible adaptive hash index on the page.
+ The page was declared uninitialized by
+ buf_LRU_block_remove_hashed_page(). We need to flag
+ the contents of the page valid (which it still is) in
+ order to avoid bogus Valgrind warnings.*/
+
+ UNIV_MEM_VALID(((buf_block_t*) bpage)->frame,
+ UNIV_PAGE_SIZE);
+ btr_search_drop_page_hash_index((buf_block_t*) bpage);
+ UNIV_MEM_INVALID(((buf_block_t*) bpage)->frame,
+ UNIV_PAGE_SIZE);
+
+ if (b) {
+ /* Compute and stamp the compressed page
+ checksum while not holding any mutex. The
+ block is already half-freed
+ (BUF_BLOCK_REMOVE_HASH) and removed from
+ buf_pool->page_hash, thus inaccessible by any
+ other thread. */
+
+ mach_write_to_4(
+ b->zip.data + FIL_PAGE_SPACE_OR_CHKSUM,
+ UNIV_LIKELY(srv_use_checksums)
+ ? page_zip_calc_checksum(
+ b->zip.data,
+ page_zip_get_size(&b->zip))
+ : BUF_NO_CHECKSUM_MAGIC);
+ }
+
+ buf_pool_mutex_enter();
+ mutex_enter(block_mutex);
+
+ if (b) {
+ mutex_enter(&buf_pool_zip_mutex);
+ b->buf_fix_count--;
+ buf_page_set_io_fix(b, BUF_IO_NONE);
+ mutex_exit(&buf_pool_zip_mutex);
+ }
+
+ buf_LRU_block_free_hashed_page((buf_block_t*) bpage);
+ } else {
+ /* The block_mutex should have been released by
+ buf_LRU_block_remove_hashed_page() when it returns
+ BUF_BLOCK_ZIP_FREE. */
+ ut_ad(block_mutex == &buf_pool_zip_mutex);
+ mutex_enter(block_mutex);
+ }
+
+ return(BUF_LRU_FREED);
+}
+
+/******************************************************************//**
+Puts a block back to the free list. */
+UNIV_INTERN
+void
+buf_LRU_block_free_non_file_page(
+/*=============================*/
+ buf_block_t* block) /*!< in: block, must not contain a file page */
+{
+ void* data;
+
+ ut_ad(block);
+ ut_ad(buf_pool_mutex_own());
+ ut_ad(mutex_own(&block->mutex));
+
+ switch (buf_block_get_state(block)) {
+ case BUF_BLOCK_MEMORY:
+ case BUF_BLOCK_READY_FOR_USE:
+ break;
+ default:
+ ut_error;
+ }
+
+#if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
+ ut_a(block->n_pointers == 0);
+#endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
+ ut_ad(!block->page.in_free_list);
+ ut_ad(!block->page.in_flush_list);
+ ut_ad(!block->page.in_LRU_list);
+
+ buf_block_set_state(block, BUF_BLOCK_NOT_USED);
+
+ UNIV_MEM_ALLOC(block->frame, UNIV_PAGE_SIZE);
+#ifdef UNIV_DEBUG
+ /* Wipe contents of page to reveal possible stale pointers to it */
+ memset(block->frame, '\0', UNIV_PAGE_SIZE);
+#else
+ /* Wipe page_no and space_id */
+ memset(block->frame + FIL_PAGE_OFFSET, 0xfe, 4);
+ memset(block->frame + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID, 0xfe, 4);
+#endif
+ data = block->page.zip.data;
+
+ if (data) {
+ block->page.zip.data = NULL;
+ mutex_exit(&block->mutex);
+ buf_pool_mutex_exit_forbid();
+ buf_buddy_free(data, page_zip_get_size(&block->page.zip));
+ buf_pool_mutex_exit_allow();
+ mutex_enter(&block->mutex);
+ page_zip_set_size(&block->page.zip, 0);
+ }
+
+ UT_LIST_ADD_FIRST(list, buf_pool->free, (&block->page));
+ ut_d(block->page.in_free_list = TRUE);
+
+ UNIV_MEM_ASSERT_AND_FREE(block->frame, UNIV_PAGE_SIZE);
+}
+
+/******************************************************************//**
+Takes a block out of the LRU list and page hash table.
+If the block is compressed-only (BUF_BLOCK_ZIP_PAGE),
+the object will be freed and buf_pool_zip_mutex will be released.
+
+If a compressed page or a compressed-only block descriptor is freed,
+other compressed pages or compressed-only block descriptors may be
+relocated.
+@return the new state of the block (BUF_BLOCK_ZIP_FREE if the state
+was BUF_BLOCK_ZIP_PAGE, or BUF_BLOCK_REMOVE_HASH otherwise) */
+static
+enum buf_page_state
+buf_LRU_block_remove_hashed_page(
+/*=============================*/
+ buf_page_t* bpage, /*!< in: block, must contain a file page and
+ be in a state where it can be freed; there
+ may or may not be a hash index to the page */
+ ibool zip) /*!< in: TRUE if should remove also the
+ compressed page of an uncompressed page */
+{
+ const buf_page_t* hashed_bpage;
+ ut_ad(bpage);
+ ut_ad(buf_pool_mutex_own());
+ ut_ad(mutex_own(buf_page_get_mutex(bpage)));
+
+ ut_a(buf_page_get_io_fix(bpage) == BUF_IO_NONE);
+ ut_a(bpage->buf_fix_count == 0);
+
+ UNIV_MEM_ASSERT_RW(bpage, sizeof *bpage);
+
+ buf_LRU_remove_block(bpage);
+
+ buf_pool->freed_page_clock += 1;
+
+ switch (buf_page_get_state(bpage)) {
+ case BUF_BLOCK_FILE_PAGE:
+ UNIV_MEM_ASSERT_W(bpage, sizeof(buf_block_t));
+ UNIV_MEM_ASSERT_W(((buf_block_t*) bpage)->frame,
+ UNIV_PAGE_SIZE);
+ buf_block_modify_clock_inc((buf_block_t*) bpage);
+ if (bpage->zip.data) {
+ const page_t* page = ((buf_block_t*) bpage)->frame;
+ const ulint zip_size
+ = page_zip_get_size(&bpage->zip);
+
+ ut_a(!zip || bpage->oldest_modification == 0);
+
+ switch (UNIV_EXPECT(fil_page_get_type(page),
+ FIL_PAGE_INDEX)) {
+ case FIL_PAGE_TYPE_ALLOCATED:
+ case FIL_PAGE_INODE:
+ case FIL_PAGE_IBUF_BITMAP:
+ case FIL_PAGE_TYPE_FSP_HDR:
+ case FIL_PAGE_TYPE_XDES:
+ /* These are essentially uncompressed pages. */
+ if (!zip) {
+ /* InnoDB writes the data to the
+ uncompressed page frame. Copy it
+ to the compressed page, which will
+ be preserved. */
+ memcpy(bpage->zip.data, page,
+ zip_size);
+ }
+ break;
+ case FIL_PAGE_TYPE_ZBLOB:
+ case FIL_PAGE_TYPE_ZBLOB2:
+ break;
+ case FIL_PAGE_INDEX:
+#ifdef UNIV_ZIP_DEBUG
+ ut_a(page_zip_validate(&bpage->zip, page));
+#endif /* UNIV_ZIP_DEBUG */
+ break;
+ default:
+ ut_print_timestamp(stderr);
+ fputs(" InnoDB: ERROR: The compressed page"
+ " to be evicted seems corrupt:", stderr);
+ ut_print_buf(stderr, page, zip_size);
+ fputs("\nInnoDB: Possibly older version"
+ " of the page:", stderr);
+ ut_print_buf(stderr, bpage->zip.data,
+ zip_size);
+ putc('\n', stderr);
+ ut_error;
+ }
+
+ break;
+ }
+ /* fall through */
+ case BUF_BLOCK_ZIP_PAGE:
+ ut_a(bpage->oldest_modification == 0);
+ UNIV_MEM_ASSERT_W(bpage->zip.data,
+ page_zip_get_size(&bpage->zip));
+ break;
+ case BUF_BLOCK_ZIP_FREE:
+ case BUF_BLOCK_ZIP_DIRTY:
+ case BUF_BLOCK_NOT_USED:
+ case BUF_BLOCK_READY_FOR_USE:
+ case BUF_BLOCK_MEMORY:
+ case BUF_BLOCK_REMOVE_HASH:
+ ut_error;
+ break;
+ }
+
+ hashed_bpage = buf_page_hash_get(bpage->space, bpage->offset);
+
+ if (UNIV_UNLIKELY(bpage != hashed_bpage)) {
+ fprintf(stderr,
+ "InnoDB: Error: page %lu %lu not found"
+ " in the hash table\n",
+ (ulong) bpage->space,
+ (ulong) bpage->offset);
+ if (hashed_bpage) {
+ fprintf(stderr,
+ "InnoDB: In hash table we find block"
+ " %p of %lu %lu which is not %p\n",
+ (const void*) hashed_bpage,
+ (ulong) hashed_bpage->space,
+ (ulong) hashed_bpage->offset,
+ (const void*) bpage);
+ }
+
+#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
+ mutex_exit(buf_page_get_mutex(bpage));
+ buf_pool_mutex_exit();
+ buf_print();
+ buf_LRU_print();
+ buf_validate();
+ buf_LRU_validate();
+#endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
+ ut_error;
+ }
+
+ ut_ad(!bpage->in_zip_hash);
+ ut_ad(bpage->in_page_hash);
+ ut_d(bpage->in_page_hash = FALSE);
+ HASH_DELETE(buf_page_t, hash, buf_pool->page_hash,
+ buf_page_address_fold(bpage->space, bpage->offset),
+ bpage);
+ switch (buf_page_get_state(bpage)) {
+ case BUF_BLOCK_ZIP_PAGE:
+ ut_ad(!bpage->in_free_list);
+ ut_ad(!bpage->in_flush_list);
+ ut_ad(!bpage->in_LRU_list);
+ ut_a(bpage->zip.data);
+ ut_a(buf_page_get_zip_size(bpage));
+
+ UT_LIST_REMOVE(list, buf_pool->zip_clean, bpage);
+
+ mutex_exit(&buf_pool_zip_mutex);
+ buf_pool_mutex_exit_forbid();
+ buf_buddy_free(bpage->zip.data,
+ page_zip_get_size(&bpage->zip));
+ buf_buddy_free(bpage, sizeof(*bpage));
+ buf_pool_mutex_exit_allow();
+ UNIV_MEM_UNDESC(bpage);
+ return(BUF_BLOCK_ZIP_FREE);
+
+ case BUF_BLOCK_FILE_PAGE:
+ memset(((buf_block_t*) bpage)->frame
+ + FIL_PAGE_OFFSET, 0xff, 4);
+ memset(((buf_block_t*) bpage)->frame
+ + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID, 0xff, 4);
+ UNIV_MEM_INVALID(((buf_block_t*) bpage)->frame,
+ UNIV_PAGE_SIZE);
+ buf_page_set_state(bpage, BUF_BLOCK_REMOVE_HASH);
+
+ if (zip && bpage->zip.data) {
+ /* Free the compressed page. */
+ void* data = bpage->zip.data;
+ bpage->zip.data = NULL;
+
+ ut_ad(!bpage->in_free_list);
+ ut_ad(!bpage->in_flush_list);
+ ut_ad(!bpage->in_LRU_list);
+ mutex_exit(&((buf_block_t*) bpage)->mutex);
+ buf_pool_mutex_exit_forbid();
+ buf_buddy_free(data, page_zip_get_size(&bpage->zip));
+ buf_pool_mutex_exit_allow();
+ mutex_enter(&((buf_block_t*) bpage)->mutex);
+ page_zip_set_size(&bpage->zip, 0);
+ }
+
+ return(BUF_BLOCK_REMOVE_HASH);
+
+ case BUF_BLOCK_ZIP_FREE:
+ case BUF_BLOCK_ZIP_DIRTY:
+ case BUF_BLOCK_NOT_USED:
+ case BUF_BLOCK_READY_FOR_USE:
+ case BUF_BLOCK_MEMORY:
+ case BUF_BLOCK_REMOVE_HASH:
+ break;
+ }
+
+ ut_error;
+ return(BUF_BLOCK_ZIP_FREE);
+}
+
+/******************************************************************//**
+Puts a file page whose has no hash index to the free list. */
+static
+void
+buf_LRU_block_free_hashed_page(
+/*===========================*/
+ buf_block_t* block) /*!< in: block, must contain a file page and
+ be in a state where it can be freed */
+{
+ ut_ad(buf_pool_mutex_own());
+ ut_ad(mutex_own(&block->mutex));
+
+ buf_block_set_state(block, BUF_BLOCK_MEMORY);
+
+ buf_LRU_block_free_non_file_page(block);
+}
+
+/********************************************************************//**
+Update the historical stats that we are collecting for LRU eviction
+policy at the end of each interval. */
+UNIV_INTERN
+void
+buf_LRU_stat_update(void)
+/*=====================*/
+{
+ buf_LRU_stat_t* item;
+
+ /* If we haven't started eviction yet then don't update stats. */
+ if (buf_pool->freed_page_clock == 0) {
+ goto func_exit;
+ }
+
+ buf_pool_mutex_enter();
+
+ /* Update the index. */
+ item = &buf_LRU_stat_arr[buf_LRU_stat_arr_ind];
+ 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;
+
+ /* Put current entry in the array. */
+ memcpy(item, &buf_LRU_stat_cur, sizeof *item);
+
+ buf_pool_mutex_exit();
+
+func_exit:
+ /* Clear the current entry. */
+ memset(&buf_LRU_stat_cur, 0, sizeof buf_LRU_stat_cur);
+}
+
+#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
+/**********************************************************************//**
+Validates the LRU list.
+@return TRUE */
+UNIV_INTERN
+ibool
+buf_LRU_validate(void)
+/*==================*/
+{
+ buf_page_t* bpage;
+ buf_block_t* block;
+ ulint old_len;
+ ulint new_len;
+ ulint LRU_pos;
+
+ ut_ad(buf_pool);
+ buf_pool_mutex_enter();
+
+ if (UT_LIST_GET_LEN(buf_pool->LRU) >= BUF_LRU_OLD_MIN_LEN) {
+
+ ut_a(buf_pool->LRU_old);
+ old_len = buf_pool->LRU_old_len;
+ new_len = 3 * (UT_LIST_GET_LEN(buf_pool->LRU) / 8);
+ ut_a(old_len >= new_len - BUF_LRU_OLD_TOLERANCE);
+ ut_a(old_len <= new_len + BUF_LRU_OLD_TOLERANCE);
+ }
+
+ UT_LIST_VALIDATE(LRU, buf_page_t, buf_pool->LRU,
+ ut_ad(ut_list_node_313->in_LRU_list));
+
+ bpage = UT_LIST_GET_FIRST(buf_pool->LRU);
+
+ old_len = 0;
+
+ while (bpage != NULL) {
+
+ switch (buf_page_get_state(bpage)) {
+ case BUF_BLOCK_ZIP_FREE:
+ case BUF_BLOCK_NOT_USED:
+ case BUF_BLOCK_READY_FOR_USE:
+ case BUF_BLOCK_MEMORY:
+ case BUF_BLOCK_REMOVE_HASH:
+ ut_error;
+ break;
+ case BUF_BLOCK_FILE_PAGE:
+ ut_ad(((buf_block_t*) bpage)->in_unzip_LRU_list
+ == buf_page_belongs_to_unzip_LRU(bpage));
+ case BUF_BLOCK_ZIP_PAGE:
+ case BUF_BLOCK_ZIP_DIRTY:
+ break;
+ }
+
+ if (buf_page_is_old(bpage)) {
+ old_len++;
+ }
+
+ if (buf_pool->LRU_old && (old_len == 1)) {
+ ut_a(buf_pool->LRU_old == bpage);
+ }
+
+ LRU_pos = buf_page_get_LRU_position(bpage);
+
+ bpage = UT_LIST_GET_NEXT(LRU, bpage);
+
+ if (bpage) {
+ /* If the following assert fails, it may
+ not be an error: just the buf_pool clock
+ has wrapped around */
+ ut_a(LRU_pos >= buf_page_get_LRU_position(bpage));
+ }
+ }
+
+ if (buf_pool->LRU_old) {
+ ut_a(buf_pool->LRU_old_len == old_len);
+ }
+
+ UT_LIST_VALIDATE(list, buf_page_t, buf_pool->free,
+ ut_ad(ut_list_node_313->in_free_list));
+
+ for (bpage = UT_LIST_GET_FIRST(buf_pool->free);
+ bpage != NULL;
+ bpage = UT_LIST_GET_NEXT(list, bpage)) {
+
+ ut_a(buf_page_get_state(bpage) == BUF_BLOCK_NOT_USED);
+ }
+
+ UT_LIST_VALIDATE(unzip_LRU, buf_block_t, buf_pool->unzip_LRU,
+ ut_ad(ut_list_node_313->in_unzip_LRU_list
+ && ut_list_node_313->page.in_LRU_list));
+
+ for (block = UT_LIST_GET_FIRST(buf_pool->unzip_LRU);
+ block;
+ block = UT_LIST_GET_NEXT(unzip_LRU, block)) {
+
+ ut_ad(block->in_unzip_LRU_list);
+ ut_ad(block->page.in_LRU_list);
+ ut_a(buf_page_belongs_to_unzip_LRU(&block->page));
+ }
+
+ buf_pool_mutex_exit();
+ return(TRUE);
+}
+#endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
+
+#if defined UNIV_DEBUG_PRINT || defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
+/**********************************************************************//**
+Prints the LRU list. */
+UNIV_INTERN
+void
+buf_LRU_print(void)
+/*===============*/
+{
+ const buf_page_t* bpage;
+
+ ut_ad(buf_pool);
+ buf_pool_mutex_enter();
+
+ fprintf(stderr, "Pool ulint clock %lu\n",
+ (ulong) buf_pool->ulint_clock);
+
+ bpage = UT_LIST_GET_FIRST(buf_pool->LRU);
+
+ while (bpage != NULL) {
+
+ fprintf(stderr, "BLOCK space %lu page %lu ",
+ (ulong) buf_page_get_space(bpage),
+ (ulong) buf_page_get_page_no(bpage));
+
+ if (buf_page_is_old(bpage)) {
+ fputs("old ", stderr);
+ }
+
+ if (bpage->buf_fix_count) {
+ fprintf(stderr, "buffix count %lu ",
+ (ulong) bpage->buf_fix_count);
+ }
+
+ if (buf_page_get_io_fix(bpage)) {
+ fprintf(stderr, "io_fix %lu ",
+ (ulong) buf_page_get_io_fix(bpage));
+ }
+
+ if (bpage->oldest_modification) {
+ fputs("modif. ", stderr);
+ }
+
+ switch (buf_page_get_state(bpage)) {
+ const byte* frame;
+ case BUF_BLOCK_FILE_PAGE:
+ frame = buf_block_get_frame((buf_block_t*) bpage);
+ fprintf(stderr, "\nLRU pos %lu type %lu"
+ " index id %lu\n",
+ (ulong) buf_page_get_LRU_position(bpage),
+ (ulong) fil_page_get_type(frame),
+ (ulong) ut_dulint_get_low(
+ btr_page_get_index_id(frame)));
+ break;
+ case BUF_BLOCK_ZIP_PAGE:
+ frame = bpage->zip.data;
+ fprintf(stderr, "\nLRU pos %lu type %lu size %lu"
+ " index id %lu\n",
+ (ulong) buf_page_get_LRU_position(bpage),
+ (ulong) fil_page_get_type(frame),
+ (ulong) buf_page_get_zip_size(bpage),
+ (ulong) ut_dulint_get_low(
+ btr_page_get_index_id(frame)));
+ break;
+
+ default:
+ fprintf(stderr, "\nLRU pos %lu !state %lu!\n",
+ (ulong) buf_page_get_LRU_position(bpage),
+ (ulong) buf_page_get_state(bpage));
+ break;
+ }
+
+ bpage = UT_LIST_GET_NEXT(LRU, bpage);
+ }
+
+ buf_pool_mutex_exit();
+}
+#endif /* UNIV_DEBUG_PRINT || UNIV_DEBUG || UNIV_BUF_DEBUG */
diff --git a/storage/innobase/buf/buf0rea.c b/storage/innodb_plugin/buf/buf0rea.c
similarity index 63%
rename from storage/innobase/buf/buf0rea.c
rename to storage/innodb_plugin/buf/buf0rea.c
index fdec0206990..319d6b2a522 100644
--- a/storage/innobase/buf/buf0rea.c
+++ b/storage/innodb_plugin/buf/buf0rea.c
@@ -1,7 +1,24 @@
-/******************************************************
-The database buffer read
+/*****************************************************************************
-(c) 1995 Innobase Oy
+Copyright (c) 1995, 2009, Innobase Oy. All Rights Reserved.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; version 2 of the License.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place, Suite 330, Boston, MA 02111-1307 USA
+
+*****************************************************************************/
+
+/**************************************************//**
+@file buf/buf0rea.c
+The database buffer read
Created 11/5/1995 Heikki Tuuri
*******************************************************/
@@ -19,60 +36,55 @@ Created 11/5/1995 Heikki Tuuri
#include "trx0sys.h"
#include "os0file.h"
#include "srv0start.h"
+#include "srv0srv.h"
-extern ulint srv_read_ahead_rnd;
-extern ulint srv_read_ahead_seq;
-extern ulint srv_buf_pool_reads;
-
-/* The size in blocks of the area where the random read-ahead algorithm counts
+/** The size in blocks of the area where the random read-ahead algorithm counts
the accessed pages when deciding whether to read-ahead */
#define BUF_READ_AHEAD_RANDOM_AREA BUF_READ_AHEAD_AREA
-/* There must be at least this many pages in buf_pool in the area to start
+/** There must be at least this many pages in buf_pool in the area to start
a random read-ahead */
-#define BUF_READ_AHEAD_RANDOM_THRESHOLD (5 + BUF_READ_AHEAD_RANDOM_AREA / 8)
+#define BUF_READ_AHEAD_RANDOM_THRESHOLD (1 + BUF_READ_AHEAD_RANDOM_AREA / 2)
-/* The linear read-ahead area size */
+/** The linear read-ahead area size */
#define BUF_READ_AHEAD_LINEAR_AREA BUF_READ_AHEAD_AREA
-/* The linear read-ahead threshold */
-#define BUF_READ_AHEAD_LINEAR_THRESHOLD (3 * BUF_READ_AHEAD_LINEAR_AREA / 8)
-
-/* If there are buf_pool->curr_size per the number below pending reads, then
+/** If there are buf_pool->curr_size per the number below pending reads, then
read-ahead is not done: this is to prevent flooding the buffer pool with
i/o-fixed buffer blocks */
#define BUF_READ_AHEAD_PEND_LIMIT 2
-/************************************************************************
+/********************************************************************//**
Low-level function which reads a page asynchronously from a file to the
buffer buf_pool if it is not already there, in which case does nothing.
Sets the io_fix flag and sets an exclusive lock on the buffer frame. The
-flag is cleared and the x-lock released by an i/o-handler thread. */
+flag is cleared and the x-lock released by an i/o-handler thread.
+@return 1 if a read request was queued, 0 if the page already resided
+in buf_pool, or if the page is in the doublewrite buffer blocks in
+which case it is never read into the pool, or if the tablespace does
+not exist or is being dropped */
static
ulint
buf_read_page_low(
/*==============*/
- /* out: 1 if a read request was queued, 0 if the page
- already resided in buf_pool, or if the page is in
- the doublewrite buffer blocks in which case it is never
- read into the pool, or if the tablespace does not
- exist or is being dropped */
- ulint* err, /* out: DB_SUCCESS or DB_TABLESPACE_DELETED if we are
+ ulint* err, /*!< out: DB_SUCCESS or DB_TABLESPACE_DELETED if we are
trying to read from a non-existent tablespace, or a
tablespace which is just now being dropped */
- ibool sync, /* in: TRUE if synchronous aio is desired */
- ulint mode, /* in: BUF_READ_IBUF_PAGES_ONLY, ...,
+ ibool sync, /*!< in: TRUE if synchronous aio is desired */
+ ulint mode, /*!< in: BUF_READ_IBUF_PAGES_ONLY, ...,
ORed to OS_AIO_SIMULATED_WAKE_LATER (see below
at read-ahead functions) */
- ulint space, /* in: space id */
- ib_longlong tablespace_version, /* in: if the space memory object has
+ ulint space, /*!< in: space id */
+ ulint zip_size,/*!< in: compressed page size, or 0 */
+ ibool unzip, /*!< in: TRUE=request uncompressed page */
+ ib_int64_t tablespace_version, /*!< in: if the space memory object has
this timestamp different from what we are giving here,
treat the tablespace as dropped; this is a timestamp we
use to stop dangling page reads from a tablespace
which we have DISCARDed + IMPORTed back */
- ulint offset) /* in: page number */
+ ulint offset) /*!< in: page number */
{
- buf_block_t* block;
+ buf_page_t* bpage;
ulint wake_later;
*err = DB_SUCCESS;
@@ -96,7 +108,8 @@ buf_read_page_low(
return(0);
}
- if (ibuf_bitmap_page(offset) || trx_sys_hdr_page(space, offset)) {
+ if (ibuf_bitmap_page(zip_size, offset)
+ || trx_sys_hdr_page(space, offset)) {
/* Trx sys header is so low in the latching order that we play
safe and do not leave the i/o-completion to an asynchronous
@@ -111,9 +124,9 @@ buf_read_page_low(
or is being dropped; if we succeed in initing the page in the buffer
pool for read, then DISCARD cannot proceed until the read has
completed */
- block = buf_page_init_for_read(err, mode, space, tablespace_version,
- offset);
- if (block == NULL) {
+ bpage = buf_page_init_for_read(err, mode, space, zip_size, unzip,
+ tablespace_version, offset);
+ if (bpage == NULL) {
return(0);
}
@@ -127,24 +140,31 @@ buf_read_page_low(
}
#endif
- ut_a(block->state == BUF_BLOCK_FILE_PAGE);
+ ut_ad(buf_page_in_file(bpage));
- *err = fil_io(OS_FILE_READ | wake_later,
- sync, space,
- offset, 0, UNIV_PAGE_SIZE,
- (void*)block->frame, (void*)block);
+ if (zip_size) {
+ *err = fil_io(OS_FILE_READ | wake_later,
+ sync, space, zip_size, offset, 0, zip_size,
+ bpage->zip.data, bpage);
+ } else {
+ ut_a(buf_page_get_state(bpage) == BUF_BLOCK_FILE_PAGE);
+
+ *err = fil_io(OS_FILE_READ | wake_later,
+ sync, space, 0, offset, 0, UNIV_PAGE_SIZE,
+ ((buf_block_t*) bpage)->frame, bpage);
+ }
ut_a(*err == DB_SUCCESS);
if (sync) {
/* The i/o is already completed when we arrive from
fil_read */
- buf_page_io_complete(block);
+ buf_page_io_complete(bpage);
}
return(1);
}
-/************************************************************************
+/********************************************************************//**
Applies a random read-ahead in buf_pool if there are at least a threshold
value of accessed pages from the random read-ahead area. Does not read any
page, not even the one at the position (space, offset), if the read-ahead
@@ -153,21 +173,20 @@ pages: to avoid deadlocks this function must be written such that it cannot
end up waiting for these latches! NOTE 2: the calling thread must want
access to the page given: this rule is set to prevent unintended read-aheads
performed by ibuf routines, a situation which could result in a deadlock if
-the OS does not support asynchronous i/o. */
+the OS does not support asynchronous i/o.
+@return number of page read requests issued; NOTE that if we read ibuf
+pages, it may happen that the page at the given page number does not
+get read even if we return a positive value! */
static
ulint
buf_read_ahead_random(
/*==================*/
- /* out: number of page read requests issued; NOTE
- that if we read ibuf pages, it may happen that
- the page at the given page number does not get
- read even if we return a value > 0! */
- ulint space, /* in: space id */
- ulint offset) /* in: page number of a page which the current thread
+ ulint space, /*!< in: space id */
+ ulint zip_size,/*!< in: compressed page size in bytes, or 0 */
+ ulint offset) /*!< in: page number of a page which the current thread
wants to access */
{
- ib_longlong tablespace_version;
- buf_block_t* block;
+ ib_int64_t tablespace_version;
ulint recent_blocks = 0;
ulint count;
ulint LRU_recent_limit;
@@ -175,13 +194,18 @@ buf_read_ahead_random(
ulint low, high;
ulint err;
ulint i;
+ ulint buf_read_ahead_random_area;
+
+ /* We have currently disabled random readahead */
+ return(0);
if (srv_startup_is_before_trx_rollback_phase) {
/* No read-ahead to avoid thread deadlocks */
return(0);
}
- if (ibuf_bitmap_page(offset) || trx_sys_hdr_page(space, offset)) {
+ if (ibuf_bitmap_page(zip_size, offset)
+ || trx_sys_hdr_page(space, offset)) {
/* If it is an ibuf bitmap page or trx sys hdr, we do
no read-ahead, as that could break the ibuf page access
@@ -196,10 +220,12 @@ buf_read_ahead_random(
tablespace_version = fil_space_get_version(space);
- low = (offset / BUF_READ_AHEAD_RANDOM_AREA)
- * BUF_READ_AHEAD_RANDOM_AREA;
- high = (offset / BUF_READ_AHEAD_RANDOM_AREA + 1)
- * BUF_READ_AHEAD_RANDOM_AREA;
+ buf_read_ahead_random_area = BUF_READ_AHEAD_RANDOM_AREA;
+
+ low = (offset / buf_read_ahead_random_area)
+ * buf_read_ahead_random_area;
+ high = (offset / buf_read_ahead_random_area + 1)
+ * buf_read_ahead_random_area;
if (high > fil_space_get_size(space)) {
high = fil_space_get_size(space);
@@ -211,11 +237,11 @@ buf_read_ahead_random(
LRU_recent_limit = buf_LRU_get_recent_limit();
- mutex_enter(&(buf_pool->mutex));
+ buf_pool_mutex_enter();
if (buf_pool->n_pend_reads
> buf_pool->curr_size / BUF_READ_AHEAD_PEND_LIMIT) {
- mutex_exit(&(buf_pool->mutex));
+ buf_pool_mutex_exit();
return(0);
}
@@ -224,24 +250,27 @@ buf_read_ahead_random(
that is, reside near the start of the LRU list. */
for (i = low; i < high; i++) {
- block = buf_page_hash_get(space, i);
+ const buf_page_t* bpage = buf_page_hash_get(space, i);
- if ((block)
- && (block->LRU_position > LRU_recent_limit)
- && block->accessed) {
+ if (bpage
+ && buf_page_is_accessed(bpage)
+ && (buf_page_get_LRU_position(bpage) > LRU_recent_limit)) {
recent_blocks++;
+
+ if (recent_blocks >= BUF_READ_AHEAD_RANDOM_THRESHOLD) {
+
+ buf_pool_mutex_exit();
+ goto read_ahead;
+ }
}
}
- mutex_exit(&(buf_pool->mutex));
-
- if (recent_blocks < BUF_READ_AHEAD_RANDOM_THRESHOLD) {
- /* Do nothing */
-
- return(0);
- }
+ buf_pool_mutex_exit();
+ /* Do nothing */
+ return(0);
+read_ahead:
/* Read all the suitable blocks within the area */
if (ibuf_inside()) {
@@ -256,11 +285,12 @@ buf_read_ahead_random(
/* It is only sensible to do read-ahead in the non-sync aio
mode: hence FALSE as the first parameter */
- if (!ibuf_bitmap_page(i)) {
+ if (!ibuf_bitmap_page(zip_size, i)) {
count += buf_read_page_low(
&err, FALSE,
ibuf_mode | OS_AIO_SIMULATED_WAKE_LATER,
- space, tablespace_version, i);
+ space, zip_size, FALSE,
+ tablespace_version, i);
if (err == DB_TABLESPACE_DELETED) {
ut_print_timestamp(stderr);
fprintf(stderr,
@@ -293,34 +323,36 @@ buf_read_ahead_random(
return(count);
}
-/************************************************************************
+/********************************************************************//**
High-level function which reads a page asynchronously from a file to the
buffer buf_pool if it is not already there. Sets the io_fix flag and sets
an exclusive lock on the buffer frame. The flag is cleared and the x-lock
released by the i/o-handler thread. Does a random read-ahead if it seems
-sensible. */
-
+sensible.
+@return number of page read requests issued: this can be greater than
+1 if read-ahead occurred */
+UNIV_INTERN
ulint
buf_read_page(
/*==========*/
- /* out: number of page read requests issued: this can
- be > 1 if read-ahead occurred */
- ulint space, /* in: space id */
- ulint offset) /* in: page number */
+ ulint space, /*!< in: space id */
+ ulint zip_size,/*!< in: compressed page size in bytes, or 0 */
+ ulint offset) /*!< in: page number */
{
- ib_longlong tablespace_version;
+ ib_int64_t tablespace_version;
ulint count;
ulint count2;
ulint err;
tablespace_version = fil_space_get_version(space);
- count = buf_read_ahead_random(space, offset);
+ count = buf_read_ahead_random(space, zip_size, offset);
/* We do the i/o in the synchronous aio mode to save thread
switches: hence TRUE */
count2 = buf_read_page_low(&err, TRUE, BUF_READ_ANY_PAGE, space,
+ zip_size, FALSE,
tablespace_version, offset);
srv_buf_pool_reads+= count2;
if (err == DB_TABLESPACE_DELETED) {
@@ -336,10 +368,13 @@ buf_read_page(
/* Flush pages from the end of the LRU list if necessary */
buf_flush_free_margin();
+ /* Increment number of I/O operations used for LRU policy. */
+ buf_LRU_stat_inc_io();
+
return(count + count2);
}
-/************************************************************************
+/********************************************************************//**
Applies linear read-ahead if in the buf_pool the page is a border page of
a linear read-ahead area and all the pages in the area have been accessed.
Does not read any page if the read-ahead mechanism is not activated. Note
@@ -361,20 +396,21 @@ function must be written such that it cannot end up waiting for these
latches!
NOTE 3: the calling thread must want access to the page given: this rule is
set to prevent unintended read-aheads performed by ibuf routines, a situation
-which could result in a deadlock if the OS does not support asynchronous io. */
-
+which could result in a deadlock if the OS does not support asynchronous io.
+@return number of page read requests issued */
+UNIV_INTERN
ulint
buf_read_ahead_linear(
/*==================*/
- /* out: number of page read requests issued */
- ulint space, /* in: space id */
- ulint offset) /* in: page number of a page; NOTE: the current thread
+ ulint space, /*!< in: space id */
+ ulint zip_size,/*!< in: compressed page size in bytes, or 0 */
+ ulint offset) /*!< in: page number of a page; NOTE: the current thread
must want access to this page (see NOTE 3 above) */
{
- ib_longlong tablespace_version;
- buf_block_t* block;
+ ib_int64_t tablespace_version;
+ buf_page_t* bpage;
buf_frame_t* frame;
- buf_block_t* pred_block = NULL;
+ buf_page_t* pred_bpage = NULL;
ulint pred_offset;
ulint succ_offset;
ulint count;
@@ -385,28 +421,32 @@ buf_read_ahead_linear(
ulint low, high;
ulint err;
ulint i;
+ const ulint buf_read_ahead_linear_area
+ = BUF_READ_AHEAD_LINEAR_AREA;
+ ulint threshold;
- if (srv_startup_is_before_trx_rollback_phase) {
+ if (UNIV_UNLIKELY(srv_startup_is_before_trx_rollback_phase)) {
/* No read-ahead to avoid thread deadlocks */
return(0);
}
- if (ibuf_bitmap_page(offset) || trx_sys_hdr_page(space, offset)) {
+ low = (offset / buf_read_ahead_linear_area)
+ * buf_read_ahead_linear_area;
+ high = (offset / buf_read_ahead_linear_area + 1)
+ * buf_read_ahead_linear_area;
- /* If it is an ibuf bitmap page or trx sys hdr, we do
- no read-ahead, as that could break the ibuf page access
- order */
+ if ((offset != low) && (offset != high - 1)) {
+ /* This is not a border page of the area: return */
return(0);
}
- low = (offset / BUF_READ_AHEAD_LINEAR_AREA)
- * BUF_READ_AHEAD_LINEAR_AREA;
- high = (offset / BUF_READ_AHEAD_LINEAR_AREA + 1)
- * BUF_READ_AHEAD_LINEAR_AREA;
+ if (ibuf_bitmap_page(zip_size, offset)
+ || trx_sys_hdr_page(space, offset)) {
- if ((offset != low) && (offset != high - 1)) {
- /* This is not a border page of the area: return */
+ /* If it is an ibuf bitmap page or trx sys hdr, we do
+ no read-ahead, as that could break the ibuf page access
+ order */
return(0);
}
@@ -417,10 +457,10 @@ buf_read_ahead_linear(
tablespace_version = fil_space_get_version(space);
- mutex_enter(&(buf_pool->mutex));
+ buf_pool_mutex_enter();
if (high > fil_space_get_size(space)) {
- mutex_exit(&(buf_pool->mutex));
+ buf_pool_mutex_exit();
/* The area is not whole, return */
return(0);
@@ -428,7 +468,7 @@ buf_read_ahead_linear(
if (buf_pool->n_pend_reads
> buf_pool->curr_size / BUF_READ_AHEAD_PEND_LIMIT) {
- mutex_exit(&(buf_pool->mutex));
+ buf_pool_mutex_exit();
return(0);
}
@@ -443,47 +483,63 @@ buf_read_ahead_linear(
asc_or_desc = -1;
}
+ /* How many out of order accessed pages can we ignore
+ when working out the access pattern for linear readahead */
+ threshold = ut_min((64 - srv_read_ahead_threshold),
+ BUF_READ_AHEAD_AREA);
+
fail_count = 0;
for (i = low; i < high; i++) {
- block = buf_page_hash_get(space, i);
+ bpage = buf_page_hash_get(space, i);
- if ((block == NULL) || !block->accessed) {
+ if ((bpage == NULL) || !buf_page_is_accessed(bpage)) {
/* Not accessed */
fail_count++;
- } else if (pred_block
- && (ut_ulint_cmp(block->LRU_position,
- pred_block->LRU_position)
- != asc_or_desc)) {
+ } else if (pred_bpage) {
+ int res = (ut_ulint_cmp(
+ buf_page_get_LRU_position(bpage),
+ buf_page_get_LRU_position(pred_bpage)));
/* Accesses not in the right order */
-
- fail_count++;
- pred_block = block;
+ if (res != 0 && res != asc_or_desc) {
+ fail_count++;
+ }
}
- }
- if (fail_count > BUF_READ_AHEAD_LINEAR_AREA
- - BUF_READ_AHEAD_LINEAR_THRESHOLD) {
- /* Too many failures: return */
+ if (fail_count > threshold) {
+ /* Too many failures: return */
+ buf_pool_mutex_exit();
+ return(0);
+ }
- mutex_exit(&(buf_pool->mutex));
-
- return(0);
+ if (bpage && buf_page_is_accessed(bpage)) {
+ pred_bpage = bpage;
+ }
}
/* If we got this far, we know that enough pages in the area have
been accessed in the right order: linear read-ahead can be sensible */
- block = buf_page_hash_get(space, offset);
+ bpage = buf_page_hash_get(space, offset);
- if (block == NULL) {
- mutex_exit(&(buf_pool->mutex));
+ if (bpage == NULL) {
+ buf_pool_mutex_exit();
return(0);
}
- frame = block->frame;
+ switch (buf_page_get_state(bpage)) {
+ case BUF_BLOCK_ZIP_PAGE:
+ frame = bpage->zip.data;
+ break;
+ case BUF_BLOCK_FILE_PAGE:
+ frame = ((buf_block_t*) bpage)->frame;
+ break;
+ default:
+ ut_error;
+ break;
+ }
/* Read the natural predecessor and successor page addresses from
the page; NOTE that because the calling thread may have an x-latch
@@ -494,7 +550,7 @@ buf_read_ahead_linear(
pred_offset = fil_page_get_prev(frame);
succ_offset = fil_page_get_next(frame);
- mutex_exit(&(buf_pool->mutex));
+ buf_pool_mutex_exit();
if ((offset == low) && (succ_offset == offset + 1)) {
@@ -511,10 +567,10 @@ buf_read_ahead_linear(
return(0);
}
- low = (new_offset / BUF_READ_AHEAD_LINEAR_AREA)
- * BUF_READ_AHEAD_LINEAR_AREA;
- high = (new_offset / BUF_READ_AHEAD_LINEAR_AREA + 1)
- * BUF_READ_AHEAD_LINEAR_AREA;
+ low = (new_offset / buf_read_ahead_linear_area)
+ * buf_read_ahead_linear_area;
+ high = (new_offset / buf_read_ahead_linear_area + 1)
+ * buf_read_ahead_linear_area;
if ((new_offset != low) && (new_offset != high - 1)) {
/* This is not a border page of the area: return */
@@ -548,11 +604,11 @@ buf_read_ahead_linear(
/* It is only sensible to do read-ahead in the non-sync
aio mode: hence FALSE as the first parameter */
- if (!ibuf_bitmap_page(i)) {
+ if (!ibuf_bitmap_page(zip_size, i)) {
count += buf_read_page_low(
&err, FALSE,
ibuf_mode | OS_AIO_SIMULATED_WAKE_LATER,
- space, tablespace_version, i);
+ space, zip_size, FALSE, tablespace_version, i);
if (err == DB_TABLESPACE_DELETED) {
ut_print_timestamp(stderr);
fprintf(stderr,
@@ -583,32 +639,42 @@ buf_read_ahead_linear(
}
#endif /* UNIV_DEBUG */
+ /* Read ahead is considered one I/O operation for the purpose of
+ LRU policy decision. */
+ buf_LRU_stat_inc_io();
+
++srv_read_ahead_seq;
return(count);
}
-/************************************************************************
+/********************************************************************//**
Issues read requests for pages which the ibuf module wants to read in, in
order to contract the insert buffer tree. Technically, this function is like
a read-ahead function. */
-
+UNIV_INTERN
void
buf_read_ibuf_merge_pages(
/*======================*/
- ibool sync, /* in: TRUE if the caller wants this function
- to wait for the highest address page to get
- read in, before this function returns */
- ulint* space_ids, /* in: array of space ids */
- ib_longlong* space_versions,/* in: the spaces must have this version
- number (timestamp), otherwise we discard the
- read; we use this to cancel reads if
- DISCARD + IMPORT may have changed the
- tablespace size */
- ulint* page_nos, /* in: array of page numbers to read, with the
- highest page number the last in the array */
- ulint n_stored) /* in: number of page numbers in the array */
+ ibool sync, /*!< in: TRUE if the caller
+ wants this function to wait
+ for the highest address page
+ to get read in, before this
+ function returns */
+ const ulint* space_ids, /*!< in: array of space ids */
+ const ib_int64_t* space_versions,/*!< in: the spaces must have
+ this version number
+ (timestamp), otherwise we
+ discard the read; we use this
+ to cancel reads if DISCARD +
+ IMPORT may have changed the
+ tablespace size */
+ const ulint* page_nos, /*!< in: array of page numbers
+ to read, with the highest page
+ number the last in the
+ array */
+ ulint n_stored) /*!< in: number of elements
+ in the arrays */
{
- ulint err;
ulint i;
ut_ad(!ibuf_inside());
@@ -621,18 +687,27 @@ buf_read_ibuf_merge_pages(
}
for (i = 0; i < n_stored; i++) {
- buf_read_page_low(&err,
- (i + 1 == n_stored) && sync,
- BUF_READ_ANY_PAGE,
- space_ids[i], space_versions[i],
+ ulint zip_size = fil_space_get_zip_size(space_ids[i]);
+ ulint err;
+
+ if (UNIV_UNLIKELY(zip_size == ULINT_UNDEFINED)) {
+
+ goto tablespace_deleted;
+ }
+
+ buf_read_page_low(&err, sync && (i + 1 == n_stored),
+ BUF_READ_ANY_PAGE, space_ids[i],
+ zip_size, TRUE, space_versions[i],
page_nos[i]);
- if (err == DB_TABLESPACE_DELETED) {
+ if (UNIV_UNLIKELY(err == DB_TABLESPACE_DELETED)) {
+tablespace_deleted:
/* We have deleted or are deleting the single-table
tablespace: remove the entries for that page */
ibuf_merge_or_delete_for_page(NULL, space_ids[i],
- page_nos[i], FALSE);
+ page_nos[i],
+ zip_size, FALSE);
}
}
@@ -650,25 +725,41 @@ buf_read_ibuf_merge_pages(
#endif /* UNIV_DEBUG */
}
-/************************************************************************
+/********************************************************************//**
Issues read requests for pages which recovery wants to read in. */
-
+UNIV_INTERN
void
buf_read_recv_pages(
/*================*/
- ibool sync, /* in: TRUE if the caller wants this function
- to wait for the highest address page to get
- read in, before this function returns */
- ulint space, /* in: space id */
- ulint* page_nos, /* in: array of page numbers to read, with the
- highest page number the last in the array */
- ulint n_stored) /* in: number of page numbers in the array */
+ ibool sync, /*!< in: TRUE if the caller
+ wants this function to wait
+ for the highest address page
+ to get read in, before this
+ function returns */
+ ulint space, /*!< in: space id */
+ ulint zip_size, /*!< in: compressed page size in
+ bytes, or 0 */
+ const ulint* page_nos, /*!< in: array of page numbers
+ to read, with the highest page
+ number the last in the
+ array */
+ ulint n_stored) /*!< in: number of page numbers
+ in the array */
{
- ib_longlong tablespace_version;
+ ib_int64_t tablespace_version;
ulint count;
ulint err;
ulint i;
+ zip_size = fil_space_get_zip_size(space);
+
+ if (UNIV_UNLIKELY(zip_size == ULINT_UNDEFINED)) {
+ /* It is a single table tablespace and the .ibd file is
+ missing: do nothing */
+
+ return;
+ }
+
tablespace_version = fil_space_get_version(space);
for (i = 0; i < n_stored; i++) {
@@ -702,14 +793,14 @@ buf_read_recv_pages(
os_aio_print_debug = FALSE;
if ((i + 1 == n_stored) && sync) {
- buf_read_page_low(&err, TRUE, BUF_READ_ANY_PAGE,
- space, tablespace_version,
+ buf_read_page_low(&err, TRUE, BUF_READ_ANY_PAGE, space,
+ zip_size, TRUE, tablespace_version,
page_nos[i]);
} else {
buf_read_page_low(&err, FALSE, BUF_READ_ANY_PAGE
| OS_AIO_SIMULATED_WAKE_LATER,
- space, tablespace_version,
- page_nos[i]);
+ space, zip_size, TRUE,
+ tablespace_version, page_nos[i]);
}
}
diff --git a/storage/innodb_plugin/compile-innodb b/storage/innodb_plugin/compile-innodb
new file mode 100755
index 00000000000..82601f03ae9
--- /dev/null
+++ b/storage/innodb_plugin/compile-innodb
@@ -0,0 +1,24 @@
+#! /bin/sh
+#
+# Copyright (c) 2006, 2009, Innobase Oy. All Rights Reserved.
+#
+# This program is free software; you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free Software
+# Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+# Place, Suite 330, Boston, MA 02111-1307 USA
+#
+
+path=`dirname $0`
+. "$path/SETUP.sh"
+
+extra_flags="$pentium_cflags $fast_cflags -g"
+extra_configs="$pentium_configs $static_link --with-plugins=innobase"
+
+. "$path/FINISH.sh"
diff --git a/storage/innodb_plugin/compile-innodb-debug b/storage/innodb_plugin/compile-innodb-debug
new file mode 100755
index 00000000000..efb4abf88d5
--- /dev/null
+++ b/storage/innodb_plugin/compile-innodb-debug
@@ -0,0 +1,24 @@
+#! /bin/sh
+#
+# Copyright (c) 2005, 2009, Innobase Oy. All Rights Reserved.
+#
+# This program is free software; you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free Software
+# Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+# Place, Suite 330, Boston, MA 02111-1307 USA
+#
+
+path=`dirname $0`
+. "$path/SETUP.sh" $@ --with-debug=full
+
+extra_flags="$pentium_cflags $debug_cflags"
+extra_configs="$pentium_configs $debug_configs --with-plugins=innobase"
+
+. "$path/FINISH.sh"
diff --git a/storage/innodb_plugin/data/data0data.c b/storage/innodb_plugin/data/data0data.c
new file mode 100644
index 00000000000..e3c1f1b4f23
--- /dev/null
+++ b/storage/innodb_plugin/data/data0data.c
@@ -0,0 +1,764 @@
+/*****************************************************************************
+
+Copyright (c) 1994, 2009, Innobase Oy. All Rights Reserved.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; version 2 of the License.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place, Suite 330, Boston, MA 02111-1307 USA
+
+*****************************************************************************/
+
+/********************************************************************//**
+@file data/data0data.c
+SQL data field and tuple
+
+Created 5/30/1994 Heikki Tuuri
+*************************************************************************/
+
+#include "data0data.h"
+
+#ifdef UNIV_NONINL
+#include "data0data.ic"
+#endif
+
+#ifndef UNIV_HOTBACKUP
+#include "rem0rec.h"
+#include "rem0cmp.h"
+#include "page0page.h"
+#include "page0zip.h"
+#include "dict0dict.h"
+#include "btr0cur.h"
+
+#include
+#endif /* !UNIV_HOTBACKUP */
+
+#ifdef UNIV_DEBUG
+/** Dummy variable to catch access to uninitialized fields. In the
+debug version, dtuple_create() will make all fields of dtuple_t point
+to data_error. */
+UNIV_INTERN byte data_error;
+
+# ifndef UNIV_DEBUG_VALGRIND
+/** this is used to fool the compiler in dtuple_validate */
+UNIV_INTERN ulint data_dummy;
+# endif /* !UNIV_DEBUG_VALGRIND */
+#endif /* UNIV_DEBUG */
+
+#ifndef UNIV_HOTBACKUP
+/*********************************************************************//**
+Tests if dfield data length and content is equal to the given.
+@return TRUE if equal */
+UNIV_INTERN
+ibool
+dfield_data_is_binary_equal(
+/*========================*/
+ const dfield_t* field, /*!< in: field */
+ ulint len, /*!< in: data length or UNIV_SQL_NULL */
+ const byte* data) /*!< in: data */
+{
+ if (len != dfield_get_len(field)) {
+
+ return(FALSE);
+ }
+
+ if (len == UNIV_SQL_NULL) {
+
+ return(TRUE);
+ }
+
+ if (0 != memcmp(dfield_get_data(field), data, len)) {
+
+ return(FALSE);
+ }
+
+ return(TRUE);
+}
+
+/************************************************************//**
+Compare two data tuples, respecting the collation of character fields.
+@return 1, 0 , -1 if tuple1 is greater, equal, less, respectively,
+than tuple2 */
+UNIV_INTERN
+int
+dtuple_coll_cmp(
+/*============*/
+ const dtuple_t* tuple1, /*!< in: tuple 1 */
+ const dtuple_t* tuple2) /*!< in: tuple 2 */
+{
+ ulint n_fields;
+ ulint i;
+
+ ut_ad(tuple1 && tuple2);
+ ut_ad(tuple1->magic_n == DATA_TUPLE_MAGIC_N);
+ ut_ad(tuple2->magic_n == DATA_TUPLE_MAGIC_N);
+ ut_ad(dtuple_check_typed(tuple1));
+ ut_ad(dtuple_check_typed(tuple2));
+
+ n_fields = dtuple_get_n_fields(tuple1);
+
+ if (n_fields != dtuple_get_n_fields(tuple2)) {
+
+ return(n_fields < dtuple_get_n_fields(tuple2) ? -1 : 1);
+ }
+
+ for (i = 0; i < n_fields; i++) {
+ int cmp;
+ const dfield_t* field1 = dtuple_get_nth_field(tuple1, i);
+ const dfield_t* field2 = dtuple_get_nth_field(tuple2, i);
+
+ cmp = cmp_dfield_dfield(field1, field2);
+
+ if (cmp) {
+ return(cmp);
+ }
+ }
+
+ return(0);
+}
+
+/*********************************************************************//**
+Sets number of fields used in a tuple. Normally this is set in
+dtuple_create, but if you want later to set it smaller, you can use this. */
+UNIV_INTERN
+void
+dtuple_set_n_fields(
+/*================*/
+ dtuple_t* tuple, /*!< in: tuple */
+ ulint n_fields) /*!< in: number of fields */
+{
+ ut_ad(tuple);
+
+ tuple->n_fields = n_fields;
+ tuple->n_fields_cmp = n_fields;
+}
+
+/**********************************************************//**
+Checks that a data field is typed.
+@return TRUE if ok */
+static
+ibool
+dfield_check_typed_no_assert(
+/*=========================*/
+ const dfield_t* field) /*!< in: data field */
+{
+ if (dfield_get_type(field)->mtype > DATA_MYSQL
+ || dfield_get_type(field)->mtype < DATA_VARCHAR) {
+
+ fprintf(stderr,
+ "InnoDB: Error: data field type %lu, len %lu\n",
+ (ulong) dfield_get_type(field)->mtype,
+ (ulong) dfield_get_len(field));
+ return(FALSE);
+ }
+
+ return(TRUE);
+}
+
+/**********************************************************//**
+Checks that a data tuple is typed.
+@return TRUE if ok */
+UNIV_INTERN
+ibool
+dtuple_check_typed_no_assert(
+/*=========================*/
+ const dtuple_t* tuple) /*!< in: tuple */
+{
+ const dfield_t* field;
+ ulint i;
+
+ if (dtuple_get_n_fields(tuple) > REC_MAX_N_FIELDS) {
+ fprintf(stderr,
+ "InnoDB: Error: index entry has %lu fields\n",
+ (ulong) dtuple_get_n_fields(tuple));
+dump:
+ fputs("InnoDB: Tuple contents: ", stderr);
+ dtuple_print(stderr, tuple);
+ putc('\n', stderr);
+
+ return(FALSE);
+ }
+
+ for (i = 0; i < dtuple_get_n_fields(tuple); i++) {
+
+ field = dtuple_get_nth_field(tuple, i);
+
+ if (!dfield_check_typed_no_assert(field)) {
+ goto dump;
+ }
+ }
+
+ return(TRUE);
+}
+#endif /* !UNIV_HOTBACKUP */
+
+#ifdef UNIV_DEBUG
+/**********************************************************//**
+Checks that a data field is typed. Asserts an error if not.
+@return TRUE if ok */
+UNIV_INTERN
+ibool
+dfield_check_typed(
+/*===============*/
+ const dfield_t* field) /*!< in: data field */
+{
+ if (dfield_get_type(field)->mtype > DATA_MYSQL
+ || dfield_get_type(field)->mtype < DATA_VARCHAR) {
+
+ fprintf(stderr,
+ "InnoDB: Error: data field type %lu, len %lu\n",
+ (ulong) dfield_get_type(field)->mtype,
+ (ulong) dfield_get_len(field));
+
+ ut_error;
+ }
+
+ return(TRUE);
+}
+
+/**********************************************************//**
+Checks that a data tuple is typed. Asserts an error if not.
+@return TRUE if ok */
+UNIV_INTERN
+ibool
+dtuple_check_typed(
+/*===============*/
+ const dtuple_t* tuple) /*!< in: tuple */
+{
+ const dfield_t* field;
+ ulint i;
+
+ for (i = 0; i < dtuple_get_n_fields(tuple); i++) {
+
+ field = dtuple_get_nth_field(tuple, i);
+
+ ut_a(dfield_check_typed(field));
+ }
+
+ return(TRUE);
+}
+
+/**********************************************************//**
+Validates the consistency of a tuple which must be complete, i.e,
+all fields must have been set.
+@return TRUE if ok */
+UNIV_INTERN
+ibool
+dtuple_validate(
+/*============*/
+ const dtuple_t* tuple) /*!< in: tuple */
+{
+ const dfield_t* field;
+ ulint n_fields;
+ ulint len;
+ ulint i;
+
+ ut_ad(tuple->magic_n == DATA_TUPLE_MAGIC_N);
+
+ n_fields = dtuple_get_n_fields(tuple);
+
+ /* We dereference all the data of each field to test
+ for memory traps */
+
+ for (i = 0; i < n_fields; i++) {
+
+ field = dtuple_get_nth_field(tuple, i);
+ len = dfield_get_len(field);
+
+ if (!dfield_is_null(field)) {
+
+ const byte* data = dfield_get_data(field);
+#ifndef UNIV_DEBUG_VALGRIND
+ ulint j;
+
+ for (j = 0; j < len; j++) {
+
+ data_dummy += *data; /* fool the compiler not
+ to optimize out this
+ code */
+ data++;
+ }
+#endif /* !UNIV_DEBUG_VALGRIND */
+
+ UNIV_MEM_ASSERT_RW(data, len);
+ }
+ }
+
+ ut_a(dtuple_check_typed(tuple));
+
+ return(TRUE);
+}
+#endif /* UNIV_DEBUG */
+
+#ifndef UNIV_HOTBACKUP
+/*************************************************************//**
+Pretty prints a dfield value according to its data type. */
+UNIV_INTERN
+void
+dfield_print(
+/*=========*/
+ const dfield_t* dfield) /*!< in: dfield */
+{
+ const byte* data;
+ ulint len;
+ ulint i;
+
+ len = dfield_get_len(dfield);
+ data = dfield_get_data(dfield);
+
+ if (dfield_is_null(dfield)) {
+ fputs("NULL", stderr);
+
+ return;
+ }
+
+ switch (dtype_get_mtype(dfield_get_type(dfield))) {
+ case DATA_CHAR:
+ case DATA_VARCHAR:
+ for (i = 0; i < len; i++) {
+ int c = *data++;
+ putc(isprint(c) ? c : ' ', stderr);
+ }
+
+ if (dfield_is_ext(dfield)) {
+ fputs("(external)", stderr);
+ }
+ break;
+ case DATA_INT:
+ ut_a(len == 4); /* only works for 32-bit integers */
+ fprintf(stderr, "%d", (int)mach_read_from_4(data));
+ break;
+ default:
+ ut_error;
+ }
+}
+
+/*************************************************************//**
+Pretty prints a dfield value according to its data type. Also the hex string
+is printed if a string contains non-printable characters. */
+UNIV_INTERN
+void
+dfield_print_also_hex(
+/*==================*/
+ const dfield_t* dfield) /*!< in: dfield */
+{
+ const byte* data;
+ ulint len;
+ ulint prtype;
+ ulint i;
+ ibool print_also_hex;
+
+ len = dfield_get_len(dfield);
+ data = dfield_get_data(dfield);
+
+ if (dfield_is_null(dfield)) {
+ fputs("NULL", stderr);
+
+ return;
+ }
+
+ prtype = dtype_get_prtype(dfield_get_type(dfield));
+
+ switch (dtype_get_mtype(dfield_get_type(dfield))) {
+ dulint id;
+ case DATA_INT:
+ switch (len) {
+ ulint val;
+ case 1:
+ val = mach_read_from_1(data);
+
+ if (!(prtype & DATA_UNSIGNED)) {
+ val &= ~0x80;
+ fprintf(stderr, "%ld", (long) val);
+ } else {
+ fprintf(stderr, "%lu", (ulong) val);
+ }
+ break;
+
+ case 2:
+ val = mach_read_from_2(data);
+
+ if (!(prtype & DATA_UNSIGNED)) {
+ val &= ~0x8000;
+ fprintf(stderr, "%ld", (long) val);
+ } else {
+ fprintf(stderr, "%lu", (ulong) val);
+ }
+ break;
+
+ case 3:
+ val = mach_read_from_3(data);
+
+ if (!(prtype & DATA_UNSIGNED)) {
+ val &= ~0x800000;
+ fprintf(stderr, "%ld", (long) val);
+ } else {
+ fprintf(stderr, "%lu", (ulong) val);
+ }
+ break;
+
+ case 4:
+ val = mach_read_from_4(data);
+
+ if (!(prtype & DATA_UNSIGNED)) {
+ val &= ~0x80000000;
+ fprintf(stderr, "%ld", (long) val);
+ } else {
+ fprintf(stderr, "%lu", (ulong) val);
+ }
+ break;
+
+ case 6:
+ id = mach_read_from_6(data);
+ fprintf(stderr, "{%lu %lu}",
+ ut_dulint_get_high(id),
+ ut_dulint_get_low(id));
+ break;
+
+ case 7:
+ id = mach_read_from_7(data);
+ fprintf(stderr, "{%lu %lu}",
+ ut_dulint_get_high(id),
+ ut_dulint_get_low(id));
+ break;
+ case 8:
+ id = mach_read_from_8(data);
+ fprintf(stderr, "{%lu %lu}",
+ ut_dulint_get_high(id),
+ ut_dulint_get_low(id));
+ break;
+ default:
+ goto print_hex;
+ }
+ break;
+
+ case DATA_SYS:
+ switch (prtype & DATA_SYS_PRTYPE_MASK) {
+ case DATA_TRX_ID:
+ id = mach_read_from_6(data);
+
+ fprintf(stderr, "trx_id " TRX_ID_FMT,
+ TRX_ID_PREP_PRINTF(id));
+ break;
+
+ case DATA_ROLL_PTR:
+ id = mach_read_from_7(data);
+
+ fprintf(stderr, "roll_ptr {%lu %lu}",
+ ut_dulint_get_high(id), ut_dulint_get_low(id));
+ break;
+
+ case DATA_ROW_ID:
+ id = mach_read_from_6(data);
+
+ fprintf(stderr, "row_id {%lu %lu}",
+ ut_dulint_get_high(id), ut_dulint_get_low(id));
+ break;
+
+ default:
+ id = mach_dulint_read_compressed(data);
+
+ fprintf(stderr, "mix_id {%lu %lu}",
+ ut_dulint_get_high(id), ut_dulint_get_low(id));
+ }
+ break;
+
+ case DATA_CHAR:
+ case DATA_VARCHAR:
+ print_also_hex = FALSE;
+
+ for (i = 0; i < len; i++) {
+ int c = *data++;
+
+ if (!isprint(c)) {
+ print_also_hex = TRUE;
+
+ fprintf(stderr, "\\x%02x", (unsigned char) c);
+ } else {
+ putc(c, stderr);
+ }
+ }
+
+ if (dfield_is_ext(dfield)) {
+ fputs("(external)", stderr);
+ }
+
+ if (!print_also_hex) {
+ break;
+ }
+
+ data = dfield_get_data(dfield);
+ /* fall through */
+
+ case DATA_BINARY:
+ default:
+print_hex:
+ fputs(" Hex: ",stderr);
+
+ for (i = 0; i < len; i++) {
+ fprintf(stderr, "%02lx", (ulint) *data++);
+ }
+
+ if (dfield_is_ext(dfield)) {
+ fputs("(external)", stderr);
+ }
+ }
+}
+
+/*************************************************************//**
+Print a dfield value using ut_print_buf. */
+static
+void
+dfield_print_raw(
+/*=============*/
+ FILE* f, /*!< in: output stream */
+ const dfield_t* dfield) /*!< in: dfield */
+{
+ ulint len = dfield_get_len(dfield);
+ if (!dfield_is_null(dfield)) {
+ ulint print_len = ut_min(len, 1000);
+ ut_print_buf(f, dfield_get_data(dfield), print_len);
+ if (len != print_len) {
+ fprintf(f, "(total %lu bytes%s)",
+ (ulong) len,
+ dfield_is_ext(dfield) ? ", external" : "");
+ }
+ } else {
+ fputs(" SQL NULL", f);
+ }
+}
+
+/**********************************************************//**
+The following function prints the contents of a tuple. */
+UNIV_INTERN
+void
+dtuple_print(
+/*=========*/
+ FILE* f, /*!< in: output stream */
+ const dtuple_t* tuple) /*!< in: tuple */
+{
+ ulint n_fields;
+ ulint i;
+
+ n_fields = dtuple_get_n_fields(tuple);
+
+ fprintf(f, "DATA TUPLE: %lu fields;\n", (ulong) n_fields);
+
+ for (i = 0; i < n_fields; i++) {
+ fprintf(f, " %lu:", (ulong) i);
+
+ dfield_print_raw(f, dtuple_get_nth_field(tuple, i));
+
+ putc(';', f);
+ putc('\n', f);
+ }
+
+ ut_ad(dtuple_validate(tuple));
+}
+
+/**************************************************************//**
+Moves parts of long fields in entry to the big record vector so that
+the size of tuple drops below the maximum record size allowed in the
+database. Moves data only from those fields which are not necessary
+to determine uniquely the insertion place of the tuple in the index.
+@return own: created big record vector, NULL if we are not able to
+shorten the entry enough, i.e., if there are too many fixed-length or
+short fields in entry or the index is clustered */
+UNIV_INTERN
+big_rec_t*
+dtuple_convert_big_rec(
+/*===================*/
+ dict_index_t* index, /*!< in: index */
+ dtuple_t* entry, /*!< in/out: index entry */
+ ulint* n_ext) /*!< in/out: number of
+ externally stored columns */
+{
+ mem_heap_t* heap;
+ big_rec_t* vector;
+ dfield_t* dfield;
+ dict_field_t* ifield;
+ ulint size;
+ ulint n_fields;
+ ulint local_len;
+ ulint local_prefix_len;
+
+ if (UNIV_UNLIKELY(!dict_index_is_clust(index))) {
+ return(NULL);
+ }
+
+ if (dict_table_get_format(index->table) < DICT_TF_FORMAT_ZIP) {
+ /* up to MySQL 5.1: store a 768-byte prefix locally */
+ local_len = BTR_EXTERN_FIELD_REF_SIZE + DICT_MAX_INDEX_COL_LEN;
+ } else {
+ /* new-format table: do not store any BLOB prefix locally */
+ local_len = BTR_EXTERN_FIELD_REF_SIZE;
+ }
+
+ ut_a(dtuple_check_typed_no_assert(entry));
+
+ size = rec_get_converted_size(index, entry, *n_ext);
+
+ if (UNIV_UNLIKELY(size > 1000000000)) {
+ fprintf(stderr,
+ "InnoDB: Warning: tuple size very big: %lu\n",
+ (ulong) size);
+ fputs("InnoDB: Tuple contents: ", stderr);
+ dtuple_print(stderr, entry);
+ putc('\n', stderr);
+ }
+
+ heap = mem_heap_create(size + dtuple_get_n_fields(entry)
+ * sizeof(big_rec_field_t) + 1000);
+
+ vector = mem_heap_alloc(heap, sizeof(big_rec_t));
+
+ vector->heap = heap;
+ vector->fields = mem_heap_alloc(heap, dtuple_get_n_fields(entry)
+ * sizeof(big_rec_field_t));
+
+ /* Decide which fields to shorten: the algorithm is to look for
+ a variable-length field that yields the biggest savings when
+ stored externally */
+
+ n_fields = 0;
+
+ while (page_zip_rec_needs_ext(rec_get_converted_size(index, entry,
+ *n_ext),
+ dict_table_is_comp(index->table),
+ dict_index_get_n_fields(index),
+ dict_table_zip_size(index->table))) {
+ ulint i;
+ ulint longest = 0;
+ ulint longest_i = ULINT_MAX;
+ byte* data;
+ big_rec_field_t* b;
+
+ for (i = dict_index_get_n_unique_in_tree(index);
+ i < dtuple_get_n_fields(entry); i++) {
+ ulint savings;
+
+ dfield = dtuple_get_nth_field(entry, i);
+ ifield = dict_index_get_nth_field(index, i);
+
+ /* Skip fixed-length, NULL, externally stored,
+ or short columns */
+
+ if (ifield->fixed_len
+ || dfield_is_null(dfield)
+ || dfield_is_ext(dfield)
+ || dfield_get_len(dfield) <= local_len
+ || dfield_get_len(dfield)
+ <= BTR_EXTERN_FIELD_REF_SIZE * 2) {
+ goto skip_field;
+ }
+
+ savings = dfield_get_len(dfield) - local_len;
+
+ /* Check that there would be savings */
+ if (longest >= savings) {
+ goto skip_field;
+ }
+
+ longest_i = i;
+ longest = savings;
+
+skip_field:
+ continue;
+ }
+
+ if (!longest) {
+ /* Cannot shorten more */
+
+ mem_heap_free(heap);
+
+ return(NULL);
+ }
+
+ /* Move data from field longest_i to big rec vector.
+
+ We store the first bytes locally to the record. Then
+ we can calculate all ordering fields in all indexes
+ from locally stored data. */
+
+ dfield = dtuple_get_nth_field(entry, longest_i);
+ ifield = dict_index_get_nth_field(index, longest_i);
+ local_prefix_len = local_len - BTR_EXTERN_FIELD_REF_SIZE;
+
+ b = &vector->fields[n_fields];
+ b->field_no = longest_i;
+ b->len = dfield_get_len(dfield) - local_prefix_len;
+ b->data = (char*) dfield_get_data(dfield) + local_prefix_len;
+
+ /* Allocate the locally stored part of the column. */
+ data = mem_heap_alloc(heap, local_len);
+
+ /* Copy the local prefix. */
+ memcpy(data, dfield_get_data(dfield), local_prefix_len);
+ /* Clear the extern field reference (BLOB pointer). */
+ memset(data + local_prefix_len, 0, BTR_EXTERN_FIELD_REF_SIZE);
+#if 0
+ /* The following would fail the Valgrind checks in
+ page_cur_insert_rec_low() and page_cur_insert_rec_zip().
+ The BLOB pointers in the record will be initialized after
+ the record and the BLOBs have been written. */
+ UNIV_MEM_ALLOC(data + local_prefix_len,
+ BTR_EXTERN_FIELD_REF_SIZE);
+#endif
+
+ dfield_set_data(dfield, data, local_len);
+ dfield_set_ext(dfield);
+
+ n_fields++;
+ (*n_ext)++;
+ ut_ad(n_fields < dtuple_get_n_fields(entry));
+ }
+
+ vector->n_fields = n_fields;
+ return(vector);
+}
+
+/**************************************************************//**
+Puts back to entry the data stored in vector. Note that to ensure the
+fields in entry can accommodate the data, vector must have been created
+from entry with dtuple_convert_big_rec. */
+UNIV_INTERN
+void
+dtuple_convert_back_big_rec(
+/*========================*/
+ dict_index_t* index __attribute__((unused)), /*!< in: index */
+ dtuple_t* entry, /*!< in: entry whose data was put to vector */
+ big_rec_t* vector) /*!< in, own: big rec vector; it is
+ freed in this function */
+{
+ big_rec_field_t* b = vector->fields;
+ const big_rec_field_t* const end = b + vector->n_fields;
+
+ for (; b < end; b++) {
+ dfield_t* dfield;
+ ulint local_len;
+
+ dfield = dtuple_get_nth_field(entry, b->field_no);
+ local_len = dfield_get_len(dfield);
+
+ ut_ad(dfield_is_ext(dfield));
+ ut_ad(local_len >= BTR_EXTERN_FIELD_REF_SIZE);
+
+ local_len -= BTR_EXTERN_FIELD_REF_SIZE;
+
+ ut_ad(local_len <= DICT_MAX_INDEX_COL_LEN);
+
+ dfield_set_data(dfield,
+ (char*) b->data - local_len,
+ b->len + local_len);
+ }
+
+ mem_heap_free(vector->heap);
+}
+#endif /* !UNIV_HOTBACKUP */
diff --git a/storage/innobase/data/data0type.c b/storage/innodb_plugin/data/data0type.c
similarity index 65%
rename from storage/innobase/data/data0type.c
rename to storage/innodb_plugin/data/data0type.c
index 305000d7c0a..8429775e7d8 100644
--- a/storage/innobase/data/data0type.c
+++ b/storage/innodb_plugin/data/data0type.c
@@ -1,7 +1,24 @@
-/******************************************************
-Data types
+/*****************************************************************************
-(c) 1996 Innobase Oy
+Copyright (c) 1996, 2009, Innobase Oy. All Rights Reserved.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; version 2 of the License.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place, Suite 330, Boston, MA 02111-1307 USA
+
+*****************************************************************************/
+
+/**************************************************//**
+@file data/data0type.c
+Data types
Created 1/16/1996 Heikki Tuuri
*******************************************************/
@@ -12,57 +29,37 @@ Created 1/16/1996 Heikki Tuuri
#include "data0type.ic"
#endif
-/**********************************************************************
-This function is used to find the storage length in bytes of the first n
-characters for prefix indexes using a multibyte character set. The function
-finds charset information and returns length of prefix_len characters in the
-index field in bytes.
-
-NOTE: the prototype of this function is copied from ha_innodb.cc! If you change
-this function, you MUST change also the prototype here! */
-
-ulint
-innobase_get_at_most_n_mbchars(
-/*===========================*/
- /* out: number of bytes occupied by the first
- n characters */
- ulint charset_id, /* in: character set id */
- ulint prefix_len, /* in: prefix length in bytes of the index
- (this has to be divided by mbmaxlen to get the
- number of CHARACTERS n in the prefix) */
- ulint data_len, /* in: length of the string in bytes */
- const char* str); /* in: character string */
+#ifndef UNIV_HOTBACKUP
+# include "ha_prototypes.h"
/* At the database startup we store the default-charset collation number of
this MySQL installation to this global variable. If we have < 4.1.2 format
column definitions, or records in the insert buffer, we use this
charset-collation code for them. */
-ulint data_mysql_default_charset_coll = 99999999;
+UNIV_INTERN ulint data_mysql_default_charset_coll;
-/*************************************************************************
+/*********************************************************************//**
Determine how many bytes the first n characters of the given string occupy.
If the string is shorter than n characters, returns the number of bytes
-the characters in the string occupy. */
-
+the characters in the string occupy.
+@return length of the prefix, in bytes */
+UNIV_INTERN
ulint
dtype_get_at_most_n_mbchars(
/*========================*/
- /* out: length of the prefix,
- in bytes */
- ulint prtype, /* in: precise type */
- ulint mbminlen, /* in: minimum length of a
+ ulint prtype, /*!< in: precise type */
+ ulint mbminlen, /*!< in: minimum length of a
multi-byte character */
- ulint mbmaxlen, /* in: maximum length of a
+ ulint mbmaxlen, /*!< in: maximum length of a
multi-byte character */
- ulint prefix_len, /* in: length of the requested
+ ulint prefix_len, /*!< in: length of the requested
prefix, in characters, multiplied by
dtype_get_mbmaxlen(dtype) */
- ulint data_len, /* in: length of str (in bytes) */
- const char* str) /* in: the string whose prefix
+ ulint data_len, /*!< in: length of str (in bytes) */
+ const char* str) /*!< in: the string whose prefix
length is being determined */
{
-#ifndef UNIV_HOTBACKUP
ut_a(data_len != UNIV_SQL_NULL);
ut_ad(!mbmaxlen || !(prefix_len % mbmaxlen));
@@ -80,23 +77,18 @@ dtype_get_at_most_n_mbchars(
}
return(data_len);
-#else /* UNIV_HOTBACKUP */
- /* This function depends on MySQL code that is not included in
- InnoDB Hot Backup builds. Besides, this function should never
- be called in InnoDB Hot Backup. */
- ut_error;
-#endif /* UNIV_HOTBACKUP */
}
+#endif /* UNIV_HOTBACKUP */
-/*************************************************************************
+/*********************************************************************//**
Checks if a data main type is a string type. Also a BLOB is considered a
-string type. */
-
+string type.
+@return TRUE if string type */
+UNIV_INTERN
ibool
dtype_is_string_type(
/*=================*/
- /* out: TRUE if string type */
- ulint mtype) /* in: InnoDB main data type code: DATA_CHAR, ... */
+ ulint mtype) /*!< in: InnoDB main data type code: DATA_CHAR, ... */
{
if (mtype <= DATA_BLOB
|| mtype == DATA_MYSQL
@@ -108,17 +100,17 @@ dtype_is_string_type(
return(FALSE);
}
-/*************************************************************************
+/*********************************************************************//**
Checks if a type is a binary string type. Note that for tables created with
< 4.0.14, we do not know if a DATA_BLOB column is a BLOB or a TEXT column. For
-those DATA_BLOB columns this function currently returns FALSE. */
-
+those DATA_BLOB columns this function currently returns FALSE.
+@return TRUE if binary string type */
+UNIV_INTERN
ibool
dtype_is_binary_string_type(
/*========================*/
- /* out: TRUE if binary string type */
- ulint mtype, /* in: main data type */
- ulint prtype) /* in: precise type */
+ ulint mtype, /*!< in: main data type */
+ ulint prtype) /*!< in: precise type */
{
if ((mtype == DATA_FIXBINARY)
|| (mtype == DATA_BINARY)
@@ -130,18 +122,18 @@ dtype_is_binary_string_type(
return(FALSE);
}
-/*************************************************************************
+/*********************************************************************//**
Checks if a type is a non-binary string type. That is, dtype_is_string_type is
TRUE and dtype_is_binary_string_type is FALSE. Note that for tables created
with < 4.0.14, we do not know if a DATA_BLOB column is a BLOB or a TEXT column.
-For those DATA_BLOB columns this function currently returns TRUE. */
-
+For those DATA_BLOB columns this function currently returns TRUE.
+@return TRUE if non-binary string type */
+UNIV_INTERN
ibool
dtype_is_non_binary_string_type(
/*============================*/
- /* out: TRUE if non-binary string type */
- ulint mtype, /* in: main data type */
- ulint prtype) /* in: precise type */
+ ulint mtype, /*!< in: main data type */
+ ulint prtype) /*!< in: precise type */
{
if (dtype_is_string_type(mtype) == TRUE
&& dtype_is_binary_string_type(mtype, prtype) == FALSE) {
@@ -152,27 +144,17 @@ dtype_is_non_binary_string_type(
return(FALSE);
}
-/*************************************************************************
-Gets the MySQL charset-collation code for MySQL string types. */
-
-ulint
-dtype_get_charset_coll_noninline(
-/*=============================*/
- ulint prtype) /* in: precise data type */
-{
- return(dtype_get_charset_coll(prtype));
-}
-
-/*************************************************************************
+/*********************************************************************//**
Forms a precise type from the < 4.1.2 format precise type plus the
-charset-collation code. */
-
+charset-collation code.
+@return precise type, including the charset-collation code */
+UNIV_INTERN
ulint
dtype_form_prtype(
/*==============*/
- ulint old_prtype, /* in: the MySQL type code and the flags
+ ulint old_prtype, /*!< in: the MySQL type code and the flags
DATA_BINARY_TYPE etc. */
- ulint charset_coll) /* in: MySQL charset-collation code */
+ ulint charset_coll) /*!< in: MySQL charset-collation code */
{
ut_a(old_prtype < 256 * 256);
ut_a(charset_coll < 256);
@@ -180,14 +162,14 @@ dtype_form_prtype(
return(old_prtype + (charset_coll << 16));
}
-/*************************************************************************
-Validates a data type structure. */
-
+/*********************************************************************//**
+Validates a data type structure.
+@return TRUE if ok */
+UNIV_INTERN
ibool
dtype_validate(
/*===========*/
- /* out: TRUE if ok */
- dtype_t* type) /* in: type struct to validate */
+ const dtype_t* type) /*!< in: type struct to validate */
{
ut_a(type);
ut_a(type->mtype >= DATA_VARCHAR);
@@ -197,18 +179,21 @@ dtype_validate(
ut_a((type->prtype & DATA_MYSQL_TYPE_MASK) < DATA_N_SYS_COLS);
}
+#ifndef UNIV_HOTBACKUP
ut_a(type->mbminlen <= type->mbmaxlen);
+#endif /* !UNIV_HOTBACKUP */
return(TRUE);
}
-/*************************************************************************
+#ifndef UNIV_HOTBACKUP
+/*********************************************************************//**
Prints a data type structure. */
-
+UNIV_INTERN
void
dtype_print(
/*========*/
- dtype_t* type) /* in: type */
+ const dtype_t* type) /*!< in: type */
{
ulint mtype;
ulint prtype;
@@ -293,3 +278,4 @@ dtype_print(
fprintf(stderr, " len %lu", (ulong) len);
}
+#endif /* !UNIV_HOTBACKUP */
diff --git a/storage/innobase/dict/dict0boot.c b/storage/innodb_plugin/dict/dict0boot.c
similarity index 75%
rename from storage/innobase/dict/dict0boot.c
rename to storage/innodb_plugin/dict/dict0boot.c
index 5f9aaf71e18..e55de30481b 100644
--- a/storage/innobase/dict/dict0boot.c
+++ b/storage/innodb_plugin/dict/dict0boot.c
@@ -1,7 +1,24 @@
-/******************************************************
-Data dictionary creation and booting
+/*****************************************************************************
-(c) 1996 Innobase Oy
+Copyright (c) 1996, 2009, Innobase Oy. All Rights Reserved.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; version 2 of the License.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place, Suite 330, Boston, MA 02111-1307 USA
+
+*****************************************************************************/
+
+/**************************************************//**
+@file dict/dict0boot.c
+Data dictionary creation and booting
Created 4/18/1996 Heikki Tuuri
*******************************************************/
@@ -23,36 +40,35 @@ Created 4/18/1996 Heikki Tuuri
#include "log0recv.h"
#include "os0file.h"
-/**************************************************************************
-Gets a pointer to the dictionary header and x-latches its page. */
-
+/**********************************************************************//**
+Gets a pointer to the dictionary header and x-latches its page.
+@return pointer to the dictionary header, page x-latched */
+UNIV_INTERN
dict_hdr_t*
dict_hdr_get(
/*=========*/
- /* out: pointer to the dictionary header,
- page x-latched */
- mtr_t* mtr) /* in: mtr */
+ mtr_t* mtr) /*!< in: mtr */
{
+ buf_block_t* block;
dict_hdr_t* header;
- ut_ad(mtr);
+ block = buf_page_get(DICT_HDR_SPACE, 0, DICT_HDR_PAGE_NO,
+ RW_X_LATCH, mtr);
+ header = DICT_HDR + buf_block_get_frame(block);
+
+ buf_block_dbg_add_level(block, SYNC_DICT_HEADER);
- header = DICT_HDR + buf_page_get(DICT_HDR_SPACE, DICT_HDR_PAGE_NO,
- RW_X_LATCH, mtr);
-#ifdef UNIV_SYNC_DEBUG
- buf_page_dbg_add_level(header, SYNC_DICT_HEADER);
-#endif /* UNIV_SYNC_DEBUG */
return(header);
}
-/**************************************************************************
-Returns a new table, index, or tree id. */
-
+/**********************************************************************//**
+Returns a new table, index, or tree id.
+@return the new id */
+UNIV_INTERN
dulint
dict_hdr_get_new_id(
/*================*/
- /* out: the new id */
- ulint type) /* in: DICT_HDR_ROW_ID, ... */
+ ulint type) /*!< in: DICT_HDR_ROW_ID, ... */
{
dict_hdr_t* dict_hdr;
dulint id;
@@ -74,10 +90,10 @@ dict_hdr_get_new_id(
return(id);
}
-/**************************************************************************
+/**********************************************************************//**
Writes the current value of the row id counter to the dictionary header file
page. */
-
+UNIV_INTERN
void
dict_hdr_flush_row_id(void)
/*=======================*/
@@ -99,31 +115,28 @@ dict_hdr_flush_row_id(void)
mtr_commit(&mtr);
}
-/*********************************************************************
+/*****************************************************************//**
Creates the file page for the dictionary header. This function is
-called only at the database creation. */
+called only at the database creation.
+@return TRUE if succeed */
static
ibool
dict_hdr_create(
/*============*/
- /* out: TRUE if succeed */
- mtr_t* mtr) /* in: mtr */
+ mtr_t* mtr) /*!< in: mtr */
{
+ buf_block_t* block;
dict_hdr_t* dict_header;
- ulint hdr_page_no;
ulint root_page_no;
- page_t* page;
ut_ad(mtr);
/* Create the dictionary header file block in a new, allocated file
segment in the system tablespace */
- page = fseg_create(DICT_HDR_SPACE, 0,
- DICT_HDR + DICT_HDR_FSEG_HEADER, mtr);
+ block = fseg_create(DICT_HDR_SPACE, 0,
+ DICT_HDR + DICT_HDR_FSEG_HEADER, mtr);
- hdr_page_no = buf_frame_get_page_no(page);
-
- ut_a(DICT_HDR_PAGE_NO == hdr_page_no);
+ ut_a(DICT_HDR_PAGE_NO == buf_block_get_page_no(block));
dict_header = dict_hdr_get(mtr);
@@ -147,7 +160,8 @@ dict_hdr_create(
/*--------------------------*/
root_page_no = btr_create(DICT_CLUSTERED | DICT_UNIQUE,
- DICT_HDR_SPACE, DICT_TABLES_ID, FALSE, mtr);
+ DICT_HDR_SPACE, 0, DICT_TABLES_ID,
+ dict_ind_redundant, mtr);
if (root_page_no == FIL_NULL) {
return(FALSE);
@@ -156,8 +170,9 @@ dict_hdr_create(
mlog_write_ulint(dict_header + DICT_HDR_TABLES, root_page_no,
MLOG_4BYTES, mtr);
/*--------------------------*/
- root_page_no = btr_create(DICT_UNIQUE, DICT_HDR_SPACE,
- DICT_TABLE_IDS_ID, FALSE, mtr);
+ root_page_no = btr_create(DICT_UNIQUE, DICT_HDR_SPACE, 0,
+ DICT_TABLE_IDS_ID,
+ dict_ind_redundant, mtr);
if (root_page_no == FIL_NULL) {
return(FALSE);
@@ -167,7 +182,8 @@ dict_hdr_create(
MLOG_4BYTES, mtr);
/*--------------------------*/
root_page_no = btr_create(DICT_CLUSTERED | DICT_UNIQUE,
- DICT_HDR_SPACE, DICT_COLUMNS_ID, FALSE, mtr);
+ DICT_HDR_SPACE, 0, DICT_COLUMNS_ID,
+ dict_ind_redundant, mtr);
if (root_page_no == FIL_NULL) {
return(FALSE);
@@ -177,7 +193,8 @@ dict_hdr_create(
MLOG_4BYTES, mtr);
/*--------------------------*/
root_page_no = btr_create(DICT_CLUSTERED | DICT_UNIQUE,
- DICT_HDR_SPACE, DICT_INDEXES_ID, FALSE, mtr);
+ DICT_HDR_SPACE, 0, DICT_INDEXES_ID,
+ dict_ind_redundant, mtr);
if (root_page_no == FIL_NULL) {
return(FALSE);
@@ -187,7 +204,8 @@ dict_hdr_create(
MLOG_4BYTES, mtr);
/*--------------------------*/
root_page_no = btr_create(DICT_CLUSTERED | DICT_UNIQUE,
- DICT_HDR_SPACE, DICT_FIELDS_ID, FALSE, mtr);
+ DICT_HDR_SPACE, 0, DICT_FIELDS_ID,
+ dict_ind_redundant, mtr);
if (root_page_no == FIL_NULL) {
return(FALSE);
@@ -200,10 +218,10 @@ dict_hdr_create(
return(TRUE);
}
-/*********************************************************************
+/*****************************************************************//**
Initializes the data dictionary memory structures when the database is
started. This function is also called when the data dictionary is created. */
-
+UNIV_INTERN
void
dict_boot(void)
/*===========*/
@@ -213,6 +231,7 @@ dict_boot(void)
dict_hdr_t* dict_hdr;
mem_heap_t* heap;
mtr_t mtr;
+ ulint error;
mtr_start(&mtr);
@@ -249,7 +268,10 @@ dict_boot(void)
dict_mem_table_add_col(table, heap, "NAME", DATA_BINARY, 0, 0);
dict_mem_table_add_col(table, heap, "ID", DATA_BINARY, 0, 0);
+ /* ROW_FORMAT = (N_COLS >> 31) ? COMPACT : REDUNDANT */
dict_mem_table_add_col(table, heap, "N_COLS", DATA_INT, 0, 4);
+ /* TYPE is either DICT_TABLE_ORDINARY, or (TYPE & DICT_TF_COMPACT)
+ and (TYPE & DICT_TF_FORMAT_MASK) are nonzero and TYPE = table->flags */
dict_mem_table_add_col(table, heap, "TYPE", DATA_INT, 0, 4);
dict_mem_table_add_col(table, heap, "MIX_ID", DATA_BINARY, 0, 0);
dict_mem_table_add_col(table, heap, "MIX_LEN", DATA_INT, 0, 4);
@@ -270,9 +292,12 @@ dict_boot(void)
index->id = DICT_TABLES_ID;
- dict_index_add_to_cache(table, index,
- mtr_read_ulint(dict_hdr + DICT_HDR_TABLES,
- MLOG_4BYTES, &mtr));
+ error = dict_index_add_to_cache(table, index,
+ mtr_read_ulint(dict_hdr
+ + DICT_HDR_TABLES,
+ MLOG_4BYTES, &mtr),
+ FALSE);
+ ut_a(error == DB_SUCCESS);
/*-------------------------*/
index = dict_mem_index_create("SYS_TABLES", "ID_IND",
@@ -280,9 +305,12 @@ dict_boot(void)
dict_mem_index_add_field(index, "ID", 0);
index->id = DICT_TABLE_IDS_ID;
- dict_index_add_to_cache(table, index,
- mtr_read_ulint(dict_hdr + DICT_HDR_TABLE_IDS,
- MLOG_4BYTES, &mtr));
+ error = dict_index_add_to_cache(table, index,
+ mtr_read_ulint(dict_hdr
+ + DICT_HDR_TABLE_IDS,
+ MLOG_4BYTES, &mtr),
+ FALSE);
+ ut_a(error == DB_SUCCESS);
/*-------------------------*/
table = dict_mem_table_create("SYS_COLUMNS", DICT_HDR_SPACE, 7, 0);
@@ -309,9 +337,12 @@ dict_boot(void)
dict_mem_index_add_field(index, "POS", 0);
index->id = DICT_COLUMNS_ID;
- dict_index_add_to_cache(table, index,
- mtr_read_ulint(dict_hdr + DICT_HDR_COLUMNS,
- MLOG_4BYTES, &mtr));
+ error = dict_index_add_to_cache(table, index,
+ mtr_read_ulint(dict_hdr
+ + DICT_HDR_COLUMNS,
+ MLOG_4BYTES, &mtr),
+ FALSE);
+ ut_a(error == DB_SUCCESS);
/*-------------------------*/
table = dict_mem_table_create("SYS_INDEXES", DICT_HDR_SPACE, 7, 0);
@@ -348,9 +379,12 @@ dict_boot(void)
dict_mem_index_add_field(index, "ID", 0);
index->id = DICT_INDEXES_ID;
- dict_index_add_to_cache(table, index,
- mtr_read_ulint(dict_hdr + DICT_HDR_INDEXES,
- MLOG_4BYTES, &mtr));
+ error = dict_index_add_to_cache(table, index,
+ mtr_read_ulint(dict_hdr
+ + DICT_HDR_INDEXES,
+ MLOG_4BYTES, &mtr),
+ FALSE);
+ ut_a(error == DB_SUCCESS);
/*-------------------------*/
table = dict_mem_table_create("SYS_FIELDS", DICT_HDR_SPACE, 3, 0);
@@ -372,9 +406,12 @@ dict_boot(void)
dict_mem_index_add_field(index, "POS", 0);
index->id = DICT_FIELDS_ID;
- dict_index_add_to_cache(table, index,
- mtr_read_ulint(dict_hdr + DICT_HDR_FIELDS,
- MLOG_4BYTES, &mtr));
+ error = dict_index_add_to_cache(table, index,
+ mtr_read_ulint(dict_hdr
+ + DICT_HDR_FIELDS,
+ MLOG_4BYTES, &mtr),
+ FALSE);
+ ut_a(error == DB_SUCCESS);
mtr_commit(&mtr);
/*-------------------------*/
@@ -393,7 +430,7 @@ dict_boot(void)
mutex_exit(&(dict_sys->mutex));
}
-/*********************************************************************
+/*****************************************************************//**
Inserts the basic system table data into themselves in the database
creation. */
static
@@ -404,9 +441,9 @@ dict_insert_initial_data(void)
/* Does nothing yet */
}
-/*********************************************************************
+/*****************************************************************//**
Creates and initializes the data dictionary at the database creation. */
-
+UNIV_INTERN
void
dict_create(void)
/*=============*/
diff --git a/storage/innobase/dict/dict0crea.c b/storage/innodb_plugin/dict/dict0crea.c
similarity index 79%
rename from storage/innobase/dict/dict0crea.c
rename to storage/innodb_plugin/dict/dict0crea.c
index 4116230347d..7bad4d2057e 100644
--- a/storage/innobase/dict/dict0crea.c
+++ b/storage/innodb_plugin/dict/dict0crea.c
@@ -1,7 +1,24 @@
-/******************************************************
-Database object creation
+/*****************************************************************************
-(c) 1996 Innobase Oy
+Copyright (c) 1996, 2009, Innobase Oy. All Rights Reserved.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; version 2 of the License.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place, Suite 330, Boston, MA 02111-1307 USA
+
+*****************************************************************************/
+
+/**************************************************//**
+@file dict/dict0crea.c
+Database object creation
Created 1/8/1996 Heikki Tuuri
*******************************************************/
@@ -26,16 +43,16 @@ Created 1/8/1996 Heikki Tuuri
#include "usr0sess.h"
#include "ut0vec.h"
-/*********************************************************************
+/*****************************************************************//**
Based on a table object, this function builds the entry to be inserted
-in the SYS_TABLES system table. */
+in the SYS_TABLES system table.
+@return the tuple which should be inserted */
static
dtuple_t*
dict_create_sys_tables_tuple(
/*=========================*/
- /* out: the tuple which should be inserted */
- dict_table_t* table, /* in: table */
- mem_heap_t* heap) /* in: memory heap from which the memory for
+ dict_table_t* table, /*!< in: table */
+ mem_heap_t* heap) /*!< in: memory heap from which the memory for
the built tuple is allocated */
{
dict_table_t* sys_tables;
@@ -49,6 +66,8 @@ dict_create_sys_tables_tuple(
entry = dtuple_create(heap, 8 + DATA_N_SYS_COLS);
+ dict_table_copy_types(entry, sys_tables);
+
/* 0: NAME -----------------------------*/
dfield = dtuple_get_nth_field(entry, 0);
@@ -75,27 +94,34 @@ dict_create_sys_tables_tuple(
dfield = dtuple_get_nth_field(entry, 3);
ptr = mem_heap_alloc(heap, 4);
- mach_write_to_4(ptr, DICT_TABLE_ORDINARY);
+ if (table->flags & ~DICT_TF_COMPACT) {
+ ut_a(table->flags & DICT_TF_COMPACT);
+ ut_a(dict_table_get_format(table) >= DICT_TF_FORMAT_ZIP);
+ ut_a((table->flags & DICT_TF_ZSSIZE_MASK)
+ <= (DICT_TF_ZSSIZE_MAX << DICT_TF_ZSSIZE_SHIFT));
+ ut_a(!(table->flags & (~0 << DICT_TF_BITS)));
+ mach_write_to_4(ptr, table->flags);
+ } else {
+ mach_write_to_4(ptr, DICT_TABLE_ORDINARY);
+ }
dfield_set_data(dfield, ptr, 4);
/* 6: MIX_ID (obsolete) ---------------------------*/
dfield = dtuple_get_nth_field(entry, 4);
- ptr = mem_heap_alloc(heap, 8);
- memset(ptr, 0, 8);
+ ptr = mem_heap_zalloc(heap, 8);
dfield_set_data(dfield, ptr, 8);
/* 7: MIX_LEN (obsolete) --------------------------*/
dfield = dtuple_get_nth_field(entry, 5);
- ptr = mem_heap_alloc(heap, 4);
- memset(ptr, 0, 4);
+ ptr = mem_heap_zalloc(heap, 4);
dfield_set_data(dfield, ptr, 4);
/* 8: CLUSTER_NAME ---------------------*/
dfield = dtuple_get_nth_field(entry, 6);
- dfield_set_data(dfield, NULL, UNIV_SQL_NULL); /* not supported */
+ dfield_set_null(dfield); /* not supported */
/* 9: SPACE ----------------------------*/
dfield = dtuple_get_nth_field(entry, 7);
@@ -106,22 +132,20 @@ dict_create_sys_tables_tuple(
dfield_set_data(dfield, ptr, 4);
/*----------------------------------*/
- dict_table_copy_types(entry, sys_tables);
-
return(entry);
}
-/*********************************************************************
+/*****************************************************************//**
Based on a table object, this function builds the entry to be inserted
-in the SYS_COLUMNS system table. */
+in the SYS_COLUMNS system table.
+@return the tuple which should be inserted */
static
dtuple_t*
dict_create_sys_columns_tuple(
/*==========================*/
- /* out: the tuple which should be inserted */
- dict_table_t* table, /* in: table */
- ulint i, /* in: column number */
- mem_heap_t* heap) /* in: memory heap from which the memory for
+ dict_table_t* table, /*!< in: table */
+ ulint i, /*!< in: column number */
+ mem_heap_t* heap) /*!< in: memory heap from which the memory for
the built tuple is allocated */
{
dict_table_t* sys_columns;
@@ -139,6 +163,8 @@ dict_create_sys_columns_tuple(
entry = dtuple_create(heap, 7 + DATA_N_SYS_COLS);
+ dict_table_copy_types(entry, sys_columns);
+
/* 0: TABLE_ID -----------------------*/
dfield = dtuple_get_nth_field(entry, 0);
@@ -188,20 +214,18 @@ dict_create_sys_columns_tuple(
dfield_set_data(dfield, ptr, 4);
/*---------------------------------*/
- dict_table_copy_types(entry, sys_columns);
-
return(entry);
}
-/*******************************************************************
-Builds a table definition to insert. */
+/***************************************************************//**
+Builds a table definition to insert.
+@return DB_SUCCESS or error code */
static
ulint
dict_build_table_def_step(
/*======================*/
- /* out: DB_SUCCESS or error code */
- que_thr_t* thr, /* in: query thread */
- tab_node_t* node) /* in: table create node */
+ que_thr_t* thr, /*!< in: query thread */
+ tab_node_t* node) /*!< in: table create node */
{
dict_table_t* table;
dtuple_t* row;
@@ -209,8 +233,6 @@ dict_build_table_def_step(
const char* path_or_name;
ibool is_path;
mtr_t mtr;
- ulint i;
- ulint row_len;
ut_ad(mutex_own(&(dict_sys->mutex)));
@@ -220,14 +242,6 @@ dict_build_table_def_step(
thr_get_trx(thr)->table_id = table->id;
- row_len = 0;
- for (i = 0; i < table->n_def; i++) {
- row_len += dict_col_get_min_size(&table->cols[i]);
- }
- if (row_len > BTR_PAGE_MAX_REC_SIZE) {
- return(DB_TOO_BIG_RECORD);
- }
-
if (srv_file_per_table) {
/* We create a new single-table tablespace for the table.
We initially let it be 4 pages:
@@ -250,8 +264,13 @@ dict_build_table_def_step(
is_path = FALSE;
}
+ ut_ad(dict_table_get_format(table) <= DICT_TF_FORMAT_MAX);
+ ut_ad(!dict_table_zip_size(table)
+ || dict_table_get_format(table) >= DICT_TF_FORMAT_ZIP);
+
error = fil_create_new_single_table_tablespace(
&space, path_or_name, is_path,
+ table->flags == DICT_TF_COMPACT ? 0 : table->flags,
FIL_IBD_FILE_INITIAL_SIZE);
table->space = (unsigned int) space;
@@ -265,6 +284,9 @@ dict_build_table_def_step(
fsp_header_init(table->space, FIL_IBD_FILE_INITIAL_SIZE, &mtr);
mtr_commit(&mtr);
+ } else {
+ /* Create in the system tablespace: disallow new features */
+ table->flags &= DICT_TF_COMPACT;
}
row = dict_create_sys_tables_tuple(table, node->heap);
@@ -274,14 +296,14 @@ dict_build_table_def_step(
return(DB_SUCCESS);
}
-/*******************************************************************
-Builds a column definition to insert. */
+/***************************************************************//**
+Builds a column definition to insert.
+@return DB_SUCCESS */
static
ulint
dict_build_col_def_step(
/*====================*/
- /* out: DB_SUCCESS */
- tab_node_t* node) /* in: table create node */
+ tab_node_t* node) /*!< in: table create node */
{
dtuple_t* row;
@@ -292,16 +314,16 @@ dict_build_col_def_step(
return(DB_SUCCESS);
}
-/*********************************************************************
+/*****************************************************************//**
Based on an index object, this function builds the entry to be inserted
-in the SYS_INDEXES system table. */
+in the SYS_INDEXES system table.
+@return the tuple which should be inserted */
static
dtuple_t*
dict_create_sys_indexes_tuple(
/*==========================*/
- /* out: the tuple which should be inserted */
- dict_index_t* index, /* in: index */
- mem_heap_t* heap) /* in: memory heap from which the memory for
+ dict_index_t* index, /*!< in: index */
+ mem_heap_t* heap) /*!< in: memory heap from which the memory for
the built tuple is allocated */
{
dict_table_t* sys_indexes;
@@ -319,6 +341,8 @@ dict_create_sys_indexes_tuple(
entry = dtuple_create(heap, 7 + DATA_N_SYS_COLS);
+ dict_table_copy_types(entry, sys_indexes);
+
/* 0: TABLE_ID -----------------------*/
dfield = dtuple_get_nth_field(entry, 0);
@@ -377,22 +401,20 @@ dict_create_sys_indexes_tuple(
dfield_set_data(dfield, ptr, 4);
/*--------------------------------*/
- dict_table_copy_types(entry, sys_indexes);
-
return(entry);
}
-/*********************************************************************
+/*****************************************************************//**
Based on an index object, this function builds the entry to be inserted
-in the SYS_FIELDS system table. */
+in the SYS_FIELDS system table.
+@return the tuple which should be inserted */
static
dtuple_t*
dict_create_sys_fields_tuple(
/*=========================*/
- /* out: the tuple which should be inserted */
- dict_index_t* index, /* in: index */
- ulint i, /* in: field number */
- mem_heap_t* heap) /* in: memory heap from which the memory for
+ dict_index_t* index, /*!< in: index */
+ ulint i, /*!< in: field number */
+ mem_heap_t* heap) /*!< in: memory heap from which the memory for
the built tuple is allocated */
{
dict_table_t* sys_fields;
@@ -408,6 +430,7 @@ dict_create_sys_fields_tuple(
for (j = 0; j < index->n_fields; j++) {
if (dict_index_get_nth_field(index, j)->prefix_len > 0) {
index_contains_column_prefix_field = TRUE;
+ break;
}
}
@@ -417,6 +440,8 @@ dict_create_sys_fields_tuple(
entry = dtuple_create(heap, 3 + DATA_N_SYS_COLS);
+ dict_table_copy_types(entry, sys_fields);
+
/* 0: INDEX_ID -----------------------*/
dfield = dtuple_get_nth_field(entry, 0);
@@ -452,26 +477,24 @@ dict_create_sys_fields_tuple(
ut_strlen(field->name));
/*---------------------------------*/
- dict_table_copy_types(entry, sys_fields);
-
return(entry);
}
-/*********************************************************************
+/*****************************************************************//**
Creates the tuple with which the index entry is searched for writing the index
-tree root page number, if such a tree is created. */
+tree root page number, if such a tree is created.
+@return the tuple for search */
static
dtuple_t*
dict_create_search_tuple(
/*=====================*/
- /* out: the tuple for search */
- dtuple_t* tuple, /* in: the tuple inserted in the SYS_INDEXES
+ const dtuple_t* tuple, /*!< in: the tuple inserted in the SYS_INDEXES
table */
- mem_heap_t* heap) /* in: memory heap from which the memory for
+ mem_heap_t* heap) /*!< in: memory heap from which the memory for
the built tuple is allocated */
{
dtuple_t* search_tuple;
- dfield_t* field1;
+ const dfield_t* field1;
dfield_t* field2;
ut_ad(tuple && heap);
@@ -493,15 +516,15 @@ dict_create_search_tuple(
return(search_tuple);
}
-/*******************************************************************
-Builds an index definition row to insert. */
+/***************************************************************//**
+Builds an index definition row to insert.
+@return DB_SUCCESS or error code */
static
ulint
dict_build_index_def_step(
/*======================*/
- /* out: DB_SUCCESS or error code */
- que_thr_t* thr, /* in: query thread */
- ind_node_t* node) /* in: index create node */
+ que_thr_t* thr, /*!< in: query thread */
+ ind_node_t* node) /*!< in: index create node */
{
dict_table_t* table;
dict_index_t* index;
@@ -525,7 +548,7 @@ dict_build_index_def_step(
node->table = table;
ut_ad((UT_LIST_GET_LEN(table->indexes) > 0)
- || (index->type & DICT_CLUSTERED));
+ || dict_index_is_clust(index));
index->id = dict_hdr_get_new_id(DICT_HDR_INDEX_ID);
@@ -539,17 +562,20 @@ dict_build_index_def_step(
ins_node_set_new_row(node->ind_def, row);
+ /* Note that the index was created by this transaction. */
+ index->trx_id = (ib_uint64_t) ut_conv_dulint_to_longlong(trx->id);
+
return(DB_SUCCESS);
}
-/*******************************************************************
-Builds a field definition row to insert. */
+/***************************************************************//**
+Builds a field definition row to insert.
+@return DB_SUCCESS */
static
ulint
dict_build_field_def_step(
/*======================*/
- /* out: DB_SUCCESS */
- ind_node_t* node) /* in: index create node */
+ ind_node_t* node) /*!< in: index create node */
{
dict_index_t* index;
dtuple_t* row;
@@ -563,14 +589,14 @@ dict_build_field_def_step(
return(DB_SUCCESS);
}
-/*******************************************************************
-Creates an index tree for the index if it is not a member of a cluster. */
+/***************************************************************//**
+Creates an index tree for the index if it is not a member of a cluster.
+@return DB_SUCCESS or DB_OUT_OF_FILE_SPACE */
static
ulint
dict_create_index_tree_step(
/*========================*/
- /* out: DB_SUCCESS or DB_OUT_OF_FILE_SPACE */
- ind_node_t* node) /* in: index create node */
+ ind_node_t* node) /*!< in: index create node */
{
dict_index_t* index;
dict_table_t* sys_indexes;
@@ -600,8 +626,9 @@ dict_create_index_tree_step(
btr_pcur_move_to_next_user_rec(&pcur, &mtr);
- node->page_no = btr_create(index->type, index->space, index->id,
- dict_table_is_comp(table), &mtr);
+ node->page_no = btr_create(index->type, index->space,
+ dict_table_zip_size(index->table),
+ index->id, index, &mtr);
/* printf("Created a new index tree in space %lu root page %lu\n",
index->space, index->page_no); */
@@ -619,20 +646,21 @@ dict_create_index_tree_step(
return(DB_SUCCESS);
}
-/***********************************************************************
+/*******************************************************************//**
Drops the index tree associated with a row in SYS_INDEXES table. */
-
+UNIV_INTERN
void
dict_drop_index_tree(
/*=================*/
- rec_t* rec, /* in: record in the clustered index of SYS_INDEXES
- table */
- mtr_t* mtr) /* in: mtr having the latch on the record page */
+ rec_t* rec, /*!< in/out: record in the clustered index
+ of SYS_INDEXES table */
+ mtr_t* mtr) /*!< in: mtr having the latch on the record page */
{
- ulint root_page_no;
- ulint space;
- byte* ptr;
- ulint len;
+ ulint root_page_no;
+ ulint space;
+ ulint zip_size;
+ const byte* ptr;
+ ulint len;
ut_ad(mutex_own(&(dict_sys->mutex)));
ut_a(!dict_table_is_comp(dict_sys->sys_indexes));
@@ -654,8 +682,9 @@ dict_drop_index_tree(
ut_ad(len == 4);
space = mtr_read_ulint(ptr, MLOG_4BYTES, mtr);
+ zip_size = fil_space_get_zip_size(space);
- if (!fil_tablespace_exists_in_mem(space)) {
+ if (UNIV_UNLIKELY(zip_size == ULINT_UNDEFINED)) {
/* It is a single table tablespace and the .ibd file is
missing: do nothing */
@@ -665,7 +694,7 @@ dict_drop_index_tree(
/* We free all the pages but the root page first; this operation
may span several mini-transactions */
- btr_free_but_not_root(space, root_page_no);
+ btr_free_but_not_root(space, zip_size, root_page_no);
/* Then we free the root page in the same mini-transaction where
we write FIL_NULL to the appropriate field in the SYS_INDEXES
@@ -673,38 +702,40 @@ dict_drop_index_tree(
/* printf("Dropping index tree in space %lu root page %lu\n", space,
root_page_no); */
- btr_free_root(space, root_page_no, mtr);
+ btr_free_root(space, zip_size, root_page_no, mtr);
page_rec_write_index_page_no(rec,
DICT_SYS_INDEXES_PAGE_NO_FIELD,
FIL_NULL, mtr);
}
-/***********************************************************************
-Truncates the index tree associated with a row in SYS_INDEXES table. */
-
+/*******************************************************************//**
+Truncates the index tree associated with a row in SYS_INDEXES table.
+@return new root page number, or FIL_NULL on failure */
+UNIV_INTERN
ulint
dict_truncate_index_tree(
/*=====================*/
- /* out: new root page number, or
- FIL_NULL on failure */
- dict_table_t* table, /* in: the table the index belongs to */
- btr_pcur_t* pcur, /* in/out: persistent cursor pointing to
+ dict_table_t* table, /*!< in: the table the index belongs to */
+ ulint space, /*!< in: 0=truncate,
+ nonzero=create the index tree in the
+ given tablespace */
+ btr_pcur_t* pcur, /*!< in/out: persistent cursor pointing to
record in the clustered index of
SYS_INDEXES table. The cursor may be
repositioned in this call. */
- mtr_t* mtr) /* in: mtr having the latch
+ mtr_t* mtr) /*!< in: mtr having the latch
on the record page. The mtr may be
committed and restarted in this call. */
{
ulint root_page_no;
- ulint space;
+ ibool drop = !space;
+ ulint zip_size;
ulint type;
dulint index_id;
rec_t* rec;
- byte* ptr;
+ const byte* ptr;
ulint len;
- ulint comp;
dict_index_t* index;
ut_ad(mutex_own(&(dict_sys->mutex)));
@@ -716,13 +747,13 @@ dict_truncate_index_tree(
root_page_no = mtr_read_ulint(ptr, MLOG_4BYTES, mtr);
- if (root_page_no == FIL_NULL) {
+ if (drop && root_page_no == FIL_NULL) {
/* The tree has been freed. */
ut_print_timestamp(stderr);
fprintf(stderr, " InnoDB: Trying to TRUNCATE"
" a missing index of table %s!\n", table->name);
- return(FIL_NULL);
+ drop = FALSE;
}
ptr = rec_get_nth_field_old(rec,
@@ -730,9 +761,13 @@ dict_truncate_index_tree(
ut_ad(len == 4);
- space = mtr_read_ulint(ptr, MLOG_4BYTES, mtr);
+ if (drop) {
+ space = mtr_read_ulint(ptr, MLOG_4BYTES, mtr);
+ }
- if (!fil_tablespace_exists_in_mem(space)) {
+ zip_size = fil_space_get_zip_size(space);
+
+ if (UNIV_UNLIKELY(zip_size == ULINT_UNDEFINED)) {
/* It is a single table tablespace and the .ibd file is
missing: do nothing */
@@ -751,20 +786,25 @@ dict_truncate_index_tree(
ut_ad(len == 8);
index_id = mach_read_from_8(ptr);
+ if (!drop) {
+
+ goto create;
+ }
+
/* We free all the pages but the root page first; this operation
may span several mini-transactions */
- btr_free_but_not_root(space, root_page_no);
+ btr_free_but_not_root(space, zip_size, root_page_no);
/* Then we free the root page in the same mini-transaction where
we create the b-tree and write its new root page number to the
appropriate field in the SYS_INDEXES record: this mini-transaction
marks the B-tree totally truncated */
- comp = page_is_comp(btr_page_get(space, root_page_no, RW_X_LATCH,
- mtr));
+ btr_page_get(space, zip_size, root_page_no, RW_X_LATCH, mtr);
- btr_free_root(space, root_page_no, mtr);
+ btr_free_root(space, zip_size, root_page_no, mtr);
+create:
/* We will temporarily write FIL_NULL to the PAGE_NO field
in SYS_INDEXES, so that the database will not get into an
inconsistent state in case it crashes between the mtr_commit()
@@ -786,36 +826,34 @@ dict_truncate_index_tree(
index;
index = UT_LIST_GET_NEXT(indexes, index)) {
if (!ut_dulint_cmp(index->id, index_id)) {
- break;
+ root_page_no = btr_create(type, space, zip_size,
+ index_id, index, mtr);
+ index->page = (unsigned int) root_page_no;
+ return(root_page_no);
}
}
- root_page_no = btr_create(type, space, index_id, comp, mtr);
- if (index) {
- index->page = (unsigned int) root_page_no;
- } else {
- ut_print_timestamp(stderr);
- fprintf(stderr,
- " InnoDB: Index %lu %lu of table %s is missing\n"
- "InnoDB: from the data dictionary during TRUNCATE!\n",
- ut_dulint_get_high(index_id),
- ut_dulint_get_low(index_id),
- table->name);
- }
+ ut_print_timestamp(stderr);
+ fprintf(stderr,
+ " InnoDB: Index %lu %lu of table %s is missing\n"
+ "InnoDB: from the data dictionary during TRUNCATE!\n",
+ ut_dulint_get_high(index_id),
+ ut_dulint_get_low(index_id),
+ table->name);
- return(root_page_no);
+ return(FIL_NULL);
}
-/*************************************************************************
-Creates a table create graph. */
-
+/*********************************************************************//**
+Creates a table create graph.
+@return own: table create node */
+UNIV_INTERN
tab_node_t*
tab_create_graph_create(
/*====================*/
- /* out, own: table create node */
- dict_table_t* table, /* in: table to create, built as a memory data
+ dict_table_t* table, /*!< in: table to create, built as a memory data
structure */
- mem_heap_t* heap) /* in: heap where created */
+ mem_heap_t* heap) /*!< in: heap where created */
{
tab_node_t* node;
@@ -842,16 +880,16 @@ tab_create_graph_create(
return(node);
}
-/*************************************************************************
-Creates an index create graph. */
-
+/*********************************************************************//**
+Creates an index create graph.
+@return own: index create node */
+UNIV_INTERN
ind_node_t*
ind_create_graph_create(
/*====================*/
- /* out, own: index create node */
- dict_index_t* index, /* in: index to create, built as a memory data
+ dict_index_t* index, /*!< in: index to create, built as a memory data
structure */
- mem_heap_t* heap) /* in: heap where created */
+ mem_heap_t* heap) /*!< in: heap where created */
{
ind_node_t* node;
@@ -879,14 +917,14 @@ ind_create_graph_create(
return(node);
}
-/***************************************************************
-Creates a table. This is a high-level function used in SQL execution graphs. */
-
+/***********************************************************//**
+Creates a table. This is a high-level function used in SQL execution graphs.
+@return query thread to run next or NULL */
+UNIV_INTERN
que_thr_t*
dict_create_table_step(
/*===================*/
- /* out: query thread to run next or NULL */
- que_thr_t* thr) /* in: query thread */
+ que_thr_t* thr) /*!< in: query thread */
{
tab_node_t* node;
ulint err = DB_ERROR;
@@ -985,15 +1023,15 @@ function_exit:
return(thr);
}
-/***************************************************************
+/***********************************************************//**
Creates an index. This is a high-level function used in SQL execution
-graphs. */
-
+graphs.
+@return query thread to run next or NULL */
+UNIV_INTERN
que_thr_t*
dict_create_index_step(
/*===================*/
- /* out: query thread to run next or NULL */
- que_thr_t* thr) /* in: query thread */
+ que_thr_t* thr) /*!< in: query thread */
{
ind_node_t* node;
ulint err = DB_ERROR;
@@ -1046,19 +1084,40 @@ dict_create_index_step(
return(thr);
} else {
- node->state = INDEX_CREATE_INDEX_TREE;
+ node->state = INDEX_ADD_TO_CACHE;
}
}
+ if (node->state == INDEX_ADD_TO_CACHE) {
+
+ dulint index_id = node->index->id;
+
+ err = dict_index_add_to_cache(node->table, node->index,
+ FIL_NULL, TRUE);
+
+ node->index = dict_index_get_if_in_cache_low(index_id);
+ ut_a(!node->index == (err != DB_SUCCESS));
+
+ if (err != DB_SUCCESS) {
+
+ goto function_exit;
+ }
+
+ node->state = INDEX_CREATE_INDEX_TREE;
+ }
+
if (node->state == INDEX_CREATE_INDEX_TREE) {
err = dict_create_index_tree_step(node);
if (err != DB_SUCCESS) {
+ dict_index_remove_from_cache(node->table, node->index);
+ node->index = NULL;
goto function_exit;
}
+ node->index->page = node->page_no;
node->state = INDEX_COMMIT_WORK;
}
@@ -1068,21 +1127,13 @@ dict_create_index_step(
(CREATE INDEX does NOT currently do an implicit commit of
the current transaction) */
- node->state = INDEX_ADD_TO_CACHE;
+ node->state = INDEX_CREATE_INDEX_TREE;
/* thr->run_node = node->commit_node;
return(thr); */
}
- if (node->state == INDEX_ADD_TO_CACHE) {
-
- dict_index_add_to_cache(node->table, node->index,
- node->page_no);
-
- err = DB_SUCCESS;
- }
-
function_exit:
trx->error_state = err;
@@ -1103,15 +1154,15 @@ function_exit:
return(thr);
}
-/********************************************************************
+/****************************************************************//**
Creates the foreign key constraints system tables inside InnoDB
at database creation or database start if they are not found or are
-not of the right form. */
-
+not of the right form.
+@return DB_SUCCESS or error code */
+UNIV_INTERN
ulint
dict_create_or_check_foreign_constraint_tables(void)
/*================================================*/
- /* out: DB_SUCCESS or error code */
{
dict_table_t* table1;
dict_table_t* table2;
@@ -1187,7 +1238,6 @@ dict_create_or_check_foreign_constraint_tables(void)
" FOR_COL_NAME CHAR, REF_COL_NAME CHAR);\n"
"CREATE UNIQUE CLUSTERED INDEX ID_IND"
" ON SYS_FOREIGN_COLS (ID, POS);\n"
- "COMMIT WORK;\n"
"END;\n"
, FALSE, trx);
@@ -1210,7 +1260,7 @@ dict_create_or_check_foreign_constraint_tables(void)
error = DB_MUST_GET_MORE_FILE_SPACE;
}
- trx->op_info = "";
+ trx_commit_for_mysql(trx);
row_mysql_unlock_data_dictionary(trx);
@@ -1225,18 +1275,18 @@ dict_create_or_check_foreign_constraint_tables(void)
return(error);
}
-/********************************************************************
-Evaluate the given foreign key SQL statement. */
-
+/****************************************************************//**
+Evaluate the given foreign key SQL statement.
+@return error code or DB_SUCCESS */
+static
ulint
dict_foreign_eval_sql(
/*==================*/
- /* out: error code or DB_SUCCESS */
- pars_info_t* info, /* in: info struct, or NULL */
- const char* sql, /* in: SQL string to evaluate */
- dict_table_t* table, /* in: table */
- dict_foreign_t* foreign,/* in: foreign */
- trx_t* trx) /* in: transaction */
+ pars_info_t* info, /*!< in: info struct, or NULL */
+ const char* sql, /*!< in: SQL string to evaluate */
+ dict_table_t* table, /*!< in: table */
+ dict_foreign_t* foreign,/*!< in: foreign */
+ trx_t* trx) /*!< in: transaction */
{
ulint error;
FILE* ef = dict_foreign_err_file;
@@ -1251,12 +1301,11 @@ dict_foreign_eval_sql(
ef);
ut_print_name(ef, trx, TRUE, table->name);
fputs(".\nA foreign key constraint of name ", ef);
- ut_print_name(ef, trx, FALSE, foreign->id);
+ ut_print_name(ef, trx, TRUE, foreign->id);
fputs("\nalready exists."
- " (Note that internally InnoDB adds 'databasename/'\n"
- "in front of the user-defined constraint name).\n",
- ef);
- fputs("Note that InnoDB's FOREIGN KEY system tables store\n"
+ " (Note that internally InnoDB adds 'databasename'\n"
+ "in front of the user-defined constraint name.)\n"
+ "Note that InnoDB's FOREIGN KEY system tables store\n"
"constraint names as case-insensitive, with the\n"
"MySQL standard latin1_swedish_ci collation. If you\n"
"create tables or databases whose names differ only in\n"
@@ -1291,18 +1340,18 @@ dict_foreign_eval_sql(
return(DB_SUCCESS);
}
-/************************************************************************
+/********************************************************************//**
Add a single foreign key field definition to the data dictionary tables in
-the database. */
+the database.
+@return error code or DB_SUCCESS */
static
ulint
dict_create_add_foreign_field_to_dictionary(
/*========================================*/
- /* out: error code or DB_SUCCESS */
- ulint field_nr, /* in: foreign field number */
- dict_table_t* table, /* in: table */
- dict_foreign_t* foreign, /* in: foreign */
- trx_t* trx) /* in: transaction */
+ ulint field_nr, /*!< in: foreign field number */
+ dict_table_t* table, /*!< in: table */
+ dict_foreign_t* foreign, /*!< in: foreign */
+ trx_t* trx) /*!< in: transaction */
{
pars_info_t* info = pars_info_create();
@@ -1326,23 +1375,23 @@ dict_create_add_foreign_field_to_dictionary(
table, foreign, trx));
}
-/************************************************************************
+/********************************************************************//**
Add a single foreign key definition to the data dictionary tables in the
database. We also generate names to constraints that were not named by the
user. A generated constraint has a name of the format
databasename/tablename_ibfk_, where the numbers start from 1, and
are given locally for this table, that is, the number is not global, as in
-the old format constraints < 4.0.18 it used to be. */
+the old format constraints < 4.0.18 it used to be.
+@return error code or DB_SUCCESS */
static
ulint
dict_create_add_foreign_to_dictionary(
/*==================================*/
- /* out: error code or DB_SUCCESS */
- ulint* id_nr, /* in/out: number to use in id generation;
+ ulint* id_nr, /*!< in/out: number to use in id generation;
incremented if used */
- dict_table_t* table, /* in: table */
- dict_foreign_t* foreign,/* in: foreign */
- trx_t* trx) /* in: transaction */
+ dict_table_t* table, /*!< in: table */
+ dict_foreign_t* foreign,/*!< in: foreign */
+ trx_t* trx) /*!< in: transaction */
{
ulint error;
ulint i;
@@ -1401,14 +1450,14 @@ dict_create_add_foreign_to_dictionary(
return(error);
}
-/************************************************************************
-Adds foreign key definitions to data dictionary tables in the database. */
-
+/********************************************************************//**
+Adds foreign key definitions to data dictionary tables in the database.
+@return error code or DB_SUCCESS */
+UNIV_INTERN
ulint
dict_create_add_foreigns_to_dictionary(
/*===================================*/
- /* out: error code or DB_SUCCESS */
- ulint start_id,/* in: if we are actually doing ALTER TABLE
+ ulint start_id,/*!< in: if we are actually doing ALTER TABLE
ADD CONSTRAINT, we want to generate constraint
numbers which are bigger than in the table so
far; we number the constraints from
@@ -1416,8 +1465,8 @@ dict_create_add_foreigns_to_dictionary(
we are creating a new table, or if the table
so far has no constraints for which the name
was generated here */
- dict_table_t* table, /* in: table */
- trx_t* trx) /* in: transaction */
+ dict_table_t* table, /*!< in: table */
+ trx_t* trx) /*!< in: transaction */
{
dict_foreign_t* foreign;
ulint number = start_id + 1;
diff --git a/storage/innobase/dict/dict0dict.c b/storage/innodb_plugin/dict/dict0dict.c
similarity index 67%
rename from storage/innobase/dict/dict0dict.c
rename to storage/innodb_plugin/dict/dict0dict.c
index c7a57d6a2b8..d1f0e0ffc19 100644
--- a/storage/innobase/dict/dict0dict.c
+++ b/storage/innodb_plugin/dict/dict0dict.c
@@ -1,7 +1,24 @@
-/**********************************************************************
-Data dictionary system
+/*****************************************************************************
-(c) 1996 Innobase Oy
+Copyright (c) 1996, 2009, Innobase Oy. All Rights Reserved.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; version 2 of the License.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place, Suite 330, Boston, MA 02111-1307 USA
+
+*****************************************************************************/
+
+/******************************************************************//**
+@file dict/dict0dict.c
+Data dictionary system
Created 1/8/1996 Heikki Tuuri
***********************************************************************/
@@ -12,6 +29,12 @@ Created 1/8/1996 Heikki Tuuri
#include "dict0dict.ic"
#endif
+/** dummy index for ROW_FORMAT=REDUNDANT supremum and infimum records */
+UNIV_INTERN dict_index_t* dict_ind_redundant;
+/** dummy index for ROW_FORMAT=COMPACT supremum and infimum records */
+UNIV_INTERN dict_index_t* dict_ind_compact;
+
+#ifndef UNIV_HOTBACKUP
#include "buf0buf.h"
#include "data0type.h"
#include "mach0data.h"
@@ -22,221 +45,136 @@ Created 1/8/1996 Heikki Tuuri
#include "btr0btr.h"
#include "btr0cur.h"
#include "btr0sea.h"
+#include "page0zip.h"
+#include "page0page.h"
#include "pars0pars.h"
#include "pars0sym.h"
#include "que0que.h"
#include "rem0cmp.h"
-#ifndef UNIV_HOTBACKUP
-# include "m_ctype.h" /* my_isspace() */
-#endif /* !UNIV_HOTBACKUP */
+#include "row0merge.h"
+#include "m_ctype.h" /* my_isspace() */
+#include "ha_prototypes.h" /* innobase_strcasecmp() */
#include
-dict_sys_t* dict_sys = NULL; /* the dictionary system */
+/** the dictionary system */
+UNIV_INTERN dict_sys_t* dict_sys = NULL;
-rw_lock_t dict_operation_lock; /* table create, drop, etc. reserve
- this in X-mode; implicit or backround
- operations purge, rollback, foreign
- key checks reserve this in S-mode; we
- cannot trust that MySQL protects
- implicit or background operations
- a table drop since MySQL does not
- know of them; therefore we need this;
- NOTE: a transaction which reserves
- this must keep book on the mode in
- trx->dict_operation_lock_mode */
+/** @brief the data dictionary rw-latch protecting dict_sys
-#define DICT_HEAP_SIZE 100 /* initial memory heap size when
+table create, drop, etc. reserve this in X-mode; implicit or
+backround operations purge, rollback, foreign key checks reserve this
+in S-mode; we cannot trust that MySQL protects implicit or background
+operations a table drop since MySQL does not know of them; therefore
+we need this; NOTE: a transaction which reserves this must keep book
+on the mode in trx_struct::dict_operation_lock_mode */
+UNIV_INTERN rw_lock_t dict_operation_lock;
+
+#define DICT_HEAP_SIZE 100 /*!< initial memory heap size when
creating a table or index object */
-#define DICT_POOL_PER_TABLE_HASH 512 /* buffer pool max size per table
+#define DICT_POOL_PER_TABLE_HASH 512 /*!< buffer pool max size per table
hash table fixed size in bytes */
-#define DICT_POOL_PER_VARYING 4 /* buffer pool max size per data
+#define DICT_POOL_PER_VARYING 4 /*!< buffer pool max size per data
dictionary varying size in bytes */
-/* Identifies generated InnoDB foreign key names */
+/** Identifies generated InnoDB foreign key names */
static char dict_ibfk[] = "_ibfk_";
-#ifndef UNIV_HOTBACKUP
-/**********************************************************************
-Converts an identifier to a table name.
-
-NOTE: the prototype of this function is copied from ha_innodb.cc! If you change
-this function, you MUST change also the prototype here! */
-extern
-void
-innobase_convert_from_table_id(
-/*===========================*/
- char* to, /* out: converted identifier */
- const char* from, /* in: identifier to convert */
- ulint len); /* in: length of 'to', in bytes;
- should be at least 5 * strlen(to) + 1 */
-/**********************************************************************
-Converts an identifier to UTF-8.
-
-NOTE: the prototype of this function is copied from ha_innodb.cc! If you change
-this function, you MUST change also the prototype here! */
-extern
-void
-innobase_convert_from_id(
-/*=====================*/
- char* to, /* out: converted identifier */
- const char* from, /* in: identifier to convert */
- ulint len); /* in: length of 'to', in bytes;
- should be at least 3 * strlen(to) + 1 */
-/**********************************************************************
-Compares NUL-terminated UTF-8 strings case insensitively.
-
-NOTE: the prototype of this function is copied from ha_innodb.cc! If you change
-this function, you MUST change also the prototype here! */
-extern
-int
-innobase_strcasecmp(
-/*================*/
- /* out: 0 if a=b, <0 if a1 if a>b */
- const char* a, /* in: first string to compare */
- const char* b); /* in: second string to compare */
-
-/**********************************************************************
-Makes all characters in a NUL-terminated UTF-8 string lower case.
-
-NOTE: the prototype of this function is copied from ha_innodb.cc! If you change
-this function, you MUST change also the prototype here! */
-extern
-void
-innobase_casedn_str(
-/*================*/
- char* a); /* in/out: string to put in lower case */
-
-/**************************************************************************
-Determines the connection character set.
-
-NOTE: the prototype of this function is copied from ha_innodb.cc! If you change
-this function, you MUST change also the prototype here! */
-struct charset_info_st*
-innobase_get_charset(
-/*=================*/
- /* out: connection character set */
- void* mysql_thd); /* in: MySQL thread handle */
-#endif /* !UNIV_HOTBACKUP */
-
-/**************************************************************************
-Removes an index from the dictionary cache. */
-static
-void
-dict_index_remove_from_cache(
-/*=========================*/
- dict_table_t* table, /* in: table */
- dict_index_t* index); /* in, own: index */
-/***********************************************************************
-Copies fields contained in index2 to index1. */
-static
-void
-dict_index_copy(
-/*============*/
- dict_index_t* index1, /* in: index to copy to */
- dict_index_t* index2, /* in: index to copy from */
- dict_table_t* table, /* in: table */
- ulint start, /* in: first position to copy */
- ulint end); /* in: last position to copy */
-/***********************************************************************
+/*******************************************************************//**
Tries to find column names for the index and sets the col field of the
index. */
static
void
dict_index_find_cols(
/*=================*/
- dict_table_t* table, /* in: table */
- dict_index_t* index); /* in: index */
-/***********************************************************************
+ dict_table_t* table, /*!< in: table */
+ dict_index_t* index); /*!< in: index */
+/*******************************************************************//**
Builds the internal dictionary cache representation for a clustered
-index, containing also system fields not defined by the user. */
+index, containing also system fields not defined by the user.
+@return own: the internal representation of the clustered index */
static
dict_index_t*
dict_index_build_internal_clust(
/*============================*/
- /* out, own: the internal representation
- of the clustered index */
- dict_table_t* table, /* in: table */
- dict_index_t* index); /* in: user representation of a clustered
- index */
-/***********************************************************************
+ const dict_table_t* table, /*!< in: table */
+ dict_index_t* index); /*!< in: user representation of
+ a clustered index */
+/*******************************************************************//**
Builds the internal dictionary cache representation for a non-clustered
-index, containing also system fields not defined by the user. */
+index, containing also system fields not defined by the user.
+@return own: the internal representation of the non-clustered index */
static
dict_index_t*
dict_index_build_internal_non_clust(
/*================================*/
- /* out, own: the internal representation
- of the non-clustered index */
- dict_table_t* table, /* in: table */
- dict_index_t* index); /* in: user representation of a non-clustered
- index */
-/**************************************************************************
+ const dict_table_t* table, /*!< in: table */
+ dict_index_t* index); /*!< in: user representation of
+ a non-clustered index */
+/**********************************************************************//**
Removes a foreign constraint struct from the dictionary cache. */
static
void
dict_foreign_remove_from_cache(
/*===========================*/
- dict_foreign_t* foreign); /* in, own: foreign constraint */
-/**************************************************************************
+ dict_foreign_t* foreign); /*!< in, own: foreign constraint */
+/**********************************************************************//**
Prints a column data. */
static
void
dict_col_print_low(
/*===============*/
- const dict_table_t* table, /* in: table */
- const dict_col_t* col); /* in: column */
-/**************************************************************************
+ const dict_table_t* table, /*!< in: table */
+ const dict_col_t* col); /*!< in: column */
+/**********************************************************************//**
Prints an index data. */
static
void
dict_index_print_low(
/*=================*/
- dict_index_t* index); /* in: index */
-/**************************************************************************
+ dict_index_t* index); /*!< in: index */
+/**********************************************************************//**
Prints a field data. */
static
void
dict_field_print_low(
/*=================*/
- dict_field_t* field); /* in: field */
-/*************************************************************************
+ dict_field_t* field); /*!< in: field */
+/*********************************************************************//**
Frees a foreign key struct. */
static
void
dict_foreign_free(
/*==============*/
- dict_foreign_t* foreign); /* in, own: foreign key struct */
+ dict_foreign_t* foreign); /*!< in, own: foreign key struct */
/* Stream for storing detailed information about the latest foreign key
and unique key errors */
-FILE* dict_foreign_err_file = NULL;
-mutex_t dict_foreign_err_mutex; /* mutex protecting the foreign
- and unique error buffers */
+UNIV_INTERN FILE* dict_foreign_err_file = NULL;
+/* mutex protecting the foreign and unique error buffers */
+UNIV_INTERN mutex_t dict_foreign_err_mutex;
-#ifndef UNIV_HOTBACKUP
-/**********************************************************************
+/******************************************************************//**
Makes all characters in a NUL-terminated UTF-8 string lower case. */
-
+UNIV_INTERN
void
dict_casedn_str(
/*============*/
- char* a) /* in/out: string to put in lower case */
+ char* a) /*!< in/out: string to put in lower case */
{
innobase_casedn_str(a);
}
-#endif /* !UNIV_HOTBACKUP */
-
-/************************************************************************
-Checks if the database name in two table names is the same. */
+/********************************************************************//**
+Checks if the database name in two table names is the same.
+@return TRUE if same db name */
+UNIV_INTERN
ibool
dict_tables_have_same_db(
/*=====================*/
- /* out: TRUE if same db name */
- const char* name1, /* in: table name in the form
+ const char* name1, /*!< in: table name in the form
dbname '/' tablename */
- const char* name2) /* in: table name in the form
+ const char* name2) /*!< in: table name in the form
dbname '/' tablename */
{
for (; *name1 == *name2; name1++, name2++) {
@@ -248,14 +186,14 @@ dict_tables_have_same_db(
return(FALSE);
}
-/************************************************************************
-Return the end of table name where we have removed dbname and '/'. */
-
+/********************************************************************//**
+Return the end of table name where we have removed dbname and '/'.
+@return table name */
+UNIV_INTERN
const char*
dict_remove_db_name(
/*================*/
- /* out: table name */
- const char* name) /* in: table name in the form
+ const char* name) /*!< in: table name in the form
dbname '/' tablename */
{
const char* s = strchr(name, '/');
@@ -264,14 +202,14 @@ dict_remove_db_name(
return(s + 1);
}
-/************************************************************************
-Get the database name length in a table name. */
-
+/********************************************************************//**
+Get the database name length in a table name.
+@return database name length */
+UNIV_INTERN
ulint
dict_get_db_name_len(
/*=================*/
- /* out: database name length */
- const char* name) /* in: table name in the form
+ const char* name) /*!< in: table name in the form
dbname '/' tablename */
{
const char* s;
@@ -280,9 +218,9 @@ dict_get_db_name_len(
return(s - name);
}
-/************************************************************************
+/********************************************************************//**
Reserves the dictionary system mutex for MySQL. */
-
+UNIV_INTERN
void
dict_mutex_enter_for_mysql(void)
/*============================*/
@@ -290,9 +228,9 @@ dict_mutex_enter_for_mysql(void)
mutex_enter(&(dict_sys->mutex));
}
-/************************************************************************
+/********************************************************************//**
Releases the dictionary system mutex for MySQL. */
-
+UNIV_INTERN
void
dict_mutex_exit_for_mysql(void)
/*===========================*/
@@ -300,97 +238,40 @@ dict_mutex_exit_for_mysql(void)
mutex_exit(&(dict_sys->mutex));
}
-/************************************************************************
+/********************************************************************//**
Decrements the count of open MySQL handles to a table. */
-
+UNIV_INTERN
void
dict_table_decrement_handle_count(
/*==============================*/
- dict_table_t* table) /* in: table */
+ dict_table_t* table, /*!< in/out: table */
+ ibool dict_locked) /*!< in: TRUE=data dictionary locked */
{
- mutex_enter(&(dict_sys->mutex));
+ if (!dict_locked) {
+ mutex_enter(&dict_sys->mutex);
+ }
+ ut_ad(mutex_own(&dict_sys->mutex));
ut_a(table->n_mysql_handles_opened > 0);
table->n_mysql_handles_opened--;
- mutex_exit(&(dict_sys->mutex));
+ if (!dict_locked) {
+ mutex_exit(&dict_sys->mutex);
+ }
}
+#endif /* !UNIV_HOTBACKUP */
-/*************************************************************************
-Gets the column data type. */
-
-void
-dict_col_copy_type_noninline(
-/*=========================*/
- const dict_col_t* col, /* in: column */
- dtype_t* type) /* out: data type */
-{
- dict_col_copy_type(col, type);
-}
-
-/************************************************************************
-Gets the nth column of a table. */
-
-const dict_col_t*
-dict_table_get_nth_col_noninline(
-/*=============================*/
- /* out: pointer to column object */
- const dict_table_t* table, /* in: table */
- ulint pos) /* in: position of column */
-{
- return(dict_table_get_nth_col(table, pos));
-}
-
-/************************************************************************
-Gets the first index on the table (the clustered index). */
-
-dict_index_t*
-dict_table_get_first_index_noninline(
-/*=================================*/
- /* out: index, NULL if none exists */
- dict_table_t* table) /* in: table */
-{
- return(dict_table_get_first_index(table));
-}
-
-/************************************************************************
-Gets the next index on the table. */
-
-dict_index_t*
-dict_table_get_next_index_noninline(
-/*================================*/
- /* out: index, NULL if none left */
- dict_index_t* index) /* in: index */
-{
- return(dict_table_get_next_index(index));
-}
-
-/**************************************************************************
-Returns an index object. */
-
-dict_index_t*
-dict_table_get_index_noninline(
-/*===========================*/
- /* out: index, NULL if does not exist */
- dict_table_t* table, /* in: table */
- const char* name) /* in: index name */
-{
- return(dict_table_get_index(table, name));
-}
-
-/**************************************************************************
-Returns a column's name. */
-
+/**********************************************************************//**
+Returns a column's name.
+@return column name. NOTE: not guaranteed to stay valid if table is
+modified in any way (columns added, etc.). */
+UNIV_INTERN
const char*
dict_table_get_col_name(
/*====================*/
- /* out: column name. NOTE: not
- guaranteed to stay valid if table is
- modified in any way (columns added,
- etc.). */
- const dict_table_t* table, /* in: table */
- ulint col_nr) /* in: column number */
+ const dict_table_t* table, /*!< in: table */
+ ulint col_nr) /*!< in: column number */
{
ulint i;
const char* s;
@@ -409,57 +290,57 @@ dict_table_get_col_name(
return(s);
}
-
-/************************************************************************
-Acquire the autoinc lock.*/
-
+#ifndef UNIV_HOTBACKUP
+/********************************************************************//**
+Acquire the autoinc lock. */
+UNIV_INTERN
void
dict_table_autoinc_lock(
/*====================*/
- dict_table_t* table)
+ dict_table_t* table) /*!< in/out: table */
{
mutex_enter(&table->autoinc_mutex);
}
-/************************************************************************
+/********************************************************************//**
Unconditionally set the autoinc counter. */
-
+UNIV_INTERN
void
dict_table_autoinc_initialize(
/*==========================*/
- dict_table_t* table, /* in: table */
- ib_ulonglong value) /* in: next value to assign to a row */
+ dict_table_t* table, /*!< in/out: table */
+ ib_uint64_t value) /*!< in: next value to assign to a row */
{
ut_ad(mutex_own(&table->autoinc_mutex));
table->autoinc = value;
}
-/************************************************************************
+/********************************************************************//**
Reads the next autoinc value (== autoinc counter value), 0 if not yet
-initialized. */
-
-ib_ulonglong
+initialized.
+@return value for a new row, or 0 */
+UNIV_INTERN
+ib_uint64_t
dict_table_autoinc_read(
/*====================*/
- /* out: value for a new row, or 0 */
- dict_table_t* table) /* in: table */
+ const dict_table_t* table) /*!< in: table */
{
ut_ad(mutex_own(&table->autoinc_mutex));
return(table->autoinc);
}
-/************************************************************************
+/********************************************************************//**
Updates the autoinc counter if the value supplied is greater than the
current value. */
-
+UNIV_INTERN
void
dict_table_autoinc_update_if_greater(
/*=================================*/
- dict_table_t* table, /* in: table */
- ib_ulonglong value) /* in: value which was assigned to a row */
+ dict_table_t* table, /*!< in/out: table */
+ ib_uint64_t value) /*!< in: value which was assigned to a row */
{
ut_ad(mutex_own(&table->autoinc_mutex));
@@ -469,28 +350,56 @@ dict_table_autoinc_update_if_greater(
}
}
-/************************************************************************
-Release the autoinc lock.*/
-
+/********************************************************************//**
+Release the autoinc lock. */
+UNIV_INTERN
void
dict_table_autoinc_unlock(
/*======================*/
- dict_table_t* table) /* in: release autoinc lock for this table */
+ dict_table_t* table) /*!< in/out: table */
{
mutex_exit(&table->autoinc_mutex);
}
-/************************************************************************
-Looks for column n in an index. */
+/**********************************************************************//**
+Looks for an index with the given table and index id.
+NOTE that we do not reserve the dictionary mutex.
+@return index or NULL if not found from cache */
+UNIV_INTERN
+dict_index_t*
+dict_index_get_on_id_low(
+/*=====================*/
+ dict_table_t* table, /*!< in: table */
+ dulint id) /*!< in: index id */
+{
+ dict_index_t* index;
+ index = dict_table_get_first_index(table);
+
+ while (index) {
+ if (0 == ut_dulint_cmp(id, index->id)) {
+ /* Found */
+
+ return(index);
+ }
+
+ index = dict_table_get_next_index(index);
+ }
+
+ return(NULL);
+}
+#endif /* !UNIV_HOTBACKUP */
+
+/********************************************************************//**
+Looks for column n in an index.
+@return position in internal representation of the index;
+ULINT_UNDEFINED if not contained */
+UNIV_INTERN
ulint
dict_index_get_nth_col_pos(
/*=======================*/
- /* out: position in internal representation
- of the index; if not contained, returns
- ULINT_UNDEFINED */
- dict_index_t* index, /* in: index */
- ulint n) /* in: column number */
+ const dict_index_t* index, /*!< in: index */
+ ulint n) /*!< in: column number */
{
const dict_field_t* field;
const dict_col_t* col;
@@ -502,7 +411,7 @@ dict_index_get_nth_col_pos(
col = dict_table_get_nth_col(index->table, n);
- if (index->type & DICT_CLUSTERED) {
+ if (dict_index_is_clust(index)) {
return(dict_col_get_clust_pos(col, index));
}
@@ -521,16 +430,16 @@ dict_index_get_nth_col_pos(
return(ULINT_UNDEFINED);
}
-/************************************************************************
-Returns TRUE if the index contains a column or a prefix of that column. */
-
+#ifndef UNIV_HOTBACKUP
+/********************************************************************//**
+Returns TRUE if the index contains a column or a prefix of that column.
+@return TRUE if contains the column or its prefix */
+UNIV_INTERN
ibool
dict_index_contains_col_or_prefix(
/*==============================*/
- /* out: TRUE if contains the column or its
- prefix */
- dict_index_t* index, /* in: index */
- ulint n) /* in: column number */
+ const dict_index_t* index, /*!< in: index */
+ ulint n) /*!< in: column number */
{
const dict_field_t* field;
const dict_col_t* col;
@@ -540,7 +449,7 @@ dict_index_contains_col_or_prefix(
ut_ad(index);
ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
- if (index->type & DICT_CLUSTERED) {
+ if (dict_index_is_clust(index)) {
return(TRUE);
}
@@ -561,26 +470,25 @@ dict_index_contains_col_or_prefix(
return(FALSE);
}
-/************************************************************************
+/********************************************************************//**
Looks for a matching field in an index. The column has to be the same. The
column in index must be complete, or must contain a prefix longer than the
column in index2. That is, we must be able to construct the prefix in index2
-from the prefix in index. */
-
+from the prefix in index.
+@return position in internal representation of the index;
+ULINT_UNDEFINED if not contained */
+UNIV_INTERN
ulint
dict_index_get_nth_field_pos(
/*=========================*/
- /* out: position in internal representation
- of the index; if not contained, returns
- ULINT_UNDEFINED */
- dict_index_t* index, /* in: index from which to search */
- dict_index_t* index2, /* in: index */
- ulint n) /* in: field number in index2 */
+ const dict_index_t* index, /*!< in: index from which to search */
+ const dict_index_t* index2, /*!< in: index */
+ ulint n) /*!< in: field number in index2 */
{
- dict_field_t* field;
- dict_field_t* field2;
- ulint n_fields;
- ulint pos;
+ const dict_field_t* field;
+ const dict_field_t* field2;
+ ulint n_fields;
+ ulint pos;
ut_ad(index);
ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
@@ -604,15 +512,15 @@ dict_index_get_nth_field_pos(
return(ULINT_UNDEFINED);
}
-/**************************************************************************
-Returns a table object based on table id. */
-
+/**********************************************************************//**
+Returns a table object based on table id.
+@return table, NULL if does not exist */
+UNIV_INTERN
dict_table_t*
dict_table_get_on_id(
/*=================*/
- /* out: table, NULL if does not exist */
- dulint table_id, /* in: table id */
- trx_t* trx) /* in: transaction handle */
+ dulint table_id, /*!< in: table id */
+ trx_t* trx) /*!< in: transaction handle */
{
dict_table_t* table;
@@ -638,47 +546,32 @@ dict_table_get_on_id(
return(table);
}
-/************************************************************************
-Looks for column n position in the clustered index. */
-
+/********************************************************************//**
+Looks for column n position in the clustered index.
+@return position in internal representation of the clustered index */
+UNIV_INTERN
ulint
dict_table_get_nth_col_pos(
/*=======================*/
- /* out: position in internal representation
- of the clustered index */
- dict_table_t* table, /* in: table */
- ulint n) /* in: column number */
+ const dict_table_t* table, /*!< in: table */
+ ulint n) /*!< in: column number */
{
return(dict_index_get_nth_col_pos(dict_table_get_first_index(table),
n));
}
-/************************************************************************
-Check whether the table uses the compact page format. */
-
-ibool
-dict_table_is_comp_noninline(
-/*=========================*/
- /* out: TRUE if table uses the
- compact page format */
- const dict_table_t* table) /* in: table */
-{
- return(dict_table_is_comp(table));
-}
-
-/************************************************************************
+/********************************************************************//**
Checks if a column is in the ordering columns of the clustered index of a
-table. Column prefixes are treated like whole columns. */
-
+table. Column prefixes are treated like whole columns.
+@return TRUE if the column, or its prefix, is in the clustered key */
+UNIV_INTERN
ibool
dict_table_col_in_clustered_key(
/*============================*/
- /* out: TRUE if the column, or its prefix, is
- in the clustered key */
- dict_table_t* table, /* in: table */
- ulint n) /* in: column number */
+ const dict_table_t* table, /*!< in: table */
+ ulint n) /*!< in: column number */
{
- dict_index_t* index;
+ const dict_index_t* index;
const dict_field_t* field;
const dict_col_t* col;
ulint pos;
@@ -704,9 +597,9 @@ dict_table_col_in_clustered_key(
return(FALSE);
}
-/**************************************************************************
+/**********************************************************************//**
Inits the data dictionary module. */
-
+UNIV_INTERN
void
dict_init(void)
/*===========*/
@@ -715,10 +608,10 @@ dict_init(void)
mutex_create(&dict_sys->mutex, SYNC_DICT);
- dict_sys->table_hash = hash_create(buf_pool_get_max_size()
+ dict_sys->table_hash = hash_create(buf_pool_get_curr_size()
/ (DICT_POOL_PER_TABLE_HASH
* UNIV_WORD_SIZE));
- dict_sys->table_id_hash = hash_create(buf_pool_get_max_size()
+ dict_sys->table_id_hash = hash_create(buf_pool_get_curr_size()
/ (DICT_POOL_PER_TABLE_HASH
* UNIV_WORD_SIZE));
dict_sys->size = 0;
@@ -733,20 +626,18 @@ dict_init(void)
mutex_create(&dict_foreign_err_mutex, SYNC_ANY_LATCH);
}
-/**************************************************************************
+/**********************************************************************//**
Returns a table object and optionally increment its MySQL open handle count.
NOTE! This is a high-level function to be used mainly from outside the
'dict' directory. Inside this directory dict_table_get_low is usually the
-appropriate function. */
-
+appropriate function.
+@return table, NULL if does not exist */
+UNIV_INTERN
dict_table_t*
dict_table_get(
/*===========*/
- /* out: table, NULL if
- does not exist */
- const char* table_name, /* in: table name */
- ibool inc_mysql_count)
- /* in: whether to increment the open
+ const char* table_name, /*!< in: table name */
+ ibool inc_mysql_count)/*!< in: whether to increment the open
handle count on the table */
{
dict_table_t* table;
@@ -772,15 +663,16 @@ dict_table_get(
return(table);
}
+#endif /* !UNIV_HOTBACKUP */
-/**************************************************************************
+/**********************************************************************//**
Adds system columns to a table object. */
-
+UNIV_INTERN
void
dict_table_add_system_columns(
/*==========================*/
- dict_table_t* table, /* in/out: table */
- mem_heap_t* heap) /* in: temporary heap */
+ dict_table_t* table, /*!< in/out: table */
+ mem_heap_t* heap) /*!< in: temporary heap */
{
ut_ad(table);
ut_ad(table->n_def == table->n_cols - DATA_N_SYS_COLS);
@@ -819,14 +711,15 @@ dict_table_add_system_columns(
#endif
}
-/**************************************************************************
+#ifndef UNIV_HOTBACKUP
+/**********************************************************************//**
Adds a table object to the dictionary cache. */
-
+UNIV_INTERN
void
dict_table_add_to_cache(
/*====================*/
- dict_table_t* table, /* in: table */
- mem_heap_t* heap) /* in: temporary heap */
+ dict_table_t* table, /*!< in: table */
+ mem_heap_t* heap) /*!< in: temporary heap */
{
ulint fold;
ulint id_fold;
@@ -866,17 +759,35 @@ dict_table_add_to_cache(
/* Look for a table with the same name: error if such exists */
{
dict_table_t* table2;
- HASH_SEARCH(name_hash, dict_sys->table_hash, fold, table2,
- (ut_strcmp(table2->name, table->name) == 0));
+ HASH_SEARCH(name_hash, dict_sys->table_hash, fold,
+ dict_table_t*, table2, ut_ad(table2->cached),
+ ut_strcmp(table2->name, table->name) == 0);
ut_a(table2 == NULL);
+
+#ifdef UNIV_DEBUG
+ /* Look for the same table pointer with a different name */
+ HASH_SEARCH_ALL(name_hash, dict_sys->table_hash,
+ dict_table_t*, table2, ut_ad(table2->cached),
+ table2 == table);
+ ut_ad(table2 == NULL);
+#endif /* UNIV_DEBUG */
}
/* Look for a table with the same id: error if such exists */
{
dict_table_t* table2;
- HASH_SEARCH(id_hash, dict_sys->table_id_hash, id_fold, table2,
- (ut_dulint_cmp(table2->id, table->id) == 0));
+ HASH_SEARCH(id_hash, dict_sys->table_id_hash, id_fold,
+ dict_table_t*, table2, ut_ad(table2->cached),
+ ut_dulint_cmp(table2->id, table->id) == 0);
ut_a(table2 == NULL);
+
+#ifdef UNIV_DEBUG
+ /* Look for the same table pointer with a different id */
+ HASH_SEARCH_ALL(id_hash, dict_sys->table_id_hash,
+ dict_table_t*, table2, ut_ad(table2->cached),
+ table2 == table);
+ ut_ad(table2 == NULL);
+#endif /* UNIV_DEBUG */
}
/* Add table to hash table of tables */
@@ -892,16 +803,16 @@ dict_table_add_to_cache(
dict_sys->size += mem_heap_get_size(table->heap);
}
-/**************************************************************************
+/**********************************************************************//**
Looks for an index with the given id. NOTE that we do not reserve
the dictionary mutex: this function is for emergency purposes like
-printing info of a corrupt database page! */
-
+printing info of a corrupt database page!
+@return index or NULL if not found from cache */
+UNIV_INTERN
dict_index_t*
dict_index_find_on_id_low(
/*======================*/
- /* out: index or NULL if not found from cache */
- dulint id) /* in: index id */
+ dulint id) /*!< in: index id */
{
dict_table_t* table;
dict_index_t* index;
@@ -927,16 +838,16 @@ dict_index_find_on_id_low(
return(NULL);
}
-/**************************************************************************
-Renames a table object. */
-
+/**********************************************************************//**
+Renames a table object.
+@return TRUE if success */
+UNIV_INTERN
ibool
dict_table_rename_in_cache(
/*=======================*/
- /* out: TRUE if success */
- dict_table_t* table, /* in: table */
- const char* new_name, /* in: new name */
- ibool rename_also_foreigns)/* in: in ALTER TABLE we want
+ dict_table_t* table, /*!< in/out: table */
+ const char* new_name, /*!< in: new name */
+ ibool rename_also_foreigns)/*!< in: in ALTER TABLE we want
to preserve the original table name
in constraints which reference it */
{
@@ -944,26 +855,31 @@ dict_table_rename_in_cache(
dict_index_t* index;
ulint fold;
ulint old_size;
- char* old_name;
- ibool success;
+ const char* old_name;
ut_ad(table);
ut_ad(mutex_own(&(dict_sys->mutex)));
old_size = mem_heap_get_size(table->heap);
+ old_name = table->name;
fold = ut_fold_string(new_name);
/* Look for a table with the same name: error if such exists */
{
dict_table_t* table2;
- HASH_SEARCH(name_hash, dict_sys->table_hash, fold, table2,
+ HASH_SEARCH(name_hash, dict_sys->table_hash, fold,
+ dict_table_t*, table2, ut_ad(table2->cached),
(ut_strcmp(table2->name, new_name) == 0));
- if (table2) {
- fprintf(stderr,
- "InnoDB: Error: dictionary cache"
- " already contains a table of name %s\n",
- new_name);
+ if (UNIV_LIKELY_NULL(table2)) {
+ ut_print_timestamp(stderr);
+ fputs(" InnoDB: Error: dictionary cache"
+ " already contains a table ", stderr);
+ ut_print_name(stderr, NULL, TRUE, new_name);
+ fputs("\n"
+ "InnoDB: cannot rename table ", stderr);
+ ut_print_name(stderr, NULL, TRUE, old_name);
+ putc('\n', stderr);
return(FALSE);
}
}
@@ -973,27 +889,24 @@ dict_table_rename_in_cache(
if (table->space != 0) {
if (table->dir_path_of_temp_table != NULL) {
- fprintf(stderr,
- "InnoDB: Error: trying to rename a table"
- " %s (%s) created with CREATE\n"
- "InnoDB: TEMPORARY TABLE\n",
- table->name, table->dir_path_of_temp_table);
- success = FALSE;
- } else {
- success = fil_rename_tablespace(
- table->name, table->space, new_name);
- }
-
- if (!success) {
-
+ ut_print_timestamp(stderr);
+ fputs(" InnoDB: Error: trying to rename a"
+ " TEMPORARY TABLE ", stderr);
+ ut_print_name(stderr, NULL, TRUE, old_name);
+ fputs(" (", stderr);
+ ut_print_filename(stderr,
+ table->dir_path_of_temp_table);
+ fputs(" )\n", stderr);
+ return(FALSE);
+ } else if (!fil_rename_tablespace(old_name, table->space,
+ new_name)) {
return(FALSE);
}
}
/* Remove table from the hash tables of tables */
HASH_DELETE(dict_table_t, name_hash, dict_sys->table_hash,
- ut_fold_string(table->name), table);
- old_name = mem_heap_strdup(table->heap, table->name);
+ ut_fold_string(old_name), table);
table->name = mem_heap_strdup(table->heap, new_name);
/* Add table to hash table of tables */
@@ -1141,15 +1054,15 @@ dict_table_rename_in_cache(
return(TRUE);
}
-/**************************************************************************
+/**********************************************************************//**
Change the id of a table object in the dictionary cache. This is used in
DISCARD TABLESPACE. */
-
+UNIV_INTERN
void
dict_table_change_id_in_cache(
/*==========================*/
- dict_table_t* table, /* in: table object already in cache */
- dulint new_id) /* in: new id to set */
+ dict_table_t* table, /*!< in/out: table object already in cache */
+ dulint new_id) /*!< in: new id to set */
{
ut_ad(table);
ut_ad(mutex_own(&(dict_sys->mutex)));
@@ -1166,13 +1079,13 @@ dict_table_change_id_in_cache(
ut_fold_dulint(table->id), table);
}
-/**************************************************************************
+/**********************************************************************//**
Removes a table object from the dictionary cache. */
-
+UNIV_INTERN
void
dict_table_remove_from_cache(
/*=========================*/
- dict_table_t* table) /* in, own: table */
+ dict_table_t* table) /*!< in, own: table */
{
dict_foreign_t* foreign;
dict_index_t* index;
@@ -1233,27 +1146,15 @@ dict_table_remove_from_cache(
dict_mem_table_free(table);
}
-/*************************************************************************
-Gets the column position in the clustered index. */
-
-ulint
-dict_col_get_clust_pos_noninline(
-/*=============================*/
- const dict_col_t* col, /* in: table column */
- const dict_index_t* clust_index) /* in: clustered index */
-{
- return(dict_col_get_clust_pos(col, clust_index));
-}
-
-/********************************************************************
+/****************************************************************//**
If the given column name is reserved for InnoDB system columns, return
-TRUE. */
-
+TRUE.
+@return TRUE if name is reserved */
+UNIV_INTERN
ibool
dict_col_name_is_reserved(
/*======================*/
- /* out: TRUE if name is reserved */
- const char* name) /* in: column name */
+ const char* name) /*!< in: column name */
{
/* This check reminds that if a new system column is added to
the program, it should be dealt with here. */
@@ -1277,16 +1178,271 @@ dict_col_name_is_reserved(
return(FALSE);
}
-/**************************************************************************
-Adds an index to the dictionary cache. */
+/****************************************************************//**
+If an undo log record for this table might not fit on a single page,
+return TRUE.
+@return TRUE if the undo log record could become too big */
+static
+ibool
+dict_index_too_big_for_undo(
+/*========================*/
+ const dict_table_t* table, /*!< in: table */
+ const dict_index_t* new_index) /*!< in: index */
+{
+ /* Make sure that all column prefixes will fit in the undo log record
+ in trx_undo_page_report_modify() right after trx_undo_page_init(). */
-void
+ ulint i;
+ const dict_index_t* clust_index
+ = dict_table_get_first_index(table);
+ ulint undo_page_len
+ = TRX_UNDO_PAGE_HDR - TRX_UNDO_PAGE_HDR_SIZE
+ + 2 /* next record pointer */
+ + 1 /* type_cmpl */
+ + 11 /* trx->undo_no */ - 11 /* table->id */
+ + 1 /* rec_get_info_bits() */
+ + 11 /* DB_TRX_ID */
+ + 11 /* DB_ROLL_PTR */
+ + 10 + FIL_PAGE_DATA_END /* trx_undo_left() */
+ + 2/* pointer to previous undo log record */;
+
+ if (UNIV_UNLIKELY(!clust_index)) {
+ ut_a(dict_index_is_clust(new_index));
+ clust_index = new_index;
+ }
+
+ /* Add the size of the ordering columns in the
+ clustered index. */
+ for (i = 0; i < clust_index->n_uniq; i++) {
+ const dict_col_t* col
+ = dict_index_get_nth_col(clust_index, i);
+
+ /* Use the maximum output size of
+ mach_write_compressed(), although the encoded
+ length should always fit in 2 bytes. */
+ undo_page_len += 5 + dict_col_get_max_size(col);
+ }
+
+ /* Add the old values of the columns to be updated.
+ First, the amount and the numbers of the columns.
+ These are written by mach_write_compressed() whose
+ maximum output length is 5 bytes. However, given that
+ the quantities are below REC_MAX_N_FIELDS (10 bits),
+ the maximum length is 2 bytes per item. */
+ undo_page_len += 2 * (dict_table_get_n_cols(table) + 1);
+
+ for (i = 0; i < clust_index->n_def; i++) {
+ const dict_col_t* col
+ = dict_index_get_nth_col(clust_index, i);
+ ulint max_size
+ = dict_col_get_max_size(col);
+ ulint fixed_size
+ = dict_col_get_fixed_size(col,
+ dict_table_is_comp(table));
+
+ if (fixed_size) {
+ /* Fixed-size columns are stored locally. */
+ max_size = fixed_size;
+ } else if (max_size <= BTR_EXTERN_FIELD_REF_SIZE * 2) {
+ /* Short columns are stored locally. */
+ } else if (!col->ord_part) {
+ /* See if col->ord_part would be set
+ because of new_index. */
+ ulint j;
+
+ for (j = 0; j < new_index->n_uniq; j++) {
+ if (dict_index_get_nth_col(
+ new_index, j) == col) {
+
+ goto is_ord_part;
+ }
+ }
+
+ /* This is not an ordering column in any index.
+ Thus, it can be stored completely externally. */
+ max_size = BTR_EXTERN_FIELD_REF_SIZE;
+ } else {
+is_ord_part:
+ /* This is an ordering column in some index.
+ A long enough prefix must be written to the
+ undo log. See trx_undo_page_fetch_ext(). */
+
+ if (max_size > REC_MAX_INDEX_COL_LEN) {
+ max_size = REC_MAX_INDEX_COL_LEN;
+ }
+
+ max_size += BTR_EXTERN_FIELD_REF_SIZE;
+ }
+
+ undo_page_len += 5 + max_size;
+ }
+
+ return(undo_page_len >= UNIV_PAGE_SIZE);
+}
+
+/****************************************************************//**
+If a record of this index might not fit on a single B-tree page,
+return TRUE.
+@return TRUE if the index record could become too big */
+static
+ibool
+dict_index_too_big_for_tree(
+/*========================*/
+ const dict_table_t* table, /*!< in: table */
+ const dict_index_t* new_index) /*!< in: index */
+{
+ ulint zip_size;
+ ulint comp;
+ ulint i;
+ /* maximum possible storage size of a record */
+ ulint rec_max_size;
+ /* maximum allowed size of a record on a leaf page */
+ ulint page_rec_max;
+ /* maximum allowed size of a node pointer record */
+ ulint page_ptr_max;
+
+ comp = dict_table_is_comp(table);
+ zip_size = dict_table_zip_size(table);
+
+ if (zip_size && zip_size < UNIV_PAGE_SIZE) {
+ /* On a compressed page, two records must fit in the
+ uncompressed page modification log. On compressed
+ pages with zip_size == UNIV_PAGE_SIZE, this limit will
+ never be reached. */
+ ut_ad(comp);
+ /* The maximum allowed record size is the size of
+ an empty page, minus a byte for recoding the heap
+ number in the page modification log. The maximum
+ allowed node pointer size is half that. */
+ page_rec_max = page_zip_empty_size(new_index->n_fields,
+ zip_size) - 1;
+ page_ptr_max = page_rec_max / 2;
+ /* On a compressed page, there is a two-byte entry in
+ the dense page directory for every record. But there
+ is no record header. */
+ rec_max_size = 2;
+ } else {
+ /* The maximum allowed record size is half a B-tree
+ page. No additional sparse page directory entry will
+ be generated for the first few user records. */
+ page_rec_max = page_get_free_space_of_empty(comp) / 2;
+ page_ptr_max = page_rec_max;
+ /* Each record has a header. */
+ rec_max_size = comp
+ ? REC_N_NEW_EXTRA_BYTES
+ : REC_N_OLD_EXTRA_BYTES;
+ }
+
+ if (comp) {
+ /* Include the "null" flags in the
+ maximum possible record size. */
+ rec_max_size += UT_BITS_IN_BYTES(new_index->n_nullable);
+ } else {
+ /* For each column, include a 2-byte offset and a
+ "null" flag. The 1-byte format is only used in short
+ records that do not contain externally stored columns.
+ Such records could never exceed the page limit, even
+ when using the 2-byte format. */
+ rec_max_size += 2 * new_index->n_fields;
+ }
+
+ /* Compute the maximum possible record size. */
+ for (i = 0; i < new_index->n_fields; i++) {
+ const dict_field_t* field
+ = dict_index_get_nth_field(new_index, i);
+ const dict_col_t* col
+ = dict_field_get_col(field);
+ ulint field_max_size;
+ ulint field_ext_max_size;
+
+ /* In dtuple_convert_big_rec(), variable-length columns
+ that are longer than BTR_EXTERN_FIELD_REF_SIZE * 2
+ may be chosen for external storage.
+
+ Fixed-length columns, and all columns of secondary
+ index records are always stored inline. */
+
+ /* Determine the maximum length of the index field.
+ The field_ext_max_size should be computed as the worst
+ case in rec_get_converted_size_comp() for
+ REC_STATUS_ORDINARY records. */
+
+ field_max_size = dict_col_get_fixed_size(col, comp);
+ if (field_max_size) {
+ /* dict_index_add_col() should guarantee this */
+ ut_ad(!field->prefix_len
+ || field->fixed_len == field->prefix_len);
+ /* Fixed lengths are not encoded
+ in ROW_FORMAT=COMPACT. */
+ field_ext_max_size = 0;
+ goto add_field_size;
+ }
+
+ field_max_size = dict_col_get_max_size(col);
+ field_ext_max_size = field_max_size < 256 ? 1 : 2;
+
+ if (field->prefix_len) {
+ if (field->prefix_len < field_max_size) {
+ field_max_size = field->prefix_len;
+ }
+ } else if (field_max_size > BTR_EXTERN_FIELD_REF_SIZE * 2
+ && dict_index_is_clust(new_index)) {
+
+ /* In the worst case, we have a locally stored
+ column of BTR_EXTERN_FIELD_REF_SIZE * 2 bytes.
+ The length can be stored in one byte. If the
+ column were stored externally, the lengths in
+ the clustered index page would be
+ BTR_EXTERN_FIELD_REF_SIZE and 2. */
+ field_max_size = BTR_EXTERN_FIELD_REF_SIZE * 2;
+ field_ext_max_size = 1;
+ }
+
+ if (comp) {
+ /* Add the extra size for ROW_FORMAT=COMPACT.
+ For ROW_FORMAT=REDUNDANT, these bytes were
+ added to rec_max_size before this loop. */
+ rec_max_size += field_ext_max_size;
+ }
+add_field_size:
+ rec_max_size += field_max_size;
+
+ /* Check the size limit on leaf pages. */
+ if (UNIV_UNLIKELY(rec_max_size >= page_rec_max)) {
+
+ return(TRUE);
+ }
+
+ /* Check the size limit on non-leaf pages. Records
+ stored in non-leaf B-tree pages consist of the unique
+ columns of the record (the key columns of the B-tree)
+ and a node pointer field. When we have processed the
+ unique columns, rec_max_size equals the size of the
+ node pointer record minus the node pointer column. */
+ if (i + 1 == dict_index_get_n_unique_in_tree(new_index)
+ && rec_max_size + REC_NODE_PTR_SIZE >= page_ptr_max) {
+
+ return(TRUE);
+ }
+ }
+
+ return(FALSE);
+}
+
+/**********************************************************************//**
+Adds an index to the dictionary cache.
+@return DB_SUCCESS or DB_TOO_BIG_RECORD */
+UNIV_INTERN
+ulint
dict_index_add_to_cache(
/*====================*/
- dict_table_t* table, /* in: table on which the index is */
- dict_index_t* index, /* in, own: index; NOTE! The index memory
+ dict_table_t* table, /*!< in: table on which the index is */
+ dict_index_t* index, /*!< in, own: index; NOTE! The index memory
object is freed in this function! */
- ulint page_no)/* in: root page number of the index */
+ ulint page_no,/*!< in: root page number of the index */
+ ibool strict) /*!< in: TRUE=refuse to create the index
+ if records could be too big to fit in
+ an B-tree page */
{
dict_index_t* new_index;
ulint n_ord;
@@ -1298,21 +1454,7 @@ dict_index_add_to_cache(
ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
ut_ad(mem_heap_validate(index->heap));
-
-#ifdef UNIV_DEBUG
- {
- dict_index_t* index2;
- index2 = UT_LIST_GET_FIRST(table->indexes);
-
- while (index2 != NULL) {
- ut_ad(ut_strcmp(index->name, index2->name) != 0);
-
- index2 = UT_LIST_GET_NEXT(indexes, index2);
- }
- }
-#endif /* UNIV_DEBUG */
-
- ut_a(!(index->type & DICT_CLUSTERED)
+ ut_a(!dict_index_is_clust(index)
|| UT_LIST_GET_LEN(table->indexes) == 0);
dict_index_find_cols(table, index);
@@ -1320,39 +1462,106 @@ dict_index_add_to_cache(
/* Build the cache internal representation of the index,
containing also the added system fields */
- if (index->type & DICT_CLUSTERED) {
+ if (dict_index_is_clust(index)) {
new_index = dict_index_build_internal_clust(table, index);
} else {
new_index = dict_index_build_internal_non_clust(table, index);
}
- new_index->search_info = btr_search_info_create(new_index->heap);
-
/* Set the n_fields value in new_index to the actual defined
number of fields in the cache internal representation */
new_index->n_fields = new_index->n_def;
+ if (strict && dict_index_too_big_for_tree(table, new_index)) {
+too_big:
+ dict_mem_index_free(new_index);
+ dict_mem_index_free(index);
+ return(DB_TOO_BIG_RECORD);
+ }
+
+ if (UNIV_UNLIKELY(index->type & DICT_UNIVERSAL)) {
+ n_ord = new_index->n_fields;
+ } else {
+ n_ord = new_index->n_uniq;
+ }
+
+ switch (dict_table_get_format(table)) {
+ case DICT_TF_FORMAT_51:
+ /* ROW_FORMAT=REDUNDANT and ROW_FORMAT=COMPACT store
+ prefixes of externally stored columns locally within
+ the record. There are no special considerations for
+ the undo log record size. */
+ goto undo_size_ok;
+
+ case DICT_TF_FORMAT_ZIP:
+ /* In ROW_FORMAT=DYNAMIC and ROW_FORMAT=COMPRESSED,
+ column prefix indexes require that prefixes of
+ externally stored columns are written to the undo log.
+ This may make the undo log record bigger than the
+ record on the B-tree page. The maximum size of an
+ undo log record is the page size. That must be
+ checked for below. */
+ break;
+
+#if DICT_TF_FORMAT_ZIP != DICT_TF_FORMAT_MAX
+# error "DICT_TF_FORMAT_ZIP != DICT_TF_FORMAT_MAX"
+#endif
+ }
+
+ for (i = 0; i < n_ord; i++) {
+ const dict_field_t* field
+ = dict_index_get_nth_field(new_index, i);
+ const dict_col_t* col
+ = dict_field_get_col(field);
+
+ /* In dtuple_convert_big_rec(), variable-length columns
+ that are longer than BTR_EXTERN_FIELD_REF_SIZE * 2
+ may be chosen for external storage. If the column appears
+ in an ordering column of an index, a longer prefix of
+ REC_MAX_INDEX_COL_LEN will be copied to the undo log
+ by trx_undo_page_report_modify() and
+ trx_undo_page_fetch_ext(). It suffices to check the
+ capacity of the undo log whenever new_index includes
+ a column prefix on a column that may be stored externally. */
+
+ if (field->prefix_len /* prefix index */
+ && !col->ord_part /* not yet ordering column */
+ && !dict_col_get_fixed_size(col, TRUE) /* variable-length */
+ && dict_col_get_max_size(col)
+ > BTR_EXTERN_FIELD_REF_SIZE * 2 /* long enough */) {
+
+ if (dict_index_too_big_for_undo(table, new_index)) {
+ /* An undo log record might not fit in
+ a single page. Refuse to create this index. */
+
+ goto too_big;
+ }
+
+ break;
+ }
+ }
+
+undo_size_ok:
+ /* Flag the ordering columns */
+
+ for (i = 0; i < n_ord; i++) {
+
+ dict_index_get_nth_field(new_index, i)->col->ord_part = 1;
+ }
+
/* Add the new index as the last index for the table */
UT_LIST_ADD_LAST(indexes, table->indexes, new_index);
new_index->table = table;
new_index->table_name = table->name;
- /* Increment the ord_part counts in columns which are ordering */
+ new_index->search_info = btr_search_info_create(new_index->heap);
- if (UNIV_UNLIKELY(index->type & DICT_UNIVERSAL)) {
- n_ord = new_index->n_fields;
- } else {
- n_ord = dict_index_get_n_unique(new_index);
- }
+ new_index->stat_index_size = 1;
+ new_index->stat_n_leaf_pages = 1;
- for (i = 0; i < n_ord; i++) {
-
- dict_index_get_nth_field(new_index, i)->col->ord_part = 1;
- }
-
- new_index->page = (unsigned int) page_no;
+ new_index->page = page_no;
rw_lock_create(&new_index->lock, SYNC_INDEX_TREE);
if (!UNIV_UNLIKELY(new_index->type & DICT_UNIVERSAL)) {
@@ -1360,7 +1569,7 @@ dict_index_add_to_cache(
new_index->stat_n_diff_key_vals = mem_heap_alloc(
new_index->heap,
(1 + dict_index_get_n_unique(new_index))
- * sizeof(ib_longlong));
+ * sizeof(ib_int64_t));
/* Give some sensible values to stat_n_... in case we do
not calculate statistics quickly enough */
@@ -1373,16 +1582,18 @@ dict_index_add_to_cache(
dict_sys->size += mem_heap_get_size(new_index->heap);
dict_mem_index_free(index);
+
+ return(DB_SUCCESS);
}
-/**************************************************************************
+/**********************************************************************//**
Removes an index from the dictionary cache. */
-static
+UNIV_INTERN
void
dict_index_remove_from_cache(
/*=========================*/
- dict_table_t* table, /* in: table */
- dict_index_t* index) /* in, own: index */
+ dict_table_t* table, /*!< in/out: table */
+ dict_index_t* index) /*!< in, own: index */
{
ulint size;
ulint retries = 0;
@@ -1452,15 +1663,15 @@ dict_index_remove_from_cache(
dict_mem_index_free(index);
}
-/***********************************************************************
+/*******************************************************************//**
Tries to find column names for the index and sets the col field of the
index. */
static
void
dict_index_find_cols(
/*=================*/
- dict_table_t* table, /* in: table */
- dict_index_t* index) /* in: index */
+ dict_table_t* table, /*!< in: table */
+ dict_index_t* index) /*!< in: index */
{
ulint i;
@@ -1475,31 +1686,36 @@ dict_index_find_cols(
for (j = 0; j < table->n_cols; j++) {
if (!strcmp(dict_table_get_col_name(table, j),
field->name)) {
- field->col = (dict_col_t*)
- dict_table_get_nth_col(table, j);
+ field->col = dict_table_get_nth_col(table, j);
goto found;
}
}
/* It is an error not to find a matching column. */
+ fputs("InnoDB: Error: no matching column for ", stderr);
+ ut_print_name(stderr, NULL, FALSE, field->name);
+ fputs(" in ", stderr);
+ dict_index_name_print(stderr, NULL, index);
+ fputs("!\n", stderr);
ut_error;
- found:
+found:
;
}
}
+#endif /* !UNIV_HOTBACKUP */
-/***********************************************************************
+/*******************************************************************//**
Adds a column to index. */
-
+UNIV_INTERN
void
dict_index_add_col(
/*===============*/
- dict_index_t* index, /* in: index */
- dict_table_t* table, /* in: table */
- dict_col_t* col, /* in: column */
- ulint prefix_len) /* in: column prefix length */
+ dict_index_t* index, /*!< in/out: index */
+ const dict_table_t* table, /*!< in: table */
+ dict_col_t* col, /*!< in: column */
+ ulint prefix_len) /*!< in: column prefix length */
{
dict_field_t* field;
const char* col_name;
@@ -1511,7 +1727,8 @@ dict_index_add_col(
field = dict_index_get_nth_field(index, index->n_def - 1);
field->col = col;
- field->fixed_len = (unsigned int) dict_col_get_fixed_size(col);
+ field->fixed_len = (unsigned int) dict_col_get_fixed_size(
+ col, dict_table_is_comp(table));
if (prefix_len && field->fixed_len > prefix_len) {
field->fixed_len = (unsigned int) prefix_len;
@@ -1536,17 +1753,18 @@ dict_index_add_col(
}
}
-/***********************************************************************
+#ifndef UNIV_HOTBACKUP
+/*******************************************************************//**
Copies fields contained in index2 to index1. */
static
void
dict_index_copy(
/*============*/
- dict_index_t* index1, /* in: index to copy to */
- dict_index_t* index2, /* in: index to copy from */
- dict_table_t* table, /* in: table */
- ulint start, /* in: first position to copy */
- ulint end) /* in: last position to copy */
+ dict_index_t* index1, /*!< in: index to copy to */
+ dict_index_t* index2, /*!< in: index to copy from */
+ const dict_table_t* table, /*!< in: table */
+ ulint start, /*!< in: first position to copy */
+ ulint end) /*!< in: last position to copy */
{
dict_field_t* field;
ulint i;
@@ -1561,15 +1779,16 @@ dict_index_copy(
}
}
-/***********************************************************************
+/*******************************************************************//**
Copies types of fields contained in index to tuple. */
-
+UNIV_INTERN
void
dict_index_copy_types(
/*==================*/
- dtuple_t* tuple, /* in: data tuple */
- dict_index_t* index, /* in: index */
- ulint n_fields) /* in: number of field types to copy */
+ dtuple_t* tuple, /*!< in/out: data tuple */
+ const dict_index_t* index, /*!< in: index */
+ ulint n_fields) /*!< in: number of
+ field types to copy */
{
ulint i;
@@ -1580,8 +1799,8 @@ dict_index_copy_types(
}
for (i = 0; i < n_fields; i++) {
- dict_field_t* ifield;
- dtype_t* dfield_type;
+ const dict_field_t* ifield;
+ dtype_t* dfield_type;
ifield = dict_index_get_nth_field(index, i);
dfield_type = dfield_get_type(dtuple_get_nth_field(tuple, i));
@@ -1589,38 +1808,40 @@ dict_index_copy_types(
}
}
-/***********************************************************************
-Copies types of columns contained in table to tuple. */
-
+/*******************************************************************//**
+Copies types of columns contained in table to tuple and sets all
+fields of the tuple to the SQL NULL value. This function should
+be called right after dtuple_create(). */
+UNIV_INTERN
void
dict_table_copy_types(
/*==================*/
- dtuple_t* tuple, /* in: data tuple */
- dict_table_t* table) /* in: index */
+ dtuple_t* tuple, /*!< in/out: data tuple */
+ const dict_table_t* table) /*!< in: table */
{
- dtype_t* dfield_type;
ulint i;
for (i = 0; i < dtuple_get_n_fields(tuple); i++) {
- dfield_type = dfield_get_type(dtuple_get_nth_field(tuple, i));
- dict_col_copy_type(dict_table_get_nth_col(table, i),
- dfield_type);
+ dfield_t* dfield = dtuple_get_nth_field(tuple, i);
+ dtype_t* dtype = dfield_get_type(dfield);
+
+ dfield_set_null(dfield);
+ dict_col_copy_type(dict_table_get_nth_col(table, i), dtype);
}
}
-/***********************************************************************
+/*******************************************************************//**
Builds the internal dictionary cache representation for a clustered
-index, containing also system fields not defined by the user. */
+index, containing also system fields not defined by the user.
+@return own: the internal representation of the clustered index */
static
dict_index_t*
dict_index_build_internal_clust(
/*============================*/
- /* out, own: the internal representation
- of the clustered index */
- dict_table_t* table, /* in: table */
- dict_index_t* index) /* in: user representation of a clustered
- index */
+ const dict_table_t* table, /*!< in: table */
+ dict_index_t* index) /*!< in: user representation of
+ a clustered index */
{
dict_index_t* new_index;
dict_field_t* field;
@@ -1630,7 +1851,7 @@ dict_index_build_internal_clust(
ibool* indexed;
ut_ad(table && index);
- ut_ad(index->type & DICT_CLUSTERED);
+ ut_ad(dict_index_is_clust(index));
ut_ad(mutex_own(&(dict_sys->mutex)));
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
@@ -1655,7 +1876,7 @@ dict_index_build_internal_clust(
new_index->n_uniq = REC_MAX_N_FIELDS;
- } else if (index->type & DICT_UNIQUE) {
+ } else if (dict_index_is_unique(index)) {
/* Only the fields defined so far are needed to identify
the index entry uniquely */
@@ -1667,7 +1888,7 @@ dict_index_build_internal_clust(
new_index->trx_id_offset = 0;
- if (!(index->type & DICT_IBUF)) {
+ if (!dict_index_is_ibuf(index)) {
/* Add system columns, trx id first */
trx_id_pos = new_index->n_def;
@@ -1682,19 +1903,19 @@ dict_index_build_internal_clust(
# error "DATA_ROLL_PTR != 2"
#endif
- if (!(index->type & DICT_UNIQUE)) {
- dict_index_add_col(new_index, table, (dict_col_t*)
+ if (!dict_index_is_unique(index)) {
+ dict_index_add_col(new_index, table,
dict_table_get_sys_col(
table, DATA_ROW_ID),
0);
trx_id_pos++;
}
- dict_index_add_col(new_index, table, (dict_col_t*)
+ dict_index_add_col(new_index, table,
dict_table_get_sys_col(table, DATA_TRX_ID),
0);
- dict_index_add_col(new_index, table, (dict_col_t*)
+ dict_index_add_col(new_index, table,
dict_table_get_sys_col(table,
DATA_ROLL_PTR),
0);
@@ -1702,7 +1923,8 @@ dict_index_build_internal_clust(
for (i = 0; i < trx_id_pos; i++) {
fixed_size = dict_col_get_fixed_size(
- dict_index_get_nth_col(new_index, i));
+ dict_index_get_nth_col(new_index, i),
+ dict_table_is_comp(table));
if (fixed_size == 0) {
new_index->trx_id_offset = 0;
@@ -1723,10 +1945,9 @@ dict_index_build_internal_clust(
}
/* Remember the table columns already contained in new_index */
- indexed = mem_alloc(table->n_cols * sizeof *indexed);
- memset(indexed, 0, table->n_cols * sizeof *indexed);
+ indexed = mem_zalloc(table->n_cols * sizeof *indexed);
- /* Mark with 0 the table columns already contained in new_index */
+ /* Mark the table columns already contained in new_index */
for (i = 0; i < new_index->n_def; i++) {
field = dict_index_get_nth_field(new_index, i);
@@ -1744,8 +1965,7 @@ dict_index_build_internal_clust(
there */
for (i = 0; i + DATA_N_SYS_COLS < (ulint) table->n_cols; i++) {
- dict_col_t* col = (dict_col_t*)
- dict_table_get_nth_col(table, i);
+ dict_col_t* col = dict_table_get_nth_col(table, i);
ut_ad(col->mtype != DATA_SYS);
if (!indexed[col->ind]) {
@@ -1755,7 +1975,7 @@ dict_index_build_internal_clust(
mem_free(indexed);
- ut_ad((index->type & DICT_IBUF)
+ ut_ad(dict_index_is_ibuf(index)
|| (UT_LIST_GET_LEN(table->indexes) == 0));
new_index->cached = TRUE;
@@ -1763,18 +1983,17 @@ dict_index_build_internal_clust(
return(new_index);
}
-/***********************************************************************
+/*******************************************************************//**
Builds the internal dictionary cache representation for a non-clustered
-index, containing also system fields not defined by the user. */
+index, containing also system fields not defined by the user.
+@return own: the internal representation of the non-clustered index */
static
dict_index_t*
dict_index_build_internal_non_clust(
/*================================*/
- /* out, own: the internal representation
- of the non-clustered index */
- dict_table_t* table, /* in: table */
- dict_index_t* index) /* in: user representation of a non-clustered
- index */
+ const dict_table_t* table, /*!< in: table */
+ dict_index_t* index) /*!< in: user representation of
+ a non-clustered index */
{
dict_field_t* field;
dict_index_t* new_index;
@@ -1783,7 +2002,7 @@ dict_index_build_internal_non_clust(
ibool* indexed;
ut_ad(table && index);
- ut_ad(0 == (index->type & DICT_CLUSTERED));
+ ut_ad(!dict_index_is_clust(index));
ut_ad(mutex_own(&(dict_sys->mutex)));
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
@@ -1791,7 +2010,7 @@ dict_index_build_internal_non_clust(
clust_index = UT_LIST_GET_FIRST(table->indexes);
ut_ad(clust_index);
- ut_ad(clust_index->type & DICT_CLUSTERED);
+ ut_ad(dict_index_is_clust(clust_index));
ut_ad(!(clust_index->type & DICT_UNIVERSAL));
/* Create a new index */
@@ -1810,10 +2029,9 @@ dict_index_build_internal_non_clust(
dict_index_copy(new_index, index, table, 0, index->n_fields);
/* Remember the table columns already contained in new_index */
- indexed = mem_alloc(table->n_cols * sizeof *indexed);
- memset(indexed, 0, table->n_cols * sizeof *indexed);
+ indexed = mem_zalloc(table->n_cols * sizeof *indexed);
- /* Mark with 0 table columns already contained in new_index */
+ /* Mark the table columns already contained in new_index */
for (i = 0; i < new_index->n_def; i++) {
field = dict_index_get_nth_field(new_index, i);
@@ -1842,7 +2060,7 @@ dict_index_build_internal_non_clust(
mem_free(indexed);
- if ((index->type) & DICT_UNIQUE) {
+ if (dict_index_is_unique(index)) {
new_index->n_uniq = index->n_fields;
} else {
new_index->n_uniq = new_index->n_def;
@@ -1860,42 +2078,98 @@ dict_index_build_internal_non_clust(
/*====================== FOREIGN KEY PROCESSING ========================*/
-/*************************************************************************
-Checks if a table is referenced by foreign keys. */
-
+/*********************************************************************//**
+Checks if a table is referenced by foreign keys.
+@return TRUE if table is referenced by a foreign key */
+UNIV_INTERN
ibool
-dict_table_referenced_by_foreign_key(
-/*=================================*/
- /* out: TRUE if table is referenced by a
- foreign key */
- dict_table_t* table) /* in: InnoDB table */
+dict_table_is_referenced_by_foreign_key(
+/*====================================*/
+ const dict_table_t* table) /*!< in: InnoDB table */
{
- if (UT_LIST_GET_LEN(table->referenced_list) > 0) {
-
- return(TRUE);
- }
-
- return(FALSE);
+ return(UT_LIST_GET_LEN(table->referenced_list) > 0);
}
-/*************************************************************************
+/*********************************************************************//**
+Check if the index is referenced by a foreign key, if TRUE return foreign
+else return NULL
+@return pointer to foreign key struct if index is defined for foreign
+key, otherwise NULL */
+UNIV_INTERN
+dict_foreign_t*
+dict_table_get_referenced_constraint(
+/*=================================*/
+ dict_table_t* table, /*!< in: InnoDB table */
+ dict_index_t* index) /*!< in: InnoDB index */
+{
+ dict_foreign_t* foreign;
+
+ ut_ad(index != NULL);
+ ut_ad(table != NULL);
+
+ for (foreign = UT_LIST_GET_FIRST(table->referenced_list);
+ foreign;
+ foreign = UT_LIST_GET_NEXT(referenced_list, foreign)) {
+
+ if (foreign->referenced_index == index) {
+
+ return(foreign);
+ }
+ }
+
+ return(NULL);
+}
+
+/*********************************************************************//**
+Checks if a index is defined for a foreign key constraint. Index is a part
+of a foreign key constraint if the index is referenced by foreign key
+or index is a foreign key index.
+@return pointer to foreign key struct if index is defined for foreign
+key, otherwise NULL */
+UNIV_INTERN
+dict_foreign_t*
+dict_table_get_foreign_constraint(
+/*==============================*/
+ dict_table_t* table, /*!< in: InnoDB table */
+ dict_index_t* index) /*!< in: InnoDB index */
+{
+ dict_foreign_t* foreign;
+
+ ut_ad(index != NULL);
+ ut_ad(table != NULL);
+
+ for (foreign = UT_LIST_GET_FIRST(table->foreign_list);
+ foreign;
+ foreign = UT_LIST_GET_NEXT(foreign_list, foreign)) {
+
+ if (foreign->foreign_index == index
+ || foreign->referenced_index == index) {
+
+ return(foreign);
+ }
+ }
+
+ return(NULL);
+}
+
+/*********************************************************************//**
Frees a foreign key struct. */
static
void
dict_foreign_free(
/*==============*/
- dict_foreign_t* foreign) /* in, own: foreign key struct */
+ dict_foreign_t* foreign) /*!< in, own: foreign key struct */
{
mem_heap_free(foreign->heap);
}
-/**************************************************************************
+/**********************************************************************//**
Removes a foreign constraint struct from the dictionary cache. */
static
void
dict_foreign_remove_from_cache(
/*===========================*/
- dict_foreign_t* foreign) /* in, own: foreign constraint */
+ dict_foreign_t* foreign) /*!< in, own: foreign constraint */
{
ut_ad(mutex_own(&(dict_sys->mutex)));
ut_a(foreign);
@@ -1915,16 +2189,16 @@ dict_foreign_remove_from_cache(
dict_foreign_free(foreign);
}
-/**************************************************************************
+/**********************************************************************//**
Looks for the foreign constraint from the foreign and referenced lists
-of a table. */
+of a table.
+@return foreign constraint */
static
dict_foreign_t*
dict_foreign_find(
/*==============*/
- /* out: foreign constraint */
- dict_table_t* table, /* in: table object */
- const char* id) /* in: foreign constraint id */
+ dict_table_t* table, /*!< in: table object */
+ const char* id) /*!< in: foreign constraint id */
{
dict_foreign_t* foreign;
@@ -1955,38 +2229,45 @@ dict_foreign_find(
return(NULL);
}
-#ifndef UNIV_HOTBACKUP
-/*************************************************************************
+/*********************************************************************//**
Tries to find an index whose first fields are the columns in the array,
-in the same order. */
+in the same order and is not marked for deletion and is not the same
+as types_idx.
+@return matching index, NULL if not found */
static
dict_index_t*
dict_foreign_find_index(
/*====================*/
- /* out: matching index, NULL if not found */
- dict_table_t* table, /* in: table */
- const char** columns,/* in: array of column names */
- ulint n_cols, /* in: number of columns */
- dict_index_t* types_idx, /* in: NULL or an index to whose types the
+ dict_table_t* table, /*!< in: table */
+ const char** columns,/*!< in: array of column names */
+ ulint n_cols, /*!< in: number of columns */
+ dict_index_t* types_idx, /*!< in: NULL or an index to whose types the
column types must match */
ibool check_charsets,
- /* in: whether to check charsets.
+ /*!< in: whether to check charsets.
only has an effect if types_idx != NULL */
ulint check_null)
- /* in: nonzero if none of the columns must
+ /*!< in: nonzero if none of the columns must
be declared NOT NULL */
{
dict_index_t* index;
- dict_field_t* field;
- const char* col_name;
- ulint i;
index = dict_table_get_first_index(table);
while (index != NULL) {
- if (dict_index_get_n_fields(index) >= n_cols) {
+ /* Ignore matches that refer to the same instance
+ or the index is to be dropped */
+ if (index->to_be_dropped || types_idx == index) {
+
+ goto next_rec;
+
+ } else if (dict_index_get_n_fields(index) >= n_cols) {
+ ulint i;
for (i = 0; i < n_cols; i++) {
+ dict_field_t* field;
+ const char* col_name;
+
field = dict_index_get_nth_field(index, i);
col_name = dict_table_get_col_name(
@@ -2027,20 +2308,104 @@ dict_foreign_find_index(
}
}
+next_rec:
index = dict_table_get_next_index(index);
}
return(NULL);
}
-/**************************************************************************
+/**********************************************************************//**
+Find an index that is equivalent to the one passed in and is not marked
+for deletion.
+@return index equivalent to foreign->foreign_index, or NULL */
+UNIV_INTERN
+dict_index_t*
+dict_foreign_find_equiv_index(
+/*==========================*/
+ dict_foreign_t* foreign)/*!< in: foreign key */
+{
+ ut_a(foreign != NULL);
+
+ /* Try to find an index which contains the columns as the
+ first fields and in the right order, and the types are the
+ same as in foreign->foreign_index */
+
+ return(dict_foreign_find_index(
+ foreign->foreign_table,
+ foreign->foreign_col_names, foreign->n_fields,
+ foreign->foreign_index, TRUE, /* check types */
+ FALSE/* allow columns to be NULL */));
+}
+
+/**********************************************************************//**
+Returns an index object by matching on the name and column names and
+if more than one index matches return the index with the max id
+@return matching index, NULL if not found */
+UNIV_INTERN
+dict_index_t*
+dict_table_get_index_by_max_id(
+/*===========================*/
+ dict_table_t* table, /*!< in: table */
+ const char* name, /*!< in: the index name to find */
+ const char** columns,/*!< in: array of column names */
+ ulint n_cols) /*!< in: number of columns */
+{
+ dict_index_t* index;
+ dict_index_t* found;
+
+ found = NULL;
+ index = dict_table_get_first_index(table);
+
+ while (index != NULL) {
+ if (ut_strcmp(index->name, name) == 0
+ && dict_index_get_n_ordering_defined_by_user(index)
+ == n_cols) {
+
+ ulint i;
+
+ for (i = 0; i < n_cols; i++) {
+ dict_field_t* field;
+ const char* col_name;
+
+ field = dict_index_get_nth_field(index, i);
+
+ col_name = dict_table_get_col_name(
+ table, dict_col_get_no(field->col));
+
+ if (0 != innobase_strcasecmp(
+ columns[i], col_name)) {
+
+ break;
+ }
+ }
+
+ if (i == n_cols) {
+ /* We found a matching index, select
+ the index with the higher id*/
+
+ if (!found
+ || ut_dulint_cmp(index->id, found->id) > 0) {
+
+ found = index;
+ }
+ }
+ }
+
+ index = dict_table_get_next_index(index);
+ }
+
+ return(found);
+}
+
+/**********************************************************************//**
Report an error in a foreign key definition. */
static
void
dict_foreign_error_report_low(
/*==========================*/
- FILE* file, /* in: output stream */
- const char* name) /* in: table name */
+ FILE* file, /*!< in: output stream */
+ const char* name) /*!< in: table name */
{
rewind(file);
ut_print_timestamp(file);
@@ -2048,15 +2413,15 @@ dict_foreign_error_report_low(
name);
}
-/**************************************************************************
+/**********************************************************************//**
Report an error in a foreign key definition. */
static
void
dict_foreign_error_report(
/*======================*/
- FILE* file, /* in: output stream */
- dict_foreign_t* fk, /* in: foreign key constraint */
- const char* msg) /* in: the error message */
+ FILE* file, /*!< in: output stream */
+ dict_foreign_t* fk, /*!< in: foreign key constraint */
+ const char* msg) /*!< in: the error message */
{
mutex_enter(&dict_foreign_err_mutex);
dict_foreign_error_report_low(file, fk->foreign_table_name);
@@ -2068,26 +2433,25 @@ dict_foreign_error_report(
fputs("The index in the foreign key in table is ", file);
ut_print_name(file, NULL, FALSE, fk->foreign_index->name);
fputs("\n"
- "See http://dev.mysql.com/doc/refman/5.1/en/"
- "innodb-foreign-key-constraints.html\n"
+ "See " REFMAN "innodb-foreign-key-constraints.html\n"
"for correct foreign key definition.\n",
file);
}
mutex_exit(&dict_foreign_err_mutex);
}
-/**************************************************************************
+/**********************************************************************//**
Adds a foreign key constraint object to the dictionary cache. May free
the object if there already is an object with the same identifier in.
At least one of the foreign table and the referenced table must already
-be in the dictionary cache! */
-
+be in the dictionary cache!
+@return DB_SUCCESS or error code */
+UNIV_INTERN
ulint
dict_foreign_add_to_cache(
/*======================*/
- /* out: DB_SUCCESS or error code */
- dict_foreign_t* foreign, /* in, own: foreign key constraint */
- ibool check_charsets) /* in: TRUE=check charset
+ dict_foreign_t* foreign, /*!< in, own: foreign key constraint */
+ ibool check_charsets) /*!< in: TRUE=check charset
compatibility */
{
dict_table_t* for_table;
@@ -2124,7 +2488,7 @@ dict_foreign_add_to_cache(
if (for_in_cache->referenced_table == NULL && ref_table) {
index = dict_foreign_find_index(
ref_table,
- (const char**) for_in_cache->referenced_col_names,
+ for_in_cache->referenced_col_names,
for_in_cache->n_fields, for_in_cache->foreign_index,
check_charsets, FALSE);
@@ -2156,7 +2520,7 @@ dict_foreign_add_to_cache(
if (for_in_cache->foreign_table == NULL && for_table) {
index = dict_foreign_find_index(
for_table,
- (const char**) for_in_cache->foreign_col_names,
+ for_in_cache->foreign_col_names,
for_in_cache->n_fields,
for_in_cache->referenced_index, check_charsets,
for_in_cache->type
@@ -2199,17 +2563,17 @@ dict_foreign_add_to_cache(
return(DB_SUCCESS);
}
-/*************************************************************************
+/*********************************************************************//**
Scans from pointer onwards. Stops if is at the start of a copy of
'string' where characters are compared without case sensitivity, and
-only outside `` or "" quotes. Stops also at '\0'. */
-
+only outside `` or "" quotes. Stops also at NUL.
+@return scanned up to this */
+static
const char*
dict_scan_to(
/*=========*/
- /* out: scanned up to this */
- const char* ptr, /* in: scan from */
- const char* string) /* in: look for this */
+ const char* ptr, /*!< in: scan from */
+ const char* string) /*!< in: look for this */
{
char quote = '\0';
@@ -2242,19 +2606,19 @@ nomatch:
return(ptr);
}
-/*************************************************************************
-Accepts a specified string. Comparisons are case-insensitive. */
+/*********************************************************************//**
+Accepts a specified string. Comparisons are case-insensitive.
+@return if string was accepted, the pointer is moved after that, else
+ptr is returned */
static
const char*
dict_accept(
/*========*/
- /* out: if string was accepted, the pointer
- is moved after that, else ptr is returned */
- struct charset_info_st* cs,/* in: the character set of ptr */
- const char* ptr, /* in: scan from this */
- const char* string, /* in: accept only this string as the next
+ struct charset_info_st* cs,/*!< in: the character set of ptr */
+ const char* ptr, /*!< in: scan from this */
+ const char* string, /*!< in: accept only this string as the next
non-whitespace string */
- ibool* success)/* out: TRUE if accepted */
+ ibool* success)/*!< out: TRUE if accepted */
{
const char* old_ptr = ptr;
const char* old_ptr2;
@@ -2278,25 +2642,25 @@ dict_accept(
return(ptr + ut_strlen(string));
}
-/*************************************************************************
+/*********************************************************************//**
Scans an id. For the lexical definition of an 'id', see the code below.
-Strips backquotes or double quotes from around the id. */
+Strips backquotes or double quotes from around the id.
+@return scanned to */
static
const char*
dict_scan_id(
/*=========*/
- /* out: scanned to */
- struct charset_info_st* cs,/* in: the character set of ptr */
- const char* ptr, /* in: scanned to */
- mem_heap_t* heap, /* in: heap where to allocate the id
+ struct charset_info_st* cs,/*!< in: the character set of ptr */
+ const char* ptr, /*!< in: scanned to */
+ mem_heap_t* heap, /*!< in: heap where to allocate the id
(NULL=id will not be allocated, but it
will point to string near ptr) */
- const char** id, /* out,own: the id; NULL if no id was
+ const char** id, /*!< out,own: the id; NULL if no id was
scannable */
- ibool table_id,/* in: TRUE=convert the allocated id
+ ibool table_id,/*!< in: TRUE=convert the allocated id
as a table name; FALSE=convert to UTF-8 */
ibool accept_also_dot)
- /* in: TRUE if also a dot can appear in a
+ /*!< in: TRUE if also a dot can appear in a
non-quoted id; in a quoted id it can appear
always */
{
@@ -2378,7 +2742,7 @@ convert_id:
len = 3 * len + 1;
*id = dst = mem_heap_alloc(heap, len);
- innobase_convert_from_id(dst, str, len);
+ innobase_convert_from_id(cs, dst, str, len);
} else if (!strncmp(str, srv_mysql50_table_name_prefix,
sizeof srv_mysql50_table_name_prefix)) {
/* This is a pre-5.1 table name
@@ -2392,26 +2756,26 @@ convert_id:
len = 5 * len + 1;
*id = dst = mem_heap_alloc(heap, len);
- innobase_convert_from_table_id(dst, str, len);
+ innobase_convert_from_table_id(cs, dst, str, len);
}
return(ptr);
}
-/*************************************************************************
-Tries to scan a column name. */
+/*********************************************************************//**
+Tries to scan a column name.
+@return scanned to */
static
const char*
dict_scan_col(
/*==========*/
- /* out: scanned to */
- struct charset_info_st* cs, /* in: the character set of ptr */
- const char* ptr, /* in: scanned to */
- ibool* success,/* out: TRUE if success */
- dict_table_t* table, /* in: table in which the column is */
- const dict_col_t** column, /* out: pointer to column if success */
- mem_heap_t* heap, /* in: heap where to allocate */
- const char** name) /* out,own: the column name;
+ struct charset_info_st* cs, /*!< in: the character set of ptr */
+ const char* ptr, /*!< in: scanned to */
+ ibool* success,/*!< out: TRUE if success */
+ dict_table_t* table, /*!< in: table in which the column is */
+ const dict_col_t** column, /*!< out: pointer to column if success */
+ mem_heap_t* heap, /*!< in: heap where to allocate */
+ const char** name) /*!< out,own: the column name;
NULL if no name was scannable */
{
ulint i;
@@ -2449,20 +2813,20 @@ dict_scan_col(
return(ptr);
}
-/*************************************************************************
-Scans a table name from an SQL string. */
+/*********************************************************************//**
+Scans a table name from an SQL string.
+@return scanned to */
static
const char*
dict_scan_table_name(
/*=================*/
- /* out: scanned to */
- struct charset_info_st* cs,/* in: the character set of ptr */
- const char* ptr, /* in: scanned to */
- dict_table_t** table, /* out: table object or NULL */
- const char* name, /* in: foreign key table name */
- ibool* success,/* out: TRUE if ok name found */
- mem_heap_t* heap, /* in: heap where to allocate the id */
- const char** ref_name)/* out,own: the table name;
+ struct charset_info_st* cs,/*!< in: the character set of ptr */
+ const char* ptr, /*!< in: scanned to */
+ dict_table_t** table, /*!< out: table object or NULL */
+ const char* name, /*!< in: foreign key table name */
+ ibool* success,/*!< out: TRUE if ok name found */
+ mem_heap_t* heap, /*!< in: heap where to allocate the id */
+ const char** ref_name)/*!< out,own: the table name;
NULL if no name was scannable */
{
const char* database_name = NULL;
@@ -2548,16 +2912,16 @@ dict_scan_table_name(
return(ptr);
}
-/*************************************************************************
-Skips one id. The id is allowed to contain also '.'. */
+/*********************************************************************//**
+Skips one id. The id is allowed to contain also '.'.
+@return scanned to */
static
const char*
dict_skip_word(
/*===========*/
- /* out: scanned to */
- struct charset_info_st* cs,/* in: the character set of ptr */
- const char* ptr, /* in: scanned to */
- ibool* success)/* out: TRUE if success, FALSE if just spaces
+ struct charset_info_st* cs,/*!< in: the character set of ptr */
+ const char* ptr, /*!< in: scanned to */
+ ibool* success)/*!< out: TRUE if success, FALSE if just spaces
left in string or a syntax error */
{
const char* start;
@@ -2573,20 +2937,19 @@ dict_skip_word(
return(ptr);
}
-/*************************************************************************
+/*********************************************************************//**
Removes MySQL comments from an SQL string. A comment is either
(a) '#' to the end of the line,
-(b) '--' to the end of the line, or
-(c) '' till the next '' (like the familiar
-C comment syntax). */
+(b) '--[space]' to the end of the line, or
+(c) '[slash][asterisk]' till the next '[asterisk][slash]' (like the familiar
+C comment syntax).
+@return own: SQL string stripped from comments; the caller must free
+this with mem_free()! */
static
char*
dict_strip_comments(
/*================*/
- /* out, own: SQL string stripped from
- comments; the caller must free this
- with mem_free()! */
- const char* sql_string) /* in: SQL string */
+ const char* sql_string) /*!< in: SQL string */
{
char* str;
const char* sptr;
@@ -2616,7 +2979,7 @@ scan_more:
} else if (quote) {
/* Within quotes: do not look for
starting quotes or comments. */
- } else if (*sptr == '"' || *sptr == '`') {
+ } else if (*sptr == '"' || *sptr == '`' || *sptr == '\'') {
/* Starting quote: remember the quote character. */
quote = *sptr;
} else if (*sptr == '#'
@@ -2660,17 +3023,16 @@ scan_more:
}
}
-/*************************************************************************
-Finds the highest for foreign key constraints of the table. Looks
+/*********************************************************************//**
+Finds the highest [number] for foreign key constraints of the table. Looks
only at the >= 4.0.18-format id's, which are of the form
-databasename/tablename_ibfk_. */
+databasename/tablename_ibfk_[number].
+@return highest number, 0 if table has no new format foreign key constraints */
static
ulint
dict_table_get_highest_foreign_id(
/*==============================*/
- /* out: highest number, 0 if table has no new
- format foreign key constraints */
- dict_table_t* table) /* in: table in the dictionary memory cache */
+ dict_table_t* table) /*!< in: table in the dictionary memory cache */
{
dict_foreign_t* foreign;
char* endp;
@@ -2709,19 +3071,19 @@ dict_table_get_highest_foreign_id(
return(biggest_id);
}
-/*************************************************************************
+/*********************************************************************//**
Reports a simple foreign key create clause syntax error. */
static
void
dict_foreign_report_syntax_err(
/*===========================*/
- const char* name, /* in: table name */
+ const char* name, /*!< in: table name */
const char* start_of_latest_foreign,
- /* in: start of the foreign key clause
+ /*!< in: start of the foreign key clause
in the SQL string */
- const char* ptr) /* in: place of the syntax error */
+ const char* ptr) /*!< in: place of the syntax error */
{
- FILE* ef = dict_foreign_err_file;
+ FILE* ef = dict_foreign_err_file;
mutex_enter(&dict_foreign_err_mutex);
dict_foreign_error_report_low(ef, name);
@@ -2730,31 +3092,31 @@ dict_foreign_report_syntax_err(
mutex_exit(&dict_foreign_err_mutex);
}
-/*************************************************************************
+/*********************************************************************//**
Scans a table create SQL string and adds to the data dictionary the foreign
key constraints declared in the string. This function should be called after
the indexes for a table have been created. Each foreign key constraint must
be accompanied with indexes in both participating tables. The indexes are
-allowed to contain more fields than mentioned in the constraint. */
+allowed to contain more fields than mentioned in the constraint.
+@return error code or DB_SUCCESS */
static
ulint
dict_create_foreign_constraints_low(
/*================================*/
- /* out: error code or DB_SUCCESS */
- trx_t* trx, /* in: transaction */
- mem_heap_t* heap, /* in: memory heap */
- struct charset_info_st* cs,/* in: the character set of sql_string */
+ trx_t* trx, /*!< in: transaction */
+ mem_heap_t* heap, /*!< in: memory heap */
+ struct charset_info_st* cs,/*!< in: the character set of sql_string */
const char* sql_string,
- /* in: CREATE TABLE or ALTER TABLE statement
+ /*!< in: CREATE TABLE or ALTER TABLE statement
where foreign keys are declared like:
FOREIGN KEY (a, b) REFERENCES table2(c, d),
table2 can be written also with the database
name before it: test.table2; the default
database is the database of parameter name */
- const char* name, /* in: table full name in the normalized form
+ const char* name, /*!< in: table full name in the normalized form
database_name/table_name */
ibool reject_fks)
- /* in: if TRUE, fail with error code
+ /*!< in: if TRUE, fail with error code
DB_CANNOT_ADD_CONSTRAINT if any foreign
keys are found. */
{
@@ -2828,8 +3190,8 @@ dict_create_foreign_constraints_low(
}
/* Starting from 4.0.18 and 4.1.2, we generate foreign key id's in the
- format databasename/tablename_ibfk_, where is local
- to the table; look for the highest for table_to_alter, so
+ format databasename/tablename_ibfk_[number], where [number] is local
+ to the table; look for the highest [number] for table_to_alter, so
that we can assign to new constraints higher numbers. */
/* If we are altering a temporary table, the table name after ALTER
@@ -2989,8 +3351,7 @@ col_loop1:
ut_print_name(ef, NULL, TRUE, name);
fprintf(ef, " where the columns appear\n"
"as the first columns. Constraint:\n%s\n"
- "See http://dev.mysql.com/doc/refman/5.1/en/"
- "innodb-foreign-key-constraints.html\n"
+ "See " REFMAN "innodb-foreign-key-constraints.html\n"
"for correct foreign key definition.\n",
start_of_latest_foreign);
mutex_exit(&dict_foreign_err_mutex);
@@ -3270,7 +3631,7 @@ try_find_index:
" and such columns in old tables\n"
"cannot be referenced by such columns"
" in new tables.\n"
- "See http://dev.mysql.com/doc/refman/5.1/en/"
+ "See " REFMAN
"innodb-foreign-key-constraints.html\n"
"for correct foreign key definition.\n",
start_of_latest_foreign);
@@ -3309,38 +3670,19 @@ try_find_index:
goto loop;
}
-/**************************************************************************
-Determines whether a string starts with the specified keyword. */
-
-ibool
-dict_str_starts_with_keyword(
-/*=========================*/
- /* out: TRUE if str starts
- with keyword */
- void* mysql_thd, /* in: MySQL thread handle */
- const char* str, /* in: string to scan for keyword */
- const char* keyword) /* in: keyword to look for */
-{
- struct charset_info_st* cs = innobase_get_charset(mysql_thd);
- ibool success;
-
- dict_accept(cs, str, keyword, &success);
- return(success);
-}
-
-/*************************************************************************
+/*********************************************************************//**
Scans a table create SQL string and adds to the data dictionary the foreign
key constraints declared in the string. This function should be called after
the indexes for a table have been created. Each foreign key constraint must
be accompanied with indexes in both participating tables. The indexes are
-allowed to contain more fields than mentioned in the constraint. */
-
+allowed to contain more fields than mentioned in the constraint.
+@return error code or DB_SUCCESS */
+UNIV_INTERN
ulint
dict_create_foreign_constraints(
/*============================*/
- /* out: error code or DB_SUCCESS */
- trx_t* trx, /* in: transaction */
- const char* sql_string, /* in: table create statement where
+ trx_t* trx, /*!< in: transaction */
+ const char* sql_string, /*!< in: table create statement where
foreign keys are declared like:
FOREIGN KEY (a, b) REFERENCES
table2(c, d), table2 can be written
@@ -3348,10 +3690,10 @@ dict_create_foreign_constraints(
name before it: test.table2; the
default database id the database of
parameter name */
- const char* name, /* in: table full name in the
+ const char* name, /*!< in: table full name in the
normalized form
database_name/table_name */
- ibool reject_fks) /* in: if TRUE, fail with error
+ ibool reject_fks) /*!< in: if TRUE, fail with error
code DB_CANNOT_ADD_CONSTRAINT if
any foreign keys are found. */
{
@@ -3375,23 +3717,21 @@ dict_create_foreign_constraints(
return(err);
}
-/**************************************************************************
-Parses the CONSTRAINT id's to be dropped in an ALTER TABLE statement. */
-
+/**********************************************************************//**
+Parses the CONSTRAINT id's to be dropped in an ALTER TABLE statement.
+@return DB_SUCCESS or DB_CANNOT_DROP_CONSTRAINT if syntax error or the
+constraint id does not match */
+UNIV_INTERN
ulint
dict_foreign_parse_drop_constraints(
/*================================*/
- /* out: DB_SUCCESS or
- DB_CANNOT_DROP_CONSTRAINT if
- syntax error or the constraint
- id does not match */
- mem_heap_t* heap, /* in: heap from which we can
+ mem_heap_t* heap, /*!< in: heap from which we can
allocate memory */
- trx_t* trx, /* in: transaction */
- dict_table_t* table, /* in: table */
- ulint* n, /* out: number of constraints
+ trx_t* trx, /*!< in: transaction */
+ dict_table_t* table, /*!< in: table */
+ ulint* n, /*!< out: number of constraints
to drop */
- const char*** constraints_to_drop) /* out: id's of the
+ const char*** constraints_to_drop) /*!< out: id's of the
constraints to drop */
{
dict_foreign_t* foreign;
@@ -3509,19 +3849,33 @@ syntax_error:
return(DB_CANNOT_DROP_CONSTRAINT);
}
-#endif /* UNIV_HOTBACKUP */
/*==================== END OF FOREIGN KEY PROCESSING ====================*/
-#ifdef UNIV_DEBUG
-/**************************************************************************
-Returns an index object if it is found in the dictionary cache. */
+/**********************************************************************//**
+Returns an index object if it is found in the dictionary cache.
+Assumes that dict_sys->mutex is already being held.
+@return index, NULL if not found */
+UNIV_INTERN
+dict_index_t*
+dict_index_get_if_in_cache_low(
+/*===========================*/
+ dulint index_id) /*!< in: index id */
+{
+ ut_ad(mutex_own(&(dict_sys->mutex)));
+ return(dict_index_find_on_id_low(index_id));
+}
+
+#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
+/**********************************************************************//**
+Returns an index object if it is found in the dictionary cache.
+@return index, NULL if not found */
+UNIV_INTERN
dict_index_t*
dict_index_get_if_in_cache(
/*=======================*/
- /* out: index, NULL if not found */
- dulint index_id) /* in: index id */
+ dulint index_id) /*!< in: index id */
{
dict_index_t* index;
@@ -3531,25 +3885,25 @@ dict_index_get_if_in_cache(
mutex_enter(&(dict_sys->mutex));
- index = dict_index_find_on_id_low(index_id);
+ index = dict_index_get_if_in_cache_low(index_id);
mutex_exit(&(dict_sys->mutex));
return(index);
}
-#endif /* UNIV_DEBUG */
+#endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
#ifdef UNIV_DEBUG
-/**************************************************************************
+/**********************************************************************//**
Checks that a tuple has n_fields_cmp value in a sensible range, so that
-no comparison can occur with the page number field in a node pointer. */
-
+no comparison can occur with the page number field in a node pointer.
+@return TRUE if ok */
+UNIV_INTERN
ibool
dict_index_check_search_tuple(
/*==========================*/
- /* out: TRUE if ok */
- dict_index_t* index, /* in: index tree */
- dtuple_t* tuple) /* in: tuple used in a search */
+ const dict_index_t* index, /*!< in: index tree */
+ const dtuple_t* tuple) /*!< in: tuple used in a search */
{
ut_a(index);
ut_a(dtuple_get_n_fields_cmp(tuple)
@@ -3558,20 +3912,22 @@ dict_index_check_search_tuple(
}
#endif /* UNIV_DEBUG */
-/**************************************************************************
-Builds a node pointer out of a physical record and a page number. */
-
+/**********************************************************************//**
+Builds a node pointer out of a physical record and a page number.
+@return own: node pointer */
+UNIV_INTERN
dtuple_t*
dict_index_build_node_ptr(
/*======================*/
- /* out, own: node pointer */
- dict_index_t* index, /* in: index tree */
- rec_t* rec, /* in: record for which to build node
- pointer */
- ulint page_no,/* in: page number to put in node pointer */
- mem_heap_t* heap, /* in: memory heap where pointer created */
- ulint level) /* in: level of rec in tree: 0 means leaf
- level */
+ const dict_index_t* index, /*!< in: index */
+ const rec_t* rec, /*!< in: record for which to build node
+ pointer */
+ ulint page_no,/*!< in: page number to put in node
+ pointer */
+ mem_heap_t* heap, /*!< in: memory heap where pointer
+ created */
+ ulint level) /*!< in: level of rec in tree:
+ 0 means leaf level */
{
dtuple_t* tuple;
dfield_t* field;
@@ -3625,20 +3981,21 @@ dict_index_build_node_ptr(
return(tuple);
}
-/**************************************************************************
+/**********************************************************************//**
Copies an initial segment of a physical record, long enough to specify an
-index entry uniquely. */
-
+index entry uniquely.
+@return pointer to the prefix record */
+UNIV_INTERN
rec_t*
dict_index_copy_rec_order_prefix(
/*=============================*/
- /* out: pointer to the prefix record */
- dict_index_t* index, /* in: index tree */
- rec_t* rec, /* in: record for which to copy prefix */
- ulint* n_fields,/* out: number of fields copied */
- byte** buf, /* in/out: memory buffer for the copied prefix,
- or NULL */
- ulint* buf_size)/* in/out: buffer size */
+ const dict_index_t* index, /*!< in: index */
+ const rec_t* rec, /*!< in: record for which to
+ copy prefix */
+ ulint* n_fields,/*!< out: number of fields copied */
+ byte** buf, /*!< in/out: memory buffer for the
+ copied prefix, or NULL */
+ ulint* buf_size)/*!< in/out: buffer size */
{
ulint n;
@@ -3655,17 +4012,17 @@ dict_index_copy_rec_order_prefix(
return(rec_copy_prefix_to_buf(rec, index, n, buf, buf_size));
}
-/**************************************************************************
-Builds a typed data tuple out of a physical record. */
-
+/**********************************************************************//**
+Builds a typed data tuple out of a physical record.
+@return own: data tuple */
+UNIV_INTERN
dtuple_t*
dict_index_build_data_tuple(
/*========================*/
- /* out, own: data tuple */
- dict_index_t* index, /* in: index tree */
- rec_t* rec, /* in: record for which to build data tuple */
- ulint n_fields,/* in: number of data fields */
- mem_heap_t* heap) /* in: memory heap where tuple created */
+ dict_index_t* index, /*!< in: index tree */
+ rec_t* rec, /*!< in: record for which to build data tuple */
+ ulint n_fields,/*!< in: number of data fields */
+ mem_heap_t* heap) /*!< in: memory heap where tuple created */
{
dtuple_t* tuple;
@@ -3683,24 +4040,25 @@ dict_index_build_data_tuple(
return(tuple);
}
-/*************************************************************************
+/*********************************************************************//**
Calculates the minimum record length in an index. */
-
+UNIV_INTERN
ulint
dict_index_calc_min_rec_len(
/*========================*/
- dict_index_t* index) /* in: index */
+ const dict_index_t* index) /*!< in: index */
{
ulint sum = 0;
ulint i;
+ ulint comp = dict_table_is_comp(index->table);
- if (dict_table_is_comp(index->table)) {
+ if (comp) {
ulint nullable = 0;
sum = REC_N_NEW_EXTRA_BYTES;
for (i = 0; i < dict_index_get_n_fields(index); i++) {
const dict_col_t* col
= dict_index_get_nth_col(index, i);
- ulint size = dict_col_get_fixed_size(col);
+ ulint size = dict_col_get_fixed_size(col, comp);
sum += size;
if (!size) {
size = col->len;
@@ -3719,7 +4077,7 @@ dict_index_calc_min_rec_len(
for (i = 0; i < dict_index_get_n_fields(index); i++) {
sum += dict_col_get_fixed_size(
- dict_index_get_nth_col(index, i));
+ dict_index_get_nth_col(index, i), comp);
}
if (sum > 127) {
@@ -3733,16 +4091,16 @@ dict_index_calc_min_rec_len(
return(sum);
}
-/*************************************************************************
+/*********************************************************************//**
Calculates new estimates for table and index statistics. The statistics
are used in query optimization. */
-
+UNIV_INTERN
void
dict_update_statistics_low(
/*=======================*/
- dict_table_t* table, /* in: table */
+ dict_table_t* table, /*!< in/out: table */
ibool has_dict_mutex __attribute__((unused)))
- /* in: TRUE if the caller has the
+ /*!< in: TRUE if the caller has the
dictionary mutex */
{
dict_index_t* index;
@@ -3755,8 +4113,7 @@ dict_update_statistics_low(
" InnoDB: cannot calculate statistics for table %s\n"
"InnoDB: because the .ibd file is missing. For help,"
" please refer to\n"
- "InnoDB: http://dev.mysql.com/doc/refman/5.1/en/"
- "innodb-troubleshooting.html\n",
+ "InnoDB: " REFMAN "innodb-troubleshooting.html\n",
table->name);
return;
@@ -3817,37 +4174,25 @@ dict_update_statistics_low(
table->stat_modified_counter = 0;
}
-/*************************************************************************
+/*********************************************************************//**
Calculates new estimates for table and index statistics. The statistics
are used in query optimization. */
-
+UNIV_INTERN
void
dict_update_statistics(
/*===================*/
- dict_table_t* table) /* in: table */
+ dict_table_t* table) /*!< in/out: table */
{
dict_update_statistics_low(table, FALSE);
}
-/**************************************************************************
-A noninlined version of dict_table_get_low. */
-
-dict_table_t*
-dict_table_get_low_noninlined(
-/*==========================*/
- /* out: table, NULL if not found */
- const char* table_name) /* in: table name */
-{
- return(dict_table_get_low(table_name));
-}
-
-/**************************************************************************
+/**********************************************************************//**
Prints info of a foreign key constraint. */
static
void
dict_foreign_print_low(
/*===================*/
- dict_foreign_t* foreign) /* in: foreign key constraint */
+ dict_foreign_t* foreign) /*!< in: foreign key constraint */
{
ulint i;
@@ -3871,26 +4216,26 @@ dict_foreign_print_low(
fputs(" )\n", stderr);
}
-/**************************************************************************
+/**********************************************************************//**
Prints a table data. */
-
+UNIV_INTERN
void
dict_table_print(
/*=============*/
- dict_table_t* table) /* in: table */
+ dict_table_t* table) /*!< in: table */
{
mutex_enter(&(dict_sys->mutex));
dict_table_print_low(table);
mutex_exit(&(dict_sys->mutex));
}
-/**************************************************************************
+/**********************************************************************//**
Prints a table data when we know the table name. */
-
+UNIV_INTERN
void
dict_table_print_by_name(
/*=====================*/
- const char* name)
+ const char* name) /*!< in: table name */
{
dict_table_t* table;
@@ -3904,13 +4249,13 @@ dict_table_print_by_name(
mutex_exit(&(dict_sys->mutex));
}
-/**************************************************************************
+/**********************************************************************//**
Prints a table data. */
-
+UNIV_INTERN
void
dict_table_print_low(
/*=================*/
- dict_table_t* table) /* in: table */
+ dict_table_t* table) /*!< in: table */
{
dict_index_t* index;
dict_foreign_t* foreign;
@@ -3922,17 +4267,18 @@ dict_table_print_low(
fprintf(stderr,
"--------------------------------------\n"
- "TABLE: name %s, id %lu %lu, columns %lu, indexes %lu,"
- " appr.rows %lu\n"
+ "TABLE: name %s, id %lu %lu, flags %lx, columns %lu,"
+ " indexes %lu, appr.rows %lu\n"
" COLUMNS: ",
table->name,
(ulong) ut_dulint_get_high(table->id),
(ulong) ut_dulint_get_low(table->id),
+ (ulong) table->flags,
(ulong) table->n_cols,
(ulong) UT_LIST_GET_LEN(table->indexes),
(ulong) table->stat_n_rows);
- for (i = 0; i + 1 < (ulint) table->n_cols; i++) {
+ for (i = 0; i < (ulint) table->n_cols; i++) {
dict_col_print_low(table, dict_table_get_nth_col(table, i));
fputs("; ", stderr);
}
@@ -3961,14 +4307,14 @@ dict_table_print_low(
}
}
-/**************************************************************************
+/**********************************************************************//**
Prints a column data. */
static
void
dict_col_print_low(
/*===============*/
- const dict_table_t* table, /* in: table */
- const dict_col_t* col) /* in: column */
+ const dict_table_t* table, /*!< in: table */
+ const dict_col_t* col) /*!< in: column */
{
dtype_t type;
@@ -3981,16 +4327,17 @@ dict_col_print_low(
dtype_print(&type);
}
-/**************************************************************************
+/**********************************************************************//**
Prints an index data. */
static
void
dict_index_print_low(
/*=================*/
- dict_index_t* index) /* in: index */
+ dict_index_t* index) /*!< in: index */
{
- ib_longlong n_vals;
+ ib_int64_t n_vals;
ulint i;
+ const char* type_string;
ut_ad(mutex_own(&(dict_sys->mutex)));
@@ -4001,6 +4348,14 @@ dict_index_print_low(
n_vals = index->stat_n_diff_key_vals[1];
}
+ if (dict_index_is_clust(index)) {
+ type_string = "clustered index";
+ } else if (dict_index_is_unique(index)) {
+ type_string = "unique index";
+ } else {
+ type_string = "secondary index";
+ }
+
fprintf(stderr,
" INDEX: name %s, id %lu %lu, fields %lu/%lu,"
" uniq %lu, type %lu\n"
@@ -4032,13 +4387,13 @@ dict_index_print_low(
#endif /* UNIV_BTR_PRINT */
}
-/**************************************************************************
+/**********************************************************************//**
Prints a field data. */
static
void
dict_field_print_low(
/*=================*/
- dict_field_t* field) /* in: field */
+ dict_field_t* field) /*!< in: field */
{
ut_ad(mutex_own(&(dict_sys->mutex)));
@@ -4049,17 +4404,17 @@ dict_field_print_low(
}
}
-/**************************************************************************
+/**********************************************************************//**
Outputs info on a foreign key of a table in a format suitable for
CREATE TABLE. */
-
+UNIV_INTERN
void
dict_print_info_on_foreign_key_in_create_format(
/*============================================*/
- FILE* file, /* in: file where to print */
- trx_t* trx, /* in: transaction */
- dict_foreign_t* foreign, /* in: foreign key constraint */
- ibool add_newline) /* in: whether to add a newline */
+ FILE* file, /*!< in: file where to print */
+ trx_t* trx, /*!< in: transaction */
+ dict_foreign_t* foreign, /*!< in: foreign key constraint */
+ ibool add_newline) /*!< in: whether to add a newline */
{
const char* stripped_id;
ulint i;
@@ -4147,19 +4502,19 @@ dict_print_info_on_foreign_key_in_create_format(
}
}
-/**************************************************************************
+/**********************************************************************//**
Outputs info on foreign keys of a table. */
-
+UNIV_INTERN
void
dict_print_info_on_foreign_keys(
/*============================*/
- ibool create_table_format, /* in: if TRUE then print in
+ ibool create_table_format, /*!< in: if TRUE then print in
a format suitable to be inserted into
a CREATE TABLE, otherwise in the format
of SHOW TABLE STATUS */
- FILE* file, /* in: file where to print */
- trx_t* trx, /* in: transaction */
- dict_table_t* table) /* in: table */
+ FILE* file, /*!< in: file where to print */
+ trx_t* trx, /*!< in: transaction */
+ dict_table_t* table) /*!< in: table */
{
dict_foreign_t* foreign;
@@ -4237,17 +4592,180 @@ dict_print_info_on_foreign_keys(
mutex_exit(&(dict_sys->mutex));
}
-/************************************************************************
+/********************************************************************//**
Displays the names of the index and the table. */
+UNIV_INTERN
void
dict_index_name_print(
/*==================*/
- FILE* file, /* in: output stream */
- trx_t* trx, /* in: transaction */
- const dict_index_t* index) /* in: index to print */
+ FILE* file, /*!< in: output stream */
+ trx_t* trx, /*!< in: transaction */
+ const dict_index_t* index) /*!< in: index to print */
{
fputs("index ", file);
ut_print_name(file, trx, FALSE, index->name);
fputs(" of table ", file);
ut_print_name(file, trx, TRUE, index->table_name);
}
+#endif /* !UNIV_HOTBACKUP */
+
+/**********************************************************************//**
+Inits dict_ind_redundant and dict_ind_compact. */
+UNIV_INTERN
+void
+dict_ind_init(void)
+/*===============*/
+{
+ dict_table_t* table;
+
+ /* create dummy table and index for REDUNDANT infimum and supremum */
+ table = dict_mem_table_create("SYS_DUMMY1", DICT_HDR_SPACE, 1, 0);
+ dict_mem_table_add_col(table, NULL, NULL, DATA_CHAR,
+ DATA_ENGLISH | DATA_NOT_NULL, 8);
+
+ dict_ind_redundant = dict_mem_index_create("SYS_DUMMY1", "SYS_DUMMY1",
+ DICT_HDR_SPACE, 0, 1);
+ dict_index_add_col(dict_ind_redundant, table,
+ dict_table_get_nth_col(table, 0), 0);
+ dict_ind_redundant->table = table;
+ /* create dummy table and index for COMPACT infimum and supremum */
+ table = dict_mem_table_create("SYS_DUMMY2",
+ DICT_HDR_SPACE, 1, DICT_TF_COMPACT);
+ dict_mem_table_add_col(table, NULL, NULL, DATA_CHAR,
+ DATA_ENGLISH | DATA_NOT_NULL, 8);
+ dict_ind_compact = dict_mem_index_create("SYS_DUMMY2", "SYS_DUMMY2",
+ DICT_HDR_SPACE, 0, 1);
+ dict_index_add_col(dict_ind_compact, table,
+ dict_table_get_nth_col(table, 0), 0);
+ dict_ind_compact->table = table;
+
+ /* avoid ut_ad(index->cached) in dict_index_get_n_unique_in_tree */
+ dict_ind_redundant->cached = dict_ind_compact->cached = TRUE;
+}
+
+#ifndef UNIV_HOTBACKUP
+/**********************************************************************//**
+Get index by name
+@return index, NULL if does not exist */
+UNIV_INTERN
+dict_index_t*
+dict_table_get_index_on_name(
+/*=========================*/
+ dict_table_t* table, /*!< in: table */
+ const char* name) /*!< in: name of the index to find */
+{
+ dict_index_t* index;
+
+ index = dict_table_get_first_index(table);
+
+ while (index != NULL) {
+ if (ut_strcmp(index->name, name) == 0) {
+
+ return(index);
+ }
+
+ index = dict_table_get_next_index(index);
+ }
+
+ return(NULL);
+
+}
+
+/**********************************************************************//**
+Replace the index passed in with another equivalent index in the tables
+foreign key list. */
+UNIV_INTERN
+void
+dict_table_replace_index_in_foreign_list(
+/*=====================================*/
+ dict_table_t* table, /*!< in/out: table */
+ dict_index_t* index) /*!< in: index to be replaced */
+{
+ dict_foreign_t* foreign;
+
+ for (foreign = UT_LIST_GET_FIRST(table->foreign_list);
+ foreign;
+ foreign = UT_LIST_GET_NEXT(foreign_list, foreign)) {
+
+ if (foreign->foreign_index == index) {
+ dict_index_t* new_index
+ = dict_foreign_find_equiv_index(foreign);
+ ut_a(new_index);
+
+ foreign->foreign_index = new_index;
+ }
+ }
+}
+
+/**********************************************************************//**
+In case there is more than one index with the same name return the index
+with the min(id).
+@return index, NULL if does not exist */
+UNIV_INTERN
+dict_index_t*
+dict_table_get_index_on_name_and_min_id(
+/*=====================================*/
+ dict_table_t* table, /*!< in: table */
+ const char* name) /*!< in: name of the index to find */
+{
+ dict_index_t* index;
+ dict_index_t* min_index; /* Index with matching name and min(id) */
+
+ min_index = NULL;
+ index = dict_table_get_first_index(table);
+
+ while (index != NULL) {
+ if (ut_strcmp(index->name, name) == 0) {
+ if (!min_index
+ || ut_dulint_cmp(index->id, min_index->id) < 0) {
+
+ min_index = index;
+ }
+ }
+
+ index = dict_table_get_next_index(index);
+ }
+
+ return(min_index);
+
+}
+
+#ifdef UNIV_DEBUG
+/**********************************************************************//**
+Check for duplicate index entries in a table [using the index name] */
+UNIV_INTERN
+void
+dict_table_check_for_dup_indexes(
+/*=============================*/
+ const dict_table_t* table) /*!< in: Check for dup indexes
+ in this table */
+{
+ /* Check for duplicates, ignoring indexes that are marked
+ as to be dropped */
+
+ const dict_index_t* index1;
+ const dict_index_t* index2;
+
+ /* The primary index _must_ exist */
+ ut_a(UT_LIST_GET_LEN(table->indexes) > 0);
+
+ index1 = UT_LIST_GET_FIRST(table->indexes);
+ index2 = UT_LIST_GET_NEXT(indexes, index1);
+
+ while (index1 && index2) {
+
+ while (index2) {
+
+ if (!index2->to_be_dropped) {
+ ut_ad(ut_strcmp(index1->name, index2->name));
+ }
+
+ index2 = UT_LIST_GET_NEXT(indexes, index2);
+ }
+
+ index1 = UT_LIST_GET_NEXT(indexes, index1);
+ index2 = UT_LIST_GET_NEXT(indexes, index1);
+ }
+}
+#endif /* UNIV_DEBUG */
+#endif /* !UNIV_HOTBACKUP */
diff --git a/storage/innobase/dict/dict0load.c b/storage/innodb_plugin/dict/dict0load.c
similarity index 79%
rename from storage/innobase/dict/dict0load.c
rename to storage/innodb_plugin/dict/dict0load.c
index 65f1c9536bd..842a129c1a6 100644
--- a/storage/innobase/dict/dict0load.c
+++ b/storage/innodb_plugin/dict/dict0load.c
@@ -1,16 +1,31 @@
-/******************************************************
+/*****************************************************************************
+
+Copyright (c) 1996, 2009, Innobase Oy. All Rights Reserved.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; version 2 of the License.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place, Suite 330, Boston, MA 02111-1307 USA
+
+*****************************************************************************/
+
+/**************************************************//**
+@file dict/dict0load.c
Loads to the memory cache database object definitions
from dictionary tables
-(c) 1996 Innobase Oy
-
Created 4/24/1996 Heikki Tuuri
*******************************************************/
#include "dict0load.h"
-#ifndef UNIV_HOTBACKUP
#include "mysql_version.h"
-#endif /* !UNIV_HOTBACKUP */
#ifdef UNIV_NONINL
#include "dict0load.ic"
@@ -26,17 +41,17 @@ Created 4/24/1996 Heikki Tuuri
#include "srv0start.h"
#include "srv0srv.h"
-/********************************************************************
-Returns TRUE if index's i'th column's name is 'name' .*/
+/****************************************************************//**
+Compare the name of an index column.
+@return TRUE if the i'th column of index is 'name'. */
static
ibool
name_of_col_is(
/*===========*/
- /* out: */
- dict_table_t* table, /* in: table */
- dict_index_t* index, /* in: index */
- ulint i, /* in: */
- const char* name) /* in: name to compare to */
+ const dict_table_t* table, /*!< in: table */
+ const dict_index_t* index, /*!< in: index */
+ ulint i, /*!< in: index field offset */
+ const char* name) /*!< in: name to compare to */
{
ulint tmp = dict_col_get_no(dict_field_get_col(
dict_index_get_nth_field(
@@ -45,16 +60,15 @@ name_of_col_is(
return(strcmp(name, dict_table_get_col_name(table, tmp)) == 0);
}
-/************************************************************************
-Finds the first table name in the given database. */
-
+/********************************************************************//**
+Finds the first table name in the given database.
+@return own: table name, NULL if does not exist; the caller must free
+the memory in the string! */
+UNIV_INTERN
char*
dict_get_first_table_name_in_db(
/*============================*/
- /* out, own: table name, NULL if
- does not exist; the caller must
- free the memory in the string! */
- const char* name) /* in: database name which ends in '/' */
+ const char* name) /*!< in: database name which ends in '/' */
{
dict_table_t* sys_tables;
btr_pcur_t pcur;
@@ -62,8 +76,8 @@ dict_get_first_table_name_in_db(
dtuple_t* tuple;
mem_heap_t* heap;
dfield_t* dfield;
- rec_t* rec;
- byte* field;
+ const rec_t* rec;
+ const byte* field;
ulint len;
mtr_t mtr;
@@ -88,7 +102,7 @@ dict_get_first_table_name_in_db(
loop:
rec = btr_pcur_get_rec(&pcur);
- if (!btr_pcur_is_on_user_rec(&pcur, &mtr)) {
+ if (!btr_pcur_is_on_user_rec(&pcur)) {
/* Not found */
btr_pcur_close(&pcur);
@@ -129,10 +143,10 @@ loop:
goto loop;
}
-/************************************************************************
+/********************************************************************//**
Prints to the standard output information on all tables found in the data
dictionary system table. */
-
+UNIV_INTERN
void
dict_print(void)
/*============*/
@@ -141,8 +155,8 @@ dict_print(void)
dict_index_t* sys_index;
dict_table_t* table;
btr_pcur_t pcur;
- rec_t* rec;
- byte* field;
+ const rec_t* rec;
+ const byte* field;
ulint len;
mtr_t mtr;
@@ -167,7 +181,7 @@ loop:
rec = btr_pcur_get_rec(&pcur);
- if (!btr_pcur_is_on_user_rec(&pcur, &mtr)) {
+ if (!btr_pcur_is_on_user_rec(&pcur)) {
/* end of index */
btr_pcur_close(&pcur);
@@ -222,7 +236,69 @@ loop:
goto loop;
}
-/************************************************************************
+/********************************************************************//**
+Determine the flags of a table described in SYS_TABLES.
+@return compressed page size in kilobytes; or 0 if the tablespace is
+uncompressed, ULINT_UNDEFINED on error */
+static
+ulint
+dict_sys_tables_get_flags(
+/*======================*/
+ const rec_t* rec) /*!< in: a record of SYS_TABLES */
+{
+ const byte* field;
+ ulint len;
+ ulint n_cols;
+ ulint flags;
+
+ field = rec_get_nth_field_old(rec, 5, &len);
+ ut_a(len == 4);
+
+ flags = mach_read_from_4(field);
+
+ if (UNIV_LIKELY(flags == DICT_TABLE_ORDINARY)) {
+ return(0);
+ }
+
+ field = rec_get_nth_field_old(rec, 4, &len);
+ n_cols = mach_read_from_4(field);
+
+ if (UNIV_UNLIKELY(!(n_cols & 0x80000000UL))) {
+ /* New file formats require ROW_FORMAT=COMPACT. */
+ return(ULINT_UNDEFINED);
+ }
+
+ switch (flags & (DICT_TF_FORMAT_MASK | DICT_TF_COMPACT)) {
+ default:
+ case DICT_TF_FORMAT_51 << DICT_TF_FORMAT_SHIFT:
+ case DICT_TF_FORMAT_51 << DICT_TF_FORMAT_SHIFT | DICT_TF_COMPACT:
+ /* flags should be DICT_TABLE_ORDINARY,
+ or DICT_TF_FORMAT_MASK should be nonzero. */
+ return(ULINT_UNDEFINED);
+
+ case DICT_TF_FORMAT_ZIP << DICT_TF_FORMAT_SHIFT | DICT_TF_COMPACT:
+#if DICT_TF_FORMAT_MAX > DICT_TF_FORMAT_ZIP
+# error "missing case labels for DICT_TF_FORMAT_ZIP .. DICT_TF_FORMAT_MAX"
+#endif
+ /* We support this format. */
+ break;
+ }
+
+ if (UNIV_UNLIKELY((flags & DICT_TF_ZSSIZE_MASK)
+ > (DICT_TF_ZSSIZE_MAX << DICT_TF_ZSSIZE_SHIFT))) {
+ /* Unsupported compressed page size. */
+ return(ULINT_UNDEFINED);
+ }
+
+ if (UNIV_UNLIKELY(flags & (~0 << DICT_TF_BITS))) {
+ /* Some unused bits are set. */
+ return(ULINT_UNDEFINED);
+ }
+
+ return(flags);
+}
+
+/********************************************************************//**
In a crash recovery we already have all the tablespace objects created.
This function compares the space id information in the InnoDB data dictionary
to what we already read with fil_load_single_table_tablespaces().
@@ -230,19 +306,16 @@ to what we already read with fil_load_single_table_tablespaces().
In a normal startup, we create the tablespace objects for every table in
InnoDB's data dictionary, if the corresponding .ibd file exists.
We also scan the biggest space id, and store it to fil_system. */
-
+UNIV_INTERN
void
dict_check_tablespaces_and_store_max_id(
/*====================================*/
- ibool in_crash_recovery) /* in: are we doing a crash recovery */
+ ibool in_crash_recovery) /*!< in: are we doing a crash recovery */
{
dict_table_t* sys_tables;
dict_index_t* sys_index;
btr_pcur_t pcur;
- rec_t* rec;
- byte* field;
- ulint len;
- ulint space_id;
+ const rec_t* rec;
ulint max_space_id = 0;
mtr_t mtr;
@@ -261,7 +334,7 @@ loop:
rec = btr_pcur_get_rec(&pcur);
- if (!btr_pcur_is_on_user_rec(&pcur, &mtr)) {
+ if (!btr_pcur_is_on_user_rec(&pcur)) {
/* end of index */
btr_pcur_close(&pcur);
@@ -279,13 +352,34 @@ loop:
return;
}
- field = rec_get_nth_field_old(rec, 0, &len);
-
if (!rec_get_deleted_flag(rec, 0)) {
/* We found one */
+ const byte* field;
+ ulint len;
+ ulint space_id;
+ ulint flags;
+ char* name;
- char* name = mem_strdupl((char*) field, len);
+ field = rec_get_nth_field_old(rec, 0, &len);
+ name = mem_strdupl((char*) field, len);
+
+ flags = dict_sys_tables_get_flags(rec);
+ if (UNIV_UNLIKELY(flags == ULINT_UNDEFINED)) {
+
+ field = rec_get_nth_field_old(rec, 5, &len);
+ flags = mach_read_from_4(field);
+
+ ut_print_timestamp(stderr);
+ fputs(" InnoDB: Error: table ", stderr);
+ ut_print_filename(stderr, name);
+ fprintf(stderr, "\n"
+ "InnoDB: in InnoDB data dictionary"
+ " has unknown type %lx.\n",
+ (ulong) flags);
+
+ goto loop;
+ }
field = rec_get_nth_field_old(rec, 9, &len);
ut_a(len == 4);
@@ -309,7 +403,7 @@ loop:
object and check that the .ibd file exists. */
fil_open_single_table_tablespace(FALSE, space_id,
- name);
+ flags, name);
}
mem_free(name);
@@ -326,22 +420,22 @@ loop:
goto loop;
}
-/************************************************************************
+/********************************************************************//**
Loads definitions for table columns. */
static
void
dict_load_columns(
/*==============*/
- dict_table_t* table, /* in: table */
- mem_heap_t* heap) /* in: memory heap for temporary storage */
+ dict_table_t* table, /*!< in: table */
+ mem_heap_t* heap) /*!< in: memory heap for temporary storage */
{
dict_table_t* sys_columns;
dict_index_t* sys_index;
btr_pcur_t pcur;
dtuple_t* tuple;
dfield_t* dfield;
- rec_t* rec;
- byte* field;
+ const rec_t* rec;
+ const byte* field;
ulint len;
byte* buf;
char* name;
@@ -374,7 +468,7 @@ dict_load_columns(
rec = btr_pcur_get_rec(&pcur);
- ut_a(btr_pcur_is_on_user_rec(&pcur, &mtr));
+ ut_a(btr_pcur_is_on_user_rec(&pcur));
ut_a(!rec_get_deleted_flag(rec, 0));
@@ -432,34 +526,14 @@ dict_load_columns(
mtr_commit(&mtr);
}
-/************************************************************************
-Report that an index field or index for a table has been delete marked. */
-static
-void
-dict_load_report_deleted_index(
-/*===========================*/
- const char* name, /* in: table name */
- ulint field) /* in: index field, or ULINT_UNDEFINED */
-{
- fprintf(stderr, "InnoDB: Error: data dictionary entry"
- " for table %s is corrupt!\n", name);
- if (field != ULINT_UNDEFINED) {
- fprintf(stderr,
- "InnoDB: Index field %lu is delete marked.\n", field);
- } else {
- fputs("InnoDB: An index is delete marked.\n", stderr);
- }
-}
-
-/************************************************************************
+/********************************************************************//**
Loads definitions for index fields. */
static
void
dict_load_fields(
/*=============*/
- dict_table_t* table, /* in: table */
- dict_index_t* index, /* in: index whose fields to load */
- mem_heap_t* heap) /* in: memory heap for temporary storage */
+ dict_index_t* index, /*!< in: index whose fields to load */
+ mem_heap_t* heap) /*!< in: memory heap for temporary storage */
{
dict_table_t* sys_fields;
dict_index_t* sys_index;
@@ -468,8 +542,8 @@ dict_load_fields(
dfield_t* dfield;
ulint pos_and_prefix_len;
ulint prefix_len;
- rec_t* rec;
- byte* field;
+ const rec_t* rec;
+ const byte* field;
ulint len;
byte* buf;
ulint i;
@@ -498,14 +572,19 @@ dict_load_fields(
rec = btr_pcur_get_rec(&pcur);
- ut_a(btr_pcur_is_on_user_rec(&pcur, &mtr));
+ ut_a(btr_pcur_is_on_user_rec(&pcur));
+
+ /* There could be delete marked records in SYS_FIELDS
+ because SYS_FIELDS.INDEX_ID can be updated
+ by ALTER TABLE ADD INDEX. */
+
if (rec_get_deleted_flag(rec, 0)) {
- dict_load_report_deleted_index(table->name, i);
+
+ goto next_rec;
}
field = rec_get_nth_field_old(rec, 0, &len);
ut_ad(len == 8);
- ut_a(ut_memcmp(buf, field, len) == 0);
field = rec_get_nth_field_old(rec, 1, &len);
ut_a(len == 4);
@@ -540,6 +619,7 @@ dict_load_fields(
(char*) field, len),
prefix_len);
+next_rec:
btr_pcur_move_to_next_user_rec(&pcur, &mtr);
}
@@ -547,19 +627,17 @@ dict_load_fields(
mtr_commit(&mtr);
}
-/************************************************************************
+/********************************************************************//**
Loads definitions for table indexes. Adds them to the data dictionary
-cache. */
+cache.
+@return DB_SUCCESS if ok, DB_CORRUPTION if corruption of dictionary
+table or DB_UNSUPPORTED if table has unknown index type */
static
ulint
dict_load_indexes(
/*==============*/
- /* out: DB_SUCCESS if ok, DB_CORRUPTION
- if corruption of dictionary table or
- DB_UNSUPPORTED if table has unknown index
- type */
- dict_table_t* table, /* in: table */
- mem_heap_t* heap) /* in: memory heap for temporary storage */
+ dict_table_t* table, /*!< in: table */
+ mem_heap_t* heap) /*!< in: memory heap for temporary storage */
{
dict_table_t* sys_indexes;
dict_index_t* sys_index;
@@ -567,8 +645,8 @@ dict_load_indexes(
btr_pcur_t pcur;
dtuple_t* tuple;
dfield_t* dfield;
- rec_t* rec;
- byte* field;
+ const rec_t* rec;
+ const byte* field;
ulint len;
ulint name_len;
char* name_buf;
@@ -609,7 +687,7 @@ dict_load_indexes(
btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
BTR_SEARCH_LEAF, &pcur, &mtr);
for (;;) {
- if (!btr_pcur_is_on_user_rec(&pcur, &mtr)) {
+ if (!btr_pcur_is_on_user_rec(&pcur)) {
break;
}
@@ -621,14 +699,9 @@ dict_load_indexes(
if (ut_memcmp(buf, field, len) != 0) {
break;
- }
-
- if (rec_get_deleted_flag(rec, 0)) {
- dict_load_report_deleted_index(table->name,
- ULINT_UNDEFINED);
-
- error = DB_CORRUPTION;
- goto func_exit;
+ } else if (rec_get_deleted_flag(rec, 0)) {
+ /* Skip delete marked records */
+ goto next_rec;
}
field = rec_get_nth_field_old(rec, 1, &len);
@@ -678,12 +751,13 @@ dict_load_indexes(
} else if ((type & DICT_CLUSTERED) == 0
&& NULL == dict_table_get_first_index(table)) {
- fprintf(stderr,
- "InnoDB: Error: trying to load index %s"
- " for table %s\n"
- "InnoDB: but the first index"
- " is not clustered!\n",
- name_buf, table->name);
+ fputs("InnoDB: Error: trying to load index ",
+ stderr);
+ ut_print_name(stderr, NULL, FALSE, name_buf);
+ fputs(" for table ", stderr);
+ ut_print_name(stderr, NULL, TRUE, table->name);
+ fputs("\nInnoDB: but the first index"
+ " is not clustered!\n", stderr);
error = DB_CORRUPTION;
goto func_exit;
@@ -701,10 +775,21 @@ dict_load_indexes(
space, type, n_fields);
index->id = id;
- dict_load_fields(table, index, heap);
- dict_index_add_to_cache(table, index, page_no);
+ dict_load_fields(index, heap);
+ error = dict_index_add_to_cache(table, index, page_no,
+ FALSE);
+ /* The data dictionary tables should never contain
+ invalid index definitions. If we ignored this error
+ and simply did not load this index definition, the
+ .frm file would disagree with the index definitions
+ inside InnoDB. */
+ if (UNIV_UNLIKELY(error != DB_SUCCESS)) {
+
+ goto func_exit;
+ }
}
+next_rec:
btr_pcur_move_to_next_user_rec(&pcur, &mtr);
}
@@ -715,22 +800,20 @@ func_exit:
return(error);
}
-/************************************************************************
+/********************************************************************//**
Loads a table definition and also all its index definitions, and also
the cluster definition if the table is a member in a cluster. Also loads
all foreign key constraints where the foreign key is in the table or where
a foreign key references columns in this table. Adds all these to the data
-dictionary cache. */
-
+dictionary cache.
+@return table, NULL if does not exist; if the table is stored in an
+.ibd file, but the file does not exist, then we set the
+ibd_file_missing flag TRUE in the table object we return */
+UNIV_INTERN
dict_table_t*
dict_load_table(
/*============*/
- /* out: table, NULL if does not exist;
- if the table is stored in an .ibd file,
- but the file does not exist,
- then we set the ibd_file_missing flag TRUE
- in the table object we return */
- const char* name) /* in: table name in the
+ const char* name) /*!< in: table name in the
databasename/tablename format */
{
ibool ibd_file_missing = FALSE;
@@ -741,8 +824,8 @@ dict_load_table(
dtuple_t* tuple;
mem_heap_t* heap;
dfield_t* dfield;
- rec_t* rec;
- byte* field;
+ const rec_t* rec;
+ const byte* field;
ulint len;
ulint space;
ulint n_cols;
@@ -770,7 +853,7 @@ dict_load_table(
BTR_SEARCH_LEAF, &pcur, &mtr);
rec = btr_pcur_get_rec(&pcur);
- if (!btr_pcur_is_on_user_rec(&pcur, &mtr)
+ if (!btr_pcur_is_on_user_rec(&pcur)
|| rec_get_deleted_flag(rec, 0)) {
/* Not found */
err_exit:
@@ -796,6 +879,22 @@ err_exit:
/* Check if the tablespace exists and has the right name */
if (space != 0) {
+ flags = dict_sys_tables_get_flags(rec);
+
+ if (UNIV_UNLIKELY(flags == ULINT_UNDEFINED)) {
+ field = rec_get_nth_field_old(rec, 5, &len);
+ flags = mach_read_from_4(field);
+
+ ut_print_timestamp(stderr);
+ fputs(" InnoDB: Error: table ", stderr);
+ ut_print_filename(stderr, name);
+ fprintf(stderr, "\n"
+ "InnoDB: in InnoDB data dictionary"
+ " has unknown type %lx.\n",
+ (ulong) flags);
+ goto err_exit;
+ }
+
if (fil_space_for_table_exists_in_mem(space, name, FALSE,
FALSE, FALSE)) {
/* Ok; (if we did a crash recovery then the tablespace
@@ -812,14 +911,16 @@ err_exit:
" Retrying an open.\n",
name, (ulong)space);
/* Try to open the tablespace */
- if (!fil_open_single_table_tablespace(TRUE,
- space, name)) {
+ if (!fil_open_single_table_tablespace(
+ TRUE, space, flags, name)) {
/* We failed to find a sensible tablespace
file */
ibd_file_missing = TRUE;
}
}
+ } else {
+ flags = 0;
}
ut_a(name_of_col_is(sys_tables, sys_index, 4, "N_COLS"));
@@ -827,8 +928,6 @@ err_exit:
field = rec_get_nth_field_old(rec, 4, &len);
n_cols = mach_read_from_4(field);
- flags = 0;
-
/* The high-order bit of N_COLS is the "compact format" flag. */
if (n_cols & 0x80000000UL) {
flags |= DICT_TF_COMPACT;
@@ -844,15 +943,6 @@ err_exit:
field = rec_get_nth_field_old(rec, 3, &len);
table->id = mach_read_from_8(field);
- field = rec_get_nth_field_old(rec, 5, &len);
- if (UNIV_UNLIKELY(mach_read_from_4(field) != DICT_TABLE_ORDINARY)) {
- ut_print_timestamp(stderr);
- fprintf(stderr,
- " InnoDB: table %s: unknown table type %lu\n",
- name, (ulong) mach_read_from_4(field));
- goto err_exit;
- }
-
btr_pcur_close(&pcur);
mtr_commit(&mtr);
@@ -903,14 +993,14 @@ err_exit:
return(table);
}
-/***************************************************************************
-Loads a table object based on the table id. */
-
+/***********************************************************************//**
+Loads a table object based on the table id.
+@return table; NULL if table does not exist */
+UNIV_INTERN
dict_table_t*
dict_load_table_on_id(
/*==================*/
- /* out: table; NULL if table does not exist */
- dulint table_id) /* in: table id */
+ dulint table_id) /*!< in: table id */
{
byte id_buf[8];
btr_pcur_t pcur;
@@ -919,8 +1009,8 @@ dict_load_table_on_id(
dfield_t* dfield;
dict_index_t* sys_table_ids;
dict_table_t* sys_tables;
- rec_t* rec;
- byte* field;
+ const rec_t* rec;
+ const byte* field;
ulint len;
dict_table_t* table;
mtr_t mtr;
@@ -953,7 +1043,7 @@ dict_load_table_on_id(
BTR_SEARCH_LEAF, &pcur, &mtr);
rec = btr_pcur_get_rec(&pcur);
- if (!btr_pcur_is_on_user_rec(&pcur, &mtr)
+ if (!btr_pcur_is_on_user_rec(&pcur)
|| rec_get_deleted_flag(rec, 0)) {
/* Not found */
@@ -994,15 +1084,15 @@ dict_load_table_on_id(
return(table);
}
-/************************************************************************
+/********************************************************************//**
This function is called when the database is booted. Loads system table
index definitions except for the clustered index which is added to the
dictionary cache at booting before calling this function. */
-
+UNIV_INTERN
void
dict_load_sys_table(
/*================*/
- dict_table_t* table) /* in: system table */
+ dict_table_t* table) /*!< in: system table */
{
mem_heap_t* heap;
@@ -1015,23 +1105,23 @@ dict_load_sys_table(
mem_heap_free(heap);
}
-/************************************************************************
+/********************************************************************//**
Loads foreign key constraint col names (also for the referenced table). */
static
void
dict_load_foreign_cols(
/*===================*/
- const char* id, /* in: foreign constraint id as a
+ const char* id, /*!< in: foreign constraint id as a
null-terminated string */
- dict_foreign_t* foreign)/* in: foreign constraint object */
+ dict_foreign_t* foreign)/*!< in: foreign constraint object */
{
dict_table_t* sys_foreign_cols;
dict_index_t* sys_index;
btr_pcur_t pcur;
dtuple_t* tuple;
dfield_t* dfield;
- rec_t* rec;
- byte* field;
+ const rec_t* rec;
+ const byte* field;
ulint len;
ulint i;
mtr_t mtr;
@@ -1061,7 +1151,7 @@ dict_load_foreign_cols(
rec = btr_pcur_get_rec(&pcur);
- ut_a(btr_pcur_is_on_user_rec(&pcur, &mtr));
+ ut_a(btr_pcur_is_on_user_rec(&pcur));
ut_a(!rec_get_deleted_flag(rec, 0));
field = rec_get_nth_field_old(rec, 0, &len);
@@ -1087,17 +1177,17 @@ dict_load_foreign_cols(
mtr_commit(&mtr);
}
-/***************************************************************************
-Loads a foreign key constraint to the dictionary cache. */
+/***********************************************************************//**
+Loads a foreign key constraint to the dictionary cache.
+@return DB_SUCCESS or error code */
static
ulint
dict_load_foreign(
/*==============*/
- /* out: DB_SUCCESS or error code */
- const char* id, /* in: foreign constraint id as a
+ const char* id, /*!< in: foreign constraint id as a
null-terminated string */
ibool check_charsets)
- /* in: TRUE=check charset compatibility */
+ /*!< in: TRUE=check charset compatibility */
{
dict_foreign_t* foreign;
dict_table_t* sys_foreign;
@@ -1106,8 +1196,8 @@ dict_load_foreign(
dtuple_t* tuple;
mem_heap_t* heap2;
dfield_t* dfield;
- rec_t* rec;
- byte* field;
+ const rec_t* rec;
+ const byte* field;
ulint len;
ulint n_fields_and_type;
mtr_t mtr;
@@ -1132,7 +1222,7 @@ dict_load_foreign(
BTR_SEARCH_LEAF, &pcur, &mtr);
rec = btr_pcur_get_rec(&pcur);
- if (!btr_pcur_is_on_user_rec(&pcur, &mtr)
+ if (!btr_pcur_is_on_user_rec(&pcur)
|| rec_get_deleted_flag(rec, 0)) {
/* Not found */
@@ -1212,19 +1302,19 @@ dict_load_foreign(
return(dict_foreign_add_to_cache(foreign, check_charsets));
}
-/***************************************************************************
+/***********************************************************************//**
Loads foreign key constraints where the table is either the foreign key
holder or where the table is referenced by a foreign key. Adds these
constraints to the data dictionary. Note that we know that the dictionary
cache already contains all constraints where the other relevant table is
-already in the dictionary cache. */
-
+already in the dictionary cache.
+@return DB_SUCCESS or error code */
+UNIV_INTERN
ulint
dict_load_foreigns(
/*===============*/
- /* out: DB_SUCCESS or error code */
- const char* table_name, /* in: table name */
- ibool check_charsets) /* in: TRUE=check charset
+ const char* table_name, /*!< in: table name */
+ ibool check_charsets) /*!< in: TRUE=check charset
compatibility */
{
btr_pcur_t pcur;
@@ -1233,8 +1323,8 @@ dict_load_foreigns(
dfield_t* dfield;
dict_index_t* sec_index;
dict_table_t* sys_foreign;
- rec_t* rec;
- byte* field;
+ const rec_t* rec;
+ const byte* field;
ulint len;
char* id ;
ulint err;
@@ -1276,7 +1366,7 @@ start_load:
loop:
rec = btr_pcur_get_rec(&pcur);
- if (!btr_pcur_is_on_user_rec(&pcur, &mtr)) {
+ if (!btr_pcur_is_on_user_rec(&pcur)) {
/* End of index */
goto load_next_index;
diff --git a/storage/innobase/dict/dict0mem.c b/storage/innodb_plugin/dict/dict0mem.c
similarity index 60%
rename from storage/innobase/dict/dict0mem.c
rename to storage/innodb_plugin/dict/dict0mem.c
index 168771ca307..6458cbab92d 100644
--- a/storage/innobase/dict/dict0mem.c
+++ b/storage/innodb_plugin/dict/dict0mem.c
@@ -1,7 +1,24 @@
-/**********************************************************************
-Data dictionary memory object creation
+/*****************************************************************************
-(c) 1996 Innobase Oy
+Copyright (c) 1996, 2009, Innobase Oy. All Rights Reserved.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; version 2 of the License.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place, Suite 330, Boston, MA 02111-1307 USA
+
+*****************************************************************************/
+
+/******************************************************************//**
+@file dict/dict0mem.c
+Data dictionary memory object creation
Created 1/8/1996 Heikki Tuuri
***********************************************************************/
@@ -16,76 +33,50 @@ Created 1/8/1996 Heikki Tuuri
#include "data0type.h"
#include "mach0data.h"
#include "dict0dict.h"
-#include "que0que.h"
-#include "pars0pars.h"
-#include "lock0lock.h"
+#ifndef UNIV_HOTBACKUP
+# include "lock0lock.h"
+#endif /* !UNIV_HOTBACKUP */
-#define DICT_HEAP_SIZE 100 /* initial memory heap size when
+#define DICT_HEAP_SIZE 100 /*!< initial memory heap size when
creating a table or index object */
-/**************************************************************************
-Creates a table memory object. */
-
+/**********************************************************************//**
+Creates a table memory object.
+@return own: table object */
+UNIV_INTERN
dict_table_t*
dict_mem_table_create(
/*==================*/
- /* out, own: table object */
- const char* name, /* in: table name */
- ulint space, /* in: space where the clustered index of
+ const char* name, /*!< in: table name */
+ ulint space, /*!< in: space where the clustered index of
the table is placed; this parameter is
ignored if the table is made a member of
a cluster */
- ulint n_cols, /* in: number of columns */
- ulint flags) /* in: table flags */
+ ulint n_cols, /*!< in: number of columns */
+ ulint flags) /*!< in: table flags */
{
dict_table_t* table;
mem_heap_t* heap;
ut_ad(name);
- ut_ad(!(flags & ~DICT_TF_COMPACT));
+ ut_a(!(flags & (~0 << DICT_TF_BITS)));
heap = mem_heap_create(DICT_HEAP_SIZE);
- table = mem_heap_alloc(heap, sizeof(dict_table_t));
+ table = mem_heap_zalloc(heap, sizeof(dict_table_t));
table->heap = heap;
table->flags = (unsigned int) flags;
table->name = mem_heap_strdup(heap, name);
- table->dir_path_of_temp_table = NULL;
table->space = (unsigned int) space;
- table->ibd_file_missing = FALSE;
- table->tablespace_discarded = FALSE;
- table->n_def = 0;
table->n_cols = (unsigned int) (n_cols + DATA_N_SYS_COLS);
- table->n_mysql_handles_opened = 0;
- table->n_foreign_key_checks_running = 0;
-
- table->cached = FALSE;
-
table->cols = mem_heap_alloc(heap, (n_cols + DATA_N_SYS_COLS)
* sizeof(dict_col_t));
- table->col_names = NULL;
- UT_LIST_INIT(table->indexes);
- table->auto_inc_lock = mem_heap_alloc(heap, lock_get_size());
-
- table->query_cache_inv_trx_id = ut_dulint_zero;
-
- UT_LIST_INIT(table->locks);
- UT_LIST_INIT(table->foreign_list);
- UT_LIST_INIT(table->referenced_list);
-
-#ifdef UNIV_DEBUG
- table->does_not_fit_in_memory = FALSE;
-#endif /* UNIV_DEBUG */
-
- table->stat_initialized = FALSE;
-
- table->stat_modified_counter = 0;
-
- table->big_rows = 0;
+#ifndef UNIV_HOTBACKUP
+ table->autoinc_lock = mem_heap_alloc(heap, lock_get_size());
mutex_create(&table->autoinc_mutex, SYNC_DICT_AUTOINC_MUTEX);
@@ -94,40 +85,42 @@ dict_mem_table_create(
/* The number of transactions that are either waiting on the
AUTOINC lock or have been granted the lock. */
table->n_waiting_or_granted_auto_inc_locks = 0;
+#endif /* !UNIV_HOTBACKUP */
-#ifdef UNIV_DEBUG
- table->magic_n = DICT_TABLE_MAGIC_N;
-#endif /* UNIV_DEBUG */
+ ut_d(table->magic_n = DICT_TABLE_MAGIC_N);
return(table);
}
-/********************************************************************
+/****************************************************************//**
Free a table memory object. */
-
+UNIV_INTERN
void
dict_mem_table_free(
/*================*/
- dict_table_t* table) /* in: table */
+ dict_table_t* table) /*!< in: table */
{
ut_ad(table);
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
+ ut_d(table->cached = FALSE);
+#ifndef UNIV_HOTBACKUP
mutex_free(&(table->autoinc_mutex));
+#endif /* UNIV_HOTBACKUP */
mem_heap_free(table->heap);
}
-/********************************************************************
-Append 'name' to 'col_names' (@see dict_table_t::col_names). */
+/****************************************************************//**
+Append 'name' to 'col_names'. @see dict_table_t::col_names
+@return new column names array */
static
const char*
dict_add_col_name(
/*==============*/
- /* out: new column names array */
- const char* col_names, /* in: existing column names, or
+ const char* col_names, /*!< in: existing column names, or
NULL */
- ulint cols, /* in: number of existing columns */
- const char* name, /* in: new column name */
- mem_heap_t* heap) /* in: heap */
+ ulint cols, /*!< in: number of existing columns */
+ const char* name, /*!< in: new column name */
+ mem_heap_t* heap) /*!< in: heap */
{
ulint old_len;
ulint new_len;
@@ -164,22 +157,24 @@ dict_add_col_name(
return(res);
}
-/**************************************************************************
+/**********************************************************************//**
Adds a column definition to a table. */
-
+UNIV_INTERN
void
dict_mem_table_add_col(
/*===================*/
- dict_table_t* table, /* in: table */
- mem_heap_t* heap, /* in: temporary memory heap, or NULL */
- const char* name, /* in: column name, or NULL */
- ulint mtype, /* in: main datatype */
- ulint prtype, /* in: precise type */
- ulint len) /* in: precision */
+ dict_table_t* table, /*!< in: table */
+ mem_heap_t* heap, /*!< in: temporary memory heap, or NULL */
+ const char* name, /*!< in: column name, or NULL */
+ ulint mtype, /*!< in: main datatype */
+ ulint prtype, /*!< in: precise type */
+ ulint len) /*!< in: precision */
{
dict_col_t* col;
+#ifndef UNIV_HOTBACKUP
ulint mbminlen;
ulint mbmaxlen;
+#endif /* !UNIV_HOTBACKUP */
ulint i;
ut_ad(table);
@@ -194,8 +189,7 @@ dict_mem_table_add_col(
}
if (UNIV_LIKELY(i) && UNIV_UNLIKELY(!table->col_names)) {
/* All preceding column names are empty. */
- char* s = mem_heap_alloc(heap, table->n_def);
- memset(s, 0, table->n_def);
+ char* s = mem_heap_zalloc(heap, table->n_def);
table->col_names = s;
}
@@ -203,7 +197,7 @@ dict_mem_table_add_col(
i, name, heap);
}
- col = (dict_col_t*) dict_table_get_nth_col(table, i);
+ col = dict_table_get_nth_col(table, i);
col->ind = (unsigned int) i;
col->ord_part = 0;
@@ -212,27 +206,29 @@ dict_mem_table_add_col(
col->prtype = (unsigned int) prtype;
col->len = (unsigned int) len;
+#ifndef UNIV_HOTBACKUP
dtype_get_mblen(mtype, prtype, &mbminlen, &mbmaxlen);
col->mbminlen = (unsigned int) mbminlen;
col->mbmaxlen = (unsigned int) mbmaxlen;
+#endif /* !UNIV_HOTBACKUP */
}
-/**************************************************************************
-Creates an index memory object. */
-
+/**********************************************************************//**
+Creates an index memory object.
+@return own: index object */
+UNIV_INTERN
dict_index_t*
dict_mem_index_create(
/*==================*/
- /* out, own: index object */
- const char* table_name, /* in: table name */
- const char* index_name, /* in: index name */
- ulint space, /* in: space where the index tree is
+ const char* table_name, /*!< in: table name */
+ const char* index_name, /*!< in: index name */
+ ulint space, /*!< in: space where the index tree is
placed, ignored if the index is of
the clustered type */
- ulint type, /* in: DICT_UNIQUE,
+ ulint type, /*!< in: DICT_UNIQUE,
DICT_CLUSTERED, ... ORed */
- ulint n_fields) /* in: number of fields */
+ ulint n_fields) /*!< in: number of fields */
{
dict_index_t* index;
mem_heap_t* heap;
@@ -240,79 +236,58 @@ dict_mem_index_create(
ut_ad(table_name && index_name);
heap = mem_heap_create(DICT_HEAP_SIZE);
- index = mem_heap_alloc(heap, sizeof(dict_index_t));
+ index = mem_heap_zalloc(heap, sizeof(dict_index_t));
index->heap = heap;
index->type = type;
+#ifndef UNIV_HOTBACKUP
index->space = (unsigned int) space;
- index->page = 0;
+#endif /* !UNIV_HOTBACKUP */
index->name = mem_heap_strdup(heap, index_name);
index->table_name = table_name;
- index->table = NULL;
- index->n_def = index->n_nullable = 0;
index->n_fields = (unsigned int) n_fields;
index->fields = mem_heap_alloc(heap, 1 + n_fields
* sizeof(dict_field_t));
/* The '1 +' above prevents allocation
of an empty mem block */
- index->stat_n_diff_key_vals = NULL;
-
- index->cached = FALSE;
- memset(&index->lock, 0, sizeof index->lock);
#ifdef UNIV_DEBUG
index->magic_n = DICT_INDEX_MAGIC_N;
#endif /* UNIV_DEBUG */
return(index);
}
-/**************************************************************************
-Creates and initializes a foreign constraint memory object. */
-
+/**********************************************************************//**
+Creates and initializes a foreign constraint memory object.
+@return own: foreign constraint struct */
+UNIV_INTERN
dict_foreign_t*
dict_mem_foreign_create(void)
/*=========================*/
- /* out, own: foreign constraint struct */
{
dict_foreign_t* foreign;
mem_heap_t* heap;
heap = mem_heap_create(100);
- foreign = mem_heap_alloc(heap, sizeof(dict_foreign_t));
+ foreign = mem_heap_zalloc(heap, sizeof(dict_foreign_t));
foreign->heap = heap;
- foreign->id = NULL;
-
- foreign->type = 0;
- foreign->foreign_table_name = NULL;
- foreign->foreign_table = NULL;
- foreign->foreign_col_names = NULL;
-
- foreign->referenced_table_name = NULL;
- foreign->referenced_table = NULL;
- foreign->referenced_col_names = NULL;
-
- foreign->n_fields = 0;
-
- foreign->foreign_index = NULL;
- foreign->referenced_index = NULL;
-
return(foreign);
}
-/**************************************************************************
+/**********************************************************************//**
Adds a field definition to an index. NOTE: does not take a copy
of the column name if the field is a column. The memory occupied
by the column name may be released only after publishing the index. */
-
+UNIV_INTERN
void
dict_mem_index_add_field(
/*=====================*/
- dict_index_t* index, /* in: index */
- const char* name, /* in: column name */
- ulint prefix_len) /* in: 0 or the column prefix length
+ dict_index_t* index, /*!< in: index */
+ const char* name, /*!< in: column name */
+ ulint prefix_len) /*!< in: 0 or the column prefix length
in a MySQL index like
INDEX (textcol(25)) */
{
@@ -329,13 +304,13 @@ dict_mem_index_add_field(
field->prefix_len = (unsigned int) prefix_len;
}
-/**************************************************************************
+/**********************************************************************//**
Frees an index memory object. */
-
+UNIV_INTERN
void
dict_mem_index_free(
/*================*/
- dict_index_t* index) /* in: index */
+ dict_index_t* index) /*!< in: index */
{
ut_ad(index);
ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
diff --git a/storage/innodb_plugin/dyn/dyn0dyn.c b/storage/innodb_plugin/dyn/dyn0dyn.c
new file mode 100644
index 00000000000..e1275f040f3
--- /dev/null
+++ b/storage/innodb_plugin/dyn/dyn0dyn.c
@@ -0,0 +1,65 @@
+/*****************************************************************************
+
+Copyright (c) 1996, 2009, Innobase Oy. All Rights Reserved.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; version 2 of the License.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place, Suite 330, Boston, MA 02111-1307 USA
+
+*****************************************************************************/
+
+/**************************************************//**
+@file dyn/dyn0dyn.c
+The dynamically allocated array
+
+Created 2/5/1996 Heikki Tuuri
+*******************************************************/
+
+#include "dyn0dyn.h"
+#ifdef UNIV_NONINL
+#include "dyn0dyn.ic"
+#endif
+
+/************************************************************//**
+Adds a new block to a dyn array.
+@return created block */
+UNIV_INTERN
+dyn_block_t*
+dyn_array_add_block(
+/*================*/
+ dyn_array_t* arr) /*!< in: dyn array */
+{
+ mem_heap_t* heap;
+ dyn_block_t* block;
+
+ ut_ad(arr);
+ ut_ad(arr->magic_n == DYN_BLOCK_MAGIC_N);
+
+ if (arr->heap == NULL) {
+ UT_LIST_INIT(arr->base);
+ UT_LIST_ADD_FIRST(list, arr->base, arr);
+
+ arr->heap = mem_heap_create(sizeof(dyn_block_t));
+ }
+
+ block = dyn_array_get_last_block(arr);
+ block->used = block->used | DYN_BLOCK_FULL_FLAG;
+
+ heap = arr->heap;
+
+ block = mem_heap_alloc(heap, sizeof(dyn_block_t));
+
+ block->used = 0;
+
+ UT_LIST_ADD_LAST(list, arr->base, block);
+
+ return(block);
+}
diff --git a/storage/innobase/eval/eval0eval.c b/storage/innodb_plugin/eval/eval0eval.c
similarity index 86%
rename from storage/innobase/eval/eval0eval.c
rename to storage/innodb_plugin/eval/eval0eval.c
index cbc47ec508f..589b0fa1576 100644
--- a/storage/innobase/eval/eval0eval.c
+++ b/storage/innodb_plugin/eval/eval0eval.c
@@ -1,9 +1,26 @@
-/******************************************************
+/*****************************************************************************
+
+Copyright (c) 1997, 2009, Innobase Oy. All Rights Reserved.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; version 2 of the License.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place, Suite 330, Boston, MA 02111-1307 USA
+
+*****************************************************************************/
+
+/**************************************************//**
+@file eval/eval0eval.c
SQL evaluator: evaluates simple data structures, like expressions, in
a query graph
-(c) 1997 Innobase Oy
-
Created 12/29/1997 Heikki Tuuri
*******************************************************/
@@ -16,29 +33,29 @@ Created 12/29/1997 Heikki Tuuri
#include "data0data.h"
#include "row0sel.h"
-/* The RND function seed */
-ulint eval_rnd = 128367121;
+/** The RND function seed */
+static ulint eval_rnd = 128367121;
-/* Dummy adress used when we should allocate a buffer of size 0 in
-the function below */
+/** Dummy adress used when we should allocate a buffer of size 0 in
+eval_node_alloc_val_buf */
-byte eval_dummy;
+static byte eval_dummy;
-/*********************************************************************
+/*****************************************************************//**
Allocate a buffer from global dynamic memory for a value of a que_node.
NOTE that this memory must be explicitly freed when the query graph is
freed. If the node already has an allocated buffer, that buffer is freed
here. NOTE that this is the only function where dynamic memory should be
-allocated for a query node val field. */
-
+allocated for a query node val field.
+@return pointer to allocated buffer */
+UNIV_INTERN
byte*
eval_node_alloc_val_buf(
/*====================*/
- /* out: pointer to allocated buffer */
- que_node_t* node, /* in: query graph node; sets the val field
+ que_node_t* node, /*!< in: query graph node; sets the val field
data field to point to the new buffer, and
len field equal to size */
- ulint size) /* in: buffer size */
+ ulint size) /*!< in: buffer size */
{
dfield_t* dfield;
byte* data;
@@ -67,15 +84,15 @@ eval_node_alloc_val_buf(
return(data);
}
-/*********************************************************************
+/*****************************************************************//**
Free the buffer from global dynamic memory for a value of a que_node,
if it has been allocated in the above function. The freeing for pushed
column values is done in sel_col_prefetch_buf_free. */
-
+UNIV_INTERN
void
eval_node_free_val_buf(
/*===================*/
- que_node_t* node) /* in: query graph node */
+ que_node_t* node) /*!< in: query graph node */
{
dfield_t* dfield;
byte* data;
@@ -94,14 +111,14 @@ eval_node_free_val_buf(
}
}
-/*********************************************************************
-Evaluates a comparison node. */
-
+/*****************************************************************//**
+Evaluates a comparison node.
+@return the result of the comparison */
+UNIV_INTERN
ibool
eval_cmp(
/*=====*/
- /* out: the result of the comparison */
- func_node_t* cmp_node) /* in: comparison node */
+ func_node_t* cmp_node) /*!< in: comparison node */
{
que_node_t* arg1;
que_node_t* arg2;
@@ -153,13 +170,13 @@ eval_cmp(
return(val);
}
-/*********************************************************************
+/*****************************************************************//**
Evaluates a logical operation node. */
UNIV_INLINE
void
eval_logical(
/*=========*/
- func_node_t* logical_node) /* in: logical operation node */
+ func_node_t* logical_node) /*!< in: logical operation node */
{
que_node_t* arg1;
que_node_t* arg2;
@@ -194,13 +211,13 @@ eval_logical(
eval_node_set_ibool_val(logical_node, val);
}
-/*********************************************************************
+/*****************************************************************//**
Evaluates an arithmetic operation node. */
UNIV_INLINE
void
eval_arith(
/*=======*/
- func_node_t* arith_node) /* in: arithmetic operation node */
+ func_node_t* arith_node) /*!< in: arithmetic operation node */
{
que_node_t* arg1;
que_node_t* arg2;
@@ -238,13 +255,13 @@ eval_arith(
eval_node_set_int_val(arith_node, val);
}
-/*********************************************************************
+/*****************************************************************//**
Evaluates an aggregate operation node. */
UNIV_INLINE
void
eval_aggregate(
/*===========*/
- func_node_t* node) /* in: aggregate operation node */
+ func_node_t* node) /*!< in: aggregate operation node */
{
que_node_t* arg;
lint val;
@@ -272,14 +289,14 @@ eval_aggregate(
eval_node_set_int_val(node, val);
}
-/*********************************************************************
+/*****************************************************************//**
Evaluates a predefined function node where the function is not relevant
in benchmarks. */
static
void
eval_predefined_2(
/*==============*/
- func_node_t* func_node) /* in: predefined function node */
+ func_node_t* func_node) /*!< in: predefined function node */
{
que_node_t* arg;
que_node_t* arg1;
@@ -359,13 +376,13 @@ eval_predefined_2(
}
}
-/*********************************************************************
+/*****************************************************************//**
Evaluates a notfound-function node. */
UNIV_INLINE
void
eval_notfound(
/*==========*/
- func_node_t* func_node) /* in: function node */
+ func_node_t* func_node) /*!< in: function node */
{
que_node_t* arg1;
que_node_t* arg2;
@@ -401,13 +418,13 @@ eval_notfound(
eval_node_set_ibool_val(func_node, ibool_val);
}
-/*********************************************************************
+/*****************************************************************//**
Evaluates a substr-function node. */
UNIV_INLINE
void
eval_substr(
/*========*/
- func_node_t* func_node) /* in: function node */
+ func_node_t* func_node) /*!< in: function node */
{
que_node_t* arg1;
que_node_t* arg2;
@@ -434,13 +451,13 @@ eval_substr(
dfield_set_data(dfield, str1 + len1, len2);
}
-/*********************************************************************
+/*****************************************************************//**
Evaluates a replstr-procedure node. */
static
void
eval_replstr(
/*=========*/
- func_node_t* func_node) /* in: function node */
+ func_node_t* func_node) /*!< in: function node */
{
que_node_t* arg1;
que_node_t* arg2;
@@ -474,13 +491,13 @@ eval_replstr(
ut_memcpy(str1 + len1, str2, len2);
}
-/*********************************************************************
+/*****************************************************************//**
Evaluates an instr-function node. */
static
void
eval_instr(
/*=======*/
- func_node_t* func_node) /* in: function node */
+ func_node_t* func_node) /*!< in: function node */
{
que_node_t* arg1;
que_node_t* arg2;
@@ -546,13 +563,13 @@ match_found:
eval_node_set_int_val(func_node, int_val);
}
-/*********************************************************************
+/*****************************************************************//**
Evaluates a predefined function node. */
UNIV_INLINE
void
eval_binary_to_number(
/*==================*/
- func_node_t* func_node) /* in: function node */
+ func_node_t* func_node) /*!< in: function node */
{
que_node_t* arg1;
dfield_t* dfield;
@@ -584,13 +601,13 @@ eval_binary_to_number(
eval_node_copy_and_alloc_val(func_node, str2, 4);
}
-/*********************************************************************
+/*****************************************************************//**
Evaluates a predefined function node. */
static
void
eval_concat(
/*========*/
- func_node_t* func_node) /* in: function node */
+ func_node_t* func_node) /*!< in: function node */
{
que_node_t* arg;
dfield_t* dfield;
@@ -626,7 +643,7 @@ eval_concat(
}
}
-/*********************************************************************
+/*****************************************************************//**
Evaluates a predefined function node. If the first argument is an integer,
this function looks at the second argument which is the integer length in
bytes, and converts the integer to a VARCHAR.
@@ -636,7 +653,7 @@ UNIV_INLINE
void
eval_to_binary(
/*===========*/
- func_node_t* func_node) /* in: function node */
+ func_node_t* func_node) /*!< in: function node */
{
que_node_t* arg1;
que_node_t* arg2;
@@ -674,13 +691,13 @@ eval_to_binary(
dfield_set_data(dfield, str1 + (4 - len1), len1);
}
-/*********************************************************************
+/*****************************************************************//**
Evaluates a predefined function node. */
UNIV_INLINE
void
eval_predefined(
/*============*/
- func_node_t* func_node) /* in: function node */
+ func_node_t* func_node) /*!< in: function node */
{
que_node_t* arg1;
lint int_val;
@@ -746,8 +763,7 @@ eval_predefined(
}
}
- dfield_set_len((dfield_t*) que_node_get_val(func_node),
- int_len);
+ dfield_set_len(que_node_get_val(func_node), int_len);
return;
@@ -767,13 +783,13 @@ eval_predefined(
eval_node_set_int_val(func_node, int_val);
}
-/*********************************************************************
+/*****************************************************************//**
Evaluates a function node. */
-
+UNIV_INTERN
void
eval_func(
/*======*/
- func_node_t* func_node) /* in: function node */
+ func_node_t* func_node) /*!< in: function node */
{
que_node_t* arg;
ulint class;
@@ -793,7 +809,7 @@ eval_func(
/* The functions are not defined for SQL null argument
values, except for eval_cmp and notfound */
- if ((dfield_get_len(que_node_get_val(arg)) == UNIV_SQL_NULL)
+ if (dfield_is_null(que_node_get_val(arg))
&& (class != PARS_FUNC_CMP)
&& (func != PARS_NOTFOUND_TOKEN)
&& (func != PARS_PRINTF_TOKEN)) {
diff --git a/storage/innobase/eval/eval0proc.c b/storage/innodb_plugin/eval/eval0proc.c
similarity index 71%
rename from storage/innobase/eval/eval0proc.c
rename to storage/innodb_plugin/eval/eval0proc.c
index a513e8e4024..3a4218d92bf 100644
--- a/storage/innobase/eval/eval0proc.c
+++ b/storage/innodb_plugin/eval/eval0proc.c
@@ -1,7 +1,24 @@
-/******************************************************
-Executes SQL stored procedures and their control structures
+/*****************************************************************************
-(c) 1998 Innobase Oy
+Copyright (c) 1998, 2009, Innobase Oy. All Rights Reserved.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; version 2 of the License.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place, Suite 330, Boston, MA 02111-1307 USA
+
+*****************************************************************************/
+
+/**************************************************//**
+@file eval/eval0proc.c
+Executes SQL stored procedures and their control structures
Created 1/20/1998 Heikki Tuuri
*******************************************************/
@@ -12,14 +29,14 @@ Created 1/20/1998 Heikki Tuuri
#include "eval0proc.ic"
#endif
-/**************************************************************************
-Performs an execution step of an if-statement node. */
-
+/**********************************************************************//**
+Performs an execution step of an if-statement node.
+@return query thread to run next or NULL */
+UNIV_INTERN
que_thr_t*
if_step(
/*====*/
- /* out: query thread to run next or NULL */
- que_thr_t* thr) /* in: query thread */
+ que_thr_t* thr) /*!< in: query thread */
{
if_node_t* node;
elsif_node_t* elsif_node;
@@ -88,14 +105,14 @@ if_step(
return(thr);
}
-/**************************************************************************
-Performs an execution step of a while-statement node. */
-
+/**********************************************************************//**
+Performs an execution step of a while-statement node.
+@return query thread to run next or NULL */
+UNIV_INTERN
que_thr_t*
while_step(
/*=======*/
- /* out: query thread to run next or NULL */
- que_thr_t* thr) /* in: query thread */
+ que_thr_t* thr) /*!< in: query thread */
{
while_node_t* node;
@@ -124,14 +141,14 @@ while_step(
return(thr);
}
-/**************************************************************************
-Performs an execution step of an assignment statement node. */
-
+/**********************************************************************//**
+Performs an execution step of an assignment statement node.
+@return query thread to run next or NULL */
+UNIV_INTERN
que_thr_t*
assign_step(
/*========*/
- /* out: query thread to run next or NULL */
- que_thr_t* thr) /* in: query thread */
+ que_thr_t* thr) /*!< in: query thread */
{
assign_node_t* node;
@@ -151,14 +168,14 @@ assign_step(
return(thr);
}
-/**************************************************************************
-Performs an execution step of a for-loop node. */
-
+/**********************************************************************//**
+Performs an execution step of a for-loop node.
+@return query thread to run next or NULL */
+UNIV_INTERN
que_thr_t*
for_step(
/*=====*/
- /* out: query thread to run next or NULL */
- que_thr_t* thr) /* in: query thread */
+ que_thr_t* thr) /*!< in: query thread */
{
for_node_t* node;
que_node_t* parent;
@@ -213,14 +230,14 @@ for_step(
return(thr);
}
-/**************************************************************************
-Performs an execution step of an exit statement node. */
-
+/**********************************************************************//**
+Performs an execution step of an exit statement node.
+@return query thread to run next or NULL */
+UNIV_INTERN
que_thr_t*
exit_step(
/*======*/
- /* out: query thread to run next or NULL */
- que_thr_t* thr) /* in: query thread */
+ que_thr_t* thr) /*!< in: query thread */
{
exit_node_t* node;
que_node_t* loop_node;
@@ -245,14 +262,14 @@ exit_step(
return(thr);
}
-/**************************************************************************
-Performs an execution step of a return-statement node. */
-
+/**********************************************************************//**
+Performs an execution step of a return-statement node.
+@return query thread to run next or NULL */
+UNIV_INTERN
que_thr_t*
return_step(
/*========*/
- /* out: query thread to run next or NULL */
- que_thr_t* thr) /* in: query thread */
+ que_thr_t* thr) /*!< in: query thread */
{
return_node_t* node;
que_node_t* parent;
diff --git a/storage/innobase/fil/fil0fil.c b/storage/innodb_plugin/fil/fil0fil.c
similarity index 69%
rename from storage/innobase/fil/fil0fil.c
rename to storage/innodb_plugin/fil/fil0fil.c
index c63d67cae60..96e60b0128f 100644
--- a/storage/innobase/fil/fil0fil.c
+++ b/storage/innodb_plugin/fil/fil0fil.c
@@ -1,7 +1,24 @@
-/******************************************************
-The tablespace memory cache
+/*****************************************************************************
-(c) 1995 Innobase Oy
+Copyright (c) 1995, 2009, Innobase Oy. All Rights Reserved.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; version 2 of the License.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place, Suite 330, Boston, MA 02111-1307 USA
+
+*****************************************************************************/
+
+/**************************************************//**
+@file fil/fil0fil.c
+The tablespace memory cache
Created 10/25/1995 Heikki Tuuri
*******************************************************/
@@ -9,16 +26,11 @@ Created 10/25/1995 Heikki Tuuri
#include "fil0fil.h"
#include "mem0mem.h"
-#include "sync0sync.h"
#include "hash0hash.h"
#include "os0file.h"
-#include "os0sync.h"
#include "mach0data.h"
-#include "ibuf0ibuf.h"
#include "buf0buf.h"
#include "buf0flu.h"
-#include "buf0lru.h"
-#include "log0log.h"
#include "log0recv.h"
#include "fsp0fsp.h"
#include "srv0srv.h"
@@ -26,7 +38,15 @@ Created 10/25/1995 Heikki Tuuri
#include "mtr0mtr.h"
#include "mtr0log.h"
#include "dict0dict.h"
-
+#include "page0zip.h"
+#ifndef UNIV_HOTBACKUP
+# include "buf0lru.h"
+# include "ibuf0ibuf.h"
+# include "sync0sync.h"
+# include "os0sync.h"
+#else /* !UNIV_HOTBACKUP */
+static ulint srv_data_read, srv_data_written;
+#endif /* !UNIV_HOTBACKUP */
/*
IMPLEMENTATION OF THE TABLESPACE MEMORY CACHE
@@ -84,131 +104,144 @@ out of the LRU-list and keep a count of pending operations. When an operation
completes, we decrement the count and return the file node to the LRU-list if
the count drops to zero. */
-/* When mysqld is run, the default directory "." is the mysqld datadir,
+/** When mysqld is run, the default directory "." is the mysqld datadir,
but in the MySQL Embedded Server Library and ibbackup it is not the default
directory, and we must set the base file path explicitly */
-const char* fil_path_to_mysql_datadir = ".";
+UNIV_INTERN const char* fil_path_to_mysql_datadir = ".";
-/* The number of fsyncs done to the log */
-ulint fil_n_log_flushes = 0;
+/** The number of fsyncs done to the log */
+UNIV_INTERN ulint fil_n_log_flushes = 0;
-ulint fil_n_pending_log_flushes = 0;
-ulint fil_n_pending_tablespace_flushes = 0;
+/** Number of pending redo log flushes */
+UNIV_INTERN ulint fil_n_pending_log_flushes = 0;
+/** Number of pending tablespace flushes */
+UNIV_INTERN ulint fil_n_pending_tablespace_flushes = 0;
-/* Null file address */
-fil_addr_t fil_addr_null = {FIL_NULL, 0};
+/** The null file address */
+UNIV_INTERN fil_addr_t fil_addr_null = {FIL_NULL, 0};
-/* File node of a tablespace or the log data space */
+/** File node of a tablespace or the log data space */
struct fil_node_struct {
- fil_space_t* space; /* backpointer to the space where this node
+ fil_space_t* space; /*!< backpointer to the space where this node
belongs */
- char* name; /* path to the file */
- ibool open; /* TRUE if file open */
- os_file_t handle; /* OS handle to the file, if file open */
- ibool is_raw_disk;/* TRUE if the 'file' is actually a raw
+ char* name; /*!< path to the file */
+ ibool open; /*!< TRUE if file open */
+ os_file_t handle; /*!< OS handle to the file, if file open */
+ ibool is_raw_disk;/*!< TRUE if the 'file' is actually a raw
device or a raw disk partition */
- ulint size; /* size of the file in database pages, 0 if
+ ulint size; /*!< size of the file in database pages, 0 if
not known yet; the possible last incomplete
megabyte may be ignored if space == 0 */
ulint n_pending;
- /* count of pending i/o's on this file;
+ /*!< count of pending i/o's on this file;
closing of the file is not allowed if
this is > 0 */
ulint n_pending_flushes;
- /* count of pending flushes on this file;
+ /*!< count of pending flushes on this file;
closing of the file is not allowed if
this is > 0 */
- ib_longlong modification_counter;/* when we write to the file we
+ ib_int64_t modification_counter;/*!< when we write to the file we
increment this by one */
- ib_longlong flush_counter;/* up to what modification_counter value
- we have flushed the modifications to disk */
+ ib_int64_t flush_counter;/*!< up to what
+ modification_counter value we have
+ flushed the modifications to disk */
UT_LIST_NODE_T(fil_node_t) chain;
- /* link field for the file chain */
+ /*!< link field for the file chain */
UT_LIST_NODE_T(fil_node_t) LRU;
- /* link field for the LRU list */
- ulint magic_n;
+ /*!< link field for the LRU list */
+ ulint magic_n;/*!< FIL_NODE_MAGIC_N */
};
+/** Value of fil_node_struct::magic_n */
#define FIL_NODE_MAGIC_N 89389
-/* Tablespace or log data space: let us call them by a common name space */
+/** Tablespace or log data space: let us call them by a common name space */
struct fil_space_struct {
- char* name; /* space name = the path to the first file in
+ char* name; /*!< space name = the path to the first file in
it */
- ulint id; /* space id */
- ib_longlong tablespace_version;
- /* in DISCARD/IMPORT this timestamp is used to
- check if we should ignore an insert buffer
- merge request for a page because it actually
- was for the previous incarnation of the
- space */
- ibool mark; /* this is set to TRUE at database startup if
+ ulint id; /*!< space id */
+ ib_int64_t tablespace_version;
+ /*!< in DISCARD/IMPORT this timestamp
+ is used to check if we should ignore
+ an insert buffer merge request for a
+ page because it actually was for the
+ previous incarnation of the space */
+ ibool mark; /*!< this is set to TRUE at database startup if
the space corresponds to a table in the InnoDB
data dictionary; so we can print a warning of
orphaned tablespaces */
- ibool stop_ios;/* TRUE if we want to rename the .ibd file of
- tablespace and want to stop temporarily
- posting of new i/o requests on the file */
+ ibool stop_ios;/*!< TRUE if we want to rename the
+ .ibd file of tablespace and want to
+ stop temporarily posting of new i/o
+ requests on the file */
ibool stop_ibuf_merges;
- /* we set this TRUE when we start deleting a
- single-table tablespace */
+ /*!< we set this TRUE when we start
+ deleting a single-table tablespace */
ibool is_being_deleted;
- /* this is set to TRUE when we start
+ /*!< this is set to TRUE when we start
deleting a single-table tablespace and its
file; when this flag is set no further i/o
or flush requests can be placed on this space,
though there may be such requests still being
processed on this space */
- ulint purpose;/* FIL_TABLESPACE, FIL_LOG, or FIL_ARCH_LOG */
+ ulint purpose;/*!< FIL_TABLESPACE, FIL_LOG, or
+ FIL_ARCH_LOG */
UT_LIST_BASE_NODE_T(fil_node_t) chain;
- /* base node for the file chain */
- ulint size; /* space size in pages; 0 if a single-table
+ /*!< base node for the file chain */
+ ulint size; /*!< space size in pages; 0 if a single-table
tablespace whose size we do not know yet;
last incomplete megabytes in data files may be
ignored if space == 0 */
+ ulint flags; /*!< compressed page size and file format, or 0 */
ulint n_reserved_extents;
- /* number of reserved free extents for
+ /*!< number of reserved free extents for
ongoing operations like B-tree page split */
- ulint n_pending_flushes; /* this is > 0 when flushing
+ ulint n_pending_flushes; /*!< this is positive when flushing
the tablespace to disk; dropping of the
- tablespace is forbidden if this is > 0 */
- ulint n_pending_ibuf_merges;/* this is > 0 when merging
- insert buffer entries to a page so that we
- may need to access the ibuf bitmap page in the
- tablespade: dropping of the tablespace is
- forbidden if this is > 0 */
- hash_node_t hash; /* hash chain node */
- hash_node_t name_hash;/* hash chain the name_hash table */
- rw_lock_t latch; /* latch protecting the file space storage
+ tablespace is forbidden if this is positive */
+ ulint n_pending_ibuf_merges;/*!< this is positive
+ when merging insert buffer entries to
+ a page so that we may need to access
+ the ibuf bitmap page in the
+ tablespade: dropping of the tablespace
+ is forbidden if this is positive */
+ hash_node_t hash; /*!< hash chain node */
+ hash_node_t name_hash;/*!< hash chain the name_hash table */
+#ifndef UNIV_HOTBACKUP
+ rw_lock_t latch; /*!< latch protecting the file space storage
allocation */
+#endif /* !UNIV_HOTBACKUP */
UT_LIST_NODE_T(fil_space_t) unflushed_spaces;
- /* list of spaces with at least one unflushed
+ /*!< list of spaces with at least one unflushed
file we have written to */
- ibool is_in_unflushed_spaces; /* TRUE if this space is
- currently in the list above */
+ ibool is_in_unflushed_spaces; /*!< TRUE if this space is
+ currently in unflushed_spaces */
UT_LIST_NODE_T(fil_space_t) space_list;
- /* list of all spaces */
- ibuf_data_t* ibuf_data;
- /* insert buffer data */
- ulint magic_n;
+ /*!< list of all spaces */
+ ulint magic_n;/*!< FIL_SPACE_MAGIC_N */
};
+/** Value of fil_space_struct::magic_n */
#define FIL_SPACE_MAGIC_N 89472
-/* The tablespace memory cache; also the totality of logs = the log data space,
-is stored here; below we talk about tablespaces, but also the ib_logfiles
-form a 'space' and it is handled here */
-
+/** The tablespace memory cache */
typedef struct fil_system_struct fil_system_t;
+
+/** The tablespace memory cache; also the totality of logs (the log
+data space) is stored here; below we talk about tablespaces, but also
+the ib_logfiles form a 'space' and it is handled here */
+
struct fil_system_struct {
- mutex_t mutex; /* The mutex protecting the cache */
- hash_table_t* spaces; /* The hash table of spaces in the
+#ifndef UNIV_HOTBACKUP
+ mutex_t mutex; /*!< The mutex protecting the cache */
+#endif /* !UNIV_HOTBACKUP */
+ hash_table_t* spaces; /*!< The hash table of spaces in the
system; they are hashed on the space
id */
- hash_table_t* name_hash; /* hash table based on the space
+ hash_table_t* name_hash; /*!< hash table based on the space
name */
UT_LIST_BASE_NODE_T(fil_node_t) LRU;
- /* base node for the LRU list of the
+ /*!< base node for the LRU list of the
most recently used open files with no
pending i/o's; if we start an i/o on
the file, we first remove it from this
@@ -219,24 +252,24 @@ struct fil_system_struct {
after the startup, and kept open until
shutdown */
UT_LIST_BASE_NODE_T(fil_space_t) unflushed_spaces;
- /* base node for the list of those
+ /*!< base node for the list of those
tablespaces whose files contain
unflushed writes; those spaces have
at least one file node where
modification_counter > flush_counter */
- ulint n_open; /* number of files currently open */
- ulint max_n_open; /* n_open is not allowed to exceed
+ ulint n_open; /*!< number of files currently open */
+ ulint max_n_open; /*!< n_open is not allowed to exceed
this */
- ib_longlong modification_counter;/* when we write to a file we
+ ib_int64_t modification_counter;/*!< when we write to a file we
increment this by one */
- ulint max_assigned_id;/* maximum space id in the existing
+ ulint max_assigned_id;/*!< maximum space id in the existing
tables, or assigned during the time
mysqld has been up; at an InnoDB
startup we scan the data dictionary
and set here the maximum of the
space id's of the tables there */
- ib_longlong tablespace_version;
- /* a counter which is incremented for
+ ib_int64_t tablespace_version;
+ /*!< a counter which is incremented for
every space object memory creation;
every space mem object gets a
'timestamp' from this; in DISCARD/
@@ -244,15 +277,15 @@ struct fil_system_struct {
should ignore an insert buffer merge
request */
UT_LIST_BASE_NODE_T(fil_space_t) space_list;
- /* list of all file spaces */
+ /*!< list of all file spaces */
};
-/* The tablespace memory cache. This variable is NULL before the module is
+/** The tablespace memory cache. This variable is NULL before the module is
initialized. */
-fil_system_t* fil_system = NULL;
+static fil_system_t* fil_system = NULL;
-/************************************************************************
+/********************************************************************//**
NOTE: you must call fil_mutex_enter_and_prepare_for_io() first!
Prepares a file node for i/o. Opens the file if it is closed. Updates the
@@ -263,153 +296,228 @@ static
void
fil_node_prepare_for_io(
/*====================*/
- fil_node_t* node, /* in: file node */
- fil_system_t* system, /* in: tablespace memory cache */
- fil_space_t* space); /* in: space */
-/************************************************************************
+ fil_node_t* node, /*!< in: file node */
+ fil_system_t* system, /*!< in: tablespace memory cache */
+ fil_space_t* space); /*!< in: space */
+/********************************************************************//**
Updates the data structures when an i/o operation finishes. Updates the
pending i/o's field in the node appropriately. */
static
void
fil_node_complete_io(
/*=================*/
- fil_node_t* node, /* in: file node */
- fil_system_t* system, /* in: tablespace memory cache */
- ulint type); /* in: OS_FILE_WRITE or OS_FILE_READ; marks
+ fil_node_t* node, /*!< in: file node */
+ fil_system_t* system, /*!< in: tablespace memory cache */
+ ulint type); /*!< in: OS_FILE_WRITE or OS_FILE_READ; marks
the node as modified if
type == OS_FILE_WRITE */
-/***********************************************************************
+/*******************************************************************//**
Checks if a single-table tablespace for a given table name exists in the
-tablespace memory cache. */
+tablespace memory cache.
+@return space id, ULINT_UNDEFINED if not found */
static
ulint
fil_get_space_id_for_table(
/*=======================*/
- /* out: space id, ULINT_UNDEFINED if not
- found */
- const char* name); /* in: table name in the standard
+ const char* name); /*!< in: table name in the standard
'databasename/tablename' format */
+/********************************************************************//**
+Reads data from a space to a buffer. Remember that the possible incomplete
+blocks at the end of file are ignored: they are not taken into account when
+calculating the byte offset within a space.
+@return DB_SUCCESS, or DB_TABLESPACE_DELETED if we are trying to do
+i/o on a tablespace which does not exist */
+UNIV_INLINE
+ulint
+fil_read(
+/*=====*/
+ ibool sync, /*!< in: TRUE if synchronous aio is desired */
+ ulint space_id, /*!< in: space id */
+ ulint zip_size, /*!< in: compressed page size in bytes;
+ 0 for uncompressed pages */
+ ulint block_offset, /*!< in: offset in number of blocks */
+ ulint byte_offset, /*!< in: remainder of offset in bytes; in aio
+ this must be divisible by the OS block size */
+ ulint len, /*!< in: how many bytes to read; this must not
+ cross a file boundary; in aio this must be a
+ block size multiple */
+ void* buf, /*!< in/out: buffer where to store data read;
+ in aio this must be appropriately aligned */
+ void* message) /*!< in: message for aio handler if non-sync
+ aio used, else ignored */
+{
+ return(fil_io(OS_FILE_READ, sync, space_id, zip_size, block_offset,
+ byte_offset, len, buf, message));
+}
+/********************************************************************//**
+Writes data to a space from a buffer. Remember that the possible incomplete
+blocks at the end of file are ignored: they are not taken into account when
+calculating the byte offset within a space.
+@return DB_SUCCESS, or DB_TABLESPACE_DELETED if we are trying to do
+i/o on a tablespace which does not exist */
+UNIV_INLINE
+ulint
+fil_write(
+/*======*/
+ ibool sync, /*!< in: TRUE if synchronous aio is desired */
+ ulint space_id, /*!< in: space id */
+ ulint zip_size, /*!< in: compressed page size in bytes;
+ 0 for uncompressed pages */
+ ulint block_offset, /*!< in: offset in number of blocks */
+ ulint byte_offset, /*!< in: remainder of offset in bytes; in aio
+ this must be divisible by the OS block size */
+ ulint len, /*!< in: how many bytes to write; this must
+ not cross a file boundary; in aio this must
+ be a block size multiple */
+ void* buf, /*!< in: buffer from which to write; in aio
+ this must be appropriately aligned */
+ void* message) /*!< in: message for aio handler if non-sync
+ aio used, else ignored */
+{
+ return(fil_io(OS_FILE_WRITE, sync, space_id, zip_size, block_offset,
+ byte_offset, len, buf, message));
+}
-/***********************************************************************
-Returns the version number of a tablespace, -1 if not found. */
+/*******************************************************************//**
+Returns the table space by a given id, NULL if not found. */
+UNIV_INLINE
+fil_space_t*
+fil_space_get_by_id(
+/*================*/
+ ulint id) /*!< in: space id */
+{
+ fil_space_t* space;
-ib_longlong
+ ut_ad(mutex_own(&fil_system->mutex));
+
+ HASH_SEARCH(hash, fil_system->spaces, id,
+ fil_space_t*, space,
+ ut_ad(space->magic_n == FIL_SPACE_MAGIC_N),
+ space->id == id);
+
+ return(space);
+}
+
+/*******************************************************************//**
+Returns the table space by a given name, NULL if not found. */
+UNIV_INLINE
+fil_space_t*
+fil_space_get_by_name(
+/*==================*/
+ const char* name) /*!< in: space name */
+{
+ fil_space_t* space;
+ ulint fold;
+
+ ut_ad(mutex_own(&fil_system->mutex));
+
+ fold = ut_fold_string(name);
+
+ HASH_SEARCH(name_hash, fil_system->name_hash, fold,
+ fil_space_t*, space,
+ ut_ad(space->magic_n == FIL_SPACE_MAGIC_N),
+ !strcmp(name, space->name));
+
+ return(space);
+}
+
+#ifndef UNIV_HOTBACKUP
+/*******************************************************************//**
+Returns the version number of a tablespace, -1 if not found.
+@return version number, -1 if the tablespace does not exist in the
+memory cache */
+UNIV_INTERN
+ib_int64_t
fil_space_get_version(
/*==================*/
- /* out: version number, -1 if the tablespace does not
- exist in the memory cache */
- ulint id) /* in: space id */
+ ulint id) /*!< in: space id */
{
- fil_system_t* system = fil_system;
fil_space_t* space;
- ib_longlong version = -1;
+ ib_int64_t version = -1;
- ut_ad(system);
+ ut_ad(fil_system);
- mutex_enter(&(system->mutex));
+ mutex_enter(&fil_system->mutex);
- HASH_SEARCH(hash, system->spaces, id, space, space->id == id);
+ space = fil_space_get_by_id(id);
if (space) {
version = space->tablespace_version;
}
- mutex_exit(&(system->mutex));
+ mutex_exit(&fil_system->mutex);
return(version);
}
-/***********************************************************************
-Returns the latch of a file space. */
-
+/*******************************************************************//**
+Returns the latch of a file space.
+@return latch protecting storage allocation */
+UNIV_INTERN
rw_lock_t*
fil_space_get_latch(
/*================*/
- /* out: latch protecting storage allocation */
- ulint id) /* in: space id */
+ ulint id, /*!< in: space id */
+ ulint* flags) /*!< out: tablespace flags */
{
- fil_system_t* system = fil_system;
fil_space_t* space;
- ut_ad(system);
+ ut_ad(fil_system);
- mutex_enter(&(system->mutex));
+ mutex_enter(&fil_system->mutex);
- HASH_SEARCH(hash, system->spaces, id, space, space->id == id);
+ space = fil_space_get_by_id(id);
ut_a(space);
- mutex_exit(&(system->mutex));
+ if (flags) {
+ *flags = space->flags;
+ }
+
+ mutex_exit(&fil_system->mutex);
return(&(space->latch));
}
-/***********************************************************************
-Returns the type of a file space. */
-
+/*******************************************************************//**
+Returns the type of a file space.
+@return FIL_TABLESPACE or FIL_LOG */
+UNIV_INTERN
ulint
fil_space_get_type(
/*===============*/
- /* out: FIL_TABLESPACE or FIL_LOG */
- ulint id) /* in: space id */
+ ulint id) /*!< in: space id */
{
- fil_system_t* system = fil_system;
fil_space_t* space;
- ut_ad(system);
+ ut_ad(fil_system);
- mutex_enter(&(system->mutex));
+ mutex_enter(&fil_system->mutex);
- HASH_SEARCH(hash, system->spaces, id, space, space->id == id);
+ space = fil_space_get_by_id(id);
ut_a(space);
- mutex_exit(&(system->mutex));
+ mutex_exit(&fil_system->mutex);
return(space->purpose);
}
+#endif /* !UNIV_HOTBACKUP */
-/***********************************************************************
-Returns the ibuf data of a file space. */
-
-ibuf_data_t*
-fil_space_get_ibuf_data(
-/*====================*/
- /* out: ibuf data for this space */
- ulint id) /* in: space id */
-{
- fil_system_t* system = fil_system;
- fil_space_t* space;
-
- ut_ad(system);
-
- ut_a(id == 0);
-
- mutex_enter(&(system->mutex));
-
- HASH_SEARCH(hash, system->spaces, id, space, space->id == id);
-
- mutex_exit(&(system->mutex));
-
- ut_a(space);
-
- return(space->ibuf_data);
-}
-
-/**************************************************************************
+/**********************************************************************//**
Checks if all the file nodes in a space are flushed. The caller must hold
-the fil_system mutex. */
+the fil_system mutex.
+@return TRUE if all are flushed */
static
ibool
fil_space_is_flushed(
/*=================*/
- /* out: TRUE if all are flushed */
- fil_space_t* space) /* in: space */
+ fil_space_t* space) /*!< in: space */
{
fil_node_t* node;
- ut_ad(mutex_own(&(fil_system->mutex)));
+ ut_ad(mutex_own(&fil_system->mutex));
node = UT_LIST_GET_FIRST(space->chain);
@@ -425,27 +533,26 @@ fil_space_is_flushed(
return(TRUE);
}
-/***********************************************************************
+/*******************************************************************//**
Appends a new file to the chain of files of a space. File must be closed. */
-
+UNIV_INTERN
void
fil_node_create(
/*============*/
- const char* name, /* in: file name (file must be closed) */
- ulint size, /* in: file size in database blocks, rounded
+ const char* name, /*!< in: file name (file must be closed) */
+ ulint size, /*!< in: file size in database blocks, rounded
downwards to an integer */
- ulint id, /* in: space id where to append */
- ibool is_raw) /* in: TRUE if a raw device or
+ ulint id, /*!< in: space id where to append */
+ ibool is_raw) /*!< in: TRUE if a raw device or
a raw disk partition */
{
- fil_system_t* system = fil_system;
fil_node_t* node;
fil_space_t* space;
- ut_a(system);
+ ut_a(fil_system);
ut_a(name);
- mutex_enter(&(system->mutex));
+ mutex_enter(&fil_system->mutex);
node = mem_alloc(sizeof(fil_node_t));
@@ -463,7 +570,7 @@ fil_node_create(
node->modification_counter = 0;
node->flush_counter = 0;
- HASH_SEARCH(hash, system->spaces, id, space, space->id == id);
+ space = fil_space_get_by_id(id);
if (!space) {
ut_print_timestamp(stderr);
@@ -476,7 +583,7 @@ fil_node_create(
mem_free(node);
- mutex_exit(&(system->mutex));
+ mutex_exit(&fil_system->mutex);
return;
}
@@ -487,21 +594,21 @@ fil_node_create(
UT_LIST_ADD_LAST(chain, space->chain, node);
- mutex_exit(&(system->mutex));
+ mutex_exit(&fil_system->mutex);
}
-/************************************************************************
+/********************************************************************//**
Opens a the file of a node of a tablespace. The caller must own the fil_system
mutex. */
static
void
fil_node_open_file(
/*===============*/
- fil_node_t* node, /* in: file node */
- fil_system_t* system, /* in: tablespace memory cache */
- fil_space_t* space) /* in: space */
+ fil_node_t* node, /*!< in: file node */
+ fil_system_t* system, /*!< in: tablespace memory cache */
+ fil_space_t* space) /*!< in: space */
{
- ib_longlong size_bytes;
+ ib_int64_t size_bytes;
ulint size_low;
ulint size_high;
ibool ret;
@@ -510,6 +617,7 @@ fil_node_open_file(
byte* buf2;
byte* page;
ulint space_id;
+ ulint flags;
#endif /* !UNIV_HOTBACKUP */
ut_ad(mutex_own(&(system->mutex)));
@@ -543,11 +651,11 @@ fil_node_open_file(
os_file_get_size(node->handle, &size_low, &size_high);
- size_bytes = (((ib_longlong)size_high) << 32)
- + (ib_longlong)size_low;
+ size_bytes = (((ib_int64_t)size_high) << 32)
+ + (ib_int64_t)size_low;
#ifdef UNIV_HOTBACKUP
node->size = (ulint) (size_bytes / UNIV_PAGE_SIZE);
-
+ /* TODO: adjust to zip_size, like below? */
#else
ut_a(space->purpose != FIL_LOG);
ut_a(space->id != 0);
@@ -577,6 +685,7 @@ fil_node_open_file(
success = os_file_read(node->handle, page, 0, 0,
UNIV_PAGE_SIZE);
space_id = fsp_header_get_space_id(page);
+ flags = fsp_header_get_flags(page);
ut_free(buf2);
@@ -584,31 +693,47 @@ fil_node_open_file(
os_file_close(node->handle);
- if (space_id == ULINT_UNDEFINED || space_id == 0) {
- fprintf(stderr,
- "InnoDB: Error: tablespace id %lu"
- " in file %s is not sensible\n",
- (ulong) space_id, node->name);
-
- ut_a(0);
- }
-
- if (space_id != space->id) {
+ if (UNIV_UNLIKELY(space_id != space->id)) {
fprintf(stderr,
"InnoDB: Error: tablespace id is %lu"
" in the data dictionary\n"
"InnoDB: but in file %s it is %lu!\n",
space->id, node->name, space_id);
- ut_a(0);
+ ut_error;
}
- if (size_bytes >= FSP_EXTENT_SIZE * UNIV_PAGE_SIZE) {
- node->size = (ulint)
- ((size_bytes / (1024 * 1024))
- * ((1024 * 1024) / UNIV_PAGE_SIZE));
- } else {
+ if (UNIV_UNLIKELY(space_id == ULINT_UNDEFINED
+ || space_id == 0)) {
+ fprintf(stderr,
+ "InnoDB: Error: tablespace id %lu"
+ " in file %s is not sensible\n",
+ (ulong) space_id, node->name);
+
+ ut_error;
+ }
+
+ if (UNIV_UNLIKELY(space->flags != flags)) {
+ fprintf(stderr,
+ "InnoDB: Error: table flags are %lx"
+ " in the data dictionary\n"
+ "InnoDB: but the flags in file %s are %lx!\n",
+ space->flags, node->name, flags);
+
+ ut_error;
+ }
+
+ if (size_bytes >= 1024 * 1024) {
+ /* Truncate the size to whole megabytes. */
+ size_bytes = ut_2pow_round(size_bytes, 1024 * 1024);
+ }
+
+ if (!(flags & DICT_TF_ZSSIZE_MASK)) {
node->size = (ulint) (size_bytes / UNIV_PAGE_SIZE);
+ } else {
+ node->size = (ulint)
+ (size_bytes
+ / dict_table_flags_to_zip_size(flags));
}
#endif
space->size += node->size;
@@ -644,14 +769,14 @@ fil_node_open_file(
}
}
-/**************************************************************************
+/**********************************************************************//**
Closes a file. */
static
void
fil_node_close_file(
/*================*/
- fil_node_t* node, /* in: file node */
- fil_system_t* system) /* in: tablespace memory cache */
+ fil_node_t* node, /*!< in: file node */
+ fil_system_t* system) /*!< in: tablespace memory cache */
{
ibool ret;
@@ -679,41 +804,38 @@ fil_node_close_file(
}
}
-/************************************************************************
+/********************************************************************//**
Tries to close a file in the LRU list. The caller must hold the fil_sys
-mutex. */
+mutex.
+@return TRUE if success, FALSE if should retry later; since i/o's
+generally complete in < 100 ms, and as InnoDB writes at most 128 pages
+from the buffer pool in a batch, and then immediately flushes the
+files, there is a good chance that the next time we find a suitable
+node from the LRU list */
static
ibool
fil_try_to_close_file_in_LRU(
/*=========================*/
- /* out: TRUE if success, FALSE if should retry
- later; since i/o's generally complete in <
- 100 ms, and as InnoDB writes at most 128 pages
- from the buffer pool in a batch, and then
- immediately flushes the files, there is a good
- chance that the next time we find a suitable
- node from the LRU list */
- ibool print_info) /* in: if TRUE, prints information why it
+ ibool print_info) /*!< in: if TRUE, prints information why it
cannot close a file */
{
- fil_system_t* system = fil_system;
fil_node_t* node;
- ut_ad(mutex_own(&(system->mutex)));
+ ut_ad(mutex_own(&fil_system->mutex));
- node = UT_LIST_GET_LAST(system->LRU);
+ node = UT_LIST_GET_LAST(fil_system->LRU);
if (print_info) {
fprintf(stderr,
"InnoDB: fil_sys open file LRU len %lu\n",
- (ulong) UT_LIST_GET_LEN(system->LRU));
+ (ulong) UT_LIST_GET_LEN(fil_system->LRU));
}
while (node != NULL) {
if (node->modification_counter == node->flush_counter
&& node->n_pending_flushes == 0) {
- fil_node_close_file(node, system);
+ fil_node_close_file(node, fil_system);
return(TRUE);
}
@@ -741,7 +863,7 @@ fil_try_to_close_file_in_LRU(
return(FALSE);
}
-/***********************************************************************
+/*******************************************************************//**
Reserves the fil_system mutex and tries to make sure we can open at least one
file while holding it. This should be called before calling
fil_node_prepare_for_io(), because that function may need to open a file. */
@@ -749,18 +871,16 @@ static
void
fil_mutex_enter_and_prepare_for_io(
/*===============================*/
- ulint space_id) /* in: space id */
+ ulint space_id) /*!< in: space id */
{
- fil_system_t* system = fil_system;
fil_space_t* space;
ibool success;
ibool print_info = FALSE;
ulint count = 0;
ulint count2 = 0;
- ut_ad(!mutex_own(&(system->mutex)));
retry:
- mutex_enter(&(system->mutex));
+ mutex_enter(&fil_system->mutex);
if (space_id == 0 || space_id >= SRV_LOG_SPACE_FIRST_ID) {
/* We keep log files and system tablespace files always open;
@@ -772,13 +892,13 @@ retry:
return;
}
- if (system->n_open < system->max_n_open) {
+ if (fil_system->n_open < fil_system->max_n_open) {
return;
}
- HASH_SEARCH(hash, system->spaces, space_id, space,
- space->id == space_id);
+ space = fil_space_get_by_id(space_id);
+
if (space != NULL && space->stop_ios) {
/* We are going to do a rename file and want to stop new i/o's
for a while */
@@ -791,7 +911,7 @@ retry:
(ulong) count2);
}
- mutex_exit(&(system->mutex));
+ mutex_exit(&fil_system->mutex);
os_thread_sleep(20000);
@@ -817,12 +937,12 @@ retry:
close_more:
success = fil_try_to_close_file_in_LRU(print_info);
- if (success && system->n_open >= system->max_n_open) {
+ if (success && fil_system->n_open >= fil_system->max_n_open) {
goto close_more;
}
- if (system->n_open < system->max_n_open) {
+ if (fil_system->n_open < fil_system->max_n_open) {
/* Ok */
return;
@@ -837,12 +957,13 @@ close_more:
"InnoDB: You may need to raise the value of"
" innodb_max_files_open in\n"
"InnoDB: my.cnf.\n",
- (ulong) system->n_open, (ulong) system->max_n_open);
+ (ulong) fil_system->n_open,
+ (ulong) fil_system->max_n_open);
return;
}
- mutex_exit(&(system->mutex));
+ mutex_exit(&fil_system->mutex);
#ifndef UNIV_HOTBACKUP
/* Wake the i/o-handler threads to make sure pending i/o's are
@@ -861,15 +982,15 @@ close_more:
goto retry;
}
-/***********************************************************************
+/*******************************************************************//**
Frees a file node object from a tablespace memory cache. */
static
void
fil_node_free(
/*==========*/
- fil_node_t* node, /* in, own: file node */
- fil_system_t* system, /* in: tablespace memory cache */
- fil_space_t* space) /* in: space where the file node is chained */
+ fil_node_t* node, /*!< in, own: file node */
+ fil_system_t* system, /*!< in: tablespace memory cache */
+ fil_space_t* space) /*!< in: space where the file node is chained */
{
ut_ad(node && system && space);
ut_ad(mutex_own(&(system->mutex)));
@@ -903,69 +1024,79 @@ fil_node_free(
mem_free(node);
}
-/********************************************************************
+#ifdef UNIV_LOG_ARCHIVE
+/****************************************************************//**
Drops files from the start of a file space, so that its size is cut by
the amount given. */
-
+UNIV_INTERN
void
fil_space_truncate_start(
/*=====================*/
- ulint id, /* in: space id */
- ulint trunc_len) /* in: truncate by this much; it is an error
+ ulint id, /*!< in: space id */
+ ulint trunc_len) /*!< in: truncate by this much; it is an error
if this does not equal to the combined size of
some initial files in the space */
{
- fil_system_t* system = fil_system;
fil_node_t* node;
fil_space_t* space;
- mutex_enter(&(system->mutex));
+ mutex_enter(&fil_system->mutex);
- HASH_SEARCH(hash, system->spaces, id, space, space->id == id);
+ space = fil_space_get_by_id(id);
ut_a(space);
while (trunc_len > 0) {
node = UT_LIST_GET_FIRST(space->chain);
- ut_a(node->size * UNIV_PAGE_SIZE >= trunc_len);
+ ut_a(node->size * UNIV_PAGE_SIZE <= trunc_len);
trunc_len -= node->size * UNIV_PAGE_SIZE;
- fil_node_free(node, system, space);
+ fil_node_free(node, fil_system, space);
}
- mutex_exit(&(system->mutex));
+ mutex_exit(&fil_system->mutex);
}
+#endif /* UNIV_LOG_ARCHIVE */
-/***********************************************************************
+/*******************************************************************//**
Creates a space memory object and puts it to the tablespace memory cache. If
-there is an error, prints an error message to the .err log. */
-
+there is an error, prints an error message to the .err log.
+@return TRUE if success */
+UNIV_INTERN
ibool
fil_space_create(
/*=============*/
- /* out: TRUE if success */
- const char* name, /* in: space name */
- ulint id, /* in: space id */
- ulint purpose)/* in: FIL_TABLESPACE, or FIL_LOG if log */
+ const char* name, /*!< in: space name */
+ ulint id, /*!< in: space id */
+ ulint flags, /*!< in: compressed page size
+ and file format, or 0 */
+ ulint purpose)/*!< in: FIL_TABLESPACE, or FIL_LOG if log */
{
- fil_system_t* system = fil_system;
fil_space_t* space;
- ulint namesake_id;
+
+ /* The tablespace flags (FSP_SPACE_FLAGS) should be 0 for
+ ROW_FORMAT=COMPACT (table->flags == DICT_TF_COMPACT) and
+ ROW_FORMAT=REDUNDANT (table->flags == 0). For any other
+ format, the tablespace flags should equal table->flags. */
+ ut_a(flags != DICT_TF_COMPACT);
+
try_again:
/*printf(
"InnoDB: Adding tablespace %lu of name %s, purpose %lu\n", id, name,
purpose);*/
- ut_a(system);
+ ut_a(fil_system);
ut_a(name);
- mutex_enter(&(system->mutex));
+ mutex_enter(&fil_system->mutex);
+
+ space = fil_space_get_by_name(name);
+
+ if (UNIV_LIKELY_NULL(space)) {
+ ulint namesake_id;
- HASH_SEARCH(name_hash, system->name_hash, ut_fold_string(name), space,
- 0 == strcmp(name, space->name));
- if (space != NULL) {
ut_print_timestamp(stderr);
fprintf(stderr,
" InnoDB: Warning: trying to init to the"
@@ -980,7 +1111,7 @@ try_again:
if (id == 0 || purpose != FIL_TABLESPACE) {
- mutex_exit(&(system->mutex));
+ mutex_exit(&fil_system->mutex);
return(FALSE);
}
@@ -1002,16 +1133,16 @@ try_again:
namesake_id = space->id;
- mutex_exit(&(system->mutex));
+ mutex_exit(&fil_system->mutex);
fil_space_free(namesake_id);
goto try_again;
}
- HASH_SEARCH(hash, system->spaces, id, space, space->id == id);
+ space = fil_space_get_by_id(id);
- if (space != NULL) {
+ if (UNIV_LIKELY_NULL(space)) {
fprintf(stderr,
"InnoDB: Error: trying to add tablespace %lu"
" of name ", (ulong) id);
@@ -1024,7 +1155,7 @@ try_again:
fputs(" already exists in the tablespace\n"
"InnoDB: memory cache!\n", stderr);
- mutex_exit(&(system->mutex));
+ mutex_exit(&fil_system->mutex);
return(FALSE);
}
@@ -1034,12 +1165,12 @@ try_again:
space->name = mem_strdup(name);
space->id = id;
- system->tablespace_version++;
- space->tablespace_version = system->tablespace_version;
+ fil_system->tablespace_version++;
+ space->tablespace_version = fil_system->tablespace_version;
space->mark = FALSE;
- if (purpose == FIL_TABLESPACE && id > system->max_assigned_id) {
- system->max_assigned_id = id;
+ if (purpose == FIL_TABLESPACE && id > fil_system->max_assigned_id) {
+ fil_system->max_assigned_id = id;
}
space->stop_ios = FALSE;
@@ -1047,6 +1178,7 @@ try_again:
space->is_being_deleted = FALSE;
space->purpose = purpose;
space->size = 0;
+ space->flags = flags;
space->n_reserved_extents = 0;
@@ -1056,42 +1188,38 @@ try_again:
UT_LIST_INIT(space->chain);
space->magic_n = FIL_SPACE_MAGIC_N;
- space->ibuf_data = NULL;
-
rw_lock_create(&space->latch, SYNC_FSP);
- HASH_INSERT(fil_space_t, hash, system->spaces, id, space);
+ HASH_INSERT(fil_space_t, hash, fil_system->spaces, id, space);
- HASH_INSERT(fil_space_t, name_hash, system->name_hash,
+ HASH_INSERT(fil_space_t, name_hash, fil_system->name_hash,
ut_fold_string(name), space);
space->is_in_unflushed_spaces = FALSE;
- UT_LIST_ADD_LAST(space_list, system->space_list, space);
+ UT_LIST_ADD_LAST(space_list, fil_system->space_list, space);
- mutex_exit(&(system->mutex));
+ mutex_exit(&fil_system->mutex);
return(TRUE);
}
-/***********************************************************************
+/*******************************************************************//**
Assigns a new space id for a new single-table tablespace. This works simply by
incrementing the global counter. If 4 billion id's is not enough, we may need
-to recycle id's. */
+to recycle id's.
+@return new tablespace id; ULINT_UNDEFINED if could not assign an id */
static
ulint
fil_assign_new_space_id(void)
/*=========================*/
- /* out: new tablespace id; ULINT_UNDEFINED if could
- not assign an id */
{
- fil_system_t* system = fil_system;
ulint id;
- mutex_enter(&(system->mutex));
+ mutex_enter(&fil_system->mutex);
- system->max_assigned_id++;
+ fil_system->max_assigned_id++;
- id = system->max_assigned_id;
+ id = fil_system->max_assigned_id;
if (id > (SRV_LOG_SPACE_FIRST_ID / 2) && (id % 1000000UL == 0)) {
ut_print_timestamp(stderr);
@@ -1117,35 +1245,34 @@ fil_assign_new_space_id(void)
" have to dump all your tables and\n"
"InnoDB: recreate the whole InnoDB installation.\n",
(ulong) id);
- system->max_assigned_id--;
+ fil_system->max_assigned_id--;
id = ULINT_UNDEFINED;
}
- mutex_exit(&(system->mutex));
+ mutex_exit(&fil_system->mutex);
return(id);
}
-/***********************************************************************
+/*******************************************************************//**
Frees a space object from the tablespace memory cache. Closes the files in
the chain but does not delete them. There must not be any pending i/o's or
-flushes on the files. */
-
+flushes on the files.
+@return TRUE if success */
+UNIV_INTERN
ibool
fil_space_free(
/*===========*/
- /* out: TRUE if success */
- ulint id) /* in: space id */
+ ulint id) /*!< in: space id */
{
- fil_system_t* system = fil_system;
fil_space_t* space;
fil_space_t* namespace;
fil_node_t* fil_node;
- mutex_enter(&(system->mutex));
+ mutex_enter(&fil_system->mutex);
- HASH_SEARCH(hash, system->spaces, id, space, space->id == id);
+ space = fil_space_get_by_id(id);
if (!space) {
ut_print_timestamp(stderr);
@@ -1154,29 +1281,28 @@ fil_space_free(
" from the cache but\n"
"InnoDB: it is not there.\n", (ulong) id);
- mutex_exit(&(system->mutex));
+ mutex_exit(&fil_system->mutex);
return(FALSE);
}
- HASH_DELETE(fil_space_t, hash, system->spaces, id, space);
+ HASH_DELETE(fil_space_t, hash, fil_system->spaces, id, space);
- HASH_SEARCH(name_hash, system->name_hash, ut_fold_string(space->name),
- namespace, 0 == strcmp(space->name, namespace->name));
+ namespace = fil_space_get_by_name(space->name);
ut_a(namespace);
ut_a(space == namespace);
- HASH_DELETE(fil_space_t, name_hash, system->name_hash,
+ HASH_DELETE(fil_space_t, name_hash, fil_system->name_hash,
ut_fold_string(space->name), space);
if (space->is_in_unflushed_spaces) {
space->is_in_unflushed_spaces = FALSE;
- UT_LIST_REMOVE(unflushed_spaces, system->unflushed_spaces,
+ UT_LIST_REMOVE(unflushed_spaces, fil_system->unflushed_spaces,
space);
}
- UT_LIST_REMOVE(space_list, system->space_list, space);
+ UT_LIST_REMOVE(space_list, fil_system->space_list, space);
ut_a(space->magic_n == FIL_SPACE_MAGIC_N);
ut_a(0 == space->n_pending_flushes);
@@ -1184,14 +1310,14 @@ fil_space_free(
fil_node = UT_LIST_GET_FIRST(space->chain);
while (fil_node != NULL) {
- fil_node_free(fil_node, system, space);
+ fil_node_free(fil_node, fil_system, space);
fil_node = UT_LIST_GET_FIRST(space->chain);
}
ut_a(0 == UT_LIST_GET_LEN(space->chain));
- mutex_exit(&(system->mutex));
+ mutex_exit(&fil_system->mutex);
rw_lock_free(&(space->latch));
@@ -1201,52 +1327,28 @@ fil_space_free(
return(TRUE);
}
-#ifdef UNIV_HOTBACKUP
-/***********************************************************************
-Returns the tablespace object for a given id, or NULL if not found from the
-tablespace memory cache. */
-static
-fil_space_t*
-fil_get_space_for_id_low(
-/*=====================*/
- /* out: tablespace object or NULL; NOTE that you must
- own &(fil_system->mutex) to call this function! */
- ulint id) /* in: space id */
-{
- fil_system_t* system = fil_system;
- fil_space_t* space;
-
- ut_ad(system);
-
- HASH_SEARCH(hash, system->spaces, id, space, space->id == id);
-
- return(space);
-}
-#endif
-
-/***********************************************************************
+/*******************************************************************//**
Returns the size of the space in pages. The tablespace must be cached in the
-memory cache. */
-
+memory cache.
+@return space size, 0 if space not found */
+UNIV_INTERN
ulint
fil_space_get_size(
/*===============*/
- /* out: space size, 0 if space not found */
- ulint id) /* in: space id */
+ ulint id) /*!< in: space id */
{
- fil_system_t* system = fil_system;
fil_node_t* node;
fil_space_t* space;
ulint size;
- ut_ad(system);
+ ut_ad(fil_system);
fil_mutex_enter_and_prepare_for_io(id);
- HASH_SEARCH(hash, system->spaces, id, space, space->id == id);
+ space = fil_space_get_by_id(id);
if (space == NULL) {
- mutex_exit(&(system->mutex));
+ mutex_exit(&fil_system->mutex);
return(0);
}
@@ -1262,27 +1364,101 @@ fil_space_get_size(
the file yet; the following calls will open it and update the
size fields */
- fil_node_prepare_for_io(node, system, space);
- fil_node_complete_io(node, system, OS_FILE_READ);
+ fil_node_prepare_for_io(node, fil_system, space);
+ fil_node_complete_io(node, fil_system, OS_FILE_READ);
}
size = space->size;
- mutex_exit(&(system->mutex));
+ mutex_exit(&fil_system->mutex);
return(size);
}
-/***********************************************************************
-Checks if the pair space, page_no refers to an existing page in a tablespace
-file space. The tablespace must be cached in the memory cache. */
+/*******************************************************************//**
+Returns the flags of the space. The tablespace must be cached
+in the memory cache.
+@return flags, ULINT_UNDEFINED if space not found */
+UNIV_INTERN
+ulint
+fil_space_get_flags(
+/*================*/
+ ulint id) /*!< in: space id */
+{
+ fil_node_t* node;
+ fil_space_t* space;
+ ulint flags;
+ ut_ad(fil_system);
+
+ if (UNIV_UNLIKELY(!id)) {
+ return(0);
+ }
+
+ fil_mutex_enter_and_prepare_for_io(id);
+
+ space = fil_space_get_by_id(id);
+
+ if (space == NULL) {
+ mutex_exit(&fil_system->mutex);
+
+ return(ULINT_UNDEFINED);
+ }
+
+ if (space->size == 0 && space->purpose == FIL_TABLESPACE) {
+ ut_a(id != 0);
+
+ ut_a(1 == UT_LIST_GET_LEN(space->chain));
+
+ node = UT_LIST_GET_FIRST(space->chain);
+
+ /* It must be a single-table tablespace and we have not opened
+ the file yet; the following calls will open it and update the
+ size fields */
+
+ fil_node_prepare_for_io(node, fil_system, space);
+ fil_node_complete_io(node, fil_system, OS_FILE_READ);
+ }
+
+ flags = space->flags;
+
+ mutex_exit(&fil_system->mutex);
+
+ return(flags);
+}
+
+/*******************************************************************//**
+Returns the compressed page size of the space, or 0 if the space
+is not compressed. The tablespace must be cached in the memory cache.
+@return compressed page size, ULINT_UNDEFINED if space not found */
+UNIV_INTERN
+ulint
+fil_space_get_zip_size(
+/*===================*/
+ ulint id) /*!< in: space id */
+{
+ ulint flags;
+
+ flags = fil_space_get_flags(id);
+
+ if (flags && flags != ULINT_UNDEFINED) {
+
+ return(dict_table_flags_to_zip_size(flags));
+ }
+
+ return(flags);
+}
+
+/*******************************************************************//**
+Checks if the pair space, page_no refers to an existing page in a tablespace
+file space. The tablespace must be cached in the memory cache.
+@return TRUE if the address is meaningful */
+UNIV_INTERN
ibool
fil_check_adress_in_tablespace(
/*===========================*/
- /* out: TRUE if the address is meaningful */
- ulint id, /* in: space id */
- ulint page_no)/* in: page number */
+ ulint id, /*!< in: space id */
+ ulint page_no)/*!< in: page number */
{
if (fil_space_get_size(id) > page_no) {
@@ -1292,84 +1468,58 @@ fil_check_adress_in_tablespace(
return(FALSE);
}
-/********************************************************************
-Creates a the tablespace memory cache. */
-static
-fil_system_t*
-fil_system_create(
-/*==============*/
- /* out, own: tablespace memory cache */
- ulint hash_size, /* in: hash table size */
- ulint max_n_open) /* in: maximum number of open files; must be
- > 10 */
+/****************************************************************//**
+Initializes the tablespace memory cache. */
+UNIV_INTERN
+void
+fil_init(
+/*=====*/
+ ulint hash_size, /*!< in: hash table size */
+ ulint max_n_open) /*!< in: max number of open files */
{
- fil_system_t* system;
+ ut_a(fil_system == NULL);
ut_a(hash_size > 0);
ut_a(max_n_open > 0);
- system = mem_alloc(sizeof(fil_system_t));
+ fil_system = mem_alloc(sizeof(fil_system_t));
- mutex_create(&system->mutex, SYNC_ANY_LATCH);
+ mutex_create(&fil_system->mutex, SYNC_ANY_LATCH);
- system->spaces = hash_create(hash_size);
- system->name_hash = hash_create(hash_size);
+ fil_system->spaces = hash_create(hash_size);
+ fil_system->name_hash = hash_create(hash_size);
- UT_LIST_INIT(system->LRU);
+ UT_LIST_INIT(fil_system->LRU);
- system->n_open = 0;
- system->max_n_open = max_n_open;
+ fil_system->n_open = 0;
+ fil_system->max_n_open = max_n_open;
- system->modification_counter = 0;
- system->max_assigned_id = 0;
+ fil_system->modification_counter = 0;
+ fil_system->max_assigned_id = 0;
- system->tablespace_version = 0;
+ fil_system->tablespace_version = 0;
- UT_LIST_INIT(system->unflushed_spaces);
- UT_LIST_INIT(system->space_list);
-
- return(system);
+ UT_LIST_INIT(fil_system->unflushed_spaces);
+ UT_LIST_INIT(fil_system->space_list);
}
-/********************************************************************
-Initializes the tablespace memory cache. */
-
-void
-fil_init(
-/*=====*/
- ulint max_n_open) /* in: max number of open files */
-{
- ulint hash_size;
-
- ut_a(fil_system == NULL);
-
- if (srv_file_per_table) {
- hash_size = 50000;
- } else {
- hash_size = 5000;
- }
-
- fil_system = fil_system_create(hash_size, max_n_open);
-}
-
-/***********************************************************************
+/*******************************************************************//**
Opens all log files and system tablespace data files. They stay open until the
database server shutdown. This should be called at a server startup after the
space objects for the log and the system tablespace have been created. The
purpose of this operation is to make sure we never run out of file descriptors
if we need to read from the insert buffer or to write to the log. */
-
+UNIV_INTERN
void
fil_open_log_and_system_tablespace_files(void)
/*==========================================*/
{
- fil_system_t* system = fil_system;
fil_space_t* space;
fil_node_t* node;
- mutex_enter(&(system->mutex));
+ mutex_enter(&fil_system->mutex);
- space = UT_LIST_GET_FIRST(system->space_list);
+ space = UT_LIST_GET_FIRST(fil_system->space_list);
while (space != NULL) {
if (space->purpose != FIL_TABLESPACE || space->id == 0) {
@@ -1377,10 +1527,11 @@ fil_open_log_and_system_tablespace_files(void)
while (node != NULL) {
if (!node->open) {
- fil_node_open_file(node, system,
+ fil_node_open_file(node, fil_system,
space);
}
- if (system->max_n_open < 10 + system->n_open) {
+ if (fil_system->max_n_open
+ < 10 + fil_system->n_open) {
fprintf(stderr,
"InnoDB: Warning: you must"
" raise the value of"
@@ -1398,8 +1549,8 @@ fil_open_log_and_system_tablespace_files(void)
" Current open files %lu,"
" max allowed"
" open files %lu.\n",
- (ulong) system->n_open,
- (ulong) system->max_n_open);
+ (ulong) fil_system->n_open,
+ (ulong) fil_system->max_n_open);
}
node = UT_LIST_GET_NEXT(chain, node);
}
@@ -1407,100 +1558,78 @@ fil_open_log_and_system_tablespace_files(void)
space = UT_LIST_GET_NEXT(space_list, space);
}
- mutex_exit(&(system->mutex));
+ mutex_exit(&fil_system->mutex);
}
-/***********************************************************************
+/*******************************************************************//**
Closes all open files. There must not be any pending i/o's or not flushed
modifications in the files. */
-
+UNIV_INTERN
void
fil_close_all_files(void)
/*=====================*/
{
- fil_system_t* system = fil_system;
fil_space_t* space;
fil_node_t* node;
- mutex_enter(&(system->mutex));
+ mutex_enter(&fil_system->mutex);
- space = UT_LIST_GET_FIRST(system->space_list);
+ space = UT_LIST_GET_FIRST(fil_system->space_list);
while (space != NULL) {
node = UT_LIST_GET_FIRST(space->chain);
while (node != NULL) {
if (node->open) {
- fil_node_close_file(node, system);
+ fil_node_close_file(node, fil_system);
}
node = UT_LIST_GET_NEXT(chain, node);
}
space = UT_LIST_GET_NEXT(space_list, space);
}
- mutex_exit(&(system->mutex));
+ mutex_exit(&fil_system->mutex);
}
-/***********************************************************************
+/*******************************************************************//**
Sets the max tablespace id counter if the given number is bigger than the
previous value. */
-
+UNIV_INTERN
void
fil_set_max_space_id_if_bigger(
/*===========================*/
- ulint max_id) /* in: maximum known id */
+ ulint max_id) /*!< in: maximum known id */
{
- fil_system_t* system = fil_system;
-
if (max_id >= SRV_LOG_SPACE_FIRST_ID) {
fprintf(stderr,
"InnoDB: Fatal error: max tablespace id"
" is too high, %lu\n", (ulong) max_id);
- ut_a(0);
+ ut_error;
}
- mutex_enter(&(system->mutex));
+ mutex_enter(&fil_system->mutex);
- if (system->max_assigned_id < max_id) {
+ if (fil_system->max_assigned_id < max_id) {
- system->max_assigned_id = max_id;
+ fil_system->max_assigned_id = max_id;
}
- mutex_exit(&(system->mutex));
+ mutex_exit(&fil_system->mutex);
}
-/********************************************************************
-Initializes the ibuf data structure for space 0 == the system tablespace.
-This can be called after the file space headers have been created and the
-dictionary system has been initialized. */
-
-void
-fil_ibuf_init_at_db_start(void)
-/*===========================*/
-{
- fil_space_t* space;
-
- space = UT_LIST_GET_FIRST(fil_system->space_list);
-
- ut_a(space);
- ut_a(space->purpose == FIL_TABLESPACE);
-
- space->ibuf_data = ibuf_data_init_for_space(space->id);
-}
-
-/********************************************************************
+/****************************************************************//**
Writes the flushed lsn and the latest archived log number to the page header
-of the first page of a data file. */
+of the first page of a data file of the system tablespace (space 0),
+which is uncompressed. */
static
ulint
fil_write_lsn_and_arch_no_to_file(
/*==============================*/
- ulint space_id, /* in: space number */
- ulint sum_of_sizes, /* in: combined size of previous files in
- space, in database pages */
- dulint lsn, /* in: lsn to write */
- ulint arch_log_no /* in: archived log number to write */
- __attribute__((unused)))
+ ulint sum_of_sizes, /*!< in: combined size of previous files
+ in space, in database pages */
+ ib_uint64_t lsn, /*!< in: lsn to write */
+ ulint arch_log_no __attribute__((unused)))
+ /*!< in: archived log number to write */
{
byte* buf1;
byte* buf;
@@ -1508,32 +1637,35 @@ fil_write_lsn_and_arch_no_to_file(
buf1 = mem_alloc(2 * UNIV_PAGE_SIZE);
buf = ut_align(buf1, UNIV_PAGE_SIZE);
- fil_read(TRUE, space_id, sum_of_sizes, 0, UNIV_PAGE_SIZE, buf, NULL);
+ fil_read(TRUE, 0, 0, sum_of_sizes, 0, UNIV_PAGE_SIZE, buf, NULL);
- mach_write_to_8(buf + FIL_PAGE_FILE_FLUSH_LSN, lsn);
+ mach_write_ull(buf + FIL_PAGE_FILE_FLUSH_LSN, lsn);
- fil_write(TRUE, space_id, sum_of_sizes, 0, UNIV_PAGE_SIZE, buf, NULL);
+ fil_write(TRUE, 0, 0, sum_of_sizes, 0, UNIV_PAGE_SIZE, buf, NULL);
+
+ mem_free(buf1);
return(DB_SUCCESS);
}
-/********************************************************************
+/****************************************************************//**
Writes the flushed lsn and the latest archived log number to the page
-header of the first page of each data file in the system tablespace. */
-
+header of the first page of each data file in the system tablespace.
+@return DB_SUCCESS or error number */
+UNIV_INTERN
ulint
fil_write_flushed_lsn_to_data_files(
/*================================*/
- /* out: DB_SUCCESS or error number */
- dulint lsn, /* in: lsn to write */
- ulint arch_log_no) /* in: latest archived log file number */
+ ib_uint64_t lsn, /*!< in: lsn to write */
+ ulint arch_log_no) /*!< in: latest archived log
+ file number */
{
fil_space_t* space;
fil_node_t* node;
ulint sum_of_sizes;
ulint err;
- mutex_enter(&(fil_system->mutex));
+ mutex_enter(&fil_system->mutex);
space = UT_LIST_GET_FIRST(fil_system->space_list);
@@ -1550,17 +1682,16 @@ fil_write_flushed_lsn_to_data_files(
node = UT_LIST_GET_FIRST(space->chain);
while (node) {
- mutex_exit(&(fil_system->mutex));
+ mutex_exit(&fil_system->mutex);
err = fil_write_lsn_and_arch_no_to_file(
- space->id, sum_of_sizes, lsn,
- arch_log_no);
+ sum_of_sizes, lsn, arch_log_no);
if (err != DB_SUCCESS) {
return(err);
}
- mutex_enter(&(fil_system->mutex));
+ mutex_enter(&fil_system->mutex);
sum_of_sizes += node->size;
node = UT_LIST_GET_NEXT(chain, node);
@@ -1569,31 +1700,32 @@ fil_write_flushed_lsn_to_data_files(
space = UT_LIST_GET_NEXT(space_list, space);
}
- mutex_exit(&(fil_system->mutex));
+ mutex_exit(&fil_system->mutex);
return(DB_SUCCESS);
}
-/***********************************************************************
+/*******************************************************************//**
Reads the flushed lsn and arch no fields from a data file at database
startup. */
-
+UNIV_INTERN
void
fil_read_flushed_lsn_and_arch_log_no(
/*=================================*/
- os_file_t data_file, /* in: open data file */
- ibool one_read_already, /* in: TRUE if min and max parameters
- below already contain sensible data */
+ os_file_t data_file, /*!< in: open data file */
+ ibool one_read_already, /*!< in: TRUE if min and max
+ parameters below already
+ contain sensible data */
#ifdef UNIV_LOG_ARCHIVE
- ulint* min_arch_log_no, /* in/out: */
- ulint* max_arch_log_no, /* in/out: */
+ ulint* min_arch_log_no, /*!< in/out: */
+ ulint* max_arch_log_no, /*!< in/out: */
#endif /* UNIV_LOG_ARCHIVE */
- dulint* min_flushed_lsn, /* in/out: */
- dulint* max_flushed_lsn) /* in/out: */
+ ib_uint64_t* min_flushed_lsn, /*!< in/out: */
+ ib_uint64_t* max_flushed_lsn) /*!< in/out: */
{
- byte* buf;
- byte* buf2;
- dulint flushed_lsn;
+ byte* buf;
+ byte* buf2;
+ ib_uint64_t flushed_lsn;
buf2 = ut_malloc(2 * UNIV_PAGE_SIZE);
/* Align the memory for a possible read from a raw device */
@@ -1601,7 +1733,7 @@ fil_read_flushed_lsn_and_arch_log_no(
os_file_read(data_file, buf, 0, 0, UNIV_PAGE_SIZE);
- flushed_lsn = mach_read_from_8(buf + FIL_PAGE_FILE_FLUSH_LSN);
+ flushed_lsn = mach_read_ull(buf + FIL_PAGE_FILE_FLUSH_LSN);
ut_free(buf2);
@@ -1615,10 +1747,10 @@ fil_read_flushed_lsn_and_arch_log_no(
return;
}
- if (ut_dulint_cmp(*min_flushed_lsn, flushed_lsn) > 0) {
+ if (*min_flushed_lsn > flushed_lsn) {
*min_flushed_lsn = flushed_lsn;
}
- if (ut_dulint_cmp(*max_flushed_lsn, flushed_lsn) < 0) {
+ if (*max_flushed_lsn < flushed_lsn) {
*max_flushed_lsn = flushed_lsn;
}
#ifdef UNIV_LOG_ARCHIVE
@@ -1633,23 +1765,22 @@ fil_read_flushed_lsn_and_arch_log_no(
/*================ SINGLE-TABLE TABLESPACES ==========================*/
-/***********************************************************************
+#ifndef UNIV_HOTBACKUP
+/*******************************************************************//**
Increments the count of pending insert buffer page merges, if space is not
-being deleted. */
-
+being deleted.
+@return TRUE if being deleted, and ibuf merges should be skipped */
+UNIV_INTERN
ibool
fil_inc_pending_ibuf_merges(
/*========================*/
- /* out: TRUE if being deleted, and ibuf merges should
- be skipped */
- ulint id) /* in: space id */
+ ulint id) /*!< in: space id */
{
- fil_system_t* system = fil_system;
fil_space_t* space;
- mutex_enter(&(system->mutex));
+ mutex_enter(&fil_system->mutex);
- HASH_SEARCH(hash, system->spaces, id, space, space->id == id);
+ space = fil_space_get_by_id(id);
if (space == NULL) {
fprintf(stderr,
@@ -1659,32 +1790,31 @@ fil_inc_pending_ibuf_merges(
}
if (space == NULL || space->stop_ibuf_merges) {
- mutex_exit(&(system->mutex));
+ mutex_exit(&fil_system->mutex);
return(TRUE);
}
space->n_pending_ibuf_merges++;
- mutex_exit(&(system->mutex));
+ mutex_exit(&fil_system->mutex);
return(FALSE);
}
-/***********************************************************************
+/*******************************************************************//**
Decrements the count of pending insert buffer page merges. */
-
+UNIV_INTERN
void
fil_decr_pending_ibuf_merges(
/*=========================*/
- ulint id) /* in: space id */
+ ulint id) /*!< in: space id */
{
- fil_system_t* system = fil_system;
fil_space_t* space;
- mutex_enter(&(system->mutex));
+ mutex_enter(&fil_system->mutex);
- HASH_SEARCH(hash, system->spaces, id, space, space->id == id);
+ space = fil_space_get_by_id(id);
if (space == NULL) {
fprintf(stderr,
@@ -1697,16 +1827,17 @@ fil_decr_pending_ibuf_merges(
space->n_pending_ibuf_merges--;
}
- mutex_exit(&(system->mutex));
+ mutex_exit(&fil_system->mutex);
}
+#endif /* !UNIV_HOTBACKUP */
-/************************************************************
+/********************************************************//**
Creates the database directory for a table if it does not exist yet. */
static
void
fil_create_directory_for_tablename(
/*===============================*/
- const char* name) /* in: name in the standard
+ const char* name) /*!< in: name in the standard
'databasename/tablename' format */
{
const char* namend;
@@ -1730,29 +1861,35 @@ fil_create_directory_for_tablename(
}
#ifndef UNIV_HOTBACKUP
-/************************************************************
+/********************************************************//**
Writes a log record about an .ibd file create/rename/delete. */
static
void
fil_op_write_log(
/*=============*/
- ulint type, /* in: MLOG_FILE_CREATE,
+ ulint type, /*!< in: MLOG_FILE_CREATE,
+ MLOG_FILE_CREATE2,
MLOG_FILE_DELETE, or
MLOG_FILE_RENAME */
- ulint space_id, /* in: space id */
- const char* name, /* in: table name in the familiar
+ ulint space_id, /*!< in: space id */
+ ulint log_flags, /*!< in: redo log flags (stored
+ in the page number field) */
+ ulint flags, /*!< in: compressed page size
+ and file format
+ if type==MLOG_FILE_CREATE2, or 0 */
+ const char* name, /*!< in: table name in the familiar
'databasename/tablename' format, or
the file path in the case of
MLOG_FILE_DELETE */
- const char* new_name, /* in: if type is MLOG_FILE_RENAME,
+ const char* new_name, /*!< in: if type is MLOG_FILE_RENAME,
the new table name in the
'databasename/tablename' format */
- mtr_t* mtr) /* in: mini-transaction handle */
+ mtr_t* mtr) /*!< in: mini-transaction handle */
{
byte* log_ptr;
ulint len;
- log_ptr = mlog_open(mtr, 11 + 2);
+ log_ptr = mlog_open(mtr, 11 + 2 + 1);
if (!log_ptr) {
/* Logging in mtr is switched off during crash recovery:
@@ -1760,8 +1897,12 @@ fil_op_write_log(
return;
}
- log_ptr = mlog_write_initial_log_record_for_file_op(type, space_id, 0,
- log_ptr, mtr);
+ log_ptr = mlog_write_initial_log_record_for_file_op(
+ type, space_id, log_flags, log_ptr, mtr);
+ if (type == MLOG_FILE_CREATE2) {
+ mach_write_to_4(log_ptr, flags);
+ log_ptr += 4;
+ }
/* Let us store the strings as null-terminated for easier readability
and handling */
@@ -1774,7 +1915,7 @@ fil_op_write_log(
mlog_catenate_string(mtr, (byte*) name, len);
if (type == MLOG_FILE_RENAME) {
- ulint len = strlen(new_name) + 1;
+ len = strlen(new_name) + 1;
log_ptr = mlog_open(mtr, 2 + len);
ut_a(log_ptr);
mach_write_to_2(log_ptr, len);
@@ -1786,7 +1927,7 @@ fil_op_write_log(
}
#endif
-/***********************************************************************
+/*******************************************************************//**
Parses the body of a log record written about an .ibd file operation. That is,
the log record part after the standard (type, space id, page no) header of the
log record.
@@ -1797,29 +1938,39 @@ at that path does not exist yet. If the database directory for the file to be
created does not exist, then we create the directory, too.
Note that ibbackup --apply-log sets fil_path_to_mysql_datadir to point to the
-datadir that we should use in replaying the file operations. */
-
+datadir that we should use in replaying the file operations.
+@return end of log record, or NULL if the record was not completely
+contained between ptr and end_ptr */
+UNIV_INTERN
byte*
fil_op_log_parse_or_replay(
/*=======================*/
- /* out: end of log record, or NULL if the
- record was not completely contained between
- ptr and end_ptr */
- byte* ptr, /* in: buffer containing the log record body,
+ byte* ptr, /*!< in: buffer containing the log record body,
or an initial segment of it, if the record does
not fir completely between ptr and end_ptr */
- byte* end_ptr, /* in: buffer end */
- ulint type, /* in: the type of this log record */
- ibool do_replay, /* in: TRUE if we want to replay the
- operation, and not just parse the log record */
- ulint space_id) /* in: if do_replay is TRUE, the space id of
- the tablespace in question; otherwise
- ignored */
+ byte* end_ptr, /*!< in: buffer end */
+ ulint type, /*!< in: the type of this log record */
+ ulint space_id, /*!< in: the space id of the tablespace in
+ question, or 0 if the log record should
+ only be parsed but not replayed */
+ ulint log_flags) /*!< in: redo log flags
+ (stored in the page number parameter) */
{
ulint name_len;
ulint new_name_len;
const char* name;
const char* new_name = NULL;
+ ulint flags = 0;
+
+ if (type == MLOG_FILE_CREATE2) {
+ if (end_ptr < ptr + 4) {
+
+ return(NULL);
+ }
+
+ flags = mach_read_from_4(ptr);
+ ptr += 4;
+ }
if (end_ptr < ptr + 2) {
@@ -1868,7 +2019,7 @@ fil_op_log_parse_or_replay(
printf("new name %s\n", new_name);
}
*/
- if (do_replay == FALSE) {
+ if (!space_id) {
return(ptr);
}
@@ -1881,11 +2032,15 @@ fil_op_log_parse_or_replay(
were renames of tables during the backup. See ibbackup code for more
on the problem. */
- if (type == MLOG_FILE_DELETE) {
+ switch (type) {
+ case MLOG_FILE_DELETE:
if (fil_tablespace_exists_in_mem(space_id)) {
ut_a(fil_delete_tablespace(space_id));
}
- } else if (type == MLOG_FILE_RENAME) {
+
+ break;
+
+ case MLOG_FILE_RENAME:
/* We do the rename based on space id, not old file name;
this should guarantee that after the log replay each .ibd file
has the correct name for the latest log sequence number; the
@@ -1909,43 +2064,49 @@ fil_op_log_parse_or_replay(
}
}
}
- } else {
- ut_a(type == MLOG_FILE_CREATE);
+ break;
+
+ case MLOG_FILE_CREATE:
+ case MLOG_FILE_CREATE2:
if (fil_tablespace_exists_in_mem(space_id)) {
/* Do nothing */
} else if (fil_get_space_id_for_table(name)
!= ULINT_UNDEFINED) {
/* Do nothing */
+ } else if (log_flags & MLOG_FILE_FLAG_TEMP) {
+ /* Temporary table, do nothing */
} else {
/* Create the database directory for name, if it does
not exist yet */
fil_create_directory_for_tablename(name);
- ut_a(space_id != 0);
-
if (fil_create_new_single_table_tablespace(
- &space_id, name, FALSE,
+ &space_id, name, FALSE, flags,
FIL_IBD_FILE_INITIAL_SIZE) != DB_SUCCESS) {
ut_error;
}
}
+
+ break;
+
+ default:
+ ut_error;
}
return(ptr);
}
-/***********************************************************************
+/*******************************************************************//**
Deletes a single-table tablespace. The tablespace must be cached in the
-memory cache. */
-
+memory cache.
+@return TRUE if success */
+UNIV_INTERN
ibool
fil_delete_tablespace(
/*==================*/
- /* out: TRUE if success */
- ulint id) /* in: space id */
+ ulint id) /*!< in: space id */
{
- fil_system_t* system = fil_system;
ibool success;
fil_space_t* space;
fil_node_t* node;
@@ -1954,15 +2115,15 @@ fil_delete_tablespace(
ut_a(id != 0);
stop_ibuf_merges:
- mutex_enter(&(system->mutex));
+ mutex_enter(&fil_system->mutex);
- HASH_SEARCH(hash, system->spaces, id, space, space->id == id);
+ space = fil_space_get_by_id(id);
if (space != NULL) {
space->stop_ibuf_merges = TRUE;
if (space->n_pending_ibuf_merges == 0) {
- mutex_exit(&(system->mutex));
+ mutex_exit(&fil_system->mutex);
count = 0;
@@ -1981,7 +2142,7 @@ stop_ibuf_merges:
(ulong) count);
}
- mutex_exit(&(system->mutex));
+ mutex_exit(&fil_system->mutex);
os_thread_sleep(20000);
count++;
@@ -1990,13 +2151,13 @@ stop_ibuf_merges:
}
}
- mutex_exit(&(system->mutex));
+ mutex_exit(&fil_system->mutex);
count = 0;
try_again:
- mutex_enter(&(system->mutex));
+ mutex_enter(&fil_system->mutex);
- HASH_SEARCH(hash, system->spaces, id, space, space->id == id);
+ space = fil_space_get_by_id(id);
if (space == NULL) {
ut_print_timestamp(stderr);
@@ -2006,7 +2167,7 @@ try_again:
" tablespace memory cache.\n",
(ulong) id);
- mutex_exit(&(system->mutex));
+ mutex_exit(&fil_system->mutex);
return(FALSE);
}
@@ -2033,7 +2194,7 @@ try_again:
(ulong) node->n_pending,
(ulong) count);
}
- mutex_exit(&(system->mutex));
+ mutex_exit(&fil_system->mutex);
os_thread_sleep(20000);
count++;
@@ -2043,7 +2204,7 @@ try_again:
path = mem_strdup(space->name);
- mutex_exit(&(system->mutex));
+ mutex_exit(&fil_system->mutex);
#ifndef UNIV_HOTBACKUP
/* Invalidate in the buffer pool all pages belonging to the
tablespace. Since we have set space->is_being_deleted = TRUE, readahead
@@ -2078,7 +2239,7 @@ try_again:
to write any log record */
mtr_start(&mtr);
- fil_op_write_log(MLOG_FILE_DELETE, id, path, NULL, &mtr);
+ fil_op_write_log(MLOG_FILE_DELETE, id, 0, 0, path, NULL, &mtr);
mtr_commit(&mtr);
#endif
mem_free(path);
@@ -2091,20 +2252,21 @@ try_again:
return(FALSE);
}
-/***********************************************************************
+#ifndef UNIV_HOTBACKUP
+/*******************************************************************//**
Discards a single-table tablespace. The tablespace must be cached in the
memory cache. Discarding is like deleting a tablespace, but
1) we do not drop the table from the data dictionary;
2) we remove all insert buffer entries for the tablespace immediately; in DROP
TABLE they are only removed gradually in the background;
3) when the user does IMPORT TABLESPACE, the tablespace will have the same id
-as it originally had. */
-
+as it originally had.
+@return TRUE if success */
+UNIV_INTERN
ibool
fil_discard_tablespace(
/*===================*/
- /* out: TRUE if success */
- ulint id) /* in: space id */
+ ulint id) /*!< in: space id */
{
ibool success;
@@ -2123,26 +2285,27 @@ fil_discard_tablespace(
ibuf_delete_for_discarded_space(id);
- return(TRUE);
+ return(success);
}
+#endif /* !UNIV_HOTBACKUP */
-/***********************************************************************
-Renames the memory cache structures of a single-table tablespace. */
+/*******************************************************************//**
+Renames the memory cache structures of a single-table tablespace.
+@return TRUE if success */
static
ibool
fil_rename_tablespace_in_mem(
/*=========================*/
- /* out: TRUE if success */
- fil_space_t* space, /* in: tablespace memory object */
- fil_node_t* node, /* in: file node of that tablespace */
- const char* path) /* in: new name */
+ fil_space_t* space, /*!< in: tablespace memory object */
+ fil_node_t* node, /*!< in: file node of that tablespace */
+ const char* path) /*!< in: new name */
{
- fil_system_t* system = fil_system;
fil_space_t* space2;
const char* old_name = space->name;
- HASH_SEARCH(name_hash, system->name_hash, ut_fold_string(old_name),
- space2, 0 == strcmp(old_name, space2->name));
+ ut_ad(mutex_own(&fil_system->mutex));
+
+ space2 = fil_space_get_by_name(old_name);
if (space != space2) {
fputs("InnoDB: Error: cannot find ", stderr);
ut_print_filename(stderr, old_name);
@@ -2151,8 +2314,7 @@ fil_rename_tablespace_in_mem(
return(FALSE);
}
- HASH_SEARCH(name_hash, system->name_hash, ut_fold_string(path),
- space2, 0 == strcmp(path, space2->name));
+ space2 = fil_space_get_by_name(path);
if (space2 != NULL) {
fputs("InnoDB: Error: ", stderr);
ut_print_filename(stderr, path);
@@ -2161,7 +2323,7 @@ fil_rename_tablespace_in_mem(
return(FALSE);
}
- HASH_DELETE(fil_space_t, name_hash, system->name_hash,
+ HASH_DELETE(fil_space_t, name_hash, fil_system->name_hash,
ut_fold_string(space->name), space);
mem_free(space->name);
mem_free(node->name);
@@ -2169,22 +2331,22 @@ fil_rename_tablespace_in_mem(
space->name = mem_strdup(path);
node->name = mem_strdup(path);
- HASH_INSERT(fil_space_t, name_hash, system->name_hash,
+ HASH_INSERT(fil_space_t, name_hash, fil_system->name_hash,
ut_fold_string(path), space);
return(TRUE);
}
-/***********************************************************************
+/*******************************************************************//**
Allocates a file name for a single-table tablespace. The string must be freed
-by caller with mem_free(). */
+by caller with mem_free().
+@return own: file name */
static
char*
fil_make_ibd_name(
/*==============*/
- /* out, own: file name */
- const char* name, /* in: table name or a dir path of a
+ const char* name, /*!< in: table name or a dir path of a
TEMPORARY table */
- ibool is_temp) /* in: TRUE if it is a dir path */
+ ibool is_temp) /*!< in: TRUE if it is a dir path */
{
ulint namelen = strlen(name);
ulint dirlen = strlen(fil_path_to_mysql_datadir);
@@ -2206,24 +2368,23 @@ fil_make_ibd_name(
return(filename);
}
-/***********************************************************************
+/*******************************************************************//**
Renames a single-table tablespace. The tablespace must be cached in the
-tablespace memory cache. */
-
+tablespace memory cache.
+@return TRUE if success */
+UNIV_INTERN
ibool
fil_rename_tablespace(
/*==================*/
- /* out: TRUE if success */
- const char* old_name, /* in: old table name in the standard
+ const char* old_name, /*!< in: old table name in the standard
databasename/tablename format of
InnoDB, or NULL if we do the rename
based on the space id only */
- ulint id, /* in: space id */
- const char* new_name) /* in: new table name in the standard
+ ulint id, /*!< in: space id */
+ const char* new_name) /*!< in: new table name in the standard
databasename/tablename format
of InnoDB */
{
- fil_system_t* system = fil_system;
ibool success;
fil_space_t* space;
fil_node_t* node;
@@ -2250,9 +2411,9 @@ retry:
fprintf(stderr, ", %lu iterations\n", (ulong) count);
}
- mutex_enter(&(system->mutex));
+ mutex_enter(&fil_system->mutex);
- HASH_SEARCH(hash, system->spaces, id, space, space->id == id);
+ space = fil_space_get_by_id(id);
if (space == NULL) {
fprintf(stderr,
@@ -2261,14 +2422,14 @@ retry:
"InnoDB: though the table ", (ulong) id);
ut_print_filename(stderr, old_name);
fputs(" in a rename operation should have that id\n", stderr);
- mutex_exit(&(system->mutex));
+ mutex_exit(&fil_system->mutex);
return(FALSE);
}
if (count > 25000) {
space->stop_ios = FALSE;
- mutex_exit(&(system->mutex));
+ mutex_exit(&fil_system->mutex);
return(FALSE);
}
@@ -2286,7 +2447,7 @@ retry:
/* There are pending i/o's or flushes, sleep for a while and
retry */
- mutex_exit(&(system->mutex));
+ mutex_exit(&fil_system->mutex);
os_thread_sleep(20000);
@@ -2295,7 +2456,7 @@ retry:
} else if (node->modification_counter > node->flush_counter) {
/* Flush the space */
- mutex_exit(&(system->mutex));
+ mutex_exit(&fil_system->mutex);
os_thread_sleep(20000);
@@ -2306,7 +2467,7 @@ retry:
} else if (node->open) {
/* Close the file */
- fil_node_close_file(node, system);
+ fil_node_close_file(node, fil_system);
}
/* Check that the old name in the space is right */
@@ -2341,7 +2502,7 @@ retry:
space->stop_ios = FALSE;
- mutex_exit(&(system->mutex));
+ mutex_exit(&fil_system->mutex);
#ifndef UNIV_HOTBACKUP
if (success) {
@@ -2349,7 +2510,7 @@ retry:
mtr_start(&mtr);
- fil_op_write_log(MLOG_FILE_RENAME, id, old_name, new_name,
+ fil_op_write_log(MLOG_FILE_RENAME, id, 0, 0, old_name, new_name,
&mtr);
mtr_commit(&mtr);
}
@@ -2357,27 +2518,28 @@ retry:
return(success);
}
-/***********************************************************************
+/*******************************************************************//**
Creates a new single-table tablespace to a database directory of MySQL.
Database directories are under the 'datadir' of MySQL. The datadir is the
directory of a running mysqld program. We can refer to it by simply the
path '.'. Tables created with CREATE TEMPORARY TABLE we place in the temp
-dir of the mysqld server. */
-
+dir of the mysqld server.
+@return DB_SUCCESS or error code */
+UNIV_INTERN
ulint
fil_create_new_single_table_tablespace(
/*===================================*/
- /* out: DB_SUCCESS or error code */
- ulint* space_id, /* in/out: space id; if this is != 0,
+ ulint* space_id, /*!< in/out: space id; if this is != 0,
then this is an input parameter,
otherwise output */
- const char* tablename, /* in: the table name in the usual
+ const char* tablename, /*!< in: the table name in the usual
databasename/tablename format
of InnoDB, or a dir path to a temp
table */
- ibool is_temp, /* in: TRUE if a table created with
+ ibool is_temp, /*!< in: TRUE if a table created with
CREATE TEMPORARY TABLE */
- ulint size) /* in: the initial size of the
+ ulint flags, /*!< in: tablespace flags */
+ ulint size) /*!< in: the initial size of the
tablespace file in pages,
must be >= FIL_IBD_FILE_INITIAL_SIZE */
{
@@ -2390,6 +2552,11 @@ fil_create_new_single_table_tablespace(
char* path;
ut_a(size >= FIL_IBD_FILE_INITIAL_SIZE);
+ /* The tablespace flags (FSP_SPACE_FLAGS) should be 0 for
+ ROW_FORMAT=COMPACT (table->flags == DICT_TF_COMPACT) and
+ ROW_FORMAT=REDUNDANT (table->flags == 0). For any other
+ format, the tablespace flags should equal table->flags. */
+ ut_a(flags != DICT_TF_COMPACT);
path = fil_make_ibd_name(tablename, is_temp);
@@ -2437,7 +2604,7 @@ fil_create_new_single_table_tablespace(
return(DB_ERROR);
}
- buf2 = ut_malloc(2 * UNIV_PAGE_SIZE);
+ buf2 = ut_malloc(3 * UNIV_PAGE_SIZE);
/* Align the memory for file i/o if we might have O_DIRECT set */
page = ut_align(buf2, UNIV_PAGE_SIZE);
@@ -2480,11 +2647,30 @@ error_exit2:
memset(page, '\0', UNIV_PAGE_SIZE);
- fsp_header_write_space_id(page, *space_id);
+ fsp_header_init_fields(page, *space_id, flags);
+ mach_write_to_4(page + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID, *space_id);
- buf_flush_init_for_writing(page, ut_dulint_zero, *space_id, 0);
+ if (!(flags & DICT_TF_ZSSIZE_MASK)) {
+ buf_flush_init_for_writing(page, NULL, 0);
+ ret = os_file_write(path, file, page, 0, 0, UNIV_PAGE_SIZE);
+ } else {
+ page_zip_des_t page_zip;
+ ulint zip_size;
- ret = os_file_write(path, file, page, 0, 0, UNIV_PAGE_SIZE);
+ zip_size = ((PAGE_ZIP_MIN_SIZE >> 1)
+ << ((flags & DICT_TF_ZSSIZE_MASK)
+ >> DICT_TF_ZSSIZE_SHIFT));
+
+ page_zip_set_size(&page_zip, zip_size);
+ page_zip.data = page + UNIV_PAGE_SIZE;
+#ifdef UNIV_DEBUG
+ page_zip.m_start =
+#endif /* UNIV_DEBUG */
+ page_zip.m_end = page_zip.m_nonempty =
+ page_zip.n_blobs = 0;
+ buf_flush_init_for_writing(page, &page_zip, 0);
+ ret = os_file_write(path, file, page_zip.data, 0, 0, zip_size);
+ }
ut_free(buf2);
@@ -2511,7 +2697,7 @@ error_exit2:
goto error_exit2;
}
- success = fil_space_create(path, *space_id, FIL_TABLESPACE);
+ success = fil_space_create(path, *space_id, flags, FIL_TABLESPACE);
if (!success) {
goto error_exit2;
@@ -2525,8 +2711,13 @@ error_exit2:
mtr_start(&mtr);
- fil_op_write_log(MLOG_FILE_CREATE, *space_id, tablename,
- NULL, &mtr);
+ fil_op_write_log(flags
+ ? MLOG_FILE_CREATE2
+ : MLOG_FILE_CREATE,
+ *space_id,
+ is_temp ? MLOG_FILE_FLAG_TEMP : 0,
+ flags,
+ tablename, NULL, &mtr);
mtr_commit(&mtr);
}
@@ -2535,7 +2726,8 @@ error_exit2:
return(DB_SUCCESS);
}
-/************************************************************************
+#ifndef UNIV_HOTBACKUP
+/********************************************************************//**
It is possible, though very improbable, that the lsn's in the tablespace to be
imported have risen above the current system lsn, if a lengthy purge, ibuf
merge, or rollback was performed on a backup taken with ibbackup. If that is
@@ -2543,15 +2735,15 @@ the case, reset page lsn's in the file. We assume that mysqld was shut down
after it performed these cleanup operations on the .ibd file, so that it at
the shutdown stamped the latest lsn to the FIL_PAGE_FILE_FLUSH_LSN in the
first page of the .ibd file, and we can determine whether we need to reset the
-lsn's just by looking at that flush lsn. */
-
+lsn's just by looking at that flush lsn.
+@return TRUE if success */
+UNIV_INTERN
ibool
fil_reset_too_high_lsns(
/*====================*/
- /* out: TRUE if success */
- const char* name, /* in: table name in the
+ const char* name, /*!< in: table name in the
databasename/tablename format */
- dulint current_lsn) /* in: reset lsn's if the lsn stamped
+ ib_uint64_t current_lsn) /*!< in: reset lsn's if the lsn stamped
to FIL_PAGE_FILE_FLUSH_LSN in the
first page is too high */
{
@@ -2559,11 +2751,11 @@ fil_reset_too_high_lsns(
char* filepath;
byte* page;
byte* buf2;
- dulint flush_lsn;
+ ib_uint64_t flush_lsn;
ulint space_id;
- ib_longlong file_size;
- ib_longlong offset;
- ulint page_no;
+ ib_int64_t file_size;
+ ib_int64_t offset;
+ ulint zip_size;
ibool success;
filepath = fil_make_ibd_name(name, FALSE);
@@ -2588,7 +2780,7 @@ fil_reset_too_high_lsns(
/* Read the first page of the tablespace */
- buf2 = ut_malloc(2 * UNIV_PAGE_SIZE);
+ buf2 = ut_malloc(3 * UNIV_PAGE_SIZE);
/* Align the memory for file i/o if we might have O_DIRECT set */
page = ut_align(buf2, UNIV_PAGE_SIZE);
@@ -2600,9 +2792,9 @@ fil_reset_too_high_lsns(
/* We have to read the file flush lsn from the header of the file */
- flush_lsn = mach_read_from_8(page + FIL_PAGE_FILE_FLUSH_LSN);
+ flush_lsn = mach_read_ull(page + FIL_PAGE_FILE_FLUSH_LSN);
- if (ut_dulint_cmp(current_lsn, flush_lsn) >= 0) {
+ if (current_lsn >= flush_lsn) {
/* Ok */
success = TRUE;
@@ -2610,48 +2802,56 @@ fil_reset_too_high_lsns(
}
space_id = fsp_header_get_space_id(page);
+ zip_size = fsp_header_get_zip_size(page);
ut_print_timestamp(stderr);
fprintf(stderr,
" InnoDB: Flush lsn in the tablespace file %lu"
" to be imported\n"
- "InnoDB: is %lu %lu, which exceeds current"
- " system lsn %lu %lu.\n"
+ "InnoDB: is %llu, which exceeds current"
+ " system lsn %llu.\n"
"InnoDB: We reset the lsn's in the file ",
(ulong) space_id,
- (ulong) ut_dulint_get_high(flush_lsn),
- (ulong) ut_dulint_get_low(flush_lsn),
- (ulong) ut_dulint_get_high(current_lsn),
- (ulong) ut_dulint_get_low(current_lsn));
+ flush_lsn, current_lsn);
ut_print_filename(stderr, filepath);
fputs(".\n", stderr);
+ ut_a(ut_is_2pow(zip_size));
+ ut_a(zip_size <= UNIV_PAGE_SIZE);
+
/* Loop through all the pages in the tablespace and reset the lsn and
the page checksum if necessary */
file_size = os_file_get_size_as_iblonglong(file);
- for (offset = 0; offset < file_size; offset += UNIV_PAGE_SIZE) {
+ for (offset = 0; offset < file_size;
+ offset += zip_size ? zip_size : UNIV_PAGE_SIZE) {
success = os_file_read(file, page,
(ulint)(offset & 0xFFFFFFFFUL),
- (ulint)(offset >> 32), UNIV_PAGE_SIZE);
+ (ulint)(offset >> 32),
+ zip_size ? zip_size : UNIV_PAGE_SIZE);
if (!success) {
goto func_exit;
}
- if (ut_dulint_cmp(mach_read_from_8(page + FIL_PAGE_LSN),
- current_lsn) > 0) {
+ if (mach_read_ull(page + FIL_PAGE_LSN) > current_lsn) {
/* We have to reset the lsn */
- space_id = mach_read_from_4(
- page + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID);
- page_no = mach_read_from_4(page + FIL_PAGE_OFFSET);
- buf_flush_init_for_writing(page, current_lsn, space_id,
- page_no);
+ if (zip_size) {
+ memcpy(page + UNIV_PAGE_SIZE, page, zip_size);
+ buf_flush_init_for_writing(
+ page, page + UNIV_PAGE_SIZE,
+ current_lsn);
+ } else {
+ buf_flush_init_for_writing(
+ page, NULL, current_lsn);
+ }
success = os_file_write(filepath, file, page,
(ulint)(offset & 0xFFFFFFFFUL),
(ulint)(offset >> 32),
- UNIV_PAGE_SIZE);
+ zip_size
+ ? zip_size
+ : UNIV_PAGE_SIZE);
if (!success) {
goto func_exit;
@@ -2666,15 +2866,17 @@ fil_reset_too_high_lsns(
}
/* We now update the flush_lsn stamp at the start of the file */
- success = os_file_read(file, page, 0, 0, UNIV_PAGE_SIZE);
+ success = os_file_read(file, page, 0, 0,
+ zip_size ? zip_size : UNIV_PAGE_SIZE);
if (!success) {
goto func_exit;
}
- mach_write_to_8(page + FIL_PAGE_FILE_FLUSH_LSN, current_lsn);
+ mach_write_ull(page + FIL_PAGE_FILE_FLUSH_LSN, current_lsn);
- success = os_file_write(filepath, file, page, 0, 0, UNIV_PAGE_SIZE);
+ success = os_file_write(filepath, file, page, 0, 0,
+ zip_size ? zip_size : UNIV_PAGE_SIZE);
if (!success) {
goto func_exit;
@@ -2688,7 +2890,7 @@ func_exit:
return(success);
}
-/************************************************************************
+/********************************************************************//**
Tries to open a single-table tablespace and optionally checks the space id is
right in it. If does not succeed, prints an error message to the .err log. This
function is used to open a tablespace when we start up mysqld, and also in
@@ -2696,21 +2898,22 @@ IMPORT TABLESPACE.
NOTE that we assume this operation is used either at the database startup
or under the protection of the dictionary mutex, so that two users cannot
race here. This operation does not leave the file associated with the
-tablespace open, but closes it after we have looked at the space id in it. */
-
+tablespace open, but closes it after we have looked at the space id in it.
+@return TRUE if success */
+UNIV_INTERN
ibool
fil_open_single_table_tablespace(
/*=============================*/
- /* out: TRUE if success */
- ibool check_space_id, /* in: should we check that the space
+ ibool check_space_id, /*!< in: should we check that the space
id in the file is right; we assume
that this function runs much faster
if no check is made, since accessing
the file inode probably is much
faster (the OS caches them) than
accessing the first page of the file */
- ulint id, /* in: space id */
- const char* name) /* in: table name in the
+ ulint id, /*!< in: space id */
+ ulint flags, /*!< in: tablespace flags */
+ const char* name) /*!< in: table name in the
databasename/tablename format */
{
os_file_t file;
@@ -2719,10 +2922,17 @@ fil_open_single_table_tablespace(
byte* buf2;
byte* page;
ulint space_id;
+ ulint space_flags;
ibool ret = TRUE;
filepath = fil_make_ibd_name(name, FALSE);
+ /* The tablespace flags (FSP_SPACE_FLAGS) should be 0 for
+ ROW_FORMAT=COMPACT (table->flags == DICT_TF_COMPACT) and
+ ROW_FORMAT=REDUNDANT (table->flags == 0). For any other
+ format, the tablespace flags should equal table->flags. */
+ ut_a(flags != DICT_TF_COMPACT);
+
file = os_file_create_simple_no_error_handling(
filepath, OS_FILE_OPEN, OS_FILE_READ_ONLY, &success);
if (!success) {
@@ -2744,8 +2954,7 @@ fil_open_single_table_tablespace(
" a temporary table #sql...,\n"
"InnoDB: and MySQL removed the .ibd file for this.\n"
"InnoDB: Please refer to\n"
- "InnoDB: http://dev.mysql.com/doc/refman/5.1/en/"
- "innodb-troubleshooting.html\n"
+ "InnoDB: " REFMAN "innodb-troubleshooting-datadict.html\n"
"InnoDB: for how to resolve the issue.\n", stderr);
mem_free(filepath);
@@ -2767,28 +2976,30 @@ fil_open_single_table_tablespace(
success = os_file_read(file, page, 0, 0, UNIV_PAGE_SIZE);
- /* We have to read the tablespace id from the file */
+ /* We have to read the tablespace id and flags from the file. */
space_id = fsp_header_get_space_id(page);
+ space_flags = fsp_header_get_flags(page);
ut_free(buf2);
- if (space_id != id) {
+ if (UNIV_UNLIKELY(space_id != id || space_flags != flags)) {
ut_print_timestamp(stderr);
- fputs(" InnoDB: Error: tablespace id in file ", stderr);
+ fputs(" InnoDB: Error: tablespace id and flags in file ",
+ stderr);
ut_print_filename(stderr, filepath);
- fprintf(stderr, " is %lu, but in the InnoDB\n"
- "InnoDB: data dictionary it is %lu.\n"
+ fprintf(stderr, " are %lu and %lu, but in the InnoDB\n"
+ "InnoDB: data dictionary they are %lu and %lu.\n"
"InnoDB: Have you moved InnoDB .ibd files"
" around without using the\n"
"InnoDB: commands DISCARD TABLESPACE and"
" IMPORT TABLESPACE?\n"
"InnoDB: Please refer to\n"
- "InnoDB: http://dev.mysql.com/doc/refman/5.1/en/"
- "innodb-troubleshooting.html\n"
+ "InnoDB: " REFMAN "innodb-troubleshooting-datadict.html\n"
"InnoDB: for how to resolve the issue.\n",
- (ulong) space_id, (ulong) id);
+ (ulong) space_id, (ulong) space_flags,
+ (ulong) id, (ulong) flags);
ret = FALSE;
@@ -2796,7 +3007,7 @@ fil_open_single_table_tablespace(
}
skip_check:
- success = fil_space_create(filepath, space_id, FIL_TABLESPACE);
+ success = fil_space_create(filepath, space_id, flags, FIL_TABLESPACE);
if (!success) {
goto func_exit;
@@ -2812,17 +3023,18 @@ func_exit:
return(ret);
}
+#endif /* !UNIV_HOTBACKUP */
#ifdef UNIV_HOTBACKUP
-/***********************************************************************
+/*******************************************************************//**
Allocates a file name for an old version of a single-table tablespace.
-The string must be freed by caller with mem_free()! */
+The string must be freed by caller with mem_free()!
+@return own: file name */
static
char*
fil_make_ibbackup_old_name(
/*=======================*/
- /* out, own: file name */
- const char* name) /* in: original file name */
+ const char* name) /*!< in: original file name */
{
static const char suffix[] = "_ibbackup_old_vers_";
ulint len = strlen(name);
@@ -2835,15 +3047,15 @@ fil_make_ibbackup_old_name(
}
#endif /* UNIV_HOTBACKUP */
-/************************************************************************
+/********************************************************************//**
Opens an .ibd file and adds the associated single-table tablespace to the
InnoDB fil0fil.c data structures. */
static
void
fil_load_single_table_tablespace(
/*=============================*/
- const char* dbname, /* in: database name */
- const char* filename) /* in: file name (not a path),
+ const char* dbname, /*!< in: database name */
+ const char* filename) /*!< in: file name (not a path),
including the .ibd extension */
{
os_file_t file;
@@ -2852,9 +3064,10 @@ fil_load_single_table_tablespace(
byte* buf2;
byte* page;
ulint space_id;
+ ulint flags;
ulint size_low;
ulint size_high;
- ib_longlong size;
+ ib_int64_t size;
#ifdef UNIV_HOTBACKUP
fil_space_t* space;
#endif
@@ -2974,7 +3187,7 @@ fil_load_single_table_tablespace(
/* Every .ibd file is created >= 4 pages in size. Smaller files
cannot be ok. */
- size = (((ib_longlong)size_high) << 32) + (ib_longlong)size_low;
+ size = (((ib_int64_t)size_high) << 32) + (ib_int64_t)size_low;
#ifndef UNIV_HOTBACKUP
if (size < FIL_IBD_FILE_INITIAL_SIZE * UNIV_PAGE_SIZE) {
fprintf(stderr,
@@ -3002,8 +3215,10 @@ fil_load_single_table_tablespace(
/* We have to read the tablespace id from the file */
space_id = fsp_header_get_space_id(page);
+ flags = fsp_header_get_flags(page);
} else {
space_id = ULINT_UNDEFINED;
+ flags = 0;
}
#ifndef UNIV_HOTBACKUP
@@ -3048,9 +3263,9 @@ fil_load_single_table_tablespace(
file than delete it, because if there is a bug, we do not want to
destroy valuable data. */
- mutex_enter(&(fil_system->mutex));
+ mutex_enter(&fil_system->mutex);
- space = fil_get_space_for_id_low(space_id);
+ space = fil_space_get_by_id(space_id);
if (space) {
char* new_path;
@@ -3068,7 +3283,7 @@ fil_load_single_table_tablespace(
new_path = fil_make_ibbackup_old_name(filepath);
- mutex_exit(&(fil_system->mutex));
+ mutex_exit(&fil_system->mutex);
ut_a(os_file_rename(filepath, new_path));
@@ -3078,9 +3293,9 @@ fil_load_single_table_tablespace(
return;
}
- mutex_exit(&(fil_system->mutex));
+ mutex_exit(&fil_system->mutex);
#endif
- success = fil_space_create(filepath, space_id, FIL_TABLESPACE);
+ success = fil_space_create(filepath, space_id, flags, FIL_TABLESPACE);
if (!success) {
@@ -3098,21 +3313,21 @@ func_exit:
mem_free(filepath);
}
-/***************************************************************************
+/***********************************************************************//**
A fault-tolerant function that tries to read the next file name in the
directory. We retry 100 times if os_file_readdir_next_file() returns -1. The
-idea is to read as much good data as we can and jump over bad data. */
+idea is to read as much good data as we can and jump over bad data.
+@return 0 if ok, -1 if error even after the retries, 1 if at the end
+of the directory */
static
int
fil_file_readdir_next_file(
/*=======================*/
- /* out: 0 if ok, -1 if error even after the
- retries, 1 if at the end of the directory */
- ulint* err, /* out: this is set to DB_ERROR if an error
+ ulint* err, /*!< out: this is set to DB_ERROR if an error
was encountered, otherwise not changed */
- const char* dirname,/* in: directory name or path */
- os_file_dir_t dir, /* in: directory stream */
- os_file_stat_t* info) /* in/out: buffer where the info is returned */
+ const char* dirname,/*!< in: directory name or path */
+ os_file_dir_t dir, /*!< in: directory stream */
+ os_file_stat_t* info) /*!< in/out: buffer where the info is returned */
{
ulint i;
int ret;
@@ -3138,18 +3353,18 @@ fil_file_readdir_next_file(
return(-1);
}
-/************************************************************************
+/********************************************************************//**
At the server startup, if we need crash recovery, scans the database
directories under the MySQL datadir, looking for .ibd files. Those files are
single-table tablespaces. We need to know the space id in each of them so that
we know into which file we should look to check the contents of a page stored
in the doublewrite buffer, also to know where to apply log records where the
-space id is != 0. */
-
+space id is != 0.
+@return DB_SUCCESS or error number */
+UNIV_INTERN
ulint
fil_load_single_table_tablespaces(void)
/*===================================*/
- /* out: DB_SUCCESS or error number */
{
int ret;
char* dbpath = NULL;
@@ -3267,23 +3482,22 @@ next_datadir_item:
return(err);
}
-/************************************************************************
+/********************************************************************//**
If we need crash recovery, and we have called
fil_load_single_table_tablespaces() and dict_load_single_table_tablespaces(),
we can call this function to print an error message of orphaned .ibd files
for which there is not a data dictionary entry with a matching table name
and space id. */
-
+UNIV_INTERN
void
fil_print_orphaned_tablespaces(void)
/*================================*/
{
- fil_system_t* system = fil_system;
fil_space_t* space;
- mutex_enter(&(system->mutex));
+ mutex_enter(&fil_system->mutex);
- space = UT_LIST_GET_FIRST(system->space_list);
+ space = UT_LIST_GET_FIRST(fil_system->space_list);
while (space) {
if (space->purpose == FIL_TABLESPACE && space->id != 0
@@ -3298,128 +3512,115 @@ fil_print_orphaned_tablespaces(void)
space = UT_LIST_GET_NEXT(space_list, space);
}
- mutex_exit(&(system->mutex));
+ mutex_exit(&fil_system->mutex);
}
-/***********************************************************************
+/*******************************************************************//**
Returns TRUE if a single-table tablespace does not exist in the memory cache,
-or is being deleted there. */
-
+or is being deleted there.
+@return TRUE if does not exist or is being\ deleted */
+UNIV_INTERN
ibool
fil_tablespace_deleted_or_being_deleted_in_mem(
/*===========================================*/
- /* out: TRUE if does not exist or is being\
- deleted */
- ulint id, /* in: space id */
- ib_longlong version)/* in: tablespace_version should be this; if
+ ulint id, /*!< in: space id */
+ ib_int64_t version)/*!< in: tablespace_version should be this; if
you pass -1 as the value of this, then this
parameter is ignored */
{
- fil_system_t* system = fil_system;
fil_space_t* space;
- ut_ad(system);
+ ut_ad(fil_system);
- mutex_enter(&(system->mutex));
+ mutex_enter(&fil_system->mutex);
- HASH_SEARCH(hash, system->spaces, id, space, space->id == id);
+ space = fil_space_get_by_id(id);
if (space == NULL || space->is_being_deleted) {
- mutex_exit(&(system->mutex));
+ mutex_exit(&fil_system->mutex);
return(TRUE);
}
- if (version != ((ib_longlong)-1)
+ if (version != ((ib_int64_t)-1)
&& space->tablespace_version != version) {
- mutex_exit(&(system->mutex));
+ mutex_exit(&fil_system->mutex);
return(TRUE);
}
- mutex_exit(&(system->mutex));
+ mutex_exit(&fil_system->mutex);
return(FALSE);
}
-/***********************************************************************
-Returns TRUE if a single-table tablespace exists in the memory cache. */
-
+/*******************************************************************//**
+Returns TRUE if a single-table tablespace exists in the memory cache.
+@return TRUE if exists */
+UNIV_INTERN
ibool
fil_tablespace_exists_in_mem(
/*=========================*/
- /* out: TRUE if exists */
- ulint id) /* in: space id */
+ ulint id) /*!< in: space id */
{
- fil_system_t* system = fil_system;
fil_space_t* space;
- ut_ad(system);
+ ut_ad(fil_system);
- mutex_enter(&(system->mutex));
+ mutex_enter(&fil_system->mutex);
- HASH_SEARCH(hash, system->spaces, id, space, space->id == id);
+ space = fil_space_get_by_id(id);
- if (space == NULL) {
- mutex_exit(&(system->mutex));
+ mutex_exit(&fil_system->mutex);
- return(FALSE);
- }
-
- mutex_exit(&(system->mutex));
-
- return(TRUE);
+ return(space != NULL);
}
-/***********************************************************************
+/*******************************************************************//**
Returns TRUE if a matching tablespace exists in the InnoDB tablespace memory
cache. Note that if we have not done a crash recovery at the database startup,
-there may be many tablespaces which are not yet in the memory cache. */
-
+there may be many tablespaces which are not yet in the memory cache.
+@return TRUE if a matching tablespace exists in the memory cache */
+UNIV_INTERN
ibool
fil_space_for_table_exists_in_mem(
/*==============================*/
- /* out: TRUE if a matching tablespace
- exists in the memory cache */
- ulint id, /* in: space id */
- const char* name, /* in: table name in the standard
+ ulint id, /*!< in: space id */
+ const char* name, /*!< in: table name in the standard
'databasename/tablename' format or
the dir path to a temp table */
- ibool is_temp, /* in: TRUE if created with CREATE
+ ibool is_temp, /*!< in: TRUE if created with CREATE
TEMPORARY TABLE */
- ibool mark_space, /* in: in crash recovery, at database
+ ibool mark_space, /*!< in: in crash recovery, at database
startup we mark all spaces which have
an associated table in the InnoDB
data dictionary, so that
we can print a warning about orphaned
tablespaces */
ibool print_error_if_does_not_exist)
- /* in: print detailed error
+ /*!< in: print detailed error
information to the .err log if a
matching tablespace is not found from
memory */
{
- fil_system_t* system = fil_system;
fil_space_t* namespace;
fil_space_t* space;
char* path;
- ut_ad(system);
+ ut_ad(fil_system);
- mutex_enter(&(system->mutex));
+ mutex_enter(&fil_system->mutex);
path = fil_make_ibd_name(name, is_temp);
/* Look if there is a space with the same id */
- HASH_SEARCH(hash, system->spaces, id, space, space->id == id);
+ space = fil_space_get_by_id(id);
/* Look if there is a space with the same name; the name is the
directory path from the datadir to the file */
- HASH_SEARCH(name_hash, system->name_hash,
- ut_fold_string(path), namespace,
- 0 == strcmp(namespace->name, path));
+ namespace = fil_space_get_by_name(path);
if (space && space == namespace) {
/* Found */
@@ -3428,7 +3629,7 @@ fil_space_for_table_exists_in_mem(
}
mem_free(path);
- mutex_exit(&(system->mutex));
+ mutex_exit(&fil_system->mutex);
return(TRUE);
}
@@ -3436,7 +3637,7 @@ fil_space_for_table_exists_in_mem(
if (!print_error_if_does_not_exist) {
mem_free(path);
- mutex_exit(&(system->mutex));
+ mutex_exit(&fil_system->mutex);
return(FALSE);
}
@@ -3476,12 +3677,11 @@ fil_space_for_table_exists_in_mem(
}
error_exit:
fputs("InnoDB: Please refer to\n"
- "InnoDB: http://dev.mysql.com/doc/refman/5.1/en/"
- "innodb-troubleshooting.html\n"
+ "InnoDB: " REFMAN "innodb-troubleshooting-datadict.html\n"
"InnoDB: for how to resolve the issue.\n", stderr);
mem_free(path);
- mutex_exit(&(system->mutex));
+ mutex_exit(&fil_system->mutex);
return(FALSE);
}
@@ -3511,69 +3711,65 @@ error_exit:
}
mem_free(path);
- mutex_exit(&(system->mutex));
+ mutex_exit(&fil_system->mutex);
return(FALSE);
}
-/***********************************************************************
+/*******************************************************************//**
Checks if a single-table tablespace for a given table name exists in the
-tablespace memory cache. */
+tablespace memory cache.
+@return space id, ULINT_UNDEFINED if not found */
static
ulint
fil_get_space_id_for_table(
/*=======================*/
- /* out: space id, ULINT_UNDEFINED if not
- found */
- const char* name) /* in: table name in the standard
+ const char* name) /*!< in: table name in the standard
'databasename/tablename' format */
{
- fil_system_t* system = fil_system;
fil_space_t* namespace;
ulint id = ULINT_UNDEFINED;
char* path;
- ut_ad(system);
+ ut_ad(fil_system);
- mutex_enter(&(system->mutex));
+ mutex_enter(&fil_system->mutex);
path = fil_make_ibd_name(name, FALSE);
/* Look if there is a space with the same name; the name is the
directory path to the file */
- HASH_SEARCH(name_hash, system->name_hash,
- ut_fold_string(path), namespace,
- 0 == strcmp(namespace->name, path));
+ namespace = fil_space_get_by_name(path);
+
if (namespace) {
id = namespace->id;
}
mem_free(path);
- mutex_exit(&(system->mutex));
+ mutex_exit(&fil_system->mutex);
return(id);
}
-/**************************************************************************
+/**********************************************************************//**
Tries to extend a data file so that it would accommodate the number of pages
given. The tablespace must be cached in the memory cache. If the space is big
-enough already, does nothing. */
-
+enough already, does nothing.
+@return TRUE if success */
+UNIV_INTERN
ibool
fil_extend_space_to_desired_size(
/*=============================*/
- /* out: TRUE if success */
- ulint* actual_size, /* out: size of the space after extension;
+ ulint* actual_size, /*!< out: size of the space after extension;
if we ran out of disk space this may be lower
than the desired size */
- ulint space_id, /* in: space id */
- ulint size_after_extend)/* in: desired size in pages after the
+ ulint space_id, /*!< in: space id */
+ ulint size_after_extend)/*!< in: desired size in pages after the
extension; if the current space size is bigger
than this already, the function does nothing */
{
- fil_system_t* system = fil_system;
fil_node_t* node;
fil_space_t* space;
byte* buf2;
@@ -3583,12 +3779,12 @@ fil_extend_space_to_desired_size(
ulint file_start_page_no;
ulint offset_high;
ulint offset_low;
+ ulint page_size;
ibool success = TRUE;
fil_mutex_enter_and_prepare_for_io(space_id);
- HASH_SEARCH(hash, system->spaces, space_id, space,
- space->id == space_id);
+ space = fil_space_get_by_id(space_id);
ut_a(space);
if (space->size >= size_after_extend) {
@@ -3596,44 +3792,48 @@ fil_extend_space_to_desired_size(
*actual_size = space->size;
- mutex_exit(&(system->mutex));
+ mutex_exit(&fil_system->mutex);
return(TRUE);
}
+ page_size = dict_table_flags_to_zip_size(space->flags);
+ if (!page_size) {
+ page_size = UNIV_PAGE_SIZE;
+ }
+
node = UT_LIST_GET_LAST(space->chain);
- fil_node_prepare_for_io(node, system, space);
+ fil_node_prepare_for_io(node, fil_system, space);
start_page_no = space->size;
file_start_page_no = space->size - node->size;
/* Extend at most 64 pages at a time */
- buf_size = ut_min(64, size_after_extend - start_page_no)
- * UNIV_PAGE_SIZE;
- buf2 = mem_alloc(buf_size + UNIV_PAGE_SIZE);
- buf = ut_align(buf2, UNIV_PAGE_SIZE);
+ buf_size = ut_min(64, size_after_extend - start_page_no) * page_size;
+ buf2 = mem_alloc(buf_size + page_size);
+ buf = ut_align(buf2, page_size);
memset(buf, 0, buf_size);
while (start_page_no < size_after_extend) {
- ulint n_pages = ut_min(buf_size / UNIV_PAGE_SIZE,
+ ulint n_pages = ut_min(buf_size / page_size,
size_after_extend - start_page_no);
offset_high = (start_page_no - file_start_page_no)
- / (4096 * ((1024 * 1024) / UNIV_PAGE_SIZE));
+ / (4096 * ((1024 * 1024) / page_size));
offset_low = ((start_page_no - file_start_page_no)
- % (4096 * ((1024 * 1024) / UNIV_PAGE_SIZE)))
- * UNIV_PAGE_SIZE;
+ % (4096 * ((1024 * 1024) / page_size)))
+ * page_size;
#ifdef UNIV_HOTBACKUP
success = os_file_write(node->name, node->handle, buf,
offset_low, offset_high,
- UNIV_PAGE_SIZE * n_pages);
+ page_size * n_pages);
#else
success = os_aio(OS_FILE_WRITE, OS_AIO_SYNC,
node->name, node->handle, buf,
offset_low, offset_high,
- UNIV_PAGE_SIZE * n_pages,
+ page_size * n_pages,
NULL, NULL);
#endif
if (success) {
@@ -3646,9 +3846,9 @@ fil_extend_space_to_desired_size(
how much we were able to extend it */
n_pages = ((ulint)
- (os_file_get_size_as_iblonglong
- (node->handle)
- / UNIV_PAGE_SIZE)) - node->size;
+ (os_file_get_size_as_iblonglong(
+ node->handle)
+ / page_size)) - node->size;
node->size += n_pages;
space->size += n_pages;
@@ -3661,13 +3861,13 @@ fil_extend_space_to_desired_size(
mem_free(buf2);
- fil_node_complete_io(node, system, OS_FILE_WRITE);
+ fil_node_complete_io(node, fil_system, OS_FILE_WRITE);
*actual_size = space->size;
#ifndef UNIV_HOTBACKUP
if (space_id == 0) {
- ulint pages_per_mb = (1024 * 1024) / UNIV_PAGE_SIZE;
+ ulint pages_per_mb = (1024 * 1024) / page_size;
/* Keep the last data file size info up to date, rounded to
full megabytes */
@@ -3680,7 +3880,7 @@ fil_extend_space_to_desired_size(
/*
printf("Extended %s to %lu, actual size %lu pages\n", space->name,
size_after_extend, *actual_size); */
- mutex_exit(&(system->mutex));
+ mutex_exit(&fil_system->mutex);
fil_flush(space_id);
@@ -3688,17 +3888,16 @@ fil_extend_space_to_desired_size(
}
#ifdef UNIV_HOTBACKUP
-/************************************************************************
+/********************************************************************//**
Extends all tablespaces to the size stored in the space header. During the
ibbackup --apply-log phase we extended the spaces on-demand so that log records
could be applied, but that may have left spaces still too small compared to
the size stored in the space header. */
-
+UNIV_INTERN
void
fil_extend_tablespaces_to_stored_len(void)
/*======================================*/
{
- fil_system_t* system = fil_system;
fil_space_t* space;
byte* buf;
ulint actual_size;
@@ -3708,18 +3907,19 @@ fil_extend_tablespaces_to_stored_len(void)
buf = mem_alloc(UNIV_PAGE_SIZE);
- mutex_enter(&(system->mutex));
+ mutex_enter(&fil_system->mutex);
- space = UT_LIST_GET_FIRST(system->space_list);
+ space = UT_LIST_GET_FIRST(fil_system->space_list);
while (space) {
ut_a(space->purpose == FIL_TABLESPACE);
- mutex_exit(&(system->mutex)); /* no need to protect with a
+ mutex_exit(&fil_system->mutex); /* no need to protect with a
mutex, because this is a
single-threaded operation */
- error = fil_read(TRUE, space->id, 0, 0, UNIV_PAGE_SIZE, buf,
- NULL);
+ error = fil_read(TRUE, space->id,
+ dict_table_flags_to_zip_size(space->flags),
+ 0, 0, UNIV_PAGE_SIZE, buf, NULL);
ut_a(error == DB_SUCCESS);
size_in_header = fsp_get_size_low(buf);
@@ -3739,12 +3939,12 @@ fil_extend_tablespaces_to_stored_len(void)
exit(1);
}
- mutex_enter(&(system->mutex));
+ mutex_enter(&fil_system->mutex);
space = UT_LIST_GET_NEXT(space_list, space);
}
- mutex_exit(&(system->mutex));
+ mutex_exit(&fil_system->mutex);
mem_free(buf);
}
@@ -3752,26 +3952,25 @@ fil_extend_tablespaces_to_stored_len(void)
/*========== RESERVE FREE EXTENTS (for a B-tree split, for example) ===*/
-/***********************************************************************
-Tries to reserve free extents in a file space. */
-
+/*******************************************************************//**
+Tries to reserve free extents in a file space.
+@return TRUE if succeed */
+UNIV_INTERN
ibool
fil_space_reserve_free_extents(
/*===========================*/
- /* out: TRUE if succeed */
- ulint id, /* in: space id */
- ulint n_free_now, /* in: number of free extents now */
- ulint n_to_reserve) /* in: how many one wants to reserve */
+ ulint id, /*!< in: space id */
+ ulint n_free_now, /*!< in: number of free extents now */
+ ulint n_to_reserve) /*!< in: how many one wants to reserve */
{
- fil_system_t* system = fil_system;
fil_space_t* space;
ibool success;
- ut_ad(system);
+ ut_ad(fil_system);
- mutex_enter(&(system->mutex));
+ mutex_enter(&fil_system->mutex);
- HASH_SEARCH(hash, system->spaces, id, space, space->id == id);
+ space = fil_space_get_by_id(id);
ut_a(space);
@@ -3782,68 +3981,66 @@ fil_space_reserve_free_extents(
success = TRUE;
}
- mutex_exit(&(system->mutex));
+ mutex_exit(&fil_system->mutex);
return(success);
}
-/***********************************************************************
+/*******************************************************************//**
Releases free extents in a file space. */
-
+UNIV_INTERN
void
fil_space_release_free_extents(
/*===========================*/
- ulint id, /* in: space id */
- ulint n_reserved) /* in: how many one reserved */
+ ulint id, /*!< in: space id */
+ ulint n_reserved) /*!< in: how many one reserved */
{
- fil_system_t* system = fil_system;
fil_space_t* space;
- ut_ad(system);
+ ut_ad(fil_system);
- mutex_enter(&(system->mutex));
+ mutex_enter(&fil_system->mutex);
- HASH_SEARCH(hash, system->spaces, id, space, space->id == id);
+ space = fil_space_get_by_id(id);
ut_a(space);
ut_a(space->n_reserved_extents >= n_reserved);
space->n_reserved_extents -= n_reserved;
- mutex_exit(&(system->mutex));
+ mutex_exit(&fil_system->mutex);
}
-/***********************************************************************
+/*******************************************************************//**
Gets the number of reserved extents. If the database is silent, this number
should be zero. */
-
+UNIV_INTERN
ulint
fil_space_get_n_reserved_extents(
/*=============================*/
- ulint id) /* in: space id */
+ ulint id) /*!< in: space id */
{
- fil_system_t* system = fil_system;
fil_space_t* space;
ulint n;
- ut_ad(system);
+ ut_ad(fil_system);
- mutex_enter(&(system->mutex));
+ mutex_enter(&fil_system->mutex);
- HASH_SEARCH(hash, system->spaces, id, space, space->id == id);
+ space = fil_space_get_by_id(id);
ut_a(space);
n = space->n_reserved_extents;
- mutex_exit(&(system->mutex));
+ mutex_exit(&fil_system->mutex);
return(n);
}
/*============================ FILE I/O ================================*/
-/************************************************************************
+/********************************************************************//**
NOTE: you must call fil_mutex_enter_and_prepare_for_io() first!
Prepares a file node for i/o. Opens the file if it is closed. Updates the
@@ -3854,9 +4051,9 @@ static
void
fil_node_prepare_for_io(
/*====================*/
- fil_node_t* node, /* in: file node */
- fil_system_t* system, /* in: tablespace memory cache */
- fil_space_t* space) /* in: space */
+ fil_node_t* node, /*!< in: file node */
+ fil_system_t* system, /*!< in: tablespace memory cache */
+ fil_space_t* space) /*!< in: space */
{
ut_ad(node && system && space);
ut_ad(mutex_own(&(system->mutex)));
@@ -3889,16 +4086,16 @@ fil_node_prepare_for_io(
node->n_pending++;
}
-/************************************************************************
+/********************************************************************//**
Updates the data structures when an i/o operation finishes. Updates the
pending i/o's field in the node appropriately. */
static
void
fil_node_complete_io(
/*=================*/
- fil_node_t* node, /* in: file node */
- fil_system_t* system, /* in: tablespace memory cache */
- ulint type) /* in: OS_FILE_WRITE or OS_FILE_READ; marks
+ fil_node_t* node, /*!< in: file node */
+ fil_system_t* system, /*!< in: tablespace memory cache */
+ ulint type) /*!< in: OS_FILE_WRITE or OS_FILE_READ; marks
the node as modified if
type == OS_FILE_WRITE */
{
@@ -3930,18 +4127,18 @@ fil_node_complete_io(
}
}
-/************************************************************************
+/********************************************************************//**
Report information about an invalid page access. */
static
void
fil_report_invalid_page_access(
/*===========================*/
- ulint block_offset, /* in: block offset */
- ulint space_id, /* in: space id */
- const char* space_name, /* in: space name */
- ulint byte_offset, /* in: byte offset */
- ulint len, /* in: I/O length */
- ulint type) /* in: I/O type */
+ ulint block_offset, /*!< in: block offset */
+ ulint space_id, /*!< in: space id */
+ const char* space_name, /*!< in: space name */
+ ulint byte_offset, /*!< in: byte offset */
+ ulint len, /*!< in: I/O length */
+ ulint type) /*!< in: I/O type */
{
fprintf(stderr,
"InnoDB: Error: trying to access page number %lu"
@@ -3958,16 +4155,15 @@ fil_report_invalid_page_access(
(ulong) byte_offset, (ulong) len, (ulong) type);
}
-/************************************************************************
-Reads or writes data. This operation is asynchronous (aio). */
-
+/********************************************************************//**
+Reads or writes data. This operation is asynchronous (aio).
+@return DB_SUCCESS, or DB_TABLESPACE_DELETED if we are trying to do
+i/o on a tablespace which does not exist */
+UNIV_INTERN
ulint
fil_io(
/*===*/
- /* out: DB_SUCCESS, or DB_TABLESPACE_DELETED
- if we are trying to do i/o on a tablespace
- which does not exist */
- ulint type, /* in: OS_FILE_READ or OS_FILE_WRITE,
+ ulint type, /*!< in: OS_FILE_READ or OS_FILE_WRITE,
ORed to OS_FILE_LOG, if a log i/o
and ORed to OS_AIO_SIMULATED_WAKE_LATER
if simulated aio and we want to post a
@@ -3976,22 +4172,23 @@ fil_io(
because i/os are not actually handled until
all have been posted: use with great
caution! */
- ibool sync, /* in: TRUE if synchronous aio is desired */
- ulint space_id, /* in: space id */
- ulint block_offset, /* in: offset in number of blocks */
- ulint byte_offset, /* in: remainder of offset in bytes; in
+ ibool sync, /*!< in: TRUE if synchronous aio is desired */
+ ulint space_id, /*!< in: space id */
+ ulint zip_size, /*!< in: compressed page size in bytes;
+ 0 for uncompressed pages */
+ ulint block_offset, /*!< in: offset in number of blocks */
+ ulint byte_offset, /*!< in: remainder of offset in bytes; in
aio this must be divisible by the OS block
size */
- ulint len, /* in: how many bytes to read or write; this
+ ulint len, /*!< in: how many bytes to read or write; this
must not cross a file boundary; in aio this
must be a block size multiple */
- void* buf, /* in/out: buffer where to store read data
+ void* buf, /*!< in/out: buffer where to store read data
or from where to write; in aio this must be
appropriately aligned */
- void* message) /* in: message for aio handler if non-sync
+ void* message) /*!< in: message for aio handler if non-sync
aio used, else ignored */
{
- fil_system_t* system = fil_system;
ulint mode;
fil_space_t* space;
fil_node_t* node;
@@ -4008,29 +4205,38 @@ fil_io(
type = type & ~OS_AIO_SIMULATED_WAKE_LATER;
ut_ad(byte_offset < UNIV_PAGE_SIZE);
+ ut_ad(!zip_size || !byte_offset);
+ ut_ad(ut_is_2pow(zip_size));
ut_ad(buf);
ut_ad(len > 0);
- ut_a((1 << UNIV_PAGE_SIZE_SHIFT) == UNIV_PAGE_SIZE);
+#if (1 << UNIV_PAGE_SIZE_SHIFT) != UNIV_PAGE_SIZE
+# error "(1 << UNIV_PAGE_SIZE_SHIFT) != UNIV_PAGE_SIZE"
+#endif
ut_ad(fil_validate());
-#ifndef UNIV_LOG_DEBUG
+#ifndef UNIV_HOTBACKUP
+# ifndef UNIV_LOG_DEBUG
/* ibuf bitmap pages must be read in the sync aio mode: */
ut_ad(recv_no_ibuf_operations || (type == OS_FILE_WRITE)
- || !ibuf_bitmap_page(block_offset) || sync || is_log);
-#ifdef UNIV_SYNC_DEBUG
+ || !ibuf_bitmap_page(zip_size, block_offset)
+ || sync || is_log);
ut_ad(!ibuf_inside() || is_log || (type == OS_FILE_WRITE)
- || ibuf_page(space_id, block_offset));
-#endif
-#endif
+ || ibuf_page(space_id, zip_size, block_offset, NULL));
+# endif /* UNIV_LOG_DEBUG */
if (sync) {
mode = OS_AIO_SYNC;
- } else if (type == OS_FILE_READ && !is_log
- && ibuf_page(space_id, block_offset)) {
- mode = OS_AIO_IBUF;
} else if (is_log) {
mode = OS_AIO_LOG;
+ } else if (type == OS_FILE_READ
+ && !recv_no_ibuf_operations
+ && ibuf_page(space_id, zip_size, block_offset, NULL)) {
+ mode = OS_AIO_IBUF;
} else {
mode = OS_AIO_NORMAL;
}
+#else /* !UNIV_HOTBACKUP */
+ ut_a(sync);
+ mode = OS_AIO_SYNC;
+#endif /* !UNIV_HOTBACKUP */
if (type == OS_FILE_READ) {
srv_data_read+= len;
@@ -4043,10 +4249,10 @@ fil_io(
fil_mutex_enter_and_prepare_for_io(space_id);
- HASH_SEARCH(hash, system->spaces, space_id, space,
- space->id == space_id);
+ space = fil_space_get_by_id(space_id);
+
if (!space) {
- mutex_exit(&(system->mutex));
+ mutex_exit(&fil_system->mutex);
ut_print_timestamp(stderr);
fprintf(stderr,
@@ -4065,7 +4271,7 @@ fil_io(
node = UT_LIST_GET_FIRST(space->chain);
for (;;) {
- if (node == NULL) {
+ if (UNIV_UNLIKELY(node == NULL)) {
fil_report_invalid_page_access(
block_offset, space_id, space->name,
byte_offset, len, type);
@@ -4090,12 +4296,12 @@ fil_io(
}
/* Open file if closed */
- fil_node_prepare_for_io(node, system, space);
+ fil_node_prepare_for_io(node, fil_system, space);
/* Check that at least the start offset is within the bounds of a
single-table tablespace */
- if (space->purpose == FIL_TABLESPACE && space->id != 0
- && node->size <= block_offset) {
+ if (UNIV_UNLIKELY(node->size <= block_offset)
+ && space->id != 0 && space->purpose == FIL_TABLESPACE) {
fil_report_invalid_page_access(
block_offset, space_id, space->name, byte_offset,
@@ -4104,17 +4310,35 @@ fil_io(
ut_error;
}
- /* Now we have made the changes in the data structures of system */
- mutex_exit(&(system->mutex));
+ /* Now we have made the changes in the data structures of fil_system */
+ mutex_exit(&fil_system->mutex);
/* Calculate the low 32 bits and the high 32 bits of the file offset */
- offset_high = (block_offset >> (32 - UNIV_PAGE_SIZE_SHIFT));
- offset_low = ((block_offset << UNIV_PAGE_SIZE_SHIFT) & 0xFFFFFFFFUL)
- + byte_offset;
+ if (!zip_size) {
+ offset_high = (block_offset >> (32 - UNIV_PAGE_SIZE_SHIFT));
+ offset_low = ((block_offset << UNIV_PAGE_SIZE_SHIFT)
+ & 0xFFFFFFFFUL) + byte_offset;
- ut_a(node->size - block_offset
- >= (byte_offset + len + (UNIV_PAGE_SIZE - 1)) / UNIV_PAGE_SIZE);
+ ut_a(node->size - block_offset
+ >= ((byte_offset + len + (UNIV_PAGE_SIZE - 1))
+ / UNIV_PAGE_SIZE));
+ } else {
+ ulint zip_size_shift;
+ switch (zip_size) {
+ case 1024: zip_size_shift = 10; break;
+ case 2048: zip_size_shift = 11; break;
+ case 4096: zip_size_shift = 12; break;
+ case 8192: zip_size_shift = 13; break;
+ case 16384: zip_size_shift = 14; break;
+ default: ut_error;
+ }
+ offset_high = block_offset >> (32 - zip_size_shift);
+ offset_low = (block_offset << zip_size_shift & 0xFFFFFFFFUL)
+ + byte_offset;
+ ut_a(node->size - block_offset
+ >= (len + (zip_size - 1)) / zip_size);
+ }
/* Do aio */
@@ -4141,11 +4365,11 @@ fil_io(
/* The i/o operation is already completed when we return from
os_aio: */
- mutex_enter(&(system->mutex));
+ mutex_enter(&fil_system->mutex);
- fil_node_complete_io(node, system, type);
+ fil_node_complete_io(node, fil_system, type);
- mutex_exit(&(system->mutex));
+ mutex_exit(&fil_system->mutex);
ut_ad(fil_validate());
}
@@ -4153,75 +4377,19 @@ fil_io(
return(DB_SUCCESS);
}
-/************************************************************************
-Reads data from a space to a buffer. Remember that the possible incomplete
-blocks at the end of file are ignored: they are not taken into account when
-calculating the byte offset within a space. */
-
-ulint
-fil_read(
-/*=====*/
- /* out: DB_SUCCESS, or DB_TABLESPACE_DELETED
- if we are trying to do i/o on a tablespace
- which does not exist */
- ibool sync, /* in: TRUE if synchronous aio is desired */
- ulint space_id, /* in: space id */
- ulint block_offset, /* in: offset in number of blocks */
- ulint byte_offset, /* in: remainder of offset in bytes; in aio
- this must be divisible by the OS block size */
- ulint len, /* in: how many bytes to read; this must not
- cross a file boundary; in aio this must be a
- block size multiple */
- void* buf, /* in/out: buffer where to store data read;
- in aio this must be appropriately aligned */
- void* message) /* in: message for aio handler if non-sync
- aio used, else ignored */
-{
- return(fil_io(OS_FILE_READ, sync, space_id, block_offset,
- byte_offset, len, buf, message));
-}
-
-/************************************************************************
-Writes data to a space from a buffer. Remember that the possible incomplete
-blocks at the end of file are ignored: they are not taken into account when
-calculating the byte offset within a space. */
-
-ulint
-fil_write(
-/*======*/
- /* out: DB_SUCCESS, or DB_TABLESPACE_DELETED
- if we are trying to do i/o on a tablespace
- which does not exist */
- ibool sync, /* in: TRUE if synchronous aio is desired */
- ulint space_id, /* in: space id */
- ulint block_offset, /* in: offset in number of blocks */
- ulint byte_offset, /* in: remainder of offset in bytes; in aio
- this must be divisible by the OS block size */
- ulint len, /* in: how many bytes to write; this must
- not cross a file boundary; in aio this must
- be a block size multiple */
- void* buf, /* in: buffer from which to write; in aio
- this must be appropriately aligned */
- void* message) /* in: message for aio handler if non-sync
- aio used, else ignored */
-{
- return(fil_io(OS_FILE_WRITE, sync, space_id, block_offset,
- byte_offset, len, buf, message));
-}
-
-/**************************************************************************
+#ifndef UNIV_HOTBACKUP
+/**********************************************************************//**
Waits for an aio operation to complete. This function is used to write the
handler for completed requests. The aio array of pending requests is divided
into segments (see os0file.c for more info). The thread specifies which
segment it wants to wait for. */
-
+UNIV_INTERN
void
fil_aio_wait(
/*=========*/
- ulint segment) /* in: the number of the segment in the aio
+ ulint segment) /*!< in: the number of the segment in the aio
array to wait for */
{
- fil_system_t* system = fil_system;
ibool ret;
fil_node_t* fil_node;
void* message;
@@ -4234,8 +4402,6 @@ fil_aio_wait(
#ifdef WIN_ASYNC_IO
ret = os_aio_windows_handle(segment, 0, &fil_node,
&message, &type);
-#elif defined(POSIX_ASYNC_IO)
- ret = os_aio_posix_handle(segment, &fil_node, &message);
#else
ret = 0; /* Eliminate compiler warning */
ut_error;
@@ -4251,11 +4417,11 @@ fil_aio_wait(
srv_set_io_thread_op_info(segment, "complete io for fil node");
- mutex_enter(&(system->mutex));
+ mutex_enter(&fil_system->mutex);
fil_node_complete_io(fil_node, fil_system, type);
- mutex_exit(&(system->mutex));
+ mutex_exit(&fil_system->mutex);
ut_ad(fil_validate());
@@ -4265,7 +4431,7 @@ fil_aio_wait(
deadlocks in the i/o system. We keep tablespace 0 data files always
open, and use a special i/o thread to serve insert buffer requests. */
- if (buf_pool_is_block(message)) {
+ if (fil_node->space->purpose == FIL_TABLESPACE) {
srv_set_io_thread_op_info(segment, "complete io for buf page");
buf_page_io_complete(message);
} else {
@@ -4273,34 +4439,34 @@ fil_aio_wait(
log_io_complete(message);
}
}
+#endif /* UNIV_HOTBACKUP */
-/**************************************************************************
+/**********************************************************************//**
Flushes to disk possible writes cached by the OS. If the space does not exist
or is being dropped, does not do anything. */
-
+UNIV_INTERN
void
fil_flush(
/*======*/
- ulint space_id) /* in: file space id (this can be a group of
+ ulint space_id) /*!< in: file space id (this can be a group of
log files or a tablespace of the database) */
{
- fil_system_t* system = fil_system;
fil_space_t* space;
fil_node_t* node;
os_file_t file;
- ib_longlong old_mod_counter;
+ ib_int64_t old_mod_counter;
- mutex_enter(&(system->mutex));
+ mutex_enter(&fil_system->mutex);
+
+ space = fil_space_get_by_id(space_id);
- HASH_SEARCH(hash, system->spaces, space_id, space,
- space->id == space_id);
if (!space || space->is_being_deleted) {
- mutex_exit(&(system->mutex));
+ mutex_exit(&fil_system->mutex);
return;
}
- space->n_pending_flushes++; /* prevent dropping of the space while
+ space->n_pending_flushes++; /*!< prevent dropping of the space while
we are flushing */
node = UT_LIST_GET_FIRST(space->chain);
@@ -4331,11 +4497,11 @@ retry:
not know what bugs OS's may contain in file
i/o; sleep for a while */
- mutex_exit(&(system->mutex));
+ mutex_exit(&fil_system->mutex);
os_thread_sleep(20000);
- mutex_enter(&(system->mutex));
+ mutex_enter(&fil_system->mutex);
if (node->flush_counter >= old_mod_counter) {
@@ -4349,14 +4515,14 @@ retry:
file = node->handle;
node->n_pending_flushes++;
- mutex_exit(&(system->mutex));
+ mutex_exit(&fil_system->mutex);
/* fprintf(stderr, "Flushing to file %s\n",
node->name); */
os_file_flush(file);
- mutex_enter(&(system->mutex));
+ mutex_enter(&fil_system->mutex);
node->n_pending_flushes--;
skip_flush:
@@ -4370,7 +4536,7 @@ skip_flush:
UT_LIST_REMOVE(
unflushed_spaces,
- system->unflushed_spaces,
+ fil_system->unflushed_spaces,
space);
}
}
@@ -4387,42 +4553,41 @@ skip_flush:
space->n_pending_flushes--;
- mutex_exit(&(system->mutex));
+ mutex_exit(&fil_system->mutex);
}
-/**************************************************************************
+/**********************************************************************//**
Flushes to disk the writes in file spaces of the given type possibly cached by
the OS. */
-
+UNIV_INTERN
void
fil_flush_file_spaces(
/*==================*/
- ulint purpose) /* in: FIL_TABLESPACE, FIL_LOG */
+ ulint purpose) /*!< in: FIL_TABLESPACE, FIL_LOG */
{
- fil_system_t* system = fil_system;
fil_space_t* space;
ulint* space_ids;
ulint n_space_ids;
ulint i;
- mutex_enter(&(system->mutex));
+ mutex_enter(&fil_system->mutex);
- n_space_ids = UT_LIST_GET_LEN(system->unflushed_spaces);
+ n_space_ids = UT_LIST_GET_LEN(fil_system->unflushed_spaces);
if (n_space_ids == 0) {
- mutex_exit(&system->mutex);
+ mutex_exit(&fil_system->mutex);
return;
}
/* Assemble a list of space ids to flush. Previously, we
- traversed system->unflushed_spaces and called UT_LIST_GET_NEXT()
+ traversed fil_system->unflushed_spaces and called UT_LIST_GET_NEXT()
on a space that was just removed from the list by fil_flush().
Thus, the space could be dropped and the memory overwritten. */
space_ids = mem_alloc(n_space_ids * sizeof *space_ids);
n_space_ids = 0;
- for (space = UT_LIST_GET_FIRST(system->unflushed_spaces);
+ for (space = UT_LIST_GET_FIRST(fil_system->unflushed_spaces);
space;
space = UT_LIST_GET_NEXT(unflushed_spaces, space)) {
@@ -4432,7 +4597,7 @@ fil_flush_file_spaces(
}
}
- mutex_exit(&system->mutex);
+ mutex_exit(&fil_system->mutex);
/* Flush the spaces. It will not hurt to call fil_flush() on
a non-existing space id. */
@@ -4444,30 +4609,31 @@ fil_flush_file_spaces(
mem_free(space_ids);
}
-/**********************************************************************
-Checks the consistency of the tablespace cache. */
-
+/******************************************************************//**
+Checks the consistency of the tablespace cache.
+@return TRUE if ok */
+UNIV_INTERN
ibool
fil_validate(void)
/*==============*/
- /* out: TRUE if ok */
{
- fil_system_t* system = fil_system;
fil_space_t* space;
fil_node_t* fil_node;
ulint n_open = 0;
ulint i;
- mutex_enter(&(system->mutex));
+ mutex_enter(&fil_system->mutex);
/* Look for spaces in the hash table */
- for (i = 0; i < hash_get_n_cells(system->spaces); i++) {
+ for (i = 0; i < hash_get_n_cells(fil_system->spaces); i++) {
- space = HASH_GET_FIRST(system->spaces, i);
+ space = HASH_GET_FIRST(fil_system->spaces, i);
while (space != NULL) {
- UT_LIST_VALIDATE(chain, fil_node_t, space->chain);
+ UT_LIST_VALIDATE(chain, fil_node_t, space->chain,
+ ut_a(ut_list_node_313->open
+ || !ut_list_node_313->n_pending));
fil_node = UT_LIST_GET_FIRST(space->chain);
@@ -4485,11 +4651,11 @@ fil_validate(void)
}
}
- ut_a(system->n_open == n_open);
+ ut_a(fil_system->n_open == n_open);
- UT_LIST_VALIDATE(LRU, fil_node_t, system->LRU);
+ UT_LIST_VALIDATE(LRU, fil_node_t, fil_system->LRU, (void) 0);
- fil_node = UT_LIST_GET_FIRST(system->LRU);
+ fil_node = UT_LIST_GET_FIRST(fil_system->LRU);
while (fil_node != NULL) {
ut_a(fil_node->n_pending == 0);
@@ -4500,65 +4666,70 @@ fil_validate(void)
fil_node = UT_LIST_GET_NEXT(LRU, fil_node);
}
- mutex_exit(&(system->mutex));
+ mutex_exit(&fil_system->mutex);
return(TRUE);
}
-/************************************************************************
-Returns TRUE if file address is undefined. */
+/********************************************************************//**
+Returns TRUE if file address is undefined.
+@return TRUE if undefined */
+UNIV_INTERN
ibool
fil_addr_is_null(
/*=============*/
- /* out: TRUE if undefined */
- fil_addr_t addr) /* in: address */
+ fil_addr_t addr) /*!< in: address */
{
- if (addr.page == FIL_NULL) {
-
- return(TRUE);
- }
-
- return(FALSE);
+ return(addr.page == FIL_NULL);
}
-/************************************************************************
-Accessor functions for a file page */
-
+/********************************************************************//**
+Get the predecessor of a file page.
+@return FIL_PAGE_PREV */
+UNIV_INTERN
ulint
-fil_page_get_prev(byte* page)
+fil_page_get_prev(
+/*==============*/
+ const byte* page) /*!< in: file page */
{
return(mach_read_from_4(page + FIL_PAGE_PREV));
}
+/********************************************************************//**
+Get the successor of a file page.
+@return FIL_PAGE_NEXT */
+UNIV_INTERN
ulint
-fil_page_get_next(byte* page)
+fil_page_get_next(
+/*==============*/
+ const byte* page) /*!< in: file page */
{
return(mach_read_from_4(page + FIL_PAGE_NEXT));
}
-/*************************************************************************
+/*********************************************************************//**
Sets the file page type. */
-
+UNIV_INTERN
void
fil_page_set_type(
/*==============*/
- byte* page, /* in: file page */
- ulint type) /* in: type */
+ byte* page, /*!< in/out: file page */
+ ulint type) /*!< in: type */
{
ut_ad(page);
mach_write_to_2(page + FIL_PAGE_TYPE, type);
}
-/*************************************************************************
-Gets the file page type. */
-
+/*********************************************************************//**
+Gets the file page type.
+@return type; NOTE that if the type has not been written to page, the
+return value not defined */
+UNIV_INTERN
ulint
fil_page_get_type(
/*==============*/
- /* out: type; NOTE that if the type has not been
- written to page, the return value not defined */
- byte* page) /* in: file page */
+ const byte* page) /*!< in: file page */
{
ut_ad(page);
diff --git a/storage/innobase/fsp/fsp0fsp.c b/storage/innodb_plugin/fsp/fsp0fsp.c
similarity index 63%
rename from storage/innobase/fsp/fsp0fsp.c
rename to storage/innodb_plugin/fsp/fsp0fsp.c
index e1074933fe8..ce14723ba18 100644
--- a/storage/innobase/fsp/fsp0fsp.c
+++ b/storage/innodb_plugin/fsp/fsp0fsp.c
@@ -1,7 +1,24 @@
-/**********************************************************************
-File space management
+/*****************************************************************************
-(c) 1995 Innobase Oy
+Copyright (c) 1995, 2009, Innobase Oy. All Rights Reserved.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; version 2 of the License.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place, Suite 330, Boston, MA 02111-1307 USA
+
+*****************************************************************************/
+
+/******************************************************************//**
+@file fsp/fsp0fsp.c
+File space management
Created 11/29/1995 Heikki Tuuri
***********************************************************************/
@@ -14,18 +31,23 @@ Created 11/29/1995 Heikki Tuuri
#include "buf0buf.h"
#include "fil0fil.h"
-#include "sync0sync.h"
#include "mtr0log.h"
-#include "fut0fut.h"
#include "ut0byte.h"
-#include "srv0srv.h"
-#include "page0types.h"
-#include "ibuf0ibuf.h"
-#include "btr0btr.h"
-#include "btr0sea.h"
-#include "dict0boot.h"
+#include "page0page.h"
+#include "page0zip.h"
+#ifdef UNIV_HOTBACKUP
+# include "fut0lst.h"
+#else /* UNIV_HOTBACKUP */
+# include "sync0sync.h"
+# include "fut0fut.h"
+# include "srv0srv.h"
+# include "ibuf0ibuf.h"
+# include "btr0btr.h"
+# include "btr0sea.h"
+# include "dict0boot.h"
+# include "log0log.h"
+#endif /* UNIV_HOTBACKUP */
#include "dict0mem.h"
-#include "log0log.h"
#define FSP_HEADER_OFFSET FIL_PAGE_DATA /* Offset of the space header
@@ -60,11 +82,7 @@ descriptor page, but used only in the first. */
about the first extent, but have not
physically allocted those pages to the
file */
-#define FSP_LOWEST_NO_WRITE 16 /* The lowest page offset for which
- the page has not been written to disk
- (if it has been written, we know that
- the OS has really reserved the
- physical space for the page) */
+#define FSP_SPACE_FLAGS 16 /* table->flags & ~DICT_TF_COMPACT */
#define FSP_FRAG_N_USED 20 /* number of used pages in the
FSP_FREE_FRAG list */
#define FSP_FREE 24 /* list of free extents */
@@ -139,8 +157,9 @@ typedef byte fseg_inode_t;
(16 + 3 * FLST_BASE_NODE_SIZE \
+ FSEG_FRAG_ARR_N_SLOTS * FSEG_FRAG_SLOT_SIZE)
-#define FSP_SEG_INODES_PER_PAGE \
- ((UNIV_PAGE_SIZE - FSEG_ARR_OFFSET - 10) / FSEG_INODE_SIZE)
+#define FSP_SEG_INODES_PER_PAGE(zip_size) \
+ (((zip_size ? zip_size : UNIV_PAGE_SIZE) \
+ - FSEG_ARR_OFFSET - 10) / FSEG_INODE_SIZE)
/* Number of segment inodes which fit on a
single page */
@@ -212,60 +231,70 @@ the extent are free and which contain old tuple version to clean. */
/* Offset of the descriptor array on a descriptor page */
#define XDES_ARR_OFFSET (FSP_HEADER_OFFSET + FSP_HEADER_SIZE)
-/**************************************************************************
+#ifndef UNIV_HOTBACKUP
+/**********************************************************************//**
Returns an extent to the free list of a space. */
static
void
fsp_free_extent(
/*============*/
- ulint space, /* in: space id */
- ulint page, /* in: page offset in the extent */
- mtr_t* mtr); /* in: mtr */
-/**************************************************************************
+ ulint space, /*!< in: space id */
+ ulint zip_size,/*!< in: compressed page size in bytes
+ or 0 for uncompressed pages */
+ ulint page, /*!< in: page offset in the extent */
+ mtr_t* mtr); /*!< in: mtr */
+/**********************************************************************//**
Frees an extent of a segment to the space free list. */
static
void
fseg_free_extent(
/*=============*/
- fseg_inode_t* seg_inode, /* in: segment inode */
- ulint space, /* in: space id */
- ulint page, /* in: page offset in the extent */
- mtr_t* mtr); /* in: mtr handle */
-/**************************************************************************
+ fseg_inode_t* seg_inode, /*!< in: segment inode */
+ ulint space, /*!< in: space id */
+ ulint zip_size,/*!< in: compressed page size in bytes
+ or 0 for uncompressed pages */
+ ulint page, /*!< in: page offset in the extent */
+ mtr_t* mtr); /*!< in: mtr handle */
+/**********************************************************************//**
Calculates the number of pages reserved by a segment, and how
-many pages are currently used. */
+many pages are currently used.
+@return number of reserved pages */
static
ulint
fseg_n_reserved_pages_low(
/*======================*/
- /* out: number of reserved pages */
- fseg_inode_t* header, /* in: segment inode */
- ulint* used, /* out: number of pages used (<= reserved) */
- mtr_t* mtr); /* in: mtr handle */
-/************************************************************************
+ fseg_inode_t* header, /*!< in: segment inode */
+ ulint* used, /*!< out: number of pages used (not
+ more than reserved) */
+ mtr_t* mtr); /*!< in: mtr handle */
+/********************************************************************//**
Marks a page used. The page must reside within the extents of the given
segment. */
static
void
fseg_mark_page_used(
/*================*/
- fseg_inode_t* seg_inode,/* in: segment inode */
- ulint space, /* in: space id */
- ulint page, /* in: page offset */
- mtr_t* mtr); /* in: mtr */
-/**************************************************************************
+ fseg_inode_t* seg_inode,/*!< in: segment inode */
+ ulint space, /*!< in: space id */
+ ulint zip_size,/*!< in: compressed page size in bytes
+ or 0 for uncompressed pages */
+ ulint page, /*!< in: page offset */
+ mtr_t* mtr); /*!< in: mtr */
+/**********************************************************************//**
Returns the first extent descriptor for a segment. We think of the extent
lists of the segment catenated in the order FSEG_FULL -> FSEG_NOT_FULL
--> FSEG_FREE. */
+-> FSEG_FREE.
+@return the first extent descriptor, or NULL if none */
static
xdes_t*
fseg_get_first_extent(
/*==================*/
- /* out: the first extent descriptor, or NULL if
- none */
- fseg_inode_t* inode, /* in: segment inode */
- mtr_t* mtr); /* in: mtr */
-/**************************************************************************
+ fseg_inode_t* inode, /*!< in: segment inode */
+ ulint space, /*!< in: space id */
+ ulint zip_size,/*!< in: compressed page size in bytes
+ or 0 for uncompressed pages */
+ mtr_t* mtr); /*!< in: mtr */
+/**********************************************************************//**
Puts new extents to the free list if
there are free extents above the free limit. If an extent happens
to contain an extent descriptor page, the extent is put to
@@ -274,87 +303,97 @@ static
void
fsp_fill_free_list(
/*===============*/
- ibool init_space, /* in: TRUE if this is a single-table
+ ibool init_space, /*!< in: TRUE if this is a single-table
tablespace and we are only initing
the tablespace's first extent
descriptor page and ibuf bitmap page;
then we do not allocate more extents */
- ulint space, /* in: space */
- fsp_header_t* header, /* in: space header */
- mtr_t* mtr); /* in: mtr */
-/**************************************************************************
+ ulint space, /*!< in: space */
+ fsp_header_t* header, /*!< in: space header */
+ mtr_t* mtr); /*!< in: mtr */
+/**********************************************************************//**
Allocates a single free page from a segment. This function implements
the intelligent allocation strategy which tries to minimize file space
-fragmentation. */
+fragmentation.
+@return the allocated page number, FIL_NULL if no page could be allocated */
static
ulint
fseg_alloc_free_page_low(
/*=====================*/
- /* out: the allocated page number, FIL_NULL
- if no page could be allocated */
- ulint space, /* in: space */
- fseg_inode_t* seg_inode, /* in: segment inode */
- ulint hint, /* in: hint of which page would be desirable */
- byte direction, /* in: if the new page is needed because
+ ulint space, /*!< in: space */
+ ulint zip_size,/*!< in: compressed page size in bytes
+ or 0 for uncompressed pages */
+ fseg_inode_t* seg_inode, /*!< in: segment inode */
+ ulint hint, /*!< in: hint of which page would be desirable */
+ byte direction, /*!< in: if the new page is needed because
of an index page split, and records are
inserted there in order, into which
direction they go alphabetically: FSP_DOWN,
FSP_UP, FSP_NO_DIR */
- mtr_t* mtr); /* in: mtr handle */
-
-
-/**************************************************************************
-Reads the file space size stored in the header page. */
+ mtr_t* mtr); /*!< in: mtr handle */
+#endif /* !UNIV_HOTBACKUP */
+/**********************************************************************//**
+Reads the file space size stored in the header page.
+@return tablespace size stored in the space header */
+UNIV_INTERN
ulint
fsp_get_size_low(
/*=============*/
- /* out: tablespace size stored in the space header */
- page_t* page) /* in: header page (page 0 in the tablespace) */
+ page_t* page) /*!< in: header page (page 0 in the tablespace) */
{
return(mach_read_from_4(page + FSP_HEADER_OFFSET + FSP_SIZE));
}
-/**************************************************************************
-Gets a pointer to the space header and x-locks its page. */
+#ifndef UNIV_HOTBACKUP
+/**********************************************************************//**
+Gets a pointer to the space header and x-locks its page.
+@return pointer to the space header, page x-locked */
UNIV_INLINE
fsp_header_t*
fsp_get_space_header(
/*=================*/
- /* out: pointer to the space header, page x-locked */
- ulint id, /* in: space id */
- mtr_t* mtr) /* in: mtr */
+ ulint id, /*!< in: space id */
+ ulint zip_size,/*!< in: compressed page size in bytes
+ or 0 for uncompressed pages */
+ mtr_t* mtr) /*!< in: mtr */
{
+ buf_block_t* block;
fsp_header_t* header;
- ut_ad(mtr);
+ ut_ad(ut_is_2pow(zip_size));
+ ut_ad(zip_size <= UNIV_PAGE_SIZE);
+ ut_ad(!zip_size || zip_size >= PAGE_ZIP_MIN_SIZE);
+ ut_ad(id || !zip_size);
- header = FSP_HEADER_OFFSET + buf_page_get(id, 0, RW_X_LATCH, mtr);
-#ifdef UNIV_SYNC_DEBUG
- buf_page_dbg_add_level(header, SYNC_FSP_PAGE);
-#endif /* UNIV_SYNC_DEBUG */
+ block = buf_page_get(id, zip_size, 0, RW_X_LATCH, mtr);
+ header = FSP_HEADER_OFFSET + buf_block_get_frame(block);
+ buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
+
+ ut_ad(id == mach_read_from_4(FSP_SPACE_ID + header));
+ ut_ad(zip_size == dict_table_flags_to_zip_size(
+ mach_read_from_4(FSP_SPACE_FLAGS + header)));
return(header);
}
-/**************************************************************************
-Gets a descriptor bit of a page. */
+/**********************************************************************//**
+Gets a descriptor bit of a page.
+@return TRUE if free */
UNIV_INLINE
ibool
xdes_get_bit(
/*=========*/
- /* out: TRUE if free */
- xdes_t* descr, /* in: descriptor */
- ulint bit, /* in: XDES_FREE_BIT or XDES_CLEAN_BIT */
- ulint offset, /* in: page offset within extent:
+ xdes_t* descr, /*!< in: descriptor */
+ ulint bit, /*!< in: XDES_FREE_BIT or XDES_CLEAN_BIT */
+ ulint offset, /*!< in: page offset within extent:
0 ... FSP_EXTENT_SIZE - 1 */
- mtr_t* mtr) /* in: mtr */
+ mtr_t* mtr) /*!< in: mtr */
{
ulint index;
ulint byte_index;
ulint bit_index;
- ut_ad(mtr_memo_contains(mtr, buf_block_align(descr),
- MTR_MEMO_PAGE_X_FIX));
+ ut_ad(mtr_memo_contains_page(mtr, descr, MTR_MEMO_PAGE_X_FIX));
ut_ad((bit == XDES_FREE_BIT) || (bit == XDES_CLEAN_BIT));
ut_ad(offset < FSP_EXTENT_SIZE);
@@ -368,26 +407,25 @@ xdes_get_bit(
bit_index));
}
-/**************************************************************************
+/**********************************************************************//**
Sets a descriptor bit of a page. */
UNIV_INLINE
void
xdes_set_bit(
/*=========*/
- xdes_t* descr, /* in: descriptor */
- ulint bit, /* in: XDES_FREE_BIT or XDES_CLEAN_BIT */
- ulint offset, /* in: page offset within extent:
+ xdes_t* descr, /*!< in: descriptor */
+ ulint bit, /*!< in: XDES_FREE_BIT or XDES_CLEAN_BIT */
+ ulint offset, /*!< in: page offset within extent:
0 ... FSP_EXTENT_SIZE - 1 */
- ibool val, /* in: bit value */
- mtr_t* mtr) /* in: mtr */
+ ibool val, /*!< in: bit value */
+ mtr_t* mtr) /*!< in: mtr */
{
ulint index;
ulint byte_index;
ulint bit_index;
ulint descr_byte;
- ut_ad(mtr_memo_contains(mtr, buf_block_align(descr),
- MTR_MEMO_PAGE_X_FIX));
+ ut_ad(mtr_memo_contains_page(mtr, descr, MTR_MEMO_PAGE_X_FIX));
ut_ad((bit == XDES_FREE_BIT) || (bit == XDES_CLEAN_BIT));
ut_ad(offset < FSP_EXTENT_SIZE);
@@ -404,29 +442,27 @@ xdes_set_bit(
MLOG_1BYTE, mtr);
}
-/**************************************************************************
+/**********************************************************************//**
Looks for a descriptor bit having the desired value. Starts from hint
and scans upward; at the end of the extent the search is wrapped to
-the start of the extent. */
+the start of the extent.
+@return bit index of the bit, ULINT_UNDEFINED if not found */
UNIV_INLINE
ulint
xdes_find_bit(
/*==========*/
- /* out: bit index of the bit, ULINT_UNDEFINED if not
- found */
- xdes_t* descr, /* in: descriptor */
- ulint bit, /* in: XDES_FREE_BIT or XDES_CLEAN_BIT */
- ibool val, /* in: desired bit value */
- ulint hint, /* in: hint of which bit position would be desirable */
- mtr_t* mtr) /* in: mtr */
+ xdes_t* descr, /*!< in: descriptor */
+ ulint bit, /*!< in: XDES_FREE_BIT or XDES_CLEAN_BIT */
+ ibool val, /*!< in: desired bit value */
+ ulint hint, /*!< in: hint of which bit position would be desirable */
+ mtr_t* mtr) /*!< in: mtr */
{
ulint i;
ut_ad(descr && mtr);
ut_ad(val <= TRUE);
ut_ad(hint < FSP_EXTENT_SIZE);
- ut_ad(mtr_memo_contains(mtr, buf_block_align(descr),
- MTR_MEMO_PAGE_X_FIX));
+ ut_ad(mtr_memo_contains_page(mtr, descr, MTR_MEMO_PAGE_X_FIX));
for (i = hint; i < FSP_EXTENT_SIZE; i++) {
if (val == xdes_get_bit(descr, bit, i, mtr)) {
@@ -444,28 +480,26 @@ xdes_find_bit(
return(ULINT_UNDEFINED);
}
-/**************************************************************************
+/**********************************************************************//**
Looks for a descriptor bit having the desired value. Scans the extent in
-a direction opposite to xdes_find_bit. */
+a direction opposite to xdes_find_bit.
+@return bit index of the bit, ULINT_UNDEFINED if not found */
UNIV_INLINE
ulint
xdes_find_bit_downward(
/*===================*/
- /* out: bit index of the bit, ULINT_UNDEFINED if not
- found */
- xdes_t* descr, /* in: descriptor */
- ulint bit, /* in: XDES_FREE_BIT or XDES_CLEAN_BIT */
- ibool val, /* in: desired bit value */
- ulint hint, /* in: hint of which bit position would be desirable */
- mtr_t* mtr) /* in: mtr */
+ xdes_t* descr, /*!< in: descriptor */
+ ulint bit, /*!< in: XDES_FREE_BIT or XDES_CLEAN_BIT */
+ ibool val, /*!< in: desired bit value */
+ ulint hint, /*!< in: hint of which bit position would be desirable */
+ mtr_t* mtr) /*!< in: mtr */
{
ulint i;
ut_ad(descr && mtr);
ut_ad(val <= TRUE);
ut_ad(hint < FSP_EXTENT_SIZE);
- ut_ad(mtr_memo_contains(mtr, buf_block_align(descr),
- MTR_MEMO_PAGE_X_FIX));
+ ut_ad(mtr_memo_contains_page(mtr, descr, MTR_MEMO_PAGE_X_FIX));
for (i = hint + 1; i > 0; i--) {
if (val == xdes_get_bit(descr, bit, i - 1, mtr)) {
@@ -483,22 +517,21 @@ xdes_find_bit_downward(
return(ULINT_UNDEFINED);
}
-/**************************************************************************
-Returns the number of used pages in a descriptor. */
+/**********************************************************************//**
+Returns the number of used pages in a descriptor.
+@return number of pages used */
UNIV_INLINE
ulint
xdes_get_n_used(
/*============*/
- /* out: number of pages used */
- xdes_t* descr, /* in: descriptor */
- mtr_t* mtr) /* in: mtr */
+ xdes_t* descr, /*!< in: descriptor */
+ mtr_t* mtr) /*!< in: mtr */
{
ulint i;
ulint count = 0;
ut_ad(descr && mtr);
- ut_ad(mtr_memo_contains(mtr, buf_block_align(descr),
- MTR_MEMO_PAGE_X_FIX));
+ ut_ad(mtr_memo_contains_page(mtr, descr, MTR_MEMO_PAGE_X_FIX));
for (i = 0; i < FSP_EXTENT_SIZE; i++) {
if (FALSE == xdes_get_bit(descr, XDES_FREE_BIT, i, mtr)) {
count++;
@@ -508,15 +541,15 @@ xdes_get_n_used(
return(count);
}
-/**************************************************************************
-Returns true if extent contains no used pages. */
+/**********************************************************************//**
+Returns true if extent contains no used pages.
+@return TRUE if totally free */
UNIV_INLINE
ibool
xdes_is_free(
/*=========*/
- /* out: TRUE if totally free */
- xdes_t* descr, /* in: descriptor */
- mtr_t* mtr) /* in: mtr */
+ xdes_t* descr, /*!< in: descriptor */
+ mtr_t* mtr) /*!< in: mtr */
{
if (0 == xdes_get_n_used(descr, mtr)) {
@@ -526,15 +559,15 @@ xdes_is_free(
return(FALSE);
}
-/**************************************************************************
-Returns true if extent contains no free pages. */
+/**********************************************************************//**
+Returns true if extent contains no free pages.
+@return TRUE if full */
UNIV_INLINE
ibool
xdes_is_full(
/*=========*/
- /* out: TRUE if full */
- xdes_t* descr, /* in: descriptor */
- mtr_t* mtr) /* in: mtr */
+ xdes_t* descr, /*!< in: descriptor */
+ mtr_t* mtr) /*!< in: mtr */
{
if (FSP_EXTENT_SIZE == xdes_get_n_used(descr, mtr)) {
@@ -544,56 +577,57 @@ xdes_is_full(
return(FALSE);
}
-/**************************************************************************
+/**********************************************************************//**
Sets the state of an xdes. */
UNIV_INLINE
void
xdes_set_state(
/*===========*/
- xdes_t* descr, /* in: descriptor */
- ulint state, /* in: state to set */
- mtr_t* mtr) /* in: mtr handle */
+ xdes_t* descr, /*!< in: descriptor */
+ ulint state, /*!< in: state to set */
+ mtr_t* mtr) /*!< in: mtr handle */
{
ut_ad(descr && mtr);
ut_ad(state >= XDES_FREE);
ut_ad(state <= XDES_FSEG);
- ut_ad(mtr_memo_contains(mtr, buf_block_align(descr),
- MTR_MEMO_PAGE_X_FIX));
+ ut_ad(mtr_memo_contains_page(mtr, descr, MTR_MEMO_PAGE_X_FIX));
mlog_write_ulint(descr + XDES_STATE, state, MLOG_4BYTES, mtr);
}
-/**************************************************************************
-Gets the state of an xdes. */
+/**********************************************************************//**
+Gets the state of an xdes.
+@return state */
UNIV_INLINE
ulint
xdes_get_state(
/*===========*/
- /* out: state */
- xdes_t* descr, /* in: descriptor */
- mtr_t* mtr) /* in: mtr handle */
+ xdes_t* descr, /*!< in: descriptor */
+ mtr_t* mtr) /*!< in: mtr handle */
{
- ut_ad(descr && mtr);
- ut_ad(mtr_memo_contains(mtr, buf_block_align(descr),
- MTR_MEMO_PAGE_X_FIX));
+ ulint state;
- return(mtr_read_ulint(descr + XDES_STATE, MLOG_4BYTES, mtr));
+ ut_ad(descr && mtr);
+ ut_ad(mtr_memo_contains_page(mtr, descr, MTR_MEMO_PAGE_X_FIX));
+
+ state = mtr_read_ulint(descr + XDES_STATE, MLOG_4BYTES, mtr);
+ ut_ad(state - 1 < XDES_FSEG);
+ return(state);
}
-/**************************************************************************
+/**********************************************************************//**
Inits an extent descriptor to the free and clean state. */
UNIV_INLINE
void
xdes_init(
/*======*/
- xdes_t* descr, /* in: descriptor */
- mtr_t* mtr) /* in: mtr */
+ xdes_t* descr, /*!< in: descriptor */
+ mtr_t* mtr) /*!< in: mtr */
{
ulint i;
ut_ad(descr && mtr);
- ut_ad(mtr_memo_contains(mtr, buf_block_align(descr),
- MTR_MEMO_PAGE_X_FIX));
+ ut_ad(mtr_memo_contains_page(mtr, descr, MTR_MEMO_PAGE_X_FIX));
ut_ad((XDES_SIZE - XDES_BITMAP) % 4 == 0);
for (i = XDES_BITMAP; i < XDES_SIZE; i += 4) {
@@ -603,68 +637,96 @@ xdes_init(
xdes_set_state(descr, XDES_FREE, mtr);
}
-/************************************************************************
-Calculates the page where the descriptor of a page resides. */
+/********************************************************************//**
+Calculates the page where the descriptor of a page resides.
+@return descriptor page offset */
UNIV_INLINE
ulint
xdes_calc_descriptor_page(
/*======================*/
- /* out: descriptor page offset */
- ulint offset) /* in: page offset */
+ ulint zip_size, /*!< in: compressed page size in bytes;
+ 0 for uncompressed pages */
+ ulint offset) /*!< in: page offset */
{
-#if UNIV_PAGE_SIZE <= XDES_ARR_OFFSET \
- + (XDES_DESCRIBED_PER_PAGE / FSP_EXTENT_SIZE) * XDES_SIZE
-# error
-#endif
+#ifndef DOXYGEN /* Doxygen gets confused of these */
+# if UNIV_PAGE_SIZE <= XDES_ARR_OFFSET \
+ + (UNIV_PAGE_SIZE / FSP_EXTENT_SIZE) * XDES_SIZE
+# error
+# endif
+# if PAGE_ZIP_MIN_SIZE <= XDES_ARR_OFFSET \
+ + (PAGE_ZIP_MIN_SIZE / FSP_EXTENT_SIZE) * XDES_SIZE
+# error
+# endif
+#endif /* !DOXYGEN */
+ ut_ad(ut_is_2pow(zip_size));
- return(ut_2pow_round(offset, XDES_DESCRIBED_PER_PAGE));
+ if (!zip_size) {
+ return(ut_2pow_round(offset, UNIV_PAGE_SIZE));
+ } else {
+ ut_ad(zip_size > XDES_ARR_OFFSET
+ + (zip_size / FSP_EXTENT_SIZE) * XDES_SIZE);
+ return(ut_2pow_round(offset, zip_size));
+ }
}
-/************************************************************************
-Calculates the descriptor index within a descriptor page. */
+/********************************************************************//**
+Calculates the descriptor index within a descriptor page.
+@return descriptor index */
UNIV_INLINE
ulint
xdes_calc_descriptor_index(
/*=======================*/
- /* out: descriptor index */
- ulint offset) /* in: page offset */
+ ulint zip_size, /*!< in: compressed page size in bytes;
+ 0 for uncompressed pages */
+ ulint offset) /*!< in: page offset */
{
- return(ut_2pow_remainder(offset, XDES_DESCRIBED_PER_PAGE)
- / FSP_EXTENT_SIZE);
+ ut_ad(ut_is_2pow(zip_size));
+
+ if (!zip_size) {
+ return(ut_2pow_remainder(offset, UNIV_PAGE_SIZE)
+ / FSP_EXTENT_SIZE);
+ } else {
+ return(ut_2pow_remainder(offset, zip_size) / FSP_EXTENT_SIZE);
+ }
}
-/************************************************************************
+/********************************************************************//**
Gets pointer to a the extent descriptor of a page. The page where the extent
descriptor resides is x-locked. If the page offset is equal to the free limit
of the space, adds new extents from above the free limit to the space free
list, if not free limit == space size. This adding is necessary to make the
-descriptor defined, as they are uninitialized above the free limit. */
+descriptor defined, as they are uninitialized above the free limit.
+@return pointer to the extent descriptor, NULL if the page does not
+exist in the space or if the offset exceeds the free limit */
UNIV_INLINE
xdes_t*
xdes_get_descriptor_with_space_hdr(
/*===============================*/
- /* out: pointer to the extent descriptor,
- NULL if the page does not exist in the
- space or if offset > free limit */
- fsp_header_t* sp_header,/* in: space header, x-latched */
- ulint space, /* in: space id */
- ulint offset, /* in: page offset;
+ fsp_header_t* sp_header,/*!< in: space header, x-latched */
+ ulint space, /*!< in: space id */
+ ulint offset, /*!< in: page offset;
if equal to the free limit,
we try to add new extents to
the space free list */
- mtr_t* mtr) /* in: mtr handle */
+ mtr_t* mtr) /*!< in: mtr handle */
{
ulint limit;
ulint size;
+ ulint zip_size;
ulint descr_page_no;
page_t* descr_page;
ut_ad(mtr);
- ut_ad(mtr_memo_contains(mtr, fil_space_get_latch(space),
+ ut_ad(mtr_memo_contains(mtr, fil_space_get_latch(space, NULL),
MTR_MEMO_X_LOCK));
+ ut_ad(mtr_memo_contains_page(mtr, sp_header, MTR_MEMO_PAGE_S_FIX)
+ || mtr_memo_contains_page(mtr, sp_header, MTR_MEMO_PAGE_X_FIX));
+ ut_ad(page_offset(sp_header) == FSP_HEADER_OFFSET);
/* Read free limit and space size */
- limit = mtr_read_ulint(sp_header + FSP_FREE_LIMIT, MLOG_4BYTES, mtr);
- size = mtr_read_ulint(sp_header + FSP_SIZE, MLOG_4BYTES, mtr);
+ limit = mach_read_from_4(sp_header + FSP_FREE_LIMIT);
+ size = mach_read_from_4(sp_header + FSP_SIZE);
+ zip_size = dict_table_flags_to_zip_size(
+ mach_read_from_4(sp_header + FSP_SPACE_FLAGS));
/* If offset is >= size or > limit, return NULL */
@@ -679,174 +741,181 @@ xdes_get_descriptor_with_space_hdr(
fsp_fill_free_list(FALSE, space, sp_header, mtr);
}
- descr_page_no = xdes_calc_descriptor_page(offset);
+ descr_page_no = xdes_calc_descriptor_page(zip_size, offset);
if (descr_page_no == 0) {
/* It is on the space header page */
- descr_page = buf_frame_align(sp_header);
+ descr_page = page_align(sp_header);
} else {
- descr_page = buf_page_get(space, descr_page_no, RW_X_LATCH,
- mtr);
-#ifdef UNIV_SYNC_DEBUG
- buf_page_dbg_add_level(descr_page, SYNC_FSP_PAGE);
-#endif /* UNIV_SYNC_DEBUG */
+ buf_block_t* block;
+
+ block = buf_page_get(space, zip_size, descr_page_no,
+ RW_X_LATCH, mtr);
+ buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
+
+ descr_page = buf_block_get_frame(block);
}
return(descr_page + XDES_ARR_OFFSET
- + XDES_SIZE * xdes_calc_descriptor_index(offset));
+ + XDES_SIZE * xdes_calc_descriptor_index(zip_size, offset));
}
-/************************************************************************
+/********************************************************************//**
Gets pointer to a the extent descriptor of a page. The page where the
extent descriptor resides is x-locked. If the page offset is equal to
the free limit of the space, adds new extents from above the free limit
to the space free list, if not free limit == space size. This adding
is necessary to make the descriptor defined, as they are uninitialized
-above the free limit. */
+above the free limit.
+@return pointer to the extent descriptor, NULL if the page does not
+exist in the space or if the offset exceeds the free limit */
static
xdes_t*
xdes_get_descriptor(
/*================*/
- /* out: pointer to the extent descriptor, NULL if the
- page does not exist in the space or if offset > free
- limit */
- ulint space, /* in: space id */
- ulint offset, /* in: page offset; if equal to the free limit,
+ ulint space, /*!< in: space id */
+ ulint zip_size,/*!< in: compressed page size in bytes
+ or 0 for uncompressed pages */
+ ulint offset, /*!< in: page offset; if equal to the free limit,
we try to add new extents to the space free list */
- mtr_t* mtr) /* in: mtr handle */
+ mtr_t* mtr) /*!< in: mtr handle */
{
+ buf_block_t* block;
fsp_header_t* sp_header;
- sp_header = FSP_HEADER_OFFSET
- + buf_page_get(space, 0, RW_X_LATCH, mtr);
-#ifdef UNIV_SYNC_DEBUG
- buf_page_dbg_add_level(sp_header, SYNC_FSP_PAGE);
-#endif /* UNIV_SYNC_DEBUG */
+ block = buf_page_get(space, zip_size, 0, RW_X_LATCH, mtr);
+ buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
+
+ sp_header = FSP_HEADER_OFFSET + buf_block_get_frame(block);
return(xdes_get_descriptor_with_space_hdr(sp_header, space, offset,
mtr));
}
-/************************************************************************
+/********************************************************************//**
Gets pointer to a the extent descriptor if the file address
of the descriptor list node is known. The page where the
-extent descriptor resides is x-locked. */
+extent descriptor resides is x-locked.
+@return pointer to the extent descriptor */
UNIV_INLINE
xdes_t*
xdes_lst_get_descriptor(
/*====================*/
- /* out: pointer to the extent descriptor */
- ulint space, /* in: space id */
- fil_addr_t lst_node,/* in: file address of the list node
+ ulint space, /*!< in: space id */
+ ulint zip_size,/*!< in: compressed page size in bytes
+ or 0 for uncompressed pages */
+ fil_addr_t lst_node,/*!< in: file address of the list node
contained in the descriptor */
- mtr_t* mtr) /* in: mtr handle */
+ mtr_t* mtr) /*!< in: mtr handle */
{
xdes_t* descr;
ut_ad(mtr);
- ut_ad(mtr_memo_contains(mtr, fil_space_get_latch(space),
+ ut_ad(mtr_memo_contains(mtr, fil_space_get_latch(space, NULL),
MTR_MEMO_X_LOCK));
- descr = fut_get_ptr(space, lst_node, RW_X_LATCH, mtr) - XDES_FLST_NODE;
+ descr = fut_get_ptr(space, zip_size, lst_node, RW_X_LATCH, mtr)
+ - XDES_FLST_NODE;
return(descr);
}
-/************************************************************************
-Gets pointer to the next descriptor in a descriptor list and x-locks its
-page. */
-UNIV_INLINE
-xdes_t*
-xdes_lst_get_next(
-/*==============*/
- xdes_t* descr, /* in: pointer to a descriptor */
- mtr_t* mtr) /* in: mtr handle */
-{
- ulint space;
-
- ut_ad(mtr && descr);
-
- space = buf_frame_get_space_id(descr);
-
- return(xdes_lst_get_descriptor(
- space,
- flst_get_next_addr(descr + XDES_FLST_NODE, mtr), mtr));
-}
-
-/************************************************************************
-Returns page offset of the first page in extent described by a descriptor. */
+/********************************************************************//**
+Returns page offset of the first page in extent described by a descriptor.
+@return offset of the first page in extent */
UNIV_INLINE
ulint
xdes_get_offset(
/*============*/
- /* out: offset of the first page in extent */
- xdes_t* descr) /* in: extent descriptor */
+ xdes_t* descr) /*!< in: extent descriptor */
{
ut_ad(descr);
- return(buf_frame_get_page_no(descr)
- + ((descr - buf_frame_align(descr) - XDES_ARR_OFFSET)
- / XDES_SIZE)
+ return(page_get_page_no(page_align(descr))
+ + ((page_offset(descr) - XDES_ARR_OFFSET) / XDES_SIZE)
* FSP_EXTENT_SIZE);
}
+#endif /* !UNIV_HOTBACKUP */
-/***************************************************************
+/***********************************************************//**
Inits a file page whose prior contents should be ignored. */
static
void
fsp_init_file_page_low(
/*===================*/
- byte* ptr) /* in: pointer to a page */
+ buf_block_t* block) /*!< in: pointer to a page */
{
- page_t* page;
- page = buf_frame_align(ptr);
+ page_t* page = buf_block_get_frame(block);
+ page_zip_des_t* page_zip= buf_block_get_page_zip(block);
- buf_block_align(page)->check_index_page_at_flush = FALSE;
+#ifndef UNIV_HOTBACKUP
+ block->check_index_page_at_flush = FALSE;
+#endif /* !UNIV_HOTBACKUP */
+
+ if (UNIV_LIKELY_NULL(page_zip)) {
+ memset(page, 0, UNIV_PAGE_SIZE);
+ memset(page_zip->data, 0, page_zip_get_size(page_zip));
+ mach_write_to_4(page + FIL_PAGE_OFFSET,
+ buf_block_get_page_no(block));
+ mach_write_to_4(page
+ + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID,
+ buf_block_get_space(block));
+ memcpy(page_zip->data + FIL_PAGE_OFFSET,
+ page + FIL_PAGE_OFFSET, 4);
+ memcpy(page_zip->data + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID,
+ page + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID, 4);
+ return;
+ }
#ifdef UNIV_BASIC_LOG_DEBUG
memset(page, 0xff, UNIV_PAGE_SIZE);
#endif
- mach_write_to_8(page + UNIV_PAGE_SIZE - FIL_PAGE_END_LSN_OLD_CHKSUM,
- ut_dulint_zero);
- mach_write_to_8(page + FIL_PAGE_LSN, ut_dulint_zero);
+ mach_write_to_4(page + FIL_PAGE_OFFSET, buf_block_get_page_no(block));
+ memset(page + FIL_PAGE_LSN, 0, 8);
+ mach_write_to_4(page + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID,
+ buf_block_get_space(block));
+ memset(page + UNIV_PAGE_SIZE - FIL_PAGE_END_LSN_OLD_CHKSUM, 0, 8);
}
-/***************************************************************
+#ifndef UNIV_HOTBACKUP
+/***********************************************************//**
Inits a file page whose prior contents should be ignored. */
static
void
fsp_init_file_page(
/*===============*/
- page_t* page, /* in: page */
- mtr_t* mtr) /* in: mtr */
+ buf_block_t* block, /*!< in: pointer to a page */
+ mtr_t* mtr) /*!< in: mtr */
{
- fsp_init_file_page_low(page);
+ fsp_init_file_page_low(block);
- mlog_write_initial_log_record(page, MLOG_INIT_FILE_PAGE, mtr);
+ mlog_write_initial_log_record(buf_block_get_frame(block),
+ MLOG_INIT_FILE_PAGE, mtr);
}
+#endif /* !UNIV_HOTBACKUP */
-/***************************************************************
-Parses a redo log record of a file page init. */
-
+/***********************************************************//**
+Parses a redo log record of a file page init.
+@return end of log record or NULL */
+UNIV_INTERN
byte*
fsp_parse_init_file_page(
/*=====================*/
- /* out: end of log record or NULL */
- byte* ptr, /* in: buffer */
- byte* end_ptr __attribute__((unused)), /* in: buffer end */
- page_t* page) /* in: page or NULL */
+ byte* ptr, /*!< in: buffer */
+ byte* end_ptr __attribute__((unused)), /*!< in: buffer end */
+ buf_block_t* block) /*!< in: block or NULL */
{
ut_ad(ptr && end_ptr);
- if (page) {
- fsp_init_file_page_low(page);
+ if (block) {
+ fsp_init_file_page_low(block);
}
return(ptr);
}
-/**************************************************************************
+/**********************************************************************//**
Initializes the fsp system. */
-
+UNIV_INTERN
void
fsp_init(void)
/*==========*/
@@ -854,46 +923,62 @@ fsp_init(void)
/* Does nothing at the moment */
}
-/**************************************************************************
-Writes the space id to a tablespace header. This function is used past the
-buffer pool when we in fil0fil.c create a new single-table tablespace. */
-
+/**********************************************************************//**
+Writes the space id and compressed page size to a tablespace header.
+This function is used past the buffer pool when we in fil0fil.c create
+a new single-table tablespace. */
+UNIV_INTERN
void
-fsp_header_write_space_id(
-/*======================*/
- page_t* page, /* in: first page in the space */
- ulint space_id) /* in: space id */
+fsp_header_init_fields(
+/*===================*/
+ page_t* page, /*!< in/out: first page in the space */
+ ulint space_id, /*!< in: space id */
+ ulint flags) /*!< in: tablespace flags (FSP_SPACE_FLAGS):
+ 0, or table->flags if newer than COMPACT */
{
- mach_write_to_4(page + FSP_HEADER_OFFSET + FSP_SPACE_ID, space_id);
+ /* The tablespace flags (FSP_SPACE_FLAGS) should be 0 for
+ ROW_FORMAT=COMPACT (table->flags == DICT_TF_COMPACT) and
+ ROW_FORMAT=REDUNDANT (table->flags == 0). For any other
+ format, the tablespace flags should equal table->flags. */
+ ut_a(flags != DICT_TF_COMPACT);
+
+ mach_write_to_4(FSP_HEADER_OFFSET + FSP_SPACE_ID + page,
+ space_id);
+ mach_write_to_4(FSP_HEADER_OFFSET + FSP_SPACE_FLAGS + page,
+ flags);
}
-/**************************************************************************
+#ifndef UNIV_HOTBACKUP
+/**********************************************************************//**
Initializes the space header of a new created space and creates also the
insert buffer tree root if space == 0. */
-
+UNIV_INTERN
void
fsp_header_init(
/*============*/
- ulint space, /* in: space id */
- ulint size, /* in: current size in blocks */
- mtr_t* mtr) /* in: mini-transaction handle */
+ ulint space, /*!< in: space id */
+ ulint size, /*!< in: current size in blocks */
+ mtr_t* mtr) /*!< in: mini-transaction handle */
{
fsp_header_t* header;
+ buf_block_t* block;
page_t* page;
+ ulint flags;
+ ulint zip_size;
ut_ad(mtr);
- mtr_x_lock(fil_space_get_latch(space), mtr);
+ mtr_x_lock(fil_space_get_latch(space, &flags), mtr);
- page = buf_page_create(space, 0, mtr);
- buf_page_get(space, 0, RW_X_LATCH, mtr);
-#ifdef UNIV_SYNC_DEBUG
- buf_page_dbg_add_level(page, SYNC_FSP_PAGE);
-#endif /* UNIV_SYNC_DEBUG */
+ zip_size = dict_table_flags_to_zip_size(flags);
+ block = buf_page_create(space, 0, zip_size, mtr);
+ buf_page_get(space, zip_size, 0, RW_X_LATCH, mtr);
+ buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
/* The prior contents of the file page should be ignored */
- fsp_init_file_page(page, mtr);
+ fsp_init_file_page(block, mtr);
+ page = buf_block_get_frame(block);
mlog_write_ulint(page + FIL_PAGE_TYPE, FIL_PAGE_TYPE_FSP_HDR,
MLOG_2BYTES, mtr);
@@ -905,7 +990,8 @@ fsp_header_init(
mlog_write_ulint(header + FSP_SIZE, size, MLOG_4BYTES, mtr);
mlog_write_ulint(header + FSP_FREE_LIMIT, 0, MLOG_4BYTES, mtr);
- mlog_write_ulint(header + FSP_LOWEST_NO_WRITE, 0, MLOG_4BYTES, mtr);
+ mlog_write_ulint(header + FSP_SPACE_FLAGS, flags,
+ MLOG_4BYTES, mtr);
mlog_write_ulint(header + FSP_FRAG_N_USED, 0, MLOG_4BYTES, mtr);
flst_init(header + FSP_FREE, mtr);
@@ -917,21 +1003,23 @@ fsp_header_init(
mlog_write_dulint(header + FSP_SEG_ID, ut_dulint_create(0, 1), mtr);
if (space == 0) {
fsp_fill_free_list(FALSE, space, header, mtr);
- btr_create(DICT_CLUSTERED | DICT_UNIVERSAL | DICT_IBUF, space,
- ut_dulint_add(DICT_IBUF_ID_MIN, space), FALSE, mtr);
+ btr_create(DICT_CLUSTERED | DICT_UNIVERSAL | DICT_IBUF,
+ 0, 0, ut_dulint_add(DICT_IBUF_ID_MIN, space),
+ dict_ind_redundant, mtr);
} else {
fsp_fill_free_list(TRUE, space, header, mtr);
}
}
+#endif /* !UNIV_HOTBACKUP */
-/**************************************************************************
-Reads the space id from the first page of a tablespace. */
-
+/**********************************************************************//**
+Reads the space id from the first page of a tablespace.
+@return space id, ULINT UNDEFINED if error */
+UNIV_INTERN
ulint
fsp_header_get_space_id(
/*====================*/
- /* out: space id, ULINT UNDEFINED if error */
- page_t* page) /* in: first page of a tablespace */
+ const page_t* page) /*!< in: first page of a tablespace */
{
ulint fsp_id;
ulint id;
@@ -952,24 +1040,56 @@ fsp_header_get_space_id(
return(id);
}
-/**************************************************************************
-Increases the space size field of a space. */
+/**********************************************************************//**
+Reads the space flags from the first page of a tablespace.
+@return flags */
+UNIV_INTERN
+ulint
+fsp_header_get_flags(
+/*=================*/
+ const page_t* page) /*!< in: first page of a tablespace */
+{
+ ut_ad(!page_offset(page));
+ return(mach_read_from_4(FSP_HEADER_OFFSET + FSP_SPACE_FLAGS + page));
+}
+
+/**********************************************************************//**
+Reads the compressed page size from the first page of a tablespace.
+@return compressed page size in bytes, or 0 if uncompressed */
+UNIV_INTERN
+ulint
+fsp_header_get_zip_size(
+/*====================*/
+ const page_t* page) /*!< in: first page of a tablespace */
+{
+ ulint flags = fsp_header_get_flags(page);
+
+ return(dict_table_flags_to_zip_size(flags));
+}
+
+#ifndef UNIV_HOTBACKUP
+/**********************************************************************//**
+Increases the space size field of a space. */
+UNIV_INTERN
void
fsp_header_inc_size(
/*================*/
- ulint space, /* in: space id */
- ulint size_inc,/* in: size increment in pages */
- mtr_t* mtr) /* in: mini-transaction handle */
+ ulint space, /*!< in: space id */
+ ulint size_inc,/*!< in: size increment in pages */
+ mtr_t* mtr) /*!< in: mini-transaction handle */
{
fsp_header_t* header;
ulint size;
+ ulint flags;
ut_ad(mtr);
- mtr_x_lock(fil_space_get_latch(space), mtr);
+ mtr_x_lock(fil_space_get_latch(space, &flags), mtr);
- header = fsp_get_space_header(space, mtr);
+ header = fsp_get_space_header(space,
+ dict_table_flags_to_zip_size(flags),
+ mtr);
size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, mtr);
@@ -977,33 +1097,30 @@ fsp_header_inc_size(
mtr);
}
-/**************************************************************************
-Gets the current free limit of a tablespace. The free limit means the
-place of the first page which has never been put to the the free list
-for allocation. The space above that address is initialized to zero.
-Sets also the global variable log_fsp_current_free_limit. */
-
+/**********************************************************************//**
+Gets the current free limit of the system tablespace. The free limit
+means the place of the first page which has never been put to the the
+free list for allocation. The space above that address is initialized
+to zero. Sets also the global variable log_fsp_current_free_limit.
+@return free limit in megabytes */
+UNIV_INTERN
ulint
-fsp_header_get_free_limit(
-/*======================*/
- /* out: free limit in megabytes */
- ulint space) /* in: space id, must be 0 */
+fsp_header_get_free_limit(void)
+/*===========================*/
{
fsp_header_t* header;
ulint limit;
mtr_t mtr;
- ut_a(space == 0); /* We have only one log_fsp_current_... variable */
-
mtr_start(&mtr);
- mtr_x_lock(fil_space_get_latch(space), &mtr);
+ mtr_x_lock(fil_space_get_latch(0, NULL), &mtr);
- header = fsp_get_space_header(space, &mtr);
+ header = fsp_get_space_header(0, 0, &mtr);
limit = mtr_read_ulint(header + FSP_FREE_LIMIT, MLOG_4BYTES, &mtr);
- limit = limit / ((1024 * 1024) / UNIV_PAGE_SIZE);
+ limit /= ((1024 * 1024) / UNIV_PAGE_SIZE);
log_fsp_current_free_limit_set_and_checkpoint(limit);
@@ -1012,28 +1129,26 @@ fsp_header_get_free_limit(
return(limit);
}
-/**************************************************************************
-Gets the size of the tablespace from the tablespace header. If we do not
-have an auto-extending data file, this should be equal to the size of the
-data files. If there is an auto-extending data file, this can be smaller. */
-
+/**********************************************************************//**
+Gets the size of the system tablespace from the tablespace header. If
+we do not have an auto-extending data file, this should be equal to
+the size of the data files. If there is an auto-extending data file,
+this can be smaller.
+@return size in pages */
+UNIV_INTERN
ulint
-fsp_header_get_tablespace_size(
-/*===========================*/
- /* out: size in pages */
- ulint space) /* in: space id, must be 0 */
+fsp_header_get_tablespace_size(void)
+/*================================*/
{
fsp_header_t* header;
ulint size;
mtr_t mtr;
- ut_a(space == 0); /* We have only one log_fsp_current_... variable */
-
mtr_start(&mtr);
- mtr_x_lock(fil_space_get_latch(space), &mtr);
+ mtr_x_lock(fil_space_get_latch(0, NULL), &mtr);
- header = fsp_get_space_header(space, &mtr);
+ header = fsp_get_space_header(0, 0, &mtr);
size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, &mtr);
@@ -1042,18 +1157,18 @@ fsp_header_get_tablespace_size(
return(size);
}
-/***************************************************************************
+/***********************************************************************//**
Tries to extend a single-table tablespace so that a page would fit in the
-data file. */
+data file.
+@return TRUE if success */
static
ibool
fsp_try_extend_data_file_with_pages(
/*================================*/
- /* out: TRUE if success */
- ulint space, /* in: space */
- ulint page_no, /* in: page number */
- fsp_header_t* header, /* in: space header */
- mtr_t* mtr) /* in: mtr */
+ ulint space, /*!< in: space */
+ ulint page_no, /*!< in: page number */
+ fsp_header_t* header, /*!< in: space header */
+ mtr_t* mtr) /*!< in: mtr */
{
ibool success;
ulint actual_size;
@@ -1075,23 +1190,24 @@ fsp_try_extend_data_file_with_pages(
return(success);
}
-/***************************************************************************
-Tries to extend the last data file of a tablespace if it is auto-extending. */
+/***********************************************************************//**
+Tries to extend the last data file of a tablespace if it is auto-extending.
+@return FALSE if not auto-extending */
static
ibool
fsp_try_extend_data_file(
/*=====================*/
- /* out: FALSE if not auto-extending */
- ulint* actual_increase,/* out: actual increase in pages, where
+ ulint* actual_increase,/*!< out: actual increase in pages, where
we measure the tablespace size from
what the header field says; it may be
the actual file size rounded down to
megabyte */
- ulint space, /* in: space */
- fsp_header_t* header, /* in: space header */
- mtr_t* mtr) /* in: mtr */
+ ulint space, /*!< in: space */
+ fsp_header_t* header, /*!< in: space header */
+ mtr_t* mtr) /*!< in: mtr */
{
ulint size;
+ ulint zip_size;
ulint new_size;
ulint old_size;
ulint size_increase;
@@ -1106,62 +1222,70 @@ fsp_try_extend_data_file(
}
size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, mtr);
+ zip_size = dict_table_flags_to_zip_size(
+ mach_read_from_4(header + FSP_SPACE_FLAGS));
old_size = size;
- if (space == 0 && srv_last_file_size_max != 0) {
- if (srv_last_file_size_max
- < srv_data_file_sizes[srv_n_data_files - 1]) {
-
- fprintf(stderr,
- "InnoDB: Error: Last data file size is %lu,"
- " max size allowed %lu\n",
- (ulong) srv_data_file_sizes[
- srv_n_data_files - 1],
- (ulong) srv_last_file_size_max);
- }
-
- size_increase = srv_last_file_size_max
- - srv_data_file_sizes[srv_n_data_files - 1];
- if (size_increase > SRV_AUTO_EXTEND_INCREMENT) {
- size_increase = SRV_AUTO_EXTEND_INCREMENT;
- }
- } else {
- if (space == 0) {
+ if (space == 0) {
+ if (!srv_last_file_size_max) {
size_increase = SRV_AUTO_EXTEND_INCREMENT;
} else {
- /* We extend single-table tablespaces first one extent
- at a time, but for bigger tablespaces more. It is not
- enough to extend always by one extent, because some
- extents are frag page extents. */
+ if (srv_last_file_size_max
+ < srv_data_file_sizes[srv_n_data_files - 1]) {
- if (size < FSP_EXTENT_SIZE) {
- /* Let us first extend the file to 64 pages */
- success = fsp_try_extend_data_file_with_pages(
- space, FSP_EXTENT_SIZE - 1,
- header, mtr);
- if (!success) {
- new_size = mtr_read_ulint(
- header + FSP_SIZE,
- MLOG_4BYTES, mtr);
-
- *actual_increase = new_size - old_size;
-
- return(FALSE);
- }
-
- size = FSP_EXTENT_SIZE;
+ fprintf(stderr,
+ "InnoDB: Error: Last data file size"
+ " is %lu, max size allowed %lu\n",
+ (ulong) srv_data_file_sizes[
+ srv_n_data_files - 1],
+ (ulong) srv_last_file_size_max);
}
- if (size < 32 * FSP_EXTENT_SIZE) {
- size_increase = FSP_EXTENT_SIZE;
- } else {
- /* Below in fsp_fill_free_list() we assume
- that we add at most FSP_FREE_ADD extents at
- a time */
- size_increase = FSP_FREE_ADD * FSP_EXTENT_SIZE;
+ size_increase = srv_last_file_size_max
+ - srv_data_file_sizes[srv_n_data_files - 1];
+ if (size_increase > SRV_AUTO_EXTEND_INCREMENT) {
+ size_increase = SRV_AUTO_EXTEND_INCREMENT;
}
}
+ } else {
+ /* We extend single-table tablespaces first one extent
+ at a time, but for bigger tablespaces more. It is not
+ enough to extend always by one extent, because some
+ extents are frag page extents. */
+ ulint extent_size; /*!< one megabyte, in pages */
+
+ if (!zip_size) {
+ extent_size = FSP_EXTENT_SIZE;
+ } else {
+ extent_size = FSP_EXTENT_SIZE
+ * UNIV_PAGE_SIZE / zip_size;
+ }
+
+ if (size < extent_size) {
+ /* Let us first extend the file to extent_size */
+ success = fsp_try_extend_data_file_with_pages(
+ space, extent_size - 1, header, mtr);
+ if (!success) {
+ new_size = mtr_read_ulint(header + FSP_SIZE,
+ MLOG_4BYTES, mtr);
+
+ *actual_increase = new_size - old_size;
+
+ return(FALSE);
+ }
+
+ size = extent_size;
+ }
+
+ if (size < 32 * extent_size) {
+ size_increase = extent_size;
+ } else {
+ /* Below in fsp_fill_free_list() we assume
+ that we add at most FSP_FREE_ADD extents at
+ a time */
+ size_increase = FSP_FREE_ADD * extent_size;
+ }
}
if (size_increase == 0) {
@@ -1174,18 +1298,21 @@ fsp_try_extend_data_file(
/* We ignore any fragments of a full megabyte when storing the size
to the space header */
- mlog_write_ulint(header + FSP_SIZE,
- ut_calc_align_down(actual_size,
- (1024 * 1024) / UNIV_PAGE_SIZE),
- MLOG_4BYTES, mtr);
- new_size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, mtr);
+ if (!zip_size) {
+ new_size = ut_calc_align_down(actual_size,
+ (1024 * 1024) / UNIV_PAGE_SIZE);
+ } else {
+ new_size = ut_calc_align_down(actual_size,
+ (1024 * 1024) / zip_size);
+ }
+ mlog_write_ulint(header + FSP_SIZE, new_size, MLOG_4BYTES, mtr);
*actual_increase = new_size - old_size;
return(TRUE);
}
-/**************************************************************************
+/**********************************************************************//**
Puts new extents to the free list if there are free extents above the free
limit. If an extent happens to contain an extent descriptor page, the extent
is put to the FSP_FREE_FRAG list with the page marked as used. */
@@ -1193,32 +1320,38 @@ static
void
fsp_fill_free_list(
/*===============*/
- ibool init_space, /* in: TRUE if this is a single-table
+ ibool init_space, /*!< in: TRUE if this is a single-table
tablespace and we are only initing
the tablespace's first extent
descriptor page and ibuf bitmap page;
then we do not allocate more extents */
- ulint space, /* in: space */
- fsp_header_t* header, /* in: space header */
- mtr_t* mtr) /* in: mtr */
+ ulint space, /*!< in: space */
+ fsp_header_t* header, /*!< in: space header */
+ mtr_t* mtr) /*!< in: mtr */
{
ulint limit;
ulint size;
+ ulint zip_size;
xdes_t* descr;
ulint count = 0;
ulint frag_n_used;
- page_t* descr_page;
- page_t* ibuf_page;
ulint actual_increase;
ulint i;
mtr_t ibuf_mtr;
ut_ad(header && mtr);
+ ut_ad(page_offset(header) == FSP_HEADER_OFFSET);
/* Check if we can fill free list from above the free list limit */
size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, mtr);
limit = mtr_read_ulint(header + FSP_FREE_LIMIT, MLOG_4BYTES, mtr);
+ zip_size = dict_table_flags_to_zip_size(
+ mach_read_from_4(FSP_SPACE_FLAGS + header));
+ ut_a(ut_is_2pow(zip_size));
+ ut_a(zip_size <= UNIV_PAGE_SIZE);
+ ut_a(!zip_size || zip_size >= PAGE_ZIP_MIN_SIZE);
+
if (space == 0 && srv_auto_extend_last_data_file
&& size < limit + FSP_EXTENT_SIZE * FSP_FREE_ADD) {
@@ -1240,32 +1373,44 @@ fsp_fill_free_list(
while ((init_space && i < 1)
|| ((i + FSP_EXTENT_SIZE <= size) && (count < FSP_FREE_ADD))) {
+ ibool init_xdes;
+ if (zip_size) {
+ init_xdes = ut_2pow_remainder(i, zip_size) == 0;
+ } else {
+ init_xdes = ut_2pow_remainder(i, UNIV_PAGE_SIZE) == 0;
+ }
+
mlog_write_ulint(header + FSP_FREE_LIMIT, i + FSP_EXTENT_SIZE,
MLOG_4BYTES, mtr);
/* Update the free limit info in the log system and make
a checkpoint */
if (space == 0) {
+ ut_a(!zip_size);
log_fsp_current_free_limit_set_and_checkpoint(
(i + FSP_EXTENT_SIZE)
/ ((1024 * 1024) / UNIV_PAGE_SIZE));
}
- if (0 == i % XDES_DESCRIBED_PER_PAGE) {
+ if (UNIV_UNLIKELY(init_xdes)) {
+
+ buf_block_t* block;
/* We are going to initialize a new descriptor page
and a new ibuf bitmap page: the prior contents of the
pages should be ignored. */
if (i > 0) {
- descr_page = buf_page_create(space, i, mtr);
- buf_page_get(space, i, RW_X_LATCH, mtr);
-#ifdef UNIV_SYNC_DEBUG
- buf_page_dbg_add_level(descr_page,
- SYNC_FSP_PAGE);
-#endif /* UNIV_SYNC_DEBUG */
- fsp_init_file_page(descr_page, mtr);
- mlog_write_ulint(descr_page + FIL_PAGE_TYPE,
+ block = buf_page_create(
+ space, i, zip_size, mtr);
+ buf_page_get(space, zip_size, i,
+ RW_X_LATCH, mtr);
+ buf_block_dbg_add_level(block,
+ SYNC_FSP_PAGE);
+
+ fsp_init_file_page(block, mtr);
+ mlog_write_ulint(buf_block_get_frame(block)
+ + FIL_PAGE_TYPE,
FIL_PAGE_TYPE_XDES,
MLOG_2BYTES, mtr);
}
@@ -1277,17 +1422,17 @@ fsp_fill_free_list(
mtr_start(&ibuf_mtr);
- ibuf_page = buf_page_create(space,
+ block = buf_page_create(space,
i + FSP_IBUF_BITMAP_OFFSET,
- &ibuf_mtr);
- buf_page_get(space, i + FSP_IBUF_BITMAP_OFFSET,
+ zip_size, &ibuf_mtr);
+ buf_page_get(space, zip_size,
+ i + FSP_IBUF_BITMAP_OFFSET,
RW_X_LATCH, &ibuf_mtr);
-#ifdef UNIV_SYNC_DEBUG
- buf_page_dbg_add_level(ibuf_page, SYNC_FSP_PAGE);
-#endif /* UNIV_SYNC_DEBUG */
- fsp_init_file_page(ibuf_page, &ibuf_mtr);
+ buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
- ibuf_bitmap_page_init(ibuf_page, &ibuf_mtr);
+ fsp_init_file_page(block, &ibuf_mtr);
+
+ ibuf_bitmap_page_init(block, &ibuf_mtr);
mtr_commit(&ibuf_mtr);
}
@@ -1296,11 +1441,14 @@ fsp_fill_free_list(
mtr);
xdes_init(descr, mtr);
-#if XDES_DESCRIBED_PER_PAGE % FSP_EXTENT_SIZE
-# error "XDES_DESCRIBED_PER_PAGE % FSP_EXTENT_SIZE != 0"
+#if UNIV_PAGE_SIZE % FSP_EXTENT_SIZE
+# error "UNIV_PAGE_SIZE % FSP_EXTENT_SIZE != 0"
+#endif
+#if PAGE_ZIP_MIN_SIZE % FSP_EXTENT_SIZE
+# error "PAGE_ZIP_MIN_SIZE % FSP_EXTENT_SIZE != 0"
#endif
- if (0 == i % XDES_DESCRIBED_PER_PAGE) {
+ if (UNIV_UNLIKELY(init_xdes)) {
/* The first page in the extent is a descriptor page
and the second is an ibuf bitmap page: mark them
@@ -1327,19 +1475,20 @@ fsp_fill_free_list(
}
}
-/**************************************************************************
-Allocates a new free extent. */
+/**********************************************************************//**
+Allocates a new free extent.
+@return extent descriptor, NULL if cannot be allocated */
static
xdes_t*
fsp_alloc_free_extent(
/*==================*/
- /* out: extent descriptor, NULL if cannot be
- allocated */
- ulint space, /* in: space id */
- ulint hint, /* in: hint of which extent would be desirable: any
+ ulint space, /*!< in: space id */
+ ulint zip_size,/*!< in: compressed page size in bytes
+ or 0 for uncompressed pages */
+ ulint hint, /*!< in: hint of which extent would be desirable: any
page offset in the extent goes; the hint must not
be > FSP_FREE_LIMIT */
- mtr_t* mtr) /* in: mtr */
+ mtr_t* mtr) /*!< in: mtr */
{
fsp_header_t* header;
fil_addr_t first;
@@ -1347,7 +1496,7 @@ fsp_alloc_free_extent(
ut_ad(mtr);
- header = fsp_get_space_header(space, mtr);
+ header = fsp_get_space_header(space, zip_size, mtr);
descr = xdes_get_descriptor_with_space_hdr(header, space, hint, mtr);
@@ -1368,7 +1517,7 @@ fsp_alloc_free_extent(
return(NULL); /* No free extents left */
}
- descr = xdes_lst_get_descriptor(space, first, mtr);
+ descr = xdes_lst_get_descriptor(space, zip_size, first, mtr);
}
flst_remove(header + FSP_FREE, descr + XDES_FLST_NODE, mtr);
@@ -1376,22 +1525,23 @@ fsp_alloc_free_extent(
return(descr);
}
-/**************************************************************************
-Allocates a single free page from a space. The page is marked as used. */
+/**********************************************************************//**
+Allocates a single free page from a space. The page is marked as used.
+@return the page offset, FIL_NULL if no page could be allocated */
static
ulint
fsp_alloc_free_page(
/*================*/
- /* out: the page offset, FIL_NULL if no page could
- be allocated */
- ulint space, /* in: space id */
- ulint hint, /* in: hint of which page would be desirable */
- mtr_t* mtr) /* in: mtr handle */
+ ulint space, /*!< in: space id */
+ ulint zip_size,/*!< in: compressed page size in bytes
+ or 0 for uncompressed pages */
+ ulint hint, /*!< in: hint of which page would be desirable */
+ mtr_t* mtr) /*!< in: mtr handle */
{
fsp_header_t* header;
fil_addr_t first;
xdes_t* descr;
- page_t* page;
+ buf_block_t* block;
ulint free;
ulint frag_n_used;
ulint page_no;
@@ -1400,7 +1550,7 @@ fsp_alloc_free_page(
ut_ad(mtr);
- header = fsp_get_space_header(space, mtr);
+ header = fsp_get_space_header(space, zip_size, mtr);
/* Get the hinted descriptor */
descr = xdes_get_descriptor_with_space_hdr(header, space, hint, mtr);
@@ -1419,7 +1569,8 @@ fsp_alloc_free_page(
FREE_FRAG list. But we will allocate our page from the
the free extent anyway. */
- descr = fsp_alloc_free_extent(space, hint, mtr);
+ descr = fsp_alloc_free_extent(space, zip_size,
+ hint, mtr);
if (descr == NULL) {
/* No free space left */
@@ -1431,7 +1582,8 @@ fsp_alloc_free_page(
flst_add_last(header + FSP_FREE_FRAG,
descr + XDES_FLST_NODE, mtr);
} else {
- descr = xdes_lst_get_descriptor(space, first, mtr);
+ descr = xdes_lst_get_descriptor(space, zip_size,
+ first, mtr);
}
/* Reset the hint */
@@ -1446,6 +1598,7 @@ fsp_alloc_free_page(
if (free == ULINT_UNDEFINED) {
ut_print_buf(stderr, ((byte*)descr) - 500, 1000);
+ putc('\n', stderr);
ut_error;
}
@@ -1502,28 +1655,28 @@ fsp_alloc_free_page(
be obtained immediately with buf_page_get without need for a disk
read. */
- buf_page_create(space, page_no, mtr);
+ buf_page_create(space, page_no, zip_size, mtr);
- page = buf_page_get(space, page_no, RW_X_LATCH, mtr);
-#ifdef UNIV_SYNC_DEBUG
- buf_page_dbg_add_level(page, SYNC_FSP_PAGE);
-#endif /* UNIV_SYNC_DEBUG */
+ block = buf_page_get(space, zip_size, page_no, RW_X_LATCH, mtr);
+ buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
/* Prior contents of the page should be ignored */
- fsp_init_file_page(page, mtr);
+ fsp_init_file_page(block, mtr);
return(page_no);
}
-/**************************************************************************
+/**********************************************************************//**
Frees a single page of a space. The page is marked as free and clean. */
static
void
fsp_free_page(
/*==========*/
- ulint space, /* in: space id */
- ulint page, /* in: page offset */
- mtr_t* mtr) /* in: mtr handle */
+ ulint space, /*!< in: space id */
+ ulint zip_size,/*!< in: compressed page size in bytes
+ or 0 for uncompressed pages */
+ ulint page, /*!< in: page offset */
+ mtr_t* mtr) /*!< in: mtr handle */
{
fsp_header_t* header;
xdes_t* descr;
@@ -1534,7 +1687,7 @@ fsp_free_page(
/* fprintf(stderr, "Freeing page %lu in space %lu\n", page, space); */
- header = fsp_get_space_header(space, mtr);
+ header = fsp_get_space_header(space, zip_size, mtr);
descr = xdes_get_descriptor_with_space_hdr(header, space, page, mtr);
@@ -1599,32 +1752,35 @@ fsp_free_page(
/* The extent has become free: move it to another list */
flst_remove(header + FSP_FREE_FRAG, descr + XDES_FLST_NODE,
mtr);
- fsp_free_extent(space, page, mtr);
+ fsp_free_extent(space, zip_size, page, mtr);
}
}
-/**************************************************************************
+/**********************************************************************//**
Returns an extent to the free list of a space. */
static
void
fsp_free_extent(
/*============*/
- ulint space, /* in: space id */
- ulint page, /* in: page offset in the extent */
- mtr_t* mtr) /* in: mtr */
+ ulint space, /*!< in: space id */
+ ulint zip_size,/*!< in: compressed page size in bytes
+ or 0 for uncompressed pages */
+ ulint page, /*!< in: page offset in the extent */
+ mtr_t* mtr) /*!< in: mtr */
{
fsp_header_t* header;
xdes_t* descr;
ut_ad(mtr);
- header = fsp_get_space_header(space, mtr);
+ header = fsp_get_space_header(space, zip_size, mtr);
descr = xdes_get_descriptor_with_space_hdr(header, space, page, mtr);
if (xdes_get_state(descr, mtr) == XDES_FREE) {
ut_print_buf(stderr, (byte*)descr - 500, 1000);
+ putc('\n', stderr);
ut_error;
}
@@ -1634,44 +1790,46 @@ fsp_free_extent(
flst_add_last(header + FSP_FREE, descr + XDES_FLST_NODE, mtr);
}
-/**************************************************************************
-Returns the nth inode slot on an inode page. */
+/**********************************************************************//**
+Returns the nth inode slot on an inode page.
+@return segment inode */
UNIV_INLINE
fseg_inode_t*
fsp_seg_inode_page_get_nth_inode(
/*=============================*/
- /* out: segment inode */
- page_t* page, /* in: segment inode page */
- ulint i, /* in: inode index on page */
- mtr_t* mtr __attribute__((unused))) /* in: mini-transaction handle */
+ page_t* page, /*!< in: segment inode page */
+ ulint i, /*!< in: inode index on page */
+ ulint zip_size __attribute__((unused)),
+ /*!< in: compressed page size, or 0 */
+ mtr_t* mtr __attribute__((unused)))
+ /*!< in: mini-transaction handle */
{
- ut_ad(i < FSP_SEG_INODES_PER_PAGE);
- ut_ad(mtr_memo_contains(mtr, buf_block_align(page),
- MTR_MEMO_PAGE_X_FIX));
+ ut_ad(i < FSP_SEG_INODES_PER_PAGE(zip_size));
+ ut_ad(mtr_memo_contains_page(mtr, page, MTR_MEMO_PAGE_X_FIX));
return(page + FSEG_ARR_OFFSET + FSEG_INODE_SIZE * i);
}
-/**************************************************************************
-Looks for a used segment inode on a segment inode page. */
+/**********************************************************************//**
+Looks for a used segment inode on a segment inode page.
+@return segment inode index, or ULINT_UNDEFINED if not found */
static
ulint
fsp_seg_inode_page_find_used(
/*=========================*/
- /* out: segment inode index, or ULINT_UNDEFINED
- if not found */
- page_t* page, /* in: segment inode page */
- mtr_t* mtr) /* in: mini-transaction handle */
+ page_t* page, /*!< in: segment inode page */
+ ulint zip_size,/*!< in: compressed page size, or 0 */
+ mtr_t* mtr) /*!< in: mini-transaction handle */
{
ulint i;
fseg_inode_t* inode;
- for (i = 0; i < FSP_SEG_INODES_PER_PAGE; i++) {
+ for (i = 0; i < FSP_SEG_INODES_PER_PAGE(zip_size); i++) {
- inode = fsp_seg_inode_page_get_nth_inode(page, i, mtr);
+ inode = fsp_seg_inode_page_get_nth_inode(
+ page, i, zip_size, mtr);
- if (ut_dulint_cmp(mach_read_from_8(inode + FSEG_ID),
- ut_dulint_zero) != 0) {
+ if (!ut_dulint_is_zero(mach_read_from_8(inode + FSEG_ID))) {
/* This is used */
return(i);
@@ -1681,27 +1839,26 @@ fsp_seg_inode_page_find_used(
return(ULINT_UNDEFINED);
}
-/**************************************************************************
-Looks for an unused segment inode on a segment inode page. */
+/**********************************************************************//**
+Looks for an unused segment inode on a segment inode page.
+@return segment inode index, or ULINT_UNDEFINED if not found */
static
ulint
fsp_seg_inode_page_find_free(
/*=========================*/
- /* out: segment inode index, or ULINT_UNDEFINED
- if not found */
- page_t* page, /* in: segment inode page */
- ulint j, /* in: search forward starting from this index */
- mtr_t* mtr) /* in: mini-transaction handle */
+ page_t* page, /*!< in: segment inode page */
+ ulint i, /*!< in: search forward starting from this index */
+ ulint zip_size,/*!< in: compressed page size, or 0 */
+ mtr_t* mtr) /*!< in: mini-transaction handle */
{
- ulint i;
fseg_inode_t* inode;
- for (i = j; i < FSP_SEG_INODES_PER_PAGE; i++) {
+ for (; i < FSP_SEG_INODES_PER_PAGE(zip_size); i++) {
- inode = fsp_seg_inode_page_get_nth_inode(page, i, mtr);
+ inode = fsp_seg_inode_page_get_nth_inode(
+ page, i, zip_size, mtr);
- if (ut_dulint_cmp(mach_read_from_8(inode + FSEG_ID),
- ut_dulint_zero) == 0) {
+ if (ut_dulint_is_zero(mach_read_from_8(inode + FSEG_ID))) {
/* This is unused */
return(i);
@@ -1711,44 +1868,51 @@ fsp_seg_inode_page_find_free(
return(ULINT_UNDEFINED);
}
-/**************************************************************************
-Allocates a new file segment inode page. */
+/**********************************************************************//**
+Allocates a new file segment inode page.
+@return TRUE if could be allocated */
static
ibool
fsp_alloc_seg_inode_page(
/*=====================*/
- /* out: TRUE if could be allocated */
- fsp_header_t* space_header, /* in: space header */
- mtr_t* mtr) /* in: mini-transaction handle */
+ fsp_header_t* space_header, /*!< in: space header */
+ mtr_t* mtr) /*!< in: mini-transaction handle */
{
fseg_inode_t* inode;
+ buf_block_t* block;
page_t* page;
ulint page_no;
ulint space;
+ ulint zip_size;
ulint i;
- space = buf_frame_get_space_id(space_header);
+ ut_ad(page_offset(space_header) == FSP_HEADER_OFFSET);
- page_no = fsp_alloc_free_page(space, 0, mtr);
+ space = page_get_space_id(page_align(space_header));
+ zip_size = dict_table_flags_to_zip_size(
+ mach_read_from_4(FSP_SPACE_FLAGS + space_header));
+
+ page_no = fsp_alloc_free_page(space, zip_size, 0, mtr);
if (page_no == FIL_NULL) {
return(FALSE);
}
- page = buf_page_get(space, page_no, RW_X_LATCH, mtr);
+ block = buf_page_get(space, zip_size, page_no, RW_X_LATCH, mtr);
+ buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
- buf_block_align(page)->check_index_page_at_flush = FALSE;
+ block->check_index_page_at_flush = FALSE;
+
+ page = buf_block_get_frame(block);
mlog_write_ulint(page + FIL_PAGE_TYPE, FIL_PAGE_INODE,
MLOG_2BYTES, mtr);
-#ifdef UNIV_SYNC_DEBUG
- buf_page_dbg_add_level(page, SYNC_FSP_PAGE);
-#endif /* UNIV_SYNC_DEBUG */
- for (i = 0; i < FSP_SEG_INODES_PER_PAGE; i++) {
+ for (i = 0; i < FSP_SEG_INODES_PER_PAGE(zip_size); i++) {
- inode = fsp_seg_inode_page_get_nth_inode(page, i, mtr);
+ inode = fsp_seg_inode_page_get_nth_inode(page, i,
+ zip_size, mtr);
mlog_write_dulint(inode + FSEG_ID, ut_dulint_zero, mtr);
}
@@ -1758,23 +1922,26 @@ fsp_alloc_seg_inode_page(
return(TRUE);
}
-/**************************************************************************
-Allocates a new file segment inode. */
+/**********************************************************************//**
+Allocates a new file segment inode.
+@return segment inode, or NULL if not enough space */
static
fseg_inode_t*
fsp_alloc_seg_inode(
/*================*/
- /* out: segment inode, or NULL if
- not enough space */
- fsp_header_t* space_header, /* in: space header */
- mtr_t* mtr) /* in: mini-transaction handle */
+ fsp_header_t* space_header, /*!< in: space header */
+ mtr_t* mtr) /*!< in: mini-transaction handle */
{
ulint page_no;
+ buf_block_t* block;
page_t* page;
fseg_inode_t* inode;
ibool success;
+ ulint zip_size;
ulint n;
+ ut_ad(page_offset(space_header) == FSP_HEADER_OFFSET);
+
if (flst_get_len(space_header + FSP_SEG_INODES_FREE, mtr) == 0) {
/* Allocate a new segment inode page */
@@ -1788,20 +1955,22 @@ fsp_alloc_seg_inode(
page_no = flst_get_first(space_header + FSP_SEG_INODES_FREE, mtr).page;
- page = buf_page_get(buf_frame_get_space_id(space_header), page_no,
- RW_X_LATCH, mtr);
-#ifdef UNIV_SYNC_DEBUG
- buf_page_dbg_add_level(page, SYNC_FSP_PAGE);
-#endif /* UNIV_SYNC_DEBUG */
+ zip_size = dict_table_flags_to_zip_size(
+ mach_read_from_4(FSP_SPACE_FLAGS + space_header));
+ block = buf_page_get(page_get_space_id(page_align(space_header)),
+ zip_size, page_no, RW_X_LATCH, mtr);
+ buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
- n = fsp_seg_inode_page_find_free(page, 0, mtr);
+ page = buf_block_get_frame(block);
+
+ n = fsp_seg_inode_page_find_free(page, 0, zip_size, mtr);
ut_a(n != ULINT_UNDEFINED);
- inode = fsp_seg_inode_page_get_nth_inode(page, n, mtr);
+ inode = fsp_seg_inode_page_get_nth_inode(page, n, zip_size, mtr);
if (ULINT_UNDEFINED == fsp_seg_inode_page_find_free(page, n + 1,
- mtr)) {
+ zip_size, mtr)) {
/* There are no other unused headers left on the page: move it
to another list */
@@ -1815,26 +1984,29 @@ fsp_alloc_seg_inode(
return(inode);
}
-/**************************************************************************
+/**********************************************************************//**
Frees a file segment inode. */
static
void
fsp_free_seg_inode(
/*===============*/
- ulint space, /* in: space id */
- fseg_inode_t* inode, /* in: segment inode */
- mtr_t* mtr) /* in: mini-transaction handle */
+ ulint space, /*!< in: space id */
+ ulint zip_size,/*!< in: compressed page size in bytes
+ or 0 for uncompressed pages */
+ fseg_inode_t* inode, /*!< in: segment inode */
+ mtr_t* mtr) /*!< in: mini-transaction handle */
{
page_t* page;
fsp_header_t* space_header;
- page = buf_frame_align(inode);
+ page = page_align(inode);
- space_header = fsp_get_space_header(space, mtr);
+ space_header = fsp_get_space_header(space, zip_size, mtr);
ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE);
- if (ULINT_UNDEFINED == fsp_seg_inode_page_find_free(page, 0, mtr)) {
+ if (ULINT_UNDEFINED
+ == fsp_seg_inode_page_find_free(page, 0, zip_size, mtr)) {
/* Move the page to another list */
@@ -1848,90 +2020,91 @@ fsp_free_seg_inode(
mlog_write_dulint(inode + FSEG_ID, ut_dulint_zero, mtr);
mlog_write_ulint(inode + FSEG_MAGIC_N, 0, MLOG_4BYTES, mtr);
- if (ULINT_UNDEFINED == fsp_seg_inode_page_find_used(page, mtr)) {
+ if (ULINT_UNDEFINED
+ == fsp_seg_inode_page_find_used(page, zip_size, mtr)) {
/* There are no other used headers left on the page: free it */
flst_remove(space_header + FSP_SEG_INODES_FREE,
page + FSEG_INODE_PAGE_NODE, mtr);
- fsp_free_page(space, buf_frame_get_page_no(page), mtr);
+ fsp_free_page(space, zip_size, page_get_page_no(page), mtr);
}
}
-/**************************************************************************
-Returns the file segment inode, page x-latched. */
+/**********************************************************************//**
+Returns the file segment inode, page x-latched.
+@return segment inode, page x-latched */
static
fseg_inode_t*
fseg_inode_get(
/*===========*/
- /* out: segment inode, page x-latched */
- fseg_header_t* header, /* in: segment header */
- mtr_t* mtr) /* in: mtr handle */
+ fseg_header_t* header, /*!< in: segment header */
+ ulint space, /*!< in: space id */
+ ulint zip_size,/*!< in: compressed page size in bytes
+ or 0 for uncompressed pages */
+ mtr_t* mtr) /*!< in: mtr handle */
{
fil_addr_t inode_addr;
fseg_inode_t* inode;
inode_addr.page = mach_read_from_4(header + FSEG_HDR_PAGE_NO);
inode_addr.boffset = mach_read_from_2(header + FSEG_HDR_OFFSET);
+ ut_ad(space == mach_read_from_4(header + FSEG_HDR_SPACE));
- inode = fut_get_ptr(mach_read_from_4(header + FSEG_HDR_SPACE),
- inode_addr, RW_X_LATCH, mtr);
+ inode = fut_get_ptr(space, zip_size, inode_addr, RW_X_LATCH, mtr);
ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE);
return(inode);
}
-/**************************************************************************
-Gets the page number from the nth fragment page slot. */
+/**********************************************************************//**
+Gets the page number from the nth fragment page slot.
+@return page number, FIL_NULL if not in use */
UNIV_INLINE
ulint
fseg_get_nth_frag_page_no(
/*======================*/
- /* out: page number, FIL_NULL if not in use */
- fseg_inode_t* inode, /* in: segment inode */
- ulint n, /* in: slot index */
- mtr_t* mtr __attribute__((unused))) /* in: mtr handle */
+ fseg_inode_t* inode, /*!< in: segment inode */
+ ulint n, /*!< in: slot index */
+ mtr_t* mtr __attribute__((unused))) /*!< in: mtr handle */
{
ut_ad(inode && mtr);
ut_ad(n < FSEG_FRAG_ARR_N_SLOTS);
- ut_ad(mtr_memo_contains(mtr, buf_block_align(inode),
- MTR_MEMO_PAGE_X_FIX));
+ ut_ad(mtr_memo_contains_page(mtr, inode, MTR_MEMO_PAGE_X_FIX));
return(mach_read_from_4(inode + FSEG_FRAG_ARR
+ n * FSEG_FRAG_SLOT_SIZE));
}
-/**************************************************************************
+/**********************************************************************//**
Sets the page number in the nth fragment page slot. */
UNIV_INLINE
void
fseg_set_nth_frag_page_no(
/*======================*/
- fseg_inode_t* inode, /* in: segment inode */
- ulint n, /* in: slot index */
- ulint page_no,/* in: page number to set */
- mtr_t* mtr) /* in: mtr handle */
+ fseg_inode_t* inode, /*!< in: segment inode */
+ ulint n, /*!< in: slot index */
+ ulint page_no,/*!< in: page number to set */
+ mtr_t* mtr) /*!< in: mtr handle */
{
ut_ad(inode && mtr);
ut_ad(n < FSEG_FRAG_ARR_N_SLOTS);
- ut_ad(mtr_memo_contains(mtr, buf_block_align(inode),
- MTR_MEMO_PAGE_X_FIX));
+ ut_ad(mtr_memo_contains_page(mtr, inode, MTR_MEMO_PAGE_X_FIX));
mlog_write_ulint(inode + FSEG_FRAG_ARR + n * FSEG_FRAG_SLOT_SIZE,
page_no, MLOG_4BYTES, mtr);
}
-/**************************************************************************
-Finds a fragment page slot which is free. */
+/**********************************************************************//**
+Finds a fragment page slot which is free.
+@return slot index; ULINT_UNDEFINED if none found */
static
ulint
fseg_find_free_frag_page_slot(
/*==========================*/
- /* out: slot index; ULINT_UNDEFINED if none
- found */
- fseg_inode_t* inode, /* in: segment inode */
- mtr_t* mtr) /* in: mtr handle */
+ fseg_inode_t* inode, /*!< in: segment inode */
+ mtr_t* mtr) /*!< in: mtr handle */
{
ulint i;
ulint page_no;
@@ -1950,16 +2123,15 @@ fseg_find_free_frag_page_slot(
return(ULINT_UNDEFINED);
}
-/**************************************************************************
-Finds a fragment page slot which is used and last in the array. */
+/**********************************************************************//**
+Finds a fragment page slot which is used and last in the array.
+@return slot index; ULINT_UNDEFINED if none found */
static
ulint
fseg_find_last_used_frag_page_slot(
/*===============================*/
- /* out: slot index; ULINT_UNDEFINED if none
- found */
- fseg_inode_t* inode, /* in: segment inode */
- mtr_t* mtr) /* in: mtr handle */
+ fseg_inode_t* inode, /*!< in: segment inode */
+ mtr_t* mtr) /*!< in: mtr handle */
{
ulint i;
ulint page_no;
@@ -1979,15 +2151,15 @@ fseg_find_last_used_frag_page_slot(
return(ULINT_UNDEFINED);
}
-/**************************************************************************
-Calculates reserved fragment page slots. */
+/**********************************************************************//**
+Calculates reserved fragment page slots.
+@return number of fragment pages */
static
ulint
fseg_get_n_frag_pages(
/*==================*/
- /* out: number of fragment pages */
- fseg_inode_t* inode, /* in: segment inode */
- mtr_t* mtr) /* in: mtr handle */
+ fseg_inode_t* inode, /*!< in: segment inode */
+ mtr_t* mtr) /*!< in: mtr handle */
{
ulint i;
ulint count = 0;
@@ -2003,51 +2175,55 @@ fseg_get_n_frag_pages(
return(count);
}
-/**************************************************************************
-Creates a new segment. */
-
-page_t*
+/**********************************************************************//**
+Creates a new segment.
+@return the block where the segment header is placed, x-latched, NULL
+if could not create segment because of lack of space */
+UNIV_INTERN
+buf_block_t*
fseg_create_general(
/*================*/
- /* out: the page where the segment header is placed,
- x-latched, NULL if could not create segment
- because of lack of space */
- ulint space, /* in: space id */
- ulint page, /* in: page where the segment header is placed: if
+ ulint space, /*!< in: space id */
+ ulint page, /*!< in: page where the segment header is placed: if
this is != 0, the page must belong to another segment,
if this is 0, a new page will be allocated and it
will belong to the created segment */
- ulint byte_offset, /* in: byte offset of the created segment header
+ ulint byte_offset, /*!< in: byte offset of the created segment header
on the page */
- ibool has_done_reservation, /* in: TRUE if the caller has already
+ ibool has_done_reservation, /*!< in: TRUE if the caller has already
done the reservation for the pages with
fsp_reserve_free_extents (at least 2 extents: one for
the inode and the other for the segment) then there is
no need to do the check for this individual
operation */
- mtr_t* mtr) /* in: mtr */
+ mtr_t* mtr) /*!< in: mtr */
{
+ ulint flags;
+ ulint zip_size;
fsp_header_t* space_header;
fseg_inode_t* inode;
dulint seg_id;
- fseg_header_t* header = 0; /* remove warning */
+ buf_block_t* block = 0; /* remove warning */
+ fseg_header_t* header = 0; /* remove warning */
rw_lock_t* latch;
ibool success;
ulint n_reserved;
- page_t* ret = NULL;
ulint i;
ut_ad(mtr);
+ ut_ad(byte_offset + FSEG_HEADER_SIZE
+ <= UNIV_PAGE_SIZE - FIL_PAGE_DATA_END);
+
+ latch = fil_space_get_latch(space, &flags);
+ zip_size = dict_table_flags_to_zip_size(flags);
if (page != 0) {
- header = byte_offset + buf_page_get(space, page, RW_X_LATCH,
- mtr);
+ block = buf_page_get(space, zip_size, page, RW_X_LATCH, mtr);
+ header = byte_offset + buf_block_get_frame(block);
}
ut_ad(!mutex_own(&kernel_mutex)
- || mtr_memo_contains(mtr, fil_space_get_latch(space),
- MTR_MEMO_X_LOCK));
- latch = fil_space_get_latch(space);
+ || mtr_memo_contains(mtr, latch, MTR_MEMO_X_LOCK));
mtr_x_lock(latch, mtr);
@@ -2055,8 +2231,8 @@ fseg_create_general(
/* This thread did not own the latch before this call: free
excess pages from the insert buffer free list */
- if (space == 0) {
- ibuf_free_excess_pages(space);
+ if (space == IBUF_SPACE_ID) {
+ ibuf_free_excess_pages();
}
}
@@ -2068,7 +2244,7 @@ fseg_create_general(
}
}
- space_header = fsp_get_space_header(space, mtr);
+ space_header = fsp_get_space_header(space, zip_size, mtr);
inode = fsp_alloc_seg_inode(space_header, mtr);
@@ -2099,78 +2275,77 @@ fseg_create_general(
}
if (page == 0) {
- page = fseg_alloc_free_page_low(space, inode, 0, FSP_UP, mtr);
+ page = fseg_alloc_free_page_low(space, zip_size,
+ inode, 0, FSP_UP, mtr);
if (page == FIL_NULL) {
- fsp_free_seg_inode(space, inode, mtr);
+ fsp_free_seg_inode(space, zip_size, inode, mtr);
goto funct_exit;
}
- header = byte_offset
- + buf_page_get(space, page, RW_X_LATCH, mtr);
+ block = buf_page_get(space, zip_size, page, RW_X_LATCH, mtr);
+ header = byte_offset + buf_block_get_frame(block);
mlog_write_ulint(header - byte_offset + FIL_PAGE_TYPE,
FIL_PAGE_TYPE_SYS, MLOG_2BYTES, mtr);
}
mlog_write_ulint(header + FSEG_HDR_OFFSET,
- inode - buf_frame_align(inode), MLOG_2BYTES, mtr);
+ page_offset(inode), MLOG_2BYTES, mtr);
mlog_write_ulint(header + FSEG_HDR_PAGE_NO,
- buf_frame_get_page_no(inode), MLOG_4BYTES, mtr);
+ page_get_page_no(page_align(inode)),
+ MLOG_4BYTES, mtr);
mlog_write_ulint(header + FSEG_HDR_SPACE, space, MLOG_4BYTES, mtr);
- ret = buf_frame_align(header);
-
funct_exit:
if (!has_done_reservation) {
fil_space_release_free_extents(space, n_reserved);
}
- return(ret);
+ return(block);
}
-/**************************************************************************
-Creates a new segment. */
-
-page_t*
+/**********************************************************************//**
+Creates a new segment.
+@return the block where the segment header is placed, x-latched, NULL
+if could not create segment because of lack of space */
+UNIV_INTERN
+buf_block_t*
fseg_create(
/*========*/
- /* out: the page where the segment header is placed,
- x-latched, NULL if could not create segment
- because of lack of space */
- ulint space, /* in: space id */
- ulint page, /* in: page where the segment header is placed: if
+ ulint space, /*!< in: space id */
+ ulint page, /*!< in: page where the segment header is placed: if
this is != 0, the page must belong to another segment,
if this is 0, a new page will be allocated and it
will belong to the created segment */
- ulint byte_offset, /* in: byte offset of the created segment header
+ ulint byte_offset, /*!< in: byte offset of the created segment header
on the page */
- mtr_t* mtr) /* in: mtr */
+ mtr_t* mtr) /*!< in: mtr */
{
return(fseg_create_general(space, page, byte_offset, FALSE, mtr));
}
-/**************************************************************************
+/**********************************************************************//**
Calculates the number of pages reserved by a segment, and how many pages are
-currently used. */
+currently used.
+@return number of reserved pages */
static
ulint
fseg_n_reserved_pages_low(
/*======================*/
- /* out: number of reserved pages */
- fseg_inode_t* inode, /* in: segment inode */
- ulint* used, /* out: number of pages used (<= reserved) */
- mtr_t* mtr) /* in: mtr handle */
+ fseg_inode_t* inode, /*!< in: segment inode */
+ ulint* used, /*!< out: number of pages used (not
+ more than reserved) */
+ mtr_t* mtr) /*!< in: mtr handle */
{
ulint ret;
ut_ad(inode && used && mtr);
- ut_ad(mtr_memo_contains(mtr, buf_block_align(inode),
- MTR_MEMO_PAGE_X_FIX));
+ ut_ad(mtr_memo_contains_page(mtr, inode, MTR_MEMO_PAGE_X_FIX));
*used = mtr_read_ulint(inode + FSEG_NOT_FULL_N_USED, MLOG_4BYTES, mtr)
+ FSP_EXTENT_SIZE * flst_get_len(inode + FSEG_FULL, mtr)
@@ -2184,38 +2359,42 @@ fseg_n_reserved_pages_low(
return(ret);
}
-/**************************************************************************
+/**********************************************************************//**
Calculates the number of pages reserved by a segment, and how many pages are
-currently used. */
-
+currently used.
+@return number of reserved pages */
+UNIV_INTERN
ulint
fseg_n_reserved_pages(
/*==================*/
- /* out: number of reserved pages */
- fseg_header_t* header, /* in: segment header */
- ulint* used, /* out: number of pages used (<= reserved) */
- mtr_t* mtr) /* in: mtr handle */
+ fseg_header_t* header, /*!< in: segment header */
+ ulint* used, /*!< out: number of pages used (<= reserved) */
+ mtr_t* mtr) /*!< in: mtr handle */
{
ulint ret;
fseg_inode_t* inode;
ulint space;
+ ulint flags;
+ ulint zip_size;
+ rw_lock_t* latch;
- space = buf_frame_get_space_id(header);
+ space = page_get_space_id(page_align(header));
+ latch = fil_space_get_latch(space, &flags);
+ zip_size = dict_table_flags_to_zip_size(flags);
ut_ad(!mutex_own(&kernel_mutex)
- || mtr_memo_contains(mtr, fil_space_get_latch(space),
- MTR_MEMO_X_LOCK));
+ || mtr_memo_contains(mtr, latch, MTR_MEMO_X_LOCK));
- mtr_x_lock(fil_space_get_latch(space), mtr);
+ mtr_x_lock(latch, mtr);
- inode = fseg_inode_get(header, mtr);
+ inode = fseg_inode_get(header, space, zip_size, mtr);
ret = fseg_n_reserved_pages_low(inode, used, mtr);
return(ret);
}
-/*************************************************************************
+/*********************************************************************//**
Tries to fill the free list of a segment with consecutive free extents.
This happens if the segment is big enough to allow extents in the free list,
the free list is empty, and the extents can be allocated consecutively from
@@ -2224,11 +2403,13 @@ static
void
fseg_fill_free_list(
/*================*/
- fseg_inode_t* inode, /* in: segment inode */
- ulint space, /* in: space id */
- ulint hint, /* in: hint which extent would be good as
+ fseg_inode_t* inode, /*!< in: segment inode */
+ ulint space, /*!< in: space id */
+ ulint zip_size,/*!< in: compressed page size in bytes
+ or 0 for uncompressed pages */
+ ulint hint, /*!< in: hint which extent would be good as
the first extent */
- mtr_t* mtr) /* in: mtr */
+ mtr_t* mtr) /*!< in: mtr */
{
xdes_t* descr;
ulint i;
@@ -2237,6 +2418,7 @@ fseg_fill_free_list(
ulint used;
ut_ad(inode && mtr);
+ ut_ad(!((page_offset(inode) - FSEG_ARR_OFFSET) % FSEG_INODE_SIZE));
reserved = fseg_n_reserved_pages_low(inode, &used, mtr);
@@ -2254,7 +2436,7 @@ fseg_fill_free_list(
}
for (i = 0; i < FSEG_FREE_LIST_MAX_LEN; i++) {
- descr = xdes_get_descriptor(space, hint, mtr);
+ descr = xdes_get_descriptor(space, zip_size, hint, mtr);
if ((descr == NULL)
|| (XDES_FREE != xdes_get_state(descr, mtr))) {
@@ -2264,7 +2446,7 @@ fseg_fill_free_list(
return;
}
- descr = fsp_alloc_free_extent(space, hint, mtr);
+ descr = fsp_alloc_free_extent(space, zip_size, hint, mtr);
xdes_set_state(descr, XDES_FSEG, mtr);
@@ -2276,34 +2458,37 @@ fseg_fill_free_list(
}
}
-/*************************************************************************
+/*********************************************************************//**
Allocates a free extent for the segment: looks first in the free list of the
segment, then tries to allocate from the space free list. NOTE that the extent
-returned still resides in the segment free list, it is not yet taken off it! */
+returned still resides in the segment free list, it is not yet taken off it!
+@return allocated extent, still placed in the segment free list, NULL
+if could not be allocated */
static
xdes_t*
fseg_alloc_free_extent(
/*===================*/
- /* out: allocated extent, still placed in the
- segment free list, NULL if could
- not be allocated */
- fseg_inode_t* inode, /* in: segment inode */
- ulint space, /* in: space id */
- mtr_t* mtr) /* in: mtr */
+ fseg_inode_t* inode, /*!< in: segment inode */
+ ulint space, /*!< in: space id */
+ ulint zip_size,/*!< in: compressed page size in bytes
+ or 0 for uncompressed pages */
+ mtr_t* mtr) /*!< in: mtr */
{
xdes_t* descr;
dulint seg_id;
fil_addr_t first;
+ ut_ad(!((page_offset(inode) - FSEG_ARR_OFFSET) % FSEG_INODE_SIZE));
+
if (flst_get_len(inode + FSEG_FREE, mtr) > 0) {
/* Segment free list is not empty, allocate from it */
first = flst_get_first(inode + FSEG_FREE, mtr);
- descr = xdes_lst_get_descriptor(space, first, mtr);
+ descr = xdes_lst_get_descriptor(space, zip_size, first, mtr);
} else {
/* Segment free list was empty, allocate from space */
- descr = fsp_alloc_free_extent(space, 0, mtr);
+ descr = fsp_alloc_free_extent(space, zip_size, 0, mtr);
if (descr == NULL) {
@@ -2317,7 +2502,7 @@ fseg_alloc_free_extent(
flst_add_last(inode + FSEG_FREE, descr + XDES_FLST_NODE, mtr);
/* Try to fill the segment free list */
- fseg_fill_free_list(inode, space,
+ fseg_fill_free_list(inode, space, zip_size,
xdes_get_offset(descr) + FSP_EXTENT_SIZE,
mtr);
}
@@ -2325,36 +2510,36 @@ fseg_alloc_free_extent(
return(descr);
}
-/**************************************************************************
+/**********************************************************************//**
Allocates a single free page from a segment. This function implements
the intelligent allocation strategy which tries to minimize file space
-fragmentation. */
+fragmentation.
+@return the allocated page number, FIL_NULL if no page could be allocated */
static
ulint
fseg_alloc_free_page_low(
/*=====================*/
- /* out: the allocated page number, FIL_NULL
- if no page could be allocated */
- ulint space, /* in: space */
- fseg_inode_t* seg_inode, /* in: segment inode */
- ulint hint, /* in: hint of which page would be desirable */
- byte direction, /* in: if the new page is needed because
+ ulint space, /*!< in: space */
+ ulint zip_size,/*!< in: compressed page size in bytes
+ or 0 for uncompressed pages */
+ fseg_inode_t* seg_inode, /*!< in: segment inode */
+ ulint hint, /*!< in: hint of which page would be desirable */
+ byte direction, /*!< in: if the new page is needed because
of an index page split, and records are
inserted there in order, into which
direction they go alphabetically: FSP_DOWN,
FSP_UP, FSP_NO_DIR */
- mtr_t* mtr) /* in: mtr handle */
+ mtr_t* mtr) /*!< in: mtr handle */
{
fsp_header_t* space_header;
ulint space_size;
dulint seg_id;
ulint used;
ulint reserved;
- xdes_t* descr; /* extent of the hinted page */
- ulint ret_page; /* the allocated page offset, FIL_NULL
+ xdes_t* descr; /*!< extent of the hinted page */
+ ulint ret_page; /*!< the allocated page offset, FIL_NULL
if could not be allocated */
- xdes_t* ret_descr; /* the extent of the allocated page */
- page_t* page;
+ xdes_t* ret_descr; /*!< the extent of the allocated page */
ibool frag_page_allocated = FALSE;
ibool success;
ulint n;
@@ -2363,13 +2548,14 @@ fseg_alloc_free_page_low(
ut_ad((direction >= FSP_UP) && (direction <= FSP_NO_DIR));
ut_ad(mach_read_from_4(seg_inode + FSEG_MAGIC_N)
== FSEG_MAGIC_N_VALUE);
+ ut_ad(!((page_offset(seg_inode) - FSEG_ARR_OFFSET) % FSEG_INODE_SIZE));
seg_id = mtr_read_dulint(seg_inode + FSEG_ID, mtr);
- ut_ad(ut_dulint_cmp(seg_id, ut_dulint_zero) > 0);
+ ut_ad(!ut_dulint_is_zero(seg_id));
reserved = fseg_n_reserved_pages_low(seg_inode, &used, mtr);
- space_header = fsp_get_space_header(space, mtr);
+ space_header = fsp_get_space_header(space, zip_size, mtr);
descr = xdes_get_descriptor_with_space_hdr(space_header, space,
hint, mtr);
@@ -2377,7 +2563,7 @@ fseg_alloc_free_page_low(
/* Hint outside space or too high above free limit: reset
hint */
hint = 0;
- descr = xdes_get_descriptor(space, hint, mtr);
+ descr = xdes_get_descriptor(space, zip_size, hint, mtr);
}
/* In the big if-else below we look for ret_page and ret_descr */
@@ -2401,7 +2587,7 @@ fseg_alloc_free_page_low(
=========================================================
the hinted page
===============*/
- ret_descr = fsp_alloc_free_extent(space, hint, mtr);
+ ret_descr = fsp_alloc_free_extent(space, zip_size, hint, mtr);
ut_a(ret_descr == descr);
@@ -2411,7 +2597,7 @@ fseg_alloc_free_page_low(
ret_descr + XDES_FLST_NODE, mtr);
/* Try to fill the segment free list */
- fseg_fill_free_list(seg_inode, space,
+ fseg_fill_free_list(seg_inode, space, zip_size,
hint + FSP_EXTENT_SIZE, mtr);
ret_page = hint;
/*-----------------------------------------------------------*/
@@ -2419,7 +2605,8 @@ fseg_alloc_free_page_low(
&& ((reserved - used) < reserved / FSEG_FILLFACTOR)
&& (used >= FSEG_FRAG_LIMIT)
&& (!!(ret_descr
- = fseg_alloc_free_extent(seg_inode, space, mtr)))) {
+ = fseg_alloc_free_extent(seg_inode,
+ space, zip_size, mtr)))) {
/* 3. We take any free extent (which was already assigned above
===============================================================
@@ -2464,7 +2651,8 @@ fseg_alloc_free_page_low(
return(FIL_NULL);
}
- ret_descr = xdes_lst_get_descriptor(space, first, mtr);
+ ret_descr = xdes_lst_get_descriptor(space, zip_size,
+ first, mtr);
ret_page = xdes_get_offset(ret_descr)
+ xdes_find_bit(ret_descr, XDES_FREE_BIT, TRUE,
0, mtr);
@@ -2472,7 +2660,7 @@ fseg_alloc_free_page_low(
} else if (used < FSEG_FRAG_LIMIT) {
/* 6. We allocate an individual page from the space
===================================================*/
- ret_page = fsp_alloc_free_page(space, hint, mtr);
+ ret_page = fsp_alloc_free_page(space, zip_size, hint, mtr);
ret_descr = NULL;
frag_page_allocated = TRUE;
@@ -2490,7 +2678,8 @@ fseg_alloc_free_page_low(
} else {
/* 7. We allocate a new extent and take its first page
======================================================*/
- ret_descr = fseg_alloc_free_extent(seg_inode, space, mtr);
+ ret_descr = fseg_alloc_free_extent(seg_inode,
+ space, zip_size, mtr);
if (ret_descr == NULL) {
ret_page = FIL_NULL;
@@ -2536,27 +2725,32 @@ fseg_alloc_free_page_low(
/* Initialize the allocated page to buffer pool, so that it
can be obtained immediately with buf_page_get without need
for a disk read */
+ buf_block_t* block;
+ ulint zip_size = dict_table_flags_to_zip_size(
+ mach_read_from_4(FSP_SPACE_FLAGS + space_header));
- page = buf_page_create(space, ret_page, mtr);
+ block = buf_page_create(space, ret_page, zip_size, mtr);
+ buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
- ut_a(page == buf_page_get(space, ret_page, RW_X_LATCH, mtr));
-
-#ifdef UNIV_SYNC_DEBUG
- buf_page_dbg_add_level(page, SYNC_FSP_PAGE);
-#endif /* UNIV_SYNC_DEBUG */
+ if (UNIV_UNLIKELY(block != buf_page_get(space, zip_size,
+ ret_page, RW_X_LATCH,
+ mtr))) {
+ ut_error;
+ }
/* The prior contents of the page should be ignored */
- fsp_init_file_page(page, mtr);
+ fsp_init_file_page(block, mtr);
/* At this point we know the extent and the page offset.
The extent is still in the appropriate list (FSEG_NOT_FULL
or FSEG_FREE), and the page is not yet marked as used. */
- ut_ad(xdes_get_descriptor(space, ret_page, mtr) == ret_descr);
+ ut_ad(xdes_get_descriptor(space, zip_size, ret_page, mtr)
+ == ret_descr);
ut_ad(xdes_get_bit(ret_descr, XDES_FREE_BIT,
ret_page % FSP_EXTENT_SIZE, mtr) == TRUE);
- fseg_mark_page_used(seg_inode, space, ret_page, mtr);
+ fseg_mark_page_used(seg_inode, space, zip_size, ret_page, mtr);
}
buf_reset_check_index_page_at_flush(space, ret_page);
@@ -2564,43 +2758,46 @@ fseg_alloc_free_page_low(
return(ret_page);
}
-/**************************************************************************
+/**********************************************************************//**
Allocates a single free page from a segment. This function implements
the intelligent allocation strategy which tries to minimize file space
-fragmentation. */
-
+fragmentation.
+@return allocated page offset, FIL_NULL if no page could be allocated */
+UNIV_INTERN
ulint
fseg_alloc_free_page_general(
/*=========================*/
- /* out: allocated page offset, FIL_NULL if no
- page could be allocated */
- fseg_header_t* seg_header,/* in: segment header */
- ulint hint, /* in: hint of which page would be desirable */
- byte direction,/* in: if the new page is needed because
+ fseg_header_t* seg_header,/*!< in: segment header */
+ ulint hint, /*!< in: hint of which page would be desirable */
+ byte direction,/*!< in: if the new page is needed because
of an index page split, and records are
inserted there in order, into which
direction they go alphabetically: FSP_DOWN,
FSP_UP, FSP_NO_DIR */
- ibool has_done_reservation, /* in: TRUE if the caller has
+ ibool has_done_reservation, /*!< in: TRUE if the caller has
already done the reservation for the page
with fsp_reserve_free_extents, then there
is no need to do the check for this individual
page */
- mtr_t* mtr) /* in: mtr handle */
+ mtr_t* mtr) /*!< in: mtr handle */
{
fseg_inode_t* inode;
ulint space;
+ ulint flags;
+ ulint zip_size;
rw_lock_t* latch;
ibool success;
ulint page_no;
ulint n_reserved;
- space = buf_frame_get_space_id(seg_header);
+ space = page_get_space_id(page_align(seg_header));
+
+ latch = fil_space_get_latch(space, &flags);
+
+ zip_size = dict_table_flags_to_zip_size(flags);
ut_ad(!mutex_own(&kernel_mutex)
- || mtr_memo_contains(mtr, fil_space_get_latch(space),
- MTR_MEMO_X_LOCK));
- latch = fil_space_get_latch(space);
+ || mtr_memo_contains(mtr, latch, MTR_MEMO_X_LOCK));
mtr_x_lock(latch, mtr);
@@ -2608,12 +2805,12 @@ fseg_alloc_free_page_general(
/* This thread did not own the latch before this call: free
excess pages from the insert buffer free list */
- if (space == 0) {
- ibuf_free_excess_pages(space);
+ if (space == IBUF_SPACE_ID) {
+ ibuf_free_excess_pages();
}
}
- inode = fseg_inode_get(seg_header, mtr);
+ inode = fseg_inode_get(seg_header, space, zip_size, mtr);
if (!has_done_reservation) {
success = fsp_reserve_free_extents(&n_reserved, space, 2,
@@ -2623,7 +2820,7 @@ fseg_alloc_free_page_general(
}
}
- page_no = fseg_alloc_free_page_low(buf_frame_get_space_id(inode),
+ page_no = fseg_alloc_free_page_low(space, zip_size,
inode, hint, direction, mtr);
if (!has_done_reservation) {
fil_space_release_free_extents(space, n_reserved);
@@ -2632,47 +2829,45 @@ fseg_alloc_free_page_general(
return(page_no);
}
-/**************************************************************************
+/**********************************************************************//**
Allocates a single free page from a segment. This function implements
the intelligent allocation strategy which tries to minimize file space
-fragmentation. */
-
+fragmentation.
+@return allocated page offset, FIL_NULL if no page could be allocated */
+UNIV_INTERN
ulint
fseg_alloc_free_page(
/*=================*/
- /* out: allocated page offset, FIL_NULL if no
- page could be allocated */
- fseg_header_t* seg_header,/* in: segment header */
- ulint hint, /* in: hint of which page would be desirable */
- byte direction,/* in: if the new page is needed because
+ fseg_header_t* seg_header,/*!< in: segment header */
+ ulint hint, /*!< in: hint of which page would be desirable */
+ byte direction,/*!< in: if the new page is needed because
of an index page split, and records are
inserted there in order, into which
direction they go alphabetically: FSP_DOWN,
FSP_UP, FSP_NO_DIR */
- mtr_t* mtr) /* in: mtr handle */
+ mtr_t* mtr) /*!< in: mtr handle */
{
return(fseg_alloc_free_page_general(seg_header, hint, direction,
FALSE, mtr));
}
-/**************************************************************************
+/**********************************************************************//**
Checks that we have at least 2 frag pages free in the first extent of a
single-table tablespace, and they are also physically initialized to the data
file. That is we have already extended the data file so that those pages are
inside the data file. If not, this function extends the tablespace with
-pages. */
+pages.
+@return TRUE if there were >= 3 free pages, or we were able to extend */
static
ibool
fsp_reserve_free_pages(
/*===================*/
- /* out: TRUE if there were >= 3 free
- pages, or we were able to extend */
- ulint space, /* in: space id, must be != 0 */
- fsp_header_t* space_header, /* in: header of that space,
+ ulint space, /*!< in: space id, must be != 0 */
+ fsp_header_t* space_header, /*!< in: header of that space,
x-latched */
- ulint size, /* in: size of the tablespace in pages,
+ ulint size, /*!< in: size of the tablespace in pages,
must be < FSP_EXTENT_SIZE / 2 */
- mtr_t* mtr) /* in: mtr */
+ mtr_t* mtr) /*!< in: mtr */
{
xdes_t* descr;
ulint n_used;
@@ -2695,7 +2890,7 @@ fsp_reserve_free_pages(
space_header, mtr));
}
-/**************************************************************************
+/**********************************************************************//**
Reserves free pages from a tablespace. All mini-transactions which may
use several pages from the tablespace should call this function beforehand
and reserve enough free extents so that they certainly will be able
@@ -2719,25 +2914,27 @@ Single-table tablespaces whose size is < 32 pages are a special case. In this
function we would liberally reserve several 64 page extents for every page
split or merge in a B-tree. But we do not want to waste disk space if the table
only occupies < 32 pages. That is why we apply different rules in that special
-case, just ensuring that there are 3 free pages available. */
-
+case, just ensuring that there are 3 free pages available.
+@return TRUE if we were able to make the reservation */
+UNIV_INTERN
ibool
fsp_reserve_free_extents(
/*=====================*/
- /* out: TRUE if we were able to make the reservation */
- ulint* n_reserved,/* out: number of extents actually reserved; if we
+ ulint* n_reserved,/*!< out: number of extents actually reserved; if we
return TRUE and the tablespace size is < 64 pages,
then this can be 0, otherwise it is n_ext */
- ulint space, /* in: space id */
- ulint n_ext, /* in: number of extents to reserve */
- ulint alloc_type,/* in: FSP_NORMAL, FSP_UNDO, or FSP_CLEANING */
- mtr_t* mtr) /* in: mtr */
+ ulint space, /*!< in: space id */
+ ulint n_ext, /*!< in: number of extents to reserve */
+ ulint alloc_type,/*!< in: FSP_NORMAL, FSP_UNDO, or FSP_CLEANING */
+ mtr_t* mtr) /*!< in: mtr */
{
fsp_header_t* space_header;
rw_lock_t* latch;
ulint n_free_list_ext;
ulint free_limit;
ulint size;
+ ulint flags;
+ ulint zip_size;
ulint n_free;
ulint n_free_up;
ulint reserve;
@@ -2745,16 +2942,17 @@ fsp_reserve_free_extents(
ulint n_pages_added;
ut_ad(mtr);
- ut_ad(!mutex_own(&kernel_mutex)
- || mtr_memo_contains(mtr, fil_space_get_latch(space),
- MTR_MEMO_X_LOCK));
*n_reserved = n_ext;
- latch = fil_space_get_latch(space);
+ latch = fil_space_get_latch(space, &flags);
+ zip_size = dict_table_flags_to_zip_size(flags);
+
+ ut_ad(!mutex_own(&kernel_mutex)
+ || mtr_memo_contains(mtr, latch, MTR_MEMO_X_LOCK));
mtr_x_lock(latch, mtr);
- space_header = fsp_get_space_header(space, mtr);
+ space_header = fsp_get_space_header(space, zip_size, mtr);
try_again:
size = mtr_read_ulint(space_header + FSP_SIZE, MLOG_4BYTES, mtr);
@@ -2777,8 +2975,13 @@ try_again:
if (n_free_up > 0) {
n_free_up--;
- n_free_up = n_free_up - n_free_up
- / (XDES_DESCRIBED_PER_PAGE / FSP_EXTENT_SIZE);
+ if (!zip_size) {
+ n_free_up -= n_free_up
+ / (UNIV_PAGE_SIZE / FSP_EXTENT_SIZE);
+ } else {
+ n_free_up -= n_free_up
+ / (zip_size / FSP_EXTENT_SIZE);
+ }
}
n_free = n_free_list_ext + n_free_up;
@@ -2823,22 +3026,24 @@ try_to_extend:
return(FALSE);
}
-/**************************************************************************
+/**********************************************************************//**
This function should be used to get information on how much we still
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. */
-
+the safety margin required by the above function fsp_reserve_free_extents.
+@return available space in kB */
+UNIV_INTERN
ullint
fsp_get_available_space_in_free_extents(
/*====================================*/
- /* out: available space in kB */
- ulint space) /* in: space id */
+ ulint space) /*!< in: space id */
{
fsp_header_t* space_header;
ulint n_free_list_ext;
ulint free_limit;
ulint size;
+ ulint flags;
+ ulint zip_size;
ulint n_free;
ulint n_free_up;
ulint reserve;
@@ -2849,11 +3054,12 @@ fsp_get_available_space_in_free_extents(
mtr_start(&mtr);
- latch = fil_space_get_latch(space);
+ latch = fil_space_get_latch(space, &flags);
+ zip_size = dict_table_flags_to_zip_size(flags);
mtr_x_lock(latch, &mtr);
- space_header = fsp_get_space_header(space, &mtr);
+ space_header = fsp_get_space_header(space, zip_size, &mtr);
size = mtr_read_ulint(space_header + FSP_SIZE, MLOG_4BYTES, &mtr);
@@ -2879,8 +3085,13 @@ fsp_get_available_space_in_free_extents(
if (n_free_up > 0) {
n_free_up--;
- n_free_up = n_free_up - n_free_up
- / (XDES_DESCRIBED_PER_PAGE / FSP_EXTENT_SIZE);
+ if (!zip_size) {
+ n_free_up -= n_free_up
+ / (UNIV_PAGE_SIZE / FSP_EXTENT_SIZE);
+ } else {
+ n_free_up -= n_free_up
+ / (zip_size / FSP_EXTENT_SIZE);
+ }
}
n_free = n_free_list_ext + n_free_up;
@@ -2895,29 +3106,38 @@ fsp_get_available_space_in_free_extents(
return(0);
}
- return((ullint)(n_free - reserve)
- * FSP_EXTENT_SIZE
- * (UNIV_PAGE_SIZE / 1024));
+ if (!zip_size) {
+ return((ullint) (n_free - reserve)
+ * FSP_EXTENT_SIZE
+ * (UNIV_PAGE_SIZE / 1024));
+ } else {
+ return((ullint) (n_free - reserve)
+ * FSP_EXTENT_SIZE
+ * (zip_size / 1024));
+ }
}
-/************************************************************************
+/********************************************************************//**
Marks a page used. The page must reside within the extents of the given
segment. */
static
void
fseg_mark_page_used(
/*================*/
- fseg_inode_t* seg_inode,/* in: segment inode */
- ulint space, /* in: space id */
- ulint page, /* in: page offset */
- mtr_t* mtr) /* in: mtr */
+ fseg_inode_t* seg_inode,/*!< in: segment inode */
+ ulint space, /*!< in: space id */
+ ulint zip_size,/*!< in: compressed page size in bytes
+ or 0 for uncompressed pages */
+ ulint page, /*!< in: page offset */
+ mtr_t* mtr) /*!< in: mtr */
{
xdes_t* descr;
ulint not_full_n_used;
ut_ad(seg_inode && mtr);
+ ut_ad(!((page_offset(seg_inode) - FSEG_ARR_OFFSET) % FSEG_INODE_SIZE));
- descr = xdes_get_descriptor(space, page, mtr);
+ descr = xdes_get_descriptor(space, zip_size, page, mtr);
ut_ad(mtr_read_ulint(seg_inode + FSEG_ID, MLOG_4BYTES, mtr)
== mtr_read_ulint(descr + XDES_ID, MLOG_4BYTES, mtr));
@@ -2955,16 +3175,18 @@ fseg_mark_page_used(
}
}
-/**************************************************************************
+/**********************************************************************//**
Frees a single page of a segment. */
static
void
fseg_free_page_low(
/*===============*/
- fseg_inode_t* seg_inode, /* in: segment inode */
- ulint space, /* in: space id */
- ulint page, /* in: page offset */
- mtr_t* mtr) /* in: mtr handle */
+ fseg_inode_t* seg_inode, /*!< in: segment inode */
+ ulint space, /*!< in: space id */
+ ulint zip_size,/*!< in: compressed page size in bytes
+ or 0 for uncompressed pages */
+ ulint page, /*!< in: page offset */
+ mtr_t* mtr) /*!< in: mtr handle */
{
xdes_t* descr;
ulint not_full_n_used;
@@ -2976,13 +3198,14 @@ fseg_free_page_low(
ut_ad(seg_inode && mtr);
ut_ad(mach_read_from_4(seg_inode + FSEG_MAGIC_N)
== FSEG_MAGIC_N_VALUE);
+ ut_ad(!((page_offset(seg_inode) - FSEG_ARR_OFFSET) % FSEG_INODE_SIZE));
/* Drop search system page hash index if the page is found in
the pool and is hashed */
- btr_search_drop_page_hash_when_freed(space, page);
+ btr_search_drop_page_hash_when_freed(space, zip_size, page);
- descr = xdes_get_descriptor(space, page, mtr);
+ descr = xdes_get_descriptor(space, zip_size, page, mtr);
ut_a(descr);
if (xdes_get_bit(descr, XDES_FREE_BIT, page % FSP_EXTENT_SIZE, mtr)) {
@@ -3001,8 +3224,7 @@ fseg_free_page_low(
"InnoDB: database!\n", (ulong) page);
crash:
fputs("InnoDB: Please refer to\n"
- "InnoDB: http://dev.mysql.com/doc/refman/5.1/en/"
- "forcing-recovery.html\n"
+ "InnoDB: " REFMAN "forcing-recovery.html\n"
"InnoDB: about forcing recovery.\n", stderr);
ut_error;
}
@@ -3022,7 +3244,7 @@ crash:
}
}
- fsp_free_page(space, page, mtr);
+ fsp_free_page(space, zip_size, page, mtr);
return;
}
@@ -3088,48 +3310,55 @@ crash:
/* The extent has become free: free it to space */
flst_remove(seg_inode + FSEG_NOT_FULL,
descr + XDES_FLST_NODE, mtr);
- fsp_free_extent(space, page, mtr);
+ fsp_free_extent(space, zip_size, page, mtr);
}
}
-/**************************************************************************
+/**********************************************************************//**
Frees a single page of a segment. */
-
+UNIV_INTERN
void
fseg_free_page(
/*===========*/
- fseg_header_t* seg_header, /* in: segment header */
- ulint space, /* in: space id */
- ulint page, /* in: page offset */
- mtr_t* mtr) /* in: mtr handle */
+ fseg_header_t* seg_header, /*!< in: segment header */
+ ulint space, /*!< in: space id */
+ ulint page, /*!< in: page offset */
+ mtr_t* mtr) /*!< in: mtr handle */
{
+ ulint flags;
+ ulint zip_size;
fseg_inode_t* seg_inode;
+ rw_lock_t* latch;
+
+ latch = fil_space_get_latch(space, &flags);
+ zip_size = dict_table_flags_to_zip_size(flags);
ut_ad(!mutex_own(&kernel_mutex)
- || mtr_memo_contains(mtr, fil_space_get_latch(space),
- MTR_MEMO_X_LOCK));
+ || mtr_memo_contains(mtr, latch, MTR_MEMO_X_LOCK));
- mtr_x_lock(fil_space_get_latch(space), mtr);
+ mtr_x_lock(latch, mtr);
- seg_inode = fseg_inode_get(seg_header, mtr);
+ seg_inode = fseg_inode_get(seg_header, space, zip_size, mtr);
- fseg_free_page_low(seg_inode, space, page, mtr);
+ fseg_free_page_low(seg_inode, space, zip_size, page, mtr);
#ifdef UNIV_DEBUG_FILE_ACCESSES
buf_page_set_file_page_was_freed(space, page);
#endif
}
-/**************************************************************************
+/**********************************************************************//**
Frees an extent of a segment to the space free list. */
static
void
fseg_free_extent(
/*=============*/
- fseg_inode_t* seg_inode, /* in: segment inode */
- ulint space, /* in: space id */
- ulint page, /* in: a page in the extent */
- mtr_t* mtr) /* in: mtr handle */
+ fseg_inode_t* seg_inode, /*!< in: segment inode */
+ ulint space, /*!< in: space id */
+ ulint zip_size,/*!< in: compressed page size in bytes
+ or 0 for uncompressed pages */
+ ulint page, /*!< in: a page in the extent */
+ mtr_t* mtr) /*!< in: mtr handle */
{
ulint first_page_in_extent;
xdes_t* descr;
@@ -3139,7 +3368,7 @@ fseg_free_extent(
ut_ad(seg_inode && mtr);
- descr = xdes_get_descriptor(space, page, mtr);
+ descr = xdes_get_descriptor(space, zip_size, page, mtr);
ut_a(xdes_get_state(descr, mtr) == XDES_FSEG);
ut_a(0 == ut_dulint_cmp(mtr_read_dulint(descr + XDES_ID, mtr),
@@ -3154,7 +3383,7 @@ fseg_free_extent(
found in the pool and is hashed */
btr_search_drop_page_hash_when_freed(
- space, first_page_in_extent + i);
+ space, zip_size, first_page_in_extent + i);
}
}
@@ -3178,7 +3407,7 @@ fseg_free_extent(
MLOG_4BYTES, mtr);
}
- fsp_free_extent(space, page, mtr);
+ fsp_free_extent(space, zip_size, page, mtr);
#ifdef UNIV_DEBUG_FILE_ACCESSES
for (i = 0; i < FSP_EXTENT_SIZE; i++) {
@@ -3189,53 +3418,60 @@ fseg_free_extent(
#endif
}
-/**************************************************************************
+/**********************************************************************//**
Frees part of a segment. This function can be used to free a segment by
repeatedly calling this function in different mini-transactions. Doing
the freeing in a single mini-transaction might result in too big a
-mini-transaction. */
-
+mini-transaction.
+@return TRUE if freeing completed */
+UNIV_INTERN
ibool
fseg_free_step(
/*===========*/
- /* out: TRUE if freeing completed */
- fseg_header_t* header, /* in, own: segment header; NOTE: if the header
+ fseg_header_t* header, /*!< in, own: segment header; NOTE: if the header
resides on the first page of the frag list
of the segment, this pointer becomes obsolete
after the last freeing step */
- mtr_t* mtr) /* in: mtr */
+ mtr_t* mtr) /*!< in: mtr */
{
ulint n;
ulint page;
xdes_t* descr;
fseg_inode_t* inode;
ulint space;
+ ulint flags;
+ ulint zip_size;
+ ulint header_page;
+ rw_lock_t* latch;
- space = buf_frame_get_space_id(header);
+ space = page_get_space_id(page_align(header));
+ header_page = page_get_page_no(page_align(header));
+
+ latch = fil_space_get_latch(space, &flags);
+ zip_size = dict_table_flags_to_zip_size(flags);
ut_ad(!mutex_own(&kernel_mutex)
- || mtr_memo_contains(mtr, fil_space_get_latch(space),
- MTR_MEMO_X_LOCK));
+ || mtr_memo_contains(mtr, latch, MTR_MEMO_X_LOCK));
- mtr_x_lock(fil_space_get_latch(space), mtr);
+ mtr_x_lock(latch, mtr);
- descr = xdes_get_descriptor(space, buf_frame_get_page_no(header), mtr);
+ descr = xdes_get_descriptor(space, zip_size, header_page, mtr);
/* Check that the header resides on a page which has not been
freed yet */
ut_a(descr);
- ut_a(xdes_get_bit(descr, XDES_FREE_BIT, buf_frame_get_page_no(header)
- % FSP_EXTENT_SIZE, mtr) == FALSE);
- inode = fseg_inode_get(header, mtr);
+ ut_a(xdes_get_bit(descr, XDES_FREE_BIT,
+ header_page % FSP_EXTENT_SIZE, mtr) == FALSE);
+ inode = fseg_inode_get(header, space, zip_size, mtr);
- descr = fseg_get_first_extent(inode, mtr);
+ descr = fseg_get_first_extent(inode, space, zip_size, mtr);
if (descr != NULL) {
/* Free the extent held by the segment */
page = xdes_get_offset(descr);
- fseg_free_extent(inode, space, page, mtr);
+ fseg_free_extent(inode, space, zip_size, page, mtr);
return(FALSE);
}
@@ -3245,19 +3481,19 @@ fseg_free_step(
if (n == ULINT_UNDEFINED) {
/* Freeing completed: free the segment inode */
- fsp_free_seg_inode(space, inode, mtr);
+ fsp_free_seg_inode(space, zip_size, inode, mtr);
return(TRUE);
}
- fseg_free_page_low(inode, space,
+ fseg_free_page_low(inode, space, zip_size,
fseg_get_nth_frag_page_no(inode, n, mtr), mtr);
n = fseg_find_last_used_frag_page_slot(inode, mtr);
if (n == ULINT_UNDEFINED) {
/* Freeing completed: free the segment inode */
- fsp_free_seg_inode(space, inode, mtr);
+ fsp_free_seg_inode(space, zip_size, inode, mtr);
return(TRUE);
}
@@ -3265,43 +3501,47 @@ fseg_free_step(
return(FALSE);
}
-/**************************************************************************
+/**********************************************************************//**
Frees part of a segment. Differs from fseg_free_step because this function
-leaves the header page unfreed. */
-
+leaves the header page unfreed.
+@return TRUE if freeing completed, except the header page */
+UNIV_INTERN
ibool
fseg_free_step_not_header(
/*======================*/
- /* out: TRUE if freeing completed, except the
- header page */
- fseg_header_t* header, /* in: segment header which must reside on
+ fseg_header_t* header, /*!< in: segment header which must reside on
the first fragment page of the segment */
- mtr_t* mtr) /* in: mtr */
+ mtr_t* mtr) /*!< in: mtr */
{
ulint n;
ulint page;
xdes_t* descr;
fseg_inode_t* inode;
ulint space;
+ ulint flags;
+ ulint zip_size;
ulint page_no;
+ rw_lock_t* latch;
- space = buf_frame_get_space_id(header);
+ space = page_get_space_id(page_align(header));
+
+ latch = fil_space_get_latch(space, &flags);
+ zip_size = dict_table_flags_to_zip_size(flags);
ut_ad(!mutex_own(&kernel_mutex)
- || mtr_memo_contains(mtr, fil_space_get_latch(space),
- MTR_MEMO_X_LOCK));
+ || mtr_memo_contains(mtr, latch, MTR_MEMO_X_LOCK));
- mtr_x_lock(fil_space_get_latch(space), mtr);
+ mtr_x_lock(latch, mtr);
- inode = fseg_inode_get(header, mtr);
+ inode = fseg_inode_get(header, space, zip_size, mtr);
- descr = fseg_get_first_extent(inode, mtr);
+ descr = fseg_get_first_extent(inode, space, zip_size, mtr);
if (descr != NULL) {
/* Free the extent held by the segment */
page = xdes_get_offset(descr);
- fseg_free_extent(inode, space, page, mtr);
+ fseg_free_extent(inode, space, zip_size, page, mtr);
return(FALSE);
}
@@ -3316,73 +3556,37 @@ fseg_free_step_not_header(
page_no = fseg_get_nth_frag_page_no(inode, n, mtr);
- if (page_no == buf_frame_get_page_no(header)) {
+ if (page_no == page_get_page_no(page_align(header))) {
return(TRUE);
}
- fseg_free_page_low(inode, space, page_no, mtr);
+ fseg_free_page_low(inode, space, zip_size, page_no, mtr);
return(FALSE);
}
-/***********************************************************************
-Frees a segment. The freeing is performed in several mini-transactions,
-so that there is no danger of bufferfixing too many buffer pages. */
-
-void
-fseg_free(
-/*======*/
- ulint space, /* in: space id */
- ulint page_no,/* in: page number where the segment header is
- placed */
- ulint offset) /* in: byte offset of the segment header on that
- page */
-{
- mtr_t mtr;
- ibool finished;
- fseg_header_t* header;
- fil_addr_t addr;
-
- addr.page = page_no;
- addr.boffset = offset;
-
- for (;;) {
- mtr_start(&mtr);
-
- header = fut_get_ptr(space, addr, RW_X_LATCH, &mtr);
-
- finished = fseg_free_step(header, &mtr);
-
- mtr_commit(&mtr);
-
- if (finished) {
-
- return;
- }
- }
-}
-
-/**************************************************************************
+/**********************************************************************//**
Returns the first extent descriptor for a segment. We think of the extent
lists of the segment catenated in the order FSEG_FULL -> FSEG_NOT_FULL
--> FSEG_FREE. */
+-> FSEG_FREE.
+@return the first extent descriptor, or NULL if none */
static
xdes_t*
fseg_get_first_extent(
/*==================*/
- /* out: the first extent descriptor, or NULL if
- none */
- fseg_inode_t* inode, /* in: segment inode */
- mtr_t* mtr) /* in: mtr */
+ fseg_inode_t* inode, /*!< in: segment inode */
+ ulint space, /*!< in: space id */
+ ulint zip_size,/*!< in: compressed page size in bytes
+ or 0 for uncompressed pages */
+ mtr_t* mtr) /*!< in: mtr */
{
fil_addr_t first;
- ulint space;
xdes_t* descr;
ut_ad(inode && mtr);
- space = buf_frame_get_space_id(inode);
+ ut_ad(space == page_get_space_id(page_align(inode)));
first = fil_addr_null;
@@ -3403,20 +3607,20 @@ fseg_get_first_extent(
return(NULL);
}
- descr = xdes_lst_get_descriptor(space, first, mtr);
+ descr = xdes_lst_get_descriptor(space, zip_size, first, mtr);
return(descr);
}
-/***********************************************************************
-Validates a segment. */
+/*******************************************************************//**
+Validates a segment.
+@return TRUE if ok */
static
ibool
fseg_validate_low(
/*==============*/
- /* out: TRUE if ok */
- fseg_inode_t* inode, /* in: segment inode */
- mtr_t* mtr2) /* in: mtr */
+ fseg_inode_t* inode, /*!< in: segment inode */
+ mtr_t* mtr2) /*!< in: mtr */
{
ulint space;
dulint seg_id;
@@ -3426,11 +3630,10 @@ fseg_validate_low(
ulint n_used = 0;
ulint n_used2 = 0;
- ut_ad(mtr_memo_contains(mtr2, buf_block_align(inode),
- MTR_MEMO_PAGE_X_FIX));
+ ut_ad(mtr_memo_contains_page(mtr2, inode, MTR_MEMO_PAGE_X_FIX));
ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE);
- space = buf_frame_get_space_id(inode);
+ space = page_get_space_id(page_align(inode));
seg_id = mtr_read_dulint(inode + FSEG_ID, mtr2);
n_used = mtr_read_ulint(inode + FSEG_NOT_FULL_N_USED,
@@ -3443,10 +3646,15 @@ fseg_validate_low(
node_addr = flst_get_first(inode + FSEG_FREE, mtr2);
while (!fil_addr_is_null(node_addr)) {
- mtr_start(&mtr);
- mtr_x_lock(fil_space_get_latch(space), &mtr);
+ ulint flags;
+ ulint zip_size;
- descr = xdes_lst_get_descriptor(space, node_addr, &mtr);
+ mtr_start(&mtr);
+ mtr_x_lock(fil_space_get_latch(space, &flags), &mtr);
+ zip_size = dict_table_flags_to_zip_size(flags);
+
+ descr = xdes_lst_get_descriptor(space, zip_size,
+ node_addr, &mtr);
ut_a(xdes_get_n_used(descr, &mtr) == 0);
ut_a(xdes_get_state(descr, &mtr) == XDES_FSEG);
@@ -3462,10 +3670,15 @@ fseg_validate_low(
node_addr = flst_get_first(inode + FSEG_NOT_FULL, mtr2);
while (!fil_addr_is_null(node_addr)) {
- mtr_start(&mtr);
- mtr_x_lock(fil_space_get_latch(space), &mtr);
+ ulint flags;
+ ulint zip_size;
- descr = xdes_lst_get_descriptor(space, node_addr, &mtr);
+ mtr_start(&mtr);
+ mtr_x_lock(fil_space_get_latch(space, &flags), &mtr);
+ zip_size = dict_table_flags_to_zip_size(flags);
+
+ descr = xdes_lst_get_descriptor(space, zip_size,
+ node_addr, &mtr);
ut_a(xdes_get_n_used(descr, &mtr) > 0);
ut_a(xdes_get_n_used(descr, &mtr) < FSP_EXTENT_SIZE);
@@ -3484,10 +3697,15 @@ fseg_validate_low(
node_addr = flst_get_first(inode + FSEG_FULL, mtr2);
while (!fil_addr_is_null(node_addr)) {
- mtr_start(&mtr);
- mtr_x_lock(fil_space_get_latch(space), &mtr);
+ ulint flags;
+ ulint zip_size;
- descr = xdes_lst_get_descriptor(space, node_addr, &mtr);
+ mtr_start(&mtr);
+ mtr_x_lock(fil_space_get_latch(space, &flags), &mtr);
+ zip_size = dict_table_flags_to_zip_size(flags);
+
+ descr = xdes_lst_get_descriptor(space, zip_size,
+ node_addr, &mtr);
ut_a(xdes_get_n_used(descr, &mtr) == FSP_EXTENT_SIZE);
ut_a(xdes_get_state(descr, &mtr) == XDES_FSEG);
@@ -3503,39 +3721,44 @@ fseg_validate_low(
return(TRUE);
}
-/***********************************************************************
-Validates a segment. */
-
+#ifdef UNIV_DEBUG
+/*******************************************************************//**
+Validates a segment.
+@return TRUE if ok */
+UNIV_INTERN
ibool
fseg_validate(
/*==========*/
- /* out: TRUE if ok */
- fseg_header_t* header, /* in: segment header */
- mtr_t* mtr2) /* in: mtr */
+ fseg_header_t* header, /*!< in: segment header */
+ mtr_t* mtr) /*!< in: mtr */
{
fseg_inode_t* inode;
ibool ret;
ulint space;
+ ulint flags;
+ ulint zip_size;
- space = buf_frame_get_space_id(header);
+ space = page_get_space_id(page_align(header));
- mtr_x_lock(fil_space_get_latch(space), mtr2);
+ mtr_x_lock(fil_space_get_latch(space, &flags), mtr);
+ zip_size = dict_table_flags_to_zip_size(flags);
- inode = fseg_inode_get(header, mtr2);
+ inode = fseg_inode_get(header, space, zip_size, mtr);
- ret = fseg_validate_low(inode, mtr2);
+ ret = fseg_validate_low(inode, mtr);
return(ret);
}
+#endif /* UNIV_DEBUG */
-/***********************************************************************
+/*******************************************************************//**
Writes info of a segment. */
static
void
fseg_print_low(
/*===========*/
- fseg_inode_t* inode, /* in: segment inode */
- mtr_t* mtr) /* in: mtr */
+ fseg_inode_t* inode, /*!< in: segment inode */
+ mtr_t* mtr) /*!< in: mtr */
{
ulint space;
ulint seg_id_low;
@@ -3550,10 +3773,9 @@ fseg_print_low(
ulint page_no;
dulint d_var;
- ut_ad(mtr_memo_contains(mtr, buf_block_align(inode),
- MTR_MEMO_PAGE_X_FIX));
- space = buf_frame_get_space_id(inode);
- page_no = buf_frame_get_page_no(inode);
+ ut_ad(mtr_memo_contains_page(mtr, inode, MTR_MEMO_PAGE_X_FIX));
+ space = page_get_space_id(page_align(inode));
+ page_no = page_get_page_no(page_align(inode));
reserved = fseg_n_reserved_pages_low(inode, &used, mtr);
@@ -3581,40 +3803,48 @@ fseg_print_low(
(ulong) n_used);
}
-/***********************************************************************
+#ifdef UNIV_BTR_PRINT
+/*******************************************************************//**
Writes info of a segment. */
-
+UNIV_INTERN
void
fseg_print(
/*=======*/
- fseg_header_t* header, /* in: segment header */
- mtr_t* mtr) /* in: mtr */
+ fseg_header_t* header, /*!< in: segment header */
+ mtr_t* mtr) /*!< in: mtr */
{
fseg_inode_t* inode;
ulint space;
+ ulint flags;
+ ulint zip_size;
- space = buf_frame_get_space_id(header);
+ space = page_get_space_id(page_align(header));
- mtr_x_lock(fil_space_get_latch(space), mtr);
+ mtr_x_lock(fil_space_get_latch(space, &flags), mtr);
+ zip_size = dict_table_flags_to_zip_size(flags);
- inode = fseg_inode_get(header, mtr);
+ inode = fseg_inode_get(header, space, zip_size, mtr);
fseg_print_low(inode, mtr);
}
+#endif /* UNIV_BTR_PRINT */
-/***********************************************************************
-Validates the file space system and its segments. */
-
+/*******************************************************************//**
+Validates the file space system and its segments.
+@return TRUE if ok */
+UNIV_INTERN
ibool
fsp_validate(
/*=========*/
- /* out: TRUE if ok */
- ulint space) /* in: space id */
+ ulint space) /*!< in: space id */
{
fsp_header_t* header;
fseg_inode_t* seg_inode;
page_t* seg_inode_page;
+ rw_lock_t* latch;
ulint size;
+ ulint flags;
+ ulint zip_size;
ulint free_limit;
ulint frag_n_used;
mtr_t mtr;
@@ -3630,15 +3860,21 @@ fsp_validate(
ulint seg_inode_len_free;
ulint seg_inode_len_full;
+ latch = fil_space_get_latch(space, &flags);
+ zip_size = dict_table_flags_to_zip_size(flags);
+ ut_a(ut_is_2pow(zip_size));
+ ut_a(zip_size <= UNIV_PAGE_SIZE);
+ ut_a(!zip_size || zip_size >= PAGE_ZIP_MIN_SIZE);
+
/* Start first a mini-transaction mtr2 to lock out all other threads
from the fsp system */
mtr_start(&mtr2);
- mtr_x_lock(fil_space_get_latch(space), &mtr2);
+ mtr_x_lock(latch, &mtr2);
mtr_start(&mtr);
- mtr_x_lock(fil_space_get_latch(space), &mtr);
+ mtr_x_lock(latch, &mtr);
- header = fsp_get_space_header(space, &mtr);
+ header = fsp_get_space_header(space, zip_size, &mtr);
size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, &mtr);
free_limit = mtr_read_ulint(header + FSP_FREE_LIMIT,
@@ -3663,19 +3899,20 @@ fsp_validate(
/* Validate FSP_FREE list */
mtr_start(&mtr);
- mtr_x_lock(fil_space_get_latch(space), &mtr);
+ mtr_x_lock(latch, &mtr);
- header = fsp_get_space_header(space, &mtr);
+ header = fsp_get_space_header(space, zip_size, &mtr);
node_addr = flst_get_first(header + FSP_FREE, &mtr);
mtr_commit(&mtr);
while (!fil_addr_is_null(node_addr)) {
mtr_start(&mtr);
- mtr_x_lock(fil_space_get_latch(space), &mtr);
+ mtr_x_lock(latch, &mtr);
descr_count++;
- descr = xdes_lst_get_descriptor(space, node_addr, &mtr);
+ descr = xdes_lst_get_descriptor(space, zip_size,
+ node_addr, &mtr);
ut_a(xdes_get_n_used(descr, &mtr) == 0);
ut_a(xdes_get_state(descr, &mtr) == XDES_FREE);
@@ -3686,19 +3923,20 @@ fsp_validate(
/* Validate FSP_FREE_FRAG list */
mtr_start(&mtr);
- mtr_x_lock(fil_space_get_latch(space), &mtr);
+ mtr_x_lock(latch, &mtr);
- header = fsp_get_space_header(space, &mtr);
+ header = fsp_get_space_header(space, zip_size, &mtr);
node_addr = flst_get_first(header + FSP_FREE_FRAG, &mtr);
mtr_commit(&mtr);
while (!fil_addr_is_null(node_addr)) {
mtr_start(&mtr);
- mtr_x_lock(fil_space_get_latch(space), &mtr);
+ mtr_x_lock(latch, &mtr);
descr_count++;
- descr = xdes_lst_get_descriptor(space, node_addr, &mtr);
+ descr = xdes_lst_get_descriptor(space, zip_size,
+ node_addr, &mtr);
ut_a(xdes_get_n_used(descr, &mtr) > 0);
ut_a(xdes_get_n_used(descr, &mtr) < FSP_EXTENT_SIZE);
@@ -3712,19 +3950,20 @@ fsp_validate(
/* Validate FSP_FULL_FRAG list */
mtr_start(&mtr);
- mtr_x_lock(fil_space_get_latch(space), &mtr);
+ mtr_x_lock(latch, &mtr);
- header = fsp_get_space_header(space, &mtr);
+ header = fsp_get_space_header(space, zip_size, &mtr);
node_addr = flst_get_first(header + FSP_FULL_FRAG, &mtr);
mtr_commit(&mtr);
while (!fil_addr_is_null(node_addr)) {
mtr_start(&mtr);
- mtr_x_lock(fil_space_get_latch(space), &mtr);
+ mtr_x_lock(latch, &mtr);
descr_count++;
- descr = xdes_lst_get_descriptor(space, node_addr, &mtr);
+ descr = xdes_lst_get_descriptor(space, zip_size,
+ node_addr, &mtr);
ut_a(xdes_get_n_used(descr, &mtr) == FSP_EXTENT_SIZE);
ut_a(xdes_get_state(descr, &mtr) == XDES_FULL_FRAG);
@@ -3735,9 +3974,9 @@ fsp_validate(
/* Validate segments */
mtr_start(&mtr);
- mtr_x_lock(fil_space_get_latch(space), &mtr);
+ mtr_x_lock(latch, &mtr);
- header = fsp_get_space_header(space, &mtr);
+ header = fsp_get_space_header(space, zip_size, &mtr);
node_addr = flst_get_first(header + FSP_SEG_INODES_FULL, &mtr);
@@ -3747,20 +3986,19 @@ fsp_validate(
while (!fil_addr_is_null(node_addr)) {
- for (n = 0; n < FSP_SEG_INODES_PER_PAGE; n++) {
-
+ n = 0;
+ do {
mtr_start(&mtr);
- mtr_x_lock(fil_space_get_latch(space), &mtr);
+ mtr_x_lock(latch, &mtr);
seg_inode_page = fut_get_ptr(
- space, node_addr, RW_X_LATCH, &mtr)
+ space, zip_size, node_addr, RW_X_LATCH, &mtr)
- FSEG_INODE_PAGE_NODE;
seg_inode = fsp_seg_inode_page_get_nth_inode(
- seg_inode_page, n, &mtr);
- ut_a(ut_dulint_cmp(
- mach_read_from_8(seg_inode + FSEG_ID),
- ut_dulint_zero) != 0);
+ seg_inode_page, n, zip_size, &mtr);
+ ut_a(!ut_dulint_is_zero(
+ mach_read_from_8(seg_inode + FSEG_ID)));
fseg_validate_low(seg_inode, &mtr);
descr_count += flst_get_len(seg_inode + FSEG_FREE,
@@ -3775,15 +4013,15 @@ fsp_validate(
next_node_addr = flst_get_next_addr(
seg_inode_page + FSEG_INODE_PAGE_NODE, &mtr);
mtr_commit(&mtr);
- }
+ } while (++n < FSP_SEG_INODES_PER_PAGE(zip_size));
node_addr = next_node_addr;
}
mtr_start(&mtr);
- mtr_x_lock(fil_space_get_latch(space), &mtr);
+ mtr_x_lock(latch, &mtr);
- header = fsp_get_space_header(space, &mtr);
+ header = fsp_get_space_header(space, zip_size, &mtr);
node_addr = flst_get_first(header + FSP_SEG_INODES_FREE, &mtr);
@@ -3793,20 +4031,20 @@ fsp_validate(
while (!fil_addr_is_null(node_addr)) {
- for (n = 0; n < FSP_SEG_INODES_PER_PAGE; n++) {
+ n = 0;
+ do {
mtr_start(&mtr);
- mtr_x_lock(fil_space_get_latch(space), &mtr);
+ mtr_x_lock(latch, &mtr);
seg_inode_page = fut_get_ptr(
- space, node_addr, RW_X_LATCH, &mtr)
+ space, zip_size, node_addr, RW_X_LATCH, &mtr)
- FSEG_INODE_PAGE_NODE;
seg_inode = fsp_seg_inode_page_get_nth_inode(
- seg_inode_page, n, &mtr);
- if (ut_dulint_cmp(
- mach_read_from_8(seg_inode + FSEG_ID),
- ut_dulint_zero) != 0) {
+ seg_inode_page, n, zip_size, &mtr);
+ if (!ut_dulint_is_zero(
+ mach_read_from_8(seg_inode + FSEG_ID))) {
fseg_validate_low(seg_inode, &mtr);
descr_count += flst_get_len(
@@ -3822,16 +4060,23 @@ fsp_validate(
next_node_addr = flst_get_next_addr(
seg_inode_page + FSEG_INODE_PAGE_NODE, &mtr);
mtr_commit(&mtr);
- }
+ } while (++n < FSP_SEG_INODES_PER_PAGE(zip_size));
node_addr = next_node_addr;
}
ut_a(descr_count * FSP_EXTENT_SIZE == free_limit);
- ut_a(n_used + n_full_frag_pages
- == n_used2 + 2* ((free_limit + XDES_DESCRIBED_PER_PAGE - 1)
- / XDES_DESCRIBED_PER_PAGE)
- + seg_inode_len_full + seg_inode_len_free);
+ if (!zip_size) {
+ ut_a(n_used + n_full_frag_pages
+ == n_used2 + 2 * ((free_limit + (UNIV_PAGE_SIZE - 1))
+ / UNIV_PAGE_SIZE)
+ + seg_inode_len_full + seg_inode_len_free);
+ } else {
+ ut_a(n_used + n_full_frag_pages
+ == n_used2 + 2 * ((free_limit + (zip_size - 1))
+ / zip_size)
+ + seg_inode_len_full + seg_inode_len_free);
+ }
ut_a(frag_n_used == n_used);
mtr_commit(&mtr2);
@@ -3839,17 +4084,20 @@ fsp_validate(
return(TRUE);
}
-/***********************************************************************
+/*******************************************************************//**
Prints info of a file space. */
-
+UNIV_INTERN
void
fsp_print(
/*======*/
- ulint space) /* in: space id */
+ ulint space) /*!< in: space id */
{
fsp_header_t* header;
fseg_inode_t* seg_inode;
page_t* seg_inode_page;
+ rw_lock_t* latch;
+ ulint flags;
+ ulint zip_size;
ulint size;
ulint free_limit;
ulint frag_n_used;
@@ -3866,18 +4114,21 @@ fsp_print(
mtr_t mtr;
mtr_t mtr2;
+ latch = fil_space_get_latch(space, &flags);
+ zip_size = dict_table_flags_to_zip_size(flags);
+
/* Start first a mini-transaction mtr2 to lock out all other threads
from the fsp system */
mtr_start(&mtr2);
- mtr_x_lock(fil_space_get_latch(space), &mtr2);
+ mtr_x_lock(latch, &mtr2);
mtr_start(&mtr);
- mtr_x_lock(fil_space_get_latch(space), &mtr);
+ mtr_x_lock(latch, &mtr);
- header = fsp_get_space_header(space, &mtr);
+ header = fsp_get_space_header(space, zip_size, &mtr);
size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, &mtr);
@@ -3900,7 +4151,7 @@ fsp_print(
"not full frag extents %lu: used pages %lu,"
" full frag extents %lu\n"
"first seg id not used %lu %lu\n",
- (long) space,
+ (ulong) space,
(ulong) size, (ulong) free_limit, (ulong) n_free,
(ulong) n_free_frag, (ulong) frag_n_used, (ulong) n_full_frag,
(ulong) seg_id_high, (ulong) seg_id_low);
@@ -3910,9 +4161,9 @@ fsp_print(
/* Print segments */
mtr_start(&mtr);
- mtr_x_lock(fil_space_get_latch(space), &mtr);
+ mtr_x_lock(latch, &mtr);
- header = fsp_get_space_header(space, &mtr);
+ header = fsp_get_space_header(space, zip_size, &mtr);
node_addr = flst_get_first(header + FSP_SEG_INODES_FULL, &mtr);
@@ -3920,20 +4171,21 @@ fsp_print(
while (!fil_addr_is_null(node_addr)) {
- for (n = 0; n < FSP_SEG_INODES_PER_PAGE; n++) {
+ n = 0;
+
+ do {
mtr_start(&mtr);
- mtr_x_lock(fil_space_get_latch(space), &mtr);
+ mtr_x_lock(latch, &mtr);
seg_inode_page = fut_get_ptr(
- space, node_addr, RW_X_LATCH, &mtr)
+ space, zip_size, node_addr, RW_X_LATCH, &mtr)
- FSEG_INODE_PAGE_NODE;
seg_inode = fsp_seg_inode_page_get_nth_inode(
- seg_inode_page, n, &mtr);
- ut_a(ut_dulint_cmp(
- mach_read_from_8(seg_inode + FSEG_ID),
- ut_dulint_zero) != 0);
+ seg_inode_page, n, zip_size, &mtr);
+ ut_a(!ut_dulint_is_zero(
+ mach_read_from_8(seg_inode + FSEG_ID)));
fseg_print_low(seg_inode, &mtr);
n_segs++;
@@ -3941,15 +4193,15 @@ fsp_print(
next_node_addr = flst_get_next_addr(
seg_inode_page + FSEG_INODE_PAGE_NODE, &mtr);
mtr_commit(&mtr);
- }
+ } while (++n < FSP_SEG_INODES_PER_PAGE(zip_size));
node_addr = next_node_addr;
}
mtr_start(&mtr);
- mtr_x_lock(fil_space_get_latch(space), &mtr);
+ mtr_x_lock(latch, &mtr);
- header = fsp_get_space_header(space, &mtr);
+ header = fsp_get_space_header(space, zip_size, &mtr);
node_addr = flst_get_first(header + FSP_SEG_INODES_FREE, &mtr);
@@ -3957,20 +4209,21 @@ fsp_print(
while (!fil_addr_is_null(node_addr)) {
- for (n = 0; n < FSP_SEG_INODES_PER_PAGE; n++) {
+ n = 0;
+
+ do {
mtr_start(&mtr);
- mtr_x_lock(fil_space_get_latch(space), &mtr);
+ mtr_x_lock(latch, &mtr);
seg_inode_page = fut_get_ptr(
- space, node_addr, RW_X_LATCH, &mtr)
+ space, zip_size, node_addr, RW_X_LATCH, &mtr)
- FSEG_INODE_PAGE_NODE;
seg_inode = fsp_seg_inode_page_get_nth_inode(
- seg_inode_page, n, &mtr);
- if (ut_dulint_cmp(
- mach_read_from_8(seg_inode + FSEG_ID),
- ut_dulint_zero) != 0) {
+ seg_inode_page, n, zip_size, &mtr);
+ if (!ut_dulint_is_zero(
+ mach_read_from_8(seg_inode + FSEG_ID))) {
fseg_print_low(seg_inode, &mtr);
n_segs++;
@@ -3979,7 +4232,7 @@ fsp_print(
next_node_addr = flst_get_next_addr(
seg_inode_page + FSEG_INODE_PAGE_NODE, &mtr);
mtr_commit(&mtr);
- }
+ } while (++n < FSP_SEG_INODES_PER_PAGE(zip_size));
node_addr = next_node_addr;
}
@@ -3988,3 +4241,4 @@ fsp_print(
fprintf(stderr, "NUMBER of file segments: %lu\n", (ulong) n_segs);
}
+#endif /* !UNIV_HOTBACKUP */
diff --git a/storage/innodb_plugin/fut/fut0fut.c b/storage/innodb_plugin/fut/fut0fut.c
new file mode 100644
index 00000000000..20b45a575e6
--- /dev/null
+++ b/storage/innodb_plugin/fut/fut0fut.c
@@ -0,0 +1,31 @@
+/*****************************************************************************
+
+Copyright (c) 1995, 2009, Innobase Oy. All Rights Reserved.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; version 2 of the License.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place, Suite 330, Boston, MA 02111-1307 USA
+
+*****************************************************************************/
+
+/******************************************************************//**
+@file fut/fut0fut.c
+File-based utilities
+
+Created 12/13/1995 Heikki Tuuri
+***********************************************************************/
+
+#include "fut0fut.h"
+
+#ifdef UNIV_NONINL
+#include "fut0fut.ic"
+#endif
+
diff --git a/storage/innobase/fut/fut0lst.c b/storage/innodb_plugin/fut/fut0lst.c
similarity index 61%
rename from storage/innobase/fut/fut0lst.c
rename to storage/innodb_plugin/fut/fut0lst.c
index 75fa8bf5552..a1e21c22725 100644
--- a/storage/innobase/fut/fut0lst.c
+++ b/storage/innodb_plugin/fut/fut0lst.c
@@ -1,7 +1,24 @@
-/**********************************************************************
-File-based list utilities
+/*****************************************************************************
-(c) 1995 Innobase Oy
+Copyright (c) 1995, 2009, Innobase Oy. All Rights Reserved.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; version 2 of the License.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place, Suite 330, Boston, MA 02111-1307 USA
+
+*****************************************************************************/
+
+/******************************************************************//**
+@file fut/fut0lst.c
+File-based list utilities
Created 11/28/1995 Heikki Tuuri
***********************************************************************/
@@ -13,18 +30,18 @@ Created 11/28/1995 Heikki Tuuri
#endif
#include "buf0buf.h"
+#include "page0page.h"
-
-/************************************************************************
+/********************************************************************//**
Adds a node to an empty list. */
static
void
flst_add_to_empty(
/*==============*/
- flst_base_node_t* base, /* in: pointer to base node of
+ flst_base_node_t* base, /*!< in: pointer to base node of
empty list */
- flst_node_t* node, /* in: node to add */
- mtr_t* mtr) /* in: mini-transaction handle */
+ flst_node_t* node, /*!< in: node to add */
+ mtr_t* mtr) /*!< in: mini-transaction handle */
{
ulint space;
fil_addr_t node_addr;
@@ -32,10 +49,8 @@ flst_add_to_empty(
ut_ad(mtr && base && node);
ut_ad(base != node);
- ut_ad(mtr_memo_contains(mtr, buf_block_align(base),
- MTR_MEMO_PAGE_X_FIX));
- ut_ad(mtr_memo_contains(mtr, buf_block_align(node),
- MTR_MEMO_PAGE_X_FIX));
+ ut_ad(mtr_memo_contains_page(mtr, base, MTR_MEMO_PAGE_X_FIX));
+ ut_ad(mtr_memo_contains_page(mtr, node, MTR_MEMO_PAGE_X_FIX));
len = flst_get_len(base, mtr);
ut_a(len == 0);
@@ -53,15 +68,15 @@ flst_add_to_empty(
mlog_write_ulint(base + FLST_LEN, len + 1, MLOG_4BYTES, mtr);
}
-/************************************************************************
+/********************************************************************//**
Adds a node as the last node in a list. */
-
+UNIV_INTERN
void
flst_add_last(
/*==========*/
- flst_base_node_t* base, /* in: pointer to base node of list */
- flst_node_t* node, /* in: node to add */
- mtr_t* mtr) /* in: mini-transaction handle */
+ flst_base_node_t* base, /*!< in: pointer to base node of list */
+ flst_node_t* node, /*!< in: node to add */
+ mtr_t* mtr) /*!< in: mini-transaction handle */
{
ulint space;
fil_addr_t node_addr;
@@ -71,10 +86,8 @@ flst_add_last(
ut_ad(mtr && base && node);
ut_ad(base != node);
- ut_ad(mtr_memo_contains(mtr, buf_block_align(base),
- MTR_MEMO_PAGE_X_FIX));
- ut_ad(mtr_memo_contains(mtr, buf_block_align(node),
- MTR_MEMO_PAGE_X_FIX));
+ ut_ad(mtr_memo_contains_page(mtr, base, MTR_MEMO_PAGE_X_FIX));
+ ut_ad(mtr_memo_contains_page(mtr, node, MTR_MEMO_PAGE_X_FIX));
len = flst_get_len(base, mtr);
last_addr = flst_get_last(base, mtr);
@@ -83,10 +96,12 @@ flst_add_last(
/* If the list is not empty, call flst_insert_after */
if (len != 0) {
if (last_addr.page == node_addr.page) {
- last_node = buf_frame_align(node) + last_addr.boffset;
+ last_node = page_align(node) + last_addr.boffset;
} else {
- last_node = fut_get_ptr(space, last_addr, RW_X_LATCH,
- mtr);
+ ulint zip_size = fil_space_get_zip_size(space);
+
+ last_node = fut_get_ptr(space, zip_size, last_addr,
+ RW_X_LATCH, mtr);
}
flst_insert_after(base, last_node, node, mtr);
@@ -96,15 +111,15 @@ flst_add_last(
}
}
-/************************************************************************
+/********************************************************************//**
Adds a node as the first node in a list. */
-
+UNIV_INTERN
void
flst_add_first(
/*===========*/
- flst_base_node_t* base, /* in: pointer to base node of list */
- flst_node_t* node, /* in: node to add */
- mtr_t* mtr) /* in: mini-transaction handle */
+ flst_base_node_t* base, /*!< in: pointer to base node of list */
+ flst_node_t* node, /*!< in: node to add */
+ mtr_t* mtr) /*!< in: mini-transaction handle */
{
ulint space;
fil_addr_t node_addr;
@@ -114,10 +129,8 @@ flst_add_first(
ut_ad(mtr && base && node);
ut_ad(base != node);
- ut_ad(mtr_memo_contains(mtr, buf_block_align(base),
- MTR_MEMO_PAGE_X_FIX));
- ut_ad(mtr_memo_contains(mtr, buf_block_align(node),
- MTR_MEMO_PAGE_X_FIX));
+ ut_ad(mtr_memo_contains_page(mtr, base, MTR_MEMO_PAGE_X_FIX));
+ ut_ad(mtr_memo_contains_page(mtr, node, MTR_MEMO_PAGE_X_FIX));
len = flst_get_len(base, mtr);
first_addr = flst_get_first(base, mtr);
@@ -126,10 +139,11 @@ flst_add_first(
/* If the list is not empty, call flst_insert_before */
if (len != 0) {
if (first_addr.page == node_addr.page) {
- first_node = buf_frame_align(node)
- + first_addr.boffset;
+ first_node = page_align(node) + first_addr.boffset;
} else {
- first_node = fut_get_ptr(space, first_addr,
+ ulint zip_size = fil_space_get_zip_size(space);
+
+ first_node = fut_get_ptr(space, zip_size, first_addr,
RW_X_LATCH, mtr);
}
@@ -140,16 +154,16 @@ flst_add_first(
}
}
-/************************************************************************
+/********************************************************************//**
Inserts a node after another in a list. */
-
+UNIV_INTERN
void
flst_insert_after(
/*==============*/
- flst_base_node_t* base, /* in: pointer to base node of list */
- flst_node_t* node1, /* in: node to insert after */
- flst_node_t* node2, /* in: node to add */
- mtr_t* mtr) /* in: mini-transaction handle */
+ flst_base_node_t* base, /*!< in: pointer to base node of list */
+ flst_node_t* node1, /*!< in: node to insert after */
+ flst_node_t* node2, /*!< in: node to add */
+ mtr_t* mtr) /*!< in: mini-transaction handle */
{
ulint space;
fil_addr_t node1_addr;
@@ -162,12 +176,9 @@ flst_insert_after(
ut_ad(base != node1);
ut_ad(base != node2);
ut_ad(node2 != node1);
- ut_ad(mtr_memo_contains(mtr, buf_block_align(base),
- MTR_MEMO_PAGE_X_FIX));
- ut_ad(mtr_memo_contains(mtr, buf_block_align(node1),
- MTR_MEMO_PAGE_X_FIX));
- ut_ad(mtr_memo_contains(mtr, buf_block_align(node2),
- MTR_MEMO_PAGE_X_FIX));
+ ut_ad(mtr_memo_contains_page(mtr, base, MTR_MEMO_PAGE_X_FIX));
+ ut_ad(mtr_memo_contains_page(mtr, node1, MTR_MEMO_PAGE_X_FIX));
+ ut_ad(mtr_memo_contains_page(mtr, node2, MTR_MEMO_PAGE_X_FIX));
buf_ptr_get_fsp_addr(node1, &space, &node1_addr);
buf_ptr_get_fsp_addr(node2, &space, &node2_addr);
@@ -180,7 +191,10 @@ flst_insert_after(
if (!fil_addr_is_null(node3_addr)) {
/* Update prev field of node3 */
- node3 = fut_get_ptr(space, node3_addr, RW_X_LATCH, mtr);
+ ulint zip_size = fil_space_get_zip_size(space);
+
+ node3 = fut_get_ptr(space, zip_size,
+ node3_addr, RW_X_LATCH, mtr);
flst_write_addr(node3 + FLST_PREV, node2_addr, mtr);
} else {
/* node1 was last in list: update last field in base */
@@ -195,16 +209,16 @@ flst_insert_after(
mlog_write_ulint(base + FLST_LEN, len + 1, MLOG_4BYTES, mtr);
}
-/************************************************************************
+/********************************************************************//**
Inserts a node before another in a list. */
-
+UNIV_INTERN
void
flst_insert_before(
/*===============*/
- flst_base_node_t* base, /* in: pointer to base node of list */
- flst_node_t* node2, /* in: node to insert */
- flst_node_t* node3, /* in: node to insert before */
- mtr_t* mtr) /* in: mini-transaction handle */
+ flst_base_node_t* base, /*!< in: pointer to base node of list */
+ flst_node_t* node2, /*!< in: node to insert */
+ flst_node_t* node3, /*!< in: node to insert before */
+ mtr_t* mtr) /*!< in: mini-transaction handle */
{
ulint space;
flst_node_t* node1;
@@ -217,12 +231,9 @@ flst_insert_before(
ut_ad(base != node2);
ut_ad(base != node3);
ut_ad(node2 != node3);
- ut_ad(mtr_memo_contains(mtr, buf_block_align(base),
- MTR_MEMO_PAGE_X_FIX));
- ut_ad(mtr_memo_contains(mtr, buf_block_align(node2),
- MTR_MEMO_PAGE_X_FIX));
- ut_ad(mtr_memo_contains(mtr, buf_block_align(node3),
- MTR_MEMO_PAGE_X_FIX));
+ ut_ad(mtr_memo_contains_page(mtr, base, MTR_MEMO_PAGE_X_FIX));
+ ut_ad(mtr_memo_contains_page(mtr, node2, MTR_MEMO_PAGE_X_FIX));
+ ut_ad(mtr_memo_contains_page(mtr, node3, MTR_MEMO_PAGE_X_FIX));
buf_ptr_get_fsp_addr(node2, &space, &node2_addr);
buf_ptr_get_fsp_addr(node3, &space, &node3_addr);
@@ -234,8 +245,10 @@ flst_insert_before(
flst_write_addr(node2 + FLST_NEXT, node3_addr, mtr);
if (!fil_addr_is_null(node1_addr)) {
+ ulint zip_size = fil_space_get_zip_size(space);
/* Update next field of node1 */
- node1 = fut_get_ptr(space, node1_addr, RW_X_LATCH, mtr);
+ node1 = fut_get_ptr(space, zip_size, node1_addr,
+ RW_X_LATCH, mtr);
flst_write_addr(node1 + FLST_NEXT, node2_addr, mtr);
} else {
/* node3 was first in list: update first field in base */
@@ -250,17 +263,18 @@ flst_insert_before(
mlog_write_ulint(base + FLST_LEN, len + 1, MLOG_4BYTES, mtr);
}
-/************************************************************************
+/********************************************************************//**
Removes a node. */
-
+UNIV_INTERN
void
flst_remove(
/*========*/
- flst_base_node_t* base, /* in: pointer to base node of list */
- flst_node_t* node2, /* in: node to remove */
- mtr_t* mtr) /* in: mini-transaction handle */
+ flst_base_node_t* base, /*!< in: pointer to base node of list */
+ flst_node_t* node2, /*!< in: node to remove */
+ mtr_t* mtr) /*!< in: mini-transaction handle */
{
ulint space;
+ ulint zip_size;
flst_node_t* node1;
fil_addr_t node1_addr;
fil_addr_t node2_addr;
@@ -269,12 +283,11 @@ flst_remove(
ulint len;
ut_ad(mtr && node2 && base);
- ut_ad(mtr_memo_contains(mtr, buf_block_align(base),
- MTR_MEMO_PAGE_X_FIX));
- ut_ad(mtr_memo_contains(mtr, buf_block_align(node2),
- MTR_MEMO_PAGE_X_FIX));
+ ut_ad(mtr_memo_contains_page(mtr, base, MTR_MEMO_PAGE_X_FIX));
+ ut_ad(mtr_memo_contains_page(mtr, node2, MTR_MEMO_PAGE_X_FIX));
buf_ptr_get_fsp_addr(node2, &space, &node2_addr);
+ zip_size = fil_space_get_zip_size(space);
node1_addr = flst_get_prev_addr(node2, mtr);
node3_addr = flst_get_next_addr(node2, mtr);
@@ -285,10 +298,10 @@ flst_remove(
if (node1_addr.page == node2_addr.page) {
- node1 = buf_frame_align(node2) + node1_addr.boffset;
+ node1 = page_align(node2) + node1_addr.boffset;
} else {
- node1 = fut_get_ptr(space, node1_addr, RW_X_LATCH,
- mtr);
+ node1 = fut_get_ptr(space, zip_size,
+ node1_addr, RW_X_LATCH, mtr);
}
ut_ad(node1 != node2);
@@ -304,10 +317,10 @@ flst_remove(
if (node3_addr.page == node2_addr.page) {
- node3 = buf_frame_align(node2) + node3_addr.boffset;
+ node3 = page_align(node2) + node3_addr.boffset;
} else {
- node3 = fut_get_ptr(space, node3_addr, RW_X_LATCH,
- mtr);
+ node3 = fut_get_ptr(space, zip_size,
+ node3_addr, RW_X_LATCH, mtr);
}
ut_ad(node2 != node3);
@@ -325,19 +338,19 @@ flst_remove(
mlog_write_ulint(base + FLST_LEN, len - 1, MLOG_4BYTES, mtr);
}
-/************************************************************************
+/********************************************************************//**
Cuts off the tail of the list, including the node given. The number of
nodes which will be removed must be provided by the caller, as this function
does not measure the length of the tail. */
-
+UNIV_INTERN
void
flst_cut_end(
/*=========*/
- flst_base_node_t* base, /* in: pointer to base node of list */
- flst_node_t* node2, /* in: first node to remove */
- ulint n_nodes,/* in: number of nodes to remove,
+ flst_base_node_t* base, /*!< in: pointer to base node of list */
+ flst_node_t* node2, /*!< in: first node to remove */
+ ulint n_nodes,/*!< in: number of nodes to remove,
must be >= 1 */
- mtr_t* mtr) /* in: mini-transaction handle */
+ mtr_t* mtr) /*!< in: mini-transaction handle */
{
ulint space;
flst_node_t* node1;
@@ -346,10 +359,8 @@ flst_cut_end(
ulint len;
ut_ad(mtr && node2 && base);
- ut_ad(mtr_memo_contains(mtr, buf_block_align(base),
- MTR_MEMO_PAGE_X_FIX));
- ut_ad(mtr_memo_contains(mtr, buf_block_align(node2),
- MTR_MEMO_PAGE_X_FIX));
+ ut_ad(mtr_memo_contains_page(mtr, base, MTR_MEMO_PAGE_X_FIX));
+ ut_ad(mtr_memo_contains_page(mtr, node2, MTR_MEMO_PAGE_X_FIX));
ut_ad(n_nodes > 0);
buf_ptr_get_fsp_addr(node2, &space, &node2_addr);
@@ -362,10 +373,11 @@ flst_cut_end(
if (node1_addr.page == node2_addr.page) {
- node1 = buf_frame_align(node2) + node1_addr.boffset;
+ node1 = page_align(node2) + node1_addr.boffset;
} else {
- node1 = fut_get_ptr(space, node1_addr, RW_X_LATCH,
- mtr);
+ node1 = fut_get_ptr(space,
+ fil_space_get_zip_size(space),
+ node1_addr, RW_X_LATCH, mtr);
}
flst_write_addr(node1 + FLST_NEXT, fil_addr_null, mtr);
@@ -383,28 +395,26 @@ flst_cut_end(
mlog_write_ulint(base + FLST_LEN, len - n_nodes, MLOG_4BYTES, mtr);
}
-/************************************************************************
+/********************************************************************//**
Cuts off the tail of the list, not including the given node. The number of
nodes which will be removed must be provided by the caller, as this function
does not measure the length of the tail. */
-
+UNIV_INTERN
void
flst_truncate_end(
/*==============*/
- flst_base_node_t* base, /* in: pointer to base node of list */
- flst_node_t* node2, /* in: first node not to remove */
- ulint n_nodes,/* in: number of nodes to remove */
- mtr_t* mtr) /* in: mini-transaction handle */
+ flst_base_node_t* base, /*!< in: pointer to base node of list */
+ flst_node_t* node2, /*!< in: first node not to remove */
+ ulint n_nodes,/*!< in: number of nodes to remove */
+ mtr_t* mtr) /*!< in: mini-transaction handle */
{
fil_addr_t node2_addr;
ulint len;
ulint space;
ut_ad(mtr && node2 && base);
- ut_ad(mtr_memo_contains(mtr, buf_block_align(base),
- MTR_MEMO_PAGE_X_FIX));
- ut_ad(mtr_memo_contains(mtr, buf_block_align(node2),
- MTR_MEMO_PAGE_X_FIX));
+ ut_ad(mtr_memo_contains_page(mtr, base, MTR_MEMO_PAGE_X_FIX));
+ ut_ad(mtr_memo_contains_page(mtr, node2, MTR_MEMO_PAGE_X_FIX));
if (n_nodes == 0) {
ut_ad(fil_addr_is_null(flst_get_next_addr(node2, mtr)));
@@ -426,27 +436,27 @@ flst_truncate_end(
mlog_write_ulint(base + FLST_LEN, len - n_nodes, MLOG_4BYTES, mtr);
}
-/************************************************************************
-Validates a file-based list. */
-
+/********************************************************************//**
+Validates a file-based list.
+@return TRUE if ok */
+UNIV_INTERN
ibool
flst_validate(
/*==========*/
- /* out: TRUE if ok */
- flst_base_node_t* base, /* in: pointer to base node of list */
- mtr_t* mtr1) /* in: mtr */
+ const flst_base_node_t* base, /*!< in: pointer to base node of list */
+ mtr_t* mtr1) /*!< in: mtr */
{
- ulint space;
- flst_node_t* node;
- fil_addr_t node_addr;
- fil_addr_t base_addr;
- ulint len;
- ulint i;
- mtr_t mtr2;
+ ulint space;
+ ulint zip_size;
+ const flst_node_t* node;
+ fil_addr_t node_addr;
+ fil_addr_t base_addr;
+ ulint len;
+ ulint i;
+ mtr_t mtr2;
ut_ad(base);
- ut_ad(mtr_memo_contains(mtr1, buf_block_align(base),
- MTR_MEMO_PAGE_X_FIX));
+ ut_ad(mtr_memo_contains_page(mtr1, base, MTR_MEMO_PAGE_X_FIX));
/* We use two mini-transaction handles: the first is used to
lock the base node, and prevent other threads from modifying the
@@ -457,6 +467,7 @@ flst_validate(
/* Find out the space id */
buf_ptr_get_fsp_addr(base, &space, &base_addr);
+ zip_size = fil_space_get_zip_size(space);
len = flst_get_len(base, mtr1);
node_addr = flst_get_first(base, mtr1);
@@ -464,7 +475,8 @@ flst_validate(
for (i = 0; i < len; i++) {
mtr_start(&mtr2);
- node = fut_get_ptr(space, node_addr, RW_X_LATCH, &mtr2);
+ node = fut_get_ptr(space, zip_size,
+ node_addr, RW_X_LATCH, &mtr2);
node_addr = flst_get_next_addr(node, &mtr2);
mtr_commit(&mtr2); /* Commit mtr2 each round to prevent buffer
@@ -478,7 +490,8 @@ flst_validate(
for (i = 0; i < len; i++) {
mtr_start(&mtr2);
- node = fut_get_ptr(space, node_addr, RW_X_LATCH, &mtr2);
+ node = fut_get_ptr(space, zip_size,
+ node_addr, RW_X_LATCH, &mtr2);
node_addr = flst_get_prev_addr(node, &mtr2);
mtr_commit(&mtr2); /* Commit mtr2 each round to prevent buffer
@@ -490,29 +503,28 @@ flst_validate(
return(TRUE);
}
-/************************************************************************
+/********************************************************************//**
Prints info of a file-based list. */
-
+UNIV_INTERN
void
flst_print(
/*=======*/
- flst_base_node_t* base, /* in: pointer to base node of list */
- mtr_t* mtr) /* in: mtr */
+ const flst_base_node_t* base, /*!< in: pointer to base node of list */
+ mtr_t* mtr) /*!< in: mtr */
{
- buf_frame_t* frame;
- ulint len;
+ const buf_frame_t* frame;
+ ulint len;
ut_ad(base && mtr);
- ut_ad(mtr_memo_contains(mtr, buf_block_align(base),
- MTR_MEMO_PAGE_X_FIX));
- frame = buf_frame_align(base);
+ ut_ad(mtr_memo_contains_page(mtr, base, MTR_MEMO_PAGE_X_FIX));
+ frame = page_align((byte*) base);
len = flst_get_len(base, mtr);
fprintf(stderr,
"FILE-BASED LIST:\n"
"Base node in space %lu page %lu byte offset %lu; len %lu\n",
- (ulong) buf_frame_get_space_id(frame),
- (ulong) buf_frame_get_page_no(frame),
- (ulong) (base - frame), (ulong) len);
+ (ulong) page_get_space_id(frame),
+ (ulong) page_get_page_no(frame),
+ (ulong) page_offset(base), (ulong) len);
}
diff --git a/storage/innodb_plugin/ha/ha0ha.c b/storage/innodb_plugin/ha/ha0ha.c
new file mode 100644
index 00000000000..cb5e541b55d
--- /dev/null
+++ b/storage/innodb_plugin/ha/ha0ha.c
@@ -0,0 +1,441 @@
+/*****************************************************************************
+
+Copyright (c) 1994, 2009, Innobase Oy. All Rights Reserved.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; version 2 of the License.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place, Suite 330, Boston, MA 02111-1307 USA
+
+*****************************************************************************/
+
+/********************************************************************//**
+@file ha/ha0ha.c
+The hash table with external chains
+
+Created 8/22/1994 Heikki Tuuri
+*************************************************************************/
+
+#include "ha0ha.h"
+#ifdef UNIV_NONINL
+#include "ha0ha.ic"
+#endif
+
+#ifdef UNIV_DEBUG
+# include "buf0buf.h"
+#endif /* UNIV_DEBUG */
+#ifdef UNIV_SYNC_DEBUG
+# include "btr0sea.h"
+#endif /* UNIV_SYNC_DEBUG */
+#include "page0page.h"
+
+/*************************************************************//**
+Creates a hash table with at least n array cells. The actual number
+of cells is chosen to be a prime number slightly bigger than n.
+@return own: created table */
+UNIV_INTERN
+hash_table_t*
+ha_create_func(
+/*===========*/
+ ulint n, /*!< in: number of array cells */
+#ifdef UNIV_SYNC_DEBUG
+ ulint mutex_level, /*!< in: level of the mutexes in the latching
+ order: this is used in the debug version */
+#endif /* UNIV_SYNC_DEBUG */
+ ulint n_mutexes) /*!< in: number of mutexes to protect the
+ hash table: must be a power of 2, or 0 */
+{
+ hash_table_t* table;
+#ifndef UNIV_HOTBACKUP
+ ulint i;
+#endif /* !UNIV_HOTBACKUP */
+
+ ut_ad(ut_is_2pow(n_mutexes));
+ table = hash_create(n);
+
+#if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
+# ifndef UNIV_HOTBACKUP
+ table->adaptive = TRUE;
+# endif /* !UNIV_HOTBACKUP */
+#endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
+ /* Creating MEM_HEAP_BTR_SEARCH type heaps can potentially fail,
+ but in practise it never should in this case, hence the asserts. */
+
+ if (n_mutexes == 0) {
+ table->heap = mem_heap_create_in_btr_search(
+ ut_min(4096, MEM_MAX_ALLOC_IN_BUF));
+ ut_a(table->heap);
+
+ return(table);
+ }
+
+#ifndef UNIV_HOTBACKUP
+ hash_create_mutexes(table, n_mutexes, mutex_level);
+
+ table->heaps = mem_alloc(n_mutexes * sizeof(void*));
+
+ for (i = 0; i < n_mutexes; i++) {
+ table->heaps[i] = mem_heap_create_in_btr_search(4096);
+ ut_a(table->heaps[i]);
+ }
+#endif /* !UNIV_HOTBACKUP */
+
+ return(table);
+}
+
+/*************************************************************//**
+Empties a hash table and frees the memory heaps. */
+UNIV_INTERN
+void
+ha_clear(
+/*=====*/
+ hash_table_t* table) /*!< in, own: hash table */
+{
+ ulint i;
+ ulint n;
+
+#ifdef UNIV_SYNC_DEBUG
+ ut_ad(rw_lock_own(&btr_search_latch, RW_LOCK_EXCLUSIVE));
+#endif /* UNIV_SYNC_DEBUG */
+
+#ifndef UNIV_HOTBACKUP
+ /* Free the memory heaps. */
+ n = table->n_mutexes;
+
+ for (i = 0; i < n; i++) {
+ mem_heap_free(table->heaps[i]);
+ }
+#endif /* !UNIV_HOTBACKUP */
+
+ /* Clear the hash table. */
+ n = hash_get_n_cells(table);
+
+ for (i = 0; i < n; i++) {
+ hash_get_nth_cell(table, i)->node = NULL;
+ }
+}
+
+/*************************************************************//**
+Inserts an entry into a hash table. If an entry with the same fold number
+is found, its node is updated to point to the new data, and no new node
+is inserted.
+@return TRUE if succeed, FALSE if no more memory could be allocated */
+UNIV_INTERN
+ibool
+ha_insert_for_fold_func(
+/*====================*/
+ hash_table_t* table, /*!< in: hash table */
+ ulint fold, /*!< in: folded value of data; if a node with
+ the same fold value already exists, it is
+ updated to point to the same data, and no new
+ node is created! */
+#if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
+ buf_block_t* block, /*!< in: buffer block containing the data */
+#endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
+ void* data) /*!< in: data, must not be NULL */
+{
+ hash_cell_t* cell;
+ ha_node_t* node;
+ ha_node_t* prev_node;
+ ulint hash;
+
+ ut_ad(table && data);
+#if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
+ ut_a(block->frame == page_align(data));
+#endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
+ ASSERT_HASH_MUTEX_OWN(table, fold);
+
+ hash = hash_calc_hash(fold, table);
+
+ cell = hash_get_nth_cell(table, hash);
+
+ prev_node = cell->node;
+
+ while (prev_node != NULL) {
+ if (prev_node->fold == fold) {
+#if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
+# ifndef UNIV_HOTBACKUP
+ if (table->adaptive) {
+ buf_block_t* prev_block = prev_node->block;
+ ut_a(prev_block->frame
+ == page_align(prev_node->data));
+ ut_a(prev_block->n_pointers > 0);
+ prev_block->n_pointers--;
+ block->n_pointers++;
+ }
+# endif /* !UNIV_HOTBACKUP */
+
+ prev_node->block = block;
+#endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
+ prev_node->data = data;
+
+ return(TRUE);
+ }
+
+ prev_node = prev_node->next;
+ }
+
+ /* We have to allocate a new chain node */
+
+ node = mem_heap_alloc(hash_get_heap(table, fold), sizeof(ha_node_t));
+
+ if (node == NULL) {
+ /* It was a btr search type memory heap and at the moment
+ no more memory could be allocated: return */
+
+ ut_ad(hash_get_heap(table, fold)->type & MEM_HEAP_BTR_SEARCH);
+
+ return(FALSE);
+ }
+
+ ha_node_set_data(node, block, data);
+
+#if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
+# ifndef UNIV_HOTBACKUP
+ if (table->adaptive) {
+ block->n_pointers++;
+ }
+# endif /* !UNIV_HOTBACKUP */
+#endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
+
+ node->fold = fold;
+
+ node->next = NULL;
+
+ prev_node = cell->node;
+
+ if (prev_node == NULL) {
+
+ cell->node = node;
+
+ return(TRUE);
+ }
+
+ while (prev_node->next != NULL) {
+
+ prev_node = prev_node->next;
+ }
+
+ prev_node->next = node;
+
+ return(TRUE);
+}
+
+/***********************************************************//**
+Deletes a hash node. */
+UNIV_INTERN
+void
+ha_delete_hash_node(
+/*================*/
+ hash_table_t* table, /*!< in: hash table */
+ ha_node_t* del_node) /*!< in: node to be deleted */
+{
+#if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
+# ifndef UNIV_HOTBACKUP
+ if (table->adaptive) {
+ ut_a(del_node->block->frame = page_align(del_node->data));
+ ut_a(del_node->block->n_pointers > 0);
+ del_node->block->n_pointers--;
+ }
+# endif /* !UNIV_HOTBACKUP */
+#endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
+
+ HASH_DELETE_AND_COMPACT(ha_node_t, next, table, del_node);
+}
+
+/*********************************************************//**
+Looks for an element when we know the pointer to the data, and updates
+the pointer to data, if found. */
+UNIV_INTERN
+void
+ha_search_and_update_if_found_func(
+/*===============================*/
+ hash_table_t* table, /*!< in/out: hash table */
+ ulint fold, /*!< in: folded value of the searched data */
+ void* data, /*!< in: pointer to the data */
+#if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
+ buf_block_t* new_block,/*!< in: block containing new_data */
+#endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
+ void* new_data)/*!< in: new pointer to the data */
+{
+ ha_node_t* node;
+
+ ASSERT_HASH_MUTEX_OWN(table, fold);
+#if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
+ ut_a(new_block->frame == page_align(new_data));
+#endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
+
+ node = ha_search_with_data(table, fold, data);
+
+ if (node) {
+#if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
+# ifndef UNIV_HOTBACKUP
+ if (table->adaptive) {
+ ut_a(node->block->n_pointers > 0);
+ node->block->n_pointers--;
+ new_block->n_pointers++;
+ }
+# endif /* !UNIV_HOTBACKUP */
+
+ node->block = new_block;
+#endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
+ node->data = new_data;
+ }
+}
+
+#ifndef UNIV_HOTBACKUP
+/*****************************************************************//**
+Removes from the chain determined by fold all nodes whose data pointer
+points to the page given. */
+UNIV_INTERN
+void
+ha_remove_all_nodes_to_page(
+/*========================*/
+ hash_table_t* table, /*!< in: hash table */
+ ulint fold, /*!< in: fold value */
+ const page_t* page) /*!< in: buffer page */
+{
+ ha_node_t* node;
+
+ ASSERT_HASH_MUTEX_OWN(table, fold);
+
+ node = ha_chain_get_first(table, fold);
+
+ while (node) {
+ if (page_align(ha_node_get_data(node)) == page) {
+
+ /* Remove the hash node */
+
+ ha_delete_hash_node(table, node);
+
+ /* Start again from the first node in the chain
+ because the deletion may compact the heap of
+ nodes and move other nodes! */
+
+ node = ha_chain_get_first(table, fold);
+ } else {
+ node = ha_chain_get_next(node);
+ }
+ }
+#ifdef UNIV_DEBUG
+ /* Check that all nodes really got deleted */
+
+ node = ha_chain_get_first(table, fold);
+
+ while (node) {
+ ut_a(page_align(ha_node_get_data(node)) != page);
+
+ node = ha_chain_get_next(node);
+ }
+#endif
+}
+
+/*************************************************************//**
+Validates a given range of the cells in hash table.
+@return TRUE if ok */
+UNIV_INTERN
+ibool
+ha_validate(
+/*========*/
+ hash_table_t* table, /*!< in: hash table */
+ ulint start_index, /*!< in: start index */
+ ulint end_index) /*!< in: end index */
+{
+ hash_cell_t* cell;
+ ha_node_t* node;
+ ibool ok = TRUE;
+ ulint i;
+
+ ut_a(start_index <= end_index);
+ ut_a(start_index < hash_get_n_cells(table));
+ ut_a(end_index < hash_get_n_cells(table));
+
+ for (i = start_index; i <= end_index; i++) {
+
+ cell = hash_get_nth_cell(table, i);
+
+ node = cell->node;
+
+ while (node) {
+ if (hash_calc_hash(node->fold, table) != i) {
+ ut_print_timestamp(stderr);
+ fprintf(stderr,
+ "InnoDB: Error: hash table node"
+ " fold value %lu does not\n"
+ "InnoDB: match the cell number %lu.\n",
+ (ulong) node->fold, (ulong) i);
+
+ ok = FALSE;
+ }
+
+ node = node->next;
+ }
+ }
+
+ return(ok);
+}
+
+/*************************************************************//**
+Prints info of a hash table. */
+UNIV_INTERN
+void
+ha_print_info(
+/*==========*/
+ FILE* file, /*!< in: file where to print */
+ hash_table_t* table) /*!< in: hash table */
+{
+#ifdef UNIV_DEBUG
+/* Some of the code here is disabled for performance reasons in production
+builds, see http://bugs.mysql.com/36941 */
+#define PRINT_USED_CELLS
+#endif /* UNIV_DEBUG */
+
+#ifdef PRINT_USED_CELLS
+ hash_cell_t* cell;
+ ulint cells = 0;
+ ulint i;
+#endif /* PRINT_USED_CELLS */
+ ulint n_bufs;
+
+#ifdef PRINT_USED_CELLS
+ for (i = 0; i < hash_get_n_cells(table); i++) {
+
+ cell = hash_get_nth_cell(table, i);
+
+ if (cell->node) {
+
+ cells++;
+ }
+ }
+#endif /* PRINT_USED_CELLS */
+
+ fprintf(file, "Hash table size %lu",
+ (ulong) hash_get_n_cells(table));
+
+#ifdef PRINT_USED_CELLS
+ fprintf(file, ", used cells %lu", (ulong) cells);
+#endif /* PRINT_USED_CELLS */
+
+ if (table->heaps == NULL && table->heap != NULL) {
+
+ /* This calculation is intended for the adaptive hash
+ index: how many buffer frames we have reserved? */
+
+ n_bufs = UT_LIST_GET_LEN(table->heap->base) - 1;
+
+ if (table->heap->free_block) {
+ n_bufs++;
+ }
+
+ fprintf(file, ", node heap has %lu buffer(s)\n",
+ (ulong) n_bufs);
+ }
+}
+#endif /* !UNIV_HOTBACKUP */
diff --git a/storage/innodb_plugin/ha/ha0storage.c b/storage/innodb_plugin/ha/ha0storage.c
new file mode 100644
index 00000000000..698e34f1166
--- /dev/null
+++ b/storage/innodb_plugin/ha/ha0storage.c
@@ -0,0 +1,184 @@
+/*****************************************************************************
+
+Copyright (c) 2007, 2009, Innobase Oy. All Rights Reserved.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; version 2 of the License.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place, Suite 330, Boston, MA 02111-1307 USA
+
+*****************************************************************************/
+
+/**************************************************//**
+@file ha/ha0storage.c
+Hash storage.
+Provides a data structure that stores chunks of data in
+its own storage, avoiding duplicates.
+
+Created September 22, 2007 Vasil Dimov
+*******************************************************/
+
+#include "univ.i"
+#include "ha0storage.h"
+#include "hash0hash.h"
+#include "mem0mem.h"
+#include "ut0rnd.h"
+
+#ifdef UNIV_NONINL
+#include "ha0storage.ic"
+#endif
+
+/*******************************************************************//**
+Retrieves a data from a storage. If it is present, a pointer to the
+stored copy of data is returned, otherwise NULL is returned. */
+static
+const void*
+ha_storage_get(
+/*===========*/
+ ha_storage_t* storage, /*!< in: hash storage */
+ const void* data, /*!< in: data to check for */
+ ulint data_len) /*!< in: data length */
+{
+ ha_storage_node_t* node;
+ ulint fold;
+
+ /* avoid repetitive calls to ut_fold_binary() in the HASH_SEARCH
+ macro */
+ fold = ut_fold_binary(data, data_len);
+
+#define IS_FOUND \
+ node->data_len == data_len && memcmp(node->data, data, data_len) == 0
+
+ HASH_SEARCH(
+ next, /* node->"next" */
+ storage->hash, /* the hash table */
+ fold, /* key */
+ ha_storage_node_t*, /* type of node->next */
+ node, /* auxiliary variable */
+ , /* assertion */
+ IS_FOUND); /* search criteria */
+
+ if (node == NULL) {
+
+ return(NULL);
+ }
+ /* else */
+
+ return(node->data);
+}
+
+/*******************************************************************//**
+Copies data into the storage and returns a pointer to the copy. If the
+same data chunk is already present, then pointer to it is returned.
+Data chunks are considered to be equal if len1 == len2 and
+memcmp(data1, data2, len1) == 0. If "data" is not present (and thus
+data_len bytes need to be allocated) and the size of storage is going to
+become more than "memlim" then "data" is not added and NULL is returned.
+To disable this behavior "memlim" can be set to 0, which stands for
+"no limit". */
+UNIV_INTERN
+const void*
+ha_storage_put_memlim(
+/*==================*/
+ ha_storage_t* storage, /*!< in/out: hash storage */
+ const void* data, /*!< in: data to store */
+ ulint data_len, /*!< in: data length */
+ ulint memlim) /*!< in: memory limit to obey */
+{
+ void* raw;
+ ha_storage_node_t* node;
+ const void* data_copy;
+ ulint fold;
+
+ /* check if data chunk is already present */
+ data_copy = ha_storage_get(storage, data, data_len);
+ if (data_copy != NULL) {
+
+ return(data_copy);
+ }
+
+ /* not present */
+
+ /* check if we are allowed to allocate data_len bytes */
+ if (memlim > 0
+ && ha_storage_get_size(storage) + data_len > memlim) {
+
+ return(NULL);
+ }
+
+ /* we put the auxiliary node struct and the data itself in one
+ continuous block */
+ raw = mem_heap_alloc(storage->heap,
+ sizeof(ha_storage_node_t) + data_len);
+
+ node = (ha_storage_node_t*) raw;
+ data_copy = (byte*) raw + sizeof(*node);
+
+ memcpy((byte*) raw + sizeof(*node), data, data_len);
+
+ node->data_len = data_len;
+ node->data = data_copy;
+
+ /* avoid repetitive calls to ut_fold_binary() in the HASH_INSERT
+ macro */
+ fold = ut_fold_binary(data, data_len);
+
+ HASH_INSERT(
+ ha_storage_node_t, /* type used in the hash chain */
+ next, /* node->"next" */
+ storage->hash, /* the hash table */
+ fold, /* key */
+ node); /* add this data to the hash */
+
+ /* the output should not be changed because it will spoil the
+ hash table */
+ return(data_copy);
+}
+
+#ifdef UNIV_COMPILE_TEST_FUNCS
+
+void
+test_ha_storage()
+{
+ ha_storage_t* storage;
+ char buf[1024];
+ int i;
+ const void* stored[256];
+ const void* p;
+
+ storage = ha_storage_create(0, 0);
+
+ for (i = 0; i < 256; i++) {
+
+ memset(buf, i, sizeof(buf));
+ stored[i] = ha_storage_put(storage, buf, sizeof(buf));
+ }
+
+ //ha_storage_empty(&storage);
+
+ for (i = 255; i >= 0; i--) {
+
+ memset(buf, i, sizeof(buf));
+ p = ha_storage_put(storage, buf, sizeof(buf));
+
+ if (p != stored[i]) {
+
+ fprintf(stderr, "ha_storage_put() returned %p "
+ "instead of %p, i=%d\n", p, stored[i], i);
+ return;
+ }
+ }
+
+ fprintf(stderr, "all ok\n");
+
+ ha_storage_free(storage);
+}
+
+#endif /* UNIV_COMPILE_TEST_FUNCS */
diff --git a/storage/innodb_plugin/ha/hash0hash.c b/storage/innodb_plugin/ha/hash0hash.c
new file mode 100644
index 00000000000..2800d7793f8
--- /dev/null
+++ b/storage/innodb_plugin/ha/hash0hash.c
@@ -0,0 +1,174 @@
+/*****************************************************************************
+
+Copyright (c) 1997, 2009, Innobase Oy. All Rights Reserved.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; version 2 of the License.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place, Suite 330, Boston, MA 02111-1307 USA
+
+*****************************************************************************/
+
+/**************************************************//**
+@file ha/hash0hash.c
+The simple hash table utility
+
+Created 5/20/1997 Heikki Tuuri
+*******************************************************/
+
+#include "hash0hash.h"
+#ifdef UNIV_NONINL
+#include "hash0hash.ic"
+#endif
+
+#include "mem0mem.h"
+
+#ifndef UNIV_HOTBACKUP
+/************************************************************//**
+Reserves the mutex for a fold value in a hash table. */
+UNIV_INTERN
+void
+hash_mutex_enter(
+/*=============*/
+ hash_table_t* table, /*!< in: hash table */
+ ulint fold) /*!< in: fold */
+{
+ mutex_enter(hash_get_mutex(table, fold));
+}
+
+/************************************************************//**
+Releases the mutex for a fold value in a hash table. */
+UNIV_INTERN
+void
+hash_mutex_exit(
+/*============*/
+ hash_table_t* table, /*!< in: hash table */
+ ulint fold) /*!< in: fold */
+{
+ mutex_exit(hash_get_mutex(table, fold));
+}
+
+/************************************************************//**
+Reserves all the mutexes of a hash table, in an ascending order. */
+UNIV_INTERN
+void
+hash_mutex_enter_all(
+/*=================*/
+ hash_table_t* table) /*!< in: hash table */
+{
+ ulint i;
+
+ for (i = 0; i < table->n_mutexes; i++) {
+
+ mutex_enter(table->mutexes + i);
+ }
+}
+
+/************************************************************//**
+Releases all the mutexes of a hash table. */
+UNIV_INTERN
+void
+hash_mutex_exit_all(
+/*================*/
+ hash_table_t* table) /*!< in: hash table */
+{
+ ulint i;
+
+ for (i = 0; i < table->n_mutexes; i++) {
+
+ mutex_exit(table->mutexes + i);
+ }
+}
+#endif /* !UNIV_HOTBACKUP */
+
+/*************************************************************//**
+Creates a hash table with >= n array cells. The actual number of cells is
+chosen to be a prime number slightly bigger than n.
+@return own: created table */
+UNIV_INTERN
+hash_table_t*
+hash_create(
+/*========*/
+ ulint n) /*!< in: number of array cells */
+{
+ hash_cell_t* array;
+ ulint prime;
+ hash_table_t* table;
+
+ prime = ut_find_prime(n);
+
+ table = mem_alloc(sizeof(hash_table_t));
+
+ array = ut_malloc(sizeof(hash_cell_t) * prime);
+
+ table->array = array;
+ table->n_cells = prime;
+#ifndef UNIV_HOTBACKUP
+# if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
+ table->adaptive = FALSE;
+# endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
+ table->n_mutexes = 0;
+ table->mutexes = NULL;
+ table->heaps = NULL;
+#endif /* !UNIV_HOTBACKUP */
+ table->heap = NULL;
+ table->magic_n = HASH_TABLE_MAGIC_N;
+
+ /* Initialize the cell array */
+ hash_table_clear(table);
+
+ return(table);
+}
+
+/*************************************************************//**
+Frees a hash table. */
+UNIV_INTERN
+void
+hash_table_free(
+/*============*/
+ hash_table_t* table) /*!< in, own: hash table */
+{
+#ifndef UNIV_HOTBACKUP
+ ut_a(table->mutexes == NULL);
+#endif /* !UNIV_HOTBACKUP */
+
+ ut_free(table->array);
+ mem_free(table);
+}
+
+#ifndef UNIV_HOTBACKUP
+/*************************************************************//**
+Creates a mutex array to protect a hash table. */
+UNIV_INTERN
+void
+hash_create_mutexes_func(
+/*=====================*/
+ hash_table_t* table, /*!< in: hash table */
+#ifdef UNIV_SYNC_DEBUG
+ ulint sync_level, /*!< in: latching order level of the
+ mutexes: used in the debug version */
+#endif /* UNIV_SYNC_DEBUG */
+ ulint n_mutexes) /*!< in: number of mutexes, must be a
+ power of 2 */
+{
+ ulint i;
+
+ ut_a(n_mutexes > 0);
+ ut_a(ut_is_2pow(n_mutexes));
+
+ table->mutexes = mem_alloc(n_mutexes * sizeof(mutex_t));
+
+ for (i = 0; i < n_mutexes; i++) {
+ mutex_create(table->mutexes + i, sync_level);
+ }
+
+ table->n_mutexes = n_mutexes;
+}
+#endif /* !UNIV_HOTBACKUP */
diff --git a/storage/innodb_plugin/ha_innodb.def b/storage/innodb_plugin/ha_innodb.def
new file mode 100644
index 00000000000..e0faa62deb1
--- /dev/null
+++ b/storage/innodb_plugin/ha_innodb.def
@@ -0,0 +1,4 @@
+EXPORTS
+ _mysql_plugin_interface_version_
+ _mysql_sizeof_struct_st_plugin_
+ _mysql_plugin_declarations_
diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innodb_plugin/handler/ha_innodb.cc
similarity index 68%
rename from storage/innobase/handler/ha_innodb.cc
rename to storage/innodb_plugin/handler/ha_innodb.cc
index 828dcdb843d..682004407c7 100644
--- a/storage/innobase/handler/ha_innodb.cc
+++ b/storage/innodb_plugin/handler/ha_innodb.cc
@@ -1,21 +1,53 @@
-/* Copyright (C) 2000-2005 MySQL AB & Innobase Oy
+/*****************************************************************************
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; version 2 of the License.
+Copyright (c) 2000, 2009, MySQL AB & Innobase Oy. All Rights Reserved.
+Copyright (c) 2008, 2009 Google Inc.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
+Portions of this file contain modifications contributed and copyrighted by
+Google, Inc. Those modifications are gratefully acknowledged and are described
+briefly in the InnoDB documentation. The contributions by Google are
+incorporated with their permission, and subject to the conditions contained in
+the file COPYING.Google.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; version 2 of the License.
-/* This file defines the InnoDB handler: the interface between MySQL and InnoDB
-NOTE: You can only use noninlined InnoDB functions in this file, because we
-have disabled the InnoDB inlining in this file. */
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place, Suite 330, Boston, MA 02111-1307 USA
+
+*****************************************************************************/
+/***********************************************************************
+
+Copyright (c) 1995, 2009, Innobase Oy. All Rights Reserved.
+Copyright (c) 2009, Percona Inc.
+
+Portions of this file contain modifications contributed and copyrighted
+by Percona Inc.. Those modifications are
+gratefully acknowledged and are described briefly in the InnoDB
+documentation. The contributions by Percona Inc. are incorporated with
+their permission, and subject to the conditions contained in the file
+COPYING.Percona.
+
+This program is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; version 2 of the License.
+
+This program is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+***********************************************************************/
/* TODO list for the InnoDB handler in 5.0:
- Remove the flag trx->active_trans and look at trx->conc_state
@@ -30,20 +62,59 @@ have disabled the InnoDB inlining in this file. */
#endif
#include
-#include
#include
-#include
-#include
#include
-#include
-#include "ha_innodb.h"
#include
+/** @file ha_innodb.cc */
+
+/* Include necessary InnoDB headers */
+extern "C" {
+#include "univ.i"
+#include "btr0sea.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 "ut0mem.h"
+#include "ibuf0ibuf.h"
+}
+
+#include "ha_innodb.h"
+#include "i_s.h"
+
#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;
+extern MYSQL_PLUGIN_IMPORT pthread_mutex_t LOCK_thread_count;
+
+#if MYSQL_VERSION_ID < 50124
+/* this is defined in mysql_priv.h inside #ifdef MYSQL_SERVER
+but we need it here */
+bool check_global_access(THD *thd, ulong want_access);
+#endif /* MYSQL_VERSION_ID < 50124 */
#endif /* MYSQL_SERVER */
/** to protect innobase_open_files */
@@ -56,51 +127,28 @@ static pthread_cond_t commit_cond;
static pthread_mutex_t commit_cond_m;
static bool innodb_inited = 0;
-/*
- This needs to exist until the query cache callback is removed
- or learns to pass hton.
-*/
-static handlerton *innodb_hton_ptr;
-
#define INSIDE_HA_INNOBASE_CC
-/* Include necessary InnoDB headers */
-extern "C" {
-#include "../storage/innobase/include/univ.i"
-#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/thr0loc.h"
-#include "../storage/innobase/include/ha_prototypes.h"
-}
+/* In the Windows plugin, the return value of current_thd is
+undefined. Map it to NULL. */
+
+#define EQ_CURRENT_THD(thd) ((thd) == current_thd)
+
+
+static struct handlerton* innodb_hton_ptr;
static const long AUTOINC_OLD_STYLE_LOCKING = 0;
static const long AUTOINC_NEW_STYLE_LOCKING = 1;
static const long AUTOINC_NO_LOCKING = 2;
static long innobase_mirrored_log_groups, innobase_log_files_in_group,
- innobase_log_buffer_size, innobase_buffer_pool_awe_mem_mb,
- innobase_additional_mem_pool_size,
- innobase_lock_wait_timeout, innobase_force_recovery,
- innobase_open_files, innobase_autoinc_lock_mode;
+ innobase_log_buffer_size,
+ innobase_additional_mem_pool_size, innobase_file_io_threads,
+ innobase_force_recovery, innobase_open_files,
+ innobase_autoinc_lock_mode;
+static ulong innobase_commit_concurrency = 0;
+static ulong innobase_read_io_threads;
+static ulong innobase_write_io_threads;
static long long innobase_buffer_pool_size, innobase_log_file_size;
@@ -110,6 +158,14 @@ are determined in innobase_init below: */
static char* innobase_data_home_dir = NULL;
static char* innobase_data_file_path = NULL;
static char* innobase_log_group_home_dir = NULL;
+static char* innobase_file_format_name = NULL;
+static char* innobase_change_buffering = NULL;
+
+/* Note: This variable can be set to on/off and any of the supported
+file formats in the configuration file, but can only be set to any
+of the supported file formats during runtime. */
+static char* innobase_file_format_check = NULL;
+
/* The following has a misleading name: starting from 4.0.5, this also
affects Windows: */
static char* innobase_unix_file_flush_method = NULL;
@@ -124,32 +180,14 @@ static char* innobase_log_arch_dir = NULL;
#endif /* UNIV_LOG_ARCHIVE */
static my_bool innobase_use_doublewrite = TRUE;
static my_bool innobase_use_checksums = TRUE;
-static my_bool innobase_file_per_table = FALSE;
static my_bool innobase_locks_unsafe_for_binlog = FALSE;
static my_bool innobase_rollback_on_timeout = FALSE;
static my_bool innobase_create_status_file = FALSE;
static my_bool innobase_stats_on_metadata = TRUE;
-static my_bool innobase_adaptive_hash_index = TRUE;
static char* internal_innobase_data_file_path = NULL;
-/* Default number of IO per second supported by server. Tunes background
- IO rate. */
-static long innobase_io_capacity = 100;
-
-/* Write dirty pages when pct dirty is less than max pct dirty */
-static my_bool innobase_extra_dirty_writes = TRUE;
-
-/* Max number of IO requests merged to perform large IO in background
- IO threads.
-*/
-long innobase_max_merged_io = 64;
-
-/* Number of background IO threads for read and write. */
-long innobase_read_io_threads, innobase_write_io_threads;
-
-/* Use timer based InnoDB concurrency throttling flag */
-static my_bool innobase_thread_concurrency_timer_based;
+static char* innodb_version_str = (char*) INNODB_VERSION_STR;
/* The following counter is used to convey information to InnoDB
about server activity: in selects it is not sensible to call
@@ -159,14 +197,18 @@ it every INNOBASE_WAKE_INTERVAL'th step. */
#define INNOBASE_WAKE_INTERVAL 32
static ulong innobase_active_counter = 0;
-static HASH innobase_open_tables;
+static hash_table_t* innobase_open_tables;
#ifdef __NETWARE__ /* some special cleanup for NetWare */
bool nw_panic = FALSE;
#endif
-static uchar* innobase_get_key(INNOBASE_SHARE *share, size_t *length,
- my_bool not_used __attribute__((unused)));
+/** Allowed values of innodb_change_buffering */
+static const char* innobase_change_buffering_values[IBUF_USE_COUNT] = {
+ "none", /* IBUF_USE_NONE */
+ "inserts" /* IBUF_USE_INSERT */
+};
+
static INNOBASE_SHARE *get_share(const char *table_name);
static void free_share(INNOBASE_SHARE *share);
static int innobase_close_connection(handlerton *hton, THD* thd);
@@ -181,8 +223,88 @@ static handler *innobase_create_handler(handlerton *hton,
TABLE_SHARE *table,
MEM_ROOT *mem_root);
+/** @brief Initialize the default value of innodb_commit_concurrency.
+
+Once InnoDB is running, the innodb_commit_concurrency must not change
+from zero to nonzero. (Bug #42101)
+
+The initial default value is 0, and without this extra initialization,
+SET GLOBAL innodb_commit_concurrency=DEFAULT would set the parameter
+to 0, even if it was initially set to nonzero at the command line
+or configuration file. */
+static
+void
+innobase_commit_concurrency_init_default(void);
+/*==========================================*/
+
+/************************************************************//**
+Validate the file format name and return its corresponding id.
+@return valid file format id */
+static
+uint
+innobase_file_format_name_lookup(
+/*=============================*/
+ const char* format_name); /*!< in: pointer to file format
+ name */
+/************************************************************//**
+Validate the file format check config parameters, as a side effect it
+sets the srv_check_file_format_at_startup variable.
+@return true if one of "on" or "off" */
+static
+bool
+innobase_file_format_check_on_off(
+/*==============================*/
+ const char* format_check); /*!< in: parameter value */
+/************************************************************//**
+Validate the file format check config parameters, as a side effect it
+sets the srv_check_file_format_at_startup variable.
+@return true if valid config value */
+static
+bool
+innobase_file_format_check_validate(
+/*================================*/
+ const char* format_check); /*!< in: parameter value */
+/****************************************************************//**
+Return alter table flags supported in an InnoDB database. */
+static
+uint
+innobase_alter_table_flags(
+/*=======================*/
+ uint flags);
+
static const char innobase_hton_name[]= "InnoDB";
+/*************************************************************//**
+Check for a valid value of innobase_commit_concurrency.
+@return 0 for valid innodb_commit_concurrency */
+static
+int
+innobase_commit_concurrency_validate(
+/*=================================*/
+ THD* thd, /*!< in: thread handle */
+ struct st_mysql_sys_var* var, /*!< in: pointer to system
+ variable */
+ void* save, /*!< out: immediate result
+ for update function */
+ struct st_mysql_value* value) /*!< in: incoming string */
+{
+ long long intbuf;
+ ulong commit_concurrency;
+
+ DBUG_ENTER("innobase_commit_concurrency_validate");
+
+ if (value->val_int(value, &intbuf)) {
+ /* The value is NULL. That is invalid. */
+ DBUG_RETURN(1);
+ }
+
+ *reinterpret_cast(save) = commit_concurrency
+ = static_cast(intbuf);
+
+ /* Allow the value to be updated, as long as it remains zero
+ or nonzero. */
+ DBUG_RETURN(!(!commit_concurrency == !innobase_commit_concurrency));
+}
static MYSQL_THDVAR_BOOL(support_xa, PLUGIN_VAR_OPCMDARG,
"Enable InnoDB support for the XA two-phase commit",
@@ -194,6 +316,15 @@ static MYSQL_THDVAR_BOOL(table_locks, PLUGIN_VAR_OPCMDARG,
/* check_func */ NULL, /* update_func */ NULL,
/* default */ TRUE);
+static MYSQL_THDVAR_BOOL(strict_mode, PLUGIN_VAR_OPCMDARG,
+ "Use strict mode when evaluating create options.",
+ NULL, NULL, FALSE);
+
+static MYSQL_THDVAR_ULONG(lock_wait_timeout, PLUGIN_VAR_RQCMDARG,
+ "Timeout in seconds an InnoDB transaction may wait for a lock before being rolled back. Values above 100000000 disable the timeout.",
+ NULL, NULL, 50, 1, 1024 * 1024 * 1024, 0);
+
+
static handler *innobase_create_handler(handlerton *hton,
TABLE_SHARE *table,
MEM_ROOT *mem_root)
@@ -201,62 +332,64 @@ static handler *innobase_create_handler(handlerton *hton,
return new (mem_root) ha_innobase(hton, table);
}
-/***********************************************************************
-This function is used to prepare X/Open XA distributed transaction */
+/*******************************************************************//**
+This function is used to prepare an X/Open XA distributed transaction.
+@return 0 or error number */
static
int
innobase_xa_prepare(
/*================*/
- /* out: 0 or error number */
- handlerton* hton,
- THD* thd, /* in: handle to the MySQL thread of the user
- whose XA transaction should be prepared */
- bool all); /* in: TRUE - commit transaction
- FALSE - the current SQL statement ended */
-/***********************************************************************
-This function is used to recover X/Open XA distributed transactions */
+ handlerton* hton, /*!< in: InnoDB handlerton */
+ THD* thd, /*!< in: handle to the MySQL thread of
+ the user whose XA transaction should
+ be prepared */
+ bool all); /*!< in: TRUE - commit transaction
+ FALSE - the current SQL statement
+ ended */
+/*******************************************************************//**
+This function is used to recover X/Open XA distributed transactions.
+@return number of prepared transactions stored in xid_list */
static
int
innobase_xa_recover(
/*================*/
- /* out: number of prepared transactions
- stored in xid_list */
- handlerton* hton,
- XID* xid_list, /* in/out: prepared transactions */
- uint len); /* in: number of slots in xid_list */
-/***********************************************************************
+ handlerton* hton, /*!< in: InnoDB handlerton */
+ XID* xid_list,/*!< in/out: prepared transactions */
+ uint len); /*!< in: number of slots in xid_list */
+/*******************************************************************//**
This function is used to commit one X/Open XA distributed transaction
-which is in the prepared state */
+which is in the prepared state
+@return 0 or error number */
static
int
innobase_commit_by_xid(
/*===================*/
- /* out: 0 or error number */
handlerton* hton,
- XID* xid); /* in: X/Open XA transaction identification */
-/***********************************************************************
+ XID* xid); /*!< in: X/Open XA transaction identification */
+/*******************************************************************//**
This function is used to rollback one X/Open XA distributed transaction
-which is in the prepared state */
+which is in the prepared state
+@return 0 or error number */
static
int
innobase_rollback_by_xid(
/*=====================*/
- /* out: 0 or error number */
- handlerton* hton,
- XID *xid); /* in: X/Open XA transaction identification */
-/***********************************************************************
+ handlerton* hton, /*!< in: InnoDB handlerton */
+ XID* xid); /*!< in: X/Open XA transaction
+ identification */
+/*******************************************************************//**
Create a consistent view for a cursor based on current transaction
which is created if the corresponding MySQL thread still lacks one.
This consistent view is then used inside of MySQL when accessing records
-using a cursor. */
+using a cursor.
+@return pointer to cursor view or NULL */
static
void*
innobase_create_cursor_view(
/*========================*/
- /* out: pointer to cursor view or NULL */
- handlerton* hton, /* in: innobase hton */
- THD* thd); /* in: user thread handle */
-/***********************************************************************
+ handlerton* hton, /*!< in: innobase hton */
+ THD* thd); /*!< in: user thread handle */
+/*******************************************************************//**
Set the given consistent cursor view to a transaction which is created
if the corresponding MySQL thread still lacks one. If the given
consistent cursor view is NULL global read view of a transaction is
@@ -266,9 +399,9 @@ void
innobase_set_cursor_view(
/*=====================*/
handlerton* hton,
- THD* thd, /* in: user thread handle */
- void* curview);/* in: Consistent cursor view to be set */
-/***********************************************************************
+ THD* thd, /*!< in: user thread handle */
+ void* curview);/*!< in: Consistent cursor view to be set */
+/*******************************************************************//**
Close the given consistent cursor view of a transaction and restore
global read view to a transaction read view. Transaction is created if the
corresponding MySQL thread still lacks one. */
@@ -277,71 +410,70 @@ void
innobase_close_cursor_view(
/*=======================*/
handlerton* hton,
- THD* thd, /* in: user thread handle */
- void* curview);/* in: Consistent read view to be closed */
-/*********************************************************************
+ THD* thd, /*!< in: user thread handle */
+ void* curview);/*!< in: Consistent read view to be closed */
+/*****************************************************************//**
Removes all tables in the named database inside InnoDB. */
static
void
innobase_drop_database(
/*===================*/
- /* out: error number */
- handlerton* hton, /* in: handlerton of Innodb */
- char* path); /* in: database path; inside InnoDB the name
+ handlerton* hton, /*!< in: handlerton of Innodb */
+ char* path); /*!< in: database path; inside InnoDB the name
of the last directory in the path is used as
the database name: for example, in 'mysql/data/test'
the database name is 'test' */
-/***********************************************************************
+/*******************************************************************//**
Closes an InnoDB database. */
static
int
innobase_end(handlerton *hton, ha_panic_function type);
-/*********************************************************************
+/*****************************************************************//**
Creates an InnoDB transaction struct for the thd if it does not yet have one.
Starts a new InnoDB transaction if a transaction is not yet started. And
assigns a new snapshot for a consistent read if the transaction does not yet
-have one. */
+have one.
+@return 0 */
static
int
innobase_start_trx_and_assign_read_view(
/*====================================*/
- /* out: 0 */
- handlerton* hton, /* in: Innodb handlerton */
- THD* thd); /* in: MySQL thread handle of the user for whom
+ handlerton* hton, /*!< in: Innodb handlerton */
+ THD* thd); /*!< in: MySQL thread handle of the user for whom
the transaction should be committed */
-/********************************************************************
+/****************************************************************//**
Flushes InnoDB logs to disk and makes a checkpoint. Really, a commit flushes
-the logs, and the name of this function should be innobase_checkpoint. */
+the logs, and the name of this function should be innobase_checkpoint.
+@return TRUE if error */
static
bool
innobase_flush_logs(
/*================*/
- /* out: TRUE if error */
- handlerton* hton); /* in: InnoDB handlerton */
+ handlerton* hton); /*!< in: InnoDB handlerton */
-/****************************************************************************
+/************************************************************************//**
Implements the SHOW INNODB STATUS command. Sends the output of the InnoDB
Monitor to the client. */
static
bool
innodb_show_status(
/*===============*/
- handlerton* hton, /* in: the innodb handlerton */
- THD* thd, /* in: the MySQL query thread of the caller */
+ handlerton* hton, /*!< in: the innodb handlerton */
+ THD* thd, /*!< in: the MySQL query thread of the caller */
stat_print_fn *stat_print);
static
bool innobase_show_status(handlerton *hton, THD* thd,
stat_print_fn* stat_print,
enum ha_stat_type stat_type);
-/*********************************************************************
+/*****************************************************************//**
Commits a transaction in an InnoDB database. */
static
void
innobase_commit_low(
/*================*/
- trx_t* trx); /* in: transaction handle */
+ trx_t* trx); /*!< in: transaction handle */
static SHOW_VAR innodb_status_variables[]= {
{"buffer_pool_pages_data",
@@ -392,10 +524,8 @@ static SHOW_VAR innodb_status_variables[]= {
(char*) &export_vars.innodb_dblwr_pages_written, SHOW_LONG},
{"dblwr_writes",
(char*) &export_vars.innodb_dblwr_writes, SHOW_LONG},
- {"have_sync_atomic",
- (char*) &export_vars.innodb_have_sync_atomic, SHOW_BOOL},
- {"heap_enabled",
- (char*) &export_vars.innodb_heap_enabled, SHOW_BOOL},
+ {"have_atomic_builtins",
+ (char*) &export_vars.innodb_have_atomic_builtins, SHOW_BOOL},
{"log_waits",
(char*) &export_vars.innodb_log_waits, SHOW_LONG},
{"log_write_requests",
@@ -436,37 +566,35 @@ static SHOW_VAR innodb_status_variables[]= {
(char*) &export_vars.innodb_rows_read, SHOW_LONG},
{"rows_updated",
(char*) &export_vars.innodb_rows_updated, SHOW_LONG},
- {"wake_ups",
- (char*) &export_vars.innodb_wake_ups, SHOW_LONG},
{NullS, NullS, SHOW_LONG}
};
/* General functions */
-/**********************************************************************
+/******************************************************************//**
Returns true if the thread is the replication thread on the slave
server. Used in srv_conc_enter_innodb() to determine if the thread
should be allowed to enter InnoDB - the replication thread is treated
differently than other threads. Also used in
-srv_conc_force_exit_innodb(). */
-extern "C"
+srv_conc_force_exit_innodb().
+@return true if thd is the replication thread */
+extern "C" UNIV_INTERN
ibool
thd_is_replication_slave_thread(
/*============================*/
- /* out: true if thd is the replication thread */
- void* thd) /* in: thread handle (THD*) */
+ void* thd) /*!< in: thread handle (THD*) */
{
return((ibool) thd_slave_thread((THD*) thd));
}
-/**********************************************************************
+/******************************************************************//**
Save some CPU by testing the value of srv_thread_concurrency in inline
functions. */
-inline
+static inline
void
innodb_srv_conc_enter_innodb(
/*=========================*/
- trx_t* trx) /* in: transaction handle */
+ trx_t* trx) /*!< in: transaction handle */
{
if (UNIV_LIKELY(!srv_thread_concurrency)) {
@@ -476,14 +604,14 @@ innodb_srv_conc_enter_innodb(
srv_conc_enter_innodb(trx);
}
-/**********************************************************************
+/******************************************************************//**
Save some CPU by testing the value of srv_thread_concurrency in inline
functions. */
-inline
+static inline
void
innodb_srv_conc_exit_innodb(
/*========================*/
- trx_t* trx) /* in: transaction handle */
+ trx_t* trx) /*!< in: transaction handle */
{
if (UNIV_LIKELY(!trx->declared_to_be_inside_innodb)) {
@@ -493,16 +621,16 @@ innodb_srv_conc_exit_innodb(
srv_conc_exit_innodb(trx);
}
-/**********************************************************************
+/******************************************************************//**
Releases possible search latch and InnoDB thread FIFO ticket. These should
be released at each SQL statement end, and also when mysqld passes the
control to the client. It does no harm to release these also in the middle
of an SQL statement. */
-inline
+static inline
void
innobase_release_stat_resources(
/*============================*/
- trx_t* trx) /* in: transaction object */
+ trx_t* trx) /*!< in: transaction object */
{
if (trx->has_search_latch) {
trx_search_latch_release_if_reserved(trx);
@@ -515,57 +643,85 @@ innobase_release_stat_resources(
}
}
-/**********************************************************************
+/******************************************************************//**
Returns true if the transaction this thread is processing has edited
non-transactional tables. Used by the deadlock detector when deciding
which transaction to rollback in case of a deadlock - we try to avoid
-rolling back transactions that have edited non-transactional tables. */
-extern "C"
+rolling back transactions that have edited non-transactional tables.
+@return true if non-transactional tables have been edited */
+extern "C" UNIV_INTERN
ibool
thd_has_edited_nontrans_tables(
/*===========================*/
- /* out: true if non-transactional tables have
- been edited */
- void* thd) /* in: thread handle (THD*) */
+ void* thd) /*!< in: thread handle (THD*) */
{
return((ibool) thd_non_transactional_update((THD*) thd));
}
-/**********************************************************************
-Returns true if the thread is executing a SELECT statement. */
-extern "C"
+/******************************************************************//**
+Returns true if the thread is executing a SELECT statement.
+@return true if thd is executing SELECT */
+extern "C" UNIV_INTERN
ibool
thd_is_select(
/*==========*/
- /* out: true if thd is executing SELECT */
- const void* thd) /* in: thread handle (THD*) */
+ const void* thd) /*!< in: thread handle (THD*) */
{
return(thd_sql_command((const THD*) thd) == SQLCOM_SELECT);
}
-/************************************************************************
-Obtain the InnoDB transaction of a MySQL thread. */
-inline
+/******************************************************************//**
+Returns true if the thread supports XA,
+global value of innodb_supports_xa if thd is NULL.
+@return true if thd has XA support */
+extern "C" UNIV_INTERN
+ibool
+thd_supports_xa(
+/*============*/
+ void* thd) /*!< in: thread handle (THD*), or NULL to query
+ the global innodb_supports_xa */
+{
+ return(THDVAR((THD*) thd, support_xa));
+}
+
+/******************************************************************//**
+Returns the lock wait timeout for the current connection.
+@return the lock wait timeout, in seconds */
+extern "C" UNIV_INTERN
+ulong
+thd_lock_wait_timeout(
+/*==================*/
+ void* thd) /*!< in: thread handle (THD*), or NULL to query
+ the global innodb_lock_wait_timeout */
+{
+ /* According to , passing thd == NULL
+ returns the global value of the session variable. */
+ return(THDVAR((THD*) thd, lock_wait_timeout));
+}
+
+/********************************************************************//**
+Obtain the InnoDB transaction of a MySQL thread.
+@return reference to transaction pointer */
+static inline
trx_t*&
thd_to_trx(
/*=======*/
- /* out: reference to transaction pointer */
- THD* thd) /* in: MySQL thread */
+ THD* thd) /*!< in: MySQL thread */
{
return(*(trx_t**) thd_ha_data(thd, innodb_hton_ptr));
}
-/************************************************************************
+/********************************************************************//**
Call this function when mysqld passes control to the client. That is to
avoid deadlocks on the adaptive hash S-latch possibly held by thd. For more
-documentation, see handler.cc. */
+documentation, see handler.cc.
+@return 0 */
static
int
innobase_release_temporary_latches(
/*===============================*/
- /* out: 0 */
- handlerton* hton, /* in: handlerton */
- THD* thd) /* in: MySQL thread */
+ handlerton* hton, /*!< in: handlerton */
+ THD* thd) /*!< in: MySQL thread */
{
trx_t* trx;
@@ -573,7 +729,7 @@ innobase_release_temporary_latches(
if (!innodb_inited) {
- return 0;
+ return(0);
}
trx = thd_to_trx(thd);
@@ -581,15 +737,15 @@ innobase_release_temporary_latches(
if (trx) {
innobase_release_stat_resources(trx);
}
- return 0;
+ return(0);
}
-/************************************************************************
+/********************************************************************//**
Increments innobase_active_counter and every INNOBASE_WAKE_INTERVALth
time calls srv_active_wake_master_thread. This function should be used
when a single database operation may introduce a small need for
server utility activity, like checkpointing. */
-inline
+static inline
void
innobase_active_small(void)
/*=======================*/
@@ -601,39 +757,40 @@ innobase_active_small(void)
}
}
-/************************************************************************
+/********************************************************************//**
Converts an InnoDB error code to a MySQL error code and also tells to MySQL
about a possible transaction rollback inside InnoDB caused by a lock wait
-timeout or a deadlock. */
-static
+timeout or a deadlock.
+@return MySQL error code */
+extern "C" UNIV_INTERN
int
convert_error_code_to_mysql(
/*========================*/
- /* out: MySQL error code */
- int error, /* in: InnoDB error code */
- THD* thd) /* in: user thread handle or NULL */
+ int error, /*!< in: InnoDB error code */
+ ulint flags, /*!< in: InnoDB table flags, or 0 */
+ THD* thd) /*!< in: user thread handle or NULL */
{
- if (error == DB_SUCCESS) {
-
+ switch (error) {
+ case DB_SUCCESS:
return(0);
- } else if (error == (int) DB_DUPLICATE_KEY) {
-
- return(HA_ERR_FOUND_DUPP_KEY);
-
- } else if (error == (int) DB_FOREIGN_DUPLICATE_KEY) {
-
- return(HA_ERR_FOREIGN_DUPLICATE_KEY);
-
- } else if (error == (int) DB_RECORD_NOT_FOUND) {
-
- return(HA_ERR_NO_ACTIVE_RECORD);
-
- } else if (error == (int) DB_ERROR) {
-
+ case DB_ERROR:
+ default:
return(-1); /* unspecified error */
- } else if (error == (int) DB_DEADLOCK) {
+ case DB_DUPLICATE_KEY:
+ return(HA_ERR_FOUND_DUPP_KEY);
+
+ case DB_FOREIGN_DUPLICATE_KEY:
+ return(HA_ERR_FOREIGN_DUPLICATE_KEY);
+
+ case DB_MISSING_HISTORY:
+ return(HA_ERR_TABLE_DEF_CHANGED);
+
+ case DB_RECORD_NOT_FOUND:
+ return(HA_ERR_NO_ACTIVE_RECORD);
+
+ case DB_DEADLOCK:
/* Since we rolled back the whole transaction, we must
tell it also to MySQL so that MySQL knows to empty the
cached binlog for this transaction */
@@ -643,8 +800,8 @@ convert_error_code_to_mysql(
}
return(HA_ERR_LOCK_DEADLOCK);
- } else if (error == (int) DB_LOCK_WAIT_TIMEOUT) {
+ case DB_LOCK_WAIT_TIMEOUT:
/* Starting from 5.0.13, we let MySQL just roll back the
latest SQL statement in a lock wait timeout. Previously, we
rolled back the whole transaction. */
@@ -656,61 +813,58 @@ convert_error_code_to_mysql(
return(HA_ERR_LOCK_WAIT_TIMEOUT);
- } else if (error == (int) DB_NO_REFERENCED_ROW) {
-
+ case DB_NO_REFERENCED_ROW:
return(HA_ERR_NO_REFERENCED_ROW);
- } else if (error == (int) DB_ROW_IS_REFERENCED) {
-
+ case DB_ROW_IS_REFERENCED:
return(HA_ERR_ROW_IS_REFERENCED);
- } else if (error == (int) DB_CANNOT_ADD_CONSTRAINT) {
-
+ case DB_CANNOT_ADD_CONSTRAINT:
return(HA_ERR_CANNOT_ADD_FOREIGN);
- } else if (error == (int) DB_CANNOT_DROP_CONSTRAINT) {
+ case DB_CANNOT_DROP_CONSTRAINT:
return(HA_ERR_ROW_IS_REFERENCED); /* TODO: This is a bit
misleading, a new MySQL error
code should be introduced */
- } else if (error == (int) DB_COL_APPEARS_TWICE_IN_INDEX) {
+ case DB_COL_APPEARS_TWICE_IN_INDEX:
+ case DB_CORRUPTION:
return(HA_ERR_CRASHED);
- } else if (error == (int) DB_OUT_OF_FILE_SPACE) {
-
+ case DB_OUT_OF_FILE_SPACE:
return(HA_ERR_RECORD_FILE_FULL);
- } else if (error == (int) DB_TABLE_IS_BEING_USED) {
-
+ case DB_TABLE_IS_BEING_USED:
return(HA_ERR_WRONG_COMMAND);
- } else if (error == (int) DB_TABLE_NOT_FOUND) {
-
+ case DB_TABLE_NOT_FOUND:
return(HA_ERR_NO_SUCH_TABLE);
- } else if (error == (int) DB_TOO_BIG_RECORD) {
-
+ case DB_TOO_BIG_RECORD:
+ my_error(ER_TOO_BIG_ROWSIZE, MYF(0),
+ page_get_free_space_of_empty(flags
+ & DICT_TF_COMPACT) / 2);
return(HA_ERR_TO_BIG_ROW);
- } else if (error == (int) DB_CORRUPTION) {
-
- return(HA_ERR_CRASHED);
- } else if (error == (int) DB_NO_SAVEPOINT) {
-
+ case DB_NO_SAVEPOINT:
return(HA_ERR_NO_SAVEPOINT);
- } else if (error == (int) DB_LOCK_TABLE_FULL) {
- /* Since we rolled back the whole transaction, we must
- tell it also to MySQL so that MySQL knows to empty the
- cached binlog for this transaction */
+
+ case DB_LOCK_TABLE_FULL:
+ /* Since we rolled back the whole transaction, we must
+ tell it also to MySQL so that MySQL knows to empty the
+ cached binlog for this transaction */
if (thd) {
thd_mark_transaction_to_rollback(thd, TRUE);
}
- return(HA_ERR_LOCK_TABLE_FULL);
- } else if (error == DB_TOO_MANY_CONCURRENT_TRXS) {
+ return(HA_ERR_LOCK_TABLE_FULL);
+ case DB_PRIMARY_KEY_IS_NULL:
+ return(ER_PRIMARY_CANT_HAVE_NULL);
+
+ case DB_TOO_MANY_CONCURRENT_TRXS:
/* Once MySQL add the appropriate code to errmsg.txt then
we can get rid of this #ifdef. NOTE: The code checked by
the #ifdef is the suggested name for the error condition
@@ -722,78 +876,68 @@ convert_error_code_to_mysql(
#else
return(HA_ERR_RECORD_FILE_FULL);
#endif
-
- } else if (error == DB_UNSUPPORTED) {
-
+ case DB_UNSUPPORTED:
return(HA_ERR_UNSUPPORTED);
- } else {
- return(-1); // Unknown error
- }
+ }
}
-/*****************************************************************
+/*************************************************************//**
If you want to print a thd that is not associated with the current thread,
you must call this function before reserving the InnoDB kernel_mutex, to
protect MySQL from setting thd->query NULL. If you print a thd of the current
thread, we know that MySQL cannot modify thd->query, and it is not necessary
to call this. Call innobase_mysql_end_print_arbitrary_thd() after you release
-the kernel_mutex.
-NOTE that /mysql/innobase/lock/lock0lock.c must contain the prototype for this
-function! */
-extern "C"
+the kernel_mutex. */
+extern "C" UNIV_INTERN
void
innobase_mysql_prepare_print_arbitrary_thd(void)
/*============================================*/
{
+ ut_ad(!mutex_own(&kernel_mutex));
VOID(pthread_mutex_lock(&LOCK_thread_count));
}
-/*****************************************************************
+/*************************************************************//**
Releases the mutex reserved by innobase_mysql_prepare_print_arbitrary_thd().
-NOTE that /mysql/innobase/lock/lock0lock.c must contain the prototype for this
-function! */
-extern "C"
+In the InnoDB latching order, the mutex sits right above the
+kernel_mutex. In debug builds, we assert that the kernel_mutex is
+released before this function is invoked. */
+extern "C" UNIV_INTERN
void
innobase_mysql_end_print_arbitrary_thd(void)
/*========================================*/
{
+ ut_ad(!mutex_own(&kernel_mutex));
VOID(pthread_mutex_unlock(&LOCK_thread_count));
}
-/*****************************************************************
-Prints info of a THD object (== user session thread) to the given file.
-NOTE that /mysql/innobase/trx/trx0trx.c must contain the prototype for
-this function! */
-extern "C"
+/*************************************************************//**
+Prints info of a THD object (== user session thread) to the given file. */
+extern "C" UNIV_INTERN
void
innobase_mysql_print_thd(
/*=====================*/
- FILE* f, /* in: output stream */
- void* input_thd, /* in: pointer to a MySQL THD object */
- uint max_query_len) /* in: max query length to print, or 0 to
+ FILE* f, /*!< in: output stream */
+ void* thd, /*!< in: pointer to a MySQL THD object */
+ uint max_query_len) /*!< in: max query length to print, or 0 to
use the default max length */
{
- THD* thd;
char buffer[1024];
- thd = (THD*) input_thd;
- fputs(thd_security_context(thd, buffer, sizeof(buffer),
+ fputs(thd_security_context((THD*) thd, buffer, sizeof buffer,
max_query_len), f);
putc('\n', f);
}
-/**********************************************************************
-Get the variable length bounds of the given character set.
-
-NOTE that the exact prototype of this function has to be in
-/innobase/include/data0type.ic! */
-extern "C"
+/******************************************************************//**
+Get the variable length bounds of the given character set. */
+extern "C" UNIV_INTERN
void
innobase_get_cset_width(
/*====================*/
- ulint cset, /* in: MySQL charset-collation code */
- ulint* mbminlen, /* out: minimum length of a char (in bytes) */
- ulint* mbmaxlen) /* out: maximum length of a char (in bytes) */
+ ulint cset, /*!< in: MySQL charset-collation code */
+ ulint* mbminlen, /*!< out: minimum length of a char (in bytes) */
+ ulint* mbmaxlen) /*!< out: maximum length of a char (in bytes) */
{
CHARSET_INFO* cs;
ut_ad(cset < 256);
@@ -810,96 +954,175 @@ innobase_get_cset_width(
}
}
-/**********************************************************************
-Converts an identifier to a table name.
-
-NOTE that the exact prototype of this function has to be in
-/innobase/dict/dict0dict.c! */
-extern "C"
+/******************************************************************//**
+Converts an identifier to a table name. */
+extern "C" UNIV_INTERN
void
innobase_convert_from_table_id(
/*===========================*/
- char* to, /* out: converted identifier */
- const char* from, /* in: identifier to convert */
- ulint len) /* in: length of 'to', in bytes */
+ struct charset_info_st* cs, /*!< in: the 'from' character set */
+ char* to, /*!< out: converted identifier */
+ const char* from, /*!< in: identifier to convert */
+ ulint len) /*!< in: length of 'to', in bytes */
{
uint errors;
- strconvert(thd_charset(current_thd), from,
- &my_charset_filename, to, (uint) len, &errors);
+ strconvert(cs, from, &my_charset_filename, to, (uint) len, &errors);
}
-/**********************************************************************
-Converts an identifier to UTF-8.
-
-NOTE that the exact prototype of this function has to be in
-/innobase/dict/dict0dict.c! */
-extern "C"
+/******************************************************************//**
+Converts an identifier to UTF-8. */
+extern "C" UNIV_INTERN
void
innobase_convert_from_id(
/*=====================*/
- char* to, /* out: converted identifier */
- const char* from, /* in: identifier to convert */
- ulint len) /* in: length of 'to', in bytes */
+ struct charset_info_st* cs, /*!< in: the 'from' character set */
+ char* to, /*!< out: converted identifier */
+ const char* from, /*!< in: identifier to convert */
+ ulint len) /*!< in: length of 'to', in bytes */
{
uint errors;
- strconvert(thd_charset(current_thd), from,
- system_charset_info, to, (uint) len, &errors);
+ strconvert(cs, from, system_charset_info, to, (uint) len, &errors);
}
-/**********************************************************************
+/******************************************************************//**
Compares NUL-terminated UTF-8 strings case insensitively.
-
-NOTE that the exact prototype of this function has to be in
-/innobase/dict/dict0dict.c! */
-extern "C"
+@return 0 if a=b, <0 if a1 if a>b */
+extern "C" UNIV_INTERN
int
innobase_strcasecmp(
/*================*/
- /* out: 0 if a=b, <0 if a1 if a>b */
- const char* a, /* in: first string to compare */
- const char* b) /* in: second string to compare */
+ const char* a, /*!< in: first string to compare */
+ const char* b) /*!< in: second string to compare */
{
return(my_strcasecmp(system_charset_info, a, b));
}
-/**********************************************************************
-Makes all characters in a NUL-terminated UTF-8 string lower case.
-
-NOTE that the exact prototype of this function has to be in
-/innobase/dict/dict0dict.c! */
-extern "C"
+/******************************************************************//**
+Makes all characters in a NUL-terminated UTF-8 string lower case. */
+extern "C" UNIV_INTERN
void
innobase_casedn_str(
/*================*/
- char* a) /* in/out: string to put in lower case */
+ char* a) /*!< in/out: string to put in lower case */
{
my_casedn_str(system_charset_info, a);
}
-/**************************************************************************
+/**********************************************************************//**
Determines the connection character set.
-
-NOTE that the exact prototype of this function has to be in
-/innobase/dict/dict0dict.c! */
-extern "C"
+@return connection character set */
+extern "C" UNIV_INTERN
struct charset_info_st*
innobase_get_charset(
/*=================*/
- /* out: connection character set */
- void* mysql_thd) /* in: MySQL thread handle */
+ void* mysql_thd) /*!< in: MySQL thread handle */
{
return(thd_charset((THD*) mysql_thd));
}
-/*************************************************************************
-Creates a temporary file. */
+#if defined (__WIN__) && defined (MYSQL_DYNAMIC_PLUGIN)
+extern MYSQL_PLUGIN_IMPORT MY_TMPDIR mysql_tmpdir_list;
+/*******************************************************************//**
+Map an OS error to an errno value. The OS error number is stored in
+_doserrno and the mapped value is stored in errno) */
extern "C"
+void __cdecl
+_dosmaperr(
+ unsigned long); /*!< in: OS error value */
+
+/*********************************************************************//**
+Creates a temporary file.
+@return temporary file descriptor, or < 0 on error */
+extern "C" UNIV_INTERN
+int
+innobase_mysql_tmpfile(void)
+/*========================*/
+{
+ int fd; /* handle of opened file */
+ HANDLE osfh; /* OS handle of opened file */
+ char* tmpdir; /* point to the directory
+ where to create file */
+ TCHAR path_buf[MAX_PATH - 14]; /* buffer for tmp file path.
+ The length cannot be longer
+ than MAX_PATH - 14, or
+ GetTempFileName will fail. */
+ char filename[MAX_PATH]; /* name of the tmpfile */
+ DWORD fileaccess = GENERIC_READ /* OS file access */
+ | GENERIC_WRITE
+ | DELETE;
+ DWORD fileshare = FILE_SHARE_READ /* OS file sharing mode */
+ | FILE_SHARE_WRITE
+ | FILE_SHARE_DELETE;
+ DWORD filecreate = CREATE_ALWAYS; /* OS method of open/create */
+ DWORD fileattrib = /* OS file attribute flags */
+ FILE_ATTRIBUTE_NORMAL
+ | FILE_FLAG_DELETE_ON_CLOSE
+ | FILE_ATTRIBUTE_TEMPORARY
+ | FILE_FLAG_SEQUENTIAL_SCAN;
+
+ DBUG_ENTER("innobase_mysql_tmpfile");
+
+ tmpdir = my_tmpdir(&mysql_tmpdir_list);
+
+ /* The tmpdir parameter can not be NULL for GetTempFileName. */
+ if (!tmpdir) {
+ uint ret;
+
+ /* Use GetTempPath to determine path for temporary files. */
+ ret = GetTempPath(sizeof(path_buf), path_buf);
+ if (ret > sizeof(path_buf) || (ret == 0)) {
+
+ _dosmaperr(GetLastError()); /* map error */
+ DBUG_RETURN(-1);
+ }
+
+ tmpdir = path_buf;
+ }
+
+ /* Use GetTempFileName to generate a unique filename. */
+ if (!GetTempFileName(tmpdir, "ib", 0, filename)) {
+
+ _dosmaperr(GetLastError()); /* map error */
+ DBUG_RETURN(-1);
+ }
+
+ DBUG_PRINT("info", ("filename: %s", filename));
+
+ /* Open/Create the file. */
+ osfh = CreateFile(filename, fileaccess, fileshare, NULL,
+ filecreate, fileattrib, NULL);
+ if (osfh == INVALID_HANDLE_VALUE) {
+
+ /* open/create file failed! */
+ _dosmaperr(GetLastError()); /* map error */
+ DBUG_RETURN(-1);
+ }
+
+ do {
+ /* Associates a CRT file descriptor with the OS file handle. */
+ fd = _open_osfhandle((intptr_t) osfh, 0);
+ } while (fd == -1 && errno == EINTR);
+
+ if (fd == -1) {
+ /* Open failed, close the file handle. */
+
+ _dosmaperr(GetLastError()); /* map error */
+ CloseHandle(osfh); /* no need to check if
+ CloseHandle fails */
+ }
+
+ DBUG_RETURN(fd);
+}
+#else
+/*********************************************************************//**
+Creates a temporary file.
+@return temporary file descriptor, or < 0 on error */
+extern "C" UNIV_INTERN
int
innobase_mysql_tmpfile(void)
/*========================*/
- /* out: temporary file descriptor, or < 0 on error */
{
int fd2 = -1;
File fd = mysql_tmpfile("ib");
@@ -924,28 +1147,69 @@ innobase_mysql_tmpfile(void)
}
return(fd2);
}
+#endif /* defined (__WIN__) && defined (MYSQL_DYNAMIC_PLUGIN) */
-/*************************************************************************
-Wrapper around MySQL's copy_and_convert function, see it for
-documentation. */
-extern "C"
+/*********************************************************************//**
+Wrapper around MySQL's copy_and_convert function.
+@return number of bytes copied to 'to' */
+extern "C" UNIV_INTERN
ulint
innobase_convert_string(
/*====================*/
- void* to,
- ulint to_length,
- CHARSET_INFO* to_cs,
- const void* from,
- ulint from_length,
- CHARSET_INFO* from_cs,
- uint* errors)
+ void* to, /*!< out: converted string */
+ ulint to_length, /*!< in: number of bytes reserved
+ for the converted string */
+ CHARSET_INFO* to_cs, /*!< in: character set to convert to */
+ const void* from, /*!< in: string to convert */
+ ulint from_length, /*!< in: number of bytes to convert */
+ CHARSET_INFO* from_cs, /*!< in: character set to convert from */
+ uint* errors) /*!< out: number of errors encountered
+ during the conversion */
{
return(copy_and_convert((char*)to, (uint32) to_length, to_cs,
(const char*)from, (uint32) from_length, from_cs,
errors));
}
-/*************************************************************************
+/*******************************************************************//**
+Formats the raw data in "data" (in InnoDB on-disk format) that is of
+type DATA_(CHAR|VARCHAR|MYSQL|VARMYSQL) using "charset_coll" and writes
+the result to "buf". The result is converted to "system_charset_info".
+Not more than "buf_size" bytes are written to "buf".
+The result is always NUL-terminated (provided buf_size > 0) and the
+number of bytes that were written to "buf" is returned (including the
+terminating NUL).
+@return number of bytes that were written */
+extern "C" UNIV_INTERN
+ulint
+innobase_raw_format(
+/*================*/
+ const char* data, /*!< in: raw data */
+ ulint data_len, /*!< in: raw data length
+ in bytes */
+ ulint charset_coll, /*!< in: charset collation */
+ char* buf, /*!< out: output buffer */
+ ulint buf_size) /*!< in: output buffer size
+ in bytes */
+{
+ /* XXX we use a hard limit instead of allocating
+ but_size bytes from the heap */
+ CHARSET_INFO* data_cs;
+ char buf_tmp[8192];
+ ulint buf_tmp_used;
+ uint num_errors;
+
+ data_cs = all_charsets[charset_coll];
+
+ buf_tmp_used = innobase_convert_string(buf_tmp, sizeof(buf_tmp),
+ system_charset_info,
+ data, data_len, data_cs,
+ &num_errors);
+
+ return(ut_str_sql_format(buf_tmp, buf_tmp_used, buf, buf_size));
+}
+
+/*********************************************************************//**
Compute the next autoinc value.
For MySQL replication the autoincrement values can be partitioned among
@@ -961,16 +1225,16 @@ values we want to reserve for multi-value inserts e.g.,
innobase_next_autoinc() will be called with increment set to
n * 3 where autoinc_lock_mode != TRADITIONAL because we want
-to reserve 3 values for the multi-value INSERT above. */
+to reserve 3 values for the multi-value INSERT above.
+@return the next value */
static
ulonglong
innobase_next_autoinc(
/*==================*/
- /* out: the next value */
- ulonglong current, /* in: Current value */
- ulonglong increment, /* in: increment current by */
- ulonglong offset, /* in: AUTOINC offset */
- ulonglong max_value) /* in: max value for type */
+ ulonglong current, /*!< in: Current value */
+ ulonglong increment, /*!< in: increment current by */
+ ulonglong offset, /*!< in: AUTOINC offset */
+ ulonglong max_value) /*!< in: max value for type */
{
ulonglong next_value;
@@ -993,7 +1257,7 @@ innobase_next_autoinc(
} else {
next_value = current + increment;
}
- } else {
+ } else if (max_value > current) {
if (current > offset) {
next_value = ((current - offset) / increment) + 1;
} else {
@@ -1019,6 +1283,8 @@ innobase_next_autoinc(
next_value += offset;
}
}
+ } else {
+ next_value = max_value;
}
ut_a(next_value <= max_value);
@@ -1026,58 +1292,84 @@ innobase_next_autoinc(
return(next_value);
}
-/*************************************************************************
+/*********************************************************************//**
+Initializes some fields in an InnoDB transaction object. */
+static
+void
+innobase_trx_init(
+/*==============*/
+ THD* thd, /*!< in: user thread handle */
+ trx_t* trx) /*!< in/out: InnoDB transaction handle */
+{
+ DBUG_ENTER("innobase_trx_init");
+ DBUG_ASSERT(EQ_CURRENT_THD(thd));
+ DBUG_ASSERT(thd == trx->mysql_thd);
+
+ trx->check_foreigns = !thd_test_options(
+ thd, OPTION_NO_FOREIGN_KEY_CHECKS);
+
+ trx->check_unique_secondary = !thd_test_options(
+ thd, OPTION_RELAXED_UNIQUE_CHECKS);
+
+ DBUG_VOID_RETURN;
+}
+
+/*********************************************************************//**
+Allocates an InnoDB transaction for a MySQL handler object.
+@return InnoDB transaction handle */
+extern "C" UNIV_INTERN
+trx_t*
+innobase_trx_allocate(
+/*==================*/
+ THD* thd) /*!< in: user thread handle */
+{
+ trx_t* trx;
+
+ DBUG_ENTER("innobase_trx_allocate");
+ DBUG_ASSERT(thd != NULL);
+ DBUG_ASSERT(EQ_CURRENT_THD(thd));
+
+ trx = trx_allocate_for_mysql();
+
+ trx->mysql_thd = thd;
+ trx->mysql_query_str = thd_query(thd);
+
+ innobase_trx_init(thd, trx);
+
+ DBUG_RETURN(trx);
+}
+
+/*********************************************************************//**
Gets the InnoDB transaction handle for a MySQL handler object, creates
an InnoDB transaction struct if the corresponding MySQL thread struct still
-lacks one. */
+lacks one.
+@return InnoDB transaction handle */
static
trx_t*
check_trx_exists(
/*=============*/
- /* out: InnoDB transaction handle */
- THD* thd) /* in: user thread handle */
+ THD* thd) /*!< in: user thread handle */
{
trx_t*& trx = thd_to_trx(thd);
- ut_ad(thd == current_thd);
+ ut_ad(EQ_CURRENT_THD(thd));
if (trx == NULL) {
- DBUG_ASSERT(thd != NULL);
- trx = trx_allocate_for_mysql();
-
- trx->mysql_thd = thd;
- trx->mysql_query_str = thd_query(thd);
-
- /* Update the info whether we should skip XA steps that eat
- CPU time */
- trx->support_xa = THDVAR(thd, support_xa);
- } else {
- if (trx->magic_n != TRX_MAGIC_N) {
- mem_analyze_corruption(trx);
-
- ut_error;
- }
+ trx = innobase_trx_allocate(thd);
+ } else if (UNIV_UNLIKELY(trx->magic_n != TRX_MAGIC_N)) {
+ mem_analyze_corruption(trx);
+ ut_error;
}
- if (thd_test_options(thd, OPTION_NO_FOREIGN_KEY_CHECKS)) {
- trx->check_foreigns = FALSE;
- } else {
- trx->check_foreigns = TRUE;
- }
-
- if (thd_test_options(thd, OPTION_RELAXED_UNIQUE_CHECKS)) {
- trx->check_unique_secondary = FALSE;
- } else {
- trx->check_unique_secondary = TRUE;
- }
+ innobase_trx_init(thd, trx);
return(trx);
}
-/*************************************************************************
+/*********************************************************************//**
Construct ha_innobase handler. */
-
+UNIV_INTERN
ha_innobase::ha_innobase(handlerton *hton, TABLE_SHARE *table_arg)
:handler(hton, table_arg),
int_table_flags(HA_REC_NOT_IN_SEQ |
@@ -1093,16 +1385,22 @@ ha_innobase::ha_innobase(handlerton *hton, TABLE_SHARE *table_arg)
num_write_row(0)
{}
-/*************************************************************************
+/*********************************************************************//**
+Destruct ha_innobase handler. */
+UNIV_INTERN
+ha_innobase::~ha_innobase()
+{
+}
+
+/*********************************************************************//**
Updates the user_thd field in a handle and also allocates a new InnoDB
transaction handle if needed, and updates the transaction fields in the
prebuilt struct. */
-inline
-int
+UNIV_INTERN inline
+void
ha_innobase::update_thd(
/*====================*/
- /* out: 0 or error code */
- THD* thd) /* in: thd to use the handle */
+ THD* thd) /*!< in: thd to use the handle */
{
trx_t* trx;
@@ -1114,39 +1412,52 @@ ha_innobase::update_thd(
}
user_thd = thd;
-
- return(0);
}
-/*************************************************************************
+/*********************************************************************//**
+Updates the user_thd field in a handle and also allocates a new InnoDB
+transaction handle if needed, and updates the transaction fields in the
+prebuilt struct. */
+UNIV_INTERN
+void
+ha_innobase::update_thd()
+/*=====================*/
+{
+ THD* thd = ha_thd();
+ ut_ad(EQ_CURRENT_THD(thd));
+ update_thd(thd);
+}
+
+/*********************************************************************//**
Registers that InnoDB takes part in an SQL statement, so that MySQL knows to
roll back the statement if the statement results in an error. This MUST be
called for every SQL statement that may be rolled back by MySQL. Calling this
several times to register the same statement is allowed, too. */
-inline
+static inline
void
innobase_register_stmt(
/*===================*/
- handlerton* hton, /* in: Innobase hton */
- THD* thd) /* in: MySQL thd (connection) object */
+ handlerton* hton, /*!< in: Innobase hton */
+ THD* thd) /*!< in: MySQL thd (connection) object */
{
+ DBUG_ASSERT(hton == innodb_hton_ptr);
/* Register the statement */
trans_register_ha(thd, FALSE, hton);
}
-/*************************************************************************
+/*********************************************************************//**
Registers an InnoDB transaction in MySQL, so that the MySQL XA code knows
to call the InnoDB prepare and commit, or rollback for the transaction. This
MUST be called for every transaction for which the user may call commit or
rollback. Calling this several times to register the same transaction is
allowed, too.
This function also registers the current SQL statement. */
-inline
+static inline
void
innobase_register_trx_and_stmt(
/*===========================*/
- handlerton *hton, /* in: Innobase handlerton */
- THD* thd) /* in: MySQL thd (connection) object */
+ handlerton *hton, /*!< in: Innobase handlerton */
+ THD* thd) /*!< in: MySQL thd (connection) object */
{
/* NOTE that actually innobase_register_stmt() registers also
the transaction in the AUTOCOMMIT=1 mode. */
@@ -1203,7 +1514,7 @@ AUTOCOMMIT==0 or we are inside BEGIN ... COMMIT. Thus transactions no longer
put restrictions on the use of the query cache.
*/
-/**********************************************************************
+/******************************************************************//**
The MySQL query cache uses this to check from InnoDB if the query cache at
the moment is allowed to operate on an InnoDB table. The SQL query must
be a non-locking SELECT.
@@ -1220,24 +1531,23 @@ at the start of a SELECT processing. Then the calling thread cannot be
holding any InnoDB semaphores. The calling thread is holding the
query cache mutex, and this function will reserver the InnoDB kernel mutex.
Thus, the 'rank' in sync0sync.h of the MySQL query cache mutex is above
-the InnoDB kernel mutex. */
+the InnoDB kernel mutex.
+@return TRUE if permitted, FALSE if not; note that the value FALSE
+does not mean we should invalidate the query cache: invalidation is
+called explicitly */
static
my_bool
innobase_query_caching_of_table_permitted(
/*======================================*/
- /* out: TRUE if permitted, FALSE if not;
- note that the value FALSE does not mean
- we should invalidate the query cache:
- invalidation is called explicitly */
- THD* thd, /* in: thd of the user who is trying to
+ THD* thd, /*!< in: thd of the user who is trying to
store a result to the query cache or
retrieve it */
- char* full_name, /* in: concatenation of database name,
- the null character '\0', and the table
+ char* full_name, /*!< in: concatenation of database name,
+ the null character NUL, and the table
name */
- uint full_name_len, /* in: length of the full name, i.e.
+ uint full_name_len, /*!< in: length of the full name, i.e.
len(dbname) + len(tablename) + 1 */
- ulonglong *unused) /* unused for this engine */
+ ulonglong *unused) /*!< unused for this engine */
{
ibool is_autocommit;
trx_t* trx;
@@ -1259,9 +1569,9 @@ innobase_query_caching_of_table_permitted(
"search, latch though calling "
"innobase_query_caching_of_table_permitted.");
- mutex_enter_noninline(&kernel_mutex);
+ mutex_enter(&kernel_mutex);
trx_print(stderr, trx, 1024);
- mutex_exit_noninline(&kernel_mutex);
+ mutex_exit(&kernel_mutex);
}
innobase_release_stat_resources(trx);
@@ -1327,21 +1637,21 @@ innobase_query_caching_of_table_permitted(
return((my_bool)FALSE);
}
-/*********************************************************************
-Invalidates the MySQL query cache for the table.
-NOTE that the exact prototype of this function has to be in
-/innobase/row/row0ins.c! */
-extern "C"
+/*****************************************************************//**
+Invalidates the MySQL query cache for the table. */
+extern "C" UNIV_INTERN
void
innobase_invalidate_query_cache(
/*============================*/
- trx_t* trx, /* in: transaction which modifies the table */
- char* full_name, /* in: concatenation of database name, null
- char '\0', table name, null char'\0';
- NOTE that in Windows this is always
- in LOWER CASE! */
- ulint full_name_len) /* in: full name length where also the null
- chars count */
+ trx_t* trx, /*!< in: transaction which
+ modifies the table */
+ const char* full_name, /*!< in: concatenation of
+ database name, null char NUL,
+ table name, null char NUL;
+ NOTE that in Windows this is
+ always in LOWER CASE! */
+ ulint full_name_len) /*!< in: full name length where
+ also the null chars count */
{
/* Note that the sync0sync.h rank of the query cache mutex is just
above the InnoDB kernel mutex. The caller of this function must not
@@ -1350,110 +1660,186 @@ innobase_invalidate_query_cache(
/* Argument TRUE below means we are using transactions */
#ifdef HAVE_QUERY_CACHE
mysql_query_cache_invalidate4((THD*) trx->mysql_thd,
- (const char*) full_name,
+ full_name,
(uint32) full_name_len,
TRUE);
#endif
}
-/*********************************************************************
-Display an SQL identifier. */
-extern "C"
-void
-innobase_print_identifier(
-/*======================*/
- FILE* f, /* in: output stream */
- trx_t* trx, /* in: transaction */
- ibool table_id,/* in: TRUE=print a table name,
- FALSE=print other identifier */
- const char* name, /* in: name to print */
- ulint namelen)/* in: length of name */
+/*****************************************************************//**
+Convert an SQL identifier to the MySQL system_charset_info (UTF-8)
+and quote it if needed.
+@return pointer to the end of buf */
+static
+char*
+innobase_convert_identifier(
+/*========================*/
+ char* buf, /*!< out: buffer for converted identifier */
+ ulint buflen, /*!< in: length of buf, in bytes */
+ const char* id, /*!< in: identifier to convert */
+ ulint idlen, /*!< in: length of id, in bytes */
+ void* thd, /*!< in: MySQL connection thread, or NULL */
+ ibool file_id)/*!< in: TRUE=id is a table or database name;
+ FALSE=id is an UTF-8 string */
{
- const char* s = name;
- char* qname = NULL;
+ char nz[NAME_LEN + 1];
+ char nz2[NAME_LEN + 1 + sizeof srv_mysql50_table_name_prefix];
+
+ const char* s = id;
int q;
- if (table_id) {
+ if (file_id) {
/* Decode the table name. The filename_to_tablename()
function expects a NUL-terminated string. The input and
- output strings buffers must not be shared. The function
- only produces more output when the name contains other
- characters than [0-9A-Z_a-z]. */
- char* temp_name = (char*) my_malloc((uint) namelen + 1, MYF(MY_WME));
- uint qnamelen = (uint) (namelen
- + (1 + sizeof srv_mysql50_table_name_prefix));
+ output strings buffers must not be shared. */
- if (temp_name) {
- qname = (char*) my_malloc(qnamelen, MYF(MY_WME));
- if (qname) {
- memcpy(temp_name, name, namelen);
- temp_name[namelen] = 0;
- s = qname;
- namelen = filename_to_tablename(temp_name,
- qname, qnamelen);
- }
- my_free(temp_name, MYF(0));
+ if (UNIV_UNLIKELY(idlen > (sizeof nz) - 1)) {
+ idlen = (sizeof nz) - 1;
}
+
+ memcpy(nz, id, idlen);
+ nz[idlen] = 0;
+
+ s = nz2;
+ idlen = filename_to_tablename(nz, nz2, sizeof nz2);
}
- if (!trx || !trx->mysql_thd) {
-
+ /* See if the identifier needs to be quoted. */
+ if (UNIV_UNLIKELY(!thd)) {
q = '"';
} else {
- q = get_quote_char_for_identifier((THD*) trx->mysql_thd,
- s, (int) namelen);
+ q = get_quote_char_for_identifier((THD*) thd, s, (int) idlen);
}
if (q == EOF) {
- fwrite(s, 1, namelen, f);
- } else {
- const char* e = s + namelen;
- putc(q, f);
- while (s < e) {
- int c = *s++;
- if (c == q) {
- putc(c, f);
- }
- putc(c, f);
+ if (UNIV_UNLIKELY(idlen > buflen)) {
+ idlen = buflen;
}
- putc(q, f);
+ memcpy(buf, s, idlen);
+ return(buf + idlen);
}
- my_free(qname, MYF(MY_ALLOW_ZERO_PTR));
+ /* Quote the identifier. */
+ if (buflen < 2) {
+ return(buf);
+ }
+
+ *buf++ = q;
+ buflen--;
+
+ for (; idlen; idlen--) {
+ int c = *s++;
+ if (UNIV_UNLIKELY(c == q)) {
+ if (UNIV_UNLIKELY(buflen < 3)) {
+ break;
+ }
+
+ *buf++ = c;
+ *buf++ = c;
+ buflen -= 2;
+ } else {
+ if (UNIV_UNLIKELY(buflen < 2)) {
+ break;
+ }
+
+ *buf++ = c;
+ buflen--;
+ }
+ }
+
+ *buf++ = q;
+ return(buf);
}
-/**************************************************************************
-Determines if the currently running transaction has been interrupted. */
-extern "C"
+/*****************************************************************//**
+Convert a table or index name to the MySQL system_charset_info (UTF-8)
+and quote it if needed.
+@return pointer to the end of buf */
+extern "C" UNIV_INTERN
+char*
+innobase_convert_name(
+/*==================*/
+ char* buf, /*!< out: buffer for converted identifier */
+ ulint buflen, /*!< in: length of buf, in bytes */
+ const char* id, /*!< in: identifier to convert */
+ ulint idlen, /*!< in: length of id, in bytes */
+ void* thd, /*!< in: MySQL connection thread, or NULL */
+ ibool table_id)/*!< in: TRUE=id is a table or database name;
+ FALSE=id is an index name */
+{
+ char* s = buf;
+ const char* bufend = buf + buflen;
+
+ if (table_id) {
+ const char* slash = (const char*) memchr(id, '/', idlen);
+ if (!slash) {
+
+ goto no_db_name;
+ }
+
+ /* Print the database name and table name separately. */
+ s = innobase_convert_identifier(s, bufend - s, id, slash - id,
+ thd, TRUE);
+ if (UNIV_LIKELY(s < bufend)) {
+ *s++ = '.';
+ s = innobase_convert_identifier(s, bufend - s,
+ slash + 1, idlen
+ - (slash - id) - 1,
+ thd, TRUE);
+ }
+ } else if (UNIV_UNLIKELY(*id == TEMP_INDEX_PREFIX)) {
+ /* Temporary index name (smart ALTER TABLE) */
+ const char temp_index_suffix[]= "--temporary--";
+
+ s = innobase_convert_identifier(buf, buflen, id + 1, idlen - 1,
+ thd, FALSE);
+ if (s - buf + (sizeof temp_index_suffix - 1) < buflen) {
+ memcpy(s, temp_index_suffix,
+ sizeof temp_index_suffix - 1);
+ s += sizeof temp_index_suffix - 1;
+ }
+ } else {
+no_db_name:
+ s = innobase_convert_identifier(buf, buflen, id, idlen,
+ thd, table_id);
+ }
+
+ return(s);
+
+}
+
+/**********************************************************************//**
+Determines if the currently running transaction has been interrupted.
+@return TRUE if interrupted */
+extern "C" UNIV_INTERN
ibool
trx_is_interrupted(
/*===============*/
- /* out: TRUE if interrupted */
- trx_t* trx) /* in: transaction */
+ trx_t* trx) /*!< in: transaction */
{
return(trx && trx->mysql_thd && thd_killed((THD*) trx->mysql_thd));
}
-/******************************************************************
+/**************************************************************//**
Resets some fields of a prebuilt struct. The template is used in fast
retrieval of just those column values MySQL needs in its processing. */
static
void
reset_template(
/*===========*/
- row_prebuilt_t* prebuilt) /* in/out: prebuilt struct */
+ row_prebuilt_t* prebuilt) /*!< in/out: prebuilt struct */
{
prebuilt->keep_other_fields_on_keyread = 0;
prebuilt->read_just_key = 0;
}
-/*********************************************************************
+/*****************************************************************//**
Call this when you have opened a new table handle in HANDLER, before you
call index_read_idx() etc. Actually, we can let the cursor stay open even
over a transaction commit! Then you should call this before every operation,
fetch next etc. This function inits the necessary things even after a
transaction commit. */
-
+UNIV_INTERN
void
ha_innobase::init_table_handle_for_HANDLER(void)
/*============================================*/
@@ -1472,7 +1858,7 @@ ha_innobase::init_table_handle_for_HANDLER(void)
/* If the transaction is not started yet, start it */
- trx_start_if_not_started_noninline(prebuilt->trx);
+ trx_start_if_not_started(prebuilt->trx);
/* Assign a read view if the transaction does not have it yet */
@@ -1509,19 +1895,20 @@ ha_innobase::init_table_handle_for_HANDLER(void)
reset_template(prebuilt);
}
-/*************************************************************************
-Opens an InnoDB database. */
+/*********************************************************************//**
+Opens an InnoDB database.
+@return 0 on success, error code on failure */
static
int
innobase_init(
/*==========*/
- /* out: 0 on success, error code on failure */
- void *p) /* in: InnoDB handlerton */
+ void *p) /*!< in: InnoDB handlerton */
{
- static char current_dir[3]; /* Set if using current lib */
+ static char current_dir[3]; /*!< Set if using current lib */
int err;
bool ret;
char *default_path;
+ uint format_id;
DBUG_ENTER("innobase_init");
handlerton *innobase_hton= (handlerton *)p;
@@ -1551,6 +1938,7 @@ innobase_init(
innobase_hton->show_status=innobase_show_status;
innobase_hton->flags=HTON_NO_FLAGS;
innobase_hton->release_temporary_latches=innobase_release_temporary_latches;
+ innobase_hton->alter_table_flags = innobase_alter_table_flags;
ut_a(DATA_MYSQL_TRUE_VARCHAR == (ulint)MYSQL_TYPE_VARCHAR);
@@ -1644,16 +2032,12 @@ innobase_init(
MYF(MY_FAE));
ret = (bool) srv_parse_data_file_paths_and_sizes(
- internal_innobase_data_file_path,
- &srv_data_file_names,
- &srv_data_file_sizes,
- &srv_data_file_is_raw_partition,
- &srv_n_data_files,
- &srv_auto_extend_last_data_file,
- &srv_last_file_size_max);
+ internal_innobase_data_file_path);
if (ret == FALSE) {
sql_print_error(
"InnoDB: syntax error in innodb_data_file_path");
+mem_free_and_error:
+ srv_free_paths_and_sizes();
my_free(internal_innobase_data_file_path,
MYF(MY_ALLOW_ZERO_PTR));
goto error;
@@ -1678,18 +2062,93 @@ innobase_init(
#endif /* UNIG_LOG_ARCHIVE */
ret = (bool)
- srv_parse_log_group_home_dirs(innobase_log_group_home_dir,
- &srv_log_group_home_dirs);
+ srv_parse_log_group_home_dirs(innobase_log_group_home_dir);
if (ret == FALSE || innobase_mirrored_log_groups != 1) {
sql_print_error("syntax error in innodb_log_group_home_dir, or a "
"wrong number of mirrored log groups");
- my_free(internal_innobase_data_file_path,
- MYF(MY_ALLOW_ZERO_PTR));
- goto error;
+ goto mem_free_and_error;
}
+ /* Validate the file format by animal name */
+ if (innobase_file_format_name != NULL) {
+
+ format_id = innobase_file_format_name_lookup(
+ innobase_file_format_name);
+
+ if (format_id > DICT_TF_FORMAT_MAX) {
+
+ sql_print_error("InnoDB: wrong innodb_file_format.");
+
+ goto mem_free_and_error;
+ }
+ } else {
+ /* Set it to the default file format id. Though this
+ should never happen. */
+ format_id = 0;
+ }
+
+ srv_file_format = format_id;
+
+ /* Given the type of innobase_file_format_name we have little
+ choice but to cast away the constness from the returned name.
+ innobase_file_format_name is used in the MySQL set variable
+ interface and so can't be const. */
+
+ innobase_file_format_name =
+ (char*) trx_sys_file_format_id_to_name(format_id);
+
+ /* Process innobase_file_format_check variable */
+ ut_a(innobase_file_format_check != NULL);
+
+ /* As a side effect it will set srv_check_file_format_at_startup
+ on valid input. First we check for "on"/"off". */
+ if (!innobase_file_format_check_on_off(innobase_file_format_check)) {
+
+ /* Did the user specify a format name that we support ?
+ As a side effect it will update the variable
+ srv_check_file_format_at_startup */
+ if (!innobase_file_format_check_validate(
+ innobase_file_format_check)) {
+
+ sql_print_error("InnoDB: invalid "
+ "innodb_file_format_check value: "
+ "should be either 'on' or 'off' or "
+ "any value up to %s or its "
+ "equivalent numeric id",
+ trx_sys_file_format_id_to_name(
+ DICT_TF_FORMAT_MAX));
+
+ goto mem_free_and_error;
+ }
+ }
+
+ if (innobase_change_buffering) {
+ ulint use;
+
+ for (use = 0;
+ use < UT_ARR_SIZE(innobase_change_buffering_values);
+ use++) {
+ if (!innobase_strcasecmp(
+ innobase_change_buffering,
+ innobase_change_buffering_values[use])) {
+ ibuf_use = (ibuf_use_t) use;
+ goto innobase_change_buffering_inited_ok;
+ }
+ }
+
+ sql_print_error("InnoDB: invalid value "
+ "innodb_file_format_check=%s",
+ innobase_change_buffering);
+ goto mem_free_and_error;
+ }
+
+innobase_change_buffering_inited_ok:
+ ut_a((ulint) ibuf_use < UT_ARR_SIZE(innobase_change_buffering_values));
+ innobase_change_buffering = (char*)
+ innobase_change_buffering_values[ibuf_use];
+
/* --------------------------------------------------*/
srv_file_flush_method_str = innobase_unix_file_flush_method;
@@ -1698,41 +2157,19 @@ innobase_init(
srv_n_log_files = (ulint) innobase_log_files_in_group;
srv_log_file_size = (ulint) innobase_log_file_size;
- srv_thread_concurrency_timer_based =
- (ibool) innobase_thread_concurrency_timer_based;
-
#ifdef UNIV_LOG_ARCHIVE
srv_log_archive_on = (ulint) innobase_log_archive;
#endif /* UNIV_LOG_ARCHIVE */
srv_log_buffer_size = (ulint) innobase_log_buffer_size;
- srv_io_capacity = (ulint) innobase_io_capacity;
- srv_extra_dirty_writes = (ulint) innobase_extra_dirty_writes;
-
- /* We set srv_pool_size here in units of 1 kB. InnoDB internally
- changes the value so that it becomes the number of database pages. */
-
- if (innobase_buffer_pool_awe_mem_mb == 0) {
- srv_pool_size = (ulint)(innobase_buffer_pool_size / 1024);
- } else {
- srv_use_awe = TRUE;
- srv_pool_size = (ulint)
- (1024 * innobase_buffer_pool_awe_mem_mb);
- srv_awe_window_size = (ulint) innobase_buffer_pool_size;
-
- /* Note that what the user specified as
- innodb_buffer_pool_size is actually the AWE memory window
- size in this case, and the real buffer pool size is
- determined by .._awe_mem_mb. */
- }
+ srv_buf_pool_size = (ulint) innobase_buffer_pool_size;
srv_mem_pool_size = (ulint) innobase_additional_mem_pool_size;
- srv_n_read_io_threads = (ulint) innobase_read_io_threads;
- srv_n_write_io_threads = (ulint) innobase_write_io_threads;
- srv_max_merged_io = (ulint) innobase_max_merged_io;
+ srv_n_file_io_threads = (ulint) innobase_file_io_threads;
+ srv_n_read_io_threads = (ulint) innobase_read_io_threads;
+ srv_n_write_io_threads = (ulint) innobase_write_io_threads;
- srv_lock_wait_timeout = (ulint) innobase_lock_wait_timeout;
srv_force_recovery = (ulint) innobase_force_recovery;
srv_use_doublewrite_buf = (ibool) innobase_use_doublewrite;
@@ -1745,15 +2182,11 @@ innobase_init(
row_rollback_on_timeout = (ibool) innobase_rollback_on_timeout;
- srv_file_per_table = (ibool) innobase_file_per_table;
srv_locks_unsafe_for_binlog = (ibool) innobase_locks_unsafe_for_binlog;
srv_max_n_open_files = (ulint) innobase_open_files;
srv_innodb_status = (ibool) innobase_create_status_file;
- srv_use_adaptive_hash_indexes =
- (ibool) innobase_adaptive_hash_index;
-
srv_print_verbose_log = mysqld_embedded ? 0 : 1;
/* Store the default charset-collation number of this MySQL
@@ -1770,9 +2203,10 @@ innobase_init(
and consequently we do not need to know the ordering internally in
InnoDB. */
- ut_a(0 == strcmp((char*)my_charset_latin1.name,
- (char*)"latin1_swedish_ci"));
- memcpy(srv_latin1_ordering, my_charset_latin1.sort_order, 256);
+ ut_a(0 == strcmp(my_charset_latin1.name, "latin1_swedish_ci"));
+ srv_latin1_ordering = my_charset_latin1.sort_order;
+
+ innobase_commit_concurrency_init_default();
/* Since we in this module access directly the fields of a trx
struct, and due to different headers and flags it might happen that
@@ -1780,41 +2214,49 @@ innobase_init(
modules, we check at run time that the size is the same in
these compilation modules. */
- srv_sizeof_trx_t_in_ha_innodb_cc = sizeof(trx_t);
-
err = innobase_start_or_create_for_mysql();
if (err != DB_SUCCESS) {
- my_free(internal_innobase_data_file_path,
- MYF(MY_ALLOW_ZERO_PTR));
- goto error;
+ goto mem_free_and_error;
}
- (void) hash_init(&innobase_open_tables,system_charset_info, 32, 0, 0,
- (hash_get_key) innobase_get_key, 0, 0);
+ innobase_open_tables = hash_create(200);
pthread_mutex_init(&innobase_share_mutex, MY_MUTEX_INIT_FAST);
pthread_mutex_init(&prepare_commit_mutex, MY_MUTEX_INIT_FAST);
pthread_mutex_init(&commit_threads_m, MY_MUTEX_INIT_FAST);
pthread_mutex_init(&commit_cond_m, MY_MUTEX_INIT_FAST);
pthread_cond_init(&commit_cond, NULL);
innodb_inited= 1;
+#ifdef MYSQL_DYNAMIC_PLUGIN
+ if (innobase_hton != p) {
+ innobase_hton = reinterpret_cast(p);
+ *innobase_hton = *innodb_hton_ptr;
+ }
+#endif /* MYSQL_DYNAMIC_PLUGIN */
+
+ /* Get the current high water mark format. */
+ innobase_file_format_check = (char*) trx_sys_file_format_max_get();
DBUG_RETURN(FALSE);
error:
DBUG_RETURN(TRUE);
}
-/***********************************************************************
-Closes an InnoDB database. */
+/*******************************************************************//**
+Closes an InnoDB database.
+@return TRUE if error */
static
int
-innobase_end(handlerton *hton, ha_panic_function type)
-/*==============*/
- /* out: TRUE if error */
+innobase_end(
+/*=========*/
+ handlerton* hton, /*!< in/out: InnoDB handlerton */
+ ha_panic_function type __attribute__((unused)))
+ /*!< in: ha_panic() parameter */
{
int err= 0;
DBUG_ENTER("innobase_end");
+ DBUG_ASSERT(hton == innodb_hton_ptr);
#ifdef __NETWARE__ /* some special cleanup for NetWare */
if (nw_panic) {
@@ -1825,10 +2267,12 @@ innobase_end(handlerton *hton, ha_panic_function type)
srv_fast_shutdown = (ulint) innobase_fast_shutdown;
innodb_inited = 0;
+ hash_table_free(innobase_open_tables);
+ innobase_open_tables = NULL;
if (innobase_shutdown_for_mysql() != DB_SUCCESS) {
err = 1;
}
- hash_free(&innobase_open_tables);
+ srv_free_paths_and_sizes();
my_free(internal_innobase_data_file_path,
MYF(MY_ALLOW_ZERO_PTR));
pthread_mutex_destroy(&innobase_share_mutex);
@@ -1841,31 +2285,48 @@ innobase_end(handlerton *hton, ha_panic_function type)
DBUG_RETURN(err);
}
-/********************************************************************
+/****************************************************************//**
Flushes InnoDB logs to disk and makes a checkpoint. Really, a commit flushes
-the logs, and the name of this function should be innobase_checkpoint. */
+the logs, and the name of this function should be innobase_checkpoint.
+@return TRUE if error */
static
bool
-innobase_flush_logs(handlerton *hton)
-/*=====================*/
- /* out: TRUE if error */
+innobase_flush_logs(
+/*================*/
+ handlerton* hton) /*!< in/out: InnoDB handlerton */
{
bool result = 0;
DBUG_ENTER("innobase_flush_logs");
+ DBUG_ASSERT(hton == innodb_hton_ptr);
log_buffer_flush_to_disk();
DBUG_RETURN(result);
}
-/*********************************************************************
+/****************************************************************//**
+Return alter table flags supported in an InnoDB database. */
+static
+uint
+innobase_alter_table_flags(
+/*=======================*/
+ uint flags)
+{
+ return(HA_ONLINE_ADD_INDEX_NO_WRITES
+ | HA_ONLINE_DROP_INDEX_NO_WRITES
+ | HA_ONLINE_ADD_UNIQUE_INDEX_NO_WRITES
+ | HA_ONLINE_DROP_UNIQUE_INDEX_NO_WRITES
+ | HA_ONLINE_ADD_PK_INDEX_NO_WRITES);
+}
+
+/*****************************************************************//**
Commits a transaction in an InnoDB database. */
static
void
innobase_commit_low(
/*================*/
- trx_t* trx) /* in: transaction handle */
+ trx_t* trx) /*!< in: transaction handle */
{
if (trx->conc_state == TRX_NOT_STARTED) {
@@ -1875,23 +2336,24 @@ innobase_commit_low(
trx_commit_for_mysql(trx);
}
-/*********************************************************************
+/*****************************************************************//**
Creates an InnoDB transaction struct for the thd if it does not yet have one.
Starts a new InnoDB transaction if a transaction is not yet started. And
assigns a new snapshot for a consistent read if the transaction does not yet
-have one. */
+have one.
+@return 0 */
static
int
innobase_start_trx_and_assign_read_view(
/*====================================*/
- /* out: 0 */
- handlerton *hton, /* in: Innodb handlerton */
- THD* thd) /* in: MySQL thread handle of the user for whom
+ handlerton *hton, /*!< in: Innodb handlerton */
+ THD* thd) /*!< in: MySQL thread handle of the user for whom
the transaction should be committed */
{
trx_t* trx;
DBUG_ENTER("innobase_start_trx_and_assign_read_view");
+ DBUG_ASSERT(hton == innodb_hton_ptr);
/* Create a new trx struct for thd, if it does not yet have one */
@@ -1905,7 +2367,7 @@ innobase_start_trx_and_assign_read_view(
/* If the transaction is not started yet, start it */
- trx_start_if_not_started_noninline(trx);
+ trx_start_if_not_started(trx);
/* Assign a read view if the transaction does not have it yet */
@@ -1914,37 +2376,35 @@ innobase_start_trx_and_assign_read_view(
/* Set the MySQL flag to mark that there is an active transaction */
if (trx->active_trans == 0) {
- innobase_register_trx_and_stmt(hton, current_thd);
+ innobase_register_trx_and_stmt(hton, thd);
trx->active_trans = 1;
}
DBUG_RETURN(0);
}
-/*********************************************************************
+/*****************************************************************//**
Commits a transaction in an InnoDB database or marks an SQL statement
-ended. */
+ended.
+@return 0 */
static
int
innobase_commit(
/*============*/
- /* out: 0 */
- handlerton *hton, /* in: Innodb handlerton */
- THD* thd, /* in: MySQL thread handle of the user for whom
+ handlerton *hton, /*!< in: Innodb handlerton */
+ THD* thd, /*!< in: MySQL thread handle of the user for whom
the transaction should be committed */
- bool all) /* in: TRUE - commit transaction
+ bool all) /*!< in: TRUE - commit transaction
FALSE - the current SQL statement ended */
{
trx_t* trx;
DBUG_ENTER("innobase_commit");
+ DBUG_ASSERT(hton == innodb_hton_ptr);
DBUG_PRINT("trans", ("ending transaction"));
trx = check_trx_exists(thd);
- /* Update the info whether we should skip XA steps that eat CPU time */
- trx->support_xa = THDVAR(thd, support_xa);
-
/* Since we will reserve the kernel mutex, we have to release
the search system latch first to obey the latching order. */
@@ -1983,11 +2443,11 @@ innobase_commit(
Note, the position is current because of
prepare_commit_mutex */
retry:
- if (srv_commit_concurrency > 0) {
+ if (innobase_commit_concurrency > 0) {
pthread_mutex_lock(&commit_cond_m);
commit_threads++;
- if (commit_threads > srv_commit_concurrency) {
+ if (commit_threads > innobase_commit_concurrency) {
commit_threads--;
pthread_cond_wait(&commit_cond,
&commit_cond_m);
@@ -2000,11 +2460,16 @@ retry:
}
trx->mysql_log_file_name = mysql_bin_log_file_name();
- trx->mysql_log_offset = (ib_longlong) mysql_bin_log_file_pos();
+ trx->mysql_log_offset = (ib_int64_t) mysql_bin_log_file_pos();
+ /* Don't do write + flush right now. For group commit
+ to work we want to do the flush after releasing the
+ prepare_commit_mutex. */
+ trx->flush_log_later = TRUE;
innobase_commit_low(trx);
+ trx->flush_log_later = FALSE;
- if (srv_commit_concurrency > 0) {
+ if (innobase_commit_concurrency > 0) {
pthread_mutex_lock(&commit_cond_m);
commit_threads--;
pthread_cond_signal(&commit_cond);
@@ -2016,6 +2481,8 @@ retry:
pthread_mutex_unlock(&prepare_commit_mutex);
}
+ /* Now do a write + flush of logs. */
+ trx_commit_complete_for_mysql(trx);
trx->active_trans = 0;
} else {
@@ -2049,30 +2516,28 @@ retry:
DBUG_RETURN(0);
}
-/*********************************************************************
-Rolls back a transaction or the latest SQL statement. */
+/*****************************************************************//**
+Rolls back a transaction or the latest SQL statement.
+@return 0 or error number */
static
int
innobase_rollback(
/*==============*/
- /* out: 0 or error number */
- handlerton *hton, /* in: Innodb handlerton */
- THD* thd, /* in: handle to the MySQL thread of the user
+ handlerton *hton, /*!< in: Innodb handlerton */
+ THD* thd, /*!< in: handle to the MySQL thread of the user
whose transaction should be rolled back */
- bool all) /* in: TRUE - commit transaction
+ bool all) /*!< in: TRUE - commit transaction
FALSE - the current SQL statement ended */
{
int error = 0;
trx_t* trx;
DBUG_ENTER("innobase_rollback");
+ DBUG_ASSERT(hton == innodb_hton_ptr);
DBUG_PRINT("trans", ("aborting transaction"));
trx = check_trx_exists(thd);
- /* Update the info whether we should skip XA steps that eat CPU time */
- trx->support_xa = THDVAR(thd, support_xa);
-
/* Release a possible FIFO ticket and search latch. Since we will
reserve the kernel mutex, we have to release the search system latch
first to obey the latching order. */
@@ -2094,17 +2559,17 @@ innobase_rollback(
error = trx_rollback_last_sql_stat_for_mysql(trx);
}
- DBUG_RETURN(convert_error_code_to_mysql(error, NULL));
+ DBUG_RETURN(convert_error_code_to_mysql(error, 0, NULL));
}
-/*********************************************************************
-Rolls back a transaction */
+/*****************************************************************//**
+Rolls back a transaction
+@return 0 or error number */
static
int
innobase_rollback_trx(
/*==================*/
- /* out: 0 or error number */
- trx_t* trx) /* in: transaction */
+ trx_t* trx) /*!< in: transaction */
{
int error = 0;
@@ -2125,28 +2590,29 @@ innobase_rollback_trx(
error = trx_rollback_for_mysql(trx);
- DBUG_RETURN(convert_error_code_to_mysql(error, NULL));
+ DBUG_RETURN(convert_error_code_to_mysql(error, 0, NULL));
}
-/*********************************************************************
-Rolls back a transaction to a savepoint. */
+/*****************************************************************//**
+Rolls back a transaction to a savepoint.
+@return 0 if success, HA_ERR_NO_SAVEPOINT if no savepoint with the
+given name */
static
int
innobase_rollback_to_savepoint(
/*===========================*/
- /* out: 0 if success, HA_ERR_NO_SAVEPOINT if
- no savepoint with the given name */
- handlerton *hton, /* in: Innodb handlerton */
- THD* thd, /* in: handle to the MySQL thread of the user
+ handlerton *hton, /*!< in: Innodb handlerton */
+ THD* thd, /*!< in: handle to the MySQL thread of the user
whose transaction should be rolled back */
- void* savepoint) /* in: savepoint data */
+ void* savepoint) /*!< in: savepoint data */
{
- ib_longlong mysql_binlog_cache_pos;
+ ib_int64_t mysql_binlog_cache_pos;
int error = 0;
trx_t* trx;
char name[64];
DBUG_ENTER("innobase_rollback_to_savepoint");
+ DBUG_ASSERT(hton == innodb_hton_ptr);
trx = check_trx_exists(thd);
@@ -2162,27 +2628,28 @@ innobase_rollback_to_savepoint(
error = (int) trx_rollback_to_savepoint_for_mysql(trx, name,
&mysql_binlog_cache_pos);
- DBUG_RETURN(convert_error_code_to_mysql(error, NULL));
+ DBUG_RETURN(convert_error_code_to_mysql(error, 0, NULL));
}
-/*********************************************************************
-Release transaction savepoint name. */
+/*****************************************************************//**
+Release transaction savepoint name.
+@return 0 if success, HA_ERR_NO_SAVEPOINT if no savepoint with the
+given name */
static
int
innobase_release_savepoint(
/*=======================*/
- /* out: 0 if success, HA_ERR_NO_SAVEPOINT if
- no savepoint with the given name */
- handlerton* hton, /* in: handlerton for Innodb */
- THD* thd, /* in: handle to the MySQL thread of the user
+ handlerton* hton, /*!< in: handlerton for Innodb */
+ THD* thd, /*!< in: handle to the MySQL thread of the user
whose transaction should be rolled back */
- void* savepoint) /* in: savepoint data */
+ void* savepoint) /*!< in: savepoint data */
{
int error = 0;
trx_t* trx;
char name[64];
DBUG_ENTER("innobase_release_savepoint");
+ DBUG_ASSERT(hton == innodb_hton_ptr);
trx = check_trx_exists(thd);
@@ -2192,24 +2659,25 @@ innobase_release_savepoint(
error = (int) trx_release_savepoint_for_mysql(trx, name);
- DBUG_RETURN(convert_error_code_to_mysql(error, NULL));
+ DBUG_RETURN(convert_error_code_to_mysql(error, 0, NULL));
}
-/*********************************************************************
-Sets a transaction savepoint. */
+/*****************************************************************//**
+Sets a transaction savepoint.
+@return always 0, that is, always succeeds */
static
int
innobase_savepoint(
/*===============*/
- /* out: always 0, that is, always succeeds */
- handlerton* hton, /* in: handle to the Innodb handlerton */
- THD* thd, /* in: handle to the MySQL thread */
- void* savepoint) /* in: savepoint data */
+ handlerton* hton, /*!< in: handle to the Innodb handlerton */
+ THD* thd, /*!< in: handle to the MySQL thread */
+ void* savepoint) /*!< in: savepoint data */
{
int error = 0;
trx_t* trx;
DBUG_ENTER("innobase_savepoint");
+ DBUG_ASSERT(hton == innodb_hton_ptr);
/*
In the autocommit mode there is no sense to set a savepoint
@@ -2236,20 +2704,20 @@ innobase_savepoint(
char name[64];
longlong2str((ulint)savepoint,name,36);
- error = (int) trx_savepoint_for_mysql(trx, name, (ib_longlong)0);
+ error = (int) trx_savepoint_for_mysql(trx, name, (ib_int64_t)0);
- DBUG_RETURN(convert_error_code_to_mysql(error, NULL));
+ DBUG_RETURN(convert_error_code_to_mysql(error, 0, NULL));
}
-/*********************************************************************
-Frees a possible InnoDB trx object associated with the current THD. */
+/*****************************************************************//**
+Frees a possible InnoDB trx object associated with the current THD.
+@return 0 or error number */
static
int
innobase_close_connection(
/*======================*/
- /* out: 0 or error number */
- handlerton* hton, /* in: innobase handlerton */
- THD* thd) /* in: handle to the MySQL thread of the user
+ handlerton* hton, /*!< in: innobase handlerton */
+ THD* thd) /*!< in: handle to the MySQL thread of the user
whose resources should be free'd */
{
trx_t* trx;
@@ -2286,23 +2754,41 @@ innobase_close_connection(
}
-/*****************************************************************************
+/*************************************************************************//**
** InnoDB database tables
*****************************************************************************/
-/********************************************************************
-Get the record format from the data dictionary. */
+/****************************************************************//**
+Get the record format from the data dictionary.
+@return one of ROW_TYPE_REDUNDANT, ROW_TYPE_COMPACT,
+ROW_TYPE_COMPRESSED, ROW_TYPE_DYNAMIC */
+UNIV_INTERN
enum row_type
ha_innobase::get_row_type() const
/*=============================*/
- /* out: ROW_TYPE_REDUNDANT or ROW_TYPE_COMPACT */
{
if (prebuilt && prebuilt->table) {
- if (dict_table_is_comp_noninline(prebuilt->table)) {
- return(ROW_TYPE_COMPACT);
- } else {
+ const ulint flags = prebuilt->table->flags;
+
+ if (UNIV_UNLIKELY(!flags)) {
return(ROW_TYPE_REDUNDANT);
}
+
+ ut_ad(flags & DICT_TF_COMPACT);
+
+ switch (flags & DICT_TF_FORMAT_MASK) {
+ case DICT_TF_FORMAT_51 << DICT_TF_FORMAT_SHIFT:
+ return(ROW_TYPE_COMPACT);
+ case DICT_TF_FORMAT_ZIP << DICT_TF_FORMAT_SHIFT:
+ if (flags & DICT_TF_ZSSIZE_MASK) {
+ return(ROW_TYPE_COMPRESSED);
+ } else {
+ return(ROW_TYPE_DYNAMIC);
+ }
+#if DICT_TF_FORMAT_ZIP != DICT_TF_FORMAT_MAX
+# error "DICT_TF_FORMAT_ZIP != DICT_TF_FORMAT_MAX"
+#endif
+ }
}
ut_ad(0);
return(ROW_TYPE_NOT_USED);
@@ -2310,36 +2796,137 @@ ha_innobase::get_row_type() const
-/********************************************************************
-Get the table flags to use for the statement. */
+/****************************************************************//**
+Get the table flags to use for the statement.
+@return table flags */
+UNIV_INTERN
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);
+ ulong const tx_isolation = thd_tx_isolation(ha_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[] = {
".ibd",
NullS
};
+/****************************************************************//**
+Returns the table type (storage engine name).
+@return table type */
+UNIV_INTERN
+const char*
+ha_innobase::table_type() const
+/*===========================*/
+{
+ return(innobase_hton_name);
+}
+
+/****************************************************************//**
+Returns the index type. */
+UNIV_INTERN
+const char*
+ha_innobase::index_type(
+/*====================*/
+ uint)
+ /*!< out: index type */
+{
+ return("BTREE");
+}
+
+/****************************************************************//**
+Returns the table file name extension.
+@return file extension string */
+UNIV_INTERN
const char**
ha_innobase::bas_ext() const
/*========================*/
- /* out: file extension string */
{
- return ha_innobase_exts;
+ return(ha_innobase_exts);
}
+/****************************************************************//**
+Returns the operations supported for indexes.
+@return flags of supported operations */
+UNIV_INTERN
+ulong
+ha_innobase::index_flags(
+/*=====================*/
+ uint,
+ uint,
+ bool)
+const
+{
+ return(HA_READ_NEXT | HA_READ_PREV | HA_READ_ORDER
+ | HA_READ_RANGE | HA_KEYREAD_ONLY);
+}
-/*********************************************************************
+/****************************************************************//**
+Returns the maximum number of keys.
+@return MAX_KEY */
+UNIV_INTERN
+uint
+ha_innobase::max_supported_keys() const
+/*===================================*/
+{
+ return(MAX_KEY);
+}
+
+/****************************************************************//**
+Returns the maximum key length.
+@return maximum supported key length, in bytes */
+UNIV_INTERN
+uint
+ha_innobase::max_supported_key_length() const
+/*=========================================*/
+{
+ /* An InnoDB page must store >= 2 keys; a secondary key record
+ must also contain the primary key value: max key length is
+ therefore set to slightly less than 1 / 4 of page size which
+ is 16 kB; but currently MySQL does not work with keys whose
+ size is > MAX_KEY_LENGTH */
+ return(3500);
+}
+
+/****************************************************************//**
+Returns the key map of keys that are usable for scanning.
+@return key_map_full */
+UNIV_INTERN
+const key_map*
+ha_innobase::keys_to_use_for_scanning()
+{
+ return(&key_map_full);
+}
+
+/****************************************************************//**
+Determines if table caching is supported.
+@return HA_CACHE_TBL_ASKTRANSACT */
+UNIV_INTERN
+uint8
+ha_innobase::table_cache_type()
+{
+ return(HA_CACHE_TBL_ASKTRANSACT);
+}
+
+/****************************************************************//**
+Determines if the primary key is clustered index.
+@return true */
+UNIV_INTERN
+bool
+ha_innobase::primary_key_is_clustered()
+{
+ return(true);
+}
+
+/*****************************************************************//**
Normalizes a table name string. A normalized name consists of the
database name catenated to '/' and table name. An example:
test/mytable. On Windows normalization puts both the database name and the
@@ -2348,9 +2935,9 @@ static
void
normalize_table_name(
/*=================*/
- char* norm_name, /* out: normalized name as a
+ char* norm_name, /*!< out: normalized name as a
null-terminated string */
- const char* name) /* in: table name string */
+ const char* name) /*!< in: table name string */
{
char* name_ptr;
char* db_ptr;
@@ -2385,19 +2972,19 @@ normalize_table_name(
#endif
}
-/************************************************************************
+/********************************************************************//**
Set the autoinc column max value. This should only be called once from
-ha_innobase::open(). Therefore there's no need for a covering lock. */
-
-ulong
+ha_innobase::open(). Therefore there's no need for a covering lock.
+@return DB_SUCCESS or error code */
+UNIV_INTERN
+ulint
ha_innobase::innobase_initialize_autoinc()
/*======================================*/
{
dict_index_t* index;
ulonglong auto_inc;
const char* col_name;
- ulint error = DB_SUCCESS;
- dict_table_t* innodb_table = prebuilt->table;
+ ulint error;
col_name = table->found_next_number_field->field_name;
index = innobase_get_index(table->s->next_number_index);
@@ -2405,35 +2992,53 @@ ha_innobase::innobase_initialize_autoinc()
/* Execute SELECT MAX(col_name) FROM TABLE; */
error = row_search_max_autoinc(index, col_name, &auto_inc);
- if (error == DB_SUCCESS) {
+ switch (error) {
+ case DB_SUCCESS:
- /* At the this stage we dont' know the increment
+ /* At the this stage we don't know the increment
or the offset, so use default inrement of 1. */
++auto_inc;
+ break;
- dict_table_autoinc_initialize(innodb_table, auto_inc);
-
- } else {
+ case DB_RECORD_NOT_FOUND:
ut_print_timestamp(stderr);
- fprintf(stderr, " InnoDB: Error: (%lu) Couldn't read "
- "the MAX(%s) autoinc value from the "
- "index (%s).\n", error, col_name, index->name);
+ fprintf(stderr, " InnoDB: MySQL and InnoDB data "
+ "dictionaries are out of sync.\n"
+ "InnoDB: Unable to find the AUTOINC column %s in the "
+ "InnoDB table %s.\n"
+ "InnoDB: We set the next AUTOINC column value to the "
+ "maximum possible value,\n"
+ "InnoDB: in effect disabling the AUTOINC next value "
+ "generation.\n"
+ "InnoDB: You can either set the next AUTOINC value "
+ "explicitly using ALTER TABLE\n"
+ "InnoDB: or fix the data dictionary by recreating "
+ "the table.\n",
+ col_name, index->table->name);
+
+ auto_inc = 0xFFFFFFFFFFFFFFFFULL;
+ break;
+
+ default:
+ return(error);
}
- return(ulong(error));
+ dict_table_autoinc_initialize(prebuilt->table, auto_inc);
+
+ return(DB_SUCCESS);
}
-/*********************************************************************
+/*****************************************************************//**
Creates and opens a handle to a table which already exists in an InnoDB
-database. */
-
+database.
+@return 1 if error, 0 if success */
+UNIV_INTERN
int
ha_innobase::open(
/*==============*/
- /* out: 1 if error, 0 if success */
- const char* name, /* in: table name */
- int mode, /* in: not used */
- uint test_if_locked) /* in: not used */
+ const char* name, /*!< in: table name */
+ int mode, /*!< in: not used */
+ uint test_if_locked) /*!< in: not used */
{
dict_table_t* ib_table;
char norm_name[1000];
@@ -2516,7 +3121,7 @@ retry:
"or, the table contains indexes that this "
"version of the engine\n"
"doesn't support.\n"
- "See http://dev.mysql.com/doc/refman/5.1/en/innodb-troubleshooting.html\n"
+ "See " REFMAN "innodb-troubleshooting.html\n"
"how you can resolve the problem.\n",
norm_name);
free_share(share);
@@ -2532,14 +3137,14 @@ retry:
"Have you deleted the .ibd file from the "
"database directory under\nthe MySQL datadir, "
"or have you used DISCARD TABLESPACE?\n"
- "See http://dev.mysql.com/doc/refman/5.1/en/innodb-troubleshooting.html\n"
+ "See " REFMAN "innodb-troubleshooting.html\n"
"how you can resolve the problem.\n",
norm_name);
free_share(share);
my_free(upd_buff, MYF(0));
my_errno = ENOENT;
- dict_table_decrement_handle_count(ib_table);
+ dict_table_decrement_handle_count(ib_table, FALSE);
DBUG_RETURN(HA_ERR_NO_SUCH_TABLE);
}
@@ -2608,12 +3213,21 @@ retry:
}
}
- stats.block_size = 16 * 1024; /* Index block size in InnoDB: used by MySQL
- in query optimization */
+ /* Index block size in InnoDB: used by MySQL in query optimization */
+ stats.block_size = 16 * 1024;
/* Init table lock structure */
thr_lock_data_init(&share->lock,&lock,(void*) 0);
+ if (prebuilt->table) {
+ /* We update the highest file format in the system table
+ space, if this table has higher file format setting. */
+
+ trx_sys_file_format_max_upgrade(
+ (const char**) &innobase_file_format_check,
+ dict_table_get_format(prebuilt->table));
+ }
+
info(HA_STATUS_NO_LOCK | HA_STATUS_VARIABLE | HA_STATUS_CONST);
/* Only if the table has an AUTOINC column. */
@@ -2629,7 +3243,6 @@ retry:
if (dict_table_autoinc_read(prebuilt->table) == 0) {
error = innobase_initialize_autoinc();
- /* Should always succeed! */
ut_a(error == DB_SUCCESS);
}
@@ -2639,30 +3252,31 @@ retry:
DBUG_RETURN(0);
}
+UNIV_INTERN
uint
ha_innobase::max_supported_key_part_length() const
{
return(DICT_MAX_INDEX_COL_LEN - 1);
}
-/**********************************************************************
-Closes a handle to an InnoDB table. */
-
+/******************************************************************//**
+Closes a handle to an InnoDB table.
+@return 0 */
+UNIV_INTERN
int
ha_innobase::close(void)
/*====================*/
- /* out: 0 */
{
THD* thd;
DBUG_ENTER("ha_innobase::close");
- thd = current_thd; // avoid calling current_thd twice, it may be slow
+ thd = ha_thd();
if (thd != NULL) {
innobase_release_temporary_latches(ht, thd);
}
- row_prebuilt_free(prebuilt);
+ row_prebuilt_free(prebuilt, FALSE);
my_free(upd_buff, MYF(0));
free_share(share);
@@ -2677,30 +3291,30 @@ ha_innobase::close(void)
/* The following accessor functions should really be inside MySQL code! */
-/******************************************************************
-Gets field offset for a field in a table. */
-inline
+/**************************************************************//**
+Gets field offset for a field in a table.
+@return offset */
+static inline
uint
get_field_offset(
/*=============*/
- /* out: offset */
- TABLE* table, /* in: MySQL table object */
- Field* field) /* in: MySQL field object */
+ TABLE* table, /*!< in: MySQL table object */
+ Field* field) /*!< in: MySQL field object */
{
return((uint) (field->ptr - table->record[0]));
}
-/******************************************************************
+/**************************************************************//**
Checks if a field in a record is SQL NULL. Uses the record format
-information in table to track the null bit in record. */
+information in table to track the null bit in record.
+@return 1 if NULL, 0 otherwise */
static inline
uint
field_in_record_is_null(
/*====================*/
- /* out: 1 if NULL, 0 otherwise */
- TABLE* table, /* in: MySQL table object */
- Field* field, /* in: MySQL field object */
- char* record) /* in: a row in MySQL format */
+ TABLE* table, /*!< in: MySQL table object */
+ Field* field, /*!< in: MySQL field object */
+ char* record) /*!< in: a row in MySQL format */
{
int null_offset;
@@ -2720,16 +3334,16 @@ field_in_record_is_null(
return(0);
}
-/******************************************************************
+/**************************************************************//**
Sets a field in a record to SQL NULL. Uses the record format
information in table to track the null bit in record. */
-inline
+static inline
void
set_field_in_record_to_null(
/*========================*/
- TABLE* table, /* in: MySQL table object */
- Field* field, /* in: MySQL field object */
- char* record) /* in: a row in MySQL format */
+ TABLE* table, /*!< in: MySQL table object */
+ Field* field, /*!< in: MySQL field object */
+ char* record) /*!< in: a row in MySQL format */
{
int null_offset;
@@ -2739,25 +3353,23 @@ set_field_in_record_to_null(
record[null_offset] = record[null_offset] | field->null_bit;
}
-extern "C" {
-/*****************************************************************
+/*************************************************************//**
InnoDB uses this function to compare two data fields for which the data type
is such that we must use MySQL code to compare them. NOTE that the prototype
of this function is in rem0cmp.c in InnoDB source code! If you change this
-function, remember to update the prototype there! */
-
+function, remember to update the prototype there!
+@return 1, 0, -1, if a is greater, equal, less than b, respectively */
+extern "C" UNIV_INTERN
int
innobase_mysql_cmp(
/*===============*/
- /* out: 1, 0, -1, if a is greater,
- equal, less than b, respectively */
- int mysql_type, /* in: MySQL type */
- uint charset_number, /* in: number of the charset */
- unsigned char* a, /* in: data field */
- unsigned int a_length, /* in: data field length,
+ int mysql_type, /*!< in: MySQL type */
+ uint charset_number, /*!< in: number of the charset */
+ const unsigned char* a, /*!< in: data field */
+ unsigned int a_length, /*!< in: data field length,
not UNIV_SQL_NULL */
- unsigned char* b, /* in: data field */
- unsigned int b_length) /* in: data field length,
+ const unsigned char* b, /*!< in: data field */
+ unsigned int b_length) /*!< in: data field length,
not UNIV_SQL_NULL */
{
CHARSET_INFO* charset;
@@ -2816,27 +3428,30 @@ innobase_mysql_cmp(
return(0);
}
default:
- assert(0);
+ ut_error;
}
return(0);
}
-}
-/******************************************************************
+/**************************************************************//**
Converts a MySQL type to an InnoDB type. Note that this function returns
the 'mtype' of InnoDB. InnoDB differentiates between MySQL's old <= 4.1
-VARCHAR and the new true VARCHAR in >= 5.0.3 by the 'prtype'. */
-inline
+VARCHAR and the new true VARCHAR in >= 5.0.3 by the 'prtype'.
+@return DATA_BINARY, DATA_VARCHAR, ... */
+extern "C" UNIV_INTERN
ulint
get_innobase_type_from_mysql_type(
/*==============================*/
- /* out: DATA_BINARY, DATA_VARCHAR, ... */
- ulint* unsigned_flag, /* out: DATA_UNSIGNED if an 'unsigned type';
- at least ENUM and SET, and unsigned integer
- types are 'unsigned types' */
- Field* field) /* in: MySQL field */
+ ulint* unsigned_flag, /*!< out: DATA_UNSIGNED if an
+ 'unsigned type';
+ at least ENUM and SET,
+ and unsigned integer
+ types are 'unsigned types' */
+ const void* f) /*!< in: MySQL Field */
{
+ const class Field* field = reinterpret_cast(f);
+
/* The following asserts try to check that the MySQL type code fits in
8 bits: this is used in ibuf and also when DATA_NOT_NULL is ORed to
the type */
@@ -2920,21 +3535,21 @@ get_innobase_type_from_mysql_type(
case MYSQL_TYPE_LONG_BLOB:
return(DATA_BLOB);
default:
- assert(0);
+ ut_error;
}
return(0);
}
-/***********************************************************************
+/*******************************************************************//**
Writes an unsigned integer value < 64k to 2 bytes, in the little-endian
storage format. */
-inline
+static inline
void
innobase_write_to_2_little_endian(
/*==============================*/
- byte* buf, /* in: where to store */
- ulint val) /* in: value to write, must be < 64k */
+ byte* buf, /*!< in: where to store */
+ ulint val) /*!< in: value to write, must be < 64k */
{
ut_a(val < 256 * 256);
@@ -2942,31 +3557,31 @@ innobase_write_to_2_little_endian(
buf[1] = (byte)(val / 256);
}
-/***********************************************************************
+/*******************************************************************//**
Reads an unsigned integer value < 64k from 2 bytes, in the little-endian
-storage format. */
-inline
+storage format.
+@return value */
+static inline
uint
innobase_read_from_2_little_endian(
/*===============================*/
- /* out: value */
- const uchar* buf) /* in: from where to read */
+ const uchar* buf) /*!< in: from where to read */
{
return (uint) ((ulint)(buf[0]) + 256 * ((ulint)(buf[1])));
}
-/***********************************************************************
-Stores a key value for a row to a buffer. */
-
+/*******************************************************************//**
+Stores a key value for a row to a buffer.
+@return key value length as stored in buff */
+UNIV_INTERN
uint
ha_innobase::store_key_val_for_row(
/*===============================*/
- /* out: key value length as stored in buff */
- uint keynr, /* in: key number */
- char* buff, /* in/out: buffer for the key value (in MySQL
+ uint keynr, /*!< in: key number */
+ char* buff, /*!< in/out: buffer for the key value (in MySQL
format) */
- uint buff_len,/* in: buffer length */
- const uchar* record)/* in: row in MySQL format */
+ uint buff_len,/*!< in: buffer length */
+ const uchar* record)/*!< in: row in MySQL format */
{
KEY* key_info = table->key_info + keynr;
KEY_PART_INFO* key_part = key_info->key_part;
@@ -3024,13 +3639,13 @@ ha_innobase::store_key_val_for_row(
if (mysql_type == MYSQL_TYPE_VARCHAR) {
/* >= 5.0.3 true VARCHAR */
- ulint lenlen;
- ulint len;
- byte* data;
- ulint key_len;
- ulint true_len;
+ ulint lenlen;
+ ulint len;
+ const byte* data;
+ ulint key_len;
+ ulint true_len;
CHARSET_INFO* cs;
- int error=0;
+ int error=0;
key_len = key_part->length;
@@ -3096,7 +3711,7 @@ ha_innobase::store_key_val_for_row(
ulint true_len;
int error=0;
ulint blob_len;
- byte* blob_data;
+ const byte* blob_data;
ut_a(key_part->key_part_flag & HA_PART_KEY_SEG);
@@ -3229,19 +3844,19 @@ ha_innobase::store_key_val_for_row(
DBUG_RETURN((uint)(buff - buff_start));
}
-/******************************************************************
+/**************************************************************//**
Builds a 'template' to the prebuilt struct. The template is used in fast
retrieval of just those column values MySQL needs in its processing. */
static
void
build_template(
/*===========*/
- row_prebuilt_t* prebuilt, /* in/out: prebuilt struct */
- THD* thd, /* in: current user thread, used
+ row_prebuilt_t* prebuilt, /*!< in/out: prebuilt struct */
+ THD* thd, /*!< in: current user thread, used
only if templ_type is
ROW_MYSQL_REC_FIELDS */
- TABLE* table, /* in: MySQL table */
- uint templ_type) /* in: ROW_MYSQL_WHOLE_ROW or
+ TABLE* table, /*!< in: MySQL table */
+ uint templ_type) /*!< in: ROW_MYSQL_WHOLE_ROW or
ROW_MYSQL_REC_FIELDS */
{
dict_index_t* index;
@@ -3296,7 +3911,7 @@ build_template(
}
}
- clust_index = dict_table_get_first_index_noninline(prebuilt->table);
+ clust_index = dict_table_get_first_index(prebuilt->table);
if (templ_type == ROW_MYSQL_REC_FIELDS) {
index = prebuilt->index;
@@ -3316,8 +3931,7 @@ build_template(
if (!prebuilt->mysql_template) {
prebuilt->mysql_template = (mysql_row_templ_t*)
- mem_alloc_noninline(
- n_fields * sizeof(mysql_row_templ_t));
+ mem_alloc(n_fields * sizeof(mysql_row_templ_t));
}
prebuilt->template_type = templ_type;
@@ -3375,7 +3989,7 @@ include_field:
templ->col_no = i;
if (index == clust_index) {
- templ->rec_field_no = dict_col_get_clust_pos_noninline(
+ templ->rec_field_no = dict_col_get_clust_pos(
&index->table->cols[i], index);
} else {
templ->rec_field_no = dict_index_get_nth_col_pos(
@@ -3413,8 +4027,8 @@ include_field:
(((Field_varstring*)field)->length_bytes);
}
- templ->charset = dtype_get_charset_coll_noninline(
- index->table->cols[i].prtype);
+ templ->charset = dtype_get_charset_coll(
+ index->table->cols[i].prtype);
templ->mbminlen = index->table->cols[i].mbminlen;
templ->mbmaxlen = index->table->cols[i].mbmaxlen;
templ->is_unsigned = index->table->cols[i].prtype
@@ -3435,16 +4049,16 @@ skip_field:
for (i = 0; i < n_requested_fields; i++) {
templ = prebuilt->mysql_template + i;
- templ->rec_field_no = dict_col_get_clust_pos_noninline(
+ templ->rec_field_no = dict_col_get_clust_pos(
&index->table->cols[templ->col_no],
clust_index);
}
}
}
-/************************************************************************
+/********************************************************************//**
Get the upper limit of the MySQL integral and floating-point type. */
-
+UNIV_INTERN
ulonglong
ha_innobase::innobase_get_int_col_max_value(
/*========================================*/
@@ -3503,18 +4117,17 @@ ha_innobase::innobase_get_int_col_max_value(
return(max_value);
}
-/************************************************************************
+/********************************************************************//**
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
+the special lock handling.
+@return DB_SUCCESS if all OK else error code */
+UNIV_INTERN
+ulint
ha_innobase::innobase_lock_autoinc(void)
/*====================================*/
- /* out: DB_SUCCESS if all OK else
- error code */
{
ulint error = DB_SUCCESS;
@@ -3564,15 +4177,14 @@ ha_innobase::innobase_lock_autoinc(void)
return(ulong(error));
}
-/************************************************************************
-Reset the autoinc value in the table.*/
-
-ulong
+/********************************************************************//**
+Reset the autoinc value in the table.
+@return DB_SUCCESS if all went well else error code */
+UNIV_INTERN
+ulint
ha_innobase::innobase_reset_autoinc(
/*================================*/
- /* out: DB_SUCCESS if all went well
- else error code */
- ulonglong autoinc) /* in: value to store */
+ ulonglong autoinc) /*!< in: value to store */
{
ulint error;
@@ -3588,16 +4200,15 @@ ha_innobase::innobase_reset_autoinc(
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
+it's greater than the existing autoinc value in the table.
+@return DB_SUCCESS if all went well else error code */
+UNIV_INTERN
+ulint
ha_innobase::innobase_set_max_autoinc(
/*==================================*/
- /* out: DB_SUCCES if all went well
- else error code */
- ulonglong auto_inc) /* in: value to store */
+ ulonglong auto_inc) /*!< in: value to store */
{
ulint error;
@@ -3613,15 +4224,15 @@ ha_innobase::innobase_set_max_autoinc(
return(ulong(error));
}
-/************************************************************************
+/********************************************************************//**
Stores a row in an InnoDB database, to the table specified in this
-handle. */
-
+handle.
+@return error code */
+UNIV_INTERN
int
ha_innobase::write_row(
/*===================*/
- /* out: error code */
- uchar* record) /* in: a row in MySQL format */
+ uchar* record) /*!< in: a row in MySQL format */
{
ulint error = 0;
int error_result= 0;
@@ -3634,7 +4245,7 @@ ha_innobase::write_row(
if (prebuilt->trx != trx) {
sql_print_error("The transaction object for the table handle is at "
"%p, but for the current thread it is at %p",
- prebuilt->trx, trx);
+ (const void*) prebuilt->trx, (const void*) trx);
fputs("InnoDB: Dump of 200 bytes around prebuilt: ", stderr);
ut_print_buf(stderr, ((const byte*)prebuilt) - 100, 200);
@@ -3668,7 +4279,7 @@ ha_innobase::write_row(
being blocked by a MySQL table lock TL_WRITE_ALLOW_READ. */
dict_table_t* src_table;
- ulint mode;
+ enum lock_mode mode;
num_write_row = 0;
@@ -3803,7 +4414,6 @@ no_commit:
case SQLCOM_INSERT_SELECT:
case SQLCOM_REPLACE_SELECT:
goto set_max_autoinc;
- break;
default:
break;
@@ -3844,7 +4454,9 @@ set_max_autoinc:
innodb_srv_conc_exit_innodb(prebuilt->trx);
report_error:
- error_result = convert_error_code_to_mysql((int) error, user_thd);
+ error_result = convert_error_code_to_mysql((int) error,
+ prebuilt->table->flags,
+ user_thd);
func_exit:
innobase_active_small();
@@ -3852,23 +4464,23 @@ func_exit:
DBUG_RETURN(error_result);
}
-/**************************************************************************
+/**********************************************************************//**
Checks which fields have changed in a row and stores information
-of them to an update vector. */
+of them to an update vector.
+@return error number or 0 */
static
int
calc_row_difference(
/*================*/
- /* out: error number or 0 */
- upd_t* uvect, /* in/out: update vector */
- uchar* old_row, /* in: old row in MySQL format */
- uchar* new_row, /* in: new row in MySQL format */
- struct st_table* table, /* in: table in MySQL data
+ upd_t* uvect, /*!< in/out: update vector */
+ uchar* old_row, /*!< in: old row in MySQL format */
+ uchar* new_row, /*!< in: new row in MySQL format */
+ struct st_table* table, /*!< in: table in MySQL data
dictionary */
- uchar* upd_buff, /* in: buffer to use */
- ulint buff_len, /* in: buffer length */
- row_prebuilt_t* prebuilt, /* in: InnoDB prebuilt struct */
- THD* thd) /* in: user thread */
+ uchar* upd_buff, /*!< in: buffer to use */
+ ulint buff_len, /*!< in: buffer length */
+ row_prebuilt_t* prebuilt, /*!< in: InnoDB prebuilt struct */
+ THD* thd) /*!< in: user thread */
{
uchar* original_upd_buff = upd_buff;
Field* field;
@@ -3877,9 +4489,9 @@ calc_row_difference(
ulint o_len;
ulint n_len;
ulint col_pack_len;
- byte* new_mysql_row_col;
- byte* o_ptr;
- byte* n_ptr;
+ const byte* new_mysql_row_col;
+ const byte* o_ptr;
+ const byte* n_ptr;
byte* buf;
upd_field_t* ufield;
ulint col_type;
@@ -3889,7 +4501,7 @@ calc_row_difference(
uint i;
n_fields = table->s->fields;
- clust_index = dict_table_get_first_index_noninline(prebuilt->table);
+ clust_index = dict_table_get_first_index(prebuilt->table);
/* We use upd_buff to convert changed fields */
buf = (byte*) upd_buff;
@@ -3897,8 +4509,8 @@ calc_row_difference(
for (i = 0; i < n_fields; i++) {
field = table->field[i];
- o_ptr = (byte*) old_row + get_field_offset(table, field);
- n_ptr = (byte*) new_row + get_field_offset(table, field);
+ o_ptr = (const byte*) old_row + get_field_offset(table, field);
+ n_ptr = (const byte*) new_row + get_field_offset(table, field);
/* Use new_mysql_row_col and col_pack_len save the values */
@@ -3968,8 +4580,8 @@ calc_row_difference(
/* Let us use a dummy dfield to make the conversion
from the MySQL column format to the InnoDB format */
- dict_col_copy_type_noninline(prebuilt->table->cols + i,
- &dfield.type);
+ dict_col_copy_type(prebuilt->table->cols + i,
+ dfield_get_type(&dfield));
if (n_len != UNIV_SQL_NULL) {
buf = row_mysql_store_col_in_innobase_format(
@@ -3978,17 +4590,15 @@ calc_row_difference(
TRUE,
new_mysql_row_col,
col_pack_len,
- dict_table_is_comp_noninline(
- prebuilt->table));
- ufield->new_val.data = dfield.data;
- ufield->new_val.len = dfield.len;
+ dict_table_is_comp(prebuilt->table));
+ dfield_copy_data(&ufield->new_val, &dfield);
} else {
- ufield->new_val.data = NULL;
- ufield->new_val.len = UNIV_SQL_NULL;
+ dfield_set_null(&ufield->new_val);
}
ufield->exp = NULL;
- ufield->field_no = dict_col_get_clust_pos_noninline(
+ ufield->orig_len = 0;
+ ufield->field_no = dict_col_get_clust_pos(
&prebuilt->table->cols[i], clust_index);
n_changed++;
}
@@ -4002,20 +4612,20 @@ calc_row_difference(
return(0);
}
-/**************************************************************************
+/**********************************************************************//**
Updates a row given as a parameter to a new value. Note that we are given
whole rows, not just the fields which are updated: this incurs some
overhead for CPU when we check which fields are actually updated.
TODO: currently InnoDB does not prevent the 'Halloween problem':
in a searched update a single row can get updated several times
-if its index columns are updated! */
-
+if its index columns are updated!
+@return error number or 0 */
+UNIV_INTERN
int
ha_innobase::update_row(
/*====================*/
- /* out: error number or 0 */
- const uchar* old_row, /* in: old row in MySQL format */
- uchar* new_row) /* in: new row in MySQL format */
+ const uchar* old_row, /*!< in: old row in MySQL format */
+ uchar* new_row) /*!< in: new row in MySQL format */
{
upd_t* uvect;
int error = 0;
@@ -4046,7 +4656,7 @@ ha_innobase::update_row(
/* This is not a delete */
prebuilt->upd_node->is_delete = FALSE;
- assert(prebuilt->template_type == ROW_MYSQL_WHOLE_ROW);
+ ut_a(prebuilt->template_type == ROW_MYSQL_WHOLE_ROW);
innodb_srv_conc_enter_innodb(trx);
@@ -4094,7 +4704,8 @@ ha_innobase::update_row(
innodb_srv_conc_exit_innodb(trx);
- error = convert_error_code_to_mysql(error, user_thd);
+ error = convert_error_code_to_mysql(error,
+ prebuilt->table->flags, user_thd);
if (error == 0 /* success */
&& uvect->n_fields == 0 /* no columns were updated */) {
@@ -4114,14 +4725,14 @@ ha_innobase::update_row(
DBUG_RETURN(error);
}
-/**************************************************************************
-Deletes a row given as the parameter. */
-
+/**********************************************************************//**
+Deletes a row given as the parameter.
+@return error number or 0 */
+UNIV_INTERN
int
ha_innobase::delete_row(
/*====================*/
- /* out: error number or 0 */
- const uchar* record) /* in: a row in MySQL format */
+ const uchar* record) /*!< in: a row in MySQL format */
{
int error = 0;
trx_t* trx = thd_to_trx(user_thd);
@@ -4146,7 +4757,8 @@ ha_innobase::delete_row(
innodb_srv_conc_exit_innodb(trx);
- error = convert_error_code_to_mysql(error, user_thd);
+ error = convert_error_code_to_mysql(
+ error, prebuilt->table->flags, user_thd);
/* Tell the InnoDB server that there might be work for
utility threads: */
@@ -4156,11 +4768,11 @@ ha_innobase::delete_row(
DBUG_RETURN(error);
}
-/**************************************************************************
+/**********************************************************************//**
Removes a new lock set on a row, if it was not read optimistically. This can
be called after a row has been read in the processing of an UPDATE or a DELETE
query, if the option innodb_locks_unsafe_for_binlog is set. */
-
+UNIV_INTERN
void
ha_innobase::unlock_row(void)
/*=========================*/
@@ -4194,6 +4806,7 @@ ha_innobase::unlock_row(void)
}
/* See handler.h and row0mysql.h for docs on this function. */
+UNIV_INTERN
bool
ha_innobase::was_semi_consistent_read(void)
/*=======================================*/
@@ -4202,6 +4815,7 @@ ha_innobase::was_semi_consistent_read(void)
}
/* See handler.h and row0mysql.h for docs on this function. */
+UNIV_INTERN
void
ha_innobase::try_semi_consistent_read(bool yes)
/*===========================================*/
@@ -4222,27 +4836,25 @@ ha_innobase::try_semi_consistent_read(bool yes)
}
}
-/**********************************************************************
-Initializes a handle to use an index. */
-
+/******************************************************************//**
+Initializes a handle to use an index.
+@return 0 or error number */
+UNIV_INTERN
int
ha_innobase::index_init(
/*====================*/
- /* out: 0 or error number */
- uint keynr, /* in: key (index) number */
- bool sorted) /* in: 1 if result MUST be sorted according to index */
+ uint keynr, /*!< in: key (index) number */
+ bool sorted) /*!< in: 1 if result MUST be sorted according to index */
{
- int error = 0;
DBUG_ENTER("index_init");
- error = change_active_index(keynr);
-
- DBUG_RETURN(error);
+ DBUG_RETURN(change_active_index(keynr));
}
-/**********************************************************************
-Currently does nothing. */
-
+/******************************************************************//**
+Currently does nothing.
+@return 0 */
+UNIV_INTERN
int
ha_innobase::index_end(void)
/*========================*/
@@ -4253,10 +4865,10 @@ ha_innobase::index_end(void)
DBUG_RETURN(error);
}
-/*************************************************************************
+/*********************************************************************//**
Converts a search mode flag understood by MySQL to a flag understood
by InnoDB. */
-inline
+static inline
ulint
convert_search_mode_to_innobase(
/*============================*/
@@ -4358,18 +4970,17 @@ overwrap, we use this test only as a secondary way of determining the
start of a new SQL statement. */
-/**************************************************************************
+/**********************************************************************//**
Positions an index cursor to the index specified in the handle. Fetches the
-row if any. */
-
+row if any.
+@return 0, HA_ERR_KEY_NOT_FOUND, or error number */
+UNIV_INTERN
int
ha_innobase::index_read(
/*====================*/
- /* out: 0, HA_ERR_KEY_NOT_FOUND,
- or error number */
- uchar* buf, /* in/out: buffer for the returned
+ uchar* buf, /*!< in/out: buffer for the returned
row */
- const uchar* key_ptr, /* in: key value; if this is NULL
+ const uchar* key_ptr, /*!< in: key value; if this is NULL
we position the cursor at the
start or end of index; this can
also contain an InnoDB row id, in
@@ -4378,8 +4989,8 @@ ha_innobase::index_read(
also be a prefix of a full key value,
and the last column can be a prefix
of a full column */
- uint key_len,/* in: key value length */
- enum ha_rkey_function find_flag)/* in: search flags from my_base.h */
+ uint key_len,/*!< in: key value length */
+ enum ha_rkey_function find_flag)/*!< in: search flags from my_base.h */
{
ulint mode;
dict_index_t* index;
@@ -4399,20 +5010,21 @@ ha_innobase::index_read(
necessarily prebuilt->index, but can also be the clustered index */
if (prebuilt->sql_stat_start) {
- build_template(prebuilt, user_thd, table,
- ROW_MYSQL_REC_FIELDS);
+ build_template(prebuilt, user_thd, table, ROW_MYSQL_REC_FIELDS);
}
if (key_ptr) {
/* Convert the search key value to InnoDB format into
prebuilt->search_tuple */
- row_sel_convert_mysql_key_to_innobase(prebuilt->search_tuple,
- (byte*) key_val_buff,
- (ulint)upd_and_key_val_buff_len,
- index,
- (byte*) key_ptr,
- (ulint) key_len, prebuilt->trx);
+ row_sel_convert_mysql_key_to_innobase(
+ prebuilt->search_tuple,
+ (byte*) key_val_buff,
+ (ulint)upd_and_key_val_buff_len,
+ index,
+ (byte*) key_ptr,
+ (ulint) key_len,
+ prebuilt->trx);
} else {
/* We position the cursor to the last or the first entry
in the index */
@@ -4425,10 +5037,12 @@ ha_innobase::index_read(
match_mode = 0;
if (find_flag == HA_READ_KEY_EXACT) {
+
match_mode = ROW_SEL_EXACT;
} else if (find_flag == HA_READ_PREFIX
- || find_flag == HA_READ_PREFIX_LAST) {
+ || find_flag == HA_READ_PREFIX_LAST) {
+
match_mode = ROW_SEL_EXACT_PREFIX;
}
@@ -4447,51 +5061,55 @@ ha_innobase::index_read(
ret = DB_UNSUPPORTED;
}
- if (ret == DB_SUCCESS) {
+ switch (ret) {
+ case DB_SUCCESS:
error = 0;
table->status = 0;
-
- } else if (ret == DB_RECORD_NOT_FOUND) {
+ break;
+ case DB_RECORD_NOT_FOUND:
error = HA_ERR_KEY_NOT_FOUND;
table->status = STATUS_NOT_FOUND;
-
- } else if (ret == DB_END_OF_INDEX) {
+ break;
+ case DB_END_OF_INDEX:
error = HA_ERR_KEY_NOT_FOUND;
table->status = STATUS_NOT_FOUND;
- } else {
- error = convert_error_code_to_mysql((int) ret, user_thd);
+ break;
+ default:
+ error = convert_error_code_to_mysql((int) ret,
+ prebuilt->table->flags,
+ user_thd);
table->status = STATUS_NOT_FOUND;
+ break;
}
DBUG_RETURN(error);
}
-/***********************************************************************
+/*******************************************************************//**
The following functions works like index_read, but it find the last
-row with the current key value or prefix. */
-
+row with the current key value or prefix.
+@return 0, HA_ERR_KEY_NOT_FOUND, or an error code */
+UNIV_INTERN
int
ha_innobase::index_read_last(
/*=========================*/
- /* out: 0, HA_ERR_KEY_NOT_FOUND, or an
- error code */
- uchar* buf, /* out: fetched row */
- const uchar* key_ptr,/* in: key value, or a prefix of a full
+ uchar* buf, /*!< out: fetched row */
+ const uchar* key_ptr,/*!< in: key value, or a prefix of a full
key value */
- uint key_len)/* in: length of the key val or prefix
+ uint key_len)/*!< in: length of the key val or prefix
in bytes */
{
return(index_read(buf, key_ptr, key_len, HA_READ_PREFIX_LAST));
}
-/************************************************************************
-Get the index for a handle. Does not change active index.*/
-
+/********************************************************************//**
+Get the index for a handle. Does not change active index.
+@return NULL or index instance. */
+UNIV_INTERN
dict_index_t*
ha_innobase::innobase_get_index(
/*============================*/
- /* out: NULL or index instance. */
- uint keynr) /* in: use this index; MAX_KEY means always
+ uint keynr) /*!< in: use this index; MAX_KEY means always
clustered index, even if it was internally
generated by InnoDB */
{
@@ -4507,10 +5125,10 @@ ha_innobase::innobase_get_index(
if (keynr != MAX_KEY && table->s->keys > 0) {
key = table->key_info + keynr;
- index = dict_table_get_index_noninline(
- prebuilt->table, key->name);
+ index = dict_table_get_index_on_name(prebuilt->table,
+ key->name);
} else {
- index = dict_table_get_first_index_noninline(prebuilt->table);
+ index = dict_table_get_first_index(prebuilt->table);
}
if (!index) {
@@ -4524,14 +5142,14 @@ ha_innobase::innobase_get_index(
DBUG_RETURN(index);
}
-/************************************************************************
-Changes the active index of a handle. */
-
+/********************************************************************//**
+Changes the active index of a handle.
+@return 0 or error code */
+UNIV_INTERN
int
ha_innobase::change_active_index(
/*=============================*/
- /* out: 0 or error code */
- uint keynr) /* in: use this index; MAX_KEY means always clustered
+ uint keynr) /*!< in: use this index; MAX_KEY means always clustered
index, even if it was internally generated by
InnoDB */
{
@@ -4544,11 +5162,24 @@ ha_innobase::change_active_index(
prebuilt->index = innobase_get_index(keynr);
- if (!prebuilt->index) {
+ if (UNIV_UNLIKELY(!prebuilt->index)) {
+ sql_print_warning("InnoDB: change_active_index(%u) failed",
+ keynr);
DBUG_RETURN(1);
}
- assert(prebuilt->search_tuple != 0);
+ prebuilt->index_usable = row_merge_is_index_usable(prebuilt->trx,
+ prebuilt->index);
+
+ if (UNIV_UNLIKELY(!prebuilt->index_usable)) {
+ sql_print_warning("InnoDB: insufficient history for index %u",
+ keynr);
+ /* The caller seems to ignore this. Thus, we must check
+ this again in row_search_for_mysql(). */
+ DBUG_RETURN(2);
+ }
+
+ ut_a(prebuilt->search_tuple != 0);
dtuple_set_n_fields(prebuilt->search_tuple, prebuilt->index->n_fields);
@@ -4566,23 +5197,23 @@ ha_innobase::change_active_index(
DBUG_RETURN(0);
}
-/**************************************************************************
+/**********************************************************************//**
Positions an index cursor to the index specified in keynr. Fetches the
-row if any. */
-/* ??? This is only used to read whole keys ??? */
-
+row if any.
+??? This is only used to read whole keys ???
+@return error number or 0 */
+UNIV_INTERN
int
ha_innobase::index_read_idx(
/*========================*/
- /* out: error number or 0 */
- uchar* buf, /* in/out: buffer for the returned
+ uchar* buf, /*!< in/out: buffer for the returned
row */
- uint keynr, /* in: use this index */
- const uchar* key, /* in: key value; if this is NULL
+ uint keynr, /*!< in: use this index */
+ const uchar* key, /*!< in: key value; if this is NULL
we position the cursor at the
start or end of index */
- uint key_len, /* in: key value length */
- enum ha_rkey_function find_flag)/* in: search flags from my_base.h */
+ uint key_len, /*!< in: key value length */
+ enum ha_rkey_function find_flag)/*!< in: search flags from my_base.h */
{
if (change_active_index(keynr)) {
@@ -4592,19 +5223,18 @@ ha_innobase::index_read_idx(
return(index_read(buf, key, key_len, find_flag));
}
-/***************************************************************************
+/***********************************************************************//**
Reads the next or previous row from a cursor, which must have previously been
-positioned using index_read. */
-
+positioned using index_read.
+@return 0, HA_ERR_END_OF_FILE, or error number */
+UNIV_INTERN
int
ha_innobase::general_fetch(
/*=======================*/
- /* out: 0, HA_ERR_END_OF_FILE, or error
- number */
- uchar* buf, /* in/out: buffer for next row in MySQL
+ uchar* buf, /*!< in/out: buffer for next row in MySQL
format */
- uint direction, /* in: ROW_SEL_NEXT or ROW_SEL_PREV */
- uint match_mode) /* in: 0, ROW_SEL_EXACT, or
+ uint direction, /*!< in: ROW_SEL_NEXT or ROW_SEL_PREV */
+ uint match_mode) /*!< in: 0, ROW_SEL_EXACT, or
ROW_SEL_EXACT_PREFIX */
{
ulint ret;
@@ -4616,39 +5246,43 @@ ha_innobase::general_fetch(
innodb_srv_conc_enter_innodb(prebuilt->trx);
- ret = row_search_for_mysql((byte*)buf, 0, prebuilt, match_mode,
- direction);
+ ret = row_search_for_mysql(
+ (byte*)buf, 0, prebuilt, match_mode, direction);
+
innodb_srv_conc_exit_innodb(prebuilt->trx);
- if (ret == DB_SUCCESS) {
+ switch (ret) {
+ case DB_SUCCESS:
error = 0;
table->status = 0;
-
- } else if (ret == DB_RECORD_NOT_FOUND) {
+ break;
+ case DB_RECORD_NOT_FOUND:
error = HA_ERR_END_OF_FILE;
table->status = STATUS_NOT_FOUND;
-
- } else if (ret == DB_END_OF_INDEX) {
+ break;
+ case DB_END_OF_INDEX:
error = HA_ERR_END_OF_FILE;
table->status = STATUS_NOT_FOUND;
- } else {
- error = convert_error_code_to_mysql((int) ret, user_thd);
+ break;
+ default:
+ error = convert_error_code_to_mysql(
+ (int) ret, prebuilt->table->flags, user_thd);
table->status = STATUS_NOT_FOUND;
+ break;
}
DBUG_RETURN(error);
}
-/***************************************************************************
+/***********************************************************************//**
Reads the next row from a cursor, which must have previously been
-positioned using index_read. */
-
+positioned using index_read.
+@return 0, HA_ERR_END_OF_FILE, or error number */
+UNIV_INTERN
int
ha_innobase::index_next(
/*====================*/
- /* out: 0, HA_ERR_END_OF_FILE, or error
- number */
- uchar* buf) /* in/out: buffer for next row in MySQL
+ uchar* buf) /*!< in/out: buffer for next row in MySQL
format */
{
ha_statistic_increment(&SSV::ha_read_next_count);
@@ -4656,47 +5290,46 @@ ha_innobase::index_next(
return(general_fetch(buf, ROW_SEL_NEXT, 0));
}
-/***********************************************************************
-Reads the next row matching to the key value given as the parameter. */
-
+/*******************************************************************//**
+Reads the next row matching to the key value given as the parameter.
+@return 0, HA_ERR_END_OF_FILE, or error number */
+UNIV_INTERN
int
ha_innobase::index_next_same(
/*=========================*/
- /* out: 0, HA_ERR_END_OF_FILE, or error
- number */
- uchar* buf, /* in/out: buffer for the row */
- const uchar* key, /* in: key value */
- uint keylen) /* in: key value length */
+ uchar* buf, /*!< in/out: buffer for the row */
+ const uchar* key, /*!< in: key value */
+ uint keylen) /*!< in: key value length */
{
ha_statistic_increment(&SSV::ha_read_next_count);
return(general_fetch(buf, ROW_SEL_NEXT, last_match_mode));
}
-/***************************************************************************
+/***********************************************************************//**
Reads the previous row from a cursor, which must have previously been
-positioned using index_read. */
-
+positioned using index_read.
+@return 0, HA_ERR_END_OF_FILE, or error number */
+UNIV_INTERN
int
ha_innobase::index_prev(
/*====================*/
- /* out: 0, HA_ERR_END_OF_FILE, or error number */
- uchar* buf) /* in/out: buffer for previous row in MySQL format */
+ uchar* buf) /*!< in/out: buffer for previous row in MySQL format */
{
ha_statistic_increment(&SSV::ha_read_prev_count);
return(general_fetch(buf, ROW_SEL_PREV, 0));
}
-/************************************************************************
+/********************************************************************//**
Positions a cursor on the first record in an index and reads the
-corresponding row to buf. */
-
+corresponding row to buf.
+@return 0, HA_ERR_END_OF_FILE, or error code */
+UNIV_INTERN
int
ha_innobase::index_first(
/*=====================*/
- /* out: 0, HA_ERR_END_OF_FILE, or error code */
- uchar* buf) /* in/out: buffer for the row */
+ uchar* buf) /*!< in/out: buffer for the row */
{
int error;
@@ -4714,15 +5347,15 @@ ha_innobase::index_first(
DBUG_RETURN(error);
}
-/************************************************************************
+/********************************************************************//**
Positions a cursor on the last record in an index and reads the
-corresponding row to buf. */
-
+corresponding row to buf.
+@return 0, HA_ERR_END_OF_FILE, or error code */
+UNIV_INTERN
int
ha_innobase::index_last(
/*====================*/
- /* out: 0, HA_ERR_END_OF_FILE, or error code */
- uchar* buf) /* in/out: buffer for the row */
+ uchar* buf) /*!< in/out: buffer for the row */
{
int error;
@@ -4740,14 +5373,14 @@ ha_innobase::index_last(
DBUG_RETURN(error);
}
-/********************************************************************
-Initialize a table scan. */
-
+/****************************************************************//**
+Initialize a table scan.
+@return 0 or error number */
+UNIV_INTERN
int
ha_innobase::rnd_init(
/*==================*/
- /* out: 0 or error number */
- bool scan) /* in: ???????? */
+ bool scan) /*!< in: TRUE if table/index scan FALSE otherwise */
{
int err;
@@ -4772,26 +5405,26 @@ ha_innobase::rnd_init(
return(err);
}
-/*********************************************************************
-Ends a table scan. */
-
+/*****************************************************************//**
+Ends a table scan.
+@return 0 or error number */
+UNIV_INTERN
int
ha_innobase::rnd_end(void)
/*======================*/
- /* out: 0 or error number */
{
return(index_end());
}
-/*********************************************************************
+/*****************************************************************//**
Reads the next row in a table scan (also used to read the FIRST row
-in a table scan). */
-
+in a table scan).
+@return 0, HA_ERR_END_OF_FILE, or error number */
+UNIV_INTERN
int
ha_innobase::rnd_next(
/*==================*/
- /* out: 0, HA_ERR_END_OF_FILE, or error number */
- uchar* buf) /* in/out: returns the row in this buffer,
+ uchar* buf) /*!< in/out: returns the row in this buffer,
in MySQL format */
{
int error;
@@ -4801,9 +5434,11 @@ ha_innobase::rnd_next(
if (start_of_scan) {
error = index_first(buf);
+
if (error == HA_ERR_KEY_NOT_FOUND) {
error = HA_ERR_END_OF_FILE;
}
+
start_of_scan = 0;
} else {
error = general_fetch(buf, ROW_SEL_NEXT, 0);
@@ -4812,15 +5447,15 @@ ha_innobase::rnd_next(
DBUG_RETURN(error);
}
-/**************************************************************************
-Fetches a row from the table based on a row reference. */
-
+/**********************************************************************//**
+Fetches a row from the table based on a row reference.
+@return 0, HA_ERR_KEY_NOT_FOUND, or error code */
+UNIV_INTERN
int
ha_innobase::rnd_pos(
/*=================*/
- /* out: 0, HA_ERR_KEY_NOT_FOUND, or error code */
- uchar* buf, /* in/out: buffer for the row */
- uchar* pos) /* in: primary key value of the row in the
+ uchar* buf, /*!< in/out: buffer for the row */
+ uchar* pos) /*!< in: primary key value of the row in the
MySQL format, or the row id if the clustered
index was internally generated by InnoDB; the
length of data in pos has to be ref_length */
@@ -4864,7 +5499,7 @@ ha_innobase::rnd_pos(
DBUG_RETURN(error);
}
-/*************************************************************************
+/*********************************************************************//**
Stores a reference to the current row to 'ref' field of the handle. Note
that in the case where we have generated the clustered index for the
table, the function parameter is illogical: we MUST ASSUME that 'record'
@@ -4872,11 +5507,11 @@ is the current 'position' of the handle, because if row ref is actually
the row id internally generated in InnoDB, then 'record' does not contain
it. We just guess that the row id must be for the record where the handle
was positioned the last time. */
-
+UNIV_INTERN
void
ha_innobase::position(
/*==================*/
- const uchar* record) /* in: row in MySQL format */
+ const uchar* record) /*!< in: row in MySQL format */
{
uint len;
@@ -4905,41 +5540,23 @@ ha_innobase::position(
}
}
-/*********************************************************************
-If it's a DB_TOO_BIG_RECORD error then set a suitable message to
-return to the client.*/
-inline
-void
-innodb_check_for_record_too_big_error(
-/*==================================*/
- ulint comp, /* in: ROW_FORMAT: nonzero=COMPACT, 0=REDUNDANT */
- int error) /* in: error code to check */
-{
- if (error == (int)DB_TOO_BIG_RECORD) {
- ulint max_row_size
- = page_get_free_space_of_empty_noninline(comp) / 2;
-
- my_error(ER_TOO_BIG_ROWSIZE, MYF(0), max_row_size);
- }
-}
-
/* limit innodb monitor access to users with PROCESS privilege.
See http://bugs.mysql.com/32710 for expl. why we choose PROCESS. */
#define IS_MAGIC_TABLE_AND_USER_DENIED_ACCESS(table_name, thd) \
(row_is_magic_monitor_table(table_name) \
&& check_global_access(thd, PROCESS_ACL))
-/*********************************************************************
+/*****************************************************************//**
Creates a table definition to an InnoDB database. */
static
int
create_table_def(
/*=============*/
- trx_t* trx, /* in: InnoDB transaction handle */
- TABLE* form, /* in: information on table
+ trx_t* trx, /*!< in: InnoDB transaction handle */
+ TABLE* form, /*!< in: information on table
columns and indexes */
- const char* table_name, /* in: table name */
- const char* path_of_temp_table,/* in: if this is a table explicitly
+ const char* table_name, /*!< in: table name */
+ const char* path_of_temp_table,/*!< in: if this is a table explicitly
created by the user with the
TEMPORARY keyword, then this
parameter is the dir path where the
@@ -4947,7 +5564,7 @@ create_table_def(
an .ibd file for it (no .ibd extension
in the path, though); otherwise this
is NULL */
- ulint flags) /* in: table flags */
+ ulint flags) /*!< in: table flags */
{
Field* field;
dict_table_t* table;
@@ -5006,9 +5623,19 @@ create_table_def(
charset_no = (ulint)field->charset()->number;
- ut_a(charset_no < 256); /* in data0type.h we assume
- that the number fits in one
- byte */
+ if (UNIV_UNLIKELY(charset_no >= 256)) {
+ /* in data0type.h we assume that the
+ number fits in one byte in prtype */
+ push_warning_printf(
+ (THD*) trx->mysql_thd,
+ MYSQL_ERROR::WARN_LEVEL_ERROR,
+ ER_CANT_CREATE_TABLE,
+ "In InnoDB, charset-collation codes"
+ " must be below 256."
+ " Unsupported code %lu.",
+ (ulong) charset_no);
+ DBUG_RETURN(ER_CANT_CREATE_TABLE);
+ }
}
ut_a(field->type() < 256); /* we assume in dtype_form_prtype()
@@ -5043,24 +5670,23 @@ create_table_def(
error = row_create_table_for_mysql(table, trx);
- innodb_check_for_record_too_big_error(flags & DICT_TF_COMPACT, error);
-
- error = convert_error_code_to_mysql(error, NULL);
+ error = convert_error_code_to_mysql(error, flags, NULL);
DBUG_RETURN(error);
}
-/*********************************************************************
+/*****************************************************************//**
Creates an index in an InnoDB database. */
static
int
create_index(
/*=========*/
- trx_t* trx, /* in: InnoDB transaction handle */
- TABLE* form, /* in: information on table
+ trx_t* trx, /*!< in: InnoDB transaction handle */
+ TABLE* form, /*!< in: information on table
columns and indexes */
- const char* table_name, /* in: table name */
- uint key_num) /* in: index number */
+ ulint flags, /*!< in: InnoDB table flags */
+ const char* table_name, /*!< in: table name */
+ uint key_num) /*!< in: index number */
{
Field* field;
dict_index_t* index;
@@ -5095,8 +5721,8 @@ create_index(
/* We pass 0 as the space id, and determine at a lower level the space
id where to store the table */
- index = dict_mem_index_create((char*) table_name, key->name, 0,
- ind_type, n_fields);
+ index = dict_mem_index_create(table_name, key->name, 0,
+ ind_type, n_fields);
field_lengths = (ulint*) my_malloc(sizeof(ulint) * n_fields,
MYF(MY_FAE));
@@ -5167,27 +5793,23 @@ create_index(
sure we don't create too long indexes. */
error = row_create_index_for_mysql(index, trx, field_lengths);
- innodb_check_for_record_too_big_error(form->s->row_type
- != ROW_TYPE_REDUNDANT, error);
-
- error = convert_error_code_to_mysql(error, NULL);
+ error = convert_error_code_to_mysql(error, flags, NULL);
my_free(field_lengths, MYF(0));
DBUG_RETURN(error);
}
-/*********************************************************************
+/*****************************************************************//**
Creates an index to an InnoDB table when the user has defined no
primary index. */
static
int
create_clustered_index_when_no_primary(
/*===================================*/
- trx_t* trx, /* in: InnoDB transaction handle */
- ulint comp, /* in: ROW_FORMAT:
- nonzero=COMPACT, 0=REDUNDANT */
- const char* table_name) /* in: table name */
+ trx_t* trx, /*!< in: InnoDB transaction handle */
+ ulint flags, /*!< in: InnoDB table flags */
+ const char* table_name) /*!< in: table name */
{
dict_index_t* index;
int error;
@@ -5197,22 +5819,187 @@ create_clustered_index_when_no_primary(
index = dict_mem_index_create(table_name, "GEN_CLUST_INDEX",
0, DICT_CLUSTERED, 0);
+
error = row_create_index_for_mysql(index, trx, NULL);
- innodb_check_for_record_too_big_error(comp, error);
-
- error = convert_error_code_to_mysql(error, NULL);
+ error = convert_error_code_to_mysql(error, flags, NULL);
return(error);
}
-/*********************************************************************
-Update create_info. Used in SHOW CREATE TABLE et al. */
+/*****************************************************************//**
+Validates the create options. We may build on this function
+in future. For now, it checks two specifiers:
+KEY_BLOCK_SIZE and ROW_FORMAT
+If innodb_strict_mode is not set then this function is a no-op
+@return TRUE if valid. */
+static
+ibool
+create_options_are_valid(
+/*=====================*/
+ THD* thd, /*!< in: connection thread. */
+ TABLE* form, /*!< in: information on table
+ columns and indexes */
+ HA_CREATE_INFO* create_info) /*!< in: create info. */
+{
+ ibool kbs_specified = FALSE;
+ ibool ret = TRUE;
+
+ ut_ad(thd != NULL);
+
+ /* If innodb_strict_mode is not set don't do any validation. */
+ if (!(THDVAR(thd, strict_mode))) {
+ return(TRUE);
+ }
+
+ ut_ad(form != NULL);
+ ut_ad(create_info != NULL);
+
+ /* First check if KEY_BLOCK_SIZE was specified. */
+ if (create_info->key_block_size
+ || (create_info->used_fields & HA_CREATE_USED_KEY_BLOCK_SIZE)) {
+
+ kbs_specified = TRUE;
+ switch (create_info->key_block_size) {
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ case 16:
+ /* Valid value. */
+ break;
+ default:
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
+ ER_ILLEGAL_HA_CREATE_OPTION,
+ "InnoDB: invalid"
+ " KEY_BLOCK_SIZE = %lu."
+ " Valid values are"
+ " [1, 2, 4, 8, 16]",
+ create_info->key_block_size);
+ ret = FALSE;
+ }
+ }
+
+ /* If KEY_BLOCK_SIZE was specified, check for its
+ dependencies. */
+ if (kbs_specified && !srv_file_per_table) {
+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
+ 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_ERROR,
+ ER_ILLEGAL_HA_CREATE_OPTION,
+ "InnoDB: KEY_BLOCK_SIZE"
+ " requires innodb_file_format >"
+ " Antelope.");
+ ret = FALSE;
+ }
+
+ /* Now check for ROW_FORMAT specifier. */
+ if (create_info->used_fields & HA_CREATE_USED_ROW_FORMAT) {
+ switch (form->s->row_type) {
+ const char* row_format_name;
+ case ROW_TYPE_COMPRESSED:
+ case ROW_TYPE_DYNAMIC:
+ row_format_name
+ = form->s->row_type == ROW_TYPE_COMPRESSED
+ ? "COMPRESSED"
+ : "DYNAMIC";
+
+ /* These two ROW_FORMATs require
+ srv_file_per_table and srv_file_format */
+ if (!srv_file_per_table) {
+ push_warning_printf(
+ thd,
+ MYSQL_ERROR::WARN_LEVEL_ERROR,
+ ER_ILLEGAL_HA_CREATE_OPTION,
+ "InnoDB: ROW_FORMAT=%s"
+ " requires innodb_file_per_table.",
+ row_format_name);
+ ret = FALSE;
+
+ }
+
+ if (srv_file_format < DICT_TF_FORMAT_ZIP) {
+ push_warning_printf(
+ thd,
+ MYSQL_ERROR::WARN_LEVEL_ERROR,
+ ER_ILLEGAL_HA_CREATE_OPTION,
+ "InnoDB: ROW_FORMAT=%s"
+ " requires innodb_file_format >"
+ " Antelope.",
+ row_format_name);
+ ret = FALSE;
+ }
+
+ /* Cannot specify KEY_BLOCK_SIZE with
+ ROW_FORMAT = DYNAMIC.
+ However, we do allow COMPRESSED to be
+ specified with KEY_BLOCK_SIZE. */
+ if (kbs_specified
+ && form->s->row_type == ROW_TYPE_DYNAMIC) {
+ push_warning_printf(
+ thd,
+ MYSQL_ERROR::WARN_LEVEL_ERROR,
+ ER_ILLEGAL_HA_CREATE_OPTION,
+ "InnoDB: cannot specify"
+ " ROW_FORMAT = DYNAMIC with"
+ " KEY_BLOCK_SIZE.");
+ ret = FALSE;
+ }
+
+ break;
+
+ case ROW_TYPE_REDUNDANT:
+ case ROW_TYPE_COMPACT:
+ case ROW_TYPE_DEFAULT:
+ /* Default is COMPACT. */
+ row_format_name
+ = form->s->row_type == ROW_TYPE_REDUNDANT
+ ? "REDUNDANT"
+ : "COMPACT";
+
+ /* Cannot specify KEY_BLOCK_SIZE with these
+ format specifiers. */
+ if (kbs_specified) {
+ push_warning_printf(
+ thd,
+ MYSQL_ERROR::WARN_LEVEL_ERROR,
+ ER_ILLEGAL_HA_CREATE_OPTION,
+ "InnoDB: cannot specify"
+ " ROW_FORMAT = %s with"
+ " KEY_BLOCK_SIZE.",
+ row_format_name);
+ ret = FALSE;
+ }
+
+ break;
+
+ default:
+ push_warning(thd,
+ MYSQL_ERROR::WARN_LEVEL_ERROR,
+ ER_ILLEGAL_HA_CREATE_OPTION,
+ "InnoDB: invalid ROW_FORMAT specifier.");
+ ret = FALSE;
+
+ }
+ }
+
+ return(ret);
+}
+
+/*****************************************************************//**
+Update create_info. Used in SHOW CREATE TABLE et al. */
+UNIV_INTERN
void
ha_innobase::update_create_info(
/*============================*/
- HA_CREATE_INFO* create_info) /* in/out: create info */
+ HA_CREATE_INFO* create_info) /*!< in/out: create info */
{
if (!(create_info->used_fields & HA_CREATE_USED_AUTO)) {
ha_innobase::info(HA_STATUS_AUTO);
@@ -5220,17 +6007,17 @@ ha_innobase::update_create_info(
}
}
-/*********************************************************************
-Creates a new table to an InnoDB database. */
-
+/*****************************************************************//**
+Creates a new table to an InnoDB database.
+@return error number */
+UNIV_INTERN
int
ha_innobase::create(
/*================*/
- /* out: error number */
- const char* name, /* in: table name */
- TABLE* form, /* in: information on table
+ const char* name, /*!< in: table name */
+ TABLE* form, /*!< in: information on table
columns and indexes */
- HA_CREATE_INFO* create_info) /* in: more information of the
+ HA_CREATE_INFO* create_info) /*!< in: more information of the
created table, contains also the
create statement string */
{
@@ -5243,8 +6030,11 @@ ha_innobase::create(
char name2[FN_REFLEN];
char norm_name[FN_REFLEN];
THD* thd = ha_thd();
- ib_longlong auto_inc_value;
+ ib_int64_t auto_inc_value;
ulint flags;
+ /* Cache the value of innodb_file_format, in case it is
+ modified by another thread while the table is being created. */
+ const ulint file_format = srv_file_format;
DBUG_ENTER("ha_innobase::create");
@@ -5290,18 +6080,7 @@ ha_innobase::create(
trx_search_latch_release_if_reserved(parent_trx);
- trx = trx_allocate_for_mysql();
-
- trx->mysql_thd = thd;
- trx->mysql_query_str = thd_query(thd);
-
- if (thd_test_options(thd, OPTION_NO_FOREIGN_KEY_CHECKS)) {
- trx->check_foreigns = FALSE;
- }
-
- if (thd_test_options(thd, OPTION_RELAXED_UNIQUE_CHECKS)) {
- trx->check_unique_secondary = FALSE;
- }
+ trx = innobase_trx_allocate(thd);
if (lower_case_table_names) {
srv_lower_case_table_names = TRUE;
@@ -5323,8 +6102,145 @@ ha_innobase::create(
flags = 0;
- if (form->s->row_type != ROW_TYPE_REDUNDANT) {
- flags |= DICT_TF_COMPACT;
+ /* Validate create options if innodb_strict_mode is set. */
+ if (!create_options_are_valid(thd, form, create_info)) {
+ error = ER_ILLEGAL_HA_CREATE_OPTION;
+ goto cleanup;
+ }
+
+ if (create_info->key_block_size
+ || (create_info->used_fields & HA_CREATE_USED_KEY_BLOCK_SIZE)) {
+ /* Determine the page_zip.ssize corresponding to the
+ requested page size (key_block_size) in kilobytes. */
+
+ ulint ssize, ksize;
+ ulint key_block_size = create_info->key_block_size;
+
+ for (ssize = ksize = 1; ssize <= DICT_TF_ZSSIZE_MAX;
+ ssize++, ksize <<= 1) {
+ if (key_block_size == ksize) {
+ flags = ssize << DICT_TF_ZSSIZE_SHIFT
+ | DICT_TF_COMPACT
+ | DICT_TF_FORMAT_ZIP
+ << DICT_TF_FORMAT_SHIFT;
+ break;
+ }
+ }
+
+ 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.");
+ flags = 0;
+ }
+
+ if (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.");
+ flags = 0;
+ }
+
+ if (!flags) {
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_ILLEGAL_HA_CREATE_OPTION,
+ "InnoDB: ignoring"
+ " KEY_BLOCK_SIZE=%lu.",
+ create_info->key_block_size);
+ }
+ }
+
+ if (create_info->used_fields & HA_CREATE_USED_ROW_FORMAT) {
+ if (flags) {
+ /* KEY_BLOCK_SIZE was specified. */
+ if (form->s->row_type != ROW_TYPE_COMPRESSED) {
+ /* ROW_FORMAT other than COMPRESSED
+ ignores KEY_BLOCK_SIZE. It does not
+ make sense to reject conflicting
+ KEY_BLOCK_SIZE and ROW_FORMAT, because
+ such combinations can be obtained
+ with ALTER TABLE anyway. */
+ push_warning_printf(
+ thd,
+ MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_ILLEGAL_HA_CREATE_OPTION,
+ "InnoDB: ignoring KEY_BLOCK_SIZE=%lu"
+ " unless ROW_FORMAT=COMPRESSED.",
+ create_info->key_block_size);
+ flags = 0;
+ }
+ } else {
+ /* No KEY_BLOCK_SIZE */
+ if (form->s->row_type == ROW_TYPE_COMPRESSED) {
+ /* ROW_FORMAT=COMPRESSED without
+ KEY_BLOCK_SIZE implies half the
+ maximum KEY_BLOCK_SIZE. */
+ flags = (DICT_TF_ZSSIZE_MAX - 1)
+ << DICT_TF_ZSSIZE_SHIFT
+ | DICT_TF_COMPACT
+ | DICT_TF_FORMAT_ZIP
+ << DICT_TF_FORMAT_SHIFT;
+#if DICT_TF_ZSSIZE_MAX < 1
+# error "DICT_TF_ZSSIZE_MAX < 1"
+#endif
+ }
+ }
+
+ switch (form->s->row_type) {
+ const char* row_format_name;
+ case ROW_TYPE_REDUNDANT:
+ break;
+ case ROW_TYPE_COMPRESSED:
+ case ROW_TYPE_DYNAMIC:
+ row_format_name
+ = form->s->row_type == ROW_TYPE_COMPRESSED
+ ? "COMPRESSED"
+ : "DYNAMIC";
+
+ 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.",
+ row_format_name);
+ } 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.",
+ row_format_name);
+ } else {
+ flags |= DICT_TF_COMPACT
+ | (DICT_TF_FORMAT_ZIP
+ << DICT_TF_FORMAT_SHIFT);
+ break;
+ }
+
+ /* fall through */
+ case ROW_TYPE_NOT_USED:
+ case ROW_TYPE_FIXED:
+ default:
+ push_warning(thd,
+ MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_ILLEGAL_HA_CREATE_OPTION,
+ "InnoDB: assuming ROW_FORMAT=COMPACT.");
+ case ROW_TYPE_DEFAULT:
+ case ROW_TYPE_COMPACT:
+ flags = DICT_TF_COMPACT;
+ break;
+ }
+ } else if (!flags) {
+ /* No KEY_BLOCK_SIZE or ROW_FORMAT specified:
+ use ROW_FORMAT=COMPACT by default. */
+ flags = DICT_TF_COMPACT;
}
error = create_table_def(trx, form, norm_name,
@@ -5344,7 +6260,7 @@ ha_innobase::create(
/* Our function row_get_mysql_key_number_for_index assumes
the primary key is always number 0, if it exists */
- DBUG_ASSERT(primary_key_no == -1 || primary_key_no == 0);
+ ut_a(primary_key_no == -1 || primary_key_no == 0);
/* Create the keys */
@@ -5354,8 +6270,7 @@ ha_innobase::create(
by InnoDB */
error = create_clustered_index_when_no_primary(
- trx, form->s->row_type != ROW_TYPE_REDUNDANT,
- norm_name);
+ trx, flags, norm_name);
if (error) {
goto cleanup;
}
@@ -5364,7 +6279,7 @@ ha_innobase::create(
if (primary_key_no != -1) {
/* In InnoDB the clustered index must always be created
first */
- if ((error = create_index(trx, form, norm_name,
+ if ((error = create_index(trx, form, flags, norm_name,
(uint) primary_key_no))) {
goto cleanup;
}
@@ -5374,7 +6289,8 @@ ha_innobase::create(
if (i != (uint) primary_key_no) {
- if ((error = create_index(trx, form, norm_name, i))) {
+ if ((error = create_index(trx, form, flags, norm_name,
+ i))) {
goto cleanup;
}
}
@@ -5385,7 +6301,7 @@ ha_innobase::create(
*trx->mysql_query_str, norm_name,
create_info->options & HA_LEX_CREATE_TMP_TABLE);
- error = convert_error_code_to_mysql(error, NULL);
+ error = convert_error_code_to_mysql(error, flags, NULL);
if (error) {
goto cleanup;
@@ -5406,6 +6322,15 @@ ha_innobase::create(
DBUG_ASSERT(innobase_table != 0);
+ if (innobase_table) {
+ /* We update the highest file format in the system table
+ space, if this table has higher file format setting. */
+
+ trx_sys_file_format_max_upgrade(
+ (const char**) &innobase_file_format_check,
+ dict_table_get_format(innobase_table));
+ }
+
/* Note: We can't call update_thd() as prebuilt will not be
setup at this stage and so we use thd. */
@@ -5449,14 +6374,14 @@ cleanup:
DBUG_RETURN(error);
}
-/*********************************************************************
-Discards or imports an InnoDB tablespace. */
-
+/*****************************************************************//**
+Discards or imports an InnoDB tablespace.
+@return 0 == success, -1 == error */
+UNIV_INTERN
int
ha_innobase::discard_or_import_tablespace(
/*======================================*/
- /* out: 0 == success, -1 == error */
- my_bool discard) /* in: TRUE if discard, else import */
+ my_bool discard) /*!< in: TRUE if discard, else import */
{
dict_table_t* dict_table;
trx_t* trx;
@@ -5477,18 +6402,18 @@ ha_innobase::discard_or_import_tablespace(
err = row_import_tablespace_for_mysql(dict_table->name, trx);
}
- err = convert_error_code_to_mysql(err, NULL);
+ err = convert_error_code_to_mysql(err, dict_table->flags, NULL);
DBUG_RETURN(err);
}
-/*********************************************************************
-Deletes all rows of an InnoDB table. */
-
+/*****************************************************************//**
+Deletes all rows of an InnoDB table.
+@return error number */
+UNIV_INTERN
int
ha_innobase::delete_all_rows(void)
/*==============================*/
- /* out: error number */
{
int error;
@@ -5515,23 +6440,24 @@ ha_innobase::delete_all_rows(void)
goto fallback;
}
- error = convert_error_code_to_mysql(error, NULL);
+ error = convert_error_code_to_mysql(error, prebuilt->table->flags,
+ NULL);
DBUG_RETURN(error);
}
-/*********************************************************************
+/*****************************************************************//**
Drops a table from an InnoDB database. Before calling this function,
MySQL calls innobase_commit to commit the transaction of the current user.
Then the current user cannot have locks set on the table. Drop table
operation inside InnoDB will remove all locks any user has on the table
-inside InnoDB. */
-
+inside InnoDB.
+@return error number */
+UNIV_INTERN
int
ha_innobase::delete_table(
/*======================*/
- /* out: error number */
- const char* name) /* in: table name */
+ const char* name) /*!< in: table name */
{
ulint name_len;
int error;
@@ -5560,28 +6486,17 @@ ha_innobase::delete_table(
trx_search_latch_release_if_reserved(parent_trx);
+ trx = innobase_trx_allocate(thd);
+
if (lower_case_table_names) {
srv_lower_case_table_names = TRUE;
} else {
srv_lower_case_table_names = FALSE;
}
- trx = trx_allocate_for_mysql();
-
- trx->mysql_thd = thd;
- trx->mysql_query_str = thd_query(thd);
-
- if (thd_test_options(thd, OPTION_NO_FOREIGN_KEY_CHECKS)) {
- trx->check_foreigns = FALSE;
- }
-
- if (thd_test_options(thd, OPTION_RELAXED_UNIQUE_CHECKS)) {
- trx->check_unique_secondary = FALSE;
- }
-
name_len = strlen(name);
- assert(name_len < 1000);
+ ut_a(name_len < 1000);
/* Drop the table in InnoDB */
@@ -5604,26 +6519,24 @@ ha_innobase::delete_table(
trx_free_for_mysql(trx);
- error = convert_error_code_to_mysql(error, NULL);
+ error = convert_error_code_to_mysql(error, 0, NULL);
DBUG_RETURN(error);
}
-/*********************************************************************
+/*****************************************************************//**
Removes all tables in the named database inside InnoDB. */
static
void
innobase_drop_database(
/*===================*/
- /* out: error number */
- handlerton *hton, /* in: handlerton of Innodb */
- char* path) /* in: database path; inside InnoDB the name
+ handlerton *hton, /*!< in: handlerton of Innodb */
+ char* path) /*!< in: database path; inside InnoDB the name
of the last directory in the path is used as
the database name: for example, in 'mysql/data/test'
the database name is 'test' */
{
ulint len = 0;
- trx_t* parent_trx;
trx_t* trx;
char* ptr;
int error;
@@ -5633,12 +6546,18 @@ innobase_drop_database(
/* Get the transaction associated with the current thd, or create one
if not yet created */
- parent_trx = check_trx_exists(thd);
+ DBUG_ASSERT(hton == innodb_hton_ptr);
- /* In case MySQL calls this in the middle of a SELECT query, release
- possible adaptive hash latch to avoid deadlocks of threads */
+ /* In the Windows plugin, thd = current_thd is always NULL */
+ if (thd) {
+ trx_t* parent_trx = check_trx_exists(thd);
- trx_search_latch_release_if_reserved(parent_trx);
+ /* In case MySQL calls this in the middle of a SELECT
+ query, release possible adaptive hash latch to avoid
+ deadlocks of threads */
+
+ trx_search_latch_release_if_reserved(parent_trx);
+ }
ptr = strend(path) - 2;
@@ -5656,14 +6575,14 @@ innobase_drop_database(
#ifdef __WIN__
innobase_casedn_str(namebuf);
#endif
+#if defined __WIN__ && !defined MYSQL_SERVER
+ /* In the Windows plugin, thd = current_thd is always NULL */
trx = trx_allocate_for_mysql();
- trx->mysql_thd = thd;
- trx->mysql_query_str = thd_query(thd);
-
- if (thd_test_options(thd, OPTION_NO_FOREIGN_KEY_CHECKS)) {
- trx->check_foreigns = FALSE;
- }
-
+ trx->mysql_thd = NULL;
+ trx->mysql_query_str = NULL;
+#else
+ trx = innobase_trx_allocate(thd);
+#endif
error = row_drop_database_for_mysql(namebuf, trx);
my_free(namebuf, MYF(0));
@@ -5680,32 +6599,85 @@ innobase_drop_database(
innobase_commit_low(trx);
trx_free_for_mysql(trx);
-#ifdef NO_LONGER_INTERESTED_IN_DROP_DB_ERROR
- error = convert_error_code_to_mysql(error, NULL);
-
- return(error);
-#else
- return;
-#endif
}
+/*********************************************************************//**
+Renames an InnoDB table.
+@return 0 or error code */
+static
+int
+innobase_rename_table(
+/*==================*/
+ trx_t* trx, /*!< in: transaction */
+ const char* from, /*!< in: old name of the table */
+ const char* to, /*!< in: new name of the table */
+ ibool lock_and_commit)
+ /*!< in: TRUE=lock data dictionary and commit */
+{
+ int error;
+ char* norm_to;
+ char* norm_from;
-/*************************************************************************
-Renames an InnoDB table. */
+ if (lower_case_table_names) {
+ srv_lower_case_table_names = TRUE;
+ } else {
+ srv_lower_case_table_names = FALSE;
+ }
+ // Magic number 64 arbitrary
+ norm_to = (char*) my_malloc(strlen(to) + 64, MYF(0));
+ norm_from = (char*) my_malloc(strlen(from) + 64, MYF(0));
+
+ normalize_table_name(norm_to, to);
+ normalize_table_name(norm_from, from);
+
+ /* Serialize data dictionary operations with dictionary mutex:
+ no deadlocks can occur then in these operations */
+
+ if (lock_and_commit) {
+ row_mysql_lock_data_dictionary(trx);
+ }
+
+ error = row_rename_table_for_mysql(
+ norm_from, norm_to, trx, lock_and_commit);
+
+ if (error != DB_SUCCESS) {
+ FILE* ef = dict_foreign_err_file;
+
+ fputs("InnoDB: Renaming table ", ef);
+ ut_print_name(ef, trx, TRUE, norm_from);
+ fputs(" to ", ef);
+ ut_print_name(ef, trx, TRUE, norm_to);
+ fputs(" failed!\n", ef);
+ }
+
+ if (lock_and_commit) {
+ row_mysql_unlock_data_dictionary(trx);
+
+ /* Flush the log to reduce probability that the .frm
+ files and the InnoDB data dictionary get out-of-sync
+ if the user runs with innodb_flush_log_at_trx_commit = 0 */
+
+ log_buffer_flush_to_disk();
+ }
+
+ my_free(norm_to, MYF(0));
+ my_free(norm_from, MYF(0));
+
+ return error;
+}
+/*********************************************************************//**
+Renames an InnoDB table.
+@return 0 or error code */
+UNIV_INTERN
int
ha_innobase::rename_table(
/*======================*/
- /* out: 0 or error code */
- const char* from, /* in: old name of the table */
- const char* to) /* in: new name of the table */
+ const char* from, /*!< in: old name of the table */
+ const char* to) /*!< in: new name of the table */
{
- ulint name_len1;
- ulint name_len2;
+ trx_t* trx;
int error;
trx_t* parent_trx;
- trx_t* trx;
- char norm_from[1000];
- char norm_to[1000];
THD* thd = ha_thd();
DBUG_ENTER("ha_innobase::rename_table");
@@ -5720,38 +6692,9 @@ ha_innobase::rename_table(
trx_search_latch_release_if_reserved(parent_trx);
- if (lower_case_table_names) {
- srv_lower_case_table_names = TRUE;
- } else {
- srv_lower_case_table_names = FALSE;
- }
+ trx = innobase_trx_allocate(thd);
- trx = trx_allocate_for_mysql();
- trx->mysql_thd = thd;
- trx->mysql_query_str = thd_query(thd);
-
- if (thd_test_options(thd, OPTION_NO_FOREIGN_KEY_CHECKS)) {
- trx->check_foreigns = FALSE;
- }
-
- name_len1 = strlen(from);
- name_len2 = strlen(to);
-
- assert(name_len1 < 1000);
- assert(name_len2 < 1000);
-
- normalize_table_name(norm_from, from);
- normalize_table_name(norm_to, to);
-
- /* Rename the table in InnoDB */
-
- error = row_rename_table_for_mysql(norm_from, norm_to, trx);
-
- /* Flush the log to reduce probability that the .frm files and
- the InnoDB data dictionary get out-of-sync if the user runs
- with innodb_flush_log_at_trx_commit = 0 */
-
- log_buffer_flush_to_disk();
+ error = innobase_rename_table(trx, from, to, TRUE);
/* Tell the InnoDB server that there might be work for
utility threads: */
@@ -5761,23 +6704,22 @@ ha_innobase::rename_table(
innobase_commit_low(trx);
trx_free_for_mysql(trx);
- error = convert_error_code_to_mysql(error, NULL);
+ error = convert_error_code_to_mysql(error, 0, NULL);
DBUG_RETURN(error);
}
-/*************************************************************************
-Estimates the number of index records in a range. */
-
+/*********************************************************************//**
+Estimates the number of index records in a range.
+@return estimated number of rows */
+UNIV_INTERN
ha_rows
ha_innobase::records_in_range(
/*==========================*/
- /* out: estimated number of
- rows */
- uint keynr, /* in: index number */
- key_range *min_key, /* in: start key value of the
+ uint keynr, /*!< in: index number */
+ key_range *min_key, /*!< in: start key value of the
range, may also be 0 */
- key_range *max_key) /* in: range end key val, may
+ key_range *max_key) /*!< in: range end key val, may
also be 0 */
{
KEY* key;
@@ -5790,11 +6732,10 @@ ha_innobase::records_in_range(
+ table->s->max_key_length + 100;
dtuple_t* range_start;
dtuple_t* range_end;
- ib_longlong n_rows;
+ ib_int64_t n_rows;
ulint mode1;
ulint mode2;
- void* heap1;
- void* heap2;
+ mem_heap_t* heap;
DBUG_ENTER("records_in_range");
@@ -5811,12 +6752,18 @@ ha_innobase::records_in_range(
key = table->key_info + active_index;
- index = dict_table_get_index_noninline(prebuilt->table, key->name);
+ index = dict_table_get_index_on_name(prebuilt->table, key->name);
- range_start = dtuple_create_for_mysql(&heap1, key->key_parts);
+ /* MySQL knows about this index and so we must be able to find it.*/
+ ut_a(index);
+
+ heap = mem_heap_create(2 * (key->key_parts * sizeof(dfield_t)
+ + sizeof(dtuple_t)));
+
+ range_start = dtuple_create(heap, key->key_parts);
dict_index_copy_types(range_start, index, key->key_parts);
- range_end = dtuple_create_for_mysql(&heap2, key->key_parts);
+ range_end = dtuple_create(heap, key->key_parts);
dict_index_copy_types(range_end, index, key->key_parts);
row_sel_convert_mysql_key_to_innobase(
@@ -5851,8 +6798,7 @@ ha_innobase::records_in_range(
n_rows = HA_POS_ERROR;
}
- dtuple_free_for_mysql(heap1);
- dtuple_free_for_mysql(heap2);
+ mem_heap_free(heap);
my_free(key_val_buff2, MYF(0));
@@ -5871,14 +6817,14 @@ ha_innobase::records_in_range(
DBUG_RETURN((ha_rows) n_rows);
}
-/*************************************************************************
+/*********************************************************************//**
Gives an UPPER BOUND to the number of rows in a table. This is used in
-filesort.cc. */
-
+filesort.cc.
+@return upper bound of rows */
+UNIV_INTERN
ha_rows
ha_innobase::estimate_rows_upper_bound(void)
/*======================================*/
- /* out: upper bound of rows */
{
dict_index_t* index;
ulonglong estimate;
@@ -5900,10 +6846,13 @@ ha_innobase::estimate_rows_upper_bound(void)
trx_search_latch_release_if_reserved(prebuilt->trx);
- index = dict_table_get_first_index_noninline(prebuilt->table);
+ index = dict_table_get_first_index(prebuilt->table);
+
+ ut_a(index->stat_n_leaf_pages > 0);
+
+ local_data_file_length =
+ ((ulonglong) index->stat_n_leaf_pages) * UNIV_PAGE_SIZE;
- local_data_file_length = ((ulonglong) index->stat_n_leaf_pages)
- * UNIV_PAGE_SIZE;
/* Calculate a minimum length for a clustered index record and from
that an upper bound for the number of rows. Since we only calculate
@@ -5918,15 +6867,15 @@ ha_innobase::estimate_rows_upper_bound(void)
DBUG_RETURN((ha_rows) estimate);
}
-/*************************************************************************
+/*********************************************************************//**
How many seeks it will take to read through the table. This is to be
comparable to the number returned by records_in_range so that we can
-decide if we should scan the table or use keys. */
-
+decide if we should scan the table or use keys.
+@return estimated time measured in disk seeks */
+UNIV_INTERN
double
ha_innobase::scan_time()
/*====================*/
- /* out: estimated time measured in disk seeks */
{
/* Since MySQL seems to favor table scans too much over index
searches, we pretend that a sequential read takes the same time
@@ -5936,17 +6885,17 @@ ha_innobase::scan_time()
return((double) (prebuilt->table->stat_clustered_index_size));
}
-/**********************************************************************
+/******************************************************************//**
Calculate the time it takes to read a set of ranges through an index
-This enables us to optimise reads for clustered indexes. */
-
+This enables us to optimise reads for clustered indexes.
+@return estimated time measured in disk seeks */
+UNIV_INTERN
double
ha_innobase::read_time(
/*===================*/
- /* out: estimated time measured in disk seeks */
- uint index, /* in: key number */
- uint ranges, /* in: how many ranges */
- ha_rows rows) /* in: estimated number of rows in the ranges */
+ uint index, /*!< in: key number */
+ uint ranges, /*!< in: how many ranges */
+ ha_rows rows) /*!< in: estimated number of rows in the ranges */
{
ha_rows total_rows;
double time_for_scan;
@@ -5974,19 +6923,19 @@ ha_innobase::read_time(
return(ranges + (double) rows / (double) total_rows * time_for_scan);
}
-/*************************************************************************
+/*********************************************************************//**
Returns statistics information of the table to the MySQL interpreter,
in various fields of the handle object. */
-
+UNIV_INTERN
int
ha_innobase::info(
/*==============*/
- uint flag) /* in: what information MySQL requests */
+ uint flag) /*!< in: what information MySQL requests */
{
dict_table_t* ib_table;
dict_index_t* index;
ha_rows rec_per_key;
- ib_longlong n_rows;
+ ib_int64_t n_rows;
ulong j;
ulong i;
char path[FN_REFLEN];
@@ -6044,7 +6993,7 @@ ha_innobase::info(
nor the CHECK TABLE time, nor the UPDATE or INSERT time. */
if (os_file_get_status(path,&stat_info)) {
- stats.create_time = stat_info.ctime;
+ stats.create_time = (ulong) stat_info.ctime;
}
}
@@ -6152,10 +7101,10 @@ ha_innobase::info(
}
if (flag & HA_STATUS_CONST) {
- index = dict_table_get_first_index_noninline(ib_table);
+ index = dict_table_get_first_index(ib_table);
if (prebuilt->clust_index_was_generated) {
- index = dict_table_get_next_index_noninline(index);
+ index = dict_table_get_next_index(index);
}
for (i = 0; i < table->s->keys; i++) {
@@ -6166,8 +7115,8 @@ ha_innobase::info(
".frm file. Have you mixed up "
".frm files from different "
"installations? See "
-"http://dev.mysql.com/doc/refman/5.1/en/innodb-troubleshooting.html\n",
-
+ REFMAN
+ "innodb-troubleshooting.html\n",
ib_table->name);
break;
}
@@ -6179,7 +7128,7 @@ ha_innobase::info(
"Index %s of %s has %lu columns unique inside InnoDB, but MySQL is asking "
"statistics for %lu columns. Have you mixed up .frm files from different "
"installations? "
-"See http://dev.mysql.com/doc/refman/5.1/en/innodb-troubleshooting.html\n",
+"See " REFMAN "innodb-troubleshooting.html\n",
index->name,
ib_table->name,
(unsigned long)
@@ -6211,37 +7160,45 @@ ha_innobase::info(
(ulong) rec_per_key;
}
- index = dict_table_get_next_index_noninline(index);
+ index = dict_table_get_next_index(index);
}
}
if (flag & HA_STATUS_ERRKEY) {
+ const dict_index_t* err_index;
+
ut_a(prebuilt->trx);
ut_a(prebuilt->trx->magic_n == TRX_MAGIC_N);
- errkey = (unsigned int) row_get_mysql_key_number_for_index(
- (dict_index_t*) trx_get_error_info(prebuilt->trx));
+ err_index = trx_get_error_info(prebuilt->trx);
+
+ if (err_index) {
+ errkey = (unsigned int)
+ row_get_mysql_key_number_for_index(err_index);
+ } else {
+ errkey = (unsigned int) prebuilt->trx->error_key_num;
+ }
}
- if (flag & HA_STATUS_AUTO && table->found_next_number_field) {
- stats.auto_increment_value = innobase_peek_autoinc();
+ if ((flag & HA_STATUS_AUTO) && table->found_next_number_field) {
+ stats.auto_increment_value = innobase_peek_autoinc();
}
prebuilt->trx->op_info = (char*)"";
- DBUG_RETURN(0);
+ DBUG_RETURN(0);
}
-/**************************************************************************
+/**********************************************************************//**
Updates index cardinalities of the table, based on 8 random dives into
-each index tree. This does NOT calculate exact statistics on the table. */
-
+each index tree. This does NOT calculate exact statistics on the table.
+@return returns always 0 (success) */
+UNIV_INTERN
int
ha_innobase::analyze(
/*=================*/
- /* out: returns always 0 (success) */
- THD* thd, /* in: connection thread handle */
- HA_CHECK_OPT* check_opt) /* in: currently ignored */
+ THD* thd, /*!< in: connection thread handle */
+ HA_CHECK_OPT* check_opt) /*!< in: currently ignored */
{
/* Simply call ::info() with all the flags */
info(HA_STATUS_TIME | HA_STATUS_CONST | HA_STATUS_VARIABLE);
@@ -6249,31 +7206,30 @@ ha_innobase::analyze(
return(0);
}
-/**************************************************************************
+/**********************************************************************//**
This is mapped to "ALTER TABLE tablename ENGINE=InnoDB", which rebuilds
the table in MySQL. */
-
+UNIV_INTERN
int
ha_innobase::optimize(
/*==================*/
- THD* thd, /* in: connection thread handle */
- HA_CHECK_OPT* check_opt) /* in: currently ignored */
+ THD* thd, /*!< in: connection thread handle */
+ HA_CHECK_OPT* check_opt) /*!< in: currently ignored */
{
return(HA_ADMIN_TRY_ALTER);
}
-/***********************************************************************
+/*******************************************************************//**
Tries to check that an InnoDB table is not corrupted. If corruption is
noticed, prints to stderr information about it. In case of corruption
-may also assert a failure and crash the server. */
-
+may also assert a failure and crash the server.
+@return HA_ADMIN_CORRUPT or HA_ADMIN_OK */
+UNIV_INTERN
int
ha_innobase::check(
/*===============*/
- /* out: HA_ADMIN_CORRUPT or
- HA_ADMIN_OK */
- THD* thd, /* in: user thread handle */
- HA_CHECK_OPT* check_opt) /* in: check options, currently
+ THD* thd, /*!< in: user thread handle */
+ HA_CHECK_OPT* check_opt) /*!< in: check options, currently
ignored */
{
ulint ret;
@@ -6299,17 +7255,16 @@ ha_innobase::check(
return(HA_ADMIN_CORRUPT);
}
-/*****************************************************************
+/*************************************************************//**
Adds information about free space in the InnoDB tablespace to a table comment
which is printed out when a user calls SHOW TABLE STATUS. Adds also info on
-foreign keys. */
-
+foreign keys.
+@return table comment + InnoDB free space + info on foreign keys */
+UNIV_INTERN
char*
ha_innobase::update_table_comment(
/*==============================*/
- /* out: table comment + InnoDB free space +
- info on foreign keys */
- const char* comment)/* in: table comment defined by user */
+ const char* comment)/*!< in: table comment defined by user */
{
uint length = (uint) strlen(comment);
char* str;
@@ -6335,7 +7290,7 @@ ha_innobase::update_table_comment(
/* output the data to a temporary file */
- mutex_enter_noninline(&srv_dict_tmpfile_mutex);
+ mutex_enter(&srv_dict_tmpfile_mutex);
rewind(srv_dict_tmpfile);
fprintf(srv_dict_tmpfile, "InnoDB free: %llu kB",
@@ -6368,22 +7323,22 @@ ha_innobase::update_table_comment(
pos[flen] = 0;
}
- mutex_exit_noninline(&srv_dict_tmpfile_mutex);
+ mutex_exit(&srv_dict_tmpfile_mutex);
prebuilt->trx->op_info = (char*)"";
return(str ? str : (char*) comment);
}
-/***********************************************************************
-Gets the foreign key create info for a table stored in InnoDB. */
-
+/*******************************************************************//**
+Gets the foreign key create info for a table stored in InnoDB.
+@return own: character string in the form which can be inserted to the
+CREATE TABLE statement, MUST be freed with
+ha_innobase::free_foreign_key_create_info */
+UNIV_INTERN
char*
ha_innobase::get_foreign_key_create_info(void)
/*==========================================*/
- /* out, own: character string in the form which
- can be inserted to the CREATE TABLE statement,
- MUST be freed with ::free_foreign_key_create_info */
{
char* str = 0;
long flen;
@@ -6404,7 +7359,7 @@ ha_innobase::get_foreign_key_create_info(void)
trx_search_latch_release_if_reserved(prebuilt->trx);
- mutex_enter_noninline(&srv_dict_tmpfile_mutex);
+ mutex_enter(&srv_dict_tmpfile_mutex);
rewind(srv_dict_tmpfile);
/* output the data to a temporary file */
@@ -6430,12 +7385,13 @@ ha_innobase::get_foreign_key_create_info(void)
str[flen] = 0;
}
- mutex_exit_noninline(&srv_dict_tmpfile_mutex);
+ mutex_exit(&srv_dict_tmpfile_mutex);
return(str);
}
+UNIV_INTERN
int
ha_innobase::get_foreign_key_list(THD *thd, List *f_key_list)
{
@@ -6446,7 +7402,7 @@ ha_innobase::get_foreign_key_list(THD *thd, List *f_key_list)
update_thd(ha_thd());
prebuilt->trx->op_info = (char*)"getting list of foreign keys";
trx_search_latch_release_if_reserved(prebuilt->trx);
- mutex_enter_noninline(&(dict_sys->mutex));
+ mutex_enter(&(dict_sys->mutex));
foreign = UT_LIST_GET_FIRST(prebuilt->table->foreign_list);
while (foreign != NULL) {
@@ -6503,7 +7459,7 @@ ha_innobase::get_foreign_key_list(THD *thd, List *f_key_list)
{
length=7;
tmp_buff= "CASCADE";
- }
+ }
else if (foreign->type & DICT_FOREIGN_ON_DELETE_SET_NULL)
{
length=8;
@@ -6521,8 +7477,8 @@ ha_innobase::get_foreign_key_list(THD *thd, List *f_key_list)
}
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)
{
length=7;
@@ -6561,17 +7517,18 @@ ha_innobase::get_foreign_key_list(THD *thd, List *f_key_list)
f_key_list->push_back(pf_key_info);
foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
}
- mutex_exit_noninline(&(dict_sys->mutex));
+ mutex_exit(&(dict_sys->mutex));
prebuilt->trx->op_info = (char*)"";
DBUG_RETURN(0);
}
-/*********************************************************************
+/*****************************************************************//**
Checks if ALTER TABLE may change the storage engine of the table.
Changing storage engines is not allowed for tables for which there
-are foreign key constraints (parent or child tables). */
-
+are foreign key constraints (parent or child tables).
+@return TRUE if can switch engines */
+UNIV_INTERN
bool
ha_innobase::can_switch_engines(void)
/*=================================*/
@@ -6595,18 +7552,18 @@ ha_innobase::can_switch_engines(void)
DBUG_RETURN(can_switch);
}
-/***********************************************************************
+/*******************************************************************//**
Checks if a table is referenced by a foreign key. The MySQL manual states that
a REPLACE is either equivalent to an INSERT, or DELETE(s) + INSERT. Only a
delete is then allowed internally to resolve a duplicate key conflict in
-REPLACE, not an update. */
-
+REPLACE, not an update.
+@return > 0 if referenced by a FOREIGN KEY */
+UNIV_INTERN
uint
ha_innobase::referenced_by_foreign_key(void)
/*========================================*/
- /* out: > 0 if referenced by a FOREIGN KEY */
{
- if (dict_table_referenced_by_foreign_key(prebuilt->table)) {
+ if (dict_table_is_referenced_by_foreign_key(prebuilt->table)) {
return(1);
}
@@ -6614,29 +7571,29 @@ ha_innobase::referenced_by_foreign_key(void)
return(0);
}
-/***********************************************************************
+/*******************************************************************//**
Frees the foreign key create info for a table stored in InnoDB, if it is
non-NULL. */
-
+UNIV_INTERN
void
ha_innobase::free_foreign_key_create_info(
/*======================================*/
- char* str) /* in, own: create info string to free */
+ char* str) /*!< in, own: create info string to free */
{
if (str) {
my_free(str, MYF(0));
}
}
-/***********************************************************************
-Tells something additional to the handler about how to do things. */
-
+/*******************************************************************//**
+Tells something additional to the handler about how to do things.
+@return 0 or error number */
+UNIV_INTERN
int
ha_innobase::extra(
/*===============*/
- /* out: 0 or error number */
enum ha_extra_function operation)
- /* in: HA_EXTRA_FLUSH or some other flag */
+ /*!< in: HA_EXTRA_FLUSH or some other flag */
{
/* Warning: since it is not sure that MySQL calls external_lock
before calling this function, the trx field in prebuilt can be
@@ -6687,11 +7644,9 @@ ha_innobase::extra(
return(0);
}
-/**********************************************************************
-Reset state of file to after 'open'.
-This function is called after every statement for all tables used
-by that statement. */
-int ha_innobase::reset()
+UNIV_INTERN
+int
+ha_innobase::reset()
{
if (prebuilt->blob_heap) {
row_mysql_prebuilt_free_blob_heap(prebuilt);
@@ -6708,7 +7663,7 @@ int ha_innobase::reset()
return(0);
}
-/**********************************************************************
+/******************************************************************//**
MySQL calls this function at the start of each SQL statement inside LOCK
TABLES. Inside LOCK TABLES the ::external_lock method does not work to
mark SQL statement borders. Note also a special case: if a temporary table
@@ -6718,13 +7673,13 @@ MySQL-5.0 also calls this before each statement in an execution of a stored
procedure. To make the execution more deterministic for binlogging, MySQL-5.0
locks all tables involved in a stored procedure with full explicit table
locks (thd_in_lock_tables(thd) holds in store_lock()) before executing the
-procedure. */
-
+procedure.
+@return 0 or error code */
+UNIV_INTERN
int
ha_innobase::start_stmt(
/*====================*/
- /* out: 0 or error code */
- THD* thd, /* in: handle to the user thread */
+ THD* thd, /*!< in: handle to the user thread */
thr_lock_type lock_type)
{
trx_t* trx;
@@ -6793,14 +7748,14 @@ ha_innobase::start_stmt(
return(0);
}
-/**********************************************************************
-Maps a MySQL trx isolation level code to the InnoDB isolation level code */
-inline
+/******************************************************************//**
+Maps a MySQL trx isolation level code to the InnoDB isolation level code
+@return InnoDB isolation level */
+static inline
ulint
innobase_map_isolation_level(
/*=========================*/
- /* out: InnoDB isolation level */
- enum_tx_isolation iso) /* in: MySQL isolation level code */
+ enum_tx_isolation iso) /*!< in: MySQL isolation level code */
{
switch(iso) {
case ISO_REPEATABLE_READ: return(TRX_ISO_REPEATABLE_READ);
@@ -6811,21 +7766,21 @@ innobase_map_isolation_level(
}
}
-/**********************************************************************
+/******************************************************************//**
As MySQL will execute an external lock for every new table it uses when it
starts to process an SQL statement (an exception is when MySQL calls
start_stmt for the handle) we can use this function to store the pointer to
the THD in the handle. We will also use this function to communicate
to InnoDB that a new SQL statement has started and that we must store a
savepoint to our transaction handle, so that we are able to roll back
-the SQL statement in case of an error. */
-
+the SQL statement in case of an error.
+@return 0 */
+UNIV_INTERN
int
ha_innobase::external_lock(
/*=======================*/
- /* out: 0 */
- THD* thd, /* in: handle to the user thread */
- int lock_type) /* in: lock type */
+ THD* thd, /*!< in: handle to the user thread */
+ int lock_type) /*!< in: lock type */
{
trx_t* trx;
@@ -6841,7 +7796,7 @@ ha_innobase::external_lock(
if (lock_type == F_WRLCK)
{
ulong const binlog_format= thd_binlog_format(thd);
- ulong const tx_isolation = thd_tx_isolation(current_thd);
+ ulong const tx_isolation = thd_tx_isolation(ha_thd());
if (tx_isolation <= ISO_READ_COMMITTED &&
binlog_format == BINLOG_FORMAT_STMT)
{
@@ -6927,7 +7882,7 @@ ha_innobase::external_lock(
if (error != DB_SUCCESS) {
error = convert_error_code_to_mysql(
- (int) error, thd);
+ (int) error, 0, thd);
DBUG_RETURN((int) error);
}
}
@@ -6979,16 +7934,16 @@ ha_innobase::external_lock(
DBUG_RETURN(0);
}
-/**********************************************************************
+/******************************************************************//**
With this function MySQL request a transactional lock to a table when
-user issued query LOCK TABLES..WHERE ENGINE = InnoDB. */
-
+user issued query LOCK TABLES..WHERE ENGINE = InnoDB.
+@return error code */
+UNIV_INTERN
int
ha_innobase::transactional_table_lock(
/*==================================*/
- /* out: error code */
- THD* thd, /* in: handle to the user thread */
- int lock_type) /* in: lock type */
+ THD* thd, /*!< in: handle to the user thread */
+ int lock_type) /*!< in: lock type */
{
trx_t* trx;
@@ -7010,8 +7965,8 @@ ha_innobase::transactional_table_lock(
"InnoDB: Have you deleted the .ibd file"
" from the database directory under\n"
"InnoDB: the MySQL datadir?"
- "InnoDB: See"
- " http://dev.mysql.com/doc/refman/5.1/en/innodb-troubleshooting.html\n"
+ "InnoDB: See " REFMAN
+ "innodb-troubleshooting.html\n"
"InnoDB: how you can resolve the problem.\n",
prebuilt->table->name);
DBUG_RETURN(HA_ERR_CRASHED);
@@ -7054,7 +8009,8 @@ ha_innobase::transactional_table_lock(
error = row_lock_table_for_mysql(prebuilt, NULL, 0);
if (error != DB_SUCCESS) {
- error = convert_error_code_to_mysql((int) error, thd);
+ error = convert_error_code_to_mysql(
+ (int) error, prebuilt->table->flags, thd);
DBUG_RETURN((int) error);
}
@@ -7071,29 +8027,27 @@ ha_innobase::transactional_table_lock(
DBUG_RETURN(0);
}
-/****************************************************************************
-Here we export InnoDB status variables to MySQL. */
+/************************************************************************//**
+Here we export InnoDB status variables to MySQL. */
static
-int
-innodb_export_status()
-/*==================*/
+void
+innodb_export_status(void)
+/*======================*/
{
if (innodb_inited) {
srv_export_innodb_status();
}
-
- return 0;
}
-/****************************************************************************
+/************************************************************************//**
Implements the SHOW INNODB STATUS command. Sends the output of the InnoDB
Monitor to the client. */
static
bool
innodb_show_status(
/*===============*/
- handlerton* hton, /* in: the innodb handlerton */
- THD* thd, /* in: the MySQL query thread of the caller */
+ handlerton* hton, /*!< in: the innodb handlerton */
+ THD* thd, /*!< in: the MySQL query thread of the caller */
stat_print_fn *stat_print)
{
trx_t* trx;
@@ -7103,6 +8057,7 @@ innodb_show_status(
ulint trx_list_end = ULINT_UNDEFINED;
DBUG_ENTER("innodb_show_status");
+ DBUG_ASSERT(hton == innodb_hton_ptr);
trx = check_trx_exists(thd);
@@ -7114,9 +8069,10 @@ innodb_show_status(
long flen, usable_len;
char* str;
- mutex_enter_noninline(&srv_monitor_file_mutex);
+ mutex_enter(&srv_monitor_file_mutex);
rewind(srv_monitor_file);
- srv_printf_innodb_monitor(srv_monitor_file);
+ srv_printf_innodb_monitor(srv_monitor_file,
+ &trx_list_start, &trx_list_end);
flen = ftell(srv_monitor_file);
os_file_set_eof(srv_monitor_file);
@@ -7134,7 +8090,7 @@ innodb_show_status(
read the contents of the temporary file */
if (!(str = (char*) my_malloc(usable_len + 1, MYF(0)))) {
- mutex_exit_noninline(&srv_monitor_file_mutex);
+ mutex_exit(&srv_monitor_file_mutex);
DBUG_RETURN(TRUE);
}
@@ -7159,7 +8115,7 @@ innodb_show_status(
flen = (long) fread(str, 1, MAX_STATUS_SIZE - 1, srv_monitor_file);
}
- mutex_exit_noninline(&srv_monitor_file_mutex);
+ mutex_exit(&srv_monitor_file_mutex);
bool result = FALSE;
@@ -7172,20 +8128,20 @@ innodb_show_status(
DBUG_RETURN(FALSE);
}
-/****************************************************************************
+/************************************************************************//**
Implements the SHOW MUTEX STATUS command. . */
static
bool
innodb_mutex_show_status(
/*=====================*/
- handlerton* hton, /* in: the innodb handlerton */
- THD* thd, /* in: the MySQL query thread of the
+ handlerton* hton, /*!< in: the innodb handlerton */
+ THD* thd, /*!< in: the MySQL query thread of the
caller */
stat_print_fn* stat_print)
{
char buf1[IO_SIZE], buf2[IO_SIZE];
- mutex_t* mutex;
- rw_lock_t* lock;
+ mutex_t* mutex;
+ rw_lock_t* lock;
#ifdef UNIV_DEBUG
ulint rw_lock_count= 0;
ulint rw_lock_count_spin_loop= 0;
@@ -7196,12 +8152,17 @@ innodb_mutex_show_status(
#endif /* UNIV_DEBUG */
uint hton_name_len= (uint) strlen(innobase_hton_name), buf1len, buf2len;
DBUG_ENTER("innodb_mutex_show_status");
+ DBUG_ASSERT(hton == innodb_hton_ptr);
- mutex_enter_noninline(&mutex_list_mutex);
+ mutex_enter(&mutex_list_mutex);
mutex = UT_LIST_GET_FIRST(mutex_list);
while (mutex != NULL) {
+ if (mutex->count_os_wait == 0
+ || buf_pool_is_block_mutex(mutex)) {
+ goto next_mutex;
+ }
#ifdef UNIV_DEBUG
if (mutex->mutex_type != 1) {
if (mutex->count_using > 0) {
@@ -7223,8 +8184,7 @@ innodb_mutex_show_status(
if (stat_print(thd, innobase_hton_name,
hton_name_len, buf1, buf1len,
buf2, buf2len)) {
- mutex_exit_noninline(
- &mutex_list_mutex);
+ mutex_exit(&mutex_list_mutex);
DBUG_RETURN(1);
}
}
@@ -7246,24 +8206,24 @@ innodb_mutex_show_status(
if (stat_print(thd, innobase_hton_name,
hton_name_len, buf1, buf1len,
buf2, buf2len)) {
- mutex_exit_noninline(&mutex_list_mutex);
+ mutex_exit(&mutex_list_mutex);
DBUG_RETURN(1);
}
#endif /* UNIV_DEBUG */
+next_mutex:
mutex = UT_LIST_GET_NEXT(list, mutex);
}
- mutex_exit_noninline(&mutex_list_mutex);
+ mutex_exit(&mutex_list_mutex);
- mutex_enter_noninline(&rw_lock_list_mutex);
+ mutex_enter(&rw_lock_list_mutex);
lock = UT_LIST_GET_FIRST(rw_lock_list);
- while (lock != NULL)
- {
- if (lock->count_os_wait)
- {
+ while (lock != NULL) {
+ if (lock->count_os_wait
+ && !buf_pool_is_block_lock(lock)) {
buf1len= my_snprintf(buf1, sizeof(buf1), "%s:%lu",
lock->cfile_name, (ulong) lock->cline);
buf2len= my_snprintf(buf2, sizeof(buf2),
@@ -7272,14 +8232,14 @@ innodb_mutex_show_status(
if (stat_print(thd, innobase_hton_name,
hton_name_len, buf1, buf1len,
buf2, buf2len)) {
- mutex_exit_noninline(&rw_lock_list_mutex);
+ mutex_exit(&rw_lock_list_mutex);
DBUG_RETURN(1);
}
}
lock = UT_LIST_GET_NEXT(list, lock);
}
- mutex_exit_noninline(&rw_lock_list_mutex);
+ mutex_exit(&rw_lock_list_mutex);
#ifdef UNIV_DEBUG
buf2len= my_snprintf(buf2, sizeof(buf2),
@@ -7304,101 +8264,111 @@ bool innobase_show_status(handlerton *hton, THD* thd,
stat_print_fn* stat_print,
enum ha_stat_type stat_type)
{
+ DBUG_ASSERT(hton == innodb_hton_ptr);
+
switch (stat_type) {
case HA_ENGINE_STATUS:
return innodb_show_status(hton, thd, stat_print);
case HA_ENGINE_MUTEX:
return innodb_mutex_show_status(hton, thd, stat_print);
default:
- return FALSE;
+ return(FALSE);
}
}
- rw_lock_t* lock;
-
-/****************************************************************************
+/************************************************************************//**
Handling the shared INNOBASE_SHARE structure that is needed to provide table
locking.
****************************************************************************/
-static uchar* innobase_get_key(INNOBASE_SHARE* share, size_t *length,
- my_bool not_used __attribute__((unused)))
-{
- *length=share->table_name_length;
-
- return (uchar*) share->table_name;
-}
-
static INNOBASE_SHARE* get_share(const char* table_name)
{
INNOBASE_SHARE *share;
pthread_mutex_lock(&innobase_share_mutex);
- uint length=(uint) strlen(table_name);
- if (!(share=(INNOBASE_SHARE*) hash_search(&innobase_open_tables,
- (uchar*) table_name,
- length))) {
+ ulint fold = ut_fold_string(table_name);
+
+ HASH_SEARCH(table_name_hash, innobase_open_tables, fold,
+ INNOBASE_SHARE*, share,
+ ut_ad(share->use_count > 0),
+ !strcmp(share->table_name, table_name));
+
+ if (!share) {
+
+ uint length = (uint) strlen(table_name);
+
+ /* TODO: invoke HASH_MIGRATE if innobase_open_tables
+ grows too big */
share = (INNOBASE_SHARE *) my_malloc(sizeof(*share)+length+1,
MYF(MY_FAE | MY_ZEROFILL));
- share->table_name_length=length;
- share->table_name=(char*) (share+1);
- strmov(share->table_name,table_name);
+ share->table_name = (char*) memcpy(share + 1,
+ table_name, length + 1);
- if (my_hash_insert(&innobase_open_tables,
- (uchar*) share)) {
- pthread_mutex_unlock(&innobase_share_mutex);
- my_free(share,0);
-
- return 0;
- }
+ HASH_INSERT(INNOBASE_SHARE, table_name_hash,
+ innobase_open_tables, fold, share);
thr_lock_init(&share->lock);
- pthread_mutex_init(&share->mutex,MY_MUTEX_INIT_FAST);
}
share->use_count++;
pthread_mutex_unlock(&innobase_share_mutex);
- return share;
+ return(share);
}
static void free_share(INNOBASE_SHARE* share)
{
pthread_mutex_lock(&innobase_share_mutex);
+#ifdef UNIV_DEBUG
+ INNOBASE_SHARE* share2;
+ ulint fold = ut_fold_string(share->table_name);
+
+ HASH_SEARCH(table_name_hash, innobase_open_tables, fold,
+ INNOBASE_SHARE*, share2,
+ ut_ad(share->use_count > 0),
+ !strcmp(share->table_name, share2->table_name));
+
+ ut_a(share2 == share);
+#endif /* UNIV_DEBUG */
+
if (!--share->use_count) {
- hash_delete(&innobase_open_tables, (uchar*) share);
+ ulint fold = ut_fold_string(share->table_name);
+
+ HASH_DELETE(INNOBASE_SHARE, table_name_hash,
+ innobase_open_tables, fold, share);
thr_lock_delete(&share->lock);
- pthread_mutex_destroy(&share->mutex);
my_free(share, MYF(0));
+
+ /* TODO: invoke HASH_MIGRATE if innobase_open_tables
+ shrinks too much */
}
pthread_mutex_unlock(&innobase_share_mutex);
}
-/*********************************************************************
+/*****************************************************************//**
Converts a MySQL table lock stored in the 'lock' field of the handle to
a proper type before storing pointer to the lock into an array of pointers.
MySQL also calls this if it wants to reset some table locks to a not-locked
state during the processing of an SQL query. An example is that during a
SELECT the read lock is released early on the 'const' tables where we only
fetch one row. MySQL does not call this when it releases all locks at the
-end of an SQL statement. */
-
+end of an SQL statement.
+@return pointer to the next element in the 'to' array */
+UNIV_INTERN
THR_LOCK_DATA**
ha_innobase::store_lock(
/*====================*/
- /* out: pointer to the next
- element in the 'to' array */
- THD* thd, /* in: user thread handle */
- THR_LOCK_DATA** to, /* in: pointer to an array
+ THD* thd, /*!< in: user thread handle */
+ THR_LOCK_DATA** to, /*!< in: pointer to an array
of pointers to lock structs;
pointer to the 'lock' field
of current handle is stored
next to this array */
- enum thr_lock_type lock_type) /* in: lock type to store in
+ enum thr_lock_type lock_type) /*!< in: lock type to store in
'lock'; this may also be
TL_IGNORE */
{
@@ -7432,7 +8402,7 @@ ha_innobase::store_lock(
}
}
- DBUG_ASSERT(thd == current_thd);
+ DBUG_ASSERT(EQ_CURRENT_THD(thd));
const bool in_lock_tables = thd_in_lock_tables(thd);
const uint sql_command = thd_sql_command(thd);
@@ -7581,16 +8551,16 @@ ha_innobase::store_lock(
return(to);
}
-/*******************************************************************************
+/*********************************************************************//**
Read the next autoinc value. Acquire the relevant locks before reading
the AUTOINC value. If SUCCESS then the table AUTOINC mutex will be locked
-on return and all relevant locks acquired. */
-
-ulong
+on return and all relevant locks acquired.
+@return DB_SUCCESS or error code */
+UNIV_INTERN
+ulint
ha_innobase::innobase_get_autoinc(
/*==============================*/
- /* out: DB_SUCCESS or error code */
- ulonglong* value) /* out: autoinc value */
+ ulonglong* value) /*!< out: autoinc value */
{
*value = 0;
@@ -7604,18 +8574,18 @@ ha_innobase::innobase_get_autoinc(
/* It should have been initialized during open. */
ut_a(*value != 0);
}
-
- return(ulong(prebuilt->autoinc_error));
+
+ return(prebuilt->autoinc_error);
}
-/***********************************************************************
+/*******************************************************************//**
This function reads the global auto-inc counter. It doesn't use the
-AUTOINC lock even if the lock mode is set to TRADITIONAL. */
-
+AUTOINC lock even if the lock mode is set to TRADITIONAL.
+@return the autoinc value */
+UNIV_INTERN
ulonglong
-ha_innobase::innobase_peek_autoinc()
-/*================================*/
- /* out: the autoinc value */
+ha_innobase::innobase_peek_autoinc(void)
+/*====================================*/
{
ulonglong auto_inc;
dict_table_t* innodb_table;
@@ -7632,26 +8602,26 @@ ha_innobase::innobase_peek_autoinc()
ut_a(auto_inc > 0);
dict_table_autoinc_unlock(innodb_table);
-
+
return(auto_inc);
}
-/*******************************************************************************
+/*********************************************************************//**
This function initializes the auto-inc counter if it has not been
initialized yet. This function does not change the value of the auto-inc
counter if it already has been initialized. Returns the value of the
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) */
-
+*first_value is set to -1 if error (deadlock or lock wait timeout) */
+UNIV_INTERN
void
ha_innobase::get_auto_increment(
/*============================*/
- 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 */
+ ulonglong offset, /*!< in: table autoinc offset */
+ 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 */
{
trx_t* trx;
ulint error;
@@ -7745,11 +8715,17 @@ ha_innobase::get_auto_increment(
dict_table_autoinc_unlock(prebuilt->table);
}
-/* See comment in handler.h */
+/*******************************************************************//**
+Reset the auto-increment counter to the given value, i.e. the next row
+inserted will get the given value. This is called e.g. after TRUNCATE
+is emulated by doing a 'DELETE FROM t'. HA_ERR_WRONG_COMMAND is
+returned by storage engines that don't support this operation.
+@return 0 or error code */
+UNIV_INTERN
int
ha_innobase::reset_auto_increment(
/*==============================*/
- ulonglong value) /* in: new value for table autoinc */
+ ulonglong value) /*!< in: new value for table autoinc */
{
DBUG_ENTER("ha_innobase::reset_auto_increment");
@@ -7760,7 +8736,9 @@ ha_innobase::reset_auto_increment(
error = row_lock_table_autoinc_for_mysql(prebuilt);
if (error != DB_SUCCESS) {
- error = convert_error_code_to_mysql(error, user_thd);
+ error = convert_error_code_to_mysql(error,
+ prebuilt->table->flags,
+ user_thd);
DBUG_RETURN(error);
}
@@ -7776,6 +8754,7 @@ ha_innobase::reset_auto_increment(
}
/* See comment in handler.cc */
+UNIV_INTERN
bool
ha_innobase::get_error_message(int error, String *buf)
{
@@ -7784,22 +8763,21 @@ ha_innobase::get_error_message(int error, String *buf)
buf->copy(trx->detailed_error, (uint) strlen(trx->detailed_error),
system_charset_info);
- return FALSE;
+ return(FALSE);
}
-/***********************************************************************
+/*******************************************************************//**
Compares two 'refs'. A 'ref' is the (internal) primary key value of the row.
If there is no explicitly declared non-null unique key or a primary key, then
-InnoDB internally uses the row id as the primary key. */
-
+InnoDB internally uses the row id as the primary key.
+@return < 0 if ref1 < ref2, 0 if equal, else > 0 */
+UNIV_INTERN
int
ha_innobase::cmp_ref(
/*=================*/
- /* out: < 0 if ref1 < ref2, 0 if equal, else
- > 0 */
- const uchar* ref1, /* in: an (internal) primary key value in the
+ const uchar* ref1, /*!< in: an (internal) primary key value in the
MySQL key value format */
- const uchar* ref2) /* in: an (internal) primary key value in the
+ const uchar* ref2) /*!< in: an (internal) primary key value in the
MySQL key value format */
{
enum_field_types mysql_type;
@@ -7859,25 +8837,24 @@ ha_innobase::cmp_ref(
return(0);
}
-/***********************************************************************
-Ask InnoDB if a query to a table can be cached. */
-
+/*******************************************************************//**
+Ask InnoDB if a query to a table can be cached.
+@return TRUE if query caching of the table is permitted */
+UNIV_INTERN
my_bool
ha_innobase::register_query_cache_table(
/*====================================*/
- /* out: TRUE if query caching
- of the table is permitted */
- THD* thd, /* in: user thread handle */
- char* table_key, /* in: concatenation of database name,
- the null character '\0',
+ THD* thd, /*!< in: user thread handle */
+ char* table_key, /*!< in: concatenation of database name,
+ the null character NUL,
and the table name */
- uint key_length, /* in: length of the full name, i.e.
+ uint key_length, /*!< in: length of the full name, i.e.
len(dbname) + len(tablename) + 1 */
qc_engine_callback*
- call_back, /* out: pointer to function for
+ call_back, /*!< out: pointer to function for
checking if query caching
is permitted */
- ulonglong *engine_data) /* in/out: data to call_back */
+ ulonglong *engine_data) /*!< in/out: data to call_back */
{
*call_back = innobase_query_caching_of_table_permitted;
*engine_data = 0;
@@ -7886,45 +8863,43 @@ ha_innobase::register_query_cache_table(
engine_data));
}
+UNIV_INTERN
char*
ha_innobase::get_mysql_bin_log_name()
{
return(trx_sys_mysql_bin_log_name);
}
+UNIV_INTERN
ulonglong
ha_innobase::get_mysql_bin_log_pos()
{
- /* trx... is ib_longlong, which is a typedef for a 64-bit integer
+ /* trx... is ib_int64_t, which is a typedef for a 64-bit integer
(__int64 or longlong) so it's ok to cast it to ulonglong. */
return(trx_sys_mysql_bin_log_pos);
}
-/**********************************************************************
+/******************************************************************//**
This function is used to find the storage length in bytes of the first n
characters for prefix indexes using a multibyte character set. The function
finds charset information and returns length of prefix_len characters in the
index field in bytes.
-
-NOTE: the prototype of this function is copied to data0type.c! If you change
-this function, you MUST change also data0type.c! */
-extern "C"
+@return number of bytes occupied by the first n characters */
+extern "C" UNIV_INTERN
ulint
innobase_get_at_most_n_mbchars(
/*===========================*/
- /* out: number of bytes occupied by the first
- n characters */
- ulint charset_id, /* in: character set id */
- ulint prefix_len, /* in: prefix length in bytes of the index
+ ulint charset_id, /*!< in: character set id */
+ ulint prefix_len, /*!< in: prefix length in bytes of the index
(this has to be divided by mbmaxlen to get the
number of CHARACTERS n in the prefix) */
- ulint data_len, /* in: length of the string in bytes */
- const char* str) /* in: character string */
+ ulint data_len, /*!< in: length of the string in bytes */
+ const char* str) /*!< in: character string */
{
- ulint char_length; /* character length in bytes */
- ulint n_chars; /* number of characters in prefix */
- CHARSET_INFO* charset; /* charset used in the field */
+ ulint char_length; /*!< character length in bytes */
+ ulint n_chars; /*!< number of characters in prefix */
+ CHARSET_INFO* charset; /*!< charset used in the field */
charset = get_charset((uint) charset_id, MYF(MY_WME));
@@ -7975,50 +8950,30 @@ innobase_get_at_most_n_mbchars(
return(char_length);
}
-/***********************************************************************
-This function is used to prepare X/Open XA distributed transaction */
+/*******************************************************************//**
+This function is used to prepare an X/Open XA distributed transaction.
+@return 0 or error number */
static
int
innobase_xa_prepare(
/*================*/
- /* out: 0 or error number */
- handlerton *hton,
- THD* thd, /* in: handle to the MySQL thread of the user
- whose XA transaction should be prepared */
- bool all) /* in: TRUE - commit transaction
- FALSE - the current SQL statement ended */
+ handlerton* hton, /*!< in: InnoDB handlerton */
+ THD* thd, /*!< in: handle to the MySQL thread of
+ the user whose XA transaction should
+ be prepared */
+ bool all) /*!< in: TRUE - commit transaction
+ FALSE - the current SQL statement
+ ended */
{
int error = 0;
trx_t* trx = check_trx_exists(thd);
- if (thd_sql_command(thd) != SQLCOM_XA_PREPARE &&
- (all || !thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)))
- {
+ DBUG_ASSERT(hton == innodb_hton_ptr);
- /* For ibbackup to work the order of transactions in binlog
- and InnoDB must be the same. Consider the situation
-
- thread1> prepare; write to binlog; ...
-
- thread2> prepare; write to binlog; commit
- thread1> ... commit
-
- To ensure this will not happen we're taking the mutex on
- prepare, and releasing it on commit.
-
- Note: only do it for normal commits, done via ha_commit_trans.
- If 2pc protocol is executed by external transaction
- coordinator, it will be just a regular MySQL client
- executing XA PREPARE and XA COMMIT commands.
- In this case we cannot know how many minutes or hours
- will be between XA PREPARE and XA COMMIT, and we don't want
- to block for undefined period of time.
- */
- pthread_mutex_lock(&prepare_commit_mutex);
- trx->active_trans = 2;
- }
-
- if (!THDVAR(thd, support_xa)) {
+ /* we use support_xa value as it was seen at transaction start
+ time, not the current session variable value. Any possible changes
+ to the session variable take effect only in the next transaction */
+ if (!trx->support_xa) {
return(0);
}
@@ -8067,21 +9022,49 @@ innobase_xa_prepare(
srv_active_wake_master_thread();
- return error;
+ if (thd_sql_command(thd) != SQLCOM_XA_PREPARE &&
+ (all || !thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)))
+ {
+
+ /* For ibbackup to work the order of transactions in binlog
+ and InnoDB must be the same. Consider the situation
+
+ thread1> prepare; write to binlog; ...
+
+ thread2> prepare; write to binlog; commit
+ thread1> ... commit
+
+ To ensure this will not happen we're taking the mutex on
+ prepare, and releasing it on commit.
+
+ Note: only do it for normal commits, done via ha_commit_trans.
+ If 2pc protocol is executed by external transaction
+ coordinator, it will be just a regular MySQL client
+ executing XA PREPARE and XA COMMIT commands.
+ In this case we cannot know how many minutes or hours
+ will be between XA PREPARE and XA COMMIT, and we don't want
+ to block for undefined period of time.
+ */
+ pthread_mutex_lock(&prepare_commit_mutex);
+ trx->active_trans = 2;
+ }
+
+ return(error);
}
-/***********************************************************************
-This function is used to recover X/Open XA distributed transactions */
+/*******************************************************************//**
+This function is used to recover X/Open XA distributed transactions.
+@return number of prepared transactions stored in xid_list */
static
int
innobase_xa_recover(
/*================*/
- /* out: number of prepared transactions
- stored in xid_list */
- handlerton *hton,
- XID* xid_list, /* in/out: prepared transactions */
- uint len) /* in: number of slots in xid_list */
+ handlerton* hton, /*!< in: InnoDB handlerton */
+ XID* xid_list,/*!< in/out: prepared transactions */
+ uint len) /*!< in: number of slots in xid_list */
{
+ DBUG_ASSERT(hton == innodb_hton_ptr);
+
if (len == 0 || xid_list == NULL) {
return(0);
@@ -8090,19 +9073,21 @@ innobase_xa_recover(
return(trx_recover_for_mysql(xid_list, len));
}
-/***********************************************************************
+/*******************************************************************//**
This function is used to commit one X/Open XA distributed transaction
-which is in the prepared state */
+which is in the prepared state
+@return 0 or error number */
static
int
innobase_commit_by_xid(
/*===================*/
- /* out: 0 or error number */
handlerton *hton,
- XID* xid) /* in: X/Open XA transaction identification */
+ XID* xid) /*!< in: X/Open XA transaction identification */
{
trx_t* trx;
+ DBUG_ASSERT(hton == innodb_hton_ptr);
+
trx = trx_get_trx_by_xid(xid);
if (trx) {
@@ -8114,19 +9099,22 @@ innobase_commit_by_xid(
}
}
-/***********************************************************************
+/*******************************************************************//**
This function is used to rollback one X/Open XA distributed transaction
-which is in the prepared state */
+which is in the prepared state
+@return 0 or error number */
static
int
innobase_rollback_by_xid(
/*=====================*/
- /* out: 0 or error number */
- handlerton *hton,
- XID *xid) /* in: X/Open XA transaction identification */
+ handlerton* hton, /*!< in: InnoDB handlerton */
+ XID* xid) /*!< in: X/Open XA transaction
+ identification */
{
trx_t* trx;
+ DBUG_ASSERT(hton == innodb_hton_ptr);
+
trx = trx_get_trx_by_xid(xid);
if (trx) {
@@ -8136,23 +9124,25 @@ innobase_rollback_by_xid(
}
}
-/***********************************************************************
+/*******************************************************************//**
Create a consistent view for a cursor based on current transaction
which is created if the corresponding MySQL thread still lacks one.
This consistent view is then used inside of MySQL when accessing records
-using a cursor. */
+using a cursor.
+@return pointer to cursor view or NULL */
static
void*
innobase_create_cursor_view(
/*========================*/
- /* out: pointer to cursor view or NULL */
- handlerton *hton, /* in: innobase hton */
- THD* thd) /* in: user thread handle */
+ handlerton *hton, /*!< in: innobase hton */
+ THD* thd) /*!< in: user thread handle */
{
+ DBUG_ASSERT(hton == innodb_hton_ptr);
+
return(read_cursor_view_create_for_mysql(check_trx_exists(thd)));
}
-/***********************************************************************
+/*******************************************************************//**
Close the given consistent cursor view of a transaction and restore
global read view to a transaction read view. Transaction is created if the
corresponding MySQL thread still lacks one. */
@@ -8161,14 +9151,16 @@ void
innobase_close_cursor_view(
/*=======================*/
handlerton *hton,
- THD* thd, /* in: user thread handle */
- void* curview)/* in: Consistent read view to be closed */
+ THD* thd, /*!< in: user thread handle */
+ void* curview)/*!< in: Consistent read view to be closed */
{
+ DBUG_ASSERT(hton == innodb_hton_ptr);
+
read_cursor_view_close_for_mysql(check_trx_exists(thd),
(cursor_view_t*) curview);
}
-/***********************************************************************
+/*******************************************************************//**
Set the given consistent cursor view to a transaction which is created
if the corresponding MySQL thread still lacks one. If the given
consistent cursor view is NULL global read view of a transaction is
@@ -8178,38 +9170,511 @@ void
innobase_set_cursor_view(
/*=====================*/
handlerton *hton,
- THD* thd, /* in: user thread handle */
- void* curview)/* in: Consistent cursor view to be set */
+ THD* thd, /*!< in: user thread handle */
+ void* curview)/*!< in: Consistent cursor view to be set */
{
+ DBUG_ASSERT(hton == innodb_hton_ptr);
+
read_cursor_set_for_mysql(check_trx_exists(thd),
(cursor_view_t*) curview);
}
-bool ha_innobase::check_if_incompatible_data(
+/***********************************************************************
+Check whether any of the given columns is being renamed in the table. */
+static
+bool
+column_is_being_renamed(
+/*====================*/
+ /* out: true if any of col_names is
+ being renamed in table */
+ TABLE* table, /* in: MySQL table */
+ uint n_cols, /* in: number of columns */
+ const char** col_names) /* in: names of the columns */
+{
+ uint j;
+ uint k;
+ Field* field;
+ const char* col_name;
+
+ for (j = 0; j < n_cols; j++) {
+ col_name = col_names[j];
+ for (k = 0; k < table->s->fields; k++) {
+ field = table->field[k];
+ if ((field->flags & FIELD_IS_RENAMED)
+ && innobase_strcasecmp(field->field_name,
+ col_name) == 0) {
+ return(true);
+ }
+ }
+ }
+
+ return(false);
+}
+
+/***********************************************************************
+Check whether a column in table "table" is being renamed and if this column
+is part of a foreign key, either part of another table, referencing this
+table or part of this table, referencing another table. */
+static
+bool
+foreign_key_column_is_being_renamed(
+/*================================*/
+ /* out: true if a column that
+ participates in a foreign key definition
+ is being renamed */
+ row_prebuilt_t* prebuilt, /* in: InnoDB prebuilt struct */
+ TABLE* table) /* in: MySQL table */
+{
+ dict_foreign_t* foreign;
+
+ /* check whether there are foreign keys at all */
+ if (UT_LIST_GET_LEN(prebuilt->table->foreign_list) == 0
+ && UT_LIST_GET_LEN(prebuilt->table->referenced_list) == 0) {
+ /* no foreign keys involved with prebuilt->table */
+
+ return(false);
+ }
+
+ row_mysql_lock_data_dictionary(prebuilt->trx);
+
+ /* Check whether any column in the foreign key constraints which refer
+ to this table is being renamed. */
+ for (foreign = UT_LIST_GET_FIRST(prebuilt->table->referenced_list);
+ foreign != NULL;
+ foreign = UT_LIST_GET_NEXT(referenced_list, foreign)) {
+
+ if (column_is_being_renamed(table, foreign->n_fields,
+ foreign->referenced_col_names)) {
+
+ row_mysql_unlock_data_dictionary(prebuilt->trx);
+ return(true);
+ }
+ }
+
+ /* Check whether any column in the foreign key constraints in the
+ table is being renamed. */
+ for (foreign = UT_LIST_GET_FIRST(prebuilt->table->foreign_list);
+ foreign != NULL;
+ foreign = UT_LIST_GET_NEXT(foreign_list, foreign)) {
+
+ if (column_is_being_renamed(table, foreign->n_fields,
+ foreign->foreign_col_names)) {
+
+ row_mysql_unlock_data_dictionary(prebuilt->trx);
+ return(true);
+ }
+ }
+
+ row_mysql_unlock_data_dictionary(prebuilt->trx);
+
+ return(false);
+}
+
+UNIV_INTERN
+bool
+ha_innobase::check_if_incompatible_data(
HA_CREATE_INFO* info,
uint table_changes)
{
if (table_changes != IS_EQUAL_YES) {
- return COMPATIBLE_DATA_NO;
+ return(COMPATIBLE_DATA_NO);
}
/* Check that auto_increment value was not changed */
if ((info->used_fields & HA_CREATE_USED_AUTO) &&
info->auto_increment_value != 0) {
+ return(COMPATIBLE_DATA_NO);
+ }
+
+ /* Check if a column participating in a foreign key is being renamed.
+ There is no mechanism for updating InnoDB foreign key definitions. */
+ if (foreign_key_column_is_being_renamed(prebuilt, table)) {
+
return COMPATIBLE_DATA_NO;
}
/* Check that row format didn't change */
- if ((info->used_fields & HA_CREATE_USED_ROW_FORMAT) &&
- get_row_type() != info->row_type) {
+ if ((info->used_fields & HA_CREATE_USED_ROW_FORMAT)
+ && info->row_type != ROW_TYPE_DEFAULT
+ && info->row_type != get_row_type()) {
- return COMPATIBLE_DATA_NO;
+ return(COMPATIBLE_DATA_NO);
}
- return COMPATIBLE_DATA_YES;
+ /* Specifying KEY_BLOCK_SIZE requests a rebuild of the table. */
+ if (info->used_fields & HA_CREATE_USED_KEY_BLOCK_SIZE) {
+ return(COMPATIBLE_DATA_NO);
+ }
+
+ return(COMPATIBLE_DATA_YES);
+}
+
+/************************************************************//**
+Validate the file format name and return its corresponding id.
+@return valid file format id */
+static
+uint
+innobase_file_format_name_lookup(
+/*=============================*/
+ const char* format_name) /*!< in: pointer to file format name */
+{
+ char* endp;
+ uint format_id;
+
+ ut_a(format_name != NULL);
+
+ /* The format name can contain the format id itself instead of
+ the name and we check for that. */
+ format_id = (uint) strtoul(format_name, &endp, 10);
+
+ /* Check for valid parse. */
+ if (*endp == '\0' && *format_name != '\0') {
+
+ if (format_id <= DICT_TF_FORMAT_MAX) {
+
+ return(format_id);
+ }
+ } else {
+
+ for (format_id = 0; format_id <= DICT_TF_FORMAT_MAX;
+ format_id++) {
+ const char* name;
+
+ name = trx_sys_file_format_id_to_name(format_id);
+
+ if (!innobase_strcasecmp(format_name, name)) {
+
+ return(format_id);
+ }
+ }
+ }
+
+ return(DICT_TF_FORMAT_MAX + 1);
+}
+
+/************************************************************//**
+Validate the file format check value, is it one of "on" or "off",
+as a side effect it sets the srv_check_file_format_at_startup variable.
+@return true if config value one of "on" or "off" */
+static
+bool
+innobase_file_format_check_on_off(
+/*==============================*/
+ const char* format_check) /*!< in: parameter value */
+{
+ bool ret = true;
+
+ if (!innobase_strcasecmp(format_check, "off")) {
+
+ /* Set the value to disable checking. */
+ srv_check_file_format_at_startup = DICT_TF_FORMAT_MAX + 1;
+
+ } else if (!innobase_strcasecmp(format_check, "on")) {
+
+ /* Set the value to the lowest supported format. */
+ srv_check_file_format_at_startup = DICT_TF_FORMAT_51;
+ } else {
+ ret = FALSE;
+ }
+
+ return(ret);
+}
+
+/************************************************************//**
+Validate the file format check config parameters, as a side effect it
+sets the srv_check_file_format_at_startup variable.
+@return true if valid config value */
+static
+bool
+innobase_file_format_check_validate(
+/*================================*/
+ const char* format_check) /*!< in: parameter value */
+{
+ uint format_id;
+ bool ret = true;
+
+ format_id = innobase_file_format_name_lookup(format_check);
+
+ if (format_id < DICT_TF_FORMAT_MAX + 1) {
+ srv_check_file_format_at_startup = format_id;
+ } else {
+ ret = false;
+ }
+
+ return(ret);
+}
+
+/*************************************************************//**
+Check if it is a valid file format. This function is registered as
+a callback with MySQL.
+@return 0 for valid file format */
+static
+int
+innodb_file_format_name_validate(
+/*=============================*/
+ THD* thd, /*!< in: thread handle */
+ struct st_mysql_sys_var* var, /*!< in: pointer to system
+ variable */
+ void* save, /*!< out: immediate result
+ for update function */
+ struct st_mysql_value* value) /*!< in: incoming string */
+{
+ const char* file_format_input;
+ char buff[STRING_BUFFER_USUAL_SIZE];
+ int len = sizeof(buff);
+
+ ut_a(save != NULL);
+ ut_a(value != NULL);
+
+ file_format_input = value->val_str(value, buff, &len);
+
+ if (file_format_input != NULL) {
+ uint format_id;
+
+ format_id = innobase_file_format_name_lookup(
+ file_format_input);
+
+ if (format_id <= DICT_TF_FORMAT_MAX) {
+
+ *static_cast(save) = file_format_input;
+ return(0);
+ }
+ }
+
+ *static_cast(save) = NULL;
+ return(1);
+}
+
+/****************************************************************//**
+Update the system variable innodb_file_format using the "saved"
+value. This function is registered as a callback with MySQL. */
+static
+void
+innodb_file_format_name_update(
+/*===========================*/
+ THD* thd, /*!< in: thread handle */
+ struct st_mysql_sys_var* var, /*!< in: pointer to
+ system variable */
+ void* var_ptr, /*!< out: where the
+ formal string goes */
+ const void* save) /*!< in: immediate result
+ from check function */
+{
+ const char* format_name;
+
+ ut_a(var_ptr != NULL);
+ ut_a(save != NULL);
+
+ format_name = *static_cast(save);
+
+ if (format_name) {
+ uint format_id;
+
+ format_id = innobase_file_format_name_lookup(format_name);
+
+ if (format_id <= DICT_TF_FORMAT_MAX) {
+ srv_file_format = format_id;
+ }
+ }
+
+ *static_cast(var_ptr)
+ = trx_sys_file_format_id_to_name(srv_file_format);
+}
+
+/*************************************************************//**
+Check if valid argument to innodb_file_format_check. This
+function is registered as a callback with MySQL.
+@return 0 for valid file format */
+static
+int
+innodb_file_format_check_validate(
+/*==============================*/
+ THD* thd, /*!< in: thread handle */
+ struct st_mysql_sys_var* var, /*!< in: pointer to system
+ variable */
+ void* save, /*!< out: immediate result
+ for update function */
+ struct st_mysql_value* value) /*!< in: incoming string */
+{
+ const char* file_format_input;
+ char buff[STRING_BUFFER_USUAL_SIZE];
+ int len = sizeof(buff);
+
+ ut_a(save != NULL);
+ ut_a(value != NULL);
+
+ file_format_input = value->val_str(value, buff, &len);
+
+ if (file_format_input != NULL) {
+
+ /* Check if user set on/off, we want to print a suitable
+ message if they did so. */
+
+ if (innobase_file_format_check_on_off(file_format_input)) {
+ sql_print_warning(
+ "InnoDB: invalid innodb_file_format_check "
+ "value; on/off can only be set at startup or "
+ "in the configuration file");
+ } else if (innobase_file_format_check_validate(
+ file_format_input)) {
+
+ *static_cast(save) = file_format_input;
+
+ return(0);
+
+ } else {
+ sql_print_warning(
+ "InnoDB: invalid innodb_file_format_check "
+ "value; can be any format up to %s "
+ "or its equivalent numeric id",
+ trx_sys_file_format_id_to_name(
+ DICT_TF_FORMAT_MAX));
+ }
+ }
+
+ *static_cast(save) = NULL;
+ return(1);
+}
+
+/****************************************************************//**
+Update the system variable innodb_file_format_check using the "saved"
+value. This function is registered as a callback with MySQL. */
+static
+void
+innodb_file_format_check_update(
+/*============================*/
+ THD* thd, /*!< in: thread handle */
+ struct st_mysql_sys_var* var, /*!< in: pointer to
+ system variable */
+ void* var_ptr, /*!< out: where the
+ formal string goes */
+ const void* save) /*!< in: immediate result
+ from check function */
+{
+ const char* format_name_in;
+ const char** format_name_out;
+ uint format_id;
+
+ ut_a(save != NULL);
+ ut_a(var_ptr != NULL);
+
+ format_name_in = *static_cast(save);
+
+ if (!format_name_in) {
+
+ return;
+ }
+
+ format_id = innobase_file_format_name_lookup(format_name_in);
+
+ if (format_id > DICT_TF_FORMAT_MAX) {
+ /* DEFAULT is "on", which is invalid at runtime. */
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_WRONG_ARGUMENTS,
+ "Ignoring SET innodb_file_format=%s",
+ format_name_in);
+ return;
+ }
+
+ format_name_out = static_cast(var_ptr);
+
+ /* Update the max format id in the system tablespace. */
+ if (trx_sys_file_format_max_set(format_id, format_name_out)) {
+ ut_print_timestamp(stderr);
+ fprintf(stderr,
+ " [Info] InnoDB: the file format in the system "
+ "tablespace is now set to %s.\n", *format_name_out);
+ }
+}
+
+/****************************************************************//**
+Update the system variable innodb_adaptive_hash_index using the "saved"
+value. This function is registered as a callback with MySQL. */
+static
+void
+innodb_adaptive_hash_index_update(
+/*==============================*/
+ THD* thd, /*!< in: thread handle */
+ struct st_mysql_sys_var* var, /*!< in: pointer to
+ system variable */
+ void* var_ptr, /*!< out: where the
+ formal string goes */
+ const void* save) /*!< in: immediate result
+ from check function */
+{
+ if (*(my_bool*) save) {
+ btr_search_enable();
+ } else {
+ btr_search_disable();
+ }
+}
+
+/*************************************************************//**
+Check if it is a valid value of innodb_change_buffering. This function is
+registered as a callback with MySQL.
+@return 0 for valid innodb_change_buffering */
+static
+int
+innodb_change_buffering_validate(
+/*=============================*/
+ THD* thd, /*!< in: thread handle */
+ struct st_mysql_sys_var* var, /*!< in: pointer to system
+ variable */
+ void* save, /*!< out: immediate result
+ for update function */
+ struct st_mysql_value* value) /*!< in: incoming string */
+{
+ const char* change_buffering_input;
+ char buff[STRING_BUFFER_USUAL_SIZE];
+ int len = sizeof(buff);
+
+ ut_a(save != NULL);
+ ut_a(value != NULL);
+
+ change_buffering_input = value->val_str(value, buff, &len);
+
+ if (change_buffering_input != NULL) {
+ ulint use;
+
+ for (use = 0; use < UT_ARR_SIZE(innobase_change_buffering_values);
+ use++) {
+ if (!innobase_strcasecmp(
+ change_buffering_input,
+ innobase_change_buffering_values[use])) {
+ *(ibuf_use_t*) save = (ibuf_use_t) use;
+ return(0);
+ }
+ }
+ }
+
+ return(1);
+}
+
+/****************************************************************//**
+Update the system variable innodb_change_buffering using the "saved"
+value. This function is registered as a callback with MySQL. */
+static
+void
+innodb_change_buffering_update(
+/*===========================*/
+ THD* thd, /*!< in: thread handle */
+ struct st_mysql_sys_var* var, /*!< in: pointer to
+ system variable */
+ void* var_ptr, /*!< out: where the
+ formal string goes */
+ const void* save) /*!< in: immediate result
+ from check function */
+{
+ ut_a(var_ptr != NULL);
+ ut_a(save != NULL);
+ ut_a((*(ibuf_use_t*) save) < IBUF_USE_COUNT);
+
+ ibuf_use = *(const ibuf_use_t*) save;
+
+ *(const char**) var_ptr = innobase_change_buffering_values[ibuf_use];
}
static int show_innodb_vars(THD *thd, SHOW_VAR *var, char *buff)
@@ -8246,15 +9711,10 @@ static MYSQL_SYSVAR_BOOL(doublewrite, innobase_use_doublewrite,
"Disable with --skip-innodb-doublewrite.",
NULL, NULL, TRUE);
-static MYSQL_SYSVAR_BOOL(extra_dirty_writes, innobase_extra_dirty_writes,
- PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY,
- "Flush dirty buffer pages when dirty max pct is not exceeded",
- NULL, NULL, TRUE);
-
-static MYSQL_SYSVAR_LONG(io_capacity, innobase_io_capacity,
- PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
+static MYSQL_SYSVAR_ULONG(io_capacity, srv_io_capacity,
+ PLUGIN_VAR_RQCMDARG,
"Number of IOPs the server can do. Tunes the background IO rate",
- NULL, NULL, (long)200, (long)100, LONG_MAX, (long)0);
+ NULL, NULL, 200, 100, ~0L, 0);
static MYSQL_SYSVAR_ULONG(fast_shutdown, innobase_fast_shutdown,
PLUGIN_VAR_OPCMDARG,
@@ -8266,21 +9726,32 @@ static MYSQL_SYSVAR_ULONG(fast_shutdown, innobase_fast_shutdown,
*/
IF_NETWARE("", " or 2 (fastest - crash-like)")
".",
- NULL, NULL, (unsigned long)1, (unsigned long)0,
- (unsigned long)IF_NETWARE(1,2), (unsigned long)0);
+ NULL, NULL, 1, 0, IF_NETWARE(1,2), 0);
-static MYSQL_SYSVAR_BOOL(file_per_table, innobase_file_per_table,
- PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY,
+static MYSQL_SYSVAR_BOOL(file_per_table, srv_file_per_table,
+ PLUGIN_VAR_NOCMDARG,
"Stores each InnoDB table to an .ibd file in the database dir.",
NULL, NULL, FALSE);
+static MYSQL_SYSVAR_STR(file_format, innobase_file_format_name,
+ PLUGIN_VAR_RQCMDARG,
+ "File format to use for new tables in .ibd files.",
+ innodb_file_format_name_validate,
+ innodb_file_format_name_update, "Antelope");
+
+static MYSQL_SYSVAR_STR(file_format_check, innobase_file_format_check,
+ PLUGIN_VAR_OPCMDARG,
+ "The highest file format in the tablespace.",
+ innodb_file_format_check_validate,
+ innodb_file_format_check_update,
+ "on");
+
static MYSQL_SYSVAR_ULONG(flush_log_at_trx_commit, srv_flush_log_at_trx_commit,
PLUGIN_VAR_OPCMDARG,
"Set to 0 (write and flush once per second),"
" 1 (write and flush at each commit)"
" or 2 (write at commit, flush once per second).",
- NULL, NULL, (unsigned long)1, (unsigned long)0, (unsigned long)2,
- (unsigned long)0);
+ NULL, NULL, 1, 0, 2, 0);
static MYSQL_SYSVAR_STR(flush_method, innobase_unix_file_flush_method,
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
@@ -8308,14 +9779,17 @@ static MYSQL_SYSVAR_STR(log_group_home_dir, innobase_log_group_home_dir,
static MYSQL_SYSVAR_ULONG(max_dirty_pages_pct, srv_max_buf_pool_modified_pct,
PLUGIN_VAR_RQCMDARG,
"Percentage of dirty pages allowed in bufferpool.",
- NULL, NULL, (unsigned long)75, (unsigned long)0, (unsigned long)99,
- (unsigned long)0);
+ NULL, NULL, 75, 0, 99, 0);
+
+static MYSQL_SYSVAR_BOOL(adaptive_flushing, srv_adaptive_flushing,
+ PLUGIN_VAR_NOCMDARG,
+ "Attempt flushing dirty pages to avoid IO bursts at checkpoints.",
+ NULL, NULL, TRUE);
static MYSQL_SYSVAR_ULONG(max_purge_lag, srv_max_purge_lag,
PLUGIN_VAR_RQCMDARG,
"Desired maximum length of the purge queue (0 = no limit)",
- NULL, NULL, (unsigned long)0, (unsigned long)0, (unsigned long)~0L,
- (unsigned long)0);
+ NULL, NULL, 0, 0, ~0L, 0);
static MYSQL_SYSVAR_BOOL(rollback_on_timeout, innobase_rollback_on_timeout,
PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_READONLY,
@@ -8332,123 +9806,112 @@ static MYSQL_SYSVAR_BOOL(stats_on_metadata, innobase_stats_on_metadata,
"Enable statistics gathering for metadata commands such as SHOW TABLE STATUS (on by default)",
NULL, NULL, TRUE);
-static MYSQL_SYSVAR_BOOL(use_legacy_cardinality_algorithm,
- srv_use_legacy_cardinality_algorithm,
- PLUGIN_VAR_OPCMDARG,
- "Use legacy algorithm for picking random pages during index cardinality "
- "estimation. Disable this to use a better algorithm, but note that your "
- "query plans may change (enabled by default).",
- NULL, NULL, TRUE);
+static MYSQL_SYSVAR_ULONGLONG(stats_sample_pages, srv_stats_sample_pages,
+ PLUGIN_VAR_RQCMDARG,
+ "The number of index pages to sample when calculating statistics (default 8)",
+ NULL, NULL, 8, 1, ~0ULL, 0);
-static MYSQL_SYSVAR_BOOL(adaptive_hash_index, innobase_adaptive_hash_index,
- PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_READONLY,
+static MYSQL_SYSVAR_BOOL(adaptive_hash_index, btr_search_enabled,
+ PLUGIN_VAR_OPCMDARG,
"Enable InnoDB adaptive hash index (enabled by default). "
"Disable with --skip-innodb-adaptive-hash-index.",
- NULL, NULL, TRUE);
+ NULL, innodb_adaptive_hash_index_update, TRUE);
+
+static MYSQL_SYSVAR_ULONG(replication_delay, srv_replication_delay,
+ PLUGIN_VAR_RQCMDARG,
+ "Replication thread delay (ms) on the slave server if "
+ "innodb_thread_concurrency is reached (0 by default)",
+ NULL, NULL, 0, 0, ~0UL, 0);
static MYSQL_SYSVAR_LONG(additional_mem_pool_size, innobase_additional_mem_pool_size,
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
"Size of a memory pool InnoDB uses to store data dictionary information and other internal data structures.",
- NULL, NULL, (long)8*1024*1024L, (long)2*1024*1024L, LONG_MAX, (long)1024);
+ NULL, NULL, 8*1024*1024L, 512*1024L, LONG_MAX, 1024);
static MYSQL_SYSVAR_ULONG(autoextend_increment, srv_auto_extend_increment,
PLUGIN_VAR_RQCMDARG,
"Data file autoextend increment in megabytes",
- NULL, NULL, (unsigned long)64L, (unsigned long)1L, (unsigned long)1000L,
- (unsigned long)0);
+ NULL, NULL, 8L, 1L, 1000L, 0);
static MYSQL_SYSVAR_LONGLONG(buffer_pool_size, innobase_buffer_pool_size,
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
"The size of the memory buffer InnoDB uses to cache data and indexes of its tables.",
- NULL, NULL, (long long)1024*1024*1024L, (long long)64*1024*1024L,
- LONGLONG_MAX, (long long)1024*1024L);
+ NULL, NULL, 128*1024*1024L, 5*1024*1024L, LONGLONG_MAX, 1024*1024L);
-static MYSQL_SYSVAR_ULONG(commit_concurrency, srv_commit_concurrency,
+static MYSQL_SYSVAR_ULONG(commit_concurrency, innobase_commit_concurrency,
PLUGIN_VAR_RQCMDARG,
"Helps in performance tuning in heavily concurrent environments.",
- NULL, NULL, (unsigned long)0, (unsigned long)0, (unsigned long)1000,
- (unsigned long)0);
+ innobase_commit_concurrency_validate, NULL, 0, 0, 1000, 0);
static MYSQL_SYSVAR_ULONG(concurrency_tickets, srv_n_free_tickets_to_enter,
PLUGIN_VAR_RQCMDARG,
"Number of times a thread is allowed to enter InnoDB within the same SQL query after it has once got the ticket",
- NULL, NULL, (unsigned long)500L, (unsigned long)1L, (unsigned long)~0L,
- (unsigned long)0);
+ NULL, NULL, 500L, 1L, ~0L, 0);
-static MYSQL_SYSVAR_LONG(write_io_threads, innobase_write_io_threads,
+static MYSQL_SYSVAR_LONG(file_io_threads, innobase_file_io_threads,
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
- "Number of write I/O threads in InnoDB.",
- NULL, NULL, (long)8, (long)1, (long)64, (long)0);
+ "Number of file I/O threads in InnoDB.",
+ NULL, NULL, 4, 4, 64, 0);
-static MYSQL_SYSVAR_LONG(read_io_threads, innobase_read_io_threads,
+static MYSQL_SYSVAR_ULONG(read_io_threads, innobase_read_io_threads,
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
- "Number of read I/O threads in InnoDB.",
- NULL, NULL, (long)8, (long)1, (long)64, (long)0);
+ "Number of background read I/O threads in InnoDB.",
+ NULL, NULL, 4, 1, 64, 0);
-static MYSQL_SYSVAR_LONG(max_merged_io, innobase_max_merged_io,
+static MYSQL_SYSVAR_ULONG(write_io_threads, innobase_write_io_threads,
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
- "Max number of adjacent IO requests to merge in InnoDB.",
- NULL, NULL, (long)64, (long)1, (long)64, (long)0);
+ "Number of background write I/O threads in InnoDB.",
+ NULL, NULL, 4, 1, 64, 0);
static MYSQL_SYSVAR_LONG(force_recovery, innobase_force_recovery,
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
"Helps to save your data in case the disk image of the database becomes corrupt.",
- NULL, NULL, (long)0, (long)0, (long)6, (long)0);
-
-static MYSQL_SYSVAR_LONG(lock_wait_timeout, innobase_lock_wait_timeout,
- PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
- "Timeout in seconds an InnoDB transaction may wait for a lock before being rolled back.",
- NULL, NULL, (long)50, (long)1, (long)(1024*1024*1024), (long)0);
+ NULL, NULL, 0, 0, 6, 0);
static MYSQL_SYSVAR_LONG(log_buffer_size, innobase_log_buffer_size,
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
"The size of the buffer which InnoDB uses to write log to the log files on disk.",
- NULL, NULL, (long)16*1024*1024L, (long)2*1024*1024L, LONG_MAX, (long)1024);
+ NULL, NULL, 8*1024*1024L, 256*1024L, LONG_MAX, 1024);
static MYSQL_SYSVAR_LONGLONG(log_file_size, innobase_log_file_size,
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
"Size of each log file in a log group.",
- NULL, NULL, (long long)128*1024*1024L, (long long)32*1024*1024L,
- LONGLONG_MAX, (long long)1024*1024L);
+ NULL, NULL, 5*1024*1024L, 1*1024*1024L, LONGLONG_MAX, 1024*1024L);
static MYSQL_SYSVAR_LONG(log_files_in_group, innobase_log_files_in_group,
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
"Number of log files in the log group. InnoDB writes to the files in a circular fashion. Value 3 is recommended here.",
- NULL, NULL, (long)3, (long)2, (long)100, (long)0);
+ NULL, NULL, 2, 2, 100, 0);
static MYSQL_SYSVAR_LONG(mirrored_log_groups, innobase_mirrored_log_groups,
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
"Number of identical copies of log groups we keep for the database. Currently this should be set to 1.",
- NULL, NULL, (long)1, (long)1, (long)10, (long)0);
+ NULL, NULL, 1, 1, 10, 0);
static MYSQL_SYSVAR_LONG(open_files, innobase_open_files,
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
"How many files at the maximum InnoDB keeps open at the same time.",
- NULL, NULL, (long)300L, (long)10L, LONG_MAX, (long)0L);
+ NULL, NULL, 300L, 10L, LONG_MAX, 0);
static MYSQL_SYSVAR_ULONG(sync_spin_loops, srv_n_spin_wait_rounds,
PLUGIN_VAR_RQCMDARG,
- "Count of spin-loop rounds in InnoDB mutexes",
- NULL, NULL, (unsigned long)20L, (unsigned long)0L, (unsigned long)~0L,
- (unsigned long)0L);
+ "Count of spin-loop rounds in InnoDB mutexes (30 by default)",
+ NULL, NULL, 30L, 0L, ~0L, 0);
-static MYSQL_SYSVAR_BOOL(thread_concurrency_timer_based,
- innobase_thread_concurrency_timer_based,
- PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
- "Use InnoDB timer based concurrency throttling. ",
- NULL, NULL, TRUE);
+static MYSQL_SYSVAR_ULONG(spin_wait_delay, srv_spin_wait_delay,
+ PLUGIN_VAR_OPCMDARG,
+ "Maximum delay between polling for a spin lock (6 by default)",
+ NULL, NULL, 6L, 0L, ~0L, 0);
static MYSQL_SYSVAR_ULONG(thread_concurrency, srv_thread_concurrency,
PLUGIN_VAR_RQCMDARG,
"Helps in performance tuning in heavily concurrent environments. Sets the maximum number of threads allowed inside InnoDB. Value 0 will disable the thread throttling.",
- NULL, NULL, (unsigned long)0, (unsigned long)0, (unsigned long)1000,
- (unsigned long)0);
+ NULL, NULL, 0, 0, 1000, 0);
static MYSQL_SYSVAR_ULONG(thread_sleep_delay, srv_thread_sleep_delay,
PLUGIN_VAR_RQCMDARG,
"Time of innodb thread sleeping before joining InnoDB queue (usec). Value 0 disable a sleep",
- NULL, NULL, (unsigned long)10000L, (unsigned long)0L, (unsigned long)~0L,
- (unsigned long)0);
+ NULL, NULL, 10000L, 0L, ~0L, 0);
static MYSQL_SYSVAR_STR(data_file_path, innobase_data_file_path,
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
@@ -8465,7 +9928,29 @@ static MYSQL_SYSVAR_LONG(autoinc_lock_mode, innobase_autoinc_lock_mode,
NULL, NULL,
AUTOINC_NEW_STYLE_LOCKING, /* Default setting */
AUTOINC_OLD_STYLE_LOCKING, /* Minimum value */
- AUTOINC_NO_LOCKING, (long)0); /* Maximum value */
+ AUTOINC_NO_LOCKING, 0); /* Maximum value */
+
+static MYSQL_SYSVAR_STR(version, innodb_version_str,
+ PLUGIN_VAR_NOCMDOPT | PLUGIN_VAR_READONLY,
+ "InnoDB version", NULL, NULL, INNODB_VERSION_STR);
+
+static MYSQL_SYSVAR_BOOL(use_sys_malloc, srv_use_sys_malloc,
+ PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY,
+ "Use OS memory allocator instead of InnoDB's internal memory allocator",
+ NULL, NULL, TRUE);
+
+static MYSQL_SYSVAR_STR(change_buffering, innobase_change_buffering,
+ PLUGIN_VAR_RQCMDARG,
+ "Buffer changes to reduce random access: "
+ "OFF, ON, inserting, deleting, changing, or purging.",
+ innodb_change_buffering_validate,
+ innodb_change_buffering_update, NULL);
+
+static MYSQL_SYSVAR_ULONG(read_ahead_threshold, srv_read_ahead_threshold,
+ PLUGIN_VAR_RQCMDARG,
+ "Number of pages that must be accessed sequentially for InnoDB to"
+ "trigger a readahead.",
+ NULL, NULL, 56, 0, 64, 0);
static struct st_mysql_sys_var* innobase_system_variables[]= {
MYSQL_SYSVAR(additional_mem_pool_size),
@@ -8478,11 +9963,12 @@ static struct st_mysql_sys_var* innobase_system_variables[]= {
MYSQL_SYSVAR(data_home_dir),
MYSQL_SYSVAR(doublewrite),
MYSQL_SYSVAR(fast_shutdown),
+ MYSQL_SYSVAR(file_io_threads),
MYSQL_SYSVAR(read_io_threads),
MYSQL_SYSVAR(write_io_threads),
- MYSQL_SYSVAR(max_merged_io),
- MYSQL_SYSVAR(thread_concurrency_timer_based),
MYSQL_SYSVAR(file_per_table),
+ MYSQL_SYSVAR(file_format),
+ MYSQL_SYSVAR(file_format_check),
MYSQL_SYSVAR(flush_log_at_trx_commit),
MYSQL_SYSVAR(flush_method),
MYSQL_SYSVAR(force_recovery),
@@ -8497,38 +9983,192 @@ static struct st_mysql_sys_var* innobase_system_variables[]= {
MYSQL_SYSVAR(log_files_in_group),
MYSQL_SYSVAR(log_group_home_dir),
MYSQL_SYSVAR(max_dirty_pages_pct),
+ MYSQL_SYSVAR(adaptive_flushing),
MYSQL_SYSVAR(max_purge_lag),
MYSQL_SYSVAR(mirrored_log_groups),
MYSQL_SYSVAR(open_files),
MYSQL_SYSVAR(rollback_on_timeout),
MYSQL_SYSVAR(stats_on_metadata),
- MYSQL_SYSVAR(use_legacy_cardinality_algorithm),
+ MYSQL_SYSVAR(stats_sample_pages),
MYSQL_SYSVAR(adaptive_hash_index),
+ MYSQL_SYSVAR(replication_delay),
MYSQL_SYSVAR(status_file),
+ MYSQL_SYSVAR(strict_mode),
MYSQL_SYSVAR(support_xa),
MYSQL_SYSVAR(sync_spin_loops),
+ MYSQL_SYSVAR(spin_wait_delay),
MYSQL_SYSVAR(table_locks),
MYSQL_SYSVAR(thread_concurrency),
MYSQL_SYSVAR(thread_sleep_delay),
MYSQL_SYSVAR(autoinc_lock_mode),
- MYSQL_SYSVAR(extra_dirty_writes),
+ MYSQL_SYSVAR(version),
+ MYSQL_SYSVAR(use_sys_malloc),
+ MYSQL_SYSVAR(change_buffering),
+ MYSQL_SYSVAR(read_ahead_threshold),
MYSQL_SYSVAR(io_capacity),
NULL
};
-mysql_declare_plugin(innobase)
+mysql_declare_plugin(innodb_plugin)
{
MYSQL_STORAGE_ENGINE_PLUGIN,
&innobase_storage_engine,
innobase_hton_name,
- "Innobase OY",
+ "Innobase Oy",
"Supports transactions, row-level locking, and foreign keys",
PLUGIN_LICENSE_GPL,
innobase_init, /* Plugin Init */
NULL, /* Plugin Deinit */
- 0x0100 /* 1.0 */,
+ INNODB_VERSION_SHORT,
innodb_status_variables_export,/* status variables */
innobase_system_variables, /* system variables */
NULL /* reserved */
-}
+},
+i_s_innodb_trx,
+i_s_innodb_locks,
+i_s_innodb_lock_waits,
+i_s_innodb_cmp,
+i_s_innodb_cmp_reset,
+i_s_innodb_cmpmem,
+i_s_innodb_cmpmem_reset
mysql_declare_plugin_end;
+
+/** @brief Initialize the default value of innodb_commit_concurrency.
+
+Once InnoDB is running, the innodb_commit_concurrency must not change
+from zero to nonzero. (Bug #42101)
+
+The initial default value is 0, and without this extra initialization,
+SET GLOBAL innodb_commit_concurrency=DEFAULT would set the parameter
+to 0, even if it was initially set to nonzero at the command line
+or configuration file. */
+static
+void
+innobase_commit_concurrency_init_default(void)
+/*==========================================*/
+{
+ MYSQL_SYSVAR_NAME(commit_concurrency).def_val
+ = innobase_commit_concurrency;
+}
+
+#ifdef UNIV_COMPILE_TEST_FUNCS
+
+typedef struct innobase_convert_name_test_struct {
+ char* buf;
+ ulint buflen;
+ const char* id;
+ ulint idlen;
+ void* thd;
+ ibool file_id;
+
+ const char* expected;
+} innobase_convert_name_test_t;
+
+void
+test_innobase_convert_name()
+{
+ char buf[1024];
+ ulint i;
+
+ innobase_convert_name_test_t test_input[] = {
+ {buf, sizeof(buf), "abcd", 4, NULL, TRUE, "\"abcd\""},
+ {buf, 7, "abcd", 4, NULL, TRUE, "\"abcd\""},
+ {buf, 6, "abcd", 4, NULL, TRUE, "\"abcd\""},
+ {buf, 5, "abcd", 4, NULL, TRUE, "\"abc\""},
+ {buf, 4, "abcd", 4, NULL, TRUE, "\"ab\""},
+
+ {buf, sizeof(buf), "ab@0060cd", 9, NULL, TRUE, "\"ab`cd\""},
+ {buf, 9, "ab@0060cd", 9, NULL, TRUE, "\"ab`cd\""},
+ {buf, 8, "ab@0060cd", 9, NULL, TRUE, "\"ab`cd\""},
+ {buf, 7, "ab@0060cd", 9, NULL, TRUE, "\"ab`cd\""},
+ {buf, 6, "ab@0060cd", 9, NULL, TRUE, "\"ab`c\""},
+ {buf, 5, "ab@0060cd", 9, NULL, TRUE, "\"ab`\""},
+ {buf, 4, "ab@0060cd", 9, NULL, TRUE, "\"ab\""},
+
+ {buf, sizeof(buf), "ab\"cd", 5, NULL, TRUE,
+ "\"#mysql50#ab\"\"cd\""},
+ {buf, 17, "ab\"cd", 5, NULL, TRUE,
+ "\"#mysql50#ab\"\"cd\""},
+ {buf, 16, "ab\"cd", 5, NULL, TRUE,
+ "\"#mysql50#ab\"\"c\""},
+ {buf, 15, "ab\"cd", 5, NULL, TRUE,
+ "\"#mysql50#ab\"\"\""},
+ {buf, 14, "ab\"cd", 5, NULL, TRUE,
+ "\"#mysql50#ab\""},
+ {buf, 13, "ab\"cd", 5, NULL, TRUE,
+ "\"#mysql50#ab\""},
+ {buf, 12, "ab\"cd", 5, NULL, TRUE,
+ "\"#mysql50#a\""},
+ {buf, 11, "ab\"cd", 5, NULL, TRUE,
+ "\"#mysql50#\""},
+ {buf, 10, "ab\"cd", 5, NULL, TRUE,
+ "\"#mysql50\""},
+
+ {buf, sizeof(buf), "ab/cd", 5, NULL, TRUE, "\"ab\".\"cd\""},
+ {buf, 9, "ab/cd", 5, NULL, TRUE, "\"ab\".\"cd\""},
+ {buf, 8, "ab/cd", 5, NULL, TRUE, "\"ab\".\"c\""},
+ {buf, 7, "ab/cd", 5, NULL, TRUE, "\"ab\".\"\""},
+ {buf, 6, "ab/cd", 5, NULL, TRUE, "\"ab\"."},
+ {buf, 5, "ab/cd", 5, NULL, TRUE, "\"ab\"."},
+ {buf, 4, "ab/cd", 5, NULL, TRUE, "\"ab\""},
+ {buf, 3, "ab/cd", 5, NULL, TRUE, "\"a\""},
+ {buf, 2, "ab/cd", 5, NULL, TRUE, "\"\""},
+ /* XXX probably "" is a better result in this case
+ {buf, 1, "ab/cd", 5, NULL, TRUE, "."},
+ */
+ {buf, 0, "ab/cd", 5, NULL, TRUE, ""},
+ };
+
+ for (i = 0; i < sizeof(test_input) / sizeof(test_input[0]); i++) {
+
+ char* end;
+ ibool ok = TRUE;
+ size_t res_len;
+
+ fprintf(stderr, "TESTING %lu, %s, %lu, %s\n",
+ test_input[i].buflen,
+ test_input[i].id,
+ test_input[i].idlen,
+ test_input[i].expected);
+
+ end = innobase_convert_name(
+ test_input[i].buf,
+ test_input[i].buflen,
+ test_input[i].id,
+ test_input[i].idlen,
+ test_input[i].thd,
+ test_input[i].file_id);
+
+ res_len = (size_t) (end - test_input[i].buf);
+
+ if (res_len != strlen(test_input[i].expected)) {
+
+ fprintf(stderr, "unexpected len of the result: %u, "
+ "expected: %u\n", (unsigned) res_len,
+ (unsigned) strlen(test_input[i].expected));
+ ok = FALSE;
+ }
+
+ if (memcmp(test_input[i].buf,
+ test_input[i].expected,
+ strlen(test_input[i].expected)) != 0
+ || !ok) {
+
+ fprintf(stderr, "unexpected result: %.*s, "
+ "expected: %s\n", (int) res_len,
+ test_input[i].buf,
+ test_input[i].expected);
+ ok = FALSE;
+ }
+
+ if (ok) {
+ fprintf(stderr, "OK: res: %.*s\n\n", (int) res_len,
+ buf);
+ } else {
+ fprintf(stderr, "FAILED\n\n");
+ return;
+ }
+ }
+}
+
+#endif /* UNIV_COMPILE_TEST_FUNCS */
diff --git a/storage/innobase/handler/ha_innodb.h b/storage/innodb_plugin/handler/ha_innodb.h
similarity index 64%
rename from storage/innobase/handler/ha_innodb.h
rename to storage/innodb_plugin/handler/ha_innodb.h
index 8ca72ee1a60..cc98003f8ff 100644
--- a/storage/innobase/handler/ha_innodb.h
+++ b/storage/innodb_plugin/handler/ha_innodb.h
@@ -1,17 +1,20 @@
-/* Copyright (C) 2000-2005 MySQL AB && Innobase Oy
+/*****************************************************************************
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; version 2 of the License.
+Copyright (c) 2000, 2009, MySQL AB & Innobase Oy. All Rights Reserved.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; version 2 of the License.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place, Suite 330, Boston, MA 02111-1307 USA
+
+*****************************************************************************/
/*
This file is based on ha_berkeley.h of MySQL distribution
@@ -24,34 +27,43 @@
#pragma interface /* gcc class implementation */
#endif
+/** InnoDB table share */
typedef struct st_innobase_share {
- THR_LOCK lock;
- pthread_mutex_t mutex;
- char *table_name;
- uint table_name_length,use_count;
+ THR_LOCK lock; /*!< MySQL lock protecting
+ this structure */
+ const char* table_name; /*!< InnoDB table name */
+ uint use_count; /*!< reference count,
+ incremented in get_share()
+ and decremented in free_share() */
+ void* table_name_hash;/*!< hash table chain node */
} INNOBASE_SHARE;
+/** InnoDB B-tree index */
struct dict_index_struct;
+/** Prebuilt structures in an Innobase table handle used within MySQL */
struct row_prebuilt_struct;
+/** InnoDB B-tree index */
typedef struct dict_index_struct dict_index_t;
+/** Prebuilt structures in an Innobase table handle used within MySQL */
typedef struct row_prebuilt_struct row_prebuilt_t;
-/* The class defining a handle to an Innodb table */
+/** The class defining a handle to an Innodb table */
class ha_innobase: public handler
{
- row_prebuilt_t* prebuilt; /* prebuilt struct in InnoDB, used
+ row_prebuilt_t* prebuilt; /*!< prebuilt struct in InnoDB, used
to save CPU time with prebuilt data
structures*/
- THD* user_thd; /* the thread handle of the user
+ THD* user_thd; /*!< the thread handle of the user
currently using the handle; this is
set in external_lock function */
THR_LOCK_DATA lock;
- INNOBASE_SHARE *share;
+ INNOBASE_SHARE* share; /*!< information for MySQL
+ table locking */
- uchar* upd_buff; /* buffer used in updates */
- uchar* key_val_buff; /* buffer used in converting
+ uchar* upd_buff; /*!< buffer used in updates */
+ uchar* key_val_buff; /*!< buffer used in converting
search key values from MySQL format
to Innodb format */
ulong upd_and_key_val_buff_len;
@@ -59,62 +71,49 @@ class ha_innobase: public handler
two buffers */
Table_flags int_table_flags;
uint primary_key;
- ulong start_of_scan; /* this is set to 1 when we are
+ ulong start_of_scan; /*!< this is set to 1 when we are
starting a table scan but have not
yet fetched any row, else 0 */
uint last_match_mode;/* match mode of the latest search:
ROW_SEL_EXACT, ROW_SEL_EXACT_PREFIX,
or undefined */
- uint num_write_row; /* number of write_row() calls */
+ uint num_write_row; /*!< number of write_row() calls */
uint store_key_val_for_row(uint keynr, char* buff, uint buff_len,
const uchar* record);
- int update_thd(THD* thd);
+ inline void update_thd(THD* thd);
+ void update_thd();
int change_active_index(uint keynr);
int general_fetch(uchar* buf, uint direction, uint match_mode);
- ulong innobase_lock_autoinc();
+ ulint innobase_lock_autoinc();
ulonglong innobase_peek_autoinc();
- ulong innobase_set_max_autoinc(ulonglong auto_inc);
- ulong innobase_reset_autoinc(ulonglong auto_inc);
- ulong innobase_get_autoinc(ulonglong* value);
- ulong innobase_update_autoinc(ulonglong auto_inc);
- ulong innobase_initialize_autoinc();
+ ulint innobase_set_max_autoinc(ulonglong auto_inc);
+ ulint innobase_reset_autoinc(ulonglong auto_inc);
+ ulint innobase_get_autoinc(ulonglong* value);
+ ulint innobase_update_autoinc(ulonglong auto_inc);
+ ulint innobase_initialize_autoinc();
dict_index_t* innobase_get_index(uint keynr);
ulonglong innobase_get_int_col_max_value(const Field* field);
/* Init values for the class: */
public:
ha_innobase(handlerton *hton, TABLE_SHARE *table_arg);
- ~ha_innobase() {}
+ ~ha_innobase();
/*
Get the row type from the storage engine. If this method returns
ROW_TYPE_NOT_USED, the information in HA_CREATE_INFO should be used.
*/
enum row_type get_row_type() const;
- const char* table_type() const { return("InnoDB");}
- const char *index_type(uint key_number) { return "BTREE"; }
+ const char* table_type() const;
+ const char* index_type(uint key_number);
const char** bas_ext() const;
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);
- }
- uint max_supported_keys() const { return MAX_KEY; }
- /* An InnoDB page must store >= 2 keys;
- a secondary key record must also contain the
- primary key value:
- max key length is therefore set to slightly
- less than 1 / 4 of page size which is 16 kB;
- but currently MySQL does not work with keys
- whose size is > MAX_KEY_LENGTH */
- uint max_supported_key_length() const { return 3500; }
+ ulong index_flags(uint idx, uint part, bool all_parts) const;
+ uint max_supported_keys() const;
+ uint max_supported_key_length() const;
uint max_supported_key_part_length() const;
- const key_map *keys_to_use_for_scanning() { return &key_map_full; }
+ const key_map* keys_to_use_for_scanning();
int open(const char *name, int mode, uint test_if_locked);
int close(void);
@@ -185,7 +184,7 @@ class ha_innobase: public handler
virtual bool get_error_message(int error, String *buf);
- uint8 table_cache_type() { return HA_CACHE_TBL_ASKTRANSACT; }
+ uint8 table_cache_type();
/*
ask handler about permission to cache table during query registration
*/
@@ -195,8 +194,14 @@ class ha_innobase: public handler
ulonglong *engine_data);
static char *get_mysql_bin_log_name();
static ulonglong get_mysql_bin_log_pos();
- bool primary_key_is_clustered() { return true; }
+ bool primary_key_is_clustered();
int cmp_ref(const uchar *ref1, const uchar *ref2);
+ /** Fast index creation (smart ALTER TABLE) @see handler0alter.cc @{ */
+ int add_index(TABLE *table_arg, KEY *key_info, uint num_of_keys);
+ int prepare_drop_index(TABLE *table_arg, uint *key_num,
+ uint num_of_keys);
+ int final_drop_index(TABLE *table_arg);
+ /** @} */
bool check_if_incompatible_data(HA_CREATE_INFO *info,
uint table_changes);
};
@@ -253,3 +258,27 @@ int thd_binlog_format(const MYSQL_THD thd);
*/
void thd_mark_transaction_to_rollback(MYSQL_THD thd, bool all);
}
+
+typedef struct trx_struct trx_t;
+/********************************************************************//**
+@file handler/ha_innodb.h
+Converts an InnoDB error code to a MySQL error code and also tells to MySQL
+about a possible transaction rollback inside InnoDB caused by a lock wait
+timeout or a deadlock.
+@return MySQL error code */
+extern "C"
+int
+convert_error_code_to_mysql(
+/*========================*/
+ int error, /*!< in: InnoDB error code */
+ ulint flags, /*!< in: InnoDB table flags, or 0 */
+ MYSQL_THD thd); /*!< in: user thread handle or NULL */
+
+/*********************************************************************//**
+Allocates an InnoDB transaction for a MySQL handler object.
+@return InnoDB transaction handle */
+extern "C"
+trx_t*
+innobase_trx_allocate(
+/*==================*/
+ MYSQL_THD thd); /*!< in: user thread handle */
diff --git a/storage/innodb_plugin/handler/handler0alter.cc b/storage/innodb_plugin/handler/handler0alter.cc
new file mode 100644
index 00000000000..d1f64a1985c
--- /dev/null
+++ b/storage/innodb_plugin/handler/handler0alter.cc
@@ -0,0 +1,1216 @@
+/*****************************************************************************
+
+Copyright (c) 2005, 2009, Innobase Oy. All Rights Reserved.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; version 2 of the License.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place, Suite 330, Boston, MA 02111-1307 USA
+
+*****************************************************************************/
+
+/**************************************************//**
+@file handler/handler0alter.cc
+Smart ALTER TABLE
+*******************************************************/
+
+#include
+#include
+
+extern "C" {
+#include "log0log.h"
+#include "row0merge.h"
+#include "srv0srv.h"
+#include "trx0trx.h"
+#include "trx0roll.h"
+#include "ha_prototypes.h"
+#include "handler0alter.h"
+}
+
+#include "ha_innodb.h"
+
+/*************************************************************//**
+Copies an InnoDB column to a MySQL field. This function is
+adapted from row_sel_field_store_in_mysql_format(). */
+static
+void
+innobase_col_to_mysql(
+/*==================*/
+ const dict_col_t* col, /*!< in: InnoDB column */
+ const uchar* data, /*!< in: InnoDB column data */
+ ulint len, /*!< in: length of data, in bytes */
+ Field* field) /*!< in/out: MySQL field */
+{
+ uchar* ptr;
+ uchar* dest = field->ptr;
+ ulint flen = field->pack_length();
+
+ switch (col->mtype) {
+ case DATA_INT:
+ ut_ad(len == flen);
+
+ /* Convert integer data from Innobase to little-endian
+ format, sign bit restored to normal */
+
+ for (ptr = dest + len; ptr != dest; ) {
+ *--ptr = *data++;
+ }
+
+ if (!(field->flags & UNSIGNED_FLAG)) {
+ ((byte*) dest)[len - 1] ^= 0x80;
+ }
+
+ break;
+
+ case DATA_VARCHAR:
+ case DATA_VARMYSQL:
+ case DATA_BINARY:
+ field->reset();
+
+ if (field->type() == MYSQL_TYPE_VARCHAR) {
+ /* This is a >= 5.0.3 type true VARCHAR. Store the
+ length of the data to the first byte or the first
+ two bytes of dest. */
+
+ dest = row_mysql_store_true_var_len(
+ dest, len, flen - field->key_length());
+ }
+
+ /* Copy the actual data */
+ memcpy(dest, data, len);
+ break;
+
+ case DATA_BLOB:
+ /* Store a pointer to the BLOB buffer to dest: the BLOB was
+ already copied to the buffer in row_sel_store_mysql_rec */
+
+ row_mysql_store_blob_ref(dest, flen, data, len);
+ break;
+
+#ifdef UNIV_DEBUG
+ case DATA_MYSQL:
+ ut_ad(flen >= len);
+ ut_ad(col->mbmaxlen >= col->mbminlen);
+ ut_ad(col->mbmaxlen > col->mbminlen || flen == len);
+ memcpy(dest, data, len);
+ break;
+
+ default:
+ case DATA_SYS_CHILD:
+ case DATA_SYS:
+ /* These column types should never be shipped to MySQL. */
+ ut_ad(0);
+
+ case DATA_CHAR:
+ case DATA_FIXBINARY:
+ case DATA_FLOAT:
+ case DATA_DOUBLE:
+ case DATA_DECIMAL:
+ /* Above are the valid column types for MySQL data. */
+ ut_ad(flen == len);
+#else /* UNIV_DEBUG */
+ default:
+#endif /* UNIV_DEBUG */
+ memcpy(dest, data, len);
+ }
+}
+
+/*************************************************************//**
+Copies an InnoDB record to table->record[0]. */
+extern "C" UNIV_INTERN
+void
+innobase_rec_to_mysql(
+/*==================*/
+ TABLE* table, /*!< in/out: MySQL table */
+ const rec_t* rec, /*!< in: record */
+ const dict_index_t* index, /*!< in: index */
+ const ulint* offsets) /*!< in: rec_get_offsets(
+ rec, index, ...) */
+{
+ uint n_fields = table->s->fields;
+ uint i;
+
+ ut_ad(n_fields == dict_table_get_n_user_cols(index->table));
+
+ for (i = 0; i < n_fields; i++) {
+ Field* field = table->field[i];
+ ulint ipos;
+ ulint ilen;
+ const uchar* ifield;
+
+ field->reset();
+
+ ipos = dict_index_get_nth_col_pos(index, i);
+
+ if (UNIV_UNLIKELY(ipos == ULINT_UNDEFINED)) {
+null_field:
+ field->set_null();
+ continue;
+ }
+
+ ifield = rec_get_nth_field(rec, offsets, ipos, &ilen);
+
+ /* Assign the NULL flag */
+ if (ilen == UNIV_SQL_NULL) {
+ ut_ad(field->real_maybe_null());
+ goto null_field;
+ }
+
+ field->set_notnull();
+
+ innobase_col_to_mysql(
+ dict_field_get_col(
+ dict_index_get_nth_field(index, ipos)),
+ ifield, ilen, field);
+ }
+}
+
+/*************************************************************//**
+Resets table->record[0]. */
+extern "C" UNIV_INTERN
+void
+innobase_rec_reset(
+/*===============*/
+ TABLE* table) /*!< in/out: MySQL table */
+{
+ uint n_fields = table->s->fields;
+ uint i;
+
+ for (i = 0; i < n_fields; i++) {
+ table->field[i]->set_default();
+ }
+}
+
+/******************************************************************//**
+Removes the filename encoding of a database and table name. */
+static
+void
+innobase_convert_tablename(
+/*=======================*/
+ char* s) /*!< in: identifier; out: decoded identifier */
+{
+ uint errors;
+
+ char* slash = strchr(s, '/');
+
+ if (slash) {
+ char* t;
+ /* Temporarily replace the '/' with NUL. */
+ *slash = 0;
+ /* Convert the database name. */
+ strconvert(&my_charset_filename, s, system_charset_info,
+ s, slash - s + 1, &errors);
+
+ t = s + strlen(s);
+ ut_ad(slash >= t);
+ /* Append a '.' after the database name. */
+ *t++ = '.';
+ slash++;
+ /* Convert the table name. */
+ strconvert(&my_charset_filename, slash, system_charset_info,
+ t, slash - t + strlen(slash), &errors);
+ } else {
+ strconvert(&my_charset_filename, s,
+ system_charset_info, s, strlen(s), &errors);
+ }
+}
+
+/*******************************************************************//**
+This function checks that index keys are sensible.
+@return 0 or error number */
+static
+int
+innobase_check_index_keys(
+/*======================*/
+ const KEY* key_info, /*!< in: Indexes to be created */
+ ulint num_of_keys) /*!< in: Number of indexes to
+ be created */
+{
+ ulint key_num;
+
+ ut_ad(key_info);
+ ut_ad(num_of_keys);
+
+ for (key_num = 0; key_num < num_of_keys; key_num++) {
+ const KEY& key = key_info[key_num];
+
+ /* Check that the same index name does not appear
+ twice in indexes to be created. */
+
+ for (ulint i = 0; i < key_num; i++) {
+ const KEY& key2 = key_info[i];
+
+ if (0 == strcmp(key.name, key2.name)) {
+ sql_print_error("InnoDB: key name `%s` appears"
+ " twice in CREATE INDEX\n",
+ key.name);
+
+ return(ER_WRONG_NAME_FOR_INDEX);
+ }
+ }
+
+ /* Check that MySQL does not try to create a column
+ prefix index field on an inappropriate data type and
+ that the same colum does not appear twice in the index. */
+
+ for (ulint i = 0; i < key.key_parts; i++) {
+ const KEY_PART_INFO& key_part1
+ = key.key_part[i];
+ const Field* field
+ = key_part1.field;
+ ibool is_unsigned;
+
+ switch (get_innobase_type_from_mysql_type(
+ &is_unsigned, field)) {
+ default:
+ break;
+ case DATA_INT:
+ case DATA_FLOAT:
+ case DATA_DOUBLE:
+ case DATA_DECIMAL:
+ if (field->type() == MYSQL_TYPE_VARCHAR) {
+ if (key_part1.length
+ >= field->pack_length()
+ - ((Field_varstring*) field)
+ ->length_bytes) {
+ break;
+ }
+ } else {
+ if (key_part1.length
+ >= field->pack_length()) {
+ break;
+ }
+ }
+
+ sql_print_error("InnoDB: MySQL is trying to"
+ " create a column prefix"
+ " index field on an"
+ " inappropriate data type."
+ " column `%s`,"
+ " index `%s`.\n",
+ field->field_name,
+ key.name);
+ return(ER_WRONG_KEY_COLUMN);
+ }
+
+ for (ulint j = 0; j < i; j++) {
+ const KEY_PART_INFO& key_part2
+ = key.key_part[j];
+
+ if (strcmp(key_part1.field->field_name,
+ key_part2.field->field_name)) {
+ continue;
+ }
+
+ sql_print_error("InnoDB: column `%s`"
+ " is not allowed to occur"
+ " twice in index `%s`.\n",
+ key_part1.field->field_name,
+ key.name);
+ return(ER_WRONG_KEY_COLUMN);
+ }
+ }
+ }
+
+ return(0);
+}
+
+/*******************************************************************//**
+Create index field definition for key part */
+static
+void
+innobase_create_index_field_def(
+/*============================*/
+ KEY_PART_INFO* key_part, /*!< in: MySQL key definition */
+ mem_heap_t* heap, /*!< in: memory heap */
+ merge_index_field_t* index_field) /*!< out: index field
+ definition for key_part */
+{
+ Field* field;
+ ibool is_unsigned;
+ ulint col_type;
+
+ DBUG_ENTER("innobase_create_index_field_def");
+
+ ut_ad(key_part);
+ ut_ad(index_field);
+
+ field = key_part->field;
+ ut_a(field);
+
+ col_type = get_innobase_type_from_mysql_type(&is_unsigned, field);
+
+ if (DATA_BLOB == col_type
+ || (key_part->length < field->pack_length()
+ && field->type() != MYSQL_TYPE_VARCHAR)
+ || (field->type() == MYSQL_TYPE_VARCHAR
+ && key_part->length < field->pack_length()
+ - ((Field_varstring*)field)->length_bytes)) {
+
+ index_field->prefix_len = key_part->length;
+ } else {
+ index_field->prefix_len = 0;
+ }
+
+ index_field->field_name = mem_heap_strdup(heap, field->field_name);
+
+ DBUG_VOID_RETURN;
+}
+
+/*******************************************************************//**
+Create index definition for key */
+static
+void
+innobase_create_index_def(
+/*======================*/
+ KEY* key, /*!< in: key definition */
+ bool new_primary, /*!< in: TRUE=generating
+ a new primary key
+ on the table */
+ bool key_primary, /*!< in: TRUE if this key
+ is a primary key */
+ merge_index_def_t* index, /*!< out: index definition */
+ mem_heap_t* heap) /*!< in: heap where memory
+ is allocated */
+{
+ ulint i;
+ ulint len;
+ ulint n_fields = key->key_parts;
+ char* index_name;
+
+ DBUG_ENTER("innobase_create_index_def");
+
+ index->fields = (merge_index_field_t*) mem_heap_alloc(
+ heap, n_fields * sizeof *index->fields);
+
+ index->ind_type = 0;
+ index->n_fields = n_fields;
+ len = strlen(key->name) + 1;
+ index->name = index_name = (char*) mem_heap_alloc(heap,
+ len + !new_primary);
+
+ if (UNIV_LIKELY(!new_primary)) {
+ *index_name++ = TEMP_INDEX_PREFIX;
+ }
+
+ memcpy(index_name, key->name, len);
+
+ if (key->flags & HA_NOSAME) {
+ index->ind_type |= DICT_UNIQUE;
+ }
+
+ if (key_primary) {
+ index->ind_type |= DICT_CLUSTERED;
+ }
+
+ for (i = 0; i < n_fields; i++) {
+ innobase_create_index_field_def(&key->key_part[i], heap,
+ &index->fields[i]);
+ }
+
+ DBUG_VOID_RETURN;
+}
+
+/*******************************************************************//**
+Copy index field definition */
+static
+void
+innobase_copy_index_field_def(
+/*==========================*/
+ const dict_field_t* field, /*!< in: definition to copy */
+ merge_index_field_t* index_field) /*!< out: copied definition */
+{
+ DBUG_ENTER("innobase_copy_index_field_def");
+ DBUG_ASSERT(field != NULL);
+ DBUG_ASSERT(index_field != NULL);
+
+ index_field->field_name = field->name;
+ index_field->prefix_len = field->prefix_len;
+
+ DBUG_VOID_RETURN;
+}
+
+/*******************************************************************//**
+Copy index definition for the index */
+static
+void
+innobase_copy_index_def(
+/*====================*/
+ const dict_index_t* index, /*!< in: index definition to copy */
+ merge_index_def_t* new_index,/*!< out: Index definition */
+ mem_heap_t* heap) /*!< in: heap where allocated */
+{
+ ulint n_fields;
+ ulint i;
+
+ DBUG_ENTER("innobase_copy_index_def");
+
+ /* Note that we take only those fields that user defined to be
+ in the index. In the internal representation more colums were
+ added and those colums are not copied .*/
+
+ n_fields = index->n_user_defined_cols;
+
+ new_index->fields = (merge_index_field_t*) mem_heap_alloc(
+ heap, n_fields * sizeof *new_index->fields);
+
+ /* When adding a PRIMARY KEY, we may convert a previous
+ clustered index to a secondary index (UNIQUE NOT NULL). */
+ new_index->ind_type = index->type & ~DICT_CLUSTERED;
+ new_index->n_fields = n_fields;
+ new_index->name = index->name;
+
+ for (i = 0; i < n_fields; i++) {
+ innobase_copy_index_field_def(&index->fields[i],
+ &new_index->fields[i]);
+ }
+
+ DBUG_VOID_RETURN;
+}
+
+/*******************************************************************//**
+Create an index table where indexes are ordered as follows:
+
+IF a new primary key is defined for the table THEN
+
+ 1) New primary key
+ 2) Original secondary indexes
+ 3) New secondary indexes
+
+ELSE
+
+ 1) All new indexes in the order they arrive from MySQL
+
+ENDIF
+
+
+@return key definitions or NULL */
+static
+merge_index_def_t*
+innobase_create_key_def(
+/*====================*/
+ trx_t* trx, /*!< in: trx */
+ const dict_table_t*table, /*!< in: table definition */
+ mem_heap_t* heap, /*!< in: heap where space for key
+ definitions are allocated */
+ KEY* key_info, /*!< in: Indexes to be created */
+ ulint& n_keys) /*!< in/out: Number of indexes to
+ be created */
+{
+ ulint i = 0;
+ merge_index_def_t* indexdef;
+ merge_index_def_t* indexdefs;
+ bool new_primary;
+
+ DBUG_ENTER("innobase_create_key_def");
+
+ indexdef = indexdefs = (merge_index_def_t*)
+ mem_heap_alloc(heap, sizeof *indexdef
+ * (n_keys + UT_LIST_GET_LEN(table->indexes)));
+
+ /* If there is a primary key, it is always the first index
+ defined for the table. */
+
+ new_primary = !my_strcasecmp(system_charset_info,
+ key_info->name, "PRIMARY");
+
+ /* If there is a UNIQUE INDEX consisting entirely of NOT NULL
+ columns, MySQL will treat it as a PRIMARY KEY unless the
+ table already has one. */
+
+ if (!new_primary && (key_info->flags & HA_NOSAME)
+ && row_table_got_default_clust_index(table)) {
+ uint key_part = key_info->key_parts;
+
+ new_primary = TRUE;
+
+ while (key_part--) {
+ if (key_info->key_part[key_part].key_type
+ & FIELDFLAG_MAYBE_NULL) {
+ new_primary = FALSE;
+ break;
+ }
+ }
+ }
+
+ if (new_primary) {
+ const dict_index_t* index;
+
+ /* Create the PRIMARY key index definition */
+ innobase_create_index_def(&key_info[i++], TRUE, TRUE,
+ indexdef++, heap);
+
+ row_mysql_lock_data_dictionary(trx);
+
+ index = dict_table_get_first_index(table);
+
+ /* Copy the index definitions of the old table. Skip
+ the old clustered index if it is a generated clustered
+ index or a PRIMARY KEY. If the clustered index is a
+ UNIQUE INDEX, it must be converted to a secondary index. */
+
+ if (dict_index_get_nth_col(index, 0)->mtype == DATA_SYS
+ || !my_strcasecmp(system_charset_info,
+ index->name, "PRIMARY")) {
+ index = dict_table_get_next_index(index);
+ }
+
+ while (index) {
+ innobase_copy_index_def(index, indexdef++, heap);
+ index = dict_table_get_next_index(index);
+ }
+
+ row_mysql_unlock_data_dictionary(trx);
+ }
+
+ /* Create definitions for added secondary indexes. */
+
+ while (i < n_keys) {
+ innobase_create_index_def(&key_info[i++], new_primary, FALSE,
+ indexdef++, heap);
+ }
+
+ n_keys = indexdef - indexdefs;
+
+ DBUG_RETURN(indexdefs);
+}
+
+/*******************************************************************//**
+Create a temporary tablename using query id, thread id, and id
+@return temporary tablename */
+static
+char*
+innobase_create_temporary_tablename(
+/*================================*/
+ mem_heap_t* heap, /*!< in: memory heap */
+ char id, /*!< in: identifier [0-9a-zA-Z] */
+ const char* table_name) /*!< in: table name */
+{
+ char* name;
+ ulint len;
+ static const char suffix[] = "@0023 "; /* "# " */
+
+ len = strlen(table_name);
+
+ name = (char*) mem_heap_alloc(heap, len + sizeof suffix);
+ memcpy(name, table_name, len);
+ memcpy(name + len, suffix, sizeof suffix);
+ name[len + (sizeof suffix - 2)] = id;
+
+ return(name);
+}
+
+/*******************************************************************//**
+Create indexes.
+@return 0 or error number */
+UNIV_INTERN
+int
+ha_innobase::add_index(
+/*===================*/
+ TABLE* table, /*!< in: Table where indexes are created */
+ KEY* key_info, /*!< in: Indexes to be created */
+ uint num_of_keys) /*!< in: Number of indexes to be created */
+{
+ dict_index_t** index; /*!< Index to be created */
+ dict_table_t* innodb_table; /*!< InnoDB table in dictionary */
+ dict_table_t* indexed_table; /*!< Table where indexes are created */
+ merge_index_def_t* index_defs; /*!< Index definitions */
+ mem_heap_t* heap; /*!< Heap for index definitions */
+ trx_t* trx; /*!< Transaction */
+ ulint num_of_idx;
+ ulint num_created = 0;
+ ibool dict_locked = FALSE;
+ ulint new_primary;
+ ulint error;
+
+ DBUG_ENTER("ha_innobase::add_index");
+ ut_a(table);
+ ut_a(key_info);
+ ut_a(num_of_keys);
+
+ if (srv_created_new_raw || srv_force_recovery) {
+ DBUG_RETURN(HA_ERR_WRONG_COMMAND);
+ }
+
+ update_thd();
+
+ heap = mem_heap_create(1024);
+
+ /* In case MySQL calls this in the middle of a SELECT query, release
+ possible adaptive hash latch to avoid deadlocks of threads. */
+ trx_search_latch_release_if_reserved(prebuilt->trx);
+ trx_start_if_not_started(prebuilt->trx);
+
+ /* Create a background transaction for the operations on
+ the data dictionary tables. */
+ trx = innobase_trx_allocate(user_thd);
+ trx_start_if_not_started(trx);
+
+ innodb_table = indexed_table
+ = dict_table_get(prebuilt->table->name, FALSE);
+
+ /* Check that index keys are sensible */
+
+ error = innobase_check_index_keys(key_info, num_of_keys);
+
+ if (UNIV_UNLIKELY(error)) {
+err_exit:
+ mem_heap_free(heap);
+ trx_general_rollback_for_mysql(trx, FALSE, NULL);
+ trx_free_for_mysql(trx);
+ trx_commit_for_mysql(prebuilt->trx);
+ DBUG_RETURN(error);
+ }
+
+ /* Create table containing all indexes to be built in this
+ alter table add index so that they are in the correct order
+ in the table. */
+
+ num_of_idx = num_of_keys;
+
+ index_defs = innobase_create_key_def(
+ trx, innodb_table, heap, key_info, num_of_idx);
+
+ new_primary = DICT_CLUSTERED & index_defs[0].ind_type;
+
+ /* Allocate memory for dictionary index definitions */
+
+ index = (dict_index_t**) mem_heap_alloc(
+ heap, num_of_idx * sizeof *index);
+
+ /* Flag this transaction as a dictionary operation, so that
+ the data dictionary will be locked in crash recovery. */
+ trx_set_dict_operation(trx, TRX_DICT_OP_INDEX);
+
+ /* Acquire a lock on the table before creating any indexes. */
+ error = row_merge_lock_table(prebuilt->trx, innodb_table,
+ new_primary ? LOCK_X : LOCK_S);
+
+ if (UNIV_UNLIKELY(error != DB_SUCCESS)) {
+
+ goto error_handling;
+ }
+
+ /* Latch the InnoDB data dictionary exclusively so that no deadlocks
+ or lock waits can happen in it during an index create operation. */
+
+ row_mysql_lock_data_dictionary(trx);
+ dict_locked = TRUE;
+
+ /* If a new primary key is defined for the table we need
+ to drop the original table and rebuild all indexes. */
+
+ if (UNIV_UNLIKELY(new_primary)) {
+ /* This transaction should be the only one
+ operating on the table. */
+ ut_a(innodb_table->n_mysql_handles_opened == 1);
+
+ char* new_table_name = innobase_create_temporary_tablename(
+ heap, '1', innodb_table->name);
+
+ /* Clone the table. */
+ trx_set_dict_operation(trx, TRX_DICT_OP_TABLE);
+ indexed_table = row_merge_create_temporary_table(
+ new_table_name, index_defs, innodb_table, trx);
+
+ if (!indexed_table) {
+
+ switch (trx->error_state) {
+ case DB_TABLESPACE_ALREADY_EXISTS:
+ case DB_DUPLICATE_KEY:
+ innobase_convert_tablename(new_table_name);
+ my_error(HA_ERR_TABLE_EXIST, MYF(0),
+ new_table_name);
+ error = HA_ERR_TABLE_EXIST;
+ break;
+ default:
+ error = convert_error_code_to_mysql(
+ trx->error_state, innodb_table->flags,
+ user_thd);
+ }
+
+ row_mysql_unlock_data_dictionary(trx);
+ goto err_exit;
+ }
+
+ trx->table_id = indexed_table->id;
+ }
+
+ /* Create the indexes in SYS_INDEXES and load into dictionary. */
+
+ for (ulint i = 0; i < num_of_idx; i++) {
+
+ index[i] = row_merge_create_index(trx, indexed_table,
+ &index_defs[i]);
+
+ if (!index[i]) {
+ error = trx->error_state;
+ goto error_handling;
+ }
+
+ num_created++;
+ }
+
+ ut_ad(error == DB_SUCCESS);
+
+ /* Commit the data dictionary transaction in order to release
+ the table locks on the system tables. Unfortunately, this
+ means that if MySQL crashes while creating a new primary key
+ inside row_merge_build_indexes(), indexed_table will not be
+ dropped on crash recovery. Thus, it will become orphaned. */
+ trx_commit_for_mysql(trx);
+
+ row_mysql_unlock_data_dictionary(trx);
+ dict_locked = FALSE;
+
+ ut_a(trx->n_active_thrs == 0);
+ ut_a(UT_LIST_GET_LEN(trx->signals) == 0);
+
+ if (UNIV_UNLIKELY(new_primary)) {
+ /* A primary key is to be built. Acquire an exclusive
+ table lock also on the table that is being created. */
+ ut_ad(indexed_table != innodb_table);
+
+ error = row_merge_lock_table(prebuilt->trx, indexed_table,
+ LOCK_X);
+
+ if (UNIV_UNLIKELY(error != DB_SUCCESS)) {
+
+ goto error_handling;
+ }
+ }
+
+ /* Read the clustered index of the table and build indexes
+ based on this information using temporary files and merge sort. */
+ error = row_merge_build_indexes(prebuilt->trx,
+ innodb_table, indexed_table,
+ index, num_of_idx, table);
+
+error_handling:
+#ifdef UNIV_DEBUG
+ /* TODO: At the moment we can't handle the following statement
+ in our debugging code below:
+
+ alter table t drop index b, add index (b);
+
+ The fix will have to parse the SQL and note that the index
+ being added has the same name as the the one being dropped and
+ ignore that in the dup index check.*/
+ //dict_table_check_for_dup_indexes(prebuilt->table);
+#endif
+
+ /* After an error, remove all those index definitions from the
+ dictionary which were defined. */
+
+ switch (error) {
+ const char* old_name;
+ char* tmp_name;
+ case DB_SUCCESS:
+ ut_a(!dict_locked);
+ row_mysql_lock_data_dictionary(trx);
+ dict_locked = TRUE;
+
+ if (!new_primary) {
+ error = row_merge_rename_indexes(trx, indexed_table);
+
+ if (error != DB_SUCCESS) {
+ row_merge_drop_indexes(trx, indexed_table,
+ index, num_created);
+ }
+
+ goto convert_error;
+ }
+
+ /* If a new primary key was defined for the table and
+ there was no error at this point, we can now rename
+ the old table as a temporary table, rename the new
+ temporary table as the old table and drop the old table. */
+ old_name = innodb_table->name;
+ tmp_name = innobase_create_temporary_tablename(heap, '2',
+ old_name);
+
+ error = row_merge_rename_tables(innodb_table, indexed_table,
+ tmp_name, trx);
+
+ if (error != DB_SUCCESS) {
+
+ row_merge_drop_table(trx, indexed_table);
+
+ switch (error) {
+ case DB_TABLESPACE_ALREADY_EXISTS:
+ case DB_DUPLICATE_KEY:
+ innobase_convert_tablename(tmp_name);
+ my_error(HA_ERR_TABLE_EXIST, MYF(0), tmp_name);
+ error = HA_ERR_TABLE_EXIST;
+ break;
+ default:
+ goto convert_error;
+ }
+ break;
+ }
+
+ trx_commit_for_mysql(prebuilt->trx);
+ row_prebuilt_free(prebuilt, TRUE);
+ prebuilt = row_create_prebuilt(indexed_table);
+
+ indexed_table->n_mysql_handles_opened++;
+
+ error = row_merge_drop_table(trx, innodb_table);
+ goto convert_error;
+
+ case DB_TOO_BIG_RECORD:
+ my_error(HA_ERR_TO_BIG_ROW, MYF(0));
+ goto error;
+ case DB_PRIMARY_KEY_IS_NULL:
+ my_error(ER_PRIMARY_CANT_HAVE_NULL, MYF(0));
+ /* fall through */
+ case DB_DUPLICATE_KEY:
+error:
+ prebuilt->trx->error_info = NULL;
+ /* fall through */
+ default:
+ if (new_primary) {
+ row_merge_drop_table(trx, indexed_table);
+ } else {
+ if (!dict_locked) {
+ row_mysql_lock_data_dictionary(trx);
+ dict_locked = TRUE;
+ }
+
+ row_merge_drop_indexes(trx, indexed_table,
+ index, num_created);
+ }
+
+convert_error:
+ error = convert_error_code_to_mysql(error,
+ innodb_table->flags,
+ user_thd);
+ }
+
+ mem_heap_free(heap);
+ trx_commit_for_mysql(trx);
+ if (prebuilt->trx) {
+ trx_commit_for_mysql(prebuilt->trx);
+ }
+
+ if (dict_locked) {
+ row_mysql_unlock_data_dictionary(trx);
+ }
+
+ trx_free_for_mysql(trx);
+
+ /* There might be work for utility threads.*/
+ srv_active_wake_master_thread();
+
+ DBUG_RETURN(error);
+}
+
+/*******************************************************************//**
+Prepare to drop some indexes of a table.
+@return 0 or error number */
+UNIV_INTERN
+int
+ha_innobase::prepare_drop_index(
+/*============================*/
+ TABLE* table, /*!< in: Table where indexes are dropped */
+ uint* key_num, /*!< in: Key nums to be dropped */
+ uint num_of_keys) /*!< in: Number of keys to be dropped */
+{
+ trx_t* trx;
+ int err = 0;
+ uint n_key;
+
+ DBUG_ENTER("ha_innobase::prepare_drop_index");
+ ut_ad(table);
+ ut_ad(key_num);
+ ut_ad(num_of_keys);
+ if (srv_created_new_raw || srv_force_recovery) {
+ DBUG_RETURN(HA_ERR_WRONG_COMMAND);
+ }
+
+ update_thd();
+
+ trx_search_latch_release_if_reserved(prebuilt->trx);
+ trx = prebuilt->trx;
+
+ /* Test and mark all the indexes to be dropped */
+
+ row_mysql_lock_data_dictionary(trx);
+
+ /* Check that none of the indexes have previously been flagged
+ for deletion. */
+ {
+ const dict_index_t* index
+ = dict_table_get_first_index(prebuilt->table);
+ do {
+ ut_a(!index->to_be_dropped);
+ index = dict_table_get_next_index(index);
+ } while (index);
+ }
+
+ for (n_key = 0; n_key < num_of_keys; n_key++) {
+ const KEY* key;
+ dict_index_t* index;
+
+ key = table->key_info + key_num[n_key];
+ index = dict_table_get_index_on_name_and_min_id(
+ prebuilt->table, key->name);
+
+ if (!index) {
+ sql_print_error("InnoDB could not find key n:o %u "
+ "with name %s for table %s",
+ key_num[n_key],
+ key ? key->name : "NULL",
+ prebuilt->table->name);
+
+ err = HA_ERR_KEY_NOT_FOUND;
+ goto func_exit;
+ }
+
+ /* Refuse to drop the clustered index. It would be
+ better to automatically generate a clustered index,
+ but mysql_alter_table() will call this method only
+ after ha_innobase::add_index(). */
+
+ if (dict_index_is_clust(index)) {
+ my_error(ER_REQUIRES_PRIMARY_KEY, MYF(0));
+ err = -1;
+ goto func_exit;
+ }
+
+ index->to_be_dropped = TRUE;
+ }
+
+ /* If FOREIGN_KEY_CHECK = 1 you may not drop an index defined
+ for a foreign key constraint because InnoDB requires that both
+ tables contain indexes for the constraint. Note that CREATE
+ INDEX id ON table does a CREATE INDEX and DROP INDEX, and we
+ can ignore here foreign keys because a new index for the
+ foreign key has already been created.
+
+ We check for the foreign key constraints after marking the
+ candidate indexes for deletion, because when we check for an
+ equivalent foreign index we don't want to select an index that
+ is later deleted. */
+
+ if (trx->check_foreigns
+ && thd_sql_command(user_thd) != SQLCOM_CREATE_INDEX) {
+ dict_index_t* index;
+
+ for (index = dict_table_get_first_index(prebuilt->table);
+ index;
+ index = dict_table_get_next_index(index)) {
+ dict_foreign_t* foreign;
+
+ if (!index->to_be_dropped) {
+
+ continue;
+ }
+
+ /* Check if the index is referenced. */
+ foreign = dict_table_get_referenced_constraint(
+ prebuilt->table, index);
+
+ if (foreign) {
+index_needed:
+ trx_set_detailed_error(
+ trx,
+ "Index needed in foreign key "
+ "constraint");
+
+ trx->error_info = index;
+
+ err = HA_ERR_DROP_INDEX_FK;
+ break;
+ } else {
+ /* Check if this index references some
+ other table */
+ foreign = dict_table_get_foreign_constraint(
+ prebuilt->table, index);
+
+ if (foreign) {
+ ut_a(foreign->foreign_index == index);
+
+ /* Search for an equivalent index that
+ the foreign key constraint could use
+ if this index were to be deleted. */
+ if (!dict_foreign_find_equiv_index(
+ foreign)) {
+
+ goto index_needed;
+ }
+ }
+ }
+ }
+ } else if (thd_sql_command(user_thd) == SQLCOM_CREATE_INDEX) {
+ /* This is a drop of a foreign key constraint index that
+ was created by MySQL when the constraint was added. MySQL
+ does this when the user creates an index explicitly which
+ can be used in place of the automatically generated index. */
+
+ dict_index_t* index;
+
+ for (index = dict_table_get_first_index(prebuilt->table);
+ index;
+ index = dict_table_get_next_index(index)) {
+ dict_foreign_t* foreign;
+
+ if (!index->to_be_dropped) {
+
+ continue;
+ }
+
+ /* Check if this index references some other table */
+ foreign = dict_table_get_foreign_constraint(
+ prebuilt->table, index);
+
+ if (foreign == NULL) {
+
+ continue;
+ }
+
+ ut_a(foreign->foreign_index == index);
+
+ /* Search for an equivalent index that the
+ foreign key constraint could use if this index
+ were to be deleted. */
+
+ if (!dict_foreign_find_equiv_index(foreign)) {
+ trx_set_detailed_error(
+ trx,
+ "Index needed in foreign key "
+ "constraint");
+
+ trx->error_info = foreign->foreign_index;
+
+ err = HA_ERR_DROP_INDEX_FK;
+ break;
+ }
+ }
+ }
+
+func_exit:
+ if (err) {
+ /* Undo our changes since there was some sort of error. */
+ dict_index_t* index
+ = dict_table_get_first_index(prebuilt->table);
+
+ do {
+ index->to_be_dropped = FALSE;
+ index = dict_table_get_next_index(index);
+ } while (index);
+ }
+
+ row_mysql_unlock_data_dictionary(trx);
+
+ DBUG_RETURN(err);
+}
+
+/*******************************************************************//**
+Drop the indexes that were passed to a successful prepare_drop_index().
+@return 0 or error number */
+UNIV_INTERN
+int
+ha_innobase::final_drop_index(
+/*==========================*/
+ TABLE* table) /*!< in: Table where indexes are dropped */
+{
+ dict_index_t* index; /*!< Index to be dropped */
+ trx_t* trx; /*!< Transaction */
+ int err;
+
+ DBUG_ENTER("ha_innobase::final_drop_index");
+ ut_ad(table);
+
+ if (srv_created_new_raw || srv_force_recovery) {
+ DBUG_RETURN(HA_ERR_WRONG_COMMAND);
+ }
+
+ update_thd();
+
+ trx_search_latch_release_if_reserved(prebuilt->trx);
+ trx_start_if_not_started(prebuilt->trx);
+
+ /* Create a background transaction for the operations on
+ the data dictionary tables. */
+ trx = innobase_trx_allocate(user_thd);
+ trx_start_if_not_started(trx);
+
+ /* Flag this transaction as a dictionary operation, so that
+ the data dictionary will be locked in crash recovery. */
+ trx_set_dict_operation(trx, TRX_DICT_OP_INDEX);
+
+ /* Lock the table exclusively, to ensure that no active
+ transaction depends on an index that is being dropped. */
+ err = convert_error_code_to_mysql(
+ row_merge_lock_table(prebuilt->trx, prebuilt->table, LOCK_X),
+ prebuilt->table->flags, user_thd);
+
+ row_mysql_lock_data_dictionary(trx);
+
+ if (UNIV_UNLIKELY(err)) {
+
+ /* Unmark the indexes to be dropped. */
+ for (index = dict_table_get_first_index(prebuilt->table);
+ index; index = dict_table_get_next_index(index)) {
+
+ index->to_be_dropped = FALSE;
+ }
+
+ goto func_exit;
+ }
+
+ /* Drop indexes marked to be dropped */
+
+ index = dict_table_get_first_index(prebuilt->table);
+
+ while (index) {
+ dict_index_t* next_index;
+
+ next_index = dict_table_get_next_index(index);
+
+ if (index->to_be_dropped) {
+
+ row_merge_drop_index(index, prebuilt->table, trx);
+ }
+
+ index = next_index;
+ }
+
+ /* Check that all flagged indexes were dropped. */
+ for (index = dict_table_get_first_index(prebuilt->table);
+ index; index = dict_table_get_next_index(index)) {
+ ut_a(!index->to_be_dropped);
+ }
+
+#ifdef UNIV_DEBUG
+ dict_table_check_for_dup_indexes(prebuilt->table);
+#endif
+
+func_exit:
+ trx_commit_for_mysql(trx);
+ trx_commit_for_mysql(prebuilt->trx);
+ row_mysql_unlock_data_dictionary(trx);
+
+ /* Flush the log to reduce probability that the .frm files and
+ the InnoDB data dictionary get out-of-sync if the user runs
+ with innodb_flush_log_at_trx_commit = 0 */
+
+ log_buffer_flush_to_disk();
+
+ trx_free_for_mysql(trx);
+
+ /* Tell the InnoDB server that there might be work for
+ utility threads: */
+
+ srv_active_wake_master_thread();
+
+ DBUG_RETURN(err);
+}
diff --git a/storage/innodb_plugin/handler/handler0vars.h b/storage/innodb_plugin/handler/handler0vars.h
new file mode 100644
index 00000000000..e0f8f75e34d
--- /dev/null
+++ b/storage/innodb_plugin/handler/handler0vars.h
@@ -0,0 +1,69 @@
+/*****************************************************************************
+
+Copyright (c) 2008, 2009, Innobase Oy. All Rights Reserved.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; version 2 of the License.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place, Suite 330, Boston, MA 02111-1307 USA
+
+*****************************************************************************/
+
+/*******************************************************************//**
+@file handler/handler0vars.h
+This file contains accessor functions for dynamic plugin on Windows.
+***********************************************************************/
+
+#if defined __WIN__ && defined MYSQL_DYNAMIC_PLUGIN
+/*******************************************************************//**
+This is a list of externals that can not be resolved by delay loading.
+They have to be resolved indirectly via their addresses in the .map file.
+All of them are external variables. */
+extern CHARSET_INFO* wdl_my_charset_bin;
+extern CHARSET_INFO* wdl_my_charset_latin1;
+extern CHARSET_INFO* wdl_my_charset_filename;
+extern CHARSET_INFO** wdl_system_charset_info;
+extern CHARSET_INFO** wdl_default_charset_info;
+extern CHARSET_INFO** wdl_all_charsets;
+extern system_variables* wdl_global_system_variables;
+extern char* wdl_mysql_real_data_home;
+extern char** wdl_mysql_data_home;
+extern char** wdl_tx_isolation_names;
+extern char** wdl_binlog_format_names;
+extern char* wdl_reg_ext;
+extern pthread_mutex_t* wdl_LOCK_thread_count;
+extern key_map* wdl_key_map_full;
+extern MY_TMPDIR* wdl_mysql_tmpdir_list;
+extern bool* wdl_mysqld_embedded;
+extern uint* wdl_lower_case_table_names;
+extern ulong* wdl_specialflag;
+extern int* wdl_my_umask;
+
+#define my_charset_bin (*wdl_my_charset_bin)
+#define my_charset_latin1 (*wdl_my_charset_latin1)
+#define my_charset_filename (*wdl_my_charset_filename)
+#define system_charset_info (*wdl_system_charset_info)
+#define default_charset_info (*wdl_default_charset_info)
+#define all_charsets (wdl_all_charsets)
+#define global_system_variables (*wdl_global_system_variables)
+#define mysql_real_data_home (wdl_mysql_real_data_home)
+#define mysql_data_home (*wdl_mysql_data_home)
+#define tx_isolation_names (wdl_tx_isolation_names)
+#define binlog_format_names (wdl_binlog_format_names)
+#define reg_ext (wdl_reg_ext)
+#define LOCK_thread_count (*wdl_LOCK_thread_count)
+#define key_map_full (*wdl_key_map_full)
+#define mysql_tmpdir_list (*wdl_mysql_tmpdir_list)
+#define mysqld_embedded (*wdl_mysqld_embedded)
+#define lower_case_table_names (*wdl_lower_case_table_names)
+#define specialflag (*wdl_specialflag)
+#define my_umask (*wdl_my_umask)
+
+#endif
diff --git a/storage/innodb_plugin/handler/i_s.cc b/storage/innodb_plugin/handler/i_s.cc
new file mode 100644
index 00000000000..c0d488d1c49
--- /dev/null
+++ b/storage/innodb_plugin/handler/i_s.cc
@@ -0,0 +1,1576 @@
+/*****************************************************************************
+
+Copyright (c) 2007, 2009, Innobase Oy. All Rights Reserved.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; version 2 of the License.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place, Suite 330, Boston, MA 02111-1307 USA
+
+*****************************************************************************/
+
+/**************************************************//**
+@file handler/i_s.cc
+InnoDB INFORMATION SCHEMA tables interface to MySQL.
+
+Created July 18, 2007 Vasil Dimov
+*******************************************************/
+
+#include
+#include