summaryrefslogtreecommitdiff
path: root/storage
diff options
context:
space:
mode:
authorSeppo Jaakola <seppo.jaakola@codership.com>2012-08-09 01:47:21 +0300
committerSeppo Jaakola <seppo.jaakola@codership.com>2012-08-09 01:47:21 +0300
commitebfa24b1d24377a241b79883da96969a9150f22c (patch)
treeef1198f9dfb1838cbdbc5056f2b84e399b446bfd /storage
parent1fd2e10736d6fd198e62054cb9006a3dc13fd55e (diff)
parenta7123f507598690ef0fce68b5d8dc58e63635024 (diff)
downloadmariadb-git-ebfa24b1d24377a241b79883da96969a9150f22c.tar.gz
References lp:1034621 - Merge up to mysql-5.5.25 level
merged codership-mysql/5.5 revisions: bzr diff -r3759..3767 merged codership-mysql/5.5 revisions: bzr diff -r3768..3771
Diffstat (limited to 'storage')
-rw-r--r--storage/blackhole/ha_blackhole.cc2
-rw-r--r--storage/example/mysql-test/mtr/suite.pm8
-rw-r--r--storage/innobase/btr/btr0cur.c2
-rw-r--r--storage/innobase/buf/buf0flu.c9
-rw-r--r--storage/innobase/dict/dict0load.c4
-rw-r--r--storage/innobase/fil/fil0fil.c2
-rw-r--r--storage/innobase/handler/ha_innodb.cc98
-rw-r--r--storage/innobase/handler/ha_innodb.h1
-rw-r--r--storage/innobase/include/srv0srv.h1
-rw-r--r--storage/innobase/lock/lock0lock.c15
-rw-r--r--storage/innobase/mysql-test/storage_engine/alter_tablespace.opt2
-rw-r--r--storage/innobase/mysql-test/storage_engine/autoinc_secondary.rdiff30
-rw-r--r--storage/innobase/mysql-test/storage_engine/cache_index.rdiff71
-rw-r--r--storage/innobase/mysql-test/storage_engine/checksum_table_live.rdiff13
-rw-r--r--storage/innobase/mysql-test/storage_engine/define_engine.inc45
-rw-r--r--storage/innobase/mysql-test/storage_engine/disabled.def9
-rw-r--r--storage/innobase/mysql-test/storage_engine/fulltext_search.rdiff150
-rw-r--r--storage/innobase/mysql-test/storage_engine/index_enable_disable.rdiff33
-rw-r--r--storage/innobase/mysql-test/storage_engine/index_type_hash.rdiff60
-rw-r--r--storage/innobase/mysql-test/storage_engine/insert_delayed.rdiff26
-rw-r--r--storage/innobase/mysql-test/storage_engine/lock_concurrent.rdiff22
-rw-r--r--storage/innobase/mysql-test/storage_engine/optimize_table.rdiff37
-rw-r--r--storage/innobase/mysql-test/storage_engine/parts/checksum_table.rdiff22
-rw-r--r--storage/innobase/mysql-test/storage_engine/parts/create_table.rdiff20
-rw-r--r--storage/innobase/mysql-test/storage_engine/parts/optimize_table.rdiff58
-rw-r--r--storage/innobase/mysql-test/storage_engine/parts/repair_table.rdiff228
-rw-r--r--storage/innobase/mysql-test/storage_engine/parts/suite.opt4
-rw-r--r--storage/innobase/mysql-test/storage_engine/repair_table.rdiff129
-rw-r--r--storage/innobase/mysql-test/storage_engine/suite.opt4
-rw-r--r--storage/innobase/mysql-test/storage_engine/tbl_opt_data_index_dir.rdiff18
-rw-r--r--storage/innobase/mysql-test/storage_engine/tbl_opt_insert_method.rdiff11
-rw-r--r--storage/innobase/mysql-test/storage_engine/tbl_opt_key_block_size.opt3
-rw-r--r--storage/innobase/mysql-test/storage_engine/tbl_opt_row_format.opt3
-rw-r--r--storage/innobase/mysql-test/storage_engine/tbl_opt_row_format.rdiff10
-rw-r--r--storage/innobase/mysql-test/storage_engine/tbl_opt_union.rdiff16
-rw-r--r--storage/innobase/mysql-test/storage_engine/trx/disabled.def2
-rw-r--r--storage/innobase/mysql-test/storage_engine/trx/suite.opt5
-rw-r--r--storage/innobase/mysql-test/storage_engine/type_char_indexes.rdiff20
-rw-r--r--storage/innobase/mysql-test/storage_engine/type_float_indexes.rdiff11
-rw-r--r--storage/innobase/mysql-test/storage_engine/type_spatial_indexes.rdiff712
-rw-r--r--storage/innobase/mysql-test/storage_engine/vcol.rdiff82
-rw-r--r--storage/innobase/os/os0file.c23
-rw-r--r--storage/innobase/os/os0thread.c6
-rw-r--r--storage/innobase/rem/rem0rec.c5
-rw-r--r--storage/innobase/row/row0ins.c35
-rw-r--r--storage/innobase/row/row0upd.c70
-rw-r--r--storage/innobase/srv/srv0start.c16
-rw-r--r--storage/innobase/sync/sync0arr.c5
-rw-r--r--storage/maria/ha_maria.cc22
-rw-r--r--storage/maria/ha_maria.h7
-rw-r--r--storage/maria/ma_close.c31
-rw-r--r--storage/maria/ma_delete_table.c12
-rw-r--r--storage/maria/ma_info.c1
-rw-r--r--storage/maria/ma_open.c4
-rw-r--r--storage/maria/maria_chk.c3
-rw-r--r--storage/myisam/ha_myisam.cc22
-rw-r--r--storage/myisam/ha_myisam.h7
-rw-r--r--storage/myisam/mi_extra.c2
-rw-r--r--storage/myisam/mi_keycache.c2
-rw-r--r--storage/myisam/myisamchk.c3
-rw-r--r--storage/myisam/mysql-test/mtr2/suite.pm9
-rw-r--r--storage/myisam/mysql-test/storage_engine/alter_tablespace.rdiff32
-rw-r--r--storage/myisam/mysql-test/storage_engine/check_table.rdiff20
-rw-r--r--storage/myisam/mysql-test/storage_engine/define_engine.inc45
-rw-r--r--storage/myisam/mysql-test/storage_engine/foreign_keys.rdiff145
-rw-r--r--storage/myisam/mysql-test/storage_engine/index_type_hash.rdiff60
-rw-r--r--storage/myisam/mysql-test/storage_engine/show_engine.rdiff10
-rw-r--r--storage/myisam/mysql-test/storage_engine/tbl_opt_insert_method.rdiff11
-rw-r--r--storage/myisam/mysql-test/storage_engine/tbl_opt_union.rdiff16
-rw-r--r--storage/myisam/mysql-test/storage_engine/trx/cons_snapshot_repeatable_read.rdiff9
-rw-r--r--storage/myisam/mysql-test/storage_engine/trx/cons_snapshot_serializable.rdiff9
-rw-r--r--storage/myisam/mysql-test/storage_engine/trx/delete.rdiff50
-rw-r--r--storage/myisam/mysql-test/storage_engine/trx/insert.rdiff65
-rw-r--r--storage/myisam/mysql-test/storage_engine/trx/level_read_committed.rdiff44
-rw-r--r--storage/myisam/mysql-test/storage_engine/trx/level_read_uncommitted.rdiff7
-rw-r--r--storage/myisam/mysql-test/storage_engine/trx/level_repeatable_read.rdiff53
-rw-r--r--storage/myisam/mysql-test/storage_engine/trx/level_serializable.rdiff69
-rw-r--r--storage/myisam/mysql-test/storage_engine/trx/select_for_update.rdiff50
-rw-r--r--storage/myisam/mysql-test/storage_engine/trx/select_lock_in_share_mode.rdiff37
-rw-r--r--storage/myisam/mysql-test/storage_engine/trx/update.rdiff58
-rw-r--r--storage/myisam/mysql-test/storage_engine/trx/xa.rdiff89
-rw-r--r--storage/myisam/mysql-test/storage_engine/trx/xa_recovery.rdiff33
-rw-r--r--storage/myisammrg/ha_myisammrg.cc41
-rw-r--r--storage/myisammrg/ha_myisammrg.h6
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/alter_table.inc116
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/alter_table.rdiff68
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/alter_tablespace.rdiff27
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/analyze_table.rdiff22
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/autoincrement.rdiff34
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/cache_index.rdiff46
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/char_indexes.rdiff0
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/checksum_table_live.rdiff6
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/cleanup_engine.inc16
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/create_table.inc208
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/create_table.rdiff37
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/define_engine.inc49
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/disabled.def2
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/foreign_keys.rdiff138
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/fulltext_search.rdiff142
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/handler.rdiff79
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/index.rdiff6
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/index_enable_disable.rdiff17
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/index_type_btree.rdiff6
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/index_type_hash.rdiff34
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/insert_delayed.rdiff14
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/lock.rdiff62
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/optimize_table.rdiff24
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/parts/alter_table.rdiff63
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/parts/analyze_table.rdiff83
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/parts/check_table.rdiff172
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/parts/checksum_table.rdiff81
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/parts/create_table.rdiff156
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/parts/optimize_table.rdiff91
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/parts/repair_table.rdiff295
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/parts/truncate_table.rdiff100
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/repair_table.rdiff103
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/show_engine.rdiff2
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/tbl_opt_ai.rdiff8
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/tbl_opt_avg_row_length.rdiff8
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/tbl_opt_checksum.rdiff8
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/tbl_opt_connection.rdiff8
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/tbl_opt_data_index_dir.rdiff8
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/tbl_opt_delay_key_write.rdiff8
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/tbl_opt_insert_method.rdiff8
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/tbl_opt_key_block_size.rdiff8
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/tbl_opt_max_rows.rdiff8
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/tbl_opt_min_rows.rdiff8
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/tbl_opt_pack_keys.rdiff8
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/tbl_opt_password.rdiff8
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/tbl_opt_row_format.rdiff8
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/tbl_opt_union.rdiff8
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/tbl_standard_opts.rdiff8
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/tbl_temporary.rdiff4
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/truncate_table.rdiff35
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/trx/cons_snapshot_repeatable_read.rdiff9
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/trx/cons_snapshot_serializable.rdiff9
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/trx/delete.rdiff34
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/trx/insert.rdiff32
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/trx/level_read_committed.rdiff44
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/trx/level_read_uncommitted.rdiff7
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/trx/level_repeatable_read.rdiff53
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/trx/level_serializable.rdiff69
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/trx/select_for_update.rdiff40
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/trx/select_lock_in_share_mode.rdiff26
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/trx/update.rdiff41
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/trx/xa.rdiff34
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/trx/xa_recovery.rdiff22
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/type_char_indexes.rdiff8
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/type_float_indexes.rdiff4
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/type_spatial.rdiff706
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/type_spatial_indexes.rdiff1412
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/vcol.rdiff79
-rw-r--r--storage/oqgraph/CMakeLists.txt20
-rw-r--r--storage/xtradb/btr/btr0btr.c315
-rw-r--r--storage/xtradb/btr/btr0cur.c264
-rw-r--r--storage/xtradb/btr/btr0pcur.c89
-rw-r--r--storage/xtradb/btr/btr0sea.c8
-rw-r--r--storage/xtradb/buf/buf0buf.c81
-rw-r--r--storage/xtradb/buf/buf0flu.c19
-rw-r--r--storage/xtradb/buf/buf0lru.c465
-rw-r--r--storage/xtradb/dict/dict0boot.c221
-rw-r--r--storage/xtradb/dict/dict0dict.c42
-rw-r--r--storage/xtradb/dict/dict0load.c42
-rw-r--r--storage/xtradb/fil/fil0fil.c108
-rw-r--r--storage/xtradb/fsp/fsp0fsp.c413
-rw-r--r--storage/xtradb/handler/ha_innodb.cc402
-rw-r--r--storage/xtradb/handler/ha_innodb.h13
-rw-r--r--storage/xtradb/handler/handler0alter.cc21
-rw-r--r--storage/xtradb/ibuf/ibuf0ibuf.c130
-rw-r--r--storage/xtradb/include/btr0btr.h58
-rw-r--r--storage/xtradb/include/btr0btr.ic2
-rw-r--r--storage/xtradb/include/btr0cur.h88
-rw-r--r--storage/xtradb/include/btr0cur.ic29
-rw-r--r--storage/xtradb/include/btr0pcur.h10
-rw-r--r--storage/xtradb/include/buf0buf.h52
-rw-r--r--storage/xtradb/include/buf0buf.ic21
-rw-r--r--storage/xtradb/include/buf0lru.h11
-rw-r--r--storage/xtradb/include/buf0types.h9
-rw-r--r--storage/xtradb/include/data0data.h23
-rw-r--r--storage/xtradb/include/data0data.ic53
-rw-r--r--storage/xtradb/include/db0err.h8
-rw-r--r--storage/xtradb/include/dict0boot.h20
-rw-r--r--storage/xtradb/include/dict0dict.h14
-rw-r--r--storage/xtradb/include/dict0dict.ic21
-rw-r--r--storage/xtradb/include/dict0mem.h10
-rw-r--r--storage/xtradb/include/fil0fil.h19
-rw-r--r--storage/xtradb/include/fsp0fsp.h40
-rw-r--r--storage/xtradb/include/log0log.h6
-rw-r--r--storage/xtradb/include/mem0mem.ic4
-rw-r--r--storage/xtradb/include/mtr0log.ic3
-rw-r--r--storage/xtradb/include/mtr0mtr.h13
-rw-r--r--storage/xtradb/include/mtr0mtr.ic11
-rw-r--r--storage/xtradb/include/page0page.h43
-rw-r--r--storage/xtradb/include/page0page.ic38
-rw-r--r--storage/xtradb/include/row0mysql.h8
-rw-r--r--storage/xtradb/include/row0sel.h7
-rw-r--r--storage/xtradb/include/srv0srv.h18
-rw-r--r--storage/xtradb/include/sync0rw.h18
-rw-r--r--storage/xtradb/include/sync0rw.ic8
-rw-r--r--storage/xtradb/include/sync0sync.h10
-rw-r--r--storage/xtradb/include/trx0purge.h4
-rw-r--r--storage/xtradb/include/trx0rec.ic7
-rw-r--r--storage/xtradb/include/trx0rseg.ic9
-rw-r--r--storage/xtradb/include/trx0sys.h6
-rw-r--r--storage/xtradb/include/trx0undo.h13
-rw-r--r--storage/xtradb/include/univ.i38
-rw-r--r--storage/xtradb/include/ut0mem.h31
-rw-r--r--storage/xtradb/include/ut0rnd.ic2
-rw-r--r--storage/xtradb/lock/lock0lock.c156
-rw-r--r--storage/xtradb/log/log0log.c175
-rw-r--r--storage/xtradb/mem/mem0pool.c6
-rw-r--r--storage/xtradb/mtr/mtr0mtr.c6
-rw-r--r--storage/xtradb/os/os0file.c122
-rw-r--r--storage/xtradb/os/os0proc.c3
-rw-r--r--storage/xtradb/os/os0thread.c6
-rw-r--r--storage/xtradb/page/page0cur.c23
-rw-r--r--storage/xtradb/page/page0page.c73
-rw-r--r--storage/xtradb/pars/pars0pars.c2
-rw-r--r--storage/xtradb/rem/rem0rec.c5
-rw-r--r--storage/xtradb/row/row0ins.c125
-rw-r--r--storage/xtradb/row/row0merge.c125
-rw-r--r--storage/xtradb/row/row0mysql.c156
-rw-r--r--storage/xtradb/row/row0row.c25
-rw-r--r--storage/xtradb/row/row0sel.c32
-rw-r--r--storage/xtradb/row/row0umod.c3
-rw-r--r--storage/xtradb/row/row0upd.c135
-rw-r--r--storage/xtradb/srv/srv0srv.c109
-rw-r--r--storage/xtradb/srv/srv0start.c29
-rw-r--r--storage/xtradb/sync/sync0rw.c10
-rw-r--r--storage/xtradb/sync/sync0sync.c16
-rw-r--r--storage/xtradb/trx/trx0purge.c5
-rw-r--r--storage/xtradb/trx/trx0rec.c42
-rw-r--r--storage/xtradb/trx/trx0sys.c62
-rw-r--r--storage/xtradb/trx/trx0trx.c2
-rw-r--r--storage/xtradb/trx/trx0undo.c43
-rw-r--r--storage/xtradb/ut/ut0mem.c82
-rw-r--r--storage/xtradb/ut/ut0ut.c8
237 files changed, 11681 insertions, 1672 deletions
diff --git a/storage/blackhole/ha_blackhole.cc b/storage/blackhole/ha_blackhole.cc
index 6c8eba08afb..812623314bf 100644
--- a/storage/blackhole/ha_blackhole.cc
+++ b/storage/blackhole/ha_blackhole.cc
@@ -1,4 +1,4 @@
-/* Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2005, 2012, Oracle and/or its affiliates. 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
diff --git a/storage/example/mysql-test/mtr/suite.pm b/storage/example/mysql-test/mtr/suite.pm
new file mode 100644
index 00000000000..f7ff42241fe
--- /dev/null
+++ b/storage/example/mysql-test/mtr/suite.pm
@@ -0,0 +1,8 @@
+package My::Suite::MTR::Example;
+
+@ISA = qw(My::Suite);
+
+sub skip_combinations {(
+ 't/combs.combinations' => [ 'c1' ],
+)}
+bless { };
diff --git a/storage/innobase/btr/btr0cur.c b/storage/innobase/btr/btr0cur.c
index e227e47b52f..9c61e0cf763 100644
--- a/storage/innobase/btr/btr0cur.c
+++ b/storage/innobase/btr/btr0cur.c
@@ -3463,6 +3463,8 @@ btr_estimate_n_rows_in_range(
n_rows = n_rows * 2;
}
+ DBUG_EXECUTE_IF("bug14007649", return(n_rows););
+
/* Do not estimate the number of rows in the range
to over 1 / 2 of the estimated rows in the whole
table */
diff --git a/storage/innobase/buf/buf0flu.c b/storage/innobase/buf/buf0flu.c
index 6e8e8fdda5a..7cd09d6675e 100644
--- a/storage/innobase/buf/buf0flu.c
+++ b/storage/innobase/buf/buf0flu.c
@@ -1750,8 +1750,6 @@ buf_flush_batch(
}
#endif /* UNIV_DEBUG */
- srv_buf_pool_flushed += count;
-
return(count);
}
@@ -1778,13 +1776,6 @@ buf_flush_common(
#endif /* UNIV_DEBUG */
srv_buf_pool_flushed += page_count;
-
- if (flush_type == BUF_FLUSH_LRU) {
- /* We keep track of all flushes happening as part of LRU
- flush. When estimating the desired rate at which flush_list
- should be flushed we factor in this value. */
- buf_lru_flush_page_count += page_count;
- }
}
/******************************************************************//**
diff --git a/storage/innobase/dict/dict0load.c b/storage/innobase/dict/dict0load.c
index 44a0ec5b338..22f0d4456d5 100644
--- a/storage/innobase/dict/dict0load.c
+++ b/storage/innobase/dict/dict0load.c
@@ -177,7 +177,7 @@ dict_print(void)
monitor printout */
mutex_enter(&kernel_mutex);
- srv_fatal_semaphore_wait_threshold += 7200; /* 2 hours */
+ srv_fatal_semaphore_wait_threshold += SRV_SEMAPHORE_WAIT_EXTENSION;
mutex_exit(&kernel_mutex);
heap = mem_heap_create(1000);
@@ -214,7 +214,7 @@ dict_print(void)
/* Restore the fatal semaphore wait timeout */
mutex_enter(&kernel_mutex);
- srv_fatal_semaphore_wait_threshold -= 7200; /* 2 hours */
+ srv_fatal_semaphore_wait_threshold -= SRV_SEMAPHORE_WAIT_EXTENSION;
mutex_exit(&kernel_mutex);
}
diff --git a/storage/innobase/fil/fil0fil.c b/storage/innobase/fil/fil0fil.c
index 2390333b393..0a467d40345 100644
--- a/storage/innobase/fil/fil0fil.c
+++ b/storage/innobase/fil/fil0fil.c
@@ -1908,7 +1908,7 @@ fil_inc_pending_ops(
if (space == NULL) {
fprintf(stderr,
- "InnoDB: Error: trying to do ibuf merge to a"
+ "InnoDB: Error: trying to do an operation on a"
" dropped tablespace %lu\n",
(ulong) id);
}
diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc
index a0b4ec43dad..0b3ea633829 100644
--- a/storage/innobase/handler/ha_innodb.cc
+++ b/storage/innobase/handler/ha_innodb.cc
@@ -4279,6 +4279,31 @@ table_opened:
}
UNIV_INTERN
+handler*
+ha_innobase::clone(
+/*===============*/
+ const char* name, /*!< in: table name */
+ MEM_ROOT* mem_root) /*!< in: memory context */
+{
+ ha_innobase* new_handler;
+
+ DBUG_ENTER("ha_innobase::clone");
+
+ new_handler = static_cast<ha_innobase*>(handler::clone(name,
+ mem_root));
+ if (new_handler) {
+ DBUG_ASSERT(new_handler->prebuilt != NULL);
+ DBUG_ASSERT(new_handler->user_thd == user_thd);
+ DBUG_ASSERT(new_handler->prebuilt->trx == prebuilt->trx);
+
+ new_handler->prebuilt->select_lock_type
+ = prebuilt->select_lock_type;
+ }
+
+ DBUG_RETURN(new_handler);
+}
+
+UNIV_INTERN
uint
ha_innobase::max_supported_key_part_length() const
{
@@ -6940,13 +6965,15 @@ wsrep_append_foreign_key(
/*===========================*/
trx_t* trx, /*!< in: trx */
dict_foreign_t* foreign, /*!< in: foreign key constraint */
- const rec_t* clust_rec, /*!<in: clustered index record */
- dict_index_t* clust_index, /*!<in: clustered index */
+ const rec_t* rec, /*!<in: clustered index record */
+ dict_index_t* index, /*!<in: clustered index */
+ ibool referenced, /*!<in: is check for referenced table */
ibool shared) /*!<in: is shared access */
{
THD* thd = (THD*)trx->mysql_thd;
ulint rcode = DB_SUCCESS;
char cache_key[512] = {'\0'};
+ int cache_key_len;
if (!wsrep_on(trx->mysql_thd) ||
wsrep_thd_exec_mode(thd) != LOCAL_STATE)
@@ -6955,39 +6982,55 @@ wsrep_append_foreign_key(
byte key[WSREP_MAX_SUPPORTED_KEY_LENGTH+1];
ulint len = WSREP_MAX_SUPPORTED_KEY_LENGTH;
- key[0] = '\0';
+ dict_index_t *idx_target = (referenced) ?
+ foreign->referenced_index : foreign->foreign_index;
+ dict_index_t *idx = (referenced) ?
+ UT_LIST_GET_FIRST(foreign->referenced_table->indexes) :
+ UT_LIST_GET_FIRST(foreign->foreign_table->indexes);
+ int i = 0;
+ while (idx != NULL && idx != idx_target) {
+ idx = UT_LIST_GET_NEXT(indexes, idx);
+ i++;
+ }
+ ut_a(idx);
+ key[0] = (char)i;
+
rcode = wsrep_rec_get_primary_key(
- &key[1], &len, clust_rec, clust_index,
+ &key[1], &len, rec, index,
wsrep_protocol_version > 1);
if (rcode != DB_SUCCESS) {
WSREP_ERROR("FK key set failed: %lu", rcode);
return rcode;
}
+ strncpy(cache_key,
+ (wsrep_protocol_version > 1) ?
+ ((referenced) ?
+ foreign->referenced_table->name :
+ foreign->foreign_table->name) :
+ foreign->foreign_table->name, 512);
+ cache_key_len = strlen(cache_key);
#ifdef WSREP_DEBUG_PRINT
- ulint i;
- fprintf(stderr, "FK parent key, table: %s shared: %d len: %lu ",
- foreign->referenced_table_name, (int)shared, len+1);
- for (i=0; i<len+1; i++) {
- fprintf(stderr, " %hhX, ", key[i]);
+ ulint j;
+ fprintf(stderr, "FK parent key, table: %s %s len: %lu ",
+ cache_key, (shared) ? "shared" : "exclusive", len+1);
+ for (j=0; j<len+1; j++) {
+ fprintf(stderr, " %hhX, ", key[j]);
}
fprintf(stderr, "\n");
#endif
- strncpy(cache_key, (wsrep_protocol_version > 1) ?
- foreign->referenced_table->name :
- foreign->foreign_table->name, 512);
char *p = strchr(cache_key, '/');
if (p) {
*p = '\0';
} else {
- WSREP_WARN("unexpected foreign key table %s",
- foreign->foreign_table->name);
+ WSREP_WARN("unexpected foreign key table %s %s",
+ foreign->referenced_table->name, foreign->foreign_table->name);
}
wsrep_key_part_t wkey_part[3];
wsrep_key_t wkey = {wkey_part, 3};
if (!wsrep_prepare_key_for_innodb(
(const uchar*)cache_key,
- strlen(foreign->foreign_table->name) + 1,
+ cache_key_len + 1,
(const uchar*)key, len+1,
wkey_part,
&wkey.key_parts_len)) {
@@ -7066,6 +7109,23 @@ wsrep_append_key(
}
DBUG_RETURN(0);
}
+
+ibool
+wsrep_is_cascding_foreign_key_parent(
+ dict_table_t* table, /*!< in: InnoDB table */
+ dict_index_t* index /*!< in: InnoDB index */
+) {
+ // return referenced_by_foreign_key();
+ dict_foreign_t* fk = dict_table_get_referenced_constraint(table, index);
+ if (fk &&
+ (fk->type & DICT_FOREIGN_ON_UPDATE_CASCADE ||
+ fk->type & DICT_FOREIGN_ON_UPDATE_SET_NULL)
+ ) {
+ return TRUE;
+ }
+ return FALSE;
+}
+
int
ha_innobase::wsrep_append_keys(
/*==================*/
@@ -7134,7 +7194,9 @@ ha_innobase::wsrep_append_keys(
keyval0[0] = (char)i;
keyval1[0] = (char)i;
- if (key_info->flags & HA_NOSAME) {
+ if (key_info->flags & HA_NOSAME ||
+ referenced_by_foreign_key()) {
+
len = wsrep_store_key_val_for_row(
table, i, key0, key_info->key_length,
record0, &is_null);
@@ -9280,7 +9342,7 @@ ha_innobase::check(
/* Enlarge the fatal lock wait timeout during CHECK TABLE. */
mutex_enter(&kernel_mutex);
- srv_fatal_semaphore_wait_threshold += 7200; /* 2 hours */
+ srv_fatal_semaphore_wait_threshold += SRV_SEMAPHORE_WAIT_EXTENSION;
mutex_exit(&kernel_mutex);
for (index = dict_table_get_first_index(prebuilt->table);
@@ -9421,7 +9483,7 @@ ha_innobase::check(
/* Restore the fatal lock wait timeout after CHECK TABLE. */
mutex_enter(&kernel_mutex);
- srv_fatal_semaphore_wait_threshold -= 7200; /* 2 hours */
+ srv_fatal_semaphore_wait_threshold -= SRV_SEMAPHORE_WAIT_EXTENSION;
mutex_exit(&kernel_mutex);
prebuilt->trx->op_info = "";
diff --git a/storage/innobase/handler/ha_innodb.h b/storage/innobase/handler/ha_innodb.h
index 8b3b63bd9fb..8f211d6e38c 100644
--- a/storage/innobase/handler/ha_innodb.h
+++ b/storage/innobase/handler/ha_innodb.h
@@ -137,6 +137,7 @@ class ha_innobase: public handler
const key_map* keys_to_use_for_scanning();
int open(const char *name, int mode, uint test_if_locked);
+ handler* clone(const char *name, MEM_ROOT *mem_root);
int close(void);
double scan_time();
double read_time(uint index, uint ranges, ha_rows rows);
diff --git a/storage/innobase/include/srv0srv.h b/storage/innobase/include/srv0srv.h
index 90accf471a2..10e4544c85a 100644
--- a/storage/innobase/include/srv0srv.h
+++ b/storage/innobase/include/srv0srv.h
@@ -266,6 +266,7 @@ extern ibool srv_print_latch_waits;
extern ulint srv_activity_count;
extern ulint srv_fatal_semaphore_wait_threshold;
+#define SRV_SEMAPHORE_WAIT_EXTENSION 7200
extern ulint srv_dml_needed_delay;
extern mutex_t* kernel_mutex_temp;/* mutex protecting the server, trx structs,
diff --git a/storage/innobase/lock/lock0lock.c b/storage/innobase/lock/lock0lock.c
index 99a2cdc9b73..b24bd05e0b3 100644
--- a/storage/innobase/lock/lock0lock.c
+++ b/storage/innobase/lock/lock0lock.c
@@ -2106,8 +2106,9 @@ lock_rec_lock_fast(
ut_ad(mode - (LOCK_MODE_MASK & mode) == LOCK_GAP
|| mode - (LOCK_MODE_MASK & mode) == 0
#ifdef WITH_WSREP
- || mode - (LOCK_MODE_MASK & mode) == WSREP_BF
- || mode - (LOCK_MODE_MASK & mode) - LOCK_REC_NOT_GAP == WSREP_BF
+ || mode - (LOCK_MODE_MASK & mode) - WSREP_BF == 0
+ || mode - (LOCK_MODE_MASK & mode) - WSREP_BF == LOCK_GAP
+ || mode - (LOCK_MODE_MASK & mode) - WSREP_BF == LOCK_REC_NOT_GAP
#endif /* WITH_WSREP */
|| mode - (LOCK_MODE_MASK & mode) == LOCK_REC_NOT_GAP);
@@ -2191,8 +2192,9 @@ lock_rec_lock_slow(
ut_ad(mode - (LOCK_MODE_MASK & mode) == LOCK_GAP
|| mode - (LOCK_MODE_MASK & mode) == 0
#ifdef WITH_WSREP
- || mode - (LOCK_MODE_MASK & mode) == WSREP_BF
- || mode - (LOCK_MODE_MASK & mode) - LOCK_REC_NOT_GAP == WSREP_BF
+ || mode - (LOCK_MODE_MASK & mode) - WSREP_BF == 0
+ || mode - (LOCK_MODE_MASK & mode) - WSREP_BF == LOCK_GAP
+ || mode - (LOCK_MODE_MASK & mode) - WSREP_BF == LOCK_REC_NOT_GAP
#endif /* WITH_WSREP */
|| mode - (LOCK_MODE_MASK & mode) == LOCK_REC_NOT_GAP);
@@ -2266,8 +2268,9 @@ lock_rec_lock(
ut_ad(mode - (LOCK_MODE_MASK & mode) == LOCK_GAP
|| mode - (LOCK_MODE_MASK & mode) == LOCK_REC_NOT_GAP
#ifdef WITH_WSREP
- || mode - (LOCK_MODE_MASK & mode) == WSREP_BF
- || mode - (LOCK_MODE_MASK & mode) - LOCK_REC_NOT_GAP == WSREP_BF
+ || mode - (LOCK_MODE_MASK & mode) - WSREP_BF == 0
+ || mode - (LOCK_MODE_MASK & mode) - WSREP_BF == LOCK_GAP
+ || mode - (LOCK_MODE_MASK & mode) - WSREP_BF == LOCK_REC_NOT_GAP
#endif /* WITH_WSREP */
|| mode - (LOCK_MODE_MASK & mode) == 0);
#ifdef WITH_WSREP
diff --git a/storage/innobase/mysql-test/storage_engine/alter_tablespace.opt b/storage/innobase/mysql-test/storage_engine/alter_tablespace.opt
new file mode 100644
index 00000000000..cf4b117e1b1
--- /dev/null
+++ b/storage/innobase/mysql-test/storage_engine/alter_tablespace.opt
@@ -0,0 +1,2 @@
+--innodb-file-per-table=1
+
diff --git a/storage/innobase/mysql-test/storage_engine/autoinc_secondary.rdiff b/storage/innobase/mysql-test/storage_engine/autoinc_secondary.rdiff
new file mode 100644
index 00000000000..c24594c5024
--- /dev/null
+++ b/storage/innobase/mysql-test/storage_engine/autoinc_secondary.rdiff
@@ -0,0 +1,30 @@
+--- suite/storage_engine/autoinc_secondary.result 2012-07-12 04:34:18.153885986 +0400
++++ suite/storage_engine/autoinc_secondary.reject 2012-07-15 17:47:03.937703666 +0400
+@@ -13,18 +13,15 @@
+ 5 a
+ DROP TABLE t1;
+ CREATE TABLE t1 (a <CHAR_COLUMN>, b <INT_COLUMN> AUTO_INCREMENT, PRIMARY KEY (a,b)) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+-INSERT INTO t1 (a) VALUES ('a'),('b'),('b'),('c'),('a');
+-SELECT LAST_INSERT_ID();
+-LAST_INSERT_ID()
+-1
+-SELECT * FROM t1;
+-a b
+-a 1
+-a 2
+-b 1
+-b 2
+-c 1
+-DROP TABLE t1;
++ERROR 42000: Incorrect table definition; there can be only one auto column and it must be defined as a key
++# ERROR: Statement ended with errno 1075, errname ER_WRONG_AUTO_KEY (expected to succeed)
++# ------------ UNEXPECTED RESULT ------------
++# The statement|command finished with ER_WRONG_AUTO_KEY.
++# Multi-part keys or PK or AUTO_INCREMENT (on a secondary column) or the mix could be unsupported|malfunctioning, or the problem was caused by previous errors.
++# You can change the engine code, or create an rdiff, or disable the test by adding it to disabled.def.
++# Further in this test, the message might sometimes be suppressed; a part of the test might be skipped.
++# Also, this problem may cause a chain effect (more errors of different kinds in the test).
++# -------------------------------------------
+ CREATE TABLE t1 (a <CHAR_COLUMN>, b <INT_COLUMN> AUTO_INCREMENT, PRIMARY KEY (a,b), <CUSTOM_INDEX>(b)) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+ INSERT INTO t1 (a) VALUES ('a'),('b'),('b'),('c'),('a');
+ SELECT LAST_INSERT_ID();
diff --git a/storage/innobase/mysql-test/storage_engine/cache_index.rdiff b/storage/innobase/mysql-test/storage_engine/cache_index.rdiff
new file mode 100644
index 00000000000..e04df87aa34
--- /dev/null
+++ b/storage/innobase/mysql-test/storage_engine/cache_index.rdiff
@@ -0,0 +1,71 @@
+--- suite/storage_engine/cache_index.result 2012-07-15 00:22:19.822493731 +0400
++++ suite/storage_engine/cache_index.reject 2012-07-15 17:47:18.321522834 +0400
+@@ -12,31 +12,31 @@
+ SET GLOBAL <CACHE_NAME>.key_buffer_size=128*1024;
+ CACHE INDEX t1 INDEX (a), t2 IN <CACHE_NAME>;
+ Table Op Msg_type Msg_text
+-test.t1 assign_to_keycache status OK
+-test.t2 assign_to_keycache status OK
++test.t1 assign_to_keycache note The storage engine for the table doesn't support assign_to_keycache
++test.t2 assign_to_keycache note The storage engine for the table doesn't support assign_to_keycache
+ LOAD INDEX INTO CACHE t1, t2;
+ Table Op Msg_type Msg_text
+-test.t1 preload_keys status OK
+-test.t2 preload_keys status OK
++test.t1 preload_keys note The storage engine for the table doesn't support preload_keys
++test.t2 preload_keys note The storage engine for the table doesn't support preload_keys
+ INSERT INTO t1 (a,b) VALUES (3,'c'),(4,'d');
+ SET GLOBAL <CACHE_NAME>.key_buffer_size=8*1024;
+ LOAD INDEX INTO CACHE t1, t2 IGNORE LEAVES;
+ Table Op Msg_type Msg_text
+-test.t1 preload_keys status OK
+-test.t2 preload_keys status OK
++test.t1 preload_keys note The storage engine for the table doesn't support preload_keys
++test.t2 preload_keys note The storage engine for the table doesn't support preload_keys
+ SET GLOBAL <CACHE_NAME>.key_cache_age_threshold = 100, <CACHE_NAME>.key_cache_block_size = 512, <CACHE_NAME>.key_cache_division_limit = 1, <CACHE_NAME>.key_cache_segments=2;
+ INSERT INTO t1 (a,b) VALUES (5,'e'),(6,'f');
+ LOAD INDEX INTO CACHE t1;
+ Table Op Msg_type Msg_text
+-test.t1 preload_keys status OK
++test.t1 preload_keys note The storage engine for the table doesn't support preload_keys
+ SET GLOBAL new_<CACHE_NAME>.key_buffer_size=128*1024;
+ CACHE INDEX t1 IN new_<CACHE_NAME>;
+ Table Op Msg_type Msg_text
+-test.t1 assign_to_keycache status OK
++test.t1 assign_to_keycache note The storage engine for the table doesn't support assign_to_keycache
+ INSERT INTO t1 (a,b) VALUES (7,'g'),(8,'h');
+ LOAD INDEX INTO CACHE t1 IGNORE LEAVES;
+ Table Op Msg_type Msg_text
+-test.t1 preload_keys status OK
++test.t1 preload_keys note The storage engine for the table doesn't support preload_keys
+ INSERT INTO t1 (a,b) VALUES (9,'i');
+ DROP TABLE t2;
+ DROP TABLE t1;
+@@ -47,11 +47,11 @@
+ ) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+ CACHE INDEX t1 IN <CACHE_NAME>;
+ Table Op Msg_type Msg_text
+-test.t1 assign_to_keycache status OK
++test.t1 assign_to_keycache note The storage engine for the table doesn't support assign_to_keycache
+ INSERT INTO t1 (a,b) VALUES (1,'a'),(2,'b');
+ LOAD INDEX INTO CACHE t1;
+ Table Op Msg_type Msg_text
+-test.t1 preload_keys status OK
++test.t1 preload_keys note The storage engine for the table doesn't support preload_keys
+ DROP TABLE t1;
+ CREATE TABLE t1 (a <INT_COLUMN>,
+ b <CHAR_COLUMN>,
+@@ -59,11 +59,11 @@
+ ) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+ CACHE INDEX t1 IN <CACHE_NAME>;
+ Table Op Msg_type Msg_text
+-test.t1 assign_to_keycache status OK
++test.t1 assign_to_keycache note The storage engine for the table doesn't support assign_to_keycache
+ INSERT INTO t1 (a,b) VALUES (1,'a'),(2,'b');
+ LOAD INDEX INTO CACHE t1;
+ Table Op Msg_type Msg_text
+-test.t1 preload_keys status OK
++test.t1 preload_keys note The storage engine for the table doesn't support preload_keys
+ DROP TABLE t1;
+ SET GLOBAL <CACHE_NAME>.key_buffer_size=0;
+ SET GLOBAL new_<CACHE_NAME>.key_buffer_size=0;
diff --git a/storage/innobase/mysql-test/storage_engine/checksum_table_live.rdiff b/storage/innobase/mysql-test/storage_engine/checksum_table_live.rdiff
new file mode 100644
index 00000000000..71c782848a6
--- /dev/null
+++ b/storage/innobase/mysql-test/storage_engine/checksum_table_live.rdiff
@@ -0,0 +1,13 @@
+--- suite/storage_engine/checksum_table_live.result 2012-07-12 21:05:44.497062968 +0400
++++ suite/storage_engine/checksum_table_live.reject 2012-07-15 17:47:28.105399836 +0400
+@@ -11,8 +11,8 @@
+ test.t1 4272806499
+ CHECKSUM TABLE t1, t2 QUICK;
+ Table Checksum
+-test.t1 4272806499
+-test.t2 0
++test.t1 NULL
++test.t2 NULL
+ CHECKSUM TABLE t1, t2 EXTENDED;
+ Table Checksum
+ test.t1 4272806499
diff --git a/storage/innobase/mysql-test/storage_engine/define_engine.inc b/storage/innobase/mysql-test/storage_engine/define_engine.inc
new file mode 100644
index 00000000000..7d7b0c7407a
--- /dev/null
+++ b/storage/innobase/mysql-test/storage_engine/define_engine.inc
@@ -0,0 +1,45 @@
+###########################################
+#
+# This is a template of the include file define_engine.inc which
+# should be placed in storage/<engine>/mysql-test/storage_engine folder.
+#
+################################
+#
+# The name of the engine under test must be defined in $ENGINE variable.
+# You can set it either here (uncomment and edit) or in your environment.
+#
+let $ENGINE = InnoDB;
+#
+################################
+#
+# The following three variables define specific options for columns and tables.
+# Normally there should be none needed, but for some engines it can be different.
+# If the engine requires specific column option for all or indexed columns,
+# set them inside the comment, e.g. /*!NOT NULL*/.
+# Do the same for table options if needed, e.g. /*!INSERT_METHOD=LAST*/
+
+let $default_col_opts = /*!*/;
+let $default_col_indexed_opts = /*!*/;
+let $default_tbl_opts = /*!*/;
+
+# INDEX, UNIQUE INDEX, PRIMARY KEY, special index type - choose the fist that the engine allows,
+# or set it to /*!*/ if none is supported
+
+let $default_index = /*!INDEX*/;
+
+# If the engine does not support the following types, replace them with the closest possible
+
+let $default_int_type = INT(11);
+let $default_char_type = CHAR(8);
+
+################################
+
+--disable_query_log
+--disable_result_log
+
+# Here you can place your custom MTR code which needs to be executed before each test,
+# e.g. creation of an additional schema or table, etc.
+# The cleanup part should be defined in cleanup_engine.inc
+
+--enable_query_log
+--enable_result_log
diff --git a/storage/innobase/mysql-test/storage_engine/disabled.def b/storage/innobase/mysql-test/storage_engine/disabled.def
new file mode 100644
index 00000000000..3849170a7b8
--- /dev/null
+++ b/storage/innobase/mysql-test/storage_engine/disabled.def
@@ -0,0 +1,9 @@
+alter_table_online : MDEV-397 (Changing a column name via ALTER ONLINE does not work for InnoDB)
+autoinc_vars : MySQL:65225 (InnoDB miscalculates auto-increment)
+tbl_opt_ai : MySQL:65901 (AUTO_INCREMENT option on InnoDB table is ignored if added before autoinc column)
+delete_low_prio : InnoDB does not use table-level locking
+insert_high_prio : InnoDB does not use table-level locking
+insert_low_prio : InnoDB does not use table-level locking
+select_high_prio : InnoDB does not use table-level locking
+update_low_prio : InnoDB does not use table-level locking
+
diff --git a/storage/innobase/mysql-test/storage_engine/fulltext_search.rdiff b/storage/innobase/mysql-test/storage_engine/fulltext_search.rdiff
new file mode 100644
index 00000000000..f668e44109c
--- /dev/null
+++ b/storage/innobase/mysql-test/storage_engine/fulltext_search.rdiff
@@ -0,0 +1,150 @@
+--- suite/storage_engine/fulltext_search.result 2012-07-12 20:03:26.664053893 +0400
++++ suite/storage_engine/fulltext_search.reject 2012-07-15 17:49:03.616199102 +0400
+@@ -4,129 +4,27 @@
+ v2 TEXT <CUSTOM_COL_OPTIONS>,
+ FULLTEXT v1 (v1)
+ ) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+-SHOW INDEXES IN t1;
+-Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment
+-t1 1 v1 1 v1 # # NULL NULL YES FULLTEXT
+-INSERT INTO t1 (v0,v1,v2) VALUES ('text1','Here is a list of recommended books on MariaDB and MySQL. We\'ve provided links to Amazon.com here for convenience, but they can be found at many other bookstores, both online and off.
+-If you want to have your favorite MySQL / MariaDB book listed here, please leave a comment.
+-For developers who want to code on MariaDB or MySQL
+-* Understanding MySQL Internals by Sasha Pachev, former MySQL developer at MySQL AB.
+-o This is the only book we know about that describes the internals of MariaDB / MySQL. A must have for anyone who wants to understand and develop on MariaDB!
+-o Not all topics are covered and some parts are slightly outdated, but still the best book on this topic.
+-* MySQL 5.1 Plugin Development by Sergei Golubchik and Andrew Hutchings
+-o A must read for anyone wanting to write a plugin for MariaDB, written by the Sergei who designed the plugin interface for MySQL and MariaDB!
+-For MariaDB / MySQL end users
+-* MariaDB Crash Course by Ben Forta
+-o First MariaDB book!
+-o For people who want to learn SQL and the basics of MariaDB.
+-o Now shipping. Purchase at Amazon.com or your favorite bookseller.
+-* SQL-99 Complete, Really by Peter Gulutzan & Trudy Pelzer.
+-o Everything you wanted to know about the SQL 99 standard. Excellent reference book!
+-o Free to read in the Knowledgebase!
+-* MySQL (4th Edition) by Paul DuBois
+-o The \'default\' book to read if you wont to learn to use MySQL / MariaDB.
+-* MySQL Cookbook by Paul DuBois
+-o A lot of examples of how to use MySQL. As with all of Paul\'s books, it\'s worth its weight in gold and even enjoyable reading for such a \'dry\' subject.
+-* High Performance MySQL, Second Edition, By Baron Schwartz, Peter Zaitsev, Vadim Tkachenko, Jeremy D. Zawodny, Arjen Lentz, Derek J. Balling, et al.
+-o \"High Performance MySQL is the definitive guide to building fast, reliable systems with MySQL. Written by noted experts with years of real-world experience building very large systems, this book covers every aspect of MySQL performance in detail, and focuses on robustness, security, and data integrity. Learn advanced techniques in depth so you can bring out MySQL\'s full power.\" (From the book description at O\'Reilly)
+-
+- * MySQL Admin Cookbook
+- o A quick step-by-step guide for MySQL users and database administrators to tackle real-world challenges with MySQL configuration and administration
+-
+- * MySQL 5.0 Certification Study Guide, By Paul DuBois, Stefan Hinz, Carsten Pedersen
+- o This is the official guide to cover the passing of the two MySQL Certification examinations. It is valid till version 5.0 of the server, so while it misses all the features available in MySQL 5.1 and greater (including MariaDB 5.1 and greater), it provides a good basic understanding of MySQL for the end-user. ',
+-'There are several reasons why contributing code is one of the easiest and most rewarding ways to contribute to MariaDB:
+-
+- 1. We are very responsive toward reviews of submitted code and as soon as the review is done, the submitted code is merged into an existing MariaDB tree and made available to everyone, not just select customers.
+- 2. Code reviews are performed by the MariaDB core development team and the quality, detail, and timeliness of our reviews are better than you will find elsewhere.
+- 3. With MariaDB everyone has access to the latest code.
+- 4. If a patch is very safe and/or very useful we are willing to push it into the stable code (as long as it can\'t break any existing applications). We are willing to do this to ensure the freedom to add small, needed fixes on a stable release so users don\'t have to wait a year for something to be added which is critical to their business.
+- 5. If you are an active contributor, you can become a member of maria-captains, even if you aren\'t working for Monty Program Ab. All captains have the same rights as any other captain to accept and reject patches. Our development model is truly open for everyone.
+-The Contributing Code page details many of the actual steps involved in working with the MariaDB source code. It\'s important that you use the same tools and submit patches in the same way as other developers to keep development running smoothly.'
+- ), ('text2','test1','test2');
+-SELECT v0 FROM t1 WHERE MATCH(v1) AGAINST ('contributing' IN NATURAL LANGUAGE MODE);
+-v0
+-INSERT INTO t1 (v0,v1,v2) VALUES ('text3','test','test');
+-SELECT v0, MATCH(v1) AGAINST('contributing' IN NATURAL LANGUAGE MODE) AS rating FROM t1 WHERE MATCH(v1) AGAINST ('contributing' IN NATURAL LANGUAGE MODE);
+-v0 rating
+-INSERT INTO t1 (v0,v1,v2) VALUES ('text4','Contributing more...','...is a good idea'),('text5','test','test');
+-SELECT v0, MATCH(v1) AGAINST('contributing') AS rating FROM t1 WHERE MATCH(v1) AGAINST ('contributing');
+-v0 rating
+-text4 1.3705332279205322
+-SELECT v0 FROM t1 WHERE MATCH(v1,v2) AGAINST ('-test1 +critical +Cook*' IN BOOLEAN MODE);
+-v0
+-text1
+-SELECT v0 FROM t1 WHERE MATCH(v1,v2) AGAINST ('-patch +critical +Cook*' IN BOOLEAN MODE);
+-v0
+-SELECT v0, MATCH(v1) AGAINST('database' WITH QUERY EXPANSION) AS rating FROM t1 WHERE MATCH(v1) AGAINST ('database' WITH QUERY EXPANSION);
+-v0 rating
+-text1 178.11756896972656
+-DROP TABLE t1;
++ERROR HY000: The used table type doesn't support FULLTEXT indexes
++# ERROR: Statement ended with errno 1214, errname ER_TABLE_CANT_HANDLE_FT (expected to succeed)
++# ------------ UNEXPECTED RESULT ------------
++# The statement|command finished with ER_TABLE_CANT_HANDLE_FT.
++# FULLTEXT indexes or VARCHAR|TEXT data types or the mix could be unsupported|malfunctioning, or the problem was caused by previous errors.
++# You can change the engine code, or create an rdiff, or disable the test by adding it to disabled.def.
++# Further in this test, the message might sometimes be suppressed; a part of the test might be skipped.
++# Also, this problem may cause a chain effect (more errors of different kinds in the test).
++# -------------------------------------------
+ CREATE TABLE t1 (v0 VARCHAR(64) <CUSTOM_COL_OPTIONS>,
+ v1 VARCHAR(16384) <CUSTOM_COL_OPTIONS>,
+ v2 TEXT <CUSTOM_COL_OPTIONS>,
+ FULLTEXT v1 (v1),
+ FULLTEXT v1_v2 (v1,v2)
+ ) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+-SHOW INDEXES IN t1;
+-Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment
+-t1 1 v1 1 v1 # # NULL NULL YES FULLTEXT
+-t1 1 v1_v2 1 v1 # # NULL NULL YES FULLTEXT
+-t1 1 v1_v2 2 v2 # # NULL NULL YES FULLTEXT
+-INSERT INTO t1 (v0,v1,v2) VALUES ('text1','Here is a list of recommended books on MariaDB and MySQL. We\'ve provided links to Amazon.com here for convenience, but they can be found at many other bookstores, both online and off.
+-If you want to have your favorite MySQL / MariaDB book listed here, please leave a comment.
+-For developers who want to code on MariaDB or MySQL
+-* Understanding MySQL Internals by Sasha Pachev, former MySQL developer at MySQL AB.
+-o This is the only book we know about that describes the internals of MariaDB / MySQL. A must have for anyone who wants to understand and develop on MariaDB!
+-o Not all topics are covered and some parts are slightly outdated, but still the best book on this topic.
+-* MySQL 5.1 Plugin Development by Sergei Golubchik and Andrew Hutchings
+-o A must read for anyone wanting to write a plugin for MariaDB, written by the Sergei who designed the plugin interface for MySQL and MariaDB!
+-For MariaDB / MySQL end users
+-* MariaDB Crash Course by Ben Forta
+-o First MariaDB book!
+-o For people who want to learn SQL and the basics of MariaDB.
+-o Now shipping. Purchase at Amazon.com or your favorite bookseller.
+-* SQL-99 Complete, Really by Peter Gulutzan & Trudy Pelzer.
+-o Everything you wanted to know about the SQL 99 standard. Excellent reference book!
+-o Free to read in the Knowledgebase!
+-* MySQL (4th Edition) by Paul DuBois
+-o The \'default\' book to read if you wont to learn to use MySQL / MariaDB.
+-* MySQL Cookbook by Paul DuBois
+-o A lot of examples of how to use MySQL. As with all of Paul\'s books, it\'s worth its weight in gold and even enjoyable reading for such a \'dry\' subject.
+-* High Performance MySQL, Second Edition, By Baron Schwartz, Peter Zaitsev, Vadim Tkachenko, Jeremy D. Zawodny, Arjen Lentz, Derek J. Balling, et al.
+-o \"High Performance MySQL is the definitive guide to building fast, reliable systems with MySQL. Written by noted experts with years of real-world experience building very large systems, this book covers every aspect of MySQL performance in detail, and focuses on robustness, security, and data integrity. Learn advanced techniques in depth so you can bring out MySQL\'s full power.\" (From the book description at O\'Reilly)
+-
+- * MySQL Admin Cookbook
+- o A quick step-by-step guide for MySQL users and database administrators to tackle real-world challenges with MySQL configuration and administration
+-
+- * MySQL 5.0 Certification Study Guide, By Paul DuBois, Stefan Hinz, Carsten Pedersen
+- o This is the official guide to cover the passing of the two MySQL Certification examinations. It is valid till version 5.0 of the server, so while it misses all the features available in MySQL 5.1 and greater (including MariaDB 5.1 and greater), it provides a good basic understanding of MySQL for the end-user. ',
+-'There are several reasons why contributing code is one of the easiest and most rewarding ways to contribute to MariaDB:
+-
+- 1. We are very responsive toward reviews of submitted code and as soon as the review is done, the submitted code is merged into an existing MariaDB tree and made available to everyone, not just select customers.
+- 2. Code reviews are performed by the MariaDB core development team and the quality, detail, and timeliness of our reviews are better than you will find elsewhere.
+- 3. With MariaDB everyone has access to the latest code.
+- 4. If a patch is very safe and/or very useful we are willing to push it into the stable code (as long as it can\'t break any existing applications). We are willing to do this to ensure the freedom to add small, needed fixes on a stable release so users don\'t have to wait a year for something to be added which is critical to their business.
+- 5. If you are an active contributor, you can become a member of maria-captains, even if you aren\'t working for Monty Program Ab. All captains have the same rights as any other captain to accept and reject patches. Our development model is truly open for everyone.
+-The Contributing Code page details many of the actual steps involved in working with the MariaDB source code. It\'s important that you use the same tools and submit patches in the same way as other developers to keep development running smoothly.'
+- ), ('text2','test1','test2');
+-SELECT v0 FROM t1 WHERE MATCH(v1,v2) AGAINST ('contributing' IN NATURAL LANGUAGE MODE);
+-v0
+-INSERT INTO t1 (v0,v1,v2) VALUES ('text3','test','test');
+-SELECT v0, MATCH(v1,v2) AGAINST('contributing' IN NATURAL LANGUAGE MODE) AS rating FROM t1 WHERE MATCH(v1,v2) AGAINST ('contributing' IN NATURAL LANGUAGE MODE);
+-v0 rating
+-text1 0.2809644043445587
+-INSERT INTO t1 (v0,v1,v2) VALUES ('text4','Contributing more...','...is a good idea'),('text5','test','test');
+-SELECT v0, MATCH(v1) AGAINST('contributing') AS rating FROM t1 WHERE MATCH(v1) AGAINST ('contributing');
+-v0 rating
+-text4 1.3705332279205322
+-SELECT v0 FROM t1 WHERE MATCH(v1,v2) AGAINST ('-test1 +critical +Cook*' IN BOOLEAN MODE);
+-v0
+-text1
+-SELECT v0 FROM t1 WHERE MATCH(v1,v2) AGAINST ('-patch +critical +Cook*' IN BOOLEAN MODE);
+-v0
+-SELECT v0, MATCH(v1,v2) AGAINST('database' WITH QUERY EXPANSION) AS rating FROM t1 WHERE MATCH(v1,v2) AGAINST ('database' WITH QUERY EXPANSION);
+-v0 rating
+-text1 190.56150817871094
+-text4 1.1758291721343994
+-DROP TABLE t1;
++ERROR HY000: The used table type doesn't support FULLTEXT indexes
++# ERROR: Statement ended with errno 1214, errname ER_TABLE_CANT_HANDLE_FT (expected to succeed)
++# ------------ UNEXPECTED RESULT ------------
++# The statement|command finished with ER_TABLE_CANT_HANDLE_FT.
++# FULLTEXT indexes or multiple keys or VARCHAR|TEXT data types or the mix could be unsupported|malfunctioning, or the problem was caused by previous errors.
++# You can change the engine code, or create an rdiff, or disable the test by adding it to disabled.def.
++# Further in this test, the message might sometimes be suppressed; a part of the test might be skipped.
++# Also, this problem may cause a chain effect (more errors of different kinds in the test).
++# -------------------------------------------
diff --git a/storage/innobase/mysql-test/storage_engine/index_enable_disable.rdiff b/storage/innobase/mysql-test/storage_engine/index_enable_disable.rdiff
new file mode 100644
index 00000000000..23aa66d2568
--- /dev/null
+++ b/storage/innobase/mysql-test/storage_engine/index_enable_disable.rdiff
@@ -0,0 +1,33 @@
+--- suite/storage_engine/index_enable_disable.result 2012-07-15 00:30:05.296641931 +0400
++++ suite/storage_engine/index_enable_disable.reject 2012-07-15 17:49:12.988081281 +0400
+@@ -11,15 +11,19 @@
+ Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment
+ t1 1 a 1 a # # NULL NULL YES BTREE
+ ALTER TABLE t1 DISABLE KEYS;
++Warnings:
++Note 1031 Table storage engine for 't1' doesn't have this option
+ SHOW INDEX IN t1;
+ Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment
+-t1 1 a 1 a # # NULL NULL YES BTREE disabled
++t1 1 a 1 a # # NULL NULL YES BTREE
+ EXPLAIN SELECT a FROM t1 ORDER BY a;
+ id select_type table type possible_keys key key_len ref rows Extra
+-1 SIMPLE t1 ALL NULL NULL NULL NULL 19 Using filesort
++1 SIMPLE t1 index NULL a 5 NULL 19 Using index
+ INSERT INTO t1 (a) VALUES
+ (11),(12),(13),(14),(15),(16),(17),(18),(19),(20);
+ ALTER TABLE t1 ENABLE KEYS;
++Warnings:
++Note 1031 Table storage engine for 't1' doesn't have this option
+ SHOW INDEX IN t1;
+ Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment
+ t1 1 a 1 a # # NULL NULL YES BTREE
+@@ -32,6 +36,8 @@
+ (1),(2),(3),(4),(5),(6),(7),(8),(9),
+ (21),(22),(23),(24),(25),(26),(27),(28),(29);
+ ALTER TABLE t1 DISABLE KEYS;
++Warnings:
++Note 1031 Table storage engine for 't1' doesn't have this option
+ INSERT INTO t1 (a) VALUES (29);
+ ERROR 23000: Duplicate entry '29' for key 'a'
+ # Statement ended with one of expected results (ER_DUP_ENTRY,ER_DUP_KEY).
diff --git a/storage/innobase/mysql-test/storage_engine/index_type_hash.rdiff b/storage/innobase/mysql-test/storage_engine/index_type_hash.rdiff
new file mode 100644
index 00000000000..02f9d93588f
--- /dev/null
+++ b/storage/innobase/mysql-test/storage_engine/index_type_hash.rdiff
@@ -0,0 +1,60 @@
+--- suite/storage_engine/index_type_hash.result 2012-07-15 01:10:17.919128889 +0400
++++ suite/storage_engine/index_type_hash.reject 2012-07-15 17:49:26.135915989 +0400
+@@ -4,7 +4,7 @@
+ ) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+ SHOW KEYS IN t1;
+ Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment
+-t1 1 a 1 a # # NULL NULL # HASH
++t1 1 a 1 a # # NULL NULL # BTREE
+ DROP TABLE t1;
+ CREATE TABLE t1 (a <INT_COLUMN>,
+ b <CHAR_COLUMN>,
+@@ -12,8 +12,8 @@
+ ) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+ SHOW KEYS IN t1;
+ Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment
+-t1 1 a_b 1 a # # NULL NULL # HASH a_b index
+-t1 1 a_b 2 b # # NULL NULL # HASH a_b index
++t1 1 a_b 1 a # # NULL NULL # BTREE a_b index
++t1 1 a_b 2 b # # NULL NULL # BTREE a_b index
+ DROP TABLE t1;
+ CREATE TABLE t1 (a <INT_COLUMN>,
+ b <CHAR_COLUMN>,
+@@ -22,8 +22,8 @@
+ ) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+ SHOW KEYS IN t1;
+ Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment
+-t1 1 a 1 a # # NULL NULL # HASH
+-t1 1 b 1 b # # NULL NULL # HASH
++t1 1 a 1 a # # NULL NULL # BTREE
++t1 1 b 1 b # # NULL NULL # BTREE
+ DROP TABLE t1;
+ CREATE TABLE t1 (a <INT_COLUMN>,
+ b <CHAR_COLUMN>,
+@@ -31,7 +31,7 @@
+ ) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+ SHOW KEYS IN t1;
+ Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment
+-t1 0 a 1 a # # NULL NULL # HASH
++t1 0 a 1 a # # NULL NULL # BTREE
+ INSERT INTO t1 (a,b) VALUES (1,'a'),(2,'b');
+ INSERT INTO t1 (a,b) VALUES (1,'c');
+ ERROR 23000: Duplicate entry '1' for key 'a'
+@@ -43,7 +43,7 @@
+ ALTER TABLE t1 ADD <CUSTOM_INDEX> (a) USING HASH COMMENT 'simple index on a';
+ SHOW INDEX FROM t1;
+ Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment
+-t1 1 a 1 a # # NULL NULL # HASH simple index on a
++t1 1 a 1 a # # NULL NULL # BTREE simple index on a
+ ALTER TABLE t1 DROP KEY a;
+ DROP TABLE t1;
+ CREATE TABLE t1 (a <INT_COLUMN>,
+@@ -52,7 +52,7 @@
+ ) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+ SHOW KEYS IN t1;
+ Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment
+-t1 0 a 1 a # # NULL NULL # HASH
++t1 0 a 1 a # # NULL NULL # BTREE
+ INSERT INTO t1 (a,b) VALUES (1,'a'),(2,'b');
+ INSERT INTO t1 (a,b) VALUES (1,'c');
+ ERROR 23000: Duplicate entry '1' for key 'a'
diff --git a/storage/innobase/mysql-test/storage_engine/insert_delayed.rdiff b/storage/innobase/mysql-test/storage_engine/insert_delayed.rdiff
new file mode 100644
index 00000000000..62895fa928f
--- /dev/null
+++ b/storage/innobase/mysql-test/storage_engine/insert_delayed.rdiff
@@ -0,0 +1,26 @@
+--- suite/storage_engine/insert_delayed.result 2012-07-12 20:04:07.143544998 +0400
++++ suite/storage_engine/insert_delayed.reject 2012-07-15 17:49:34.551810189 +0400
+@@ -5,7 +5,16 @@
+ connect con0,localhost,root,,;
+ SET lock_wait_timeout = 1;
+ INSERT DELAYED INTO t1 (a,b) VALUES (3,'c');
++ERROR HY000: DELAYED option not supported for table 't1'
++# ------------ UNEXPECTED RESULT ------------
++# The statement|command finished with ER_DELAYED_NOT_SUPPORTED.
++# INSERT DELAYED or the mix could be unsupported|malfunctioning, or the problem was caused by previous errors.
++# You can change the engine code, or create an rdiff, or disable the test by adding it to disabled.def.
++# Further in this test, the message might sometimes be suppressed; a part of the test might be skipped.
++# Also, this problem may cause a chain effect (more errors of different kinds in the test).
++# -------------------------------------------
+ INSERT DELAYED INTO t1 SET a=4, b='d';
++ERROR HY000: DELAYED option not supported for table 't1'
+ INSERT DELAYED INTO t1 SELECT 5, 'e';
+ ERROR HY000: Lock wait timeout exceeded; try restarting transaction
+ disconnect con0;
+@@ -20,6 +29,4 @@
+ a b
+ 1 f
+ 2 b
+-3 c
+-4 d
+ DROP TABLE t1;
diff --git a/storage/innobase/mysql-test/storage_engine/lock_concurrent.rdiff b/storage/innobase/mysql-test/storage_engine/lock_concurrent.rdiff
new file mode 100644
index 00000000000..fe4a0087fa9
--- /dev/null
+++ b/storage/innobase/mysql-test/storage_engine/lock_concurrent.rdiff
@@ -0,0 +1,22 @@
+--- suite/storage_engine/lock_concurrent.result 2012-06-24 23:55:19.539380000 +0400
++++ suite/storage_engine/lock_concurrent.reject 2012-07-15 17:50:21.279222746 +0400
+@@ -3,10 +3,19 @@
+ LOCK TABLES t1 WRITE CONCURRENT, t1 AS t2 READ;
+ SET lock_wait_timeout = 1;
+ LOCK TABLES t1 READ LOCAL;
++ERROR HY000: Lock wait timeout exceeded; try restarting transaction
++# ------------ UNEXPECTED RESULT ------------
++# The statement|command finished with ER_LOCK_WAIT_TIMEOUT.
++# LOCK .. WRITE CONCURRENT or the mix could be unsupported|malfunctioning, or the problem was caused by previous errors.
++# You can change the engine code, or create an rdiff, or disable the test by adding it to disabled.def.
++# Further in this test, the message might sometimes be suppressed; a part of the test might be skipped.
++# Also, this problem may cause a chain effect (more errors of different kinds in the test).
++# -------------------------------------------
+ UNLOCK TABLES;
+ UNLOCK TABLES;
+ LOCK TABLES t1 READ LOCAL;
+ LOCK TABLES t1 WRITE CONCURRENT, t1 AS t2 READ;
++ERROR HY000: Lock wait timeout exceeded; try restarting transaction
+ UNLOCK TABLES;
+ UNLOCK TABLES;
+ DROP TABLE t1;
diff --git a/storage/innobase/mysql-test/storage_engine/optimize_table.rdiff b/storage/innobase/mysql-test/storage_engine/optimize_table.rdiff
new file mode 100644
index 00000000000..54d1f600516
--- /dev/null
+++ b/storage/innobase/mysql-test/storage_engine/optimize_table.rdiff
@@ -0,0 +1,37 @@
+--- suite/storage_engine/optimize_table.result 2012-07-12 19:13:53.741428591 +0400
++++ suite/storage_engine/optimize_table.reject 2012-07-15 17:50:30.843102510 +0400
+@@ -5,25 +5,32 @@
+ INSERT INTO t1 (a,b) VALUES (3,'c'),(4,'d');
+ OPTIMIZE TABLE t1;
+ Table Op Msg_type Msg_text
++test.t1 optimize note Table does not support optimize, doing recreate + analyze instead
+ test.t1 optimize status OK
+ INSERT INTO t2 (a,b) VALUES (4,'d');
+ OPTIMIZE NO_WRITE_TO_BINLOG TABLE t2;
+ Table Op Msg_type Msg_text
++test.t2 optimize note Table does not support optimize, doing recreate + analyze instead
+ test.t2 optimize status OK
+ INSERT INTO t2 (a,b) VALUES (5,'e');
+ INSERT INTO t1 (a,b) VALUES (6,'f');
+ OPTIMIZE LOCAL TABLE t1, t2;
+ Table Op Msg_type Msg_text
++test.t1 optimize note Table does not support optimize, doing recreate + analyze instead
+ test.t1 optimize status OK
++test.t2 optimize note Table does not support optimize, doing recreate + analyze instead
+ test.t2 optimize status OK
+ OPTIMIZE TABLE t1, t2;
+ Table Op Msg_type Msg_text
+-test.t1 optimize status Table is already up to date
+-test.t2 optimize status Table is already up to date
++test.t1 optimize note Table does not support optimize, doing recreate + analyze instead
++test.t1 optimize status OK
++test.t2 optimize note Table does not support optimize, doing recreate + analyze instead
++test.t2 optimize status OK
+ DROP TABLE t1, t2;
+ CREATE TABLE t1 (a <INT_COLUMN>, b <CHAR_COLUMN>, <CUSTOM_INDEX> (a)) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+ INSERT INTO t1 (a,b) VALUES (1,'a'),(100,'b'),(2,'c'),(3,'d');
+ OPTIMIZE TABLE t1;
+ Table Op Msg_type Msg_text
++test.t1 optimize note Table does not support optimize, doing recreate + analyze instead
+ test.t1 optimize status OK
+ DROP TABLE t1;
diff --git a/storage/innobase/mysql-test/storage_engine/parts/checksum_table.rdiff b/storage/innobase/mysql-test/storage_engine/parts/checksum_table.rdiff
new file mode 100644
index 00000000000..3d4d2a683d9
--- /dev/null
+++ b/storage/innobase/mysql-test/storage_engine/parts/checksum_table.rdiff
@@ -0,0 +1,22 @@
+--- suite/storage_engine/parts/checksum_table.result 2012-07-12 21:41:00.754458011 +0400
++++ suite/storage_engine/parts/checksum_table.reject 2012-07-15 20:04:35.881962676 +0400
+@@ -24,15 +24,15 @@
+ CREATE TABLE t2 (a <INT_COLUMN>, b <CHAR_COLUMN>) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS> CHECKSUM=1 PARTITION BY HASH(a) PARTITIONS 2;
+ CHECKSUM TABLE t1;
+ Table Checksum
+-test.t1 0
++test.t1 4272806499
+ CHECKSUM TABLE t2, t1;
+ Table Checksum
+ test.t2 0
+-test.t1 0
++test.t1 4272806499
+ CHECKSUM TABLE t1, t2 QUICK;
+ Table Checksum
+-test.t1 0
+-test.t2 0
++test.t1 NULL
++test.t2 NULL
+ CHECKSUM TABLE t1, t2 EXTENDED;
+ Table Checksum
+ test.t1 4272806499
diff --git a/storage/innobase/mysql-test/storage_engine/parts/create_table.rdiff b/storage/innobase/mysql-test/storage_engine/parts/create_table.rdiff
new file mode 100644
index 00000000000..0df91c6fc6e
--- /dev/null
+++ b/storage/innobase/mysql-test/storage_engine/parts/create_table.rdiff
@@ -0,0 +1,20 @@
+--- suite/storage_engine/parts/create_table.result 2012-07-12 21:56:38.618667460 +0400
++++ suite/storage_engine/parts/create_table.reject 2012-07-15 20:06:43.496358345 +0400
+@@ -65,7 +65,7 @@
+ 1 SIMPLE t1 abc,def # # # # # # #
+ EXPLAIN PARTITIONS SELECT a FROM t1 WHERE a = 100;
+ id select_type table partitions type possible_keys key key_len ref rows Extra
+-1 SIMPLE NULL NULL # # # # # # #
++1 SIMPLE t1 def # # # # # # #
+ INSERT INTO t1 (a) VALUES (50);
+ ERROR HY000: Table has no partition for value 50
+ DROP TABLE t1;
+@@ -81,7 +81,7 @@
+ 1 SIMPLE t1 abc_abcsp0,def_defsp0 # # # # # # #
+ EXPLAIN PARTITIONS SELECT a FROM t1 WHERE a = 100;
+ id select_type table partitions type possible_keys key key_len ref rows Extra
+-1 SIMPLE NULL NULL # # # # # # #
++1 SIMPLE t1 def_defsp0 # # # # # # #
+ SELECT TABLE_SCHEMA, TABLE_NAME, PARTITION_NAME, SUBPARTITION_NAME, PARTITION_METHOD, SUBPARTITION_METHOD
+ FROM INFORMATION_SCHEMA.PARTITIONS WHERE TABLE_NAME = 't1';
+ TABLE_SCHEMA TABLE_NAME PARTITION_NAME SUBPARTITION_NAME PARTITION_METHOD SUBPARTITION_METHOD
diff --git a/storage/innobase/mysql-test/storage_engine/parts/optimize_table.rdiff b/storage/innobase/mysql-test/storage_engine/parts/optimize_table.rdiff
new file mode 100644
index 00000000000..77ee7e2eb31
--- /dev/null
+++ b/storage/innobase/mysql-test/storage_engine/parts/optimize_table.rdiff
@@ -0,0 +1,58 @@
+--- suite/storage_engine/parts/optimize_table.result 2012-07-12 22:16:39.343572304 +0400
++++ suite/storage_engine/parts/optimize_table.reject 2012-07-15 20:07:01.632130348 +0400
+@@ -9,18 +9,22 @@
+ INSERT INTO t1 (a,b) VALUES (3,'c'),(4,'d');
+ ALTER TABLE t1 OPTIMIZE PARTITION p1;
+ Table Op Msg_type Msg_text
++test.t1 optimize note Table does not support optimize, doing recreate + analyze instead
+ test.t1 optimize status OK
+ INSERT INTO t2 (a,b) VALUES (4,'d');
+ ALTER TABLE t2 OPTIMIZE PARTITION p0 NO_WRITE_TO_BINLOG;
+ Table Op Msg_type Msg_text
++test.t2 optimize note Table does not support optimize, doing recreate + analyze instead
+ test.t2 optimize status OK
+ INSERT INTO t1 (a,b) VALUES (6,'f');
+ ALTER TABLE t1 OPTIMIZE PARTITION ALL LOCAL;
+ Table Op Msg_type Msg_text
++test.t1 optimize note Table does not support optimize, doing recreate + analyze instead
+ test.t1 optimize status OK
+ INSERT INTO t2 (a,b) VALUES (5,'e');
+ ALTER TABLE t2 OPTIMIZE PARTITION p1,p0;
+ Table Op Msg_type Msg_text
++test.t2 optimize note Table does not support optimize, doing recreate + analyze instead
+ test.t2 optimize status OK
+ DROP TABLE t1, t2;
+ DROP TABLE IF EXISTS t1,t2;
+@@ -30,25 +34,32 @@
+ INSERT INTO t1 (a,b) VALUES (3,'c'),(4,'d');
+ OPTIMIZE TABLE t1;
+ Table Op Msg_type Msg_text
++test.t1 optimize note Table does not support optimize, doing recreate + analyze instead
+ test.t1 optimize status OK
+ INSERT INTO t2 (a,b) VALUES (4,'d');
+ OPTIMIZE NO_WRITE_TO_BINLOG TABLE t2;
+ Table Op Msg_type Msg_text
++test.t2 optimize note Table does not support optimize, doing recreate + analyze instead
+ test.t2 optimize status OK
+ INSERT INTO t2 (a,b) VALUES (5,'e');
+ INSERT INTO t1 (a,b) VALUES (6,'f');
+ OPTIMIZE LOCAL TABLE t1, t2;
+ Table Op Msg_type Msg_text
++test.t1 optimize note Table does not support optimize, doing recreate + analyze instead
+ test.t1 optimize status OK
++test.t2 optimize note Table does not support optimize, doing recreate + analyze instead
+ test.t2 optimize status OK
+ OPTIMIZE TABLE t1, t2;
+ Table Op Msg_type Msg_text
++test.t1 optimize note Table does not support optimize, doing recreate + analyze instead
+ test.t1 optimize status OK
++test.t2 optimize note Table does not support optimize, doing recreate + analyze instead
+ test.t2 optimize status OK
+ DROP TABLE t1, t2;
+ CREATE TABLE t1 (a <INT_COLUMN>, b <CHAR_COLUMN>, <CUSTOM_INDEX> (a)) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS> PARTITION BY HASH(a) PARTITIONS 2;
+ INSERT INTO t1 (a,b) VALUES (1,'a'),(100,'b'),(2,'c'),(3,'d');
+ OPTIMIZE TABLE t1;
+ Table Op Msg_type Msg_text
++test.t1 optimize note Table does not support optimize, doing recreate + analyze instead
+ test.t1 optimize status OK
+ DROP TABLE t1;
diff --git a/storage/innobase/mysql-test/storage_engine/parts/repair_table.rdiff b/storage/innobase/mysql-test/storage_engine/parts/repair_table.rdiff
new file mode 100644
index 00000000000..aab866fde83
--- /dev/null
+++ b/storage/innobase/mysql-test/storage_engine/parts/repair_table.rdiff
@@ -0,0 +1,228 @@
+--- suite/storage_engine/parts/repair_table.result 2012-07-15 01:22:58.861853325 +0400
++++ suite/storage_engine/parts/repair_table.reject 2012-07-15 20:07:11.268009209 +0400
+@@ -9,27 +9,27 @@
+ INSERT INTO t2 (a,b) SELECT a, b FROM t1;
+ ALTER TABLE t1 REPAIR PARTITION p0;
+ Table Op Msg_type Msg_text
+-test.t1 repair status OK
++test.t1 repair note The storage engine for the table doesn't support repair
+ INSERT INTO t1 VALUES (3,'c');
+ ALTER TABLE t1 REPAIR PARTITION NO_WRITE_TO_BINLOG p0, p1;
+ Table Op Msg_type Msg_text
+-test.t1 repair status OK
++test.t1 repair note The storage engine for the table doesn't support repair
+ INSERT INTO t2 (a,b) VALUES (5,'e'),(6,'f');
+ ALTER TABLE t2 REPAIR PARTITION LOCAL p1;
+ Table Op Msg_type Msg_text
+-test.t2 repair status OK
++test.t2 repair note The storage engine for the table doesn't support repair
+ INSERT INTO t1 (a,b) VALUES (7,'g'),(8,'h');
+ ALTER TABLE t1 REPAIR PARTITION LOCAL ALL EXTENDED;
+ Table Op Msg_type Msg_text
+-test.t1 repair status OK
++test.t1 repair note The storage engine for the table doesn't support repair
+ INSERT INTO t1 VALUES (10,'j');
+ ALTER TABLE t1 REPAIR PARTITION p1 QUICK USE_FRM;
+ Table Op Msg_type Msg_text
+-test.t1 repair status OK
++test.t1 repair note The storage engine for the table doesn't support repair
+ INSERT INTO t2 (a,b) VALUES (12,'l');
+ ALTER TABLE t2 REPAIR PARTITION NO_WRITE_TO_BINLOG ALL QUICK EXTENDED USE_FRM;
+ Table Op Msg_type Msg_text
+-test.t2 repair status OK
++test.t2 repair note The storage engine for the table doesn't support repair
+ DROP TABLE t1, t2;
+ DROP TABLE IF EXISTS t1,t2;
+ CREATE TABLE t1 (a <INT_COLUMN>, b <CHAR_COLUMN>) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS> PARTITION BY HASH(a) PARTITIONS 2;
+@@ -37,35 +37,35 @@
+ CREATE TABLE t2 (a <INT_COLUMN>, b <CHAR_COLUMN>) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS> PARTITION BY HASH(a) PARTITIONS 2;
+ REPAIR TABLE t1;
+ Table Op Msg_type Msg_text
+-test.t1 repair status OK
++test.t1 repair note The storage engine for the table doesn't support repair
+ INSERT INTO t1 (a,b) VALUES (3,'c');
+ INSERT INTO t2 (a,b) VALUES (4,'d');
+ REPAIR NO_WRITE_TO_BINLOG TABLE t1, t2;
+ Table Op Msg_type Msg_text
+-test.t1 repair status OK
+-test.t2 repair status OK
++test.t1 repair note The storage engine for the table doesn't support repair
++test.t2 repair note The storage engine for the table doesn't support repair
+ INSERT INTO t2 (a,b) VALUES (5,'e'),(6,'f');
+ REPAIR LOCAL TABLE t2;
+ Table Op Msg_type Msg_text
+-test.t2 repair status OK
++test.t2 repair note The storage engine for the table doesn't support repair
+ INSERT INTO t1 (a,b) VALUES (7,'g'),(8,'h');
+ INSERT INTO t2 (a,b) VALUES (9,'i');
+ REPAIR LOCAL TABLE t2, t1 EXTENDED;
+ Table Op Msg_type Msg_text
+-test.t2 repair status OK
+-test.t1 repair status OK
++test.t2 repair note The storage engine for the table doesn't support repair
++test.t1 repair note The storage engine for the table doesn't support repair
+ INSERT INTO t1 (a,b) VALUES (10,'j');
+ INSERT INTO t2 (a,b) VALUES (11,'k');
+ REPAIR TABLE t1, t2 QUICK USE_FRM;
+ Table Op Msg_type Msg_text
+-test.t1 repair status OK
+-test.t2 repair status OK
++test.t1 repair note The storage engine for the table doesn't support repair
++test.t2 repair note The storage engine for the table doesn't support repair
+ INSERT INTO t1 (a,b) VALUES (12,'l');
+ INSERT INTO t2 (a,b) VALUES (13,'m');
+ REPAIR NO_WRITE_TO_BINLOG TABLE t1, t2 QUICK EXTENDED USE_FRM;
+ Table Op Msg_type Msg_text
+-test.t1 repair status OK
+-test.t2 repair status OK
++test.t1 repair note The storage engine for the table doesn't support repair
++test.t2 repair note The storage engine for the table doesn't support repair
+ FLUSH TABLE t1;
+ INSERT INTO t1 (a,b) VALUES (14,'n');
+ ERROR HY000: Failed to read from the .par file
+@@ -93,127 +93,21 @@
+ CREATE TABLE t1 (a <INT_COLUMN>, b <CHAR_COLUMN>, <CUSTOM_INDEX> (a)) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS> PARTITION BY HASH(a) PARTITIONS 2;
+ REPAIR TABLE t1;
+ Table Op Msg_type Msg_text
+-test.t1 repair status OK
++test.t1 repair note The storage engine for the table doesn't support repair
+ INSERT INTO t1 (a,b) VALUES (7,'g'),(8,'h');
+ REPAIR TABLE t1 EXTENDED;
+ Table Op Msg_type Msg_text
+-test.t1 repair status OK
++test.t1 repair note The storage engine for the table doesn't support repair
+ INSERT INTO t1 (a,b) VALUES (10,'j');
+ REPAIR TABLE t1 USE_FRM;
+ Table Op Msg_type Msg_text
+-test.t1 repair status OK
+-t1#P#p0.MYD
+-t1#P#p0.MYI
+-t1#P#p1.MYD
+-t1#P#p1.MYI
++test.t1 repair note The storage engine for the table doesn't support repair
+ t1.frm
+ t1.par
+ INSERT INTO t1 (a,b) VALUES (14,'n'),(15,'o');
+ # Statement ended with one of expected results (0,144).
+ # If you got a difference in error message, just add it to rdiff file
+ FLUSH TABLE t1;
+-Restoring <DATADIR>/test/t1#P#p0.MYD
+-CHECK TABLE t1;
+-Table Op Msg_type Msg_text
+-test.t1 check error Size of datafile is: 26 Should be: 39
+-test.t1 check error Partition p0 returned error
+-test.t1 check error Corrupt
+-SELECT * FROM t1;
+-a b
+-8 h
+-10 j
+-7 g
+-15 o
+-Warnings:
+-Error 145 Table './test/t1#P#p0' is marked as crashed and should be repaired
+-Error 1194 Table 't1' is marked as crashed and should be repaired
+-Error 1034 Number of rows changed from 3 to 2
+-# Statement ended with one of expected results (0,ER_NOT_KEYFILE,144).
+-# If you got a difference in error message, just add it to rdiff file
+-INSERT INTO t1 (a,b) VALUES (14,'n'),(15,'o');
+-# Statement ended with one of expected results (0,144).
+-# If you got a difference in error message, just add it to rdiff file
+-FLUSH TABLE t1;
+-Restoring <DATADIR>/test/t1#P#p0.MYI
+-CHECK TABLE t1;
+-Table Op Msg_type Msg_text
+-test.t1 check warning Size of datafile is: 39 Should be: 26
+-test.t1 check error Record-count is not ok; is 3 Should be: 2
+-test.t1 check warning Found 3 key parts. Should be: 2
+-test.t1 check error Partition p0 returned error
+-test.t1 check error Corrupt
+-SELECT * FROM t1;
+-a b
+-8 h
+-10 j
+-14 n
+-7 g
+-15 o
+-15 o
+-Warnings:
+-Error 145 Table './test/t1#P#p0' is marked as crashed and should be repaired
+-Error 1194 Table 't1' is marked as crashed and should be repaired
+-Error 1034 Number of rows changed from 2 to 3
+-# Statement ended with one of expected results (0,ER_NOT_KEYFILE,144).
+-# If you got a difference in error message, just add it to rdiff file
+-INSERT INTO t1 (a,b) VALUES (14,'n'),(15,'o');
+-# Statement ended with one of expected results (0,144).
+-# If you got a difference in error message, just add it to rdiff file
+-FLUSH TABLE t1;
+-Restoring <DATADIR>/test/t1#P#p1.MYD
+-CHECK TABLE t1;
+-Table Op Msg_type Msg_text
+-test.t1 check error Size of datafile is: 39 Should be: 52
+-test.t1 check error Partition p1 returned error
+-test.t1 check error Corrupt
+-SELECT * FROM t1;
+-a b
+-8 h
+-10 j
+-14 n
+-14 n
+-7 g
+-15 o
+-15 o
+-Warnings:
+-Error 145 Table './test/t1#P#p1' is marked as crashed and should be repaired
+-Error 1194 Table 't1' is marked as crashed and should be repaired
+-Error 1034 Number of rows changed from 4 to 3
+-# Statement ended with one of expected results (0,ER_NOT_KEYFILE,144).
+-# If you got a difference in error message, just add it to rdiff file
+-INSERT INTO t1 (a,b) VALUES (14,'n'),(15,'o');
+-# Statement ended with one of expected results (0,144).
+-# If you got a difference in error message, just add it to rdiff file
+-FLUSH TABLE t1;
+-Restoring <DATADIR>/test/t1#P#p1.MYI
+-CHECK TABLE t1;
+-Table Op Msg_type Msg_text
+-test.t1 check warning Size of datafile is: 52 Should be: 39
+-test.t1 check error Record-count is not ok; is 4 Should be: 3
+-test.t1 check warning Found 4 key parts. Should be: 3
+-test.t1 check error Partition p1 returned error
+-test.t1 check error Corrupt
+-SELECT * FROM t1;
+-a b
+-8 h
+-10 j
+-14 n
+-14 n
+-14 n
+-7 g
+-15 o
+-15 o
+-15 o
+-Warnings:
+-Error 145 Table './test/t1#P#p1' is marked as crashed and should be repaired
+-Error 1194 Table 't1' is marked as crashed and should be repaired
+-Error 1034 Number of rows changed from 3 to 4
+-# Statement ended with one of expected results (0,ER_NOT_KEYFILE,144).
+-# If you got a difference in error message, just add it to rdiff file
+-INSERT INTO t1 (a,b) VALUES (14,'n'),(15,'o');
+-# Statement ended with one of expected results (0,144).
+-# If you got a difference in error message, just add it to rdiff file
+-FLUSH TABLE t1;
+ Restoring <DATADIR>/test/t1.par
+ CHECK TABLE t1;
+ Table Op Msg_type Msg_text
+@@ -223,14 +117,8 @@
+ 8 h
+ 10 j
+ 14 n
+-14 n
+-14 n
+-14 n
+ 7 g
+ 15 o
+-15 o
+-15 o
+-15 o
+ # Statement ended with one of expected results (0,ER_NOT_KEYFILE,144).
+ # If you got a difference in error message, just add it to rdiff file
+ DROP TABLE t1;
diff --git a/storage/innobase/mysql-test/storage_engine/parts/suite.opt b/storage/innobase/mysql-test/storage_engine/parts/suite.opt
new file mode 100644
index 00000000000..28ae8786144
--- /dev/null
+++ b/storage/innobase/mysql-test/storage_engine/parts/suite.opt
@@ -0,0 +1,4 @@
+--ignore-builtin-innodb
+--plugin-load=ha_innodb
+--innodb
+
diff --git a/storage/innobase/mysql-test/storage_engine/repair_table.rdiff b/storage/innobase/mysql-test/storage_engine/repair_table.rdiff
new file mode 100644
index 00000000000..9c51fea47ff
--- /dev/null
+++ b/storage/innobase/mysql-test/storage_engine/repair_table.rdiff
@@ -0,0 +1,129 @@
+--- suite/storage_engine/repair_table.result 2012-07-15 01:26:44.347708000 +0400
++++ suite/storage_engine/repair_table.reject 2012-07-15 17:50:37.927013454 +0400
+@@ -4,56 +4,57 @@
+ CREATE TABLE t2 (a <INT_COLUMN>, b <CHAR_COLUMN>) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+ REPAIR TABLE t1;
+ Table Op Msg_type Msg_text
+-test.t1 repair status OK
++test.t1 repair note The storage engine for the table doesn't support repair
+ INSERT INTO t1 (a,b) VALUES (3,'c');
+ INSERT INTO t2 (a,b) VALUES (4,'d');
+ REPAIR NO_WRITE_TO_BINLOG TABLE t1, t2;
+ Table Op Msg_type Msg_text
+-test.t1 repair status OK
+-test.t2 repair status OK
++test.t1 repair note The storage engine for the table doesn't support repair
++test.t2 repair note The storage engine for the table doesn't support repair
+ INSERT INTO t2 (a,b) VALUES (5,'e'),(6,'f');
+ REPAIR LOCAL TABLE t2;
+ Table Op Msg_type Msg_text
+-test.t2 repair status OK
++test.t2 repair note The storage engine for the table doesn't support repair
+ INSERT INTO t1 (a,b) VALUES (7,'g'),(8,'h');
+ INSERT INTO t2 (a,b) VALUES (9,'i');
+ REPAIR LOCAL TABLE t2, t1 EXTENDED;
+ Table Op Msg_type Msg_text
+-test.t2 repair status OK
+-test.t1 repair status OK
++test.t2 repair note The storage engine for the table doesn't support repair
++test.t1 repair note The storage engine for the table doesn't support repair
+ INSERT INTO t1 (a,b) VALUES (10,'j');
+ INSERT INTO t2 (a,b) VALUES (11,'k');
+ REPAIR TABLE t1, t2 QUICK USE_FRM;
+ Table Op Msg_type Msg_text
+-test.t1 repair warning Number of rows changed from 0 to 6
+-test.t1 repair status OK
+-test.t2 repair warning Number of rows changed from 0 to 5
+-test.t2 repair status OK
++test.t1 repair note The storage engine for the table doesn't support repair
++test.t2 repair note The storage engine for the table doesn't support repair
+ INSERT INTO t1 (a,b) VALUES (12,'l');
+ INSERT INTO t2 (a,b) VALUES (13,'m');
+ REPAIR NO_WRITE_TO_BINLOG TABLE t1, t2 QUICK EXTENDED USE_FRM;
+ Table Op Msg_type Msg_text
+-test.t1 repair warning Number of rows changed from 0 to 7
+-test.t1 repair status OK
+-test.t2 repair warning Number of rows changed from 0 to 6
+-test.t2 repair status OK
++test.t1 repair note The storage engine for the table doesn't support repair
++test.t2 repair note The storage engine for the table doesn't support repair
+ FLUSH TABLE t1;
+ INSERT INTO t1 (a,b) VALUES (14,'n');
+-ERROR HY000: Incorrect file format 't1'
+ # Statement ended with one of expected results (0,130,ER_FAILED_READ_FROM_PAR_FILE,ER_OPEN_AS_READONLY).
+ # If you got a difference in error message, just add it to rdiff file
+ CHECK TABLE t1;
+ Table Op Msg_type Msg_text
+-test.t1 check Error Incorrect file format 't1'
+-test.t1 check error Corrupt
++test.t1 check status OK
+ SELECT * FROM t1;
+-ERROR HY000: Incorrect file format 't1'
++a b
++1 a
++2 b
++3 c
++7 g
++8 h
++10 j
++12 l
++14 n
+ # Statement ended with one of expected results (0,130,ER_FAILED_READ_FROM_PAR_FILE,ER_OPEN_AS_READONLY).
+ # If you got a difference in error message, just add it to rdiff file
+ REPAIR TABLE t1;
+ Table Op Msg_type Msg_text
+-test.t1 repair Error Incorrect file format 't1'
+-test.t1 repair error Corrupt
++test.t1 repair note The storage engine for the table doesn't support repair
+ DROP TABLE t1, t2;
+ call mtr.add_suppression("Got an error from thread_id=.*");
+ call mtr.add_suppression("MySQL thread id .*, query id .* localhost.*root Checking table");
+@@ -62,45 +63,14 @@
+ CREATE TABLE t1 (a <INT_COLUMN>, b <CHAR_COLUMN>, <CUSTOM_INDEX> (a)) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+ REPAIR TABLE t1;
+ Table Op Msg_type Msg_text
+-test.t1 repair status OK
++test.t1 repair note The storage engine for the table doesn't support repair
+ INSERT INTO t1 (a,b) VALUES (7,'g'),(8,'h');
+ REPAIR TABLE t1 EXTENDED;
+ Table Op Msg_type Msg_text
+-test.t1 repair status OK
++test.t1 repair note The storage engine for the table doesn't support repair
+ INSERT INTO t1 (a,b) VALUES (10,'j');
+ REPAIR TABLE t1 USE_FRM;
+ Table Op Msg_type Msg_text
+-test.t1 repair warning Number of rows changed from 0 to 3
+-test.t1 repair status OK
+-t1.MYD
+-t1.MYI
++test.t1 repair note The storage engine for the table doesn't support repair
+ t1.frm
+-INSERT INTO t1 (a,b) VALUES (14,'n'),(15,'o');
+-# Statement ended with one of expected results (0,144).
+-# If you got a difference in error message, just add it to rdiff file
+-FLUSH TABLE t1;
+-Restoring <DATADIR>/test/t1.MYD
+-CHECK TABLE t1;
+-Table Op Msg_type Msg_text
+-test.t1 check error Size of datafile is: 39 Should be: 65
+-test.t1 check error Corrupt
+-SELECT * FROM t1;
+-ERROR HY000: Incorrect key file for table 't1'; try to repair it
+-# Statement ended with one of expected results (0,ER_NOT_KEYFILE,144).
+-# If you got a difference in error message, just add it to rdiff file
+-INSERT INTO t1 (a,b) VALUES (14,'n'),(15,'o');
+-ERROR HY000: Table './test/t1' is marked as crashed and last (automatic?) repair failed
+-# Statement ended with one of expected results (0,144).
+-# If you got a difference in error message, just add it to rdiff file
+-FLUSH TABLE t1;
+-Restoring <DATADIR>/test/t1.MYI
+-CHECK TABLE t1;
+-Table Op Msg_type Msg_text
+-test.t1 check warning Table is marked as crashed and last repair failed
+-test.t1 check error Size of datafile is: 39 Should be: 65
+-test.t1 check error Corrupt
+-SELECT * FROM t1;
+-ERROR HY000: Table './test/t1' is marked as crashed and last (automatic?) repair failed
+-# Statement ended with one of expected results (0,ER_NOT_KEYFILE,144).
+-# If you got a difference in error message, just add it to rdiff file
+ DROP TABLE t1;
diff --git a/storage/innobase/mysql-test/storage_engine/suite.opt b/storage/innobase/mysql-test/storage_engine/suite.opt
new file mode 100644
index 00000000000..28ae8786144
--- /dev/null
+++ b/storage/innobase/mysql-test/storage_engine/suite.opt
@@ -0,0 +1,4 @@
+--ignore-builtin-innodb
+--plugin-load=ha_innodb
+--innodb
+
diff --git a/storage/innobase/mysql-test/storage_engine/tbl_opt_data_index_dir.rdiff b/storage/innobase/mysql-test/storage_engine/tbl_opt_data_index_dir.rdiff
new file mode 100644
index 00000000000..47f624c73d9
--- /dev/null
+++ b/storage/innobase/mysql-test/storage_engine/tbl_opt_data_index_dir.rdiff
@@ -0,0 +1,18 @@
+--- suite/storage_engine/tbl_opt_data_index_dir.result 2012-06-24 23:55:19.539380000 +0400
++++ suite/storage_engine/tbl_opt_data_index_dir.reject 2012-07-15 17:51:04.070684784 +0400
+@@ -4,7 +4,7 @@
+ t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL,
+ `b` char(8) DEFAULT NULL
+-) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 DATA DIRECTORY='<DATA_DIR>' INDEX DIRECTORY='<INDEX_DIR>'
++) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1
+ Warnings:
+ Warning 1618 <INDEX DIRECTORY> option ignored
+ SHOW CREATE TABLE t1;
+@@ -12,5 +12,5 @@
+ t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL,
+ `b` char(8) DEFAULT NULL
+-) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 DATA DIRECTORY='<DATA_DIR>' INDEX DIRECTORY='<INDEX_DIR>'
++) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1
+ DROP TABLE t1;
diff --git a/storage/innobase/mysql-test/storage_engine/tbl_opt_insert_method.rdiff b/storage/innobase/mysql-test/storage_engine/tbl_opt_insert_method.rdiff
new file mode 100644
index 00000000000..468b82926f0
--- /dev/null
+++ b/storage/innobase/mysql-test/storage_engine/tbl_opt_insert_method.rdiff
@@ -0,0 +1,11 @@
+--- suite/storage_engine/tbl_opt_insert_method.result 2012-06-24 23:55:19.539380000 +0400
++++ suite/storage_engine/tbl_opt_insert_method.reject 2012-07-15 17:51:09.978610512 +0400
+@@ -5,7 +5,7 @@
+ t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL,
+ `b` char(8) DEFAULT NULL
+-) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 INSERT_METHOD=FIRST
++) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1
+ ALTER TABLE t1 INSERT_METHOD=NO;
+ SHOW CREATE TABLE t1;
+ Table Create Table
diff --git a/storage/innobase/mysql-test/storage_engine/tbl_opt_key_block_size.opt b/storage/innobase/mysql-test/storage_engine/tbl_opt_key_block_size.opt
new file mode 100644
index 00000000000..7cd737b2b87
--- /dev/null
+++ b/storage/innobase/mysql-test/storage_engine/tbl_opt_key_block_size.opt
@@ -0,0 +1,3 @@
+--innodb-file-per-table=1
+--innodb-file-format=Barracuda
+
diff --git a/storage/innobase/mysql-test/storage_engine/tbl_opt_row_format.opt b/storage/innobase/mysql-test/storage_engine/tbl_opt_row_format.opt
new file mode 100644
index 00000000000..7cd737b2b87
--- /dev/null
+++ b/storage/innobase/mysql-test/storage_engine/tbl_opt_row_format.opt
@@ -0,0 +1,3 @@
+--innodb-file-per-table=1
+--innodb-file-format=Barracuda
+
diff --git a/storage/innobase/mysql-test/storage_engine/tbl_opt_row_format.rdiff b/storage/innobase/mysql-test/storage_engine/tbl_opt_row_format.rdiff
new file mode 100644
index 00000000000..4c0e0c375f5
--- /dev/null
+++ b/storage/innobase/mysql-test/storage_engine/tbl_opt_row_format.rdiff
@@ -0,0 +1,10 @@
+--- suite/storage_engine/tbl_opt_row_format.result 2012-06-24 23:55:19.539380000 +0400
++++ suite/storage_engine/tbl_opt_row_format.reject 2012-07-15 19:26:02.235049157 +0400
+@@ -1,5 +1,7 @@
+ DROP TABLE IF EXISTS t1;
+ CREATE TABLE t1 (a <INT_COLUMN>, b <CHAR_COLUMN>) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS> ROW_FORMAT=FIXED;
++Warnings:
++Warning 1478 InnoDB: assuming ROW_FORMAT=COMPACT.
+ SHOW CREATE TABLE t1;
+ Table Create Table
+ t1 CREATE TABLE `t1` (
diff --git a/storage/innobase/mysql-test/storage_engine/tbl_opt_union.rdiff b/storage/innobase/mysql-test/storage_engine/tbl_opt_union.rdiff
new file mode 100644
index 00000000000..cbdf5818022
--- /dev/null
+++ b/storage/innobase/mysql-test/storage_engine/tbl_opt_union.rdiff
@@ -0,0 +1,16 @@
+--- suite/storage_engine/tbl_opt_union.result 2012-06-24 23:55:19.539380000 +0400
++++ suite/storage_engine/tbl_opt_union.reject 2012-07-15 17:51:31.014346053 +0400
+@@ -4,11 +4,11 @@
+ Table Create Table
+ t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+-) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 UNION=(`child1`)
++) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1
+ ALTER TABLE t1 UNION = (child1,child2);
+ SHOW CREATE TABLE t1;
+ Table Create Table
+ t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+-) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 UNION=(`child1`,`child2`)
++) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1
+ DROP TABLE t1, child1, child2;
diff --git a/storage/innobase/mysql-test/storage_engine/trx/disabled.def b/storage/innobase/mysql-test/storage_engine/trx/disabled.def
new file mode 100644
index 00000000000..7b8a16d0b7a
--- /dev/null
+++ b/storage/innobase/mysql-test/storage_engine/trx/disabled.def
@@ -0,0 +1,2 @@
+cons_snapshot_serializable : MySQL:65146 (CONSISTENT SNAPSHOT does not work with SERIALIZABLE)
+
diff --git a/storage/innobase/mysql-test/storage_engine/trx/suite.opt b/storage/innobase/mysql-test/storage_engine/trx/suite.opt
new file mode 100644
index 00000000000..2bf66f067f6
--- /dev/null
+++ b/storage/innobase/mysql-test/storage_engine/trx/suite.opt
@@ -0,0 +1,5 @@
+--ignore-builtin-innodb
+--plugin-load=ha_innodb
+--innodb
+--innodb-lock-wait-timeout=1
+
diff --git a/storage/innobase/mysql-test/storage_engine/type_char_indexes.rdiff b/storage/innobase/mysql-test/storage_engine/type_char_indexes.rdiff
new file mode 100644
index 00000000000..7fce0a108e9
--- /dev/null
+++ b/storage/innobase/mysql-test/storage_engine/type_char_indexes.rdiff
@@ -0,0 +1,20 @@
+--- suite/storage_engine/type_char_indexes.result 2012-07-12 19:27:42.191013570 +0400
++++ suite/storage_engine/type_char_indexes.reject 2012-07-15 17:51:55.810034331 +0400
+@@ -98,7 +98,7 @@
+ SET SESSION optimizer_switch = 'engine_condition_pushdown=on';
+ EXPLAIN SELECT * FROM t1 WHERE c > 'a';
+ id select_type table type possible_keys key key_len ref rows Extra
+-# # # range c_v c_v # # # Using index condition
++# # # range c_v c_v # # # Using where
+ SELECT * FROM t1 WHERE c > 'a';
+ c c20 v16 v128
+ b char3 varchar1a varchar1b
+@@ -135,7 +135,7 @@
+ r3a
+ EXPLAIN SELECT * FROM t1 WHERE v16 = 'varchar1a' OR v16 = 'varchar3a' ORDER BY v16;
+ id select_type table type possible_keys key key_len ref rows Extra
+-# # # range # v16 # # # #
++# # # ALL # NULL # # # #
+ SELECT * FROM t1 WHERE v16 = 'varchar1a' OR v16 = 'varchar3a' ORDER BY v16;
+ c c20 v16 v128
+ a char1 varchar1a varchar1b
diff --git a/storage/innobase/mysql-test/storage_engine/type_float_indexes.rdiff b/storage/innobase/mysql-test/storage_engine/type_float_indexes.rdiff
new file mode 100644
index 00000000000..6ebfd61d876
--- /dev/null
+++ b/storage/innobase/mysql-test/storage_engine/type_float_indexes.rdiff
@@ -0,0 +1,11 @@
+--- suite/storage_engine/type_float_indexes.result 2012-07-12 19:37:27.031661128 +0400
++++ suite/storage_engine/type_float_indexes.reject 2012-07-15 17:52:12.189828410 +0400
+@@ -60,7 +60,7 @@
+ ALTER TABLE t1 ADD UNIQUE KEY(d);
+ EXPLAIN SELECT d FROM t1 WHERE r > 0 and d > 0 ORDER BY d;
+ id select_type table type possible_keys key key_len ref rows Extra
+-# # # # # d # # # #
++# # # # # NULL # # # #
+ SELECT d FROM t1 WHERE r > 0 and d > 0 ORDER BY d;
+ d
+ 1.2345
diff --git a/storage/innobase/mysql-test/storage_engine/type_spatial_indexes.rdiff b/storage/innobase/mysql-test/storage_engine/type_spatial_indexes.rdiff
new file mode 100644
index 00000000000..9a9566deafb
--- /dev/null
+++ b/storage/innobase/mysql-test/storage_engine/type_spatial_indexes.rdiff
@@ -0,0 +1,712 @@
+--- suite/storage_engine/type_spatial_indexes.result 2012-07-12 04:52:40.840023344 +0400
++++ suite/storage_engine/type_spatial_indexes.reject 2012-07-15 19:27:32.761911079 +0400
+@@ -702,699 +702,15 @@
+ DROP DATABASE IF EXISTS gis_ogs;
+ CREATE DATABASE gis_ogs;
+ CREATE TABLE gis_point (fid <INT_COLUMN>, g POINT NOT NULL, SPATIAL INDEX(g)) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+-CREATE TABLE gis_line (fid <INT_COLUMN>, g LINESTRING NOT NULL, SPATIAL INDEX(g)) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+-CREATE TABLE gis_polygon (fid <INT_COLUMN>, g POLYGON NOT NULL, SPATIAL INDEX(g)) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+-CREATE TABLE gis_multi_point (fid <INT_COLUMN>, g MULTIPOINT NOT NULL, SPATIAL INDEX(g)) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+-CREATE TABLE gis_multi_line (fid <INT_COLUMN>, g MULTILINESTRING NOT NULL, SPATIAL INDEX(g)) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+-CREATE TABLE gis_multi_polygon (fid <INT_COLUMN>, g MULTIPOLYGON NOT NULL, SPATIAL INDEX(g)) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+-CREATE TABLE gis_geometrycollection (fid <INT_COLUMN>, g GEOMETRYCOLLECTION NOT NULL, SPATIAL INDEX(g)) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+-CREATE TABLE gis_geometry (fid <INT_COLUMN>, g GEOMETRY NOT NULL) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+-USE gis_ogs;
+-CREATE TABLE lakes (fid INT <CUSTOM_COL_OPTIONS>,
+-name CHAR(64) <CUSTOM_COL_OPTIONS>,
+-shore POLYGON NOT NULL, SPATIAL INDEX s(shore)) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+-CREATE TABLE road_segments (fid INT <CUSTOM_COL_OPTIONS>,
+-name CHAR(64) <CUSTOM_COL_OPTIONS>,
+-aliases CHAR(64) <CUSTOM_COL_OPTIONS>,
+-num_lanes INT <CUSTOM_COL_OPTIONS>,
+-centerline LINESTRING NOT NULL, SPATIAL INDEX c(centerline)) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+-CREATE TABLE divided_routes (fid INT <CUSTOM_COL_OPTIONS>,
+-name CHAR(64) <CUSTOM_COL_OPTIONS>,
+-num_lanes INT <CUSTOM_COL_OPTIONS>,
+-centerlines MULTILINESTRING NOT NULL, SPATIAL INDEX c(centerlines)) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+-CREATE TABLE forests (fid INT <CUSTOM_COL_OPTIONS>,
+-name CHAR(64) <CUSTOM_COL_OPTIONS>,
+-boundary MULTIPOLYGON NOT NULL, SPATIAL INDEX b(boundary)) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+-CREATE TABLE bridges (fid INT <CUSTOM_COL_OPTIONS>,
+-name CHAR(64) <CUSTOM_COL_OPTIONS>,
+-position POINT NOT NULL, SPATIAL INDEX p(position)) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+-CREATE TABLE streams (fid INT <CUSTOM_COL_OPTIONS>,
+-name CHAR(64) <CUSTOM_COL_OPTIONS>,
+-centerline LINESTRING NOT NULL, SPATIAL INDEX c(centerline)) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+-CREATE TABLE buildings (fid INT <CUSTOM_COL_OPTIONS>,
+-name CHAR(64) <CUSTOM_COL_OPTIONS>,
+-position POINT NOT NULL,
+-footprint POLYGON NOT NULL, SPATIAL INDEX p(position), SPATIAL INDEX f(footprint)) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+-CREATE TABLE ponds (fid INT <CUSTOM_COL_OPTIONS>,
+-name CHAR(64) <CUSTOM_COL_OPTIONS>,
+-type CHAR(64) <CUSTOM_COL_OPTIONS>,
+-shores MULTIPOLYGON NOT NULL, SPATIAL INDEX s(shores)) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+-CREATE TABLE named_places (fid INT <CUSTOM_COL_OPTIONS>,
+-name CHAR(64) <CUSTOM_COL_OPTIONS>,
+-boundary POLYGON NOT NULL, SPATIAL INDEX b(boundary)) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+-CREATE TABLE map_neatlines (fid INT <CUSTOM_COL_OPTIONS>,
+-neatline POLYGON NOT NULL, SPATIAL INDEX n(neatline)) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+-USE test;
+-SHOW FIELDS FROM gis_point;
+-Field Type Null Key Default Extra
+-fid int(11) YES NULL
+-g point NO MUL NULL
+-SHOW FIELDS FROM gis_line;
+-Field Type Null Key Default Extra
+-fid int(11) YES NULL
+-g linestring NO MUL NULL
+-SHOW FIELDS FROM gis_polygon;
+-Field Type Null Key Default Extra
+-fid int(11) YES NULL
+-g polygon NO MUL NULL
+-SHOW FIELDS FROM gis_multi_point;
+-Field Type Null Key Default Extra
+-fid int(11) YES NULL
+-g multipoint NO MUL NULL
+-SHOW FIELDS FROM gis_multi_line;
+-Field Type Null Key Default Extra
+-fid int(11) YES NULL
+-g multilinestring NO MUL NULL
+-SHOW FIELDS FROM gis_multi_polygon;
+-Field Type Null Key Default Extra
+-fid int(11) YES NULL
+-g multipolygon NO MUL NULL
+-SHOW FIELDS FROM gis_geometrycollection;
+-Field Type Null Key Default Extra
+-fid int(11) YES NULL
+-g geometrycollection NO MUL NULL
+-SHOW FIELDS FROM gis_geometry;
+-Field Type Null Key Default Extra
+-fid int(11) YES NULL
+-g geometry NO NULL
+-INSERT INTO gis_point VALUES
+-(101, PointFromText('POINT(10 10)')),
+-(102, PointFromText('POINT(20 10)')),
+-(103, PointFromText('POINT(20 20)')),
+-(104, PointFromWKB(AsWKB(PointFromText('POINT(10 20)'))));
+-INSERT INTO gis_line VALUES
+-(105, LineFromText('LINESTRING(0 0,0 10,10 0)')),
+-(106, LineStringFromText('LINESTRING(10 10,20 10,20 20,10 20,10 10)')),
+-(107, LineStringFromWKB(AsWKB(LineString(Point(10, 10), Point(40, 10)))));
+-INSERT INTO gis_polygon VALUES
+-(108, PolygonFromText('POLYGON((10 10,20 10,20 20,10 20,10 10))')),
+-(109, PolyFromText('POLYGON((0 0,50 0,50 50,0 50,0 0), (10 10,20 10,20 20,10 20,10 10))')),
+-(110, PolyFromWKB(AsWKB(Polygon(LineString(Point(0, 0), Point(30, 0), Point(30, 30), Point(0, 0))))));
+-INSERT INTO gis_multi_point VALUES
+-(111, MultiPointFromText('MULTIPOINT(0 0,10 10,10 20,20 20)')),
+-(112, MPointFromText('MULTIPOINT(1 1,11 11,11 21,21 21)')),
+-(113, MPointFromWKB(AsWKB(MultiPoint(Point(3, 6), Point(4, 10)))));
+-INSERT INTO gis_multi_line VALUES
+-(114, MultiLineStringFromText('MULTILINESTRING((10 48,10 21,10 0),(16 0,16 23,16 48))')),
+-(115, MLineFromText('MULTILINESTRING((10 48,10 21,10 0))')),
+-(116, MLineFromWKB(AsWKB(MultiLineString(LineString(Point(1, 2), Point(3, 5)), LineString(Point(2, 5), Point(5, 8), Point(21, 7))))));
+-INSERT INTO gis_multi_polygon VALUES
+-(117, MultiPolygonFromText('MULTIPOLYGON(((28 26,28 0,84 0,84 42,28 26),(52 18,66 23,73 9,48 6,52 18)),((59 18,67 18,67 13,59 13,59 18)))')),
+-(118, MPolyFromText('MULTIPOLYGON(((28 26,28 0,84 0,84 42,28 26),(52 18,66 23,73 9,48 6,52 18)),((59 18,67 18,67 13,59 13,59 18)))')),
+-(119, MPolyFromWKB(AsWKB(MultiPolygon(Polygon(LineString(Point(0, 3), Point(3, 3), Point(3, 0), Point(0, 3)))))));
+-INSERT INTO gis_geometrycollection VALUES
+-(120, GeomCollFromText('GEOMETRYCOLLECTION(POINT(0 0), LINESTRING(0 0,10 10))')),
+-(121, GeometryFromWKB(AsWKB(GeometryCollection(Point(44, 6), LineString(Point(3, 6), Point(7, 9)))))),
+-(122, GeomFromText('GeometryCollection()')),
+-(123, GeomFromText('GeometryCollection EMPTY'));
+-INSERT into gis_geometry SELECT * FROM gis_point;
+-INSERT into gis_geometry SELECT * FROM gis_line;
+-INSERT into gis_geometry SELECT * FROM gis_polygon;
+-INSERT into gis_geometry SELECT * FROM gis_multi_point;
+-INSERT into gis_geometry SELECT * FROM gis_multi_line;
+-INSERT into gis_geometry SELECT * FROM gis_multi_polygon;
+-INSERT into gis_geometry SELECT * FROM gis_geometrycollection;
+-SELECT fid, AsText(g) FROM gis_point;
+-fid AsText(g)
+-101 POINT(10 10)
+-102 POINT(20 10)
+-103 POINT(20 20)
+-104 POINT(10 20)
+-SELECT fid, AsText(g) FROM gis_line;
+-fid AsText(g)
+-105 LINESTRING(0 0,0 10,10 0)
+-106 LINESTRING(10 10,20 10,20 20,10 20,10 10)
+-107 LINESTRING(10 10,40 10)
+-SELECT fid, AsText(g) FROM gis_polygon;
+-fid AsText(g)
+-108 POLYGON((10 10,20 10,20 20,10 20,10 10))
+-109 POLYGON((0 0,50 0,50 50,0 50,0 0),(10 10,20 10,20 20,10 20,10 10))
+-110 POLYGON((0 0,30 0,30 30,0 0))
+-SELECT fid, AsText(g) FROM gis_multi_point;
+-fid AsText(g)
+-111 MULTIPOINT(0 0,10 10,10 20,20 20)
+-112 MULTIPOINT(1 1,11 11,11 21,21 21)
+-113 MULTIPOINT(3 6,4 10)
+-SELECT fid, AsText(g) FROM gis_multi_line;
+-fid AsText(g)
+-114 MULTILINESTRING((10 48,10 21,10 0),(16 0,16 23,16 48))
+-115 MULTILINESTRING((10 48,10 21,10 0))
+-116 MULTILINESTRING((1 2,3 5),(2 5,5 8,21 7))
+-SELECT fid, AsText(g) FROM gis_multi_polygon;
+-fid AsText(g)
+-117 MULTIPOLYGON(((28 26,28 0,84 0,84 42,28 26),(52 18,66 23,73 9,48 6,52 18)),((59 18,67 18,67 13,59 13,59 18)))
+-118 MULTIPOLYGON(((28 26,28 0,84 0,84 42,28 26),(52 18,66 23,73 9,48 6,52 18)),((59 18,67 18,67 13,59 13,59 18)))
+-119 MULTIPOLYGON(((0 3,3 3,3 0,0 3)))
+-SELECT fid, AsText(g) FROM gis_geometrycollection;
+-fid AsText(g)
+-120 GEOMETRYCOLLECTION(POINT(0 0),LINESTRING(0 0,10 10))
+-121 GEOMETRYCOLLECTION(POINT(44 6),LINESTRING(3 6,7 9))
+-122 GEOMETRYCOLLECTION EMPTY
+-123 GEOMETRYCOLLECTION EMPTY
+-SELECT fid, AsText(g) FROM gis_geometry;
+-fid AsText(g)
+-101 POINT(10 10)
+-102 POINT(20 10)
+-103 POINT(20 20)
+-104 POINT(10 20)
+-105 LINESTRING(0 0,0 10,10 0)
+-106 LINESTRING(10 10,20 10,20 20,10 20,10 10)
+-107 LINESTRING(10 10,40 10)
+-108 POLYGON((10 10,20 10,20 20,10 20,10 10))
+-109 POLYGON((0 0,50 0,50 50,0 50,0 0),(10 10,20 10,20 20,10 20,10 10))
+-110 POLYGON((0 0,30 0,30 30,0 0))
+-111 MULTIPOINT(0 0,10 10,10 20,20 20)
+-112 MULTIPOINT(1 1,11 11,11 21,21 21)
+-113 MULTIPOINT(3 6,4 10)
+-114 MULTILINESTRING((10 48,10 21,10 0),(16 0,16 23,16 48))
+-115 MULTILINESTRING((10 48,10 21,10 0))
+-116 MULTILINESTRING((1 2,3 5),(2 5,5 8,21 7))
+-117 MULTIPOLYGON(((28 26,28 0,84 0,84 42,28 26),(52 18,66 23,73 9,48 6,52 18)),((59 18,67 18,67 13,59 13,59 18)))
+-118 MULTIPOLYGON(((28 26,28 0,84 0,84 42,28 26),(52 18,66 23,73 9,48 6,52 18)),((59 18,67 18,67 13,59 13,59 18)))
+-119 MULTIPOLYGON(((0 3,3 3,3 0,0 3)))
+-120 GEOMETRYCOLLECTION(POINT(0 0),LINESTRING(0 0,10 10))
+-121 GEOMETRYCOLLECTION(POINT(44 6),LINESTRING(3 6,7 9))
+-122 GEOMETRYCOLLECTION EMPTY
+-123 GEOMETRYCOLLECTION EMPTY
+-SELECT fid, Dimension(g) FROM gis_geometry;
+-fid Dimension(g)
+-101 0
+-102 0
+-103 0
+-104 0
+-105 1
+-106 1
+-107 1
+-108 2
+-109 2
+-110 2
+-111 0
+-112 0
+-113 0
+-114 1
+-115 1
+-116 1
+-117 2
+-118 2
+-119 2
+-120 1
+-121 1
+-122 0
+-123 0
+-SELECT fid, GeometryType(g) FROM gis_geometry;
+-fid GeometryType(g)
+-101 POINT
+-102 POINT
+-103 POINT
+-104 POINT
+-105 LINESTRING
+-106 LINESTRING
+-107 LINESTRING
+-108 POLYGON
+-109 POLYGON
+-110 POLYGON
+-111 MULTIPOINT
+-112 MULTIPOINT
+-113 MULTIPOINT
+-114 MULTILINESTRING
+-115 MULTILINESTRING
+-116 MULTILINESTRING
+-117 MULTIPOLYGON
+-118 MULTIPOLYGON
+-119 MULTIPOLYGON
+-120 GEOMETRYCOLLECTION
+-121 GEOMETRYCOLLECTION
+-122 GEOMETRYCOLLECTION
+-123 GEOMETRYCOLLECTION
+-SELECT fid, IsEmpty(g) FROM gis_geometry;
+-fid IsEmpty(g)
+-101 0
+-102 0
+-103 0
+-104 0
+-105 0
+-106 0
+-107 0
+-108 0
+-109 0
+-110 0
+-111 0
+-112 0
+-113 0
+-114 0
+-115 0
+-116 0
+-117 0
+-118 0
+-119 0
+-120 0
+-121 0
+-122 0
+-123 0
+-SELECT fid, AsText(Envelope(g)) FROM gis_geometry;
+-fid AsText(Envelope(g))
+-101 POLYGON((10 10,10 10,10 10,10 10,10 10))
+-102 POLYGON((20 10,20 10,20 10,20 10,20 10))
+-103 POLYGON((20 20,20 20,20 20,20 20,20 20))
+-104 POLYGON((10 20,10 20,10 20,10 20,10 20))
+-105 POLYGON((0 0,10 0,10 10,0 10,0 0))
+-106 POLYGON((10 10,20 10,20 20,10 20,10 10))
+-107 POLYGON((10 10,40 10,40 10,10 10,10 10))
+-108 POLYGON((10 10,20 10,20 20,10 20,10 10))
+-109 POLYGON((0 0,50 0,50 50,0 50,0 0))
+-110 POLYGON((0 0,30 0,30 30,0 30,0 0))
+-111 POLYGON((0 0,20 0,20 20,0 20,0 0))
+-112 POLYGON((1 1,21 1,21 21,1 21,1 1))
+-113 POLYGON((3 6,4 6,4 10,3 10,3 6))
+-114 POLYGON((10 0,16 0,16 48,10 48,10 0))
+-115 POLYGON((10 0,10 0,10 48,10 48,10 0))
+-116 POLYGON((1 2,21 2,21 8,1 8,1 2))
+-117 POLYGON((28 0,84 0,84 42,28 42,28 0))
+-118 POLYGON((28 0,84 0,84 42,28 42,28 0))
+-119 POLYGON((0 0,3 0,3 3,0 3,0 0))
+-120 POLYGON((0 0,10 0,10 10,0 10,0 0))
+-121 POLYGON((3 6,44 6,44 9,3 9,3 6))
+-122 GEOMETRYCOLLECTION EMPTY
+-123 GEOMETRYCOLLECTION EMPTY
+-SELECT fid, X(g) FROM gis_point;
+-fid X(g)
+-101 10
+-102 20
+-103 20
+-104 10
+-SELECT fid, Y(g) FROM gis_point;
+-fid Y(g)
+-101 10
+-102 10
+-103 20
+-104 20
+-SELECT fid, AsText(StartPoint(g)) FROM gis_line;
+-fid AsText(StartPoint(g))
+-105 POINT(0 0)
+-106 POINT(10 10)
+-107 POINT(10 10)
+-SELECT fid, AsText(EndPoint(g)) FROM gis_line;
+-fid AsText(EndPoint(g))
+-105 POINT(10 0)
+-106 POINT(10 10)
+-107 POINT(40 10)
+-SELECT fid, GLength(g) FROM gis_line;
+-fid GLength(g)
+-105 24.14213562373095
+-106 40
+-107 30
+-SELECT fid, NumPoints(g) FROM gis_line;
+-fid NumPoints(g)
+-105 3
+-106 5
+-107 2
+-SELECT fid, AsText(PointN(g, 2)) FROM gis_line;
+-fid AsText(PointN(g, 2))
+-105 POINT(0 10)
+-106 POINT(20 10)
+-107 POINT(40 10)
+-SELECT fid, IsClosed(g) FROM gis_line;
+-fid IsClosed(g)
+-105 0
+-106 1
+-107 0
+-SELECT fid, AsText(Centroid(g)) FROM gis_polygon;
+-fid AsText(Centroid(g))
+-108 POINT(15 15)
+-109 POINT(25.416666666666668 25.416666666666668)
+-110 POINT(20 10)
+-SELECT fid, Area(g) FROM gis_polygon;
+-fid Area(g)
+-108 100
+-109 2400
+-110 450
+-SELECT fid, AsText(ExteriorRing(g)) FROM gis_polygon;
+-fid AsText(ExteriorRing(g))
+-108 LINESTRING(10 10,20 10,20 20,10 20,10 10)
+-109 LINESTRING(0 0,50 0,50 50,0 50,0 0)
+-110 LINESTRING(0 0,30 0,30 30,0 0)
+-SELECT fid, NumInteriorRings(g) FROM gis_polygon;
+-fid NumInteriorRings(g)
+-108 0
+-109 1
+-110 0
+-SELECT fid, AsText(InteriorRingN(g, 1)) FROM gis_polygon;
+-fid AsText(InteriorRingN(g, 1))
+-108 NULL
+-109 LINESTRING(10 10,20 10,20 20,10 20,10 10)
+-110 NULL
+-SELECT fid, IsClosed(g) FROM gis_multi_line;
+-fid IsClosed(g)
+-114 0
+-115 0
+-116 0
+-SELECT fid, AsText(Centroid(g)) FROM gis_multi_polygon;
+-fid AsText(Centroid(g))
+-117 POINT(55.58852775304245 17.426536064113982)
+-118 POINT(55.58852775304245 17.426536064113982)
+-119 POINT(2 2)
+-SELECT fid, Area(g) FROM gis_multi_polygon;
+-fid Area(g)
+-117 1684.5
+-118 1684.5
+-119 4.5
+-SELECT fid, NumGeometries(g) from gis_multi_point;
+-fid NumGeometries(g)
+-111 4
+-112 4
+-113 2
+-SELECT fid, NumGeometries(g) from gis_multi_line;
+-fid NumGeometries(g)
+-114 2
+-115 1
+-116 2
+-SELECT fid, NumGeometries(g) from gis_multi_polygon;
+-fid NumGeometries(g)
+-117 2
+-118 2
+-119 1
+-SELECT fid, NumGeometries(g) from gis_geometrycollection;
+-fid NumGeometries(g)
+-120 2
+-121 2
+-122 0
+-123 0
+-SELECT fid, AsText(GeometryN(g, 2)) from gis_multi_point;
+-fid AsText(GeometryN(g, 2))
+-111 POINT(10 10)
+-112 POINT(11 11)
+-113 POINT(4 10)
+-SELECT fid, AsText(GeometryN(g, 2)) from gis_multi_line;
+-fid AsText(GeometryN(g, 2))
+-114 LINESTRING(16 0,16 23,16 48)
+-115 NULL
+-116 LINESTRING(2 5,5 8,21 7)
+-SELECT fid, AsText(GeometryN(g, 2)) from gis_multi_polygon;
+-fid AsText(GeometryN(g, 2))
+-117 POLYGON((59 18,67 18,67 13,59 13,59 18))
+-118 POLYGON((59 18,67 18,67 13,59 13,59 18))
+-119 NULL
+-SELECT fid, AsText(GeometryN(g, 2)) from gis_geometrycollection;
+-fid AsText(GeometryN(g, 2))
+-120 LINESTRING(0 0,10 10)
+-121 LINESTRING(3 6,7 9)
+-122 NULL
+-123 NULL
+-SELECT fid, AsText(GeometryN(g, 1)) from gis_geometrycollection;
+-fid AsText(GeometryN(g, 1))
+-120 POINT(0 0)
+-121 POINT(44 6)
+-122 NULL
+-123 NULL
+-SELECT g1.fid as first, g2.fid as second,
+-Within(g1.g, g2.g) as w, Contains(g1.g, g2.g) as c, Overlaps(g1.g, g2.g) as o,
+-Equals(g1.g, g2.g) as e, Disjoint(g1.g, g2.g) as d, Touches(g1.g, g2.g) as t,
+-Intersects(g1.g, g2.g) as i, Crosses(g1.g, g2.g) as r
+-FROM gis_geometrycollection g1, gis_geometrycollection g2 ORDER BY first, second;
+-first second w c o e d t i r
+-120 120 1 1 0 1 0 1 1 0
+-120 121 0 0 1 0 0 0 1 0
+-120 122 0 1 NULL 0 NULL 0 NULL 0
+-120 123 0 1 NULL 0 NULL 0 NULL 0
+-121 120 0 0 1 0 0 0 1 0
+-121 121 1 1 0 1 0 1 1 0
+-121 122 0 1 NULL 0 NULL 0 NULL 0
+-121 123 0 1 NULL 0 NULL 0 NULL 0
+-122 120 1 0 NULL 0 NULL 0 NULL 0
+-122 121 1 0 NULL 0 NULL 0 NULL 0
+-122 122 1 1 NULL 1 NULL 0 NULL 0
+-122 123 1 1 NULL 1 NULL 0 NULL 0
+-123 120 1 0 NULL 0 NULL 0 NULL 0
+-123 121 1 0 NULL 0 NULL 0 NULL 0
+-123 122 1 1 NULL 1 NULL 0 NULL 0
+-123 123 1 1 NULL 1 NULL 0 NULL 0
+-DROP TABLE gis_point, gis_line, gis_polygon, gis_multi_point, gis_multi_line, gis_multi_polygon, gis_geometrycollection, gis_geometry;
+-USE gis_ogs;
+-# Lakes
+-INSERT INTO lakes VALUES (
+-101, 'BLUE LAKE',
+-PolyFromText(
+-'POLYGON(
+- (52 18,66 23,73 9,48 6,52 18),
+- (59 18,67 18,67 13,59 13,59 18)
+- )',
+-101));
+-# Road Segments
+-INSERT INTO road_segments VALUES(102, 'Route 5', NULL, 2,
+-LineFromText(
+-'LINESTRING( 0 18, 10 21, 16 23, 28 26, 44 31 )' ,101));
+-INSERT INTO road_segments VALUES(103, 'Route 5', 'Main Street', 4,
+-LineFromText(
+-'LINESTRING( 44 31, 56 34, 70 38 )' ,101));
+-INSERT INTO road_segments VALUES(104, 'Route 5', NULL, 2,
+-LineFromText(
+-'LINESTRING( 70 38, 72 48 )' ,101));
+-INSERT INTO road_segments VALUES(105, 'Main Street', NULL, 4,
+-LineFromText(
+-'LINESTRING( 70 38, 84 42 )' ,101));
+-INSERT INTO road_segments VALUES(106, 'Dirt Road by Green Forest', NULL,
+-1,
+-LineFromText(
+-'LINESTRING( 28 26, 28 0 )',101));
+-# DividedRoutes
+-INSERT INTO divided_routes VALUES(119, 'Route 75', 4,
+-MLineFromText(
+-'MULTILINESTRING((10 48,10 21,10 0),
+- (16 0,16 23,16 48))', 101));
+-# Forests
+-INSERT INTO forests VALUES(109, 'Green Forest',
+-MPolyFromText(
+-'MULTIPOLYGON(((28 26,28 0,84 0,84 42,28 26),
+- (52 18,66 23,73 9,48 6,52 18)),((59 18,67 18,67 13,59 13,59 18)))',
+-101));
+-# Bridges
+-INSERT INTO bridges VALUES(110, 'Cam Bridge', PointFromText(
+-'POINT( 44 31 )', 101));
+-# Streams
+-INSERT INTO streams VALUES(111, 'Cam Stream',
+-LineFromText(
+-'LINESTRING( 38 48, 44 41, 41 36, 44 31, 52 18 )', 101));
+-INSERT INTO streams VALUES(112, NULL,
+-LineFromText(
+-'LINESTRING( 76 0, 78 4, 73 9 )', 101));
+-# Buildings
+-INSERT INTO buildings VALUES(113, '123 Main Street',
+-PointFromText(
+-'POINT( 52 30 )', 101),
+-PolyFromText(
+-'POLYGON( ( 50 31, 54 31, 54 29, 50 29, 50 31) )', 101));
+-INSERT INTO buildings VALUES(114, '215 Main Street',
+-PointFromText(
+-'POINT( 64 33 )', 101),
+-PolyFromText(
+-'POLYGON( ( 66 34, 62 34, 62 32, 66 32, 66 34) )', 101));
+-# Ponds
+-INSERT INTO ponds VALUES(120, NULL, 'Stock Pond',
+-MPolyFromText(
+-'MULTIPOLYGON( ( ( 24 44, 22 42, 24 40, 24 44) ),
+- ( ( 26 44, 26 40, 28 42, 26 44) ) )', 101));
+-# Named Places
+-INSERT INTO named_places VALUES(117, 'Ashton',
+-PolyFromText(
+-'POLYGON( ( 62 48, 84 48, 84 30, 56 30, 56 34, 62 48) )', 101));
+-INSERT INTO named_places VALUES(118, 'Goose Island',
+-PolyFromText(
+-'POLYGON( ( 67 13, 67 18, 59 18, 59 13, 67 13) )', 101));
+-# Map Neatlines
+-INSERT INTO map_neatlines VALUES(115,
+-PolyFromText(
+-'POLYGON( ( 0 0, 0 48, 84 48, 84 0, 0 0 ) )', 101));
+-SELECT Dimension(shore)
+-FROM lakes
+-WHERE name = 'Blue Lake';
+-Dimension(shore)
+-2
+-SELECT GeometryType(centerlines)
+-FROM divided_routes
+-WHERE name = 'Route 75';
+-GeometryType(centerlines)
+-MULTILINESTRING
+-SELECT AsText(boundary)
+-FROM named_places
+-WHERE name = 'Goose Island';
+-AsText(boundary)
+-POLYGON((67 13,67 18,59 18,59 13,67 13))
+-SELECT AsText(PolyFromWKB(AsBinary(boundary),101))
+-FROM named_places
+-WHERE name = 'Goose Island';
+-AsText(PolyFromWKB(AsBinary(boundary),101))
+-POLYGON((67 13,67 18,59 18,59 13,67 13))
+-SELECT SRID(boundary)
+-FROM named_places
+-WHERE name = 'Goose Island';
+-SRID(boundary)
+-101
+-SELECT IsEmpty(centerline)
+-FROM road_segments
+-WHERE name = 'Route 5'
+-AND aliases = 'Main Street';
+-IsEmpty(centerline)
+-0
+-SELECT AsText(Envelope(boundary))
+-FROM named_places
+-WHERE name = 'Goose Island';
+-AsText(Envelope(boundary))
+-POLYGON((59 13,67 13,67 18,59 18,59 13))
+-SELECT X(position)
+-FROM bridges
+-WHERE name = 'Cam Bridge';
+-X(position)
+-44
+-SELECT Y(position)
+-FROM bridges
+-WHERE name = 'Cam Bridge';
+-Y(position)
+-31
+-SELECT AsText(StartPoint(centerline))
+-FROM road_segments
+-WHERE fid = 102;
+-AsText(StartPoint(centerline))
+-POINT(0 18)
+-SELECT AsText(EndPoint(centerline))
+-FROM road_segments
+-WHERE fid = 102;
+-AsText(EndPoint(centerline))
+-POINT(44 31)
+-SELECT GLength(centerline)
+-FROM road_segments
+-WHERE fid = 106;
+-GLength(centerline)
+-26
+-SELECT NumPoints(centerline)
+-FROM road_segments
+-WHERE fid = 102;
+-NumPoints(centerline)
+-5
+-SELECT AsText(PointN(centerline, 1))
+-FROM road_segments
+-WHERE fid = 102;
+-AsText(PointN(centerline, 1))
+-POINT(0 18)
+-SELECT AsText(Centroid(boundary))
+-FROM named_places
+-WHERE name = 'Goose Island';
+-AsText(Centroid(boundary))
+-POINT(63 15.5)
+-SELECT Area(boundary)
+-FROM named_places
+-WHERE name = 'Goose Island';
+-Area(boundary)
+-40
+-SELECT AsText(ExteriorRing(shore))
+-FROM lakes
+-WHERE name = 'Blue Lake';
+-AsText(ExteriorRing(shore))
+-LINESTRING(52 18,66 23,73 9,48 6,52 18)
+-SELECT NumInteriorRings(shore)
+-FROM lakes
+-WHERE name = 'Blue Lake';
+-NumInteriorRings(shore)
+-1
+-SELECT AsText(InteriorRingN(shore, 1))
+-FROM lakes
+-WHERE name = 'Blue Lake';
+-AsText(InteriorRingN(shore, 1))
+-LINESTRING(59 18,67 18,67 13,59 13,59 18)
+-SELECT NumGeometries(centerlines)
+-FROM divided_routes
+-WHERE name = 'Route 75';
+-NumGeometries(centerlines)
+-2
+-SELECT AsText(GeometryN(centerlines, 2))
+-FROM divided_routes
+-WHERE name = 'Route 75';
+-AsText(GeometryN(centerlines, 2))
+-LINESTRING(16 0,16 23,16 48)
+-SELECT IsClosed(centerlines)
+-FROM divided_routes
+-WHERE name = 'Route 75';
+-IsClosed(centerlines)
+-0
+-SELECT GLength(centerlines)
+-FROM divided_routes
+-WHERE name = 'Route 75';
+-GLength(centerlines)
+-96
+-SELECT AsText(Centroid(shores))
+-FROM ponds
+-WHERE fid = 120;
+-AsText(Centroid(shores))
+-POINT(25 42)
+-SELECT Area(shores)
+-FROM ponds
+-WHERE fid = 120;
+-Area(shores)
+-8
+-SELECT ST_Equals(boundary,
+-PolyFromText('POLYGON( ( 67 13, 67 18, 59 18, 59 13, 67 13) )',1))
+-FROM named_places
+-WHERE name = 'Goose Island';
+-ST_Equals(boundary,
+-PolyFromText('POLYGON( ( 67 13, 67 18, 59 18, 59 13, 67 13) )',1))
+-1
+-SELECT ST_Disjoint(centerlines, boundary)
+-FROM divided_routes, named_places
+-WHERE divided_routes.name = 'Route 75'
+-AND named_places.name = 'Ashton';
+-ST_Disjoint(centerlines, boundary)
+-1
+-SELECT ST_Touches(centerline, shore)
+-FROM streams, lakes
+-WHERE streams.name = 'Cam Stream'
+-AND lakes.name = 'Blue Lake';
+-ST_Touches(centerline, shore)
+-1
+-SELECT Crosses(road_segments.centerline, divided_routes.centerlines)
+-FROM road_segments, divided_routes
+-WHERE road_segments.fid = 102
+-AND divided_routes.name = 'Route 75';
+-Crosses(road_segments.centerline, divided_routes.centerlines)
+-1
+-SELECT ST_Intersects(road_segments.centerline, divided_routes.centerlines)
+-FROM road_segments, divided_routes
+-WHERE road_segments.fid = 102
+-AND divided_routes.name = 'Route 75';
+-ST_Intersects(road_segments.centerline, divided_routes.centerlines)
+-1
+-SELECT ST_Contains(forests.boundary, named_places.boundary)
+-FROM forests, named_places
+-WHERE forests.name = 'Green Forest'
+-AND named_places.name = 'Ashton';
+-ST_Contains(forests.boundary, named_places.boundary)
+-0
+-SELECT ST_Distance(position, boundary)
+-FROM bridges, named_places
+-WHERE bridges.name = 'Cam Bridge'
+-AND named_places.name = 'Ashton';
+-ST_Distance(position, boundary)
+-12
+-SELECT AsText(ST_Difference(named_places.boundary, forests.boundary))
+-FROM named_places, forests
+-WHERE named_places.name = 'Ashton'
+-AND forests.name = 'Green Forest';
+-AsText(ST_Difference(named_places.boundary, forests.boundary))
+-POLYGON((56 34,62 48,84 48,84 42,56 34))
+-SELECT AsText(ST_Union(shore, boundary))
+-FROM lakes, named_places
+-WHERE lakes.name = 'Blue Lake'
+-AND named_places.name = 'Goose Island';
+-AsText(ST_Union(shore, boundary))
+-POLYGON((48 6,52 18,66 23,73 9,48 6))
+-SELECT AsText(ST_SymDifference(shore, boundary))
+-FROM lakes, named_places
+-WHERE lakes.name = 'Blue Lake'
+-AND named_places.name = 'Ashton';
+-AsText(ST_SymDifference(shore, boundary))
+-MULTIPOLYGON(((48 6,52 18,66 23,73 9,48 6),(59 13,59 18,67 18,67 13,59 13)),((56 30,56 34,62 48,84 48,84 30,56 30)))
+-SELECT count(*)
+-FROM buildings, bridges
+-WHERE ST_Contains(ST_Buffer(bridges.position, 15.0), buildings.footprint) = 1;
+-count(*)
+-1
++ERROR HY000: The used table type doesn't support SPATIAL indexes
++# ERROR: Statement ended with errno 1464, errname ER_TABLE_CANT_HANDLE_SPKEYS (expected to succeed)
++# ------------ UNEXPECTED RESULT ------------
++# [ CREATE TABLE gis_point (fid INT(11) /*!*/ /*Custom column options*/, g POINT NOT NULL, SPATIAL INDEX(g)) ENGINE=InnoDB /*!*/ /*Custom table options*/ ]
++# The statement|command finished with ER_TABLE_CANT_HANDLE_SPKEYS.
++# Geometry types or spatial indexes or the mix could be unsupported|malfunctioning, or the problem was caused by previous errors.
++# You can change the engine code, or create an rdiff, or disable the test by adding it to disabled.def.
++# Further in this test, the message might sometimes be suppressed; a part of the test might be skipped.
++# Also, this problem may cause a chain effect (more errors of different kinds in the test).
++# -------------------------------------------
+ DROP DATABASE gis_ogs;
+ USE test;
diff --git a/storage/innobase/mysql-test/storage_engine/vcol.rdiff b/storage/innobase/mysql-test/storage_engine/vcol.rdiff
new file mode 100644
index 00000000000..2226062834e
--- /dev/null
+++ b/storage/innobase/mysql-test/storage_engine/vcol.rdiff
@@ -0,0 +1,82 @@
+--- suite/storage_engine/vcol.result 2012-07-12 20:24:16.628339715 +0400
++++ suite/storage_engine/vcol.reject 2012-07-15 17:53:17.457007891 +0400
+@@ -1,69 +1,12 @@
+ DROP TABLE IF EXISTS t1;
+ CREATE TABLE t1 (a <INT_COLUMN>, b <INT_COLUMN> GENERATED ALWAYS AS (a+1)) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+-SHOW COLUMNS IN t1;
+-Field Type Null Key Default Extra
+-a int(11) # #
+-b int(11) # # VIRTUAL
+-INSERT INTO t1 (a) VALUES (1),(2);
+-INSERT INTO t1 (a,b) VALUES (3,3),(4,4);
+-Warnings:
+-Warning 1906 The value specified for computed column 'b' in table 't1' ignored
+-Warning 1906 The value specified for computed column 'b' in table 't1' ignored
+-SELECT * FROM t1;
+-a b
+-1 2
+-2 3
+-3 4
+-4 5
+-DROP TABLE t1;
+-CREATE TABLE t1 (a <INT_COLUMN>, b <INT_COLUMN> GENERATED ALWAYS AS (a+1) PERSISTENT) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+-SHOW COLUMNS IN t1;
+-Field Type Null Key Default Extra
+-a int(11) # #
+-b int(11) # # PERSISTENT
+-INSERT INTO t1 (a) VALUES (1),(2);
+-INSERT INTO t1 (a,b) VALUES (3,3),(4,4);
+-Warnings:
+-Warning 1906 The value specified for computed column 'b' in table 't1' ignored
+-Warning 1906 The value specified for computed column 'b' in table 't1' ignored
+-SELECT * FROM t1;
+-a b
+-1 2
+-2 3
+-3 4
+-4 5
+-DROP TABLE t1;
+-CREATE TABLE t1 (a <INT_COLUMN>, b <INT_COLUMN> GENERATED ALWAYS AS (a+1) VIRTUAL) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+-SHOW COLUMNS IN t1;
+-Field Type Null Key Default Extra
+-a int(11) # #
+-b int(11) # # VIRTUAL
+-INSERT INTO t1 (a) VALUES (1),(2);
+-INSERT INTO t1 (a,b) VALUES (3,3),(4,4);
+-Warnings:
+-Warning 1906 The value specified for computed column 'b' in table 't1' ignored
+-Warning 1906 The value specified for computed column 'b' in table 't1' ignored
+-SELECT * FROM t1;
+-a b
+-1 2
+-2 3
+-3 4
+-4 5
+-DROP TABLE t1;
+-CREATE TABLE t1 (a <INT_COLUMN>, b <INT_COLUMN> AS (a+1) PERSISTENT) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+-SHOW COLUMNS IN t1;
+-Field Type Null Key Default Extra
+-a int(11) # #
+-b int(11) # # PERSISTENT
+-INSERT INTO t1 (a) VALUES (1),(2);
+-INSERT INTO t1 (a,b) VALUES (3,3),(4,4);
+-Warnings:
+-Warning 1906 The value specified for computed column 'b' in table 't1' ignored
+-Warning 1906 The value specified for computed column 'b' in table 't1' ignored
+-SELECT * FROM t1;
+-a b
+-1 2
+-2 3
+-3 4
+-4 5
+-DROP TABLE t1;
++ERROR HY000: InnoDB storage engine does not support computed columns
++# ERROR: Statement ended with errno 1910, errname ER_UNSUPPORTED_ENGINE_FOR_VIRTUAL_COLUMNS (expected to succeed)
++# ------------ UNEXPECTED RESULT ------------
++# [ CREATE TABLE t1 (a INT(11) /*!*/ /*Custom column options*/, b INT(11) /*!*/ /*Custom column options*/ GENERATED ALWAYS AS (a+1)) ENGINE=InnoDB /*!*/ /*Custom table options*/ ]
++# The statement|command finished with ER_UNSUPPORTED_ENGINE_FOR_VIRTUAL_COLUMNS.
++# Virtual columns or the mix could be unsupported|malfunctioning, or the problem was caused by previous errors.
++# You can change the engine code, or create an rdiff, or disable the test by adding it to disabled.def.
++# Further in this test, the message might sometimes be suppressed; a part of the test might be skipped.
++# Also, this problem may cause a chain effect (more errors of different kinds in the test).
++# -------------------------------------------
diff --git a/storage/innobase/os/os0file.c b/storage/innobase/os/os0file.c
index cc8dff3b621..6ba27d1af9c 100644
--- a/storage/innobase/os/os0file.c
+++ b/storage/innobase/os/os0file.c
@@ -3382,12 +3382,23 @@ os_aio_array_create(
if (!os_aio_linux_create_io_ctx(n/n_segments,
&array->aio_ctx[i])) {
/* If something bad happened during aio setup
- we should call it a day and return right away.
- We don't care about any leaks because a failure
- to initialize the io subsystem means that the
- server (or atleast the innodb storage engine)
- is not going to startup. */
- return(NULL);
+ we disable linux native aio.
+ The disadvantage will be a small memory leak
+ at shutdown but that's ok compared to a crash
+ or a not working server.
+ This frequently happens when running the test suite
+ with many threads on a system with low fs.aio-max-nr!
+ */
+
+ fprintf(stderr,
+ " InnoDB: Warning: Linux Native AIO disabled "
+ "because os_aio_linux_create_io_ctx() "
+ "failed. To get rid of this warning you can "
+ "try increasing system "
+ "fs.aio-max-nr to 1048576 or larger or "
+ "setting innodb_use_native_aio = 0 in my.cnf\n");
+ srv_use_native_aio = FALSE;
+ goto skip_native_aio;
}
}
diff --git a/storage/innobase/os/os0thread.c b/storage/innobase/os/os0thread.c
index 12b6805d98e..b19b5378fcd 100644
--- a/storage/innobase/os/os0thread.c
+++ b/storage/innobase/os/os0thread.c
@@ -136,8 +136,10 @@ os_thread_create(
if (thread_id) {
*thread_id = win_thread_id;
}
-
- return(thread);
+ if (thread) {
+ CloseHandle(thread);
+ }
+ return((os_thread_t)win_thread_id);
#else
int ret;
os_thread_t pthread;
diff --git a/storage/innobase/rem/rem0rec.c b/storage/innobase/rem/rem0rec.c
index 15618a3fa02..0cee1ffb3c8 100644
--- a/storage/innobase/rem/rem0rec.c
+++ b/storage/innobase/rem/rem0rec.c
@@ -1803,7 +1803,10 @@ wsrep_rec_get_primary_key(
ut_ad(rec);
key_parts = dict_index_get_n_unique_in_tree(index);
- for (i = 0; i < key_parts; i++) {
+ for (i = 0;
+ i < key_parts && (index->type & DICT_CLUSTERED || i < key_parts - 1);
+ i++) {
+
dict_field_t* field = dict_index_get_nth_field(index, i);
const dict_col_t* col = dict_field_get_col(field);
diff --git a/storage/innobase/row/row0ins.c b/storage/innobase/row/row0ins.c
index a829e6990b2..d7823c140bf 100644
--- a/storage/innobase/row/row0ins.c
+++ b/storage/innobase/row/row0ins.c
@@ -761,7 +761,8 @@ ulint wsrep_append_foreign_key(trx_t *trx,
dict_foreign_t* foreign,
const rec_t* clust_rec,
dict_index_t* clust_index,
- ibool shared);
+ ibool referenced,
+ ibool shared);
#endif /* WITH_WSREP */
/*********************************************************************//**
@@ -1086,7 +1087,7 @@ row_ins_foreign_check_on_constraint(
foreign,
clust_rec,
clust_index,
- FALSE);
+ FALSE, FALSE);
}
#endif /* WITH_WSREP */
if (foreign->foreign_table->n_foreign_key_checks_running == 0) {
@@ -1422,12 +1423,22 @@ run_again:
if (check_ref) {
err = DB_SUCCESS;
#ifdef WITH_WSREP
- err = wsrep_append_foreign_key(
- thr_get_trx(thr),
- foreign,
- rec,
- check_index,
- TRUE);
+ if (thr->fk_cascade_depth == 0) {
+ err = wsrep_append_foreign_key(
+ thr_get_trx(thr),
+ foreign,
+ rec,
+ check_index,
+ check_ref, TRUE);
+ } else {
+ fprintf(stderr, "WSREP: skipping FK key append\n");
+ err = wsrep_append_foreign_key(
+ thr_get_trx(thr),
+ foreign,
+ rec,
+ check_index,
+ TRUE, TRUE);
+ }
#endif /* WITH_WSREP */
goto end_scan;
} else if (foreign->type != 0) {
@@ -1458,6 +1469,14 @@ run_again:
goto end_scan;
}
+#ifdef WITH_WSREP_REMOVED
+ err = wsrep_append_foreign_key(
+ thr_get_trx(thr),
+ foreign,
+ rec,
+ check_index,
+ FALSE);
+#endif /* WITH_WSREP */
/* row_ins_foreign_check_on_constraint
may have repositioned pcur on a
different block */
diff --git a/storage/innobase/row/row0upd.c b/storage/innobase/row/row0upd.c
index 4f5096a162b..8469d688c5c 100644
--- a/storage/innobase/row/row0upd.c
+++ b/storage/innobase/row/row0upd.c
@@ -170,6 +170,46 @@ func_exit:
return(is_referenced);
}
+#ifdef WITH_WSREP
+ulint wsrep_append_foreign_key(trx_t *trx,
+ dict_foreign_t* foreign,
+ const rec_t* clust_rec,
+ dict_index_t* clust_index,
+ ibool referenced,
+ ibool shared);
+
+static
+void
+wsrep_append_fk_reference(
+/*=================================*/
+ upd_node_t* node, /*!< in: row update node */
+ dict_table_t* table, /*!< in: table in question */
+ dict_index_t* index, /*!< in: index of the cursor */
+ que_thr_t* thr, /*!< in: query thread */
+ const rec_t* rec
+) {
+ dict_foreign_t *foreign = UT_LIST_GET_FIRST(table->foreign_list);
+
+ while (foreign) {
+ if (foreign->foreign_index == index
+ && node->is_delete)
+ {
+ if (DB_SUCCESS != wsrep_append_foreign_key(
+ thr_get_trx(thr),
+ foreign,
+ rec,
+ index,
+ TRUE, TRUE)
+ ) {
+ fprintf(stderr,
+ "WSREP: FK key append failed\n");
+ }
+ }
+ foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
+ }
+}
+#endif /* WITH_WSREP */
+
/*********************************************************************//**
Checks if possible foreign key constraints hold after a delete of the record
under pcur.
@@ -283,7 +323,6 @@ row_upd_check_references_constraints(
}
err = DB_SUCCESS;
-
func_exit:
if (got_s_lock) {
row_mysql_unfreeze_data_dictionary(trx);
@@ -1646,6 +1685,12 @@ row_upd_sec_index_entry(
node, &pcur, index->table,
index, offsets, thr, &mtr);
}
+#ifdef WITH_WSREP
+ if (err == DB_SUCCESS && !referenced) {
+ wsrep_append_fk_reference(node, index->table,
+ index, thr, rec);
+ }
+#endif /* WITH_WSREP */
}
break;
}
@@ -1887,6 +1932,12 @@ err_exit:
goto err_exit;
}
}
+#ifdef WITH_WSREP
+ if (!referenced) {
+ wsrep_append_fk_reference(node, index->table,
+ index, thr, rec);
+ }
+#endif /* WITH_WSREP */
}
mtr_commit(mtr);
@@ -2089,6 +2140,9 @@ row_upd_del_mark_clust_rec(
btr_pcur_t* pcur;
btr_cur_t* btr_cur;
ulint err;
+#ifdef WITH_WSREP
+ rec_t* rec;
+#endif /* WITH_WSREP */
ut_ad(node);
ut_ad(dict_index_is_clust(index));
@@ -2105,15 +2159,29 @@ row_upd_del_mark_clust_rec(
/* Mark the clustered index record deleted; we do not have to check
locks, because we assume that we have an x-lock on the record */
+#ifdef WITH_WSREP
+ rec = btr_cur_get_rec(btr_cur);
+#endif /* WITH_WSREP */
+
err = btr_cur_del_mark_set_clust_rec(
BTR_NO_LOCKING_FLAG, btr_cur_get_block(btr_cur),
+#ifdef WITH_WSREP
+ rec, index, offsets, TRUE, thr, mtr);
+#else
btr_cur_get_rec(btr_cur), index, offsets, TRUE, thr, mtr);
+#endif /* WITH_WSREP */
if (err == DB_SUCCESS && referenced) {
/* NOTE that the following call loses the position of pcur ! */
err = row_upd_check_references_constraints(
node, pcur, index->table, index, offsets, thr, mtr);
}
+#ifdef WITH_WSREP
+ if (err == DB_SUCCESS && !referenced) {
+ wsrep_append_fk_reference(node, index->table,
+ index, thr, rec);
+ }
+#endif /* WITH_WSREP */
mtr_commit(mtr);
diff --git a/storage/innobase/srv/srv0start.c b/storage/innobase/srv/srv0start.c
index 343e41fe376..86669a50895 100644
--- a/storage/innobase/srv/srv0start.c
+++ b/storage/innobase/srv/srv0start.c
@@ -1364,10 +1364,18 @@ innobase_start_or_create_for_mysql(void)
}
# endif /* __WIN__ */
- os_aio_init(io_limit,
- srv_n_read_io_threads,
- srv_n_write_io_threads,
- SRV_MAX_N_PENDING_SYNC_IOS);
+ if (!os_aio_init(io_limit,
+ srv_n_read_io_threads,
+ srv_n_write_io_threads,
+ SRV_MAX_N_PENDING_SYNC_IOS)) {
+
+ ut_print_timestamp(stderr);
+ fprintf(stderr,
+ " InnoDB: Fatal error: cannot initialize AIO"
+ " sub-system\n");
+
+ return(DB_ERROR);
+ }
fil_init(srv_file_per_table ? 50000 : 5000,
srv_max_n_open_files);
diff --git a/storage/innobase/sync/sync0arr.c b/storage/innobase/sync/sync0arr.c
index 30caddccced..c6cbfc94dca 100644
--- a/storage/innobase/sync/sync0arr.c
+++ b/storage/innobase/sync/sync0arr.c
@@ -928,6 +928,11 @@ sync_array_print_long_waits(
ibool fatal = FALSE;
double longest_diff = 0;
+ /* For huge tables, skip the check during CHECK TABLE etc... */
+ if (fatal_timeout > SRV_SEMAPHORE_WAIT_EXTENSION) {
+ return(FALSE);
+ }
+
#ifdef UNIV_DEBUG_VALGRIND
/* Increase the timeouts if running under valgrind because it executes
extremely slowly. UNIV_DEBUG_VALGRIND does not necessary mean that
diff --git a/storage/maria/ha_maria.cc b/storage/maria/ha_maria.cc
index 2b67f29f9f8..e763b7e7a37 100644
--- a/storage/maria/ha_maria.cc
+++ b/storage/maria/ha_maria.cc
@@ -1008,6 +1008,28 @@ const char *ha_maria::index_type(uint key_number)
}
+ulong ha_maria::index_flags(uint inx, uint part, bool all_parts) const
+{
+ ulong flags;
+ if (table_share->key_info[inx].algorithm == HA_KEY_ALG_FULLTEXT)
+ flags= 0;
+ else
+ if ((table_share->key_info[inx].flags & HA_SPATIAL ||
+ table_share->key_info[inx].algorithm == HA_KEY_ALG_RTREE))
+ {
+ /* All GIS scans are non-ROR scans. We also disable IndexConditionPushdown */
+ flags= HA_READ_NEXT | HA_READ_PREV | HA_READ_RANGE |
+ HA_READ_ORDER | HA_KEYREAD_ONLY | HA_KEY_SCAN_NOT_ROR;
+ }
+ else
+ {
+ flags= HA_READ_NEXT | HA_READ_PREV | HA_READ_RANGE |
+ HA_READ_ORDER | HA_KEYREAD_ONLY | HA_DO_INDEX_COND_PUSHDOWN;
+ }
+ return flags;
+}
+
+
double ha_maria::scan_time()
{
if (file->s->data_file_type == BLOCK_RECORD)
diff --git a/storage/maria/ha_maria.h b/storage/maria/ha_maria.h
index 35c98cc52d7..545daca12fe 100644
--- a/storage/maria/ha_maria.h
+++ b/storage/maria/ha_maria.h
@@ -65,12 +65,7 @@ public:
const char **bas_ext() const;
ulonglong table_flags() const
{ return int_table_flags; }
- ulong index_flags(uint inx, uint part, bool all_parts) const
- {
- return ((table_share->key_info[inx].algorithm == HA_KEY_ALG_FULLTEXT) ?
- 0 : HA_READ_NEXT | HA_READ_PREV | HA_READ_RANGE |
- HA_READ_ORDER | HA_KEYREAD_ONLY | HA_DO_INDEX_COND_PUSHDOWN);
- }
+ ulong index_flags(uint inx, uint part, bool all_parts) const;
uint max_supported_keys() const
{ return MARIA_MAX_KEY; }
uint max_supported_key_length() const;
diff --git a/storage/maria/ma_close.c b/storage/maria/ma_close.c
index 973adf2b91e..c355f1f1def 100644
--- a/storage/maria/ma_close.c
+++ b/storage/maria/ma_close.c
@@ -195,20 +195,27 @@ int maria_close(register MARIA_HA *info)
if (share->state_history)
{
- MARIA_STATE_HISTORY_CLOSED *history;
- /*
- Here we ignore the unlikely case that we don't have memory to
- store the state. In the worst case what happens is that any transaction
- that tries to access this table will get a wrong status information.
- */
- if ((history= (MARIA_STATE_HISTORY_CLOSED *)
- my_malloc(sizeof(*history), MYF(MY_WME))))
+ if (share->state_history->trid) /* If not visible for all */
{
- history->create_rename_lsn= share->state.create_rename_lsn;
- history->state_history= share->state_history;
- if (my_hash_insert(&maria_stored_state, (uchar*) history))
- my_free(history);
+ MARIA_STATE_HISTORY_CLOSED *history;
+ DBUG_PRINT("info", ("Storing state history"));
+ /*
+ Here we ignore the unlikely case that we don't have memory
+ to store the state. In the worst case what happens is that
+ any transaction that tries to access this table will get a
+ wrong status information.
+ */
+ if ((history= (MARIA_STATE_HISTORY_CLOSED *)
+ my_malloc(sizeof(*history), MYF(MY_WME))))
+ {
+ history->create_rename_lsn= share->state.create_rename_lsn;
+ history->state_history= share->state_history;
+ if (my_hash_insert(&maria_stored_state, (uchar*) history))
+ my_free(history);
+ }
}
+ else
+ my_free(share->state_history);
/* Marker for concurrent checkpoint */
share->state_history= 0;
}
diff --git a/storage/maria/ma_delete_table.c b/storage/maria/ma_delete_table.c
index 9e91638fa27..09d5cde5ad0 100644
--- a/storage/maria/ma_delete_table.c
+++ b/storage/maria/ma_delete_table.c
@@ -38,14 +38,8 @@ int maria_delete_table(const char *name)
/** @todo LOCK take X-lock on table */
/*
We need to know if this table is transactional.
- When built with RAID support, we also need to determine if this table
- makes use of the raid feature. If yes, we need to remove all raid
- chunks. This is done with my_raid_delete(). Unfortunately it is
- necessary to open the table just to check this. We use
- 'open_for_repair' to be able to open even a crashed table. If even
- this open fails, we assume no raid configuration for this table
- and try to remove the normal data file only. This may however
- leave the raid chunks behind.
+ Unfortunately it is necessary to open the table just to check this. We use
+ 'open_for_repair' to be able to open even a crashed table.
*/
if (!(info= maria_open(name, O_RDONLY, HA_OPEN_FOR_REPAIR)))
{
@@ -56,6 +50,8 @@ int maria_delete_table(const char *name)
sync_dir= (info->s->now_transactional && !info->s->temporary &&
!maria_in_recovery) ?
MY_SYNC_DIR : 0;
+ /* Remove history for table */
+ _ma_reset_state(info);
maria_close(info);
}
diff --git a/storage/maria/ma_info.c b/storage/maria/ma_info.c
index 97b5b8b7f7b..341ea147785 100644
--- a/storage/maria/ma_info.c
+++ b/storage/maria/ma_info.c
@@ -42,6 +42,7 @@ int maria_status(MARIA_HA *info, register MARIA_INFO *x, uint flag)
MY_STAT state;
MARIA_SHARE *share= info->s;
DBUG_ENTER("maria_status");
+ DBUG_PRINT("info", ("records: %lld", info->state->records));
x->recpos= info->cur_row.lastpos;
if (flag == HA_STATUS_POS)
diff --git a/storage/maria/ma_open.c b/storage/maria/ma_open.c
index a526c0d4276..5f90f61c786 100644
--- a/storage/maria/ma_open.c
+++ b/storage/maria/ma_open.c
@@ -866,6 +866,9 @@ MARIA_HA *maria_open(const char *name, int mode, uint open_flags)
_ma_remove_not_visible_states(history->state_history, 0, 0);
history->state_history= 0;
(void) my_hash_delete(&maria_stored_state, (uchar*) history);
+ DBUG_PRINT("info", ("Reading state history. trid: %lu records: %lld",
+ (ulong) share->state_history->trid,
+ share->state_history->state.records));
}
else
{
@@ -988,6 +991,7 @@ MARIA_HA *maria_open(const char *name, int mode, uint open_flags)
mysql_mutex_unlock(&THR_LOCK_maria);
m_info->open_flags= open_flags;
+ DBUG_PRINT("exit", ("table: %p name: %s",m_info, name));
DBUG_RETURN(m_info);
err:
diff --git a/storage/maria/maria_chk.c b/storage/maria/maria_chk.c
index 27653ae5574..62225a7a4b0 100644
--- a/storage/maria/maria_chk.c
+++ b/storage/maria/maria_chk.c
@@ -21,9 +21,6 @@
#include <m_ctype.h>
#include <stdarg.h>
#include <my_getopt.h>
-#ifdef HAVE_SYS_VADVICE_H
-#include <sys/vadvise.h>
-#endif
#ifdef HAVE_SYS_MMAN_H
#include <sys/mman.h>
#endif
diff --git a/storage/myisam/ha_myisam.cc b/storage/myisam/ha_myisam.cc
index 4fbd94a1a3b..73e0fadd530 100644
--- a/storage/myisam/ha_myisam.cc
+++ b/storage/myisam/ha_myisam.cc
@@ -689,6 +689,28 @@ const char *ha_myisam::index_type(uint key_number)
}
+ulong ha_myisam::index_flags(uint inx, uint part, bool all_parts) const
+{
+ ulong flags;
+ if (table_share->key_info[inx].algorithm == HA_KEY_ALG_FULLTEXT)
+ flags= 0;
+ else
+ if ((table_share->key_info[inx].flags & HA_SPATIAL ||
+ table_share->key_info[inx].algorithm == HA_KEY_ALG_RTREE))
+ {
+ /* All GIS scans are non-ROR scans. We also disable IndexConditionPushdown */
+ flags= HA_READ_NEXT | HA_READ_PREV | HA_READ_RANGE |
+ HA_READ_ORDER | HA_KEYREAD_ONLY | HA_KEY_SCAN_NOT_ROR;
+ }
+ else
+ {
+ flags= HA_READ_NEXT | HA_READ_PREV | HA_READ_RANGE |
+ HA_READ_ORDER | HA_KEYREAD_ONLY | HA_DO_INDEX_COND_PUSHDOWN;
+ }
+ return flags;
+}
+
+
/* Name is here without an extension */
int ha_myisam::open(const char *name, int mode, uint test_if_locked)
{
diff --git a/storage/myisam/ha_myisam.h b/storage/myisam/ha_myisam.h
index 579ef061af4..79324f64370 100644
--- a/storage/myisam/ha_myisam.h
+++ b/storage/myisam/ha_myisam.h
@@ -64,12 +64,7 @@ class ha_myisam: public handler
int index_end();
int rnd_end();
- ulong index_flags(uint inx, uint part, bool all_parts) const
- {
- return ((table_share->key_info[inx].algorithm == HA_KEY_ALG_FULLTEXT) ?
- 0 : HA_READ_NEXT | HA_READ_PREV | HA_READ_RANGE |
- HA_READ_ORDER | HA_KEYREAD_ONLY | HA_DO_INDEX_COND_PUSHDOWN);
- }
+ ulong index_flags(uint inx, uint part, bool all_parts) const;
uint max_supported_keys() const { return MI_MAX_KEY; }
uint max_supported_key_parts() const { return HA_MAX_KEY_SEG; }
uint max_supported_key_length() const { return HA_MAX_KEY_LENGTH; }
diff --git a/storage/myisam/mi_extra.c b/storage/myisam/mi_extra.c
index 92d7459dfc5..dab1f66ed6d 100644
--- a/storage/myisam/mi_extra.c
+++ b/storage/myisam/mi_extra.c
@@ -330,9 +330,7 @@ int mi_extra(MI_INFO *info, enum ha_extra_function function, void *extra_arg)
if (!share->temporary)
flush_key_blocks(share->key_cache, share->kfile, &share->dirty_part_map,
FLUSH_KEEP);
-#ifdef HAVE_PWRITE
_mi_decrement_open_count(info);
-#endif
if (share->not_flushed)
{
share->not_flushed=0;
diff --git a/storage/myisam/mi_keycache.c b/storage/myisam/mi_keycache.c
index a2422b71bbf..b45f0efa2f7 100644
--- a/storage/myisam/mi_keycache.c
+++ b/storage/myisam/mi_keycache.c
@@ -76,6 +76,7 @@ int mi_assign_to_key_cache(MI_INFO *info,
in the old key cache.
*/
+ pthread_mutex_lock(&share->key_cache->op_lock);
if (flush_key_blocks(share->key_cache, share->kfile, &share->dirty_part_map,
FLUSH_RELEASE))
{
@@ -83,6 +84,7 @@ int mi_assign_to_key_cache(MI_INFO *info,
mi_print_error(info->s, HA_ERR_CRASHED);
mi_mark_crashed(info); /* Mark that table must be checked */
}
+ pthread_mutex_unlock(&share->key_cache->op_lock);
/*
Flush the new key cache for this file. This is needed to ensure
diff --git a/storage/myisam/myisamchk.c b/storage/myisam/myisamchk.c
index fa8cc679997..7d8b577e8b0 100644
--- a/storage/myisam/myisamchk.c
+++ b/storage/myisam/myisamchk.c
@@ -20,9 +20,6 @@
#include <stdarg.h>
#include <my_getopt.h>
#include <my_bit.h>
-#ifdef HAVE_SYS_VADVICE_H
-#include <sys/vadvise.h>
-#endif
#ifdef HAVE_SYS_MMAN_H
#include <sys/mman.h>
#endif
diff --git a/storage/myisam/mysql-test/mtr2/suite.pm b/storage/myisam/mysql-test/mtr2/suite.pm
new file mode 100644
index 00000000000..0f287e4a8ba
--- /dev/null
+++ b/storage/myisam/mysql-test/mtr2/suite.pm
@@ -0,0 +1,9 @@
+package My::Suite::MTR2::MyISAM;
+
+@ISA = qw(My::Suite);
+
+sub skip_combinations {(
+ 'combinations' => [ '1st' ],
+)}
+bless { };
+
diff --git a/storage/myisam/mysql-test/storage_engine/alter_tablespace.rdiff b/storage/myisam/mysql-test/storage_engine/alter_tablespace.rdiff
new file mode 100644
index 00000000000..3caf2ad6c3a
--- /dev/null
+++ b/storage/myisam/mysql-test/storage_engine/alter_tablespace.rdiff
@@ -0,0 +1,32 @@
+--- suite/storage_engine/alter_tablespace.result 2012-07-12 19:53:40.775419511 +0400
++++ suite/storage_engine/alter_tablespace.reject 2012-07-15 16:21:14.910435703 +0400
+@@ -1,19 +1,14 @@
+ DROP TABLE IF EXISTS t1, t2;
+ CREATE TABLE t1 (a <INT_COLUMN>) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+ ALTER TABLE t1 DISCARD TABLESPACE;
+-DROP TABLE t1;
+-CREATE TABLE t1 (a <INT_COLUMN>) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+-INSERT INTO t1 (a) VALUES (1),(2);
+-SELECT * FROM t1;
+-a
+-1
+-2
+-ALTER TABLE t1 DISCARD TABLESPACE;
+-SELECT * FROM t1;
+-ERROR HY000: Got error -1 from storage engine
+-ALTER TABLE t1 IMPORT TABLESPACE;
+-SELECT * FROM t1;
+-a
+-1
+-2
++ERROR HY000: Table storage engine for 't1' doesn't have this option
++# ERROR: Statement ended with errno 1031, errname ER_ILLEGAL_HA (expected to succeed)
++# ------------ UNEXPECTED RESULT ------------
++# [ ALTER TABLE t1 DISCARD TABLESPACE ]
++# The statement|command finished with ER_ILLEGAL_HA.
++# Tablespace operations or the syntax or the mix could be unsupported.
++# You can change the engine code, or create an rdiff, or disable the test by adding it to disabled.def.
++# Further in this test, the message might sometimes be suppressed; a part of the test might be skipped.
++# Also, this problem may cause a chain effect (more errors of different kinds in the test).
++# -------------------------------------------
+ DROP TABLE t1;
diff --git a/storage/myisam/mysql-test/storage_engine/check_table.rdiff b/storage/myisam/mysql-test/storage_engine/check_table.rdiff
new file mode 100644
index 00000000000..48e8fc2e770
--- /dev/null
+++ b/storage/myisam/mysql-test/storage_engine/check_table.rdiff
@@ -0,0 +1,20 @@
+--- suite/storage_engine/check_table.result 2012-07-15 04:19:07.782936394 +0400
++++ suite/storage_engine/check_table.reject 2012-07-15 16:21:16.734412773 +0400
+@@ -18,7 +18,7 @@
+ INSERT INTO t1 (a,b) VALUES (6,'f');
+ CHECK TABLE t1 FAST;
+ Table Op Msg_type Msg_text
+-test.t1 check status OK
++test.t1 check status Table is already up to date
+ INSERT INTO t1 (a,b) VALUES (7,'g');
+ INSERT INTO t2 (a,b) VALUES (8,'h');
+ CHECK TABLE t2, t1 MEDIUM;
+@@ -52,7 +52,7 @@
+ INSERT INTO t1 (a) VALUES (17),(120),(132);
+ CHECK TABLE t1 FAST;
+ Table Op Msg_type Msg_text
+-test.t1 check status OK
++test.t1 check status Table is already up to date
+ INSERT INTO t1 (a) VALUES (801),(900),(7714);
+ CHECK TABLE t1 MEDIUM;
+ Table Op Msg_type Msg_text
diff --git a/storage/myisam/mysql-test/storage_engine/define_engine.inc b/storage/myisam/mysql-test/storage_engine/define_engine.inc
new file mode 100644
index 00000000000..d5e741629de
--- /dev/null
+++ b/storage/myisam/mysql-test/storage_engine/define_engine.inc
@@ -0,0 +1,45 @@
+###########################################
+#
+# This is a template of the include file define_engine.inc which
+# should be placed in storage/<engine>/mysql-test/storage_engine folder.
+#
+################################
+#
+# The name of the engine under test must be defined in $ENGINE variable.
+# You can set it either here (uncomment and edit) or in your environment.
+#
+let $ENGINE = MyISAM;
+#
+################################
+#
+# The following three variables define specific options for columns and tables.
+# Normally there should be none needed, but for some engines it can be different.
+# If the engine requires specific column option for all or indexed columns,
+# set them inside the comment, e.g. /*!NOT NULL*/.
+# Do the same for table options if needed, e.g. /*!INSERT_METHOD=LAST*/
+
+let $default_col_opts = /*!*/;
+let $default_col_indexed_opts = /*!*/;
+let $default_tbl_opts = /*!*/;
+
+# INDEX, UNIQUE INDEX, PRIMARY KEY, special index type - choose the fist that the engine allows,
+# or set it to /*!*/ if none is supported
+
+let $default_index = /*!INDEX*/;
+
+# If the engine does not support the following types, replace them with the closest possible
+
+let $default_int_type = INT(11);
+let $default_char_type = CHAR(8);
+
+################################
+
+--disable_query_log
+--disable_result_log
+
+# Here you can place your custom MTR code which needs to be executed before each test,
+# e.g. creation of an additional schema or table, etc.
+# The cleanup part should be defined in cleanup_engine.inc
+
+--enable_query_log
+--enable_result_log
diff --git a/storage/myisam/mysql-test/storage_engine/foreign_keys.rdiff b/storage/myisam/mysql-test/storage_engine/foreign_keys.rdiff
new file mode 100644
index 00000000000..67157754c04
--- /dev/null
+++ b/storage/myisam/mysql-test/storage_engine/foreign_keys.rdiff
@@ -0,0 +1,145 @@
+--- suite/storage_engine/foreign_keys.result 2012-07-12 18:56:19.782678645 +0400
++++ suite/storage_engine/foreign_keys.reject 2012-07-15 16:21:30.414240794 +0400
+@@ -12,29 +12,57 @@
+ t2 CREATE TABLE `t2` (
+ `a` int(11) DEFAULT NULL,
+ `b` char(8) DEFAULT NULL,
+- KEY `a` (`a`),
+- CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`a`) REFERENCES `t1` (`a`)
++ KEY `a` (`a`)
+ ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1
+ INSERT INTO t2 (a,b) VALUES (1,'a'),(2,'b');
+-ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`a`) REFERENCES `t1` (`a`))
++# ERROR: Statement succeeded (expected results: ER_NO_REFERENCED_ROW_2)
++# ------------ UNEXPECTED RESULT ------------
++# The statement|command succeeded unexpectedly.
++# Foreign keys or the mix could be unsupported|malfunctioning, or the problem was caused by previous errors.
++# You can change the engine code, or create an rdiff, or disable the test by adding it to disabled.def.
++# Further in this test, the message might sometimes be suppressed; a part of the test might be skipped.
++# Also, this problem may cause a chain effect (more errors of different kinds in the test).
++# -------------------------------------------
+ INSERT INTO t1 (a,b) VALUES (1,'c'),(2,'d');
+ INSERT INTO t2 (a,b) VALUES (1,'a'),(2,'b');
+ UPDATE t2 SET a=a+1;
+-ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`a`) REFERENCES `t1` (`a`))
++# ERROR: Statement succeeded (expected results: ER_NO_REFERENCED_ROW_2)
++# ------------ UNEXPECTED RESULT ------------
++# The statement|command succeeded unexpectedly.
++# Foreign keys or the mix could be unsupported|malfunctioning, or the problem was caused by previous errors.
++# You can change the engine code, or create an rdiff, or disable the test by adding it to disabled.def.
++# Further in this test, the message might sometimes be suppressed; a part of the test might be skipped.
++# Also, this problem may cause a chain effect (more errors of different kinds in the test).
++# -------------------------------------------
+ UPDATE t1 SET a=3 WHERE a=2;
+-ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`a`) REFERENCES `t1` (`a`))
++# ERROR: Statement succeeded (expected results: ER_ROW_IS_REFERENCED_2)
+ DELETE FROM t1 WHERE a=2;
+-ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`a`) REFERENCES `t1` (`a`))
++# ERROR: Statement succeeded (expected results: ER_ROW_IS_REFERENCED_2)
++# ------------ UNEXPECTED RESULT ------------
++# The statement|command succeeded unexpectedly.
++# Foreign keys or the mix could be unsupported|malfunctioning, or the problem was caused by previous errors.
++# You can change the engine code, or create an rdiff, or disable the test by adding it to disabled.def.
++# Further in this test, the message might sometimes be suppressed; a part of the test might be skipped.
++# Also, this problem may cause a chain effect (more errors of different kinds in the test).
++# -------------------------------------------
+ DELETE FROM t2 WHERE a=2;
+ SELECT * FROM t1;
+ a b
+ 1 c
+-2 d
++3 d
+ SELECT * FROM t2;
+ a b
+-1 a
++3 b
++3 b
+ DROP TABLE t1;
+-ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails
++# ERROR: Statement succeeded (expected results: ER_ROW_IS_REFERENCED)
++# ------------ UNEXPECTED RESULT ------------
++# The statement|command succeeded unexpectedly.
++# Foreign keys or the mix could be unsupported|malfunctioning, or the problem was caused by previous errors.
++# You can change the engine code, or create an rdiff, or disable the test by adding it to disabled.def.
++# Further in this test, the message might sometimes be suppressed; a part of the test might be skipped.
++# Also, this problem may cause a chain effect (more errors of different kinds in the test).
++# -------------------------------------------
+ DROP TABLE t2;
+ CREATE TABLE t2 (a <INT_COLUMN>,
+ b <CHAR_COLUMN>,
+@@ -46,26 +74,65 @@
+ t2 CREATE TABLE `t2` (
+ `a` int(11) DEFAULT NULL,
+ `b` char(8) DEFAULT NULL,
+- KEY `a` (`a`),
+- CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`a`) REFERENCES `t1` (`a`) ON DELETE CASCADE ON UPDATE CASCADE
++ KEY `a` (`a`)
+ ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1
+ INSERT INTO t2 (a,b) VALUES (1,'a'),(2,'b'),(3,'c'),(4,'d');
+-ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`a`) REFERENCES `t1` (`a`) ON DELETE CASCADE ON UPDATE CASCADE)
++# ERROR: Statement succeeded (expected results: ER_NO_REFERENCED_ROW_2)
+ INSERT INTO t1 (a,b) VALUES (3,'a'),(4,'a');
++ERROR 42S02: Table 'test.t1' doesn't exist
+ INSERT INTO t2 (a,b) VALUES (1,'a'),(2,'b'),(3,'c'),(4,'d'),(4,'e'),(3,'a');
+ UPDATE t1 SET a=a+1;
++ERROR 42S02: Table 'test.t1' doesn't exist
++# ------------ UNEXPECTED RESULT ------------
++# The statement|command finished with ER_NO_SUCH_TABLE.
++# UPDATE or the mix could be unsupported|malfunctioning, or the problem was caused by previous errors.
++# You can change the engine code, or create an rdiff, or disable the test by adding it to disabled.def.
++# Further in this test, the message might sometimes be suppressed; a part of the test might be skipped.
++# Also, this problem may cause a chain effect (more errors of different kinds in the test).
++# -------------------------------------------
+ SELECT * FROM t2;
+ a b
+-5 a
+-5 a
+-5 b
+-5 c
+-5 d
+-5 e
++1 a
++1 a
++2 b
++2 b
++3 a
++3 c
++3 c
++4 d
++4 d
++4 e
+ DELETE FROM t1 WHERE b='a' LIMIT 2;
++ERROR 42S02: Table 'test.t1' doesn't exist
++# ------------ UNEXPECTED RESULT ------------
++# The statement|command finished with ER_NO_SUCH_TABLE.
++# DELETE or the mix could be unsupported|malfunctioning, or the problem was caused by previous errors.
++# You can change the engine code, or create an rdiff, or disable the test by adding it to disabled.def.
++# Further in this test, the message might sometimes be suppressed; a part of the test might be skipped.
++# Also, this problem may cause a chain effect (more errors of different kinds in the test).
++# -------------------------------------------
+ SELECT * FROM t2;
+ a b
++1 a
++1 a
++2 b
++2 b
++3 a
++3 c
++3 c
++4 d
++4 d
++4 e
+ TRUNCATE TABLE t1;
+-ERROR 42000: Cannot truncate a table referenced in a foreign key constraint (`test`.`t2`, CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`a`) REFERENCES `test`.`t1` (`a`))
++ERROR 42S02: Table 'test.t1' doesn't exist
++# ERROR: Statement ended with errno 1146, errname ER_NO_SUCH_TABLE (expected results: ER_TRUNCATE_ILLEGAL_FK)
++# ------------ UNEXPECTED RESULT ------------
++# The statement|command finished with ER_NO_SUCH_TABLE.
++# Foreign keys or the mix could be unsupported|malfunctioning, or the problem was caused by previous errors.
++# You can change the engine code, or create an rdiff, or disable the test by adding it to disabled.def.
++# Further in this test, the message might sometimes be suppressed; a part of the test might be skipped.
++# Also, this problem may cause a chain effect (more errors of different kinds in the test).
++# -------------------------------------------
+ DROP TABLE t2;
+ DROP TABLE t1;
++ERROR 42S02: Unknown table 't1'
diff --git a/storage/myisam/mysql-test/storage_engine/index_type_hash.rdiff b/storage/myisam/mysql-test/storage_engine/index_type_hash.rdiff
new file mode 100644
index 00000000000..e7fa0013fa9
--- /dev/null
+++ b/storage/myisam/mysql-test/storage_engine/index_type_hash.rdiff
@@ -0,0 +1,60 @@
+--- suite/storage_engine/index_type_hash.result 2012-07-15 01:10:17.919128889 +0400
++++ suite/storage_engine/index_type_hash.reject 2012-07-15 16:21:32.806210722 +0400
+@@ -4,7 +4,7 @@
+ ) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+ SHOW KEYS IN t1;
+ Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment
+-t1 1 a 1 a # # NULL NULL # HASH
++t1 1 a 1 a # # NULL NULL # BTREE
+ DROP TABLE t1;
+ CREATE TABLE t1 (a <INT_COLUMN>,
+ b <CHAR_COLUMN>,
+@@ -12,8 +12,8 @@
+ ) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+ SHOW KEYS IN t1;
+ Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment
+-t1 1 a_b 1 a # # NULL NULL # HASH a_b index
+-t1 1 a_b 2 b # # NULL NULL # HASH a_b index
++t1 1 a_b 1 a # # NULL NULL # BTREE a_b index
++t1 1 a_b 2 b # # NULL NULL # BTREE a_b index
+ DROP TABLE t1;
+ CREATE TABLE t1 (a <INT_COLUMN>,
+ b <CHAR_COLUMN>,
+@@ -22,8 +22,8 @@
+ ) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+ SHOW KEYS IN t1;
+ Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment
+-t1 1 a 1 a # # NULL NULL # HASH
+-t1 1 b 1 b # # NULL NULL # HASH
++t1 1 a 1 a # # NULL NULL # BTREE
++t1 1 b 1 b # # NULL NULL # BTREE
+ DROP TABLE t1;
+ CREATE TABLE t1 (a <INT_COLUMN>,
+ b <CHAR_COLUMN>,
+@@ -31,7 +31,7 @@
+ ) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+ SHOW KEYS IN t1;
+ Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment
+-t1 0 a 1 a # # NULL NULL # HASH
++t1 0 a 1 a # # NULL NULL # BTREE
+ INSERT INTO t1 (a,b) VALUES (1,'a'),(2,'b');
+ INSERT INTO t1 (a,b) VALUES (1,'c');
+ ERROR 23000: Duplicate entry '1' for key 'a'
+@@ -43,7 +43,7 @@
+ ALTER TABLE t1 ADD <CUSTOM_INDEX> (a) USING HASH COMMENT 'simple index on a';
+ SHOW INDEX FROM t1;
+ Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment
+-t1 1 a 1 a # # NULL NULL # HASH simple index on a
++t1 1 a 1 a # # NULL NULL # BTREE simple index on a
+ ALTER TABLE t1 DROP KEY a;
+ DROP TABLE t1;
+ CREATE TABLE t1 (a <INT_COLUMN>,
+@@ -52,7 +52,7 @@
+ ) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+ SHOW KEYS IN t1;
+ Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment
+-t1 0 a 1 a # # NULL NULL # HASH
++t1 0 a 1 a # # NULL NULL # BTREE
+ INSERT INTO t1 (a,b) VALUES (1,'a'),(2,'b');
+ INSERT INTO t1 (a,b) VALUES (1,'c');
+ ERROR 23000: Duplicate entry '1' for key 'a'
diff --git a/storage/myisam/mysql-test/storage_engine/show_engine.rdiff b/storage/myisam/mysql-test/storage_engine/show_engine.rdiff
new file mode 100644
index 00000000000..4e6624653ea
--- /dev/null
+++ b/storage/myisam/mysql-test/storage_engine/show_engine.rdiff
@@ -0,0 +1,10 @@
+--- suite/storage_engine/show_engine.result 2012-06-24 23:55:19.539380000 +0400
++++ suite/storage_engine/show_engine.reject 2012-07-15 16:21:54.401939228 +0400
+@@ -4,7 +4,6 @@
+ # volatile data (timestamps, memory info, etc.)
+ SHOW ENGINE <STORAGE_ENGINE> STATUS;
+ Type Name Status
+-<STORAGE_ENGINE> ### Engine status, can be long and changeable ###
+ # For SHOW MUTEX even the number of lines is volatile, so the result logging is disabled,
+ # the test only checks that the command does not produce any errors
+ SHOW ENGINE <STORAGE_ENGINE> MUTEX;
diff --git a/storage/myisam/mysql-test/storage_engine/tbl_opt_insert_method.rdiff b/storage/myisam/mysql-test/storage_engine/tbl_opt_insert_method.rdiff
new file mode 100644
index 00000000000..a8df852515a
--- /dev/null
+++ b/storage/myisam/mysql-test/storage_engine/tbl_opt_insert_method.rdiff
@@ -0,0 +1,11 @@
+--- suite/storage_engine/tbl_opt_insert_method.result 2012-06-24 23:55:19.539380000 +0400
++++ suite/storage_engine/tbl_opt_insert_method.reject 2012-07-15 16:21:56.381914337 +0400
+@@ -5,7 +5,7 @@
+ t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL,
+ `b` char(8) DEFAULT NULL
+-) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 INSERT_METHOD=FIRST
++) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1
+ ALTER TABLE t1 INSERT_METHOD=NO;
+ SHOW CREATE TABLE t1;
+ Table Create Table
diff --git a/storage/myisam/mysql-test/storage_engine/tbl_opt_union.rdiff b/storage/myisam/mysql-test/storage_engine/tbl_opt_union.rdiff
new file mode 100644
index 00000000000..4fa164523db
--- /dev/null
+++ b/storage/myisam/mysql-test/storage_engine/tbl_opt_union.rdiff
@@ -0,0 +1,16 @@
+--- suite/storage_engine/tbl_opt_union.result 2012-06-24 23:55:19.539380000 +0400
++++ suite/storage_engine/tbl_opt_union.reject 2012-07-15 16:21:58.121892463 +0400
+@@ -4,11 +4,11 @@
+ Table Create Table
+ t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+-) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 UNION=(`child1`)
++) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1
+ ALTER TABLE t1 UNION = (child1,child2);
+ SHOW CREATE TABLE t1;
+ Table Create Table
+ t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+-) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 UNION=(`child1`,`child2`)
++) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1
+ DROP TABLE t1, child1, child2;
diff --git a/storage/myisam/mysql-test/storage_engine/trx/cons_snapshot_repeatable_read.rdiff b/storage/myisam/mysql-test/storage_engine/trx/cons_snapshot_repeatable_read.rdiff
new file mode 100644
index 00000000000..8d1434ad2fe
--- /dev/null
+++ b/storage/myisam/mysql-test/storage_engine/trx/cons_snapshot_repeatable_read.rdiff
@@ -0,0 +1,9 @@
+0a1,6
+> # -- WARNING ----------------------------------------------------------------
+> # According to I_S.ENGINES, MyISAM does not support transactions.
+> # If it is true, the test will most likely fail; you can
+> # either create an rdiff file, or add the test to disabled.def.
+> # If transactions should be supported, check the data in Information Schema.
+> # ---------------------------------------------------------------------------
+13a20
+> 1
diff --git a/storage/myisam/mysql-test/storage_engine/trx/cons_snapshot_serializable.rdiff b/storage/myisam/mysql-test/storage_engine/trx/cons_snapshot_serializable.rdiff
new file mode 100644
index 00000000000..8d1434ad2fe
--- /dev/null
+++ b/storage/myisam/mysql-test/storage_engine/trx/cons_snapshot_serializable.rdiff
@@ -0,0 +1,9 @@
+0a1,6
+> # -- WARNING ----------------------------------------------------------------
+> # According to I_S.ENGINES, MyISAM does not support transactions.
+> # If it is true, the test will most likely fail; you can
+> # either create an rdiff file, or add the test to disabled.def.
+> # If transactions should be supported, check the data in Information Schema.
+> # ---------------------------------------------------------------------------
+13a20
+> 1
diff --git a/storage/myisam/mysql-test/storage_engine/trx/delete.rdiff b/storage/myisam/mysql-test/storage_engine/trx/delete.rdiff
new file mode 100644
index 00000000000..491b4636796
--- /dev/null
+++ b/storage/myisam/mysql-test/storage_engine/trx/delete.rdiff
@@ -0,0 +1,50 @@
+--- suite/storage_engine/trx/delete.result 2012-07-12 23:06:18.946113626 +0400
++++ suite/storage_engine/trx/delete.reject 2012-07-15 16:55:46.108397219 +0400
+@@ -1,3 +1,15 @@
++# -- WARNING ----------------------------------------------------------------
++# According to I_S.ENGINES, MyISAM does not support transactions.
++# If it is true, the test will most likely fail; you can
++# either create an rdiff file, or add the test to disabled.def.
++# If transactions should be supported, check the data in Information Schema.
++# ---------------------------------------------------------------------------
++# -- WARNING ----------------------------------------------------------------
++# According to I_S.ENGINES, MyISAM does not support savepoints.
++# If it is true, the test will most likely fail; you can
++# either create an rdiff file (recommended), or add the test to disabled.def.
++# If savepoints should be supported, check the data in Information Schema.
++# ---------------------------------------------------------------------------
+ DROP TABLE IF EXISTS t1;
+ CREATE TABLE t1 (a <INT_COLUMN>, b <CHAR_COLUMN>) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+ INSERT INTO t1 (a,b) VALUES (1,'a'),(2,'b'),(3,'c'),(4,'d'),(5,'e'),(6,'f'),(7,'g'),(8,'h'),(10000,'foobar');
+@@ -46,27 +58,17 @@
+ DELETE FROM t1;
+ RELEASE SAVEPOINT spt1;
+ ROLLBACK;
++Warnings:
++Warning 1196 Some non-transactional changed tables couldn't be rolled back
+ SELECT * FROM t1;
+ a b
+-10000 foobar
+-10000 foobar
+-2 b
+-2 b
+-4 d
+-4 d
+-5 e
+-5 e
+-6 f
+-6 f
+-7 g
+-7 g
+-8 h
+-8 h
+ BEGIN;
+ DELETE FROM t1 WHERE a <= 4 ORDER BY b DESC LIMIT 1;
+ SAVEPOINT spt1;
+ DELETE FROM t1;
+ INSERT INTO t1 (a,b) VALUES (1,'a');
+ ROLLBACK TO SAVEPOINT spt1;
++Warnings:
++Warning 1196 Some non-transactional changed tables couldn't be rolled back
+ COMMIT;
+ DROP TABLE t1;
diff --git a/storage/myisam/mysql-test/storage_engine/trx/insert.rdiff b/storage/myisam/mysql-test/storage_engine/trx/insert.rdiff
new file mode 100644
index 00000000000..4619db1d095
--- /dev/null
+++ b/storage/myisam/mysql-test/storage_engine/trx/insert.rdiff
@@ -0,0 +1,65 @@
+--- suite/storage_engine/trx/insert.result 2012-07-12 23:09:44.663527407 +0400
++++ suite/storage_engine/trx/insert.reject 2012-07-15 16:55:46.676390078 +0400
+@@ -1,3 +1,15 @@
++# -- WARNING ----------------------------------------------------------------
++# According to I_S.ENGINES, MyISAM does not support transactions.
++# If it is true, the test will most likely fail; you can
++# either create an rdiff file, or add the test to disabled.def.
++# If transactions should be supported, check the data in Information Schema.
++# ---------------------------------------------------------------------------
++# -- WARNING ----------------------------------------------------------------
++# According to I_S.ENGINES, MyISAM does not support savepoints.
++# If it is true, the test will most likely fail; you can
++# either create an rdiff file (recommended), or add the test to disabled.def.
++# If savepoints should be supported, check the data in Information Schema.
++# ---------------------------------------------------------------------------
+ DROP TABLE IF EXISTS t1;
+ CREATE TABLE t1 (a <INT_COLUMN>, b <CHAR_COLUMN>) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+ BEGIN;
+@@ -21,8 +33,11 @@
+ RELEASE SAVEPOINT spt1;
+ INSERT INTO t1 (a,b) VALUES (DEFAULT,DEFAULT);
+ ROLLBACK;
++Warnings:
++Warning 1196 Some non-transactional changed tables couldn't be rolled back
+ SELECT * FROM t1;
+ a b
++0 test
+ 1 a
+ 10 foo
+ 100 foo
+@@ -31,25 +46,34 @@
+ 3 c
+ 4 d
+ 5 e
++NULL NULL
++NULL NULL
+ BEGIN;
+ INSERT t1 (a) VALUE (10),(20);
+ SAVEPOINT spt1;
+ INSERT INTO t1 SET a = 11, b = 'f';
+ INSERT t1 SET b = DEFAULT;
+ ROLLBACK TO SAVEPOINT spt1;
++Warnings:
++Warning 1196 Some non-transactional changed tables couldn't be rolled back
+ INSERT INTO t1 (b,a) VALUES ('test1',10);
+ COMMIT;
+ SELECT * FROM t1;
+ a b
++0 test
+ 1 a
+ 10 NULL
+ 10 foo
+ 10 test1
+ 100 foo
+ 11 abc
++11 f
+ 2 b
+ 20 NULL
+ 3 c
+ 4 d
+ 5 e
++NULL NULL
++NULL NULL
++NULL NULL
+ DROP TABLE t1;
diff --git a/storage/myisam/mysql-test/storage_engine/trx/level_read_committed.rdiff b/storage/myisam/mysql-test/storage_engine/trx/level_read_committed.rdiff
new file mode 100644
index 00000000000..c0cc9ff9351
--- /dev/null
+++ b/storage/myisam/mysql-test/storage_engine/trx/level_read_committed.rdiff
@@ -0,0 +1,44 @@
+0a1,6
+> # -- WARNING ----------------------------------------------------------------
+> # According to I_S.ENGINES, MyISAM does not support transactions.
+> # If it is true, the test will most likely fail; you can
+> # either create an rdiff file, or add the test to disabled.def.
+> # If transactions should be supported, check the data in Information Schema.
+> # ---------------------------------------------------------------------------
+18a25
+> 1
+25a33,34
+> 1
+> 2
+30a40,43
+> 1
+> 101
+> 102
+> 2
+34a48,49
+> 101
+> 102
+39a55,56
+> 101
+> 102
+44a62,63
+> 101
+> 102
+51a71,72
+> 101
+> 102
+54a76,77
+> 301
+> 302
+58a82,83
+> 101
+> 102
+61a87,88
+> 301
+> 302
+65a93,94
+> 101
+> 102
+68a98,99
+> 301
+> 302
diff --git a/storage/myisam/mysql-test/storage_engine/trx/level_read_uncommitted.rdiff b/storage/myisam/mysql-test/storage_engine/trx/level_read_uncommitted.rdiff
new file mode 100644
index 00000000000..2a7ddd33c8c
--- /dev/null
+++ b/storage/myisam/mysql-test/storage_engine/trx/level_read_uncommitted.rdiff
@@ -0,0 +1,7 @@
+0a1,6
+> # -- WARNING ----------------------------------------------------------------
+> # According to I_S.ENGINES, MyISAM does not support transactions.
+> # If it is true, the test will most likely fail; you can
+> # either create an rdiff file, or add the test to disabled.def.
+> # If transactions should be supported, check the data in Information Schema.
+> # ---------------------------------------------------------------------------
diff --git a/storage/myisam/mysql-test/storage_engine/trx/level_repeatable_read.rdiff b/storage/myisam/mysql-test/storage_engine/trx/level_repeatable_read.rdiff
new file mode 100644
index 00000000000..8b8df802275
--- /dev/null
+++ b/storage/myisam/mysql-test/storage_engine/trx/level_repeatable_read.rdiff
@@ -0,0 +1,53 @@
+0a1,6
+> # -- WARNING ----------------------------------------------------------------
+> # According to I_S.ENGINES, MyISAM does not support transactions.
+> # If it is true, the test will most likely fail; you can
+> # either create an rdiff file, or add the test to disabled.def.
+> # If transactions should be supported, check the data in Information Schema.
+> # ---------------------------------------------------------------------------
+18a25
+> 1
+25a33,34
+> 1
+> 2
+27,28c36
+< ERROR HY000: Lock wait timeout exceeded; try restarting transaction
+< # WARNING: Statement ended with errno 1205, errname 'ER_LOCK_WAIT_TIMEOUT'.
+---
+> # WARNING: Statement ended with errno 0, errname ''.
+31a40,43
+> 1
+> 101
+> 102
+> 2
+35a48,49
+> 101
+> 102
+40a55,56
+> 101
+> 102
+44a61,64
+> 1
+> 101
+> 102
+> 2
+49a70,73
+> 1
+> 101
+> 102
+> 2
+51a76,77
+> 301
+> 302
+55a82,83
+> 101
+> 102
+58a87,88
+> 301
+> 302
+62a93,94
+> 101
+> 102
+65a98,99
+> 301
+> 302
diff --git a/storage/myisam/mysql-test/storage_engine/trx/level_serializable.rdiff b/storage/myisam/mysql-test/storage_engine/trx/level_serializable.rdiff
new file mode 100644
index 00000000000..bbcb8ac1838
--- /dev/null
+++ b/storage/myisam/mysql-test/storage_engine/trx/level_serializable.rdiff
@@ -0,0 +1,69 @@
+0a1,6
+> # -- WARNING ----------------------------------------------------------------
+> # According to I_S.ENGINES, MyISAM does not support transactions.
+> # If it is true, the test will most likely fail; you can
+> # either create an rdiff file, or add the test to disabled.def.
+> # If transactions should be supported, check the data in Information Schema.
+> # ---------------------------------------------------------------------------
+14,15c20
+< ERROR HY000: Lock wait timeout exceeded; try restarting transaction
+< # WARNING: Statement ended with errno 1205, errname 'ER_LOCK_WAIT_TIMEOUT'.
+---
+> # WARNING: Statement ended with errno 0, errname ''.
+19a25
+> 1
+22,23c28
+< ERROR HY000: Lock wait timeout exceeded; try restarting transaction
+< # WARNING: Statement ended with errno 1205, errname 'ER_LOCK_WAIT_TIMEOUT'.
+---
+> # WARNING: Statement ended with errno 0, errname ''.
+27a33,34
+> 1
+> 2
+32a40,43
+> 1
+> 101
+> 102
+> 2
+35a47,50
+> 1
+> 101
+> 102
+> 2
+38a54,57
+> 1
+> 101
+> 102
+> 2
+41a61,64
+> 1
+> 101
+> 102
+> 2
+46a70,77
+> 1
+> 101
+> 102
+> 2
+> 201
+> 202
+> 301
+> 302
+49a81,88
+> 1
+> 101
+> 102
+> 2
+> 201
+> 202
+> 301
+> 302
+52a92,99
+> 1
+> 101
+> 102
+> 2
+> 201
+> 202
+> 301
+> 302
diff --git a/storage/myisam/mysql-test/storage_engine/trx/select_for_update.rdiff b/storage/myisam/mysql-test/storage_engine/trx/select_for_update.rdiff
new file mode 100644
index 00000000000..08e0802a28f
--- /dev/null
+++ b/storage/myisam/mysql-test/storage_engine/trx/select_for_update.rdiff
@@ -0,0 +1,50 @@
+--- suite/storage_engine/trx/select_for_update.result 2012-07-13 01:26:07.612653808 +0400
++++ suite/storage_engine/trx/select_for_update.reject 2012-07-15 16:55:49.784351006 +0400
+@@ -1,3 +1,9 @@
++# -- WARNING ----------------------------------------------------------------
++# According to I_S.ENGINES, MyISAM does not support transactions.
++# If it is true, the test will most likely fail; you can
++# either create an rdiff file, or add the test to disabled.def.
++# If transactions should be supported, check the data in Information Schema.
++# ---------------------------------------------------------------------------
+ DROP TABLE IF EXISTS t1;
+ CREATE TABLE t1 (a <INT_COLUMN>, b <CHAR_COLUMN>) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+ INSERT INTO t1 (a,b) VALUES (1,'a'),(2,'b'),(3,'a');
+@@ -14,16 +20,33 @@
+ 1 a
+ 3 a
+ SELECT * FROM t1 WHERE b='a' LOCK IN SHARE MODE;
+-ERROR HY000: Lock wait timeout exceeded; try restarting transaction
++a b
++1 a
++3 a
++# ERROR: Statement succeeded (expected results: ER_LOCK_WAIT_TIMEOUT)
++# ------------ UNEXPECTED RESULT ------------
++# The statement|command succeeded unexpectedly.
++# SELECT .. FOR UPDATE or LOCK IN SHARE MODE or the mix could be unsupported|malfunctioning, or the problem was caused by previous errors.
++# You can change the engine code, or create an rdiff, or disable the test by adding it to disabled.def.
++# Further in this test, the message might sometimes be suppressed; a part of the test might be skipped.
++# Also, this problem may cause a chain effect (more errors of different kinds in the test).
++# -------------------------------------------
+ UPDATE t1 SET b='c' WHERE b='a';
+-ERROR HY000: Lock wait timeout exceeded; try restarting transaction
++# ERROR: Statement succeeded (expected results: ER_LOCK_WAIT_TIMEOUT)
++# ------------ UNEXPECTED RESULT ------------
++# The statement|command succeeded unexpectedly.
++# UPDATE or SELECT .. FOR UPDATE or the mix could be unsupported|malfunctioning, or the problem was caused by previous errors.
++# You can change the engine code, or create an rdiff, or disable the test by adding it to disabled.def.
++# Further in this test, the message might sometimes be suppressed; a part of the test might be skipped.
++# Also, this problem may cause a chain effect (more errors of different kinds in the test).
++# -------------------------------------------
+ connection con1;
+ COMMIT;
+ SELECT * FROM t1;
+ a b
+-1 a
++1 c
+ 2 b
+-3 a
++3 c
+ disconnect con1;
+ connection default;
+ UPDATE t1 SET b='c' WHERE b='a';
diff --git a/storage/myisam/mysql-test/storage_engine/trx/select_lock_in_share_mode.rdiff b/storage/myisam/mysql-test/storage_engine/trx/select_lock_in_share_mode.rdiff
new file mode 100644
index 00000000000..97941bbdb13
--- /dev/null
+++ b/storage/myisam/mysql-test/storage_engine/trx/select_lock_in_share_mode.rdiff
@@ -0,0 +1,37 @@
+--- suite/storage_engine/trx/select_lock_in_share_mode.result 2012-07-13 01:30:17.505512229 +0400
++++ suite/storage_engine/trx/select_lock_in_share_mode.reject 2012-07-15 16:55:50.444342708 +0400
+@@ -1,3 +1,9 @@
++# -- WARNING ----------------------------------------------------------------
++# According to I_S.ENGINES, MyISAM does not support transactions.
++# If it is true, the test will most likely fail; you can
++# either create an rdiff file, or add the test to disabled.def.
++# If transactions should be supported, check the data in Information Schema.
++# ---------------------------------------------------------------------------
+ DROP TABLE IF EXISTS t1;
+ CREATE TABLE t1 (a <INT_COLUMN>, b <CHAR_COLUMN>) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+ INSERT INTO t1 (a,b) VALUES (1,'a'),(2,'b'),(3,'a');
+@@ -18,14 +24,21 @@
+ 1 a
+ 3 a
+ UPDATE t1 SET b='c' WHERE b='a';
+-ERROR HY000: Lock wait timeout exceeded; try restarting transaction
++# ERROR: Statement succeeded (expected results: ER_LOCK_WAIT_TIMEOUT)
++# ------------ UNEXPECTED RESULT ------------
++# The statement|command succeeded unexpectedly.
++# LOCK IN SHARE MODE or UPDATE or the mix could be unsupported|malfunctioning, or the problem was caused by previous errors.
++# You can change the engine code, or create an rdiff, or disable the test by adding it to disabled.def.
++# Further in this test, the message might sometimes be suppressed; a part of the test might be skipped.
++# Also, this problem may cause a chain effect (more errors of different kinds in the test).
++# -------------------------------------------
+ connection con1;
+ COMMIT;
+ SELECT * FROM t1;
+ a b
+-1 a
++1 c
+ 2 b
+-3 a
++3 c
+ disconnect con1;
+ connection default;
+ UPDATE t1 SET b='c' WHERE b='a';
diff --git a/storage/myisam/mysql-test/storage_engine/trx/update.rdiff b/storage/myisam/mysql-test/storage_engine/trx/update.rdiff
new file mode 100644
index 00000000000..131286d613c
--- /dev/null
+++ b/storage/myisam/mysql-test/storage_engine/trx/update.rdiff
@@ -0,0 +1,58 @@
+--- suite/storage_engine/trx/update.result 2012-07-13 01:43:50.355293322 +0400
++++ suite/storage_engine/trx/update.reject 2012-07-15 16:55:51.016335518 +0400
+@@ -1,3 +1,15 @@
++# -- WARNING ----------------------------------------------------------------
++# According to I_S.ENGINES, MyISAM does not support transactions.
++# If it is true, the test will most likely fail; you can
++# either create an rdiff file, or add the test to disabled.def.
++# If transactions should be supported, check the data in Information Schema.
++# ---------------------------------------------------------------------------
++# -- WARNING ----------------------------------------------------------------
++# According to I_S.ENGINES, MyISAM does not support savepoints.
++# If it is true, the test will most likely fail; you can
++# either create an rdiff file (recommended), or add the test to disabled.def.
++# If savepoints should be supported, check the data in Information Schema.
++# ---------------------------------------------------------------------------
+ DROP TABLE IF EXISTS t1;
+ CREATE TABLE t1 (a <INT_COLUMN>, b <CHAR_COLUMN>) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+ INSERT INTO t1 (a,b) VALUES (1,'a'),(2,'b'),(3,'c'),(4,'d'),(5,'e'),(10000,'foobar');
+@@ -24,25 +36,29 @@
+ UPDATE t1 SET b = 'update' WHERE a <= 4 ORDER BY a DESC, b ASC LIMIT 3;
+ UPDATE t1 SET b = '';
+ ROLLBACK;
++Warnings:
++Warning 1196 Some non-transactional changed tables couldn't be rolled back
+ BEGIN;
+ UPDATE t1 SET b = 'update2' WHERE a <= 100;
+ SAVEPOINT spt1;
+ UPDATE t1 SET b = '';
+ ROLLBACK TO SAVEPOINT spt1;
++Warnings:
++Warning 1196 Some non-transactional changed tables couldn't be rolled back
+ UPDATE t1 SET b = 'upd' WHERE a = 10050;
+ COMMIT;
+ SELECT * FROM t1;
+ a b
+ 10050 upd
+ 10050 upd
+-51 update2
+-51 update2
+-52 update2
+-52 update2
+-53 update2
+-53 update2
+-54 update2
+-54 update2
+-55 update2
+-55 update2
++51
++51
++52
++52
++53
++53
++54
++54
++55
++55
+ DROP TABLE t1;
diff --git a/storage/myisam/mysql-test/storage_engine/trx/xa.rdiff b/storage/myisam/mysql-test/storage_engine/trx/xa.rdiff
new file mode 100644
index 00000000000..f445ad909f3
--- /dev/null
+++ b/storage/myisam/mysql-test/storage_engine/trx/xa.rdiff
@@ -0,0 +1,89 @@
+--- suite/storage_engine/trx/xa.result 2012-07-13 01:47:00.788899248 +0400
++++ suite/storage_engine/trx/xa.reject 2012-07-15 16:55:51.604328125 +0400
+@@ -1,3 +1,9 @@
++# -- WARNING ----------------------------------------------------------------
++# According to I_S.ENGINES, MyISAM does not support XA.
++# If it is true, the test will most likely fail; you can
++# either create an rdiff file, or add the test to disabled.def.
++# If XA should be supported, check the data in Information Schema.
++# ---------------------------------------------------------------------------
+ DROP TABLE IF EXISTS t1;
+ connect con1,localhost,root,,;
+ connect con2,localhost,root,,;
+@@ -9,17 +15,22 @@
+ connection con1;
+ SELECT * FROM t1;
+ a
++1
+ connection con2;
+ INSERT INTO t1 (a) VALUES (2);
+ XA END 'xa1';
+ connection con1;
+ SELECT * FROM t1;
+ a
++1
++2
+ connection con2;
+ XA PREPARE 'xa1';
+ connection con1;
+ SELECT * FROM t1;
+ a
++1
++2
+ connection con2;
+ XA RECOVER;
+ formatID gtrid_length bqual_length data
+@@ -38,6 +49,7 @@
+ a
+ 1
+ 2
++3
+ connection con2;
+ INSERT INTO t1 (a) VALUES (4);
+ XA END 'xa2';
+@@ -46,6 +58,8 @@
+ a
+ 1
+ 2
++3
++4
+ connection con2;
+ XA COMMIT 'xa2' ONE PHASE;
+ connection con1;
+@@ -65,6 +79,7 @@
+ 2
+ 3
+ 4
++5
+ connection con2;
+ INSERT INTO t1 (a) VALUES (6);
+ XA END 'xa3';
+@@ -75,6 +90,8 @@
+ 2
+ 3
+ 4
++5
++6
+ connection con2;
+ XA PREPARE 'xa3';
+ connection con1;
+@@ -84,8 +101,12 @@
+ 2
+ 3
+ 4
++5
++6
+ connection con2;
+ XA ROLLBACK 'xa3';
++Warnings:
++Warning 1196 Some non-transactional changed tables couldn't be rolled back
+ connection con1;
+ SELECT * FROM t1;
+ a
+@@ -93,4 +114,6 @@
+ 2
+ 3
+ 4
++5
++6
+ DROP TABLE t1;
diff --git a/storage/myisam/mysql-test/storage_engine/trx/xa_recovery.rdiff b/storage/myisam/mysql-test/storage_engine/trx/xa_recovery.rdiff
new file mode 100644
index 00000000000..f4629fb19a0
--- /dev/null
+++ b/storage/myisam/mysql-test/storage_engine/trx/xa_recovery.rdiff
@@ -0,0 +1,33 @@
+--- suite/storage_engine/trx/xa_recovery.result 2012-07-13 01:48:46.859565758 +0400
++++ suite/storage_engine/trx/xa_recovery.reject 2012-07-15 16:55:53.740301272 +0400
+@@ -1,3 +1,9 @@
++# -- WARNING ----------------------------------------------------------------
++# According to I_S.ENGINES, MyISAM does not support XA.
++# If it is true, the test will most likely fail; you can
++# either create an rdiff file, or add the test to disabled.def.
++# If XA should be supported, check the data in Information Schema.
++# ---------------------------------------------------------------------------
+ call mtr.add_suppression("Found 2 prepared XA transactions");
+ FLUSH TABLES;
+ DROP TABLE IF EXISTS t1;
+@@ -18,12 +24,18 @@
+ connection default;
+ XA RECOVER;
+ formatID gtrid_length bqual_length data
+-1 3 0 xa1
+-1 3 0 xa2
+ XA ROLLBACK 'xa1';
++ERROR XAE04: XAER_NOTA: Unknown XID
+ XA COMMIT 'xa2';
++ERROR XAE04: XAER_NOTA: Unknown XID
+ SELECT * FROM t1;
+ a
++1
++2
+ 3
+ 4
++Warnings:
++Error 145 Table './test/t1' is marked as crashed and should be repaired
++Error 1194 Table 't1' is marked as crashed and should be repaired
++Error 1034 1 client is using or hasn't closed the table properly
+ DROP TABLE t1;
diff --git a/storage/myisammrg/ha_myisammrg.cc b/storage/myisammrg/ha_myisammrg.cc
index e6bece5b7ff..47a3abb78d2 100644
--- a/storage/myisammrg/ha_myisammrg.cc
+++ b/storage/myisammrg/ha_myisammrg.cc
@@ -1652,6 +1652,47 @@ ha_rows ha_myisammrg::records()
return myrg_records(file);
}
+uint ha_myisammrg::count_query_cache_dependant_tables(uint8 *tables_type)
+{
+ MYRG_INFO *file = myrg_info();
+ /*
+ Here should be following statement
+ (*tables_type)|= HA_CACHE_TBL_NONTRANSACT;
+ but it has no effect because HA_CACHE_TBL_NONTRANSACT is 0
+ */
+ return (file->end_table - file->open_tables);
+}
+
+
+my_bool ha_myisammrg::register_query_cache_dependant_tables(THD *thd
+ __attribute__((unused)),
+ Query_cache *cache,
+ Query_cache_block_table **block_table,
+ uint *n)
+{
+ MYRG_INFO *file =myrg_info();
+ DBUG_ENTER("ha_myisammrg::register_query_cache_dependant_tables");
+
+ for (MYRG_TABLE *table =file->open_tables;
+ table != file->end_table ;
+ table++)
+ {
+ char key[MAX_DBKEY_LENGTH];
+ uint32 db_length;
+ uint key_length= cache->filename_2_table_key(key, table->table->filename,
+ &db_length);
+ (++(*block_table))->n= ++(*n);
+ /*
+ There are not callback function for for MyISAM, and engine data
+ */
+ if (!cache->insert_table(key_length, key, (*block_table),
+ db_length,
+ table_cache_type(),
+ 0, 0, TRUE))
+ DBUG_RETURN(TRUE);
+ }
+ DBUG_RETURN(FALSE);
+}
extern int myrg_panic(enum ha_panic_function flag);
int myisammrg_panic(handlerton *hton, ha_panic_function flag)
diff --git a/storage/myisammrg/ha_myisammrg.h b/storage/myisammrg/ha_myisammrg.h
index e0dc6e07542..f5ba2ffef38 100644
--- a/storage/myisammrg/ha_myisammrg.h
+++ b/storage/myisammrg/ha_myisammrg.h
@@ -149,4 +149,10 @@ public:
bool check_if_incompatible_data(HA_CREATE_INFO *info, uint table_changes);
int check(THD* thd, HA_CHECK_OPT* check_opt);
ha_rows records();
+ virtual uint count_query_cache_dependant_tables(uint8 *tables_type);
+ virtual my_bool
+ register_query_cache_dependant_tables(THD *thd,
+ Query_cache *cache,
+ Query_cache_block_table **block,
+ uint *n);
};
diff --git a/storage/myisammrg/mysql-test/storage_engine/alter_table.inc b/storage/myisammrg/mysql-test/storage_engine/alter_table.inc
new file mode 100644
index 00000000000..a978ade4f75
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/alter_table.inc
@@ -0,0 +1,116 @@
+##################################
+#
+# This include file will be used for all ALTER TABLE statements in the suite.
+# If you need to add additional steps or change the logic, copy the file
+# to storage/<engine>/mysql-test/storage_engine/ folder and modify it there.
+#
+##################
+#
+# Parameters:
+#
+# --let $alter_definition = <alter definition> # mandatory, everything that goes after the table name in ALTER statement
+# --let $table_name = <table name> # optional, default t1
+# --let $error_codes = <expected error codes, as in --error> # optional, default 0
+# --let $online = [0|1] # optional, default 0 (1 adds ONLINE)
+# --let $rename_to = <new table name> # optional, default empty.
+# # If set, means we are running RENAME TO, then alter definition is ignored
+#
+# Usage examples:
+#
+# --let $alter_definition = ADD COLUMN b $char_col DEFAULT ''
+#
+
+--let $child_alter_definition = $alter_definition
+
+if ($rename_to)
+{
+ --let $alter_definition = RENAME TO $rename_to
+ --let $child_alter_definition = RENAME TO mrg.$rename_to
+}
+
+if (!$alter_definition)
+{
+ --die # The ALTER statement is empty
+}
+
+--let $alter_statement = ALTER
+
+if ($online)
+{
+ --let $alter_statement = $alter_statement ONLINE
+}
+
+if (!$table_name)
+{
+ --let $table_name = t1
+}
+
+--let $alter_statement = $alter_statement TABLE $table_name $alter_definition
+# We don't want to do ONLINE on underlying tables, we are not testing MyISAM
+--let $child_statement = ALTER TABLE mrg.$table_name $child_alter_definition
+
+
+
+# We now have the complete ALTER statement in $alter_statement.
+# If your ALTER statement should be composed differently,
+# modify the logic above.
+
+#####################
+# Here you can add logic needed BEFORE the main statement
+# (e.g. base tables need to be altered, etc.).
+# Surround it by --disable_query_log/--enable_query_log
+# if you don't want it to appear in the result output.
+#####################
+
+--source obfuscate.inc
+
+eval $alter_statement;
+--source check_errors.inc
+
+# Make sure you don't add any statements between the main ALTER (above)
+# and saving mysql_errno and mysql_errname (below)
+# They are saved in case you want to add more logic after the main ALTER,
+# because we need the result code of the statement.
+# Also, do not change $alter_statement after it is executed!
+
+--let $my_errno = $mysql_errno
+--let $my_errname = $mysql_errname
+
+#####################
+# Here you can add logic needed AFTER the main statement.
+# Surround it by --disable_query_log/--enable_query_log
+# if you don't want it to appear in the result output.
+#####################
+--disable_query_log
+--disable_warnings
+--disable_result_log
+# We will only try to alter the underlying table if the main alter was successful
+if (!$my_errno)
+{
+ if ($rename_to)
+ {
+ eval ALTER TABLE $rename_to UNION(mrg.$rename_to);
+ }
+ # In the same section, the manual says that FLUSH TABLES should be performed before altering
+ # the underlying table, and later also says that it should be done after. We'll do both
+ FLUSH TABLES;
+ eval $child_statement;
+ FLUSH TABLES;
+}
+--enable_result_log
+--enable_warnings
+--enable_query_log
+
+# Unset the parameters, we don't want them to be accidentally reused later
+--let $alter_definition =
+--let $table_name =
+--let $error_codes =
+--let $online = 0
+--let $rename_to =
+
+# Restore the error codes of the main statement
+--let $mysql_errno = $my_errno
+--let $mysql_errname = $my_errname
+# Make sure you don't add any SQL statements after restoring
+# mysql_errno and mysql_errname (above)
+
diff --git a/storage/myisammrg/mysql-test/storage_engine/alter_table.rdiff b/storage/myisammrg/mysql-test/storage_engine/alter_table.rdiff
new file mode 100644
index 00000000000..447a38a5b2b
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/alter_table.rdiff
@@ -0,0 +1,68 @@
+11c11
+< ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1
+---
+> ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(`mrg`.`t1`)
+19c19
+< ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1
+---
+> ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(`mrg`.`t1`)
+27c27
+< ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1
+---
+> ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(`mrg`.`t1`)
+35c35
+< ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1
+---
+> ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(`mrg`.`t1`)
+43c43
+< ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1
+---
+> ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(`mrg`.`t1`)
+51c51
+< ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1
+---
+> ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(`mrg`.`t1`)
+59c59
+< ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1
+---
+> ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(`mrg`.`t1`)
+67c67
+< ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1
+---
+> ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(`mrg`.`t1`)
+75c75
+< ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1
+---
+> ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(`mrg`.`t1`)
+82c82
+< ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1
+---
+> ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(`mrg`.`t1`)
+91c91
+< ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1
+---
+> ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(`mrg`.`t2`)
+100c100
+< ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1
+---
+> ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(`mrg`.`t1`)
+107c107
+< ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1
+---
+> ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(`mrg`.`t1`)
+122c122
+< ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 COLLATE=latin1_general_cs
+---
+> ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 COLLATE=latin1_general_cs INSERT_METHOD=LAST UNION=(`mrg`.`t1`)
+130c130
+< ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=utf8
+---
+> ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=utf8 INSERT_METHOD=LAST UNION=(`mrg`.`t1`)
+138c138
+< ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci
+---
+> ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci INSERT_METHOD=LAST UNION=(`mrg`.`t1`)
+146c146
+< ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci
+---
+> ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci INSERT_METHOD=LAST UNION=(`mrg`.`t1`)
diff --git a/storage/myisammrg/mysql-test/storage_engine/alter_tablespace.rdiff b/storage/myisammrg/mysql-test/storage_engine/alter_tablespace.rdiff
new file mode 100644
index 00000000000..cfc821582ed
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/alter_tablespace.rdiff
@@ -0,0 +1,27 @@
+4,18c4,13
+< DROP TABLE t1;
+< CREATE TABLE t1 (a <INT_COLUMN>) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+< INSERT INTO t1 (a) VALUES (1),(2);
+< SELECT * FROM t1;
+< a
+< 1
+< 2
+< ALTER TABLE t1 DISCARD TABLESPACE;
+< SELECT * FROM t1;
+< ERROR HY000: Got error -1 from storage engine
+< ALTER TABLE t1 IMPORT TABLESPACE;
+< SELECT * FROM t1;
+< a
+< 1
+< 2
+---
+> ERROR HY000: 'test.t1' is not BASE TABLE
+> # ERROR: Statement ended with errno 1347, errname ER_WRONG_OBJECT (expected to succeed)
+> # ------------ UNEXPECTED RESULT ------------
+> # [ ALTER TABLE t1 DISCARD TABLESPACE ]
+> # The statement|command finished with ER_WRONG_OBJECT.
+> # Tablespace operations or the mix could be unsupported|malfunctioning, or the problem was caused by previous errors.
+> # You can change the engine code, or create an rdiff, or disable the test by adding it to disabled.def.
+> # Further in this test, the message might sometimes be suppressed; a part of the test might be skipped.
+> # Also, this problem may cause a chain effect (more errors of different kinds in the test).
+> # -------------------------------------------
diff --git a/storage/myisammrg/mysql-test/storage_engine/analyze_table.rdiff b/storage/myisammrg/mysql-test/storage_engine/analyze_table.rdiff
new file mode 100644
index 00000000000..139bcc00a81
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/analyze_table.rdiff
@@ -0,0 +1,22 @@
+8c8
+< test.t1 analyze status OK
+---
+> test.t1 analyze note The storage engine for the table doesn't support analyze
+12c12
+< test.t2 analyze status OK
+---
+> test.t2 analyze note The storage engine for the table doesn't support analyze
+17,18c17,18
+< test.t1 analyze status OK
+< test.t2 analyze status OK
+---
+> test.t1 analyze note The storage engine for the table doesn't support analyze
+> test.t2 analyze note The storage engine for the table doesn't support analyze
+24c24
+< test.t1 analyze status OK
+---
+> test.t1 analyze note The storage engine for the table doesn't support analyze
+28c28
+< test.t1 analyze status OK
+---
+> test.t1 analyze note The storage engine for the table doesn't support analyze
diff --git a/storage/myisammrg/mysql-test/storage_engine/autoincrement.rdiff b/storage/myisammrg/mysql-test/storage_engine/autoincrement.rdiff
new file mode 100644
index 00000000000..e9095aa3944
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/autoincrement.rdiff
@@ -0,0 +1,34 @@
+9c9
+< ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1
+---
+> ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(`mrg`.`t1`)
+55c55
+< t1 <STORAGE_ENGINE> # # # # # # # # 6 # # # # # # #
+---
+> t1 <STORAGE_ENGINE> # # # # # # # # 0 # # # # # # #
+62c62
+< t1 # # # # # # # # # 8 # # # # # # #
+---
+> t1 # # # # # # # # # 0 # # # # # # #
+81c81
+< t1 # # # # # # # # # 10 # # # # # # #
+---
+> t1 # # # # # # # # # 0 # # # # # # #
+85c85
+< t1 # # # # # # # # # 21 # # # # # # #
+---
+> t1 # # # # # # # # # 0 # # # # # # #
+106c106
+< t1 # # # # # # # # # 22 # # # # # # #
+---
+> t1 # # # # # # # # # 0 # # # # # # #
+128,129c128,129
+< 100 a
+< 101 b
+---
+> 1 a
+> 2 b
+132c132
+< 100
+---
+> 1
diff --git a/storage/myisammrg/mysql-test/storage_engine/cache_index.rdiff b/storage/myisammrg/mysql-test/storage_engine/cache_index.rdiff
new file mode 100644
index 00000000000..e10b22a8e66
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/cache_index.rdiff
@@ -0,0 +1,46 @@
+15,16c15,16
+< test.t1 assign_to_keycache status OK
+< test.t2 assign_to_keycache status OK
+---
+> test.t1 assign_to_keycache note The storage engine for the table doesn't support assign_to_keycache
+> test.t2 assign_to_keycache note The storage engine for the table doesn't support assign_to_keycache
+19,20c19,20
+< test.t1 preload_keys status OK
+< test.t2 preload_keys status OK
+---
+> test.t1 preload_keys note The storage engine for the table doesn't support preload_keys
+> test.t2 preload_keys note The storage engine for the table doesn't support preload_keys
+25,26c25,26
+< test.t1 preload_keys status OK
+< test.t2 preload_keys status OK
+---
+> test.t1 preload_keys note The storage engine for the table doesn't support preload_keys
+> test.t2 preload_keys note The storage engine for the table doesn't support preload_keys
+31c31
+< test.t1 preload_keys status OK
+---
+> test.t1 preload_keys note The storage engine for the table doesn't support preload_keys
+35c35
+< test.t1 assign_to_keycache status OK
+---
+> test.t1 assign_to_keycache note The storage engine for the table doesn't support assign_to_keycache
+39c39
+< test.t1 preload_keys status OK
+---
+> test.t1 preload_keys note The storage engine for the table doesn't support preload_keys
+50c50
+< test.t1 assign_to_keycache status OK
+---
+> test.t1 assign_to_keycache note The storage engine for the table doesn't support assign_to_keycache
+54c54
+< test.t1 preload_keys status OK
+---
+> test.t1 preload_keys note The storage engine for the table doesn't support preload_keys
+62c62
+< test.t1 assign_to_keycache status OK
+---
+> test.t1 assign_to_keycache note The storage engine for the table doesn't support assign_to_keycache
+66c66
+< test.t1 preload_keys status OK
+---
+> test.t1 preload_keys note The storage engine for the table doesn't support preload_keys
diff --git a/storage/myisammrg/mysql-test/storage_engine/char_indexes.rdiff b/storage/myisammrg/mysql-test/storage_engine/char_indexes.rdiff
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/char_indexes.rdiff
diff --git a/storage/myisammrg/mysql-test/storage_engine/checksum_table_live.rdiff b/storage/myisammrg/mysql-test/storage_engine/checksum_table_live.rdiff
new file mode 100644
index 00000000000..1710cc18fea
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/checksum_table_live.rdiff
@@ -0,0 +1,6 @@
+14,15c14,15
+< test.t1 4272806499
+< test.t2 0
+---
+> test.t1 NULL
+> test.t2 NULL
diff --git a/storage/myisammrg/mysql-test/storage_engine/cleanup_engine.inc b/storage/myisammrg/mysql-test/storage_engine/cleanup_engine.inc
new file mode 100644
index 00000000000..b8f84110c76
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/cleanup_engine.inc
@@ -0,0 +1,16 @@
+###########################################
+#
+# This is a stub of the include file cleanup_engine.inc which
+# should be placed in storage/<engine>/mysql-test/storage_engine folder.
+#
+################################
+#
+# Here you can add whatever is needed to cleanup
+# in case your define_engine.inc created any artefacts,
+# e.g. an additional schema and/or tables.
+--disable_query_log
+--disable_warnings
+DROP DATABASE IF EXISTS mrg;
+--enable_warnings
+--enable_query_log
+
diff --git a/storage/myisammrg/mysql-test/storage_engine/create_table.inc b/storage/myisammrg/mysql-test/storage_engine/create_table.inc
new file mode 100644
index 00000000000..c74460d42fb
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/create_table.inc
@@ -0,0 +1,208 @@
+##################################
+#
+# This include file will be used for all CREATE TABLE statements in the suite.
+# If you need to add additional steps or change the logic, copy the file
+# to storage/<engine>/mysql-test/storage_engine/ folder and modify it there.
+#
+##################
+#
+# Parameters:
+#
+# --let $create_definition = <column names, types, indexes) # optional, default a $int_col, b $char_col (based on defaults)
+# --let $table_name = <table name> # optional, default t1
+# --let $table_options = <table options> # optional, default based on define_engine.inc
+# --let $partition_options = <partitioning definition> # optional, default none
+# --let $as_select = <SELECT statement> # optional, default empty
+# --let $error_codes = <expected error codes, as in --error> # optional, default 0
+# --let $if_not_exists = [0|1] # optional, default 0 (1 adds IF NOT EXISTS clause)
+# --let $default_engine = [0|1] # optional, default 0 (with 1 will rely on default engine, no ENGINE=)
+# --let $temporary = [0|1] # optional, default 0 (1 adds TEMPORARY)
+# --let $disable_query_log = [0|1] # optional, default 0 (1 disables logging of CREATE)
+#
+# Usage examples:
+#
+# --source create_table.inc -- creates a default table
+#
+# --let $create_definition = a INT NOT NULL, b CHAR(1) PRIMARY KEY, INDEX(a)
+# --let $table_options = AUTO_INCREMENT = 100
+# --let $partition_options = PARTITION BY HASH(a) PARTITIONS 2
+# --let $as_select = SELECT 1, 'a'
+# --source create_table.inc
+#
+# Additionally, a test can define $extra_tbl_options. The difference with $table_options
+# is that its value is persistent and will be used until it is unset explicitly, or
+# until the test ends. The purpose of it is to allow one test to call another test,
+# when the called test does not know about specific options the calling test might require,
+# and thus cannot set them on per-create basis.
+
+--let $create_statement = CREATE
+
+if ($temporary)
+{
+ --let $create_statement = $create_statement TEMPORARY
+}
+
+--let $create_statement = $create_statement TABLE
+
+if ($if_not_exists)
+{
+ --let $create_statement = $create_statement IF NOT EXISTS
+}
+
+if (!$table_name)
+{
+ --let $table_name = t1
+}
+
+# Child statement is a statement that will create an underlying table.
+# From this point, it will deviate from the main statement, that's why
+# we start creating it here in parallel with the main one.
+# For underlying tables, we will create a table in mrg schema, e.g.
+# for table t1 the underlying table will be mrg.t1, etc.
+# Since we will only create one child here, it should be enough. If we want more,
+# we can always add a suffix, e.g. mrg.t1_child1, mrg.t1_child2, etc.
+
+--let $child_statement = $create_statement mrg.$table_name
+--let $create_statement = $create_statement $table_name
+
+if (!$create_definition)
+{
+ # If $create_definition is not defined, and AS SELECT is requested,
+ # we should not set $create_definition to the default value,
+ # because it might be inconsistent with the SELECT.
+ if (!$as_select)
+ {
+ --let $create_definition = a $int_col, b $char_col
+ }
+}
+
+if ($create_definition)
+{
+ --let $create_statement = $create_statement ($create_definition)
+ # Table definition for the underlying table should be the same
+ # as for the MERGE table
+ --let $child_statement = $child_statement ($create_definition)
+}
+
+# If $default_engine is set, we will rely on the default storage engine
+
+if (!$default_engine)
+{
+ --let $create_statement = $create_statement ENGINE=$storage_engine
+}
+# Engine for an underlying table differs
+--let $child_statement = $child_statement ENGINE=MyISAM
+
+# Save default table options, we will want to restore them later
+--let $default_tbl_opts_saved = $default_tbl_opts
+--let $default_tbl_opts = $default_tbl_opts UNION(mrg.$table_name) INSERT_METHOD=LAST
+
+# Default table options from define_engine.inc
+--let $create_statement = $create_statement $default_tbl_opts
+
+# The calling script could request additional table options
+if ($table_options)
+{
+ --let $create_statement = $create_statement $table_options
+ --let $child_statement = $child_statement $table_options
+}
+
+# The difference between $extra_tbl_opts and $table_options
+# is that its $extra_tbl_opts is persistent -- it will not be unset at the end of this file,
+# and will be used until it is unset explicitly by the calling test,
+# or until the test ends. The purpose of it is to allow one test to call another test,
+# when the called test does not know about specific options the calling test might require,
+# and thus cannot set them on per-create basis.
+
+if ($extra_tbl_opts)
+{
+ --let $create_statement = $create_statement $extra_tbl_opts
+ --let $child_statement = $child_statement $extra_tbl_opts
+}
+
+if ($as_select)
+{
+ --let $create_statement = $create_statement AS $as_select
+ --let $child_statement = $child_statement AS $as_select
+}
+
+if ($partition_options)
+{
+ --let $create_statement = $create_statement $partition_options
+ --let $child_statement = $child_statement $partition_options
+}
+
+# We now have the complete CREATE statement in $create_statement.
+# If your CREATE statement should be composed differently,
+# modify the logic above.
+
+#####################
+# Here you can add logic needed BEFORE the main table creation
+# (e.g. the table needs a base table, a reference table, etc.).
+# Surround it by --disable_query_log/--enable_query_log
+# if you don't want it to appear in the result output.
+#####################
+--disable_warnings
+--disable_query_log
+--disable_result_log
+eval DROP TABLE IF EXISTS mrg.$table_name;
+eval $child_statement;
+--enable_result_log
+--enable_query_log
+--enable_warnings
+
+if ($disable_query_log)
+{
+ --disable_query_log
+}
+
+--source obfuscate.inc
+
+eval $create_statement;
+--source strict_check_errors.inc
+
+# Make sure you don't add any statements between the main CREATE (above)
+# and saving mysql_errno and mysql_errname (below)
+# They are saved in case you want to add more logic after the main CREATE,
+# because we need the result code of the table creation.
+# Also, do not change $create_statement after it is executed!
+
+--let $my_errno = $mysql_errno
+--let $my_errname = $mysql_errname
+
+
+if ($disable_query_log)
+{
+ --enable_query_log
+}
+
+#####################
+# Here you can add logic needed AFTER the main table creation,
+# e.g. triggers creation.
+# Surround it by --disable_query_log/--enable_query_log
+# if you don't want it to appear in the result output.
+#####################
+
+
+# Unset the parameters, we don't want them to be accidentally reused later
+--let $create_definition =
+--let $table_name = t1
+--let $table_options =
+--let $partition_options =
+--let $as_select = 0
+--let $error_codes =
+--let $if_not_exists = 0
+--let $default_engine = 0
+--let $temporary = 0
+--let $disable_query_log = 0
+
+# Restore default table options now
+--let $default_tbl_opts = $default_tbl_opts_saved
+
+
+# Restore the error codes of the main statement
+--let $mysql_errno = $my_errno
+--let $mysql_errname = $my_errname
+# Make sure you don't add any SQL statements after restoring
+# mysql_errno and mysql_errname (above)
+
diff --git a/storage/myisammrg/mysql-test/storage_engine/create_table.rdiff b/storage/myisammrg/mysql-test/storage_engine/create_table.rdiff
new file mode 100644
index 00000000000..5d3578ad3cd
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/create_table.rdiff
@@ -0,0 +1,37 @@
+7c7
+< ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1
+---
+> ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(`mrg`.`t1`)
+16c16
+< ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1
+---
+> ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(`mrg`.`t1`)
+22c22
+< ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1
+---
+> ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(`mrg`.`t1`)
+27,36c27,35
+< SHOW CREATE TABLE t1;
+< Table Create Table
+< t1 CREATE TABLE `t1` (
+< `1` bigint(20) NOT NULL DEFAULT '0'
+< ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1
+< SELECT * FROM t1;
+< 1
+< 1
+< 2
+< DROP TABLE t1;
+---
+> ERROR HY000: 'test.t1' is not BASE TABLE
+> # ERROR: Statement ended with errno 1347, errname ER_WRONG_OBJECT (expected to succeed)
+> # ------------ UNEXPECTED RESULT ------------
+> # The statement|command finished with ER_WRONG_OBJECT.
+> # CREATE TABLE .. AS SELECT or the mix could be unsupported|malfunctioning, or the problem was caused by previous errors.
+> # You can change the engine code, or create an rdiff, or disable the test by adding it to disabled.def.
+> # Further in this test, the message might sometimes be suppressed; a part of the test might be skipped.
+> # Also, this problem may cause a chain effect (more errors of different kinds in the test).
+> # -------------------------------------------
+43c42
+< ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1
+---
+> ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(`mrg`.`t1`)
diff --git a/storage/myisammrg/mysql-test/storage_engine/define_engine.inc b/storage/myisammrg/mysql-test/storage_engine/define_engine.inc
new file mode 100644
index 00000000000..aabd1747737
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/define_engine.inc
@@ -0,0 +1,49 @@
+###########################################
+#
+# This is a template of the include file define_engine.inc which
+# should be placed in storage/<engine>/mysql-test/storage_engine folder.
+#
+################################
+#
+# The name of the engine under test must be defined in $ENGINE variable.
+# You can set it either here (uncomment and edit) or in your environment.
+#
+let $ENGINE = MRG_MYISAM;
+#
+################################
+#
+# The following three variables define specific options for columns and tables.
+# Normally there should be none needed, but for some engines it can be different.
+# If the engine requires specific column option for all or indexed columns,
+# set them inside the comment, e.g. /*!NOT NULL*/.
+# Do the same for table options if needed, e.g. /*!INSERT_METHOD=LAST*/
+
+let $default_col_opts = /*!*/;
+let $default_col_indexed_opts = /*!*/;
+let $default_tbl_opts = /*!*/;
+
+# INDEX, UNIQUE INDEX, PRIMARY KEY, special index type - choose the fist that the engine allows,
+# or set it to /*!*/ if none is supported
+
+let $default_index = /*!INDEX*/;
+
+# If the engine does not support the following types, replace them with the closest possible
+
+let $default_int_type = INT(11);
+let $default_char_type = CHAR(8);
+
+################################
+
+--disable_query_log
+--disable_result_log
+
+# Here you can place your custom MTR code which needs to be executed before each test,
+# e.g. creation of an additional schema or table, etc.
+# The cleanup part should be defined in cleanup_engine.inc
+--disable_warnings
+DROP DATABASE IF EXISTS mrg;
+--enable_warnings
+CREATE DATABASE mrg;
+
+--enable_query_log
+--enable_result_log
diff --git a/storage/myisammrg/mysql-test/storage_engine/disabled.def b/storage/myisammrg/mysql-test/storage_engine/disabled.def
new file mode 100644
index 00000000000..9f7569a2d24
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/disabled.def
@@ -0,0 +1,2 @@
+alter_table_online : MySQL:57657 (Temporary MERGE table with temporary underlying is broken by ALTER)
+
diff --git a/storage/myisammrg/mysql-test/storage_engine/foreign_keys.rdiff b/storage/myisammrg/mysql-test/storage_engine/foreign_keys.rdiff
new file mode 100644
index 00000000000..7362bd282a5
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/foreign_keys.rdiff
@@ -0,0 +1,138 @@
+15,17c15,16
+< KEY `a` (`a`),
+< CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`a`) REFERENCES `t1` (`a`)
+< ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1
+---
+> KEY `a` (`a`)
+> ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(`mrg`.`t2`)
+19c18,25
+< ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`a`) REFERENCES `t1` (`a`))
+---
+> # ERROR: Statement succeeded (expected results: ER_NO_REFERENCED_ROW_2)
+> # ------------ UNEXPECTED RESULT ------------
+> # The statement|command succeeded unexpectedly.
+> # Foreign keys or the mix could be unsupported|malfunctioning, or the problem was caused by previous errors.
+> # You can change the engine code, or create an rdiff, or disable the test by adding it to disabled.def.
+> # Further in this test, the message might sometimes be suppressed; a part of the test might be skipped.
+> # Also, this problem may cause a chain effect (more errors of different kinds in the test).
+> # -------------------------------------------
+23c29,36
+< ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`a`) REFERENCES `t1` (`a`))
+---
+> # ERROR: Statement succeeded (expected results: ER_NO_REFERENCED_ROW_2)
+> # ------------ UNEXPECTED RESULT ------------
+> # The statement|command succeeded unexpectedly.
+> # Foreign keys or the mix could be unsupported|malfunctioning, or the problem was caused by previous errors.
+> # You can change the engine code, or create an rdiff, or disable the test by adding it to disabled.def.
+> # Further in this test, the message might sometimes be suppressed; a part of the test might be skipped.
+> # Also, this problem may cause a chain effect (more errors of different kinds in the test).
+> # -------------------------------------------
+25c38
+< ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`a`) REFERENCES `t1` (`a`))
+---
+> # ERROR: Statement succeeded (expected results: ER_ROW_IS_REFERENCED_2)
+27c40,47
+< ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`a`) REFERENCES `t1` (`a`))
+---
+> # ERROR: Statement succeeded (expected results: ER_ROW_IS_REFERENCED_2)
+> # ------------ UNEXPECTED RESULT ------------
+> # The statement|command succeeded unexpectedly.
+> # Foreign keys or the mix could be unsupported|malfunctioning, or the problem was caused by previous errors.
+> # You can change the engine code, or create an rdiff, or disable the test by adding it to disabled.def.
+> # Further in this test, the message might sometimes be suppressed; a part of the test might be skipped.
+> # Also, this problem may cause a chain effect (more errors of different kinds in the test).
+> # -------------------------------------------
+32c52
+< 2 d
+---
+> 3 d
+35c55,56
+< 1 a
+---
+> 3 b
+> 3 b
+37c58,65
+< ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails
+---
+> # ERROR: Statement succeeded (expected results: ER_ROW_IS_REFERENCED)
+> # ------------ UNEXPECTED RESULT ------------
+> # The statement|command succeeded unexpectedly.
+> # Foreign keys or the mix could be unsupported|malfunctioning, or the problem was caused by previous errors.
+> # You can change the engine code, or create an rdiff, or disable the test by adding it to disabled.def.
+> # Further in this test, the message might sometimes be suppressed; a part of the test might be skipped.
+> # Also, this problem may cause a chain effect (more errors of different kinds in the test).
+> # -------------------------------------------
+49,51c77,78
+< KEY `a` (`a`),
+< CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`a`) REFERENCES `t1` (`a`) ON DELETE CASCADE ON UPDATE CASCADE
+< ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1
+---
+> KEY `a` (`a`)
+> ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(`mrg`.`t2`)
+53c80
+< ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`a`) REFERENCES `t1` (`a`) ON DELETE CASCADE ON UPDATE CASCADE)
+---
+> # ERROR: Statement succeeded (expected results: ER_NO_REFERENCED_ROW_2)
+54a82
+> ERROR 42S02: Table 'test.t1' doesn't exist
+56a85,92
+> ERROR 42S02: Table 'test.t1' doesn't exist
+> # ------------ UNEXPECTED RESULT ------------
+> # The statement|command finished with ER_NO_SUCH_TABLE.
+> # UPDATE or the mix could be unsupported|malfunctioning, or the problem was caused by previous errors.
+> # You can change the engine code, or create an rdiff, or disable the test by adding it to disabled.def.
+> # Further in this test, the message might sometimes be suppressed; a part of the test might be skipped.
+> # Also, this problem may cause a chain effect (more errors of different kinds in the test).
+> # -------------------------------------------
+59,64c95,104
+< 5 a
+< 5 a
+< 5 b
+< 5 c
+< 5 d
+< 5 e
+---
+> 1 a
+> 1 a
+> 2 b
+> 2 b
+> 3 a
+> 3 c
+> 3 c
+> 4 d
+> 4 d
+> 4 e
+65a106,113
+> ERROR 42S02: Table 'test.t1' doesn't exist
+> # ------------ UNEXPECTED RESULT ------------
+> # The statement|command finished with ER_NO_SUCH_TABLE.
+> # DELETE or the mix could be unsupported|malfunctioning, or the problem was caused by previous errors.
+> # You can change the engine code, or create an rdiff, or disable the test by adding it to disabled.def.
+> # Further in this test, the message might sometimes be suppressed; a part of the test might be skipped.
+> # Also, this problem may cause a chain effect (more errors of different kinds in the test).
+> # -------------------------------------------
+67a116,125
+> 1 a
+> 1 a
+> 2 b
+> 2 b
+> 3 a
+> 3 c
+> 3 c
+> 4 d
+> 4 d
+> 4 e
+69c127,135
+< ERROR 42000: Cannot truncate a table referenced in a foreign key constraint (`test`.`t2`, CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`a`) REFERENCES `test`.`t1` (`a`))
+---
+> ERROR 42S02: Table 'test.t1' doesn't exist
+> # ERROR: Statement ended with errno 1146, errname ER_NO_SUCH_TABLE (expected results: ER_TRUNCATE_ILLEGAL_FK)
+> # ------------ UNEXPECTED RESULT ------------
+> # The statement|command finished with ER_NO_SUCH_TABLE.
+> # Foreign keys or the mix could be unsupported|malfunctioning, or the problem was caused by previous errors.
+> # You can change the engine code, or create an rdiff, or disable the test by adding it to disabled.def.
+> # Further in this test, the message might sometimes be suppressed; a part of the test might be skipped.
+> # Also, this problem may cause a chain effect (more errors of different kinds in the test).
+> # -------------------------------------------
+71a138
+> ERROR 42S02: Unknown table 't1'
diff --git a/storage/myisammrg/mysql-test/storage_engine/fulltext_search.rdiff b/storage/myisammrg/mysql-test/storage_engine/fulltext_search.rdiff
new file mode 100644
index 00000000000..262370f01ed
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/fulltext_search.rdiff
@@ -0,0 +1,142 @@
+7,64c7,15
+< SHOW INDEXES IN t1;
+< Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment
+< t1 1 v1 1 v1 # # NULL NULL YES FULLTEXT
+< INSERT INTO t1 (v0,v1,v2) VALUES ('text1','Here is a list of recommended books on MariaDB and MySQL. We\'ve provided links to Amazon.com here for convenience, but they can be found at many other bookstores, both online and off.
+< If you want to have your favorite MySQL / MariaDB book listed here, please leave a comment.
+< For developers who want to code on MariaDB or MySQL
+< * Understanding MySQL Internals by Sasha Pachev, former MySQL developer at MySQL AB.
+< o This is the only book we know about that describes the internals of MariaDB / MySQL. A must have for anyone who wants to understand and develop on MariaDB!
+< o Not all topics are covered and some parts are slightly outdated, but still the best book on this topic.
+< * MySQL 5.1 Plugin Development by Sergei Golubchik and Andrew Hutchings
+< o A must read for anyone wanting to write a plugin for MariaDB, written by the Sergei who designed the plugin interface for MySQL and MariaDB!
+< For MariaDB / MySQL end users
+< * MariaDB Crash Course by Ben Forta
+< o First MariaDB book!
+< o For people who want to learn SQL and the basics of MariaDB.
+< o Now shipping. Purchase at Amazon.com or your favorite bookseller.
+< * SQL-99 Complete, Really by Peter Gulutzan & Trudy Pelzer.
+< o Everything you wanted to know about the SQL 99 standard. Excellent reference book!
+< o Free to read in the Knowledgebase!
+< * MySQL (4th Edition) by Paul DuBois
+< o The \'default\' book to read if you wont to learn to use MySQL / MariaDB.
+< * MySQL Cookbook by Paul DuBois
+< o A lot of examples of how to use MySQL. As with all of Paul\'s books, it\'s worth its weight in gold and even enjoyable reading for such a \'dry\' subject.
+< * High Performance MySQL, Second Edition, By Baron Schwartz, Peter Zaitsev, Vadim Tkachenko, Jeremy D. Zawodny, Arjen Lentz, Derek J. Balling, et al.
+< o \"High Performance MySQL is the definitive guide to building fast, reliable systems with MySQL. Written by noted experts with years of real-world experience building very large systems, this book covers every aspect of MySQL performance in detail, and focuses on robustness, security, and data integrity. Learn advanced techniques in depth so you can bring out MySQL\'s full power.\" (From the book description at O\'Reilly)
+<
+< * MySQL Admin Cookbook
+< o A quick step-by-step guide for MySQL users and database administrators to tackle real-world challenges with MySQL configuration and administration
+<
+< * MySQL 5.0 Certification Study Guide, By Paul DuBois, Stefan Hinz, Carsten Pedersen
+< o This is the official guide to cover the passing of the two MySQL Certification examinations. It is valid till version 5.0 of the server, so while it misses all the features available in MySQL 5.1 and greater (including MariaDB 5.1 and greater), it provides a good basic understanding of MySQL for the end-user. ',
+< 'There are several reasons why contributing code is one of the easiest and most rewarding ways to contribute to MariaDB:
+<
+< 1. We are very responsive toward reviews of submitted code and as soon as the review is done, the submitted code is merged into an existing MariaDB tree and made available to everyone, not just select customers.
+< 2. Code reviews are performed by the MariaDB core development team and the quality, detail, and timeliness of our reviews are better than you will find elsewhere.
+< 3. With MariaDB everyone has access to the latest code.
+< 4. If a patch is very safe and/or very useful we are willing to push it into the stable code (as long as it can\'t break any existing applications). We are willing to do this to ensure the freedom to add small, needed fixes on a stable release so users don\'t have to wait a year for something to be added which is critical to their business.
+< 5. If you are an active contributor, you can become a member of maria-captains, even if you aren\'t working for Monty Program Ab. All captains have the same rights as any other captain to accept and reject patches. Our development model is truly open for everyone.
+< The Contributing Code page details many of the actual steps involved in working with the MariaDB source code. It\'s important that you use the same tools and submit patches in the same way as other developers to keep development running smoothly.'
+< ), ('text2','test1','test2');
+< SELECT v0 FROM t1 WHERE MATCH(v1) AGAINST ('contributing' IN NATURAL LANGUAGE MODE);
+< v0
+< INSERT INTO t1 (v0,v1,v2) VALUES ('text3','test','test');
+< SELECT v0, MATCH(v1) AGAINST('contributing' IN NATURAL LANGUAGE MODE) AS rating FROM t1 WHERE MATCH(v1) AGAINST ('contributing' IN NATURAL LANGUAGE MODE);
+< v0 rating
+< INSERT INTO t1 (v0,v1,v2) VALUES ('text4','Contributing more...','...is a good idea'),('text5','test','test');
+< SELECT v0, MATCH(v1) AGAINST('contributing') AS rating FROM t1 WHERE MATCH(v1) AGAINST ('contributing');
+< v0 rating
+< text4 1.3705332279205322
+< SELECT v0 FROM t1 WHERE MATCH(v1,v2) AGAINST ('-test1 +critical +Cook*' IN BOOLEAN MODE);
+< v0
+< text1
+< SELECT v0 FROM t1 WHERE MATCH(v1,v2) AGAINST ('-patch +critical +Cook*' IN BOOLEAN MODE);
+< v0
+< SELECT v0, MATCH(v1) AGAINST('database' WITH QUERY EXPANSION) AS rating FROM t1 WHERE MATCH(v1) AGAINST ('database' WITH QUERY EXPANSION);
+< v0 rating
+< text1 178.11756896972656
+< DROP TABLE t1;
+---
+> ERROR HY000: The used table type doesn't support FULLTEXT indexes
+> # ERROR: Statement ended with errno 1214, errname ER_TABLE_CANT_HANDLE_FT (expected to succeed)
+> # ------------ UNEXPECTED RESULT ------------
+> # The statement|command finished with ER_TABLE_CANT_HANDLE_FT.
+> # FULLTEXT indexes or VARCHAR|TEXT data types or the mix could be unsupported|malfunctioning, or the problem was caused by previous errors.
+> # You can change the engine code, or create an rdiff, or disable the test by adding it to disabled.def.
+> # Further in this test, the message might sometimes be suppressed; a part of the test might be skipped.
+> # Also, this problem may cause a chain effect (more errors of different kinds in the test).
+> # -------------------------------------------
+71,132c22,30
+< SHOW INDEXES IN t1;
+< Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment
+< t1 1 v1 1 v1 # # NULL NULL YES FULLTEXT
+< t1 1 v1_v2 1 v1 # # NULL NULL YES FULLTEXT
+< t1 1 v1_v2 2 v2 # # NULL NULL YES FULLTEXT
+< INSERT INTO t1 (v0,v1,v2) VALUES ('text1','Here is a list of recommended books on MariaDB and MySQL. We\'ve provided links to Amazon.com here for convenience, but they can be found at many other bookstores, both online and off.
+< If you want to have your favorite MySQL / MariaDB book listed here, please leave a comment.
+< For developers who want to code on MariaDB or MySQL
+< * Understanding MySQL Internals by Sasha Pachev, former MySQL developer at MySQL AB.
+< o This is the only book we know about that describes the internals of MariaDB / MySQL. A must have for anyone who wants to understand and develop on MariaDB!
+< o Not all topics are covered and some parts are slightly outdated, but still the best book on this topic.
+< * MySQL 5.1 Plugin Development by Sergei Golubchik and Andrew Hutchings
+< o A must read for anyone wanting to write a plugin for MariaDB, written by the Sergei who designed the plugin interface for MySQL and MariaDB!
+< For MariaDB / MySQL end users
+< * MariaDB Crash Course by Ben Forta
+< o First MariaDB book!
+< o For people who want to learn SQL and the basics of MariaDB.
+< o Now shipping. Purchase at Amazon.com or your favorite bookseller.
+< * SQL-99 Complete, Really by Peter Gulutzan & Trudy Pelzer.
+< o Everything you wanted to know about the SQL 99 standard. Excellent reference book!
+< o Free to read in the Knowledgebase!
+< * MySQL (4th Edition) by Paul DuBois
+< o The \'default\' book to read if you wont to learn to use MySQL / MariaDB.
+< * MySQL Cookbook by Paul DuBois
+< o A lot of examples of how to use MySQL. As with all of Paul\'s books, it\'s worth its weight in gold and even enjoyable reading for such a \'dry\' subject.
+< * High Performance MySQL, Second Edition, By Baron Schwartz, Peter Zaitsev, Vadim Tkachenko, Jeremy D. Zawodny, Arjen Lentz, Derek J. Balling, et al.
+< o \"High Performance MySQL is the definitive guide to building fast, reliable systems with MySQL. Written by noted experts with years of real-world experience building very large systems, this book covers every aspect of MySQL performance in detail, and focuses on robustness, security, and data integrity. Learn advanced techniques in depth so you can bring out MySQL\'s full power.\" (From the book description at O\'Reilly)
+<
+< * MySQL Admin Cookbook
+< o A quick step-by-step guide for MySQL users and database administrators to tackle real-world challenges with MySQL configuration and administration
+<
+< * MySQL 5.0 Certification Study Guide, By Paul DuBois, Stefan Hinz, Carsten Pedersen
+< o This is the official guide to cover the passing of the two MySQL Certification examinations. It is valid till version 5.0 of the server, so while it misses all the features available in MySQL 5.1 and greater (including MariaDB 5.1 and greater), it provides a good basic understanding of MySQL for the end-user. ',
+< 'There are several reasons why contributing code is one of the easiest and most rewarding ways to contribute to MariaDB:
+<
+< 1. We are very responsive toward reviews of submitted code and as soon as the review is done, the submitted code is merged into an existing MariaDB tree and made available to everyone, not just select customers.
+< 2. Code reviews are performed by the MariaDB core development team and the quality, detail, and timeliness of our reviews are better than you will find elsewhere.
+< 3. With MariaDB everyone has access to the latest code.
+< 4. If a patch is very safe and/or very useful we are willing to push it into the stable code (as long as it can\'t break any existing applications). We are willing to do this to ensure the freedom to add small, needed fixes on a stable release so users don\'t have to wait a year for something to be added which is critical to their business.
+< 5. If you are an active contributor, you can become a member of maria-captains, even if you aren\'t working for Monty Program Ab. All captains have the same rights as any other captain to accept and reject patches. Our development model is truly open for everyone.
+< The Contributing Code page details many of the actual steps involved in working with the MariaDB source code. It\'s important that you use the same tools and submit patches in the same way as other developers to keep development running smoothly.'
+< ), ('text2','test1','test2');
+< SELECT v0 FROM t1 WHERE MATCH(v1,v2) AGAINST ('contributing' IN NATURAL LANGUAGE MODE);
+< v0
+< INSERT INTO t1 (v0,v1,v2) VALUES ('text3','test','test');
+< SELECT v0, MATCH(v1,v2) AGAINST('contributing' IN NATURAL LANGUAGE MODE) AS rating FROM t1 WHERE MATCH(v1,v2) AGAINST ('contributing' IN NATURAL LANGUAGE MODE);
+< v0 rating
+< text1 0.2809644043445587
+< INSERT INTO t1 (v0,v1,v2) VALUES ('text4','Contributing more...','...is a good idea'),('text5','test','test');
+< SELECT v0, MATCH(v1) AGAINST('contributing') AS rating FROM t1 WHERE MATCH(v1) AGAINST ('contributing');
+< v0 rating
+< text4 1.3705332279205322
+< SELECT v0 FROM t1 WHERE MATCH(v1,v2) AGAINST ('-test1 +critical +Cook*' IN BOOLEAN MODE);
+< v0
+< text1
+< SELECT v0 FROM t1 WHERE MATCH(v1,v2) AGAINST ('-patch +critical +Cook*' IN BOOLEAN MODE);
+< v0
+< SELECT v0, MATCH(v1,v2) AGAINST('database' WITH QUERY EXPANSION) AS rating FROM t1 WHERE MATCH(v1,v2) AGAINST ('database' WITH QUERY EXPANSION);
+< v0 rating
+< text1 190.56150817871094
+< text4 1.1758291721343994
+< DROP TABLE t1;
+---
+> ERROR HY000: The used table type doesn't support FULLTEXT indexes
+> # ERROR: Statement ended with errno 1214, errname ER_TABLE_CANT_HANDLE_FT (expected to succeed)
+> # ------------ UNEXPECTED RESULT ------------
+> # The statement|command finished with ER_TABLE_CANT_HANDLE_FT.
+> # FULLTEXT indexes or multiple keys or VARCHAR|TEXT data types or the mix could be unsupported|malfunctioning, or the problem was caused by previous errors.
+> # You can change the engine code, or create an rdiff, or disable the test by adding it to disabled.def.
+> # Further in this test, the message might sometimes be suppressed; a part of the test might be skipped.
+> # Also, this problem may cause a chain effect (more errors of different kinds in the test).
+> # -------------------------------------------
diff --git a/storage/myisammrg/mysql-test/storage_engine/handler.rdiff b/storage/myisammrg/mysql-test/storage_engine/handler.rdiff
new file mode 100644
index 00000000000..f0c01085ad9
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/handler.rdiff
@@ -0,0 +1,79 @@
+5,47c5,12
+< HANDLER t1 READ FIRST;
+< ERROR 42S02: Unknown table 't1' in HANDLER
+< HANDLER h1 READ FIRST;
+< a b
+< foobar 1000
+< HANDLER h1 READ NEXT;
+< a b
+< a 1
+< HANDLER h1 READ FIRST WHERE a < 'foo';
+< a b
+< a 1
+< HANDLER h1 READ NEXT;
+< a b
+< bar 200
+< HANDLER h1 READ NEXT;
+< a b
+< foo 100
+< HANDLER h1 READ NEXT;
+< a b
+< HANDLER h1 READ FIRST LIMIT 2;
+< a b
+< foobar 1000
+< a 1
+< HANDLER h1 READ NEXT;
+< a b
+< bar 200
+< HANDLER h1 READ NEXT WHERE b>500 LIMIT 2;
+< a b
+< HANDLER t1 OPEN;
+< HANDLER h1 READ FIRST WHERE b>500 LIMIT 5;
+< a b
+< foobar 1000
+< HANDLER t1 READ NEXT;
+< a b
+< foobar 1000
+< HANDLER h1 READ NEXT WHERE b<100;
+< a b
+< HANDLER t1 CLOSE;
+< HANDLER h1 READ FIRST;
+< a b
+< foobar 1000
+< HANDLER t1 CLOSE;
+< ERROR 42S02: Unknown table 't1' in HANDLER
+---
+> ERROR HY000: Table storage engine for 'h1' doesn't have this option
+> # ------------ UNEXPECTED RESULT ------------
+> # The statement|command finished with ER_ILLEGAL_HA.
+> # Functionality or the syntax or the mix could be unsupported.
+> # You can change the engine code, or create an rdiff, or disable the test by adding it to disabled.def.
+> # Further in this test, the message might sometimes be suppressed; a part of the test might be skipped.
+> # Also, this problem may cause a chain effect (more errors of different kinds in the test).
+> # -------------------------------------------
+54,76c19
+< HANDLER h1 READ a = (100);
+< a b
+< 100 f
+< HANDLER h1 READ a <= (100) WHERE b < 'f';
+< a b
+< 2 c
+< HANDLER h1 READ a > (2) WHERE b IS NOT NULL LIMIT 2;
+< a b
+< 100 f
+< 101 b
+< HANDLER h1 READ a FIRST;
+< a b
+< 1 a
+< HANDLER h1 READ a LAST;
+< a b
+< 200 b
+< HANDLER h1 READ a PREV;
+< a b
+< 101 b
+< HANDLER h1 READ a NEXT;
+< a b
+< 200 b
+< HANDLER h1 CLOSE;
+---
+> ERROR HY000: Table storage engine for 'h1' doesn't have this option
diff --git a/storage/myisammrg/mysql-test/storage_engine/index.rdiff b/storage/myisammrg/mysql-test/storage_engine/index.rdiff
new file mode 100644
index 00000000000..6e6f18e39bc
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/index.rdiff
@@ -0,0 +1,6 @@
+64,66c64
+< ERROR 23000: Duplicate entry '1' for key 'a'
+< # Statement ended with one of expected results (ER_DUP_ENTRY,ER_DUP_KEY).
+< # If you got a difference in error message, just add it to rdiff file
+---
+> # ERROR: Statement succeeded (expected results: ER_DUP_ENTRY,ER_DUP_KEY)
diff --git a/storage/myisammrg/mysql-test/storage_engine/index_enable_disable.rdiff b/storage/myisammrg/mysql-test/storage_engine/index_enable_disable.rdiff
new file mode 100644
index 00000000000..8913f17a2a6
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/index_enable_disable.rdiff
@@ -0,0 +1,17 @@
+13a14,15
+> Warnings:
+> Note 1031 Table storage engine for 't1' doesn't have this option
+16c18
+< t1 1 a 1 a # # NULL NULL YES BTREE disabled
+---
+> t1 1 a 1 a # # NULL NULL YES BTREE
+19c21
+< 1 SIMPLE t1 ALL NULL NULL NULL NULL 19 Using filesort
+---
+> 1 SIMPLE t1 index NULL a 5 NULL 19 Using index
+22a25,26
+> Warnings:
+> Note 1031 Table storage engine for 't1' doesn't have this option
+34a39,40
+> Warnings:
+> Note 1031 Table storage engine for 't1' doesn't have this option
diff --git a/storage/myisammrg/mysql-test/storage_engine/index_type_btree.rdiff b/storage/myisammrg/mysql-test/storage_engine/index_type_btree.rdiff
new file mode 100644
index 00000000000..6e6f18e39bc
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/index_type_btree.rdiff
@@ -0,0 +1,6 @@
+64,66c64
+< ERROR 23000: Duplicate entry '1' for key 'a'
+< # Statement ended with one of expected results (ER_DUP_ENTRY,ER_DUP_KEY).
+< # If you got a difference in error message, just add it to rdiff file
+---
+> # ERROR: Statement succeeded (expected results: ER_DUP_ENTRY,ER_DUP_KEY)
diff --git a/storage/myisammrg/mysql-test/storage_engine/index_type_hash.rdiff b/storage/myisammrg/mysql-test/storage_engine/index_type_hash.rdiff
new file mode 100644
index 00000000000..1b57afe5b64
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/index_type_hash.rdiff
@@ -0,0 +1,34 @@
+7c7
+< t1 1 a 1 a # # NULL NULL # HASH
+---
+> t1 1 a 1 a # # NULL NULL # BTREE
+15,16c15,16
+< t1 1 a_b 1 a # # NULL NULL # HASH a_b index
+< t1 1 a_b 2 b # # NULL NULL # HASH a_b index
+---
+> t1 1 a_b 1 a # # NULL NULL # BTREE a_b index
+> t1 1 a_b 2 b # # NULL NULL # BTREE a_b index
+25,26c25,26
+< t1 1 a 1 a # # NULL NULL # HASH
+< t1 1 b 1 b # # NULL NULL # HASH
+---
+> t1 1 a 1 a # # NULL NULL # BTREE
+> t1 1 b 1 b # # NULL NULL # BTREE
+34c34
+< t1 0 a 1 a # # NULL NULL # HASH
+---
+> t1 0 a 1 a # # NULL NULL # BTREE
+46c46
+< t1 1 a 1 a # # NULL NULL # HASH simple index on a
+---
+> t1 1 a 1 a # # NULL NULL # BTREE simple index on a
+55c55
+< t1 0 a 1 a # # NULL NULL # HASH
+---
+> t1 0 a 1 a # # NULL NULL # BTREE
+64,66c64
+< ERROR 23000: Duplicate entry '1' for key 'a'
+< # Statement ended with one of expected results (ER_DUP_ENTRY,ER_DUP_KEY).
+< # If you got a difference in error message, just add it to rdiff file
+---
+> # ERROR: Statement succeeded (expected results: ER_DUP_ENTRY,ER_DUP_KEY)
diff --git a/storage/myisammrg/mysql-test/storage_engine/insert_delayed.rdiff b/storage/myisammrg/mysql-test/storage_engine/insert_delayed.rdiff
new file mode 100644
index 00000000000..e0d0eefabe4
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/insert_delayed.rdiff
@@ -0,0 +1,14 @@
+7a8,15
+> ERROR HY000: DELAYED option not supported for table 't1'
+> # ------------ UNEXPECTED RESULT ------------
+> # The statement|command finished with ER_DELAYED_NOT_SUPPORTED.
+> # INSERT DELAYED or the mix could be unsupported|malfunctioning, or the problem was caused by previous errors.
+> # You can change the engine code, or create an rdiff, or disable the test by adding it to disabled.def.
+> # Further in this test, the message might sometimes be suppressed; a part of the test might be skipped.
+> # Also, this problem may cause a chain effect (more errors of different kinds in the test).
+> # -------------------------------------------
+8a17
+> ERROR HY000: DELAYED option not supported for table 't1'
+23,24d31
+< 3 c
+< 4 d
diff --git a/storage/myisammrg/mysql-test/storage_engine/lock.rdiff b/storage/myisammrg/mysql-test/storage_engine/lock.rdiff
new file mode 100644
index 00000000000..d035648551a
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/lock.rdiff
@@ -0,0 +1,62 @@
+44a45,46
+> ERROR HY000: Table 't1' was not locked with LOCK TABLES
+> # ERROR: Statement ended with errno 1100, errname ER_TABLE_NOT_LOCKED (expected to succeed)
+45a48,49
+> ERROR HY000: Table 't2' was not locked with LOCK TABLES
+> # ERROR: Statement ended with errno 1100, errname ER_TABLE_NOT_LOCKED (expected to succeed)
+46a51
+> ERROR HY000: Table 't2' was not locked with LOCK TABLES
+47a53
+> ERROR HY000: Table 't2' was not locked with LOCK TABLES
+48a55
+> ERROR 42S02: Table 'test.t1' doesn't exist
+49a57
+> ERROR 42S02: Table 'test.t1' doesn't exist
+50a59
+> ERROR 42S02: Table 'test.t1' doesn't exist
+52a62
+> ERROR 42S02: Table 'test.t1' doesn't exist
+54c64,65
+< ERROR HY000: Table 't1' was not locked with LOCK TABLES
+---
+> ERROR 42S02: Table 'test.t1' doesn't exist
+> # ERROR: Statement ended with errno 1146, errname ER_NO_SUCH_TABLE (expected results: ER_TABLE_NOT_LOCKED)
+56a68
+> ERROR 42S02: Table 'test.t1' doesn't exist
+57a70
+> ERROR 42S02: Table 'test.t1' doesn't exist
+59c72,73
+< ERROR HY000: Table 't2' was not locked with LOCK TABLES
+---
+> ERROR 42S02: Unknown table 't1,t2'
+> # ERROR: Statement ended with errno 1051, errname ER_BAD_TABLE_ERROR (expected results: ER_TABLE_NOT_LOCKED)
+61a76
+> ERROR 42S02: Unknown table 't1,t2'
+67a83,84
+> ERROR HY000: Table 't1' was not locked with LOCK TABLES
+> # ERROR: Statement ended with errno 1100, errname ER_TABLE_NOT_LOCKED (expected to succeed)
+68a86,87
+> ERROR HY000: Table 't2' was not locked with LOCK TABLES
+> # ERROR: Statement ended with errno 1100, errname ER_TABLE_NOT_LOCKED (expected to succeed)
+69a89,90
+> ERROR HY000: Table 't3' was not locked with LOCK TABLES
+> # ERROR: Statement ended with errno 1100, errname ER_TABLE_NOT_LOCKED (expected to succeed)
+70a92
+> ERROR 42S02: Table 'test.t1' doesn't exist
+71a94,103
+> ERROR 42S02: Table 'test.t2' doesn't exist
+> # ERROR: Statement ended with errno 1146, errname ER_NO_SUCH_TABLE (expected to succeed)
+> # ------------ UNEXPECTED RESULT ------------
+> # [ ALTER TABLE t2 ADD COLUMN c2 INT(11) /*!*/ /*Custom column options*/ ]
+> # The statement|command finished with ER_NO_SUCH_TABLE.
+> # ALTER TABLE or the mix could be unsupported|malfunctioning, or the problem was caused by previous errors.
+> # You can change the engine code, or create an rdiff, or disable the test by adding it to disabled.def.
+> # Further in this test, the message might sometimes be suppressed; a part of the test might be skipped.
+> # Also, this problem may cause a chain effect (more errors of different kinds in the test).
+> # -------------------------------------------
+72a105
+> ERROR 42S02: Unknown table 't1,t2,t3'
+109c142
+< a b
+---
+> ERROR HY000: Unable to open underlying table which is differently defined or of non-MyISAM type or doesn't exist
diff --git a/storage/myisammrg/mysql-test/storage_engine/optimize_table.rdiff b/storage/myisammrg/mysql-test/storage_engine/optimize_table.rdiff
new file mode 100644
index 00000000000..f74c49cedea
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/optimize_table.rdiff
@@ -0,0 +1,24 @@
+8c8
+< test.t1 optimize status OK
+---
+> test.t1 optimize note The storage engine for the table doesn't support optimize
+12c12
+< test.t2 optimize status OK
+---
+> test.t2 optimize note The storage engine for the table doesn't support optimize
+17,18c17,18
+< test.t1 optimize status OK
+< test.t2 optimize status OK
+---
+> test.t1 optimize note The storage engine for the table doesn't support optimize
+> test.t2 optimize note The storage engine for the table doesn't support optimize
+21,22c21,22
+< test.t1 optimize status Table is already up to date
+< test.t2 optimize status Table is already up to date
+---
+> test.t1 optimize note The storage engine for the table doesn't support optimize
+> test.t2 optimize note The storage engine for the table doesn't support optimize
+28c28
+< test.t1 optimize status OK
+---
+> test.t1 optimize note The storage engine for the table doesn't support optimize
diff --git a/storage/myisammrg/mysql-test/storage_engine/parts/alter_table.rdiff b/storage/myisammrg/mysql-test/storage_engine/parts/alter_table.rdiff
new file mode 100644
index 00000000000..a2cb0c1dcb1
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/parts/alter_table.rdiff
@@ -0,0 +1,63 @@
+3,36c3,12
+< INSERT INTO t1 (a) VALUES (1),(2),(2),(3),(4);
+< ALTER TABLE t1 ADD PARTITION PARTITIONS 2;
+< EXPLAIN PARTiTIONS SELECT a FROM t1 WHERE a = 3;
+< id select_type table partitions type possible_keys key key_len ref rows Extra
+< 1 SIMPLE t1 p3 # # # # # # #
+< ALTER TABLE t1 COALESCE PARTITION 1;
+< EXPLAIN PARTiTIONS SELECT a FROM t1 WHERE a = 3;
+< id select_type table partitions type possible_keys key key_len ref rows Extra
+< 1 SIMPLE t1 p0 # # # # # # #
+< ALTER TABLE t1 REORGANIZE PARTITION;
+< EXPLAIN PARTiTIONS SELECT a FROM t1 WHERE a = 2;
+< id select_type table partitions type possible_keys key key_len ref rows Extra
+< 1 SIMPLE t1 p0 # # # # # # #
+< ALTER TABLE t1 REBUILD PARTITION p0;
+< EXPLAIN PARTiTIONS SELECT a FROM t1;
+< id select_type table partitions type possible_keys key key_len ref rows Extra
+< 1 SIMPLE t1 p0 # # # # # # #
+< ALTER TABLE t1 REMOVE PARTITIONING;
+< EXPLAIN PARTiTIONS SELECT a FROM t1;
+< id select_type table partitions type possible_keys key key_len ref rows Extra
+< 1 SIMPLE t1 NULL # # # # # # #
+< ALTER TABLE t1 PARTITION BY LIST(a) (PARTITION p0 VALUES IN (1,2,3), PARTITION p1 VALUES IN (101,102));
+< ERROR HY000: Table has no partition for value 4
+< ALTER TABLE t1 PARTITION BY LIST(a) (PARTITION p0 VALUES IN (1,2,3,4), PARTITION p1 VALUES IN (101,102));
+< INSERT INTO t1 (a) VALUES (50);
+< ERROR HY000: Table has no partition for value 50
+< ALTER TABLE t1 ADD PARTITION (PARTITION p2 VALUES IN (50,51));
+< INSERT INTO t1 (a) VALUES (50);
+< ALTER TABLE t1 DROP PARTITION p1;
+< ALTER TABLE t1 REORGANIZE PARTITION p0, p2 INTO (PARTITION p0 VALUES IN (1,2,3), PARTITION p1 VALUES IN (4), PARTITION p2 VALUES IN (50,51), PARTITION p3 VALUES IN (101,102));
+< EXPLAIN PARTiTIONS SELECT a FROM t1 WHERE a = 2;
+< id select_type table partitions type possible_keys key key_len ref rows Extra
+< 1 SIMPLE t1 p0 # # # # # # #
+< DROP TABLE t1;
+---
+> ERROR HY000: Engine cannot be used in partitioned tables
+> # ERROR: Statement ended with errno 1572, errname ER_PARTITION_MERGE_ERROR (expected to succeed)
+> # ------------ UNEXPECTED RESULT ------------
+> # [ CREATE TABLE t1 (a INT(11) /*!*/ /*Custom column options*/) ENGINE=MRG_MYISAM /*!*/ /*Custom table options*/ UNION(mrg.t1) INSERT_METHOD=LAST PARTITION BY HASH(a) PARTITIONS 2 ]
+> # The statement|command finished with ER_PARTITION_MERGE_ERROR.
+> # Partitions or the mix could be unsupported|malfunctioning, or the problem was caused by previous errors.
+> # You can change the engine code, or create an rdiff, or disable the test by adding it to disabled.def.
+> # Further in this test, the message might sometimes be suppressed; a part of the test might be skipped.
+> # Also, this problem may cause a chain effect (more errors of different kinds in the test).
+> # -------------------------------------------
+41,42c17,29
+< ALTER TABLE t1 DROP PARTITION abc;
+< DROP TABLE t1;
+---
+> ERROR HY000: Engine cannot be used in partitioned tables
+> # ERROR: Statement ended with errno 1572, errname ER_PARTITION_MERGE_ERROR (expected to succeed)
+> # ------------ UNEXPECTED RESULT ------------
+> # [ CREATE TABLE t1 (a INT(11) /*!*/ /*Custom column options*/, b INT(11) /*!*/ /*Custom column options*/) ENGINE=MRG_MYISAM /*!*/ /*Custom table options*/ UNION(mrg.t1) INSERT_METHOD=LAST PARTITION BY LIST(a) SUBPARTITION by HASH(b) (
+> PARTITION abc VALUES IN (1,2,3),
+> PARTITION def VALUES IN (100,101,102)
+> ) ]
+> # The statement|command finished with ER_PARTITION_MERGE_ERROR.
+> # Partitions or subpartitions or the mix could be unsupported|malfunctioning, or the problem was caused by previous errors.
+> # You can change the engine code, or create an rdiff, or disable the test by adding it to disabled.def.
+> # Further in this test, the message might sometimes be suppressed; a part of the test might be skipped.
+> # Also, this problem may cause a chain effect (more errors of different kinds in the test).
+> # -------------------------------------------
diff --git a/storage/myisammrg/mysql-test/storage_engine/parts/analyze_table.rdiff b/storage/myisammrg/mysql-test/storage_engine/parts/analyze_table.rdiff
new file mode 100644
index 00000000000..ce29f3dcf52
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/parts/analyze_table.rdiff
@@ -0,0 +1,83 @@
+3,18c3,12
+< INSERT INTO t1 (a,b) VALUES (1,'a'),(2,'b'),(3,'c'),(2,'d'),(4,'e'),(100,'f'),(101,'g');
+< CREATE TABLE t2 (a <INT_COLUMN>, b <CHAR_COLUMN>) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+< INSERT INTO t2 (a,b) SELECT a,b FROM t1;
+< INSERT INTO t1 (a,b) VALUES (3,'c');
+< ALTER TABLE t1 ANALYZE PARTITION p0;
+< Table Op Msg_type Msg_text
+< test.t1 analyze status OK
+< INSERT INTO t2 (a,b) VALUES (4,'d'), (1000,'e');
+< ALTER TABLE t1 ANALYZE PARTITION LOCAL ALL;
+< Table Op Msg_type Msg_text
+< test.t1 analyze status OK
+< INSERT INTO t1 (a,b) VALUES (5,'f'),(50,'g');
+< ALTER TABLE t1 ANALYZE PARTITION NO_WRITE_TO_BINLOG p1,p0;
+< Table Op Msg_type Msg_text
+< test.t1 analyze status OK
+< DROP TABLE t1, t2;
+---
+> ERROR HY000: Engine cannot be used in partitioned tables
+> # ERROR: Statement ended with errno 1572, errname ER_PARTITION_MERGE_ERROR (expected to succeed)
+> # ------------ UNEXPECTED RESULT ------------
+> # [ CREATE TABLE t1 (a INT(11) /*!*/ /*Custom column options*/, b CHAR(8) /*!*/ /*Custom column options*/) ENGINE=MRG_MYISAM /*!*/ /*Custom table options*/ UNION(mrg.t1) INSERT_METHOD=LAST PARTITION BY HASH(a) PARTITIONS 2 ]
+> # The statement|command finished with ER_PARTITION_MERGE_ERROR.
+> # Partitions or the mix could be unsupported|malfunctioning, or the problem was caused by previous errors.
+> # You can change the engine code, or create an rdiff, or disable the test by adding it to disabled.def.
+> # Further in this test, the message might sometimes be suppressed; a part of the test might be skipped.
+> # Also, this problem may cause a chain effect (more errors of different kinds in the test).
+> # -------------------------------------------
+20a15,16
+> ERROR HY000: Engine cannot be used in partitioned tables
+> # ERROR: Statement ended with errno 1572, errname ER_PARTITION_MERGE_ERROR (expected to succeed)
+21a18
+> ERROR 42S02: Table 'test.t1' doesn't exist
+22a20,21
+> ERROR HY000: Engine cannot be used in partitioned tables
+> # ERROR: Statement ended with errno 1572, errname ER_PARTITION_MERGE_ERROR (expected to succeed)
+23a23
+> ERROR 42S02: Table 'test.t1' doesn't exist
+26c26,27
+< test.t1 analyze status OK
+---
+> test.t1 analyze Error Table 'test.t1' doesn't exist
+> test.t1 analyze status Operation failed
+27a29
+> ERROR 42S02: Table 'test.t2' doesn't exist
+30c32,33
+< test.t2 analyze status OK
+---
+> test.t2 analyze Error Table 'test.t2' doesn't exist
+> test.t2 analyze status Operation failed
+31a35
+> ERROR 42S02: Table 'test.t1' doesn't exist
+32a37
+> ERROR 42S02: Table 'test.t2' doesn't exist
+35,36c40,43
+< test.t1 analyze status OK
+< test.t2 analyze status OK
+---
+> test.t1 analyze Error Table 'test.t1' doesn't exist
+> test.t1 analyze status Operation failed
+> test.t2 analyze Error Table 'test.t2' doesn't exist
+> test.t2 analyze status Operation failed
+37a45
+> ERROR 42S02: Unknown table 't1,t2'
+38a47,48
+> ERROR HY000: Engine cannot be used in partitioned tables
+> # ERROR: Statement ended with errno 1572, errname ER_PARTITION_MERGE_ERROR (expected to succeed)
+39a50
+> ERROR 42S02: Table 'test.t1' doesn't exist
+42c53,54
+< test.t1 analyze status OK
+---
+> test.t1 analyze Error Table 'test.t1' doesn't exist
+> test.t1 analyze status Operation failed
+43a56
+> ERROR 42S02: Table 'test.t1' doesn't exist
+46c59,60
+< test.t1 analyze status OK
+---
+> test.t1 analyze Error Table 'test.t1' doesn't exist
+> test.t1 analyze status Operation failed
+47a62
+> ERROR 42S02: Unknown table 't1'
diff --git a/storage/myisammrg/mysql-test/storage_engine/parts/check_table.rdiff b/storage/myisammrg/mysql-test/storage_engine/parts/check_table.rdiff
new file mode 100644
index 00000000000..3f3db85a23e
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/parts/check_table.rdiff
@@ -0,0 +1,172 @@
+3,36c3,12
+< INSERT INTO t1 (a,b) VALUES (1,'a'),(2,'b'),(3,'c'),(2,'d'),(4,'e'),(100,'f'),(101,'g');
+< CREATE TABLE t2 (a <INT_COLUMN>, b <CHAR_COLUMN>) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS> PARTITION BY RANGE(a) (
+< PARTITION p0 VALUES LESS THAN (100),
+< PARTITION p1 VALUES LESS THAN MAXVALUE
+< );
+< INSERT INTO t2 (a,b) SELECT a, b FROM t1;
+< ALTER TABLE t1 CHECK PARTITION p0;
+< Table Op Msg_type Msg_text
+< test.t1 check status OK
+< INSERT INTO t1 (a,b) VALUES (3,'c');
+< ALTER TABLE t1 CHECK PARTITION p0, p1 FOR UPGRADE;
+< Table Op Msg_type Msg_text
+< test.t1 check status OK
+< INSERT INTO t2 (a,b) VALUES (10000,'e');
+< ALTER TABLE t2 CHECK PARTITION p0 QUICK;
+< Table Op Msg_type Msg_text
+< test.t2 check status OK
+< INSERT INTO t1 (a,b) VALUES (6,'f');
+< ALTER TABLE t1 CHECK PARTITION p1 FAST;
+< Table Op Msg_type Msg_text
+< test.t1 check status OK
+< INSERT INTO t2 (a,b) VALUES (8,'h');
+< ALTER TABLE t2 CHECK PARTITION p1 MEDIUM;
+< Table Op Msg_type Msg_text
+< test.t2 check status OK
+< INSERT INTO t1 (a,b) VALUES (9,'i');
+< ALTER TABLE t1 CHECK PARTITION ALL EXTENDED;
+< Table Op Msg_type Msg_text
+< test.t1 check status OK
+< INSERT INTO t1 (a,b) VALUES (11,'k');
+< ALTER TABLE t1 CHECK PARTITION p0 CHANGED;
+< Table Op Msg_type Msg_text
+< test.t1 check status OK
+< DROP TABLE t1, t2;
+---
+> ERROR HY000: Engine cannot be used in partitioned tables
+> # ERROR: Statement ended with errno 1572, errname ER_PARTITION_MERGE_ERROR (expected to succeed)
+> # ------------ UNEXPECTED RESULT ------------
+> # [ CREATE TABLE t1 (a INT(11) /*!*/ /*Custom column options*/, b CHAR(8) /*!*/ /*Custom column options*/) ENGINE=MRG_MYISAM /*!*/ /*Custom table options*/ UNION(mrg.t1) INSERT_METHOD=LAST PARTITION BY HASH(a) PARTITIONS 2 ]
+> # The statement|command finished with ER_PARTITION_MERGE_ERROR.
+> # Partitions or the mix could be unsupported|malfunctioning, or the problem was caused by previous errors.
+> # You can change the engine code, or create an rdiff, or disable the test by adding it to disabled.def.
+> # Further in this test, the message might sometimes be suppressed; a part of the test might be skipped.
+> # Also, this problem may cause a chain effect (more errors of different kinds in the test).
+> # -------------------------------------------
+38a15,16
+> ERROR HY000: Engine cannot be used in partitioned tables
+> # ERROR: Statement ended with errno 1572, errname ER_PARTITION_MERGE_ERROR (expected to succeed)
+39a18
+> ERROR 42S02: Table 'test.t1' doesn't exist
+40a20,21
+> ERROR HY000: Engine cannot be used in partitioned tables
+> # ERROR: Statement ended with errno 1572, errname ER_PARTITION_MERGE_ERROR (expected to succeed)
+43c24,25
+< test.t1 check status OK
+---
+> test.t1 check Error Table 'test.t1' doesn't exist
+> test.t1 check status Operation failed
+44a27
+> ERROR 42S02: Table 'test.t1' doesn't exist
+45a29
+> ERROR 42S02: Table 'test.t2' doesn't exist
+48,49c32,35
+< test.t1 check status OK
+< test.t2 check status OK
+---
+> test.t1 check Error Table 'test.t1' doesn't exist
+> test.t1 check status Operation failed
+> test.t2 check Error Table 'test.t2' doesn't exist
+> test.t2 check status Operation failed
+50a37
+> ERROR 42S02: Table 'test.t2' doesn't exist
+53c40,41
+< test.t2 check status OK
+---
+> test.t2 check Error Table 'test.t2' doesn't exist
+> test.t2 check status Operation failed
+54a43
+> ERROR 42S02: Table 'test.t1' doesn't exist
+57c46,47
+< test.t1 check status OK
+---
+> test.t1 check Error Table 'test.t1' doesn't exist
+> test.t1 check status Operation failed
+58a49
+> ERROR 42S02: Table 'test.t1' doesn't exist
+59a51
+> ERROR 42S02: Table 'test.t2' doesn't exist
+62,63c54,57
+< test.t2 check status OK
+< test.t1 check status OK
+---
+> test.t2 check Error Table 'test.t2' doesn't exist
+> test.t2 check status Operation failed
+> test.t1 check Error Table 'test.t1' doesn't exist
+> test.t1 check status Operation failed
+64a59
+> ERROR 42S02: Table 'test.t1' doesn't exist
+65a61
+> ERROR 42S02: Table 'test.t2' doesn't exist
+68,69c64,67
+< test.t1 check status OK
+< test.t2 check status OK
+---
+> test.t1 check Error Table 'test.t1' doesn't exist
+> test.t1 check status Operation failed
+> test.t2 check Error Table 'test.t2' doesn't exist
+> test.t2 check status Operation failed
+70a69
+> ERROR 42S02: Table 'test.t1' doesn't exist
+73c72,73
+< test.t1 check status OK
+---
+> test.t1 check Error Table 'test.t1' doesn't exist
+> test.t1 check status Operation failed
+74a75
+> ERROR 42S02: Unknown table 't1,t2'
+75a77,78
+> ERROR HY000: Engine cannot be used in partitioned tables
+> # ERROR: Statement ended with errno 1572, errname ER_PARTITION_MERGE_ERROR (expected to succeed)
+76a80
+> ERROR 42S02: Table 'test.t1' doesn't exist
+79c83,84
+< test.t1 check status OK
+---
+> test.t1 check Error Table 'test.t1' doesn't exist
+> test.t1 check status Operation failed
+80a86
+> ERROR 42S02: Table 'test.t1' doesn't exist
+83c89,90
+< test.t1 check status OK
+---
+> test.t1 check Error Table 'test.t1' doesn't exist
+> test.t1 check status Operation failed
+84a92
+> ERROR 42S02: Table 'test.t1' doesn't exist
+87c95,96
+< test.t1 check status OK
+---
+> test.t1 check Error Table 'test.t1' doesn't exist
+> test.t1 check status Operation failed
+88a98
+> ERROR 42S02: Table 'test.t1' doesn't exist
+91c101,102
+< test.t1 check status OK
+---
+> test.t1 check Error Table 'test.t1' doesn't exist
+> test.t1 check status Operation failed
+92a104
+> ERROR 42S02: Table 'test.t1' doesn't exist
+95c107,108
+< test.t1 check status OK
+---
+> test.t1 check Error Table 'test.t1' doesn't exist
+> test.t1 check status Operation failed
+96a110
+> ERROR 42S02: Table 'test.t1' doesn't exist
+99c113,114
+< test.t1 check status OK
+---
+> test.t1 check Error Table 'test.t1' doesn't exist
+> test.t1 check status Operation failed
+100a116
+> ERROR 42S02: Table 'test.t1' doesn't exist
+103c119,120
+< test.t1 check status OK
+---
+> test.t1 check Error Table 'test.t1' doesn't exist
+> test.t1 check status Operation failed
+104a122
+> ERROR 42S02: Unknown table 't1'
diff --git a/storage/myisammrg/mysql-test/storage_engine/parts/checksum_table.rdiff b/storage/myisammrg/mysql-test/storage_engine/parts/checksum_table.rdiff
new file mode 100644
index 00000000000..bc5b07686bf
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/parts/checksum_table.rdiff
@@ -0,0 +1,81 @@
+2a3,4
+> ERROR HY000: Engine cannot be used in partitioned tables
+> # ERROR: Statement ended with errno 1572, errname ER_PARTITION_MERGE_ERROR (expected to succeed)
+3a6
+> ERROR 42S02: Table 'test.t1' doesn't exist
+4a8,9
+> ERROR HY000: Engine cannot be used in partitioned tables
+> # ERROR: Statement ended with errno 1572, errname ER_PARTITION_MERGE_ERROR (expected to succeed)
+7c12,14
+< test.t1 4272806499
+---
+> test.t1 NULL
+> Warnings:
+> Error 1146 Table 'test.t1' doesn't exist
+10,11c17,21
+< test.t2 0
+< test.t1 4272806499
+---
+> test.t2 NULL
+> test.t1 NULL
+> Warnings:
+> Error 1146 Table 'test.t2' doesn't exist
+> Error 1146 Table 'test.t1' doesn't exist
+15a26,28
+> Warnings:
+> Error 1146 Table 'test.t1' doesn't exist
+> Error 1146 Table 'test.t2' doesn't exist
+18,19c31,35
+< test.t1 4272806499
+< test.t2 0
+---
+> test.t1 NULL
+> test.t2 NULL
+> Warnings:
+> Error 1146 Table 'test.t1' doesn't exist
+> Error 1146 Table 'test.t2' doesn't exist
+20a37
+> ERROR 42S02: Unknown table 't1,t2'
+22a40,41
+> ERROR HY000: Engine cannot be used in partitioned tables
+> # ERROR: Statement ended with errno 1572, errname ER_PARTITION_MERGE_ERROR (expected to succeed)
+23a43
+> ERROR 42S02: Table 'test.t1' doesn't exist
+24a45,46
+> ERROR HY000: Engine cannot be used in partitioned tables
+> # ERROR: Statement ended with errno 1572, errname ER_PARTITION_MERGE_ERROR (expected to succeed)
+27c49,51
+< test.t1 0
+---
+> test.t1 NULL
+> Warnings:
+> Error 1146 Table 'test.t1' doesn't exist
+30,31c54,58
+< test.t2 0
+< test.t1 0
+---
+> test.t2 NULL
+> test.t1 NULL
+> Warnings:
+> Error 1146 Table 'test.t2' doesn't exist
+> Error 1146 Table 'test.t1' doesn't exist
+34,35c61,65
+< test.t1 0
+< test.t2 0
+---
+> test.t1 NULL
+> test.t2 NULL
+> Warnings:
+> Error 1146 Table 'test.t1' doesn't exist
+> Error 1146 Table 'test.t2' doesn't exist
+38,39c68,72
+< test.t1 4272806499
+< test.t2 0
+---
+> test.t1 NULL
+> test.t2 NULL
+> Warnings:
+> Error 1146 Table 'test.t1' doesn't exist
+> Error 1146 Table 'test.t2' doesn't exist
+40a74
+> ERROR 42S02: Unknown table 't1,t2'
diff --git a/storage/myisammrg/mysql-test/storage_engine/parts/create_table.rdiff b/storage/myisammrg/mysql-test/storage_engine/parts/create_table.rdiff
new file mode 100644
index 00000000000..11fbc4812dc
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/parts/create_table.rdiff
@@ -0,0 +1,156 @@
+3,10c3,12
+< INSERT INTO t1 (a) VALUES (1),(2),(3),(2);
+< EXPLAIN PARTITIONS SELECT a FROM t1;
+< id select_type table partitions type possible_keys key key_len ref rows Extra
+< 1 SIMPLE t1 p0,p1 # # # # # # #
+< EXPLAIN PARTITIONS SELECT a FROM t1 WHERE a=2;
+< id select_type table partitions type possible_keys key key_len ref rows Extra
+< 1 SIMPLE t1 p0 # # # # # # #
+< DROP TABLE t1;
+---
+> ERROR HY000: Engine cannot be used in partitioned tables
+> # ERROR: Statement ended with errno 1572, errname ER_PARTITION_MERGE_ERROR (expected to succeed)
+> # ------------ UNEXPECTED RESULT ------------
+> # [ CREATE TABLE t1 (a INT(11) /*!*/ /*Custom column options*/) ENGINE=MRG_MYISAM /*!*/ /*Custom table options*/ UNION(mrg.t1) INSERT_METHOD=LAST PARTITION BY HASH(a) PARTITIONS 2 ]
+> # The statement|command finished with ER_PARTITION_MERGE_ERROR.
+> # Partitions or the mix could be unsupported|malfunctioning, or the problem was caused by previous errors.
+> # You can change the engine code, or create an rdiff, or disable the test by adding it to disabled.def.
+> # Further in this test, the message might sometimes be suppressed; a part of the test might be skipped.
+> # Also, this problem may cause a chain effect (more errors of different kinds in the test).
+> # -------------------------------------------
+12,19c14,23
+< INSERT INTO t1 (a) VALUES ('a'),('b'),('c');
+< EXPLAIN PARTITIONS SELECT a FROM t1;
+< id select_type table partitions type possible_keys key key_len ref rows Extra
+< 1 SIMPLE t1 p0,p1 # # # # # # #
+< EXPLAIN PARTITIONS SELECT a FROM t1 WHERE a = 'b';
+< id select_type table partitions type possible_keys key key_len ref rows Extra
+< 1 SIMPLE t1 p1 # # # # # # #
+< DROP TABLE t1;
+---
+> ERROR HY000: Engine cannot be used in partitioned tables
+> # ERROR: Statement ended with errno 1572, errname ER_PARTITION_MERGE_ERROR (expected to succeed)
+> # ------------ UNEXPECTED RESULT ------------
+> # [ CREATE TABLE t1 (a CHAR(8) /*!*/ /*Custom column options*/) ENGINE=MRG_MYISAM /*!*/ /*Custom table options*/ UNION(mrg.t1) INSERT_METHOD=LAST PARTITION BY KEY(a) PARTITIONS 2 ]
+> # The statement|command finished with ER_PARTITION_MERGE_ERROR.
+> # Partitions or CHAR types or the mix could be unsupported|malfunctioning, or the problem was caused by previous errors.
+> # You can change the engine code, or create an rdiff, or disable the test by adding it to disabled.def.
+> # Further in this test, the message might sometimes be suppressed; a part of the test might be skipped.
+> # Also, this problem may cause a chain effect (more errors of different kinds in the test).
+> # -------------------------------------------
+21,31c25,34
+< SHOW INDEX IN t1;
+< Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment
+< t1 1 a 1 a # # NULL NULL # #
+< INSERT INTO t1 (a) VALUES (1),(2),(3),(5);
+< EXPLAIN PARTITIONS SELECT a FROM t1;
+< id select_type table partitions type possible_keys key key_len ref rows Extra
+< 1 SIMPLE t1 p0,p1 # # # # # # #
+< EXPLAIN PARTITIONS SELECT a FROM t1 WHERE a IN (1,3);
+< id select_type table partitions type possible_keys key key_len ref rows Extra
+< 1 SIMPLE t1 p0 # # # # # # #
+< DROP TABLE t1;
+---
+> ERROR HY000: Engine cannot be used in partitioned tables
+> # ERROR: Statement ended with errno 1572, errname ER_PARTITION_MERGE_ERROR (expected to succeed)
+> # ------------ UNEXPECTED RESULT ------------
+> # [ CREATE TABLE t1 (a INT(11) /*!*/ /*Custom indexed column options*/, /*!INDEX*/ /*Custom index*/ (a)) ENGINE=MRG_MYISAM /*!*/ /*Custom table options*/ UNION(mrg.t1) INSERT_METHOD=LAST PARTITION BY KEY(a) PARTITIONS 2 ]
+> # The statement|command finished with ER_PARTITION_MERGE_ERROR.
+> # Partitions or indexes or the mix could be unsupported|malfunctioning, or the problem was caused by previous errors.
+> # You can change the engine code, or create an rdiff, or disable the test by adding it to disabled.def.
+> # Further in this test, the message might sometimes be suppressed; a part of the test might be skipped.
+> # Also, this problem may cause a chain effect (more errors of different kinds in the test).
+> # -------------------------------------------
+33,43c36,45
+< SHOW INDEX IN t1;
+< Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment
+< t1 0 PRIMARY 1 a # # NULL NULL # #
+< INSERT INTO t1 (a) VALUES (1),(200),(3),(2);
+< EXPLAIN PARTITIONS SELECT a FROM t1;
+< id select_type table partitions type possible_keys key key_len ref rows Extra
+< 1 SIMPLE t1 p0,p1 # # # # # # #
+< EXPLAIN PARTITIONS SELECT a FROM t1 WHERE a=2;
+< id select_type table partitions type possible_keys key key_len ref rows Extra
+< 1 SIMPLE t1 p1 # # # # # # #
+< DROP TABLE t1;
+---
+> ERROR HY000: Engine cannot be used in partitioned tables
+> # ERROR: Statement ended with errno 1572, errname ER_PARTITION_MERGE_ERROR (expected to succeed)
+> # ------------ UNEXPECTED RESULT ------------
+> # [ CREATE TABLE t1 (a INT(11) /*!*/ /*Custom indexed column options*/ PRIMARY KEY) ENGINE=MRG_MYISAM /*!*/ /*Custom table options*/ UNION(mrg.t1) INSERT_METHOD=LAST PARTITION BY KEY() PARTITIONS 2 ]
+> # The statement|command finished with ER_PARTITION_MERGE_ERROR.
+> # PK or the mix could be unsupported|malfunctioning, or the problem was caused by previous errors.
+> # You can change the engine code, or create an rdiff, or disable the test by adding it to disabled.def.
+> # Further in this test, the message might sometimes be suppressed; a part of the test might be skipped.
+> # Also, this problem may cause a chain effect (more errors of different kinds in the test).
+> # -------------------------------------------
+48,58c50,63
+< INSERT INTO t1 (a) VALUES (1),(2),(400);
+< EXPLAIN PARTITIONS SELECT a FROM t1;
+< id select_type table partitions type possible_keys key key_len ref rows Extra
+< 1 SIMPLE t1 p0,p1 # # # # # # #
+< EXPLAIN PARTITIONS SELECT a FROM t1 WHERE a = 2;
+< id select_type table partitions type possible_keys key key_len ref rows Extra
+< 1 SIMPLE t1 p0 # # # # # # #
+< INSERT INTO t1 (a) VALUES (10000);
+< ERROR HY000: Table has no partition for value 10000
+< DROP TABLE t1;
+< CREATE TABLE t1 (a <INT_COLUMN>) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS> PARTITION BY LIST(a) (
+---
+> ERROR HY000: Engine cannot be used in partitioned tables
+> # ERROR: Statement ended with errno 1572, errname ER_PARTITION_MERGE_ERROR (expected to succeed)
+> # ------------ UNEXPECTED RESULT ------------
+> # [ CREATE TABLE t1 (a INT(11) /*!*/ /*Custom column options*/) ENGINE=MRG_MYISAM /*!*/ /*Custom table options*/ UNION(mrg.t1) INSERT_METHOD=LAST PARTITION BY RANGE(a) (
+> PARTITION p0 VALUES LESS THAN (10),
+> PARTITION p1 VALUES LESS THAN (1000)
+> ) ]
+> # The statement|command finished with ER_PARTITION_MERGE_ERROR.
+> # Partitions or the mix could be unsupported|malfunctioning, or the problem was caused by previous errors.
+> # You can change the engine code, or create an rdiff, or disable the test by adding it to disabled.def.
+> # Further in this test, the message might sometimes be suppressed; a part of the test might be skipped.
+> # Also, this problem may cause a chain effect (more errors of different kinds in the test).
+> # -------------------------------------------
+> CREATE TABLE t1 (a <INT_COLUMN>, b <INT_COLUMN>) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS> PARTITION BY LIST(a) SUBPARTITION by HASH(b) (
+62,72c67,70
+< INSERT INTO t1 (a) VALUES (1),(101),(1);
+< EXPLAIN PARTITIONS SELECT a FROM t1;
+< id select_type table partitions type possible_keys key key_len ref rows Extra
+< 1 SIMPLE t1 abc,def # # # # # # #
+< EXPLAIN PARTITIONS SELECT a FROM t1 WHERE a = 100;
+< id select_type table partitions type possible_keys key key_len ref rows Extra
+< 1 SIMPLE NULL NULL # # # # # # #
+< INSERT INTO t1 (a) VALUES (50);
+< ERROR HY000: Table has no partition for value 50
+< DROP TABLE t1;
+< CREATE TABLE t1 (a <INT_COLUMN>, b <INT_COLUMN>) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS> PARTITION BY LIST(a) SUBPARTITION by HASH(b) (
+---
+> ERROR HY000: Engine cannot be used in partitioned tables
+> # ERROR: Statement ended with errno 1572, errname ER_PARTITION_MERGE_ERROR (expected to succeed)
+> # ------------ UNEXPECTED RESULT ------------
+> # [ CREATE TABLE t1 (a INT(11) /*!*/ /*Custom column options*/, b INT(11) /*!*/ /*Custom column options*/) ENGINE=MRG_MYISAM /*!*/ /*Custom table options*/ UNION(mrg.t1) INSERT_METHOD=LAST PARTITION BY LIST(a) SUBPARTITION by HASH(b) (
+75,91c73,79
+< );
+< SHOW INDEX IN t1;
+< Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment
+< INSERT INTO t1 (a,b) VALUES (1,1),(101,2),(1,3);
+< EXPLAIN PARTITIONS SELECT a FROM t1;
+< id select_type table partitions type possible_keys key key_len ref rows Extra
+< 1 SIMPLE t1 abc_abcsp0,def_defsp0 # # # # # # #
+< EXPLAIN PARTITIONS SELECT a FROM t1 WHERE a = 100;
+< id select_type table partitions type possible_keys key key_len ref rows Extra
+< 1 SIMPLE NULL NULL # # # # # # #
+< SELECT TABLE_SCHEMA, TABLE_NAME, PARTITION_NAME, SUBPARTITION_NAME, PARTITION_METHOD, SUBPARTITION_METHOD
+< FROM INFORMATION_SCHEMA.PARTITIONS WHERE TABLE_NAME = 't1';
+< TABLE_SCHEMA TABLE_NAME PARTITION_NAME SUBPARTITION_NAME PARTITION_METHOD SUBPARTITION_METHOD
+< test t1 abc abcsp0 LIST HASH
+< test t1 def defsp0 LIST HASH
+< SELECT * FROM INFORMATION_SCHEMA.PARTITIONS;
+< DROP TABLE t1;
+---
+> ) ]
+> # The statement|command finished with ER_PARTITION_MERGE_ERROR.
+> # Partitions or subpartitions or the mix could be unsupported|malfunctioning, or the problem was caused by previous errors.
+> # You can change the engine code, or create an rdiff, or disable the test by adding it to disabled.def.
+> # Further in this test, the message might sometimes be suppressed; a part of the test might be skipped.
+> # Also, this problem may cause a chain effect (more errors of different kinds in the test).
+> # -------------------------------------------
diff --git a/storage/myisammrg/mysql-test/storage_engine/parts/optimize_table.rdiff b/storage/myisammrg/mysql-test/storage_engine/parts/optimize_table.rdiff
new file mode 100644
index 00000000000..350d93fe91f
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/parts/optimize_table.rdiff
@@ -0,0 +1,91 @@
+3,25c3,12
+< INSERT INTO t1 (a,b) VALUES (1,'a'),(2,'b'),(3,'c'),(2,'d'),(4,'e'),(100,'f'),(101,'g');
+< CREATE TABLE t2 (a <INT_COLUMN>, b <CHAR_COLUMN>) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS> PARTITION BY RANGE(a) (
+< PARTITION p0 VALUES LESS THAN (100),
+< PARTITION p1 VALUES LESS THAN MAXVALUE
+< );
+< INSERT INTO t2 (a,b) SELECT a, b FROM t1;
+< INSERT INTO t1 (a,b) VALUES (3,'c'),(4,'d');
+< ALTER TABLE t1 OPTIMIZE PARTITION p1;
+< Table Op Msg_type Msg_text
+< test.t1 optimize status OK
+< INSERT INTO t2 (a,b) VALUES (4,'d');
+< ALTER TABLE t2 OPTIMIZE PARTITION p0 NO_WRITE_TO_BINLOG;
+< Table Op Msg_type Msg_text
+< test.t2 optimize status OK
+< INSERT INTO t1 (a,b) VALUES (6,'f');
+< ALTER TABLE t1 OPTIMIZE PARTITION ALL LOCAL;
+< Table Op Msg_type Msg_text
+< test.t1 optimize status OK
+< INSERT INTO t2 (a,b) VALUES (5,'e');
+< ALTER TABLE t2 OPTIMIZE PARTITION p1,p0;
+< Table Op Msg_type Msg_text
+< test.t2 optimize status OK
+< DROP TABLE t1, t2;
+---
+> ERROR HY000: Engine cannot be used in partitioned tables
+> # ERROR: Statement ended with errno 1572, errname ER_PARTITION_MERGE_ERROR (expected to succeed)
+> # ------------ UNEXPECTED RESULT ------------
+> # [ CREATE TABLE t1 (a INT(11) /*!*/ /*Custom column options*/, b CHAR(8) /*!*/ /*Custom column options*/) ENGINE=MRG_MYISAM /*!*/ /*Custom table options*/ UNION(mrg.t1) INSERT_METHOD=LAST PARTITION BY HASH(a) PARTITIONS 2 ]
+> # The statement|command finished with ER_PARTITION_MERGE_ERROR.
+> # Partitions or the mix could be unsupported|malfunctioning, or the problem was caused by previous errors.
+> # You can change the engine code, or create an rdiff, or disable the test by adding it to disabled.def.
+> # Further in this test, the message might sometimes be suppressed; a part of the test might be skipped.
+> # Also, this problem may cause a chain effect (more errors of different kinds in the test).
+> # -------------------------------------------
+27a15,16
+> ERROR HY000: Engine cannot be used in partitioned tables
+> # ERROR: Statement ended with errno 1572, errname ER_PARTITION_MERGE_ERROR (expected to succeed)
+28a18
+> ERROR 42S02: Table 'test.t1' doesn't exist
+29a20,21
+> ERROR HY000: Engine cannot be used in partitioned tables
+> # ERROR: Statement ended with errno 1572, errname ER_PARTITION_MERGE_ERROR (expected to succeed)
+30a23
+> ERROR 42S02: Table 'test.t1' doesn't exist
+33c26,27
+< test.t1 optimize status OK
+---
+> test.t1 optimize Error Table 'test.t1' doesn't exist
+> test.t1 optimize status Operation failed
+34a29
+> ERROR 42S02: Table 'test.t2' doesn't exist
+37c32,33
+< test.t2 optimize status OK
+---
+> test.t2 optimize Error Table 'test.t2' doesn't exist
+> test.t2 optimize status Operation failed
+38a35
+> ERROR 42S02: Table 'test.t2' doesn't exist
+39a37
+> ERROR 42S02: Table 'test.t1' doesn't exist
+42,43c40,43
+< test.t1 optimize status OK
+< test.t2 optimize status OK
+---
+> test.t1 optimize Error Table 'test.t1' doesn't exist
+> test.t1 optimize status Operation failed
+> test.t2 optimize Error Table 'test.t2' doesn't exist
+> test.t2 optimize status Operation failed
+46,47c46,49
+< test.t1 optimize status OK
+< test.t2 optimize status OK
+---
+> test.t1 optimize Error Table 'test.t1' doesn't exist
+> test.t1 optimize status Operation failed
+> test.t2 optimize Error Table 'test.t2' doesn't exist
+> test.t2 optimize status Operation failed
+48a51
+> ERROR 42S02: Unknown table 't1,t2'
+49a53,54
+> ERROR HY000: Engine cannot be used in partitioned tables
+> # ERROR: Statement ended with errno 1572, errname ER_PARTITION_MERGE_ERROR (expected to succeed)
+50a56
+> ERROR 42S02: Table 'test.t1' doesn't exist
+53c59,60
+< test.t1 optimize status OK
+---
+> test.t1 optimize Error Table 'test.t1' doesn't exist
+> test.t1 optimize status Operation failed
+54a62
+> ERROR 42S02: Unknown table 't1'
diff --git a/storage/myisammrg/mysql-test/storage_engine/parts/repair_table.rdiff b/storage/myisammrg/mysql-test/storage_engine/parts/repair_table.rdiff
new file mode 100644
index 00000000000..4c39421261c
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/parts/repair_table.rdiff
@@ -0,0 +1,295 @@
+4,33c4,13
+< INSERT INTO t1 (a,b) VALUES (1,'a'),(2,'b'),(3,'c'),(2,'d'),(4,'e'),(100,'f'),(101,'g');
+< CREATE TABLE t2 (a <INT_COLUMN>, b <CHAR_COLUMN>) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS> PARTITION BY RANGE(a) (
+< PARTITION p0 VALUES LESS THAN (100),
+< PARTITION p1 VALUES LESS THAN MAXVALUE
+< );
+< INSERT INTO t2 (a,b) SELECT a, b FROM t1;
+< ALTER TABLE t1 REPAIR PARTITION p0;
+< Table Op Msg_type Msg_text
+< test.t1 repair status OK
+< INSERT INTO t1 VALUES (3,'c');
+< ALTER TABLE t1 REPAIR PARTITION NO_WRITE_TO_BINLOG p0, p1;
+< Table Op Msg_type Msg_text
+< test.t1 repair status OK
+< INSERT INTO t2 (a,b) VALUES (5,'e'),(6,'f');
+< ALTER TABLE t2 REPAIR PARTITION LOCAL p1;
+< Table Op Msg_type Msg_text
+< test.t2 repair status OK
+< INSERT INTO t1 (a,b) VALUES (7,'g'),(8,'h');
+< ALTER TABLE t1 REPAIR PARTITION LOCAL ALL EXTENDED;
+< Table Op Msg_type Msg_text
+< test.t1 repair status OK
+< INSERT INTO t1 VALUES (10,'j');
+< ALTER TABLE t1 REPAIR PARTITION p1 QUICK USE_FRM;
+< Table Op Msg_type Msg_text
+< test.t1 repair status OK
+< INSERT INTO t2 (a,b) VALUES (12,'l');
+< ALTER TABLE t2 REPAIR PARTITION NO_WRITE_TO_BINLOG ALL QUICK EXTENDED USE_FRM;
+< Table Op Msg_type Msg_text
+< test.t2 repair status OK
+< DROP TABLE t1, t2;
+---
+> ERROR HY000: Engine cannot be used in partitioned tables
+> # ERROR: Statement ended with errno 1572, errname ER_PARTITION_MERGE_ERROR (expected to succeed)
+> # ------------ UNEXPECTED RESULT ------------
+> # [ CREATE TABLE t1 (a INT(11) /*!*/ /*Custom column options*/, b CHAR(8) /*!*/ /*Custom column options*/) ENGINE=MRG_MYISAM /*!*/ /*Custom table options*/ UNION(mrg.t1) INSERT_METHOD=LAST PARTITION BY HASH(a) PARTITIONS 2 ]
+> # The statement|command finished with ER_PARTITION_MERGE_ERROR.
+> # Partitions or the mix could be unsupported|malfunctioning, or the problem was caused by previous errors.
+> # You can change the engine code, or create an rdiff, or disable the test by adding it to disabled.def.
+> # Further in this test, the message might sometimes be suppressed; a part of the test might be skipped.
+> # Also, this problem may cause a chain effect (more errors of different kinds in the test).
+> # -------------------------------------------
+35a16,17
+> ERROR HY000: Engine cannot be used in partitioned tables
+> # ERROR: Statement ended with errno 1572, errname ER_PARTITION_MERGE_ERROR (expected to succeed)
+36a19
+> ERROR 42S02: Table 'test.t1' doesn't exist
+37a21,22
+> ERROR HY000: Engine cannot be used in partitioned tables
+> # ERROR: Statement ended with errno 1572, errname ER_PARTITION_MERGE_ERROR (expected to succeed)
+40c25,26
+< test.t1 repair status OK
+---
+> test.t1 repair Error Table 'test.t1' doesn't exist
+> test.t1 repair status Operation failed
+41a28
+> ERROR 42S02: Table 'test.t1' doesn't exist
+42a30
+> ERROR 42S02: Table 'test.t2' doesn't exist
+45,46c33,36
+< test.t1 repair status OK
+< test.t2 repair status OK
+---
+> test.t1 repair Error Table 'test.t1' doesn't exist
+> test.t1 repair status Operation failed
+> test.t2 repair Error Table 'test.t2' doesn't exist
+> test.t2 repair status Operation failed
+47a38
+> ERROR 42S02: Table 'test.t2' doesn't exist
+50c41,42
+< test.t2 repair status OK
+---
+> test.t2 repair Error Table 'test.t2' doesn't exist
+> test.t2 repair status Operation failed
+51a44
+> ERROR 42S02: Table 'test.t1' doesn't exist
+52a46
+> ERROR 42S02: Table 'test.t2' doesn't exist
+55,56c49,52
+< test.t2 repair status OK
+< test.t1 repair status OK
+---
+> test.t2 repair Error Table 'test.t2' doesn't exist
+> test.t2 repair status Operation failed
+> test.t1 repair Error Table 'test.t1' doesn't exist
+> test.t1 repair status Operation failed
+57a54
+> ERROR 42S02: Table 'test.t1' doesn't exist
+58a56
+> ERROR 42S02: Table 'test.t2' doesn't exist
+61,62c59,62
+< test.t1 repair status OK
+< test.t2 repair status OK
+---
+> test.t1 repair Error Table 'test.t1' doesn't exist
+> test.t1 repair status Operation failed
+> test.t2 repair Error Table 'test.t2' doesn't exist
+> test.t2 repair status Operation failed
+63a64
+> ERROR 42S02: Table 'test.t1' doesn't exist
+64a66
+> ERROR 42S02: Table 'test.t2' doesn't exist
+67,68c69,72
+< test.t1 repair status OK
+< test.t2 repair status OK
+---
+> test.t1 repair Error Table 'test.t1' doesn't exist
+> test.t1 repair status Operation failed
+> test.t2 repair Error Table 'test.t2' doesn't exist
+> test.t2 repair status Operation failed
+71,73c75,76
+< ERROR HY000: Failed to read from the .par file
+< # Statement ended with one of expected results (0,130,ER_FAILED_READ_FROM_PAR_FILE,ER_OPEN_AS_READONLY).
+< # If you got a difference in error message, just add it to rdiff file
+---
+> ERROR 42S02: Table 'test.t1' doesn't exist
+> # ERROR: Statement ended with errno 1146, errname ER_NO_SUCH_TABLE (expected results: 0,130,ER_FAILED_READ_FROM_PAR_FILE,ER_OPEN_AS_READONLY)
+76,78c79,80
+< test.t1 check Error Failed to read from the .par file
+< test.t1 check Error Incorrect information in file: './test/t1.frm'
+< test.t1 check error Corrupt
+---
+> test.t1 check Error Table 'test.t1' doesn't exist
+> test.t1 check status Operation failed
+80,82c82,83
+< ERROR HY000: Failed to read from the .par file
+< # Statement ended with one of expected results (0,130,ER_FAILED_READ_FROM_PAR_FILE,ER_OPEN_AS_READONLY).
+< # If you got a difference in error message, just add it to rdiff file
+---
+> ERROR 42S02: Table 'test.t1' doesn't exist
+> # ERROR: Statement ended with errno 1146, errname ER_NO_SUCH_TABLE (expected results: 0,130,ER_FAILED_READ_FROM_PAR_FILE,ER_OPEN_AS_READONLY)
+85,87c86,87
+< test.t1 repair Error Failed to read from the .par file
+< test.t1 repair Error Incorrect information in file: './test/t1.frm'
+< test.t1 repair error Corrupt
+---
+> test.t1 repair Error Table 'test.t1' doesn't exist
+> test.t1 repair status Operation failed
+88a89
+> ERROR 42S02: Unknown table 't1,t2'
+93a95,96
+> ERROR HY000: Engine cannot be used in partitioned tables
+> # ERROR: Statement ended with errno 1572, errname ER_PARTITION_MERGE_ERROR (expected to succeed)
+96c99,100
+< test.t1 repair status OK
+---
+> test.t1 repair Error Table 'test.t1' doesn't exist
+> test.t1 repair status Operation failed
+97a102
+> ERROR 42S02: Table 'test.t1' doesn't exist
+100c105,106
+< test.t1 repair status OK
+---
+> test.t1 repair Error Table 'test.t1' doesn't exist
+> test.t1 repair status Operation failed
+101a108
+> ERROR 42S02: Table 'test.t1' doesn't exist
+104,235c111,112
+< test.t1 repair status OK
+< t1#P#p0.MYD
+< t1#P#p0.MYI
+< t1#P#p1.MYD
+< t1#P#p1.MYI
+< t1.frm
+< t1.par
+< INSERT INTO t1 (a,b) VALUES (14,'n'),(15,'o');
+< # Statement ended with one of expected results (0,144).
+< # If you got a difference in error message, just add it to rdiff file
+< FLUSH TABLE t1;
+< Restoring <DATADIR>/test/t1#P#p0.MYD
+< CHECK TABLE t1;
+< Table Op Msg_type Msg_text
+< test.t1 check error Size of datafile is: 26 Should be: 39
+< test.t1 check error Partition p0 returned error
+< test.t1 check error Corrupt
+< SELECT * FROM t1;
+< a b
+< 8 h
+< 10 j
+< 7 g
+< 15 o
+< Warnings:
+< Error 145 Table './test/t1#P#p0' is marked as crashed and should be repaired
+< Error 1194 Table 't1' is marked as crashed and should be repaired
+< Error 1034 Number of rows changed from 3 to 2
+< # Statement ended with one of expected results (0,ER_NOT_KEYFILE,144).
+< # If you got a difference in error message, just add it to rdiff file
+< INSERT INTO t1 (a,b) VALUES (14,'n'),(15,'o');
+< # Statement ended with one of expected results (0,144).
+< # If you got a difference in error message, just add it to rdiff file
+< FLUSH TABLE t1;
+< Restoring <DATADIR>/test/t1#P#p0.MYI
+< CHECK TABLE t1;
+< Table Op Msg_type Msg_text
+< test.t1 check warning Size of datafile is: 39 Should be: 26
+< test.t1 check error Record-count is not ok; is 3 Should be: 2
+< test.t1 check warning Found 3 key parts. Should be: 2
+< test.t1 check error Partition p0 returned error
+< test.t1 check error Corrupt
+< SELECT * FROM t1;
+< a b
+< 8 h
+< 10 j
+< 14 n
+< 7 g
+< 15 o
+< 15 o
+< Warnings:
+< Error 145 Table './test/t1#P#p0' is marked as crashed and should be repaired
+< Error 1194 Table 't1' is marked as crashed and should be repaired
+< Error 1034 Number of rows changed from 2 to 3
+< # Statement ended with one of expected results (0,ER_NOT_KEYFILE,144).
+< # If you got a difference in error message, just add it to rdiff file
+< INSERT INTO t1 (a,b) VALUES (14,'n'),(15,'o');
+< # Statement ended with one of expected results (0,144).
+< # If you got a difference in error message, just add it to rdiff file
+< FLUSH TABLE t1;
+< Restoring <DATADIR>/test/t1#P#p1.MYD
+< CHECK TABLE t1;
+< Table Op Msg_type Msg_text
+< test.t1 check error Size of datafile is: 39 Should be: 52
+< test.t1 check error Partition p1 returned error
+< test.t1 check error Corrupt
+< SELECT * FROM t1;
+< a b
+< 8 h
+< 10 j
+< 14 n
+< 14 n
+< 7 g
+< 15 o
+< 15 o
+< Warnings:
+< Error 145 Table './test/t1#P#p1' is marked as crashed and should be repaired
+< Error 1194 Table 't1' is marked as crashed and should be repaired
+< Error 1034 Number of rows changed from 4 to 3
+< # Statement ended with one of expected results (0,ER_NOT_KEYFILE,144).
+< # If you got a difference in error message, just add it to rdiff file
+< INSERT INTO t1 (a,b) VALUES (14,'n'),(15,'o');
+< # Statement ended with one of expected results (0,144).
+< # If you got a difference in error message, just add it to rdiff file
+< FLUSH TABLE t1;
+< Restoring <DATADIR>/test/t1#P#p1.MYI
+< CHECK TABLE t1;
+< Table Op Msg_type Msg_text
+< test.t1 check warning Size of datafile is: 52 Should be: 39
+< test.t1 check error Record-count is not ok; is 4 Should be: 3
+< test.t1 check warning Found 4 key parts. Should be: 3
+< test.t1 check error Partition p1 returned error
+< test.t1 check error Corrupt
+< SELECT * FROM t1;
+< a b
+< 8 h
+< 10 j
+< 14 n
+< 14 n
+< 14 n
+< 7 g
+< 15 o
+< 15 o
+< 15 o
+< Warnings:
+< Error 145 Table './test/t1#P#p1' is marked as crashed and should be repaired
+< Error 1194 Table 't1' is marked as crashed and should be repaired
+< Error 1034 Number of rows changed from 3 to 4
+< # Statement ended with one of expected results (0,ER_NOT_KEYFILE,144).
+< # If you got a difference in error message, just add it to rdiff file
+< INSERT INTO t1 (a,b) VALUES (14,'n'),(15,'o');
+< # Statement ended with one of expected results (0,144).
+< # If you got a difference in error message, just add it to rdiff file
+< FLUSH TABLE t1;
+< Restoring <DATADIR>/test/t1.par
+< CHECK TABLE t1;
+< Table Op Msg_type Msg_text
+< test.t1 check status OK
+< SELECT * FROM t1;
+< a b
+< 8 h
+< 10 j
+< 14 n
+< 14 n
+< 14 n
+< 14 n
+< 7 g
+< 15 o
+< 15 o
+< 15 o
+< 15 o
+< # Statement ended with one of expected results (0,ER_NOT_KEYFILE,144).
+< # If you got a difference in error message, just add it to rdiff file
+---
+> test.t1 repair Error Table 'test.t1' doesn't exist
+> test.t1 repair status Operation failed
+236a114
+> ERROR 42S02: Unknown table 't1'
diff --git a/storage/myisammrg/mysql-test/storage_engine/parts/truncate_table.rdiff b/storage/myisammrg/mysql-test/storage_engine/parts/truncate_table.rdiff
new file mode 100644
index 00000000000..2c1364d52e1
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/parts/truncate_table.rdiff
@@ -0,0 +1,100 @@
+3,8c3,12
+< TRUNCATE TABLE t1;
+< INSERT INTO t1 (a,b) VALUES (1,'a'), (2,'b'), (3,'c');
+< TRUNCATE TABLE t1;
+< SELECT * FROM t1;
+< a b
+< DROP TABLE t1;
+---
+> ERROR HY000: Engine cannot be used in partitioned tables
+> # ERROR: Statement ended with errno 1572, errname ER_PARTITION_MERGE_ERROR (expected to succeed)
+> # ------------ UNEXPECTED RESULT ------------
+> # [ CREATE TABLE t1 (a INT(11) /*!*/ /*Custom column options*/, b CHAR(8) /*!*/ /*Custom column options*/) ENGINE=MRG_MYISAM /*!*/ /*Custom table options*/ UNION(mrg.t1) INSERT_METHOD=LAST PARTITION BY HASH(a) PARTITIONS 2 ]
+> # The statement|command finished with ER_PARTITION_MERGE_ERROR.
+> # Partitions or the mix could be unsupported|malfunctioning, or the problem was caused by previous errors.
+> # You can change the engine code, or create an rdiff, or disable the test by adding it to disabled.def.
+> # Further in this test, the message might sometimes be suppressed; a part of the test might be skipped.
+> # Also, this problem may cause a chain effect (more errors of different kinds in the test).
+> # -------------------------------------------
+10,52c14,23
+< SHOW CREATE TABLE t1;
+< Table Create Table
+< t1 CREATE TABLE `t1` (
+< `a` int(11) NOT NULL AUTO_INCREMENT,
+< `c` char(8) DEFAULT NULL,
+< PRIMARY KEY (`a`)
+< ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1
+< /*!50100 PARTITION BY HASH (a)
+< PARTITIONS 2 */
+< INSERT INTO t1 (c) VALUES ('a'),('b'),('c');
+< SHOW CREATE TABLE t1;
+< Table Create Table
+< t1 CREATE TABLE `t1` (
+< `a` int(11) NOT NULL AUTO_INCREMENT,
+< `c` char(8) DEFAULT NULL,
+< PRIMARY KEY (`a`)
+< ) ENGINE=<STORAGE_ENGINE> AUTO_INCREMENT=4 DEFAULT CHARSET=latin1
+< /*!50100 PARTITION BY HASH (a)
+< PARTITIONS 2 */
+< TRUNCATE TABLE t1;
+< SHOW CREATE TABLE t1;
+< Table Create Table
+< t1 CREATE TABLE `t1` (
+< `a` int(11) NOT NULL AUTO_INCREMENT,
+< `c` char(8) DEFAULT NULL,
+< PRIMARY KEY (`a`)
+< ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1
+< /*!50100 PARTITION BY HASH (a)
+< PARTITIONS 2 */
+< INSERT INTO t1 (c) VALUES ('d');
+< SHOW CREATE TABLE t1;
+< Table Create Table
+< t1 CREATE TABLE `t1` (
+< `a` int(11) NOT NULL AUTO_INCREMENT,
+< `c` char(8) DEFAULT NULL,
+< PRIMARY KEY (`a`)
+< ) ENGINE=<STORAGE_ENGINE> AUTO_INCREMENT=2 DEFAULT CHARSET=latin1
+< /*!50100 PARTITION BY HASH (a)
+< PARTITIONS 2 */
+< SELECT * FROM t1;
+< a c
+< 1 d
+< DROP TABLE t1;
+---
+> ERROR HY000: Engine cannot be used in partitioned tables
+> # ERROR: Statement ended with errno 1572, errname ER_PARTITION_MERGE_ERROR (expected to succeed)
+> # ------------ UNEXPECTED RESULT ------------
+> # [ CREATE TABLE t1 (a INT(11) /*!*/ /*Custom indexed column options*/ KEY AUTO_INCREMENT, c CHAR(8) /*!*/ /*Custom column options*/) ENGINE=MRG_MYISAM /*!*/ /*Custom table options*/ UNION(mrg.t1) INSERT_METHOD=LAST PARTITION BY HASH(a) PARTITIONS 2 ]
+> # The statement|command finished with ER_PARTITION_MERGE_ERROR.
+> # Partitions or PK or auto-increment or the mix could be unsupported|malfunctioning, or the problem was caused by previous errors.
+> # You can change the engine code, or create an rdiff, or disable the test by adding it to disabled.def.
+> # Further in this test, the message might sometimes be suppressed; a part of the test might be skipped.
+> # Also, this problem may cause a chain effect (more errors of different kinds in the test).
+> # -------------------------------------------
+54,68c25,34
+< INSERT INTO t1 (a,b) VALUES (1,'a'),(2,'b'),(3,'c'),(2,'d'),(4,'e'),(100,'f'),(101,'g');
+< ALTER TABLE t1 TRUNCATE PARTITION p0;
+< SELECT * FROM t1;
+< a b
+< 1 a
+< 101 g
+< 3 c
+< EXPLAIN PARTITIONS SELECT * FROM t1;
+< id select_type table partitions type possible_keys key key_len ref rows Extra
+< 1 SIMPLE t1 p0,p1 # # # # # #
+< INSERT INTO t1 (a,b) VALUES (1,'a'), (2,'b'), (3,'c');
+< ALTER TABLE t1 TRUNCATE PARTITION ALL;
+< SELECT * FROM t1;
+< a b
+< DROP TABLE t1;
+---
+> ERROR HY000: Engine cannot be used in partitioned tables
+> # ERROR: Statement ended with errno 1572, errname ER_PARTITION_MERGE_ERROR (expected to succeed)
+> # ------------ UNEXPECTED RESULT ------------
+> # [ CREATE TABLE t1 (a INT(11) /*!*/ /*Custom column options*/, b CHAR(8) /*!*/ /*Custom column options*/) ENGINE=MRG_MYISAM /*!*/ /*Custom table options*/ UNION(mrg.t1) INSERT_METHOD=LAST PARTITION BY HASH(a) PARTITIONS 2 ]
+> # The statement|command finished with ER_PARTITION_MERGE_ERROR.
+> # Partitions or the mix could be unsupported|malfunctioning, or the problem was caused by previous errors.
+> # You can change the engine code, or create an rdiff, or disable the test by adding it to disabled.def.
+> # Further in this test, the message might sometimes be suppressed; a part of the test might be skipped.
+> # Also, this problem may cause a chain effect (more errors of different kinds in the test).
+> # -------------------------------------------
diff --git a/storage/myisammrg/mysql-test/storage_engine/repair_table.rdiff b/storage/myisammrg/mysql-test/storage_engine/repair_table.rdiff
new file mode 100644
index 00000000000..180647323bc
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/repair_table.rdiff
@@ -0,0 +1,103 @@
+7c7
+< test.t1 repair status OK
+---
+> test.t1 repair note The storage engine for the table doesn't support repair
+12,13c12,13
+< test.t1 repair status OK
+< test.t2 repair status OK
+---
+> test.t1 repair note The storage engine for the table doesn't support repair
+> test.t2 repair note The storage engine for the table doesn't support repair
+17c17
+< test.t2 repair status OK
+---
+> test.t2 repair note The storage engine for the table doesn't support repair
+22,23c22,23
+< test.t2 repair status OK
+< test.t1 repair status OK
+---
+> test.t2 repair note The storage engine for the table doesn't support repair
+> test.t1 repair note The storage engine for the table doesn't support repair
+28,31c28,29
+< test.t1 repair warning Number of rows changed from 0 to 6
+< test.t1 repair status OK
+< test.t2 repair warning Number of rows changed from 0 to 5
+< test.t2 repair status OK
+---
+> test.t1 repair note The storage engine for the table doesn't support repair
+> test.t2 repair note The storage engine for the table doesn't support repair
+36,39c34,35
+< test.t1 repair warning Number of rows changed from 0 to 7
+< test.t1 repair status OK
+< test.t2 repair warning Number of rows changed from 0 to 6
+< test.t2 repair status OK
+---
+> test.t1 repair note The storage engine for the table doesn't support repair
+> test.t2 repair note The storage engine for the table doesn't support repair
+42c38
+< ERROR HY000: Incorrect file format 't1'
+---
+> ERROR HY000: Table 't1' is read only
+47,48c43
+< test.t1 check Error Incorrect file format 't1'
+< test.t1 check error Corrupt
+---
+> test.t1 check status OK
+50c45
+< ERROR HY000: Incorrect file format 't1'
+---
+> a b
+55,56c50
+< test.t1 repair Error Incorrect file format 't1'
+< test.t1 repair error Corrupt
+---
+> test.t1 repair note The storage engine for the table doesn't support repair
+65c59
+< test.t1 repair status OK
+---
+> test.t1 repair note The storage engine for the table doesn't support repair
+69c63
+< test.t1 repair status OK
+---
+> test.t1 repair note The storage engine for the table doesn't support repair
+73,76c67,68
+< test.t1 repair warning Number of rows changed from 0 to 3
+< test.t1 repair status OK
+< t1.MYD
+< t1.MYI
+---
+> test.t1 repair note The storage engine for the table doesn't support repair
+> t1.MRG
+82c74
+< Restoring <DATADIR>/test/t1.MYD
+---
+> Restoring <DATADIR>/test/t1.MRG
+85,86c77
+< test.t1 check error Size of datafile is: 39 Should be: 65
+< test.t1 check error Corrupt
+---
+> test.t1 check status OK
+88,103c79,84
+< ERROR HY000: Incorrect key file for table 't1'; try to repair it
+< # Statement ended with one of expected results (0,ER_NOT_KEYFILE,144).
+< # If you got a difference in error message, just add it to rdiff file
+< INSERT INTO t1 (a,b) VALUES (14,'n'),(15,'o');
+< ERROR HY000: Table './test/t1' is marked as crashed and last (automatic?) repair failed
+< # Statement ended with one of expected results (0,144).
+< # If you got a difference in error message, just add it to rdiff file
+< FLUSH TABLE t1;
+< Restoring <DATADIR>/test/t1.MYI
+< CHECK TABLE t1;
+< Table Op Msg_type Msg_text
+< test.t1 check warning Table is marked as crashed and last repair failed
+< test.t1 check error Size of datafile is: 39 Should be: 65
+< test.t1 check error Corrupt
+< SELECT * FROM t1;
+< ERROR HY000: Table './test/t1' is marked as crashed and last (automatic?) repair failed
+---
+> a b
+> 7 g
+> 8 h
+> 10 j
+> 14 n
+> 15 o
diff --git a/storage/myisammrg/mysql-test/storage_engine/show_engine.rdiff b/storage/myisammrg/mysql-test/storage_engine/show_engine.rdiff
new file mode 100644
index 00000000000..e7c9b0176b6
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/show_engine.rdiff
@@ -0,0 +1,2 @@
+7d6
+< <STORAGE_ENGINE> ### Engine status, can be long and changeable ###
diff --git a/storage/myisammrg/mysql-test/storage_engine/tbl_opt_ai.rdiff b/storage/myisammrg/mysql-test/storage_engine/tbl_opt_ai.rdiff
new file mode 100644
index 00000000000..bca6fa60d13
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/tbl_opt_ai.rdiff
@@ -0,0 +1,8 @@
+7c7
+< ) ENGINE=<STORAGE_ENGINE> AUTO_INCREMENT=10 DEFAULT CHARSET=latin1
+---
+> ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(`mrg`.`t1`)
+13c13
+< ) ENGINE=<STORAGE_ENGINE> AUTO_INCREMENT=100 DEFAULT CHARSET=latin1
+---
+> ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(`mrg`.`t1`)
diff --git a/storage/myisammrg/mysql-test/storage_engine/tbl_opt_avg_row_length.rdiff b/storage/myisammrg/mysql-test/storage_engine/tbl_opt_avg_row_length.rdiff
new file mode 100644
index 00000000000..7a3ac54fd3e
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/tbl_opt_avg_row_length.rdiff
@@ -0,0 +1,8 @@
+8c8
+< ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 AVG_ROW_LENGTH=300
+---
+> ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 AVG_ROW_LENGTH=300 INSERT_METHOD=LAST UNION=(`mrg`.`t1`)
+15c15
+< ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 AVG_ROW_LENGTH=30000000
+---
+> ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 AVG_ROW_LENGTH=30000000 INSERT_METHOD=LAST UNION=(`mrg`.`t1`)
diff --git a/storage/myisammrg/mysql-test/storage_engine/tbl_opt_checksum.rdiff b/storage/myisammrg/mysql-test/storage_engine/tbl_opt_checksum.rdiff
new file mode 100644
index 00000000000..ecb3fadb479
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/tbl_opt_checksum.rdiff
@@ -0,0 +1,8 @@
+8c8
+< ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 CHECKSUM=1
+---
+> ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 CHECKSUM=1 INSERT_METHOD=LAST UNION=(`mrg`.`t1`)
+15c15
+< ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1
+---
+> ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(`mrg`.`t1`)
diff --git a/storage/myisammrg/mysql-test/storage_engine/tbl_opt_connection.rdiff b/storage/myisammrg/mysql-test/storage_engine/tbl_opt_connection.rdiff
new file mode 100644
index 00000000000..d3ebd87ad1e
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/tbl_opt_connection.rdiff
@@ -0,0 +1,8 @@
+13c13
+< ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 CONNECTION='test_connection'
+---
+> ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(`mrg`.`t1`) CONNECTION='test_connection'
+20c20
+< ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 CONNECTION='test_connection2'
+---
+> ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(`mrg`.`t1`) CONNECTION='test_connection2'
diff --git a/storage/myisammrg/mysql-test/storage_engine/tbl_opt_data_index_dir.rdiff b/storage/myisammrg/mysql-test/storage_engine/tbl_opt_data_index_dir.rdiff
new file mode 100644
index 00000000000..3c15e10d1f1
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/tbl_opt_data_index_dir.rdiff
@@ -0,0 +1,8 @@
+7c7
+< ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 DATA DIRECTORY='<DATA_DIR>' INDEX DIRECTORY='<INDEX_DIR>'
+---
+> ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(`mrg`.`t1`)
+15c15
+< ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 DATA DIRECTORY='<DATA_DIR>' INDEX DIRECTORY='<INDEX_DIR>'
+---
+> ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(`mrg`.`t1`)
diff --git a/storage/myisammrg/mysql-test/storage_engine/tbl_opt_delay_key_write.rdiff b/storage/myisammrg/mysql-test/storage_engine/tbl_opt_delay_key_write.rdiff
new file mode 100644
index 00000000000..5723e425b4d
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/tbl_opt_delay_key_write.rdiff
@@ -0,0 +1,8 @@
+8c8
+< ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 DELAY_KEY_WRITE=1
+---
+> ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 DELAY_KEY_WRITE=1 INSERT_METHOD=LAST UNION=(`mrg`.`t1`)
+15c15
+< ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1
+---
+> ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(`mrg`.`t1`)
diff --git a/storage/myisammrg/mysql-test/storage_engine/tbl_opt_insert_method.rdiff b/storage/myisammrg/mysql-test/storage_engine/tbl_opt_insert_method.rdiff
new file mode 100644
index 00000000000..2ced7647483
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/tbl_opt_insert_method.rdiff
@@ -0,0 +1,8 @@
+8c8
+< ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 INSERT_METHOD=FIRST
+---
+> ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 INSERT_METHOD=FIRST UNION=(`mrg`.`t1`)
+15c15
+< ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1
+---
+> ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 UNION=(`mrg`.`t1`)
diff --git a/storage/myisammrg/mysql-test/storage_engine/tbl_opt_key_block_size.rdiff b/storage/myisammrg/mysql-test/storage_engine/tbl_opt_key_block_size.rdiff
new file mode 100644
index 00000000000..8378f04ebcb
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/tbl_opt_key_block_size.rdiff
@@ -0,0 +1,8 @@
+8c8
+< ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 KEY_BLOCK_SIZE=8
+---
+> ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 KEY_BLOCK_SIZE=8 INSERT_METHOD=LAST UNION=(`mrg`.`t1`)
+15c15
+< ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 KEY_BLOCK_SIZE=1
+---
+> ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 KEY_BLOCK_SIZE=1 INSERT_METHOD=LAST UNION=(`mrg`.`t1`)
diff --git a/storage/myisammrg/mysql-test/storage_engine/tbl_opt_max_rows.rdiff b/storage/myisammrg/mysql-test/storage_engine/tbl_opt_max_rows.rdiff
new file mode 100644
index 00000000000..f89147826c6
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/tbl_opt_max_rows.rdiff
@@ -0,0 +1,8 @@
+8c8
+< ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 MAX_ROWS=10000000
+---
+> ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 MAX_ROWS=10000000 INSERT_METHOD=LAST UNION=(`mrg`.`t1`)
+15c15
+< ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 MAX_ROWS=30000000
+---
+> ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 MAX_ROWS=30000000 INSERT_METHOD=LAST UNION=(`mrg`.`t1`)
diff --git a/storage/myisammrg/mysql-test/storage_engine/tbl_opt_min_rows.rdiff b/storage/myisammrg/mysql-test/storage_engine/tbl_opt_min_rows.rdiff
new file mode 100644
index 00000000000..3ce28480dcf
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/tbl_opt_min_rows.rdiff
@@ -0,0 +1,8 @@
+8c8
+< ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 MIN_ROWS=1
+---
+> ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 MIN_ROWS=1 INSERT_METHOD=LAST UNION=(`mrg`.`t1`)
+15c15
+< ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 MIN_ROWS=10000
+---
+> ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 MIN_ROWS=10000 INSERT_METHOD=LAST UNION=(`mrg`.`t1`)
diff --git a/storage/myisammrg/mysql-test/storage_engine/tbl_opt_pack_keys.rdiff b/storage/myisammrg/mysql-test/storage_engine/tbl_opt_pack_keys.rdiff
new file mode 100644
index 00000000000..246c7397a96
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/tbl_opt_pack_keys.rdiff
@@ -0,0 +1,8 @@
+8c8
+< ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 PACK_KEYS=1
+---
+> ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 PACK_KEYS=1 INSERT_METHOD=LAST UNION=(`mrg`.`t1`)
+15c15
+< ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 PACK_KEYS=0
+---
+> ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 PACK_KEYS=0 INSERT_METHOD=LAST UNION=(`mrg`.`t1`)
diff --git a/storage/myisammrg/mysql-test/storage_engine/tbl_opt_password.rdiff b/storage/myisammrg/mysql-test/storage_engine/tbl_opt_password.rdiff
new file mode 100644
index 00000000000..b1ef20c6f30
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/tbl_opt_password.rdiff
@@ -0,0 +1,8 @@
+8c8
+< ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1
+---
+> ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(`mrg`.`t1`)
+15c15
+< ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1
+---
+> ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(`mrg`.`t1`)
diff --git a/storage/myisammrg/mysql-test/storage_engine/tbl_opt_row_format.rdiff b/storage/myisammrg/mysql-test/storage_engine/tbl_opt_row_format.rdiff
new file mode 100644
index 00000000000..9c72c7c06ba
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/tbl_opt_row_format.rdiff
@@ -0,0 +1,8 @@
+8c8
+< ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 ROW_FORMAT=FIXED
+---
+> ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 ROW_FORMAT=FIXED INSERT_METHOD=LAST UNION=(`mrg`.`t1`)
+15c15
+< ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 ROW_FORMAT=DYNAMIC
+---
+> ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 ROW_FORMAT=DYNAMIC INSERT_METHOD=LAST UNION=(`mrg`.`t1`)
diff --git a/storage/myisammrg/mysql-test/storage_engine/tbl_opt_union.rdiff b/storage/myisammrg/mysql-test/storage_engine/tbl_opt_union.rdiff
new file mode 100644
index 00000000000..f77753f4d6b
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/tbl_opt_union.rdiff
@@ -0,0 +1,8 @@
+7c7
+< ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 UNION=(`child1`)
+---
+> ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(`child1`)
+13c13
+< ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 UNION=(`child1`,`child2`)
+---
+> ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(`child1`,`child2`)
diff --git a/storage/myisammrg/mysql-test/storage_engine/tbl_standard_opts.rdiff b/storage/myisammrg/mysql-test/storage_engine/tbl_standard_opts.rdiff
new file mode 100644
index 00000000000..9b7ffc6af76
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/tbl_standard_opts.rdiff
@@ -0,0 +1,8 @@
+11c11
+< ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=utf8 COMMENT='standard table options'
+---
+> ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=utf8 INSERT_METHOD=LAST UNION=(`mrg`.`t1`) COMMENT='standard table options'
+18c18
+< ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=utf8 COMMENT='table altered'
+---
+> ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=utf8 INSERT_METHOD=LAST UNION=(`mrg`.`t1`) COMMENT='table altered'
diff --git a/storage/myisammrg/mysql-test/storage_engine/tbl_temporary.rdiff b/storage/myisammrg/mysql-test/storage_engine/tbl_temporary.rdiff
new file mode 100644
index 00000000000..45a229c98eb
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/tbl_temporary.rdiff
@@ -0,0 +1,4 @@
+9c9
+< ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1
+---
+> ) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(`mrg`.`t1`)
diff --git a/storage/myisammrg/mysql-test/storage_engine/truncate_table.rdiff b/storage/myisammrg/mysql-test/storage_engine/truncate_table.rdiff
new file mode 100644
index 00000000000..3a89f730540
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/truncate_table.rdiff
@@ -0,0 +1,35 @@
+12c12
+< t1 # # # # # # # # # 1 # # # # # # #
+---
+> t1 # # # # # # # # # 0 # # # # # # #
+16c16
+< t1 # # # # # # # # # 4 # # # # # # #
+---
+> t1 # # # # # # # # # 0 # # # # # # #
+20c20
+< t1 # # # # # # # # # 1 # # # # # # #
+---
+> t1 # # # # # # # # # 0 # # # # # # #
+24c24
+< t1 # # # # # # # # # 2 # # # # # # #
+---
+> t1 # # # # # # # # # 0 # # # # # # #
+32,40c32,39
+< HANDLER h1 READ FIRST;
+< a b
+< 1 a
+< TRUNCATE TABLE t1;
+< HANDLER h1 READ NEXT;
+< ERROR 42S02: Unknown table 'h1' in HANDLER
+< HANDLER t1 OPEN AS h2;
+< HANDLER h2 READ FIRST;
+< a b
+---
+> ERROR HY000: Table storage engine for 'h1' doesn't have this option
+> # ------------ UNEXPECTED RESULT ------------
+> # The statement|command finished with ER_ILLEGAL_HA.
+> # HANDLER or the syntax or the mix could be unsupported.
+> # You can change the engine code, or create an rdiff, or disable the test by adding it to disabled.def.
+> # Further in this test, the message might sometimes be suppressed; a part of the test might be skipped.
+> # Also, this problem may cause a chain effect (more errors of different kinds in the test).
+> # -------------------------------------------
diff --git a/storage/myisammrg/mysql-test/storage_engine/trx/cons_snapshot_repeatable_read.rdiff b/storage/myisammrg/mysql-test/storage_engine/trx/cons_snapshot_repeatable_read.rdiff
new file mode 100644
index 00000000000..018b28bd24c
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/trx/cons_snapshot_repeatable_read.rdiff
@@ -0,0 +1,9 @@
+0a1,6
+> # -- WARNING ----------------------------------------------------------------
+> # According to I_S.ENGINES, MRG_MYISAM does not support transactions.
+> # If it is true, the test will most likely fail; you can
+> # either create an rdiff file, or add the test to disabled.def.
+> # If transactions should be supported, check the data in Information Schema.
+> # ---------------------------------------------------------------------------
+13a20
+> 1
diff --git a/storage/myisammrg/mysql-test/storage_engine/trx/cons_snapshot_serializable.rdiff b/storage/myisammrg/mysql-test/storage_engine/trx/cons_snapshot_serializable.rdiff
new file mode 100644
index 00000000000..018b28bd24c
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/trx/cons_snapshot_serializable.rdiff
@@ -0,0 +1,9 @@
+0a1,6
+> # -- WARNING ----------------------------------------------------------------
+> # According to I_S.ENGINES, MRG_MYISAM does not support transactions.
+> # If it is true, the test will most likely fail; you can
+> # either create an rdiff file, or add the test to disabled.def.
+> # If transactions should be supported, check the data in Information Schema.
+> # ---------------------------------------------------------------------------
+13a20
+> 1
diff --git a/storage/myisammrg/mysql-test/storage_engine/trx/delete.rdiff b/storage/myisammrg/mysql-test/storage_engine/trx/delete.rdiff
new file mode 100644
index 00000000000..45a3e5fb52d
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/trx/delete.rdiff
@@ -0,0 +1,34 @@
+0a1,12
+> # -- WARNING ----------------------------------------------------------------
+> # According to I_S.ENGINES, MRG_MYISAM does not support transactions.
+> # If it is true, the test will most likely fail; you can
+> # either create an rdiff file, or add the test to disabled.def.
+> # If transactions should be supported, check the data in Information Schema.
+> # ---------------------------------------------------------------------------
+> # -- WARNING ----------------------------------------------------------------
+> # According to I_S.ENGINES, MRG_MYISAM does not support savepoints.
+> # If it is true, the test will most likely fail; you can
+> # either create an rdiff file (recommended), or add the test to disabled.def.
+> # If savepoints should be supported, check the data in Information Schema.
+> # ---------------------------------------------------------------------------
+48a61,62
+> Warnings:
+> Warning 1196 Some non-transactional changed tables couldn't be rolled back
+51,64d64
+< 10000 foobar
+< 10000 foobar
+< 2 b
+< 2 b
+< 4 d
+< 4 d
+< 5 e
+< 5 e
+< 6 f
+< 6 f
+< 7 g
+< 7 g
+< 8 h
+< 8 h
+70a71,72
+> Warnings:
+> Warning 1196 Some non-transactional changed tables couldn't be rolled back
diff --git a/storage/myisammrg/mysql-test/storage_engine/trx/insert.rdiff b/storage/myisammrg/mysql-test/storage_engine/trx/insert.rdiff
new file mode 100644
index 00000000000..69981f90e13
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/trx/insert.rdiff
@@ -0,0 +1,32 @@
+0a1,12
+> # -- WARNING ----------------------------------------------------------------
+> # According to I_S.ENGINES, MRG_MYISAM does not support transactions.
+> # If it is true, the test will most likely fail; you can
+> # either create an rdiff file, or add the test to disabled.def.
+> # If transactions should be supported, check the data in Information Schema.
+> # ---------------------------------------------------------------------------
+> # -- WARNING ----------------------------------------------------------------
+> # According to I_S.ENGINES, MRG_MYISAM does not support savepoints.
+> # If it is true, the test will most likely fail; you can
+> # either create an rdiff file (recommended), or add the test to disabled.def.
+> # If savepoints should be supported, check the data in Information Schema.
+> # ---------------------------------------------------------------------------
+23a36,37
+> Warnings:
+> Warning 1196 Some non-transactional changed tables couldn't be rolled back
+25a40
+> 0 test
+33a49,50
+> NULL NULL
+> NULL NULL
+39a57,58
+> Warnings:
+> Warning 1196 Some non-transactional changed tables couldn't be rolled back
+43a63
+> 0 test
+49a70
+> 11 f
+54a76,78
+> NULL NULL
+> NULL NULL
+> NULL NULL
diff --git a/storage/myisammrg/mysql-test/storage_engine/trx/level_read_committed.rdiff b/storage/myisammrg/mysql-test/storage_engine/trx/level_read_committed.rdiff
new file mode 100644
index 00000000000..0837c74f5ff
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/trx/level_read_committed.rdiff
@@ -0,0 +1,44 @@
+0a1,6
+> # -- WARNING ----------------------------------------------------------------
+> # According to I_S.ENGINES, MRG_MYISAM does not support transactions.
+> # If it is true, the test will most likely fail; you can
+> # either create an rdiff file, or add the test to disabled.def.
+> # If transactions should be supported, check the data in Information Schema.
+> # ---------------------------------------------------------------------------
+18a25
+> 1
+25a33,34
+> 1
+> 2
+30a40,43
+> 1
+> 101
+> 102
+> 2
+34a48,49
+> 101
+> 102
+39a55,56
+> 101
+> 102
+44a62,63
+> 101
+> 102
+51a71,72
+> 101
+> 102
+54a76,77
+> 301
+> 302
+58a82,83
+> 101
+> 102
+61a87,88
+> 301
+> 302
+65a93,94
+> 101
+> 102
+68a98,99
+> 301
+> 302
diff --git a/storage/myisammrg/mysql-test/storage_engine/trx/level_read_uncommitted.rdiff b/storage/myisammrg/mysql-test/storage_engine/trx/level_read_uncommitted.rdiff
new file mode 100644
index 00000000000..bd9569267e5
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/trx/level_read_uncommitted.rdiff
@@ -0,0 +1,7 @@
+0a1,6
+> # -- WARNING ----------------------------------------------------------------
+> # According to I_S.ENGINES, MRG_MYISAM does not support transactions.
+> # If it is true, the test will most likely fail; you can
+> # either create an rdiff file, or add the test to disabled.def.
+> # If transactions should be supported, check the data in Information Schema.
+> # ---------------------------------------------------------------------------
diff --git a/storage/myisammrg/mysql-test/storage_engine/trx/level_repeatable_read.rdiff b/storage/myisammrg/mysql-test/storage_engine/trx/level_repeatable_read.rdiff
new file mode 100644
index 00000000000..82f7c5c5ba6
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/trx/level_repeatable_read.rdiff
@@ -0,0 +1,53 @@
+0a1,6
+> # -- WARNING ----------------------------------------------------------------
+> # According to I_S.ENGINES, MRG_MYISAM does not support transactions.
+> # If it is true, the test will most likely fail; you can
+> # either create an rdiff file, or add the test to disabled.def.
+> # If transactions should be supported, check the data in Information Schema.
+> # ---------------------------------------------------------------------------
+18a25
+> 1
+25a33,34
+> 1
+> 2
+27,28c36
+< ERROR HY000: Lock wait timeout exceeded; try restarting transaction
+< # WARNING: Statement ended with errno 1205, errname 'ER_LOCK_WAIT_TIMEOUT'.
+---
+> # WARNING: Statement ended with errno 0, errname ''.
+31a40,43
+> 1
+> 101
+> 102
+> 2
+35a48,49
+> 101
+> 102
+40a55,56
+> 101
+> 102
+44a61,64
+> 1
+> 101
+> 102
+> 2
+49a70,73
+> 1
+> 101
+> 102
+> 2
+51a76,77
+> 301
+> 302
+55a82,83
+> 101
+> 102
+58a87,88
+> 301
+> 302
+62a93,94
+> 101
+> 102
+65a98,99
+> 301
+> 302
diff --git a/storage/myisammrg/mysql-test/storage_engine/trx/level_serializable.rdiff b/storage/myisammrg/mysql-test/storage_engine/trx/level_serializable.rdiff
new file mode 100644
index 00000000000..3924b3784a9
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/trx/level_serializable.rdiff
@@ -0,0 +1,69 @@
+0a1,6
+> # -- WARNING ----------------------------------------------------------------
+> # According to I_S.ENGINES, MRG_MYISAM does not support transactions.
+> # If it is true, the test will most likely fail; you can
+> # either create an rdiff file, or add the test to disabled.def.
+> # If transactions should be supported, check the data in Information Schema.
+> # ---------------------------------------------------------------------------
+14,15c20
+< ERROR HY000: Lock wait timeout exceeded; try restarting transaction
+< # WARNING: Statement ended with errno 1205, errname 'ER_LOCK_WAIT_TIMEOUT'.
+---
+> # WARNING: Statement ended with errno 0, errname ''.
+19a25
+> 1
+22,23c28
+< ERROR HY000: Lock wait timeout exceeded; try restarting transaction
+< # WARNING: Statement ended with errno 1205, errname 'ER_LOCK_WAIT_TIMEOUT'.
+---
+> # WARNING: Statement ended with errno 0, errname ''.
+27a33,34
+> 1
+> 2
+32a40,43
+> 1
+> 101
+> 102
+> 2
+35a47,50
+> 1
+> 101
+> 102
+> 2
+38a54,57
+> 1
+> 101
+> 102
+> 2
+41a61,64
+> 1
+> 101
+> 102
+> 2
+46a70,77
+> 1
+> 101
+> 102
+> 2
+> 201
+> 202
+> 301
+> 302
+49a81,88
+> 1
+> 101
+> 102
+> 2
+> 201
+> 202
+> 301
+> 302
+52a92,99
+> 1
+> 101
+> 102
+> 2
+> 201
+> 202
+> 301
+> 302
diff --git a/storage/myisammrg/mysql-test/storage_engine/trx/select_for_update.rdiff b/storage/myisammrg/mysql-test/storage_engine/trx/select_for_update.rdiff
new file mode 100644
index 00000000000..f8ffe67586d
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/trx/select_for_update.rdiff
@@ -0,0 +1,40 @@
+0a1,6
+> # -- WARNING ----------------------------------------------------------------
+> # According to I_S.ENGINES, MRG_MYISAM does not support transactions.
+> # If it is true, the test will most likely fail; you can
+> # either create an rdiff file, or add the test to disabled.def.
+> # If transactions should be supported, check the data in Information Schema.
+> # ---------------------------------------------------------------------------
+17c23,33
+< ERROR HY000: Lock wait timeout exceeded; try restarting transaction
+---
+> a b
+> 1 a
+> 3 a
+> # ERROR: Statement succeeded (expected results: ER_LOCK_WAIT_TIMEOUT)
+> # ------------ UNEXPECTED RESULT ------------
+> # The statement|command succeeded unexpectedly.
+> # SELECT .. FOR UPDATE or LOCK IN SHARE MODE or the mix could be unsupported|malfunctioning, or the problem was caused by previous errors.
+> # You can change the engine code, or create an rdiff, or disable the test by adding it to disabled.def.
+> # Further in this test, the message might sometimes be suppressed; a part of the test might be skipped.
+> # Also, this problem may cause a chain effect (more errors of different kinds in the test).
+> # -------------------------------------------
+19c35,42
+< ERROR HY000: Lock wait timeout exceeded; try restarting transaction
+---
+> # ERROR: Statement succeeded (expected results: ER_LOCK_WAIT_TIMEOUT)
+> # ------------ UNEXPECTED RESULT ------------
+> # The statement|command succeeded unexpectedly.
+> # UPDATE or SELECT .. FOR UPDATE or the mix could be unsupported|malfunctioning, or the problem was caused by previous errors.
+> # You can change the engine code, or create an rdiff, or disable the test by adding it to disabled.def.
+> # Further in this test, the message might sometimes be suppressed; a part of the test might be skipped.
+> # Also, this problem may cause a chain effect (more errors of different kinds in the test).
+> # -------------------------------------------
+24c47
+< 1 a
+---
+> 1 c
+26c49
+< 3 a
+---
+> 3 c
diff --git a/storage/myisammrg/mysql-test/storage_engine/trx/select_lock_in_share_mode.rdiff b/storage/myisammrg/mysql-test/storage_engine/trx/select_lock_in_share_mode.rdiff
new file mode 100644
index 00000000000..e316993830a
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/trx/select_lock_in_share_mode.rdiff
@@ -0,0 +1,26 @@
+0a1,6
+> # -- WARNING ----------------------------------------------------------------
+> # According to I_S.ENGINES, MRG_MYISAM does not support transactions.
+> # If it is true, the test will most likely fail; you can
+> # either create an rdiff file, or add the test to disabled.def.
+> # If transactions should be supported, check the data in Information Schema.
+> # ---------------------------------------------------------------------------
+21c27,34
+< ERROR HY000: Lock wait timeout exceeded; try restarting transaction
+---
+> # ERROR: Statement succeeded (expected results: ER_LOCK_WAIT_TIMEOUT)
+> # ------------ UNEXPECTED RESULT ------------
+> # The statement|command succeeded unexpectedly.
+> # LOCK IN SHARE MODE or UPDATE or the mix could be unsupported|malfunctioning, or the problem was caused by previous errors.
+> # You can change the engine code, or create an rdiff, or disable the test by adding it to disabled.def.
+> # Further in this test, the message might sometimes be suppressed; a part of the test might be skipped.
+> # Also, this problem may cause a chain effect (more errors of different kinds in the test).
+> # -------------------------------------------
+26c39
+< 1 a
+---
+> 1 c
+28c41
+< 3 a
+---
+> 3 c
diff --git a/storage/myisammrg/mysql-test/storage_engine/trx/update.rdiff b/storage/myisammrg/mysql-test/storage_engine/trx/update.rdiff
new file mode 100644
index 00000000000..7ad463053eb
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/trx/update.rdiff
@@ -0,0 +1,41 @@
+0a1,12
+> # -- WARNING ----------------------------------------------------------------
+> # According to I_S.ENGINES, MRG_MYISAM does not support transactions.
+> # If it is true, the test will most likely fail; you can
+> # either create an rdiff file, or add the test to disabled.def.
+> # If transactions should be supported, check the data in Information Schema.
+> # ---------------------------------------------------------------------------
+> # -- WARNING ----------------------------------------------------------------
+> # According to I_S.ENGINES, MRG_MYISAM does not support savepoints.
+> # If it is true, the test will most likely fail; you can
+> # either create an rdiff file (recommended), or add the test to disabled.def.
+> # If savepoints should be supported, check the data in Information Schema.
+> # ---------------------------------------------------------------------------
+26a39,40
+> Warnings:
+> Warning 1196 Some non-transactional changed tables couldn't be rolled back
+31a46,47
+> Warnings:
+> Warning 1196 Some non-transactional changed tables couldn't be rolled back
+38,47c54,63
+< 51 update2
+< 51 update2
+< 52 update2
+< 52 update2
+< 53 update2
+< 53 update2
+< 54 update2
+< 54 update2
+< 55 update2
+< 55 update2
+---
+> 51
+> 51
+> 52
+> 52
+> 53
+> 53
+> 54
+> 54
+> 55
+> 55
diff --git a/storage/myisammrg/mysql-test/storage_engine/trx/xa.rdiff b/storage/myisammrg/mysql-test/storage_engine/trx/xa.rdiff
new file mode 100644
index 00000000000..ee7c2a984be
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/trx/xa.rdiff
@@ -0,0 +1,34 @@
+0a1,6
+> # -- WARNING ----------------------------------------------------------------
+> # According to I_S.ENGINES, MRG_MYISAM does not support XA.
+> # If it is true, the test will most likely fail; you can
+> # either create an rdiff file, or add the test to disabled.def.
+> # If XA should be supported, check the data in Information Schema.
+> # ---------------------------------------------------------------------------
+11a18
+> 1
+17a25,26
+> 1
+> 2
+22a32,33
+> 1
+> 2
+40a52
+> 3
+48a61,62
+> 3
+> 4
+67a82
+> 5
+77a93,94
+> 5
+> 6
+86a104,105
+> 5
+> 6
+88a108,109
+> Warnings:
+> Warning 1196 Some non-transactional changed tables couldn't be rolled back
+95a117,118
+> 5
+> 6
diff --git a/storage/myisammrg/mysql-test/storage_engine/trx/xa_recovery.rdiff b/storage/myisammrg/mysql-test/storage_engine/trx/xa_recovery.rdiff
new file mode 100644
index 00000000000..362e3a8914a
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/trx/xa_recovery.rdiff
@@ -0,0 +1,22 @@
+0a1,6
+> # -- WARNING ----------------------------------------------------------------
+> # According to I_S.ENGINES, MRG_MYISAM does not support XA.
+> # If it is true, the test will most likely fail; you can
+> # either create an rdiff file, or add the test to disabled.def.
+> # If XA should be supported, check the data in Information Schema.
+> # ---------------------------------------------------------------------------
+21,22d26
+< 1 3 0 xa1
+< 1 3 0 xa2
+23a28
+> ERROR XAE04: XAER_NOTA: Unknown XID
+24a30
+> ERROR XAE04: XAER_NOTA: Unknown XID
+26a33,34
+> 1
+> 2
+28a37,40
+> Warnings:
+> Error 145 Table './mrg/t1' is marked as crashed and should be repaired
+> Error 1194 Table 't1' is marked as crashed and should be repaired
+> Error 1034 1 client is using or hasn't closed the table properly
diff --git a/storage/myisammrg/mysql-test/storage_engine/type_char_indexes.rdiff b/storage/myisammrg/mysql-test/storage_engine/type_char_indexes.rdiff
new file mode 100644
index 00000000000..a0a418e0bcc
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/type_char_indexes.rdiff
@@ -0,0 +1,8 @@
+101c101
+< # # # range c_v c_v # # # Using index condition
+---
+> # # # ALL c_v NULL # # # Using where
+138c138
+< # # # range # v16 # # # #
+---
+> # # # ALL # NULL # # # #
diff --git a/storage/myisammrg/mysql-test/storage_engine/type_float_indexes.rdiff b/storage/myisammrg/mysql-test/storage_engine/type_float_indexes.rdiff
new file mode 100644
index 00000000000..640e1050a99
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/type_float_indexes.rdiff
@@ -0,0 +1,4 @@
+63c63
+< # # # # # d # # # #
+---
+> # # # # # NULL # # # #
diff --git a/storage/myisammrg/mysql-test/storage_engine/type_spatial.rdiff b/storage/myisammrg/mysql-test/storage_engine/type_spatial.rdiff
new file mode 100644
index 00000000000..a4d7d4390b8
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/type_spatial.rdiff
@@ -0,0 +1,706 @@
+5,698c5,14
+< CREATE TABLE gis_line (fid <INT_COLUMN>, g LINESTRING) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+< CREATE TABLE gis_polygon (fid <INT_COLUMN>, g POLYGON) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+< CREATE TABLE gis_multi_point (fid <INT_COLUMN>, g MULTIPOINT) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+< CREATE TABLE gis_multi_line (fid <INT_COLUMN>, g MULTILINESTRING) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+< CREATE TABLE gis_multi_polygon (fid <INT_COLUMN>, g MULTIPOLYGON) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+< CREATE TABLE gis_geometrycollection (fid <INT_COLUMN>, g GEOMETRYCOLLECTION) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+< CREATE TABLE gis_geometry (fid <INT_COLUMN>, g GEOMETRY) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+< USE gis_ogs;
+< CREATE TABLE lakes (fid INT <CUSTOM_COL_OPTIONS>,
+< name CHAR(64) <CUSTOM_COL_OPTIONS>,
+< shore POLYGON) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+< CREATE TABLE road_segments (fid INT <CUSTOM_COL_OPTIONS>,
+< name CHAR(64) <CUSTOM_COL_OPTIONS>,
+< aliases CHAR(64) <CUSTOM_COL_OPTIONS>,
+< num_lanes INT <CUSTOM_COL_OPTIONS>,
+< centerline LINESTRING) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+< CREATE TABLE divided_routes (fid INT <CUSTOM_COL_OPTIONS>,
+< name CHAR(64) <CUSTOM_COL_OPTIONS>,
+< num_lanes INT <CUSTOM_COL_OPTIONS>,
+< centerlines MULTILINESTRING) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+< CREATE TABLE forests (fid INT <CUSTOM_COL_OPTIONS>,
+< name CHAR(64) <CUSTOM_COL_OPTIONS>,
+< boundary MULTIPOLYGON) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+< CREATE TABLE bridges (fid INT <CUSTOM_COL_OPTIONS>,
+< name CHAR(64) <CUSTOM_COL_OPTIONS>,
+< position POINT) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+< CREATE TABLE streams (fid INT <CUSTOM_COL_OPTIONS>,
+< name CHAR(64) <CUSTOM_COL_OPTIONS>,
+< centerline LINESTRING) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+< CREATE TABLE buildings (fid INT <CUSTOM_COL_OPTIONS>,
+< name CHAR(64) <CUSTOM_COL_OPTIONS>,
+< position POINT,
+< footprint POLYGON) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+< CREATE TABLE ponds (fid INT <CUSTOM_COL_OPTIONS>,
+< name CHAR(64) <CUSTOM_COL_OPTIONS>,
+< type CHAR(64) <CUSTOM_COL_OPTIONS>,
+< shores MULTIPOLYGON) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+< CREATE TABLE named_places (fid INT <CUSTOM_COL_OPTIONS>,
+< name CHAR(64) <CUSTOM_COL_OPTIONS>,
+< boundary POLYGON) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+< CREATE TABLE map_neatlines (fid INT <CUSTOM_COL_OPTIONS>,
+< neatline POLYGON) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+< USE test;
+< SHOW FIELDS FROM gis_point;
+< Field Type Null Key Default Extra
+< fid int(11) YES NULL
+< g point YES NULL
+< SHOW FIELDS FROM gis_line;
+< Field Type Null Key Default Extra
+< fid int(11) YES NULL
+< g linestring YES NULL
+< SHOW FIELDS FROM gis_polygon;
+< Field Type Null Key Default Extra
+< fid int(11) YES NULL
+< g polygon YES NULL
+< SHOW FIELDS FROM gis_multi_point;
+< Field Type Null Key Default Extra
+< fid int(11) YES NULL
+< g multipoint YES NULL
+< SHOW FIELDS FROM gis_multi_line;
+< Field Type Null Key Default Extra
+< fid int(11) YES NULL
+< g multilinestring YES NULL
+< SHOW FIELDS FROM gis_multi_polygon;
+< Field Type Null Key Default Extra
+< fid int(11) YES NULL
+< g multipolygon YES NULL
+< SHOW FIELDS FROM gis_geometrycollection;
+< Field Type Null Key Default Extra
+< fid int(11) YES NULL
+< g geometrycollection YES NULL
+< SHOW FIELDS FROM gis_geometry;
+< Field Type Null Key Default Extra
+< fid int(11) YES NULL
+< g geometry YES NULL
+< INSERT INTO gis_point VALUES
+< (101, PointFromText('POINT(10 10)')),
+< (102, PointFromText('POINT(20 10)')),
+< (103, PointFromText('POINT(20 20)')),
+< (104, PointFromWKB(AsWKB(PointFromText('POINT(10 20)'))));
+< INSERT INTO gis_line VALUES
+< (105, LineFromText('LINESTRING(0 0,0 10,10 0)')),
+< (106, LineStringFromText('LINESTRING(10 10,20 10,20 20,10 20,10 10)')),
+< (107, LineStringFromWKB(AsWKB(LineString(Point(10, 10), Point(40, 10)))));
+< INSERT INTO gis_polygon VALUES
+< (108, PolygonFromText('POLYGON((10 10,20 10,20 20,10 20,10 10))')),
+< (109, PolyFromText('POLYGON((0 0,50 0,50 50,0 50,0 0), (10 10,20 10,20 20,10 20,10 10))')),
+< (110, PolyFromWKB(AsWKB(Polygon(LineString(Point(0, 0), Point(30, 0), Point(30, 30), Point(0, 0))))));
+< INSERT INTO gis_multi_point VALUES
+< (111, MultiPointFromText('MULTIPOINT(0 0,10 10,10 20,20 20)')),
+< (112, MPointFromText('MULTIPOINT(1 1,11 11,11 21,21 21)')),
+< (113, MPointFromWKB(AsWKB(MultiPoint(Point(3, 6), Point(4, 10)))));
+< INSERT INTO gis_multi_line VALUES
+< (114, MultiLineStringFromText('MULTILINESTRING((10 48,10 21,10 0),(16 0,16 23,16 48))')),
+< (115, MLineFromText('MULTILINESTRING((10 48,10 21,10 0))')),
+< (116, MLineFromWKB(AsWKB(MultiLineString(LineString(Point(1, 2), Point(3, 5)), LineString(Point(2, 5), Point(5, 8), Point(21, 7))))));
+< INSERT INTO gis_multi_polygon VALUES
+< (117, MultiPolygonFromText('MULTIPOLYGON(((28 26,28 0,84 0,84 42,28 26),(52 18,66 23,73 9,48 6,52 18)),((59 18,67 18,67 13,59 13,59 18)))')),
+< (118, MPolyFromText('MULTIPOLYGON(((28 26,28 0,84 0,84 42,28 26),(52 18,66 23,73 9,48 6,52 18)),((59 18,67 18,67 13,59 13,59 18)))')),
+< (119, MPolyFromWKB(AsWKB(MultiPolygon(Polygon(LineString(Point(0, 3), Point(3, 3), Point(3, 0), Point(0, 3)))))));
+< INSERT INTO gis_geometrycollection VALUES
+< (120, GeomCollFromText('GEOMETRYCOLLECTION(POINT(0 0), LINESTRING(0 0,10 10))')),
+< (121, GeometryFromWKB(AsWKB(GeometryCollection(Point(44, 6), LineString(Point(3, 6), Point(7, 9)))))),
+< (122, GeomFromText('GeometryCollection()')),
+< (123, GeomFromText('GeometryCollection EMPTY'));
+< INSERT into gis_geometry SELECT * FROM gis_point;
+< INSERT into gis_geometry SELECT * FROM gis_line;
+< INSERT into gis_geometry SELECT * FROM gis_polygon;
+< INSERT into gis_geometry SELECT * FROM gis_multi_point;
+< INSERT into gis_geometry SELECT * FROM gis_multi_line;
+< INSERT into gis_geometry SELECT * FROM gis_multi_polygon;
+< INSERT into gis_geometry SELECT * FROM gis_geometrycollection;
+< SELECT fid, AsText(g) FROM gis_point;
+< fid AsText(g)
+< 101 POINT(10 10)
+< 102 POINT(20 10)
+< 103 POINT(20 20)
+< 104 POINT(10 20)
+< SELECT fid, AsText(g) FROM gis_line;
+< fid AsText(g)
+< 105 LINESTRING(0 0,0 10,10 0)
+< 106 LINESTRING(10 10,20 10,20 20,10 20,10 10)
+< 107 LINESTRING(10 10,40 10)
+< SELECT fid, AsText(g) FROM gis_polygon;
+< fid AsText(g)
+< 108 POLYGON((10 10,20 10,20 20,10 20,10 10))
+< 109 POLYGON((0 0,50 0,50 50,0 50,0 0),(10 10,20 10,20 20,10 20,10 10))
+< 110 POLYGON((0 0,30 0,30 30,0 0))
+< SELECT fid, AsText(g) FROM gis_multi_point;
+< fid AsText(g)
+< 111 MULTIPOINT(0 0,10 10,10 20,20 20)
+< 112 MULTIPOINT(1 1,11 11,11 21,21 21)
+< 113 MULTIPOINT(3 6,4 10)
+< SELECT fid, AsText(g) FROM gis_multi_line;
+< fid AsText(g)
+< 114 MULTILINESTRING((10 48,10 21,10 0),(16 0,16 23,16 48))
+< 115 MULTILINESTRING((10 48,10 21,10 0))
+< 116 MULTILINESTRING((1 2,3 5),(2 5,5 8,21 7))
+< SELECT fid, AsText(g) FROM gis_multi_polygon;
+< fid AsText(g)
+< 117 MULTIPOLYGON(((28 26,28 0,84 0,84 42,28 26),(52 18,66 23,73 9,48 6,52 18)),((59 18,67 18,67 13,59 13,59 18)))
+< 118 MULTIPOLYGON(((28 26,28 0,84 0,84 42,28 26),(52 18,66 23,73 9,48 6,52 18)),((59 18,67 18,67 13,59 13,59 18)))
+< 119 MULTIPOLYGON(((0 3,3 3,3 0,0 3)))
+< SELECT fid, AsText(g) FROM gis_geometrycollection;
+< fid AsText(g)
+< 120 GEOMETRYCOLLECTION(POINT(0 0),LINESTRING(0 0,10 10))
+< 121 GEOMETRYCOLLECTION(POINT(44 6),LINESTRING(3 6,7 9))
+< 122 GEOMETRYCOLLECTION EMPTY
+< 123 GEOMETRYCOLLECTION EMPTY
+< SELECT fid, AsText(g) FROM gis_geometry;
+< fid AsText(g)
+< 101 POINT(10 10)
+< 102 POINT(20 10)
+< 103 POINT(20 20)
+< 104 POINT(10 20)
+< 105 LINESTRING(0 0,0 10,10 0)
+< 106 LINESTRING(10 10,20 10,20 20,10 20,10 10)
+< 107 LINESTRING(10 10,40 10)
+< 108 POLYGON((10 10,20 10,20 20,10 20,10 10))
+< 109 POLYGON((0 0,50 0,50 50,0 50,0 0),(10 10,20 10,20 20,10 20,10 10))
+< 110 POLYGON((0 0,30 0,30 30,0 0))
+< 111 MULTIPOINT(0 0,10 10,10 20,20 20)
+< 112 MULTIPOINT(1 1,11 11,11 21,21 21)
+< 113 MULTIPOINT(3 6,4 10)
+< 114 MULTILINESTRING((10 48,10 21,10 0),(16 0,16 23,16 48))
+< 115 MULTILINESTRING((10 48,10 21,10 0))
+< 116 MULTILINESTRING((1 2,3 5),(2 5,5 8,21 7))
+< 117 MULTIPOLYGON(((28 26,28 0,84 0,84 42,28 26),(52 18,66 23,73 9,48 6,52 18)),((59 18,67 18,67 13,59 13,59 18)))
+< 118 MULTIPOLYGON(((28 26,28 0,84 0,84 42,28 26),(52 18,66 23,73 9,48 6,52 18)),((59 18,67 18,67 13,59 13,59 18)))
+< 119 MULTIPOLYGON(((0 3,3 3,3 0,0 3)))
+< 120 GEOMETRYCOLLECTION(POINT(0 0),LINESTRING(0 0,10 10))
+< 121 GEOMETRYCOLLECTION(POINT(44 6),LINESTRING(3 6,7 9))
+< 122 GEOMETRYCOLLECTION EMPTY
+< 123 GEOMETRYCOLLECTION EMPTY
+< SELECT fid, Dimension(g) FROM gis_geometry;
+< fid Dimension(g)
+< 101 0
+< 102 0
+< 103 0
+< 104 0
+< 105 1
+< 106 1
+< 107 1
+< 108 2
+< 109 2
+< 110 2
+< 111 0
+< 112 0
+< 113 0
+< 114 1
+< 115 1
+< 116 1
+< 117 2
+< 118 2
+< 119 2
+< 120 1
+< 121 1
+< 122 0
+< 123 0
+< SELECT fid, GeometryType(g) FROM gis_geometry;
+< fid GeometryType(g)
+< 101 POINT
+< 102 POINT
+< 103 POINT
+< 104 POINT
+< 105 LINESTRING
+< 106 LINESTRING
+< 107 LINESTRING
+< 108 POLYGON
+< 109 POLYGON
+< 110 POLYGON
+< 111 MULTIPOINT
+< 112 MULTIPOINT
+< 113 MULTIPOINT
+< 114 MULTILINESTRING
+< 115 MULTILINESTRING
+< 116 MULTILINESTRING
+< 117 MULTIPOLYGON
+< 118 MULTIPOLYGON
+< 119 MULTIPOLYGON
+< 120 GEOMETRYCOLLECTION
+< 121 GEOMETRYCOLLECTION
+< 122 GEOMETRYCOLLECTION
+< 123 GEOMETRYCOLLECTION
+< SELECT fid, IsEmpty(g) FROM gis_geometry;
+< fid IsEmpty(g)
+< 101 0
+< 102 0
+< 103 0
+< 104 0
+< 105 0
+< 106 0
+< 107 0
+< 108 0
+< 109 0
+< 110 0
+< 111 0
+< 112 0
+< 113 0
+< 114 0
+< 115 0
+< 116 0
+< 117 0
+< 118 0
+< 119 0
+< 120 0
+< 121 0
+< 122 0
+< 123 0
+< SELECT fid, AsText(Envelope(g)) FROM gis_geometry;
+< fid AsText(Envelope(g))
+< 101 POLYGON((10 10,10 10,10 10,10 10,10 10))
+< 102 POLYGON((20 10,20 10,20 10,20 10,20 10))
+< 103 POLYGON((20 20,20 20,20 20,20 20,20 20))
+< 104 POLYGON((10 20,10 20,10 20,10 20,10 20))
+< 105 POLYGON((0 0,10 0,10 10,0 10,0 0))
+< 106 POLYGON((10 10,20 10,20 20,10 20,10 10))
+< 107 POLYGON((10 10,40 10,40 10,10 10,10 10))
+< 108 POLYGON((10 10,20 10,20 20,10 20,10 10))
+< 109 POLYGON((0 0,50 0,50 50,0 50,0 0))
+< 110 POLYGON((0 0,30 0,30 30,0 30,0 0))
+< 111 POLYGON((0 0,20 0,20 20,0 20,0 0))
+< 112 POLYGON((1 1,21 1,21 21,1 21,1 1))
+< 113 POLYGON((3 6,4 6,4 10,3 10,3 6))
+< 114 POLYGON((10 0,16 0,16 48,10 48,10 0))
+< 115 POLYGON((10 0,10 0,10 48,10 48,10 0))
+< 116 POLYGON((1 2,21 2,21 8,1 8,1 2))
+< 117 POLYGON((28 0,84 0,84 42,28 42,28 0))
+< 118 POLYGON((28 0,84 0,84 42,28 42,28 0))
+< 119 POLYGON((0 0,3 0,3 3,0 3,0 0))
+< 120 POLYGON((0 0,10 0,10 10,0 10,0 0))
+< 121 POLYGON((3 6,44 6,44 9,3 9,3 6))
+< 122 GEOMETRYCOLLECTION EMPTY
+< 123 GEOMETRYCOLLECTION EMPTY
+< SELECT fid, X(g) FROM gis_point;
+< fid X(g)
+< 101 10
+< 102 20
+< 103 20
+< 104 10
+< SELECT fid, Y(g) FROM gis_point;
+< fid Y(g)
+< 101 10
+< 102 10
+< 103 20
+< 104 20
+< SELECT fid, AsText(StartPoint(g)) FROM gis_line;
+< fid AsText(StartPoint(g))
+< 105 POINT(0 0)
+< 106 POINT(10 10)
+< 107 POINT(10 10)
+< SELECT fid, AsText(EndPoint(g)) FROM gis_line;
+< fid AsText(EndPoint(g))
+< 105 POINT(10 0)
+< 106 POINT(10 10)
+< 107 POINT(40 10)
+< SELECT fid, GLength(g) FROM gis_line;
+< fid GLength(g)
+< 105 24.14213562373095
+< 106 40
+< 107 30
+< SELECT fid, NumPoints(g) FROM gis_line;
+< fid NumPoints(g)
+< 105 3
+< 106 5
+< 107 2
+< SELECT fid, AsText(PointN(g, 2)) FROM gis_line;
+< fid AsText(PointN(g, 2))
+< 105 POINT(0 10)
+< 106 POINT(20 10)
+< 107 POINT(40 10)
+< SELECT fid, IsClosed(g) FROM gis_line;
+< fid IsClosed(g)
+< 105 0
+< 106 1
+< 107 0
+< SELECT fid, AsText(Centroid(g)) FROM gis_polygon;
+< fid AsText(Centroid(g))
+< 108 POINT(15 15)
+< 109 POINT(25.416666666666668 25.416666666666668)
+< 110 POINT(20 10)
+< SELECT fid, Area(g) FROM gis_polygon;
+< fid Area(g)
+< 108 100
+< 109 2400
+< 110 450
+< SELECT fid, AsText(ExteriorRing(g)) FROM gis_polygon;
+< fid AsText(ExteriorRing(g))
+< 108 LINESTRING(10 10,20 10,20 20,10 20,10 10)
+< 109 LINESTRING(0 0,50 0,50 50,0 50,0 0)
+< 110 LINESTRING(0 0,30 0,30 30,0 0)
+< SELECT fid, NumInteriorRings(g) FROM gis_polygon;
+< fid NumInteriorRings(g)
+< 108 0
+< 109 1
+< 110 0
+< SELECT fid, AsText(InteriorRingN(g, 1)) FROM gis_polygon;
+< fid AsText(InteriorRingN(g, 1))
+< 108 NULL
+< 109 LINESTRING(10 10,20 10,20 20,10 20,10 10)
+< 110 NULL
+< SELECT fid, IsClosed(g) FROM gis_multi_line;
+< fid IsClosed(g)
+< 114 0
+< 115 0
+< 116 0
+< SELECT fid, AsText(Centroid(g)) FROM gis_multi_polygon;
+< fid AsText(Centroid(g))
+< 117 POINT(55.58852775304245 17.426536064113982)
+< 118 POINT(55.58852775304245 17.426536064113982)
+< 119 POINT(2 2)
+< SELECT fid, Area(g) FROM gis_multi_polygon;
+< fid Area(g)
+< 117 1684.5
+< 118 1684.5
+< 119 4.5
+< SELECT fid, NumGeometries(g) from gis_multi_point;
+< fid NumGeometries(g)
+< 111 4
+< 112 4
+< 113 2
+< SELECT fid, NumGeometries(g) from gis_multi_line;
+< fid NumGeometries(g)
+< 114 2
+< 115 1
+< 116 2
+< SELECT fid, NumGeometries(g) from gis_multi_polygon;
+< fid NumGeometries(g)
+< 117 2
+< 118 2
+< 119 1
+< SELECT fid, NumGeometries(g) from gis_geometrycollection;
+< fid NumGeometries(g)
+< 120 2
+< 121 2
+< 122 0
+< 123 0
+< SELECT fid, AsText(GeometryN(g, 2)) from gis_multi_point;
+< fid AsText(GeometryN(g, 2))
+< 111 POINT(10 10)
+< 112 POINT(11 11)
+< 113 POINT(4 10)
+< SELECT fid, AsText(GeometryN(g, 2)) from gis_multi_line;
+< fid AsText(GeometryN(g, 2))
+< 114 LINESTRING(16 0,16 23,16 48)
+< 115 NULL
+< 116 LINESTRING(2 5,5 8,21 7)
+< SELECT fid, AsText(GeometryN(g, 2)) from gis_multi_polygon;
+< fid AsText(GeometryN(g, 2))
+< 117 POLYGON((59 18,67 18,67 13,59 13,59 18))
+< 118 POLYGON((59 18,67 18,67 13,59 13,59 18))
+< 119 NULL
+< SELECT fid, AsText(GeometryN(g, 2)) from gis_geometrycollection;
+< fid AsText(GeometryN(g, 2))
+< 120 LINESTRING(0 0,10 10)
+< 121 LINESTRING(3 6,7 9)
+< 122 NULL
+< 123 NULL
+< SELECT fid, AsText(GeometryN(g, 1)) from gis_geometrycollection;
+< fid AsText(GeometryN(g, 1))
+< 120 POINT(0 0)
+< 121 POINT(44 6)
+< 122 NULL
+< 123 NULL
+< SELECT g1.fid as first, g2.fid as second,
+< Within(g1.g, g2.g) as w, Contains(g1.g, g2.g) as c, Overlaps(g1.g, g2.g) as o,
+< Equals(g1.g, g2.g) as e, Disjoint(g1.g, g2.g) as d, Touches(g1.g, g2.g) as t,
+< Intersects(g1.g, g2.g) as i, Crosses(g1.g, g2.g) as r
+< FROM gis_geometrycollection g1, gis_geometrycollection g2 ORDER BY first, second;
+< first second w c o e d t i r
+< 120 120 1 1 0 1 0 1 1 0
+< 120 121 0 0 1 0 0 0 1 0
+< 120 122 0 1 NULL 0 NULL 0 NULL 0
+< 120 123 0 1 NULL 0 NULL 0 NULL 0
+< 121 120 0 0 1 0 0 0 1 0
+< 121 121 1 1 0 1 0 1 1 0
+< 121 122 0 1 NULL 0 NULL 0 NULL 0
+< 121 123 0 1 NULL 0 NULL 0 NULL 0
+< 122 120 1 0 NULL 0 NULL 0 NULL 0
+< 122 121 1 0 NULL 0 NULL 0 NULL 0
+< 122 122 1 1 NULL 1 NULL 0 NULL 0
+< 122 123 1 1 NULL 1 NULL 0 NULL 0
+< 123 120 1 0 NULL 0 NULL 0 NULL 0
+< 123 121 1 0 NULL 0 NULL 0 NULL 0
+< 123 122 1 1 NULL 1 NULL 0 NULL 0
+< 123 123 1 1 NULL 1 NULL 0 NULL 0
+< DROP TABLE gis_point, gis_line, gis_polygon, gis_multi_point, gis_multi_line, gis_multi_polygon, gis_geometrycollection, gis_geometry;
+< USE gis_ogs;
+< # Lakes
+< INSERT INTO lakes VALUES (
+< 101, 'BLUE LAKE',
+< PolyFromText(
+< 'POLYGON(
+< (52 18,66 23,73 9,48 6,52 18),
+< (59 18,67 18,67 13,59 13,59 18)
+< )',
+< 101));
+< # Road Segments
+< INSERT INTO road_segments VALUES(102, 'Route 5', NULL, 2,
+< LineFromText(
+< 'LINESTRING( 0 18, 10 21, 16 23, 28 26, 44 31 )' ,101));
+< INSERT INTO road_segments VALUES(103, 'Route 5', 'Main Street', 4,
+< LineFromText(
+< 'LINESTRING( 44 31, 56 34, 70 38 )' ,101));
+< INSERT INTO road_segments VALUES(104, 'Route 5', NULL, 2,
+< LineFromText(
+< 'LINESTRING( 70 38, 72 48 )' ,101));
+< INSERT INTO road_segments VALUES(105, 'Main Street', NULL, 4,
+< LineFromText(
+< 'LINESTRING( 70 38, 84 42 )' ,101));
+< INSERT INTO road_segments VALUES(106, 'Dirt Road by Green Forest', NULL,
+< 1,
+< LineFromText(
+< 'LINESTRING( 28 26, 28 0 )',101));
+< # DividedRoutes
+< INSERT INTO divided_routes VALUES(119, 'Route 75', 4,
+< MLineFromText(
+< 'MULTILINESTRING((10 48,10 21,10 0),
+< (16 0,16 23,16 48))', 101));
+< # Forests
+< INSERT INTO forests VALUES(109, 'Green Forest',
+< MPolyFromText(
+< 'MULTIPOLYGON(((28 26,28 0,84 0,84 42,28 26),
+< (52 18,66 23,73 9,48 6,52 18)),((59 18,67 18,67 13,59 13,59 18)))',
+< 101));
+< # Bridges
+< INSERT INTO bridges VALUES(110, 'Cam Bridge', PointFromText(
+< 'POINT( 44 31 )', 101));
+< # Streams
+< INSERT INTO streams VALUES(111, 'Cam Stream',
+< LineFromText(
+< 'LINESTRING( 38 48, 44 41, 41 36, 44 31, 52 18 )', 101));
+< INSERT INTO streams VALUES(112, NULL,
+< LineFromText(
+< 'LINESTRING( 76 0, 78 4, 73 9 )', 101));
+< # Buildings
+< INSERT INTO buildings VALUES(113, '123 Main Street',
+< PointFromText(
+< 'POINT( 52 30 )', 101),
+< PolyFromText(
+< 'POLYGON( ( 50 31, 54 31, 54 29, 50 29, 50 31) )', 101));
+< INSERT INTO buildings VALUES(114, '215 Main Street',
+< PointFromText(
+< 'POINT( 64 33 )', 101),
+< PolyFromText(
+< 'POLYGON( ( 66 34, 62 34, 62 32, 66 32, 66 34) )', 101));
+< # Ponds
+< INSERT INTO ponds VALUES(120, NULL, 'Stock Pond',
+< MPolyFromText(
+< 'MULTIPOLYGON( ( ( 24 44, 22 42, 24 40, 24 44) ),
+< ( ( 26 44, 26 40, 28 42, 26 44) ) )', 101));
+< # Named Places
+< INSERT INTO named_places VALUES(117, 'Ashton',
+< PolyFromText(
+< 'POLYGON( ( 62 48, 84 48, 84 30, 56 30, 56 34, 62 48) )', 101));
+< INSERT INTO named_places VALUES(118, 'Goose Island',
+< PolyFromText(
+< 'POLYGON( ( 67 13, 67 18, 59 18, 59 13, 67 13) )', 101));
+< # Map Neatlines
+< INSERT INTO map_neatlines VALUES(115,
+< PolyFromText(
+< 'POLYGON( ( 0 0, 0 48, 84 48, 84 0, 0 0 ) )', 101));
+< SELECT Dimension(shore)
+< FROM lakes
+< WHERE name = 'Blue Lake';
+< Dimension(shore)
+< 2
+< SELECT GeometryType(centerlines)
+< FROM divided_routes
+< WHERE name = 'Route 75';
+< GeometryType(centerlines)
+< MULTILINESTRING
+< SELECT AsText(boundary)
+< FROM named_places
+< WHERE name = 'Goose Island';
+< AsText(boundary)
+< POLYGON((67 13,67 18,59 18,59 13,67 13))
+< SELECT AsText(PolyFromWKB(AsBinary(boundary),101))
+< FROM named_places
+< WHERE name = 'Goose Island';
+< AsText(PolyFromWKB(AsBinary(boundary),101))
+< POLYGON((67 13,67 18,59 18,59 13,67 13))
+< SELECT SRID(boundary)
+< FROM named_places
+< WHERE name = 'Goose Island';
+< SRID(boundary)
+< 101
+< SELECT IsEmpty(centerline)
+< FROM road_segments
+< WHERE name = 'Route 5'
+< AND aliases = 'Main Street';
+< IsEmpty(centerline)
+< 0
+< SELECT AsText(Envelope(boundary))
+< FROM named_places
+< WHERE name = 'Goose Island';
+< AsText(Envelope(boundary))
+< POLYGON((59 13,67 13,67 18,59 18,59 13))
+< SELECT X(position)
+< FROM bridges
+< WHERE name = 'Cam Bridge';
+< X(position)
+< 44
+< SELECT Y(position)
+< FROM bridges
+< WHERE name = 'Cam Bridge';
+< Y(position)
+< 31
+< SELECT AsText(StartPoint(centerline))
+< FROM road_segments
+< WHERE fid = 102;
+< AsText(StartPoint(centerline))
+< POINT(0 18)
+< SELECT AsText(EndPoint(centerline))
+< FROM road_segments
+< WHERE fid = 102;
+< AsText(EndPoint(centerline))
+< POINT(44 31)
+< SELECT GLength(centerline)
+< FROM road_segments
+< WHERE fid = 106;
+< GLength(centerline)
+< 26
+< SELECT NumPoints(centerline)
+< FROM road_segments
+< WHERE fid = 102;
+< NumPoints(centerline)
+< 5
+< SELECT AsText(PointN(centerline, 1))
+< FROM road_segments
+< WHERE fid = 102;
+< AsText(PointN(centerline, 1))
+< POINT(0 18)
+< SELECT AsText(Centroid(boundary))
+< FROM named_places
+< WHERE name = 'Goose Island';
+< AsText(Centroid(boundary))
+< POINT(63 15.5)
+< SELECT Area(boundary)
+< FROM named_places
+< WHERE name = 'Goose Island';
+< Area(boundary)
+< 40
+< SELECT AsText(ExteriorRing(shore))
+< FROM lakes
+< WHERE name = 'Blue Lake';
+< AsText(ExteriorRing(shore))
+< LINESTRING(52 18,66 23,73 9,48 6,52 18)
+< SELECT NumInteriorRings(shore)
+< FROM lakes
+< WHERE name = 'Blue Lake';
+< NumInteriorRings(shore)
+< 1
+< SELECT AsText(InteriorRingN(shore, 1))
+< FROM lakes
+< WHERE name = 'Blue Lake';
+< AsText(InteriorRingN(shore, 1))
+< LINESTRING(59 18,67 18,67 13,59 13,59 18)
+< SELECT NumGeometries(centerlines)
+< FROM divided_routes
+< WHERE name = 'Route 75';
+< NumGeometries(centerlines)
+< 2
+< SELECT AsText(GeometryN(centerlines, 2))
+< FROM divided_routes
+< WHERE name = 'Route 75';
+< AsText(GeometryN(centerlines, 2))
+< LINESTRING(16 0,16 23,16 48)
+< SELECT IsClosed(centerlines)
+< FROM divided_routes
+< WHERE name = 'Route 75';
+< IsClosed(centerlines)
+< 0
+< SELECT GLength(centerlines)
+< FROM divided_routes
+< WHERE name = 'Route 75';
+< GLength(centerlines)
+< 96
+< SELECT AsText(Centroid(shores))
+< FROM ponds
+< WHERE fid = 120;
+< AsText(Centroid(shores))
+< POINT(25 42)
+< SELECT Area(shores)
+< FROM ponds
+< WHERE fid = 120;
+< Area(shores)
+< 8
+< SELECT ST_Equals(boundary,
+< PolyFromText('POLYGON( ( 67 13, 67 18, 59 18, 59 13, 67 13) )',1))
+< FROM named_places
+< WHERE name = 'Goose Island';
+< ST_Equals(boundary,
+< PolyFromText('POLYGON( ( 67 13, 67 18, 59 18, 59 13, 67 13) )',1))
+< 1
+< SELECT ST_Disjoint(centerlines, boundary)
+< FROM divided_routes, named_places
+< WHERE divided_routes.name = 'Route 75'
+< AND named_places.name = 'Ashton';
+< ST_Disjoint(centerlines, boundary)
+< 1
+< SELECT ST_Touches(centerline, shore)
+< FROM streams, lakes
+< WHERE streams.name = 'Cam Stream'
+< AND lakes.name = 'Blue Lake';
+< ST_Touches(centerline, shore)
+< 1
+< SELECT Crosses(road_segments.centerline, divided_routes.centerlines)
+< FROM road_segments, divided_routes
+< WHERE road_segments.fid = 102
+< AND divided_routes.name = 'Route 75';
+< Crosses(road_segments.centerline, divided_routes.centerlines)
+< 1
+< SELECT ST_Intersects(road_segments.centerline, divided_routes.centerlines)
+< FROM road_segments, divided_routes
+< WHERE road_segments.fid = 102
+< AND divided_routes.name = 'Route 75';
+< ST_Intersects(road_segments.centerline, divided_routes.centerlines)
+< 1
+< SELECT ST_Contains(forests.boundary, named_places.boundary)
+< FROM forests, named_places
+< WHERE forests.name = 'Green Forest'
+< AND named_places.name = 'Ashton';
+< ST_Contains(forests.boundary, named_places.boundary)
+< 0
+< SELECT ST_Distance(position, boundary)
+< FROM bridges, named_places
+< WHERE bridges.name = 'Cam Bridge'
+< AND named_places.name = 'Ashton';
+< ST_Distance(position, boundary)
+< 12
+< SELECT AsText(ST_Difference(named_places.boundary, forests.boundary))
+< FROM named_places, forests
+< WHERE named_places.name = 'Ashton'
+< AND forests.name = 'Green Forest';
+< AsText(ST_Difference(named_places.boundary, forests.boundary))
+< POLYGON((56 34,62 48,84 48,84 42,56 34))
+< SELECT AsText(ST_Union(shore, boundary))
+< FROM lakes, named_places
+< WHERE lakes.name = 'Blue Lake'
+< AND named_places.name = 'Goose Island';
+< AsText(ST_Union(shore, boundary))
+< POLYGON((48 6,52 18,66 23,73 9,48 6))
+< SELECT AsText(ST_SymDifference(shore, boundary))
+< FROM lakes, named_places
+< WHERE lakes.name = 'Blue Lake'
+< AND named_places.name = 'Ashton';
+< AsText(ST_SymDifference(shore, boundary))
+< MULTIPOLYGON(((48 6,52 18,66 23,73 9,48 6),(59 13,59 18,67 18,67 13,59 13)),((56 30,56 34,62 48,84 48,84 30,56 30)))
+< SELECT count(*)
+< FROM buildings, bridges
+< WHERE ST_Contains(ST_Buffer(bridges.position, 15.0), buildings.footprint) = 1;
+< count(*)
+< 1
+---
+> ERROR 42000: The storage engine for the table doesn't support GEOMETRY
+> # ERROR: Statement ended with errno 1178, errname ER_CHECK_NOT_IMPLEMENTED (expected to succeed)
+> # ------------ UNEXPECTED RESULT ------------
+> # [ CREATE TABLE gis_point (fid INT(11) /*!*/ /*Custom column options*/, g POINT) ENGINE=MRG_MYISAM /*!*/ /*Custom table options*/ UNION(mrg.gis_point) INSERT_METHOD=LAST ]
+> # The statement|command finished with ER_CHECK_NOT_IMPLEMENTED.
+> # Geometry types or the mix could be unsupported|malfunctioning, or the problem was caused by previous errors.
+> # You can change the engine code, or create an rdiff, or disable the test by adding it to disabled.def.
+> # Further in this test, the message might sometimes be suppressed; a part of the test might be skipped.
+> # Also, this problem may cause a chain effect (more errors of different kinds in the test).
+> # -------------------------------------------
diff --git a/storage/myisammrg/mysql-test/storage_engine/type_spatial_indexes.rdiff b/storage/myisammrg/mysql-test/storage_engine/type_spatial_indexes.rdiff
new file mode 100644
index 00000000000..89f1100f550
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/type_spatial_indexes.rdiff
@@ -0,0 +1,1412 @@
+5,698c5,14
+< CREATE TABLE gis_line (fid <INT_COLUMN>, g LINESTRING, <CUSTOM_INDEX> g(g(256))) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+< CREATE TABLE gis_polygon (fid <INT_COLUMN>, g POLYGON, <CUSTOM_INDEX> g(g(512))) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+< CREATE TABLE gis_multi_point (fid <INT_COLUMN>, g MULTIPOINT, <CUSTOM_INDEX> g(g(128))) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+< CREATE TABLE gis_multi_line (fid <INT_COLUMN>, g MULTILINESTRING, <CUSTOM_INDEX> g(g(256))) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+< CREATE TABLE gis_multi_polygon (fid <INT_COLUMN>, g MULTIPOLYGON) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+< CREATE TABLE gis_geometrycollection (fid <INT_COLUMN>, g GEOMETRYCOLLECTION) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+< CREATE TABLE gis_geometry (fid <INT_COLUMN>, g GEOMETRY) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+< USE gis_ogs;
+< CREATE TABLE lakes (fid INT <CUSTOM_COL_OPTIONS>,
+< name CHAR(64) <CUSTOM_COL_OPTIONS>,
+< shore POLYGON, <CUSTOM_INDEX> s(shore(64))) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+< CREATE TABLE road_segments (fid INT <CUSTOM_COL_OPTIONS>,
+< name CHAR(64) <CUSTOM_COL_OPTIONS>,
+< aliases CHAR(64) <CUSTOM_COL_OPTIONS>,
+< num_lanes INT <CUSTOM_COL_OPTIONS>,
+< centerline LINESTRING, <CUSTOM_INDEX> c(centerline(128))) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+< CREATE TABLE divided_routes (fid INT <CUSTOM_COL_OPTIONS>,
+< name CHAR(64) <CUSTOM_COL_OPTIONS>,
+< num_lanes INT <CUSTOM_COL_OPTIONS>,
+< centerlines MULTILINESTRING, <CUSTOM_INDEX> c(centerlines(512))) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+< CREATE TABLE forests (fid INT <CUSTOM_COL_OPTIONS>,
+< name CHAR(64) <CUSTOM_COL_OPTIONS>,
+< boundary MULTIPOLYGON, <CUSTOM_INDEX> b(boundary(128))) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+< CREATE TABLE bridges (fid INT <CUSTOM_COL_OPTIONS>,
+< name CHAR(64) <CUSTOM_COL_OPTIONS>,
+< position POINT, <CUSTOM_INDEX> p(`position`(64))) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+< CREATE TABLE streams (fid INT <CUSTOM_COL_OPTIONS>,
+< name CHAR(64) <CUSTOM_COL_OPTIONS>,
+< centerline LINESTRING, <CUSTOM_INDEX> c(centerline(256))) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+< CREATE TABLE buildings (fid INT <CUSTOM_COL_OPTIONS>,
+< name CHAR(64) <CUSTOM_COL_OPTIONS>,
+< position POINT,
+< footprint POLYGON, <CUSTOM_INDEX> p(`position`(64)), <CUSTOM_INDEX> f(footprint(128))) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+< CREATE TABLE ponds (fid INT <CUSTOM_COL_OPTIONS>,
+< name CHAR(64) <CUSTOM_COL_OPTIONS>,
+< type CHAR(64) <CUSTOM_COL_OPTIONS>,
+< shores MULTIPOLYGON, <CUSTOM_INDEX> s(shores(256))) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+< CREATE TABLE named_places (fid INT <CUSTOM_COL_OPTIONS>,
+< name CHAR(64) <CUSTOM_COL_OPTIONS>,
+< boundary POLYGON, <CUSTOM_INDEX> b(boundary(512))) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+< CREATE TABLE map_neatlines (fid INT <CUSTOM_COL_OPTIONS>,
+< neatline POLYGON, <CUSTOM_INDEX> n(neatline(700))) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+< USE test;
+< SHOW FIELDS FROM gis_point;
+< Field Type Null Key Default Extra
+< fid int(11) YES NULL
+< g point YES MUL NULL
+< SHOW FIELDS FROM gis_line;
+< Field Type Null Key Default Extra
+< fid int(11) YES NULL
+< g linestring YES MUL NULL
+< SHOW FIELDS FROM gis_polygon;
+< Field Type Null Key Default Extra
+< fid int(11) YES NULL
+< g polygon YES MUL NULL
+< SHOW FIELDS FROM gis_multi_point;
+< Field Type Null Key Default Extra
+< fid int(11) YES NULL
+< g multipoint YES MUL NULL
+< SHOW FIELDS FROM gis_multi_line;
+< Field Type Null Key Default Extra
+< fid int(11) YES NULL
+< g multilinestring YES MUL NULL
+< SHOW FIELDS FROM gis_multi_polygon;
+< Field Type Null Key Default Extra
+< fid int(11) YES NULL
+< g multipolygon YES NULL
+< SHOW FIELDS FROM gis_geometrycollection;
+< Field Type Null Key Default Extra
+< fid int(11) YES NULL
+< g geometrycollection YES NULL
+< SHOW FIELDS FROM gis_geometry;
+< Field Type Null Key Default Extra
+< fid int(11) YES NULL
+< g geometry YES NULL
+< INSERT INTO gis_point VALUES
+< (101, PointFromText('POINT(10 10)')),
+< (102, PointFromText('POINT(20 10)')),
+< (103, PointFromText('POINT(20 20)')),
+< (104, PointFromWKB(AsWKB(PointFromText('POINT(10 20)'))));
+< INSERT INTO gis_line VALUES
+< (105, LineFromText('LINESTRING(0 0,0 10,10 0)')),
+< (106, LineStringFromText('LINESTRING(10 10,20 10,20 20,10 20,10 10)')),
+< (107, LineStringFromWKB(AsWKB(LineString(Point(10, 10), Point(40, 10)))));
+< INSERT INTO gis_polygon VALUES
+< (108, PolygonFromText('POLYGON((10 10,20 10,20 20,10 20,10 10))')),
+< (109, PolyFromText('POLYGON((0 0,50 0,50 50,0 50,0 0), (10 10,20 10,20 20,10 20,10 10))')),
+< (110, PolyFromWKB(AsWKB(Polygon(LineString(Point(0, 0), Point(30, 0), Point(30, 30), Point(0, 0))))));
+< INSERT INTO gis_multi_point VALUES
+< (111, MultiPointFromText('MULTIPOINT(0 0,10 10,10 20,20 20)')),
+< (112, MPointFromText('MULTIPOINT(1 1,11 11,11 21,21 21)')),
+< (113, MPointFromWKB(AsWKB(MultiPoint(Point(3, 6), Point(4, 10)))));
+< INSERT INTO gis_multi_line VALUES
+< (114, MultiLineStringFromText('MULTILINESTRING((10 48,10 21,10 0),(16 0,16 23,16 48))')),
+< (115, MLineFromText('MULTILINESTRING((10 48,10 21,10 0))')),
+< (116, MLineFromWKB(AsWKB(MultiLineString(LineString(Point(1, 2), Point(3, 5)), LineString(Point(2, 5), Point(5, 8), Point(21, 7))))));
+< INSERT INTO gis_multi_polygon VALUES
+< (117, MultiPolygonFromText('MULTIPOLYGON(((28 26,28 0,84 0,84 42,28 26),(52 18,66 23,73 9,48 6,52 18)),((59 18,67 18,67 13,59 13,59 18)))')),
+< (118, MPolyFromText('MULTIPOLYGON(((28 26,28 0,84 0,84 42,28 26),(52 18,66 23,73 9,48 6,52 18)),((59 18,67 18,67 13,59 13,59 18)))')),
+< (119, MPolyFromWKB(AsWKB(MultiPolygon(Polygon(LineString(Point(0, 3), Point(3, 3), Point(3, 0), Point(0, 3)))))));
+< INSERT INTO gis_geometrycollection VALUES
+< (120, GeomCollFromText('GEOMETRYCOLLECTION(POINT(0 0), LINESTRING(0 0,10 10))')),
+< (121, GeometryFromWKB(AsWKB(GeometryCollection(Point(44, 6), LineString(Point(3, 6), Point(7, 9)))))),
+< (122, GeomFromText('GeometryCollection()')),
+< (123, GeomFromText('GeometryCollection EMPTY'));
+< INSERT into gis_geometry SELECT * FROM gis_point;
+< INSERT into gis_geometry SELECT * FROM gis_line;
+< INSERT into gis_geometry SELECT * FROM gis_polygon;
+< INSERT into gis_geometry SELECT * FROM gis_multi_point;
+< INSERT into gis_geometry SELECT * FROM gis_multi_line;
+< INSERT into gis_geometry SELECT * FROM gis_multi_polygon;
+< INSERT into gis_geometry SELECT * FROM gis_geometrycollection;
+< SELECT fid, AsText(g) FROM gis_point;
+< fid AsText(g)
+< 101 POINT(10 10)
+< 102 POINT(20 10)
+< 103 POINT(20 20)
+< 104 POINT(10 20)
+< SELECT fid, AsText(g) FROM gis_line;
+< fid AsText(g)
+< 105 LINESTRING(0 0,0 10,10 0)
+< 106 LINESTRING(10 10,20 10,20 20,10 20,10 10)
+< 107 LINESTRING(10 10,40 10)
+< SELECT fid, AsText(g) FROM gis_polygon;
+< fid AsText(g)
+< 108 POLYGON((10 10,20 10,20 20,10 20,10 10))
+< 109 POLYGON((0 0,50 0,50 50,0 50,0 0),(10 10,20 10,20 20,10 20,10 10))
+< 110 POLYGON((0 0,30 0,30 30,0 0))
+< SELECT fid, AsText(g) FROM gis_multi_point;
+< fid AsText(g)
+< 111 MULTIPOINT(0 0,10 10,10 20,20 20)
+< 112 MULTIPOINT(1 1,11 11,11 21,21 21)
+< 113 MULTIPOINT(3 6,4 10)
+< SELECT fid, AsText(g) FROM gis_multi_line;
+< fid AsText(g)
+< 114 MULTILINESTRING((10 48,10 21,10 0),(16 0,16 23,16 48))
+< 115 MULTILINESTRING((10 48,10 21,10 0))
+< 116 MULTILINESTRING((1 2,3 5),(2 5,5 8,21 7))
+< SELECT fid, AsText(g) FROM gis_multi_polygon;
+< fid AsText(g)
+< 117 MULTIPOLYGON(((28 26,28 0,84 0,84 42,28 26),(52 18,66 23,73 9,48 6,52 18)),((59 18,67 18,67 13,59 13,59 18)))
+< 118 MULTIPOLYGON(((28 26,28 0,84 0,84 42,28 26),(52 18,66 23,73 9,48 6,52 18)),((59 18,67 18,67 13,59 13,59 18)))
+< 119 MULTIPOLYGON(((0 3,3 3,3 0,0 3)))
+< SELECT fid, AsText(g) FROM gis_geometrycollection;
+< fid AsText(g)
+< 120 GEOMETRYCOLLECTION(POINT(0 0),LINESTRING(0 0,10 10))
+< 121 GEOMETRYCOLLECTION(POINT(44 6),LINESTRING(3 6,7 9))
+< 122 GEOMETRYCOLLECTION EMPTY
+< 123 GEOMETRYCOLLECTION EMPTY
+< SELECT fid, AsText(g) FROM gis_geometry;
+< fid AsText(g)
+< 101 POINT(10 10)
+< 102 POINT(20 10)
+< 103 POINT(20 20)
+< 104 POINT(10 20)
+< 105 LINESTRING(0 0,0 10,10 0)
+< 106 LINESTRING(10 10,20 10,20 20,10 20,10 10)
+< 107 LINESTRING(10 10,40 10)
+< 108 POLYGON((10 10,20 10,20 20,10 20,10 10))
+< 109 POLYGON((0 0,50 0,50 50,0 50,0 0),(10 10,20 10,20 20,10 20,10 10))
+< 110 POLYGON((0 0,30 0,30 30,0 0))
+< 111 MULTIPOINT(0 0,10 10,10 20,20 20)
+< 112 MULTIPOINT(1 1,11 11,11 21,21 21)
+< 113 MULTIPOINT(3 6,4 10)
+< 114 MULTILINESTRING((10 48,10 21,10 0),(16 0,16 23,16 48))
+< 115 MULTILINESTRING((10 48,10 21,10 0))
+< 116 MULTILINESTRING((1 2,3 5),(2 5,5 8,21 7))
+< 117 MULTIPOLYGON(((28 26,28 0,84 0,84 42,28 26),(52 18,66 23,73 9,48 6,52 18)),((59 18,67 18,67 13,59 13,59 18)))
+< 118 MULTIPOLYGON(((28 26,28 0,84 0,84 42,28 26),(52 18,66 23,73 9,48 6,52 18)),((59 18,67 18,67 13,59 13,59 18)))
+< 119 MULTIPOLYGON(((0 3,3 3,3 0,0 3)))
+< 120 GEOMETRYCOLLECTION(POINT(0 0),LINESTRING(0 0,10 10))
+< 121 GEOMETRYCOLLECTION(POINT(44 6),LINESTRING(3 6,7 9))
+< 122 GEOMETRYCOLLECTION EMPTY
+< 123 GEOMETRYCOLLECTION EMPTY
+< SELECT fid, Dimension(g) FROM gis_geometry;
+< fid Dimension(g)
+< 101 0
+< 102 0
+< 103 0
+< 104 0
+< 105 1
+< 106 1
+< 107 1
+< 108 2
+< 109 2
+< 110 2
+< 111 0
+< 112 0
+< 113 0
+< 114 1
+< 115 1
+< 116 1
+< 117 2
+< 118 2
+< 119 2
+< 120 1
+< 121 1
+< 122 0
+< 123 0
+< SELECT fid, GeometryType(g) FROM gis_geometry;
+< fid GeometryType(g)
+< 101 POINT
+< 102 POINT
+< 103 POINT
+< 104 POINT
+< 105 LINESTRING
+< 106 LINESTRING
+< 107 LINESTRING
+< 108 POLYGON
+< 109 POLYGON
+< 110 POLYGON
+< 111 MULTIPOINT
+< 112 MULTIPOINT
+< 113 MULTIPOINT
+< 114 MULTILINESTRING
+< 115 MULTILINESTRING
+< 116 MULTILINESTRING
+< 117 MULTIPOLYGON
+< 118 MULTIPOLYGON
+< 119 MULTIPOLYGON
+< 120 GEOMETRYCOLLECTION
+< 121 GEOMETRYCOLLECTION
+< 122 GEOMETRYCOLLECTION
+< 123 GEOMETRYCOLLECTION
+< SELECT fid, IsEmpty(g) FROM gis_geometry;
+< fid IsEmpty(g)
+< 101 0
+< 102 0
+< 103 0
+< 104 0
+< 105 0
+< 106 0
+< 107 0
+< 108 0
+< 109 0
+< 110 0
+< 111 0
+< 112 0
+< 113 0
+< 114 0
+< 115 0
+< 116 0
+< 117 0
+< 118 0
+< 119 0
+< 120 0
+< 121 0
+< 122 0
+< 123 0
+< SELECT fid, AsText(Envelope(g)) FROM gis_geometry;
+< fid AsText(Envelope(g))
+< 101 POLYGON((10 10,10 10,10 10,10 10,10 10))
+< 102 POLYGON((20 10,20 10,20 10,20 10,20 10))
+< 103 POLYGON((20 20,20 20,20 20,20 20,20 20))
+< 104 POLYGON((10 20,10 20,10 20,10 20,10 20))
+< 105 POLYGON((0 0,10 0,10 10,0 10,0 0))
+< 106 POLYGON((10 10,20 10,20 20,10 20,10 10))
+< 107 POLYGON((10 10,40 10,40 10,10 10,10 10))
+< 108 POLYGON((10 10,20 10,20 20,10 20,10 10))
+< 109 POLYGON((0 0,50 0,50 50,0 50,0 0))
+< 110 POLYGON((0 0,30 0,30 30,0 30,0 0))
+< 111 POLYGON((0 0,20 0,20 20,0 20,0 0))
+< 112 POLYGON((1 1,21 1,21 21,1 21,1 1))
+< 113 POLYGON((3 6,4 6,4 10,3 10,3 6))
+< 114 POLYGON((10 0,16 0,16 48,10 48,10 0))
+< 115 POLYGON((10 0,10 0,10 48,10 48,10 0))
+< 116 POLYGON((1 2,21 2,21 8,1 8,1 2))
+< 117 POLYGON((28 0,84 0,84 42,28 42,28 0))
+< 118 POLYGON((28 0,84 0,84 42,28 42,28 0))
+< 119 POLYGON((0 0,3 0,3 3,0 3,0 0))
+< 120 POLYGON((0 0,10 0,10 10,0 10,0 0))
+< 121 POLYGON((3 6,44 6,44 9,3 9,3 6))
+< 122 GEOMETRYCOLLECTION EMPTY
+< 123 GEOMETRYCOLLECTION EMPTY
+< SELECT fid, X(g) FROM gis_point;
+< fid X(g)
+< 101 10
+< 102 20
+< 103 20
+< 104 10
+< SELECT fid, Y(g) FROM gis_point;
+< fid Y(g)
+< 101 10
+< 102 10
+< 103 20
+< 104 20
+< SELECT fid, AsText(StartPoint(g)) FROM gis_line;
+< fid AsText(StartPoint(g))
+< 105 POINT(0 0)
+< 106 POINT(10 10)
+< 107 POINT(10 10)
+< SELECT fid, AsText(EndPoint(g)) FROM gis_line;
+< fid AsText(EndPoint(g))
+< 105 POINT(10 0)
+< 106 POINT(10 10)
+< 107 POINT(40 10)
+< SELECT fid, GLength(g) FROM gis_line;
+< fid GLength(g)
+< 105 24.14213562373095
+< 106 40
+< 107 30
+< SELECT fid, NumPoints(g) FROM gis_line;
+< fid NumPoints(g)
+< 105 3
+< 106 5
+< 107 2
+< SELECT fid, AsText(PointN(g, 2)) FROM gis_line;
+< fid AsText(PointN(g, 2))
+< 105 POINT(0 10)
+< 106 POINT(20 10)
+< 107 POINT(40 10)
+< SELECT fid, IsClosed(g) FROM gis_line;
+< fid IsClosed(g)
+< 105 0
+< 106 1
+< 107 0
+< SELECT fid, AsText(Centroid(g)) FROM gis_polygon;
+< fid AsText(Centroid(g))
+< 108 POINT(15 15)
+< 109 POINT(25.416666666666668 25.416666666666668)
+< 110 POINT(20 10)
+< SELECT fid, Area(g) FROM gis_polygon;
+< fid Area(g)
+< 108 100
+< 109 2400
+< 110 450
+< SELECT fid, AsText(ExteriorRing(g)) FROM gis_polygon;
+< fid AsText(ExteriorRing(g))
+< 108 LINESTRING(10 10,20 10,20 20,10 20,10 10)
+< 109 LINESTRING(0 0,50 0,50 50,0 50,0 0)
+< 110 LINESTRING(0 0,30 0,30 30,0 0)
+< SELECT fid, NumInteriorRings(g) FROM gis_polygon;
+< fid NumInteriorRings(g)
+< 108 0
+< 109 1
+< 110 0
+< SELECT fid, AsText(InteriorRingN(g, 1)) FROM gis_polygon;
+< fid AsText(InteriorRingN(g, 1))
+< 108 NULL
+< 109 LINESTRING(10 10,20 10,20 20,10 20,10 10)
+< 110 NULL
+< SELECT fid, IsClosed(g) FROM gis_multi_line;
+< fid IsClosed(g)
+< 114 0
+< 115 0
+< 116 0
+< SELECT fid, AsText(Centroid(g)) FROM gis_multi_polygon;
+< fid AsText(Centroid(g))
+< 117 POINT(55.58852775304245 17.426536064113982)
+< 118 POINT(55.58852775304245 17.426536064113982)
+< 119 POINT(2 2)
+< SELECT fid, Area(g) FROM gis_multi_polygon;
+< fid Area(g)
+< 117 1684.5
+< 118 1684.5
+< 119 4.5
+< SELECT fid, NumGeometries(g) from gis_multi_point;
+< fid NumGeometries(g)
+< 111 4
+< 112 4
+< 113 2
+< SELECT fid, NumGeometries(g) from gis_multi_line;
+< fid NumGeometries(g)
+< 114 2
+< 115 1
+< 116 2
+< SELECT fid, NumGeometries(g) from gis_multi_polygon;
+< fid NumGeometries(g)
+< 117 2
+< 118 2
+< 119 1
+< SELECT fid, NumGeometries(g) from gis_geometrycollection;
+< fid NumGeometries(g)
+< 120 2
+< 121 2
+< 122 0
+< 123 0
+< SELECT fid, AsText(GeometryN(g, 2)) from gis_multi_point;
+< fid AsText(GeometryN(g, 2))
+< 111 POINT(10 10)
+< 112 POINT(11 11)
+< 113 POINT(4 10)
+< SELECT fid, AsText(GeometryN(g, 2)) from gis_multi_line;
+< fid AsText(GeometryN(g, 2))
+< 114 LINESTRING(16 0,16 23,16 48)
+< 115 NULL
+< 116 LINESTRING(2 5,5 8,21 7)
+< SELECT fid, AsText(GeometryN(g, 2)) from gis_multi_polygon;
+< fid AsText(GeometryN(g, 2))
+< 117 POLYGON((59 18,67 18,67 13,59 13,59 18))
+< 118 POLYGON((59 18,67 18,67 13,59 13,59 18))
+< 119 NULL
+< SELECT fid, AsText(GeometryN(g, 2)) from gis_geometrycollection;
+< fid AsText(GeometryN(g, 2))
+< 120 LINESTRING(0 0,10 10)
+< 121 LINESTRING(3 6,7 9)
+< 122 NULL
+< 123 NULL
+< SELECT fid, AsText(GeometryN(g, 1)) from gis_geometrycollection;
+< fid AsText(GeometryN(g, 1))
+< 120 POINT(0 0)
+< 121 POINT(44 6)
+< 122 NULL
+< 123 NULL
+< SELECT g1.fid as first, g2.fid as second,
+< Within(g1.g, g2.g) as w, Contains(g1.g, g2.g) as c, Overlaps(g1.g, g2.g) as o,
+< Equals(g1.g, g2.g) as e, Disjoint(g1.g, g2.g) as d, Touches(g1.g, g2.g) as t,
+< Intersects(g1.g, g2.g) as i, Crosses(g1.g, g2.g) as r
+< FROM gis_geometrycollection g1, gis_geometrycollection g2 ORDER BY first, second;
+< first second w c o e d t i r
+< 120 120 1 1 0 1 0 1 1 0
+< 120 121 0 0 1 0 0 0 1 0
+< 120 122 0 1 NULL 0 NULL 0 NULL 0
+< 120 123 0 1 NULL 0 NULL 0 NULL 0
+< 121 120 0 0 1 0 0 0 1 0
+< 121 121 1 1 0 1 0 1 1 0
+< 121 122 0 1 NULL 0 NULL 0 NULL 0
+< 121 123 0 1 NULL 0 NULL 0 NULL 0
+< 122 120 1 0 NULL 0 NULL 0 NULL 0
+< 122 121 1 0 NULL 0 NULL 0 NULL 0
+< 122 122 1 1 NULL 1 NULL 0 NULL 0
+< 122 123 1 1 NULL 1 NULL 0 NULL 0
+< 123 120 1 0 NULL 0 NULL 0 NULL 0
+< 123 121 1 0 NULL 0 NULL 0 NULL 0
+< 123 122 1 1 NULL 1 NULL 0 NULL 0
+< 123 123 1 1 NULL 1 NULL 0 NULL 0
+< DROP TABLE gis_point, gis_line, gis_polygon, gis_multi_point, gis_multi_line, gis_multi_polygon, gis_geometrycollection, gis_geometry;
+< USE gis_ogs;
+< # Lakes
+< INSERT INTO lakes VALUES (
+< 101, 'BLUE LAKE',
+< PolyFromText(
+< 'POLYGON(
+< (52 18,66 23,73 9,48 6,52 18),
+< (59 18,67 18,67 13,59 13,59 18)
+< )',
+< 101));
+< # Road Segments
+< INSERT INTO road_segments VALUES(102, 'Route 5', NULL, 2,
+< LineFromText(
+< 'LINESTRING( 0 18, 10 21, 16 23, 28 26, 44 31 )' ,101));
+< INSERT INTO road_segments VALUES(103, 'Route 5', 'Main Street', 4,
+< LineFromText(
+< 'LINESTRING( 44 31, 56 34, 70 38 )' ,101));
+< INSERT INTO road_segments VALUES(104, 'Route 5', NULL, 2,
+< LineFromText(
+< 'LINESTRING( 70 38, 72 48 )' ,101));
+< INSERT INTO road_segments VALUES(105, 'Main Street', NULL, 4,
+< LineFromText(
+< 'LINESTRING( 70 38, 84 42 )' ,101));
+< INSERT INTO road_segments VALUES(106, 'Dirt Road by Green Forest', NULL,
+< 1,
+< LineFromText(
+< 'LINESTRING( 28 26, 28 0 )',101));
+< # DividedRoutes
+< INSERT INTO divided_routes VALUES(119, 'Route 75', 4,
+< MLineFromText(
+< 'MULTILINESTRING((10 48,10 21,10 0),
+< (16 0,16 23,16 48))', 101));
+< # Forests
+< INSERT INTO forests VALUES(109, 'Green Forest',
+< MPolyFromText(
+< 'MULTIPOLYGON(((28 26,28 0,84 0,84 42,28 26),
+< (52 18,66 23,73 9,48 6,52 18)),((59 18,67 18,67 13,59 13,59 18)))',
+< 101));
+< # Bridges
+< INSERT INTO bridges VALUES(110, 'Cam Bridge', PointFromText(
+< 'POINT( 44 31 )', 101));
+< # Streams
+< INSERT INTO streams VALUES(111, 'Cam Stream',
+< LineFromText(
+< 'LINESTRING( 38 48, 44 41, 41 36, 44 31, 52 18 )', 101));
+< INSERT INTO streams VALUES(112, NULL,
+< LineFromText(
+< 'LINESTRING( 76 0, 78 4, 73 9 )', 101));
+< # Buildings
+< INSERT INTO buildings VALUES(113, '123 Main Street',
+< PointFromText(
+< 'POINT( 52 30 )', 101),
+< PolyFromText(
+< 'POLYGON( ( 50 31, 54 31, 54 29, 50 29, 50 31) )', 101));
+< INSERT INTO buildings VALUES(114, '215 Main Street',
+< PointFromText(
+< 'POINT( 64 33 )', 101),
+< PolyFromText(
+< 'POLYGON( ( 66 34, 62 34, 62 32, 66 32, 66 34) )', 101));
+< # Ponds
+< INSERT INTO ponds VALUES(120, NULL, 'Stock Pond',
+< MPolyFromText(
+< 'MULTIPOLYGON( ( ( 24 44, 22 42, 24 40, 24 44) ),
+< ( ( 26 44, 26 40, 28 42, 26 44) ) )', 101));
+< # Named Places
+< INSERT INTO named_places VALUES(117, 'Ashton',
+< PolyFromText(
+< 'POLYGON( ( 62 48, 84 48, 84 30, 56 30, 56 34, 62 48) )', 101));
+< INSERT INTO named_places VALUES(118, 'Goose Island',
+< PolyFromText(
+< 'POLYGON( ( 67 13, 67 18, 59 18, 59 13, 67 13) )', 101));
+< # Map Neatlines
+< INSERT INTO map_neatlines VALUES(115,
+< PolyFromText(
+< 'POLYGON( ( 0 0, 0 48, 84 48, 84 0, 0 0 ) )', 101));
+< SELECT Dimension(shore)
+< FROM lakes
+< WHERE name = 'Blue Lake';
+< Dimension(shore)
+< 2
+< SELECT GeometryType(centerlines)
+< FROM divided_routes
+< WHERE name = 'Route 75';
+< GeometryType(centerlines)
+< MULTILINESTRING
+< SELECT AsText(boundary)
+< FROM named_places
+< WHERE name = 'Goose Island';
+< AsText(boundary)
+< POLYGON((67 13,67 18,59 18,59 13,67 13))
+< SELECT AsText(PolyFromWKB(AsBinary(boundary),101))
+< FROM named_places
+< WHERE name = 'Goose Island';
+< AsText(PolyFromWKB(AsBinary(boundary),101))
+< POLYGON((67 13,67 18,59 18,59 13,67 13))
+< SELECT SRID(boundary)
+< FROM named_places
+< WHERE name = 'Goose Island';
+< SRID(boundary)
+< 101
+< SELECT IsEmpty(centerline)
+< FROM road_segments
+< WHERE name = 'Route 5'
+< AND aliases = 'Main Street';
+< IsEmpty(centerline)
+< 0
+< SELECT AsText(Envelope(boundary))
+< FROM named_places
+< WHERE name = 'Goose Island';
+< AsText(Envelope(boundary))
+< POLYGON((59 13,67 13,67 18,59 18,59 13))
+< SELECT X(position)
+< FROM bridges
+< WHERE name = 'Cam Bridge';
+< X(position)
+< 44
+< SELECT Y(position)
+< FROM bridges
+< WHERE name = 'Cam Bridge';
+< Y(position)
+< 31
+< SELECT AsText(StartPoint(centerline))
+< FROM road_segments
+< WHERE fid = 102;
+< AsText(StartPoint(centerline))
+< POINT(0 18)
+< SELECT AsText(EndPoint(centerline))
+< FROM road_segments
+< WHERE fid = 102;
+< AsText(EndPoint(centerline))
+< POINT(44 31)
+< SELECT GLength(centerline)
+< FROM road_segments
+< WHERE fid = 106;
+< GLength(centerline)
+< 26
+< SELECT NumPoints(centerline)
+< FROM road_segments
+< WHERE fid = 102;
+< NumPoints(centerline)
+< 5
+< SELECT AsText(PointN(centerline, 1))
+< FROM road_segments
+< WHERE fid = 102;
+< AsText(PointN(centerline, 1))
+< POINT(0 18)
+< SELECT AsText(Centroid(boundary))
+< FROM named_places
+< WHERE name = 'Goose Island';
+< AsText(Centroid(boundary))
+< POINT(63 15.5)
+< SELECT Area(boundary)
+< FROM named_places
+< WHERE name = 'Goose Island';
+< Area(boundary)
+< 40
+< SELECT AsText(ExteriorRing(shore))
+< FROM lakes
+< WHERE name = 'Blue Lake';
+< AsText(ExteriorRing(shore))
+< LINESTRING(52 18,66 23,73 9,48 6,52 18)
+< SELECT NumInteriorRings(shore)
+< FROM lakes
+< WHERE name = 'Blue Lake';
+< NumInteriorRings(shore)
+< 1
+< SELECT AsText(InteriorRingN(shore, 1))
+< FROM lakes
+< WHERE name = 'Blue Lake';
+< AsText(InteriorRingN(shore, 1))
+< LINESTRING(59 18,67 18,67 13,59 13,59 18)
+< SELECT NumGeometries(centerlines)
+< FROM divided_routes
+< WHERE name = 'Route 75';
+< NumGeometries(centerlines)
+< 2
+< SELECT AsText(GeometryN(centerlines, 2))
+< FROM divided_routes
+< WHERE name = 'Route 75';
+< AsText(GeometryN(centerlines, 2))
+< LINESTRING(16 0,16 23,16 48)
+< SELECT IsClosed(centerlines)
+< FROM divided_routes
+< WHERE name = 'Route 75';
+< IsClosed(centerlines)
+< 0
+< SELECT GLength(centerlines)
+< FROM divided_routes
+< WHERE name = 'Route 75';
+< GLength(centerlines)
+< 96
+< SELECT AsText(Centroid(shores))
+< FROM ponds
+< WHERE fid = 120;
+< AsText(Centroid(shores))
+< POINT(25 42)
+< SELECT Area(shores)
+< FROM ponds
+< WHERE fid = 120;
+< Area(shores)
+< 8
+< SELECT ST_Equals(boundary,
+< PolyFromText('POLYGON( ( 67 13, 67 18, 59 18, 59 13, 67 13) )',1))
+< FROM named_places
+< WHERE name = 'Goose Island';
+< ST_Equals(boundary,
+< PolyFromText('POLYGON( ( 67 13, 67 18, 59 18, 59 13, 67 13) )',1))
+< 1
+< SELECT ST_Disjoint(centerlines, boundary)
+< FROM divided_routes, named_places
+< WHERE divided_routes.name = 'Route 75'
+< AND named_places.name = 'Ashton';
+< ST_Disjoint(centerlines, boundary)
+< 1
+< SELECT ST_Touches(centerline, shore)
+< FROM streams, lakes
+< WHERE streams.name = 'Cam Stream'
+< AND lakes.name = 'Blue Lake';
+< ST_Touches(centerline, shore)
+< 1
+< SELECT Crosses(road_segments.centerline, divided_routes.centerlines)
+< FROM road_segments, divided_routes
+< WHERE road_segments.fid = 102
+< AND divided_routes.name = 'Route 75';
+< Crosses(road_segments.centerline, divided_routes.centerlines)
+< 1
+< SELECT ST_Intersects(road_segments.centerline, divided_routes.centerlines)
+< FROM road_segments, divided_routes
+< WHERE road_segments.fid = 102
+< AND divided_routes.name = 'Route 75';
+< ST_Intersects(road_segments.centerline, divided_routes.centerlines)
+< 1
+< SELECT ST_Contains(forests.boundary, named_places.boundary)
+< FROM forests, named_places
+< WHERE forests.name = 'Green Forest'
+< AND named_places.name = 'Ashton';
+< ST_Contains(forests.boundary, named_places.boundary)
+< 0
+< SELECT ST_Distance(position, boundary)
+< FROM bridges, named_places
+< WHERE bridges.name = 'Cam Bridge'
+< AND named_places.name = 'Ashton';
+< ST_Distance(position, boundary)
+< 12
+< SELECT AsText(ST_Difference(named_places.boundary, forests.boundary))
+< FROM named_places, forests
+< WHERE named_places.name = 'Ashton'
+< AND forests.name = 'Green Forest';
+< AsText(ST_Difference(named_places.boundary, forests.boundary))
+< POLYGON((56 34,62 48,84 48,84 42,56 34))
+< SELECT AsText(ST_Union(shore, boundary))
+< FROM lakes, named_places
+< WHERE lakes.name = 'Blue Lake'
+< AND named_places.name = 'Goose Island';
+< AsText(ST_Union(shore, boundary))
+< POLYGON((48 6,52 18,66 23,73 9,48 6))
+< SELECT AsText(ST_SymDifference(shore, boundary))
+< FROM lakes, named_places
+< WHERE lakes.name = 'Blue Lake'
+< AND named_places.name = 'Ashton';
+< AsText(ST_SymDifference(shore, boundary))
+< MULTIPOLYGON(((48 6,52 18,66 23,73 9,48 6),(59 13,59 18,67 18,67 13,59 13)),((56 30,56 34,62 48,84 48,84 30,56 30)))
+< SELECT count(*)
+< FROM buildings, bridges
+< WHERE ST_Contains(ST_Buffer(bridges.position, 15.0), buildings.footprint) = 1;
+< count(*)
+< 1
+---
+> ERROR 42000: The storage engine for the table doesn't support GEOMETRY
+> # ERROR: Statement ended with errno 1178, errname ER_CHECK_NOT_IMPLEMENTED (expected to succeed)
+> # ------------ UNEXPECTED RESULT ------------
+> # [ CREATE TABLE gis_point (fid INT(11) /*!*/ /*Custom column options*/, g POINT, /*!INDEX*/ /*Custom index*/ g(g(128))) ENGINE=MRG_MYISAM /*!*/ /*Custom table options*/ UNION(mrg.gis_point) INSERT_METHOD=LAST ]
+> # The statement|command finished with ER_CHECK_NOT_IMPLEMENTED.
+> # Geometry types or indexes on them or the mix could be unsupported|malfunctioning, or the problem was caused by previous errors.
+> # You can change the engine code, or create an rdiff, or disable the test by adding it to disabled.def.
+> # Further in this test, the message might sometimes be suppressed; a part of the test might be skipped.
+> # Also, this problem may cause a chain effect (more errors of different kinds in the test).
+> # -------------------------------------------
+705,1398c21,30
+< CREATE TABLE gis_line (fid <INT_COLUMN>, g LINESTRING NOT NULL, SPATIAL INDEX(g)) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+< CREATE TABLE gis_polygon (fid <INT_COLUMN>, g POLYGON NOT NULL, SPATIAL INDEX(g)) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+< CREATE TABLE gis_multi_point (fid <INT_COLUMN>, g MULTIPOINT NOT NULL, SPATIAL INDEX(g)) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+< CREATE TABLE gis_multi_line (fid <INT_COLUMN>, g MULTILINESTRING NOT NULL, SPATIAL INDEX(g)) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+< CREATE TABLE gis_multi_polygon (fid <INT_COLUMN>, g MULTIPOLYGON NOT NULL, SPATIAL INDEX(g)) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+< CREATE TABLE gis_geometrycollection (fid <INT_COLUMN>, g GEOMETRYCOLLECTION NOT NULL, SPATIAL INDEX(g)) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+< CREATE TABLE gis_geometry (fid <INT_COLUMN>, g GEOMETRY NOT NULL) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+< USE gis_ogs;
+< CREATE TABLE lakes (fid INT <CUSTOM_COL_OPTIONS>,
+< name CHAR(64) <CUSTOM_COL_OPTIONS>,
+< shore POLYGON NOT NULL, SPATIAL INDEX s(shore)) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+< CREATE TABLE road_segments (fid INT <CUSTOM_COL_OPTIONS>,
+< name CHAR(64) <CUSTOM_COL_OPTIONS>,
+< aliases CHAR(64) <CUSTOM_COL_OPTIONS>,
+< num_lanes INT <CUSTOM_COL_OPTIONS>,
+< centerline LINESTRING NOT NULL, SPATIAL INDEX c(centerline)) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+< CREATE TABLE divided_routes (fid INT <CUSTOM_COL_OPTIONS>,
+< name CHAR(64) <CUSTOM_COL_OPTIONS>,
+< num_lanes INT <CUSTOM_COL_OPTIONS>,
+< centerlines MULTILINESTRING NOT NULL, SPATIAL INDEX c(centerlines)) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+< CREATE TABLE forests (fid INT <CUSTOM_COL_OPTIONS>,
+< name CHAR(64) <CUSTOM_COL_OPTIONS>,
+< boundary MULTIPOLYGON NOT NULL, SPATIAL INDEX b(boundary)) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+< CREATE TABLE bridges (fid INT <CUSTOM_COL_OPTIONS>,
+< name CHAR(64) <CUSTOM_COL_OPTIONS>,
+< position POINT NOT NULL, SPATIAL INDEX p(position)) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+< CREATE TABLE streams (fid INT <CUSTOM_COL_OPTIONS>,
+< name CHAR(64) <CUSTOM_COL_OPTIONS>,
+< centerline LINESTRING NOT NULL, SPATIAL INDEX c(centerline)) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+< CREATE TABLE buildings (fid INT <CUSTOM_COL_OPTIONS>,
+< name CHAR(64) <CUSTOM_COL_OPTIONS>,
+< position POINT NOT NULL,
+< footprint POLYGON NOT NULL, SPATIAL INDEX p(position), SPATIAL INDEX f(footprint)) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+< CREATE TABLE ponds (fid INT <CUSTOM_COL_OPTIONS>,
+< name CHAR(64) <CUSTOM_COL_OPTIONS>,
+< type CHAR(64) <CUSTOM_COL_OPTIONS>,
+< shores MULTIPOLYGON NOT NULL, SPATIAL INDEX s(shores)) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+< CREATE TABLE named_places (fid INT <CUSTOM_COL_OPTIONS>,
+< name CHAR(64) <CUSTOM_COL_OPTIONS>,
+< boundary POLYGON NOT NULL, SPATIAL INDEX b(boundary)) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+< CREATE TABLE map_neatlines (fid INT <CUSTOM_COL_OPTIONS>,
+< neatline POLYGON NOT NULL, SPATIAL INDEX n(neatline)) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+< USE test;
+< SHOW FIELDS FROM gis_point;
+< Field Type Null Key Default Extra
+< fid int(11) YES NULL
+< g point NO MUL NULL
+< SHOW FIELDS FROM gis_line;
+< Field Type Null Key Default Extra
+< fid int(11) YES NULL
+< g linestring NO MUL NULL
+< SHOW FIELDS FROM gis_polygon;
+< Field Type Null Key Default Extra
+< fid int(11) YES NULL
+< g polygon NO MUL NULL
+< SHOW FIELDS FROM gis_multi_point;
+< Field Type Null Key Default Extra
+< fid int(11) YES NULL
+< g multipoint NO MUL NULL
+< SHOW FIELDS FROM gis_multi_line;
+< Field Type Null Key Default Extra
+< fid int(11) YES NULL
+< g multilinestring NO MUL NULL
+< SHOW FIELDS FROM gis_multi_polygon;
+< Field Type Null Key Default Extra
+< fid int(11) YES NULL
+< g multipolygon NO MUL NULL
+< SHOW FIELDS FROM gis_geometrycollection;
+< Field Type Null Key Default Extra
+< fid int(11) YES NULL
+< g geometrycollection NO MUL NULL
+< SHOW FIELDS FROM gis_geometry;
+< Field Type Null Key Default Extra
+< fid int(11) YES NULL
+< g geometry NO NULL
+< INSERT INTO gis_point VALUES
+< (101, PointFromText('POINT(10 10)')),
+< (102, PointFromText('POINT(20 10)')),
+< (103, PointFromText('POINT(20 20)')),
+< (104, PointFromWKB(AsWKB(PointFromText('POINT(10 20)'))));
+< INSERT INTO gis_line VALUES
+< (105, LineFromText('LINESTRING(0 0,0 10,10 0)')),
+< (106, LineStringFromText('LINESTRING(10 10,20 10,20 20,10 20,10 10)')),
+< (107, LineStringFromWKB(AsWKB(LineString(Point(10, 10), Point(40, 10)))));
+< INSERT INTO gis_polygon VALUES
+< (108, PolygonFromText('POLYGON((10 10,20 10,20 20,10 20,10 10))')),
+< (109, PolyFromText('POLYGON((0 0,50 0,50 50,0 50,0 0), (10 10,20 10,20 20,10 20,10 10))')),
+< (110, PolyFromWKB(AsWKB(Polygon(LineString(Point(0, 0), Point(30, 0), Point(30, 30), Point(0, 0))))));
+< INSERT INTO gis_multi_point VALUES
+< (111, MultiPointFromText('MULTIPOINT(0 0,10 10,10 20,20 20)')),
+< (112, MPointFromText('MULTIPOINT(1 1,11 11,11 21,21 21)')),
+< (113, MPointFromWKB(AsWKB(MultiPoint(Point(3, 6), Point(4, 10)))));
+< INSERT INTO gis_multi_line VALUES
+< (114, MultiLineStringFromText('MULTILINESTRING((10 48,10 21,10 0),(16 0,16 23,16 48))')),
+< (115, MLineFromText('MULTILINESTRING((10 48,10 21,10 0))')),
+< (116, MLineFromWKB(AsWKB(MultiLineString(LineString(Point(1, 2), Point(3, 5)), LineString(Point(2, 5), Point(5, 8), Point(21, 7))))));
+< INSERT INTO gis_multi_polygon VALUES
+< (117, MultiPolygonFromText('MULTIPOLYGON(((28 26,28 0,84 0,84 42,28 26),(52 18,66 23,73 9,48 6,52 18)),((59 18,67 18,67 13,59 13,59 18)))')),
+< (118, MPolyFromText('MULTIPOLYGON(((28 26,28 0,84 0,84 42,28 26),(52 18,66 23,73 9,48 6,52 18)),((59 18,67 18,67 13,59 13,59 18)))')),
+< (119, MPolyFromWKB(AsWKB(MultiPolygon(Polygon(LineString(Point(0, 3), Point(3, 3), Point(3, 0), Point(0, 3)))))));
+< INSERT INTO gis_geometrycollection VALUES
+< (120, GeomCollFromText('GEOMETRYCOLLECTION(POINT(0 0), LINESTRING(0 0,10 10))')),
+< (121, GeometryFromWKB(AsWKB(GeometryCollection(Point(44, 6), LineString(Point(3, 6), Point(7, 9)))))),
+< (122, GeomFromText('GeometryCollection()')),
+< (123, GeomFromText('GeometryCollection EMPTY'));
+< INSERT into gis_geometry SELECT * FROM gis_point;
+< INSERT into gis_geometry SELECT * FROM gis_line;
+< INSERT into gis_geometry SELECT * FROM gis_polygon;
+< INSERT into gis_geometry SELECT * FROM gis_multi_point;
+< INSERT into gis_geometry SELECT * FROM gis_multi_line;
+< INSERT into gis_geometry SELECT * FROM gis_multi_polygon;
+< INSERT into gis_geometry SELECT * FROM gis_geometrycollection;
+< SELECT fid, AsText(g) FROM gis_point;
+< fid AsText(g)
+< 101 POINT(10 10)
+< 102 POINT(20 10)
+< 103 POINT(20 20)
+< 104 POINT(10 20)
+< SELECT fid, AsText(g) FROM gis_line;
+< fid AsText(g)
+< 105 LINESTRING(0 0,0 10,10 0)
+< 106 LINESTRING(10 10,20 10,20 20,10 20,10 10)
+< 107 LINESTRING(10 10,40 10)
+< SELECT fid, AsText(g) FROM gis_polygon;
+< fid AsText(g)
+< 108 POLYGON((10 10,20 10,20 20,10 20,10 10))
+< 109 POLYGON((0 0,50 0,50 50,0 50,0 0),(10 10,20 10,20 20,10 20,10 10))
+< 110 POLYGON((0 0,30 0,30 30,0 0))
+< SELECT fid, AsText(g) FROM gis_multi_point;
+< fid AsText(g)
+< 111 MULTIPOINT(0 0,10 10,10 20,20 20)
+< 112 MULTIPOINT(1 1,11 11,11 21,21 21)
+< 113 MULTIPOINT(3 6,4 10)
+< SELECT fid, AsText(g) FROM gis_multi_line;
+< fid AsText(g)
+< 114 MULTILINESTRING((10 48,10 21,10 0),(16 0,16 23,16 48))
+< 115 MULTILINESTRING((10 48,10 21,10 0))
+< 116 MULTILINESTRING((1 2,3 5),(2 5,5 8,21 7))
+< SELECT fid, AsText(g) FROM gis_multi_polygon;
+< fid AsText(g)
+< 117 MULTIPOLYGON(((28 26,28 0,84 0,84 42,28 26),(52 18,66 23,73 9,48 6,52 18)),((59 18,67 18,67 13,59 13,59 18)))
+< 118 MULTIPOLYGON(((28 26,28 0,84 0,84 42,28 26),(52 18,66 23,73 9,48 6,52 18)),((59 18,67 18,67 13,59 13,59 18)))
+< 119 MULTIPOLYGON(((0 3,3 3,3 0,0 3)))
+< SELECT fid, AsText(g) FROM gis_geometrycollection;
+< fid AsText(g)
+< 120 GEOMETRYCOLLECTION(POINT(0 0),LINESTRING(0 0,10 10))
+< 121 GEOMETRYCOLLECTION(POINT(44 6),LINESTRING(3 6,7 9))
+< 122 GEOMETRYCOLLECTION EMPTY
+< 123 GEOMETRYCOLLECTION EMPTY
+< SELECT fid, AsText(g) FROM gis_geometry;
+< fid AsText(g)
+< 101 POINT(10 10)
+< 102 POINT(20 10)
+< 103 POINT(20 20)
+< 104 POINT(10 20)
+< 105 LINESTRING(0 0,0 10,10 0)
+< 106 LINESTRING(10 10,20 10,20 20,10 20,10 10)
+< 107 LINESTRING(10 10,40 10)
+< 108 POLYGON((10 10,20 10,20 20,10 20,10 10))
+< 109 POLYGON((0 0,50 0,50 50,0 50,0 0),(10 10,20 10,20 20,10 20,10 10))
+< 110 POLYGON((0 0,30 0,30 30,0 0))
+< 111 MULTIPOINT(0 0,10 10,10 20,20 20)
+< 112 MULTIPOINT(1 1,11 11,11 21,21 21)
+< 113 MULTIPOINT(3 6,4 10)
+< 114 MULTILINESTRING((10 48,10 21,10 0),(16 0,16 23,16 48))
+< 115 MULTILINESTRING((10 48,10 21,10 0))
+< 116 MULTILINESTRING((1 2,3 5),(2 5,5 8,21 7))
+< 117 MULTIPOLYGON(((28 26,28 0,84 0,84 42,28 26),(52 18,66 23,73 9,48 6,52 18)),((59 18,67 18,67 13,59 13,59 18)))
+< 118 MULTIPOLYGON(((28 26,28 0,84 0,84 42,28 26),(52 18,66 23,73 9,48 6,52 18)),((59 18,67 18,67 13,59 13,59 18)))
+< 119 MULTIPOLYGON(((0 3,3 3,3 0,0 3)))
+< 120 GEOMETRYCOLLECTION(POINT(0 0),LINESTRING(0 0,10 10))
+< 121 GEOMETRYCOLLECTION(POINT(44 6),LINESTRING(3 6,7 9))
+< 122 GEOMETRYCOLLECTION EMPTY
+< 123 GEOMETRYCOLLECTION EMPTY
+< SELECT fid, Dimension(g) FROM gis_geometry;
+< fid Dimension(g)
+< 101 0
+< 102 0
+< 103 0
+< 104 0
+< 105 1
+< 106 1
+< 107 1
+< 108 2
+< 109 2
+< 110 2
+< 111 0
+< 112 0
+< 113 0
+< 114 1
+< 115 1
+< 116 1
+< 117 2
+< 118 2
+< 119 2
+< 120 1
+< 121 1
+< 122 0
+< 123 0
+< SELECT fid, GeometryType(g) FROM gis_geometry;
+< fid GeometryType(g)
+< 101 POINT
+< 102 POINT
+< 103 POINT
+< 104 POINT
+< 105 LINESTRING
+< 106 LINESTRING
+< 107 LINESTRING
+< 108 POLYGON
+< 109 POLYGON
+< 110 POLYGON
+< 111 MULTIPOINT
+< 112 MULTIPOINT
+< 113 MULTIPOINT
+< 114 MULTILINESTRING
+< 115 MULTILINESTRING
+< 116 MULTILINESTRING
+< 117 MULTIPOLYGON
+< 118 MULTIPOLYGON
+< 119 MULTIPOLYGON
+< 120 GEOMETRYCOLLECTION
+< 121 GEOMETRYCOLLECTION
+< 122 GEOMETRYCOLLECTION
+< 123 GEOMETRYCOLLECTION
+< SELECT fid, IsEmpty(g) FROM gis_geometry;
+< fid IsEmpty(g)
+< 101 0
+< 102 0
+< 103 0
+< 104 0
+< 105 0
+< 106 0
+< 107 0
+< 108 0
+< 109 0
+< 110 0
+< 111 0
+< 112 0
+< 113 0
+< 114 0
+< 115 0
+< 116 0
+< 117 0
+< 118 0
+< 119 0
+< 120 0
+< 121 0
+< 122 0
+< 123 0
+< SELECT fid, AsText(Envelope(g)) FROM gis_geometry;
+< fid AsText(Envelope(g))
+< 101 POLYGON((10 10,10 10,10 10,10 10,10 10))
+< 102 POLYGON((20 10,20 10,20 10,20 10,20 10))
+< 103 POLYGON((20 20,20 20,20 20,20 20,20 20))
+< 104 POLYGON((10 20,10 20,10 20,10 20,10 20))
+< 105 POLYGON((0 0,10 0,10 10,0 10,0 0))
+< 106 POLYGON((10 10,20 10,20 20,10 20,10 10))
+< 107 POLYGON((10 10,40 10,40 10,10 10,10 10))
+< 108 POLYGON((10 10,20 10,20 20,10 20,10 10))
+< 109 POLYGON((0 0,50 0,50 50,0 50,0 0))
+< 110 POLYGON((0 0,30 0,30 30,0 30,0 0))
+< 111 POLYGON((0 0,20 0,20 20,0 20,0 0))
+< 112 POLYGON((1 1,21 1,21 21,1 21,1 1))
+< 113 POLYGON((3 6,4 6,4 10,3 10,3 6))
+< 114 POLYGON((10 0,16 0,16 48,10 48,10 0))
+< 115 POLYGON((10 0,10 0,10 48,10 48,10 0))
+< 116 POLYGON((1 2,21 2,21 8,1 8,1 2))
+< 117 POLYGON((28 0,84 0,84 42,28 42,28 0))
+< 118 POLYGON((28 0,84 0,84 42,28 42,28 0))
+< 119 POLYGON((0 0,3 0,3 3,0 3,0 0))
+< 120 POLYGON((0 0,10 0,10 10,0 10,0 0))
+< 121 POLYGON((3 6,44 6,44 9,3 9,3 6))
+< 122 GEOMETRYCOLLECTION EMPTY
+< 123 GEOMETRYCOLLECTION EMPTY
+< SELECT fid, X(g) FROM gis_point;
+< fid X(g)
+< 101 10
+< 102 20
+< 103 20
+< 104 10
+< SELECT fid, Y(g) FROM gis_point;
+< fid Y(g)
+< 101 10
+< 102 10
+< 103 20
+< 104 20
+< SELECT fid, AsText(StartPoint(g)) FROM gis_line;
+< fid AsText(StartPoint(g))
+< 105 POINT(0 0)
+< 106 POINT(10 10)
+< 107 POINT(10 10)
+< SELECT fid, AsText(EndPoint(g)) FROM gis_line;
+< fid AsText(EndPoint(g))
+< 105 POINT(10 0)
+< 106 POINT(10 10)
+< 107 POINT(40 10)
+< SELECT fid, GLength(g) FROM gis_line;
+< fid GLength(g)
+< 105 24.14213562373095
+< 106 40
+< 107 30
+< SELECT fid, NumPoints(g) FROM gis_line;
+< fid NumPoints(g)
+< 105 3
+< 106 5
+< 107 2
+< SELECT fid, AsText(PointN(g, 2)) FROM gis_line;
+< fid AsText(PointN(g, 2))
+< 105 POINT(0 10)
+< 106 POINT(20 10)
+< 107 POINT(40 10)
+< SELECT fid, IsClosed(g) FROM gis_line;
+< fid IsClosed(g)
+< 105 0
+< 106 1
+< 107 0
+< SELECT fid, AsText(Centroid(g)) FROM gis_polygon;
+< fid AsText(Centroid(g))
+< 108 POINT(15 15)
+< 109 POINT(25.416666666666668 25.416666666666668)
+< 110 POINT(20 10)
+< SELECT fid, Area(g) FROM gis_polygon;
+< fid Area(g)
+< 108 100
+< 109 2400
+< 110 450
+< SELECT fid, AsText(ExteriorRing(g)) FROM gis_polygon;
+< fid AsText(ExteriorRing(g))
+< 108 LINESTRING(10 10,20 10,20 20,10 20,10 10)
+< 109 LINESTRING(0 0,50 0,50 50,0 50,0 0)
+< 110 LINESTRING(0 0,30 0,30 30,0 0)
+< SELECT fid, NumInteriorRings(g) FROM gis_polygon;
+< fid NumInteriorRings(g)
+< 108 0
+< 109 1
+< 110 0
+< SELECT fid, AsText(InteriorRingN(g, 1)) FROM gis_polygon;
+< fid AsText(InteriorRingN(g, 1))
+< 108 NULL
+< 109 LINESTRING(10 10,20 10,20 20,10 20,10 10)
+< 110 NULL
+< SELECT fid, IsClosed(g) FROM gis_multi_line;
+< fid IsClosed(g)
+< 114 0
+< 115 0
+< 116 0
+< SELECT fid, AsText(Centroid(g)) FROM gis_multi_polygon;
+< fid AsText(Centroid(g))
+< 117 POINT(55.58852775304245 17.426536064113982)
+< 118 POINT(55.58852775304245 17.426536064113982)
+< 119 POINT(2 2)
+< SELECT fid, Area(g) FROM gis_multi_polygon;
+< fid Area(g)
+< 117 1684.5
+< 118 1684.5
+< 119 4.5
+< SELECT fid, NumGeometries(g) from gis_multi_point;
+< fid NumGeometries(g)
+< 111 4
+< 112 4
+< 113 2
+< SELECT fid, NumGeometries(g) from gis_multi_line;
+< fid NumGeometries(g)
+< 114 2
+< 115 1
+< 116 2
+< SELECT fid, NumGeometries(g) from gis_multi_polygon;
+< fid NumGeometries(g)
+< 117 2
+< 118 2
+< 119 1
+< SELECT fid, NumGeometries(g) from gis_geometrycollection;
+< fid NumGeometries(g)
+< 120 2
+< 121 2
+< 122 0
+< 123 0
+< SELECT fid, AsText(GeometryN(g, 2)) from gis_multi_point;
+< fid AsText(GeometryN(g, 2))
+< 111 POINT(10 10)
+< 112 POINT(11 11)
+< 113 POINT(4 10)
+< SELECT fid, AsText(GeometryN(g, 2)) from gis_multi_line;
+< fid AsText(GeometryN(g, 2))
+< 114 LINESTRING(16 0,16 23,16 48)
+< 115 NULL
+< 116 LINESTRING(2 5,5 8,21 7)
+< SELECT fid, AsText(GeometryN(g, 2)) from gis_multi_polygon;
+< fid AsText(GeometryN(g, 2))
+< 117 POLYGON((59 18,67 18,67 13,59 13,59 18))
+< 118 POLYGON((59 18,67 18,67 13,59 13,59 18))
+< 119 NULL
+< SELECT fid, AsText(GeometryN(g, 2)) from gis_geometrycollection;
+< fid AsText(GeometryN(g, 2))
+< 120 LINESTRING(0 0,10 10)
+< 121 LINESTRING(3 6,7 9)
+< 122 NULL
+< 123 NULL
+< SELECT fid, AsText(GeometryN(g, 1)) from gis_geometrycollection;
+< fid AsText(GeometryN(g, 1))
+< 120 POINT(0 0)
+< 121 POINT(44 6)
+< 122 NULL
+< 123 NULL
+< SELECT g1.fid as first, g2.fid as second,
+< Within(g1.g, g2.g) as w, Contains(g1.g, g2.g) as c, Overlaps(g1.g, g2.g) as o,
+< Equals(g1.g, g2.g) as e, Disjoint(g1.g, g2.g) as d, Touches(g1.g, g2.g) as t,
+< Intersects(g1.g, g2.g) as i, Crosses(g1.g, g2.g) as r
+< FROM gis_geometrycollection g1, gis_geometrycollection g2 ORDER BY first, second;
+< first second w c o e d t i r
+< 120 120 1 1 0 1 0 1 1 0
+< 120 121 0 0 1 0 0 0 1 0
+< 120 122 0 1 NULL 0 NULL 0 NULL 0
+< 120 123 0 1 NULL 0 NULL 0 NULL 0
+< 121 120 0 0 1 0 0 0 1 0
+< 121 121 1 1 0 1 0 1 1 0
+< 121 122 0 1 NULL 0 NULL 0 NULL 0
+< 121 123 0 1 NULL 0 NULL 0 NULL 0
+< 122 120 1 0 NULL 0 NULL 0 NULL 0
+< 122 121 1 0 NULL 0 NULL 0 NULL 0
+< 122 122 1 1 NULL 1 NULL 0 NULL 0
+< 122 123 1 1 NULL 1 NULL 0 NULL 0
+< 123 120 1 0 NULL 0 NULL 0 NULL 0
+< 123 121 1 0 NULL 0 NULL 0 NULL 0
+< 123 122 1 1 NULL 1 NULL 0 NULL 0
+< 123 123 1 1 NULL 1 NULL 0 NULL 0
+< DROP TABLE gis_point, gis_line, gis_polygon, gis_multi_point, gis_multi_line, gis_multi_polygon, gis_geometrycollection, gis_geometry;
+< USE gis_ogs;
+< # Lakes
+< INSERT INTO lakes VALUES (
+< 101, 'BLUE LAKE',
+< PolyFromText(
+< 'POLYGON(
+< (52 18,66 23,73 9,48 6,52 18),
+< (59 18,67 18,67 13,59 13,59 18)
+< )',
+< 101));
+< # Road Segments
+< INSERT INTO road_segments VALUES(102, 'Route 5', NULL, 2,
+< LineFromText(
+< 'LINESTRING( 0 18, 10 21, 16 23, 28 26, 44 31 )' ,101));
+< INSERT INTO road_segments VALUES(103, 'Route 5', 'Main Street', 4,
+< LineFromText(
+< 'LINESTRING( 44 31, 56 34, 70 38 )' ,101));
+< INSERT INTO road_segments VALUES(104, 'Route 5', NULL, 2,
+< LineFromText(
+< 'LINESTRING( 70 38, 72 48 )' ,101));
+< INSERT INTO road_segments VALUES(105, 'Main Street', NULL, 4,
+< LineFromText(
+< 'LINESTRING( 70 38, 84 42 )' ,101));
+< INSERT INTO road_segments VALUES(106, 'Dirt Road by Green Forest', NULL,
+< 1,
+< LineFromText(
+< 'LINESTRING( 28 26, 28 0 )',101));
+< # DividedRoutes
+< INSERT INTO divided_routes VALUES(119, 'Route 75', 4,
+< MLineFromText(
+< 'MULTILINESTRING((10 48,10 21,10 0),
+< (16 0,16 23,16 48))', 101));
+< # Forests
+< INSERT INTO forests VALUES(109, 'Green Forest',
+< MPolyFromText(
+< 'MULTIPOLYGON(((28 26,28 0,84 0,84 42,28 26),
+< (52 18,66 23,73 9,48 6,52 18)),((59 18,67 18,67 13,59 13,59 18)))',
+< 101));
+< # Bridges
+< INSERT INTO bridges VALUES(110, 'Cam Bridge', PointFromText(
+< 'POINT( 44 31 )', 101));
+< # Streams
+< INSERT INTO streams VALUES(111, 'Cam Stream',
+< LineFromText(
+< 'LINESTRING( 38 48, 44 41, 41 36, 44 31, 52 18 )', 101));
+< INSERT INTO streams VALUES(112, NULL,
+< LineFromText(
+< 'LINESTRING( 76 0, 78 4, 73 9 )', 101));
+< # Buildings
+< INSERT INTO buildings VALUES(113, '123 Main Street',
+< PointFromText(
+< 'POINT( 52 30 )', 101),
+< PolyFromText(
+< 'POLYGON( ( 50 31, 54 31, 54 29, 50 29, 50 31) )', 101));
+< INSERT INTO buildings VALUES(114, '215 Main Street',
+< PointFromText(
+< 'POINT( 64 33 )', 101),
+< PolyFromText(
+< 'POLYGON( ( 66 34, 62 34, 62 32, 66 32, 66 34) )', 101));
+< # Ponds
+< INSERT INTO ponds VALUES(120, NULL, 'Stock Pond',
+< MPolyFromText(
+< 'MULTIPOLYGON( ( ( 24 44, 22 42, 24 40, 24 44) ),
+< ( ( 26 44, 26 40, 28 42, 26 44) ) )', 101));
+< # Named Places
+< INSERT INTO named_places VALUES(117, 'Ashton',
+< PolyFromText(
+< 'POLYGON( ( 62 48, 84 48, 84 30, 56 30, 56 34, 62 48) )', 101));
+< INSERT INTO named_places VALUES(118, 'Goose Island',
+< PolyFromText(
+< 'POLYGON( ( 67 13, 67 18, 59 18, 59 13, 67 13) )', 101));
+< # Map Neatlines
+< INSERT INTO map_neatlines VALUES(115,
+< PolyFromText(
+< 'POLYGON( ( 0 0, 0 48, 84 48, 84 0, 0 0 ) )', 101));
+< SELECT Dimension(shore)
+< FROM lakes
+< WHERE name = 'Blue Lake';
+< Dimension(shore)
+< 2
+< SELECT GeometryType(centerlines)
+< FROM divided_routes
+< WHERE name = 'Route 75';
+< GeometryType(centerlines)
+< MULTILINESTRING
+< SELECT AsText(boundary)
+< FROM named_places
+< WHERE name = 'Goose Island';
+< AsText(boundary)
+< POLYGON((67 13,67 18,59 18,59 13,67 13))
+< SELECT AsText(PolyFromWKB(AsBinary(boundary),101))
+< FROM named_places
+< WHERE name = 'Goose Island';
+< AsText(PolyFromWKB(AsBinary(boundary),101))
+< POLYGON((67 13,67 18,59 18,59 13,67 13))
+< SELECT SRID(boundary)
+< FROM named_places
+< WHERE name = 'Goose Island';
+< SRID(boundary)
+< 101
+< SELECT IsEmpty(centerline)
+< FROM road_segments
+< WHERE name = 'Route 5'
+< AND aliases = 'Main Street';
+< IsEmpty(centerline)
+< 0
+< SELECT AsText(Envelope(boundary))
+< FROM named_places
+< WHERE name = 'Goose Island';
+< AsText(Envelope(boundary))
+< POLYGON((59 13,67 13,67 18,59 18,59 13))
+< SELECT X(position)
+< FROM bridges
+< WHERE name = 'Cam Bridge';
+< X(position)
+< 44
+< SELECT Y(position)
+< FROM bridges
+< WHERE name = 'Cam Bridge';
+< Y(position)
+< 31
+< SELECT AsText(StartPoint(centerline))
+< FROM road_segments
+< WHERE fid = 102;
+< AsText(StartPoint(centerline))
+< POINT(0 18)
+< SELECT AsText(EndPoint(centerline))
+< FROM road_segments
+< WHERE fid = 102;
+< AsText(EndPoint(centerline))
+< POINT(44 31)
+< SELECT GLength(centerline)
+< FROM road_segments
+< WHERE fid = 106;
+< GLength(centerline)
+< 26
+< SELECT NumPoints(centerline)
+< FROM road_segments
+< WHERE fid = 102;
+< NumPoints(centerline)
+< 5
+< SELECT AsText(PointN(centerline, 1))
+< FROM road_segments
+< WHERE fid = 102;
+< AsText(PointN(centerline, 1))
+< POINT(0 18)
+< SELECT AsText(Centroid(boundary))
+< FROM named_places
+< WHERE name = 'Goose Island';
+< AsText(Centroid(boundary))
+< POINT(63 15.5)
+< SELECT Area(boundary)
+< FROM named_places
+< WHERE name = 'Goose Island';
+< Area(boundary)
+< 40
+< SELECT AsText(ExteriorRing(shore))
+< FROM lakes
+< WHERE name = 'Blue Lake';
+< AsText(ExteriorRing(shore))
+< LINESTRING(52 18,66 23,73 9,48 6,52 18)
+< SELECT NumInteriorRings(shore)
+< FROM lakes
+< WHERE name = 'Blue Lake';
+< NumInteriorRings(shore)
+< 1
+< SELECT AsText(InteriorRingN(shore, 1))
+< FROM lakes
+< WHERE name = 'Blue Lake';
+< AsText(InteriorRingN(shore, 1))
+< LINESTRING(59 18,67 18,67 13,59 13,59 18)
+< SELECT NumGeometries(centerlines)
+< FROM divided_routes
+< WHERE name = 'Route 75';
+< NumGeometries(centerlines)
+< 2
+< SELECT AsText(GeometryN(centerlines, 2))
+< FROM divided_routes
+< WHERE name = 'Route 75';
+< AsText(GeometryN(centerlines, 2))
+< LINESTRING(16 0,16 23,16 48)
+< SELECT IsClosed(centerlines)
+< FROM divided_routes
+< WHERE name = 'Route 75';
+< IsClosed(centerlines)
+< 0
+< SELECT GLength(centerlines)
+< FROM divided_routes
+< WHERE name = 'Route 75';
+< GLength(centerlines)
+< 96
+< SELECT AsText(Centroid(shores))
+< FROM ponds
+< WHERE fid = 120;
+< AsText(Centroid(shores))
+< POINT(25 42)
+< SELECT Area(shores)
+< FROM ponds
+< WHERE fid = 120;
+< Area(shores)
+< 8
+< SELECT ST_Equals(boundary,
+< PolyFromText('POLYGON( ( 67 13, 67 18, 59 18, 59 13, 67 13) )',1))
+< FROM named_places
+< WHERE name = 'Goose Island';
+< ST_Equals(boundary,
+< PolyFromText('POLYGON( ( 67 13, 67 18, 59 18, 59 13, 67 13) )',1))
+< 1
+< SELECT ST_Disjoint(centerlines, boundary)
+< FROM divided_routes, named_places
+< WHERE divided_routes.name = 'Route 75'
+< AND named_places.name = 'Ashton';
+< ST_Disjoint(centerlines, boundary)
+< 1
+< SELECT ST_Touches(centerline, shore)
+< FROM streams, lakes
+< WHERE streams.name = 'Cam Stream'
+< AND lakes.name = 'Blue Lake';
+< ST_Touches(centerline, shore)
+< 1
+< SELECT Crosses(road_segments.centerline, divided_routes.centerlines)
+< FROM road_segments, divided_routes
+< WHERE road_segments.fid = 102
+< AND divided_routes.name = 'Route 75';
+< Crosses(road_segments.centerline, divided_routes.centerlines)
+< 1
+< SELECT ST_Intersects(road_segments.centerline, divided_routes.centerlines)
+< FROM road_segments, divided_routes
+< WHERE road_segments.fid = 102
+< AND divided_routes.name = 'Route 75';
+< ST_Intersects(road_segments.centerline, divided_routes.centerlines)
+< 1
+< SELECT ST_Contains(forests.boundary, named_places.boundary)
+< FROM forests, named_places
+< WHERE forests.name = 'Green Forest'
+< AND named_places.name = 'Ashton';
+< ST_Contains(forests.boundary, named_places.boundary)
+< 0
+< SELECT ST_Distance(position, boundary)
+< FROM bridges, named_places
+< WHERE bridges.name = 'Cam Bridge'
+< AND named_places.name = 'Ashton';
+< ST_Distance(position, boundary)
+< 12
+< SELECT AsText(ST_Difference(named_places.boundary, forests.boundary))
+< FROM named_places, forests
+< WHERE named_places.name = 'Ashton'
+< AND forests.name = 'Green Forest';
+< AsText(ST_Difference(named_places.boundary, forests.boundary))
+< POLYGON((56 34,62 48,84 48,84 42,56 34))
+< SELECT AsText(ST_Union(shore, boundary))
+< FROM lakes, named_places
+< WHERE lakes.name = 'Blue Lake'
+< AND named_places.name = 'Goose Island';
+< AsText(ST_Union(shore, boundary))
+< POLYGON((48 6,52 18,66 23,73 9,48 6))
+< SELECT AsText(ST_SymDifference(shore, boundary))
+< FROM lakes, named_places
+< WHERE lakes.name = 'Blue Lake'
+< AND named_places.name = 'Ashton';
+< AsText(ST_SymDifference(shore, boundary))
+< MULTIPOLYGON(((48 6,52 18,66 23,73 9,48 6),(59 13,59 18,67 18,67 13,59 13)),((56 30,56 34,62 48,84 48,84 30,56 30)))
+< SELECT count(*)
+< FROM buildings, bridges
+< WHERE ST_Contains(ST_Buffer(bridges.position, 15.0), buildings.footprint) = 1;
+< count(*)
+< 1
+---
+> ERROR 42000: The storage engine for the table doesn't support GEOMETRY
+> # ERROR: Statement ended with errno 1178, errname ER_CHECK_NOT_IMPLEMENTED (expected to succeed)
+> # ------------ UNEXPECTED RESULT ------------
+> # [ CREATE TABLE gis_point (fid INT(11) /*!*/ /*Custom column options*/, g POINT NOT NULL, SPATIAL INDEX(g)) ENGINE=MRG_MYISAM /*!*/ /*Custom table options*/ UNION(mrg.gis_point) INSERT_METHOD=LAST ]
+> # The statement|command finished with ER_CHECK_NOT_IMPLEMENTED.
+> # Geometry types or spatial indexes or the mix could be unsupported|malfunctioning, or the problem was caused by previous errors.
+> # You can change the engine code, or create an rdiff, or disable the test by adding it to disabled.def.
+> # Further in this test, the message might sometimes be suppressed; a part of the test might be skipped.
+> # Also, this problem may cause a chain effect (more errors of different kinds in the test).
+> # -------------------------------------------
diff --git a/storage/myisammrg/mysql-test/storage_engine/vcol.rdiff b/storage/myisammrg/mysql-test/storage_engine/vcol.rdiff
new file mode 100644
index 00000000000..20431a9c713
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/vcol.rdiff
@@ -0,0 +1,79 @@
+3,69c3,12
+< SHOW COLUMNS IN t1;
+< Field Type Null Key Default Extra
+< a int(11) # #
+< b int(11) # # VIRTUAL
+< INSERT INTO t1 (a) VALUES (1),(2);
+< INSERT INTO t1 (a,b) VALUES (3,3),(4,4);
+< Warnings:
+< Warning 1906 The value specified for computed column 'b' in table 't1' ignored
+< Warning 1906 The value specified for computed column 'b' in table 't1' ignored
+< SELECT * FROM t1;
+< a b
+< 1 2
+< 2 3
+< 3 4
+< 4 5
+< DROP TABLE t1;
+< CREATE TABLE t1 (a <INT_COLUMN>, b <INT_COLUMN> GENERATED ALWAYS AS (a+1) PERSISTENT) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+< SHOW COLUMNS IN t1;
+< Field Type Null Key Default Extra
+< a int(11) # #
+< b int(11) # # PERSISTENT
+< INSERT INTO t1 (a) VALUES (1),(2);
+< INSERT INTO t1 (a,b) VALUES (3,3),(4,4);
+< Warnings:
+< Warning 1906 The value specified for computed column 'b' in table 't1' ignored
+< Warning 1906 The value specified for computed column 'b' in table 't1' ignored
+< SELECT * FROM t1;
+< a b
+< 1 2
+< 2 3
+< 3 4
+< 4 5
+< DROP TABLE t1;
+< CREATE TABLE t1 (a <INT_COLUMN>, b <INT_COLUMN> GENERATED ALWAYS AS (a+1) VIRTUAL) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+< SHOW COLUMNS IN t1;
+< Field Type Null Key Default Extra
+< a int(11) # #
+< b int(11) # # VIRTUAL
+< INSERT INTO t1 (a) VALUES (1),(2);
+< INSERT INTO t1 (a,b) VALUES (3,3),(4,4);
+< Warnings:
+< Warning 1906 The value specified for computed column 'b' in table 't1' ignored
+< Warning 1906 The value specified for computed column 'b' in table 't1' ignored
+< SELECT * FROM t1;
+< a b
+< 1 2
+< 2 3
+< 3 4
+< 4 5
+< DROP TABLE t1;
+< CREATE TABLE t1 (a <INT_COLUMN>, b <INT_COLUMN> AS (a+1) PERSISTENT) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+< SHOW COLUMNS IN t1;
+< Field Type Null Key Default Extra
+< a int(11) # #
+< b int(11) # # PERSISTENT
+< INSERT INTO t1 (a) VALUES (1),(2);
+< INSERT INTO t1 (a,b) VALUES (3,3),(4,4);
+< Warnings:
+< Warning 1906 The value specified for computed column 'b' in table 't1' ignored
+< Warning 1906 The value specified for computed column 'b' in table 't1' ignored
+< SELECT * FROM t1;
+< a b
+< 1 2
+< 2 3
+< 3 4
+< 4 5
+< DROP TABLE t1;
+---
+> ERROR HY000: MRG_MYISAM storage engine does not support computed columns
+> # ERROR: Statement ended with errno 1910, errname ER_UNSUPPORTED_ENGINE_FOR_VIRTUAL_COLUMNS (expected to succeed)
+> # ------------ UNEXPECTED RESULT ------------
+> # [ CREATE TABLE t1 (a INT(11) /*!*/ /*Custom column options*/, b INT(11) /*!*/ /*Custom column options*/ GENERATED ALWAYS AS (a+1)) ENGINE=MRG_MYISAM /*!*/ /*Custom table options*/ UNION(mrg.t1) INSERT_METHOD=LAST ]
+> # The statement|command finished with ER_UNSUPPORTED_ENGINE_FOR_VIRTUAL_COLUMNS.
+> # Virtual columns or the mix could be unsupported|malfunctioning, or the problem was caused by previous errors.
+> # You can change the engine code, or create an rdiff, or disable the test by adding it to disabled.def.
+> # Further in this test, the message might sometimes be suppressed; a part of the test might be skipped.
+> # Also, this problem may cause a chain effect (more errors of different kinds in the test).
+> # -------------------------------------------
diff --git a/storage/oqgraph/CMakeLists.txt b/storage/oqgraph/CMakeLists.txt
index 4b8dac20350..ecd2d46dad3 100644
--- a/storage/oqgraph/CMakeLists.txt
+++ b/storage/oqgraph/CMakeLists.txt
@@ -1,14 +1,24 @@
-FIND_PACKAGE(Boost 1.45.0) # we need at least 1.45 if we want -fno-rtti for the server
+FIND_PACKAGE(Boost 1.40.0)
IF(NOT Boost_FOUND)
RETURN()
ENDIF()
INCLUDE_DIRECTORIES(BEFORE ${Boost_INCLUDE_DIRS})
-# lp:756966 OQGRAPH on Win64 does not compile
-IF(MSVC AND CMAKE_SIZEOF_VOID_P EQUAL 8)
- SET(BOOST_OK 0)
+IF(MSVC)
+ # lp:756966 OQGRAPH on Win64 does not compile
+ IF (CMAKE_SIZEOF_VOID_P EQUAL 8)
+ SET(BOOST_OK 0)
+ ELSE()
+ SET(BOOST_OK 1)
+ ENDIF()
ELSE()
- SET(BOOST_OK 1)
+# See if that works. On old gcc it'll fail because of -fno-rtti
+CHECK_CXX_SOURCE_COMPILES(
+"
+#include <boost/config.hpp>
+#include <boost/property_map/property_map.hpp>
+int main() { return 0; }
+" BOOST_OK)
ENDIF()
IF(BOOST_OK)
diff --git a/storage/xtradb/btr/btr0btr.c b/storage/xtradb/btr/btr0btr.c
index 433b062bcec..1fa6df44f7c 100644
--- a/storage/xtradb/btr/btr0btr.c
+++ b/storage/xtradb/btr/btr0btr.c
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1994, 2010, Innobase Oy. All Rights Reserved.
+Copyright (c) 1994, 2012, Oracle and/or its affiliates. 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
@@ -11,8 +11,8 @@ 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 program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
*****************************************************************************/
@@ -42,6 +42,28 @@ Created 6/2/1994 Heikki Tuuri
#include "ibuf0ibuf.h"
#include "trx0trx.h"
+/**************************************************************//**
+Report that an index page is corrupted. */
+UNIV_INTERN
+void
+btr_corruption_report(
+/*==================*/
+ const buf_block_t* block, /*!< in: corrupted block */
+ const dict_index_t* index) /*!< in: index tree */
+{
+ fprintf(stderr, "InnoDB: flag mismatch in space %u page %u"
+ " index %s of table %s\n",
+ (unsigned) buf_block_get_space(block),
+ (unsigned) buf_block_get_page_no(block),
+ index->name, index->table_name);
+ if (block->page.zip.data) {
+ buf_page_print(block->page.zip.data,
+ buf_block_get_zip_size(block),
+ BUF_PAGE_PRINT_NO_CRASH);
+ }
+ buf_page_print(buf_block_get_frame(block), 0, 0);
+}
+
#ifdef UNIV_BLOB_DEBUG
# include "srv0srv.h"
# include "ut0rbt.h"
@@ -664,6 +686,12 @@ btr_root_fseg_validate(
{
ulint offset = mach_read_from_2(seg_header + FSEG_HDR_OFFSET);
+ if (UNIV_UNLIKELY(srv_pass_corrupt_table)) {
+ return (mach_read_from_4(seg_header + FSEG_HDR_SPACE) == space)
+ && (offset >= FIL_PAGE_DATA)
+ && (offset <= UNIV_PAGE_SIZE - FIL_PAGE_DATA_END);
+ }
+
ut_a(mach_read_from_4(seg_header + FSEG_HDR_SPACE) == space);
ut_a(offset >= FIL_PAGE_DATA);
ut_a(offset <= UNIV_PAGE_SIZE - FIL_PAGE_DATA_END);
@@ -698,12 +726,22 @@ btr_root_block_get(
}
ut_a(block);
- ut_a((ibool)!!page_is_comp(buf_block_get_frame(block))
- == dict_table_is_comp(index->table));
+ btr_assert_not_corrupted(block, index);
#ifdef UNIV_BTR_DEBUG
if (!dict_index_is_ibuf(index)) {
const page_t* root = buf_block_get_frame(block);
+ if (UNIV_UNLIKELY(srv_pass_corrupt_table)) {
+ if (!btr_root_fseg_validate(FIL_PAGE_DATA
+ + PAGE_BTR_SEG_LEAF
+ + root, space))
+ return(NULL);
+ if (!btr_root_fseg_validate(FIL_PAGE_DATA
+ + PAGE_BTR_SEG_TOP
+ + root, space))
+ return(NULL);
+ return(block);
+ }
ut_a(btr_root_fseg_validate(FIL_PAGE_DATA + PAGE_BTR_SEG_LEAF
+ root, space));
ut_a(btr_root_fseg_validate(FIL_PAGE_DATA + PAGE_BTR_SEG_TOP
@@ -912,28 +950,31 @@ btr_page_alloc_for_ibuf(
/**************************************************************//**
Allocates a new file page to be used in an index tree. NOTE: we assume
that the caller has made the reservation for free extents!
-@return new allocated block, x-latched; NULL if out of space */
-UNIV_INTERN
+@retval NULL if no page could be allocated
+@retval block, rw_lock_x_lock_count(&block->lock) == 1 if allocation succeeded
+(init_mtr == mtr, or the page was not previously freed in mtr)
+@retval block (not allocated or initialized) otherwise */
+static __attribute__((nonnull, warn_unused_result))
buf_block_t*
-btr_page_alloc(
-/*===========*/
+btr_page_alloc_low(
+/*===============*/
dict_index_t* index, /*!< in: index */
ulint hint_page_no, /*!< in: hint of a good page */
byte file_direction, /*!< in: direction where a possible
page split is made */
ulint level, /*!< in: level where the page is placed
in the tree */
- mtr_t* mtr) /*!< in: mtr */
+ mtr_t* mtr, /*!< in/out: mini-transaction
+ for the allocation */
+ mtr_t* init_mtr) /*!< in/out: mtr or another
+ mini-transaction in which the
+ page should be initialized.
+ If init_mtr!=mtr, but the page
+ is already X-latched in mtr, do
+ not initialize the page. */
{
fseg_header_t* seg_header;
page_t* root;
- buf_block_t* new_block;
- ulint new_page_no;
-
- if (dict_index_is_ibuf(index)) {
-
- return(btr_page_alloc_for_ibuf(index, mtr));
- }
root = btr_root_get(index, mtr);
@@ -947,45 +988,81 @@ btr_page_alloc(
reservation for free extents, and thus we know that a page can
be allocated: */
- new_page_no = fseg_alloc_free_page_general(seg_header, hint_page_no,
- file_direction, TRUE, mtr);
- if (new_page_no == FIL_NULL) {
+ return(fseg_alloc_free_page_general(
+ seg_header, hint_page_no, file_direction,
+ TRUE, mtr, init_mtr));
+}
- return(NULL);
+/**************************************************************//**
+Allocates a new file page to be used in an index tree. NOTE: we assume
+that the caller has made the reservation for free extents!
+@retval NULL if no page could be allocated
+@retval block, rw_lock_x_lock_count(&block->lock) == 1 if allocation succeeded
+(init_mtr == mtr, or the page was not previously freed in mtr)
+@retval block (not allocated or initialized) otherwise */
+UNIV_INTERN
+buf_block_t*
+btr_page_alloc(
+/*===========*/
+ dict_index_t* index, /*!< in: index */
+ ulint hint_page_no, /*!< in: hint of a good page */
+ byte file_direction, /*!< in: direction where a possible
+ page split is made */
+ ulint level, /*!< in: level where the page is placed
+ in the tree */
+ mtr_t* mtr, /*!< in/out: mini-transaction
+ for the allocation */
+ mtr_t* init_mtr) /*!< in/out: mini-transaction
+ for x-latching and initializing
+ the page */
+{
+ buf_block_t* new_block;
+
+ if (dict_index_is_ibuf(index)) {
+
+ return(btr_page_alloc_for_ibuf(index, mtr));
}
- new_block = buf_page_get(dict_index_get_space(index),
- dict_table_zip_size(index->table),
- new_page_no, RW_X_LATCH, mtr);
- buf_block_dbg_add_level(new_block, SYNC_TREE_NODE_NEW);
+ new_block = btr_page_alloc_low(
+ index, hint_page_no, file_direction, level, mtr, init_mtr);
+
+ if (new_block) {
+ buf_block_dbg_add_level(new_block, SYNC_TREE_NODE_NEW);
+ }
return(new_block);
}
/**************************************************************//**
Gets the number of pages in a B-tree.
-@return number of pages */
+@return number of pages, or ULINT_UNDEFINED if the index is unavailable */
UNIV_INTERN
ulint
btr_get_size(
/*=========*/
dict_index_t* index, /*!< in: index */
- ulint flag) /*!< in: BTR_N_LEAF_PAGES or BTR_TOTAL_SIZE */
+ ulint flag, /*!< in: BTR_N_LEAF_PAGES or BTR_TOTAL_SIZE */
+ mtr_t* mtr) /*!< in/out: mini-transaction where index
+ is s-latched */
{
fseg_header_t* seg_header;
page_t* root;
ulint n;
ulint dummy;
- mtr_t mtr;
- mtr_start(&mtr);
+ ut_ad(mtr_memo_contains(mtr, dict_index_get_lock(index),
+ MTR_MEMO_S_LOCK));
- mtr_s_lock(dict_index_get_lock(index), &mtr);
+ if (index->page == FIL_NULL
+ || index->to_be_dropped
+ || *index->name == TEMP_INDEX_PREFIX) {
+ return(ULINT_UNDEFINED);
+ }
- root = btr_root_get(index, &mtr);
+ root = btr_root_get(index, mtr);
if (srv_pass_corrupt_table && !root) {
- mtr_commit(&mtr);
+ mtr_commit(mtr);
return(0);
}
ut_a(root);
@@ -993,22 +1070,20 @@ btr_get_size(
if (flag == BTR_N_LEAF_PAGES) {
seg_header = root + PAGE_HEADER + PAGE_BTR_SEG_LEAF;
- fseg_n_reserved_pages(seg_header, &n, &mtr);
+ fseg_n_reserved_pages(seg_header, &n, mtr);
} else if (flag == BTR_TOTAL_SIZE) {
seg_header = root + PAGE_HEADER + PAGE_BTR_SEG_TOP;
- n = fseg_n_reserved_pages(seg_header, &dummy, &mtr);
+ n = fseg_n_reserved_pages(seg_header, &dummy, mtr);
seg_header = root + PAGE_HEADER + PAGE_BTR_SEG_LEAF;
- n += fseg_n_reserved_pages(seg_header, &dummy, &mtr);
+ n += fseg_n_reserved_pages(seg_header, &dummy, mtr);
} else {
ut_error;
}
- mtr_commit(&mtr);
-
return(n);
}
@@ -1090,10 +1165,10 @@ btr_page_free(
buf_block_t* block, /*!< in: block to be freed, x-latched */
mtr_t* mtr) /*!< in: mtr */
{
- ulint level;
-
- level = btr_page_get_level(buf_block_get_frame(block), mtr);
+ const page_t* page = buf_block_get_frame(block);
+ ulint level = btr_page_get_level(page, mtr);
+ ut_ad(fil_page_get_type(block->frame) == FIL_PAGE_INDEX);
btr_page_free_low(index, block, level, mtr);
}
@@ -1207,9 +1282,11 @@ btr_page_get_father_node_ptr_func(
!= page_no)) {
rec_t* print_rec;
fputs("InnoDB: Dump of the child page:\n", stderr);
- buf_page_print(page_align(user_rec), 0);
+ buf_page_print(page_align(user_rec), 0,
+ BUF_PAGE_PRINT_NO_CRASH);
fputs("InnoDB: Dump of the parent page:\n", stderr);
- buf_page_print(page_align(node_ptr), 0);
+ buf_page_print(page_align(node_ptr), 0,
+ BUF_PAGE_PRINT_NO_CRASH);
fputs("InnoDB: Corruption of an index tree: table ", stderr);
ut_print_name(stderr, NULL, TRUE, index->table_name);
@@ -1333,16 +1410,12 @@ btr_create(
/* Allocate then the next page to the segment: it will be the
tree root page */
- page_no = fseg_alloc_free_page(buf_block_get_frame(
- ibuf_hdr_block)
- + IBUF_HEADER
- + IBUF_TREE_SEG_HEADER,
- IBUF_TREE_ROOT_PAGE_NO,
- FSP_UP, mtr);
- ut_ad(page_no == IBUF_TREE_ROOT_PAGE_NO);
-
- block = buf_page_get(space, zip_size, page_no,
- RW_X_LATCH, mtr);
+ block = fseg_alloc_free_page(
+ buf_block_get_frame(ibuf_hdr_block)
+ + IBUF_HEADER + IBUF_TREE_SEG_HEADER,
+ IBUF_TREE_ROOT_PAGE_NO,
+ FSP_UP, mtr);
+ ut_ad(buf_block_get_page_no(block) == IBUF_TREE_ROOT_PAGE_NO);
} else {
#ifdef UNIV_BLOB_DEBUG
if ((type & DICT_CLUSTERED) && !index->blobs) {
@@ -1562,7 +1635,7 @@ btr_page_reorganize_low(
ibool success = FALSE;
ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX));
- ut_ad(!!page_is_comp(page) == dict_table_is_comp(index->table));
+ btr_assert_not_corrupted(block, index);
#ifdef UNIV_ZIP_DEBUG
ut_a(!page_zip || page_zip_validate(page_zip, page));
#endif /* UNIV_ZIP_DEBUG */
@@ -1664,8 +1737,8 @@ btr_page_reorganize_low(
if (UNIV_UNLIKELY(data_size1 != data_size2)
|| UNIV_UNLIKELY(max_ins_size1 != max_ins_size2)) {
- buf_page_print(page, 0);
- buf_page_print(temp_page, 0);
+ buf_page_print(page, 0, BUF_PAGE_PRINT_NO_CRASH);
+ buf_page_print(temp_page, 0, BUF_PAGE_PRINT_NO_CRASH);
fprintf(stderr,
"InnoDB: Error: page old data size %lu"
" new data size %lu\n"
@@ -1676,6 +1749,7 @@ btr_page_reorganize_low(
(unsigned long) data_size1, (unsigned long) data_size2,
(unsigned long) max_ins_size1,
(unsigned long) max_ins_size2);
+ ut_ad(0);
} else {
success = TRUE;
}
@@ -1839,7 +1913,7 @@ btr_root_raise_and_insert(
level = btr_page_get_level(root, mtr);
- new_block = btr_page_alloc(index, 0, FSP_NO_DIR, level, mtr);
+ new_block = btr_page_alloc(index, 0, FSP_NO_DIR, level, mtr, mtr);
new_page = buf_block_get_frame(new_block);
new_page_zip = buf_block_get_page_zip(new_block);
ut_a(!new_page_zip == !root_page_zip);
@@ -2575,7 +2649,7 @@ func_start:
/* 2. Allocate a new page to the index */
new_block = btr_page_alloc(cursor->index, hint_page_no, direction,
- btr_page_get_level(page, mtr), mtr);
+ btr_page_get_level(page, mtr), mtr, mtr);
new_page = buf_block_get_frame(new_block);
new_page_zip = buf_block_get_page_zip(new_block);
btr_page_create(new_block, new_page_zip, cursor->index,
@@ -3025,15 +3099,16 @@ btr_node_ptr_delete(
ut_a(err == DB_SUCCESS);
if (!compressed) {
- btr_cur_compress_if_useful(&cursor, mtr);
+ btr_cur_compress_if_useful(&cursor, FALSE, mtr);
}
}
/*************************************************************//**
If page is the only on its level, this function moves its records to the
-father page, thus reducing the tree height. */
+father page, thus reducing the tree height.
+@return father block */
static
-void
+buf_block_t*
btr_lift_page_up(
/*=============*/
dict_index_t* index, /*!< in: index tree */
@@ -3150,6 +3225,8 @@ btr_lift_page_up(
}
ut_ad(page_validate(father_page, index));
ut_ad(btr_check_node_ptr(index, father_block, mtr));
+
+ return(father_block);
}
/*************************************************************//**
@@ -3166,11 +3243,13 @@ UNIV_INTERN
ibool
btr_compress(
/*=========*/
- btr_cur_t* cursor, /*!< in: cursor on the page to merge or lift;
- the page must not be empty: in record delete
- use btr_discard_page if the page would become
- empty */
- mtr_t* mtr) /*!< in: mtr */
+ btr_cur_t* cursor, /*!< in/out: cursor on the page to merge
+ or lift; the page must not be empty:
+ when deleting records, use btr_discard_page()
+ if the page would become empty */
+ ibool adjust, /*!< in: TRUE if should adjust the
+ cursor position even if compression occurs */
+ mtr_t* mtr) /*!< in/out: mini-transaction */
{
dict_index_t* index;
ulint space;
@@ -3188,13 +3267,15 @@ btr_compress(
ulint* offsets;
ulint data_size;
ulint n_recs;
+ ulint nth_rec = 0; /* remove bogus warning */
ulint max_ins_size;
ulint max_ins_size_reorg;
block = btr_cur_get_block(cursor);
page = btr_cur_get_page(cursor);
index = btr_cur_get_index(cursor);
- ut_a((ibool) !!page_is_comp(page) == dict_table_is_comp(index->table));
+
+ btr_assert_not_corrupted(block, index);
ut_ad(mtr_memo_contains(mtr, dict_index_get_lock(index),
MTR_MEMO_X_LOCK));
@@ -3214,6 +3295,10 @@ btr_compress(
offsets = btr_page_get_father_block(NULL, heap, index, block, mtr,
&father_cursor);
+ if (adjust) {
+ nth_rec = page_rec_get_n_recs_before(btr_cur_get_rec(cursor));
+ }
+
/* Decide the page to which we try to merge and which will inherit
the locks */
@@ -3240,9 +3325,9 @@ btr_compress(
} else {
/* The page is the only one on the level, lift the records
to the father */
- btr_lift_page_up(index, block, mtr);
- mem_heap_free(heap);
- return(TRUE);
+
+ merge_block = btr_lift_page_up(index, block, mtr);
+ goto func_exit;
}
n_recs = page_get_n_recs(page);
@@ -3324,6 +3409,10 @@ err_exit:
btr_node_ptr_delete(index, block, mtr);
lock_update_merge_left(merge_block, orig_pred, block);
+
+ if (adjust) {
+ nth_rec += page_rec_get_n_recs_before(orig_pred);
+ }
} else {
rec_t* orig_succ;
#ifdef UNIV_BTR_DEBUG
@@ -3388,7 +3477,6 @@ err_exit:
}
btr_blob_dbg_remove(page, index, "btr_compress");
- mem_heap_free(heap);
if (!dict_index_is_clust(index) && page_is_leaf(merge_page)) {
/* Update the free bits of the B-tree page in the
@@ -3440,6 +3528,16 @@ err_exit:
btr_page_free(index, block, mtr);
ut_ad(btr_check_node_ptr(index, merge_block, mtr));
+func_exit:
+ mem_heap_free(heap);
+
+ if (adjust) {
+ btr_cur_position(
+ index,
+ page_rec_get_nth(merge_block->frame, nth_rec),
+ merge_block, cursor);
+ }
+
return(TRUE);
}
@@ -3876,7 +3974,7 @@ btr_index_rec_validate(
(ulong) rec_get_n_fields_old(rec), (ulong) n);
if (dump_on_error) {
- buf_page_print(page, 0);
+ buf_page_print(page, 0, BUF_PAGE_PRINT_NO_CRASH);
fputs("InnoDB: corrupt record ", stderr);
rec_print_old(stderr, rec);
@@ -3914,7 +4012,8 @@ btr_index_rec_validate(
(ulong) i, (ulong) len, (ulong) fixed_size);
if (dump_on_error) {
- buf_page_print(page, 0);
+ buf_page_print(page, 0,
+ BUF_PAGE_PRINT_NO_CRASH);
fputs("InnoDB: corrupt record ", stderr);
rec_print_new(stderr, rec, offsets);
@@ -4124,8 +4223,8 @@ loop:
btr_validate_report2(index, level, block, right_block);
fputs("InnoDB: broken FIL_PAGE_NEXT"
" or FIL_PAGE_PREV links\n", stderr);
- buf_page_print(page, 0);
- buf_page_print(right_page, 0);
+ buf_page_print(page, 0, BUF_PAGE_PRINT_NO_CRASH);
+ buf_page_print(right_page, 0, BUF_PAGE_PRINT_NO_CRASH);
ret = FALSE;
}
@@ -4134,8 +4233,8 @@ loop:
!= page_is_comp(page))) {
btr_validate_report2(index, level, block, right_block);
fputs("InnoDB: 'compact' flag mismatch\n", stderr);
- buf_page_print(page, 0);
- buf_page_print(right_page, 0);
+ buf_page_print(page, 0, BUF_PAGE_PRINT_NO_CRASH);
+ buf_page_print(right_page, 0, BUF_PAGE_PRINT_NO_CRASH);
ret = FALSE;
@@ -4158,8 +4257,8 @@ loop:
fputs("InnoDB: records in wrong order"
" on adjacent pages\n", stderr);
- buf_page_print(page, 0);
- buf_page_print(right_page, 0);
+ buf_page_print(page, 0, BUF_PAGE_PRINT_NO_CRASH);
+ buf_page_print(right_page, 0, BUF_PAGE_PRINT_NO_CRASH);
fputs("InnoDB: record ", stderr);
rec = page_rec_get_prev(page_get_supremum_rec(page));
@@ -4208,8 +4307,8 @@ loop:
fputs("InnoDB: node pointer to the page is wrong\n",
stderr);
- buf_page_print(father_page, 0);
- buf_page_print(page, 0);
+ buf_page_print(father_page, 0, BUF_PAGE_PRINT_NO_CRASH);
+ buf_page_print(page, 0, BUF_PAGE_PRINT_NO_CRASH);
fputs("InnoDB: node ptr ", stderr);
rec_print(stderr, node_ptr, index);
@@ -4241,8 +4340,10 @@ loop:
btr_validate_report1(index, level, block);
- buf_page_print(father_page, 0);
- buf_page_print(page, 0);
+ buf_page_print(father_page, 0,
+ BUF_PAGE_PRINT_NO_CRASH);
+ buf_page_print(page, 0,
+ BUF_PAGE_PRINT_NO_CRASH);
fputs("InnoDB: Error: node ptrs differ"
" on levels > 0\n"
@@ -4287,9 +4388,15 @@ loop:
btr_validate_report1(index, level,
block);
- buf_page_print(father_page, 0);
- buf_page_print(page, 0);
- buf_page_print(right_page, 0);
+ buf_page_print(
+ father_page, 0,
+ BUF_PAGE_PRINT_NO_CRASH);
+ buf_page_print(
+ page, 0,
+ BUF_PAGE_PRINT_NO_CRASH);
+ buf_page_print(
+ right_page, 0,
+ BUF_PAGE_PRINT_NO_CRASH);
}
} else {
page_t* right_father_page
@@ -4307,10 +4414,18 @@ loop:
btr_validate_report1(index, level,
block);
- buf_page_print(father_page, 0);
- buf_page_print(right_father_page, 0);
- buf_page_print(page, 0);
- buf_page_print(right_page, 0);
+ buf_page_print(
+ father_page, 0,
+ BUF_PAGE_PRINT_NO_CRASH);
+ buf_page_print(
+ right_father_page, 0,
+ BUF_PAGE_PRINT_NO_CRASH);
+ buf_page_print(
+ page, 0,
+ BUF_PAGE_PRINT_NO_CRASH);
+ buf_page_print(
+ right_page, 0,
+ BUF_PAGE_PRINT_NO_CRASH);
}
if (page_get_page_no(right_father_page)
@@ -4324,10 +4439,18 @@ loop:
btr_validate_report1(index, level,
block);
- buf_page_print(father_page, 0);
- buf_page_print(right_father_page, 0);
- buf_page_print(page, 0);
- buf_page_print(right_page, 0);
+ buf_page_print(
+ father_page, 0,
+ BUF_PAGE_PRINT_NO_CRASH);
+ buf_page_print(
+ right_father_page, 0,
+ BUF_PAGE_PRINT_NO_CRASH);
+ buf_page_print(
+ page, 0,
+ BUF_PAGE_PRINT_NO_CRASH);
+ buf_page_print(
+ right_page, 0,
+ BUF_PAGE_PRINT_NO_CRASH);
}
}
}
@@ -4372,6 +4495,12 @@ btr_validate_index(
mtr_x_lock(dict_index_get_lock(index), &mtr);
root = btr_root_get(index, &mtr);
+
+ if (UNIV_UNLIKELY(srv_pass_corrupt_table && !root)) {
+ mtr_commit(&mtr);
+ return(FALSE);
+ }
+
n = btr_page_get_level(root, &mtr);
for (i = 0; i <= n && !trx_is_interrupted(trx); i++) {
diff --git a/storage/xtradb/btr/btr0cur.c b/storage/xtradb/btr/btr0cur.c
index 43313474071..e093dabebf1 100644
--- a/storage/xtradb/btr/btr0cur.c
+++ b/storage/xtradb/btr/btr0cur.c
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1994, 2011, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1994, 2012, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2008, Google Inc.
Portions of this file contain modifications contributed and copyrighted by
@@ -18,8 +18,8 @@ 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 program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
*****************************************************************************/
@@ -438,7 +438,12 @@ btr_cur_search_to_nth_level(
ut_ad(dict_index_check_search_tuple(index, tuple));
ut_ad(!dict_index_is_ibuf(index) || ibuf_inside(mtr));
ut_ad(dtuple_check_typed(tuple));
+ ut_ad(index->page != FIL_NULL);
+ UNIV_MEM_INVALID(&cursor->up_match, sizeof cursor->up_match);
+ UNIV_MEM_INVALID(&cursor->up_bytes, sizeof cursor->up_bytes);
+ UNIV_MEM_INVALID(&cursor->low_match, sizeof cursor->low_match);
+ UNIV_MEM_INVALID(&cursor->low_bytes, sizeof cursor->low_bytes);
#ifdef UNIV_DEBUG
cursor->up_match = ULINT_UNDEFINED;
cursor->low_match = ULINT_UNDEFINED;
@@ -810,11 +815,11 @@ retry_page_get:
if (level != 0) {
/* x-latch the page */
- page = btr_page_get(
+ buf_block_t* child_block = btr_block_get(
space, zip_size, page_no, RW_X_LATCH, index, mtr);
- ut_a((ibool)!!page_is_comp(page)
- == dict_table_is_comp(index->table));
+ page = buf_block_get_frame(child_block);
+ btr_assert_not_corrupted(child_block, index);
} else {
cursor->low_match = low_match;
cursor->low_bytes = low_bytes;
@@ -1959,7 +1964,7 @@ btr_cur_update_in_place(
page_zip = buf_block_get_page_zip(block);
/* Check that enough space is available on the compressed page. */
- if (UNIV_LIKELY_NULL(page_zip)
+ if (page_zip
&& !btr_cur_update_alloc_zip(page_zip, block, index,
rec_offs_size(offsets), FALSE, mtr)) {
return(DB_ZIP_OVERFLOW);
@@ -2158,7 +2163,7 @@ any_extern:
ut_a(!page_zip || page_zip_validate(page_zip, page));
#endif /* UNIV_ZIP_DEBUG */
- if (UNIV_LIKELY_NULL(page_zip)
+ if (page_zip
&& !btr_cur_update_alloc_zip(page_zip, block, index,
new_rec_size, TRUE, mtr)) {
err = DB_ZIP_OVERFLOW;
@@ -2321,7 +2326,9 @@ btr_cur_pessimistic_update(
/*=======================*/
ulint flags, /*!< in: undo logging, locking, and rollback
flags */
- btr_cur_t* cursor, /*!< in: cursor on the record to update */
+ btr_cur_t* cursor, /*!< in/out: cursor on the record to update;
+ cursor may become invalid if *big_rec == NULL
+ || !(flags & BTR_KEEP_POS_FLAG) */
mem_heap_t** heap, /*!< in/out: pointer to memory heap, or NULL */
big_rec_t** big_rec,/*!< out: big rec vector whose fields have to
be stored externally by the caller, or NULL */
@@ -2463,10 +2470,10 @@ btr_cur_pessimistic_update(
record to be inserted: we have to remember which fields were such */
ut_ad(!page_is_comp(page) || !rec_get_node_ptr_flag(rec));
- offsets = rec_get_offsets(rec, index, offsets, ULINT_UNDEFINED, heap);
+ ut_ad(rec_offs_validate(rec, index, offsets));
n_ext += btr_push_update_extern_fields(new_entry, update, *heap);
- if (UNIV_LIKELY_NULL(page_zip)) {
+ if (page_zip) {
ut_ad(page_is_comp(page));
if (page_zip_rec_needs_ext(
rec_get_converted_size(index, new_entry, n_ext),
@@ -2486,6 +2493,10 @@ make_external:
err = DB_TOO_BIG_RECORD;
goto return_after_reservations;
}
+
+ ut_ad(page_is_leaf(page));
+ ut_ad(dict_index_is_clust(index));
+ ut_ad(flags & BTR_KEEP_POS_FLAG);
}
if (trx->fake_changes) {
@@ -2519,6 +2530,8 @@ make_external:
rec = btr_cur_insert_if_possible(cursor, new_entry, n_ext, mtr);
if (rec) {
+ page_cursor->rec = rec;
+
lock_rec_restore_from_page_infimum(btr_cur_get_block(cursor),
rec, block);
@@ -2532,7 +2545,10 @@ make_external:
rec, index, offsets, mtr);
}
- btr_cur_compress_if_useful(cursor, mtr);
+ btr_cur_compress_if_useful(
+ cursor,
+ big_rec_vec != NULL && (flags & BTR_KEEP_POS_FLAG),
+ mtr);
if (page_zip && !dict_index_is_clust(index)
&& page_is_leaf(page)) {
@@ -2552,6 +2568,21 @@ make_external:
}
}
+ if (big_rec_vec) {
+ ut_ad(page_is_leaf(page));
+ ut_ad(dict_index_is_clust(index));
+ ut_ad(flags & BTR_KEEP_POS_FLAG);
+
+ /* btr_page_split_and_insert() in
+ btr_cur_pessimistic_insert() invokes
+ mtr_memo_release(mtr, index->lock, MTR_MEMO_X_LOCK).
+ We must keep the index->lock when we created a
+ big_rec, so that row_upd_clust_rec() can store the
+ big_rec in the same mini-transaction. */
+
+ mtr_x_lock(dict_index_get_lock(index), mtr);
+ }
+
/* Was the record to be updated positioned as the first user
record on its page? */
was_first = page_cur_is_before_first(page_cursor);
@@ -2567,6 +2598,7 @@ make_external:
ut_a(rec);
ut_a(err == DB_SUCCESS);
ut_a(dummy_big_rec == NULL);
+ page_cursor->rec = rec;
if (dict_index_is_sec_or_ibuf(index)) {
/* Update PAGE_MAX_TRX_ID in the index page header.
@@ -3011,10 +3043,12 @@ UNIV_INTERN
ibool
btr_cur_compress_if_useful(
/*=======================*/
- btr_cur_t* cursor, /*!< in: cursor on the page to compress;
- cursor does not stay valid if compression
- occurs */
- mtr_t* mtr) /*!< in: mtr */
+ btr_cur_t* cursor, /*!< in/out: cursor on the page to compress;
+ cursor does not stay valid if !adjust and
+ compression occurs */
+ ibool adjust, /*!< in: TRUE if should adjust the
+ cursor position even if compression occurs */
+ mtr_t* mtr) /*!< in/out: mini-transaction */
{
ut_ad(mtr_memo_contains(mtr,
dict_index_get_lock(btr_cur_get_index(cursor)),
@@ -3023,7 +3057,7 @@ btr_cur_compress_if_useful(
MTR_MEMO_PAGE_X_FIX));
return(btr_cur_compress_recommendation(cursor, mtr)
- && btr_compress(cursor, mtr));
+ && btr_compress(cursor, adjust, mtr));
}
/*******************************************************//**
@@ -3270,7 +3304,7 @@ return_after_reservations:
mem_heap_free(heap);
if (ret == FALSE) {
- ret = btr_cur_compress_if_useful(cursor, mtr);
+ ret = btr_cur_compress_if_useful(cursor, FALSE, mtr);
}
if (n_extents > 0) {
@@ -4011,10 +4045,10 @@ btr_cur_set_ownership_of_extern_field(
byte_val = byte_val | BTR_EXTERN_OWNER_FLAG;
}
- if (UNIV_LIKELY_NULL(page_zip)) {
+ if (page_zip) {
mach_write_to_1(data + local_len + BTR_EXTERN_LEN, byte_val);
page_zip_write_blob_ptr(page_zip, rec, index, offsets, i, mtr);
- } else if (UNIV_LIKELY(mtr != NULL)) {
+ } else if (mtr != NULL) {
mlog_write_ulint(data + local_len + BTR_EXTERN_LEN, byte_val,
MLOG_1BYTE, mtr);
@@ -4253,9 +4287,9 @@ The fields are stored on pages allocated from leaf node
file segment of the index tree.
@return DB_SUCCESS or DB_OUT_OF_FILE_SPACE */
UNIV_INTERN
-ulint
-btr_store_big_rec_extern_fields_func(
-/*=================================*/
+enum db_err
+btr_store_big_rec_extern_fields(
+/*============================*/
dict_index_t* index, /*!< in: index of rec; the index tree
MUST be X-latched */
buf_block_t* rec_block, /*!< in/out: block containing rec */
@@ -4264,38 +4298,37 @@ btr_store_big_rec_extern_fields_func(
the "external storage" flags in offsets
will not correspond to rec when
this function returns */
-#ifdef UNIV_DEBUG
- mtr_t* local_mtr, /*!< in: mtr containing the
- latch to rec and to the tree */
-#endif /* UNIV_DEBUG */
-#if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG
- ibool update_in_place,/*! in: TRUE if the record is updated
- in place (not delete+insert) */
-#endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */
- const big_rec_t*big_rec_vec) /*!< in: vector containing fields
+ const big_rec_t*big_rec_vec, /*!< in: vector containing fields
to be stored externally */
-
+ mtr_t* btr_mtr, /*!< in: mtr containing the
+ latches to the clustered index */
+ enum blob_op op) /*! in: operation code */
{
- ulint rec_page_no;
- byte* field_ref;
- ulint extern_len;
- ulint store_len;
- ulint page_no;
- ulint space_id;
- ulint zip_size;
- ulint prev_page_no;
- ulint hint_page_no;
- ulint i;
- mtr_t mtr;
- mem_heap_t* heap = NULL;
+ ulint rec_page_no;
+ byte* field_ref;
+ ulint extern_len;
+ ulint store_len;
+ ulint page_no;
+ ulint space_id;
+ ulint zip_size;
+ ulint prev_page_no;
+ ulint hint_page_no;
+ ulint i;
+ mtr_t mtr;
+ mtr_t* alloc_mtr;
+ mem_heap_t* heap = NULL;
page_zip_des_t* page_zip;
- z_stream c_stream;
+ z_stream c_stream;
+ buf_block_t** freed_pages = NULL;
+ ulint n_freed_pages = 0;
+ enum db_err error = DB_SUCCESS;
ut_ad(rec_offs_validate(rec, index, offsets));
ut_ad(rec_offs_any_extern(offsets));
- ut_ad(mtr_memo_contains(local_mtr, dict_index_get_lock(index),
+ ut_ad(btr_mtr);
+ ut_ad(mtr_memo_contains(btr_mtr, dict_index_get_lock(index),
MTR_MEMO_X_LOCK));
- ut_ad(mtr_memo_contains(local_mtr, rec_block, MTR_MEMO_PAGE_X_FIX));
+ ut_ad(mtr_memo_contains(btr_mtr, rec_block, MTR_MEMO_PAGE_X_FIX));
ut_ad(buf_block_get_frame(rec_block) == page_align(rec));
ut_a(dict_index_is_clust(index));
@@ -4308,7 +4341,7 @@ btr_store_big_rec_extern_fields_func(
rec_page_no = buf_block_get_page_no(rec_block);
ut_a(fil_page_get_type(page_align(rec)) == FIL_PAGE_INDEX);
- if (UNIV_LIKELY_NULL(page_zip)) {
+ if (page_zip) {
int err;
/* Zlib deflate needs 128 kilobytes for the default
@@ -4324,6 +4357,42 @@ btr_store_big_rec_extern_fields_func(
ut_a(err == Z_OK);
}
+ if (btr_blob_op_is_update(op)) {
+ /* Avoid reusing pages that have been previously freed
+ in btr_mtr. */
+ if (btr_mtr->n_freed_pages) {
+ if (heap == NULL) {
+ heap = mem_heap_create(
+ btr_mtr->n_freed_pages
+ * sizeof *freed_pages);
+ }
+
+ freed_pages = mem_heap_alloc(
+ heap,
+ btr_mtr->n_freed_pages
+ * sizeof *freed_pages);
+ n_freed_pages = 0;
+ }
+
+ /* Because btr_mtr will be committed after mtr, it is
+ possible that the tablespace has been extended when
+ the B-tree record was updated or inserted, or it will
+ be extended while allocating pages for big_rec.
+
+ TODO: In mtr (not btr_mtr), write a redo log record
+ about extending the tablespace to its current size,
+ and remember the current size. Whenever the tablespace
+ grows as pages are allocated, write further redo log
+ records to mtr. (Currently tablespace extension is not
+ covered by the redo log. If it were, the record would
+ only be written to btr_mtr, which is committed after
+ mtr.) */
+ alloc_mtr = btr_mtr;
+ } else {
+ /* Use the local mtr for allocations. */
+ alloc_mtr = &mtr;
+ }
+
#if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG
/* All pointers to externally stored columns in the record
must either be zero or they must be pointers to inherited
@@ -4338,7 +4407,7 @@ btr_store_big_rec_extern_fields_func(
/* Either this must be an update in place,
or the BLOB must be inherited, or the BLOB pointer
must be zero (will be written in this function). */
- ut_a(update_in_place
+ ut_a(op == BTR_STORE_UPDATE
|| (field_ref[BTR_EXTERN_LEN] & BTR_EXTERN_INHERITED_FLAG)
|| !memcmp(field_ref, field_ref_zero,
BTR_EXTERN_FIELD_REF_SIZE));
@@ -4363,7 +4432,7 @@ btr_store_big_rec_extern_fields_func(
prev_page_no = FIL_NULL;
- if (UNIV_LIKELY_NULL(page_zip)) {
+ if (page_zip) {
int err = deflateReset(&c_stream);
ut_a(err == Z_OK);
@@ -4383,18 +4452,24 @@ btr_store_big_rec_extern_fields_func(
hint_page_no = prev_page_no + 1;
}
+alloc_another:
block = btr_page_alloc(index, hint_page_no,
- FSP_NO_DIR, 0, &mtr);
+ FSP_NO_DIR, 0, alloc_mtr, &mtr);
if (UNIV_UNLIKELY(block == NULL)) {
-
mtr_commit(&mtr);
+ error = DB_OUT_OF_FILE_SPACE;
+ goto func_exit;
+ }
- if (UNIV_LIKELY_NULL(page_zip)) {
- deflateEnd(&c_stream);
- mem_heap_free(heap);
- }
-
- return(DB_OUT_OF_FILE_SPACE);
+ if (rw_lock_get_x_lock_count(&block->lock) > 1) {
+ /* This page must have been freed in
+ btr_mtr previously. Put it aside, and
+ allocate another page for the BLOB data. */
+ ut_ad(alloc_mtr == btr_mtr);
+ ut_ad(btr_blob_op_is_update(op));
+ ut_ad(n_freed_pages < btr_mtr->n_freed_pages);
+ freed_pages[n_freed_pages++] = block;
+ goto alloc_another;
}
page_no = buf_block_get_page_no(block);
@@ -4411,7 +4486,7 @@ btr_store_big_rec_extern_fields_func(
SYNC_EXTERN_STORAGE);
prev_page = buf_block_get_frame(prev_block);
- if (UNIV_LIKELY_NULL(page_zip)) {
+ if (page_zip) {
mlog_write_ulint(
prev_page + FIL_PAGE_NEXT,
page_no, MLOG_4BYTES, &mtr);
@@ -4428,7 +4503,7 @@ btr_store_big_rec_extern_fields_func(
}
- if (UNIV_LIKELY_NULL(page_zip)) {
+ if (page_zip) {
int err;
page_zip_des_t* blob_page_zip;
@@ -4511,11 +4586,15 @@ btr_store_big_rec_extern_fields_func(
goto next_zip_page;
}
- rec_block = buf_page_get(space_id, zip_size,
- rec_page_no,
- RW_X_LATCH, &mtr);
- buf_block_dbg_add_level(rec_block,
- SYNC_NO_ORDER_CHECK);
+ if (alloc_mtr == &mtr) {
+ rec_block = buf_page_get(
+ space_id, zip_size,
+ rec_page_no,
+ RW_X_LATCH, &mtr);
+ buf_block_dbg_add_level(
+ rec_block,
+ SYNC_NO_ORDER_CHECK);
+ }
if (err == Z_STREAM_END) {
mach_write_to_4(field_ref
@@ -4549,7 +4628,8 @@ btr_store_big_rec_extern_fields_func(
page_zip_write_blob_ptr(
page_zip, rec, index, offsets,
- big_rec_vec->fields[i].field_no, &mtr);
+ big_rec_vec->fields[i].field_no,
+ alloc_mtr);
next_zip_page:
prev_page_no = page_no;
@@ -4594,19 +4674,23 @@ next_zip_page:
extern_len -= store_len;
- rec_block = buf_page_get(space_id, zip_size,
- rec_page_no,
- RW_X_LATCH, &mtr);
- buf_block_dbg_add_level(rec_block,
- SYNC_NO_ORDER_CHECK);
+ if (alloc_mtr == &mtr) {
+ rec_block = buf_page_get(
+ space_id, zip_size,
+ rec_page_no,
+ RW_X_LATCH, &mtr);
+ buf_block_dbg_add_level(
+ rec_block,
+ SYNC_NO_ORDER_CHECK);
+ }
mlog_write_ulint(field_ref + BTR_EXTERN_LEN, 0,
- MLOG_4BYTES, &mtr);
+ MLOG_4BYTES, alloc_mtr);
mlog_write_ulint(field_ref
+ BTR_EXTERN_LEN + 4,
big_rec_vec->fields[i].len
- extern_len,
- MLOG_4BYTES, &mtr);
+ MLOG_4BYTES, alloc_mtr);
if (prev_page_no == FIL_NULL) {
btr_blob_dbg_add_blob(
@@ -4616,18 +4700,19 @@ next_zip_page:
mlog_write_ulint(field_ref
+ BTR_EXTERN_SPACE_ID,
- space_id,
- MLOG_4BYTES, &mtr);
+ space_id, MLOG_4BYTES,
+ alloc_mtr);
mlog_write_ulint(field_ref
+ BTR_EXTERN_PAGE_NO,
- page_no,
- MLOG_4BYTES, &mtr);
+ page_no, MLOG_4BYTES,
+ alloc_mtr);
mlog_write_ulint(field_ref
+ BTR_EXTERN_OFFSET,
FIL_PAGE_DATA,
- MLOG_4BYTES, &mtr);
+ MLOG_4BYTES,
+ alloc_mtr);
}
prev_page_no = page_no;
@@ -4641,8 +4726,23 @@ next_zip_page:
}
}
- if (UNIV_LIKELY_NULL(page_zip)) {
+func_exit:
+ if (page_zip) {
deflateEnd(&c_stream);
+ }
+
+ if (n_freed_pages) {
+ ulint i;
+
+ ut_ad(alloc_mtr == btr_mtr);
+ ut_ad(btr_blob_op_is_update(op));
+
+ for (i = 0; i < n_freed_pages; i++) {
+ btr_page_free_low(index, freed_pages[i], 0, alloc_mtr);
+ }
+ }
+
+ if (heap != NULL) {
mem_heap_free(heap);
}
@@ -4663,7 +4763,7 @@ next_zip_page:
ut_a(!(field_ref[BTR_EXTERN_LEN] & BTR_EXTERN_OWNER_FLAG));
}
#endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */
- return(DB_SUCCESS);
+ return(error);
}
/*******************************************************************//**
@@ -4866,7 +4966,7 @@ btr_free_externally_stored_field(
btr_page_free_low(index, ext_block, 0, &mtr);
- if (UNIV_LIKELY(page_zip != NULL)) {
+ if (page_zip) {
mach_write_to_4(field_ref + BTR_EXTERN_PAGE_NO,
next_page_no);
mach_write_to_4(field_ref + BTR_EXTERN_LEN + 4,
diff --git a/storage/xtradb/btr/btr0pcur.c b/storage/xtradb/btr/btr0pcur.c
index e6a9ddcf43e..0de7b63f92d 100644
--- a/storage/xtradb/btr/btr0pcur.c
+++ b/storage/xtradb/btr/btr0pcur.c
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1996, 2011, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1996, 2012, Oracle and/or its affiliates. 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
@@ -52,12 +52,13 @@ btr_pcur_create_for_mysql(void)
}
/**************************************************************//**
-Frees the memory for a persistent cursor object. */
+Resets a persistent cursor object, freeing ::old_rec_buf if it is
+allocated and resetting the other members to their initial values. */
UNIV_INTERN
void
-btr_pcur_free_for_mysql(
-/*====================*/
- btr_pcur_t* cursor) /*!< in, own: persistent cursor */
+btr_pcur_reset(
+/*===========*/
+ btr_pcur_t* cursor) /*!< in, out: persistent cursor */
{
if (cursor->old_rec_buf != NULL) {
@@ -66,6 +67,7 @@ btr_pcur_free_for_mysql(
cursor->old_rec_buf = NULL;
}
+ cursor->btr_cur.index = NULL;
cursor->btr_cur.page_cur.rec = NULL;
cursor->old_rec = NULL;
cursor->old_n_fields = 0;
@@ -73,7 +75,17 @@ btr_pcur_free_for_mysql(
cursor->latch_mode = BTR_NO_LATCHES;
cursor->pos_state = BTR_PCUR_NOT_POSITIONED;
+}
+/**************************************************************//**
+Frees the memory for a persistent cursor object. */
+UNIV_INTERN
+void
+btr_pcur_free_for_mysql(
+/*====================*/
+ btr_pcur_t* cursor) /*!< in, own: persistent cursor */
+{
+ btr_pcur_reset(cursor);
mem_free(cursor);
}
@@ -127,6 +139,8 @@ btr_pcur_store_position(
ut_a(btr_page_get_next(page, mtr) == FIL_NULL);
ut_a(btr_page_get_prev(page, mtr) == FIL_NULL);
+ ut_ad(page_is_leaf(page));
+ ut_ad(page_get_page_no(page) == index->page);
cursor->old_stored = BTR_PCUR_OLD_STORED;
@@ -319,13 +333,19 @@ btr_pcur_restore_position_func(
/* Save the old search mode of the cursor */
old_mode = cursor->search_mode;
- if (UNIV_LIKELY(cursor->rel_pos == BTR_PCUR_ON)) {
+ switch (cursor->rel_pos) {
+ case BTR_PCUR_ON:
mode = PAGE_CUR_LE;
- } else if (cursor->rel_pos == BTR_PCUR_AFTER) {
+ break;
+ case BTR_PCUR_AFTER:
mode = PAGE_CUR_G;
- } else {
- ut_ad(cursor->rel_pos == BTR_PCUR_BEFORE);
+ break;
+ case BTR_PCUR_BEFORE:
mode = PAGE_CUR_L;
+ break;
+ default:
+ ut_error;
+ mode = 0;
}
btr_pcur_open_with_no_init_func(index, tuple, mode, latch_mode,
@@ -334,25 +354,44 @@ btr_pcur_restore_position_func(
/* 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 */
+ if (btr_pcur_is_on_user_rec(cursor)) {
+ switch (cursor->rel_pos) {
+ case BTR_PCUR_ON:
+ if (!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;
- 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);
- mem_heap_free(heap);
+ return(TRUE);
+ }
- return(TRUE);
+ break;
+ case BTR_PCUR_BEFORE:
+ page_cur_move_to_next(btr_pcur_get_page_cur(cursor));
+ break;
+ case BTR_PCUR_AFTER:
+ page_cur_move_to_prev(btr_pcur_get_page_cur(cursor));
+ break;
+#ifdef UNIV_DEBUG
+ default:
+ ut_error;
+#endif /* UNIV_DEBUG */
+ }
}
mem_heap_free(heap);
diff --git a/storage/xtradb/btr/btr0sea.c b/storage/xtradb/btr/btr0sea.c
index bddbcc79dd6..855ab62c42f 100644
--- a/storage/xtradb/btr/btr0sea.c
+++ b/storage/xtradb/btr/btr0sea.c
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1996, 2011, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1996, 2012, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2008, Google Inc.
Portions of this file contain modifications contributed and copyrighted by
@@ -1240,7 +1240,7 @@ cleanup:
index->name, (ulong) block->n_pointers);
rw_lock_x_unlock(btr_search_get_latch(index->id));
- btr_search_validate();
+ ut_ad(btr_search_validate());
} else {
rw_lock_x_unlock(btr_search_get_latch(index->id));
}
@@ -2143,7 +2143,9 @@ btr_search_validate(void)
(ulong) block->curr_left_side);
if (n_page_dumps < 20) {
- buf_page_print(page, 0);
+ buf_page_print(
+ page, 0,
+ BUF_PAGE_PRINT_NO_CRASH);
n_page_dumps++;
}
}
diff --git a/storage/xtradb/buf/buf0buf.c b/storage/xtradb/buf/buf0buf.c
index 11b079dd0ef..fd7b8959473 100644
--- a/storage/xtradb/buf/buf0buf.c
+++ b/storage/xtradb/buf/buf0buf.c
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1995, 2011, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1995, 2012, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2008, Google Inc.
Portions of this file contain modifications contributed and copyrighted by
@@ -57,7 +57,9 @@ Created 11/5/1995 Heikki Tuuri
/* prototypes for new functions added to ha_innodb.cc */
trx_t* innobase_get_trx();
-static inline void _increment_page_get_statistics(buf_block_t* block, trx_t* trx)
+static inline
+void
+_increment_page_get_statistics(buf_block_t* block, trx_t* trx)
{
ulint block_hash;
ulint block_hash_byte;
@@ -680,8 +682,12 @@ void
buf_page_print(
/*===========*/
const byte* read_buf, /*!< in: a database page */
- ulint zip_size) /*!< in: compressed page size, or
- 0 for uncompressed pages */
+ ulint zip_size, /*!< in: compressed page size, or
+ 0 for uncompressed pages */
+ ulint flags) /*!< in: 0 or
+ BUF_PAGE_PRINT_NO_CRASH or
+ BUF_PAGE_PRINT_NO_FULL */
+
{
#ifndef UNIV_HOTBACKUP
dict_index_t* index;
@@ -695,11 +701,14 @@ buf_page_print(
size = UNIV_PAGE_SIZE;
}
- ut_print_timestamp(stderr);
- fprintf(stderr, " InnoDB: Page dump in ascii and hex (%lu bytes):\n",
- (ulong) size);
- ut_print_buf(stderr, read_buf, size);
- fputs("\nInnoDB: End of page dump\n", stderr);
+ if (!(flags & BUF_PAGE_PRINT_NO_FULL)) {
+ ut_print_timestamp(stderr);
+ fprintf(stderr,
+ " InnoDB: Page dump in ascii and hex (%lu bytes):\n",
+ (ulong) size);
+ ut_print_buf(stderr, read_buf, size);
+ fputs("\nInnoDB: End of page dump\n", stderr);
+ }
if (zip_size) {
/* Print compressed page. */
@@ -873,6 +882,8 @@ buf_page_print(
stderr);
break;
}
+
+ ut_ad(flags & BUF_PAGE_PRINT_NO_CRASH);
}
#ifndef UNIV_HOTBACKUP
@@ -1078,11 +1089,8 @@ buf_chunk_init(
for (i = chunk->size; i--; ) {
buf_block_init(buf_pool, block, frame);
+ UNIV_MEM_INVALID(block->frame, UNIV_PAGE_SIZE);
-#ifdef HAVE_valgrind
- /* Wipe contents of frame to eliminate a Purify warning */
- memset(block->frame, '\0', UNIV_PAGE_SIZE);
-#endif
/* Add the block to the free list */
mutex_enter(&buf_pool->free_list_mutex);
UT_LIST_ADD_LAST(free, buf_pool->free, (&block->page));
@@ -2768,7 +2776,7 @@ wait_until_unfixed:
block->page.buf_fix_count = 1;
buf_block_set_io_fix(block, BUF_IO_READ);
- rw_lock_x_lock_func(&block->lock, 0, file, line);
+ rw_lock_x_lock_inline(&block->lock, 0, file, line);
UNIV_MEM_INVALID(bpage, sizeof *bpage);
@@ -2931,14 +2939,14 @@ wait_until_unfixed:
break;
case RW_S_LATCH:
- rw_lock_s_lock_func(&(block->lock), 0, file, line);
+ rw_lock_s_lock_inline(&(block->lock), 0, file, line);
fix_type = MTR_MEMO_PAGE_S_FIX;
break;
default:
ut_ad(rw_latch == RW_X_LATCH);
- rw_lock_x_lock_func(&(block->lock), 0, file, line);
+ rw_lock_x_lock_inline(&(block->lock), 0, file, line);
fix_type = MTR_MEMO_PAGE_X_FIX;
break;
@@ -3023,8 +3031,8 @@ buf_page_optimistic_get(
file, line);
fix_type = MTR_MEMO_PAGE_S_FIX;
} else {
- success = rw_lock_x_lock_func_nowait(&(block->lock),
- file, line);
+ success = rw_lock_x_lock_func_nowait_inline(&(block->lock),
+ file, line);
fix_type = MTR_MEMO_PAGE_X_FIX;
}
@@ -3165,8 +3173,8 @@ buf_page_get_known_nowait(
file, line);
fix_type = MTR_MEMO_PAGE_S_FIX;
} else {
- success = rw_lock_x_lock_func_nowait(&(block->lock),
- file, line);
+ success = rw_lock_x_lock_func_nowait_inline(&(block->lock),
+ file, line);
fix_type = MTR_MEMO_PAGE_X_FIX;
}
@@ -3186,7 +3194,7 @@ buf_page_get_known_nowait(
ut_a(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE);
#endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
#if defined UNIV_DEBUG_FILE_ACCESSES || defined UNIV_DEBUG
- ut_a(block->page.file_page_was_freed == FALSE);
+ ut_a(mode == BUF_KEEP_OLD || !block->page.file_page_was_freed);
#endif
#ifdef UNIV_IBUF_COUNT_DEBUG
@@ -3261,8 +3269,8 @@ buf_page_try_get_func(
S-latch. */
fix_type = MTR_MEMO_PAGE_X_FIX;
- success = rw_lock_x_lock_func_nowait(&block->lock,
- file, line);
+ success = rw_lock_x_lock_func_nowait_inline(&block->lock,
+ file, line);
}
if (!success) {
@@ -3997,7 +4005,8 @@ corrupt:
"InnoDB: You may have to recover"
" from a backup.\n",
(ulong) bpage->offset);
- buf_page_print(frame, buf_page_get_zip_size(bpage));
+ buf_page_print(frame, buf_page_get_zip_size(bpage),
+ BUF_PAGE_PRINT_NO_CRASH);
fprintf(stderr,
"InnoDB: Database page corruption on disk"
" or a failed\n"
@@ -5285,34 +5294,32 @@ buf_all_freed(void)
/*********************************************************************//**
Checks that there currently are no pending i/o-operations for the buffer
pool.
-@return TRUE if there is no pending i/o */
+@return number of pending i/o */
UNIV_INTERN
-ibool
-buf_pool_check_no_pending_io(void)
-/*==============================*/
+ulint
+buf_pool_check_num_pending_io(void)
+/*===============================*/
{
ulint i;
- ibool ret = TRUE;
+ ulint pending_io = 0;
buf_pool_mutex_enter_all();
- for (i = 0; i < srv_buf_pool_instances && ret; i++) {
+ for (i = 0; i < srv_buf_pool_instances; i++) {
const buf_pool_t* buf_pool;
buf_pool = buf_pool_from_array(i);
- if (buf_pool->n_pend_reads
- + buf_pool->n_flush[BUF_FLUSH_LRU]
- + buf_pool->n_flush[BUF_FLUSH_LIST]
- + buf_pool->n_flush[BUF_FLUSH_SINGLE_PAGE]) {
+ pending_io += buf_pool->n_pend_reads
+ + buf_pool->n_flush[BUF_FLUSH_LRU]
+ + buf_pool->n_flush[BUF_FLUSH_LIST]
+ + buf_pool->n_flush[BUF_FLUSH_SINGLE_PAGE];
- ret = FALSE;
- }
}
buf_pool_mutex_exit_all();
- return(ret);
+ return(pending_io);
}
#if 0
diff --git a/storage/xtradb/buf/buf0flu.c b/storage/xtradb/buf/buf0flu.c
index d776a274d14..bb921928653 100644
--- a/storage/xtradb/buf/buf0flu.c
+++ b/storage/xtradb/buf/buf0flu.c
@@ -767,7 +767,8 @@ buf_flush_buffered_writes(void)
if (UNIV_UNLIKELY
(!page_simple_validate_new(block->frame))) {
corrupted_page:
- buf_page_print(block->frame, 0);
+ buf_page_print(block->frame, 0,
+ BUF_PAGE_PRINT_NO_CRASH);
ut_print_timestamp(stderr);
fprintf(stderr,
@@ -2036,22 +2037,6 @@ buf_flush_list(
buf_pool = buf_pool_from_array(i);
- if (lsn_limit != IB_ULONGLONG_MAX) {
- buf_page_t* bpage;
-
- buf_flush_list_mutex_enter(buf_pool);
- bpage = UT_LIST_GET_LAST(buf_pool->flush_list);
- if (!bpage
- || bpage->oldest_modification >= lsn_limit) {
-
- buf_flush_list_mutex_exit(buf_pool);
- continue;
- } else {
-
- buf_flush_list_mutex_exit(buf_pool);
- }
- }
-
if (!buf_flush_start(buf_pool, BUF_FLUSH_LIST)) {
/* We have two choices here. If lsn_limit was
specified then skipping an instance of buffer
diff --git a/storage/xtradb/buf/buf0lru.c b/storage/xtradb/buf/buf0lru.c
index ecad1cf1e64..f7b5db2d0cc 100644
--- a/storage/xtradb/buf/buf0lru.c
+++ b/storage/xtradb/buf/buf0lru.c
@@ -48,6 +48,7 @@ Created 11/5/1995 Heikki Tuuri
#include "page0zip.h"
#include "log0recv.h"
#include "srv0srv.h"
+#include "srv0start.h"
/** The number of blocks from the LRU_old pointer onward, including
the block pointed to, must be buf_pool->LRU_old_ratio/BUF_LRU_OLD_RATIO_DIV
@@ -372,41 +373,277 @@ next_page:
}
/******************************************************************//**
+While flushing (or removing dirty) pages from a tablespace we don't
+want to hog the CPU and resources. Release the buffer pool and block
+mutex and try to force a context switch. Then reacquire the same mutexes.
+The current page is "fixed" before the release of the mutexes and then
+"unfixed" again once we have reacquired the mutexes. */
+static
+void
+buf_flush_yield(
+/*============*/
+ buf_pool_t* buf_pool, /*!< in/out: buffer pool instance */
+ buf_page_t* bpage) /*!< in/out: current page */
+{
+ mutex_t* block_mutex;
+
+ ut_ad(buf_pool_mutex_own(buf_pool));
+ ut_ad(buf_page_in_file(bpage));
+
+ block_mutex = buf_page_get_mutex(bpage);
+
+ mutex_enter(block_mutex);
+ /* "Fix" the block so that the position cannot be
+ changed after we release the buffer pool and
+ block mutexes. */
+ buf_page_set_sticky(bpage);
+
+ /* Now it is safe to release the buf_pool->mutex. */
+ buf_pool_mutex_exit(buf_pool);
+
+ mutex_exit(block_mutex);
+ /* Try and force a context switch. */
+ os_thread_yield();
+
+ buf_pool_mutex_enter(buf_pool);
+
+ mutex_enter(block_mutex);
+ /* "Unfix" the block now that we have both the
+ buffer pool and block mutex again. */
+ buf_page_unset_sticky(bpage);
+ mutex_exit(block_mutex);
+}
+
+/******************************************************************//**
+If we have hogged the resources for too long then release the buffer
+pool and flush list mutex and do a thread yield. Set the current page
+to "sticky" so that it is not relocated during the yield.
+@return TRUE if yielded */
+static
+ibool
+buf_flush_try_yield(
+/*================*/
+ buf_pool_t* buf_pool, /*!< in/out: buffer pool instance */
+ buf_page_t* bpage, /*!< in/out: bpage to remove */
+ ulint processed) /*!< in: number of pages processed */
+{
+ /* Every BUF_LRU_DROP_SEARCH_SIZE iterations in the
+ loop we release buf_pool->mutex to let other threads
+ do their job but only if the block is not IO fixed. This
+ ensures that the block stays in its position in the
+ flush_list. */
+
+ if (bpage != NULL
+ && processed >= BUF_LRU_DROP_SEARCH_SIZE
+ && buf_page_get_io_fix(bpage) == BUF_IO_NONE) {
+
+ buf_flush_list_mutex_exit(buf_pool);
+
+ /* Release the buffer pool and block mutex
+ to give the other threads a go. */
+
+ buf_flush_yield(buf_pool, bpage);
+
+ buf_flush_list_mutex_enter(buf_pool);
+
+ /* Should not have been removed from the flush
+ list during the yield. However, this check is
+ not sufficient to catch a remove -> add. */
+
+ ut_ad(bpage->in_flush_list);
+
+ return(TRUE);
+ }
+
+ return(FALSE);
+}
+
+/******************************************************************//**
+Removes a single page from a given tablespace inside a specific
+buffer pool instance.
+@return TRUE if page was removed. */
+static
+ibool
+buf_flush_or_remove_page(
+/*=====================*/
+ buf_pool_t* buf_pool, /*!< in/out: buffer pool instance */
+ buf_page_t* bpage) /*!< in/out: bpage to remove */
+{
+ mutex_t* block_mutex;
+ ibool processed = FALSE;
+
+ ut_ad(buf_pool_mutex_own(buf_pool));
+ ut_ad(buf_flush_list_mutex_own(buf_pool));
+
+ block_mutex = buf_page_get_mutex(bpage);
+
+ /* bpage->space and bpage->io_fix are protected by
+ buf_pool->mutex and block_mutex. It is safe to check
+ them while holding buf_pool->mutex only. */
+
+ if (buf_page_get_io_fix(bpage) != BUF_IO_NONE) {
+
+ /* We cannot remove this page during this scan
+ yet; maybe the system is currently reading it
+ in, or flushing the modifications to the file */
+
+ } else {
+
+ /* We have to release the flush_list_mutex to obey the
+ latching order. We are however guaranteed that the page
+ will stay in the flush_list because buf_flush_remove()
+ needs buf_pool->mutex as well (for the non-flush case). */
+
+ buf_flush_list_mutex_exit(buf_pool);
+
+ mutex_enter(block_mutex);
+
+ ut_ad(bpage->oldest_modification != 0);
+
+ if (bpage->buf_fix_count == 0) {
+
+ buf_flush_remove(bpage);
+
+ processed = TRUE;
+ }
+
+ mutex_exit(block_mutex);
+
+ buf_flush_list_mutex_enter(buf_pool);
+ }
+
+ ut_ad(!mutex_own(block_mutex));
+
+ return(processed);
+}
+
+/******************************************************************//**
Remove all dirty pages belonging to a given tablespace inside a specific
buffer pool instance when we are deleting the data file(s) of that
tablespace. The pages still remain a part of LRU and are evicted from
-the list as they age towards the tail of the LRU. */
+the list as they age towards the tail of the LRU.
+@return TRUE if all freed. */
+static
+ibool
+buf_flush_or_remove_pages(
+/*======================*/
+ buf_pool_t* buf_pool, /*!< buffer pool instance */
+ ulint id) /*!< in: target space id for which
+ to remove or flush pages */
+{
+ buf_page_t* prev;
+ buf_page_t* bpage;
+ ulint processed = 0;
+ ibool all_freed = TRUE;
+
+ buf_flush_list_mutex_enter(buf_pool);
+
+ for (bpage = UT_LIST_GET_LAST(buf_pool->flush_list);
+ bpage != NULL;
+ bpage = prev) {
+
+ ut_a(buf_page_in_file(bpage));
+ ut_ad(bpage->in_flush_list);
+
+ /* Save the previous link because once we free the
+ page we can't rely on the links. */
+
+ prev = UT_LIST_GET_PREV(flush_list, bpage);
+
+ if (buf_page_get_space(bpage) != id) {
+
+ /* Skip this block, as it does not belong to
+ the target space. */
+
+ } else if (!buf_flush_or_remove_page(buf_pool, bpage)) {
+
+ /* Remove was unsuccessful, we have to try again
+ by scanning the entire list from the end. */
+
+ all_freed = FALSE;
+ }
+
+ ++processed;
+
+ /* Yield if we have hogged the CPU and mutexes for too long. */
+ if (buf_flush_try_yield(buf_pool, prev, processed)) {
+
+ /* Reset the batch size counter if we had to yield. */
+
+ processed = 0;
+ }
+
+ }
+
+ buf_flush_list_mutex_exit(buf_pool);
+
+ return(all_freed);
+}
+
+/******************************************************************//**
+Remove or flush all the dirty pages that belong to a given tablespace
+inside a specific buffer pool instance. The pages will remain in the LRU
+list and will be evicted from the LRU list as they age and move towards
+the tail of the LRU list. */
+static
+void
+buf_flush_dirty_pages(
+/*==================*/
+ buf_pool_t* buf_pool, /*!< buffer pool instance */
+ ulint id) /*!< in: space id */
+{
+ ibool all_freed;
+
+ do {
+ buf_pool_mutex_enter(buf_pool);
+
+ all_freed = buf_flush_or_remove_pages(buf_pool, id);
+
+ buf_pool_mutex_exit(buf_pool);
+
+ ut_ad(buf_flush_validate(buf_pool));
+
+ if (!all_freed) {
+ os_thread_sleep(20000);
+ }
+
+ } while (!all_freed);
+}
+
+/******************************************************************//**
+Remove all pages that belong to a given tablespace inside a specific
+buffer pool instance when we are DISCARDing the tablespace. */
static
void
-buf_LRU_remove_dirty_pages_for_tablespace(
-/*======================================*/
+buf_LRU_remove_all_pages(
+/*=====================*/
buf_pool_t* buf_pool, /*!< buffer pool instance */
ulint id) /*!< in: space id */
{
buf_page_t* bpage;
ibool all_freed;
- ulint i;
scan_again:
//buf_pool_mutex_enter(buf_pool);
mutex_enter(&buf_pool->LRU_list_mutex);
rw_lock_x_lock(&buf_pool->page_hash_latch);
- buf_flush_list_mutex_enter(buf_pool);
all_freed = TRUE;
- for (bpage = UT_LIST_GET_LAST(buf_pool->flush_list), i = 0;
- bpage != NULL; ++i) {
+ for (bpage = UT_LIST_GET_LAST(buf_pool->LRU);
+ bpage != NULL;
+ /* No op */) {
buf_page_t* prev_bpage;
mutex_t* block_mutex = NULL;
ut_a(buf_page_in_file(bpage));
+ ut_ad(bpage->in_LRU_list);
- prev_bpage = UT_LIST_GET_PREV(flush_list, bpage);
+ prev_bpage = UT_LIST_GET_PREV(LRU, bpage);
/* bpage->space and bpage->io_fix are protected by
- buf_pool->mutex and block_mutex. It is safe to check
+ buf_pool->mutex and the block_mutex. It is safe to check
them while holding buf_pool->mutex only. */
if (buf_page_get_space(bpage) != id) {
@@ -420,97 +657,89 @@ scan_again:
all_freed = FALSE;
goto next_page;
- }
+ } else {
- /* We have to release the flush_list_mutex to obey the
- latching order. We are however guaranteed that the page
- will stay in the flush_list because buf_flush_remove()
- needs buf_pool->mutex as well. */
- buf_flush_list_mutex_exit(buf_pool);
- block_mutex = buf_page_get_mutex_enter(bpage);
+ block_mutex = buf_page_get_mutex(bpage);
+ mutex_enter(block_mutex);
- if (!block_mutex) {
- /* It may be impossible case...
- Something wrong, so will be scan_again */
- all_freed = FALSE;
- goto next_page;
- }
+ if (bpage->buf_fix_count > 0) {
- if (bpage->buf_fix_count > 0) {
- mutex_exit(block_mutex);
- buf_flush_list_mutex_enter(buf_pool);
+ mutex_exit(block_mutex);
- /* We cannot remove this page during
- this scan yet; maybe the system is
- currently reading it in, or flushing
- the modifications to the file */
+ /* We cannot remove this page during
+ this scan yet; maybe the system is
+ currently reading it in, or flushing
+ the modifications to the file */
- all_freed = FALSE;
- goto next_page;
+ all_freed = FALSE;
+
+ goto next_page;
+ }
}
- ut_ad(bpage->oldest_modification != 0);
+ ut_ad(mutex_own(block_mutex));
- buf_flush_remove(bpage);
+#ifdef UNIV_DEBUG
+ if (buf_debug_prints) {
+ fprintf(stderr,
+ "Dropping space %lu page %lu\n",
+ (ulong) buf_page_get_space(bpage),
+ (ulong) buf_page_get_page_no(bpage));
+ }
+#endif
+ if (buf_page_get_state(bpage) != BUF_BLOCK_FILE_PAGE) {
+ /* Do nothing, because the adaptive hash index
+ covers uncompressed pages only. */
+ } else if (((buf_block_t*) bpage)->index) {
+ ulint page_no;
+ ulint zip_size;
- mutex_exit(block_mutex);
- buf_flush_list_mutex_enter(buf_pool);
-next_page:
- bpage = prev_bpage;
+ buf_pool_mutex_exit(buf_pool);
- if (!bpage) {
- break;
- }
+ zip_size = buf_page_get_zip_size(bpage);
+ page_no = buf_page_get_page_no(bpage);
- /* Every BUF_LRU_DROP_SEARCH_SIZE iterations in the
- loop we release buf_pool->mutex to let other threads
- do their job. */
- if (i < BUF_LRU_DROP_SEARCH_SIZE) {
- continue;
+ mutex_exit(block_mutex);
+
+ /* Note that the following call will acquire
+ and release block->lock X-latch. */
+
+ btr_search_drop_page_hash_when_freed(
+ id, zip_size, page_no);
+
+ goto scan_again;
}
- /* We IO-fix the block to make sure that the block
- stays in its position in the flush_list. */
- if (buf_page_get_io_fix(bpage) != BUF_IO_NONE) {
- /* Block is already IO-fixed. We don't
- want to change the value. Lets leave
- this block alone. */
- continue;
+ if (bpage->oldest_modification != 0) {
+ buf_flush_remove(bpage);
}
- buf_flush_list_mutex_exit(buf_pool);
- block_mutex = buf_page_get_mutex(bpage);
- mutex_enter(block_mutex);
- buf_page_set_sticky(bpage);
- mutex_exit(block_mutex);
+ ut_ad(!bpage->in_flush_list);
- /* Now it is safe to release the buf_pool->mutex. */
- //buf_pool_mutex_exit(buf_pool);
- mutex_exit(&buf_pool->LRU_list_mutex);
- rw_lock_x_unlock(&buf_pool->page_hash_latch);
+ /* Remove from the LRU list. */
- os_thread_yield();
- //buf_pool_mutex_enter(buf_pool);
- mutex_enter(&buf_pool->LRU_list_mutex);
- rw_lock_x_lock(&buf_pool->page_hash_latch);
+ if (buf_LRU_block_remove_hashed_page(bpage, TRUE)
+ != BUF_BLOCK_ZIP_FREE) {
+ buf_LRU_block_free_hashed_page((buf_block_t*) bpage, TRUE);
+ mutex_exit(block_mutex);
- mutex_enter(block_mutex);
- buf_page_unset_sticky(bpage);
- mutex_exit(block_mutex);
+ } else {
+ /* The block_mutex should have been released
+ by buf_LRU_block_remove_hashed_page() when it
+ returns BUF_BLOCK_ZIP_FREE. */
+ ut_ad(block_mutex == &buf_pool->zip_mutex);
+ }
- buf_flush_list_mutex_enter(buf_pool);
- ut_ad(bpage->in_flush_list);
+ ut_ad(!mutex_own(block_mutex));
- i = 0;
+next_page:
+ bpage = prev_bpage;
}
// buf_pool_mutex_exit(buf_pool);
mutex_exit(&buf_pool->LRU_list_mutex);
rw_lock_x_unlock(&buf_pool->page_hash_latch);
- buf_flush_list_mutex_exit(buf_pool);
-
- ut_ad(buf_flush_validate(buf_pool));
if (!all_freed) {
os_thread_sleep(20000);
@@ -520,28 +749,46 @@ next_page:
}
/******************************************************************//**
-Invalidates all pages belonging to a given tablespace when we are deleting
-the data file(s) of that tablespace. */
+Removes all pages belonging to a given tablespace. */
UNIV_INTERN
void
-buf_LRU_invalidate_tablespace(
+buf_LRU_flush_or_remove_pages(
/*==========================*/
- ulint id) /*!< in: space id */
+ ulint id, /*!< in: space id */
+ enum buf_remove_t buf_remove)/*!< in: remove or flush
+ strategy */
{
- ulint i;
+ ulint i;
- /* Before we attempt to drop pages one by one we first
- attempt to drop page hash index entries in batches to make
- it more efficient. The batching attempt is a best effort
- attempt and does not guarantee that all pages hash entries
- will be dropped. We get rid of remaining page hash entries
- one by one below. */
for (i = 0; i < srv_buf_pool_instances; i++) {
buf_pool_t* buf_pool;
buf_pool = buf_pool_from_array(i);
- buf_LRU_drop_page_hash_for_tablespace(buf_pool, id);
- buf_LRU_remove_dirty_pages_for_tablespace(buf_pool, id);
+
+ switch (buf_remove) {
+ case BUF_REMOVE_ALL_NO_WRITE:
+ /* A DISCARD tablespace case. Remove AHI entries
+ and evict all pages from LRU. */
+
+ /* Before we attempt to drop pages hash entries
+ one by one we first attempt to drop page hash
+ index entries in batches to make it more
+ efficient. The batching attempt is a best effort
+ attempt and does not guarantee that all pages
+ hash entries will be dropped. We get rid of
+ remaining page hash entries one by one below. */
+ buf_LRU_drop_page_hash_for_tablespace(buf_pool, id);
+ buf_LRU_remove_all_pages(buf_pool, id);
+ break;
+
+ case BUF_REMOVE_FLUSH_NO_WRITE:
+ /* A DROP table case. AHI entries are already
+ removed. No need to evict all pages from LRU
+ list. Just evict pages from flush list without
+ writing. */
+ buf_flush_dirty_pages(buf_pool, id);
+ break;
+ }
}
}
@@ -614,7 +861,7 @@ buf_LRU_insert_zip_clean(
buf_pool_t* buf_pool = buf_pool_from_bpage(bpage);
//ut_ad(buf_pool_mutex_own(buf_pool));
- ut_ad(mutex_own(&buf_pool->LRU_list_mutex));
+ //ut_ad(mutex_own(&buf_pool->LRU_list_mutex));
ut_ad(mutex_own(&buf_pool->zip_mutex));
ut_ad(buf_page_get_state(bpage) == BUF_BLOCK_ZIP_PAGE);
@@ -2260,6 +2507,7 @@ func_exit:
/********************************************************************//**
Dump the LRU page list to the specific file. */
#define LRU_DUMP_FILE "ib_lru_dump"
+#define LRU_DUMP_TEMP_FILE "ib_lru_dump.tmp"
UNIV_INTERN
ibool
@@ -2294,8 +2542,10 @@ buf_LRU_file_dump(void)
goto end;
}
- dump_file = os_file_create(innodb_file_temp_key, LRU_DUMP_FILE, OS_FILE_OVERWRITE,
- OS_FILE_NORMAL, OS_DATA_FILE, &success);
+ dump_file = os_file_create(innodb_file_temp_key, LRU_DUMP_TEMP_FILE,
+ OS_FILE_OVERWRITE, OS_FILE_NORMAL, OS_DATA_FILE,
+ &success);
+
if (!success) {
os_file_get_last_error(TRUE);
fprintf(stderr,
@@ -2324,6 +2574,13 @@ buf_LRU_file_dump(void)
offset++;
if (offset == UNIV_PAGE_SIZE/4) {
+ if (srv_shutdown_state != SRV_SHUTDOWN_NONE) {
+ success = 0;
+ fprintf(stderr,
+ " InnoDB: stopped dumping lru"
+ " pages because of server"
+ " shutdown.\n");
+ }
success = os_file_write(LRU_DUMP_FILE, dump_file, buffer,
(buffers << UNIV_PAGE_SIZE_SHIFT) & 0xFFFFFFFFUL,
(buffers >> (32 - UNIV_PAGE_SIZE_SHIFT)),
@@ -2363,8 +2620,16 @@ buf_LRU_file_dump(void)
ret = TRUE;
end:
- if (dump_file != (os_file_t) -1)
+ if (dump_file != (os_file_t) -1) {
+ if (success) {
+ success = os_file_flush(dump_file, TRUE);
+ }
os_file_close(dump_file);
+ }
+ if (success) {
+ success = os_file_rename(innodb_file_temp_key,
+ LRU_DUMP_TEMP_FILE, LRU_DUMP_FILE);
+ }
if (buffer_base)
ut_free(buffer_base);
@@ -2410,6 +2675,7 @@ buf_LRU_file_restore(void)
dump_record_t* records = NULL;
ulint size;
ulint size_high;
+ ulint recsize = sizeof(dump_record_t);
ulint length;
dump_file = os_file_create_simple_no_error_handling(innodb_file_temp_key,
@@ -2417,7 +2683,14 @@ buf_LRU_file_restore(void)
if (!success || !os_file_get_size(dump_file, &size, &size_high)) {
os_file_get_last_error(TRUE);
fprintf(stderr,
- " InnoDB: cannot open %s\n", LRU_DUMP_FILE);
+ " InnoDB: cannot open %s, "
+ " buffer pool preload not done.\n", LRU_DUMP_FILE);
+ goto end;
+ }
+
+ if (size == 0 || size_high > 0 || size % recsize) {
+ fprintf(stderr, " InnoDB: broken LRU dump file,"
+ " buffer pool preload not done\n");
goto end;
}
@@ -2501,6 +2774,14 @@ buf_LRU_file_restore(void)
if (offset % 16 == 15) {
os_aio_simulated_wake_handler_threads();
buf_flush_free_margins(FALSE);
+ /* skip loading of the rest of the file if we are
+ terminating anyway */
+ if(srv_shutdown_state != SRV_SHUTDOWN_NONE) {
+ fprintf(stderr,
+ " InnoDB: stopped loading lru pages"
+ " because of server shutdown\n");
+ break;
+ }
}
zip_size = fil_space_get_zip_size(space_id);
diff --git a/storage/xtradb/dict/dict0boot.c b/storage/xtradb/dict/dict0boot.c
index fd08fa759ee..4bf69fa4e0b 100644
--- a/storage/xtradb/dict/dict0boot.c
+++ b/storage/xtradb/dict/dict0boot.c
@@ -240,6 +240,166 @@ dict_hdr_create(
}
/*****************************************************************//**
+Verifies the SYS_STATS table by scanning its clustered index. This
+function may only be called at InnoDB startup time.
+
+@return TRUE if SYS_STATS was verified successfully */
+UNIV_INTERN
+ibool
+dict_verify_xtradb_sys_stats(void)
+/*==============================*/
+{
+ dict_index_t* sys_stats_index;
+ ulint saved_srv_pass_corrupt_table = srv_pass_corrupt_table;
+ ibool result;
+
+ sys_stats_index = dict_table_get_first_index(dict_sys->sys_stats);
+
+ /* Since this may be called only during server startup, avoid hitting
+ various asserts by using XtraDB pass_corrupt_table option. */
+ srv_pass_corrupt_table = 1;
+ result = btr_validate_index(sys_stats_index, NULL);
+ srv_pass_corrupt_table = saved_srv_pass_corrupt_table;
+
+ return result;
+}
+
+/*****************************************************************//**
+Creates the B-tree for the SYS_STATS clustered index, adds the XtraDB
+mark and the id of the index to the dictionary header page. Rewrites
+both passed args. */
+static
+void
+dict_create_xtradb_sys_stats(
+/*=========================*/
+ dict_hdr_t** dict_hdr, /*!< in/out: dictionary header */
+ mtr_t* mtr) /*!< in/out: mtr */
+{
+ ulint root_page_no;
+
+ root_page_no = btr_create(DICT_CLUSTERED | DICT_UNIQUE,
+ DICT_HDR_SPACE, 0, DICT_STATS_ID,
+ dict_ind_redundant, mtr);
+ if (root_page_no == FIL_NULL) {
+ fprintf(stderr, "InnoDB: Warning: failed to create SYS_STATS btr.\n");
+ srv_use_sys_stats_table = FALSE;
+ } else {
+ mlog_write_ulint(*dict_hdr + DICT_HDR_STATS, root_page_no,
+ MLOG_4BYTES, mtr);
+ mlog_write_ull(*dict_hdr + DICT_HDR_XTRADB_MARK,
+ DICT_HDR_XTRADB_FLAG, mtr);
+ }
+ mtr_commit(mtr);
+ /* restart mtr */
+ mtr_start(mtr);
+ *dict_hdr = dict_hdr_get(mtr);
+}
+
+/*****************************************************************//**
+Create the table and index structure of SYS_STATS for the dictionary
+cache and add it there. If called for the first time, also support
+wrong root page id injection for testing purposes. */
+static
+void
+dict_add_to_cache_xtradb_sys_stats(
+/*===============================*/
+ ibool first_time __attribute__((unused)),
+ /*!< in: first invocation flag. If
+ TRUE, optionally inject wrong root page
+ id */
+ mem_heap_t* heap, /*!< in: memory heap for table/index
+ allocation */
+ dict_hdr_t* dict_hdr, /*!< in: dictionary header */
+ mtr_t* mtr) /*!< in: mtr */
+{
+ dict_table_t* table;
+ dict_index_t* index;
+ ulint root_page_id;
+ ulint error;
+
+ table = dict_mem_table_create("SYS_STATS", DICT_HDR_SPACE, 4, 0);
+ table->n_mysql_handles_opened = 1; /* for pin */
+
+ dict_mem_table_add_col(table, heap, "INDEX_ID", DATA_BINARY, 0, 0);
+ dict_mem_table_add_col(table, heap, "KEY_COLS", DATA_INT, 0, 4);
+ dict_mem_table_add_col(table, heap, "DIFF_VALS", DATA_BINARY, 0, 0);
+ dict_mem_table_add_col(table, heap, "NON_NULL_VALS", DATA_BINARY, 0, 0);
+
+ /* The '+ 2' below comes from the fields DB_TRX_ID, DB_ROLL_PTR */
+#if DICT_SYS_STATS_DIFF_VALS_FIELD != 2 + 2
+#error "DICT_SYS_STATS_DIFF_VALS_FIELD != 2 + 2"
+#endif
+#if DICT_SYS_STATS_NON_NULL_VALS_FIELD != 3 + 2
+#error "DICT_SYS_STATS_NON_NULL_VALS_FIELD != 3 + 2"
+#endif
+
+ table->id = DICT_STATS_ID;
+ dict_table_add_to_cache(table, heap);
+ dict_sys->sys_stats = table;
+ mem_heap_empty(heap);
+
+ index = dict_mem_index_create("SYS_STATS", "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, "KEY_COLS", 0);
+
+ index->id = DICT_STATS_ID;
+
+ root_page_id = mtr_read_ulint(dict_hdr + DICT_HDR_STATS, MLOG_4BYTES,
+ mtr);
+#ifdef UNIV_DEBUG
+ if ((srv_sys_stats_root_page != 0) && first_time)
+ root_page_id = srv_sys_stats_root_page;
+#endif
+ error = dict_index_add_to_cache(table, index, root_page_id, FALSE);
+ ut_a(error == DB_SUCCESS);
+
+ mem_heap_empty(heap);
+}
+
+/*****************************************************************//**
+Discard the existing dictionary cache SYS_STATS information, create and
+add it there anew. Does not touch the old SYS_STATS tablespace page
+under the assumption that they are corrupted or overwritten for other
+purposes. */
+UNIV_INTERN
+void
+dict_recreate_xtradb_sys_stats(void)
+/*================================*/
+{
+ mtr_t mtr;
+ dict_hdr_t* dict_hdr;
+ dict_index_t* sys_stats_clust_idx;
+ mem_heap_t* heap;
+
+ heap = mem_heap_create(450);
+
+ mutex_enter(&(dict_sys->mutex));
+
+ sys_stats_clust_idx = dict_table_get_first_index(dict_sys->sys_stats);
+ dict_index_remove_from_cache(dict_sys->sys_stats, sys_stats_clust_idx);
+
+ dict_table_remove_from_cache(dict_sys->sys_stats);
+
+ dict_sys->sys_stats = NULL;
+
+ mtr_start(&mtr);
+
+ dict_hdr = dict_hdr_get(&mtr);
+
+ dict_create_xtradb_sys_stats(&dict_hdr, &mtr);
+ dict_add_to_cache_xtradb_sys_stats(FALSE, heap, dict_hdr, &mtr);
+
+ mem_heap_free(heap);
+
+ mtr_commit(&mtr);
+
+ mutex_exit(&(dict_sys->mutex));
+}
+
+/*****************************************************************//**
Initializes the data dictionary memory structures when the database is
started. This function is also called when the data dictionary is created. */
UNIV_INTERN
@@ -254,13 +414,13 @@ dict_boot(void)
mtr_t mtr;
ulint error;
+ heap = mem_heap_create(450);
+
mtr_start(&mtr);
/* Create the hash tables etc. */
dict_init();
- heap = mem_heap_create(450);
-
mutex_enter(&(dict_sys->mutex));
/* Get the dictionary header */
@@ -268,25 +428,9 @@ dict_boot(void)
if (mach_read_from_8(dict_hdr + DICT_HDR_XTRADB_MARK)
!= DICT_HDR_XTRADB_FLAG) {
+
/* not extended yet by XtraDB, need to be extended */
- ulint root_page_no;
-
- root_page_no = btr_create(DICT_CLUSTERED | DICT_UNIQUE,
- DICT_HDR_SPACE, 0, DICT_STATS_ID,
- dict_ind_redundant, &mtr);
- if (root_page_no == FIL_NULL) {
- fprintf(stderr, "InnoDB: Warning: failed to create SYS_STATS btr.\n");
- srv_use_sys_stats_table = FALSE;
- } else {
- mlog_write_ulint(dict_hdr + DICT_HDR_STATS, root_page_no,
- MLOG_4BYTES, &mtr);
- mlog_write_ull(dict_hdr + DICT_HDR_XTRADB_MARK,
- DICT_HDR_XTRADB_FLAG, &mtr);
- }
- mtr_commit(&mtr);
- /* restart mtr */
- mtr_start(&mtr);
- dict_hdr = dict_hdr_get(&mtr);
+ dict_create_xtradb_sys_stats(&dict_hdr, &mtr);
}
/* Because we only write new row ids to disk-based data structure
@@ -465,42 +609,7 @@ dict_boot(void)
FALSE);
ut_a(error == DB_SUCCESS);
- /*-------------------------*/
- table = dict_mem_table_create("SYS_STATS", DICT_HDR_SPACE, 4, 0);
- table->n_mysql_handles_opened = 1; /* for pin */
-
- dict_mem_table_add_col(table, heap, "INDEX_ID", DATA_BINARY, 0, 0);
- dict_mem_table_add_col(table, heap, "KEY_COLS", DATA_INT, 0, 4);
- dict_mem_table_add_col(table, heap, "DIFF_VALS", DATA_BINARY, 0, 0);
- dict_mem_table_add_col(table, heap, "NON_NULL_VALS", DATA_BINARY, 0, 0);
-
- /* The '+ 2' below comes from the fields DB_TRX_ID, DB_ROLL_PTR */
-#if DICT_SYS_STATS_DIFF_VALS_FIELD != 2 + 2
-#error "DICT_SYS_STATS_DIFF_VALS_FIELD != 2 + 2"
-#endif
-#if DICT_SYS_STATS_NON_NULL_VALS_FIELD != 3 + 2
-#error "DICT_SYS_STATS_NON_NULL_VALS_FIELD != 3 + 2"
-#endif
-
- table->id = DICT_STATS_ID;
- dict_table_add_to_cache(table, heap);
- dict_sys->sys_stats = table;
- mem_heap_empty(heap);
-
- index = dict_mem_index_create("SYS_STATS", "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, "KEY_COLS", 0);
-
- index->id = DICT_STATS_ID;
- error = dict_index_add_to_cache(table, index,
- mtr_read_ulint(dict_hdr
- + DICT_HDR_STATS,
- MLOG_4BYTES, &mtr),
- FALSE);
- ut_a(error == DB_SUCCESS);
+ dict_add_to_cache_xtradb_sys_stats(TRUE, heap, dict_hdr, &mtr);
mem_heap_free(heap);
diff --git a/storage/xtradb/dict/dict0dict.c b/storage/xtradb/dict/dict0dict.c
index 98cf88455bd..3ee045807ed 100644
--- a/storage/xtradb/dict/dict0dict.c
+++ b/storage/xtradb/dict/dict0dict.c
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1996, 2011, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1996, 2012, Oracle and/or its affiliates. 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
@@ -11,8 +11,8 @@ 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 program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
*****************************************************************************/
@@ -56,6 +56,8 @@ UNIV_INTERN dict_index_t* dict_ind_compact;
#include "ha_prototypes.h" /* innobase_strcasecmp(), innobase_casedn_str()*/
#include "row0upd.h"
#include "srv0start.h" /* SRV_LOG_SPACE_FIRST_ID */
+#include "m_string.h"
+#include "my_sys.h"
#include <ctype.h>
@@ -2400,6 +2402,8 @@ dict_foreign_free(
/*==============*/
dict_foreign_t* foreign) /*!< in, own: foreign key struct */
{
+ ut_a(foreign->foreign_table->n_foreign_key_checks_running == 0);
+
mem_heap_free(foreign->heap);
}
@@ -4381,25 +4385,32 @@ dict_reload_statistics(
heap = mem_heap_create(1000);
while (index) {
+ mtr_t mtr;
+
if (table->is_corrupt) {
ut_a(srv_pass_corrupt_table);
mem_heap_free(heap);
return(FALSE);
}
- size = btr_get_size(index, BTR_TOTAL_SIZE);
+ mtr_start(&mtr);
+ mtr_s_lock(dict_index_get_lock(index), &mtr);
+
+ size = btr_get_size(index, BTR_TOTAL_SIZE, &mtr);
index->stat_index_size = size;
*sum_of_index_sizes += size;
- size = btr_get_size(index, BTR_N_LEAF_PAGES);
+ size = btr_get_size(index, BTR_N_LEAF_PAGES, &mtr);
if (size == 0) {
/* The root node of the tree is a leaf */
size = 1;
}
+ mtr_commit(&mtr);
+
index->stat_n_leaf_pages = size;
/*===========================================*/
@@ -4731,6 +4742,7 @@ dict_update_statistics(
(srv_force_recovery < SRV_FORCE_NO_IBUF_MERGE
|| (srv_force_recovery < SRV_FORCE_NO_LOG_REDO
&& dict_index_is_clust(index)))) {
+ mtr_t mtr;
ulint size;
if (table->is_corrupt) {
@@ -4739,15 +4751,24 @@ dict_update_statistics(
return;
}
- size = btr_get_size(index, BTR_TOTAL_SIZE);
+ mtr_start(&mtr);
+ mtr_s_lock(dict_index_get_lock(index), &mtr);
- index->stat_index_size = size;
+ size = btr_get_size(index, BTR_TOTAL_SIZE, &mtr);
- sum_of_index_sizes += size;
+ if (size != ULINT_UNDEFINED) {
+ sum_of_index_sizes += size;
+ index->stat_index_size = size;
+ size = btr_get_size(
+ index, BTR_N_LEAF_PAGES, &mtr);
+ }
- size = btr_get_size(index, BTR_N_LEAF_PAGES);
+ mtr_commit(&mtr);
- if (size == 0) {
+ switch (size) {
+ case ULINT_UNDEFINED:
+ goto fake_statistics;
+ case 0:
/* The root node of the tree is a leaf */
size = 1;
}
@@ -4764,6 +4785,7 @@ dict_update_statistics(
various means, also via secondary indexes. */
ulint i;
+fake_statistics:
sum_of_index_sizes++;
index->stat_index_size = index->stat_n_leaf_pages = 1;
diff --git a/storage/xtradb/dict/dict0load.c b/storage/xtradb/dict/dict0load.c
index 5303557548b..44492960bb8 100644
--- a/storage/xtradb/dict/dict0load.c
+++ b/storage/xtradb/dict/dict0load.c
@@ -2137,8 +2137,9 @@ static
void
dict_load_foreign_cols(
/*===================*/
- const char* id, /*!< in: foreign constraint id as a
- null-terminated string */
+ const char* id, /*!< in: foreign constraint id, not
+ necessary '\0'-terminated */
+ ulint id_len, /*!< in: id length */
dict_foreign_t* foreign)/*!< in: foreign constraint object */
{
dict_table_t* sys_foreign_cols;
@@ -2168,7 +2169,7 @@ dict_load_foreign_cols(
tuple = dtuple_create(foreign->heap, 1);
dfield = dtuple_get_nth_field(tuple, 0);
- dfield_set_data(dfield, id, ut_strlen(id));
+ dfield_set_data(dfield, id, id_len);
dict_index_copy_types(tuple, sys_index, 1);
btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
@@ -2181,7 +2182,7 @@ dict_load_foreign_cols(
ut_a(!rec_get_deleted_flag(rec, 0));
field = rec_get_nth_field_old(rec, 0, &len);
- ut_a(len == ut_strlen(id));
+ ut_a(len == id_len);
ut_a(ut_memcmp(id, field, len) == 0);
field = rec_get_nth_field_old(rec, 1, &len);
@@ -2210,8 +2211,9 @@ static
ulint
dict_load_foreign(
/*==============*/
- const char* id, /*!< in: foreign constraint id as a
- null-terminated string */
+ const char* id, /*!< in: foreign constraint id, not
+ necessary '\0'-terminated */
+ ulint id_len, /*!< in: id length */
ibool check_charsets,
/*!< in: TRUE=check charset compatibility */
ibool check_recursive)
@@ -2247,7 +2249,7 @@ dict_load_foreign(
tuple = dtuple_create(heap2, 1);
dfield = dtuple_get_nth_field(tuple, 0);
- dfield_set_data(dfield, id, ut_strlen(id));
+ dfield_set_data(dfield, id, id_len);
dict_index_copy_types(tuple, sys_index, 1);
btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
@@ -2259,8 +2261,8 @@ dict_load_foreign(
/* Not found */
fprintf(stderr,
- "InnoDB: Error A: cannot load foreign constraint %s\n",
- id);
+ "InnoDB: Error A: cannot load foreign constraint "
+ "%.*s\n", (int) id_len, id);
btr_pcur_close(&pcur);
mtr_commit(&mtr);
@@ -2272,11 +2274,11 @@ dict_load_foreign(
field = rec_get_nth_field_old(rec, 0, &len);
/* Check if the id in record is the searched one */
- if (len != ut_strlen(id) || ut_memcmp(id, field, len) != 0) {
+ if (len != id_len || ut_memcmp(id, field, len) != 0) {
fprintf(stderr,
- "InnoDB: Error B: cannot load foreign constraint %s\n",
- id);
+ "InnoDB: Error B: cannot load foreign constraint "
+ "%.*s\n", (int) id_len, id);
btr_pcur_close(&pcur);
mtr_commit(&mtr);
@@ -2302,7 +2304,7 @@ dict_load_foreign(
foreign->type = (unsigned int) (n_fields_and_type >> 24);
foreign->n_fields = (unsigned int) (n_fields_and_type & 0x3FFUL);
- foreign->id = mem_heap_strdup(foreign->heap, id);
+ foreign->id = mem_heap_strdupl(foreign->heap, id, id_len);
field = rec_get_nth_field_old(rec, 3, &len);
@@ -2318,7 +2320,7 @@ dict_load_foreign(
btr_pcur_close(&pcur);
mtr_commit(&mtr);
- dict_load_foreign_cols(id, foreign);
+ dict_load_foreign_cols(id, id_len, foreign);
ref_table = dict_table_check_if_in_cache_low(
foreign->referenced_table_name_lookup);
@@ -2397,8 +2399,8 @@ dict_load_foreigns(
ibool check_charsets) /*!< in: TRUE=check charset
compatibility */
{
+ char tuple_buf[DTUPLE_EST_ALLOC(1)];
btr_pcur_t pcur;
- mem_heap_t* heap;
dtuple_t* tuple;
dfield_t* dfield;
dict_index_t* sec_index;
@@ -2406,7 +2408,6 @@ dict_load_foreigns(
const rec_t* rec;
const byte* field;
ulint len;
- char* id ;
ulint err;
mtr_t mtr;
@@ -2433,9 +2434,8 @@ dict_load_foreigns(
sec_index = dict_table_get_next_index(
dict_table_get_first_index(sys_foreign));
start_load:
- heap = mem_heap_create(256);
- tuple = dtuple_create(heap, 1);
+ tuple = dtuple_create_from_mem(tuple_buf, sizeof(tuple_buf), 1);
dfield = dtuple_get_nth_field(tuple, 0);
dfield_set_data(dfield, table_name, ut_strlen(table_name));
@@ -2489,7 +2489,6 @@ loop:
/* Now we get a foreign key constraint id */
field = rec_get_nth_field_old(rec, 1, &len);
- id = mem_heap_strdupl(heap, (char*) field, len);
btr_pcur_store_position(&pcur, &mtr);
@@ -2497,11 +2496,11 @@ loop:
/* Load the foreign constraint definition to the dictionary cache */
- err = dict_load_foreign(id, check_charsets, check_recursive);
+ err = dict_load_foreign((char*) field, len, check_charsets,
+ check_recursive);
if (err != DB_SUCCESS) {
btr_pcur_close(&pcur);
- mem_heap_free(heap);
return(err);
}
@@ -2517,7 +2516,6 @@ next_rec:
load_next_index:
btr_pcur_close(&pcur);
mtr_commit(&mtr);
- mem_heap_free(heap);
sec_index = dict_table_get_next_index(sec_index);
diff --git a/storage/xtradb/fil/fil0fil.c b/storage/xtradb/fil/fil0fil.c
index 8cabf13e2c4..2b67bdafeb9 100644
--- a/storage/xtradb/fil/fil0fil.c
+++ b/storage/xtradb/fil/fil0fil.c
@@ -193,7 +193,7 @@ struct fil_space_struct {
.ibd file of tablespace and want to
stop temporarily posting of new i/o
requests on the file */
- ibool stop_ibuf_merges;
+ ibool stop_new_ops;
/*!< we set this TRUE when we start
deleting a single-table tablespace */
ibool is_being_deleted;
@@ -218,12 +218,13 @@ struct fil_space_struct {
ulint n_pending_flushes; /*!< this is positive when flushing
the tablespace to disk; dropping of the
tablespace is forbidden if this is positive */
- ulint n_pending_ibuf_merges;/*!< this is positive
- when merging insert buffer entries to
- a page so that we may need to access
- the ibuf bitmap page in the
- tablespade: dropping of the tablespace
- is forbidden if this is positive */
+ ulint n_pending_ops;/*!< this is positive when we
+ have pending operations against this
+ tablespace. The pending operations can
+ be ibuf merges or lock validation code
+ trying to read a block.
+ Dropping of the tablespace is forbidden
+ if this is positive */
hash_node_t hash; /*!< hash chain node */
hash_node_t name_hash;/*!< hash chain the name_hash table */
#ifndef UNIV_HOTBACKUP
@@ -974,11 +975,6 @@ retry:
return;
}
- if (fil_system->n_open < fil_system->max_n_open) {
-
- return;
- }
-
space = fil_space_get_by_id(space_id);
if (space != NULL && space->stop_ios) {
@@ -995,6 +991,25 @@ retry:
mutex_exit(&fil_system->mutex);
+#ifndef UNIV_HOTBACKUP
+
+ /* Wake the i/o-handler threads to make sure pending
+ i/o's are performed */
+ os_aio_simulated_wake_handler_threads();
+
+ /* The sleep here is just to give IO helper threads a
+ bit of time to do some work. It is not required that
+ all IO related to the tablespace being renamed must
+ be flushed here as we do fil_flush() in
+ fil_rename_tablespace() as well. */
+ os_thread_sleep(20000);
+
+#endif /* UNIV_HOTBACKUP */
+
+ /* Flush tablespaces so that we can close modified
+ files in the LRU list */
+ fil_flush_file_spaces(FIL_TABLESPACE);
+
os_thread_sleep(20000);
count2++;
@@ -1002,6 +1017,11 @@ retry:
goto retry;
}
+ if (fil_system->n_open < fil_system->max_n_open) {
+
+ return;
+ }
+
/* If the file is already open, no need to do anything; if the space
does not exist, we handle the situation in the function which called
this function */
@@ -1274,7 +1294,7 @@ try_again:
}
space->stop_ios = FALSE;
- space->stop_ibuf_merges = FALSE;
+ space->stop_new_ops = FALSE;
space->is_being_deleted = FALSE;
space->purpose = purpose;
space->size = 0;
@@ -1283,7 +1303,7 @@ try_again:
space->n_reserved_extents = 0;
space->n_pending_flushes = 0;
- space->n_pending_ibuf_merges = 0;
+ space->n_pending_ops = 0;
UT_LIST_INIT(space->chain);
space->magic_n = FIL_SPACE_MAGIC_N;
@@ -1896,13 +1916,12 @@ fil_read_first_page(
#ifndef UNIV_HOTBACKUP
/*******************************************************************//**
-Increments the count of pending insert buffer page merges, if space is not
-being deleted.
-@return TRUE if being deleted, and ibuf merges should be skipped */
+Increments the count of pending operation, if space is not being deleted.
+@return TRUE if being deleted, and operation should be skipped */
UNIV_INTERN
ibool
-fil_inc_pending_ibuf_merges(
-/*========================*/
+fil_inc_pending_ops(
+/*================*/
ulint id) /*!< in: space id */
{
fil_space_t* space;
@@ -1918,13 +1937,13 @@ fil_inc_pending_ibuf_merges(
(ulong) id);
}
- if (space == NULL || space->stop_ibuf_merges) {
+ if (space == NULL || space->stop_new_ops) {
mutex_exit(&fil_system->mutex);
return(TRUE);
}
- space->n_pending_ibuf_merges++;
+ space->n_pending_ops++;
mutex_exit(&fil_system->mutex);
@@ -1932,11 +1951,11 @@ fil_inc_pending_ibuf_merges(
}
/*******************************************************************//**
-Decrements the count of pending insert buffer page merges. */
+Decrements the count of pending operations. */
UNIV_INTERN
void
-fil_decr_pending_ibuf_merges(
-/*=========================*/
+fil_decr_pending_ops(
+/*=================*/
ulint id) /*!< in: space id */
{
fil_space_t* space;
@@ -1947,13 +1966,13 @@ fil_decr_pending_ibuf_merges(
if (space == NULL) {
fprintf(stderr,
- "InnoDB: Error: decrementing ibuf merge of a"
- " dropped tablespace %lu\n",
+ "InnoDB: Error: decrementing pending operation"
+ " of a dropped tablespace %lu\n",
(ulong) id);
}
if (space != NULL) {
- space->n_pending_ibuf_merges--;
+ space->n_pending_ops--;
}
mutex_exit(&fil_system->mutex);
@@ -2164,7 +2183,7 @@ fil_op_log_parse_or_replay(
switch (type) {
case MLOG_FILE_DELETE:
if (fil_tablespace_exists_in_mem(space_id)) {
- ut_a(fil_delete_tablespace(space_id));
+ ut_a(fil_delete_tablespace(space_id, TRUE));
}
break;
@@ -2234,7 +2253,9 @@ UNIV_INTERN
ibool
fil_delete_tablespace(
/*==================*/
- ulint id) /*!< in: space id */
+ ulint id, /*!< in: space id */
+ ibool evict_all) /*!< in: TRUE if we want all pages
+ evicted from LRU. */
{
ibool success;
fil_space_t* space;
@@ -2243,15 +2264,15 @@ fil_delete_tablespace(
char* path;
ut_a(id != 0);
-stop_ibuf_merges:
+stop_new_ops:
mutex_enter(&fil_system->mutex);
space = fil_space_get_by_id(id);
if (space != NULL) {
- space->stop_ibuf_merges = TRUE;
+ space->stop_new_ops = TRUE;
- if (space->n_pending_ibuf_merges == 0) {
+ if (space->n_pending_ops == 0) {
mutex_exit(&fil_system->mutex);
count = 0;
@@ -2265,9 +2286,10 @@ stop_ibuf_merges:
ut_print_filename(stderr, space->name);
fprintf(stderr, ",\n"
"InnoDB: but there are %lu pending"
- " ibuf merges on it.\n"
+ " operations (most likely ibuf merges)"
+ " on it.\n"
"InnoDB: Loop %lu.\n",
- (ulong) space->n_pending_ibuf_merges,
+ (ulong) space->n_pending_ops,
(ulong) count);
}
@@ -2276,7 +2298,7 @@ stop_ibuf_merges:
os_thread_sleep(20000);
count++;
- goto stop_ibuf_merges;
+ goto stop_new_ops;
}
}
@@ -2302,7 +2324,7 @@ try_again:
}
ut_a(space);
- ut_a(space->n_pending_ibuf_merges == 0);
+ ut_a(space->n_pending_ops == 0);
space->is_being_deleted = TRUE;
@@ -2358,7 +2380,11 @@ try_again:
if (srv_lazy_drop_table) {
buf_LRU_mark_space_was_deleted(id);
} else {
- buf_LRU_invalidate_tablespace(id);
+ buf_LRU_flush_or_remove_pages(
+ id, evict_all
+ ? BUF_REMOVE_ALL_NO_WRITE
+ : BUF_REMOVE_FLUSH_NO_WRITE);
+
}
#endif
/* printf("Deleting tablespace %s id %lu\n", space->name, id); */
@@ -2447,7 +2473,7 @@ fil_discard_tablespace(
{
ibool success;
- success = fil_delete_tablespace(id);
+ success = fil_delete_tablespace(id, TRUE);
if (!success) {
fprintf(stderr,
@@ -2579,7 +2605,7 @@ fil_rename_tablespace(
retry:
count++;
- if (count > 1000) {
+ if (!(count % 1000)) {
ut_print_timestamp(stderr);
fputs(" InnoDB: Warning: problems renaming ", stderr);
ut_print_filename(stderr, old_name);
@@ -3905,7 +3931,7 @@ convert_err_exit:
level = btr_page_get_level(page, &mtr);
- new_block = btr_page_alloc(index, 0, FSP_NO_DIR, level, &mtr);
+ new_block = btr_page_alloc(index, 0, FSP_NO_DIR, level, &mtr, &mtr);
new_page = buf_block_get_frame(new_block);
new_page_zip = buf_block_get_page_zip(new_block);
btr_page_create(new_block, new_page_zip, index, level, &mtr);
@@ -3953,7 +3979,7 @@ convert_err_exit:
split_rec = page_get_middle_rec(page);
new_block = btr_page_alloc(index, page_no + 1, FSP_UP,
- btr_page_get_level(page, &mtr), &mtr);
+ btr_page_get_level(page, &mtr), &mtr, &mtr);
new_page = buf_block_get_frame(new_block);
new_page_zip = buf_block_get_page_zip(new_block);
btr_page_create(new_block, new_page_zip, index,
diff --git a/storage/xtradb/fsp/fsp0fsp.c b/storage/xtradb/fsp/fsp0fsp.c
index 0c96aab0356..d4a2745b90b 100644
--- a/storage/xtradb/fsp/fsp0fsp.c
+++ b/storage/xtradb/fsp/fsp0fsp.c
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1995, 2011, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1995, 2012, Oracle and/or its affiliates. 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
@@ -248,28 +248,38 @@ fsp_fill_free_list(
descriptor page and ibuf bitmap page;
then we do not allocate more extents */
ulint space, /*!< in: space */
- fsp_header_t* header, /*!< in: space header */
- mtr_t* mtr); /*!< in: mtr */
+ fsp_header_t* header, /*!< in/out: space header */
+ mtr_t* mtr) /*!< in/out: mini-transaction */
+ __attribute__((nonnull));
/**********************************************************************//**
Allocates a single free page from a segment. This function implements
the intelligent allocation strategy which tries to minimize file space
fragmentation.
-@return the allocated page number, FIL_NULL if no page could be allocated */
+@retval NULL if no page could be allocated
+@retval block, rw_lock_x_lock_count(&block->lock) == 1 if allocation succeeded
+(init_mtr == mtr, or the page was not previously freed in mtr)
+@retval block (not allocated or initialized) otherwise */
static
-ulint
+buf_block_t*
fseg_alloc_free_page_low(
/*=====================*/
ulint space, /*!< in: space */
ulint zip_size,/*!< in: compressed page size in bytes
or 0 for uncompressed pages */
- fseg_inode_t* seg_inode, /*!< in: segment inode */
- ulint hint, /*!< in: hint of which page would be desirable */
+ fseg_inode_t* seg_inode, /*!< in/out: segment inode */
+ ulint hint, /*!< in: hint of which page would be
+ desirable */
byte direction, /*!< in: if the new page is needed because
of an index page split, and records are
inserted there in order, into which
direction they go alphabetically: FSP_DOWN,
FSP_UP, FSP_NO_DIR */
- mtr_t* mtr); /*!< in: mtr handle */
+ mtr_t* mtr, /*!< in/out: mini-transaction */
+ mtr_t* init_mtr)/*!< in/out: mtr or another mini-transaction
+ in which the page should be initialized.
+ If init_mtr!=mtr, but the page is already
+ latched in mtr, do not initialize the page. */
+ __attribute__((warn_unused_result, nonnull));
#endif /* !UNIV_HOTBACKUP */
/**********************************************************************//**
@@ -639,23 +649,22 @@ xdes_calc_descriptor_index(
/********************************************************************//**
Gets pointer to a the extent descriptor of a page. The page where the extent
-descriptor resides is x-locked. If the page offset is equal to the free limit
-of the space, adds new extents from above the free limit to the space free
-list, if not free limit == space size. This adding is necessary to make the
-descriptor defined, as they are uninitialized above the free limit.
+descriptor resides is x-locked. This function no longer extends the data
+file.
@return pointer to the extent descriptor, NULL if the page does not
-exist in the space or if the offset exceeds the free limit */
-UNIV_INLINE
+exist in the space or if the offset is >= the free limit */
+UNIV_INLINE __attribute__((nonnull, warn_unused_result))
xdes_t*
xdes_get_descriptor_with_space_hdr(
/*===============================*/
- fsp_header_t* sp_header,/*!< in/out: space header, x-latched */
- ulint space, /*!< in: space id */
- ulint offset, /*!< in: page offset;
- if equal to the free limit,
- we try to add new extents to
- the space free list */
- mtr_t* mtr) /*!< in: mtr handle */
+ fsp_header_t* sp_header, /*!< in/out: space header, x-latched
+ in mtr */
+ ulint space, /*!< in: space id */
+ ulint offset, /*!< in: page offset; if equal
+ to the free limit, we try to
+ add new extents to the space
+ free list */
+ mtr_t* mtr) /*!< in/out: mini-transaction */
{
ulint limit;
ulint size;
@@ -663,11 +672,9 @@ xdes_get_descriptor_with_space_hdr(
ulint descr_page_no;
page_t* descr_page;
- ut_ad(mtr);
ut_ad(mtr_memo_contains(mtr, fil_space_get_latch(space, NULL),
MTR_MEMO_X_LOCK));
- ut_ad(mtr_memo_contains_page(mtr, sp_header, MTR_MEMO_PAGE_S_FIX)
- || mtr_memo_contains_page(mtr, sp_header, MTR_MEMO_PAGE_X_FIX));
+ ut_ad(mtr_memo_contains_page(mtr, sp_header, MTR_MEMO_PAGE_X_FIX));
ut_ad(page_offset(sp_header) == FSP_HEADER_OFFSET);
/* Read free limit and space size */
limit = mach_read_from_4(sp_header + FSP_FREE_LIMIT);
@@ -704,8 +711,8 @@ Gets pointer to a the extent descriptor of a page. The page where the extent
descriptor resides is x-locked. This function no longer extends the data
file.
@return pointer to the extent descriptor, NULL if the page does not
-exist in the space or if the offset is >= the free limit */
-static
+exist in the space or if the offset exceeds the free limit */
+static __attribute__((nonnull, warn_unused_result))
xdes_t*
xdes_get_descriptor(
/*================*/
@@ -714,7 +721,7 @@ xdes_get_descriptor(
or 0 for uncompressed pages */
ulint offset, /*!< in: page offset; if equal to the free limit,
we try to add new extents to the space free list */
- mtr_t* mtr) /*!< in: mtr handle */
+ mtr_t* mtr) /*!< in/out: mini-transaction */
{
buf_block_t* block;
fsp_header_t* sp_header;
@@ -1098,14 +1105,14 @@ fsp_header_get_tablespace_size(void)
Tries to extend a single-table tablespace so that a page would fit in the
data file.
@return TRUE if success */
-static
+static __attribute__((nonnull, warn_unused_result))
ibool
fsp_try_extend_data_file_with_pages(
/*================================*/
ulint space, /*!< in: space */
ulint page_no, /*!< in: page number */
- fsp_header_t* header, /*!< in: space header */
- mtr_t* mtr) /*!< in: mtr */
+ fsp_header_t* header, /*!< in/out: space header */
+ mtr_t* mtr) /*!< in/out: mini-transaction */
{
ibool success;
ulint actual_size;
@@ -1130,7 +1137,7 @@ fsp_try_extend_data_file_with_pages(
/***********************************************************************//**
Tries to extend the last data file of a tablespace if it is auto-extending.
@return FALSE if not auto-extending */
-static
+static __attribute__((nonnull))
ibool
fsp_try_extend_data_file(
/*=====================*/
@@ -1140,8 +1147,8 @@ fsp_try_extend_data_file(
the actual file size rounded down to
megabyte */
ulint space, /*!< in: space */
- fsp_header_t* header, /*!< in: space header */
- mtr_t* mtr) /*!< in: mtr */
+ fsp_header_t* header, /*!< in/out: space header */
+ mtr_t* mtr) /*!< in/out: mini-transaction */
{
ulint size;
ulint zip_size;
@@ -1277,7 +1284,7 @@ fsp_fill_free_list(
then we do not allocate more extents */
ulint space, /*!< in: space */
fsp_header_t* header, /*!< in/out: space header */
- mtr_t* mtr) /*!< in: mtr */
+ mtr_t* mtr) /*!< in/out: mini-transaction */
{
ulint limit;
ulint size;
@@ -1476,29 +1483,120 @@ fsp_alloc_free_extent(
}
/**********************************************************************//**
-Allocates a single free page from a space. The page is marked as used.
-@return the page offset, FIL_NULL if no page could be allocated */
+Allocates a single free page from a space. */
+static __attribute__((nonnull))
+void
+fsp_alloc_from_free_frag(
+/*=====================*/
+ fsp_header_t* header, /*!< in/out: tablespace header */
+ xdes_t* descr, /*!< in/out: extent descriptor */
+ ulint bit, /*!< in: slot to allocate in the extent */
+ mtr_t* mtr) /*!< in/out: mini-transaction */
+{
+ ulint frag_n_used;
+
+ ut_ad(xdes_get_state(descr, mtr) == XDES_FREE_FRAG);
+ ut_a(xdes_get_bit(descr, XDES_FREE_BIT, bit, mtr));
+ xdes_set_bit(descr, XDES_FREE_BIT, bit, FALSE, mtr);
+
+ /* Update the FRAG_N_USED field */
+ frag_n_used = mtr_read_ulint(header + FSP_FRAG_N_USED, MLOG_4BYTES,
+ mtr);
+ frag_n_used++;
+ mlog_write_ulint(header + FSP_FRAG_N_USED, frag_n_used, MLOG_4BYTES,
+ mtr);
+ if (xdes_is_full(descr, mtr)) {
+ /* The fragment is full: move it to another list */
+ flst_remove(header + FSP_FREE_FRAG, descr + XDES_FLST_NODE,
+ mtr);
+ xdes_set_state(descr, XDES_FULL_FRAG, mtr);
+
+ flst_add_last(header + FSP_FULL_FRAG, descr + XDES_FLST_NODE,
+ mtr);
+ mlog_write_ulint(header + FSP_FRAG_N_USED,
+ frag_n_used - FSP_EXTENT_SIZE, MLOG_4BYTES,
+ mtr);
+ }
+}
+
+/**********************************************************************//**
+Gets a buffer block for an allocated page.
+
+NOTE: If init_mtr != mtr, the block will only be initialized if it was
+not previously x-latched. It is assumed that the block has been
+x-latched only by mtr, and freed in mtr in that case.
+
+@return block, initialized if init_mtr==mtr
+or rw_lock_x_lock_count(&block->lock) == 1 */
static
-ulint
+buf_block_t*
+fsp_page_create(
+/*============*/
+ ulint space, /*!< in: space id of the allocated page */
+ ulint zip_size, /*!< in: compressed page size in bytes
+ or 0 for uncompressed pages */
+ ulint page_no, /*!< in: page number of the allocated page */
+ mtr_t* mtr, /*!< in: mini-transaction of the allocation */
+ mtr_t* init_mtr) /*!< in: mini-transaction for initializing
+ the page */
+{
+ buf_block_t* block
+ = buf_page_create(space, page_no, zip_size, init_mtr);
+#ifdef UNIV_SYNC_DEBUG
+ ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX)
+ == rw_lock_own(&block->lock, RW_LOCK_EX));
+#endif /* UNIV_SYNC_DEBUG */
+
+ /* Mimic buf_page_get(), but avoid the buf_pool->page_hash lookup. */
+ rw_lock_x_lock(&block->lock);
+ mutex_enter(&block->mutex);
+ buf_block_buf_fix_inc(block, __FILE__, __LINE__);
+ mutex_exit(&block->mutex);
+ mtr_memo_push(init_mtr, block, MTR_MEMO_PAGE_X_FIX);
+
+ if (init_mtr == mtr
+ || rw_lock_get_x_lock_count(&block->lock) == 1) {
+
+ /* Initialize the page, unless it was already
+ X-latched in mtr. (In this case, we would want to
+ allocate another page that has not been freed in mtr.) */
+ ut_ad(init_mtr == mtr
+ || !mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX));
+
+ fsp_init_file_page(block, init_mtr);
+ }
+
+ return(block);
+}
+
+/**********************************************************************//**
+Allocates a single free page from a space. The page is marked as used.
+@retval NULL if no page could be allocated
+@retval block, rw_lock_x_lock_count(&block->lock) == 1 if allocation succeeded
+(init_mtr == mtr, or the page was not previously freed in mtr)
+@retval block (not allocated or initialized) otherwise */
+static __attribute__((nonnull, warn_unused_result))
+buf_block_t*
fsp_alloc_free_page(
/*================*/
ulint space, /*!< in: space id */
ulint zip_size,/*!< in: compressed page size in bytes
or 0 for uncompressed pages */
ulint hint, /*!< in: hint of which page would be desirable */
- mtr_t* mtr) /*!< in: mtr handle */
+ mtr_t* mtr, /*!< in/out: mini-transaction */
+ mtr_t* init_mtr)/*!< in/out: mini-transaction in which the
+ page should be initialized
+ (may be the same as mtr) */
{
fsp_header_t* header;
fil_addr_t first;
xdes_t* descr;
- buf_block_t* block;
ulint free;
- ulint frag_n_used;
ulint page_no;
ulint space_size;
- ibool success;
ut_ad(mtr);
+ ut_ad(init_mtr);
header = fsp_get_space_header(space, zip_size, mtr);
@@ -1525,7 +1623,7 @@ fsp_alloc_free_page(
if (descr == NULL) {
/* No free space left */
- return(FIL_NULL);
+ return(NULL);
}
xdes_set_state(descr, XDES_FREE_FRAG, mtr);
@@ -1570,50 +1668,18 @@ fsp_alloc_free_page(
" space size %lu. Page no %lu.\n",
(ulong) space, (ulong) space_size,
(ulong) page_no);
- return(FIL_NULL);
+ return(NULL);
}
- success = fsp_try_extend_data_file_with_pages(space, page_no,
- header, mtr);
- if (!success) {
+ if (!fsp_try_extend_data_file_with_pages(space, page_no,
+ header, mtr)) {
/* No disk space left */
- return(FIL_NULL);
+ return(NULL);
}
}
- xdes_set_bit(descr, XDES_FREE_BIT, free, FALSE, mtr);
+ fsp_alloc_from_free_frag(header, descr, free, mtr);
- /* Update the FRAG_N_USED field */
- frag_n_used = mtr_read_ulint(header + FSP_FRAG_N_USED, MLOG_4BYTES,
- mtr);
- frag_n_used++;
- mlog_write_ulint(header + FSP_FRAG_N_USED, frag_n_used, MLOG_4BYTES,
- mtr);
- if (xdes_is_full(descr, mtr)) {
- /* The fragment is full: move it to another list */
- flst_remove(header + FSP_FREE_FRAG, descr + XDES_FLST_NODE,
- mtr);
- xdes_set_state(descr, XDES_FULL_FRAG, mtr);
-
- flst_add_last(header + FSP_FULL_FRAG, descr + XDES_FLST_NODE,
- mtr);
- mlog_write_ulint(header + FSP_FRAG_N_USED,
- frag_n_used - FSP_EXTENT_SIZE, MLOG_4BYTES,
- mtr);
- }
-
- /* Initialize the allocated page to the buffer pool, so that it can
- be obtained immediately with buf_page_get without need for a disk
- read. */
-
- buf_page_create(space, page_no, zip_size, mtr);
-
- block = buf_page_get(space, zip_size, page_no, RW_X_LATCH, mtr);
- buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
-
- /* Prior contents of the page should be ignored */
- fsp_init_file_page(block, mtr);
-
- return(page_no);
+ return(fsp_page_create(space, zip_size, page_no, mtr, init_mtr));
}
/**********************************************************************//**
@@ -1652,6 +1718,9 @@ fsp_free_page(
fputs("InnoDB: Dump of descriptor: ", stderr);
ut_print_buf(stderr, ((byte*)descr) - 50, 200);
putc('\n', stderr);
+ /* Crash in debug version, so that we get a core dump
+ of this corruption. */
+ ut_ad(0);
if (state == XDES_FREE) {
/* We put here some fault tolerance: if the page
@@ -1670,6 +1739,9 @@ fsp_free_page(
"InnoDB: Dump of descriptor: ", (ulong) page);
ut_print_buf(stderr, ((byte*)descr) - 50, 200);
putc('\n', stderr);
+ /* Crash in debug version, so that we get a core dump
+ of this corruption. */
+ ut_ad(0);
/* We put here some fault tolerance: if the page
is already free, return without doing anything! */
@@ -1704,6 +1776,8 @@ fsp_free_page(
mtr);
fsp_free_extent(space, zip_size, page, mtr);
}
+
+ mtr->n_freed_pages++;
}
/**********************************************************************//**
@@ -1841,7 +1915,6 @@ fsp_alloc_seg_inode_page(
fseg_inode_t* inode;
buf_block_t* block;
page_t* page;
- ulint page_no;
ulint space;
ulint zip_size;
ulint i;
@@ -1852,15 +1925,15 @@ fsp_alloc_seg_inode_page(
zip_size = dict_table_flags_to_zip_size(
mach_read_from_4(FSP_SPACE_FLAGS + space_header));
- page_no = fsp_alloc_free_page(space, zip_size, 0, mtr);
+ block = fsp_alloc_free_page(space, zip_size, 0, mtr, mtr);
- if (page_no == FIL_NULL) {
+ if (block == NULL) {
return(FALSE);
}
- block = buf_page_get(space, zip_size, page_no, RW_X_LATCH, mtr);
buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
+ ut_ad(rw_lock_get_x_lock_count(&block->lock) == 1);
block->check_index_page_at_flush = FALSE;
@@ -2273,19 +2346,20 @@ fseg_create_general(
}
if (page == 0) {
- page = fseg_alloc_free_page_low(space, zip_size,
- inode, 0, FSP_UP, mtr);
+ block = fseg_alloc_free_page_low(space, zip_size,
+ inode, 0, FSP_UP, mtr, mtr);
- if (page == FIL_NULL) {
+ if (block == NULL) {
fsp_free_seg_inode(space, zip_size, inode, mtr);
goto funct_exit;
}
- block = buf_page_get(space, zip_size, page, RW_X_LATCH, mtr);
+ ut_ad(rw_lock_get_x_lock_count(&block->lock) == 1);
+
header = byte_offset + buf_block_get_frame(block);
- mlog_write_ulint(header - byte_offset + FIL_PAGE_TYPE,
+ mlog_write_ulint(buf_block_get_frame(block) + FIL_PAGE_TYPE,
FIL_PAGE_TYPE_SYS, MLOG_2BYTES, mtr);
}
@@ -2462,8 +2536,10 @@ fseg_fill_free_list(
Allocates a free extent for the segment: looks first in the free list of the
segment, then tries to allocate from the space free list. NOTE that the extent
returned still resides in the segment free list, it is not yet taken off it!
-@return allocated extent, still placed in the segment free list, NULL
-if could not be allocated */
+@retval NULL if no page could be allocated
+@retval block, rw_lock_x_lock_count(&block->lock) == 1 if allocation succeeded
+(init_mtr == mtr, or the page was not previously freed in mtr)
+@retval block (not allocated or initialized) otherwise */
static
xdes_t*
fseg_alloc_free_extent(
@@ -2515,22 +2591,30 @@ fseg_alloc_free_extent(
Allocates a single free page from a segment. This function implements
the intelligent allocation strategy which tries to minimize file space
fragmentation.
-@return the allocated page number, FIL_NULL if no page could be allocated */
+@retval NULL if no page could be allocated
+@retval block, rw_lock_x_lock_count(&block->lock) == 1 if allocation succeeded
+(init_mtr == mtr, or the page was not previously freed in mtr)
+@retval block (not allocated or initialized) otherwise */
static
-ulint
+buf_block_t*
fseg_alloc_free_page_low(
/*=====================*/
ulint space, /*!< in: space */
ulint zip_size,/*!< in: compressed page size in bytes
or 0 for uncompressed pages */
- fseg_inode_t* seg_inode, /*!< in: segment inode */
- ulint hint, /*!< in: hint of which page would be desirable */
+ fseg_inode_t* seg_inode, /*!< in/out: segment inode */
+ ulint hint, /*!< in: hint of which page would be
+ desirable */
byte direction, /*!< in: if the new page is needed because
of an index page split, and records are
inserted there in order, into which
direction they go alphabetically: FSP_DOWN,
FSP_UP, FSP_NO_DIR */
- mtr_t* mtr) /*!< in: mtr handle */
+ mtr_t* mtr, /*!< in/out: mini-transaction */
+ mtr_t* init_mtr)/*!< in/out: mtr or another mini-transaction
+ in which the page should be initialized.
+ If init_mtr!=mtr, but the page is already
+ latched in mtr, do not initialize the page. */
{
fsp_header_t* space_header;
ulint space_size;
@@ -2541,7 +2625,6 @@ fseg_alloc_free_page_low(
ulint ret_page; /*!< the allocated page offset, FIL_NULL
if could not be allocated */
xdes_t* ret_descr; /*!< the extent of the allocated page */
- ibool frag_page_allocated = FALSE;
ibool success;
ulint n;
@@ -2563,6 +2646,7 @@ fseg_alloc_free_page_low(
if (descr == NULL) {
/* Hint outside space or too high above free limit: reset
hint */
+ /* The file space header page is always allocated. */
hint = 0;
descr = xdes_get_descriptor(space, zip_size, hint, mtr);
}
@@ -2573,15 +2657,19 @@ fseg_alloc_free_page_low(
&& mach_read_from_8(descr + XDES_ID) == seg_id
&& (xdes_get_bit(descr, XDES_FREE_BIT,
hint % FSP_EXTENT_SIZE, mtr) == TRUE)) {
-
+take_hinted_page:
/* 1. We can take the hinted page
=================================*/
ret_descr = descr;
ret_page = hint;
+ /* Skip the check for extending the tablespace. If the
+ page hint were not within the size of the tablespace,
+ we would have got (descr == NULL) above and reset the hint. */
+ goto got_hinted_page;
/*-----------------------------------------------------------*/
- } else if ((xdes_get_state(descr, mtr) == XDES_FREE)
- && ((reserved - used) < reserved / FSEG_FILLFACTOR)
- && (used >= FSEG_FRAG_LIMIT)) {
+ } else if (xdes_get_state(descr, mtr) == XDES_FREE
+ && reserved - used < reserved / FSEG_FILLFACTOR
+ && used >= FSEG_FRAG_LIMIT) {
/* 2. We allocate the free extent from space and can take
=========================================================
@@ -2599,7 +2687,7 @@ fseg_alloc_free_page_low(
/* Try to fill the segment free list */
fseg_fill_free_list(seg_inode, space, zip_size,
hint + FSP_EXTENT_SIZE, mtr);
- ret_page = hint;
+ goto take_hinted_page;
/*-----------------------------------------------------------*/
} else if ((direction != FSP_NO_DIR)
&& ((reserved - used) < reserved / FSEG_FILLFACTOR)
@@ -2647,7 +2735,7 @@ fseg_alloc_free_page_low(
first = flst_get_first(seg_inode + FSEG_FREE, mtr);
} else {
ut_error;
- return(FIL_NULL);
+ return(NULL);
}
ret_descr = xdes_lst_get_descriptor(space, zip_size,
@@ -2659,20 +2747,23 @@ fseg_alloc_free_page_low(
} else if (used < FSEG_FRAG_LIMIT) {
/* 6. We allocate an individual page from the space
===================================================*/
- ret_page = fsp_alloc_free_page(space, zip_size, hint, mtr);
- ret_descr = NULL;
+ buf_block_t* block = fsp_alloc_free_page(
+ space, zip_size, hint, mtr, init_mtr);
- frag_page_allocated = TRUE;
-
- if (ret_page != FIL_NULL) {
+ if (block != NULL) {
/* Put the page in the fragment page array of the
segment */
n = fseg_find_free_frag_page_slot(seg_inode, mtr);
- ut_a(n != FIL_NULL);
+ ut_a(n != ULINT_UNDEFINED);
- fseg_set_nth_frag_page_no(seg_inode, n, ret_page,
- mtr);
+ fseg_set_nth_frag_page_no(
+ seg_inode, n, buf_block_get_page_no(block),
+ mtr);
}
+
+ /* fsp_alloc_free_page() invoked fsp_init_file_page()
+ already. */
+ return(block);
/*-----------------------------------------------------------*/
} else {
/* 7. We allocate a new extent and take its first page
@@ -2690,7 +2781,7 @@ fseg_alloc_free_page_low(
if (ret_page == FIL_NULL) {
/* Page could not be allocated */
- return(FIL_NULL);
+ return(NULL);
}
if (space != 0) {
@@ -2708,38 +2799,22 @@ fseg_alloc_free_page_low(
" the space size %lu. Page no %lu.\n",
(ulong) space, (ulong) space_size,
(ulong) ret_page);
- return(FIL_NULL);
+ return(NULL);
}
success = fsp_try_extend_data_file_with_pages(
space, ret_page, space_header, mtr);
if (!success) {
/* No disk space left */
- return(FIL_NULL);
+ return(NULL);
}
}
}
- if (!frag_page_allocated) {
- /* Initialize the allocated page to buffer pool, so that it
- can be obtained immediately with buf_page_get without need
- for a disk read */
- buf_block_t* block;
- ulint zip_size = dict_table_flags_to_zip_size(
- mach_read_from_4(FSP_SPACE_FLAGS + space_header));
-
- block = buf_page_create(space, ret_page, zip_size, mtr);
- buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
-
- if (UNIV_UNLIKELY(block != buf_page_get(space, zip_size,
- ret_page, RW_X_LATCH,
- mtr))) {
- ut_error;
- }
-
- /* The prior contents of the page should be ignored */
- fsp_init_file_page(block, mtr);
-
+got_hinted_page:
+ /* ret_descr == NULL if the block was allocated from free_frag
+ (XDES_FREE_FRAG) */
+ if (ret_descr != NULL) {
/* At this point we know the extent and the page offset.
The extent is still in the appropriate list (FSEG_NOT_FULL
or FSEG_FREE), and the page is not yet marked as used. */
@@ -2752,22 +2827,28 @@ fseg_alloc_free_page_low(
fseg_mark_page_used(seg_inode, ret_page, ret_descr, mtr);
}
- buf_reset_check_index_page_at_flush(space, ret_page);
-
- return(ret_page);
+ return(fsp_page_create(
+ space, dict_table_flags_to_zip_size(
+ mach_read_from_4(FSP_SPACE_FLAGS
+ + space_header)),
+ ret_page, mtr, init_mtr));
}
/**********************************************************************//**
Allocates a single free page from a segment. This function implements
the intelligent allocation strategy which tries to minimize file space
fragmentation.
-@return allocated page offset, FIL_NULL if no page could be allocated */
+@retval NULL if no page could be allocated
+@retval block, rw_lock_x_lock_count(&block->lock) == 1 if allocation succeeded
+(init_mtr == mtr, or the page was not previously freed in mtr)
+@retval block (not allocated or initialized) otherwise */
UNIV_INTERN
-ulint
+buf_block_t*
fseg_alloc_free_page_general(
/*=========================*/
- fseg_header_t* seg_header,/*!< in: segment header */
- ulint hint, /*!< in: hint of which page would be desirable */
+ fseg_header_t* seg_header,/*!< in/out: segment header */
+ ulint hint, /*!< in: hint of which page would be
+ desirable */
byte direction,/*!< in: if the new page is needed because
of an index page split, and records are
inserted there in order, into which
@@ -2778,15 +2859,18 @@ fseg_alloc_free_page_general(
with fsp_reserve_free_extents, then there
is no need to do the check for this individual
page */
- mtr_t* mtr) /*!< in: mtr handle */
+ mtr_t* mtr, /*!< in/out: mini-transaction handle */
+ mtr_t* init_mtr)/*!< in/out: mtr or another mini-transaction
+ in which the page should be initialized.
+ If init_mtr!=mtr, but the page is already
+ latched in mtr, do not initialize the page. */
{
fseg_inode_t* inode;
ulint space;
ulint flags;
ulint zip_size;
rw_lock_t* latch;
- ibool success;
- ulint page_no;
+ buf_block_t* block;
ulint n_reserved;
space = page_get_space_id(page_align(seg_header));
@@ -2811,43 +2895,20 @@ fseg_alloc_free_page_general(
inode = fseg_inode_get(seg_header, space, zip_size, mtr);
- if (!has_done_reservation) {
- success = fsp_reserve_free_extents(&n_reserved, space, 2,
- FSP_NORMAL, mtr);
- if (!success) {
- return(FIL_NULL);
- }
+ if (!has_done_reservation
+ && !fsp_reserve_free_extents(&n_reserved, space, 2,
+ FSP_NORMAL, mtr)) {
+ return(NULL);
}
- page_no = fseg_alloc_free_page_low(space, zip_size,
- inode, hint, direction, mtr);
+ block = fseg_alloc_free_page_low(space, zip_size,
+ inode, hint, direction,
+ mtr, init_mtr);
if (!has_done_reservation) {
fil_space_release_free_extents(space, n_reserved);
}
- return(page_no);
-}
-
-/**********************************************************************//**
-Allocates a single free page from a segment. This function implements
-the intelligent allocation strategy which tries to minimize file space
-fragmentation.
-@return allocated page offset, FIL_NULL if no page could be allocated */
-UNIV_INTERN
-ulint
-fseg_alloc_free_page(
-/*=================*/
- fseg_header_t* seg_header,/*!< in: segment header */
- ulint hint, /*!< in: hint of which page would be desirable */
- byte direction,/*!< in: if the new page is needed because
- of an index page split, and records are
- inserted there in order, into which
- direction they go alphabetically: FSP_DOWN,
- FSP_UP, FSP_NO_DIR */
- mtr_t* mtr) /*!< in: mtr handle */
-{
- return(fseg_alloc_free_page_general(seg_header, hint, direction,
- FALSE, mtr));
+ return(block);
}
/**********************************************************************//**
@@ -3358,6 +3419,8 @@ crash:
descr + XDES_FLST_NODE, mtr);
fsp_free_extent(space, zip_size, page, mtr);
}
+
+ mtr->n_freed_pages++;
}
/**********************************************************************//**
diff --git a/storage/xtradb/handler/ha_innodb.cc b/storage/xtradb/handler/ha_innodb.cc
index 61b14c2358a..12a9abd443e 100644
--- a/storage/xtradb/handler/ha_innodb.cc
+++ b/storage/xtradb/handler/ha_innodb.cc
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 2000, 2011, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2000, 2012, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2008, 2009 Google Inc.
Copyright (c) 2009, Percona Inc.
@@ -26,8 +26,8 @@ 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 program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
*****************************************************************************/
@@ -226,6 +226,9 @@ static my_bool innobase_create_status_file = FALSE;
static my_bool innobase_stats_on_metadata = TRUE;
static my_bool innobase_large_prefix = FALSE;
static my_bool innobase_use_sys_stats_table = FALSE;
+#ifdef UNIV_DEBUG
+static ulong innobase_sys_stats_root_page = 0;
+#endif
static my_bool innobase_buffer_pool_shm_checksum = TRUE;
static uint innobase_buffer_pool_shm_key = 0;
@@ -1217,6 +1220,9 @@ convert_error_code_to_mysql(
case DB_OUT_OF_FILE_SPACE:
return(HA_ERR_RECORD_FILE_FULL);
+ case DB_TABLE_IN_FK_CHECK:
+ return(HA_ERR_TABLE_IN_FK_CHECK);
+
case DB_TABLE_IS_BEING_USED:
return(HA_ERR_WRONG_COMMAND);
@@ -2774,6 +2780,10 @@ mem_free_and_error:
srv_use_sys_stats_table = (ibool) innobase_use_sys_stats_table;
+#ifdef UNIV_DEBUG
+ srv_sys_stats_root_page = innobase_sys_stats_root_page;
+#endif
+
/* -------------- Log files ---------------------------*/
/* The default dir for log files is the datadir of MySQL */
@@ -3896,52 +3906,140 @@ ha_innobase::primary_key_is_clustered()
return(true);
}
+/** Always normalize table name to lower case on Windows */
+#ifdef __WIN__
+#define normalize_table_name(norm_name, name) \
+ normalize_table_name_low(norm_name, name, TRUE)
+#else
+#define normalize_table_name(norm_name, name) \
+ normalize_table_name_low(norm_name, name, FALSE)
+#endif /* __WIN__ */
+
/*****************************************************************//**
Normalizes a table name string. A normalized name consists of the
database name catenated to '/' and table name. An example:
test/mytable. On Windows normalization puts both the database name and the
-table name always to lower case. */
+table name always to lower case if "set_lower_case" is set to TRUE. */
static
void
-normalize_table_name(
-/*=================*/
+normalize_table_name_low(
+/*=====================*/
char* norm_name, /*!< out: normalized name as a
null-terminated string */
- const char* name) /*!< in: table name string */
+ const char* name, /*!< in: table name string */
+ ibool set_lower_case) /*!< in: TRUE if we want to set
+ name to lower case */
{
char* name_ptr;
char* db_ptr;
+ ulint db_len;
char* ptr;
/* Scan name from the end */
- ptr = strend(name)-1;
+ ptr = strend(name) - 1;
+ /* seek to the last path separator */
while (ptr >= name && *ptr != '\\' && *ptr != '/') {
ptr--;
}
name_ptr = ptr + 1;
- DBUG_ASSERT(ptr > name);
+ /* skip any number of path separators */
+ while (ptr >= name && (*ptr == '\\' || *ptr == '/')) {
+ ptr--;
+ }
- ptr--;
+ DBUG_ASSERT(ptr >= name);
+ /* seek to the last but one path separator or one char before
+ the beginning of name */
+ db_len = 0;
while (ptr >= name && *ptr != '\\' && *ptr != '/') {
ptr--;
+ db_len++;
}
db_ptr = ptr + 1;
- memcpy(norm_name, db_ptr, strlen(name) + 1 - (db_ptr - name));
+ memcpy(norm_name, db_ptr, db_len);
- norm_name[name_ptr - db_ptr - 1] = '/';
+ norm_name[db_len] = '/';
-#ifdef __WIN__
- innobase_casedn_str(norm_name);
-#endif
+ memcpy(norm_name + db_len + 1, name_ptr, strlen(name_ptr) + 1);
+
+ if (set_lower_case) {
+ innobase_casedn_str(norm_name);
+ }
}
+#if !defined(DBUG_OFF)
+/*********************************************************************
+Test normalize_table_name_low(). */
+static
+void
+test_normalize_table_name_low()
+/*===========================*/
+{
+ char norm_name[128];
+ const char* test_data[][2] = {
+ /* input, expected result */
+ {"./mysqltest/t1", "mysqltest/t1"},
+ {"./test/#sql-842b_2", "test/#sql-842b_2"},
+ {"./test/#sql-85a3_10", "test/#sql-85a3_10"},
+ {"./test/#sql2-842b-2", "test/#sql2-842b-2"},
+ {"./test/bug29807", "test/bug29807"},
+ {"./test/foo", "test/foo"},
+ {"./test/innodb_bug52663", "test/innodb_bug52663"},
+ {"./test/t", "test/t"},
+ {"./test/t1", "test/t1"},
+ {"./test/t10", "test/t10"},
+ {"/a/b/db/table", "db/table"},
+ {"/a/b/db///////table", "db/table"},
+ {"/a/b////db///////table", "db/table"},
+ {"/var/tmp/mysqld.1/#sql842b_2_10", "mysqld.1/#sql842b_2_10"},
+ {"db/table", "db/table"},
+ {"ddd/t", "ddd/t"},
+ {"d/ttt", "d/ttt"},
+ {"d/t", "d/t"},
+ {".\\mysqltest\\t1", "mysqltest/t1"},
+ {".\\test\\#sql-842b_2", "test/#sql-842b_2"},
+ {".\\test\\#sql-85a3_10", "test/#sql-85a3_10"},
+ {".\\test\\#sql2-842b-2", "test/#sql2-842b-2"},
+ {".\\test\\bug29807", "test/bug29807"},
+ {".\\test\\foo", "test/foo"},
+ {".\\test\\innodb_bug52663", "test/innodb_bug52663"},
+ {".\\test\\t", "test/t"},
+ {".\\test\\t1", "test/t1"},
+ {".\\test\\t10", "test/t10"},
+ {"C:\\a\\b\\db\\table", "db/table"},
+ {"C:\\a\\b\\db\\\\\\\\\\\\\\table", "db/table"},
+ {"C:\\a\\b\\\\\\\\db\\\\\\\\\\\\\\table", "db/table"},
+ {"C:\\var\\tmp\\mysqld.1\\#sql842b_2_10", "mysqld.1/#sql842b_2_10"},
+ {"db\\table", "db/table"},
+ {"ddd\\t", "ddd/t"},
+ {"d\\ttt", "d/ttt"},
+ {"d\\t", "d/t"},
+ };
+
+ for (size_t i = 0; i < UT_ARR_SIZE(test_data); i++) {
+ printf("test_normalize_table_name_low(): "
+ "testing \"%s\", expected \"%s\"... ",
+ test_data[i][0], test_data[i][1]);
+
+ normalize_table_name_low(norm_name, test_data[i][0], FALSE);
+
+ if (strcmp(norm_name, test_data[i][1]) == 0) {
+ printf("ok\n");
+ } else {
+ printf("got \"%s\"\n", norm_name);
+ ut_error;
+ }
+ }
+}
+#endif /* !DBUG_OFF */
+
/********************************************************************//**
Get the upper limit of the MySQL integral and floating-point type.
@return maximum allowed value for the field */
@@ -4343,6 +4441,8 @@ ha_innobase::open(
THD* thd;
ulint retries = 0;
char* is_part = NULL;
+ ibool par_case_name_set = FALSE;
+ char par_case_name[MAX_FULL_NAME_LEN + 1];
DBUG_ENTER("ha_innobase::open");
@@ -4373,51 +4473,107 @@ ha_innobase::open(
DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE);
}
- /* Create buffers for packing the fields of a record. Why
- table->stored_rec_length did not work here? Obviously, because char
- fields when packed actually became 1 byte longer, when we also
- stored the string length as the first byte. */
-
- upd_and_key_val_buff_len =
- table->s->stored_rec_length + table->s->max_key_length
- + MAX_REF_PARTS * 3;
- if (!(uchar*) my_multi_malloc(MYF(MY_WME),
- &upd_buff, upd_and_key_val_buff_len,
- &key_val_buff, upd_and_key_val_buff_len,
- NullS)) {
- free_share(share);
-
- DBUG_RETURN(1);
- }
+ /* Will be allocated if it is needed in ::update_row() */
+ upd_buf = NULL;
+ upd_buf_size = 0;
/* We look for pattern #P# to see if the table is partitioned
MySQL table. The retry logic for partitioned tables is a
workaround for http://bugs.mysql.com/bug.php?id=33349. Look
at support issue https://support.mysql.com/view.php?id=21080
for more details. */
+#ifdef __WIN__
+ is_part = strstr(norm_name, "#p#");
+#else
is_part = strstr(norm_name, "#P#");
+#endif /* __WIN__ */
+
retry:
/* Get pointer to a table object in InnoDB dictionary cache */
ib_table = dict_table_get(norm_name, TRUE);
-
+
if (srv_pass_corrupt_table <= 1 && ib_table && ib_table->is_corrupt) {
free_share(share);
- my_free(upd_buff);
+ my_free(upd_buf);
+ upd_buf = NULL;
+ upd_buf_size = 0;
DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE);
}
share->ib_table = ib_table;
-
-
-
-
if (NULL == ib_table) {
if (is_part && retries < 10) {
- ++retries;
- os_thread_sleep(100000);
- goto retry;
+ /* MySQL partition engine hard codes the file name
+ separator as "#P#". The text case is fixed even if
+ lower_case_table_names is set to 1 or 2. This is true
+ for sub-partition names as well. InnoDB always
+ normalises file names to lower case on Windows, this
+ can potentially cause problems when copying/moving
+ tables between platforms.
+
+ 1) If boot against an installation from Windows
+ platform, then its partition table name could
+ be all be in lower case in system tables. So we
+ will need to check lower case name when load table.
+
+ 2) If we boot an installation from other case
+ sensitive platform in Windows, we might need to
+ check the existence of table name without lowering
+ case them in the system table. */
+ if (innobase_get_lower_case_table_names() == 1) {
+
+ if (!par_case_name_set) {
+#ifndef __WIN__
+ /* Check for the table using lower
+ case name, including the partition
+ separator "P" */
+ memcpy(par_case_name, norm_name,
+ strlen(norm_name));
+ par_case_name[strlen(norm_name)] = 0;
+ innobase_casedn_str(par_case_name);
+#else
+ /* On Windows platfrom, check
+ whether there exists table name in
+ system table whose name is
+ not being normalized to lower case */
+ normalize_table_name_low(
+ par_case_name, name, FALSE);
+#endif
+ par_case_name_set = TRUE;
+ }
+
+ ib_table = dict_table_get(
+ par_case_name, FALSE);
+ }
+ if (!ib_table) {
+ ++retries;
+ os_thread_sleep(100000);
+ goto retry;
+ } else {
+#ifndef __WIN__
+ sql_print_warning("Partition table %s opened "
+ "after converting to lower "
+ "case. The table may have "
+ "been moved from a case "
+ "in-sensitive file system. "
+ "Please recreate table in "
+ "the current file system\n",
+ norm_name);
+#else
+ sql_print_warning("Partition table %s opened "
+ "after skipping the step to "
+ "lower case the table name. "
+ "The table may have been "
+ "moved from a case sensitive "
+ "file system. Please "
+ "recreate table in the "
+ "current file system\n",
+ norm_name);
+#endif
+ goto table_opened;
+ }
}
if (is_part) {
@@ -4442,12 +4598,13 @@ retry:
"how you can resolve the problem.\n",
norm_name);
free_share(share);
- my_free(upd_buff);
my_errno = ENOENT;
DBUG_RETURN(HA_ERR_NO_SUCH_TABLE);
}
+table_opened:
+
if (ib_table->ibd_file_missing && !thd_tablespace_op(thd)) {
sql_print_error("MySQL is trying to open a table handle but "
"the .ibd file for\ntable %s does not exist.\n"
@@ -4458,16 +4615,14 @@ retry:
"how you can resolve the problem.\n",
norm_name);
free_share(share);
- my_free(upd_buff);
my_errno = ENOENT;
dict_table_decrement_handle_count(ib_table, FALSE);
DBUG_RETURN(HA_ERR_NO_SUCH_TABLE);
}
- prebuilt = row_create_prebuilt(ib_table);
+ prebuilt = row_create_prebuilt(ib_table, table->s->stored_rec_length);
- prebuilt->mysql_row_len = table->s->stored_rec_length;;
prebuilt->default_rec = table->s->default_values;
ut_ad(prebuilt->default_rec);
@@ -4656,7 +4811,13 @@ ha_innobase::close(void)
row_prebuilt_free(prebuilt, FALSE);
- my_free(upd_buff);
+ if (upd_buf != NULL) {
+ ut_ad(upd_buf_size != 0);
+ my_free(upd_buf);
+ upd_buf = NULL;
+ upd_buf_size = 0;
+ }
+
free_share(share);
/* Tell InnoDB server that there might be work for
@@ -6576,6 +6737,23 @@ ha_innobase::update_row(
ut_a(prebuilt->trx == trx);
+ if (upd_buf == NULL) {
+ ut_ad(upd_buf_size == 0);
+
+ /* Create a buffer for packing the fields of a record. Why
+ table->stored_rec_length did not work here? Obviously, because char
+ fields when packed actually became 1 byte longer, when we also
+ stored the string length as the first byte. */
+
+ upd_buf_size = table->s->stored_rec_length + table->s->max_key_length
+ + MAX_REF_PARTS * 3;
+ upd_buf = (uchar*) my_malloc(upd_buf_size, MYF(MY_WME));
+ if (upd_buf == NULL) {
+ upd_buf_size = 0;
+ DBUG_RETURN(HA_ERR_OUT_OF_MEM);
+ }
+ }
+
ha_statistic_increment(&SSV::ha_update_count);
if (share->ib_table->is_corrupt) {
@@ -6592,11 +6770,10 @@ ha_innobase::update_row(
}
/* Build an update vector from the modified fields in the rows
- (uses upd_buff of the handle) */
+ (uses upd_buf of the handle) */
calc_row_difference(uvect, (uchar*) old_row, new_row, table,
- upd_buff, (ulint)upd_and_key_val_buff_len,
- prebuilt, user_thd);
+ upd_buf, upd_buf_size, prebuilt, user_thd);
/* This is not a delete */
prebuilt->upd_node->is_delete = FALSE;
@@ -6993,6 +7170,7 @@ ha_innobase::index_read(
DBUG_ENTER("index_read");
ut_a(prebuilt->trx == thd_to_trx(user_thd));
+ ut_ad(key_len != 0 || find_flag != HA_READ_KEY_EXACT);
ha_statistic_increment(&SSV::ha_read_key_count);
@@ -7025,8 +7203,7 @@ ha_innobase::index_read(
row_sel_convert_mysql_key_to_innobase(
prebuilt->search_tuple,
- (byte*) key_val_buff,
- (ulint)upd_and_key_val_buff_len,
+ srch_key_val1, sizeof(srch_key_val1),
index,
(byte*) key_ptr,
(ulint) key_len,
@@ -7580,13 +7757,15 @@ wsrep_append_foreign_key(
/*===========================*/
trx_t* trx, /*!< in: trx */
dict_foreign_t* foreign, /*!< in: foreign key constraint */
- const rec_t* clust_rec, /*!<in: clustered index record */
- dict_index_t* clust_index, /*!<in: clustered index */
+ const rec_t* rec, /*!<in: clustered index record */
+ dict_index_t* index, /*!<in: clustered index */
+ ibool referenced, /*!<in: is check for referenced table */
ibool shared) /*!<in: is shared access */
{
THD* thd = (THD*)trx->mysql_thd;
ulint rcode = DB_SUCCESS;
char cache_key[512] = {'\0'};
+ int cache_key_len;
if (!wsrep_on(trx->mysql_thd) ||
wsrep_thd_exec_mode(thd) != LOCAL_STATE)
@@ -7595,39 +7774,55 @@ wsrep_append_foreign_key(
byte key[WSREP_MAX_SUPPORTED_KEY_LENGTH+1];
ulint len = WSREP_MAX_SUPPORTED_KEY_LENGTH;
- key[0] = '\0';
+ dict_index_t *idx_target = (referenced) ?
+ foreign->referenced_index : foreign->foreign_index;
+ dict_index_t *idx = (referenced) ?
+ UT_LIST_GET_FIRST(foreign->referenced_table->indexes) :
+ UT_LIST_GET_FIRST(foreign->foreign_table->indexes);
+ int i = 0;
+ while (idx != NULL && idx != idx_target) {
+ idx = UT_LIST_GET_NEXT(indexes, idx);
+ i++;
+ }
+ ut_a(idx);
+ key[0] = (char)i;
+
rcode = wsrep_rec_get_primary_key(
- &key[1], &len, clust_rec, clust_index,
+ &key[1], &len, rec, index,
wsrep_protocol_version > 1);
if (rcode != DB_SUCCESS) {
WSREP_ERROR("FK key set failed: %lu", rcode);
return rcode;
}
+ strncpy(cache_key,
+ (wsrep_protocol_version > 1) ?
+ ((referenced) ?
+ foreign->referenced_table->name :
+ foreign->foreign_table->name) :
+ foreign->foreign_table->name, 512);
+ cache_key_len = strlen(cache_key);
#ifdef WSREP_DEBUG_PRINT
- ulint i;
- fprintf(stderr, "FK parent key, table: %s shared: %d len: %lu ",
- foreign->referenced_table_name, (int)shared, len+1);
- for (i=0; i<len+1; i++) {
- fprintf(stderr, " %hhX, ", key[i]);
+ ulint j;
+ fprintf(stderr, "FK parent key, table: %s %s len: %lu ",
+ cache_key, (shared) ? "shared" : "exclusive", len+1);
+ for (j=0; j<len+1; j++) {
+ fprintf(stderr, " %hhX, ", key[j]);
}
fprintf(stderr, "\n");
#endif
- strncpy(cache_key, (wsrep_protocol_version > 1) ?
- foreign->referenced_table->name :
- foreign->foreign_table->name, 512);
char *p = strchr(cache_key, '/');
if (p) {
*p = '\0';
} else {
- WSREP_WARN("unexpected foreign key table %s",
- foreign->foreign_table->name);
+ WSREP_WARN("unexpected foreign key table %s %s",
+ foreign->referenced_table->name, foreign->foreign_table->name);
}
wsrep_key_part_t wkey_part[3];
wsrep_key_t wkey = {wkey_part, 3};
if (!wsrep_prepare_key_for_innodb(
(const uchar*)cache_key,
- strlen(foreign->foreign_table->name) + 1,
+ cache_key_len + 1,
(const uchar*)key, len+1,
wkey_part,
&wkey.key_parts_len)) {
@@ -7706,6 +7901,23 @@ wsrep_append_key(
}
DBUG_RETURN(0);
}
+
+ibool
+wsrep_is_cascding_foreign_key_parent(
+ dict_table_t* table, /*!< in: InnoDB table */
+ dict_index_t* index /*!< in: InnoDB index */
+) {
+ // return referenced_by_foreign_key();
+ dict_foreign_t* fk = dict_table_get_referenced_constraint(table, index);
+ if (fk &&
+ (fk->type & DICT_FOREIGN_ON_UPDATE_CASCADE ||
+ fk->type & DICT_FOREIGN_ON_UPDATE_SET_NULL)
+ ) {
+ return TRUE;
+ }
+ return FALSE;
+}
+
int
ha_innobase::wsrep_append_keys(
/*==================*/
@@ -7774,7 +7986,9 @@ ha_innobase::wsrep_append_keys(
keyval0[0] = (char)i;
keyval1[0] = (char)i;
- if (key_info->flags & HA_NOSAME) {
+ if (key_info->flags & HA_NOSAME ||
+ referenced_by_foreign_key()) {
+
len = wsrep_store_key_val_for_row(
table, i, key0, key_info->key_length,
record0, &is_null);
@@ -8429,6 +8643,8 @@ ha_innobase::create(
DBUG_RETURN(HA_ERR_TO_BIG_ROW);
}
+ ut_a(strlen(name) < sizeof(name2));
+
strcpy(name2, name);
normalize_table_name(norm_name, name2);
@@ -8872,6 +9088,11 @@ ha_innobase::delete_table(
DBUG_ENTER("ha_innobase::delete_table");
+ DBUG_EXECUTE_IF(
+ "test_normalize_table_name_low",
+ test_normalize_table_name_low();
+ );
+
/* Strangely, MySQL passes the table name without the '.frm'
extension, in contrast to ::create */
normalize_table_name(norm_name, name);
@@ -9033,6 +9254,8 @@ innobase_rename_table(
normalize_table_name(norm_to, to);
normalize_table_name(norm_from, from);
+ DEBUG_SYNC_C("innodb_rename_table_ready");
+
/* Serialize data dictionary operations with dictionary mutex:
no deadlocks can occur then in these operations */
@@ -9151,12 +9374,6 @@ ha_innobase::records_in_range(
{
KEY* key;
dict_index_t* index;
- uchar* key_val_buff2 = (uchar*) my_malloc(
- table->s->stored_rec_length
- + table->s->max_key_length + 100,
- MYF(MY_FAE));
- ulint buff2_len = table->s->stored_rec_length
- + table->s->max_key_length + 100;
dtuple_t* range_start;
dtuple_t* range_end;
ib_int64_t n_rows;
@@ -9213,8 +9430,8 @@ ha_innobase::records_in_range(
dict_index_copy_types(range_end, index, key_parts);
row_sel_convert_mysql_key_to_innobase(
- range_start, (byte*) key_val_buff,
- (ulint)upd_and_key_val_buff_len,
+ range_start,
+ srch_key_val1, sizeof(srch_key_val1),
index,
(byte*) (min_key ? min_key->key :
(const uchar*) 0),
@@ -9225,8 +9442,9 @@ ha_innobase::records_in_range(
: range_start->n_fields == 0);
row_sel_convert_mysql_key_to_innobase(
- range_end, (byte*) key_val_buff2,
- buff2_len, index,
+ range_end,
+ srch_key_val2, sizeof(srch_key_val2),
+ index,
(byte*) (max_key ? max_key->key :
(const uchar*) 0),
(ulint) (max_key ? max_key->length : 0),
@@ -9253,7 +9471,6 @@ ha_innobase::records_in_range(
mem_heap_free(heap);
func_exit:
- my_free(key_val_buff2);
prebuilt->trx->op_info = (char*)"";
@@ -13373,6 +13590,13 @@ static MYSQL_SYSVAR_BOOL(use_sys_stats_table, innobase_use_sys_stats_table,
"So you should use ANALYZE TABLE command intentionally.",
NULL, NULL, FALSE);
+#ifdef UNIV_DEBUG_never
+static MYSQL_SYSVAR_ULONG(sys_stats_root_page, innobase_sys_stats_root_page,
+ PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
+ "Override the SYS_STATS root page id, 0 = no override (for testing only)",
+ NULL, NULL, 0, 0, ULONG_MAX, 0);
+#endif
+
static MYSQL_SYSVAR_BOOL(adaptive_hash_index, btr_search_enabled,
PLUGIN_VAR_OPCMDARG,
"Enable InnoDB adaptive hash index (enabled by default). "
@@ -13623,6 +13847,13 @@ static MYSQL_SYSVAR_ULONG(read_ahead_threshold, srv_read_ahead_threshold,
"trigger a readahead.",
NULL, NULL, 56, 0, 64, 0);
+#ifdef UNIV_DEBUG_never
+static MYSQL_SYSVAR_UINT(trx_rseg_n_slots_debug, trx_rseg_n_slots_debug,
+ PLUGIN_VAR_RQCMDARG,
+ "Debug flags for InnoDB to limit TRX_RSEG_N_SLOTS for trx_rsegf_undo_find_free()",
+ NULL, NULL, 0, 0, 1024, 0);
+#endif /* UNIV_DEBUG */
+
static MYSQL_SYSVAR_LONGLONG(ibuf_max_size, srv_ibuf_max_size,
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
"The maximum size of the insert buffer. (in bytes)",
@@ -13744,14 +13975,6 @@ static MYSQL_SYSVAR_ENUM(adaptive_flushing_method, srv_adaptive_flushing_method,
"Choose method of innodb_adaptive_flushing. (native, [estimate], keep_average)",
NULL, innodb_adaptive_flushing_method_update, 1, &adaptive_flushing_method_typelib);
-#ifdef UNIV_DEBUG
-static MYSQL_SYSVAR_ULONG(flush_checkpoint_debug, srv_flush_checkpoint_debug,
- PLUGIN_VAR_RQCMDARG,
- "Debug flags for InnoDB flushing and checkpointing (0=none,"
- "1=stop preflush and checkpointing)",
- NULL, NULL, 0, 0, 1, 0);
-#endif
-
static MYSQL_SYSVAR_ULONG(import_table_from_xtrabackup, srv_expand_import,
PLUGIN_VAR_RQCMDARG,
"Enable/Disable converting automatically *.ibd files when import tablespace.",
@@ -13857,6 +14080,9 @@ static struct st_mysql_sys_var* innobase_system_variables[]= {
MYSQL_SYSVAR(stats_auto_update),
MYSQL_SYSVAR(stats_update_need_lock),
MYSQL_SYSVAR(use_sys_stats_table),
+#ifdef UNIV_DEBUG_never /* disable this flag. --innodb-sys-stats becomes ambiguous */
+ MYSQL_SYSVAR(sys_stats_root_page),
+#endif
MYSQL_SYSVAR(stats_sample_pages),
MYSQL_SYSVAR(adaptive_hash_index),
MYSQL_SYSVAR(adaptive_hash_index_partitions),
@@ -13901,9 +14127,9 @@ static struct st_mysql_sys_var* innobase_system_variables[]= {
MYSQL_SYSVAR(purge_threads),
MYSQL_SYSVAR(purge_batch_size),
MYSQL_SYSVAR(rollback_segments),
-#ifdef UNIV_DEBUG
- MYSQL_SYSVAR(flush_checkpoint_debug),
-#endif
+#ifdef UNIV_DEBUG_never /* disable this flag. --innodb-trx becomes ambiguous */
+ MYSQL_SYSVAR(trx_rseg_n_slots_debug),
+#endif /* UNIV_DEBUG */
MYSQL_SYSVAR(corrupt_table_action),
MYSQL_SYSVAR(lazy_drop_table),
MYSQL_SYSVAR(fake_changes),
diff --git a/storage/xtradb/handler/ha_innodb.h b/storage/xtradb/handler/ha_innodb.h
index 5d0b4f75a3f..397faa725c0 100644
--- a/storage/xtradb/handler/ha_innodb.h
+++ b/storage/xtradb/handler/ha_innodb.h
@@ -79,13 +79,14 @@ class ha_innobase: public handler
INNOBASE_SHARE* share; /*!< information for MySQL
table locking */
- uchar* upd_buff; /*!< buffer used in updates */
- uchar* key_val_buff; /*!< buffer used in converting
+ uchar* upd_buf; /*!< buffer used in updates */
+ ulint upd_buf_size; /*!< the size of upd_buf in bytes */
+ uchar srch_key_val1[REC_VERSION_56_MAX_INDEX_COL_LEN + 2];
+ uchar srch_key_val2[REC_VERSION_56_MAX_INDEX_COL_LEN + 2];
+ /*!< buffers 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 */
+ to InnoDB format. "+ 2" for the two
+ bytes where the length is stored */
Table_flags int_table_flags;
uint primary_key;
ulong start_of_scan; /*!< this is set to 1 when we are
diff --git a/storage/xtradb/handler/handler0alter.cc b/storage/xtradb/handler/handler0alter.cc
index e20e4797dd5..b2aaf31df03 100644
--- a/storage/xtradb/handler/handler0alter.cc
+++ b/storage/xtradb/handler/handler0alter.cc
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 2005, 2010, Innobase Oy. All Rights Reserved.
+Copyright (c) 2005, 2012, Oracle and/or its affiliates. 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
@@ -11,8 +11,8 @@ 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 program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
*****************************************************************************/
@@ -882,6 +882,8 @@ ha_innobase::add_index(
prebuilt->table, indexed_table,
index, num_of_idx, table);
+ DBUG_EXECUTE_IF("crash_innodb_add_index_after", DBUG_SUICIDE(););
+
error_handling:
/* After an error, remove all those index definitions from the
dictionary which were defined. */
@@ -1024,7 +1026,12 @@ ha_innobase::final_add_index(
row_prebuilt_free(prebuilt, TRUE);
error = row_merge_drop_table(trx, old_table);
add->indexed_table->n_mysql_handles_opened++;
- prebuilt = row_create_prebuilt(add->indexed_table);
+ prebuilt = row_create_prebuilt(add->indexed_table,
+ 0 /* XXX Do we know the mysql_row_len here?
+ Before the addition of this parameter to
+ row_create_prebuilt() the mysql_row_len
+ member was left 0 (from zalloc) in the
+ prebuilt object. */);
}
err = convert_error_code_to_mysql(
@@ -1158,7 +1165,9 @@ ha_innobase::prepare_drop_index(
goto func_exit;
}
+ rw_lock_x_lock(dict_index_get_lock(index));
index->to_be_dropped = TRUE;
+ rw_lock_x_unlock(dict_index_get_lock(index));
}
/* If FOREIGN_KEY_CHECKS = 1 you may not drop an index defined
@@ -1277,7 +1286,9 @@ func_exit:
= dict_table_get_first_index(prebuilt->table);
do {
+ rw_lock_x_lock(dict_index_get_lock(index));
index->to_be_dropped = FALSE;
+ rw_lock_x_unlock(dict_index_get_lock(index));
index = dict_table_get_next_index(index);
} while (index);
}
@@ -1343,7 +1354,9 @@ ha_innobase::final_drop_index(
for (index = dict_table_get_first_index(prebuilt->table);
index; index = dict_table_get_next_index(index)) {
+ rw_lock_x_lock(dict_index_get_lock(index));
index->to_be_dropped = FALSE;
+ rw_lock_x_unlock(dict_index_get_lock(index));
}
goto func_exit;
diff --git a/storage/xtradb/ibuf/ibuf0ibuf.c b/storage/xtradb/ibuf/ibuf0ibuf.c
index 00b7ea7347d..562f207268a 100644
--- a/storage/xtradb/ibuf/ibuf0ibuf.c
+++ b/storage/xtradb/ibuf/ibuf0ibuf.c
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1997, 2011, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1997, 2012, Oracle and/or its affiliates. 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
@@ -11,8 +11,8 @@ 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 program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
*****************************************************************************/
@@ -1523,7 +1523,7 @@ ibuf_add_ops(
for (i = 0; i < IBUF_OP_COUNT; i++) {
#ifdef HAVE_ATOMIC_BUILTINS
- os_atomic_increment_ulint(&arr[i], ops[i]);
+ (void) os_atomic_increment_ulint(&arr[i], ops[i]);
#else /* HAVE_ATOMIC_BUILTINS */
arr[i] += ops[i];
#endif /* HAVE_ATOMIC_BUILTINS */
@@ -2222,14 +2222,14 @@ ibool
ibuf_add_free_page(void)
/*====================*/
{
- mtr_t mtr;
- page_t* header_page;
- ulint flags;
- ulint zip_size;
- ulint page_no;
- page_t* page;
- page_t* root;
- page_t* bitmap_page;
+ mtr_t mtr;
+ page_t* header_page;
+ ulint flags;
+ ulint zip_size;
+ buf_block_t* block;
+ page_t* page;
+ page_t* root;
+ page_t* bitmap_page;
mtr_start(&mtr);
@@ -2250,28 +2250,23 @@ ibuf_add_free_page(void)
of a deadlock. This is the reason why we created a special ibuf
header page apart from the ibuf tree. */
- page_no = fseg_alloc_free_page(
+ block = fseg_alloc_free_page(
header_page + IBUF_HEADER + IBUF_TREE_SEG_HEADER, 0, FSP_UP,
&mtr);
- if (UNIV_UNLIKELY(page_no == FIL_NULL)) {
+ if (block == NULL) {
mtr_commit(&mtr);
return(FALSE);
- } else {
- buf_block_t* block = buf_page_get(
- IBUF_SPACE_ID, 0, page_no, RW_X_LATCH, &mtr);
-
- ibuf_enter(&mtr);
-
- mutex_enter(&ibuf_mutex);
-
- root = ibuf_tree_root_get(&mtr);
+ }
- buf_block_dbg_add_level(block, SYNC_IBUF_TREE_NODE_NEW);
+ ut_ad(rw_lock_get_x_lock_count(&block->lock) == 1);
+ ibuf_enter(&mtr);
+ mutex_enter(&ibuf_mutex);
+ root = ibuf_tree_root_get(&mtr);
- page = buf_block_get_frame(block);
- }
+ buf_block_dbg_add_level(block, SYNC_IBUF_TREE_NODE_NEW);
+ page = buf_block_get_frame(block);
/* Add the page to the free list and update the ibuf size data */
@@ -2288,12 +2283,13 @@ ibuf_add_free_page(void)
(level 2 page) */
bitmap_page = ibuf_bitmap_get_map_page(
- IBUF_SPACE_ID, page_no, zip_size, &mtr);
+ IBUF_SPACE_ID, buf_block_get_page_no(block), zip_size, &mtr);
mutex_exit(&ibuf_mutex);
ibuf_bitmap_page_set_bits(
- bitmap_page, page_no, zip_size, IBUF_BITMAP_IBUF, TRUE, &mtr);
+ bitmap_page, buf_block_get_page_no(block), zip_size,
+ IBUF_BITMAP_IBUF, TRUE, &mtr);
ibuf_mtr_commit(&mtr);
@@ -2588,7 +2584,15 @@ ibuf_get_merge_page_nos_func(
} else {
rec_page_no = ibuf_rec_get_page_no(mtr, rec);
rec_space_id = ibuf_rec_get_space(mtr, rec);
- ut_ad(rec_page_no > IBUF_TREE_ROOT_PAGE_NO);
+ /* In the system tablespace, the smallest
+ possible secondary index leaf page number is
+ bigger than IBUF_TREE_ROOT_PAGE_NO (4). In
+ other tablespaces, the clustered index tree is
+ created at page 3, which makes page 4 the
+ smallest possible secondary index leaf page
+ (and that only after DROP INDEX). */
+ ut_ad(rec_page_no
+ > IBUF_TREE_ROOT_PAGE_NO - (rec_space_id != 0));
}
#ifdef UNIV_IBUF_DEBUG
@@ -3920,6 +3924,7 @@ ibuf_insert_to_index_page_low(
fputs("InnoDB: Submit a detailed bug report"
" to http://bugs.mysql.com\n", stderr);
+ ut_ad(0);
}
/************************************************************************
@@ -3970,9 +3975,10 @@ ibuf_insert_to_index_page(
"InnoDB: but the number of fields does not match!\n",
stderr);
dump:
- buf_page_print(page, 0);
+ buf_page_print(page, 0, BUF_PAGE_PRINT_NO_CRASH);
dtuple_print(stderr, entry);
+ ut_ad(0);
fputs("InnoDB: The table where where"
" this index record belongs\n"
@@ -4113,6 +4119,11 @@ ibuf_set_del_mark(
TRUE, mtr);
}
} else {
+ const page_t* page
+ = page_cur_get_page(&page_cur);
+ const buf_block_t* block
+ = page_cur_get_block(&page_cur);
+
ut_print_timestamp(stderr);
fputs(" InnoDB: unable to find a record to delete-mark\n",
stderr);
@@ -4121,10 +4132,14 @@ ibuf_set_del_mark(
fputs("\n"
"InnoDB: record ", stderr);
rec_print(stderr, page_cur_get_rec(&page_cur), index);
- putc('\n', stderr);
- fputs("\n"
- "InnoDB: Submit a detailed bug report"
- " to http://bugs.mysql.com\n", stderr);
+ fprintf(stderr, "\nspace %u offset %u"
+ " (%u records, index id %llu)\n"
+ "InnoDB: Submit a detailed bug report"
+ " to http://bugs.mysql.com\n",
+ (unsigned) buf_block_get_space(block),
+ (unsigned) buf_block_get_page_no(block),
+ (unsigned) page_get_n_recs(page),
+ (ulonglong) btr_page_get_index_id(page));
ut_ad(0);
}
}
@@ -4168,12 +4183,31 @@ ibuf_delete(
offsets = rec_get_offsets(
rec, index, offsets, ULINT_UNDEFINED, &heap);
- /* Refuse to delete the last record. */
- ut_a(page_get_n_recs(page) > 1);
-
- /* The record should have been marked for deletion. */
- ut_ad(REC_INFO_DELETED_FLAG
- & rec_get_info_bits(rec, page_is_comp(page)));
+ if (page_get_n_recs(page) <= 1
+ || !(REC_INFO_DELETED_FLAG
+ & rec_get_info_bits(rec, page_is_comp(page)))) {
+ /* Refuse to purge the last record or a
+ record that has not been marked for deletion. */
+ ut_print_timestamp(stderr);
+ fputs(" InnoDB: unable to purge a record\n",
+ stderr);
+ fputs("InnoDB: tuple ", stderr);
+ dtuple_print(stderr, entry);
+ fputs("\n"
+ "InnoDB: record ", stderr);
+ rec_print_new(stderr, rec, offsets);
+ fprintf(stderr, "\nspace %u offset %u"
+ " (%u records, index id %llu)\n"
+ "InnoDB: Submit a detailed bug report"
+ " to http://bugs.mysql.com\n",
+ (unsigned) buf_block_get_space(block),
+ (unsigned) buf_block_get_page_no(block),
+ (unsigned) page_get_n_recs(page),
+ (ulonglong) btr_page_get_index_id(page));
+
+ ut_ad(0);
+ return;
+ }
lock_update_delete(block, rec);
@@ -4259,6 +4293,7 @@ ibuf_restore_pos(
fprintf(stderr, "InnoDB: ibuf tree ok\n");
fflush(stderr);
+ ut_ad(0);
}
return(FALSE);
@@ -4441,7 +4476,7 @@ ibuf_merge_or_delete_for_page(
function. When the counter is > 0, that prevents tablespace
from being dropped. */
- tablespace_being_deleted = fil_inc_pending_ibuf_merges(space);
+ tablespace_being_deleted = fil_inc_pending_ops(space);
if (UNIV_UNLIKELY(tablespace_being_deleted)) {
/* Do not try to read the bitmap page from space;
@@ -4467,7 +4502,7 @@ ibuf_merge_or_delete_for_page(
/* No inserts buffered for this page */
if (!tablespace_being_deleted) {
- fil_decr_pending_ibuf_merges(space);
+ fil_decr_pending_ops(space);
}
return;
@@ -4516,12 +4551,14 @@ ibuf_merge_or_delete_for_page(
bitmap_page = ibuf_bitmap_get_map_page(space, page_no,
zip_size, &mtr);
- buf_page_print(bitmap_page, 0);
+ buf_page_print(bitmap_page, 0,
+ BUF_PAGE_PRINT_NO_CRASH);
ibuf_mtr_commit(&mtr);
fputs("\nInnoDB: Dump of the page:\n", stderr);
- buf_page_print(block->frame, 0);
+ buf_page_print(block->frame, 0,
+ BUF_PAGE_PRINT_NO_CRASH);
fprintf(stderr,
"InnoDB: Error: corruption in the tablespace."
@@ -4541,6 +4578,7 @@ ibuf_merge_or_delete_for_page(
(ulong) page_no,
(ulong)
fil_page_get_type(block->frame));
+ ut_ad(0);
}
}
@@ -4747,7 +4785,7 @@ reset_bit:
mem_heap_free(heap);
#ifdef HAVE_ATOMIC_BUILTINS
- os_atomic_increment_ulint(&ibuf->n_merges, 1);
+ (void) os_atomic_increment_ulint(&ibuf->n_merges, 1);
ibuf_add_ops(ibuf->n_merged_ops, mops);
ibuf_add_ops(ibuf->n_discarded_ops, dops);
#else /* HAVE_ATOMIC_BUILTINS */
@@ -4763,7 +4801,7 @@ reset_bit:
if (update_ibuf_bitmap && !tablespace_being_deleted) {
- fil_decr_pending_ibuf_merges(space);
+ fil_decr_pending_ops(space);
}
#ifdef UNIV_IBUF_COUNT_DEBUG
diff --git a/storage/xtradb/include/btr0btr.h b/storage/xtradb/include/btr0btr.h
index 058fcfb64de..520527d0375 100644
--- a/storage/xtradb/include/btr0btr.h
+++ b/storage/xtradb/include/btr0btr.h
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1994, 2010, Innobase Oy. All Rights Reserved.
+Copyright (c) 1994, 2012, Oracle and/or its affiliates. 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
@@ -11,8 +11,8 @@ 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 program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
*****************************************************************************/
@@ -92,6 +92,26 @@ insert/delete buffer when the record is not in the buffer pool. */
buffer when the record is not in the buffer pool. */
#define BTR_DELETE 8192
+/**************************************************************//**
+Report that an index page is corrupted. */
+UNIV_INTERN
+void
+btr_corruption_report(
+/*==================*/
+ const buf_block_t* block, /*!< in: corrupted block */
+ const dict_index_t* index) /*!< in: index tree */
+ UNIV_COLD __attribute__((nonnull));
+
+/** Assert that a B-tree page is not corrupted.
+@param block buffer block containing a B-tree page
+@param index the B-tree index */
+#define btr_assert_not_corrupted(block, index) \
+ if ((ibool) !!page_is_comp(buf_block_get_frame(block)) \
+ != dict_table_is_comp((index)->table)) { \
+ btr_corruption_report(block, index); \
+ ut_error; \
+ }
+
#ifdef UNIV_BLOB_DEBUG
# include "ut0rbt.h"
/** An index->blobs entry for keeping track of off-page column references */
@@ -569,11 +589,14 @@ UNIV_INTERN
ibool
btr_compress(
/*=========*/
- btr_cur_t* cursor, /*!< in: cursor on the page to merge or lift;
- the page must not be empty: in record delete
- use btr_discard_page if the page would become
- empty */
- mtr_t* mtr); /*!< in: mtr */
+ btr_cur_t* cursor, /*!< in/out: cursor on the page to merge
+ or lift; the page must not be empty:
+ when deleting records, use btr_discard_page()
+ if the page would become empty */
+ ibool adjust, /*!< in: TRUE if should adjust the
+ cursor position even if compression occurs */
+ mtr_t* mtr) /*!< in/out: mini-transaction */
+ __attribute__((nonnull));
/*************************************************************//**
Discards a page from a B-tree. This is used to remove the last record from
a B-tree page: the whole page must be removed at the same time. This cannot
@@ -614,17 +637,23 @@ btr_parse_page_reorganize(
#ifndef UNIV_HOTBACKUP
/**************************************************************//**
Gets the number of pages in a B-tree.
-@return number of pages */
+@return number of pages, or ULINT_UNDEFINED if the index is unavailable */
UNIV_INTERN
ulint
btr_get_size(
/*=========*/
dict_index_t* index, /*!< in: index */
- ulint flag); /*!< in: BTR_N_LEAF_PAGES or BTR_TOTAL_SIZE */
+ ulint flag, /*!< in: BTR_N_LEAF_PAGES or BTR_TOTAL_SIZE */
+ mtr_t* mtr) /*!< in/out: mini-transaction where index
+ is s-latched */
+ __attribute__((nonnull, warn_unused_result));
/**************************************************************//**
Allocates a new file page to be used in an index tree. NOTE: we assume
that the caller has made the reservation for free extents!
-@return new allocated block, x-latched; NULL if out of space */
+@retval NULL if no page could be allocated
+@retval block, rw_lock_x_lock_count(&block->lock) == 1 if allocation succeeded
+(init_mtr == mtr, or the page was not previously freed in mtr)
+@retval block (not allocated or initialized) otherwise */
UNIV_INTERN
buf_block_t*
btr_page_alloc(
@@ -635,7 +664,12 @@ btr_page_alloc(
page split is made */
ulint level, /*!< in: level where the page is placed
in the tree */
- mtr_t* mtr); /*!< in: mtr */
+ mtr_t* mtr, /*!< in/out: mini-transaction
+ for the allocation */
+ mtr_t* init_mtr) /*!< in/out: mini-transaction
+ for x-latching and initializing
+ the page */
+ __attribute__((nonnull, warn_unused_result));
/**************************************************************//**
Frees a file page used in an index tree. NOTE: cannot free field external
storage pages because the page must contain info on its level. */
diff --git a/storage/xtradb/include/btr0btr.ic b/storage/xtradb/include/btr0btr.ic
index f446ecb69d3..53c8159c448 100644
--- a/storage/xtradb/include/btr0btr.ic
+++ b/storage/xtradb/include/btr0btr.ic
@@ -279,7 +279,7 @@ btr_node_ptr_get_child_page_no(
"InnoDB: a nonsensical page number 0"
" in a node ptr record at offset %lu\n",
(ulong) page_offset(rec));
- buf_page_print(page_align(rec), 0);
+ buf_page_print(page_align(rec), 0, 0);
}
return(page_no);
diff --git a/storage/xtradb/include/btr0cur.h b/storage/xtradb/include/btr0cur.h
index 4f33aacc48e..cbc6103c2ee 100644
--- a/storage/xtradb/include/btr0cur.h
+++ b/storage/xtradb/include/btr0cur.h
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1994, 2010, Innobase Oy. All Rights Reserved.
+Copyright (c) 1994, 2012, Oracle and/or its affiliates. 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
@@ -11,8 +11,8 @@ 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 program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
*****************************************************************************/
@@ -36,6 +36,9 @@ Created 10/16/1994 Heikki Tuuri
#define BTR_NO_LOCKING_FLAG 2 /* do no record lock checking */
#define BTR_KEEP_SYS_FLAG 4 /* sys fields will be found from the
update vector or inserted entry */
+#define BTR_KEEP_POS_FLAG 8 /* btr_cur_pessimistic_update()
+ must keep cursor position when
+ moving columns to big_rec */
#ifndef UNIV_HOTBACKUP
#include "que0types.h"
@@ -310,7 +313,9 @@ btr_cur_pessimistic_update(
/*=======================*/
ulint flags, /*!< in: undo logging, locking, and rollback
flags */
- btr_cur_t* cursor, /*!< in: cursor on the record to update */
+ btr_cur_t* cursor, /*!< in/out: cursor on the record to update;
+ cursor may become invalid if *big_rec == NULL
+ || !(flags & BTR_KEEP_POS_FLAG) */
mem_heap_t** heap, /*!< in/out: pointer to memory heap, or NULL */
big_rec_t** big_rec,/*!< out: big rec vector whose fields have to
be stored externally by the caller, or NULL */
@@ -364,10 +369,13 @@ UNIV_INTERN
ibool
btr_cur_compress_if_useful(
/*=======================*/
- btr_cur_t* cursor, /*!< in: cursor on the page to compress;
+ btr_cur_t* cursor, /*!< in/out: cursor on the page to compress;
cursor does not stay valid if compression
occurs */
- mtr_t* mtr); /*!< in: mtr */
+ ibool adjust, /*!< in: TRUE if should adjust the
+ cursor position even if compression occurs */
+ mtr_t* mtr) /*!< in/out: mini-transaction */
+ __attribute__((nonnull));
/*******************************************************//**
Removes the record on which the tree cursor is positioned. It is assumed
that the mtr has an x-latch on the page where the cursor is positioned,
@@ -492,6 +500,27 @@ btr_cur_disown_inherited_fields(
const upd_t* update, /*!< in: update vector */
mtr_t* mtr) /*!< in/out: mini-transaction */
__attribute__((nonnull(2,3,4,5,6)));
+
+/** Operation code for btr_store_big_rec_extern_fields(). */
+enum blob_op {
+ /** Store off-page columns for a freshly inserted record */
+ BTR_STORE_INSERT = 0,
+ /** Store off-page columns for an insert by update */
+ BTR_STORE_INSERT_UPDATE,
+ /** Store off-page columns for an update */
+ BTR_STORE_UPDATE
+};
+
+/*******************************************************************//**
+Determine if an operation on off-page columns is an update.
+@return TRUE if op != BTR_STORE_INSERT */
+UNIV_INLINE
+ibool
+btr_blob_op_is_update(
+/*==================*/
+ enum blob_op op) /*!< in: operation */
+ __attribute__((warn_unused_result));
+
/*******************************************************************//**
Stores the fields in big_rec_vec to the tablespace and puts pointers to
them in rec. The extern flags in rec will have to be set beforehand.
@@ -499,52 +528,23 @@ The fields are stored on pages allocated from leaf node
file segment of the index tree.
@return DB_SUCCESS or DB_OUT_OF_FILE_SPACE */
UNIV_INTERN
-ulint
-btr_store_big_rec_extern_fields_func(
-/*=================================*/
+enum db_err
+btr_store_big_rec_extern_fields(
+/*============================*/
dict_index_t* index, /*!< in: index of rec; the index tree
MUST be X-latched */
buf_block_t* rec_block, /*!< in/out: block containing rec */
- rec_t* rec, /*!< in: record */
+ rec_t* rec, /*!< in/out: record */
const ulint* offsets, /*!< in: rec_get_offsets(rec, index);
the "external storage" flags in offsets
will not correspond to rec when
this function returns */
-#ifdef UNIV_DEBUG
- mtr_t* local_mtr, /*!< in: mtr containing the
- latch to rec and to the tree */
-#endif /* UNIV_DEBUG */
-#if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG
- ibool update_in_place,/*! in: TRUE if the record is updated
- in place (not delete+insert) */
-#endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */
- const big_rec_t*big_rec_vec) /*!< in: vector containing fields
+ const big_rec_t*big_rec_vec, /*!< in: vector containing fields
to be stored externally */
- __attribute__((nonnull));
-
-/** Stores the fields in big_rec_vec to the tablespace and puts pointers to
-them in rec. The extern flags in rec will have to be set beforehand.
-The fields are stored on pages allocated from leaf node
-file segment of the index tree.
-@param index in: clustered index; MUST be X-latched by mtr
-@param b in/out: block containing rec; MUST be X-latched by mtr
-@param rec in/out: clustered index record
-@param offsets in: rec_get_offsets(rec, index);
- the "external storage" flags in offsets will not be adjusted
-@param mtr in: mini-transaction that holds x-latch on index and b
-@param upd in: TRUE if the record is updated in place (not delete+insert)
-@param big in: vector containing fields to be stored externally
-@return DB_SUCCESS or DB_OUT_OF_FILE_SPACE */
-#ifdef UNIV_DEBUG
-# define btr_store_big_rec_extern_fields(index,b,rec,offsets,mtr,upd,big) \
- btr_store_big_rec_extern_fields_func(index,b,rec,offsets,mtr,upd,big)
-#elif defined UNIV_BLOB_LIGHT_DEBUG
-# define btr_store_big_rec_extern_fields(index,b,rec,offsets,mtr,upd,big) \
- btr_store_big_rec_extern_fields_func(index,b,rec,offsets,upd,big)
-#else
-# define btr_store_big_rec_extern_fields(index,b,rec,offsets,mtr,upd,big) \
- btr_store_big_rec_extern_fields_func(index,b,rec,offsets,big)
-#endif
+ mtr_t* btr_mtr, /*!< in: mtr containing the
+ latches to the clustered index */
+ enum blob_op op) /*! in: operation code */
+ __attribute__((nonnull, warn_unused_result));
/*******************************************************************//**
Frees the space in an externally stored field to the file space
diff --git a/storage/xtradb/include/btr0cur.ic b/storage/xtradb/include/btr0cur.ic
index 280583f6ccf..e31f77c77eb 100644
--- a/storage/xtradb/include/btr0cur.ic
+++ b/storage/xtradb/include/btr0cur.ic
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1994, 2009, Innobase Oy. All Rights Reserved.
+Copyright (c) 1994, 2012, Oracle and/or its affiliates. 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
@@ -11,8 +11,8 @@ 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 program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
*****************************************************************************/
@@ -139,7 +139,7 @@ btr_cur_compress_recommendation(
btr_cur_t* cursor, /*!< in: btr cursor */
mtr_t* mtr) /*!< in: mtr */
{
- page_t* page;
+ const page_t* page;
ut_ad(mtr_memo_contains(mtr, btr_cur_get_block(cursor),
MTR_MEMO_PAGE_X_FIX));
@@ -197,4 +197,25 @@ btr_cur_can_delete_without_compress(
return(TRUE);
}
+
+/*******************************************************************//**
+Determine if an operation on off-page columns is an update.
+@return TRUE if op != BTR_STORE_INSERT */
+UNIV_INLINE
+ibool
+btr_blob_op_is_update(
+/*==================*/
+ enum blob_op op) /*!< in: operation */
+{
+ switch (op) {
+ case BTR_STORE_INSERT:
+ return(FALSE);
+ case BTR_STORE_INSERT_UPDATE:
+ case BTR_STORE_UPDATE:
+ return(TRUE);
+ }
+
+ ut_ad(0);
+ return(FALSE);
+}
#endif /* !UNIV_HOTBACKUP */
diff --git a/storage/xtradb/include/btr0pcur.h b/storage/xtradb/include/btr0pcur.h
index 140f94466db..2ebd70a6f23 100644
--- a/storage/xtradb/include/btr0pcur.h
+++ b/storage/xtradb/include/btr0pcur.h
@@ -53,6 +53,16 @@ UNIV_INTERN
btr_pcur_t*
btr_pcur_create_for_mysql(void);
/*============================*/
+
+/**************************************************************//**
+Resets a persistent cursor object, freeing ::old_rec_buf if it is
+allocated and resetting the other members to their initial values. */
+UNIV_INTERN
+void
+btr_pcur_reset(
+/*===========*/
+ btr_pcur_t* cursor);/*!< in, out: persistent cursor */
+
/**************************************************************//**
Frees the memory for a persistent cursor object. */
UNIV_INTERN
diff --git a/storage/xtradb/include/buf0buf.h b/storage/xtradb/include/buf0buf.h
index 0ea74fb9eb2..7502942d681 100644
--- a/storage/xtradb/include/buf0buf.h
+++ b/storage/xtradb/include/buf0buf.h
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1995, 2010, Innobase Oy. All Rights Reserved.
+Copyright (c) 1995, 2012, Oracle and/or its affiliates. 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
@@ -11,8 +11,8 @@ 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 program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
*****************************************************************************/
@@ -611,6 +611,31 @@ buf_block_get_modify_clock(
#else /* !UNIV_HOTBACKUP */
# define buf_block_modify_clock_inc(block) ((void) 0)
#endif /* !UNIV_HOTBACKUP */
+/*******************************************************************//**
+Increments the bufferfix count. */
+UNIV_INLINE
+void
+buf_block_buf_fix_inc_func(
+/*=======================*/
+#ifdef UNIV_SYNC_DEBUG
+ const char* file, /*!< in: file name */
+ ulint line, /*!< in: line */
+#endif /* UNIV_SYNC_DEBUG */
+ buf_block_t* block) /*!< in/out: block to bufferfix */
+ __attribute__((nonnull));
+#ifdef UNIV_SYNC_DEBUG
+/** Increments the bufferfix count.
+@param b in/out: block to bufferfix
+@param f in: file name where requested
+@param l in: line number where requested */
+# define buf_block_buf_fix_inc(b,f,l) buf_block_buf_fix_inc_func(f,l,b)
+#else /* UNIV_SYNC_DEBUG */
+/** Increments the bufferfix count.
+@param b in/out: block to bufferfix
+@param f in: file name where requested
+@param l in: line number where requested */
+# define buf_block_buf_fix_inc(b,f,l) buf_block_buf_fix_inc_func(b)
+#endif /* UNIV_SYNC_DEBUG */
/********************************************************************//**
Calculates a page checksum which is stored to the page when it is written
to a file. Note that we must be careful to calculate the same value
@@ -700,6 +725,13 @@ buf_print(void);
/*============*/
#endif /* UNIV_DEBUG_PRINT || UNIV_DEBUG || UNIV_BUF_DEBUG */
#endif /* !UNIV_HOTBACKUP */
+enum buf_page_print_flags {
+ /** Do not crash at the end of buf_page_print(). */
+ BUF_PAGE_PRINT_NO_CRASH = 1,
+ /** Do not print the full page dump. */
+ BUF_PAGE_PRINT_NO_FULL = 2
+};
+
/********************************************************************//**
Prints a page to stderr. */
UNIV_INTERN
@@ -707,8 +739,12 @@ void
buf_page_print(
/*===========*/
const byte* read_buf, /*!< in: a database page */
- ulint zip_size); /*!< in: compressed page size, or
+ ulint zip_size, /*!< in: compressed page size, or
0 for uncompressed pages */
+ ulint flags) /*!< in: 0 or
+ BUF_PAGE_PRINT_NO_CRASH or
+ BUF_PAGE_PRINT_NO_FULL */
+ __attribute__((nonnull));
/********************************************************************//**
Decompress a block.
@return TRUE if successful */
@@ -773,11 +809,11 @@ buf_all_freed(void);
/*********************************************************************//**
Checks that there currently are no pending i/o-operations for the buffer
pool.
-@return TRUE if there is no pending i/o */
+@return number of pending i/o operations */
UNIV_INTERN
-ibool
-buf_pool_check_no_pending_io(void);
-/*==============================*/
+ulint
+buf_pool_check_num_pending_io(void);
+/*===============================*/
/*********************************************************************//**
Invalidates the file pages in the buffer pool when an archive recovery is
completed. All the file pages buffered must be in a replaceable state when
diff --git a/storage/xtradb/include/buf0buf.ic b/storage/xtradb/include/buf0buf.ic
index 55d89b66375..66006d366c6 100644
--- a/storage/xtradb/include/buf0buf.ic
+++ b/storage/xtradb/include/buf0buf.ic
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1995, 2010, Innobase Oy. All Rights Reserved.
+Copyright (c) 1995, 2012, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2008, Google Inc.
Portions of this file contain modifications contributed and copyrighted by
@@ -18,8 +18,8 @@ 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 program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
*****************************************************************************/
@@ -1026,19 +1026,6 @@ buf_block_buf_fix_inc_func(
block->page.buf_fix_count++;
}
-#ifdef UNIV_SYNC_DEBUG
-/** Increments the bufferfix count.
-@param b in/out: block to bufferfix
-@param f in: file name where requested
-@param l in: line number where requested */
-# define buf_block_buf_fix_inc(b,f,l) buf_block_buf_fix_inc_func(f,l,b)
-#else /* UNIV_SYNC_DEBUG */
-/** Increments the bufferfix count.
-@param b in/out: block to bufferfix
-@param f in: file name where requested
-@param l in: line number where requested */
-# define buf_block_buf_fix_inc(b,f,l) buf_block_buf_fix_inc_func(b)
-#endif /* UNIV_SYNC_DEBUG */
/*******************************************************************//**
Decrements the bufferfix count. */
@@ -1295,7 +1282,7 @@ buf_block_dbg_add_level(
where we have acquired latch */
ulint level) /*!< in: latching order level */
{
- sync_thread_add_level(&block->lock, level);
+ sync_thread_add_level(&block->lock, level, FALSE);
}
#endif /* UNIV_SYNC_DEBUG */
/********************************************************************//**
diff --git a/storage/xtradb/include/buf0lru.h b/storage/xtradb/include/buf0lru.h
index 700136ec488..c3672a65ed7 100644
--- a/storage/xtradb/include/buf0lru.h
+++ b/storage/xtradb/include/buf0lru.h
@@ -64,15 +64,14 @@ These are low-level functions
#define BUF_LRU_FREE_SEARCH_LEN(b) (5 + 2 * BUF_READ_AHEAD_AREA(b))
/******************************************************************//**
-Invalidates all pages belonging to a given tablespace when we are deleting
-the data file(s) of that tablespace. A PROBLEM: if readahead is being started,
-what guarantees that it will not try to read in pages after this operation has
-completed? */
+Removes all pages belonging to a given tablespace. */
UNIV_INTERN
void
-buf_LRU_invalidate_tablespace(
+buf_LRU_flush_or_remove_pages(
/*==========================*/
- ulint id); /*!< in: space id */
+ ulint id, /*!< in: space id */
+ enum buf_remove_t buf_remove);/*!< in: remove or flush
+ strategy */
/******************************************************************//**
*/
diff --git a/storage/xtradb/include/buf0types.h b/storage/xtradb/include/buf0types.h
index d140936a886..a6e947dc21a 100644
--- a/storage/xtradb/include/buf0types.h
+++ b/storage/xtradb/include/buf0types.h
@@ -63,6 +63,15 @@ enum buf_io_fix {
the flush_list */
};
+/** Algorithm to remove the pages for a tablespace from the buffer pool.
+@See buf_LRU_flush_or_remove_pages(). */
+enum buf_remove_t {
+ BUF_REMOVE_ALL_NO_WRITE, /*!< Remove all pages from the buffer
+ pool, don't write or sync to disk */
+ BUF_REMOVE_FLUSH_NO_WRITE /*!< Remove only, from the flush list,
+ don't write or sync to disk */
+};
+
/** Parameters of binary buddy system for compressed pages (buf0buddy.h) */
/* @{ */
#define BUF_BUDDY_LOW_SHIFT PAGE_ZIP_MIN_SIZE_SHIFT
diff --git a/storage/xtradb/include/data0data.h b/storage/xtradb/include/data0data.h
index f7bdd29ed90..6d3c2988fdc 100644
--- a/storage/xtradb/include/data0data.h
+++ b/storage/xtradb/include/data0data.h
@@ -231,6 +231,26 @@ dtuple_set_n_fields_cmp(
dtuple_t* tuple, /*!< in: tuple */
ulint n_fields_cmp); /*!< in: number of fields used in
comparisons in rem0cmp.* */
+
+/* Estimate the number of bytes that are going to be allocated when
+creating a new dtuple_t object */
+#define DTUPLE_EST_ALLOC(n_fields) \
+ (sizeof(dtuple_t) + (n_fields) * sizeof(dfield_t))
+
+/**********************************************************//**
+Creates a data tuple from an already allocated chunk of memory.
+The size of the chunk must be at least DTUPLE_EST_ALLOC(n_fields).
+The default value for number of fields used in record comparisons
+for this tuple is n_fields.
+@return created tuple (inside buf) */
+UNIV_INLINE
+dtuple_t*
+dtuple_create_from_mem(
+/*===================*/
+ void* buf, /*!< in, out: buffer to use */
+ ulint buf_size, /*!< in: buffer size */
+ ulint n_fields); /*!< in: number of fields */
+
/**********************************************************//**
Creates a data tuple to a memory heap. The default value for number
of fields used in record comparisons for this tuple is n_fields.
@@ -240,7 +260,8 @@ dtuple_t*
dtuple_create(
/*==========*/
mem_heap_t* heap, /*!< in: memory heap where the tuple
- is created */
+ is created, DTUPLE_EST_ALLOC(n_fields)
+ bytes will be allocated from this heap */
ulint n_fields); /*!< in: number of fields */
/**********************************************************//**
diff --git a/storage/xtradb/include/data0data.ic b/storage/xtradb/include/data0data.ic
index 5c0f8039c80..205fa397987 100644
--- a/storage/xtradb/include/data0data.ic
+++ b/storage/xtradb/include/data0data.ic
@@ -348,23 +348,25 @@ dtuple_get_nth_field(
#endif /* UNIV_DEBUG */
/**********************************************************//**
-Creates a data tuple to a memory heap. The default value for number
-of fields used in record comparisons for this tuple is n_fields.
-@return own: created tuple */
+Creates a data tuple from an already allocated chunk of memory.
+The size of the chunk must be at least DTUPLE_EST_ALLOC(n_fields).
+The default value for number of fields used in record comparisons
+for this tuple is n_fields.
+@return created tuple (inside buf) */
UNIV_INLINE
dtuple_t*
-dtuple_create(
-/*==========*/
- mem_heap_t* heap, /*!< in: memory heap where the tuple
- is created */
- ulint n_fields) /*!< in: number of fields */
+dtuple_create_from_mem(
+/*===================*/
+ void* buf, /*!< in, out: buffer to use */
+ ulint buf_size, /*!< in: buffer size */
+ ulint n_fields) /*!< in: number of fields */
{
dtuple_t* tuple;
- ut_ad(heap);
+ ut_ad(buf != NULL);
+ ut_a(buf_size >= DTUPLE_EST_ALLOC(n_fields));
- tuple = (dtuple_t*) mem_heap_alloc(heap, sizeof(dtuple_t)
- + n_fields * sizeof(dfield_t));
+ tuple = (dtuple_t*) buf;
tuple->info_bits = 0;
tuple->n_fields = n_fields;
tuple->n_fields_cmp = n_fields;
@@ -386,9 +388,38 @@ dtuple_create(
dfield_get_type(field)->mtype = DATA_ERROR;
}
}
+#endif
+ return(tuple);
+}
+
+/**********************************************************//**
+Creates a data tuple to a memory heap. The default value for number
+of fields used in record comparisons for this tuple is n_fields.
+@return own: created tuple */
+UNIV_INLINE
+dtuple_t*
+dtuple_create(
+/*==========*/
+ mem_heap_t* heap, /*!< in: memory heap where the tuple
+ is created, DTUPLE_EST_ALLOC(n_fields)
+ bytes will be allocated from this heap */
+ ulint n_fields) /*!< in: number of fields */
+{
+ void* buf;
+ ulint buf_size;
+ dtuple_t* tuple;
+
+ ut_ad(heap);
+
+ buf_size = DTUPLE_EST_ALLOC(n_fields);
+ buf = mem_heap_alloc(heap, buf_size);
+ tuple = dtuple_create_from_mem(buf, buf_size, n_fields);
+
+#ifdef UNIV_DEBUG
UNIV_MEM_INVALID(tuple->fields, n_fields * sizeof *tuple->fields);
#endif
+
return(tuple);
}
diff --git a/storage/xtradb/include/db0err.h b/storage/xtradb/include/db0err.h
index 7048341b31e..3a4c8a54016 100644
--- a/storage/xtradb/include/db0err.h
+++ b/storage/xtradb/include/db0err.h
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1996, 2011, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1996, 2012, Oracle and/or its affiliates. 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
@@ -11,8 +11,8 @@ 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 program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
*****************************************************************************/
@@ -112,6 +112,8 @@ enum db_err {
limit */
DB_INDEX_CORRUPT, /* we have corrupted index */
DB_UNDO_RECORD_TOO_BIG, /* the undo log record is too big */
+ DB_TABLE_IN_FK_CHECK, /* table is being used in foreign
+ key check */
/* The following are partial failure codes */
DB_FAIL = 1000,
diff --git a/storage/xtradb/include/dict0boot.h b/storage/xtradb/include/dict0boot.h
index a817775c93c..9905217ccf7 100644
--- a/storage/xtradb/include/dict0boot.h
+++ b/storage/xtradb/include/dict0boot.h
@@ -94,6 +94,26 @@ void
dict_create(void);
/*=============*/
+/*****************************************************************//**
+Verifies the SYS_STATS table by scanning its clustered index. This
+function may only be called at InnoDB startup time.
+
+@return TRUE if SYS_STATS was verified successfully */
+UNIV_INTERN
+ibool
+dict_verify_xtradb_sys_stats(void);
+/*==============================*/
+
+/*****************************************************************//**
+Discard the existing dictionary cache SYS_STATS information, create and
+add it there anew. Does not touch the old SYS_STATS tablespace page
+under the assumption that they are corrupted or overwritten for other
+purposes. */
+UNIV_INTERN
+void
+dict_recreate_xtradb_sys_stats(void);
+/*================================*/
+
/* Space id and page no where the dictionary header resides */
#define DICT_HDR_SPACE 0 /* the SYSTEM tablespace */
diff --git a/storage/xtradb/include/dict0dict.h b/storage/xtradb/include/dict0dict.h
index 8af806c3572..6974e480144 100644
--- a/storage/xtradb/include/dict0dict.h
+++ b/storage/xtradb/include/dict0dict.h
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1996, 2009, Innobase Oy. All Rights Reserved.
+Copyright (c) 1996, 2012, Oracle and/or its affiliates. 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
@@ -11,8 +11,8 @@ 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 program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
*****************************************************************************/
@@ -1099,14 +1099,6 @@ dict_index_get_page(
/*================*/
const dict_index_t* tree); /*!< in: index */
/*********************************************************************//**
-Sets the page number of the root of index tree. */
-UNIV_INLINE
-void
-dict_index_set_page(
-/*================*/
- dict_index_t* index, /*!< in/out: index */
- ulint page); /*!< in: page number */
-/*********************************************************************//**
Gets the read-write lock of the index tree.
@return read-write lock */
UNIV_INLINE
diff --git a/storage/xtradb/include/dict0dict.ic b/storage/xtradb/include/dict0dict.ic
index b10deddd28f..5ed9b182d6c 100644
--- a/storage/xtradb/include/dict0dict.ic
+++ b/storage/xtradb/include/dict0dict.ic
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1996, 2009, Innobase Oy. All Rights Reserved.
+Copyright (c) 1996, 2012, Oracle and/or its affiliates. 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
@@ -11,8 +11,8 @@ 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 program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
*****************************************************************************/
@@ -776,21 +776,6 @@ dict_index_get_page(
}
/*********************************************************************//**
-Sets the page number of the root of index tree. */
-UNIV_INLINE
-void
-dict_index_set_page(
-/*================*/
- dict_index_t* index, /*!< in/out: index */
- ulint page) /*!< in: page number */
-{
- ut_ad(index);
- ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
-
- index->page = page;
-}
-
-/*********************************************************************//**
Gets the read-write lock of the index tree.
@return read-write lock */
UNIV_INLINE
diff --git a/storage/xtradb/include/dict0mem.h b/storage/xtradb/include/dict0mem.h
index 7f7904f6a25..50c6e1ee142 100644
--- a/storage/xtradb/include/dict0mem.h
+++ b/storage/xtradb/include/dict0mem.h
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1996, 2010, Innobase Oy. All Rights Reserved.
+Copyright (c) 1996, 2012, Oracle and/or its affiliates. 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
@@ -11,8 +11,8 @@ 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 program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
*****************************************************************************/
@@ -399,7 +399,9 @@ struct dict_index_struct{
unsigned to_be_dropped:1;
/*!< TRUE if this index is marked to be
dropped in ha_innobase::prepare_drop_index(),
- otherwise FALSE */
+ otherwise FALSE. Protected by
+ dict_sys->mutex, dict_operation_lock and
+ index->lock.*/
dict_field_t* fields; /*!< array of field descriptions */
#ifndef UNIV_HOTBACKUP
UT_LIST_NODE_T(dict_index_t)
diff --git a/storage/xtradb/include/fil0fil.h b/storage/xtradb/include/fil0fil.h
index 92fdca0db1b..19bf5960ae4 100644
--- a/storage/xtradb/include/fil0fil.h
+++ b/storage/xtradb/include/fil0fil.h
@@ -348,20 +348,19 @@ fil_read_first_page(
ib_uint64_t* max_flushed_lsn); /*!< out: max of flushed
lsn values in data files */
/*******************************************************************//**
-Increments the count of pending insert buffer page merges, if space is not
-being deleted.
-@return TRUE if being deleted, and ibuf merges should be skipped */
+Increments the count of pending operation, if space is not being deleted.
+@return TRUE if being deleted, and operation should be skipped */
UNIV_INTERN
ibool
-fil_inc_pending_ibuf_merges(
-/*========================*/
+fil_inc_pending_ops(
+/*================*/
ulint id); /*!< in: space id */
/*******************************************************************//**
-Decrements the count of pending insert buffer page merges. */
+Decrements the count of pending operations. */
UNIV_INTERN
void
-fil_decr_pending_ibuf_merges(
-/*=========================*/
+fil_decr_pending_ops(
+/*=================*/
ulint id); /*!< in: space id */
#endif /* !UNIV_HOTBACKUP */
/*******************************************************************//**
@@ -400,7 +399,9 @@ UNIV_INTERN
ibool
fil_delete_tablespace(
/*==================*/
- ulint id); /*!< in: space id */
+ ulint id, /*!< in: space id */
+ ibool evict_all); /*!< in: TRUE if we want all pages
+ evicted from LRU. */
#ifndef UNIV_HOTBACKUP
/*******************************************************************//**
Discards a single-table tablespace. The tablespace must be cached in the
diff --git a/storage/xtradb/include/fsp0fsp.h b/storage/xtradb/include/fsp0fsp.h
index d5e235aa870..f07e3decc66 100644
--- a/storage/xtradb/include/fsp0fsp.h
+++ b/storage/xtradb/include/fsp0fsp.h
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1995, 2011, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1995, 2012, Oracle and/or its affiliates. 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
@@ -260,30 +260,33 @@ fseg_n_reserved_pages(
Allocates a single free page from a segment. This function implements
the intelligent allocation strategy which tries to minimize
file space fragmentation.
-@return the allocated page offset FIL_NULL if no page could be allocated */
-UNIV_INTERN
-ulint
-fseg_alloc_free_page(
-/*=================*/
- fseg_header_t* seg_header, /*!< in: segment header */
- ulint hint, /*!< in: hint of which page would be desirable */
- byte direction, /*!< in: if the new page is needed because
+@param[in/out] seg_header segment header
+@param[in] hint hint of which page would be desirable
+@param[in] direction if the new page is needed because
of an index page split, and records are
inserted there in order, into which
direction they go alphabetically: FSP_DOWN,
- FSP_UP, FSP_NO_DIR */
- mtr_t* mtr); /*!< in: mtr handle */
+ FSP_UP, FSP_NO_DIR
+@param[in/out] mtr mini-transaction
+@return X-latched block, or NULL if no page could be allocated */
+#define fseg_alloc_free_page(seg_header, hint, direction, mtr) \
+ fseg_alloc_free_page_general(seg_header, hint, direction, \
+ FALSE, mtr, mtr)
/**********************************************************************//**
Allocates a single free page from a segment. This function implements
the intelligent allocation strategy which tries to minimize file space
fragmentation.
-@return allocated page offset, FIL_NULL if no page could be allocated */
+@retval NULL if no page could be allocated
+@retval block, rw_lock_x_lock_count(&block->lock) == 1 if allocation succeeded
+(init_mtr == mtr, or the page was not previously freed in mtr)
+@retval block (not allocated or initialized) otherwise */
UNIV_INTERN
-ulint
+buf_block_t*
fseg_alloc_free_page_general(
/*=========================*/
- fseg_header_t* seg_header,/*!< in: segment header */
- ulint hint, /*!< in: hint of which page would be desirable */
+ fseg_header_t* seg_header,/*!< in/out: segment header */
+ ulint hint, /*!< in: hint of which page would be
+ desirable */
byte direction,/*!< in: if the new page is needed because
of an index page split, and records are
inserted there in order, into which
@@ -294,7 +297,12 @@ fseg_alloc_free_page_general(
with fsp_reserve_free_extents, then there
is no need to do the check for this individual
page */
- mtr_t* mtr); /*!< in: mtr handle */
+ mtr_t* mtr, /*!< in/out: mini-transaction */
+ mtr_t* init_mtr)/*!< in/out: mtr or another mini-transaction
+ in which the page should be initialized.
+ If init_mtr!=mtr, but the page is already
+ latched in mtr, do not initialize the page. */
+ __attribute__((warn_unused_result, nonnull));
/**********************************************************************//**
Reserves free pages from a tablespace. All mini-transactions which may
use several pages from the tablespace should call this function beforehand
diff --git a/storage/xtradb/include/log0log.h b/storage/xtradb/include/log0log.h
index 281dd61a105..6b1c2859cf7 100644
--- a/storage/xtradb/include/log0log.h
+++ b/storage/xtradb/include/log0log.h
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1995, 2010, Innobase Oy. All Rights Reserved.
+Copyright (c) 1995, 2010, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2009, Google Inc.
Portions of this file contain modifications contributed and copyrighted by
@@ -18,8 +18,8 @@ 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 program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
*****************************************************************************/
diff --git a/storage/xtradb/include/mem0mem.ic b/storage/xtradb/include/mem0mem.ic
index d214c3fe6c9..c70615e1ca9 100644
--- a/storage/xtradb/include/mem0mem.ic
+++ b/storage/xtradb/include/mem0mem.ic
@@ -209,10 +209,6 @@ mem_heap_alloc(
buf = (byte*)buf + MEM_FIELD_HEADER_SIZE;
#endif
-#ifdef UNIV_SET_MEM_TO_ZERO
- UNIV_MEM_ALLOC(buf, n);
- memset(buf, '\0', n);
-#endif
UNIV_MEM_ALLOC(buf, n);
return(buf);
}
diff --git a/storage/xtradb/include/mtr0log.ic b/storage/xtradb/include/mtr0log.ic
index fa9ac014f4e..3ed1183f5c0 100644
--- a/storage/xtradb/include/mtr0log.ic
+++ b/storage/xtradb/include/mtr0log.ic
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1995, 2009, Innobase Oy. All Rights Reserved.
+Copyright (c) 1995, 2012, Oracle and/or its affiliates. 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
@@ -217,6 +217,7 @@ mlog_write_initial_log_record_fast(
"Please post a bug report to "
"bugs.mysql.com.\n",
type, offset, space);
+ ut_ad(0);
}
}
diff --git a/storage/xtradb/include/mtr0mtr.h b/storage/xtradb/include/mtr0mtr.h
index 7f608546cc2..46f1ff9310c 100644
--- a/storage/xtradb/include/mtr0mtr.h
+++ b/storage/xtradb/include/mtr0mtr.h
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1995, 2009, Innobase Oy. All Rights Reserved.
+Copyright (c) 1995, 2012, Oracle and/or its affiliates. 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
@@ -11,8 +11,8 @@ 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 program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
*****************************************************************************/
@@ -50,7 +50,9 @@ first 3 values must be RW_S_LATCH, RW_X_LATCH, RW_NO_LATCH */
#define MTR_MEMO_PAGE_S_FIX RW_S_LATCH
#define MTR_MEMO_PAGE_X_FIX RW_X_LATCH
#define MTR_MEMO_BUF_FIX RW_NO_LATCH
-#define MTR_MEMO_MODIFY 54
+#ifdef UNIV_DEBUG
+# define MTR_MEMO_MODIFY 54
+#endif /* UNIV_DEBUG */
#define MTR_MEMO_S_LOCK 55
#define MTR_MEMO_X_LOCK 56
@@ -376,6 +378,9 @@ struct mtr_struct{
ulint n_log_recs;
/* count of how many page initial log records
have been written to the mtr log */
+ ulint n_freed_pages;
+ /* number of pages that have been freed in
+ this mini-transaction */
ulint log_mode; /* specifies which operations should be
logged; default value MTR_LOG_ALL */
ib_uint64_t start_lsn;/* start lsn of the possible log entry for
diff --git a/storage/xtradb/include/mtr0mtr.ic b/storage/xtradb/include/mtr0mtr.ic
index 1db4a4bd735..a03a0271535 100644
--- a/storage/xtradb/include/mtr0mtr.ic
+++ b/storage/xtradb/include/mtr0mtr.ic
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1995, 2010, Innobase Oy. All Rights Reserved.
+Copyright (c) 1995, 2012, Oracle and/or its affiliates. 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
@@ -11,8 +11,8 @@ 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 program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
*****************************************************************************/
@@ -46,6 +46,7 @@ mtr_start(
mtr->modifications = FALSE;
mtr->inside_ibuf = FALSE;
mtr->n_log_recs = 0;
+ mtr->n_freed_pages = 0;
ut_d(mtr->state = MTR_ACTIVE);
ut_d(mtr->magic_n = MTR_MAGIC_N);
@@ -248,7 +249,7 @@ mtr_s_lock_func(
ut_ad(mtr);
ut_ad(lock);
- rw_lock_s_lock_func(lock, 0, file, line);
+ rw_lock_s_lock_inline(lock, 0, file, line);
mtr_memo_push(mtr, lock, MTR_MEMO_S_LOCK);
}
@@ -267,7 +268,7 @@ mtr_x_lock_func(
ut_ad(mtr);
ut_ad(lock);
- rw_lock_x_lock_func(lock, 0, file, line);
+ rw_lock_x_lock_inline(lock, 0, file, line);
mtr_memo_push(mtr, lock, MTR_MEMO_X_LOCK);
}
diff --git a/storage/xtradb/include/page0page.h b/storage/xtradb/include/page0page.h
index 1b9f9c84225..ba1ee7a7d11 100644
--- a/storage/xtradb/include/page0page.h
+++ b/storage/xtradb/include/page0page.h
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1994, 2009, Innobase Oy. All Rights Reserved.
+Copyright (c) 1994, 2012, Oracle and/or its affiliates. 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
@@ -11,8 +11,8 @@ 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 program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
*****************************************************************************/
@@ -281,16 +281,42 @@ page_get_supremum_offset(
const page_t* page); /*!< in: page which must have record(s) */
#define page_get_infimum_rec(page) ((page) + page_get_infimum_offset(page))
#define page_get_supremum_rec(page) ((page) + page_get_supremum_offset(page))
+
/************************************************************//**
-Returns the middle record of record list. If there are an even number
-of records in the list, returns the first record of upper half-list.
-@return middle record */
+Returns the nth record of the record list.
+This is the inverse function of page_rec_get_n_recs_before().
+@return nth record */
UNIV_INTERN
+const rec_t*
+page_rec_get_nth_const(
+/*===================*/
+ const page_t* page, /*!< in: page */
+ ulint nth) /*!< in: nth record */
+ __attribute__((nonnull, warn_unused_result));
+/************************************************************//**
+Returns the nth record of the record list.
+This is the inverse function of page_rec_get_n_recs_before().
+@return nth record */
+UNIV_INLINE
+rec_t*
+page_rec_get_nth(
+/*=============*/
+ page_t* page, /*< in: page */
+ ulint nth) /*!< in: nth record */
+ __attribute__((nonnull, warn_unused_result));
+
+#ifndef UNIV_HOTBACKUP
+/************************************************************//**
+Returns the middle record of the records on the page. If there is an
+even number of records in the list, returns the first record of the
+upper half-list.
+@return middle record */
+UNIV_INLINE
rec_t*
page_get_middle_rec(
/*================*/
- page_t* page); /*!< in: page */
-#ifndef UNIV_HOTBACKUP
+ page_t* page) /*!< in: page */
+ __attribute__((nonnull, warn_unused_result));
/*************************************************************//**
Compares a data tuple to a physical record. Differs from the function
cmp_dtuple_rec_with_match in the way that the record must reside on an
@@ -345,6 +371,7 @@ page_get_n_recs(
/***************************************************************//**
Returns the number of records before the given record in chain.
The number includes infimum and supremum records.
+This is the inverse function of page_rec_get_nth().
@return number of records */
UNIV_INTERN
ulint
diff --git a/storage/xtradb/include/page0page.ic b/storage/xtradb/include/page0page.ic
index d8570108115..4fe93345ce5 100644
--- a/storage/xtradb/include/page0page.ic
+++ b/storage/xtradb/include/page0page.ic
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1994, 2009, Innobase Oy. All Rights Reserved.
+Copyright (c) 1994, 2012, Oracle and/or its affiliates. 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
@@ -11,8 +11,8 @@ 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 program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
*****************************************************************************/
@@ -422,7 +422,37 @@ page_rec_is_infimum(
return(page_rec_is_infimum_low(page_offset(rec)));
}
+/************************************************************//**
+Returns the nth record of the record list.
+This is the inverse function of page_rec_get_n_recs_before().
+@return nth record */
+UNIV_INLINE
+rec_t*
+page_rec_get_nth(
+/*=============*/
+ page_t* page, /*!< in: page */
+ ulint nth) /*!< in: nth record */
+{
+ return((rec_t*) page_rec_get_nth_const(page, nth));
+}
+
#ifndef UNIV_HOTBACKUP
+/************************************************************//**
+Returns the middle record of the records on the page. If there is an
+even number of records in the list, returns the first record of the
+upper half-list.
+@return middle record */
+UNIV_INLINE
+rec_t*
+page_get_middle_rec(
+/*================*/
+ page_t* page) /*!< in: page */
+{
+ ulint middle = (page_get_n_recs(page) + PAGE_HEAP_NO_USER_LOW) / 2;
+
+ return(page_rec_get_nth(page, middle));
+}
+
/*************************************************************//**
Compares a data tuple to a physical record. Differs from the function
cmp_dtuple_rec_with_match in the way that the record must reside on an
@@ -713,7 +743,7 @@ page_rec_get_next_low(
(void*) rec,
(ulong) page_get_space_id(page),
(ulong) page_get_page_no(page));
- buf_page_print(page, 0);
+ buf_page_print(page, 0, 0);
ut_error;
}
diff --git a/storage/xtradb/include/row0mysql.h b/storage/xtradb/include/row0mysql.h
index 69e59ae120f..464024ebe03 100644
--- a/storage/xtradb/include/row0mysql.h
+++ b/storage/xtradb/include/row0mysql.h
@@ -168,7 +168,9 @@ UNIV_INTERN
row_prebuilt_t*
row_create_prebuilt(
/*================*/
- dict_table_t* table); /*!< in: Innobase table handle */
+ dict_table_t* table, /*!< in: Innobase table handle */
+ ulint mysql_row_len); /*!< in: length in bytes of a row in
+ the MySQL format */
/********************************************************************//**
Free a prebuilt struct for a MySQL table handle. */
UNIV_INTERN
@@ -693,9 +695,9 @@ struct row_prebuilt_struct {
in inserts */
que_fork_t* upd_graph; /*!< Innobase SQL query graph used
in updates or deletes */
- btr_pcur_t* pcur; /*!< persistent cursor used in selects
+ btr_pcur_t pcur; /*!< persistent cursor used in selects
and updates */
- btr_pcur_t* clust_pcur; /*!< persistent cursor used in
+ btr_pcur_t clust_pcur; /*!< persistent cursor used in
some selects and updates */
que_fork_t* sel_graph; /*!< dummy query graph used in
selects */
diff --git a/storage/xtradb/include/row0sel.h b/storage/xtradb/include/row0sel.h
index 8544b9d08ba..1c4ea6f7244 100644
--- a/storage/xtradb/include/row0sel.h
+++ b/storage/xtradb/include/row0sel.h
@@ -128,7 +128,12 @@ row_sel_convert_mysql_key_to_innobase(
in the tuple is already according
to index! */
byte* buf, /*!< in: buffer to use in field
- conversions */
+ conversions; NOTE that dtuple->data
+ may end up pointing inside buf so
+ do not discard that buffer while
+ the tuple is being used. See
+ row_mysql_store_col_in_innobase_format()
+ in the case of DATA_INT */
ulint buf_len, /*!< in: buffer length */
dict_index_t* index, /*!< in: index of the key value */
const byte* key_ptr, /*!< in: MySQL key value */
diff --git a/storage/xtradb/include/srv0srv.h b/storage/xtradb/include/srv0srv.h
index eeb5806de40..756a22f4242 100644
--- a/storage/xtradb/include/srv0srv.h
+++ b/storage/xtradb/include/srv0srv.h
@@ -233,6 +233,9 @@ extern unsigned long long srv_stats_sample_pages;
extern ulint srv_stats_auto_update;
extern ulint srv_stats_update_need_lock;
extern ibool srv_use_sys_stats_table;
+#ifdef UNIV_DEBUG
+extern ulong srv_sys_stats_root_page;
+#endif
extern ibool srv_use_doublewrite_buf;
extern ibool srv_use_checksums;
@@ -292,9 +295,6 @@ extern ibool srv_print_lock_waits;
extern ibool srv_print_buf_io;
extern ibool srv_print_log_io;
extern ibool srv_print_latch_waits;
-
-extern ulong srv_flush_checkpoint_debug;
-
#else /* UNIV_DEBUG */
# define srv_print_thread_releases FALSE
# define srv_print_lock_waits FALSE
@@ -741,12 +741,14 @@ srv_que_task_enqueue_low(
que_thr_t* thr); /*!< in: query thread */
/**********************************************************************//**
-Check whether any background thread is active.
-@return FALSE if all are are suspended or have exited. */
+Check whether any background thread is active. If so, return the thread
+type.
+@return ULINT_UNDEFINED if all are are suspended or have exited, thread
+type if any are still active. */
UNIV_INTERN
-ibool
-srv_is_any_background_thread_active(void);
-/*======================================*/
+ulint
+srv_get_active_thread_type(void);
+/*============================*/
/** Status variables to be passed to MySQL */
struct export_var_struct{
diff --git a/storage/xtradb/include/sync0rw.h b/storage/xtradb/include/sync0rw.h
index 971099c91f5..6159d8d0c81 100644
--- a/storage/xtradb/include/sync0rw.h
+++ b/storage/xtradb/include/sync0rw.h
@@ -155,6 +155,9 @@ unlocking, not the corresponding function. */
# define rw_lock_s_lock(M) \
rw_lock_s_lock_func((M), 0, __FILE__, __LINE__)
+# define rw_lock_s_lock_inline(M, P, F, L) \
+ rw_lock_s_lock_func((M), (P), (F), (L))
+
# define rw_lock_s_lock_gen(M, P) \
rw_lock_s_lock_func((M), (P), __FILE__, __LINE__)
@@ -171,12 +174,18 @@ unlocking, not the corresponding function. */
# define rw_lock_x_lock(M) \
rw_lock_x_lock_func((M), 0, __FILE__, __LINE__)
+# define rw_lock_x_lock_inline(M, P, F, L) \
+ rw_lock_x_lock_func((M), (P), (F), (L))
+
# define rw_lock_x_lock_gen(M, P) \
rw_lock_x_lock_func((M), (P), __FILE__, __LINE__)
# define rw_lock_x_lock_nowait(M) \
rw_lock_x_lock_func_nowait((M), __FILE__, __LINE__)
+# define rw_lock_x_lock_func_nowait_inline(M, F, L) \
+ rw_lock_x_lock_func_nowait((M), (F), (L))
+
# ifdef UNIV_SYNC_DEBUG
# define rw_lock_x_unlock_gen(L, P) rw_lock_x_unlock_func(P, L)
# else
@@ -208,6 +217,9 @@ unlocking, not the corresponding function. */
# define rw_lock_s_lock(M) \
pfs_rw_lock_s_lock_func((M), 0, __FILE__, __LINE__)
+# define rw_lock_s_lock_inline(M, P, F, L) \
+ pfs_rw_lock_s_lock_func((M), (P), (F), (L))
+
# define rw_lock_s_lock_gen(M, P) \
pfs_rw_lock_s_lock_func((M), (P), __FILE__, __LINE__)
@@ -223,12 +235,18 @@ unlocking, not the corresponding function. */
# define rw_lock_x_lock(M) \
pfs_rw_lock_x_lock_func((M), 0, __FILE__, __LINE__)
+# define rw_lock_x_lock_inline(M, P, F, L) \
+ pfs_rw_lock_x_lock_func((M), (P), (F), (L))
+
# define rw_lock_x_lock_gen(M, P) \
pfs_rw_lock_x_lock_func((M), (P), __FILE__, __LINE__)
# define rw_lock_x_lock_nowait(M) \
pfs_rw_lock_x_lock_func_nowait((M), __FILE__, __LINE__)
+# define rw_lock_x_lock_func_nowait_inline(M, F, L) \
+ pfs_rw_lock_x_lock_func_nowait((M), (F), (L))
+
# ifdef UNIV_SYNC_DEBUG
# define rw_lock_x_unlock_gen(L, P) pfs_rw_lock_x_unlock_func(P, L)
# else
diff --git a/storage/xtradb/include/sync0rw.ic b/storage/xtradb/include/sync0rw.ic
index 3eaa6172631..73e1f880aad 100644
--- a/storage/xtradb/include/sync0rw.ic
+++ b/storage/xtradb/include/sync0rw.ic
@@ -90,7 +90,7 @@ rw_lock_set_waiter_flag(
rw_lock_t* lock) /*!< in/out: rw-lock */
{
#ifdef INNODB_RW_LOCKS_USE_ATOMICS
- os_compare_and_swap_ulint(&lock->waiters, 0, 1);
+ (void) os_compare_and_swap_ulint(&lock->waiters, 0, 1);
#else /* INNODB_RW_LOCKS_USE_ATOMICS */
lock->waiters = 1;
#endif /* INNODB_RW_LOCKS_USE_ATOMICS */
@@ -107,7 +107,7 @@ rw_lock_reset_waiter_flag(
rw_lock_t* lock) /*!< in/out: rw-lock */
{
#ifdef INNODB_RW_LOCKS_USE_ATOMICS
- os_compare_and_swap_ulint(&lock->waiters, 1, 0);
+ (void) os_compare_and_swap_ulint(&lock->waiters, 1, 0);
#else /* INNODB_RW_LOCKS_USE_ATOMICS */
lock->waiters = 0;
#endif /* INNODB_RW_LOCKS_USE_ATOMICS */
@@ -564,8 +564,6 @@ rw_lock_x_unlock_func(
if (lock->lock_word == 0) {
/* Last caller in a possible recursive chain. */
lock->recursive = FALSE;
- UNIV_MEM_INVALID(&lock->writer_thread,
- sizeof lock->writer_thread);
}
#ifdef UNIV_SYNC_DEBUG
@@ -610,8 +608,6 @@ rw_lock_x_unlock_direct(
if (lock->lock_word == 0) {
lock->recursive = FALSE;
- UNIV_MEM_INVALID(&lock->writer_thread,
- sizeof lock->writer_thread);
}
lock->lock_word += X_LOCK_DECR;
diff --git a/storage/xtradb/include/sync0sync.h b/storage/xtradb/include/sync0sync.h
index f9434ed54be..4a2f55d90ff 100644
--- a/storage/xtradb/include/sync0sync.h
+++ b/storage/xtradb/include/sync0sync.h
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1995, 2011, Innobase Oy. All Rights Reserved.
+Copyright (c) 1995, 2012, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2008, Google Inc.
Portions of this file contain modifications contributed and copyrighted by
@@ -18,8 +18,8 @@ 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 program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
*****************************************************************************/
@@ -404,8 +404,10 @@ void
sync_thread_add_level(
/*==================*/
void* latch, /*!< in: pointer to a mutex or an rw-lock */
- ulint level); /*!< in: level in the latching order; if
+ ulint level, /*!< in: level in the latching order; if
SYNC_LEVEL_VARYING, nothing is done */
+ ibool relock) /*!< in: TRUE if re-entering an x-lock */
+ __attribute__((nonnull));
/******************************************************************//**
Removes a latch from the thread level array if it is found there.
@return TRUE if found in the array; it is no error if the latch is
diff --git a/storage/xtradb/include/trx0purge.h b/storage/xtradb/include/trx0purge.h
index 0b83a76cab7..2bd9e64476b 100644
--- a/storage/xtradb/include/trx0purge.h
+++ b/storage/xtradb/include/trx0purge.h
@@ -143,9 +143,9 @@ struct trx_purge_struct{
obtaining an s-latch here. */
read_view_t* view; /*!< The purge will not remove undo logs
which are >= this view (purge view) */
- ulint n_pages_handled;/*!< Approximate number of undo log
+ ulonglong n_pages_handled;/*!< Approximate number of undo log
pages processed in purge */
- ulint handle_limit; /*!< Target of how many pages to get
+ ulonglong handle_limit; /*!< Target of how many pages to get
processed in the current purge */
/*------------------------------*/
/* The following two fields form the 'purge pointer' which advances
diff --git a/storage/xtradb/include/trx0rec.ic b/storage/xtradb/include/trx0rec.ic
index f0b3276ed44..4fc5a7147f9 100644
--- a/storage/xtradb/include/trx0rec.ic
+++ b/storage/xtradb/include/trx0rec.ic
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1996, 2009, Innobase Oy. All Rights Reserved.
+Copyright (c) 1996, 2012, Oracle and/or its affiliates. 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
@@ -11,8 +11,8 @@ 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 program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
*****************************************************************************/
@@ -107,6 +107,7 @@ trx_undo_rec_copy(
len = mach_read_from_2(undo_rec)
- ut_align_offset(undo_rec, UNIV_PAGE_SIZE);
+ ut_ad(len < UNIV_PAGE_SIZE);
return(mem_heap_dup(heap, undo_rec, len));
}
#endif /* !UNIV_HOTBACKUP */
diff --git a/storage/xtradb/include/trx0rseg.ic b/storage/xtradb/include/trx0rseg.ic
index daffa92fc7d..5e8d2b41120 100644
--- a/storage/xtradb/include/trx0rseg.ic
+++ b/storage/xtradb/include/trx0rseg.ic
@@ -25,6 +25,7 @@ Created 3/26/1996 Heikki Tuuri
#include "srv0srv.h"
#include "mtr0log.h"
+#include "trx0sys.h"
/******************************************************************//**
Gets a rollback segment header.
@@ -131,7 +132,13 @@ trx_rsegf_undo_find_free(
ulint i;
ulint page_no;
- for (i = 0; i < TRX_RSEG_N_SLOTS; i++) {
+ for (i = 0;
+#ifndef UNIV_DEBUG
+ i < TRX_RSEG_N_SLOTS;
+#else
+ i < (trx_rseg_n_slots_debug ? trx_rseg_n_slots_debug : TRX_RSEG_N_SLOTS);
+#endif
+ i++) {
page_no = trx_rsegf_get_nth_undo(rsegf, i, mtr);
diff --git a/storage/xtradb/include/trx0sys.h b/storage/xtradb/include/trx0sys.h
index 0f12fc496b7..c17b0c11767 100644
--- a/storage/xtradb/include/trx0sys.h
+++ b/storage/xtradb/include/trx0sys.h
@@ -252,6 +252,12 @@ trx_id_t
trx_sys_get_new_trx_id(void);
/*========================*/
#endif /* !UNIV_HOTBACKUP */
+
+#ifdef UNIV_DEBUG
+/* Flag to control TRX_RSEG_N_SLOTS behavior debugging. */
+extern uint trx_rseg_n_slots_debug;
+#endif
+
/*****************************************************************//**
Writes a trx id to an index page. In case that the id size changes in
some future version, this function should be used instead of
diff --git a/storage/xtradb/include/trx0undo.h b/storage/xtradb/include/trx0undo.h
index 50aa6d0ac09..4a1e40af505 100644
--- a/storage/xtradb/include/trx0undo.h
+++ b/storage/xtradb/include/trx0undo.h
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1996, 2011, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1996, 2012, Oracle and/or its affiliates. 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
@@ -11,8 +11,8 @@ 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 program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
*****************************************************************************/
@@ -194,16 +194,17 @@ trx_undo_get_first_rec(
mtr_t* mtr); /*!< in: mtr */
/********************************************************************//**
Tries to add a page to the undo log segment where the undo log is placed.
-@return page number if success, else FIL_NULL */
+@return X-latched block if success, else NULL */
UNIV_INTERN
-ulint
+buf_block_t*
trx_undo_add_page(
/*==============*/
trx_t* trx, /*!< in: transaction */
trx_undo_t* undo, /*!< in: undo log memory object */
- mtr_t* mtr); /*!< in: mtr which does not have a latch to any
+ mtr_t* mtr) /*!< in: mtr which does not have a latch to any
undo log page; the caller must have reserved
the rollback segment mutex */
+ __attribute__((nonnull, warn_unused_result));
/********************************************************************//**
Frees the last undo log page.
The caller must hold the rollback segment mutex. */
diff --git a/storage/xtradb/include/univ.i b/storage/xtradb/include/univ.i
index 1a48d68d0d7..f4b06ccefa4 100644
--- a/storage/xtradb/include/univ.i
+++ b/storage/xtradb/include/univ.i
@@ -54,7 +54,10 @@ Created 1/20/1994 Heikki Tuuri
#define INNODB_VERSION_BUGFIX 8
#ifndef PERCONA_INNODB_VERSION
-#define PERCONA_INNODB_VERSION 24.1
+/* this is *not* the version of XtraDB as in Percona-Server sources,
+ but the version of Percona-Server, where this XtraDB was taken from.
+ Because Percona does not update XtraDB version for every release */
+#define PERCONA_INNODB_VERSION 26.0
#endif
/* The following is the InnoDB version as shown in
@@ -159,14 +162,6 @@ resolved */
/* DEBUG VERSION CONTROL
===================== */
-/* The following flag will make InnoDB to initialize
-all memory it allocates to zero. It hides Purify
-warnings about reading unallocated memory unless
-memory is read outside the allocated blocks. */
-/*
-#define UNIV_INIT_MEM_TO_ZERO
-*/
-
/* When this macro is defined then additional test functions will be
compiled. These functions live at the end of each relevant source file
and have "test_" prefix. These functions are not called from anywhere in
@@ -236,15 +231,6 @@ operations (very slow); also UNIV_DEBUG must be defined */
#define UNIV_BTR_DEBUG /* check B-tree links */
#define UNIV_LIGHT_MEM_DEBUG /* light memory debugging */
-#ifdef HAVE_valgrind
-/* The following sets all new allocated memory to zero before use:
-this can be used to eliminate unnecessary Purify warnings, but note that
-it also masks many bugs Purify could detect. For detailed Purify analysis it
-is best to remove the define below and look through the warnings one
-by one. */
-#define UNIV_SET_MEM_TO_ZERO
-#endif
-
/*
#define UNIV_SQL_DEBUG
#define UNIV_LOG_DEBUG
@@ -329,11 +315,17 @@ management to ensure correct alignment for doubles etc. */
/* Maximum number of parallel threads in a parallelized operation */
#define UNIV_MAX_PARALLELISM 32
-/* The maximum length of a table name. This is the MySQL limit and is
-defined in mysql_com.h like NAME_CHAR_LEN*SYSTEM_CHARSET_MBMAXLEN, the
-number does not include a terminating '\0'. InnoDB probably can handle
-longer names internally */
-#define MAX_TABLE_NAME_LEN 192
+/** This is the "mbmaxlen" for my_charset_filename (defined in
+strings/ctype-utf8.c), which is used to encode File and Database names. */
+#define FILENAME_CHARSET_MAXNAMLEN 5
+
+/** The maximum length of an encode table name in bytes. The max
+table and database names are NAME_CHAR_LEN (64) characters. After the
+encoding, the max length would be NAME_CHAR_LEN (64) *
+FILENAME_CHARSET_MAXNAMLEN (5) = 320 bytes. The number does not include a
+terminating '\0'. InnoDB can handle longer names internally */
+#define MAX_TABLE_NAME_LEN 320
+
/* The maximum length of a database name. Like MAX_TABLE_NAME_LEN this is
the MySQL's NAME_LEN, see check_and_convert_db_name(). */
diff --git a/storage/xtradb/include/ut0mem.h b/storage/xtradb/include/ut0mem.h
index faf6f242883..39f5f20dc6d 100644
--- a/storage/xtradb/include/ut0mem.h
+++ b/storage/xtradb/include/ut0mem.h
@@ -78,40 +78,19 @@ ut_mem_init(void);
/*=============*/
/**********************************************************************//**
-Allocates memory. Sets it also to zero if UNIV_SET_MEM_TO_ZERO is
-defined and set_to_zero is TRUE.
+Allocates memory.
@return own: allocated memory */
UNIV_INTERN
void*
ut_malloc_low(
/*==========*/
ulint n, /*!< in: number of bytes to allocate */
- ibool set_to_zero, /*!< in: TRUE if allocated memory
- should be set to zero if
- UNIV_SET_MEM_TO_ZERO is defined */
- ibool assert_on_error); /*!< in: if TRUE, we crash mysqld if
+ ibool assert_on_error) /*!< in: if TRUE, we crash mysqld if
the memory cannot be allocated */
+ __attribute__((malloc));
/**********************************************************************//**
-Allocates memory. Sets it also to zero if UNIV_SET_MEM_TO_ZERO is
-defined.
-@return own: allocated memory */
-UNIV_INTERN
-void*
-ut_malloc(
-/*======*/
- ulint n); /*!< in: number of bytes to allocate */
-#ifndef UNIV_HOTBACKUP
-/**********************************************************************//**
-Tests if malloc of n bytes would succeed. ut_malloc() asserts if memory runs
-out. It cannot be used if we want to return an error message. Prints to
-stderr a message if fails.
-@return TRUE if succeeded */
-UNIV_INTERN
-ibool
-ut_test_malloc(
-/*===========*/
- ulint n); /*!< in: try to allocate this many bytes */
-#endif /* !UNIV_HOTBACKUP */
+Allocates memory. */
+#define ut_malloc(n) ut_malloc_low(n, TRUE)
/**********************************************************************//**
Frees a memory block allocated with ut_malloc. Freeing a NULL pointer is
a nop. */
diff --git a/storage/xtradb/include/ut0rnd.ic b/storage/xtradb/include/ut0rnd.ic
index 2c8c959d804..60e213dd19f 100644
--- a/storage/xtradb/include/ut0rnd.ic
+++ b/storage/xtradb/include/ut0rnd.ic
@@ -114,7 +114,7 @@ ut_rnd_interval(
rnd = ut_rnd_gen_ulint();
- return(low + (rnd % (high - low + 1)));
+ return(low + (rnd % (high - low)));
}
/*********************************************************//**
diff --git a/storage/xtradb/lock/lock0lock.c b/storage/xtradb/lock/lock0lock.c
index ff711195785..eadd52f462a 100644
--- a/storage/xtradb/lock/lock0lock.c
+++ b/storage/xtradb/lock/lock0lock.c
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1996, 2010, Innobase Oy. All Rights Reserved.
+Copyright (c) 1996, 2012, Oracle and/or its affiliates. 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
@@ -38,6 +38,7 @@ Created 5/7/1996 Heikki Tuuri
#include "trx0purge.h"
#include "dict0mem.h"
#include "trx0sys.h"
+#include "btr0btr.h"
#ifdef WITH_WSREP
extern my_bool wsrep_debug;
@@ -1655,7 +1656,7 @@ lock_sec_rec_some_has_impl_off_kernel(
if (!lock_check_trx_id_sanity(page_get_max_trx_id(page),
rec, index, offsets, TRUE)) {
- buf_page_print(page, 0);
+ buf_page_print(page, 0, 0);
/* The page is corrupt: try to avoid a crash by returning
NULL */
@@ -1734,7 +1735,7 @@ lock_rec_create(
page_no = buf_block_get_page_no(block);
page = block->frame;
- ut_ad(!!page_is_comp(page) == dict_table_is_comp(index->table));
+ btr_assert_not_corrupted(block, index);
/* If rec is the supremum record, then we reset the gap and
LOCK_REC_NOT_GAP bits, as all locks on the supremum are
@@ -1898,6 +1899,7 @@ lock_rec_enqueue_waiting(
"InnoDB: Submit a detailed bug report"
" to http://bugs.mysql.com\n",
stderr);
+ ut_ad(0);
}
/* Enqueue the lock request that will wait to be granted */
@@ -2112,8 +2114,9 @@ lock_rec_lock_fast(
ut_ad(mode - (LOCK_MODE_MASK & mode) == LOCK_GAP
|| mode - (LOCK_MODE_MASK & mode) == 0
#ifdef WITH_WSREP
- || mode - (LOCK_MODE_MASK & mode) == WSREP_BF
- || mode - (LOCK_MODE_MASK & mode) - LOCK_REC_NOT_GAP == WSREP_BF
+ || mode - (LOCK_MODE_MASK & mode) - WSREP_BF == 0
+ || mode - (LOCK_MODE_MASK & mode) - WSREP_BF == LOCK_GAP
+ || mode - (LOCK_MODE_MASK & mode) - WSREP_BF == LOCK_REC_NOT_GAP
#endif /* WITH_WSREP */
|| mode - (LOCK_MODE_MASK & mode) == LOCK_REC_NOT_GAP);
@@ -2197,8 +2200,9 @@ lock_rec_lock_slow(
ut_ad(mode - (LOCK_MODE_MASK & mode) == LOCK_GAP
|| mode - (LOCK_MODE_MASK & mode) == 0
#ifdef WITH_WSREP
- || mode - (LOCK_MODE_MASK & mode) == WSREP_BF
- || mode - (LOCK_MODE_MASK & mode) - LOCK_REC_NOT_GAP == WSREP_BF
+ || mode - (LOCK_MODE_MASK & mode) - WSREP_BF == 0
+ || mode - (LOCK_MODE_MASK & mode) - WSREP_BF == LOCK_GAP
+ || mode - (LOCK_MODE_MASK & mode) - WSREP_BF == LOCK_REC_NOT_GAP
#endif /* WITH_WSREP */
|| mode - (LOCK_MODE_MASK & mode) == LOCK_REC_NOT_GAP);
@@ -2272,8 +2276,9 @@ lock_rec_lock(
ut_ad(mode - (LOCK_MODE_MASK & mode) == LOCK_GAP
|| mode - (LOCK_MODE_MASK & mode) == LOCK_REC_NOT_GAP
#ifdef WITH_WSREP
- || mode - (LOCK_MODE_MASK & mode) == WSREP_BF
- || mode - (LOCK_MODE_MASK & mode) - LOCK_REC_NOT_GAP == WSREP_BF
+ || mode - (LOCK_MODE_MASK & mode) - WSREP_BF == 0
+ || mode - (LOCK_MODE_MASK & mode) - WSREP_BF == LOCK_GAP
+ || mode - (LOCK_MODE_MASK & mode) - WSREP_BF == LOCK_REC_NOT_GAP
#endif /* WITH_WSREP */
|| mode - (LOCK_MODE_MASK & mode) == 0);
#ifdef WITH_WSREP
@@ -4029,6 +4034,7 @@ lock_table_enqueue_waiting(
"InnoDB: Submit a detailed bug report"
" to http://bugs.mysql.com\n",
stderr);
+ ut_ad(0);
}
/* Enqueue the lock request that will wait to be granted */
@@ -5256,6 +5262,79 @@ function_exit:
}
/*********************************************************************//**
+Validate record locks up to a limit.
+@return lock at limit or NULL if no more locks in the hash bucket */
+static __attribute__((nonnull, warn_unused_result))
+const lock_t*
+lock_rec_validate(
+/*==============*/
+ ulint start, /*!< in: lock_sys->rec_hash
+ bucket */
+ ib_uint64_t* limit) /*!< in/out: upper limit of
+ (space, page_no) */
+{
+ lock_t* lock;
+ ut_ad(mutex_own(&kernel_mutex));
+
+ for (lock = HASH_GET_FIRST(lock_sys->rec_hash, start);
+ lock != NULL;
+ lock = HASH_GET_NEXT(hash, lock)) {
+
+ ib_uint64_t current;
+
+ ut_a(trx_in_trx_list(lock->trx));
+ ut_a(lock_get_type(lock) == LOCK_REC);
+
+ current = ut_ull_create(
+ lock->un_member.rec_lock.space,
+ lock->un_member.rec_lock.page_no);
+
+ if (current > *limit) {
+ *limit = current + 1;
+ return(lock);
+ }
+ }
+
+ return(NULL);
+}
+
+/*********************************************************************//**
+Validate a record lock's block */
+static
+void
+lock_rec_block_validate(
+/*====================*/
+ ulint space,
+ ulint page_no)
+{
+ /* The lock and the block that it is referring to may be freed at
+ this point. We pass BUF_GET_POSSIBLY_FREED to skip a debug check.
+ If the lock exists in lock_rec_validate_page() we assert
+ !block->page.file_page_was_freed. */
+
+ mtr_t mtr;
+ buf_block_t* block;
+
+ /* Make sure that the tablespace is not deleted while we are
+ trying to access the page. */
+ if (!fil_inc_pending_ops(space)) {
+ mtr_start(&mtr);
+ block = buf_page_get_gen(
+ space, fil_space_get_zip_size(space),
+ page_no, RW_X_LATCH, NULL,
+ BUF_GET_POSSIBLY_FREED,
+ __FILE__, __LINE__, &mtr);
+
+ buf_block_dbg_add_level(block, SYNC_NO_ORDER_CHECK);
+
+ ut_ad(lock_rec_validate_page(block));
+ mtr_commit(&mtr);
+
+ fil_decr_pending_ops(space);
+ }
+}
+
+/*********************************************************************//**
Validates the lock system.
@return TRUE if ok */
static
@@ -5287,60 +5366,21 @@ lock_validate(void)
trx = UT_LIST_GET_NEXT(trx_list, trx);
}
- for (i = 0; i < hash_get_n_cells(lock_sys->rec_hash); i++) {
-
- ulint space;
- ulint page_no;
- ib_uint64_t limit = 0;
-
- for (;;) {
- mtr_t mtr;
- buf_block_t* block;
-
- lock = HASH_GET_FIRST(lock_sys->rec_hash, i);
-
- while (lock) {
- ib_uint64_t space_page;
- ut_a(trx_in_trx_list(lock->trx));
-
- space = lock->un_member.rec_lock.space;
- page_no = lock->un_member.rec_lock.page_no;
-
- space_page = ut_ull_create(space, page_no);
+ /* Iterate over all the record locks and validate the locks. We
+ don't want to hog the lock_sys_t::mutex and the trx_sys_t::mutex.
+ Release both mutexes during the validation check. */
- if (space_page >= limit) {
- break;
- }
-
- lock = HASH_GET_NEXT(hash, lock);
- }
+ for (i = 0; i < hash_get_n_cells(lock_sys->rec_hash); i++) {
+ const lock_t* lock;
+ ib_uint64_t limit = 0;
- if (!lock) {
+ while ((lock = lock_rec_validate(i, &limit)) != NULL) {
- break;
- }
+ ulint space = lock->un_member.rec_lock.space;
+ ulint page_no = lock->un_member.rec_lock.page_no;
lock_mutex_exit_kernel();
-
- /* The lock and the block that it is referring
- to may be freed at this point. We pass
- BUF_GET_POSSIBLY_FREED to skip a debug check.
- If the lock exists in lock_rec_validate_page()
- we assert !block->page.file_page_was_freed. */
-
- mtr_start(&mtr);
- block = buf_page_get_gen(
- space, fil_space_get_zip_size(space),
- page_no, RW_X_LATCH, NULL,
- BUF_GET_POSSIBLY_FREED,
- __FILE__, __LINE__, &mtr);
- buf_block_dbg_add_level(block, SYNC_NO_ORDER_CHECK);
-
- ut_ad(lock_rec_validate_page(block));
- mtr_commit(&mtr);
-
- limit++;
-
+ lock_rec_block_validate(space, page_no);
lock_mutex_enter_kernel();
}
}
diff --git a/storage/xtradb/log/log0log.c b/storage/xtradb/log/log0log.c
index af0c801a4ec..dcaf951a0ed 100644
--- a/storage/xtradb/log/log0log.c
+++ b/storage/xtradb/log/log0log.c
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1995, 2010, Innobase Oy. All Rights Reserved.
+Copyright (c) 1995, 2010, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2009, Google Inc.
Portions of this file contain modifications contributed and copyrighted by
@@ -18,8 +18,8 @@ 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 program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
*****************************************************************************/
@@ -1693,13 +1693,10 @@ log_preflush_pool_modified_pages(
recv_apply_hashed_log_recs(TRUE);
}
- retry:
n_pages = buf_flush_list(ULINT_MAX, new_oldest);
- if (sync && n_pages != 0) {
- //buf_flush_wait_batch_end(NULL, BUF_FLUSH_LIST);
- os_thread_sleep(100000);
- goto retry;
+ if (sync) {
+ buf_flush_wait_batch_end(NULL, BUF_FLUSH_LIST);
}
if (n_pages == ULINT_UNDEFINED) {
@@ -2023,13 +2020,6 @@ log_checkpoint(
{
ib_uint64_t oldest_lsn;
-#ifdef UNIV_DEBUG
- if (srv_flush_checkpoint_debug == 1) {
-
- return TRUE;
- }
-#endif
-
if (recv_recovery_is_on()) {
recv_apply_hashed_log_recs(TRUE);
}
@@ -2134,11 +2124,7 @@ log_make_checkpoint_at(
physical write will always be made to
log files */
{
-#ifdef UNIV_DEBUG
- if (srv_flush_checkpoint_debug == 1)
- return;
-#endif
-/* Preflush pages synchronously */
+ /* Preflush pages synchronously */
while (!log_preflush_pool_modified_pages(lsn, TRUE));
@@ -2230,13 +2216,7 @@ log_checkpoint_margin(void)
ibool checkpoint_sync;
ibool do_checkpoint;
ibool success;
-
-#ifdef UNIV_DEBUG
- if (srv_flush_checkpoint_debug == 1)
- return;
-#endif
-
- loop:
+loop:
sync = FALSE;
checkpoint_sync = FALSE;
do_checkpoint = FALSE;
@@ -2259,15 +2239,13 @@ log_checkpoint_margin(void)
/* A flush is urgent: we have to do a synchronous preflush */
sync = TRUE;
- advance = age - log->max_modified_age_sync;
+ advance = 2 * (age - log->max_modified_age_sync);
} else if (age > log_max_modified_age_async()) {
/* A flush is not urgent: we do an asynchronous preflush */
advance = age - log_max_modified_age_async();
- log->check_flush_or_checkpoint = FALSE;
} else {
advance = 0;
- log->check_flush_or_checkpoint = FALSE;
}
checkpoint_age = log->lsn - log->last_checkpoint_lsn;
@@ -2284,9 +2262,9 @@ log_checkpoint_margin(void)
do_checkpoint = TRUE;
- //log->check_flush_or_checkpoint = FALSE;
+ log->check_flush_or_checkpoint = FALSE;
} else {
- //log->check_flush_or_checkpoint = FALSE;
+ log->check_flush_or_checkpoint = FALSE;
}
mutex_exit(&(log->mutex));
@@ -2294,7 +2272,6 @@ log_checkpoint_margin(void)
if (advance) {
ib_uint64_t new_oldest = oldest_lsn + advance;
-retry:
success = log_preflush_pool_modified_pages(new_oldest, sync);
/* If the flush succeeded, this thread has done its part
@@ -2309,7 +2286,7 @@ retry:
log->check_flush_or_checkpoint = TRUE;
mutex_exit(&(log->mutex));
- goto retry;
+ goto loop;
}
}
@@ -3187,11 +3164,7 @@ void
log_check_margins(void)
/*===================*/
{
-#ifdef UNIV_DEBUG
- if (srv_flush_checkpoint_debug == 1)
- return;
-#endif
- loop:
+loop:
log_flush_margin();
log_checkpoint_margin();
@@ -3223,9 +3196,12 @@ void
logs_empty_and_mark_files_at_shutdown(void)
/*=======================================*/
{
- ib_uint64_t lsn;
- ulint arch_log_no;
- ibool server_busy;
+ ib_uint64_t lsn;
+ ulint arch_log_no;
+ ibool server_busy;
+ ulint count = 0;
+ ulint pending_io;
+ ulint active_thd;
if (srv_print_verbose_log) {
ut_print_timestamp(stderr);
@@ -3244,6 +3220,8 @@ logs_empty_and_mark_files_at_shutdown(void)
loop:
os_thread_sleep(100000);
+ count++;
+
mutex_enter(&kernel_mutex);
/* We need the monitor threads to stop before we proceed with
@@ -3252,6 +3230,21 @@ loop:
if (srv_error_monitor_active
|| srv_lock_timeout_active
|| srv_monitor_active) {
+ const char* thread_active = NULL;
+
+ /* Print a message every 60 seconds if we are waiting
+ for the monitor thread to exit. Master and worker threads
+ check will be done later. */
+ if (srv_print_verbose_log && count > 600) {
+
+ if (srv_error_monitor_active) {
+ thread_active = "srv_error_monitor_thread";
+ } else if (srv_lock_timeout_active) {
+ thread_active = "srv_lock_timeout thread";
+ } else if (srv_monitor_active) {
+ thread_active = "srv_monitor_thread";
+ }
+ }
mutex_exit(&kernel_mutex);
@@ -3259,6 +3252,13 @@ loop:
os_event_set(srv_monitor_event);
os_event_set(srv_timeout_event);
+ if (thread_active) {
+ ut_print_timestamp(stderr);
+ fprintf(stderr, " InnoDB: Waiting for %s to exit\n",
+ thread_active);
+ count = 0;
+ }
+
goto loop;
}
@@ -3269,9 +3269,54 @@ loop:
server_busy = trx_n_mysql_transactions > 0
|| UT_LIST_GET_LEN(trx_sys->trx_list) > trx_n_prepared;
+
+ if (server_busy) {
+ ulint total_trx = UT_LIST_GET_LEN(trx_sys->trx_list)
+ + trx_n_mysql_transactions;
+
+ mutex_exit(&kernel_mutex);
+
+ if (srv_print_verbose_log && count > 600) {
+ ut_print_timestamp(stderr);
+ fprintf(stderr, " InnoDB: Waiting for %lu "
+ "active transactions to finish\n",
+ (ulong) total_trx);
+ count = 0;
+ }
+
+ goto loop;
+ }
+
mutex_exit(&kernel_mutex);
- if (server_busy || srv_is_any_background_thread_active()) {
+ /* Check that the background threads are suspended */
+ active_thd = srv_get_active_thread_type();
+
+ if (active_thd != ULINT_UNDEFINED) {
+
+ /* The srv_lock_timeout_thread, srv_error_monitor_thread
+ and srv_monitor_thread should already exit by now. The
+ only threads to be suspended are the master threads
+ and worker threads (purge threads). Print the thread
+ type if any of such threads not in suspended mode */
+ if (srv_print_verbose_log && count > 600) {
+ const char* thread_type = "<null>";
+
+ switch (active_thd) {
+ case SRV_WORKER:
+ thread_type = "worker threads";
+ break;
+ case SRV_MASTER:
+ thread_type = "master thread";
+ break;
+ }
+
+ ut_print_timestamp(stderr);
+ fprintf(stderr, " InnoDB: Waiting for %s "
+ "to be suspended\n", thread_type);
+ count = 0;
+ }
+
goto loop;
}
@@ -3283,10 +3328,35 @@ loop:
|| log_sys->n_pending_writes;
mutex_exit(&log_sys->mutex);
- if (server_busy || !buf_pool_check_no_pending_io()) {
+ if (server_busy) {
+ if (srv_print_verbose_log && count > 600) {
+ ut_print_timestamp(stderr);
+ fprintf(stderr,
+ " InnoDB: Pending checkpoint_writes: %lu\n"
+ " InnoDB: Pending log flush writes: %lu\n",
+ (ulong) log_sys->n_pending_checkpoint_writes,
+ (ulong) log_sys->n_pending_writes);
+ count = 0;
+ }
+
goto loop;
}
+ pending_io = buf_pool_check_num_pending_io();
+
+ if (pending_io) {
+ if (srv_print_verbose_log && count > 600) {
+ ut_print_timestamp(stderr);
+ fprintf(stderr, " InnoDB: Waiting for %lu buffer page "
+ "I/Os to complete\n",
+ (ulong) pending_io);
+ count = 0;
+ }
+
+ goto loop;
+ }
+
+
#ifdef UNIV_LOG_ARCHIVE
log_archive_all();
#endif /* UNIV_LOG_ARCHIVE */
@@ -3310,7 +3380,7 @@ loop:
log_buffer_flush_to_disk();
/* Check that the background threads stay suspended */
- if (srv_is_any_background_thread_active()) {
+ if (srv_get_active_thread_type() != ULINT_UNDEFINED) {
fprintf(stderr,
"InnoDB: Warning: some background thread"
" woke up during shutdown\n");
@@ -3319,7 +3389,7 @@ loop:
srv_shutdown_state = SRV_SHUTDOWN_LAST_PHASE;
fil_close_all_files();
- ut_a(!srv_is_any_background_thread_active());
+ ut_a(srv_get_active_thread_type() == ULINT_UNDEFINED);
return;
}
@@ -3357,7 +3427,7 @@ loop:
mutex_exit(&log_sys->mutex);
/* Check that the background threads stay suspended */
- if (srv_is_any_background_thread_active()) {
+ if (srv_get_active_thread_type() != ULINT_UNDEFINED) {
fprintf(stderr,
"InnoDB: Warning: some background thread woke up"
" during shutdown\n");
@@ -3375,13 +3445,20 @@ loop:
if (!buf_all_freed()) {
+ if (srv_print_verbose_log && count > 600) {
+ ut_print_timestamp(stderr);
+ fprintf(stderr, " InnoDB: Waiting for dirty buffer "
+ "pages to be flushed\n");
+ count = 0;
+ }
+
goto loop;
}
srv_shutdown_state = SRV_SHUTDOWN_LAST_PHASE;
/* Make some checks that the server really is quiet */
- ut_a(!srv_is_any_background_thread_active());
+ ut_a(srv_get_active_thread_type() == ULINT_UNDEFINED);
ut_a(buf_all_freed());
ut_a(lsn == log_sys->lsn);
@@ -3403,7 +3480,7 @@ loop:
fil_close_all_files();
/* Make some checks that the server really is quiet */
- ut_a(!srv_is_any_background_thread_active());
+ ut_a(srv_get_active_thread_type() == ULINT_UNDEFINED);
ut_a(buf_all_freed());
ut_a(lsn == log_sys->lsn);
diff --git a/storage/xtradb/mem/mem0pool.c b/storage/xtradb/mem/mem0pool.c
index dc68cf8eb24..50dbe526d64 100644
--- a/storage/xtradb/mem/mem0pool.c
+++ b/storage/xtradb/mem/mem0pool.c
@@ -228,11 +228,7 @@ mem_pool_create(
pool = ut_malloc(sizeof(mem_pool_t));
- /* We do not set the memory to zero (FALSE) in the pool,
- but only when allocated at a higher level in mem0mem.c.
- This is to avoid masking useful Purify warnings. */
-
- pool->buf = ut_malloc_low(size, FALSE, TRUE);
+ pool->buf = ut_malloc_low(size, TRUE);
pool->size = size;
mutex_create(mem_pool_mutex_key, &pool->mutex, SYNC_MEM_POOL);
diff --git a/storage/xtradb/mtr/mtr0mtr.c b/storage/xtradb/mtr/mtr0mtr.c
index 529af43d2e0..092bd702115 100644
--- a/storage/xtradb/mtr/mtr0mtr.c
+++ b/storage/xtradb/mtr/mtr0mtr.c
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1995, 2009, Innobase Oy. All Rights Reserved.
+Copyright (c) 1995, 2012, Oracle and/or its affiliates. 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
@@ -11,8 +11,8 @@ 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 program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
*****************************************************************************/
diff --git a/storage/xtradb/os/os0file.c b/storage/xtradb/os/os0file.c
index 875aea7878d..075a2ac4a12 100644
--- a/storage/xtradb/os/os0file.c
+++ b/storage/xtradb/os/os0file.c
@@ -3339,7 +3339,91 @@ retry:
fprintf(stderr,
"InnoDB: You can disable Linux Native AIO by"
- " setting innodb_native_aio = off in my.cnf\n");
+ " setting innodb_use_native_aio = 0 in my.cnf\n");
+ return(FALSE);
+}
+
+/******************************************************************//**
+Checks if the system supports native linux aio. On some kernel
+versions where native aio is supported it won't work on tmpfs. In such
+cases we can't use native aio as it is not possible to mix simulated
+and native aio.
+@return: TRUE if supported, FALSE otherwise. */
+static
+ibool
+os_aio_native_aio_supported(void)
+/*=============================*/
+{
+ int fd;
+ byte* buf;
+ byte* ptr;
+ struct io_event io_event;
+ io_context_t io_ctx;
+ struct iocb iocb;
+ struct iocb* p_iocb;
+ int err;
+
+ if (!os_aio_linux_create_io_ctx(1, &io_ctx)) {
+ /* The platform does not support native aio. */
+ return(FALSE);
+ }
+
+ /* Now check if tmpdir supports native aio ops. */
+ fd = innobase_mysql_tmpfile();
+
+ if (fd < 0) {
+ ut_print_timestamp(stderr);
+ fprintf(stderr, " InnoDB: Error: unable to create "
+ "temp file to check native AIO support.\n");
+
+ return(FALSE);
+ }
+
+ memset(&io_event, 0x0, sizeof(io_event));
+
+ buf = (byte*) ut_malloc(UNIV_PAGE_SIZE * 2);
+ ptr = (byte*) ut_align(buf, UNIV_PAGE_SIZE);
+
+ /* Suppress valgrind warning. */
+ memset(buf, 0x00, UNIV_PAGE_SIZE * 2);
+
+ memset(&iocb, 0x0, sizeof(iocb));
+ p_iocb = &iocb;
+ io_prep_pwrite(p_iocb, fd, ptr, UNIV_PAGE_SIZE, 0);
+
+ err = io_submit(io_ctx, 1, &p_iocb);
+ if (err >= 1) {
+ /* Now collect the submitted IO request. */
+ err = io_getevents(io_ctx, 1, 1, &io_event, NULL);
+ }
+
+ ut_free(buf);
+ close(fd);
+
+ switch (err) {
+ case 1:
+ return(TRUE);
+
+ case -EINVAL:
+ case -ENOSYS:
+ ut_print_timestamp(stderr);
+ fprintf(stderr,
+ " InnoDB: Error: Linux Native AIO is not"
+ " supported on tmpdir.\n"
+ "InnoDB: You can either move tmpdir to a"
+ " file system that supports native AIO\n"
+ "InnoDB: or you can set"
+ " innodb_use_native_aio to FALSE to avoid"
+ " this message.\n");
+
+ /* fall through. */
+ default:
+ ut_print_timestamp(stderr);
+ fprintf(stderr,
+ " InnoDB: Error: Linux Native AIO check"
+ " on tmpdir returned error[%d]\n", -err);
+ }
+
return(FALSE);
}
#endif /* LINUX_NATIVE_AIO */
@@ -3400,12 +3484,23 @@ os_aio_array_create(
if (!os_aio_linux_create_io_ctx(n/n_segments,
&array->aio_ctx[i])) {
/* If something bad happened during aio setup
- we should call it a day and return right away.
- We don't care about any leaks because a failure
- to initialize the io subsystem means that the
- server (or atleast the innodb storage engine)
- is not going to startup. */
- return(NULL);
+ we disable linux native aio.
+ The disadvantage will be a small memory leak
+ at shutdown but that's ok compared to a crash
+ or a not working server.
+ This frequently happens when running the test suite
+ with many threads on a system with low fs.aio-max-nr!
+ */
+
+ fprintf(stderr,
+ " InnoDB: Warning: Linux Native AIO disabled "
+ "because os_aio_linux_create_io_ctx() "
+ "failed. To get rid of this warning you can "
+ "try increasing system "
+ "fs.aio-max-nr to 1048576 or larger or "
+ "setting innodb_use_native_aio = 0 in my.cnf\n");
+ srv_use_native_aio = FALSE;
+ goto skip_native_aio;
}
}
@@ -3479,6 +3574,19 @@ os_aio_init(
os_io_init_simple();
+#if defined(LINUX_NATIVE_AIO)
+ /* Check if native aio is supported on this system and tmpfs */
+ if (srv_use_native_aio
+ && !os_aio_native_aio_supported()) {
+
+ ut_print_timestamp(stderr);
+ fprintf(stderr,
+ " InnoDB: Warning: Linux Native AIO"
+ " disabled.\n");
+ srv_use_native_aio = FALSE;
+ }
+#endif /* LINUX_NATIVE_AIO */
+
for (i = 0; i < n_segments; i++) {
srv_set_io_thread_op_info(i, "not started yet");
}
diff --git a/storage/xtradb/os/os0proc.c b/storage/xtradb/os/os0proc.c
index 0f56a608f38..68321e1aaf9 100644
--- a/storage/xtradb/os/os0proc.c
+++ b/storage/xtradb/os/os0proc.c
@@ -111,9 +111,6 @@ os_mem_alloc_large(
os_fast_mutex_lock(&ut_list_mutex);
ut_total_allocated_memory += size;
os_fast_mutex_unlock(&ut_list_mutex);
-# ifdef UNIV_SET_MEM_TO_ZERO
- memset(ptr, '\0', size);
-# endif
UNIV_MEM_ALLOC(ptr, size);
return(ptr);
}
diff --git a/storage/xtradb/os/os0thread.c b/storage/xtradb/os/os0thread.c
index 12b6805d98e..b19b5378fcd 100644
--- a/storage/xtradb/os/os0thread.c
+++ b/storage/xtradb/os/os0thread.c
@@ -136,8 +136,10 @@ os_thread_create(
if (thread_id) {
*thread_id = win_thread_id;
}
-
- return(thread);
+ if (thread) {
+ CloseHandle(thread);
+ }
+ return((os_thread_t)win_thread_id);
#else
int ret;
os_thread_t pthread;
diff --git a/storage/xtradb/page/page0cur.c b/storage/xtradb/page/page0cur.c
index 936762b986a..d49b121afab 100644
--- a/storage/xtradb/page/page0cur.c
+++ b/storage/xtradb/page/page0cur.c
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1994, 2009, Innobase Oy. All Rights Reserved.
+Copyright (c) 1994, 2012, Oracle and/or its affiliates. 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
@@ -11,8 +11,8 @@ 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 program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
*****************************************************************************/
@@ -900,7 +900,7 @@ page_cur_parse_insert_rec(
ut_print_buf(stderr, ptr2, 300);
putc('\n', stderr);
- buf_page_print(page, 0);
+ buf_page_print(page, 0, 0);
ut_error;
}
@@ -1180,14 +1180,15 @@ page_cur_insert_rec_zip_reorg(
/* Before trying to reorganize the page,
store the number of preceding records on the page. */
pos = page_rec_get_n_recs_before(rec);
+ ut_ad(pos > 0);
if (page_zip_reorganize(block, index, mtr)) {
/* The page was reorganized: Find rec by seeking to pos,
and update *current_rec. */
- rec = page + PAGE_NEW_INFIMUM;
-
- while (--pos) {
- rec = page + rec_get_next_offs(rec, TRUE);
+ if (pos > 1) {
+ rec = page_rec_get_nth(page, pos - 1);
+ } else {
+ rec = page + PAGE_NEW_INFIMUM;
}
*current_rec = rec;
@@ -1283,6 +1284,12 @@ page_cur_insert_rec_zip(
insert_rec = page_cur_insert_rec_zip_reorg(
current_rec, block, index, insert_rec,
page, page_zip, mtr);
+#ifdef UNIV_DEBUG
+ if (insert_rec) {
+ rec_offs_make_valid(
+ insert_rec, index, offsets);
+ }
+#endif /* UNIV_DEBUG */
}
return(insert_rec);
diff --git a/storage/xtradb/page/page0page.c b/storage/xtradb/page/page0page.c
index 4858929082a..4a389bbe5b8 100644
--- a/storage/xtradb/page/page0page.c
+++ b/storage/xtradb/page/page0page.c
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1994, 2010, Innobase Oy. All Rights Reserved.
+Copyright (c) 1994, 2012, Oracle and/or its affiliates. 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
@@ -11,8 +11,8 @@ 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 program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
*****************************************************************************/
@@ -148,7 +148,7 @@ page_dir_find_owner_slot(
fputs("\n"
"InnoDB: on that page!\n", stderr);
- buf_page_print(page, 0);
+ buf_page_print(page, 0, 0);
ut_error;
}
@@ -549,8 +549,7 @@ page_copy_rec_list_end_no_locks(
page_cur_move_to_next(&cur1);
}
- ut_a((ibool)!!page_is_comp(new_page)
- == dict_table_is_comp(index->table));
+ btr_assert_not_corrupted(new_block, index);
ut_a(page_is_comp(new_page) == page_rec_is_comp(rec));
ut_a(mach_read_from_2(new_page + UNIV_PAGE_SIZE - 10) == (ulint)
(page_is_comp(new_page) ? PAGE_NEW_INFIMUM : PAGE_OLD_INFIMUM));
@@ -570,8 +569,10 @@ page_copy_rec_list_end_no_locks(
/* Track an assertion failure reported on the mailing
list on June 18th, 2003 */
- buf_page_print(new_page, 0);
- buf_page_print(page_align(rec), 0);
+ buf_page_print(new_page, 0,
+ BUF_PAGE_PRINT_NO_CRASH);
+ buf_page_print(page_align(rec), 0,
+ BUF_PAGE_PRINT_NO_CRASH);
ut_print_timestamp(stderr);
fprintf(stderr,
@@ -1453,55 +1454,54 @@ page_dir_balance_slot(
}
}
-#ifndef UNIV_HOTBACKUP
/************************************************************//**
-Returns the middle record of the record list. If there are an even number
-of records in the list, returns the first record of the upper half-list.
-@return middle record */
+Returns the nth record of the record list.
+This is the inverse function of page_rec_get_n_recs_before().
+@return nth record */
UNIV_INTERN
-rec_t*
-page_get_middle_rec(
-/*================*/
- page_t* page) /*!< in: page */
+const rec_t*
+page_rec_get_nth_const(
+/*===================*/
+ const page_t* page, /*!< in: page */
+ ulint nth) /*!< in: nth record */
{
- page_dir_slot_t* slot;
- ulint middle;
+ const page_dir_slot_t* slot;
ulint i;
ulint n_owned;
- ulint count;
- rec_t* rec;
-
- /* This many records we must leave behind */
- middle = (page_get_n_recs(page) + PAGE_HEAP_NO_USER_LOW) / 2;
+ const rec_t* rec;
- count = 0;
+ ut_ad(nth < UNIV_PAGE_SIZE / (REC_N_NEW_EXTRA_BYTES + 1));
for (i = 0;; i++) {
slot = page_dir_get_nth_slot(page, i);
n_owned = page_dir_slot_get_n_owned(slot);
- if (count + n_owned > middle) {
+ if (n_owned > nth) {
break;
} else {
- count += n_owned;
+ nth -= n_owned;
}
}
ut_ad(i > 0);
slot = page_dir_get_nth_slot(page, i - 1);
- rec = (rec_t*) page_dir_slot_get_rec(slot);
- rec = page_rec_get_next(rec);
-
- /* There are now count records behind rec */
+ rec = page_dir_slot_get_rec(slot);
- for (i = 0; i < middle - count; i++) {
- rec = page_rec_get_next(rec);
+ if (page_is_comp(page)) {
+ do {
+ rec = page_rec_get_next_low(rec, TRUE);
+ ut_ad(rec);
+ } while (nth--);
+ } else {
+ do {
+ rec = page_rec_get_next_low(rec, FALSE);
+ ut_ad(rec);
+ } while (nth--);
}
return(rec);
}
-#endif /* !UNIV_HOTBACKUP */
/***************************************************************//**
Returns the number of records before the given record in chain.
@@ -1563,6 +1563,7 @@ page_rec_get_n_recs_before(
n--;
ut_ad(n >= 0);
+ ut_ad((ulint)n < UNIV_PAGE_SIZE / (REC_N_NEW_EXTRA_BYTES + 1));
return((ulint) n);
}
@@ -1835,7 +1836,7 @@ page_check_dir(
fprintf(stderr,
"InnoDB: Page directory corruption:"
" infimum not pointed to\n");
- buf_page_print(page, 0);
+ buf_page_print(page, 0, 0);
}
if (UNIV_UNLIKELY(!page_rec_is_supremum_low(supremum_offs))) {
@@ -1843,7 +1844,7 @@ page_check_dir(
fprintf(stderr,
"InnoDB: Page directory corruption:"
" supremum not pointed to\n");
- buf_page_print(page, 0);
+ buf_page_print(page, 0, 0);
}
}
#endif /* !UNIV_HOTBACKUP */
@@ -2547,7 +2548,7 @@ func_exit2:
(ulong) page_get_space_id(page),
(ulong) page_get_page_no(page),
index->name);
- buf_page_print(page, 0);
+ buf_page_print(page, 0, 0);
}
return(ret);
diff --git a/storage/xtradb/pars/pars0pars.c b/storage/xtradb/pars/pars0pars.c
index ef107f2896f..86f54195682 100644
--- a/storage/xtradb/pars/pars0pars.c
+++ b/storage/xtradb/pars/pars0pars.c
@@ -1857,7 +1857,7 @@ pars_sql(
ut_ad(str);
- heap = mem_heap_create(256);
+ heap = mem_heap_create(16000);
/* Currently, the parser is not reentrant: */
ut_ad(mutex_own(&(dict_sys->mutex)));
diff --git a/storage/xtradb/rem/rem0rec.c b/storage/xtradb/rem/rem0rec.c
index 15618a3fa02..0cee1ffb3c8 100644
--- a/storage/xtradb/rem/rem0rec.c
+++ b/storage/xtradb/rem/rem0rec.c
@@ -1803,7 +1803,10 @@ wsrep_rec_get_primary_key(
ut_ad(rec);
key_parts = dict_index_get_n_unique_in_tree(index);
- for (i = 0; i < key_parts; i++) {
+ for (i = 0;
+ i < key_parts && (index->type & DICT_CLUSTERED || i < key_parts - 1);
+ i++) {
+
dict_field_t* field = dict_index_get_nth_field(index, i);
const dict_col_t* col = dict_field_get_col(field);
diff --git a/storage/xtradb/row/row0ins.c b/storage/xtradb/row/row0ins.c
index bc722d56203..9fbb5122a82 100644
--- a/storage/xtradb/row/row0ins.c
+++ b/storage/xtradb/row/row0ins.c
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1996, 2010, Innobase Oy. All Rights Reserved.
+Copyright (c) 1996, 2012, Oracle and/or its affiliates. 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
@@ -11,8 +11,8 @@ 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 program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
*****************************************************************************/
@@ -23,6 +23,8 @@ Insert into a table
Created 4/20/1996 Heikki Tuuri
*******************************************************/
+#include "m_string.h" /* for my_sys.h */
+#include "my_sys.h" /* DEBUG_SYNC_C */
#include "row0ins.h"
#ifdef UNIV_NONINL
@@ -47,6 +49,8 @@ Created 4/20/1996 Heikki Tuuri
#include "data0data.h"
#include "usr0sess.h"
#include "buf0lru.h"
+#include "m_string.h"
+#include "my_sys.h"
#define ROW_INS_PREV 1
#define ROW_INS_NEXT 2
@@ -348,9 +352,9 @@ row_ins_clust_index_entry_by_modify(
return(DB_LOCK_TABLE_FULL);
}
- err = btr_cur_pessimistic_update(0, cursor,
- heap, big_rec, update,
- 0, thr, mtr);
+ err = btr_cur_pessimistic_update(
+ BTR_KEEP_POS_FLAG, cursor, heap, big_rec, update,
+ 0, thr, mtr);
}
return(err);
@@ -757,7 +761,8 @@ ulint wsrep_append_foreign_key(trx_t *trx,
dict_foreign_t* foreign,
const rec_t* clust_rec,
dict_index_t* clust_index,
- ibool shared);
+ ibool referenced,
+ ibool shared);
#endif /* WITH_WSREP */
/*********************************************************************//**
@@ -957,7 +962,7 @@ row_ins_foreign_check_on_constraint(
fputs("\n"
"InnoDB: Submit a detailed bug report to"
" http://bugs.mysql.com\n", stderr);
-
+ ut_ad(0);
err = DB_SUCCESS;
goto nonstandard_exit_func;
@@ -1082,7 +1087,7 @@ row_ins_foreign_check_on_constraint(
foreign,
clust_rec,
clust_index,
- FALSE);
+ FALSE, FALSE);
}
#endif /* WITH_WSREP */
if (foreign->foreign_table->n_foreign_key_checks_running == 0) {
@@ -1100,6 +1105,9 @@ row_ins_foreign_check_on_constraint(
release the latch. */
row_mysql_unfreeze_data_dictionary(thr_get_trx(thr));
+
+ DEBUG_SYNC_C("innodb_dml_cascade_dict_unfreeze");
+
row_mysql_freeze_data_dictionary(thr_get_trx(thr));
mtr_start(mtr);
@@ -1421,12 +1429,22 @@ run_again:
if (check_ref) {
err = DB_SUCCESS;
#ifdef WITH_WSREP
- err = wsrep_append_foreign_key(
- thr_get_trx(thr),
- foreign,
- rec,
- check_index,
- TRUE);
+ if (thr->fk_cascade_depth == 0) {
+ err = wsrep_append_foreign_key(
+ thr_get_trx(thr),
+ foreign,
+ rec,
+ check_index,
+ check_ref, TRUE);
+ } else {
+ fprintf(stderr, "WSREP: skipping FK key append\n");
+ err = wsrep_append_foreign_key(
+ thr_get_trx(thr),
+ foreign,
+ rec,
+ check_index,
+ TRUE, TRUE);
+ }
#endif /* WITH_WSREP */
goto end_scan;
} else if (foreign->type != 0) {
@@ -1457,6 +1475,14 @@ run_again:
goto end_scan;
}
+#ifdef WITH_WSREP_REMOVED
+ err = wsrep_append_foreign_key(
+ thr_get_trx(thr),
+ foreign,
+ rec,
+ check_index,
+ FALSE);
+#endif /* WITH_WSREP */
/* row_ins_foreign_check_on_constraint
may have repositioned pcur on a
different block */
@@ -2036,6 +2062,7 @@ row_ins_index_entry_low(
ulint modify = 0; /* remove warning */
rec_t* insert_rec;
rec_t* rec;
+ ulint* offsets;
ulint err;
ulint n_unique;
big_rec_t* big_rec = NULL;
@@ -2145,6 +2172,64 @@ row_ins_index_entry_low(
err = row_ins_clust_index_entry_by_modify(
mode, &cursor, &heap, &big_rec, entry,
thr, &mtr);
+
+ if (big_rec) {
+ ut_a(err == DB_SUCCESS);
+ /* Write out the externally stored
+ columns while still x-latching
+ index->lock and block->lock. Allocate
+ pages for big_rec in the mtr that
+ modified the B-tree, but be sure to skip
+ any pages that were freed in mtr. We will
+ write out the big_rec pages before
+ committing the B-tree mini-transaction. If
+ the system crashes so that crash recovery
+ will not replay the mtr_commit(&mtr), the
+ big_rec pages will be left orphaned until
+ the pages are allocated for something else.
+
+ TODO: If the allocation extends the
+ tablespace, it will not be redo
+ logged, in either mini-transaction.
+ Tablespace extension should be
+ redo-logged in the big_rec
+ mini-transaction, so that recovery
+ will not fail when the big_rec was
+ written to the extended portion of the
+ file, in case the file was somehow
+ truncated in the crash. */
+
+ rec = btr_cur_get_rec(&cursor);
+ offsets = rec_get_offsets(
+ rec, index, NULL,
+ ULINT_UNDEFINED, &heap);
+
+ DEBUG_SYNC_C("before_row_ins_upd_extern");
+ err = btr_store_big_rec_extern_fields(
+ index, btr_cur_get_block(&cursor),
+ rec, offsets, big_rec, &mtr,
+ BTR_STORE_INSERT_UPDATE);
+ DEBUG_SYNC_C("after_row_ins_upd_extern");
+ /* If writing big_rec fails (for
+ example, because of DB_OUT_OF_FILE_SPACE),
+ the record will be corrupted. Even if
+ we did not update any externally
+ stored columns, our update could cause
+ the record to grow so that a
+ non-updated column was selected for
+ external storage. This non-update
+ would not have been written to the
+ undo log, and thus the record cannot
+ be rolled back.
+
+ However, because we have not executed
+ mtr_commit(mtr) yet, the update will
+ not be replayed in crash recovery, and
+ the following assertion failure will
+ effectively "roll back" the operation. */
+ ut_a(err == DB_SUCCESS);
+ goto stored_big_rec;
+ }
} else {
ut_ad(!n_ext);
err = row_ins_sec_index_entry_by_modify(
@@ -2191,8 +2276,13 @@ function_exit:
return(err);
}
+ DBUG_EXECUTE_IF(
+ "row_ins_extern_checkpoint",
+ log_make_checkpoint_at(IB_ULONGLONG_MAX, TRUE););
+
mtr_start(&mtr);
+ DEBUG_SYNC_C("before_row_ins_extern_latch");
btr_cur_search_to_nth_level(index, 0, entry, PAGE_CUR_LE,
BTR_MODIFY_TREE, &cursor, 0,
__FILE__, __LINE__, &mtr);
@@ -2200,10 +2290,13 @@ function_exit:
offsets = rec_get_offsets(rec, index, NULL,
ULINT_UNDEFINED, &heap);
+ DEBUG_SYNC_C("before_row_ins_extern");
err = btr_store_big_rec_extern_fields(
index, btr_cur_get_block(&cursor),
- rec, offsets, &mtr, FALSE, big_rec);
+ rec, offsets, big_rec, &mtr, BTR_STORE_INSERT);
+ DEBUG_SYNC_C("after_row_ins_extern");
+stored_big_rec:
if (modify) {
dtuple_big_rec_free(big_rec);
} else {
diff --git a/storage/xtradb/row/row0merge.c b/storage/xtradb/row/row0merge.c
index 9390946ad88..f00706da0d3 100644
--- a/storage/xtradb/row/row0merge.c
+++ b/storage/xtradb/row/row0merge.c
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 2005, 2010, Innobase Oy. All Rights Reserved.
+Copyright (c) 1995, 2012, Oracle and/or its affiliates. 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
@@ -1607,22 +1607,28 @@ row_merge(
const dict_index_t* index, /*!< in: index being created */
merge_file_t* file, /*!< in/out: file containing
index entries */
- ulint* half, /*!< in/out: half the file */
row_merge_block_t* block, /*!< in/out: 3 buffers */
int* tmpfd, /*!< in/out: temporary file handle */
- struct TABLE* table) /*!< in/out: MySQL table, for
+ struct TABLE* table, /*!< in/out: MySQL table, for
reporting erroneous key value
if applicable */
+ ulint* num_run,/*!< in/out: Number of runs remain
+ to be merged */
+ ulint* run_offset) /*!< in/out: Array contains the
+ first offset number for each merge
+ run */
{
ulint foffs0; /*!< first input offset */
ulint foffs1; /*!< second input offset */
ulint error; /*!< error code */
merge_file_t of; /*!< output file */
- const ulint ihalf = *half;
+ const ulint ihalf = run_offset[*num_run / 2];
/*!< half the input file */
- ulint ohalf; /*!< half the output file */
+ ulint n_run = 0;
+ /*!< num of runs generated from this merge */
UNIV_MEM_ASSERT_W(block[0], 3 * sizeof block[0]);
+
ut_ad(ihalf < file->offset);
of.fd = *tmpfd;
@@ -1638,17 +1644,20 @@ row_merge(
#endif /* POSIX_FADV_SEQUENTIAL */
/* Merge blocks to the output file. */
- ohalf = 0;
foffs0 = 0;
foffs1 = ihalf;
+ UNIV_MEM_INVALID(run_offset, *num_run * sizeof *run_offset);
+
for (; foffs0 < ihalf && foffs1 < file->offset; foffs0++, foffs1++) {
- ulint ahalf; /*!< arithmetic half the input file */
if (UNIV_UNLIKELY(trx_is_interrupted(trx))) {
return(DB_INTERRUPTED);
}
+ /* Remember the offset number for this run */
+ run_offset[n_run++] = of.offset;
+
error = row_merge_blocks(index, file, block,
&foffs0, &foffs1, &of, table);
@@ -1656,21 +1665,6 @@ row_merge(
return(error);
}
- /* Record the offset of the output file when
- approximately half the output has been generated. In
- this way, the next invocation of row_merge() will
- spend most of the time in this loop. The initial
- estimate is ohalf==0. */
- ahalf = file->offset / 2;
- ut_ad(ohalf <= of.offset);
-
- /* Improve the estimate until reaching half the input
- file size, or we can not get any closer to it. All
- comparands should be non-negative when !(ohalf < ahalf)
- because ohalf <= of.offset. */
- if (ohalf < ahalf || of.offset - ahalf < ohalf - ahalf) {
- ohalf = of.offset;
- }
}
/* Copy the last blocks, if there are any. */
@@ -1680,6 +1674,9 @@ row_merge(
return(DB_INTERRUPTED);
}
+ /* Remember the offset number for this run */
+ run_offset[n_run++] = of.offset;
+
if (!row_merge_blocks_copy(index, file, block, &foffs0, &of)) {
return(DB_CORRUPTION);
}
@@ -1692,6 +1689,9 @@ row_merge(
return(DB_INTERRUPTED);
}
+ /* Remember the offset number for this run */
+ run_offset[n_run++] = of.offset;
+
if (!row_merge_blocks_copy(index, file, block, &foffs1, &of)) {
return(DB_CORRUPTION);
}
@@ -1703,10 +1703,23 @@ row_merge(
return(DB_CORRUPTION);
}
+ ut_ad(n_run <= *num_run);
+
+ *num_run = n_run;
+
+ /* Each run can contain one or more offsets. As merge goes on,
+ the number of runs (to merge) will reduce until we have one
+ single run. So the number of runs will always be smaller than
+ the number of offsets in file */
+ ut_ad((*num_run) <= file->offset);
+
+ /* The number of offsets in output file is always equal or
+ smaller than input file */
+ ut_ad(of.offset <= file->offset);
+
/* Swap file descriptors for the next pass. */
*tmpfd = file->fd;
*file = of;
- *half = ohalf;
UNIV_MEM_INVALID(block[0], 3 * sizeof block[0]);
@@ -1731,27 +1744,44 @@ row_merge_sort(
if applicable */
{
ulint half = file->offset / 2;
+ ulint num_runs;
+ ulint* run_offset;
+ ulint error = DB_SUCCESS;
+
+ /* Record the number of merge runs we need to perform */
+ num_runs = file->offset;
+
+ /* If num_runs are less than 1, nothing to merge */
+ if (num_runs <= 1) {
+ return(error);
+ }
+
+ /* "run_offset" records each run's first offset number */
+ run_offset = (ulint*) mem_alloc(file->offset * sizeof(ulint));
+
+ /* This tells row_merge() where to start for the first round
+ of merge. */
+ run_offset[half] = half;
/* The file should always contain at least one byte (the end
of file marker). Thus, it must be at least one block. */
ut_ad(file->offset > 0);
+ /* Merge the runs until we have one big run */
do {
- ulint error;
+ error = row_merge(trx, index, file, block, tmpfd,
+ table, &num_runs, run_offset);
- error = row_merge(trx, index, file, &half,
- block, tmpfd, table);
+ UNIV_MEM_ASSERT_RW(run_offset, num_runs * sizeof *run_offset);
if (error != DB_SUCCESS) {
- return(error);
+ break;
}
+ } while (num_runs > 1);
- /* half > 0 should hold except when the file consists
- of one block. No need to merge further then. */
- ut_ad(half > 0 || file->offset == 1);
- } while (half < file->offset && half > 0);
+ mem_free(run_offset);
- return(DB_SUCCESS);
+ return(error);
}
/*************************************************************//**
@@ -2018,7 +2048,7 @@ row_merge_drop_index(
tables in Innobase. Deleting a row from SYS_INDEXES table also
frees the file segments of the B-tree associated with the index. */
- static const char str1[] =
+ static const char sql[] =
"PROCEDURE DROP_INDEX_PROC () IS\n"
"BEGIN\n"
/* Rename the index, so that it will be dropped by
@@ -2044,9 +2074,19 @@ row_merge_drop_index(
ut_a(trx->dict_operation_lock_mode == RW_X_LATCH);
- err = que_eval_sql(info, str1, FALSE, trx);
+ err = que_eval_sql(info, sql, FALSE, trx);
+
- ut_a(err == DB_SUCCESS);
+ if (err != DB_SUCCESS) {
+ /* Even though we ensure that DDL transactions are WAIT
+ and DEADLOCK free, we could encounter other errors e.g.,
+ DB_TOO_MANY_TRANSACTIONS. */
+ trx->error_state = DB_SUCCESS;
+
+ ut_print_timestamp(stderr);
+ fprintf(stderr, " InnoDB: Error: row_merge_drop_index failed "
+ "with error code: %lu.\n", (ulint) err);
+ }
/* Replace this index with another equivalent index for all
foreign key constraints on this table where this index is used */
@@ -2346,7 +2386,7 @@ row_merge_rename_indexes(
/* We use the private SQL parser of Innobase to generate the
query graphs needed in renaming indexes. */
- static const char rename_indexes[] =
+ static const char sql[] =
"PROCEDURE RENAME_INDEXES_PROC () IS\n"
"BEGIN\n"
"UPDATE SYS_INDEXES SET NAME=SUBSTR(NAME,1,LENGTH(NAME)-1)\n"
@@ -2362,7 +2402,7 @@ row_merge_rename_indexes(
pars_info_add_ull_literal(info, "tableid", table->id);
- err = que_eval_sql(info, rename_indexes, FALSE, trx);
+ err = que_eval_sql(info, sql, FALSE, trx);
if (err == DB_SUCCESS) {
dict_index_t* index = dict_table_get_first_index(table);
@@ -2372,6 +2412,15 @@ row_merge_rename_indexes(
}
index = dict_table_get_next_index(index);
} while (index);
+ } else {
+ /* Even though we ensure that DDL transactions are WAIT
+ and DEADLOCK free, we could encounter other errors e.g.,
+ DB_TOO_MANY_TRANSACTIONS. */
+ trx->error_state = DB_SUCCESS;
+
+ ut_print_timestamp(stderr);
+ fprintf(stderr, " InnoDB: Error: row_merge_rename_indexes "
+ "failed with error code: %lu.\n", (ulint) err);
}
trx->op_info = "";
@@ -2409,7 +2458,7 @@ row_merge_rename_tables(
memcpy(old_name, old_table->name, strlen(old_table->name) + 1);
} else {
ut_print_timestamp(stderr);
- fprintf(stderr, "InnoDB: too long table name: '%s', "
+ fprintf(stderr, " InnoDB: too long table name: '%s', "
"max length is %d\n", old_table->name,
MAX_FULL_NAME_LEN);
ut_error;
diff --git a/storage/xtradb/row/row0mysql.c b/storage/xtradb/row/row0mysql.c
index 63252ed01b3..575160501c3 100644
--- a/storage/xtradb/row/row0mysql.c
+++ b/storage/xtradb/row/row0mysql.c
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 2000, 2011, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2000, 2012, Oracle and/or its affiliates. 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
@@ -11,8 +11,8 @@ 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 program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
*****************************************************************************/
@@ -53,6 +53,8 @@ Created 9/17/2000 Heikki Tuuri
#include "fil0fil.h"
#include "ibuf0ibuf.h"
#include "ha_prototypes.h"
+#include "m_string.h"
+#include "my_sys.h"
/** Provide optional 4.x backwards compatibility for 5.0 and above */
UNIV_INTERN ibool row_rollback_on_timeout = FALSE;
@@ -669,17 +671,60 @@ UNIV_INTERN
row_prebuilt_t*
row_create_prebuilt(
/*================*/
- dict_table_t* table) /*!< in: Innobase table handle */
+ dict_table_t* table, /*!< in: Innobase table handle */
+ ulint mysql_row_len) /*!< in: length in bytes of a row in
+ the MySQL format */
{
row_prebuilt_t* prebuilt;
mem_heap_t* heap;
dict_index_t* clust_index;
dtuple_t* ref;
ulint ref_len;
+ ulint search_tuple_n_fields;
+
+ search_tuple_n_fields = 2 * dict_table_get_n_cols(table);
- heap = mem_heap_create(sizeof *prebuilt + 128);
+ clust_index = dict_table_get_first_index(table);
- prebuilt = mem_heap_zalloc(heap, sizeof *prebuilt);
+ /* Make sure that search_tuple is long enough for clustered index */
+ ut_a(2 * dict_table_get_n_cols(table) >= clust_index->n_fields);
+
+ ref_len = dict_index_get_n_unique(clust_index);
+
+#define PREBUILT_HEAP_INITIAL_SIZE \
+ ( \
+ sizeof(*prebuilt) \
+ /* allocd in this function */ \
+ + DTUPLE_EST_ALLOC(search_tuple_n_fields) \
+ + DTUPLE_EST_ALLOC(ref_len) \
+ /* allocd in row_prebuild_sel_graph() */ \
+ + sizeof(sel_node_t) \
+ + sizeof(que_fork_t) \
+ + sizeof(que_thr_t) \
+ /* allocd in row_get_prebuilt_update_vector() */ \
+ + sizeof(upd_node_t) \
+ + sizeof(upd_t) \
+ + sizeof(upd_field_t) \
+ * dict_table_get_n_cols(table) \
+ + sizeof(que_fork_t) \
+ + sizeof(que_thr_t) \
+ /* allocd in row_get_prebuilt_insert_row() */ \
+ + sizeof(ins_node_t) \
+ /* mysql_row_len could be huge and we are not \
+ sure if this prebuilt instance is going to be \
+ used in inserts */ \
+ + (mysql_row_len < 256 ? mysql_row_len : 0) \
+ + DTUPLE_EST_ALLOC(dict_table_get_n_cols(table)) \
+ + sizeof(que_fork_t) \
+ + sizeof(que_thr_t) \
+ )
+
+ /* We allocate enough space for the objects that are likely to
+ be created later in order to minimize the number of malloc()
+ calls */
+ heap = mem_heap_create(PREBUILT_HEAP_INITIAL_SIZE);
+
+ prebuilt = mem_heap_zalloc(heap, sizeof(*prebuilt));
prebuilt->magic_n = ROW_PREBUILT_ALLOCATED;
prebuilt->magic_n2 = ROW_PREBUILT_ALLOCATED;
@@ -689,23 +734,15 @@ row_create_prebuilt(
prebuilt->sql_stat_start = TRUE;
prebuilt->heap = heap;
- prebuilt->pcur = btr_pcur_create_for_mysql();
- prebuilt->clust_pcur = btr_pcur_create_for_mysql();
+ btr_pcur_reset(&prebuilt->pcur);
+ btr_pcur_reset(&prebuilt->clust_pcur);
prebuilt->select_lock_type = LOCK_NONE;
prebuilt->stored_select_lock_type = 99999999;
UNIV_MEM_INVALID(&prebuilt->stored_select_lock_type,
sizeof prebuilt->stored_select_lock_type);
- prebuilt->search_tuple = dtuple_create(
- heap, 2 * dict_table_get_n_cols(table));
-
- clust_index = dict_table_get_first_index(table);
-
- /* Make sure that search_tuple is long enough for clustered index */
- ut_a(2 * dict_table_get_n_cols(table) >= clust_index->n_fields);
-
- ref_len = dict_index_get_n_unique(clust_index);
+ prebuilt->search_tuple = dtuple_create(heap, search_tuple_n_fields);
ref = dtuple_create(heap, ref_len);
@@ -722,6 +759,8 @@ row_create_prebuilt(
prebuilt->autoinc_last_value = 0;
+ prebuilt->mysql_row_len = mysql_row_len;
+
return(prebuilt);
}
@@ -757,8 +796,8 @@ row_prebuilt_free(
prebuilt->magic_n = ROW_PREBUILT_FREED;
prebuilt->magic_n2 = ROW_PREBUILT_FREED;
- btr_pcur_free_for_mysql(prebuilt->pcur);
- btr_pcur_free_for_mysql(prebuilt->clust_pcur);
+ btr_pcur_reset(&prebuilt->pcur);
+ btr_pcur_reset(&prebuilt->clust_pcur);
if (prebuilt->mysql_template) {
mem_free(prebuilt->mysql_template);
@@ -1419,6 +1458,8 @@ row_update_for_mysql(
return(DB_ERROR);
}
+ DEBUG_SYNC_C("innodb_row_update_for_mysql_begin");
+
trx->op_info = "updating or deleting";
row_mysql_delay_if_needed();
@@ -1429,11 +1470,11 @@ row_update_for_mysql(
clust_index = dict_table_get_first_index(table);
- if (prebuilt->pcur->btr_cur.index == clust_index) {
- btr_pcur_copy_stored_position(node->pcur, prebuilt->pcur);
+ if (prebuilt->pcur.btr_cur.index == clust_index) {
+ btr_pcur_copy_stored_position(node->pcur, &prebuilt->pcur);
} else {
btr_pcur_copy_stored_position(node->pcur,
- prebuilt->clust_pcur);
+ &prebuilt->clust_pcur);
}
ut_a(node->pcur->rel_pos == BTR_PCUR_ON);
@@ -1538,8 +1579,8 @@ row_unlock_for_mysql(
clust_pcur, and we do not need
to reposition the cursors. */
{
- btr_pcur_t* pcur = prebuilt->pcur;
- btr_pcur_t* clust_pcur = prebuilt->clust_pcur;
+ btr_pcur_t* pcur = &prebuilt->pcur;
+ btr_pcur_t* clust_pcur = &prebuilt->clust_pcur;
trx_t* trx = prebuilt->trx;
ut_ad(prebuilt && trx);
@@ -1761,7 +1802,7 @@ row_mysql_freeze_data_dictionary_func(
{
ut_a(trx->dict_operation_lock_mode == 0);
- rw_lock_s_lock_func(&dict_operation_lock, 0, file, line);
+ rw_lock_s_lock_inline(&dict_operation_lock, 0, file, line);
trx->dict_operation_lock_mode = RW_S_LATCH;
}
@@ -1798,7 +1839,7 @@ row_mysql_lock_data_dictionary_func(
/* Serialize data dictionary operations with dictionary mutex:
no deadlocks or lock waits can occur then in these operations */
- rw_lock_x_lock_func(&dict_operation_lock, 0, file, line);
+ rw_lock_x_lock_inline(&dict_operation_lock, 0, file, line);
trx->dict_operation_lock_mode = RW_X_LATCH;
mutex_enter(&(dict_sys->mutex));
@@ -1969,6 +2010,21 @@ err_exit:
}
break;
+ case DB_TOO_MANY_CONCURRENT_TRXS:
+ /* We already have .ibd file here. it should be deleted. */
+
+ if (table->space && !fil_delete_tablespace(table->space,
+ FALSE)) {
+ ut_print_timestamp(stderr);
+ fprintf(stderr,
+ " InnoDB: Error: not able to"
+ " delete tablespace %lu of table ",
+ (ulong) table->space);
+ ut_print_name(stderr, trx, TRUE, table->name);
+ fputs("!\n", stderr);
+ }
+ /* fall through */
+
case DB_DUPLICATE_KEY:
default:
/* We may also get err == DB_ERROR if the .ibd file for the
@@ -3146,6 +3202,7 @@ row_drop_table_for_mysql(
{
dict_foreign_t* foreign;
dict_table_t* table;
+ dict_index_t* index;
ulint space_id;
ulint err;
const char* table_name;
@@ -3353,6 +3410,18 @@ check_next_foreign:
trx_set_dict_operation(trx, TRX_DICT_OP_TABLE);
trx->table_id = table->id;
+ /* Mark all indexes unavailable in the data dictionary cache
+ before starting to drop the table. */
+
+ for (index = dict_table_get_first_index(table);
+ index != NULL;
+ index = dict_table_get_next_index(index)) {
+ rw_lock_x_lock(dict_index_get_lock(index));
+ ut_ad(!index->to_be_dropped);
+ index->to_be_dropped = TRUE;
+ rw_lock_x_unlock(dict_index_get_lock(index));
+ }
+
/* We use the private SQL parser of Innobase to generate the
query graphs needed in deleting the dictionary data from system
tables in Innobase. Deleting a row from SYS_INDEXES table also
@@ -3493,7 +3562,7 @@ check_next_foreign:
"InnoDB: of table ");
ut_print_name(stderr, trx, TRUE, name);
fprintf(stderr, ".\n");
- } else if (!fil_delete_tablespace(space_id)) {
+ } else if (!fil_delete_tablespace(space_id, FALSE)) {
fprintf(stderr,
"InnoDB: We removed now the InnoDB"
" internal data dictionary entry\n"
@@ -3520,6 +3589,17 @@ check_next_foreign:
the undo log. We can directly exit here
and return the DB_TOO_MANY_CONCURRENT_TRXS
error. */
+
+ /* Mark all indexes available in the data dictionary
+ cache again. */
+
+ for (index = dict_table_get_first_index(table);
+ index != NULL;
+ index = dict_table_get_next_index(index)) {
+ rw_lock_x_lock(dict_index_get_lock(index));
+ index->to_be_dropped = FALSE;
+ rw_lock_x_unlock(dict_index_get_lock(index));
+ }
break;
case DB_OUT_OF_FILE_SPACE:
@@ -3614,7 +3694,7 @@ row_mysql_drop_temp_tables(void)
btr_pcur_store_position(&pcur, &mtr);
btr_pcur_commit_specify_mtr(&pcur, &mtr);
- table = dict_load_table(table_name, TRUE, DICT_ERR_IGNORE_NONE);
+ table = dict_table_get_low(table_name);
if (table) {
row_drop_table_for_mysql(table_name, trx, FALSE);
@@ -3876,6 +3956,7 @@ row_rename_table_for_mysql(
ulint n_constraints_to_drop = 0;
ibool old_is_tmp, new_is_tmp;
pars_info_t* info = NULL;
+ int retry;
ut_a(old_name != NULL);
ut_a(new_name != NULL);
@@ -3958,6 +4039,25 @@ row_rename_table_for_mysql(
}
}
+ /* Is a foreign key check running on this table? */
+ for (retry = 0; retry < 100
+ && table->n_foreign_key_checks_running > 0; ++retry) {
+ row_mysql_unlock_data_dictionary(trx);
+ os_thread_yield();
+ row_mysql_lock_data_dictionary(trx);
+ }
+
+ if (table->n_foreign_key_checks_running > 0) {
+ ut_print_timestamp(stderr);
+ fputs(" InnoDB: Error: in ALTER TABLE ", stderr);
+ ut_print_name(stderr, trx, TRUE, old_name);
+ fprintf(stderr, "\n"
+ "InnoDB: a FOREIGN KEY check is running.\n"
+ "InnoDB: Cannot rename table.\n");
+ err = DB_TABLE_IN_FK_CHECK;
+ goto funct_exit;
+ }
+
/* We use the private SQL parser of Innobase to generate the query
graphs needed in updating the dictionary data from system tables. */
diff --git a/storage/xtradb/row/row0row.c b/storage/xtradb/row/row0row.c
index 0462f280858..2c33bdc4b15 100644
--- a/storage/xtradb/row/row0row.c
+++ b/storage/xtradb/row/row0row.c
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1996, 2011, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1996, 2012, Oracle and/or its affiliates. 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
@@ -11,8 +11,8 @@ 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 program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
*****************************************************************************/
@@ -241,13 +241,18 @@ row_build(
ut_ad(rec_offs_validate(rec, index, offsets));
}
-#if 0 && defined UNIV_BLOB_NULL_DEBUG
- /* This one can fail in trx_rollback_active() if
- the server crashed during an insert before the
- btr_store_big_rec_extern_fields() did mtr_commit()
- all BLOB pointers to the clustered index record. */
- ut_a(!rec_offs_any_null_extern(rec, offsets));
-#endif /* 0 && UNIV_BLOB_NULL_DEBUG */
+#ifdef UNIV_BLOB_NULL_DEBUG
+ if (rec_offs_any_null_extern(rec, offsets)) {
+ /* This condition can occur during crash recovery
+ before trx_rollback_active() has completed execution,
+ or when a concurrently executing
+ row_ins_index_entry_low() has committed the B-tree
+ mini-transaction but has not yet managed to restore
+ the cursor position for writing the big_rec. */
+ ut_a(trx_undo_roll_ptr_is_insert(
+ row_get_rec_roll_ptr(rec, index, offsets)));
+ }
+#endif /* UNIV_BLOB_NULL_DEBUG */
if (type != ROW_COPY_POINTERS) {
/* Take a copy of rec to heap */
diff --git a/storage/xtradb/row/row0sel.c b/storage/xtradb/row/row0sel.c
index be2f5d0fcd0..ec3603f2550 100644
--- a/storage/xtradb/row/row0sel.c
+++ b/storage/xtradb/row/row0sel.c
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1997, 2011, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1997, 2012, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2008, Google Inc.
Portions of this file contain modifications contributed and copyrighted by
@@ -2303,7 +2303,12 @@ row_sel_convert_mysql_key_to_innobase(
in the tuple is already according
to index! */
byte* buf, /*!< in: buffer to use in field
- conversions */
+ conversions; NOTE that dtuple->data
+ may end up pointing inside buf so
+ do not discard that buffer while
+ the tuple is being used. See
+ row_mysql_store_col_in_innobase_format()
+ in the case of DATA_INT */
ulint buf_len, /*!< in: buffer length */
dict_index_t* index, /*!< in: index of the key value */
const byte* key_ptr, /*!< in: MySQL key value */
@@ -2435,6 +2440,7 @@ row_sel_convert_mysql_key_to_innobase(
/* Storing may use at most data_len bytes of buf */
if (UNIV_LIKELY(!is_null)) {
+ ut_a(buf + data_len <= original_buf + buf_len);
row_mysql_store_col_in_innobase_format(
dfield, buf,
FALSE, /* MySQL key value format col */
@@ -2949,17 +2955,17 @@ row_sel_get_clust_rec_for_mysql(
btr_pcur_open_with_no_init(clust_index, prebuilt->clust_ref,
PAGE_CUR_LE, BTR_SEARCH_LEAF,
- prebuilt->clust_pcur, 0, mtr);
+ &prebuilt->clust_pcur, 0, mtr);
- clust_rec = btr_pcur_get_rec(prebuilt->clust_pcur);
+ clust_rec = btr_pcur_get_rec(&prebuilt->clust_pcur);
- prebuilt->clust_pcur->trx_if_known = trx;
+ prebuilt->clust_pcur.trx_if_known = trx;
/* Note: only if the search ends up on a non-infimum record is the
low_match value the real match to the search tuple */
if (!page_rec_is_user_rec(clust_rec)
- || btr_pcur_get_low_match(prebuilt->clust_pcur)
+ || btr_pcur_get_low_match(&prebuilt->clust_pcur)
< dict_index_get_n_unique(clust_index)) {
/* In a rare case it is possible that no clust rec is found
@@ -2991,6 +2997,7 @@ row_sel_get_clust_rec_for_mysql(
fputs("\n"
"InnoDB: Submit a detailed bug report"
" to http://bugs.mysql.com\n", stderr);
+ ut_ad(0);
}
clust_rec = NULL;
@@ -3008,7 +3015,7 @@ row_sel_get_clust_rec_for_mysql(
we set a LOCK_REC_NOT_GAP type lock */
err = lock_clust_rec_read_check_and_lock(
- 0, btr_pcur_get_block(prebuilt->clust_pcur),
+ 0, btr_pcur_get_block(&prebuilt->clust_pcur),
clust_rec, clust_index, *offsets,
prebuilt->select_lock_type, LOCK_REC_NOT_GAP, thr);
switch (err) {
@@ -3086,7 +3093,7 @@ func_exit:
/* We may use the cursor in update or in unlock_row():
store its position */
- btr_pcur_store_position(prebuilt->clust_pcur, mtr);
+ btr_pcur_store_position(&prebuilt->clust_pcur, mtr);
}
err_exit:
@@ -3341,7 +3348,7 @@ row_sel_try_search_shortcut_for_mysql(
{
dict_index_t* index = prebuilt->index;
const dtuple_t* search_tuple = prebuilt->search_tuple;
- btr_pcur_t* pcur = prebuilt->pcur;
+ btr_pcur_t* pcur = &prebuilt->pcur;
trx_t* trx = prebuilt->trx;
const rec_t* rec;
@@ -3507,7 +3514,7 @@ row_search_for_mysql(
dict_index_t* index = prebuilt->index;
ibool comp = dict_table_is_comp(index->table);
const dtuple_t* search_tuple = prebuilt->search_tuple;
- btr_pcur_t* pcur = prebuilt->pcur;
+ btr_pcur_t* pcur = &prebuilt->pcur;
trx_t* trx = prebuilt->trx;
dict_index_t* clust_index;
que_thr_t* thr;
@@ -4213,7 +4220,8 @@ wrong_offs:
if ((srv_force_recovery == 0 || moves_up == FALSE)
&& srv_pass_corrupt_table <= 1) {
ut_print_timestamp(stderr);
- buf_page_print(page_align(rec), 0);
+ buf_page_print(page_align(rec), 0,
+ BUF_PAGE_PRINT_NO_CRASH);
fprintf(stderr,
"\nInnoDB: rec address %p,"
" buf block fix count %lu\n",
@@ -4232,7 +4240,7 @@ wrong_offs:
"InnoDB: restore from a backup, or"
" dump + drop + reimport the table.\n",
stderr);
-
+ ut_ad(0);
err = DB_CORRUPTION;
goto lock_wait_or_error;
diff --git a/storage/xtradb/row/row0umod.c b/storage/xtradb/row/row0umod.c
index b86ce9eeabd..9597c476125 100644
--- a/storage/xtradb/row/row0umod.c
+++ b/storage/xtradb/row/row0umod.c
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1997, 2010, Innobase Oy. All Rights Reserved.
+Copyright (c) 1997, 2012, Oracle and/or its affiliates. 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
@@ -509,6 +509,7 @@ row_undo_mod_del_unmark_sec_and_undo_update(
fputs("\n"
"InnoDB: Submit a detailed bug report"
" to http://bugs.mysql.com\n", stderr);
+ ut_ad(0);
break;
case ROW_FOUND:
btr_cur = btr_pcur_get_btr_cur(&pcur);
diff --git a/storage/xtradb/row/row0upd.c b/storage/xtradb/row/row0upd.c
index 5e8099691c5..6453277c8d6 100644
--- a/storage/xtradb/row/row0upd.c
+++ b/storage/xtradb/row/row0upd.c
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1996, 2010, Innobase Oy. All Rights Reserved.
+Copyright (c) 1996, 2012, Oracle and/or its affiliates. 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
@@ -11,8 +11,8 @@ 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 program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
*****************************************************************************/
@@ -23,6 +23,8 @@ Update of a row
Created 12/27/1996 Heikki Tuuri
*******************************************************/
+#include "m_string.h" /* for my_sys.h */
+#include "my_sys.h" /* DEBUG_SYNC_C */
#include "row0upd.h"
#ifdef UNIV_NONINL
@@ -168,6 +170,46 @@ func_exit:
return(is_referenced);
}
+#ifdef WITH_WSREP
+ulint wsrep_append_foreign_key(trx_t *trx,
+ dict_foreign_t* foreign,
+ const rec_t* clust_rec,
+ dict_index_t* clust_index,
+ ibool referenced,
+ ibool shared);
+
+static
+void
+wsrep_append_fk_reference(
+/*=================================*/
+ upd_node_t* node, /*!< in: row update node */
+ dict_table_t* table, /*!< in: table in question */
+ dict_index_t* index, /*!< in: index of the cursor */
+ que_thr_t* thr, /*!< in: query thread */
+ const rec_t* rec
+) {
+ dict_foreign_t *foreign = UT_LIST_GET_FIRST(table->foreign_list);
+
+ while (foreign) {
+ if (foreign->foreign_index == index
+ && node->is_delete)
+ {
+ if (DB_SUCCESS != wsrep_append_foreign_key(
+ thr_get_trx(thr),
+ foreign,
+ rec,
+ index,
+ TRUE, TRUE)
+ ) {
+ fprintf(stderr,
+ "WSREP: FK key append failed\n");
+ }
+ }
+ foreign = UT_LIST_GET_NEXT(foreign_list, foreign);
+ }
+}
+#endif /* WITH_WSREP */
+
/*********************************************************************//**
Checks if possible foreign key constraints hold after a delete of the record
under pcur.
@@ -281,7 +323,6 @@ row_upd_check_references_constraints(
}
err = DB_SUCCESS;
-
func_exit:
if (got_s_lock) {
row_mysql_unfreeze_data_dictionary(trx);
@@ -1636,6 +1677,7 @@ row_upd_sec_index_entry(
fputs("\n"
"InnoDB: Submit a detailed bug report"
" to http://bugs.mysql.com\n", stderr);
+ ut_ad(0);
break;
case ROW_FOUND:
/* Delete mark the old index record; it can already be
@@ -1662,6 +1704,12 @@ row_upd_sec_index_entry(
node, &pcur, index->table,
index, offsets, thr, &mtr);
}
+#ifdef WITH_WSREP
+ if (err == DB_SUCCESS && !referenced) {
+ wsrep_append_fk_reference(node, index->table,
+ index, thr, rec);
+ }
+#endif /* WITH_WSREP */
}
break;
}
@@ -1905,6 +1953,12 @@ err_exit:
goto err_exit;
}
}
+#ifdef WITH_WSREP
+ if (!referenced) {
+ wsrep_append_fk_reference(node, index->table,
+ index, thr, rec);
+ }
+#endif /* WITH_WSREP */
}
mtr_commit(mtr);
@@ -2021,29 +2075,65 @@ row_upd_clust_rec(
ut_ad(!rec_get_deleted_flag(btr_pcur_get_rec(pcur),
dict_table_is_comp(index->table)));
- err = btr_cur_pessimistic_update(BTR_NO_LOCKING_FLAG, btr_cur,
- &heap, &big_rec, node->update,
- node->cmpl_info, thr, mtr);
- mtr_commit(mtr);
+ err = btr_cur_pessimistic_update(
+ BTR_NO_LOCKING_FLAG | BTR_KEEP_POS_FLAG, btr_cur,
+ &heap, &big_rec, node->update,
+ node->cmpl_info, thr, mtr);
/* skip store extern for fake_changes */
if (err == DB_SUCCESS && big_rec && !(thr_get_trx(thr)->fake_changes)) {
- ulint offsets_[REC_OFFS_NORMAL_SIZE];
- rec_t* rec;
+ ulint offsets_[REC_OFFS_NORMAL_SIZE];
+ rec_t* rec;
rec_offs_init(offsets_);
- mtr_start(mtr);
+ ut_a(err == DB_SUCCESS);
+ /* Write out the externally stored
+ columns while still x-latching
+ index->lock and block->lock. Allocate
+ pages for big_rec in the mtr that
+ modified the B-tree, but be sure to skip
+ any pages that were freed in mtr. We will
+ write out the big_rec pages before
+ committing the B-tree mini-transaction. If
+ the system crashes so that crash recovery
+ will not replay the mtr_commit(&mtr), the
+ big_rec pages will be left orphaned until
+ the pages are allocated for something else.
+
+ TODO: If the allocation extends the tablespace, it
+ will not be redo logged, in either mini-transaction.
+ Tablespace extension should be redo-logged in the
+ big_rec mini-transaction, so that recovery will not
+ fail when the big_rec was written to the extended
+ portion of the file, in case the file was somehow
+ truncated in the crash. */
- ut_a(btr_pcur_restore_position(BTR_MODIFY_TREE, pcur, mtr));
rec = btr_cur_get_rec(btr_cur);
+ DEBUG_SYNC_C("before_row_upd_extern");
err = btr_store_big_rec_extern_fields(
index, btr_cur_get_block(btr_cur), rec,
rec_get_offsets(rec, index, offsets_,
ULINT_UNDEFINED, &heap),
- mtr, TRUE, big_rec);
- mtr_commit(mtr);
+ big_rec, mtr, BTR_STORE_UPDATE);
+ DEBUG_SYNC_C("after_row_upd_extern");
+ /* If writing big_rec fails (for example, because of
+ DB_OUT_OF_FILE_SPACE), the record will be corrupted.
+ Even if we did not update any externally stored
+ columns, our update could cause the record to grow so
+ that a non-updated column was selected for external
+ storage. This non-update would not have been written
+ to the undo log, and thus the record cannot be rolled
+ back.
+
+ However, because we have not executed mtr_commit(mtr)
+ yet, the update will not be replayed in crash
+ recovery, and the following assertion failure will
+ effectively "roll back" the operation. */
+ ut_a(err == DB_SUCCESS);
}
+ mtr_commit(mtr);
+
if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
}
@@ -2075,6 +2165,9 @@ row_upd_del_mark_clust_rec(
btr_pcur_t* pcur;
btr_cur_t* btr_cur;
ulint err;
+#ifdef WITH_WSREP
+ rec_t* rec;
+#endif /* WITH_WSREP */
ut_ad(node);
ut_ad(dict_index_is_clust(index));
@@ -2091,15 +2184,29 @@ row_upd_del_mark_clust_rec(
/* Mark the clustered index record deleted; we do not have to check
locks, because we assume that we have an x-lock on the record */
+#ifdef WITH_WSREP
+ rec = btr_cur_get_rec(btr_cur);
+#endif /* WITH_WSREP */
+
err = btr_cur_del_mark_set_clust_rec(
BTR_NO_LOCKING_FLAG, btr_cur_get_block(btr_cur),
+#ifdef WITH_WSREP
+ rec, index, offsets, TRUE, thr, mtr);
+#else
btr_cur_get_rec(btr_cur), index, offsets, TRUE, thr, mtr);
+#endif /* WITH_WSREP */
if (err == DB_SUCCESS && referenced) {
/* NOTE that the following call loses the position of pcur ! */
err = row_upd_check_references_constraints(
node, pcur, index->table, index, offsets, thr, mtr);
}
+#ifdef WITH_WSREP
+ if (err == DB_SUCCESS && !referenced) {
+ wsrep_append_fk_reference(node, index->table,
+ index, thr, rec);
+ }
+#endif /* WITH_WSREP */
mtr_commit(mtr);
diff --git a/storage/xtradb/srv/srv0srv.c b/storage/xtradb/srv/srv0srv.c
index c8eefb56fef..598e0505506 100644
--- a/storage/xtradb/srv/srv0srv.c
+++ b/storage/xtradb/srv/srv0srv.c
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1995, 2011, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1995, 2012, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2008, 2009 Google Inc.
Copyright (c) 2009, Percona Inc.
@@ -444,6 +444,9 @@ UNIV_INTERN unsigned long long srv_stats_sample_pages = 8;
UNIV_INTERN ulint srv_stats_auto_update = 1;
UNIV_INTERN ulint srv_stats_update_need_lock = 1;
UNIV_INTERN ibool srv_use_sys_stats_table = FALSE;
+#ifdef UNIV_DEBUG
+UNIV_INTERN ulong srv_sys_stats_root_page = 0;
+#endif
UNIV_INTERN ibool srv_use_doublewrite_buf = TRUE;
UNIV_INTERN ibool srv_use_checksums = TRUE;
@@ -482,9 +485,6 @@ UNIV_INTERN ibool srv_print_lock_waits = FALSE;
UNIV_INTERN ibool srv_print_buf_io = FALSE;
UNIV_INTERN ibool srv_print_log_io = FALSE;
UNIV_INTERN ibool srv_print_latch_waits = FALSE;
-
-UNIV_INTERN ulong srv_flush_checkpoint_debug = 0;
-
#endif /* UNIV_DEBUG */
UNIV_INTERN ulint srv_n_rows_inserted = 0;
@@ -2902,6 +2902,7 @@ loop:
"InnoDB: Please submit a bug report"
" to http://bugs.mysql.com\n",
old_lsn, new_lsn);
+ ut_ad(0);
}
old_lsn = new_lsn;
@@ -3066,21 +3067,23 @@ exit_func:
}
/**********************************************************************//**
-Check whether any background thread is active.
-@return FALSE if all are are suspended or have exited. */
+Check whether any background thread is active. If so return the thread
+type
+@return ULINT_UNDEFINED if all are suspended or have exited, thread
+type if any are still active. */
UNIV_INTERN
-ibool
-srv_is_any_background_thread_active(void)
-/*=====================================*/
+ulint
+srv_get_active_thread_type(void)
+/*============================*/
{
ulint i;
- ibool ret = FALSE;
+ ibool ret = ULINT_UNDEFINED;
mutex_enter(&kernel_mutex);
for (i = 0; i <= SRV_MASTER; ++i) {
if (srv_n_threads_active[i] != 0) {
- ret = TRUE;
+ ret = i;
break;
}
}
@@ -3090,6 +3093,57 @@ srv_is_any_background_thread_active(void)
return(ret);
}
+/*********************************************************************//**
+This function prints progress message every 60 seconds during server
+shutdown, for any activities that master thread is pending on. */
+static
+void
+srv_shutdown_print_master_pending(
+/*==============================*/
+ ib_time_t* last_print_time, /*!< last time the function
+ print the message */
+ ulint n_tables_to_drop, /*!< number of tables to
+ be dropped */
+ ulint n_bytes_merged, /*!< number of change buffer
+ just merged */
+ ulint n_pages_flushed) /*!< number of pages flushed */
+{
+ ib_time_t current_time;
+ double time_elapsed;
+
+ current_time = ut_time();
+ time_elapsed = ut_difftime(current_time, *last_print_time);
+
+ if (time_elapsed > 60) {
+ *last_print_time = ut_time();
+
+ if (n_tables_to_drop) {
+ ut_print_timestamp(stderr);
+ fprintf(stderr, " InnoDB: Waiting for "
+ "%lu table(s) to be dropped\n",
+ (ulong) n_tables_to_drop);
+ }
+
+ /* Check change buffer merge, we only wait for change buffer
+ merge if it is a slow shutdown */
+ if (!srv_fast_shutdown && n_bytes_merged) {
+ ut_print_timestamp(stderr);
+ fprintf(stderr, " InnoDB: Waiting for change "
+ "buffer merge to complete\n"
+ " InnoDB: number of bytes of change buffer "
+ "just merged: %lu\n",
+ n_bytes_merged);
+ }
+
+ if (n_pages_flushed) {
+ ut_print_timestamp(stderr);
+ fprintf(stderr, " InnoDB: Waiting for "
+ "%lu pages to be flushed\n",
+ (ulong) n_pages_flushed);
+ }
+ }
+}
+
/*******************************************************************//**
Tells the InnoDB server that there has been activity in the database
and wakes up the master thread if it is suspended (not sleeping). Used
@@ -3259,6 +3313,7 @@ srv_master_thread(
ib_uint64_t lsn_old;
ib_uint64_t oldest_lsn;
+ ib_time_t last_print_time;
#ifdef UNIV_DEBUG_THREAD_CREATION
fprintf(stderr, "Master thread starts, id %lu\n",
@@ -3284,6 +3339,9 @@ srv_master_thread(
mutex_enter(&(log_sys->mutex));
lsn_old = log_sys->lsn;
mutex_exit(&(log_sys->mutex));
+
+ last_print_time = ut_time();
+
loop:
/*****************************************************************/
/* ---- When there is database activity by users, we cycle in this
@@ -3738,18 +3796,11 @@ retry_flush_batch:
PCT_IO(10), IB_ULONGLONG_MAX);
}
-#ifdef UNIV_DEBUG
- if (srv_flush_checkpoint_debug != 1) {
-#endif
-
- srv_main_thread_op_info = "making checkpoint";
+ srv_main_thread_op_info = "making checkpoint";
- /* Make a new checkpoint about once in 10 seconds */
+ /* Make a new checkpoint about once in 10 seconds */
- log_checkpoint(TRUE, FALSE, TRUE);
-#ifdef UNIV_DEBUG
- }
-#endif
+ log_checkpoint(TRUE, FALSE, TRUE);
srv_main_thread_op_info = "reserving kernel mutex";
@@ -3828,10 +3879,6 @@ background_loop:
}
mutex_exit(&kernel_mutex);
-#ifdef UNIV_DEBUG
- if (srv_flush_checkpoint_debug == 1)
- goto skip_flush;
-#endif
flush_loop:
srv_main_thread_op_info = "flushing buffer pool pages";
srv_main_flush_loops++;
@@ -3872,9 +3919,6 @@ flush_loop:
goto flush_loop;
}
-#ifdef UNIV_DEBUG
-skip_flush:
-#endif
srv_main_thread_op_info = "reserving kernel mutex";
mutex_enter(&kernel_mutex);
@@ -3890,6 +3934,14 @@ skip_flush:
*/
n_bytes_archived = 0;
+ /* Print progress message every 60 seconds during shutdown */
+ if (srv_shutdown_state > 0 && srv_print_verbose_log) {
+ srv_shutdown_print_master_pending(&last_print_time,
+ n_tables_to_drop,
+ n_bytes_merged,
+ n_pages_flushed);
+ }
+
/* Keep looping in the background loop if still work to do */
if (srv_fast_shutdown && srv_shutdown_state > 0) {
@@ -3908,6 +3960,7 @@ skip_flush:
} else if (n_tables_to_drop
+ n_pages_purged + n_bytes_merged + n_pages_flushed
+ n_bytes_archived != 0) {
+
/* In a 'slow' shutdown we run purge and the insert buffer
merge to completion */
diff --git a/storage/xtradb/srv/srv0start.c b/storage/xtradb/srv/srv0start.c
index 99916610c21..75e8097ee0b 100644
--- a/storage/xtradb/srv/srv0start.c
+++ b/storage/xtradb/srv/srv0start.c
@@ -925,8 +925,9 @@ skip_size_check:
#endif /* UNIV_LOG_ARCHIVE */
min_flushed_lsn, max_flushed_lsn);
- if (UNIV_PAGE_SIZE
- != fsp_flags_get_page_size(flags)) {
+ if (!one_opened
+ && UNIV_PAGE_SIZE
+ != fsp_flags_get_page_size(flags)) {
ut_print_timestamp(stderr);
fprintf(stderr,
@@ -1508,10 +1509,20 @@ innobase_start_or_create_for_mysql(void)
}
# endif /* __WIN__ */
- os_aio_init(io_limit,
- srv_n_read_io_threads,
- srv_n_write_io_threads,
- SRV_MAX_N_PENDING_SYNC_IOS);
+ if (!os_aio_init(io_limit,
+ srv_n_read_io_threads,
+ srv_n_write_io_threads,
+ SRV_MAX_N_PENDING_SYNC_IOS))
+ {
+ ut_print_timestamp(stderr);
+ fprintf(stderr,
+ " InnoDB: Fatal error: cannot initialize AIO"
+ " sub-system\n");
+#if defined(LINUX_NATIVE_AIO)
+ fprintf(stderr, "You can try increasing system fs.aio-max-nr to 1048576 or larger or setting innodb_use_native_aio = 0 in my.cnf\n");
+#endif
+ return(DB_ERROR);
+ }
fil_init(srv_file_per_table ? 50000 : 5000,
srv_max_n_open_files);
@@ -1938,6 +1949,12 @@ innobase_start_or_create_for_mysql(void)
trx_sys_dummy_create(TRX_DOUBLEWRITE_SPACE);
}
+
+ if (UNIV_UNLIKELY(!dict_verify_xtradb_sys_stats())) {
+ fprintf(stderr, "InnoDB: Warning: "
+ "SYS_STATS table corrupted, recreating\n");
+ dict_recreate_xtradb_sys_stats();
+ }
}
if (!create_new_db && sum_of_new_sizes > 0) {
diff --git a/storage/xtradb/sync/sync0rw.c b/storage/xtradb/sync/sync0rw.c
index 8884812d84d..5068d1679c0 100644
--- a/storage/xtradb/sync/sync0rw.c
+++ b/storage/xtradb/sync/sync0rw.c
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1995, 2011, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1995, 2012, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2008, Google Inc.
Portions of this file contain modifications contributed and copyrighted by
@@ -18,8 +18,8 @@ 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 program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
*****************************************************************************/
@@ -780,7 +780,9 @@ rw_lock_add_debug_info(
rw_lock_debug_mutex_exit();
if ((pass == 0) && (lock_type != RW_LOCK_WAIT_EX)) {
- sync_thread_add_level(lock, lock->level);
+ sync_thread_add_level(lock, lock->level,
+ lock_type == RW_LOCK_EX
+ && lock->lock_word < 0);
}
}
diff --git a/storage/xtradb/sync/sync0sync.c b/storage/xtradb/sync/sync0sync.c
index d2c4617d65c..7654fade6e8 100644
--- a/storage/xtradb/sync/sync0sync.c
+++ b/storage/xtradb/sync/sync0sync.c
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1995, 2011, Innobase Oy. All Rights Reserved.
+Copyright (c) 1995, 2012, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2008, Google Inc.
Portions of this file contain modifications contributed and copyrighted by
@@ -18,8 +18,8 @@ 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 program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
*****************************************************************************/
@@ -700,7 +700,7 @@ mutex_set_debug_info(
ut_ad(mutex);
ut_ad(file_name);
- sync_thread_add_level(mutex, mutex->level);
+ sync_thread_add_level(mutex, mutex->level, FALSE);
mutex->file_name = file_name;
mutex->line = line;
@@ -1142,8 +1142,9 @@ void
sync_thread_add_level(
/*==================*/
void* latch, /*!< in: pointer to a mutex or an rw-lock */
- ulint level) /*!< in: level in the latching order; if
+ ulint level, /*!< in: level in the latching order; if
SYNC_LEVEL_VARYING, nothing is done */
+ ibool relock) /*!< in: TRUE if re-entering an x-lock */
{
ulint i;
sync_level_t* slot;
@@ -1194,6 +1195,10 @@ sync_thread_add_level(
array = thread_slot->levels;
+ if (relock) {
+ goto levels_ok;
+ }
+
/* NOTE that there is a problem with _NODE and _LEAF levels: if the
B-tree height changes, then a leaf can change to an internal node
or the other way around. We do not know at present if this can cause
@@ -1376,6 +1381,7 @@ sync_thread_add_level(
ut_error;
}
+levels_ok:
if (array->next_free == ULINT_UNDEFINED) {
ut_a(array->n_elems < array->max_elems);
diff --git a/storage/xtradb/trx/trx0purge.c b/storage/xtradb/trx/trx0purge.c
index eb4fa80fa40..122aab119ba 100644
--- a/storage/xtradb/trx/trx0purge.c
+++ b/storage/xtradb/trx/trx0purge.c
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1996, 2011, Innobase Oy. All Rights Reserved.
+Copyright (c) 1996, 2012, Oracle and/or its affiliates. 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
@@ -730,6 +730,7 @@ trx_purge_rseg_get_next_history_log(
"InnoDB: report, and submit it"
" to http://bugs.mysql.com\n",
(ulong) trx_sys->rseg_history_len);
+ ut_ad(0);
}
mutex_exit(&kernel_mutex);
@@ -1200,7 +1201,7 @@ trx_purge(
(ulong) purge_sys->n_pages_handled);
}
- return(purge_sys->n_pages_handled - old_pages_handled);
+ return((ulint) (purge_sys->n_pages_handled - old_pages_handled));
}
/******************************************************************//**
diff --git a/storage/xtradb/trx/trx0rec.c b/storage/xtradb/trx/trx0rec.c
index 104b80f5d96..db4897c368d 100644
--- a/storage/xtradb/trx/trx0rec.c
+++ b/storage/xtradb/trx/trx0rec.c
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1996, 2011, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1996, 2012, Oracle and/or its affiliates. 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
@@ -11,8 +11,8 @@ 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 program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
*****************************************************************************/
@@ -1016,6 +1016,7 @@ trx_undo_update_rec_get_update(
fprintf(stderr, "\n"
"InnoDB: n_fields = %lu, i = %lu, ptr %p\n",
(ulong) n_fields, (ulong) i, ptr);
+ ut_ad(0);
*upd = NULL;
return(NULL);
}
@@ -1210,6 +1211,7 @@ trx_undo_report_row_operation(
trx_t* trx;
trx_undo_t* undo;
ulint page_no;
+ buf_block_t* undo_block;
trx_rseg_t* rseg;
mtr_t mtr;
ulint err = DB_SUCCESS;
@@ -1252,10 +1254,13 @@ trx_undo_report_row_operation(
if (UNIV_UNLIKELY(!undo)) {
/* Did not succeed */
+ ut_ad(err != DB_SUCCESS);
mutex_exit(&(trx->undo_mutex));
return(err);
}
+
+ ut_ad(err == DB_SUCCESS);
} else {
ut_ad(op_type == TRX_UNDO_MODIFY_OP);
@@ -1269,30 +1274,30 @@ trx_undo_report_row_operation(
if (UNIV_UNLIKELY(!undo)) {
/* Did not succeed */
+ ut_ad(err != DB_SUCCESS);
mutex_exit(&(trx->undo_mutex));
return(err);
}
+ ut_ad(err == DB_SUCCESS);
offsets = rec_get_offsets(rec, index, offsets,
ULINT_UNDEFINED, &heap);
}
- page_no = undo->last_page_no;
-
mtr_start(&mtr);
+ page_no = undo->last_page_no;
+ undo_block = buf_page_get_gen(
+ undo->space, undo->zip_size, page_no, RW_X_LATCH,
+ undo->guess_block, BUF_GET, __FILE__, __LINE__, &mtr);
+ buf_block_dbg_add_level(undo_block, SYNC_TRX_UNDO_PAGE);
+
do {
- buf_block_t* undo_block;
page_t* undo_page;
ulint offset;
- undo_block = buf_page_get_gen(undo->space, undo->zip_size,
- page_no, RW_X_LATCH,
- undo->guess_block, BUF_GET,
- __FILE__, __LINE__, &mtr);
- buf_block_dbg_add_level(undo_block, SYNC_TRX_UNDO_PAGE);
-
undo_page = buf_block_get_frame(undo_block);
+ ut_ad(page_no == buf_block_get_page_no(undo_block));
if (op_type == TRX_UNDO_INSERT_OP) {
offset = trx_undo_page_report_insert(
@@ -1369,12 +1374,11 @@ trx_undo_report_row_operation(
a pessimistic insert in a B-tree, and we must reserve the
counterpart of the tree latch, which is the rseg mutex. */
- mutex_enter(&(rseg->mutex));
-
- page_no = trx_undo_add_page(trx, undo, &mtr);
-
- mutex_exit(&(rseg->mutex));
- } while (UNIV_LIKELY(page_no != FIL_NULL));
+ mutex_enter(&rseg->mutex);
+ undo_block = trx_undo_add_page(trx, undo, &mtr);
+ mutex_exit(&rseg->mutex);
+ page_no = undo->last_page_no;
+ } while (undo_block != NULL);
/* Did not succeed: out of space */
err = DB_OUT_OF_FILE_SPACE;
@@ -1526,6 +1530,7 @@ trx_undo_prev_version_build(
"InnoDB: record version ", stderr);
rec_print_new(stderr, rec, offsets);
putc('\n', stderr);
+ ut_ad(0);
return(DB_ERROR);
}
@@ -1631,6 +1636,7 @@ trx_undo_prev_version_build(
(ullint) old_roll_ptr, (ullint) roll_ptr);
trx_purge_sys_print();
+ ut_ad(0);
return(DB_ERROR);
}
diff --git a/storage/xtradb/trx/trx0sys.c b/storage/xtradb/trx/trx0sys.c
index 56d0723d777..89db43fb776 100644
--- a/storage/xtradb/trx/trx0sys.c
+++ b/storage/xtradb/trx/trx0sys.c
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1996, 2011, Innobase Oy. All Rights Reserved.
+Copyright (c) 1996, 2012, Oracle and/or its affiliates. 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
@@ -11,8 +11,8 @@ 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 program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
*****************************************************************************/
@@ -141,6 +141,11 @@ UNIV_INTERN mysql_pfs_key_t trx_doublewrite_mutex_key;
UNIV_INTERN mysql_pfs_key_t file_format_max_mutex_key;
#endif /* UNIV_PFS_MUTEX */
+#ifdef UNIV_DEBUG
+/* Flag to control TRX_RSEG_N_SLOTS behavior debugging. */
+uint trx_rseg_n_slots_debug = 0;
+#endif
+
#ifndef UNIV_HOTBACKUP
/** This is used to track the maximum file format id known to InnoDB. It's
updated via SET GLOBAL innodb_file_format_max = 'x' or when we open
@@ -257,9 +262,7 @@ trx_sys_create_doublewrite_buf(void)
{
buf_block_t* block;
buf_block_t* block2;
-#ifdef UNIV_SYNC_DEBUG
buf_block_t* new_block;
-#endif /* UNIV_SYNC_DEBUG */
byte* doublewrite;
byte* fseg_header;
ulint page_no;
@@ -338,10 +341,9 @@ start_again:
for (i = 0; i < 2 * TRX_SYS_DOUBLEWRITE_BLOCK_SIZE
+ FSP_EXTENT_SIZE / 2; i++) {
- page_no = fseg_alloc_free_page(fseg_header,
- prev_page_no + 1,
- FSP_UP, &mtr);
- if (page_no == FIL_NULL) {
+ new_block = fseg_alloc_free_page(
+ fseg_header, prev_page_no + 1, FSP_UP, &mtr);
+ if (new_block == NULL) {
fprintf(stderr,
"InnoDB: Cannot create doublewrite"
" buffer: you must\n"
@@ -362,13 +364,8 @@ start_again:
the page position in the tablespace, then the page
has not been written to in doublewrite. */
-#ifdef UNIV_SYNC_DEBUG
- new_block =
-#endif /* UNIV_SYNC_DEBUG */
- buf_page_get(TRX_SYS_SPACE, 0, page_no,
- RW_X_LATCH, &mtr);
- buf_block_dbg_add_level(new_block,
- SYNC_NO_ORDER_CHECK);
+ ut_ad(rw_lock_get_x_lock_count(&new_block->lock) == 1);
+ page_no = buf_block_get_page_no(new_block);
if (i == FSP_EXTENT_SIZE / 2) {
ut_a(page_no == FSP_EXTENT_SIZE);
@@ -438,7 +435,10 @@ start_again:
/* The doublewrite buffer has already been created:
just read in some numbers */
+ trx_doublewrite_init(doublewrite);
+
mtr_commit(&mtr);
+ trx_doublewrite_buf_is_being_created = FALSE;
} else {
fprintf(stderr,
"InnoDB: Doublewrite buffer not found in the doublewrite file:"
@@ -485,13 +485,12 @@ start_again:
for (i = 0; i < 2 * TRX_SYS_DOUBLEWRITE_BLOCK_SIZE
+ FSP_EXTENT_SIZE / 2; i++) {
- page_no = fseg_alloc_free_page(fseg_header,
- prev_page_no + 1,
- FSP_UP, &mtr);
- if (page_no == FIL_NULL) {
+ new_block = fseg_alloc_free_page(
+ fseg_header, prev_page_no + 1, FSP_UP, &mtr);
+ if (new_block == NULL) {
fprintf(stderr,
- "InnoDB: Cannot create the doublewrite"
- " buffer: You must\n"
+ "InnoDB: Cannot create doublewrite"
+ " buffer: you must\n"
"InnoDB: increase your"
" tablespace size.\n"
"InnoDB: Cannot continue operation.\n"
@@ -509,13 +508,8 @@ start_again:
the page position in the tablespace, then the page
has not been written to in doublewrite. */
-#ifdef UNIV_SYNC_DEBUG
- new_block =
-#endif /* UNIV_SYNC_DEBUG */
- buf_page_get(TRX_DOUBLEWRITE_SPACE, 0, page_no,
- RW_X_LATCH, &mtr);
- buf_block_dbg_add_level(new_block,
- SYNC_NO_ORDER_CHECK);
+ ut_ad(rw_lock_get_x_lock_count(&new_block->lock) == 1);
+ page_no = buf_block_get_page_no(new_block);
if (i == FSP_EXTENT_SIZE / 2) {
ut_a(page_no == FSP_EXTENT_SIZE);
@@ -750,12 +744,16 @@ trx_sys_doublewrite_init_or_restore_pages(
if (buf_page_is_corrupted(page, zip_size)) {
fprintf(stderr,
"InnoDB: Dump of the page:\n");
- buf_page_print(read_buf, zip_size);
+ buf_page_print(
+ read_buf, zip_size,
+ BUF_PAGE_PRINT_NO_CRASH);
fprintf(stderr,
"InnoDB: Dump of"
" corresponding page"
" in doublewrite buffer:\n");
- buf_page_print(page, zip_size);
+ buf_page_print(
+ page, zip_size,
+ BUF_PAGE_PRINT_NO_CRASH);
fprintf(stderr,
"InnoDB: Also the page in the"
@@ -769,7 +767,7 @@ trx_sys_doublewrite_init_or_restore_pages(
"InnoDB: option:\n"
"InnoDB:"
" innodb_force_recovery=6\n");
- exit(1);
+ ut_error;
}
/* Write the good page from the
diff --git a/storage/xtradb/trx/trx0trx.c b/storage/xtradb/trx/trx0trx.c
index 96e0716e5c0..a6b5fab8589 100644
--- a/storage/xtradb/trx/trx0trx.c
+++ b/storage/xtradb/trx/trx0trx.c
@@ -1158,6 +1158,8 @@ trx_commit_off_kernel(
}
#endif
UT_LIST_REMOVE(trx_list, trx_sys->trx_list, trx);
+
+ trx->error_state = DB_SUCCESS;
}
/****************************************************************//**
diff --git a/storage/xtradb/trx/trx0undo.c b/storage/xtradb/trx/trx0undo.c
index dae0637f72c..3d794c69c8b 100644
--- a/storage/xtradb/trx/trx0undo.c
+++ b/storage/xtradb/trx/trx0undo.c
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1996, 2009, Innobase Oy. All Rights Reserved.
+Copyright (c) 1996, 2012, Oracle and/or its affiliates. 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
@@ -11,8 +11,8 @@ 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 program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
*****************************************************************************/
@@ -876,9 +876,9 @@ trx_undo_discard_latest_update_undo(
#ifndef UNIV_HOTBACKUP
/********************************************************************//**
Tries to add a page to the undo log segment where the undo log is placed.
-@return page number if success, else FIL_NULL */
+@return X-latched block if success, else NULL */
UNIV_INTERN
-ulint
+buf_block_t*
trx_undo_add_page(
/*==============*/
trx_t* trx, /*!< in: transaction */
@@ -888,11 +888,10 @@ trx_undo_add_page(
the rollback segment mutex */
{
page_t* header_page;
+ buf_block_t* new_block;
page_t* new_page;
trx_rseg_t* rseg;
- ulint page_no;
ulint n_reserved;
- ibool success;
ut_ad(mutex_own(&(trx->undo_mutex)));
ut_ad(!mutex_own(&kernel_mutex));
@@ -902,37 +901,37 @@ trx_undo_add_page(
if (rseg->curr_size == rseg->max_size) {
- return(FIL_NULL);
+ return(NULL);
}
header_page = trx_undo_page_get(undo->space, undo->zip_size,
undo->hdr_page_no, mtr);
- success = fsp_reserve_free_extents(&n_reserved, undo->space, 1,
- FSP_UNDO, mtr);
- if (!success) {
+ if (!fsp_reserve_free_extents(&n_reserved, undo->space, 1,
+ FSP_UNDO, mtr)) {
- return(FIL_NULL);
+ return(NULL);
}
- page_no = fseg_alloc_free_page_general(header_page + TRX_UNDO_SEG_HDR
- + TRX_UNDO_FSEG_HEADER,
- undo->top_page_no + 1, FSP_UP,
- TRUE, mtr);
+ new_block = fseg_alloc_free_page_general(
+ TRX_UNDO_SEG_HDR + TRX_UNDO_FSEG_HEADER
+ + header_page,
+ undo->top_page_no + 1, FSP_UP, TRUE, mtr, mtr);
fil_space_release_free_extents(undo->space, n_reserved);
- if (page_no == FIL_NULL) {
+ if (new_block == NULL) {
/* No space left */
- return(FIL_NULL);
+ return(NULL);
}
- undo->last_page_no = page_no;
+ ut_ad(rw_lock_get_x_lock_count(&new_block->lock) == 1);
+ buf_block_dbg_add_level(new_block, SYNC_TRX_UNDO_PAGE);
+ undo->last_page_no = buf_block_get_page_no(new_block);
- new_page = trx_undo_page_get(undo->space, undo->zip_size,
- page_no, mtr);
+ new_page = buf_block_get_frame(new_block);
trx_undo_page_init(new_page, undo->type, mtr);
@@ -941,7 +940,7 @@ trx_undo_add_page(
undo->size++;
rseg->curr_size++;
- return(page_no);
+ return(new_block);
}
/********************************************************************//**
diff --git a/storage/xtradb/ut/ut0mem.c b/storage/xtradb/ut/ut0mem.c
index 303fdd6dd44..cb6b050beca 100644
--- a/storage/xtradb/ut/ut0mem.c
+++ b/storage/xtradb/ut/ut0mem.c
@@ -84,17 +84,13 @@ ut_mem_init(void)
#endif /* !UNIV_HOTBACKUP */
/**********************************************************************//**
-Allocates memory. Sets it also to zero if UNIV_SET_MEM_TO_ZERO is
-defined and set_to_zero is TRUE.
+Allocates memory.
@return own: allocated memory */
UNIV_INTERN
void*
ut_malloc_low(
/*==========*/
ulint n, /*!< in: number of bytes to allocate */
- ibool set_to_zero, /*!< in: TRUE if allocated memory should be
- set to zero if UNIV_SET_MEM_TO_ZERO is
- defined */
ibool assert_on_error)/*!< in: if TRUE, we crash mysqld if the
memory cannot be allocated */
{
@@ -106,12 +102,6 @@ ut_malloc_low(
ret = malloc(n);
ut_a(ret || !assert_on_error);
-#ifdef UNIV_SET_MEM_TO_ZERO
- if (set_to_zero) {
- memset(ret, '\0', n);
- UNIV_MEM_ALLOC(ret, n);
- }
-#endif
return(ret);
}
@@ -193,12 +183,6 @@ retry:
}
}
- if (set_to_zero) {
-#ifdef UNIV_SET_MEM_TO_ZERO
- memset(ret, '\0', n + sizeof(ut_mem_block_t));
-#endif
- }
-
UNIV_MEM_ALLOC(ret, n + sizeof(ut_mem_block_t));
((ut_mem_block_t*)ret)->size = n + sizeof(ut_mem_block_t);
@@ -215,75 +199,11 @@ retry:
void* ret = malloc(n);
ut_a(ret || !assert_on_error);
-# ifdef UNIV_SET_MEM_TO_ZERO
- if (set_to_zero) {
- memset(ret, '\0', n);
- }
-# endif
return(ret);
#endif /* !UNIV_HOTBACKUP */
}
/**********************************************************************//**
-Allocates memory. Sets it also to zero if UNIV_SET_MEM_TO_ZERO is
-defined.
-@return own: allocated memory */
-UNIV_INTERN
-void*
-ut_malloc(
-/*======*/
- ulint n) /*!< in: number of bytes to allocate */
-{
-#ifndef UNIV_HOTBACKUP
- return(ut_malloc_low(n, TRUE, TRUE));
-#else /* !UNIV_HOTBACKUP */
- return(malloc(n));
-#endif /* !UNIV_HOTBACKUP */
-}
-
-#ifndef UNIV_HOTBACKUP
-/**********************************************************************//**
-Tests if malloc of n bytes would succeed. ut_malloc() asserts if memory runs
-out. It cannot be used if we want to return an error message. Prints to
-stderr a message if fails.
-@return TRUE if succeeded */
-UNIV_INTERN
-ibool
-ut_test_malloc(
-/*===========*/
- ulint n) /*!< in: try to allocate this many bytes */
-{
- void* ret;
-
- ret = malloc(n);
-
- if (ret == NULL) {
- ut_print_timestamp(stderr);
- fprintf(stderr,
- " InnoDB: Error: cannot allocate"
- " %lu bytes of memory for\n"
- "InnoDB: a BLOB with malloc! Total allocated memory\n"
- "InnoDB: by InnoDB %lu bytes."
- " Operating system errno: %d\n"
- "InnoDB: Check if you should increase"
- " the swap file or\n"
- "InnoDB: ulimits of your operating system.\n"
- "InnoDB: On FreeBSD check you have"
- " compiled the OS with\n"
- "InnoDB: a big enough maximum process size.\n",
- (ulong) n,
- (ulong) ut_total_allocated_memory,
- (int) errno);
- return(FALSE);
- }
-
- free(ret);
-
- return(TRUE);
-}
-#endif /* !UNIV_HOTBACKUP */
-
-/**********************************************************************//**
Frees a memory block allocated with ut_malloc. Freeing a NULL pointer is
a nop. */
UNIV_INTERN
diff --git a/storage/xtradb/ut/ut0ut.c b/storage/xtradb/ut/ut0ut.c
index 4fab362b5f5..60def59193a 100644
--- a/storage/xtradb/ut/ut0ut.c
+++ b/storage/xtradb/ut/ut0ut.c
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 2011, Oracle Corpn. All Rights Reserved.
+Copyright (c) 2011, 2012, Oracle and/or its affiliates. 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
@@ -11,8 +11,8 @@ 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 program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
*****************************************************************************/
@@ -720,6 +720,8 @@ ut_strerr(
return("End of index");
case DB_SEARCH_ABORTED_BY_USER:
return("Operation was interrupted by end user");
+ case DB_TABLE_IN_FK_CHECK:
+ return("Table is being used in foreign key check");
/* do not add default: in order to produce a warning if new code
is added to the enum but not added here */
}