4214 Dmitry Shulga 2012-09-24
Fixed bug in handling of default values of table fields inside BEFORE-trigger.
modified:
sql/field.cc
sql/field.h
sql/partition_info.cc
sql/sql_base.cc
sql/sql_base.h
sql/sql_executor.cc
sql/sql_insert.cc
sql/sql_load.cc
sql/sql_union.cc
sql/sql_update.cc
4213 Dmitry Shulga 2012-09-24
Fixed bug in multi-update.
modified:
mysql-test/r/wl6030.result
mysql-test/t/wl6030.test
sql/sql_update.cc
4212 Alexander Nozdrin 2012-09-21
Polish wl6030.test.
modified:
mysql-test/r/wl6030.result
mysql-test/t/wl6030.test
=== modified file 'mysql-test/r/wl6030.result'
--- a/mysql-test/r/wl6030.result 2012-09-21 14:30:00 +0000
+++ b/mysql-test/r/wl6030.result 2012-09-24 14:53:23 +0000
@@ -145,8 +145,6 @@ INSERT INTO t1 VALUES (1, 2, 3), (10, 20
CREATE TABLE t3(a INT, b INT);
INSERT INTO t3 VALUES (10, -10);
UPDATE t1, t3 SET t1.a = NULL, t3.a = -20 WHERE t1.a = t3.a AND t3.a = 10;
-Warnings:
-Warning 1048 Column 'a' cannot be null
SELECT * FROM t1;
a b c
@@ -158,8 +156,24 @@ SELECT * FROM t3;
a b
-20 -10
-DROP TABLE t3;
DROP TRIGGER t1_bu;
+DROP TABLE t3;
+DELETE FROM t1;
+CREATE TABLE t3(a INT NOT NULL, b INT);
+CREATE TRIGGER t3_bu BEFORE UPDATE ON t3 FOR EACH ROW SET NEW.a = 999;
+INSERT INTO t1 VALUES (1, 2, 3), (10, 20, 30), (100, 200, 300);
+INSERT INTO t3 VALUES (10, -10);
+UPDATE t1, t3 SET t1.a = -20, t3.a = NULL WHERE t1.a = t3.a AND t3.a = 10;
+SELECT * FROM t1;
+a b c
+1 2 3
+-20 20 30
+100 200 300
+SELECT * FROM t3;
+a b
+999 -10
+DROP TRIGGER t3_bu;
+DROP TABLE t3;
# - Test 2.1: SET to NULL.
CREATE TRIGGER t1_bu BEFORE UPDATE ON t1 FOR EACH ROW SET NEW.a = NULL;
@@ -494,8 +508,6 @@ INSERT INTO t1(a, b, c) VALUES (1, 2, 3)
CREATE TABLE t3(a INT, b INT);
INSERT INTO t3 VALUES (10, -10);
UPDATE t1, t3 SET t1.a = NULL, t3.a = -20 WHERE t1.a = t3.a AND t3.a = 10;
-Warnings:
-Warning 1048 Column 'a' cannot be null
SELECT * FROM t1;
a b c a_new_is_null a_old_is_null b_new_is_null b_old_is_null
=== modified file 'mysql-test/t/wl6030.test'
--- a/mysql-test/t/wl6030.test 2012-09-21 14:30:00 +0000
+++ b/mysql-test/t/wl6030.test 2012-09-24 14:53:23 +0000
@@ -136,7 +136,6 @@ INSERT INTO t1 VALUES (1, 2, 3), (10, 20
CREATE TABLE t3(a INT, b INT);
INSERT INTO t3 VALUES (10, -10);
-# FIXME: there should be no warnings here.
UPDATE t1, t3 SET t1.a = NULL, t3.a = -20 WHERE t1.a = t3.a AND t3.a = 10;
--echo
@@ -145,8 +144,21 @@ SELECT * FROM t1;
SELECT * FROM t3;
--echo
-DROP TABLE t3;
DROP TRIGGER t1_bu;
+DROP TABLE t3;
+DELETE FROM t1;
+
+CREATE TABLE t3(a INT NOT NULL, b INT);
+CREATE TRIGGER t3_bu BEFORE UPDATE ON t3 FOR EACH ROW SET NEW.a = 999;
+INSERT INTO t1 VALUES (1, 2, 3), (10, 20, 30), (100, 200, 300);
+INSERT INTO t3 VALUES (10, -10);
+
+UPDATE t1, t3 SET t1.a = -20, t3.a = NULL WHERE t1.a = t3.a AND t3.a = 10;
+
+SELECT * FROM t1;
+SELECT * FROM t3;
+DROP TRIGGER t3_bu;
+DROP TABLE t3;
--echo
--echo # - Test 2.1: SET to NULL.
@@ -434,7 +446,6 @@ INSERT INTO t1(a, b, c) VALUES (1, 2, 3)
CREATE TABLE t3(a INT, b INT);
INSERT INTO t3 VALUES (10, -10);
-# FIXME: there should be no warnings here.
UPDATE t1, t3 SET t1.a = NULL, t3.a = -20 WHERE t1.a = t3.a AND t3.a = 10;
--echo
=== modified file 'sql/field.cc'
--- a/sql/field.cc 2012-08-27 07:05:07 +0000
+++ b/sql/field.cc 2012-09-24 14:54:55 +0000
@@ -1441,11 +1441,18 @@ void Field::set_null(my_ptrdiff_t row_of
}
else if (is_tmp_nullable())
{
- m_is_tmp_null= true;
- m_count_cuted_fields_saved= table->in_use->count_cuted_fields;
+ set_tmp_null();
+// m_is_tmp_null= true;
+// m_count_cuted_fields_saved= table->in_use->count_cuted_fields;
}
}
+void Field::set_tmp_null()
+{
+ m_is_tmp_null= true;
+ m_count_cuted_fields_saved= table->in_use->count_cuted_fields;
+}
+
/**
Set field to value NOT NULL.
=== modified file 'sql/field.h'
--- a/sql/field.h 2012-08-27 07:05:07 +0000
+++ b/sql/field.h 2012-09-24 14:54:55 +0000
@@ -582,6 +582,8 @@ public:
void set_tmp_nullable(bool is_tmp_nullable)
{ m_is_tmp_nullable= is_tmp_nullable; }
+ void set_tmp_null();
+
/**
Return temporary NULLability flag.
=== modified file 'sql/partition_info.cc'
--- a/sql/partition_info.cc 2012-08-08 06:31:24 +0000
+++ b/sql/partition_info.cc 2012-09-24 14:54:55 +0000
@@ -442,12 +442,12 @@ bool partition_info::set_used_partition(
if (fields.elements || !values.elements)
{
- if (fill_record(thd, fields, values, false, &full_part_field_set))
+ if (fill_record(thd, fields, values, false, &full_part_field_set, NULL))
goto err;
}
else
{
- if (fill_record(thd, table->field, values, false, &full_part_field_set))
+ if (fill_record(thd, table->field, values, false, &full_part_field_set, NULL))
goto err;
}
DBUG_ASSERT(!table->auto_increment_field_not_null);
=== modified file 'sql/sql_base.cc'
--- a/sql/sql_base.cc 2012-09-13 09:24:15 +0000
+++ b/sql/sql_base.cc 2012-09-24 14:54:55 +0000
@@ -8833,7 +8833,8 @@ err_no_arena:
bool
fill_record(THD * thd, List<Item> &fields, List<Item> &values,
- bool ignore_errors, MY_BITMAP *bitmap)
+ bool ignore_errors, MY_BITMAP *bitmap,
+ MY_BITMAP *insert_into_fields_bitmap)
{
List_iterator_fast<Item> f(fields),v(values);
Item *value, *fld;
@@ -8882,6 +8883,8 @@ fill_record(THD * thd, List<Item> &field
goto err;
}
bitmap_set_bit(table->fields_set_during_insert, rfield->field_index);
+ if (insert_into_fields_bitmap)
+ bitmap_set_bit(insert_into_fields_bitmap, rfield->field_index);
}
DBUG_RETURN(thd->is_error());
err:
@@ -8966,17 +8969,55 @@ bool
fill_record_n_invoke_before_triggers(THD *thd, List<Item> &fields,
List<Item> &values, bool ignore_errors,
Table_triggers_list *triggers,
- enum trg_event_type event)
+ enum trg_event_type event,
+ uint bitmap_size)
{
if (triggers)
+ {
triggers->enable_fields_temporary_nullability(thd);
+ }
+
+ MY_BITMAP insert_into_fields_bitmap;
+ bool rc;
+
+ if (thd->lex->sql_command == SQLCOM_INSERT ||
+ thd->lex->sql_command == SQLCOM_INSERT_SELECT)
+ {
+ bitmap_init(&insert_into_fields_bitmap, NULL, bitmap_size, false);
+ rc= fill_record(thd, fields, values, ignore_errors, NULL,
+ &insert_into_fields_bitmap);
+ }
+ else
+ rc= fill_record(thd, fields, values, ignore_errors, NULL, NULL);
+
+ if (rc)
+ {
+ // Return error status if fill_record() failed.
- bool rc= fill_record(thd, fields, values, ignore_errors, NULL) ||
- (triggers &&
- triggers->process_triggers(thd, event, TRG_ACTION_BEFORE, true));
+ if (triggers)
+ triggers->disable_fields_temporary_nullability();
+
+ return true;
+ }
if (triggers)
+ {
+ if (thd->lex->sql_command == SQLCOM_INSERT ||
+ thd->lex->sql_command == SQLCOM_INSERT_SELECT)
+ {
+ TABLE *tbl= triggers->trigger_table;
+
+ for (Field** f= tbl->field; *f; ++f)
+ {
+ if (!bitmap_is_set(&insert_into_fields_bitmap, (*f)->field_index))
+ (*f)->set_tmp_null();
+ }
+ }
+
+ rc= triggers->process_triggers(thd, event, TRG_ACTION_BEFORE, true);
+
triggers->disable_fields_temporary_nullability();
+ }
if (rc)
return true;
@@ -9007,7 +9048,7 @@ fill_record_n_invoke_before_triggers(THD
bool
fill_record(THD *thd, Field **ptr, List<Item> &values, bool ignore_errors,
- MY_BITMAP *bitmap)
+ MY_BITMAP *bitmap, MY_BITMAP *insert_into_fields_bitmap)
{
List_iterator_fast<Item> v(values);
Item *value;
@@ -9045,6 +9086,8 @@ fill_record(THD *thd, Field **ptr, List<
*/
if (table->fields_set_during_insert)
bitmap_set_bit(table->fields_set_during_insert, field->field_index);
+ if (insert_into_fields_bitmap)
+ bitmap_set_bit(insert_into_fields_bitmap, field->field_index);
}
DBUG_ASSERT(thd->is_error() || !v++); // No extra value!
DBUG_RETURN(thd->is_error());
@@ -9083,17 +9126,57 @@ bool
fill_record_n_invoke_before_triggers(THD *thd, Field **ptr,
List<Item> &values, bool ignore_errors,
Table_triggers_list *triggers,
- enum trg_event_type event)
+ enum trg_event_type event,
+ uint bitmap_size)
{
if (triggers)
+ {
triggers->enable_fields_temporary_nullability(thd);
+ }
+
+ MY_BITMAP insert_into_fields_bitmap;
+ bool rc;
+ if (thd->lex->sql_command == SQLCOM_INSERT ||
+ thd->lex->sql_command == SQLCOM_INSERT_SELECT)
+ {
+ bitmap_init(&insert_into_fields_bitmap, NULL, bitmap_size, false);
+
+ rc= fill_record(thd, ptr, values, ignore_errors, NULL,
+ &insert_into_fields_bitmap);
+ }
+ else
+ rc= fill_record(thd, ptr, values, ignore_errors, NULL,
+ NULL);
- bool rc= fill_record(thd, ptr, values, ignore_errors, NULL) ||
- (triggers &&
- triggers->process_triggers(thd, event, TRG_ACTION_BEFORE, true));
+ if (rc)
+ {
+ // Return error status if fill_record() failed.
+
+ if (triggers)
+ triggers->disable_fields_temporary_nullability();
+
+ return true;
+ }
if (triggers)
+ {
+ if (thd->lex->sql_command == SQLCOM_INSERT ||
+ thd->lex->sql_command == SQLCOM_INSERT_SELECT)
+ {
+ TABLE *tbl= triggers->trigger_table;
+
+ for (Field** f= tbl->field; *f; ++f)
+ {
+ if (!bitmap_is_set(&insert_into_fields_bitmap, (*f)->field_index))
+ (*f)->set_tmp_null();
+ }
+ }
+
+ rc= triggers->process_triggers(thd, event, TRG_ACTION_BEFORE, true);
+
triggers->disable_fields_temporary_nullability();
+ }
+
if (rc)
return true;
=== modified file 'sql/sql_base.h'
--- a/sql/sql_base.h 2012-07-24 07:09:42 +0000
+++ b/sql/sql_base.h 2012-09-24 14:54:55 +0000
@@ -169,12 +169,14 @@ bool fill_record_n_invoke_before_trigger
List<Item> &values,
bool ignore_errors,
Table_triggers_list *triggers,
- enum trg_event_type event);
+ enum trg_event_type event,
+ uint bitmap_size);
bool fill_record_n_invoke_before_triggers(THD *thd, Field **field,
List<Item> &values,
bool ignore_errors,
Table_triggers_list *triggers,
- enum trg_event_type event);
+ enum trg_event_type event,
+ uint bitmap_size);
bool insert_fields(THD *thd, Name_resolution_context *context,
const char *db_name, const char *table_name,
List_iterator<Item> *it, bool any_privileges);
@@ -184,9 +186,11 @@ bool setup_fields(THD *thd, Ref_ptr_arra
List<Item> &item, enum_mark_columns mark_used_columns,
List<Item> *sum_func_list, bool allow_sum_func);
bool fill_record(THD * thd, List<Item> &fields, List<Item> &values,
- bool ignore_errors, MY_BITMAP *bitmap);
+ bool ignore_errors, MY_BITMAP *bitmap,
+ MY_BITMAP *insert_into_fields_bitmap);
bool fill_record(THD *thd, Field **field, List<Item> &values,
- bool ignore_errors, MY_BITMAP *bitmap);
+ bool ignore_errors, MY_BITMAP *bitmap,
+ MY_BITMAP *insert_into_fields_bitmap);
Field *
find_field_in_tables(THD *thd, Item_ident *item,
=== modified file 'sql/sql_executor.cc'
--- a/sql/sql_executor.cc 2012-08-03 12:40:53 +0000
+++ b/sql/sql_executor.cc 2012-09-24 14:54:55 +0000
@@ -614,7 +614,7 @@ end_sj_materialize(JOIN *join, JOIN_TAB
if (item->is_null())
DBUG_RETURN(NESTED_LOOP_OK);
}
- fill_record(thd, table->field, sjm->table_cols, 1, NULL);
+ fill_record(thd, table->field, sjm->table_cols, 1, NULL, NULL);
if (thd->is_error())
DBUG_RETURN(NESTED_LOOP_ERROR); /* purecov: inspected */
if ((error= table->file->ha_write_row(table->record[0])))
=== modified file 'sql/sql_insert.cc'
--- a/sql/sql_insert.cc 2012-09-18 01:50:47 +0000
+++ b/sql/sql_insert.cc 2012-09-24 14:54:55 +0000
@@ -1099,7 +1099,8 @@ bool mysql_insert(THD *thd,TABLE_LIST *t
restore_record(table,s->default_values); // Get empty record
if (fill_record_n_invoke_before_triggers(thd, fields, *values, 0,
table->triggers,
- TRG_EVENT_INSERT))
+ TRG_EVENT_INSERT,
+ table->s->fields))
{
if (values_list.elements != 1 && ! thd->is_error())
{
@@ -1161,7 +1162,8 @@ bool mysql_insert(THD *thd,TABLE_LIST *t
}
if (fill_record_n_invoke_before_triggers(thd, table->field, *values, 0,
table->triggers,
- TRG_EVENT_INSERT))
+ TRG_EVENT_INSERT,
+ table->s->fields))
{
if (values_list.elements != 1 && ! thd->is_error())
{
@@ -1867,7 +1869,7 @@ int write_record(THD *thd, TABLE *table,
*update->update_values,
ignore_errors,
table->triggers,
- TRG_EVENT_UPDATE))
+ TRG_EVENT_UPDATE, 0))
goto before_trg_err;
/* CHECK OPTION for VIEW ... ON DUPLICATE KEY UPDATE ... */
@@ -3793,10 +3795,12 @@ void select_insert::store_values(List<It
const bool ignore_err= true;
if (fields->elements)
fill_record_n_invoke_before_triggers(thd, *fields, values, ignore_err,
- table->triggers, TRG_EVENT_INSERT);
+ table->triggers, TRG_EVENT_INSERT,
+ table->s->fields);
else
fill_record_n_invoke_before_triggers(thd, table->field, values, ignore_err,
- table->triggers, TRG_EVENT_INSERT);
+ table->triggers, TRG_EVENT_INSERT,
+ table->s->fields);
check_that_all_fields_are_given_values(thd, table_list->table, table_list,
&missed_fields_handler);
@@ -4400,7 +4404,8 @@ void select_create::store_values(List<It
{
const bool ignore_err= true;
fill_record_n_invoke_before_triggers(thd, field, values, ignore_err,
- table->triggers, TRG_EVENT_INSERT);
+ table->triggers, TRG_EVENT_INSERT,
+ table->s->fields);
}
=== modified file 'sql/sql_load.cc'
--- a/sql/sql_load.cc 2012-09-17 15:26:51 +0000
+++ b/sql/sql_load.cc 2012-09-24 14:54:55 +0000
@@ -886,7 +886,8 @@ read_fixed_length(THD *thd, COPY_INFO &i
fill_record_n_invoke_before_triggers(thd, set_fields, set_values,
ignore_check_option_errors,
table->triggers,
- TRG_EVENT_INSERT))
+ TRG_EVENT_INSERT,
+ table->s->fields))
DBUG_RETURN(1);
switch (table_list->view_check_option(thd,
@@ -1117,7 +1118,8 @@ read_sep_field(THD *thd, COPY_INFO &info
fill_record_n_invoke_before_triggers(thd, set_fields, set_values,
ignore_check_option_errors,
table->triggers,
- TRG_EVENT_INSERT))
+ TRG_EVENT_INSERT,
+ table->s->fields))
DBUG_RETURN(1);
if (!table->triggers)
@@ -1307,7 +1309,8 @@ read_xml_field(THD *thd, COPY_INFO &info
fill_record_n_invoke_before_triggers(thd, set_fields, set_values,
ignore_check_option_errors,
table->triggers,
- TRG_EVENT_INSERT))
+ TRG_EVENT_INSERT,
+ table->s->fields))
DBUG_RETURN(1);
switch (table_list->view_check_option(thd,
=== modified file 'sql/sql_union.cc'
--- a/sql/sql_union.cc 2012-08-03 11:41:36 +0000
+++ b/sql/sql_union.cc 2012-09-24 14:54:55 +0000
@@ -90,7 +90,7 @@ bool select_union::send_data(List<Item>
unit->offset_limit_cnt--;
return 0;
}
- fill_record(thd, table->field, values, 1, NULL);
+ fill_record(thd, table->field, values, 1, NULL, NULL);
if (thd->is_error())
return 1;
=== modified file 'sql/sql_update.cc'
--- a/sql/sql_update.cc 2012-08-08 06:54:02 +0000
+++ b/sql/sql_update.cc 2012-09-24 14:54:55 +0000
@@ -809,7 +809,7 @@ int mysql_update(THD *thd,
store_record(table,record[1]);
if (fill_record_n_invoke_before_triggers(thd, fields, values, 0,
table->triggers,
- TRG_EVENT_UPDATE))
+ TRG_EVENT_UPDATE, 0))
break; /* purecov: inspected */
found++;
@@ -2086,7 +2086,7 @@ bool multi_update::send_data(List<Item>
*values_for_table[offset],
false, // ignore_errors
table->triggers,
- TRG_EVENT_UPDATE))
+ TRG_EVENT_UPDATE, 0))
DBUG_RETURN(1);
/*
@@ -2188,10 +2188,19 @@ bool multi_update::send_data(List<Item>
field_num++;
} while ((tbl= tbl_it++));
+ /*
+ Enable temporary nullability for temporary table fields.
+ */
+ for (Field** modified_fields= tmp_table->field + 1 + unupdated_check_opt_tables.elements;
+ *modified_fields; ++modified_fields)
+ {
+ (*modified_fields)->set_tmp_nullable(true);
+ }
+
/* Store regular updated fields in the row. */
fill_record(thd,
tmp_table->field + 1 + unupdated_check_opt_tables.elements,
- *values_for_table[offset], 1, NULL);
+ *values_for_table[offset], 1, NULL, NULL);
/* Write row, ignoring duplicated updates to a row */
error= tmp_table->file->ha_write_row(tmp_table->record[0]);
No bundle (reason: useless for push emails).
| Thread |
|---|
| • bzr push into mysql-trunk branch (Dmitry.Shulga:4212 to 4214) | Dmitry Shulga | 26 Sep |