#At file:///home/msvensson/mysql/6.4/
2763 Magnus Svensson 2008-09-15
WL#4350 Extend Config
added:
storage/ndb/src/mgmsrv/testConfig.cpp
modified:
storage/ndb/src/mgmsrv/Config.cpp
storage/ndb/src/mgmsrv/Config.hpp
storage/ndb/src/mgmsrv/ConfigInfo.cpp
storage/ndb/src/mgmsrv/Makefile.am
per-file messages:
storage/ndb/src/mgmsrv/Config.cpp
Add functions for diff, printing the diff and detecting if a config change is illegal
Add utility functions for set/get generation
Add wrapper for 'pack'
storage/ndb/src/mgmsrv/Config.hpp
Add functions for diff, printing the diff and detecting if a config change is illegal
Add utility functions for set/get generation
Add wrapper for 'pack'
storage/ndb/src/mgmsrv/ConfigInfo.cpp
Add missing initializer of m_section_name
storage/ndb/src/mgmsrv/Makefile.am
Add test program for config to be built ad testConfig
storage/ndb/src/mgmsrv/testConfig.cpp
Test program for Config
=== modified file 'storage/ndb/src/mgmsrv/Config.cpp'
--- a/storage/ndb/src/mgmsrv/Config.cpp 2008-07-29 14:04:27 +0000
+++ b/storage/ndb/src/mgmsrv/Config.cpp 2008-09-15 11:04:42 +0000
@@ -20,12 +20,25 @@
#include "ConfigInfo.hpp"
+static void require(bool b)
+{
+ if (!b)
+ abort();
+}
+
+
Config::Config(struct ndb_mgm_configuration *config_values) :
m_configValues(config_values)
{
}
+Config::Config(ConfigValues *config_values) :
+ m_configValues((struct ndb_mgm_configuration*)config_values)
+{
+}
+
+
Config::~Config() {
if(m_configValues != 0){
free(m_configValues);
@@ -47,7 +60,7 @@ Config::print() const {
for(unsigned i= 0; i < num_sections; i++) {
unsigned section= sections[i];
- ndb_mgm_configuration_iterator it(*m_configValues, section);
+ ConfigIter it(this, section);
if (it.first())
continue;
@@ -81,3 +94,552 @@ Config::print() const {
}
}
}
+
+
+
+Uint32
+Config::getGeneration() const
+{
+ Uint32 generation;
+ ConfigIter iter(this, CFG_SECTION_SYSTEM);
+
+ if (iter.get(CFG_SYS_CONFIG_GENERATION, &generation))
+ return 0;
+
+ return generation;
+}
+
+
+
+bool
+Config::setValue(Uint32 section, Uint32 section_no,
+ Uint32 id, Uint32 new_val)
+{
+ ConfigValues::Iterator iter(m_configValues->m_config);
+ if (iter.openSection(section, section_no)){
+ if (!iter.set(id, new_val))
+ return false;
+ }
+ else
+ {
+ ConfigValuesFactory cf(&m_configValues->m_config);
+ if (!cf.openSection(section, section_no))
+ return false;
+ if (!cf.put(CFG_TYPE_OF_SECTION, section))
+ return false;
+ if (!cf.put(id, new_val))
+ return false;
+ cf.closeSection();
+
+ m_configValues= (struct ndb_mgm_configuration*)cf.getConfigValues();
+ }
+
+ return true;
+}
+
+
+bool
+Config::setGeneration(Uint32 new_gen)
+{
+ return setValue(CFG_SECTION_SYSTEM, 0,
+ CFG_SYS_CONFIG_GENERATION,
+ new_gen);
+}
+
+
+Uint32
+Config::pack(UtilBuffer& buf) const
+{
+ return m_configValues->m_config.pack(buf);
+}
+
+
+
+enum diff_types {
+ DT_DIFF, // Value differed
+ DT_MISSING_VALUE, // Value didn't exist
+ DT_MISSING_SECTION, // Section missing
+ DT_ILLEGAL_CHANGE // Illegal change detected
+};
+
+
+static void
+add_diff(const char* name, const char* key,
+ Properties& diff,
+ const char* value_name, Properties* value)
+{
+
+ Properties *section;
+ // Create a new section if it did not exist
+ if (!diff.getCopy(key, §ion)){
+ Properties new_section(true);
+ new_section.put("Key", key);
+ new_section.put("Name", name);
+
+ require(diff.put(key, &new_section));
+
+ // Get copy of section
+ require(diff.getCopy(key, §ion));
+ }
+
+ // Make sure type of diff has been set
+ Uint32 type;
+ require(value->get("Type", &type));
+
+ // Add the value to the section if not already added
+ if (!section->put(value_name, value))
+ require(section->getPropertiesErrno() ==
+ E_PROPERTIES_ELEMENT_ALREADY_EXISTS);
+
+ // Put the updated section into the diff
+ require(diff.put(key, section, true));
+}
+
+
+static void
+compare_value(const char* name, const char* key,
+ const ConfigInfo::ParamInfo* pinfo,
+ ndb_mgm_configuration_iterator& it,
+ ndb_mgm_configuration_iterator& it2,
+ Properties& diff)
+{
+ Uint32 pid= pinfo->_paramId;
+ {
+ Uint32 val;
+ if (it.get(pid, &val) == 0) {
+ Uint32 val2;
+ if (it2.get(pid, &val2) == 0) {
+ if (val != val2){
+ Properties info(true);
+ info.put("Type", DT_DIFF);
+ info.put("New", val2);
+ info.put("Old", val);
+ add_diff(name, key,
+ diff,
+ pinfo->_fname, &info);
+ }
+ }
+ else
+ {
+ Properties info(true);
+ info.put("Type", DT_MISSING_VALUE);
+ info.put("Old", val);
+ add_diff(name, key,
+ diff,
+ pinfo->_fname, &info);
+ }
+ return;
+ }
+ }
+
+ {
+ Uint64 val;
+ if (it.get(pid, &val) == 0) {
+ Uint64 val2;
+ if (it2.get(pid, &val2) == 0) {
+ if (val != val2) {
+ Properties info(true);
+ info.put("Type", DT_DIFF);
+ info.put("New", val2);
+ info.put("Old", val);
+ add_diff(name, key,
+ diff,
+ pinfo->_fname, &info);
+ }
+ }
+ else
+ {
+ Properties info(true);
+ info.put("Type", DT_MISSING_VALUE);
+ info.put("Old", val);
+ add_diff(name, key,
+ diff,
+ pinfo->_fname, &info);
+ }
+ return;
+ }
+ }
+
+ {
+ const char* val;
+ if (it.get(pid, &val) == 0) {
+ const char* val2;
+ if (it2.get(pid, &val2) == 0) {
+ if (strcmp(val, val2)) {
+ Properties info(true);
+ info.put("Type", DT_DIFF);
+ info.put("New", val2);
+ info.put("Old", val);
+ add_diff(name, key,
+ diff,
+ pinfo->_fname, &info);
+ }
+ }
+ else
+ {
+ Properties info(true);
+ info.put("Type", DT_MISSING_VALUE);
+ info.put("Old", val);
+ add_diff(name, key,
+ diff,
+ pinfo->_fname, &info);
+ }
+ return;
+ }
+ }
+}
+
+
+static void
+diff_system(const Config* a, const Config* b, Properties& diff)
+{
+ ConfigIter itA(a, CFG_SECTION_SYSTEM);
+ ConfigIter itB(b, CFG_SECTION_SYSTEM);
+
+ // Check each possible configuration value
+ const ConfigInfo::ParamInfo* pinfo= NULL;
+ ConfigInfo::ParamInfoIter param_iter(g_info,
+ CFG_SECTION_SYSTEM,
+ CFG_SECTION_SYSTEM);
+ while((pinfo= param_iter.next())) {
+ /* Loop through the section and compare values */
+ compare_value("SYSTEM", "", pinfo, itA, itB, diff);
+ }
+}
+
+
+static void
+diff_nodes(const Config* a, const Config* b, Properties& diff)
+{
+ ConfigIter itA(a, CFG_SECTION_NODE);
+
+ for(;itA.valid(); itA.next())
+ {
+
+ /* Get typ of Node */
+ Uint32 nodeType;
+ require(itA.get(CFG_TYPE_OF_SECTION, &nodeType) == 0);
+
+ BaseString name(g_info.sectionName(CFG_SECTION_NODE, nodeType));
+
+ /* Get NodeId which is "primary key" */
+ Uint32 nodeId;
+ require(itA.get(CFG_NODE_ID, &nodeId) == 0);
+
+ BaseString key;
+ key.assfmt("NodeId=%d", nodeId);
+
+ /* Position itB in the section with same NodeId */
+ ConfigIter itB(b, CFG_SECTION_NODE);
+ if (itB.find(CFG_NODE_ID, nodeId) != 0)
+ {
+ // A whole node has been removed
+ Properties info(true);
+ info.put("Type", DT_MISSING_SECTION);
+ info.put("Why", "Node removed");
+ add_diff(name.c_str(), key.c_str(),
+ diff,
+ "Node removed", &info);
+
+ continue;
+ }
+
+ /* Make sure it has the same node type */
+ Uint32 nodeType2;
+ require(itB.get(CFG_TYPE_OF_SECTION, &nodeType2) == 0);
+ if ((nodeType == NODE_TYPE_DB || nodeType == NODE_TYPE_MGM) &&
+ nodeType != nodeType2)
+ {
+ // DB or MGM node has changed type -> not allowed change
+ Properties info(true);
+ info.put("Type", DT_ILLEGAL_CHANGE);
+ info.put("Why", "Node has changed type");
+ add_diff(name.c_str(), key.c_str(),
+ diff,
+ "Node type changed", &info);
+ continue;
+ }
+
+ // Check each possible configuration value
+ const ConfigInfo::ParamInfo* pinfo= NULL;
+ ConfigInfo::ParamInfoIter param_iter(g_info, CFG_SECTION_NODE, nodeType);
+ while((pinfo= param_iter.next())) {
+ /* Loop through the section and compare values */
+ compare_value(name.c_str(), key.c_str(), pinfo, itA, itB, diff);
+ }
+ }
+}
+
+
+static void
+diff_connections(const Config* a, const Config* b, Properties& diff)
+{
+ ConfigIter itA(a, CFG_SECTION_CONNECTION);
+
+ for(;itA.valid(); itA.next())
+ {
+ /* Get typ of connection */
+ Uint32 connectionType;
+ require(itA.get(CFG_TYPE_OF_SECTION, &connectionType) == 0);
+
+ BaseString name(g_info.sectionName(CFG_SECTION_CONNECTION, connectionType));
+
+ /* Get NodeId1 and NodeId2 which is "primary key" */
+ Uint32 nodeId1_A, nodeId2_A;
+ require(itA.get(CFG_CONNECTION_NODE_1, &nodeId1_A) == 0);
+ require(itA.get(CFG_CONNECTION_NODE_2, &nodeId2_A) == 0);
+
+ BaseString key;
+ key.assfmt("NodeId1=%d;NodeId2=%d", nodeId1_A, nodeId2_A);
+
+ /* Find the connecton in other config */
+ ConfigIter itB(b, CFG_SECTION_CONNECTION);
+ bool found= false;
+ Uint32 nodeId1_B, nodeId2_B;
+ while(itB.get(CFG_CONNECTION_NODE_1, &nodeId1_B) == 0 &&
+ itB.get(CFG_CONNECTION_NODE_2, &nodeId2_B) == 0)
+ {
+ if (nodeId1_A == nodeId1_B && nodeId2_A == nodeId2_B)
+ {
+ found= true;
+ break;
+ }
+
+ if(itB.next() != 0)
+ break;
+ }
+
+ if (!found)
+ {
+ // A connection has been removed
+ Properties info(true);
+ info.put("Type", DT_MISSING_SECTION);
+ info.put("Why", "Connection removed");
+ add_diff(name.c_str(), key.c_str(),
+ diff,
+ "Connection removed", &info);
+
+ continue;
+ }
+
+ // Check each possible configuration value
+ const ConfigInfo::ParamInfo* pinfo= NULL;
+ ConfigInfo::ParamInfoIter param_iter(g_info,
+ CFG_SECTION_CONNECTION,
+ connectionType);
+ while((pinfo= param_iter.next())) {
+ /* Loop through the section and compare values */
+ compare_value(name.c_str(), key.c_str(), pinfo, itA, itB, diff);
+ }
+ }
+}
+
+
+static bool
+include_section(const unsigned* exclude, unsigned section){
+ if (exclude == NULL)
+ return true;
+
+ while(*exclude){
+ if (*exclude == section)
+ return false;
+ exclude++;
+ }
+ return true;
+}
+
+
+/**
+ Generate a diff list
+*/
+
+void Config::diff(const Config* other, Properties& diff,
+ const unsigned* exclude) const {
+
+ if (include_section(exclude, CFG_SECTION_SYSTEM)) {
+ diff_system(this, other, diff);
+ diff_system(other, this, diff);
+ }
+ if (include_section(exclude, CFG_SECTION_NODE)) {
+ diff_nodes(this, other, diff);
+ diff_nodes(other, this, diff);
+ }
+ if (include_section(exclude, CFG_SECTION_CONNECTION)) {
+ diff_connections(this, other, diff);
+ diff_connections(other, this, diff);
+ }
+}
+
+
+static const char*
+p2s(const Properties* prop, const char* name, BaseString& buf){
+ PropertiesType type;
+ require(prop->getTypeOf(name, &type));
+ switch(type){
+ case PropertiesType_Uint32:
+ {
+ Uint32 val;
+ require(prop->get(name, &val));
+ buf.assfmt("%d", val);
+ break;
+ }
+ case PropertiesType_Uint64:
+ {
+ Uint64 val;
+ require(prop->get(name, &val));
+ buf.assfmt("%lld", val);
+ break;
+ }
+ case PropertiesType_char:
+ {
+ require(prop->get(name, buf));
+ break;
+ }
+ default:
+ require(false);
+ break;
+ }
+ return buf.c_str();
+}
+
+
+const char*
+Config::diff2str(const Properties& diff_list, BaseString& str) const
+{
+ const char* name;
+ Properties::Iterator prop_it(&diff_list);
+ while ((name= prop_it.next())){
+
+ const Properties *node;
+ require(diff_list.get(name, &node));
+
+ require(node->get("Name", &name));
+ str.appfmt("[%s]\n", name);
+
+ BaseString key;
+ require(node->get("Key", key));
+ if (key.length() > 0){
+ Vector<BaseString> keys;
+ key.split(keys, ";");
+ for (unsigned i= 0; i < keys.size(); i++)
+ str.appfmt("%s\n", keys[i].c_str());
+ }
+
+ BaseString buf;
+ Properties::Iterator prop_it2(node);
+ while ((name= prop_it2.next())){
+
+ const Properties *what;
+ if (!node->get(name, &what))
+ continue;
+
+ Uint32 type;
+ require(what->get("Type", &type));
+ switch (type) {
+ case DT_DIFF:
+ {
+ str.appfmt("-%s=%s\n", name, p2s(what, "Old", buf));
+ str.appfmt("+%s=%s\n", name, p2s(what, "New", buf));
+ break;
+ }
+
+ case DT_MISSING_VALUE:
+ {
+ str.appfmt("-%s=%s\n", name, p2s(what, "Old", buf));
+ break;
+ }
+
+ case DT_MISSING_SECTION:
+ {
+ const char* why;
+ if (what->get("Why", &why))
+ str.appfmt("%s\n", why);
+ break;
+ }
+
+ case DT_ILLEGAL_CHANGE:
+ {
+ const char* why;
+ str.appfmt("Illegal change\n");
+ if (what->get("Why", &why))
+ str.appfmt("%s\n", why);
+ break;
+ }
+
+ default:
+ str.appfmt("Illegal 'type' found in diff_list\n");
+ require(false);
+ break;
+ }
+ }
+ str.appfmt("\n");
+ }
+ return str.c_str();
+}
+
+
+void Config::print_diff(const Config* other) const {
+ Properties diff_list;
+ diff(other, diff_list);
+ BaseString str;
+ ndbout_c("%s", diff2str(diff_list, str));
+}
+
+
+const char*
+Config::diff2str(const Config* other, BaseString& str) const {
+ Properties diff_list;
+ diff(other, diff_list);
+ return diff2str(diff_list, str);
+}
+
+
+bool Config::equal(const Properties& diff_list) const {
+ int count= 0;
+ Properties::Iterator prop_it(&diff_list);
+ while ((prop_it.next()))
+ count++;
+ return (count == 0);
+}
+
+
+bool Config::equal(const Config* other, const unsigned * exclude) const {
+ Properties diff_list;
+ diff(other, diff_list, exclude);
+ return equal(diff_list);
+}
+
+
+
+bool Config::illegal_change(const Properties& diff_list) const {
+ bool illegal= false;
+ const char* name;
+ Properties::Iterator prop_it(&diff_list);
+ while ((name= prop_it.next())){
+
+ const Properties *node;
+ require(diff_list.get(name, &node));
+
+ Properties::Iterator prop_it2(node);
+ while ((name= prop_it2.next())){
+
+ const Properties *what;
+ if (!node->get(name, &what))
+ continue;
+
+ Uint32 type;
+ require(what->get("Type", &type));
+ if (type == DT_ILLEGAL_CHANGE)
+ illegal= true;
+ }
+ }
+ return illegal;
+}
+
+
+bool Config::illegal_change(const Config* other) const {
+ Properties diff_list;
+ diff(other, diff_list);
+ return illegal_change(diff_list);
+}
+
=== modified file 'storage/ndb/src/mgmsrv/Config.hpp'
--- a/storage/ndb/src/mgmsrv/Config.hpp 2008-07-29 13:38:18 +0000
+++ b/storage/ndb/src/mgmsrv/Config.hpp 2008-09-15 11:04:42 +0000
@@ -32,11 +32,59 @@
class Config {
public:
Config(struct ndb_mgm_configuration *config_values = NULL);
+ Config(ConfigValues* config_values);
virtual ~Config();
void print() const;
+ /*
+ Returns generation of the config
+ 0 => not set(yet), ie. config has never been committed
+ */
+ Uint32 getGeneration() const;
+ bool setGeneration(Uint32);
+
+ /*
+ Pack the config into a UtilBuffer and return it's size in bytes
+ */
+ Uint32 pack(UtilBuffer&) const;
+
+ /*
+ Compare against another config and return a list of
+ differences in a Properties object
+ */
+ void diff(const Config* other, Properties& diff_list,
+ const unsigned* exclude=NULL) const;
+
+ /*
+ Print the difference against another config
+ */
+ void print_diff(const Config* other) const;
+
+ /*
+ Print the difference to string buffer
+ */
+ const char* diff2str(const Config* other, BaseString& str) const;
+
+ /*
+ Determine if changing to the other config is illegal
+ */
+ bool illegal_change(const Config* other) const;
+
+ /*
+ Check if the config is equal to another config
+ */
+ bool equal(const Config*, const unsigned* exclude = NULL) const;
+
struct ndb_mgm_configuration * m_configValues;
+
+private:
+ bool setValue(Uint32 section, Uint32 section_no,
+ Uint32 id, Uint32 new_gen);
+
+ bool illegal_change(const Properties&) const;
+ bool equal(const Properties&) const;
+ const char* diff2str(const Properties&, BaseString& str) const;
};
class ConfigIter : public ndb_mgm_configuration_iterator {
=== modified file 'storage/ndb/src/mgmsrv/ConfigInfo.cpp'
--- a/storage/ndb/src/mgmsrv/ConfigInfo.cpp 2008-09-12 12:55:29 +0000
+++ b/storage/ndb/src/mgmsrv/ConfigInfo.cpp 2008-09-15 11:04:42 +0000
@@ -4420,6 +4420,7 @@ ConfigInfo::ParamInfoIter::ParamInfoIter
Uint32 section,
Uint32 section_type) :
m_info(info),
+ m_section_name(NULL),
m_curr_param(0)
{
/* Find the section's name */
=== modified file 'storage/ndb/src/mgmsrv/Makefile.am'
--- a/storage/ndb/src/mgmsrv/Makefile.am 2008-06-09 10:52:24 +0000
+++ b/storage/ndb/src/mgmsrv/Makefile.am 2008-09-15 11:04:42 +0000
@@ -30,6 +30,15 @@ ndb_mgmd_SOURCES = \
InitConfigFileParser.cpp \
Config.cpp
+
+noinst_PROGRAMS = testConfig
+
+testConfig_SOURCES = \
+ testConfig.cpp \
+ InitConfigFileParser.cpp \
+ ConfigInfo.cpp \
+ Config.cpp
+
INCLUDES_LOC = -I$(top_srcdir)/storage/ndb/src/ndbapi \
-I$(top_srcdir)/storage/ndb/src/mgmapi \
-I$(top_srcdir)/storage/ndb/src/common/mgmcommon \
=== added file 'storage/ndb/src/mgmsrv/testConfig.cpp'
--- a/storage/ndb/src/mgmsrv/testConfig.cpp 1970-01-01 00:00:00 +0000
+++ b/storage/ndb/src/mgmsrv/testConfig.cpp 2008-09-15 11:04:42 +0000
@@ -0,0 +1,166 @@
+#include <ndb_global.h>
+#include "InitConfigFileParser.hpp"
+#include "ConfigInfo.hpp"
+#include "Config.hpp"
+
+my_bool opt_core= 1;
+my_bool opt_ndb_shm= 0;
+
+
+#define CHECK(x) \
+ if (!(x)) {\
+ fprintf(stderr, "testConfig: '"#x"' failed on line %d\n", __LINE__); \
+ exit(1); \
+ }
+
+
+static const ConfigInfo g_info;
+
+/*
+ Create a small config.ini with the given parameter and run
+ it through InitConfigFileParser
+ */
+bool
+check_param(const ConfigInfo::ParamInfo & param)
+{
+
+ FILE* config_file= tmpfile();
+ CHECK(config_file);
+
+ const char* section= g_info.nameToAlias(param._section);
+ if (section == NULL)
+ section= param._section;
+
+ if (param._type == ConfigInfo::CI_SECTION)
+ return true;
+
+ if(param._default == MANDATORY)
+ {
+ // Mandatory parameter
+ return true;
+ }
+ else
+ {
+ fprintf(config_file, "[%s]\n", section);
+ fprintf(config_file, "%s=%s\n", param._fname, param._default);
+ }
+
+ // Fill in lines needed for a minimal config
+ if (strcmp(section, "NDBD") != 0)
+ fprintf(config_file, "[ndbd]\n");
+ if (strcmp(param._fname, "NoOfReplicas") != 0)
+ fprintf(config_file, "NoOfReplicas=1\n");
+
+ if (strcmp(section, "NDB_MGMD") != 0)
+ fprintf(config_file, "[ndb_mgmd]\n");
+ if (strcmp(param._fname, "Hostname") != 0)
+ fprintf(config_file, "HostName=localhost\n");
+
+ if (strcmp(section, "MYSQLD") != 0)
+ fprintf(config_file, "[mysqld]\n");
+
+ rewind(config_file);
+
+ // Run the config file through InitConfigFileParser
+ // throw away the error messages for now.
+ FILE* err_file= tmpfile();
+ InitConfigFileParser parser(err_file);
+ Config* conf = parser.parseConfig(config_file);
+ fclose(config_file);
+ fclose(err_file);
+
+ return (conf != NULL);
+}
+
+
+bool
+check_params(void)
+{
+ bool ok= true;
+ for (int j=0; j<g_info.m_NoOfParams; j++) {
+ const ConfigInfo::ParamInfo & param= g_info.m_ParamInfo[j];
+ if (!check_param(param))
+ {
+ ok= false;
+ }
+ }
+
+ return true; // Ignore ok for now
+}
+
+
+
+Config*
+create_config(const char* first, ...)
+{
+ va_list args;
+
+ FILE* config_file= tmpfile();
+ CHECK(config_file);
+
+ va_start(args, first);
+ const char* str= first;
+ do
+ fprintf(config_file, "%s\n", str);
+ while((str= va_arg(args, const char*)) != NULL);
+ va_end(args);
+
+#if 0
+ rewind(config_file);
+
+ char buf[100];
+ while(fgets(buf, sizeof(buf), config_file))
+ ndbout_c(buf);
+#endif
+
+ rewind(config_file);
+
+ InitConfigFileParser parser;
+ Config* conf = parser.parseConfig(config_file);
+ CHECK(conf);
+ fclose(config_file);
+
+ return conf;
+}
+
+
+
+
+void
+diff_config(void)
+{
+ Config* c1=
+ create_config("[ndbd]", "NoOfReplicas=1",
+ "[ndb_mgmd]", "HostName=localhost",
+ "[mysqld]", NULL);
+ Config* c2=
+ create_config("[ndbd]", "NoOfReplicas=1",
+ "[ndb_mgmd]", "HostName=localhost",
+ "[mysqld]", "[mysqld]", NULL);
+
+ CHECK(c1->equal(c1));
+
+ CHECK(!c1->equal(c2));
+ CHECK(!c2->equal(c1));
+ CHECK(!c2->illegal_change(c1));
+ CHECK(!c1->illegal_change(c2));
+
+
+ ndbout_c("==================");
+ ndbout_c("c1->print_diff(c2)");
+ c1->print_diff(c2);
+ ndbout_c("==================");
+ ndbout_c("c2->print_diff(c1)");
+ c2->print_diff(c1);
+ ndbout_c("==================");
+}
+
+
+int
+main(void){
+ ndbout_c("1..1");
+ diff_config();
+ CHECK(check_params());
+ ndbout_c("ok");
+ exit(0);
+}
| Thread |
|---|
| • bzr commit into mysql-5.1 branch (msvensson:2763) WL#4350 | Magnus Svensson | 15 Sep |