Below is the list of changes that have just been committed into a local
6.0-falcon repository of istruewing. When istruewing does a push these changes will
be propagated to the main repository and, within 24 hours after the
push, to the public repository.
For information on how to access the public repository
see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html
ChangeSet@stripped, 2007-06-28 22:24:01+02:00, istruewing@stripped +2 -0
Bug#28158 - table->read_set is set incorrectly,
causing wrong error message in Falcon
An error message about a duplicate key could show a wrong key
value when not all columns of the key were used to select the
rows for update.
Some storage engines return a record with only the selected
columns filled.
This is fixed by re-reading the record with a read_set which
includes all columns of the duplicate key after a duplicate key
error happens and before the error message is printed.
mysql-test/t/disabled.def@stripped, 2007-06-28 22:23:56+02:00, istruewing@stripped +0 -2
Bug#28158 - table->read_set is set incorrectly,
causing wrong error message in Falcon
Enabled test cases falcon_bug_28158 and falcon_bug_28165.
sql/sql_update.cc@stripped, 2007-06-28 22:23:56+02:00, istruewing@stripped +103 -1
Bug#28158 - table->read_set is set incorrectly,
causing wrong error message in Falcon
Added a function for re-reading a record with a read_set
that contains all fields used by a duplicate key.
Called the function before every call to handler::print_error(),
which could print a duplicate key value.
# This is a BitKeeper patch. What follows are the unified diffs for the
# set of deltas contained in the patch. The rest of the patch, the part
# that BitKeeper cares about, is below these diffs.
# User: istruewing
# Host: chilla.local
# Root: /home/mydev/mysql-5.1-falcon-bug28158
--- 1.245/sql/sql_update.cc 2007-06-28 22:24:10 +02:00
+++ 1.246/sql/sql_update.cc 2007-06-28 22:24:10 +02:00
@@ -83,6 +83,74 @@ static bool check_fields(THD *thd, List<
}
+/**
+ @brief Re-read record if more columns are needed for error message.
+
+ @detail If we got a duplicate key error, we want to write an error
+ message containing the value of the duplicate key. If we do not have
+ all fields of the key value in record[0], we need to re-read the
+ record with a proper read_set.
+
+ @param[in] thd thread handle
+ @param[in] error error number
+ @param[in] table table
+
+ @return Requirement for fill_record().
+ @retval TRUE fill_record() must be called on table->record[0].
+ @retval FALSE No need to do anything.
+*/
+
+static bool prepare_record_for_error_message(THD *thd, int error, TABLE *table)
+{
+ uint keynr;
+ MY_BITMAP unique_map; /* Fields in offended unique. */
+ my_bitmap_map unique_map_buf[bitmap_buffer_size(MAX_FIELDS)];
+ DBUG_ENTER("prepare_record_for_error_message");
+
+ /*
+ Only duplicate key errors print the key value.
+ If storage engine does always read all columns, we have the value alraedy.
+ */
+ if ((error != HA_ERR_FOUND_DUPP_KEY) ||
+ !(table->file->ha_table_flags() & HA_PARTIAL_COLUMN_READ))
+ DBUG_RETURN(FALSE);
+
+ /* Get the number of the offended index. */
+ keynr= table->file->get_dup_key(error);
+
+ /* Create unique_map with all fields used by that index. */
+ bitmap_init(&unique_map, unique_map_buf, table->s->fields, FALSE);
+ table->mark_columns_used_by_index_no_reset(keynr, &unique_map);
+
+ /* Subtract read_set and write_set. */
+ bitmap_subtract(&unique_map, table->read_set);
+ bitmap_subtract(&unique_map, table->write_set);
+
+ /*
+ If the unique index uses columns that are neither in read_set
+ nor in write_set, we must re-read the record.
+ Otherwise no need to do anything.
+ */
+ if (bitmap_is_clear_all(&unique_map))
+ DBUG_RETURN(FALSE);
+
+ /* Get identifier of last read reocrd into table->file->ref. */
+ table->file->position(table->record[0]);
+ /* Add all fields used by unique index to read_set. */
+ bitmap_union(table->read_set, &unique_map);
+ /* Tell the engine about the new set. */
+ table->file->column_bitmaps_signal();
+ /* Read record that is identified by table->file->ref. */
+ (void) table->file->rnd_pos(table->record[0], table->file->ref);
+ /*
+ Now we can be sure that we have a record that contains
+ the whole key value. But it is the old value.
+ fill_record() must be called on table->record[0].
+ */
+ DBUG_RETURN(TRUE);
+}
+
+
/*
Process usual UPDATE
@@ -471,6 +539,13 @@ int mysql_update(THD *thd,
will_batch= !table->file->start_bulk_update();
/*
+ Assure that we can use position()
+ if we need to create an error message.
+ */
+ if (table->file->ha_table_flags() & HA_PARTIAL_COLUMN_READ)
+ table->prepare_for_position();
+
+ /*
We can use compare_record() to optimize away updates if
the table handler is returning all columns OR if
if all updated columns are read
@@ -570,6 +645,11 @@ int mysql_update(THD *thd,
*/
if (table->file->is_fatal_error(error, HA_CHECK_DUP_KEY))
thd->fatal_error(); /* Other handler errors are fatal */
+
+ if (prepare_record_for_error_message(thd, error, table))
+ (void) fill_record_n_invoke_before_triggers(thd, fields, values,
+ 1, NULL,
+ TRG_EVENT_UPDATE);
table->file->print_error(error,MYF(0));
error= 1;
break;
@@ -597,6 +677,10 @@ int mysql_update(THD *thd,
The handler should not report error of duplicate keys if they
are ignored. This is a requirement on batching handlers.
*/
+ if (prepare_record_for_error_message(thd, error, table))
+ (void) fill_record_n_invoke_before_triggers(thd, fields, values,
+ 1, NULL,
+ TRG_EVENT_UPDATE);
table->file->print_error(error,MYF(0));
error= 1;
break;
@@ -666,6 +750,9 @@ int mysql_update(THD *thd,
*/
{
thd->fatal_error();
+ if (prepare_record_for_error_message(thd, loc_error, table))
+ (void) fill_record_n_invoke_before_triggers(thd, fields, values,
+ 1, NULL, TRG_EVENT_UPDATE);
table->file->print_error(loc_error,MYF(0));
error= 1;
}
@@ -1525,6 +1612,12 @@ bool multi_update::send_data(List<Item>
*/
if (table->file->is_fatal_error(error, HA_CHECK_DUP_KEY))
thd->fatal_error(); /* Other handler errors are fatal */
+
+ if (prepare_record_for_error_message(thd, error, table))
+ (void) fill_record_n_invoke_before_triggers(thd,
+ *fields_for_table[offset],
+ *values_for_table[offset],
+ 1, NULL, TRG_EVENT_UPDATE);
table->file->print_error(error,MYF(0));
DBUG_RETURN(1);
}
@@ -1616,8 +1709,10 @@ int multi_update::do_updates(bool from_s
int local_error= 0;
ha_rows org_updated;
TABLE *table, *tmp_table;
+ Copy_field *copy_field_ptr= copy_field, *copy_field_end;
List_iterator_fast<TABLE> check_opt_it(unupdated_check_opt_tables);
DBUG_ENTER("do_updates");
+ LINT_INIT(copy_field_end);
do_update= 0; // Don't retry this function
if (!found)
@@ -1650,7 +1745,6 @@ int multi_update::do_updates(bool from_s
List_iterator_fast<Item> field_it(*fields_for_table[offset]);
Field **field= tmp_table->field +
1 + unupdated_check_opt_tables.elements; // Skip row pointers
- Copy_field *copy_field_ptr= copy_field, *copy_field_end;
for ( ; *field ; field++)
{
Item_field *item= (Item_field* ) field_it++;
@@ -1753,6 +1847,14 @@ err:
if (!from_send_error)
{
thd->fatal_error();
+ if (prepare_record_for_error_message(thd, local_error, table))
+ {
+ /* Copy data from temporary table to current table */
+ for (copy_field_ptr= copy_field;
+ copy_field_ptr != copy_field_end;
+ copy_field_ptr++)
+ (*copy_field_ptr->do_copy)(copy_field_ptr);
+ }
table->file->print_error(local_error,MYF(0));
}
--- 1.335/mysql-test/t/disabled.def 2007-06-28 22:24:10 +02:00
+++ 1.336/mysql-test/t/disabled.def 2007-06-28 22:24:10 +02:00
@@ -72,8 +72,6 @@ falcon_bug_26827 : Bug#26827 2007-03-
falcon_bug_27426 : Bug#27426 2007-03-27 hakank Currently failing
falcon_bug_27997 : Bug#27997 2007-04-21 hakank Currently failing
falcon_bug_28026 : Bug#28026 2007-04-25 hakank Currently failing
-falcon_bug_28158 : Bug#28158 2007-05-02 hakank Currently failing
-falcon_bug_28165 : Bug#28158 2007-05-02 hakank Currently failing because of Bug#28158
falcon_bug_29246 : Bug#29246 2007-06-21 hakank Currently failing
falcon_bug_29319 : Bug#29319 2007-06-24 hakank Currently failing
falcon_page_size_1 : Bug#23220 2007-02-19 hakank Currently failing