diff options
author | Andrei Elkin <aelkin@mysql.com> | 2009-11-30 14:34:39 +0200 |
---|---|---|
committer | Andrei Elkin <aelkin@mysql.com> | 2009-11-30 14:34:39 +0200 |
commit | 3962da934f6e2a92ba04505bd6a33dd7d8322005 (patch) | |
tree | c5510a774ac5e8722c26070e21e3d266d6408381 /sql | |
parent | 13dad4ebd268e4bf26c4d6f478f19896770d9b78 (diff) | |
parent | a95f54c6d81f20b07e41a7e0e2246ee00641df6c (diff) | |
download | mariadb-git-3962da934f6e2a92ba04505bd6a33dd7d8322005.tar.gz |
merging from 5.1 to rep+2 starting at gca(5.1, next-mr) == build@mysql.com-20091104182209-iui387z35159aoyw
Diffstat (limited to 'sql')
54 files changed, 1081 insertions, 553 deletions
diff --git a/sql/event_data_objects.cc b/sql/event_data_objects.cc index dba32cac6b2..f2ec0e8cf64 100644 --- a/sql/event_data_objects.cc +++ b/sql/event_data_objects.cc @@ -1433,7 +1433,7 @@ Event_job_data::execute(THD *thd, bool drop) thd->set_query(sp_sql.c_ptr_safe(), sp_sql.length()); { - Parser_state parser_state(thd, thd->query, thd->query_length); + Parser_state parser_state(thd, thd->query(), thd->query_length()); lex_start(thd); if (parse_sql(thd, & parser_state, creation_ctx)) diff --git a/sql/events.cc b/sql/events.cc index 34da0e185b7..458ad61718d 100644 --- a/sql/events.cc +++ b/sql/events.cc @@ -465,7 +465,7 @@ Events::create_event(THD *thd, Event_parse_data *parse_data, if (!dropped) { /* Binlog the create event. */ - DBUG_ASSERT(thd->query && thd->query_length); + DBUG_ASSERT(thd->query() && thd->query_length()); String log_query; if (create_query_string(thd, &log_query)) { @@ -595,8 +595,8 @@ Events::update_event(THD *thd, Event_parse_data *parse_data, event_queue->update_event(thd, parse_data->dbname, parse_data->name, new_element); /* Binlog the alter event. */ - DBUG_ASSERT(thd->query && thd->query_length); - write_bin_log(thd, TRUE, thd->query, thd->query_length); + DBUG_ASSERT(thd->query() && thd->query_length()); + write_bin_log(thd, TRUE, thd->query(), thd->query_length()); } } pthread_mutex_unlock(&LOCK_event_metadata); @@ -670,8 +670,8 @@ Events::drop_event(THD *thd, LEX_STRING dbname, LEX_STRING name, bool if_exists) if (event_queue) event_queue->drop_event(thd, dbname, name); /* Binlog the drop event. */ - DBUG_ASSERT(thd->query && thd->query_length); - write_bin_log(thd, TRUE, thd->query, thd->query_length); + DBUG_ASSERT(thd->query() && thd->query_length()); + write_bin_log(thd, TRUE, thd->query(), thd->query_length()); } pthread_mutex_unlock(&LOCK_event_metadata); DBUG_RETURN(ret); diff --git a/sql/field.cc b/sql/field.cc index 0df9b0fc2e4..354c911e1c0 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -1,4 +1,4 @@ -/* Copyright 2000-2008 MySQL AB, 2008 Sun Microsystems, Inc. +/* Copyright 2000-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. 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 @@ -2480,97 +2480,12 @@ 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); @@ -6550,20 +6465,9 @@ uint Field::is_equal(Create_field *new_field) } -/* If one of the fields is binary and the other one isn't return 1 else 0 */ - -bool Field_str::compare_str_field_flags(Create_field *new_field, uint32 flag_arg) -{ - return (((new_field->flags & (BINCMP_FLAG | BINARY_FLAG)) && - !(flag_arg & (BINCMP_FLAG | BINARY_FLAG))) || - (!(new_field->flags & (BINCMP_FLAG | BINARY_FLAG)) && - (flag_arg & (BINCMP_FLAG | BINARY_FLAG)))); -} - - uint Field_str::is_equal(Create_field *new_field) { - if (compare_str_field_flags(new_field, flags)) + if (field_flags_are_binary() != new_field->field_flags_are_binary()) return 0; return ((new_field->sql_type == real_type()) && @@ -8329,7 +8233,7 @@ uint Field_blob::max_packed_col_length(uint max_length) uint Field_blob::is_equal(Create_field *new_field) { - if (compare_str_field_flags(new_field, flags)) + if (field_flags_are_binary() != new_field->field_flags_are_binary()) return 0; return ((new_field->sql_type == get_blob_type_from_length(max_data_length())) @@ -8889,7 +8793,7 @@ uint Field_enum::is_equal(Create_field *new_field) The fields are compatible if they have the same flags, type, charset and have the same underlying length. */ - if (compare_str_field_flags(new_field, flags) || + if (new_field->field_flags_are_binary() != field_flags_are_binary() || new_field->sql_type != real_type() || new_field->charset != field_charset || new_field->pack_length != pack_length()) @@ -9658,7 +9562,7 @@ bool Create_field::init(THD *thd, char *fld_name, enum_field_types fld_type, } if (length == 0) - fld_length= 0; /* purecov: inspected */ + fld_length= NULL; /* purecov: inspected */ } sign_len= fld_type_modifier & UNSIGNED_FLAG ? 0 : 1; @@ -9810,8 +9714,7 @@ bool Create_field::init(THD *thd, char *fld_name, enum_field_types fld_type, case MYSQL_TYPE_TIMESTAMP: if (fld_length == NULL) { - /* Compressed date YYYYMMDDHHMMSS */ - length= MAX_DATETIME_COMPRESSED_WIDTH; + length= MAX_DATETIME_WIDTH; } else if (length != MAX_DATETIME_WIDTH) { @@ -9876,7 +9779,7 @@ bool Create_field::init(THD *thd, char *fld_name, enum_field_types fld_type, sql_type= MYSQL_TYPE_NEWDATE; /* fall trough */ case MYSQL_TYPE_NEWDATE: - length= 10; + length= MAX_DATE_WIDTH; break; case MYSQL_TYPE_TIME: length= 10; @@ -9957,6 +9860,17 @@ bool Create_field::init(THD *thd, char *fld_name, enum_field_types fld_type, DBUG_RETURN(TRUE); } + switch (fld_type) { + case MYSQL_TYPE_DATE: + case MYSQL_TYPE_NEWDATE: + case MYSQL_TYPE_TIME: + case MYSQL_TYPE_DATETIME: + case MYSQL_TYPE_TIMESTAMP: + charset= &my_charset_bin; + flags|= BINCMP_FLAG; + default: break; + } + DBUG_RETURN(FALSE); /* success */ } diff --git a/sql/field.h b/sql/field.h index 51397cad7b1..18b017516a7 100644 --- a/sql/field.h +++ b/sql/field.h @@ -1,7 +1,7 @@ #ifndef FIELD_INCLUDED #define FIELD_INCLUDED -/* Copyright 2000-2008 MySQL AB, 2008 Sun Microsystems, Inc. +/* Copyright 2000-2008 MySQL AB, 2008, 2009 Sun Microsystems, Inc. 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 @@ -613,15 +613,17 @@ protected: handle_int64(to, from, low_byte_first_from, table->s->db_low_byte_first); return from + sizeof(int64); } + + bool field_flags_are_binary() + { + return (flags & (BINCMP_FLAG | BINARY_FLAG)) != 0; + } + }; 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, @@ -672,7 +674,6 @@ public: friend class Create_field; my_decimal *val_decimal(my_decimal *); virtual bool str_needs_quotes() { return TRUE; } - bool compare_str_field_flags(Create_field *new_field, uint32 flags); uint is_equal(Create_field *new_field); }; @@ -780,11 +781,6 @@ 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; } @@ -1287,12 +1283,12 @@ public: Field_date(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg, enum utype unireg_check_arg, const char *field_name_arg, CHARSET_INFO *cs) - :Field_str(ptr_arg, 10, null_ptr_arg, null_bit_arg, + :Field_str(ptr_arg, MAX_DATE_WIDTH, null_ptr_arg, null_bit_arg, unireg_check_arg, field_name_arg, cs) {} Field_date(bool maybe_null_arg, const char *field_name_arg, CHARSET_INFO *cs) - :Field_str((uchar*) 0,10, maybe_null_arg ? (uchar*) "": 0,0, + :Field_str((uchar*) 0, MAX_DATE_WIDTH, maybe_null_arg ? (uchar*) "": 0,0, NONE, field_name_arg, cs) {} enum_field_types type() const { return MYSQL_TYPE_DATE;} enum ha_base_keytype key_type() const { return HA_KEYTYPE_ULONG_INT; } @@ -1402,12 +1398,12 @@ public: Field_datetime(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg, enum utype unireg_check_arg, const char *field_name_arg, CHARSET_INFO *cs) - :Field_str(ptr_arg, 19, null_ptr_arg, null_bit_arg, + :Field_str(ptr_arg, MAX_DATETIME_WIDTH, null_ptr_arg, null_bit_arg, unireg_check_arg, field_name_arg, cs) {} Field_datetime(bool maybe_null_arg, const char *field_name_arg, CHARSET_INFO *cs) - :Field_str((uchar*) 0,19, maybe_null_arg ? (uchar*) "": 0,0, + :Field_str((uchar*) 0, MAX_DATETIME_WIDTH, maybe_null_arg ? (uchar*) "": 0,0, NONE, field_name_arg, cs) {} enum_field_types type() const { return MYSQL_TYPE_DATETIME;} #ifdef HAVE_LONG_LONG @@ -2079,6 +2075,11 @@ public: Item *on_update_value, LEX_STRING *comment, char *change, List<String> *interval_list, CHARSET_INFO *cs, uint uint_geom_type); + + bool field_flags_are_binary() + { + return (flags & (BINCMP_FLAG | BINARY_FLAG)) != 0; + } }; diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index dfd7ddc4d6c..9fdb8b628ca 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -5525,7 +5525,7 @@ int ha_ndbcluster::create(const char *name, if (share && !do_event_op) share->flags|= NSF_NO_BINLOG; ndbcluster_log_schema_op(thd, share, - thd->query, thd->query_length, + thd->query(), thd->query_length(), share->db, share->table_name, m_table->getObjectId(), m_table->getObjectVersion(), @@ -5967,7 +5967,8 @@ int ha_ndbcluster::rename_table(const char *from, const char *to) */ if (!is_old_table_tmpfile) ndbcluster_log_schema_op(current_thd, share, - current_thd->query, current_thd->query_length, + current_thd->query(), + current_thd->query_length(), old_dbname, m_tabname, ndb_table_id, ndb_table_version, SOT_RENAME_TABLE, @@ -6162,7 +6163,7 @@ retry_temporary_error1: current_thd->lex->sql_command != SQLCOM_TRUNCATE) { ndbcluster_log_schema_op(thd, share, - thd->query, thd->query_length, + thd->query(), thd->query_length(), share->db, share->table_name, ndb_table_id, ndb_table_version, SOT_DROP_TABLE, 0, 0, 1); @@ -6884,7 +6885,7 @@ static void ndbcluster_drop_database(handlerton *hton, char *path) THD *thd= current_thd; ha_ndbcluster::set_dbname(path, db); ndbcluster_log_schema_op(thd, 0, - thd->query, thd->query_length, + thd->query(), thd->query_length(), db, "", 0, 0, SOT_DROP_DB, 0, 0, 0); #endif DBUG_VOID_RETURN; @@ -10251,13 +10252,13 @@ int ndbcluster_alter_tablespace(handlerton *hton, #ifdef HAVE_NDB_BINLOG if (is_tablespace) ndbcluster_log_schema_op(thd, 0, - thd->query, thd->query_length, + thd->query(), thd->query_length(), "", alter_info->tablespace_name, 0, 0, SOT_TABLESPACE, 0, 0, 0); else ndbcluster_log_schema_op(thd, 0, - thd->query, thd->query_length, + thd->query(), thd->query_length(), "", alter_info->logfile_group_name, 0, 0, SOT_LOGFILE_GROUP, 0, 0, 0); diff --git a/sql/ha_ndbcluster_binlog.cc b/sql/ha_ndbcluster_binlog.cc index 2a87697c7fa..27af3f2cf2f 100644 --- a/sql/ha_ndbcluster_binlog.cc +++ b/sql/ha_ndbcluster_binlog.cc @@ -241,8 +241,8 @@ static void dbug_print_table(const char *info, TABLE *table) static void run_query(THD *thd, char *buf, char *end, const int *no_print_error, my_bool disable_binlog) { - ulong save_thd_query_length= thd->query_length; - char *save_thd_query= thd->query; + ulong save_thd_query_length= thd->query_length(); + char *save_thd_query= thd->query(); ulong save_thread_id= thd->variables.pseudo_thread_id; struct system_status_var save_thd_status_var= thd->status_var; THD_TRANS save_thd_transaction_all= thd->transaction.all; @@ -259,12 +259,12 @@ static void run_query(THD *thd, char *buf, char *end, if (disable_binlog) thd->options&= ~OPTION_BIN_LOG; - DBUG_PRINT("query", ("%s", thd->query)); + DBUG_PRINT("query", ("%s", thd->query())); DBUG_ASSERT(!thd->in_sub_stmt); DBUG_ASSERT(!thd->prelocked_mode); - mysql_parse(thd, thd->query, thd->query_length, &found_semicolon); + mysql_parse(thd, thd->query(), thd->query_length(), &found_semicolon); if (no_print_error && thd->is_slave_error) { diff --git a/sql/handler.cc b/sql/handler.cc index 0a7ea682313..2414ba64196 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -1331,7 +1331,8 @@ int ha_rollback_trans(THD *thd, bool all) } trans->ha_list= 0; trans->no_2pc=0; - if (is_real_trans && thd->transaction_rollback_request) + if (is_real_trans && thd->transaction_rollback_request && + thd->transaction.xid_state.xa_state != XA_NOTR) thd->transaction.xid_state.rm_error= thd->main_da.sql_errno(); if (all) thd->variables.tx_isolation=thd->session_tx_isolation; diff --git a/sql/handler.h b/sql/handler.h index 577b239fba1..4fe38b659bb 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -408,7 +408,6 @@ struct xid_t { my_xid get_my_xid() { return gtrid_length == MYSQL_XID_GTRID_LEN && bqual_length == 0 && - !memcmp(data+MYSQL_XID_PREFIX_LEN, &server_id, sizeof(server_id)) && !memcmp(data, MYSQL_XID_PREFIX, MYSQL_XID_PREFIX_LEN) ? quick_get_my_xid() : 0; } diff --git a/sql/item.cc b/sql/item.cc index 86e4551e55b..8f487872f1b 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -435,26 +435,17 @@ 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)) - precision= my_decimal_length_to_precision(max_length, decimals, unsigned_flag); - - return precision; + { + 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); } @@ -4908,7 +4899,9 @@ 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= Field_new_decimal::new_decimal_field(this); + field= new Field_new_decimal((uchar*) 0, max_length, null_ptr, 0, + Field::NONE, name, decimals, 0, + unsigned_flag); break; case MYSQL_TYPE_TINY: field= new Field_tiny((uchar*) 0, max_length, null_ptr, 0, Field::NONE, @@ -6866,52 +6859,61 @@ void resolve_const_item(THD *thd, Item **ref, Item *comp_item) } /** - Compare the value stored in field, with the original item. + Compare the value stored in field with the expression from the query. - @param field field which the item is converted and stored in - @param item original item + @param field Field which the Item is stored in after conversion + @param item Original expression from query - @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 + @return Returns 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. A 0 may also be returned if + out of memory. @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. */ -int stored_field_cmp_to_item(Field *field, Item *item) +int stored_field_cmp_to_item(THD *thd, Field *field, Item *item) { - Item_result res_type=item_cmp_type(field->result_type(), item->result_type()); if (res_type == STRING_RESULT) { char item_buff[MAX_FIELD_WIDTH]; char field_buff[MAX_FIELD_WIDTH]; - String item_tmp(item_buff,sizeof(item_buff),&my_charset_bin),*item_result; + + String item_tmp(item_buff,sizeof(item_buff),&my_charset_bin); String field_tmp(field_buff,sizeof(field_buff),&my_charset_bin); - enum_field_types field_type; - item_result=item->val_str(&item_tmp); + String *item_result= item->val_str(&item_tmp); + /* + Some implementations of Item::val_str(String*) actually modify + the field Item::null_value, hence we can't check it earlier. + */ if (item->null_value) return 0; - field->val_str(&field_tmp); + String *field_result= field->val_str(&field_tmp); - /* - 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); + enum_field_types field_type= field->type(); + + if (field_type == MYSQL_TYPE_DATE || field_type == MYSQL_TYPE_DATETIME) + { + enum_mysql_timestamp_type type= MYSQL_TIMESTAMP_ERROR; + + if (field_type == MYSQL_TYPE_DATE) + type= MYSQL_TIMESTAMP_DATE; + + if (field_type == MYSQL_TYPE_DATETIME) + type= MYSQL_TIMESTAMP_DATETIME; + + const char *field_name= field->field_name; + MYSQL_TIME field_time, item_time; + get_mysql_time_from_str(thd, field_result, type, field_name, &field_time); + get_mysql_time_from_str(thd, item_result, type, field_name, &item_time); + + return my_time_compare(&field_time, &item_time); + } + return stringcmp(field_result, item_result); } if (res_type == INT_RESULT) return 0; // Both are of type int diff --git a/sql/item.h b/sql/item.h index b44e84f4b15..e83634843be 100644 --- a/sql/item.h +++ b/sql/item.h @@ -765,10 +765,9 @@ 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 decimal_precision() - decimals; } + { return my_decimal_int_part(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. @@ -3128,6 +3127,6 @@ 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 int stored_field_cmp_to_item(Field *field, Item *item); - +extern int stored_field_cmp_to_item(THD *thd, Field *field, Item *item); #endif /* ITEM_INCLUDED */ + diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index c29031d25b5..c6b88cd8188 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -636,56 +636,51 @@ int Arg_comparator::set_compare_func(Item_bool_func2 *item, Item_result type) return 0; } - /** - @brief Convert date provided in a string to the int representation. - - @param[in] thd thread handle - @param[in] str a string to convert - @param[in] warn_type type of the timestamp for issuing the warning - @param[in] warn_name field name for issuing the warning - @param[out] error_arg could not extract a DATE or DATETIME - - @details Convert date provided in the string str to the int - representation. If the string contains wrong date or doesn't - contain it at all then a warning is issued. The warn_type and - the warn_name arguments are used as the name and the type of the - field when issuing the warning. If any input was discarded - (trailing or non-timestampy characters), was_cut will be non-zero. - was_type will return the type str_to_datetime() could correctly - extract. - - @return - converted value. 0 on error and on zero-dates -- check 'failure' + Parse date provided in a string to a MYSQL_TIME. + + @param[in] thd Thread handle + @param[in] str A string to convert + @param[in] warn_type Type of the timestamp for issuing the warning + @param[in] warn_name Field name for issuing the warning + @param[out] l_time The MYSQL_TIME objects is initialized. + + Parses a date provided in the string str into a MYSQL_TIME object. If the + string contains an incorrect date or doesn't correspond to a date at all + then a warning is issued. The warn_type and the warn_name arguments are used + as the name and the type of the field when issuing the warning. If any input + was discarded (trailing or non-timestamp-y characters), return value will be + TRUE. + + @return Status flag + @retval FALSE Success. + @retval True Indicates failure. */ -static ulonglong -get_date_from_str(THD *thd, String *str, timestamp_type warn_type, - char *warn_name, bool *error_arg) +bool get_mysql_time_from_str(THD *thd, String *str, timestamp_type warn_type, + const char *warn_name, MYSQL_TIME *l_time) { - ulonglong value= 0; + bool value; int error; - MYSQL_TIME l_time; - enum_mysql_timestamp_type ret; + enum_mysql_timestamp_type timestamp_type; - ret= str_to_datetime(str->ptr(), str->length(), &l_time, - (TIME_FUZZY_DATE | MODE_INVALID_DATES | - (thd->variables.sql_mode & - (MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE))), - &error); + timestamp_type= + str_to_datetime(str->ptr(), str->length(), l_time, + (TIME_FUZZY_DATE | MODE_INVALID_DATES | + (thd->variables.sql_mode & + (MODE_NO_ZERO_IN_DATE | MODE_NO_ZERO_DATE))), + &error); - if (ret == MYSQL_TIMESTAMP_DATETIME || ret == MYSQL_TIMESTAMP_DATE) - { + if (timestamp_type == MYSQL_TIMESTAMP_DATETIME || + timestamp_type == MYSQL_TIMESTAMP_DATE) /* Do not return yet, we may still want to throw a "trailing garbage" warning. */ - *error_arg= FALSE; - value= TIME_to_ulonglong_datetime(&l_time); - } + value= FALSE; else { - *error_arg= TRUE; + value= TRUE; error= 1; /* force warning */ } @@ -698,6 +693,37 @@ get_date_from_str(THD *thd, String *str, timestamp_type warn_type, } +/** + @brief Convert date provided in a string to the int representation. + + @param[in] thd thread handle + @param[in] str a string to convert + @param[in] warn_type type of the timestamp for issuing the warning + @param[in] warn_name field name for issuing the warning + @param[out] error_arg could not extract a DATE or DATETIME + + @details Convert date provided in the string str to the int + representation. If the string contains wrong date or doesn't + contain it at all then a warning is issued. The warn_type and + the warn_name arguments are used as the name and the type of the + field when issuing the warning. + + @return + converted value. 0 on error and on zero-dates -- check 'failure' +*/ +static ulonglong get_date_from_str(THD *thd, String *str, + timestamp_type warn_type, + const char *warn_name, bool *error_arg) +{ + MYSQL_TIME l_time; + *error_arg= get_mysql_time_from_str(thd, str, warn_type, warn_name, &l_time); + + if (*error_arg) + return 0; + return TIME_to_ulonglong_datetime(&l_time); +} + + /* Check whether compare_datetime() can be used to compare items. @@ -1559,61 +1585,73 @@ longlong Item_in_optimizer::val_int() if (cache->null_value) { + /* + We're evaluating + "<outer_value_list> [NOT] IN (SELECT <inner_value_list>...)" + where one or more of the outer values is NULL. + */ if (((Item_in_subselect*)args[1])->is_top_level_item()) { /* - We're evaluating "NULL IN (SELECT ...)". The result can be NULL or - FALSE, and we can return one instead of another. Just return NULL. + We're evaluating a top level item, e.g. + "<outer_value_list> IN (SELECT <inner_value_list>...)", + and in this case a NULL value in the outer_value_list means + that the result shall be NULL/FALSE (makes no difference for + top level items). The cached value is NULL, so just return + NULL. */ null_value= 1; } else { - if (!((Item_in_subselect*)args[1])->is_correlated && - result_for_null_param != UNKNOWN) + /* + We're evaluating an item where a NULL value in either the + outer or inner value list does not automatically mean that we + can return NULL/FALSE. An example of such a query is + "<outer_value_list> NOT IN (SELECT <inner_value_list>...)" + The result when there is at least one NULL value is: NULL if the + SELECT evaluated over the non-NULL values produces at least + one row, FALSE otherwise + */ + Item_in_subselect *item_subs=(Item_in_subselect*)args[1]; + bool all_left_cols_null= true; + const uint ncols= cache->cols(); + + /* + Turn off the predicates that are based on column compares for + which the left part is currently NULL + */ + for (uint i= 0; i < ncols; i++) { - /* Use cached value from previous execution */ - null_value= result_for_null_param; + if (cache->element_index(i)->null_value) + item_subs->set_cond_guard_var(i, FALSE); + else + all_left_cols_null= false; } - else + + if (!((Item_in_subselect*)args[1])->is_correlated && + all_left_cols_null && result_for_null_param != UNKNOWN) { - /* - We're evaluating "NULL IN (SELECT ...)". The result is: - FALSE if SELECT produces an empty set, or - NULL otherwise. - We disable the predicates we've pushed down into subselect, run the - subselect and see if it has produced any rows. + /* + This is a non-correlated subquery, all values in the outer + value list are NULL, and we have already evaluated the + subquery for all NULL values: Return the same result we + did last time without evaluating the subquery. */ - Item_in_subselect *item_subs=(Item_in_subselect*)args[1]; - if (cache->cols() == 1) - { - item_subs->set_cond_guard_var(0, FALSE); - (void) args[1]->val_bool_result(); - result_for_null_param= null_value= !item_subs->engine->no_rows(); - item_subs->set_cond_guard_var(0, TRUE); - } - else - { - uint i; - uint ncols= cache->cols(); - /* - Turn off the predicates that are based on column compares for - which the left part is currently NULL - */ - for (i= 0; i < ncols; i++) - { - if (cache->element_index(i)->null_value) - item_subs->set_cond_guard_var(i, FALSE); - } - - (void) args[1]->val_bool_result(); - result_for_null_param= null_value= !item_subs->engine->no_rows(); - - /* Turn all predicates back on */ - for (i= 0; i < ncols; i++) - item_subs->set_cond_guard_var(i, TRUE); - } + null_value= result_for_null_param; + } + else + { + /* The subquery has to be evaluated */ + (void) args[1]->val_bool_result(); + null_value= !item_subs->engine->no_rows(); + if (all_left_cols_null) + result_for_null_param= null_value; } + + /* Turn all predicates back on */ + for (uint i= 0; i < ncols; i++) + item_subs->set_cond_guard_var(i, TRUE); } return 0; } @@ -2191,7 +2229,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 precision; + return min(precision, DECIMAL_MAX_PRECISION); } @@ -2375,7 +2413,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 precision; + return min(precision, DECIMAL_MAX_PRECISION); } @@ -2783,7 +2821,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 max_int_part + decimals; + return min(max_int_part + decimals, DECIMAL_MAX_PRECISION); } diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 3462bed94a2..ec703d0a9f9 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -1725,4 +1725,6 @@ inline Item *and_conds(Item *a, Item *b) Item *and_expressions(Item *a, Item *b, Item **org_item); +bool get_mysql_time_from_str(THD *thd, String *str, timestamp_type warn_type, + const char *warn_name, MYSQL_TIME *l_time); #endif /* ITEM_CMPFUNC_INCLUDED */ diff --git a/sql/item_func.cc b/sql/item_func.cc index d9e6f76dd6b..ac52f36474a 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -451,8 +451,45 @@ Field *Item_func::tmp_table_field(TABLE *table) return make_string_field(table); break; case DECIMAL_RESULT: - field= Field_new_decimal::new_decimal_field(this); + { + 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); break; + } case ROW_RESULT: default: // This case should never be chosen @@ -4739,19 +4776,6 @@ 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); diff --git a/sql/item_func.h b/sql/item_func.h index 628878bcaed..6f2b3f0bfc2 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -1396,7 +1396,6 @@ 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_geofunc.cc b/sql/item_geofunc.cc index a34204b7181..3c5990eb359 100644 --- a/sql/item_geofunc.cc +++ b/sql/item_geofunc.cc @@ -84,7 +84,9 @@ String *Item_func_geometry_from_wkb::val_str(String *str) if (args[0]->field_type() == MYSQL_TYPE_GEOMETRY) { - return args[0]->val_str(str); + String *str_ret= args[0]->val_str(str); + null_value= args[0]->null_value; + return str_ret; } wkb= args[0]->val_str(&arg_val); @@ -94,7 +96,10 @@ String *Item_func_geometry_from_wkb::val_str(String *str) str->set_charset(&my_charset_bin); if (str->reserve(SRID_SIZE, 512)) - return 0; + { + null_value= TRUE; /* purecov: inspected */ + return 0; /* purecov: inspected */ + } str->length(0); str->q_append(srid); if ((null_value= diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index da651cec70c..fa776ea3dca 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -311,9 +311,14 @@ void Item_subselect::update_used_tables() void Item_subselect::print(String *str, enum_query_type query_type) { - str->append('('); - engine->print(str, query_type); - str->append(')'); + if (engine) + { + str->append('('); + engine->print(str, query_type); + str->append(')'); + } + else + str->append("(...)"); } @@ -1949,6 +1954,7 @@ int subselect_single_select_engine::exec() tab->read_record.record= tab->table->record[0]; tab->read_record.thd= join->thd; tab->read_record.ref_length= tab->table->file->ref_length; + tab->read_record.unlock_row= rr_unlock_row; *(last_changed_tab++)= tab; break; } diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 08a48c6ce2f..38251294053 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -517,7 +517,8 @@ Field *Item_sum::create_tmp_field(bool group, TABLE *table, name, table->s, collation.collation); break; case DECIMAL_RESULT: - field= Field_new_decimal::new_decimal_field(this); + field= new Field_new_decimal(max_length, maybe_null, name, + decimals, unsigned_flag); break; case ROW_RESULT: default: diff --git a/sql/log.cc b/sql/log.cc index 1ffb2e8b5c3..3d863583859 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -1579,7 +1579,6 @@ static int binlog_commit(handlerton *hton, THD *thd, bool all) trx_data->at_least_one_stmt_committed = my_b_tell(&trx_data->trans_log) > 0; -end: if (!all) trx_data->before_stmt_pos = MY_OFF_T_UNDEF; // part of the stmt commit DBUG_RETURN(error); @@ -1747,7 +1746,7 @@ static int binlog_savepoint_set(handlerton *hton, THD *thd, void *sv) int errcode= query_error_code(thd, thd->killed == THD::NOT_KILLED); int const error= thd->binlog_query(THD::STMT_QUERY_TYPE, - thd->query, thd->query_length, TRUE, FALSE, errcode); + thd->query(), thd->query_length(), TRUE, FALSE, errcode); DBUG_RETURN(error); } @@ -1766,7 +1765,7 @@ static int binlog_savepoint_rollback(handlerton *hton, THD *thd, void *sv) int errcode= query_error_code(thd, thd->killed == THD::NOT_KILLED); int error= thd->binlog_query(THD::STMT_QUERY_TYPE, - thd->query, thd->query_length, TRUE, FALSE, errcode); + thd->query(), thd->query_length(), TRUE, FALSE, errcode); DBUG_RETURN(error); } binlog_trans_log_truncate(thd, *(my_off_t*)sv); @@ -3689,7 +3688,7 @@ void MYSQL_BIN_LOG::new_file_impl(bool need_lock) } old_name=name; name=0; // Don't free name - close(LOG_CLOSE_TO_BE_OPENED); + close(LOG_CLOSE_TO_BE_OPENED | LOG_CLOSE_INDEX); /* Note that at this point, log_state != LOG_CLOSED (important for is_open()). @@ -3704,8 +3703,10 @@ void MYSQL_BIN_LOG::new_file_impl(bool need_lock) trigger temp tables deletion on slaves. */ - open(old_name, log_type, new_name_ptr, - io_cache_type, no_auto_events, max_size, 1); + /* reopen index binlog file, BUG#34582 */ + if (!open_index_file(index_file_name, 0)) + open(old_name, log_type, new_name_ptr, + io_cache_type, no_auto_events, max_size, 1); my_free(old_name,MYF(0)); end: diff --git a/sql/log_event.cc b/sql/log_event.cc index d36b126fd2e..060b675b0e4 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -3059,7 +3059,7 @@ int Query_log_event::do_apply_event(Relay_log_info const *rli, thd->query_id = next_query_id(); VOID(pthread_mutex_unlock(&LOCK_thread_count)); thd->variables.pseudo_thread_id= thread_id; // for temp tables - DBUG_PRINT("query",("%s",thd->query)); + DBUG_PRINT("query",("%s", thd->query())); if (ignored_error_code((expected_error= error_code)) || !unexpected_error_code(expected_error)) @@ -3153,7 +3153,7 @@ int Query_log_event::do_apply_event(Relay_log_info const *rli, /* Execute the query (note that we bypass dispatch_command()) */ const char* found_semicolon= NULL; - mysql_parse(thd, thd->query, thd->query_length, &found_semicolon); + mysql_parse(thd, thd->query(), thd->query_length(), &found_semicolon); log_slow_statement(thd); } else @@ -3165,7 +3165,7 @@ int Query_log_event::do_apply_event(Relay_log_info const *rli, we exit gracefully; otherwise we warn about the bad error and tell DBA to check/fix it. */ - if (mysql_test_parse_for_slave(thd, thd->query, thd->query_length)) + if (mysql_test_parse_for_slave(thd, thd->query(), thd->query_length())) clear_all_errors(thd, const_cast<Relay_log_info*>(rli)); /* Can ignore query */ else { @@ -3175,7 +3175,7 @@ Query partially completed on the master (error on master: %d) \ and was aborted. There is a chance that your master is inconsistent at this \ point. If you are sure that your master is ok, run this query manually on the \ slave and then restart the slave with SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1; \ -START SLAVE; . Query: '%s'", expected_error, thd->query); +START SLAVE; . Query: '%s'", expected_error, thd->query()); thd->is_slave_error= 1; } goto end; @@ -3183,7 +3183,7 @@ START SLAVE; . Query: '%s'", expected_error, thd->query); /* If the query was not ignored, it is printed to the general log */ if (!thd->is_error() || thd->main_da.sql_errno() != ER_SLAVE_IGNORED_TABLE) - general_log_write(thd, COM_QUERY, thd->query, thd->query_length); + general_log_write(thd, COM_QUERY, thd->query(), thd->query_length()); compare_errors: @@ -4530,8 +4530,8 @@ int Load_log_event::do_apply_event(NET* net, 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); - DBUG_ASSERT(thd->query == 0); - thd->query_length= 0; // Should not be needed + DBUG_ASSERT(thd->query() == 0); + thd->set_query_inner(NULL, 0); // Should not be needed thd->is_slave_error= 0; clear_all_errors(thd, const_cast<Relay_log_info*>(rli)); @@ -7555,7 +7555,7 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli) } if (get_flags(STMT_END_F)) - if (error= rows_event_stmt_cleanup(rli, thd)) + if ((error= rows_event_stmt_cleanup(rli, thd))) rli->report(ERROR_LEVEL, error, "Error in %s event: commit of row events failed, " "table `%s`.`%s`", diff --git a/sql/log_event_old.cc b/sql/log_event_old.cc index 18e5284490c..7ed36ed33b0 100644 --- a/sql/log_event_old.cc +++ b/sql/log_event_old.cc @@ -1814,7 +1814,7 @@ int Old_rows_log_event::do_apply_event(Relay_log_info const *rli) are involved, commit the transaction and flush the pending event to the binlog. */ - if (error= ha_autocommit_or_rollback(thd, 0)) + if ((error= ha_autocommit_or_rollback(thd, 0))) rli->report(ERROR_LEVEL, error, "Error in %s event: commit of row events failed, " "table `%s`.`%s`", diff --git a/sql/my_decimal.h b/sql/my_decimal.h index b1df1395dcd..21669e82c44 100644 --- a/sql/my_decimal.h +++ b/sql/my_decimal.h @@ -48,12 +48,10 @@ 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 @@ -77,6 +75,12 @@ 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. @@ -180,7 +184,7 @@ inline uint my_decimal_length_to_precision(uint length, uint scale, } inline uint32 my_decimal_precision_to_length_no_truncation(uint precision, - uint scale, + uint8 scale, bool unsigned_flag) { /* @@ -192,7 +196,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, uint scale, +inline uint32 my_decimal_precision_to_length(uint precision, uint8 scale, bool unsigned_flag) { /* diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 035ab0e70cc..8468e7cf79a 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -1718,7 +1718,7 @@ static void network_init(void) saPipeSecurity.lpSecurityDescriptor = &sdPipeDescriptor; saPipeSecurity.bInheritHandle = FALSE; if ((hPipe= CreateNamedPipe(pipe_name, - PIPE_ACCESS_DUPLEX, + PIPE_ACCESS_DUPLEX|FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, @@ -2521,7 +2521,7 @@ terribly wrong...\n"); } fprintf(stderr, "Trying to get some variables.\n\ Some pointers may be invalid and cause the dump to abort...\n"); - my_safe_print_str("thd->query", thd->query, 1024); + my_safe_print_str("thd->query", thd->query(), 1024); fprintf(stderr, "thd->thread_id=%lu\n", (ulong) thd->thread_id); fprintf(stderr, "thd->killed=%s\n", kreason); } @@ -5205,17 +5205,26 @@ pthread_handler_t handle_connections_sockets(void *arg __attribute__((unused))) pthread_handler_t handle_connections_namedpipes(void *arg) { HANDLE hConnectedPipe; - BOOL fConnected; + OVERLAPPED connectOverlapped = {0}; THD *thd; my_thread_init(); DBUG_ENTER("handle_connections_namedpipes"); - (void) my_pthread_getprio(pthread_self()); // For debugging + connectOverlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); DBUG_PRINT("general",("Waiting for named pipe connections.")); while (!abort_loop) { /* wait for named pipe connection */ - fConnected = ConnectNamedPipe(hPipe, NULL); + BOOL fConnected= ConnectNamedPipe(hPipe, &connectOverlapped); + if (!fConnected && (GetLastError() == ERROR_IO_PENDING)) + { + /* + ERROR_IO_PENDING says async IO has started but not yet finished. + GetOverlappedResult will wait for completion. + */ + DWORD bytes; + fConnected= GetOverlappedResult(hPipe, &connectOverlapped,&bytes, TRUE); + } if (abort_loop) break; if (!fConnected) @@ -5224,7 +5233,7 @@ pthread_handler_t handle_connections_namedpipes(void *arg) { CloseHandle(hPipe); if ((hPipe= CreateNamedPipe(pipe_name, - PIPE_ACCESS_DUPLEX, + PIPE_ACCESS_DUPLEX|FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, @@ -5244,7 +5253,7 @@ pthread_handler_t handle_connections_namedpipes(void *arg) hConnectedPipe = hPipe; /* create new pipe for new connection */ if ((hPipe = CreateNamedPipe(pipe_name, - PIPE_ACCESS_DUPLEX, + PIPE_ACCESS_DUPLEX|FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, @@ -5266,7 +5275,7 @@ pthread_handler_t handle_connections_namedpipes(void *arg) CloseHandle(hConnectedPipe); continue; } - if (!(thd->net.vio = vio_new_win32pipe(hConnectedPipe)) || + if (!(thd->net.vio= vio_new_win32pipe(hConnectedPipe)) || my_net_init(&thd->net, thd->net.vio)) { close_connection(thd, ER_OUT_OF_RESOURCES, 1); @@ -5277,7 +5286,7 @@ pthread_handler_t handle_connections_namedpipes(void *arg) thd->security_ctx->host= my_strdup(my_localhost, MYF(0)); create_new_thread(thd); } - + CloseHandle(connectOverlapped.hEvent); decrement_handler_count(); DBUG_RETURN(0); } @@ -5454,8 +5463,7 @@ pthread_handler_t handle_connections_shared_memory(void *arg) errmsg= "Could not set client to read mode"; goto errorconn; } - if (!(thd->net.vio= vio_new_win32shared_memory(&thd->net, - handle_client_file_map, + if (!(thd->net.vio= vio_new_win32shared_memory(handle_client_file_map, handle_client_map, event_client_wrote, event_client_read, diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 119f90bc97a..5f9bae22c70 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -5709,6 +5709,27 @@ get_mm_leaf(RANGE_OPT_PARAM *param, COND *conf_func, Field *field, !(conf_func->compare_collation()->state & MY_CS_BINSORT)) goto end; + if (key_part->image_type == Field::itMBR) + { + switch (type) { + case Item_func::SP_EQUALS_FUNC: + case Item_func::SP_DISJOINT_FUNC: + case Item_func::SP_INTERSECTS_FUNC: + case Item_func::SP_TOUCHES_FUNC: + case Item_func::SP_CROSSES_FUNC: + case Item_func::SP_WITHIN_FUNC: + case Item_func::SP_CONTAINS_FUNC: + case Item_func::SP_OVERLAPS_FUNC: + break; + default: + /* + We cannot involve spatial indexes for queries that + don't use MBREQUALS(), MBRDISJOINT(), etc. functions. + */ + goto end; + } + } + if (param->using_real_indexes) optimize_range= field->optimize_range(param->real_keynr[key_part->key], key_part->part); @@ -5891,6 +5912,17 @@ get_mm_leaf(RANGE_OPT_PARAM *param, COND *conf_func, Field *field, goto end; } field->table->in_use->variables.sql_mode= orig_sql_mode; + + /* + Any sargable predicate except "<=>" involving NULL as a constant is always + FALSE + */ + if (type != Item_func::EQUAL_FUNC && field->is_real_null()) + { + tree= &null_element; + goto end; + } + str= (uchar*) alloc_root(alloc, key_part->store_length+1); if (!str) goto end; @@ -5936,7 +5968,7 @@ get_mm_leaf(RANGE_OPT_PARAM *param, COND *conf_func, Field *field, switch (type) { case Item_func::LT_FUNC: - if (stored_field_cmp_to_item(field,value) == 0) + if (stored_field_cmp_to_item(param->thd, field, value) == 0) tree->max_flag=NEAR_MAX; /* fall through */ case Item_func::LE_FUNC: @@ -5951,14 +5983,14 @@ get_mm_leaf(RANGE_OPT_PARAM *param, COND *conf_func, Field *field, case Item_func::GT_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)) + (stored_field_cmp_to_item(param->thd, field, value) <= 0)) tree->min_flag=NEAR_MIN; 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)) + (stored_field_cmp_to_item(param->thd, field, value) < 0)) tree->min_flag= NEAR_MIN; tree->max_flag=NO_MAX_RANGE; break; diff --git a/sql/records.cc b/sql/records.cc index 9e040de3fda..b6faf0227f9 100644 --- a/sql/records.cc +++ b/sql/records.cc @@ -57,10 +57,12 @@ void init_read_record_idx(READ_RECORD *info, THD *thd, TABLE *table, { empty_record(table); bzero((char*) info,sizeof(*info)); + info->thd= thd; info->table= table; info->file= table->file; info->record= table->record[0]; info->print_error= print_error; + info->unlock_row= rr_unlock_row; table->status=0; /* And it's always found */ if (!table->file->inited) @@ -186,6 +188,7 @@ void init_read_record(READ_RECORD *info,THD *thd, TABLE *table, } info->select=select; info->print_error=print_error; + info->unlock_row= rr_unlock_row; info->ignore_not_found_rows= 0; table->status=0; /* And it's always found */ @@ -292,6 +295,12 @@ void end_read_record(READ_RECORD *info) static int rr_handle_error(READ_RECORD *info, int error) { + if (info->thd->killed) + { + info->thd->send_kill_message(); + return 1; + } + if (error == HA_ERR_END_OF_FILE) error= -1; else @@ -312,12 +321,7 @@ static int rr_quick(READ_RECORD *info) int tmp; while ((tmp= info->select->quick->get_next())) { - if (info->thd->killed) - { - my_error(ER_SERVER_SHUTDOWN, MYF(0)); - return 1; - } - if (tmp != HA_ERR_RECORD_DELETED) + if (info->thd->killed || (tmp != HA_ERR_RECORD_DELETED)) { tmp= rr_handle_error(info, tmp); break; @@ -380,16 +384,11 @@ int rr_sequential(READ_RECORD *info) int tmp; while ((tmp=info->file->rnd_next(info->record))) { - if (info->thd->killed) - { - info->thd->send_kill_message(); - return 1; - } /* rnd_next can return RECORD_DELETED for MyISAM when one thread is reading and another deleting without locks. */ - if (tmp != HA_ERR_RECORD_DELETED) + if (info->thd->killed || (tmp != HA_ERR_RECORD_DELETED)) { tmp= rr_handle_error(info, tmp); break; diff --git a/sql/slave.cc b/sql/slave.cc index 8e69066ed9b..40b476e4f17 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -1458,6 +1458,199 @@ network_err: DBUG_RETURN(2); } +/* + Used by fetch_master_table (used by LOAD TABLE tblname FROM MASTER and LOAD + DATA FROM MASTER). Drops the table (if 'overwrite' is true) and recreates it + from the dump. Honours replication inclusion/exclusion rules. + db must be non-zero (guarded by assertion). + + RETURN VALUES + 0 success + 1 error +*/ + +static int create_table_from_dump(THD* thd, MYSQL *mysql, const char* db, + const char* table_name, bool overwrite) +{ + ulong packet_len; + char *query, *save_db; + uint32 save_db_length; + Vio* save_vio; + HA_CHECK_OPT check_opt; + TABLE_LIST tables; + int error= 1; + handler *file; + ulonglong save_options; + NET *net= &mysql->net; + const char *found_semicolon= NULL; + DBUG_ENTER("create_table_from_dump"); + + packet_len= my_net_read(net); // read create table statement + if (packet_len == packet_error) + { + my_message(ER_MASTER_NET_READ, ER(ER_MASTER_NET_READ), MYF(0)); + DBUG_RETURN(1); + } + if (net->read_pos[0] == 255) // error from master + { + char *err_msg; + err_msg= (char*) net->read_pos + ((mysql->server_capabilities & + CLIENT_PROTOCOL_41) ? + 3+SQLSTATE_LENGTH+1 : 3); + my_error(ER_MASTER, MYF(0), err_msg); + DBUG_RETURN(1); + } + thd->command = COM_TABLE_DUMP; + if (!(query = thd->strmake((char*) net->read_pos, packet_len))) + { + sql_print_error("create_table_from_dump: out of memory"); + my_message(ER_GET_ERRNO, "Out of memory", MYF(0)); + DBUG_RETURN(1); + } + thd->set_query(query, packet_len); + thd->is_slave_error = 0; + + bzero((char*) &tables,sizeof(tables)); + tables.db = (char*)db; + tables.alias= tables.table_name= (char*)table_name; + + /* Drop the table if 'overwrite' is true */ + if (overwrite) + { + if (mysql_rm_table(thd,&tables,1,0)) /* drop if exists */ + { + sql_print_error("create_table_from_dump: failed to drop the table"); + goto err; + } + else + { + /* Clear the OK result of mysql_rm_table(). */ + thd->main_da.reset_diagnostics_area(); + } + } + + /* Create the table. We do not want to log the "create table" statement */ + save_options = thd->options; + thd->options &= ~ (OPTION_BIN_LOG); + thd_proc_info(thd, "Creating table from master dump"); + // save old db in case we are creating in a different database + save_db = thd->db; + save_db_length= thd->db_length; + thd->db = (char*)db; + DBUG_ASSERT(thd->db != 0); + thd->db_length= strlen(thd->db); + /* run create table */ + mysql_parse(thd, thd->query(), packet_len, &found_semicolon); + thd->db = save_db; // leave things the way the were before + thd->db_length= save_db_length; + thd->options = save_options; + + if (thd->is_slave_error) + goto err; // mysql_parse took care of the error send + + thd_proc_info(thd, "Opening master dump table"); + thd->main_da.reset_diagnostics_area(); /* cleanup from CREATE_TABLE */ + /* + Note: If this function starts to fail for MERGE tables, + change the next two lines to these: + tables.table= NULL; // was set by mysql_rm_table() + if (!open_n_lock_single_table(thd, &tables, TL_WRITE)) + */ + tables.lock_type = TL_WRITE; + if (!open_ltable(thd, &tables, TL_WRITE, 0)) + { + sql_print_error("create_table_from_dump: could not open created table"); + goto err; + } + + file = tables.table->file; + thd_proc_info(thd, "Reading master dump table data"); + /* Copy the data file */ + if (file->net_read_dump(net)) + { + my_message(ER_MASTER_NET_READ, ER(ER_MASTER_NET_READ), MYF(0)); + sql_print_error("create_table_from_dump: failed in\ + handler::net_read_dump()"); + goto err; + } + + check_opt.init(); + check_opt.flags|= T_VERY_SILENT | T_CALC_CHECKSUM | T_QUICK; + thd_proc_info(thd, "Rebuilding the index on master dump table"); + /* + We do not want repair() to spam us with messages + just send them to the error log, and report the failure in case of + problems. + */ + save_vio = thd->net.vio; + thd->net.vio = 0; + /* Rebuild the index file from the copied data file (with REPAIR) */ + error=file->ha_repair(thd,&check_opt) != 0; + thd->net.vio = save_vio; + if (error) + my_error(ER_INDEX_REBUILD, MYF(0), tables.table->s->table_name.str); + +err: + close_thread_tables(thd); + DBUG_RETURN(error); +} + + +int fetch_master_table(THD *thd, const char *db_name, const char *table_name, + Master_info *mi, MYSQL *mysql, bool overwrite) +{ + int error= 1; + const char *errmsg=0; + bool called_connected= (mysql != NULL); + DBUG_ENTER("fetch_master_table"); + DBUG_PRINT("enter", ("db_name: '%s' table_name: '%s'", + db_name,table_name)); + + if (!called_connected) + { + if (!(mysql = mysql_init(NULL))) + { + DBUG_RETURN(1); + } + if (connect_to_master(thd, mysql, mi)) + { + my_error(ER_CONNECT_TO_MASTER, MYF(0), mysql_error(mysql)); + /* + We need to clear the active VIO since, theoretically, somebody + might issue an awake() on this thread. If we are then in the + middle of closing and destroying the VIO inside the + mysql_close(), we will have a problem. + */ +#ifdef SIGNAL_WITH_VIO_CLOSE + thd->clear_active_vio(); +#endif + mysql_close(mysql); + DBUG_RETURN(1); + } + if (thd->killed) + goto err; + } + + if (request_table_dump(mysql, db_name, table_name)) + { + error= ER_UNKNOWN_ERROR; + errmsg= "Failed on table dump request"; + goto err; + } + if (create_table_from_dump(thd, mysql, db_name, + table_name, overwrite)) + goto err; // create_table_from_dump have sent the error already + error = 0; + + err: + if (!called_connected) + mysql_close(mysql); + if (errmsg && thd->vio_ok()) + my_message(error, errmsg, MYF(0)); + DBUG_RETURN(test(error)); // Return 1 on error +} + + static bool wait_for_relay_log_space(Relay_log_info* rli) { bool slave_killed=0; diff --git a/sql/sp.cc b/sql/sp.cc index 4d840f53e2f..fd420732628 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -997,7 +997,7 @@ sp_drop_routine(THD *thd, int type, sp_name *name) if (ret == SP_OK) { - write_bin_log(thd, TRUE, thd->query, thd->query_length); + write_bin_log(thd, TRUE, thd->query(), thd->query_length()); sp_cache_invalidate(); } @@ -1067,7 +1067,7 @@ sp_update_routine(THD *thd, int type, sp_name *name, st_sp_chistics *chistics) if (ret == SP_OK) { - write_bin_log(thd, TRUE, thd->query, thd->query_length); + write_bin_log(thd, TRUE, thd->query(), thd->query_length()); sp_cache_invalidate(); } diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 8ab91222bcc..6a0ab4bfc46 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -332,16 +332,18 @@ bool sp_eval_expr(THD *thd, Field *result_field, Item **expr_item_ptr) { Item *expr_item; + enum_check_fields save_count_cuted_fields= thd->count_cuted_fields; + bool save_abort_on_warning= thd->abort_on_warning; + bool save_stmt_modified_non_trans_table= + thd->transaction.stmt.modified_non_trans_table; DBUG_ENTER("sp_eval_expr"); if (!*expr_item_ptr) - DBUG_RETURN(TRUE); + goto error; if (!(expr_item= sp_prepare_func_item(thd, expr_item_ptr))) - DBUG_RETURN(TRUE); - - bool err_status= FALSE; + goto error; /* Set THD flags to emit warnings/errors in case of overflow/type errors @@ -350,10 +352,6 @@ sp_eval_expr(THD *thd, Field *result_field, Item **expr_item_ptr) Save original values and restore them after save. */ - enum_check_fields save_count_cuted_fields= thd->count_cuted_fields; - bool save_abort_on_warning= thd->abort_on_warning; - bool save_stmt_modified_non_trans_table= thd->transaction.stmt.modified_non_trans_table; - thd->count_cuted_fields= CHECK_FIELD_ERROR_FOR_NULL; thd->abort_on_warning= thd->variables.sql_mode & @@ -368,13 +366,18 @@ sp_eval_expr(THD *thd, Field *result_field, Item **expr_item_ptr) thd->abort_on_warning= save_abort_on_warning; thd->transaction.stmt.modified_non_trans_table= save_stmt_modified_non_trans_table; - if (thd->is_error()) - { - /* Return error status if something went wrong. */ - err_status= TRUE; - } + if (!thd->is_error()) + DBUG_RETURN(FALSE); - DBUG_RETURN(err_status); +error: + /* + In case of error during evaluation, leave the result field set to NULL. + Sic: we can't do it in the beginning of the function because the + result field might be needed for its own re-evaluation, e.g. case of + set x = x + 1; + */ + result_field->set_null(); + DBUG_RETURN (TRUE); } @@ -2824,8 +2827,8 @@ sp_instr_stmt::execute(THD *thd, uint *nextp) DBUG_ENTER("sp_instr_stmt::execute"); DBUG_PRINT("info", ("command: %d", m_lex_keeper.sql_command())); - query= thd->query; - query_length= thd->query_length; + query= thd->query(); + query_length= thd->query_length(); #if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER) /* This s-p instr is profilable and will be captured. */ thd->profiling.set_query_source(m_query.str, m_query.length); @@ -2838,10 +2841,11 @@ sp_instr_stmt::execute(THD *thd, uint *nextp) queries with SP vars can't be cached) */ if (unlikely((thd->options & OPTION_LOG_OFF)==0)) - general_log_write(thd, COM_QUERY, thd->query, thd->query_length); + general_log_write(thd, COM_QUERY, thd->query(), thd->query_length()); if (query_cache_send_result_to_client(thd, - thd->query, thd->query_length) <= 0) + thd->query(), + thd->query_length()) <= 0) { res= m_lex_keeper.reset_lex_and_exec_core(thd, nextp, FALSE, this); diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index d7d662f912d..0592bb3be1d 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -263,8 +263,7 @@ my_bool acl_init(bool dont_read_acl_tables) acl_cache= new hash_filo(ACL_CACHE_SIZE, 0, 0, (hash_get_key) acl_entry_get_key, (hash_free_key) free, - lower_case_file_system ? - system_charset_info : &my_charset_bin); + &my_charset_utf8_bin); if (dont_read_acl_tables) { DBUG_RETURN(0); /* purecov: tested */ @@ -2251,10 +2250,13 @@ public: ulong sort; size_t key_length; GRANT_NAME(const char *h, const char *d,const char *u, - const char *t, ulong p); - GRANT_NAME (TABLE *form); + const char *t, ulong p, bool is_routine); + GRANT_NAME (TABLE *form, bool is_routine); virtual ~GRANT_NAME() {}; virtual bool ok() { return privs != 0; } + void set_user_details(const char *h, const char *d, + const char *u, const char *t, + bool is_routine); }; @@ -2272,38 +2274,48 @@ public: }; - -GRANT_NAME::GRANT_NAME(const char *h, const char *d,const char *u, - const char *t, ulong p) - :privs(p) +void GRANT_NAME::set_user_details(const char *h, const char *d, + const char *u, const char *t, + bool is_routine) { /* Host given by user */ update_hostname(&host, strdup_root(&memex, h)); - db = strdup_root(&memex,d); + if (db != d) + { + db= strdup_root(&memex, d); + if (lower_case_table_names) + my_casedn_str(files_charset_info, db); + } user = strdup_root(&memex,u); sort= get_sort(3,host.hostname,db,user); - tname= strdup_root(&memex,t); - if (lower_case_table_names) + if (tname != t) { - my_casedn_str(files_charset_info, db); - my_casedn_str(files_charset_info, tname); + tname= strdup_root(&memex, t); + if (lower_case_table_names || is_routine) + my_casedn_str(files_charset_info, tname); } key_length= strlen(d) + strlen(u)+ strlen(t)+3; hash_key= (char*) alloc_root(&memex,key_length); strmov(strmov(strmov(hash_key,user)+1,db)+1,tname); } +GRANT_NAME::GRANT_NAME(const char *h, const char *d,const char *u, + const char *t, ulong p, bool is_routine) + :db(0), tname(0), privs(p) +{ + set_user_details(h, d, u, t, is_routine); +} GRANT_TABLE::GRANT_TABLE(const char *h, const char *d,const char *u, const char *t, ulong p, ulong c) - :GRANT_NAME(h,d,u,t,p), cols(c) + :GRANT_NAME(h,d,u,t,p, FALSE), cols(c) { (void) hash_init2(&hash_columns,4,system_charset_info, 0,0,0, (hash_get_key) get_key_column,0,0); } -GRANT_NAME::GRANT_NAME(TABLE *form) +GRANT_NAME::GRANT_NAME(TABLE *form, bool is_routine) { update_hostname(&host, get_field(&memex, form->field[0])); db= get_field(&memex,form->field[1]); @@ -2321,6 +2333,9 @@ GRANT_NAME::GRANT_NAME(TABLE *form) if (lower_case_table_names) { my_casedn_str(files_charset_info, db); + } + if (lower_case_table_names || is_routine) + { my_casedn_str(files_charset_info, tname); } key_length= (strlen(db) + strlen(user) + strlen(tname) + 3); @@ -2332,7 +2347,7 @@ GRANT_NAME::GRANT_NAME(TABLE *form) GRANT_TABLE::GRANT_TABLE(TABLE *form, TABLE *col_privs) - :GRANT_NAME(form) + :GRANT_NAME(form, FALSE) { uchar key[MAX_KEY_LENGTH]; @@ -3184,7 +3199,7 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list, if (!result) /* success */ { - write_bin_log(thd, TRUE, thd->query, thd->query_length); + write_bin_log(thd, TRUE, thd->query(), thd->query_length()); } rw_unlock(&LOCK_grant); @@ -3327,7 +3342,7 @@ bool mysql_routine_grant(THD *thd, TABLE_LIST *table_list, bool is_proc, } grant_name= new GRANT_NAME(Str->host.str, db_name, Str->user.str, table_name, - rights); + rights, TRUE); if (!grant_name) { result= TRUE; @@ -3349,7 +3364,7 @@ bool mysql_routine_grant(THD *thd, TABLE_LIST *table_list, bool is_proc, if (write_to_binlog) { - write_bin_log(thd, TRUE, thd->query, thd->query_length); + write_bin_log(thd, TRUE, thd->query(), thd->query_length()); } rw_unlock(&LOCK_grant); @@ -3461,7 +3476,7 @@ bool mysql_grant(THD *thd, const char *db, List <LEX_USER> &list, if (!result) { - write_bin_log(thd, TRUE, thd->query, thd->query_length); + write_bin_log(thd, TRUE, thd->query(), thd->query_length()); } rw_unlock(&LOCK_grant); @@ -3538,10 +3553,10 @@ static my_bool grant_load_procs_priv(TABLE *p_table) MEM_ROOT **save_mem_root_ptr= my_pthread_getspecific_ptr(MEM_ROOT**, THR_MALLOC); DBUG_ENTER("grant_load_procs_priv"); - (void) hash_init(&proc_priv_hash,system_charset_info, + (void) hash_init(&proc_priv_hash, &my_charset_utf8_bin, 0,0,0, (hash_get_key) get_grant_table, 0,0); - (void) hash_init(&func_priv_hash,system_charset_info, + (void) hash_init(&func_priv_hash, &my_charset_utf8_bin, 0,0,0, (hash_get_key) get_grant_table, 0,0); p_table->file->ha_index_init(0, 1); @@ -3555,7 +3570,7 @@ static my_bool grant_load_procs_priv(TABLE *p_table) { GRANT_NAME *mem_check; HASH *hash; - if (!(mem_check=new (memex_ptr) GRANT_NAME(p_table))) + if (!(mem_check=new (memex_ptr) GRANT_NAME(p_table, TRUE))) { /* This could only happen if we are out memory */ goto end_unlock; @@ -3639,7 +3654,7 @@ static my_bool grant_load(THD *thd, TABLE_LIST *tables) thd->variables.sql_mode&= ~MODE_PAD_CHAR_TO_FULL_LENGTH; - (void) hash_init(&column_priv_hash,system_charset_info, + (void) hash_init(&column_priv_hash, &my_charset_utf8_bin, 0,0,0, (hash_get_key) get_grant_table, (hash_free_key) free_grant_table,0); @@ -5436,9 +5451,21 @@ static int handle_grant_struct(uint struct_no, bool drop, case 2: case 3: - grant_name->user= strdup_root(&mem, user_to->user.str); - update_hostname(&grant_name->host, - strdup_root(&mem, user_to->host.str)); + /* + Update the grant structure with the new user name and + host name + */ + grant_name->set_user_details(user_to->host.str, grant_name->db, + user_to->user.str, grant_name->tname, + TRUE); + + /* + Since username is part of the hash key, when the user name + is renamed, the hash key is changed. Update the hash to + ensure that the position matches the new hash key value + */ + hash_update(&column_priv_hash, (uchar*) grant_name, + (uchar*) grant_name->hash_key, grant_name->key_length); break; } } @@ -5663,7 +5690,7 @@ bool mysql_create_user(THD *thd, List <LEX_USER> &list) my_error(ER_CANNOT_USER, MYF(0), "CREATE USER", wrong_users.c_ptr_safe()); if (some_users_created) - write_bin_log(thd, FALSE, thd->query, thd->query_length); + write_bin_log(thd, FALSE, thd->query(), thd->query_length()); rw_unlock(&LOCK_grant); close_thread_tables(thd); @@ -5736,7 +5763,7 @@ bool mysql_drop_user(THD *thd, List <LEX_USER> &list) my_error(ER_CANNOT_USER, MYF(0), "DROP USER", wrong_users.c_ptr_safe()); if (some_users_deleted) - write_bin_log(thd, FALSE, thd->query, thd->query_length); + write_bin_log(thd, FALSE, thd->query(), thd->query_length()); rw_unlock(&LOCK_grant); close_thread_tables(thd); @@ -5821,7 +5848,7 @@ bool mysql_rename_user(THD *thd, List <LEX_USER> &list) my_error(ER_CANNOT_USER, MYF(0), "RENAME USER", wrong_users.c_ptr_safe()); if (some_users_renamed && mysql_bin_log.is_open()) - write_bin_log(thd, FALSE, thd->query, thd->query_length); + write_bin_log(thd, FALSE, thd->query(), thd->query_length()); rw_unlock(&LOCK_grant); close_thread_tables(thd); @@ -6003,7 +6030,7 @@ bool mysql_revoke_all(THD *thd, List <LEX_USER> &list) VOID(pthread_mutex_unlock(&acl_cache->lock)); - write_bin_log(thd, FALSE, thd->query, thd->query_length); + write_bin_log(thd, FALSE, thd->query(), thd->query_length()); rw_unlock(&LOCK_grant); close_thread_tables(thd); @@ -6117,7 +6144,7 @@ bool sp_revoke_privileges(THD *thd, const char *sp_db, const char *sp_name, for (counter= 0, revoked= 0 ; counter < hash->records ; ) { GRANT_NAME *grant_proc= (GRANT_NAME*) hash_element(hash, counter); - if (!my_strcasecmp(system_charset_info, grant_proc->db, sp_db) && + if (!my_strcasecmp(&my_charset_utf8_bin, grant_proc->db, sp_db) && !my_strcasecmp(system_charset_info, grant_proc->tname, sp_name)) { LEX_USER lex_user; diff --git a/sql/sql_base.cc b/sql/sql_base.cc index ed64242e4b1..776fea20676 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -25,6 +25,7 @@ #include <m_ctype.h> #include <my_dir.h> #include <hash.h> +#include "rpl_filter.h" #ifdef __WIN__ #include <io.h> #endif @@ -1547,6 +1548,7 @@ void close_temporary_tables(THD *thd) s_query.length() - 1 /* to remove trailing ',' */, 0, FALSE, 0); qinfo.db= db.ptr(); + qinfo.db_len= db.length(); thd->variables.character_set_client= cs_save; mysql_bin_log.write(&qinfo); thd->variables.pseudo_thread_id= save_pseudo_thread_id; @@ -5098,7 +5100,16 @@ static void mark_real_tables_as_free_for_reuse(TABLE_LIST *table) int decide_logging_format(THD *thd, TABLE_LIST *tables) { - if (mysql_bin_log.is_open() && (thd->options & OPTION_BIN_LOG)) + /* + In SBR mode, we are only proceeding if we are binlogging this + statement, ie, the filtering rules won't later filter this out. + + This check here is needed to prevent some spurious error to be + raised in some cases (See BUG#42829). + */ + if (mysql_bin_log.is_open() && (thd->options & OPTION_BIN_LOG) && + (thd->variables.binlog_format != BINLOG_FORMAT_STMT || + binlog_filter->db_ok(thd->db))) { /* Compute the starting vectors for the computations by creating a diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index a41b7bd40bb..861bd97928d 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -1119,8 +1119,8 @@ void Query_cache::store_query(THD *thd, TABLE_LIST *tables_used) DBUG_VOID_RETURN; uint8 tables_type= 0; - if ((local_tables= is_cacheable(thd, thd->query_length, - thd->query, thd->lex, tables_used, + if ((local_tables= is_cacheable(thd, thd->query_length(), + thd->query(), thd->lex, tables_used, &tables_type))) { NET *net= &thd->net; @@ -1210,7 +1210,8 @@ def_week_frmt: %lu, in_trans: %d, autocommit: %d", /* Key is query + database + flag */ if (thd->db_length) { - memcpy(thd->query+thd->query_length+1, thd->db, thd->db_length); + memcpy(thd->query() + thd->query_length() + 1, thd->db, + thd->db_length); DBUG_PRINT("qcache", ("database: %s length: %u", thd->db, (unsigned) thd->db_length)); } @@ -1218,24 +1219,24 @@ def_week_frmt: %lu, in_trans: %d, autocommit: %d", { DBUG_PRINT("qcache", ("No active database")); } - tot_length= thd->query_length + thd->db_length + 1 + + tot_length= thd->query_length() + thd->db_length + 1 + QUERY_CACHE_FLAGS_SIZE; /* We should only copy structure (don't use it location directly) because of alignment issue */ - memcpy((void *)(thd->query + (tot_length - QUERY_CACHE_FLAGS_SIZE)), + memcpy((void*) (thd->query() + (tot_length - QUERY_CACHE_FLAGS_SIZE)), &flags, QUERY_CACHE_FLAGS_SIZE); /* Check if another thread is processing the same query? */ Query_cache_block *competitor = (Query_cache_block *) - hash_search(&queries, (uchar*) thd->query, tot_length); + hash_search(&queries, (uchar*) thd->query(), tot_length); DBUG_PRINT("qcache", ("competitor 0x%lx", (ulong) competitor)); if (competitor == 0) { /* Query is not in cache and no one is working with it; Store it */ Query_cache_block *query_block; - query_block= write_block_data(tot_length, (uchar*) thd->query, + query_block= write_block_data(tot_length, (uchar*) thd->query(), ALIGN_SIZE(sizeof(Query_cache_query)), Query_cache_block::QUERY, local_tables); if (query_block != 0) diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 179be88442c..a041df23cc5 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -412,14 +412,14 @@ char *thd_security_context(THD *thd, char *buffer, unsigned int length, str.append(proc_info); } - if (thd->query) + if (thd->query()) { if (max_query_len < 1) - len= thd->query_length; + len= thd->query_length(); else - len= min(thd->query_length, max_query_len); + len= min(thd->query_length(), max_query_len); str.append('\n'); - str.append(thd->query, len); + str.append(thd->query(), len); } if (str.c_ptr_safe() == buffer) return buffer; @@ -2467,12 +2467,12 @@ Statement::Statement(LEX *lex_arg, MEM_ROOT *mem_root_arg, id(id_arg), mark_used_columns(MARK_COLUMNS_READ), lex(lex_arg), - query(0), - query_length(0), cursor(0), db(NULL), db_length(0) { + query_string.length= 0; + query_string.str= NULL; name.str= NULL; } @@ -2488,8 +2488,7 @@ void Statement::set_statement(Statement *stmt) id= stmt->id; mark_used_columns= stmt->mark_used_columns; lex= stmt->lex; - query= stmt->query; - query_length= stmt->query_length; + query_string= stmt->query_string; cursor= stmt->cursor; } @@ -2513,6 +2512,15 @@ void Statement::restore_backup_statement(Statement *stmt, Statement *backup) } +/** Assign a new value to thd->query. */ + +void Statement::set_query_inner(char *query_arg, uint32 query_length_arg) +{ + query_string.str= query_arg; + query_string.length= query_length_arg; +} + + void THD::end_statement() { /* Cleanup SQL processing state to reuse this statement in next query. */ @@ -2748,9 +2756,11 @@ bool select_dumpvar::send_data(List<Item> &items) else { Item_func_set_user_var *suv= new Item_func_set_user_var(mv->s, item); - suv->fix_fields(thd, 0); + if (suv->fix_fields(thd, 0)) + DBUG_RETURN (1); suv->save_item_result(item); - suv->update(); + if (suv->update()) + DBUG_RETURN (1); } } DBUG_RETURN(thd->is_error()); @@ -3026,9 +3036,24 @@ extern "C" struct charset_info_st *thd_charset(MYSQL_THD thd) return(thd->charset()); } +/** + OBSOLETE : there's no way to ensure the string is null terminated. + Use thd_query_string instead() +*/ extern "C" char **thd_query(MYSQL_THD thd) { - return(&thd->query); + return(&thd->query_string.str); +} + +/** + Get the current query string for the thread. + + @param The MySQL internal thread pointer + @return query string and length. May be non-null-terminated. +*/ +extern "C" LEX_STRING * thd_query_string (MYSQL_THD thd) +{ + return(&thd->query_string); } extern "C" int thd_slave_thread(const MYSQL_THD thd) @@ -3053,6 +3078,11 @@ extern "C" void thd_mark_transaction_to_rollback(MYSQL_THD thd, bool all) { mark_transaction_to_rollback(thd, all); } + +extern "C" bool thd_binlog_filter_ok(const MYSQL_THD thd) +{ + return binlog_filter->db_ok(thd->db); +} #endif // INNODB_COMPATIBILITY_HOOKS */ /**************************************************************************** @@ -3207,8 +3237,7 @@ void THD::set_statement(Statement *stmt) void THD::set_query(char *query_arg, uint32 query_length_arg) { pthread_mutex_lock(&LOCK_thd_data); - query= query_arg; - query_length= query_length_arg; + set_query_inner(query_arg, query_length_arg); pthread_mutex_unlock(&LOCK_thd_data); } @@ -3226,6 +3255,16 @@ void mark_transaction_to_rollback(THD *thd, bool all) { thd->is_fatal_sub_stmt_error= TRUE; thd->transaction_rollback_request= all; + /* + Aborted transactions can not be IGNOREd. + Switch off the IGNORE flag for the current + SELECT_LEX. This should allow my_error() + to report the error and abort the execution + flow, even in presence + of IGNORE clause. + */ + if (thd->lex->current_select) + thd->lex->current_select->no_error= FALSE; } } /*************************************************************************** diff --git a/sql/sql_class.h b/sql/sql_class.h index 8c3a4f2e62d..05f2cb50ff6 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -97,6 +97,8 @@ extern char internal_table_name[2]; extern char empty_c_string[1]; extern MYSQL_PLUGIN_IMPORT const char **errmesg; +extern bool volatile shutdown_in_progress; + #define TC_LOG_PAGE_SIZE 8192 #define TC_LOG_MIN_SIZE (3*TC_LOG_PAGE_SIZE) @@ -646,10 +648,13 @@ public: This printing is needed at least in SHOW PROCESSLIST and SHOW ENGINE INNODB STATUS. */ - char *query; - uint32 query_length; // current query length + LEX_STRING query_string; Server_side_cursor *cursor; + inline char *query() { return query_string.str; } + inline uint32 query_length() { return query_string.length; } + void set_query_inner(char *query_arg, uint32 query_length_arg); + /** Name of the current (default) database. @@ -2122,7 +2127,11 @@ public: { int err= killed_errno(); if (err) + { + if ((err == KILL_CONNECTION) && !shutdown_in_progress) + err = KILL_QUERY; my_message(err, ER(err), MYF(0)); + } } /* return TRUE if we will abort query if we make a warning now */ inline bool really_abort_on_warning() diff --git a/sql/sql_db.cc b/sql/sql_db.cc index c19bfba9fc1..e6ccd9aa594 100644 --- a/sql/sql_db.cc +++ b/sql/sql_db.cc @@ -703,7 +703,7 @@ not_silent: char *query; uint query_length; - if (!thd->query) // Only in replication + if (!thd->query()) // Only in replication { query= tmp_query; query_length= (uint) (strxmov(tmp_query,"create database `", @@ -711,8 +711,8 @@ not_silent: } else { - query= thd->query; - query_length= thd->query_length; + query= thd->query(); + query_length= thd->query_length(); } ha_binlog_log_query(thd, 0, LOGCOM_CREATE_DB, @@ -805,13 +805,13 @@ bool mysql_alter_db(THD *thd, const char *db, HA_CREATE_INFO *create_info) } ha_binlog_log_query(thd, 0, LOGCOM_ALTER_DB, - thd->query, thd->query_length, + thd->query(), thd->query_length(), db, ""); if (mysql_bin_log.is_open()) { int errcode= query_error_code(thd, TRUE); - Query_log_event qinfo(thd, thd->query, thd->query_length, 0, + Query_log_event qinfo(thd, thd->query(), thd->query_length(), 0, /* suppress_use */ TRUE, errcode); /* @@ -948,7 +948,7 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent) { const char *query; ulong query_length; - if (!thd->query) + if (!thd->query()) { /* The client used the old obsolete mysql_drop_db() call */ query= path; @@ -957,8 +957,8 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent) } else { - query =thd->query; - query_length= thd->query_length; + query= thd->query(); + query_length= thd->query_length(); } if (mysql_bin_log.is_open()) { @@ -1964,7 +1964,7 @@ bool mysql_upgrade_db(THD *thd, LEX_STRING *old_db) if (mysql_bin_log.is_open()) { int errcode= query_error_code(thd, TRUE); - Query_log_event qinfo(thd, thd->query, thd->query_length, + Query_log_event qinfo(thd, thd->query(), thd->query_length(), 0, TRUE, errcode); thd->clear_error(); mysql_bin_log.write(&qinfo); diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index a81a5f4641f..b80138af7f2 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -413,7 +413,7 @@ cleanup: therefore be treated as a DDL. */ int log_result= thd->binlog_query(query_type, - thd->query, thd->query_length, + thd->query(), thd->query_length(), is_trans, FALSE, errcode); if (log_result) @@ -850,7 +850,7 @@ void multi_delete::abort() { int errcode= query_error_code(thd, thd->killed == THD::NOT_KILLED); thd->binlog_query(THD::ROW_QUERY_TYPE, - thd->query, thd->query_length, + thd->query(), thd->query_length(), transactional_tables, FALSE, errcode); } thd->transaction.all.modified_non_trans_table= true; @@ -1024,7 +1024,7 @@ bool multi_delete::send_eof() else errcode= query_error_code(thd, killed_status == THD::NOT_KILLED); if (thd->binlog_query(THD::ROW_QUERY_TYPE, - thd->query, thd->query_length, + thd->query(), thd->query_length(), transactional_tables, FALSE, errcode) && !normal_tables) { @@ -1166,7 +1166,7 @@ end: TRUNCATE must always be statement-based binlogged (not row-based) so we don't test current_stmt_binlog_row_based. */ - write_bin_log(thd, TRUE, thd->query, thd->query_length); + write_bin_log(thd, TRUE, thd->query(), thd->query_length()); my_ok(thd); // This should return record count } VOID(pthread_mutex_lock(&LOCK_open)); diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 3ac40ae825a..6e2b3903b52 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -567,7 +567,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, Name_resolution_context *context; Name_resolution_context_state ctx_state; #ifndef EMBEDDED_LIBRARY - char *query= thd->query; + char *query= thd->query(); /* log_on is about delayed inserts only. By default, both logs are enabled (this won't cause problems if the server @@ -801,7 +801,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, #ifndef EMBEDDED_LIBRARY if (lock_type == TL_WRITE_DELAYED) { - LEX_STRING const st_query = { query, thd->query_length }; + LEX_STRING const st_query = { query, thd->query_length() }; error=write_delayed(thd, table, duplic, st_query, ignore, log_on); query=0; } @@ -894,7 +894,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, */ DBUG_ASSERT(thd->killed != THD::KILL_BAD_DATA || error > 0); if (thd->binlog_query(THD::ROW_QUERY_TYPE, - thd->query, thd->query_length, + thd->query(), thd->query_length(), transactional_table, FALSE, errcode)) { @@ -1764,7 +1764,7 @@ public: pthread_cond_destroy(&cond); pthread_cond_destroy(&cond_client); thd.unlink(); // Must be unlinked under lock - x_free(thd.query); + x_free(thd.query()); thd.security_ctx->user= thd.security_ctx->host=0; thread_count--; delayed_insert_threads--; @@ -1910,7 +1910,7 @@ bool delayed_get_table(THD *thd, TABLE_LIST *table_list) pthread_mutex_unlock(&LOCK_thread_count); di->thd.set_db(table_list->db, (uint) strlen(table_list->db)); di->thd.set_query(my_strdup(table_list->table_name, MYF(MY_WME)), 0); - if (di->thd.db == NULL || di->thd.query == NULL) + if (di->thd.db == NULL || di->thd.query() == NULL) { /* The error is reported */ delete di; @@ -1919,7 +1919,7 @@ bool delayed_get_table(THD *thd, TABLE_LIST *table_list) } di->table_list= *table_list; // Needed to open table /* Replace volatile strings with local copies */ - di->table_list.alias= di->table_list.table_name= di->thd.query; + di->table_list.alias= di->table_list.table_name= di->thd.query(); di->table_list.db= di->thd.db; di->lock(); pthread_mutex_lock(&di->mutex); @@ -3250,7 +3250,7 @@ bool select_insert::send_eof() else errcode= query_error_code(thd, killed_status == THD::NOT_KILLED); thd->binlog_query(THD::ROW_QUERY_TYPE, - thd->query, thd->query_length, + thd->query(), thd->query_length(), trans_table, FALSE, errcode); } table->file->ha_release_auto_increment(); @@ -3320,7 +3320,8 @@ void select_insert::abort() { if (mysql_bin_log.is_open()) { int errcode= query_error_code(thd, thd->killed == THD::NOT_KILLED); - thd->binlog_query(THD::ROW_QUERY_TYPE, thd->query, thd->query_length, + thd->binlog_query(THD::ROW_QUERY_TYPE, thd->query(), + thd->query_length(), transactional_table, FALSE, errcode); } if (!thd->current_stmt_binlog_row_based && !can_rollback_data()) diff --git a/sql/sql_load.cc b/sql/sql_load.cc index 5c278467179..8dda4a52466 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -84,7 +84,7 @@ static int read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, bool ignore_check_option_errors); #ifndef EMBEDDED_LIBRARY static bool write_execute_load_query_log_event(THD *thd, sql_exchange* ex, - const char* db_arg, + const char* db_arg, /* table's database */ const char* table_name_arg, enum enum_duplicates duplicates, bool ignore, @@ -502,7 +502,8 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, if (thd->transaction.stmt.modified_non_trans_table) write_execute_load_query_log_event(thd, ex, - tdb, table_list->table_name, + table_list->db, + table_list->table_name, handle_duplicates, ignore, transactional_table, errcode); @@ -549,7 +550,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, { int errcode= query_error_code(thd, killed_status == THD::NOT_KILLED); write_execute_load_query_log_event(thd, ex, - tdb, table_list->table_name, + table_list->db, table_list->table_name, handle_duplicates, ignore, transactional_table, errcode); @@ -574,7 +575,7 @@ err: /* Not a very useful function; just to avoid duplication of code */ static bool write_execute_load_query_log_event(THD *thd, sql_exchange* ex, - const char* db_arg, + const char* db_arg, /* table's database */ const char* table_name_arg, enum enum_duplicates duplicates, bool ignore, @@ -591,8 +592,27 @@ static bool write_execute_load_query_log_event(THD *thd, sql_exchange* ex, Item *item, *val; String pfield, pfields; int n; + const char *tbl= table_name_arg; + const char *tdb= (thd->db != NULL ? thd->db : db_arg); + String string_buf; - Load_log_event lle(thd, ex, db_arg, table_name_arg, fv, duplicates, + if (!thd->db || strcmp(db_arg, thd->db)) + { + /* + If used database differs from table's database, + prefix table name with database name so that it + becomes a FQ name. + */ + string_buf.set_charset(system_charset_info); + string_buf.append(db_arg); + string_buf.append("`"); + string_buf.append("."); + string_buf.append("`"); + string_buf.append(table_name_arg); + tbl= string_buf.c_ptr_safe(); + } + + Load_log_event lle(thd, ex, tdb, tbl, fv, duplicates, ignore, transactional_table); /* @@ -655,13 +675,12 @@ static bool write_execute_load_query_log_event(THD *thd, sql_exchange* ex, strcpy(end, p); end += pl; - thd->query_length= end - load_data_query; - thd->query= load_data_query; + thd->set_query_inner(load_data_query, end - load_data_query); Execute_load_query_log_event - e(thd, thd->query, thd->query_length, - (uint) ((char*)fname_start - (char*)thd->query - 1), - (uint) ((char*)fname_end - (char*)thd->query), + e(thd, thd->query(), thd->query_length(), + (uint) ((char*) fname_start - (char*) thd->query() - 1), + (uint) ((char*) fname_end - (char*) thd->query()), (duplicates == DUP_REPLACE) ? LOAD_DUP_REPLACE : (ignore ? LOAD_DUP_IGNORE : LOAD_DUP_ERROR), transactional_table, FALSE, errcode); diff --git a/sql/sql_locale.cc b/sql/sql_locale.cc index 3def9864c29..5ddf65cd1b7 100644 --- a/sql/sql_locale.cc +++ b/sql/sql_locale.cc @@ -1309,9 +1309,9 @@ static const char *my_locale_month_names_ro_RO[13] = static const char *my_locale_ab_month_names_ro_RO[13] = {"ian","feb","mar","apr","mai","iun","iul","aug","sep","oct","nov","dec", NullS }; static const char *my_locale_day_names_ro_RO[8] = - {"Luni","MarÅ£i","Miercuri","Joi","Vineri","SîmbÄ‚tÄ‚","DuminicÄ‚", NullS }; + {"Luni","MarÅ£i","Miercuri","Joi","Vineri","Sâmbătă","Duminică", NullS }; static const char *my_locale_ab_day_names_ro_RO[8] = - {"Lu","Ma","Mi","Jo","Vi","Sî","Du", NullS }; + {"Lu","Ma","Mi","Jo","Vi","Sâ","Du", NullS }; static TYPELIB my_locale_typelib_month_names_ro_RO = { array_elements(my_locale_month_names_ro_RO)-1, "", my_locale_month_names_ro_RO, NULL }; static TYPELIB my_locale_typelib_ab_month_names_ro_RO = diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 7c19cd7f82a..80f366d774a 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -123,6 +123,14 @@ static bool xa_trans_rolled_back(XID_STATE *xid_state) */ static bool xa_trans_rollback(THD *thd) { + /* + Resource Manager error is meaningless at this point, as we perform + explicit rollback request by user. We must reset rm_error before + calling ha_rollback(), so thd->transaction.xid structure gets reset + by ha_rollback()/THD::transaction::cleanup(). + */ + thd->transaction.xid_state.rm_error= 0; + bool status= test(ha_rollback(thd)); thd->options&= ~(ulong) OPTION_BEGIN; @@ -130,7 +138,6 @@ static bool xa_trans_rollback(THD *thd) thd->server_status&= ~SERVER_STATUS_IN_TRANS; xid_cache_delete(&thd->transaction.xid_state); thd->transaction.xid_state.xa_state= XA_NOTR; - thd->transaction.xid_state.rm_error= 0; return status; } @@ -476,10 +483,10 @@ static void handle_bootstrap_impl(THD *thd) thd->db_length + 1 + QUERY_CACHE_FLAGS_SIZE); thd->set_query(query, length); - DBUG_PRINT("query",("%-.4096s",thd->query)); + DBUG_PRINT("query",("%-.4096s", thd->query())); #if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER) thd->profiling.start_new_query(); - thd->profiling.set_query_source(thd->query, length); + thd->profiling.set_query_source(thd->query(), length); #endif /* @@ -488,7 +495,7 @@ static void handle_bootstrap_impl(THD *thd) */ thd->query_id=next_query_id(); thd->set_time(); - mysql_parse(thd, thd->query, length, & found_semicolon); + mysql_parse(thd, thd->query(), length, & found_semicolon); close_thread_tables(thd); // Free tables bootstrap_error= thd->is_error(); @@ -1107,20 +1114,20 @@ bool dispatch_command(enum enum_server_command command, THD *thd, { if (alloc_query(thd, packet, packet_length)) break; // fatal error is set - char *packet_end= thd->query + thd->query_length; + char *packet_end= thd->query() + thd->query_length(); /* 'b' stands for 'buffer' parameter', special for 'my_snprintf' */ const char* end_of_stmt= NULL; - general_log_write(thd, command, thd->query, thd->query_length); - DBUG_PRINT("query",("%-.4096s",thd->query)); + general_log_write(thd, command, thd->query(), thd->query_length()); + DBUG_PRINT("query",("%-.4096s",thd->query())); #if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER) - thd->profiling.set_query_source(thd->query, thd->query_length); + thd->profiling.set_query_source(thd->query(), thd->query_length()); #endif if (!(specialflag & SPECIAL_NO_PRIOR)) my_pthread_setprio(pthread_self(),QUERY_PRIOR); - mysql_parse(thd, thd->query, thd->query_length, &end_of_stmt); + mysql_parse(thd, thd->query(), thd->query_length(), &end_of_stmt); while (!thd->killed && (end_of_stmt != NULL) && ! thd->is_error()) { @@ -1563,7 +1570,8 @@ void log_slow_statement(THD *thd) { thd_proc_info(thd, "logging slow query"); thd->status_var.long_query_count++; - slow_log_print(thd, thd->query, thd->query_length, end_utime_of_query); + slow_log_print(thd, thd->query(), thd->query_length(), + end_utime_of_query); } } DBUG_VOID_RETURN; @@ -2816,7 +2824,7 @@ end_with_restore_list: /* Presumably, REPAIR and binlog writing doesn't require synchronization */ - write_bin_log(thd, TRUE, thd->query, thd->query_length); + write_bin_log(thd, TRUE, thd->query(), thd->query_length()); } select_lex->table_list.first= (uchar*) first_table; lex->query_tables=all_tables; @@ -2848,7 +2856,7 @@ end_with_restore_list: /* Presumably, ANALYZE and binlog writing doesn't require synchronization */ - write_bin_log(thd, TRUE, thd->query, thd->query_length); + write_bin_log(thd, TRUE, thd->query(), thd->query_length()); } select_lex->table_list.first= (uchar*) first_table; lex->query_tables=all_tables; @@ -2871,7 +2879,7 @@ end_with_restore_list: /* Presumably, OPTIMIZE and binlog writing doesn't require synchronization */ - write_bin_log(thd, TRUE, thd->query, thd->query_length); + write_bin_log(thd, TRUE, thd->query(), thd->query_length()); } select_lex->table_list.first= (uchar*) first_table; lex->query_tables=all_tables; @@ -3823,7 +3831,7 @@ end_with_restore_list: */ if (!lex->no_write_to_binlog && write_to_binlog) { - write_bin_log(thd, FALSE, thd->query, thd->query_length); + write_bin_log(thd, FALSE, thd->query(), thd->query_length()); } my_ok(thd); } @@ -4400,7 +4408,7 @@ create_sp_error: case SP_KEY_NOT_FOUND: if (lex->drop_if_exists) { - write_bin_log(thd, TRUE, thd->query, thd->query_length); + write_bin_log(thd, TRUE, thd->query(), thd->query_length()); push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, ER_SP_DOES_NOT_EXIST, ER(ER_SP_DOES_NOT_EXIST), SP_COM_STRING(lex), lex->spname->m_name.str); @@ -4930,8 +4938,6 @@ bool check_single_table_access(THD *thd, ulong privilege, /* Show only 1 table for check_grant */ if (!(all_tables->belong_to_view && (thd->lex->sql_command == SQLCOM_SHOW_FIELDS)) && - !(all_tables->view && - all_tables->effective_algorithm == VIEW_ALGORITHM_TMPTABLE) && check_grant(thd, privilege, all_tables, 0, 1, no_errors)) goto deny; @@ -5791,9 +5797,10 @@ void mysql_parse(THD *thd, const char *inBuf, uint length, PROCESSLIST. Note that we don't need LOCK_thread_count to modify query_length. */ - if (*found_semicolon && - (thd->query_length= (ulong)(*found_semicolon - thd->query))) - thd->query_length--; + if (*found_semicolon && (ulong) (*found_semicolon - thd->query())) + thd->set_query_inner(thd->query(), + (uint32) (*found_semicolon - + thd->query() - 1)); /* Actually execute the query */ if (*found_semicolon) { diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index a7b35caeb8a..5a622740638 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -4081,7 +4081,7 @@ static int fast_end_partition(THD *thd, ulonglong copied, if ((!is_empty) && (!written_bin_log) && (!thd->lex->no_write_to_binlog)) - write_bin_log(thd, FALSE, thd->query, thd->query_length); + write_bin_log(thd, FALSE, thd->query(), thd->query_length()); my_snprintf(tmp_name, sizeof(tmp_name), ER(ER_INSERT_INFO), (ulong) (copied + deleted), @@ -6239,7 +6239,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, ERROR_INJECT_CRASH("crash_drop_partition_5") || ((!thd->lex->no_write_to_binlog) && (write_bin_log(thd, FALSE, - thd->query, thd->query_length), FALSE)) || + thd->query(), thd->query_length()), FALSE)) || ERROR_INJECT_CRASH("crash_drop_partition_6") || ((frm_install= TRUE), FALSE) || mysql_write_frm(lpt, WFRM_INSTALL_SHADOW) || @@ -6306,7 +6306,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, ERROR_INJECT_CRASH("crash_add_partition_5") || ((!thd->lex->no_write_to_binlog) && (write_bin_log(thd, FALSE, - thd->query, thd->query_length), FALSE)) || + thd->query(), thd->query_length()), FALSE)) || ERROR_INJECT_CRASH("crash_add_partition_6") || write_log_rename_frm(lpt) || (not_completed= FALSE) || @@ -6396,7 +6396,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, ERROR_INJECT_CRASH("crash_change_partition_6") || ((!thd->lex->no_write_to_binlog) && (write_bin_log(thd, FALSE, - thd->query, thd->query_length), FALSE)) || + thd->query(), thd->query_length()), FALSE)) || ERROR_INJECT_CRASH("crash_change_partition_7") || mysql_write_frm(lpt, WFRM_INSTALL_SHADOW) || ERROR_INJECT_CRASH("crash_change_partition_8") || diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc index 5500e44d1b2..e4cecdecc7e 100644 --- a/sql/sql_plugin.cc +++ b/sql/sql_plugin.cc @@ -2061,7 +2061,7 @@ static int check_func_set(THD *thd, struct st_mysql_sys_var *var, const char *strvalue= "NULL", *str; TYPELIB *typelib; ulonglong result; - uint error_len; + uint error_len= 0; // init as only set on error bool not_used; int length; @@ -2660,7 +2660,9 @@ uchar* sys_var_pluginvar::value_ptr(THD *thd, enum_var_type type, { if (!(value & mask)) continue; - str.append(typelib->type_names[i], typelib->type_lengths[i]); + str.append(typelib->type_names[i], typelib->type_lengths + ? typelib->type_lengths[i] + : strlen(typelib->type_names[i])); str.append(','); } diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index c1839b7220f..e2a24f7da1e 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -752,7 +752,7 @@ static bool insert_params_with_log(Prepared_statement *stmt, uchar *null_array, const String *res; DBUG_ENTER("insert_params_with_log"); - if (query->copy(stmt->query, stmt->query_length, default_charset_info)) + if (query->copy(stmt->query(), stmt->query_length(), default_charset_info)) DBUG_RETURN(1); for (Item_param **it= begin; it < end; ++it) @@ -914,7 +914,7 @@ static bool emb_insert_params_with_log(Prepared_statement *stmt, DBUG_ENTER("emb_insert_params_with_log"); - if (query->copy(stmt->query, stmt->query_length, default_charset_info)) + if (query->copy(stmt->query(), stmt->query_length(), default_charset_info)) DBUG_RETURN(1); for (; it < end; ++it, ++client_param) @@ -1065,7 +1065,7 @@ static bool insert_params_from_vars_with_log(Prepared_statement *stmt, DBUG_ENTER("insert_params_from_vars"); - if (query->copy(stmt->query, stmt->query_length, default_charset_info)) + if (query->copy(stmt->query(), stmt->query_length(), default_charset_info)) DBUG_RETURN(1); for (Item_param **it= begin; it < end; ++it) @@ -2342,6 +2342,9 @@ void reinit_stmt_before_use(THD *thd, LEX *lex) /* Fix ORDER list */ for (order= (ORDER *)sl->order_list.first; order; order= order->next) order->item= &order->item_ptr; + + /* clear the no_error flag for INSERT/UPDATE IGNORE */ + sl->no_error= FALSE; } { SELECT_LEX_UNIT *unit= sl->master_unit(); @@ -2457,9 +2460,9 @@ void mysqld_stmt_execute(THD *thd, char *packet_arg, uint packet_length) } #if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER) - thd->profiling.set_query_source(stmt->query, stmt->query_length); + thd->profiling.set_query_source(stmt->query(), stmt->query_length()); #endif - DBUG_PRINT("exec_query", ("%s", stmt->query)); + DBUG_PRINT("exec_query", ("%s", stmt->query())); DBUG_PRINT("info",("stmt: 0x%lx", (long) stmt)); sp_cache_flush_obsolete(&thd->sp_proc_cache); @@ -3029,7 +3032,7 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len) old_stmt_arena= thd->stmt_arena; thd->stmt_arena= this; - Parser_state parser_state(thd, thd->query, thd->query_length); + Parser_state parser_state(thd, thd->query(), thd->query_length()); parser_state.m_lip.stmt_prepare_mode= TRUE; lex_start(thd); @@ -3118,7 +3121,7 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len) the general log. */ if (thd->spcont == NULL) - general_log_write(thd, COM_STMT_PREPARE, query, query_length); + general_log_write(thd, COM_STMT_PREPARE, query(), query_length()); } DBUG_RETURN(error); } @@ -3309,7 +3312,7 @@ Prepared_statement::reprepare() return TRUE; error= ((name.str && copy.set_name(&name)) || - copy.prepare(query, query_length) || + copy.prepare(query(), query_length()) || validate_metadata(©)); if (cur_db_changed) @@ -3547,8 +3550,7 @@ bool Prepared_statement::execute(String *expanded_query, bool open_cursor) to point at it even after we restore from backup. This is ok, as expanded query was allocated in thd->mem_root. */ - stmt_backup.query= thd->query; - stmt_backup.query_length= thd->query_length; + stmt_backup.set_query_inner(thd->query(), thd->query_length()); /* At first execution of prepared statement we may perform logical @@ -3573,8 +3575,8 @@ bool Prepared_statement::execute(String *expanded_query, bool open_cursor) Note that multi-statements cannot exist here (they are not supported in prepared statements). */ - if (query_cache_send_result_to_client(thd, thd->query, - thd->query_length) <= 0) + if (query_cache_send_result_to_client(thd, thd->query(), + thd->query_length()) <= 0) { error= mysql_execute_command(thd); } @@ -3619,7 +3621,7 @@ bool Prepared_statement::execute(String *expanded_query, bool open_cursor) the general log. */ if (error == 0 && thd->spcont == NULL) - general_log_write(thd, COM_STMT_EXECUTE, thd->query, thd->query_length); + general_log_write(thd, COM_STMT_EXECUTE, thd->query(), thd->query_length()); error: flags&= ~ (uint) IS_IN_USE; diff --git a/sql/sql_rename.cc b/sql/sql_rename.cc index 0e0b8eb60b9..dac96f2e9c4 100644 --- a/sql/sql_rename.cc +++ b/sql/sql_rename.cc @@ -177,7 +177,7 @@ bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list, bool silent) /* Lets hope this doesn't fail as the result will be messy */ if (!silent && !error) { - write_bin_log(thd, TRUE, thd->query, thd->query_length); + write_bin_log(thd, TRUE, thd->query(), thd->query_length()); my_ok(thd); } diff --git a/sql/sql_select.cc b/sql/sql_select.cc index c5e0bce498d..cdaebef49f6 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -149,6 +149,7 @@ static int join_read_const_table(JOIN_TAB *tab, POSITION *pos); static int join_read_system(JOIN_TAB *tab); static int join_read_const(JOIN_TAB *tab); static int join_read_key(JOIN_TAB *tab); +static void join_read_key_unlock_row(st_join_table *tab); static int join_read_always_key(JOIN_TAB *tab); static int join_read_last_key(JOIN_TAB *tab); static int join_no_more_records(READ_RECORD *info); @@ -633,6 +634,18 @@ JOIN::prepare(Item ***rref_pointer_array, MYF(0)); /* purecov: inspected */ goto err; /* purecov: inspected */ } + if (thd->lex->derived_tables) + { + my_error(ER_WRONG_USAGE, MYF(0), "PROCEDURE", + thd->lex->derived_tables & DERIVED_VIEW ? + "view" : "subquery"); + goto err; + } + if (thd->lex->sql_command != SQLCOM_SELECT) + { + my_error(ER_WRONG_USAGE, MYF(0), "PROCEDURE", "non-SELECT"); + goto err; + } } if (!procedure && result && result->prepare(fields_list, unit_arg)) @@ -969,6 +982,12 @@ JOIN::optimize() DBUG_RETURN(1); } + if (select_lex->olap == ROLLUP_TYPE && rollup_process_const_fields()) + { + DBUG_PRINT("error", ("Error: rollup_process_fields() failed")); + DBUG_RETURN(1); + } + /* Remove distinct if only const tables */ select_distinct= select_distinct && (const_tables != tables); thd_proc_info(thd, "preparing"); @@ -1099,7 +1118,7 @@ JOIN::optimize() join_tab[const_tables].select->quick->get_type() != QUICK_SELECT_I::QS_TYPE_GROUP_MIN_MAX)) { - if (group_list && + if (group_list && rollup.state == ROLLUP::STATE_NONE && list_contains_unique_index(join_tab[const_tables].table, find_field_in_order_list, (void *) group_list)) @@ -1143,7 +1162,8 @@ JOIN::optimize() if (! hidden_group_fields && rollup.state == ROLLUP::STATE_NONE) select_distinct=0; } - else if (select_distinct && tables - const_tables == 1) + else if (select_distinct && tables - const_tables == 1 && + rollup.state == ROLLUP::STATE_NONE) { /* We are only using one table. In this case we change DISTINCT to a @@ -3560,7 +3580,7 @@ add_key_part(DYNAMIC_ARRAY *keyuse_array,KEY_FIELD *key_field) { if (!(form->keys_in_use_for_query.is_set(key))) continue; - if (form->key_info[key].flags & HA_FULLTEXT) + if (form->key_info[key].flags & (HA_FULLTEXT | HA_SPATIAL)) continue; // ToDo: ft-keys in non-ft queries. SerG uint key_parts= (uint) form->key_info[key].key_parts; @@ -5609,7 +5629,9 @@ static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, KEYUSE *org_keyuse, } j->ref.key_buff2=j->ref.key_buff+ALIGN_SIZE(length); j->ref.key_err=1; + j->ref.has_record= FALSE; j->ref.null_rejecting= 0; + j->ref.use_count= 0; keyuse=org_keyuse; store_key **ref_key= j->ref.key_copy; @@ -6442,6 +6464,20 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond) DBUG_RETURN(0); } + +/** + The default implementation of unlock-row method of READ_RECORD, + used in all access methods. +*/ + +void rr_unlock_row(st_join_table *tab) +{ + READ_RECORD *info= &tab->read_record; + info->file->unlock_row(); +} + + + static void make_join_readinfo(JOIN *join, ulonglong options) { @@ -6457,6 +6493,7 @@ make_join_readinfo(JOIN *join, ulonglong options) TABLE *table=tab->table; tab->read_record.table= table; tab->read_record.file=table->file; + tab->read_record.unlock_row= rr_unlock_row; tab->next_select=sub_select; /* normal select */ /* @@ -6502,6 +6539,7 @@ make_join_readinfo(JOIN *join, ulonglong options) delete tab->quick; tab->quick=0; tab->read_first_record= join_read_key; + tab->read_record.unlock_row= join_read_key_unlock_row; tab->read_record.read_record= join_no_more_records; if (table->covering_keys.is_set(tab->ref.key) && !table->no_keyread) @@ -8964,7 +9002,10 @@ static void restore_prev_nj_state(JOIN_TAB *last) join->cur_embedding_map&= ~last_emb->nested_join->nj_map; else if (last_emb->nested_join->join_list.elements-1 == last_emb->nested_join->counter) + { join->cur_embedding_map|= last_emb->nested_join->nj_map; + break; + } else break; last_emb= last_emb->embedding; @@ -9411,8 +9452,47 @@ static Field *create_tmp_field_from_item(THD *thd, Item *item, TABLE *table, new_field->set_derivation(item->collation.derivation); break; case DECIMAL_RESULT: - new_field= Field_new_decimal::new_decimal_field(item); + { + 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 + */ + + const int required_length= + my_decimal_precision_to_length(intg + dec, dec, + item->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; + } + + new_field= new Field_new_decimal(len, maybe_null, item->name, + dec, item->unsigned_flag); break; + } case ROW_RESULT: default: // This case should never be choosen @@ -10212,6 +10292,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, for (; cur_group ; cur_group= cur_group->next, key_part_info++) { Field *field=(*cur_group->item)->get_tmp_table_field(); + DBUG_ASSERT(field->table == table); bool maybe_null=(*cur_group->item)->maybe_null; key_part_info->null_bit=0; key_part_info->field= field; @@ -11189,6 +11270,7 @@ evaluate_join_record(JOIN *join, JOIN_TAB *join_tab, bool not_used_in_distinct=join_tab->not_used_in_distinct; ha_rows found_records=join->found_records; COND *select_cond= join_tab->select_cond; + bool select_cond_result= TRUE; if (error > 0 || (join->thd->is_error())) // Fatal error return NESTED_LOOP_ERROR; @@ -11200,7 +11282,17 @@ evaluate_join_record(JOIN *join, JOIN_TAB *join_tab, return NESTED_LOOP_KILLED; /* purecov: inspected */ } DBUG_PRINT("info", ("select cond 0x%lx", (ulong)select_cond)); - if (!select_cond || select_cond->val_int()) + + if (select_cond) + { + select_cond_result= test(select_cond->val_int()); + + /* check for errors evaluating the condition */ + if (join->thd->is_error()) + return NESTED_LOOP_ERROR; + } + + if (!select_cond || select_cond_result) { /* There is no select condition or the attached pushed down @@ -11284,7 +11376,7 @@ evaluate_join_record(JOIN *join, JOIN_TAB *join_tab, return NESTED_LOOP_NO_MORE_ROWS; } else - join_tab->read_record.file->unlock_row(); + join_tab->read_record.unlock_row(join_tab); } else { @@ -11294,7 +11386,7 @@ evaluate_join_record(JOIN *join, JOIN_TAB *join_tab, */ join->examined_rows++; join->thd->row_count++; - join_tab->read_record.file->unlock_row(); + join_tab->read_record.unlock_row(join_tab); } return NESTED_LOOP_OK; } @@ -11654,18 +11746,55 @@ join_read_key(JOIN_TAB *tab) table->status=STATUS_NOT_FOUND; return -1; } + /* + Moving away from the current record. Unlock the row + in the handler if it did not match the partial WHERE. + */ + if (tab->ref.has_record && tab->ref.use_count == 0) + { + tab->read_record.file->unlock_row(); + tab->ref.has_record= FALSE; + } error=table->file->index_read_map(table->record[0], tab->ref.key_buff, make_prev_keypart_map(tab->ref.key_parts), HA_READ_KEY_EXACT); if (error && error != HA_ERR_KEY_NOT_FOUND && error != HA_ERR_END_OF_FILE) return report_error(table, error); + + if (! error) + { + tab->ref.has_record= TRUE; + tab->ref.use_count= 1; + } + } + else if (table->status == 0) + { + DBUG_ASSERT(tab->ref.has_record); + tab->ref.use_count++; } table->null_row=0; return table->status ? -1 : 0; } +/** + Since join_read_key may buffer a record, do not unlock + it if it was not used in this invocation of join_read_key(). + Only count locks, thus remembering if the record was left unused, + and unlock already when pruning the current value of + TABLE_REF buffer. + @sa join_read_key() +*/ + +static void +join_read_key_unlock_row(st_join_table *tab) +{ + DBUG_ASSERT(tab->ref.use_count); + if (tab->ref.use_count) + tab->ref.use_count--; +} + /* ref access method implementation: "read_first" function @@ -15637,32 +15766,7 @@ bool JOIN::rollup_init() { item->maybe_null= 1; found_in_group= 1; - if (item->const_item()) - { - /* - For ROLLUP queries each constant item referenced in GROUP BY list - is wrapped up into an Item_func object yielding the same value - as the constant item. The objects of the wrapper class are never - considered as constant items and besides they inherit all - properties of the Item_result_field class. - This wrapping allows us to ensure writing constant items - into temporary tables whenever the result of the ROLLUP - operation has to be written into a temporary table, e.g. when - ROLLUP is used together with DISTINCT in the SELECT list. - Usually when creating temporary tables for a intermidiate - result we do not include fields for constant expressions. - */ - Item* new_item= new Item_func_rollup_const(item); - if (!new_item) - return 1; - new_item->fix_fields(thd, (Item **) 0); - thd->change_item_tree(it.ref(), new_item); - for (ORDER *tmp= group_tmp; tmp; tmp= tmp->next) - { - if (*tmp->item == item) - thd->change_item_tree(tmp->item, new_item); - } - } + break; } } if (item->type() == Item::FUNC_ITEM && !found_in_group) @@ -15681,6 +15785,59 @@ bool JOIN::rollup_init() } return 0; } + +/** + Wrap all constant Items in GROUP BY list. + + For ROLLUP queries each constant item referenced in GROUP BY list + is wrapped up into an Item_func object yielding the same value + as the constant item. The objects of the wrapper class are never + considered as constant items and besides they inherit all + properties of the Item_result_field class. + This wrapping allows us to ensure writing constant items + into temporary tables whenever the result of the ROLLUP + operation has to be written into a temporary table, e.g. when + ROLLUP is used together with DISTINCT in the SELECT list. + Usually when creating temporary tables for a intermidiate + result we do not include fields for constant expressions. + + @retval + 0 if ok + @retval + 1 on error +*/ + +bool JOIN::rollup_process_const_fields() +{ + ORDER *group_tmp; + Item *item; + List_iterator<Item> it(all_fields); + + for (group_tmp= group_list; group_tmp; group_tmp= group_tmp->next) + { + if (!(*group_tmp->item)->const_item()) + continue; + while ((item= it++)) + { + if (*group_tmp->item == item) + { + Item* new_item= new Item_func_rollup_const(item); + if (!new_item) + return 1; + new_item->fix_fields(thd, (Item **) 0); + thd->change_item_tree(it.ref(), new_item); + for (ORDER *tmp= group_tmp; tmp; tmp= tmp->next) + { + if (*tmp->item == item) + thd->change_item_tree(tmp->item, new_item); + } + break; + } + } + it.rewind(); + } + return 0; +} /** diff --git a/sql/sql_select.h b/sql/sql_select.h index 0b9aa3576c7..e44d416380e 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -61,6 +61,8 @@ class store_key; typedef struct st_table_ref { bool key_err; + /** True if something was read into buffer in join_read_key. */ + bool has_record; uint key_parts; ///< num of ... uint key_length; ///< length of key_buff int key; ///< key no @@ -88,6 +90,11 @@ typedef struct st_table_ref table_map depend_map; ///< Table depends on these tables. /* null byte position in the key_buf. Used for REF_OR_NULL optimization */ uchar *null_ref_key; + /* + The number of times the record associated with this key was used + in the join. + */ + ha_rows use_count; } TABLE_REF; @@ -515,6 +522,7 @@ public: } bool rollup_init(); + bool rollup_process_const_fields(); bool rollup_make_fields(List<Item> &all_fields, List<Item> &fields, Item_sum ***func); int rollup_send_data(uint idx); diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 1747da1a149..413733c0148 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -1835,10 +1835,10 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose) thd_info->query=0; /* Lock THD mutex that protects its data when looking at it. */ pthread_mutex_lock(&tmp->LOCK_thd_data); - if (tmp->query) + if (tmp->query()) { - uint length= min(max_query_length, tmp->query_length); - thd_info->query=(char*) thd->strmake(tmp->query,length); + uint length= min(max_query_length, tmp->query_length()); + thd_info->query= (char*) thd->strmake(tmp->query(),length); } pthread_mutex_unlock(&tmp->LOCK_thd_data); thread_infos.append(thd_info); @@ -1963,11 +1963,11 @@ int fill_schema_processlist(THD* thd, TABLE_LIST* tables, COND* cond) pthread_mutex_unlock(&mysys_var->mutex); /* INFO */ - if (tmp->query) + if (tmp->query()) { - table->field[7]->store(tmp->query, + table->field[7]->store(tmp->query(), min(PROCESS_LIST_INFO_WIDTH, - tmp->query_length), cs); + tmp->query_length()), cs); table->field[7]->set_notnull(); } diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 8fd80d04af9..cb9ff6163a8 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -2089,7 +2089,7 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, tables). In this case, we can write the original query into the binary log. */ - write_bin_log(thd, !error, thd->query, thd->query_length); + write_bin_log(thd, !error, thd->query(), thd->query_length()); } else if (thd->current_stmt_binlog_row_based && tmp_table_deleted) @@ -3554,7 +3554,7 @@ static inline void write_create_table_bin_log(THD *thd, (!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_bin_log(thd, TRUE, thd->query(), thd->query_length()); } @@ -5337,14 +5337,14 @@ binlog: write_bin_log(thd, TRUE, query.ptr(), query.length()); } else // Case 1 - write_bin_log(thd, TRUE, thd->query, thd->query_length); + write_bin_log(thd, TRUE, thd->query(), thd->query_length()); } /* Case 3 and 4 does nothing under RBR */ } else - write_bin_log(thd, TRUE, thd->query, thd->query_length); + write_bin_log(thd, TRUE, thd->query(), thd->query_length()); res= FALSE; @@ -5432,7 +5432,7 @@ mysql_discard_or_import_tablespace(THD *thd, error=1; if (error) goto err; - write_bin_log(thd, FALSE, thd->query, thd->query_length); + write_bin_log(thd, FALSE, thd->query(), thd->query_length()); err: ha_autocommit_or_rollback(thd, error); @@ -6441,7 +6441,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, if (mysql_bin_log.is_open()) { thd->clear_error(); - Query_log_event qinfo(thd, thd->query, thd->query_length, + Query_log_event qinfo(thd, thd->query(), thd->query_length(), 0, FALSE, 0); mysql_bin_log.write(&qinfo); } @@ -6695,7 +6695,7 @@ view_err: if (!error) { - write_bin_log(thd, TRUE, thd->query, thd->query_length); + write_bin_log(thd, TRUE, thd->query(), thd->query_length()); my_ok(thd); } else if (error > 0) @@ -7185,7 +7185,7 @@ view_err: goto err1; /* We don't replicate alter table statement on temporary tables */ if (!thd->current_stmt_binlog_row_based) - write_bin_log(thd, TRUE, thd->query, thd->query_length); + write_bin_log(thd, TRUE, thd->query(), thd->query_length()); goto end_temporary; } @@ -7342,13 +7342,13 @@ view_err: DBUG_EXECUTE_IF("sleep_alter_before_main_binlog", my_sleep(6000000);); ha_binlog_log_query(thd, create_info->db_type, LOGCOM_ALTER_TABLE, - thd->query, thd->query_length, + thd->query(), thd->query_length(), db, table_name); DBUG_ASSERT(!(mysql_bin_log.is_open() && 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_bin_log(thd, TRUE, thd->query(), thd->query_length()); if (ha_check_storage_engine_flag(old_db_type, HTON_FLUSH_AFTER_RENAME)) { diff --git a/sql/sql_tablespace.cc b/sql/sql_tablespace.cc index 9fec0e3bc63..fcc442a8f9a 100644 --- a/sql/sql_tablespace.cc +++ b/sql/sql_tablespace.cc @@ -66,6 +66,6 @@ int mysql_alter_tablespace(THD *thd, st_alter_tablespace *ts_info) ha_resolve_storage_engine_name(hton), "TABLESPACE or LOGFILE GROUP"); } - write_bin_log(thd, FALSE, thd->query, thd->query_length); + write_bin_log(thd, FALSE, thd->query(), thd->query_length()); DBUG_RETURN(FALSE); } diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc index c055268ecca..a251a533622 100644 --- a/sql/sql_trigger.cc +++ b/sql/sql_trigger.cc @@ -409,7 +409,7 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create) */ result= FALSE; /* Still, we need to log the query ... */ - stmt_query.append(thd->query, thd->query_length); + stmt_query.append(thd->query(), thd->query_length()); goto end; } } @@ -918,7 +918,7 @@ bool Table_triggers_list::drop_trigger(THD *thd, TABLE_LIST *tables, List_iterator<LEX_STRING> it_connection_cl_name(connection_cl_names); List_iterator<LEX_STRING> it_db_cl_name(db_cl_names); - stmt_query->append(thd->query, thd->query_length); + stmt_query->append(thd->query(), thd->query_length()); while ((name= it_name++)) { diff --git a/sql/sql_udf.cc b/sql/sql_udf.cc index c60dac42fb8..c6b41b59a3f 100644 --- a/sql/sql_udf.cc +++ b/sql/sql_udf.cc @@ -506,7 +506,7 @@ int mysql_create_function(THD *thd,udf_func *udf) rw_unlock(&THR_LOCK_udf); /* Binlog the create function. */ - write_bin_log(thd, TRUE, thd->query, thd->query_length); + write_bin_log(thd, TRUE, thd->query(), thd->query_length()); DBUG_RETURN(0); @@ -581,7 +581,7 @@ int mysql_drop_function(THD *thd,const LEX_STRING *udf_name) rw_unlock(&THR_LOCK_udf); /* Binlog the drop function. */ - write_bin_log(thd, TRUE, thd->query, thd->query_length); + write_bin_log(thd, TRUE, thd->query(), thd->query_length()); DBUG_RETURN(0); err: diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 152613c0009..cfa383ce9cb 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -810,7 +810,7 @@ int mysql_update(THD *thd, errcode= query_error_code(thd, killed_status == THD::NOT_KILLED); if (thd->binlog_query(THD::ROW_QUERY_TYPE, - thd->query, thd->query_length, + thd->query(), thd->query_length(), transactional_table, FALSE, errcode)) { error=1; // Rollback update @@ -1696,6 +1696,11 @@ bool multi_update::send_data(List<Item> ¬_used_values) TRG_EVENT_UPDATE)) DBUG_RETURN(1); + /* + Reset the table->auto_increment_field_not_null as it is valid for + only one row. + */ + table->auto_increment_field_not_null= FALSE; found++; if (!can_compare_record || compare_record(table)) { @@ -1860,7 +1865,7 @@ void multi_update::abort() */ int errcode= query_error_code(thd, thd->killed == THD::NOT_KILLED); thd->binlog_query(THD::ROW_QUERY_TYPE, - thd->query, thd->query_length, + thd->query(), thd->query_length(), transactional_tables, FALSE, errcode); } thd->transaction.all.modified_non_trans_table= TRUE; @@ -2093,7 +2098,7 @@ bool multi_update::send_eof() else errcode= query_error_code(thd, killed_status == THD::NOT_KILLED); if (thd->binlog_query(THD::ROW_QUERY_TYPE, - thd->query, thd->query_length, + thd->query(), thd->query_length(), transactional_tables, FALSE, errcode)) { local_error= 1; // Rollback update diff --git a/sql/sql_view.cc b/sql/sql_view.cc index 43d0b9fade0..ae3af0640a3 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -1652,7 +1652,7 @@ bool mysql_drop_view(THD *thd, TABLE_LIST *views, enum_drop_mode drop_mode) /* if something goes wrong, bin-log with possible error code, otherwise bin-log with error code cleared. */ - write_bin_log(thd, !something_wrong, thd->query, thd->query_length); + write_bin_log(thd, !something_wrong, thd->query(), thd->query_length()); } VOID(pthread_mutex_unlock(&LOCK_open)); diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 4b2d4634ee7..1b85e5afdce 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -9117,8 +9117,7 @@ procedure_clause: MYSQL_YYABORT; } - if (&lex->select_lex != lex->current_select || - lex->select_lex.get_table_list()->derived) + if (&lex->select_lex != lex->current_select) { my_error(ER_WRONG_USAGE, MYF(0), "PROCEDURE", "subquery"); MYSQL_YYABORT; @@ -10698,7 +10697,7 @@ param_marker: my_error(ER_VIEW_SELECT_VARIABLE, MYF(0)); MYSQL_YYABORT; } - item= new (thd->mem_root) Item_param((uint) (lip->get_tok_start() - thd->query)); + item= new (thd->mem_root) Item_param((uint) (lip->get_tok_start() - thd->query())); if (!($$= item) || lex->param_list.push_back(item)) { my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0)); diff --git a/sql/structs.h b/sql/structs.h index bcda7b1e787..d54921791a1 100644 --- a/sql/structs.h +++ b/sql/structs.h @@ -118,16 +118,22 @@ typedef struct st_reginfo { /* Extra info about reg */ } REGINFO; -struct st_read_record; /* For referense later */ class SQL_SELECT; class THD; class handler; +struct st_join_table; + +void rr_unlock_row(st_join_table *tab); -typedef struct st_read_record { /* Parameter to read_record */ +struct READ_RECORD { /* Parameter to read_record */ + typedef int (*Read_func)(READ_RECORD*); + typedef void (*Unlock_row_func)(st_join_table *); struct st_table *table; /* Head-form */ handler *file; struct st_table **forms; /* head and ref forms */ - int (*read_record)(struct st_read_record *); + + Read_func read_record; + Unlock_row_func unlock_row; THD *thd; SQL_SELECT *select; uint cache_records; @@ -139,7 +145,7 @@ typedef struct st_read_record { /* Parameter to read_record */ uchar *cache,*cache_pos,*cache_end,*read_positions; IO_CACHE *io_cache; bool print_error, ignore_not_found_rows; -} READ_RECORD; +}; /* diff --git a/sql/time.cc b/sql/time.cc index 962b65e454c..8b554beb94b 100644 --- a/sql/time.cc +++ b/sql/time.cc @@ -965,20 +965,22 @@ calc_time_diff(MYSQL_TIME *l_time1, MYSQL_TIME *l_time2, int l_sign, longlong *s 0 - a == b 1 - a > b - NOTES - TIME.second_part is not considered during comparison */ -int -my_time_compare(MYSQL_TIME *a, MYSQL_TIME *b) +int my_time_compare(MYSQL_TIME *a, MYSQL_TIME *b) { - my_ulonglong a_t= TIME_to_ulonglong_datetime(a); - my_ulonglong b_t= TIME_to_ulonglong_datetime(b); + ulonglong a_t= TIME_to_ulonglong_datetime(a); + ulonglong b_t= TIME_to_ulonglong_datetime(b); + if (a_t < b_t) + return -1; if (a_t > b_t) return 1; - else if (a_t < b_t) + + if (a->second_part < b->second_part) return -1; + if (a->second_part > b->second_part) + return 1; return 0; } |