diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index 9dba51c26d9..10a9ac87748 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -2694,3 +2694,45 @@ Age 38 DROP VIEW v1; DROP TABLE t1; +CREATE TABLE t1 (id int NOT NULL PRIMARY KEY, a char(6) DEFAULT 'xxx'); +INSERT INTO t1(id) VALUES (1), (2), (3), (4); +INSERT INTO t1 VALUES (5,'yyy'), (6,'yyy'); +SELECT * FROM t1; +id a +1 xxx +2 xxx +3 xxx +4 xxx +5 yyy +6 yyy +CREATE VIEW v1(a, m) AS SELECT a, MIN(id) FROM t1 GROUP BY a; +SELECT * FROM v1; +a m +xxx 1 +yyy 5 +CREATE TABLE t2 SELECT * FROM v1; +INSERT INTO t2(m) VALUES (0); +SELECT * FROM t2; +a m +xxx 1 +yyy 5 +xxx 0 +DROP VIEW v1; +DROP TABLE t1,t2; +CREATE TABLE t1 (id int PRIMARY KEY, e ENUM('a','b') NOT NULL DEFAULT 'b'); +INSERT INTO t1(id) VALUES (1), (2), (3); +INSERT INTO t1 VALUES (4,'a'); +SELECT * FROM t1; +id e +1 b +2 b +3 b +4 a +CREATE VIEW v1(m, e) AS SELECT MIN(id), e FROM t1 GROUP BY e; +CREATE TABLE t2 SELECT * FROM v1; +SELECT * FROM t2; +m e +4 a +1 b +DROP VIEW v1; +DROP TABLE IF EXISTS t1,t2; diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index ae633b2cc38..535ba3da7fa 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -2571,4 +2571,33 @@ SELECT * FROM v1; DROP VIEW v1; DROP TABLE t1; +# +# Bug #19089: wrong inherited dafault values in temp table views +# +CREATE TABLE t1 (id int NOT NULL PRIMARY KEY, a char(6) DEFAULT 'xxx'); +INSERT INTO t1(id) VALUES (1), (2), (3), (4); +INSERT INTO t1 VALUES (5,'yyy'), (6,'yyy'); +SELECT * FROM t1; + +CREATE VIEW v1(a, m) AS SELECT a, MIN(id) FROM t1 GROUP BY a; +SELECT * FROM v1; + +CREATE TABLE t2 SELECT * FROM v1; +INSERT INTO t2(m) VALUES (0); +SELECT * FROM t2; + +DROP VIEW v1; +DROP TABLE t1,t2; + +CREATE TABLE t1 (id int PRIMARY KEY, e ENUM('a','b') NOT NULL DEFAULT 'b'); +INSERT INTO t1(id) VALUES (1), (2), (3); +INSERT INTO t1 VALUES (4,'a'); +SELECT * FROM t1; + +CREATE VIEW v1(m, e) AS SELECT MIN(id), e FROM t1 GROUP BY e; +CREATE TABLE t2 SELECT * FROM v1; +SELECT * FROM t2; + +DROP VIEW v1; +DROP TABLE IF EXISTS t1,t2; diff --git a/sql/field.cc b/sql/field.cc index 9c504f186b3..e1d7aaf6343 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -1223,7 +1223,7 @@ Field::Field(char *ptr_arg,uint32 length_arg,uchar *null_ptr_arg, field_name(field_name_arg), query_id(0), key_start(0), part_of_key(0), part_of_sortkey(0), unireg_check(unireg_check_arg), - field_length(length_arg),null_bit(null_bit_arg) + field_length(length_arg), null_bit(null_bit_arg), dflt_field(0) { flags=null_ptr ? 0: NOT_NULL_FLAG; comment.str= (char*) ""; diff --git a/sql/field.h b/sql/field.h index b473100eaab..602b4ea779d 100644 --- a/sql/field.h +++ b/sql/field.h @@ -54,6 +54,12 @@ public: char *ptr; // Position to field in record uchar *null_ptr; // Byte where null_bit is + /* + dflt_field is used only for the fields of temporary tables. + It points to the default value of the field in another table + from which this field has been created. + */ + Field *dflt_field; // Field to copy default value from /* Note that you can use table->in_use as replacement for current_thd member only inside of val_*() and store() members (e.g. you can't use it in cons) diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 810b7789f3d..b0505e26ce3 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -8197,6 +8197,7 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type, bool make_copy_field, uint convert_blob_length) { + Field *result; Item::Type orig_type= type; Item *orig_item= 0; @@ -8214,8 +8215,7 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type, case Item::SUM_FUNC_ITEM: { Item_sum *item_sum=(Item_sum*) item; - Field *result= item_sum->create_tmp_field(group, table, - convert_blob_length); + result= item_sum->create_tmp_field(group, table, convert_blob_length); if (!result) thd->fatal_error(); return result; @@ -8225,7 +8225,6 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type, { Item_field *field= (Item_field*) item; bool orig_modify= modify_item; - Field *result; if (orig_type == Item::REF_ITEM) modify_item= 0; /* @@ -8259,6 +8258,8 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type, convert_blob_length); if (orig_type == Item::REF_ITEM && orig_modify) ((Item_ref*)orig_item)->set_result_field(result); + if (field->field->eq_def(result)) + result->dflt_field= field->field; return result; } /* Fall through */ @@ -8281,10 +8282,10 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type, DBUG_ASSERT(((Item_result_field*)item)->result_field); *from_field= ((Item_result_field*)item)->result_field; } - return create_tmp_field_from_item(thd, item, table, (make_copy_field ? 0 : - copy_func), modify_item, - convert_blob_length); - case Item::TYPE_HOLDER: + return create_tmp_field_from_item(thd, item, table, + (make_copy_field ? 0 : copy_func), + modify_item, convert_blob_length); + case Item::TYPE_HOLDER: return ((Item_type_holder *)item)->make_field_by_type(table); default: // Dosen't have to be stored return 0; @@ -8739,6 +8740,33 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List &fields, null_count+= (field->field_length & 7); } field->reset(); + + if (field->dflt_field && field->dflt_field->ptr) + { + /* + field->dflt_field is set only in the cases when 'field' can + inherit the default value that is defined for the field referred + by the Item_field object from which 'field' has been created. + For a field created not from a Item_field item dflt_field == 0. + */ + my_ptrdiff_t diff; + Field *orig_field= field->dflt_field; + /* Get the value from default_values */ + diff= (my_ptrdiff_t) (orig_field->table->s->default_values- + orig_field->table->record[0]); + orig_field->move_field(diff); // Points now at default_values + bool is_null= orig_field->is_real_null(); + char *from= orig_field->ptr; + orig_field->move_field(-diff); // Back to record[0] + if (is_null) + field->set_null(); + else + { + field->set_notnull(); + memcpy(field->ptr, from, field->pack_length()); + } + } + if (from_field[i]) { /* Not a table Item */ copy->set(field,from_field[i],save_sum_fields);