diff options
author | Tatiana A. Nurnberg <azundris@mysql.com> | 2010-03-29 03:32:30 +0100 |
---|---|---|
committer | Tatiana A. Nurnberg <azundris@mysql.com> | 2010-03-29 03:32:30 +0100 |
commit | 28e95ba535e175dc696fe7a739736ae9bf2a2b36 (patch) | |
tree | 6d2d62ce4463efb41a7a237232d44360c9cce500 | |
parent | 454c003a5c5a31a8d59ba4ab54d3b3a90a609752 (diff) | |
download | mariadb-git-28e95ba535e175dc696fe7a739736ae9bf2a2b36.tar.gz |
Bug#48525: trigger changes "Column 'id' cannot be null" behaviour
CHECK_FIELD_IGNORE was treated as CHECK_FIELD_ERROR_FOR_NULL;
UPDATE...SET...NULL on NOT NULL fields behaved differently after
a trigger.
Now distinguishes between IGNORE and ERROR_FOR_NULL and save/restores
check-field options.
mysql-test/r/trigger.result:
Show that UPDATE...SET...NULL on NOT NULL columns doesn't behave differently
when run after a trigger.
mysql-test/t/trigger.test:
Show that UPDATE...SET...NULL on NOT NULL columns doesn't behave differently
when run after a trigger.
sql/field_conv.cc:
CHECK_FIELD_IGNORE was treated as CHECK_FIELD_ERROR_FOR_NULL.
Distinguish between the two.
sql/sp_head.cc:
Raise error as needed.
sql/sql_class.cc:
Save and restore check-fields options.
sql/sql_class.h:
Make room so we can save check-fields options.
sql/sql_insert.cc:
Raise error as needed.
-rw-r--r-- | mysql-test/r/trigger.result | 17 | ||||
-rw-r--r-- | mysql-test/t/trigger.test | 13 | ||||
-rw-r--r-- | sql/field_conv.cc | 26 | ||||
-rw-r--r-- | sql/sp_head.cc | 1 | ||||
-rw-r--r-- | sql/sql_class.cc | 4 | ||||
-rw-r--r-- | sql/sql_class.h | 1 | ||||
-rw-r--r-- | sql/sql_insert.cc | 2 |
7 files changed, 55 insertions, 9 deletions
diff --git a/mysql-test/r/trigger.result b/mysql-test/r/trigger.result index 5758f5b93d7..3446babbb52 100644 --- a/mysql-test/r/trigger.result +++ b/mysql-test/r/trigger.result @@ -2111,4 +2111,21 @@ SET @bug51650 = 1; INSERT IGNORE INTO t2 SET a = '777'; DROP TRIGGER trg1; DROP TABLE t1, t2; +CREATE TABLE t1 (id INT NOT NULL); +CREATE TABLE t2 (id INT NOT NULL); +INSERT t1 VALUES (1),(2),(3); +UPDATE t1 SET id=NULL; +Warnings: +Warning 1048 Column 'id' cannot be null +Warning 1048 Column 'id' cannot be null +Warning 1048 Column 'id' cannot be null +CREATE TRIGGER t1_bu BEFORE UPDATE ON t1 FOR EACH ROW +INSERT INTO t2 VALUES (3); +UPDATE t1 SET id=NULL; +Warnings: +Warning 1048 Column 'id' cannot be null +Warning 1048 Column 'id' cannot be null +Warning 1048 Column 'id' cannot be null +DROP TRIGGER t1_bu; +DROP TABLE t1,t2; End of 5.1 tests. diff --git a/mysql-test/t/trigger.test b/mysql-test/t/trigger.test index 2ab8fa9ba1e..368271f1fb2 100644 --- a/mysql-test/t/trigger.test +++ b/mysql-test/t/trigger.test @@ -2426,4 +2426,17 @@ INSERT IGNORE INTO t2 SET a = '777'; DROP TRIGGER trg1; DROP TABLE t1, t2; +# +# Bug #48525: trigger changes "Column 'id' cannot be null" behaviour +# +CREATE TABLE t1 (id INT NOT NULL); +CREATE TABLE t2 (id INT NOT NULL); +INSERT t1 VALUES (1),(2),(3); +UPDATE t1 SET id=NULL; +CREATE TRIGGER t1_bu BEFORE UPDATE ON t1 FOR EACH ROW + INSERT INTO t2 VALUES (3); +UPDATE t1 SET id=NULL; +DROP TRIGGER t1_bu; +DROP TABLE t1,t2; + --echo End of 5.1 tests. diff --git a/sql/field_conv.cc b/sql/field_conv.cc index 3574534722e..0bffde9671a 100644 --- a/sql/field_conv.cc +++ b/sql/field_conv.cc @@ -122,13 +122,18 @@ set_field_to_null(Field *field) return 0; } field->reset(); - if (field->table->in_use->count_cuted_fields == CHECK_FIELD_WARN) - { + switch (field->table->in_use->count_cuted_fields) { + case CHECK_FIELD_WARN: field->set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, 1); + /* fall through */ + case CHECK_FIELD_IGNORE: return 0; + case CHECK_FIELD_ERROR_FOR_NULL: + if (!field->table->in_use->no_errors) + my_error(ER_BAD_NULL_ERROR, MYF(0), field->field_name); + return -1; } - if (!field->table->in_use->no_errors) - my_error(ER_BAD_NULL_ERROR, MYF(0), field->field_name); + DBUG_ASSERT(0); // impossible return -1; } @@ -178,13 +183,18 @@ set_field_to_null_with_conversions(Field *field, bool no_conversions) field->table->auto_increment_field_not_null= FALSE; return 0; // field is set in fill_record() } - if (field->table->in_use->count_cuted_fields == CHECK_FIELD_WARN) - { + switch (field->table->in_use->count_cuted_fields) { + case CHECK_FIELD_WARN: field->set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_BAD_NULL_ERROR, 1); + /* fall through */ + case CHECK_FIELD_IGNORE: return 0; + case CHECK_FIELD_ERROR_FOR_NULL: + if (!field->table->in_use->no_errors) + my_error(ER_BAD_NULL_ERROR, MYF(0), field->field_name); + return -1; } - if (!field->table->in_use->no_errors) - my_error(ER_BAD_NULL_ERROR, MYF(0), field->field_name); + DBUG_ASSERT(0); // impossible return -1; } diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 8a626cabd90..11d5e5f830b 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -3009,6 +3009,7 @@ int sp_instr_set_trigger_field::execute(THD *thd, uint *nextp) { DBUG_ENTER("sp_instr_set_trigger_field::execute"); + thd->count_cuted_fields= CHECK_FIELD_ERROR_FOR_NULL; DBUG_RETURN(m_lex_keeper.reset_lex_and_exec_core(thd, nextp, TRUE, this)); } diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 673fc9b78e6..266064f9f08 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -3100,6 +3100,7 @@ void THD::reset_sub_statement_state(Sub_statement_state *backup, } #endif + backup->count_cuted_fields= count_cuted_fields; backup->options= options; backup->in_sub_stmt= in_sub_stmt; backup->enable_slow_log= enable_slow_log; @@ -3137,6 +3138,7 @@ void THD::reset_sub_statement_state(Sub_statement_state *backup, void THD::restore_sub_statement_state(Sub_statement_state *backup) { + DBUG_ENTER("THD::restore_sub_statement_state"); #ifndef EMBEDDED_LIBRARY /* BUG#33029, if we are replicating from a buggy master, restore auto_inc_intervals_forced so that the top statement can use the @@ -3163,6 +3165,7 @@ void THD::restore_sub_statement_state(Sub_statement_state *backup) /* ha_release_savepoint() never returns error. */ (void)ha_release_savepoint(this, sv); } + count_cuted_fields= backup->count_cuted_fields; transaction.savepoints= backup->savepoints; options= backup->options; in_sub_stmt= backup->in_sub_stmt; @@ -3192,6 +3195,7 @@ void THD::restore_sub_statement_state(Sub_statement_state *backup) */ examined_row_count+= backup->examined_row_count; cuted_fields+= backup->cuted_fields; + DBUG_VOID_RETURN; } diff --git a/sql/sql_class.h b/sql/sql_class.h index 032985dc44e..2ddd9358382 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -995,6 +995,7 @@ public: bool enable_slow_log; bool last_insert_id_used; SAVEPOINT *savepoints; + enum enum_check_fields count_cuted_fields; }; diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 1f4ca90157f..35c24e7571e 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -3158,7 +3158,7 @@ bool select_insert::send_data(List<Item> &values) thd->count_cuted_fields= CHECK_FIELD_WARN; // Calculate cuted fields store_values(values); - thd->count_cuted_fields= CHECK_FIELD_IGNORE; + thd->count_cuted_fields= CHECK_FIELD_ERROR_FOR_NULL; if (thd->is_error()) { table->auto_increment_field_not_null= FALSE; |