diff --git a/mysql-test/suite/vcol/r/vcol_misc.result b/mysql-test/suite/vcol/r/vcol_misc.result index fe41e7e65f3..1826bf2dd3e 100644 --- a/mysql-test/suite/vcol/r/vcol_misc.result +++ b/mysql-test/suite/vcol/r/vcol_misc.result @@ -45,3 +45,20 @@ C 1 1 DROP TABLE t1; +CREATE TABLE t1(a int, b int DEFAULT 0, v INT AS (b+10) PERSISTENT); +INSERT INTO t1(a) VALUES (1); +SELECT b, v FROM t1; +b v +0 10 +DROP TABLE t1; +CREATE TABLE t1(a int DEFAULT 100, v int AS (a+1) PERSISTENT); +INSERT INTO t1 () VALUES (); +CREATE TABLE t2(a int DEFAULT 100 , v int AS (a+1)); +INSERT INTO t2 () VALUES (); +SELECT a, v FROM t1; +a v +100 101 +SELECT a, v FROM t2; +a v +100 101 +DROP TABLE t1,t2; diff --git a/mysql-test/suite/vcol/t/vcol_misc.test b/mysql-test/suite/vcol/t/vcol_misc.test index 2ed08a69fa2..67e4b18d596 100644 --- a/mysql-test/suite/vcol/t/vcol_misc.test +++ b/mysql-test/suite/vcol/t/vcol_misc.test @@ -43,5 +43,22 @@ SELECT 1 AS C FROM t1 ORDER BY v; DROP TABLE t1; +# +# Bug#603186: Insert for a table with stored vurtual columns +# +CREATE TABLE t1(a int, b int DEFAULT 0, v INT AS (b+10) PERSISTENT); +INSERT INTO t1(a) VALUES (1); +SELECT b, v FROM t1; +DROP TABLE t1; + +CREATE TABLE t1(a int DEFAULT 100, v int AS (a+1) PERSISTENT); +INSERT INTO t1 () VALUES (); +CREATE TABLE t2(a int DEFAULT 100 , v int AS (a+1)); +INSERT INTO t2 () VALUES (); + +SELECT a, v FROM t1; +SELECT a, v FROM t2; + +DROP TABLE t1,t2; diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 8baff521c02..af4a6577915 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -8204,6 +8204,8 @@ fill_record(THD * thd, List &fields, List &values, table->auto_increment_field_not_null= FALSE; f.rewind(); } + else if (thd->lex->unit.insert_table_with_stored_vcol) + tbl_list.push_back(thd->lex->unit.insert_table_with_stored_vcol); while ((fld= f++)) { if (!(field= fld->filed_for_view_update())) diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 54234eb8ab4..4ce13374d03 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -273,7 +273,7 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list, } /* Mark virtual columns used in the insert statement */ if (table->vfield) - table->mark_virtual_columns_for_write(); + table->mark_virtual_columns_for_write(TRUE); // For the values we need select_priv #ifndef NO_EMBEDDED_ACCESS_CHECKS table->grant.want_privilege= (SELECT_ACL & ~table->grant.privilege); @@ -1267,7 +1267,6 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, if (mysql_prepare_insert_check_table(thd, table_list, fields, select_insert)) DBUG_RETURN(TRUE); - /* Prepare the fields in the statement. */ if (values) { @@ -1320,6 +1319,18 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, if (!table) table= table_list->table; + if (!fields.elements && table->vfield) + { + for (Field **vfield_ptr= table->vfield; *vfield_ptr; vfield_ptr++) + { + if ((*vfield_ptr)->stored_in_db) + { + thd->lex->unit.insert_table_with_stored_vcol= table; + break; + } + } + } + if (!select_insert) { Item *fake_conds= 0; diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 51a87a3aa60..e380c94b58a 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -1590,6 +1590,7 @@ void st_select_lex_unit::init_query() item_list.empty(); describe= 0; found_rows_for_union= 0; + insert_table_with_stored_vcol= 0; } void st_select_lex::init_query() diff --git a/sql/sql_lex.h b/sql/sql_lex.h index de3e01e06a9..b571d7d707a 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -532,6 +532,13 @@ public: bool describe; /* union exec() called for EXPLAIN */ Procedure *last_procedure; /* Pointer to procedure, if such exists */ + /* + Insert table with stored virtual columns. + This is used only in those rare cases + when the list of inserted values is empty. + */ + TABLE *insert_table_with_stored_vcol; + void init_query(); st_select_lex_unit* master_unit(); st_select_lex* outer_select(); diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 624aab93e33..1c0a29c589d 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -7876,7 +7876,7 @@ copy_data_between_tables(TABLE *from,TABLE *to, /* Tell handler that we have values for all columns in the to table */ to->use_all_columns(); - to->mark_virtual_columns_for_write(); + to->mark_virtual_columns_for_write(TRUE); init_read_record(&info, thd, from, (SQL_SELECT *) 0, 1, 1, FALSE); errpos= 4; if (ignore) diff --git a/sql/table.cc b/sql/table.cc index 451515c1262..80c0c72d8f4 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -5024,7 +5024,7 @@ void st_table::mark_columns_needed_for_update() } } /* Mark all virtual columns needed for update */ - mark_virtual_columns_for_write(); + mark_virtual_columns_for_write(FALSE); DBUG_VOID_RETURN; } @@ -5052,7 +5052,7 @@ void st_table::mark_columns_needed_for_insert() if (found_next_number_field) mark_auto_increment_column(); /* Mark virtual columns for insert */ - mark_virtual_columns_for_write(); + mark_virtual_columns_for_write(TRUE); } @@ -5090,10 +5090,14 @@ bool st_table::mark_virtual_col(Field *field) /* @brief Mark virtual columns for update/insert commands + + @param insert_fl <-> virtual columns are marked for insert command @details The function marks virtual columns used in a update/insert commands in the vcol_set bitmap. + For an insert command a virtual column is always marked in write_set if + it is a stored column. If a virtual column is from write_set it is always marked in vcol_set. If a stored virtual column is not from write_set but it is computed through columns from write_set it is also marked in vcol_set, and, @@ -5112,7 +5116,7 @@ bool st_table::mark_virtual_col(Field *field) be added to read_set either. */ -void st_table::mark_virtual_columns_for_write(void) +void st_table::mark_virtual_columns_for_write(bool insert_fl) { Field **vfield_ptr, *tmp_vfield; bool bitmap_updated= FALSE; @@ -5124,16 +5128,21 @@ void st_table::mark_virtual_columns_for_write(void) bitmap_updated= mark_virtual_col(tmp_vfield); else if (tmp_vfield->stored_in_db) { - MY_BITMAP *save_read_set; - Item *vcol_item= tmp_vfield->vcol_info->expr_item; - DBUG_ASSERT(vcol_item); - bitmap_clear_all(&tmp_set); - save_read_set= read_set; - read_set= &tmp_set; - vcol_item->walk(&Item::register_field_in_read_map, 1, (uchar *) 0); - read_set= save_read_set; - bitmap_intersect(&tmp_set, write_set); - if (!bitmap_is_clear_all(&tmp_set)) + bool mark_fl= insert_fl; + if (!mark_fl) + { + MY_BITMAP *save_read_set; + Item *vcol_item= tmp_vfield->vcol_info->expr_item; + DBUG_ASSERT(vcol_item); + bitmap_clear_all(&tmp_set); + save_read_set= read_set; + read_set= &tmp_set; + vcol_item->walk(&Item::register_field_in_read_map, 1, (uchar *) 0); + read_set= save_read_set; + bitmap_intersect(&tmp_set, write_set); + mark_fl= !bitmap_is_clear_all(&tmp_set); + } + if (mark_fl) { bitmap_set_bit(write_set, tmp_vfield->field_index); mark_virtual_col(tmp_vfield); diff --git a/sql/table.h b/sql/table.h index 1424414ade8..fdd055daeeb 100644 --- a/sql/table.h +++ b/sql/table.h @@ -886,7 +886,7 @@ struct st_table { void mark_columns_needed_for_delete(void); void mark_columns_needed_for_insert(void); bool mark_virtual_col(Field *field); - void mark_virtual_columns_for_write(void); + void mark_virtual_columns_for_write(bool insert_fl); inline void column_bitmaps_set(MY_BITMAP *read_set_arg, MY_BITMAP *write_set_arg) {