summaryrefslogtreecommitdiffstats
path: root/storage/maria/ma_rename.c
diff options
context:
space:
mode:
Diffstat (limited to 'storage/maria/ma_rename.c')
-rw-r--r--storage/maria/ma_rename.c165
1 files changed, 165 insertions, 0 deletions
diff --git a/storage/maria/ma_rename.c b/storage/maria/ma_rename.c
new file mode 100644
index 00000000..ade6e52f
--- /dev/null
+++ b/storage/maria/ma_rename.c
@@ -0,0 +1,165 @@
+/* Copyright (C) 2006 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; 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 */
+
+/*
+ Rename a table
+*/
+
+#include "ma_fulltext.h"
+#include "trnman_public.h"
+
+/**
+ @brief renames a table
+
+ @param old_name current name of table
+ @param new_name table should be renamed to this name
+
+ @return Operation status
+ @retval 0 OK
+ @retval !=0 Error
+*/
+
+int maria_rename(const char *old_name, const char *new_name)
+{
+ char from[FN_REFLEN],to[FN_REFLEN];
+ int data_file_rename_error= 0, index_file_rename_error= 0;
+#ifdef USE_RAID
+ uint raid_type=0,raid_chunks=0;
+#endif
+ MARIA_HA *info;
+ MARIA_SHARE *share;
+ myf sync_dir= 0;
+ my_bool ddl_recovery= 0;
+ DBUG_ENTER("maria_rename");
+
+#ifdef EXTRA_DEBUG
+ _ma_check_table_is_closed(old_name,"rename old_table");
+ _ma_check_table_is_closed(new_name,"rename new table2");
+#endif
+ /** @todo LOCK take X-lock on table */
+ if (!(info= maria_open(old_name, O_RDWR, HA_OPEN_FOR_REPAIR, 0)))
+ {
+ int error= my_errno;
+ /*
+ Check if we are in recovery from a rename that failed in the middle
+ and we are now renaming things back.
+ */
+ if (error == ENOENT)
+ {
+ char *index_file= from;
+ char *data_file= to;
+ fn_format(index_file, old_name, "", MARIA_NAME_IEXT,
+ MY_UNPACK_FILENAME | MY_APPEND_EXT);
+ fn_format(data_file, old_name, "", MARIA_NAME_DEXT,
+ MY_UNPACK_FILENAME | MY_APPEND_EXT);
+ if (!access(data_file, F_OK) && access(index_file, F_OK))
+ {
+ ddl_recovery= 1;
+ goto forced_rename;
+ }
+ }
+ DBUG_RETURN(error);
+ }
+ share= info->s;
+#ifdef USE_RAID
+ raid_type = share->base.raid_type;
+ raid_chunks = share->base.raid_chunks;
+#endif
+
+ /*
+ the renaming of an internal table to the final table (like in ALTER TABLE)
+ is the moment when this table receives its correct create_rename_lsn and
+ this is important; make sure transactionality has been re-enabled.
+ */
+ DBUG_ASSERT(share->now_transactional == share->base.born_transactional);
+ if (share->now_transactional && !share->temporary && !maria_in_recovery)
+ {
+ LSN lsn;
+ LEX_CUSTRING log_array[TRANSLOG_INTERNAL_PARTS + 2];
+ size_t old_name_len= strlen(old_name)+1, new_name_len= strlen(new_name)+1;
+ sync_dir= MY_SYNC_DIR;
+ log_array[TRANSLOG_INTERNAL_PARTS + 0].str= (uchar*)old_name;
+ log_array[TRANSLOG_INTERNAL_PARTS + 0].length= old_name_len;
+ log_array[TRANSLOG_INTERNAL_PARTS + 1].str= (uchar*)new_name;
+ log_array[TRANSLOG_INTERNAL_PARTS + 1].length= new_name_len;
+ /*
+ For this record to be of any use for Recovery, we need the upper
+ MySQL layer to be crash-safe, which it is not now (that would require
+ work using the ddl_log of sql/sql_table.cc); when it is, we should
+ reconsider the moment of writing this log record (before or after op,
+ under THR_LOCK_maria or not...), how to use it in Recovery.
+ For now it can serve to apply logs to a backup so we sync it.
+ */
+ if (unlikely(translog_write_record(&lsn, LOGREC_REDO_RENAME_TABLE,
+ &dummy_transaction_object, NULL,
+ (translog_size_t)(old_name_len + new_name_len),
+ sizeof(log_array)/sizeof(log_array[0]),
+ log_array, NULL, NULL) ||
+ translog_flush(lsn)))
+ {
+ maria_close(info);
+ DBUG_RETURN(1);
+ }
+ /*
+ store LSN into file, needed for Recovery to not be confused if a
+ RENAME happened (applying REDOs to the wrong table).
+ */
+ if (_ma_update_state_lsns(share, lsn, share->state.create_trid, TRUE,
+ TRUE))
+ {
+ maria_close(info);
+ DBUG_RETURN(1);
+ }
+ }
+
+ _ma_reset_state(info);
+ maria_close(info);
+
+forced_rename:
+ /*
+ This code is written so that it should be possible to re-run a
+ failed rename (even if there is a server crash in between the
+ renames) and complete it.
+ */
+ fn_format(from,old_name,"",MARIA_NAME_IEXT,MY_UNPACK_FILENAME|MY_APPEND_EXT);
+ fn_format(to,new_name,"",MARIA_NAME_IEXT,MY_UNPACK_FILENAME|MY_APPEND_EXT);
+ if (mysql_file_rename_with_symlink(key_file_kfile, from, to,
+ MYF(MY_WME | sync_dir)))
+ index_file_rename_error= my_errno;
+ fn_format(from,old_name,"",MARIA_NAME_DEXT,MY_UNPACK_FILENAME|MY_APPEND_EXT);
+ fn_format(to,new_name,"",MARIA_NAME_DEXT,MY_UNPACK_FILENAME|MY_APPEND_EXT);
+ if (mysql_file_rename_with_symlink(key_file_dfile, from, to,
+ MYF(MY_WME | sync_dir)))
+ data_file_rename_error= my_errno;
+ if (data_file_rename_error && data_file_rename_error != ENOENT &&
+ !ddl_recovery)
+ {
+ /*
+ Now we have a renamed index file and a non-renamed data file, try to
+ undo a successful rename of the index file.
+ */
+ if (!index_file_rename_error)
+ {
+ fn_format(from, old_name, "", MARIA_NAME_IEXT,
+ MYF(MY_UNPACK_FILENAME|MY_APPEND_EXT));
+ fn_format(to, new_name, "", MARIA_NAME_IEXT,
+ MYF(MY_UNPACK_FILENAME|MY_APPEND_EXT));
+ mysql_file_rename_with_symlink(key_file_kfile, to, from,
+ MYF(MY_WME | sync_dir));
+ }
+ }
+ DBUG_RETURN(data_file_rename_error ? data_file_rename_error:
+ index_file_rename_error);
+}