Below is the list of changes that have just been committed into a local
5.1 repository of tomas. When tomas does a push these changes will
be propagated to the main repository and, within 24 hours after the
push, to the public repository.
For information on how to access the public repository
see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html
ChangeSet@stripped, 2007-04-12 11:12:43+02:00, tomas@stripped +5 -0
Merge whalegate.ndb.mysql.com:/home/tomas/mysql-5.0-ndb
into whalegate.ndb.mysql.com:/home/tomas/mysql-5.1-single-user
MERGE: 1.1810.2374.123
mysql-test/r/ndb_restore.result@stripped, 2007-04-12 11:12:40+02:00, tomas@stripped +9 -27
manual merge
MERGE: 1.4.1.2
mysql-test/t/ndb_restore.test@stripped, 2007-04-12 11:12:40+02:00, tomas@stripped +0 -37
manual merge
MERGE: 1.9.1.2
sql/ha_ndbcluster.cc@stripped, 2007-04-12 11:12:08+02:00, tomas@stripped +0 -4
null merge, 5.1 already reports correct error
MERGE: 1.175.1.134
storage/ndb/tools/restore/consumer_restore.cpp@stripped, 2007-04-12 11:08:09+02:00, tomas@stripped +0 -0
Auto merged
MERGE: 1.14.15.2
storage/ndb/tools/restore/consumer_restore.cpp@stripped, 2007-04-12 11:08:09+02:00, tomas@stripped +0 -0
Merge rename: ndb/tools/restore/consumer_restore.cpp -> storage/ndb/tools/restore/consumer_restore.cpp
storage/ndb/tools/restore/restore_main.cpp@stripped, 2007-04-12 11:08:09+02:00, tomas@stripped +0 -0
Auto merged
MERGE: 1.29.17.2
storage/ndb/tools/restore/restore_main.cpp@stripped, 2007-04-12 11:08:09+02:00, tomas@stripped +0 -0
Merge rename: ndb/tools/restore/restore_main.cpp -> storage/ndb/tools/restore/restore_main.cpp
# This is a BitKeeper patch. What follows are the unified diffs for the
# set of deltas contained in the patch. The rest of the patch, the part
# that BitKeeper cares about, is below these diffs.
# User: tomas
# Host: whalegate.ndb.mysql.com
# Root: /home/tomas/mysql-5.1-single-user/RESYNC
--- 1.29.17.1/ndb/tools/restore/restore_main.cpp 2007-04-12 11:07:28 +02:00
+++ 1.55/storage/ndb/tools/restore/restore_main.cpp 2007-04-12 11:08:09 +02:00
@@ -40,6 +40,11 @@
static const char* default_backupPath = "." DIR_SEPARATOR;
static const char* ga_backupPath = default_backupPath;
+static const char *opt_nodegroup_map_str= 0;
+static unsigned opt_nodegroup_map_len= 0;
+static NODE_GROUP_MAP opt_nodegroup_map[MAX_NODE_GROUP_MAPS];
+#define OPT_NDB_NODEGROUP_MAP 'z'
+
const char *opt_ndb_database= NULL;
const char *opt_ndb_table= NULL;
unsigned int opt_verbose;
@@ -53,14 +58,17 @@
/**
* print and restore flags
*/
+static bool ga_restore_epoch = false;
static bool ga_restore = false;
static bool ga_print = false;
+static bool ga_skip_table_check = false;
static int _print = 0;
static int _print_meta = 0;
static int _print_data = 0;
static int _print_log = 0;
static int _restore_data = 0;
static int _restore_meta = 0;
+static int _no_restore_disk = 0;
BaseString g_options("ndb_restore");
const char *load_default_groups[]= { "mysql_cluster","ndb_restore",0 };
@@ -107,6 +115,19 @@
"Restore meta data into NDB Cluster using NDBAPI",
(gptr*) &_restore_meta, (gptr*) &_restore_meta, 0,
GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
+ { "no-restore-disk-objects", 'd',
+ "Dont restore disk objects (tablespace/logfilegroups etc)",
+ (gptr*) &_no_restore_disk, (gptr*) &_no_restore_disk, 0,
+ GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
+ { "restore_epoch", 'e',
+ "Restore epoch info into the status table. Convenient on a MySQL Cluster "
+ "replication slave, for starting replication. The row in "
+ NDB_REP_DB "." NDB_APPLY_TABLE " with id 0 will be updated/inserted.",
+ (gptr*) &ga_restore_epoch, (gptr*) &ga_restore_epoch, 0,
+ GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
+ { "skip-table-check", 's', "Skip table structure check during restore of data",
+ (gptr*) &ga_skip_table_check, (gptr*) &ga_skip_table_check, 0,
+ GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
{ "parallelism", 'p',
"No of parallel transactions during restore of data."
"(parallelism can be 1 to 1024)",
@@ -131,6 +152,12 @@
"Experimental. Do not ignore system table during restore.",
(gptr*) &ga_dont_ignore_systab_0, (gptr*) &ga_dont_ignore_systab_0, 0,
GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
+ { "ndb-nodegroup-map", OPT_NDB_NODEGROUP_MAP,
+ "Nodegroup map for ndbcluster. Syntax: list of (source_ng, dest_ng)",
+ (gptr*) &opt_nodegroup_map_str,
+ (gptr*) &opt_nodegroup_map_str,
+ 0,
+ GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
{ "fields-enclosed-by", OPT_FIELDS_ENCLOSED_BY,
"Fields are enclosed by ...",
(gptr*) &opt_fields_enclosed_by, (gptr*) &opt_fields_enclosed_by, 0,
@@ -165,6 +192,115 @@
{ 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
};
+
+static char* analyse_one_map(char *map_str, uint16 *source, uint16 *dest)
+{
+ char *end_ptr;
+ int number;
+ DBUG_ENTER("analyse_one_map");
+ /*
+ Search for pattern ( source_ng , dest_ng )
+ */
+
+ while (isspace(*map_str)) map_str++;
+
+ if (*map_str != '(')
+ {
+ DBUG_RETURN(NULL);
+ }
+ map_str++;
+
+ while (isspace(*map_str)) map_str++;
+
+ number= strtol(map_str, &end_ptr, 10);
+ if (!end_ptr || number < 0 || number >= MAX_NODE_GROUP_MAPS)
+ {
+ DBUG_RETURN(NULL);
+ }
+ *source= (uint16)number;
+ map_str= end_ptr;
+
+ while (isspace(*map_str)) map_str++;
+
+ if (*map_str != ',')
+ {
+ DBUG_RETURN(NULL);
+ }
+ map_str++;
+
+ number= strtol(map_str, &end_ptr, 10);
+ if (!end_ptr || number < 0 || number >= UNDEF_NODEGROUP)
+ {
+ DBUG_RETURN(NULL);
+ }
+ *dest= (uint16)number;
+ map_str= end_ptr;
+
+ if (*map_str != ')')
+ {
+ DBUG_RETURN(NULL);
+ }
+ map_str++;
+
+ while (isspace(*map_str)) map_str++;
+ DBUG_RETURN(map_str);
+}
+
+static bool insert_ng_map(NODE_GROUP_MAP *ng_map,
+ uint16 source_ng, uint16 dest_ng)
+{
+ uint index= source_ng;
+ uint ng_index= ng_map[index].no_maps;
+
+ opt_nodegroup_map_len++;
+ if (ng_index >= MAX_MAPS_PER_NODE_GROUP)
+ return true;
+ ng_map[index].no_maps++;
+ ng_map[index].map_array[ng_index]= dest_ng;
+ return false;
+}
+
+static void init_nodegroup_map()
+{
+ uint i,j;
+ NODE_GROUP_MAP *ng_map = &opt_nodegroup_map[0];
+
+ for (i = 0; i < MAX_NODE_GROUP_MAPS; i++)
+ {
+ ng_map[i].no_maps= 0;
+ for (j= 0; j < MAX_MAPS_PER_NODE_GROUP; j++)
+ ng_map[i].map_array[j]= UNDEF_NODEGROUP;
+ }
+}
+
+static bool analyse_nodegroup_map(const char *ng_map_str,
+ NODE_GROUP_MAP *ng_map)
+{
+ uint16 source_ng, dest_ng;
+ char *local_str= (char*)ng_map_str;
+ DBUG_ENTER("analyse_nodegroup_map");
+
+ do
+ {
+ if (!local_str)
+ {
+ DBUG_RETURN(TRUE);
+ }
+ local_str= analyse_one_map(local_str, &source_ng, &dest_ng);
+ if (!local_str)
+ {
+ DBUG_RETURN(TRUE);
+ }
+ if (insert_ng_map(ng_map, source_ng, dest_ng))
+ {
+ DBUG_RETURN(TRUE);
+ }
+ if (!(*local_str))
+ break;
+ } while (TRUE);
+ DBUG_RETURN(FALSE);
+}
+
static void short_usage_sub(void)
{
printf("Usage: %s [OPTIONS] [<path to backup files>]\n", my_progname);
@@ -208,6 +344,21 @@
info.setLevel(254);
info << "Backup Id = " << ga_backupId << endl;
break;
+ case OPT_NDB_NODEGROUP_MAP:
+ /*
+ This option is used to set a map from nodegroup in original cluster
+ to nodegroup in new cluster.
+ */
+ opt_nodegroup_map_len= 0;
+
+ info.setLevel(254);
+ info << "Analyse node group map" << endl;
+ if (analyse_nodegroup_map(opt_nodegroup_map_str,
+ &opt_nodegroup_map[0]))
+ {
+ exit(NDBT_ProgramExit(NDBT_WRONGARGS));
+ }
+ break;
}
return 0;
}
@@ -218,18 +369,51 @@
debug << "Load defaults" << endl;
const char *load_default_groups[]= { "mysql_cluster","ndb_restore",0 };
+ init_nodegroup_map();
load_defaults("my",load_default_groups,pargc,pargv);
debug << "handle_options" << endl;
if (handle_options(pargc, pargv, my_long_options, get_one_option))
{
exit(NDBT_ProgramExit(NDBT_WRONGARGS));
}
+ for (i = 0; i < MAX_NODE_GROUP_MAPS; i++)
+ opt_nodegroup_map[i].curr_index = 0;
- g_printer = new BackupPrinter();
+#if 0
+ /*
+ Test code written t{
+o verify nodegroup mapping
+ */
+ printf("Handled options successfully\n");
+ Uint16 map_ng[16];
+ Uint32 j;
+ for (j = 0; j < 4; j++)
+ {
+ for (i = 0; i < 4 ; i++)
+ map_ng[i] = i;
+ map_nodegroups(&map_ng[0], (Uint32)4);
+ for (i = 0; i < 4 ; i++)
+ printf("NG %u mapped to %u \n", i, map_ng[i]);
+ }
+ for (j = 0; j < 4; j++)
+ {
+ for (i = 0; i < 8 ; i++)
+ map_ng[i] = i >> 1;
+ map_nodegroups(&map_ng[0], (Uint32)8);
+ for (i = 0; i < 8 ; i++)
+ printf("NG %u mapped to %u \n", i >> 1, map_ng[i]);
+ }
+ exit(NDBT_ProgramExit(NDBT_WRONGARGS));
+#endif
+
+ g_printer = new BackupPrinter(opt_nodegroup_map,
+ opt_nodegroup_map_len);
if (g_printer == NULL)
return false;
- BackupRestore* restore = new BackupRestore(ga_nParallelism);
+ BackupRestore* restore = new BackupRestore(opt_nodegroup_map,
+ opt_nodegroup_map_len,
+ ga_nParallelism);
if (restore == NULL)
{
delete g_printer;
@@ -271,6 +455,16 @@
restore->m_restore_meta = true;
}
+ if (_no_restore_disk)
+ {
+ restore->m_no_restore_disk = true;
+ }
+
+ if (ga_restore_epoch)
+ {
+ restore->m_restore_epoch = true;
+ }
+
{
BackupConsumer * c = g_printer;
g_consumers.push_back(c);
@@ -450,8 +644,14 @@
g_options.appfmt(" -n %d", ga_nodeId);
if (_restore_meta)
g_options.appfmt(" -m");
+ if (ga_skip_table_check)
+ g_options.appfmt(" -s");
if (_restore_data)
g_options.appfmt(" -r");
+ if (ga_restore_epoch)
+ g_options.appfmt(" -e");
+ if (_no_restore_disk)
+ g_options.appfmt(" -d");
g_options.appfmt(" -p %d", ga_nParallelism);
g_connect_string = opt_connect_str;
@@ -478,6 +678,18 @@
/**
* check wheater we can restore the backup (right version).
*/
+ // in these versions there was an error in how replica info was
+ // stored on disk
+ if (version >= MAKE_VERSION(5,1,3) && version <= MAKE_VERSION(5,1,9))
+ {
+ err << "Restore program incompatible with backup versions between "
+ << getVersionString(MAKE_VERSION(5,1,3), 0, buf, sizeof(buf))
+ << " and "
+ << getVersionString(MAKE_VERSION(5,1,9), 0, buf, sizeof(buf))
+ << endl;
+ exitHandler(NDBT_FAILED);
+ }
+
if (version > NDB_VERSION)
{
err << "Restore program older than backup version. Not supported. "
@@ -518,6 +730,18 @@
}
}
+ debug << "Restore objects (tablespaces, ..)" << endl;
+ for(i = 0; i<metaData.getNoOfObjects(); i++)
+ {
+ for(Uint32 j= 0; j < g_consumers.size(); j++)
+ if (!g_consumers[j]->object(metaData.getObjType(i),
+ metaData.getObjPtr(i)))
+ {
+ err << "Restore: Failed to restore table: ";
+ err << metaData[i]->getTableName() << " ... Exiting " << endl;
+ exitHandler(NDBT_FAILED);
+ }
+ }
Vector<OutputStream *> table_output(metaData.getNoOfTables());
debug << "Restoring tables" << endl;
@@ -562,6 +786,14 @@
err << "Restore: Failed to restore table: `";
err << table->getTableName() << "` ... Exiting " << endl;
exitHandler(NDBT_FAILED);
+ }
+ } else {
+ for(Uint32 j= 0; j < g_consumers.size(); j++)
+ if (!g_consumers[j]->createSystable(* table))
+ {
+ err << "Restore: Failed to restore system table: ";
+ err << table->getTableName() << " ... Exiting " << endl;
+ exitHandler(NDBT_FAILED);
}
}
}
@@ -577,6 +809,20 @@
{
if(_restore_data || _print_data)
{
+ if (!ga_skip_table_check){
+ for(i=0; i < metaData.getNoOfTables(); i++){
+ if (checkSysTable(metaData, i))
+ {
+ for(Uint32 j= 0; j < g_consumers.size(); j++)
+ if (!g_consumers[j]->table_equal(* metaData[i]))
+ {
+ err << "Restore: Failed to restore data, ";
+ err << metaData[i]->getTableName() << " table structure doesn't match backup ... Exiting " << endl;
+ exitHandler(NDBT_FAILED);
+ }
+ }
+ }
+ }
RestoreDataIterator dataIter(metaData, &free_data_callback);
// Read data file header
@@ -586,8 +832,8 @@
exitHandler(NDBT_FAILED);
}
-
- while (dataIter.readFragmentHeader(res= 0))
+ Uint32 fragmentId;
+ while (dataIter.readFragmentHeader(res= 0, &fragmentId))
{
const TupleS* tuple;
while ((tuple = dataIter.getNextTuple(res= 1)) != 0)
@@ -599,7 +845,7 @@
OutputStream *tmp = ndbout.m_out;
ndbout.m_out = output;
for(Uint32 j= 0; j < g_consumers.size(); j++)
- g_consumers[j]->tuple(* tuple);
+ g_consumers[j]->tuple(* tuple, fragmentId);
ndbout.m_out = tmp;
} // while (tuple != NULL);
@@ -678,6 +924,16 @@
}
}
}
+ if (ga_restore_epoch)
+ {
+ for (i= 0; i < g_consumers.size(); i++)
+ if (!g_consumers[i]->update_apply_status(metaData))
+ {
+ err << "Restore: Failed to restore epoch" << endl;
+ return -1;
+ }
+ }
+
for(Uint32 j= 0; j < g_consumers.size(); j++)
{
if (g_consumers[j]->has_temp_error())
--- 1.14.15.1/ndb/tools/restore/consumer_restore.cpp 2007-04-12 11:07:28 +02:00
+++ 1.44/storage/ndb/tools/restore/consumer_restore.cpp 2007-04-12 11:08:09 +02:00
@@ -15,6 +15,7 @@
#include <NDBT_ReturnCodes.h>
#include "consumer_restore.hpp"
+#include <my_sys.h>
#include <NdbSleep.h>
extern my_bool opt_core;
@@ -24,6 +25,8 @@
extern FilteredNdbOut debug;
static void callback(int, NdbTransaction*, void*);
+static Uint32 get_part_id(const NdbDictionary::Table *table,
+ Uint32 hash_value);
extern const char * g_connect_string;
extern BaseString g_options;
@@ -33,7 +36,7 @@
{
release();
- if (!m_restore && !m_restore_meta)
+ if (!m_restore && !m_restore_meta && !m_restore_epoch)
return true;
m_cluster_connection = new Ndb_cluster_connection(g_connect_string);
@@ -178,18 +181,623 @@
} while (1);
}
+
+#ifdef NOT_USED
+static bool default_nodegroups(NdbDictionary::Table *table)
+{
+ Uint16 *node_groups = (Uint16*)table->getFragmentData();
+ Uint32 no_parts = table->getFragmentDataLen() >> 1;
+ Uint32 i;
+
+ if (node_groups[0] != 0)
+ return false;
+ for (i = 1; i < no_parts; i++)
+ {
+ if (node_groups[i] != UNDEF_NODEGROUP)
+ return false;
+ }
+ return true;
+}
+#endif
+
+
+static Uint32 get_no_fragments(Uint64 max_rows, Uint32 no_nodes)
+{
+ Uint32 i = 0;
+ Uint32 acc_row_size = 27;
+ Uint32 acc_fragment_size = 512*1024*1024;
+ Uint32 no_parts= (max_rows*acc_row_size)/acc_fragment_size + 1;
+ Uint32 reported_parts = no_nodes;
+ while (reported_parts < no_parts && ++i < 4 &&
+ (reported_parts + no_parts) < MAX_NDB_PARTITIONS)
+ reported_parts+= no_nodes;
+ if (reported_parts < no_parts)
+ {
+ err << "Table will be restored but will not be able to handle the maximum";
+ err << " amount of rows as requested" << endl;
+ }
+ return reported_parts;
+}
+
+
+static void set_default_nodegroups(NdbDictionary::Table *table)
+{
+ Uint32 no_parts = table->getFragmentCount();
+ Uint16 node_group[MAX_NDB_PARTITIONS];
+ Uint32 i;
+
+ node_group[0] = 0;
+ for (i = 1; i < no_parts; i++)
+ {
+ node_group[i] = UNDEF_NODEGROUP;
+ }
+ table->setFragmentData((const void*)node_group, 2 * no_parts);
+}
+
+Uint32 BackupRestore::map_ng(Uint32 ng)
+{
+ NODE_GROUP_MAP *ng_map = m_nodegroup_map;
+
+ if (ng == UNDEF_NODEGROUP ||
+ ng_map[ng].map_array[0] == UNDEF_NODEGROUP)
+ {
+ return ng;
+ }
+ else
+ {
+ Uint32 new_ng;
+ Uint32 curr_inx = ng_map[ng].curr_index;
+ Uint32 new_curr_inx = curr_inx + 1;
+
+ assert(ng < MAX_NDB_PARTITIONS);
+ assert(curr_inx < MAX_MAPS_PER_NODE_GROUP);
+ assert(new_curr_inx < MAX_MAPS_PER_NODE_GROUP);
+
+ if (new_curr_inx >= MAX_MAPS_PER_NODE_GROUP)
+ new_curr_inx = 0;
+ else if (ng_map[ng].map_array[new_curr_inx] == UNDEF_NODEGROUP)
+ new_curr_inx = 0;
+ new_ng = ng_map[ng].map_array[curr_inx];
+ ng_map[ng].curr_index = new_curr_inx;
+ return new_ng;
+ }
+}
+
+
+bool BackupRestore::map_nodegroups(Uint16 *ng_array, Uint32 no_parts)
+{
+ Uint32 i;
+ bool mapped = FALSE;
+ DBUG_ENTER("map_nodegroups");
+
+ assert(no_parts < MAX_NDB_PARTITIONS);
+ for (i = 0; i < no_parts; i++)
+ {
+ Uint32 ng;
+ ng = map_ng((Uint32)ng_array[i]);
+ if (ng != ng_array[i])
+ mapped = TRUE;
+ ng_array[i] = ng;
+ }
+ DBUG_RETURN(mapped);
+}
+
+
+static void copy_byte(const char **data, char **new_data, uint *len)
+{
+ **new_data = **data;
+ (*data)++;
+ (*new_data)++;
+ (*len)++;
+}
+
+
+bool BackupRestore::search_replace(char *search_str, char **new_data,
+ const char **data, const char *end_data,
+ uint *new_data_len)
+{
+ uint search_str_len = strlen(search_str);
+ uint inx = 0;
+ bool in_delimiters = FALSE;
+ bool escape_char = FALSE;
+ char start_delimiter = 0;
+ DBUG_ENTER("search_replace");
+
+ do
+ {
+ char c = **data;
+ copy_byte(data, new_data, new_data_len);
+ if (escape_char)
+ {
+ escape_char = FALSE;
+ }
+ else if (in_delimiters)
+ {
+ if (c == start_delimiter)
+ in_delimiters = FALSE;
+ }
+ else if (c == '\'' || c == '\"')
+ {
+ in_delimiters = TRUE;
+ start_delimiter = c;
+ }
+ else if (c == '\\')
+ {
+ escape_char = TRUE;
+ }
+ else if (c == search_str[inx])
+ {
+ inx++;
+ if (inx == search_str_len)
+ {
+ bool found = FALSE;
+ uint number = 0;
+ while (*data != end_data)
+ {
+ if (isdigit(**data))
+ {
+ found = TRUE;
+ number = (10 * number) + (**data);
+ if (number > MAX_NDB_NODES)
+ break;
+ }
+ else if (found)
+ {
+ /*
+ After long and tedious preparations we have actually found
+ a node group identifier to convert. We'll use the mapping
+ table created for node groups and then insert the new number
+ instead of the old number.
+ */
+ uint temp = map_ng(number);
+ int no_digits = 0;
+ char digits[10];
+ while (temp != 0)
+ {
+ digits[no_digits] = temp % 10;
+ no_digits++;
+ temp/=10;
+ }
+ for (no_digits--; no_digits >= 0; no_digits--)
+ {
+ **new_data = digits[no_digits];
+ *new_data_len+=1;
+ }
+ DBUG_RETURN(FALSE);
+ }
+ else
+ break;
+ (*data)++;
+ }
+ DBUG_RETURN(TRUE);
+ }
+ }
+ else
+ inx = 0;
+ } while (*data < end_data);
+ DBUG_RETURN(FALSE);
+}
+
+bool BackupRestore::map_in_frm(char *new_data, const char *data,
+ uint data_len, uint *new_data_len)
+{
+ const char *end_data= data + data_len;
+ const char *end_part_data;
+ const char *part_data;
+ char *extra_ptr;
+ uint start_key_definition_len = uint2korr(data + 6);
+ uint key_definition_len = uint4korr(data + 47);
+ uint part_info_len;
+ DBUG_ENTER("map_in_frm");
+
+ if (data_len < 4096) goto error;
+ extra_ptr = (char*)data + start_key_definition_len + key_definition_len;
+ if ((int)data_len < ((extra_ptr - data) + 2)) goto error;
+ extra_ptr = extra_ptr + 2 + uint2korr(extra_ptr);
+ if ((int)data_len < ((extra_ptr - data) + 2)) goto error;
+ extra_ptr = extra_ptr + 2 + uint2korr(extra_ptr);
+ if ((int)data_len < ((extra_ptr - data) + 4)) goto error;
+ part_info_len = uint4korr(extra_ptr);
+ part_data = extra_ptr + 4;
+ if ((int)data_len < ((part_data + part_info_len) - data)) goto error;
+
+ do
+ {
+ copy_byte(&data, &new_data, new_data_len);
+ } while (data < part_data);
+ end_part_data = part_data + part_info_len;
+ do
+ {
+ if (search_replace((char*)" NODEGROUP = ", &new_data, &data,
+ end_part_data, new_data_len))
+ goto error;
+ } while (data != end_part_data);
+ do
+ {
+ copy_byte(&data, &new_data, new_data_len);
+ } while (data < end_data);
+ DBUG_RETURN(FALSE);
+error:
+ DBUG_RETURN(TRUE);
+}
+
+
+bool BackupRestore::translate_frm(NdbDictionary::Table *table)
+{
+ const void *pack_data, *data, *new_pack_data;
+ char *new_data;
+ uint data_len, new_data_len, new_pack_len;
+ uint no_parts, extra_growth;
+ DBUG_ENTER("translate_frm");
+
+ pack_data = table->getFrmData();
+ no_parts = table->getFragmentCount();
+ /*
+ Add max 4 characters per partition to handle worst case
+ of mapping from single digit to 5-digit number.
+ Fairly future-proof, ok up to 99999 node groups.
+ */
+ extra_growth = no_parts * 4;
+ if (unpackfrm(&data, &data_len, pack_data))
+ {
+ DBUG_RETURN(TRUE);
+ }
+ if ((new_data = my_malloc(data_len + extra_growth, MYF(0))))
+ {
+ DBUG_RETURN(TRUE);
+ }
+ if (map_in_frm(new_data, (const char*)data, data_len, &new_data_len))
+ {
+ my_free(new_data, MYF(0));
+ DBUG_RETURN(TRUE);
+ }
+ if (packfrm((const void*)new_data, new_data_len,
+ &new_pack_data, &new_pack_len))
+ {
+ my_free(new_data, MYF(0));
+ DBUG_RETURN(TRUE);
+ }
+ table->setFrm(new_pack_data, new_pack_len);
+ DBUG_RETURN(FALSE);
+}
+
+#include <signaldata/DictTabInfo.hpp>
+
+bool
+BackupRestore::object(Uint32 type, const void * ptr)
+{
+ if (!m_restore_meta)
+ return true;
+
+ NdbDictionary::Dictionary* dict = m_ndb->getDictionary();
+ switch(type){
+ case DictTabInfo::Tablespace:
+ {
+ NdbDictionary::Tablespace old(*(NdbDictionary::Tablespace*)ptr);
+
+ Uint32 id = old.getObjectId();
+
+ if (!m_no_restore_disk)
+ {
+ NdbDictionary::LogfileGroup * lg = m_logfilegroups[old.getDefaultLogfileGroupId()];
+ old.setDefaultLogfileGroup(* lg);
+ info << "Creating tablespace: " << old.getName() << "..." << flush;
+ int ret = dict->createTablespace(old);
+ if (ret)
+ {
+ NdbError errobj= dict->getNdbError();
+ info << "FAILED" << endl;
+ err << "Create tablespace failed: " << old.getName() << ": " << errobj << endl;
+ return false;
+ }
+ info << "done" << endl;
+ }
+
+ NdbDictionary::Tablespace curr = dict->getTablespace(old.getName());
+ NdbError errobj = dict->getNdbError();
+ if ((int) errobj.classification == (int) ndberror_cl_none)
+ {
+ NdbDictionary::Tablespace* currptr = new NdbDictionary::Tablespace(curr);
+ NdbDictionary::Tablespace * null = 0;
+ m_tablespaces.set(currptr, id, null);
+ debug << "Retreived tablespace: " << currptr->getName()
+ << " oldid: " << id << " newid: " << currptr->getObjectId()
+ << " " << (void*)currptr << endl;
+ return true;
+ }
+
+ err << "Failed to retrieve tablespace \"" << old.getName() << "\": "
+ << errobj << endl;
+
+ return false;
+ break;
+ }
+ case DictTabInfo::LogfileGroup:
+ {
+ NdbDictionary::LogfileGroup old(*(NdbDictionary::LogfileGroup*)ptr);
+
+ Uint32 id = old.getObjectId();
+
+ if (!m_no_restore_disk)
+ {
+ info << "Creating logfile group: " << old.getName() << "..." << flush;
+ int ret = dict->createLogfileGroup(old);
+ if (ret)
+ {
+ NdbError errobj= dict->getNdbError();
+ info << "FAILED" << endl;
+ err << "Create logfile group failed: " << old.getName() << ": " << errobj << endl;
+ return false;
+ }
+ info << "done" << endl;
+ }
+
+ NdbDictionary::LogfileGroup curr = dict->getLogfileGroup(old.getName());
+ NdbError errobj = dict->getNdbError();
+ if ((int) errobj.classification == (int) ndberror_cl_none)
+ {
+ NdbDictionary::LogfileGroup* currptr =
+ new NdbDictionary::LogfileGroup(curr);
+ NdbDictionary::LogfileGroup * null = 0;
+ m_logfilegroups.set(currptr, id, null);
+ debug << "Retreived logfile group: " << currptr->getName()
+ << " oldid: " << id << " newid: " << currptr->getObjectId()
+ << " " << (void*)currptr << endl;
+ return true;
+ }
+
+ err << "Failed to retrieve logfile group \"" << old.getName() << "\": "
+ << errobj << endl;
+
+ return false;
+ break;
+ }
+ case DictTabInfo::Datafile:
+ {
+ if (!m_no_restore_disk)
+ {
+ NdbDictionary::Datafile old(*(NdbDictionary::Datafile*)ptr);
+ NdbDictionary::ObjectId objid;
+ old.getTablespaceId(&objid);
+ NdbDictionary::Tablespace * ts = m_tablespaces[objid.getObjectId()];
+ debug << "Connecting datafile " << old.getPath()
+ << " to tablespace: oldid: " << objid.getObjectId()
+ << " newid: " << ts->getObjectId() << endl;
+ old.setTablespace(* ts);
+ info << "Creating datafile \"" << old.getPath() << "\"..." << flush;
+ if (dict->createDatafile(old))
+ {
+ NdbError errobj= dict->getNdbError();
+ info << "FAILED" << endl;
+ err << "Create datafile failed: " << old.getPath() << ": " << errobj << endl;
+ return false;
+ }
+ info << "done" << endl;
+ }
+ return true;
+ break;
+ }
+ case DictTabInfo::Undofile:
+ {
+ if (!m_no_restore_disk)
+ {
+ NdbDictionary::Undofile old(*(NdbDictionary::Undofile*)ptr);
+ NdbDictionary::ObjectId objid;
+ old.getLogfileGroupId(&objid);
+ NdbDictionary::LogfileGroup * lg = m_logfilegroups[objid.getObjectId()];
+ debug << "Connecting undofile " << old.getPath()
+ << " to logfile group: oldid: " << objid.getObjectId()
+ << " newid: " << lg->getObjectId()
+ << " " << (void*)lg << endl;
+ old.setLogfileGroup(* lg);
+ info << "Creating undofile \"" << old.getPath() << "\"..." << flush;
+ if (dict->createUndofile(old))
+ {
+ NdbError errobj= dict->getNdbError();
+ info << "FAILED" << endl;
+ err << "Create undofile failed: " << old.getPath() << ": " << errobj << endl;
+ return false;
+ }
+ info << "done" << endl;
+ }
+ return true;
+ break;
+ }
+ }
+ return true;
+}
+
bool
BackupRestore::has_temp_error(){
return m_temp_error;
}
bool
+BackupRestore::update_apply_status(const RestoreMetaData &metaData)
+{
+ if (!m_restore_epoch)
+ return true;
+
+ bool result= false;
+ unsigned apply_table_format= 0;
+
+ m_ndb->setDatabaseName(NDB_REP_DB);
+ m_ndb->setSchemaName("def");
+
+ NdbDictionary::Dictionary *dict= m_ndb->getDictionary();
+ const NdbDictionary::Table *ndbtab= dict->getTable(Ndb_apply_table);
+ if (!ndbtab)
+ {
+ err << Ndb_apply_table << ": "
+ << dict->getNdbError() << endl;
+ return false;
+ }
+ if
+ (ndbtab->getColumn(0)->getType() == NdbDictionary::Column::Unsigned &&
+ ndbtab->getColumn(1)->getType() == NdbDictionary::Column::Bigunsigned)
+ {
+ if (ndbtab->getNoOfColumns() == 2)
+ {
+ apply_table_format= 1;
+ }
+ else if
+ (ndbtab->getColumn(2)->getType() == NdbDictionary::Column::Varchar &&
+ ndbtab->getColumn(3)->getType() == NdbDictionary::Column::Bigunsigned &&
+ ndbtab->getColumn(4)->getType() == NdbDictionary::Column::Bigunsigned)
+ {
+ apply_table_format= 2;
+ }
+ }
+ if (apply_table_format == 0)
+ {
+ err << Ndb_apply_table << " has wrong format\n";
+ return false;
+ }
+
+ Uint32 server_id= 0;
+ Uint64 epoch= metaData.getStopGCP();
+ Uint64 zero= 0;
+ char empty_string[1];
+ empty_string[0]= 0;
+ NdbTransaction * trans= m_ndb->startTransaction();
+ if (!trans)
+ {
+ err << Ndb_apply_table << ": "
+ << m_ndb->getNdbError() << endl;
+ return false;
+ }
+ NdbOperation * op= trans->getNdbOperation(ndbtab);
+ if (!op)
+ {
+ err << Ndb_apply_table << ": "
+ << trans->getNdbError() << endl;
+ goto err;
+ }
+ if (op->writeTuple() ||
+ op->equal(0u, (const char *)&server_id, sizeof(server_id)) ||
+ op->setValue(1u, (const char *)&epoch, sizeof(epoch)))
+ {
+ err << Ndb_apply_table << ": "
+ << op->getNdbError() << endl;
+ goto err;
+ }
+ if ((apply_table_format == 2) &&
+ (op->setValue(2u, (const char *)&empty_string, 1) ||
+ op->setValue(3u, (const char *)&zero, sizeof(zero)) ||
+ op->setValue(4u, (const char *)&zero, sizeof(zero))))
+ {
+ err << Ndb_apply_table << ": "
+ << op->getNdbError() << endl;
+ goto err;
+ }
+ if (trans->execute(NdbTransaction::Commit))
+ {
+ err << Ndb_apply_table << ": "
+ << trans->getNdbError() << endl;
+ goto err;
+ }
+ result= true;
+err:
+ m_ndb->closeTransaction(trans);
+ return result;
+}
+
+bool
+BackupRestore::table_equal(const TableS &tableS)
+{
+ if (!m_restore)
+ return true;
+
+ const char *tablename = tableS.getTableName();
+
+ if(tableS.m_dictTable == NULL){
+ ndbout<<"Table %s has no m_dictTable " << tablename << endl;
+ return false;
+ }
+ /**
+ * Ignore blob tables
+ */
+ if(match_blob(tablename) >= 0)
+ return true;
+
+ const NdbTableImpl & tmptab = NdbTableImpl::getImpl(* tableS.m_dictTable);
+ if ((int) tmptab.m_indexType != (int) NdbDictionary::Index::Undefined){
+ return true;
+ }
+
+ BaseString tmp(tablename);
+ Vector<BaseString> split;
+ if(tmp.split(split, "/") != 3){
+ err << "Invalid table name format " << tablename << endl;
+ return false;
+ }
+
+ m_ndb->setDatabaseName(split[0].c_str());
+ m_ndb->setSchemaName(split[1].c_str());
+
+ NdbDictionary::Dictionary* dict = m_ndb->getDictionary();
+ const NdbDictionary::Table* tab = dict->getTable(split[2].c_str());
+ if(tab == 0){
+ err << "Unable to find table: " << split[2].c_str() << endl;
+ return false;
+ }
+
+ if(tab->getNoOfColumns() != tableS.m_dictTable->getNoOfColumns())
+ {
+ ndbout_c("m_columns.size %d != %d",tab->getNoOfColumns(),
+ tableS.m_dictTable->getNoOfColumns());
+ return false;
+ }
+
+ for(int i = 0; i<tab->getNoOfColumns(); i++)
+ {
+ if(!tab->getColumn(i)->equal(*(tableS.m_dictTable->getColumn(i))))
+ {
+ ndbout_c("m_columns %s != %s",tab->getColumn(i)->getName(),
+ tableS.m_dictTable->getColumn(i)->getName());
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool
+BackupRestore::createSystable(const TableS & tables){
+ if (!m_restore && !m_restore_meta && !m_restore_epoch)
+ return true;
+ const char *tablename = tables.getTableName();
+
+ if( strcmp(tablename, NDB_REP_DB "/def/" NDB_APPLY_TABLE) != 0 &&
+ strcmp(tablename, NDB_REP_DB "/def/" NDB_SCHEMA_TABLE) != 0 )
+ {
+ return true;
+ }
+
+ BaseString tmp(tablename);
+ Vector<BaseString> split;
+ if(tmp.split(split, "/") != 3){
+ err << "Invalid table name format " << tablename << endl;
+ return false;
+ }
+
+ m_ndb->setDatabaseName(split[0].c_str());
+ m_ndb->setSchemaName(split[1].c_str());
+
+ NdbDictionary::Dictionary* dict = m_ndb->getDictionary();
+ if( dict->getTable(split[2].c_str()) != NULL ){
+ return true;
+ }
+ return table(tables);
+}
+
+bool
BackupRestore::table(const TableS & table){
if (!m_restore && !m_restore_meta)
return true;
const char * name = table.getTableName();
-
+
/**
* Ignore blob tables
*/
@@ -197,7 +805,7 @@
return true;
const NdbTableImpl & tmptab = NdbTableImpl::getImpl(* table.m_dictTable);
- if(tmptab.m_indexType != NdbDictionary::Index::Undefined){
+ if ((int) tmptab.m_indexType != (int) NdbDictionary::Index::Undefined){
m_indexes.push_back(table.m_dictTable);
return true;
}
@@ -213,10 +821,53 @@
m_ndb->setSchemaName(split[1].c_str());
NdbDictionary::Dictionary* dict = m_ndb->getDictionary();
- if(m_restore_meta){
+ if(m_restore_meta)
+ {
NdbDictionary::Table copy(*table.m_dictTable);
copy.setName(split[2].c_str());
+ Uint32 id;
+ if (copy.getTablespace(&id))
+ {
+ debug << "Connecting " << name << " to tablespace oldid: " << id << flush;
+ NdbDictionary::Tablespace* ts = m_tablespaces[id];
+ debug << " newid: " << ts->getObjectId() << endl;
+ copy.setTablespace(* ts);
+ }
+
+ if (copy.getDefaultNoPartitionsFlag())
+ {
+ /*
+ Table was defined with default number of partitions. We can restore
+ it with whatever is the default in this cluster.
+ We use the max_rows parameter in calculating the default number.
+ */
+ Uint32 no_nodes = m_cluster_connection->no_db_nodes();
+ copy.setFragmentCount(get_no_fragments(copy.getMaxRows(),
+ no_nodes));
+ set_default_nodegroups(©);
+ }
+ else
+ {
+ /*
+ Table was defined with specific number of partitions. It should be
+ restored with the same number of partitions. It will either be
+ restored in the same node groups as when backup was taken or by
+ using a node group map supplied to the ndb_restore program.
+ */
+ Uint16 *ng_array = (Uint16*)copy.getFragmentData();
+ Uint16 no_parts = copy.getFragmentCount();
+ if (map_nodegroups(ng_array, no_parts))
+ {
+ if (translate_frm(©))
+ {
+ err << "Create table " << table.getTableName() << " failed: ";
+ err << "Translate frm error" << endl;
+ return false;
+ }
+ }
+ copy.setFragmentData((const void *)ng_array, no_parts << 1);
+ }
/*
update min and max rows to reflect the table, this to
@@ -231,7 +882,20 @@
if (dict->createTable(copy) == -1)
{
err << "Create table `" << table.getTableName() << "` failed: "
- << dict->getNdbError() << endl;
+ << dict->getNdbError() << endl;
+ if (dict->getNdbError().code == 771)
+ {
+ /*
+ The user on the cluster where the backup was created had specified
+ specific node groups for partitions. Some of these node groups
+ didn't exist on this cluster. We will warn the user of this and
+ inform him of his option.
+ */
+ err << "The node groups defined in the table didn't exist in this";
+ err << " cluster." << endl << "There is an option to use the";
+ err << " the parameter ndb-nodegroup-map to define a mapping from";
+ err << endl << "the old nodegroups to new nodegroups" << endl;
+ }
return false;
}
info << "Successfully restored table `"
@@ -243,6 +907,50 @@
err << "Unable to find table: `" << split[2].c_str() << "`" << endl;
return false;
}
+ if(m_restore_meta)
+ {
+ if (tab->getFrmData())
+ {
+ // a MySQL Server table is restored, thus an event should be created
+ BaseString event_name("REPL$");
+ event_name.append(split[0].c_str());
+ event_name.append("/");
+ event_name.append(split[2].c_str());
+
+ NdbDictionary::Event my_event(event_name.c_str());
+ my_event.setTable(*tab);
+ my_event.addTableEvent(NdbDictionary::Event::TE_ALL);
+
+ // add all columns to the event
+ bool has_blobs = false;
+ for(int a= 0; a < tab->getNoOfColumns(); a++)
+ {
+ my_event.addEventColumn(a);
+ NdbDictionary::Column::Type t = tab->getColumn(a)->getType();
+ if (t == NdbDictionary::Column::Blob ||
+ t == NdbDictionary::Column::Text)
+ has_blobs = true;
+ }
+ if (has_blobs)
+ my_event.mergeEvents(true);
+
+ while ( dict->createEvent(my_event) ) // Add event to database
+ {
+ if (dict->getNdbError().classification == NdbError::SchemaObjectExists)
+ {
+ info << "Event for table " << table.getTableName()
+ << " already exists, removing.\n";
+ if (!dict->dropEvent(my_event.getName()))
+ continue;
+ }
+ err << "Create table event for " << table.getTableName() << " failed: "
+ << dict->getNdbError() << endl;
+ dict->dropTable(split[2].c_str());
+ return false;
+ }
+ info << "Successfully restored table event " << event_name << endl ;
+ }
+ }
const NdbDictionary::Table* null = 0;
m_new_tables.fill(table.m_dictTable->getTableId(), null);
m_new_tables[table.m_dictTable->getTableId()] = tab;
@@ -313,7 +1021,7 @@
return true;
}
-void BackupRestore::tuple(const TupleS & tup)
+void BackupRestore::tuple(const TupleS & tup, Uint32 fragmentId)
{
if (!m_restore)
return;
@@ -333,6 +1041,7 @@
m_free_callback = cb->next;
cb->retries = 0;
+ cb->fragId = fragmentId;
cb->tup = tup; // must do copy!
tuple_a(cb);
@@ -340,6 +1049,7 @@
void BackupRestore::tuple_a(restore_callback_t *cb)
{
+ Uint32 partition_id = cb->fragId;
while (cb->retries < 10)
{
/**
@@ -353,6 +1063,7 @@
m_ndb->sendPollNdb(3000, 1);
continue;
}
+ err << "Cannot start transaction" << endl;
exitHandler();
} // if
@@ -365,6 +1076,7 @@
{
if (errorHandler(cb))
continue;
+ err << "Cannot get operation: " << cb->connection->getNdbError() << endl;
exitHandler();
} // if
@@ -372,9 +1084,37 @@
{
if (errorHandler(cb))
continue;
+ err << "Error defining op: " << cb->connection->getNdbError() << endl;
exitHandler();
} // if
-
+
+ if (table->getFragmentType() == NdbDictionary::Object::UserDefined)
+ {
+ if (table->getDefaultNoPartitionsFlag())
+ {
+ /*
+ This can only happen for HASH partitioning with
+ user defined hash function where user hasn't
+ specified the number of partitions and we
+ have to calculate it. We use the hash value
+ stored in the record to calculate the partition
+ to use.
+ */
+ int i = tup.getNoOfAttributes() - 1;
+ const AttributeData *attr_data = tup.getData(i);
+ Uint32 hash_value = *attr_data->u_int32_value;
+ op->setPartitionId(get_part_id(table, hash_value));
+ }
+ else
+ {
+ /*
+ Either RANGE or LIST (with or without subparts)
+ OR HASH partitioning with user defined hash
+ function but with fixed set of partitions.
+ */
+ op->setPartitionId(partition_id);
+ }
+ }
int ret = 0;
for (int j = 0; j < 2; j++)
{
@@ -385,11 +1125,11 @@
int size = attr_desc->size;
int arraySize = attr_desc->arraySize;
char * dataPtr = attr_data->string_value;
- Uint32 length = (size * arraySize) / 8;
-
+ Uint32 length = attr_data->size;
+
if (j == 0 && tup.getTable()->have_auto_inc(i))
tup.getTable()->update_max_auto_val(dataPtr,size);
-
+
if (attr_desc->m_column->getPrimaryKey())
{
if (j == 1) continue;
@@ -417,6 +1157,7 @@
{
if (errorHandler(cb))
continue;
+ err << "Error defining op: " << cb->connection->getNdbError() << endl;
exitHandler();
}
@@ -489,9 +1230,9 @@
switch(error.status)
{
case NdbError::Success:
+ err << "Success error: " << error << endl;
return false;
// ERROR!
- break;
case NdbError::TemporaryError:
err << "Temporary error: " << error << endl;
@@ -499,21 +1240,19 @@
NdbSleep_MilliSleep(sleepTime);
return true;
// RETRY
- break;
case NdbError::UnknownResult:
- err << error << endl;
+ err << "Unknown: " << error << endl;
return false;
// ERROR!
- break;
default:
case NdbError::PermanentError:
//ERROR
- err << error << endl;
+ err << "Permanent: " << error << endl;
return false;
- break;
}
+ err << "No error status" << endl;
return false;
}
@@ -547,6 +1286,37 @@
tuple_free();
}
+#ifdef NOT_USED
+static bool use_part_id(const NdbDictionary::Table *table)
+{
+ if (table->getDefaultNoPartitionsFlag() &&
+ (table->getFragmentType() == NdbDictionary::Object::UserDefined))
+ return false;
+ else
+ return true;
+}
+#endif
+
+static Uint32 get_part_id(const NdbDictionary::Table *table,
+ Uint32 hash_value)
+{
+ Uint32 no_frags = table->getFragmentCount();
+
+ if (table->getLinearFlag())
+ {
+ Uint32 part_id;
+ Uint32 mask = 1;
+ while (no_frags > mask) mask <<= 1;
+ mask--;
+ part_id = hash_value & mask;
+ if (part_id >= no_frags)
+ part_id = hash_value & (mask >> 1);
+ return part_id;
+ }
+ else
+ return (hash_value % no_frags);
+}
+
void
BackupRestore::logEntry(const LogEntry & tup)
{
@@ -592,7 +1362,19 @@
err << "Error defining op: " << trans->getNdbError() << endl;
exitHandler();
} // if
-
+
+ if (table->getFragmentType() == NdbDictionary::Object::UserDefined)
+ {
+ if (table->getDefaultNoPartitionsFlag())
+ {
+ const AttributeS * attr = tup[tup.size()-1];
+ Uint32 hash_value = *(Uint32*)attr->Data.string_value;
+ op->setPartitionId(get_part_id(table, hash_value));
+ }
+ else
+ op->setPartitionId(tup.m_frag_id);
+ }
+
Bitmask<4096> keys;
for (Uint32 i= 0; i < tup.size(); i++)
{
@@ -758,3 +1540,5 @@
template class Vector<NdbDictionary::Table*>;
template class Vector<const NdbDictionary::Table*>;
+template class Vector<NdbDictionary::Tablespace*>;
+template class Vector<NdbDictionary::LogfileGroup*>;
--- 1.19/mysql-test/r/ndb_restore.result 2006-07-07 00:17:51 +02:00
+++ 1.20/mysql-test/r/ndb_restore.result 2007-04-12 11:12:40 +02:00
@@ -16,7 +16,7 @@
`descrpooppo` varchar(64) default NULL,
`svcutonsa` varchar(64) NOT NULL default '',
PRIMARY KEY (`capgotod`),
-KEY `i_quadaddsvr` (`gotod`)
+KEY `i quadaddsvr` (`gotod`)
) ENGINE=ndbcluster DEFAULT CHARSET=latin1;
INSERT INTO `t2_c` VALUES (5,4,'','q3.net','addavp:MK_CASELECTOR=1','postorod rattoaa'),(2,1,'4','','addavp:MK_BRANDTAD=345','REDS Brandtad'),(3,2,'4','q3.net','execorder','fixedRatediPO REDS'),(1,1,'3','','addavp:MK_BRANDTAD=123','TEST Brandtad'),(6,5,'','told.q3.net','addavp:MK_BRANDTAD=123','Brandtad Toldzone'),(4,3,'3','q3.net','addavp:MK_POOLHINT=2','ratedi PO TEST');
CREATE TABLE `t3_c` (
--- 1.23/mysql-test/t/ndb_restore.test 2006-07-07 00:17:51 +02:00
+++ 1.24/mysql-test/t/ndb_restore.test 2007-04-12 11:12:40 +02:00
@@ -15,7 +15,10 @@
PRIMARY KEY (`capgoaledatta`,`goaledatta`,`maturegarbagefa`)
) ENGINE=ndbcluster DEFAULT CHARSET=latin1;
INSERT INTO `t1_c` VALUES (2,'3','q3plus.qt'),(4,'4','q3plus.qt'),(1,'3','q3.net'),(3,'4','q3.net'),(3,'20','threetrees.qt');
-
+#
+# Bug #27758 Restoring NDB backups makes table usable in SQL nodes
+# - space in key made table unusable after restore
+#
CREATE TABLE `t2_c` (
`capgotod` smallint(5) unsigned NOT NULL auto_increment,
`gotod` smallint(5) unsigned NOT NULL default '0',
@@ -24,7 +27,7 @@
`descrpooppo` varchar(64) default NULL,
`svcutonsa` varchar(64) NOT NULL default '',
PRIMARY KEY (`capgotod`),
- KEY `i_quadaddsvr` (`gotod`)
+ KEY `i quadaddsvr` (`gotod`)
) ENGINE=ndbcluster DEFAULT CHARSET=latin1;
INSERT INTO `t2_c` VALUES (5,4,'','q3.net','addavp:MK_CASELECTOR=1','postorod rattoaa'),(2,1,'4','','addavp:MK_BRANDTAD=345','REDS Brandtad'),(3,2,'4','q3.net','execorder','fixedRatediPO REDS'),(1,1,'3','','addavp:MK_BRANDTAD=123','TEST Brandtad'),(6,5,'','told.q3.net','addavp:MK_BRANDTAD=123','Brandtad Toldzone'),(4,3,'3','q3.net','addavp:MK_POOLHINT=2','ratedi PO TEST');
| Thread |
|---|
| • bk commit into 5.1 tree (tomas:1.2577) | tomas | 12 Apr |