1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-30 16:24:05 +03:00

Merge of Percona XtraDB into MariaDB.

This commit is contained in:
unknown
2009-06-11 19:49:51 +02:00
365 changed files with 204932 additions and 181 deletions

View File

@ -1444,6 +1444,21 @@ storage/innobase/ib_config.h
storage/innobase/ib_config.h.in storage/innobase/ib_config.h.in
storage/innobase/mkinstalldirs storage/innobase/mkinstalldirs
storage/innobase/stamp-h1 storage/innobase/stamp-h1
storage/xtradb/autom4te-2.53.cache/*
storage/xtradb/autom4te-2.53.cache/output.0
storage/xtradb/autom4te-2.53.cache/requests
storage/xtradb/autom4te-2.53.cache/traces.0
storage/xtradb/autom4te.cache/*
storage/xtradb/autom4te.cache/output.0
storage/xtradb/autom4te.cache/requests
storage/xtradb/autom4te.cache/traces.0
storage/xtradb/configure.lineno
storage/xtradb/conftest.s1
storage/xtradb/conftest.subs
storage/xtradb/ib_config.h
storage/xtradb/ib_config.h.in
storage/xtradb/mkinstalldirs
storage/xtradb/stamp-h1
storage/maria/*.MAD storage/maria/*.MAD
storage/maria/*.MAI storage/maria/*.MAI
storage/maria/ma_rt_test storage/maria/ma_rt_test

24
BUILD/compile-innodb Executable file
View File

@ -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"

24
BUILD/compile-innodb-debug Executable file
View File

@ -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"

View File

@ -263,7 +263,7 @@ IF(WITH_FEDERATED_STORAGE_ENGINE)
ADD_SUBDIRECTORY(storage/federated) ADD_SUBDIRECTORY(storage/federated)
ENDIF(WITH_FEDERATED_STORAGE_ENGINE) ENDIF(WITH_FEDERATED_STORAGE_ENGINE)
IF(WITH_INNOBASE_STORAGE_ENGINE) IF(WITH_INNOBASE_STORAGE_ENGINE)
ADD_SUBDIRECTORY(storage/innobase) ADD_SUBDIRECTORY(storage/xtradb)
ENDIF(WITH_INNOBASE_STORAGE_ENGINE) ENDIF(WITH_INNOBASE_STORAGE_ENGINE)
IF(WITH_MARIA_STORAGE_ENGINE) IF(WITH_MARIA_STORAGE_ENGINE)
ADD_SUBDIRECTORY(storage/maria) ADD_SUBDIRECTORY(storage/maria)

View File

@ -1729,6 +1729,30 @@ then
fi fi
fi fi
AC_CACHE_CHECK([whether the compiler provides atomic builtins],
[mysql_cv_gcc_atomic_builtins], [AC_TRY_RUN([
int main()
{
int foo= -10; int bar= 10;
if (!__sync_fetch_and_add(&foo, bar) || foo)
return -1;
bar= __sync_lock_test_and_set(&foo, bar);
if (bar || foo != 10)
return -1;
bar= __sync_val_compare_and_swap(&bar, foo, 15);
if (bar)
return -1;
return 0;
}
], [mysql_cv_gcc_atomic_builtins=yes],
[mysql_cv_gcc_atomic_builtins=no],
[mysql_cv_gcc_atomic_builtins=no])])
if test "x$mysql_cv_gcc_atomic_builtins" = xyes; then
AC_DEFINE(HAVE_GCC_ATOMIC_BUILTINS, 1,
[Define to 1 if compiler provides atomic builtins.])
fi
AC_ARG_WITH([atomic-ops], AC_ARG_WITH([atomic-ops],
AC_HELP_STRING([--with-atomic-ops=rwlocks|smp|up], AC_HELP_STRING([--with-atomic-ops=rwlocks|smp|up],
[Implement atomic operations using pthread rwlocks or atomic CPU [Implement atomic operations using pthread rwlocks or atomic CPU
@ -1742,28 +1766,9 @@ case "$with_atomic_ops" in
[Use pthread rwlocks for atomic ops]) ;; [Use pthread rwlocks for atomic ops]) ;;
"smp") ;; "smp") ;;
"") "")
AC_CACHE_CHECK([whether the compiler provides atomic builtins], if test "x$mysql_cv_gcc_atomic_builtins" = xyes_but_disabled; then
[mysql_cv_gcc_atomic_builtins], [AC_TRY_RUN([ AC_DEFINE([MY_ATOMIC_MODE_GCC_BUILTINS], [1],
int main() [Use GCC atomic builtins for atomic ops])
{
int foo= -10; int bar= 10;
if (!__sync_fetch_and_add(&foo, bar) || foo)
return -1;
bar= __sync_lock_test_and_set(&foo, bar);
if (bar || foo != 10)
return -1;
bar= __sync_val_compare_and_swap(&bar, foo, 15);
if (bar)
return -1;
return 0;
}
], [mysql_cv_gcc_atomic_builtins=yes_but_disabled],
[mysql_cv_gcc_atomic_builtins=no],
[mysql_cv_gcc_atomic_builtins=no])])
if test "x$mysql_cv_gcc_atomic_builtins" = xyes; then
AC_DEFINE(HAVE_GCC_ATOMIC_BUILTINS, 1,
[Define to 1 if compiler provides atomic builtins.])
fi fi
;; ;;
*) AC_MSG_ERROR(["$with_atomic_ops" is not a valid value for --with-atomic-ops]) ;; *) AC_MSG_ERROR(["$with_atomic_ops" is not a valid value for --with-atomic-ops]) ;;

View File

@ -14,7 +14,7 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#if defined(__i386__) || defined(_MSC_VER) || \ #if defined(__i386__) || defined(_MSC_VER) || \
defined(__x86_64__) || defined(HAVE_GCC_ATOMIC_BUILTINS) defined(__x86_64__) || defined(MY_ATOMIC_MODE_GCC_BUILTINS)
# ifdef MY_ATOMIC_MODE_DUMMY # ifdef MY_ATOMIC_MODE_DUMMY
# define LOCK_prefix "" # define LOCK_prefix ""
@ -22,7 +22,7 @@
# define LOCK_prefix "lock" # define LOCK_prefix "lock"
# endif # endif
# ifdef HAVE_GCC_ATOMIC_BUILTINS # ifdef MY_ATOMIC_MODE_GCC_BUILTINS
# include "gcc_builtins.h" # include "gcc_builtins.h"
# elif __GNUC__ # elif __GNUC__
# include "x86-gcc.h" # include "x86-gcc.h"

View File

@ -791,6 +791,9 @@ extern size_t my_b_gets(IO_CACHE *info, char *to, size_t max_length);
extern my_off_t my_b_filelength(IO_CACHE *info); extern my_off_t my_b_filelength(IO_CACHE *info);
extern size_t my_b_printf(IO_CACHE *info, const char* fmt, ...); extern size_t my_b_printf(IO_CACHE *info, const char* fmt, ...);
extern size_t my_b_vprintf(IO_CACHE *info, const char* fmt, va_list ap); extern size_t my_b_vprintf(IO_CACHE *info, const char* fmt, va_list ap);
extern int init_strvar_from_file(char *var, int max_size, IO_CACHE *f,
const char *default_val);
extern int init_intvar_from_file(int* var, IO_CACHE* f, int default_val);
extern my_bool open_cached_file(IO_CACHE *cache,const char *dir, extern my_bool open_cached_file(IO_CACHE *cache,const char *dir,
const char *prefix, size_t cache_size, const char *prefix, size_t cache_size,
myf cache_myflags); myf cache_myflags);

View File

@ -132,9 +132,9 @@ IF(WITH_FEDERATED_STORAGE_ENGINE)
ENDIF(WITH_FEDERATED_STORAGE_ENGINE) ENDIF(WITH_FEDERATED_STORAGE_ENGINE)
IF(WITH_INNOBASE_STORAGE_ENGINE) IF(WITH_INNOBASE_STORAGE_ENGINE)
INCLUDE(${CMAKE_SOURCE_DIR}/storage/innobase/CMakeLists.txt) INCLUDE(${CMAKE_SOURCE_DIR}/storage/xtradb/CMakeLists.txt)
FOREACH(rpath ${INNOBASE_SOURCES}) FOREACH(rpath ${INNOBASE_SOURCES})
SET(LIB_SOURCES ${LIB_SOURCES} ../storage/innobase/${rpath}) SET(LIB_SOURCES ${LIB_SOURCES} ../storage/xtradb/${rpath})
ENDFOREACH(rpath) ENDFOREACH(rpath)
ENDIF(WITH_INNOBASE_STORAGE_ENGINE) ENDIF(WITH_INNOBASE_STORAGE_ENGINE)

View File

@ -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;

View File

@ -111,7 +111,7 @@ count(*)
explain select count(*) from t1 where explain select count(*) from t1 where
key1a = 2 and key1b is null and key2a = 2 and key2b is null; key1a = 2 and key1b is null and key2a = 2 and key2b is null;
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 index_merge i1,i2 i1,i2 10,10 NULL 4 Using intersect(i1,i2); Using where; Using index 1 SIMPLE t1 index_merge i1,i2 i1,i2 10,10 NULL 3 Using intersect(i1,i2); Using where; Using index
select count(*) from t1 where select count(*) from t1 where
key1a = 2 and key1b is null and key2a = 2 and key2b is null; key1a = 2 and key1b is null and key2a = 2 and key2b is null;
count(*) count(*)
@ -119,7 +119,7 @@ count(*)
explain select count(*) from t1 where explain select count(*) from t1 where
key1a = 2 and key1b is null and key3a = 2 and key3b is null; key1a = 2 and key1b is null and key3a = 2 and key3b is null;
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 index_merge i1,i3 i1,i3 10,10 NULL 4 Using intersect(i1,i3); Using where; Using index 1 SIMPLE t1 index_merge i1,i3 i1,i3 10,10 NULL 3 Using intersect(i1,i3); Using where; Using index
select count(*) from t1 where select count(*) from t1 where
key1a = 2 and key1b is null and key3a = 2 and key3b is null; key1a = 2 and key1b is null and key3a = 2 and key3b is null;
count(*) count(*)

View File

@ -42,7 +42,7 @@ WHERE table_schema IN ('mysql', 'INFORMATION_SCHEMA', 'test', 'mysqltest') AND
table_name<>'ndb_binlog_index' AND table_name<>'ndb_binlog_index' AND
table_name<>'ndb_apply_status' AND table_name<>'ndb_apply_status' AND
NOT (table_schema = 'INFORMATION_SCHEMA' AND table_name LIKE 'PBXT_%'); NOT (table_schema = 'INFORMATION_SCHEMA' AND table_name LIKE 'PBXT_%');
select * from v1; select * from v1 ORDER BY c COLLATE utf8_bin;
c c
CHARACTER_SETS CHARACTER_SETS
COLLATIONS COLLATIONS
@ -54,6 +54,17 @@ EVENTS
FILES FILES
GLOBAL_STATUS GLOBAL_STATUS
GLOBAL_VARIABLES GLOBAL_VARIABLES
INNODB_BUFFER_POOL_PAGES
INNODB_BUFFER_POOL_PAGES_BLOB
INNODB_BUFFER_POOL_PAGES_INDEX
INNODB_CMP
INNODB_CMPMEM
INNODB_CMPMEM_RESET
INNODB_CMP_RESET
INNODB_LOCKS
INNODB_LOCK_WAITS
INNODB_RSEG
INNODB_TRX
KEY_COLUMN_USAGE KEY_COLUMN_USAGE
PARTITIONS PARTITIONS
PLUGINS PLUGINS
@ -72,6 +83,7 @@ TABLE_PRIVILEGES
TRIGGERS TRIGGERS
USER_PRIVILEGES USER_PRIVILEGES
VIEWS VIEWS
XTRADB_ENHANCEMENTS
columns_priv columns_priv
db db
event event
@ -87,6 +99,11 @@ proc
procs_priv procs_priv
servers servers
slow_log slow_log
t1
t2
t3
t4
t5
tables_priv tables_priv
time_zone time_zone
time_zone_leap_second time_zone_leap_second
@ -94,11 +111,6 @@ time_zone_name
time_zone_transition time_zone_transition
time_zone_transition_type time_zone_transition_type
user user
t1
t4
t2
t3
t5
v1 v1
select c,table_name from v1 select c,table_name from v1
inner join information_schema.TABLES v2 on (v1.c=v2.table_name) inner join information_schema.TABLES v2 on (v1.c=v2.table_name)
@ -800,6 +812,8 @@ TABLES CREATE_TIME datetime
TABLES UPDATE_TIME datetime TABLES UPDATE_TIME datetime
TABLES CHECK_TIME datetime TABLES CHECK_TIME datetime
TRIGGERS CREATED datetime TRIGGERS CREATED datetime
INNODB_TRX trx_started datetime
INNODB_TRX trx_wait_started datetime
event execute_at datetime event execute_at datetime
event last_executed datetime event last_executed datetime
event starts datetime event starts datetime
@ -848,6 +862,7 @@ TABLES TABLE_NAME select
TABLE_CONSTRAINTS TABLE_NAME select TABLE_CONSTRAINTS TABLE_NAME select
TABLE_PRIVILEGES TABLE_NAME select TABLE_PRIVILEGES TABLE_NAME select
VIEWS TABLE_NAME select VIEWS TABLE_NAME select
INNODB_BUFFER_POOL_PAGES_INDEX table_name select
delete from mysql.user where user='mysqltest_4'; delete from mysql.user where user='mysqltest_4';
delete from mysql.db where user='mysqltest_4'; delete from mysql.db where user='mysqltest_4';
flush privileges; flush privileges;
@ -1223,12 +1238,12 @@ DROP PROCEDURE p1;
DROP USER mysql_bug20230@localhost; DROP USER mysql_bug20230@localhost;
SELECT MAX(table_name) FROM information_schema.tables WHERE table_schema IN ('mysql', 'INFORMATION_SCHEMA', 'test'); SELECT MAX(table_name) FROM information_schema.tables WHERE table_schema IN ('mysql', 'INFORMATION_SCHEMA', 'test');
MAX(table_name) MAX(table_name)
VIEWS XTRADB_ENHANCEMENTS
SELECT table_name from information_schema.tables SELECT table_name from information_schema.tables
WHERE table_name=(SELECT MAX(table_name) WHERE table_name=(SELECT MAX(table_name)
FROM information_schema.tables WHERE table_schema IN ('mysql', 'INFORMATION_SCHEMA', 'test')); FROM information_schema.tables WHERE table_schema IN ('mysql', 'INFORMATION_SCHEMA', 'test'));
table_name table_name
VIEWS XTRADB_ENHANCEMENTS
DROP TABLE IF EXISTS bug23037; DROP TABLE IF EXISTS bug23037;
DROP FUNCTION IF EXISTS get_value; DROP FUNCTION IF EXISTS get_value;
SELECT COLUMN_NAME, MD5(COLUMN_DEFAULT), LENGTH(COLUMN_DEFAULT) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='bug23037'; SELECT COLUMN_NAME, MD5(COLUMN_DEFAULT), LENGTH(COLUMN_DEFAULT) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='bug23037';

View File

@ -29,7 +29,19 @@ TABLE_PRIVILEGES
TRIGGERS TRIGGERS
USER_PRIVILEGES USER_PRIVILEGES
VIEWS VIEWS
INNODB_BUFFER_POOL_PAGES
PBXT_STATISTICS PBXT_STATISTICS
INNODB_CMP
INNODB_RSEG
XTRADB_ENHANCEMENTS
INNODB_BUFFER_POOL_PAGES_INDEX
INNODB_BUFFER_POOL_PAGES_BLOB
INNODB_TRX
INNODB_CMP_RESET
INNODB_LOCK_WAITS
INNODB_CMPMEM_RESET
INNODB_LOCKS
INNODB_CMPMEM
SELECT t.table_name, c1.column_name SELECT t.table_name, c1.column_name
FROM information_schema.tables t FROM information_schema.tables t
INNER JOIN INNER JOIN
@ -73,7 +85,19 @@ TABLE_PRIVILEGES TABLE_SCHEMA
TRIGGERS TRIGGER_SCHEMA TRIGGERS TRIGGER_SCHEMA
USER_PRIVILEGES GRANTEE USER_PRIVILEGES GRANTEE
VIEWS TABLE_SCHEMA VIEWS TABLE_SCHEMA
INNODB_BUFFER_POOL_PAGES page_type
PBXT_STATISTICS ID PBXT_STATISTICS ID
INNODB_CMP page_size
INNODB_RSEG rseg_id
XTRADB_ENHANCEMENTS name
INNODB_BUFFER_POOL_PAGES_INDEX schema_name
INNODB_BUFFER_POOL_PAGES_BLOB space_id
INNODB_TRX trx_id
INNODB_CMP_RESET page_size
INNODB_LOCK_WAITS requesting_trx_id
INNODB_CMPMEM_RESET page_size
INNODB_LOCKS lock_id
INNODB_CMPMEM page_size
SELECT t.table_name, c1.column_name SELECT t.table_name, c1.column_name
FROM information_schema.tables t FROM information_schema.tables t
INNER JOIN INNER JOIN
@ -117,7 +141,19 @@ TABLE_PRIVILEGES TABLE_SCHEMA
TRIGGERS TRIGGER_SCHEMA TRIGGERS TRIGGER_SCHEMA
USER_PRIVILEGES GRANTEE USER_PRIVILEGES GRANTEE
VIEWS TABLE_SCHEMA VIEWS TABLE_SCHEMA
INNODB_BUFFER_POOL_PAGES page_type
PBXT_STATISTICS ID PBXT_STATISTICS ID
INNODB_CMP page_size
INNODB_RSEG rseg_id
XTRADB_ENHANCEMENTS name
INNODB_BUFFER_POOL_PAGES_INDEX schema_name
INNODB_BUFFER_POOL_PAGES_BLOB space_id
INNODB_TRX trx_id
INNODB_CMP_RESET page_size
INNODB_LOCK_WAITS requesting_trx_id
INNODB_CMPMEM_RESET page_size
INNODB_LOCKS lock_id
INNODB_CMPMEM page_size
select 1 as f1 from information_schema.tables where "CHARACTER_SETS"= select 1 as f1 from information_schema.tables where "CHARACTER_SETS"=
(select cast(table_name as char) from information_schema.tables (select cast(table_name as char) from information_schema.tables
order by table_name limit 1) limit 1; order by table_name limit 1) limit 1;
@ -149,6 +185,17 @@ EVENTS information_schema.EVENTS 1
FILES information_schema.FILES 1 FILES information_schema.FILES 1
GLOBAL_STATUS information_schema.GLOBAL_STATUS 1 GLOBAL_STATUS information_schema.GLOBAL_STATUS 1
GLOBAL_VARIABLES information_schema.GLOBAL_VARIABLES 1 GLOBAL_VARIABLES information_schema.GLOBAL_VARIABLES 1
INNODB_BUFFER_POOL_PAGES information_schema.INNODB_BUFFER_POOL_PAGES 1
INNODB_BUFFER_POOL_PAGES_BLOB information_schema.INNODB_BUFFER_POOL_PAGES_BLOB 1
INNODB_BUFFER_POOL_PAGES_INDEX information_schema.INNODB_BUFFER_POOL_PAGES_INDEX 1
INNODB_CMP information_schema.INNODB_CMP 1
INNODB_CMPMEM information_schema.INNODB_CMPMEM 1
INNODB_CMPMEM_RESET information_schema.INNODB_CMPMEM_RESET 1
INNODB_CMP_RESET information_schema.INNODB_CMP_RESET 1
INNODB_LOCKS information_schema.INNODB_LOCKS 1
INNODB_LOCK_WAITS information_schema.INNODB_LOCK_WAITS 1
INNODB_RSEG information_schema.INNODB_RSEG 1
INNODB_TRX information_schema.INNODB_TRX 1
KEY_COLUMN_USAGE information_schema.KEY_COLUMN_USAGE 1 KEY_COLUMN_USAGE information_schema.KEY_COLUMN_USAGE 1
PARTITIONS information_schema.PARTITIONS 1 PARTITIONS information_schema.PARTITIONS 1
PBXT_STATISTICS information_schema.PBXT_STATISTICS 1 PBXT_STATISTICS information_schema.PBXT_STATISTICS 1
@ -168,6 +215,7 @@ TABLE_PRIVILEGES information_schema.TABLE_PRIVILEGES 1
TRIGGERS information_schema.TRIGGERS 1 TRIGGERS information_schema.TRIGGERS 1
USER_PRIVILEGES information_schema.USER_PRIVILEGES 1 USER_PRIVILEGES information_schema.USER_PRIVILEGES 1
VIEWS information_schema.VIEWS 1 VIEWS information_schema.VIEWS 1
XTRADB_ENHANCEMENTS information_schema.XTRADB_ENHANCEMENTS 1
Database: information_schema Database: information_schema
+---------------------------------------+ +---------------------------------------+
| Tables | | Tables |
@ -200,7 +248,19 @@ Database: information_schema
| TRIGGERS | | TRIGGERS |
| USER_PRIVILEGES | | USER_PRIVILEGES |
| VIEWS | | VIEWS |
| INNODB_BUFFER_POOL_PAGES |
| PBXT_STATISTICS | | PBXT_STATISTICS |
| INNODB_CMP |
| INNODB_RSEG |
| XTRADB_ENHANCEMENTS |
| INNODB_BUFFER_POOL_PAGES_INDEX |
| INNODB_BUFFER_POOL_PAGES_BLOB |
| INNODB_TRX |
| INNODB_CMP_RESET |
| INNODB_LOCK_WAITS |
| INNODB_CMPMEM_RESET |
| INNODB_LOCKS |
| INNODB_CMPMEM |
+---------------------------------------+ +---------------------------------------+
Database: INFORMATION_SCHEMA Database: INFORMATION_SCHEMA
+---------------------------------------+ +---------------------------------------+
@ -234,7 +294,19 @@ Database: INFORMATION_SCHEMA
| TRIGGERS | | TRIGGERS |
| USER_PRIVILEGES | | USER_PRIVILEGES |
| VIEWS | | VIEWS |
| INNODB_BUFFER_POOL_PAGES |
| PBXT_STATISTICS | | PBXT_STATISTICS |
| INNODB_CMP |
| INNODB_RSEG |
| XTRADB_ENHANCEMENTS |
| INNODB_BUFFER_POOL_PAGES_INDEX |
| INNODB_BUFFER_POOL_PAGES_BLOB |
| INNODB_TRX |
| INNODB_CMP_RESET |
| INNODB_LOCK_WAITS |
| INNODB_CMPMEM_RESET |
| INNODB_LOCKS |
| INNODB_CMPMEM |
+---------------------------------------+ +---------------------------------------+
Wildcard: inf_rmation_schema Wildcard: inf_rmation_schema
+--------------------+ +--------------------+
@ -244,5 +316,5 @@ Wildcard: inf_rmation_schema
+--------------------+ +--------------------+
SELECT table_schema, count(*) FROM information_schema.TABLES WHERE table_schema IN ('mysql', 'INFORMATION_SCHEMA', 'test', 'mysqltest') AND table_name<>'ndb_binlog_index' AND table_name<>'ndb_apply_status' GROUP BY TABLE_SCHEMA; SELECT table_schema, count(*) FROM information_schema.TABLES WHERE table_schema IN ('mysql', 'INFORMATION_SCHEMA', 'test', 'mysqltest') AND table_name<>'ndb_binlog_index' AND table_name<>'ndb_apply_status' GROUP BY TABLE_SCHEMA;
table_schema count(*) table_schema count(*)
information_schema 29 information_schema 41
mysql 22 mysql 22

View File

@ -0,0 +1,2 @@
Variable_name Value
innodb_stats_sample_pages 1

View File

@ -581,11 +581,10 @@ c1
DROP TABLE t1; DROP TABLE t1;
SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1;
SET @@INSERT_ID=1; SET @@INSERT_ID=1;
SHOW VARIABLES LIKE "%auto_inc%"; SHOW VARIABLES LIKE "auto_inc%";
Variable_name Value Variable_name Value
auto_increment_increment 1 auto_increment_increment 1
auto_increment_offset 1 auto_increment_offset 1
pbxt_auto_increment_mode 0
CREATE TABLE t1 (c1 DOUBLE NOT NULL AUTO_INCREMENT, c2 INT, PRIMARY KEY (c1)) ENGINE=InnoDB; CREATE TABLE t1 (c1 DOUBLE NOT NULL AUTO_INCREMENT, c2 INT, PRIMARY KEY (c1)) ENGINE=InnoDB;
INSERT INTO t1 VALUES(NULL, 1); INSERT INTO t1 VALUES(NULL, 1);
INSERT INTO t1 VALUES(NULL, 2); INSERT INTO t1 VALUES(NULL, 2);

File diff suppressed because it is too large Load Diff

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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(438)))
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;

View File

@ -1508,7 +1508,7 @@ t2 CREATE TABLE `t2` (
) ENGINE=InnoDB DEFAULT CHARSET=latin1 ) ENGINE=InnoDB DEFAULT CHARSET=latin1
drop index id2 on t2; drop index id2 on t2;
drop index id on t2; drop index id on t2;
Got one of the listed errors ERROR HY000: Cannot drop index 'id': needed in a foreign key constraint
show create table t2; show create table t2;
Table Create Table Table Create Table
t2 CREATE TABLE `t2` ( t2 CREATE TABLE `t2` (
@ -1738,7 +1738,7 @@ count(*)
drop table t1; drop table t1;
show status like "Innodb_buffer_pool_pages_total"; show status like "Innodb_buffer_pool_pages_total";
Variable_name Value Variable_name Value
Innodb_buffer_pool_pages_total 512 Innodb_buffer_pool_pages_total 511
show status like "Innodb_page_size"; show status like "Innodb_page_size";
Variable_name Value Variable_name Value
Innodb_page_size 16384 Innodb_page_size 16384
@ -1784,7 +1784,7 @@ innodb_sync_spin_loops 20
SET @old_innodb_thread_concurrency= @@global.innodb_thread_concurrency; SET @old_innodb_thread_concurrency= @@global.innodb_thread_concurrency;
show variables like "innodb_thread_concurrency"; show variables like "innodb_thread_concurrency";
Variable_name Value Variable_name Value
innodb_thread_concurrency 8 innodb_thread_concurrency 0
set global innodb_thread_concurrency=1001; set global innodb_thread_concurrency=1001;
Warnings: Warnings:
Warning 1292 Truncated incorrect thread_concurrency value: '1001' Warning 1292 Truncated incorrect thread_concurrency value: '1001'
@ -1970,7 +1970,7 @@ explain select count(*) from t1 where v between 'a' and 'a ' and v between 'a '
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ref v v 13 const # Using where; Using index 1 SIMPLE t1 ref v v 13 const # Using where; Using index
alter table t1 add unique(v); alter table t1 add unique(v);
ERROR 23000: Duplicate entry '{ ' for key 'v_2' ERROR 23000: Duplicate entry 'v' for key 'v_2'
alter table t1 add key(v); alter table t1 add key(v);
select concat('*',v,'*',c,'*',t,'*') as qq from t1 where v='a'; select concat('*',v,'*',c,'*',t,'*') as qq from t1 where v='a';
qq qq
@ -2377,6 +2377,8 @@ t1 CREATE TABLE `t1` (
) ENGINE=InnoDB DEFAULT CHARSET=latin1 ) ENGINE=InnoDB DEFAULT CHARSET=latin1
drop table t1; drop table t1;
create table t1 (v varchar(10), c char(10)) row_format=fixed; create table t1 (v varchar(10), c char(10)) row_format=fixed;
Warnings:
Warning 1478 InnoDB: assuming ROW_FORMAT=COMPACT.
show create table t1; show create table t1;
Table Create Table Table Create Table
t1 CREATE TABLE `t1` ( t1 CREATE TABLE `t1` (
@ -3190,6 +3192,7 @@ t1 CREATE TABLE `t1` (
CONSTRAINT `t1_t2` FOREIGN KEY (`id`) REFERENCES `t2` (`id`) CONSTRAINT `t1_t2` FOREIGN KEY (`id`) REFERENCES `t2` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=349 DEFAULT CHARSET=latin1 ) ENGINE=InnoDB AUTO_INCREMENT=349 DEFAULT CHARSET=latin1
DROP TABLE t1,t2; DROP TABLE t1,t2;
set innodb_strict_mode=on;
CREATE TABLE t1 ( CREATE TABLE t1 (
c01 CHAR(255), c02 CHAR(255), c03 CHAR(255), c04 CHAR(255), c01 CHAR(255), c02 CHAR(255), c03 CHAR(255), c04 CHAR(255),
c05 CHAR(255), c06 CHAR(255), c07 CHAR(255), c08 CHAR(255), c05 CHAR(255), c06 CHAR(255), c07 CHAR(255), c08 CHAR(255),

View File

@ -1,8 +1,4 @@
SELECT f4, f8 FROM bug34300;
f4 f8 f4 f8
xxx zzz xxx zzz
ALTER TABLE bug34300 ADD COLUMN (f10 INT);
SELECT f4, f8 FROM bug34300;
f4 f8 f4 f8
xxx zzz xxx zzz
DROP TABLE bug34300;

View File

@ -0,0 +1,5 @@
SET @save_innodb_file_format=@@global.innodb_file_format;
SET @save_innodb_file_format_check=@@global.innodb_file_format_check;
SET @save_innodb_file_per_table=@@global.innodb_file_per_table;
SET GLOBAL innodb_file_format='Barracuda';
SET GLOBAL innodb_file_per_table=ON;

View File

@ -0,0 +1 @@
SET storage_engine=InnoDB;

View File

@ -0,0 +1,4 @@
SET TX_ISOLATION='READ-COMMITTED';
CREATE TABLE bug40360 (a INT) engine=innodb;
INSERT INTO bug40360 VALUES (1);
DROP TABLE bug40360;

View File

@ -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;

View File

@ -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

View File

@ -0,0 +1,5 @@
SET @save_innodb_file_format=@@global.innodb_file_format;
SET @save_innodb_file_format_check=@@global.innodb_file_format_check;
SET @save_innodb_file_per_table=@@global.innodb_file_per_table;
SET GLOBAL innodb_file_format='Barracuda';
SET GLOBAL innodb_file_per_table=ON;

View File

@ -1,4 +1,9 @@
# #
# We need big packets.
#
SET @old_global_max_allowed_packet=@@global.max_allowed_packet;
SET @@global.max_allowed_packet= 1024*1024*1024;
#
# Preparatory cleanup. # Preparatory cleanup.
# #
DROP TABLE IF EXISTS t1; DROP TABLE IF EXISTS t1;
@ -7,10 +12,6 @@ DROP TABLE IF EXISTS t1;
# #
SET timestamp=1000000000; SET timestamp=1000000000;
# #
# We need big packets.
#
SET @@global.max_allowed_packet= 1024*1024*1024;
#
# Delete all existing binary logs. # Delete all existing binary logs.
# #
RESET MASTER; RESET MASTER;
@ -71,4 +72,5 @@ FLUSH LOGS;
# Cleanup. # Cleanup.
# #
DROP TABLE t1; DROP TABLE t1;
SET @@global.max_allowed_packet=@old_global_max_allowed_packet;
remove_file $MYSQLTEST_VARDIR/tmp/mysqlbinlog_big_1.out remove_file $MYSQLTEST_VARDIR/tmp/mysqlbinlog_big_1.out

View File

@ -72,6 +72,8 @@ Table Checksum
test.t1 4108368782 test.t1 4108368782
drop table if exists t1; drop table if exists t1;
create table t1 (a int null, v varchar(100)) engine=innodb checksum=0 row_format=fixed; create table t1 (a int null, v varchar(100)) engine=innodb checksum=0 row_format=fixed;
Warnings:
Warning 1478 InnoDB: assuming ROW_FORMAT=COMPACT.
insert into t1 values(null, null), (1, "hello"); insert into t1 values(null, null), (1, "hello");
checksum table t1; checksum table t1;
Table Checksum Table Checksum

View File

@ -72,6 +72,8 @@ Table Checksum
test.t1 3885665021 test.t1 3885665021
drop table if exists t1; drop table if exists t1;
create table t1 (a int null, v varchar(100)) engine=innodb checksum=0 row_format=fixed; create table t1 (a int null, v varchar(100)) engine=innodb checksum=0 row_format=fixed;
Warnings:
Warning 1478 InnoDB: assuming ROW_FORMAT=COMPACT.
insert into t1 values(null, null), (1, "hello"); insert into t1 values(null, null), (1, "hello");
checksum table t1; checksum table t1;
Table Checksum Table Checksum

View File

@ -1,20 +1,20 @@
set session transaction_prealloc_size=1024*1024*1024*1; set session transaction_prealloc_size=1024*1024*1024*1;
show processlist; select @pid_temp = (select ID from information_schema.processlist) as 'TRUE';
Id User Host db Command Time State Info TRUE
# root localhost test Query 0 NULL show processlist 1
set session transaction_prealloc_size=1024*1024*1024*2; set session transaction_prealloc_size=1024*1024*1024*2;
show processlist; select @pid_temp = (select ID from information_schema.processlist) as 'TRUE';
Id User Host db Command Time State Info TRUE
# root localhost test Query 0 NULL show processlist 1
set session transaction_prealloc_size=1024*1024*1024*3; set session transaction_prealloc_size=1024*1024*1024*3;
show processlist; select @pid_temp = (select ID from information_schema.processlist) as 'TRUE';
Id User Host db Command Time State Info TRUE
# root localhost test Query 0 NULL show processlist 1
set session transaction_prealloc_size=1024*1024*1024*4; set session transaction_prealloc_size=1024*1024*1024*4;
show processlist; select @pid_temp = (select ID from information_schema.processlist) as 'TRUE';
Id User Host db Command Time State Info TRUE
# root localhost test Query 0 NULL show processlist 1
set session transaction_prealloc_size=1024*1024*1024*5; set session transaction_prealloc_size=1024*1024*1024*5;
show processlist; select @pid_temp = (select ID from information_schema.processlist) as 'TRUE';
Id User Host db Command Time State Info TRUE
# root localhost test Query 0 NULL show processlist 1

View File

@ -47,7 +47,7 @@ create view v1 (c) as
table_name<>'ndb_binlog_index' AND table_name<>'ndb_binlog_index' AND
table_name<>'ndb_apply_status' AND table_name<>'ndb_apply_status' AND
NOT (table_schema = 'INFORMATION_SCHEMA' AND table_name LIKE 'PBXT_%'); NOT (table_schema = 'INFORMATION_SCHEMA' AND table_name LIKE 'PBXT_%');
select * from v1; select * from v1 ORDER BY c COLLATE utf8_bin;
select c,table_name from v1 select c,table_name from v1
inner join information_schema.TABLES v2 on (v1.c=v2.table_name) inner join information_schema.TABLES v2 on (v1.c=v2.table_name)

View File

@ -0,0 +1,65 @@
#
# 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
# 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 @save_innodb_stats_sample_pages=@@innodb_stats_sample_pages;
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;
SET GLOBAL innodb_stats_sample_pages=@save_innodb_stats_sample_pages;
DROP TABLE innodb_analyze;

View File

@ -396,7 +396,7 @@ DROP TABLE t1;
# #
SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1;
SET @@INSERT_ID=1; SET @@INSERT_ID=1;
SHOW VARIABLES LIKE "%auto_inc%"; SHOW VARIABLES LIKE "auto_inc%";
CREATE TABLE t1 (c1 DOUBLE NOT NULL AUTO_INCREMENT, c2 INT, PRIMARY KEY (c1)) ENGINE=InnoDB; CREATE TABLE t1 (c1 DOUBLE NOT NULL AUTO_INCREMENT, c2 INT, PRIMARY KEY (c1)) ENGINE=InnoDB;
INSERT INTO t1 VALUES(NULL, 1); INSERT INTO t1 VALUES(NULL, 1);
INSERT INTO t1 VALUES(NULL, 2); INSERT INTO t1 VALUES(NULL, 2);

View File

@ -0,0 +1,516 @@
-- source include/have_innodb.inc
SET @save_innodb_file_format_check=@@global.innodb_file_format_check;
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;
call mtr.add_suppression(" table `test`\\.`t1#[12]` already exists in InnoDB internal");
--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 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;
SET GLOBAL innodb_file_format_check=@save_innodb_file_format_check;

View File

@ -0,0 +1,5 @@
-- source include/have_innodb.inc
-- source include/have_ucs2.inc
-- let charset = ucs2
-- source include/innodb-index.inc

View File

@ -0,0 +1,64 @@
-- source include/have_innodb.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;

View File

@ -0,0 +1,2 @@
--innodb-use-sys-malloc=true
--innodb-use-sys-malloc=true

View File

@ -0,0 +1,48 @@
--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;
--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;

View File

@ -0,0 +1,347 @@
-- source include/have_innodb.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;
# The maximum key size for a compressed row actually depends on the
# version of libz used, as account must be taken for the maximum
# compressed size of a key, and this differs between libz
# versions. Some libz versions allow a size of 439, some only 438.
CREATE TABLE t1(c TEXT, PRIMARY KEY (c(438)))
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;

View File

@ -1126,7 +1126,7 @@ show create table t2;
create index id2 on t2 (id); create index id2 on t2 (id);
show create table t2; show create table t2;
drop index id2 on t2; drop index id2 on t2;
--error 1025,1025 --error ER_DROP_INDEX_FK
drop index id on t2; drop index id on t2;
show create table t2; show create table t2;
drop table t2; drop table t2;
@ -1294,6 +1294,7 @@ drop table t1;
# Test for testable InnoDB status variables. This test # Test for testable InnoDB status variables. This test
# uses previous ones(pages_created, rows_deleted, ...). # uses previous ones(pages_created, rows_deleted, ...).
--replace_result 512 511
show status like "Innodb_buffer_pool_pages_total"; show status like "Innodb_buffer_pool_pages_total";
show status like "Innodb_page_size"; show status like "Innodb_page_size";
show status like "Innodb_rows_deleted"; show status like "Innodb_rows_deleted";
@ -2357,6 +2358,7 @@ DROP TABLE t1,t2;
# #
# Bug #21101 (Prints wrong error message if max row size is too large) # Bug #21101 (Prints wrong error message if max row size is too large)
# #
set innodb_strict_mode=on;
--error 1118 --error 1118
CREATE TABLE t1 ( CREATE TABLE t1 (
c01 CHAR(255), c02 CHAR(255), c03 CHAR(255), c04 CHAR(255), c01 CHAR(255), c02 CHAR(255), c03 CHAR(255), c04 CHAR(255),

View File

@ -9,6 +9,7 @@
-- disable_result_log -- disable_result_log
# set packet size and reconnect # set packet size and reconnect
SET @save_max_allowed_packet=@@global.max_allowed_packet;
SET @@global.max_allowed_packet=16777216; SET @@global.max_allowed_packet=16777216;
--connect (newconn, localhost, root,,) --connect (newconn, localhost, root,,)
@ -21,7 +22,6 @@ CREATE TABLE bug34300 (
INSERT INTO bug34300 VALUES ('xxx', repeat('a', 8459264), 'zzz'); INSERT INTO bug34300 VALUES ('xxx', repeat('a', 8459264), 'zzz');
-- enable_query_log
-- enable_result_log -- enable_result_log
SELECT f4, f8 FROM bug34300; SELECT f4, f8 FROM bug34300;
@ -31,11 +31,6 @@ ALTER TABLE bug34300 ADD COLUMN (f10 INT);
SELECT f4, f8 FROM bug34300; SELECT f4, f8 FROM bug34300;
DROP TABLE bug34300; DROP TABLE bug34300;
disconnect newconn; disconnect newconn;
connection default; connection default;
--disable_result_log SET @@global.max_allowed_packet=@save_max_allowed_packet;
--disable_query_log
SET @@global.max_allowed_packet=default;
--enable_result_log
--enable_query_log

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,33 @@
#
# Test case for bug 36172
#
-- source include/not_embedded.inc
-- source include/have_innodb.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 @save_innodb_file_format=@@global.innodb_file_format;
SET @save_innodb_file_format_check=@@global.innodb_file_format_check;
SET @save_innodb_file_per_table=@@global.innodb_file_per_table;
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;
SET GLOBAL innodb_file_format=@save_innodb_file_format;
SET GLOBAL innodb_file_format_check=@save_innodb_file_format_check;
SET GLOBAL innodb_file_per_table=@save_innodb_file_per_table;
DROP TABLE table0;

View File

@ -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;

View File

@ -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;

View File

@ -0,0 +1,145 @@
#
# Test that user data is correctly "visualized" in
# INFORMATION_SCHEMA.innodb_locks.lock_data
#
-- source include/have_innodb.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`;

View File

@ -0,0 +1,45 @@
-- source include/have_innodb.inc
SET @save_innodb_file_format=@@global.innodb_file_format;
SET @save_innodb_file_format_check=@@global.innodb_file_format_check;
SET @save_innodb_file_per_table=@@global.innodb_file_per_table;
SET GLOBAL innodb_file_format='Barracuda';
SET GLOBAL innodb_file_per_table=ON;
-- disable_query_log
-- disable_result_log
DROP TABLE IF EXISTS `test1`;
CREATE TABLE IF NOT EXISTS `test1` (
`a` int primary key auto_increment,
`b` int default 0,
`c` char(100) default 'testtest'
) ENGINE=InnoDB ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=8;
delimiter |;
CREATE PROCEDURE insert_many(p1 int)
BEGIN
SET @x = 0;
SET @y = 0;
REPEAT
insert into test1 set b=1;
SET @x = @x + 1;
SET @y = @y + 1;
IF @y >= 100 THEN
commit;
SET @y = 0;
END IF;
UNTIL @x >= p1 END REPEAT;
END|
delimiter ;|
call insert_many(100000);
DROP PROCEDURE insert_many;
# The bug is hangup at the following statement
ALTER TABLE test1 ENGINE=MyISAM;
SET GLOBAL innodb_file_format=@save_innodb_file_format;
SET GLOBAL innodb_file_format_check=@save_innodb_file_format_check;
SET GLOBAL innodb_file_per_table=@save_innodb_file_per_table;
DROP TABLE test1;

View File

@ -23,6 +23,16 @@
# This is a big test. # This is a big test.
--source include/big_test.inc --source include/big_test.inc
--echo #
--echo # We need big packets.
--echo #
connect (con1, localhost, root,,);
connection con1;
SET @old_global_max_allowed_packet=@@global.max_allowed_packet;
SET @@global.max_allowed_packet= 1024*1024*1024;
connect (con2, localhost, root,,);
connection con2;
--echo # --echo #
--echo # Preparatory cleanup. --echo # Preparatory cleanup.
--echo # --echo #
@ -35,11 +45,6 @@ DROP TABLE IF EXISTS t1;
--echo # --echo #
SET timestamp=1000000000; SET timestamp=1000000000;
--echo #
--echo # We need big packets.
--echo #
SET @@global.max_allowed_packet= 1024*1024*1024;
--echo # --echo #
--echo # Delete all existing binary logs. --echo # Delete all existing binary logs.
--echo # --echo #
@ -122,9 +127,14 @@ let $MYSQLD_DATADIR= `select @@datadir`;
--echo # --echo #
DROP TABLE t1; DROP TABLE t1;
connection con1;
SET @@global.max_allowed_packet=@old_global_max_allowed_packet;
--echo remove_file \$MYSQLTEST_VARDIR/$mysqlbinlog_output --echo remove_file \$MYSQLTEST_VARDIR/$mysqlbinlog_output
# #
# NOTE: If you want to see the *huge* mysqlbinlog output, disable next line: # NOTE: If you want to see the *huge* mysqlbinlog output, disable next line:
# #
--remove_file $MYSQLTEST_VARDIR/$mysqlbinlog_output --remove_file $MYSQLTEST_VARDIR/$mysqlbinlog_output
disconnect con1
disconnect con2

View File

@ -27,14 +27,14 @@ UPDATE t1 SET DATA = data*2 WHERE id = 3;
# grouping/referencing in replace_regex is very slow on long strings, # grouping/referencing in replace_regex is very slow on long strings,
# removing all before/after the interesting row before grouping/referencing # removing all before/after the interesting row before grouping/referencing
--replace_regex /.*---TRANSACTION [0-9]+ [0-9]+, .*, OS thread id [0-9]+// /MySQL thread id [0-9]+, query id [0-9]+ .*// /.*([0-9]+ lock struct\(s\)), heap size [0-9]+, ([0-9]+ row lock\(s\)).*/\1 \2/ --replace_regex /.*LIST OF TRANSACTIONS FOR EACH SESSION:// /MySQL thread id [0-9]+, query id [0-9]+ .*// /.*([0-9]+ lock struct\(s\)), heap size [0-9]+, ([0-9]+ row lock\(s\)).*/\1 \2/
SHOW ENGINE InnoDB STATUS; SHOW ENGINE InnoDB STATUS;
UPDATE t1 SET data = data*2 WHERE data = 2; UPDATE t1 SET data = data*2 WHERE data = 2;
# grouping/referencing in replace_regex is very slow on long strings, # grouping/referencing in replace_regex is very slow on long strings,
# removing all before/after the interesting row before grouping/referencing # removing all before/after the interesting row before grouping/referencing
--replace_regex /.*---TRANSACTION [0-9]+ [0-9]+, .*, OS thread id [0-9]+// /MySQL thread id [0-9]+, query id [0-9]+ .*// /.*([0-9]+ lock struct\(s\)), heap size [0-9]+, ([0-9]+ row lock\(s\)).*/\1 \2/ --replace_regex /.*LIST OF TRANSACTIONS FOR EACH SESSION:// /MySQL thread id [0-9]+, query id [0-9]+ .*// /.*([0-9]+ lock struct\(s\)), heap size [0-9]+, ([0-9]+ row lock\(s\)).*/\1 \2/
SHOW ENGINE InnoDB STATUS; SHOW ENGINE InnoDB STATUS;
SET @@session.tx_isolation = @old_tx_isolation; SET @@session.tx_isolation = @old_tx_isolation;

View File

@ -41,7 +41,7 @@ create table t1 (a bit) engine=innodb;
insert into t1 values (b'0'), (b'1'), (b'000'), (b'100'), (b'001'); insert into t1 values (b'0'), (b'1'), (b'000'), (b'100'), (b'001');
select hex(a) from t1; select hex(a) from t1;
# It is not deterministic which duplicate will be seen first # It is not deterministic which duplicate will be seen first
--replace_regex /(.*Duplicate entry )'.*'( for key.*)/\1''\2/ --replace_regex /entry '(.*)' for/entry '' for/
--error ER_DUP_ENTRY --error ER_DUP_ENTRY
alter table t1 add unique (a); alter table t1 add unique (a);
drop table t1; drop table t1;

View File

@ -8,19 +8,20 @@
# Bug #27322 failure to allocate transaction_prealloc_size causes crash # Bug #27322 failure to allocate transaction_prealloc_size causes crash
# #
set @pid_temp = (select ID from information_schema.processlist);
set session transaction_prealloc_size=1024*1024*1024*1; set session transaction_prealloc_size=1024*1024*1024*1;
--replace_column 1 # --replace_column 1 #
show processlist; select @pid_temp = (select ID from information_schema.processlist) as 'TRUE';
set session transaction_prealloc_size=1024*1024*1024*2; set session transaction_prealloc_size=1024*1024*1024*2;
--replace_column 1 # --replace_column 1 #
show processlist; select @pid_temp = (select ID from information_schema.processlist) as 'TRUE';
--replace_column 1 # --replace_column 1 #
set session transaction_prealloc_size=1024*1024*1024*3; set session transaction_prealloc_size=1024*1024*1024*3;
--replace_column 1 # --replace_column 1 #
show processlist; select @pid_temp = (select ID from information_schema.processlist) as 'TRUE';
set session transaction_prealloc_size=1024*1024*1024*4; set session transaction_prealloc_size=1024*1024*1024*4;
--replace_column 1 # --replace_column 1 #
show processlist; select @pid_temp = (select ID from information_schema.processlist) as 'TRUE';
set session transaction_prealloc_size=1024*1024*1024*5; set session transaction_prealloc_size=1024*1024*1024*5;
--replace_column 1 # --replace_column 1 #
show processlist; select @pid_temp = (select ID from information_schema.processlist) as 'TRUE';

View File

@ -464,3 +464,52 @@ process_flags:
err: err:
return (size_t) -1; return (size_t) -1;
} }
int init_strvar_from_file(char *var, int max_size, IO_CACHE *f,
const char *default_val)
{
uint length;
DBUG_ENTER("init_strvar_from_file");
if ((length=my_b_gets(f,var, max_size)))
{
char* last_p = var + length -1;
if (*last_p == '\n')
*last_p = 0; /* if we stopped on newline, kill it */
else
{
/*
If we truncated a line or stopped on last char, remove all chars
up to and including newline.
*/
int c;
while (((c=my_b_get(f)) != '\n' && c != my_b_EOF))
;
}
DBUG_RETURN(0);
}
else if (default_val)
{
strmake(var, default_val, max_size-1);
DBUG_RETURN(0);
}
DBUG_RETURN(1);
}
int init_intvar_from_file(int* var, IO_CACHE* f, int default_val)
{
char buf[32];
DBUG_ENTER("init_intvar_from_file");
if (my_b_gets(f, buf, sizeof(buf)))
{
*var = atoi(buf);
DBUG_RETURN(0);
}
else if (default_val)
{
*var = default_val;
DBUG_RETURN(0);
}
DBUG_RETURN(1);
}

View File

@ -149,6 +149,35 @@ static inline void remove_from_active_list(safe_mutex_t *mp)
mp->prev= mp->next= 0; mp->prev= mp->next= 0;
} }
/*
We initialise the hashes for deadlock detection lazily.
This greatly helps with performance when lots of mutexes are initiased but
only a few of them are actually used (eg. XtraDB).
*/
static int safe_mutex_lazy_init_deadlock_detection(safe_mutex_t *mp)
{
if (!my_multi_malloc(MY_FAE | MY_WME,
&mp->locked_mutex, sizeof(*mp->locked_mutex),
&mp->used_mutex, sizeof(*mp->used_mutex), NullS))
{
return 1; /* Error */
}
pthread_mutex_lock(&THR_LOCK_mutex);
mp->id= ++safe_mutex_id;
pthread_mutex_unlock(&THR_LOCK_mutex);
hash_init(mp->locked_mutex, &my_charset_bin,
1000,
offsetof(safe_mutex_deadlock_t, id),
sizeof(mp->id),
0, 0, HASH_UNIQUE);
hash_init(mp->used_mutex, &my_charset_bin,
1000,
offsetof(safe_mutex_t, id),
sizeof(mp->id),
0, 0, HASH_UNIQUE);
return 0;
}
int safe_mutex_init(safe_mutex_t *mp, int safe_mutex_init(safe_mutex_t *mp,
const pthread_mutexattr_t *attr __attribute__((unused)), const pthread_mutexattr_t *attr __attribute__((unused)),
@ -167,35 +196,8 @@ int safe_mutex_init(safe_mutex_t *mp,
mp->line= line; mp->line= line;
/* Skip the very common '&' prefix from the autogenerated name */ /* Skip the very common '&' prefix from the autogenerated name */
mp->name= name[0] == '&' ? name + 1 : name; mp->name= name[0] == '&' ? name + 1 : name;
/* Deadlock detection is initialised only lazily, on first use. */
if (safe_mutex_deadlock_detector && !( my_flags & MYF_NO_DEADLOCK_DETECTION))
{
if (!my_multi_malloc(MY_FAE | MY_WME,
&mp->locked_mutex, sizeof(*mp->locked_mutex),
&mp->used_mutex, sizeof(*mp->used_mutex), NullS))
{
/* Disable deadlock handling for this mutex */
my_flags|= MYF_NO_DEADLOCK_DETECTION;
}
else
{
pthread_mutex_lock(&THR_LOCK_mutex);
mp->id= ++safe_mutex_id;
pthread_mutex_unlock(&THR_LOCK_mutex);
hash_init(mp->locked_mutex, &my_charset_bin,
1000,
offsetof(safe_mutex_deadlock_t, id),
sizeof(mp->id),
0, 0, HASH_UNIQUE);
hash_init(mp->used_mutex, &my_charset_bin,
1000,
offsetof(safe_mutex_t, id),
sizeof(mp->id),
0, 0, HASH_UNIQUE);
}
}
else
my_flags|= MYF_NO_DEADLOCK_DETECTION;
mp->create_flags= my_flags; mp->create_flags= my_flags;
#ifdef SAFE_MUTEX_DETECT_DESTROY #ifdef SAFE_MUTEX_DETECT_DESTROY
@ -310,7 +312,8 @@ int safe_mutex_lock(safe_mutex_t *mp, myf my_flags, const char *file,
/* Deadlock detection */ /* Deadlock detection */
mp->prev= mp->next= 0; mp->prev= mp->next= 0;
if (!(mp->active_flags & (MYF_TRY_LOCK | MYF_NO_DEADLOCK_DETECTION))) if (!(mp->active_flags & (MYF_TRY_LOCK | MYF_NO_DEADLOCK_DETECTION)) &&
(mp->used_mutex != NULL || !safe_mutex_lazy_init_deadlock_detection(mp)))
{ {
safe_mutex_t **mutex_in_use= my_thread_var_mutex_in_use(); safe_mutex_t **mutex_in_use= my_thread_var_mutex_in_use();
@ -643,7 +646,7 @@ int safe_mutex_destroy(safe_mutex_t *mp, const char *file, uint line)
void safe_mutex_free_deadlock_data(safe_mutex_t *mp) void safe_mutex_free_deadlock_data(safe_mutex_t *mp)
{ {
/* Free all entries that points to this one */ /* Free all entries that points to this one */
if (!(mp->create_flags & MYF_NO_DEADLOCK_DETECTION)) if (!(mp->create_flags & MYF_NO_DEADLOCK_DETECTION) && mp->used_mutex != NULL)
{ {
pthread_mutex_lock(&THR_LOCK_mutex); pthread_mutex_lock(&THR_LOCK_mutex);
my_hash_iterate(mp->used_mutex, my_hash_iterate(mp->used_mutex,

View File

@ -9313,3 +9313,29 @@ st_print_event_info::st_print_event_info()
open_cached_file(&body_cache, NULL, NULL, 0, flags); open_cached_file(&body_cache, NULL, NULL, 0, flags);
} }
#endif #endif
#if defined(MYSQL_SERVER)
/*
Access to the current replication position.
There is a dummy replacement for this in the embedded library that returns
FALSE; this is used by XtraDB to allow it to access replication stuff while
still being able to use the same plugin in both stand-alone and embedded.
*/
bool rpl_get_position_info(const char **log_file_name, ulonglong *log_pos,
const char **group_relay_log_name,
ulonglong *relay_log_pos)
{
#if defined(EMBEDDED_LIBRARY) || !defined(HAVE_REPLICATION)
return FALSE;
#else
const Relay_log_info *rli= &(active_mi->rli);
*log_file_name= rli->group_master_log_name;
*log_pos= rli->group_master_log_pos +
(rli->future_event_relay_log_pos - rli->group_relay_log_pos);
*group_relay_log_name= rli->group_relay_log_name;
*relay_log_pos= rli->future_event_relay_log_pos;
return TRUE;
#endif
}
#endif

View File

@ -3917,6 +3917,10 @@ static inline bool copy_event_cache_to_file_and_reinit(IO_CACHE *cache,
reinit_io_cache(cache, WRITE_CACHE, 0, FALSE, TRUE); reinit_io_cache(cache, WRITE_CACHE, 0, FALSE, TRUE);
} }
bool rpl_get_position_info(const char **log_file_name, ulonglong *log_pos,
const char **group_relay_log_name,
ulonglong *relay_log_pos);
/** /**
@} (end of group Replication) @} (end of group Replication)
*/ */

View File

@ -22,11 +22,6 @@
#ifdef HAVE_REPLICATION #ifdef HAVE_REPLICATION
// Defined in slave.cc
int init_intvar_from_file(int* var, IO_CACHE* f, int default_val);
int init_strvar_from_file(char *var, int max_size, IO_CACHE *f,
const char *default_val);
Master_info::Master_info() Master_info::Master_info()
:Slave_reporting_capability("I/O"), :Slave_reporting_capability("I/O"),
ssl(0), ssl_verify_server_cert(0), fd(-1), io_thd(0), inited(0), ssl(0), ssl_verify_server_cert(0), fd(-1), io_thd(0), inited(0),

View File

@ -23,11 +23,6 @@
static int count_relay_log_space(Relay_log_info* rli); static int count_relay_log_space(Relay_log_info* rli);
// Defined in slave.cc
int init_intvar_from_file(int* var, IO_CACHE* f, int default_val);
int init_strvar_from_file(char *var, int max_size, IO_CACHE *f,
const char *default_val);
Relay_log_info::Relay_log_info() Relay_log_info::Relay_log_info()
:Slave_reporting_capability("SQL"), :Slave_reporting_capability("SQL"),

View File

@ -755,57 +755,6 @@ const char *print_slave_db_safe(const char* db)
DBUG_RETURN((db ? db : "")); DBUG_RETURN((db ? db : ""));
} }
int init_strvar_from_file(char *var, int max_size, IO_CACHE *f,
const char *default_val)
{
uint length;
DBUG_ENTER("init_strvar_from_file");
if ((length=my_b_gets(f,var, max_size)))
{
char* last_p = var + length -1;
if (*last_p == '\n')
*last_p = 0; // if we stopped on newline, kill it
else
{
/*
If we truncated a line or stopped on last char, remove all chars
up to and including newline.
*/
int c;
while (((c=my_b_get(f)) != '\n' && c != my_b_EOF))
;
}
DBUG_RETURN(0);
}
else if (default_val)
{
strmake(var, default_val, max_size-1);
DBUG_RETURN(0);
}
DBUG_RETURN(1);
}
int init_intvar_from_file(int* var, IO_CACHE* f, int default_val)
{
char buf[32];
DBUG_ENTER("init_intvar_from_file");
if (my_b_gets(f, buf, sizeof(buf)))
{
*var = atoi(buf);
DBUG_RETURN(0);
}
else if (default_val)
{
*var = default_val;
DBUG_RETURN(0);
}
DBUG_RETURN(1);
}
/* /*
Note that we rely on the master's version (3.23, 4.0.14 etc) instead of Note that we rely on the master's version (3.23, 4.0.14 etc) instead of
relying on the binlog's version. This is not perfect: imagine an upgrade relying on the binlog's version. This is not perfect: imagine an upgrade

View File

@ -0,0 +1,97 @@
# 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(-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/xtradb/mem/mem0mem.c
${CMAKE_SOURCE_DIR}/storage/xtradb/mem/mem0pool.c
PROPERTIES COMPILE_FLAGS -Od)
ENDIF(CMAKE_GENERATOR MATCHES "Visual Studio" AND CMAKE_SIZEOF_VOID_P MATCHES 8)
INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/zlib
${CMAKE_SOURCE_DIR}/storage/xtradb/include
${CMAKE_SOURCE_DIR}/storage/xtradb/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/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)
IF(NOT SOURCE_SUBLIBS)
ADD_LIBRARY(innobase ${INNOBASE_SOURCES})
ADD_DEPENDENCIES(innobase GenError)
SET_TARGET_PROPERTIES(innobase PROPERTIES COMPILE_FLAGS "-DMYSQL_SERVER")
IF(INNODB_DYNAMIC_PLUGIN)
# The dynamic plugin requires CMake 2.6.0 or later. Otherwise, the /DELAYLOAD property
# will not be set
CMAKE_MINIMUM_REQUIRED(VERSION 2.6.0 FATAL_ERROR)
ADD_LIBRARY(ha_innodb SHARED ${INNOBASE_SOURCES} ha_innodb.def handler/win_delay_loader.cc)
ADD_DEPENDENCIES(ha_innodb GenError mysqld)
# If build type is not specified as Release, default to Debug
# This is a workaround to a problem in CMake 2.6, which does not
# set the path of mysqld.lib correctly
IF(CMAKE_BUILD_TYPE MATCHES Release)
SET(CMAKE_BUILD_TYPE "Release")
ELSE(CMAKE_BUILD_TYPE MATCHES Release)
SET(CMAKE_BUILD_TYPE "Debug")
ENDIF(CMAKE_BUILD_TYPE MATCHES Release)
TARGET_LINK_LIBRARIES(ha_innodb strings zlib)
TARGET_LINK_LIBRARIES(ha_innodb ${CMAKE_SOURCE_DIR}/sql/${CMAKE_BUILD_TYPE}/mysqld.lib)
SET_TARGET_PROPERTIES(ha_innodb PROPERTIES OUTPUT_NAME ha_innodb)
SET_TARGET_PROPERTIES(ha_innodb PROPERTIES LINK_FLAGS "/MAP /MAPINFO:EXPORTS")
SET_TARGET_PROPERTIES(ha_innodb PROPERTIES LINK_FLAGS "/ENTRY:\"_DllMainCRTStartup@12\"")
SET_TARGET_PROPERTIES(ha_innodb PROPERTIES COMPILE_FLAGS "-DMYSQL_DYNAMIC_PLUGIN")
SET_TARGET_PROPERTIES(ha_innodb PROPERTIES LINK_FLAGS "/DELAYLOAD:mysqld.exe")
ENDIF(INNODB_DYNAMIC_PLUGIN)
ENDIF(NOT SOURCE_SUBLIBS)

View File

@ -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.

775
storage/xtradb/ChangeLog Normal file
View File

@ -0,0 +1,775 @@
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

195
storage/xtradb/Makefile.am Normal file
View File

@ -0,0 +1,195 @@
# 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/xtradb/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/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/fut0fut.h \
include/fut0fut.ic include/fut0lst.h \
include/fut0lst.ic include/ha0ha.h \
include/ha0ha.ic \
include/ha0storage.h \
include/ha0storage.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/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/page0zip.h include/page0zip.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/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/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 \
include/handler0alter.h \
handler/i_s.h handler/innodb_patch_info.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/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 \
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 \
handler/ha_innodb.cc handler/handler0alter.cc \
handler/i_s.cc \
handler/mysql_addons.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
# Don't update the files from bitkeeper
%::SCCS/s.%

3656
storage/xtradb/btr/btr0btr.c Normal file

File diff suppressed because it is too large Load Diff

4809
storage/xtradb/btr/btr0cur.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,584 @@
/*****************************************************************************
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
*****************************************************************************/
/******************************************************
The index tree persistent cursor
Created 2/23/1996 Heikki Tuuri
*******************************************************/
#include "btr0pcur.h"
#ifdef UNIV_NONINL
#include "btr0pcur.ic"
#endif
#include "ut0byte.h"
#include "rem0cmp.h"
#include "trx0trx.h"
/******************************************************************
Allocates memory for a persistent cursor object and initializes the cursor. */
UNIV_INTERN
btr_pcur_t*
btr_pcur_create_for_mysql(void)
/*============================*/
/* out, own: persistent cursor */
{
btr_pcur_t* pcur;
pcur = mem_alloc(sizeof(btr_pcur_t));
pcur->btr_cur.index = NULL;
btr_pcur_init(pcur);
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 */
{
if (cursor->old_rec_buf != NULL) {
mem_free(cursor->old_rec_buf);
cursor->old_rec_buf = NULL;
}
cursor->btr_cur.page_cur.rec = NULL;
cursor->old_rec = NULL;
cursor->old_n_fields = 0;
cursor->old_stored = BTR_PCUR_OLD_NOT_STORED;
cursor->latch_mode = BTR_NO_LATCHES;
cursor->pos_state = BTR_PCUR_NOT_POSITIONED;
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 */
{
page_cur_t* page_cursor;
buf_block_t* block;
rec_t* rec;
dict_index_t* index;
page_t* page;
ulint offs;
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);
rec = page_cur_get_rec(page_cursor);
page = page_align(rec);
offs = page_offset(rec);
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)) {
/* It must be an empty index tree; NOTE that in this case
we do not store the modify_clock, but always do a search
if we restore the cursor position */
ut_a(btr_page_get_next(page, mtr) == FIL_NULL);
ut_a(btr_page_get_prev(page, mtr) == FIL_NULL);
cursor->old_stored = BTR_PCUR_OLD_STORED;
if (page_rec_is_supremum_low(offs)) {
cursor->rel_pos = BTR_PCUR_AFTER_LAST_IN_TREE;
} else {
cursor->rel_pos = BTR_PCUR_BEFORE_FIRST_IN_TREE;
}
return;
}
if (page_rec_is_supremum_low(offs)) {
rec = page_rec_get_prev(rec);
cursor->rel_pos = BTR_PCUR_AFTER;
} else if (page_rec_is_infimum_low(offs)) {
rec = page_rec_get_next(rec);
cursor->rel_pos = BTR_PCUR_BEFORE;
} else {
cursor->rel_pos = BTR_PCUR_ON;
}
cursor->old_stored = BTR_PCUR_OLD_STORED;
cursor->old_rec = dict_index_copy_rec_order_prefix(
index, rec, &cursor->old_n_fields,
&cursor->old_rec_buf, &cursor->buf_size);
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
position info */
btr_pcur_t* pcur_donate) /* in: pcur from which the info is
copied */
{
if (pcur_receive->old_rec_buf) {
mem_free(pcur_receive->old_rec_buf);
}
ut_memcpy(pcur_receive, pcur_donate, sizeof(btr_pcur_t));
if (pcur_donate->old_rec_buf) {
pcur_receive->old_rec_buf = mem_alloc(pcur_donate->buf_size);
ut_memcpy(pcur_receive->old_rec_buf, pcur_donate->old_rec_buf,
pcur_donate->buf_size);
pcur_receive->old_rec = pcur_receive->old_rec_buf
+ (pcur_donate->old_rec - pcur_donate->old_rec_buf);
}
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
to the last record LESS OR EQUAL to the stored record;
(2) cursor was positioned on a page infimum record: restores the position to
the last record LESS than the user record which was the successor of the page
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. */
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 */
{
dict_index_t* index;
dtuple_t* tuple;
ulint mode;
ulint old_mode;
mem_heap_t* heap;
index = btr_cur_get_index(btr_pcur_get_btr_cur(cursor));
if (UNIV_UNLIKELY(cursor->old_stored != BTR_PCUR_OLD_STORED)
|| 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);
}
ut_error;
}
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 */
btr_cur_open_at_index_side(
cursor->rel_pos == BTR_PCUR_BEFORE_FIRST_IN_TREE,
index, latch_mode, btr_pcur_get_btr_cur(cursor), mtr);
cursor->block_when_stored = btr_pcur_get_block(cursor);
return(FALSE);
}
ut_a(cursor->old_rec);
ut_a(cursor->old_n_fields);
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,
cursor->modify_clock, mtr))) {
cursor->pos_state = BTR_PCUR_IS_POSITIONED;
buf_block_dbg_add_level(btr_pcur_get_block(cursor),
SYNC_TREE_NODE);
if (cursor->rel_pos == BTR_PCUR_ON) {
#ifdef UNIV_DEBUG
const rec_t* rec;
const ulint* offsets1;
const ulint* offsets2;
#endif /* UNIV_DEBUG */
cursor->latch_mode = latch_mode;
#ifdef UNIV_DEBUG
rec = btr_pcur_get_rec(cursor);
heap = mem_heap_create(256);
offsets1 = rec_get_offsets(
cursor->old_rec, index, NULL,
cursor->old_n_fields, &heap);
offsets2 = rec_get_offsets(
rec, index, NULL,
cursor->old_n_fields, &heap);
ut_ad(!cmp_rec_rec(cursor->old_rec,
rec, offsets1, offsets2,
index));
mem_heap_free(heap);
#endif /* UNIV_DEBUG */
return(TRUE);
}
return(FALSE);
}
}
/* If optimistic restoration did not succeed, open the cursor anew */
heap = mem_heap_create(256);
tuple = dict_index_build_data_tuple(index, cursor->old_rec,
cursor->old_n_fields, heap);
/* Save the old search mode of the cursor */
old_mode = cursor->search_mode;
if (UNIV_LIKELY(cursor->rel_pos == BTR_PCUR_ON)) {
mode = PAGE_CUR_LE;
} else if (cursor->rel_pos == BTR_PCUR_AFTER) {
mode = PAGE_CUR_G;
} else {
ut_ad(cursor->rel_pos == BTR_PCUR_BEFORE);
mode = PAGE_CUR_L;
}
btr_pcur_open_with_no_init(index, tuple, mode, latch_mode,
cursor, 0, mtr);
/* Restore the old search mode */
cursor->search_mode = old_mode;
if (cursor->rel_pos == BTR_PCUR_ON
&& 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,
NULL, ULINT_UNDEFINED, &heap))) {
/* We have to store the NEW value for the modify clock, since
the cursor can now be on a different page! But we can retain
the value of old_rec */
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;
mem_heap_free(heap);
return(TRUE);
}
mem_heap_free(heap);
/* We have to store new position information, modify_clock etc.,
to the cursor because it can now be on a different page, the record
under it may have been removed, etc. */
btr_pcur_store_position(cursor, mtr);
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 */
{
buf_block_t* block;
ut_a(cursor->pos_state == BTR_PCUR_IS_POSITIONED);
ut_ad(cursor->latch_mode != BTR_NO_LATCHES);
block = btr_pcur_get_block(cursor);
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
last record of the current page */
mtr_t* mtr) /* in: mtr */
{
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));
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_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_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(page_is_comp(next_page) == page_is_comp(page));
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(btr_pcur_get_block(cursor),
cursor->latch_mode, mtr);
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
latches and restores the cursor position again before returning. The
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
record of the current page */
mtr_t* mtr) /* in: mtr */
{
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));
ut_ad(!btr_pcur_is_before_first_in_tree(cursor, mtr));
latch_mode = cursor->latch_mode;
if (latch_mode == BTR_SEARCH_LEAF) {
latch_mode2 = BTR_SEARCH_PREV;
} else if (latch_mode == BTR_MODIFY_LEAF) {
latch_mode2 = BTR_MODIFY_PREV;
} else {
latch_mode2 = 0; /* To eliminate compiler warning */
ut_error;
}
btr_pcur_store_position(cursor, mtr);
mtr_commit(mtr);
mtr_start(mtr);
btr_pcur_restore_position(latch_mode2, cursor, mtr);
page = btr_pcur_get_page(cursor);
prev_page_no = btr_page_get_prev(page, mtr);
space = buf_block_get_space(btr_pcur_get_block(cursor));
if (prev_page_no == FIL_NULL) {
} else if (btr_pcur_is_before_first_on_page(cursor)) {
prev_block = btr_pcur_get_btr_cur(cursor)->left_block;
btr_leaf_page_release(btr_pcur_get_block(cursor),
latch_mode, mtr);
page_cur_set_after_last(prev_block,
btr_pcur_get_page_cur(cursor));
} 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_block = btr_pcur_get_btr_cur(cursor)->left_block;
btr_leaf_page_release(prev_block, latch_mode, mtr);
}
cursor->latch_mode = latch_mode;
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'. */
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
function may release the page latch */
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)) {
if (btr_pcur_is_before_first_in_tree(cursor, mtr)) {
return(FALSE);
}
btr_pcur_move_backward_from_page(cursor, mtr);
return(TRUE);
}
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 */
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
cursor */
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)) {
btr_pcur_move_to_next_user_rec(cursor, mtr);
}
} else {
ut_ad((mode == PAGE_CUR_LE) || (mode == PAGE_CUR_L));
/* Not implemented yet */
ut_error;
}
}

1872
storage/xtradb/btr/btr0sea.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,682 @@
/*****************************************************************************
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
*****************************************************************************/
/******************************************************
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. */
UNIV_INLINE
byte*
buf_buddy_get(
/*==========*/
/* out: the buddy relative of page */
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->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_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[]. */
static
void*
buf_buddy_alloc_zip(
/*================*/
/* out: allocated block, or NULL
if buf_pool->zip_free[] was empty */
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);
#if defined UNIV_DEBUG && !defined UNIV_DEBUG_VALGRIND
/* Valgrind would complain about accessing free memory. */
UT_LIST_VALIDATE(list, buf_page_t, buf_pool->zip_free[i]);
#endif /* UNIV_DEBUG && !UNIV_DEBUG_VALGRIND */
bpage = UT_LIST_GET_LAST(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));
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. */
static
void*
buf_buddy_alloc_from(
/*=================*/
/* out: allocated block */
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;
#if defined UNIV_DEBUG && !defined UNIV_DEBUG_VALGRIND
/* Valgrind would complain about accessing free memory. */
UT_LIST_VALIDATE(list, buf_page_t, buf_pool->zip_free[j]);
#endif /* UNIV_DEBUG && !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. */
UNIV_INTERN
void*
buf_buddy_alloc_low(
/*================*/
/* out: allocated block,
possibly NULL if lru==NULL */
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. */
static
ibool
buf_buddy_relocate_block(
/*=====================*/
/* out: TRUE if relocated */
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. */
static
ibool
buf_buddy_relocate(
/*===============*/
/* out: TRUE if relocated */
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[] */
{
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]));
#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);
#if defined UNIV_DEBUG && !defined UNIV_DEBUG_VALGRIND
{
const buf_page_t* b;
/* 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.)*/
for (b = UT_LIST_GET_FIRST(buf_pool->zip_free[i]);
b; b = UT_LIST_GET_NEXT(list, b)) {
ut_a(b != buddy);
}
}
#endif /* UNIV_DEBUG && !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);
}

3920
storage/xtradb/buf/buf0buf.c Normal file

File diff suppressed because it is too large Load Diff

1277
storage/xtradb/buf/buf0flu.c Normal file

File diff suppressed because it is too large Load Diff

2060
storage/xtradb/buf/buf0lru.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,818 @@
/*****************************************************************************
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
*****************************************************************************/
/******************************************************
The database buffer read
Created 11/5/1995 Heikki Tuuri
*******************************************************/
#include "buf0rea.h"
#include "fil0fil.h"
#include "mtr0mtr.h"
#include "buf0buf.h"
#include "buf0flu.h"
#include "buf0lru.h"
#include "ibuf0ibuf.h"
#include "log0recv.h"
#include "trx0sys.h"
#include "os0file.h"
#include "srv0start.h"
extern ulint srv_read_ahead;
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 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
a random read-ahead */
#define BUF_READ_AHEAD_RANDOM_THRESHOLD (5 + buf_read_ahead_random_area / 8)
/* The linear read-ahead area size */
#define BUF_READ_AHEAD_LINEAR_AREA BUF_READ_AHEAD_AREA
/* The linear read-ahead threshold */
#define LINEAR_AREA_THRESHOLD_COEF 5 / 8
/* 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. */
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
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, ...,
ORed to OS_AIO_SIMULATED_WAKE_LATER (see below
at read-ahead functions) */
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 */
{
buf_page_t* bpage;
ulint wake_later;
*err = DB_SUCCESS;
wake_later = mode & OS_AIO_SIMULATED_WAKE_LATER;
mode = mode & ~OS_AIO_SIMULATED_WAKE_LATER;
if (trx_doublewrite && space == TRX_SYS_SPACE
&& ( (offset >= trx_doublewrite->block1
&& offset < trx_doublewrite->block1
+ TRX_SYS_DOUBLEWRITE_BLOCK_SIZE)
|| (offset >= trx_doublewrite->block2
&& offset < trx_doublewrite->block2
+ TRX_SYS_DOUBLEWRITE_BLOCK_SIZE))) {
ut_print_timestamp(stderr);
fprintf(stderr,
" InnoDB: Warning: trying to read"
" doublewrite buffer page %lu\n",
(ulong) offset);
return(0);
}
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
i/o-thread. Ibuf bitmap pages must always be read with
syncronous i/o, to make sure they do not get involved in
thread deadlocks. */
sync = TRUE;
}
/* The following call will also check if the tablespace does not exist
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 */
bpage = buf_page_init_for_read(err, mode, space, zip_size, unzip,
tablespace_version, offset);
if (bpage == NULL) {
return(0);
}
#ifdef UNIV_DEBUG
if (buf_debug_prints) {
fprintf(stderr,
"Posting read request for page %lu, sync %lu\n",
(ulong) offset,
(ulong) sync);
}
#endif
ut_ad(buf_page_in_file(bpage));
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(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
mechanism is not activated. NOTE 1: the calling thread may own latches on
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. */
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 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_int64_t tablespace_version;
ulint recent_blocks = 0;
ulint count;
ulint LRU_recent_limit;
ulint ibuf_mode;
ulint low, high;
ulint err;
ulint i;
ulint buf_read_ahead_random_area;
if (!(srv_read_ahead & 1)) {
return(0);
}
if (srv_startup_is_before_trx_rollback_phase) {
/* No read-ahead to avoid thread deadlocks */
return(0);
}
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
order */
return(0);
}
/* Remember the tablespace version before we ask te tablespace size
below: if DISCARD + IMPORT changes the actual .ibd file meanwhile, we
do not try to read outside the bounds of the tablespace! */
tablespace_version = fil_space_get_version(space);
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);
}
/* Get the minimum LRU_position field value for an initial segment
of the LRU list, to determine which blocks have recently been added
to the start of the list. */
LRU_recent_limit = buf_LRU_get_recent_limit();
buf_pool_mutex_enter();
if (buf_pool->n_pend_reads
> buf_pool->curr_size / BUF_READ_AHEAD_PEND_LIMIT) {
buf_pool_mutex_exit();
return(0);
}
/* Count how many blocks in the area have been recently accessed,
that is, reside near the start of the LRU list. */
for (i = low; i < high; i++) {
const buf_page_t* bpage = buf_page_hash_get(space, i);
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;
}
}
}
buf_pool_mutex_exit();
/* Do nothing */
return(0);
read_ahead:
/* Read all the suitable blocks within the area */
if (ibuf_inside()) {
ibuf_mode = BUF_READ_IBUF_PAGES_ONLY;
} else {
ibuf_mode = BUF_READ_ANY_PAGE;
}
count = 0;
for (i = low; i < high; i++) {
/* It is only sensible to do read-ahead in the non-sync aio
mode: hence FALSE as the first parameter */
if (!ibuf_bitmap_page(zip_size, i)) {
count += buf_read_page_low(
&err, FALSE,
ibuf_mode | OS_AIO_SIMULATED_WAKE_LATER,
space, zip_size, FALSE,
tablespace_version, i);
if (err == DB_TABLESPACE_DELETED) {
ut_print_timestamp(stderr);
fprintf(stderr,
" InnoDB: Warning: in random"
" readahead trying to access\n"
"InnoDB: tablespace %lu page %lu,\n"
"InnoDB: but the tablespace does not"
" exist or is just being dropped.\n",
(ulong) space, (ulong) i);
}
}
}
/* In simulated aio we wake the aio handler threads only after
queuing all aio requests, in native aio the following call does
nothing: */
os_aio_simulated_wake_handler_threads();
#ifdef UNIV_DEBUG
if (buf_debug_prints && (count > 0)) {
fprintf(stderr,
"Random read-ahead space %lu offset %lu pages %lu\n",
(ulong) space, (ulong) offset,
(ulong) count);
}
#endif /* UNIV_DEBUG */
++srv_read_ahead_rnd;
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. */
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 zip_size,/* in: compressed page size in bytes, or 0 */
ulint offset) /* in: page number */
{
ib_int64_t tablespace_version;
ulint count;
ulint count2;
ulint err;
tablespace_version = fil_space_get_version(space);
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) {
ut_print_timestamp(stderr);
fprintf(stderr,
" InnoDB: Error: trying to access"
" tablespace %lu page no. %lu,\n"
"InnoDB: but the tablespace does not exist"
" or is just being dropped.\n",
(ulong) space, (ulong) offset);
}
/* Flush pages from the end of the LRU list if necessary */
buf_flush_free_margin(FALSE);
/* 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
that the the algorithm looks at the 'natural' adjacent successor and
predecessor of the page, which on the leaf level of a B-tree are the next
and previous page in the chain of leaves. To know these, the page specified
in (space, offset) must already be present in the buf_pool. Thus, the
natural way to use this function is to call it when a page in the buf_pool
is accessed the first time, calling this function just after it has been
bufferfixed.
NOTE 1: as this function looks at the natural predecessor and successor
fields on the page, what happens, if these are not initialized to any
sensible value? No problem, before applying read-ahead we check that the
area to read is within the span of the space, if not, read-ahead is not
applied. An uninitialized value may result in a useless read operation, but
only very improbably.
NOTE 2: the calling thread may own latches on pages: to avoid deadlocks this
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. */
UNIV_INTERN
ulint
buf_read_ahead_linear(
/*==================*/
/* out: number of page read requests issued */
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_int64_t tablespace_version;
buf_page_t* bpage;
buf_frame_t* frame;
buf_page_t* pred_bpage = NULL;
ulint pred_offset;
ulint succ_offset;
ulint count;
int asc_or_desc;
ulint new_offset;
ulint fail_count;
ulint ibuf_mode;
ulint low, high;
ulint err;
ulint i;
const ulint buf_read_ahead_linear_area
= BUF_READ_AHEAD_LINEAR_AREA;
if (!(srv_read_ahead & 2)) {
return(0);
}
if (UNIV_UNLIKELY(srv_startup_is_before_trx_rollback_phase)) {
/* No read-ahead to avoid thread deadlocks */
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 ((offset != low) && (offset != high - 1)) {
/* This is not a border page of the area: return */
return(0);
}
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
order */
return(0);
}
/* Remember the tablespace version before we ask te tablespace size
below: if DISCARD + IMPORT changes the actual .ibd file meanwhile, we
do not try to read outside the bounds of the tablespace! */
tablespace_version = fil_space_get_version(space);
buf_pool_mutex_enter();
if (high > fil_space_get_size(space)) {
buf_pool_mutex_exit();
/* The area is not whole, return */
return(0);
}
if (buf_pool->n_pend_reads
> buf_pool->curr_size / BUF_READ_AHEAD_PEND_LIMIT) {
buf_pool_mutex_exit();
return(0);
}
/* Check that almost all pages in the area have been accessed; if
offset == low, the accesses must be in a descending order, otherwise,
in an ascending order. */
asc_or_desc = 1;
if (offset == low) {
asc_or_desc = -1;
}
fail_count = 0;
for (i = low; i < high; i++) {
bpage = buf_page_hash_get(space, i);
if ((bpage == NULL) || !buf_page_is_accessed(bpage)) {
/* Not accessed */
fail_count++;
} else if (pred_bpage
&& (ut_ulint_cmp(
buf_page_get_LRU_position(bpage),
buf_page_get_LRU_position(pred_bpage))
!= asc_or_desc)) {
/* Accesses not in the right order */
fail_count++;
pred_bpage = bpage;
}
}
if (fail_count > buf_read_ahead_linear_area
* LINEAR_AREA_THRESHOLD_COEF) {
/* Too many failures: return */
buf_pool_mutex_exit();
return(0);
}
/* 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 */
bpage = buf_page_hash_get(space, offset);
if (bpage == NULL) {
buf_pool_mutex_exit();
return(0);
}
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
on the page, we do not acquire an s-latch on the page, this is to
prevent deadlocks. Even if we read values which are nonsense, the
algorithm will work. */
pred_offset = fil_page_get_prev(frame);
succ_offset = fil_page_get_next(frame);
buf_pool_mutex_exit();
if ((offset == low) && (succ_offset == offset + 1)) {
/* This is ok, we can continue */
new_offset = pred_offset;
} else if ((offset == high - 1) && (pred_offset == offset - 1)) {
/* This is ok, we can continue */
new_offset = succ_offset;
} else {
/* Successor or predecessor not in the right order */
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;
if ((new_offset != low) && (new_offset != high - 1)) {
/* This is not a border page of the area: return */
return(0);
}
if (high > fil_space_get_size(space)) {
/* The area is not whole, return */
return(0);
}
/* If we got this far, read-ahead can be sensible: do it */
if (ibuf_inside()) {
ibuf_mode = BUF_READ_IBUF_PAGES_ONLY;
} else {
ibuf_mode = BUF_READ_ANY_PAGE;
}
count = 0;
/* Since Windows XP seems to schedule the i/o handler thread
very eagerly, and consequently it does not wait for the
full read batch to be posted, we use special heuristics here */
os_aio_simulated_put_read_threads_to_sleep();
for (i = low; i < high; i++) {
/* It is only sensible to do read-ahead in the non-sync
aio mode: hence FALSE as the first parameter */
if (!ibuf_bitmap_page(zip_size, i)) {
count += buf_read_page_low(
&err, FALSE,
ibuf_mode | OS_AIO_SIMULATED_WAKE_LATER,
space, zip_size, FALSE, tablespace_version, i);
if (err == DB_TABLESPACE_DELETED) {
ut_print_timestamp(stderr);
fprintf(stderr,
" InnoDB: Warning: in"
" linear readahead trying to access\n"
"InnoDB: tablespace %lu page %lu,\n"
"InnoDB: but the tablespace does not"
" exist or is just being dropped.\n",
(ulong) space, (ulong) i);
}
}
}
/* In simulated aio we wake the aio handler threads only after
queuing all aio requests, in native aio the following call does
nothing: */
os_aio_simulated_wake_handler_threads();
/* Flush pages from the end of the LRU list if necessary */
buf_flush_free_margin(FALSE);
#ifdef UNIV_DEBUG
if (buf_debug_prints && (count > 0)) {
fprintf(stderr,
"LINEAR read-ahead space %lu offset %lu pages %lu\n",
(ulong) space, (ulong) offset, (ulong) count);
}
#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 */
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 i;
ut_ad(!ibuf_inside());
#ifdef UNIV_IBUF_DEBUG
ut_a(n_stored < UNIV_PAGE_SIZE);
#endif
while (buf_pool->n_pend_reads
> buf_pool->curr_size / BUF_READ_AHEAD_PEND_LIMIT) {
os_thread_sleep(500000);
}
for (i = 0; i < n_stored; 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 (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],
zip_size, FALSE);
}
}
os_aio_simulated_wake_handler_threads();
/* Flush pages from the end of the LRU list if necessary */
buf_flush_free_margin(FALSE);
#ifdef UNIV_DEBUG
if (buf_debug_prints) {
fprintf(stderr,
"Ibuf merge read-ahead space %lu pages %lu\n",
(ulong) space_ids[0], (ulong) n_stored);
}
#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 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_int64_t tablespace_version;
ulint count;
ulint err;
ulint i;
zip_size = fil_space_get_zip_size(space);
tablespace_version = fil_space_get_version(space);
for (i = 0; i < n_stored; i++) {
count = 0;
os_aio_print_debug = FALSE;
while (buf_pool->n_pend_reads >= recv_n_pool_free_frames / 2) {
os_aio_simulated_wake_handler_threads();
os_thread_sleep(500000);
count++;
if (count > 100) {
fprintf(stderr,
"InnoDB: Error: InnoDB has waited for"
" 50 seconds for pending\n"
"InnoDB: reads to the buffer pool to"
" be finished.\n"
"InnoDB: Number of pending reads %lu,"
" pending pread calls %lu\n",
(ulong) buf_pool->n_pend_reads,
(ulong)os_file_n_pending_preads);
os_aio_print_debug = TRUE;
}
}
os_aio_print_debug = FALSE;
if ((i + 1 == n_stored) && sync) {
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, zip_size, TRUE,
tablespace_version, page_nos[i]);
}
}
os_aio_simulated_wake_handler_threads();
/* Flush pages from the end of the LRU list if necessary */
buf_flush_free_margin(FALSE);
#ifdef UNIV_DEBUG
if (buf_debug_prints) {
fprintf(stderr,
"Recovery applies read-ahead pages %lu\n",
(ulong) n_stored);
}
#endif /* UNIV_DEBUG */
}

View File

@ -0,0 +1,758 @@
/*****************************************************************************
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
*****************************************************************************/
/************************************************************************
SQL data field and tuple
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 "page0zip.h"
#include "dict0dict.h"
#include "btr0cur.h"
#include <ctype.h>
#ifdef UNIV_DEBUG
/* data pointers of tuple fields are initialized to point here
for error checking */
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 */
/*************************************************************************
Tests if dfield data length and content is equal to the given. */
UNIV_INTERN
ibool
dfield_data_is_binary_equal(
/*========================*/
/* out: TRUE if 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. */
UNIV_INTERN
int
dtuple_coll_cmp(
/*============*/
/* out: 1, 0 , -1 if tuple1 is greater, equal,
less, respectively, than tuple2 */
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. */
static
ibool
dfield_check_typed_no_assert(
/*=========================*/
/* out: TRUE if ok */
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. */
UNIV_INTERN
ibool
dtuple_check_typed_no_assert(
/*=========================*/
/* out: TRUE if ok */
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);
}
/**************************************************************
Checks that a data field is typed. Asserts an error if not. */
UNIV_INTERN
ibool
dfield_check_typed(
/*===============*/
/* out: TRUE if ok */
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. */
UNIV_INTERN
ibool
dtuple_check_typed(
/*===============*/
/* out: TRUE if ok */
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);
}
#ifdef UNIV_DEBUG
/**************************************************************
Validates the consistency of a tuple which must be complete, i.e,
all fields must have been set. */
UNIV_INTERN
ibool
dtuple_validate(
/*============*/
/* out: TRUE if ok */
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 */
/*****************************************************************
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. */
UNIV_INTERN
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 fixed-length or short fields
in entry or the index is clustered */
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);
}

View File

@ -0,0 +1,300 @@
/*****************************************************************************
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
*****************************************************************************/
/******************************************************
Data types
Created 1/16/1996 Heikki Tuuri
*******************************************************/
#include "data0type.h"
#ifdef UNIV_NONINL
#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! */
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
(this has to be divided by mbmaxlen to get the
number of CHARACTERS n in the prefix) */
ulint data_len, /* in: length of the string in bytes */
const char* str); /* in: character string */
/* At the database startup we store the default-charset collation number of
this MySQL installation to this global variable. If we have < 4.1.2 format
column definitions, or records in the insert buffer, we use this
charset-collation code for them. */
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. */
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
multi-byte character */
ulint mbmaxlen, /* in: maximum length of a
multi-byte character */
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
length is being determined */
{
#ifndef UNIV_HOTBACKUP
ut_a(data_len != UNIV_SQL_NULL);
ut_ad(!mbmaxlen || !(prefix_len % mbmaxlen));
if (mbminlen != mbmaxlen) {
ut_a(!(prefix_len % mbmaxlen));
return(innobase_get_at_most_n_mbchars(
dtype_get_charset_coll(prtype),
prefix_len, data_len, str));
}
if (prefix_len < data_len) {
return(prefix_len);
}
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 */
}
/*************************************************************************
Checks if a data main type is a string type. Also a BLOB is considered a
string type. */
UNIV_INTERN
ibool
dtype_is_string_type(
/*=================*/
/* out: TRUE if string type */
ulint mtype) /* in: InnoDB main data type code: DATA_CHAR, ... */
{
if (mtype <= DATA_BLOB
|| mtype == DATA_MYSQL
|| mtype == DATA_VARMYSQL) {
return(TRUE);
}
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. */
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 */
{
if ((mtype == DATA_FIXBINARY)
|| (mtype == DATA_BINARY)
|| (mtype == DATA_BLOB && (prtype & DATA_BINARY_TYPE))) {
return(TRUE);
}
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. */
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 */
{
if (dtype_is_string_type(mtype) == TRUE
&& dtype_is_binary_string_type(mtype, prtype) == FALSE) {
return(TRUE);
}
return(FALSE);
}
/*************************************************************************
Forms a precise type from the < 4.1.2 format precise type plus the
charset-collation code. */
UNIV_INTERN
ulint
dtype_form_prtype(
/*==============*/
ulint old_prtype, /* in: the MySQL type code and the flags
DATA_BINARY_TYPE etc. */
ulint charset_coll) /* in: MySQL charset-collation code */
{
ut_a(old_prtype < 256 * 256);
ut_a(charset_coll < 256);
return(old_prtype + (charset_coll << 16));
}
/*************************************************************************
Validates a data type structure. */
UNIV_INTERN
ibool
dtype_validate(
/*===========*/
/* out: TRUE if ok */
const dtype_t* type) /* in: type struct to validate */
{
ut_a(type);
ut_a(type->mtype >= DATA_VARCHAR);
ut_a(type->mtype <= DATA_MYSQL);
if (type->mtype == DATA_SYS) {
ut_a((type->prtype & DATA_MYSQL_TYPE_MASK) < DATA_N_SYS_COLS);
}
ut_a(type->mbminlen <= type->mbmaxlen);
return(TRUE);
}
/*************************************************************************
Prints a data type structure. */
UNIV_INTERN
void
dtype_print(
/*========*/
const dtype_t* type) /* in: type */
{
ulint mtype;
ulint prtype;
ulint len;
ut_a(type);
mtype = type->mtype;
prtype = type->prtype;
switch (mtype) {
case DATA_VARCHAR:
fputs("DATA_VARCHAR", stderr);
break;
case DATA_CHAR:
fputs("DATA_CHAR", stderr);
break;
case DATA_BINARY:
fputs("DATA_BINARY", stderr);
break;
case DATA_FIXBINARY:
fputs("DATA_FIXBINARY", stderr);
break;
case DATA_BLOB:
fputs("DATA_BLOB", stderr);
break;
case DATA_INT:
fputs("DATA_INT", stderr);
break;
case DATA_MYSQL:
fputs("DATA_MYSQL", stderr);
break;
case DATA_SYS:
fputs("DATA_SYS", stderr);
break;
default:
fprintf(stderr, "type %lu", (ulong) mtype);
break;
}
len = type->len;
if ((type->mtype == DATA_SYS)
|| (type->mtype == DATA_VARCHAR)
|| (type->mtype == DATA_CHAR)) {
putc(' ', stderr);
if (prtype == DATA_ROW_ID) {
fputs("DATA_ROW_ID", stderr);
len = DATA_ROW_ID_LEN;
} else if (prtype == DATA_ROLL_PTR) {
fputs("DATA_ROLL_PTR", stderr);
len = DATA_ROLL_PTR_LEN;
} else if (prtype == DATA_TRX_ID) {
fputs("DATA_TRX_ID", stderr);
len = DATA_TRX_ID_LEN;
} else if (prtype == DATA_ENGLISH) {
fputs("DATA_ENGLISH", stderr);
} else {
fprintf(stderr, "prtype %lu", (ulong) prtype);
}
} else {
if (prtype & DATA_UNSIGNED) {
fputs(" DATA_UNSIGNED", stderr);
}
if (prtype & DATA_BINARY_TYPE) {
fputs(" DATA_BINARY_TYPE", stderr);
}
if (prtype & DATA_NOT_NULL) {
fputs(" DATA_NOT_NULL", stderr);
}
}
fprintf(stderr, " len %lu", (ulong) len);
}

View File

@ -0,0 +1,462 @@
/*****************************************************************************
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
*****************************************************************************/
/******************************************************
Data dictionary creation and booting
Created 4/18/1996 Heikki Tuuri
*******************************************************/
#include "dict0boot.h"
#ifdef UNIV_NONINL
#include "dict0boot.ic"
#endif
#include "dict0crea.h"
#include "btr0btr.h"
#include "dict0load.h"
#include "dict0load.h"
#include "trx0trx.h"
#include "srv0srv.h"
#include "ibuf0ibuf.h"
#include "buf0flu.h"
#include "log0recv.h"
#include "os0file.h"
/**************************************************************************
Gets a pointer to the dictionary header and x-latches its page. */
UNIV_INTERN
dict_hdr_t*
dict_hdr_get(
/*=========*/
/* out: pointer to the dictionary header,
page x-latched */
mtr_t* mtr) /* in: mtr */
{
buf_block_t* block;
dict_hdr_t* header;
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);
return(header);
}
/**************************************************************************
Returns a new table, index, or tree id. */
UNIV_INTERN
dulint
dict_hdr_get_new_id(
/*================*/
/* out: the new id */
ulint type) /* in: DICT_HDR_ROW_ID, ... */
{
dict_hdr_t* dict_hdr;
dulint id;
mtr_t mtr;
ut_ad((type == DICT_HDR_TABLE_ID) || (type == DICT_HDR_INDEX_ID));
mtr_start(&mtr);
dict_hdr = dict_hdr_get(&mtr);
id = mtr_read_dulint(dict_hdr + type, &mtr);
id = ut_dulint_add(id, 1);
mlog_write_dulint(dict_hdr + type, id, &mtr);
mtr_commit(&mtr);
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)
/*=======================*/
{
dict_hdr_t* dict_hdr;
dulint id;
mtr_t mtr;
ut_ad(mutex_own(&(dict_sys->mutex)));
id = dict_sys->row_id;
mtr_start(&mtr);
dict_hdr = dict_hdr_get(&mtr);
mlog_write_dulint(dict_hdr + DICT_HDR_ROW_ID, id, &mtr);
mtr_commit(&mtr);
}
/*********************************************************************
Creates the file page for the dictionary header. This function is
called only at the database creation. */
static
ibool
dict_hdr_create(
/*============*/
/* out: TRUE if succeed */
mtr_t* mtr) /* in: mtr */
{
buf_block_t* block;
dict_hdr_t* dict_header;
ulint root_page_no;
ut_ad(mtr);
/* Create the dictionary header file block in a new, allocated file
segment in the system tablespace */
block = fseg_create(DICT_HDR_SPACE, 0,
DICT_HDR + DICT_HDR_FSEG_HEADER, mtr);
ut_a(DICT_HDR_PAGE_NO == buf_block_get_page_no(block));
dict_header = dict_hdr_get(mtr);
/* Start counting row, table, index, and tree ids from
DICT_HDR_FIRST_ID */
mlog_write_dulint(dict_header + DICT_HDR_ROW_ID,
ut_dulint_create(0, DICT_HDR_FIRST_ID), mtr);
mlog_write_dulint(dict_header + DICT_HDR_TABLE_ID,
ut_dulint_create(0, DICT_HDR_FIRST_ID), mtr);
mlog_write_dulint(dict_header + DICT_HDR_INDEX_ID,
ut_dulint_create(0, DICT_HDR_FIRST_ID), mtr);
/* Obsolete, but we must initialize it to 0 anyway. */
mlog_write_dulint(dict_header + DICT_HDR_MIX_ID,
ut_dulint_create(0, DICT_HDR_FIRST_ID), mtr);
/* Create the B-tree roots for the clustered indexes of the basic
system tables */
/*--------------------------*/
root_page_no = btr_create(DICT_CLUSTERED | DICT_UNIQUE,
DICT_HDR_SPACE, 0, DICT_TABLES_ID,
srv_sys->dummy_ind1, mtr);
if (root_page_no == FIL_NULL) {
return(FALSE);
}
mlog_write_ulint(dict_header + DICT_HDR_TABLES, root_page_no,
MLOG_4BYTES, mtr);
/*--------------------------*/
root_page_no = btr_create(DICT_UNIQUE, DICT_HDR_SPACE, 0,
DICT_TABLE_IDS_ID,
srv_sys->dummy_ind1, mtr);
if (root_page_no == FIL_NULL) {
return(FALSE);
}
mlog_write_ulint(dict_header + DICT_HDR_TABLE_IDS, root_page_no,
MLOG_4BYTES, mtr);
/*--------------------------*/
root_page_no = btr_create(DICT_CLUSTERED | DICT_UNIQUE,
DICT_HDR_SPACE, 0, DICT_COLUMNS_ID,
srv_sys->dummy_ind1, mtr);
if (root_page_no == FIL_NULL) {
return(FALSE);
}
mlog_write_ulint(dict_header + DICT_HDR_COLUMNS, root_page_no,
MLOG_4BYTES, mtr);
/*--------------------------*/
root_page_no = btr_create(DICT_CLUSTERED | DICT_UNIQUE,
DICT_HDR_SPACE, 0, DICT_INDEXES_ID,
srv_sys->dummy_ind1, mtr);
if (root_page_no == FIL_NULL) {
return(FALSE);
}
mlog_write_ulint(dict_header + DICT_HDR_INDEXES, root_page_no,
MLOG_4BYTES, mtr);
/*--------------------------*/
root_page_no = btr_create(DICT_CLUSTERED | DICT_UNIQUE,
DICT_HDR_SPACE, 0, DICT_FIELDS_ID,
srv_sys->dummy_ind1, mtr);
if (root_page_no == FIL_NULL) {
return(FALSE);
}
mlog_write_ulint(dict_header + DICT_HDR_FIELDS, root_page_no,
MLOG_4BYTES, mtr);
/*--------------------------*/
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)
/*===========*/
{
dict_table_t* table;
dict_index_t* index;
dict_hdr_t* dict_hdr;
mem_heap_t* heap;
mtr_t mtr;
ulint error;
mtr_start(&mtr);
/* Create the hash tables etc. */
dict_init();
heap = mem_heap_create(450);
mutex_enter(&(dict_sys->mutex));
/* Get the dictionary header */
dict_hdr = dict_hdr_get(&mtr);
/* Because we only write new row ids to disk-based data structure
(dictionary header) when it is divisible by
DICT_HDR_ROW_ID_WRITE_MARGIN, in recovery we will not recover
the latest value of the row id counter. Therefore we advance
the counter at the database startup to avoid overlapping values.
Note that when a user after database startup first time asks for
a new row id, then because the counter is now divisible by
..._MARGIN, it will immediately be updated to the disk-based
header. */
dict_sys->row_id = ut_dulint_add(
ut_dulint_align_up(mtr_read_dulint(dict_hdr + DICT_HDR_ROW_ID,
&mtr),
DICT_HDR_ROW_ID_WRITE_MARGIN),
DICT_HDR_ROW_ID_WRITE_MARGIN);
/* Insert into the dictionary cache the descriptions of the basic
system tables */
/*-------------------------*/
table = dict_mem_table_create("SYS_TABLES", DICT_HDR_SPACE, 8, 0);
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);
dict_mem_table_add_col(table, heap, "CLUSTER_NAME", DATA_BINARY, 0, 0);
dict_mem_table_add_col(table, heap, "SPACE", DATA_INT, 0, 4);
table->id = DICT_TABLES_ID;
dict_table_add_to_cache(table, heap);
dict_sys->sys_tables = table;
mem_heap_empty(heap);
index = dict_mem_index_create("SYS_TABLES", "CLUST_IND",
DICT_HDR_SPACE,
DICT_UNIQUE | DICT_CLUSTERED, 1);
dict_mem_index_add_field(index, "NAME", 0);
index->id = DICT_TABLES_ID;
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",
DICT_HDR_SPACE, DICT_UNIQUE, 1);
dict_mem_index_add_field(index, "ID", 0);
index->id = DICT_TABLE_IDS_ID;
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);
dict_mem_table_add_col(table, heap, "TABLE_ID", DATA_BINARY, 0, 0);
dict_mem_table_add_col(table, heap, "POS", DATA_INT, 0, 4);
dict_mem_table_add_col(table, heap, "NAME", DATA_BINARY, 0, 0);
dict_mem_table_add_col(table, heap, "MTYPE", DATA_INT, 0, 4);
dict_mem_table_add_col(table, heap, "PRTYPE", DATA_INT, 0, 4);
dict_mem_table_add_col(table, heap, "LEN", DATA_INT, 0, 4);
dict_mem_table_add_col(table, heap, "PREC", DATA_INT, 0, 4);
table->id = DICT_COLUMNS_ID;
dict_table_add_to_cache(table, heap);
dict_sys->sys_columns = table;
mem_heap_empty(heap);
index = dict_mem_index_create("SYS_COLUMNS", "CLUST_IND",
DICT_HDR_SPACE,
DICT_UNIQUE | DICT_CLUSTERED, 2);
dict_mem_index_add_field(index, "TABLE_ID", 0);
dict_mem_index_add_field(index, "POS", 0);
index->id = DICT_COLUMNS_ID;
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);
dict_mem_table_add_col(table, heap, "TABLE_ID", DATA_BINARY, 0, 0);
dict_mem_table_add_col(table, heap, "ID", DATA_BINARY, 0, 0);
dict_mem_table_add_col(table, heap, "NAME", DATA_BINARY, 0, 0);
dict_mem_table_add_col(table, heap, "N_FIELDS", DATA_INT, 0, 4);
dict_mem_table_add_col(table, heap, "TYPE", DATA_INT, 0, 4);
dict_mem_table_add_col(table, heap, "SPACE", DATA_INT, 0, 4);
dict_mem_table_add_col(table, heap, "PAGE_NO", DATA_INT, 0, 4);
/* The '+ 2' below comes from the 2 system fields */
#if DICT_SYS_INDEXES_PAGE_NO_FIELD != 6 + 2
#error "DICT_SYS_INDEXES_PAGE_NO_FIELD != 6 + 2"
#endif
#if DICT_SYS_INDEXES_SPACE_NO_FIELD != 5 + 2
#error "DICT_SYS_INDEXES_SPACE_NO_FIELD != 5 + 2"
#endif
#if DICT_SYS_INDEXES_TYPE_FIELD != 4 + 2
#error "DICT_SYS_INDEXES_TYPE_FIELD != 4 + 2"
#endif
table->id = DICT_INDEXES_ID;
dict_table_add_to_cache(table, heap);
dict_sys->sys_indexes = table;
mem_heap_empty(heap);
index = dict_mem_index_create("SYS_INDEXES", "CLUST_IND",
DICT_HDR_SPACE,
DICT_UNIQUE | DICT_CLUSTERED, 2);
dict_mem_index_add_field(index, "TABLE_ID", 0);
dict_mem_index_add_field(index, "ID", 0);
index->id = DICT_INDEXES_ID;
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);
dict_mem_table_add_col(table, heap, "INDEX_ID", DATA_BINARY, 0, 0);
dict_mem_table_add_col(table, heap, "POS", DATA_INT, 0, 4);
dict_mem_table_add_col(table, heap, "COL_NAME", DATA_BINARY, 0, 0);
table->id = DICT_FIELDS_ID;
dict_table_add_to_cache(table, heap);
dict_sys->sys_fields = table;
mem_heap_free(heap);
index = dict_mem_index_create("SYS_FIELDS", "CLUST_IND",
DICT_HDR_SPACE,
DICT_UNIQUE | DICT_CLUSTERED, 2);
dict_mem_index_add_field(index, "INDEX_ID", 0);
dict_mem_index_add_field(index, "POS", 0);
index->id = DICT_FIELDS_ID;
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);
/*-------------------------*/
/* Initialize the insert buffer table and index for each tablespace */
ibuf_init_at_db_start();
/* Load definitions of other indexes on system tables */
dict_load_sys_table(dict_sys->sys_tables);
dict_load_sys_table(dict_sys->sys_columns);
dict_load_sys_table(dict_sys->sys_indexes);
dict_load_sys_table(dict_sys->sys_fields);
mutex_exit(&(dict_sys->mutex));
}
/*********************************************************************
Inserts the basic system table data into themselves in the database
creation. */
static
void
dict_insert_initial_data(void)
/*==========================*/
{
/* Does nothing yet */
}
/*********************************************************************
Creates and initializes the data dictionary at the database creation. */
UNIV_INTERN
void
dict_create(void)
/*=============*/
{
mtr_t mtr;
mtr_start(&mtr);
dict_hdr_create(&mtr);
mtr_commit(&mtr);
dict_boot();
dict_insert_initial_data();
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,308 @@
/*****************************************************************************
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
*****************************************************************************/
/**********************************************************************
Data dictionary memory object creation
Created 1/8/1996 Heikki Tuuri
***********************************************************************/
#include "dict0mem.h"
#ifdef UNIV_NONINL
#include "dict0mem.ic"
#endif
#include "rem0rec.h"
#include "data0type.h"
#include "mach0data.h"
#include "dict0dict.h"
#include "lock0lock.h"
#define DICT_HEAP_SIZE 100 /* initial memory heap size when
creating a table or index object */
/**************************************************************************
Creates a table memory 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
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 */
{
dict_table_t* table;
mem_heap_t* heap;
ut_ad(name);
ut_a(!(flags & (~0 << DICT_TF_BITS)));
heap = mem_heap_create(DICT_HEAP_SIZE);
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->space = (unsigned int) space;
table->n_cols = (unsigned int) (n_cols + DATA_N_SYS_COLS);
table->cols = mem_heap_alloc(heap, (n_cols + DATA_N_SYS_COLS)
* sizeof(dict_col_t));
table->autoinc_lock = mem_heap_alloc(heap, lock_get_size());
mutex_create(&table->autoinc_mutex, SYNC_DICT_AUTOINC_MUTEX);
table->autoinc = 0;
/* 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;
#ifdef UNIV_DEBUG
table->magic_n = DICT_TABLE_MAGIC_N;
#endif /* UNIV_DEBUG */
return(table);
}
/********************************************************************
Free a table memory object. */
UNIV_INTERN
void
dict_mem_table_free(
/*================*/
dict_table_t* table) /* in: table */
{
ut_ad(table);
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
ut_d(table->cached = FALSE);
mutex_free(&(table->autoinc_mutex));
mem_heap_free(table->heap);
}
/********************************************************************
Append 'name' to 'col_names' (@see dict_table_t::col_names). */
static
const char*
dict_add_col_name(
/*==============*/
/* out: new column names array */
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 old_len;
ulint new_len;
ulint total_len;
char* res;
ut_ad(!cols == !col_names);
/* Find out length of existing array. */
if (col_names) {
const char* s = col_names;
ulint i;
for (i = 0; i < cols; i++) {
s += strlen(s) + 1;
}
old_len = s - col_names;
} else {
old_len = 0;
}
new_len = strlen(name) + 1;
total_len = old_len + new_len;
res = mem_heap_alloc(heap, total_len);
if (old_len > 0) {
memcpy(res, col_names, old_len);
}
memcpy(res + old_len, name, new_len);
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_col_t* col;
ulint mbminlen;
ulint mbmaxlen;
ulint i;
ut_ad(table);
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
ut_ad(!heap == !name);
i = table->n_def++;
if (name) {
if (UNIV_UNLIKELY(table->n_def == table->n_cols)) {
heap = table->heap;
}
if (UNIV_LIKELY(i) && UNIV_UNLIKELY(!table->col_names)) {
/* All preceding column names are empty. */
char* s = mem_heap_zalloc(heap, table->n_def);
table->col_names = s;
}
table->col_names = dict_add_col_name(table->col_names,
i, name, heap);
}
col = dict_table_get_nth_col(table, i);
col->ind = (unsigned int) i;
col->ord_part = 0;
col->mtype = (unsigned int) mtype;
col->prtype = (unsigned int) prtype;
col->len = (unsigned int) len;
dtype_get_mblen(mtype, prtype, &mbminlen, &mbmaxlen);
col->mbminlen = (unsigned int) mbminlen;
col->mbmaxlen = (unsigned int) mbmaxlen;
}
/**************************************************************************
Creates an index memory 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
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 */
{
dict_index_t* index;
mem_heap_t* heap;
ut_ad(table_name && index_name);
heap = mem_heap_create(DICT_HEAP_SIZE);
index = mem_heap_zalloc(heap, sizeof(dict_index_t));
index->heap = heap;
index->type = type;
index->space = (unsigned int) space;
index->name = mem_heap_strdup(heap, index_name);
index->table_name = table_name;
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 */
#ifdef UNIV_DEBUG
index->magic_n = DICT_INDEX_MAGIC_N;
#endif /* UNIV_DEBUG */
return(index);
}
/**************************************************************************
Creates and initializes a foreign constraint memory object. */
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_zalloc(heap, sizeof(dict_foreign_t));
foreign->heap = heap;
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
in a MySQL index like
INDEX (textcol(25)) */
{
dict_field_t* field;
ut_ad(index);
ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
index->n_def++;
field = dict_index_get_nth_field(index, index->n_def - 1);
field->name = name;
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 */
{
ut_ad(index);
ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
mem_heap_free(index->heap);
}

View File

@ -0,0 +1,64 @@
/*****************************************************************************
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
*****************************************************************************/
/******************************************************
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. */
UNIV_INTERN
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);
}

View File

@ -0,0 +1,851 @@
/*****************************************************************************
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
*****************************************************************************/
/******************************************************
SQL evaluator: evaluates simple data structures, like expressions, in
a query graph
Created 12/29/1997 Heikki Tuuri
*******************************************************/
#include "eval0eval.h"
#ifdef UNIV_NONINL
#include "eval0eval.ic"
#endif
#include "data0data.h"
#include "row0sel.h"
/* 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 */
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. */
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
data field to point to the new buffer, and
len field equal to size */
ulint size) /* in: buffer size */
{
dfield_t* dfield;
byte* data;
ut_ad(que_node_get_type(node) == QUE_NODE_SYMBOL
|| que_node_get_type(node) == QUE_NODE_FUNC);
dfield = que_node_get_val(node);
data = dfield_get_data(dfield);
if (data && data != &eval_dummy) {
mem_free(data);
}
if (size == 0) {
data = &eval_dummy;
} else {
data = mem_alloc(size);
}
que_node_set_val_buf_size(node, size);
dfield_set_data(dfield, data, size);
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 */
{
dfield_t* dfield;
byte* data;
ut_ad(que_node_get_type(node) == QUE_NODE_SYMBOL
|| que_node_get_type(node) == QUE_NODE_FUNC);
dfield = que_node_get_val(node);
data = dfield_get_data(dfield);
if (que_node_get_val_buf_size(node) > 0) {
ut_a(data);
mem_free(data);
}
}
/*********************************************************************
Evaluates a comparison node. */
UNIV_INTERN
ibool
eval_cmp(
/*=====*/
/* out: the result of the comparison */
func_node_t* cmp_node) /* in: comparison node */
{
que_node_t* arg1;
que_node_t* arg2;
int res;
ibool val;
int func;
ut_ad(que_node_get_type(cmp_node) == QUE_NODE_FUNC);
arg1 = cmp_node->args;
arg2 = que_node_get_next(arg1);
res = cmp_dfield_dfield(que_node_get_val(arg1),
que_node_get_val(arg2));
val = TRUE;
func = cmp_node->func;
if (func == '=') {
if (res != 0) {
val = FALSE;
}
} else if (func == '<') {
if (res != -1) {
val = FALSE;
}
} else if (func == PARS_LE_TOKEN) {
if (res == 1) {
val = FALSE;
}
} else if (func == PARS_NE_TOKEN) {
if (res == 0) {
val = FALSE;
}
} else if (func == PARS_GE_TOKEN) {
if (res == -1) {
val = FALSE;
}
} else {
ut_ad(func == '>');
if (res != 1) {
val = FALSE;
}
}
eval_node_set_ibool_val(cmp_node, val);
return(val);
}
/*********************************************************************
Evaluates a logical operation node. */
UNIV_INLINE
void
eval_logical(
/*=========*/
func_node_t* logical_node) /* in: logical operation node */
{
que_node_t* arg1;
que_node_t* arg2;
ibool val1;
ibool val2 = 0; /* remove warning */
ibool val = 0; /* remove warning */
int func;
ut_ad(que_node_get_type(logical_node) == QUE_NODE_FUNC);
arg1 = logical_node->args;
arg2 = que_node_get_next(arg1); /* arg2 is NULL if func is 'NOT' */
val1 = eval_node_get_ibool_val(arg1);
if (arg2) {
val2 = eval_node_get_ibool_val(arg2);
}
func = logical_node->func;
if (func == PARS_AND_TOKEN) {
val = val1 & val2;
} else if (func == PARS_OR_TOKEN) {
val = val1 | val2;
} else if (func == PARS_NOT_TOKEN) {
val = TRUE - val1;
} else {
ut_error;
}
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 */
{
que_node_t* arg1;
que_node_t* arg2;
lint val1;
lint val2 = 0; /* remove warning */
lint val;
int func;
ut_ad(que_node_get_type(arith_node) == QUE_NODE_FUNC);
arg1 = arith_node->args;
arg2 = que_node_get_next(arg1); /* arg2 is NULL if func is unary '-' */
val1 = eval_node_get_int_val(arg1);
if (arg2) {
val2 = eval_node_get_int_val(arg2);
}
func = arith_node->func;
if (func == '+') {
val = val1 + val2;
} else if ((func == '-') && arg2) {
val = val1 - val2;
} else if (func == '-') {
val = -val1;
} else if (func == '*') {
val = val1 * val2;
} else {
ut_ad(func == '/');
val = val1 / val2;
}
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 */
{
que_node_t* arg;
lint val;
lint arg_val;
int func;
ut_ad(que_node_get_type(node) == QUE_NODE_FUNC);
val = eval_node_get_int_val(node);
func = node->func;
if (func == PARS_COUNT_TOKEN) {
val = val + 1;
} else {
ut_ad(func == PARS_SUM_TOKEN);
arg = node->args;
arg_val = eval_node_get_int_val(arg);
val = val + arg_val;
}
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 */
{
que_node_t* arg;
que_node_t* arg1;
que_node_t* arg2 = 0; /* remove warning (??? bug ???) */
lint int_val;
byte* data;
ulint len1;
ulint len2;
int func;
ulint i;
ut_ad(que_node_get_type(func_node) == QUE_NODE_FUNC);
arg1 = func_node->args;
if (arg1) {
arg2 = que_node_get_next(arg1);
}
func = func_node->func;
if (func == PARS_PRINTF_TOKEN) {
arg = arg1;
while (arg) {
dfield_print(que_node_get_val(arg));
arg = que_node_get_next(arg);
}
putc('\n', stderr);
} else if (func == PARS_ASSERT_TOKEN) {
if (!eval_node_get_ibool_val(arg1)) {
fputs("SQL assertion fails in a stored procedure!\n",
stderr);
}
ut_a(eval_node_get_ibool_val(arg1));
/* This function, or more precisely, a debug procedure,
returns no value */
} else if (func == PARS_RND_TOKEN) {
len1 = (ulint)eval_node_get_int_val(arg1);
len2 = (ulint)eval_node_get_int_val(arg2);
ut_ad(len2 >= len1);
if (len2 > len1) {
int_val = (lint) (len1
+ (eval_rnd % (len2 - len1 + 1)));
} else {
int_val = (lint) len1;
}
eval_rnd = ut_rnd_gen_next_ulint(eval_rnd);
eval_node_set_int_val(func_node, int_val);
} else if (func == PARS_RND_STR_TOKEN) {
len1 = (ulint)eval_node_get_int_val(arg1);
data = eval_node_ensure_val_buf(func_node, len1);
for (i = 0; i < len1; i++) {
data[i] = (byte)(97 + (eval_rnd % 3));
eval_rnd = ut_rnd_gen_next_ulint(eval_rnd);
}
} else {
ut_error;
}
}
/*********************************************************************
Evaluates a notfound-function node. */
UNIV_INLINE
void
eval_notfound(
/*==========*/
func_node_t* func_node) /* in: function node */
{
que_node_t* arg1;
que_node_t* arg2;
sym_node_t* cursor;
sel_node_t* sel_node;
ibool ibool_val;
arg1 = func_node->args;
arg2 = que_node_get_next(arg1);
ut_ad(func_node->func == PARS_NOTFOUND_TOKEN);
cursor = arg1;
ut_ad(que_node_get_type(cursor) == QUE_NODE_SYMBOL);
if (cursor->token_type == SYM_LIT) {
ut_ad(ut_memcmp(dfield_get_data(que_node_get_val(cursor)),
"SQL", 3) == 0);
sel_node = cursor->sym_table->query_graph->last_sel_node;
} else {
sel_node = cursor->alias->cursor_def;
}
if (sel_node->state == SEL_NODE_NO_MORE_ROWS) {
ibool_val = TRUE;
} else {
ibool_val = FALSE;
}
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 */
{
que_node_t* arg1;
que_node_t* arg2;
que_node_t* arg3;
dfield_t* dfield;
byte* str1;
ulint len1;
ulint len2;
arg1 = func_node->args;
arg2 = que_node_get_next(arg1);
ut_ad(func_node->func == PARS_SUBSTR_TOKEN);
arg3 = que_node_get_next(arg2);
str1 = dfield_get_data(que_node_get_val(arg1));
len1 = (ulint)eval_node_get_int_val(arg2);
len2 = (ulint)eval_node_get_int_val(arg3);
dfield = que_node_get_val(func_node);
dfield_set_data(dfield, str1 + len1, len2);
}
/*********************************************************************
Evaluates a replstr-procedure node. */
static
void
eval_replstr(
/*=========*/
func_node_t* func_node) /* in: function node */
{
que_node_t* arg1;
que_node_t* arg2;
que_node_t* arg3;
que_node_t* arg4;
byte* str1;
byte* str2;
ulint len1;
ulint len2;
arg1 = func_node->args;
arg2 = que_node_get_next(arg1);
ut_ad(que_node_get_type(arg1) == QUE_NODE_SYMBOL);
arg3 = que_node_get_next(arg2);
arg4 = que_node_get_next(arg3);
str1 = dfield_get_data(que_node_get_val(arg1));
str2 = dfield_get_data(que_node_get_val(arg2));
len1 = (ulint)eval_node_get_int_val(arg3);
len2 = (ulint)eval_node_get_int_val(arg4);
if ((dfield_get_len(que_node_get_val(arg1)) < len1 + len2)
|| (dfield_get_len(que_node_get_val(arg2)) < len2)) {
ut_error;
}
ut_memcpy(str1 + len1, str2, len2);
}
/*********************************************************************
Evaluates an instr-function node. */
static
void
eval_instr(
/*=======*/
func_node_t* func_node) /* in: function node */
{
que_node_t* arg1;
que_node_t* arg2;
dfield_t* dfield1;
dfield_t* dfield2;
lint int_val;
byte* str1;
byte* str2;
byte match_char;
ulint len1;
ulint len2;
ulint i;
ulint j;
arg1 = func_node->args;
arg2 = que_node_get_next(arg1);
dfield1 = que_node_get_val(arg1);
dfield2 = que_node_get_val(arg2);
str1 = dfield_get_data(dfield1);
str2 = dfield_get_data(dfield2);
len1 = dfield_get_len(dfield1);
len2 = dfield_get_len(dfield2);
if (len2 == 0) {
ut_error;
}
match_char = str2[0];
for (i = 0; i < len1; i++) {
/* In this outer loop, the number of matched characters is 0 */
if (str1[i] == match_char) {
if (i + len2 > len1) {
break;
}
for (j = 1;; j++) {
/* We have already matched j characters */
if (j == len2) {
int_val = i + 1;
goto match_found;
}
if (str1[i + j] != str2[j]) {
break;
}
}
}
}
int_val = 0;
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 */
{
que_node_t* arg1;
dfield_t* dfield;
byte* str1;
byte* str2;
ulint len1;
ulint int_val;
arg1 = func_node->args;
dfield = que_node_get_val(arg1);
str1 = dfield_get_data(dfield);
len1 = dfield_get_len(dfield);
if (len1 > 4) {
ut_error;
}
if (len1 == 4) {
str2 = str1;
} else {
int_val = 0;
str2 = (byte*)&int_val;
ut_memcpy(str2 + (4 - len1), str1, len1);
}
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 */
{
que_node_t* arg;
dfield_t* dfield;
byte* data;
ulint len;
ulint len1;
arg = func_node->args;
len = 0;
while (arg) {
len1 = dfield_get_len(que_node_get_val(arg));
len += len1;
arg = que_node_get_next(arg);
}
data = eval_node_ensure_val_buf(func_node, len);
arg = func_node->args;
len = 0;
while (arg) {
dfield = que_node_get_val(arg);
len1 = dfield_get_len(dfield);
ut_memcpy(data + len, dfield_get_data(dfield), len1);
len += len1;
arg = que_node_get_next(arg);
}
}
/*********************************************************************
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.
If the first argument is of some other type, this function converts it to
BINARY. */
UNIV_INLINE
void
eval_to_binary(
/*===========*/
func_node_t* func_node) /* in: function node */
{
que_node_t* arg1;
que_node_t* arg2;
dfield_t* dfield;
byte* str1;
ulint len;
ulint len1;
arg1 = func_node->args;
str1 = dfield_get_data(que_node_get_val(arg1));
if (dtype_get_mtype(que_node_get_data_type(arg1)) != DATA_INT) {
len = dfield_get_len(que_node_get_val(arg1));
dfield = que_node_get_val(func_node);
dfield_set_data(dfield, str1, len);
return;
}
arg2 = que_node_get_next(arg1);
len1 = (ulint)eval_node_get_int_val(arg2);
if (len1 > 4) {
ut_error;
}
dfield = que_node_get_val(func_node);
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 */
{
que_node_t* arg1;
lint int_val;
byte* data;
int func;
func = func_node->func;
arg1 = func_node->args;
if (func == PARS_LENGTH_TOKEN) {
int_val = (lint)dfield_get_len(que_node_get_val(arg1));
} else if (func == PARS_TO_CHAR_TOKEN) {
/* Convert number to character string as a
signed decimal integer. */
ulint uint_val;
int int_len;
int_val = eval_node_get_int_val(arg1);
/* Determine the length of the string. */
if (int_val == 0) {
int_len = 1; /* the number 0 occupies 1 byte */
} else {
int_len = 0;
if (int_val < 0) {
uint_val = ((ulint) -int_val - 1) + 1;
int_len++; /* reserve space for minus sign */
} else {
uint_val = (ulint) int_val;
}
for (; uint_val > 0; int_len++) {
uint_val /= 10;
}
}
/* allocate the string */
data = eval_node_ensure_val_buf(func_node, int_len + 1);
/* add terminating NUL character */
data[int_len] = 0;
/* convert the number */
if (int_val == 0) {
data[0] = '0';
} else {
int tmp;
if (int_val < 0) {
data[0] = '-'; /* preceding minus sign */
uint_val = ((ulint) -int_val - 1) + 1;
} else {
uint_val = (ulint) int_val;
}
for (tmp = int_len; uint_val > 0; uint_val /= 10) {
data[--tmp] = (byte)
('0' + (byte)(uint_val % 10));
}
}
dfield_set_len(que_node_get_val(func_node), int_len);
return;
} else if (func == PARS_TO_NUMBER_TOKEN) {
int_val = atoi((char*)
dfield_get_data(que_node_get_val(arg1)));
} else if (func == PARS_SYSDATE_TOKEN) {
int_val = (lint)ut_time();
} else {
eval_predefined_2(func_node);
return;
}
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 */
{
que_node_t* arg;
ulint class;
ulint func;
ut_ad(que_node_get_type(func_node) == QUE_NODE_FUNC);
class = func_node->class;
func = func_node->func;
arg = func_node->args;
/* Evaluate first the argument list */
while (arg) {
eval_exp(arg);
/* The functions are not defined for SQL null argument
values, except for eval_cmp and notfound */
if (dfield_is_null(que_node_get_val(arg))
&& (class != PARS_FUNC_CMP)
&& (func != PARS_NOTFOUND_TOKEN)
&& (func != PARS_PRINTF_TOKEN)) {
ut_error;
}
arg = que_node_get_next(arg);
}
if (class == PARS_FUNC_CMP) {
eval_cmp(func_node);
} else if (class == PARS_FUNC_ARITH) {
eval_arith(func_node);
} else if (class == PARS_FUNC_AGGREGATE) {
eval_aggregate(func_node);
} else if (class == PARS_FUNC_PREDEFINED) {
if (func == PARS_NOTFOUND_TOKEN) {
eval_notfound(func_node);
} else if (func == PARS_SUBSTR_TOKEN) {
eval_substr(func_node);
} else if (func == PARS_REPLSTR_TOKEN) {
eval_replstr(func_node);
} else if (func == PARS_INSTR_TOKEN) {
eval_instr(func_node);
} else if (func == PARS_BINARY_TO_NUMBER_TOKEN) {
eval_binary_to_number(func_node);
} else if (func == PARS_CONCAT_TOKEN) {
eval_concat(func_node);
} else if (func == PARS_TO_BINARY_TOKEN) {
eval_to_binary(func_node);
} else {
eval_predefined(func_node);
}
} else {
ut_ad(class == PARS_FUNC_LOGICAL);
eval_logical(func_node);
}
}

View File

@ -0,0 +1,294 @@
/*****************************************************************************
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
*****************************************************************************/
/******************************************************
Executes SQL stored procedures and their control structures
Created 1/20/1998 Heikki Tuuri
*******************************************************/
#include "eval0proc.h"
#ifdef UNIV_NONINL
#include "eval0proc.ic"
#endif
/**************************************************************************
Performs an execution step of an if-statement node. */
UNIV_INTERN
que_thr_t*
if_step(
/*====*/
/* out: query thread to run next or NULL */
que_thr_t* thr) /* in: query thread */
{
if_node_t* node;
elsif_node_t* elsif_node;
ut_ad(thr);
node = thr->run_node;
ut_ad(que_node_get_type(node) == QUE_NODE_IF);
if (thr->prev_node == que_node_get_parent(node)) {
/* Evaluate the condition */
eval_exp(node->cond);
if (eval_node_get_ibool_val(node->cond)) {
/* The condition evaluated to TRUE: start execution
from the first statement in the statement list */
thr->run_node = node->stat_list;
} else if (node->else_part) {
thr->run_node = node->else_part;
} else if (node->elsif_list) {
elsif_node = node->elsif_list;
for (;;) {
eval_exp(elsif_node->cond);
if (eval_node_get_ibool_val(
elsif_node->cond)) {
/* The condition evaluated to TRUE:
start execution from the first
statement in the statement list */
thr->run_node = elsif_node->stat_list;
break;
}
elsif_node = que_node_get_next(elsif_node);
if (elsif_node == NULL) {
thr->run_node = NULL;
break;
}
}
} else {
thr->run_node = NULL;
}
} 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 while-statement node. */
UNIV_INTERN
que_thr_t*
while_step(
/*=======*/
/* out: query thread to run next or NULL */
que_thr_t* thr) /* in: query thread */
{
while_node_t* node;
ut_ad(thr);
node = thr->run_node;
ut_ad(que_node_get_type(node) == QUE_NODE_WHILE);
ut_ad((thr->prev_node == que_node_get_parent(node))
|| (que_node_get_next(thr->prev_node) == NULL));
/* Evaluate the condition */
eval_exp(node->cond);
if (eval_node_get_ibool_val(node->cond)) {
/* The condition evaluated to TRUE: start execution
from the first statement in the statement list */
thr->run_node = node->stat_list;
} else {
thr->run_node = que_node_get_parent(node);
}
return(thr);
}
/**************************************************************************
Performs an execution step of an assignment statement node. */
UNIV_INTERN
que_thr_t*
assign_step(
/*========*/
/* out: query thread to run next or NULL */
que_thr_t* thr) /* in: query thread */
{
assign_node_t* node;
ut_ad(thr);
node = thr->run_node;
ut_ad(que_node_get_type(node) == QUE_NODE_ASSIGNMENT);
/* Evaluate the value to assign */
eval_exp(node->val);
eval_node_copy_val(node->var->alias, node->val);
thr->run_node = que_node_get_parent(node);
return(thr);
}
/**************************************************************************
Performs an execution step of a for-loop node. */
UNIV_INTERN
que_thr_t*
for_step(
/*=====*/
/* out: query thread to run next or NULL */
que_thr_t* thr) /* in: query thread */
{
for_node_t* node;
que_node_t* parent;
lint loop_var_value;
ut_ad(thr);
node = thr->run_node;
ut_ad(que_node_get_type(node) == QUE_NODE_FOR);
parent = que_node_get_parent(node);
if (thr->prev_node != parent) {
/* Move to the next statement */
thr->run_node = que_node_get_next(thr->prev_node);
if (thr->run_node != NULL) {
return(thr);
}
/* Increment the value of loop_var */
loop_var_value = 1 + eval_node_get_int_val(node->loop_var);
} else {
/* Initialize the loop */
eval_exp(node->loop_start_limit);
eval_exp(node->loop_end_limit);
loop_var_value = eval_node_get_int_val(node->loop_start_limit);
node->loop_end_value
= (int) eval_node_get_int_val(node->loop_end_limit);
}
/* Check if we should do another loop */
if (loop_var_value > node->loop_end_value) {
/* Enough loops done */
thr->run_node = parent;
} else {
eval_node_set_int_val(node->loop_var, loop_var_value);
thr->run_node = node->stat_list;
}
return(thr);
}
/**************************************************************************
Performs an execution step of an exit statement node. */
UNIV_INTERN
que_thr_t*
exit_step(
/*======*/
/* out: query thread to run next or NULL */
que_thr_t* thr) /* in: query thread */
{
exit_node_t* node;
que_node_t* loop_node;
ut_ad(thr);
node = thr->run_node;
ut_ad(que_node_get_type(node) == QUE_NODE_EXIT);
/* Loops exit by setting thr->run_node as the loop node's parent, so
find our containing loop node and get its parent. */
loop_node = que_node_get_containing_loop_node(node);
/* If someone uses an EXIT statement outside of a loop, this will
trigger. */
ut_a(loop_node);
thr->run_node = que_node_get_parent(loop_node);
return(thr);
}
/**************************************************************************
Performs an execution step of a return-statement node. */
UNIV_INTERN
que_thr_t*
return_step(
/*========*/
/* out: query thread to run next or NULL */
que_thr_t* thr) /* in: query thread */
{
return_node_t* node;
que_node_t* parent;
ut_ad(thr);
node = thr->run_node;
ut_ad(que_node_get_type(node) == QUE_NODE_RETURN);
parent = node;
while (que_node_get_type(parent) != QUE_NODE_PROC) {
parent = que_node_get_parent(parent);
}
ut_a(parent);
thr->run_node = que_node_get_parent(parent);
return(thr);
}

4817
storage/xtradb/fil/fil0fil.c Normal file

File diff suppressed because it is too large Load Diff

4284
storage/xtradb/fsp/fsp0fsp.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,30 @@
/*****************************************************************************
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-based utilities
Created 12/13/1995 Heikki Tuuri
***********************************************************************/
#include "fut0fut.h"
#ifdef UNIV_NONINL
#include "fut0fut.ic"
#endif

View File

@ -0,0 +1,529 @@
/*****************************************************************************
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-based list utilities
Created 11/28/1995 Heikki Tuuri
***********************************************************************/
#include "fut0lst.h"
#ifdef UNIV_NONINL
#include "fut0lst.ic"
#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
empty list */
flst_node_t* node, /* in: node to add */
mtr_t* mtr) /* in: mini-transaction handle */
{
ulint space;
fil_addr_t node_addr;
ulint len;
ut_ad(mtr && base && node);
ut_ad(base != node);
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);
buf_ptr_get_fsp_addr(node, &space, &node_addr);
/* Update first and last fields of base node */
flst_write_addr(base + FLST_FIRST, node_addr, mtr);
flst_write_addr(base + FLST_LAST, node_addr, mtr);
/* Set prev and next fields of node to add */
flst_write_addr(node + FLST_PREV, fil_addr_null, mtr);
flst_write_addr(node + FLST_NEXT, fil_addr_null, mtr);
/* Update len of base node */
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 */
{
ulint space;
fil_addr_t node_addr;
ulint len;
fil_addr_t last_addr;
flst_node_t* last_node;
ut_ad(mtr && base && node);
ut_ad(base != node);
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);
buf_ptr_get_fsp_addr(node, &space, &node_addr);
/* If the list is not empty, call flst_insert_after */
if (len != 0) {
if (last_addr.page == node_addr.page) {
last_node = page_align(node) + last_addr.boffset;
} else {
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);
} else {
/* else call flst_add_to_empty */
flst_add_to_empty(base, node, mtr);
}
}
/************************************************************************
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 */
{
ulint space;
fil_addr_t node_addr;
ulint len;
fil_addr_t first_addr;
flst_node_t* first_node;
ut_ad(mtr && base && node);
ut_ad(base != node);
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);
buf_ptr_get_fsp_addr(node, &space, &node_addr);
/* If the list is not empty, call flst_insert_before */
if (len != 0) {
if (first_addr.page == node_addr.page) {
first_node = page_align(node) + first_addr.boffset;
} else {
ulint zip_size = fil_space_get_zip_size(space);
first_node = fut_get_ptr(space, zip_size, first_addr,
RW_X_LATCH, mtr);
}
flst_insert_before(base, node, first_node, mtr);
} else {
/* else call flst_add_to_empty */
flst_add_to_empty(base, node, mtr);
}
}
/************************************************************************
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 */
{
ulint space;
fil_addr_t node1_addr;
fil_addr_t node2_addr;
flst_node_t* node3;
fil_addr_t node3_addr;
ulint len;
ut_ad(mtr && node1 && node2 && base);
ut_ad(base != node1);
ut_ad(base != node2);
ut_ad(node2 != node1);
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);
node3_addr = flst_get_next_addr(node1, mtr);
/* Set prev and next fields of node2 */
flst_write_addr(node2 + FLST_PREV, node1_addr, mtr);
flst_write_addr(node2 + FLST_NEXT, node3_addr, mtr);
if (!fil_addr_is_null(node3_addr)) {
/* Update prev field of node3 */
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 */
flst_write_addr(base + FLST_LAST, node2_addr, mtr);
}
/* Set next field of node1 */
flst_write_addr(node1 + FLST_NEXT, node2_addr, mtr);
/* Update len of base node */
len = flst_get_len(base, mtr);
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 */
{
ulint space;
flst_node_t* node1;
fil_addr_t node1_addr;
fil_addr_t node2_addr;
fil_addr_t node3_addr;
ulint len;
ut_ad(mtr && node2 && node3 && base);
ut_ad(base != node2);
ut_ad(base != node3);
ut_ad(node2 != node3);
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);
node1_addr = flst_get_prev_addr(node3, mtr);
/* Set prev and next fields of node2 */
flst_write_addr(node2 + FLST_PREV, node1_addr, mtr);
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, 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 */
flst_write_addr(base + FLST_FIRST, node2_addr, mtr);
}
/* Set prev field of node3 */
flst_write_addr(node3 + FLST_PREV, node2_addr, mtr);
/* Update len of base node */
len = flst_get_len(base, mtr);
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 */
{
ulint space;
ulint zip_size;
flst_node_t* node1;
fil_addr_t node1_addr;
fil_addr_t node2_addr;
flst_node_t* node3;
fil_addr_t node3_addr;
ulint len;
ut_ad(mtr && node2 && base);
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);
if (!fil_addr_is_null(node1_addr)) {
/* Update next field of node1 */
if (node1_addr.page == node2_addr.page) {
node1 = page_align(node2) + node1_addr.boffset;
} else {
node1 = fut_get_ptr(space, zip_size,
node1_addr, RW_X_LATCH, mtr);
}
ut_ad(node1 != node2);
flst_write_addr(node1 + FLST_NEXT, node3_addr, mtr);
} else {
/* node2 was first in list: update first field in base */
flst_write_addr(base + FLST_FIRST, node3_addr, mtr);
}
if (!fil_addr_is_null(node3_addr)) {
/* Update prev field of node3 */
if (node3_addr.page == node2_addr.page) {
node3 = page_align(node2) + node3_addr.boffset;
} else {
node3 = fut_get_ptr(space, zip_size,
node3_addr, RW_X_LATCH, mtr);
}
ut_ad(node2 != node3);
flst_write_addr(node3 + FLST_PREV, node1_addr, mtr);
} else {
/* node2 was last in list: update last field in base */
flst_write_addr(base + FLST_LAST, node1_addr, mtr);
}
/* Update len of base node */
len = flst_get_len(base, mtr);
ut_ad(len > 0);
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,
must be >= 1 */
mtr_t* mtr) /* in: mini-transaction handle */
{
ulint space;
flst_node_t* node1;
fil_addr_t node1_addr;
fil_addr_t node2_addr;
ulint len;
ut_ad(mtr && node2 && base);
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);
node1_addr = flst_get_prev_addr(node2, mtr);
if (!fil_addr_is_null(node1_addr)) {
/* Update next field of node1 */
if (node1_addr.page == node2_addr.page) {
node1 = page_align(node2) + node1_addr.boffset;
} else {
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);
} else {
/* node2 was first in list: update the field in base */
flst_write_addr(base + FLST_FIRST, fil_addr_null, mtr);
}
flst_write_addr(base + FLST_LAST, node1_addr, mtr);
/* Update len of base node */
len = flst_get_len(base, mtr);
ut_ad(len >= n_nodes);
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 */
{
fil_addr_t node2_addr;
ulint len;
ulint space;
ut_ad(mtr && node2 && base);
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)));
return;
}
buf_ptr_get_fsp_addr(node2, &space, &node2_addr);
/* Update next field of node2 */
flst_write_addr(node2 + FLST_NEXT, fil_addr_null, mtr);
flst_write_addr(base + FLST_LAST, node2_addr, mtr);
/* Update len of base node */
len = flst_get_len(base, mtr);
ut_ad(len >= n_nodes);
mlog_write_ulint(base + FLST_LEN, len - n_nodes, MLOG_4BYTES, mtr);
}
/************************************************************************
Validates a file-based list. */
UNIV_INTERN
ibool
flst_validate(
/*==========*/
/* out: TRUE if ok */
const flst_base_node_t* base, /* in: pointer to base node of list */
mtr_t* mtr1) /* in: mtr */
{
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_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
list. The second is used to traverse the list. We cannot run the
second mtr without committing it at times, because if the list
is long, then the x-locked pages could fill the buffer resulting
in a deadlock. */
/* 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);
for (i = 0; i < len; i++) {
mtr_start(&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
becoming full */
}
ut_a(fil_addr_is_null(node_addr));
node_addr = flst_get_last(base, mtr1);
for (i = 0; i < len; i++) {
mtr_start(&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
becoming full */
}
ut_a(fil_addr_is_null(node_addr));
return(TRUE);
}
/************************************************************************
Prints info of a file-based list. */
UNIV_INTERN
void
flst_print(
/*=======*/
const flst_base_node_t* base, /* in: pointer to base node of list */
mtr_t* mtr) /* in: mtr */
{
const buf_frame_t* frame;
ulint len;
ut_ad(base && mtr);
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) page_get_space_id(frame),
(ulong) page_get_page_no(frame),
(ulong) page_offset(base), (ulong) len);
}

442
storage/xtradb/ha/ha0ha.c Normal file
View File

@ -0,0 +1,442 @@
/*****************************************************************************
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
*****************************************************************************/
/************************************************************************
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 >= n array cells. The actual number of cells is
chosen to be a prime number slightly bigger than n. */
UNIV_INTERN
hash_table_t*
ha_create_func(
/*===========*/
/* out, own: created table */
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 defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
table->adaptive = TRUE;
#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);
}
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]);
}
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 */
/* Free the memory heaps. */
n = table->n_mutexes;
for (i = 0; i < n; i++) {
mem_heap_free(table->heaps[i]);
}
/* 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. */
UNIV_INTERN
ibool
ha_insert_for_fold_func(
/*====================*/
/* 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! */
#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 */
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 defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
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++;
}
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
if (table->adaptive) {
block->n_pointers++;
}
#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
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_AHI_DEBUG || UNIV_DEBUG */
HASH_DELETE_AND_COMPACT(ha_node_t, next, table, del_node);
}
/*****************************************************************
Deletes an entry from a hash table. */
UNIV_INTERN
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. */
UNIV_INTERN
void
ha_search_and_update_if_found_func(
/*===============================*/
hash_table_t* table, /* in: 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;
ut_ad(!table->mutexes || mutex_own(hash_get_mutex(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
if (table->adaptive) {
ut_a(node->block->n_pointers > 0);
node->block->n_pointers--;
new_block->n_pointers++;
}
node->block = new_block;
#endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
node->data = new_data;
}
}
/*********************************************************************
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;
ut_ad(!table->mutexes || mutex_own(hash_get_mutex(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. */
UNIV_INTERN
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. */
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);
}
}

View File

@ -0,0 +1,183 @@
/*****************************************************************************
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
*****************************************************************************/
/******************************************************
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 */

View File

@ -0,0 +1,165 @@
/*****************************************************************************
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
*****************************************************************************/
/******************************************************
The simple hash table utility
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. */
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);
}
}
/*****************************************************************
Creates a hash table with >= n array cells. The actual number of cells is
chosen to be a prime number slightly bigger than n. */
UNIV_INTERN
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;
prime = ut_find_prime(n);
table = mem_alloc(sizeof(hash_table_t));
array = ut_malloc(sizeof(hash_cell_t) * prime);
#if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
table->adaptive = FALSE;
#endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
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 */
hash_table_clear(table);
return(table);
}
/*****************************************************************
Frees a hash table. */
UNIV_INTERN
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. */
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;
}

View File

@ -0,0 +1,4 @@
EXPORTS
_mysql_plugin_interface_version_
_mysql_sizeof_struct_st_plugin_
_mysql_plugin_declarations_

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,283 @@
/*****************************************************************************
Copyright (c) 2000, 2009, MySQL AB & 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
*****************************************************************************/
/*
This file is based on ha_berkeley.h of MySQL distribution
This file defines the Innodb handler: the interface between MySQL and
Innodb
*/
#ifdef USE_PRAGMA_INTERFACE
#pragma interface /* gcc class implementation */
#endif
typedef struct st_innobase_share {
THR_LOCK lock;
pthread_mutex_t mutex;
const char* table_name;
uint use_count;
void* table_name_hash;
} INNOBASE_SHARE;
struct dict_index_struct;
struct row_prebuilt_struct;
typedef struct dict_index_struct dict_index_t;
typedef struct row_prebuilt_struct row_prebuilt_t;
/* The class defining a handle to an Innodb table */
class ha_innobase: public handler
{
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
currently using the handle; this is
set in external_lock function */
THR_LOCK_DATA lock;
INNOBASE_SHARE *share;
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;
/* the length of each of the previous
two buffers */
Table_flags int_table_flags;
uint primary_key;
ulong start_of_scan; /* this is set to 1 when we are
starting a table scan but have not
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 store_key_val_for_row(uint keynr, char* buff, uint buff_len,
const uchar* record);
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);
ulint innobase_lock_autoinc();
ulonglong innobase_peek_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();
/*
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;
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;
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();
int open(const char *name, int mode, uint test_if_locked);
int close(void);
double scan_time();
double read_time(uint index, uint ranges, ha_rows rows);
int write_row(uchar * buf);
int update_row(const uchar * old_data, uchar * new_data);
int delete_row(const uchar * buf);
bool was_semi_consistent_read();
void try_semi_consistent_read(bool yes);
void unlock_row();
#ifdef ROW_MERGE_IS_INDEX_USABLE
/** Check if an index can be used by this transaction.
* @param keynr key number to check
* @return true if available, false if the index
* does not contain old records that exist
* in the read view of this transaction */
bool is_index_available(uint keynr);
#endif /* ROW_MERGE_IS_INDEX_USABLE */
int index_init(uint index, bool sorted);
int index_end();
int index_read(uchar * buf, const uchar * key,
uint key_len, enum ha_rkey_function find_flag);
int index_read_idx(uchar * buf, uint index, const uchar * key,
uint key_len, enum ha_rkey_function find_flag);
int index_read_last(uchar * buf, const uchar * key, uint key_len);
int index_next(uchar * buf);
int index_next_same(uchar * buf, const uchar *key, uint keylen);
int index_prev(uchar * buf);
int index_first(uchar * buf);
int index_last(uchar * buf);
int rnd_init(bool scan);
int rnd_end();
int rnd_next(uchar *buf);
int rnd_pos(uchar * buf, uchar *pos);
void position(const uchar *record);
int info(uint);
int analyze(THD* thd,HA_CHECK_OPT* check_opt);
int optimize(THD* thd,HA_CHECK_OPT* check_opt);
int discard_or_import_tablespace(my_bool discard);
int extra(enum ha_extra_function operation);
int reset();
int external_lock(THD *thd, int lock_type);
int transactional_table_lock(THD *thd, int lock_type);
int start_stmt(THD *thd, thr_lock_type lock_type);
void position(uchar *record);
ha_rows records_in_range(uint inx, key_range *min_key, key_range
*max_key);
ha_rows estimate_rows_upper_bound();
void update_create_info(HA_CREATE_INFO* create_info);
int create(const char *name, register TABLE *form,
HA_CREATE_INFO *create_info);
int delete_all_rows();
int delete_table(const char *name);
int rename_table(const char* from, const char* to);
int check(THD* thd, HA_CHECK_OPT* check_opt);
char* update_table_comment(const char* comment);
char* get_foreign_key_create_info();
int get_foreign_key_list(THD *thd, List<FOREIGN_KEY_INFO> *f_key_list);
bool can_switch_engines();
uint referenced_by_foreign_key();
void free_foreign_key_create_info(char* str);
THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to,
enum thr_lock_type lock_type);
void init_table_handle_for_HANDLER();
virtual void get_auto_increment(ulonglong offset, ulonglong increment,
ulonglong nb_desired_values,
ulonglong *first_value,
ulonglong *nb_reserved_values);
int reset_auto_increment(ulonglong value);
virtual bool get_error_message(int error, String *buf);
uint8 table_cache_type();
/*
ask handler about permission to cache table during query registration
*/
my_bool register_query_cache_table(THD *thd, char *table_key,
uint key_length,
qc_engine_callback *call_back,
ulonglong *engine_data);
static char *get_mysql_bin_log_name();
static ulonglong get_mysql_bin_log_pos();
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);
};
/* Some accessor functions which the InnoDB plugin needs, but which
can not be added to mysql/plugin.h as part of the public interface;
the definitions are bracketed with #ifdef INNODB_COMPATIBILITY_HOOKS */
#ifndef INNODB_COMPATIBILITY_HOOKS
#error InnoDB needs MySQL to be built with #define INNODB_COMPATIBILITY_HOOKS
#endif
extern "C" {
struct charset_info_st *thd_charset(MYSQL_THD thd);
char **thd_query(MYSQL_THD thd);
/** Get the file name of the MySQL binlog.
* @return the name of the binlog file
*/
const char* mysql_bin_log_file_name(void);
/** Get the current position of the MySQL binlog.
* @return byte offset from the beginning of the binlog
*/
ulonglong mysql_bin_log_file_pos(void);
/**
Check if a user thread is a replication slave thread
@param thd user thread
@retval 0 the user thread is not a replication slave thread
@retval 1 the user thread is a replication slave thread
*/
int thd_slave_thread(const MYSQL_THD thd);
/**
Check if a user thread is running a non-transactional update
@param thd user thread
@retval 0 the user thread is not running a non-transactional update
@retval 1 the user thread is running a non-transactional update
*/
int thd_non_transactional_update(const MYSQL_THD thd);
/**
Get the user thread's binary logging format
@param thd user thread
@return Value to be used as index into the binlog_format_names array
*/
int thd_binlog_format(const MYSQL_THD thd);
/**
Mark transaction to rollback and mark error as fatal to a sub-statement.
@param thd Thread handle
@param all TRUE <=> rollback main transaction.
*/
void thd_mark_transaction_to_rollback(MYSQL_THD thd, bool all);
}
typedef struct trx_struct trx_t;
/************************************************************************
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. */
extern "C"
int
convert_error_code_to_mysql(
/*========================*/
/* out: MySQL error code */
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. */
extern "C"
trx_t*
innobase_trx_allocate(
/*==================*/
/* out: InnoDB transaction handle */
MYSQL_THD thd); /* in: user thread handle */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,68 @@
/*****************************************************************************
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
*****************************************************************************/
/***********************************************************************
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

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,41 @@
/*****************************************************************************
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
*****************************************************************************/
/******************************************************
InnoDB INFORMATION SCHEMA tables interface to MySQL.
Created July 18, 2007 Vasil Dimov
*******************************************************/
#ifndef i_s_h
#define i_s_h
extern struct st_mysql_plugin i_s_innodb_buffer_pool_pages;
extern struct st_mysql_plugin i_s_innodb_buffer_pool_pages_index;
extern struct st_mysql_plugin i_s_innodb_buffer_pool_pages_blob;
extern struct st_mysql_plugin i_s_innodb_trx;
extern struct st_mysql_plugin i_s_innodb_locks;
extern struct st_mysql_plugin i_s_innodb_lock_waits;
extern struct st_mysql_plugin i_s_innodb_cmp;
extern struct st_mysql_plugin i_s_innodb_cmp_reset;
extern struct st_mysql_plugin i_s_innodb_cmpmem;
extern struct st_mysql_plugin i_s_innodb_cmpmem_reset;
extern struct st_mysql_plugin i_s_innodb_patches;
extern struct st_mysql_plugin i_s_innodb_rseg;
#endif /* i_s_h */

View File

@ -0,0 +1,35 @@
/* Copyright (C) 2002-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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#ifdef USE_PRAGMA_INTERFACE
#pragma interface /* gcc class implementation */
#endif
struct innodb_enhancement {
const char *file;
const char *name;
const char *comment;
const char *link;
}innodb_enhancements[] = {
{"xtradb_show_enhancements","I_S.XTRADB_ENHANCEMENTS","","http://www.percona.com/docs/wiki/percona-xtradb"},
{"innodb_show_status","Improvements to SHOW INNODB STATUS","Memory information and lock info fixes","http://www.percona.com/docs/wiki/percona-xtradb"},
{"innodb_io","Improvements to InnoDB IO","","http://www.percona.com/docs/wiki/percona-xtradb"},
{"innodb_opt_lru_count","Fix of buffer_pool mutex","Decreases contention on buffer_pool mutex on LRU operations","http://www.percona.com/docs/wiki/percona-xtradb"},
{"innodb_buffer_pool_pages","Information of buffer pool content","","http://www.percona.com/docs/wiki/percona-xtradb"},
{"innodb_expand_undo_slots","expandable maximum number of undo slots","from 1024 (default) to about 4000","http://www.percona.com/docs/wiki/percona-xtradb"},
{"innodb_extra_rseg","allow to create extra rollback segments","When create new db, the new parameter allows to create more rollback segments","http://www.percona.com/docs/wiki/percona-xtradb"},
{"innodb_overwrite_relay_log_info","overwrite relay-log.info when slave recovery","Building as plugin, it is not used.","http://www.percona.com/docs/wiki/percona-xtradb:innodb_overwrite_relay_log_info"},
{NULL, NULL, NULL, NULL}
};

View File

@ -0,0 +1,41 @@
/*****************************************************************************
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
*****************************************************************************/
/******************************************************
This file contains functions that need to be added to
MySQL code but have not been added yet.
Whenever you add a function here submit a MySQL bug
report (feature request) with the implementation. Then
write the bug number in the comment before the
function in this file.
When MySQL commits the function it can be deleted from
here. In a perfect world this file exists but is empty.
Created November 07, 2007 Vasil Dimov
*******************************************************/
#ifndef MYSQL_SERVER
#define MYSQL_SERVER
#endif /* MYSQL_SERVER */
#include <mysql_priv.h>
#include "mysql_addons.h"
#include "univ.i"

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More