summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorunknown <lars/lthalmann@dl145h.mysql.com>2007-09-17 12:38:22 +0200
committerunknown <lars/lthalmann@dl145h.mysql.com>2007-09-17 12:38:22 +0200
commita7ace70e95dd714611ce0e2d636435c7e7d10812 (patch)
tree27d7a9a4f32afbf68deb65143071769a79487261 /sql
parent98dfab56286eb934e4ed44e842d80ff63420fd1e (diff)
parent14f5002d83fc4fe242f311501259955651214122 (diff)
downloadmariadb-git-a7ace70e95dd714611ce0e2d636435c7e7d10812.tar.gz
Merge mysql.com:/nfsdisk1/lars/bkroot/mysql-5.1-new-rpl
into mysql.com:/nfsdisk1/lars/MERGE/mysql-5.1-merge sql/field.cc: Auto merged sql/log_event.cc: Auto merged sql/rpl_utility.cc: Auto merged sql/rpl_utility.h: Auto merged sql/slave.cc: Auto merged sql/sql_insert.cc: Auto merged sql/sql_update.cc: Auto merged
Diffstat (limited to 'sql')
-rw-r--r--sql/field.cc1
-rw-r--r--sql/log_event.cc10
-rw-r--r--sql/rpl_utility.cc36
-rw-r--r--sql/rpl_utility.h14
-rw-r--r--sql/sql_delete.cc6
-rw-r--r--sql/sql_insert.cc106
-rw-r--r--sql/sql_load.cc2
-rw-r--r--sql/sql_update.cc2
8 files changed, 99 insertions, 78 deletions
diff --git a/sql/field.cc b/sql/field.cc
index fa93454c757..052f1cdf6d2 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -6732,6 +6732,7 @@ const uint Field_varstring::MAX_SIZE= UINT_MAX16;
int Field_varstring::do_save_field_metadata(uchar *metadata_ptr)
{
char *ptr= (char *)metadata_ptr;
+ DBUG_ASSERT(field_length <= 65535);
int2store(ptr, field_length);
return 2;
}
diff --git a/sql/log_event.cc b/sql/log_event.cc
index 44898ca8639..f03d4a25c38 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -6469,6 +6469,16 @@ void Rows_log_event::print_helper(FILE *file,
data) in the table map are initialized as zero (0). The array size is the
same as the columns for the table on the slave.
+ Additionally, values saved for field metadata on the master are saved as a
+ string of bytes (uchar) in the binlog. A field may require 1 or more bytes
+ to store the information. In cases where values require multiple bytes
+ (e.g. values > 255), the endian-safe methods are used to properly encode
+ the values on the master and decode them on the slave. When the field
+ metadata values are captured on the slave, they are stored in an array of
+ type uint16. This allows the least number of casts to prevent casting bugs
+ when the field metadata is used in comparisons of field attributes. When
+ the field metadata is used for calculating addresses in pointer math, the
+ type used is uint32.
*/
/**
diff --git a/sql/rpl_utility.cc b/sql/rpl_utility.cc
index d1ce5bf3b7b..b3ca26d4c2c 100644
--- a/sql/rpl_utility.cc
+++ b/sql/rpl_utility.cc
@@ -31,31 +31,34 @@ uint32 table_def::calc_field_size(uint col, uchar *master_data) const
switch (type(col)) {
case MYSQL_TYPE_NEWDECIMAL:
length= my_decimal_get_binary_size(m_field_metadata[col] >> 8,
- m_field_metadata[col] - ((m_field_metadata[col] >> 8) << 8));
+ m_field_metadata[col] & 0xff);
break;
case MYSQL_TYPE_DECIMAL:
case MYSQL_TYPE_FLOAT:
case MYSQL_TYPE_DOUBLE:
length= m_field_metadata[col];
break;
+ /*
+ The cases for SET and ENUM are include for completeness, however
+ both are mapped to type MYSQL_TYPE_STRING and their real types
+ are encoded in the field metadata.
+ */
case MYSQL_TYPE_SET:
case MYSQL_TYPE_ENUM:
case MYSQL_TYPE_STRING:
{
- if (((m_field_metadata[col] & 0xff00) == (MYSQL_TYPE_SET << 8)) ||
- ((m_field_metadata[col] & 0xff00) == (MYSQL_TYPE_ENUM << 8)))
+ uchar type= m_field_metadata[col] >> 8U;
+ if ((type == MYSQL_TYPE_SET) || (type == MYSQL_TYPE_ENUM))
length= m_field_metadata[col] & 0x00ff;
else
{
- length= m_field_metadata[col] & 0x00ff;
- DBUG_ASSERT(length > 0);
- if (length > 255)
- {
- DBUG_ASSERT(uint2korr(master_data) > 0);
- length= uint2korr(master_data) + 2;
- }
- else
- length= (uint) *master_data + 1;
+ /*
+ We are reading the actual size from the master_data record
+ because this field has the actual lengh stored in the first
+ byte.
+ */
+ length= (uint) *master_data + 1;
+ DBUG_ASSERT(length != 0);
}
break;
}
@@ -95,6 +98,13 @@ uint32 table_def::calc_field_size(uint col, uchar *master_data) const
break;
case MYSQL_TYPE_BIT:
{
+ /*
+ Decode the size of the bit field from the master.
+ from_len is the length in bytes from the master
+ from_bit_len is the number of extra bits stored in the master record
+ If from_bit_len is not 0, add 1 to the length to account for accurate
+ number of bytes needed.
+ */
uint from_len= (m_field_metadata[col] >> 8U) & 0x00ff;
uint from_bit_len= m_field_metadata[col] & 0x00ff;
DBUG_ASSERT(from_bit_len <= 7);
@@ -136,7 +146,7 @@ uint32 table_def::calc_field_size(uint col, uchar *master_data) const
length= *master_data;
break;
case 2:
- length= sint2korr(master_data);
+ length= uint2korr(master_data);
break;
case 3:
length= uint3korr(master_data);
diff --git a/sql/rpl_utility.h b/sql/rpl_utility.h
index 26edbdd1405..375715c7858 100644
--- a/sql/rpl_utility.h
+++ b/sql/rpl_utility.h
@@ -99,7 +99,7 @@ public:
/*
These types store a single byte.
*/
- m_field_metadata[i]= (uchar)field_metadata[index];
+ m_field_metadata[i]= field_metadata[index];
index++;
break;
}
@@ -107,14 +107,14 @@ public:
case MYSQL_TYPE_ENUM:
case MYSQL_TYPE_STRING:
{
- short int x= field_metadata[index++] << 8U; // real_type
- x = x + field_metadata[index++]; // pack or field length
+ uint16 x= field_metadata[index++] << 8U; // real_type
+ x+= field_metadata[index++]; // pack or field length
m_field_metadata[i]= x;
break;
}
case MYSQL_TYPE_BIT:
{
- short int x= field_metadata[index++];
+ uint16 x= field_metadata[index++];
x = x + (field_metadata[index++] << 8U);
m_field_metadata[i]= x;
break;
@@ -125,14 +125,14 @@ public:
These types store two bytes.
*/
char *ptr= (char *)&field_metadata[index];
- m_field_metadata[i]= sint2korr(ptr);
+ m_field_metadata[i]= uint2korr(ptr);
index= index + 2;
break;
}
case MYSQL_TYPE_NEWDECIMAL:
{
- short int x= field_metadata[index++] << 8U; // precision
- x = x + field_metadata[index++]; // decimals
+ uint16 x= field_metadata[index++] << 8U; // precision
+ x+= field_metadata[index++]; // decimals
m_field_metadata[i]= x;
break;
}
diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc
index 303918f42a2..d5e88ab8761 100644
--- a/sql/sql_delete.cc
+++ b/sql/sql_delete.cc
@@ -345,7 +345,7 @@ cleanup:
thd->transaction.stmt.modified_non_trans_table= TRUE;
/* See similar binlogging code in sql_update.cc, for comments */
- if ((error < 0) || (deleted && !transactional_table))
+ if ((error < 0) || thd->transaction.stmt.modified_non_trans_table)
{
if (mysql_bin_log.is_open())
{
@@ -862,7 +862,8 @@ bool multi_delete::send_eof()
{
query_cache_invalidate3(thd, delete_tables, 1);
}
- if ((local_error == 0) || (deleted && normal_tables))
+ DBUG_ASSERT(!normal_tables || !deleted || thd->transaction.stmt.modified_non_trans_table);
+ if ((local_error == 0) || thd->transaction.stmt.modified_non_trans_table)
{
if (mysql_bin_log.is_open())
{
@@ -879,7 +880,6 @@ bool multi_delete::send_eof()
if (thd->transaction.stmt.modified_non_trans_table)
thd->transaction.all.modified_non_trans_table= TRUE;
}
- DBUG_ASSERT(!normal_tables || !deleted || thd->transaction.stmt.modified_non_trans_table);
/* Commit or rollback the current SQL statement */
if (transactional_tables)
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index ebbf4cafb19..41e4fe4957e 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -839,59 +839,58 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
}
transactional_table= table->file->has_transactions();
- if ((changed= (info.copied || info.deleted || info.updated)) ||
- was_insert_delayed)
+ if ((changed= (info.copied || info.deleted || info.updated)))
{
/*
Invalidate the table in the query cache if something changed.
For the transactional algorithm to work the invalidation must be
before binlog writing and ha_autocommit_or_rollback
*/
- if (changed)
- query_cache_invalidate3(thd, table_list, 1);
- if (error <= 0 || !transactional_table)
+ query_cache_invalidate3(thd, table_list, 1);
+ }
+ if (changed && error <= 0 || thd->transaction.stmt.modified_non_trans_table
+ || was_insert_delayed)
+ {
+ if (mysql_bin_log.is_open())
{
- if (mysql_bin_log.is_open())
+ if (error <= 0)
{
- if (error <= 0)
- {
- /*
- [Guilhem wrote] Temporary errors may have filled
- thd->net.last_error/errno. For example if there has
- been a disk full error when writing the row, and it was
- MyISAM, then thd->net.last_error/errno will be set to
- "disk full"... and the my_pwrite() will wait until free
- space appears, and so when it finishes then the
- write_row() was entirely successful
- */
- /* todo: consider removing */
- thd->clear_error();
- }
- /* bug#22725:
-
- A query which per-row-loop can not be interrupted with
- KILLED, like INSERT, and that does not invoke stored
- routines can be binlogged with neglecting the KILLED error.
-
- If there was no error (error == zero) until after the end of
- inserting loop the KILLED flag that appeared later can be
- disregarded since previously possible invocation of stored
- routines did not result in any error due to the KILLED. In
- such case the flag is ignored for constructing binlog event.
- */
- DBUG_ASSERT(thd->killed != THD::KILL_BAD_DATA || error > 0);
- if (thd->binlog_query(THD::ROW_QUERY_TYPE,
- thd->query, thd->query_length,
- transactional_table, FALSE,
- (error>0) ? thd->killed : THD::NOT_KILLED) &&
- transactional_table)
- {
- error=1;
- }
- }
- if (thd->transaction.stmt.modified_non_trans_table)
- thd->transaction.all.modified_non_trans_table= TRUE;
+ /*
+ [Guilhem wrote] Temporary errors may have filled
+ thd->net.last_error/errno. For example if there has
+ been a disk full error when writing the row, and it was
+ MyISAM, then thd->net.last_error/errno will be set to
+ "disk full"... and the my_pwrite() will wait until free
+ space appears, and so when it finishes then the
+ write_row() was entirely successful
+ */
+ /* todo: consider removing */
+ thd->clear_error();
+ }
+ /* bug#22725:
+
+ A query which per-row-loop can not be interrupted with
+ KILLED, like INSERT, and that does not invoke stored
+ routines can be binlogged with neglecting the KILLED error.
+
+ If there was no error (error == zero) until after the end of
+ inserting loop the KILLED flag that appeared later can be
+ disregarded since previously possible invocation of stored
+ routines did not result in any error due to the KILLED. In
+ such case the flag is ignored for constructing binlog event.
+ */
+ DBUG_ASSERT(thd->killed != THD::KILL_BAD_DATA || error > 0);
+ if (thd->binlog_query(THD::ROW_QUERY_TYPE,
+ thd->query, thd->query_length,
+ transactional_table, FALSE,
+ (error>0) ? thd->killed : THD::NOT_KILLED) &&
+ transactional_table)
+ {
+ error=1;
+ }
}
+ if (thd->transaction.stmt.modified_non_trans_table)
+ thd->transaction.all.modified_non_trans_table= TRUE;
}
DBUG_ASSERT(transactional_table || !changed ||
thd->transaction.stmt.modified_non_trans_table);
@@ -3164,6 +3163,7 @@ void select_insert::abort() {
*/
if (table)
{
+ bool changed, transactional_table;
/*
If we are not in prelocked mode, we end the bulk insert started
before.
@@ -3185,20 +3185,20 @@ void select_insert::abort() {
If table creation failed, the number of rows modified will also be
zero, so no check for that is made.
*/
- if (info.copied || info.deleted || info.updated)
+ changed= (info.copied || info.deleted || info.updated);
+ transactional_table= table->file->has_transactions();
+ if (thd->transaction.stmt.modified_non_trans_table)
{
- DBUG_ASSERT(table != NULL);
- if (!table->file->has_transactions())
- {
if (mysql_bin_log.is_open())
thd->binlog_query(THD::ROW_QUERY_TYPE, thd->query, thd->query_length,
- table->file->has_transactions(), FALSE);
- if (!thd->current_stmt_binlog_row_based && !table->s->tmp_table &&
- !can_rollback_data())
+ transactional_table, FALSE);
+ if (!thd->current_stmt_binlog_row_based && !can_rollback_data())
thd->transaction.all.modified_non_trans_table= TRUE;
- query_cache_invalidate3(thd, table, 1);
- }
+ if (changed)
+ query_cache_invalidate3(thd, table, 1);
}
+ DBUG_ASSERT(transactional_table || !changed ||
+ thd->transaction.stmt.modified_non_trans_table);
table->file->ha_release_auto_increment();
}
diff --git a/sql/sql_load.cc b/sql/sql_load.cc
index 8bbe1e413b3..23547349a37 100644
--- a/sql/sql_load.cc
+++ b/sql/sql_load.cc
@@ -445,7 +445,7 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
/* If the file was not empty, wrote_create_file is true */
if (lf_info.wrote_create_file)
{
- if ((info.copied || info.deleted) && !transactional_table)
+ if (thd->transaction.stmt.modified_non_trans_table)
write_execute_load_query_log_event(thd, handle_duplicates,
ignore, transactional_table);
else
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index d4df805d006..2a469220fa7 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -797,7 +797,7 @@ int mysql_update(THD *thd,
Sometimes we want to binlog even if we updated no rows, in case user used
it to be sure master and slave are in same state.
*/
- if ((error < 0) || (updated && !transactional_table))
+ if ((error < 0) || thd->transaction.stmt.modified_non_trans_table)
{
if (mysql_bin_log.is_open())
{