From 12e53358f0845de0e31313b285653e7d75c575de Mon Sep 17 00:00:00 2001 From: "igor@rurik.mysql.com" <> Date: Sat, 20 May 2006 18:54:43 -0700 Subject: [PATCH 1/2] Fixed bug #19089. When a CREATE TABLE command created a table from a materialized view id does not inherit default values from the underlying table. Moreover the temporary table used for the view materialization does not inherit those default values. In the case when the underlying table contained ENUM fields it caused misleading error messages. In other cases the created table contained wrong default values. The code was modified to ensure inheritance of default values for materialized views. --- mysql-test/r/view.result | 42 ++++++++++++++++++++++++++++++++++++++++ mysql-test/t/view.test | 31 +++++++++++++++++++++++++++++ sql/field.cc | 1 + sql/field.h | 1 + sql/sql_select.cc | 38 ++++++++++++++++++++++++++++++------ 5 files changed, 107 insertions(+), 6 deletions(-) diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index 667d10cd145..4edee82029d 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -2649,3 +2649,45 @@ ldt 2006-01-01 03:00:00 drop view v1, v2; 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 +NULL 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 8f759c2d43e..d4f7876d75f 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -2512,3 +2512,34 @@ create view v2 as select convert_tz(dt, 'UTC', 'Europe/Moscow') as ldt from v1; select * from v2; drop view v1, v2; 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 bdf84c588e1..18105b31f97 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -1233,6 +1233,7 @@ Field::Field(char *ptr_arg,uint32 length_arg,uchar *null_ptr_arg, flags=null_ptr ? 0: NOT_NULL_FLAG; comment.str= (char*) ""; comment.length=0; + dflt_field= 0; } uint Field::offset() diff --git a/sql/field.h b/sql/field.h index f4d27e46877..1801f0d0f86 100644 --- a/sql/field.h +++ b/sql/field.h @@ -53,6 +53,7 @@ public: char *ptr; // Position to field in record uchar *null_ptr; // Byte where null_bit is + 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 465f41fa8de..576f4f1cb7a 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -8378,6 +8378,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; @@ -8394,7 +8395,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; @@ -8404,7 +8405,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; /* @@ -8438,6 +8438,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 */ @@ -8460,10 +8462,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; @@ -8914,6 +8916,30 @@ 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 + memcpy(field->ptr, from, field->pack_length()); + } + if (from_field[i]) { /* Not a table Item */ copy->set(field,from_field[i],save_sum_fields); From a6aaca7d6a8d56e075033e4f39c484b8bf81f46f Mon Sep 17 00:00:00 2001 From: "igor@rurik.mysql.com" <> Date: Mon, 22 May 2006 07:57:46 -0700 Subject: [PATCH 2/2] Post-review fixes for bug #19089 --- mysql-test/r/view.result | 2 +- sql/field.cc | 3 +-- sql/field.h | 5 +++++ sql/sql_select.cc | 3 +++ 4 files changed, 10 insertions(+), 3 deletions(-) diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index 6c2db5962dd..2aab169ba76 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -2716,7 +2716,7 @@ SELECT * FROM t2; a m xxx 1 yyy 5 -NULL 0 +xxx 0 DROP VIEW v1; DROP TABLE t1,t2; CREATE TABLE t1 (id int PRIMARY KEY, e ENUM('a','b') NOT NULL DEFAULT 'b'); diff --git a/sql/field.cc b/sql/field.cc index 18105b31f97..c31fbacc25e 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -1228,12 +1228,11 @@ 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*) ""; comment.length=0; - dflt_field= 0; } uint Field::offset() diff --git a/sql/field.h b/sql/field.h index 1801f0d0f86..4c3f6cd0709 100644 --- a/sql/field.h +++ b/sql/field.h @@ -53,6 +53,11 @@ 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 diff --git a/sql/sql_select.cc b/sql/sql_select.cc index b278b4ac167..1fe1747c44f 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -8697,7 +8697,10 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List &fields, if (is_null) field->set_null(); else + { + field->set_notnull(); memcpy(field->ptr, from, field->pack_length()); + } } if (from_field[i])