summaryrefslogtreecommitdiff
path: root/sql/table.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/table.cc')
-rw-r--r--sql/table.cc469
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]);
}
-