diff options
author | Mikael Ronstrom <mikael@mysql.com> | 2009-10-16 16:16:06 +0200 |
---|---|---|
committer | Mikael Ronstrom <mikael@mysql.com> | 2009-10-16 16:16:06 +0200 |
commit | c90669c4d423ba46f09aadde5ff6662e8a63a1c0 (patch) | |
tree | df5230b4e7781d295ef1eb1cedbd289ee413a075 /sql | |
parent | 576dd76aa81787f71e038efd9e00713b7a44b3c5 (diff) | |
download | mariadb-git-c90669c4d423ba46f09aadde5ff6662e8a63a1c0.tar.gz |
Fixed removal of column_list keyword for VALUES part, retained for PARTITION BY RANGE/LIST COLUMN_LIST, not entirely working yet
Diffstat (limited to 'sql')
-rw-r--r-- | sql/partition_element.h | 1 | ||||
-rw-r--r-- | sql/partition_info.cc | 615 | ||||
-rw-r--r-- | sql/partition_info.h | 15 | ||||
-rw-r--r-- | sql/share/errmsg.txt | 8 | ||||
-rw-r--r-- | sql/sql_partition.cc | 28 | ||||
-rw-r--r-- | sql/sql_yacc.yy | 272 |
6 files changed, 640 insertions, 299 deletions
diff --git a/sql/partition_element.h b/sql/partition_element.h index d749681fe9b..5cb3b41fa2e 100644 --- a/sql/partition_element.h +++ b/sql/partition_element.h @@ -74,6 +74,7 @@ typedef struct p_column_list_val typedef struct p_elem_val { longlong value; + uint added_items; bool null_value; bool unsigned_flag; part_column_list_val *col_val_array; diff --git a/sql/partition_info.cc b/sql/partition_info.cc index ef212fce28d..430d5b81640 100644 --- a/sql/partition_info.cc +++ b/sql/partition_info.cc @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 MySQL AB +/* Copyrght (C) 2006 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -682,7 +682,7 @@ bool partition_info::check_range_constants(THD *thd) part_elem_value *range_val= list_val_it++; part_column_list_val *col_val= range_val->col_val_array; - if (fix_column_value_functions(thd, col_val, i)) + if (fix_column_value_functions(thd, range_val, i)) goto end; memcpy(loc_range_col_array, (const void*)col_val, size_entries); loc_range_col_array+= num_column_values; @@ -827,85 +827,6 @@ int partition_info::compare_column_values(const void *first_arg, } /* - Evaluate VALUES functions for column list values - SYNOPSIS - fix_column_value_functions() - thd Thread object - col_val List of column values - part_id Partition id we are fixing - RETURN VALUES - TRUE Error - FALSE Success - DESCRIPTION - Fix column VALUES and store in memory array adapted to the data type -*/ - -bool partition_info::fix_column_value_functions(THD *thd, - part_column_list_val *col_val, - uint part_id) -{ - uint num_columns= part_field_list.elements; - Name_resolution_context *context= &thd->lex->current_select->context; - TABLE_LIST *save_list= context->table_list; - bool result= FALSE; - uint i; - const char *save_where= thd->where; - DBUG_ENTER("partition_info::fix_column_value_functions"); - if (col_val->fixed > 1) - { - DBUG_RETURN(FALSE); - } - context->table_list= 0; - thd->where= "partition function"; - for (i= 0; i < num_columns; col_val++, i++) - { - Item *column_item= col_val->item_expression; - Field *field= part_field_array[i]; - col_val->part_info= this; - col_val->partition_id= part_id; - if (col_val->max_value) - col_val->column_value= NULL; - else - { - if (!col_val->fixed && - (column_item->fix_fields(thd, (Item**)0) || - (!column_item->const_item()))) - { - my_error(ER_NO_CONST_EXPR_IN_RANGE_OR_LIST_ERROR, MYF(0)); - result= TRUE; - goto end; - } - col_val->null_value= column_item->null_value; - col_val->column_value= NULL; - if (!col_val->null_value) - { - uchar *val_ptr; - uint len= field->pack_length(); - if (column_item->save_in_field(field, TRUE)) - { - my_error(ER_WRONG_TYPE_COLUMN_VALUE_ERROR, MYF(0)); - result= TRUE; - goto end; - } - if (!(val_ptr= (uchar*) sql_calloc(len))) - { - mem_alloc_error(len); - result= TRUE; - goto end; - } - col_val->column_value= val_ptr; - memcpy(val_ptr, field->ptr, len); - } - } - col_val->fixed= 2; - } -end: - thd->where= save_where; - context->table_list= save_list; - DBUG_RETURN(result); -} - -/* This routine allocates an array for all list constants to achieve a fast check what partition a certain value belongs to. At the same time it does also check that there are no duplicates among the list constants and that @@ -1002,7 +923,7 @@ bool partition_info::check_list_constants(THD *thd) while ((list_value= list_val_it2++)) { part_column_list_val *col_val= list_value->col_val_array; - if (unlikely(fix_column_value_functions(thd, col_val, i))) + if (unlikely(fix_column_value_functions(thd, list_value, i))) { DBUG_RETURN(TRUE); } @@ -1126,6 +1047,8 @@ bool partition_info::check_partition_info(THD *thd, handlerton **eng_type, my_error(ER_PARTITION_FUNCTION_IS_NOT_ALLOWED, MYF(0)); goto end; } + if (fix_parser_data(thd)) + goto end; } if (unlikely(!is_sub_partitioned() && !(use_default_subpartitions && use_default_num_subpartitions))) @@ -1378,31 +1301,6 @@ void partition_info::print_no_partition_found(TABLE *table) /* - Create a new column value in current list - SYNOPSIS - add_column_value() - RETURN - >0 A part_column_list_val object which have been - inserted into its list - 0 Memory allocation failure -*/ - -part_column_list_val *partition_info::add_column_value() -{ - uint max_val= num_columns ? num_columns : MAX_REF_PARTS; - DBUG_ENTER("add_column_value"); - DBUG_PRINT("enter", ("num_columns = %u, curr_list_object %u, max_val = %u", - num_columns, curr_list_object, max_val)); - if (curr_list_object < max_val) - { - DBUG_RETURN(&curr_list_val->col_val_array[curr_list_object++]); - } - my_error(ER_PARTITION_COLUMN_LIST_ERROR, MYF(0)); - DBUG_RETURN(NULL); -} - - -/* Set fields related to partition expression SYNOPSIS set_part_expr() @@ -1616,4 +1514,507 @@ id_err: } +/* + Create a new column value in current list with maxvalue + Called from parser + + SYNOPSIS + add_max_value() + RETURN + TRUE Error + FALSE Success +*/ + +int partition_info::add_max_value() +{ + DBUG_ENTER("partition_info::add_max_value"); + + part_column_list_val *col_val; + if (!(col_val= add_column_value())) + { + DBUG_RETURN(TRUE); + } + col_val->max_value= TRUE; + DBUG_RETURN(FALSE); +} + +/* + Create a new column value in current list + Called from parser + + SYNOPSIS + add_column_value() + RETURN + >0 A part_column_list_val object which have been + inserted into its list + 0 Memory allocation failure +*/ + +part_column_list_val *partition_info::add_column_value() +{ + uint max_val= num_columns ? num_columns : MAX_REF_PARTS; + DBUG_ENTER("add_column_value"); + DBUG_PRINT("enter", ("num_columns = %u, curr_list_object %u, max_val = %u", + num_columns, curr_list_object, max_val)); + if (curr_list_object < max_val) + { + curr_list_val->added_items++; + DBUG_RETURN(&curr_list_val->col_val_array[curr_list_object++]); + } + if (!num_columns && part_type == LIST_PARTITION) + { + /* + We're trying to add more than MAX_REF_PARTS, this can happen + in ALTER TABLE using List partitions where the first partition + uses VALUES IN (1,2,3...,17) where the number of fields in + the list is more than MAX_REF_PARTS, in this case we know + that the number of columns must be 1 and we thus reorganize + into the structure used for 1 column. After this we call + ourselves recursively which should always succeed. + */ + if (!reorganize_into_single_field_col_val()) + { + DBUG_RETURN(add_column_value()); + } + DBUG_RETURN(NULL); + } + my_error(ER_PARTITION_COLUMN_LIST_ERROR, MYF(0)); + DBUG_RETURN(NULL); +} + + +/* + Add a column value in VALUES LESS THAN or VALUES IN + (Called from parser) + + SYNOPSIS + add_column_list_value() + lex Parser's lex object + item Item object representing column value + + RETURN VALUES + TRUE Failure + FALSE Success +*/ +bool partition_info::add_column_list_value(Item *item) +{ + part_column_list_val *col_val; + DBUG_ENTER("partition_info::add_column_list_value"); + + if (part_type == LIST_PARTITION && + num_columns == 1U) + { + if (init_column_part()) + { + DBUG_RETURN(TRUE); + } + } + if (!(col_val= add_column_value())) + { + DBUG_RETURN(TRUE); + } + col_val->item_expression= item; + col_val->part_info= NULL; + DBUG_RETURN(FALSE); +} + +/* + Initialise part_info object for receiving a set of column values + for a partition, called when parser reaches VALUES LESS THAN or + VALUES IN. + + SYNOPSIS + init_column_part() + lex Parser's lex object + + RETURN VALUES + TRUE Failure + FALSE Success +*/ +bool partition_info::init_column_part() +{ + partition_element *p_elem= curr_part_elem; + part_column_list_val *col_val_array; + part_elem_value *list_val; + uint loc_num_columns; + DBUG_ENTER("partition_info::init_column_part"); + + if (!(list_val= + (part_elem_value*)sql_calloc(sizeof(part_elem_value))) || + p_elem->list_val_list.push_back(list_val)) + { + mem_alloc_error(sizeof(part_elem_value)); + DBUG_RETURN(TRUE); + } + if (num_columns) + loc_num_columns= num_columns; + else + loc_num_columns= MAX_REF_PARTS; + if (!(col_val_array= + (part_column_list_val*)sql_calloc(loc_num_columns * + sizeof(part_column_list_val)))) + { + mem_alloc_error(loc_num_columns * sizeof(part_elem_value)); + DBUG_RETURN(TRUE); + } + list_val->col_val_array= col_val_array; + list_val->added_items= 0; + curr_list_val= list_val; + curr_list_object= 0; + DBUG_RETURN(FALSE); +} + +/* + In the case of ALTER TABLE ADD/REORGANIZE PARTITION for LIST + partitions we can specify list values as: + VALUES IN (v1, v2,,,, v17) if we're using the first partitioning + variant with a function or a column list partitioned table with + one partition field. In this case the parser knows not the + number of columns start with and allocates MAX_REF_PARTS in the + array. If we try to allocate something beyond MAX_REF_PARTS we + will call this function to reorganize into a structure with + num_columns = 1. Also when the parser knows that we used LIST + partitioning and we used a VALUES IN like above where number of + values was smaller than MAX_REF_PARTS or equal, then we will + reorganize after discovering this in the parser. + + SYNOPSIS + reorganize_into_single_field_col_val() + + RETURN VALUES + TRUE Failure + FALSE Success +*/ +int partition_info::reorganize_into_single_field_col_val() +{ + part_column_list_val *col_val; + Item *part_expr; + uint loc_num_columns= num_columns; + uint i; + DBUG_ENTER("partition_info::reorganize_into_single_field_col_val"); + + num_columns= 1; + curr_list_val->added_items= 1U; + for (i= 1; i < loc_num_columns; i++) + { + col_val= &curr_list_val->col_val_array[i]; + part_expr= col_val->item_expression; + if ((part_type != LIST_PARTITION && + init_column_part()) || + add_column_list_value(part_expr)) + { + DBUG_RETURN(TRUE); + } + } + DBUG_RETURN(FALSE); +} + +/* + This function handles the case of function-based partitioning. + It fixes some data structures created in the parser and puts + them in the format required by the rest of the partitioning + code. + + SYNOPSIS + fix_func_partition() + thd Thread object + col_val Array of one value + part_elem The partition instance + + RETURN VALUES + TRUE Failure + FALSE Success +*/ +int partition_info::fix_func_partition(THD *thd, + part_elem_value *val, + partition_element *part_elem) +{ + uint i; + part_column_list_val *col_val= val->col_val_array; + DBUG_ENTER("partition_info::fix_func_partition"); + + if (col_val->fixed) + { + DBUG_RETURN(FALSE); + } + if (val->added_items != 1) + { + my_error(ER_PARTITION_COLUMN_LIST_ERROR, MYF(0)); + DBUG_RETURN(TRUE); + } + if (col_val->max_value) + { + /* The parser ensures we're not LIST partitioned here */ + DBUG_ASSERT(part_type == RANGE_PARTITION); + if (defined_max_value) + { + my_error(ER_PARTITION_MAXVALUE_ERROR, MYF(0)); + DBUG_RETURN(TRUE); + } + if (i == (num_parts - 1)) + { + defined_max_value= TRUE; + part_elem->max_value= TRUE; + part_elem->range_value= LONGLONG_MAX; + } + else + { + my_error(ER_PARTITION_MAXVALUE_ERROR, MYF(0)); + DBUG_RETURN(TRUE); + } + } + else + { + part_elem_value *value_ptr; + Name_resolution_context *context= &thd->lex->current_select->context; + TABLE_LIST *save_list= context->table_list; + const char *save_where= thd->where; + Item *item_expr= col_val->item_expression; + + context->table_list= 0; + thd->where= "partition function"; + + value_ptr= (part_elem_value*)sql_alloc(sizeof(part_elem_value)); + if (!value_ptr) + { + mem_alloc_error(sizeof(part_elem_value)); + DBUG_RETURN(TRUE); + } + if (item_expr->walk(&Item::check_partition_func_processor, 0, + NULL)) + { + my_error(ER_PARTITION_FUNCTION_IS_NOT_ALLOWED, MYF(0)); + DBUG_RETURN(TRUE); + } + if (item_expr->fix_fields(thd, (Item**)0) || + ((context->table_list= save_list), FALSE) || + (!item_expr->const_item())) + { + context->table_list= save_list; + thd->where= save_where; + my_error(ER_NO_CONST_EXPR_IN_RANGE_OR_LIST_ERROR, MYF(0)); + DBUG_RETURN(TRUE); + } + thd->where= save_where; + value_ptr->value= part_expr->val_int(); + value_ptr->unsigned_flag= TRUE; + if (!item_expr->unsigned_flag && + value_ptr->value < 0) + value_ptr->unsigned_flag= FALSE; + if ((value_ptr->null_value= item_expr->null_value)) + { + if (part_elem->has_null_value) + { + my_error(ER_MULTIPLE_DEF_CONST_IN_LIST_PART_ERROR, MYF(0)); + DBUG_RETURN(TRUE); + } + part_elem->has_null_value= TRUE; + } + else if (item_expr->result_type() != INT_RESULT) + { + my_error(ER_INCONSISTENT_TYPE_OF_FUNCTIONS_ERROR, MYF(0)); + DBUG_RETURN(TRUE); + } + if (!value_ptr->unsigned_flag) + part_elem->signed_flag= TRUE; + if (part_type == RANGE_PARTITION) + { + if (part_elem->has_null_value) + { + my_error(ER_NULL_IN_VALUES_LESS_THAN, MYF(0)); + DBUG_RETURN(TRUE); + } + part_elem->range_value= value_ptr->value; + } + else if (part_type == LIST_PARTITION) + { + if (!value_ptr->null_value && + part_elem->list_val_list.push_back(value_ptr)) + { + mem_alloc_error(sizeof(part_elem_value)); + DBUG_RETURN(TRUE); + } + } + } + col_val->fixed= 2; + DBUG_RETURN(FALSE); +} + + +/* + Evaluate VALUES functions for column list values + SYNOPSIS + fix_column_value_functions() + thd Thread object + col_val List of column values + part_id Partition id we are fixing + + RETURN VALUES + TRUE Error + FALSE Success + DESCRIPTION + Fix column VALUES and store in memory array adapted to the data type +*/ + +bool partition_info::fix_column_value_functions(THD *thd, + part_elem_value *val, + uint part_id) +{ + uint num_columns= part_field_list.elements; + Name_resolution_context *context= &thd->lex->current_select->context; + TABLE_LIST *save_list= context->table_list; + bool result= FALSE; + uint i; + const char *save_where= thd->where; + part_column_list_val *col_val= val->col_val_array; + DBUG_ENTER("partition_info::fix_column_value_functions"); + + if (col_val->fixed > 1) + { + DBUG_RETURN(FALSE); + } + if (val->added_items != num_columns) + { + my_error(ER_PARTITION_COLUMN_LIST_ERROR, MYF(0)); + DBUG_RETURN(TRUE); + } + context->table_list= 0; + thd->where= "partition function"; + for (i= 0; i < num_columns; col_val++, i++) + { + Item *column_item= col_val->item_expression; + Field *field= part_field_array[i]; + col_val->part_info= this; + col_val->partition_id= part_id; + if (col_val->max_value) + col_val->column_value= NULL; + else + { + if (!col_val->fixed && + (column_item->fix_fields(thd, (Item**)0) || + (!column_item->const_item()))) + { + my_error(ER_NO_CONST_EXPR_IN_RANGE_OR_LIST_ERROR, MYF(0)); + result= TRUE; + goto end; + } + col_val->null_value= column_item->null_value; + col_val->column_value= NULL; + if (!col_val->null_value) + { + uchar *val_ptr; + uint len= field->pack_length(); + if (column_item->save_in_field(field, TRUE)) + { + my_error(ER_WRONG_TYPE_COLUMN_VALUE_ERROR, MYF(0)); + result= TRUE; + goto end; + } + if (!(val_ptr= (uchar*) sql_calloc(len))) + { + mem_alloc_error(len); + result= TRUE; + goto end; + } + col_val->column_value= val_ptr; + memcpy(val_ptr, field->ptr, len); + } + } + col_val->fixed= 2; + } +end: + thd->where= save_where; + context->table_list= save_list; + DBUG_RETURN(result); +} + +/* + The parser generates generic data structures, we need to set them up + as the rest of the code expects to find them. This is in reality part + of the syntax check of the parser code. + + It is necessary to call this function in the case of a CREATE TABLE + statement, in this case we do it early in the check_partition_info + function. + + It is necessary to call this function for ALTER TABLE where we + assign a completely new partition structure, in this case we do it + in prep_alter_part_table after discovering that the partition + structure is entirely redefined. + + It's necessary to call this method also for ALTER TABLE ADD/REORGANIZE + of partitions, in this we call it in prep_alter_part_table after + making some initial checks but before going deep to check the partition + info, we also assign the column_list variable before calling this function + here. + + Finally we also call it immediately after returning from parsing the + partitioning text found in the frm file. + + This function mainly fixes the VALUES parts, these are handled differently + whether or not we use column list partitioning. Since the parser doesn't + know which we are using we need to set-up the old data structures after + the parser is complete when we know if what type of partitioning the + base table is using. + + For column lists we will handle this in the fix_column_value_function. + For column lists it is sufficient to verify that the number of columns + and number of elements are in synch with each other. So only partitioning + using functions need to be set-up to their data structures. + + SYNOPSIS + fix_parser_data() + thd Thread object + + RETURN VALUES + TRUE Failure + FALSE Success +*/ + +int partition_info::fix_parser_data(THD *thd) +{ + List_iterator<partition_element> it(partitions); + partition_element *part_elem; + part_elem_value *val; + uint num_elements; + uint i= 0, j; + int result; + DBUG_ENTER("partition_info::fix_parser_data"); + + if (!(part_type == RANGE_PARTITION || + part_type == LIST_PARTITION)) + { + /* Nothing to do for HASH/KEY partitioning */ + DBUG_RETURN(FALSE); + } + do + { + part_elem= it++; + j= 0; + num_elements= part_elem->list_val_list.elements; + DBUG_ASSERT(part_type == RANGE_PARTITION ? + num_elements == 1U : TRUE); + { + List_iterator<part_elem_value> list_val_it(part_elem->list_val_list); + part_elem_value *val= list_val_it++; + result= column_list ? + fix_column_value_functions(thd, val, i) : + fix_func_partition(thd, val, part_elem); + if (result) + { + DBUG_RETURN(TRUE); + } + } while (++j < num_elements); + } while (++i < num_parts); +} + +void partition_info::print_debug(const char *str, uint *value) +{ + DBUG_ENTER("print_debug"); + if (value) + DBUG_PRINT("info", ("parser: %s, val = %u", str, *value)); + else + DBUG_PRINT("info", ("parser: %s", str)); + DBUG_VOID_RETURN; +} #endif /* WITH_PARTITION_STORAGE_ENGINE */ diff --git a/sql/partition_info.h b/sql/partition_info.h index 6e197198807..bf0d12e2df6 100644 --- a/sql/partition_info.h +++ b/sql/partition_info.h @@ -280,11 +280,23 @@ public: handler *file, HA_CREATE_INFO *info, bool check_partition_function); void print_no_partition_found(TABLE *table); + void print_debug(const char *str, uint*); + int fix_func_partition(THD *thd, + part_elem_value *val, + partition_element *part_elem); + bool fix_column_value_functions(THD *thd, + part_elem_value *val, + uint part_id); + int fix_parser_data(THD *thd); + int add_max_value(); + int reorganize_into_single_field_col_val(); part_column_list_val *add_column_value(); bool set_part_expr(char *start_token, Item *item_ptr, char *end_token, bool is_subpart); static int compare_column_values(const void *a, const void *b); bool set_up_charset_field_preps(); + bool init_column_part(); + bool add_column_list_value(Item *item); private: static int list_part_cmp(const void* a, const void* b); bool set_up_default_partitions(handler *file, HA_CREATE_INFO *info, @@ -294,9 +306,6 @@ private: uint start_no); char *create_subpartition_name(uint subpart_no, const char *part_name); bool has_unique_name(partition_element *element); - bool fix_column_value_functions(THD *thd, - part_column_list_val *col_val, - uint part_id); }; uint32 get_next_partition_id_range(struct st_partition_iter* part_iter); diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index 3d228f58360..470997aa948 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -5822,8 +5822,6 @@ ER_SAME_NAME_PARTITION eng "Duplicate partition name %-.192s" ger "Doppelter Partitionsname: %-.192s" swe "Duplicerat partitionsnamn %-.192s" -ER_SAME_NAME_PARTITION_FIELD - eng "Duplicate partition field name %-.192s" ER_NO_BINLOG_ERROR eng "It is not allowed to shut off binlog on this command" ger "Es es nicht erlaubt, bei diesem Befehl binlog abzuschalten" @@ -6192,6 +6190,12 @@ ER_TOO_MANY_PARTITION_FUNC_FIELDS_ERROR eng "Too many fields in '%s'" ER_MAXVALUE_IN_LIST_PARTITIONING_ERROR eng "Cannot use MAXVALUE as value in List partitioning" +ER_TOO_MANY_VALUES_ERROR + eng "Cannot have more than one value for this type of %-.64s partitioning" +ER_SAME_NAME_PARTITION_FIELD + eng "Duplicate partition field name %-.192s" +ER_ROW_SINGLE_PARTITION_FIELD_ERROR + eng "Row expressions in VALUES IN only allowed for multi-field column partitioning" # When updating these, please update EXPLAIN_FILENAME_MAX_EXTRA_LENGTH in # mysql_priv.h with the new maximal additional length for explain_filename. diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 52e28311ead..4cb001ef659 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -1990,8 +1990,11 @@ static int add_column_list_values(File fptr, partition_info *part_info, int err= 0; uint i; uint num_elements= part_info->part_field_list.elements; - err+= add_string(fptr, partition_keywords[PKW_COLUMNS].str); - err+= add_begin_parenthesis(fptr); + bool use_parenthesis= (part_info->part_type == LIST_PARTITION && + part_info->num_columns > 1U); + + if (use_parenthesis) + err+= add_begin_parenthesis(fptr); for (i= 0; i < num_elements; i++) { part_column_list_val *col_val= &list_value->col_val_array[i]; @@ -2032,7 +2035,8 @@ static int add_column_list_values(File fptr, partition_info *part_info, if (i != (num_elements - 1)) err+= add_string(fptr, comma_str); } - err+= add_end_parenthesis(fptr); + if (use_parenthesis) + err+= add_end_parenthesis(fptr); return err; } @@ -3894,10 +3898,12 @@ bool mysql_unpack_partition(THD *thd, mem_alloc_error(sizeof(partition_info)); goto end; } - lex.part_info->part_state= part_state; - lex.part_info->part_state_len= part_state_len; + part_info= lex.part_info; + part_info->part_state= part_state; + part_info->part_state_len= part_state_len; DBUG_PRINT("info", ("Parse: %s", part_buf)); - if (parse_sql(thd, & parser_state, NULL)) + if (parse_sql(thd, & parser_state, NULL) || + part_info->fix_parser_data(thd)) { thd->free_items(); goto end; @@ -3918,7 +3924,6 @@ bool mysql_unpack_partition(THD *thd, */ DBUG_PRINT("info", ("Successful parse")); - part_info= lex.part_info; DBUG_PRINT("info", ("default engine = %s, default_db_type = %s", ha_resolve_storage_engine_name(part_info->default_engine_type), ha_resolve_storage_engine_name(default_db_type))); @@ -4370,6 +4375,11 @@ uint prep_alter_part_table(THD *thd, TABLE *table, Alter_info *alter_info, } DBUG_RETURN(TRUE); } + alt_part_info->column_list= tab_part_info->column_list; + if (alt_part_info->fix_parser_data(thd)) + { + DBUG_RETURN(TRUE); + } } if (alter_info->flags & ALTER_ADD_PARTITION) { @@ -5126,6 +5136,10 @@ the generated partition syntax in a correct manner. { DBUG_PRINT("info", ("partition changed")); *partition_changed= TRUE; + if (thd->work_part_info->fix_parser_data(thd)) + { + DBUG_RETURN(TRUE); + } } /* Set up partition default_engine_type either from the create_info diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 0610350b38f..9d9fa7cde2e 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -515,10 +515,10 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %pure_parser /* We have threads */ /* - Currently there are 168 shift/reduce conflicts. + Currently there are 169 shift/reduce conflicts. We should not introduce new conflicts any more. */ -%expect 168 +%expect 169 /* Comments for TOKENS. @@ -1165,9 +1165,6 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %type <ulonglong_number> ulonglong_num real_ulonglong_num size_number -%type <p_elem_value> - part_bit_expr - %type <lock_type> replace_lock_option opt_low_priority insert_lock_option load_data_lock @@ -1300,8 +1297,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); view_check_option trigger_tail sp_tail sf_tail udf_tail event_tail install uninstall partition_entry binlog_base64_event init_key_options key_options key_opts key_opt key_using_alg - part_column_list part_column_expr_list part_column_expr_item - part_column_list_value + part_column_list server_def server_options_list server_option definer_opt no_definer definer END_OF_INPUT @@ -3818,6 +3814,7 @@ part_type_def: { partition_info *part_info= Lex->part_info; part_info->list_of_part_fields= TRUE; + part_info->column_list= FALSE; part_info->part_type= HASH_PARTITION; } | opt_linear HASH_SYM @@ -3869,20 +3866,22 @@ part_field_item: ; part_column_list: - COLUMN_LIST_SYM '(' part_field_list ')' - { - partition_info *part_info= Lex->part_info; - part_info->column_list= TRUE; - part_info->list_of_part_fields= TRUE; - } + COLUMN_LIST_SYM '(' part_field_list ')' + { + partition_info *part_info= Lex->part_info; + part_info->column_list= TRUE; + part_info->list_of_part_fields= TRUE; + } ; part_func: '(' remember_name part_func_expr remember_end ')' { - if (Lex->part_info->set_part_expr($2+1, $3, $4, FALSE)) + partition_info *part_info= Lex->part_info; + if (part_info->set_part_expr($2+1, $3, $4, FALSE)) { MYSQL_YYABORT; } + part_info->column_list= FALSE; } ; @@ -4067,7 +4066,7 @@ opt_part_values: else part_info->part_type= HASH_PARTITION; } - | VALUES LESS_SYM THAN_SYM part_func_max + | VALUES LESS_SYM THAN_SYM { LEX *lex= Lex; partition_info *part_info= lex->part_info; @@ -4083,7 +4082,8 @@ opt_part_values: else part_info->part_type= RANGE_PARTITION; } - | VALUES IN_SYM '(' part_list_func ')' + part_func_max {} + | VALUES IN_SYM { LEX *lex= Lex; partition_info *part_info= lex->part_info; @@ -4099,241 +4099,153 @@ opt_part_values: else part_info->part_type= LIST_PARTITION; } + part_values_in {} ; -part_column_expr_list: - part_column_expr_item {} - | part_column_expr_list ',' part_column_expr_item {} - ; - -part_column_expr_item: +part_func_max: MAX_VALUE_SYM { partition_info *part_info= Lex->part_info; - part_column_list_val *col_val; - if (part_info->part_type == LIST_PARTITION) + + if (part_info->num_columns && + part_info->num_columns != 1U) { - my_parse_error(ER(ER_MAXVALUE_IN_LIST_PARTITIONING_ERROR)); + my_parse_error(ER(ER_PARTITION_COLUMN_LIST_ERROR)); MYSQL_YYABORT; } - if (!(col_val= part_info->add_column_value())) + else + part_info->num_columns= 1U; + if (part_info->init_column_part()) { MYSQL_YYABORT; } - col_val->max_value= TRUE; - } - | bit_expr - { - part_column_list_val *col_val; - LEX *lex= Lex; - if (!lex->safe_to_cache_query) + if (part_info->add_max_value()) { - my_error(ER_NO_CONST_EXPR_IN_RANGE_OR_LIST_ERROR, MYF(0)); MYSQL_YYABORT; } - if (!(col_val= lex->part_info->add_column_value())) - { - MYSQL_YYABORT; - } - col_val->item_expression= $1; - col_val->part_info= NULL; } + | part_value_item {} ; -part_column_list_value: - COLUMN_LIST_SYM +part_values_in: + part_value_item { LEX *lex= Lex; partition_info *part_info= lex->part_info; - uint num_columns; - partition_element *p_elem= part_info->curr_part_elem; - part_column_list_val *col_val_array; - part_elem_value *list_val; - if (!part_info->column_list && - !lex->is_partition_management()) + if (part_info->num_columns != 1U) { - my_error(ER_PARTITION_COLUMN_LIST_ERROR, MYF(0)); - MYSQL_YYABORT; - } - if (!(list_val= - (part_elem_value*)sql_calloc(sizeof(part_elem_value))) || - p_elem->list_val_list.push_back(list_val)) - { - mem_alloc_error(sizeof(part_elem_value)); - MYSQL_YYABORT; - } - if (part_info->num_columns) - num_columns= part_info->num_columns; - else - num_columns= MAX_REF_PARTS; - if (!(col_val_array= - (part_column_list_val*)sql_calloc(num_columns * - sizeof(part_column_list_val)))) - { - mem_alloc_error(num_columns * sizeof(part_elem_value)); - MYSQL_YYABORT; + if (!lex->is_partition_management() || + part_info->num_columns == 0 || + part_info->num_columns > MAX_REF_PARTS) + { + my_parse_error(ER(ER_PARTITION_COLUMN_LIST_ERROR)); + MYSQL_YYABORT; + } + /* + Reorganize the current large array into a list of small + arrays with one entry in each array. This can happen + in the first partition of an ALTER TABLE statement where + we ADD or REORGANIZE partitions. + */ + if (part_info->reorganize_into_single_field_col_val()) + { + MYSQL_YYABORT; + } } - list_val->col_val_array= col_val_array; - part_info->curr_list_val= list_val; - part_info->curr_list_object= 0; } - '(' part_column_expr_list ')' + | '(' part_value_list ')' { partition_info *part_info= Lex->part_info; - uint num_columns= part_info->num_columns; - if (num_columns && num_columns != part_info->curr_list_object) + if (part_info->num_columns < 2U) { - my_error(ER_PARTITION_COLUMN_LIST_ERROR, MYF(0)); + my_parse_error(ER(ER_ROW_SINGLE_PARTITION_FIELD_ERROR)); MYSQL_YYABORT; } - part_info->num_columns= part_info->curr_list_object; } ; -part_func_max: - max_value_sym +part_value_list: + part_value_item {} + | part_value_list ',' part_value_item {} + ; + +part_value_item: + '(' { partition_info *part_info= Lex->part_info; - if (part_info->defined_max_value) - { - my_parse_error(ER(ER_PARTITION_MAXVALUE_ERROR)); - MYSQL_YYABORT; - } - if (part_info->column_list) + /* Initialisation code needed for each list of value expressions */ + if (!(part_info->column_list && + part_info->part_type == LIST_PARTITION && + part_info->num_columns == 1U) && + part_info->init_column_part()) { - my_parse_error(ER(ER_PARTITION_COLUMN_LIST_ERROR)); MYSQL_YYABORT; } - part_info->defined_max_value= TRUE; - part_info->curr_part_elem->max_value= TRUE; - part_info->curr_part_elem->range_value= LONGLONG_MAX; } - | part_range_func + part_value_item_list {} + ')' { + LEX *lex= Lex; partition_info *part_info= Lex->part_info; - if (part_info->defined_max_value) - { - my_parse_error(ER(ER_PARTITION_MAXVALUE_ERROR)); - MYSQL_YYABORT; - } - if (part_info->curr_part_elem->has_null_value) - { - my_parse_error(ER(ER_NULL_IN_VALUES_LESS_THAN)); - MYSQL_YYABORT; - } - if (part_info->column_list) + + if (part_info->num_columns == 0) + part_info->num_columns= part_info->curr_list_object; + if (part_info->num_columns != part_info->curr_list_object) { + /* + All value items lists must be of equal length, in some cases + which is covered by the above if-statement we don't know yet + how many columns is in the partition so the assignment above + ensures that we only report errors when we know we have an + error. + */ my_parse_error(ER(ER_PARTITION_COLUMN_LIST_ERROR)); MYSQL_YYABORT; } - } - | '(' part_column_list_value ')' - {} - ; - -max_value_sym: - MAX_VALUE_SYM - | '(' MAX_VALUE_SYM ')' - ; - -part_range_func: - '(' part_bit_expr ')' - { - partition_info *part_info= Lex->part_info; - if (!($2->unsigned_flag)) - part_info->curr_part_elem->signed_flag= TRUE; - part_info->curr_part_elem->range_value= $2->value; + part_info->curr_list_object= 0; } ; -part_list_func: - part_list_item {} - | part_list_func ',' part_list_item {} +part_value_item_list: + part_value_expr_item {} + | part_value_item_list ',' part_value_expr_item {} ; -part_list_item: - part_bit_expr +part_value_expr_item: + MAX_VALUE_SYM { - part_elem_value *value_ptr= $1; partition_info *part_info= Lex->part_info; - if (!value_ptr->unsigned_flag) - part_info->curr_part_elem->signed_flag= TRUE; - if (!value_ptr->null_value && - part_info->curr_part_elem-> - list_val_list.push_back(value_ptr)) + part_column_list_val *col_val; + if (part_info->part_type == LIST_PARTITION) { - mem_alloc_error(sizeof(part_elem_value)); + my_parse_error(ER(ER_MAXVALUE_IN_LIST_PARTITIONING_ERROR)); MYSQL_YYABORT; } - if (part_info->column_list) + if (part_info->add_max_value()) { - my_parse_error(ER(ER_PARTITION_COLUMN_LIST_ERROR)); MYSQL_YYABORT; } } - | part_column_list_value - ; - -part_bit_expr: - bit_expr + | bit_expr { - Item *part_expr= $1; - THD *thd= YYTHD; - LEX *lex= thd->lex; + LEX *lex= Lex; partition_info *part_info= lex->part_info; - Name_resolution_context *context= &lex->current_select->context; - TABLE_LIST *save_list= context->table_list; - const char *save_where= thd->where; - - context->table_list= 0; - thd->where= "partition function"; + Item *part_expr= $1; - part_elem_value *value_ptr= - (part_elem_value*)sql_alloc(sizeof(part_elem_value)); - if (!value_ptr) - { - mem_alloc_error(sizeof(part_elem_value)); - MYSQL_YYABORT; - } - if (part_expr->walk(&Item::check_partition_func_processor, 0, - NULL)) - { - my_error(ER_PARTITION_FUNCTION_IS_NOT_ALLOWED, MYF(0)); - MYSQL_YYABORT; - } - if (part_expr->fix_fields(YYTHD, (Item**)0) || - ((context->table_list= save_list), FALSE) || - (!part_expr->const_item()) || - (!lex->safe_to_cache_query)) + if (!lex->safe_to_cache_query) { my_error(ER_NO_CONST_EXPR_IN_RANGE_OR_LIST_ERROR, MYF(0)); MYSQL_YYABORT; } - thd->where= save_where; - value_ptr->value= part_expr->val_int(); - value_ptr->unsigned_flag= TRUE; - if (!part_expr->unsigned_flag && - value_ptr->value < 0) - value_ptr->unsigned_flag= FALSE; - if ((value_ptr->null_value= part_expr->null_value)) + if (part_info->add_column_list_value(part_expr)) { - if (part_info->curr_part_elem->has_null_value) - { - my_error(ER_MULTIPLE_DEF_CONST_IN_LIST_PART_ERROR, MYF(0)); - MYSQL_YYABORT; - } - part_info->curr_part_elem->has_null_value= TRUE; - } - else if (part_expr->result_type() != INT_RESULT) - { - my_parse_error(ER(ER_INCONSISTENT_TYPE_OF_FUNCTIONS_ERROR)); MYSQL_YYABORT; } - $$= value_ptr; } ; + opt_sub_partition: /* empty */ { |