diff options
author | unknown <mats@romeo.(none)> | 2006-09-13 19:25:12 +0200 |
---|---|---|
committer | unknown <mats@romeo.(none)> | 2006-09-13 19:25:12 +0200 |
commit | 3936ce19d20e085cb5317d2fc024ee6818e4bbf4 (patch) | |
tree | a66b9bd59add75c92a1ec41646e6f0d3aa5baeb1 | |
parent | d4d01d5906d09ac23ae6f46e71377ea2786505fc (diff) | |
download | mariadb-git-3936ce19d20e085cb5317d2fc024ee6818e4bbf4.tar.gz |
WL#3259 (RBR with more columns on slave than master):
Incorporating changes from review.
Fixing one bug that surfaced.
mysql-test/extra/rpl_tests/rpl_row_tabledefs.test:
Adding tests that UPDATE and DELETE does not generate an error.
mysql-test/r/rpl_row_tabledefs_2myisam.result:
Result change.
mysql-test/r/rpl_row_tabledefs_3innodb.result:
Result change.
mysql-test/t/disabled.def:
Enabling rpl_sp_effects (even though it gives a result mismatch currently).
sql/field.cc:
Using constant to denote undefined last null byte.
sql/field.h:
Using constant to denote undefined last null byte.
Adding documentation.
sql/log_event.cc:
Not generating error for non-NULL no-DEFAULT columns when updating or deleting row.
Better documentation and comments.
sql/rpl_utility.cc:
Moving documentation to header file.
sql/rpl_utility.h:
Documenting class and members.
-rw-r--r-- | mysql-test/extra/rpl_tests/rpl_row_tabledefs.test | 68 | ||||
-rw-r--r-- | mysql-test/r/rpl_row_tabledefs_2myisam.result | 105 | ||||
-rw-r--r-- | mysql-test/r/rpl_row_tabledefs_3innodb.result | 97 | ||||
-rw-r--r-- | mysql-test/t/disabled.def | 1 | ||||
-rw-r--r-- | sql/field.cc | 10 | ||||
-rw-r--r-- | sql/field.h | 31 | ||||
-rw-r--r-- | sql/log_event.cc | 110 | ||||
-rw-r--r-- | sql/rpl_utility.cc | 5 | ||||
-rw-r--r-- | sql/rpl_utility.h | 76 |
9 files changed, 441 insertions, 62 deletions
diff --git a/mysql-test/extra/rpl_tests/rpl_row_tabledefs.test b/mysql-test/extra/rpl_tests/rpl_row_tabledefs.test index b17103d8396..1d39a2c3efd 100644 --- a/mysql-test/extra/rpl_tests/rpl_row_tabledefs.test +++ b/mysql-test/extra/rpl_tests/rpl_row_tabledefs.test @@ -25,6 +25,8 @@ eval CREATE TABLE t3 (a INT PRIMARY KEY, b INT) ENGINE=$engine_type; eval CREATE TABLE t4 (a INT) ENGINE=$engine_type; eval CREATE TABLE t5 (a INT, b INT, c INT) ENGINE=$engine_type; eval CREATE TABLE t6 (a INT, b INT, c INT) ENGINE=$engine_type; +eval CREATE TABLE t7 (a INT NOT NULL) ENGINE=$engine_type; +eval CREATE TABLE t8 (a INT NOT NULL) ENGINE=$engine_type; # Table used to detect that slave is running eval CREATE TABLE t9 (a INT) ENGINE=$engine_type; @@ -53,6 +55,17 @@ ALTER TABLE t5 MODIFY b FLOAT; # ... change the type of the last column of table 't6' ALTER TABLE t6 MODIFY c FLOAT; +# ... add one byte worth of null bytes to the table on the slave +ALTER TABLE t7 ADD e1 INT, ADD e2 INT, ADD e3 INT, ADD e4 INT, + ADD e5 INT, ADD e6 INT, ADD e7 INT, ADD e8 INT; + +# ... add 8 columns that are nullable: t8 will not be entirely +# nullable and have no null bits (just an X bit) +ALTER TABLE t8 ADD e1 INT NOT NULL DEFAULT 0, ADD e2 INT NOT NULL DEFAULT 0, + ADD e3 INT NOT NULL DEFAULT 0, ADD e4 INT NOT NULL DEFAULT 0, + ADD e5 INT NOT NULL DEFAULT 0, ADD e6 INT NOT NULL DEFAULT 0, + ADD e7 INT NOT NULL DEFAULT 0, ADD e8 INT NOT NULL DEFAULT 0; + # Insert some values for tables on slave side. These should not be # modified when the row from the master is applied. INSERT INTO t1_int VALUES (2, 4, 4711); @@ -90,7 +103,7 @@ SELECT a,b,x FROM t1_int; SELECT a,b,HEX(x),HEX(y),HEX(z) FROM t1_bit; SELECT a,b,x FROM t1_char; -# Each of these should generate an error and stop the slave +# Each of these inserts should generate an error and stop the slave connection master; INSERT INTO t9 VALUES (2); @@ -163,8 +176,59 @@ SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; START SLAVE; connection master; +INSERT INTO t9 VALUES (6); +sync_slave_with_master; +--replace_result $MASTER_MYPORT MASTER_PORT +--replace_column 1 # 7 # 8 # 9 # 22 # 23 # 33 # +--query_vertical SHOW SLAVE STATUS + +# Testing some tables extra field that can be null and cannot be null +# (but have default values) + +connection master; +INSERT INTO t7 VALUES (1),(2),(3); +INSERT INTO t8 VALUES (1),(2),(3); +SELECT * FROM t7; +SELECT * FROM t8; +sync_slave_with_master; +SELECT * FROM t7; +SELECT * FROM t8; + +# We will now try to update and then delete a row on the master where +# the extra field on the slave does not have a default value. This +# update should not generate an error even though there is no default +# for the extra column. + +--echo **** On Master **** +connection master; +TRUNCATE t1_nodef; +SET SQL_LOG_BIN=0; +INSERT INTO t1_nodef VALUES (1,2); +INSERT INTO t1_nodef VALUES (2,4); +SET SQL_LOG_BIN=1; +--echo **** On Slave **** +connection slave; +INSERT INTO t1_nodef VALUES (1,2,3); +INSERT INTO t1_nodef VALUES (2,4,6); +--echo **** On Master **** +connection master; +UPDATE t1_nodef SET b=2*b WHERE a=1; +SELECT * FROM t1_nodef; +--echo **** On Slave **** +sync_slave_with_master; +SELECT * FROM t1_nodef; +--echo **** On Master **** +connection master; +DELETE FROM t1_nodef WHERE a=2; +SELECT * FROM t1_nodef; +--echo **** On Slave **** +sync_slave_with_master; +SELECT * FROM t1_nodef; + +--echo **** Cleanup **** +connection master; --disable_warnings DROP TABLE IF EXISTS t1_int,t1_bit,t1_char,t1_nodef; -DROP TABLE IF EXISTS t2,t3,t4,t5,t6,t9; +DROP TABLE IF EXISTS t2,t3,t4,t5,t6,t7,t8,t9; --enable_warnings sync_slave_with_master; diff --git a/mysql-test/r/rpl_row_tabledefs_2myisam.result b/mysql-test/r/rpl_row_tabledefs_2myisam.result index 37559b0412a..ae792a5dc2a 100644 --- a/mysql-test/r/rpl_row_tabledefs_2myisam.result +++ b/mysql-test/r/rpl_row_tabledefs_2myisam.result @@ -16,6 +16,8 @@ CREATE TABLE t3 (a INT PRIMARY KEY, b INT) ENGINE='MyISAM'; CREATE TABLE t4 (a INT) ENGINE='MyISAM'; CREATE TABLE t5 (a INT, b INT, c INT) ENGINE='MyISAM'; CREATE TABLE t6 (a INT, b INT, c INT) ENGINE='MyISAM'; +CREATE TABLE t7 (a INT NOT NULL) ENGINE='MyISAM'; +CREATE TABLE t8 (a INT NOT NULL) ENGINE='MyISAM'; CREATE TABLE t9 (a INT) ENGINE='MyISAM'; ALTER TABLE t1_int ADD x INT DEFAULT 42; ALTER TABLE t1_bit @@ -28,6 +30,12 @@ ALTER TABLE t2 DROP b; ALTER TABLE t4 MODIFY a FLOAT; ALTER TABLE t5 MODIFY b FLOAT; ALTER TABLE t6 MODIFY c FLOAT; +ALTER TABLE t7 ADD e1 INT, ADD e2 INT, ADD e3 INT, ADD e4 INT, +ADD e5 INT, ADD e6 INT, ADD e7 INT, ADD e8 INT; +ALTER TABLE t8 ADD e1 INT NOT NULL DEFAULT 0, ADD e2 INT NOT NULL DEFAULT 0, +ADD e3 INT NOT NULL DEFAULT 0, ADD e4 INT NOT NULL DEFAULT 0, +ADD e5 INT NOT NULL DEFAULT 0, ADD e6 INT NOT NULL DEFAULT 0, +ADD e7 INT NOT NULL DEFAULT 0, ADD e8 INT NOT NULL DEFAULT 0; INSERT INTO t1_int VALUES (2, 4, 4711); INSERT INTO t1_char VALUES (2, 4, 'Foo is a bar'); INSERT INTO t1_bit VALUES (2, 4, b'101', b'11100', b'01'); @@ -151,7 +159,7 @@ Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1514 +Last_Errno 1522 Last_Error Table width mismatch - received 2 columns, test.t2 has 1 columns Skip_Counter 0 Exec_Master_Log_Pos # @@ -189,7 +197,7 @@ Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1514 +Last_Errno 1522 Last_Error Column 0 type mismatch - received type 3, test.t4 has type 4 Skip_Counter 0 Exec_Master_Log_Pos # @@ -227,7 +235,7 @@ Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1514 +Last_Errno 1522 Last_Error Column 1 type mismatch - received type 3, test.t5 has type 4 Skip_Counter 0 Exec_Master_Log_Pos # @@ -265,7 +273,7 @@ Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table -Last_Errno 1514 +Last_Errno 1522 Last_Error Column 2 type mismatch - received type 3, test.t6 has type 4 Skip_Counter 0 Exec_Master_Log_Pos # @@ -282,5 +290,92 @@ Master_SSL_Key Seconds_Behind_Master # SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; START SLAVE; +INSERT INTO t9 VALUES (6); +SHOW SLAVE STATUS; +Slave_IO_State # +Master_Host 127.0.0.1 +Master_User root +Master_Port MASTER_PORT +Connect_Retry 1 +Master_Log_File master-bin.000001 +Read_Master_Log_Pos # +Relay_Log_File # +Relay_Log_Pos # +Relay_Master_Log_File master-bin.000001 +Slave_IO_Running Yes +Slave_SQL_Running Yes +Replicate_Do_DB +Replicate_Ignore_DB +Replicate_Do_Table +Replicate_Ignore_Table +Replicate_Wild_Do_Table +Replicate_Wild_Ignore_Table +Last_Errno 0 +Last_Error +Skip_Counter 0 +Exec_Master_Log_Pos # +Relay_Log_Space # +Until_Condition None +Until_Log_File +Until_Log_Pos 0 +Master_SSL_Allowed No +Master_SSL_CA_File +Master_SSL_CA_Path +Master_SSL_Cert +Master_SSL_Cipher +Master_SSL_Key +Seconds_Behind_Master # +INSERT INTO t7 VALUES (1),(2),(3); +INSERT INTO t8 VALUES (1),(2),(3); +SELECT * FROM t7; +a +1 +2 +3 +SELECT * FROM t8; +a +1 +2 +3 +SELECT * FROM t7; +a e1 e2 e3 e4 e5 e6 e7 e8 +1 NULL NULL NULL NULL NULL NULL NULL NULL +2 NULL NULL NULL NULL NULL NULL NULL NULL +3 NULL NULL NULL NULL NULL NULL NULL NULL +SELECT * FROM t8; +a e1 e2 e3 e4 e5 e6 e7 e8 +1 0 0 0 0 0 0 0 0 +2 0 0 0 0 0 0 0 0 +3 0 0 0 0 0 0 0 0 +**** On Master **** +TRUNCATE t1_nodef; +SET SQL_LOG_BIN=0; +INSERT INTO t1_nodef VALUES (1,2); +INSERT INTO t1_nodef VALUES (2,4); +SET SQL_LOG_BIN=1; +**** On Slave **** +INSERT INTO t1_nodef VALUES (1,2,3); +INSERT INTO t1_nodef VALUES (2,4,6); +**** On Master **** +UPDATE t1_nodef SET b=2*b WHERE a=1; +SELECT * FROM t1_nodef; +a b +1 4 +2 4 +**** On Slave **** +SELECT * FROM t1_nodef; +a b x +1 4 3 +2 4 6 +**** On Master **** +DELETE FROM t1_nodef WHERE a=2; +SELECT * FROM t1_nodef; +a b +1 4 +**** On Slave **** +SELECT * FROM t1_nodef; +a b x +1 4 3 +**** Cleanup **** DROP TABLE IF EXISTS t1_int,t1_bit,t1_char,t1_nodef; -DROP TABLE IF EXISTS t2,t3,t4,t5,t6,t9; +DROP TABLE IF EXISTS t2,t3,t4,t5,t6,t7,t8,t9; diff --git a/mysql-test/r/rpl_row_tabledefs_3innodb.result b/mysql-test/r/rpl_row_tabledefs_3innodb.result index 0c1b25ec7fc..b7f0b7b15e2 100644 --- a/mysql-test/r/rpl_row_tabledefs_3innodb.result +++ b/mysql-test/r/rpl_row_tabledefs_3innodb.result @@ -16,6 +16,8 @@ CREATE TABLE t3 (a INT PRIMARY KEY, b INT) ENGINE='InnoDB'; CREATE TABLE t4 (a INT) ENGINE='InnoDB'; CREATE TABLE t5 (a INT, b INT, c INT) ENGINE='InnoDB'; CREATE TABLE t6 (a INT, b INT, c INT) ENGINE='InnoDB'; +CREATE TABLE t7 (a INT NOT NULL) ENGINE='InnoDB'; +CREATE TABLE t8 (a INT NOT NULL) ENGINE='InnoDB'; CREATE TABLE t9 (a INT) ENGINE='InnoDB'; ALTER TABLE t1_int ADD x INT DEFAULT 42; ALTER TABLE t1_bit @@ -28,6 +30,12 @@ ALTER TABLE t2 DROP b; ALTER TABLE t4 MODIFY a FLOAT; ALTER TABLE t5 MODIFY b FLOAT; ALTER TABLE t6 MODIFY c FLOAT; +ALTER TABLE t7 ADD e1 INT, ADD e2 INT, ADD e3 INT, ADD e4 INT, +ADD e5 INT, ADD e6 INT, ADD e7 INT, ADD e8 INT; +ALTER TABLE t8 ADD e1 INT NOT NULL DEFAULT 0, ADD e2 INT NOT NULL DEFAULT 0, +ADD e3 INT NOT NULL DEFAULT 0, ADD e4 INT NOT NULL DEFAULT 0, +ADD e5 INT NOT NULL DEFAULT 0, ADD e6 INT NOT NULL DEFAULT 0, +ADD e7 INT NOT NULL DEFAULT 0, ADD e8 INT NOT NULL DEFAULT 0; INSERT INTO t1_int VALUES (2, 4, 4711); INSERT INTO t1_char VALUES (2, 4, 'Foo is a bar'); INSERT INTO t1_bit VALUES (2, 4, b'101', b'11100', b'01'); @@ -282,5 +290,92 @@ Master_SSL_Key Seconds_Behind_Master # SET GLOBAL SQL_SLAVE_SKIP_COUNTER=2; START SLAVE; +INSERT INTO t9 VALUES (6); +SHOW SLAVE STATUS; +Slave_IO_State # +Master_Host 127.0.0.1 +Master_User root +Master_Port MASTER_PORT +Connect_Retry 1 +Master_Log_File master-bin.000001 +Read_Master_Log_Pos # +Relay_Log_File # +Relay_Log_Pos # +Relay_Master_Log_File master-bin.000001 +Slave_IO_Running Yes +Slave_SQL_Running Yes +Replicate_Do_DB +Replicate_Ignore_DB +Replicate_Do_Table +Replicate_Ignore_Table +Replicate_Wild_Do_Table +Replicate_Wild_Ignore_Table +Last_Errno 0 +Last_Error +Skip_Counter 0 +Exec_Master_Log_Pos # +Relay_Log_Space # +Until_Condition None +Until_Log_File +Until_Log_Pos 0 +Master_SSL_Allowed No +Master_SSL_CA_File +Master_SSL_CA_Path +Master_SSL_Cert +Master_SSL_Cipher +Master_SSL_Key +Seconds_Behind_Master # +INSERT INTO t7 VALUES (1),(2),(3); +INSERT INTO t8 VALUES (1),(2),(3); +SELECT * FROM t7; +a +1 +2 +3 +SELECT * FROM t8; +a +1 +2 +3 +SELECT * FROM t7; +a e1 e2 e3 e4 e5 e6 e7 e8 +1 NULL NULL NULL NULL NULL NULL NULL NULL +2 NULL NULL NULL NULL NULL NULL NULL NULL +3 NULL NULL NULL NULL NULL NULL NULL NULL +SELECT * FROM t8; +a e1 e2 e3 e4 e5 e6 e7 e8 +1 0 0 0 0 0 0 0 0 +2 0 0 0 0 0 0 0 0 +3 0 0 0 0 0 0 0 0 +**** On Master **** +TRUNCATE t1_nodef; +SET SQL_LOG_BIN=0; +INSERT INTO t1_nodef VALUES (1,2); +INSERT INTO t1_nodef VALUES (2,4); +SET SQL_LOG_BIN=1; +**** On Slave **** +INSERT INTO t1_nodef VALUES (1,2,3); +INSERT INTO t1_nodef VALUES (2,4,6); +**** On Master **** +UPDATE t1_nodef SET b=2*b WHERE a=1; +SELECT * FROM t1_nodef; +a b +1 4 +2 4 +**** On Slave **** +SELECT * FROM t1_nodef; +a b x +1 4 3 +2 4 6 +**** On Master **** +DELETE FROM t1_nodef WHERE a=2; +SELECT * FROM t1_nodef; +a b +1 4 +**** On Slave **** +SELECT * FROM t1_nodef; +a b x +1 4 3 +**** Cleanup **** DROP TABLE IF EXISTS t1_int,t1_bit,t1_char,t1_nodef; -DROP TABLE IF EXISTS t2,t3,t4,t5,t6,t9; +DROP TABLE IF EXISTS t2,t3,t4,t5,t6,t7,t8,t9; diff --git a/mysql-test/t/disabled.def b/mysql-test/t/disabled.def index f1322fcb699..a3bedbaa22d 100644 --- a/mysql-test/t/disabled.def +++ b/mysql-test/t/disabled.def @@ -36,7 +36,6 @@ rpl_row_blob_innodb : BUG#18980 2006-04-10 kent Test fails randomly rpl_row_func003 : BUG#19074 2006-13-04 andrei test failed rpl_row_inexist_tbl : BUG#18948 2006-03-09 mats Disabled since patch makes this test wait forever rpl_sp : BUG#16456 2006-02-16 jmiller -rpl_sp_effects : BUG#19862 2006-08-22 mats Bug appear to be fixed rpl_until : BUG#15886 2006-02-16 jmiller Unstable test case sp-goto : BUG#18949 2006-02-16 jmiller GOTO is currently is disabled - will be fixed in the future mysqldump : BUG#18078 2006-03-10 lars diff --git a/sql/field.cc b/sql/field.cc index 340f33f1e01..479a562aaac 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -1261,7 +1261,10 @@ my_size_t Field::do_last_null_byte() const { DBUG_ASSERT(null_ptr == NULL || (byte*) null_ptr >= table->record[0]); - return null_ptr ? (byte*) null_ptr - table->record[0] + 1 : 0; + if (null_ptr) + return (byte*) null_ptr - table->record[0] + 1; + else + return LAST_NULL_BYTE_UNDEF; } @@ -8196,7 +8199,10 @@ Field_bit::do_last_null_byte() const else result= bit_ptr; - return result ? (byte*) result - table->record[0] + 1 : 0; + if (result) + return (byte*) result - table->record[0] + 1; + else + return LAST_NULL_BYTE_UNDEF; } Field *Field_bit::new_key_field(MEM_ROOT *root, diff --git a/sql/field.h b/sql/field.h index 51b624b799f..26a9cd0b465 100644 --- a/sql/field.h +++ b/sql/field.h @@ -208,10 +208,24 @@ public: inline bool maybe_null(void) { return null_ptr != 0 || table->maybe_null; } inline bool real_maybe_null(void) { return null_ptr != 0; } + enum { + LAST_NULL_BYTE_UNDEF= 0 + }; + /* - Return a pointer to the last byte of the null bytes where the - field conceptually is placed. In the case that the field does not - use any bits of the null bytes, a null pointer is returned. + Find the position of the last null byte for the field. + + SYNOPSIS + last_null_byte() + + DESCRIPTION + Return a pointer to the last byte of the null bytes where the + field conceptually is placed. + + RETURN VALUE + The position of the last null byte relative to the beginning of + the record. If the field does not use any bits of the null + bytes, the value 0 (LAST_NULL_BYTE_UNDEF) is returned. */ my_size_t last_null_byte() const { my_size_t bytes= do_last_null_byte(); @@ -384,6 +398,17 @@ public: friend class Item_func_group_concat; private: + /* + Primitive for implementing last_null_byte(). + + SYNOPSIS + do_last_null_byte() + + DESCRIPTION + Primitive for the implementation of the last_null_byte() + function. This represents the inheritance interface and can be + overridden by subclasses. + */ virtual my_size_t do_last_null_byte() const; }; diff --git a/sql/log_event.cc b/sql/log_event.cc index ceacc1eade7..ebfaa4bfff3 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -5304,7 +5304,7 @@ int Rows_log_event::do_add_row_data(byte *const row_data, row_end Pointer to variable that will hold the value of the one-after-end position for the row master_reclength - Pointer to variable that will hold the length of the + Pointer to variable that will be set to the length of the record on the master side rw_set Pointer to bitmap that holds either the read_set or the write_set of the table @@ -5317,13 +5317,22 @@ int Rows_log_event::do_add_row_data(byte *const row_data, At most 'colcnt' columns are read: if the table is larger than that, the remaining fields are not filled in. + + RETURN VALUE + + Error code, or zero if no error. The following error codes can + be returned: + + ER_NO_DEFAULT_FOR_FIELD + Returned if one of the fields existing on the slave but not on + the master does not have a default value (and isn't nullable) */ static int unpack_row(RELAY_LOG_INFO *rli, TABLE *table, uint const colcnt, byte *record, char const *row, MY_BITMAP const *cols, char const **row_end, ulong *master_reclength, - MY_BITMAP* const rw_set) + MY_BITMAP* const rw_set, Log_event_type const event_type) { DBUG_ASSERT(record && row); my_ptrdiff_t const offset= record - (byte*) table->record[0]; @@ -5334,10 +5343,20 @@ unpack_row(RELAY_LOG_INFO *rli, Field **fptr= &table->field[colcnt-1]; do master_null_bytes= (*fptr)->last_null_byte(); - while (master_null_bytes == 0 && fptr-- > table->field); + while (master_null_bytes == Field::LAST_NULL_BYTE_UNDEF && + fptr-- > table->field); + + /* + If master_null_bytes is LAST_NULL_BYTE_UNDEF (0) at this time, + there were no nullable fields nor BIT fields at all in the + columns that are common to the master and the slave. In that + case, there is only one null byte holding the X bit. - if (master_null_bytes == 0) - master_null_bytes= table->s->null_bytes; + OBSERVE! There might still be nullable columns following the + common columns, so table->s->null_bytes might be greater than 1. + */ + if (master_null_bytes == Field::LAST_NULL_BYTE_UNDEF) + master_null_bytes= 1; } DBUG_ASSERT(master_null_bytes <= table->s->null_bytes); @@ -5348,31 +5367,29 @@ unpack_row(RELAY_LOG_INFO *rli, Field **const begin_ptr = table->field; Field **field_ptr; + char const *ptr= row + master_null_bytes; + Field **const end_ptr= begin_ptr + colcnt; + for (field_ptr= begin_ptr ; field_ptr < end_ptr ; ++field_ptr) { - char const *ptr= row + master_null_bytes; - Field **const end_ptr= begin_ptr + colcnt; - for (field_ptr= begin_ptr ; field_ptr < end_ptr ; ++field_ptr) - { - Field *const f= *field_ptr; - - if (bitmap_is_set(cols, field_ptr - begin_ptr)) - { - ptr= f->unpack(f->ptr + offset, ptr); - /* Field...::unpack() cannot return 0 */ - DBUG_ASSERT(ptr != NULL); - } - else - bitmap_clear_bit(rw_set, field_ptr - begin_ptr); - } + Field *const f= *field_ptr; - *row_end = ptr; - if (master_reclength) + if (bitmap_is_set(cols, field_ptr - begin_ptr)) { - if (*field_ptr) - *master_reclength = (*field_ptr)->ptr - (char*) table->record[0]; - else - *master_reclength = table->s->reclength; + ptr= f->unpack(f->ptr + offset, ptr); + /* Field...::unpack() cannot return 0 */ + DBUG_ASSERT(ptr != NULL); } + else + bitmap_clear_bit(rw_set, field_ptr - begin_ptr); + } + + *row_end = ptr; + if (master_reclength) + { + if (*field_ptr) + *master_reclength = (*field_ptr)->ptr - (char*) table->record[0]; + else + *master_reclength = table->s->reclength; } /* @@ -5381,16 +5398,26 @@ unpack_row(RELAY_LOG_INFO *rli, it was not there already. We iterate over all remaining columns, even if there were an error, to get as many error messages as possible. We are still able to return a pointer to the next row, - so wedo that. + so redo that. + + This generation of error messages is only relevant when inserting + new rows. */ for ( ; *field_ptr ; ++field_ptr) { - if ((*field_ptr)->flags & (NOT_NULL_FLAG | NO_DEFAULT_VALUE_FLAG)) + uint32 const mask= NOT_NULL_FLAG | NO_DEFAULT_VALUE_FLAG; + + DBUG_PRINT("debug", ("flags = 0x%x, mask = 0x%x, flags & mask = 0x%x", + (*field_ptr)->flags, mask, + (*field_ptr)->flags & mask)); + + if (event_type == WRITE_ROWS_EVENT && + ((*field_ptr)->flags & mask) == mask) { - slave_print_msg(ERROR_LEVEL, rli, ER_NO_DEFAULT_FOR_FIELD, + slave_print_msg(ERROR_LEVEL, rli, ER_NO_DEFAULT_FOR_FIELD, "Field `%s` of table `%s`.`%s` " "has no default value and cannot be NULL", - (*field_ptr)->field_name, table->s->db.str, + (*field_ptr)->field_name, table->s->db.str, table->s->table_name.str); error = ER_NO_DEFAULT_FOR_FIELD; } @@ -5562,8 +5589,8 @@ int Rows_log_event::exec_event(st_relay_log_info *rli) { char const *row_end= NULL; if ((error= do_prepare_row(thd, rli, table, row_start, &row_end))) - break; // We should to the after-row operation even in the - // case of error + break; // We should perform the after-row operation even in + // the case of error DBUG_ASSERT(row_end != NULL); // cannot happen DBUG_ASSERT(row_end <= (const char*)m_rows_end); @@ -6224,7 +6251,7 @@ int Write_rows_log_event::do_prepare_row(THD *thd, RELAY_LOG_INFO *rli, error= unpack_row(rli, table, m_width, table->record[0], row_start, &m_cols, row_end, &m_master_reclength, - table->write_set); + table->write_set, WRITE_ROWS_EVENT); bitmap_copy(table->read_set, table->write_set); return error; } @@ -6285,10 +6312,17 @@ copy_extra_record_fields(TABLE *table, my_size_t master_reclength, my_ptrdiff_t master_fields) { - DBUG_PRINT("info", ("Copying to %p from field %d at offset %u to field %d at offset %u", - table->record[0], + DBUG_PRINT("info", ("Copying to %p " + "from field %d at offset %u " + "to field %d at offset %u", + table->record[0], master_fields, master_reclength, table->s->fields, table->s->reclength)); + /* + Copying the extra fields of the slave that does not exist on + master into record[0] (which are basically the default values). + */ + DBUG_ASSERT(master_reclength <= table->s->reclength); if (master_reclength < table->s->reclength) bmove_align(table->record[0] + master_reclength, table->record[1] + master_reclength, @@ -6771,7 +6805,7 @@ int Delete_rows_log_event::do_prepare_row(THD *thd, RELAY_LOG_INFO *rli, error= unpack_row(rli, table, m_width, table->record[0], row_start, &m_cols, row_end, &m_master_reclength, - table->read_set); + table->read_set, DELETE_ROWS_EVENT); /* If we will access rows using the random access method, m_key will be set to NULL, so we do not need to make a key copy in that case. @@ -6914,13 +6948,13 @@ int Update_rows_log_event::do_prepare_row(THD *thd, RELAY_LOG_INFO *rli, error= unpack_row(rli, table, m_width, table->record[0], row_start, &m_cols, row_end, &m_master_reclength, - table->read_set); + table->read_set, UPDATE_ROWS_EVENT); row_start = *row_end; /* m_after_image is the after image for the update */ error= unpack_row(rli, table, m_width, m_after_image, row_start, &m_cols, row_end, &m_master_reclength, - table->write_set); + table->write_set, UPDATE_ROWS_EVENT); /* If we will access rows using the random access method, m_key will diff --git a/sql/rpl_utility.cc b/sql/rpl_utility.cc index 5405d022223..c80b6dc3f69 100644 --- a/sql/rpl_utility.cc +++ b/sql/rpl_utility.cc @@ -107,11 +107,6 @@ field_length_from_packed(enum_field_types const field_type, /* Is the definition compatible with a table? - Compare the definition with a table to see if it is compatible with - it. A table definition is compatible with a table if - - the columns types of the table definition is a (not necessarily - proper) prefix of the column type of the table, or - - the other way around */ int table_def::compatible_with(RELAY_LOG_INFO *rli, TABLE *table) diff --git a/sql/rpl_utility.h b/sql/rpl_utility.h index 0ac3c10eec6..df0b0cd2ee1 100644 --- a/sql/rpl_utility.h +++ b/sql/rpl_utility.h @@ -32,29 +32,95 @@ field_length_from_packed(enum_field_types const field_type, RESPONSIBILITIES - - Extract table definition data from the table map event + - Extract and decode table definition data from the table map event - Check if table definition in table map is compatible with table definition on slave + + DESCRIPTION + + Currently, the only field type data available is an array of the + type operators that are present in the table map event. + + TODO + + Add type operands to this structure to allow detection of + difference between, e.g., BIT(5) and BIT(10). */ class table_def { public: + /* + Convenience declaration of the type of the field type data in a + table map event. + */ typedef unsigned char field_type; - table_def(field_type *t, my_size_t s) - : m_type(t), m_size(s) + /* + Constructor. + + SYNOPSIS + table_def() + types Array of types + size Number of elements in array 'types' + */ + table_def(field_type *types, my_size_t size) + : m_type(types), m_size(size) { } + /* + Return the number of fields there is type data for. + + SYNOPSIS + size() + + RETURN VALUE + The number of fields that there is type data for. + */ my_size_t size() const { return m_size; } + + /* + Return a representation of the type data for one field. + + SYNOPSIS + type() + i Field index to return data for + + RETURN VALUE + + Will return a representation of the type data for field + 'i'. Currently, only the type identifier is returned. + */ field_type type(my_ptrdiff_t i) const { return m_type[i]; } + /* + Decide if the table definition is compatible with a table. + + SYNOPSIS + compatible_with() + rli Pointer to relay log info + table Pointer to table to compare with. + + DESCRIPTION + + Compare the definition with a table to see if it is compatible + with it. A table definition is compatible with a table if: + + - the columns types of the table definition is a (not + necessarily proper) prefix of the column type of the table, or + + - the other way around + + RETURN VALUE + 1 if the table definition is not compatible with 'table' + 0 if the table definition is compatible with 'table' + */ int compatible_with(RELAY_LOG_INFO *rli, TABLE *table) const; private: - my_size_t m_size; - field_type *m_type; + my_size_t m_size; // Number of elements in the types array + field_type *m_type; // Array of type descriptors }; #endif /* RPL_UTILITY_H */ |