diff options
Diffstat (limited to 'sql/table.cc')
-rw-r--r-- | sql/table.cc | 613 |
1 files changed, 208 insertions, 405 deletions
diff --git a/sql/table.cc b/sql/table.cc index f33e90d73b8..3d3bc3336ef 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -915,6 +915,54 @@ static uint upgrade_collation(ulong mysql_version, uint cs_number) } +void Column_definition_attributes::frm_pack_basic(uchar *buff) const +{ + int2store(buff + 3, length); + int2store(buff + 8, pack_flag); + buff[10]= (uchar) unireg_check; +} + + +void Column_definition_attributes::frm_unpack_basic(const uchar *buff) +{ + length= uint2korr(buff + 3); + pack_flag= uint2korr(buff + 8); + unireg_check= (Field::utype) MTYP_TYPENR((uint) buff[10]); +} + + +void Column_definition_attributes::frm_pack_charset(uchar *buff) const +{ + buff[11]= (uchar) (charset->number >> 8); + buff[14]= (uchar) charset->number; +} + + +bool Column_definition_attributes::frm_unpack_charset(TABLE_SHARE *share, + const uchar *buff) +{ + uint cs_org= buff[14] + (((uint) buff[11]) << 8); + uint cs_new= upgrade_collation(share->mysql_version, cs_org); + if (cs_org != cs_new) + share->incompatible_version|= HA_CREATE_USED_CHARSET; + if (cs_new && !(charset= get_charset(cs_new, MYF(0)))) + { + const char *csname= get_charset_name((uint) cs_new); + char tmp[10]; + if (!csname || csname[0] =='?') + { + my_snprintf(tmp, sizeof(tmp), "#%u", cs_new); + csname= tmp; + } + my_printf_error(ER_UNKNOWN_COLLATION, + "Unknown collation '%s' in table '%-.64s' definition", + MYF(0), csname, share->table_name.str); + return true; + } + return false; +} + + /* In MySQL 5.7 the null bits for not stored virtual fields are last. Calculate the position for these bits @@ -1145,6 +1193,38 @@ end: DBUG_RETURN(res); } + +static const Type_handler *old_frm_type_handler(uint pack_flag, + uint interval_nr) +{ + enum_field_types field_type= (enum_field_types) f_packtype(pack_flag); + DBUG_ASSERT(field_type < 16); + + if (!f_is_alpha(pack_flag)) + return Type_handler::get_handler_by_real_type(field_type); + + if (!f_is_packed(pack_flag)) + { + if (field_type == MYSQL_TYPE_DECIMAL) // 3.23 or 4.0 string + return &type_handler_string; + if (field_type == MYSQL_TYPE_VARCHAR) // Since mysql-5.0 + return &type_handler_varchar; + return NULL; // Error (bad frm?) + } + + if (f_is_blob(pack_flag)) + return &type_handler_blob; // QQ: exact type?? + + if (interval_nr) + { + if (f_is_enum(pack_flag)) + return &type_handler_enum; + return &type_handler_set; + } + return Type_handler::get_handler_by_real_type(field_type); +} + + /** Read data from a binary .frm file image into a TABLE_SHARE @@ -1191,8 +1271,7 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, size_t UNINIT_VAR(options_len); uchar *vcol_screen_pos; const uchar *options= 0; - size_t UNINIT_VAR(gis_options_len); - const uchar *gis_options= 0; + LEX_CUSTRING gis_options= { NULL, 0}; KEY first_keyinfo; uint len; uint ext_key_parts= 0; @@ -1288,10 +1367,10 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, case EXTRA2_GIS: #ifdef HAVE_SPATIAL { - if (gis_options) + if (gis_options.str) goto err; - gis_options= extra2; - gis_options_len= length; + gis_options.str= extra2; + gis_options.length= length; } #endif /*HAVE_SPATIAL*/ break; @@ -1782,83 +1861,19 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, for (i=0 ; i < share->fields; i++, strpos+=field_pack_length, field_ptr++) { - uint pack_flag, interval_nr, unireg_type, recpos, field_length; - uint vcol_info_length=0; - uint vcol_expr_length=0; - enum_field_types field_type; - CHARSET_INFO *charset=NULL; - Field::geometry_type geom_type= Field::GEOM_GEOMETRY; + uint interval_nr= 0, recpos; LEX_CSTRING comment; LEX_CSTRING name; Virtual_column_info *vcol_info= 0; - uint gis_length, gis_decimals, srid= 0; - Field::utype unireg_check; const Type_handler *handler; uint32 flags= 0; + Column_definition_attributes attr; if (new_frm_ver >= 3) { /* new frm file in 4.1 */ - field_length= uint2korr(strpos+3); recpos= uint3korr(strpos+5); - pack_flag= uint2korr(strpos+8); - unireg_type= (uint) strpos[10]; - interval_nr= (uint) strpos[12]; uint comment_length=uint2korr(strpos+15); - field_type=(enum_field_types) (uint) strpos[13]; - - /* charset and geometry_type share the same byte in frm */ - if (field_type == MYSQL_TYPE_GEOMETRY) - { -#ifdef HAVE_SPATIAL - uint gis_opt_read; - Field_geom::storage_type st_type; - geom_type= (Field::geometry_type) strpos[14]; - charset= &my_charset_bin; - gis_opt_read= gis_field_options_read(gis_options, gis_options_len, - &st_type, &gis_length, &gis_decimals, &srid); - gis_options+= gis_opt_read; - gis_options_len-= gis_opt_read; -#else - goto err; -#endif - } - else - { - uint cs_org= strpos[14] + (((uint) strpos[11]) << 8); - uint cs_new= upgrade_collation(share->mysql_version, cs_org); - if (cs_org != cs_new) - share->incompatible_version|= HA_CREATE_USED_CHARSET; - if (!cs_new) - charset= &my_charset_bin; - else if (!(charset= get_charset(cs_new, MYF(0)))) - { - const char *csname= get_charset_name((uint) cs_new); - char tmp[10]; - if (!csname || csname[0] =='?') - { - my_snprintf(tmp, sizeof(tmp), "#%u", cs_new); - csname= tmp; - } - my_printf_error(ER_UNKNOWN_COLLATION, - "Unknown collation '%s' in table '%-.64s' definition", - MYF(0), csname, share->table_name.str); - goto err; - } - } - - if ((uchar)field_type == (uchar)MYSQL_TYPE_VIRTUAL) - { - if (!interval_nr) // Expect non-null expression - goto err; - /* - MariaDB version 10.0 version. - The interval_id byte in the .frm file stores the length of the - expression statement for a virtual column. - */ - vcol_info_length= interval_nr; - interval_nr= 0; - } if (!comment_length) { @@ -1872,32 +1887,21 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, comment_pos+= comment_length; } - if (unireg_type & MYSQL57_GENERATED_FIELD) + if ((uchar) strpos[13] == (uchar) MYSQL_TYPE_VIRTUAL) { - unireg_type&= MYSQL57_GENERATED_FIELD; - /* - MySQL 5.7 generated fields - - byte 1 = 1 - byte 2,3 = expr length - byte 4 = stored_in_db - byte 5.. = expr + MariaDB version 10.0 version. + The interval_id byte in the .frm file stores the length of the + expression statement for a virtual column. */ - if ((uint)(vcol_screen_pos)[0] != 1) + uint vcol_info_length= (uint) strpos[12]; + + if (!vcol_info_length) // Expect non-null expression goto err; - vcol_info= new (&share->mem_root) Virtual_column_info(); - vcol_info_length= uint2korr(vcol_screen_pos + 1); - DBUG_ASSERT(vcol_info_length); - vcol_info->stored_in_db= vcol_screen_pos[3]; - vcol_info->utf8= 0; - vcol_screen_pos+= vcol_info_length + MYSQL57_GCOL_HEADER_SIZE;; - share->virtual_fields++; - vcol_info_length= 0; - } - if (vcol_info_length) - { + attr.frm_unpack_basic(strpos); + if (attr.frm_unpack_charset(share, strpos)) + goto err; /* Old virtual field information before 10.2 @@ -1911,7 +1915,9 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, vcol_info= new (&share->mem_root) Virtual_column_info(); bool opt_interval_id= (uint)vcol_screen_pos[0] == 2; - field_type= (enum_field_types) (uchar) vcol_screen_pos[1]; + enum_field_types ftype= (enum_field_types) (uchar) vcol_screen_pos[1]; + if (!(handler= Type_handler::get_handler_by_real_type(ftype))) + goto err; if (opt_interval_id) interval_nr= (uint)vcol_screen_pos[3]; else if ((uint)vcol_screen_pos[0] != 1) @@ -1919,26 +1925,63 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, bool stored= vcol_screen_pos[2] & 1; vcol_info->stored_in_db= stored; vcol_info->set_vcol_type(stored ? VCOL_GENERATED_STORED : VCOL_GENERATED_VIRTUAL); - vcol_expr_length= vcol_info_length - - (uint)(FRM_VCOL_OLD_HEADER_SIZE(opt_interval_id)); + uint vcol_expr_length= vcol_info_length - + (uint)(FRM_VCOL_OLD_HEADER_SIZE(opt_interval_id)); vcol_info->utf8= 0; // before 10.2.1 the charset was unknown int2store(vcol_screen_pos+1, vcol_expr_length); // for parse_vcol_defs() vcol_screen_pos+= vcol_info_length; share->virtual_fields++; } + else + { + interval_nr= (uint) strpos[12]; + enum_field_types field_type= (enum_field_types) strpos[13]; + if (!(handler= Type_handler::get_handler_by_real_type(field_type))) + goto err; // Not supported field type + if (handler->Column_definition_attributes_frm_unpack(&attr, share, + strpos, + &gis_options)) + goto err; + } + + if (((uint) strpos[10]) & MYSQL57_GENERATED_FIELD) + { + attr.unireg_check= Field::NONE; + + /* + MySQL 5.7 generated fields + + byte 1 = 1 + byte 2,3 = expr length + byte 4 = stored_in_db + byte 5.. = expr + */ + if ((uint)(vcol_screen_pos)[0] != 1) + goto err; + vcol_info= new (&share->mem_root) Virtual_column_info(); + uint vcol_info_length= uint2korr(vcol_screen_pos + 1); + DBUG_ASSERT(vcol_info_length); + vcol_info->stored_in_db= vcol_screen_pos[3]; + vcol_info->utf8= 0; + vcol_screen_pos+= vcol_info_length + MYSQL57_GCOL_HEADER_SIZE;; + share->virtual_fields++; + } } else { - field_length= (uint) strpos[3]; + attr.length= (uint) strpos[3]; recpos= uint2korr(strpos+4), - pack_flag= uint2korr(strpos+6); - pack_flag&= ~FIELDFLAG_NO_DEFAULT; // Safety for old files - unireg_type= (uint) strpos[8]; + attr.pack_flag= uint2korr(strpos+6); + attr.pack_flag&= ~FIELDFLAG_NO_DEFAULT; // Safety for old files + attr.unireg_check= (Field::utype) MTYP_TYPENR((uint) strpos[8]); interval_nr= (uint) strpos[10]; /* old frm file */ - field_type= (enum_field_types) f_packtype(pack_flag); - if (f_is_binary(pack_flag)) + enum_field_types ftype= (enum_field_types) f_packtype(attr.pack_flag); + if (!(handler= Type_handler::get_handler_by_real_type(ftype))) + goto err; // Not supported field type + + if (f_is_binary(attr.pack_flag)) { /* Try to choose the best 4.1 type: @@ -1946,26 +1989,26 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, try to find a binary collation for character set. - for other types (e.g. BLOB) just use my_charset_bin. */ - if (!f_is_blob(pack_flag)) + if (!f_is_blob(attr.pack_flag)) { // 3.23 or 4.0 string - if (!(charset= get_charset_by_csname(share->table_charset->csname, - MY_CS_BINSORT, MYF(0)))) - charset= &my_charset_bin; + if (!(attr.charset= get_charset_by_csname(share->table_charset->csname, + MY_CS_BINSORT, MYF(0)))) + attr.charset= &my_charset_bin; } - else - charset= &my_charset_bin; } else - charset= share->table_charset; + attr.charset= share->table_charset; bzero((char*) &comment, sizeof(comment)); + if ((!(handler= old_frm_type_handler(attr.pack_flag, interval_nr)))) + goto err; // Not supported field type } /* Remove >32 decimals from old files */ if (share->mysql_version < 100200) - pack_flag&= ~FIELDFLAG_LONG_DECIMAL; + attr.pack_flag&= ~FIELDFLAG_LONG_DECIMAL; - if (interval_nr && charset->mbminlen > 1) + if (interval_nr && attr.charset->mbminlen > 1) { /* Unescape UCS2 intervals from HEX notation */ TYPELIB *interval= share->intervals + interval_nr - 1; @@ -1973,17 +2016,18 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, } #ifndef TO_BE_DELETED_ON_PRODUCTION - if (field_type == MYSQL_TYPE_NEWDECIMAL && !share->mysql_version) + if (handler->real_field_type() == MYSQL_TYPE_NEWDECIMAL && + !share->mysql_version) { /* Fix pack length of old decimal values from 5.0.3 -> 5.0.4 The difference is that in the old version we stored precision in the .frm table while we now store the display_length */ - uint decimals= f_decimals(pack_flag); - field_length= my_decimal_precision_to_length(field_length, - decimals, - f_is_dec(pack_flag) == 0); + uint decimals= f_decimals(attr.pack_flag); + attr.length= + my_decimal_precision_to_length((uint) attr.length, decimals, + f_is_dec(attr.pack_flag) == 0); sql_print_error("Found incompatible DECIMAL field '%s' in %s; " "Please do \"ALTER TABLE '%s' FORCE\" to fix it!", share->fieldnames.type_names[i], share->table_name.str, @@ -2014,7 +2058,7 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, if (flags & VERS_SYSTEM_FIELD) { - switch (field_type) + switch (handler->real_field_type()) { case MYSQL_TYPE_TIMESTAMP2: case MYSQL_TYPE_DATETIME2: @@ -2036,22 +2080,17 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, } /* Convert pre-10.2.2 timestamps to use Field::default_value */ - unireg_check= (Field::utype) MTYP_TYPENR(unireg_type); name.str= fieldnames.type_names[i]; name.length= strlen(name.str); - if (!(handler= Type_handler::get_handler_by_real_type(field_type))) - goto err; // Not supported field type + attr.interval= interval_nr ? share->intervals + interval_nr - 1 : NULL; + Record_addr addr(record + recpos, null_pos, null_bit_pos); *field_ptr= reg_field= - make_field(share, &share->mem_root, record+recpos, (uint32) field_length, - null_pos, null_bit_pos, pack_flag, handler, charset, - geom_type, srid, unireg_check, - (interval_nr ? share->intervals+interval_nr-1 : NULL), - &name, flags); + attr.make_field(share, &share->mem_root, &addr, handler, &name, flags); if (!reg_field) // Not supported field type goto err; - if (unireg_check == Field::TIMESTAMP_DNUN_FIELD || - unireg_check == Field::TIMESTAMP_DN_FIELD) + if (attr.unireg_check == Field::TIMESTAMP_DNUN_FIELD || + attr.unireg_check == Field::TIMESTAMP_DN_FIELD) { reg_field->default_value= new (&share->mem_root) Virtual_column_info(); reg_field->default_value->set_vcol_type(VCOL_DEFAULT); @@ -2075,10 +2114,11 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, status_var_increment(thd->status_var.feature_invisible_columns); if (!reg_field->invisible) share->visible_fields++; - if (field_type == MYSQL_TYPE_BIT && !f_bit_as_char(pack_flag)) + if (handler->real_field_type() == MYSQL_TYPE_BIT && + !f_bit_as_char(attr.pack_flag)) { null_bits_are_used= 1; - if ((null_bit_pos+= field_length & 7) > 7) + if ((null_bit_pos+= (uint) (attr.length & 7)) > 7) { null_pos++; null_bit_pos-= 8; @@ -2101,7 +2141,7 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, } } - if (f_no_default(pack_flag)) + if (f_no_default(attr.pack_flag)) reg_field->flags|= NO_DEFAULT_VALUE_FLAG; if (reg_field->unireg_check == Field::NEXT_NUMBER) @@ -2882,7 +2922,7 @@ bool fix_session_vcol_expr(THD *thd, Virtual_column_info *vcol) DBUG_RETURN(0); vcol->expr->walk(&Item::cleanup_excluding_fields_processor, 0, 0); - DBUG_ASSERT(!vcol->expr->fixed); + DBUG_ASSERT(!vcol->expr->is_fixed()); DBUG_RETURN(fix_vcol_expr(thd, vcol)); } @@ -2937,7 +2977,7 @@ static bool fix_and_check_vcol_expr(THD *thd, TABLE *table, DBUG_PRINT("info", ("vcol: %p", vcol)); DBUG_ASSERT(func_expr); - if (func_expr->fixed) + if (func_expr->is_fixed()) DBUG_RETURN(0); // nothing to do if (fix_vcol_expr(thd, vcol)) @@ -2981,7 +3021,7 @@ static bool fix_and_check_vcol_expr(THD *thd, TABLE *table, of the statement because the field item does not have a field pointer at that time */ - myf warn= table->s->frm_version < FRM_VER_EXPRESSSIONS ? ME_JUST_WARNING : 0; + myf warn= table->s->frm_version < FRM_VER_EXPRESSSIONS ? ME_WARNING : 0; my_error(ER_VIRTUAL_COLUMN_FUNCTION_IS_NOT_ALLOWED, MYF(warn), "AUTO_INCREMENT", vcol->get_vcol_type_name(), res.name); if (!warn) @@ -3428,17 +3468,6 @@ partititon_err: (my_bitmap_map*) bitmaps, share->fields, FALSE); bitmaps+= bitmap_size; - /* Don't allocate vcol_bitmap if we don't need it */ - if (share->virtual_fields) - { - if (!(outparam->def_vcol_set= (MY_BITMAP*) - alloc_root(&outparam->mem_root, sizeof(*outparam->def_vcol_set)))) - goto err; - my_bitmap_init(outparam->def_vcol_set, - (my_bitmap_map*) bitmaps, share->fields, FALSE); - bitmaps+= bitmap_size; - } - my_bitmap_init(&outparam->has_value_set, (my_bitmap_map*) bitmaps, share->fields, FALSE); bitmaps+= bitmap_size; @@ -3631,7 +3660,7 @@ void open_table_error(TABLE_SHARE *share, enum open_frm_error error, int db_errno) { char buff[FN_REFLEN]; - const myf errortype= ME_ERROR+ME_WAITTANG; // Write fatals error to log + const myf errortype= ME_ERROR_LOG; // Write fatals error to log DBUG_ENTER("open_table_error"); DBUG_PRINT("info", ("error: %d db_errno: %d", error, db_errno)); @@ -4887,7 +4916,7 @@ bool TABLE_LIST::prep_where(THD *thd, Item **conds, if (where) { - if (where->fixed) + if (where->is_fixed()) where->update_used_tables(); else if (where->fix_fields(thd, &where)) DBUG_RETURN(TRUE); @@ -5212,7 +5241,7 @@ int TABLE_LIST::view_check_option(THD *thd, bool ignore_failure) main_view->db.str); const char *name_table= (main_view->view ? main_view->view_name.str : main_view->table_name.str); - my_error(ER_VIEW_CHECK_FAILED, MYF(ignore_failure ? ME_JUST_WARNING : 0), + my_error(ER_VIEW_CHECK_FAILED, MYF(ignore_failure ? ME_WARNING : 0), name_db, name_table); return ignore_failure ? VIEW_CHECK_SKIP : VIEW_CHECK_ERROR; } @@ -5246,7 +5275,7 @@ int TABLE::verify_constraints(bool ignore_failure) in_use->is_error()) { my_error(ER_CONSTRAINT_FAILED, - MYF(ignore_failure ? ME_JUST_WARNING : 0), (*chk)->name.str, + MYF(ignore_failure ? ME_WARNING : 0), (*chk)->name.str, s->db.str, s->error_table_name()); return ignore_failure ? VIEW_CHECK_SKIP : VIEW_CHECK_ERROR; } @@ -5902,13 +5931,13 @@ Item *create_view_field(THD *thd, TABLE_LIST *view, Item **field_ref, ('mysql_schema_table' function). So we can return directly the field. This case happens only for 'show & where' commands. */ - DBUG_ASSERT(field && field->fixed); + DBUG_ASSERT(field && field->is_fixed()); DBUG_RETURN(field); } DBUG_ASSERT(field); thd->lex->current_select->no_wrap_view_item= TRUE; - if (!field->fixed) + if (!field->is_fixed()) { if (field->fix_fields(thd, field_ref)) { @@ -6246,13 +6275,12 @@ void TABLE::clear_column_bitmaps() Reset column read/write usage. It's identical to: bitmap_clear_all(&table->def_read_set); bitmap_clear_all(&table->def_write_set); - if (s->virtual_fields) bitmap_clear_all(table->def_vcol_set); The code assumes that the bitmaps are allocated after each other, as guaranteed by open_table_from_share() */ bzero((char*) def_read_set.bitmap, s->column_bitmap_size * (s->virtual_fields ? 3 : 2)); - column_bitmaps_set(&def_read_set, &def_write_set, def_vcol_set); + column_bitmaps_set(&def_read_set, &def_write_set); rpl_write_set= 0; // Safety } @@ -6399,13 +6427,8 @@ void TABLE::mark_columns_needed_for_delete() Field **reg_field; for (reg_field= field ; *reg_field ; reg_field++) { - Field *cur_field= *reg_field; - if (cur_field->flags & (PART_KEY_FLAG | PART_INDIRECT_KEY_FLAG)) - { - bitmap_set_bit(read_set, cur_field->field_index); - if (cur_field->vcol_info) - bitmap_set_bit(vcol_set, cur_field->field_index); - } + if ((*reg_field)->flags & (PART_KEY_FLAG | PART_INDIRECT_KEY_FLAG)) + mark_column_with_deps(*reg_field); } need_signal= true; } @@ -6484,13 +6507,7 @@ void TABLE::mark_columns_needed_for_update() if (any_written && !all_read) { for (KEY_PART_INFO *kp= k->key_part; kp < kpend; kp++) - { - int idx= kp->fieldnr - 1; - if (bitmap_fast_test_and_set(read_set, idx)) - continue; - if (field[idx]->vcol_info) - mark_virtual_col(field[idx]); - } + mark_column_with_deps(field[kp->fieldnr - 1]); } } need_signal= true; @@ -6687,49 +6704,12 @@ void TABLE::mark_columns_per_binlog_row_image() DBUG_ASSERT(FALSE); } } - /* - We have to ensure that all virtual columns that are part of read set - are calculated. - */ - if (vcol_set) - bitmap_union(vcol_set, read_set); file->column_bitmaps_signal(); } DBUG_VOID_RETURN; } -/* - @brief Mark a column as virtual used by the query - - @param field the field for the column to be marked - - @details - The function marks the column for 'field' as virtual (computed) - in the bitmap vcol_set. - If the column is marked for the first time the expression to compute - the column is traversed and all columns that are occurred there are - marked in the read_set of the table. - - @retval - TRUE if column is marked for the first time - @retval - FALSE otherwise -*/ - -bool TABLE::mark_virtual_col(Field *field) -{ - bool res; - DBUG_ASSERT(field->vcol_info); - if (!(res= bitmap_fast_test_and_set(vcol_set, field->field_index))) - { - Item *vcol_item= field->vcol_info->expr; - DBUG_ASSERT(vcol_item); - vcol_item->walk(&Item::register_field_in_read_map, 1, 0); - } - return res; -} - /* @brief Mark virtual columns for update/insert commands @@ -6771,13 +6751,13 @@ bool TABLE::mark_virtual_columns_for_write(bool insert_fl { tmp_vfield= *vfield_ptr; if (bitmap_is_set(write_set, tmp_vfield->field_index)) - bitmap_updated|= mark_virtual_col(tmp_vfield); + bitmap_updated|= mark_virtual_column_with_deps(tmp_vfield); else if (tmp_vfield->vcol_info->stored_in_db || (tmp_vfield->flags & (PART_KEY_FLAG | FIELD_IN_PART_FUNC_FLAG | PART_INDIRECT_KEY_FLAG))) { bitmap_set_bit(write_set, tmp_vfield->field_index); - mark_virtual_col(tmp_vfield); + mark_virtual_column_with_deps(tmp_vfield); bitmap_updated= true; } } @@ -6904,8 +6884,6 @@ void TABLE::mark_columns_used_by_virtual_fields(void) void TABLE::mark_check_constraint_columns_for_read(void) { bitmap_union(read_set, s->check_set); - if (vcol_set) - bitmap_union(vcol_set, s->check_set); } @@ -7650,6 +7628,20 @@ public: } }; + +/* + to satisfy ASSERT_COLUMN_MARKED_FOR_WRITE Field's assert we temporarily + mark field for write before storing the generated value in it +*/ +#ifndef DBUG_OFF +#define DBUG_FIX_WRITE_SET(f) bool _write_set_fixed= !bitmap_fast_test_and_set(write_set, (f)->field_index) +#define DBUG_RESTORE_WRITE_SET(f) if (_write_set_fixed) bitmap_clear_bit(write_set, (f)->field_index) +#else +#define DBUG_FIX_WRITE_SET(f) +#define DBUG_RESTORE_WRITE_SET(f) +#endif + + /* @brief Compute values for virtual columns used in query @@ -7713,17 +7705,17 @@ int TABLE::update_virtual_fields(handler *h, enum_vcol_update_mode update_mode) switch (update_mode) { case VCOL_UPDATE_FOR_READ: update= (!vcol_info->stored_in_db && - bitmap_is_set(vcol_set, vf->field_index)); + bitmap_is_set(read_set, vf->field_index)); swap_values= 1; break; case VCOL_UPDATE_FOR_DELETE: case VCOL_UPDATE_FOR_WRITE: - update= bitmap_is_set(vcol_set, vf->field_index); + update= bitmap_is_set(read_set, vf->field_index); break; case VCOL_UPDATE_FOR_REPLACE: update= ((!vcol_info->stored_in_db && (vf->flags & (PART_KEY_FLAG | PART_INDIRECT_KEY_FLAG)) && - bitmap_is_set(vcol_set, vf->field_index)) || + bitmap_is_set(read_set, vf->field_index)) || update_all_columns); if (update && (vf->flags & BLOB_FLAG)) { @@ -7743,7 +7735,7 @@ int TABLE::update_virtual_fields(handler *h, enum_vcol_update_mode update_mode) /* Read indexed fields that was not updated in VCOL_UPDATE_FOR_READ */ update= (!vcol_info->stored_in_db && (vf->flags & (PART_KEY_FLAG | PART_INDIRECT_KEY_FLAG)) && - !bitmap_is_set(vcol_set, vf->field_index)); + !bitmap_is_set(read_set, vf->field_index)); swap_values= 1; break; } @@ -7752,8 +7744,10 @@ int TABLE::update_virtual_fields(handler *h, enum_vcol_update_mode update_mode) { int field_error __attribute__((unused)) = 0; /* Compute the actual value of the virtual fields */ + DBUG_FIX_WRITE_SET(vf); if (vcol_info->expr->save_in_field(vf, 0)) field_error= error= 1; + DBUG_RESTORE_WRITE_SET(vf); DBUG_PRINT("info", ("field '%s' - updated error: %d", vf->field_name.str, field_error)); if (swap_values && (vf->flags & BLOB_FLAG)) @@ -7787,7 +7781,9 @@ int TABLE::update_virtual_field(Field *vf) in_use->set_n_backup_active_arena(expr_arena, &backup_arena); bitmap_clear_all(&tmp_set); vf->vcol_info->expr->walk(&Item::update_vcol_processor, 0, &tmp_set); + DBUG_FIX_WRITE_SET(vf); vf->vcol_info->expr->save_in_field(vf, 0); + DBUG_RESTORE_WRITE_SET(vf); in_use->restore_active_arena(expr_arena, &backup_arena); DBUG_RETURN(in_use->is_error()); } @@ -8452,200 +8448,6 @@ double KEY::actual_rec_per_key(uint i) } -/** - @brief - Mark subformulas of a condition unusable for the condition pushed into table - - @param cond The condition whose subformulas are to be marked - - @details - This method recursively traverses the AND-OR condition cond and for each subformula - of the codition it checks whether it can be usable for the extraction of a condition - that can be pushed into this table. The subformulas that are not usable are - marked with the flag NO_EXTRACTION_FL. - @note - This method is called before any call of TABLE_LIST::build_pushable_cond_for_table. - The flag NO_EXTRACTION_FL set in a subformula allows to avoid building clone - for the subformula when extracting the pushable condition. -*/ - -void TABLE_LIST::check_pushable_cond_for_table(Item *cond) -{ - table_map tab_map= table->map; - cond->clear_extraction_flag(); - if (cond->type() == Item::COND_ITEM) - { - bool and_cond= ((Item_cond*) cond)->functype() == Item_func::COND_AND_FUNC; - List_iterator<Item> li(*((Item_cond*) cond)->argument_list()); - uint count= 0; - Item *item; - while ((item=li++)) - { - check_pushable_cond_for_table(item); - if (item->get_extraction_flag() != NO_EXTRACTION_FL) - count++; - else if (!and_cond) - break; - } - if ((and_cond && count == 0) || item) - { - cond->set_extraction_flag(NO_EXTRACTION_FL); - if (and_cond) - li.rewind(); - while ((item= li++)) - item->clear_extraction_flag(); - } - } - else if (!cond->excl_dep_on_table(tab_map)) - cond->set_extraction_flag(NO_EXTRACTION_FL); -} - - -/** - @brief - Build condition extractable from the given one depended only on this table - - @param thd The thread handle - @param cond The condition from which the pushable one is to be extracted - - @details - For the given condition cond this method finds out what condition depended - only on this table can be extracted from cond. If such condition C exists - the method builds the item for it. - The method uses the flag NO_EXTRACTION_FL set by the preliminary call of - the method TABLE_LIST::check_pushable_cond_for_table to figure out whether - a subformula depends only on this table or not. - @note - The built condition C is always implied by the condition cond - (cond => C). The method tries to build the most restictive such - condition (i.e. for any other condition C' such that cond => C' - we have C => C'). - @note - The build item is not ready for usage: substitution for the field items - has to be done and it has to be re-fixed. - - @retval - the built condition pushable into this table if such a condition exists - NULL if there is no such a condition -*/ - -Item* TABLE_LIST::build_pushable_cond_for_table(THD *thd, Item *cond) -{ - table_map tab_map= table->map; - bool is_multiple_equality= cond->type() == Item::FUNC_ITEM && - ((Item_func*) cond)->functype() == Item_func::MULT_EQUAL_FUNC; - if (cond->get_extraction_flag() == NO_EXTRACTION_FL) - return 0; - if (cond->type() == Item::COND_ITEM) - { - bool cond_and= false; - Item_cond *new_cond; - if (((Item_cond*) cond)->functype() == Item_func::COND_AND_FUNC) - { - cond_and= true; - new_cond=new (thd->mem_root) Item_cond_and(thd); - } - else - new_cond= new (thd->mem_root) Item_cond_or(thd); - if (!new_cond) - return 0; - List_iterator<Item> li(*((Item_cond*) cond)->argument_list()); - Item *item; - bool is_fix_needed= false; - while ((item=li++)) - { - if (item->get_extraction_flag() == NO_EXTRACTION_FL) - { - if (!cond_and) - return 0; - continue; - } - Item *fix= build_pushable_cond_for_table(thd, item); - if (!fix && !cond_and) - return 0; - if (!fix) - continue; - - if (fix->type() == Item::COND_ITEM && - ((Item_cond*) fix)->functype() == Item_func::COND_AND_FUNC) - is_fix_needed= true; - - new_cond->argument_list()->push_back(fix, thd->mem_root); - } - if (is_fix_needed && new_cond->fix_fields(thd, 0)) - return 0; - - switch (new_cond->argument_list()->elements) - { - case 0: - return 0; - case 1: - return new_cond->argument_list()->head(); - default: - return new_cond; - } - } - else if (is_multiple_equality) - { - if (!(cond->used_tables() & tab_map)) - return 0; - Item *new_cond= NULL; - int i= 0; - Item_equal *item_equal= (Item_equal *) cond; - Item *left_item = item_equal->get_const(); - Item_equal_fields_iterator it(*item_equal); - Item *item; - if (!left_item) - { - while ((item=it++)) - if (item->used_tables() == tab_map) - { - left_item= item; - break; - } - } - if (!left_item) - return 0; - while ((item=it++)) - { - if (!(item->used_tables() == tab_map)) - continue; - Item_func_eq *eq= 0; - Item *left_item_clone= left_item->build_clone(thd); - Item *right_item_clone= item->build_clone(thd); - if (left_item_clone && right_item_clone) - { - left_item_clone->set_item_equal(NULL); - right_item_clone->set_item_equal(NULL); - eq= new (thd->mem_root) Item_func_eq(thd, right_item_clone, - left_item_clone); - } - if (eq) - { - i++; - switch (i) - { - case 1: - new_cond= eq; - break; - case 2: - new_cond= new (thd->mem_root) Item_cond_and(thd, new_cond, eq); - break; - default: - ((Item_cond_and*)new_cond)->argument_list()->push_back(eq, - thd->mem_root); - } - } - } - if (new_cond) - new_cond->fix_fields(thd, &new_cond); - return new_cond; - } - else if (cond->get_extraction_flag() != NO_EXTRACTION_FL) - return cond->build_clone(thd); - return 0; -} - LEX_CSTRING *fk_option_name(enum_fk_option opt) { static LEX_CSTRING names[]= @@ -9032,7 +8834,8 @@ bool Vers_history_point::resolve_unit(THD *thd) return false; if (item->fix_fields_if_needed(thd, &item)) return true; - return item->this_item()->type_handler_for_system_time()-> + return item->this_item()->real_type_handler()-> + type_handler_for_system_time()-> Vers_history_point_resolve_unit(thd, this); } |