summaryrefslogtreecommitdiff
path: root/storage/myisammrg
diff options
context:
space:
mode:
Diffstat (limited to 'storage/myisammrg')
-rw-r--r--storage/myisammrg/.cvsignore3
-rw-r--r--storage/myisammrg/CMakeLists.txt13
-rw-r--r--storage/myisammrg/Makefile.am45
-rw-r--r--storage/myisammrg/ha_myisammrg.cc607
-rw-r--r--storage/myisammrg/ha_myisammrg.h88
-rwxr-xr-xstorage/myisammrg/make-ccc3
-rw-r--r--storage/myisammrg/myrg_close.c40
-rw-r--r--storage/myisammrg/myrg_create.c73
-rw-r--r--storage/myisammrg/myrg_def.h33
-rw-r--r--storage/myisammrg/myrg_delete.c27
-rw-r--r--storage/myisammrg/myrg_extra.c88
-rw-r--r--storage/myisammrg/myrg_info.c68
-rw-r--r--storage/myisammrg/myrg_locking.c44
-rw-r--r--storage/myisammrg/myrg_open.c179
-rw-r--r--storage/myisammrg/myrg_panic.c46
-rw-r--r--storage/myisammrg/myrg_queue.c81
-rw-r--r--storage/myisammrg/myrg_range.c36
-rw-r--r--storage/myisammrg/myrg_rfirst.c49
-rw-r--r--storage/myisammrg/myrg_rkey.c94
-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.c30
-rw-r--r--storage/myisammrg/myrg_update.c27
-rw-r--r--storage/myisammrg/myrg_write.c30
-rw-r--r--storage/myisammrg/plug.in6
29 files changed, 2062 insertions, 0 deletions
diff --git a/storage/myisammrg/.cvsignore b/storage/myisammrg/.cvsignore
new file mode 100644
index 00000000000..e9955884756
--- /dev/null
+++ b/storage/myisammrg/.cvsignore
@@ -0,0 +1,3 @@
+.deps
+Makefile
+Makefile.in
diff --git a/storage/myisammrg/CMakeLists.txt b/storage/myisammrg/CMakeLists.txt
new file mode 100644
index 00000000000..a86eff9d764
--- /dev/null
+++ b/storage/myisammrg/CMakeLists.txt
@@ -0,0 +1,13 @@
+SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX")
+SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX")
+
+INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/zlib
+ ${CMAKE_SOURCE_DIR}/sql
+ ${CMAKE_SOURCE_DIR}/regex
+ ${CMAKE_SOURCE_DIR}/extra/yassl/include)
+ADD_LIBRARY(myisammrg 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)
diff --git a/storage/myisammrg/Makefile.am b/storage/myisammrg/Makefile.am
new file mode 100644
index 00000000000..2008cc62559
--- /dev/null
+++ b/storage/myisammrg/Makefile.am
@@ -0,0 +1,45 @@
+# Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+MYSQLDATAdir = $(localstatedir)
+MYSQLSHAREdir = $(pkgdatadir)
+MYSQLBASEdir= $(prefix)
+MYSQLLIBdir= $(pkglibdir)
+INCLUDES = -I$(top_srcdir)/include -I$(top_builddir)/include \
+ -I$(top_srcdir)/regex \
+ -I$(top_srcdir)/sql \
+ -I$(srcdir)
+WRAPLIBS=
+
+LDADD =
+
+DEFS = @DEFS@
+pkglib_LIBRARIES = libmyisammrg.a
+noinst_HEADERS = myrg_def.h ha_myisammrg.h
+noinst_LIBRARIES = libmyisammrg.a
+libmyisammrg_a_SOURCES = myrg_open.c myrg_extra.c myrg_info.c myrg_locking.c \
+ myrg_rrnd.c myrg_update.c myrg_delete.c myrg_rsame.c \
+ myrg_panic.c myrg_close.c myrg_create.c myrg_static.c \
+ myrg_rkey.c myrg_rfirst.c myrg_rlast.c myrg_rnext.c \
+ myrg_rprev.c myrg_queue.c myrg_write.c myrg_range.c \
+ ha_myisammrg.cc \
+ myrg_rnext_same.c
+
+
+EXTRA_DIST = CMakeLists.txt plug.in
+
+# Don't update the files from bitkeeper
+%::SCCS/s.%
diff --git a/storage/myisammrg/ha_myisammrg.cc b/storage/myisammrg/ha_myisammrg.cc
new file mode 100644
index 00000000000..9637173a3ad
--- /dev/null
+++ b/storage/myisammrg/ha_myisammrg.cc
@@ -0,0 +1,607 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+
+#ifdef USE_PRAGMA_IMPLEMENTATION
+#pragma implementation // gcc: Class implementation
+#endif
+
+#define MYSQL_SERVER 1
+#include "mysql_priv.h"
+#include <mysql/plugin.h>
+#include <m_ctype.h>
+#include "ha_myisammrg.h"
+#include "myrg_def.h"
+
+
+/*****************************************************************************
+** MyISAM MERGE tables
+*****************************************************************************/
+
+static handler *myisammrg_create_handler(TABLE_SHARE *table,
+ MEM_ROOT *mem_root);
+
+static handler *myisammrg_create_handler(handlerton *hton,
+ TABLE_SHARE *table,
+ MEM_ROOT *mem_root)
+{
+ return new (mem_root) ha_myisammrg(hton, table);
+}
+
+
+ha_myisammrg::ha_myisammrg(handlerton *hton, TABLE_SHARE *table_arg)
+ :handler(hton, table_arg), file(0)
+{}
+
+static const char *ha_myisammrg_exts[] = {
+ ".MRG",
+ NullS
+};
+
+const char **ha_myisammrg::bas_ext() const
+{
+ return ha_myisammrg_exts;
+}
+
+
+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");
+}
+
+
+int ha_myisammrg::open(const char *name, int mode, uint test_if_locked)
+{
+ char name_buff[FN_REFLEN];
+
+ DBUG_PRINT("info", ("ha_myisammrg::open"));
+ if (!(file=myrg_open(fn_format(name_buff,name,"","",
+ MY_UNPACK_FILENAME|MY_APPEND_EXT),
+ mode, test_if_locked)))
+ {
+ DBUG_PRINT("info", ("ha_myisammrg::open exit %d", my_errno));
+ return (my_errno ? my_errno : -1);
+ }
+ DBUG_PRINT("info", ("ha_myisammrg::open 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);
+
+ 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));
+ goto err;
+ }
+#if !defined(BIG_TABLES) || SIZEOF_OFF_T == 4
+ /* Merge table has more than 2G rows */
+ if (table->s->crashed)
+ goto err;
+#endif
+ return (0);
+err:
+ myrg_close(file);
+ file=0;
+ return (my_errno= HA_ERR_WRONG_MRG_TABLE_DEF);
+}
+
+int ha_myisammrg::close(void)
+{
+ return myrg_close(file);
+}
+
+int ha_myisammrg::write_row(byte * buf)
+{
+ statistic_increment(table->in_use->status_var.ha_write_count,&LOCK_status);
+
+ if (file->merge_insert_method == MERGE_INSERT_DISABLED || !file->tables)
+ return (HA_ERR_TABLE_READONLY);
+
+ if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT)
+ table->timestamp_field->set_time();
+ if (table->next_number_field && buf == table->record[0])
+ {
+ int error;
+ if ((error= update_auto_increment()))
+ return error;
+ }
+ return myrg_write(file,buf);
+}
+
+int ha_myisammrg::update_row(const byte * old_data, byte * new_data)
+{
+ statistic_increment(table->in_use->status_var.ha_update_count,&LOCK_status);
+ if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE)
+ table->timestamp_field->set_time();
+ return myrg_update(file,old_data,new_data);
+}
+
+int ha_myisammrg::delete_row(const byte * buf)
+{
+ statistic_increment(table->in_use->status_var.ha_delete_count,&LOCK_status);
+ return myrg_delete(file,buf);
+}
+
+int ha_myisammrg::index_read(byte * buf, const byte * key,
+ uint key_len, enum ha_rkey_function find_flag)
+{
+ statistic_increment(table->in_use->status_var.ha_read_key_count,
+ &LOCK_status);
+ int error=myrg_rkey(file,buf,active_index, key, key_len, find_flag);
+ table->status=error ? STATUS_NOT_FOUND: 0;
+ return error;
+}
+
+int ha_myisammrg::index_read_idx(byte * buf, uint index, const byte * key,
+ uint key_len, enum ha_rkey_function find_flag)
+{
+ statistic_increment(table->in_use->status_var.ha_read_key_count,
+ &LOCK_status);
+ int error=myrg_rkey(file,buf,index, key, key_len, find_flag);
+ table->status=error ? STATUS_NOT_FOUND: 0;
+ return error;
+}
+
+int ha_myisammrg::index_read_last(byte * buf, const byte * key, uint key_len)
+{
+ statistic_increment(table->in_use->status_var.ha_read_key_count,
+ &LOCK_status);
+ int error=myrg_rkey(file,buf,active_index, key, key_len,
+ HA_READ_PREFIX_LAST);
+ table->status=error ? STATUS_NOT_FOUND: 0;
+ return error;
+}
+
+int ha_myisammrg::index_next(byte * buf)
+{
+ statistic_increment(table->in_use->status_var.ha_read_next_count,
+ &LOCK_status);
+ int error=myrg_rnext(file,buf,active_index);
+ table->status=error ? STATUS_NOT_FOUND: 0;
+ return error;
+}
+
+int ha_myisammrg::index_prev(byte * buf)
+{
+ statistic_increment(table->in_use->status_var.ha_read_prev_count,
+ &LOCK_status);
+ int error=myrg_rprev(file,buf, active_index);
+ table->status=error ? STATUS_NOT_FOUND: 0;
+ return error;
+}
+
+int ha_myisammrg::index_first(byte * buf)
+{
+ statistic_increment(table->in_use->status_var.ha_read_first_count,
+ &LOCK_status);
+ int error=myrg_rfirst(file, buf, active_index);
+ table->status=error ? STATUS_NOT_FOUND: 0;
+ return error;
+}
+
+int ha_myisammrg::index_last(byte * buf)
+{
+ statistic_increment(table->in_use->status_var.ha_read_last_count,
+ &LOCK_status);
+ int error=myrg_rlast(file, buf, active_index);
+ table->status=error ? STATUS_NOT_FOUND: 0;
+ return error;
+}
+
+int ha_myisammrg::index_next_same(byte * buf,
+ const byte *key __attribute__((unused)),
+ uint length __attribute__((unused)))
+{
+ statistic_increment(table->in_use->status_var.ha_read_next_count,
+ &LOCK_status);
+ int error=myrg_rnext_same(file,buf);
+ table->status=error ? STATUS_NOT_FOUND: 0;
+ return error;
+}
+
+
+int ha_myisammrg::rnd_init(bool scan)
+{
+ return myrg_reset(file);
+}
+
+
+int ha_myisammrg::rnd_next(byte *buf)
+{
+ statistic_increment(table->in_use->status_var.ha_read_rnd_next_count,
+ &LOCK_status);
+ int error=myrg_rrnd(file, buf, HA_OFFSET_ERROR);
+ table->status=error ? STATUS_NOT_FOUND: 0;
+ return error;
+}
+
+
+int ha_myisammrg::rnd_pos(byte * buf, byte *pos)
+{
+ statistic_increment(table->in_use->status_var.ha_read_rnd_count,
+ &LOCK_status);
+ int error=myrg_rrnd(file, buf, my_get_ptr(pos,ref_length));
+ table->status=error ? STATUS_NOT_FOUND: 0;
+ return error;
+}
+
+void ha_myisammrg::position(const byte *record)
+{
+ ulonglong position= myrg_position(file);
+ my_store_ptr(ref, ref_length, (my_off_t) position);
+}
+
+
+ha_rows ha_myisammrg::records_in_range(uint inx, key_range *min_key,
+ key_range *max_key)
+{
+ return (ha_rows) myrg_records_in_range(file, (int) inx, min_key, max_key);
+}
+
+
+int ha_myisammrg::info(uint flag)
+{
+ MYMERGE_INFO info;
+ (void) myrg_status(file,&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) info.records;
+ stats.deleted = (ha_rows) info.deleted;
+#if !defined(BIG_TABLES) || SIZEOF_OFF_T == 4
+ if ((info.records >= (ulonglong) 1 << 32) ||
+ (info.deleted >= (ulonglong) 1 << 32))
+ table->s->crashed= 1;
+#endif
+ stats.data_file_length=info.data_file_length;
+ errkey = info.errkey;
+ table->s->keys_in_use.set_prefix(table->s->keys);
+ table->s->db_options_in_use= info.options;
+ stats.mean_rec_length= 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 && info.rec_per_key)
+ {
+#ifdef HAVE_purify
+ /*
+ 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) * table->s->key_parts);
+#endif
+ memcpy((char*) table->key_info[0].rec_per_key,
+ (char*) info.rec_per_key,
+ sizeof(table->key_info[0].rec_per_key) *
+ min(file->keys, table->s->key_parts));
+ }
+ }
+ return 0;
+}
+
+
+int ha_myisammrg::extra(enum ha_extra_function operation)
+{
+ /* 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_DELETE)
+ return 0;
+ return myrg_extra(file,operation,0);
+}
+
+int ha_myisammrg::reset(void)
+{
+ 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)
+{
+ if ((specialflag & SPECIAL_SAFE_MODE) && operation == HA_EXTRA_WRITE_CACHE)
+ return 0;
+ return myrg_extra(file, operation, (void*) &cache_size);
+}
+
+int ha_myisammrg::external_lock(THD *thd, int lock_type)
+{
+ return myrg_lock_database(file,lock_type);
+}
+
+uint ha_myisammrg::lock_count(void) const
+{
+ return file->tables;
+}
+
+
+THR_LOCK_DATA **ha_myisammrg::store_lock(THD *thd,
+ THR_LOCK_DATA **to,
+ enum thr_lock_type lock_type)
+{
+ MYRG_TABLE *open_table;
+
+ for (open_table=file->open_tables ;
+ open_table != file->end_table ;
+ open_table++)
+ {
+ *(to++)= &open_table->table->lock;
+ if (lock_type != TL_IGNORE && open_table->table->lock.type == TL_UNLOCK)
+ open_table->table->lock.type=lock_type;
+ }
+ 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)
+{
+ uint dir_length, prefix_length;
+ char buff[FN_REFLEN];
+
+ db->length= 0;
+ strmake(buff, file_name, sizeof(buff)-1);
+ 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))
+ {
+ MYRG_TABLE *open_table;
+ THD *thd=current_thd;
+
+ create_info->merge_list.next= &create_info->merge_list.first;
+ create_info->merge_list.elements=0;
+
+ for (open_table=file->open_tables ;
+ open_table != file->end_table ;
+ open_table++)
+ {
+ TABLE_LIST *ptr;
+ LEX_STRING db, name;
+
+ if (!(ptr = (TABLE_LIST *) thd->calloc(sizeof(TABLE_LIST))))
+ goto err;
+ split_file_name(open_table->table->filename, &db, &name);
+ if (!(ptr->table_name= thd->strmake(name.str, name.length)))
+ goto err;
+ if (db.length && !(ptr->db= thd->strmake(db.str, db.length)))
+ goto err;
+
+ create_info->merge_list.elements++;
+ (*create_info->merge_list.next) = (byte*) ptr;
+ create_info->merge_list.next= (byte**) &ptr->next_local;
+ }
+ *create_info->merge_list.next=0;
+ }
+ if (!(create_info->used_fields & HA_CREATE_USED_INSERT_METHOD))
+ {
+ create_info->merge_insert_method = file->merge_insert_method;
+ }
+ DBUG_VOID_RETURN;
+
+err:
+ create_info->merge_list.elements=0;
+ create_info->merge_list.first=0;
+ DBUG_VOID_RETURN;
+}
+
+
+int ha_myisammrg::create(const char *name, register TABLE *form,
+ HA_CREATE_INFO *create_info)
+{
+ char buff[FN_REFLEN];
+ const char **table_names, **pos;
+ TABLE_LIST *tables= (TABLE_LIST*) create_info->merge_list.first;
+ THD *thd= current_thd;
+ uint dirlgt= dirname_length(name);
+ DBUG_ENTER("ha_myisammrg::create");
+
+ if (!(table_names= (const char**)
+ thd->alloc((create_info->merge_list.elements+1) * sizeof(char*))))
+ DBUG_RETURN(HA_ERR_OUT_OF_MEM);
+ for (pos= table_names; tables; tables= tables->next_local)
+ {
+ const char *table_name;
+ TABLE *tbl= 0;
+ if (create_info->options & HA_LEX_CREATE_TMP_TABLE)
+ tbl= find_temporary_table(thd, tables);
+ if (!tbl)
+ {
+ /*
+ 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.
+ */
+ uint length= build_table_filename(buff, sizeof(buff),
+ tables->db, tables->table_name, "", 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= tables->table_name;
+ else
+ if (! (table_name= thd->strmake(buff, length)))
+ DBUG_RETURN(HA_ERR_OUT_OF_MEM);
+ }
+ else
+ table_name= tbl->s->path.str;
+ *pos++= table_name;
+ }
+ *pos=0;
+ DBUG_RETURN(myrg_create(fn_format(buff,name,"","",
+ MY_RESOLVE_SYMLINKS|
+ MY_UNPACK_FILENAME|MY_APPEND_EXT),
+ table_names,
+ create_info->merge_insert_method,
+ (my_bool) 0));
+}
+
+
+void ha_myisammrg::append_create_info(String *packet)
+{
+ const char *current_db;
+ uint db_length;
+ THD *thd= current_thd;
+ MYRG_TABLE *open_table, *first;
+
+ if (file->merge_insert_method != MERGE_INSERT_DISABLED)
+ {
+ packet->append(STRING_WITH_LEN(" INSERT_METHOD="));
+ packet->append(get_type(&merge_insert_method,file->merge_insert_method-1));
+ }
+ packet->append(STRING_WITH_LEN(" UNION=("));
+
+ current_db= table->s->db.str;
+ db_length= table->s->db.length;
+
+ for (first=open_table=file->open_tables ;
+ open_table != file->end_table ;
+ open_table++)
+ {
+ LEX_STRING db, name;
+ split_file_name(open_table->table->filename, &db, &name);
+ 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, name.str, name.length);
+ }
+ packet->append(')');
+}
+
+
+bool ha_myisammrg::check_if_incompatible_data(HA_CREATE_INFO *info,
+ uint table_changes)
+{
+ /*
+ For myisammrg, we should always re-generate the mapping file as this
+ is trivial to do
+ */
+ return COMPATIBLE_DATA_NO;
+}
+
+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;
+
+ myisammrg_hton->state= SHOW_OPTION_YES;
+ myisammrg_hton->db_type= DB_TYPE_MRG_MYISAM;
+ myisammrg_hton->create= myisammrg_create_handler;
+ myisammrg_hton->panic= myisammrg_panic;
+ myisammrg_hton->flags= HTON_CAN_RECREATE|HTON_NO_PARTITION;
+
+ return 0;
+}
+
+struct st_mysql_storage_engine myisammrg_storage_engine=
+{ MYSQL_HANDLERTON_INTERFACE_VERSION };
+
+mysql_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 */
+ NULL /* config options */
+}
+mysql_declare_plugin_end;
diff --git a/storage/myisammrg/ha_myisammrg.h b/storage/myisammrg/ha_myisammrg.h
new file mode 100644
index 00000000000..ae3cb0aea42
--- /dev/null
+++ b/storage/myisammrg/ha_myisammrg.h
@@ -0,0 +1,88 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+
+#ifdef USE_PRAGMA_INTERFACE
+#pragma interface /* gcc class implementation */
+#endif
+
+/* class for the the myisam merge handler */
+
+#include <myisammrg.h>
+
+class ha_myisammrg: public handler
+{
+ MYRG_INFO *file;
+
+ public:
+ ha_myisammrg(handlerton *hton, TABLE_SHARE *table_arg);
+ ~ha_myisammrg() {}
+ const char *table_type() const { return "MRG_MyISAM"; }
+ const char **bas_ext() const;
+ 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_NULL_IN_KEY | HA_CAN_INDEX_BLOBS | HA_FILE_BASED |
+ HA_CAN_INSERT_DELAYED | HA_ANY_INDEX_MAY_BE_UNIQUE |
+ HA_CAN_BIT_FIELD | HA_NO_COPY_ON_ALTER);
+ }
+ 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 MI_MAX_KEY_LENGTH; }
+ uint max_supported_key_part_length() const { return MI_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 close(void);
+ int write_row(byte * buf);
+ int update_row(const byte * old_data, byte * new_data);
+ int delete_row(const byte * buf);
+ int index_read(byte * buf, const byte * key,
+ uint key_len, enum ha_rkey_function find_flag);
+ int index_read_idx(byte * buf, uint idx, const byte * key,
+ uint key_len, enum ha_rkey_function find_flag);
+ int index_read_last(byte * buf, const byte * key, uint key_len);
+ int index_next(byte * buf);
+ int index_prev(byte * buf);
+ int index_first(byte * buf);
+ int index_last(byte * buf);
+ int index_next_same(byte *buf, const byte *key, uint keylen);
+ int rnd_init(bool scan);
+ int rnd_next(byte *buf);
+ int rnd_pos(byte * buf, byte *pos);
+ void position(const byte *record);
+ ha_rows records_in_range(uint inx, key_range *min_key, key_range *max_key);
+ 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(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; }
+ bool check_if_incompatible_data(HA_CREATE_INFO *info, uint table_changes);
+};
diff --git a/storage/myisammrg/make-ccc b/storage/myisammrg/make-ccc
new file mode 100755
index 00000000000..a7e3dfc3cdb
--- /dev/null
+++ b/storage/myisammrg/make-ccc
@@ -0,0 +1,3 @@
+ccc -I./../include -I../include -DDBUG_OFF -fast -O3 -c myrg_close.c myrg_create.c myrg_delete.c myrg_extra.c myrg_info.c myrg_locking.c myrg_open.c myrg_panic.c myrg_rrnd.c myrg_rsame.c myrg_static.c myrg_update.c
+rm libmyisammrg.a
+ar -cr libmyisammrg.a myrg_close.o
diff --git a/storage/myisammrg/myrg_close.c b/storage/myisammrg/myrg_close.c
new file mode 100644
index 00000000000..897020c6865
--- /dev/null
+++ b/storage/myisammrg/myrg_close.c
@@ -0,0 +1,40 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* 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");
+
+ for (file=info->open_tables ; file != info->end_table ; file++)
+ if ((new_error=mi_close(file->table)))
+ error=new_error;
+ delete_queue(&info->by_key);
+ pthread_mutex_lock(&THR_LOCK_open);
+ myrg_open_list=list_delete(myrg_open_list,&info->open_list);
+ pthread_mutex_unlock(&THR_LOCK_open);
+ my_free((gptr) info,MYF(0));
+ 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 00000000000..3261cc1d6ad
--- /dev/null
+++ b/storage/myisammrg/myrg_create.c
@@ -0,0 +1,73 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* 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 = my_create(fn_format(buff,name,"",MYRG_NAME_EXT,
+ MY_UNPACK_FILENAME|MY_APPEND_EXT),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 (my_write(file,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 (my_write(file,buff,(uint) (end-buff),MYF(MY_WME | MY_NABP)))
+ goto err;
+ }
+ if (my_close(file,MYF(0)))
+ goto err;
+ DBUG_RETURN(0);
+
+err:
+ save_errno=my_errno ? my_errno : -1;
+ switch (errpos) {
+ case 1:
+ VOID(my_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 00000000000..00e7950bccf
--- /dev/null
+++ b/storage/myisammrg/myrg_def.h
@@ -0,0 +1,33 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* 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;
+
+#ifdef THREAD
+extern pthread_mutex_t THR_LOCK_open;
+#endif
+
+int _myrg_init_queue(MYRG_INFO *info,int inx,enum ha_rkey_function search_flag);
+int _myrg_mi_read_record(MI_INFO *info, byte *buf);
+
diff --git a/storage/myisammrg/myrg_delete.c b/storage/myisammrg/myrg_delete.c
new file mode 100644
index 00000000000..8b89ed62ac1
--- /dev/null
+++ b/storage/myisammrg/myrg_delete.c
@@ -0,0 +1,27 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* Delete last read record */
+
+#include "myrg_def.h"
+
+int myrg_delete(MYRG_INFO *info, const byte *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 00000000000..2d6f9423de9
--- /dev/null
+++ b/storage/myisammrg/myrg_extra.c
@@ -0,0 +1,88 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/*
+ 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 (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;
+
+ 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 00000000000..ba840ac444b
--- /dev/null
+++ b/storage/myisammrg/myrg_info.c
@@ -0,0 +1,68 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#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)
+ x->errkey= current_table->table->errkey;
+ else
+ x->errkey= 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 00000000000..98e8305b9ce
--- /dev/null
+++ b/storage/myisammrg/myrg_locking.c
@@ -0,0 +1,44 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/*
+ 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++)
+ {
+#ifdef __WIN__
+ /*
+ Make sure this table is marked as owned by a merge table.
+ The semaphore is never released as long as table remains
+ in memory. This should be refactored into a more generic
+ approach (observer pattern)
+ */
+ (file->table)->owned_by_merge = TRUE;
+#endif
+ if ((new_error=mi_lock_database(file->table,lock_type)))
+ error=new_error;
+ }
+ return(error);
+}
diff --git a/storage/myisammrg/myrg_open.c b/storage/myisammrg/myrg_open.c
new file mode 100644
index 00000000000..dafb3246cbf
--- /dev/null
+++ b/storage/myisammrg/myrg_open.c
@@ -0,0 +1,179 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* open a MyISAM MERGE table */
+
+#include "myrg_def.h"
+#include <stddef.h>
+#include <errno.h>
+#ifdef VMS
+#include "mrg_static.c"
+#endif
+
+/*
+ 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
+*/
+
+
+MYRG_INFO *myrg_open(const char *name, int mode, int handle_locking)
+{
+ int save_errno,errpos=0;
+ uint files= 0, i, dir_length, length, key_parts, min_keys= 0;
+ ulonglong file_offset=0;
+ char name_buff[FN_REFLEN*2],buff[FN_REFLEN],*end;
+ MYRG_INFO *m_info=0;
+ File fd;
+ IO_CACHE file;
+ MI_INFO *isam=0;
+ uint found_merge_insert_method= 0;
+ DBUG_ENTER("myrg_open");
+
+ LINT_INIT(key_parts);
+
+ bzero((char*) &file,sizeof(file));
+ if ((fd=my_open(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);
+ while ((length=my_b_gets(&file,buff,FN_REFLEN-1)))
+ {
+ if ((end=buff+length)[-1] == '\n')
+ end[-1]='\0';
+ if (buff[0] && buff[0] != '#')
+ files++;
+ }
+
+ my_b_seek(&file, 0);
+ while ((length=my_b_gets(&file,buff,FN_REFLEN-1)))
+ {
+ if ((end=buff+length)[-1] == '\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,2);
+ 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))))
+ {
+ my_errno= HA_ERR_WRONG_MRG_TABLE_DEF;
+ goto err;
+ }
+ if (!m_info) /* First file */
+ {
+ key_parts=isam->s->base.key_parts;
+ if (!(m_info= (MYRG_INFO*) my_malloc(sizeof(MYRG_INFO) +
+ files*sizeof(MYRG_TABLE) +
+ key_parts*sizeof(long),
+ MYF(MY_WME|MY_ZEROFILL))))
+ goto err;
+ if (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)
+ {
+ my_errno=HA_ERR_WRONG_MRG_TABLE_DEF;
+ goto err;
+ }
+ 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 (!m_info && !(m_info= (MYRG_INFO*) my_malloc(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;
+
+ VOID(my_close(fd,MYF(0)));
+ end_io_cache(&file);
+ m_info->open_list.data=(void*) m_info;
+ pthread_mutex_lock(&THR_LOCK_open);
+ myrg_open_list=list_add(myrg_open_list,&m_info->open_list);
+ pthread_mutex_unlock(&THR_LOCK_open);
+ DBUG_RETURN(m_info);
+
+err:
+ save_errno=my_errno;
+ switch (errpos) {
+ case 3:
+ while (files)
+ mi_close(m_info->open_tables[--files].table);
+ my_free((char*) m_info,MYF(0));
+ /* Fall through */
+ case 2:
+ end_io_cache(&file);
+ /* Fall through */
+ case 1:
+ VOID(my_close(fd,MYF(0)));
+ }
+ my_errno=save_errno;
+ DBUG_RETURN (NULL);
+}
diff --git a/storage/myisammrg/myrg_panic.c b/storage/myisammrg/myrg_panic.c
new file mode 100644
index 00000000000..ab08b8082c3
--- /dev/null
+++ b/storage/myisammrg/myrg_panic.c
@@ -0,0 +1,46 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#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 00000000000..74fdddc7748
--- /dev/null
+++ b/storage/myisammrg/myrg_queue.c
@@ -0,0 +1,81 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include "myrg_def.h"
+
+static int queue_key_cmp(void *keyseg, byte *a, byte *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))
+ 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))
+ error=my_errno;
+ }
+ }
+ else
+ my_errno= error= HA_ERR_WRONG_INDEX;
+ return error;
+}
+
+int _myrg_mi_read_record(MI_INFO *info, byte *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 00000000000..aafdf70525c
--- /dev/null
+++ b/storage/myisammrg/myrg_range.c
@@ -0,0 +1,36 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include "myrg_def.h"
+
+ha_rows myrg_records_in_range(MYRG_INFO *info, int inx,
+ key_range *min_key, key_range *max_key)
+{
+ ha_rows records=0, res;
+ MYRG_TABLE *table;
+
+ for (table=info->open_tables ; table != info->end_table ; table++)
+ {
+ res= mi_records_in_range(table->table, inx, min_key, max_key);
+ 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_rfirst.c b/storage/myisammrg/myrg_rfirst.c
new file mode 100644
index 00000000000..9ba07686c47
--- /dev/null
+++ b/storage/myisammrg/myrg_rfirst.c
@@ -0,0 +1,49 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include "myrg_def.h"
+
+ /* Read first row according to specific key */
+
+int myrg_rfirst(MYRG_INFO *info, byte *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),(byte *)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 00000000000..85464374d5d
--- /dev/null
+++ b/storage/myisammrg/myrg_rkey.c
@@ -0,0 +1,94 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* 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,byte *buf,int inx, const byte *key,
+ uint key_len, enum ha_rkey_function search_flag)
+{
+ byte *key_buff;
+ uint pack_key_length;
+ MYRG_TABLE *table;
+ MI_INFO *mi;
+ int err;
+ DBUG_ENTER("myrg_rkey");
+ LINT_INIT(key_buff);
+ LINT_INIT(pack_key_length);
+
+ 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,key_len,search_flag);
+ /* Get the saved packed key and packed key length. */
+ key_buff=(byte*) mi->lastkey+mi->s->base.max_key_length;
+ pack_key_length=mi->pack_key_length;
+ }
+ else
+ {
+ mi->once_flags|= USE_PACKED_KEYS;
+ 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),(byte *)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", (byte*) 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 00000000000..96bb798bd4f
--- /dev/null
+++ b/storage/myisammrg/myrg_rlast.c
@@ -0,0 +1,50 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include "myrg_def.h"
+
+ /* Read last row with the same key as the previous read. */
+
+int myrg_rlast(MYRG_INFO *info, byte *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),(byte *)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 00000000000..0929c63fc1d
--- /dev/null
+++ b/storage/myisammrg/myrg_rnext.c
@@ -0,0 +1,53 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include "myrg_def.h"
+
+ /*
+ Read next row with the same key as previous read
+ */
+
+int myrg_rnext(MYRG_INFO *info, byte *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(&(info->by_key),0);
+ 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))=(byte *)(info->current_table);
+ queue_replaced(&(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 00000000000..997e4100acd
--- /dev/null
+++ b/storage/myisammrg/myrg_rnext_same.c
@@ -0,0 +1,51 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include "myrg_def.h"
+
+
+int myrg_rnext_same(MYRG_INFO *info, byte *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(&(info->by_key),0);
+ 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))=(byte *)(info->current_table);
+ queue_replaced(&(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 00000000000..797993e903d
--- /dev/null
+++ b/storage/myisammrg/myrg_rprev.c
@@ -0,0 +1,53 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include "myrg_def.h"
+
+ /*
+ Read previous row with the same key as previous read
+ */
+
+int myrg_rprev(MYRG_INFO *info, byte *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(&(info->by_key),0);
+ 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))=(byte *)(info->current_table);
+ queue_replaced(&(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 00000000000..d623ea8ea9c
--- /dev/null
+++ b/storage/myisammrg/myrg_rrnd.c
@@ -0,0 +1,117 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/*
+ 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,byte *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,(byte*) &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,(byte*) 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,
+ (byte*) &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,
+ (byte*) &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, (byte*) 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 00000000000..f6b2164dc21
--- /dev/null
+++ b/storage/myisammrg/myrg_rsame.c
@@ -0,0 +1,28 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include "myrg_def.h"
+
+int myrg_rsame(MYRG_INFO *info,byte *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 00000000000..9e76cbae07b
--- /dev/null
+++ b/storage/myisammrg/myrg_static.c
@@ -0,0 +1,30 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/*
+ 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};
diff --git a/storage/myisammrg/myrg_update.c b/storage/myisammrg/myrg_update.c
new file mode 100644
index 00000000000..7b9f614b965
--- /dev/null
+++ b/storage/myisammrg/myrg_update.c
@@ -0,0 +1,27 @@
+/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* Update last read record */
+
+#include "myrg_def.h"
+
+int myrg_update(register MYRG_INFO *info,const byte *oldrec, byte *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 00000000000..532709e361d
--- /dev/null
+++ b/storage/myisammrg/myrg_write.c
@@ -0,0 +1,30 @@
+/* Copyright (C) 2001 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* Write a row to a MyISAM MERGE table */
+
+#include "myrg_def.h"
+
+int myrg_write(register MYRG_INFO *info, byte *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/plug.in b/storage/myisammrg/plug.in
new file mode 100644
index 00000000000..1f94e07d881
--- /dev/null
+++ b/storage/myisammrg/plug.in
@@ -0,0 +1,6 @@
+MYSQL_STORAGE_ENGINE(myisammrg,no,[MyISAM MERGE Engine],
+ [Merge multiple MySQL tables into one])
+MYSQL_PLUGIN_DIRECTORY(myisammrg,[storage/myisammrg])
+MYSQL_PLUGIN_STATIC(myisammrg, [libmyisammrg.a])
+MYSQL_PLUGIN_MANDATORY(myisammrg)
+MYSQL_PLUGIN_DEPENDS_ON_MYSQL_INTERNALS(myisammrg, [ha_myisammrg.cc])