summaryrefslogtreecommitdiffstats
path: root/storage/myisammrg
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-13 12:24:36 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-13 12:24:36 +0000
commit06eaf7232e9a920468c0f8d74dcf2fe8b555501c (patch)
treee2c7b5777f728320e5b5542b6213fd3591ba51e2 /storage/myisammrg
parentInitial commit. (diff)
downloadmariadb-06eaf7232e9a920468c0f8d74dcf2fe8b555501c.tar.xz
mariadb-06eaf7232e9a920468c0f8d74dcf2fe8b555501c.zip
Adding upstream version 1:10.11.6.upstream/1%10.11.6
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'storage/myisammrg')
-rw-r--r--storage/myisammrg/CMakeLists.txt23
-rw-r--r--storage/myisammrg/ha_myisammrg.cc1785
-rw-r--r--storage/myisammrg/ha_myisammrg.h162
-rw-r--r--storage/myisammrg/myrg_close.c68
-rw-r--r--storage/myisammrg/myrg_create.c73
-rw-r--r--storage/myisammrg/myrg_def.h44
-rw-r--r--storage/myisammrg/myrg_delete.c27
-rw-r--r--storage/myisammrg/myrg_extra.c97
-rw-r--r--storage/myisammrg/myrg_info.c86
-rw-r--r--storage/myisammrg/myrg_locking.c45
-rw-r--r--storage/myisammrg/myrg_open.c551
-rw-r--r--storage/myisammrg/myrg_panic.c46
-rw-r--r--storage/myisammrg/myrg_queue.c90
-rw-r--r--storage/myisammrg/myrg_range.c43
-rw-r--r--storage/myisammrg/myrg_records.c28
-rw-r--r--storage/myisammrg/myrg_rfirst.c49
-rw-r--r--storage/myisammrg/myrg_rkey.c95
-rw-r--r--storage/myisammrg/myrg_rlast.c50
-rw-r--r--storage/myisammrg/myrg_rnext.c53
-rw-r--r--storage/myisammrg/myrg_rnext_same.c51
-rw-r--r--storage/myisammrg/myrg_rprev.c53
-rw-r--r--storage/myisammrg/myrg_rrnd.c117
-rw-r--r--storage/myisammrg/myrg_rsame.c28
-rw-r--r--storage/myisammrg/myrg_static.c71
-rw-r--r--storage/myisammrg/myrg_update.c28
-rw-r--r--storage/myisammrg/myrg_write.c30
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/alter_table.inc116
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/alter_table.rdiff151
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/alter_table_online.rdiff82
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/alter_tablespace.rdiff34
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/analyze_table.rdiff34
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/autoincrement.rdiff64
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/cache_index.rdiff71
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/checksum_table_live.rdiff13
-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.rdiff57
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/define_engine.inc49
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/disabled.def4
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/foreign_keys.rdiff147
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/fulltext_search.rdiff150
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/handler.rdiff88
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/index.rdiff11
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/index_enable_disable.rdiff33
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/index_type_btree.rdiff11
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/index_type_hash.rdiff69
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/insert_delayed.rdiff26
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/lock.rdiff80
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/misc.rdiff34
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/optimize_table.rdiff35
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/parts/alter_table.rdiff68
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/parts/analyze_table.rdiff87
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/parts/check_table.rdiff176
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/parts/checksum_table.rdiff89
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/parts/create_table.rdiff159
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/parts/optimize_table.rdiff95
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/parts/repair_table.rdiff299
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/parts/truncate_table.rdiff101
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/repair_table.rdiff132
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/show_engine.rdiff10
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/tbl_opt_ai.rdiff16
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/tbl_opt_avg_row_length.rdiff17
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/tbl_opt_checksum.rdiff17
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/tbl_opt_connection.rdiff19
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/tbl_opt_data_dir.rdiff18
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/tbl_opt_delay_key_write.rdiff17
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/tbl_opt_index_dir.rdiff18
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/tbl_opt_insert_method.rdiff17
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/tbl_opt_key_block_size.rdiff17
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/tbl_opt_max_rows.rdiff17
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/tbl_opt_min_rows.rdiff17
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/tbl_opt_pack_keys.rdiff17
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/tbl_opt_password.rdiff17
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/tbl_opt_row_format.rdiff33
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/tbl_opt_union.rdiff16
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/tbl_standard_opts.rdiff19
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/tbl_temporary.rdiff10
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/truncate_table.rdiff48
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/trx/cons_snapshot_repeatable_read.rdiff20
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/trx/cons_snapshot_serializable.rdiff20
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/trx/delete.rdiff50
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/trx/insert.rdiff65
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/trx/level_read_committed.rdiff94
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/trx/level_read_uncommitted.rdiff12
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/trx/level_repeatable_read.rdiff96
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/trx/level_serializable.rdiff103
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/trx/select_for_update.rdiff50
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/trx/select_lock_in_share_mode.rdiff37
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/trx/update.rdiff58
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/trx/xa.rdiff89
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/trx/xa_recovery.rdiff32
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/type_char_indexes.rdiff20
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/type_float_indexes.rdiff11
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/type_spatial.rdiff712
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/type_spatial_indexes.rdiff1422
-rw-r--r--storage/myisammrg/mysql-test/storage_engine/vcol.rdiff82
96 files changed, 9915 insertions, 0 deletions
diff --git a/storage/myisammrg/CMakeLists.txt b/storage/myisammrg/CMakeLists.txt
new file mode 100644
index 00000000..b4db348d
--- /dev/null
+++ b/storage/myisammrg/CMakeLists.txt
@@ -0,0 +1,23 @@
+# Copyright (c) 2006, 2010, 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 Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA
+
+SET(MYISAMMRG_SOURCES myrg_close.c myrg_create.c myrg_delete.c myrg_extra.c myrg_info.c
+ ha_myisammrg.cc
+ myrg_locking.c myrg_open.c myrg_panic.c myrg_queue.c myrg_range.c
+ myrg_rfirst.c myrg_rkey.c myrg_rlast.c myrg_rnext.c myrg_rnext_same.c
+ myrg_rprev.c myrg_rrnd.c myrg_rsame.c myrg_static.c myrg_update.c
+ myrg_write.c myrg_records.c)
+
+MYSQL_ADD_PLUGIN(myisammrg ${MYISAMMRG_SOURCES} STORAGE_ENGINE MANDATORY RECOMPILE_FOR_EMBEDDED)
diff --git a/storage/myisammrg/ha_myisammrg.cc b/storage/myisammrg/ha_myisammrg.cc
new file mode 100644
index 00000000..d37636ab
--- /dev/null
+++ b/storage/myisammrg/ha_myisammrg.cc
@@ -0,0 +1,1785 @@
+/* Copyright (c) 2000, 2011, Oracle and/or its affiliates
+ Copyright (c) 2009, 2016, MariaDB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */
+
+
+/*
+ MyISAM MERGE tables
+
+ A MyISAM MERGE table is kind of a union of zero or more MyISAM tables.
+
+ Besides the normal form file (.frm) a MERGE table has a meta file
+ (.MRG) with a list of tables. These are paths to the MyISAM table
+ files. The last two components of the path contain the database name
+ and the table name respectively.
+
+ When a MERGE table is open, there exists an TABLE object for the MERGE
+ table itself and a TABLE object for each of the MyISAM tables. For
+ abbreviated writing, I call the MERGE table object "parent" and the
+ MyISAM table objects "children".
+
+ A MERGE table is almost always opened through open_and_lock_tables()
+ and hence through open_tables(). When the parent appears in the list
+ of tables to open, the initial open of the handler does nothing but
+ read the meta file and collect a list of TABLE_LIST objects for the
+ children. This list is attached to the handler object as
+ ha_myisammrg::children_l. The end of the children list is saved in
+ ha_myisammrg::children_last_l.
+
+ Back in open_tables(), handler::extra(HA_EXTRA_ADD_CHILDREN_LIST) is
+ called. It updates each list member with the lock type and a back
+ pointer to the parent TABLE_LIST object TABLE_LIST::parent_l. The list
+ is then inserted in the list of tables to open, right behind the
+ parent. Consequently, open_tables() opens the children, one after the
+ other. The TABLE references of the TABLE_LIST objects are implicitly
+ set to the open tables by open_table(). The children are opened as
+ independent MyISAM tables, right as if they are used by the SQL
+ statement.
+
+ When all tables from the statement query list are open,
+ handler::extra(HA_EXTRA_ATTACH_CHILDREN) is called. It "attaches" the
+ children to the parent. All required references between parent and
+ children are set up.
+
+ The MERGE storage engine sets up an array with references to the
+ low-level MyISAM table objects (MI_INFO). It remembers the state of
+ the table in MYRG_INFO::children_attached.
+
+ If necessary, the compatibility of parent and children is checked.
+ This check is necessary when any of the objects are reopend. This is
+ detected by comparing the current table def version against the
+ remembered child def version. On parent open, the list members are
+ initialized to an "impossible"/"undefined" version value. So the check
+ is always executed on the first attach.
+
+ The version check is done in myisammrg_attach_children_callback(),
+ which is called for every child. ha_myisammrg::attach_children()
+ initializes 'need_compat_check' to FALSE and
+ myisammrg_attach_children_callback() sets it ot TRUE if a table
+ def version mismatches the remembered child def version.
+
+ The children chain remains in the statement query list until the table
+ is closed or the children are detached. This is done so that the
+ children are locked by lock_tables().
+
+ At statement end the children are detached. At the next statement
+ begin the open-add-attach sequence repeats. There is no exception for
+ LOCK TABLES. The fresh establishment of the parent-child relationship
+ before every statement catches numerous cases of ALTER/FLUSH/DROP/etc
+ of parent or children during LOCK TABLES.
+
+ ---
+
+ On parent open the storage engine structures are allocated and initialized.
+ They stay with the open table until its final close.
+*/
+
+#ifdef USE_PRAGMA_IMPLEMENTATION
+#pragma implementation // gcc: Class implementation
+#endif
+
+#define MYSQL_SERVER 1
+#include <my_global.h>
+#include "sql_priv.h"
+#include "unireg.h"
+#include "sql_cache.h" // query_cache_*
+#include "sql_show.h" // append_identifier
+#include "sql_table.h" // build_table_filename
+#include <m_ctype.h>
+#include "../myisam/ha_myisam.h"
+#include "ha_myisammrg.h"
+#include "myrg_def.h"
+#include "thr_malloc.h" // init_sql_alloc
+#include "sql_class.h" // THD
+#include "debug_sync.h"
+
+static handler *myisammrg_create_handler(handlerton *hton,
+ TABLE_SHARE *table,
+ MEM_ROOT *mem_root)
+{
+ return new (mem_root) ha_myisammrg(hton, table);
+}
+
+
+/**
+ @brief Constructor
+*/
+
+ha_myisammrg::ha_myisammrg(handlerton *hton, TABLE_SHARE *table_arg)
+ :handler(hton, table_arg), file(0), is_cloned(0)
+{
+ init_sql_alloc(rg_key_memory_children, &children_mem_root,
+ FN_REFLEN, 0, MYF(0));
+}
+
+
+/**
+ @brief Destructor
+*/
+
+ha_myisammrg::~ha_myisammrg(void)
+{
+ free_root(&children_mem_root, MYF(0));
+}
+
+
+static const char *ha_myisammrg_exts[] = {
+ MYRG_NAME_EXT,
+ NullS
+};
+extern int table2myisam(TABLE *table_arg, MI_KEYDEF **keydef_out,
+ MI_COLUMNDEF **recinfo_out, uint *records_out);
+extern int check_definition(MI_KEYDEF *t1_keyinfo,
+ MI_COLUMNDEF *t1_recinfo,
+ uint t1_keys, uint t1_recs,
+ MI_KEYDEF *t2_keyinfo,
+ MI_COLUMNDEF *t2_recinfo,
+ uint t2_keys, uint t2_recs, bool strict,
+ TABLE *table_arg);
+static void split_file_name(const char *file_name,
+ LEX_STRING *db, LEX_STRING *name);
+
+
+extern "C" void myrg_print_wrong_table(const char *table_name)
+{
+ LEX_STRING db= {NULL, 0}, name;
+ char buf[FN_REFLEN];
+ split_file_name(table_name, &db, &name);
+ memcpy(buf, db.str, db.length);
+ buf[db.length]= '.';
+ memcpy(buf + db.length + 1, name.str, name.length);
+ buf[db.length + name.length + 1]= 0;
+ /*
+ Push an error to be reported as part of CHECK/REPAIR result-set.
+ Note that calling my_error() from handler is a hack which is kept
+ here to avoid refactoring. Normally engines should report errors
+ through return value which will be interpreted by caller using
+ handler::print_error() call.
+ */
+ my_error(ER_ADMIN_WRONG_MRG_TABLE, MYF(0), buf);
+}
+
+
+const char *ha_myisammrg::index_type(uint key_number)
+{
+ return ((table->key_info[key_number].flags & HA_FULLTEXT) ?
+ "FULLTEXT" :
+ (table->key_info[key_number].flags & HA_SPATIAL) ?
+ "SPATIAL" :
+ (table->key_info[key_number].algorithm == HA_KEY_ALG_RTREE) ?
+ "RTREE" :
+ "BTREE");
+}
+
+
+/**
+ Callback function for open of a MERGE parent table.
+
+ @param[in] callback_param data pointer as given to myrg_parent_open()
+ this is used to pass the handler handle
+ @param[in] filename file name of MyISAM table
+ without extension.
+
+ @return status
+ @retval 0 OK
+ @retval != 0 Error
+
+ @detail
+
+ This function adds a TABLE_LIST object for a MERGE child table to a
+ list of tables in the parent handler object. It is called for each
+ child table.
+
+ The list of child TABLE_LIST objects is kept in the handler object
+ of the parent for the whole life time of the MERGE table. It is
+ inserted in the statement query list behind the MERGE parent
+ TABLE_LIST object when the MERGE table is opened. It is removed from
+ the statement query list at end of statement or at children detach.
+
+ All memory used for the child TABLE_LIST objects and the strings
+ referred by it are taken from the parent
+ ha_myisammrg::children_mem_root. Thus they are all freed implicitly at
+ the final close of the table.
+
+ children_l -> TABLE_LIST::next_global -> TABLE_LIST::next_global
+ # # ^ # ^
+ # # | # |
+ # # +--------- TABLE_LIST::prev_global
+ # # |
+ # |<--- TABLE_LIST::prev_global |
+ # |
+ children_last_l -----------------------------------------+
+*/
+
+CPP_UNNAMED_NS_START
+
+extern "C" int myisammrg_parent_open_callback(void *callback_param,
+ const char *filename)
+{
+ ha_myisammrg *ha_myrg= (ha_myisammrg*) callback_param;
+ TABLE *parent= ha_myrg->table_ptr();
+ Mrg_child_def *mrg_child_def;
+ char *db;
+ char *table_name;
+ size_t dirlen;
+ size_t db_length;
+ size_t table_name_length;
+ char dir_path[FN_REFLEN];
+ char name_buf[NAME_LEN];
+ DBUG_ENTER("myisammrg_parent_open_callback");
+
+ /*
+ Depending on MySQL version, filename may be encoded by table name to
+ file name encoding or not. Always encoded if parent table is created
+ by 5.1.46+. Encoded if parent is created by 5.1.6+ and child table is
+ in different database.
+ */
+ if (!has_path(filename))
+ {
+ /* Child is in the same database as parent. */
+ db_length= parent->s->db.length;
+ db= strmake_root(&ha_myrg->children_mem_root, parent->s->db.str, db_length);
+ /* Child table name is encoded in parent dot-MRG starting with 5.1.46. */
+ if (parent->s->mysql_version >= 50146)
+ {
+ table_name_length= filename_to_tablename(filename, name_buf,
+ sizeof(name_buf));
+ table_name= strmake_root(&ha_myrg->children_mem_root, name_buf,
+ table_name_length);
+ }
+ else
+ {
+ table_name_length= strlen(filename);
+ table_name= strmake_root(&ha_myrg->children_mem_root, filename,
+ table_name_length);
+ }
+ }
+ else
+ {
+ DBUG_ASSERT(strlen(filename) < sizeof(dir_path));
+ fn_format(dir_path, filename, "", "", 0);
+ /* Extract child table name and database name from filename. */
+ dirlen= dirname_length(dir_path);
+ /* Child db/table name is encoded in parent dot-MRG starting with 5.1.6. */
+ if (parent->s->mysql_version >= 50106)
+ {
+ table_name_length= filename_to_tablename(dir_path + dirlen, name_buf,
+ sizeof(name_buf));
+ table_name= strmake_root(&ha_myrg->children_mem_root, name_buf,
+ table_name_length);
+ dir_path[dirlen - 1]= 0;
+ dirlen= dirname_length(dir_path);
+ db_length= filename_to_tablename(dir_path + dirlen, name_buf, sizeof(name_buf));
+ db= strmake_root(&ha_myrg->children_mem_root, name_buf, db_length);
+ }
+ else
+ {
+ table_name_length= strlen(dir_path + dirlen);
+ table_name= strmake_root(&ha_myrg->children_mem_root, dir_path + dirlen,
+ table_name_length);
+ dir_path[dirlen - 1]= 0;
+ dirlen= dirname_length(dir_path);
+ db_length= strlen(dir_path + dirlen);
+ db= strmake_root(&ha_myrg->children_mem_root, dir_path + dirlen,
+ db_length);
+ }
+ }
+
+ if (! db || ! table_name)
+ DBUG_RETURN(1);
+
+ DBUG_PRINT("myrg", ("open: '%.*s'.'%.*s'", (int) db_length, db,
+ (int) table_name_length, table_name));
+
+ /* Convert to lowercase if required. */
+ if (lower_case_table_names && table_name_length)
+ {
+ /* purecov: begin tested */
+ table_name_length= my_casedn_str(files_charset_info, table_name);
+ /* purecov: end */
+ }
+
+ mrg_child_def= new (&ha_myrg->children_mem_root)
+ Mrg_child_def(db, db_length, table_name, table_name_length);
+
+ if (! mrg_child_def ||
+ ha_myrg->child_def_list.push_back(mrg_child_def,
+ &ha_myrg->children_mem_root))
+ {
+ DBUG_RETURN(1);
+ }
+ DBUG_RETURN(0);
+}
+
+CPP_UNNAMED_NS_END
+
+
+/*
+ Set external_ref for the child MyISAM tables. They need this to be set in
+ order to check for killed status.
+*/
+static void myrg_set_external_ref(MYRG_INFO *m_info, void *ext_ref_arg)
+{
+ int i;
+ for (i= 0; i < (int)m_info->tables; i++)
+ {
+ m_info->open_tables[i].table->external_ref= ext_ref_arg;
+ }
+}
+
+/**
+ Open a MERGE parent table, but not its children.
+
+ @param[in] name MERGE table path name
+ @param[in] mode read/write mode, unused
+ @param[in] test_if_locked_arg open flags
+
+ @return status
+ @retval 0 OK
+ @retval -1 Error, my_errno gives reason
+
+ @detail
+ This function initializes the MERGE storage engine structures
+ and adds a child list of TABLE_LIST to the parent handler.
+*/
+
+int ha_myisammrg::open(const char *name, int mode __attribute__((unused)),
+ uint test_if_locked_arg)
+{
+ DBUG_ENTER("ha_myisammrg::open");
+ DBUG_PRINT("myrg", ("name: '%s' table: %p", name, table));
+ DBUG_PRINT("myrg", ("test_if_locked_arg: %u", test_if_locked_arg));
+
+ /* Must not be used when table is open. */
+ DBUG_ASSERT(!this->file);
+
+ /* Save for later use. */
+ test_if_locked= test_if_locked_arg;
+
+ /* In case this handler was open and closed before, free old data. */
+ free_root(&this->children_mem_root, MYF(MY_MARK_BLOCKS_FREE));
+
+ /*
+ Initialize variables that are used, modified, and/or set by
+ myisammrg_parent_open_callback().
+ 'children_l' is the head of the children chain.
+ 'children_last_l' points to the end of the children chain.
+ 'my_errno' is set by myisammrg_parent_open_callback() in
+ case of an error.
+ */
+ children_l= NULL;
+ children_last_l= NULL;
+ child_def_list.empty();
+ my_errno= 0;
+
+ /* retrieve children table list. */
+ if (is_cloned)
+ {
+ /*
+ Open and attaches the MyISAM tables,that are under the MERGE table
+ parent, on the MyISAM storage engine interface directly within the
+ MERGE engine. The new MyISAM table instances, as well as the MERGE
+ clone itself, are not visible in the table cache. This is not a
+ problem because all locking is handled by the original MERGE table
+ from which this is cloned of.
+ */
+ if (!(file= myrg_open(name, table->db_stat, HA_OPEN_IGNORE_IF_LOCKED)))
+ {
+ DBUG_PRINT("error", ("my_errno %d", my_errno));
+ DBUG_RETURN(my_errno ? my_errno : -1);
+ }
+
+ file->children_attached= TRUE;
+ myrg_set_external_ref(file, (void*)table);
+
+ info(HA_STATUS_NO_LOCK | HA_STATUS_VARIABLE | HA_STATUS_CONST);
+ }
+ else if (!(file= myrg_parent_open(name, myisammrg_parent_open_callback, this)))
+ {
+ /* purecov: begin inspected */
+ DBUG_PRINT("error", ("my_errno %d", my_errno));
+ DBUG_RETURN(my_errno ? my_errno : -1);
+ /* purecov: end */
+ }
+ DBUG_PRINT("myrg", ("MYRG_INFO: %p child tables: %u",
+ file, file->tables));
+ DBUG_RETURN(0);
+}
+
+
+/**
+ Add list of MERGE children to a TABLE_LIST chain.
+
+ @return status
+ @retval 0 OK
+ @retval != 0 Error
+
+ @detail
+ When a MERGE parent table has just been opened, insert the
+ TABLE_LIST chain from the MERGE handler into the table list used for
+ opening tables for this statement. This lets the children be opened
+ too.
+*/
+
+int ha_myisammrg::add_children_list(void)
+{
+ TABLE_LIST *parent_l= this->table->pos_in_table_list;
+ THD *thd= table->in_use;
+ List_iterator_fast<Mrg_child_def> it(child_def_list);
+ Mrg_child_def *mrg_child_def;
+ DBUG_ENTER("ha_myisammrg::add_children_list");
+ DBUG_PRINT("myrg", ("table: '%s'.'%s' %p", this->table->s->db.str,
+ this->table->s->table_name.str, this->table));
+
+ /* Must call this with open table. */
+ DBUG_ASSERT(this->file);
+
+ /* Ignore this for empty MERGE tables (UNION=()). */
+ if (!this->file->tables)
+ {
+ DBUG_PRINT("myrg", ("empty merge table union"));
+ goto end;
+ }
+
+ /* Must not call this with attached children. */
+ DBUG_ASSERT(!this->file->children_attached);
+
+ /* Must not call this with children list in place. */
+ DBUG_ASSERT(this->children_l == NULL);
+
+ /*
+ Prevent inclusion of another MERGE table, which could make infinite
+ recursion.
+ */
+ if (parent_l->parent_l)
+ {
+ my_error(ER_ADMIN_WRONG_MRG_TABLE, MYF(0), parent_l->alias.str);
+ DBUG_RETURN(1);
+ }
+
+ while ((mrg_child_def= it++))
+ {
+ TABLE_LIST *child_l;
+ LEX_CSTRING db;
+ LEX_CSTRING table_name;
+
+ child_l= (TABLE_LIST*) thd->alloc(sizeof(TABLE_LIST));
+ db.str= (char*) thd->memdup(mrg_child_def->db.str, mrg_child_def->db.length+1);
+ db.length= mrg_child_def->db.length;
+ table_name.str= (char*) thd->memdup(mrg_child_def->name.str,
+ mrg_child_def->name.length+1);
+ table_name.length= mrg_child_def->name.length;
+
+ if (child_l == NULL || db.str == NULL || table_name.str == NULL)
+ DBUG_RETURN(1);
+
+ child_l->init_one_table(&db, &table_name, 0, parent_l->lock_type);
+ /* Set parent reference. Used to detect MERGE in children list. */
+ child_l->parent_l= parent_l;
+ /* Copy select_lex. Used in unique_table() at least. */
+ child_l->select_lex= parent_l->select_lex;
+ /* Set the expected table version, to not cause spurious re-prepare. */
+ child_l->set_table_ref_id(mrg_child_def->get_child_table_ref_type(),
+ mrg_child_def->get_child_def_version());
+ /*
+ Copy parent's prelocking attribute to allow opening of child
+ temporary residing in the prelocking list.
+ */
+ child_l->prelocking_placeholder= parent_l->prelocking_placeholder;
+ /*
+ For statements which acquire a SNW metadata lock on a parent table and
+ then later try to upgrade it to an X lock (e.g. ALTER TABLE), SNW
+ locks should be also taken on the children tables.
+
+ Otherwise we end up in a situation where the thread trying to upgrade SNW
+ to X lock on the parent also holds a SR metadata lock and a read
+ thr_lock.c lock on the child. As a result, another thread might be
+ blocked on the thr_lock.c lock for the child after successfully acquiring
+ a SR or SW metadata lock on it. If at the same time this second thread
+ has a shared metadata lock on the parent table or there is some other
+ thread which has a shared metadata lock on the parent and is waiting for
+ this second thread, we get a deadlock. This deadlock cannot be properly
+ detected by the MDL subsystem as part of the waiting happens within
+ thr_lock.c. By taking SNW locks on the child tables we ensure that any
+ thread which waits for a thread doing SNW -> X upgrade, does this within
+ the MDL subsystem and thus potential deadlocks are exposed to the deadlock
+ detector.
+
+ We don't do the same thing for SNRW locks as this would allow
+ DDL on implicitly locked underlying tables of a MERGE table.
+ */
+ if (! thd->locked_tables_mode &&
+ parent_l->mdl_request.type == MDL_SHARED_UPGRADABLE)
+ child_l->mdl_request.set_type(MDL_SHARED_NO_WRITE);
+ /* Link TABLE_LIST object into the children list. */
+ if (this->children_last_l)
+ child_l->prev_global= this->children_last_l;
+ else
+ {
+ /* Initialize children_last_l when handling first child. */
+ this->children_last_l= &this->children_l;
+ }
+ *this->children_last_l= child_l;
+ this->children_last_l= &child_l->next_global;
+ }
+
+ /* Insert children into the table list. */
+ if (parent_l->next_global)
+ parent_l->next_global->prev_global= this->children_last_l;
+ *this->children_last_l= parent_l->next_global;
+ parent_l->next_global= this->children_l;
+ this->children_l->prev_global= &parent_l->next_global;
+ /*
+ We have to update LEX::query_tables_last if children are added to
+ the tail of the table list in order to be able correctly add more
+ elements to it (e.g. as part of prelocking process).
+ */
+ if (thd->lex->query_tables_last == &parent_l->next_global)
+ thd->lex->query_tables_last= this->children_last_l;
+ /*
+ The branch below works only when re-executing a prepared
+ statement or a stored routine statement:
+ We've just modified query_tables_last. Keep it in sync with
+ query_tables_last_own, if it was set by the prelocking code.
+ This ensures that the check that prohibits double updates (*)
+ can correctly identify what tables belong to the main statement.
+ (*) A double update is, e.g. when a user issues UPDATE t1 and
+ t1 has an AFTER UPDATE trigger that also modifies t1.
+ */
+ if (thd->lex->query_tables_own_last == &parent_l->next_global)
+ thd->lex->query_tables_own_last= this->children_last_l;
+
+end:
+ DBUG_RETURN(0);
+}
+
+
+/**
+ A context of myrg_attach_children() callback.
+*/
+
+class Mrg_attach_children_callback_param
+{
+public:
+ /**
+ 'need_compat_check' is set by myisammrg_attach_children_callback()
+ if a child fails the table def version check.
+ */
+ bool need_compat_check;
+ /** TABLE_LIST identifying this merge parent. */
+ TABLE_LIST *parent_l;
+ /** Iterator position, the current child to attach. */
+ TABLE_LIST *next_child_attach;
+ List_iterator_fast<Mrg_child_def> def_it;
+ Mrg_child_def *mrg_child_def;
+public:
+ Mrg_attach_children_callback_param(TABLE_LIST *parent_l_arg,
+ TABLE_LIST *first_child,
+ List<Mrg_child_def> &child_def_list)
+ :need_compat_check(FALSE),
+ parent_l(parent_l_arg),
+ next_child_attach(first_child),
+ def_it(child_def_list),
+ mrg_child_def(def_it++)
+ {}
+ void next()
+ {
+ next_child_attach= next_child_attach->next_global;
+ if (next_child_attach && next_child_attach->parent_l != parent_l)
+ next_child_attach= NULL;
+ if (mrg_child_def)
+ mrg_child_def= def_it++;
+ }
+};
+
+
+/**
+ Callback function for attaching a MERGE child table.
+
+ @param[in] callback_param data pointer as given to myrg_attach_children()
+ this is used to pass the handler handle
+
+ @return pointer to open MyISAM table structure
+ @retval !=NULL OK, returning pointer
+ @retval NULL, Error.
+
+ @detail
+ This function retrieves the MyISAM table handle from the
+ next child table. It is called for each child table.
+*/
+
+CPP_UNNAMED_NS_START
+
+extern "C" MI_INFO *myisammrg_attach_children_callback(void *callback_param)
+{
+ Mrg_attach_children_callback_param *param=
+ (Mrg_attach_children_callback_param*) callback_param;
+ TABLE *parent= param->parent_l->table;
+ TABLE *child;
+ TABLE_LIST *child_l= param->next_child_attach;
+ Mrg_child_def *mrg_child_def= param->mrg_child_def;
+ MI_INFO *myisam= NULL;
+ DBUG_ENTER("myisammrg_attach_children_callback");
+
+ /*
+ Number of children in the list and MYRG_INFO::tables_count,
+ which is used by caller of this function, should always match.
+ */
+ DBUG_ASSERT(child_l);
+
+ child= child_l->table;
+ /* Prepare for next child. */
+ param->next();
+
+ /*
+ When MERGE table is opened for CHECK or REPAIR TABLE statements,
+ failure to open any of underlying tables is ignored until this moment
+ (this is needed to provide complete list of the problematic underlying
+ tables in CHECK/REPAIR TABLE output).
+ Here we detect such a situation and report an appropriate error.
+ */
+ if (! child)
+ {
+ DBUG_PRINT("error", ("failed to open underlying table '%s'.'%s'",
+ child_l->db.str, child_l->table_name.str));
+ /*
+ This should only happen inside of CHECK/REPAIR TABLE or
+ for the tables added by the pre-locking code.
+ */
+ DBUG_ASSERT(current_thd->open_options & HA_OPEN_FOR_REPAIR ||
+ child_l->prelocking_placeholder);
+ goto end;
+ }
+
+ /*
+ Do a quick compatibility check. The table def version is set when
+ the table share is created. The child def version is copied
+ from the table def version after a successful compatibility check.
+ We need to repeat the compatibility check only if a child is opened
+ from a different share than last time it was used with this MERGE
+ table.
+ */
+ DBUG_PRINT("myrg", ("table_def_version last: %lu current: %lu",
+ (ulong) mrg_child_def->get_child_def_version(),
+ (ulong) child->s->get_table_def_version()));
+ if (mrg_child_def->get_child_def_version() != child->s->get_table_def_version())
+ param->need_compat_check= TRUE;
+
+ /*
+ If child is temporary, parent must be temporary as well. Other
+ parent/child combinations are allowed. This check must be done for
+ every child on every open because the table def version can overlap
+ between temporary and non-temporary tables. We need to detect the
+ case where a non-temporary table has been replaced with a temporary
+ table of the same version. Or vice versa. A very unlikely case, but
+ it could happen. (Note that the condition was different from
+ 5.1.23/6.0.4(Bug#19627) to 5.5.6 (Bug#36171): child->s->tmp_table !=
+ parent->s->tmp_table. Tables were required to have the same status.)
+ */
+ if (child->s->tmp_table && !parent->s->tmp_table)
+ {
+ DBUG_PRINT("error", ("temporary table mismatch parent: %d child: %d",
+ parent->s->tmp_table, child->s->tmp_table));
+ goto end;
+ }
+
+ /* Extract the MyISAM table structure pointer from the handler object. */
+ if ((child->file->ht->db_type != DB_TYPE_MYISAM) ||
+ !(myisam= ((ha_myisam*) child->file)->file_ptr()))
+ {
+ DBUG_PRINT("error", ("no MyISAM handle for child table: '%s'.'%s' %p",
+ child->s->db.str, child->s->table_name.str,
+ child));
+ }
+
+ DBUG_PRINT("myrg", ("MyISAM handle: %p", myisam));
+
+ end:
+
+ if (!myisam &&
+ (current_thd->open_options & HA_OPEN_FOR_REPAIR))
+ {
+ char buf[2*NAME_LEN + 1 + 1];
+ strxnmov(buf, sizeof(buf) - 1, child_l->db.str, ".",
+ child_l->table_name.str, NULL);
+ /*
+ Push an error to be reported as part of CHECK/REPAIR result-set.
+ Note that calling my_error() from handler is a hack which is kept
+ here to avoid refactoring. Normally engines should report errors
+ through return value which will be interpreted by caller using
+ handler::print_error() call.
+ */
+ my_error(ER_ADMIN_WRONG_MRG_TABLE, MYF(0), buf);
+ }
+
+ DBUG_RETURN(myisam);
+}
+
+CPP_UNNAMED_NS_END
+
+/**
+ Returns a cloned instance of the current handler.
+
+ @return A cloned handler instance.
+ */
+handler *ha_myisammrg::clone(const char *name, MEM_ROOT *mem_root)
+{
+ MYRG_TABLE *u_table,*newu_table;
+ ha_myisammrg *new_handler=
+ (ha_myisammrg*) get_new_handler(table->s, mem_root, table->s->db_type());
+ if (!new_handler)
+ return NULL;
+
+ /* Inform ha_myisammrg::open() that it is a cloned handler */
+ new_handler->is_cloned= TRUE;
+ /*
+ Allocate handler->ref here because otherwise ha_open will allocate it
+ on this->table->mem_root and we will not be able to reclaim that memory
+ when the clone handler object is destroyed.
+ */
+ if (!(new_handler->ref= (uchar*) alloc_root(mem_root, ALIGN_SIZE(ref_length)*2)))
+ {
+ delete new_handler;
+ return NULL;
+ }
+
+ if (new_handler->ha_open(table, name, table->db_stat,
+ HA_OPEN_IGNORE_IF_LOCKED))
+ {
+ delete new_handler;
+ return NULL;
+ }
+
+ /*
+ Iterate through the original child tables and
+ copy the state into the cloned child tables.
+ We need to do this because all the child tables
+ can be involved in delete.
+ */
+ newu_table= new_handler->file->open_tables;
+ for (u_table= file->open_tables; u_table < file->end_table; u_table++)
+ {
+ newu_table->table->state= u_table->table->state;
+ newu_table++;
+ }
+
+ return new_handler;
+ }
+
+
+/**
+ Attach children to a MERGE table.
+
+ @return status
+ @retval 0 OK
+ @retval != 0 Error, my_errno gives reason
+
+ @detail
+ Let the storage engine attach its children through a callback
+ function. Check table definitions for consistency.
+
+ @note
+ Special thd->open_options may be in effect. We can make use of
+ them in attach. I.e. we use HA_OPEN_FOR_REPAIR to report the names
+ of mismatching child tables. We cannot transport these options in
+ ha_myisammrg::test_if_locked because they may change after the
+ parent is opened. The parent is kept open in the table cache over
+ multiple statements and can be used by other threads. Open options
+ can change over time.
+*/
+
+int ha_myisammrg::attach_children(void)
+{
+ MYRG_TABLE *u_table;
+ MI_COLUMNDEF *recinfo;
+ MI_KEYDEF *keyinfo;
+ uint recs;
+ uint keys= table->s->keys;
+ TABLE_LIST *parent_l= table->pos_in_table_list;
+ int error;
+ Mrg_attach_children_callback_param param(parent_l, this->children_l, child_def_list);
+ DBUG_ENTER("ha_myisammrg::attach_children");
+ DBUG_PRINT("myrg", ("table: '%s'.'%s' %p", table->s->db.str,
+ table->s->table_name.str, table));
+ DBUG_PRINT("myrg", ("test_if_locked: %u", this->test_if_locked));
+
+ /* Must call this with open table. */
+ DBUG_ASSERT(this->file);
+
+ /*
+ A MERGE table with no children (empty union) is always seen as
+ attached internally.
+ */
+ if (!this->file->tables)
+ {
+ DBUG_PRINT("myrg", ("empty merge table union"));
+ goto end;
+ }
+ DBUG_PRINT("myrg", ("child tables: %u", this->file->tables));
+
+ /* Must not call this with attached children. */
+ DBUG_ASSERT(!this->file->children_attached);
+
+ DEBUG_SYNC(current_thd, "before_myisammrg_attach");
+ /* Must call this with children list in place. */
+ DBUG_ASSERT(this->table->pos_in_table_list->next_global == this->children_l);
+
+ if (myrg_attach_children(this->file, this->test_if_locked |
+ current_thd->open_options,
+ myisammrg_attach_children_callback, &param,
+ (my_bool *) &param.need_compat_check))
+ {
+ error= my_errno;
+ goto err;
+ }
+ DBUG_PRINT("myrg", ("calling myrg_extrafunc"));
+ myrg_extrafunc(file, query_cache_invalidate_by_MyISAM_filename_ref);
+ if (!(test_if_locked == HA_OPEN_WAIT_IF_LOCKED ||
+ test_if_locked == HA_OPEN_ABORT_IF_LOCKED))
+ myrg_extra(file,HA_EXTRA_NO_WAIT_LOCK,0);
+ info(HA_STATUS_NO_LOCK | HA_STATUS_VARIABLE | HA_STATUS_CONST);
+ if (!(test_if_locked & HA_OPEN_WAIT_IF_LOCKED))
+ myrg_extra(file,HA_EXTRA_WAIT_LOCK,0);
+
+ /*
+ The compatibility check is required only if one or more children do
+ not match their table def version from the last check. This will
+ always happen at the first attach because the reference child def
+ version is initialized to 'undefined' at open.
+ */
+ DBUG_PRINT("myrg", ("need_compat_check: %d", param.need_compat_check));
+ if (param.need_compat_check)
+ {
+ TABLE_LIST *child_l;
+
+ if (table->s->reclength != stats.mean_rec_length && stats.mean_rec_length)
+ {
+ DBUG_PRINT("error",("reclength: %lu mean_rec_length: %lu",
+ table->s->reclength, stats.mean_rec_length));
+ if (test_if_locked & HA_OPEN_FOR_REPAIR)
+ {
+ /* purecov: begin inspected */
+ myrg_print_wrong_table(file->open_tables->table->filename);
+ /* purecov: end */
+ }
+ error= HA_ERR_WRONG_MRG_TABLE_DEF;
+ goto err;
+ }
+ /*
+ Both recinfo and keyinfo are allocated by my_multi_malloc(), thus
+ only recinfo must be freed.
+ */
+ if ((error= table2myisam(table, &keyinfo, &recinfo, &recs)))
+ {
+ /* purecov: begin inspected */
+ DBUG_PRINT("error", ("failed to convert TABLE object to MyISAM "
+ "key and column definition"));
+ goto err;
+ /* purecov: end */
+ }
+ for (u_table= file->open_tables; u_table < file->end_table; u_table++)
+ {
+ if (check_definition(keyinfo, recinfo, keys, recs,
+ u_table->table->s->keyinfo, u_table->table->s->rec,
+ u_table->table->s->base.keys,
+ u_table->table->s->base.fields, false, NULL))
+ {
+ DBUG_PRINT("error", ("table definition mismatch: '%s'",
+ u_table->table->filename));
+ error= HA_ERR_WRONG_MRG_TABLE_DEF;
+ if (!(this->test_if_locked & HA_OPEN_FOR_REPAIR))
+ {
+ my_free(recinfo);
+ goto err;
+ }
+ /* purecov: begin inspected */
+ myrg_print_wrong_table(u_table->table->filename);
+ /* purecov: end */
+ }
+ }
+ my_free(recinfo);
+ if (error == HA_ERR_WRONG_MRG_TABLE_DEF)
+ goto err; /* purecov: inspected */
+
+ List_iterator_fast<Mrg_child_def> def_it(child_def_list);
+ DBUG_ASSERT(this->children_l);
+ for (child_l= this->children_l; ; child_l= child_l->next_global)
+ {
+ Mrg_child_def *mrg_child_def= def_it++;
+ mrg_child_def->set_child_def_version(
+ child_l->table->s->get_table_ref_type(),
+ child_l->table->s->get_table_def_version());
+
+ if (&child_l->next_global == this->children_last_l)
+ break;
+ }
+ }
+#if !defined(BIG_TABLES) || SIZEOF_OFF_T == 4
+ /* Merge table has more than 2G rows */
+ if (table->s->crashed)
+ {
+ DBUG_PRINT("error", ("MERGE table marked crashed"));
+ error= HA_ERR_WRONG_MRG_TABLE_DEF;
+ goto err;
+ }
+#endif
+
+ end:
+ DBUG_RETURN(0);
+
+err:
+ DBUG_PRINT("error", ("attaching MERGE children failed: %d", error));
+ print_error(error, MYF(0));
+ detach_children();
+ DBUG_RETURN(my_errno= error);
+}
+
+
+/**
+ Detach all children from a MERGE table and from the query list of tables.
+
+ @return status
+ @retval 0 OK
+ @retval != 0 Error, my_errno gives reason
+
+ @note
+ Detach must not touch the child TABLE objects in any way.
+ They may have been closed at ths point already.
+ All references to the children should be removed.
+*/
+
+int ha_myisammrg::detach_children(void)
+{
+ TABLE_LIST *child_l;
+ DBUG_ENTER("ha_myisammrg::detach_children");
+
+ /* Must call this with open table. */
+ DBUG_ASSERT(this->file);
+
+ /* A MERGE table with no children (empty union) cannot be detached. */
+ if (!this->file->tables)
+ {
+ DBUG_PRINT("myrg", ("empty merge table union"));
+ goto end;
+ }
+
+ if (this->children_l)
+ {
+ THD *thd= table->in_use;
+
+ /* Clear TABLE references. */
+ for (child_l= this->children_l; ; child_l= child_l->next_global)
+ {
+ /*
+ Do not DBUG_ASSERT(child_l->table); open_tables might be
+ incomplete.
+
+ Clear the table reference.
+ */
+ child_l->table= NULL;
+ /* Similarly, clear the ticket reference. */
+ child_l->mdl_request.ticket= NULL;
+
+ /* Break when this was the last child. */
+ if (&child_l->next_global == this->children_last_l)
+ break;
+ }
+ /*
+ Remove children from the table list. This won't fail if called
+ twice. The list is terminated after removal.
+
+ If the parent is LEX::query_tables_own_last and pre-locked tables
+ follow (tables used by stored functions or triggers), the children
+ are inserted behind the parent and before the pre-locked tables. But
+ we do not adjust LEX::query_tables_own_last. The pre-locked tables
+ could have chopped off the list by clearing
+ *LEX::query_tables_own_last. This did also chop off the children. If
+ we would copy the reference from *this->children_last_l in this
+ case, we would put the chopped off pre-locked tables back to the
+ list. So we refrain from copying it back, if the destination has
+ been set to NULL meanwhile.
+ */
+ if (this->children_l->prev_global && *this->children_l->prev_global)
+ *this->children_l->prev_global= *this->children_last_l;
+ if (*this->children_last_l)
+ (*this->children_last_l)->prev_global= this->children_l->prev_global;
+
+ /*
+ If table elements being removed are at the end of table list we
+ need to adjust LEX::query_tables_last member to point to the
+ new last element of the list.
+ */
+ if (thd->lex->query_tables_last == this->children_last_l)
+ thd->lex->query_tables_last= this->children_l->prev_global;
+
+ /*
+ If the statement requires prelocking, and prelocked
+ tables were added right after merge children, modify the
+ last own table pointer to point at prev_global of the merge
+ parent.
+ */
+ if (thd->lex->query_tables_own_last == this->children_last_l)
+ thd->lex->query_tables_own_last= this->children_l->prev_global;
+
+ /* Terminate child list. So it cannot be tried to remove again. */
+ *this->children_last_l= NULL;
+ this->children_l->prev_global= NULL;
+
+ /* Forget about the children, we don't own their memory. */
+ this->children_l= NULL;
+ this->children_last_l= NULL;
+ }
+
+ if (!this->file->children_attached)
+ {
+ DBUG_PRINT("myrg", ("merge children are already detached"));
+ goto end;
+ }
+
+ if (myrg_detach_children(this->file))
+ {
+ /* purecov: begin inspected */
+ print_error(my_errno, MYF(0));
+ DBUG_RETURN(my_errno ? my_errno : -1);
+ /* purecov: end */
+ }
+
+ end:
+ DBUG_RETURN(0);
+}
+
+
+/**
+ Close a MERGE parent table, but not its children.
+
+ @return status
+ @retval 0 OK
+ @retval != 0 Error, my_errno gives reason
+
+ @note
+ The children are expected to be closed separately by the caller.
+*/
+
+int ha_myisammrg::close(void)
+{
+ int rc;
+ DBUG_ENTER("ha_myisammrg::close");
+ /*
+ There are cases where children are not explicitly detached before
+ close. detach_children() protects itself against double detach.
+ */
+ if (!is_cloned)
+ detach_children();
+
+ rc= myrg_close(file);
+ file= 0;
+ DBUG_RETURN(rc);
+}
+
+int ha_myisammrg::write_row(const uchar * buf)
+{
+ DBUG_ENTER("ha_myisammrg::write_row");
+ DBUG_ASSERT(this->file->children_attached);
+
+ if (file->merge_insert_method == MERGE_INSERT_DISABLED || !file->tables)
+ DBUG_RETURN(HA_ERR_TABLE_READONLY);
+
+ if (table->next_number_field && buf == table->record[0])
+ {
+ int error;
+ if ((error= update_auto_increment()))
+ DBUG_RETURN(error); /* purecov: inspected */
+ }
+ DBUG_RETURN(myrg_write(file,buf));
+}
+
+int ha_myisammrg::update_row(const uchar * old_data, const uchar * new_data)
+{
+ DBUG_ASSERT(this->file->children_attached);
+ return myrg_update(file,old_data,new_data);
+}
+
+int ha_myisammrg::delete_row(const uchar * buf)
+{
+ DBUG_ASSERT(this->file->children_attached);
+ return myrg_delete(file,buf);
+}
+
+int ha_myisammrg::index_read_map(uchar * buf, const uchar * key,
+ key_part_map keypart_map,
+ enum ha_rkey_function find_flag)
+{
+ DBUG_ASSERT(this->file->children_attached);
+ int error=myrg_rkey(file,buf,active_index, key, keypart_map, find_flag);
+ return error;
+}
+
+int ha_myisammrg::index_read_idx_map(uchar * buf, uint index, const uchar * key,
+ key_part_map keypart_map,
+ enum ha_rkey_function find_flag)
+{
+ DBUG_ASSERT(this->file->children_attached);
+ int error=myrg_rkey(file,buf,index, key, keypart_map, find_flag);
+ return error;
+}
+
+int ha_myisammrg::index_read_last_map(uchar *buf, const uchar *key,
+ key_part_map keypart_map)
+{
+ DBUG_ASSERT(this->file->children_attached);
+ int error=myrg_rkey(file,buf,active_index, key, keypart_map,
+ HA_READ_PREFIX_LAST);
+ return error;
+}
+
+int ha_myisammrg::index_next(uchar * buf)
+{
+ DBUG_ASSERT(this->file->children_attached);
+ int error=myrg_rnext(file,buf,active_index);
+ return error;
+}
+
+int ha_myisammrg::index_prev(uchar * buf)
+{
+ DBUG_ASSERT(this->file->children_attached);
+ int error=myrg_rprev(file,buf, active_index);
+ return error;
+}
+
+int ha_myisammrg::index_first(uchar * buf)
+{
+ DBUG_ASSERT(this->file->children_attached);
+ int error=myrg_rfirst(file, buf, active_index);
+ return error;
+}
+
+int ha_myisammrg::index_last(uchar * buf)
+{
+ DBUG_ASSERT(this->file->children_attached);
+ int error=myrg_rlast(file, buf, active_index);
+ return error;
+}
+
+int ha_myisammrg::index_next_same(uchar * buf,
+ const uchar *key __attribute__((unused)),
+ uint length __attribute__((unused)))
+{
+ int error;
+ DBUG_ASSERT(this->file->children_attached);
+ do
+ {
+ error= myrg_rnext_same(file,buf);
+ } while (error == HA_ERR_RECORD_DELETED);
+ return error;
+}
+
+
+int ha_myisammrg::rnd_init(bool scan)
+{
+ DBUG_ASSERT(this->file->children_attached);
+ return myrg_reset(file);
+}
+
+
+int ha_myisammrg::rnd_next(uchar *buf)
+{
+ DBUG_ASSERT(this->file->children_attached);
+ int error=myrg_rrnd(file, buf, HA_OFFSET_ERROR);
+ return error;
+}
+
+
+int ha_myisammrg::rnd_pos(uchar * buf, uchar *pos)
+{
+ DBUG_ASSERT(this->file->children_attached);
+ int error=myrg_rrnd(file, buf, my_get_ptr(pos,ref_length));
+ return error;
+}
+
+void ha_myisammrg::position(const uchar *record)
+{
+ DBUG_ASSERT(this->file->children_attached);
+ ulonglong row_position= myrg_position(file);
+ my_store_ptr(ref, ref_length, (my_off_t) row_position);
+}
+
+
+ha_rows ha_myisammrg::records_in_range(uint inx,
+ const key_range *min_key,
+ const key_range *max_key,
+ page_range *pages)
+{
+ DBUG_ASSERT(this->file->children_attached);
+ return (ha_rows) myrg_records_in_range(file, (int) inx, min_key, max_key,
+ pages);
+}
+
+
+int ha_myisammrg::delete_all_rows()
+{
+ int err= 0;
+ MYRG_TABLE *table;
+ DBUG_ENTER("ha_myisammrg::delete_all_rows");
+
+ for (table= file->open_tables; table != file->end_table; table++)
+ {
+ if ((err= mi_delete_all_rows(table->table)))
+ break;
+ }
+
+ DBUG_RETURN(err);
+}
+
+
+int ha_myisammrg::info(uint flag)
+{
+ MYMERGE_INFO mrg_info;
+ DBUG_ASSERT(this->file->children_attached);
+ (void) myrg_status(file,&mrg_info,flag);
+ /*
+ The following fails if one has not compiled MySQL with -DBIG_TABLES
+ and one has more than 2^32 rows in the merge tables.
+ */
+ stats.records = (ha_rows) mrg_info.records;
+ stats.deleted = (ha_rows) mrg_info.deleted;
+#if !defined(BIG_TABLES) || SIZEOF_OFF_T == 4
+ if ((mrg_info.records >= (ulonglong) 1 << 32) ||
+ (mrg_info.deleted >= (ulonglong) 1 << 32))
+ table->s->crashed= 1;
+#endif
+ stats.data_file_length= mrg_info.data_file_length;
+ if (mrg_info.errkey >= (int) table_share->keys)
+ {
+ /*
+ If value of errkey is higher than the number of keys
+ on the table set errkey to MAX_KEY. This will be
+ treated as unknown key case and error message generator
+ won't try to locate key causing segmentation fault.
+ */
+ mrg_info.errkey= MAX_KEY;
+ }
+ table->s->keys_in_use.set_prefix(table->s->keys);
+ stats.mean_rec_length= mrg_info.reclength;
+
+ /*
+ The handler::block_size is used all over the code in index scan cost
+ calculations. It is used to get number of disk seeks required to
+ retrieve a number of index tuples.
+ If the merge table has N underlying tables, then (assuming underlying
+ tables have equal size, the only "simple" approach we can use)
+ retrieving X index records from a merge table will require N times more
+ disk seeks compared to doing the same on a MyISAM table with equal
+ number of records.
+ In the edge case (file_tables > myisam_block_size) we'll get
+ block_size==0, and index calculation code will act as if we need one
+ disk seek to retrieve one index tuple.
+
+ TODO: In 5.2 index scan cost calculation will be factored out into a
+ virtual function in class handler and we'll be able to remove this hack.
+ */
+ stats.block_size= 0;
+ if (file->tables)
+ stats.block_size= myisam_block_size / file->tables;
+
+ stats.update_time= 0;
+#if SIZEOF_OFF_T > 4
+ ref_length=6; // Should be big enough
+#else
+ ref_length=4; // Can't be > than my_off_t
+#endif
+ if (flag & HA_STATUS_CONST)
+ {
+ if (table->s->key_parts && mrg_info.rec_per_key)
+ {
+#ifdef HAVE_valgrind
+ /*
+ valgrind may be unhappy about it, because optimizer may access values
+ between file->keys and table->key_parts, that will be uninitialized.
+ It's safe though, because even if opimizer will decide to use a key
+ with such a number, it'll be an error later anyway.
+ */
+ bzero((char*) table->key_info[0].rec_per_key,
+ sizeof(table->key_info[0].rec_per_key[0]) * table->s->key_parts);
+#endif
+ memcpy((char*) table->key_info[0].rec_per_key,
+ (char*) mrg_info.rec_per_key,
+ sizeof(table->key_info[0].rec_per_key[0]) *
+ MY_MIN(file->keys, table->s->key_parts));
+ }
+ }
+ if (flag & HA_STATUS_ERRKEY)
+ {
+ errkey= mrg_info.errkey;
+ my_store_ptr(dup_ref, ref_length, mrg_info.dupp_key_pos);
+ }
+ return 0;
+}
+
+
+int ha_myisammrg::extra(enum ha_extra_function operation)
+{
+ if (operation == HA_EXTRA_ADD_CHILDREN_LIST)
+ {
+ int rc= add_children_list();
+ return(rc);
+ }
+ else if (operation == HA_EXTRA_ATTACH_CHILDREN)
+ {
+ int rc= attach_children();
+ if (!rc)
+ (void) extra(HA_EXTRA_NO_READCHECK); // Not needed in SQL
+ return(rc);
+ }
+ else if (operation == HA_EXTRA_IS_ATTACHED_CHILDREN)
+ {
+ /* For the upper layer pretend empty MERGE union is never attached. */
+ return(file && file->tables && file->children_attached);
+ }
+ else if (operation == HA_EXTRA_DETACH_CHILDREN)
+ {
+ /*
+ Note that detach must not touch the children in any way.
+ They may have been closed at ths point already.
+ */
+ int rc= detach_children();
+ return(rc);
+ }
+
+ /* As this is just a mapping, we don't have to force the underlying
+ tables to be closed */
+ if (operation == HA_EXTRA_FORCE_REOPEN ||
+ operation == HA_EXTRA_PREPARE_FOR_DROP ||
+ operation == HA_EXTRA_PREPARE_FOR_RENAME)
+ return 0;
+ if (operation == HA_EXTRA_MMAP && !opt_myisam_use_mmap)
+ return 0;
+ return myrg_extra(file,operation,0);
+}
+
+int ha_myisammrg::reset(void)
+{
+ /* This is normally called with detached children. */
+ return myrg_reset(file);
+}
+
+/* To be used with WRITE_CACHE, EXTRA_CACHE and BULK_INSERT_BEGIN */
+
+int ha_myisammrg::extra_opt(enum ha_extra_function operation, ulong cache_size)
+{
+ DBUG_ASSERT(this->file->children_attached);
+ return myrg_extra(file, operation, (void*) &cache_size);
+}
+
+int ha_myisammrg::external_lock(THD *thd, int lock_type)
+{
+ /*
+ This can be called with no children attached. E.g. FLUSH TABLES
+ unlocks and re-locks tables under LOCK TABLES, but it does not open
+ them first. So they are detached all the time. But locking of the
+ children should work anyway because thd->open_tables is not changed
+ during FLUSH TABLES.
+
+ If this handler instance has been cloned, we still must call
+ myrg_lock_database().
+ */
+ if (is_cloned)
+ return myrg_lock_database(file, lock_type);
+ return 0;
+}
+
+uint ha_myisammrg::lock_count(void) const
+{
+ return 0;
+}
+
+
+THR_LOCK_DATA **ha_myisammrg::store_lock(THD *thd,
+ THR_LOCK_DATA **to,
+ enum thr_lock_type lock_type)
+{
+ MYRG_TABLE *open_table;
+
+ /*
+ This method can be called while another thread is attaching the
+ children. If the processor reorders instructions or write to memory,
+ 'children_attached' could be set before 'open_tables' has all the
+ pointers to the children. Use of a mutex here and in
+ myrg_attach_children() forces consistent data.
+ */
+ mysql_mutex_lock(&this->file->mutex);
+
+ /*
+ When MERGE table is open, but not yet attached, other threads
+ could flush it, which means calling mysql_lock_abort_for_thread()
+ on this threads TABLE. 'children_attached' is FALSE in this
+ situation. Since the table is not locked, return no lock data.
+ */
+ if (!this->file->children_attached)
+ goto end; /* purecov: tested */
+
+ for (open_table=file->open_tables ;
+ open_table != file->end_table ;
+ open_table++)
+ open_table->table->lock.priority|= THR_LOCK_MERGE_PRIV;
+
+ end:
+ mysql_mutex_unlock(&this->file->mutex);
+ return to;
+}
+
+
+/* Find out database name and table name from a filename */
+
+static void split_file_name(const char *file_name,
+ LEX_STRING *db, LEX_STRING *name)
+{
+ size_t dir_length, prefix_length;
+ char buff[FN_REFLEN];
+
+ db->length= 0;
+ strmake_buf(buff, file_name);
+ dir_length= dirname_length(buff);
+ if (dir_length > 1)
+ {
+ /* Get database */
+ buff[dir_length-1]= 0; // Remove end '/'
+ prefix_length= dirname_length(buff);
+ db->str= (char*) file_name+ prefix_length;
+ db->length= dir_length - prefix_length -1;
+ }
+ name->str= (char*) file_name+ dir_length;
+ name->length= (uint) (fn_ext(name->str) - name->str);
+}
+
+
+void ha_myisammrg::update_create_info(HA_CREATE_INFO *create_info)
+{
+ DBUG_ENTER("ha_myisammrg::update_create_info");
+
+ if (!(create_info->used_fields & HA_CREATE_USED_UNION))
+ {
+ TABLE_LIST *child_table, *end= NULL;
+ THD *thd=ha_thd();
+
+ if (children_l != NULL)
+ {
+ for (child_table= children_l;; child_table= child_table->next_global)
+ {
+ TABLE_LIST *ptr;
+
+ if (!(ptr= (TABLE_LIST *) thd->calloc(sizeof(TABLE_LIST))))
+ DBUG_VOID_RETURN;
+
+ if (!(ptr->table_name.str= thd->strmake(child_table->table_name.str,
+ child_table->table_name.length)))
+ DBUG_VOID_RETURN;
+ ptr->table_name.length= child_table->table_name.length;
+ if (child_table->db.str && !(ptr->db.str= thd->strmake(child_table->db.str,
+ child_table->db.length)))
+ DBUG_VOID_RETURN;
+ ptr->db.length= child_table->db.length;
+
+ if (create_info->merge_list)
+ end->next_local= ptr;
+ else
+ create_info->merge_list= ptr;
+ end= ptr;
+
+ if (&child_table->next_global == children_last_l)
+ break;
+ }
+ }
+ }
+ if (!(create_info->used_fields & HA_CREATE_USED_INSERT_METHOD))
+ {
+ create_info->merge_insert_method = file->merge_insert_method;
+ }
+ DBUG_VOID_RETURN;
+}
+
+
+int ha_myisammrg::create_mrg(const char *name, HA_CREATE_INFO *create_info)
+{
+ char buff[FN_REFLEN];
+ const char **table_names, **pos;
+ TABLE_LIST *tables= create_info->merge_list;
+ THD *thd= ha_thd();
+ size_t dirlgt= dirname_length(name);
+ uint ntables= 0;
+ DBUG_ENTER("ha_myisammrg::create_mrg");
+
+ for (tables= create_info->merge_list; tables; tables= tables->next_local)
+ ntables++;
+
+ /* Allocate a table_names array in thread mem_root. */
+ if (!(pos= table_names= (const char**) thd->alloc((ntables + 1) * sizeof(char*))))
+ DBUG_RETURN(HA_ERR_OUT_OF_MEM); /* purecov: inspected */
+
+ /* Create child path names. */
+ for (tables= create_info->merge_list; tables; tables= tables->next_local)
+ {
+ const char *table_name= buff;
+
+ /*
+ Construct the path to the MyISAM table. Try to meet two conditions:
+ 1.) Allow to include MyISAM tables from different databases, and
+ 2.) allow for moving DATADIR around in the file system.
+ The first means that we need paths in the .MRG file. The second
+ means that we should not have absolute paths in the .MRG file.
+ The best, we can do, is to use 'mysql_data_home', which is '.'
+ in mysqld and may be an absolute path in an embedded server.
+ This means that it might not be possible to move the DATADIR of
+ an embedded server without changing the paths in the .MRG file.
+
+ Do the same even for temporary tables. MERGE children are now
+ opened through the table cache. They are opened by db.table_name,
+ not by their path name.
+ */
+ size_t length= build_table_filename(buff, sizeof(buff),
+ tables->db.str, tables->table_name.str, "", 0);
+ /*
+ If a MyISAM table is in the same directory as the MERGE table,
+ we use the table name without a path. This means that the
+ DATADIR can easily be moved even for an embedded server as long
+ as the MyISAM tables are from the same database as the MERGE table.
+ */
+ if ((dirname_length(buff) == dirlgt) && ! memcmp(buff, name, dirlgt))
+ {
+ table_name+= dirlgt;
+ length-= dirlgt;
+ }
+ if (!(table_name= thd->strmake(table_name, length)))
+ DBUG_RETURN(HA_ERR_OUT_OF_MEM); /* purecov: inspected */
+
+ *pos++= table_name;
+ }
+ *pos=0;
+
+ /* Create a MERGE meta file from the table_names array. */
+ int res= myrg_create(name, table_names, create_info->merge_insert_method, 0);
+ DBUG_RETURN(res);
+}
+
+
+int ha_myisammrg::create(const char *name, TABLE *form,
+ HA_CREATE_INFO *create_info)
+{
+ char buff[FN_REFLEN];
+ DBUG_ENTER("ha_myisammrg::create");
+ fn_format(buff, name, "", MYRG_NAME_EXT, MY_UNPACK_FILENAME | MY_APPEND_EXT);
+ int res= create_mrg(buff, create_info);
+ DBUG_RETURN(res);
+}
+
+
+void ha_myisammrg::append_create_info(String *packet)
+{
+ const char *current_db;
+ size_t db_length;
+ THD *thd= current_thd;
+ TABLE_LIST *open_table, *first;
+
+ if (file->merge_insert_method != MERGE_INSERT_DISABLED)
+ {
+ const char *type;
+ packet->append(STRING_WITH_LEN(" INSERT_METHOD="));
+ type= get_type(&merge_insert_method,file->merge_insert_method-1);
+ packet->append(type, strlen(type));
+ }
+ /*
+ There is no sence adding UNION clause in case there is no underlying
+ tables specified.
+ */
+ if (file->open_tables == file->end_table)
+ return;
+ packet->append(STRING_WITH_LEN(" UNION=("));
+
+ current_db= table->s->db.str;
+ db_length= table->s->db.length;
+
+ for (first= open_table= children_l;;
+ open_table= open_table->next_global)
+ {
+ LEX_CSTRING db= open_table->db;
+
+ if (open_table != first)
+ packet->append(',');
+ /* Report database for mapped table if it isn't in current database */
+ if (db.length &&
+ (db_length != db.length ||
+ strncmp(current_db, db.str, db.length)))
+ {
+ append_identifier(thd, packet, db.str, db.length);
+ packet->append('.');
+ }
+ append_identifier(thd, packet, &open_table->table_name);
+ if (&open_table->next_global == children_last_l)
+ break;
+ }
+ packet->append(')');
+}
+
+
+enum_alter_inplace_result
+ha_myisammrg::check_if_supported_inplace_alter(TABLE *altered_table,
+ Alter_inplace_info *ha_alter_info)
+{
+ /*
+ We always support inplace ALTER in the new API, because old
+ HA_NO_COPY_ON_ALTER table_flags() hack prevents non-inplace ALTER anyway.
+ */
+ return HA_ALTER_INPLACE_EXCLUSIVE_LOCK;
+}
+
+
+bool ha_myisammrg::inplace_alter_table(TABLE *altered_table,
+ Alter_inplace_info *ha_alter_info)
+{
+ char tmp_path[FN_REFLEN];
+ const char *name= table->s->normalized_path.str;
+ DBUG_ENTER("ha_myisammrg::inplace_alter_table");
+ fn_format(tmp_path, name, "", MYRG_NAME_TMPEXT, MY_UNPACK_FILENAME | MY_APPEND_EXT);
+ int res= create_mrg(tmp_path, ha_alter_info->create_info);
+ if (res)
+ mysql_file_delete(rg_key_file_MRG, tmp_path, MYF(0));
+ else
+ {
+ char path[FN_REFLEN];
+ fn_format(path, name, "", MYRG_NAME_EXT, MY_UNPACK_FILENAME | MY_APPEND_EXT);
+ if (mysql_file_rename(rg_key_file_MRG, tmp_path, path, MYF(0)))
+ {
+ res= my_errno;
+ mysql_file_delete(rg_key_file_MRG, tmp_path, MYF(0));
+ }
+ }
+ DBUG_RETURN(res);
+}
+
+int ha_myisammrg::check(THD* thd, HA_CHECK_OPT* check_opt)
+{
+ return this->file->children_attached ? HA_ADMIN_OK : HA_ADMIN_CORRUPT;
+}
+
+
+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 (uint)(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(thd, key_length, key, (*block_table),
+ db_length, 0,
+ table_cache_type(),
+ 0, 0, TRUE))
+ DBUG_RETURN(TRUE);
+ }
+ DBUG_RETURN(FALSE);
+}
+
+
+void ha_myisammrg::set_lock_type(enum thr_lock_type lock)
+{
+ handler::set_lock_type(lock);
+ if (children_l != NULL)
+ {
+ for (TABLE_LIST *child_table= children_l;;
+ child_table= child_table->next_global)
+ {
+ child_table->lock_type=
+ child_table->table->reginfo.lock_type= lock;
+
+ if (&child_table->next_global == children_last_l)
+ break;
+ }
+ }
+}
+
+extern int myrg_panic(enum ha_panic_function flag);
+int myisammrg_panic(handlerton *hton, ha_panic_function flag)
+{
+ return myrg_panic(flag);
+}
+
+static int myisammrg_init(void *p)
+{
+ handlerton *myisammrg_hton;
+
+ myisammrg_hton= (handlerton *)p;
+
+#ifdef HAVE_PSI_INTERFACE
+ init_myisammrg_psi_keys();
+#endif
+
+ myisammrg_hton->db_type= DB_TYPE_MRG_MYISAM;
+ myisammrg_hton->create= myisammrg_create_handler;
+ myisammrg_hton->panic= myisammrg_panic;
+ myisammrg_hton->flags= HTON_NO_PARTITION;
+ myisammrg_hton->tablefile_extensions= ha_myisammrg_exts;
+
+ return 0;
+}
+
+struct st_mysql_storage_engine myisammrg_storage_engine=
+{ MYSQL_HANDLERTON_INTERFACE_VERSION };
+
+maria_declare_plugin(myisammrg)
+{
+ MYSQL_STORAGE_ENGINE_PLUGIN,
+ &myisammrg_storage_engine,
+ "MRG_MyISAM",
+ "MySQL AB",
+ "Collection of identical MyISAM tables",
+ PLUGIN_LICENSE_GPL,
+ myisammrg_init, /* Plugin Init */
+ NULL, /* Plugin Deinit */
+ 0x0100, /* 1.0 */
+ NULL, /* status variables */
+ NULL, /* system variables */
+ "1.0", /* string version */
+ MariaDB_PLUGIN_MATURITY_STABLE /* maturity */
+}
+maria_declare_plugin_end;
diff --git a/storage/myisammrg/ha_myisammrg.h b/storage/myisammrg/ha_myisammrg.h
new file mode 100644
index 00000000..6da327ec
--- /dev/null
+++ b/storage/myisammrg/ha_myisammrg.h
@@ -0,0 +1,162 @@
+/*
+ Copyright (c) 2000, 2011, Oracle and/or its affiliates
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */
+
+
+#ifdef USE_PRAGMA_INTERFACE
+#pragma interface /* gcc class implementation */
+#endif
+
+/* class for the the myisam merge handler */
+
+#include <myisammrg.h>
+
+/**
+ Represents one name of a MERGE child.
+
+ @todo: Add MYRG_SHARE and store chlidren names in the
+ share.
+*/
+
+class Mrg_child_def: public Sql_alloc
+{
+ /* Remembered MERGE child def version. See top comment in ha_myisammrg.cc */
+ enum_table_ref_type m_child_table_ref_type;
+ ulong m_child_def_version;
+public:
+ LEX_STRING db;
+ LEX_STRING name;
+
+ /* Access MERGE child def version. See top comment in ha_myisammrg.cc */
+ inline enum_table_ref_type get_child_table_ref_type()
+ {
+ return m_child_table_ref_type;
+ }
+ inline ulong get_child_def_version()
+ {
+ return m_child_def_version;
+ }
+ inline void set_child_def_version(enum_table_ref_type child_table_ref_type,
+ ulong version)
+ {
+ m_child_table_ref_type= child_table_ref_type;
+ m_child_def_version= version;
+ }
+
+ Mrg_child_def(char *db_arg, size_t db_len_arg,
+ char *table_name_arg, size_t table_name_len_arg)
+ {
+ db.str= db_arg;
+ db.length= db_len_arg;
+ name.str= table_name_arg;
+ name.length= table_name_len_arg;
+ m_child_def_version= ~0UL;
+ m_child_table_ref_type= TABLE_REF_NULL;
+ }
+};
+
+
+class ha_myisammrg final : public handler
+{
+ MYRG_INFO *file;
+ my_bool is_cloned; /* This instance has been cloned */
+
+public:
+ MEM_ROOT children_mem_root; /* mem root for children list */
+ List<Mrg_child_def> child_def_list;
+ TABLE_LIST *children_l; /* children list */
+ TABLE_LIST **children_last_l; /* children list end */
+ uint test_if_locked; /* flags from ::open() */
+
+ ha_myisammrg(handlerton *hton, TABLE_SHARE *table_arg);
+ ~ha_myisammrg();
+ const char *index_type(uint key_number);
+ ulonglong table_flags() const
+ {
+ return (HA_REC_NOT_IN_SEQ | HA_AUTO_PART_KEY | HA_NO_TRANSACTIONS |
+ HA_BINLOG_ROW_CAPABLE | HA_BINLOG_STMT_CAPABLE |
+ HA_NULL_IN_KEY | HA_CAN_INDEX_BLOBS | HA_FILE_BASED |
+ HA_ANY_INDEX_MAY_BE_UNIQUE | HA_CAN_BIT_FIELD |
+ HA_HAS_RECORDS | HA_CAN_EXPORT |
+ HA_NO_COPY_ON_ALTER |
+ HA_DUPLICATE_POS | HA_CAN_MULTISTEP_MERGE);
+ }
+ 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);
+ }
+ uint max_supported_keys() const { return MI_MAX_KEY; }
+ uint max_supported_key_length() const { return HA_MAX_KEY_LENGTH; }
+ uint max_supported_key_part_length() const { return HA_MAX_KEY_LENGTH; }
+ double scan_time()
+ { return ulonglong2double(stats.data_file_length) / IO_SIZE + file->tables; }
+
+ int open(const char *name, int mode, uint test_if_locked);
+ int add_children_list(void);
+ int attach_children(void);
+ int detach_children(void);
+ virtual handler *clone(const char *name, MEM_ROOT *mem_root);
+ int close(void);
+ int write_row(const uchar * buf);
+ int update_row(const uchar * old_data, const uchar * new_data);
+ int delete_row(const uchar * buf);
+ int index_read_map(uchar *buf, const uchar *key, key_part_map keypart_map,
+ enum ha_rkey_function find_flag);
+ int index_read_idx_map(uchar *buf, uint index, const uchar *key,
+ key_part_map keypart_map,
+ enum ha_rkey_function find_flag);
+ int index_read_last_map(uchar *buf, const uchar *key, key_part_map keypart_map);
+ int index_next(uchar * buf);
+ int index_prev(uchar * buf);
+ int index_first(uchar * buf);
+ int index_last(uchar * buf);
+ int index_next_same(uchar *buf, const uchar *key, uint keylen);
+ int rnd_init(bool scan);
+ int rnd_next(uchar *buf);
+ int rnd_pos(uchar * buf, uchar *pos);
+ void position(const uchar *record);
+ ha_rows records_in_range(uint inx, const key_range *start_key,
+ const key_range *end_key, page_range *pages);
+ int delete_all_rows();
+ int info(uint);
+ int reset(void);
+ int extra(enum ha_extra_function operation);
+ int extra_opt(enum ha_extra_function operation, ulong cache_size);
+ int external_lock(THD *thd, int lock_type);
+ uint lock_count(void) const;
+ int create_mrg(const char *name, HA_CREATE_INFO *create_info);
+ int create(const char *name, TABLE *form, HA_CREATE_INFO *create_info);
+ THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to,
+ enum thr_lock_type lock_type);
+ void update_create_info(HA_CREATE_INFO *create_info);
+ void append_create_info(String *packet);
+ MYRG_INFO *myrg_info() { return file; }
+ TABLE *table_ptr() { return table; }
+ enum_alter_inplace_result check_if_supported_inplace_alter(TABLE *,
+ Alter_inplace_info *);
+ bool inplace_alter_table(TABLE *altered_table,
+ Alter_inplace_info *ha_alter_info);
+ 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);
+ virtual void set_lock_type(enum thr_lock_type lock);
+};
diff --git a/storage/myisammrg/myrg_close.c b/storage/myisammrg/myrg_close.c
new file mode 100644
index 00000000..636382f9
--- /dev/null
+++ b/storage/myisammrg/myrg_close.c
@@ -0,0 +1,68 @@
+/* Copyright (c) 2000, 2010, 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 Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */
+
+/* close a isam-database */
+
+#include "myrg_def.h"
+
+int myrg_close(MYRG_INFO *info)
+{
+ int error=0,new_error;
+ MYRG_TABLE *file;
+ DBUG_ENTER("myrg_close");
+
+ /*
+ Assume that info->children_attached means that this is called from
+ direct use of MERGE, not from a MySQL server. In this case the
+ children must be closed and info->rec_per_key_part is part of the
+ 'info' multi_alloc.
+ If info->children_attached is false, this is called from a MySQL
+ server. Children are closed independently but info->rec_per_key_part
+ must be freed.
+ Just in case of a server panic (myrg_panic()) info->children_attached
+ might be true. We would close the children though they should be
+ closed independently and info->rec_per_key_part is not freed.
+ This should be acceptable for a panic.
+ In case of a MySQL server and no children, children_attached is
+ always true. In this case no rec_per_key_part has been allocated.
+ So it is correct to use the branch where an empty list of tables is
+ (not) closed.
+ */
+ if (info->children_attached)
+ {
+ for (file= info->open_tables; file != info->end_table; file++)
+ {
+ /* purecov: begin inspected */
+ if ((new_error= mi_close(file->table)))
+ error= new_error;
+ else
+ file->table= NULL;
+ /* purecov: end */
+ }
+ }
+ else
+ my_free(info->rec_per_key_part);
+ delete_queue(&info->by_key);
+ mysql_mutex_lock(&THR_LOCK_open);
+ myrg_open_list=list_delete(myrg_open_list,&info->open_list);
+ mysql_mutex_unlock(&THR_LOCK_open);
+ mysql_mutex_destroy(&info->mutex);
+ my_free(info);
+ if (error)
+ {
+ DBUG_RETURN(my_errno=error);
+ }
+ DBUG_RETURN(0);
+}
diff --git a/storage/myisammrg/myrg_create.c b/storage/myisammrg/myrg_create.c
new file mode 100644
index 00000000..67e94f1d
--- /dev/null
+++ b/storage/myisammrg/myrg_create.c
@@ -0,0 +1,73 @@
+/* Copyright (c) 2000, 2001, 2005-2007 MySQL AB, 2009 Sun Microsystems, Inc.
+ Use is subject to license terms.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */
+
+/* Create a MYMERGE_-file */
+
+#include "myrg_def.h"
+
+ /* create file named 'name' and save filenames in it
+ table_names should be NULL or a vector of string-pointers with
+ a NULL-pointer last
+ */
+
+int myrg_create(const char *name, const char **table_names,
+ uint insert_method, my_bool fix_names)
+{
+ int save_errno;
+ uint errpos;
+ File file;
+ char buff[FN_REFLEN],*end;
+ DBUG_ENTER("myrg_create");
+
+ errpos=0;
+ if ((file= mysql_file_create(rg_key_file_MRG, name, 0,
+ O_RDWR | O_EXCL | O_NOFOLLOW, MYF(MY_WME))) < 0)
+ goto err;
+ errpos=1;
+ if (table_names)
+ {
+ for ( ; *table_names ; table_names++)
+ {
+ strmov(buff,*table_names);
+ if (fix_names)
+ fn_same(buff,name,4);
+ *(end=strend(buff))='\n';
+ end[1]=0;
+ if (mysql_file_write(file, (uchar*) buff, (uint) (end-buff+1),
+ MYF(MY_WME | MY_NABP)))
+ goto err;
+ }
+ }
+ if (insert_method != MERGE_INSERT_DISABLED)
+ {
+ end=strxmov(buff,"#INSERT_METHOD=",
+ get_type(&merge_insert_method,insert_method-1),"\n",NullS);
+ if (mysql_file_write(file, (uchar*) buff, (uint) (end-buff),
+ MYF(MY_WME | MY_NABP)))
+ goto err;
+ }
+ if (mysql_file_close(file, MYF(0)))
+ goto err;
+ DBUG_RETURN(0);
+
+err:
+ save_errno=my_errno ? my_errno : -1;
+ switch (errpos) {
+ case 1:
+ (void) mysql_file_close(file, MYF(0));
+ }
+ DBUG_RETURN(my_errno=save_errno);
+} /* myrg_create */
diff --git a/storage/myisammrg/myrg_def.h b/storage/myisammrg/myrg_def.h
new file mode 100644
index 00000000..8bb79a73
--- /dev/null
+++ b/storage/myisammrg/myrg_def.h
@@ -0,0 +1,44 @@
+/* Copyright (c) 2000, 2011, 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 Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */
+
+/* This file is included by all myisam-merge files */
+
+#ifndef N_MAXKEY
+#include "../myisam/myisamdef.h"
+#endif
+
+#include "myisammrg.h"
+
+extern LIST *myrg_open_list;
+
+extern mysql_mutex_t THR_LOCK_open;
+
+int _myrg_init_queue(MYRG_INFO *info,int inx,enum ha_rkey_function search_flag);
+int _myrg_mi_read_record(MI_INFO *info, uchar *buf);
+#ifdef __cplusplus
+extern "C"
+#endif
+void myrg_print_wrong_table(const char *table_name);
+
+/* Always defined */
+extern PSI_memory_key rg_key_memory_MYRG_INFO;
+
+C_MODE_START
+extern PSI_mutex_key rg_key_mutex_MYRG_INFO_mutex;
+extern PSI_memory_key rg_key_memory_children;
+extern PSI_file_key rg_key_file_MRG;
+void init_myisammrg_psi_keys();
+C_MODE_END
+
diff --git a/storage/myisammrg/myrg_delete.c b/storage/myisammrg/myrg_delete.c
new file mode 100644
index 00000000..e13b9b4e
--- /dev/null
+++ b/storage/myisammrg/myrg_delete.c
@@ -0,0 +1,27 @@
+/* Copyright (c) 2000-2002, 2005-2007 MySQL AB
+ Use is subject to license terms
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
+
+/* Delete last read record */
+
+#include "myrg_def.h"
+
+int myrg_delete(MYRG_INFO *info, const uchar *record)
+{
+ if (!info->current_table)
+ return (my_errno= HA_ERR_NO_ACTIVE_RECORD);
+
+ return mi_delete(info->current_table->table,record);
+}
diff --git a/storage/myisammrg/myrg_extra.c b/storage/myisammrg/myrg_extra.c
new file mode 100644
index 00000000..2b3861b9
--- /dev/null
+++ b/storage/myisammrg/myrg_extra.c
@@ -0,0 +1,97 @@
+/* Copyright (c) 2000-2003, 2005-2007 MySQL AB, 2009 Sun Microsystems, Inc.
+ Use is subject to license terms.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */
+
+/*
+ Extra functions we want to do with a database
+ - All flags, exept record-cache-flags, are set in all used databases
+ record-cache-flags are set in myrg_rrnd when we are changing database.
+*/
+
+#include "myrg_def.h"
+
+int myrg_extra(MYRG_INFO *info,enum ha_extra_function function,
+ void *extra_arg)
+{
+ int error,save_error=0;
+ MYRG_TABLE *file;
+ DBUG_ENTER("myrg_extra");
+ DBUG_PRINT("info",("function: %lu", (ulong) function));
+
+ if (!info->children_attached)
+ DBUG_RETURN(0);
+ if (function == HA_EXTRA_CACHE)
+ {
+ info->cache_in_use=1;
+ info->cache_size= (extra_arg ? *(ulong*) extra_arg :
+ my_default_record_cache_size);
+ }
+ else
+ {
+ if (function == HA_EXTRA_NO_CACHE ||
+ function == HA_EXTRA_PREPARE_FOR_UPDATE)
+ info->cache_in_use=0;
+ if (function == HA_EXTRA_RESET_STATE)
+ {
+ info->current_table=0;
+ info->last_used_table=info->open_tables;
+ }
+ for (file=info->open_tables ; file != info->end_table ; file++)
+ {
+ if ((error=mi_extra(file->table, function, extra_arg)))
+ save_error=error;
+ }
+ }
+ DBUG_RETURN(save_error);
+}
+
+
+void myrg_extrafunc(MYRG_INFO *info, invalidator_by_filename inv)
+{
+ MYRG_TABLE *file;
+ DBUG_ENTER("myrg_extrafunc");
+
+ for (file=info->open_tables ; file != info->end_table ; file++)
+ file->table->s->invalidator = inv;
+
+ DBUG_VOID_RETURN;
+}
+
+
+int myrg_reset(MYRG_INFO *info)
+{
+ int save_error= 0;
+ MYRG_TABLE *file;
+ DBUG_ENTER("myrg_reset");
+
+ info->cache_in_use=0;
+ info->current_table=0;
+ info->last_used_table= info->open_tables;
+
+ /*
+ This is normally called with detached children.
+ Return OK as this is the normal case.
+ */
+ if (!info->children_attached)
+ DBUG_RETURN(0);
+
+ for (file=info->open_tables ; file != info->end_table ; file++)
+ {
+ int error;
+ if ((error= mi_reset(file->table)))
+ save_error=error;
+ }
+ DBUG_RETURN(save_error);
+}
diff --git a/storage/myisammrg/myrg_info.c b/storage/myisammrg/myrg_info.c
new file mode 100644
index 00000000..1d78c650
--- /dev/null
+++ b/storage/myisammrg/myrg_info.c
@@ -0,0 +1,86 @@
+/* Copyright (c) 2000, 2001, 2005, 2006 MySQL AB, 2009 Sun Microsystems, Inc.
+ Use is subject to license terms.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */
+
+#include "myrg_def.h"
+
+ulonglong myrg_position(MYRG_INFO *info)
+{
+ MYRG_TABLE *current_table;
+
+ if (!(current_table = info->current_table) &&
+ info->open_tables != info->end_table)
+ current_table = info->open_tables;
+ return current_table ?
+ current_table->table->lastpos + current_table->file_offset :
+ ~(ulonglong) 0;
+}
+
+int myrg_status(MYRG_INFO *info,register MYMERGE_INFO *x,int flag)
+{
+ MYRG_TABLE *current_table;
+ DBUG_ENTER("myrg_status");
+
+ if (!(current_table = info->current_table) &&
+ info->open_tables != info->end_table)
+ current_table = info->open_tables;
+ x->recpos = info->current_table ?
+ info->current_table->table->lastpos + info->current_table->file_offset :
+ (ulong) -1L;
+ if (flag != HA_STATUS_POS)
+ {
+ MYRG_TABLE *file;
+
+ info->records=info->del=info->data_file_length=0;
+ for (file=info->open_tables ; file != info->end_table ; file++)
+ {
+ file->file_offset=info->data_file_length;
+ info->data_file_length+=file->table->s->state.state.data_file_length;
+ info->records+=file->table->s->state.state.records;
+ info->del+=file->table->s->state.state.del;
+ DBUG_PRINT("info2",("table: %s, offset: %lu",
+ file->table->filename,(ulong) file->file_offset));
+ }
+ x->records= info->records;
+ x->deleted= info->del;
+ x->data_file_length= info->data_file_length;
+ x->reclength= info->reclength;
+ x->options= info->options;
+ if (current_table)
+ {
+ /*
+ errkey is set to the index number of the myisam tables. But
+ since the MERGE table can have less keys than the MyISAM
+ tables, errkey cannot be be used as an index into the key_info
+ on the server. This value will be overwritten with MAX_KEY by
+ the MERGE engine.
+ */
+ x->errkey= current_table->table->errkey;
+ /*
+ Calculate the position of the duplicate key to be the sum of the
+ offset of the myisam file and the offset into the file at which
+ the duplicate key is located.
+ */
+ x->dupp_key_pos= current_table->file_offset + current_table->table->dupp_key_pos;
+ }
+ else
+ {
+ x->errkey= 0;
+ x->dupp_key_pos= 0;
+ }
+ x->rec_per_key = info->rec_per_key_part;
+ }
+ DBUG_RETURN(0);
+}
diff --git a/storage/myisammrg/myrg_locking.c b/storage/myisammrg/myrg_locking.c
new file mode 100644
index 00000000..a79e35d2
--- /dev/null
+++ b/storage/myisammrg/myrg_locking.c
@@ -0,0 +1,45 @@
+/* Copyright (c) 2000-2002, 2005-2007 MySQL AB
+ Use is subject to license terms
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
+
+/*
+ Lock databases against read or write.
+*/
+
+#include "myrg_def.h"
+
+int myrg_lock_database(MYRG_INFO *info, int lock_type)
+{
+ int error,new_error;
+ MYRG_TABLE *file;
+
+ error=0;
+ for (file=info->open_tables ; file != info->end_table ; file++)
+ {
+ DBUG_ASSERT(file->table->open_flag & HA_OPEN_MERGE_TABLE);
+
+ if ((new_error=mi_lock_database(file->table,lock_type)))
+ {
+ error=new_error;
+ if (lock_type != F_UNLCK)
+ {
+ while (--file >= info->open_tables)
+ mi_lock_database(file->table, F_UNLCK);
+ break;
+ }
+ }
+ }
+ return(error);
+}
diff --git a/storage/myisammrg/myrg_open.c b/storage/myisammrg/myrg_open.c
new file mode 100644
index 00000000..4a983684
--- /dev/null
+++ b/storage/myisammrg/myrg_open.c
@@ -0,0 +1,551 @@
+/*
+ Copyright (c) 2000, 2011, Oracle and/or its affiliates
+ Copyright (c) 2010, 2020, MariaDB Corporation.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
+
+/* open a MyISAM MERGE table */
+
+#include "myrg_def.h"
+#include <stddef.h>
+#include <errno.h>
+
+/*
+ open a MyISAM MERGE table
+ if handle_locking is 0 then exit with error if some table is locked
+ if handle_locking is 1 then wait if table is locked
+
+ NOTE: This function is only used in the MySQL server when a
+ table is cloned. It is also used for usage of MERGE
+ independent from MySQL. Currently there is some code
+ duplication between myrg_open() and myrg_parent_open() +
+ myrg_attach_children(). Please duplicate changes in these
+ functions or make common sub-functions.
+*/
+
+MYRG_INFO *myrg_open(const char *name, int mode, int handle_locking)
+{
+ int save_errno,errpos=0;
+ uint files= 0, i, UNINIT_VAR(key_parts), min_keys= 0;
+ size_t length, dir_length;
+ ulonglong file_offset=0;
+ char name_buff[FN_REFLEN*2],buff[FN_REFLEN];
+ MYRG_INFO *m_info=0;
+ File fd;
+ IO_CACHE file;
+ MI_INFO *isam=0;
+ uint found_merge_insert_method= 0;
+ size_t name_buff_length;
+ my_bool bad_children= FALSE;
+ DBUG_ENTER("myrg_open");
+
+ bzero((char*) &file,sizeof(file));
+ if ((fd= mysql_file_open(rg_key_file_MRG,
+ fn_format(name_buff, name, "", MYRG_NAME_EXT,
+ MY_UNPACK_FILENAME|MY_APPEND_EXT),
+ O_RDONLY | O_SHARE, MYF(0))) < 0)
+ goto err;
+ errpos=1;
+ if (init_io_cache(&file, fd, 4*IO_SIZE, READ_CACHE, 0, 0,
+ MYF(MY_WME | MY_NABP)))
+ goto err;
+ errpos=2;
+ dir_length=dirname_part(name_buff, name, &name_buff_length);
+ while ((length=my_b_gets(&file,buff,FN_REFLEN-1)))
+ {
+ char *end= &buff[length - 1];
+ if (*end == '\n')
+ *end= '\0';
+ if (buff[0] && buff[0] != '#')
+ files++;
+ }
+
+ my_b_seek(&file, 0);
+ while ((length=my_b_gets(&file,buff,FN_REFLEN-1)))
+ {
+ char *end= &buff[length - 1];
+ if (*end == '\n')
+ *end= '\0';
+ if (!buff[0])
+ continue; /* Skip empty lines */
+ if (buff[0] == '#')
+ {
+ if (!strncmp(buff+1,"INSERT_METHOD=",14))
+ { /* Lookup insert method */
+ int tmp= find_type(buff + 15, &merge_insert_method, FIND_TYPE_BASIC);
+ found_merge_insert_method = (uint) (tmp >= 0 ? tmp : 0);
+ }
+ continue; /* Skip comments */
+ }
+
+ if (!has_path(buff))
+ {
+ (void) strmake(name_buff+dir_length,buff,
+ sizeof(name_buff)-1-dir_length);
+ (void) cleanup_dirname(buff,name_buff);
+ }
+ else
+ fn_format(buff, buff, "", "", 0);
+ if (!(isam=mi_open(buff,mode,(handle_locking?HA_OPEN_WAIT_IF_LOCKED:0) |
+ HA_OPEN_MERGE_TABLE)))
+ {
+ if (handle_locking & HA_OPEN_FOR_REPAIR)
+ {
+ myrg_print_wrong_table(buff);
+ bad_children= TRUE;
+ continue;
+ }
+ goto bad_children;
+ }
+ if (!m_info) /* First file */
+ {
+ key_parts=isam->s->base.key_parts;
+ if (!(m_info= (MYRG_INFO*) my_malloc(rg_key_memory_MYRG_INFO,
+ sizeof(MYRG_INFO) +
+ files*sizeof(MYRG_TABLE) +
+ key_parts*sizeof(long),
+ MYF(MY_WME|MY_ZEROFILL))))
+ goto err;
+ DBUG_ASSERT(files);
+ m_info->open_tables=(MYRG_TABLE *) (m_info+1);
+ m_info->rec_per_key_part=(ulong *) (m_info->open_tables+files);
+ m_info->tables= files;
+ files= 0;
+ m_info->reclength=isam->s->base.reclength;
+ min_keys= isam->s->base.keys;
+ errpos=3;
+ }
+ m_info->open_tables[files].table= isam;
+ m_info->open_tables[files].file_offset=(my_off_t) file_offset;
+ file_offset+=isam->state->data_file_length;
+ files++;
+ if (m_info->reclength != isam->s->base.reclength)
+ {
+ if (handle_locking & HA_OPEN_FOR_REPAIR)
+ {
+ myrg_print_wrong_table(buff);
+ bad_children= TRUE;
+ continue;
+ }
+ goto bad_children;
+ }
+ m_info->options|= isam->s->options;
+ m_info->records+= isam->state->records;
+ m_info->del+= isam->state->del;
+ m_info->data_file_length+= isam->state->data_file_length;
+ if (min_keys > isam->s->base.keys)
+ min_keys= isam->s->base.keys;
+ for (i=0; i < key_parts; i++)
+ m_info->rec_per_key_part[i]+= (isam->s->state.rec_per_key_part[i] /
+ m_info->tables);
+ }
+
+ if (bad_children)
+ goto bad_children;
+ if (!m_info && !(m_info= (MYRG_INFO*) my_malloc(rg_key_memory_MYRG_INFO,
+ sizeof(MYRG_INFO),
+ MYF(MY_WME | MY_ZEROFILL))))
+ goto err;
+ /* Don't mark table readonly, for ALTER TABLE ... UNION=(...) to work */
+ m_info->options&= ~(HA_OPTION_COMPRESS_RECORD | HA_OPTION_READ_ONLY_DATA);
+ m_info->merge_insert_method= found_merge_insert_method;
+
+ if (sizeof(my_off_t) == 4 && file_offset > (ulonglong) (ulong) ~0L)
+ {
+ my_errno=HA_ERR_RECORD_FILE_FULL;
+ goto err;
+ }
+ m_info->keys= min_keys;
+ bzero((char*) &m_info->by_key,sizeof(m_info->by_key));
+
+ /* this works ok if the table list is empty */
+ m_info->end_table=m_info->open_tables+files;
+ m_info->last_used_table=m_info->open_tables;
+ m_info->children_attached= TRUE;
+
+ (void) mysql_file_close(fd, MYF(0));
+ end_io_cache(&file);
+ mysql_mutex_init(rg_key_mutex_MYRG_INFO_mutex,
+ &m_info->mutex, MY_MUTEX_INIT_FAST);
+ m_info->open_list.data=(void*) m_info;
+ mysql_mutex_lock(&THR_LOCK_open);
+ myrg_open_list=list_add(myrg_open_list,&m_info->open_list);
+ mysql_mutex_unlock(&THR_LOCK_open);
+ DBUG_RETURN(m_info);
+
+bad_children:
+ my_errno= HA_ERR_WRONG_MRG_TABLE_DEF;
+err:
+ save_errno=my_errno;
+ switch (errpos) {
+ case 3:
+ while (files)
+ (void) mi_close(m_info->open_tables[--files].table);
+ my_free(m_info);
+ /* Fall through */
+ case 2:
+ end_io_cache(&file);
+ /* Fall through */
+ case 1:
+ (void) mysql_file_close(fd, MYF(0));
+ }
+ my_errno=save_errno;
+ DBUG_RETURN (NULL);
+}
+
+
+/**
+ @brief Open parent table of a MyISAM MERGE table.
+
+ @detail Open MERGE meta file to get the table name paths for the child
+ tables. Count the children. Allocate and initialize MYRG_INFO
+ structure. Call a callback function for each child table.
+
+ @param[in] parent_name merge table name path as "database/table"
+ @param[in] callback function to call for each child table
+ @param[in] callback_param data pointer to give to the callback
+
+ @return MYRG_INFO pointer
+ @retval != NULL OK
+ @retval NULL Error
+
+ @note: Currently there is some code duplication between myrg_open()
+ and myrg_parent_open() + myrg_attach_children(). Please duplicate
+ changes in these functions or make common sub-functions.
+*/
+
+MYRG_INFO *myrg_parent_open(const char *parent_name,
+ int (*callback)(void*, const char*),
+ void *callback_param)
+{
+ MYRG_INFO *UNINIT_VAR(m_info);
+ int rc;
+ int errpos;
+ int save_errno;
+ int insert_method;
+ size_t length;
+ uint child_count;
+ File fd;
+ IO_CACHE file_cache;
+ char parent_name_buff[FN_REFLEN * 2];
+ char child_name_buff[FN_REFLEN];
+ DBUG_ENTER("myrg_parent_open");
+
+ rc= 1;
+ errpos= 0;
+ bzero((char*) &file_cache, sizeof(file_cache));
+
+ /* Open MERGE meta file. */
+ if ((fd= mysql_file_open(rg_key_file_MRG,
+ fn_format(parent_name_buff, parent_name,
+ "", MYRG_NAME_EXT,
+ MY_UNPACK_FILENAME|MY_APPEND_EXT),
+ O_RDONLY | O_SHARE, MYF(0))) < 0)
+ goto err; /* purecov: inspected */
+ errpos= 1;
+
+ if (init_io_cache(&file_cache, fd, 4 * IO_SIZE, READ_CACHE, 0, 0,
+ MYF(MY_WME | MY_NABP)))
+ goto err; /* purecov: inspected */
+ errpos= 2;
+
+ /* Count children. Determine insert method. */
+ child_count= 0;
+ insert_method= 0;
+ while ((length= my_b_gets(&file_cache, child_name_buff, FN_REFLEN - 1)))
+ {
+ /* Remove line terminator. */
+ if (child_name_buff[length - 1] == '\n')
+ child_name_buff[--length]= '\0';
+
+ /* Skip empty lines. */
+ if (!child_name_buff[0])
+ continue; /* purecov: inspected */
+
+ /* Skip comments, but evaluate insert method. */
+ if (child_name_buff[0] == '#')
+ {
+ if (!strncmp(child_name_buff + 1, "INSERT_METHOD=", 14))
+ {
+ /* Compare buffer with global methods list: merge_insert_method. */
+ insert_method= find_type(child_name_buff + 15,
+ &merge_insert_method, FIND_TYPE_BASIC);
+ }
+ continue;
+ }
+
+ /* Count the child. */
+ child_count++;
+ }
+
+ /* Allocate MERGE parent table structure. */
+ if (!(m_info= (MYRG_INFO*) my_malloc(rg_key_memory_MYRG_INFO,
+ sizeof(MYRG_INFO) +
+ child_count * sizeof(MYRG_TABLE),
+ MYF(MY_WME | MY_ZEROFILL))))
+ goto err; /* purecov: inspected */
+ errpos= 3;
+ m_info->open_tables= (MYRG_TABLE*) (m_info + 1);
+ m_info->tables= child_count;
+ m_info->merge_insert_method= insert_method > 0 ? insert_method : 0;
+ /* This works even if the table list is empty. */
+ m_info->end_table= m_info->open_tables + child_count;
+ if (!child_count)
+ {
+ /* Do not attach/detach an empty child list. */
+ m_info->children_attached= TRUE;
+ }
+
+ /* Call callback for each child. */
+ my_b_seek(&file_cache, 0);
+ while ((length= my_b_gets(&file_cache, child_name_buff, FN_REFLEN - 1)))
+ {
+ /* Remove line terminator. */
+ if (child_name_buff[length - 1] == '\n')
+ child_name_buff[--length]= '\0';
+
+ /* Skip empty lines and comments. */
+ if (!child_name_buff[0] || (child_name_buff[0] == '#'))
+ continue;
+
+ DBUG_PRINT("info", ("child: '%s'", child_name_buff));
+
+ /* Callback registers child with handler table. */
+ if ((rc= (*callback)(callback_param, child_name_buff)))
+ goto err; /* purecov: inspected */
+ }
+
+ end_io_cache(&file_cache);
+ (void) mysql_file_close(fd, MYF(0));
+ mysql_mutex_init(rg_key_mutex_MYRG_INFO_mutex,
+ &m_info->mutex, MY_MUTEX_INIT_FAST);
+
+ m_info->open_list.data= (void*) m_info;
+ mysql_mutex_lock(&THR_LOCK_open);
+ myrg_open_list= list_add(myrg_open_list, &m_info->open_list);
+ mysql_mutex_unlock(&THR_LOCK_open);
+
+ DBUG_RETURN(m_info);
+
+ /* purecov: begin inspected */
+ err:
+ save_errno= my_errno;
+ switch (errpos) {
+ case 3:
+ my_free(m_info);
+ /* Fall through */
+ case 2:
+ end_io_cache(&file_cache);
+ /* Fall through */
+ case 1:
+ (void) mysql_file_close(fd, MYF(0));
+ }
+ my_errno= save_errno;
+ DBUG_RETURN (NULL);
+ /* purecov: end */
+}
+
+
+/**
+ @brief Attach children to a MyISAM MERGE parent table.
+
+ @detail Call a callback function for each child table.
+ The callback returns the MyISAM table handle of the child table.
+ Check table definition match.
+
+ @param[in] m_info MERGE parent table structure
+ @param[in] handle_locking if contains HA_OPEN_FOR_REPAIR, warn about
+ incompatible child tables, but continue
+ @param[in] callback function to call for each child table
+ @param[in] callback_param data pointer to give to the callback
+ @param[in] need_compat_check pointer to ha_myisammrg::need_compat_check
+ (we need this one to decide if previously
+ allocated buffers can be reused).
+
+ @return status
+ @retval 0 OK
+ @retval != 0 Error
+
+ @note: Currently there is some code duplication between myrg_open()
+ and myrg_parent_open() + myrg_attach_children(). Please duplicate
+ changes in these functions or make common sub-functions.
+*/
+
+int myrg_attach_children(MYRG_INFO *m_info, int handle_locking,
+ MI_INFO *(*callback)(void*),
+ void *callback_param, my_bool *need_compat_check)
+{
+ ulonglong file_offset;
+ MI_INFO *myisam;
+ int errpos;
+ int save_errno;
+ uint idx;
+ uint child_nr;
+ uint UNINIT_VAR(key_parts);
+ uint min_keys;
+ my_bool bad_children= FALSE;
+ my_bool first_child= TRUE;
+ DBUG_ENTER("myrg_attach_children");
+ DBUG_PRINT("myrg", ("handle_locking: %d", handle_locking));
+
+ /*
+ This function can be called while another thread is trying to abort
+ locks of this MERGE table. If the processor reorders instructions or
+ write to memory, 'children_attached' could be set before
+ 'open_tables' has all the pointers to the children. Use of a mutex
+ here and in ha_myisammrg::store_lock() forces consistent data.
+ */
+ mysql_mutex_lock(&m_info->mutex);
+ errpos= 0;
+ file_offset= 0;
+ min_keys= 0;
+ for (child_nr= 0; child_nr < m_info->tables; child_nr++)
+ {
+ if (! (myisam= (*callback)(callback_param)))
+ {
+ if (handle_locking & HA_OPEN_FOR_REPAIR)
+ {
+ /* An appropriate error should've been already pushed by callback. */
+ bad_children= TRUE;
+ continue;
+ }
+ goto bad_children;
+ }
+
+ DBUG_PRINT("myrg", ("child_nr: %u table: '%s'",
+ child_nr, myisam->filename));
+
+ /* Special handling when the first child is attached. */
+ if (first_child)
+ {
+ first_child= FALSE;
+ m_info->reclength= myisam->s->base.reclength;
+ min_keys= myisam->s->base.keys;
+ key_parts= myisam->s->base.base_key_parts;
+ if (*need_compat_check && m_info->rec_per_key_part)
+ {
+ my_free(m_info->rec_per_key_part);
+ m_info->rec_per_key_part= NULL;
+ }
+ if (!m_info->rec_per_key_part || m_info->key_parts != key_parts)
+ {
+ m_info->key_parts= key_parts;
+ /* The +1 is because by my_realloc() don't allow zero length */
+ if (!(m_info->rec_per_key_part= (ulong*)
+ my_realloc(rg_key_memory_MYRG_INFO, m_info->rec_per_key_part,
+ key_parts * sizeof(long) +1,
+ MYF(MY_WME | MY_ALLOW_ZERO_PTR | MY_FREE_ON_ERROR))))
+ goto err; /* purecov: inspected */
+ errpos= 1;
+ }
+ bzero((char*) m_info->rec_per_key_part, key_parts * sizeof(long));
+ }
+
+ /* Add MyISAM table info. */
+ m_info->open_tables[child_nr].table= myisam;
+ m_info->open_tables[child_nr].file_offset= (my_off_t) file_offset;
+ file_offset+= myisam->state->data_file_length;
+ /* Mark as MERGE table */
+ myisam->open_flag|= HA_OPEN_MERGE_TABLE;
+
+ /* Check table definition match. */
+ if (m_info->reclength != myisam->s->base.reclength ||
+ key_parts != myisam->s->base.base_key_parts)
+ {
+ DBUG_PRINT("error", ("definition mismatch table: '%s' repair: %d",
+ myisam->filename,
+ (handle_locking & HA_OPEN_FOR_REPAIR)));
+ if (handle_locking & HA_OPEN_FOR_REPAIR)
+ {
+ myrg_print_wrong_table(myisam->filename);
+ bad_children= TRUE;
+ continue;
+ }
+ goto bad_children;
+ }
+
+ m_info->options|= myisam->s->options;
+ m_info->records+= myisam->state->records;
+ m_info->del+= myisam->state->del;
+ m_info->data_file_length+= myisam->state->data_file_length;
+ if (min_keys > myisam->s->base.keys)
+ min_keys= myisam->s->base.keys; /* purecov: inspected */
+ for (idx= 0; idx < key_parts; idx++)
+ m_info->rec_per_key_part[idx]+= (myisam->s->state.rec_per_key_part[idx] /
+ m_info->tables);
+ }
+
+ if (bad_children)
+ goto bad_children;
+
+ if (sizeof(my_off_t) == 4 && file_offset > (ulonglong) (ulong) ~0L)
+ {
+ my_errno= HA_ERR_RECORD_FILE_FULL;
+ goto err;
+ }
+ /* Don't mark table readonly, for ALTER TABLE ... UNION=(...) to work */
+ m_info->options&= ~(HA_OPTION_COMPRESS_RECORD | HA_OPTION_READ_ONLY_DATA);
+ m_info->keys= min_keys;
+ m_info->last_used_table= m_info->open_tables;
+ m_info->children_attached= TRUE;
+ mysql_mutex_unlock(&m_info->mutex);
+ DBUG_RETURN(0);
+
+bad_children:
+ my_errno= HA_ERR_WRONG_MRG_TABLE_DEF;
+err:
+ save_errno= my_errno;
+ switch (errpos) {
+ case 1:
+ my_free(m_info->rec_per_key_part);
+ m_info->rec_per_key_part= NULL;
+ }
+ mysql_mutex_unlock(&m_info->mutex);
+ my_errno= save_errno;
+ DBUG_RETURN(1);
+}
+
+
+/**
+ @brief Detach children from a MyISAM MERGE parent table.
+
+ @param[in] m_info MERGE parent table structure
+
+ @note Detach must not touch the children in any way.
+ They may have been closed at ths point already.
+ All references to the children should be removed.
+
+ @return status
+ @retval 0 OK
+*/
+
+int myrg_detach_children(MYRG_INFO *m_info)
+{
+ DBUG_ENTER("myrg_detach_children");
+ /* For symmetry with myrg_attach_children() we use the mutex here. */
+ mysql_mutex_lock(&m_info->mutex);
+ if (m_info->tables)
+ {
+ /* Do not attach/detach an empty child list. */
+ m_info->children_attached= FALSE;
+ bzero((char*) m_info->open_tables, m_info->tables * sizeof(MYRG_TABLE));
+ }
+ m_info->records= 0;
+ m_info->del= 0;
+ m_info->data_file_length= 0;
+ m_info->options= 0;
+ mysql_mutex_unlock(&m_info->mutex);
+ DBUG_RETURN(0);
+}
+
diff --git a/storage/myisammrg/myrg_panic.c b/storage/myisammrg/myrg_panic.c
new file mode 100644
index 00000000..3721b403
--- /dev/null
+++ b/storage/myisammrg/myrg_panic.c
@@ -0,0 +1,46 @@
+/* Copyright (c) 2000, 2001, 2005, 2006 MySQL AB
+ Use is subject to license terms
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
+
+#include "myrg_def.h"
+
+ /* if flag == HA_PANIC_CLOSE then all misam files are closed */
+ /* if flag == HA_PANIC_WRITE then all misam files are unlocked and
+ all changed data in single user misam is written to file */
+ /* if flag == HA_PANIC_READ then all misam files that was locked when
+ mi_panic(HA_PANIC_WRITE) was done is locked. A mi_readinfo() is
+ done for all single user files to get changes in database */
+
+
+int myrg_panic(enum ha_panic_function flag)
+{
+ int error=0;
+ LIST *list_element,*next_open;
+ MYRG_INFO *info;
+ DBUG_ENTER("myrg_panic");
+
+ for (list_element=myrg_open_list ; list_element ; list_element=next_open)
+ {
+ next_open=list_element->next; /* Save if close */
+ info=(MYRG_INFO*) list_element->data;
+ if (flag == HA_PANIC_CLOSE && myrg_close(info))
+ error=my_errno;
+ }
+ if (myrg_open_list && flag != HA_PANIC_CLOSE)
+ DBUG_RETURN(mi_panic(flag));
+ if (error)
+ my_errno=error;
+ DBUG_RETURN(error);
+}
diff --git a/storage/myisammrg/myrg_queue.c b/storage/myisammrg/myrg_queue.c
new file mode 100644
index 00000000..08d02bd5
--- /dev/null
+++ b/storage/myisammrg/myrg_queue.c
@@ -0,0 +1,90 @@
+/* Copyright (c) 2000, 2010, 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 Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */
+
+#include "myrg_def.h"
+
+static int queue_key_cmp(void *keyseg, uchar *a, uchar *b)
+{
+ MYRG_TABLE *ma= (MYRG_TABLE *)a;
+ MYRG_TABLE *mb= (MYRG_TABLE *)b;
+ MI_INFO *aa= ma->table;
+ MI_INFO *bb= mb->table;
+ uint not_used[2];
+ int ret= ha_key_cmp((HA_KEYSEG *)keyseg, aa->lastkey, bb->lastkey,
+ USE_WHOLE_KEY, SEARCH_FIND, not_used);
+ if (ret < 0)
+ return -1;
+ if (ret > 0)
+ return 1;
+
+ /*
+ If index tuples have the same values, let the record with least rowid
+ value be "smaller", so index scans return records ordered by (keytuple,
+ rowid). This is used by index_merge access method, grep for ROR in
+ sql/opt_range.cc for details.
+ */
+ return (ma->file_offset < mb->file_offset)? -1 : (ma->file_offset >
+ mb->file_offset) ? 1 : 0;
+} /* queue_key_cmp */
+
+
+int _myrg_init_queue(MYRG_INFO *info,int inx,enum ha_rkey_function search_flag)
+{
+ int error=0;
+ QUEUE *q= &(info->by_key);
+
+ if (inx < (int) info->keys)
+ {
+ if (!is_queue_inited(q))
+ {
+ if (init_queue(q,info->tables, 0,
+ (myisam_readnext_vec[search_flag] == SEARCH_SMALLER),
+ queue_key_cmp,
+ info->open_tables->table->s->keyinfo[inx].seg, 0, 0))
+ error=my_errno;
+ }
+ else
+ {
+ if (reinit_queue(q,info->tables, 0,
+ (myisam_readnext_vec[search_flag] == SEARCH_SMALLER),
+ queue_key_cmp,
+ info->open_tables->table->s->keyinfo[inx].seg, 0, 0))
+ error=my_errno;
+ }
+ }
+ else
+ {
+ /*
+ inx may be bigger than info->keys if there are no underlying tables
+ defined. In this case we should return empty result. As we check for
+ underlying tables conformance when we open a table, we may not enter
+ this branch with underlying table that has less keys than merge table
+ have.
+ */
+ DBUG_ASSERT(!info->tables);
+ error= my_errno= HA_ERR_END_OF_FILE;
+ }
+ return error;
+}
+
+int _myrg_mi_read_record(MI_INFO *info, uchar *buf)
+{
+ if (!(*info->read_record)(info,info->lastpos,buf))
+ {
+ info->update|= HA_STATE_AKTIV; /* Record is read */
+ return 0;
+ }
+ return my_errno;
+}
diff --git a/storage/myisammrg/myrg_range.c b/storage/myisammrg/myrg_range.c
new file mode 100644
index 00000000..da5e2c38
--- /dev/null
+++ b/storage/myisammrg/myrg_range.c
@@ -0,0 +1,43 @@
+/* Copyright (c) 2002, 2004-2006 MySQL AB
+ Use is subject to license terms
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
+
+#include "myrg_def.h"
+
+ha_rows myrg_records_in_range(MYRG_INFO *info, int inx,
+ const key_range *min_key,
+ const key_range *max_key,
+ page_range *pages)
+{
+ ha_rows records=0, res;
+ MYRG_TABLE *table;
+ page_range ignore_pages;
+
+ /* Don't calculate pages of more than one active partition */
+ if (info->open_tables +1 != info->end_table)
+ pages= &ignore_pages;
+
+ for (table=info->open_tables ; table != info->end_table ; table++)
+ {
+ res= mi_records_in_range(table->table, inx, min_key, max_key, pages);
+ if (res == HA_POS_ERROR)
+ return HA_POS_ERROR;
+ if (records > HA_POS_ERROR - res)
+ return HA_POS_ERROR-1;
+ records+=res;
+ }
+ return records;
+}
+
diff --git a/storage/myisammrg/myrg_records.c b/storage/myisammrg/myrg_records.c
new file mode 100644
index 00000000..4aa33a08
--- /dev/null
+++ b/storage/myisammrg/myrg_records.c
@@ -0,0 +1,28 @@
+/* Copyright (C) 2008 MySQL AB
+ Use is subject to license terms
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
+
+#include "myrg_def.h"
+
+ha_rows myrg_records(MYRG_INFO *info)
+{
+ ha_rows records=0;
+ MYRG_TABLE *file;
+ DBUG_ENTER("myrg_records");
+
+ for (file=info->open_tables ; file != info->end_table ; file++)
+ records+= file->table->s->state.state.records;
+ DBUG_RETURN(records);
+}
diff --git a/storage/myisammrg/myrg_rfirst.c b/storage/myisammrg/myrg_rfirst.c
new file mode 100644
index 00000000..c8400c0a
--- /dev/null
+++ b/storage/myisammrg/myrg_rfirst.c
@@ -0,0 +1,49 @@
+/* Copyright (c) 2000, 2001, 2003, 2005-2007 MySQL AB
+ Use is subject to license terms
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
+
+#include "myrg_def.h"
+
+ /* Read first row according to specific key */
+
+int myrg_rfirst(MYRG_INFO *info, uchar *buf, int inx)
+{
+ MYRG_TABLE *table;
+ MI_INFO *mi;
+ int err;
+
+ if (_myrg_init_queue(info,inx,HA_READ_KEY_OR_NEXT))
+ return my_errno;
+
+ for (table=info->open_tables ; table != info->end_table ; table++)
+ {
+ if ((err=mi_rfirst(table->table,NULL,inx)))
+ {
+ if (err == HA_ERR_END_OF_FILE)
+ continue;
+ return err;
+ }
+ /* adding to queue */
+ queue_insert(&(info->by_key),(uchar *)table);
+ }
+ /* We have done a read in all tables */
+ info->last_used_table=table;
+
+ if (!info->by_key.elements)
+ return HA_ERR_END_OF_FILE;
+
+ mi=(info->current_table=(MYRG_TABLE *)queue_top(&(info->by_key)))->table;
+ return _myrg_mi_read_record(mi,buf);
+}
diff --git a/storage/myisammrg/myrg_rkey.c b/storage/myisammrg/myrg_rkey.c
new file mode 100644
index 00000000..84e8297f
--- /dev/null
+++ b/storage/myisammrg/myrg_rkey.c
@@ -0,0 +1,95 @@
+/* Copyright (c) 2000-2003, 2005-2008 MySQL AB, 2009 Sun Microsystems, Inc.
+ Use is subject to license terms.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */
+
+/* Read record based on a key */
+
+/*
+ * HA_READ_KEY_EXACT => SEARCH_BIGGER
+ * HA_READ_KEY_OR_NEXT => SEARCH_BIGGER
+ * HA_READ_AFTER_KEY => SEARCH_BIGGER
+ * HA_READ_PREFIX => SEARCH_BIGGER
+ * HA_READ_KEY_OR_PREV => SEARCH_SMALLER
+ * HA_READ_BEFORE_KEY => SEARCH_SMALLER
+ * HA_READ_PREFIX_LAST => SEARCH_SMALLER
+ */
+
+
+#include "myrg_def.h"
+
+/* todo: we could store some additional info to speedup lookups:
+ column (key, keyseg) can be constant per table
+ it can also be increasing (table1.val > table2.val > ...),
+ or decreasing, <=, >=, etc.
+ SerG
+*/
+
+int myrg_rkey(MYRG_INFO *info,uchar *buf,int inx, const uchar *key,
+ key_part_map keypart_map, enum ha_rkey_function search_flag)
+{
+ uchar *UNINIT_VAR(key_buff);
+ uint UNINIT_VAR(pack_key_length);
+ uint16 UNINIT_VAR(last_used_keyseg);
+ MYRG_TABLE *table;
+ MI_INFO *mi;
+ int err;
+ DBUG_ENTER("myrg_rkey");
+
+ if (_myrg_init_queue(info,inx,search_flag))
+ DBUG_RETURN(my_errno);
+
+ for (table=info->open_tables ; table != info->end_table ; table++)
+ {
+ mi=table->table;
+
+ if (table == info->open_tables)
+ {
+ err=mi_rkey(mi, 0, inx, key, keypart_map, search_flag);
+ /* Get the saved packed key and packed key length. */
+ key_buff=(uchar*) mi->lastkey+mi->s->base.max_key_length;
+ pack_key_length=mi->pack_key_length;
+ last_used_keyseg= mi->last_used_keyseg;
+ }
+ else
+ {
+ mi->once_flags|= USE_PACKED_KEYS;
+ mi->last_used_keyseg= last_used_keyseg;
+ err=mi_rkey(mi, 0, inx, key_buff, pack_key_length, search_flag);
+ }
+ info->last_used_table=table+1;
+
+ if (err)
+ {
+ if (err == HA_ERR_KEY_NOT_FOUND)
+ continue;
+ DBUG_PRINT("exit", ("err: %d", err));
+ DBUG_RETURN(err);
+ }
+ /* adding to queue */
+ queue_insert(&(info->by_key),(uchar *)table);
+
+ }
+
+ DBUG_PRINT("info", ("tables with matches: %u", info->by_key.elements));
+ if (!info->by_key.elements)
+ DBUG_RETURN(HA_ERR_KEY_NOT_FOUND);
+
+ mi=(info->current_table=(MYRG_TABLE *)queue_top(&(info->by_key)))->table;
+ mi->once_flags|= RRND_PRESERVE_LASTINX;
+ DBUG_PRINT("info", ("using table no: %d",
+ (int) (info->current_table - info->open_tables + 1)));
+ DBUG_DUMP("result key", (uchar*) mi->lastkey, mi->lastkey_length);
+ DBUG_RETURN(_myrg_mi_read_record(mi,buf));
+}
diff --git a/storage/myisammrg/myrg_rlast.c b/storage/myisammrg/myrg_rlast.c
new file mode 100644
index 00000000..d9402568
--- /dev/null
+++ b/storage/myisammrg/myrg_rlast.c
@@ -0,0 +1,50 @@
+/* Copyright (c) 2000, 2001, 2003, 2005-2007 MySQL AB
+ Use is subject to license terms
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
+
+#include "myrg_def.h"
+
+ /* Read last row with the same key as the previous read. */
+
+int myrg_rlast(MYRG_INFO *info, uchar *buf, int inx)
+{
+ MYRG_TABLE *table;
+ MI_INFO *mi;
+ int err;
+
+ if (_myrg_init_queue(info,inx, HA_READ_KEY_OR_PREV))
+ return my_errno;
+
+ for (table=info->open_tables ; table < info->end_table ; table++)
+ {
+ if ((err=mi_rlast(table->table,NULL,inx)))
+ {
+ if (err == HA_ERR_END_OF_FILE)
+ continue;
+ return err;
+ }
+ /* adding to queue */
+ queue_insert(&(info->by_key),(uchar *)table);
+ }
+ /* We have done a read in all tables */
+ info->last_used_table=table;
+
+ if (!info->by_key.elements)
+ return HA_ERR_END_OF_FILE;
+
+ mi=(info->current_table=(MYRG_TABLE *)queue_top(&(info->by_key)))->table;
+ return _myrg_mi_read_record(mi,buf);
+}
+
diff --git a/storage/myisammrg/myrg_rnext.c b/storage/myisammrg/myrg_rnext.c
new file mode 100644
index 00000000..8b35e40f
--- /dev/null
+++ b/storage/myisammrg/myrg_rnext.c
@@ -0,0 +1,53 @@
+/* Copyright (c) 2000-2003, 2005-2007 MySQL AB
+ Use is subject to license terms
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
+
+#include "myrg_def.h"
+
+ /*
+ Read next row with the same key as previous read
+ */
+
+int myrg_rnext(MYRG_INFO *info, uchar *buf, int inx)
+{
+ int err;
+ MI_INFO *mi;
+
+ if (!info->current_table)
+ return (HA_ERR_KEY_NOT_FOUND);
+
+ /* at first, do rnext for the table found before */
+ if ((err=mi_rnext(info->current_table->table,NULL,inx)))
+ {
+ if (err == HA_ERR_END_OF_FILE)
+ {
+ queue_remove_top(&(info->by_key));
+ if (!info->by_key.elements)
+ return HA_ERR_END_OF_FILE;
+ }
+ else
+ return err;
+ }
+ else
+ {
+ /* Found here, adding to queue */
+ queue_top(&(info->by_key))=(uchar *)(info->current_table);
+ queue_replace_top(&(info->by_key));
+ }
+
+ /* now, mymerge's read_next is as simple as one queue_top */
+ mi=(info->current_table=(MYRG_TABLE *)queue_top(&(info->by_key)))->table;
+ return _myrg_mi_read_record(mi,buf);
+}
diff --git a/storage/myisammrg/myrg_rnext_same.c b/storage/myisammrg/myrg_rnext_same.c
new file mode 100644
index 00000000..f9a114a7
--- /dev/null
+++ b/storage/myisammrg/myrg_rnext_same.c
@@ -0,0 +1,51 @@
+/* Copyright (c) 2002, 2004-2007 MySQL AB
+ Use is subject to license terms
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
+
+#include "myrg_def.h"
+
+
+int myrg_rnext_same(MYRG_INFO *info, uchar *buf)
+{
+ int err;
+ MI_INFO *mi;
+
+ if (!info->current_table)
+ return (HA_ERR_KEY_NOT_FOUND);
+
+ /* at first, do rnext for the table found before */
+ if ((err=mi_rnext_same(info->current_table->table,NULL)))
+ {
+ if (err == HA_ERR_END_OF_FILE)
+ {
+ queue_remove_top(&(info->by_key));
+ if (!info->by_key.elements)
+ return HA_ERR_END_OF_FILE;
+ }
+ else
+ return err;
+ }
+ else
+ {
+ /* Found here, adding to queue */
+ queue_top(&(info->by_key))=(uchar *)(info->current_table);
+ queue_replace_top(&(info->by_key));
+ }
+
+ /* now, mymerge's read_next is as simple as one queue_top */
+ mi=(info->current_table=(MYRG_TABLE *)queue_top(&(info->by_key)))->table;
+ return _myrg_mi_read_record(mi,buf);
+}
+
diff --git a/storage/myisammrg/myrg_rprev.c b/storage/myisammrg/myrg_rprev.c
new file mode 100644
index 00000000..72765f5d
--- /dev/null
+++ b/storage/myisammrg/myrg_rprev.c
@@ -0,0 +1,53 @@
+/* Copyright (c) 2000-2003, 2005-2007 MySQL AB
+ Use is subject to license terms
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
+
+#include "myrg_def.h"
+
+ /*
+ Read previous row with the same key as previous read
+ */
+
+int myrg_rprev(MYRG_INFO *info, uchar *buf, int inx)
+{
+ int err;
+ MI_INFO *mi;
+
+ if (!info->current_table)
+ return (HA_ERR_KEY_NOT_FOUND);
+
+ /* at first, do rprev for the table found before */
+ if ((err=mi_rprev(info->current_table->table,NULL,inx)))
+ {
+ if (err == HA_ERR_END_OF_FILE)
+ {
+ queue_remove_top(&(info->by_key));
+ if (!info->by_key.elements)
+ return HA_ERR_END_OF_FILE;
+ }
+ else
+ return err;
+ }
+ else
+ {
+ /* Found here, adding to queue */
+ queue_top(&(info->by_key))=(uchar *)(info->current_table);
+ queue_replace_top(&(info->by_key));
+ }
+
+ /* now, mymerge's read_prev is as simple as one queue_top */
+ mi=(info->current_table=(MYRG_TABLE *)queue_top(&(info->by_key)))->table;
+ return _myrg_mi_read_record(mi,buf);
+}
diff --git a/storage/myisammrg/myrg_rrnd.c b/storage/myisammrg/myrg_rrnd.c
new file mode 100644
index 00000000..a97f6d30
--- /dev/null
+++ b/storage/myisammrg/myrg_rrnd.c
@@ -0,0 +1,117 @@
+/* Copyright (c) 2000-2002, 2005-2007 MySQL AB
+ Use is subject to license terms
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
+
+/*
+ Read a record with random-access. The position to the record must
+ get by myrg_info(). The next record can be read with pos= -1 */
+
+
+#include "myrg_def.h"
+
+static MYRG_TABLE *find_table(MYRG_TABLE *start,MYRG_TABLE *end,ulonglong pos);
+
+/*
+ If filepos == HA_OFFSET_ERROR, read next
+ Returns same as mi_rrnd:
+ 0 = Ok.
+ HA_ERR_RECORD_DELETED = Record is deleted.
+ HA_ERR_END_OF_FILE = EOF.
+*/
+
+int myrg_rrnd(MYRG_INFO *info,uchar *buf,ulonglong filepos)
+{
+ int error;
+ MI_INFO *isam_info;
+ DBUG_ENTER("myrg_rrnd");
+ DBUG_PRINT("info",("offset: %lu", (ulong) filepos));
+
+ if (filepos == HA_OFFSET_ERROR)
+ {
+ if (!info->current_table)
+ {
+ if (info->open_tables == info->end_table)
+ { /* No tables */
+ DBUG_RETURN(my_errno=HA_ERR_END_OF_FILE);
+ }
+ isam_info=(info->current_table=info->open_tables)->table;
+ if (info->cache_in_use)
+ mi_extra(isam_info,HA_EXTRA_CACHE,(uchar*) &info->cache_size);
+ filepos=isam_info->s->pack.header_length;
+ isam_info->lastinx= (uint) -1; /* Can't forward or backward */
+ }
+ else
+ {
+ isam_info=info->current_table->table;
+ filepos= isam_info->nextpos;
+ }
+
+ for (;;)
+ {
+ isam_info->update&= HA_STATE_CHANGED;
+ if ((error=(*isam_info->s->read_rnd)(isam_info,(uchar*) buf,
+ (my_off_t) filepos,1)) !=
+ HA_ERR_END_OF_FILE)
+ DBUG_RETURN(error);
+ if (info->cache_in_use)
+ mi_extra(info->current_table->table, HA_EXTRA_NO_CACHE,
+ (uchar*) &info->cache_size);
+ if (info->current_table+1 == info->end_table)
+ DBUG_RETURN(HA_ERR_END_OF_FILE);
+ info->current_table++;
+ info->last_used_table=info->current_table;
+ if (info->cache_in_use)
+ mi_extra(info->current_table->table, HA_EXTRA_CACHE,
+ (uchar*) &info->cache_size);
+ info->current_table->file_offset=
+ info->current_table[-1].file_offset+
+ info->current_table[-1].table->state->data_file_length;
+
+ isam_info=info->current_table->table;
+ filepos=isam_info->s->pack.header_length;
+ isam_info->lastinx= (uint) -1;
+ }
+ }
+ info->current_table=find_table(info->open_tables,
+ info->end_table-1,filepos);
+ isam_info=info->current_table->table;
+ isam_info->update&= HA_STATE_CHANGED;
+ DBUG_RETURN((*isam_info->s->read_rnd)
+ (isam_info, (uchar*) buf,
+ (my_off_t) (filepos - info->current_table->file_offset),
+ 0));
+}
+
+
+ /* Find which table to use according to file-pos */
+
+static MYRG_TABLE *find_table(MYRG_TABLE *start, MYRG_TABLE *end,
+ ulonglong pos)
+{
+ MYRG_TABLE *mid;
+ DBUG_ENTER("find_table");
+
+ while (start != end)
+ {
+ mid=start+((uint) (end-start)+1)/2;
+ if (mid->file_offset > pos)
+ end=mid-1;
+ else
+ start=mid;
+ }
+ DBUG_PRINT("info",("offset: %lu, table: %s",
+ (ulong) pos, start->table->filename));
+ DBUG_RETURN(start);
+}
diff --git a/storage/myisammrg/myrg_rsame.c b/storage/myisammrg/myrg_rsame.c
new file mode 100644
index 00000000..f76fe79f
--- /dev/null
+++ b/storage/myisammrg/myrg_rsame.c
@@ -0,0 +1,28 @@
+/* Copyright (c) 2000-2002, 2005-2007 MySQL AB
+ Use is subject to license terms
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
+
+#include "myrg_def.h"
+
+int myrg_rsame(MYRG_INFO *info,uchar *record,int inx)
+{
+ if (inx) /* not yet used, should be 0 */
+ return (my_errno=HA_ERR_WRONG_INDEX);
+
+ if (!info->current_table)
+ return (my_errno=HA_ERR_NO_ACTIVE_RECORD);
+
+ return mi_rsame(info->current_table->table,record,inx);
+}
diff --git a/storage/myisammrg/myrg_static.c b/storage/myisammrg/myrg_static.c
new file mode 100644
index 00000000..36ec25cb
--- /dev/null
+++ b/storage/myisammrg/myrg_static.c
@@ -0,0 +1,71 @@
+/* Copyright (c) 2000, 2001, 2005, 2006 MySQL AB, 2009 Sun Microsystems, Inc.
+ Use is subject to license terms.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */
+
+/*
+ Static variables for pisam library. All definied here for easy making of
+ a shared library
+*/
+
+#ifndef stdin
+#include "myrg_def.h"
+#endif
+
+LIST *myrg_open_list=0;
+static const char *merge_insert_methods[] =
+{ "FIRST", "LAST", NullS };
+TYPELIB merge_insert_method= { array_elements(merge_insert_methods)-1,"",
+ merge_insert_methods, 0};
+
+PSI_memory_key rg_key_memory_MYRG_INFO;
+PSI_memory_key rg_key_memory_children;
+
+#ifdef HAVE_PSI_INTERFACE
+PSI_mutex_key rg_key_mutex_MYRG_INFO_mutex;
+
+static PSI_mutex_info all_myisammrg_mutexes[]=
+{
+ { &rg_key_mutex_MYRG_INFO_mutex, "MYRG_INFO::mutex", 0}
+};
+
+PSI_file_key rg_key_file_MRG;
+
+static PSI_file_info all_myisammrg_files[]=
+{
+ { &rg_key_file_MRG, "MRG", 0}
+};
+
+static PSI_memory_info all_myisammrg_memory[]=
+{
+ { &rg_key_memory_MYRG_INFO, "MYRG_INFO", 0},
+ { &rg_key_memory_children, "children", 0}
+};
+
+void init_myisammrg_psi_keys()
+{
+ const char* category= "myisammrg";
+ int count;
+
+ count= array_elements(all_myisammrg_mutexes);
+ mysql_mutex_register(category, all_myisammrg_mutexes, count);
+
+ count= array_elements(all_myisammrg_files);
+ mysql_file_register(category, all_myisammrg_files, count);
+
+ count= array_elements(all_myisammrg_memory);
+ mysql_memory_register(category, all_myisammrg_memory, count);
+}
+#endif /* HAVE_PSI_INTERFACE */
+
diff --git a/storage/myisammrg/myrg_update.c b/storage/myisammrg/myrg_update.c
new file mode 100644
index 00000000..1620b712
--- /dev/null
+++ b/storage/myisammrg/myrg_update.c
@@ -0,0 +1,28 @@
+/* Copyright (c) 2000-2002, 2005-2007 MySQL AB
+ Use is subject to license terms
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
+
+/* Update last read record */
+
+#include "myrg_def.h"
+
+int myrg_update(register MYRG_INFO *info,const uchar *oldrec,
+ const uchar *newrec)
+{
+ if (!info->current_table)
+ return (my_errno=HA_ERR_NO_ACTIVE_RECORD);
+
+ return mi_update(info->current_table->table,oldrec,newrec);
+}
diff --git a/storage/myisammrg/myrg_write.c b/storage/myisammrg/myrg_write.c
new file mode 100644
index 00000000..e511d60d
--- /dev/null
+++ b/storage/myisammrg/myrg_write.c
@@ -0,0 +1,30 @@
+/* Copyright (c) 2001, 2002, 2004-2007 MySQL AB
+ Use is subject to license terms
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
+
+/* Write a row to a MyISAM MERGE table */
+
+#include "myrg_def.h"
+
+int myrg_write(register MYRG_INFO *info, const uchar *rec)
+{
+ /* [phi] MERGE_WRITE_DISABLED is handled by the else case */
+ if (info->merge_insert_method == MERGE_INSERT_TO_FIRST)
+ return mi_write((info->current_table=info->open_tables)->table,rec);
+ else if (info->merge_insert_method == MERGE_INSERT_TO_LAST)
+ return mi_write((info->current_table=info->end_table-1)->table,rec);
+ else /* unsupported insertion method */
+ return (my_errno= HA_ERR_WRONG_COMMAND);
+}
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 00000000..a978ade4
--- /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 00000000..b2ec2129
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/alter_table.rdiff
@@ -0,0 +1,151 @@
+--- alter_table.result 2013-01-22 22:05:05.246633000 +0400
++++ alter_table.reject 2013-01-23 02:50:10.652118538 +0400
+@@ -8,7 +8,7 @@
+ `a` int(11) DEFAULT NULL,
+ `c` char(8) DEFAULT NULL,
+ `b` int(11) DEFAULT NULL
+-) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1
++) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(`mrg`.`t1`)
+ ALTER TABLE t1 ALTER COLUMN a SET DEFAULT '0';
+ SHOW CREATE TABLE t1;
+ Table Create Table
+@@ -16,7 +16,7 @@
+ `a` int(11) DEFAULT '0',
+ `c` char(8) DEFAULT NULL,
+ `b` int(11) DEFAULT NULL
+-) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1
++) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(`mrg`.`t1`)
+ ALTER TABLE t1 ALTER a DROP DEFAULT;
+ SHOW CREATE TABLE t1;
+ Table Create Table
+@@ -24,7 +24,7 @@
+ `a` int(11),
+ `c` char(8) DEFAULT NULL,
+ `b` int(11) DEFAULT NULL
+-) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1
++) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(`mrg`.`t1`)
+ ALTER TABLE t1 CHANGE COLUMN b b1 <CHAR_COLUMN> FIRST;
+ SHOW CREATE TABLE t1;
+ Table Create Table
+@@ -32,7 +32,7 @@
+ `b1` char(8) DEFAULT NULL,
+ `a` int(11),
+ `c` char(8) DEFAULT NULL
+-) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1
++) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(`mrg`.`t1`)
+ ALTER TABLE t1 CHANGE b1 b <INT_COLUMN> AFTER c;
+ SHOW CREATE TABLE t1;
+ Table Create Table
+@@ -40,7 +40,7 @@
+ `a` int(11),
+ `c` char(8) DEFAULT NULL,
+ `b` int(11) DEFAULT NULL
+-) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1
++) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(`mrg`.`t1`)
+ ALTER TABLE t1 CHANGE b b <CHAR_COLUMN>;
+ SHOW CREATE TABLE t1;
+ Table Create Table
+@@ -48,7 +48,7 @@
+ `a` int(11),
+ `c` char(8) DEFAULT NULL,
+ `b` char(8) DEFAULT NULL
+-) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1
++) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(`mrg`.`t1`)
+ ALTER TABLE t1 MODIFY COLUMN b <INT_COLUMN>;
+ SHOW CREATE TABLE t1;
+ Table Create Table
+@@ -56,7 +56,7 @@
+ `a` int(11),
+ `c` char(8) DEFAULT NULL,
+ `b` int(11) DEFAULT NULL
+-) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1
++) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(`mrg`.`t1`)
+ ALTER TABLE t1 MODIFY COLUMN b <CHAR_COLUMN> FIRST;
+ SHOW CREATE TABLE t1;
+ Table Create Table
+@@ -64,7 +64,7 @@
+ `b` char(8) DEFAULT NULL,
+ `a` int(11),
+ `c` char(8) DEFAULT NULL
+-) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1
++) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(`mrg`.`t1`)
+ ALTER TABLE t1 MODIFY COLUMN b <INT_COLUMN> AFTER a;
+ SHOW CREATE TABLE t1;
+ Table Create Table
+@@ -72,14 +72,14 @@
+ `a` int(11),
+ `b` int(11) DEFAULT NULL,
+ `c` char(8) DEFAULT NULL
+-) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1
++) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(`mrg`.`t1`)
+ ALTER TABLE t1 DROP COLUMN b;
+ SHOW CREATE TABLE t1;
+ Table Create Table
+ t1 CREATE TABLE `t1` (
+ `a` int(11),
+ `c` char(8) DEFAULT NULL
+-) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1
++) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(`mrg`.`t1`)
+ ALTER TABLE t1 RENAME TO t2;
+ SHOW CREATE TABLE t1;
+ ERROR 42S02: Table 'test.t1' doesn't exist
+@@ -88,7 +88,7 @@
+ t2 CREATE TABLE `t2` (
+ `a` int(11),
+ `c` char(8) DEFAULT NULL
+-) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1
++) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(`mrg`.`t2`)
+ DROP TABLE t2;
+ CREATE TABLE t1 (a <INT_COLUMN>, b <INT_COLUMN>) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+ INSERT INTO t1 (a,b) VALUES (1,5),(2,2),(4,3);
+@@ -97,14 +97,14 @@
+ t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL,
+ `b` int(11) DEFAULT NULL
+-) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1
++) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(`mrg`.`t1`)
+ ALTER TABLE t1 ORDER BY b ASC, a DESC;
+ SHOW CREATE TABLE t1;
+ Table Create Table
+ t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL,
+ `b` int(11) DEFAULT NULL
+-) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1
++) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(`mrg`.`t1`)
+ SELECT a,b FROM t1;
+ a b
+ 2 2
+@@ -119,7 +119,7 @@
+ `a` int(11) DEFAULT NULL,
+ `b` char(8) COLLATE latin1_general_cs DEFAULT NULL,
+ `c` char(8) COLLATE latin1_general_cs DEFAULT NULL
+-) 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`)
+ ALTER TABLE t1 CONVERT TO CHARACTER SET utf8;
+ SHOW CREATE TABLE t1;
+ Table Create Table
+@@ -127,7 +127,7 @@
+ `a` int(11) DEFAULT NULL,
+ `b` char(8) DEFAULT NULL,
+ `c` char(8) DEFAULT NULL
+-) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=utf8
++) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=utf8 INSERT_METHOD=LAST UNION=(`mrg`.`t1`)
+ ALTER TABLE t1 DEFAULT CHARACTER SET = latin1 COLLATE latin1_general_ci;
+ SHOW CREATE TABLE t1;
+ Table Create Table
+@@ -135,7 +135,7 @@
+ `a` int(11) DEFAULT NULL,
+ `b` char(8) CHARACTER SET utf8 DEFAULT NULL,
+ `c` char(8) CHARACTER SET utf8 DEFAULT NULL
+-) 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`)
+ ALTER TABLE t1 FORCE;
+ SHOW CREATE TABLE t1;
+ Table Create Table
+@@ -143,5 +143,5 @@
+ `a` int(11) DEFAULT NULL,
+ `b` char(8) CHARACTER SET utf8 DEFAULT NULL,
+ `c` char(8) CHARACTER SET utf8 DEFAULT NULL
+-) 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`)
+ DROP TABLE t1;
diff --git a/storage/myisammrg/mysql-test/storage_engine/alter_table_online.rdiff b/storage/myisammrg/mysql-test/storage_engine/alter_table_online.rdiff
new file mode 100644
index 00000000..857854a6
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/alter_table_online.rdiff
@@ -0,0 +1,82 @@
+--- suite/storage_engine/alter_table_online.result 2014-11-12 05:27:00.000000000 +0400
++++ suite/storage_engine/alter_table_online.reject 2014-12-05 20:42:25.000000000 +0400
+@@ -2,8 +2,35 @@
+ CREATE TABLE t1 (a <INT_COLUMN>, b <INT_COLUMN>, c <CHAR_COLUMN>) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+ INSERT INTO t1 (a,b,c) VALUES (1,100,'a'),(2,200,'b'),(3,300,'c');
+ ALTER ONLINE TABLE t1 MODIFY b <INT_COLUMN> DEFAULT 5;
++ERROR 0A000: LOCK=NONE/SHARED is not supported for this operation. Try LOCK=EXCLUSIVE.
++# ERROR: Statement ended with errno 1845, errname ER_ALTER_OPERATION_NOT_SUPPORTED (expected to succeed)
++# ------------ UNEXPECTED RESULT ------------
++# The statement|command finished with ER_ALTER_OPERATION_NOT_SUPPORTED.
++# Functionality 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).
++# -------------------------------------------
+ ALTER ONLINE TABLE t1 CHANGE b new_name <INT_COLUMN>;
++ERROR 0A000: LOCK=NONE/SHARED is not supported for this operation. Try LOCK=EXCLUSIVE.
++# ERROR: Statement ended with errno 1845, errname ER_ALTER_OPERATION_NOT_SUPPORTED (expected to succeed)
++# ------------ UNEXPECTED RESULT ------------
++# The statement|command finished with ER_ALTER_OPERATION_NOT_SUPPORTED.
++# Functionality 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).
++# -------------------------------------------
+ ALTER ONLINE TABLE t1 COMMENT 'new comment';
++ERROR 0A000: LOCK=NONE/SHARED is not supported for this operation. Try LOCK=EXCLUSIVE.
++# ERROR: Statement ended with errno 1845, errname ER_ALTER_OPERATION_NOT_SUPPORTED (expected to succeed)
++# ------------ UNEXPECTED RESULT ------------
++# The statement|command finished with ER_ALTER_OPERATION_NOT_SUPPORTED.
++# Functionality 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).
++# -------------------------------------------
+ ALTER ONLINE TABLE t1 RENAME TO t2;
+ ERROR 0A000: LOCK=NONE/SHARED is not supported for this operation. Try LOCK=EXCLUSIVE.
+ DROP TABLE IF EXISTS t2;
+@@ -12,10 +39,6 @@
+ CREATE TEMPORARY 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');
+ ALTER ONLINE TABLE t1 MODIFY b <INT_COLUMN> DEFAULT 5;
+-Warnings:
+-Warning 1366 Incorrect integer value: 'a' for column 'b' at row 1
+-Warning 1366 Incorrect integer value: 'b' for column 'b' at row 2
+-Warning 1366 Incorrect integer value: 'c' for column 'b' at row 3
+ ALTER ONLINE TABLE t1 CHANGE b new_name <INT_COLUMN>;
+ ALTER ONLINE TABLE t1 COMMENT 'new comment';
+ ALTER ONLINE TABLE t1 RENAME TO t2;
+@@ -23,12 +46,30 @@
+ CREATE TABLE t1 (a <INT_COLUMN>, b <INT_COLUMN>, c <CHAR_COLUMN>) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+ INSERT INTO t1 (a,b,c) VALUES (1,100,'a'),(2,200,'b'),(3,300,'c');
+ ALTER ONLINE TABLE t1 DROP COLUMN b, ADD b <INT_COLUMN>;
++ERROR 0A000: LOCK=NONE/SHARED is not supported for this operation. Try LOCK=EXCLUSIVE.
++# ERROR: Statement ended with errno 1845, errname ER_ALTER_OPERATION_NOT_SUPPORTED (expected to succeed)
++# ------------ UNEXPECTED RESULT ------------
++# The statement|command finished with ER_ALTER_OPERATION_NOT_SUPPORTED.
++# Functionality 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).
++# -------------------------------------------
+ ALTER ONLINE TABLE t1 MODIFY b BIGINT <CUSTOM_COL_OPTIONS>;
+-ERROR 0A000: LOCK=NONE is not supported. Reason: Cannot change column type. Try LOCK=SHARED.
++ERROR 0A000: LOCK=NONE/SHARED is not supported for this operation. Try LOCK=EXCLUSIVE.
++# ERROR: Statement ended with errno 1845, errname ER_ALTER_OPERATION_NOT_SUPPORTED (expected results: ER_ALTER_OPERATION_NOT_SUPPORTED_REASON)
+ ALTER ONLINE TABLE t1 ENGINE=MEMORY;
+ ERROR 0A000: LOCK=NONE is not supported. Reason: COPY algorithm requires a lock. Try LOCK=SHARED.
+ DROP TABLE t1;
+ CREATE TABLE t1 (a <INT_COLUMN>, b <INT_COLUMN>, c <CHAR_COLUMN>) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+ ALTER ONLINE TABLE t1 ADD INDEX (b);
+-ALTER ONLINE TABLE t1 DROP INDEX b;
++ERROR 0A000: LOCK=NONE/SHARED is not supported for this operation. Try LOCK=EXCLUSIVE.
++# ERROR: Statement ended with errno 1845, errname ER_ALTER_OPERATION_NOT_SUPPORTED (expected to succeed)
++# ------------ UNEXPECTED RESULT ------------
++# The statement|command finished with ER_ALTER_OPERATION_NOT_SUPPORTED.
++# Adding an index or ALTER ONLINE 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 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 00000000..e5462f8c
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/alter_tablespace.rdiff
@@ -0,0 +1,34 @@
+--- alter_tablespace.result 2013-01-22 22:05:05.246633000 +0400
++++ alter_tablespace.reject 2013-01-23 02:50:11.288110543 +0400
+@@ -1,21 +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 a FROM t1;
+-a
+-1
+-2
+-ALTER TABLE t1 DISCARD TABLESPACE;
+-SELECT a FROM t1;
+-ERROR HY000: Tablespace has been discarded for table `t1`
+-ALTER TABLE t1 IMPORT TABLESPACE;
+-Warnings:
+-Warning 1810 IO Read error: (2, No such file or directory) Error opening './test/t1.cfg', will attempt to import without schema verification
+-SELECT a FROM t1;
+-a
+-1
+-2
++ERROR HY000: Storage engine MRG_MyISAM of the table `test`.`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/myisammrg/mysql-test/storage_engine/analyze_table.rdiff b/storage/myisammrg/mysql-test/storage_engine/analyze_table.rdiff
new file mode 100644
index 00000000..9854a986
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/analyze_table.rdiff
@@ -0,0 +1,34 @@
+--- analyze_table.result 2013-01-22 22:05:05.246633000 +0400
++++ analyze_table.reject 2013-01-23 02:50:11.912102699 +0400
+@@ -5,25 +5,25 @@
+ INSERT INTO t1 (a,b) VALUES (3,'c');
+ ANALYZE TABLE t1;
+ Table Op Msg_type Msg_text
+-test.t1 analyze status OK
++test.t1 analyze note The storage engine for the table doesn't support analyze
+ INSERT INTO t2 (a,b) VALUES (4,'d');
+ ANALYZE NO_WRITE_TO_BINLOG TABLE t2;
+ Table Op Msg_type Msg_text
+-test.t2 analyze status OK
++test.t2 analyze note The storage engine for the table doesn't support analyze
+ INSERT INTO t1 (a,b) VALUES (5,'e');
+ INSERT INTO t2 (a,b) VALUES (6,'f');
+ ANALYZE LOCAL TABLE t1, t2;
+ Table Op Msg_type Msg_text
+-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
+ DROP TABLE t1, t2;
+ CREATE TABLE t1 (a <INT_COLUMN>, <CUSTOM_INDEX>(a)) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+ INSERT INTO t1 (a) VALUES (1),(2),(4),(7);
+ ANALYZE TABLE t1;
+ Table Op Msg_type Msg_text
+-test.t1 analyze status OK
++test.t1 analyze note The storage engine for the table doesn't support analyze
+ INSERT INTO t1 (a) VALUES (8),(10),(11),(12);
+ ANALYZE TABLE t1;
+ Table Op Msg_type Msg_text
+-test.t1 analyze status OK
++test.t1 analyze note The storage engine for the table doesn't support analyze
+ DROP TABLE t1;
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 00000000..cc04b800
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/autoincrement.rdiff
@@ -0,0 +1,64 @@
+--- autoincrement.result 2013-01-22 22:05:05.246633000 +0400
++++ autoincrement.reject 2013-01-23 02:50:12.848090932 +0400
+@@ -6,7 +6,7 @@
+ `a` int(11) NOT NULL AUTO_INCREMENT,
+ `b` char(8) DEFAULT NULL,
+ KEY `a` (`a`)
+-) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1
++) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(`mrg`.`t1`)
+ INSERT INTO t1 (b) VALUES ('a'),('b');
+ SELECT a,b FROM t1 ORDER BY a;
+ a b
+@@ -52,14 +52,14 @@
+ SET sql_mode = '<INITIAL_SQL_MODE>';
+ SHOW TABLE STATUS FROM test LIKE 't1';
+ Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment Max_index_length Temporary
+-t1 <STORAGE_ENGINE> # # # # # # # # 6 # # # # # # # # N
++t1 <STORAGE_ENGINE> # # # # # # # # 0 # # # # # # # # N
+ INSERT INTO t1 (a,b) VALUES (6,'g'),(7,'h');
+ SELECT LAST_INSERT_ID();
+ LAST_INSERT_ID()
+ 5
+ SHOW TABLE STATUS FROM test LIKE 't1';
+ Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment Max_index_length Temporary
+-t1 # # # # # # # # # 8 # # # # # # # # N
++t1 # # # # # # # # # 0 # # # # # # # # N
+ INSERT INTO t1 (a,b) VALUES (NULL,'i'),(9,'j');
+ SELECT a,b FROM t1 ORDER BY a;
+ a b
+@@ -78,11 +78,11 @@
+ 8
+ SHOW TABLE STATUS FROM test LIKE 't1';
+ Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment Max_index_length Temporary
+-t1 # # # # # # # # # 10 # # # # # # # # N
++t1 # # # # # # # # # 0 # # # # # # # # N
+ INSERT INTO t1 (a,b) VALUES (20,'k');
+ SHOW TABLE STATUS FROM test LIKE 't1';
+ Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment Max_index_length Temporary
+-t1 # # # # # # # # # 21 # # # # # # # # N
++t1 # # # # # # # # # 0 # # # # # # # # N
+ INSERT INTO t1 (a,b) VALUES (NULL,'l');
+ SELECT a,b FROM t1 ORDER BY a;
+ a b
+@@ -103,7 +103,7 @@
+ 21
+ SHOW TABLE STATUS FROM test LIKE 't1';
+ Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment Max_index_length Temporary
+-t1 # # # # # # # # # 22 # # # # # # # # N
++t1 # # # # # # # # # 0 # # # # # # # # N
+ INSERT INTO t1 (a,b) VALUES (-5,'m');
+ SELECT a,b FROM t1 ORDER BY a;
+ a b
+@@ -125,9 +125,9 @@
+ INSERT INTO t1 (a,b) VALUES (NULL,'a'),(NULL,'b');
+ SELECT a,b FROM t1;
+ a b
+-100 a
+-101 b
++1 a
++2 b
+ SELECT LAST_INSERT_ID();
+ LAST_INSERT_ID()
+-100
++1
+ DROP TABLE t1;
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 00000000..612c8d38
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/cache_index.rdiff
@@ -0,0 +1,71 @@
+--- cache_index.result 2013-01-22 22:05:05.246633000 +0400
++++ cache_index.reject 2013-01-23 02:50:13.468083137 +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/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 00000000..f09aec97
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/checksum_table_live.rdiff
@@ -0,0 +1,13 @@
+--- checksum_table_live.result 2013-01-22 22:05:05.246633000 +0400
++++ checksum_table_live.reject 2013-01-23 02:50:14.440070917 +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/myisammrg/mysql-test/storage_engine/cleanup_engine.inc b/storage/myisammrg/mysql-test/storage_engine/cleanup_engine.inc
new file mode 100644
index 00000000..b8f84110
--- /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 00000000..c74460d4
--- /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 00000000..ad6352d3
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/create_table.rdiff
@@ -0,0 +1,57 @@
+--- create_table.result 2013-01-22 22:05:05.246633000 +0400
++++ create_table.reject 2013-01-23 02:50:19.544006752 +0400
+@@ -4,7 +4,7 @@
+ Table Create Table
+ t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+-) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1
++) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(`mrg`.`t1`)
+ CREATE TABLE IF NOT EXISTS t1 (a <INT_COLUMN>) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+ Warnings:
+ Note 1050 Table 't1' already exists
+@@ -13,33 +13,32 @@
+ Table Create Table
+ t2 CREATE TABLE `t2` (
+ `a` int(11) DEFAULT NULL
+-) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1
++) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(`mrg`.`t1`)
+ CREATE TEMPORARY TABLE t2 LIKE t1;
+ SHOW CREATE TABLE t2;
+ Table Create Table
+ t2 CREATE TEMPORARY TABLE `t2` (
+ `a` int(11) DEFAULT NULL
+-) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1
++) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(`mrg`.`t1`)
+ DROP TEMPORARY TABLE t2;
+ DROP TABLE t2;
+ DROP TABLE IF EXISTS t1;
+ CREATE TABLE t1 ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS> AS SELECT 1 UNION SELECT 2;
+-SHOW CREATE TABLE t1;
+-Table Create Table
+-t1 CREATE TABLE `t1` (
+- `1` int(1) 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 of type '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).
++# -------------------------------------------
+ SET storage_engine = <STORAGE_ENGINE>;
+ CREATE TABLE t1 (a <INT_COLUMN>) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+ SHOW CREATE TABLE t1;
+ Table Create Table
+ t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+-) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1
++) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(`mrg`.`t1`)
+ FLUSH LOGS;
+ DROP TABLE IF EXISTS 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 00000000..aabd1747
--- /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 00000000..55fc952c
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/disabled.def
@@ -0,0 +1,4 @@
+insert_delayed : MDEV-12880 - INSERT DELAYED is not detected as inapplicable to a table under lock
+lock_concurrent : MDEV-12882 - Assertion failure
+select_high_prio : MDEV-12885 - MDL_SHARED_READ_ONLY is taken instead of MDL_SHARED_READ
+lock : MDEV-17145 (Unexpected ER_LOCK_WAIT_TIMEOUT)
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 00000000..fc07ebc0
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/foreign_keys.rdiff
@@ -0,0 +1,147 @@
+--- foreign_keys.result 2013-01-22 22:05:05.246633000 +0400
++++ foreign_keys.reject 2013-01-23 02:50:28.187898084 +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`)
+-) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1
++ KEY `a` (`a`)
++) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(`mrg`.`t2`)
+ 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 a,b FROM t1;
+ a b
+ 1 c
+-2 d
++3 d
+ SELECT a,b 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_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).
++# -------------------------------------------
+ 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
+-) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1
++ KEY `a` (`a`)
++) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(`mrg`.`t2`)
+ 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 a,b 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 a,b 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 'test.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 00000000..c96b6971
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/fulltext_search.rdiff
@@ -0,0 +1,150 @@
+--- fulltext_search.result 2013-01-22 22:05:05.246633000 +0400
++++ fulltext_search.reject 2013-01-23 02:50:28.807890289 +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 storage engine MRG_MyISAM 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 storage engine MRG_MyISAM 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 00000000..9e9117e0
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/handler.rdiff
@@ -0,0 +1,88 @@
+--- handler.result 2013-01-22 22:05:05.246633000 +0400
++++ handler.reject 2013-01-23 02:50:29.411882697 +0400
+@@ -2,76 +2,19 @@
+ CREATE TABLE t1 (a <CHAR_COLUMN>, b <INT_COLUMN>) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+ INSERT INTO t1 (a,b) VALUES ('foobar',1000),('a',1),('bar',200),('foo',100);
+ HANDLER t1 OPEN AS h1;
+-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: Storage engine MRG_MyISAM of the table `test`.`t1` 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).
++# -------------------------------------------
+ DROP TABLE t1;
+ HANDLER h1 CLOSE;
+ ERROR 42S02: Unknown table 'h1' in HANDLER
+ CREATE TABLE t1 (a <INT_COLUMN>, b <CHAR_COLUMN>, <CUSTOM_INDEX> (a)) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+ INSERT INTO t1 (b,a) VALUES ('a',1),('b',200),('f',100),('b',101),('c',2);
+ HANDLER t1 OPEN AS h1;
+-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: Storage engine MRG_MyISAM of the table `test`.`t1` doesn't have this option
+ DROP TABLE t1;
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 00000000..bf680697
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/index.rdiff
@@ -0,0 +1,11 @@
+--- index.result 2013-01-22 22:05:05.246633000 +0400
++++ index.reject 2013-01-23 02:50:30.111873897 +0400
+@@ -61,7 +61,5 @@
+ ALTER TABLE t1 DROP INDEX a;
+ INSERT INTO t1 (a,b) VALUES (1,'c');
+ ALTER TABLE t1 ADD UNIQUE INDEX a(a) ;
+-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)
+ DROP TABLE t1;
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 00000000..357d4e93
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/index_enable_disable.rdiff
@@ -0,0 +1,33 @@
+--- index_enable_disable.result 2013-01-22 22:05:05.246633000 +0400
++++ index_enable_disable.reject 2013-01-23 02:50:30.723866202 +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 Storage engine MRG_MyISAM of the table `test`.`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 Storage engine MRG_MyISAM of the table `test`.`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 Storage engine MRG_MyISAM of the table `test`.`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/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 00000000..1874b0d5
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/index_type_btree.rdiff
@@ -0,0 +1,11 @@
+--- index_type_btree.result 2013-01-22 22:05:05.246633000 +0400
++++ index_type_btree.reject 2013-01-23 02:50:31.963850614 +0400
+@@ -61,7 +61,5 @@
+ ALTER TABLE t1 DROP INDEX a;
+ INSERT INTO t1 (a,b) VALUES (1,'c');
+ ALTER TABLE t1 ADD UNIQUE INDEX a(a) USING BTREE;
+-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)
+ DROP TABLE t1;
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 00000000..f6fd1e39
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/index_type_hash.rdiff
@@ -0,0 +1,69 @@
+--- index_type_hash.result 2013-01-22 22:05:05.246633000 +0400
++++ index_type_hash.reject 2013-01-23 02:50:32.647842015 +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'
+@@ -61,7 +61,5 @@
+ ALTER TABLE t1 DROP INDEX a;
+ INSERT INTO t1 (a,b) VALUES (1,'c');
+ ALTER TABLE t1 ADD UNIQUE INDEX a(a) USING HASH;
+-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)
+ DROP TABLE t1;
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 00000000..24ffa2ab
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/insert_delayed.rdiff
@@ -0,0 +1,26 @@
+--- insert_delayed.result 2013-01-23 01:23:49.461254916 +0400
++++ insert_delayed.reject 2013-01-23 02:50:34.475819034 +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 (a,b) 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/myisammrg/mysql-test/storage_engine/lock.rdiff b/storage/myisammrg/mysql-test/storage_engine/lock.rdiff
new file mode 100644
index 00000000..f6bb7540
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/lock.rdiff
@@ -0,0 +1,80 @@
+--- lock.result 2013-01-23 01:24:01.797100027 +0400
++++ lock.reject 2013-01-23 02:50:53.291582487 +0400
+@@ -42,34 +42,67 @@
+ UPDATE t1 SET id=1 WHERE id=-1;
+ DROP TABLE t1,t2;
+ CREATE TABLE t1 (i1 <INT_COLUMN>, nr <INT_COLUMN>) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
++ERROR HY000: Table 't1' was not locked with LOCK TABLES
++# ERROR: Statement ended with errno 1100, errname ER_TABLE_NOT_LOCKED (expected to succeed)
+ CREATE TABLE t2 (nr <INT_COLUMN>, nm <INT_COLUMN>) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
++ERROR HY000: Table 't2' was not locked with LOCK TABLES
++# ERROR: Statement ended with errno 1100, errname ER_TABLE_NOT_LOCKED (expected to succeed)
+ INSERT INTO t2 (nr,nm) VALUES (1,3);
++ERROR HY000: Table 't2' was not locked with LOCK TABLES
+ INSERT INTO t2 (nr,nm) VALUES (2,4);
++ERROR HY000: Table 't2' was not locked with LOCK TABLES
+ lock tables t1 write, t2 read;
++ERROR 42S02: Table 'test.t1' doesn't exist
+ INSERT INTO t1 (i1,nr) SELECT 1, nr FROM t2 WHERE nm=3;
++ERROR 42S02: Table 'test.t1' doesn't exist
+ INSERT INTO t1 (i1,nr) SELECT 2, nr FROM t2 WHERE nm=4;
++ERROR 42S02: Table 'test.t1' doesn't exist
+ UNLOCK TABLES;
+ LOCK TABLES t1 WRITE;
++ERROR 42S02: Table 'test.t1' doesn't exist
+ INSERT INTO t1 (i1,nr) SELECT i1, nr FROM t1;
+-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)
+ UNLOCK TABLES;
+ LOCK TABLES t1 WRITE, t1 AS t1_alias READ;
++ERROR 42S02: Table 'test.t1' doesn't exist
+ INSERT INTO t1 (i1,nr) SELECT i1, nr FROM t1 AS t1_alias;
++ERROR 42S02: Table 'test.t1' doesn't exist
+ DROP TABLE t1,t2;
+-ERROR HY000: Table 't2' was not locked with LOCK TABLES
++ERROR 42S02: Unknown table 'test.t1,test.t2'
++# ERROR: Statement ended with errno 1051, errname ER_BAD_TABLE_ERROR (expected results: ER_TABLE_NOT_LOCKED)
+ UNLOCK TABLES;
+ DROP TABLE t1,t2;
++ERROR 42S02: Unknown table 'test.t1,test.t2'
+ CREATE TABLE t1 (a <INT_COLUMN>, b <CHAR_COLUMN>) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+ CREATE TABLE t2 (a <INT_COLUMN>, b <CHAR_COLUMN>) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+ CREATE TABLE t3 (a <INT_COLUMN>, b <CHAR_COLUMN>) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+ LOCK TABLES t1 WRITE, t2 WRITE, t3 WRITE;
+ DROP TABLE t2, t3, t1;
+ CREATE TABLE t1 (a <INT_COLUMN>, b <CHAR_COLUMN>) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
++ERROR HY000: Table 't1' was not locked with LOCK TABLES
++# ERROR: Statement ended with errno 1100, errname ER_TABLE_NOT_LOCKED (expected to succeed)
+ CREATE TABLE t2 (a <INT_COLUMN>, b <CHAR_COLUMN>) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
++ERROR HY000: Table 't2' was not locked with LOCK TABLES
++# ERROR: Statement ended with errno 1100, errname ER_TABLE_NOT_LOCKED (expected to succeed)
+ CREATE TABLE t3 (a <INT_COLUMN>, b <CHAR_COLUMN>) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
++ERROR HY000: Table 't3' was not locked with LOCK TABLES
++# ERROR: Statement ended with errno 1100, errname ER_TABLE_NOT_LOCKED (expected to succeed)
+ LOCK TABLES t1 WRITE, t2 WRITE, t3 WRITE, t1 AS t4 READ;
++ERROR 42S02: Table 'test.t1' doesn't exist
+ ALTER TABLE t2 ADD COLUMN c2 <INT_COLUMN>;
++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).
++# -------------------------------------------
+ DROP TABLE t1, t2, t3;
++ERROR 42S02: Unknown table 'test.t1,test.t2,test.t3'
+ CREATE TABLE t1 (a <INT_COLUMN>, b <CHAR_COLUMN>) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+ CREATE TABLE t2 (a <INT_COLUMN>, b <CHAR_COLUMN>) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+ LOCK TABLE t1 READ, t2 READ;
+@@ -106,6 +139,6 @@
+ FLUSH TABLE t1;
+ DROP TEMPORARY TABLE t1;
+ SELECT a,b FROM t1;
+-a b
++ERROR HY000: Unable to open underlying table which is differently defined or of non-MyISAM type or doesn't exist
+ UNLOCK TABLES;
+ DROP TABLE t1, t2;
diff --git a/storage/myisammrg/mysql-test/storage_engine/misc.rdiff b/storage/myisammrg/mysql-test/storage_engine/misc.rdiff
new file mode 100644
index 00000000..cdbad003
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/misc.rdiff
@@ -0,0 +1,34 @@
+--- suite/storage_engine/misc.result 2018-02-23 03:01:49.673249912 +0200
++++ suite/storage_engine/misc.reject 2018-02-23 03:02:05.669249564 +0200
+@@ -28,6 +28,10 @@
+ SELECT TABLE_NAME, COLUMN_NAME, REFERENCED_TABLE_NAME, REFERENCED_COLUMN_NAME
+ FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE ORDER BY TABLE_NAME;
+ TABLE_NAME COLUMN_NAME REFERENCED_TABLE_NAME REFERENCED_COLUMN_NAME
++Warning 1286 Unknown storage engine 'InnoDB'
++Warning 1286 Unknown storage engine 'InnoDB'
++Warning 1286 Unknown storage engine 'InnoDB'
++Warnings:
+ column_stats column_name NULL NULL
+ column_stats db_name NULL NULL
+ column_stats table_name NULL NULL
+@@ -58,12 +62,6 @@
+ index_stats index_name NULL NULL
+ index_stats prefix_arity NULL NULL
+ index_stats table_name NULL NULL
+-innodb_index_stats database_name NULL NULL
+-innodb_index_stats index_name NULL NULL
+-innodb_index_stats stat_name NULL NULL
+-innodb_index_stats table_name NULL NULL
+-innodb_table_stats database_name NULL NULL
+-innodb_table_stats table_name NULL NULL
+ plugin name NULL NULL
+ proc db NULL NULL
+ proc name NULL NULL
+@@ -94,7 +92,5 @@
+ time_zone_transition Transition_time NULL NULL
+ time_zone_transition_type Time_zone_id NULL NULL
+ time_zone_transition_type Transition_type_id NULL NULL
+-transaction_registry commit_id NULL NULL
+-transaction_registry transaction_id NULL NULL
+ user Host NULL NULL
+ user User NULL NULL
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 00000000..1b611adf
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/optimize_table.rdiff
@@ -0,0 +1,35 @@
+--- optimize_table.result 2013-01-22 22:05:05.246633000 +0400
++++ optimize_table.reject 2013-01-23 02:50:54.339569313 +0400
+@@ -5,25 +5,25 @@
+ INSERT INTO t1 (a,b) VALUES (3,'c'),(4,'d');
+ OPTIMIZE TABLE t1;
+ Table Op Msg_type Msg_text
+-test.t1 optimize status OK
++test.t1 optimize note The storage engine for the table doesn't support optimize
+ INSERT INTO t2 (a,b) VALUES (4,'d');
+ OPTIMIZE NO_WRITE_TO_BINLOG TABLE t2;
+ Table Op Msg_type Msg_text
+-test.t2 optimize status OK
++test.t2 optimize note The storage engine for the table doesn't support optimize
+ 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 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
+ 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 The storage engine for the table doesn't support optimize
++test.t2 optimize note The storage engine for the table doesn't support optimize
+ 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 status OK
++test.t1 optimize note The storage engine for the table doesn't support optimize
+ DROP TABLE t1;
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 00000000..4c7ba7d8
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/parts/alter_table.rdiff
@@ -0,0 +1,68 @@
+--- alter_table.result 2013-01-22 22:05:05.246633000 +0400
++++ alter_table.reject 2013-01-23 03:16:22.620356221 +0400
+@@ -1,42 +1,29 @@
+ DROP TABLE IF EXISTS t1;
+ CREATE TABLE t1 (a <INT_COLUMN>) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS> PARTITION BY HASH(a) PARTITIONS 2;
+-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).
++# -------------------------------------------
+ CREATE TABLE t1 (a <INT_COLUMN>, b <INT_COLUMN>) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS> PARTITION BY LIST(a) SUBPARTITION by HASH(b) (
+ PARTITION abc VALUES IN (1,2,3),
+ PARTITION def VALUES IN (100,101,102)
+ );
+-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 00000000..7163aaef
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/parts/analyze_table.rdiff
@@ -0,0 +1,87 @@
+--- analyze_table.result 2013-01-22 22:05:05.246633000 +0400
++++ analyze_table.reject 2013-01-23 03:16:23.240348427 +0400
+@@ -1,47 +1,62 @@
+ 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;
+-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).
++# -------------------------------------------
+ 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;
++ERROR HY000: Engine cannot be used in partitioned tables
++# ERROR: Statement ended with errno 1572, errname ER_PARTITION_MERGE_ERROR (expected to succeed)
+ INSERT INTO t1 (a,b) VALUES (1,'a'),(2,'b');
++ERROR 42S02: Table 'test.t1' doesn't exist
+ CREATE TABLE t2 (a <INT_COLUMN>, b <CHAR_COLUMN>) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS> PARTITION BY HASH(a) PARTITIONS 2;
++ERROR HY000: Engine cannot be used in partitioned tables
++# ERROR: Statement ended with errno 1572, errname ER_PARTITION_MERGE_ERROR (expected to succeed)
+ INSERT INTO t1 (a,b) VALUES (3,'c');
++ERROR 42S02: Table 'test.t1' doesn't exist
+ ANALYZE TABLE t1;
+ Table Op Msg_type Msg_text
+-test.t1 analyze status OK
++test.t1 analyze Error Table 'test.t1' doesn't exist
++test.t1 analyze status Operation failed
+ INSERT INTO t2 (a,b) VALUES (4,'d');
++ERROR 42S02: Table 'test.t2' doesn't exist
+ ANALYZE NO_WRITE_TO_BINLOG TABLE t2;
+ Table Op Msg_type Msg_text
+-test.t2 analyze status OK
++test.t2 analyze Error Table 'test.t2' doesn't exist
++test.t2 analyze status Operation failed
+ INSERT INTO t1 (a,b) VALUES (5,'e');
++ERROR 42S02: Table 'test.t1' doesn't exist
+ INSERT INTO t2 (a,b) VALUES (6,'f');
++ERROR 42S02: Table 'test.t2' doesn't exist
+ ANALYZE LOCAL TABLE t1, t2;
+ Table Op Msg_type Msg_text
+-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
+ DROP TABLE t1, t2;
++ERROR 42S02: Unknown table 'test.t1,test.t2'
+ CREATE TABLE t1 (a <INT_COLUMN>, <CUSTOM_INDEX>(a)) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS> PARTITION BY HASH(a) PARTITIONS 2;
++ERROR HY000: Engine cannot be used in partitioned tables
++# ERROR: Statement ended with errno 1572, errname ER_PARTITION_MERGE_ERROR (expected to succeed)
+ INSERT INTO t1 (a) VALUES (1),(2),(4),(7);
++ERROR 42S02: Table 'test.t1' doesn't exist
+ ANALYZE TABLE t1;
+ Table Op Msg_type Msg_text
+-test.t1 analyze status OK
++test.t1 analyze Error Table 'test.t1' doesn't exist
++test.t1 analyze status Operation failed
+ INSERT INTO t1 (a) VALUES (8),(10),(11),(12);
++ERROR 42S02: Table 'test.t1' doesn't exist
+ ANALYZE TABLE t1;
+ Table Op Msg_type Msg_text
+-test.t1 analyze status OK
++test.t1 analyze Error Table 'test.t1' doesn't exist
++test.t1 analyze status Operation failed
+ DROP TABLE t1;
++ERROR 42S02: Unknown table 'test.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 00000000..5f7b7c75
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/parts/check_table.rdiff
@@ -0,0 +1,176 @@
+--- check_table.result 2013-01-22 22:05:05.246633000 +0400
++++ check_table.reject 2013-01-23 03:16:23.872340482 +0400
+@@ -1,104 +1,122 @@
+ 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;
+-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).
++# -------------------------------------------
+ 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;
++ERROR HY000: Engine cannot be used in partitioned tables
++# ERROR: Statement ended with errno 1572, errname ER_PARTITION_MERGE_ERROR (expected to succeed)
+ INSERT INTO t1 (a,b) VALUES (1,'a'),(2,'b');
++ERROR 42S02: Table 'test.t1' doesn't exist
+ CREATE TABLE t2 (a <INT_COLUMN>, b <CHAR_COLUMN>) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS> PARTITION BY HASH(a) PARTITIONS 2;
++ERROR HY000: Engine cannot be used in partitioned tables
++# ERROR: Statement ended with errno 1572, errname ER_PARTITION_MERGE_ERROR (expected to succeed)
+ CHECK TABLE t1;
+ Table Op Msg_type Msg_text
+-test.t1 check status OK
++test.t1 check Error Table 'test.t1' doesn't exist
++test.t1 check status Operation failed
+ INSERT INTO t1 (a,b) VALUES (3,'c');
++ERROR 42S02: Table 'test.t1' doesn't exist
+ INSERT INTO t2 (a,b) VALUES (4,'d');
++ERROR 42S02: Table 'test.t2' doesn't exist
+ CHECK TABLE t1, t2 FOR UPGRADE;
+ Table Op Msg_type Msg_text
+-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
+ INSERT INTO t2 (a,b) VALUES (5,'e');
++ERROR 42S02: Table 'test.t2' doesn't exist
+ CHECK TABLE t2 QUICK;
+ Table Op Msg_type Msg_text
+-test.t2 check status OK
++test.t2 check Error Table 'test.t2' doesn't exist
++test.t2 check status Operation failed
+ INSERT INTO t1 (a,b) VALUES (6,'f');
++ERROR 42S02: Table 'test.t1' doesn't exist
+ CHECK TABLE t1 FAST;
+ Table Op Msg_type Msg_text
+-test.t1 check status OK
++test.t1 check Error Table 'test.t1' doesn't exist
++test.t1 check status Operation failed
+ INSERT INTO t1 (a,b) VALUES (7,'g');
++ERROR 42S02: Table 'test.t1' doesn't exist
+ INSERT INTO t2 (a,b) VALUES (8,'h');
++ERROR 42S02: Table 'test.t2' doesn't exist
+ CHECK TABLE t2, t1 MEDIUM;
+ Table Op Msg_type Msg_text
+-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
+ INSERT INTO t1 (a,b) VALUES (9,'i');
++ERROR 42S02: Table 'test.t1' doesn't exist
+ INSERT INTO t2 (a,b) VALUES (10,'j');
++ERROR 42S02: Table 'test.t2' doesn't exist
+ CHECK TABLE t1, t2 EXTENDED;
+ Table Op Msg_type Msg_text
+-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
+ INSERT INTO t1 (a,b) VALUES (11,'k');
++ERROR 42S02: Table 'test.t1' doesn't exist
+ CHECK TABLE t1 CHANGED;
+ Table Op Msg_type Msg_text
+-test.t1 check status OK
++test.t1 check Error Table 'test.t1' doesn't exist
++test.t1 check status Operation failed
+ DROP TABLE t1, t2;
++ERROR 42S02: Unknown table 'test.t1,test.t2'
+ CREATE TABLE t1 (a <INT_COLUMN>, <CUSTOM_INDEX>(a)) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS> PARTITION BY HASH(a) PARTITIONS 2;
++ERROR HY000: Engine cannot be used in partitioned tables
++# ERROR: Statement ended with errno 1572, errname ER_PARTITION_MERGE_ERROR (expected to succeed)
+ INSERT INTO t1 (a) VALUES (1),(2),(5);
++ERROR 42S02: Table 'test.t1' doesn't exist
+ CHECK TABLE t1;
+ Table Op Msg_type Msg_text
+-test.t1 check status OK
++test.t1 check Error Table 'test.t1' doesn't exist
++test.t1 check status Operation failed
+ INSERT INTO t1 (a) VALUES (6),(8),(12);
++ERROR 42S02: Table 'test.t1' doesn't exist
+ CHECK TABLE t1 FOR UPGRADE;
+ Table Op Msg_type Msg_text
+-test.t1 check status OK
++test.t1 check Error Table 'test.t1' doesn't exist
++test.t1 check status Operation failed
+ INSERT INTO t1 (a) VALUES (13),(15),(16);
++ERROR 42S02: Table 'test.t1' doesn't exist
+ CHECK TABLE t1 QUICK;
+ Table Op Msg_type Msg_text
+-test.t1 check status OK
++test.t1 check Error Table 'test.t1' doesn't exist
++test.t1 check status Operation failed
+ INSERT INTO t1 (a) VALUES (17),(120),(132);
++ERROR 42S02: Table 'test.t1' doesn't exist
+ CHECK TABLE t1 FAST;
+ Table Op Msg_type Msg_text
+-test.t1 check status OK
++test.t1 check Error Table 'test.t1' doesn't exist
++test.t1 check status Operation failed
+ INSERT INTO t1 (a) VALUES (801),(900),(7714);
++ERROR 42S02: Table 'test.t1' doesn't exist
+ CHECK TABLE t1 MEDIUM;
+ Table Op Msg_type Msg_text
+-test.t1 check status OK
++test.t1 check Error Table 'test.t1' doesn't exist
++test.t1 check status Operation failed
+ INSERT INTO t1 (a) VALUES (8760),(10023),(12000);
++ERROR 42S02: Table 'test.t1' doesn't exist
+ CHECK TABLE t1 EXTENDED;
+ Table Op Msg_type Msg_text
+-test.t1 check status OK
++test.t1 check Error Table 'test.t1' doesn't exist
++test.t1 check status Operation failed
+ INSERT INTO t1 (a) VALUES (13345),(24456),(78302),(143028);
++ERROR 42S02: Table 'test.t1' doesn't exist
+ CHECK TABLE t1 CHANGED;
+ Table Op Msg_type Msg_text
+-test.t1 check status OK
++test.t1 check Error Table 'test.t1' doesn't exist
++test.t1 check status Operation failed
+ DROP TABLE t1;
++ERROR 42S02: Unknown table 'test.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 00000000..6d01f056
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/parts/checksum_table.rdiff
@@ -0,0 +1,89 @@
+--- checksum_table.result 2013-01-22 22:05:05.246633000 +0400
++++ checksum_table.reject 2013-01-23 03:16:24.496332636 +0400
+@@ -1,40 +1,74 @@
+ DROP TABLE IF EXISTS t1,t2;
+ CREATE TABLE t1 (a <INT_COLUMN>, b <CHAR_COLUMN>) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS> CHECKSUM=0 PARTITION BY HASH(a) PARTITIONS 2;
++ERROR HY000: Engine cannot be used in partitioned tables
++# ERROR: Statement ended with errno 1572, errname ER_PARTITION_MERGE_ERROR (expected to succeed)
+ INSERT INTO t1 (a,b) VALUES (1,'a'),(2,'b');
++ERROR 42S02: Table 'test.t1' doesn't exist
+ CREATE TABLE t2 (a <INT_COLUMN>, b <CHAR_COLUMN>) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS> CHECKSUM=0 PARTITION BY HASH(a) PARTITIONS 2;
++ERROR HY000: Engine cannot be used in partitioned tables
++# ERROR: Statement ended with errno 1572, errname ER_PARTITION_MERGE_ERROR (expected to succeed)
+ CHECKSUM TABLE t1;
+ Table Checksum
+-test.t1 4272806499
++test.t1 NULL
++Warnings:
++Error 1146 Table 'test.t1' doesn't exist
+ CHECKSUM TABLE t2, t1;
+ Table Checksum
+-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
+ CHECKSUM TABLE t1, t2 QUICK;
+ Table Checksum
+ test.t1 NULL
+ test.t2 NULL
++Warnings:
++Error 1146 Table 'test.t1' doesn't exist
++Error 1146 Table 'test.t2' doesn't exist
+ CHECKSUM TABLE t1, t2 EXTENDED;
+ Table Checksum
+-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
+ DROP TABLE t1, t2;
++ERROR 42S02: Unknown table 'test.t1,test.t2'
+ DROP TABLE IF EXISTS t1,t2;
+ CREATE TABLE t1 (a <INT_COLUMN>, b <CHAR_COLUMN>) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS> CHECKSUM=1 PARTITION BY HASH(a) PARTITIONS 2;
++ERROR HY000: Engine cannot be used in partitioned tables
++# ERROR: Statement ended with errno 1572, errname ER_PARTITION_MERGE_ERROR (expected to succeed)
+ INSERT INTO t1 (a,b) VALUES (1,'a'),(2,'b');
++ERROR 42S02: Table 'test.t1' doesn't exist
+ CREATE TABLE t2 (a <INT_COLUMN>, b <CHAR_COLUMN>) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS> CHECKSUM=1 PARTITION BY HASH(a) PARTITIONS 2;
++ERROR HY000: Engine cannot be used in partitioned tables
++# ERROR: Statement ended with errno 1572, errname ER_PARTITION_MERGE_ERROR (expected to succeed)
+ CHECKSUM TABLE t1;
+ Table Checksum
+-test.t1 4272806499
++test.t1 NULL
++Warnings:
++Error 1146 Table 'test.t1' doesn't exist
+ CHECKSUM TABLE t2, t1;
+ Table Checksum
+-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
+ CHECKSUM TABLE t1, t2 QUICK;
+ Table Checksum
+-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
+ CHECKSUM TABLE t1, t2 EXTENDED;
+ Table Checksum
+-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
+ DROP TABLE t1, t2;
++ERROR 42S02: Unknown table 'test.t1,test.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 00000000..d6aa75f1
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/parts/create_table.rdiff
@@ -0,0 +1,159 @@
+--- create_table.result 2013-01-22 22:05:05.246633000 +0400
++++ create_table.reject 2013-01-23 03:16:25.160324290 +0400
+@@ -1,91 +1,79 @@
+ DROP TABLE IF EXISTS t1;
+ CREATE TABLE t1 (a <INT_COLUMN>) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS> PARTITION BY HASH(a) PARTITIONS 2;
+-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).
++# -------------------------------------------
+ CREATE TABLE t1 (a <CHAR_COLUMN>) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS> PARTITION BY KEY(a) PARTITIONS 2;
+-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).
++# -------------------------------------------
+ CREATE TABLE t1 (a <INT_COLUMN>, <CUSTOM_INDEX> (a)) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS> PARTITION BY KEY(a) PARTITIONS 2;
+-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).
++# -------------------------------------------
+ CREATE TABLE t1 (a <INT_COLUMN> PRIMARY KEY) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS> PARTITION BY KEY() PARTITIONS 2;
+-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).
++# -------------------------------------------
+ CREATE TABLE t1 (a <INT_COLUMN>) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS> PARTITION BY RANGE(a) (
+ PARTITION p0 VALUES LESS THAN (10),
+ PARTITION p1 VALUES LESS THAN (1000)
+ );
+-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) (
+ PARTITION abc VALUES IN (1,2,3),
+ PARTITION def VALUES IN (100,101,102)
+ );
+-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) (
+ PARTITION abc VALUES IN (1,2,3),
+ PARTITION def VALUES IN (100,101,102)
+-);
+-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 00000000..2e2a1fec
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/parts/optimize_table.rdiff
@@ -0,0 +1,95 @@
+--- optimize_table.result 2013-01-22 22:05:05.246633000 +0400
++++ optimize_table.reject 2013-01-23 03:16:25.780316495 +0400
+@@ -1,54 +1,62 @@
+ 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;
+-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).
++# -------------------------------------------
+ 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;
++ERROR HY000: Engine cannot be used in partitioned tables
++# ERROR: Statement ended with errno 1572, errname ER_PARTITION_MERGE_ERROR (expected to succeed)
+ INSERT INTO t1 (a,b) VALUES (1,'a'),(2,'b');
++ERROR 42S02: Table 'test.t1' doesn't exist
+ CREATE TABLE t2 (a <INT_COLUMN>, b <CHAR_COLUMN>) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS> PARTITION BY HASH(a) PARTITIONS 2;
++ERROR HY000: Engine cannot be used in partitioned tables
++# ERROR: Statement ended with errno 1572, errname ER_PARTITION_MERGE_ERROR (expected to succeed)
+ INSERT INTO t1 (a,b) VALUES (3,'c'),(4,'d');
++ERROR 42S02: Table 'test.t1' doesn't exist
+ OPTIMIZE TABLE t1;
+ Table Op Msg_type Msg_text
+-test.t1 optimize status OK
++test.t1 optimize Error Table 'test.t1' doesn't exist
++test.t1 optimize status Operation failed
+ INSERT INTO t2 (a,b) VALUES (4,'d');
++ERROR 42S02: Table 'test.t2' doesn't exist
+ OPTIMIZE NO_WRITE_TO_BINLOG TABLE t2;
+ Table Op Msg_type Msg_text
+-test.t2 optimize status OK
++test.t2 optimize Error Table 'test.t2' doesn't exist
++test.t2 optimize status Operation failed
+ INSERT INTO t2 (a,b) VALUES (5,'e');
++ERROR 42S02: Table 'test.t2' doesn't exist
+ INSERT INTO t1 (a,b) VALUES (6,'f');
++ERROR 42S02: Table 'test.t1' doesn't exist
+ OPTIMIZE LOCAL TABLE t1, t2;
+ Table Op Msg_type Msg_text
+-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
+ OPTIMIZE TABLE t1, t2;
+ Table Op Msg_type Msg_text
+-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
+ DROP TABLE t1, t2;
++ERROR 42S02: Unknown table 'test.t1,test.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;
++ERROR HY000: Engine cannot be used in partitioned tables
++# ERROR: Statement ended with errno 1572, errname ER_PARTITION_MERGE_ERROR (expected to succeed)
+ INSERT INTO t1 (a,b) VALUES (1,'a'),(100,'b'),(2,'c'),(3,'d');
++ERROR 42S02: Table 'test.t1' doesn't exist
+ OPTIMIZE TABLE t1;
+ Table Op Msg_type Msg_text
+-test.t1 optimize status OK
++test.t1 optimize Error Table 'test.t1' doesn't exist
++test.t1 optimize status Operation failed
+ DROP TABLE t1;
++ERROR 42S02: Unknown table 'test.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 00000000..eddb6872
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/parts/repair_table.rdiff
@@ -0,0 +1,299 @@
+--- suite/storage_engine/parts/repair_table.result 2017-08-28 19:29:20.491633306 +0300
++++ suite/storage_engine/parts/repair_table.reject 2017-08-28 19:34:41.723633059 +0300
+@@ -1,232 +1,116 @@
+ call mtr.add_suppression("Table '.*t1.*' is marked as crashed and should be repaired");
+ 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;
+-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 (a,b) 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 (a,b) 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).
++# -------------------------------------------
+ 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;
++ERROR HY000: Engine cannot be used in partitioned tables
++# ERROR: Statement ended with errno 1572, errname ER_PARTITION_MERGE_ERROR (expected to succeed)
+ INSERT INTO t1 (a,b) VALUES (1,'a'),(2,'b');
++ERROR 42S02: Table 'test.t1' doesn't exist
+ CREATE TABLE t2 (a <INT_COLUMN>, b <CHAR_COLUMN>) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS> PARTITION BY HASH(a) PARTITIONS 2;
++ERROR HY000: Engine cannot be used in partitioned tables
++# ERROR: Statement ended with errno 1572, errname ER_PARTITION_MERGE_ERROR (expected to succeed)
+ REPAIR TABLE t1;
+ Table Op Msg_type Msg_text
+-test.t1 repair status OK
++test.t1 repair Error Table 'test.t1' doesn't exist
++test.t1 repair status Operation failed
+ INSERT INTO t1 (a,b) VALUES (3,'c');
++ERROR 42S02: Table 'test.t1' doesn't exist
+ INSERT INTO t2 (a,b) VALUES (4,'d');
++ERROR 42S02: Table 'test.t2' doesn't exist
+ 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 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
+ INSERT INTO t2 (a,b) VALUES (5,'e'),(6,'f');
++ERROR 42S02: Table 'test.t2' doesn't exist
+ REPAIR LOCAL TABLE t2;
+ Table Op Msg_type Msg_text
+-test.t2 repair status OK
++test.t2 repair Error Table 'test.t2' doesn't exist
++test.t2 repair status Operation failed
+ INSERT INTO t1 (a,b) VALUES (7,'g'),(8,'h');
++ERROR 42S02: Table 'test.t1' doesn't exist
+ INSERT INTO t2 (a,b) VALUES (9,'i');
++ERROR 42S02: Table 'test.t2' doesn't exist
+ 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 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
+ INSERT INTO t1 (a,b) VALUES (10,'j');
++ERROR 42S02: Table 'test.t1' doesn't exist
+ INSERT INTO t2 (a,b) VALUES (11,'k');
++ERROR 42S02: Table 'test.t2' doesn't exist
+ 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 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
+ INSERT INTO t1 (a,b) VALUES (12,'l');
++ERROR 42S02: Table 'test.t1' doesn't exist
+ INSERT INTO t2 (a,b) VALUES (13,'m');
++ERROR 42S02: Table 'test.t2' doesn't exist
+ 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 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
+ FLUSH TABLE t1;
+ INSERT INTO t1 (a,b) VALUES (14,'n');
+-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)
+ CHECK TABLE t1;
+ Table Op Msg_type Msg_text
+-test.t1 check Error Failed to read from the .par file
+-test.t1 check error Corrupt
++test.t1 check Error Table 'test.t1' doesn't exist
++test.t1 check status Operation failed
+ SELECT a,b FROM t1;
+-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)
+ REPAIR TABLE t1;
+ Table Op Msg_type Msg_text
+-test.t1 repair Error Failed to read from the .par file
+-test.t1 repair error Corrupt
++test.t1 repair Error Table 'test.t1' doesn't exist
++test.t1 repair status Operation failed
+ DROP TABLE t1, t2;
++ERROR 42S02: Unknown table 'test.t1,test.t2'
+ call mtr.add_suppression("Got an error from thread_id=.*");
+ call mtr.add_suppression("MySQL thread id .*, query id .* localhost.*root Checking table");
+ call mtr.add_suppression(" '\..test.t1'");
+ call mtr.add_suppression("Couldn't repair table: test.t1");
+ call mtr.add_suppression("Table 't1' is marked as crashed.*");
+ CREATE TABLE t1 (a <INT_COLUMN>, b <CHAR_COLUMN>, <CUSTOM_INDEX> (a)) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS> PARTITION BY HASH(a) PARTITIONS 2;
++ERROR HY000: Engine cannot be used in partitioned tables
++# ERROR: Statement ended with errno 1572, errname ER_PARTITION_MERGE_ERROR (expected to succeed)
+ REPAIR TABLE t1;
+ Table Op Msg_type Msg_text
+-test.t1 repair status OK
++test.t1 repair Error Table 'test.t1' doesn't exist
++test.t1 repair status Operation failed
+ INSERT INTO t1 (a,b) VALUES (7,'g'),(8,'h');
++ERROR 42S02: Table 'test.t1' doesn't exist
+ REPAIR TABLE t1 EXTENDED;
+ Table Op Msg_type Msg_text
+-test.t1 repair status OK
++test.t1 repair Error Table 'test.t1' doesn't exist
++test.t1 repair status Operation failed
+ INSERT INTO t1 (a,b) VALUES (10,'j');
++ERROR 42S02: Table 'test.t1' doesn't exist
+ REPAIR TABLE t1 USE_FRM;
+ Table Op Msg_type Msg_text
+-test.t1 repair status OK
++test.t1 repair Error Table 'test.t1' doesn't exist
++test.t1 repair status Operation failed
+ db.opt
+-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 a,b 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 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 a,b 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 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 a,b 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 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 a,b 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 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 a,b 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
+ DROP TABLE t1;
++ERROR 42S02: Unknown table 'test.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 00000000..9ba985f7
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/parts/truncate_table.rdiff
@@ -0,0 +1,101 @@
+--- truncate_table.result 2013-01-22 22:05:05.246633000 +0400
++++ truncate_table.reject 2013-01-23 03:16:27.076300201 +0400
+@@ -1,68 +1,34 @@
+ DROP TABLE IF EXISTS t1;
+ CREATE TABLE t1 (a <INT_COLUMN>, b <CHAR_COLUMN>) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS> PARTITION BY HASH(a) PARTITIONS 2;
+-TRUNCATE TABLE t1;
+-INSERT INTO t1 (a,b) VALUES (1,'a'), (2,'b'), (3,'c');
+-TRUNCATE TABLE t1;
+-SELECT a,b 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).
++# -------------------------------------------
+ CREATE TABLE t1 (a <INT_COLUMN> KEY AUTO_INCREMENT, c <CHAR_COLUMN>) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS> PARTITION BY HASH(a) PARTITIONS 2;
+-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
+- 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
+- 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
+- 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
+- PARTITION BY HASH (`a`)
+-PARTITIONS 2
+-SELECT a,c 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).
++# -------------------------------------------
+ CREATE TABLE t1 (a <INT_COLUMN>, b <CHAR_COLUMN>) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS> PARTITION BY HASH(a) PARTITIONS 2;
+-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 a,b FROM t1;
+-a b
+-1 a
+-101 g
+-3 c
+-EXPLAIN PARTITIONS SELECT a,b 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 a,b 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 00000000..d6c46b8c
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/repair_table.rdiff
@@ -0,0 +1,132 @@
+--- suite/storage_engine/repair_table.result 2017-05-24 01:09:07.274213486 +0300
++++ suite/storage_engine/repair_table.reject 2017-05-24 01:10:25.466214949 +0300
+@@ -4,56 +4,50 @@
+ 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'
++ERROR HY000: Table 't1' is read only
+ # 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 a,b FROM t1;
+-ERROR HY000: Incorrect file format 't1'
++a b
+ # 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");
+@@ -63,46 +57,33 @@
+ 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
++test.t1 repair note The storage engine for the table doesn't support repair
+ db.opt
+-t1.MYD
+-t1.MYI
++t1.MRG
+ 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
++Restoring <DATADIR>/test/t1.MRG
+ 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
++test.t1 check status OK
+ SELECT a,b FROM t1;
+-ERROR HY000: Index for table 't1' is corrupt; 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 a,b 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
+ # 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/myisammrg/mysql-test/storage_engine/show_engine.rdiff b/storage/myisammrg/mysql-test/storage_engine/show_engine.rdiff
new file mode 100644
index 00000000..e78e6fda
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/show_engine.rdiff
@@ -0,0 +1,10 @@
+--- show_engine.result 2013-01-22 22:05:05.246633000 +0400
++++ show_engine.reject 2013-01-23 02:50:56.871537482 +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/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 00000000..4de7e81f
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/tbl_opt_ai.rdiff
@@ -0,0 +1,16 @@
+--- tbl_opt_ai.result 2013-01-22 22:05:05.246633000 +0400
++++ tbl_opt_ai.reject 2013-01-23 02:50:57.547528984 +0400
+@@ -4,11 +4,11 @@
+ Table Create Table
+ t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+-) ENGINE=<STORAGE_ENGINE> AUTO_INCREMENT=10 DEFAULT CHARSET=latin1
++) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(`mrg`.`t1`)
+ ALTER TABLE t1 AUTO_INCREMENT=100;
+ SHOW CREATE TABLE t1;
+ Table Create Table
+ t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+-) ENGINE=<STORAGE_ENGINE> AUTO_INCREMENT=100 DEFAULT CHARSET=latin1
++) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(`mrg`.`t1`)
+ DROP TABLE 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 00000000..2632fabf
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/tbl_opt_avg_row_length.rdiff
@@ -0,0 +1,17 @@
+--- tbl_opt_avg_row_length.result 2013-01-22 22:05:05.246633000 +0400
++++ tbl_opt_avg_row_length.reject 2013-01-23 02:50:58.123521742 +0400
+@@ -5,12 +5,12 @@
+ t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL,
+ `b` char(8) DEFAULT NULL
+-) 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`)
+ ALTER TABLE t1 AVG_ROW_LENGTH=30000000;
+ SHOW CREATE TABLE t1;
+ Table Create Table
+ t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL,
+ `b` char(8) DEFAULT NULL
+-) 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`)
+ DROP TABLE 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 00000000..baad32dd
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/tbl_opt_checksum.rdiff
@@ -0,0 +1,17 @@
+--- tbl_opt_checksum.result 2013-01-22 22:05:05.246633000 +0400
++++ tbl_opt_checksum.reject 2013-01-23 02:50:58.739513998 +0400
+@@ -5,12 +5,12 @@
+ t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL,
+ `b` char(8) DEFAULT NULL
+-) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 CHECKSUM=1
++) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 CHECKSUM=1 INSERT_METHOD=LAST UNION=(`mrg`.`t1`)
+ ALTER TABLE t1 CHECKSUM=0;
+ SHOW CREATE TABLE t1;
+ Table Create Table
+ t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL,
+ `b` char(8) DEFAULT NULL
+-) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1
++) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(`mrg`.`t1`)
+ DROP TABLE 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 00000000..3dc06fb2
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/tbl_opt_connection.rdiff
@@ -0,0 +1,19 @@
+--- tbl_opt_connection.result 2013-01-22 22:05:05.246633000 +0400
++++ tbl_opt_connection.reject 2013-01-23 02:50:59.335506506 +0400
+@@ -10,14 +10,14 @@
+ t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL,
+ `b` char(8) DEFAULT NULL
+-) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 CONNECTION='test_connection'
++) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(`mrg`.`t1`) CONNECTION='test_connection'
+ ALTER TABLE t1 CONNECTION='test_connection2';
+ SHOW CREATE TABLE t1;
+ Table Create Table
+ t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL,
+ `b` char(8) DEFAULT NULL
+-) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 CONNECTION='test_connection2'
++) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(`mrg`.`t1`) CONNECTION='test_connection2'
+ DROP TABLE t1;
+ DROP SERVER test_connection;
+ DROP SERVER test_connection2;
diff --git a/storage/myisammrg/mysql-test/storage_engine/tbl_opt_data_dir.rdiff b/storage/myisammrg/mysql-test/storage_engine/tbl_opt_data_dir.rdiff
new file mode 100644
index 00000000..671e26ec
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/tbl_opt_data_dir.rdiff
@@ -0,0 +1,18 @@
+--- suite/storage_engine/tbl_opt_data_dir.result 2017-05-24 00:21:15.550159778 +0300
++++ ../storage/myisammrg/mysql-test/storage_engine/tbl_opt_data_dir.reject 2017-05-24 00:25:45.506164827 +0300
+@@ -5,7 +5,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_1>'
++) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(`mrg`.`t1`)
+ # For ALTER TABLE the option is ignored
+ # Running ALTER TABLE .. DATA DIRECTORY = <>
+ Warnings:
+@@ -15,5 +15,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_1>'
++) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(`mrg`.`t1`)
+ DROP TABLE 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 00000000..2c2e40fa
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/tbl_opt_delay_key_write.rdiff
@@ -0,0 +1,17 @@
+--- tbl_opt_delay_key_write.result 2013-01-22 22:05:05.246633000 +0400
++++ tbl_opt_delay_key_write.reject 2013-01-23 02:51:00.591490716 +0400
+@@ -5,12 +5,12 @@
+ t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL,
+ `b` char(8) DEFAULT NULL
+-) 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`)
+ ALTER TABLE t1 DELAY_KEY_WRITE=0;
+ SHOW CREATE TABLE t1;
+ Table Create Table
+ t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL,
+ `b` char(8) DEFAULT NULL
+-) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1
++) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(`mrg`.`t1`)
+ DROP TABLE t1;
diff --git a/storage/myisammrg/mysql-test/storage_engine/tbl_opt_index_dir.rdiff b/storage/myisammrg/mysql-test/storage_engine/tbl_opt_index_dir.rdiff
new file mode 100644
index 00000000..ca025861
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/tbl_opt_index_dir.rdiff
@@ -0,0 +1,18 @@
+--- suite/storage_engine/tbl_opt_index_dir.result 2017-05-24 00:21:15.550159778 +0300
++++ ../storage/myisammrg/mysql-test/storage_engine/tbl_opt_index_dir.reject 2017-05-24 00:25:45.506164827 +0300
+@@ -5,7 +5,7 @@
+ t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL,
+ `b` char(8) DEFAULT NULL
+-) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 INDEX DIRECTORY='<INDEX_DIR_1>'
++) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(`mrg`.`t1`)
+ # For ALTER TABLE the option is ignored
+ # Running ALTER TABLE .. INDEX DIRECTORY = <>
+ Warnings:
+@@ -15,5 +15,5 @@
+ t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL,
+ `b` char(8) DEFAULT NULL
+-) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 INDEX DIRECTORY='<INDEX_DIR_1>'
++) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(`mrg`.`t1`)
+ DROP TABLE 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 00000000..f5dc536c
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/tbl_opt_insert_method.rdiff
@@ -0,0 +1,17 @@
+--- tbl_opt_insert_method.result 2013-01-22 22:05:05.246633000 +0400
++++ tbl_opt_insert_method.reject 2013-01-23 02:51:01.211482922 +0400
+@@ -5,12 +5,12 @@
+ 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 INSERT_METHOD=FIRST UNION=(`mrg`.`t1`)
+ ALTER TABLE t1 INSERT_METHOD=NO;
+ SHOW CREATE TABLE t1;
+ Table Create Table
+ t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL,
+ `b` char(8) DEFAULT NULL
+-) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1
++) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 UNION=(`mrg`.`t1`)
+ DROP TABLE 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 00000000..be90252f
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/tbl_opt_key_block_size.rdiff
@@ -0,0 +1,17 @@
+--- tbl_opt_key_block_size.result 2013-01-22 22:05:05.246633000 +0400
++++ tbl_opt_key_block_size.reject 2013-01-23 02:51:01.787475681 +0400
+@@ -5,12 +5,12 @@
+ t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL,
+ `b` char(8) DEFAULT NULL
+-) 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`)
+ ALTER TABLE t1 KEY_BLOCK_SIZE=1;
+ SHOW CREATE TABLE t1;
+ Table Create Table
+ t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL,
+ `b` char(8) DEFAULT NULL
+-) 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`)
+ DROP TABLE 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 00000000..3eebf8cc
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/tbl_opt_max_rows.rdiff
@@ -0,0 +1,17 @@
+--- tbl_opt_max_rows.result 2013-01-22 22:05:05.246633000 +0400
++++ tbl_opt_max_rows.reject 2013-01-23 02:51:02.403467936 +0400
+@@ -5,12 +5,12 @@
+ t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL,
+ `b` char(8) DEFAULT NULL
+-) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 MAX_ROWS=10000000
++) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 MAX_ROWS=10000000 INSERT_METHOD=LAST UNION=(`mrg`.`t1`)
+ ALTER TABLE t1 MAX_ROWS=30000000;
+ SHOW CREATE TABLE t1;
+ Table Create Table
+ t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL,
+ `b` char(8) DEFAULT NULL
+-) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 MAX_ROWS=30000000
++) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 MAX_ROWS=30000000 INSERT_METHOD=LAST UNION=(`mrg`.`t1`)
+ DROP TABLE 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 00000000..48c7124c
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/tbl_opt_min_rows.rdiff
@@ -0,0 +1,17 @@
+--- tbl_opt_min_rows.result 2013-01-22 22:05:05.246633000 +0400
++++ tbl_opt_min_rows.reject 2013-01-23 02:51:02.983460644 +0400
+@@ -5,12 +5,12 @@
+ t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL,
+ `b` char(8) DEFAULT NULL
+-) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 MIN_ROWS=1
++) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 MIN_ROWS=1 INSERT_METHOD=LAST UNION=(`mrg`.`t1`)
+ ALTER TABLE t1 MIN_ROWS=10000;
+ SHOW CREATE TABLE t1;
+ Table Create Table
+ t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL,
+ `b` char(8) DEFAULT NULL
+-) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 MIN_ROWS=10000
++) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 MIN_ROWS=10000 INSERT_METHOD=LAST UNION=(`mrg`.`t1`)
+ DROP TABLE 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 00000000..ab16cbcb
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/tbl_opt_pack_keys.rdiff
@@ -0,0 +1,17 @@
+--- tbl_opt_pack_keys.result 2013-01-22 22:05:05.246633000 +0400
++++ tbl_opt_pack_keys.reject 2013-01-23 02:51:03.563453353 +0400
+@@ -5,12 +5,12 @@
+ t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL,
+ `b` char(8) DEFAULT NULL
+-) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 PACK_KEYS=1
++) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 PACK_KEYS=1 INSERT_METHOD=LAST UNION=(`mrg`.`t1`)
+ ALTER TABLE t1 PACK_KEYS=0;
+ SHOW CREATE TABLE t1;
+ Table Create Table
+ t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL,
+ `b` char(8) DEFAULT NULL
+-) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 PACK_KEYS=0
++) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 PACK_KEYS=0 INSERT_METHOD=LAST UNION=(`mrg`.`t1`)
+ DROP TABLE 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 00000000..dc830368
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/tbl_opt_password.rdiff
@@ -0,0 +1,17 @@
+--- tbl_opt_password.result 2013-01-22 22:05:05.246633000 +0400
++++ tbl_opt_password.reject 2013-01-23 02:51:04.155445910 +0400
+@@ -5,12 +5,12 @@
+ t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL,
+ `b` char(8) DEFAULT NULL
+-) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1
++) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(`mrg`.`t1`)
+ ALTER TABLE t1 PASSWORD='new_password';
+ SHOW CREATE TABLE t1;
+ Table Create Table
+ t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL,
+ `b` char(8) DEFAULT NULL
+-) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1
++) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(`mrg`.`t1`)
+ DROP TABLE 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 00000000..6c756e7b
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/tbl_opt_row_format.rdiff
@@ -0,0 +1,33 @@
+--- ../storage/myisammrg/mysql-test/storage_engine/tbl_opt_row_format.result~ 2017-05-24 00:50:44.254192857 +0300
++++ ../storage/myisammrg/mysql-test/storage_engine/tbl_opt_row_format.reject 2017-05-24 00:50:44.334192859 +0300
+@@ -5,26 +5,26 @@
+ t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL,
+ `b` char(8) DEFAULT NULL
+-) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 ROW_FORMAT=DYNAMIC
++) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 ROW_FORMAT=DYNAMIC INSERT_METHOD=LAST UNION=(`mrg`.`t1`)
+ ALTER TABLE t1 ROW_FORMAT=FIXED;
+ SHOW CREATE TABLE t1;
+ Table Create Table
+ t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL,
+ `b` char(8) DEFAULT NULL
+-) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 ROW_FORMAT=FIXED
++) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 ROW_FORMAT=FIXED INSERT_METHOD=LAST UNION=(`mrg`.`t1`)
+ ALTER TABLE t1 ROW_FORMAT=PAGE;
+ SHOW CREATE TABLE t1;
+ Table Create Table
+ t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL,
+ `b` char(8) DEFAULT NULL
+-) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 ROW_FORMAT=PAGE
++) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 ROW_FORMAT=PAGE INSERT_METHOD=LAST UNION=(`mrg`.`t1`)
+ ALTER TABLE t1 ROW_FORMAT=COMPACT;
+ SHOW CREATE TABLE t1;
+ Table Create Table
+ t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL,
+ `b` char(8) DEFAULT NULL
+-) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT
++) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT INSERT_METHOD=LAST UNION=(`mrg`.`t1`)
+ DROP TABLE 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 00000000..e4e098a1
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/tbl_opt_union.rdiff
@@ -0,0 +1,16 @@
+--- tbl_opt_union.result 2013-01-22 22:05:05.246633000 +0400
++++ tbl_opt_union.reject 2013-01-23 02:51:05.375430573 +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 INSERT_METHOD=LAST UNION=(`child1`)
+ 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 INSERT_METHOD=LAST UNION=(`child1`,`child2`)
+ DROP TABLE t1, 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 00000000..a929b6df
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/tbl_standard_opts.rdiff
@@ -0,0 +1,19 @@
+--- tbl_standard_opts.result 2013-01-22 22:05:05.246633000 +0400
++++ tbl_standard_opts.reject 2013-01-23 02:51:05.991422829 +0400
+@@ -8,14 +8,14 @@
+ t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL,
+ `b` char(8) DEFAULT NULL
+-) 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'
+ ALTER TABLE t1 COMMENT = 'table altered';
+ SHOW CREATE TABLE t1;
+ Table Create Table
+ t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL,
+ `b` char(8) DEFAULT NULL
+-) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=utf8 COMMENT='table altered'
++) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=utf8 INSERT_METHOD=LAST UNION=(`mrg`.`t1`) COMMENT='table altered'
+ ALTER TABLE t1 ENGINE=MEMORY;
+ SHOW CREATE TABLE t1;
+ Table Create Table
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 00000000..d2c7d4f2
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/tbl_temporary.rdiff
@@ -0,0 +1,10 @@
+--- tbl_temporary.result 2013-01-22 22:05:05.246633000 +0400
++++ tbl_temporary.reject 2013-01-23 02:51:06.599415185 +0400
+@@ -6,6 +6,6 @@
+ t1 CREATE TEMPORARY TABLE `t1` (
+ `a` int(11) DEFAULT NULL,
+ `b` char(8) DEFAULT NULL
+-) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1
++) ENGINE=<STORAGE_ENGINE> DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(`mrg`.`t1`)
+ DROP TEMPORARY TABLE t1;
+ DROP TABLE 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 00000000..e429bbdb
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/truncate_table.rdiff
@@ -0,0 +1,48 @@
+--- truncate_table.result 2013-01-22 22:05:05.246633000 +0400
++++ truncate_table.reject 2013-01-23 02:51:07.507403770 +0400
+@@ -9,19 +9,19 @@
+ CREATE TABLE t1 (a <INT_COLUMN> KEY AUTO_INCREMENT, c <CHAR_COLUMN>) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+ SHOW TABLE STATUS LIKE 't1';
+ Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment Max_index_length Temporary
+-t1 # # # # # # # # # 1 # # # # # # # # N
++t1 # # # # # # # # # 0 # # # # # # # # N
+ INSERT INTO t1 (c) VALUES ('a'),('b'),('c');
+ SHOW TABLE STATUS LIKE 't1';
+ Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment Max_index_length Temporary
+-t1 # # # # # # # # # 4 # # # # # # # # N
++t1 # # # # # # # # # 0 # # # # # # # # N
+ TRUNCATE TABLE t1;
+ SHOW TABLE STATUS LIKE 't1';
+ Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment Max_index_length Temporary
+-t1 # # # # # # # # # 1 # # # # # # # # N
++t1 # # # # # # # # # 0 # # # # # # # # N
+ INSERT INTO t1 (c) VALUES ('d');
+ SHOW TABLE STATUS LIKE 't1';
+ Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment Max_index_length Temporary
+-t1 # # # # # # # # # 2 # # # # # # # # N
++t1 # # # # # # # # # 0 # # # # # # # # N
+ SELECT a,c FROM t1;
+ a c
+ 1 d
+@@ -29,13 +29,12 @@
+ 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');
+ HANDLER t1 OPEN AS h1;
+-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: Storage engine MRG_MyISAM of the table `test`.`t1` 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).
++# -------------------------------------------
+ DROP TABLE t1;
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 00000000..94cfa74f
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/trx/cons_snapshot_repeatable_read.rdiff
@@ -0,0 +1,20 @@
+--- cons_snapshot_repeatable_read.result 2013-01-22 22:05:05.246633000 +0400
++++ cons_snapshot_repeatable_read.reject 2013-01-23 03:22:34.255684132 +0400
+@@ -1,3 +1,9 @@
++# -- 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.
++# ---------------------------------------------------------------------------
+ DROP TABLE IF EXISTS t1;
+ connect con1,localhost,root,,;
+ connect con2,localhost,root,,;
+@@ -11,6 +17,7 @@
+ # If consistent read works on this isolation level (REPEATABLE READ), the following SELECT should not return the value we inserted (1)
+ SELECT a FROM t1;
+ a
++1
+ COMMIT;
+ connection default;
+ disconnect con1;
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 00000000..a9b9ba7f
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/trx/cons_snapshot_serializable.rdiff
@@ -0,0 +1,20 @@
+--- cons_snapshot_serializable.result 2013-01-22 22:05:05.246633000 +0400
++++ cons_snapshot_serializable.reject 2013-01-23 03:22:34.847676690 +0400
+@@ -1,3 +1,9 @@
++# -- 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.
++# ---------------------------------------------------------------------------
+ DROP TABLE IF EXISTS t1;
+ connect con1,localhost,root,,;
+ connect con2,localhost,root,,;
+@@ -11,6 +17,7 @@
+ # If consistent read works on this isolation level (SERIALIZABLE), the following SELECT should not return the value we inserted (1)
+ SELECT a FROM t1;
+ a
++1
+ COMMIT;
+ connection default;
+ disconnect con1;
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 00000000..e4249478
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/trx/delete.rdiff
@@ -0,0 +1,50 @@
+--- delete.result 2013-01-22 22:05:05.246633000 +0400
++++ delete.reject 2013-01-23 03:22:35.419669500 +0400
+@@ -1,3 +1,15 @@
++# -- 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.
++# ---------------------------------------------------------------------------
+ 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 a,b 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/myisammrg/mysql-test/storage_engine/trx/insert.rdiff b/storage/myisammrg/mysql-test/storage_engine/trx/insert.rdiff
new file mode 100644
index 00000000..d5e99b6d
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/trx/insert.rdiff
@@ -0,0 +1,65 @@
+--- insert.result 2013-01-22 22:05:05.246633000 +0400
++++ insert.reject 2013-01-23 03:22:35.987662359 +0400
+@@ -1,3 +1,15 @@
++# -- 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.
++# ---------------------------------------------------------------------------
+ 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 a,b 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 a,b 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/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 00000000..9e7c340c
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/trx/level_read_committed.rdiff
@@ -0,0 +1,94 @@
+--- level_read_committed.result 2013-01-22 22:05:05.246633000 +0400
++++ level_read_committed.reject 2013-01-23 03:22:36.603654615 +0400
+@@ -1,3 +1,9 @@
++# -- 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.
++# ---------------------------------------------------------------------------
+ DROP TABLE IF EXISTS t1;
+ connect con1,localhost,root,,;
+ SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
+@@ -16,6 +22,7 @@
+ connection con1;
+ SELECT a FROM t1;
+ a
++1
+ connection con2;
+ INSERT INTO t1 (a) VALUES (2);
+ # WARNING: Statement ended with errno 0, errname ''.
+@@ -23,25 +30,37 @@
+ connection con1;
+ SELECT a FROM t1;
+ a
++1
++2
+ INSERT INTO t1 (a) SELECT a+100 FROM t1;
+ # WARNING: Statement ended with errno 0, errname ''.
+ # If it differs from the result file, it might indicate a problem.
+ SELECT a FROM t1;
+ a
++1
++101
++102
++2
+ connection con2;
+ SELECT a FROM t1;
+ a
+ 1
++101
++102
+ 2
+ COMMIT;
+ SELECT a FROM t1;
+ a
+ 1
++101
++102
+ 2
+ connection con1;
+ SELECT a FROM t1;
+ a
+ 1
++101
++102
+ 2
+ INSERT INTO t1 (a) SELECT a+200 FROM t1;
+ # WARNING: Statement ended with errno 0, errname ''.
+@@ -49,23 +68,35 @@
+ SELECT a FROM t1;
+ a
+ 1
++101
++102
+ 2
+ 201
+ 202
++301
++302
+ COMMIT;
+ SELECT a FROM t1;
+ a
+ 1
++101
++102
+ 2
+ 201
+ 202
++301
++302
+ connection con2;
+ SELECT a FROM t1;
+ a
+ 1
++101
++102
+ 2
+ 201
+ 202
++301
++302
+ connection default;
+ disconnect con1;
+ disconnect con2;
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 00000000..d44e4aa7
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/trx/level_read_uncommitted.rdiff
@@ -0,0 +1,12 @@
+--- level_read_uncommitted.result 2013-01-22 22:05:05.246633000 +0400
++++ level_read_uncommitted.reject 2013-01-23 03:22:37.263646318 +0400
+@@ -1,3 +1,9 @@
++# -- 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.
++# ---------------------------------------------------------------------------
+ DROP TABLE IF EXISTS t1;
+ connect con1,localhost,root,,;
+ SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
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 00000000..b24376a9
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/trx/level_repeatable_read.rdiff
@@ -0,0 +1,96 @@
+--- level_repeatable_read.result 2013-01-22 22:05:05.246633000 +0400
++++ level_repeatable_read.reject 2013-01-23 03:22:37.867638724 +0400
+@@ -1,3 +1,9 @@
++# -- 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.
++# ---------------------------------------------------------------------------
+ DROP TABLE IF EXISTS t1;
+ connect con1,localhost,root,,;
+ SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
+@@ -16,6 +22,7 @@
+ connection con1;
+ SELECT a FROM t1;
+ a
++1
+ connection con2;
+ INSERT INTO t1 (a) VALUES (2);
+ # WARNING: Statement ended with errno 0, errname ''.
+@@ -23,46 +30,73 @@
+ connection con1;
+ SELECT a FROM t1;
+ a
++1
++2
+ INSERT INTO t1 (a) SELECT a+100 FROM t1;
+-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 ''.
+ # If it differs from the result file, it might indicate a problem.
+ SELECT a FROM t1;
+ a
++1
++101
++102
++2
+ connection con2;
+ SELECT a FROM t1;
+ a
+ 1
++101
++102
+ 2
+ COMMIT;
+ SELECT a FROM t1;
+ a
+ 1
++101
++102
+ 2
+ connection con1;
+ SELECT a FROM t1;
+ a
++1
++101
++102
++2
+ INSERT INTO t1 (a) SELECT a+200 FROM t1;
+ # WARNING: Statement ended with errno 0, errname ''.
+ # If it differs from the result file, it might indicate a problem.
+ SELECT a FROM t1;
+ a
++1
++101
++102
++2
+ 201
+ 202
++301
++302
+ COMMIT;
+ SELECT a FROM t1;
+ a
+ 1
++101
++102
+ 2
+ 201
+ 202
++301
++302
+ connection con2;
+ SELECT a FROM t1;
+ a
+ 1
++101
++102
+ 2
+ 201
+ 202
++301
++302
+ connection default;
+ disconnect con1;
+ disconnect con2;
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 00000000..3567e718
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/trx/level_serializable.rdiff
@@ -0,0 +1,103 @@
+--- level_serializable.result 2013-01-22 22:05:05.246633000 +0400
++++ level_serializable.reject 2013-01-23 03:22:38.471631132 +0400
+@@ -1,3 +1,9 @@
++# -- 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.
++# ---------------------------------------------------------------------------
+ DROP TABLE IF EXISTS t1;
+ connect con1,localhost,root,,;
+ SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
+@@ -11,45 +17,86 @@
+ connection con2;
+ BEGIN;
+ INSERT INTO t1 (a) VALUES(1);
+-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 ''.
+ # If it differs from the result file, it might indicate a problem.
+ connection con1;
+ SELECT a FROM t1;
+ a
++1
+ connection con2;
+ INSERT INTO t1 (a) VALUES (2);
+-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 ''.
+ # If it differs from the result file, it might indicate a problem.
+ connection con1;
+ SELECT a FROM t1;
+ a
++1
++2
+ INSERT INTO t1 (a) SELECT a+100 FROM t1;
+ # WARNING: Statement ended with errno 0, errname ''.
+ # If it differs from the result file, it might indicate a problem.
+ SELECT a FROM t1;
+ a
++1
++101
++102
++2
+ connection con2;
+ SELECT a FROM t1;
+ a
++1
++101
++102
++2
+ COMMIT;
+ SELECT a FROM t1;
+ a
++1
++101
++102
++2
+ connection con1;
+ SELECT a FROM t1;
+ a
++1
++101
++102
++2
+ INSERT INTO t1 (a) SELECT a+200 FROM t1;
+ # WARNING: Statement ended with errno 0, errname ''.
+ # If it differs from the result file, it might indicate a problem.
+ SELECT a FROM t1;
+ a
++1
++101
++102
++2
++201
++202
++301
++302
+ COMMIT;
+ SELECT a FROM t1;
+ a
++1
++101
++102
++2
++201
++202
++301
++302
+ connection con2;
+ SELECT a FROM t1;
+ a
++1
++101
++102
++2
++201
++202
++301
++302
+ connection default;
+ disconnect con1;
+ disconnect con2;
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 00000000..bad014d8
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/trx/select_for_update.rdiff
@@ -0,0 +1,50 @@
+--- select_for_update.result 2013-01-22 22:05:05.246633000 +0400
++++ select_for_update.reject 2013-01-23 03:22:39.123622935 +0400
+@@ -1,3 +1,9 @@
++# -- 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.
++# ---------------------------------------------------------------------------
+ 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 a,b 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 a,b 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/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 00000000..db3eec1b
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/trx/select_lock_in_share_mode.rdiff
@@ -0,0 +1,37 @@
+--- select_lock_in_share_mode.result 2013-01-22 22:05:05.246633000 +0400
++++ select_lock_in_share_mode.reject 2013-01-23 03:22:39.739615191 +0400
+@@ -1,3 +1,9 @@
++# -- 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.
++# ---------------------------------------------------------------------------
+ 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 a,b 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/myisammrg/mysql-test/storage_engine/trx/update.rdiff b/storage/myisammrg/mysql-test/storage_engine/trx/update.rdiff
new file mode 100644
index 00000000..baac0547
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/trx/update.rdiff
@@ -0,0 +1,58 @@
+--- update.result 2013-01-22 22:05:05.246633000 +0400
++++ update.reject 2013-01-23 03:22:40.355607446 +0400
+@@ -1,3 +1,15 @@
++# -- 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.
++# ---------------------------------------------------------------------------
+ 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 a,b 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/myisammrg/mysql-test/storage_engine/trx/xa.rdiff b/storage/myisammrg/mysql-test/storage_engine/trx/xa.rdiff
new file mode 100644
index 00000000..a4912873
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/trx/xa.rdiff
@@ -0,0 +1,89 @@
+--- xa.result 2013-01-22 22:05:05.246633000 +0400
++++ xa.reject 2013-01-23 03:22:41.047598747 +0400
+@@ -1,3 +1,9 @@
++# -- 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.
++# ---------------------------------------------------------------------------
+ DROP TABLE IF EXISTS t1;
+ connect con1,localhost,root,,;
+ connect con2,localhost,root,,;
+@@ -9,17 +15,22 @@
+ connection con1;
+ SELECT a FROM t1;
+ a
++1
+ connection con2;
+ INSERT INTO t1 (a) VALUES (2);
+ XA END 'xa1';
+ connection con1;
+ SELECT a FROM t1;
+ a
++1
++2
+ connection con2;
+ XA PREPARE 'xa1';
+ connection con1;
+ SELECT a 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 a FROM t1;
+ a
+@@ -93,4 +114,6 @@
+ 2
+ 3
+ 4
++5
++6
+ DROP TABLE t1;
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 00000000..fa920abe
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/trx/xa_recovery.rdiff
@@ -0,0 +1,32 @@
+--- xa_recovery.result 2013-01-22 22:05:05.246633000 +0400
++++ xa_recovery.reject 2013-01-23 03:22:43.247571090 +0400
+@@ -1,3 +1,9 @@
++# -- 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.
++# ---------------------------------------------------------------------------
+ call mtr.add_suppression("Found 2 prepared XA transactions");
+ FLUSH TABLES;
+ DROP TABLE IF EXISTS t1;
+@@ -18,12 +24,17 @@
+ 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 a FROM t1;
+ a
++1
++2
+ 3
+ 4
++Warnings:
++Error 145 Table './mrg/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/mysql-test/storage_engine/type_char_indexes.rdiff b/storage/myisammrg/mysql-test/storage_engine/type_char_indexes.rdiff
new file mode 100644
index 00000000..797907fa
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/type_char_indexes.rdiff
@@ -0,0 +1,20 @@
+--- suite/storage_engine/type_char_indexes.result 2014-10-12 14:22:11.000000000 +0400
++++ suite/storage_engine/type_char_indexes.reject 2014-10-12 14:22:41.000000000 +0400
+@@ -100,7 +100,7 @@
+ Warning 1681 'engine_condition_pushdown=on' is deprecated and will be removed in a future release.
+ EXPLAIN SELECT c,c20,v16,v128 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
++# # # ALL c_v NULL # # # Using where
+ SELECT c,c20,v16,v128 FROM t1 WHERE c > 'a';
+ c c20 v16 v128
+ b char3 varchar1a varchar1b
+@@ -137,7 +137,7 @@
+ r3a
+ EXPLAIN SELECT c,c20,v16,v128 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 c,c20,v16,v128 FROM t1 WHERE v16 = 'varchar1a' OR v16 = 'varchar3a' ORDER BY v16;
+ c c20 v16 v128
+ a char1 varchar1a varchar1b
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 00000000..eb4da4db
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/type_float_indexes.rdiff
@@ -0,0 +1,11 @@
+--- type_float_indexes.result 2013-01-22 22:05:05.246633000 +0400
++++ type_float_indexes.reject 2013-01-23 02:51:13.059333973 +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/myisammrg/mysql-test/storage_engine/type_spatial.rdiff b/storage/myisammrg/mysql-test/storage_engine/type_spatial.rdiff
new file mode 100644
index 00000000..6f337ffb
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/type_spatial.rdiff
@@ -0,0 +1,712 @@
+--- suite/storage_engine/type_spatial.result 2013-08-05 17:52:53.000000000 +0400
++++ suite/storage_engine/type_spatial.reject 2013-08-05 17:56:37.000000000 +0400
+@@ -2,699 +2,15 @@
+ DROP DATABASE IF EXISTS gis_ogs;
+ CREATE DATABASE gis_ogs;
+ CREATE TABLE gis_point (fid <INT_COLUMN>, g POINT) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+-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 (fid,g) 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 (fid,g) 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 (fid,g) 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 (fid,g) 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 (fid,g) 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 (fid,g) 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 (fid,g) 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 (fid,g) SELECT fid,g FROM gis_point;
+-INSERT into gis_geometry (fid,g) SELECT fid,g FROM gis_line;
+-INSERT into gis_geometry (fid,g) SELECT fid,g FROM gis_polygon;
+-INSERT into gis_geometry (fid,g) SELECT fid,g FROM gis_multi_point;
+-INSERT into gis_geometry (fid,g) SELECT fid,g FROM gis_multi_line;
+-INSERT into gis_geometry (fid,g) SELECT fid,g FROM gis_multi_polygon;
+-INSERT into gis_geometry (fid,g) SELECT fid,g 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(57.98031067576927 17.854754130800433)
+-118 POINT(57.98031067576927 17.854754130800433)
+-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 0 1 0
+-120 121 0 0 1 0 0 0 1 0
+-120 122 NULL NULL NULL NULL NULL NULL NULL NULL
+-120 123 NULL NULL NULL NULL NULL NULL NULL NULL
+-121 120 0 0 1 0 0 0 1 0
+-121 121 1 1 0 1 0 0 1 0
+-121 122 NULL NULL NULL NULL NULL NULL NULL NULL
+-121 123 NULL NULL NULL NULL NULL NULL NULL NULL
+-122 120 NULL NULL NULL NULL NULL NULL NULL NULL
+-122 121 NULL NULL NULL NULL NULL NULL NULL NULL
+-122 122 NULL NULL NULL NULL NULL NULL NULL NULL
+-122 123 NULL NULL NULL NULL NULL NULL NULL NULL
+-123 120 NULL NULL NULL NULL NULL NULL NULL NULL
+-123 121 NULL NULL NULL NULL NULL NULL NULL NULL
+-123 122 NULL NULL NULL NULL NULL NULL NULL NULL
+-123 123 NULL NULL NULL NULL NULL NULL NULL NULL
+-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 (fid,name,shore) 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 (fid,name,aliases,num_lanes,centerline) VALUES(102, 'Route 5', NULL, 2,
+-LineFromText(
+-'LINESTRING( 0 18, 10 21, 16 23, 28 26, 44 31 )' ,101));
+-INSERT INTO road_segments (fid,name,aliases,num_lanes,centerline) VALUES(103, 'Route 5', 'Main Street', 4,
+-LineFromText(
+-'LINESTRING( 44 31, 56 34, 70 38 )' ,101));
+-INSERT INTO road_segments (fid,name,aliases,num_lanes,centerline) VALUES(104, 'Route 5', NULL, 2,
+-LineFromText(
+-'LINESTRING( 70 38, 72 48 )' ,101));
+-INSERT INTO road_segments (fid,name,aliases,num_lanes,centerline) VALUES(105, 'Main Street', NULL, 4,
+-LineFromText(
+-'LINESTRING( 70 38, 84 42 )' ,101));
+-INSERT INTO road_segments (fid,name,aliases,num_lanes,centerline) VALUES(106, 'Dirt Road by Green Forest', NULL,
+-1,
+-LineFromText(
+-'LINESTRING( 28 26, 28 0 )',101));
+-# DividedRoutes
+-INSERT INTO divided_routes (fid,name,num_lanes,centerlines) VALUES(119, 'Route 75', 4,
+-MLineFromText(
+-'MULTILINESTRING((10 48,10 21,10 0),
+- (16 0,16 23,16 48))', 101));
+-# Forests
+-INSERT INTO forests (fid,name,boundary) 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 (fid,name,position) VALUES(110, 'Cam Bridge', PointFromText(
+-'POINT( 44 31 )', 101));
+-# Streams
+-INSERT INTO streams (fid,name,centerline) VALUES(111, 'Cam Stream',
+-LineFromText(
+-'LINESTRING( 38 48, 44 41, 41 36, 44 31, 52 18 )', 101));
+-INSERT INTO streams (fid,name,centerline) VALUES(112, NULL,
+-LineFromText(
+-'LINESTRING( 76 0, 78 4, 73 9 )', 101));
+-# Buildings
+-INSERT INTO buildings (fid,name,position,footprint) 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 (fid,name,position,footprint) 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 (fid,name,type,shores) 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 (fid,name,boundary) VALUES(117, 'Ashton',
+-PolyFromText(
+-'POLYGON( ( 62 48, 84 48, 84 30, 56 30, 56 34, 62 48) )', 101));
+-INSERT INTO named_places (fid,name,boundary) VALUES(118, 'Goose Island',
+-PolyFromText(
+-'POLYGON( ( 67 13, 67 18, 59 18, 59 13, 67 13) )', 101));
+-# Map Neatlines
+-INSERT INTO map_neatlines (fid,neatline) 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).
++# -------------------------------------------
+ DROP DATABASE gis_ogs;
+ USE 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 00000000..04c56979
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/type_spatial_indexes.rdiff
@@ -0,0 +1,1422 @@
+--- suite/storage_engine/type_spatial_indexes.result 2013-08-05 18:08:49.000000000 +0400
++++ suite/storage_engine/type_spatial_indexes.reject 2013-08-05 18:27:47.000000000 +0400
+@@ -2,1399 +2,31 @@
+ DROP DATABASE IF EXISTS gis_ogs;
+ CREATE DATABASE gis_ogs;
+ CREATE TABLE gis_point (fid <INT_COLUMN>, g POINT, <CUSTOM_INDEX> g(g(128))) ENGINE=<STORAGE_ENGINE> <CUSTOM_TABLE_OPTIONS>;
+-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 (fid,g) 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 (fid,g) 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 (fid,g) 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 (fid,g) 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 (fid,g) 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 (fid,g) 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 (fid,g) 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 (fid,g) SELECT fid,g FROM gis_point;
+-INSERT into gis_geometry (fid,g) SELECT fid,g FROM gis_line;
+-INSERT into gis_geometry (fid,g) SELECT fid,g FROM gis_polygon;
+-INSERT into gis_geometry (fid,g) SELECT fid,g FROM gis_multi_point;
+-INSERT into gis_geometry (fid,g) SELECT fid,g FROM gis_multi_line;
+-INSERT into gis_geometry (fid,g) SELECT fid,g FROM gis_multi_polygon;
+-INSERT into gis_geometry (fid,g) SELECT fid,g 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(57.98031067576927 17.854754130800433)
+-118 POINT(57.98031067576927 17.854754130800433)
+-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 0 1 0
+-120 121 0 0 1 0 0 0 1 0
+-120 122 NULL NULL NULL NULL NULL NULL NULL NULL
+-120 123 NULL NULL NULL NULL NULL NULL NULL NULL
+-121 120 0 0 1 0 0 0 1 0
+-121 121 1 1 0 1 0 0 1 0
+-121 122 NULL NULL NULL NULL NULL NULL NULL NULL
+-121 123 NULL NULL NULL NULL NULL NULL NULL NULL
+-122 120 NULL NULL NULL NULL NULL NULL NULL NULL
+-122 121 NULL NULL NULL NULL NULL NULL NULL NULL
+-122 122 NULL NULL NULL NULL NULL NULL NULL NULL
+-122 123 NULL NULL NULL NULL NULL NULL NULL NULL
+-123 120 NULL NULL NULL NULL NULL NULL NULL NULL
+-123 121 NULL NULL NULL NULL NULL NULL NULL NULL
+-123 122 NULL NULL NULL NULL NULL NULL NULL NULL
+-123 123 NULL NULL NULL NULL NULL NULL NULL NULL
+-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 (fid,name,shore) 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 (fid,name,aliases,num_lanes,centerline) VALUES(102, 'Route 5', NULL, 2,
+-LineFromText(
+-'LINESTRING( 0 18, 10 21, 16 23, 28 26, 44 31 )' ,101));
+-INSERT INTO road_segments (fid,name,aliases,num_lanes,centerline) VALUES(103, 'Route 5', 'Main Street', 4,
+-LineFromText(
+-'LINESTRING( 44 31, 56 34, 70 38 )' ,101));
+-INSERT INTO road_segments (fid,name,aliases,num_lanes,centerline) VALUES(104, 'Route 5', NULL, 2,
+-LineFromText(
+-'LINESTRING( 70 38, 72 48 )' ,101));
+-INSERT INTO road_segments (fid,name,aliases,num_lanes,centerline) VALUES(105, 'Main Street', NULL, 4,
+-LineFromText(
+-'LINESTRING( 70 38, 84 42 )' ,101));
+-INSERT INTO road_segments (fid,name,aliases,num_lanes,centerline) VALUES(106, 'Dirt Road by Green Forest', NULL,
+-1,
+-LineFromText(
+-'LINESTRING( 28 26, 28 0 )',101));
+-# DividedRoutes
+-INSERT INTO divided_routes (fid,name,num_lanes,centerlines) VALUES(119, 'Route 75', 4,
+-MLineFromText(
+-'MULTILINESTRING((10 48,10 21,10 0),
+- (16 0,16 23,16 48))', 101));
+-# Forests
+-INSERT INTO forests (fid,name,boundary) 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 (fid,name,position) VALUES(110, 'Cam Bridge', PointFromText(
+-'POINT( 44 31 )', 101));
+-# Streams
+-INSERT INTO streams (fid,name,centerline) VALUES(111, 'Cam Stream',
+-LineFromText(
+-'LINESTRING( 38 48, 44 41, 41 36, 44 31, 52 18 )', 101));
+-INSERT INTO streams (fid,name,centerline) VALUES(112, NULL,
+-LineFromText(
+-'LINESTRING( 76 0, 78 4, 73 9 )', 101));
+-# Buildings
+-INSERT INTO buildings (fid,name,position,footprint) 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 (fid,name,position,footprint) 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 (fid,name,type,shores) 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 (fid,name,boundary) VALUES(117, 'Ashton',
+-PolyFromText(
+-'POLYGON( ( 62 48, 84 48, 84 30, 56 30, 56 34, 62 48) )', 101));
+-INSERT INTO named_places (fid,name,boundary) VALUES(118, 'Goose Island',
+-PolyFromText(
+-'POLYGON( ( 67 13, 67 18, 59 18, 59 13, 67 13) )', 101));
+-# Map Neatlines
+-INSERT INTO map_neatlines (fid,neatline) 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).
++# -------------------------------------------
+ DROP DATABASE gis_ogs;
+ USE test;
+ DROP TABLE IF EXISTS t1, gis_point, gis_line, gis_polygon, gis_multi_point, gis_multi_line, gis_multi_polygon, gis_geometrycollection, gis_geometry;
+ 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 (fid,g) 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 (fid,g) 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 (fid,g) 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 (fid,g) 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 (fid,g) 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 (fid,g) 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 (fid,g) 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 (fid,g) SELECT fid,g FROM gis_point;
+-INSERT into gis_geometry (fid,g) SELECT fid,g FROM gis_line;
+-INSERT into gis_geometry (fid,g) SELECT fid,g FROM gis_polygon;
+-INSERT into gis_geometry (fid,g) SELECT fid,g FROM gis_multi_point;
+-INSERT into gis_geometry (fid,g) SELECT fid,g FROM gis_multi_line;
+-INSERT into gis_geometry (fid,g) SELECT fid,g FROM gis_multi_polygon;
+-INSERT into gis_geometry (fid,g) SELECT fid,g 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(57.98031067576927 17.854754130800433)
+-118 POINT(57.98031067576927 17.854754130800433)
+-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 0 1 0
+-120 121 0 0 1 0 0 0 1 0
+-120 122 NULL NULL NULL NULL NULL NULL NULL NULL
+-120 123 NULL NULL NULL NULL NULL NULL NULL NULL
+-121 120 0 0 1 0 0 0 1 0
+-121 121 1 1 0 1 0 0 1 0
+-121 122 NULL NULL NULL NULL NULL NULL NULL NULL
+-121 123 NULL NULL NULL NULL NULL NULL NULL NULL
+-122 120 NULL NULL NULL NULL NULL NULL NULL NULL
+-122 121 NULL NULL NULL NULL NULL NULL NULL NULL
+-122 122 NULL NULL NULL NULL NULL NULL NULL NULL
+-122 123 NULL NULL NULL NULL NULL NULL NULL NULL
+-123 120 NULL NULL NULL NULL NULL NULL NULL NULL
+-123 121 NULL NULL NULL NULL NULL NULL NULL NULL
+-123 122 NULL NULL NULL NULL NULL NULL NULL NULL
+-123 123 NULL NULL NULL NULL NULL NULL NULL NULL
+-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 (fid,name,shore) 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 (fid,name,aliases,num_lanes,centerline) VALUES(102, 'Route 5', NULL, 2,
+-LineFromText(
+-'LINESTRING( 0 18, 10 21, 16 23, 28 26, 44 31 )' ,101));
+-INSERT INTO road_segments (fid,name,aliases,num_lanes,centerline) VALUES(103, 'Route 5', 'Main Street', 4,
+-LineFromText(
+-'LINESTRING( 44 31, 56 34, 70 38 )' ,101));
+-INSERT INTO road_segments (fid,name,aliases,num_lanes,centerline) VALUES(104, 'Route 5', NULL, 2,
+-LineFromText(
+-'LINESTRING( 70 38, 72 48 )' ,101));
+-INSERT INTO road_segments (fid,name,aliases,num_lanes,centerline) VALUES(105, 'Main Street', NULL, 4,
+-LineFromText(
+-'LINESTRING( 70 38, 84 42 )' ,101));
+-INSERT INTO road_segments (fid,name,aliases,num_lanes,centerline) VALUES(106, 'Dirt Road by Green Forest', NULL,
+-1,
+-LineFromText(
+-'LINESTRING( 28 26, 28 0 )',101));
+-# DividedRoutes
+-INSERT INTO divided_routes (fid,name,num_lanes,centerlines) VALUES(119, 'Route 75', 4,
+-MLineFromText(
+-'MULTILINESTRING((10 48,10 21,10 0),
+- (16 0,16 23,16 48))', 101));
+-# Forests
+-INSERT INTO forests (fid,name,boundary) 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 (fid,name,position) VALUES(110, 'Cam Bridge', PointFromText(
+-'POINT( 44 31 )', 101));
+-# Streams
+-INSERT INTO streams (fid,name,centerline) VALUES(111, 'Cam Stream',
+-LineFromText(
+-'LINESTRING( 38 48, 44 41, 41 36, 44 31, 52 18 )', 101));
+-INSERT INTO streams (fid,name,centerline) VALUES(112, NULL,
+-LineFromText(
+-'LINESTRING( 76 0, 78 4, 73 9 )', 101));
+-# Buildings
+-INSERT INTO buildings (fid,name,position,footprint) 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 (fid,name,position,footprint) 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 (fid,name,type,shores) 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 (fid,name,boundary) VALUES(117, 'Ashton',
+-PolyFromText(
+-'POLYGON( ( 62 48, 84 48, 84 30, 56 30, 56 34, 62 48) )', 101));
+-INSERT INTO named_places (fid,name,boundary) VALUES(118, 'Goose Island',
+-PolyFromText(
+-'POLYGON( ( 67 13, 67 18, 59 18, 59 13, 67 13) )', 101));
+-# Map Neatlines
+-INSERT INTO map_neatlines (fid,neatline) 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).
++# -------------------------------------------
+ DROP DATABASE gis_ogs;
+ USE 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 00000000..6c4971c6
--- /dev/null
+++ b/storage/myisammrg/mysql-test/storage_engine/vcol.rdiff
@@ -0,0 +1,82 @@
+--- vcol.result 2013-01-22 22:05:05.246633000 +0400
++++ vcol.reject 2013-01-23 02:51:26.851160587 +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 GENERATED
+-INSERT INTO t1 (a) VALUES (1),(2);
+-INSERT INTO t1 (a,b) VALUES (3,3),(4,4);
+-Warnings:
+-Warning 1906 The value specified for generated column 'b' in table 't1' has been ignored
+-Warning 1906 The value specified for generated column 'b' in table 't1' has been ignored
+-SELECT a,b 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) # # STORED GENERATED
+-INSERT INTO t1 (a) VALUES (1),(2);
+-INSERT INTO t1 (a,b) VALUES (3,3),(4,4);
+-Warnings:
+-Warning 1906 The value specified for generated column 'b' in table 't1' has been ignored
+-Warning 1906 The value specified for generated column 'b' in table 't1' has been ignored
+-SELECT a,b 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 GENERATED
+-INSERT INTO t1 (a) VALUES (1),(2);
+-INSERT INTO t1 (a,b) VALUES (3,3),(4,4);
+-Warnings:
+-Warning 1906 The value specified for generated column 'b' in table 't1' has been ignored
+-Warning 1906 The value specified for generated column 'b' in table 't1' has been ignored
+-SELECT a,b 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) # # STORED GENERATED
+-INSERT INTO t1 (a) VALUES (1),(2);
+-INSERT INTO t1 (a,b) VALUES (3,3),(4,4);
+-Warnings:
+-Warning 1906 The value specified for generated column 'b' in table 't1' has been ignored
+-Warning 1906 The value specified for generated column 'b' in table 't1' has been ignored
+-SELECT a,b FROM t1;
+-a b
+-1 2
+-2 3
+-3 4
+-4 5
+-DROP TABLE t1;
++ERROR HY000: MRG_MyISAM storage engine does not support generated columns
++# ERROR: Statement ended with errno 1910, errname ER_UNSUPPORTED_ENGINE_FOR_GENERATED_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_GENERATED_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).
++# -------------------------------------------