From: Dmitry Shulga Date: September 24 2012 2:55pm Subject: bzr push into mysql-trunk branch (Dmitry.Shulga:4212 to 4214) List-Archive: http://lists.mysql.com/commits/144891 Message-Id: <201209241454.q8OEsLeM015751@acsmt357.oracle.com> MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit 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 &fields, List &values, - bool ignore_errors, MY_BITMAP *bitmap) + bool ignore_errors, MY_BITMAP *bitmap, + MY_BITMAP *insert_into_fields_bitmap) { List_iterator_fast f(fields),v(values); Item *value, *fld; @@ -8882,6 +8883,8 @@ fill_record(THD * thd, List &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 &fields, List &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 &values, bool ignore_errors, - MY_BITMAP *bitmap) + MY_BITMAP *bitmap, MY_BITMAP *insert_into_fields_bitmap) { List_iterator_fast 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 &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 &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 &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 *it, bool any_privileges); @@ -184,9 +186,11 @@ bool setup_fields(THD *thd, Ref_ptr_arra List &item, enum_mark_columns mark_used_columns, List *sum_func_list, bool allow_sum_func); bool fill_record(THD * thd, List &fields, List &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 &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(Listelements) 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(Listtriggers, 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 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 *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 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).