2686 Oystein Grovlen 2008-09-15 [merge]
Merge from mysql-6.0-backup to mysql-6.0-backup-merge.
added:
mysql-test/r/backup_blob.result
mysql-test/t/backup_blob.test
modified:
sql/backup/be_default.cc
sql/backup/stream.cc
sql/backup/stream_v1.c
sql/backup/stream_v1.h
sql/backup/stream_v1_transport.c
sql/field.h
sql/log.cc
sql/log_event.h
sql/log_event_old.h
sql/rpl_record.cc
sql/rpl_record.h
sql/sql_class.cc
2685 Oystein Grovlen 2008-09-15 [merge]
Merge from mysql-6.0 to mysql-6.0-backup-merge
modified:
.bzr-mysql/default.conf
2684 Oystein Grovlen 2008-09-11 [merge]
Merge from mysql-6.0 to mysql-6.0-backup-merge.
removed:
include/mysql_h.ic
added:
include/mysql.h.pp
include/mysql/plugin.h.pp
sql/mysql_priv.h.pp
modified:
Makefile.am
configure.in
include/Makefile.am
sql/ha_ndbcluster.cc
sql/handler.h
sql/sql_insert.cc
sql/sql_show.cc
sql/table.h
=== modified file '.bzr-mysql/default.conf'
=== modified file '.bzr-mysql/default.conf'
--- a/.bzr-mysql/default.conf 2008-09-11 11:42:13 +0000
+++ b/.bzr-mysql/default.conf 2008-09-15 08:35:01 +0000
@@ -3,4 +3,3 @@
post_commit_to = commits@stripped
post_push_to = commits@stripped
tree_name = mysql-6.0-backup-merge
-
=== added file 'mysql-test/r/backup_blob.result'
--- a/mysql-test/r/backup_blob.result 1970-01-01 00:00:00 +0000
+++ b/mysql-test/r/backup_blob.result 2008-09-09 08:19:21 +0000
@@ -0,0 +1,52 @@
+DROP DATABASE IF EXISTS mysqltest;
+
+Test blobs, InnoDB
+
+CREATE DATABASE mysqltest;
+USE mysqltest;
+CREATE TABLE t1 (id int, txt longblob) ENGINE=innodb;
+INSERT INTO t1 VALUES(1, "short text");
+INSERT INTO t1 VALUES(2, "a little longer, but still short text");
+CREATE TABLE t2 (id int, txt longblob) ENGINE=innodb;
+INSERT INTO t2 VALUES(1, REPEAT('x',1000));
+INSERT INTO t2 VALUES(2, REPEAT('y',10000));
+INSERT INTO t2 VALUES(3, REPEAT('z',1048576));
+CREATE TABLE t3 (id int, txt longblob, txt2 longblob, txt3 longblob) ENGINE=innodb;
+INSERT INTO t3 VALUES(1, REPEAT('x',1048576), REPEAT('y',1048576), REPEAT('z',1048576));
+
+Check tables before backup
+SELECT * FROM t1 ORDER BY id;
+id txt
+1 short text
+2 a little longer, but still short text
+CHECKSUM TABLE t2;
+Table Checksum
+mysqltest.t2 1646886041
+CHECKSUM TABLE t3;
+Table Checksum
+mysqltest.t3 2938103984
+
+Backup, drop and restore database
+BACKUP DATABASE mysqltest TO 'blob.bak';
+backup_id
+#
+DROP DATABASE mysqltest;
+RESTORE FROM 'blob.bak';
+backup_id
+#
+
+Check tables after restore
+SELECT * FROM t1 ORDER BY id;
+id txt
+1 short text
+2 a little longer, but still short text
+CHECKSUM TABLE t2;
+Table Checksum
+mysqltest.t2 1646886041
+CHECKSUM TABLE t3;
+Table Checksum
+mysqltest.t3 2938103984
+
+Cleanup
+
+DROP DATABASE mysqltest;
=== added file 'mysql-test/t/backup_blob.test'
--- a/mysql-test/t/backup_blob.test 1970-01-01 00:00:00 +0000
+++ b/mysql-test/t/backup_blob.test 2008-09-09 08:19:21 +0000
@@ -0,0 +1,64 @@
+###########################################################################
+# Purpose: Test backup/restore of blobs
+###########################################################################
+
+# This is currently only a regression test for bug#37212. When the
+# test is moved to the backup suite, at least one storage engine for
+# each driver should be tested.
+
+--source include/not_embedded.inc
+--source include/have_innodb.inc
+
+--disable_warnings
+DROP DATABASE IF EXISTS mysqltest;
+--enable_warnings
+
+--echo
+--echo Test blobs, InnoDB
+--echo
+
+CREATE DATABASE mysqltest;
+USE mysqltest;
+
+CREATE TABLE t1 (id int, txt longblob) ENGINE=innodb;
+INSERT INTO t1 VALUES(1, "short text");
+INSERT INTO t1 VALUES(2, "a little longer, but still short text");
+
+CREATE TABLE t2 (id int, txt longblob) ENGINE=innodb;
+INSERT INTO t2 VALUES(1, REPEAT('x',1000));
+INSERT INTO t2 VALUES(2, REPEAT('y',10000));
+INSERT INTO t2 VALUES(3, REPEAT('z',1048576));
+
+CREATE TABLE t3 (id int, txt longblob, txt2 longblob, txt3 longblob) ENGINE=innodb;
+INSERT INTO t3 VALUES(1, REPEAT('x',1048576), REPEAT('y',1048576), REPEAT('z',1048576));
+
+--echo
+--echo Check tables before backup
+SELECT * FROM t1 ORDER BY id;
+CHECKSUM TABLE t2;
+CHECKSUM TABLE t3;
+
+--echo
+--echo Backup, drop and restore database
+
+--replace_column 1 #
+BACKUP DATABASE mysqltest TO 'blob.bak';
+
+DROP DATABASE mysqltest;
+--replace_column 1 #
+RESTORE FROM 'blob.bak';
+
+--echo
+--echo Check tables after restore
+
+SELECT * FROM t1 ORDER BY id;
+CHECKSUM TABLE t2;
+CHECKSUM TABLE t3;
+
+--echo
+--echo Cleanup
+--echo
+
+DROP DATABASE mysqltest;
+
+--remove_file $MYSQLTEST_VARDIR/master-data/blob.bak
=== modified file 'sql/backup/be_default.cc'
--- a/sql/backup/be_default.cc 2008-08-18 08:25:56 +0000
+++ b/sql/backup/be_default.cc 2008-09-09 08:19:21 +0000
@@ -275,7 +275,7 @@
my_bool use_bitbuf= n_fields <= sizeof(bitbuf) * 8;
error= bitmap_init(&cols, use_bitbuf ? bitbuf : NULL, (n_fields + 7) & ~7UL, FALSE);
bitmap_set_all(&cols);
- size= pack_row(cur_table, &cols, packed_row, rcd);
+ size= pack_row(cur_table, &cols, packed_row, rcd, FALSE);
if (!use_bitbuf)
bitmap_free(&cols);
}
@@ -680,7 +680,7 @@
error= bitmap_init(&cols, use_bitbuf ? bitbuf : NULL, (n_fields + 7) & ~7UL, FALSE);
bitmap_set_all(&cols);
ulong length;
- error= unpack_row(NULL, cur_table, n_fields, packed_row, &cols, &cur_row_end, &length);
+ error= unpack_row(NULL, cur_table, n_fields, packed_row, &cols, &cur_row_end, &length, FALSE);
if (!use_bitbuf)
bitmap_free(&cols);
}
@@ -906,6 +906,7 @@
memcpy(blob_ptrs[blob_ptr_index], (byte *)buf.data + META_SIZE, size);
((Field_blob*) cur_table->field[*cur_blob])->set_ptr(size,
(uchar *)blob_ptrs[blob_ptr_index]);
+ cur_table->field[*cur_blob]->set_notnull();
blob_ptr_index++;
mode= CHECK_BLOBS;
DBUG_RETURN(PROCESSING);
@@ -944,6 +945,7 @@
ptr= (byte *)blob_buffer.get_base_ptr();
((Field_blob*) cur_table->field[*cur_blob])->set_ptr(max_blob_size,
(uchar *)ptr);
+ cur_table->field[*cur_blob]->set_notnull();
blob_ptr_index++;
mode= CHECK_BLOBS;
DBUG_RETURN(PROCESSING);
=== modified file 'sql/backup/stream.cc'
--- a/sql/backup/stream.cc 2008-09-08 07:25:00 +0000
+++ b/sql/backup/stream.cc 2008-09-11 11:14:59 +0000
@@ -591,6 +591,10 @@
if (m_fd < 0)
return;
+ /*
+ Note: Even if bstream_close() fails we want to do the lower level clean-up.
+ This is why errors from bstream_close() are ignored.
+ */
bstream_close(this);
#ifdef HAVE_COMPRESS
if (m_with_compression)
@@ -632,7 +636,8 @@
*/
bool Output_stream::rewind()
{
- bstream_close(this);
+ if (bstream_close(this) != BSTREAM_OK)
+ return FALSE;
bool ret= Stream::rewind();
@@ -777,6 +782,10 @@
if (m_fd < 0)
return;
+ /*
+ Note: Even if bstream_close() fails we want to do the lower level clean-up.
+ This is why errors from bstream_close() are ignored.
+ */
bstream_close(this);
#ifdef HAVE_COMPRESS
if (m_with_compression)
@@ -798,7 +807,8 @@
*/
bool Input_stream::rewind()
{
- bstream_close(this);
+ if (bstream_close(this) != BSTREAM_OK)
+ return FALSE;
bool ret= Stream::rewind();
=== modified file 'sql/backup/stream_v1.c'
--- a/sql/backup/stream_v1.c 2008-08-13 12:41:33 +0000
+++ b/sql/backup/stream_v1.c 2008-09-09 08:19:21 +0000
@@ -1811,9 +1811,11 @@
{
memmove(buf->begin, chunk->data.begin, howmuch);
envelope= buf;
- chunk->data= *buf;
}
+ // update chunk->data to point to the new buffer
+ chunk->data= *buf;
+
/* update to_read blob to indicate free space left */
to_read.begin= buf->begin + howmuch;
to_read.end= buf->end;
=== modified file 'sql/backup/stream_v1.h'
--- a/sql/backup/stream_v1.h 2008-05-14 00:35:24 +0000
+++ b/sql/backup/stream_v1.h 2008-09-11 09:47:53 +0000
@@ -378,6 +378,16 @@
the bytes being written to/read from a backup stream. This is done by
storing pointers to functions performing basic I/O operations inside
this structure.
+
+ Low-level @c write(), @c read() and @c forward() functions should return
+ BSTREAM_OK on success and BSTREAM_ERROR on error. Additionally, @c read()
+ should return BSTREAM_EOS if there is no more data in the input stream.
+
+ Functions @c write() and @c read() should behave like functions
+ @c bstream_write_part() and @c bstream_read_part(), respectively. The latter
+ are documented in stream_v1_transport.c. The only difference is that low-level
+ @c read() doesn't deal with chunk boundaries and never returns BSTREAM_EOC.
+ However, it should detect end of stream and return BSTREAM_EOS in that case.
*/
struct st_abstract_stream
{
=== modified file 'sql/backup/stream_v1_transport.c'
--- a/sql/backup/stream_v1_transport.c 2008-07-19 03:03:39 +0000
+++ b/sql/backup/stream_v1_transport.c 2008-09-11 09:47:53 +0000
@@ -24,6 +24,11 @@
#endif
/**
+ @brief Set stream to error state and return BSTREAM_ERROR
+*/
+#define SERROR(S) ((S)->state= ERROR, BSTREAM_ERROR)
+
+/**
@brief Default size of a stream block.
When opening stream for writing a different size can be specified.
@@ -386,7 +391,11 @@
int ret= BSTREAM_OK;
if (s->buf.pos > s->buf.begin)
+ {
ret= as_write_all(&s->stream,*(bstream_blob*)&s->buf,s->mem);
+ if (ret != BSTREAM_OK)
+ return SERROR(s);
+ }
/*
Now buffer should be empty. If whole block has been written, reset buffer
@@ -398,7 +407,7 @@
else
s->buf.begin= s->buf.header= s->buf.pos; /* now invariant should hold */
- return ret;
+ return BSTREAM_OK;
}
/**
@@ -408,18 +417,16 @@
is left for fragment`s header.
*/
static
-int append_to_buffer(backup_stream *s, blob *b)
+void append_to_buffer(backup_stream *s, blob *b)
{
if (b->begin >= b->end) /* no data to append */
- return BSTREAM_OK;
+ return;
if(s->buf.pos == s->buf.header) /* current fragment empty */
s->buf.pos++;
while ((s->buf.pos < s->buf.end) && (b->begin < b->end))
*(s->buf.pos++)= *(b->begin++);
-
- return BSTREAM_OK;
}
/**
@@ -480,7 +487,7 @@
ret= write_buffer(s); /* this empties the buffer */
if (ret != BSTREAM_OK)
- return ret;
+ return SERROR(s);
buf->pos= current_fragment.end;
@@ -657,6 +664,8 @@
data.end= s->buf.pos + howmuch;
ret= as_read(&s->stream,&data,s->mem);
+ if (ret == BSTREAM_ERROR)
+ return SERROR(s);
s->buf.pos= data.begin;
@@ -715,8 +724,7 @@
}
else if (block_size != s->block_size)
{
- s->state= ERROR;
- return BSTREAM_ERROR;
+ return SERROR(s);
}
else
s->init_block_count--;
@@ -751,6 +759,7 @@
@retval BSTREAM_OK next fragment has been entered
@retval BSTREAM_EOC the entered fragment is the last fragment of a chunk
@retval BSTREAM_EOS there are no more fragments in the stream
+ @retval BSTREAM_ERROR error when reading from underlying stream
*/
static
int load_next_fragment(backup_stream *s)
@@ -766,7 +775,7 @@
s->state= NORMAL; /* default, unless changed below */
- ret= read_fragment_header(&s->buf.header);
+ ret= read_fragment_header(&s->buf.header); // Never errors.
/*
If buf.header was not moved, it means that the fragment extends to
@@ -916,6 +925,11 @@
if (s->mode == WRITING)
{
+ /*
+ Note: even if bstream_end_chunk() or bstream_flush() fail we still try
+ to write the EOS marker and continue with other clean-up. In case of
+ failure s->state will be set to ERROR which is detected later.
+ */
bstream_end_chunk(s);
bstream_flush(s);
/* write EOS marker */
@@ -999,7 +1013,7 @@
{
ret= bstream_flush(s);
if (ret != BSTREAM_OK)
- return ret;
+ return BSTREAM_ERROR;
}
ASSERT(s->buf.pos < s->buf.end);
@@ -1044,7 +1058,7 @@
ret= write_buffer(s);
if (ret != BSTREAM_OK)
- return ret;
+ return BSTREAM_ERROR;
/* write bytes from data blob to fill the block */
saved_end= data->end;
@@ -1052,7 +1066,7 @@
ret= as_write_all(&s->stream,*data,buf);
if (ret != BSTREAM_OK)
- return ret;
+ return SERROR(s);
data->begin= data->end;
data->end= saved_end;
@@ -1081,13 +1095,15 @@
/* write contents of the output buffer */
ret= write_buffer(s);
if (ret != BSTREAM_OK)
- return ret;
+ return BSTREAM_ERROR;
/* write remainder of the fragment from data blob */
saved_end= data->end;
data->end= data->begin + (fragment.begin - s->buf.pos);
ret= as_write_all(&s->stream,*data,*data);
+ if (ret != BSTREAM_OK)
+ return SERROR(s);
data->begin= data->end;
data->end= saved_end;
@@ -1112,7 +1128,7 @@
If nothing else worked, we just append the data to the output buffer
and return.
*/
- append_to_buffer(s,data);
+ append_to_buffer(s,data); // Never errors.
return BSTREAM_OK;
}
@@ -1185,6 +1201,8 @@
else
{
ret= close_current_fragment(s);
+ if (ret != BSTREAM_OK)
+ return BSTREAM_ERROR;
/*
If the last fragment in the buffer is a small fragment, we can mark it as
@@ -1270,7 +1288,7 @@
/* Otherwise close the current fragment to set its header */
ret= close_current_fragment(s);
if (ret != BSTREAM_OK)
- return ret;
+ return BSTREAM_ERROR;
/*
If there is only one byte left to the end of block, we fill this byte with
@@ -1335,7 +1353,6 @@
if (s->buf.begin == s->buf.pos)
{
ret= load_buffer(s);
-
if (ret != BSTREAM_OK)
return ret;
}
@@ -1423,7 +1440,6 @@
if ((s->buf.begin == s->buf.end) || (s->buf.begin == s->buf.header))
{
ret= load_buffer(s);
-
if (ret != BSTREAM_OK)
return ret;
}
@@ -1482,10 +1498,11 @@
saved= *data;
data->end= data->begin + howmuch;
- if (as_read(&s->stream, data, buf) == BSTREAM_EOS)
- {
+ ret= as_read(&s->stream, data, buf);
+ if (ret == BSTREAM_ERROR)
+ return SERROR(s);
+ if (ret == BSTREAM_EOS)
s->state= EOS;
- }
s->buf.begin += data->begin - saved.begin;
s->buf.pos= s->buf.begin;
@@ -1570,7 +1587,6 @@
if (s->buf.begin == s->buf.end)
{
ret= load_buffer(s);
-
if (ret != BSTREAM_OK)
return ret;
}
@@ -1592,7 +1608,10 @@
else
{
howmuch= s->buf.header - s->buf.pos;
- as_forward(&s->stream, &howmuch);
+ ret= as_forward(&s->stream, &howmuch);
+ if (ret != BSTREAM_OK)
+ return SERROR(s);
+
s->buf.begin= s->buf.pos= s->buf.header;
}
}
@@ -1611,7 +1630,6 @@
if (s->buf.pos == s->buf.begin)
{
ret= load_buffer(s);
-
if (ret != BSTREAM_OK)
return ret;
}
@@ -1620,7 +1638,8 @@
ASSERT(s->buf.pos > s->buf.header);
ret= load_next_fragment(s);
-
+ if (ret == BSTREAM_ERROR) // To avoid invariant check below.
+ return BSTREAM_ERROR;
/* if we hit EOC marker here, we treat it as empty chunk */
if (ret == BSTREAM_EOC)
ret= BSTREAM_OK;
@@ -1638,5 +1657,9 @@
*/
int bstream_skip(backup_stream *s, unsigned long int howmuch)
{
- return as_forward(&s->stream, &howmuch);
+ int ret= as_forward(&s->stream, &howmuch);
+ if (ret != BSTREAM_OK)
+ return SERROR(s);
+
+ return BSTREAM_OK;
}
=== modified file 'sql/field.h'
--- a/sql/field.h 2008-08-28 11:17:29 +0000
+++ b/sql/field.h 2008-09-09 08:19:21 +0000
@@ -1759,6 +1759,18 @@
{
memcpy_fixed((uchar*) str,ptr+packlength+row_offset,sizeof(char*));
}
+
+ /**
+ Copy value in data to the field ptr.
+
+ NOTE
+ If the null_bit for this field is set, @c
+ set_notnull(my_ptrdiff_t) needs to be called for set_ptr to have
+ any effect when inserting a record.
+
+ @param length Length of data
+ @param data The value of the field
+ */
inline void set_ptr(uchar *length, uchar *data)
{
memcpy(ptr,length,packlength);
=== modified file 'sql/log.cc'
--- a/sql/log.cc 2008-08-28 15:13:31 +0000
+++ b/sql/log.cc 2008-09-11 18:21:54 +0000
@@ -3515,6 +3515,8 @@
ulonglong MYSQL_BACKUP_LOG::get_next_backup_id()
{
ulonglong id= 0;
+ uchar *read_id= 0;
+ uchar *write_id= 0;
char buff[FN_REFLEN], *file_path;
File file= 0;
@@ -3538,7 +3540,6 @@
file= my_open(file_path, O_RDWR|O_BINARY|O_CREAT, MYF(MY_WME));
if (!file)
goto err_end;
-
if (my_fstat(file, &state, MYF(0)))
goto err;
/*
@@ -3562,10 +3563,10 @@
// else .... we read the next value in the file!
else
{
- ulonglong read_id= 0;
my_seek(file, 0, 0, MYF(MY_WME));
- my_read(file, (uchar *)&read_id, sizeof(ulonglong), MYF(MY_WME|MY_NABP));
- id= uint8korr(&read_id);
+ read_id= (uchar *)my_malloc(sizeof(ulonglong), MYF(MY_ZEROFILL));
+ my_read(file, read_id, sizeof(ulonglong), MYF(MY_WME|MY_NABP));
+ id= uint8korr(read_id);
id++;
}
}
@@ -3579,8 +3580,6 @@
*/
if ((m_next_id != id) && id)
{
- ulonglong write_id= 0;
-
if (!file)
{
file_path= make_backup_log_name(buff, BACKUP_SETTINGS_NAME.str, ".obx");
@@ -3589,8 +3588,9 @@
goto err_end;
}
my_seek(file, 0, 0, MYF(MY_WME));
- int8store(&write_id, id);
- my_write(file, (uchar *)&write_id, sizeof(ulonglong), MYF(MY_WME));
+ write_id= (uchar *)my_malloc(sizeof(ulonglong), MYF(MY_ZEROFILL));
+ int8store(write_id, id);
+ my_write(file, write_id, sizeof(ulonglong), MYF(MY_WME));
}
err:
if (file > 0)
@@ -3600,6 +3600,10 @@
m_next_id= id;
pthread_mutex_unlock(&LOCK_backupid);
DBUG_PRINT("backup_log",("The next id is %lu.\n", (ulong)id));
+ if(read_id)
+ my_free(read_id, MYF(0));
+ if(write_id)
+ my_free(write_id, MYF(0));
return id;
}
=== modified file 'sql/log_event.h'
--- a/sql/log_event.h 2008-08-28 09:59:54 +0000
+++ b/sql/log_event.h 2008-09-09 08:19:21 +0000
@@ -3545,7 +3545,7 @@
DBUG_ASSERT(m_table);
ASSERT_OR_RETURN_ERROR(m_curr_row < m_rows_end, HA_ERR_CORRUPT_EVENT);
int const result= ::unpack_row(rli, m_table, m_width, m_curr_row, cols,
- &m_curr_row_end, &m_master_reclength);
+ &m_curr_row_end, &m_master_reclength, TRUE);
if (m_curr_row_end > m_rows_end)
my_error(ER_SLAVE_CORRUPT_EVENT, MYF(0));
ASSERT_OR_RETURN_ERROR(m_curr_row_end <= m_rows_end, HA_ERR_CORRUPT_EVENT);
=== modified file 'sql/log_event_old.h'
--- a/sql/log_event_old.h 2008-05-29 15:44:11 +0000
+++ b/sql/log_event_old.h 2008-09-09 08:19:21 +0000
@@ -204,7 +204,7 @@
DBUG_ASSERT(m_table);
ASSERT_OR_RETURN_ERROR(m_curr_row < m_rows_end, HA_ERR_CORRUPT_EVENT);
int const result= ::unpack_row(rli, m_table, m_width, m_curr_row, &m_cols,
- &m_curr_row_end, &m_master_reclength);
+ &m_curr_row_end, &m_master_reclength, TRUE);
ASSERT_OR_RETURN_ERROR(m_curr_row_end <= m_rows_end, HA_ERR_CORRUPT_EVENT);
return result;
}
=== modified file 'sql/rpl_record.cc'
--- a/sql/rpl_record.cc 2008-03-27 18:40:00 +0000
+++ b/sql/rpl_record.cc 2008-09-09 08:19:21 +0000
@@ -51,12 +51,19 @@
record[0] or @c record[1], but no such check is
made since the code does not rely on that.
+ @param pack_blobs Whether or not blob fields are packed. If true,
+ row_data has to be big enough to store all blobs
+ in this record. If false, the blobs are not
+ stored in row_data but should instead be fetched
+ by calling @c get_ptr
+
@return The number of bytes written at @c row_data.
*/
#if !defined(MYSQL_CLIENT)
size_t
pack_row(TABLE *table, MY_BITMAP const* cols,
- uchar *row_data, const uchar *record)
+ uchar *row_data, const uchar *record,
+ bool pack_blobs)
{
Field **p_field= table->field, *field;
int const null_byte_count= (bitmap_bits_set(cols) + 7) / 8;
@@ -92,6 +99,11 @@
offset= def_offset;
null_bits |= null_mask;
}
+ else if (!pack_blobs && field->unireg_check==Field::BLOB_FIELD)
+ {
+ // The field is not empty. Fetch by calling get_ptr()
+ null_bits &= ~null_mask;
+ }
else
{
offset= rec_offset;
@@ -179,6 +191,10 @@
Pointer to variable that will be set to the length of the
record on the master side
+ @param unpack_blobs Whether or not blob fields are unpacked. If
+ false, the blobs must be added by calling
+ @c set_ptr() and @c set_notnull().
+
@retval 0 No error
@retval ER_NO_DEFAULT_FOR_FIELD
@@ -191,7 +207,8 @@
unpack_row(Relay_log_info const *rli,
TABLE *table, uint const colcnt,
uchar const *const row_data, MY_BITMAP const *cols,
- uchar const **const row_end, ulong *const master_reclength)
+ uchar const **const row_end, ulong *const master_reclength,
+ bool unpack_blobs)
{
DBUG_ENTER("unpack_row");
DBUG_ASSERT(row_data);
@@ -255,6 +272,11 @@
f->set_null();
}
+ else if (!unpack_blobs && f->unireg_check==Field::BLOB_FIELD)
+ {
+ DBUG_PRINT("debug", ("Not unpacking BLOB; field_ptr: %p", field_ptr));
+ f->set_null();
+ }
else
{
f->set_notnull();
=== modified file 'sql/rpl_record.h'
--- a/sql/rpl_record.h 2008-03-25 15:10:50 +0000
+++ b/sql/rpl_record.h 2008-09-09 08:19:21 +0000
@@ -20,14 +20,16 @@
#if !defined(MYSQL_CLIENT)
size_t pack_row(TABLE* table, MY_BITMAP const* cols,
- uchar *row_data, const uchar *data);
+ uchar *row_data, const uchar *data,
+ bool pack_blobs);
#endif
#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
int unpack_row(Relay_log_info const *rli,
TABLE *table, uint const colcnt,
uchar const *const row_data, MY_BITMAP const *cols,
- uchar const **const row_end, ulong *const master_reclength);
+ uchar const **const row_end, ulong *const master_reclength,
+ bool unpack_blobs);
// Fill table's record[0] with default values.
int prepare_record(TABLE *const, const MY_BITMAP *cols, uint width, const bool);
=== modified file 'sql/sql_class.cc'
--- a/sql/sql_class.cc 2008-09-04 13:46:04 +0000
+++ b/sql/sql_class.cc 2008-09-09 08:19:21 +0000
@@ -3428,7 +3428,7 @@
uchar *row_data= memory.slot(0);
- size_t const len= pack_row(table, table->write_set, row_data, record);
+ size_t const len= pack_row(table, table->write_set, row_data, record, TRUE);
Rows_log_event* const ev=
binlog_prepare_pending_rows_event(table, server_id, len, is_trans,
@@ -3457,9 +3457,9 @@
uchar *after_row= row_data.slot(1);
size_t const before_size= pack_row(table, table->read_set, before_row,
- before_record);
+ before_record, TRUE);
size_t const after_size= pack_row(table, table->write_set, after_row,
- after_record);
+ after_record, TRUE);
/*
Don't print debug messages when running valgrind since they can
@@ -3501,7 +3501,7 @@
uchar *row_data= memory.slot(0);
DBUG_DUMP("table->read_set", (uchar*) table->read_set->bitmap, (table->s->fields + 7) / 8);
- size_t const len= pack_row(table, table->read_set, row_data, record);
+ size_t const len= pack_row(table, table->read_set, row_data, record, TRUE);
Rows_log_event* const ev=
binlog_prepare_pending_rows_event(table, server_id, len, is_trans,
| Thread |
|---|
| • bzr push into mysql-6.0-backup-merge branch (oystein.grovlen:2684 to 2686) | Oystein Grovlen | 15 Sep |