summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorunknown <mats@romeo.(none)>2007-04-12 15:50:54 +0200
committerunknown <mats@romeo.(none)>2007-04-12 15:50:54 +0200
commit5c35b4174ef8a3505f927444ec9001848b3073be (patch)
tree99bc39551e216b0f815a7d3af2d4237c7ed72cc9 /sql
parentec9b5eca9cee569eb4c1442cb0ab47c72dac818d (diff)
downloadmariadb-git-5c35b4174ef8a3505f927444ec9001848b3073be.tar.gz
BUG#27779 (Slave cannot read old rows log events):
Taking code from before BUG#22583 and incorporating as events to be able to read old events. Also incorporating old pack and unpack functions into patch. client/Makefile.am: Adding files log_event_old.{h,cc} and rpl_record_old.{h,cc} client/mysqlbinlog.cc: Adding log_event_old.cc. libmysqld/Makefile.am: Adding files log_event_old.{h,cc} and rpl_record_old.{h,cc} sql/CMakeLists.txt: Adding files log_event_old.{h,cc} and rpl_record_old.{h,cc} sql/Makefile.am: Adding files log_event_old.{h,cc} and rpl_record_old.{h,cc} sql/log_event.cc: Adding code to read pre-GA rows events. sql/log_event.h: Refactoring to support inheritance and including "old" events definitions. sql/log_event_old.cc: New BitKeeper file ``sql/log_event_old.cc'' sql/log_event_old.h: New BitKeeper file ``sql/log_event_old.h'' sql/rpl_record_old.cc: New BitKeeper file ``sql/rpl_record_old.cc'' sql/rpl_record_old.h: New BitKeeper file ``sql/rpl_record_old.h''
Diffstat (limited to 'sql')
-rw-r--r--sql/CMakeLists.txt1
-rw-r--r--sql/Makefile.am2
-rw-r--r--sql/log_event.cc9
-rw-r--r--sql/log_event.h6
-rw-r--r--sql/log_event_old.cc98
-rw-r--r--sql/log_event_old.h91
-rw-r--r--sql/rpl_record_old.cc173
-rw-r--r--sql/rpl_record_old.h17
8 files changed, 395 insertions, 2 deletions
diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt
index 002aabb91b0..f0e7bea74c6 100644
--- a/sql/CMakeLists.txt
+++ b/sql/CMakeLists.txt
@@ -48,6 +48,7 @@ ADD_EXECUTABLE(mysqld ../sql-common/client.c derror.cc des_key_file.cc
item_create.cc item_func.cc item_geofunc.cc item_row.cc
item_strfunc.cc item_subselect.cc item_sum.cc item_timefunc.cc
key.cc log.cc lock.cc log_event.cc message.rc
+ log_event_old.cc rpl_record_old.cc
message.h mf_iocache.cc my_decimal.cc ../sql-common/my_time.c
mysqld.cc net_serv.cc
nt_servc.cc nt_servc.h opt_range.cc opt_range.h opt_sum.cc
diff --git a/sql/Makefile.am b/sql/Makefile.am
index a85eb012f1d..0656c1a8f9b 100644
--- a/sql/Makefile.am
+++ b/sql/Makefile.am
@@ -59,6 +59,7 @@ noinst_HEADERS = item.h item_func.h item_sum.h item_cmpfunc.h \
lex.h lex_symbol.h sql_acl.h sql_crypt.h \
log_event.h sql_repl.h slave.h rpl_filter.h \
rpl_injector.h \
+ log_event_old.h rpl_record_old.h \
stacktrace.h sql_sort.h sql_cache.h set_var.h \
spatial.h gstream.h client_settings.h tzfile.h \
tztime.h my_decimal.h\
@@ -88,6 +89,7 @@ mysqld_SOURCES = sql_lex.cc sql_handler.cc sql_partition.cc \
procedure.cc sql_test.cc \
log.cc log_event.cc init.cc derror.cc sql_acl.cc \
unireg.cc des_key_file.cc \
+ log_event_old.cc rpl_record_old.cc \
discover.cc time.cc opt_range.cc opt_sum.cc \
records.cc filesort.cc handler.cc \
ha_partition.cc \
diff --git a/sql/log_event.cc b/sql/log_event.cc
index e3c94b5e1c9..29bafc23e88 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -995,6 +995,15 @@ Log_event* Log_event::read_log_event(const char* buf, uint event_len,
ev = new Format_description_log_event(buf, event_len, description_event);
break;
#if defined(HAVE_REPLICATION)
+ case PRE_GA_WRITE_ROWS_EVENT:
+ ev = new Write_rows_log_event_old(buf, event_len, description_event);
+ break;
+ case PRE_GA_UPDATE_ROWS_EVENT:
+ ev = new Update_rows_log_event_old(buf, event_len, description_event);
+ break;
+ case PRE_GA_DELETE_ROWS_EVENT:
+ ev = new Delete_rows_log_event_old(buf, event_len, description_event);
+ break;
case WRITE_ROWS_EVENT:
ev = new Write_rows_log_event(buf, event_len, description_event);
break;
diff --git a/sql/log_event.h b/sql/log_event.h
index 51543291621..eac17565fe0 100644
--- a/sql/log_event.h
+++ b/sql/log_event.h
@@ -2427,7 +2427,7 @@ public:
return Rows_log_event::is_valid() && m_cols_ai.bitmap;
}
-private:
+protected:
virtual Log_event_type get_type_code() { return (Log_event_type)TYPE_CODE; }
#ifdef MYSQL_CLIENT
@@ -2498,7 +2498,7 @@ public:
}
#endif
-private:
+protected:
virtual Log_event_type get_type_code() { return (Log_event_type)TYPE_CODE; }
#ifdef MYSQL_CLIENT
@@ -2519,6 +2519,8 @@ private:
};
+#include "log_event_old.h"
+
/**
Class representing an incident, an occurance out of the ordinary,
that happened on the master.
diff --git a/sql/log_event_old.cc b/sql/log_event_old.cc
new file mode 100644
index 00000000000..1172a3e0ad4
--- /dev/null
+++ b/sql/log_event_old.cc
@@ -0,0 +1,98 @@
+
+#include "mysql_priv.h"
+#include "log_event_old.h"
+#include "rpl_record_old.h"
+
+#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
+int
+Write_rows_log_event_old::do_prepare_row(THD *thd, RELAY_LOG_INFO *rli,
+ TABLE *table,
+ char const *row_start,
+ char const **row_end)
+{
+ DBUG_ASSERT(table != NULL);
+ DBUG_ASSERT(row_start && row_end);
+
+ int error;
+ error= unpack_row_old(rli, table, m_width, table->record[0],
+ row_start, &m_cols, row_end, &m_master_reclength,
+ table->write_set, PRE_GA_WRITE_ROWS_EVENT);
+ bitmap_copy(table->read_set, table->write_set);
+ return error;
+}
+
+
+int
+Delete_rows_log_event_old::do_prepare_row(THD *thd, RELAY_LOG_INFO *rli,
+ TABLE *table,
+ char const *row_start,
+ char const **row_end)
+{
+ int error;
+ DBUG_ASSERT(row_start && row_end);
+ /*
+ This assertion actually checks that there is at least as many
+ columns on the slave as on the master.
+ */
+ DBUG_ASSERT(table->s->fields >= m_width);
+
+ error= unpack_row_old(rli, table, m_width, table->record[0],
+ row_start, &m_cols, row_end, &m_master_reclength,
+ table->read_set, PRE_GA_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.
+ */
+ if (m_key)
+ {
+ KEY *const key_info= table->key_info;
+
+ key_copy(m_key, table->record[0], key_info, 0);
+ }
+
+ return error;
+}
+
+
+int Update_rows_log_event_old::do_prepare_row(THD *thd, RELAY_LOG_INFO *rli,
+ TABLE *table,
+ char const *row_start,
+ char const **row_end)
+{
+ int error;
+ DBUG_ASSERT(row_start && row_end);
+ /*
+ This assertion actually checks that there is at least as many
+ columns on the slave as on the master.
+ */
+ DBUG_ASSERT(table->s->fields >= m_width);
+
+ /* record[0] is the before image for the update */
+ error= unpack_row_old(rli, table, m_width, table->record[0],
+ row_start, &m_cols, row_end, &m_master_reclength,
+ table->read_set, PRE_GA_UPDATE_ROWS_EVENT);
+ row_start = *row_end;
+ /* m_after_image is the after image for the update */
+ error= unpack_row_old(rli, table, m_width, m_after_image,
+ row_start, &m_cols, row_end, &m_master_reclength,
+ table->write_set, PRE_GA_UPDATE_ROWS_EVENT);
+
+ DBUG_DUMP("record[0]", table->record[0], table->s->reclength);
+ DBUG_DUMP("m_after_image", m_after_image, table->s->reclength);
+
+
+ /*
+ 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.
+ */
+ if (m_key)
+ {
+ KEY *const key_info= table->key_info;
+
+ key_copy(m_key, table->record[0], key_info, 0);
+ }
+
+ return error;
+}
+
+#endif
diff --git a/sql/log_event_old.h b/sql/log_event_old.h
new file mode 100644
index 00000000000..aad0f6cc6cd
--- /dev/null
+++ b/sql/log_event_old.h
@@ -0,0 +1,91 @@
+#ifndef LOG_EVENT_OLD_H
+#define LOG_EVENT_OLD_H
+
+/*
+ Need to include this file at the proper position of log_event.h
+ */
+
+
+class Write_rows_log_event_old : public Write_rows_log_event
+{
+public:
+ enum
+ {
+ /* Support interface to THD::binlog_prepare_pending_rows_event */
+ TYPE_CODE = PRE_GA_WRITE_ROWS_EVENT
+ };
+
+#if defined(HAVE_REPLICATION)
+ Write_rows_log_event_old(const char *buf, uint event_len,
+ const Format_description_log_event *descr)
+ : Write_rows_log_event(buf, event_len, descr)
+ {
+ }
+#endif
+
+private:
+ virtual Log_event_type get_type_code() { return (Log_event_type)TYPE_CODE; }
+
+#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
+ virtual int do_prepare_row(THD*, RELAY_LOG_INFO*, TABLE*,
+ char const *row_start, char const **row_end);
+#endif
+};
+
+
+class Update_rows_log_event_old : public Update_rows_log_event
+{
+public:
+ enum
+ {
+ /* Support interface to THD::binlog_prepare_pending_rows_event */
+ TYPE_CODE = PRE_GA_UPDATE_ROWS_EVENT
+ };
+
+#if defined(HAVE_REPLICATION)
+ Update_rows_log_event_old(const char *buf, uint event_len,
+ const Format_description_log_event *descr)
+ : Update_rows_log_event(buf, event_len, descr)
+ {
+ }
+#endif
+
+private:
+ virtual Log_event_type get_type_code() { return (Log_event_type)TYPE_CODE; }
+
+#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
+ virtual int do_prepare_row(THD*, RELAY_LOG_INFO*, TABLE*,
+ char const *row_start, char const **row_end);
+#endif /* !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) */
+};
+
+
+class Delete_rows_log_event_old : public Delete_rows_log_event
+{
+public:
+ enum
+ {
+ /* Support interface to THD::binlog_prepare_pending_rows_event */
+ TYPE_CODE = PRE_GA_DELETE_ROWS_EVENT
+ };
+
+#if defined(HAVE_REPLICATION)
+ Delete_rows_log_event_old(const char *buf, uint event_len,
+ const Format_description_log_event *descr)
+ : Delete_rows_log_event(buf, event_len, descr)
+ {
+ }
+#endif
+
+private:
+ virtual Log_event_type get_type_code() { return (Log_event_type)TYPE_CODE; }
+
+#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
+ virtual int do_prepare_row(THD*, RELAY_LOG_INFO*, TABLE*,
+ char const *row_start, char const **row_end);
+#endif
+};
+
+
+#endif
+
diff --git a/sql/rpl_record_old.cc b/sql/rpl_record_old.cc
new file mode 100644
index 00000000000..ccee1b2211b
--- /dev/null
+++ b/sql/rpl_record_old.cc
@@ -0,0 +1,173 @@
+
+#include "mysql_priv.h"
+#include "rpl_record_old.h"
+
+my_size_t
+pack_row_old(THD *thd, TABLE *table, MY_BITMAP const* cols,
+ byte *row_data, const byte *record)
+{
+ Field **p_field= table->field, *field;
+ int n_null_bytes= table->s->null_bytes;
+ byte *ptr;
+ uint i;
+ my_ptrdiff_t const rec_offset= record - table->record[0];
+ my_ptrdiff_t const def_offset= table->s->default_values - table->record[0];
+ memcpy(row_data, record, n_null_bytes);
+ ptr= row_data+n_null_bytes;
+
+ for (i= 0 ; (field= *p_field) ; i++, p_field++)
+ {
+ if (bitmap_is_set(cols,i))
+ {
+ my_ptrdiff_t const offset=
+ field->is_null(rec_offset) ? def_offset : rec_offset;
+ field->move_field_offset(offset);
+ ptr= (byte*)field->pack((char *) ptr, field->ptr);
+ field->move_field_offset(-offset);
+ }
+ }
+ return (static_cast<my_size_t>(ptr - row_data));
+}
+
+
+/*
+ Unpack a row into a record.
+
+ SYNOPSIS
+ unpack_row()
+ rli Relay log info
+ table Table to unpack into
+ colcnt Number of columns to read from record
+ record Record where the data should be unpacked
+ row Packed row data
+ cols Pointer to columns data to fill in
+ 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 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
+
+ DESCRIPTION
+
+ The row is assumed to only consist of the fields for which the
+ bitset represented by 'arr' and 'bits'; the other parts of the
+ record are left alone.
+
+ 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)
+ */
+#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
+int
+unpack_row_old(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, Log_event_type const event_type)
+{
+ DBUG_ASSERT(record && row);
+ my_ptrdiff_t const offset= record - (byte*) table->record[0];
+ my_size_t master_null_bytes= table->s->null_bytes;
+
+ if (colcnt != table->s->fields)
+ {
+ Field **fptr= &table->field[colcnt-1];
+ do
+ master_null_bytes= (*fptr)->last_null_byte();
+ 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.
+
+ 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);
+ memcpy(record, row, master_null_bytes); // [1]
+ int error= 0;
+
+ bitmap_set_all(rw_set);
+
+ 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)
+ {
+ Field *const f= *field_ptr;
+
+ if (bitmap_is_set(cols, field_ptr - begin_ptr))
+ {
+ f->move_field_offset(offset);
+ ptr= f->unpack(f->ptr, ptr);
+ f->move_field_offset(-offset);
+ /* 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;
+ }
+
+ /*
+ Set properties for remaining columns, if there are any. We let the
+ corresponding bit in the write_set be set, to write the value if
+ 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 redo that.
+
+ This generation of error messages is only relevant when inserting
+ new rows.
+ */
+ for ( ; *field_ptr ; ++field_ptr)
+ {
+ 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,
+ "Field `%s` of table `%s`.`%s` "
+ "has no default value and cannot be NULL",
+ (*field_ptr)->field_name, table->s->db.str,
+ table->s->table_name.str);
+ error = ER_NO_DEFAULT_FOR_FIELD;
+ }
+ else
+ (*field_ptr)->set_default();
+ }
+
+ return error;
+}
+#endif
diff --git a/sql/rpl_record_old.h b/sql/rpl_record_old.h
new file mode 100644
index 00000000000..7249d98c7b1
--- /dev/null
+++ b/sql/rpl_record_old.h
@@ -0,0 +1,17 @@
+#ifndef RPL_RECORD_OLD_H
+#define RPL_RECORD_OLD_H
+
+#ifndef MYSQL_CLIENT
+my_size_t pack_row_old(THD *thd, TABLE *table, MY_BITMAP const* cols,
+ byte *row_data, const byte *record);
+
+#ifdef HAVE_REPLICATION
+int unpack_row_old(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,
+ Log_event_type const event_type);
+#endif
+#endif
+#endif