diff options
author | Sergei Golubchik <serg@mariadb.org> | 2016-12-30 13:03:47 +0100 |
---|---|---|
committer | Sergei Golubchik <serg@mariadb.org> | 2017-02-13 18:12:04 +0100 |
commit | cd4dd2b62dda31a4ea1da99ca6732ecb7ee0d628 (patch) | |
tree | de21f02863d5dfe94b65b92211f3c730216d9068 | |
parent | 588eca31e3c60a6778e59e618717396eb5293ebe (diff) | |
download | mariadb-git-cd4dd2b62dda31a4ea1da99ca6732ecb7ee0d628.tar.gz |
MDEV-10201 Bad results for CREATE TABLE t1 (a INT DEFAULT b, b INT DEFAULT 4)
Optionally do table->update_default_fields() even for INSERT
that supposedly provides values for all column. Because these
"values" might be DEFAULT, which would need table->update_default_fields()
at the end.
Also set Item_default_value::used_tables() from the default expression.
Non-zero used_field() means that mysql_insert() will initialize all
fields to their default values (with restore_record()) even if
all columns are later provided with values. Because default expressions
may refer to other columns and they must be initialized.
-rw-r--r-- | mysql-test/r/default.result | 18 | ||||
-rw-r--r-- | mysql-test/t/default.test | 20 | ||||
-rw-r--r-- | sql/field.cc | 11 | ||||
-rw-r--r-- | sql/field.h | 12 | ||||
-rw-r--r-- | sql/item.cc | 18 | ||||
-rw-r--r-- | sql/item.h | 2 | ||||
-rw-r--r-- | sql/sql_base.cc | 7 | ||||
-rw-r--r-- | sql/sql_insert.cc | 1 |
8 files changed, 63 insertions, 26 deletions
diff --git a/mysql-test/r/default.result b/mysql-test/r/default.result index e3088e7ee85..014d4bee6c8 100644 --- a/mysql-test/r/default.result +++ b/mysql-test/r/default.result @@ -1553,7 +1553,7 @@ t1 CREATE TABLE `t1` ( `s` int(11) DEFAULT NULL, `b` timestamp(6) NOT NULL DEFAULT sysdate(6) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 -INSERT INTO t1 VALUES (DEFAULT, SLEEP(0.1), DEFAULT); +INSERT INTO t1 VALUES (DEFAULT(a), SLEEP(0.1), DEFAULT(b)); SELECT b>a FROM t1; b>a 1 @@ -3316,7 +3316,6 @@ ERROR 42000: Invalid default value for 'c' EXECUTE stmt USING @a; ERROR 42000: Invalid default value for 'c' DEALLOCATE PREPARE stmt; -# end of 10.2 test set sql_mode=ansi_quotes; create table t1 (a int, b int default (a+1)); show create table t1; @@ -3349,3 +3348,18 @@ a b 30 31 drop table t1; set sql_mode=default; +create table t1 (a int default b, b int default 4, t text); +insert into t1 (b, t) values (5, '1 column is omitted'); +insert into t1 values (default, 5, '2 column gets DEFAULT, keyword'); +insert into t1 values (default(a), 5, '3 column gets DEFAULT(a), expression'); +insert into t1 values (default(a)+0, 5, '4 also expression DEFAULT(0)+0'); +insert into t1 values (b, 5, '5 the value of the DEFAULT(a), that is b'); +select * from t1 order by t; +a b t +5 5 1 column is omitted +5 5 2 column gets DEFAULT, keyword +4 5 3 column gets DEFAULT(a), expression +4 5 4 also expression DEFAULT(0)+0 +4 5 5 the value of the DEFAULT(a), that is b +drop table t1; +# end of 10.2 test diff --git a/mysql-test/t/default.test b/mysql-test/t/default.test index d75966cd2dc..c96f8ac239b 100644 --- a/mysql-test/t/default.test +++ b/mysql-test/t/default.test @@ -1099,7 +1099,7 @@ SET time_zone=DEFAULT, timestamp= DEFAULT; # SYSDATE is evaluated during get_date() rather than fix_fields. CREATE TABLE t1 (a TIMESTAMP(6) DEFAULT SYSDATE(6), s INT, b TIMESTAMP(6) DEFAULT SYSDATE(6)); SHOW CREATE TABLE t1; -INSERT INTO t1 VALUES (DEFAULT, SLEEP(0.1), DEFAULT); +INSERT INTO t1 VALUES (DEFAULT(a), SLEEP(0.1), DEFAULT(b)); SELECT b>a FROM t1; DROP TABLE t1; @@ -2012,7 +2012,6 @@ INSERT INTO t1 VALUES (1),(2),(3); EXECUTE IMMEDIATE 'EXPLAIN EXTENDED SELECT * FROM t1 WHERE ?+a<=>?+a' USING DEFAULT,DEFAULT; DROP TABLE t1; - --echo # --echo # MDEV-11134 Assertion `fixed' failed in Item::const_charset_converter(THD*, CHARSET_INFO*, bool, const char*) --echo # @@ -2041,10 +2040,6 @@ EXECUTE stmt USING @a; EXECUTE stmt USING @a; DEALLOCATE PREPARE stmt; - - ---echo # end of 10.2 test - # # ANSI_QUOTES # @@ -2062,3 +2057,16 @@ select * from t1; drop table t1; set sql_mode=default; +# +# MDEV-10201 Bad results for CREATE TABLE t1 (a INT DEFAULT b, b INT DEFAULT 4) +# +create table t1 (a int default b, b int default 4, t text); +insert into t1 (b, t) values (5, '1 column is omitted'); +insert into t1 values (default, 5, '2 column gets DEFAULT, keyword'); +insert into t1 values (default(a), 5, '3 column gets DEFAULT(a), expression'); +insert into t1 values (default(a)+0, 5, '4 also expression DEFAULT(0)+0'); +insert into t1 values (b, 5, '5 the value of the DEFAULT(a), that is b'); +select * from t1 order by t; +drop table t1; + +--echo # end of 10.2 test diff --git a/sql/field.cc b/sql/field.cc index 23a8ecd965d..a458a42f282 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -5264,6 +5264,7 @@ int Field_timestamp::set_time() Mark the field as having an explicit default value. @param value if available, the value that the field is being set to + @returns whether the explicit default bit was set @note Fields that have an explicit default value should not be updated @@ -5279,13 +5280,14 @@ int Field_timestamp::set_time() This is how MySQL has worked since it's start. */ -void Field_timestamp::set_explicit_default(Item *value) +bool Field_timestamp::set_explicit_default(Item *value) { if (((value->type() == Item::DEFAULT_VALUE_ITEM && !((Item_default_value*)value)->arg) || (!maybe_null() && value->null_value))) - return; + return false; set_has_explicit_value(); + return true; } #ifdef NOT_USED @@ -10790,12 +10792,13 @@ key_map Field::get_possible_keys() analyzed to check if it really should count as a value. */ -void Field::set_explicit_default(Item *value) +bool Field::set_explicit_default(Item *value) { if (value->type() == Item::DEFAULT_VALUE_ITEM && !((Item_default_value*)value)->arg) - return; + return false; set_has_explicit_value(); + return true; } diff --git a/sql/field.h b/sql/field.h index f0c3b48cd6a..2dc5d91c126 100644 --- a/sql/field.h +++ b/sql/field.h @@ -954,7 +954,7 @@ public: { return bitmap_is_set(&table->has_value_set, field_index); } - virtual void set_explicit_default(Item *value); + virtual bool set_explicit_default(Item *value); /** Evaluates the @c UPDATE default function, if one exists, and stores the @@ -2379,9 +2379,9 @@ public: uint32 pack_length() const { return 4; } void sql_type(String &str) const; bool zero_pack() const { return 0; } - virtual int set_time(); - virtual void set_explicit_default(Item *value); - virtual int evaluate_update_default_function() + int set_time(); + bool set_explicit_default(Item *value); + int evaluate_update_default_function() { int res= 0; if (has_update_default_function()) @@ -2813,8 +2813,8 @@ public: void sql_type(String &str) const; bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate) { return Field_datetime::get_TIME(ltime, ptr, fuzzydate); } - virtual int set_time(); - virtual int evaluate_update_default_function() + int set_time(); + int evaluate_update_default_function() { int res= 0; if (has_update_default_function()) diff --git a/sql/item.cc b/sql/item.cc index 4ce0b318ed0..a2c59255b55 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -8834,15 +8834,23 @@ bool Item_default_value::send(Protocol *protocol, String *buffer) int Item_default_value::save_in_field(Field *field_arg, bool no_conversions) { if (arg) - calculate(); - else { - return field_arg->save_in_field_default_value(context->error_processor == - &view_error_processor); + calculate(); + return Item_field::save_in_field(field_arg, no_conversions); } - return Item_field::save_in_field(field_arg, no_conversions); + + if (field_arg->default_value && field_arg->default_value->flags) + return 0; // defaut fields will be set later, no need to do it twice + return field_arg->save_in_field_default_value(context->error_processor == + &view_error_processor); } +table_map Item_default_value::used_tables() const +{ + if (field && field->default_value && field->default_value->flags) + return field->default_value->expr->used_tables(); + return static_cast<table_map>(0); +} /** This method like the walk method traverses the item tree, but at the diff --git a/sql/item.h b/sql/item.h index bdea0289df9..07f489a35a3 100644 --- a/sql/item.h +++ b/sql/item.h @@ -5185,7 +5185,7 @@ public: param->set_default(); return false; } - table_map used_tables() const { return (table_map)0L; } + table_map used_tables() const; Field *get_tmp_table_field() { return 0; } Item *get_tmp_table_item(THD *thd) { return this; } Item_field *field_for_view_update() { return 0; } diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 3758b3ba710..cdbef309527 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -8102,6 +8102,7 @@ fill_record(THD *thd, TABLE *table, Field **ptr, List<Item> &values, { List_iterator_fast<Item> v(values); List<TABLE> tbl_list; + bool all_fields_have_values= true; Item *value; Field *field; bool abort_on_warning_saved= thd->abort_on_warning; @@ -8154,9 +8155,11 @@ fill_record(THD *thd, TABLE *table, Field **ptr, List<Item> &values, else if (value->save_in_field(field, 0) < 0) goto err; - field->set_explicit_default(value); + all_fields_have_values &= field->set_explicit_default(value); } - /* There is no default fields to update, as all fields are updated */ + if (!all_fields_have_values && table->default_field && + table->update_default_fields(0, ignore_errors)) + goto err; /* Update virtual fields */ thd->abort_on_warning= FALSE; if (table->vfield && diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 1e9de5a039a..8e8f6c7a26f 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -991,6 +991,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, share->default_values[share->null_bytes - 1]; } } + table->reset_default_fields(); if (fill_record_n_invoke_before_triggers(thd, table, table->field_to_fill(), *values, 0, TRG_EVENT_INSERT)) |