diff options
author | Michael Widenius <monty@askmonty.org> | 2011-02-28 19:39:30 +0200 |
---|---|---|
committer | Michael Widenius <monty@askmonty.org> | 2011-02-28 19:39:30 +0200 |
commit | 3358cdd5048671ee6cbbf50c291f7e0d0fda8e1e (patch) | |
tree | da0e622896425203d23ecdfd1bc77b57e3502edf /sql | |
parent | 869f5d0e81d5cbecaec3605f292fbb363b9ccbf6 (diff) | |
parent | f83e594218a6d19da2fa1ea2a01d860c30fe2913 (diff) | |
download | mariadb-git-3358cdd5048671ee6cbbf50c291f7e0d0fda8e1e.tar.gz |
Merge with 5.1 to get in changes from MySQL 5.1.55
Diffstat (limited to 'sql')
79 files changed, 1098 insertions, 650 deletions
diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt index 9ba6bd1e1b4..53ba75c4d8c 100755 --- a/sql/CMakeLists.txt +++ b/sql/CMakeLists.txt @@ -142,7 +142,7 @@ ADD_CUSTOM_TARGET( ${PROJECT_SOURCE_DIR}/sql/message.rc ${PROJECT_SOURCE_DIR}/sql/lex_hash.h) -ADD_DEPENDENCIES(mysqld GenServerSource) +ADD_DEPENDENCIES(sql GenServerSource) # Remove the auto-generated files as part of 'Clean Solution' SET_DIRECTORY_PROPERTIES(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES diff --git a/sql/Makefile.am b/sql/Makefile.am index 1c3ee09c0d5..c1920f41cc7 100644 --- a/sql/Makefile.am +++ b/sql/Makefile.am @@ -42,7 +42,7 @@ mysqld_DEPENDENCIES= @mysql_plugin_libs@ $(SUPPORTING_LIBS) libndb.la LDADD = $(SUPPORTING_LIBS) @ZLIB_LIBS@ @NDB_SCI_LIBS@ mysqld_LDADD = libndb.la \ @MYSQLD_EXTRA_LDFLAGS@ \ - @pstack_libs@ $(libevent_libs) \ + $(libevent_libs) \ @mysql_plugin_libs@ \ $(LDADD) $(CXXLDFLAGS) $(WRAPLIBS) @LIBDL@ \ $(yassl_libs) $(openssl_libs) @MYSQLD_EXTRA_LIBS@ diff --git a/sql/field.cc b/sql/field.cc index 32c4d1949a8..13162fcb0d6 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2000, 2010 Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. 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 diff --git a/sql/field.h b/sql/field.h index 0161f69ac4d..c205c9b5582 100644 --- a/sql/field.h +++ b/sql/field.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2000, 2010 Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2000, 2010 Oracle and/or its affiliates. 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 diff --git a/sql/field_conv.cc b/sql/field_conv.cc index 67ef4f95368..d934e8d007a 100644 --- a/sql/field_conv.cc +++ b/sql/field_conv.cc @@ -783,10 +783,12 @@ int field_conv(Field *to,Field *from) ((Field_varstring*)from)->length_bytes == ((Field_varstring*)to)->length_bytes)) { // Identical fields -#ifdef HAVE_valgrind - /* This may happen if one does 'UPDATE ... SET x=x' */ + /* + This may happen if one does 'UPDATE ... SET x=x' + The test is here mostly for valgrind, but can also be relevant + if memcpy() is implemented with prefetch-write + */ if (to->ptr != from->ptr) -#endif memcpy(to->ptr,from->ptr,to->pack_length()); return 0; } diff --git a/sql/gen_lex_hash.cc b/sql/gen_lex_hash.cc index 5a0904f87b9..e8a83b34d9d 100644 --- a/sql/gen_lex_hash.cc +++ b/sql/gen_lex_hash.cc @@ -1,4 +1,4 @@ -/* Copyright (C) 2000-2006 MySQL AB +/* Copyright (C) 2000-2007 MySQL AB, 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 @@ -451,7 +451,7 @@ int main(int argc,char **argv) printf("/*\n\n Do " "not " "edit " "this " "file " "directly!\n\n*/\n"); printf("\ -/* Copyright 2001-2008 MySQL AB, 2008 Sun Microsystems, Inc.\n\ +/* Copyright (C) 2000-2008 MySQL AB, 2008 Sun Microsystems, Inc.\n\ \n\ This program is free software; you can redistribute it and/or modify\n\ it under the terms of the GNU General Public License as published by\n\ diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index 1a791507b22..56a4005e3e2 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -168,6 +168,7 @@ ha_partition::ha_partition(handlerton *hton, TABLE_SHARE *share) m_is_sub_partitioned(0) { DBUG_ENTER("ha_partition::ha_partition(table)"); + init_alloc_root(&m_mem_root, 512, 512); init_handler_variables(); DBUG_VOID_RETURN; } @@ -189,6 +190,7 @@ ha_partition::ha_partition(handlerton *hton, partition_info *part_info) m_is_sub_partitioned(m_part_info->is_sub_partitioned()) { DBUG_ENTER("ha_partition::ha_partition(part_info)"); + init_alloc_root(&m_mem_root, 512, 512); init_handler_variables(); DBUG_ASSERT(m_part_info); DBUG_VOID_RETURN; @@ -213,6 +215,7 @@ void ha_partition::init_handler_variables() m_file_buffer= NULL; m_name_buffer_ptr= NULL; m_engine_array= NULL; + m_connect_string= NULL; m_file= NULL; m_file_tot_parts= 0; m_reorged_file= NULL; @@ -287,9 +290,14 @@ ha_partition::~ha_partition() for (i= 0; i < m_tot_parts; i++) delete m_file[i]; } - my_free((char*) m_ordered_rec_buffer, MYF(MY_ALLOW_ZERO_PTR)); + + my_free(m_ordered_rec_buffer, MYF(MY_ALLOW_ZERO_PTR)); + m_ordered_rec_buffer= NULL; clear_handler_file(); + + free_root(&m_mem_root, MYF(0)); + DBUG_VOID_RETURN; } @@ -556,6 +564,13 @@ int ha_partition::create(const char *name, TABLE *table_arg, char t_name[FN_REFLEN]; DBUG_ENTER("ha_partition::create"); + if (create_info->used_fields & HA_CREATE_USED_CONNECTION) + { + my_error(ER_CONNECT_TO_FOREIGN_DATA_SOURCE, MYF(0), + "CONNECTION not valid for partition"); + DBUG_RETURN(1); + } + strmov(t_name, name); DBUG_ASSERT(*fn_rext((char*)name) == '\0'); if (del_ren_cre_table(t_name, NULL, table_arg, create_info)) @@ -1230,6 +1245,7 @@ int ha_partition::prepare_new_partition(TABLE *tbl, if ((error= set_up_table_before_create(tbl, part_name, create_info, 0, p_elem))) goto error_create; + tbl->s->connect_string = p_elem->connect_string; if ((error= file->ha_create(part_name, tbl, create_info))) { /* @@ -1750,6 +1766,8 @@ void ha_partition::update_create_info(HA_CREATE_INFO *create_info) create_info->auto_increment_value= stats.auto_increment_value; create_info->data_file_name= create_info->index_file_name = NULL; + create_info->connect_string.str= NULL; + create_info->connect_string.length= 0; return; } @@ -2039,6 +2057,10 @@ int ha_partition::set_up_table_before_create(TABLE *tbl, } info->index_file_name= part_elem->index_file_name; info->data_file_name= part_elem->data_file_name; + info->connect_string= part_elem->connect_string; + if (info->connect_string.length) + info->used_fields|= HA_CREATE_USED_CONNECTION; + tbl->s->connect_string= part_elem->connect_string; DBUG_RETURN(0); } @@ -2153,8 +2175,10 @@ bool ha_partition::create_handler_file(const char *name) tot_name_words= (tot_name_len + 3) / 4; tot_len_words= 4 + tot_partition_words + tot_name_words; tot_len_byte= 4 * tot_len_words; - if (!(file_buffer= (uchar *) my_malloc(tot_len_byte, MYF(MY_ZEROFILL)))) + file_buffer= (uchar *) my_alloca(tot_len_byte); + if (!file_buffer) DBUG_RETURN(TRUE); + bzero(file_buffer, tot_len_byte); engine_array= (file_buffer + 12); name_buffer_ptr= (char*) (file_buffer + ((4 + tot_partition_words) * 4)); part_it.rewind(); @@ -2210,11 +2234,24 @@ bool ha_partition::create_handler_file(const char *name) { result= my_write(file, (uchar *) file_buffer, tot_len_byte, MYF(MY_WME | MY_NABP)) != 0; + + part_it.rewind(); + for (i= 0; i < no_parts && !result; i++) + { + uchar buffer[4]; + part_elem= part_it++; + uint length = part_elem->connect_string.length; + int4store(buffer, length); + if (my_write(file, buffer, 4, MYF(MY_WME | MY_NABP)) || + my_write(file, (uchar *) part_elem->connect_string.str, length, + MYF(MY_WME | MY_NABP))) + result= TRUE; + } VOID(my_close(file, MYF(0))); } else result= TRUE; - my_free((char*) file_buffer, MYF(0)); + my_afree((char*) file_buffer); DBUG_RETURN(result); } @@ -2232,10 +2269,10 @@ void ha_partition::clear_handler_file() { if (m_engine_array) plugin_unlock_list(NULL, m_engine_array, m_tot_parts); - my_free((char*) m_file_buffer, MYF(MY_ALLOW_ZERO_PTR)); - my_free((char*) m_engine_array, MYF(MY_ALLOW_ZERO_PTR)); + free_root(&m_mem_root, MYF(MY_KEEP_PREALLOC)); m_file_buffer= NULL; m_engine_array= NULL; + m_connect_string= NULL; } /* @@ -2394,7 +2431,7 @@ bool ha_partition::get_from_handler_file(const char *name, MEM_ROOT *mem_root) goto err1; len_words= uint4korr(buff); len_bytes= 4 * len_words; - if (!(file_buffer= (char*) my_malloc(len_bytes, MYF(0)))) + if (!(file_buffer= (char*) alloc_root(&m_mem_root, len_bytes))) goto err1; VOID(my_seek(file, 0, MY_SEEK_SET, MYF(0))); if (my_read(file, (uchar *) file_buffer, len_bytes, MYF(MY_NABP))) @@ -2423,12 +2460,33 @@ bool ha_partition::get_from_handler_file(const char *name, MEM_ROOT *mem_root) if (len_words != (tot_partition_words + tot_name_words + 4)) goto err3; name_buffer_ptr= file_buffer + 16 + 4 * tot_partition_words; + + if (!(m_connect_string= (LEX_STRING*) + alloc_root(&m_mem_root, m_tot_parts * sizeof(LEX_STRING)))) + goto err3; + bzero(m_connect_string, m_tot_parts * sizeof(LEX_STRING)); + + for (i= 0; i < m_tot_parts; i++) + { + LEX_STRING connect_string; + uchar buffer[4]; + if (my_read(file, buffer, 4, MYF(MY_NABP))) + break; + connect_string.length= uint4korr(buffer); + connect_string.str= (char*) alloc_root(&m_mem_root, connect_string.length+1); + if (my_read(file, (uchar*) connect_string.str, connect_string.length, + MYF(MY_NABP))) + break; + connect_string.str[connect_string.length]= 0; + m_connect_string[i]= connect_string; + } + VOID(my_close(file, MYF(0))); m_file_buffer= file_buffer; // Will be freed in clear_handler_file() m_name_buffer_ptr= name_buffer_ptr; if (!(m_engine_array= (plugin_ref*) - my_malloc(m_tot_parts * sizeof(plugin_ref), MYF(MY_WME)))) + alloc_root(&m_mem_root, m_tot_parts * sizeof(plugin_ref)))) goto err3; for (i= 0; i < m_tot_parts; i++) @@ -2446,7 +2504,6 @@ bool ha_partition::get_from_handler_file(const char *name, MEM_ROOT *mem_root) err3: my_afree(engine_array); err2: - my_free(file_buffer, MYF(0)); err1: VOID(my_close(file, MYF(0))); DBUG_RETURN(TRUE); @@ -2562,9 +2619,11 @@ int ha_partition::open(const char *name, int mode, uint test_if_locked) { create_partition_name(name_buff, name, name_buffer_ptr, NORMAL_PART_NAME, FALSE); + table->s->connect_string = m_connect_string[(uint)(file-m_file)]; if ((error= (*file)->ha_open(table, (const char*) name_buff, mode, test_if_locked))) goto err_handler; + bzero(&table->s->connect_string, sizeof(LEX_STRING)); m_no_locks+= (*file)->lock_count(); name_buffer_ptr+= strlen(name_buffer_ptr) + 1; set_if_bigger(ref_length, ((*file)->ref_length)); @@ -3055,7 +3114,9 @@ int ha_partition::write_row(uchar * buf) my_bitmap_map *old_map; HA_DATA_PARTITION *ha_data= (HA_DATA_PARTITION*) table_share->ha_data; THD *thd= ha_thd(); - timestamp_auto_set_type orig_timestamp_type= table->timestamp_field_type; + timestamp_auto_set_type saved_timestamp_type= table->timestamp_field_type; + ulong saved_sql_mode= thd->variables.sql_mode; + bool saved_auto_inc_field_not_null= table->auto_increment_field_not_null; #ifdef NOT_NEEDED uchar *rec0= m_rec0; #endif @@ -3091,6 +3152,22 @@ int ha_partition::write_row(uchar * buf) */ if (error) goto exit; + + /* + Don't allow generation of auto_increment value the partitions handler. + If a partitions handler would change the value, then it might not + match the partition any longer. + This can occur if 'SET INSERT_ID = 0; INSERT (NULL)', + So allow this by adding 'MODE_NO_AUTO_VALUE_ON_ZERO' to sql_mode. + The partitions handler::next_insert_id must always be 0. Otherwise + we need to forward release_auto_increment, or reset it for all + partitions. + */ + if (table->next_number_field->val_int() == 0) + { + table->auto_increment_field_not_null= TRUE; + thd->variables.sql_mode|= MODE_NO_AUTO_VALUE_ON_ZERO; + } } old_map= dbug_tmp_use_all_columns(table, table->read_set); @@ -3124,7 +3201,9 @@ int ha_partition::write_row(uchar * buf) set_auto_increment_if_higher(table->next_number_field); reenable_binlog(thd); exit: - table->timestamp_field_type= orig_timestamp_type; + thd->variables.sql_mode= saved_sql_mode; + table->auto_increment_field_not_null= saved_auto_inc_field_not_null; + table->timestamp_field_type= saved_timestamp_type; DBUG_RETURN(error); } @@ -3191,11 +3270,24 @@ int ha_partition::update_row(const uchar *old_data, uchar *new_data) } else { + Field *saved_next_number_field= table->next_number_field; + /* + Don't allow generation of auto_increment value for update. + table->next_number_field is never set on UPDATE. + But is set for INSERT ... ON DUPLICATE KEY UPDATE, + and since update_row() does not generate or update an auto_inc value, + we cannot have next_number_field set when moving a row + to another partition with write_row(), since that could + generate/update the auto_inc value. + This gives the same behavior for partitioned vs non partitioned tables. + */ + table->next_number_field= NULL; DBUG_PRINT("info", ("Update from partition %d to partition %d", old_part_id, new_part_id)); tmp_disable_binlog(thd); /* Do not replicate the low-level changes. */ error= m_file[new_part_id]->ha_write_row(new_data); reenable_binlog(thd); + table->next_number_field= saved_next_number_field; if (error) goto exit; diff --git a/sql/ha_partition.h b/sql/ha_partition.h index 0cf1713ed13..f5e66c5913e 100644 --- a/sql/ha_partition.h +++ b/sql/ha_partition.h @@ -72,12 +72,14 @@ private: uint m_open_test_lock; // Open test_if_locked char *m_file_buffer; // Buffer with names char *m_name_buffer_ptr; // Pointer to first partition name + MEM_ROOT m_mem_root; plugin_ref *m_engine_array; // Array of types of the handlers handler **m_file; // Array of references to handler inst. uint m_file_tot_parts; // Debug handler **m_new_file; // Array of references to new handlers handler **m_reorged_file; // Reorganised partitions handler **m_added_file; // Added parts kept for errors + LEX_STRING *m_connect_string; partition_info *m_part_info; // local reference to partition Field **m_part_field_array; // Part field array locally to save acc uchar *m_ordered_rec_buffer; // Row and key buffer for ord. idx scan diff --git a/sql/handler.cc b/sql/handler.cc index 92e20b86c6d..a89c3c7f05c 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -1,4 +1,5 @@ -/* Copyright 2000-2008 MySQL AB, 2008 Sun Microsystems, Inc. +/* Copyright (c) 2000, 2011, Oracle and/or its affiliates. + Copyright (c) 2009-2011 Monty Program Ab This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -1200,7 +1201,11 @@ int ha_commit_trans(THD *thd, bool all) error=ha_commit_one_phase(thd, all) ? (cookie ? 2 : 1) : 0; DBUG_EXECUTE_IF("crash_commit_before_unlog", DBUG_SUICIDE();); if (cookie) - tc_log->unlog(cookie, xid); + if(tc_log->unlog(cookie, xid)) + { + error= 2; + goto end; + } DBUG_EXECUTE_IF("crash_commit_after", DBUG_SUICIDE();); end: if (rw_trans) @@ -2194,7 +2199,8 @@ int handler::read_first_row(uchar * buf, uint primary_key) computes the lowest number - strictly greater than "nr" - of the form: auto_increment_offset + N * auto_increment_increment - + If overflow happened then return MAX_ULONGLONG value as an + indication of overflow. In most cases increment= offset= 1, in which case we get: @verbatim 1,2,3,4,5,... @endverbatim If increment=10 and offset=5 and previous number is 1, we get: @@ -2203,13 +2209,23 @@ int handler::read_first_row(uchar * buf, uint primary_key) inline ulonglong compute_next_insert_id(ulonglong nr,struct system_variables *variables) { + const ulonglong save_nr= nr; + if (variables->auto_increment_increment == 1) - return (nr+1); // optimization of the formula below - nr= (((nr+ variables->auto_increment_increment - - variables->auto_increment_offset)) / - (ulonglong) variables->auto_increment_increment); - return (nr* (ulonglong) variables->auto_increment_increment + - variables->auto_increment_offset); + nr= nr + 1; // optimization of the formula below + else + { + nr= (((nr+ variables->auto_increment_increment - + variables->auto_increment_offset)) / + (ulonglong) variables->auto_increment_increment); + nr= (nr* (ulonglong) variables->auto_increment_increment + + variables->auto_increment_offset); + } + + if (unlikely(nr <= save_nr)) + return ULONGLONG_MAX; + + return nr; } @@ -2420,7 +2436,7 @@ int handler::update_auto_increment() variables->auto_increment_increment, nb_desired_values, &nr, &nb_reserved_values); - if (nr == ~(ulonglong) 0) + if (nr == ULONGLONG_MAX) DBUG_RETURN(HA_ERR_AUTOINC_READ_FAILED); // Mark failure /* @@ -2451,6 +2467,9 @@ int handler::update_auto_increment() } } + if (unlikely(nr == ULONGLONG_MAX)) + DBUG_RETURN(HA_ERR_AUTOINC_ERANGE); + DBUG_PRINT("info",("auto_increment: %lu", (ulong) nr)); if (unlikely(table->next_number_field->store((longlong) nr, TRUE))) @@ -2651,17 +2670,11 @@ void handler::print_keydup_error(uint key_nr, const char *msg) - table->alias */ -#ifndef DBUG_OFF #define SET_FATAL_ERROR fatal_error=1 -#else -#define SET_FATAL_ERROR -#endif void handler::print_error(int error, myf errflag) { -#ifndef DBUG_OFF bool fatal_error= 0; -#endif DBUG_ENTER("handler::print_error"); DBUG_PRINT("enter",("error: %d",error)); @@ -2869,6 +2882,15 @@ void handler::print_error(int error, myf errflag) DBUG_VOID_RETURN; } } + if (fatal_error && (debug_assert_if_crashed_table || + global_system_variables.log_warnings > 1)) + { + /* + Log error to log before we crash or if extended warnings are requested + */ + errflag|= ME_NOREFRESH; + } + my_error(textno, errflag, table_share->table_name.str, error); DBUG_ASSERT(!fatal_error || !debug_assert_if_crashed_table); DBUG_VOID_RETURN; @@ -4856,6 +4878,7 @@ int handler::ha_reset() free_io_cache(table); /* reset the bitmaps to point to defaults */ table->default_column_bitmaps(); + pushed_cond= NULL; DBUG_RETURN(reset()); } diff --git a/sql/item.cc b/sql/item.cc index c46598e6172..92dbff867c5 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -1736,16 +1736,7 @@ bool agg_item_set_converter(DTCollation &coll, const char *fname, if (!(conv= (*arg)->safe_charset_converter(coll.collation)) && ((*arg)->collation.repertoire == MY_REPERTOIRE_ASCII)) - { - /* - We should disable const subselect item evaluation because - subselect transformation does not happen in view_prepare_mode - and thus val_...() methods can not be called for const items. - */ - bool resolve_const= ((*arg)->type() == Item::SUBSELECT_ITEM && - thd->lex->view_prepare_mode) ? FALSE : TRUE; - conv= new Item_func_conv_charset(*arg, coll.collation, resolve_const); - } + conv= new Item_func_conv_charset(*arg, coll.collation, 1); if (!conv) { @@ -5321,8 +5312,17 @@ static uint nr_of_decimals(const char *str, const char *end) /** - This function is only called during parsing. We will signal an error if - value is not a true double value (overflow) + This function is only called during parsing: + - when parsing SQL query from sql_yacc.yy + - when parsing XPath query from item_xmlfunc.cc + We will signal an error if value is not a true double value (overflow): + eng: Illegal %s '%-.192s' value found during parsing + + Note: the string is NOT null terminated when called from item_xmlfunc.cc, + so this->name will contain some SQL query tail behind the "length" bytes. + This is Ok for now, as this Item is never seen in SHOW, + or EXPLAIN, or anywhere else in metadata. + Item->name should be fixed to use LEX_STRING eventually. */ Item_float::Item_float(const char *str_arg, uint length) @@ -5333,12 +5333,9 @@ Item_float::Item_float(const char *str_arg, uint length) &error); if (error) { - /* - Note that we depend on that str_arg is null terminated, which is true - when we are in the parser - */ - DBUG_ASSERT(str_arg[length] == 0); - my_error(ER_ILLEGAL_VALUE_FOR_TYPE, MYF(0), "double", (char*) str_arg); + char tmp[NAME_LEN + 1]; + my_snprintf(tmp, sizeof(tmp), "%.*s", length, str_arg); + my_error(ER_ILLEGAL_VALUE_FOR_TYPE, MYF(0), "double", tmp); } presentation= name=(char*) str_arg; decimals=(uint8) nr_of_decimals(str_arg, str_arg+length); @@ -5610,6 +5607,10 @@ bool Item::send(Protocol *protocol, String *buffer) String *res; if ((res=val_str(buffer))) result= protocol->store(res->ptr(),res->length(),res->charset()); + else + { + DBUG_ASSERT(null_value); + } break; } case MYSQL_TYPE_TINY: diff --git a/sql/item.h b/sql/item.h index 3f732cf126e..28856842b99 100644 --- a/sql/item.h +++ b/sql/item.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2000, 2010 Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2000, 2011, Oracle and/or its affiliates. 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 @@ -1050,11 +1050,11 @@ public: virtual bool set_no_const_sub(uchar *arg) { return FALSE; } virtual Item *replace_equal_field(uchar * arg) { return this; } /* - Check if an expression value depends on the current timezone. Used by - partitioning code to reject timezone-dependent expressions in a - (sub)partitioning function. + Check if an expression value has allowed arguments, like DATE/DATETIME + for date functions. Also used by partitioning code to reject + timezone-dependent expressions in a (sub)partitioning function. */ - virtual bool is_timezone_dependent_processor(uchar *bool_arg) + virtual bool check_valid_arguments_processor(uchar *bool_arg) { return FALSE; } @@ -3130,11 +3130,10 @@ class Item_cache: public Item_basic_constant protected: Item *example; table_map used_table_map; - /* - Field that this object will get value from. This is set/used by + /** + Field that this object will get value from. This is used by index-based subquery engines to detect and remove the equality injected by IN->EXISTS transformation. - For all other uses of Item_cache, cached_field doesn't matter. */ Field *cached_field; enum enum_field_types cached_field_type; @@ -3196,6 +3195,13 @@ public: return trace_unsupported_by_check_vcol_func_processor("cache"); } + /** + If this item caches a field value, return pointer to underlying field. + + @return Pointer to field, or NULL if this is not a cache for a field value. + */ + Field* field() { return cached_field; } + virtual void store(Item *item); virtual bool cache_value()= 0; }; diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index d7fa6cba030..51a73d774a8 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2000, 2010 Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2000, 2011, Oracle and/or its affiliates. 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 @@ -401,7 +401,7 @@ static bool convert_constant_item(THD *thd, Item_field *field_item, Field *field= field_item->field; int result= 0; - if (!(*item)->with_subselect && (*item)->const_item()) + if ((*item)->const_item()) { TABLE *table= field->table; ulong orig_sql_mode= thd->variables.sql_mode; @@ -497,7 +497,7 @@ void Item_bool_func2::fix_length_and_dec() } thd= current_thd; - if (!thd->is_context_analysis_only()) + if (!thd->lex->is_ps_or_view_context_analysis()) { if (args[0]->real_item()->type() == FIELD_ITEM) { @@ -801,7 +801,7 @@ Arg_comparator::can_compare_as_dates(Item *a, Item *b, ulonglong *const_value) confuse storage engines since in context analysis mode tables aren't locked. */ - if (!thd->is_context_analysis_only() && + if (!thd->lex->is_ps_or_view_context_analysis() && cmp_type != CMP_DATE_WITH_DATE && str_arg->const_item() && (str_arg->type() != Item::FUNC_ITEM || ((Item_func*)str_arg)->functype() != Item_func::GUSERVAR_FUNC)) @@ -1035,7 +1035,7 @@ Item** Arg_comparator::cache_converted_constant(THD *thd_arg, Item **value, Item_result type) { /* Don't need cache if doing context analysis only. */ - if (!thd_arg->is_context_analysis_only() && + if (!thd->lex->is_ps_or_view_context_analysis() && (*value)->const_item() && type != (*value)->result_type()) { Item_cache *cache= Item_cache::get_cache(*value, type); @@ -1209,9 +1209,12 @@ get_year_value(THD *thd, Item ***item_arg, Item **cache_arg, value of 2000. */ Item *real_item= item->real_item(); - if (!(real_item->type() == Item::FIELD_ITEM && - ((Item_field *)real_item)->field->type() == MYSQL_TYPE_YEAR && - ((Item_field *)real_item)->field->field_length == 4)) + Field *field= NULL; + if (real_item->type() == Item::FIELD_ITEM) + field= ((Item_field *)real_item)->field; + else if (real_item->type() == Item::CACHE_ITEM) + field= ((Item_cache *)real_item)->field(); + if (!(field && field->type() == MYSQL_TYPE_YEAR && field->field_length == 4)) { if (value < 70) value+= 100; @@ -4708,12 +4711,13 @@ bool Item_func_like::fix_fields(THD *thd, Item **ref) return TRUE; } - if (escape_item->const_item() && !thd->lex->view_prepare_mode) + if (escape_item->const_item()) { /* If we are on execution stage */ String *escape_str= escape_item->val_str(&cmp.value1); if (escape_str) { + const char *escape_str_ptr= escape_str->ptr(); if (escape_used_in_parsing && ( (((thd->variables.sql_mode & MODE_NO_BACKSLASH_ESCAPES) && escape_str->numchars() != 1) || @@ -4728,9 +4732,9 @@ bool Item_func_like::fix_fields(THD *thd, Item **ref) CHARSET_INFO *cs= escape_str->charset(); my_wc_t wc; int rc= cs->cset->mb_wc(cs, &wc, - (const uchar*) escape_str->ptr(), - (const uchar*) escape_str->ptr() + - escape_str->length()); + (const uchar*) escape_str_ptr, + (const uchar*) escape_str_ptr + + escape_str->length()); escape= (int) (rc > 0 ? wc : '\\'); } else @@ -4747,13 +4751,13 @@ bool Item_func_like::fix_fields(THD *thd, Item **ref) { char ch; uint errors; - uint32 cnvlen= copy_and_convert(&ch, 1, cs, escape_str->ptr(), + uint32 cnvlen= copy_and_convert(&ch, 1, cs, escape_str_ptr, escape_str->length(), escape_str->charset(), &errors); escape= cnvlen ? ch : '\\'; } else - escape= *(escape_str->ptr()); + escape= escape_str_ptr ? *escape_str_ptr : '\\'; } } else diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index c45d6bef315..2cacd92bc8a 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2000, 2010 Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. 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 diff --git a/sql/item_create.cc b/sql/item_create.cc index eade395a229..b3a0e7cf3b2 100644 --- a/sql/item_create.cc +++ b/sql/item_create.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2000, 2010 Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2000, 2010 Oracle and/or its affiliates. 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 diff --git a/sql/item_create.h b/sql/item_create.h index 848f4793c83..e9824a71132 100644 --- a/sql/item_create.h +++ b/sql/item_create.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2000, 2010 Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2000, 2010 Oracle and/or its affiliates. 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 diff --git a/sql/item_func.cc b/sql/item_func.cc index 28104edc653..b5e70ac84ef 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -1,4 +1,4 @@ -/* Copyright 2000-2008 MySQL AB, 2008 Sun Microsystems, Inc. +/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. 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 @@ -157,7 +157,14 @@ Item_func::fix_fields(THD *thd, Item **ref) used_tables_cache= not_null_tables_cache= 0; const_item_cache=1; - if (check_stack_overrun(thd, STACK_MIN_SIZE, buff)) + /* + Use stack limit of STACK_MIN_SIZE * 2 since + on some platforms a recursive call to fix_fields + requires more than STACK_MIN_SIZE bytes (e.g. for + MIPS, it takes about 22kB to make one recursive + call to Item_func::fix_fields()) + */ + if (check_stack_overrun(thd, STACK_MIN_SIZE * 2, buff)) return TRUE; // Fatal error if flag is set! if (arg_count) { // Print purify happy @@ -1336,9 +1343,14 @@ void Item_func_div::fix_length_and_dec() { decimals=max(args[0]->decimals,args[1]->decimals)+prec_increment; set_if_smaller(decimals, NOT_FIXED_DEC); - max_length=args[0]->max_length - args[0]->decimals + decimals; uint tmp=float_length(decimals); - set_if_smaller(max_length,tmp); + if (decimals == NOT_FIXED_DEC) + max_length= tmp; + else + { + max_length=args[0]->max_length - args[0]->decimals + decimals; + set_if_smaller(max_length,tmp); + } break; } case INT_RESULT: @@ -3970,7 +3982,7 @@ update_hash(user_var_entry *entry, bool set_null, void *ptr, uint length, length--; // Fix length change above entry->value[length]= 0; // Store end \0 } - memcpy(entry->value,ptr,length); + memmove(entry->value, ptr, length); if (type == DECIMAL_RESULT) ((my_decimal*)entry->value)->fix_buffer_pointer(); entry->length= length; @@ -4114,7 +4126,7 @@ my_decimal *user_var_entry::val_decimal(bool *null_value, my_decimal *val) int2my_decimal(E_DEC_FATAL_ERROR, *(longlong*) value, 0, val); break; case DECIMAL_RESULT: - val= (my_decimal *)value; + my_decimal2decimal((my_decimal *) value, val); break; case STRING_RESULT: str2my_decimal(E_DEC_FATAL_ERROR, value, length, collation.collation, val); @@ -4927,7 +4939,7 @@ void Item_func_get_system_var::fix_length_and_dec() decimals=0; break; case SHOW_LONGLONG: - unsigned_flag= FALSE; + unsigned_flag= TRUE; max_length= MY_INT64_NUM_DECIMAL_DIGITS; decimals=0; break; @@ -5068,7 +5080,7 @@ longlong Item_func_get_system_var::val_int() { case SHOW_INT: get_sys_var_safe (uint); case SHOW_LONG: get_sys_var_safe (ulong); - case SHOW_LONGLONG: get_sys_var_safe (longlong); + case SHOW_LONGLONG: get_sys_var_safe (ulonglong); case SHOW_HA_ROWS: get_sys_var_safe (ha_rows); case SHOW_BOOL: get_sys_var_safe (bool); case SHOW_MY_BOOL: get_sys_var_safe (my_bool); @@ -6117,7 +6129,7 @@ Item_func_sp::fix_fields(THD *thd, Item **ref) if (res) DBUG_RETURN(res); - if (thd->lex->view_prepare_mode) + if (thd->lex->context_analysis_only & CONTEXT_ANALYSIS_ONLY_VIEW) { /* Here we check privileges of the stored routine only during view diff --git a/sql/item_func.h b/sql/item_func.h index 99660bd2a40..a41324b4102 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -1,4 +1,4 @@ -/* Copyright 2000-2008 MySQL AB, 2008 Sun Microsystems, Inc. +/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. 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 @@ -190,6 +190,7 @@ public: null_value=1; return 0.0; } + bool has_timestamp_args() { DBUG_ASSERT(fixed == TRUE); @@ -201,6 +202,45 @@ public: } return FALSE; } + + bool has_date_args() + { + DBUG_ASSERT(fixed == TRUE); + for (uint i= 0; i < arg_count; i++) + { + if (args[i]->type() == Item::FIELD_ITEM && + (args[i]->field_type() == MYSQL_TYPE_DATE || + args[i]->field_type() == MYSQL_TYPE_DATETIME)) + return TRUE; + } + return FALSE; + } + + bool has_time_args() + { + DBUG_ASSERT(fixed == TRUE); + for (uint i= 0; i < arg_count; i++) + { + if (args[i]->type() == Item::FIELD_ITEM && + (args[i]->field_type() == MYSQL_TYPE_TIME || + args[i]->field_type() == MYSQL_TYPE_DATETIME)) + return TRUE; + } + return FALSE; + } + + bool has_datetime_args() + { + DBUG_ASSERT(fixed == TRUE); + for (uint i= 0; i < arg_count; i++) + { + if (args[i]->type() == Item::FIELD_ITEM && + args[i]->field_type() == MYSQL_TYPE_DATETIME) + return TRUE; + } + return FALSE; + } + /* We assume the result of any function that has a TIMESTAMP argument to be timezone-dependent, since a TIMESTAMP value in both numeric and string @@ -209,7 +249,7 @@ public: representation of a TIMESTAMP argument verbatim, and thus does not depend on the timezone. */ - virtual bool is_timezone_dependent_processor(uchar *bool_arg) + virtual bool check_valid_arguments_processor(uchar *bool_arg) { return has_timestamp_args(); } diff --git a/sql/item_geofunc.h b/sql/item_geofunc.h index b3ecbc39933..0bcd933e52b 100644 --- a/sql/item_geofunc.h +++ b/sql/item_geofunc.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2000-2003 MySQL AB +/* Copyright (c) 2003, 2011, Oracle and/or its affiliates. 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 @@ -177,6 +177,7 @@ public: String *val_str(String *); void fix_length_and_dec() { + Item_geometry_func::fix_length_and_dec(); for (unsigned int i= 0; i < arg_count; ++i) { if (args[i]->fixed && args[i]->field_type() != MYSQL_TYPE_GEOMETRY) diff --git a/sql/item_row.cc b/sql/item_row.cc index 7535c1fa80b..408bc11eb9b 100644 --- a/sql/item_row.cc +++ b/sql/item_row.cc @@ -73,12 +73,8 @@ bool Item_row::fix_fields(THD *thd, Item **ref) used_tables_cache |= item->used_tables(); const_item_cache&= item->const_item() && !with_null; not_null_tables_cache|= item->not_null_tables(); - /* - Some subqueries transformations aren't done in the view_prepare_mode thus - is_null() will fail. So we skip is_null() calculation for CREATE VIEW as - not necessary. - */ - if (const_item_cache && !thd->lex->view_prepare_mode) + + if (const_item_cache) { if (item->cols() > 1) with_null|= item->null_inside(); diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index aebbc21b0fc..ad88fe31a0d 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -905,9 +905,15 @@ String *Item_func_replace::val_str(String *str) search=res2->ptr(); search_end=search+from_length; redo: + DBUG_ASSERT(res->ptr() || !offset); ptr=res->ptr()+offset; strend=res->ptr()+res->length(); - end=strend-from_length+1; + /* + In some cases val_str() can return empty string + with ptr() == NULL and length() == 0. + Let's check strend to avoid overflow. + */ + end= strend ? strend - from_length + 1 : NULL; while (ptr < end) { if (*ptr == *search) diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 6d3a4c66649..02f708cdf91 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -1,4 +1,4 @@ -/* Copyright (C) 2000 MySQL AB +/* Copyright (c) 2002, 2010, Oracle and/or its affiliates. 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 @@ -124,20 +124,6 @@ void Item_subselect::cleanup() } -/* - We cannot use generic Item::safe_charset_converter() because - Subselect transformation does not happen in view_prepare_mode - and thus we can not evaluate val_...() for const items. -*/ - -Item *Item_subselect::safe_charset_converter(CHARSET_INFO *tocs) -{ - Item_func_conv_charset *conv= - new Item_func_conv_charset(this, tocs, thd->lex->view_prepare_mode ? 0 : 1); - return conv->safe ? conv : NULL; -} - - void Item_singlerow_subselect::cleanup() { DBUG_ENTER("Item_singlerow_subselect::cleanup"); @@ -295,6 +281,7 @@ bool Item_subselect::exec() if (thd->is_error() || thd->killed) return 1; + DBUG_ASSERT(!thd->lex->context_analysis_only); /* Simulate a failure in sub-query execution. Used to test e.g. out of memory or query being killed conditions. @@ -331,7 +318,7 @@ table_map Item_subselect::used_tables() const bool Item_subselect::const_item() const { - return const_item_cache; + return thd->lex->context_analysis_only ? FALSE : const_item_cache; } Item *Item_subselect::get_tmp_table_item(THD *thd_arg) @@ -1663,7 +1650,8 @@ bool Item_in_subselect::fix_fields(THD *thd_arg, Item **ref) { bool result = 0; - if (thd_arg->lex->view_prepare_mode && left_expr && !left_expr->fixed) + if ((thd_arg->lex->context_analysis_only & CONTEXT_ANALYSIS_ONLY_VIEW) && + left_expr && !left_expr->fixed) result = left_expr->fix_fields(thd_arg, &left_expr); return result || Item_subselect::fix_fields(thd_arg, ref); diff --git a/sql/item_subselect.h b/sql/item_subselect.h index 48bfaab4e3a..16b901e1333 100644 --- a/sql/item_subselect.h +++ b/sql/item_subselect.h @@ -141,7 +141,6 @@ public: { return trace_unsupported_by_check_vcol_func_processor("subselect"); } - Item *safe_charset_converter(CHARSET_INFO *tocs); /** Get the SELECT_LEX structure associated with this Item. diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 86d1b693f28..40ece652ba3 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2000, 2010 Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. 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 @@ -661,8 +661,10 @@ void Item_sum_hybrid::setup_hybrid(Item *item, Item *value_arg) value= Item_cache::get_cache(item); value->setup(item); value->store(value_arg); + arg_cache= Item_cache::get_cache(item); + arg_cache->setup(item); cmp= new Arg_comparator(); - cmp->set_cmp_func(this, args, (Item**)&value, FALSE); + cmp->set_cmp_func(this, (Item**)&arg_cache, (Item**)&value, FALSE); collation.set(item->collation); } @@ -1648,11 +1650,11 @@ Item *Item_sum_min::copy_or_same(THD* thd) bool Item_sum_min::add() { /* args[0] < value */ - int res= cmp->compare(); - if (!args[0]->null_value && - (null_value || res < 0)) + arg_cache->cache_value(); + if (!arg_cache->null_value && + (null_value || cmp->compare() < 0)) { - value->store(args[0]); + value->store(arg_cache); value->cache_value(); null_value= 0; } @@ -1671,11 +1673,11 @@ Item *Item_sum_max::copy_or_same(THD* thd) bool Item_sum_max::add() { /* args[0] > value */ - int res= cmp->compare(); - if (!args[0]->null_value && - (null_value || res > 0)) + arg_cache->cache_value(); + if (!arg_cache->null_value && + (null_value || cmp->compare() > 0)) { - value->store(args[0]); + value->store(arg_cache); value->cache_value(); null_value= 0; } @@ -3026,6 +3028,7 @@ Item_func_group_concat(Name_resolution_context *context_arg, order_item->item= arg_ptr++; } } + memcpy(orig_args, args, sizeof(Item*) * arg_count); } @@ -3255,7 +3258,6 @@ Item_func_group_concat::fix_fields(THD *thd, Item **ref) if (check_sum_func(thd, ref)) return TRUE; - memcpy (orig_args, args, sizeof (Item *) * arg_count); fixed= 1; return FALSE; } diff --git a/sql/item_sum.h b/sql/item_sum.h index 46e5ae76ab1..8e8f8ac99d2 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2000, 2010 Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2000, 2010 Oracle and/or its affiliates. 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 @@ -850,7 +850,7 @@ class Item_cache; class Item_sum_hybrid :public Item_sum { protected: - Item_cache *value; + Item_cache *value, *arg_cache; Arg_comparator *cmp; Item_result hybrid_type; enum_field_types hybrid_field_type; @@ -860,14 +860,14 @@ protected: public: Item_sum_hybrid(Item *item_par,int sign) - :Item_sum(item_par), value(0), cmp(0), + :Item_sum(item_par), value(0), arg_cache(0), cmp(0), hybrid_type(INT_RESULT), hybrid_field_type(MYSQL_TYPE_LONGLONG), cmp_sign(sign), was_values(TRUE) { collation.set(&my_charset_bin); } Item_sum_hybrid(THD *thd, Item_sum_hybrid *item) - :Item_sum(thd, item), value(item->value), hybrid_type(item->hybrid_type), - hybrid_field_type(item->hybrid_field_type), cmp_sign(item->cmp_sign), - was_values(item->was_values) + :Item_sum(thd, item), value(item->value), arg_cache(0), + hybrid_type(item->hybrid_type), hybrid_field_type(item->hybrid_field_type), + cmp_sign(item->cmp_sign), was_values(item->was_values) { } bool fix_fields(THD *, Item **); void setup_hybrid(Item *item, Item *value_arg); diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index 443bf3faf6f..9cf56148994 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -2463,14 +2463,14 @@ String *Item_char_typecast::val_str(String *str) { // Convert character set if differ uint dummy_errors; - if (!(res= args[0]->val_str(&tmp_value)) || - str->copy(res->ptr(), res->length(), from_cs, - cast_cs, &dummy_errors)) + if (!(res= args[0]->val_str(str)) || + tmp_value.copy(res->ptr(), res->length(), from_cs, + cast_cs, &dummy_errors)) { null_value= 1; return 0; } - res= str; + res= &tmp_value; } res->set_charset(cast_cs); @@ -2504,9 +2504,9 @@ String *Item_char_typecast::val_str(String *str) { if (res->alloced_length() < (uint) cast_length) { - str->alloc(cast_length); - str->copy(*res); - res= str; + str_value.alloc(cast_length); + str_value.copy(*res); + res= &str_value; } bzero((char*) res->ptr() + res->length(), (uint) cast_length - res->length()); diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h index 49fa87efd7b..87af384923e 100644 --- a/sql/item_timefunc.h +++ b/sql/item_timefunc.h @@ -71,6 +71,10 @@ public: longlong val_int_endpoint(bool left_endp, bool *incl_endp); bool check_partition_func_processor(uchar *int_arg) {return FALSE;} bool check_vcol_func_processor(uchar *int_arg) { return FALSE;} + bool check_valid_arguments_processor(uchar *int_arg) + { + return !has_date_args(); + } }; @@ -88,6 +92,10 @@ public: } bool check_partition_func_processor(uchar *int_arg) {return FALSE;} bool check_vcol_func_processor(uchar *int_arg) { return FALSE;} + bool check_valid_arguments_processor(uchar *int_arg) + { + return !has_date_args(); + } }; @@ -114,6 +122,10 @@ public: } bool check_partition_func_processor(uchar *int_arg) {return FALSE;} bool check_vcol_func_processor(uchar *int_arg) { return FALSE;} + bool check_valid_arguments_processor(uchar *int_arg) + { + return !has_date_args(); + } }; @@ -145,6 +157,10 @@ public: } bool check_partition_func_processor(uchar *int_arg) {return FALSE;} bool check_vcol_func_processor(uchar *int_arg) { return FALSE;} + bool check_valid_arguments_processor(uchar *int_arg) + { + return !has_date_args(); + } }; @@ -162,6 +178,10 @@ public: } bool check_partition_func_processor(uchar *int_arg) {return FALSE;} bool check_vcol_func_processor(uchar *int_arg) { return FALSE;} + bool check_valid_arguments_processor(uchar *int_arg) + { + return !has_time_args(); + } }; @@ -179,6 +199,10 @@ public: } bool check_partition_func_processor(uchar *int_arg) {return FALSE;} bool check_vcol_func_processor(uchar *int_arg) { return FALSE;} + bool check_valid_arguments_processor(uchar *int_arg) + { + return !has_time_args(); + } }; @@ -196,6 +220,10 @@ public: } bool check_partition_func_processor(uchar *int_arg) {return FALSE;} bool check_vcol_func_processor(uchar *int_arg) { return FALSE;} + bool check_valid_arguments_processor(uchar *int_arg) + { + return !has_date_args(); + } }; @@ -213,6 +241,10 @@ public: } bool check_partition_func_processor(uchar *int_arg) {return FALSE;} bool check_vcol_func_processor(uchar *int_arg) { return FALSE;} + bool check_valid_arguments_processor(uchar *int_arg) + { + return !has_time_args(); + } }; @@ -244,6 +276,10 @@ public: } bool check_partition_func_processor(uchar *int_arg) {return FALSE;} bool check_vcol_func_processor(uchar *int_arg) { return FALSE;} + bool check_valid_arguments_processor(uchar *int_arg) + { + return !has_date_args(); + } }; @@ -263,6 +299,10 @@ public: } bool check_partition_func_processor(uchar *int_arg) {return FALSE;} bool check_vcol_func_processor(uchar *int_arg) { return FALSE;} + bool check_valid_arguments_processor(uchar *int_arg) + { + return !has_date_args(); + } }; @@ -294,6 +334,10 @@ public: } bool check_partition_func_processor(uchar *int_arg) {return FALSE;} bool check_vcol_func_processor(uchar *int_arg) { return FALSE;} + bool check_valid_arguments_processor(uchar *int_arg) + { + return !has_date_args(); + } }; class Item_func_dayname :public Item_func_weekday @@ -324,7 +368,7 @@ public: (and thus may not be used as a partitioning function) when its argument is NOT of the TIMESTAMP type. */ - bool is_timezone_dependent_processor(uchar *int_arg) + bool check_valid_arguments_processor(uchar *int_arg) { return !has_timestamp_args(); } @@ -352,11 +396,16 @@ public: const char *func_name() const { return "time_to_sec"; } void fix_length_and_dec() { + maybe_null= TRUE; decimals=0; max_length=10*MY_CHARSET_BIN_MB_MAXLEN; } bool check_partition_func_processor(uchar *int_arg) {return FALSE;} bool check_vcol_func_processor(uchar *int_arg) { return FALSE;} + bool check_valid_arguments_processor(uchar *int_arg) + { + return !has_time_args(); + } }; @@ -623,6 +672,10 @@ public: bool get_date(MYSQL_TIME *res, uint fuzzy_date); bool check_partition_func_processor(uchar *int_arg) {return FALSE;} bool check_vcol_func_processor(uchar *int_arg) { return FALSE;} + bool check_valid_arguments_processor(uchar *int_arg) + { + return has_date_args() || has_time_args(); + } }; @@ -750,6 +803,42 @@ class Item_extract :public Item_int_func virtual void print(String *str, enum_query_type query_type); bool check_partition_func_processor(uchar *int_arg) {return FALSE;} bool check_vcol_func_processor(uchar *int_arg) { return FALSE;} + bool check_valid_arguments_processor(uchar *int_arg) + { + switch (int_type) { + case INTERVAL_YEAR: + case INTERVAL_YEAR_MONTH: + case INTERVAL_QUARTER: + case INTERVAL_MONTH: + /* case INTERVAL_WEEK: Not allowed as partitioning function, bug#57071 */ + case INTERVAL_DAY: + return !has_date_args(); + case INTERVAL_DAY_HOUR: + case INTERVAL_DAY_MINUTE: + case INTERVAL_DAY_SECOND: + case INTERVAL_DAY_MICROSECOND: + return !has_datetime_args(); + case INTERVAL_HOUR: + case INTERVAL_HOUR_MINUTE: + case INTERVAL_HOUR_SECOND: + case INTERVAL_MINUTE: + case INTERVAL_MINUTE_SECOND: + case INTERVAL_SECOND: + case INTERVAL_MICROSECOND: + case INTERVAL_HOUR_MICROSECOND: + case INTERVAL_MINUTE_MICROSECOND: + case INTERVAL_SECOND_MICROSECOND: + return !has_time_args(); + default: + /* + INTERVAL_LAST is only an end marker, + INTERVAL_WEEK depends on default_week_format which is a session + variable and cannot be used for partitioning. See bug#57071. + */ + break; + } + return true; + } }; @@ -1001,6 +1090,10 @@ public: } bool check_partition_func_processor(uchar *int_arg) {return FALSE;} bool check_vcol_func_processor(uchar *int_arg) { return FALSE;} + bool check_valid_arguments_processor(uchar *int_arg) + { + return !has_time_args(); + } }; diff --git a/sql/item_xmlfunc.cc b/sql/item_xmlfunc.cc index 537965b60cc..f491da5b95a 100644 --- a/sql/item_xmlfunc.cc +++ b/sql/item_xmlfunc.cc @@ -2799,12 +2799,12 @@ String *Item_func_xml_extractvalue::val_str(String *str) null_value= 0; if (!nodeset_func || !(res= args[0]->val_str(str)) || - !parse_xml(res, &pxml)) + !parse_xml(res, &pxml) || + !(res= nodeset_func->val_str(&tmp_value))) { null_value= 1; return 0; } - res= nodeset_func->val_str(&tmp_value); return res; } diff --git a/sql/lock.cc b/sql/lock.cc index 8f5b5ac233f..9a069d6d96f 100644 --- a/sql/lock.cc +++ b/sql/lock.cc @@ -923,7 +923,10 @@ static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count, *to++= table; if (locks) for ( ; org_locks != locks ; org_locks++) + { (*org_locks)->debug_print_param= (void *) table; + (*org_locks)->lock->name= table->alias.c_ptr(); + } } /* We do not use 'tables', because there are cases where store_lock() diff --git a/sql/log.cc b/sql/log.cc index 7d837938ab4..5c72ce96890 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -1,4 +1,4 @@ -/* Copyright 2000-2008 MySQL AB, 2008 Sun Microsystems, Inc. +/* Copyright (c) 2000, 2011, Oracle and/or its affiliates. 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 @@ -1907,10 +1907,11 @@ static int find_uniq_filename(char *name) *end='.'; length= (size_t) (end-start+1); - if (!(dir_info = my_dir(buff,MYF(MY_DONT_SORT)))) + if ((DBUG_EVALUATE_IF("error_unique_log_filename", 1, + !(dir_info = my_dir(buff,MYF(MY_DONT_SORT)))))) { // This shouldn't happen strmov(end,".1"); // use name+1 - DBUG_RETURN(0); + DBUG_RETURN(1); } file_info= dir_info->dir_entry; for (i=dir_info->number_off_files ; i-- ; file_info++) @@ -1924,8 +1925,7 @@ static int find_uniq_filename(char *name) my_dirend(dir_info); *end++='.'; - sprintf(end,"%06ld",max_found+1); - DBUG_RETURN(0); + DBUG_RETURN((sprintf(end,"%06ld",max_found+1) < 0)); } @@ -2137,6 +2137,8 @@ int MYSQL_LOG::generate_new_name(char *new_name, const char *log_name) { if (find_uniq_filename(new_name)) { + my_printf_error(ER_NO_UNIQUE_LOGFILE, ER(ER_NO_UNIQUE_LOGFILE), + MYF(ME_FATALERROR), log_name); sql_print_error(ER(ER_NO_UNIQUE_LOGFILE), log_name); return 1; } @@ -2658,6 +2660,23 @@ bool MYSQL_BIN_LOG::open(const char *log_name, sync_purge_index_file() || DBUG_EVALUATE_IF("fault_injection_registering_index", 1, 0)) { + /** + TODO: although this was introduced to appease valgrind + when injecting emulated faults using fault_injection_registering_index + it may be good to consider what actually happens when + open_purge_index_file succeeds but register or sync fails. + + Perhaps we might need the code below in MYSQL_LOG_BIN::cleanup + for "real life" purposes as well? + */ + DBUG_EXECUTE_IF("fault_injection_registering_index", { + if (my_b_inited(&purge_index_file)) + { + end_io_cache(&purge_index_file); + my_close(purge_index_file.file, MYF(0)); + } + }); + sql_print_error("MSYQL_BIN_LOG::open failed to sync the index file."); DBUG_RETURN(1); } @@ -3098,7 +3117,7 @@ bool MYSQL_BIN_LOG::reset_logs(THD* thd) } /* Start logging with a new file */ - close(LOG_CLOSE_INDEX); + close(LOG_CLOSE_INDEX | LOG_CLOSE_TO_BE_OPENED); if ((error= my_delete_allow_opened(index_file_name, MYF(0)))) // Reset (open will update) { if (my_errno == ENOENT) @@ -3127,7 +3146,8 @@ bool MYSQL_BIN_LOG::reset_logs(THD* thd) if (!thd->slave_thread) need_start_event=1; if (!open_index_file(index_file_name, 0, FALSE)) - open(save_name, log_type, 0, io_cache_type, no_auto_events, max_size, 0, FALSE); + if ((error= open(save_name, log_type, 0, io_cache_type, no_auto_events, max_size, 0, FALSE))) + goto err; my_free((uchar*) save_name, MYF(0)); err: @@ -3789,17 +3809,23 @@ bool MYSQL_BIN_LOG::is_active(const char *log_file_name_arg) incapsulation 3) allows external access to the class without a lock (which is not possible with private new_file_without_locking method). + + @retval + nonzero - error */ -void MYSQL_BIN_LOG::new_file() +int MYSQL_BIN_LOG::new_file() { - new_file_impl(1); + return new_file_impl(1); } - -void MYSQL_BIN_LOG::new_file_without_locking() +/* + @retval + nonzero - error + */ +int MYSQL_BIN_LOG::new_file_without_locking() { - new_file_impl(0); + return new_file_impl(0); } @@ -3808,19 +3834,23 @@ void MYSQL_BIN_LOG::new_file_without_locking() @param need_lock Set to 1 if caller has not locked LOCK_log + @retval + nonzero - error + @note The new file name is stored last in the index file */ -void MYSQL_BIN_LOG::new_file_impl(bool need_lock) +int MYSQL_BIN_LOG::new_file_impl(bool need_lock) { - char new_name[FN_REFLEN], *new_name_ptr, *old_name; + int error= 0, close_on_error= FALSE; + char new_name[FN_REFLEN], *new_name_ptr, *old_name, *file_to_open; DBUG_ENTER("MYSQL_BIN_LOG::new_file_impl"); if (!is_open()) { DBUG_PRINT("info",("log is closed")); - DBUG_VOID_RETURN; + DBUG_RETURN(error); } if (need_lock) @@ -3858,7 +3888,7 @@ void MYSQL_BIN_LOG::new_file_impl(bool need_lock) We have to do this here and not in open as we want to store the new file name in the current binary log file. */ - if (generate_new_name(new_name, name)) + if ((error= generate_new_name(new_name, name))) goto end; new_name_ptr=new_name; @@ -3872,7 +3902,14 @@ void MYSQL_BIN_LOG::new_file_impl(bool need_lock) */ Rotate_log_event r(new_name+dirname_length(new_name), 0, LOG_EVENT_OFFSET, is_relay_log ? Rotate_log_event::RELAY_LOG : 0); - r.write(&log_file); + if(DBUG_EVALUATE_IF("fault_injection_new_file_rotate_event", (error=close_on_error=TRUE), FALSE) || + (error= r.write(&log_file))) + { + DBUG_EXECUTE_IF("fault_injection_new_file_rotate_event", errno=2;); + close_on_error= TRUE; + my_printf_error(ER_ERROR_ON_WRITE, ER(ER_CANT_OPEN_FILE), MYF(ME_FATALERROR), name, errno); + goto end; + } bytes_written += r.data_written; } /* @@ -3900,17 +3937,56 @@ void MYSQL_BIN_LOG::new_file_impl(bool need_lock) */ /* reopen index binlog file, BUG#34582 */ - if (!open_index_file(index_file_name, 0, FALSE)) - open(old_name, log_type, new_name_ptr, - io_cache_type, no_auto_events, max_size, 1, FALSE); + file_to_open= index_file_name; + error= open_index_file(index_file_name, 0, FALSE); + if (!error) + { + /* reopen the binary log file. */ + file_to_open= new_name_ptr; + error= open(old_name, log_type, new_name_ptr, io_cache_type, + no_auto_events, max_size, 1, FALSE); + } + + /* handle reopening errors */ + if (error) + { + my_printf_error(ER_CANT_OPEN_FILE, ER(ER_CANT_OPEN_FILE), + MYF(ME_FATALERROR), file_to_open, error); + close_on_error= TRUE; + } + my_free(old_name,MYF(0)); end: + + if (error && close_on_error /* rotate or reopen failed */) + { + /* + Close whatever was left opened. + + We are keeping the behavior as it exists today, ie, + we disable logging and move on (see: BUG#51014). + + TODO: as part of WL#1790 consider other approaches: + - kill mysql (safety); + - try multiple locations for opening a log file; + - switch server to protected/readonly mode + - ... + */ + close(LOG_CLOSE_INDEX); + sql_print_error("Could not open %s for logging (error %d). " + "Turning logging off for the whole duration " + "of the MySQL server process. To turn it on " + "again: fix the cause, shutdown the MySQL " + "server and restart it.", + new_name_ptr, errno); + } + if (need_lock) pthread_mutex_unlock(&LOCK_log); pthread_mutex_unlock(&LOCK_index); - DBUG_VOID_RETURN; + DBUG_RETURN(error); } @@ -3933,8 +4009,7 @@ bool MYSQL_BIN_LOG::append(Log_event* ev) bytes_written+= ev->data_written; DBUG_PRINT("info",("max_size: %lu",max_size)); if ((uint) my_b_append_tell(&log_file) > max_size) - new_file_without_locking(); - + error= new_file_without_locking(); err: pthread_mutex_unlock(&LOCK_log); signal_update(); // Safe as we don't call close @@ -3963,8 +4038,7 @@ bool MYSQL_BIN_LOG::appendv(const char* buf, uint len,...) } while ((buf=va_arg(args,const char*)) && (len=va_arg(args,uint))); DBUG_PRINT("info",("max_size: %lu",max_size)); if ((uint) my_b_append_tell(&log_file) > max_size) - new_file_without_locking(); - + error= new_file_without_locking(); err: if (!error) signal_update(); @@ -4313,7 +4387,7 @@ MYSQL_BIN_LOG::flush_and_set_pending_rows_event(THD *thd, if (!error) { signal_update(); - rotate_and_purge(RP_LOCK_LOG_IS_ALREADY_LOCKED); + error= rotate_and_purge(RP_LOCK_LOG_IS_ALREADY_LOCKED); } } @@ -4511,7 +4585,9 @@ bool MYSQL_BIN_LOG::write(Log_event *event_info) if (flush_and_sync()) goto err; signal_update(); - rotate_and_purge(RP_LOCK_LOG_IS_ALREADY_LOCKED); + if ((error= rotate_and_purge(RP_LOCK_LOG_IS_ALREADY_LOCKED))) + goto err; + } error=0; @@ -4594,8 +4670,19 @@ bool general_log_write(THD *thd, enum enum_server_command command, return FALSE; } -void MYSQL_BIN_LOG::rotate_and_purge(uint flags) +/** + @note + If rotation fails, for instance the server was unable + to create a new log file, we still try to write an + incident event to the current log. + + @retval + nonzero - error +*/ +int MYSQL_BIN_LOG::rotate_and_purge(uint flags) { + int error= 0; + DBUG_ENTER("MYSQL_BIN_LOG::rotate_and_purge"); #ifdef HAVE_REPLICATION bool check_purge= false; #endif @@ -4604,26 +4691,38 @@ void MYSQL_BIN_LOG::rotate_and_purge(uint flags) if ((flags & RP_FORCE_ROTATE) || (my_b_tell(&log_file) >= (my_off_t) max_size)) { - new_file_without_locking(); + if ((error= new_file_without_locking())) + /** + Be conservative... There are possible lost events (eg, + failing to log the Execute_load_query_log_event + on a LOAD DATA while using a non-transactional + table)! + + We give it a shot and try to write an incident event anyway + to the current log. + */ + if (!write_incident(current_thd, FALSE)) + flush_and_sync(); + #ifdef HAVE_REPLICATION check_purge= true; #endif } if (!(flags & RP_LOCK_LOG_IS_ALREADY_LOCKED)) pthread_mutex_unlock(&LOCK_log); - #ifdef HAVE_REPLICATION /* NOTE: Run purge_logs wo/ holding LOCK_log as it otherwise will deadlock in ndbcluster_binlog_index_purge_file */ - if (check_purge && expire_logs_days) + if (!error && check_purge && expire_logs_days) { time_t purge_time= my_time(0) - expire_logs_days*24*60*60; if (purge_time >= 0) purge_logs_before_date(purge_time); } #endif + DBUG_RETURN(error); } uint MYSQL_BIN_LOG::next_file_id() @@ -4815,6 +4914,10 @@ bool MYSQL_BIN_LOG::write_incident(THD *thd, bool lock) { uint error= 0; DBUG_ENTER("MYSQL_BIN_LOG::write_incident"); + + if (!is_open()) + DBUG_RETURN(error); + LEX_STRING const write_error_msg= { C_STRING_WITH_LEN("error writing to the binary log") }; Incident incident= INCIDENT_LOST_EVENTS; @@ -4828,7 +4931,7 @@ bool MYSQL_BIN_LOG::write_incident(THD *thd, bool lock) if (!error && !(error= flush_and_sync())) { signal_update(); - rotate_and_purge(RP_LOCK_LOG_IS_ALREADY_LOCKED); + error= rotate_and_purge(RP_LOCK_LOG_IS_ALREADY_LOCKED); } pthread_mutex_unlock(&LOCK_log); } @@ -4947,7 +5050,8 @@ bool MYSQL_BIN_LOG::write(THD *thd, IO_CACHE *cache, Log_event *commit_event, pthread_mutex_unlock(&LOCK_prep_xids); } else - rotate_and_purge(RP_LOCK_LOG_IS_ALREADY_LOCKED); + if (rotate_and_purge(RP_LOCK_LOG_IS_ALREADY_LOCKED)) + goto err; } VOID(pthread_mutex_unlock(&LOCK_log)); @@ -5143,80 +5247,26 @@ void sql_perror(const char *message) } -#ifdef __WIN__ +/* + Change the file associated with two output streams. Used to + redirect stdout and stderr to a file. The streams are reopened + only for appending (writing at end of file). +*/ extern "C" my_bool reopen_fstreams(const char *filename, FILE *outstream, FILE *errstream) { - int handle_fd; - int err_fd, out_fd; - HANDLE osfh; - - DBUG_ASSERT(filename && errstream); - - // Services don't have stdout/stderr on Windows, so _fileno returns -1. - err_fd= _fileno(errstream); - if (err_fd < 0) - { - if (!freopen(filename, "a+", errstream)) - return TRUE; - - setbuf(errstream, NULL); - err_fd= _fileno(errstream); - } - - if (outstream) - { - out_fd= _fileno(outstream); - if (out_fd < 0) - { - if (!freopen(filename, "a+", outstream)) - return TRUE; - out_fd= _fileno(outstream); - } - } - - if ((osfh= CreateFile(filename, GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_READ | FILE_SHARE_WRITE | - FILE_SHARE_DELETE, NULL, - OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, - NULL)) == INVALID_HANDLE_VALUE) - return TRUE; - - if ((handle_fd= _open_osfhandle((intptr_t)osfh, - _O_APPEND | _O_TEXT)) == -1) - { - CloseHandle(osfh); - return TRUE; - } - - if (_dup2(handle_fd, err_fd) < 0) - { - CloseHandle(osfh); + if (outstream && !my_freopen(filename, "a", outstream)) return TRUE; - } - if (outstream && _dup2(handle_fd, out_fd) < 0) - { - CloseHandle(osfh); + if (errstream && !my_freopen(filename, "a", errstream)) return TRUE; - } - _close(handle_fd); - return FALSE; -} -#else -extern "C" my_bool reopen_fstreams(const char *filename, - FILE *outstream, FILE *errstream) -{ - if (outstream && !freopen(filename, "a+", outstream)) - return TRUE; - - if (errstream && !freopen(filename, "a+", errstream)) - return TRUE; + /* The error stream must be unbuffered. */ + if (errstream) + setbuf(errstream, NULL); return FALSE; } -#endif /* @@ -5783,7 +5833,7 @@ int TC_LOG_MMAP::sync() cookie points directly to the memory where xid was logged. */ -void TC_LOG_MMAP::unlog(ulong cookie, my_xid xid) +int TC_LOG_MMAP::unlog(ulong cookie, my_xid xid) { PAGE *p=pages+(cookie/tc_log_page_size); my_xid *x=(my_xid *)(data+cookie); @@ -5801,6 +5851,7 @@ void TC_LOG_MMAP::unlog(ulong cookie, my_xid xid) if (p->waiters == 0) // the page is in pool and ready to rock pthread_cond_signal(&COND_pool); // ping ... for overflow() pthread_mutex_unlock(&p->lock); + return 0; } void TC_LOG_MMAP::close() @@ -6042,8 +6093,9 @@ int TC_LOG_BINLOG::log_xid(THD *thd, my_xid xid) DBUG_RETURN(!binlog_end_trans(thd, trx_data, &xle, TRUE)); } -void TC_LOG_BINLOG::unlog(ulong cookie, my_xid xid) +int TC_LOG_BINLOG::unlog(ulong cookie, my_xid xid) { + DBUG_ENTER("TC_LOG_BINLOG::unlog"); pthread_mutex_lock(&LOCK_prep_xids); DBUG_ASSERT(prepared_xids > 0); if (--prepared_xids == 0) { @@ -6051,7 +6103,7 @@ void TC_LOG_BINLOG::unlog(ulong cookie, my_xid xid) pthread_cond_signal(&COND_prep_xids); } pthread_mutex_unlock(&LOCK_prep_xids); - rotate_and_purge(0); // as ::write() did not rotate + DBUG_RETURN(rotate_and_purge(0)); // as ::write() did not rotate } int TC_LOG_BINLOG::recover(IO_CACHE *log, Format_description_log_event *fdle) diff --git a/sql/log.h b/sql/log.h index 8ee94ab5807..df475268cc3 100644 --- a/sql/log.h +++ b/sql/log.h @@ -39,7 +39,7 @@ class TC_LOG virtual int open(const char *opt_name)=0; virtual void close()=0; virtual int log_xid(THD *thd, my_xid xid)=0; - virtual void unlog(ulong cookie, my_xid xid)=0; + virtual int unlog(ulong cookie, my_xid xid)=0; }; class TC_LOG_DUMMY: public TC_LOG // use it to disable the logging @@ -49,7 +49,7 @@ public: int open(const char *opt_name) { return 0; } void close() { } int log_xid(THD *thd, my_xid xid) { return 1; } - void unlog(ulong cookie, my_xid xid) { } + int unlog(ulong cookie, my_xid xid) { return 0; } }; #ifdef HAVE_MMAP @@ -94,7 +94,7 @@ class TC_LOG_MMAP: public TC_LOG int open(const char *opt_name); void close(); int log_xid(THD *thd, my_xid xid); - void unlog(ulong cookie, my_xid xid); + int unlog(ulong cookie, my_xid xid); int recover(); private: @@ -283,8 +283,8 @@ class MYSQL_BIN_LOG: public TC_LOG, private MYSQL_LOG new_file() is locking. new_file_without_locking() does not acquire LOCK_log. */ - void new_file_without_locking(); - void new_file_impl(bool need_lock); + int new_file_without_locking(); + int new_file_impl(bool need_lock); public: MYSQL_LOG::generate_name; @@ -314,7 +314,7 @@ public: int open(const char *opt_name); void close(); int log_xid(THD *thd, my_xid xid); - void unlog(ulong cookie, my_xid xid); + int unlog(ulong cookie, my_xid xid); int recover(IO_CACHE *log, Format_description_log_event *fdle); #if !defined(MYSQL_CLIENT) int flush_and_set_pending_rows_event(THD *thd, Rows_log_event* event); @@ -354,7 +354,7 @@ public: bool open_index_file(const char *index_file_name_arg, const char *log_name, bool need_mutex); /* Use this to start writing a new log file */ - void new_file(); + int new_file(); void reset_gathered_updates(THD *thd); bool write(Log_event* event_info); // binary log write @@ -379,7 +379,7 @@ public: void make_log_name(char* buf, const char* log_ident); bool is_active(const char* log_file_name); int update_log_index(LOG_INFO* linfo, bool need_update_threads); - void rotate_and_purge(uint flags); + int rotate_and_purge(uint flags); bool flush_and_sync(); int purge_logs(const char *to_log, bool included, bool need_mutex, bool need_update_threads, diff --git a/sql/log_event.cc b/sql/log_event.cc index 4a1ccc037a5..95cf853d9ff 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -2893,7 +2893,12 @@ void Query_log_event::print_query_header(IO_CACHE* file, error_code); } - if (!(flags & LOG_EVENT_SUPPRESS_USE_F) && db) + if ((flags & LOG_EVENT_SUPPRESS_USE_F)) + { + if (!is_trans_keyword()) + print_event_info->db[0]= '\0'; + } + else if (db) { different_db= memcmp(print_event_info->db, db, db_len + 1); if (different_db) @@ -3349,7 +3354,8 @@ compare_errors: rli->report(ERROR_LEVEL, 0, "\ Query caused different errors on master and slave. \ -Error on master: '%s' (%d), Error on slave: '%s' (%d). \ +Error on master: message (format)='%s' error code=%d ; \ +Error on slave: actual message='%s', error code=%d. \ Default database: '%s'. Query: '%s'", ER_SAFE(expected_error), expected_error, @@ -7586,6 +7592,14 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli) // Do event specific preparations error= do_before_row_operations(rli); + /* + Bug#56662 Assertion failed: next_insert_id == 0, file handler.cc + Don't allow generation of auto_increment value when processing + rows event by setting 'MODE_NO_AUTO_VALUE_ON_ZERO'. + */ + ulong saved_sql_mode= thd->variables.sql_mode; + thd->variables.sql_mode= MODE_NO_AUTO_VALUE_ON_ZERO; + // row processing loop while (error == 0 && m_curr_row < m_rows_end) @@ -7648,6 +7662,11 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli) thd->transaction.stmt.modified_non_trans_table= TRUE; } // row processing loop + /* + Restore the sql_mode after the rows event is processed. + */ + thd->variables.sql_mode= saved_sql_mode; + DBUG_EXECUTE_IF("STOP_SLAVE_after_first_Rows_event", const_cast<Relay_log_info*>(rli)->abort_slave= 1;); @@ -8722,16 +8741,11 @@ Rows_log_event::write_row(const Relay_log_info *const rli, int UNINIT_VAR(keynum); auto_afree_ptr<char> key(NULL); - /* fill table->record[0] with default values */ - bool abort_on_warnings= (rli->sql_thd->variables.sql_mode & - (MODE_STRICT_TRANS_TABLES | MODE_STRICT_ALL_TABLES)); - if ((error= prepare_record(table, m_width, - table->file->ht->db_type != DB_TYPE_NDBCLUSTER, - abort_on_warnings, m_curr_row == m_rows_buf))) - DBUG_RETURN(error); - + prepare_record(table, m_width, + table->file->ht->db_type != DB_TYPE_NDBCLUSTER); + /* unpack row into table->record[0] */ - if ((error= unpack_current_row(rli, abort_on_warnings))) + if ((error= unpack_current_row(rli))) DBUG_RETURN(error); if (m_curr_row == m_rows_buf) @@ -9582,11 +9596,9 @@ Update_rows_log_event::do_exec_row(const Relay_log_info *const rli) store_record(m_table,record[1]); - bool abort_on_warnings= (rli->sql_thd->variables.sql_mode & - (MODE_STRICT_TRANS_TABLES | MODE_STRICT_ALL_TABLES)); m_curr_row= m_curr_row_end; /* this also updates m_curr_row_end */ - if ((error= unpack_current_row(rli, abort_on_warnings))) + if ((error= unpack_current_row(rli))) return error; /* diff --git a/sql/log_event.h b/sql/log_event.h index 770fb29301b..4ea511f45b5 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -3597,16 +3597,13 @@ protected: int write_row(const Relay_log_info *const, const bool); // Unpack the current row into m_table->record[0] - int unpack_current_row(const Relay_log_info *const rli, - const bool abort_on_warning= TRUE) - { + int unpack_current_row(const Relay_log_info *const rli) + { DBUG_ASSERT(m_table); - bool first_row= (m_curr_row == m_rows_buf); ASSERT_OR_RETURN_ERROR(m_curr_row < m_rows_end, HA_ERR_CORRUPT_EVENT); int const result= ::unpack_row(rli, m_table, m_width, m_curr_row, &m_cols, - &m_curr_row_end, &m_master_reclength, - abort_on_warning, first_row); + &m_curr_row_end, &m_master_reclength); if (m_curr_row_end > m_rows_end) my_error(ER_SLAVE_CORRUPT_EVENT, MYF(0)); ASSERT_OR_RETURN_ERROR(m_curr_row_end <= m_rows_end, HA_ERR_CORRUPT_EVENT); diff --git a/sql/log_event_old.h b/sql/log_event_old.h index 719802a80fb..da5cf403fdb 100644 --- a/sql/log_event_old.h +++ b/sql/log_event_old.h @@ -1,4 +1,4 @@ -/* Copyright 2007 MySQL AB. All rights reserved. +/* Copyright 2007 MySQL AB. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/sql/my_decimal.cc b/sql/my_decimal.cc index 8b15ef4e586..2bbdeed2d87 100644 --- a/sql/my_decimal.cc +++ b/sql/my_decimal.cc @@ -109,6 +109,7 @@ int my_decimal2string(uint mask, const my_decimal *d, result= decimal2string((decimal_t*) d, (char*) str->ptr(), &length, (int)fixed_prec, fixed_dec, filler); + str->set_charset(&my_charset_bin); str->length(length); return check_result(mask, result); } diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 3f836a5ab1f..46e202df071 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -593,17 +593,42 @@ protected: #define MY_CHARSET_BIN_MB_MAXLEN 1 +/* + Flags below are set when we perform + context analysis of the statement and make + subqueries non-const. It prevents subquery + evaluation at context analysis stage. +*/ + +/* + Don't evaluate this subquery during statement prepare even if + it's a constant one. The flag is switched off in the end of + mysqld_stmt_prepare. +*/ +#define CONTEXT_ANALYSIS_ONLY_PREPARE 1 +/* + Special JOIN::prepare mode: changing of query is prohibited. + When creating a view, we need to just check its syntax omitting + any optimizations: afterwards definition of the view will be + reconstructed by means of ::print() methods and written to + to an .frm file. We need this definition to stay untouched. +*/ +#define CONTEXT_ANALYSIS_ONLY_VIEW 2 +/* + Don't evaluate this subquery during derived table prepare even if + it's a constant one. +*/ +#define CONTEXT_ANALYSIS_ONLY_DERIVED 4 + // uncachable cause #define UNCACHEABLE_DEPENDENT 1 #define UNCACHEABLE_RAND 2 #define UNCACHEABLE_SIDEEFFECT 4 /// forcing to save JOIN for explain #define UNCACHEABLE_EXPLAIN 8 -/** Don't evaluate subqueries in prepare even if they're not correlated */ -#define UNCACHEABLE_PREPARE 16 /* For uncorrelated SELECT in an UNION with some correlated SELECTs */ -#define UNCACHEABLE_UNITED 32 -#define UNCACHEABLE_CHECKOPTION 64 +#define UNCACHEABLE_UNITED 16 +#define UNCACHEABLE_CHECKOPTION 32 /* Used to check GROUP BY list in the MODE_ONLY_FULL_GROUP_BY mode */ #define UNDEF_POS (-1) @@ -1102,7 +1127,7 @@ uint cached_table_definitions(void); void kill_mysql(void); void close_connection(THD *thd, uint errcode, bool lock); bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables, - bool *write_to_binlog); + int *write_to_binlog); #ifndef NO_EMBEDDED_ACCESS_CHECKS bool check_access(THD *thd, ulong access, const char *db, ulong *save_priv, bool no_grant, bool no_errors, bool schema_db); diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 828dc27583f..47922210df5 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -1,4 +1,5 @@ /* Copyright (C) 2000-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. + 2010 Oracle and/or its affiliates 2009-2010 Monty Program Ab This program is free software; you can redistribute it and/or modify @@ -67,13 +68,6 @@ #define MAX_MEM_TABLE_SIZE ~(ulonglong) 0 #endif -/* stack traces are only supported on linux intel */ -#if defined(__linux__) && defined(__i386__) && defined(USE_PSTACK) -#define HAVE_STACK_TRACE_ON_SEGV -#include "../pstack/pstack.h" -char pstack_file_name[80]; -#endif /* __linux__ */ - /* We have HAVE_valgrind below as this speeds up the shutdown of MySQL */ #if defined(HAVE_DEC_3_2_THREADS) || defined(SIGNALS_DONT_BREAK_READ) || defined(HAVE_valgrind) && defined(__linux__) @@ -750,9 +744,9 @@ char *opt_logname, *opt_slow_logname; /* Static variables */ static bool kill_in_progress, segfaulted; -#ifdef HAVE_STACK_TRACE_ON_SEGV -static my_bool opt_do_pstack; -#endif /* HAVE_STACK_TRACE_ON_SEGV */ +#ifdef HAVE_STACKTRACE +static my_bool opt_stack_trace; +#endif /* HAVE_STACKTRACE */ static my_bool opt_bootstrap, opt_myisam_log; static int cleanup_done; static ulong opt_specialflag, opt_myisam_block_size; @@ -2654,9 +2648,9 @@ the thread stack. Please read http://dev.mysql.com/doc/mysql/en/linux.html\n\n", #ifdef HAVE_STACKTRACE - if (!(test_flags & TEST_NO_STACKTRACE)) + if (opt_stack_trace) { - fprintf(stderr, "thd: 0x%lx\n",(long) thd); + fprintf(stderr, "Thread pointer: 0x%lx\n", (long) thd); fprintf(stderr, "Attempting backtrace. You can use the following " "information to find out\nwhere mysqld died. If " "you see no messages after this, something went\n" @@ -2684,11 +2678,13 @@ the thread stack. Please read http://dev.mysql.com/doc/mysql/en/linux.html\n\n", kreason= "KILLED_NO_VALUE"; break; } - 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); - fprintf(stderr, "thd->thread_id=%lu\n", (ulong) thd->thread_id); - fprintf(stderr, "thd->killed=%s\n", kreason); + fprintf(stderr, "\nTrying to get some variables.\n" + "Some pointers may be invalid and cause the dump to abort.\n"); + fprintf(stderr, "Query (%p): ", thd->query()); + my_safe_print_str(thd->query(), min(1024, thd->query_length())); + fprintf(stderr, "Connection ID (thread ID): %lu\n", (ulong) thd->thread_id); + fprintf(stderr, "Status: %s\n", kreason); + fputc('\n', stderr); } fprintf(stderr, "\ The manual page at http://dev.mysql.com/doc/mysql/en/crashing.html contains\n\ @@ -2765,7 +2761,7 @@ static void init_signals(void) my_sigset(THR_SERVER_ALARM,print_signal_warning); // Should never be called! - if (!(test_flags & TEST_NO_STACKTRACE) || (test_flags & TEST_CORE_ON_SIGNAL)) + if (opt_stack_trace || (test_flags & TEST_CORE_ON_SIGNAL)) { sa.sa_flags = SA_RESETHAND | SA_NODEFER; sigemptyset(&sa.sa_mask); @@ -2912,14 +2908,6 @@ pthread_handler_t signal_hand(void *arg __attribute__((unused))) if (!opt_bootstrap) create_pid_file(); -#ifdef HAVE_STACK_TRACE_ON_SEGV - if (opt_do_pstack) - { - sprintf(pstack_file_name,"mysqld-%lu-%%d-%%d.backtrace", (ulong)getpid()); - pstack_install_segv_action(pstack_file_name); - } -#endif /* HAVE_STACK_TRACE_ON_SEGV */ - /* signal to start_signal_handler that we are ready This works by waiting for start_signal_handler to free mutex, @@ -2980,7 +2968,7 @@ pthread_handler_t signal_hand(void *arg __attribute__((unused))) case SIGHUP: if (!abort_loop) { - bool not_used; + int not_used; mysql_print_status(); // Print some debug info reload_acl_and_cache((THD*) 0, (REFRESH_LOG | REFRESH_TABLES | REFRESH_FAST | @@ -5898,7 +5886,7 @@ enum options_mysqld OPT_NDB_USE_COPYING_ALTER_TABLE, OPT_SKIP_SAFEMALLOC, OPT_MUTEX_DEADLOCK_DETECTOR, OPT_TEMP_POOL, OPT_TX_ISOLATION, OPT_COMPLETION_TYPE, - OPT_SKIP_STACK_TRACE, OPT_SKIP_SYMLINKS, + OPT_SKIP_SYMLINKS, OPT_MAX_BINLOG_DUMP_EVENTS, OPT_SPORADIC_BINLOG_DUMP_FAIL, OPT_SAFE_USER_CREATE, OPT_SQL_MODE, OPT_HAVE_NAMED_PIPE, @@ -6234,11 +6222,11 @@ struct my_option my_long_options[] = &opt_enable_named_pipe, &opt_enable_named_pipe, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, #endif -#ifdef HAVE_STACK_TRACE_ON_SEGV - {"enable-pstack", OPT_DO_PSTACK, "Print a symbolic stack trace on failure.", - &opt_do_pstack, &opt_do_pstack, 0, GET_BOOL, NO_ARG, 0, 0, - 0, 0, 0, 0}, -#endif /* HAVE_STACK_TRACE_ON_SEGV */ +#ifdef HAVE_STACKTRACE + {"stack-trace", OPT_DO_PSTACK, "Print a symbolic stack trace on failure. " + "On by default. Disable with --disable-stack-trace.", + &opt_stack_trace, &opt_stack_trace, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, +#endif /* HAVE_STACKTRACE */ {"engine-condition-pushdown", OPT_ENGINE_CONDITION_PUSHDOWN, "Push supported query conditions to the storage engine.", @@ -6832,9 +6820,6 @@ thread is in the relay logs.", {"skip-slave-start", OPT_SKIP_SLAVE_START, "If set, slave is not autostarted.", &opt_skip_slave_start, &opt_skip_slave_start, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"skip-stack-trace", OPT_SKIP_STACK_TRACE, - "Don't print a stack trace on failure.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, - 0, 0, 0, 0}, {"skip-symlink", OPT_SKIP_SYMLINKS, "Don't allow symlinking of tables. " "Deprecated option. Use --skip-symbolic-links instead.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, @@ -7077,7 +7062,7 @@ thread is in the relay logs.", "as much as you can afford; 1GB on a 4GB machine that mainly runs MySQL is " "quite common.", &dflt_key_cache_var.param_buff_size, NULL, NULL, (GET_ULL | GET_ASK_ADDR), - REQUIRED_ARG, KEY_CACHE_SIZE, MALLOC_OVERHEAD, SIZE_T_MAX, MALLOC_OVERHEAD, + REQUIRED_ARG, KEY_CACHE_SIZE, 0, SIZE_T_MAX, MALLOC_OVERHEAD, IO_SIZE, 0}, {"key_cache_age_threshold", OPT_KEY_CACHE_AGE_THRESHOLD, "This characterizes the number of hits a hot block has to be untouched " @@ -8833,9 +8818,6 @@ mysqld_get_one_option(int optid, case (int) OPT_WANT_CORE: test_flags |= TEST_CORE_ON_SIGNAL; break; - case (int) OPT_SKIP_STACK_TRACE: - test_flags|=TEST_NO_STACKTRACE; - break; case (int) OPT_SKIP_SYMLINKS: WARN_DEPRECATED(NULL, VER_CELOSIA, "--skip-symlink", "--skip-symbolic-links"); my_use_symdir=0; @@ -9260,7 +9242,8 @@ static int get_options(int *argc,char **argv) if (opt_debugging) { /* Allow break with SIGINT, no core or stack trace */ - test_flags|= TEST_SIGINT | TEST_NO_STACKTRACE; + test_flags|= TEST_SIGINT; + opt_stack_trace= 1; test_flags&= ~TEST_CORE_ON_SIGNAL; } /* Set global MyISAM variables from delay_key_write_options */ diff --git a/sql/net_serv.cc b/sql/net_serv.cc index 9b23367da8a..272b1759151 100644 --- a/sql/net_serv.cc +++ b/sql/net_serv.cc @@ -1,4 +1,4 @@ -/* Copyright (C) 2000 MySQL AB +/* Copyright (c) 2000, 2011, Oracle and/or its affiliates. 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 @@ -168,17 +168,7 @@ my_bool net_realloc(NET *net, size_t length) DBUG_ENTER("net_realloc"); DBUG_PRINT("enter",("length: %lu", (ulong) length)); - /* - When compression is off, net->where_b is always 0. - With compression turned on, net->where_b may indicate - that we still have a piece of the previous logical - packet in the buffer, unprocessed. Take it into account - when checking that max_allowed_packet is not exceeded. - This ensures that the client treats max_allowed_packet - limit identically, regardless of compression being on - or off. - */ - if (length >= (net->max_packet_size + net->where_b)) + if (length >= net->max_packet_size) { DBUG_PRINT("error", ("Packet too large. Max size: %lu", net->max_packet_size)); diff --git a/sql/opt_range.cc b/sql/opt_range.cc index bfa6a49fbdc..2e39f367a70 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -1,4 +1,4 @@ -/* Copyright 2000-2008 MySQL AB, 2008 Sun Microsystems, Inc. +/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. 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 diff --git a/sql/opt_range.h b/sql/opt_range.h index 29df043cb69..1321b3886ee 100644 --- a/sql/opt_range.h +++ b/sql/opt_range.h @@ -271,6 +271,7 @@ public: virtual bool reverse_sorted() = 0; virtual bool unique_key_range() { return false; } + virtual bool clustered_pk_range() { return false; } enum { QS_TYPE_RANGE = 0, @@ -541,6 +542,8 @@ public: THD *thd; int read_keys_and_merge(); + bool clustered_pk_range() { return test(pk_quick_select); } + /* used to get rows collected in Unique */ READ_RECORD read_record; }; diff --git a/sql/opt_sum.cc b/sql/opt_sum.cc index 450ded89653..0c2e41225ba 100644 --- a/sql/opt_sum.cc +++ b/sql/opt_sum.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2000, 2010 Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2000, 2010 Oracle and/or its affiliates. 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 diff --git a/sql/partition_element.h b/sql/partition_element.h index 905bc38165b..a0e74a6830f 100644 --- a/sql/partition_element.h +++ b/sql/partition_element.h @@ -65,6 +65,7 @@ public: char* data_file_name; char* index_file_name; handlerton *engine_type; + LEX_STRING connect_string; enum partition_state part_state; uint16 nodegroup_id; bool has_null_value; @@ -80,6 +81,8 @@ public: nodegroup_id(UNDEF_NODEGROUP), has_null_value(FALSE), signed_flag(FALSE), max_value(FALSE) { + connect_string.str= 0; + connect_string.length= 0; } partition_element(partition_element *part_elem) : part_max_rows(part_elem->part_max_rows), @@ -90,10 +93,13 @@ public: data_file_name(part_elem->data_file_name), index_file_name(part_elem->index_file_name), engine_type(part_elem->engine_type), + connect_string(part_elem->connect_string), part_state(part_elem->part_state), nodegroup_id(part_elem->nodegroup_id), has_null_value(FALSE) { + connect_string.str= 0; + connect_string.length= 0; } ~partition_element() {} }; diff --git a/sql/protocol.cc b/sql/protocol.cc index 70b171fa652..2db81e925a2 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2000, 2010 Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2000, 2010 Oracle and/or its affiliates. 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 diff --git a/sql/records.cc b/sql/records.cc index bdb27322a28..6bb7c7cffa1 100644 --- a/sql/records.cc +++ b/sql/records.cc @@ -195,6 +195,15 @@ bool init_read_record(READ_RECORD *info,THD *thd, TABLE *table, if (select && my_b_inited(&select->file)) tempfile= &select->file; + else if (select && select->quick && select->quick->clustered_pk_range()) + { + /* + In case of QUICK_INDEX_MERGE_SELECT with clustered pk range we have to + use its own access method(i.e QUICK_INDEX_MERGE_SELECT::get_next()) as + sort file does not contain rowids which satisfy clustered pk range. + */ + tempfile= 0; + } else tempfile= table->sort.io_cache; if (tempfile && my_b_inited(tempfile) && diff --git a/sql/rpl_injector.cc b/sql/rpl_injector.cc index 719528a7728..07d9452abe9 100644 --- a/sql/rpl_injector.cc +++ b/sql/rpl_injector.cc @@ -230,8 +230,7 @@ int injector::record_incident(THD *thd, Incident incident) Incident_log_event ev(thd, incident); if (int error= mysql_bin_log.write(&ev)) return error; - mysql_bin_log.rotate_and_purge(RP_FORCE_ROTATE); - return 0; + return mysql_bin_log.rotate_and_purge(RP_FORCE_ROTATE); } int injector::record_incident(THD *thd, Incident incident, LEX_STRING const message) @@ -239,6 +238,5 @@ int injector::record_incident(THD *thd, Incident incident, LEX_STRING const mess Incident_log_event ev(thd, incident, message); if (int error= mysql_bin_log.write(&ev)) return error; - mysql_bin_log.rotate_and_purge(RP_FORCE_ROTATE); - return 0; + return mysql_bin_log.rotate_and_purge(RP_FORCE_ROTATE); } diff --git a/sql/rpl_record.cc b/sql/rpl_record.cc index ecae1efdce4..35e283a886e 100644 --- a/sql/rpl_record.cc +++ b/sql/rpl_record.cc @@ -1,4 +1,4 @@ -/* Copyright 2007 MySQL AB. All rights reserved. +/* Copyright 2007 MySQL AB. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -180,8 +180,7 @@ int unpack_row(Relay_log_info const *rli, TABLE *table, uint const colcnt, uchar const *const row_data, MY_BITMAP const *cols, - uchar const **const row_end, ulong *const master_reclength, - const bool abort_on_warning, const bool first_row) + uchar const **const row_end, ulong *const master_reclength) { DBUG_ENTER("unpack_row"); DBUG_ASSERT(row_data); @@ -251,22 +250,9 @@ unpack_row(Relay_log_info const *rli, } else { - MYSQL_ERROR::enum_warning_level error_type= - MYSQL_ERROR::WARN_LEVEL_NOTE; - if (abort_on_warning && (table->file->has_transactions() || - first_row)) - { - error = HA_ERR_ROWS_EVENT_APPLY; - error_type= MYSQL_ERROR::WARN_LEVEL_ERROR; - } - else - { - f->set_default(); - error_type= MYSQL_ERROR::WARN_LEVEL_WARN; - } - push_warning_printf(current_thd, error_type, - ER_BAD_NULL_ERROR, - ER(ER_BAD_NULL_ERROR), + f->set_default(); + push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_BAD_NULL_ERROR, ER(ER_BAD_NULL_ERROR), f->field_name); } } @@ -350,20 +336,13 @@ unpack_row(Relay_log_info const *rli, @param skip Number of columns for which default/nullable check should be skipped. @param check Specifies if lack of default error needs checking. - @param abort_on_warning - Controls how to react on lack of a field's default. - The parameter mimics the master side one for - @c check_that_all_fields_are_given_values. - + @returns 0 on success or a handler level error code */ -int prepare_record(TABLE *const table, - const uint skip, const bool check, - const bool abort_on_warning, const bool first_row) +int prepare_record(TABLE *const table, const uint skip, const bool check) { DBUG_ENTER("prepare_record"); - int error= 0; restore_record(table, s->default_values); /* @@ -386,28 +365,16 @@ int prepare_record(TABLE *const table, if ((f->flags & NO_DEFAULT_VALUE_FLAG) && (f->real_type() != MYSQL_TYPE_ENUM)) { - - MYSQL_ERROR::enum_warning_level error_type= - MYSQL_ERROR::WARN_LEVEL_NOTE; - if (abort_on_warning && (table->file->has_transactions() || - first_row)) - { - error= HA_ERR_ROWS_EVENT_APPLY; - error_type= MYSQL_ERROR::WARN_LEVEL_ERROR; - } - else - { - f->set_default(); - error_type= MYSQL_ERROR::WARN_LEVEL_WARN; - } - push_warning_printf(current_thd, error_type, + f->set_default(); + push_warning_printf(current_thd, + MYSQL_ERROR::WARN_LEVEL_WARN, ER_NO_DEFAULT_FOR_FIELD, ER(ER_NO_DEFAULT_FOR_FIELD), f->field_name); } } - DBUG_RETURN(error); + DBUG_RETURN(0); } #endif // HAVE_REPLICATION diff --git a/sql/rpl_record.h b/sql/rpl_record.h index 6e8838f82b3..90b3257848c 100644 --- a/sql/rpl_record.h +++ b/sql/rpl_record.h @@ -1,4 +1,4 @@ -/* Copyright 2007 MySQL AB. All rights reserved. +/* Copyright 2007 MySQL AB. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -27,13 +27,10 @@ size_t pack_row(TABLE* table, MY_BITMAP const* cols, int unpack_row(Relay_log_info const *rli, TABLE *table, uint const colcnt, uchar const *const row_data, MY_BITMAP const *cols, - uchar const **const row_end, ulong *const master_reclength, - const bool abort_on_warning= TRUE, const bool first_row= TRUE); + uchar const **const row_end, ulong *const master_reclength); // Fill table's record[0] with default values. -int prepare_record(TABLE *const table, const uint skip, const bool check, - const bool abort_on_warning= TRUE, - const bool first_row= TRUE); +int prepare_record(TABLE *const table, const uint skip, const bool check); #endif #endif diff --git a/sql/rpl_record_old.h b/sql/rpl_record_old.h index bdaedd56741..300c9d9a1a6 100644 --- a/sql/rpl_record_old.h +++ b/sql/rpl_record_old.h @@ -1,4 +1,4 @@ -/* Copyright 2007 MySQL AB. All rights reserved. +/* Copyright 2007 MySQL AB. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/sql/set_var.cc b/sql/set_var.cc index 9917ba9bfe3..5a30bd1c0f4 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -1,4 +1,5 @@ -/* Copyright 2000-2008 MySQL AB, 2008 Sun Microsystems, Inc. +/* Copyright (c) 2002, 2010, Oracle and/or its affiliates. + 2009-2010 Monty Program Ab This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -1487,44 +1488,6 @@ bool throw_bounds_warning(THD *thd, bool fixed, bool unsignd, /** - check an unsigned user-supplied value for a systemvariable against bounds. - - TODO: This is a wrapper function to call clipping from within an update() - function. Calling bounds from within update() is fair game in theory, - but we can only send warnings from in there, not errors, and besides, - it violates our model of separating check from update phase. - To avoid breaking out of the server with an ASSERT() in strict mode, - we pretend we're not in strict mode when we go through here. Bug#43233 - was opened to remind us to replace this kludge with The Right Thing, - which of course is to do the check in the actual check phase, and then - throw an error or warning accordingly. - - @param thd thread handle - @param num the value to limit - @param option_limits the bounds-record, or NULL if none - */ -static void bound_unsigned(THD *thd, ulonglong *num, - const struct my_option *option_limits) -{ - if (option_limits) - { - my_bool fixed = FALSE; - ulonglong unadjusted= *num; - - *num= getopt_ull_limit_value(unadjusted, option_limits, &fixed); - - if (fixed) - { - ulong ssm= thd->variables.sql_mode; - thd->variables.sql_mode&= ~MODE_STRICT_ALL_TABLES; - throw_bounds_warning(thd, fixed, TRUE, option_limits->name, unadjusted); - thd->variables.sql_mode= ssm; - } - } -} - - -/** Get unsigned system-variable. Negative value does not wrap around, but becomes zero. Check user-supplied value for a systemvariable against bounds. @@ -1642,11 +1605,16 @@ void sys_var_long_ptr_global::set_default(THD *thd, enum_var_type type) } +bool sys_var_ulonglong_ptr::check(THD *thd, set_var *var) +{ + return get_unsigned(thd, var, 0, GET_ULL); +} + + bool sys_var_ulonglong_ptr::update(THD *thd, set_var *var) { ulonglong tmp= var->save_result.ulonglong_value; pthread_mutex_lock(&LOCK_global_system_variables); - bound_unsigned(thd, &tmp, option_limits); *value= (ulonglong) tmp; pthread_mutex_unlock(&LOCK_global_system_variables); return 0; @@ -1731,25 +1699,30 @@ uchar *sys_var_thd_ulong::value_ptr(THD *thd, enum_var_type type, } -bool sys_var_thd_ha_rows::update(THD *thd, set_var *var) +bool sys_var_thd_ha_rows::check(THD *thd, set_var *var) { - ulonglong tmp= var->save_result.ulonglong_value; - - /* Don't use bigger value than given with --maximum-variable-name=.. */ - if ((ha_rows) tmp > max_system_variables.*offset) - tmp= max_system_variables.*offset; + return get_unsigned(thd, var, max_system_variables.*offset, +#ifdef BIG_TABLES + GET_ULL +#else + GET_ULONG +#endif + ); +} - bound_unsigned(thd, &tmp, option_limits); +bool sys_var_thd_ha_rows::update(THD *thd, set_var *var) +{ if (var->type == OPT_GLOBAL) { /* Lock is needed to make things safe on 32 bit systems */ pthread_mutex_lock(&LOCK_global_system_variables); - global_system_variables.*offset= (ha_rows) tmp; + global_system_variables.*offset= (ha_rows) + var->save_result.ulonglong_value; pthread_mutex_unlock(&LOCK_global_system_variables); } else - thd->variables.*offset= (ha_rows) tmp; + thd->variables.*offset= (ha_rows) var->save_result.ulonglong_value; return 0; } @@ -2421,6 +2394,12 @@ uchar *sys_var_key_cache_param::value_ptr(THD *thd, enum_var_type type, } +bool sys_var_key_buffer_size::check(THD *thd, set_var *var) +{ + return get_unsigned(thd, var, 0, GET_ULL); +} + + bool sys_var_key_buffer_size::update(THD *thd, set_var *var) { ulonglong tmp= var->save_result.ulonglong_value; @@ -2434,10 +2413,10 @@ bool sys_var_key_buffer_size::update(THD *thd, set_var *var) pthread_mutex_lock(&LOCK_global_system_variables); key_cache= get_key_cache(base_name); - + if (!key_cache) { - /* Key cache didn't exists */ + /* Key cache didn't exist */ if (!tmp) // Tried to delete cache goto end; // Ok, nothing to do if (!(key_cache= create_key_cache(base_name->str, base_name->length))) @@ -2459,9 +2438,8 @@ bool sys_var_key_buffer_size::update(THD *thd, set_var *var) { if (key_cache == dflt_key_cache) { - push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, - ER_WARN_CANT_DROP_DEFAULT_KEYCACHE, - ER(ER_WARN_CANT_DROP_DEFAULT_KEYCACHE)); + error= 1; + my_error(ER_WARN_CANT_DROP_DEFAULT_KEYCACHE, MYF(0)); goto end; // Ignore default key cache } @@ -2487,7 +2465,6 @@ bool sys_var_key_buffer_size::update(THD *thd, set_var *var) goto end; } - bound_unsigned(thd, &tmp, option_limits); key_cache->param_buff_size= (ulonglong) tmp; /* If key cache didn't exist initialize it, else resize it */ @@ -2504,10 +2481,19 @@ bool sys_var_key_buffer_size::update(THD *thd, set_var *var) end: pthread_mutex_unlock(&LOCK_global_system_variables); + + var->save_result.ulonglong_value = SIZE_T_MAX; + return error; } +bool sys_var_key_cache_long::check(THD *thd, set_var *var) +{ + return get_unsigned(thd, var, 0, GET_ULONG); +} + + /** @todo Abort if some other thread is changing the key cache. @@ -2516,7 +2502,6 @@ end: */ bool sys_var_key_cache_long::update(THD *thd, set_var *var) { - ulonglong tmp= var->value->val_int(); LEX_STRING *base_name= &var->base; bool error= 0; @@ -2541,8 +2526,8 @@ bool sys_var_key_cache_long::update(THD *thd, set_var *var) if (key_cache->in_init) goto end; - bound_unsigned(thd, &tmp, option_limits); - *((ulong*) (((char*) key_cache) + offset))= (ulong) tmp; + *((ulong*) (((char*) key_cache) + offset))= (ulong) + var->save_result.ulonglong_value; /* Don't create a new key cache if it didn't exist diff --git a/sql/set_var.h b/sql/set_var.h index 653f9b5155d..95885357b83 100644 --- a/sql/set_var.h +++ b/sql/set_var.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2002-2006 MySQL AB +/* Copyright (c) 2002, 2010, Oracle and/or its affiliates. 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 @@ -198,6 +198,7 @@ public: sys_after_update_func func) :sys_var(name_arg,func), value(value_ptr_arg) { chain_sys_var(chain); } + bool check(THD *thd, set_var *var); bool update(THD *thd, set_var *var); void set_default(THD *thd, enum_var_type type); SHOW_TYPE show_type() { return SHOW_LONGLONG; } @@ -437,6 +438,7 @@ public: sys_after_update_func func) :sys_var_thd(name_arg,func), offset(offset_arg) { chain_sys_var(chain); } + bool check(THD *thd, set_var *var); bool update(THD *thd, set_var *var); void set_default(THD *thd, enum_var_type type); SHOW_TYPE show_type() { return SHOW_HA_ROWS; } @@ -860,6 +862,7 @@ public: :sys_var_key_cache_param(chain, name_arg, offsetof(KEY_CACHE, param_buff_size)) {} + bool check(THD *thd, set_var *var); bool update(THD *thd, set_var *var); SHOW_TYPE show_type() { return SHOW_LONGLONG; } }; @@ -871,6 +874,7 @@ public: sys_var_key_cache_long(sys_var_chain *chain, const char *name_arg, size_t offset_arg) :sys_var_key_cache_param(chain, name_arg, offset_arg) {} + bool check(THD *thd, set_var *var); bool update(THD *thd, set_var *var); SHOW_TYPE show_type() { return SHOW_LONG; } }; diff --git a/sql/share/charsets/cp1251.xml b/sql/share/charsets/cp1251.xml index b80db9f8ec0..06ba8a5a4b9 100644 --- a/sql/share/charsets/cp1251.xml +++ b/sql/share/charsets/cp1251.xml @@ -98,7 +98,7 @@ 0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 005B 005C 005D 005E 005F 0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F 0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 007B 007C 007D 007E 007F - 0402 0403 201A 0453 201E 2026 2020 2021 0000 2030 0409 2039 040A 040C 040B 040F + 0402 0403 201A 0453 201E 2026 2020 2021 20AC 2030 0409 2039 040A 040C 040B 040F 0452 2018 2019 201C 201D 2022 2013 2014 0000 2122 0459 203A 045A 045C 045B 045F 00A0 040E 045E 0408 00A4 0490 00A6 00A7 0401 00A9 0404 00AB 00AC 00AD 00AE 0407 00B0 00B1 0406 0456 0491 00B5 00B6 00B7 0451 2116 0454 00BB 0458 0405 0455 0457 diff --git a/sql/slave.cc b/sql/slave.cc index 0e41d897dd4..0d14234766b 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -3360,8 +3360,7 @@ static int process_io_rotate(Master_info *mi, Rotate_log_event *rev) Rotate the relay log makes binlog format detection easier (at next slave start or mysqlbinlog) */ - rotate_relay_log(mi); /* will take the right mutexes */ - DBUG_RETURN(0); + DBUG_RETURN(rotate_relay_log(mi) /* will take the right mutexes */); } /* @@ -4445,10 +4444,11 @@ err: is void). */ -void rotate_relay_log(Master_info* mi) +int rotate_relay_log(Master_info* mi) { DBUG_ENTER("rotate_relay_log"); Relay_log_info* rli= &mi->rli; + int error= 0; /* We don't lock rli->run_lock. This would lead to deadlocks. */ pthread_mutex_lock(&mi->run_lock); @@ -4464,7 +4464,8 @@ void rotate_relay_log(Master_info* mi) } /* If the relay log is closed, new_file() will do nothing. */ - rli->relay_log.new_file(); + if ((error= rli->relay_log.new_file())) + goto end; /* We harvest now, because otherwise BIN_LOG_HEADER_SIZE will not immediately @@ -4482,7 +4483,7 @@ void rotate_relay_log(Master_info* mi) rli->relay_log.harvest_bytes_written(&rli->log_space_total); end: pthread_mutex_unlock(&mi->run_lock); - DBUG_VOID_RETURN; + DBUG_RETURN(error); } diff --git a/sql/slave.h b/sql/slave.h index 1a1cfcebd9b..1aa5b374e4b 100644 --- a/sql/slave.h +++ b/sql/slave.h @@ -190,7 +190,7 @@ int purge_relay_logs(Relay_log_info* rli, THD *thd, bool just_reset, const char** errmsg); void set_slave_thread_options(THD* thd); void set_slave_thread_default_charset(THD *thd, Relay_log_info const *rli); -void rotate_relay_log(Master_info* mi); +int rotate_relay_log(Master_info* mi); int apply_event_and_update_pos(Log_event* ev, THD* thd, Relay_log_info* rli); pthread_handler_t handle_slave_io(void *arg); diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 2f1aa042c61..dbaeb9467ae 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -1374,7 +1374,7 @@ sp_head::execute(THD *thd) If the DB has changed, the pointer has changed too, but the original thd->db will then have been freed */ - if (cur_db_changed && !thd->killed) + if (cur_db_changed && thd->killed != THD::KILL_CONNECTION) { /* Force switching back to the saved current database, because it may be diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 9b1d0df4251..47d85238cff 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -7560,6 +7560,19 @@ static ulong parse_client_handshake_packet(MPVIO_EXT *mpvio, user_len-= 2; } + /* + Clip username to allowed length in characters (not bytes). This is + mostly for backward compatibility. + */ + { + CHARSET_INFO *cs= system_charset_info; + int err; + + user_len= (uint) cs->cset->well_formed_len(cs, user, user + user_len, + USERNAME_CHAR_LENGTH, &err); + user[user_len]= '\0'; + } + Security_context *sctx= thd->security_ctx; if (thd->make_lex_string(&mpvio->db, db, db_len, 0) == 0) diff --git a/sql/sql_base.cc b/sql/sql_base.cc index b6281777f81..8816e6672f8 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -1,4 +1,4 @@ -/* Copyright 2000-2008 MySQL AB, 2008 Sun Microsystems, Inc. +/* Copyright (c) 2000, 2011, Oracle and/or its affiliates. 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 @@ -3018,6 +3018,12 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root, table->insert_values= 0; table->fulltext_searched= 0; table->file->ha_start_of_new_statement(); + table->file->ft_handler= 0; + /* + Check that there is no reference to a condition from an earlier query + (cf. Bug#58553). + */ + DBUG_ASSERT(table->file->pushed_cond == NULL); table->reginfo.impossible_range= 0; /* Catch wrong handling of the auto_increment_field_not_null. */ DBUG_ASSERT(!table->auto_increment_field_not_null); @@ -6003,6 +6009,8 @@ find_field_in_natural_join(THD *thd, TABLE_LIST *table_ref, const char *name, /* Find field by name in a base table or a view with temp table algorithm. + The caller is expected to check column-level privileges. + SYNOPSIS find_field_in_table() thd thread handler @@ -6111,6 +6119,8 @@ find_field_in_table(THD *thd, TABLE *table, const char *name, uint length, This procedure detects the type of the table reference 'table_list' and calls the corresponding search routine. + The routine checks column-level privieleges for the found field. + RETURN 0 field is not found view_ref_found found value in VIEW (real result is in *ref) @@ -6384,8 +6394,16 @@ find_field_in_tables(THD *thd, Item_ident *item, when table_ref->field_translation != NULL. */ if (table_ref->table && !table_ref->view) + { found= find_field_in_table(thd, table_ref->table, name, length, TRUE, &(item->cached_field_index)); +#ifndef NO_EMBEDDED_ACCESS_CHECKS + /* Check if there are sufficient access rights to the found field. */ + if (found && check_privileges && + check_column_grant_in_table_ref(thd, table_ref, name, length)) + found= WRONG_GRANT; +#endif + } else found= find_field_in_table_ref(thd, table_ref, name, length, item->name, NULL, NULL, ref, check_privileges, diff --git a/sql/sql_binlog.cc b/sql/sql_binlog.cc index da582c37ae9..9713ec1ef5c 100644 --- a/sql/sql_binlog.cc +++ b/sql/sql_binlog.cc @@ -51,6 +51,13 @@ void mysql_client_binlog_statement(THD* thd) size_t decoded_len= base64_needed_decoded_length(coded_len); /* + thd->options will be changed when applying the event. But we don't expect + it be changed permanently after BINLOG statement, so backup it first. + It will be restored at the end of this function. + */ + ulonglong thd_options= thd->options; + + /* Allocation */ @@ -236,6 +243,7 @@ void mysql_client_binlog_statement(THD* thd) my_ok(thd); end: + thd->options= thd_options; rli->clear_tables_to_lock(); my_free(buf, MYF(MY_ALLOW_ZERO_PTR)); DBUG_VOID_RETURN; diff --git a/sql/sql_class.h b/sql/sql_class.h index f496cbe3b74..8a5cc6da741 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1,4 +1,5 @@ -/* Copyright (C) 2000-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc. +/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. + 2009-2011 Monty Program Ab This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -2258,8 +2259,6 @@ public: (variables.sql_mode & MODE_STRICT_ALL_TABLES))); } void set_status_var_init(); - bool is_context_analysis_only() - { return stmt_arena->is_stmt_prepare() || lex->view_prepare_mode; } void reset_n_backup_open_tables_state(Open_tables_state *backup); void restore_backup_open_tables_state(Open_tables_state *backup); void reset_sub_statement_state(Sub_statement_state *backup, uint new_state); diff --git a/sql/sql_db.cc b/sql/sql_db.cc index 7aa48524b20..655268da637 100644 --- a/sql/sql_db.cc +++ b/sql/sql_db.cc @@ -948,9 +948,6 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent) remove_db_from_cache(db); pthread_mutex_unlock(&LOCK_open); - Drop_table_error_handler err_handler(thd->get_internal_handler()); - thd->push_internal_handler(&err_handler); - error= -1; /* We temporarily disable the binary log while dropping the objects @@ -983,8 +980,8 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent) error = 0; reenable_binlog(thd); } - thd->pop_internal_handler(); } + if (!silent && deleted>=0) { const char *query; @@ -1213,16 +1210,34 @@ static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *db, else { strxmov(filePath, org_path, "/", file->name, NullS); - if (my_delete_with_symlink(filePath,MYF(MY_WME))) + /* + We ignore ENOENT error in order to skip files that was deleted + by concurrently running statement like REAPIR TABLE ... + */ + if (my_delete_with_symlink(filePath, MYF(0)) && + my_errno != ENOENT) { - goto err; + my_error(EE_DELETE, MYF(0), filePath, my_errno); + goto err; } } } - if (thd->killed || - (tot_list && mysql_rm_table_part2(thd, tot_list, 1, 0, 1, 1))) + + if (thd->killed) goto err; + if (tot_list) + { + int res= 0; + Drop_table_error_handler err_handler(thd->get_internal_handler()); + + thd->push_internal_handler(&err_handler); + res= mysql_rm_table_part2(thd, tot_list, 1, 0, 1, 1); + thd->pop_internal_handler(); + if (res) + goto err; + } + /* Remove RAID directories */ { List_iterator<String> it(raid_dirs); diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc index 782589f7d0f..3214c756bc7 100644 --- a/sql/sql_derived.cc +++ b/sql/sql_derived.cc @@ -147,10 +147,11 @@ bool mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *orig_table_list) if (!(derived_result= new select_union)) DBUG_RETURN(TRUE); // out of memory + lex->context_analysis_only|= CONTEXT_ANALYSIS_ONLY_DERIVED; // st_select_lex_unit::prepare correctly work for single select if ((res= unit->prepare(thd, derived_result, 0))) goto exit; - + lex->context_analysis_only&= ~CONTEXT_ANALYSIS_ONLY_DERIVED; if ((res= check_duplicate_names(unit->types, 0))) goto exit; diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 6256a0f89d6..aea9796ba56 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -305,7 +305,7 @@ void lex_start(THD *thd) lex->select_lex.group_list.empty(); lex->describe= 0; lex->subqueries= FALSE; - lex->view_prepare_mode= FALSE; + lex->context_analysis_only= 0; lex->derived_tables= 0; lex->lock_option= TL_READ; lex->safe_to_cache_query= 1; diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 0539de0206d..64e2edba0a6 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -1734,14 +1734,8 @@ typedef struct st_lex : public Query_tables_list bool verbose, no_write_to_binlog; bool tx_chain, tx_release; - /* - Special JOIN::prepare mode: changing of query is prohibited. - When creating a view, we need to just check its syntax omitting - any optimizations: afterwards definition of the view will be - reconstructed by means of ::print() methods and written to - to an .frm file. We need this definition to stay untouched. - */ - bool view_prepare_mode; + + uint8 context_analysis_only; bool safe_to_cache_query; bool subqueries, ignore; st_parsing_options parsing_options; @@ -1867,6 +1861,13 @@ typedef struct st_lex : public Query_tables_list delete_dynamic(&plugins); } + inline bool is_ps_or_view_context_analysis() + { + return (context_analysis_only & + (CONTEXT_ANALYSIS_ONLY_PREPARE | + CONTEXT_ANALYSIS_ONLY_VIEW)); + } + inline void uncacheable(uint8 cause) { safe_to_cache_query= 0; diff --git a/sql/sql_load.cc b/sql/sql_load.cc index f440f78a9bc..3483a8226d4 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -314,56 +314,57 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, (void) fn_format(name, ex->file_name, mysql_real_data_home, "", MY_RELATIVE_PATH | MY_UNPACK_FILENAME | MY_RETURN_REAL_PATH); -#if !defined(__WIN__) && ! defined(__NETWARE__) - MY_STAT stat_info; - if (!my_stat(name,&stat_info,MYF(MY_WME))) - DBUG_RETURN(TRUE); - - // if we are not in slave thread, the file must be: - if (!thd->slave_thread && - !((stat_info.st_mode & S_IROTH) == S_IROTH && // readable by others - (stat_info.st_mode & S_IFLNK) != S_IFLNK && // and not a symlink - ((stat_info.st_mode & S_IFREG) == S_IFREG || - (stat_info.st_mode & S_IFIFO) == S_IFIFO))) - { - my_error(ER_TEXTFILE_NOT_READABLE, MYF(0), name); - DBUG_RETURN(TRUE); - } - if ((stat_info.st_mode & S_IFIFO) == S_IFIFO) - is_fifo = 1; -#endif + } - if (thd->slave_thread) - { + if (thd->slave_thread) + { #if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) - if (strncmp(active_mi->rli.slave_patternload_file, name, - active_mi->rli.slave_patternload_file_size)) - { - /* - LOAD DATA INFILE in the slave SQL Thread can only read from - --slave-load-tmpdir". This should never happen. Please, report a bug. - */ - - sql_print_error("LOAD DATA INFILE in the slave SQL Thread can only read from --slave-load-tmpdir. " \ - "Please, report a bug."); - my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--slave-load-tmpdir"); - DBUG_RETURN(TRUE); - } -#else + if (strncmp(active_mi->rli.slave_patternload_file, name, + active_mi->rli.slave_patternload_file_size)) + { /* - This is impossible and should never happen. + LOAD DATA INFILE in the slave SQL Thread can only read from + --slave-load-tmpdir". This should never happen. Please, report a bug. */ - DBUG_ASSERT(FALSE); -#endif - } - else if (!is_secure_file_path(name)) - { - /* Read only allowed from within dir specified by secure_file_priv */ - my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--secure-file-priv"); + + sql_print_error("LOAD DATA INFILE in the slave SQL Thread can only read from --slave-load-tmpdir. " \ + "Please, report a bug."); + my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--slave-load-tmpdir"); DBUG_RETURN(TRUE); } +#else + /* + This is impossible and should never happen. + */ + DBUG_ASSERT(FALSE); +#endif + } + else if (!is_secure_file_path(name)) + { + /* Read only allowed from within dir specified by secure_file_priv */ + my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--secure-file-priv"); + DBUG_RETURN(TRUE); + } +#if !defined(__WIN__) && ! defined(__NETWARE__) + MY_STAT stat_info; + if (!my_stat(name,&stat_info,MYF(MY_WME))) + DBUG_RETURN(TRUE); + + // if we are not in slave thread, the file must be: + if (!thd->slave_thread && + !((stat_info.st_mode & S_IROTH) == S_IROTH && // readable by others + (stat_info.st_mode & S_IFLNK) != S_IFLNK && // and not a symlink + ((stat_info.st_mode & S_IFREG) == S_IFREG || + (stat_info.st_mode & S_IFIFO) == S_IFIFO))) + { + my_error(ER_TEXTFILE_NOT_READABLE, MYF(0), name); + DBUG_RETURN(TRUE); } + if ((stat_info.st_mode & S_IFIFO) == S_IFIFO) + is_fifo = 1; +#endif + if ((file=my_open(name,O_RDONLY,MYF(MY_WME))) < 0) DBUG_RETURN(TRUE); } @@ -567,6 +568,13 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, transactional_table, errcode); } + + /* + Flushing the IO CACHE while writing the execute load query log event + may result in error (for instance, because the max_binlog_size has been + reached, and rotation of the binary log failed). + */ + error= error || mysql_bin_log.get_log_file()->error; } if (error) goto err; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 50d45fdfa69..a215644bce3 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1,4 +1,4 @@ -/* Copyright 2000-2008 MySQL AB, 2008 Sun Microsystems, Inc. +/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. 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 @@ -1430,7 +1430,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, #endif case COM_REFRESH: { - bool not_used; + int not_used; status_var_increment(thd->status_var.com_stat[SQLCOM_FLUSH]); ulong options= (ulong) (uchar) packet[0]; if (check_global_access(thd,RELOAD_ACL)) @@ -3199,7 +3199,11 @@ end_with_restore_list: { Incident_log_event ev(thd, incident); (void) mysql_bin_log.write(&ev); /* error is ignored */ - mysql_bin_log.rotate_and_purge(RP_FORCE_ROTATE); + if (mysql_bin_log.rotate_and_purge(RP_FORCE_ROTATE)) + { + res= 1; + break; + } } DBUG_PRINT("debug", ("Just after generate_incident()")); } @@ -4028,7 +4032,7 @@ end_with_restore_list: lex->no_write_to_binlog= 1; case SQLCOM_FLUSH: { - bool write_to_binlog; + int write_to_binlog; if (check_global_access(thd,RELOAD_ACL)) goto error; @@ -4045,12 +4049,22 @@ end_with_restore_list: /* Presumably, RESET and binlog writing doesn't require synchronization */ - if (!lex->no_write_to_binlog && write_to_binlog) + + if (write_to_binlog > 0) // we should write + { + if (!lex->no_write_to_binlog) + res= write_bin_log(thd, FALSE, thd->query(), thd->query_length()); + } else if (write_to_binlog < 0) { - if ((res= write_bin_log(thd, FALSE, thd->query(), thd->query_length()))) - break; - } - my_ok(thd); + /* + We should not write, but rather report error because + reload_acl_and_cache binlog interactions failed + */ + res= 1; + } + + if (!res) + my_ok(thd); } break; @@ -5925,13 +5939,6 @@ mysql_new_select(LEX *lex, bool move_down) DBUG_RETURN(1); } select_lex->nest_level= lex->nest_level; - /* - Don't evaluate this subquery during statement prepare even if - it's a constant one. The flag is switched off in the end of - mysqld_stmt_prepare. - */ - if (thd->stmt_arena->is_stmt_prepare()) - select_lex->uncacheable|= UNCACHEABLE_PREPARE; if (move_down) { SELECT_LEX_UNIT *unit; @@ -6925,7 +6932,10 @@ void add_join_natural(TABLE_LIST *a, TABLE_LIST *b, List<String> *using_fields, @param thd Thread handler (can be NULL!) @param options What should be reset/reloaded (tables, privileges, slave...) @param tables Tables to flush (if any) - @param write_to_binlog True if we can write to the binlog. + @param write_to_binlog < 0 if there was an error while interacting with the binary log inside + reload_acl_and_cache, + 0 if we should not write to the binary log, + > 0 if we can write to the binlog. @note Depending on 'options', it may be very bad to write the query to the binlog (e.g. FLUSH SLAVE); this is a @@ -6939,11 +6949,11 @@ void add_join_natural(TABLE_LIST *a, TABLE_LIST *b, List<String> *using_fields, */ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables, - bool *write_to_binlog) + int *write_to_binlog) { bool result=0; select_errors=0; /* Write if more errors */ - bool tmp_write_to_binlog= 1; + int tmp_write_to_binlog= *write_to_binlog= 1; DBUG_ASSERT(!thd || !thd->in_sub_stmt); @@ -7006,12 +7016,16 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables, tmp_write_to_binlog= 0; if( mysql_bin_log.is_open() ) { - mysql_bin_log.rotate_and_purge(RP_FORCE_ROTATE); + if (mysql_bin_log.rotate_and_purge(RP_FORCE_ROTATE)) + *write_to_binlog= -1; } #ifdef HAVE_REPLICATION + int rotate_error= 0; pthread_mutex_lock(&LOCK_active_mi); - rotate_relay_log(active_mi); + rotate_error= rotate_relay_log(active_mi); pthread_mutex_unlock(&LOCK_active_mi); + if (rotate_error) + *write_to_binlog= -1; #endif /* flush slow and general logs */ @@ -7158,7 +7172,8 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables, } pthread_mutex_unlock(&LOCK_global_user_client_stats); } - *write_to_binlog= tmp_write_to_binlog; + if (*write_to_binlog != -1) + *write_to_binlog= tmp_write_to_binlog; /* If the query was killed then this function must fail. */ diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 851bd6b875b..1c78f6a3613 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -1015,12 +1015,13 @@ static bool fix_fields_part_func(THD *thd, Item* func_expr, TABLE *table, } /* - We don't allow creating partitions with timezone-dependent expressions as - a (sub)partitioning function, but we want to allow such expressions when - opening existing tables for easier maintenance. This exception should be - deprecated at some point in future so that we always throw an error. + We don't allow creating partitions with expressions with non matching + arguments as a (sub)partitioning function, + but we want to allow such expressions when opening existing tables for + easier maintenance. This exception should be deprecated at some point + in future so that we always throw an error. */ - if (func_expr->walk(&Item::is_timezone_dependent_processor, + if (func_expr->walk(&Item::check_valid_arguments_processor, 0, NULL)) { if (is_create_table_ind) @@ -1983,6 +1984,9 @@ static int add_partition_options(File fptr, partition_element *p_elem) } if (p_elem->part_comment) err+= add_keyword_string(fptr, "COMMENT", TRUE, p_elem->part_comment); + if (p_elem->connect_string.length) + err+= add_keyword_string(fptr, "CONNECTION", TRUE, + p_elem->connect_string.str); return err + add_engine(fptr,p_elem->engine_type); } @@ -5936,6 +5940,12 @@ static void alter_partition_lock_handling(ALTER_PARTITION_PARAM_TYPE *lpt) if (lpt->thd->locked_tables) { /* + Close the table if open, to remove/destroy the already altered + table->part_info object, so that it is not reused. + */ + if (lpt->table->db_stat) + abort_and_upgrade_lock_and_close_table(lpt); + /* When we have the table locked, it is necessary to reopen the table since all table objects were closed and removed as part of the ALTER TABLE of partitioning structure. @@ -6437,7 +6447,20 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, table, table_list, FALSE, NULL, written_bin_log)); err: - close_thread_tables(thd); + if (thd->locked_tables) + { + /* + table->part_info was altered in prep_alter_part_table and must be + destroyed and recreated, since otherwise it will be reused, since + we are under LOCK TABLE. + */ + alter_partition_lock_handling(lpt); + } + else + { + /* Force the table to be closed to avoid reuse of the table->part_info */ + close_thread_tables(thd); + } DBUG_RETURN(TRUE); } #endif @@ -6748,8 +6771,8 @@ int get_part_iter_for_interval_via_mapping(partition_info *part_info, { DBUG_ASSERT(!is_subpart); Field *field= part_info->part_field_array[0]; - uint32 max_endpoint_val; - get_endpoint_func get_endpoint; + uint32 UNINIT_VAR(max_endpoint_val); + get_endpoint_func UNINIT_VAR(get_endpoint); bool can_match_multiple_values; /* is not '=' */ uint field_len= field->pack_length_in_rec(); part_iter->ret_null_part= part_iter->ret_null_part_orig= FALSE; diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc index 58cc7dc93a9..391a574b35d 100644 --- a/sql/sql_plugin.cc +++ b/sql/sql_plugin.cc @@ -273,6 +273,26 @@ static void report_error(int where_to, uint error, ...) } } +/** + Check if the provided path is valid in the sense that it does cause + a relative reference outside the directory. + + @note Currently, this function only check if there are any + characters in FN_DIRSEP in the string, but it might change in the + future. + + @code + check_valid_path("../foo.so") -> true + check_valid_path("foo.so") -> false + @endcode + */ +bool check_valid_path(const char *path, size_t len) +{ + size_t prefix= my_strcspn(files_charset_info, path, path + len, FN_DIRSEP); + return prefix < len; +} + + /**************************************************************************** Value type thunks, allows the C world to play in the C++ world ****************************************************************************/ @@ -615,13 +635,15 @@ static st_plugin_dl *plugin_dl_add(const LEX_STRING *dl, int report) struct st_plugin_dl *tmp, plugin_dl; void *sym; DBUG_ENTER("plugin_dl_add"); + DBUG_PRINT("enter", ("dl->str: '%s', dl->length: %d", + dl->str, (int) dl->length)); plugin_dir_len= strlen(opt_plugin_dir); /* Ensure that the dll doesn't have a path. This is done to ensure that only approved libraries from the plugin directory are used (to make this even remotely secure). */ - if (my_strchr(files_charset_info, dl->str, dl->str + dl->length, FN_LIBCHAR) || + if (check_valid_path(dl->str, dl->length) || check_string_char_length((LEX_STRING *) dl, "", NAME_CHAR_LEN, system_charset_info, 1) || plugin_dir_len + dl->length + 1 >= FN_REFLEN) diff --git a/sql/sql_plugin.h b/sql/sql_plugin.h index 149b7e0cbb1..9919e41b0ed 100644 --- a/sql/sql_plugin.h +++ b/sql/sql_plugin.h @@ -130,6 +130,7 @@ extern bool mysql_uninstall_plugin(THD *thd, const LEX_STRING *name); extern bool plugin_register_builtin(struct st_mysql_plugin *plugin); extern void plugin_thdvar_init(THD *thd); extern void plugin_thdvar_cleanup(THD *thd); +extern bool check_valid_path(const char *path, size_t length); typedef my_bool (plugin_foreach_func)(THD *thd, plugin_ref plugin, diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 98434439998..c7109982f93 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -1,4 +1,4 @@ -/* Copyright (C) 1995-2002 MySQL AB +/* Copyright (c) 2002, 2010, Oracle and/or its affiliates. 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 @@ -1692,7 +1692,7 @@ static bool mysql_test_create_view(Prepared_statement *stmt) if (open_normal_and_derived_tables(thd, tables, 0)) goto err; - lex->view_prepare_mode= 1; + lex->context_analysis_only|= CONTEXT_ANALYSIS_ONLY_VIEW; res= select_like_stmt_test(stmt, 0, 0); err: @@ -2238,19 +2238,6 @@ end: } -/** Init PS/SP specific parse tree members. */ - -static void init_stmt_after_parse(LEX *lex) -{ - SELECT_LEX *sl= lex->all_selects_list; - /* - Switch off a temporary flag that prevents evaluation of - subqueries in statement prepare. - */ - for (; sl; sl= sl->next_select_in_list()) - sl->uncacheable&= ~UNCACHEABLE_PREPARE; -} - /** SQLCOM_PREPARE implementation. @@ -3084,6 +3071,7 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len) parser_state.m_lip.stmt_prepare_mode= TRUE; lex_start(thd); + lex->context_analysis_only|= CONTEXT_ANALYSIS_ONLY_PREPARE; error= parse_sql(thd, & parser_state, NULL) || thd->is_error() || @@ -3136,7 +3124,7 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len) if (error == 0) { setup_set_params(); - init_stmt_after_parse(lex); + lex->context_analysis_only&= ~CONTEXT_ANALYSIS_ONLY_PREPARE; state= Query_arena::PREPARED; flags&= ~ (uint) IS_IN_USE; /* diff --git a/sql/sql_profile.cc b/sql/sql_profile.cc index 9c0dec336b8..7bfb127815d 100644 --- a/sql/sql_profile.cc +++ b/sql/sql_profile.cc @@ -1,4 +1,4 @@ -/* Copyright (c) 2007, 2010 Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2007, 2010 Oracle and/or its affiliates. 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 diff --git a/sql/sql_rename.cc b/sql/sql_rename.cc index e85e730db5b..df7054c94d0 100644 --- a/sql/sql_rename.cc +++ b/sql/sql_rename.cc @@ -99,7 +99,7 @@ bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list, bool silent) */ my_error(ER_CANT_RENAME_LOG_TABLE, MYF(0), ren_table->table_name, ren_table->table_name); - DBUG_RETURN(1); + goto err; } } else @@ -112,7 +112,7 @@ bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list, bool silent) */ my_error(ER_CANT_RENAME_LOG_TABLE, MYF(0), ren_table->table_name, ren_table->table_name); - DBUG_RETURN(1); + goto err; } else { @@ -130,7 +130,7 @@ bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list, bool silent) else my_error(ER_CANT_RENAME_LOG_TABLE, MYF(0), rename_log_table[1], rename_log_table[1]); - DBUG_RETURN(1); + goto err; } } diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 771c3c2e371..052c01725de 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1,5 +1,5 @@ -/* Copyright (c) 2000, 2010 Oracle and/or its affiliates. All rights reserved. - Copyright (c) 2009-2010 Monty Program Ab +/* Copyright (c) 2000, 2010 Oracle and/or its affiliates. + 2009-2011 Monty Program Ab This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -548,7 +548,8 @@ JOIN::prepare(Item ***rref_pointer_array, thd->lex->allow_sum_func= save_allow_sum_func; } - if (!thd->lex->view_prepare_mode && !(select_options & SELECT_DESCRIBE)) + if (!(thd->lex->context_analysis_only & CONTEXT_ANALYSIS_ONLY_VIEW) && + !(select_options & SELECT_DESCRIBE)) { Item_subselect *subselect; /* Is it subselect? */ @@ -4111,10 +4112,13 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab, continue; } -#ifdef HAVE_valgrind - /* Valgrind complains about overlapped memcpy when save_pos==use. */ + /* + Old gcc used a memcpy(), which is undefined if save_pos==use: + http://gcc.gnu.org/bugzilla/show_bug.cgi?id=19410 + http://gcc.gnu.org/bugzilla/show_bug.cgi?id=39480 + This also disables a valgrind warning, so better to have the test. + */ if (save_pos != use) -#endif *save_pos= *use; prev=use; found_eq_constant= !use->used_tables; @@ -6444,7 +6448,6 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond) tab->select_cond=sel->cond=tmp; /* Push condition to storage engine if this is enabled and the condition is not guarded */ - tab->table->file->pushed_cond= NULL; if (thd->variables.engine_condition_pushdown) { COND *push_cond= @@ -9916,7 +9919,12 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type, convert_blob_length); if (orig_type == Item::REF_ITEM && orig_modify) ((Item_ref*)orig_item)->set_result_field(result); - if (field->field->eq_def(result)) + /* + Fields that are used as arguments to the DEFAULT() function already have + their data pointers set to the default value during name resolution. See + Item_default_value::fix_fields. + */ + if (orig_type != Item::DEFAULT_VALUE_ITEM && field->field->eq_def(result)) *default_field= field->field; return result; } @@ -11157,6 +11165,7 @@ create_internal_tmp_table_from_heap2(THD *thd, TABLE *table, const char *save_proc_info; int write_err; DBUG_ENTER("create_internal_tmp_table_from_heap2"); + LINT_INIT(write_err); if (table->s->db_type() != heap_hton || error != HA_ERR_RECORD_FILE_FULL) @@ -11969,7 +11978,8 @@ flush_cached_records(JOIN *join,JOIN_TAB *join_tab,bool skip_last) return error < 0 ? NESTED_LOOP_NO_MORE_ROWS: NESTED_LOOP_ERROR; } - for (JOIN_TAB *tmp=join->join_tab; tmp != join_tab ; tmp++) + for (JOIN_TAB *tmp= join_tab-1; + tmp >= join->join_tab && !tmp->cache.buff; tmp--) { tmp->status=tmp->table->status; tmp->table->status=0; @@ -12029,7 +12039,8 @@ flush_cached_records(JOIN *join,JOIN_TAB *join_tab,bool skip_last) reset_cache_write(&join_tab->cache); if (error > 0) // Fatal error return NESTED_LOOP_ERROR; /* purecov: inspected */ - for (JOIN_TAB *tmp2=join->join_tab; tmp2 != join_tab ; tmp2++) + for (JOIN_TAB *tmp2= join_tab-1; + tmp2 >= join->join_tab && !tmp2->cache.buff; tmp2--) tmp2->table->status=tmp2->status; return NESTED_LOOP_OK; } @@ -15568,6 +15579,8 @@ calc_group_buffer(JOIN *join,ORDER *group) { key_length+= 8; } + else if (type == MYSQL_TYPE_BLOB) + key_length+= MAX_BLOB_WIDTH; // Can't be used as a key else { /* diff --git a/sql/sql_select.h b/sql/sql_select.h index 2a9af48f1cd..ea06b26a229 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2000-2006 MySQL AB +/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. 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 diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 4d717caaaea..fa84be7bc17 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -1,4 +1,5 @@ -/* Copyright 2000, 2010 Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2000, 2011, Oracle and/or its affiliates. + 2009-2011 Monty Program Ab This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -565,12 +566,6 @@ find_files(THD *thd, List<LEX_STRING> *files, const char *db, else if (wild_compare(uname, wild, 0)) continue; } - if (!(file_name= - thd->make_lex_string(file_name, uname, file_name_len, TRUE))) - { - my_dirend(dirp); - DBUG_RETURN(FIND_FILES_OOM); - } } else { @@ -755,7 +750,7 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list) table_list->table_name)); /* We want to preserve the tree for views. */ - thd->lex->view_prepare_mode= TRUE; + thd->lex->context_analysis_only|= CONTEXT_ANALYSIS_ONLY_VIEW; { Show_create_error_handler view_error_suppressor(thd, table_list); @@ -3715,7 +3710,7 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) uint derived_tables= lex->derived_tables; int error= 1; Open_tables_state open_tables_state_backup; - bool save_view_prepare_mode= lex->view_prepare_mode; + uint8 save_context_analysis_only= lex->context_analysis_only; Query_tables_list query_tables_list_backup; #ifndef NO_EMBEDDED_ACCESS_CHECKS Security_context *sctx= thd->security_ctx; @@ -3723,7 +3718,7 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) uint table_open_method; DBUG_ENTER("get_all_tables"); - lex->view_prepare_mode= TRUE; + lex->context_analysis_only|= CONTEXT_ANALYSIS_ONLY_VIEW; lex->reset_n_backup_query_tables_list(&query_tables_list_backup); /* @@ -3940,7 +3935,7 @@ err: lex->restore_backup_query_tables_list(&query_tables_list_backup); lex->derived_tables= derived_tables; lex->all_selects_list= old_all_select_lex; - lex->view_prepare_mode= save_view_prepare_mode; + lex->context_analysis_only= save_context_analysis_only; lex->sql_command= save_sql_command; DBUG_RETURN(error); } @@ -4036,28 +4031,28 @@ static int get_schema_tables_record(THD *thd, TABLE_LIST *tables, { const char *tmp_buff; MYSQL_TIME time; + int info_error= 0; CHARSET_INFO *cs= system_charset_info; DBUG_ENTER("get_schema_tables_record"); restore_record(table, s->default_values); table->field[1]->store(db_name->str, db_name->length, cs); table->field[2]->store(table_name->str, table_name->length, cs); + if (res) { - /* - there was errors during opening tables - */ - const char *error= thd->is_error() ? thd->main_da.message() : ""; + /* There was a table open error, so set the table type and return */ if (tables->view) table->field[3]->store(STRING_WITH_LEN("VIEW"), cs); else if (tables->schema_table) table->field[3]->store(STRING_WITH_LEN("SYSTEM VIEW"), cs); else table->field[3]->store(STRING_WITH_LEN("BASE TABLE"), cs); - table->field[20]->store(error, strlen(error), cs); - thd->clear_error(); + + goto err; } - else if (tables->view) + + if (tables->view) { table->field[3]->store(STRING_WITH_LEN("VIEW"), cs); table->field[20]->store(STRING_WITH_LEN("VIEW"), cs); @@ -4158,9 +4153,14 @@ static int get_schema_tables_record(THD *thd, TABLE_LIST *tables, if (share->comment.str) table->field[20]->store(share->comment.str, share->comment.length, cs); - if(file) + if (file) { - file->info(HA_STATUS_VARIABLE | HA_STATUS_TIME | HA_STATUS_AUTO); + /* If info() fails, then there's nothing else to do */ + if ((info_error= file->info(HA_STATUS_VARIABLE | + HA_STATUS_TIME | + HA_STATUS_AUTO)) != 0) + goto err; + enum row_type row_type = file->get_row_type(); switch (row_type) { case ROW_TYPE_NOT_USED: @@ -4238,6 +4238,26 @@ static int get_schema_tables_record(THD *thd, TABLE_LIST *tables, } } } + +err: + if (res || info_error) + { + /* + If an error was encountered, push a warning, set the TABLE COMMENT + column with the error text, and clear the error so that the operation + can continue. + */ + const char *error= thd->is_error() ? thd->main_da.message() : ""; + table->field[20]->store(error, strlen(error), cs); + + if (thd->is_error()) + { + push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + thd->main_da.sql_errno(), thd->main_da.message()); + thd->clear_error(); + } + } + DBUG_RETURN(schema_table_store_record(thd, table)); } @@ -5036,9 +5056,6 @@ static int get_schema_constraints_record(THD *thd, TABLE_LIST *tables, TABLE *show_table= tables->table; KEY *key_info=show_table->key_info; uint primary_key= show_table->s->primary_key; - show_table->file->info(HA_STATUS_VARIABLE | - HA_STATUS_NO_LOCK | - HA_STATUS_TIME); for (uint i=0 ; i < show_table->s->keys ; i++, key_info++) { if (i != primary_key && !(key_info->flags & HA_NOSAME)) @@ -5219,9 +5236,6 @@ static int get_schema_key_column_usage_record(THD *thd, TABLE *show_table= tables->table; KEY *key_info=show_table->key_info; uint primary_key= show_table->s->primary_key; - show_table->file->info(HA_STATUS_VARIABLE | - HA_STATUS_NO_LOCK | - HA_STATUS_TIME); for (uint i=0 ; i < show_table->s->keys ; i++, key_info++) { if (i != primary_key && !(key_info->flags & HA_NOSAME)) @@ -5949,9 +5963,6 @@ get_referential_constraints_record(THD *thd, TABLE_LIST *tables, { List<FOREIGN_KEY_INFO> f_key_list; TABLE *show_table= tables->table; - show_table->file->info(HA_STATUS_VARIABLE | - HA_STATUS_NO_LOCK | - HA_STATUS_TIME); show_table->file->get_foreign_key_list(thd, &f_key_list); FOREIGN_KEY_INFO *f_key_info; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 0f1928e37dc..98de5e95da9 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -6958,7 +6958,6 @@ view_err: table->alias.c_ptr()); } - VOID(pthread_mutex_lock(&LOCK_open)); /* Unlike to the above case close_cached_table() below will remove ALL instances of TABLE from table cache (it will also remove table lock @@ -6976,15 +6975,10 @@ view_err: Workaround InnoDB ending the transaction when the table instance is unlocked/closed (close_cached_table below), otherwise the trx state will differ between the server and storage engine layers. - - We have to unlock LOCK_open here as otherwise we can get deadlock - in wait_if_global_readlock(). This is still safe as we have a - name lock on the table object. */ - VOID(pthread_mutex_unlock(&LOCK_open)); ha_autocommit_or_rollback(thd, 0); - VOID(pthread_mutex_lock(&LOCK_open)); + VOID(pthread_mutex_lock(&LOCK_open)); /* Then do a 'simple' rename of the table. First we need to close all instances of 'source' table. @@ -7017,6 +7011,8 @@ view_err: } } } + else + VOID(pthread_mutex_lock(&LOCK_open)); if (error == HA_ERR_WRONG_COMMAND) { diff --git a/sql/sql_udf.cc b/sql/sql_udf.cc index 754a6f18536..76ccca0a894 100644 --- a/sql/sql_udf.cc +++ b/sql/sql_udf.cc @@ -179,10 +179,7 @@ void udf_init() On windows we must check both FN_LIBCHAR and '/'. */ - if (my_strchr(files_charset_info, dl_name, - dl_name + strlen(dl_name), FN_LIBCHAR) || - IF_WIN(my_strchr(files_charset_info, dl_name, - dl_name + strlen(dl_name), '/'), 0) || + if (check_valid_path(dl_name, strlen(dl_name)) || check_string_char_length(&name, "", NAME_CHAR_LEN, system_charset_info, 1)) { @@ -422,13 +419,8 @@ int mysql_create_function(THD *thd,udf_func *udf) Ensure that the .dll doesn't have a path This is done to ensure that only approved dll from the system directories are used (to make this even remotely secure). - - On windows we must check both FN_LIBCHAR and '/'. */ - if (my_strchr(files_charset_info, udf->dl, - udf->dl + strlen(udf->dl), FN_LIBCHAR) || - IF_WIN(my_strchr(files_charset_info, udf->dl, - udf->dl + strlen(udf->dl), '/'), 0)) + if (check_valid_path(udf->dl, strlen(udf->dl))) { my_message(ER_UDF_NO_PATHS, ER(ER_UDF_NO_PATHS), MYF(0)); DBUG_RETURN(1); diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 66a9f83387a..41ff4e998e2 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -1,4 +1,4 @@ -/* Copyright 2000-2008 MySQL AB, 2008 Sun Microsystems, Inc. +/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. 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 diff --git a/sql/sql_view.cc b/sql/sql_view.cc index 8b8b7f5c90e..0f7b7637744 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -1,4 +1,4 @@ -/* Copyright (C) 2004 MySQL AB +/* Copyright (c) 2004, 2011, Oracle and/or its affiliates. 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 @@ -545,7 +545,7 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views, } /* prepare select to resolve all fields */ - lex->view_prepare_mode= 1; + lex->context_analysis_only|= CONTEXT_ANALYSIS_ONLY_VIEW; if (unit->prepare(thd, 0, 0)) { /* @@ -1257,6 +1257,7 @@ bool mysql_make_view(THD *thd, File_parser *parser, TABLE_LIST *table, TABLE_LIST *view_tables= lex->query_tables; TABLE_LIST *view_tables_tail= 0; TABLE_LIST *tbl; + Security_context *security_ctx; /* Check rights to run commands (EXPLAIN SELECT & SHOW CREATE) which show @@ -1398,26 +1399,39 @@ bool mysql_make_view(THD *thd, File_parser *parser, TABLE_LIST *table, if (table->view_suid) { /* - Prepare a security context to check underlying objects of the view + For suid views prepare a security context for checking underlying + objects of the view. */ if (!(table->view_sctx= (Security_context *) thd->stmt_arena->alloc(sizeof(Security_context)))) goto err; - /* Assign the context to the tables referenced in the view */ - if (view_tables) - { - DBUG_ASSERT(view_tables_tail); - for (tbl= view_tables; tbl != view_tables_tail->next_global; - tbl= tbl->next_global) - tbl->security_ctx= table->view_sctx; - } - /* assign security context to SELECT name resolution contexts of view */ - for(SELECT_LEX *sl= lex->all_selects_list; - sl; - sl= sl->next_select_in_list()) - sl->context.security_ctx= table->view_sctx; + security_ctx= table->view_sctx; + } + else + { + /* + For non-suid views inherit security context from view's table list. + This allows properly handle situation when non-suid view is used + from within suid view. + */ + security_ctx= table->security_ctx; + } + + /* Assign the context to the tables referenced in the view */ + if (view_tables) + { + DBUG_ASSERT(view_tables_tail); + for (tbl= view_tables; tbl != view_tables_tail->next_global; + tbl= tbl->next_global) + tbl->security_ctx= security_ctx; } + /* assign security context to SELECT name resolution contexts of view */ + for(SELECT_LEX *sl= lex->all_selects_list; + sl; + sl= sl->next_select_in_list()) + sl->context.security_ctx= security_ctx; + /* Setup an error processor to hide error messages issued by stored routines referenced in the view diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 3ed25f2e78f..bf213b19bb9 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -4523,6 +4523,12 @@ opt_part_option: lex->part_info->curr_part_elem->engine_type= $4; lex->part_info->default_engine_type= $4; } + | CONNECTION_SYM opt_equal TEXT_STRING_sys + { + LEX *lex= Lex; + lex->part_info->curr_part_elem->connect_string.str= $3.str; + lex->part_info->curr_part_elem->connect_string.length= $3.length; + } | NODEGROUP_SYM opt_equal real_ulong_num { Lex->part_info->curr_part_elem->nodegroup_id= (uint16) $3; } | MAX_ROWS opt_equal real_ulonglong_num diff --git a/sql/table.cc b/sql/table.cc index 27d5b0643c7..d52c6bb085d 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -2084,7 +2084,7 @@ int open_table_from_share(THD *thd, TABLE_SHARE *share, const char *alias, bool error_reported= FALSE; uchar *record, *bitmaps; Field **field_ptr, **vfield_ptr; - bool save_view_prepare_mode= thd->lex->view_prepare_mode; + uint8 save_context_analysis_only= thd->lex->context_analysis_only; DBUG_ENTER("open_table_from_share"); DBUG_PRINT("enter",("name: '%s.%s' form: 0x%lx", share->db.str, share->table_name.str, (long) outparam)); @@ -2092,7 +2092,7 @@ int open_table_from_share(THD *thd, TABLE_SHARE *share, const char *alias, /* Parsing of partitioning information from .frm needs thd->lex set up. */ DBUG_ASSERT(thd->lex->is_lex_started); - thd->lex->view_prepare_mode= FALSE; // not a view + thd->lex->context_analysis_only= 0; // not a view error= 1; bzero((char*) outparam, sizeof(*outparam)); @@ -2422,7 +2422,7 @@ partititon_err: HA_HAS_OWN_BINLOGGING); thd->status_var.opened_tables++; - thd->lex->view_prepare_mode= save_view_prepare_mode; + thd->lex->context_analysis_only= save_context_analysis_only; DBUG_RETURN (0); err: @@ -2435,7 +2435,7 @@ partititon_err: #endif outparam->file= 0; // For easier error checking outparam->db_stat=0; - thd->lex->view_prepare_mode= save_view_prepare_mode; + thd->lex->context_analysis_only= save_context_analysis_only; free_root(&outparam->mem_root, MYF(0)); // Safe to call on bzero'd root outparam->alias.free(); DBUG_RETURN (error); @@ -2674,13 +2674,17 @@ void open_table_error(TABLE_SHARE *share, int error, int db_errno, int errarg) { int err_no; char buff[FN_REFLEN]; - myf errortype= ME_ERROR+ME_WAITTANG; + myf errortype= ME_ERROR+ME_WAITTANG; // Write fatals error to log DBUG_ENTER("open_table_error"); switch (error) { case 7: case 1: - if (db_errno == ENOENT) + /* + Test if file didn't exists. We have to also test for EINVAL as this + may happen on windows when opening a file with a not legal file name + */ + if (db_errno == ENOENT || db_errno == EINVAL) my_error(ER_NO_SUCH_TABLE, MYF(0), share->db.str, share->table_name.str); else { diff --git a/sql/table.h b/sql/table.h index bd767e34564..afe1f64dae1 100644 --- a/sql/table.h +++ b/sql/table.h @@ -1,4 +1,4 @@ -/* Copyright 2000-2008 MySQL AB, 2008 Sun Microsystems, Inc. +/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. 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 |