summaryrefslogtreecommitdiff
path: root/sql/table.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/table.cc')
-rw-r--r--sql/table.cc281
1 files changed, 157 insertions, 124 deletions
diff --git a/sql/table.cc b/sql/table.cc
index 2b1a85a74ea..302c5090925 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -54,6 +54,8 @@ static uint find_field(Field **fields, uchar *record, uint start, uint length);
inline bool is_system_table_name(const char *name, uint length);
+static ulong get_form_pos(File file, uchar *head);
+
/**************************************************************************
Object_creation_ctx implementation.
**************************************************************************/
@@ -306,13 +308,6 @@ TABLE_SHARE *alloc_table_share(TABLE_LIST *table_list, char *key,
share->version= refresh_version;
/*
- This constant is used to mark that no table map version has been
- assigned. No arithmetic is done on the value: it will be
- overwritten with a value taken from MYSQL_BIN_LOG.
- */
- share->table_map_version= ~(ulonglong)0;
-
- /*
Since alloc_table_share() can be called without any locking (for
example, ha_create_table... functions), we do not assign a table
map id here. Instead we assign a value that is not used
@@ -375,11 +370,6 @@ void init_tmp_table_share(THD *thd, TABLE_SHARE *share, const char *key,
share->path.length= share->normalized_path.length= strlen(path);
share->frm_version= FRM_VER_TRUE_VARCHAR;
- /*
- Temporary tables are not replicated, but we set up these fields
- anyway to be able to catch errors.
- */
- share->table_map_version= ~(ulonglong)0;
share->cached_row_logging_check= -1;
/*
@@ -708,15 +698,20 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head,
const char **interval_array;
enum legacy_db_type legacy_db_type;
my_bitmap_map *bitmaps;
+ bool null_bits_are_used;
DBUG_ENTER("open_binary_frm");
+ LINT_INIT(options);
+ LINT_INIT(options_len);
+
new_field_pack_flag= head[27];
new_frm_ver= (head[2] - FRM_VER);
field_pack_length= new_frm_ver < 2 ? 11 : 17;
disk_buff= 0;
error= 3;
- if (!(pos=get_form_pos(file,head,(TYPELIB*) 0)))
+ /* Position of the form in the form file. */
+ if (!(pos= get_form_pos(file, head)))
goto err; /* purecov: inspected */
share->frm_version= head[2];
@@ -885,7 +880,7 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head,
/* Read extra data segment */
uchar *next_chunk, *buff_end;
DBUG_PRINT("info", ("extra segment size is %u bytes", n_length));
- if (!(next_chunk= buff= (uchar*) my_malloc(n_length, MYF(MY_WME))))
+ if (!(next_chunk= buff= (uchar*) my_malloc(n_length+1, MYF(MY_WME))))
goto err;
if (my_pread(file, buff, n_length, record_offset + share->reclength,
MYF(MY_NABP)))
@@ -960,6 +955,7 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head,
{
/* purecov: begin inspected */
error= 8;
+ name.str[name.length]= 0;
my_error(ER_UNKNOWN_STORAGE_ENGINE, MYF(0), name.str);
goto free_and_err;
/* purecov: end */
@@ -1154,6 +1150,7 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head,
goto free_and_err;
record= share->default_values-1; /* Fieldstart = 1 */
+ null_bits_are_used= share->null_fields != 0;
if (share->null_field_first)
{
null_flags= null_pos= (uchar*) record+1;
@@ -1372,6 +1369,7 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head,
reg_field->stored_in_db= fld_stored_in_db;
if (field_type == MYSQL_TYPE_BIT && !f_bit_as_char(pack_flag))
{
+ null_bits_are_used= 1;
if ((null_bit_pos+= field_length & 7) > 7)
{
null_pos++;
@@ -1505,12 +1503,6 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head,
keyinfo->extra_length+=HA_KEY_BLOB_LENGTH;
key_part->store_length+=HA_KEY_BLOB_LENGTH;
keyinfo->key_length+= HA_KEY_BLOB_LENGTH;
- /*
- Mark that there may be many matching values for one key
- combination ('a', 'a ', 'a '...)
- */
- if (!(field->flags & BINARY_FLAG))
- keyinfo->flags|= HA_END_SPACE_KEY;
}
if (field->type() == MYSQL_TYPE_BIT)
key_part->key_part_flag|= HA_BIT_PART;
@@ -1694,6 +1686,9 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head,
share->null_bytes= (null_pos - (uchar*) null_flags +
(null_bit_pos + 7) / 8);
share->last_null_bit_pos= null_bit_pos;
+ share->null_bytes_for_compare= null_bits_are_used ? share->null_bytes : 0;
+ share->can_cmp_whole_record= (share->blob_fields == 0 &&
+ share->varchar_fields == 0);
share->db_low_byte_first= handler_file->low_byte_first();
share->column_bitmap_size= bitmap_buffer_size(share->fields);
@@ -1851,6 +1846,11 @@ bool fix_vcol_expr(THD *thd,
goto end;
}
thd->where= save_where;
+ if (unlikely(func_expr->result_type() == ROW_RESULT))
+ {
+ my_error(ER_ROW_EXPR_FOR_VCOL, MYF(0));
+ goto end;
+ }
#ifdef PARANOID
/*
Walk through the Item tree checking if all items are valid
@@ -1915,10 +1915,8 @@ end:
parses it, building an item object for it. The pointer to this item is
placed into in field->vcol_info.expr_item. After this the function performs
semantic analysis of the item by calling the the function fix_vcol_expr.
- Since the defining expression is part of the table definition the item
- for it is created in table->memroot within a separate Query_arena.
- The free_list of this arena is saved in field->vcol_info.item_free_list
- to be freed when the table defition is removed from the TABLE_SHARE cache.
+ Since the defining expression is part of the table definition the item for
+ it is created in table->memroot within the special arena TABLE::expr_arena.
@note
Before passing 'vcol_expr" to the parser the function embraces it in
@@ -1935,18 +1933,25 @@ bool unpack_vcol_info_from_frm(THD *thd,
LEX_STRING *vcol_expr,
bool *error_reported)
{
- bool rc= FALSE;
+ bool rc;
+ char *vcol_expr_str;
+ int str_len;
+ CHARSET_INFO *old_character_set_client;
+ Query_arena *backup_stmt_arena_ptr;
+ Query_arena backup_arena;
+ Query_arena *vcol_arena= 0;
+ Parser_state parser_state;
DBUG_ENTER("unpack_vcol_info_from_frm");
DBUG_ASSERT(vcol_expr);
+ old_character_set_client= thd->variables.character_set_client;
+ backup_stmt_arena_ptr= thd->stmt_arena;
+
/*
Step 1: Construct the input string for the parser.
The string to be parsed has to be of the following format:
"PARSE_VCOL_EXPR (<expr_string_from_frm>)".
*/
- char *vcol_expr_str;
- int str_len= 0;
- CHARSET_INFO *old_character_set_client;
if (!(vcol_expr_str= (char*) alloc_root(&table->mem_root,
vcol_expr->length +
@@ -1968,19 +1973,27 @@ bool unpack_vcol_info_from_frm(THD *thd,
str_len++;
memcpy(vcol_expr_str + str_len, "\0", 1);
str_len++;
- Parser_state parser_state(thd, vcol_expr_str, str_len);
+
+ if (parser_state.init(thd, vcol_expr_str, str_len))
+ goto err;
/*
Step 2: Setup thd for parsing.
*/
- Query_arena *backup_stmt_arena_ptr= thd->stmt_arena;
- Query_arena backup_arena;
- Query_arena vcol_arena(&table->mem_root, Query_arena::INITIALIZED);
- thd->set_n_backup_active_arena(&vcol_arena, &backup_arena);
- thd->stmt_arena= &vcol_arena;
+ vcol_arena= table->expr_arena;
+ if (!vcol_arena)
+ {
+ Query_arena expr_arena(&table->mem_root, Query_arena::INITIALIZED);
+ if (!(vcol_arena= (Query_arena *) alloc_root(&table->mem_root,
+ sizeof(Query_arena))))
+ goto err;
+ *vcol_arena= expr_arena;
+ table->expr_arena= vcol_arena;
+ }
+ thd->set_n_backup_active_arena(vcol_arena, &backup_arena);
+ thd->stmt_arena= vcol_arena;
thd->lex->parse_vcol_expr= TRUE;
- old_character_set_client= thd->variables.character_set_client;
/*
Step 3: Use the parser to build an Item object from vcol_expr_str.
@@ -1999,7 +2012,7 @@ bool unpack_vcol_info_from_frm(THD *thd,
field->vcol_info= 0;
goto err;
}
- field->vcol_info->item_free_list= thd->free_list;
+ rc= FALSE;
goto end;
err:
@@ -2008,7 +2021,8 @@ err:
thd->free_items();
end:
thd->stmt_arena= backup_stmt_arena_ptr;
- thd->restore_active_arena(&vcol_arena, &backup_arena);
+ if (vcol_arena)
+ thd->restore_active_arena(vcol_arena, &backup_arena);
thd->variables.character_set_client= old_character_set_client;
DBUG_RETURN(rc);
@@ -2323,9 +2337,9 @@ partititon_err:
(my_bitmap_map*) bitmaps, share->fields, FALSE);
bitmap_init(&outparam->def_write_set,
(my_bitmap_map*) (bitmaps+bitmap_size), share->fields, FALSE);
- bitmap_init(&outparam->tmp_set,
+ bitmap_init(&outparam->def_vcol_set,
(my_bitmap_map*) (bitmaps+bitmap_size*2), share->fields, FALSE);
- bitmap_init(&outparam->vcol_set,
+ bitmap_init(&outparam->tmp_set,
(my_bitmap_map*) (bitmaps+bitmap_size*3), share->fields, FALSE);
outparam->default_column_bitmaps();
@@ -2431,12 +2445,12 @@ int closefrm(register TABLE *table, bool free_share)
}
my_free((char*) table->alias, MYF(MY_ALLOW_ZERO_PTR));
table->alias= 0;
+ if (table->expr_arena)
+ table->expr_arena->free_items();
if (table->field)
{
for (Field **ptr=table->field ; *ptr ; ptr++)
{
- if ((*ptr)->vcol_info)
- free_items((*ptr)->vcol_info->item_free_list);
delete *ptr;
}
table->field= 0;
@@ -2497,55 +2511,46 @@ void free_field_buffers_larger_than(TABLE *table, uint32 size)
}
}
- /* Find where a form starts */
- /* if formname is NullS then only formnames is read */
+/**
+ Find where a form starts.
+
+ @param head The start of the form file.
+
+ @remark If formname is NULL then only formnames is read.
+
+ @retval The form position.
+*/
-ulong get_form_pos(File file, uchar *head, TYPELIB *save_names)
+static ulong get_form_pos(File file, uchar *head)
{
- uint a_length,names,length;
- uchar *pos,*buf;
+ uchar *pos, *buf;
+ uint names, length;
ulong ret_value=0;
DBUG_ENTER("get_form_pos");
- LINT_INIT(buf);
+ names= uint2korr(head+8);
- names=uint2korr(head+8);
- a_length=(names+2)*sizeof(char *); /* Room for two extra */
+ if (!(names= uint2korr(head+8)))
+ DBUG_RETURN(0);
- if (!save_names)
- a_length=0;
- else
- save_names->type_names=0; /* Clear if error */
-
- if (names)
- {
- length=uint2korr(head+4);
- VOID(my_seek(file,64L,MY_SEEK_SET,MYF(0)));
- if (!(buf= (uchar*) my_malloc((size_t) length+a_length+names*4,
- MYF(MY_WME))) ||
- my_read(file, buf+a_length, (size_t) (length+names*4),
- MYF(MY_NABP)))
- { /* purecov: inspected */
- x_free((uchar*) buf); /* purecov: inspected */
- DBUG_RETURN(0L); /* purecov: inspected */
- }
- pos= buf+a_length+length;
- ret_value=uint4korr(pos);
- }
- if (! save_names)
- {
- if (names)
- my_free((uchar*) buf,MYF(0));
- }
- else if (!names)
- bzero((char*) save_names,sizeof(save_names));
- else
+ length= uint2korr(head+4);
+
+ my_seek(file, 64L, MY_SEEK_SET, MYF(0));
+
+ if (!(buf= (uchar*) my_malloc(length+names*4, MYF(MY_WME))))
+ DBUG_RETURN(0);
+
+ if (my_read(file, buf, length+names*4, MYF(MY_NABP)))
{
- char *str;
- const char **tmp = (const char**) buf;
- str=(char *) (buf+a_length);
- fix_type_pointers(&tmp, save_names, 1, &str);
+ x_free(buf);
+ DBUG_RETURN(0);
}
+
+ pos= buf+length;
+ ret_value= uint4korr(pos);
+
+ my_free(buf, MYF(0));
+
DBUG_RETURN(ret_value);
}
@@ -3143,6 +3148,13 @@ bool check_db_name(LEX_STRING *org_name)
{
char *name= org_name->str;
uint name_length= org_name->length;
+ bool check_for_path_chars;
+
+ if ((check_for_path_chars= check_mysql50_prefix(name)))
+ {
+ name+= MYSQL50_TABLE_NAME_PREFIX_LENGTH;
+ name_length-= MYSQL50_TABLE_NAME_PREFIX_LENGTH;
+ }
if (!name_length || name_length > NAME_LEN)
return 1;
@@ -3150,41 +3162,29 @@ bool check_db_name(LEX_STRING *org_name)
if (lower_case_table_names && name != any_db)
my_casedn_str(files_charset_info, name);
-#if defined(USE_MB) && defined(USE_MB_IDENT)
- if (use_mb(system_charset_info))
- {
- name_length= 0;
- bool last_char_is_space= TRUE;
- char *end= name + org_name->length;
- while (name < end)
- {
- int len;
- last_char_is_space= my_isspace(system_charset_info, *name);
- len= my_ismbchar(system_charset_info, name, end);
- if (!len)
- len= 1;
- name+= len;
- name_length++;
- }
- return (last_char_is_space || name_length > NAME_CHAR_LEN);
- }
- else
-#endif
- return ((org_name->str[org_name->length - 1] != ' ') ||
- (name_length > NAME_CHAR_LEN)); /* purecov: inspected */
+ return check_table_name(name, name_length, check_for_path_chars);
}
+
/*
Allow anything as a table name, as long as it doesn't contain an
' ' at the end
returns 1 on error
*/
-
bool check_table_name(const char *name, uint length, bool check_for_path_chars)
{
uint name_length= 0; // name length in symbols
const char *end= name+length;
+
+
+ if (!check_for_path_chars &&
+ (check_for_path_chars= check_mysql50_prefix(name)))
+ {
+ name+= MYSQL50_TABLE_NAME_PREFIX_LENGTH;
+ length-= MYSQL50_TABLE_NAME_PREFIX_LENGTH;
+ }
+
if (!length || length > NAME_LEN)
return 1;
#if defined(USE_MB) && defined(USE_MB_IDENT)
@@ -3208,10 +3208,10 @@ bool check_table_name(const char *name, uint length, bool check_for_path_chars)
continue;
}
}
+#endif
if (check_for_path_chars &&
(*name == '/' || *name == '\\' || *name == '~' || *name == FN_EXTCHAR))
return 1;
-#endif
name++;
name_length++;
}
@@ -4789,10 +4789,10 @@ void st_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);
*/
- bzero((char*) def_read_set.bitmap, s->column_bitmap_size*2);
- bzero((char*) def_read_set.bitmap, s->column_bitmap_size*4);
- column_bitmaps_set(&def_read_set, &def_write_set);
+ bzero((char*) def_read_set.bitmap, s->column_bitmap_size*3);
+ column_bitmaps_set(&def_read_set, &def_write_set, &def_vcol_set);
}
@@ -4844,6 +4844,27 @@ void st_table::mark_columns_used_by_index(uint index)
/*
+ Add fields used by a specified index to the table's read_set.
+
+ NOTE:
+ The original state can be restored with
+ restore_column_maps_after_mark_index().
+*/
+
+void st_table::add_read_columns_used_by_index(uint index)
+{
+ MY_BITMAP *bitmap= &tmp_set;
+ DBUG_ENTER("st_table::add_read_columns_used_by_index");
+
+ enable_keyread();
+ bitmap_copy(bitmap, read_set);
+ mark_columns_used_by_index_no_reset(index, bitmap);
+ column_bitmaps_set(bitmap, write_set);
+ DBUG_VOID_RETURN;
+}
+
+
+/*
Restore to use normal column maps after key read
NOTES
@@ -5011,7 +5032,7 @@ void st_table::mark_columns_needed_for_update()
}
}
/* Mark all virtual columns needed for update */
- mark_virtual_columns_for_write();
+ mark_virtual_columns_for_write(FALSE);
DBUG_VOID_RETURN;
}
@@ -5039,7 +5060,7 @@ void st_table::mark_columns_needed_for_insert()
if (found_next_number_field)
mark_auto_increment_column();
/* Mark virtual columns for insert */
- mark_virtual_columns_for_write();
+ mark_virtual_columns_for_write(TRUE);
}
@@ -5065,7 +5086,7 @@ bool st_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)))
+ if (!(res= bitmap_fast_test_and_set(vcol_set, field->field_index)))
{
Item *vcol_item= field->vcol_info->expr_item;
DBUG_ASSERT(vcol_item);
@@ -5077,10 +5098,14 @@ bool st_table::mark_virtual_col(Field *field)
/*
@brief Mark virtual columns for update/insert commands
+
+ @param insert_fl <-> virtual columns are marked for insert command
@details
The function marks virtual columns used in a update/insert commands
in the vcol_set bitmap.
+ For an insert command a virtual column is always marked in write_set if
+ it is a stored column.
If a virtual column is from write_set it is always marked in vcol_set.
If a stored virtual column is not from write_set but it is computed
through columns from write_set it is also marked in vcol_set, and,
@@ -5099,7 +5124,7 @@ bool st_table::mark_virtual_col(Field *field)
be added to read_set either.
*/
-void st_table::mark_virtual_columns_for_write(void)
+void st_table::mark_virtual_columns_for_write(bool insert_fl)
{
Field **vfield_ptr, *tmp_vfield;
bool bitmap_updated= FALSE;
@@ -5111,16 +5136,21 @@ void st_table::mark_virtual_columns_for_write(void)
bitmap_updated= mark_virtual_col(tmp_vfield);
else if (tmp_vfield->stored_in_db)
{
- MY_BITMAP *save_read_set;
- Item *vcol_item= tmp_vfield->vcol_info->expr_item;
- DBUG_ASSERT(vcol_item);
- bitmap_clear_all(&tmp_set);
- save_read_set= read_set;
- read_set= &tmp_set;
- vcol_item->walk(&Item::register_field_in_read_map, 1, (uchar *) 0);
- read_set= save_read_set;
- bitmap_intersect(&tmp_set, write_set);
- if (!bitmap_is_clear_all(&tmp_set))
+ bool mark_fl= insert_fl;
+ if (!mark_fl)
+ {
+ MY_BITMAP *save_read_set;
+ Item *vcol_item= tmp_vfield->vcol_info->expr_item;
+ DBUG_ASSERT(vcol_item);
+ bitmap_clear_all(&tmp_set);
+ save_read_set= read_set;
+ read_set= &tmp_set;
+ vcol_item->walk(&Item::register_field_in_read_map, 1, (uchar *) 0);
+ read_set= save_read_set;
+ bitmap_intersect(&tmp_set, write_set);
+ mark_fl= !bitmap_is_clear_all(&tmp_set);
+ }
+ if (mark_fl)
{
bitmap_set_bit(write_set, tmp_vfield->field_index);
mark_virtual_col(tmp_vfield);
@@ -5529,6 +5559,7 @@ size_t max_row_length(TABLE *table, const uchar *data)
/*
@brief Compute values for virtual columns used in query
+ @param thd Thread handle
@param table The TABLE object
@param for_write Requests to compute only fields needed for write
@@ -5545,7 +5576,7 @@ size_t max_row_length(TABLE *table, const uchar *data)
>0 Error occurred when storing a virtual field value
*/
-int update_virtual_fields(TABLE *table, bool for_write)
+int update_virtual_fields(THD *thd, TABLE *table, bool for_write)
{
DBUG_ENTER("update_virtual_fields");
Field **vfield_ptr, *vfield;
@@ -5553,13 +5584,14 @@ int update_virtual_fields(TABLE *table, bool for_write)
if (!table || !table->vfield)
DBUG_RETURN(0);
+ thd->reset_arena_for_cached_items(table->expr_arena);
/* Iterate over virtual fields in the table */
for (vfield_ptr= table->vfield; *vfield_ptr; vfield_ptr++)
{
vfield= (*vfield_ptr);
DBUG_ASSERT(vfield->vcol_info && vfield->vcol_info->expr_item);
/* Only update those fields that are marked in the vcol_set bitmap */
- if (bitmap_is_set(&table->vcol_set, vfield->field_index) &&
+ if (bitmap_is_set(table->vcol_set, vfield->field_index) &&
(for_write || !vfield->stored_in_db))
{
/* Compute the actual value of the virtual fields */
@@ -5571,6 +5603,7 @@ int update_virtual_fields(TABLE *table, bool for_write)
DBUG_PRINT("info", ("field '%s' - skipped", vfield->field_name));
}
}
+ thd->reset_arena_for_cached_items(0);
DBUG_RETURN(0);
}