diff options
Diffstat (limited to 'sql')
37 files changed, 684 insertions, 333 deletions
diff --git a/sql/client_settings.h b/sql/client_settings.h index f0742cd8046..4f06c15a29e 100644 --- a/sql/client_settings.h +++ b/sql/client_settings.h @@ -33,3 +33,11 @@ #define mysql_server_init(a,b,c) 0 +#ifdef HAVE_REPLICATION +C_MODE_START +void slave_io_thread_detach_vio(); +C_MODE_END +#else +#define slave_io_thread_detach_vio() +#endif + diff --git a/sql/events.cc b/sql/events.cc index c4c00e09b4a..026d096e2a3 100644 --- a/sql/events.cc +++ b/sql/events.cc @@ -341,6 +341,33 @@ common_1_lev_code: /** + Create a new query string for removing executable comments + for avoiding leak and keeping consistency of the execution + on master and slave. + + @param[in] thd Thread handler + @param[in] buf Query string + + @return + 0 ok + 1 error +*/ +static int +create_query_string(THD *thd, String *buf) +{ + /* Append the "CREATE" part of the query */ + if (buf->append(STRING_WITH_LEN("CREATE "))) + return 1; + /* Append definer */ + append_definer(thd, buf, &(thd->lex->definer->user), &(thd->lex->definer->host)); + /* Append the left part of thd->query after "DEFINER" part */ + if (buf->append(thd->lex->stmt_definition_begin)) + return 1; + + return 0; +} + +/** Create a new event. @param[in,out] thd THD @@ -438,7 +465,16 @@ Events::create_event(THD *thd, Event_parse_data *parse_data, { /* Binlog the create event. */ DBUG_ASSERT(thd->query && thd->query_length); - write_bin_log(thd, TRUE, thd->query, thd->query_length); + String log_query; + if (create_query_string(thd, &log_query)) + { + sql_print_error("Event Error: An error occurred while creating query string, " + "before writing it into binary log."); + DBUG_RETURN(TRUE); + } + /* If the definer is not set or set to CURRENT_USER, the value of CURRENT_USER + will be written into the binary log as the definer for the SQL thread. */ + write_bin_log(thd, TRUE, log_query.c_ptr(), log_query.length()); } } pthread_mutex_unlock(&LOCK_event_metadata); diff --git a/sql/field.cc b/sql/field.cc index 5bce6a412fc..d1202657786 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -1923,16 +1923,16 @@ int Field_decimal::store(const char *from_arg, uint len, CHARSET_INFO *cs) Pointers used when digits move from the left of the '.' to the right of the '.' (explained below) */ - const uchar *int_digits_tail_from; + const uchar *UNINIT_VAR(int_digits_tail_from); /* Number of 0 that need to be added at the left of the '.' (1E3: 3 zeros) */ - uint int_digits_added_zeros; + uint UNINIT_VAR(int_digits_added_zeros); /* Pointer used when digits move from the right of the '.' to the left of the '.' */ - const uchar *frac_digits_head_end; + const uchar *UNINIT_VAR(frac_digits_head_end); /* Number of 0 that need to be added at the right of the '.' (for 1E-3) */ - uint frac_digits_added_zeros; + uint UNINIT_VAR(frac_digits_added_zeros); uchar *pos,*tmp_left_pos,*tmp_right_pos; /* Pointers that are used as limits (begin and end of the field buffer) */ uchar *left_wall,*right_wall; @@ -1943,11 +1943,6 @@ int Field_decimal::store(const char *from_arg, uint len, CHARSET_INFO *cs) */ bool is_cuted_fields_incr=0; - LINT_INIT(int_digits_tail_from); - LINT_INIT(int_digits_added_zeros); - LINT_INIT(frac_digits_head_end); - LINT_INIT(frac_digits_added_zeros); - /* There are three steps in this function : - parse the input string @@ -2486,12 +2481,97 @@ Field_new_decimal::Field_new_decimal(uint32 len_arg, { precision= my_decimal_length_to_precision(len_arg, dec_arg, unsigned_arg); set_if_smaller(precision, DECIMAL_MAX_PRECISION); + DBUG_ASSERT(precision >= dec); DBUG_ASSERT((precision <= DECIMAL_MAX_PRECISION) && (dec <= DECIMAL_MAX_SCALE)); bin_size= my_decimal_get_binary_size(precision, dec); } +/** + Create a field to hold a decimal value from an item. + + @remark The MySQL DECIMAL data type has a characteristic that needs to be + taken into account when deducing the type from a Item_decimal. + + But first, let's briefly recap what is the new MySQL DECIMAL type: + + The declaration syntax for a decimal is DECIMAL(M,D), where: + + * M is the maximum number of digits (the precision). + It has a range of 1 to 65. + * D is the number of digits to the right of the decimal separator (the scale). + It has a range of 0 to 30 and must be no larger than M. + + D and M are used to determine the storage requirements for the integer + and fractional parts of each value. The integer part is to the left of + the decimal separator and to the right is the fractional part. Hence: + + M is the number of digits for the integer and fractional part. + D is the number of digits for the fractional part. + + Consequently, M - D is the number of digits for the integer part. For + example, a DECIMAL(20,10) column has ten digits on either side of + the decimal separator. + + The characteristic that needs to be taken into account is that the + backing type for Item_decimal is a my_decimal that has a higher + precision (DECIMAL_MAX_POSSIBLE_PRECISION, see my_decimal.h) than + DECIMAL. + + Drawing a comparison between my_decimal and DECIMAL: + + * M has a range of 1 to 81. + * D has a range of 0 to 81. + + There can be a difference in range if the decimal contains a integer + part. This is because the fractional part must always be on a group + boundary, leaving at least one group for the integer part. Since each + group is 9 (DIG_PER_DEC1) digits and there are 9 (DECIMAL_BUFF_LENGTH) + groups, the fractional part is limited to 72 digits if there is at + least one digit in the integral part. + + Although the backing type for a DECIMAL is also my_decimal, every + time a my_decimal is stored in a DECIMAL field, the precision and + scale are explicitly capped at 65 (DECIMAL_MAX_PRECISION) and 30 + (DECIMAL_MAX_SCALE) digits, following my_decimal truncation procedure + (FIX_INTG_FRAC_ERROR). +*/ + +Field_new_decimal * +Field_new_decimal::new_decimal_field(const Item *item) +{ + uint32 len; + uint intg= item->decimal_int_part(), scale= item->decimals; + + DBUG_ASSERT(item->decimal_precision() >= item->decimals); + + /* + Employ a procedure along the lines of the my_decimal truncation process: + - If the integer part is equal to or bigger than the maximum precision: + Truncate integer part to fit and the fractional becomes zero. + - Otherwise: + Truncate fractional part to fit. + */ + if (intg >= DECIMAL_MAX_PRECISION) + { + intg= DECIMAL_MAX_PRECISION; + scale= 0; + } + else + { + uint room= min(DECIMAL_MAX_PRECISION - intg, DECIMAL_MAX_SCALE); + if (scale > room) + scale= room; + } + + len= my_decimal_precision_to_length(intg + scale, scale, item->unsigned_flag); + + return new Field_new_decimal(len, item->maybe_null, item->name, scale, + item->unsigned_flag); +} + + int Field_new_decimal::reset(void) { store_value(&decimal_zero); @@ -9923,10 +10003,8 @@ Field *make_field(TABLE_SHARE *share, uchar *ptr, uint32 field_length, TYPELIB *interval, const char *field_name) { - uchar *bit_ptr; - uchar bit_offset; - LINT_INIT(bit_ptr); - LINT_INIT(bit_offset); + uchar *UNINIT_VAR(bit_ptr); + uchar UNINIT_VAR(bit_offset); if (field_type == MYSQL_TYPE_BIT && !f_bit_as_char(pack_flag)) { bit_ptr= null_pos; diff --git a/sql/field.h b/sql/field.h index ac8e7dae3c5..5ac1b35fd81 100644 --- a/sql/field.h +++ b/sql/field.h @@ -608,6 +608,10 @@ protected: class Field_num :public Field { public: + /** + The scale of the Field's value, i.e. the number of digits to the right + of the decimal point. + */ const uint8 dec; bool zerofill,unsigned_flag; // Purify cannot handle bit fields Field_num(uchar *ptr_arg,uint32 len_arg, uchar *null_ptr_arg, @@ -766,6 +770,11 @@ public: Field_new_decimal(uint32 len_arg, bool maybe_null_arg, const char *field_name_arg, uint8 dec_arg, bool unsigned_arg); + /* + Create a field to hold a decimal value from an item. + Truncates the precision and/or scale if necessary. + */ + static Field_new_decimal *new_decimal_field(const Item *item); enum_field_types type() const { return MYSQL_TYPE_NEWDECIMAL;} enum ha_base_keytype key_type() const { return HA_KEYTYPE_BINARY; } Item_result result_type () const { return DECIMAL_RESULT; } diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index 10e011ec06f..b1df1f27623 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -4415,17 +4415,6 @@ int ha_partition::handle_unordered_scan_next_partition(uchar * buf) break; case partition_index_first: DBUG_PRINT("info", ("index_first on partition %d", i)); - /* MyISAM engine can fail if we call index_first() when indexes disabled */ - /* that happens if the table is empty. */ - /* Here we use file->stats.records instead of file->records() because */ - /* file->records() is supposed to return an EXACT count, and it can be */ - /* possibly slow. We don't need an exact number, an approximate one- from*/ - /* the last ::info() call - is sufficient. */ - if (file->stats.records == 0) - { - error= HA_ERR_END_OF_FILE; - break; - } error= file->index_first(buf); break; case partition_index_first_unordered: @@ -4513,32 +4502,10 @@ int ha_partition::handle_ordered_index_scan(uchar *buf, bool reverse_order) m_start_key.flag); break; case partition_index_first: - /* MyISAM engine can fail if we call index_first() when indexes disabled */ - /* that happens if the table is empty. */ - /* Here we use file->stats.records instead of file->records() because */ - /* file->records() is supposed to return an EXACT count, and it can be */ - /* possibly slow. We don't need an exact number, an approximate one- from*/ - /* the last ::info() call - is sufficient. */ - if (file->stats.records == 0) - { - error= HA_ERR_END_OF_FILE; - break; - } error= file->index_first(rec_buf_ptr); reverse_order= FALSE; break; case partition_index_last: - /* MyISAM engine can fail if we call index_last() when indexes disabled */ - /* that happens if the table is empty. */ - /* Here we use file->stats.records instead of file->records() because */ - /* file->records() is supposed to return an EXACT count, and it can be */ - /* possibly slow. We don't need an exact number, an approximate one- from*/ - /* the last ::info() call - is sufficient. */ - if (file->stats.records == 0) - { - error= HA_ERR_END_OF_FILE; - break; - } error= file->index_last(rec_buf_ptr); reverse_order= TRUE; break; diff --git a/sql/item.cc b/sql/item.cc index b2ab28a77fd..b6e8c5dac0b 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -433,17 +433,26 @@ Item::Item(THD *thd, Item *item): } +/** + Decimal precision of the item. + + @remark The precision must not be capped as it can be used in conjunction + with Item::decimals to determine the size of the integer part when + constructing a decimal data type. + + @see Item::decimal_int_part() + @see Item::decimals +*/ + uint Item::decimal_precision() const { + uint precision= max_length; Item_result restype= result_type(); if ((restype == DECIMAL_RESULT) || (restype == INT_RESULT)) - { - uint prec= - my_decimal_length_to_precision(max_length, decimals, unsigned_flag); - return min(prec, DECIMAL_MAX_PRECISION); - } - return min(max_length, DECIMAL_MAX_PRECISION); + precision= my_decimal_length_to_precision(max_length, decimals, unsigned_flag); + + return precision; } @@ -1664,7 +1673,7 @@ bool agg_item_collations_for_comparison(DTCollation &c, const char *fname, bool agg_item_set_converter(DTCollation &coll, const char *fname, Item **args, uint nargs, uint flags, int item_sep) { - Item **arg, *safe_args[2]; + Item **arg, *safe_args[2]= {NULL, NULL}; /* For better error reporting: save the first and the second argument. @@ -1673,8 +1682,6 @@ bool agg_item_set_converter(DTCollation &coll, const char *fname, doesn't display each argument's characteristics. - if nargs is 1, then this error cannot happen. */ - LINT_INIT(safe_args[0]); - LINT_INIT(safe_args[1]); if (nargs >=2 && nargs <= 3) { safe_args[0]= args[0]; @@ -3305,8 +3312,7 @@ Item_copy *Item_copy::create (Item *item) new Item_copy_uint (item) : new Item_copy_int (item); case DECIMAL_RESULT: return new Item_copy_decimal (item); - case IMPOSSIBLE_RESULT: - case ROW_RESULT: + default: DBUG_ASSERT (0); } /* should not happen */ @@ -4911,9 +4917,7 @@ Field *Item::tmp_table_field_from_field_type(TABLE *table, bool fixed_length) switch (field_type()) { case MYSQL_TYPE_DECIMAL: case MYSQL_TYPE_NEWDECIMAL: - field= new Field_new_decimal((uchar*) 0, max_length, null_ptr, 0, - Field::NONE, name, decimals, 0, - unsigned_flag); + field= Field_new_decimal::new_decimal_field(this); break; case MYSQL_TYPE_TINY: field= new Field_tiny((uchar*) 0, max_length, null_ptr, 0, Field::NONE, @@ -5510,9 +5514,8 @@ bool Item_null::send(Protocol *protocol, String *packet) bool Item::send(Protocol *protocol, String *buffer) { - bool result; + bool UNINIT_VAR(result); // Will be set if null_value == 0 enum_field_types f_type; - LINT_INIT(result); // Will be set if null_value == 0 switch ((f_type=field_type())) { default: @@ -6855,14 +6858,21 @@ void resolve_const_item(THD *thd, Item **ref, Item *comp_item) } /** - Return true if the value stored in the field is equal to the const - item. + Compare the value stored in field, with the original item. + + @param field field which the item is converted and stored in + @param item original item - We need to use this on the range optimizer because in some cases - we can't store the value in the field without some precision/character loss. + @return Return an integer greater than, equal to, or less than 0 if + the value stored in the field is greater than, equal to, + or less than the original item + + @note We only use this on the range optimizer/partition pruning, + because in some cases we can't store the value in the field + without some precision/character loss. */ -bool field_is_equal_to_item(Field *field,Item *item) +int stored_field_cmp_to_item(Field *field, Item *item) { Item_result res_type=item_cmp_type(field->result_type(), @@ -6873,28 +6883,49 @@ bool field_is_equal_to_item(Field *field,Item *item) char field_buff[MAX_FIELD_WIDTH]; String item_tmp(item_buff,sizeof(item_buff),&my_charset_bin),*item_result; String field_tmp(field_buff,sizeof(field_buff),&my_charset_bin); + enum_field_types field_type; item_result=item->val_str(&item_tmp); if (item->null_value) - return 1; // This must be true + return 0; field->val_str(&field_tmp); - return !stringcmp(&field_tmp,item_result); + + /* + If comparing DATE with DATETIME, append the time-part to the DATE. + So that the strings are equally formatted. + A DATE converted to string is 10 characters, and a DATETIME converted + to string is 19 characters. + */ + field_type= field->type(); + if (field_type == MYSQL_TYPE_DATE && + item_result->length() == 19) + field_tmp.append(" 00:00:00"); + else if (field_type == MYSQL_TYPE_DATETIME && + item_result->length() == 10) + item_result->append(" 00:00:00"); + + return stringcmp(&field_tmp,item_result); } if (res_type == INT_RESULT) - return 1; // Both where of type int + return 0; // Both are of type int if (res_type == DECIMAL_RESULT) { my_decimal item_buf, *item_val, field_buf, *field_val; item_val= item->val_decimal(&item_buf); if (item->null_value) - return 1; // This must be true + return 0; field_val= field->val_decimal(&field_buf); - return !my_decimal_cmp(item_val, field_val); + return my_decimal_cmp(item_val, field_val); } double result= item->val_real(); if (item->null_value) + return 0; + double field_result= field->val_real(); + if (field_result < result) + return -1; + else if (field_result > result) return 1; - return result == field->val_real(); + return 0; } Item_cache* Item_cache::get_cache(const Item *item) diff --git a/sql/item.h b/sql/item.h index 74c4ca701f7..84a359e8cd1 100644 --- a/sql/item.h +++ b/sql/item.h @@ -397,13 +397,20 @@ public: from INT_RESULT, may be NULL, or are unsigned. It will be possible to address this issue once the related partitioning bugs (BUG#16002, BUG#15447, BUG#13436) are fixed. + + The NOT_NULL enums are used in TO_DAYS, since TO_DAYS('2001-00-00') returns + NULL which puts those rows into the NULL partition, but + '2000-12-31' < '2001-00-00' < '2001-01-01'. So special handling is needed + for this (see Bug#20577). */ typedef enum monotonicity_info { NON_MONOTONIC, /* none of the below holds */ MONOTONIC_INCREASING, /* F() is unary and (x < y) => (F(x) <= F(y)) */ - MONOTONIC_STRICT_INCREASING /* F() is unary and (x < y) => (F(x) < F(y)) */ + MONOTONIC_INCREASING_NOT_NULL, /* But only for valid/real x and y */ + MONOTONIC_STRICT_INCREASING,/* F() is unary and (x < y) => (F(x) < F(y)) */ + MONOTONIC_STRICT_INCREASING_NOT_NULL /* But only for valid/real x and y */ } enum_monotonicity_info; /*************************************************************************/ @@ -576,8 +583,8 @@ public: left_endp FALSE <=> The interval is "x < const" or "x <= const" TRUE <=> The interval is "x > const" or "x >= const" - incl_endp IN TRUE <=> the comparison is '<' or '>' - FALSE <=> the comparison is '<=' or '>=' + incl_endp IN FALSE <=> the comparison is '<' or '>' + TRUE <=> the comparison is '<=' or '>=' OUT The same but for the "F(x) $CMP$ F(const)" comparison DESCRIPTION @@ -759,9 +766,10 @@ public: virtual cond_result eq_cmp_result() const { return COND_OK; } inline uint float_length(uint decimals_par) const { return decimals != NOT_FIXED_DEC ? (DBL_DIG+2+decimals_par) : DBL_DIG+8;} + /** Returns the uncapped decimal precision of this item. */ virtual uint decimal_precision() const; inline int decimal_int_part() const - { return my_decimal_int_part(decimal_precision(), decimals); } + { return decimal_precision() - decimals; } /* Returns true if this is constant (during query execution, i.e. its value will not change until next fix_fields) and its value is known. @@ -3152,4 +3160,4 @@ void mark_select_range_as_dependent(THD *thd, extern Cached_item *new_Cached_item(THD *thd, Item *item); extern Item_result item_cmp_type(Item_result a,Item_result b); extern void resolve_const_item(THD *thd, Item **ref, Item *cmp_item); -extern bool field_is_equal_to_item(Field *field,Item *item); +extern int stored_field_cmp_to_item(Field *field, Item *item); diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index b2e7be5ef09..d351fe7d7dc 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -395,11 +395,10 @@ static bool convert_constant_item(THD *thd, Item_field *field_item, ulong orig_sql_mode= thd->variables.sql_mode; enum_check_fields orig_count_cuted_fields= thd->count_cuted_fields; my_bitmap_map *old_maps[2]; - ulonglong orig_field_val; /* original field value if valid */ + ulonglong UNINIT_VAR(orig_field_val); /* original field value if valid */ LINT_INIT(old_maps[0]); LINT_INIT(old_maps[1]); - LINT_INIT(orig_field_val); if (table) dbug_tmp_use_all_columns(table, old_maps, @@ -2182,7 +2181,7 @@ uint Item_func_ifnull::decimal_precision() const int arg1_int_part= args[1]->decimal_int_part(); int max_int_part= max(arg0_int_part, arg1_int_part); int precision= max_int_part + decimals; - return min(precision, DECIMAL_MAX_PRECISION); + return precision; } @@ -2366,7 +2365,7 @@ uint Item_func_if::decimal_precision() const int arg1_prec= args[1]->decimal_int_part(); int arg2_prec= args[2]->decimal_int_part(); int precision=max(arg1_prec,arg2_prec) + decimals; - return min(precision, DECIMAL_MAX_PRECISION); + return precision; } @@ -2783,7 +2782,7 @@ uint Item_func_case::decimal_precision() const if (else_expr_num != -1) set_if_bigger(max_int_part, args[else_expr_num]->decimal_int_part()); - return min(max_int_part + decimals, DECIMAL_MAX_PRECISION); + return max_int_part + decimals; } diff --git a/sql/item_create.cc b/sql/item_create.cc index 35c757309e5..255c692e4cb 100644 --- a/sql/item_create.cc +++ b/sql/item_create.cc @@ -5032,10 +5032,9 @@ create_func_cast(THD *thd, Item *a, Cast_target cast_type, const char *c_len, const char *c_dec, CHARSET_INFO *cs) { - Item *res; + Item *UNINIT_VAR(res); ulong len; uint dec; - LINT_INIT(res); switch (cast_type) { case ITEM_CAST_BINARY: diff --git a/sql/item_func.cc b/sql/item_func.cc index 7aa455b1b4a..d2b1634ba5e 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -451,45 +451,8 @@ Field *Item_func::tmp_table_field(TABLE *table) case STRING_RESULT: return make_string_field(table); case DECIMAL_RESULT: - { - uint8 dec= decimals; - uint8 intg= decimal_precision() - dec; - uint32 len= max_length; - - /* - Trying to put too many digits overall in a DECIMAL(prec,dec) - will always throw a warning. We must limit dec to - DECIMAL_MAX_SCALE however to prevent an assert() later. - */ - - if (dec > 0) - { - int overflow; - - dec= min(dec, DECIMAL_MAX_SCALE); - - /* - If the value still overflows the field with the corrected dec, - we'll throw out decimals rather than integers. This is still - bad and of course throws a truncation warning. - */ - - const int required_length= - my_decimal_precision_to_length(intg + dec, dec, - unsigned_flag); - - overflow= required_length - len; - - if (overflow > 0) - dec= max(0, dec - overflow); // too long, discard fract - else - /* Corrected value fits. */ - len= required_length; - } - - field= new Field_new_decimal(len, maybe_null, name, dec, unsigned_flag); + field= Field_new_decimal::new_decimal_field(this); break; - } case ROW_RESULT: default: // This case should never be chosen @@ -2304,9 +2267,8 @@ void Item_func_min_max::fix_length_and_dec() uint Item_func_min_max::cmp_datetimes(ulonglong *value) { - longlong min_max; + longlong UNINIT_VAR(min_max); uint min_max_idx= 0; - LINT_INIT(min_max); for (uint i=0; i < arg_count ; i++) { @@ -2371,8 +2333,7 @@ String *Item_func_min_max::val_str(String *str) } case STRING_RESULT: { - String *res; - LINT_INIT(res); + String *UNINIT_VAR(res); for (uint i=0; i < arg_count ; i++) { if (i == 0) @@ -2461,8 +2422,7 @@ longlong Item_func_min_max::val_int() my_decimal *Item_func_min_max::val_decimal(my_decimal *dec) { DBUG_ASSERT(fixed == 1); - my_decimal tmp_buf, *tmp, *res; - LINT_INIT(res); + my_decimal tmp_buf, *tmp, *UNINIT_VAR(res); if (compare_as_dates) { @@ -4784,6 +4744,19 @@ void Item_func_get_user_var::fix_length_and_dec() } +uint Item_func_get_user_var::decimal_precision() const +{ + uint precision= max_length; + Item_result restype= result_type(); + + /* Default to maximum as the precision is unknown a priori. */ + if ((restype == DECIMAL_RESULT) || (restype == INT_RESULT)) + precision= DECIMAL_MAX_PRECISION; + + return precision; +} + + bool Item_func_get_user_var::const_item() const { return (!var_entry || current_thd->query_id != var_entry->update_query_id); @@ -5447,8 +5420,7 @@ void Item_func_match::init_search(bool no_order) bool Item_func_match::fix_fields(THD *thd, Item **ref) { DBUG_ASSERT(fixed == 0); - Item *item; - LINT_INIT(item); // Safe as arg_count is > 1 + Item *UNINIT_VAR(item); // Safe as arg_count is > 1 maybe_null=1; join_key=0; diff --git a/sql/item_func.h b/sql/item_func.h index eee3a7ef0f6..2e00ac99429 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -1393,6 +1393,7 @@ public: table_map used_tables() const { return const_item() ? 0 : RAND_TABLE_BIT; } bool eq(const Item *item, bool binary_cmp) const; + uint decimal_precision() const; private: bool set_value(THD *thd, sp_rcontext *ctx, Item **it); diff --git a/sql/item_sum.cc b/sql/item_sum.cc index ab2da503209..ff70c2aedfc 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -517,8 +517,7 @@ Field *Item_sum::create_tmp_field(bool group, TABLE *table, name, table->s, collation.collation); break; case DECIMAL_RESULT: - field= new Field_new_decimal(max_length, maybe_null, name, - decimals, unsigned_flag); + field= Field_new_decimal::new_decimal_field(this); break; case ROW_RESULT: default: diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index c313c3338d1..33a00cdd8c0 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -961,9 +961,9 @@ enum_monotonicity_info Item_func_to_days::get_monotonicity_info() const if (args[0]->type() == Item::FIELD_ITEM) { if (args[0]->field_type() == MYSQL_TYPE_DATE) - return MONOTONIC_STRICT_INCREASING; + return MONOTONIC_STRICT_INCREASING_NOT_NULL; if (args[0]->field_type() == MYSQL_TYPE_DATETIME) - return MONOTONIC_INCREASING; + return MONOTONIC_INCREASING_NOT_NULL; } return NON_MONOTONIC; } @@ -974,12 +974,27 @@ longlong Item_func_to_days::val_int_endpoint(bool left_endp, bool *incl_endp) DBUG_ASSERT(fixed == 1); MYSQL_TIME ltime; longlong res; - if (get_arg0_date(<ime, TIME_NO_ZERO_DATE)) + int dummy; /* unused */ + if (get_arg0_date(<ime, TIME_FUZZY_DATE)) { /* got NULL, leave the incl_endp intact */ return LONGLONG_MIN; } res=(longlong) calc_daynr(ltime.year,ltime.month,ltime.day); + /* Set to NULL if invalid date, but keep the value */ + null_value= check_date(<ime, + (ltime.year || ltime.month || ltime.day), + (TIME_NO_ZERO_IN_DATE | TIME_NO_ZERO_DATE), + &dummy); + if (null_value) + { + /* + Even if the evaluation return NULL, the calc_daynr is useful for pruning + */ + if (args[0]->field_type() != MYSQL_TYPE_DATE) + *incl_endp= TRUE; + return res; + } if (args[0]->field_type() == MYSQL_TYPE_DATE) { @@ -992,15 +1007,19 @@ longlong Item_func_to_days::val_int_endpoint(bool left_endp, bool *incl_endp) point to day bound ("strictly less" comparison stays intact): col < '2007-09-15 00:00:00' -> TO_DAYS(col) < TO_DAYS('2007-09-15') + col > '2007-09-15 23:59:59' -> TO_DAYS(col) > TO_DAYS('2007-09-15') which is different from the general case ("strictly less" changes to "less or equal"): col < '2007-09-15 12:34:56' -> TO_DAYS(col) <= TO_DAYS('2007-09-15') */ - if (!left_endp && !(ltime.hour || ltime.minute || ltime.second || - ltime.second_part)) - ; /* do nothing */ + if ((!left_endp && !(ltime.hour || ltime.minute || ltime.second || + ltime.second_part)) || + (left_endp && ltime.hour == 23 && ltime.minute == 59 && + ltime.second == 59)) + /* do nothing */ + ; else *incl_endp= TRUE; return res; diff --git a/sql/lock.cc b/sql/lock.cc index e75186d276e..d0076a49232 100644 --- a/sql/lock.cc +++ b/sql/lock.cc @@ -1472,11 +1472,10 @@ void unlock_global_read_lock(THD *thd) bool wait_if_global_read_lock(THD *thd, bool abort_on_refresh, bool is_not_commit) { - const char *old_message; + const char *UNINIT_VAR(old_message); bool result= 0, need_exit_cond; DBUG_ENTER("wait_if_global_read_lock"); - LINT_INIT(old_message); /* Assert that we do not own LOCK_open. If we would own it, other threads could not close their tables. This would make a pretty diff --git a/sql/log.cc b/sql/log.cc index ea71e6caefd..0d80812fe61 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -1275,6 +1275,25 @@ int LOGGER::set_handlers(uint error_log_printer, return 0; } +/** + This function checks if a transactional talbe was updated by the + current statement. + + @param thd The client thread that executed the current statement. + @return + @c true if a transactional table was updated, @false otherwise. +*/ +static bool stmt_has_updated_trans_table(THD *thd) +{ + Ha_trx_info *ha_info; + + for (ha_info= thd->transaction.stmt.ha_list; ha_info; ha_info= ha_info->next()) + { + if (ha_info->is_trx_read_write() && ha_info->ht() != binlog_hton) + return (TRUE); + } + return (FALSE); +} /* Save position of binary log transaction cache. @@ -4104,7 +4123,8 @@ bool MYSQL_BIN_LOG::write(Log_event *event_info) (binlog_trx_data*) thd_get_ha_data(thd, binlog_hton); IO_CACHE *trans_log= &trx_data->trans_log; my_off_t trans_log_pos= my_b_tell(trans_log); - if (event_info->get_cache_stmt() || trans_log_pos != 0) + if (event_info->get_cache_stmt() || trans_log_pos != 0 || + stmt_has_updated_trans_table(thd)) { DBUG_PRINT("info", ("Using trans_log: cache: %d, trans_log_pos: %lu", event_info->get_cache_stmt(), @@ -4855,7 +4875,8 @@ bool flush_error_log() my_rename(log_error_file,err_renamed,MYF(0)); if (freopen(log_error_file,"a+",stdout)) { - freopen(log_error_file,"a+",stderr); + FILE *reopen; + reopen= freopen(log_error_file,"a+",stderr); setbuf(stderr, NULL); } else diff --git a/sql/log_event.cc b/sql/log_event.cc index f33ee8310cf..6aa5365a708 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -2948,6 +2948,8 @@ int Query_log_event::do_apply_event(Relay_log_info const *rli, { LEX_STRING new_db; int expected_error,actual_error= 0; + HA_CREATE_INFO db_options; + /* Colleagues: please never free(thd->catalog) in MySQL. This would lead to bugs as here thd->catalog is a part of an alloced block, @@ -2959,6 +2961,13 @@ int Query_log_event::do_apply_event(Relay_log_info const *rli, new_db.length= db_len; new_db.str= (char *) rpl_filter->get_rewrite_db(db, &new_db.length); thd->set_db(new_db.str, new_db.length); /* allocates a copy of 'db' */ + + /* + Setting the character set and collation of the current database thd->db. + */ + load_db_opt_by_name(thd, thd->db, &db_options); + if (db_options.default_table_charset) + thd->db_charset= db_options.default_table_charset; thd->variables.auto_increment_increment= auto_increment_increment; thd->variables.auto_increment_offset= auto_increment_offset; @@ -3159,7 +3168,7 @@ compare_errors: /* If we expected a non-zero error code, and we don't get the same error - code, and none of them should be ignored. + code, and it should be ignored or is related to a concurrency issue. */ actual_error= thd->is_error() ? thd->main_da.sql_errno() : 0; DBUG_PRINT("info",("expected_error: %d sql_errno: %d", @@ -3182,7 +3191,8 @@ Default database: '%s'. Query: '%s'", thd->is_slave_error= 1; } /* - If we get the same error code as expected, or they should be ignored. + If we get the same error code as expected and it is not a concurrency + issue, or should be ignored. */ else if ((expected_error == actual_error && !concurrency_error_code(expected_error)) || @@ -3191,8 +3201,25 @@ Default database: '%s'. Query: '%s'", DBUG_PRINT("info",("error ignored")); clear_all_errors(thd, const_cast<Relay_log_info*>(rli)); thd->killed= THD::NOT_KILLED; + /* + When an error is expected and matches the actual error the + slave does not report any error and by consequence changes + on transactional tables are not rolled back in the function + close_thread_tables(). For that reason, we explicitly roll + them back here. + */ + if (expected_error && expected_error == actual_error) + ha_autocommit_or_rollback(thd, TRUE); } /* + If we expected a non-zero error code and get nothing and, it is a concurrency + issue or should be ignored. + */ + else if (expected_error && !actual_error && + (concurrency_error_code(expected_error) || + ignored_error_code(expected_error))) + ha_autocommit_or_rollback(thd, TRUE); + /* Other cases: mostly we expected no error and get one. */ else if (thd->is_slave_error || thd->is_fatal_error) diff --git a/sql/my_decimal.h b/sql/my_decimal.h index d736bad9a4b..d991dd1c54c 100644 --- a/sql/my_decimal.h +++ b/sql/my_decimal.h @@ -48,10 +48,12 @@ C_MODE_END digits * number of decimal digits in one our big digit - number of decimal digits in one our big digit decreased by 1 (because we always put decimal point on the border of our big digits)) + + This value is 65 due to historical reasons partly due to it being used + as the maximum allowed precision and not the actual maximum precision. */ #define DECIMAL_MAX_PRECISION (DECIMAL_MAX_POSSIBLE_PRECISION - 8*2) #define DECIMAL_MAX_SCALE 30 -#define DECIMAL_NOT_SPECIFIED 31 /** maximum length of string representation (number of maximum decimal @@ -75,12 +77,6 @@ inline uint my_decimal_size(uint precision, uint scale) } -inline int my_decimal_int_part(uint precision, uint decimals) -{ - return precision - ((decimals == DECIMAL_NOT_SPECIFIED) ? 0 : decimals); -} - - /** my_decimal class limits 'decimal_t' type to what we need in MySQL. @@ -184,7 +180,7 @@ inline uint my_decimal_length_to_precision(uint length, uint scale, } inline uint32 my_decimal_precision_to_length_no_truncation(uint precision, - uint8 scale, + uint scale, bool unsigned_flag) { /* @@ -196,7 +192,7 @@ inline uint32 my_decimal_precision_to_length_no_truncation(uint precision, (unsigned_flag || !precision ? 0 : 1)); } -inline uint32 my_decimal_precision_to_length(uint precision, uint8 scale, +inline uint32 my_decimal_precision_to_length(uint precision, uint scale, bool unsigned_flag) { /* diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 63d5621742e..b234b2f31b2 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -2304,7 +2304,8 @@ enum enum_explain_filename_mode { EXPLAIN_ALL_VERBOSE= 0, EXPLAIN_PARTITIONS_VERBOSE, - EXPLAIN_PARTITIONS_AS_COMMENT + EXPLAIN_PARTITIONS_AS_COMMENT, + EXPLAIN_PARTITIONS_AS_COMMENT_NO_QUOTING }; uint explain_filename(const char *from, char *to, uint to_length, enum_explain_filename_mode explain_mode); diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 0d7d7253f08..9c0929671a1 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -2243,7 +2243,7 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use, KEY *key_info; PARAM param; - if (check_stack_overrun(thd, 2*STACK_MIN_SIZE, buff)) + if (check_stack_overrun(thd, 2*STACK_MIN_SIZE + sizeof(PARAM), buff)) DBUG_RETURN(0); // Fatal error flag is set /* set up parameter that is passed to all functions */ @@ -4839,11 +4839,10 @@ static TRP_RANGE *get_key_scans_params(PARAM *param, SEL_TREE *tree, { int idx; SEL_ARG **key,**end, **key_to_read= NULL; - ha_rows best_records; + ha_rows UNINIT_VAR(best_records); /* protected by key_to_read */ TRP_RANGE* read_plan= NULL; bool pk_is_clustered= param->table->file->primary_key_is_clustered(); DBUG_ENTER("get_key_scans_params"); - LINT_INIT(best_records); /* protected by key_to_read */ /* Note that there may be trees that have type SEL_TREE::KEY but contain no key reads at all, e.g. tree for expression "key1 is not null" where key1 @@ -5827,6 +5826,7 @@ get_mm_leaf(RANGE_OPT_PARAM *param, COND *conf_func, Field *field, { tree= new (alloc) SEL_ARG(field, 0, 0); tree->type= SEL_ARG::IMPOSSIBLE; + field->table->in_use->variables.sql_mode= orig_sql_mode; goto end; } else @@ -5856,11 +5856,14 @@ get_mm_leaf(RANGE_OPT_PARAM *param, COND *conf_func, Field *field, but we'll need to convert '>' to '>=' and '<' to '<='. This will be done together with other types at the end of this function - (grep for field_is_equal_to_item) + (grep for stored_field_cmp_to_item) */ } else + { + field->table->in_use->variables.sql_mode= orig_sql_mode; goto end; + } } } @@ -5931,7 +5934,7 @@ get_mm_leaf(RANGE_OPT_PARAM *param, COND *conf_func, Field *field, switch (type) { case Item_func::LT_FUNC: - if (field_is_equal_to_item(field,value)) + if (stored_field_cmp_to_item(field,value) == 0) tree->max_flag=NEAR_MAX; /* fall through */ case Item_func::LE_FUNC: @@ -5945,11 +5948,16 @@ get_mm_leaf(RANGE_OPT_PARAM *param, COND *conf_func, Field *field, break; case Item_func::GT_FUNC: /* Don't use open ranges for partial key_segments */ - if (field_is_equal_to_item(field,value) && - !(key_part->flag & HA_PART_KEY_SEG)) + if ((!(key_part->flag & HA_PART_KEY_SEG)) && + (stored_field_cmp_to_item(field, value) <= 0)) tree->min_flag=NEAR_MIN; - /* fall through */ + tree->max_flag= NO_MAX_RANGE; + break; case Item_func::GE_FUNC: + /* Don't use open ranges for partial key_segments */ + if ((!(key_part->flag & HA_PART_KEY_SEG)) && + (stored_field_cmp_to_item(field,value) < 0)) + tree->min_flag= NEAR_MIN; tree->max_flag=NO_MAX_RANGE; break; case Item_func::SP_EQUALS_FUNC: @@ -6440,13 +6448,6 @@ key_and(RANGE_OPT_PARAM *param, SEL_ARG *key1, SEL_ARG *key2, uint clone_flag) return 0; // Can't optimize this } - if ((key1->min_flag | key2->min_flag) & GEOM_FLAG) - { - key1->free_tree(); - key2->free_tree(); - return 0; // Can't optimize this - } - key1->use_count--; key2->use_count--; SEL_ARG *e1=key1->first(), *e2=key2->first(), *new_tree=0; @@ -6797,9 +6798,7 @@ static bool eq_tree(SEL_ARG* a,SEL_ARG *b) SEL_ARG * SEL_ARG::insert(SEL_ARG *key) { - SEL_ARG *element,**par,*last_element; - LINT_INIT(par); - LINT_INIT(last_element); + SEL_ARG *element,**UNINIT_VAR(par),*UNINIT_VAR(last_element); for (element= this; element != &null_element ; ) { @@ -8066,7 +8065,10 @@ int QUICK_INDEX_MERGE_SELECT::read_keys_and_merge() if (cur_quick->file->inited != handler::NONE) cur_quick->file->ha_index_end(); if (cur_quick->init() || cur_quick->reset()) + { + delete unique; DBUG_RETURN(1); + } } if (result) @@ -8074,13 +8076,17 @@ int QUICK_INDEX_MERGE_SELECT::read_keys_and_merge() if (result != HA_ERR_END_OF_FILE) { cur_quick->range_end(); + delete unique; DBUG_RETURN(result); } break; } if (thd->killed) + { + delete unique; DBUG_RETURN(1); + } /* skip row if it will be retrieved by clustered PK scan */ if (pk_quick_select && pk_quick_select->row_in_ranges()) @@ -8089,8 +8095,10 @@ int QUICK_INDEX_MERGE_SELECT::read_keys_and_merge() cur_quick->file->position(cur_quick->record); result= unique->unique_add((char*)cur_quick->file->ref); if (result) + { + delete unique; DBUG_RETURN(1); - + } } /* @@ -9395,7 +9403,9 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree) goto next_index; } else + { DBUG_ASSERT(FALSE); + } /* Check (SA2). */ if (min_max_arg_item) @@ -9629,7 +9639,17 @@ check_group_min_max_predicates(COND *cond, Item_field *min_max_arg_item, */ if (cond_type == Item::SUBSELECT_ITEM) DBUG_RETURN(FALSE); - + + /* + Condition of the form 'field' is equivalent to 'field <> 0' and thus + satisfies the SA3 condition. + */ + if (cond_type == Item::FIELD_ITEM) + { + DBUG_PRINT("info", ("Analyzing: %s", cond->full_name())); + DBUG_RETURN(TRUE); + } + /* We presume that at this point there are no other Items than functions. */ DBUG_ASSERT(cond_type == Item::FUNC_ITEM); @@ -9787,11 +9807,22 @@ get_constant_key_infix(KEY *index_info, SEL_ARG *index_range_tree, return FALSE; uint field_length= cur_part->store_length; - if ((cur_range->maybe_null && - cur_range->min_value[0] && cur_range->max_value[0]) || - !memcmp(cur_range->min_value, cur_range->max_value, field_length)) - { - /* cur_range specifies 'IS NULL' or an equality condition. */ + if (cur_range->maybe_null && + cur_range->min_value[0] && cur_range->max_value[0]) + { + /* + cur_range specifies 'IS NULL'. In this case the argument points + to a "null value" (is_null_string) that may not always be long + enough for a direct memcpy to a field. + */ + DBUG_ASSERT (field_length > 0); + *key_ptr= 1; + bzero(key_ptr+1,field_length-1); + key_ptr+= field_length; + *key_infix_len+= field_length; + } + else if (memcmp(cur_range->min_value, cur_range->max_value, field_length) == 0) + { /* cur_range specifies an equality condition. */ memcpy(key_ptr, cur_range->min_value, field_length); key_ptr+= field_length; *key_infix_len+= field_length; diff --git a/sql/partition_info.h b/sql/partition_info.h index 415f955d5d4..9f438e8260b 100644 --- a/sql/partition_info.h +++ b/sql/partition_info.h @@ -300,6 +300,7 @@ static inline void init_single_partition_iterator(uint32 part_id, { part_iter->part_nums.start= part_iter->part_nums.cur= part_id; part_iter->part_nums.end= part_id+1; + part_iter->ret_null_part= part_iter->ret_null_part_orig= FALSE; part_iter->get_next= get_next_partition_id_range; } @@ -310,5 +311,6 @@ void init_all_partitions_iterator(partition_info *part_info, { part_iter->part_nums.start= part_iter->part_nums.cur= 0; part_iter->part_nums.end= part_info->no_parts; + part_iter->ret_null_part= part_iter->ret_null_part_orig= FALSE; part_iter->get_next= get_next_partition_id_range; } diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index df0d7d97d2d..b0ed27b9977 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -6184,17 +6184,17 @@ ER_FUNC_INEXISTENT_NAME_COLLISION 42000 # When updating these, please update EXPLAIN_FILENAME_MAX_EXTRA_LENGTH in # mysql_priv.h with the new maximal additional length for explain_filename. ER_DATABASE_NAME - eng "Database `%s`" - swe "Databas `%s`" + eng "Database" + swe "Databas" ER_TABLE_NAME - eng "Table `%s`" - swe "Tabell `%s`" + eng "Table" + swe "Tabell" ER_PARTITION_NAME - eng "Partition `%s`" - swe "Partition `%s`" + eng "Partition" + swe "Partition" ER_SUBPARTITION_NAME - eng "Subpartition `%s`" - swe "Subpartition `%s`" + eng "Subpartition" + swe "Subpartition" ER_TEMPORARY_NAME eng "Temporary" swe "Temporär" diff --git a/sql/slave.cc b/sql/slave.cc index 926db30be15..314c12313f6 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -1961,9 +1961,6 @@ static int has_temporary_error(THD *thd) { DBUG_ENTER("has_temporary_error"); - if (thd->is_fatal_error) - DBUG_RETURN(0); - DBUG_EXECUTE_IF("all_errors_are_temporary_errors", if (thd->main_da.is_error()) { @@ -3689,6 +3686,31 @@ void end_relay_log_info(Relay_log_info* rli) DBUG_VOID_RETURN; } + +/** + Hook to detach the active VIO before closing a connection handle. + + The client API might close the connection (and associated data) + in case it encounters a unrecoverable (network) error. This hook + is called from the client code before the VIO handle is deleted + allows the thread to detach the active vio so it does not point + to freed memory. + + Other calls to THD::clear_active_vio throughout this module are + redundant due to the hook but are left in place for illustrative + purposes. +*/ + +extern "C" void slave_io_thread_detach_vio() +{ +#ifdef SIGNAL_WITH_VIO_CLOSE + THD *thd= current_thd; + if (thd->slave_thread) + thd->clear_active_vio(); +#endif +} + + /* Try to connect until successful or slave killed diff --git a/sql/spatial.cc b/sql/spatial.cc index 9e59a5ee0de..a23e8ec0d90 100644 --- a/sql/spatial.cc +++ b/sql/spatial.cc @@ -935,13 +935,10 @@ int Gis_polygon::interior_ring_n(uint32 num, String *result) const int Gis_polygon::centroid_xy(double *x, double *y) const { uint32 n_linear_rings; - double res_area; - double res_cx, res_cy; + double UNINIT_VAR(res_area); + double UNINIT_VAR(res_cx), UNINIT_VAR(res_cy); const char *data= m_data; bool first_loop= 1; - LINT_INIT(res_area); - LINT_INIT(res_cx); - LINT_INIT(res_cy); if (no_data(data, 4)) return 1; @@ -1636,14 +1633,10 @@ int Gis_multi_polygon::centroid(String *result) const uint32 n_polygons; bool first_loop= 1; Gis_polygon p; - double res_area, res_cx, res_cy; + double UNINIT_VAR(res_area), UNINIT_VAR(res_cx), UNINIT_VAR(res_cy); double cur_area, cur_cx, cur_cy; const char *data= m_data; - LINT_INIT(res_area); - LINT_INIT(res_cx); - LINT_INIT(res_cy); - if (no_data(data, 4)) return 1; n_polygons= uint4korr(data); diff --git a/sql/sql_base.cc b/sql/sql_base.cc index d94a35259f4..9fd47a655e0 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -1515,21 +1515,23 @@ void close_temporary_tables(THD *thd) my_thread_id save_pseudo_thread_id= thd->variables.pseudo_thread_id; /* Set pseudo_thread_id to be that of the processed table */ thd->variables.pseudo_thread_id= tmpkeyval(thd, table); - /* - Loop forward through all tables within the sublist of - common pseudo_thread_id to create single DROP query. + String db; + db.append(table->s->db.str); + /* Loop forward through all tables that belong to a common database + within the sublist of common pseudo_thread_id to create single + DROP query */ for (s_query.length(stub_len); table && is_user_table(table) && - tmpkeyval(thd, table) == thd->variables.pseudo_thread_id; + tmpkeyval(thd, table) == thd->variables.pseudo_thread_id && + table->s->db.length == db.length() && + strcmp(table->s->db.str, db.ptr()) == 0; table= next) { /* - We are going to add 4 ` around the db/table names and possible more - due to special characters in the names + We are going to add ` around the table names and possible more + due to special characters */ - append_identifier(thd, &s_query, table->s->db.str, strlen(table->s->db.str)); - s_query.append('.'); append_identifier(thd, &s_query, table->s->table_name.str, strlen(table->s->table_name.str)); s_query.append(','); @@ -1542,6 +1544,7 @@ void close_temporary_tables(THD *thd) Query_log_event qinfo(thd, s_query.ptr(), s_query.length() - 1 /* to remove trailing ',' */, 0, FALSE, 0); + qinfo.db= db.ptr(); thd->variables.character_set_client= cs_save; mysql_bin_log.write(&qinfo); thd->variables.pseudo_thread_id= save_pseudo_thread_id; diff --git a/sql/sql_db.cc b/sql/sql_db.cc index 9e528622416..82f5bf48166 100644 --- a/sql/sql_db.cc +++ b/sql/sql_db.cc @@ -658,10 +658,8 @@ int mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create_info, } push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, ER_DB_CREATE_EXISTS, ER(ER_DB_CREATE_EXISTS), db); - if (!silent) - my_ok(thd); error= 0; - goto exit; + goto not_silent; } else { @@ -698,7 +696,8 @@ int mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create_info, happened. (This is a very unlikely senario) */ } - + +not_silent: if (!silent) { char *query; diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 8fa396a8553..8a5afa8da17 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -1067,6 +1067,9 @@ bool mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok) bzero((char*) &create_info,sizeof(create_info)); + /* Remove tables from the HANDLER's hash. */ + mysql_ha_rm_tables(thd, table_list, FALSE); + /* If it is a temporary table, close and regenerate it */ if (!dont_send_ok && (table= find_temporary_table(thd, table_list))) { diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 710da7067e4..85b77bbb326 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -3420,25 +3420,6 @@ static TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info, bool not_used; DBUG_ENTER("create_table_from_items"); - DBUG_EXECUTE_IF("sleep_create_select_before_check_if_exists", my_sleep(6000000);); - - if (!(create_info->options & HA_LEX_CREATE_TMP_TABLE) && - create_table->table->db_stat) - { - /* Table already exists and was open at open_and_lock_tables() stage. */ - if (create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS) - { - create_info->table_existed= 1; // Mark that table existed - push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, - ER_TABLE_EXISTS_ERROR, ER(ER_TABLE_EXISTS_ERROR), - create_table->table_name); - DBUG_RETURN(create_table->table); - } - - my_error(ER_TABLE_EXISTS_ERROR, MYF(0), create_table->table_name); - DBUG_RETURN(0); - } - tmp_table.alias= 0; tmp_table.timestamp_field= 0; tmp_table.s= &share; @@ -3647,10 +3628,35 @@ select_create::prepare(List<Item> &values, SELECT_LEX_UNIT *u) thd->binlog_start_trans_and_stmt(); } - if (!(table= create_table_from_items(thd, create_info, create_table, - alter_info, &values, - &extra_lock, hook_ptr))) - DBUG_RETURN(-1); // abort() deletes table + DBUG_EXECUTE_IF("sleep_create_select_before_check_if_exists", my_sleep(6000000);); + + if (!(create_info->options & HA_LEX_CREATE_TMP_TABLE) && + create_table->table->db_stat) + { + /* Table already exists and was open at open_and_lock_tables() stage. */ + if (create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS) + { + /* Mark that table existed */ + create_info->table_existed= 1; + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, + ER_TABLE_EXISTS_ERROR, ER(ER_TABLE_EXISTS_ERROR), + create_table->table_name); + if (thd->current_stmt_binlog_row_based) + binlog_show_create_table(&(create_table->table), 1); + table= create_table->table; + } + else + { + my_error(ER_TABLE_EXISTS_ERROR, MYF(0), create_table->table_name); + DBUG_RETURN(-1); + } + } + else + if (!(table= create_table_from_items(thd, create_info, create_table, + alter_info, &values, + &extra_lock, hook_ptr))) + /* abort() deletes table */ + DBUG_RETURN(-1); if (extra_lock) { diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 20033e23b93..ff0d4f55bd1 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -464,7 +464,7 @@ pthread_handler_t handle_bootstrap(void *arg) thd->init_for_queries(); while (fgets(buff, thd->net.max_packet, file)) { - char *query; + char *query, *res; /* strlen() can't be deleted because fgets() doesn't return length */ ulong length= (ulong) strlen(buff); while (buff[length-1] != '\n' && !feof(file)) @@ -481,7 +481,7 @@ pthread_handler_t handle_bootstrap(void *arg) break; } buff= (char*) thd->net.buff; - fgets(buff + length, thd->net.max_packet - length, file); + res= fgets(buff + length, thd->net.max_packet - length, file); length+= (ulong) strlen(buff + length); /* purecov: end */ } diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 236df78d455..f7453e76d21 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -2766,8 +2766,24 @@ uint32 get_list_array_idx_for_endpoint(partition_info *part_info, if (part_info->part_expr->null_value) { - DBUG_RETURN(0); + /* + Special handling for MONOTONIC functions that can return NULL for + values that are comparable. I.e. + '2000-00-00' can be compared to '2000-01-01' but TO_DAYS('2000-00-00') + returns NULL which cannot be compared used <, >, <=, >= etc. + + Otherwise, just return the the first index (lowest value). + */ + enum_monotonicity_info monotonic; + monotonic= part_info->part_expr->get_monotonicity_info(); + if (monotonic != MONOTONIC_INCREASING_NOT_NULL && + monotonic != MONOTONIC_STRICT_INCREASING_NOT_NULL) + { + /* F(col) can not return NULL, return index with lowest value */ + DBUG_RETURN(0); + } } + if (unsigned_flag) part_func_value-= 0x8000000000000000ULL; DBUG_ASSERT(part_info->no_list_values); @@ -2916,11 +2932,29 @@ uint32 get_partition_id_range_for_endpoint(partition_info *part_info, if (part_info->part_expr->null_value) { - uint32 ret_part_id= 0; - if (!left_endpoint && include_endpoint) - ret_part_id= 1; - DBUG_RETURN(ret_part_id); + /* + Special handling for MONOTONIC functions that can return NULL for + values that are comparable. I.e. + '2000-00-00' can be compared to '2000-01-01' but TO_DAYS('2000-00-00') + returns NULL which cannot be compared used <, >, <=, >= etc. + + Otherwise, just return the first partition + (may be included if not left endpoint) + */ + enum_monotonicity_info monotonic; + monotonic= part_info->part_expr->get_monotonicity_info(); + if (monotonic != MONOTONIC_INCREASING_NOT_NULL && + monotonic != MONOTONIC_STRICT_INCREASING_NOT_NULL) + { + /* F(col) can not return NULL, return partition with lowest value */ + if (!left_endpoint && include_endpoint) + DBUG_RETURN(1); + DBUG_RETURN(0); + + } } + + if (unsigned_flag) part_func_value-= 0x8000000000000000ULL; if (left_endpoint && !include_endpoint) @@ -6077,6 +6111,9 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, lpt->pack_frm_len= 0; thd->work_part_info= part_info; + /* Never update timestamp columns when alter */ + table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET; + if (fast_alter_partition & HA_PARTITION_ONE_PHASE) { /* @@ -6693,6 +6730,7 @@ int get_part_iter_for_interval_via_mapping(partition_info *part_info, Field *field= part_info->part_field_array[0]; uint32 max_endpoint_val; get_endpoint_func get_endpoint; + bool can_match_multiple_values; /* is not '=' */ uint field_len= field->pack_length_in_rec(); part_iter->ret_null_part= part_iter->ret_null_part_orig= FALSE; @@ -6730,6 +6768,23 @@ int get_part_iter_for_interval_via_mapping(partition_info *part_info, } else assert(0); + + can_match_multiple_values= (flags || !min_value || !max_value || + memcmp(min_value, max_value, field_len)); + if (can_match_multiple_values && + (part_info->part_type == RANGE_PARTITION || + part_info->has_null_value)) + { + /* Range scan on RANGE or LIST partitioned table */ + enum_monotonicity_info monotonic; + monotonic= part_info->part_expr->get_monotonicity_info(); + if (monotonic == MONOTONIC_INCREASING_NOT_NULL || + monotonic == MONOTONIC_STRICT_INCREASING_NOT_NULL) + { + /* col is NOT NULL, but F(col) can return NULL, add NULL partition */ + part_iter->ret_null_part= part_iter->ret_null_part_orig= TRUE; + } + } /* Find minimum: Do special handling if the interval has left bound in form @@ -6762,6 +6817,14 @@ int get_part_iter_for_interval_via_mapping(partition_info *part_info, store_key_image_to_rec(field, min_value, field_len); bool include_endp= !test(flags & NEAR_MIN); part_iter->part_nums.start= get_endpoint(part_info, 1, include_endp); + if (!can_match_multiple_values && part_info->part_expr->null_value) + { + /* col = x and F(x) = NULL -> only search NULL partition */ + part_iter->part_nums.cur= part_iter->part_nums.start= 0; + part_iter->part_nums.end= 0; + part_iter->ret_null_part= part_iter->ret_null_part_orig= TRUE; + return 1; + } part_iter->part_nums.cur= part_iter->part_nums.start; if (part_iter->part_nums.start == max_endpoint_val) return 0; /* No partitions */ @@ -6846,6 +6909,7 @@ int get_part_iter_for_interval_via_walking(partition_info *part_info, Field *field; uint total_parts; partition_iter_func get_next_func; + part_iter->ret_null_part= part_iter->ret_null_part_orig= FALSE; if (is_subpart) { field= part_info->subpart_field_array[0]; @@ -6956,7 +7020,13 @@ uint32 get_next_partition_id_range(PARTITION_ITERATOR* part_iter) { if (part_iter->part_nums.cur >= part_iter->part_nums.end) { + if (part_iter->ret_null_part) + { + part_iter->ret_null_part= FALSE; + return 0; /* NULL always in first range partition */ + } part_iter->part_nums.cur= part_iter->part_nums.start; + part_iter->ret_null_part= part_iter->ret_null_part_orig; return NOT_A_PARTITION_ID; } else @@ -6984,7 +7054,7 @@ uint32 get_next_partition_id_range(PARTITION_ITERATOR* part_iter) uint32 get_next_partition_id_list(PARTITION_ITERATOR *part_iter) { - if (part_iter->part_nums.cur == part_iter->part_nums.end) + if (part_iter->part_nums.cur >= part_iter->part_nums.end) { if (part_iter->ret_null_part) { diff --git a/sql/sql_profile.cc b/sql/sql_profile.cc index de501b9089e..bd871bb41a2 100644 --- a/sql/sql_profile.cc +++ b/sql/sql_profile.cc @@ -33,7 +33,7 @@ #include "my_sys.h" #define TIME_FLOAT_DIGITS 9 -/** two vals encoded: (dec*100)+len */ +/** two vals encoded: (len*100)+dec */ #define TIME_I_S_DECIMAL_SIZE (TIME_FLOAT_DIGITS*100)+(TIME_FLOAT_DIGITS-3) #define MAX_QUERY_LENGTH 300 diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 014b63c057c..a89638937be 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -9493,43 +9493,8 @@ static Field *create_tmp_field_from_item(THD *thd, Item *item, TABLE *table, new_field->set_derivation(item->collation.derivation); break; case DECIMAL_RESULT: - { - uint8 dec= item->decimals; - uint8 intg= ((Item_decimal *) item)->decimal_precision() - dec; - uint32 len= item->max_length; - - /* - Trying to put too many digits overall in a DECIMAL(prec,dec) - will always throw a warning. We must limit dec to - DECIMAL_MAX_SCALE however to prevent an assert() later. - */ - - if (dec > 0) - { - signed int overflow; - - dec= min(dec, DECIMAL_MAX_SCALE); - - /* - If the value still overflows the field with the corrected dec, - we'll throw out decimals rather than integers. This is still - bad and of course throws a truncation warning. - +1: for decimal point - */ - - overflow= my_decimal_precision_to_length(intg + dec, dec, - item->unsigned_flag) - len; - - if (overflow > 0) - dec= max(0, dec - overflow); // too long, discard fract - else - len -= item->decimals - dec; // corrected value fits - } - - new_field= new Field_new_decimal(len, maybe_null, item->name, - dec, item->unsigned_flag); + new_field= Field_new_decimal::new_decimal_field(item); break; - } case ROW_RESULT: default: // This case should never be choosen diff --git a/sql/sql_show.cc b/sql/sql_show.cc index b1f64a5a703..bd9e1fb5c72 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -7095,8 +7095,6 @@ bool show_create_trigger(THD *thd, const sp_name *trg_name) /* Perform closing actions and return error status. */ } - DBUG_ASSERT(num_tables == 1); - Table_triggers_list *triggers= lst->table->triggers; if (!triggers) diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 3aa9722c6ea..843e8db91ce 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -72,7 +72,7 @@ static void wait_for_kill_signal(THD *thd) @brief Helper function for explain_filename */ static char* add_identifier(char *to_p, const char * end_p, - const char* name, uint name_len, int errcode) + const char* name, uint name_len, bool add_quotes) { uint res; uint errors; @@ -92,18 +92,44 @@ static char* add_identifier(char *to_p, const char * end_p, res= strconvert(&my_charset_filename, conv_name, system_charset_info, conv_string, FN_REFLEN, &errors); if (!res || errors) + { + DBUG_PRINT("error", ("strconvert of '%s' failed with %u (errors: %u)", conv_name, res, errors)); conv_name= name; + } else { DBUG_PRINT("info", ("conv '%s' -> '%s'", conv_name, conv_string)); conv_name= conv_string; } - if (errcode) - to_p+= my_snprintf(to_p, end_p - to_p, ER(errcode), conv_name); + if (add_quotes && (end_p - to_p > 2)) + { + *(to_p++)= '`'; + while (*conv_name && (end_p - to_p - 1) > 0) + { + uint length= my_mbcharlen(system_charset_info, *conv_name); + if (!length) + length= 1; + if (length == 1 && *conv_name == '`') + { + if ((end_p - to_p) < 3) + break; + *(to_p++)= '`'; + *(to_p++)= *(conv_name++); + } + else if (((long) length) < (end_p - to_p)) + { + to_p= strnmov(to_p, conv_name, length); + conv_name+= length; + } + else + break; /* string already filled */ + } + to_p= strnmov(to_p, "`", end_p - to_p); + } else - to_p+= my_snprintf(to_p, end_p - to_p, "`%s`", conv_name); - return to_p; + to_p= strnmov(to_p, conv_name, end_p - to_p); + DBUG_RETURN(to_p); } @@ -135,6 +161,8 @@ static char* add_identifier(char *to_p, const char * end_p, [,[ Temporary| Renamed] Partition `p` [, Subpartition `sp`]] *| (| is really a /, and it is all in one line) + EXPLAIN_PARTITIONS_AS_COMMENT_NO_QUOTING -> + same as above but no quotes are added. @retval Length of returned string */ @@ -245,28 +273,39 @@ uint explain_filename(const char *from, part_name_len-= 5; } } + else + table_name_len= strlen(table_name); if (db_name) { if (explain_mode == EXPLAIN_ALL_VERBOSE) { - to_p= add_identifier(to_p, end_p, db_name, db_name_len, - ER_DATABASE_NAME); + to_p= strnmov(to_p, ER(ER_DATABASE_NAME), end_p - to_p); + *(to_p++)= ' '; + to_p= add_identifier(to_p, end_p, db_name, db_name_len, 1); to_p= strnmov(to_p, ", ", end_p - to_p); } else { - to_p= add_identifier(to_p, end_p, db_name, db_name_len, 0); + to_p= add_identifier(to_p, end_p, db_name, db_name_len, + (explain_mode != + EXPLAIN_PARTITIONS_AS_COMMENT_NO_QUOTING)); to_p= strnmov(to_p, ".", end_p - to_p); } } if (explain_mode == EXPLAIN_ALL_VERBOSE) - to_p= add_identifier(to_p, end_p, table_name, table_name_len, - ER_TABLE_NAME); + { + to_p= strnmov(to_p, ER(ER_TABLE_NAME), end_p - to_p); + *(to_p++)= ' '; + to_p= add_identifier(to_p, end_p, table_name, table_name_len, 1); + } else - to_p= add_identifier(to_p, end_p, table_name, table_name_len, 0); + to_p= add_identifier(to_p, end_p, table_name, table_name_len, + (explain_mode != + EXPLAIN_PARTITIONS_AS_COMMENT_NO_QUOTING)); if (part_name) { - if (explain_mode == EXPLAIN_PARTITIONS_AS_COMMENT) + if (explain_mode == EXPLAIN_PARTITIONS_AS_COMMENT || + explain_mode == EXPLAIN_PARTITIONS_AS_COMMENT_NO_QUOTING) to_p= strnmov(to_p, " /* ", end_p - to_p); else if (explain_mode == EXPLAIN_PARTITIONS_VERBOSE) to_p= strnmov(to_p, " ", end_p - to_p); @@ -280,15 +319,22 @@ uint explain_filename(const char *from, to_p= strnmov(to_p, ER(ER_RENAMED_NAME), end_p - to_p); to_p= strnmov(to_p, " ", end_p - to_p); } + to_p= strnmov(to_p, ER(ER_PARTITION_NAME), end_p - to_p); + *(to_p++)= ' '; to_p= add_identifier(to_p, end_p, part_name, part_name_len, - ER_PARTITION_NAME); + (explain_mode != + EXPLAIN_PARTITIONS_AS_COMMENT_NO_QUOTING)); if (subpart_name) { to_p= strnmov(to_p, ", ", end_p - to_p); + to_p= strnmov(to_p, ER(ER_SUBPARTITION_NAME), end_p - to_p); + *(to_p++)= ' '; to_p= add_identifier(to_p, end_p, subpart_name, subpart_name_len, - ER_SUBPARTITION_NAME); + (explain_mode != + EXPLAIN_PARTITIONS_AS_COMMENT_NO_QUOTING)); } - if (explain_mode == EXPLAIN_PARTITIONS_AS_COMMENT) + if (explain_mode == EXPLAIN_PARTITIONS_AS_COMMENT || + explain_mode == EXPLAIN_PARTITIONS_AS_COMMENT_NO_QUOTING) to_p= strnmov(to_p, " */", end_p - to_p); } DBUG_PRINT("exit", ("to '%s'", to)); @@ -3476,6 +3522,41 @@ void sp_prepare_create_field(THD *thd, Create_field *sql_field) /* + Write CREATE TABLE binlog + + SYNOPSIS + write_create_table_bin_log() + thd Thread object + create_info Create information + internal_tmp_table Set to 1 if this is an internal temporary table + + DESCRIPTION + This function only is called in mysql_create_table_no_lock and + mysql_create_table + + RETURN VALUES + NONE + */ +static inline void write_create_table_bin_log(THD *thd, + const HA_CREATE_INFO *create_info, + bool internal_tmp_table) +{ + /* + Don't write statement if: + - It is an internal temporary table, + - Row-based logging is used and it we are creating a temporary table, or + - The binary log is not open. + Otherwise, the statement shall be binlogged. + */ + if (!internal_tmp_table && + (!thd->current_stmt_binlog_row_based || + (thd->current_stmt_binlog_row_based && + !(create_info->options & HA_LEX_CREATE_TMP_TABLE)))) + write_bin_log(thd, TRUE, thd->query, thd->query_length); +} + + +/* Create a table SYNOPSIS @@ -3739,6 +3820,7 @@ bool mysql_create_table_no_lock(THD *thd, ER_TABLE_EXISTS_ERROR, ER(ER_TABLE_EXISTS_ERROR), alias); error= 0; + write_create_table_bin_log(thd, create_info, internal_tmp_table); goto err; } my_error(ER_TABLE_EXISTS_ERROR, MYF(0), alias); @@ -3866,18 +3948,7 @@ bool mysql_create_table_no_lock(THD *thd, thd->thread_specific_used= TRUE; } - /* - Don't write statement if: - - It is an internal temporary table, - - Row-based logging is used and it we are creating a temporary table, or - - The binary log is not open. - Otherwise, the statement shall be binlogged. - */ - if (!internal_tmp_table && - (!thd->current_stmt_binlog_row_based || - (thd->current_stmt_binlog_row_based && - !(create_info->options & HA_LEX_CREATE_TMP_TABLE)))) - write_bin_log(thd, TRUE, thd->query, thd->query_length); + write_create_table_bin_log(thd, create_info, internal_tmp_table); error= FALSE; unlock_and_end: VOID(pthread_mutex_unlock(&LOCK_open)); @@ -3893,6 +3964,7 @@ warn: ER_TABLE_EXISTS_ERROR, ER(ER_TABLE_EXISTS_ERROR), alias); create_info->table_existed= 1; // Mark that table existed + write_create_table_bin_log(thd, create_info, internal_tmp_table); goto unlock_and_end; } @@ -3944,6 +4016,7 @@ bool mysql_create_table(THD *thd, const char *db, const char *table_name, table_name); create_info->table_existed= 1; result= FALSE; + write_create_table_bin_log(thd, create_info, internal_tmp_table); } else { @@ -5285,6 +5358,24 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, TABLE_LIST* src_table, goto err; /* purecov: inspected */ } +goto binlog; + +table_exists: + if (create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS) + { + char warn_buff[MYSQL_ERRMSG_SIZE]; + my_snprintf(warn_buff, sizeof(warn_buff), + ER(ER_TABLE_EXISTS_ERROR), table_name); + push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, + ER_TABLE_EXISTS_ERROR,warn_buff); + } + else + { + my_error(ER_TABLE_EXISTS_ERROR, MYF(0), table_name); + goto err; + } + +binlog: DBUG_EXECUTE_IF("sleep_create_like_before_binlogging", my_sleep(6000000);); /* @@ -5348,20 +5439,6 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, TABLE_LIST* src_table, write_bin_log(thd, TRUE, thd->query, thd->query_length); res= FALSE; - goto err; - -table_exists: - if (create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS) - { - char warn_buff[MYSQL_ERRMSG_SIZE]; - my_snprintf(warn_buff, sizeof(warn_buff), - ER(ER_TABLE_EXISTS_ERROR), table_name); - push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, - ER_TABLE_EXISTS_ERROR,warn_buff); - res= FALSE; - } - else - my_error(ER_TABLE_EXISTS_ERROR, MYF(0), table_name); err: if (name_lock) diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 4c9a50000aa..a721a086b6b 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -730,6 +730,7 @@ int mysql_update(THD *thd, break; } } + table->auto_increment_field_not_null= FALSE; dup_key_found= 0; /* Caching the killed status to pass as the arg to query event constuctor; diff --git a/sql/sql_view.cc b/sql/sql_view.cc index 1b210226992..43d0b9fade0 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -1032,7 +1032,8 @@ bool mysql_make_view(THD *thd, File_parser *parser, TABLE_LIST *table, TABLE_LIST *top_view= table->top_table(); bool parse_status; bool result, view_is_mergeable; - TABLE_LIST *view_main_select_tables; + TABLE_LIST *UNINIT_VAR(view_main_select_tables); + DBUG_ENTER("mysql_make_view"); DBUG_PRINT("info", ("table: 0x%lx (%s)", (ulong) table, table->table_name)); @@ -1309,7 +1310,6 @@ bool mysql_make_view(THD *thd, File_parser *parser, TABLE_LIST *table, old_lex->set_stmt_unsafe(); view_is_mergeable= (table->algorithm != VIEW_ALGORITHM_TMPTABLE && lex->can_be_merged()); - LINT_INIT(view_main_select_tables); if (view_is_mergeable) { diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index e08e44d34d7..7064bac2085 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -1814,15 +1814,16 @@ server_option: ; event_tail: - EVENT_SYM opt_if_not_exists sp_name + remember_name EVENT_SYM opt_if_not_exists sp_name { THD *thd= YYTHD; LEX *lex=Lex; - lex->create_info.options= $2; + lex->stmt_definition_begin= $1; + lex->create_info.options= $3; if (!(lex->event_parse_data= Event_parse_data::new_instance(thd))) MYSQL_YYABORT; - lex->event_parse_data->identifier= $3; + lex->event_parse_data->identifier= $4; lex->event_parse_data->on_completion= Event_parse_data::ON_COMPLETION_DROP; @@ -3759,8 +3760,8 @@ partitioning: LEX_STRING partition_name={C_STRING_WITH_LEN("partition")}; if (!plugin_is_ready(&partition_name, MYSQL_STORAGE_ENGINE_PLUGIN)) { - my_error(ER_FEATURE_DISABLED, MYF(0), - "partitioning", "--with-partition"); + my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), + "--skip-partition"); MYSQL_YYABORT; } lex->part_info= new partition_info(); @@ -9096,7 +9097,8 @@ procedure_clause: MYSQL_YYABORT; } - if (&lex->select_lex != lex->current_select) + if (&lex->select_lex != lex->current_select || + lex->select_lex.get_table_list()->derived) { my_error(ER_WRONG_USAGE, MYF(0), "PROCEDURE", "subquery"); MYSQL_YYABORT; diff --git a/sql/table.cc b/sql/table.cc index edf671b5a3b..2c45dc800f5 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -914,6 +914,15 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head, we unlock the old value of share->db_plugin before replacing it with a globally locked version of tmp_plugin */ + /* Check if the partitioning engine is ready */ + if (!plugin_is_ready(&name, MYSQL_STORAGE_ENGINE_PLUGIN)) + { + error= 8; + my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), + "--skip-partition"); + my_free(buff, MYF(0)); + goto err; + } plugin_unlock(NULL, share->db_plugin); share->db_plugin= ha_lock_engine(NULL, partition_hton); DBUG_PRINT("info", ("setting dbtype to '%.*s' (%d)", |