diff options
Diffstat (limited to 'sql/table.cc')
-rw-r--r-- | sql/table.cc | 469 |
1 files changed, 362 insertions, 107 deletions
diff --git a/sql/table.cc b/sql/table.cc index 38a64348937..53d88bc02aa 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -39,6 +39,7 @@ #include "sql_statistics.h" #include "discover.h" #include "mdl.h" // MDL_wait_for_graph_visitor +#include "sql_view.h" /* INFORMATION_SCHEMA name */ LEX_STRING INFORMATION_SCHEMA_NAME= {C_STRING_WITH_LEN("information_schema")}; @@ -148,7 +149,7 @@ View_creation_ctx * View_creation_ctx::create(THD *thd, { push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE, ER_VIEW_NO_CREATION_CTX, - ER(ER_VIEW_NO_CREATION_CTX), + ER_THD(thd, ER_VIEW_NO_CREATION_CTX), (const char *) view->db, (const char *) view->table_name); @@ -182,7 +183,7 @@ View_creation_ctx * View_creation_ctx::create(THD *thd, push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE, ER_VIEW_INVALID_CREATION_CTX, - ER(ER_VIEW_INVALID_CREATION_CTX), + ER_THD(thd, ER_VIEW_INVALID_CREATION_CTX), (const char *) view->db, (const char *) view->table_name); } @@ -324,7 +325,7 @@ TABLE_SHARE *alloc_table_share(const char *db, const char *table_name, &share->LOCK_share, MY_MUTEX_INIT_SLOW); mysql_mutex_init(key_TABLE_SHARE_LOCK_ha_data, &share->LOCK_ha_data, MY_MUTEX_INIT_FAST); - tdc_init_share(share); + tdc_assign_new_table_id(share); } DBUG_RETURN(share); } @@ -421,7 +422,6 @@ void TABLE_SHARE::destroy() { mysql_mutex_destroy(&LOCK_share); mysql_mutex_destroy(&LOCK_ha_data); - tdc_deinit_share(this); } my_hash_free(&name_hash); @@ -558,13 +558,15 @@ enum open_frm_error open_table_def(THD *thd, TABLE_SHARE *share, uint flags) uchar head[FRM_HEADER_SIZE]; char path[FN_REFLEN]; size_t frmlen, read_length; + uint length; DBUG_ENTER("open_table_def"); DBUG_PRINT("enter", ("table: '%s'.'%s' path: '%s'", share->db.str, share->table_name.str, share->normalized_path.str)); share->error= OPEN_FRM_OPEN_ERROR; - strxmov(path, share->normalized_path.str, reg_ext, NullS); + length=(uint) (strxmov(path, share->normalized_path.str, reg_ext, NullS) - + path); if (flags & GTS_FORCE_DISCOVERY) { DBUG_ASSERT(flags & GTS_TABLE); @@ -595,7 +597,21 @@ enum open_frm_error open_table_def(THD *thd, TABLE_SHARE *share, uint flags) if (memcmp(head, STRING_WITH_LEN("TYPE=VIEW\n")) == 0) { share->is_view= 1; - share->error= flags & GTS_VIEW ? OPEN_FRM_OK : OPEN_FRM_NOT_A_TABLE; + if (flags & GTS_VIEW) + { + LEX_STRING pathstr= { path, length }; + /* + Create view file parser and hold it in TABLE_SHARE member + view_def. + */ + share->view_def= sql_parse_prepare(&pathstr, &share->mem_root, true); + if (!share->view_def) + share->error= OPEN_FRM_ERROR_ALREADY_ISSUED; + else + share->error= OPEN_FRM_OK; + } + else + share->error= OPEN_FRM_NOT_A_TABLE; goto err; } if (!is_binary_frm_header(head)) @@ -924,6 +940,8 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, uint vcol_screen_length, UNINIT_VAR(options_len); char *vcol_screen_pos; const uchar *options= 0; + uint UNINIT_VAR(gis_options_len); + const uchar *gis_options= 0; KEY first_keyinfo; uint len; uint ext_key_parts= 0; @@ -996,12 +1014,22 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, #ifdef WITH_PARTITION_STORAGE_ENGINE { LEX_STRING name= { (char*)extra2, length }; - share->default_part_plugin= ha_resolve_by_name(NULL, &name); + share->default_part_plugin= ha_resolve_by_name(NULL, &name, false); if (!share->default_part_plugin) goto err; } #endif break; + case EXTRA2_GIS: +#ifdef HAVE_SPATIAL + { + if (gis_options) + goto err; + gis_options= extra2; + gis_options_len= length; + } +#endif /*HAVE_SPATIAL*/ + break; default: /* abort frm parsing if it's an unknown but important extra2 value */ if (type >= EXTRA2_ENGINE_IMPORTANT) @@ -1035,8 +1063,7 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, if (frm_image[61] && !share->default_part_plugin) { enum legacy_db_type db_type= (enum legacy_db_type) (uint) frm_image[61]; - share->default_part_plugin= - ha_lock_engine(NULL, ha_checktype(thd, db_type, 1, 0)); + share->default_part_plugin= ha_lock_engine(NULL, ha_checktype(thd, db_type)); if (!share->default_part_plugin) goto err; } @@ -1048,7 +1075,7 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, */ if (legacy_db_type > DB_TYPE_UNKNOWN && legacy_db_type < DB_TYPE_FIRST_DYNAMIC) - se_plugin= ha_lock_engine(NULL, ha_checktype(thd, legacy_db_type, 0, 0)); + se_plugin= ha_lock_engine(NULL, ha_checktype(thd, legacy_db_type)); share->db_create_options= db_create_options= uint2korr(frm_image+30); share->db_options_in_use= share->db_create_options; share->mysql_version= uint4korr(frm_image+51); @@ -1153,7 +1180,7 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, name.str= (char*) next_chunk + 2; name.length= str_db_type_length; - plugin_ref tmp_plugin= ha_resolve_by_name(thd, &name); + plugin_ref tmp_plugin= ha_resolve_by_name(thd, &name, false); if (tmp_plugin != NULL && !plugin_equals(tmp_plugin, se_plugin)) { if (se_plugin) @@ -1450,6 +1477,7 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, LEX_STRING comment; Virtual_column_info *vcol_info= 0; bool fld_stored_in_db= TRUE; + uint gis_length, gis_decimals, srid= 0; if (new_frm_ver >= 3) { @@ -1466,8 +1494,14 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, 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 @@ -1622,13 +1656,13 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, #endif *field_ptr= reg_field= - make_field(share, record+recpos, + make_field(share, &share->mem_root, record+recpos, (uint32) field_length, null_pos, null_bit_pos, pack_flag, field_type, charset, - geom_type, + geom_type, srid, (Field::utype) MTYP_TYPENR(unireg_type), (interval_nr ? share->intervals+interval_nr-1 : @@ -1687,6 +1721,7 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, keyinfo= share->key_info; uint primary_key= my_strcasecmp(system_charset_info, share->keynames.type_names[0], primary_key_name) ? MAX_KEY : 0; + KEY* key_first_info; if (primary_key >= MAX_KEY && keyinfo->flags & HA_NOSAME) { @@ -1766,34 +1801,72 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, keyinfo->name_length+1); } + if (!key) + key_first_info= keyinfo; + if (ext_key_parts > share->key_parts && key) { KEY_PART_INFO *new_key_part= (keyinfo-1)->key_part + (keyinfo-1)->ext_key_parts; + uint add_keyparts_for_this_key= add_first_key_parts; + uint length_bytes= 0, len_null_byte= 0, ext_key_length= 0; + Field *field; /* Do not extend the key that contains a component defined over the beginning of a field. */ for (i= 0; i < keyinfo->user_defined_key_parts; i++) - { + { uint fieldnr= keyinfo->key_part[i].fieldnr; + field= share->field[keyinfo->key_part[i].fieldnr-1]; + + if (field->null_ptr) + len_null_byte= HA_KEY_NULL_LENGTH; + + if (field->type() == MYSQL_TYPE_BLOB || + field->real_type() == MYSQL_TYPE_VARCHAR || + field->type() == MYSQL_TYPE_GEOMETRY) + { + length_bytes= HA_KEY_BLOB_LENGTH; + } + + ext_key_length+= keyinfo->key_part[i].length + len_null_byte + + length_bytes; if (share->field[fieldnr-1]->key_length() != keyinfo->key_part[i].length) { - add_first_key_parts= 0; + add_keyparts_for_this_key= 0; break; } } - if (add_first_key_parts < keyinfo->ext_key_parts-keyinfo->user_defined_key_parts) + if (add_keyparts_for_this_key) + { + for (i= 0; i < add_keyparts_for_this_key; i++) + { + uint pk_part_length= key_first_info->key_part[i].store_length; + if (keyinfo->ext_key_part_map & 1<<i) + { + if (ext_key_length + pk_part_length > MAX_KEY_LENGTH) + { + add_keyparts_for_this_key= i; + break; + } + ext_key_length+= pk_part_length; + } + } + } + + if (add_keyparts_for_this_key < (keyinfo->ext_key_parts - + keyinfo->user_defined_key_parts)) { share->ext_key_parts-= keyinfo->ext_key_parts; key_part_map ext_key_part_map= keyinfo->ext_key_part_map; keyinfo->ext_key_parts= keyinfo->user_defined_key_parts; keyinfo->ext_key_flags= keyinfo->flags; keyinfo->ext_key_part_map= 0; - for (i= 0; i < add_first_key_parts; i++) + for (i= 0; i < add_keyparts_for_this_key; i++) { if (ext_key_part_map & 1<<i) { @@ -2078,7 +2151,7 @@ static bool sql_unusable_for_discovery(THD *thd, handlerton *engine, if (lex->sql_command != SQLCOM_CREATE_TABLE) return 1; // ... create like - if (create_info->options & HA_LEX_CREATE_TABLE_LIKE) + if (lex->create_info.like()) return 1; // ... create select if (lex->select_lex.item_list.elements) @@ -2087,7 +2160,7 @@ static bool sql_unusable_for_discovery(THD *thd, handlerton *engine, if (create_info->tmp_table()) return 1; // ... if exists - if (create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS) + if (lex->create_info.if_not_exists()) return 1; // XXX error out or rather ignore the following: @@ -2123,6 +2196,7 @@ int TABLE_SHARE::init_from_sql_statement_string(THD *thd, bool write, uint unused2; handlerton *hton= plugin_hton(db_plugin); LEX_CUSTRING frm= {0,0}; + LEX_STRING db_backup= { thd->db, thd->db_length }; DBUG_ENTER("TABLE_SHARE::init_from_sql_statement_string"); @@ -2150,6 +2224,7 @@ int TABLE_SHARE::init_from_sql_statement_string(THD *thd, bool write, else thd->set_n_backup_active_arena(arena, &backup); + thd->reset_db(db.str, db.length); lex_start(thd); if ((error= parse_sql(thd, & parser_state, NULL) || @@ -2178,6 +2253,7 @@ int TABLE_SHARE::init_from_sql_statement_string(THD *thd, bool write, ret: my_free(const_cast<uchar*>(frm.str)); lex_end(thd->lex); + thd->reset_db(db_backup.str, db_backup.length); thd->lex= old_lex; if (arena) thd->restore_active_arena(arena, &backup); @@ -2412,6 +2488,7 @@ bool unpack_vcol_info_from_frm(THD *thd, Query_arena *backup_stmt_arena_ptr; Query_arena backup_arena; Query_arena *vcol_arena= 0; + Create_field vcol_storage; // placeholder for vcol_info Parser_state parser_state; LEX *old_lex= thd->lex; LEX lex; @@ -2475,7 +2552,8 @@ bool unpack_vcol_info_from_frm(THD *thd, if (init_lex_with_single_table(thd, table, &lex)) goto err; - thd->lex->parse_vcol_expr= TRUE; + lex.parse_vcol_expr= TRUE; + lex.last_field= &vcol_storage; /* Step 3: Use the parser to build an Item object from vcol_expr_str. @@ -2485,7 +2563,7 @@ bool unpack_vcol_info_from_frm(THD *thd, goto err; } /* From now on use vcol_info generated by the parser. */ - field->vcol_info= thd->lex->vcol_info; + field->vcol_info= vcol_storage.vcol_info; /* Validate the Item tree. */ if (fix_vcol_expr(thd, table, field)) @@ -2545,7 +2623,7 @@ enum open_frm_error open_table_from_share(THD *thd, TABLE_SHARE *share, bool is_create_table) { enum open_frm_error error; - uint records, i, bitmap_size; + uint records, i, bitmap_size, bitmap_count; bool error_reported= FALSE; uchar *record, *bitmaps; Field **field_ptr, **UNINIT_VAR(vfield_ptr), **UNINIT_VAR(dfield_ptr); @@ -2577,6 +2655,7 @@ enum open_frm_error open_table_from_share(THD *thd, TABLE_SHARE *share, outparam->quick_keys.init(); outparam->covering_keys.init(); outparam->merge_keys.init(); + outparam->intersect_keys.init(); outparam->keys_in_use_for_query.init(); /* Allocate handler */ @@ -2685,8 +2764,8 @@ enum open_frm_error open_table_from_share(THD *thd, TABLE_SHARE *share, We are using only a prefix of the column as a key: Create a new field for the key part that matches the index */ - field= key_part->field=field->new_field(&outparam->mem_root, - outparam, 0); + field= key_part->field=field->make_new_field(&outparam->mem_root, + outparam, 0); field->field_length= key_part->length; } } @@ -2829,20 +2908,42 @@ partititon_err: /* Allocate bitmaps */ bitmap_size= share->column_bitmap_size; - if (!(bitmaps= (uchar*) alloc_root(&outparam->mem_root, bitmap_size*6))) + bitmap_count= 6; + if (share->vfields) + { + if (!(outparam->def_vcol_set= (MY_BITMAP*) + alloc_root(&outparam->mem_root, sizeof(*outparam->def_vcol_set)))) + goto err; + bitmap_count++; + } + if (!(bitmaps= (uchar*) alloc_root(&outparam->mem_root, + bitmap_size * bitmap_count))) goto err; + my_bitmap_init(&outparam->def_read_set, - (my_bitmap_map*) bitmaps, share->fields, FALSE); + (my_bitmap_map*) bitmaps, share->fields, FALSE); + bitmaps+= bitmap_size; my_bitmap_init(&outparam->def_write_set, - (my_bitmap_map*) (bitmaps+bitmap_size), share->fields, FALSE); - my_bitmap_init(&outparam->def_vcol_set, - (my_bitmap_map*) (bitmaps+bitmap_size*2), share->fields, FALSE); + (my_bitmap_map*) bitmaps, share->fields, FALSE); + bitmaps+= bitmap_size; + if (share->vfields) + { + /* Don't allocate vcol_bitmap if we don't need it */ + my_bitmap_init(outparam->def_vcol_set, + (my_bitmap_map*) bitmaps, share->fields, FALSE); + bitmaps+= bitmap_size; + } my_bitmap_init(&outparam->tmp_set, - (my_bitmap_map*) (bitmaps+bitmap_size*3), share->fields, FALSE); + (my_bitmap_map*) bitmaps, share->fields, FALSE); + bitmaps+= bitmap_size; my_bitmap_init(&outparam->eq_join_set, - (my_bitmap_map*) (bitmaps+bitmap_size*4), share->fields, FALSE); + (my_bitmap_map*) bitmaps, share->fields, FALSE); + bitmaps+= bitmap_size; my_bitmap_init(&outparam->cond_set, - (my_bitmap_map*) (bitmaps+bitmap_size*5), share->fields, FALSE); + (my_bitmap_map*) bitmaps, share->fields, FALSE); + bitmaps+= bitmap_size; + my_bitmap_init(&outparam->def_rpl_write_set, + (my_bitmap_map*) bitmaps, share->fields, FALSE); outparam->default_column_bitmaps(); outparam->cond_selectivity= 1.0; @@ -2891,10 +2992,6 @@ partititon_err: } } -#if defined(HAVE_valgrind) && !defined(DBUG_OFF) - bzero((char*) bitmaps, bitmap_size*3); -#endif - if (share->table_category == TABLE_CATEGORY_LOG) { outparam->no_replicate= TRUE; @@ -3271,8 +3368,8 @@ void prepare_frm_header(THD *thd, uint reclength, uchar *fileinfo, fileinfo[1]= 1; fileinfo[2]= FRM_VER + 3 + MY_TEST(create_info->varchar); - fileinfo[3]= (uchar) ha_legacy_type( - ha_checktype(thd,ha_legacy_type(create_info->db_type),0,0)); + DBUG_ASSERT(ha_storage_engine_is_enabled(create_info->db_type)); + fileinfo[3]= (uchar) ha_legacy_type(create_info->db_type); /* Keep in sync with pack_keys() in unireg.cc @@ -3637,13 +3734,14 @@ Table_check_intact::check(TABLE *table, const TABLE_FIELD_DEF *table_def) if (table->s->fields != table_def->count) { + THD *thd= current_thd; DBUG_PRINT("info", ("Column count has changed, checking the definition")); /* previous MySQL version */ if (MYSQL_VERSION_ID > table->s->mysql_version) { report_error(ER_COL_COUNT_DOESNT_MATCH_PLEASE_UPDATE, - ER(ER_COL_COUNT_DOESNT_MATCH_PLEASE_UPDATE), + ER_THD(thd, ER_COL_COUNT_DOESNT_MATCH_PLEASE_UPDATE), table->alias.c_ptr(), table_def->count, table->s->fields, static_cast<int>(table->s->mysql_version), MYSQL_VERSION_ID); @@ -3652,7 +3750,7 @@ Table_check_intact::check(TABLE *table, const TABLE_FIELD_DEF *table_def) else if (MYSQL_VERSION_ID == table->s->mysql_version) { report_error(ER_COL_COUNT_DOESNT_MATCH_CORRUPTED_V2, - ER(ER_COL_COUNT_DOESNT_MATCH_CORRUPTED_V2), + ER_THD(thd, ER_COL_COUNT_DOESNT_MATCH_CORRUPTED_V2), table->s->db.str, table->s->table_name.str, table_def->count, table->s->fields); DBUG_RETURN(TRUE); @@ -3800,6 +3898,15 @@ Table_check_intact::check(TABLE *table, const TABLE_FIELD_DEF *table_def) } +void Table_check_intact_log_error::report_error(uint, const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + error_log_print(ERROR_LEVEL, fmt, args); + va_end(args); +} + + /** Traverse portion of wait-for graph which is reachable through edge represented by this flush ticket in search for deadlocks. @@ -3847,11 +3954,11 @@ bool TABLE_SHARE::visit_subgraph(Wait_for_flush *wait_for_flush, because we won't try to acquire tdc.LOCK_table_share while holding a write-lock on MDL_lock::m_rwlock. */ - mysql_mutex_lock(&tdc.LOCK_table_share); - tdc.all_tables_refs++; - mysql_mutex_unlock(&tdc.LOCK_table_share); + mysql_mutex_lock(&tdc->LOCK_table_share); + tdc->all_tables_refs++; + mysql_mutex_unlock(&tdc->LOCK_table_share); - All_share_tables_list::Iterator tables_it(tdc.all_tables); + TDC_element::All_share_tables_list::Iterator tables_it(tdc->all_tables); /* In case of multiple searches running in parallel, avoid going @@ -3869,7 +3976,7 @@ bool TABLE_SHARE::visit_subgraph(Wait_for_flush *wait_for_flush, while ((table= tables_it++)) { - DBUG_ASSERT(table->in_use && tdc.flushed); + DBUG_ASSERT(table->in_use && tdc->flushed); if (gvisitor->inspect_edge(&table->in_use->mdl_context)) { goto end_leave_node; @@ -3879,7 +3986,7 @@ bool TABLE_SHARE::visit_subgraph(Wait_for_flush *wait_for_flush, tables_it.rewind(); while ((table= tables_it++)) { - DBUG_ASSERT(table->in_use && tdc.flushed); + DBUG_ASSERT(table->in_use && tdc->flushed); if (table->in_use->mdl_context.visit_subgraph(gvisitor)) { goto end_leave_node; @@ -3892,10 +3999,10 @@ end_leave_node: gvisitor->leave_node(src_ctx); end: - mysql_mutex_lock(&tdc.LOCK_table_share); - if (!--tdc.all_tables_refs) - mysql_cond_broadcast(&tdc.COND_release); - mysql_mutex_unlock(&tdc.LOCK_table_share); + mysql_mutex_lock(&tdc->LOCK_table_share); + if (!--tdc->all_tables_refs) + mysql_cond_broadcast(&tdc->COND_release); + mysql_mutex_unlock(&tdc->LOCK_table_share); return result; } @@ -3930,14 +4037,14 @@ bool TABLE_SHARE::wait_for_old_version(THD *thd, struct timespec *abstime, Wait_for_flush ticket(mdl_context, this, deadlock_weight); MDL_wait::enum_wait_status wait_status; - mysql_mutex_assert_owner(&tdc.LOCK_table_share); - DBUG_ASSERT(tdc.flushed); + mysql_mutex_assert_owner(&tdc->LOCK_table_share); + DBUG_ASSERT(tdc->flushed); - tdc.m_flush_tickets.push_front(&ticket); + tdc->m_flush_tickets.push_front(&ticket); mdl_context->m_wait.reset_status(); - mysql_mutex_unlock(&tdc.LOCK_table_share); + mysql_mutex_unlock(&tdc->LOCK_table_share); mdl_context->will_wait_for(&ticket); @@ -3948,21 +4055,10 @@ bool TABLE_SHARE::wait_for_old_version(THD *thd, struct timespec *abstime, mdl_context->done_waiting_for(); - mysql_mutex_lock(&tdc.LOCK_table_share); - - tdc.m_flush_tickets.remove(&ticket); - - if (tdc.m_flush_tickets.is_empty() && tdc.ref_count == 0) - { - /* - If our thread was the last one using the share, - we must destroy it here. - */ - mysql_mutex_unlock(&tdc.LOCK_table_share); - destroy(); - } - else - mysql_mutex_unlock(&tdc.LOCK_table_share); + mysql_mutex_lock(&tdc->LOCK_table_share); + tdc->m_flush_tickets.remove(&ticket); + mysql_cond_broadcast(&tdc->COND_release); + mysql_mutex_unlock(&tdc->LOCK_table_share); /* @@ -4008,7 +4104,7 @@ bool TABLE_SHARE::wait_for_old_version(THD *thd, struct timespec *abstime, void TABLE::init(THD *thd, TABLE_LIST *tl) { - DBUG_ASSERT(s->tdc.ref_count > 0 || s->tmp_table != NO_TMP_TABLE); + DBUG_ASSERT(s->tmp_table != NO_TMP_TABLE || s->tdc->ref_count > 0); if (thd->lex->need_correct_ident()) alias_name_used= my_strcasecmp(table_alias_charset, @@ -4054,16 +4150,7 @@ void TABLE::init(THD *thd, TABLE_LIST *tl) DBUG_ASSERT(key_read == 0); - /* mark the record[0] uninitialized */ - TRASH(record[0], s->reclength); - - /* - Initialize the null marker bits, to ensure that if we are doing a read - of only selected columns (like in keyread), all null markers are - initialized. - */ - memset(record[0], 255, s->null_bytes); - memset(record[1], 255, s->null_bytes); + restore_record(this, s->default_values); /* Tables may be reused in a sub statement. */ DBUG_ASSERT(!file->extra(HA_EXTRA_IS_ATTACHED_CHILDREN)); @@ -4095,7 +4182,7 @@ bool TABLE::fill_item_list(List<Item> *item_list) const */ for (Field **ptr= field; *ptr; ptr++) { - Item_field *item= new Item_field(*ptr); + Item_field *item= new (in_use->mem_root) Item_field(in_use, *ptr); if (!item || item_list->push_back(item)) return TRUE; } @@ -4139,7 +4226,7 @@ void TABLE::reset_item_list(List<Item> *item_list) const void TABLE_LIST::calc_md5(char *buffer) { uchar digest[16]; - compute_md5_hash((char*) digest, select_stmt.str, + compute_md5_hash(digest, select_stmt.str, select_stmt.length); sprintf((char *) buffer, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", @@ -4343,7 +4430,7 @@ bool TABLE_LIST::prep_where(THD *thd, Item **conds, this expression will not be moved to WHERE condition (i.e. will be clean correctly for PS/SP) */ - tbl->on_expr= and_conds(tbl->on_expr, + tbl->on_expr= and_conds(thd, tbl->on_expr, where->copy_andor_structure(thd)); break; } @@ -4353,7 +4440,7 @@ bool TABLE_LIST::prep_where(THD *thd, Item **conds, if (*conds && !(*conds)->fixed) res= (*conds)->fix_fields(thd, conds); if (!res) - *conds= and_conds(*conds, where->copy_andor_structure(thd)); + *conds= and_conds(thd, *conds, where->copy_andor_structure(thd)); if (*conds && !(*conds)->fixed && !res) res= (*conds)->fix_fields(thd, conds); } @@ -4425,7 +4512,7 @@ merge_on_conds(THD *thd, TABLE_LIST *table, bool is_cascaded) { if (tbl->view && !is_cascaded) continue; - cond= and_conds(cond, merge_on_conds(thd, tbl, is_cascaded)); + cond= and_conds(thd, cond, merge_on_conds(thd, tbl, is_cascaded)); } DBUG_RETURN(cond); } @@ -4485,10 +4572,10 @@ bool TABLE_LIST::prep_check_option(THD *thd, uint8 check_opt_type) for (TABLE_LIST *tbl= merge_underlying_list; tbl; tbl= tbl->next_local) { if (tbl->check_option) - check_option= and_conds(check_option, tbl->check_option); + check_option= and_conds(thd, check_option, tbl->check_option); } } - check_option= and_conds(check_option, + check_option= and_conds(thd, check_option, merge_on_conds(thd, this, is_cascaded)); if (arena) @@ -4642,7 +4729,8 @@ int TABLE_LIST::view_check_option(THD *thd, bool ignore_failure) if (ignore_failure) { push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, - ER_VIEW_CHECK_FAILED, ER(ER_VIEW_CHECK_FAILED), + ER_VIEW_CHECK_FAILED, + ER_THD(thd, ER_VIEW_CHECK_FAILED), main_view->view_db.str, main_view->view_name.str); return(VIEW_CHECK_SKIP); } @@ -4792,9 +4880,8 @@ bool TABLE_LIST::is_leaf_for_name_resolution() TABLE_LIST *TABLE_LIST::first_leaf_for_name_resolution() { - TABLE_LIST *cur_table_ref; + TABLE_LIST *UNINIT_VAR(cur_table_ref); NESTED_JOIN *cur_nested_join; - LINT_INIT(cur_table_ref); if (is_leaf_for_name_resolution()) return this; @@ -4940,7 +5027,7 @@ bool TABLE_LIST::prepare_view_security_context(THD *thd) { push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE, ER_NO_SUCH_USER, - ER(ER_NO_SUCH_USER), + ER_THD(thd, ER_NO_SUCH_USER), definer.user.str, definer.host.str); } else @@ -4960,7 +5047,8 @@ bool TABLE_LIST::prepare_view_security_context(THD *thd) my_error(ER_ACCESS_DENIED_ERROR, MYF(0), thd->security_ctx->priv_user, thd->security_ctx->priv_host, - (thd->password ? ER(ER_YES) : ER(ER_NO))); + (thd->password ? ER_THD(thd, ER_YES) : + ER_THD(thd, ER_NO))); } DBUG_RETURN(TRUE); } @@ -5258,7 +5346,7 @@ Item *Field_iterator_table::create_item(THD *thd) { SELECT_LEX *select= thd->lex->current_select; - Item_field *item= new Item_field(thd, &select->context, *ptr); + Item_field *item= new (thd->mem_root) Item_field(thd, &select->context, *ptr); if (item && thd->variables.sql_mode & MODE_ONLY_FULL_GROUP_BY && !thd->lex->in_sum_func && select->cur_pos_in_select_list != UNDEF_POS && select->join) @@ -5316,9 +5404,10 @@ Item *create_view_field(THD *thd, TABLE_LIST *view, Item **field_ref, { DBUG_RETURN(field); } - Item *item= new Item_direct_view_ref(&view->view->select_lex.context, - field_ref, view->alias, - name, view); + Item *item= (new (thd->mem_root) + Item_direct_view_ref(thd, &view->view->select_lex.context, + field_ref, view->alias, + name, view)); /* Force creation of nullable item for the result tmp table for outer joined views/derived tables. @@ -5326,13 +5415,13 @@ Item *create_view_field(THD *thd, TABLE_LIST *view, Item **field_ref, if (view->table && view->table->maybe_null) item->maybe_null= TRUE; /* Save item in case we will need to fall back to materialization. */ - view->used_items.push_front(item); + view->used_items.push_front(item, thd->mem_root); /* If we create this reference on persistent memory then it should be present in persistent list */ if (thd->mem_root == thd->stmt_arena->mem_root) - view->persistent_used_items.push_front(item); + view->persistent_used_items.push_front(item, thd->mem_root); DBUG_RETURN(item); } @@ -5518,17 +5607,16 @@ Field_iterator_table_ref::get_or_create_column_ref(THD *thd, TABLE_LIST *parent_ { Natural_join_column *nj_col; bool is_created= TRUE; - uint field_count; + uint UNINIT_VAR(field_count); TABLE_LIST *add_table_ref= parent_table_ref ? parent_table_ref : table_ref; - LINT_INIT(field_count); if (field_it == &table_field_it) { /* The field belongs to a stored table. */ Field *tmp_field= table_field_it.field(); Item_field *tmp_item= - new Item_field(thd, &thd->lex->current_select->context, tmp_field); + new (thd->mem_root) Item_field(thd, &thd->lex->current_select->context, tmp_field); if (!tmp_item) return NULL; nj_col= new Natural_join_column(tmp_item, table_ref); @@ -5636,10 +5724,14 @@ 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); - bitmap_clear_all(&table->def_vcol_set); + if (s->vfields) 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*3); - column_bitmaps_set(&def_read_set, &def_write_set, &def_vcol_set); + bzero((char*) def_read_set.bitmap, + s->column_bitmap_size * (s->vfields ? 3 : 2)); + column_bitmaps_set(&def_read_set, &def_write_set, def_vcol_set); + rpl_write_set= 0; // Safety } @@ -5798,6 +5890,8 @@ void TABLE::mark_auto_increment_column() void TABLE::mark_columns_needed_for_delete() { + mark_columns_per_binlog_row_image(); + if (triggers) triggers->mark_fields_used(TRG_EVENT_DELETE); if (file->ha_table_flags() & HA_REQUIRES_KEY_COLUMNS_FOR_DELETE) @@ -5849,6 +5943,9 @@ void TABLE::mark_columns_needed_for_delete() void TABLE::mark_columns_needed_for_update() { DBUG_ENTER("mark_columns_needed_for_update"); + + mark_columns_per_binlog_row_image(); + if (triggers) triggers->mark_fields_used(TRG_EVENT_UPDATE); if (file->ha_table_flags() & HA_REQUIRES_KEY_COLUMNS_FOR_DELETE) @@ -5893,6 +5990,8 @@ void TABLE::mark_columns_needed_for_update() void TABLE::mark_columns_needed_for_insert() { + mark_columns_per_binlog_row_image(); + if (triggers) { /* @@ -5910,6 +6009,121 @@ void TABLE::mark_columns_needed_for_insert() mark_virtual_columns_for_write(TRUE); } +/* + Mark columns according the binlog row image option. + + Columns to be written are stored in 'rpl_write_set' + + When logging in RBR, the user can select whether to + log partial or full rows, depending on the table + definition, and the value of binlog_row_image. + + Semantics of the binlog_row_image are the following + (PKE - primary key equivalent, ie, PK fields if PK + exists, all fields otherwise): + + binlog_row_image= MINIMAL + - This marks the PKE fields in the read_set + - This marks all fields where a value was specified + in the rpl_write_set + + binlog_row_image= NOBLOB + - This marks PKE + all non-blob fields in the read_set + - This marks all fields where a value was specified + and all non-blob fields in the rpl_write_set + + binlog_row_image= FULL + - all columns in the read_set + - all columns in the rpl_write_set + + This marking is done without resetting the original + bitmaps. This means that we will strip extra fields in + the read_set at binlogging time (for those cases that + we only want to log a PK and we needed other fields for + execution). +*/ + +void TABLE::mark_columns_per_binlog_row_image() +{ + THD *thd= in_use; + DBUG_ENTER("mark_columns_per_binlog_row_image"); + DBUG_ASSERT(read_set->bitmap); + DBUG_ASSERT(write_set->bitmap); + + /* If not using row format */ + rpl_write_set= write_set; + + /** + If in RBR we may need to mark some extra columns, + depending on the binlog-row-image command line argument. + */ + if ((WSREP_EMULATE_BINLOG(thd) || mysql_bin_log.is_open()) && + thd->is_current_stmt_binlog_format_row() && + !ha_check_storage_engine_flag(s->db_type(), HTON_NO_BINLOG_ROW_OPT)) + { + /* if there is no PK, then mark all columns for the BI. */ + if (s->primary_key >= MAX_KEY) + { + bitmap_set_all(read_set); + rpl_write_set= read_set; + } + else + { + switch (thd->variables.binlog_row_image) { + case BINLOG_ROW_IMAGE_FULL: + bitmap_set_all(read_set); + /* Set of columns that should be written (all) */ + rpl_write_set= read_set; + break; + case BINLOG_ROW_IMAGE_NOBLOB: + /* Only write changed columns + not blobs */ + rpl_write_set= &def_rpl_write_set; + bitmap_copy(rpl_write_set, write_set); + + /* + for every field that is not set, mark it unless it is a blob or + part of a primary key + */ + for (Field **ptr=field ; *ptr ; ptr++) + { + Field *my_field= *ptr; + /* + bypass blob fields. These can be set or not set, we don't care. + Later, at binlogging time, if we don't need them in the before + image, we will discard them. + + If set in the AI, then the blob is really needed, there is + nothing we can do about it. + */ + if ((my_field->flags & PRI_KEY_FLAG) || + (my_field->type() != MYSQL_TYPE_BLOB)) + { + bitmap_set_bit(read_set, my_field->field_index); + bitmap_set_bit(rpl_write_set, my_field->field_index); + } + } + break; + case BINLOG_ROW_IMAGE_MINIMAL: + /* + mark the primary key in the read set so that we can find the row + that is updated / deleted. + We don't need to mark the primary key in the rpl_write_set as the + binary log will include all columns read anyway. + */ + mark_columns_used_by_index_no_reset(s->primary_key, read_set); + /* Only write columns that have changed */ + rpl_write_set= write_set; + break; + + default: + DBUG_ASSERT(FALSE); + } + } + file->column_bitmaps_signal(); + } + + DBUG_VOID_RETURN; +} /* @brief Mark a column as virtual used by the query @@ -6228,7 +6442,7 @@ bool TABLE::add_tmp_key(uint key, uint key_parts, KEY* keyinfo; Field **reg_field; uint i; - + bool key_start= TRUE; KEY_PART_INFO* key_part_info= (KEY_PART_INFO*) alloc_root(&mem_root, sizeof(KEY_PART_INFO)*key_parts); @@ -6867,6 +7081,48 @@ bool TABLE::prepare_triggers_for_update_stmt_or_event() return FALSE; } + +/** + Validates default value of fields which are not specified in + the column list of INSERT/LOAD statement. + + @Note s->default_values should be properly populated + before calling this function. + + @param thd thread context + @param record the record to check values in + + @return + @retval false Success. + @retval true Failure. +*/ + +bool TABLE::validate_default_values_of_unset_fields(THD *thd) const +{ + DBUG_ENTER("TABLE::validate_default_values_of_unset_fields"); + for (Field **fld= field; *fld; fld++) + { + if (!bitmap_is_set(write_set, (*fld)->field_index) && + !((*fld)->flags & NO_DEFAULT_VALUE_FLAG)) + { + if (!(*fld)->is_null_in_record(s->default_values) && + (*fld)->validate_value_in_record_with_warn(thd, s->default_values) && + thd->is_error()) + { + /* + We're here if: + - validate_value_in_record_with_warn() failed and + strict mode converted WARN to ERROR + - or the connection was killed, or closed unexpectedly + */ + DBUG_RETURN(true); + } + } + } + DBUG_RETURN(false); +} + + /* @brief Reset const_table flag @@ -7153,7 +7409,7 @@ bool TABLE_LIST::change_refs_to_fields() DBUG_ASSERT(!field_it.end_of_fields()); if (!materialized_items[idx]) { - materialized_items[idx]= new Item_field(table->field[idx]); + materialized_items[idx]= new (thd->mem_root) Item_field(thd, table->field[idx]); if (!materialized_items[idx]) return TRUE; } @@ -7205,4 +7461,3 @@ double KEY::actual_rec_per_key(uint i) return (is_statistics_from_stat_tables ? read_stats->get_avg_frequency(i) : (double) rec_per_key[i]); } - |