From: Frazer Clement Date: January 11 2012 11:16am Subject: bzr push into mysql-5.1-telco-7.0 branch (frazer.clement:4778 to 4779) Bug#13578660 List-Archive: http://lists.mysql.com/commits/142365 X-Bug: 13578660 Message-Id: <201201111116.q0BBGqIH030634@acsmt358.oracle.com> MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit 4779 Frazer Clement 2012-01-11 Bug#13578660 NDB REPLICATION : CONFLICT DETECTION NOT ENABLED ON ALL CONNECTED MYSQLDS Conflict function setup was using a TABLE* object (MySQLD table representation) to determine the offsets of the resolve column in the table record for NDB$MAX and NDB$OLD, and the primary key column offsets for exceptions table inserts. Conflict function setup is part of binlog setup and occurs as a result of : - Table creation - Table 'discovery' due to observed ndb_schema notifications - Table 'discovery' due to SHOW TABLES - Table 'discovery' at server startup In some of these situations, the calling context has no MySQLD Table* for the table, and so null is passed. As the information to setup conflict detection was not available, it was not set up! Fix Remove the use of a TABLE* when setting up conflict detection. Parts : 1) Store resolve column number in NDB_SHARE rather than a record offset 2) Store exception's table pk attrids in NDB_SHARE rather than record offsets 3) Modify conflict function definition code to use resolve column number and NdbRecord to determine the correct offset. 4) Modify exceptions table insert code to use pk attrids and NdbRecord to determine the correct offsets. 5) Avoid using TABLE* members for error messages etc 6) Remove TABLE* parameter from calls 7) Remove check for TABLE*==NULL Additional items Cleanup/improve reporting of conflict function setup. Use sufficient bits to encode resolve column attrid. Add testcase to verify conflict table setup distribution. added: mysql-test/suite/ndb_rpl/t/show_mysqld_warnings.inc modified: mysql-test/suite/ndb_rpl/r/ndb_rpl_conflict.result mysql-test/suite/ndb_rpl/r/ndb_rpl_rep_error.result mysql-test/suite/ndb_rpl/t/ndb_rpl_conflict.test mysql-test/suite/ndb_rpl/t/ndb_rpl_conflict_epoch.test mysql-test/suite/ndb_rpl/t/ndb_rpl_rep_error.test sql/ha_ndbcluster.cc sql/ha_ndbcluster.h sql/ha_ndbcluster_binlog.cc sql/ha_ndbcluster_binlog.h 4778 Jonas Oreland 2012-01-11 ndb - make various buffers (more) thread-aware. 1) ActiveThreadSync 2) compute_jb_pages modified: storage/ndb/src/kernel/vm/GlobalData.hpp storage/ndb/src/kernel/vm/SimulatedBlock.cpp storage/ndb/src/kernel/vm/mt.cpp === modified file 'mysql-test/suite/ndb_rpl/r/ndb_rpl_conflict.result' --- a/mysql-test/suite/ndb_rpl/r/ndb_rpl_conflict.result 2011-09-01 15:12:11 +0000 +++ b/mysql-test/suite/ndb_rpl/r/ndb_rpl_conflict.result 2012-01-11 11:07:09 +0000 @@ -229,7 +229,51 @@ select server_id, master_server_id, coun server_id master_server_id count a 2 1 1 3 drop table t2_max, t2_max$EX; +drop table t1_old, `t1_old$EX`, t1_max, `t1_max$EX`, t1_max_delete_win, `t1_max_delete_win$EX`; +delete from mysql.ndb_replication; +Test that online table distribution sets up conflict functions and exceptions tables +insert into mysql.ndb_replication values ("test", "t1allsame", 0, 7, "NDB$MAX(X)"); +insert into mysql.ndb_replication values ("test", "t2diffex", 1, 7, "NDB$OLD(X)"); +insert into mysql.ndb_replication values ("test", "t2diffex", 3, 7, "NDB$MAX(X)"); +insert into mysql.ndb_replication values ("test", "t3oneex", 3, 7, "NDB$EPOCH()"); +create table t2diffex$EX ( +server_id int unsigned, +master_server_id int unsigned, +master_epoch bigint unsigned, +count int unsigned, +a int not null, +primary key(server_id, master_server_id, master_epoch, count)) engine ndb; +create table t3oneex$EX ( +server_id int unsigned, +master_server_id int unsigned, +master_epoch bigint unsigned, +count int unsigned, +a int not null, +primary key(server_id, master_server_id, master_epoch, count)) engine ndb; +create table t1allsame(a int primary key, b varchar(200), X int unsigned) engine=ndb; +create table t2diffex(a int primary key, b varchar(200), X int unsigned) engine=ndb; +create table t3oneex(a int primary key, b varchar(200)) engine=ndb; +show variables like 'server_id'; +Variable_name Value +server_id 1 +MySQLD error output for server 1.1 matching pattern %NDB Slave% +right(txt, length(txt) - locate('[',txt) + 1) +[Note] NDB Slave: Table test.t2diffex using conflict_fn NDB$OLD on attribute X. +[Note] NDB Slave: Table test.t2diffex logging exceptions to test.t2diffex$EX +[Note] NDB Slave: Table test.t1allsame using conflict_fn NDB$MAX on attribute X. +[Note] NDB Slave: Table test.t2_max using conflict_fn NDB$MAX on attribute X. +show variables like 'server_id'; +Variable_name Value +server_id 3 +MySQLD error output for server 2.1 matching pattern %NDB Slave% +right(txt, length(txt) - locate('[',txt) + 1) +[Warning] NDB Slave: Table test.t3oneex : No extra row author bits in table. +[Note] NDB Slave: Table test.t3oneex : CFT_NDB_EPOCH[_TRANS], low epoch resolution +[Note] NDB Slave: Table test.t2diffex using conflict_fn NDB$MAX on attribute X. +[Note] NDB Slave: Table test.t2diffex logging exceptions to test.t2diffex$EX +[Note] NDB Slave: Table test.t1allsame using conflict_fn NDB$MAX on attribute X. +[Note] NDB Slave: Table test.t2_max using conflict_fn NDB$MAX on attribute X. +drop table t3oneex, t2diffex, t1allsame, t3oneex$EX, t2diffex$EX; "Cleanup" drop table mysql.ndb_replication; -drop table t1_old, `t1_old$EX`, t1_max, `t1_max$EX`, t1_max_delete_win, `t1_max_delete_win$EX`; include/rpl_end.inc === modified file 'mysql-test/suite/ndb_rpl/r/ndb_rpl_rep_error.result' --- a/mysql-test/suite/ndb_rpl/r/ndb_rpl_rep_error.result 2011-06-16 14:34:56 +0000 +++ b/mysql-test/suite/ndb_rpl/r/ndb_rpl_rep_error.result 2012-01-11 11:07:09 +0000 @@ -15,7 +15,7 @@ delete from mysql.ndb_replication; insert into mysql.ndb_replication values ("test", "t1", 0, NULL, "NDB$MAX(X)"); create table t1 (a int key, X int) engine ndb; Warnings: -Error 1627 Error in parsing conflict function. Message: column 'X' has wrong datatype +Error 1627 Error in parsing conflict function. Message: Column 'X' has wrong datatype drop table t1; delete from mysql.ndb_replication; insert into mysql.ndb_replication values ("test", "t1", 0, NULL, "NDB$MAX()"); === modified file 'mysql-test/suite/ndb_rpl/t/ndb_rpl_conflict.test' --- a/mysql-test/suite/ndb_rpl/t/ndb_rpl_conflict.test 2011-09-01 15:12:11 +0000 +++ b/mysql-test/suite/ndb_rpl/t/ndb_rpl_conflict.test 2012-01-11 11:07:09 +0000 @@ -2,7 +2,7 @@ # Test engine native conflict resolution for ndb # # ---source include/have_ndb.inc +--source include/have_multi_ndb.inc --source include/have_binlog_format_mixed_or_row.inc --source suite/ndb_rpl/ndb_master-slave.inc @@ -307,14 +307,77 @@ select server_id, master_server_id, coun --connection master drop table t2_max, t2_max$EX; +drop table t1_old, `t1_old$EX`, t1_max, `t1_max$EX`, t1_max_delete_win, `t1_max_delete_win$EX`; +delete from mysql.ndb_replication; + +--echo Test that online table distribution sets up conflict functions and exceptions tables + +# t1allsame - Same on all servers, no exceptions table +insert into mysql.ndb_replication values ("test", "t1allsame", 0, 7, "NDB$MAX(X)"); + +# t2diffex - Different on each server with an exceptions table +# Not a recommended configuration! +insert into mysql.ndb_replication values ("test", "t2diffex", 1, 7, "NDB$OLD(X)"); +insert into mysql.ndb_replication values ("test", "t2diffex", 3, 7, "NDB$MAX(X)"); + +# t3oneex - Only on one server with an exceptions table +# Note that it's not defined on the server where it's created (not recommended) +# so on the server where it's defined, we get an error due to having no extra +# author bits +# +insert into mysql.ndb_replication values ("test", "t3oneex", 3, 7, "NDB$EPOCH()"); + +# Create exception tables +create table t2diffex$EX ( + server_id int unsigned, + master_server_id int unsigned, + master_epoch bigint unsigned, + count int unsigned, + a int not null, + primary key(server_id, master_server_id, master_epoch, count)) engine ndb; + +create table t3oneex$EX ( + server_id int unsigned, + master_server_id int unsigned, + master_epoch bigint unsigned, + count int unsigned, + a int not null, + primary key(server_id, master_server_id, master_epoch, count)) engine ndb; +# Now create actual tables on this server (id 1) +create table t1allsame(a int primary key, b varchar(200), X int unsigned) engine=ndb; +create table t2diffex(a int primary key, b varchar(200), X int unsigned) engine=ndb; +create table t3oneex(a int primary key, b varchar(200)) engine=ndb; + +# Now examine server logs to see that conflict detection and +# exceptions tables were setup as expected +show variables like 'server_id'; +--let $server_num=1.1 +--let $pattern=%NDB Slave% +--let $limit=4 +--source suite/ndb_rpl/t/show_mysqld_warnings.inc + + +--connection server2 +--disable_query_log +call mtr.add_suppression("NDB Slave: .* No extra row author bits in table.*"); +--enable_query_log + +show variables like 'server_id'; +--let $server_num=2.1 +--let $pattern=%NDB Slave% +--let $limit=6 + +--source suite/ndb_rpl/t/show_mysqld_warnings.inc + +--connection master +drop table t3oneex, t2diffex, t1allsame, t3oneex$EX, t2diffex$EX; ############### --echo "Cleanup" --connection master drop table mysql.ndb_replication; -drop table t1_old, `t1_old$EX`, t1_max, `t1_max$EX`, t1_max_delete_win, `t1_max_delete_win$EX`; --sync_slave_with_master --source include/rpl_end.inc === modified file 'mysql-test/suite/ndb_rpl/t/ndb_rpl_conflict_epoch.test' --- a/mysql-test/suite/ndb_rpl/t/ndb_rpl_conflict_epoch.test 2011-07-07 14:48:06 +0000 +++ b/mysql-test/suite/ndb_rpl/t/ndb_rpl_conflict_epoch.test 2012-01-11 11:07:09 +0000 @@ -231,6 +231,10 @@ insert into mysql.ndb_replication values ("test", "t3", 0, 7, "NDB\$EPOCH(32)"), ("test", "t4", 0, 7, "NDB\$EPOCH(-1)"); +--disable_query_log +call mtr.add_suppression("NDB Slave: .* Too many extra Gci bits at .*"); +--enable_query_log + --error 1005 create table test.t3 (a int primary key) engine=ndb; show warnings; === modified file 'mysql-test/suite/ndb_rpl/t/ndb_rpl_rep_error.test' --- a/mysql-test/suite/ndb_rpl/t/ndb_rpl_rep_error.test 2011-06-16 14:34:56 +0000 +++ b/mysql-test/suite/ndb_rpl/t/ndb_rpl_rep_error.test 2012-01-11 11:07:09 +0000 @@ -48,6 +48,10 @@ CREATE TABLE mysql.ndb_replication # Non existant conflict_fn # gives error when creating table +--disable_query_log +call mtr.add_suppression("NDB Slave: .* unknown conflict resolution function .*"); +--enable_query_log + insert into mysql.ndb_replication values ("test", "t1", 0, NULL, "NDB$X(X)"); --error 1005 create table t1 (a int key, X int) engine ndb; @@ -56,6 +60,10 @@ delete from mysql.ndb_replication; # Column type cannot be used for this function # gives warning when creating table +--disable_query_log +call mtr.add_suppression("NDB Slave: .* has wrong datatype.*"); +--enable_query_log + insert into mysql.ndb_replication values ("test", "t1", 0, NULL, "NDB$MAX(X)"); create table t1 (a int key, X int) engine ndb; drop table t1; @@ -63,6 +71,10 @@ delete from mysql.ndb_replication; # Too few arguments # gives error when creating table +--disable_query_log +call mtr.add_suppression("NDB Slave: .* missing function argument .*"); +--enable_query_log + insert into mysql.ndb_replication values ("test", "t1", 0, NULL, "NDB$MAX()"); --error 1005 create table t1 (a int key, X int) engine ndb; @@ -71,6 +83,9 @@ delete from mysql.ndb_replication; # Too many arguments # gives error when creating table +--disable_query_log +call mtr.add_suppression("NDB Slave: .* missing \')\' .*"); +--enable_query_log insert into mysql.ndb_replication values ("test", "t1", 0, NULL, "NDB$MAX(X Y)"); --error 1005 create table t1 (a int key, X int) engine ndb; === added file 'mysql-test/suite/ndb_rpl/t/show_mysqld_warnings.inc' --- a/mysql-test/suite/ndb_rpl/t/show_mysqld_warnings.inc 1970-01-01 00:00:00 +0000 +++ b/mysql-test/suite/ndb_rpl/t/show_mysqld_warnings.inc 2012-01-11 11:07:09 +0000 @@ -0,0 +1,10 @@ +--disable_query_log +--echo MySQLD error output for server $server_num matching pattern $pattern +create table errlog (a int auto_increment primary key, txt text) engine=myisam; + +--eval load data local infile "$MYSQLTEST_VARDIR/log/mysqld.$server_num.err" into table errlog (txt); + +--eval select right(txt, length(txt) - locate('[',txt) + 1) from errlog where txt like '$pattern' order by a desc limit $limit; + +drop table errlog; +--enable_query_log === modified file 'sql/ha_ndbcluster.cc' --- a/sql/ha_ndbcluster.cc 2011-12-18 12:19:55 +0000 +++ b/sql/ha_ndbcluster.cc 2012-01-11 11:07:09 +0000 @@ -2199,7 +2199,7 @@ int ha_ndbcluster::get_metadata(THD *thd #ifdef HAVE_NDB_BINLOG ndbcluster_read_binlog_replication(thd, ndb, m_share, m_table, - ::server_id, table, FALSE); + ::server_id, FALSE); #endif DBUG_RETURN(0); @@ -4805,6 +4805,7 @@ ha_ndbcluster::prepare_conflict_detectio { res = conflict_fn->prep_func(m_share->m_cfn_share, op_type, + m_ndb_record, old_data, new_data, table->write_set, @@ -5655,7 +5656,10 @@ handle_row_conflict(NDB_CONFLICT_FN_SHAR for (k= 0; k < nkey; k++) { DBUG_ASSERT(pk_row != NULL); - const uchar* data= pk_row + cfn_share->m_offset[k]; + const uchar* data= + (const uchar*) NdbDictionary::getValuePtr(key_rec, + (const char*) pk_row, + cfn_share->m_key_attrids[k]); if (ex_op->setValue((Uint32)(fixed_cols + k), (const char*)data) == -1) { err= ex_op->getNdbError(); @@ -9599,7 +9603,6 @@ int ha_ndbcluster::create(const char *na m_dbname, m_tabname, ::server_id, - form, &binlog_flags, &conflict_fn, args, @@ -10078,7 +10081,6 @@ cleanup_failed: ndbcluster_apply_binlog_replication_info(thd, share, m_table, - form, conflict_fn, args, num_args, @@ -10518,7 +10520,7 @@ int ha_ndbcluster::rename_table(const ch #ifdef HAVE_NDB_BINLOG if (share) ndbcluster_read_binlog_replication(thd, ndb, share, ndbtab, - ::server_id, NULL, TRUE); + ::server_id, TRUE); #endif /* always create an event for the table */ String event_name(INJECTOR_EVENT_LEN); === modified file 'sql/ha_ndbcluster.h' --- a/sql/ha_ndbcluster.h 2011-11-10 10:35:09 +0000 +++ b/sql/ha_ndbcluster.h 2012-01-11 11:07:09 +0000 @@ -144,11 +144,9 @@ enum enum_conflict_fn_arg_type struct st_conflict_fn_arg { enum_conflict_fn_arg_type type; - const char *ptr; - uint32 len; union { - uint32 fieldno; // CFAT_COLUMN_NAME + char resolveColNameBuff[ NAME_CHAR_LEN + 1 ]; // CFAT_COLUMN_NAME uint32 extraGciBits; // CFAT_EXTRA_GCI_BITS }; }; @@ -176,6 +174,7 @@ enum enum_conflicting_op_type */ typedef int (* prepare_detect_func) (struct st_ndbcluster_conflict_fn_share* cfn_share, enum_conflicting_op_type op_type, + const NdbRecord* data_record, const uchar* old_data, const uchar* new_data, const MY_BITMAP* write_set, @@ -219,16 +218,21 @@ enum enum_conflict_fn_table_flags CFF_REFRESH_ROWS = 1 }; +/* + Maximum supported key parts (16) + (Ndb supports 32, but MySQL has a lower limit) +*/ +static const int NDB_MAX_KEY_PARTS = MAX_REF_PARTS; + typedef struct st_ndbcluster_conflict_fn_share { const st_conflict_fn_def* m_conflict_fn; /* info about original table */ uint8 m_pk_cols; - uint8 m_resolve_column; + uint16 m_resolve_column; uint8 m_resolve_size; uint8 m_flags; - uint16 m_offset[16]; - uint16 m_resolve_offset; + uint16 m_key_attrids[ NDB_MAX_KEY_PARTS ]; const NdbDictionary::Table *m_ex_tab; uint32 m_count; === modified file 'sql/ha_ndbcluster_binlog.cc' --- a/sql/ha_ndbcluster_binlog.cc 2012-01-09 10:49:49 +0000 +++ b/sql/ha_ndbcluster_binlog.cc 2012-01-11 11:07:09 +0000 @@ -3847,7 +3847,6 @@ slave_set_resolve_fn(THD *thd, NDB_SHARE const NDBTAB *ndbtab, uint field_index, uint resolve_col_sz, const st_conflict_fn_def* conflict_fn, - TABLE *table, uint8 flags) { DBUG_ENTER("slave_set_resolve_fn"); @@ -3867,8 +3866,6 @@ slave_set_resolve_fn(THD *thd, NDB_SHARE /* Calculate resolve col stuff (if relevant) */ cfn_share->m_resolve_size= resolve_col_sz; cfn_share->m_resolve_column= field_index; - cfn_share->m_resolve_offset= (uint16)(table->field[field_index]->ptr - - table->record[0]); cfn_share->m_flags = flags; { @@ -3917,8 +3914,11 @@ slave_set_resolve_fn(THD *thd, NDB_SHARE col->getNullable() == ex_col->getNullable(); if (!ok) break; - cfn_share->m_offset[k]= - (uint16)(table->field[i]->ptr - table->record[0]); + /* + Store mapping of Exception table key# to + orig table attrid + */ + cfn_share->m_key_attrids[k]= i; k++; } } @@ -3929,9 +3929,9 @@ slave_set_resolve_fn(THD *thd, NDB_SHARE ndbtab_g.release(); if (opt_ndb_extra_logging) sql_print_information("NDB Slave: Table %s.%s logging exceptions to %s.%s", - table->s->db.str, - table->s->table_name.str, - table->s->db.str, + share->db, + share->table_name, + share->db, ex_tab_name); } else @@ -3964,6 +3964,7 @@ slave_set_resolve_fn(THD *thd, NDB_SHARE int row_conflict_fn_old(st_ndbcluster_conflict_fn_share* cfn_share, enum_conflicting_op_type op_type, + const NdbRecord* data_record, const uchar* old_data, const uchar* new_data, const MY_BITMAP* write_set, @@ -3972,7 +3973,10 @@ row_conflict_fn_old(st_ndbcluster_confli DBUG_ENTER("row_conflict_fn_old"); uint32 resolve_column= cfn_share->m_resolve_column; uint32 resolve_size= cfn_share->m_resolve_size; - const uchar* field_ptr = old_data + cfn_share->m_resolve_offset; + const uchar* field_ptr = (const uchar*) + NdbDictionary::getValuePtr(data_record, + (const char*) old_data, + cfn_share->m_resolve_column); assert((resolve_size == 4) || (resolve_size == 8)); @@ -4040,6 +4044,7 @@ row_conflict_fn_old(st_ndbcluster_confli int row_conflict_fn_max_update_only(st_ndbcluster_conflict_fn_share* cfn_share, enum_conflicting_op_type op_type, + const NdbRecord* data_record, const uchar* old_data, const uchar* new_data, const MY_BITMAP* write_set, @@ -4048,7 +4053,10 @@ row_conflict_fn_max_update_only(st_ndbcl DBUG_ENTER("row_conflict_fn_max_update_only"); uint32 resolve_column= cfn_share->m_resolve_column; uint32 resolve_size= cfn_share->m_resolve_size; - const uchar* field_ptr = new_data + cfn_share->m_resolve_offset; + const uchar* field_ptr = (const uchar*) + NdbDictionary::getValuePtr(data_record, + (const char*) new_data, + cfn_share->m_resolve_column); assert((resolve_size == 4) || (resolve_size == 8)); @@ -4127,6 +4135,7 @@ row_conflict_fn_max_update_only(st_ndbcl int row_conflict_fn_max(st_ndbcluster_conflict_fn_share* cfn_share, enum_conflicting_op_type op_type, + const NdbRecord* data_record, const uchar* old_data, const uchar* new_data, const MY_BITMAP* write_set, @@ -4140,6 +4149,7 @@ row_conflict_fn_max(st_ndbcluster_confli case UPDATE_ROW: return row_conflict_fn_max_update_only(cfn_share, op_type, + data_record, old_data, new_data, write_set, @@ -4151,6 +4161,7 @@ row_conflict_fn_max(st_ndbcluster_confli */ return row_conflict_fn_old(cfn_share, op_type, + data_record, old_data, new_data, write_set, @@ -4179,6 +4190,7 @@ row_conflict_fn_max(st_ndbcluster_confli int row_conflict_fn_max_del_win(st_ndbcluster_conflict_fn_share* cfn_share, enum_conflicting_op_type op_type, + const NdbRecord* data_record, const uchar* old_data, const uchar* new_data, const MY_BITMAP* write_set, @@ -4192,6 +4204,7 @@ row_conflict_fn_max_del_win(st_ndbcluste case UPDATE_ROW: return row_conflict_fn_max_update_only(cfn_share, op_type, + data_record, old_data, new_data, write_set, @@ -4216,6 +4229,7 @@ row_conflict_fn_max_del_win(st_ndbcluste int row_conflict_fn_epoch(st_ndbcluster_conflict_fn_share* cfn_share, enum_conflicting_op_type op_type, + const NdbRecord* data_record, const uchar* old_data, const uchar* new_data, const MY_BITMAP* write_set, @@ -4311,7 +4325,6 @@ parse_conflict_fn_spec(const char* confl const st_conflict_fn_def** conflict_fn, st_conflict_fn_arg* args, Uint32* max_args, - const TABLE* table, char *msg, uint msg_len) { DBUG_ENTER("parse_conflict_fn_spec"); @@ -4402,9 +4415,6 @@ parse_conflict_fn_spec(const char* confl uint len= (uint)(end_arg - start_arg); args[no_args].type= type; - args[no_args].ptr= start_arg; - args[no_args].len= len; - args[no_args].fieldno= (uint32)-1; DBUG_PRINT("info", ("found argument %s %u", start_arg, len)); @@ -4413,20 +4423,11 @@ parse_conflict_fn_spec(const char* confl { case CFAT_COLUMN_NAME: { - /* find column in table */ - DBUG_PRINT("info", ("searching for %s %u", start_arg, len)); - TABLE_SHARE *table_s= table->s; - for (uint j= 0; j < table_s->fields; j++) - { - Field *field= table_s->field[j]; - if (strncmp(start_arg, field->field_name, len) == 0 && - field->field_name[len] == '\0') - { - DBUG_PRINT("info", ("found %s", field->field_name)); - args[no_args].fieldno= j; - break; - } - } + /* Copy column name out into argument's buffer */ + char* dest= &args[no_args].resolveColNameBuff[0]; + + memcpy(dest, start_arg, MIN(len, (uint)NAME_CHAR_LEN)); + dest[len]= '\0'; break; } case CFAT_EXTRA_GCI_BITS: @@ -4488,7 +4489,7 @@ parse_conflict_fn_spec(const char* confl } /* parse error */ my_snprintf(msg, msg_len, "%s, %s at '%s'", - conflict_fn_spec, error_str, ptr); + conflict_fn_spec, error_str, ptr); DBUG_PRINT("info", ("%s", msg)); DBUG_RETURN(-1); } @@ -4497,7 +4498,6 @@ static int setup_conflict_fn(THD *thd, NDB_SHARE *share, const NDBTAB *ndbtab, char *msg, uint msg_len, - TABLE *table, const st_conflict_fn_def* conflict_fn, const st_conflict_fn_arg* args, const Uint32 num_args) @@ -4519,38 +4519,65 @@ setup_conflict_fn(THD *thd, NDB_SHARE *s DBUG_RETURN(-1); } + /* Now try to find the column in the table */ + int colNum = -1; + const char* resolveColName = args[0].resolveColNameBuff; + int resolveColNameLen = strlen(resolveColName); + + for (int j=0; j< ndbtab->getNoOfColumns(); j++) + { + const char* colName = ndbtab->getColumn(j)->getName(); + + if (strncmp(colName, + resolveColName, + resolveColNameLen) == 0 && + colName[resolveColNameLen] == '\0') + { + colNum = j; + break; + } + } + if (colNum == -1) + { + my_snprintf(msg, msg_len, + "Could not find resolve column %s.", + resolveColName); + DBUG_PRINT("info", ("%s", msg)); + DBUG_RETURN(-1); + } + uint resolve_col_sz= 0; if (0 == (resolve_col_sz = - slave_check_resolve_col_type(ndbtab, args[0].fieldno))) + slave_check_resolve_col_type(ndbtab, colNum))) { /* wrong data type */ slave_reset_conflict_fn(share); my_snprintf(msg, msg_len, - "column '%s' has wrong datatype", - table->s->field[args[0].fieldno]->field_name); + "Column '%s' has wrong datatype", + resolveColName); DBUG_PRINT("info", ("%s", msg)); DBUG_RETURN(-1); } if (slave_set_resolve_fn(thd, share, ndbtab, - args[0].fieldno, resolve_col_sz, - conflict_fn, table, CFF_NONE)) + colNum, resolve_col_sz, + conflict_fn, CFF_NONE)) { my_snprintf(msg, msg_len, - "unable to setup conflict resolution using column '%s'", - table->s->field[args[0].fieldno]->field_name); + "Unable to setup conflict resolution using column '%s'", + resolveColName); DBUG_PRINT("info", ("%s", msg)); DBUG_RETURN(-1); } - if (opt_ndb_extra_logging) - { - sql_print_information("NDB Slave: Table %s.%s using conflict_fn %s on attribute %s.", - table->s->db.str, - table->s->table_name.str, - conflict_fn->name, - table->s->field[args[0].fieldno]->field_name); - } + + /* Success, update message */ + my_snprintf(msg, msg_len, + "NDB Slave: Table %s.%s using conflict_fn %s on attribute %s.", + share->db, + share->table_name, + conflict_fn->name, + resolveColName); break; } case CFT_NDB_EPOCH: @@ -4577,7 +4604,9 @@ setup_conflict_fn(THD *thd, NDB_SHARE *s * represent SavePeriod/EpochPeriod */ if (ndbtab->getExtraRowGciBits() == 0) - sql_print_information("Ndb Slave : CFT_NDB_EPOCH[_TRANS], low epoch resolution"); + sql_print_information("NDB Slave: Table %s.%s : CFT_NDB_EPOCH[_TRANS], low epoch resolution", + share->db, + share->table_name); if (ndbtab->getExtraRowAuthorBits() == 0) { @@ -4589,20 +4618,20 @@ setup_conflict_fn(THD *thd, NDB_SHARE *s if (slave_set_resolve_fn(thd, share, ndbtab, 0, // field_no 0, // resolve_col_sz - conflict_fn, table, CFF_REFRESH_ROWS)) + conflict_fn, CFF_REFRESH_ROWS)) { my_snprintf(msg, msg_len, "unable to setup conflict resolution"); DBUG_PRINT("info", ("%s", msg)); DBUG_RETURN(-1); } - if (opt_ndb_extra_logging) - { - sql_print_information("NDB Slave: Table %s.%s using conflict_fn %s.", - table->s->db.str, - table->s->table_name.str, - conflict_fn->name); - } + /* Success, update message */ + my_snprintf(msg, msg_len, + "NDB Slave: Table %s.%s using conflict_fn %s.", + share->db, + share->table_name, + conflict_fn->name); + break; } case CFT_NUMBER_OF_CFTS: @@ -4908,7 +4937,6 @@ ndbcluster_get_binlog_replication_info(T const char* db, const char* table_name, uint server_id, - const TABLE *table, Uint32* binlog_flags, const st_conflict_fn_def** conflict_fn, st_conflict_fn_arg* args, @@ -4956,34 +4984,42 @@ ndbcluster_get_binlog_replication_info(T DBUG_RETURN(ER_NDB_REPLICATION_SCHEMA_ERROR); } - if (table != NULL) + if (conflict_fn_spec != NULL) { - if (conflict_fn_spec != NULL) + char tmp_buf[FN_REFLEN]; + + if (parse_conflict_fn_spec(conflict_fn_spec, + conflict_fn, + args, + num_args, + tmp_buf, + sizeof(tmp_buf)) != 0) { - char tmp_buf[FN_REFLEN]; + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, + ER_CONFLICT_FN_PARSE_ERROR, + ER(ER_CONFLICT_FN_PARSE_ERROR), + tmp_buf); - if (parse_conflict_fn_spec(conflict_fn_spec, - conflict_fn, - args, - num_args, - table, - tmp_buf, - sizeof(tmp_buf)) != 0) + /* + Log as well, useful for contexts where the thd's stack of + warnings are ignored + */ + if (opt_ndb_extra_logging) { - push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, - ER_CONFLICT_FN_PARSE_ERROR, - ER(ER_CONFLICT_FN_PARSE_ERROR), - tmp_buf); - DBUG_RETURN(ER_CONFLICT_FN_PARSE_ERROR); + sql_print_warning("NDB Slave: Table %s.%s : Parse error on conflict fn : %s", + db, table_name, + tmp_buf); } - } - else - { - /* No conflict function specified */ - conflict_fn= NULL; - num_args= 0; + + DBUG_RETURN(ER_CONFLICT_FN_PARSE_ERROR); } } + else + { + /* No conflict function specified */ + conflict_fn= NULL; + num_args= 0; + } DBUG_RETURN(0); } @@ -4992,7 +5028,6 @@ int ndbcluster_apply_binlog_replication_info(THD *thd, NDB_SHARE *share, const NDBTAB* ndbtab, - TABLE* table, const st_conflict_fn_def* conflict_fn, const st_conflict_fn_arg* args, Uint32 num_args, @@ -5013,15 +5048,32 @@ ndbcluster_apply_binlog_replication_info if (setup_conflict_fn(thd, share, ndbtab, tmp_buf, sizeof(tmp_buf), - table, conflict_fn, args, - num_args) != 0) + num_args) == 0) { + if (opt_ndb_extra_logging) + { + sql_print_information("%s", tmp_buf); + } + } + else + { + /* + Dump setup failure message to error log + for cases where thd warning stack is + ignored + */ + sql_print_warning("NDB Slave: Table %s.%s : %s", + share->db, + share->table_name, + tmp_buf); + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, ER_CONFLICT_FN_PARSE_ERROR, ER(ER_CONFLICT_FN_PARSE_ERROR), tmp_buf); + DBUG_RETURN(-1); } } @@ -5039,7 +5091,6 @@ ndbcluster_read_binlog_replication(THD * NDB_SHARE *share, const NDBTAB *ndbtab, uint server_id, - TABLE *table, bool do_set_binlog_flags) { DBUG_ENTER("ndbcluster_read_binlog_replication"); @@ -5052,7 +5103,6 @@ ndbcluster_read_binlog_replication(THD * share->db, share->table_name, server_id, - table, &binlog_flags, &conflict_fn, args, @@ -5060,7 +5110,6 @@ ndbcluster_read_binlog_replication(THD * (ndbcluster_apply_binlog_replication_info(thd, share, ndbtab, - table, conflict_fn, args, num_args, @@ -5236,7 +5285,7 @@ int ndbcluster_create_binlog_setup(THD * /* */ ndbcluster_read_binlog_replication(thd, ndb, share, ndbtab, - ::server_id, NULL, TRUE); + ::server_id, TRUE); #endif /* check if logging turned off for this table === modified file 'sql/ha_ndbcluster_binlog.h' --- a/sql/ha_ndbcluster_binlog.h 2011-11-10 10:35:09 +0000 +++ b/sql/ha_ndbcluster_binlog.h 2012-01-11 11:07:09 +0000 @@ -237,7 +237,6 @@ ndbcluster_get_binlog_replication_info(T const char* db, const char* table_name, uint server_id, - const TABLE *table, Uint32* binlog_flags, const st_conflict_fn_def** conflict_fn, st_conflict_fn_arg* args, @@ -246,7 +245,6 @@ int ndbcluster_apply_binlog_replication_info(THD *thd, NDB_SHARE *share, const NDBTAB* ndbtab, - TABLE* table, const st_conflict_fn_def* conflict_fn, const st_conflict_fn_arg* args, Uint32 num_args, @@ -257,7 +255,6 @@ ndbcluster_read_binlog_replication(THD * NDB_SHARE *share, const NDBTAB *ndbtab, uint server_id, - TABLE *table, bool do_set_binlog_flags); #endif int ndb_create_table_from_engine(THD *thd, const char *db, No bundle (reason: useless for push emails).